Skip to content
Merged
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
32 changes: 32 additions & 0 deletions include/zephyr/usb/class/usbd_hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,38 @@ int hid_device_register(const struct device *dev,
int hid_device_submit_report(const struct device *dev,
const uint16_t size, const uint8_t *const report);

/**
* @brief Set input report polling period
*
* Similar to devicetree property in-polling-period-us, but it allows setting
* different polling periods at runtime.
*
* @kconfig_dep{CONFIG_USBD_HID_SET_POLLING_PERIOD}
*
* @param[in] dev Pointer to HID device
* @param[in] period_us Polling period in microseconds
*
* @return 0 on success, negative errno code on failure.
* @retval -ENOTSUP If API is not enabled.
*/
int hid_device_set_in_polling(const struct device *dev, const unsigned int period_us);

/**
* @brief Set output report polling period
*
* Similar to devicetree property out-polling-period-us, but it allows setting
* different polling periods at runtime.
*
* @kconfig_dep{CONFIG_USBD_HID_SET_POLLING_PERIOD}
*
* @param[in] dev Pointer to HID device
* @param[in] period_us Polling period in microseconds
*
* @return 0 on success, negative errno code on failure.
* @retval -ENOTSUP If API is not enabled.
*/
int hid_device_set_out_polling(const struct device *dev, const unsigned int period_us);

/**
* @}
*/
Expand Down
2 changes: 2 additions & 0 deletions samples/subsys/usb/hid-keyboard/sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ tests:
sample.usbd.hid-keyboard.large-out-report:
extra_args:
- EXTRA_DTC_OVERLAY_FILE="large_out_report.overlay"
extra_configs:
- CONFIG_USBD_HID_SET_POLLING_PERIOD=y
12 changes: 12 additions & 0 deletions samples/subsys/usb/hid-keyboard/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,18 @@ int main(void)
return ret;
}

if (IS_ENABLED(CONFIG_USBD_HID_SET_POLLING_PERIOD)) {
ret = hid_device_set_in_polling(hid_dev, 1000);
if (ret) {
LOG_WRN("Failed to set IN report polling period, %d", ret);
}

ret = hid_device_set_out_polling(hid_dev, 1000);
if (ret != 0 && ret != -ENOTSUP) {
LOG_WRN("Failed to set OUT report polling period, %d", ret);
}
}

sample_usbd = sample_usbd_init_device(msg_cb);
if (sample_usbd == NULL) {
LOG_ERR("Failed to initialize USB device");
Expand Down
5 changes: 5 additions & 0 deletions subsys/usb/device_next/class/Kconfig.hid
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ config USBD_HID_INIT_PRIORITY
help
HID device initialization priority

config USBD_HID_SET_POLLING_PERIOD
bool "Allow to set polling period at runtime"
help
Allow to set input or output report polling period at runtime.

module = USBD_HID
module-str = usbd hid
source "subsys/logging/Kconfig.template.log_config"
Expand Down
68 changes: 67 additions & 1 deletion subsys/usb/device_next/class/usbd_hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct usbd_hid_descriptor {
};

enum {
HID_DEV_CLASS_INITIALIZED,
HID_DEV_CLASS_ENABLED,
};

Expand Down Expand Up @@ -503,7 +504,14 @@ static int usbd_hid_init(struct usbd_class_data *const c_data)
const struct device *dev = usbd_class_get_private(c_data);
const struct hid_device_config *dcfg = dev->config;
struct usbd_hid_descriptor *const desc = dcfg->desc;
struct hid_device_data *const ddata = dev->data;

if (ddata->ops == NULL || ddata->rdesc == NULL || !ddata->rsize) {
LOG_ERR("HID device does not seem to be registered");
return -EINVAL;
}

atomic_set_bit(&ddata->state, HID_DEV_CLASS_INITIALIZED);
LOG_DBG("HID class %s init", c_data->name);

if (dcfg->if_desc_data != NULL && desc->if0.iInterface == 0) {
Expand All @@ -519,6 +527,10 @@ static int usbd_hid_init(struct usbd_class_data *const c_data)

static void usbd_hid_shutdown(struct usbd_class_data *const c_data)
{
const struct device *dev = usbd_class_get_private(c_data);
struct hid_device_data *const ddata = dev->data;

atomic_clear_bit(&ddata->state, HID_DEV_CLASS_INITIALIZED);
LOG_DBG("HID class %s shutdown", c_data->name);
}

Expand Down Expand Up @@ -620,6 +632,56 @@ static int hid_dev_submit_report(const struct device *dev,
return 0;
}

static inline int hid_dev_set_out_polling(const struct device *dev,
const unsigned int period_us)
{
const struct hid_device_config *const dcfg = dev->config;
struct hid_device_data *const ddata = dev->data;
struct usbd_hid_descriptor *const desc = dcfg->desc;

if (atomic_test_bit(&ddata->state, HID_DEV_CLASS_INITIALIZED)) {
return -EBUSY;
}

if (USBD_SUPPORTS_HIGH_SPEED) {
if (desc->hs_out_ep.bLength == 0) {
/* This device does not have output reports. */
return -ENOTSUP;
}

desc->hs_out_ep.bInterval = USB_HS_INT_EP_INTERVAL(period_us);
}

if (desc->out_ep.bLength == 0) {
/* This device does not have output reports. */
return -ENOTSUP;
}

desc->out_ep.bInterval = USB_FS_INT_EP_INTERVAL(period_us);

return 0;
}

static inline int hid_dev_set_in_polling(const struct device *dev,
const unsigned int period_us)
{
const struct hid_device_config *const dcfg = dev->config;
struct hid_device_data *const ddata = dev->data;
struct usbd_hid_descriptor *const desc = dcfg->desc;

if (atomic_test_bit(&ddata->state, HID_DEV_CLASS_INITIALIZED)) {
return -EBUSY;
}

if (USBD_SUPPORTS_HIGH_SPEED) {
desc->hs_in_ep.bInterval = USB_HS_INT_EP_INTERVAL(period_us);
}

desc->in_ep.bInterval = USB_FS_INT_EP_INTERVAL(period_us);

return 0;
}

static int hid_dev_register(const struct device *dev,
const uint8_t *const rdesc, const uint16_t rsize,
const struct hid_device_ops *const ops)
Expand All @@ -628,7 +690,7 @@ static int hid_dev_register(const struct device *dev,
struct hid_device_data *const ddata = dev->data;
struct usbd_hid_descriptor *const desc = dcfg->desc;

if (atomic_test_bit(&ddata->state, HID_DEV_CLASS_ENABLED)) {
if (atomic_test_bit(&ddata->state, HID_DEV_CLASS_INITIALIZED)) {
return -EALREADY;
}

Expand Down Expand Up @@ -694,6 +756,10 @@ struct usbd_class_api usbd_hid_api = {
static const struct hid_device_driver_api hid_device_api = {
.submit_report = hid_dev_submit_report,
.dev_register = hid_dev_register,
#if CONFIG_USBD_HID_SET_POLLING_PERIOD
.set_out_polling = hid_dev_set_out_polling,
.set_in_polling = hid_dev_set_in_polling,
#endif
};

#include "usbd_hid_macros.h"
Expand Down
22 changes: 22 additions & 0 deletions subsys/usb/device_next/class/usbd_hid_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ int hid_device_register(const struct device *dev,
return api->dev_register(dev, rdesc, rsize, ops);
}

int hid_device_set_in_polling(const struct device *dev, const unsigned int period_us)
{
const struct hid_device_driver_api *const api = dev->api;

if (IS_ENABLED(CONFIG_USBD_HID_SET_POLLING_PERIOD)) {
return api->set_in_polling(dev, period_us);
}

return -ENOTSUP;
}

int hid_device_set_out_polling(const struct device *dev, const unsigned int period_us)
{
const struct hid_device_driver_api *const api = dev->api;

if (IS_ENABLED(CONFIG_USBD_HID_SET_POLLING_PERIOD)) {
return api->set_out_polling(dev, period_us);
}

return -ENOTSUP;
}

/* Legacy HID API wrapper below */

struct legacy_wrapper {
Expand Down
2 changes: 2 additions & 0 deletions subsys/usb/device_next/class/usbd_hid_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ struct hid_device_driver_api {
int (*dev_register)(const struct device *dev,
const uint8_t *const rdesc, const uint16_t rsize,
const struct hid_device_ops *const ops);
int (*set_in_polling)(const struct device *dev, const unsigned int period_us);
int (*set_out_polling)(const struct device *dev, const unsigned int period_us);
};