X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fehci-hub.c;h=740835bb85758ff260557d2b38dda2911d29dc25;hb=8e2fc39ddea7fe8c6798837da282db88a09af793;hp=735db4aec831cc2302a761801f51eccc25efdeb7;hpb=3a4fa0a25da81600ea0bcd75692ae8ca6050d165;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 735db4a..740835b 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -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; +}