ChangeSet 1.1371.759.2, 2004/04/23 14:48:28-07:00, david-b@pacbell.net [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. drivers/usb/core/hcd.c | 39 ++++++++++++++++++++++++++++----------- drivers/usb/core/hcd.h | 11 ++++++++++- 2 files changed, 38 insertions(+), 12 deletions(-) diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Fri May 14 15:34:43 2004 +++ b/drivers/usb/core/hcd.c Fri May 14 15:34:43 2004 @@ -171,10 +171,10 @@ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, + 0xc0, /* __u8 bmAttributes; + Bit 7: must be set, 6: Self-powered, - 5 Remote-wakwup, + 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ @@ -218,10 +218,10 @@ 0x01, /* __u8 bNumInterfaces; (1) */ 0x01, /* __u8 bConfigurationValue; */ 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, + 0xc0, /* __u8 bmAttributes; + Bit 7: must be set, 6: Self-powered, - 5 Remote-wakwup, + 5: Remote wakeup, 4..0: resvd */ 0x00, /* __u8 MaxPower; */ @@ -324,13 +324,15 @@ /* Root hub control transfers execute synchronously */ 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; const u8 *bufp = 0; u8 *ubuf = urb->transfer_buffer; int len = 0; + int patch_wakeup = 0; unsigned long flags; + cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); wIndex = le16_to_cpu (cmd->wIndex); @@ -347,13 +349,21 @@ /* DEVICE REQUESTS */ case DeviceRequest | USB_REQ_GET_STATUS: - // DEVICE_REMOTE_WAKEUP - ubuf [0] = 1; // selfpowered + ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP) + | (1 << USB_DEVICE_SELF_POWERED); ubuf [1] = 0; - /* FALLTHROUGH */ + break; 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: - 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; case DeviceRequest | USB_REQ_GET_CONFIGURATION: ubuf [0] = 1; @@ -379,6 +389,8 @@ bufp = fs_rh_config_descriptor; len = sizeof fs_rh_config_descriptor; } + if (hcd->can_wakeup) + patch_wakeup = 1; break; case USB_DT_STRING << 8: urb->actual_length = rh_string ( @@ -444,6 +456,11 @@ urb->actual_length = len; // always USB_DIR_IN, toward host 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 */ diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Fri May 14 15:34:43 2004 +++ b/drivers/usb/core/hcd.h Fri May 14 15:34:43 2004 @@ -74,6 +74,8 @@ */ struct hc_driver *driver; /* hw-specific hooks */ unsigned saw_irq : 1; + unsigned can_wakeup:1; /* hw supports wakeup? */ + unsigned remote_wakeup:1;/* sw should use wakeup? */ int irq; /* irq allocated */ void *regs; /* device memory/io */ @@ -344,9 +346,16 @@ extern int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev); -/* for portability to 2.4, hcds should call this */ 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 ( hcd_to_bus (hcd)->root_hub, hcd->self.controller); }