diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-11-06 15:42:44 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-11-15 10:56:14 +0100 |
commit | e0b4edbdcc3558d3f38af8398f995c2e9f019f07 (patch) | |
tree | ea91a5fcfb9b6a66a8c0b74cf68ff8d450ce17e0 /freebsd/sys/dev/evdev | |
parent | Disable or make static kern_* functions (diff) | |
download | rtems-libbsd-e0b4edbdcc3558d3f38af8398f995c2e9f019f07.tar.bz2 |
Update to FreeBSD head 2018-11-15
Git mirror commit a18b0830c4be01b39489a891b63d6023ada6358a.
Update #3472.
Diffstat (limited to 'freebsd/sys/dev/evdev')
-rw-r--r-- | freebsd/sys/dev/evdev/cdev.c | 13 | ||||
-rw-r--r-- | freebsd/sys/dev/evdev/evdev.c | 44 | ||||
-rw-r--r-- | freebsd/sys/dev/evdev/evdev_private.h | 12 |
3 files changed, 68 insertions, 1 deletions
diff --git a/freebsd/sys/dev/evdev/cdev.c b/freebsd/sys/dev/evdev/cdev.c index 5ae14fed..a9370e7e 100644 --- a/freebsd/sys/dev/evdev/cdev.c +++ b/freebsd/sys/dev/evdev/cdev.c @@ -351,6 +351,19 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, if (client->ec_revoked || evdev == NULL) return (ENODEV); + /* + * Fix evdev state corrupted with discarding of kdb events. + * EVIOCGKEY and EVIOCGLED ioctls can suffer from this. + */ + if (evdev->ev_kdb_active) { + EVDEV_LOCK(evdev); + if (evdev->ev_kdb_active) { + evdev->ev_kdb_active = false; + evdev_restore_after_kdb(evdev); + } + EVDEV_UNLOCK(evdev); + } + /* file I/O ioctl handling */ switch (cmd) { case FIOSETOWN: diff --git a/freebsd/sys/dev/evdev/evdev.c b/freebsd/sys/dev/evdev/evdev.c index a355ec50..63e651a2 100644 --- a/freebsd/sys/dev/evdev/evdev.c +++ b/freebsd/sys/dev/evdev/evdev.c @@ -34,9 +34,11 @@ #include <sys/param.h> #include <sys/bitstring.h> #include <sys/conf.h> +#include <sys/kdb.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/module.h> +#include <sys/proc.h> #include <sys/sysctl.h> #include <sys/systm.h> @@ -769,6 +771,30 @@ evdev_send_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, } } +void +evdev_restore_after_kdb(struct evdev_dev *evdev) +{ + int code; + + EVDEV_LOCK_ASSERT(evdev); + + /* Report postponed leds */ + for (code = 0; code < LED_CNT; code++) + if (bit_test(evdev->ev_kdb_led_states, code)) + evdev_send_event(evdev, EV_LED, code, + !bit_test(evdev->ev_led_states, code)); + bit_nclear(evdev->ev_kdb_led_states, 0, LED_MAX); + + /* Release stuck keys (CTRL + ALT + ESC) */ + evdev_stop_repeat(evdev); + for (code = 0; code < KEY_CNT; code++) { + if (bit_test(evdev->ev_key_states, code)) { + evdev_send_event(evdev, EV_KEY, code, KEY_EVENT_UP); + evdev_send_event(evdev, EV_SYN, SYN_REPORT, 1); + } + } +} + int evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, int32_t value) @@ -777,8 +803,26 @@ evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, if (evdev_check_event(evdev, type, code, value) != 0) return (EINVAL); + /* + * Discard all but LEDs kdb events as unrelated to userspace. + * Aggregate LED updates and postpone reporting until kdb deactivation. + */ + if (kdb_active || SCHEDULER_STOPPED()) { + evdev->ev_kdb_active = true; + if (type == EV_LED) + bit_set(evdev->ev_kdb_led_states, + bit_test(evdev->ev_led_states, code) != value); + return (0); + } + EVDEV_ENTER(evdev); + /* Fix evdev state corrupted with discarding of kdb events */ + if (evdev->ev_kdb_active) { + evdev->ev_kdb_active = false; + evdev_restore_after_kdb(evdev); + } + evdev_modify_event(evdev, type, code, &value); if (type == EV_SYN && code == SYN_REPORT && bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) diff --git a/freebsd/sys/dev/evdev/evdev_private.h b/freebsd/sys/dev/evdev/evdev_private.h index 05206a9d..71bdecaa 100644 --- a/freebsd/sys/dev/evdev/evdev_private.h +++ b/freebsd/sys/dev/evdev/evdev_private.h @@ -117,6 +117,10 @@ struct evdev_dev bitstr_t bit_decl(ev_sw_states, SW_CNT); bool ev_report_opened; + /* KDB state: */ + bool ev_kdb_active; + bitstr_t bit_decl(ev_kdb_led_states, LED_CNT); + /* Multitouch protocol type B state: */ struct evdev_mt * ev_mt; @@ -132,9 +136,14 @@ struct evdev_dev LIST_HEAD(, evdev_client) ev_clients; }; +#define SYSTEM_CONSOLE_LOCK &Giant + #define EVDEV_LOCK(evdev) mtx_lock((evdev)->ev_lock) #define EVDEV_UNLOCK(evdev) mtx_unlock((evdev)->ev_lock) -#define EVDEV_LOCK_ASSERT(evdev) mtx_assert((evdev)->ev_lock, MA_OWNED) +#define EVDEV_LOCK_ASSERT(evdev) do { \ + if ((evdev)->ev_lock != SYSTEM_CONSOLE_LOCK) \ + mtx_assert((evdev)->ev_lock, MA_OWNED); \ +} while (0) #define EVDEV_ENTER(evdev) do { \ if ((evdev)->ev_lock_type == EV_LOCK_INTERNAL) \ EVDEV_LOCK(evdev); \ @@ -185,6 +194,7 @@ int evdev_cdev_destroy(struct evdev_dev *); bool evdev_event_supported(struct evdev_dev *, uint16_t); void evdev_set_abs_bit(struct evdev_dev *, uint16_t); void evdev_set_absinfo(struct evdev_dev *, uint16_t, struct input_absinfo *); +void evdev_restore_after_kdb(struct evdev_dev *); /* Client interface: */ int evdev_register_client(struct evdev_dev *, struct evdev_client *); |