Skip to content

Commit 99c5150

Browse files
zonqueFelipe Balbi
authored andcommitted
usb: gadget: hidg: register OUT INT endpoint for SET_REPORT
The hidg function driver currently handles its SET_REPORT calls via EP0. This is the implicit behaviour when no OUT interrupt endpoint is configured and generally works fine. The problem is that due to EP0's role in the gadget framework, we cannot hold back packets and control traffic flow to sync it to the char device, and hence there's a high risk of loosing packets with this implementation. This patch adds an OUT interrupt endpoint to the interface and queues a fix number of request to catch SET_REPORT events. According to the specs, host drivers should always use the dedicated OUT endpoint when present. The char device's read implementation was rewritten to retrieve data from the list of completed output requests. Signed-off-by: Daniel Mack <[email protected]> Cc: Felipe Balbi <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Signed-off-by: Felipe Balbi <[email protected]>
1 parent a8287a4 commit 99c5150

File tree

1 file changed

+165
-43
lines changed

1 file changed

+165
-43
lines changed

drivers/usb/gadget/f_hid.c

Lines changed: 165 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ static struct class *hidg_class;
2626
/*-------------------------------------------------------------------------*/
2727
/* HID gadget struct */
2828

29+
struct f_hidg_req_list {
30+
struct usb_request *req;
31+
unsigned int pos;
32+
struct list_head list;
33+
};
34+
2935
struct f_hidg {
3036
/* configuration */
3137
unsigned char bInterfaceSubClass;
@@ -35,10 +41,10 @@ struct f_hidg {
3541
unsigned short report_length;
3642

3743
/* recv report */
38-
char *set_report_buff;
39-
unsigned short set_report_length;
44+
struct list_head completed_out_req;
4045
spinlock_t spinlock;
4146
wait_queue_head_t read_queue;
47+
unsigned int qlen;
4248

4349
/* send report */
4450
struct mutex lock;
@@ -49,7 +55,9 @@ struct f_hidg {
4955
int minor;
5056
struct cdev cdev;
5157
struct usb_function func;
58+
5259
struct usb_ep *in_ep;
60+
struct usb_ep *out_ep;
5361
};
5462

5563
static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -65,7 +73,7 @@ static struct usb_interface_descriptor hidg_interface_desc = {
6573
.bDescriptorType = USB_DT_INTERFACE,
6674
/* .bInterfaceNumber = DYNAMIC */
6775
.bAlternateSetting = 0,
68-
.bNumEndpoints = 1,
76+
.bNumEndpoints = 2,
6977
.bInterfaceClass = USB_CLASS_HID,
7078
/* .bInterfaceSubClass = DYNAMIC */
7179
/* .bInterfaceProtocol = DYNAMIC */
@@ -96,10 +104,23 @@ static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = {
96104
*/
97105
};
98106

107+
static struct usb_endpoint_descriptor hidg_hs_out_ep_desc = {
108+
.bLength = USB_DT_ENDPOINT_SIZE,
109+
.bDescriptorType = USB_DT_ENDPOINT,
110+
.bEndpointAddress = USB_DIR_OUT,
111+
.bmAttributes = USB_ENDPOINT_XFER_INT,
112+
/*.wMaxPacketSize = DYNAMIC */
113+
.bInterval = 4, /* FIXME: Add this field in the
114+
* HID gadget configuration?
115+
* (struct hidg_func_descriptor)
116+
*/
117+
};
118+
99119
static struct usb_descriptor_header *hidg_hs_descriptors[] = {
100120
(struct usb_descriptor_header *)&hidg_interface_desc,
101121
(struct usb_descriptor_header *)&hidg_desc,
102122
(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
123+
(struct usb_descriptor_header *)&hidg_hs_out_ep_desc,
103124
NULL,
104125
};
105126

@@ -117,10 +138,23 @@ static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
117138
*/
118139
};
119140

141+
static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {
142+
.bLength = USB_DT_ENDPOINT_SIZE,
143+
.bDescriptorType = USB_DT_ENDPOINT,
144+
.bEndpointAddress = USB_DIR_OUT,
145+
.bmAttributes = USB_ENDPOINT_XFER_INT,
146+
/*.wMaxPacketSize = DYNAMIC */
147+
.bInterval = 10, /* FIXME: Add this field in the
148+
* HID gadget configuration?
149+
* (struct hidg_func_descriptor)
150+
*/
151+
};
152+
120153
static struct usb_descriptor_header *hidg_fs_descriptors[] = {
121154
(struct usb_descriptor_header *)&hidg_interface_desc,
122155
(struct usb_descriptor_header *)&hidg_desc,
123156
(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
157+
(struct usb_descriptor_header *)&hidg_fs_out_ep_desc,
124158
NULL,
125159
};
126160

@@ -130,9 +164,11 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = {
130164
static ssize_t f_hidg_read(struct file *file, char __user *buffer,
131165
size_t count, loff_t *ptr)
132166
{
133-
struct f_hidg *hidg = file->private_data;
134-
char *tmp_buff = NULL;
135-
unsigned long flags;
167+
struct f_hidg *hidg = file->private_data;
168+
struct f_hidg_req_list *list;
169+
struct usb_request *req;
170+
unsigned long flags;
171+
int ret;
136172

137173
if (!count)
138174
return 0;
@@ -142,8 +178,9 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
142178

143179
spin_lock_irqsave(&hidg->spinlock, flags);
144180

145-
#define READ_COND (hidg->set_report_buff != NULL)
181+
#define READ_COND (!list_empty(&hidg->completed_out_req))
146182

183+
/* wait for at least one buffer to complete */
147184
while (!READ_COND) {
148185
spin_unlock_irqrestore(&hidg->spinlock, flags);
149186
if (file->f_flags & O_NONBLOCK)
@@ -155,19 +192,34 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
155192
spin_lock_irqsave(&hidg->spinlock, flags);
156193
}
157194

158-
159-
count = min_t(unsigned, count, hidg->set_report_length);
160-
tmp_buff = hidg->set_report_buff;
161-
hidg->set_report_buff = NULL;
162-
195+
/* pick the first one */
196+
list = list_first_entry(&hidg->completed_out_req,
197+
struct f_hidg_req_list, list);
198+
req = list->req;
199+
count = min_t(unsigned int, count, req->actual - list->pos);
163200
spin_unlock_irqrestore(&hidg->spinlock, flags);
164201

165-
if (tmp_buff != NULL) {
166-
/* copy to user outside spinlock */
167-
count -= copy_to_user(buffer, tmp_buff, count);
168-
kfree(tmp_buff);
169-
} else
170-
count = -ENOMEM;
202+
/* copy to user outside spinlock */
203+
count -= copy_to_user(buffer, req->buf + list->pos, count);
204+
list->pos += count;
205+
206+
/*
207+
* if this request is completely handled and transfered to
208+
* userspace, remove its entry from the list and requeue it
209+
* again. Otherwise, we will revisit it again upon the next
210+
* call, taking into account its current read position.
211+
*/
212+
if (list->pos == req->actual) {
213+
spin_lock_irqsave(&hidg->spinlock, flags);
214+
list_del(&list->list);
215+
kfree(list);
216+
spin_unlock_irqrestore(&hidg->spinlock, flags);
217+
218+
req->length = hidg->report_length;
219+
ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL);
220+
if (ret < 0)
221+
return ret;
222+
}
171223

172224
return count;
173225
}
@@ -282,28 +334,37 @@ static int f_hidg_open(struct inode *inode, struct file *fd)
282334
/*-------------------------------------------------------------------------*/
283335
/* usb_function */
284336

285-
static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
337+
static struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, unsigned length)
286338
{
287-
struct f_hidg *hidg = (struct f_hidg *)req->context;
288-
289-
if (req->status != 0 || req->buf == NULL || req->actual == 0) {
290-
ERROR(hidg->func.config->cdev, "%s FAILED\n", __func__);
291-
return;
339+
struct usb_request *req;
340+
341+
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
342+
if (req) {
343+
req->length = length;
344+
req->buf = kmalloc(length, GFP_ATOMIC);
345+
if (!req->buf) {
346+
usb_ep_free_request(ep, req);
347+
req = NULL;
348+
}
292349
}
350+
return req;
351+
}
293352

294-
spin_lock(&hidg->spinlock);
295-
296-
hidg->set_report_buff = krealloc(hidg->set_report_buff,
297-
req->actual, GFP_ATOMIC);
353+
static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req)
354+
{
355+
struct f_hidg *hidg = (struct f_hidg *) req->context;
356+
struct f_hidg_req_list *req_list;
357+
unsigned long flags;
298358

299-
if (hidg->set_report_buff == NULL) {
300-
spin_unlock(&hidg->spinlock);
359+
req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC);
360+
if (!req_list)
301361
return;
302-
}
303-
hidg->set_report_length = req->actual;
304-
memcpy(hidg->set_report_buff, req->buf, req->actual);
305362

306-
spin_unlock(&hidg->spinlock);
363+
req_list->req = req;
364+
365+
spin_lock_irqsave(&hidg->spinlock, flags);
366+
list_add_tail(&req_list->list, &hidg->completed_out_req);
367+
spin_unlock_irqrestore(&hidg->spinlock, flags);
307368

308369
wake_up(&hidg->read_queue);
309370
}
@@ -344,9 +405,7 @@ static int hidg_setup(struct usb_function *f,
344405
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
345406
| HID_REQ_SET_REPORT):
346407
VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength);
347-
req->context = hidg;
348-
req->complete = hidg_set_report_complete;
349-
goto respond;
408+
goto stall;
350409
break;
351410

352411
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
@@ -403,16 +462,25 @@ static int hidg_setup(struct usb_function *f,
403462
static void hidg_disable(struct usb_function *f)
404463
{
405464
struct f_hidg *hidg = func_to_hidg(f);
465+
struct f_hidg_req_list *list, *next;
406466

407467
usb_ep_disable(hidg->in_ep);
408468
hidg->in_ep->driver_data = NULL;
469+
470+
usb_ep_disable(hidg->out_ep);
471+
hidg->out_ep->driver_data = NULL;
472+
473+
list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
474+
list_del(&list->list);
475+
kfree(list);
476+
}
409477
}
410478

411479
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
412480
{
413481
struct usb_composite_dev *cdev = f->config->cdev;
414482
struct f_hidg *hidg = func_to_hidg(f);
415-
int status = 0;
483+
int i, status = 0;
416484

417485
VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
418486

@@ -429,11 +497,55 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
429497
}
430498
status = usb_ep_enable(hidg->in_ep);
431499
if (status < 0) {
432-
ERROR(cdev, "Enable endpoint FAILED!\n");
500+
ERROR(cdev, "Enable IN endpoint FAILED!\n");
433501
goto fail;
434502
}
435503
hidg->in_ep->driver_data = hidg;
436504
}
505+
506+
507+
if (hidg->out_ep != NULL) {
508+
/* restart endpoint */
509+
if (hidg->out_ep->driver_data != NULL)
510+
usb_ep_disable(hidg->out_ep);
511+
512+
status = config_ep_by_speed(f->config->cdev->gadget, f,
513+
hidg->out_ep);
514+
if (status) {
515+
ERROR(cdev, "config_ep_by_speed FAILED!\n");
516+
goto fail;
517+
}
518+
status = usb_ep_enable(hidg->out_ep);
519+
if (status < 0) {
520+
ERROR(cdev, "Enable IN endpoint FAILED!\n");
521+
goto fail;
522+
}
523+
hidg->out_ep->driver_data = hidg;
524+
525+
/*
526+
* allocate a bunch of read buffers and queue them all at once.
527+
*/
528+
for (i = 0; i < hidg->qlen && status == 0; i++) {
529+
struct usb_request *req =
530+
hidg_alloc_ep_req(hidg->out_ep,
531+
hidg->report_length);
532+
if (req) {
533+
req->complete = hidg_set_report_complete;
534+
req->context = hidg;
535+
status = usb_ep_queue(hidg->out_ep, req,
536+
GFP_ATOMIC);
537+
if (status)
538+
ERROR(cdev, "%s queue req --> %d\n",
539+
hidg->out_ep->name, status);
540+
} else {
541+
usb_ep_disable(hidg->out_ep);
542+
hidg->out_ep->driver_data = NULL;
543+
status = -ENOMEM;
544+
goto fail;
545+
}
546+
}
547+
}
548+
437549
fail:
438550
return status;
439551
}
@@ -470,13 +582,18 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
470582
ep->driver_data = c->cdev; /* claim */
471583
hidg->in_ep = ep;
472584

585+
ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
586+
if (!ep)
587+
goto fail;
588+
ep->driver_data = c->cdev; /* claim */
589+
hidg->out_ep = ep;
590+
473591
/* preallocate request and buffer */
474592
status = -ENOMEM;
475593
hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
476594
if (!hidg->req)
477595
goto fail;
478596

479-
480597
hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
481598
if (!hidg->req->buf)
482599
goto fail;
@@ -486,12 +603,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
486603
hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
487604
hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
488605
hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
606+
hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
607+
hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
489608
hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
490609
hidg_desc.desc[0].wDescriptorLength =
491610
cpu_to_le16(hidg->report_desc_length);
492611

493-
hidg->set_report_buff = NULL;
494-
495612
/* copy descriptors */
496613
f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
497614
if (!f->descriptors)
@@ -500,6 +617,8 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
500617
if (gadget_is_dualspeed(c->cdev->gadget)) {
501618
hidg_hs_in_ep_desc.bEndpointAddress =
502619
hidg_fs_in_ep_desc.bEndpointAddress;
620+
hidg_hs_out_ep_desc.bEndpointAddress =
621+
hidg_fs_out_ep_desc.bEndpointAddress;
503622
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
504623
if (!f->hs_descriptors)
505624
goto fail;
@@ -509,6 +628,7 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
509628
spin_lock_init(&hidg->spinlock);
510629
init_waitqueue_head(&hidg->write_queue);
511630
init_waitqueue_head(&hidg->read_queue);
631+
INIT_LIST_HEAD(&hidg->completed_out_req);
512632

513633
/* create char device */
514634
cdev_init(&hidg->cdev, &f_hidg_fops);
@@ -553,7 +673,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
553673
usb_free_descriptors(f->descriptors);
554674

555675
kfree(hidg->report_desc);
556-
kfree(hidg->set_report_buff);
557676
kfree(hidg);
558677
}
559678

@@ -624,6 +743,9 @@ int __init hidg_bind_config(struct usb_configuration *c,
624743
hidg->func.disable = hidg_disable;
625744
hidg->func.setup = hidg_setup;
626745

746+
/* this could me made configurable at some point */
747+
hidg->qlen = 4;
748+
627749
status = usb_add_function(c, &hidg->func);
628750
if (status)
629751
kfree(hidg);

0 commit comments

Comments
 (0)