usb: Add remote wakeup support

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 <pawel.zadrozniak@nordicsemi.no>
This commit is contained in:
Paweł Zadrożniak 2019-02-07 13:19:16 +01:00 committed by Anas Nashif
commit 3ecbff501a
6 changed files with 68 additions and 5 deletions

View file

@ -392,6 +392,15 @@ int usb_dc_ep_read_continue(u8_t ep);
*/ */
int usb_dc_ep_mps(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);
/** /**
* @} * @}
*/ */

View file

@ -96,7 +96,10 @@
* D5:Remote Wakeup -> 0, * D5:Remote Wakeup -> 0,
* D4...0:Reserved -> 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 */ /* Classes */
#define COMMUNICATION_DEVICE_CLASS 0x02 #define COMMUNICATION_DEVICE_CLASS 0x02

View file

@ -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); 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);
/** /**
* @} * @}
*/ */

View file

@ -71,6 +71,9 @@
#define FEA_REMOTE_WAKEUP 0x01 #define FEA_REMOTE_WAKEUP 0x01
#define FEA_TEST_MODE 0x02 #define FEA_TEST_MODE 0x02
#define DEVICE_STATUS_SELF_POWERED 0x01
#define DEVICE_STATUS_REMOTE_WAKEUP 0x02
/* /*
* USB descriptors * USB descriptors
*/ */

View file

@ -64,6 +64,11 @@ config USB_COMPOSITE_BUFFER_SIZE
config USB_DEVICE_SOF config USB_DEVICE_SOF
bool "Enable Start of Frame processing in events" 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 config USB_DEVICE_BOS
bool "Enable USB Binary Device Object Store (BOS)" bool "Enable USB Binary Device Object Store (BOS)"

View file

@ -162,6 +162,8 @@ static struct usb_dev_priv {
bool enabled; bool enabled;
/** Currently selected configuration */ /** Currently selected configuration */
u8_t configuration; u8_t configuration;
/** Remote wakeup feature status */
bool remote_wakeup;
/** Transfer list */ /** Transfer list */
struct usb_transfer_data transfer[MAX_NUM_TRANSFERS]; struct usb_transfer_data transfer[MAX_NUM_TRANSFERS];
} usb_dev; } usb_dev;
@ -615,9 +617,15 @@ static bool usb_handle_std_device_req(struct usb_setup_packet *setup,
case REQ_GET_STATUS: case REQ_GET_STATUS:
LOG_DBG("REQ_GET_STATUS"); LOG_DBG("REQ_GET_STATUS");
/* bit 0: self-powered */ /* bit 0: self-powered */
/* bit 1: remote wakeup = not supported */ /* bit 1: remote wakeup */
data[0] = 0U; data[0] = 0U;
data[1] = 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; *len = 2;
break; break;
@ -654,18 +662,29 @@ static bool usb_handle_std_device_req(struct usb_setup_packet *setup,
case REQ_CLEAR_FEATURE: case REQ_CLEAR_FEATURE:
LOG_DBG("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; break;
case REQ_SET_FEATURE: case REQ_SET_FEATURE:
LOG_DBG("REQ_SET_FEATURE"); LOG_DBG("REQ_SET_FEATURE");
ret = false;
if (IS_ENABLED(CONFIG_USB_DEVICE_REMOTE_WAKEUP)) {
if (value == FEA_REMOTE_WAKEUP) { if (value == FEA_REMOTE_WAKEUP) {
/* put DEVICE_REMOTE_WAKEUP code here */ usb_dev.remote_wakeup = true;
ret = true;
}
} }
if (value == FEA_TEST_MODE) { if (value == FEA_TEST_MODE) {
/* put TEST_MODE code here */ /* put TEST_MODE code here */
} }
ret = false;
break; break;
case REQ_SET_DESCRIPTOR: 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; 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 #ifdef CONFIG_USB_COMPOSITE_DEVICE
static u8_t iface_data_buf[CONFIG_USB_COMPOSITE_BUFFER_SIZE]; static u8_t iface_data_buf[CONFIG_USB_COMPOSITE_BUFFER_SIZE];