This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / usb / host / uhci-hub.c
index 1feccf2..22bbd70 100644 (file)
@@ -36,16 +36,14 @@ static __u8 root_hub_hub_des[] =
 static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       int port;
+       unsigned long io_addr = uhci->io_addr;
+       int i;
 
        *buf = 0;
-       for (port = 0; port < uhci->rh_numports; ++port) {
-               if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
-                               test_bit(port, &uhci->port_c_suspend))
-                       *buf |= (1 << (port + 1));
+       for (i = 0; i < uhci->rh_numports; i++) {
+               if (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS)
+                       *buf |= (1 << (i + 1));
        }
-       if (*buf && uhci->state == UHCI_SUSPENDED)
-               uhci->resume_detect = 1;
        return !!*buf;
 }
 
@@ -64,73 +62,31 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
        status &= ~(RWC_BITS|WZ_BITS); \
        outw(status, port_addr)
 
-/* UHCI controllers don't automatically stop resume signalling after 20 msec,
- * so we have to poll and check timeouts in order to take care of it.
- * FIXME:  Synchronize access to these fields by a spinlock.
- */
-static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
-               unsigned long port_addr)
-{
-       int status;
-
-       if (test_bit(port, &uhci->suspended_ports)) {
-               CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
-               clear_bit(port, &uhci->suspended_ports);
-               clear_bit(port, &uhci->resuming_ports);
-               set_bit(port, &uhci->port_c_suspend);
-
-               /* The controller won't actually turn off the RD bit until
-                * it has had a chance to send a low-speed EOP sequence,
-                * which takes 3 bit times (= 2 microseconds).  We'll delay
-                * slightly longer for good luck. */
-               udelay(4);
-       }
-}
-
-static void uhci_check_resume(struct uhci_hcd *uhci)
-{
-       unsigned int port;
-       unsigned long port_addr;
-
-       for (port = 0; port < uhci->rh_numports; ++port) {
-               port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
-               if (unlikely(inw(port_addr) & USBPORTSC_RD)) {
-                       if (!test_bit(port, &uhci->resuming_ports)) {
-
-                               /* Port received a wakeup request */
-                               set_bit(port, &uhci->resuming_ports);
-                               uhci->resume_timeout = jiffies +
-                                               msecs_to_jiffies(20);
-                       } else if (time_after_eq(jiffies,
-                                               uhci->resume_timeout)) {
-                               uhci_finish_suspend(uhci, port, port_addr);
-                       }
-               }
-       }
-}
 
 /* size of returned buffer is part of USB spec */
 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        u16 wIndex, char *buf, u16 wLength)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       int status, lstatus, retval = 0, len = 0;
-       unsigned int port = wIndex - 1;
-       unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
-       u16 wPortChange, wPortStatus;
+       int status, retval = 0, len = 0;
+       unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1);
+       __u16 wPortChange, wPortStatus;
 
        switch (typeReq) {
+               /* Request Destination:
+                  without flags: Device,
+                  RH_INTERFACE: interface,
+                  RH_ENDPOINT: endpoint,
+                  RH_CLASS means HUB here,
+                  RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+               */
 
        case GetHubStatus:
                *(__le32 *)buf = cpu_to_le32(0);
                OK(4);          /* hub power */
        case GetPortStatus:
-               if (port >= uhci->rh_numports)
+               if (!wIndex || wIndex > uhci->rh_numports)
                        goto err;
-
-               if (uhci->resuming_ports)
-                       uhci_check_resume(uhci);
-
                status = inw(port_addr);
 
                /* Intel controllers report the OverCurrent bit active on.
@@ -141,43 +97,34 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                PCI_VENDOR_ID_VIA)
                        status ^= USBPORTSC_OC;
 
-               /* UHCI doesn't support C_RESET (always false) */
-               wPortChange = lstatus = 0;
+               /* UHCI doesn't support C_SUSPEND and C_RESET (always false) */
+               wPortChange = 0;
                if (status & USBPORTSC_CSC)
-                       wPortChange |= USB_PORT_STAT_C_CONNECTION;
+                       wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16);
                if (status & USBPORTSC_PEC)
-                       wPortChange |= USB_PORT_STAT_C_ENABLE;
+                       wPortChange |= 1 << (USB_PORT_FEAT_C_ENABLE - 16);
                if (status & USBPORTSC_OCC)
-                       wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
-
-               if (test_bit(port, &uhci->port_c_suspend)) {
-                       wPortChange |= USB_PORT_STAT_C_SUSPEND;
-                       lstatus |= 1;
-               }
-               if (test_bit(port, &uhci->suspended_ports))
-                       lstatus |= 2;
-               if (test_bit(port, &uhci->resuming_ports))
-                       lstatus |= 4;
+                       wPortChange |= 1 << (USB_PORT_FEAT_C_OVER_CURRENT - 16);
 
                /* UHCI has no power switching (always on) */
-               wPortStatus = USB_PORT_STAT_POWER;
+               wPortStatus = 1 << USB_PORT_FEAT_POWER;
                if (status & USBPORTSC_CCS)
-                       wPortStatus |= USB_PORT_STAT_CONNECTION;
+                       wPortStatus |= 1 << USB_PORT_FEAT_CONNECTION;
                if (status & USBPORTSC_PE) {
-                       wPortStatus |= USB_PORT_STAT_ENABLE;
+                       wPortStatus |= 1 << USB_PORT_FEAT_ENABLE;
                        if (status & (USBPORTSC_SUSP | USBPORTSC_RD))
-                               wPortStatus |= USB_PORT_STAT_SUSPEND;
+                               wPortStatus |= 1 << USB_PORT_FEAT_SUSPEND;
                }
                if (status & USBPORTSC_OC)
-                       wPortStatus |= USB_PORT_STAT_OVERCURRENT;
+                       wPortStatus |= 1 << USB_PORT_FEAT_OVER_CURRENT;
                if (status & USBPORTSC_PR)
-                       wPortStatus |= USB_PORT_STAT_RESET;
+                       wPortStatus |= 1 << USB_PORT_FEAT_RESET;
                if (status & USBPORTSC_LSDA)
-                       wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+                       wPortStatus |= 1 << USB_PORT_FEAT_LOWSPEED;
 
                if (wPortChange)
-                       dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n",
-                                       wIndex, status, lstatus);
+                       dev_dbg(uhci_dev(uhci), "port %d portsc %04x\n",
+                                       wIndex, status);
 
                *(__le16 *)buf = cpu_to_le16(wPortStatus);
                *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);
@@ -193,12 +140,11 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                }
                break;
        case SetPortFeature:
-               if (port >= uhci->rh_numports)
+               if (!wIndex || wIndex > uhci->rh_numports)
                        goto err;
 
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
-                       set_bit(port, &uhci->suspended_ports);
                        SET_RH_PORTSTAT(USBPORTSC_SUSP);
                        OK(0);
                case USB_PORT_FEAT_RESET:
@@ -206,9 +152,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        mdelay(50);     /* USB v1.1 7.1.7.3 */
                        CLR_RH_PORTSTAT(USBPORTSC_PR);
                        udelay(10);
-
-                       /* Reset terminates Resume signalling */
-                       uhci_finish_suspend(uhci, port, port_addr);
                        SET_RH_PORTSTAT(USBPORTSC_PE);
                        mdelay(10);
                        CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
@@ -221,38 +164,21 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                }
                break;
        case ClearPortFeature:
-               if (port >= uhci->rh_numports)
+               if (!wIndex || wIndex > uhci->rh_numports)
                        goto err;
 
                switch (wValue) {
                case USB_PORT_FEAT_ENABLE:
                        CLR_RH_PORTSTAT(USBPORTSC_PE);
-
-                       /* Disable terminates Resume signalling */
-                       uhci_finish_suspend(uhci, port, port_addr);
                        OK(0);
                case USB_PORT_FEAT_C_ENABLE:
                        CLR_RH_PORTSTAT(USBPORTSC_PEC);
                        OK(0);
                case USB_PORT_FEAT_SUSPEND:
-                       if (test_bit(port, &uhci->suspended_ports) &&
-                                       !test_and_set_bit(port,
-                                               &uhci->resuming_ports)) {
-                               uhci->resume_timeout = jiffies +
-                                               msecs_to_jiffies(20);
-                               SET_RH_PORTSTAT(USBPORTSC_RD);
-
-                               /* The controller won't allow RD to be set
-                                * if the port is disabled.  When this happens
-                                * just skip the Resume signalling.
-                                */
-                               if (!(inw(port_addr) & USBPORTSC_RD))
-                                       uhci_finish_suspend(uhci, port,
-                                                       port_addr);
-                       }
+                       CLR_RH_PORTSTAT(USBPORTSC_SUSP);
                        OK(0);
                case USB_PORT_FEAT_C_SUSPEND:
-                       clear_bit(port, &uhci->port_c_suspend);
+                       /* this driver won't report these */
                        OK(0);
                case USB_PORT_FEAT_POWER:
                        /* UHCI has no power switching */