* [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs
@ 2025-04-29 13:33 hoff.benjamin.k
2025-04-29 13:48 ` Greg KH
2025-04-29 13:50 ` Krishna Kurapati
0 siblings, 2 replies; 4+ messages in thread
From: hoff.benjamin.k @ 2025-04-29 13:33 UTC (permalink / raw)
To: linux-usb; +Cc: gregkh, linux-kernel, Ben Hoff
From: Ben Hoff <hoff.benjamin.k@gmail.com>
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 <hoff.benjamin.k@gmail.com>
---
drivers/usb/gadget/function/f_hid.c | 54 ++++++++++++++---------------
drivers/usb/gadget/function/u_hid.h | 1 +
2 files changed, 27 insertions(+), 28 deletions(-)
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 740311c4fa24..8aae22f9d609 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -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,
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
index 84bb70292855..a29dcb14f738 100644
--- a/drivers/usb/gadget/function/u_hid.h
+++ b/drivers/usb/gadget/function/u_hid.h
@@ -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
--
2.49.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs
2025-04-29 13:33 [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs hoff.benjamin.k
@ 2025-04-29 13:48 ` Greg KH
2025-04-29 13:50 ` Krishna Kurapati
1 sibling, 0 replies; 4+ messages in thread
From: Greg KH @ 2025-04-29 13:48 UTC (permalink / raw)
To: hoff.benjamin.k; +Cc: linux-usb, linux-kernel
On Tue, Apr 29, 2025 at 09:33:10AM -0400, hoff.benjamin.k@gmail.com wrote:
> From: Ben Hoff <hoff.benjamin.k@gmail.com>
>
> 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:
> - .bInterval = 4, /* FIXME: Add this field in the
> - * HID gadget configuration?
> - * (struct hidg_func_descriptor)
> - */
to:
> + opts->interval = 10;
do you mean to do that without documenting it?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs
2025-04-29 13:33 [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs hoff.benjamin.k
2025-04-29 13:48 ` Greg KH
@ 2025-04-29 13:50 ` Krishna Kurapati
2025-04-29 14:11 ` Ben Hoff
1 sibling, 1 reply; 4+ messages in thread
From: Krishna Kurapati @ 2025-04-29 13:50 UTC (permalink / raw)
To: hoff.benjamin.k; +Cc: gregkh, linux-kernel, linux-usb
On 4/29/2025 7:03 PM, hoff.benjamin.k@gmail.com wrote:
> From: Ben Hoff <hoff.benjamin.k@gmail.com>
>
> 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 <hoff.benjamin.k@gmail.com>
> ---
> drivers/usb/gadget/function/f_hid.c | 54 ++++++++++++++---------------
> drivers/usb/gadget/function/u_hid.h | 1 +
> 2 files changed, 27 insertions(+), 28 deletions(-)
>
[...]
> @@ -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,
> 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,
> diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
> index 84bb70292855..a29dcb14f738 100644
> --- a/drivers/usb/gadget/function/u_hid.h
> +++ b/drivers/usb/gadget/function/u_hid.h
> @@ -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
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs
2025-04-29 13:50 ` Krishna Kurapati
@ 2025-04-29 14:11 ` Ben Hoff
0 siblings, 0 replies; 4+ messages in thread
From: Ben Hoff @ 2025-04-29 14:11 UTC (permalink / raw)
To: Krishna Kurapati; +Cc: gregkh, linux-kernel, linux-usb
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
On Tue, Apr 29, 2025 at 9:50 AM Krishna Kurapati
<krishna.kurapati@oss.qualcomm.com> wrote:
>
>
>
> On 4/29/2025 7:03 PM, hoff.benjamin.k@gmail.com wrote:
> > From: Ben Hoff <hoff.benjamin.k@gmail.com>
> >
> > 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 <hoff.benjamin.k@gmail.com>
> > ---
> > drivers/usb/gadget/function/f_hid.c | 54 ++++++++++++++---------------
> > drivers/usb/gadget/function/u_hid.h | 1 +
> > 2 files changed, 27 insertions(+), 28 deletions(-)
> >
>
> [...]
>
> > @@ -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,
>
> > 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,
> > diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h
> > index 84bb70292855..a29dcb14f738 100644
> > --- a/drivers/usb/gadget/function/u_hid.h
> > +++ b/drivers/usb/gadget/function/u_hid.h
> > @@ -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
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-04-29 14:11 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-29 13:33 [PATCH] usb: gadget: hid: allow dynamic interval configuration via configfs hoff.benjamin.k
2025-04-29 13:48 ` Greg KH
2025-04-29 13:50 ` Krishna Kurapati
2025-04-29 14:11 ` Ben Hoff
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).