diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
| -rw-r--r-- | drivers/usb/core/hcd.c | 40 | 
1 files changed, 26 insertions, 14 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6368562d73c..a98d978d76e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -367,21 +367,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  	/* DEVICE REQUESTS */ +	/* The root hub's remote wakeup enable bit is implemented using +	 * driver model wakeup flags.  If this system supports wakeup +	 * through USB, userspace may change the default "allow wakeup" +	 * policy through sysfs or these calls. +	 * +	 * Most root hubs support wakeup from downstream devices, for +	 * runtime power management (disabling USB clocks and reducing +	 * VBUS power usage).  However, not all of them do so; silicon, +	 * board, and BIOS bugs here are not uncommon, so these can't +	 * be treated quite like external hubs. +	 * +	 * Likewise, not all root hubs will pass wakeup events upstream, +	 * to wake up the whole system.  So don't assume root hub and +	 * controller capabilities are identical. +	 */ +  	case DeviceRequest | USB_REQ_GET_STATUS: -		tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) +		tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) +					<< USB_DEVICE_REMOTE_WAKEUP)  				| (1 << USB_DEVICE_SELF_POWERED);  		tbuf [1] = 0;  		len = 2;  		break;  	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:  		if (wValue == USB_DEVICE_REMOTE_WAKEUP) -			hcd->remote_wakeup = 0; +			device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);  		else  			goto error;  		break;  	case DeviceOutRequest | USB_REQ_SET_FEATURE: -		if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP) -			hcd->remote_wakeup = 1; +		if (device_can_wakeup(&hcd->self.root_hub->dev) +				&& wValue == USB_DEVICE_REMOTE_WAKEUP) +			device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);  		else  			goto error;  		break; @@ -410,7 +428,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  				bufp = fs_rh_config_descriptor;  				len = sizeof fs_rh_config_descriptor;  			} -			if (hcd->can_wakeup) +			if (device_can_wakeup(&hcd->self.root_hub->dev))  				patch_wakeup = 1;  			break;  		case USB_DT_STRING << 8: @@ -1804,16 +1822,10 @@ int usb_add_hcd(struct usb_hcd *hcd,  	device_init_wakeup(&rhdev->dev,  			device_can_wakeup(hcd->self.controller)); -	// ... all these hcd->*_wakeup flags will vanish -	hcd->can_wakeup = device_can_wakeup(hcd->self.controller); - -	/* hcd->driver->reset() reported can_wakeup, probably with -	 * assistance from board's boot firmware. -	 * NOTE:  normal devices won't enable wakeup by default. -	 */ -	if (hcd->can_wakeup) +	/* NOTE: root hub and controller capabilities may not be the same */ +	if (device_can_wakeup(hcd->self.controller) +			&& device_can_wakeup(&hcd->self.root_hub->dev))  		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); -	hcd->remote_wakeup = hcd->can_wakeup;  	/* enable irqs just before we start the controller */  	if (hcd->driver->irq) {  |