usb: gadget: hid: allow dynamic interval configuration via configfs
PATCH 1/1 usb: gadget: hid: allow dynamic interval configuration via configfs
From: Ben Hoff <[email protected]>
This patch adds support for dynamically configuring the polling interval (bInterval) for HID function drivers using configfs. This enables custom HID gadgets with user-specified poll rates without recompilation.
--- drivers/usb/gadget/function/f_hid.c | 54 ++++++++++++++--------------- drivers/usb/gadget/function/u_hid.h | 1 + 2 files changed, 27 insertions(+), 28 deletions(-)
drivers/usb/gadget/function/f_hid.c +26 -28
@@ -62,6 +62,7 @@ struct f_hidg {unsigned short report_desc_length;char *report_desc;unsigned short report_length; +unsigned char interval;/* * use_out_ep - if true, the OUT Endpoint (interrupt out method) * will be used to receive reports from the host
@@ -156,10 +157,7 @@ static struct usb_endpoint_descriptor hidg_ss_in_ep_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT,/*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the -* HID gadget configuration? -* (struct hidg_func_descriptor) -*/ +/*.bInterval = DYNAMIC */ };static struct usb_ss_ep_comp_descriptor hidg_ss_in_comp_desc = {
@@ -177,10 +175,7 @@ static struct usb_endpoint_descriptor hidg_ss_out_ep_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_INT,/*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the -* HID gadget configuration? -* (struct hidg_func_descriptor) -*/ +/*.bInterval = DYNAMIC */ };static struct usb_ss_ep_comp_descriptor hidg_ss_out_comp_desc = {
@@ -218,10 +213,7 @@ static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT,/*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the -* HID gadget configuration? -* (struct hidg_func_descriptor) -*/ +/* .bInterval = DYNAMIC */ };static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
@@ -230,10 +222,7 @@ static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_INT,/*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the -* HID gadget configuration? -* (struct hidg_func_descriptor) -*/ +/*.bInterval = DYNAMIC */ };static struct usb_descriptor_header *hidg_hs_descriptors_intout[] = {
@@ -259,10 +248,7 @@ static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT,/*.wMaxPacketSize = DYNAMIC */ - .bInterval = 10, /* FIXME: Add this field in the -* HID gadget configuration? -* (struct hidg_func_descriptor) -*/ +/*.bInterval = DYNAMIC */ };static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
@@ -1202,6 +1188,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_hs_in_ep_desc.wMaxPacketSize =cpu_to_le16 (hidg->report_length); hidg_fs_in_ep_desc.wMaxPacketSize =cpu_to_le16 (hidg->report_length); hidg_ss_out_ep_desc.wMaxPacketSize =cpu_to_le16 (hidg->report_length); + + hidg_fs_in_ep_desc.bInterval = hidg->interval; + hidg_hs_in_ep_desc.bInterval = hidg->interval; + hidg_ss_out_comp_desc.wBytesPerInterval =cpu_to_le16 (hidg->report_length); hidg_hs_out_ep_desc.wMaxPacketSize =cpu_to_le16 (hidg->report_length);
@@ -1224,19 +1214,21 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) hidg_ss_out_ep_desc.bEndpointAddress = hidg_fs_out_ep_desc.bEndpointAddress; -if (hidg->use_out_ep) - status =usb_assign_descriptors (f, - hidg_fs_descriptors_intout, - hidg_hs_descriptors_intout, - hidg_ss_descriptors_intout, - hidg_ss_descriptors_intout); -else +if (hidg->use_out_ep) { + hidg_fs_out_ep_desc.bInterval = hidg->interval; + hidg_hs_out_ep_desc.bInterval = hidg->interval; + status =usb_assign_descriptors (f, + hidg_fs_descriptors_intout, + hidg_hs_descriptors_intout, + hidg_ss_descriptors_intout, + hidg_ss_descriptors_intout); + }else { status =usb_assign_descriptors (f, hidg_fs_descriptors_ssreport, hidg_hs_descriptors_ssreport, hidg_ss_descriptors_ssreport, hidg_ss_descriptors_ssreport); - + }if (status) goto fail;
@@ -1362,6 +1354,7 @@ F_HID_OPT(subclass, 8, 255);F_HID_OPT (protocol,8 ,255 );F_HID_OPT (no_out_endpoint,8 ,1 );F_HID_OPT (report_length,16 ,65535 ); +F_HID_OPT (interval,8 ,255 );static ssize_t f_hid_opts_report_desc_show (struct config_item *item,char *page) {
@@ -1422,6 +1415,7 @@ static struct configfs_attribute *hid_attrs[] = { &f_hid_opts_attr_protocol, &f_hid_opts_attr_no_out_endpoint, &f_hid_opts_attr_report_length, + &f_hid_opts_attr_interval, &f_hid_opts_attr_report_desc, &f_hid_opts_attr_dev, NULL,
@@ -1468,6 +1462,9 @@ static struct usb_function_instance *hidg_alloc_inst(void)if (!opts)return ERR_PTR (-ENOMEM );mutex_init (&opts->lock); + + opts->interval =10 ; + opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst;
@@ -1546,6 +1543,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) hidg->bInterfaceProtocol = opts->protocol; hidg->report_length = opts->report_length; hidg->report_desc_length = opts->report_desc_length; + hidg->interval = opts->interval;if (opts->report_desc) { hidg->report_desc = kmemdup(opts->report_desc, opts->report_desc_length,
drivers/usb/gadget/function/u_hid.h +1 -0
@@ -25,6 +25,7 @@ struct f_hid_opts {unsigned short report_desc_length;unsigned char *report_desc;bool report_desc_alloc; +unsigned char interval;/* * Protect the data form concurrent access by read/write
Signature · 1 line
2.49.0
Greg KH
maintainerQuoted 5 lines · On Tue, Apr 29, 2025 at 09:33:10AM -0400, [email protected] wrote:
From: Ben Hoff <[email protected]>
This patch adds support for dynamically configuring the polling interval (bInterval) for HID function drivers using configfs. This enables custom HID gadgets with user-specified poll rates without recompilation.
But you changed the default from:
drivers/usb/gadget/function/f_hid.c static struct usb_endpoint_descriptor hidg_ss_in_ep_desc = { · line 162
Quoted 4 lines
drivers/usb/gadget/function/f_hid.c +0
-4- .bInterval = 4, /* FIXME: Add this field in the -* HID gadget configuration? -* (struct hidg_func_descriptor) -*/
to:
drivers/usb/gadget/function/f_hid.c static struct usb_function_instance *hidg_alloc_inst(void) · line 1466
Quoted 1 line
drivers/usb/gadget/function/f_hid.c +1
-0+ opts->interval =10 ;
do you mean to do that without documenting it?
thanks,
greg k-h
Quoted 12 lines · On 4/29/2025 7:03 PM, [email protected] wrote:
From: Ben Hoff <[email protected]>
This patch adds support for dynamically configuring the polling interval (bInterval) for HID function drivers using configfs. This enables custom HID gadgets with user-specified poll rates without recompilation.
Signed-off-by Ben Hoff <[email protected]>--- drivers/usb/gadget/function/f_hid.c | 54 ++++++++++++++--------------- drivers/usb/gadget/function/u_hid.h | 1 + 2 files changed, 27 insertions(+), 28 deletions(-)
[...]
drivers/usb/gadget/function/f_hid.c static struct usb_function_instance *hidg_alloc_inst(void) · line 1467
Quoted 7 lines
drivers/usb/gadget/function/f_hid.c +3
-0@@ -1468,6 +1462,9 @@ static struct usb_function_instance *hidg_alloc_inst(void)if (!opts)return ERR_PTR (-ENOMEM );mutex_init (&opts->lock); + + opts->interval =10 ; +
The default value was 10 only for hidg_hs_descriptors_intout. Aren't we now making it 10 for all other ep descriptors as well ?
Regards,
Krishna,
Quoted 23 lines
drivers/usb/gadget/function/f_hid.c +1
-0opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst;@@ -1546,6 +1543,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) hidg->bInterfaceProtocol = opts->protocol; hidg->report_length = opts->report_length; hidg->report_desc_length = opts->report_desc_length; + hidg->interval = opts->interval;if (opts->report_desc) { hidg->report_desc = kmemdup(opts->report_desc, opts->report_desc_length,drivers/usb/gadget/function/u_hid.h +1
-0@@ -25,6 +25,7 @@ struct f_hid_opts {unsigned short report_desc_length;unsigned char *report_desc;bool report_desc_alloc; +unsigned char interval;/* * Protect the data form concurrent access by read/write
Hi Greg, Krishna,
Thanks for the feedback!
You're right — I should not have changed the default bInterval from 4 to 10 for all endpoints.
To preserve the original behavior, I'll resend a v2 patch that:
- Sets the global default bInterval to 4 frames, matching the existing implementation.
- Leaves the High-Speed interrupt-out endpoints (hidg_hs_descriptors_intout) at their historic 10-frame default unless explicitly overridden through configfs.
Thanks again for reviewing this — I'll send an updated patch shortly.
Ben
Quoted 56 lines · Krishna Kurapati
Quoted 12 lines · On 4/29/2025 7:03 PM, [email protected] wrote:
From: Ben Hoff <[email protected]>
This patch adds support for dynamically configuring the polling interval (bInterval) for HID function drivers using configfs. This enables custom HID gadgets with user-specified poll rates without recompilation.
Signed-off-by Ben Hoff <[email protected]>--- drivers/usb/gadget/function/f_hid.c | 54 ++++++++++++++--------------- drivers/usb/gadget/function/u_hid.h | 1 + 2 files changed, 27 insertions(+), 28 deletions(-)[...]
drivers/usb/gadget/function/f_hid.c static struct usb_function_instance *hidg_alloc_inst(void) · line 1467
Quoted 7 lines
drivers/usb/gadget/function/f_hid.c +3
-0@@ -1468,6 +1462,9 @@ static struct usb_function_instance *hidg_alloc_inst(void)if (!opts)return ERR_PTR (-ENOMEM );mutex_init (&opts->lock); + + opts->interval =10 ; +The default value was 10 only for
hidg_hs_descriptors_intout. Aren't we now making it 10 for all other ep descriptors as well ?Regards,
Krishna,Quoted 23 lines
drivers/usb/gadget/function/f_hid.c +1
-0opts->func_inst.free_func_inst = hidg_free_inst; ret = &opts->func_inst;@@ -1546,6 +1543,7 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) hidg->bInterfaceProtocol = opts->protocol; hidg->report_length = opts->report_length; hidg->report_desc_length = opts->report_desc_length; + hidg->interval = opts->interval;if (opts->report_desc) { hidg->report_desc = kmemdup(opts->report_desc, opts->report_desc_length,drivers/usb/gadget/function/u_hid.h +1
-0@@ -25,6 +25,7 @@ struct f_hid_opts {unsigned short report_desc_length;unsigned char *report_desc;bool report_desc_alloc; +unsigned char interval;/* * Protect the data form concurrent access by read/write