diff --git a/repos/dde_linux/patches/usb_hid_evdev.patch b/repos/dde_linux/patches/usb_hid_evdev.patch index d9c6c2b498..1c1d039cc3 100644 --- a/repos/dde_linux/patches/usb_hid_evdev.patch +++ b/repos/dde_linux/patches/usb_hid_evdev.patch @@ -1,5 +1,5 @@ diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c -index c81c79d..c75bd8d 100644 +index c81c79d..a31b866 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -1425,6 +1425,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, @@ -10,7 +10,15 @@ index c81c79d..c75bd8d 100644 return 0; err_cleanup_evdev: -@@ -1456,8 +1457,7 @@ static const struct input_device_id evdev_ids[] = { +@@ -1445,6 +1446,7 @@ static void evdev_disconnect(struct input_handle *handle) + evdev_cleanup(evdev); + input_free_minor(MINOR(evdev->dev.devt)); + input_unregister_handle(handle); ++ mutex_destroy(&evdev->mutex); + put_device(&evdev->dev); + } + +@@ -1456,8 +1458,7 @@ static const struct input_device_id evdev_ids[] = { MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { diff --git a/repos/dde_linux/patches/usb_hid_hid.patch b/repos/dde_linux/patches/usb_hid_hid.patch new file mode 100644 index 0000000000..602106b94e --- /dev/null +++ b/repos/dde_linux/patches/usb_hid_hid.patch @@ -0,0 +1,12 @@ +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index c2560aa..0a45da0 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -2179,6 +2180,7 @@ static void hid_remove_device(struct hid_device *hdev) + kfree(hdev->dev_rdesc); + hdev->dev_rdesc = NULL; + hdev->dev_rsize = 0; ++ mutex_destroy(&hdev->ll_open_lock); + } + + /** diff --git a/repos/dde_linux/patches/usb_hid_input.patch b/repos/dde_linux/patches/usb_hid_input.patch new file mode 100644 index 0000000000..7f288d074f --- /dev/null +++ b/repos/dde_linux/patches/usb_hid_input.patch @@ -0,0 +1,20 @@ +diff --git a/drivers/input/input.c b/drivers/input/input.c +index 9785546..cf6f435 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -1885,6 +1885,7 @@ void input_free_device(struct input_dev *dev) + devm_input_device_release, + devm_input_device_match, + dev)); ++ mutex_destroy(&dev->mutex); + input_put_device(dev); + } + } +@@ -2024,6 +2025,7 @@ static void __input_unregister_device(struct input_dev *dev) + + mutex_unlock(&input_mutex); + ++ mutex_destroy(&dev->mutex); + device_del(&dev->dev); + } + diff --git a/repos/dde_linux/patches/usb_hid_usbhid.patch b/repos/dde_linux/patches/usb_hid_usbhid.patch index 5784fc1e36..b6d0cbf34d 100644 --- a/repos/dde_linux/patches/usb_hid_usbhid.patch +++ b/repos/dde_linux/patches/usb_hid_usbhid.patch @@ -1,8 +1,16 @@ diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c -index 77c50cd..55379da 100644 +index 77c50cd..b7d37b2 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c -@@ -1636,7 +1636,7 @@ struct usb_interface *usbhid_find_interface(int minor) +@@ -1386,6 +1386,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * + err_free: + kfree(usbhid); + err: ++ usb_set_intfdata(intf, NULL); + hid_destroy_device(hid); + return ret; + } +@@ -1636,7 +1637,7 @@ struct usb_interface *usbhid_find_interface(int minor) return usb_find_interface(&hid_driver, minor); } @@ -11,7 +19,7 @@ index 77c50cd..55379da 100644 { int retval = -ENOMEM; -@@ -1655,14 +1655,14 @@ usbhid_quirks_init_fail: +@@ -1655,14 +1656,14 @@ usbhid_quirks_init_fail: return retval; } diff --git a/repos/dde_linux/ports/dde_linux.hash b/repos/dde_linux/ports/dde_linux.hash index 38d42a3c8a..64d01989d6 100644 --- a/repos/dde_linux/ports/dde_linux.hash +++ b/repos/dde_linux/ports/dde_linux.hash @@ -1 +1 @@ -17ca56af6e9fde7df9b2ab6bdaa8f9b65c3bc533 +c928941836288b77a6f7337fd458d9308ed6cf80 diff --git a/repos/dde_linux/ports/dde_linux.port b/repos/dde_linux/ports/dde_linux.port index ebeb65b0a7..323882d826 100644 --- a/repos/dde_linux/ports/dde_linux.port +++ b/repos/dde_linux/ports/dde_linux.port @@ -215,6 +215,8 @@ USB_HID_OPT = -p1 -d$(SRC_DIR_USB_HID) PATCH_OPT(patches/usb_hid_usbhid.patch) := $(USB_HID_OPT) PATCH_OPT(patches/usb_hid_wacom_sys.patch) := $(USB_HID_OPT) PATCH_OPT(patches/usb_hid_evdev.patch) := $(USB_HID_OPT) +PATCH_OPT(patches/usb_hid_hid.patch) := $(USB_HID_OPT) +PATCH_OPT(patches/usb_hid_input.patch) := $(USB_HID_OPT) # USB NET USB_NET_OPT = -p1 -d$(SRC_DIR_USB_NET) diff --git a/repos/dde_linux/src/drivers/usb_hid/driver.h b/repos/dde_linux/src/drivers/usb_hid/driver.h index a3acc44d26..e4faeeecaa 100644 --- a/repos/dde_linux/src/drivers/usb_hid/driver.h +++ b/repos/dde_linux/src/drivers/usb_hid/driver.h @@ -31,18 +31,36 @@ struct Driver struct Task { - Lx::Task task; - Genode::Signal_handler handler; - bool handling_signal { false }; + Lx::Task task; + Genode::Signal_handler handler; + bool handling_signal { false }; + + /* + * If the task is currently executing and the signal handler + * is called again via 'block_and_schedule()', we need to + * keep this information, so the task does not block at the + * end when a new signal already occurred. + * + * Initialized as true for the initial run of the task. + */ + bool _signal_pending { true }; void handle_signal() { + _signal_pending = true; task.unblock(); handling_signal = true; Lx::scheduler().schedule(); handling_signal = false; } - + + bool signal_pending() + { + bool ret = _signal_pending; + _signal_pending = false; + return ret; + } + template Task(Genode::Entrypoint & ep, ARGS &&... args) : task(args...), handler(ep, *this, &Task::handle_signal) {} @@ -56,7 +74,13 @@ struct Driver Label label; Driver &driver; Genode::Env &env; - Genode::Allocator_avl &alloc; + + /* + * Dedicated allocator per device to notice dangling + * allocations on device destruction. + */ + Genode::Allocator_avl alloc; + Task state_task; Task urb_task; @@ -101,7 +125,6 @@ struct Driver Genode::Env &env; Genode::Entrypoint &ep { env.ep() }; Genode::Heap heap { env.ram(), env.rm() }; - Genode::Allocator_avl alloc { &heap }; Event::Connection event { env }; Genode::Constructible main_task; Genode::Constructible report_rom; diff --git a/repos/dde_linux/src/drivers/usb_hid/dummies.c b/repos/dde_linux/src/drivers/usb_hid/dummies.c index 852c98a265..6fc8b0275b 100644 --- a/repos/dde_linux/src/drivers/usb_hid/dummies.c +++ b/repos/dde_linux/src/drivers/usb_hid/dummies.c @@ -259,7 +259,7 @@ int input_event_to_user(char __user *buffer, const struct input_event *event) struct input_dev; void input_ff_destroy(struct input_dev *dev) { - TRACE_AND_STOP; + TRACE; } struct ff_effect; @@ -327,22 +327,6 @@ struct device *kobj_to_dev(struct kobject *kobj) return NULL; } -void kref_get(struct kref *kref) -{ - TRACE_AND_STOP; -} - -void kref_init(struct kref *kref) -{ - TRACE; -} - -int kref_put(struct kref *kref, void (*release) (struct kref *kref)) -{ - TRACE_AND_STOP; - return -1; -} - int kstrtou8(const char *s, unsigned int base, u8 *res) { TRACE_AND_STOP; @@ -410,7 +394,7 @@ void __module_get(struct module *module) void module_put(struct module * module) { - TRACE_AND_STOP; + TRACE; } loff_t no_llseek(struct file *file, loff_t offset, int whence) @@ -525,7 +509,7 @@ void usb_block_urb(struct urb *urb) struct usb_device; int usb_clear_halt(struct usb_device *dev, int pipe) { - TRACE_AND_STOP; + TRACE; return -1; } @@ -538,7 +522,7 @@ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, struct usb_interface; void usb_queue_reset_device(struct usb_interface *dev) { - TRACE_AND_STOP; + TRACE; } int usb_string(struct usb_device *dev, int index, char *buf, size_t size) @@ -645,11 +629,6 @@ void power_supply_changed(struct power_supply *psy) TRACE_AND_STOP; } -void put_device(struct device *dev) -{ - TRACE; -} - int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) { TRACE; diff --git a/repos/dde_linux/src/drivers/usb_hid/lx_emul.cc b/repos/dde_linux/src/drivers/usb_hid/lx_emul.cc index e96f879834..2223e51251 100644 --- a/repos/dde_linux/src/drivers/usb_hid/lx_emul.cc +++ b/repos/dde_linux/src/drivers/usb_hid/lx_emul.cc @@ -101,9 +101,18 @@ struct Lx_driver Lx_driver(device_driver & drv) : dev_drv(drv) { list().insert(&le); } - bool match(struct device *dev) { + bool match(struct device *dev) + { + /* + * Don't try if buses don't match, since drivers often use 'container_of' + * which might cast the device to non-matching type + */ + if (dev_drv.bus != dev->bus) + return false; + return dev_drv.bus->match ? dev_drv.bus->match(dev, &dev_drv) - : false; } + : false; + } int probe(struct device *dev) { @@ -296,11 +305,25 @@ void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags, d struct device *get_device(struct device *dev) { - //dev->ref++; + dev->ref++; return dev; } +void put_device(struct device *dev) +{ + if (dev->ref) { + dev->ref--; + return; + } + + if (dev->release) + dev->release(dev); + else if (dev->type && dev->type->release) + dev->type->release(dev); +} + + void cdev_init(struct cdev *c, const struct file_operations *fops) { c->ops = fops; @@ -309,7 +332,7 @@ void cdev_init(struct cdev *c, const struct file_operations *fops) void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma) { - //kfree(dev); + kfree(addr); } @@ -611,3 +634,29 @@ void *kmemdup(const void *src, size_t size, gfp_t flags) return addr; } + +/****************** + ** linux/kref.h ** + ******************/ + +void kref_init(struct kref *kref) +{ + atomic_set(&kref->refcount, 1); +} + + +void kref_get(struct kref *kref) +{ + atomic_inc(&kref->refcount); +} + + +int kref_put(struct kref *kref, void (*release) (struct kref *kref)) +{ + if(!atomic_dec_return(&kref->refcount)) { + release(kref); + return 1; + } + return 0; +} + diff --git a/repos/dde_linux/src/drivers/usb_hid/lx_emul.h b/repos/dde_linux/src/drivers/usb_hid/lx_emul.h index 2395d51cc2..e68b8e5c05 100644 --- a/repos/dde_linux/src/drivers/usb_hid/lx_emul.h +++ b/repos/dde_linux/src/drivers/usb_hid/lx_emul.h @@ -126,6 +126,7 @@ struct device const struct device_type * type; void (*release)(struct device *dev); void * driver_data; + unsigned ref; }; void down(struct semaphore *sem); @@ -630,6 +631,7 @@ void genode_evdev_event(struct input_handle *handle, unsigned int type, unsigned struct usb_device; extern int usb_get_configuration(struct usb_device *dev); +extern void usb_destroy_configuration(struct usb_device *dev); struct usb_hcd { unsigned amd_resume_bug:1; }; diff --git a/repos/dde_linux/src/drivers/usb_hid/main.cc b/repos/dde_linux/src/drivers/usb_hid/main.cc index 0c20e8e6a7..328bfe124a 100644 --- a/repos/dde_linux/src/drivers/usb_hid/main.cc +++ b/repos/dde_linux/src/drivers/usb_hid/main.cc @@ -13,12 +13,13 @@ #include +#include +#include + #include #include #include - -#include -#include +#include #include #include @@ -40,13 +41,11 @@ void Driver::Device::register_device() udev = (usb_device*) kzalloc(sizeof(usb_device), GFP_KERNEL); udev->bus = (usb_bus*) kzalloc(sizeof(usb_bus), GFP_KERNEL); - udev->config = (usb_host_config*) kzalloc(sizeof(usb_host_config), GFP_KERNEL); udev->bus->bus_name = "usbbus"; udev->bus->controller = (device*) (&usb); udev->bus_mA = 900; /* set to maximum USB3.0 */ Genode::memcpy(&udev->descriptor, &dev_desc, sizeof(usb_device_descriptor)); - Genode::memcpy(&udev->config->desc, &config_desc, sizeof(usb_config_descriptor)); udev->devnum = dev_desc.num; udev->speed = (usb_device_speed) dev_desc.speed; udev->authorized = 1; @@ -56,9 +55,19 @@ void Driver::Device::register_device() Genode::error("usb_get_configuration returned error ", cfg); return; } + usb_detect_interface_quirks(udev); cfg = usb_choose_configuration(udev); - usb_set_configuration(udev, cfg); + if (cfg < 0) { + Genode::error("usb_choose_configuration returned error ", cfg); + return; + } + + int ret = usb_set_configuration(udev, cfg); + if (ret < 0) { + Genode::error("usb_set_configuration returned error ", ret); + return; + } for (int i = 0; i < udev->config->desc.bNumInterfaces; i++) { struct usb_interface * iface = udev->config->interface[i]; @@ -84,8 +93,8 @@ void Driver::Device::unregister_device() if (!udev->config->interface[i]) break; else remove_interface(udev->config->interface[i]); } + usb_destroy_configuration(udev); kfree(udev->bus); - kfree(udev->config); kfree(udev); udev = nullptr; } @@ -96,12 +105,13 @@ void Driver::Device::state_task_entry(void * arg) Device & dev = *reinterpret_cast(arg); for (;;) { - if (dev.usb.plugged() && !dev.udev) - dev.register_device(); - - if (!dev.usb.plugged() && dev.udev) - dev.unregister_device(); + while (dev.state_task.signal_pending()) { + if (dev.usb.plugged() && !dev.udev) + dev.register_device(); + if (!dev.usb.plugged() && dev.udev) + dev.unregister_device(); + } Lx::scheduler().current()->block_and_schedule(); } } @@ -127,7 +137,7 @@ Driver::Device::Device(Driver & driver, Label label) : label(label), driver(driver), env(driver.env), - alloc(driver.alloc), + alloc(&driver.heap), state_task(env.ep(), state_task_entry, reinterpret_cast(this), "usb_state", Lx::Task::PRIORITY_0, Lx::scheduler()), urb_task(env.ep(), urb_task_entry, reinterpret_cast(this), @@ -193,10 +203,12 @@ void Driver::main_task_entry(void * arg) " (multitouch=", multi_touch ? "true" : "false", ")"); for (;;) { - if (!use_report) - static Device dev(*driver, Label("")); - else - driver->scan_report(); + while (driver->main_task->signal_pending()) { + if (!use_report) + static Device dev(*driver, Label("")); + else + driver->scan_report(); + } Lx::scheduler().current()->block_and_schedule(); } } @@ -289,6 +301,7 @@ Driver::Driver(Genode::Env &env) : env(env) Lx::scheduler(&env); Lx::timer(&env, &ep, &heap, &jiffies); + Lx::Work::work_queue(&heap); main_task.construct(env.ep(), main_task_entry, reinterpret_cast(this), "main", Lx::Task::PRIORITY_0, Lx::scheduler());