summaryrefslogtreecommitdiff
path: root/sys/dev/evdev/evdev.c
diff options
context:
space:
mode:
authorVladimir Kondratyev <wulf@FreeBSD.org>2018-11-17 20:18:15 +0000
committerVladimir Kondratyev <wulf@FreeBSD.org>2018-11-17 20:18:15 +0000
commit04a7a36d95a6948ec1b1b86fe098b9fc71168bdc (patch)
tree47686b820215d8179bb1fd6e645e44d8ace9f6cd /sys/dev/evdev/evdev.c
parent70c13856e27464fe887a922e2a937de05354f1de (diff)
Notes
Diffstat (limited to 'sys/dev/evdev/evdev.c')
-rw-r--r--sys/dev/evdev/evdev.c44
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))