From 0ed94b334265b6ee3e3336b4fedacfa9cb2ccaba Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Nov 2008 16:20:07 +0100 Subject: HID: move usbhid flags to usbhid.h Move usbhid specific flags from global hid.h into local usbhid.h. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- include/linux/hid.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'include/linux/hid.h') diff --git a/include/linux/hid.h b/include/linux/hid.h index e5780f8c934..2c20f20283b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -403,15 +403,6 @@ struct hid_output_fifo { #define HID_STAT_ADDED 1 #define HID_STAT_PARSED 2 -#define HID_CTRL_RUNNING 1 -#define HID_OUT_RUNNING 2 -#define HID_IN_RUNNING 3 -#define HID_RESET_PENDING 4 -#define HID_SUSPENDED 5 -#define HID_CLEAR_HALT 6 -#define HID_DISCONNECTED 7 -#define HID_STARTED 8 - struct hid_input { struct list_head list; struct hid_report *report; -- cgit v1.2.3-70-g09d2 From 3a6f82f7a22cf19687f556997c6978b31c109360 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 24 Nov 2008 16:20:09 +0100 Subject: HID: add dynids facility Allow adding new devices to the hid drivers on the fly without a need of kernel recompilation. Now, one can test a driver e.g. by: echo 0003:045E:00F0.0003 > ../generic-usb/unbind echo 0003 045E 00F0 > new_id from some driver subdir. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/hid.h | 5 +++ 2 files changed, 103 insertions(+), 3 deletions(-) (limited to 'include/linux/hid.h') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 344f8fdb282..34cc3b0d01f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1304,12 +1304,92 @@ static const struct hid_device_id hid_blacklist[] = { { } }; +struct hid_dynid { + struct list_head list; + struct hid_device_id id; +}; + +/** + * store_new_id - add a new HID device ID to this driver and re-probe devices + * @driver: target device driver + * @buf: buffer for scanning device ID data + * @count: input size + * + * Adds a new dynamic hid device ID to this driver, + * and causes the driver to probe for all devices again. + */ +static ssize_t store_new_id(struct device_driver *drv, const char *buf, + size_t count) +{ + struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver); + struct hid_dynid *dynid; + __u32 bus, vendor, product; + unsigned long driver_data = 0; + int ret; + + ret = sscanf(buf, "%x %x %x %lx", + &bus, &vendor, &product, &driver_data); + if (ret < 3) + return -EINVAL; + + dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); + if (!dynid) + return -ENOMEM; + + dynid->id.bus = bus; + dynid->id.vendor = vendor; + dynid->id.product = product; + dynid->id.driver_data = driver_data; + + spin_lock(&hdrv->dyn_lock); + list_add_tail(&dynid->list, &hdrv->dyn_list); + spin_unlock(&hdrv->dyn_lock); + + ret = 0; + if (get_driver(&hdrv->driver)) { + ret = driver_attach(&hdrv->driver); + put_driver(&hdrv->driver); + } + + return ret ? : count; +} +static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); + +static void hid_free_dynids(struct hid_driver *hdrv) +{ + struct hid_dynid *dynid, *n; + + spin_lock(&hdrv->dyn_lock); + list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) { + list_del(&dynid->list); + kfree(dynid); + } + spin_unlock(&hdrv->dyn_lock); +} + +static const struct hid_device_id *hid_match_device(struct hid_device *hdev, + struct hid_driver *hdrv) +{ + struct hid_dynid *dynid; + + spin_lock(&hdrv->dyn_lock); + list_for_each_entry(dynid, &hdrv->dyn_list, list) { + if (hid_match_one_id(hdev, &dynid->id)) { + spin_unlock(&hdrv->dyn_lock); + return &dynid->id; + } + } + spin_unlock(&hdrv->dyn_lock); + + return hid_match_id(hdev, hdrv->id_table); +} + static int hid_bus_match(struct device *dev, struct device_driver *drv) { struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver); struct hid_device *hdev = container_of(dev, struct hid_device, dev); - if (!hid_match_id(hdev, hdrv->id_table)) + if (!hid_match_device(hdev, hdrv)) return 0; /* generic wants all non-blacklisted */ @@ -1328,7 +1408,7 @@ static int hid_device_probe(struct device *dev) int ret = 0; if (!hdev->driver) { - id = hid_match_id(hdev, hdrv->id_table); + id = hid_match_device(hdev, hdrv); if (id == NULL) return -ENODEV; @@ -1695,18 +1775,33 @@ EXPORT_SYMBOL_GPL(hid_destroy_device); int __hid_register_driver(struct hid_driver *hdrv, struct module *owner, const char *mod_name) { + int ret; + hdrv->driver.name = hdrv->name; hdrv->driver.bus = &hid_bus_type; hdrv->driver.owner = owner; hdrv->driver.mod_name = mod_name; - return driver_register(&hdrv->driver); + INIT_LIST_HEAD(&hdrv->dyn_list); + spin_lock_init(&hdrv->dyn_lock); + + ret = driver_register(&hdrv->driver); + if (ret) + return ret; + + ret = driver_create_file(&hdrv->driver, &driver_attr_new_id); + if (ret) + driver_unregister(&hdrv->driver); + + return ret; } EXPORT_SYMBOL_GPL(__hid_register_driver); void hid_unregister_driver(struct hid_driver *hdrv) { + driver_remove_file(&hdrv->driver, &driver_attr_new_id); driver_unregister(&hdrv->driver); + hid_free_dynids(hdrv); } EXPORT_SYMBOL_GPL(hid_unregister_driver); diff --git a/include/linux/hid.h b/include/linux/hid.h index 2c20f20283b..215035bbb28 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -531,6 +531,8 @@ struct hid_usage_id { * @name: driver name (e.g. "Footech_bar-wheel") * @id_table: which devices is this driver for (must be non-NULL for probe * to be called) + * @dyn_list: list of dynamically added device ids + * @dyn_lock: lock protecting @dyn_list * @probe: new device inserted * @remove: device removed (NULL if not a hot-plug capable driver) * @report_table: on which reports to call raw_event (NULL means all) @@ -558,6 +560,9 @@ struct hid_driver { char *name; const struct hid_device_id *id_table; + struct list_head dyn_list; + spinlock_t dyn_lock; + int (*probe)(struct hid_device *dev, const struct hid_device_id *id); void (*remove)(struct hid_device *dev); -- cgit v1.2.3-70-g09d2 From 725cf0f47dbb02e0482f081828cff73f55479b79 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Tue, 16 Dec 2008 14:20:23 +0100 Subject: HID: avoid sparse warning in HID_COMPAT_LOAD_DRIVER Impact: include a prototype for the exported function in the macro Fix about 20 of this warnings: drivers/hid/hid-a4tech.c:162:1: warning: symbol 'hid_compat_a4tech' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: Jiri Kosina --- include/linux/hid.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux/hid.h') diff --git a/include/linux/hid.h b/include/linux/hid.h index 215035bbb28..81aa84d60c6 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -793,6 +793,8 @@ dbg_hid(const char *fmt, ...) #ifdef CONFIG_HID_COMPAT #define HID_COMPAT_LOAD_DRIVER(name) \ +/* prototype to avoid sparse warning */ \ +extern void hid_compat_##name(void); \ void hid_compat_##name(void) { } \ EXPORT_SYMBOL(hid_compat_##name) #else -- cgit v1.2.3-70-g09d2