aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2008-11-24 10:20:09 -0500
committerJiri Kosina <jkosina@suse.cz>2009-01-03 19:00:52 -0500
commit3a6f82f7a22cf19687f556997c6978b31c109360 (patch)
tree0b3a34f0c2035beb21c6d15af33207d3057bcdaf
parent898089d08f983ef0fdb176267620543a7929826a (diff)
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 <jirislaby@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-core.c101
-rw-r--r--include/linux/hid.h5
2 files changed, 103 insertions, 3 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 344f8fdb2824..34cc3b0d01f6 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[] = {
1304 { } 1304 { }
1305}; 1305};
1306 1306
1307struct hid_dynid {
1308 struct list_head list;
1309 struct hid_device_id id;
1310};
1311
1312/**
1313 * store_new_id - add a new HID device ID to this driver and re-probe devices
1314 * @driver: target device driver
1315 * @buf: buffer for scanning device ID data
1316 * @count: input size
1317 *
1318 * Adds a new dynamic hid device ID to this driver,
1319 * and causes the driver to probe for all devices again.
1320 */
1321static ssize_t store_new_id(struct device_driver *drv, const char *buf,
1322 size_t count)
1323{
1324 struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
1325 struct hid_dynid *dynid;
1326 __u32 bus, vendor, product;
1327 unsigned long driver_data = 0;
1328 int ret;
1329
1330 ret = sscanf(buf, "%x %x %x %lx",
1331 &bus, &vendor, &product, &driver_data);
1332 if (ret < 3)
1333 return -EINVAL;
1334
1335 dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
1336 if (!dynid)
1337 return -ENOMEM;
1338
1339 dynid->id.bus = bus;
1340 dynid->id.vendor = vendor;
1341 dynid->id.product = product;
1342 dynid->id.driver_data = driver_data;
1343
1344 spin_lock(&hdrv->dyn_lock);
1345 list_add_tail(&dynid->list, &hdrv->dyn_list);
1346 spin_unlock(&hdrv->dyn_lock);
1347
1348 ret = 0;
1349 if (get_driver(&hdrv->driver)) {
1350 ret = driver_attach(&hdrv->driver);
1351 put_driver(&hdrv->driver);
1352 }
1353
1354 return ret ? : count;
1355}
1356static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
1357
1358static void hid_free_dynids(struct hid_driver *hdrv)
1359{
1360 struct hid_dynid *dynid, *n;
1361
1362 spin_lock(&hdrv->dyn_lock);
1363 list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) {
1364 list_del(&dynid->list);
1365 kfree(dynid);
1366 }
1367 spin_unlock(&hdrv->dyn_lock);
1368}
1369
1370static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
1371 struct hid_driver *hdrv)
1372{
1373 struct hid_dynid *dynid;
1374
1375 spin_lock(&hdrv->dyn_lock);
1376 list_for_each_entry(dynid, &hdrv->dyn_list, list) {
1377 if (hid_match_one_id(hdev, &dynid->id)) {
1378 spin_unlock(&hdrv->dyn_lock);
1379 return &dynid->id;
1380 }
1381 }
1382 spin_unlock(&hdrv->dyn_lock);
1383
1384 return hid_match_id(hdev, hdrv->id_table);
1385}
1386
1307static int hid_bus_match(struct device *dev, struct device_driver *drv) 1387static int hid_bus_match(struct device *dev, struct device_driver *drv)
1308{ 1388{
1309 struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver); 1389 struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
1310 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 1390 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
1311 1391
1312 if (!hid_match_id(hdev, hdrv->id_table)) 1392 if (!hid_match_device(hdev, hdrv))
1313 return 0; 1393 return 0;
1314 1394
1315 /* generic wants all non-blacklisted */ 1395 /* generic wants all non-blacklisted */
@@ -1328,7 +1408,7 @@ static int hid_device_probe(struct device *dev)
1328 int ret = 0; 1408 int ret = 0;
1329 1409
1330 if (!hdev->driver) { 1410 if (!hdev->driver) {
1331 id = hid_match_id(hdev, hdrv->id_table); 1411 id = hid_match_device(hdev, hdrv);
1332 if (id == NULL) 1412 if (id == NULL)
1333 return -ENODEV; 1413 return -ENODEV;
1334 1414
@@ -1695,18 +1775,33 @@ EXPORT_SYMBOL_GPL(hid_destroy_device);
1695int __hid_register_driver(struct hid_driver *hdrv, struct module *owner, 1775int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
1696 const char *mod_name) 1776 const char *mod_name)
1697{ 1777{
1778 int ret;
1779
1698 hdrv->driver.name = hdrv->name; 1780 hdrv->driver.name = hdrv->name;
1699 hdrv->driver.bus = &hid_bus_type; 1781 hdrv->driver.bus = &hid_bus_type;
1700 hdrv->driver.owner = owner; 1782 hdrv->driver.owner = owner;
1701 hdrv->driver.mod_name = mod_name; 1783 hdrv->driver.mod_name = mod_name;
1702 1784
1703 return driver_register(&hdrv->driver); 1785 INIT_LIST_HEAD(&hdrv->dyn_list);
1786 spin_lock_init(&hdrv->dyn_lock);
1787
1788 ret = driver_register(&hdrv->driver);
1789 if (ret)
1790 return ret;
1791
1792 ret = driver_create_file(&hdrv->driver, &driver_attr_new_id);
1793 if (ret)
1794 driver_unregister(&hdrv->driver);
1795
1796 return ret;
1704} 1797}
1705EXPORT_SYMBOL_GPL(__hid_register_driver); 1798EXPORT_SYMBOL_GPL(__hid_register_driver);
1706 1799
1707void hid_unregister_driver(struct hid_driver *hdrv) 1800void hid_unregister_driver(struct hid_driver *hdrv)
1708{ 1801{
1802 driver_remove_file(&hdrv->driver, &driver_attr_new_id);
1709 driver_unregister(&hdrv->driver); 1803 driver_unregister(&hdrv->driver);
1804 hid_free_dynids(hdrv);
1710} 1805}
1711EXPORT_SYMBOL_GPL(hid_unregister_driver); 1806EXPORT_SYMBOL_GPL(hid_unregister_driver);
1712 1807
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 2c20f20283b2..215035bbb288 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -531,6 +531,8 @@ struct hid_usage_id {
531 * @name: driver name (e.g. "Footech_bar-wheel") 531 * @name: driver name (e.g. "Footech_bar-wheel")
532 * @id_table: which devices is this driver for (must be non-NULL for probe 532 * @id_table: which devices is this driver for (must be non-NULL for probe
533 * to be called) 533 * to be called)
534 * @dyn_list: list of dynamically added device ids
535 * @dyn_lock: lock protecting @dyn_list
534 * @probe: new device inserted 536 * @probe: new device inserted
535 * @remove: device removed (NULL if not a hot-plug capable driver) 537 * @remove: device removed (NULL if not a hot-plug capable driver)
536 * @report_table: on which reports to call raw_event (NULL means all) 538 * @report_table: on which reports to call raw_event (NULL means all)
@@ -558,6 +560,9 @@ struct hid_driver {
558 char *name; 560 char *name;
559 const struct hid_device_id *id_table; 561 const struct hid_device_id *id_table;
560 562
563 struct list_head dyn_list;
564 spinlock_t dyn_lock;
565
561 int (*probe)(struct hid_device *dev, const struct hid_device_id *id); 566 int (*probe)(struct hid_device *dev, const struct hid_device_id *id);
562 void (*remove)(struct hid_device *dev); 567 void (*remove)(struct hid_device *dev);
563 568