usb: device_next: hid: fix Get Report buffer handling
After the get_report() callback, we need to determine how many bytes the
HID device wrote to the report buffer. Use the callback return value to
do this, and modify the net_buf data length value if get_report was
successful.
Reported-by: Marek Pieta <Marek.Pieta@nordicsemi.no>
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 5dd6d0d..9798b08 100644
--- a/include/zephyr/usb/class/usbd_hid.h
+++ b/include/zephyr/usb/class/usbd_hid.h
@@ -106,8 +106,10 @@
* feature, input, or output report, which is specified by the argument
* type. If there is no report ID in the report descriptor, the id
* argument is zero. The callback implementation must check the
- * arguments, such as whether the report type is supported, and return
- * a nonzero value to indicate an unsupported type or an error.
+ * arguments, such as whether the report type is supported and the
+ * report length, and return a negative value to indicate an
+ * unsupported type or an error, or return the length of the report
+ * written to the buffer.
*/
int (*get_report)(const struct device *dev,
const uint8_t type, const uint8_t id,
diff --git a/subsys/usb/device_next/class/usbd_hid.c b/subsys/usb/device_next/class/usbd_hid.c
index 6fef55d..1b39aa1 100644
--- a/subsys/usb/device_next/class/usbd_hid.c
+++ b/subsys/usb/device_next/class/usbd_hid.c
@@ -231,25 +231,34 @@
const uint8_t id = HID_GET_REPORT_ID(setup->wValue);
struct hid_device_data *const ddata = dev->data;
const struct hid_device_ops *ops = ddata->ops;
+ const size_t size = net_buf_tailroom(buf);
+ int ret = 0;
switch (type) {
case HID_REPORT_TYPE_INPUT:
LOG_DBG("Get Report, Input Report ID %u", id);
- errno = ops->get_report(dev, type, id, net_buf_tailroom(buf), buf->data);
+ ret = ops->get_report(dev, type, id, size, buf->data);
break;
case HID_REPORT_TYPE_OUTPUT:
LOG_DBG("Get Report, Output Report ID %u", id);
- errno = ops->get_report(dev, type, id, net_buf_tailroom(buf), buf->data);
+ ret = ops->get_report(dev, type, id, size, buf->data);
break;
case HID_REPORT_TYPE_FEATURE:
LOG_DBG("Get Report, Feature Report ID %u", id);
- errno = ops->get_report(dev, type, id, net_buf_tailroom(buf), buf->data);
+ ret = ops->get_report(dev, type, id, size, buf->data);
break;
default:
errno = -ENOTSUP;
break;
}
+ if (ret > 0) {
+ __ASSERT(ret <= size, "Buffer overflow in the HID driver");
+ net_buf_add(buf, MIN(size, ret));
+ } else {
+ errno = ret ? ret : -ENOTSUP;
+ }
+
return 0;
}