linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).