diff options
| author | Vladimir Kondratyev <wulf@FreeBSD.org> | 2018-11-17 20:18:15 +0000 |
|---|---|---|
| committer | Vladimir Kondratyev <wulf@FreeBSD.org> | 2018-11-17 20:18:15 +0000 |
| commit | 04a7a36d95a6948ec1b1b86fe098b9fc71168bdc (patch) | |
| tree | 47686b820215d8179bb1fd6e645e44d8ace9f6cd /sys/dev/evdev/evdev.c | |
| parent | 70c13856e27464fe887a922e2a937de05354f1de (diff) | |
Notes
Diffstat (limited to 'sys/dev/evdev/evdev.c')
| -rw-r--r-- | sys/dev/evdev/evdev.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/sys/dev/evdev/evdev.c b/sys/dev/evdev/evdev.c index a119cbbc3ea0..2f5eb11b96b2 100644 --- a/sys/dev/evdev/evdev.c +++ b/sys/dev/evdev/evdev.c @@ -32,9 +32,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> @@ -763,6 +765,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) @@ -771,8 +797,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)) |
