aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorValentina Manea <valentina.manea.m@gmail.com>2014-01-23 16:12:29 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-07 13:54:30 -0500
commitb7945b77cd03094458f3624bc82a27e0d36e75d0 (patch)
tree55fa77ff4d051b90a69e2fca601dea3c3c7562c1
parenta6646ea683c0c73962cb67aea9be40b11b916de5 (diff)
staging: usbip: convert usbip-host driver to usb_device_driver
This driver was previously an interface driver. Since USB/IP exports a whole device, not just an interface, it would make sense to be a device driver. This patch also modifies the way userspace sees and uses a shared device: * the usbip_status file is no longer created for interface 0, but for the whole device (such as /sys/devices/pci0000:00/0000:00:01.2/usb1/1-1/usbip_status). * per interface information, such as interface class or protocol, is no longer sent/received; only device specific information is transmitted. * since the driver was moved one level below in the USB architecture, there is no need to bind/unbind each interface, just the device as a whole. Signed-off-by: Valentina Manea <valentina.manea.m@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/usbip/stub.h2
-rw-r--r--drivers/staging/usbip/stub_dev.c150
-rw-r--r--drivers/staging/usbip/stub_main.c6
-rw-r--r--drivers/staging/usbip/stub_rx.c2
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c45
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_bind.c142
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_list.c19
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_unbind.c51
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c15
-rw-r--r--drivers/usb/core/generic.c1
-rw-r--r--drivers/usb/core/message.c1
-rw-r--r--include/linux/usb.h4
12 files changed, 150 insertions, 288 deletions
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
index a73e437ec215..82e539a4fcff 100644
--- a/drivers/staging/usbip/stub.h
+++ b/drivers/staging/usbip/stub.h
@@ -93,7 +93,7 @@ struct bus_id_priv {
93extern struct kmem_cache *stub_priv_cache; 93extern struct kmem_cache *stub_priv_cache;
94 94
95/* stub_dev.c */ 95/* stub_dev.c */
96extern struct usb_driver stub_driver; 96extern struct usb_device_driver stub_driver;
97 97
98/* stub_main.c */ 98/* stub_main.c */
99struct bus_id_priv *get_busid_priv(const char *busid); 99struct bus_id_priv *get_busid_priv(const char *busid);
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 76a1ff0e6275..b0bfd3430d47 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -279,21 +279,19 @@ static void stub_device_unusable(struct usbip_device *ud)
279 * 279 *
280 * Allocates and initializes a new stub_device struct. 280 * Allocates and initializes a new stub_device struct.
281 */ 281 */
282static struct stub_device *stub_device_alloc(struct usb_device *udev, 282static struct stub_device *stub_device_alloc(struct usb_device *udev)
283 struct usb_interface *interface)
284{ 283{
285 struct stub_device *sdev; 284 struct stub_device *sdev;
286 int busnum = interface_to_busnum(interface); 285 int busnum = udev->bus->busnum;
287 int devnum = interface_to_devnum(interface); 286 int devnum = udev->devnum;
288 287
289 dev_dbg(&interface->dev, "allocating stub device"); 288 dev_dbg(&udev->dev, "allocating stub device");
290 289
291 /* yes, it's a new device */ 290 /* yes, it's a new device */
292 sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL); 291 sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
293 if (!sdev) 292 if (!sdev)
294 return NULL; 293 return NULL;
295 294
296 sdev->interface = usb_get_intf(interface);
297 sdev->udev = usb_get_dev(udev); 295 sdev->udev = usb_get_dev(udev);
298 296
299 /* 297 /*
@@ -322,7 +320,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev,
322 320
323 usbip_start_eh(&sdev->ud); 321 usbip_start_eh(&sdev->ud);
324 322
325 dev_dbg(&interface->dev, "register new interface\n"); 323 dev_dbg(&udev->dev, "register new device\n");
326 324
327 return sdev; 325 return sdev;
328} 326}
@@ -332,32 +330,20 @@ static void stub_device_free(struct stub_device *sdev)
332 kfree(sdev); 330 kfree(sdev);
333} 331}
334 332
335/* 333static int stub_probe(struct usb_device *udev)
336 * If a usb device has multiple active interfaces, this driver is bound to all
337 * the active interfaces. However, usbip exports *a* usb device (i.e., not *an*
338 * active interface). Currently, a userland program must ensure that it
339 * looks at the usbip's sysfs entries of only the first active interface.
340 *
341 * TODO: use "struct usb_device_driver" to bind a usb device.
342 * However, it seems it is not fully supported in mainline kernel yet
343 * (2.6.19.2).
344 */
345static int stub_probe(struct usb_interface *interface,
346 const struct usb_device_id *id)
347{ 334{
348 struct usb_device *udev = interface_to_usbdev(interface);
349 struct stub_device *sdev = NULL; 335 struct stub_device *sdev = NULL;
350 const char *udev_busid = dev_name(interface->dev.parent); 336 const char *udev_busid = dev_name(&udev->dev);
351 int err = 0; 337 int err = 0, config;
352 struct bus_id_priv *busid_priv; 338 struct bus_id_priv *busid_priv;
353 339
354 dev_dbg(&interface->dev, "Enter\n"); 340 dev_dbg(&udev->dev, "Enter\n");
355 341
356 /* check we should claim or not by busid_table */ 342 /* check we should claim or not by busid_table */
357 busid_priv = get_busid_priv(udev_busid); 343 busid_priv = get_busid_priv(udev_busid);
358 if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) || 344 if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
359 (busid_priv->status == STUB_BUSID_OTHER)) { 345 (busid_priv->status == STUB_BUSID_OTHER)) {
360 dev_info(&interface->dev, 346 dev_info(&udev->dev,
361 "%s is not in match_busid table... skip!\n", 347 "%s is not in match_busid table... skip!\n",
362 udev_busid); 348 udev_busid);
363 349
@@ -383,60 +369,36 @@ static int stub_probe(struct usb_interface *interface,
383 return -ENODEV; 369 return -ENODEV;
384 } 370 }
385 371
386 if (busid_priv->status == STUB_BUSID_ALLOC) {
387 sdev = busid_priv->sdev;
388 if (!sdev)
389 return -ENODEV;
390
391 busid_priv->interf_count++;
392 dev_info(&interface->dev,
393 "usbip-host: register new interface (bus %u dev %u ifn %u)\n",
394 udev->bus->busnum, udev->devnum,
395 interface->cur_altsetting->desc.bInterfaceNumber);
396
397 /* set private data to usb_interface */
398 usb_set_intfdata(interface, sdev);
399
400 err = stub_add_files(&interface->dev);
401 if (err) {
402 dev_err(&interface->dev, "stub_add_files for %s\n",
403 udev_busid);
404 usb_set_intfdata(interface, NULL);
405 busid_priv->interf_count--;
406 return err;
407 }
408
409 usb_get_intf(interface);
410 return 0;
411 }
412
413 /* ok, this is my device */ 372 /* ok, this is my device */
414 sdev = stub_device_alloc(udev, interface); 373 sdev = stub_device_alloc(udev);
415 if (!sdev) 374 if (!sdev)
416 return -ENOMEM; 375 return -ENOMEM;
417 376
418 dev_info(&interface->dev, 377 dev_info(&udev->dev,
419 "usbip-host: register new device (bus %u dev %u ifn %u)\n", 378 "usbip-host: register new device (bus %u dev %u)\n",
420 udev->bus->busnum, udev->devnum, 379 udev->bus->busnum, udev->devnum);
421 interface->cur_altsetting->desc.bInterfaceNumber);
422 380
423 busid_priv->interf_count = 0;
424 busid_priv->shutdown_busid = 0; 381 busid_priv->shutdown_busid = 0;
425 382
426 /* set private data to usb_interface */ 383 config = usb_choose_configuration(udev);
427 usb_set_intfdata(interface, sdev); 384 if (config >= 0) {
428 busid_priv->interf_count++; 385 err = usb_set_configuration(udev, config);
386 if (err && err != -ENODEV)
387 dev_err(&udev->dev, "can't set config #%d, error %d\n",
388 config, err);
389 }
390
391 /* set private data to usb_device */
392 dev_set_drvdata(&udev->dev, sdev);
429 busid_priv->sdev = sdev; 393 busid_priv->sdev = sdev;
430 394
431 err = stub_add_files(&interface->dev); 395 err = stub_add_files(&udev->dev);
432 if (err) { 396 if (err) {
433 dev_err(&interface->dev, "stub_add_files for %s\n", udev_busid); 397 dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
434 usb_set_intfdata(interface, NULL); 398 dev_set_drvdata(&udev->dev, NULL);
435 usb_put_intf(interface);
436 usb_put_dev(udev); 399 usb_put_dev(udev);
437 kthread_stop_put(sdev->ud.eh); 400 kthread_stop_put(sdev->ud.eh);
438 401
439 busid_priv->interf_count = 0;
440 busid_priv->sdev = NULL; 402 busid_priv->sdev = NULL;
441 stub_device_free(sdev); 403 stub_device_free(sdev);
442 return err; 404 return err;
@@ -461,13 +423,13 @@ static void shutdown_busid(struct bus_id_priv *busid_priv)
461 * called in usb_disconnect() or usb_deregister() 423 * called in usb_disconnect() or usb_deregister()
462 * but only if actconfig(active configuration) exists 424 * but only if actconfig(active configuration) exists
463 */ 425 */
464static void stub_disconnect(struct usb_interface *interface) 426static void stub_disconnect(struct usb_device *udev)
465{ 427{
466 struct stub_device *sdev; 428 struct stub_device *sdev;
467 const char *udev_busid = dev_name(interface->dev.parent); 429 const char *udev_busid = dev_name(&udev->dev);
468 struct bus_id_priv *busid_priv; 430 struct bus_id_priv *busid_priv;
469 431
470 dev_dbg(&interface->dev, "Enter\n"); 432 dev_dbg(&udev->dev, "Enter\n");
471 433
472 busid_priv = get_busid_priv(udev_busid); 434 busid_priv = get_busid_priv(udev_busid);
473 if (!busid_priv) { 435 if (!busid_priv) {
@@ -475,41 +437,29 @@ static void stub_disconnect(struct usb_interface *interface)
475 return; 437 return;
476 } 438 }
477 439
478 sdev = usb_get_intfdata(interface); 440 sdev = dev_get_drvdata(&udev->dev);
479 441
480 /* get stub_device */ 442 /* get stub_device */
481 if (!sdev) { 443 if (!sdev) {
482 dev_err(&interface->dev, "could not get device"); 444 dev_err(&udev->dev, "could not get device");
483 return; 445 return;
484 } 446 }
485 447
486 usb_set_intfdata(interface, NULL); 448 dev_set_drvdata(&udev->dev, NULL);
487 449
488 /* 450 /*
489 * NOTE: rx/tx threads are invoked for each usb_device. 451 * NOTE: rx/tx threads are invoked for each usb_device.
490 */ 452 */
491 stub_remove_files(&interface->dev); 453 stub_remove_files(&udev->dev);
492 454
493 /* If usb reset is called from event handler */ 455 /* If usb reset is called from event handler */
494 if (busid_priv->sdev->ud.eh == current) { 456 if (busid_priv->sdev->ud.eh == current)
495 busid_priv->interf_count--;
496 return; 457 return;
497 }
498
499 if (busid_priv->interf_count > 1) {
500 busid_priv->interf_count--;
501 shutdown_busid(busid_priv);
502 usb_put_intf(interface);
503 return;
504 }
505
506 busid_priv->interf_count = 0;
507 458
508 /* shutdown the current connection */ 459 /* shutdown the current connection */
509 shutdown_busid(busid_priv); 460 shutdown_busid(busid_priv);
510 461
511 usb_put_dev(sdev->udev); 462 usb_put_dev(sdev->udev);
512 usb_put_intf(interface);
513 463
514 /* free sdev */ 464 /* free sdev */
515 busid_priv->sdev = NULL; 465 busid_priv->sdev = NULL;
@@ -523,28 +473,34 @@ static void stub_disconnect(struct usb_interface *interface)
523 } 473 }
524} 474}
525 475
526/* 476#ifdef CONFIG_PM
527 * Presence of pre_reset and post_reset prevents the driver from being unbound
528 * when the device is being reset
529 */
530 477
531static int stub_pre_reset(struct usb_interface *interface) 478/* These functions need usb_port_suspend and usb_port_resume,
479 * which reside in drivers/usb/core/usb.h. Skip for now. */
480
481static int stub_suspend(struct usb_device *udev, pm_message_t message)
532{ 482{
533 dev_dbg(&interface->dev, "pre_reset\n"); 483 dev_dbg(&udev->dev, "stub_suspend\n");
484
534 return 0; 485 return 0;
535} 486}
536 487
537static int stub_post_reset(struct usb_interface *interface) 488static int stub_resume(struct usb_device *udev, pm_message_t message)
538{ 489{
539 dev_dbg(&interface->dev, "post_reset\n"); 490 dev_dbg(&udev->dev, "stub_resume\n");
491
540 return 0; 492 return 0;
541} 493}
542 494
543struct usb_driver stub_driver = { 495#endif /* CONFIG_PM */
496
497struct usb_device_driver stub_driver = {
544 .name = "usbip-host", 498 .name = "usbip-host",
545 .probe = stub_probe, 499 .probe = stub_probe,
546 .disconnect = stub_disconnect, 500 .disconnect = stub_disconnect,
547 .id_table = stub_table, 501#ifdef CONFIG_PM
548 .pre_reset = stub_pre_reset, 502 .suspend = stub_suspend,
549 .post_reset = stub_post_reset, 503 .resume = stub_resume,
504#endif
505 .supports_autosuspend = 0,
550}; 506};
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
index baf857f7cc88..bd7b83a9d758 100644
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -254,7 +254,7 @@ static int __init usbip_host_init(void)
254 return -ENOMEM; 254 return -ENOMEM;
255 } 255 }
256 256
257 ret = usb_register(&stub_driver); 257 ret = usb_register_device_driver(&stub_driver, THIS_MODULE);
258 if (ret) { 258 if (ret) {
259 pr_err("usb_register failed %d\n", ret); 259 pr_err("usb_register failed %d\n", ret);
260 goto err_usb_register; 260 goto err_usb_register;
@@ -271,7 +271,7 @@ static int __init usbip_host_init(void)
271 return ret; 271 return ret;
272 272
273err_create_file: 273err_create_file:
274 usb_deregister(&stub_driver); 274 usb_deregister_device_driver(&stub_driver);
275err_usb_register: 275err_usb_register:
276 kmem_cache_destroy(stub_priv_cache); 276 kmem_cache_destroy(stub_priv_cache);
277 return ret; 277 return ret;
@@ -286,7 +286,7 @@ static void __exit usbip_host_exit(void)
286 * deregister() calls stub_disconnect() for all devices. Device 286 * deregister() calls stub_disconnect() for all devices. Device
287 * specific data is cleared in stub_disconnect(). 287 * specific data is cleared in stub_disconnect().
288 */ 288 */
289 usb_deregister(&stub_driver); 289 usb_deregister_device_driver(&stub_driver);
290 290
291 kmem_cache_destroy(stub_priv_cache); 291 kmem_cache_destroy(stub_priv_cache);
292} 292}
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 5d1d4a183300..76e44d949232 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -550,7 +550,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
550 int ret; 550 int ret;
551 struct usbip_header pdu; 551 struct usbip_header pdu;
552 struct stub_device *sdev = container_of(ud, struct stub_device, ud); 552 struct stub_device *sdev = container_of(ud, struct stub_device, ud);
553 struct device *dev = &sdev->interface->dev; 553 struct device *dev = &sdev->udev->dev;
554 554
555 usbip_dbg_stub_rx("Enter\n"); 555 usbip_dbg_stub_rx("Enter\n");
556 556
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
index 71a449cf50db..86a867582de6 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
@@ -32,7 +32,6 @@ struct usbip_host_driver *host_driver;
32 32
33#define SYSFS_OPEN_RETRIES 100 33#define SYSFS_OPEN_RETRIES 100
34 34
35/* only the first interface value is true! */
36static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) 35static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
37{ 36{
38 char attrpath[SYSFS_PATH_MAX]; 37 char attrpath[SYSFS_PATH_MAX];
@@ -56,8 +55,8 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
56 * usbip_status to reappear. 55 * usbip_status to reappear.
57 */ 56 */
58 57
59 snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status", 58 snprintf(attrpath, SYSFS_PATH_MAX, "%s/usbip_status",
60 udev->path, udev->busid, udev->bConfigurationValue, 0); 59 udev->path);
61 60
62 while (retries > 0) { 61 while (retries > 0) {
63 if (stat(attrpath, &s) == 0) 62 if (stat(attrpath, &s) == 0)
@@ -168,19 +167,18 @@ static void delete_nothing(void *unused_data)
168 167
169static int refresh_exported_devices(void) 168static int refresh_exported_devices(void)
170{ 169{
171 /* sysfs_device of usb_interface */
172 struct sysfs_device *suintf;
173 struct dlist *suintf_list;
174 /* sysfs_device of usb_device */ 170 /* sysfs_device of usb_device */
175 struct sysfs_device *sudev; 171 struct sysfs_device *sudev;
176 struct dlist *sudev_list; 172 struct dlist *sudev_list;
173 struct dlist *sudev_unique_list;
177 struct usbip_exported_device *edev; 174 struct usbip_exported_device *edev;
178 175
179 sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), 176 sudev_unique_list = dlist_new_with_delete(sizeof(struct sysfs_device),
180 delete_nothing); 177 delete_nothing);
181 178
182 suintf_list = sysfs_get_driver_devices(host_driver->sysfs_driver); 179 sudev_list = sysfs_get_driver_devices(host_driver->sysfs_driver);
183 if (!suintf_list) { 180
181 if (!sudev_list) {
184 /* 182 /*
185 * Not an error condition. There are simply no devices bound to 183 * Not an error condition. There are simply no devices bound to
186 * the driver yet. 184 * the driver yet.
@@ -190,23 +188,13 @@ static int refresh_exported_devices(void)
190 return 0; 188 return 0;
191 } 189 }
192 190
193 /* collect unique USB devices (not interfaces) */ 191 dlist_for_each_data(sudev_list, sudev, struct sysfs_device)
194 dlist_for_each_data(suintf_list, suintf, struct sysfs_device) { 192 if (check_new(sudev_unique_list, sudev))
195 /* get usb device of this usb interface */ 193 dlist_unshift(sudev_unique_list, sudev);
196 sudev = sysfs_get_device_parent(suintf);
197 if (!sudev) {
198 dbg("sysfs_get_device_parent failed: %s", suintf->name);
199 continue;
200 }
201 194
202 if (check_new(sudev_list, sudev)) { 195 dlist_for_each_data(sudev_unique_list, sudev, struct sysfs_device) {
203 /* insert item at head of list */
204 dlist_unshift(sudev_list, sudev);
205 }
206 }
207
208 dlist_for_each_data(sudev_list, sudev, struct sysfs_device) {
209 edev = usbip_exported_device_new(sudev->path); 196 edev = usbip_exported_device_new(sudev->path);
197
210 if (!edev) { 198 if (!edev) {
211 dbg("usbip_exported_device_new failed"); 199 dbg("usbip_exported_device_new failed");
212 continue; 200 continue;
@@ -216,7 +204,7 @@ static int refresh_exported_devices(void)
216 host_driver->ndevs++; 204 host_driver->ndevs++;
217 } 205 }
218 206
219 dlist_destroy(sudev_list); 207 dlist_destroy(sudev_unique_list);
220 208
221 return 0; 209 return 0;
222} 210}
@@ -356,9 +344,8 @@ int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
356 } 344 }
357 345
358 /* only the first interface is true */ 346 /* only the first interface is true */
359 snprintf(attr_path, sizeof(attr_path), "%s/%s:%d.%d/%s", 347 snprintf(attr_path, sizeof(attr_path), "%s/%s",
360 edev->udev.path, edev->udev.busid, 348 edev->udev.path, attr_name);
361 edev->udev.bConfigurationValue, 0, attr_name);
362 349
363 attr = sysfs_open_attribute(attr_path); 350 attr = sysfs_open_attribute(attr_path);
364 if (!attr) { 351 if (!attr) {
diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c
index 9ecaf6e574df..8cfd2dbd9510 100644
--- a/drivers/staging/usbip/userspace/src/usbip_bind.c
+++ b/drivers/staging/usbip/userspace/src/usbip_bind.c
@@ -52,12 +52,8 @@ static int bind_usbip(char *busid)
52 char attr_name[] = "bind"; 52 char attr_name[] = "bind";
53 char sysfs_mntpath[SYSFS_PATH_MAX]; 53 char sysfs_mntpath[SYSFS_PATH_MAX];
54 char bind_attr_path[SYSFS_PATH_MAX]; 54 char bind_attr_path[SYSFS_PATH_MAX];
55 char intf_busid[SYSFS_BUS_ID_SIZE];
56 struct sysfs_device *busid_dev;
57 struct sysfs_attribute *bind_attr; 55 struct sysfs_attribute *bind_attr;
58 struct sysfs_attribute *bConfValue; 56 int failed = 0;
59 struct sysfs_attribute *bNumIntfs;
60 int i, failed = 0;
61 int rc, ret = -1; 57 int rc, ret = -1;
62 58
63 rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); 59 rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
@@ -76,39 +72,15 @@ static int bind_usbip(char *busid)
76 return -1; 72 return -1;
77 } 73 }
78 74
79 busid_dev = sysfs_open_device(bus_type, busid); 75 rc = sysfs_write_attribute(bind_attr, busid, SYSFS_BUS_ID_SIZE);
80 if (!busid_dev) { 76 if (rc < 0) {
81 dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); 77 dbg("bind driver at %s failed", busid);
82 goto err_close_bind_attr; 78 failed = 1;
83 }
84
85 bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue");
86 bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces");
87
88 if (!bConfValue || !bNumIntfs) {
89 dbg("problem getting device attributes: %s",
90 strerror(errno));
91 goto err_close_busid_dev;
92 }
93
94 for (i = 0; i < atoi(bNumIntfs->value); i++) {
95 snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid,
96 bConfValue->value, i);
97
98 rc = sysfs_write_attribute(bind_attr, intf_busid,
99 SYSFS_BUS_ID_SIZE);
100 if (rc < 0) {
101 dbg("bind driver at %s failed", intf_busid);
102 failed = 1;
103 }
104 } 79 }
105 80
106 if (!failed) 81 if (!failed)
107 ret = 0; 82 ret = 0;
108 83
109err_close_busid_dev:
110 sysfs_close_device(busid_dev);
111err_close_bind_attr:
112 sysfs_close_attribute(bind_attr); 84 sysfs_close_attribute(bind_attr);
113 85
114 return ret; 86 return ret;
@@ -118,15 +90,12 @@ err_close_bind_attr:
118static int unbind_other(char *busid) 90static int unbind_other(char *busid)
119{ 91{
120 char bus_type[] = "usb"; 92 char bus_type[] = "usb";
121 char intf_busid[SYSFS_BUS_ID_SIZE];
122 struct sysfs_device *busid_dev; 93 struct sysfs_device *busid_dev;
123 struct sysfs_device *intf_dev; 94 struct sysfs_device *dev;
124 struct sysfs_driver *intf_drv; 95 struct sysfs_driver *drv;
125 struct sysfs_attribute *unbind_attr; 96 struct sysfs_attribute *unbind_attr;
126 struct sysfs_attribute *bConfValue;
127 struct sysfs_attribute *bDevClass; 97 struct sysfs_attribute *bDevClass;
128 struct sysfs_attribute *bNumIntfs; 98 int rc;
129 int i, rc;
130 enum unbind_status status = UNBIND_ST_OK; 99 enum unbind_status status = UNBIND_ST_OK;
131 100
132 busid_dev = sysfs_open_device(bus_type, busid); 101 busid_dev = sysfs_open_device(bus_type, busid);
@@ -134,12 +103,11 @@ static int unbind_other(char *busid)
134 dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); 103 dbg("sysfs_open_device %s failed: %s", busid, strerror(errno));
135 return -1; 104 return -1;
136 } 105 }
106 dbg("busid path: %s", busid_dev->path);
137 107
138 bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue");
139 bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass"); 108 bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass");
140 bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); 109 if (!bDevClass) {
141 if (!bConfValue || !bDevClass || !bNumIntfs) { 110 dbg("problem getting device attribute: %s",
142 dbg("problem getting device attributes: %s",
143 strerror(errno)); 111 strerror(errno));
144 goto err_close_busid_dev; 112 goto err_close_busid_dev;
145 } 113 }
@@ -149,62 +117,62 @@ static int unbind_other(char *busid)
149 goto err_close_busid_dev; 117 goto err_close_busid_dev;
150 } 118 }
151 119
152 for (i = 0; i < atoi(bNumIntfs->value); i++) { 120 dev = sysfs_open_device(bus_type, busid);
153 snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, 121 if (!dev) {
154 bConfValue->value, i); 122 dbg("could not open device: %s",
155 intf_dev = sysfs_open_device(bus_type, intf_busid); 123 strerror(errno));
156 if (!intf_dev) { 124 goto err_close_busid_dev;
157 dbg("could not open interface device: %s", 125 }
158 strerror(errno));
159 goto err_close_busid_dev;
160 }
161
162 dbg("%s -> %s", intf_dev->name, intf_dev->driver_name);
163 126
164 if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN)) 127 dbg("%s -> %s", dev->name, dev->driver_name);
165 /* unbound interface */
166 continue;
167 128
168 if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name, 129 if (!strncmp("unknown", dev->driver_name, SYSFS_NAME_LEN)) {
169 SYSFS_NAME_LEN)) { 130 /* unbound interface */
170 /* already bound to usbip-host */ 131 sysfs_close_device(dev);
171 status = UNBIND_ST_USBIP_HOST; 132 goto out;
172 continue; 133 }
173 }
174 134
175 /* unbinding */ 135 if (!strncmp(USBIP_HOST_DRV_NAME, dev->driver_name,
176 intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name); 136 SYSFS_NAME_LEN)) {
177 if (!intf_drv) { 137 /* already bound to usbip-host */
178 dbg("could not open interface driver on %s: %s", 138 status = UNBIND_ST_USBIP_HOST;
179 intf_dev->name, strerror(errno)); 139 sysfs_close_device(dev);
180 goto err_close_intf_dev; 140 goto out;
181 } 141 }
182 142
183 unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind"); 143 /* unbinding */
184 if (!unbind_attr) { 144 drv = sysfs_open_driver(bus_type, dev->driver_name);
185 dbg("problem getting interface driver attribute: %s", 145 if (!drv) {
186 strerror(errno)); 146 dbg("could not open device driver on %s: %s",
187 goto err_close_intf_drv; 147 dev->name, strerror(errno));
188 } 148 goto err_close_intf_dev;
149 }
150 dbg("device driver: %s", drv->path);
189 151
190 rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id, 152 unbind_attr = sysfs_get_driver_attr(drv, "unbind");
191 SYSFS_BUS_ID_SIZE); 153 if (!unbind_attr) {
192 if (rc < 0) { 154 dbg("problem getting device driver attribute: %s",
193 /* NOTE: why keep unbinding other interfaces? */ 155 strerror(errno));
194 dbg("unbind driver at %s failed", intf_dev->bus_id); 156 goto err_close_intf_drv;
195 status = UNBIND_ST_FAILED; 157 }
196 }
197 158
198 sysfs_close_driver(intf_drv); 159 rc = sysfs_write_attribute(unbind_attr, dev->bus_id,
199 sysfs_close_device(intf_dev); 160 SYSFS_BUS_ID_SIZE);
161 if (rc < 0) {
162 /* NOTE: why keep unbinding other interfaces? */
163 dbg("unbind driver at %s failed", dev->bus_id);
164 status = UNBIND_ST_FAILED;
200 } 165 }
201 166
167 sysfs_close_driver(drv);
168 sysfs_close_device(dev);
169
202 goto out; 170 goto out;
203 171
204err_close_intf_drv: 172err_close_intf_drv:
205 sysfs_close_driver(intf_drv); 173 sysfs_close_driver(drv);
206err_close_intf_dev: 174err_close_intf_dev:
207 sysfs_close_device(intf_dev); 175 sysfs_close_device(dev);
208err_close_busid_dev: 176err_close_busid_dev:
209 status = UNBIND_ST_FAILED; 177 status = UNBIND_ST_FAILED;
210out: 178out:
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
index 237e099337a1..8864fa2a7f0b 100644
--- a/drivers/staging/usbip/userspace/src/usbip_list.c
+++ b/drivers/staging/usbip/userspace/src/usbip_list.c
@@ -52,9 +52,8 @@ static int get_exported_devices(char *host, int sockfd)
52 struct op_devlist_reply reply; 52 struct op_devlist_reply reply;
53 uint16_t code = OP_REP_DEVLIST; 53 uint16_t code = OP_REP_DEVLIST;
54 struct usbip_usb_device udev; 54 struct usbip_usb_device udev;
55 struct usbip_usb_interface uintf;
56 unsigned int i; 55 unsigned int i;
57 int j, rc; 56 int rc;
58 57
59 rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); 58 rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
60 if (rc < 0) { 59 if (rc < 0) {
@@ -104,22 +103,6 @@ static int get_exported_devices(char *host, int sockfd)
104 printf("%11s: %s\n", "", udev.path); 103 printf("%11s: %s\n", "", udev.path);
105 printf("%11s: %s\n", "", class_name); 104 printf("%11s: %s\n", "", class_name);
106 105
107 for (j = 0; j < udev.bNumInterfaces; j++) {
108 rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
109 if (rc < 0) {
110 dbg("usbip_net_recv failed: usbip_usb_intf[%d]",
111 j);
112
113 return -1;
114 }
115 usbip_net_pack_usb_interface(0, &uintf);
116
117 usbip_names_get_class(class_name, sizeof(class_name),
118 uintf.bInterfaceClass,
119 uintf.bInterfaceSubClass,
120 uintf.bInterfaceProtocol);
121 printf("%11s: %2d - %s\n", "", j, class_name);
122 }
123 printf("\n"); 106 printf("\n");
124 } 107 }
125 108
diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c
index d5a9ab6af2a6..cace87838c24 100644
--- a/drivers/staging/usbip/userspace/src/usbip_unbind.c
+++ b/drivers/staging/usbip/userspace/src/usbip_unbind.c
@@ -47,12 +47,10 @@ static int unbind_device(char *busid)
47 int verified = 0; 47 int verified = 0;
48 int rc, ret = -1; 48 int rc, ret = -1;
49 49
50 char attr_name[] = "bConfigurationValue"; 50 char attr_name[] = "unbind";
51 char sysfs_mntpath[SYSFS_PATH_MAX]; 51 char sysfs_mntpath[SYSFS_PATH_MAX];
52 char busid_attr_path[SYSFS_PATH_MAX]; 52 char unbind_attr_path[SYSFS_PATH_MAX];
53 struct sysfs_attribute *busid_attr; 53 struct sysfs_attribute *unbind_attr;
54 char *val = NULL;
55 int len;
56 54
57 /* verify the busid device is using usbip-host */ 55 /* verify the busid device is using usbip-host */
58 usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME); 56 usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME);
@@ -99,55 +97,34 @@ static int unbind_device(char *busid)
99 return -1; 97 return -1;
100 } 98 }
101 99
102 snprintf(busid_attr_path, sizeof(busid_attr_path), "%s/%s/%s/%s/%s/%s", 100 snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
103 sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DEVICES_NAME, 101 sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
104 busid, attr_name); 102 USBIP_HOST_DRV_NAME, attr_name);
105 103
106 /* read a device attribute */ 104 /* read a device attribute */
107 busid_attr = sysfs_open_attribute(busid_attr_path); 105 unbind_attr = sysfs_open_attribute(unbind_attr_path);
108 if (!busid_attr) { 106 if (!unbind_attr) {
109 err("could not open %s/%s: %s", busid, attr_name, 107 err("could not open %s/%s: %s", busid, attr_name,
110 strerror(errno)); 108 strerror(errno));
111 return -1; 109 return -1;
112 } 110 }
113 111
114 if (sysfs_read_attribute(busid_attr) < 0) {
115 err("problem reading attribute: %s", strerror(errno));
116 goto err_out;
117 }
118
119 len = busid_attr->len;
120 val = malloc(len);
121 *val = *busid_attr->value;
122 sysfs_close_attribute(busid_attr);
123
124 /* notify driver of unbind */ 112 /* notify driver of unbind */
125 rc = modify_match_busid(busid, 0); 113 rc = modify_match_busid(busid, 0);
126 if (rc < 0) { 114 if (rc < 0) {
127 err("unable to unbind device on %s", busid); 115 err("unable to unbind device on %s", busid);
128 goto err_out;
129 }
130
131 /* write the device attribute */
132 busid_attr = sysfs_open_attribute(busid_attr_path);
133 if (!busid_attr) {
134 err("could not open %s/%s: %s", busid, attr_name,
135 strerror(errno));
136 return -1;
137 } 116 }
138 117
139 rc = sysfs_write_attribute(busid_attr, val, len); 118 rc = sysfs_write_attribute(unbind_attr, busid,
140 if (rc < 0) { 119 SYSFS_BUS_ID_SIZE);
141 err("problem writing attribute: %s", strerror(errno)); 120 if (rc < 0) {
142 goto err_out; 121 dbg("bind driver at %s failed", busid);
143 } 122 }
144 sysfs_close_attribute(busid_attr); 123 sysfs_close_attribute(unbind_attr);
145 124
146 ret = 0; 125 ret = 0;
147 printf("unbind device on busid %s: complete\n", busid); 126 printf("unbind device on busid %s: complete\n", busid);
148 127
149err_out:
150 free(val);
151err_close_usbip_host_drv: 128err_close_usbip_host_drv:
152 sysfs_close_driver(usbip_host_drv); 129 sysfs_close_driver(usbip_host_drv);
153 130
diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c
index 7980f8b5517b..c2b3ced9ca6e 100644
--- a/drivers/staging/usbip/userspace/src/usbipd.c
+++ b/drivers/staging/usbip/userspace/src/usbipd.c
@@ -159,9 +159,7 @@ static int send_reply_devlist(int connfd)
159{ 159{
160 struct usbip_exported_device *edev; 160 struct usbip_exported_device *edev;
161 struct usbip_usb_device pdu_udev; 161 struct usbip_usb_device pdu_udev;
162 struct usbip_usb_interface pdu_uinf;
163 struct op_devlist_reply reply; 162 struct op_devlist_reply reply;
164 int i;
165 int rc; 163 int rc;
166 164
167 reply.ndev = 0; 165 reply.ndev = 0;
@@ -196,19 +194,6 @@ static int send_reply_devlist(int connfd)
196 dbg("usbip_net_send failed: pdu_udev"); 194 dbg("usbip_net_send failed: pdu_udev");
197 return -1; 195 return -1;
198 } 196 }
199
200 for (i = 0; i < edev->udev.bNumInterfaces; i++) {
201 dump_usb_interface(&edev->uinf[i]);
202 memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
203 usbip_net_pack_usb_interface(1, &pdu_uinf);
204
205 rc = usbip_net_send(connfd, &pdu_uinf,
206 sizeof(pdu_uinf));
207 if (rc < 0) {
208 dbg("usbip_net_send failed: pdu_uinf");
209 return -1;
210 }
211 }
212 } 197 }
213 198
214 return 0; 199 return 0;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index acbfeb0a0119..358ca8dd784f 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -155,6 +155,7 @@ int usb_choose_configuration(struct usb_device *udev)
155 } 155 }
156 return i; 156 return i;
157} 157}
158EXPORT_SYMBOL_GPL(usb_choose_configuration);
158 159
159static int generic_probe(struct usb_device *udev) 160static int generic_probe(struct usb_device *udev)
160{ 161{
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f829a1aad1c3..08d95e9d56c2 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1920,6 +1920,7 @@ free_interfaces:
1920 usb_autosuspend_device(dev); 1920 usb_autosuspend_device(dev);
1921 return 0; 1921 return 0;
1922} 1922}
1923EXPORT_SYMBOL_GPL(usb_set_configuration);
1923 1924
1924static LIST_HEAD(set_config_list); 1925static LIST_HEAD(set_config_list);
1925static DEFINE_SPINLOCK(set_config_lock); 1926static DEFINE_SPINLOCK(set_config_lock);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index c716da18c668..f434619f3975 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1668,6 +1668,10 @@ extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
1668/* this request isn't really synchronous, but it belongs with the others */ 1668/* this request isn't really synchronous, but it belongs with the others */
1669extern int usb_driver_set_configuration(struct usb_device *udev, int config); 1669extern int usb_driver_set_configuration(struct usb_device *udev, int config);
1670 1670
1671/* choose and set configuration for device */
1672extern int usb_choose_configuration(struct usb_device *udev);
1673extern int usb_set_configuration(struct usb_device *dev, int configuration);
1674
1671/* 1675/*
1672 * timeouts, in milliseconds, used for sending/receiving control messages 1676 * timeouts, in milliseconds, used for sending/receiving control messages
1673 * they typically complete within a few frames (msec) after they're issued 1677 * they typically complete within a few frames (msec) after they're issued