diff options
| -rw-r--r-- | drivers/usb/core/driver.c | 218 | ||||
| -rw-r--r-- | include/linux/usb.h | 8 |
2 files changed, 176 insertions, 50 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 921a21be651d..1c0611045379 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
| @@ -27,6 +27,15 @@ | |||
| 27 | #include "hcd.h" | 27 | #include "hcd.h" |
| 28 | #include "usb.h" | 28 | #include "usb.h" |
| 29 | 29 | ||
| 30 | static int usb_match_one_id(struct usb_interface *interface, | ||
| 31 | const struct usb_device_id *id); | ||
| 32 | |||
| 33 | struct usb_dynid { | ||
| 34 | struct list_head node; | ||
| 35 | struct usb_device_id id; | ||
| 36 | }; | ||
| 37 | |||
| 38 | |||
| 30 | static int generic_probe(struct device *dev) | 39 | static int generic_probe(struct device *dev) |
| 31 | { | 40 | { |
| 32 | return 0; | 41 | return 0; |
| @@ -58,6 +67,96 @@ struct device_driver usb_generic_driver = { | |||
| 58 | * usb device or a usb interface. */ | 67 | * usb device or a usb interface. */ |
| 59 | int usb_generic_driver_data; | 68 | int usb_generic_driver_data; |
| 60 | 69 | ||
| 70 | #ifdef CONFIG_HOTPLUG | ||
| 71 | |||
| 72 | /* | ||
| 73 | * Adds a new dynamic USBdevice ID to this driver, | ||
| 74 | * and cause the driver to probe for all devices again. | ||
| 75 | */ | ||
| 76 | static ssize_t store_new_id(struct device_driver *driver, | ||
| 77 | const char *buf, size_t count) | ||
| 78 | { | ||
| 79 | struct usb_driver *usb_drv = to_usb_driver(driver); | ||
| 80 | struct usb_dynid *dynid; | ||
| 81 | u32 idVendor = 0; | ||
| 82 | u32 idProduct = 0; | ||
| 83 | int fields = 0; | ||
| 84 | |||
| 85 | fields = sscanf(buf, "%x %x", &idVendor, &idProduct); | ||
| 86 | if (fields < 2) | ||
| 87 | return -EINVAL; | ||
| 88 | |||
| 89 | dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); | ||
| 90 | if (!dynid) | ||
| 91 | return -ENOMEM; | ||
| 92 | |||
| 93 | INIT_LIST_HEAD(&dynid->node); | ||
| 94 | dynid->id.idVendor = idVendor; | ||
| 95 | dynid->id.idProduct = idProduct; | ||
| 96 | dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; | ||
| 97 | |||
| 98 | spin_lock(&usb_drv->dynids.lock); | ||
| 99 | list_add_tail(&usb_drv->dynids.list, &dynid->node); | ||
| 100 | spin_unlock(&usb_drv->dynids.lock); | ||
| 101 | |||
| 102 | if (get_driver(driver)) { | ||
| 103 | driver_attach(driver); | ||
| 104 | put_driver(driver); | ||
| 105 | } | ||
| 106 | |||
| 107 | return count; | ||
| 108 | } | ||
| 109 | static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); | ||
| 110 | |||
| 111 | static int usb_create_newid_file(struct usb_driver *usb_drv) | ||
| 112 | { | ||
| 113 | int error = 0; | ||
| 114 | |||
| 115 | if (usb_drv->probe != NULL) | ||
| 116 | error = sysfs_create_file(&usb_drv->driver.kobj, | ||
| 117 | &driver_attr_new_id.attr); | ||
| 118 | return error; | ||
| 119 | } | ||
| 120 | |||
| 121 | static void usb_free_dynids(struct usb_driver *usb_drv) | ||
| 122 | { | ||
| 123 | struct usb_dynid *dynid, *n; | ||
| 124 | |||
| 125 | spin_lock(&usb_drv->dynids.lock); | ||
| 126 | list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) { | ||
| 127 | list_del(&dynid->node); | ||
| 128 | kfree(dynid); | ||
| 129 | } | ||
| 130 | spin_unlock(&usb_drv->dynids.lock); | ||
| 131 | } | ||
| 132 | #else | ||
| 133 | static inline int usb_create_newid_file(struct usb_driver *usb_drv) | ||
| 134 | { | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline void usb_free_dynids(struct usb_driver *usb_drv) | ||
| 139 | { | ||
| 140 | } | ||
| 141 | #endif | ||
| 142 | |||
| 143 | static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf, | ||
| 144 | struct usb_driver *drv) | ||
| 145 | { | ||
| 146 | struct usb_dynid *dynid; | ||
| 147 | |||
| 148 | spin_lock(&drv->dynids.lock); | ||
| 149 | list_for_each_entry(dynid, &drv->dynids.list, node) { | ||
| 150 | if (usb_match_one_id(intf, &dynid->id)) { | ||
| 151 | spin_unlock(&drv->dynids.lock); | ||
| 152 | return &dynid->id; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | spin_unlock(&drv->dynids.lock); | ||
| 156 | return NULL; | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 61 | /* called from driver core with usb_bus_type.subsys writelock */ | 160 | /* called from driver core with usb_bus_type.subsys writelock */ |
| 62 | static int usb_probe_interface(struct device *dev) | 161 | static int usb_probe_interface(struct device *dev) |
| 63 | { | 162 | { |
| @@ -75,6 +174,8 @@ static int usb_probe_interface(struct device *dev) | |||
| 75 | return -EHOSTUNREACH; | 174 | return -EHOSTUNREACH; |
| 76 | 175 | ||
| 77 | id = usb_match_id(intf, driver->id_table); | 176 | id = usb_match_id(intf, driver->id_table); |
| 177 | if (!id) | ||
| 178 | id = usb_match_dynamic_id(intf, driver); | ||
| 78 | if (id) { | 179 | if (id) { |
| 79 | dev_dbg(dev, "%s - got id\n", __FUNCTION__); | 180 | dev_dbg(dev, "%s - got id\n", __FUNCTION__); |
| 80 | 181 | ||
| @@ -120,6 +221,64 @@ static int usb_unbind_interface(struct device *dev) | |||
| 120 | return 0; | 221 | return 0; |
| 121 | } | 222 | } |
| 122 | 223 | ||
| 224 | /* returns 0 if no match, 1 if match */ | ||
| 225 | static int usb_match_one_id(struct usb_interface *interface, | ||
| 226 | const struct usb_device_id *id) | ||
| 227 | { | ||
| 228 | struct usb_host_interface *intf; | ||
| 229 | struct usb_device *dev; | ||
| 230 | |||
| 231 | /* proc_connectinfo in devio.c may call us with id == NULL. */ | ||
| 232 | if (id == NULL) | ||
| 233 | return 0; | ||
| 234 | |||
| 235 | intf = interface->cur_altsetting; | ||
| 236 | dev = interface_to_usbdev(interface); | ||
| 237 | |||
| 238 | if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && | ||
| 239 | id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) | ||
| 240 | return 0; | ||
| 241 | |||
| 242 | if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && | ||
| 243 | id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) | ||
| 244 | return 0; | ||
| 245 | |||
| 246 | /* No need to test id->bcdDevice_lo != 0, since 0 is never | ||
| 247 | greater than any unsigned number. */ | ||
| 248 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && | ||
| 249 | (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) | ||
| 250 | return 0; | ||
| 251 | |||
| 252 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && | ||
| 253 | (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) | ||
| 254 | return 0; | ||
| 255 | |||
| 256 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && | ||
| 257 | (id->bDeviceClass != dev->descriptor.bDeviceClass)) | ||
| 258 | return 0; | ||
| 259 | |||
| 260 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && | ||
| 261 | (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) | ||
| 262 | return 0; | ||
| 263 | |||
| 264 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && | ||
| 265 | (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) | ||
| 266 | return 0; | ||
| 267 | |||
| 268 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && | ||
| 269 | (id->bInterfaceClass != intf->desc.bInterfaceClass)) | ||
| 270 | return 0; | ||
| 271 | |||
| 272 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && | ||
| 273 | (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass)) | ||
| 274 | return 0; | ||
| 275 | |||
| 276 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && | ||
| 277 | (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) | ||
| 278 | return 0; | ||
| 279 | |||
| 280 | return 1; | ||
| 281 | } | ||
| 123 | /** | 282 | /** |
| 124 | * usb_match_id - find first usb_device_id matching device or interface | 283 | * usb_match_id - find first usb_device_id matching device or interface |
| 125 | * @interface: the interface of interest | 284 | * @interface: the interface of interest |
| @@ -184,16 +343,10 @@ static int usb_unbind_interface(struct device *dev) | |||
| 184 | const struct usb_device_id *usb_match_id(struct usb_interface *interface, | 343 | const struct usb_device_id *usb_match_id(struct usb_interface *interface, |
| 185 | const struct usb_device_id *id) | 344 | const struct usb_device_id *id) |
| 186 | { | 345 | { |
| 187 | struct usb_host_interface *intf; | ||
| 188 | struct usb_device *dev; | ||
| 189 | |||
| 190 | /* proc_connectinfo in devio.c may call us with id == NULL. */ | 346 | /* proc_connectinfo in devio.c may call us with id == NULL. */ |
| 191 | if (id == NULL) | 347 | if (id == NULL) |
| 192 | return NULL; | 348 | return NULL; |
| 193 | 349 | ||
| 194 | intf = interface->cur_altsetting; | ||
| 195 | dev = interface_to_usbdev(interface); | ||
| 196 | |||
| 197 | /* It is important to check that id->driver_info is nonzero, | 350 | /* It is important to check that id->driver_info is nonzero, |
| 198 | since an entry that is all zeroes except for a nonzero | 351 | since an entry that is all zeroes except for a nonzero |
| 199 | id->driver_info is the way to create an entry that | 352 | id->driver_info is the way to create an entry that |
| @@ -201,50 +354,8 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, | |||
| 201 | device and interface. */ | 354 | device and interface. */ |
| 202 | for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || | 355 | for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || |
| 203 | id->driver_info; id++) { | 356 | id->driver_info; id++) { |
| 204 | 357 | if (usb_match_one_id(interface, id)) | |
| 205 | if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && | 358 | return id; |
| 206 | id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) | ||
| 207 | continue; | ||
| 208 | |||
| 209 | if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && | ||
| 210 | id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) | ||
| 211 | continue; | ||
| 212 | |||
| 213 | /* No need to test id->bcdDevice_lo != 0, since 0 is never | ||
| 214 | greater than any unsigned number. */ | ||
| 215 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && | ||
| 216 | (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) | ||
| 217 | continue; | ||
| 218 | |||
| 219 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && | ||
| 220 | (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) | ||
| 221 | continue; | ||
| 222 | |||
| 223 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && | ||
| 224 | (id->bDeviceClass != dev->descriptor.bDeviceClass)) | ||
| 225 | continue; | ||
| 226 | |||
| 227 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && | ||
| 228 | (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass)) | ||
| 229 | continue; | ||
| 230 | |||
| 231 | if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && | ||
| 232 | (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) | ||
| 233 | continue; | ||
| 234 | |||
| 235 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && | ||
| 236 | (id->bInterfaceClass != intf->desc.bInterfaceClass)) | ||
| 237 | continue; | ||
| 238 | |||
| 239 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && | ||
| 240 | (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass)) | ||
| 241 | continue; | ||
| 242 | |||
| 243 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && | ||
| 244 | (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) | ||
| 245 | continue; | ||
| 246 | |||
| 247 | return id; | ||
| 248 | } | 359 | } |
| 249 | 360 | ||
| 250 | return NULL; | 361 | return NULL; |
| @@ -268,6 +379,9 @@ int usb_device_match(struct device *dev, struct device_driver *drv) | |||
| 268 | if (id) | 379 | if (id) |
| 269 | return 1; | 380 | return 1; |
| 270 | 381 | ||
| 382 | id = usb_match_dynamic_id(intf, usb_drv); | ||
| 383 | if (id) | ||
| 384 | return 1; | ||
| 271 | return 0; | 385 | return 0; |
| 272 | } | 386 | } |
| 273 | 387 | ||
| @@ -296,6 +410,8 @@ int usb_register(struct usb_driver *new_driver) | |||
| 296 | new_driver->driver.probe = usb_probe_interface; | 410 | new_driver->driver.probe = usb_probe_interface; |
| 297 | new_driver->driver.remove = usb_unbind_interface; | 411 | new_driver->driver.remove = usb_unbind_interface; |
| 298 | new_driver->driver.owner = new_driver->owner; | 412 | new_driver->driver.owner = new_driver->owner; |
| 413 | spin_lock_init(&new_driver->dynids.lock); | ||
| 414 | INIT_LIST_HEAD(&new_driver->dynids.list); | ||
| 299 | 415 | ||
| 300 | usb_lock_all_devices(); | 416 | usb_lock_all_devices(); |
| 301 | retval = driver_register(&new_driver->driver); | 417 | retval = driver_register(&new_driver->driver); |
| @@ -305,6 +421,7 @@ int usb_register(struct usb_driver *new_driver) | |||
| 305 | pr_info("%s: registered new driver %s\n", | 421 | pr_info("%s: registered new driver %s\n", |
| 306 | usbcore_name, new_driver->name); | 422 | usbcore_name, new_driver->name); |
| 307 | usbfs_update_special(); | 423 | usbfs_update_special(); |
| 424 | usb_create_newid_file(new_driver); | ||
| 308 | } else { | 425 | } else { |
| 309 | printk(KERN_ERR "%s: error %d registering driver %s\n", | 426 | printk(KERN_ERR "%s: error %d registering driver %s\n", |
| 310 | usbcore_name, retval, new_driver->name); | 427 | usbcore_name, retval, new_driver->name); |
| @@ -330,6 +447,7 @@ void usb_deregister(struct usb_driver *driver) | |||
| 330 | pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); | 447 | pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); |
| 331 | 448 | ||
| 332 | usb_lock_all_devices(); | 449 | usb_lock_all_devices(); |
| 450 | usb_free_dynids(driver); | ||
| 333 | driver_unregister(&driver->driver); | 451 | driver_unregister(&driver->driver); |
| 334 | usb_unlock_all_devices(); | 452 | usb_unlock_all_devices(); |
| 335 | 453 | ||
diff --git a/include/linux/usb.h b/include/linux/usb.h index d81b050e5955..0dd96ef78c13 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -529,6 +529,11 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, | |||
| 529 | 529 | ||
| 530 | /* ----------------------------------------------------------------------- */ | 530 | /* ----------------------------------------------------------------------- */ |
| 531 | 531 | ||
| 532 | struct usb_dynids { | ||
| 533 | spinlock_t lock; | ||
| 534 | struct list_head list; | ||
| 535 | }; | ||
| 536 | |||
| 532 | /** | 537 | /** |
| 533 | * struct usb_driver - identifies USB driver to usbcore | 538 | * struct usb_driver - identifies USB driver to usbcore |
| 534 | * @owner: Pointer to the module owner of this driver; initialize | 539 | * @owner: Pointer to the module owner of this driver; initialize |
| @@ -553,6 +558,8 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, | |||
| 553 | * @id_table: USB drivers use ID table to support hotplugging. | 558 | * @id_table: USB drivers use ID table to support hotplugging. |
| 554 | * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set | 559 | * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set |
| 555 | * or your driver's probe function will never get called. | 560 | * or your driver's probe function will never get called. |
| 561 | * @dynids: used internally to hold the list of dynamically added device | ||
| 562 | * ids for this driver. | ||
| 556 | * @driver: the driver model core driver structure. | 563 | * @driver: the driver model core driver structure. |
| 557 | * | 564 | * |
| 558 | * USB drivers must provide a name, probe() and disconnect() methods, | 565 | * USB drivers must provide a name, probe() and disconnect() methods, |
| @@ -588,6 +595,7 @@ struct usb_driver { | |||
| 588 | 595 | ||
| 589 | const struct usb_device_id *id_table; | 596 | const struct usb_device_id *id_table; |
| 590 | 597 | ||
| 598 | struct usb_dynids dynids; | ||
| 591 | struct device_driver driver; | 599 | struct device_driver driver; |
| 592 | }; | 600 | }; |
| 593 | #define to_usb_driver(d) container_of(d, struct usb_driver, driver) | 601 | #define to_usb_driver(d) container_of(d, struct usb_driver, driver) |
