Index: stable/11/sys/dev/evdev/evdev.c =================================================================== --- stable/11/sys/dev/evdev/evdev.c (revision 326542) +++ stable/11/sys/dev/evdev/evdev.c (revision 326543) @@ -1,938 +1,941 @@ /*- * Copyright (c) 2014 Jakub Wojciech Klama * Copyright (c) 2015-2016 Vladimir Kondratyev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_evdev.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef EVDEV_DEBUG #define debugf(evdev, fmt, args...) printf("evdev: " fmt "\n", ##args) #else #define debugf(evdev, fmt, args...) #endif #ifdef FEATURE FEATURE(evdev, "Input event devices support"); #ifdef EVDEV_SUPPORT FEATURE(evdev_support, "Evdev support in hybrid drivers"); #endif #endif enum evdev_sparse_result { EV_SKIP_EVENT, /* Event value not changed */ EV_REPORT_EVENT, /* Event value changed */ EV_REPORT_MT_SLOT, /* Event value and MT slot number changed */ }; MALLOC_DEFINE(M_EVDEV, "evdev", "evdev memory"); int evdev_rcpt_mask = EVDEV_RCPT_SYSMOUSE | EVDEV_RCPT_KBDMUX; int evdev_sysmouse_t_axis = 0; #ifdef EVDEV_SUPPORT SYSCTL_NODE(_kern, OID_AUTO, evdev, CTLFLAG_RW, 0, "Evdev args"); SYSCTL_INT(_kern_evdev, OID_AUTO, rcpt_mask, CTLFLAG_RW, &evdev_rcpt_mask, 0, "Who is receiving events: bit0 - sysmouse, bit1 - kbdmux, " "bit2 - mouse hardware, bit3 - keyboard hardware"); SYSCTL_INT(_kern_evdev, OID_AUTO, sysmouse_t_axis, CTLFLAG_RW, &evdev_sysmouse_t_axis, 0, "Extract T-axis from 0-none, 1-ums, 2-psm"); #endif static void evdev_start_repeat(struct evdev_dev *, uint16_t); static void evdev_stop_repeat(struct evdev_dev *); static int evdev_check_event(struct evdev_dev *, uint16_t, uint16_t, int32_t); static inline void bit_change(bitstr_t *bitstr, int bit, int value) { if (value) bit_set(bitstr, bit); else bit_clear(bitstr, bit); } struct evdev_dev * evdev_alloc(void) { return malloc(sizeof(struct evdev_dev), M_EVDEV, M_WAITOK | M_ZERO); } void evdev_free(struct evdev_dev *evdev) { if (evdev != NULL && evdev->ev_cdev != NULL && evdev->ev_cdev->si_drv1 != NULL) evdev_unregister(evdev); free(evdev, M_EVDEV); } static struct input_absinfo * evdev_alloc_absinfo(void) { return (malloc(sizeof(struct input_absinfo) * ABS_CNT, M_EVDEV, M_WAITOK | M_ZERO)); } static void evdev_free_absinfo(struct input_absinfo *absinfo) { free(absinfo, M_EVDEV); } int evdev_set_report_size(struct evdev_dev *evdev, size_t report_size) { if (report_size > KEY_CNT + REL_CNT + ABS_CNT + MAX_MT_SLOTS * MT_CNT + MSC_CNT + LED_CNT + SND_CNT + SW_CNT + FF_CNT) return (EINVAL); evdev->ev_report_size = report_size; return (0); } static size_t evdev_estimate_report_size(struct evdev_dev *evdev) { size_t size = 0; int res; /* * Keyboards generate one event per report but other devices with * buttons like mouses can report events simultaneously */ bit_ffs_at(evdev->ev_key_flags, KEY_OK, KEY_CNT - KEY_OK, &res); if (res == -1) bit_ffs(evdev->ev_key_flags, BTN_MISC, &res); size += (res != -1); bit_count(evdev->ev_key_flags, BTN_MISC, KEY_OK - BTN_MISC, &res); size += res; /* All relative axes can be reported simultaneously */ bit_count(evdev->ev_rel_flags, 0, REL_CNT, &res); size += res; /* * All absolute axes can be reported simultaneously. * Multitouch axes can be reported ABS_MT_SLOT times */ if (evdev->ev_absinfo != NULL) { bit_count(evdev->ev_abs_flags, 0, ABS_CNT, &res); size += res; bit_count(evdev->ev_abs_flags, ABS_MT_FIRST, MT_CNT, &res); if (res > 0) { res++; /* ABS_MT_SLOT or SYN_MT_REPORT */ if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT)) /* MT type B */ size += res * MAXIMAL_MT_SLOT(evdev); else /* MT type A */ size += res * (MAX_MT_REPORTS - 1); } } /* All misc events can be reported simultaneously */ bit_count(evdev->ev_msc_flags, 0, MSC_CNT, &res); size += res; /* All leds can be reported simultaneously */ bit_count(evdev->ev_led_flags, 0, LED_CNT, &res); size += res; /* Assume other events are generated once per report */ bit_ffs(evdev->ev_snd_flags, SND_CNT, &res); size += (res != -1); bit_ffs(evdev->ev_sw_flags, SW_CNT, &res); size += (res != -1); /* XXX: FF part is not implemented yet */ size++; /* SYN_REPORT */ return (size); } static int evdev_register_common(struct evdev_dev *evdev) { int ret; debugf(evdev, "%s: registered evdev provider: %s <%s>\n", evdev->ev_shortname, evdev->ev_name, evdev->ev_serial); /* Initialize internal structures */ LIST_INIT(&evdev->ev_clients); if (evdev_event_supported(evdev, EV_REP) && bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT)) { /* Initialize callout */ callout_init_mtx(&evdev->ev_rep_callout, &evdev->ev_mtx, 0); if (evdev->ev_rep[REP_DELAY] == 0 && evdev->ev_rep[REP_PERIOD] == 0) { /* Supply default values */ evdev->ev_rep[REP_DELAY] = 250; evdev->ev_rep[REP_PERIOD] = 33; } } /* Initialize multitouch protocol type B states */ if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT) && evdev->ev_absinfo != NULL && MAXIMAL_MT_SLOT(evdev) > 0) evdev_mt_init(evdev); /* Estimate maximum report size */ if (evdev->ev_report_size == 0) { ret = evdev_set_report_size(evdev, evdev_estimate_report_size(evdev)); if (ret != 0) goto bail_out; } /* Create char device node */ ret = evdev_cdev_create(evdev); bail_out: return (ret); } int evdev_register(struct evdev_dev *evdev) { int ret; evdev->ev_lock_type = EV_LOCK_INTERNAL; evdev->ev_lock = &evdev->ev_mtx; mtx_init(&evdev->ev_mtx, "evmtx", NULL, MTX_DEF); ret = evdev_register_common(evdev); if (ret != 0) mtx_destroy(&evdev->ev_mtx); return (ret); } int evdev_register_mtx(struct evdev_dev *evdev, struct mtx *mtx) { evdev->ev_lock_type = EV_LOCK_MTX; evdev->ev_lock = mtx; return (evdev_register_common(evdev)); } int evdev_unregister(struct evdev_dev *evdev) { struct evdev_client *client; int ret; debugf(evdev, "%s: unregistered evdev provider: %s\n", evdev->ev_shortname, evdev->ev_name); EVDEV_LOCK(evdev); evdev->ev_cdev->si_drv1 = NULL; /* Wake up sleepers */ LIST_FOREACH(client, &evdev->ev_clients, ec_link) { evdev_revoke_client(client); evdev_dispose_client(evdev, client); EVDEV_CLIENT_LOCKQ(client); evdev_notify_event(client); EVDEV_CLIENT_UNLOCKQ(client); } EVDEV_UNLOCK(evdev); /* destroy_dev can sleep so release lock */ ret = evdev_cdev_destroy(evdev); evdev->ev_cdev = NULL; if (ret == 0 && evdev->ev_lock_type == EV_LOCK_INTERNAL) mtx_destroy(&evdev->ev_mtx); evdev_free_absinfo(evdev->ev_absinfo); evdev_mt_free(evdev); return (ret); } inline void evdev_set_name(struct evdev_dev *evdev, const char *name) { snprintf(evdev->ev_name, NAMELEN, "%s", name); } inline void evdev_set_id(struct evdev_dev *evdev, uint16_t bustype, uint16_t vendor, uint16_t product, uint16_t version) { evdev->ev_id = (struct input_id) { .bustype = bustype, .vendor = vendor, .product = product, .version = version }; } inline void evdev_set_phys(struct evdev_dev *evdev, const char *name) { snprintf(evdev->ev_shortname, NAMELEN, "%s", name); } inline void evdev_set_serial(struct evdev_dev *evdev, const char *serial) { snprintf(evdev->ev_serial, NAMELEN, "%s", serial); } inline void evdev_set_methods(struct evdev_dev *evdev, void *softc, const struct evdev_methods *methods) { evdev->ev_methods = methods; evdev->ev_softc = softc; } inline void evdev_support_prop(struct evdev_dev *evdev, uint16_t prop) { KASSERT(prop < INPUT_PROP_CNT, ("invalid evdev input property")); bit_set(evdev->ev_prop_flags, prop); } inline void evdev_support_event(struct evdev_dev *evdev, uint16_t type) { KASSERT(type < EV_CNT, ("invalid evdev event property")); bit_set(evdev->ev_type_flags, type); } inline void evdev_support_key(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < KEY_CNT, ("invalid evdev key property")); bit_set(evdev->ev_key_flags, code); } inline void evdev_support_rel(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < REL_CNT, ("invalid evdev rel property")); bit_set(evdev->ev_rel_flags, code); } inline void evdev_support_abs(struct evdev_dev *evdev, uint16_t code, int32_t value, int32_t minimum, int32_t maximum, int32_t fuzz, int32_t flat, int32_t resolution) { struct input_absinfo absinfo; KASSERT(code < ABS_CNT, ("invalid evdev abs property")); absinfo = (struct input_absinfo) { .value = value, .minimum = minimum, .maximum = maximum, .fuzz = fuzz, .flat = flat, .resolution = resolution, }; evdev_set_abs_bit(evdev, code); evdev_set_absinfo(evdev, code, &absinfo); } inline void evdev_set_abs_bit(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < ABS_CNT, ("invalid evdev abs property")); if (evdev->ev_absinfo == NULL) evdev->ev_absinfo = evdev_alloc_absinfo(); bit_set(evdev->ev_abs_flags, code); } inline void evdev_support_msc(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < MSC_CNT, ("invalid evdev msc property")); bit_set(evdev->ev_msc_flags, code); } inline void evdev_support_led(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < LED_CNT, ("invalid evdev led property")); bit_set(evdev->ev_led_flags, code); } inline void evdev_support_snd(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < SND_CNT, ("invalid evdev snd property")); bit_set(evdev->ev_snd_flags, code); } inline void evdev_support_sw(struct evdev_dev *evdev, uint16_t code) { KASSERT(code < SW_CNT, ("invalid evdev sw property")); bit_set(evdev->ev_sw_flags, code); } bool evdev_event_supported(struct evdev_dev *evdev, uint16_t type) { KASSERT(type < EV_CNT, ("invalid evdev event property")); return (bit_test(evdev->ev_type_flags, type)); } inline void evdev_set_absinfo(struct evdev_dev *evdev, uint16_t axis, struct input_absinfo *absinfo) { KASSERT(axis < ABS_CNT, ("invalid evdev abs property")); if (axis == ABS_MT_SLOT && (absinfo->maximum < 1 || absinfo->maximum >= MAX_MT_SLOTS)) return; if (evdev->ev_absinfo == NULL) evdev->ev_absinfo = evdev_alloc_absinfo(); if (axis == ABS_MT_SLOT) evdev->ev_absinfo[ABS_MT_SLOT].maximum = absinfo->maximum; else memcpy(&evdev->ev_absinfo[axis], absinfo, sizeof(struct input_absinfo)); } inline void evdev_set_repeat_params(struct evdev_dev *evdev, uint16_t property, int value) { KASSERT(property < REP_CNT, ("invalid evdev repeat property")); evdev->ev_rep[property] = value; } inline void evdev_set_flag(struct evdev_dev *evdev, uint16_t flag) { KASSERT(flag < EVDEV_FLAG_CNT, ("invalid evdev flag property")); bit_set(evdev->ev_flags, flag); } static int evdev_check_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) { if (type >= EV_CNT) return (EINVAL); /* Allow SYN events implicitly */ if (type != EV_SYN && !evdev_event_supported(evdev, type)) return (EINVAL); switch (type) { case EV_SYN: if (code >= SYN_CNT) return (EINVAL); break; case EV_KEY: if (code >= KEY_CNT) return (EINVAL); if (!bit_test(evdev->ev_key_flags, code)) return (EINVAL); break; case EV_REL: if (code >= REL_CNT) return (EINVAL); if (!bit_test(evdev->ev_rel_flags, code)) return (EINVAL); break; case EV_ABS: if (code >= ABS_CNT) return (EINVAL); if (!bit_test(evdev->ev_abs_flags, code)) return (EINVAL); if (code == ABS_MT_SLOT && (value < 0 || value > MAXIMAL_MT_SLOT(evdev))) return (EINVAL); if (ABS_IS_MT(code) && evdev->ev_mt == NULL && bit_test(evdev->ev_abs_flags, ABS_MT_SLOT)) return (EINVAL); break; case EV_MSC: if (code >= MSC_CNT) return (EINVAL); if (!bit_test(evdev->ev_msc_flags, code)) return (EINVAL); break; case EV_LED: if (code >= LED_CNT) return (EINVAL); if (!bit_test(evdev->ev_led_flags, code)) return (EINVAL); break; case EV_SND: if (code >= SND_CNT) return (EINVAL); if (!bit_test(evdev->ev_snd_flags, code)) return (EINVAL); break; case EV_SW: if (code >= SW_CNT) return (EINVAL); if (!bit_test(evdev->ev_sw_flags, code)) return (EINVAL); break; case EV_REP: if (code >= REP_CNT) return (EINVAL); break; default: return (EINVAL); } return (0); } static void evdev_modify_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t *value) { EVDEV_LOCK_ASSERT(evdev); switch (type) { case EV_KEY: if (!evdev_event_supported(evdev, EV_REP)) break; if (!bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT)) { /* Detect driver key repeats. */ if (bit_test(evdev->ev_key_states, code) && *value == KEY_EVENT_DOWN) *value = KEY_EVENT_REPEAT; } else { /* Start/stop callout for evdev repeats */ - if (bit_test(evdev->ev_key_states, code) == !*value) { + if (bit_test(evdev->ev_key_states, code) == !*value && + !LIST_EMPTY(&evdev->ev_clients)) { if (*value == KEY_EVENT_DOWN) evdev_start_repeat(evdev, code); else evdev_stop_repeat(evdev); } } break; case EV_ABS: /* TBD: implement fuzz */ break; } } static enum evdev_sparse_result evdev_sparse_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) { int32_t last_mt_slot; EVDEV_LOCK_ASSERT(evdev); /* * For certain event types, update device state bits * and convert level reporting to edge reporting */ switch (type) { case EV_KEY: switch (value) { case KEY_EVENT_UP: case KEY_EVENT_DOWN: if (bit_test(evdev->ev_key_states, code) == value) return (EV_SKIP_EVENT); bit_change(evdev->ev_key_states, code, value); break; case KEY_EVENT_REPEAT: if (bit_test(evdev->ev_key_states, code) == 0 || !evdev_event_supported(evdev, EV_REP)) return (EV_SKIP_EVENT); break; default: return (EV_SKIP_EVENT); } break; case EV_LED: if (bit_test(evdev->ev_led_states, code) == value) return (EV_SKIP_EVENT); bit_change(evdev->ev_led_states, code, value); break; case EV_SND: - if (bit_test(evdev->ev_snd_states, code) == value) - return (EV_SKIP_EVENT); bit_change(evdev->ev_snd_states, code, value); break; case EV_SW: if (bit_test(evdev->ev_sw_states, code) == value) return (EV_SKIP_EVENT); bit_change(evdev->ev_sw_states, code, value); break; case EV_REP: if (evdev->ev_rep[code] == value) return (EV_SKIP_EVENT); evdev_set_repeat_params(evdev, code, value); break; case EV_REL: if (value == 0) return (EV_SKIP_EVENT); break; /* For EV_ABS, save last value in absinfo and ev_mt_states */ case EV_ABS: switch (code) { case ABS_MT_SLOT: /* Postpone ABS_MT_SLOT till next event */ evdev_set_last_mt_slot(evdev, value); return (EV_SKIP_EVENT); case ABS_MT_FIRST ... ABS_MT_LAST: /* Pass MT protocol type A events as is */ if (!bit_test(evdev->ev_abs_flags, ABS_MT_SLOT)) break; /* Don`t repeat MT protocol type B events */ last_mt_slot = evdev_get_last_mt_slot(evdev); if (evdev_get_mt_value(evdev, last_mt_slot, code) == value) return (EV_SKIP_EVENT); evdev_set_mt_value(evdev, last_mt_slot, code, value); if (last_mt_slot != CURRENT_MT_SLOT(evdev)) { CURRENT_MT_SLOT(evdev) = last_mt_slot; evdev->ev_report_opened = true; return (EV_REPORT_MT_SLOT); } break; default: if (evdev->ev_absinfo[code].value == value) return (EV_SKIP_EVENT); evdev->ev_absinfo[code].value = value; } break; case EV_SYN: if (code == SYN_REPORT) { /* Count empty reports as well as non empty */ evdev->ev_report_count++; /* Skip empty reports */ if (!evdev->ev_report_opened) return (EV_SKIP_EVENT); evdev->ev_report_opened = false; return (EV_REPORT_EVENT); } break; } evdev->ev_report_opened = true; return (EV_REPORT_EVENT); } static void evdev_propagate_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) { struct evdev_client *client; debugf(evdev, "%s pushed event %d/%d/%d", evdev->ev_shortname, type, code, value); EVDEV_LOCK_ASSERT(evdev); /* Propagate event through all clients */ LIST_FOREACH(client, &evdev->ev_clients, ec_link) { if (evdev->ev_grabber != NULL && evdev->ev_grabber != client) continue; EVDEV_CLIENT_LOCKQ(client); evdev_client_push(client, type, code, value); if (type == EV_SYN && code == SYN_REPORT) evdev_notify_event(client); EVDEV_CLIENT_UNLOCKQ(client); } evdev->ev_event_count++; } void evdev_send_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) { enum evdev_sparse_result sparse; EVDEV_LOCK_ASSERT(evdev); sparse = evdev_sparse_event(evdev, type, code, value); switch (sparse) { case EV_REPORT_MT_SLOT: /* report postponed ABS_MT_SLOT */ evdev_propagate_event(evdev, EV_ABS, ABS_MT_SLOT, CURRENT_MT_SLOT(evdev)); /* FALLTHROUGH */ case EV_REPORT_EVENT: evdev_propagate_event(evdev, type, code, value); /* FALLTHROUGH */ case EV_SKIP_EVENT: break; } } int evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) { if (evdev_check_event(evdev, type, code, value) != 0) return (EINVAL); EVDEV_ENTER(evdev); evdev_modify_event(evdev, type, code, &value); if (type == EV_SYN && code == SYN_REPORT && bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) evdev_send_mt_autorel(evdev); if (type == EV_SYN && code == SYN_REPORT && evdev->ev_report_opened && bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) evdev_send_mt_compat(evdev); evdev_send_event(evdev, type, code, value); EVDEV_EXIT(evdev); return (0); } int evdev_inject_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) { int ret = 0; switch (type) { case EV_REP: /* evdev repeats should not be processed by hardware driver */ if (bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT)) goto push; /* FALLTHROUGH */ case EV_LED: case EV_MSC: case EV_SND: case EV_FF: if (evdev->ev_methods != NULL && evdev->ev_methods->ev_event != NULL) evdev->ev_methods->ev_event(evdev, evdev->ev_softc, type, code, value); /* * Leds and driver repeats should be reported in ev_event * method body to interoperate with kbdmux states and rates * propagation so both ways (ioctl and evdev) of changing it * will produce only one evdev event report to client. */ if (type == EV_LED || type == EV_REP) break; /* FALLTHROUGH */ case EV_SYN: case EV_KEY: case EV_REL: case EV_ABS: case EV_SW: push: + if (evdev->ev_lock_type != EV_LOCK_INTERNAL) + EVDEV_LOCK(evdev); ret = evdev_push_event(evdev, type, code, value); + if (evdev->ev_lock_type != EV_LOCK_INTERNAL) + EVDEV_UNLOCK(evdev); break; default: ret = EINVAL; } return (ret); } int evdev_register_client(struct evdev_dev *evdev, struct evdev_client *client) { int ret = 0; debugf(evdev, "adding new client for device %s", evdev->ev_shortname); EVDEV_LOCK_ASSERT(evdev); if (LIST_EMPTY(&evdev->ev_clients) && evdev->ev_methods != NULL && evdev->ev_methods->ev_open != NULL) { debugf(evdev, "calling ev_open() on device %s", evdev->ev_shortname); ret = evdev->ev_methods->ev_open(evdev, evdev->ev_softc); } if (ret == 0) LIST_INSERT_HEAD(&evdev->ev_clients, client, ec_link); return (ret); } void evdev_dispose_client(struct evdev_dev *evdev, struct evdev_client *client) { debugf(evdev, "removing client for device %s", evdev->ev_shortname); EVDEV_LOCK_ASSERT(evdev); LIST_REMOVE(client, ec_link); if (LIST_EMPTY(&evdev->ev_clients)) { if (evdev->ev_methods != NULL && evdev->ev_methods->ev_close != NULL) evdev->ev_methods->ev_close(evdev, evdev->ev_softc); if (evdev_event_supported(evdev, EV_REP) && bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT)) evdev_stop_repeat(evdev); } evdev_release_client(evdev, client); } int evdev_grab_client(struct evdev_dev *evdev, struct evdev_client *client) { EVDEV_LOCK_ASSERT(evdev); if (evdev->ev_grabber != NULL) return (EBUSY); evdev->ev_grabber = client; return (0); } int evdev_release_client(struct evdev_dev *evdev, struct evdev_client *client) { EVDEV_LOCK_ASSERT(evdev); if (evdev->ev_grabber != client) return (EINVAL); evdev->ev_grabber = NULL; return (0); } static void evdev_repeat_callout(void *arg) { struct evdev_dev *evdev = (struct evdev_dev *)arg; evdev_send_event(evdev, EV_KEY, evdev->ev_rep_key, KEY_EVENT_REPEAT); evdev_send_event(evdev, EV_SYN, SYN_REPORT, 1); if (evdev->ev_rep[REP_PERIOD]) callout_reset(&evdev->ev_rep_callout, evdev->ev_rep[REP_PERIOD] * hz / 1000, evdev_repeat_callout, evdev); else evdev->ev_rep_key = KEY_RESERVED; } static void evdev_start_repeat(struct evdev_dev *evdev, uint16_t key) { EVDEV_LOCK_ASSERT(evdev); if (evdev->ev_rep[REP_DELAY]) { evdev->ev_rep_key = key; callout_reset(&evdev->ev_rep_callout, evdev->ev_rep[REP_DELAY] * hz / 1000, evdev_repeat_callout, evdev); } } static void evdev_stop_repeat(struct evdev_dev *evdev) { EVDEV_LOCK_ASSERT(evdev); if (evdev->ev_rep_key != KEY_RESERVED) { callout_stop(&evdev->ev_rep_callout); evdev->ev_rep_key = KEY_RESERVED; } } MODULE_VERSION(evdev, 1); Index: stable/11/sys/dev/evdev/evdev.h =================================================================== --- stable/11/sys/dev/evdev/evdev.h (revision 326542) +++ stable/11/sys/dev/evdev/evdev.h (revision 326543) @@ -1,210 +1,210 @@ /*- * Copyright (c) 2014 Jakub Wojciech Klama * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_EVDEV_EVDEV_H #define _DEV_EVDEV_EVDEV_H #include #include #include #include #define NAMELEN 80 struct evdev_dev; typedef int (evdev_open_t)(struct evdev_dev *, void *); typedef void (evdev_close_t)(struct evdev_dev *, void *); typedef void (evdev_event_t)(struct evdev_dev *, void *, uint16_t, uint16_t, int32_t); typedef void (evdev_keycode_t)(struct evdev_dev *, void *, struct input_keymap_entry *); /* * Keyboard and mouse events recipient mask. * evdev_rcpt_mask variable should be respected by keyboard and mouse drivers * that are able to send events through both evdev and sysmouse/kbdmux * interfaces so user can choose prefered one to not receive one event twice. */ #define EVDEV_RCPT_SYSMOUSE (1<<0) #define EVDEV_RCPT_KBDMUX (1<<1) #define EVDEV_RCPT_HW_MOUSE (1<<2) #define EVDEV_RCPT_HW_KBD (1<<3) extern int evdev_rcpt_mask; /* * Sysmouse protocol does not support horizontal wheel movement reporting. * To overcome this limitation different drivers use different sysmouse proto * extensions. Set kern.evdev.sysmouse_t_axis to tell sysmouse evdev driver * which protocol extension is used. * 0 - do not extract horizontal wheel movement (default). * 1 - ums(4) horizontal wheel encoding. T-axis is mapped to buttons 6 and 7 * 2 - psm(4) wheels encoding: z = 1,-1 - vert. wheel, z = 2,-2 - horiz. wheel */ enum { EVDEV_SYSMOUSE_T_AXIS_NONE = 0, EVDEV_SYSMOUSE_T_AXIS_UMS = 1, EVDEV_SYSMOUSE_T_AXIS_PSM = 2, }; extern int evdev_sysmouse_t_axis; #define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR #define ABS_MT_LAST ABS_MT_TOOL_Y #define ABS_IS_MT(x) ((x) >= ABS_MT_FIRST && (x) <= ABS_MT_LAST) #define ABS_MT_INDEX(x) ((x) - ABS_MT_FIRST) #define MT_CNT (ABS_MT_INDEX(ABS_MT_LAST) + 1) /* Multitouch protocol type A */ #define MAX_MT_REPORTS 5 /* Multitouch protocol type B interface */ #define MAX_MT_SLOTS 16 #define EVDEV_FLAG_SOFTREPEAT 0x00 /* use evdev to repeat keys */ #define EVDEV_FLAG_MT_STCOMPAT 0x01 /* autogenerate ST-compatible events * for MT protocol type B reports */ #define EVDEV_FLAG_MT_AUTOREL 0x02 /* Autorelease MT-slots not listed in * current MT protocol type B report */ #define EVDEV_FLAG_MAX 0x1F #define EVDEV_FLAG_CNT (EVDEV_FLAG_MAX + 1) struct evdev_methods { evdev_open_t *ev_open; evdev_close_t *ev_close; evdev_event_t *ev_event; evdev_keycode_t *ev_get_keycode; evdev_keycode_t *ev_set_keycode; }; /* Input device interface: */ struct evdev_dev *evdev_alloc(void); void evdev_free(struct evdev_dev *); void evdev_set_name(struct evdev_dev *, const char *); void evdev_set_id(struct evdev_dev *, uint16_t, uint16_t, uint16_t, uint16_t); void evdev_set_phys(struct evdev_dev *, const char *); void evdev_set_serial(struct evdev_dev *, const char *); void evdev_set_methods(struct evdev_dev *, void *, const struct evdev_methods *); int evdev_register(struct evdev_dev *); int evdev_register_mtx(struct evdev_dev *, struct mtx *); int evdev_unregister(struct evdev_dev *); int evdev_push_event(struct evdev_dev *, uint16_t, uint16_t, int32_t); void evdev_support_prop(struct evdev_dev *, uint16_t); void evdev_support_event(struct evdev_dev *, uint16_t); void evdev_support_key(struct evdev_dev *, uint16_t); void evdev_support_rel(struct evdev_dev *, uint16_t); void evdev_support_abs(struct evdev_dev *, uint16_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t); void evdev_support_msc(struct evdev_dev *, uint16_t); void evdev_support_led(struct evdev_dev *, uint16_t); void evdev_support_snd(struct evdev_dev *, uint16_t); void evdev_support_sw(struct evdev_dev *, uint16_t); void evdev_set_repeat_params(struct evdev_dev *, uint16_t, int); int evdev_set_report_size(struct evdev_dev *, size_t); void evdev_set_flag(struct evdev_dev *, uint16_t); /* Multitouch related functions: */ int32_t evdev_get_mt_slot_by_tracking_id(struct evdev_dev *, int32_t); void evdev_support_nfingers(struct evdev_dev *, int32_t); void evdev_support_mt_compat(struct evdev_dev *); void evdev_push_nfingers(struct evdev_dev *, int32_t); void evdev_push_mt_compat(struct evdev_dev *); /* Utility functions: */ uint16_t evdev_hid2key(int); void evdev_support_all_known_keys(struct evdev_dev *); uint16_t evdev_scancode2key(int *, int); void evdev_push_mouse_btn(struct evdev_dev *, int); void evdev_push_leds(struct evdev_dev *, int); void evdev_push_repeats(struct evdev_dev *, keyboard_t *); evdev_event_t evdev_ev_kbd_event; /* Event reporting shortcuts: */ static __inline int evdev_sync(struct evdev_dev *evdev) { return (evdev_push_event(evdev, EV_SYN, SYN_REPORT, 1)); } static __inline int evdev_mt_sync(struct evdev_dev *evdev) { return (evdev_push_event(evdev, EV_SYN, SYN_MT_REPORT, 1)); } static __inline int evdev_push_key(struct evdev_dev *evdev, uint16_t code, int32_t value) { return (evdev_push_event(evdev, EV_KEY, code, value != 0)); } static __inline int evdev_push_rel(struct evdev_dev *evdev, uint16_t code, int32_t value) { return (evdev_push_event(evdev, EV_REL, code, value)); } static __inline int evdev_push_abs(struct evdev_dev *evdev, uint16_t code, int32_t value) { return (evdev_push_event(evdev, EV_ABS, code, value)); } static __inline int evdev_push_msc(struct evdev_dev *evdev, uint16_t code, int32_t value) { return (evdev_push_event(evdev, EV_MSC, code, value)); } static __inline int evdev_push_led(struct evdev_dev *evdev, uint16_t code, int32_t value) { return (evdev_push_event(evdev, EV_LED, code, value != 0)); } static __inline int evdev_push_snd(struct evdev_dev *evdev, uint16_t code, int32_t value) { - return (evdev_push_event(evdev, EV_SND, code, value != 0)); + return (evdev_push_event(evdev, EV_SND, code, value)); } static __inline int evdev_push_sw(struct evdev_dev *evdev, uint16_t code, int32_t value) { return (evdev_push_event(evdev, EV_SW, code, value != 0)); } #endif /* _DEV_EVDEV_EVDEV_H */ Index: stable/11/sys/dev/evdev/evdev_utils.c =================================================================== --- stable/11/sys/dev/evdev/evdev_utils.c (revision 326542) +++ stable/11/sys/dev/evdev/evdev_utils.c (revision 326543) @@ -1,332 +1,341 @@ /*- * Copyright (c) 2014 Jakub Wojciech Klama * Copyright (c) 2015-2016 Vladimir Kondratyev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include +#include #include +#include #include #include #include #include #define NONE KEY_RESERVED static uint16_t evdev_usb_scancodes[256] = { /* 0x00 - 0x27 */ NONE, NONE, NONE, NONE, KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, /* 0x28 - 0x3f */ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, /* 0x40 - 0x5f */ KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, /* 0x60 - 0x7f */ KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, /* 0x80 - 0x9f */ KEY_VOLUMEUP, KEY_VOLUMEDOWN, NONE, NONE, NONE, KEY_KPCOMMA, NONE, KEY_RO, KEY_KATAKANAHIRAGANA, KEY_YEN,KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, NONE, NONE, NONE, KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 0xa0 - 0xbf */ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 0xc0 - 0xdf */ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 0xe0 - 0xff */ KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG,KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, KEY_COFFEE, KEY_REFRESH, KEY_CALC, NONE, NONE, NONE, NONE, }; static uint16_t evdev_at_set1_scancodes[] = { /* 0x00 - 0x1f */ NONE, KEY_ESC, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_ENTER, KEY_LEFTCTRL, KEY_A, KEY_S, /* 0x20 - 0x3f */ KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_LEFTSHIFT, KEY_BACKSLASH, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_RIGHTSHIFT, KEY_KPASTERISK, KEY_LEFTALT, KEY_SPACE, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, /* 0x40 - 0x5f */ KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KPMINUS, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KPPLUS, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP0, KEY_KPDOT, NONE, NONE, KEY_102ND, KEY_F11, KEY_F12, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 0x60 - 0x7f */ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, KEY_KATAKANAHIRAGANA, NONE, NONE, KEY_RO, NONE, NONE, KEY_ZENKAKUHANKAKU, KEY_HIRAGANA, KEY_KATAKANA, KEY_HENKAN, NONE, KEY_MUHENKAN, NONE, KEY_YEN, KEY_KPCOMMA, NONE, /* 0x00 - 0x1f. 0xE0 prefixed */ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, KEY_PREVIOUSSONG, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, KEY_NEXTSONG, NONE, NONE, KEY_KPENTER, KEY_RIGHTCTRL, NONE, NONE, /* 0x20 - 0x3f. 0xE0 prefixed */ KEY_MUTE, KEY_CALC, KEY_PLAYPAUSE, NONE, KEY_STOPCD, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, KEY_VOLUMEDOWN, NONE, KEY_VOLUMEUP, NONE, KEY_HOMEPAGE, NONE, NONE, KEY_KPSLASH, NONE, KEY_SYSRQ, KEY_RIGHTALT, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 0x40 - 0x5f. 0xE0 prefixed */ NONE, NONE, NONE, NONE, NONE, NONE, KEY_PAUSE, KEY_HOME, KEY_UP, KEY_PAGEUP, NONE, KEY_LEFT, NONE, KEY_RIGHT, NONE, KEY_END, KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_MENU, KEY_POWER, KEY_SLEEP, /* 0x60 - 0x7f. 0xE0 prefixed */ NONE, NONE, NONE, KEY_WAKEUP, NONE, KEY_SEARCH, KEY_BOOKMARKS, KEY_REFRESH, KEY_STOP, KEY_FORWARD, KEY_BACK, KEY_COMPUTER, KEY_MAIL, KEY_MEDIA, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, }; static uint16_t evdev_mouse_button_codes[] = { BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, BTN_SIDE, BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK, }; static uint16_t evdev_led_codes[] = { LED_CAPSL, /* CLKED */ LED_NUML, /* NLKED */ LED_SCROLLL, /* SLKED */ }; uint16_t evdev_hid2key(int scancode) { return evdev_usb_scancodes[scancode]; } void evdev_support_all_known_keys(struct evdev_dev *evdev) { size_t i; for (i = KEY_RESERVED; i < nitems(evdev_at_set1_scancodes); i++) if (evdev_at_set1_scancodes[i] != NONE) evdev_support_key(evdev, evdev_at_set1_scancodes[i]); } uint16_t evdev_scancode2key(int *state, int scancode) { uint16_t keycode; /* translate the scan code into a keycode */ keycode = evdev_at_set1_scancodes[scancode & 0x7f]; switch (*state) { case 0x00: /* normal scancode */ switch(scancode) { case 0xE0: case 0xE1: *state = scancode; return (NONE); } break; case 0xE0: /* 0xE0 prefix */ *state = 0; keycode = evdev_at_set1_scancodes[0x80 + (scancode & 0x7f)]; break; case 0xE1: /* 0xE1 prefix */ /* * The pause/break key on the 101 keyboard produces: * E1-1D-45 E1-9D-C5 * Ctrl-pause/break produces: * E0-46 E0-C6 (See above.) */ *state = 0; if ((scancode & 0x7f) == 0x1D) *state = 0x1D; return (NONE); /* NOT REACHED */ case 0x1D: /* pause / break */ *state = 0; if (scancode != 0x45) return (NONE); keycode = KEY_PAUSE; break; } return (keycode); } void evdev_push_mouse_btn(struct evdev_dev *evdev, int buttons) { size_t i; for (i = 0; i < nitems(evdev_mouse_button_codes); i++) evdev_push_key(evdev, evdev_mouse_button_codes[i], buttons & (1 << i)); } void evdev_push_leds(struct evdev_dev *evdev, int leds) { size_t i; /* Some drivers initialize leds before evdev */ if (evdev == NULL) return; for (i = 0; i < nitems(evdev_led_codes); i++) evdev_push_led(evdev, evdev_led_codes[i], leds & (1 << i)); } void evdev_push_repeats(struct evdev_dev *evdev, keyboard_t *kbd) { /* Some drivers initialize typematics before evdev */ if (evdev == NULL) return; evdev_push_event(evdev, EV_REP, REP_DELAY, kbd->kb_delay1); evdev_push_event(evdev, EV_REP, REP_PERIOD, kbd->kb_delay2); } void evdev_ev_kbd_event(struct evdev_dev *evdev, void *softc, uint16_t type, uint16_t code, int32_t value) { keyboard_t *kbd = (keyboard_t *)softc; int delay[2], leds, oleds; size_t i; if (type == EV_LED) { leds = oleds = KBD_LED_VAL(kbd); for (i = 0; i < nitems(evdev_led_codes); i++) { if (evdev_led_codes[i] == code) { if (value) leds |= 1 << i; else leds &= ~(1 << i); - if (leds != oleds) + if (leds != oleds) { + mtx_lock(&Giant); kbdd_ioctl(kbd, KDSETLED, (caddr_t)&leds); + mtx_unlock(&Giant); + } break; } } } else if (type == EV_REP && code == REP_DELAY) { delay[0] = value; delay[1] = kbd->kb_delay2; + mtx_lock(&Giant); kbdd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); + mtx_unlock(&Giant); } else if (type == EV_REP && code == REP_PERIOD) { delay[0] = kbd->kb_delay1; delay[1] = value; + mtx_lock(&Giant); kbdd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); + mtx_unlock(&Giant); } } Index: stable/11/sys/dev/syscons/sysmouse.c =================================================================== --- stable/11/sys/dev/syscons/sysmouse.c (revision 326542) +++ stable/11/sys/dev/syscons/sysmouse.c (revision 326543) @@ -1,335 +1,335 @@ /*- * Copyright (c) 1999 Kazutaka YOKOTA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer as * the first lines of this file unmodified. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include "opt_evdev.h" #include "opt_syscons.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef EVDEV_SUPPORT #include #include #endif #ifndef SC_NO_SYSMOUSE /* local variables */ static struct tty *sysmouse_tty; static int mouse_level; /* sysmouse protocol level */ static mousestatus_t mouse_status; #ifdef EVDEV_SUPPORT static struct evdev_dev *sysmouse_evdev; static void smdev_evdev_init(void) { int i; sysmouse_evdev = evdev_alloc(); evdev_set_name(sysmouse_evdev, "System mouse"); evdev_set_phys(sysmouse_evdev, "sysmouse"); evdev_set_id(sysmouse_evdev, BUS_VIRTUAL, 0, 0, 0); evdev_support_prop(sysmouse_evdev, INPUT_PROP_POINTER); evdev_support_event(sysmouse_evdev, EV_SYN); evdev_support_event(sysmouse_evdev, EV_REL); evdev_support_event(sysmouse_evdev, EV_KEY); evdev_support_rel(sysmouse_evdev, REL_X); evdev_support_rel(sysmouse_evdev, REL_Y); evdev_support_rel(sysmouse_evdev, REL_WHEEL); evdev_support_rel(sysmouse_evdev, REL_HWHEEL); for (i = 0; i < 8; i++) evdev_support_key(sysmouse_evdev, BTN_MOUSE + i); if (evdev_register(sysmouse_evdev)) { evdev_free(sysmouse_evdev); sysmouse_evdev = NULL; } } static void smdev_evdev_write(int x, int y, int z, int buttons) { if (sysmouse_evdev == NULL || !(evdev_rcpt_mask & EVDEV_RCPT_SYSMOUSE)) return; evdev_push_event(sysmouse_evdev, EV_REL, REL_X, x); evdev_push_event(sysmouse_evdev, EV_REL, REL_Y, y); switch (evdev_sysmouse_t_axis) { case EVDEV_SYSMOUSE_T_AXIS_PSM: switch (z) { case 1: case -1: evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); break; case 2: case -2: evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2); break; } break; case EVDEV_SYSMOUSE_T_AXIS_UMS: - /* XXX: Edge triggering should be used here */ - if (buttons & (1 << 5)) + if (buttons & (1 << 6)) evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1); - else if (buttons & (1 << 6)) + else if (buttons & (1 << 5)) evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1); + buttons &= ~((1 << 5)|(1 << 6)); /* PASSTHROUGH */ case EVDEV_SYSMOUSE_T_AXIS_NONE: default: evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); } evdev_push_mouse_btn(sysmouse_evdev, buttons); evdev_sync(sysmouse_evdev); } #endif static void smdev_close(struct tty *tp) { mouse_level = 0; } static int smdev_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) { mousehw_t *hw; mousemode_t *mode; switch (cmd) { case MOUSE_GETHWINFO: /* get device information */ hw = (mousehw_t *)data; hw->buttons = 10; /* XXX unknown */ hw->iftype = MOUSE_IF_SYSMOUSE; hw->type = MOUSE_MOUSE; hw->model = MOUSE_MODEL_GENERIC; hw->hwid = 0; return 0; case MOUSE_GETMODE: /* get protocol/mode */ mode = (mousemode_t *)data; mode->level = mouse_level; switch (mode->level) { case 0: /* emulate MouseSystems protocol */ mode->protocol = MOUSE_PROTO_MSC; mode->rate = -1; /* unknown */ mode->resolution = -1; /* unknown */ mode->accelfactor = 0; /* disabled */ mode->packetsize = MOUSE_MSC_PACKETSIZE; mode->syncmask[0] = MOUSE_MSC_SYNCMASK; mode->syncmask[1] = MOUSE_MSC_SYNC; break; case 1: /* sysmouse protocol */ mode->protocol = MOUSE_PROTO_SYSMOUSE; mode->rate = -1; mode->resolution = -1; mode->accelfactor = 0; mode->packetsize = MOUSE_SYS_PACKETSIZE; mode->syncmask[0] = MOUSE_SYS_SYNCMASK; mode->syncmask[1] = MOUSE_SYS_SYNC; break; } return 0; case MOUSE_SETMODE: /* set protocol/mode */ mode = (mousemode_t *)data; if (mode->level == -1) ; /* don't change the current setting */ else if ((mode->level < 0) || (mode->level > 1)) return EINVAL; else mouse_level = mode->level; return 0; case MOUSE_GETLEVEL: /* get operation level */ *(int *)data = mouse_level; return 0; case MOUSE_SETLEVEL: /* set operation level */ if ((*(int *)data < 0) || (*(int *)data > 1)) return EINVAL; mouse_level = *(int *)data; return 0; case MOUSE_GETSTATUS: /* get accumulated mouse events */ *(mousestatus_t *)data = mouse_status; mouse_status.flags = 0; mouse_status.obutton = mouse_status.button; mouse_status.dx = 0; mouse_status.dy = 0; mouse_status.dz = 0; return 0; #ifdef notyet case MOUSE_GETVARS: /* get internal mouse variables */ case MOUSE_SETVARS: /* set internal mouse variables */ return ENODEV; #endif case MOUSE_READSTATE: /* read status from the device */ case MOUSE_READDATA: /* read data from the device */ return ENODEV; } return (ENOIOCTL); } static int smdev_param(struct tty *tp, struct termios *t) { /* * Set the output baud rate to zero. The mouse device supports * no output, so we don't want to waste buffers. */ t->c_ispeed = TTYDEF_SPEED; t->c_ospeed = B0; return (0); } static struct ttydevsw smdev_ttydevsw = { .tsw_flags = TF_NOPREFIX, .tsw_close = smdev_close, .tsw_ioctl = smdev_ioctl, .tsw_param = smdev_param, }; static void sm_attach_mouse(void *unused) { if (!vty_enabled(VTY_SC)) return; sysmouse_tty = tty_alloc(&smdev_ttydevsw, NULL); tty_makedev(sysmouse_tty, NULL, "sysmouse"); #ifdef EVDEV_SUPPORT smdev_evdev_init(); #endif } SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sm_attach_mouse, NULL); int sysmouse_event(mouse_info_t *info) { /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */ static int butmap[8] = { MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, MOUSE_MSC_BUTTON2UP, MOUSE_MSC_BUTTON1UP, 0, }; u_char buf[8]; int x, y, z; int i, flags = 0; tty_lock(sysmouse_tty); switch (info->operation) { case MOUSE_ACTION: mouse_status.button = info->u.data.buttons; /* FALL THROUGH */ case MOUSE_MOTION_EVENT: x = info->u.data.x; y = info->u.data.y; z = info->u.data.z; break; case MOUSE_BUTTON_EVENT: x = y = z = 0; if (info->u.event.value > 0) mouse_status.button |= info->u.event.id; else mouse_status.button &= ~info->u.event.id; break; default: goto done; } mouse_status.dx += x; mouse_status.dy += y; mouse_status.dz += z; mouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0) | (mouse_status.obutton ^ mouse_status.button); flags = mouse_status.flags; if (flags == 0) goto done; #ifdef EVDEV_SUPPORT smdev_evdev_write(x, y, z, mouse_status.button); #endif if (!tty_opened(sysmouse_tty)) goto done; /* the first five bytes are compatible with MouseSystems' */ buf[0] = MOUSE_MSC_SYNC | butmap[mouse_status.button & MOUSE_STDBUTTONS]; x = imax(imin(x, 255), -256); buf[1] = x >> 1; buf[3] = x - buf[1]; y = -imax(imin(y, 255), -256); buf[2] = y >> 1; buf[4] = y - buf[2]; for (i = 0; i < MOUSE_MSC_PACKETSIZE; ++i) ttydisc_rint(sysmouse_tty, buf[i], 0); if (mouse_level >= 1) { /* extended part */ z = imax(imin(z, 127), -128); buf[5] = (z >> 1) & 0x7f; buf[6] = (z - (z >> 1)) & 0x7f; /* buttons 4-10 */ buf[7] = (~mouse_status.button >> 3) & 0x7f; for (i = MOUSE_MSC_PACKETSIZE; i < MOUSE_SYS_PACKETSIZE; ++i) ttydisc_rint(sysmouse_tty, buf[i], 0); } ttydisc_rint_done(sysmouse_tty); done: tty_unlock(sysmouse_tty); return (flags); } #endif /* !SC_NO_SYSMOUSE */ Index: stable/11/sys/dev/vt/vt_sysmouse.c =================================================================== --- stable/11/sys/dev/vt/vt_sysmouse.c (revision 326542) +++ stable/11/sys/dev/vt/vt_sysmouse.c (revision 326543) @@ -1,488 +1,488 @@ /*- * Copyright (c) 1999 Kazutaka YOKOTA * All rights reserved. * * Copyright (c) 2009 The FreeBSD Foundation * All rights reserved. * * This software was developed by Ed Schouten under sponsorship from the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_evdev.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EVDEV_SUPPORT #include #include #endif static d_open_t sysmouse_open; static d_close_t sysmouse_close; static d_read_t sysmouse_read; static d_ioctl_t sysmouse_ioctl; static d_poll_t sysmouse_poll; static struct cdevsw sysmouse_cdevsw = { .d_version = D_VERSION, .d_open = sysmouse_open, .d_close = sysmouse_close, .d_read = sysmouse_read, .d_ioctl = sysmouse_ioctl, .d_poll = sysmouse_poll, .d_name = "sysmouse", }; static struct mtx sysmouse_lock; static struct cv sysmouse_sleep; static struct selinfo sysmouse_bufpoll; static int sysmouse_level; static mousestatus_t sysmouse_status; static int sysmouse_flags; #define SM_ASYNC 0x1 static struct sigio *sysmouse_sigio; #define SYSMOUSE_MAXFRAMES 250 /* 2 KB */ static MALLOC_DEFINE(M_SYSMOUSE, "sysmouse", "sysmouse device"); static unsigned char *sysmouse_buffer; static unsigned int sysmouse_start, sysmouse_length; #ifdef EVDEV_SUPPORT static struct evdev_dev *sysmouse_evdev; static void sysmouse_evdev_init(void) { int i; sysmouse_evdev = evdev_alloc(); evdev_set_name(sysmouse_evdev, "System mouse"); evdev_set_phys(sysmouse_evdev, "sysmouse"); evdev_set_id(sysmouse_evdev, BUS_VIRTUAL, 0, 0, 0); evdev_support_prop(sysmouse_evdev, INPUT_PROP_POINTER); evdev_support_event(sysmouse_evdev, EV_SYN); evdev_support_event(sysmouse_evdev, EV_REL); evdev_support_event(sysmouse_evdev, EV_KEY); evdev_support_rel(sysmouse_evdev, REL_X); evdev_support_rel(sysmouse_evdev, REL_Y); evdev_support_rel(sysmouse_evdev, REL_WHEEL); evdev_support_rel(sysmouse_evdev, REL_HWHEEL); for (i = 0; i < 8; i++) evdev_support_key(sysmouse_evdev, BTN_MOUSE + i); if (evdev_register(sysmouse_evdev)) { evdev_free(sysmouse_evdev); sysmouse_evdev = NULL; } } static void sysmouse_evdev_store(int x, int y, int z, int buttons) { if (sysmouse_evdev == NULL || !(evdev_rcpt_mask & EVDEV_RCPT_SYSMOUSE)) return; evdev_push_event(sysmouse_evdev, EV_REL, REL_X, x); evdev_push_event(sysmouse_evdev, EV_REL, REL_Y, y); switch (evdev_sysmouse_t_axis) { case EVDEV_SYSMOUSE_T_AXIS_PSM: switch (z) { case 1: case -1: evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); break; case 2: case -2: evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2); break; } break; case EVDEV_SYSMOUSE_T_AXIS_UMS: - /* XXX: Edge triggering should be used here */ - if (buttons & (1 << 5)) + if (buttons & (1 << 6)) evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1); - else if (buttons & (1 << 6)) + else if (buttons & (1 << 5)) evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1); + buttons &= ~((1 << 5)|(1 << 6)); /* PASSTHROUGH */ case EVDEV_SYSMOUSE_T_AXIS_NONE: default: evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z); } evdev_push_mouse_btn(sysmouse_evdev, buttons); evdev_sync(sysmouse_evdev); } #endif static int sysmouse_buf_read(struct uio *uio, unsigned int length) { unsigned char buf[MOUSE_SYS_PACKETSIZE]; int error; if (sysmouse_buffer == NULL) return (ENXIO); else if (sysmouse_length == 0) return (EWOULDBLOCK); memcpy(buf, sysmouse_buffer + sysmouse_start * MOUSE_SYS_PACKETSIZE, MOUSE_SYS_PACKETSIZE); sysmouse_start = (sysmouse_start + 1) % SYSMOUSE_MAXFRAMES; sysmouse_length--; mtx_unlock(&sysmouse_lock); error = uiomove(buf, length, uio); mtx_lock(&sysmouse_lock); return (error); } static void sysmouse_buf_store(const unsigned char buf[MOUSE_SYS_PACKETSIZE]) { unsigned int idx; if (sysmouse_buffer == NULL || sysmouse_length == SYSMOUSE_MAXFRAMES) return; idx = (sysmouse_start + sysmouse_length) % SYSMOUSE_MAXFRAMES; memcpy(sysmouse_buffer + idx * MOUSE_SYS_PACKETSIZE, buf, MOUSE_SYS_PACKETSIZE); sysmouse_length++; cv_broadcast(&sysmouse_sleep); selwakeup(&sysmouse_bufpoll); if (sysmouse_flags & SM_ASYNC && sysmouse_sigio != NULL) pgsigio(&sysmouse_sigio, SIGIO, 0); } void sysmouse_process_event(mouse_info_t *mi) { /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */ static const int buttonmap[8] = { MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON3UP, MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, MOUSE_MSC_BUTTON2UP, MOUSE_MSC_BUTTON1UP, 0, }; unsigned char buf[MOUSE_SYS_PACKETSIZE]; int x, y, iy, z; random_harvest_queue(mi, sizeof *mi, 2, RANDOM_MOUSE); mtx_lock(&sysmouse_lock); switch (mi->operation) { case MOUSE_ACTION: sysmouse_status.button = mi->u.data.buttons; /* FALLTHROUGH */ case MOUSE_MOTION_EVENT: x = mi->u.data.x; y = mi->u.data.y; z = mi->u.data.z; break; case MOUSE_BUTTON_EVENT: x = y = z = 0; if (mi->u.event.value > 0) sysmouse_status.button |= mi->u.event.id; else sysmouse_status.button &= ~mi->u.event.id; break; default: goto done; } sysmouse_status.dx += x; sysmouse_status.dy += y; sysmouse_status.dz += z; sysmouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0) | (sysmouse_status.obutton ^ sysmouse_status.button); if (sysmouse_status.flags == 0) goto done; #ifdef EVDEV_SUPPORT sysmouse_evdev_store(x, y, z, sysmouse_status.button); #endif /* The first five bytes are compatible with MouseSystems. */ buf[0] = MOUSE_MSC_SYNC | buttonmap[sysmouse_status.button & MOUSE_STDBUTTONS]; x = imax(imin(x, 255), -256); buf[1] = x >> 1; buf[3] = x - buf[1]; iy = -imax(imin(y, 255), -256); buf[2] = iy >> 1; buf[4] = iy - buf[2]; /* Extended part. */ z = imax(imin(z, 127), -128); buf[5] = (z >> 1) & 0x7f; buf[6] = (z - (z >> 1)) & 0x7f; /* Buttons 4-10. */ buf[7] = (~sysmouse_status.button >> 3) & 0x7f; sysmouse_buf_store(buf); #ifndef SC_NO_CUTPASTE mtx_unlock(&sysmouse_lock); vt_mouse_event(mi->operation, x, y, mi->u.event.id, mi->u.event.value, sysmouse_level); return; #endif done: mtx_unlock(&sysmouse_lock); } static int sysmouse_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { void *buf; buf = malloc(MOUSE_SYS_PACKETSIZE * SYSMOUSE_MAXFRAMES, M_SYSMOUSE, M_WAITOK); mtx_lock(&sysmouse_lock); if (sysmouse_buffer == NULL) { sysmouse_buffer = buf; sysmouse_start = sysmouse_length = 0; sysmouse_level = 0; } else { free(buf, M_SYSMOUSE); } mtx_unlock(&sysmouse_lock); return (0); } static int sysmouse_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { mtx_lock(&sysmouse_lock); free(sysmouse_buffer, M_SYSMOUSE); sysmouse_buffer = NULL; sysmouse_level = 0; mtx_unlock(&sysmouse_lock); return (0); } static int sysmouse_read(struct cdev *dev, struct uio *uio, int ioflag) { unsigned int length; ssize_t oresid; int error = 0; oresid = uio->uio_resid; mtx_lock(&sysmouse_lock); length = sysmouse_level >= 1 ? MOUSE_SYS_PACKETSIZE : MOUSE_MSC_PACKETSIZE; while (uio->uio_resid >= length) { error = sysmouse_buf_read(uio, length); if (error == 0) { /* Process the next frame. */ continue; } else if (error != EWOULDBLOCK) { /* Error (e.g. EFAULT). */ break; } else { /* Block. */ if (oresid != uio->uio_resid || ioflag & O_NONBLOCK) break; error = cv_wait_sig(&sysmouse_sleep, &sysmouse_lock); if (error != 0) break; } } mtx_unlock(&sysmouse_lock); return (error); } static int sysmouse_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { switch (cmd) { case FIOASYNC: mtx_lock(&sysmouse_lock); if (*(int *)data) sysmouse_flags |= SM_ASYNC; else sysmouse_flags &= ~SM_ASYNC; mtx_unlock(&sysmouse_lock); return (0); case FIONBIO: return (0); case FIOGETOWN: *(int *)data = fgetown(&sysmouse_sigio); return (0); case FIOSETOWN: return (fsetown(*(int *)data, &sysmouse_sigio)); case MOUSE_GETHWINFO: { mousehw_t *hw = (mousehw_t *)data; hw->buttons = 10; hw->iftype = MOUSE_IF_SYSMOUSE; hw->type = MOUSE_MOUSE; hw->model = MOUSE_MODEL_GENERIC; hw->hwid = 0; return (0); } case MOUSE_GETLEVEL: *(int *)data = sysmouse_level; return (0); case MOUSE_GETMODE: { mousemode_t *mode = (mousemode_t *)data; mode->rate = -1; mode->resolution = -1; mode->accelfactor = 0; mode->level = sysmouse_level; switch (mode->level) { case 0: mode->protocol = MOUSE_PROTO_MSC; mode->packetsize = MOUSE_MSC_PACKETSIZE; mode->syncmask[0] = MOUSE_MSC_SYNCMASK; mode->syncmask[1] = MOUSE_MSC_SYNC; break; case 1: mode->protocol = MOUSE_PROTO_SYSMOUSE; mode->packetsize = MOUSE_SYS_PACKETSIZE; mode->syncmask[0] = MOUSE_SYS_SYNCMASK; mode->syncmask[1] = MOUSE_SYS_SYNC; break; } return (0); } case MOUSE_GETSTATUS: mtx_lock(&sysmouse_lock); *(mousestatus_t *)data = sysmouse_status; sysmouse_status.flags = 0; sysmouse_status.obutton = sysmouse_status.button; sysmouse_status.dx = 0; sysmouse_status.dy = 0; sysmouse_status.dz = 0; mtx_unlock(&sysmouse_lock); return (0); case MOUSE_SETLEVEL: { int level; level = *(int *)data; if (level != 0 && level != 1) return (EINVAL); sysmouse_level = level; return (0); } case MOUSE_SETMODE: { mousemode_t *mode = (mousemode_t *)data; switch (mode->level) { case -1: /* Do nothing. */ break; case 0: case 1: sysmouse_level = mode->level; break; default: return (EINVAL); } return (0); } case MOUSE_MOUSECHAR: return (0); default: #ifdef VT_SYSMOUSE_DEBUG printf("sysmouse: unknown ioctl: %c:%lx\n", (char)IOCGROUP(cmd), IOCBASECMD(cmd)); #endif return (ENOIOCTL); } } static int sysmouse_poll(struct cdev *dev, int events, struct thread *td) { int revents = 0; mtx_lock(&sysmouse_lock); if (events & (POLLIN|POLLRDNORM)) { if (sysmouse_length > 0) revents = events & (POLLIN|POLLRDNORM); else selrecord(td, &sysmouse_bufpoll); } mtx_unlock(&sysmouse_lock); return (revents); } static void sysmouse_drvinit(void *unused) { if (!vty_enabled(VTY_VT)) return; mtx_init(&sysmouse_lock, "sysmouse", NULL, MTX_DEF); cv_init(&sysmouse_sleep, "sysmrd"); make_dev(&sysmouse_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "sysmouse"); #ifdef EVDEV_SUPPORT sysmouse_evdev_init(); #endif } SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sysmouse_drvinit, NULL); Index: stable/11 =================================================================== --- stable/11 (revision 326542) +++ stable/11 (revision 326543) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r325295-325299