Commit 93bacefc4cc0b53e1cb6a336d43847154fdf6886

Authored by Greg Kroah-Hartman
1 parent 495a678fc6

USB serial: add dynamic id support to usb-serial core

Thanks to Johannes Hölzl <johannes.hoelzl@gmx.de> for fixing a few
things and getting it all working properly.

This adds support for dynamic usb ids to the usb serial core.  The file
"new_id" will show up under the usb serial driver, not the usb driver
associated with the usb-serial driver (yeah, it can be a bit confusing
at first glance...)

This patch also modifies the USB core to allow the usb-serial core to
reuse much of the dynamic id logic.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Johannes Hölzl <johannes.hoelzl@gmx.de>

Showing 5 changed files with 117 additions and 21 deletions Side-by-side Diff

drivers/usb/core/driver.c
... ... @@ -28,24 +28,16 @@
28 28 #include "hcd.h"
29 29 #include "usb.h"
30 30  
31   -static int usb_match_one_id(struct usb_interface *interface,
32   - const struct usb_device_id *id);
33   -
34   -struct usb_dynid {
35   - struct list_head node;
36   - struct usb_device_id id;
37   -};
38   -
39 31 #ifdef CONFIG_HOTPLUG
40 32  
41 33 /*
42 34 * Adds a new dynamic USBdevice ID to this driver,
43 35 * and cause the driver to probe for all devices again.
44 36 */
45   -static ssize_t store_new_id(struct device_driver *driver,
46   - const char *buf, size_t count)
  37 +ssize_t usb_store_new_id(struct usb_dynids *dynids,
  38 + struct device_driver *driver,
  39 + const char *buf, size_t count)
47 40 {
48   - struct usb_driver *usb_drv = to_usb_driver(driver);
49 41 struct usb_dynid *dynid;
50 42 u32 idVendor = 0;
51 43 u32 idProduct = 0;
... ... @@ -65,9 +57,9 @@
65 57 dynid->id.idProduct = idProduct;
66 58 dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
67 59  
68   - spin_lock(&usb_drv->dynids.lock);
69   - list_add_tail(&usb_drv->dynids.list, &dynid->node);
70   - spin_unlock(&usb_drv->dynids.lock);
  60 + spin_lock(&dynids->lock);
  61 + list_add_tail(&dynids->list, &dynid->node);
  62 + spin_unlock(&dynids->lock);
71 63  
72 64 if (get_driver(driver)) {
73 65 retval = driver_attach(driver);
... ... @@ -78,6 +70,15 @@
78 70 return retval;
79 71 return count;
80 72 }
  73 +EXPORT_SYMBOL_GPL(usb_store_new_id);
  74 +
  75 +static ssize_t store_new_id(struct device_driver *driver,
  76 + const char *buf, size_t count)
  77 +{
  78 + struct usb_driver *usb_drv = to_usb_driver(driver);
  79 +
  80 + return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
  81 +}
81 82 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
82 83  
83 84 static int usb_create_newid_file(struct usb_driver *usb_drv)
... ... @@ -365,8 +366,8 @@
365 366 EXPORT_SYMBOL(usb_driver_release_interface);
366 367  
367 368 /* returns 0 if no match, 1 if match */
368   -static int usb_match_one_id(struct usb_interface *interface,
369   - const struct usb_device_id *id)
  369 +int usb_match_one_id(struct usb_interface *interface,
  370 + const struct usb_device_id *id)
370 371 {
371 372 struct usb_host_interface *intf;
372 373 struct usb_device *dev;
... ... @@ -432,6 +433,8 @@
432 433  
433 434 return 1;
434 435 }
  436 +EXPORT_SYMBOL_GPL(usb_match_one_id);
  437 +
435 438 /**
436 439 * usb_match_id - find first usb_device_id matching device or interface
437 440 * @interface: the interface of interest
drivers/usb/serial/bus.c
... ... @@ -103,11 +103,52 @@
103 103 return retval;
104 104 }
105 105  
  106 +#ifdef CONFIG_HOTPLUG
  107 +static ssize_t store_new_id(struct device_driver *driver,
  108 + const char *buf, size_t count)
  109 +{
  110 + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
  111 + ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
  112 +
  113 + if (retval >= 0 && usb_drv->usb_driver != NULL)
  114 + retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
  115 + &usb_drv->usb_driver->drvwrap.driver,
  116 + buf, count);
  117 + return retval;
  118 +}
  119 +
  120 +static struct driver_attribute drv_attrs[] = {
  121 + __ATTR(new_id, S_IWUSR, NULL, store_new_id),
  122 + __ATTR_NULL,
  123 +};
  124 +
  125 +static void free_dynids(struct usb_serial_driver *drv)
  126 +{
  127 + struct usb_dynid *dynid, *n;
  128 +
  129 + spin_lock(&drv->dynids.lock);
  130 + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
  131 + list_del(&dynid->node);
  132 + kfree(dynid);
  133 + }
  134 + spin_unlock(&drv->dynids.lock);
  135 +}
  136 +
  137 +#else
  138 +static struct driver_attribute drv_attrs[] = {
  139 + __ATTR_NULL,
  140 +};
  141 +static inline void free_dynids(struct usb_driver *drv)
  142 +{
  143 +}
  144 +#endif
  145 +
106 146 struct bus_type usb_serial_bus_type = {
107 147 .name = "usb-serial",
108 148 .match = usb_serial_device_match,
109 149 .probe = usb_serial_device_probe,
110 150 .remove = usb_serial_device_remove,
  151 + .drv_attrs = drv_attrs,
111 152 };
112 153  
113 154 int usb_serial_bus_register(struct usb_serial_driver *driver)
... ... @@ -115,6 +156,9 @@
115 156 int retval;
116 157  
117 158 driver->driver.bus = &usb_serial_bus_type;
  159 + spin_lock_init(&driver->dynids.lock);
  160 + INIT_LIST_HEAD(&driver->dynids.list);
  161 +
118 162 retval = driver_register(&driver->driver);
119 163  
120 164 return retval;
... ... @@ -122,6 +166,7 @@
122 166  
123 167 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
124 168 {
  169 + free_dynids(driver);
125 170 driver_unregister(&driver->driver);
126 171 }
drivers/usb/serial/usb-serial.c
... ... @@ -596,6 +596,39 @@
596 596 return serial;
597 597 }
598 598  
  599 +static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
  600 + struct usb_serial_driver *drv)
  601 +{
  602 + struct usb_dynid *dynid;
  603 +
  604 + spin_lock(&drv->dynids.lock);
  605 + list_for_each_entry(dynid, &drv->dynids.list, node) {
  606 + if (usb_match_one_id(intf, &dynid->id)) {
  607 + spin_unlock(&drv->dynids.lock);
  608 + return &dynid->id;
  609 + }
  610 + }
  611 + spin_unlock(&drv->dynids.lock);
  612 + return NULL;
  613 +}
  614 +
  615 +static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
  616 + struct usb_interface *intf)
  617 +{
  618 + const struct usb_device_id *id;
  619 +
  620 + id = usb_match_id(intf, drv->id_table);
  621 + if (id) {
  622 + dbg("static descriptor matches");
  623 + goto exit;
  624 + }
  625 + id = match_dynamic_id(intf, drv);
  626 + if (id)
  627 + dbg("dynamic descriptor matches");
  628 +exit:
  629 + return id;
  630 +}
  631 +
599 632 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
600 633 {
601 634 struct list_head *p;
602 635  
... ... @@ -605,11 +638,9 @@
605 638 /* Check if the usb id matches a known device */
606 639 list_for_each(p, &usb_serial_driver_list) {
607 640 t = list_entry(p, struct usb_serial_driver, driver_list);
608   - id = usb_match_id(iface, t->id_table);
609   - if (id != NULL) {
610   - dbg("descriptor matches");
  641 + id = get_iface_id(t, iface);
  642 + if (id)
611 643 return t;
612   - }
613 644 }
614 645  
615 646 return NULL;
... ... @@ -661,7 +692,7 @@
661 692 return -EIO;
662 693 }
663 694  
664   - id = usb_match_id(interface, type->id_table);
  695 + id = get_iface_id(type, interface);
665 696 retval = type->probe(serial, id);
666 697 module_put(type->driver.owner);
667 698  
... ... @@ -476,6 +476,8 @@
476 476 struct usb_interface *iface);
477 477 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
478 478 const struct usb_device_id *id);
  479 +extern int usb_match_one_id(struct usb_interface *interface,
  480 + const struct usb_device_id *id);
479 481  
480 482 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
481 483 int minor);
482 484  
... ... @@ -724,10 +726,20 @@
724 726  
725 727 /* ----------------------------------------------------------------------- */
726 728  
  729 +/* Stuff for dynamic usb ids */
727 730 struct usb_dynids {
728 731 spinlock_t lock;
729 732 struct list_head list;
730 733 };
  734 +
  735 +struct usb_dynid {
  736 + struct list_head node;
  737 + struct usb_device_id id;
  738 +};
  739 +
  740 +extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
  741 + struct device_driver *driver,
  742 + const char *buf, size_t count);
731 743  
732 744 /**
733 745 * struct usbdrv_wrap - wrapper for driver-model structure
include/linux/usb/serial.h
... ... @@ -179,6 +179,9 @@
179 179 * memory structure allocation at this point in time.
180 180 * @shutdown: pointer to the driver's shutdown function. This will be
181 181 * called when the device is removed from the system.
  182 + * @usb_driver: pointer to the struct usb_driver that controls this
  183 + * device. This is necessary to allow dynamic ids to be added to
  184 + * the driver from sysfs.
182 185 *
183 186 * This structure is defines a USB Serial driver. It provides all of
184 187 * the information that the USB serial core code needs. If the function
... ... @@ -202,6 +205,8 @@
202 205  
203 206 struct list_head driver_list;
204 207 struct device_driver driver;
  208 + struct usb_driver *usb_driver;
  209 + struct usb_dynids dynids;
205 210  
206 211 int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
207 212 int (*attach) (struct usb_serial *serial);