xref: /linux/drivers/usb/host/uhci-hub.c (revision b8fb6f79f76f478acbbffccc966daa878f172a0a)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Universal Host Controller Interface driver for USB.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Maintainer: Alan Stern <stern@rowland.harvard.edu>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * (C) Copyright 1999 Linus Torvalds
71da177e4SLinus Torvalds  * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
81da177e4SLinus Torvalds  * (C) Copyright 1999 Randy Dunlap
91da177e4SLinus Torvalds  * (C) Copyright 1999 Georg Acher, acher@in.tum.de
101da177e4SLinus Torvalds  * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
111da177e4SLinus Torvalds  * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
121da177e4SLinus Torvalds  * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15bef4665aSMing Lei static const __u8 root_hub_hub_des[] =
161da177e4SLinus Torvalds {
171da177e4SLinus Torvalds 	0x09,			/*  __u8  bLength; */
181da177e4SLinus Torvalds 	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
191da177e4SLinus Torvalds 	0x02,			/*  __u8  bNbrPorts; */
20673016d9SSergei Shtylyov 	HUB_CHAR_NO_LPSM |	/* __u16  wHubCharacteristics; */
21673016d9SSergei Shtylyov 		HUB_CHAR_INDV_PORT_OCPM, /* (per-port OC, no power switching) */
22673016d9SSergei Shtylyov 	0x00,
231da177e4SLinus Torvalds 	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
241da177e4SLinus Torvalds 	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
253171fcabSChen Gang 	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max */
263171fcabSChen Gang 	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max */
271da177e4SLinus Torvalds };
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define	UHCI_RH_MAXCHILD	7
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds /* must write as zeroes */
321da177e4SLinus Torvalds #define WZ_BITS		(USBPORTSC_RES2 | USBPORTSC_RES3 | USBPORTSC_RES4)
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds /* status change bits:  nonzero writes will clear */
351da177e4SLinus Torvalds #define RWC_BITS	(USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
361da177e4SLinus Torvalds 
3788018158SAlan Stern /* suspend/resume bits: port suspended or port resuming */
3888018158SAlan Stern #define SUSPEND_BITS	(USBPORTSC_SUSP | USBPORTSC_RD)
3988018158SAlan Stern 
40f5946f82SAlan Stern /* A port that either is connected or has a changed-bit set will prevent
41f5946f82SAlan Stern  * us from AUTO_STOPPING.
42f5946f82SAlan Stern  */
43f5946f82SAlan Stern static int any_ports_active(struct uhci_hcd *uhci)
44f5946f82SAlan Stern {
45f5946f82SAlan Stern 	int port;
46f5946f82SAlan Stern 
47f5946f82SAlan Stern 	for (port = 0; port < uhci->rh_numports; ++port) {
489faa091aSJan Andersson 		if ((uhci_readw(uhci, USBPORTSC1 + port * 2) &
49f5946f82SAlan Stern 				(USBPORTSC_CCS | RWC_BITS)) ||
50f5946f82SAlan Stern 				test_bit(port, &uhci->port_c_suspend))
51f5946f82SAlan Stern 			return 1;
52f5946f82SAlan Stern 	}
53f5946f82SAlan Stern 	return 0;
54f5946f82SAlan Stern }
55f5946f82SAlan Stern 
566c1b445cSAlan Stern static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	int port;
595f8364b7SAlan Stern 	int mask = RWC_BITS;
605f8364b7SAlan Stern 
615f8364b7SAlan Stern 	/* Some boards (both VIA and Intel apparently) report bogus
625f8364b7SAlan Stern 	 * overcurrent indications, causing massive log spam unless
635f8364b7SAlan Stern 	 * we completely ignore them.  This doesn't seem to be a problem
645f8364b7SAlan Stern 	 * with the chipset so much as with the way it is connected on
655f8364b7SAlan Stern 	 * the motherboard; if the overcurrent input is left to float
665f8364b7SAlan Stern 	 * then it may constantly register false positives. */
675f8364b7SAlan Stern 	if (ignore_oc)
685f8364b7SAlan Stern 		mask &= ~USBPORTSC_OCC;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	*buf = 0;
711da177e4SLinus Torvalds 	for (port = 0; port < uhci->rh_numports; ++port) {
729faa091aSJan Andersson 		if ((uhci_readw(uhci, USBPORTSC1 + port * 2) & mask) ||
731da177e4SLinus Torvalds 				test_bit(port, &uhci->port_c_suspend))
741da177e4SLinus Torvalds 			*buf |= (1 << (port + 1));
751da177e4SLinus Torvalds 	}
761da177e4SLinus Torvalds 	return !!*buf;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds #define CLR_RH_PORTSTAT(x) \
809faa091aSJan Andersson 	status = uhci_readw(uhci, port_addr);	\
811da177e4SLinus Torvalds 	status &= ~(RWC_BITS|WZ_BITS); \
821da177e4SLinus Torvalds 	status &= ~(x); \
831da177e4SLinus Torvalds 	status |= RWC_BITS & (x); \
849faa091aSJan Andersson 	uhci_writew(uhci, status, port_addr)
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds #define SET_RH_PORTSTAT(x) \
879faa091aSJan Andersson 	status = uhci_readw(uhci, port_addr);	\
881da177e4SLinus Torvalds 	status |= (x); \
891da177e4SLinus Torvalds 	status &= ~(RWC_BITS|WZ_BITS); \
909faa091aSJan Andersson 	uhci_writew(uhci, status, port_addr)
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds /* UHCI controllers don't automatically stop resume signalling after 20 msec,
931da177e4SLinus Torvalds  * so we have to poll and check timeouts in order to take care of it.
941da177e4SLinus Torvalds  */
951da177e4SLinus Torvalds static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
961da177e4SLinus Torvalds 		unsigned long port_addr)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	int status;
99de06a3b8SAlan Stern 	int i;
1001da177e4SLinus Torvalds 
1019faa091aSJan Andersson 	if (uhci_readw(uhci, port_addr) & SUSPEND_BITS) {
10288018158SAlan Stern 		CLR_RH_PORTSTAT(SUSPEND_BITS);
1038e326406SAlan Stern 		if (test_bit(port, &uhci->resuming_ports))
1041da177e4SLinus Torvalds 			set_bit(port, &uhci->port_c_suspend);
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 		/* The controller won't actually turn off the RD bit until
1071da177e4SLinus Torvalds 		 * it has had a chance to send a low-speed EOP sequence,
108de06a3b8SAlan Stern 		 * which is supposed to take 3 bit times (= 2 microseconds).
109de06a3b8SAlan Stern 		 * Experiments show that some controllers take longer, so
110de06a3b8SAlan Stern 		 * we'll poll for completion. */
111de06a3b8SAlan Stern 		for (i = 0; i < 10; ++i) {
1129faa091aSJan Andersson 			if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS))
113de06a3b8SAlan Stern 				break;
114de06a3b8SAlan Stern 			udelay(1);
115de06a3b8SAlan Stern 		}
1161da177e4SLinus Torvalds 	}
1178e326406SAlan Stern 	clear_bit(port, &uhci->resuming_ports);
118840008bbSAlan Stern 	usb_hcd_end_port_resume(&uhci_to_hcd(uhci)->self, port);
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds 
121ae557175SAlan Stern /* Wait for the UHCI controller in HP's iLO2 server management chip.
122ae557175SAlan Stern  * It can take up to 250 us to finish a reset and set the CSC bit.
123ae557175SAlan Stern  */
1249faa091aSJan Andersson static void wait_for_HP(struct uhci_hcd *uhci, unsigned long port_addr)
125ae557175SAlan Stern {
126ae557175SAlan Stern 	int i;
127ae557175SAlan Stern 
128ae557175SAlan Stern 	for (i = 10; i < 250; i += 10) {
1299faa091aSJan Andersson 		if (uhci_readw(uhci, port_addr) & USBPORTSC_CSC)
130ae557175SAlan Stern 			return;
131ae557175SAlan Stern 		udelay(10);
132ae557175SAlan Stern 	}
133ae557175SAlan Stern 	/* Log a warning? */
134ae557175SAlan Stern }
135ae557175SAlan Stern 
1361da177e4SLinus Torvalds static void uhci_check_ports(struct uhci_hcd *uhci)
1371da177e4SLinus Torvalds {
1381da177e4SLinus Torvalds 	unsigned int port;
1391da177e4SLinus Torvalds 	unsigned long port_addr;
1401da177e4SLinus Torvalds 	int status;
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	for (port = 0; port < uhci->rh_numports; ++port) {
1439faa091aSJan Andersson 		port_addr = USBPORTSC1 + 2 * port;
1449faa091aSJan Andersson 		status = uhci_readw(uhci, port_addr);
1451da177e4SLinus Torvalds 		if (unlikely(status & USBPORTSC_PR)) {
1461da177e4SLinus Torvalds 			if (time_after_eq(jiffies, uhci->ports_timeout)) {
1471da177e4SLinus Torvalds 				CLR_RH_PORTSTAT(USBPORTSC_PR);
1481da177e4SLinus Torvalds 				udelay(10);
1491da177e4SLinus Torvalds 
150ae557175SAlan Stern 				/* HP's server management chip requires
151ae557175SAlan Stern 				 * a longer delay. */
152dfeca7a8SJan Andersson 				if (uhci->wait_for_hp)
1539faa091aSJan Andersson 					wait_for_HP(uhci, port_addr);
154ae557175SAlan Stern 
1551da177e4SLinus Torvalds 				/* If the port was enabled before, turning
1561da177e4SLinus Torvalds 				 * reset on caused a port enable change.
1571da177e4SLinus Torvalds 				 * Turning reset off causes a port connect
1581da177e4SLinus Torvalds 				 * status change.  Clear these changes. */
1591da177e4SLinus Torvalds 				CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
1601da177e4SLinus Torvalds 				SET_RH_PORTSTAT(USBPORTSC_PE);
1611da177e4SLinus Torvalds 			}
1621da177e4SLinus Torvalds 		}
1631da177e4SLinus Torvalds 		if (unlikely(status & USBPORTSC_RD)) {
1641da177e4SLinus Torvalds 			if (!test_bit(port, &uhci->resuming_ports)) {
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 				/* Port received a wakeup request */
1671da177e4SLinus Torvalds 				set_bit(port, &uhci->resuming_ports);
1681da177e4SLinus Torvalds 				uhci->ports_timeout = jiffies +
169*b8fb6f79SFelipe Balbi 					msecs_to_jiffies(USB_RESUME_TIMEOUT);
170840008bbSAlan Stern 				usb_hcd_start_port_resume(
171840008bbSAlan Stern 						&uhci_to_hcd(uhci)->self, port);
1726c1b445cSAlan Stern 
1736c1b445cSAlan Stern 				/* Make sure we see the port again
1746c1b445cSAlan Stern 				 * after the resuming period is over. */
1756c1b445cSAlan Stern 				mod_timer(&uhci_to_hcd(uhci)->rh_timer,
1766c1b445cSAlan Stern 						uhci->ports_timeout);
1771da177e4SLinus Torvalds 			} else if (time_after_eq(jiffies,
1781da177e4SLinus Torvalds 						uhci->ports_timeout)) {
1791da177e4SLinus Torvalds 				uhci_finish_suspend(uhci, port, port_addr);
1801da177e4SLinus Torvalds 			}
1811da177e4SLinus Torvalds 		}
1821da177e4SLinus Torvalds 	}
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
1856c1b445cSAlan Stern static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
1866c1b445cSAlan Stern {
1876c1b445cSAlan Stern 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
1886c1b445cSAlan Stern 	unsigned long flags;
1891f09df8bSAlan Stern 	int status = 0;
1906c1b445cSAlan Stern 
1916c1b445cSAlan Stern 	spin_lock_irqsave(&uhci->lock, flags);
1926c1b445cSAlan Stern 
1937d12e780SDavid Howells 	uhci_scan_schedule(uhci);
194541c7d43SAlan Stern 	if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
1951f09df8bSAlan Stern 		goto done;
1966c1b445cSAlan Stern 	uhci_check_ports(uhci);
1971f09df8bSAlan Stern 
1986c1b445cSAlan Stern 	status = get_hub_status_data(uhci, buf);
1996c1b445cSAlan Stern 
2006c1b445cSAlan Stern 	switch (uhci->rh_state) {
2016c1b445cSAlan Stern 	    case UHCI_RH_SUSPENDED:
2026c1b445cSAlan Stern 		/* if port change, ask to be resumed */
203b446b96fSAlan Stern 		if (status || uhci->resuming_ports) {
204b446b96fSAlan Stern 			status = 1;
2056c1b445cSAlan Stern 			usb_hcd_resume_root_hub(hcd);
206b446b96fSAlan Stern 		}
2076c1b445cSAlan Stern 		break;
2086c1b445cSAlan Stern 
2096c1b445cSAlan Stern 	    case UHCI_RH_AUTO_STOPPED:
2106c1b445cSAlan Stern 		/* if port change, auto start */
2116c1b445cSAlan Stern 		if (status)
2126c1b445cSAlan Stern 			wakeup_rh(uhci);
2136c1b445cSAlan Stern 		break;
2146c1b445cSAlan Stern 
2156c1b445cSAlan Stern 	    case UHCI_RH_RUNNING:
2166c1b445cSAlan Stern 		/* are any devices attached? */
2176c1b445cSAlan Stern 		if (!any_ports_active(uhci)) {
2186c1b445cSAlan Stern 			uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
2196c1b445cSAlan Stern 			uhci->auto_stop_time = jiffies + HZ;
2206c1b445cSAlan Stern 		}
2216c1b445cSAlan Stern 		break;
2226c1b445cSAlan Stern 
2236c1b445cSAlan Stern 	    case UHCI_RH_RUNNING_NODEVS:
2246c1b445cSAlan Stern 		/* auto-stop if nothing connected for 1 second */
2256c1b445cSAlan Stern 		if (any_ports_active(uhci))
2266c1b445cSAlan Stern 			uhci->rh_state = UHCI_RH_RUNNING;
227997ff893SAlan Stern 		else if (time_after_eq(jiffies, uhci->auto_stop_time) &&
228997ff893SAlan Stern 				!uhci->wait_for_hp)
2296c1b445cSAlan Stern 			suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
2306c1b445cSAlan Stern 		break;
2316c1b445cSAlan Stern 
2326c1b445cSAlan Stern 	    default:
2336c1b445cSAlan Stern 		break;
2346c1b445cSAlan Stern 	}
2356c1b445cSAlan Stern 
2366c1b445cSAlan Stern done:
2376c1b445cSAlan Stern 	spin_unlock_irqrestore(&uhci->lock, flags);
2386c1b445cSAlan Stern 	return status;
2396c1b445cSAlan Stern }
2406c1b445cSAlan Stern 
2411da177e4SLinus Torvalds /* size of returned buffer is part of USB spec */
2421da177e4SLinus Torvalds static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
2431da177e4SLinus Torvalds 			u16 wIndex, char *buf, u16 wLength)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
2465a3e2055SDeng-Cheng Zhu 	int status, lstatus, retval = 0;
2471da177e4SLinus Torvalds 	unsigned int port = wIndex - 1;
2489faa091aSJan Andersson 	unsigned long port_addr = USBPORTSC1 + 2 * port;
2491da177e4SLinus Torvalds 	u16 wPortChange, wPortStatus;
2501da177e4SLinus Torvalds 	unsigned long flags;
2511da177e4SLinus Torvalds 
252541c7d43SAlan Stern 	if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
253a8bed8b6SAlan Stern 		return -ETIMEDOUT;
254a8bed8b6SAlan Stern 
2551da177e4SLinus Torvalds 	spin_lock_irqsave(&uhci->lock, flags);
2561da177e4SLinus Torvalds 	switch (typeReq) {
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	case GetHubStatus:
2591da177e4SLinus Torvalds 		*(__le32 *)buf = cpu_to_le32(0);
2605a3e2055SDeng-Cheng Zhu 		retval = 4; /* hub power */
2615a3e2055SDeng-Cheng Zhu 		break;
2621da177e4SLinus Torvalds 	case GetPortStatus:
2631da177e4SLinus Torvalds 		if (port >= uhci->rh_numports)
2641da177e4SLinus Torvalds 			goto err;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 		uhci_check_ports(uhci);
2679faa091aSJan Andersson 		status = uhci_readw(uhci, port_addr);
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 		/* Intel controllers report the OverCurrent bit active on.
2701da177e4SLinus Torvalds 		 * VIA controllers report it active off, so we'll adjust the
2711da177e4SLinus Torvalds 		 * bit value.  (It's not standardized in the UHCI spec.)
2721da177e4SLinus Torvalds 		 */
273dfeca7a8SJan Andersson 		if (uhci->oc_low)
2741da177e4SLinus Torvalds 			status ^= USBPORTSC_OC;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 		/* UHCI doesn't support C_RESET (always false) */
2771da177e4SLinus Torvalds 		wPortChange = lstatus = 0;
2781da177e4SLinus Torvalds 		if (status & USBPORTSC_CSC)
2791da177e4SLinus Torvalds 			wPortChange |= USB_PORT_STAT_C_CONNECTION;
2801da177e4SLinus Torvalds 		if (status & USBPORTSC_PEC)
2811da177e4SLinus Torvalds 			wPortChange |= USB_PORT_STAT_C_ENABLE;
2825f8364b7SAlan Stern 		if ((status & USBPORTSC_OCC) && !ignore_oc)
2831da177e4SLinus Torvalds 			wPortChange |= USB_PORT_STAT_C_OVERCURRENT;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 		if (test_bit(port, &uhci->port_c_suspend)) {
2861da177e4SLinus Torvalds 			wPortChange |= USB_PORT_STAT_C_SUSPEND;
2871da177e4SLinus Torvalds 			lstatus |= 1;
2881da177e4SLinus Torvalds 		}
2891da177e4SLinus Torvalds 		if (test_bit(port, &uhci->resuming_ports))
2901da177e4SLinus Torvalds 			lstatus |= 4;
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 		/* UHCI has no power switching (always on) */
2931da177e4SLinus Torvalds 		wPortStatus = USB_PORT_STAT_POWER;
2941da177e4SLinus Torvalds 		if (status & USBPORTSC_CCS)
2951da177e4SLinus Torvalds 			wPortStatus |= USB_PORT_STAT_CONNECTION;
2961da177e4SLinus Torvalds 		if (status & USBPORTSC_PE) {
2971da177e4SLinus Torvalds 			wPortStatus |= USB_PORT_STAT_ENABLE;
29888018158SAlan Stern 			if (status & SUSPEND_BITS)
2991da177e4SLinus Torvalds 				wPortStatus |= USB_PORT_STAT_SUSPEND;
3001da177e4SLinus Torvalds 		}
3011da177e4SLinus Torvalds 		if (status & USBPORTSC_OC)
3021da177e4SLinus Torvalds 			wPortStatus |= USB_PORT_STAT_OVERCURRENT;
3031da177e4SLinus Torvalds 		if (status & USBPORTSC_PR)
3041da177e4SLinus Torvalds 			wPortStatus |= USB_PORT_STAT_RESET;
3051da177e4SLinus Torvalds 		if (status & USBPORTSC_LSDA)
3061da177e4SLinus Torvalds 			wPortStatus |= USB_PORT_STAT_LOW_SPEED;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 		if (wPortChange)
3091da177e4SLinus Torvalds 			dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n",
3101da177e4SLinus Torvalds 					wIndex, status, lstatus);
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 		*(__le16 *)buf = cpu_to_le16(wPortStatus);
3131da177e4SLinus Torvalds 		*(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);
3145a3e2055SDeng-Cheng Zhu 		retval = 4;
3155a3e2055SDeng-Cheng Zhu 		break;
3161da177e4SLinus Torvalds 	case SetHubFeature:		/* We don't implement these */
3171da177e4SLinus Torvalds 	case ClearHubFeature:
3181da177e4SLinus Torvalds 		switch (wValue) {
3191da177e4SLinus Torvalds 		case C_HUB_OVER_CURRENT:
3201da177e4SLinus Torvalds 		case C_HUB_LOCAL_POWER:
3215a3e2055SDeng-Cheng Zhu 			break;
3221da177e4SLinus Torvalds 		default:
3231da177e4SLinus Torvalds 			goto err;
3241da177e4SLinus Torvalds 		}
3251da177e4SLinus Torvalds 		break;
3261da177e4SLinus Torvalds 	case SetPortFeature:
3271da177e4SLinus Torvalds 		if (port >= uhci->rh_numports)
3281da177e4SLinus Torvalds 			goto err;
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 		switch (wValue) {
3311da177e4SLinus Torvalds 		case USB_PORT_FEAT_SUSPEND:
3321da177e4SLinus Torvalds 			SET_RH_PORTSTAT(USBPORTSC_SUSP);
3335a3e2055SDeng-Cheng Zhu 			break;
3341da177e4SLinus Torvalds 		case USB_PORT_FEAT_RESET:
3351da177e4SLinus Torvalds 			SET_RH_PORTSTAT(USBPORTSC_PR);
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 			/* Reset terminates Resume signalling */
3381da177e4SLinus Torvalds 			uhci_finish_suspend(uhci, port, port_addr);
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 			/* USB v2.0 7.1.7.5 */
341*b8fb6f79SFelipe Balbi 			uhci->ports_timeout = jiffies +
342*b8fb6f79SFelipe Balbi 				msecs_to_jiffies(USB_RESUME_TIMEOUT);
3435a3e2055SDeng-Cheng Zhu 			break;
3441da177e4SLinus Torvalds 		case USB_PORT_FEAT_POWER:
3451da177e4SLinus Torvalds 			/* UHCI has no power switching */
3465a3e2055SDeng-Cheng Zhu 			break;
3471da177e4SLinus Torvalds 		default:
3481da177e4SLinus Torvalds 			goto err;
3491da177e4SLinus Torvalds 		}
3501da177e4SLinus Torvalds 		break;
3511da177e4SLinus Torvalds 	case ClearPortFeature:
3521da177e4SLinus Torvalds 		if (port >= uhci->rh_numports)
3531da177e4SLinus Torvalds 			goto err;
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 		switch (wValue) {
3561da177e4SLinus Torvalds 		case USB_PORT_FEAT_ENABLE:
3571da177e4SLinus Torvalds 			CLR_RH_PORTSTAT(USBPORTSC_PE);
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 			/* Disable terminates Resume signalling */
3601da177e4SLinus Torvalds 			uhci_finish_suspend(uhci, port, port_addr);
3615a3e2055SDeng-Cheng Zhu 			break;
3621da177e4SLinus Torvalds 		case USB_PORT_FEAT_C_ENABLE:
3631da177e4SLinus Torvalds 			CLR_RH_PORTSTAT(USBPORTSC_PEC);
3645a3e2055SDeng-Cheng Zhu 			break;
3651da177e4SLinus Torvalds 		case USB_PORT_FEAT_SUSPEND:
3669faa091aSJan Andersson 			if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) {
3678e326406SAlan Stern 
3688e326406SAlan Stern 				/* Make certain the port isn't suspended */
3698e326406SAlan Stern 				uhci_finish_suspend(uhci, port, port_addr);
3708e326406SAlan Stern 			} else if (!test_and_set_bit(port,
3711da177e4SLinus Torvalds 						&uhci->resuming_ports)) {
3721da177e4SLinus Torvalds 				SET_RH_PORTSTAT(USBPORTSC_RD);
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 				/* The controller won't allow RD to be set
3751da177e4SLinus Torvalds 				 * if the port is disabled.  When this happens
3761da177e4SLinus Torvalds 				 * just skip the Resume signalling.
3771da177e4SLinus Torvalds 				 */
3789faa091aSJan Andersson 				if (!(uhci_readw(uhci, port_addr) &
3799faa091aSJan Andersson 						USBPORTSC_RD))
3801da177e4SLinus Torvalds 					uhci_finish_suspend(uhci, port,
3811da177e4SLinus Torvalds 							port_addr);
3821da177e4SLinus Torvalds 				else
3831da177e4SLinus Torvalds 					/* USB v2.0 7.1.7.7 */
3841da177e4SLinus Torvalds 					uhci->ports_timeout = jiffies +
3851da177e4SLinus Torvalds 						msecs_to_jiffies(20);
3861da177e4SLinus Torvalds 			}
3875a3e2055SDeng-Cheng Zhu 			break;
3881da177e4SLinus Torvalds 		case USB_PORT_FEAT_C_SUSPEND:
3891da177e4SLinus Torvalds 			clear_bit(port, &uhci->port_c_suspend);
3905a3e2055SDeng-Cheng Zhu 			break;
3911da177e4SLinus Torvalds 		case USB_PORT_FEAT_POWER:
3921da177e4SLinus Torvalds 			/* UHCI has no power switching */
3931da177e4SLinus Torvalds 			goto err;
3941da177e4SLinus Torvalds 		case USB_PORT_FEAT_C_CONNECTION:
3951da177e4SLinus Torvalds 			CLR_RH_PORTSTAT(USBPORTSC_CSC);
3965a3e2055SDeng-Cheng Zhu 			break;
3971da177e4SLinus Torvalds 		case USB_PORT_FEAT_C_OVER_CURRENT:
3981da177e4SLinus Torvalds 			CLR_RH_PORTSTAT(USBPORTSC_OCC);
3995a3e2055SDeng-Cheng Zhu 			break;
4001da177e4SLinus Torvalds 		case USB_PORT_FEAT_C_RESET:
4011da177e4SLinus Torvalds 			/* this driver won't report these */
4025a3e2055SDeng-Cheng Zhu 			break;
4031da177e4SLinus Torvalds 		default:
4041da177e4SLinus Torvalds 			goto err;
4051da177e4SLinus Torvalds 		}
4061da177e4SLinus Torvalds 		break;
4071da177e4SLinus Torvalds 	case GetHubDescriptor:
4085a3e2055SDeng-Cheng Zhu 		retval = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
4095a3e2055SDeng-Cheng Zhu 		memcpy(buf, root_hub_hub_des, retval);
4105a3e2055SDeng-Cheng Zhu 		if (retval > 2)
4111da177e4SLinus Torvalds 			buf[2] = uhci->rh_numports;
4125a3e2055SDeng-Cheng Zhu 		break;
4131da177e4SLinus Torvalds 	default:
4141da177e4SLinus Torvalds err:
4151da177e4SLinus Torvalds 		retval = -EPIPE;
4161da177e4SLinus Torvalds 	}
4171da177e4SLinus Torvalds 	spin_unlock_irqrestore(&uhci->lock, flags);
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	return retval;
4201da177e4SLinus Torvalds }
421