From 3ecbff501aab6b6cf08339d39dbee7ae56814328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Zadro=C5=BCniak?= Date: Thu, 7 Feb 2019 13:19:16 +0100 Subject: [PATCH] usb: Add remote wakeup support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds support for remote wakeup and extends USB api with a wakeup request call. Remote wakeup can be dsabled in kconfig when a specific driver does not support this feature. Signed-off-by: Paweł Zadrożniak --- include/drivers/usb/usb_dc.h | 9 +++++++++ include/usb/usb_common.h | 5 ++++- include/usb/usb_device.h | 12 +++++++++++ include/usb/usbstruct.h | 3 +++ subsys/usb/Kconfig | 5 +++++ subsys/usb/usb_device.c | 39 ++++++++++++++++++++++++++++++++---- 6 files changed, 68 insertions(+), 5 deletions(-) diff --git a/include/drivers/usb/usb_dc.h b/include/drivers/usb/usb_dc.h index b489991ec3f..4d0f7c4bfde 100644 --- a/include/drivers/usb/usb_dc.h +++ b/include/drivers/usb/usb_dc.h @@ -392,6 +392,15 @@ int usb_dc_ep_read_continue(u8_t ep); */ int usb_dc_ep_mps(u8_t ep); +/** + * @brief Start the host wake up procedure. + * + * Function to wake up the host if it's currently in sleep mode. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_wakeup_request(void); + /** * @} */ diff --git a/include/usb/usb_common.h b/include/usb/usb_common.h index 1de1977f21d..6189d1bb478 100644 --- a/include/usb/usb_common.h +++ b/include/usb/usb_common.h @@ -96,7 +96,10 @@ * D5:Remote Wakeup -> 0, * D4...0:Reserved -> 0 */ -#define USB_CONFIGURATION_ATTRIBUTES 0xC0 +#define USB_CONFIGURATION_ATTRIBUTES_REMOTE_WAKEUP 0x20 +#define USB_CONFIGURATION_ATTRIBUTES 0xC0 \ + | (COND_CODE_1(CONFIG_USB_DEVICE_REMOTE_WAKEUP, \ + (USB_CONFIGURATION_ATTRIBUTES_REMOTE_WAKEUP), (0))) /* Classes */ #define COMMUNICATION_DEVICE_CLASS 0x02 diff --git a/include/usb/usb_device.h b/include/usb/usb_device.h index edfd879c69e..9546bfad253 100644 --- a/include/usb/usb_device.h +++ b/include/usb/usb_device.h @@ -418,6 +418,18 @@ int usb_transfer_sync(u8_t ep, u8_t *data, size_t dlen, unsigned int flags); */ void usb_cancel_transfer(u8_t ep); +/** + * @brief Start the USB remote wakeup procedure + * + * Function to request a remote wakeup. + * This feature must be enabled in configuration, otherwise + * it will always return -ENOTSUP error. + * + * @return 0 on success, negative errno code on fail, + * i.e. when the bus is already active. + */ +int usb_wakeup_request(void); + /** * @} */ diff --git a/include/usb/usbstruct.h b/include/usb/usbstruct.h index 9079c51ddb2..62337f4221b 100644 --- a/include/usb/usbstruct.h +++ b/include/usb/usbstruct.h @@ -71,6 +71,9 @@ #define FEA_REMOTE_WAKEUP 0x01 #define FEA_TEST_MODE 0x02 +#define DEVICE_STATUS_SELF_POWERED 0x01 +#define DEVICE_STATUS_REMOTE_WAKEUP 0x02 + /* * USB descriptors */ diff --git a/subsys/usb/Kconfig b/subsys/usb/Kconfig index 161f77deb8e..5fe8ac7c5b5 100644 --- a/subsys/usb/Kconfig +++ b/subsys/usb/Kconfig @@ -64,6 +64,11 @@ config USB_COMPOSITE_BUFFER_SIZE config USB_DEVICE_SOF bool "Enable Start of Frame processing in events" +config USB_DEVICE_REMOTE_WAKEUP + bool "Enable support for remote wakeup" + help + This option requires USBD peripheral driver to also support remote wakeup. + config USB_DEVICE_BOS bool "Enable USB Binary Device Object Store (BOS)" diff --git a/subsys/usb/usb_device.c b/subsys/usb/usb_device.c index 33c5a4641eb..14e7e5e5da6 100644 --- a/subsys/usb/usb_device.c +++ b/subsys/usb/usb_device.c @@ -162,6 +162,8 @@ static struct usb_dev_priv { bool enabled; /** Currently selected configuration */ u8_t configuration; + /** Remote wakeup feature status */ + bool remote_wakeup; /** Transfer list */ struct usb_transfer_data transfer[MAX_NUM_TRANSFERS]; } usb_dev; @@ -615,9 +617,15 @@ static bool usb_handle_std_device_req(struct usb_setup_packet *setup, case REQ_GET_STATUS: LOG_DBG("REQ_GET_STATUS"); /* bit 0: self-powered */ - /* bit 1: remote wakeup = not supported */ + /* bit 1: remote wakeup */ data[0] = 0U; data[1] = 0U; + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + data[0] |= (usb_dev.remote_wakeup ? + DEVICE_STATUS_REMOTE_WAKEUP : 0); + } + *len = 2; break; @@ -654,18 +662,29 @@ static bool usb_handle_std_device_req(struct usb_setup_packet *setup, case REQ_CLEAR_FEATURE: LOG_DBG("REQ_CLEAR_FEATURE"); + ret = false; + + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (value == FEA_REMOTE_WAKEUP) { + usb_dev.remote_wakeup = false; + ret = true; + } + } break; case REQ_SET_FEATURE: LOG_DBG("REQ_SET_FEATURE"); + ret = false; - if (value == FEA_REMOTE_WAKEUP) { - /* put DEVICE_REMOTE_WAKEUP code here */ + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (value == FEA_REMOTE_WAKEUP) { + usb_dev.remote_wakeup = true; + ret = true; + } } if (value == FEA_TEST_MODE) { /* put TEST_MODE code here */ } - ret = false; break; case REQ_SET_DESCRIPTOR: @@ -1368,6 +1387,18 @@ int usb_transfer_sync(u8_t ep, u8_t *data, size_t dlen, unsigned int flags) return pdata.tsize; } +int usb_wakeup_request(void) +{ + if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) { + if (usb_dev.remote_wakeup) { + return usb_dc_wakeup_request(); + } + return -EACCES; + } else { + return -ENOTSUP; + } +} + #ifdef CONFIG_USB_COMPOSITE_DEVICE static u8_t iface_data_buf[CONFIG_USB_COMPOSITE_BUFFER_SIZE];