diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2005-11-16 16:41:28 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:48:32 -0500 |
commit | 733260ff9c45bd4db60f45d17e8560a4a68dff4d (patch) | |
tree | e7f09a9a9e2d7a9f22288c9777f7b03906a89e20 /drivers/usb/core/driver.c | |
parent | ddae41be6145f5f9cb4e6df35661a09121b90672 (diff) |
[PATCH] USB: add dynamic id functionality to USB core
Echo the usb vendor and product id to the "new_id" file in the driver's
sysfs directory, and then that driver will be able to bind to a device
with those ids if it is present.
Example:
echo 0557 2008 > /sys/bus/usb/drivers/foo_driver/new_id
adds the hex values 0557 and 2008 to the device id table for the foo_driver.
Note, usb-serial drivers do not currently work with this capability yet.
usb-storage also might have some oddities.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r-- | drivers/usb/core/driver.c | 218 |
1 files changed, 168 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 | ||