Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions host/class/hid/usb_host_hid/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- Added remote wakeup feature

## [1.1.0] - 2026-01-09

### Fixed
Expand Down
72 changes: 67 additions & 5 deletions host/class/hid/usb_host_hid/hid_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ typedef struct hid_host_device {
usb_transfer_t *ctrl_xfer; /**< Pointer to control transfer buffer */
usb_device_handle_t dev_hdl; /**< USB device handle */
uint8_t dev_addr; /**< USB device address */
#ifdef HID_HOST_REMOTE_WAKE_SUPPORTED
bool remote_wakeup_enabled; /**< To indicate whether remote wakeup is currently enabled */
#endif // HID_HOST_REMOTE_WAKE_SUPPORTED
} hid_device_t;

/**
Expand Down Expand Up @@ -886,7 +889,9 @@ static void in_xfer_done(usb_transfer_t *in_xfer)
*
* @param[in] hid_device Pointer to HID device structure
* @param[in] timeout_ms Timeout of trying to take the mutex
* @return esp_err_t
* @return
* - ESP_OK if the mutex was successfully taken
* - ESP_ERR_TIMEOUT if the mutex could not be taken within the specified timeout
*/
static inline esp_err_t hid_device_try_lock(hid_device_t *hid_device, uint32_t timeout_ms)
{
Expand All @@ -899,7 +904,6 @@ static inline esp_err_t hid_device_try_lock(hid_device_t *hid_device, uint32_t t
*
* @param[in] hid_device Pointer to HID device structure
* @param[in] timeout_ms Timeout of trying to take the mutex
* @return esp_err_t
*/
static inline void hid_device_unlock(hid_device_t *hid_device)
{
Expand Down Expand Up @@ -1197,9 +1201,9 @@ static esp_err_t hid_host_string_descriptor_copy(wchar_t *dest,
return ESP_OK;
}

esp_err_t hid_host_install_device(uint8_t dev_addr,
usb_device_handle_t dev_hdl,
hid_device_t **hid_device_handle)
static esp_err_t hid_host_install_device(uint8_t dev_addr,
usb_device_handle_t dev_hdl,
hid_device_t **hid_device_handle)
{
esp_err_t ret;
hid_device_t *hid_device;
Expand Down Expand Up @@ -1562,6 +1566,64 @@ esp_err_t hid_host_device_get_raw_input_report_data(hid_host_device_handle_t hid
return ESP_OK;
}

#ifdef HID_HOST_REMOTE_WAKE_SUPPORTED

esp_err_t hid_host_device_host_enable_remote_wakeup(hid_host_device_handle_t hid_dev_handle, bool enable)
{
HID_RETURN_ON_FALSE(s_hid_driver, ESP_ERR_INVALID_STATE, "HID Driver is not installed");
hid_iface_t *iface = get_iface_by_handle(hid_dev_handle);

HID_RETURN_ON_INVALID_ARG(iface);
HID_RETURN_ON_INVALID_ARG(iface->parent);
HID_RETURN_ON_FALSE(is_interface_in_list(iface), ESP_ERR_NOT_FOUND, "Interface handle not found");
hid_device_t *hid_device = iface->parent;

// Get device's config descriptor
const usb_config_desc_t *config_desc;
ESP_RETURN_ON_ERROR(
usb_host_get_active_config_descriptor(hid_device->dev_hdl, &config_desc), TAG, "Unable to get configuration descriptor");

// Check if the device reports remote wakeup feature in it's configuration descriptor
ESP_RETURN_ON_FALSE(
(config_desc->bmAttributes & USB_BM_ATTRIBUTES_WAKEUP), ESP_ERR_NOT_SUPPORTED, TAG, "Device does not support remote wakeup");

// Check current remote wakeup status
// If user wants to enable it and is already enabled (or vice versa) return early, otherwise proceed to ctrl transfer
if (hid_device->remote_wakeup_enabled == enable) {
ESP_LOGD(TAG, "Remote wakeup already %d on this device", (enable) ? "enabled" : "disabled");
return ESP_OK;
}

usb_transfer_t *ctrl_xfer = hid_device->ctrl_xfer;
HID_RETURN_ON_INVALID_ARG(ctrl_xfer);
HID_RETURN_ON_ERROR( hid_device_try_lock(hid_device, DEFAULT_TIMEOUT_MS), "HID Device is busy by other task");

usb_setup_packet_t *setup = (usb_setup_packet_t *)ctrl_xfer->data_buffer;
if (enable) {
// Enable remote wakeup
USB_SETUP_PACKET_INIT_SET_FEATURE(setup, DEVICE_REMOTE_WAKEUP);
ESP_LOGI(TAG, "Enabling remote wakeup on device");
} else {
// Disable remote wakeup
USB_SETUP_PACKET_INIT_CLEAR_FEATURE(setup, DEVICE_REMOTE_WAKEUP);
ESP_LOGI(TAG, "Disabling remote wakeup on device");
}

esp_err_t ret = hid_control_transfer(hid_device,
USB_SETUP_PACKET_SIZE + setup->wLength,
DEFAULT_TIMEOUT_MS);

// CTRL transfer passed, update device status about remote wakeup
if (ret == ESP_OK) {
hid_device->remote_wakeup_enabled = enable;
}

hid_device_unlock(hid_device);
return ret;
}

#endif // HID_HOST_REMOTE_WAKE_SUPPORTED

// ------------------------ USB HID Host driver API ----------------------------

esp_err_t hid_host_device_start(hid_host_device_handle_t hid_dev_handle)
Expand Down
27 changes: 27 additions & 0 deletions host/class/hid/usb_host_hid/include/usb/hid_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ extern "C" {
#define HID_HOST_SUSPEND_RESUME_API_SUPPORTED
#endif

// For backward compatibility with IDF versions which do not have remote wakeup HAL changes
#ifdef REMOTE_WAKE_HAL_SUPPORTED
#define HID_HOST_REMOTE_WAKE_SUPPORTED
#endif

typedef struct hid_interface *hid_host_device_handle_t; /**< Device Handle. Handle to a particular HID interface */

// ------------------------ USB HID Host events --------------------------------
Expand Down Expand Up @@ -197,6 +202,28 @@ esp_err_t hid_host_device_get_raw_input_report_data(hid_host_device_handle_t hid
size_t data_length_max,
size_t *data_length);

#ifdef HID_HOST_REMOTE_WAKE_SUPPORTED
/**
* @brief Enable/Disable remote wakeup on device
* @note API availability depends on presence of remote wakeup support in esp-idf HAL
* and is guarded by the HID_HOST_REMOTE_WAKE_SUPPORTED
*
* @param[in] hid_dev_handle HID Device handle
* @param[in] enable Enable/Disable remote wakeup
* @return
* - ESP_OK: Remote wakeup successfully enabled/disabled, or already enabled/disabled on the device
* - ESP_ERR_INVALID_STATE: HID driver not installed
* - ESP_ERR_INVALID_ARG: Invalid input argument
* - ESP_ERR_NOT_FOUND: Interface not found in interfaces list
* - ESP_ERR_NOT_SUPPORTED: Device does not support remote wakeup
* - ESP_ERR_TIMEOUT: Transfer timed out, or failed to acquire ctr transfer mutex
* - ESP_ERR_INVALID_RESPONSE: Invalid response of the control transfer
* - Errors propagated from caller functions
*/
esp_err_t hid_host_device_host_enable_remote_wakeup(hid_host_device_handle_t hid_dev_handle, bool enable);

#endif // HID_HOST_REMOTE_WAKE_SUPPORTED

// ------------------------ USB HID Host driver API ----------------------------

/**
Expand Down
Loading
Loading