Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>


+117 -21
+19 -16
drivers/usb/core/driver.c
··· 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; ··· 57 65 dynid->id.idProduct = idProduct; 58 66 dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; 59 67 60 - spin_lock(&usb_drv->dynids.lock); 61 - list_add_tail(&usb_drv->dynids.list, &dynid->node); 62 - spin_unlock(&usb_drv->dynids.lock); 68 + spin_lock(&dynids->lock); 69 + list_add_tail(&dynids->list, &dynid->node); 70 + spin_unlock(&dynids->lock); 63 71 64 72 if (get_driver(driver)) { 65 73 retval = driver_attach(driver); ··· 69 77 if (retval) 70 78 return retval; 71 79 return count; 80 + } 81 + EXPORT_SYMBOL_GPL(usb_store_new_id); 82 + 83 + static ssize_t store_new_id(struct device_driver *driver, 84 + const char *buf, size_t count) 85 + { 86 + struct usb_driver *usb_drv = to_usb_driver(driver); 87 + 88 + return usb_store_new_id(&usb_drv->dynids, driver, buf, count); 72 89 } 73 90 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); 74 91 ··· 366 365 EXPORT_SYMBOL(usb_driver_release_interface); 367 366 368 367 /* returns 0 if no match, 1 if match */ 369 - static int usb_match_one_id(struct usb_interface *interface, 370 - const struct usb_device_id *id) 368 + int usb_match_one_id(struct usb_interface *interface, 369 + const struct usb_device_id *id) 371 370 { 372 371 struct usb_host_interface *intf; 373 372 struct usb_device *dev; ··· 433 432 434 433 return 1; 435 434 } 435 + EXPORT_SYMBOL_GPL(usb_match_one_id); 436 + 436 437 /** 437 438 * usb_match_id - find first usb_device_id matching device or interface 438 439 * @interface: the interface of interest
+45
drivers/usb/serial/bus.c
··· 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) ··· 156 115 int retval; 157 116 158 117 driver->driver.bus = &usb_serial_bus_type; 118 + spin_lock_init(&driver->dynids.lock); 119 + INIT_LIST_HEAD(&driver->dynids.list); 120 + 159 121 retval = driver_register(&driver->driver); 160 122 161 123 return retval; ··· 166 122 167 123 void usb_serial_bus_deregister(struct usb_serial_driver *driver) 168 124 { 125 + free_dynids(driver); 169 126 driver_unregister(&driver->driver); 170 127 } 171 128
+36 -5
drivers/usb/serial/usb-serial.c
··· 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; ··· 638 605 /* Check if the usb id matches a known device */ 639 606 list_for_each(p, &usb_serial_driver_list) { 640 607 t = list_entry(p, struct usb_serial_driver, driver_list); 641 - id = usb_match_id(iface, t->id_table); 642 - if (id != NULL) { 643 - dbg("descriptor matches"); 608 + id = get_iface_id(t, iface); 609 + if (id) 644 610 return t; 645 - } 646 611 } 647 612 648 613 return NULL; ··· 692 661 return -EIO; 693 662 } 694 663 695 - id = usb_match_id(interface, type->id_table); 664 + id = get_iface_id(type, interface); 696 665 retval = type->probe(serial, id); 697 666 module_put(type->driver.owner); 698 667
+12
include/linux/usb.h
··· 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); ··· 726 724 727 725 /* ----------------------------------------------------------------------- */ 728 726 727 + /* Stuff for dynamic usb ids */ 729 728 struct usb_dynids { 730 729 spinlock_t lock; 731 730 struct list_head list; 732 731 }; 732 + 733 + struct usb_dynid { 734 + struct list_head node; 735 + struct usb_device_id id; 736 + }; 737 + 738 + extern ssize_t usb_store_new_id(struct usb_dynids *dynids, 739 + struct device_driver *driver, 740 + const char *buf, size_t count); 733 741 734 742 /** 735 743 * struct usbdrv_wrap - wrapper for driver-model structure
+5
include/linux/usb/serial.h
··· 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 ··· 205 202 206 203 struct list_head driver_list; 207 204 struct device_driver driver; 205 + struct usb_driver *usb_driver; 206 + struct usb_dynids dynids; 208 207 209 208 int (*probe) (struct usb_serial *serial, const struct usb_device_id *id); 210 209 int (*attach) (struct usb_serial *serial);