From 092e4a001f928068e2d1c72421275d1b462de303 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Fri, 19 Jan 2024 14:46:59 +0100 Subject: [PATCH] usb_hid: mode led handling to shadow input-leds.c The former implementation relied on input drvdata always pointing to struct hid_device, which is not true for Wacom touch devices (at least). Now, we implement the input handler for devices providing LEDs (evbit[EV_LED] set) only and use input_inject_event() to set the LED states. --- repos/dde_linux/run/usb_hid_raw.run | 40 +++- repos/dde_linux/run/usb_hid_reconnect.run | 2 +- repos/dde_linux/src/drivers/usb_hid/led.c | 206 ------------------ repos/dde_linux/src/drivers/usb_hid/main.cc | 7 +- .../src/drivers/usb_hid/spec/arm/source.list | 10 +- .../drivers/usb_hid/spec/arm_64/source.list | 10 +- .../drivers/usb_hid/spec/x86_32/source.list | 8 +- .../drivers/usb_hid/spec/x86_64/source.list | 8 +- .../dde_linux/src/drivers/usb_hid/target.inc | 2 +- .../src/include/lx_emul/input_leds.h | 27 +++ .../lib/lx_emul/shadow/drivers/input/evdev.c | 3 + .../lx_emul/shadow/drivers/input/input-leds.c | 160 ++++++++++++++ .../raw/drivers_interactive-pc/drivers.config | 2 +- 13 files changed, 244 insertions(+), 241 deletions(-) delete mode 100644 repos/dde_linux/src/drivers/usb_hid/led.c create mode 100644 repos/dde_linux/src/include/lx_emul/input_leds.h create mode 100644 repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/input-leds.c diff --git a/repos/dde_linux/run/usb_hid_raw.run b/repos/dde_linux/run/usb_hid_raw.run index d010438db2..8e4733dac7 100644 --- a/repos/dde_linux/run/usb_hid_raw.run +++ b/repos/dde_linux/run/usb_hid_raw.run @@ -113,7 +113,7 @@ install_config { - + @@ -132,23 +132,41 @@ install_config { - - - - - - - + + + + + + + + + + + + + + + + + + + - - + + + + + + - + + + diff --git a/repos/dde_linux/run/usb_hid_reconnect.run b/repos/dde_linux/run/usb_hid_reconnect.run index c61113451d..84b024a409 100644 --- a/repos/dde_linux/run/usb_hid_reconnect.run +++ b/repos/dde_linux/run/usb_hid_reconnect.run @@ -68,7 +68,7 @@ install_config { - + diff --git a/repos/dde_linux/src/drivers/usb_hid/led.c b/repos/dde_linux/src/drivers/usb_hid/led.c deleted file mode 100644 index 70d577e491..0000000000 --- a/repos/dde_linux/src/drivers/usb_hid/led.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * \brief Keyboard LED handling - * \author Sebastian Sumpf - * \date 2023-06-29 - */ - -/* - * Copyright (C) 2023 Genode Labs GmbH - * - * This file is distributed under the terms of the GNU General Public License - * version 2. - */ - -#include -#include -#include -#include - -struct keyboard -{ - struct input_dev *input_dev; - struct usb_interface *intf; - struct usb_device *udev; - struct list_head list; -}; - - -enum Update_state { NONE, UPDATE, BLOCKED }; - -struct led_update -{ - enum Update_state state; - struct completion update; - unsigned leds; -}; - - -static LIST_HEAD(_keyboards); -static struct led_update _led_update; - - -static bool keyboard_match(struct keyboard *kbd, struct input_dev *input_dev) -{ - return kbd->input_dev == input_dev; -} - - -static void keyboard_update(struct keyboard *kbd, unsigned leds) -{ - usb_control_msg(kbd->udev, usb_sndctrlpipe(kbd->udev, 0), - 0x9, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x200, - kbd->intf->cur_altsetting->desc.bInterfaceNumber, - &leds, 1, 500); -} - - -void lx_led_state_update(bool capslock, bool numlock, bool scrlock) -{ - - struct keyboard *kbd; - unsigned leds = 0; - - leds |= capslock ? 1u << LED_CAPSL : 0; - leds |= numlock ? 1u << LED_NUML : 0; - leds |= scrlock ? 1u << LED_SCROLLL : 0; - - _led_update.leds = leds; - _led_update.state = UPDATE; - - /* udpdate keyboards */ - list_for_each_entry(kbd, &_keyboards, list) { - keyboard_update(kbd, leds); - } - - if (_led_update.state == BLOCKED) - complete(&_led_update.update); - - _led_update.state = NONE; -} - - -static void wait_for_update(void) -{ - if (_led_update.state == UPDATE) { - _led_update.state = BLOCKED; - wait_for_completion(&_led_update.update); - } -} - - -static int led_connect(struct input_handler *handler, struct input_dev *dev, - const struct input_device_id *id) -{ - struct keyboard *kbd; - struct input_handle *handle; - - wait_for_update(); - - handle = (struct input_handle *)kzalloc(sizeof(*handle), 0); - if (!handle) return -ENOMEM; - handle->dev = input_get_device(dev); - handle->handler = handler; - - kbd = (struct keyboard *)kzalloc(sizeof(*kbd), GFP_KERNEL); - if (!kbd) goto err; - - kbd->input_dev = input_get_device(dev); - kbd->intf = container_of(kbd->input_dev->dev.parent->parent, struct usb_interface, dev); - kbd->udev = interface_to_usbdev(kbd->intf); - - INIT_LIST_HEAD(&kbd->list); - list_add_tail(&kbd->list, &_keyboards); - - keyboard_update(kbd, _led_update.leds); - - input_register_handle(handle); - - return 0; - -err: - kfree(handle); - return -ENOMEM; -} - - -static void led_disconnect(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - struct keyboard *kbd, *temp; - - wait_for_update(); - - list_for_each_entry_safe(kbd, temp, &_keyboards, list) { - if (keyboard_match(kbd, dev)) { - list_del(&kbd->list); - kfree(kbd); - } - } - input_unregister_handle(handle); - input_put_device(dev); - kfree(handle); -} - - -static bool led_match(struct input_handler *handler, struct input_dev *dev) -{ - struct hid_device *hid = (struct hid_device *)input_get_drvdata(dev); - struct hid_report *report; - struct hid_usage *usage; - unsigned i, j; - - /* search report for keyboard entries */ - list_for_each_entry(report, &hid->report_enum[0].report_list, list) { - - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) { - usage = report->field[i]->usage + j; - if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) { - return true; - } - } - } - - return false; -} - - -static struct input_device_id led_ids[] = { - { .driver_info = 1 }, /* match all */ - { }, -}; - - -MODULE_DEVICE_TABLE(input, led_ids); - -static struct input_handler led_handler = { - .name = "keyboard_led", - .connect = led_connect, - .disconnect = led_disconnect, - .id_table = led_ids, - .match = led_match, - .id_table = led_ids, -}; - - -static int __init input_leds_init(void) -{ - _led_update.state = NONE; - init_completion(&_led_update.update); - - return input_register_handler(&led_handler); -} - - -static void __exit input_leds_exit(void) -{ - input_unregister_handler(&led_handler); -} - - -/** - * Let's hook into the input_leds initcall, so we do not need to register - * an additional one - */ -module_init(input_leds_init); -module_exit(input_leds_exit); diff --git a/repos/dde_linux/src/drivers/usb_hid/main.cc b/repos/dde_linux/src/drivers/usb_hid/main.cc index 2c3a39c60a..475283b421 100644 --- a/repos/dde_linux/src/drivers/usb_hid/main.cc +++ b/repos/dde_linux/src/drivers/usb_hid/main.cc @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -127,9 +128,9 @@ struct Leds while (true) { led.handle_config(); - lx_led_state_update(led.capslock.enabled(), - led.numlock.enabled(), - led.scrlock.enabled()); + lx_emul_input_leds_update(led.capslock.enabled(), + led.numlock.enabled(), + led.scrlock.enabled()); led.led_task_handler.block_and_schedule(); } diff --git a/repos/dde_linux/src/drivers/usb_hid/spec/arm/source.list b/repos/dde_linux/src/drivers/usb_hid/spec/arm/source.list index ae8c5f44bf..1c71bd091f 100644 --- a/repos/dde_linux/src/drivers/usb_hid/spec/arm/source.list +++ b/repos/dde_linux/src/drivers/usb_hid/spec/arm/source.list @@ -6,11 +6,11 @@ arch/arm/lib/strchr.S arch/arm/lib/testclearbit.S arch/arm/lib/testsetbit.S drivers/base/bus.c -drivers/base/core.c drivers/base/class.c +drivers/base/core.c +drivers/base/dd.c drivers/base/devres.c drivers/base/driver.c -drivers/base/dd.c drivers/base/property.c drivers/hid/hid-apple.c drivers/hid/hid-cherry.c @@ -41,8 +41,8 @@ kernel/time/clocksource.c kernel/time/hrtimer.c kernel/time/jiffies.c kernel/time/ntp.c -kernel/time/tick-broadcast.c kernel/time/tick-broadcast-hrtimer.c +kernel/time/tick-broadcast.c kernel/time/tick-common.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c @@ -53,7 +53,6 @@ kernel/time/timekeeping.c kernel/time/timer.c kernel/time/timer_list.c kernel/workqueue.c -mm/util.c lib/bitmap.c lib/ctype.c lib/find_bit.c @@ -65,8 +64,9 @@ lib/klist.c lib/kobject.c lib/kstrtox.c lib/radix-tree.c -lib/xarray.c lib/siphash.c lib/string.c lib/string_helpers.c lib/vsprintf.c +lib/xarray.c +mm/util.c diff --git a/repos/dde_linux/src/drivers/usb_hid/spec/arm_64/source.list b/repos/dde_linux/src/drivers/usb_hid/spec/arm_64/source.list index a7e5322d02..4c3af31d34 100644 --- a/repos/dde_linux/src/drivers/usb_hid/spec/arm_64/source.list +++ b/repos/dde_linux/src/drivers/usb_hid/spec/arm_64/source.list @@ -4,11 +4,11 @@ arch/arm64/lib/strcmp.S arch/arm64/lib/strlen.S arch/arm64/lib/strncmp.S drivers/base/bus.c -drivers/base/core.c drivers/base/class.c +drivers/base/core.c +drivers/base/dd.c drivers/base/devres.c drivers/base/driver.c -drivers/base/dd.c drivers/base/property.c drivers/hid/hid-apple.c drivers/hid/hid-cherry.c @@ -39,8 +39,8 @@ kernel/time/clocksource.c kernel/time/hrtimer.c kernel/time/jiffies.c kernel/time/ntp.c -kernel/time/tick-broadcast.c kernel/time/tick-broadcast-hrtimer.c +kernel/time/tick-broadcast.c kernel/time/tick-common.c kernel/time/tick-oneshot.c kernel/time/tick-sched.c @@ -51,7 +51,6 @@ kernel/time/timekeeping.c kernel/time/timer.c kernel/time/timer_list.c kernel/workqueue.c -mm/util.c lib/bitmap.c lib/ctype.c lib/find_bit.c @@ -63,8 +62,9 @@ lib/klist.c lib/kobject.c lib/kstrtox.c lib/radix-tree.c -lib/xarray.c lib/siphash.c lib/string.c lib/string_helpers.c lib/vsprintf.c +lib/xarray.c +mm/util.c diff --git a/repos/dde_linux/src/drivers/usb_hid/spec/x86_32/source.list b/repos/dde_linux/src/drivers/usb_hid/spec/x86_32/source.list index 77ec7252cc..9c03c946ec 100644 --- a/repos/dde_linux/src/drivers/usb_hid/spec/x86_32/source.list +++ b/repos/dde_linux/src/drivers/usb_hid/spec/x86_32/source.list @@ -1,10 +1,10 @@ arch/x86/lib/hweight.S drivers/base/bus.c -drivers/base/core.c drivers/base/class.c +drivers/base/core.c +drivers/base/dd.c drivers/base/devres.c drivers/base/driver.c -drivers/base/dd.c drivers/base/property.c drivers/hid/hid-apple.c drivers/hid/hid-cherry.c @@ -46,7 +46,6 @@ kernel/time/timekeeping.c kernel/time/timer.c kernel/time/timer_list.c kernel/workqueue.c -mm/util.c lib/bitmap.c lib/ctype.c lib/find_bit.c @@ -57,8 +56,9 @@ lib/klist.c lib/kobject.c lib/kstrtox.c lib/radix-tree.c -lib/xarray.c lib/siphash.c lib/string.c lib/string_helpers.c lib/vsprintf.c +lib/xarray.c +mm/util.c diff --git a/repos/dde_linux/src/drivers/usb_hid/spec/x86_64/source.list b/repos/dde_linux/src/drivers/usb_hid/spec/x86_64/source.list index 77ec7252cc..9c03c946ec 100644 --- a/repos/dde_linux/src/drivers/usb_hid/spec/x86_64/source.list +++ b/repos/dde_linux/src/drivers/usb_hid/spec/x86_64/source.list @@ -1,10 +1,10 @@ arch/x86/lib/hweight.S drivers/base/bus.c -drivers/base/core.c drivers/base/class.c +drivers/base/core.c +drivers/base/dd.c drivers/base/devres.c drivers/base/driver.c -drivers/base/dd.c drivers/base/property.c drivers/hid/hid-apple.c drivers/hid/hid-cherry.c @@ -46,7 +46,6 @@ kernel/time/timekeeping.c kernel/time/timer.c kernel/time/timer_list.c kernel/workqueue.c -mm/util.c lib/bitmap.c lib/ctype.c lib/find_bit.c @@ -57,8 +56,9 @@ lib/klist.c lib/kobject.c lib/kstrtox.c lib/radix-tree.c -lib/xarray.c lib/siphash.c lib/string.c lib/string_helpers.c lib/vsprintf.c +lib/xarray.c +mm/util.c diff --git a/repos/dde_linux/src/drivers/usb_hid/target.inc b/repos/dde_linux/src/drivers/usb_hid/target.inc index 27784ba841..f6624d91fa 100644 --- a/repos/dde_linux/src/drivers/usb_hid/target.inc +++ b/repos/dde_linux/src/drivers/usb_hid/target.inc @@ -5,11 +5,11 @@ INC_DIR = $(PRG_DIR)/../.. $(REP_DIR)/src/lib/usb_client SRC_C += dummies.c \ generated_dummies.c \ - led.c \ lx_emul.c \ lx_user.c SRC_C += lx_emul/shadow/drivers/input/evdev.c \ + lx_emul/shadow/drivers/input/input-leds.c \ lx_emul/virt/shadow/drivers/usb/core/message.c \ lx_emul/virt/shadow/drivers/usb/core/urb.c \ lx_emul/virt/usb_client.c diff --git a/repos/dde_linux/src/include/lx_emul/input_leds.h b/repos/dde_linux/src/include/lx_emul/input_leds.h new file mode 100644 index 0000000000..864d5ac11a --- /dev/null +++ b/repos/dde_linux/src/include/lx_emul/input_leds.h @@ -0,0 +1,27 @@ +/* + * \brief Lx_emul support for input leds + * \author Christian Helmuth + * \date 2024-01-19 + */ + +/* + * Copyright (C) 2024 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#ifndef _LX_EMUL__INPUT_LEDS_H_ +#define _LX_EMUL__INPUT_LEDS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void lx_emul_input_leds_update(bool capslock, bool numlock, bool scrolllock); + +#ifdef __cplusplus +} +#endif + +#endif /* _LX_EMUL__INPUT_LEDS_H_ */ diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/evdev.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/evdev.c index 4b4f14555f..368efec88f 100644 --- a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/evdev.c +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/evdev.c @@ -311,6 +311,9 @@ static void evdev_event_generator(struct genode_event_generator_ctx *ctx, bool processed = false; + /* filter injected EV_LED updates */ + if (v->type == EV_LED) continue; + /* filter input_repeat_key() */ if ((v->type == EV_KEY) && (v->value > 1)) continue; diff --git a/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/input-leds.c b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/input-leds.c new file mode 100644 index 0000000000..be2a00f820 --- /dev/null +++ b/repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/input-leds.c @@ -0,0 +1,160 @@ +/* + * \brief Input LED handling + * \author Sebastian Sumpf + * \author Christian Helmuth + * \date 2023-06-29 + * + * This implementation is derived from drivers/input/input-leds.c. + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include +#include +#include + +#include + + +struct led_handler +{ + struct list_head list; + struct input_handle handle; +}; + +static LIST_HEAD(led_handlers); + + +enum Update_state { NONE, UPDATE, BLOCKED }; + +struct led_update +{ + enum Update_state state; + struct completion update; + + bool capsl, numl, scrolll; +}; + +static struct led_update led_update; + + +static void update_leds(struct led_handler *handler) +{ + input_inject_event(&handler->handle, EV_LED, LED_CAPSL, led_update.capsl); + input_inject_event(&handler->handle, EV_LED, LED_NUML, led_update.numl); + input_inject_event(&handler->handle, EV_LED, LED_SCROLLL, led_update.scrolll); +} + + +void lx_emul_input_leds_update(bool capslock, bool numlock, bool scrolllock) +{ + + struct led_handler *handler; + + led_update.state = UPDATE; + + led_update.capsl = capslock; + led_update.numl = numlock; + led_update.scrolll = scrolllock; + + list_for_each_entry(handler, &led_handlers, list) { + update_leds(handler); + } + + if (led_update.state == BLOCKED) + complete(&led_update.update); + + led_update.state = NONE; +} + + +static void wait_for_update(void) +{ + if (led_update.state == UPDATE) { + led_update.state = BLOCKED; + wait_for_completion(&led_update.update); + } +} + + +static int input_leds_connect(struct input_handler *input_handler, struct input_dev *dev, + const struct input_device_id *id) +{ + struct led_handler *handler; + + wait_for_update(); + + handler = (struct led_handler *)kzalloc(sizeof(*handler), GFP_KERNEL); + if (!handler) + return -ENOMEM; + + handler->handle.dev = input_get_device(dev); + handler->handle.handler = input_handler; + handler->handle.name = "leds"; + handler->handle.private = handler; + + INIT_LIST_HEAD(&handler->list); + list_add_tail(&handler->list, &led_handlers); + + update_leds(handler); + + input_register_handle(&handler->handle); + + return 0; +} + + +static void input_leds_disconnect(struct input_handle *handle) +{ + struct led_handler *handler = (struct led_handler *)handle->private; + + wait_for_update(); + + list_del(&handler->list); + input_unregister_handle(handle); + input_put_device(handle->dev); + kfree(handler); +} + + +static struct input_device_id input_leds_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_LED) }, + }, +}; + + +MODULE_DEVICE_TABLE(input, led_ids); + +static struct input_handler input_leds_handler = { + .name = "input-leds", + .connect = input_leds_connect, + .disconnect = input_leds_disconnect, + .id_table = input_leds_ids, +}; + + +static int __init input_leds_init(void) +{ + led_update.state = NONE; + init_completion(&led_update.update); + + return input_register_handler(&input_leds_handler); +} + + +static void __exit input_leds_exit(void) +{ + input_unregister_handler(&input_leds_handler); +} + + +module_init(input_leds_init); +module_exit(input_leds_exit); diff --git a/repos/os/recipes/raw/drivers_interactive-pc/drivers.config b/repos/os/recipes/raw/drivers_interactive-pc/drivers.config index c1debc2167..ca56b90c26 100644 --- a/repos/os/recipes/raw/drivers_interactive-pc/drivers.config +++ b/repos/os/recipes/raw/drivers_interactive-pc/drivers.config @@ -138,7 +138,7 @@ - +