usb: device_next: hid: allow to set polling period at runtime
Allow to set input or output report polling period at runtime.
Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
diff --git a/include/zephyr/usb/class/usbd_hid.h b/include/zephyr/usb/class/usbd_hid.h
index 5539369..79b52dd 100644
--- a/include/zephyr/usb/class/usbd_hid.h
+++ b/include/zephyr/usb/class/usbd_hid.h
@@ -213,6 +213,38 @@
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);
+
+/**
* @}
*/
diff --git a/subsys/usb/device_next/class/Kconfig.hid b/subsys/usb/device_next/class/Kconfig.hid
index 8e3133a..a6f2980 100644
--- a/subsys/usb/device_next/class/Kconfig.hid
+++ b/subsys/usb/device_next/class/Kconfig.hid
@@ -30,6 +30,11 @@
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"
diff --git a/subsys/usb/device_next/class/usbd_hid.c b/subsys/usb/device_next/class/usbd_hid.c
index 212b409..2ea3a08 100644
--- a/subsys/usb/device_next/class/usbd_hid.c
+++ b/subsys/usb/device_next/class/usbd_hid.c
@@ -632,6 +632,56 @@
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)
@@ -706,6 +756,10 @@
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"
diff --git a/subsys/usb/device_next/class/usbd_hid_api.c b/subsys/usb/device_next/class/usbd_hid_api.c
index f2efa4e..fd9f27a 100644
--- a/subsys/usb/device_next/class/usbd_hid_api.c
+++ b/subsys/usb/device_next/class/usbd_hid_api.c
@@ -34,6 +34,28 @@
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 {
diff --git a/subsys/usb/device_next/class/usbd_hid_internal.h b/subsys/usb/device_next/class/usbd_hid_internal.h
index d049b0c..dcb7474 100644
--- a/subsys/usb/device_next/class/usbd_hid_internal.h
+++ b/subsys/usb/device_next/class/usbd_hid_internal.h
@@ -20,4 +20,6 @@
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);
};