aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/generic.c5
-rw-r--r--drivers/usb/core/hcd.h2
-rw-r--r--drivers/usb/core/hub.c61
-rw-r--r--drivers/usb/core/quirks.c4
-rw-r--r--drivers/usb/core/sysfs.c44
5 files changed, 85 insertions, 31 deletions
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index c1cb94e9f242..7e912f21fd36 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -155,9 +155,6 @@ static int generic_probe(struct usb_device *udev)
155{ 155{
156 int err, c; 156 int err, c;
157 157
158 /* put device-specific files into sysfs */
159 usb_create_sysfs_dev_files(udev);
160
161 /* Choose and set the configuration. This registers the interfaces 158 /* Choose and set the configuration. This registers the interfaces
162 * with the driver core and lets interface drivers bind to them. 159 * with the driver core and lets interface drivers bind to them.
163 */ 160 */
@@ -189,8 +186,6 @@ static void generic_disconnect(struct usb_device *udev)
189 * unconfigure the device */ 186 * unconfigure the device */
190 if (udev->actconfig) 187 if (udev->actconfig)
191 usb_set_configuration(udev, -1); 188 usb_set_configuration(udev, -1);
192
193 usb_remove_sysfs_dev_files(udev);
194} 189}
195 190
196#ifdef CONFIG_PM 191#ifdef CONFIG_PM
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 1e4b81e9eb50..a0bf5df6cb6f 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -213,6 +213,8 @@ struct hc_driver {
213 213
214 /* force handover of high-speed port to full-speed companion */ 214 /* force handover of high-speed port to full-speed companion */
215 void (*relinquish_port)(struct usb_hcd *, int); 215 void (*relinquish_port)(struct usb_hcd *, int);
216 /* has a port been handed over to a companion? */
217 int (*port_handed_over)(struct usb_hcd *, int);
216}; 218};
217 219
218extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); 220extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index eb57fcc701d7..94789be54ca3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -644,6 +644,48 @@ static void hub_stop(struct usb_hub *hub)
644 644
645#ifdef CONFIG_PM 645#ifdef CONFIG_PM
646 646
647/* Try to identify which devices need USB-PERSIST handling */
648static int persistent_device(struct usb_device *udev)
649{
650 int i;
651 int retval;
652 struct usb_host_config *actconfig;
653
654 /* Explicitly not marked persistent? */
655 if (!udev->persist_enabled)
656 return 0;
657
658 /* No active config? */
659 actconfig = udev->actconfig;
660 if (!actconfig)
661 return 0;
662
663 /* FIXME! We should check whether it's open here or not! */
664
665 /*
666 * Check that all the interface drivers have a
667 * 'reset_resume' entrypoint
668 */
669 retval = 0;
670 for (i = 0; i < actconfig->desc.bNumInterfaces; i++) {
671 struct usb_interface *intf;
672 struct usb_driver *driver;
673
674 intf = actconfig->interface[i];
675 if (!intf->dev.driver)
676 continue;
677 driver = to_usb_driver(intf->dev.driver);
678 if (!driver->reset_resume)
679 return 0;
680 /*
681 * We have at least one driver, and that one
682 * has a reset_resume method.
683 */
684 retval = 1;
685 }
686 return retval;
687}
688
647static void hub_restart(struct usb_hub *hub, int type) 689static void hub_restart(struct usb_hub *hub, int type)
648{ 690{
649 struct usb_device *hdev = hub->hdev; 691 struct usb_device *hdev = hub->hdev;
@@ -689,8 +731,8 @@ static void hub_restart(struct usb_hub *hub, int type)
689 * turn off the various status changes to prevent 731 * turn off the various status changes to prevent
690 * khubd from disconnecting it later. 732 * khubd from disconnecting it later.
691 */ 733 */
692 if (udev->persist_enabled && status == 0 && 734 if (status == 0 && !(portstatus & USB_PORT_STAT_ENABLE) &&
693 !(portstatus & USB_PORT_STAT_ENABLE)) { 735 persistent_device(udev)) {
694 if (portchange & USB_PORT_STAT_C_ENABLE) 736 if (portchange & USB_PORT_STAT_C_ENABLE)
695 clear_port_feature(hub->hdev, port1, 737 clear_port_feature(hub->hdev, port1,
696 USB_PORT_FEAT_C_ENABLE); 738 USB_PORT_FEAT_C_ENABLE);
@@ -1326,6 +1368,12 @@ void usb_disconnect(struct usb_device **pdev)
1326 1368
1327 usb_unlock_device(udev); 1369 usb_unlock_device(udev);
1328 1370
1371 /* Remove the device-specific files from sysfs. This must be
1372 * done with udev unlocked, because some of the attribute
1373 * routines try to acquire the device lock.
1374 */
1375 usb_remove_sysfs_dev_files(udev);
1376
1329 /* Unregister the device. The device driver is responsible 1377 /* Unregister the device. The device driver is responsible
1330 * for removing the device files from usbfs and sysfs and for 1378 * for removing the device files from usbfs and sysfs and for
1331 * de-configuring the device. 1379 * de-configuring the device.
@@ -1541,6 +1589,9 @@ int usb_new_device(struct usb_device *udev)
1541 goto fail; 1589 goto fail;
1542 } 1590 }
1543 1591
1592 /* put device-specific files into sysfs */
1593 usb_create_sysfs_dev_files(udev);
1594
1544 /* Tell the world! */ 1595 /* Tell the world! */
1545 announce_device(udev); 1596 announce_device(udev);
1546 return err; 1597 return err;
@@ -2744,7 +2795,11 @@ loop:
2744 if ((status == -ENOTCONN) || (status == -ENOTSUPP)) 2795 if ((status == -ENOTCONN) || (status == -ENOTSUPP))
2745 break; 2796 break;
2746 } 2797 }
2747 dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); 2798 if (hub->hdev->parent ||
2799 !hcd->driver->port_handed_over ||
2800 !(hcd->driver->port_handed_over)(hcd, port1))
2801 dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
2802 port1);
2748 2803
2749done: 2804done:
2750 hub_port_disable(hub, port1, 1); 2805 hub_port_disable(hub, port1, 1);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 2e2019390290..3da1ab4b389d 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -47,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = {
47 /* Edirol SD-20 */ 47 /* Edirol SD-20 */
48 { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, 48 { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME },
49 49
50 /* Avision AV600U */
51 { USB_DEVICE(0x0638, 0x0a13), .driver_info =
52 USB_QUIRK_STRING_FETCH_255 },
53
50 /* M-Systems Flash Disk Pioneers */ 54 /* M-Systems Flash Disk Pioneers */
51 { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, 55 { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
52 56
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index c783cb111847..5e1f5d55bf04 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -588,35 +588,33 @@ read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
588 container_of(kobj, struct device, kobj)); 588 container_of(kobj, struct device, kobj));
589 size_t nleft = count; 589 size_t nleft = count;
590 size_t srclen, n; 590 size_t srclen, n;
591 int cfgno;
592 void *src;
591 593
592 usb_lock_device(udev); 594 /* The binary attribute begins with the device descriptor.
593 595 * Following that are the raw descriptor entries for all the
594 /* The binary attribute begins with the device descriptor */ 596 * configurations (config plus subsidiary descriptors).
595 srclen = sizeof(struct usb_device_descriptor);
596 if (off < srclen) {
597 n = min_t(size_t, nleft, srclen - off);
598 memcpy(buf, off + (char *) &udev->descriptor, n);
599 nleft -= n;
600 buf += n;
601 off = 0;
602 } else {
603 off -= srclen;
604 }
605
606 /* Then follows the raw descriptor entry for the current
607 * configuration (config plus subsidiary descriptors).
608 */ 597 */
609 if (udev->actconfig) { 598 for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
610 int cfgno = udev->actconfig - udev->config; 599 nleft > 0; ++cfgno) {
611 600 if (cfgno < 0) {
612 srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength); 601 src = &udev->descriptor;
602 srclen = sizeof(struct usb_device_descriptor);
603 } else {
604 src = udev->rawdescriptors[cfgno];
605 srclen = __le16_to_cpu(udev->config[cfgno].desc.
606 wTotalLength);
607 }
613 if (off < srclen) { 608 if (off < srclen) {
614 n = min_t(size_t, nleft, srclen - off); 609 n = min(nleft, srclen - (size_t) off);
615 memcpy(buf, off + udev->rawdescriptors[cfgno], n); 610 memcpy(buf, src + off, n);
616 nleft -= n; 611 nleft -= n;
612 buf += n;
613 off = 0;
614 } else {
615 off -= srclen;
617 } 616 }
618 } 617 }
619 usb_unlock_device(udev);
620 return count - nleft; 618 return count - nleft;
621} 619}
622 620