pcmcia: pcmcia_config_loop() default CIS entry handling
[safe/jmp/linux-2.6] / drivers / usb / host / ehci-hub.c
index 735db4a..740835b 100644 (file)
@@ -28,7 +28,9 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_USB_PERSIST
+#define        PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+#ifdef CONFIG_PM
 
 static int ehci_hub_control(
        struct usb_hcd  *hcd,
@@ -104,15 +106,6 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
        ehci->owned_ports = 0;
 }
 
-#else  /* CONFIG_USB_PERSIST */
-
-static inline void ehci_handover_companion_ports(struct ehci_hcd *ehci)
-{ }
-
-#endif
-
-#ifdef CONFIG_PM
-
 static int ehci_bus_suspend (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
@@ -123,6 +116,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 
        if (time_before (jiffies, ehci->next_statechange))
                msleep(5);
+       del_timer_sync(&ehci->watchdog);
+       del_timer_sync(&ehci->iaa_watchdog);
 
        port = HCS_N_PORTS (ehci->hcs_params);
        spin_lock_irq (&ehci->lock);
@@ -133,8 +128,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                hcd->state = HC_STATE_QUIESCING;
        }
        ehci->command = ehci_readl(ehci, &ehci->regs->command);
-       if (ehci->reclaim)
-               ehci->reclaim_ready = 1;
        ehci_work(ehci);
 
        /* Unlike other USB host controller types, EHCI doesn't have
@@ -158,10 +151,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
 
                /* enable remote wakeup on all ports */
-               if (device_may_wakeup(&hcd->self.root_hub->dev))
-                       t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
+               if (hcd->self.root_hub->do_remote_wakeup)
+                       t2 |= PORT_WAKE_BITS;
                else
-                       t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+                       t2 &= ~PORT_WAKE_BITS;
 
                if (t1 != t2) {
                        ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
@@ -170,14 +163,20 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
        }
 
+       /* Apparently some devices need a >= 1-uframe delay here */
+       if (ehci->bus_suspended)
+               udelay(150);
+
        /* turn off now-idle HC */
-       del_timer_sync (&ehci->watchdog);
        ehci_halt (ehci);
        hcd->state = HC_STATE_SUSPENDED;
 
+       if (ehci->reclaim)
+               end_unlink_async(ehci);
+
        /* allow remote wakeup */
        mask = INTR_MASK;
-       if (!device_may_wakeup(&hcd->self.root_hub->dev))
+       if (!hcd->self.root_hub->do_remote_wakeup)
                mask &= ~STS_PCD;
        ehci_writel(ehci, mask, &ehci->regs->intr_enable);
        ehci_readl(ehci, &ehci->regs->intr_enable);
@@ -235,8 +234,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        i = HCS_N_PORTS (ehci->hcs_params);
        while (i--) {
                temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
-               temp &= ~(PORT_RWC_BITS
-                       | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
+               temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
                if (test_bit(i, &ehci->bus_suspended) &&
                                (temp & PORT_SUSPEND)) {
                        ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
@@ -275,9 +273,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
        spin_unlock_irq (&ehci->lock);
-
-       if (!power_okay)
-               ehci_handover_companion_ports(ehci);
+       ehci_handover_companion_ports(ehci);
        return 0;
 }
 
@@ -291,14 +287,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 /*-------------------------------------------------------------------------*/
 
 /* Display the ports dedicated to the companion controller */
-static ssize_t show_companion(struct class_device *class_dev, char *buf)
+static ssize_t show_companion(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
 {
        struct ehci_hcd         *ehci;
        int                     nports, index, n;
        int                     count = PAGE_SIZE;
        char                    *ptr = buf;
 
-       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+       ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
        nports = HCS_N_PORTS(ehci->hcs_params);
 
        for (index = 0; index < nports; ++index) {
@@ -312,40 +310,21 @@ static ssize_t show_companion(struct class_device *class_dev, char *buf)
 }
 
 /*
- * Dedicate or undedicate a port to the companion controller.
- * Syntax is "[-]portnum", where a leading '-' sign means
- * return control of the port to the EHCI controller.
+ * Sets the owner of a port
  */
-static ssize_t store_companion(struct class_device *class_dev,
-               const char *buf, size_t count)
+static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
 {
-       struct ehci_hcd         *ehci;
-       int                     portnum, new_owner, try;
        u32 __iomem             *status_reg;
        u32                     port_status;
+       int                     try;
 
-       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
-       new_owner = PORT_OWNER;         /* Owned by companion */
-       if (sscanf(buf, "%d", &portnum) != 1)
-               return -EINVAL;
-       if (portnum < 0) {
-               portnum = - portnum;
-               new_owner = 0;          /* Owned by EHCI */
-       }
-       if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
-               return -ENOENT;
-       status_reg = &ehci->regs->port_status[--portnum];
-       if (new_owner)
-               set_bit(portnum, &ehci->companion_ports);
-       else
-               clear_bit(portnum, &ehci->companion_ports);
+       status_reg = &ehci->regs->port_status[portnum];
 
        /*
         * The controller won't set the OWNER bit if the port is
         * enabled, so this loop will sometimes require at least two
         * iterations: one to disable the port and one to set OWNER.
         */
-
        for (try = 4; try > 0; --try) {
                spin_lock_irq(&ehci->lock);
                port_status = ehci_readl(ehci, status_reg);
@@ -362,9 +341,39 @@ static ssize_t store_companion(struct class_device *class_dev,
                if (try > 1)
                        msleep(5);
        }
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct ehci_hcd         *ehci;
+       int                     portnum, new_owner;
+
+       ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+       new_owner = PORT_OWNER;         /* Owned by companion */
+       if (sscanf(buf, "%d", &portnum) != 1)
+               return -EINVAL;
+       if (portnum < 0) {
+               portnum = - portnum;
+               new_owner = 0;          /* Owned by EHCI */
+       }
+       if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+               return -ENOENT;
+       portnum--;
+       if (new_owner)
+               set_bit(portnum, &ehci->companion_ports);
+       else
+               clear_bit(portnum, &ehci->companion_ports);
+       set_owner(ehci, portnum, new_owner);
        return count;
 }
-static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
 
 static inline void create_companion_file(struct ehci_hcd *ehci)
 {
@@ -372,16 +381,16 @@ static inline void create_companion_file(struct ehci_hcd *ehci)
 
        /* with integrated TT there is no companion! */
        if (!ehci_is_TDI(ehci))
-               i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
-                               &class_device_attr_companion);
+               i = device_create_file(ehci_to_hcd(ehci)->self.dev,
+                                      &dev_attr_companion);
 }
 
 static inline void remove_companion_file(struct ehci_hcd *ehci)
 {
        /* with integrated TT there is no companion! */
        if (!ehci_is_TDI(ehci))
-               class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
-                               &class_device_attr_companion);
+               device_remove_file(ehci_to_hcd(ehci)->self.dev,
+                                  &dev_attr_companion);
 }
 
 
@@ -393,10 +402,8 @@ static int check_reset_complete (
        u32 __iomem     *status_reg,
        int             port_status
 ) {
-       if (!(port_status & PORT_CONNECT)) {
-               ehci->reset_done [index] = 0;
+       if (!(port_status & PORT_CONNECT))
                return port_status;
-       }
 
        /* if reset finished and it's still not enabled -- handoff */
        if (!(port_status & PORT_PE)) {
@@ -475,8 +482,6 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
                 * controller by the user.
                 */
 
-               if (!(temp & PORT_CONNECT))
-                       ehci->reset_done [i] = 0;
                if ((temp & mask) != 0
                                || ((temp & PORT_RESUME) != 0
                                        && time_after_eq(jiffies,
@@ -525,13 +530,11 @@ ehci_hub_descriptor (
        if (HCS_INDICATOR (ehci->hcs_params))
                temp |= 0x0080;         /* per-port indicators (LEDs) */
 #endif
-       desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp);
+       desc->wHubCharacteristics = cpu_to_le16(temp);
 }
 
 /*-------------------------------------------------------------------------*/
 
-#define        PORT_WAKE_BITS  (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-
 static int ehci_hub_control (
        struct usb_hcd  *hcd,
        u16             typeReq,
@@ -606,7 +609,7 @@ static int ehci_hub_control (
                        }
                        break;
                case USB_PORT_FEAT_C_SUSPEND:
-                       /* we auto-clear this feature */
+                       clear_bit(wIndex, &ehci->port_c_suspend);
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
@@ -685,7 +688,7 @@ static int ehci_hub_control (
                        /* resume completed? */
                        else if (time_after_eq(jiffies,
                                        ehci->reset_done[wIndex])) {
-                               status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+                               set_bit(wIndex, &ehci->port_c_suspend);
                                ehci->reset_done[wIndex] = 0;
 
                                /* stop resume signaling */
@@ -762,12 +765,14 @@ static int ehci_hub_control (
                        status |= 1 << USB_PORT_FEAT_RESET;
                if (temp & PORT_POWER)
                        status |= 1 << USB_PORT_FEAT_POWER;
+               if (test_bit(wIndex, &ehci->port_c_suspend))
+                       status |= 1 << USB_PORT_FEAT_C_SUSPEND;
 
-#ifndef        EHCI_VERBOSE_DEBUG
+#ifndef        VERBOSE_DEBUG
        if (status & ~0xffff)   /* only if wPortChange is interesting */
 #endif
                dbg_port (ehci, "GetStatus", wIndex + 1, temp);
-               put_unaligned(cpu_to_le32 (status), (__le32 *) buf);
+               put_unaligned_le32(status, buf);
                break;
        case SetHubFeature:
                switch (wValue) {
@@ -797,8 +802,6 @@ static int ehci_hub_control (
                        if ((temp & PORT_PE) == 0
                                        || (temp & PORT_RESET) != 0)
                                goto error;
-                       if (device_may_wakeup(&hcd->self.root_hub->dev))
-                               temp |= PORT_WAKE_BITS;
                        ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
                        break;
                case USB_PORT_FEAT_POWER:
@@ -864,3 +867,23 @@ error:
        spin_unlock_irqrestore (&ehci->lock, flags);
        return retval;
 }
+
+static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+
+       if (ehci_is_TDI(ehci))
+               return;
+       set_owner(ehci, --portnum, PORT_OWNER);
+}
+
+static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+       u32 __iomem             *reg;
+
+       if (ehci_is_TDI(ehci))
+               return 0;
+       reg = &ehci->regs->port_status[portnum - 1];
+       return ehci_readl(ehci, reg) & PORT_OWNER;
+}