diff --git a/chip/g/usb.c b/chip/g/usb.c index 0fc4f62242..901a959e92 100644 --- a/chip/g/usb.c +++ b/chip/g/usb.c @@ -200,14 +200,6 @@ static void showregs(void) #define CONFIG_USB_BCD_DEV 0x0100 /* 1.00 */ #endif -#ifndef USB_BMATTRIBUTES -#ifdef CONFIG_USB_SELF_POWERED -#define USB_BMATTRIBUTES 0xc0 /* Self powered. */ -#else -#define USB_BMATTRIBUTES 0x80 /* Bus powered. */ -#endif -#endif - /* USB Standard Device Descriptor */ static const struct usb_device_descriptor dev_desc = { .bLength = USB_DT_DEVICE_SIZE, @@ -234,7 +226,14 @@ const struct usb_config_descriptor USB_CONF_DESC(conf) = { .bNumInterfaces = USB_IFACE_COUNT, .bConfigurationValue = 1, /* Caution: hard-coded value */ .iConfiguration = USB_STR_VERSION, - .bmAttributes = USB_BMATTRIBUTES, /* bus or self powered */ + .bmAttributes = 0x80 /* Reserved bit */ +#ifdef CONFIG_USB_SELF_POWERED /* bus or self powered */ + | 0x40 +#endif +#ifdef CONFIG_USB_REMOTE_WAKEUP + | 0x20 +#endif + , .bMaxPower = (CONFIG_USB_MAXPOWER_MA / 2), }; diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index 4cdfe0828c..ad1e76d65b 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -36,14 +36,6 @@ #define CONFIG_USB_BCD_DEV 0x0100 /* 1.00 */ #endif -#ifndef USB_BMATTRIBUTES -#ifdef CONFIG_USB_SELF_POWERED -#define USB_BMATTRIBUTES 0xc0 /* Self powered. */ -#else -#define USB_BMATTRIBUTES 0x80 /* Bus powered. */ -#endif -#endif - #ifndef CONFIG_USB_SERIALNO #define USB_STR_SERIALNO 0 #else @@ -76,7 +68,14 @@ const struct usb_config_descriptor USB_CONF_DESC(conf) = { .bNumInterfaces = USB_IFACE_COUNT, .bConfigurationValue = 1, .iConfiguration = USB_STR_VERSION, - .bmAttributes = USB_BMATTRIBUTES, /* bus or self powered */ + .bmAttributes = 0x80 /* Reserved bit */ +#ifdef CONFIG_USB_SELF_POWERED /* bus or self powered */ + | 0x40 +#endif +#ifdef CONFIG_USB_REMOTE_WAKEUP + | 0x20 +#endif + , .bMaxPower = (CONFIG_USB_MAXPOWER_MA / 2), }; @@ -332,6 +331,21 @@ static void usb_resume(void) /* USB is in use again */ disable_sleep(SLEEP_MASK_USB_DEVICE); } + +#ifdef CONFIG_USB_REMOTE_WAKEUP +void usb_wake(void) +{ + if (!(STM32_USB_CNTR & STM32_USB_CNTR_FSUSP)) { + /* USB is already woken up, nothing to do. */ + return; + } + + /* Set RESUME bit for 1 to 15 ms, then clear it. */ + STM32_USB_CNTR |= STM32_USB_CNTR_RESUME; + msleep(5); + STM32_USB_CNTR &= ~STM32_USB_CNTR_RESUME; +} +#endif #endif /* CONFIG_USB_SUSPEND */ void usb_interrupt(void) diff --git a/chip/stm32/usb_dwc.c b/chip/stm32/usb_dwc.c index 1b009a25cf..7ed0c20c60 100644 --- a/chip/stm32/usb_dwc.c +++ b/chip/stm32/usb_dwc.c @@ -52,14 +52,6 @@ #define CONFIG_USB_BCD_DEV 0x0100 /* 1.00 */ #endif -#ifndef USB_BMATTRIBUTES -#ifdef CONFIG_USB_SELF_POWERED -#define USB_BMATTRIBUTES 0xc0 /* Self powered. */ -#else -#define USB_BMATTRIBUTES 0x80 /* Bus powered. */ -#endif -#endif - #ifndef CONFIG_USB_SERIALNO #define USB_STR_SERIALNO 0 #else @@ -93,7 +85,14 @@ const struct usb_config_descriptor USB_CONF_DESC(conf) = { .bNumInterfaces = USB_IFACE_COUNT, .bConfigurationValue = 1, /* Caution: hard-coded value */ .iConfiguration = USB_STR_VERSION, - .bmAttributes = USB_BMATTRIBUTES, /* bus or self powered */ + .bmAttributes = 0x80 /* Reserved bit */ +#ifdef CONFIG_USB_SELF_POWERED /* bus or self powered */ + | 0x40 +#endif +#ifdef CONFIG_USB_REMOTE_WAKEUP + | 0x20 +#endif + , .bMaxPower = (CONFIG_USB_MAXPOWER_MA / 2), }; diff --git a/chip/stm32/usb_hid_keyboard.c b/chip/stm32/usb_hid_keyboard.c index 38354815c3..91b8c8ed35 100644 --- a/chip/stm32/usb_hid_keyboard.c +++ b/chip/stm32/usb_hid_keyboard.c @@ -165,6 +165,11 @@ static void write_keyboard_report(void) STM32_TOGGLE_EP(USB_EP_HID_KEYBOARD, EP_TX_MASK, EP_TX_VALID, 0); } + +#ifdef CONFIG_USB_REMOTE_WAKEUP + /* Wake up host, if required. */ + usb_wake(); +#endif } static void hid_keyboard_tx(void) diff --git a/chip/stm32/usb_hid_touchpad.c b/chip/stm32/usb_hid_touchpad.c index a0fc3b311a..92e1b09886 100644 --- a/chip/stm32/usb_hid_touchpad.c +++ b/chip/stm32/usb_hid_touchpad.c @@ -327,6 +327,11 @@ void set_touchpad_report(struct usb_hid_touchpad_report *report) report, sizeof(*report)); /* enable TX */ STM32_TOGGLE_EP(USB_EP_HID_TOUCHPAD, EP_TX_MASK, EP_TX_VALID, 0); + +#ifdef CONFIG_USB_REMOTE_WAKEUP + /* Wake up host, if required. */ + usb_wake(); +#endif } static void hid_touchpad_tx(void) diff --git a/include/config.h b/include/config.h index 5811e0f2b5..8577194e8a 100644 --- a/include/config.h +++ b/include/config.h @@ -2433,6 +2433,12 @@ */ #undef CONFIG_USB_PORT_POWER_SMART_INVERTED +/* + * Support waking up host by setting the K-state on the data lines (requires + * CONFIG_USB_SUSPEND to be set as well). + */ +#undef CONFIG_USB_REMOTE_WAKEUP + /* Support programmable USB device iSerial field. */ #undef CONFIG_USB_SERIALNO diff --git a/include/usb_api.h b/include/usb_api.h index c2e365cf28..a251b3f857 100644 --- a/include/usb_api.h +++ b/include/usb_api.h @@ -42,6 +42,14 @@ void usb_disconnect(void); */ void usb_release(void); +/* + * Tell the host to wake up. Requires CONFIG_USB_REMOTE_WAKEUP to be defined, + * and a chip that implements the function. + * + * This function sleeps, so it must not be used in interrupt context. + */ +void usb_wake(void); + #ifdef CONFIG_USB_SELECT_PHY /* Select which PHY to use. */ void usb_select_phy(uint32_t phy);