writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME, 
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); writel (temp | PORT_RESUME, 
static int ehci_hub_control (	struct usb_hcd	*hcd,	u16		typeReq,	u16		wValue,	u16		wIndex,	char		*buf,	u16		wLength) {	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);	int		ports = HCS_N_PORTS (ehci->hcs_params);	u32		temp, status;	unsigned long	flags;	int		retval = 0;	/*	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.	 * (track current state ourselves) ... blink for diagnostics,	 * power, "this is the one", etc.  EHCI spec supports this.	 */	spin_lock_irqsave (&ehci->lock, flags);	switch (typeReq) {	case ClearHubFeature:		switch (wValue) {		case C_HUB_LOCAL_POWER:		case C_HUB_OVER_CURRENT:			/* no hub-wide feature/status flags */			break;		default:			goto error;		}		break;	case ClearPortFeature:		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		temp = readl (&ehci->regs->port_status [wIndex]);		if (temp & PORT_OWNER)			break;		switch (wValue) {		case USB_PORT_FEAT_ENABLE:			writel (temp & ~PORT_PE,				&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_C_ENABLE:			writel (temp | PORT_PEC,				&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_SUSPEND:			if (temp & PORT_RESET)				goto error;			if (temp & PORT_SUSPEND) {				if ((temp & PORT_PE) == 0)					goto error;				/* resume signaling for 20 msec */				writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,					&ehci->regs->port_status [wIndex]);				ehci->reset_done [wIndex] = jiffies						+ msecs_to_jiffies (20);			}			break;		case USB_PORT_FEAT_C_SUSPEND:			/* we auto-clear this feature */			break;		case USB_PORT_FEAT_POWER:			if (HCS_PPC (ehci->hcs_params))				writel (temp & ~PORT_POWER,					&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_C_CONNECTION:			writel (temp | PORT_CSC,				&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_C_OVER_CURRENT:			writel (temp | PORT_OCC,				&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_C_RESET:			/* GetPortStatus clears reset */			break;		default:			goto error;		}		readl (&ehci->regs->command);	/* unblock posted write */		break;	case GetHubDescriptor:		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)			buf);		break;	case GetHubStatus:		/* no hub-wide feature/status flags */		memset (buf, 0, 4);		//cpu_to_le32s ((u32 *) buf);		break;	case GetPortStatus:		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		status = 0;		temp = readl (&ehci->regs->port_status [wIndex]);		// wPortChange bits		if (temp & PORT_CSC)			status |= 1 << USB_PORT_FEAT_C_CONNECTION;		if (temp & PORT_PEC)			status |= 1 << USB_PORT_FEAT_C_ENABLE;		if (temp & PORT_OCC)			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;		/* whoever resumes must GetPortStatus to complete it!! */		if ((temp & PORT_RESUME)				&& time_after (jiffies,					ehci->reset_done [wIndex])) {			status |= 1 << USB_PORT_FEAT_C_SUSPEND;			ehci->reset_done [wIndex] = 0;			/* stop resume signaling */			temp = readl (&ehci->regs->port_status [wIndex]);			writel (temp & ~PORT_RESUME,				&ehci->regs->port_status [wIndex]);			retval = handshake (					&ehci->regs->port_status [wIndex],					PORT_RESUME, 0, 2000 /* 2msec */);			if (retval != 0) {				ehci_err (ehci, "port %d resume error %d\n",					wIndex + 1, retval);				goto error;			}			temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));		}		/* whoever resets must GetPortStatus to complete it!! */		if ((temp & PORT_RESET)				&& time_after (jiffies,					ehci->reset_done [wIndex])) {			status |= 1 << USB_PORT_FEAT_C_RESET;			ehci->reset_done [wIndex] = 0;			/* force reset to complete */			writel (temp & ~PORT_RESET,					&ehci->regs->port_status [wIndex]);			/* REVISIT:  some hardware needs 550+ usec to clear			 * this bit; seems too long to spin routinely...			 */			retval = handshake (					&ehci->regs->port_status [wIndex],					PORT_RESET, 0, 750);			if (retval != 0) {				ehci_err (ehci, "port %d reset error %d\n",					wIndex + 1, retval);				goto error;			}			/* see what we found out */			temp = check_reset_complete (ehci, wIndex,				readl (&ehci->regs->port_status [wIndex]));		}		// don't show wPortStatus if it's owned by a companion hc		if (!(temp & PORT_OWNER)) {			if (temp & PORT_CONNECT) {				status |= 1 << USB_PORT_FEAT_CONNECTION;				// status may be from integrated TT				status |= ehci_port_speed(ehci, temp);			}			if (temp & PORT_PE)				status |= 1 << USB_PORT_FEAT_ENABLE;			if (temp & (PORT_SUSPEND|PORT_RESUME))				status |= 1 << USB_PORT_FEAT_SUSPEND;			if (temp & PORT_OC)				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;			if (temp & PORT_RESET)				status |= 1 << USB_PORT_FEAT_RESET;			if (temp & PORT_POWER)				status |= 1 << USB_PORT_FEAT_POWER;		}#ifndef	EHCI_VERBOSE_DEBUG	if (status & ~0xffff)	/* only if wPortChange is interesting */#endif		dbg_port (ehci, "GetStatus", wIndex + 1, temp);		// we "know" this alignment is good, caller used kmalloc()...		*((__le32 *) buf) = cpu_to_le32 (status);		break;	case SetHubFeature:		switch (wValue) {		case C_HUB_LOCAL_POWER:		case C_HUB_OVER_CURRENT:			/* no hub-wide feature/status flags */			break;		default:			goto error;		}		break;	case SetPortFeature:		if (!wIndex || wIndex > ports)			goto error;		wIndex--;		temp = readl (&ehci->regs->port_status [wIndex]);		if (temp & PORT_OWNER)			break;		switch (wValue) {		case USB_PORT_FEAT_SUSPEND:			if ((temp & PORT_PE) == 0					|| (temp & PORT_RESET) != 0)				goto error;			if (hcd->remote_wakeup)				temp |= PORT_WAKE_BITS;			writel (temp | PORT_SUSPEND,				&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_POWER:			if (HCS_PPC (ehci->hcs_params))				writel (temp | PORT_POWER,					&ehci->regs->port_status [wIndex]);			break;		case USB_PORT_FEAT_RESET:			if (temp & PORT_RESUME)				goto error;			/* line status bits may report this as low speed,			 * which can be fine if this root hub has a			 * transaction translator built in.			 */			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT					&& !ehci_is_TDI(ehci)					&& PORT_USB11 (temp)) {				ehci_dbg (ehci,					"port %d low speed --> companion\n",					wIndex + 1);				temp |= PORT_OWNER;			} else {				ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);				temp |= PORT_RESET;				temp &= ~PORT_PE;				/*				 * caller must wait, then call GetPortStatus				 * usb 2.0 spec says 50 ms resets on root				 */				ehci->reset_done [wIndex] = jiffies						+ msecs_to_jiffies (50);			}			writel (temp, &ehci->regs->port_status [wIndex]);			break;		default:			goto error;		}		readl (&ehci->regs->command);	/* unblock posted writes */		break;	default:error:		/* "stall" on error */		retval = -EPIPE;	}	spin_unlock_irqrestore (&ehci->lock, flags);	return retval;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/10f6524a8ef1413a8cbd952673997013183fe2a9/ehci-hub.c/buggy/drivers/usb/host/ehci-hub.c