]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/usb/core/hub.c
USB: Fix USB3.0 Port Speed Downgrade after port reset
[net-next-2.6.git] / drivers / usb / core / hub.c
index 0940ccd6f4f4fbebb8ba9bccb67dd453a7b0e990..70cccc75a362013267de1744c7d4b196d78a3a95 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ioctl.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb/hcd.h>
 #include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
@@ -28,8 +29,6 @@
 #include <asm/byteorder.h>
 
 #include "usb.h"
-#include "hcd.h"
-#include "hub.h"
 
 /* if we are in debug mode, always announce new devices */
 #ifdef DEBUG
@@ -154,11 +153,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev);
 
 static inline char *portspeed(int portstatus)
 {
-       if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED))
+       if (portstatus & USB_PORT_STAT_HIGH_SPEED)
                return "480 Mb/s";
-       else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
+       else if (portstatus & USB_PORT_STAT_LOW_SPEED)
                return "1.5 Mb/s";
-       else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))
+       else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
                return "5.0 Gb/s";
        else
                return "12 Mb/s";
@@ -745,8 +744,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                                !(portstatus & USB_PORT_STAT_CONNECTION) ||
                                !udev ||
                                udev->state == USB_STATE_NOTATTACHED)) {
-                       clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
-                       portstatus &= ~USB_PORT_STAT_ENABLE;
+                       /*
+                        * USB3 protocol ports will automatically transition
+                        * to Enabled state when detect an USB3.0 device attach.
+                        * Do not disable USB3 protocol ports.
+                        * FIXME: USB3 root hub and external hubs are treated
+                        * differently here.
+                        */
+                       if (hdev->descriptor.bDeviceProtocol != 3 ||
+                           (!hdev->parent &&
+                            !(portstatus & USB_PORT_STAT_SUPER_SPEED))) {
+                               clear_port_feature(hdev, port1,
+                                                  USB_PORT_FEAT_ENABLE);
+                               portstatus &= ~USB_PORT_STAT_ENABLE;
+                       }
                }
 
                /* Clear status-change flags; we'll debounce later */
@@ -1784,7 +1795,6 @@ int usb_new_device(struct usb_device *udev)
                 * sysfs power/wakeup controls wakeup enabled/disabled
                 */
                device_init_wakeup(&udev->dev, 0);
-               device_set_wakeup_enable(&udev->dev, 1);
        }
 
        /* Tell the runtime-PM framework the device is active */
@@ -1972,6 +1982,8 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                    (portstatus & USB_PORT_STAT_ENABLE)) {
                        if (hub_is_wusb(hub))
                                udev->speed = USB_SPEED_WIRELESS;
+                       else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
+                               udev->speed = USB_SPEED_SUPER;
                        else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
                                udev->speed = USB_SPEED_HIGH;
                        else if (portstatus & USB_PORT_STAT_LOW_SPEED)
@@ -3038,7 +3050,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 
                /* maybe switch power back on (e.g. root hub was reset) */
                if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
-                               && !(portstatus & (1 << USB_PORT_FEAT_POWER)))
+                               && !(portstatus & USB_PORT_STAT_POWER))
                        set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 
                if (portstatus & USB_PORT_STAT_ENABLE)
@@ -3076,7 +3088,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                if (!(hcd->driver->flags & HCD_USB3))
                        udev->speed = USB_SPEED_UNKNOWN;
                else if ((hdev->parent == NULL) &&
-                               (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
+                               (portstatus & USB_PORT_STAT_SUPER_SPEED))
                        udev->speed = USB_SPEED_SUPER;
                else
                        udev->speed = USB_SPEED_UNKNOWN;