Commit 1d6569cd authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: root hubs can report remote wakeup feature

The patch lets HCDs report the root hub remote wakeup feature to usbcore
through config descriptors, and lets usbcore say whether or not remote
wakeup (of host from sleep, by devices) should be enabled.

Both OHCI and UHCI HCDs have some remote wakeup support already; I'm not
too sure how well it works.  Given (separate) patches, their root hubs
can start to act more like other hubs in this area too.  That'll make
it easier to start using USB suspend mode.
parent 2aad220d
...@@ -171,10 +171,10 @@ static const u8 fs_rh_config_descriptor [] = { ...@@ -171,10 +171,10 @@ static const u8 fs_rh_config_descriptor [] = {
0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */ 0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */ 0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes; 0xc0, /* __u8 bmAttributes;
Bit 7: Bus-powered, Bit 7: must be set,
6: Self-powered, 6: Self-powered,
5 Remote-wakwup, 5: Remote wakeup,
4..0: resvd */ 4..0: resvd */
0x00, /* __u8 MaxPower; */ 0x00, /* __u8 MaxPower; */
...@@ -218,10 +218,10 @@ static const u8 hs_rh_config_descriptor [] = { ...@@ -218,10 +218,10 @@ static const u8 hs_rh_config_descriptor [] = {
0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */ 0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */ 0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes; 0xc0, /* __u8 bmAttributes;
Bit 7: Bus-powered, Bit 7: must be set,
6: Self-powered, 6: Self-powered,
5 Remote-wakwup, 5: Remote wakeup,
4..0: resvd */ 4..0: resvd */
0x00, /* __u8 MaxPower; */ 0x00, /* __u8 MaxPower; */
...@@ -324,13 +324,15 @@ static int rh_string ( ...@@ -324,13 +324,15 @@ static int rh_string (
/* Root hub control transfers execute synchronously */ /* Root hub control transfers execute synchronously */
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
{ {
struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength; u16 typeReq, wValue, wIndex, wLength;
const u8 *bufp = 0; const u8 *bufp = 0;
u8 *ubuf = urb->transfer_buffer; u8 *ubuf = urb->transfer_buffer;
int len = 0; int len = 0;
int patch_wakeup = 0;
unsigned long flags; unsigned long flags;
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest; typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue); wValue = le16_to_cpu (cmd->wValue);
wIndex = le16_to_cpu (cmd->wIndex); wIndex = le16_to_cpu (cmd->wIndex);
...@@ -347,13 +349,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -347,13 +349,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* DEVICE REQUESTS */ /* DEVICE REQUESTS */
case DeviceRequest | USB_REQ_GET_STATUS: case DeviceRequest | USB_REQ_GET_STATUS:
// DEVICE_REMOTE_WAKEUP ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
ubuf [0] = 1; // selfpowered | (1 << USB_DEVICE_SELF_POWERED);
ubuf [1] = 0; ubuf [1] = 0;
/* FALLTHROUGH */ break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (wValue == USB_DEVICE_REMOTE_WAKEUP)
hcd->remote_wakeup = 0;
else
goto error;
break;
case DeviceOutRequest | USB_REQ_SET_FEATURE: case DeviceOutRequest | USB_REQ_SET_FEATURE:
dev_dbg (hcd->self.controller, "no device features yet yet\n"); if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
hcd->remote_wakeup = 1;
else
goto error;
break; break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION: case DeviceRequest | USB_REQ_GET_CONFIGURATION:
ubuf [0] = 1; ubuf [0] = 1;
...@@ -379,6 +389,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -379,6 +389,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
bufp = fs_rh_config_descriptor; bufp = fs_rh_config_descriptor;
len = sizeof fs_rh_config_descriptor; len = sizeof fs_rh_config_descriptor;
} }
if (hcd->can_wakeup)
patch_wakeup = 1;
break; break;
case USB_DT_STRING << 8: case USB_DT_STRING << 8:
urb->actual_length = rh_string ( urb->actual_length = rh_string (
...@@ -444,6 +456,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -444,6 +456,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
urb->actual_length = len; urb->actual_length = len;
// always USB_DIR_IN, toward host // always USB_DIR_IN, toward host
memcpy (ubuf, bufp, len); memcpy (ubuf, bufp, len);
/* report whether RH hardware supports remote wakeup */
if (patch_wakeup)
((struct usb_config_descriptor *)ubuf)->bmAttributes
|= USB_CONFIG_ATT_WAKEUP;
} }
/* any errors get returned through the urb completion */ /* any errors get returned through the urb completion */
......
...@@ -74,6 +74,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -74,6 +74,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
*/ */
struct hc_driver *driver; /* hw-specific hooks */ struct hc_driver *driver; /* hw-specific hooks */
unsigned saw_irq : 1; unsigned saw_irq : 1;
unsigned can_wakeup:1; /* hw supports wakeup? */
unsigned remote_wakeup:1;/* sw should use wakeup? */
int irq; /* irq allocated */ int irq; /* irq allocated */
void *regs; /* device memory/io */ void *regs; /* device memory/io */
...@@ -344,9 +346,16 @@ extern void usb_deregister_bus (struct usb_bus *); ...@@ -344,9 +346,16 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_dev, extern int usb_register_root_hub (struct usb_device *usb_dev,
struct device *parent_dev); struct device *parent_dev);
/* for portability to 2.4, hcds should call this */
static inline int hcd_register_root (struct usb_hcd *hcd) static inline int hcd_register_root (struct usb_hcd *hcd)
{ {
/* hcd->driver->start() reported can_wakeup, probably with
* assistance from board's boot firmware.
* NOTE: normal devices won't enable wakeup by default.
*/
if (hcd->can_wakeup)
dev_dbg (hcd->self.controller, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup;
return usb_register_root_hub ( return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->self.controller); hcd_to_bus (hcd)->root_hub, hcd->self.controller);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment