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