usb_hid_drv: stability improvements

Fixes #4007
This commit is contained in:
Christian Prochaska 2021-02-01 05:46:11 +01:00 committed by Norman Feske
parent e1698cf200
commit 33406940f3
11 changed files with 174 additions and 58 deletions

View File

@ -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 = {

View File

@ -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);
}
/**

View File

@ -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);
}

View File

@ -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;
}

View File

@ -1 +1 @@
17ca56af6e9fde7df9b2ab6bdaa8f9b65c3bc533
c928941836288b77a6f7337fd458d9308ed6cf80

View File

@ -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)

View File

@ -31,18 +31,36 @@ struct Driver
struct Task
{
Lx::Task task;
Genode::Signal_handler<Task> handler;
bool handling_signal { false };
Lx::Task task;
Genode::Signal_handler<Task> 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 <typename... ARGS>
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<Task> main_task;
Genode::Constructible<Genode::Attached_rom_dataspace> report_rom;

View File

@ -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;

View File

@ -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;
}

View File

@ -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; };

View File

@ -13,12 +13,13 @@
#include <base/component.h>
#include <driver.h>
#include <lx_emul.h>
#include <lx_kit/env.h>
#include <lx_kit/scheduler.h>
#include <lx_kit/timer.h>
#include <driver.h>
#include <lx_emul.h>
#include <lx_kit/work.h>
#include <lx_emul/extern_c_begin.h>
#include <linux/hid.h>
@ -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<Device*>(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<void*>(this),
"usb_state", Lx::Task::PRIORITY_0, Lx::scheduler()),
urb_task(env.ep(), urb_task_entry, reinterpret_cast<void*>(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<void*>(this),
"main", Lx::Task::PRIORITY_0, Lx::scheduler());