Skip to content

Commit fbcaba0

Browse files
bhupesh-sharmaFelipe Balbi
authored andcommitted
usb: gadget: uvc: Add super-speed support to UVC webcam gadget
This patch adds super-speed support to UVC webcam gadget. Also in this patch: - We add the configurability to pass bInterval, bMaxBurst, mult factors for video streaming endpoint (ISOC IN) through module parameters. - We use config_ep_by_speed helper routine to configure video streaming endpoint. Signed-off-by: Bhupesh Sharma <bhupesh.sharma@st.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
1 parent 5797663 commit fbcaba0

File tree

4 files changed

+247
-35
lines changed

4 files changed

+247
-35
lines changed

drivers/usb/gadget/f_uvc.c

Lines changed: 214 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@
2929

3030
unsigned int uvc_gadget_trace_param;
3131

32+
/*-------------------------------------------------------------------------*/
33+
34+
/* module parameters specific to the Video streaming endpoint */
35+
static unsigned streaming_interval = 1;
36+
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
37+
MODULE_PARM_DESC(streaming_interval, "1 - 16");
38+
39+
static unsigned streaming_maxpacket = 1024;
40+
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
41+
MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
42+
43+
static unsigned streaming_mult;
44+
module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
45+
MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
46+
47+
static unsigned streaming_maxburst;
48+
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
49+
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
50+
3251
/* --------------------------------------------------------------------------
3352
* Function descriptors
3453
*/
@@ -84,7 +103,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
84103
.iInterface = 0,
85104
};
86105

87-
static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
106+
static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
88107
.bLength = USB_DT_ENDPOINT_SIZE,
89108
.bDescriptorType = USB_DT_ENDPOINT,
90109
.bEndpointAddress = USB_DIR_IN,
@@ -124,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
124143
.iInterface = 0,
125144
};
126145

127-
static struct usb_endpoint_descriptor uvc_streaming_ep = {
146+
static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
128147
.bLength = USB_DT_ENDPOINT_SIZE,
129148
.bDescriptorType = USB_DT_ENDPOINT,
130149
.bEndpointAddress = USB_DIR_IN,
@@ -133,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = {
133152
.bInterval = 1,
134153
};
135154

155+
static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
156+
.bLength = USB_DT_ENDPOINT_SIZE,
157+
.bDescriptorType = USB_DT_ENDPOINT,
158+
.bEndpointAddress = USB_DIR_IN,
159+
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
160+
.wMaxPacketSize = cpu_to_le16(1024),
161+
.bInterval = 1,
162+
};
163+
164+
/* super speed support */
165+
static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
166+
.bLength = USB_DT_ENDPOINT_SIZE,
167+
.bDescriptorType = USB_DT_ENDPOINT,
168+
169+
.bEndpointAddress = USB_DIR_IN,
170+
.bmAttributes = USB_ENDPOINT_XFER_INT,
171+
.wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
172+
.bInterval = 8,
173+
};
174+
175+
static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
176+
.bLength = sizeof uvc_ss_control_comp,
177+
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
178+
179+
/* the following 3 values can be tweaked if necessary */
180+
/* .bMaxBurst = 0, */
181+
/* .bmAttributes = 0, */
182+
.wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
183+
};
184+
185+
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
186+
.bLength = USB_DT_ENDPOINT_SIZE,
187+
.bDescriptorType = USB_DT_ENDPOINT,
188+
189+
.bEndpointAddress = USB_DIR_IN,
190+
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
191+
.wMaxPacketSize = cpu_to_le16(1024),
192+
.bInterval = 4,
193+
};
194+
195+
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
196+
.bLength = sizeof uvc_ss_streaming_comp,
197+
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
198+
199+
/* the following 3 values can be tweaked if necessary */
200+
.bMaxBurst = 0,
201+
.bmAttributes = 0,
202+
.wBytesPerInterval = cpu_to_le16(1024),
203+
};
204+
136205
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
137206
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
138-
(struct usb_descriptor_header *) &uvc_streaming_ep,
207+
(struct usb_descriptor_header *) &uvc_fs_streaming_ep,
139208
NULL,
140209
};
141210

142211
static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
143212
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
144-
(struct usb_descriptor_header *) &uvc_streaming_ep,
213+
(struct usb_descriptor_header *) &uvc_hs_streaming_ep,
214+
NULL,
215+
};
216+
217+
static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
218+
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
219+
(struct usb_descriptor_header *) &uvc_ss_streaming_ep,
220+
(struct usb_descriptor_header *) &uvc_ss_streaming_comp,
145221
NULL,
146222
};
147223

@@ -217,6 +293,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
217293
struct uvc_device *uvc = to_uvc(f);
218294
struct v4l2_event v4l2_event;
219295
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
296+
int ret;
220297

221298
INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
222299

@@ -264,7 +341,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
264341
return 0;
265342

266343
if (uvc->video.ep) {
267-
uvc->video.ep->desc = &uvc_streaming_ep;
344+
ret = config_ep_by_speed(f->config->cdev->gadget,
345+
&(uvc->func), uvc->video.ep);
346+
if (ret)
347+
return ret;
268348
usb_ep_enable(uvc->video.ep);
269349
}
270350

@@ -370,9 +450,11 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
370450
{
371451
struct uvc_input_header_descriptor *uvc_streaming_header;
372452
struct uvc_header_descriptor *uvc_control_header;
453+
const struct uvc_descriptor_header * const *uvc_control_desc;
373454
const struct uvc_descriptor_header * const *uvc_streaming_cls;
374455
const struct usb_descriptor_header * const *uvc_streaming_std;
375456
const struct usb_descriptor_header * const *src;
457+
static struct usb_endpoint_descriptor *uvc_control_ep;
376458
struct usb_descriptor_header **dst;
377459
struct usb_descriptor_header **hdr;
378460
unsigned int control_size;
@@ -381,10 +463,29 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
381463
unsigned int bytes;
382464
void *mem;
383465

384-
uvc_streaming_cls = (speed == USB_SPEED_FULL)
385-
? uvc->desc.fs_streaming : uvc->desc.hs_streaming;
386-
uvc_streaming_std = (speed == USB_SPEED_FULL)
387-
? uvc_fs_streaming : uvc_hs_streaming;
466+
switch (speed) {
467+
case USB_SPEED_SUPER:
468+
uvc_control_desc = uvc->desc.ss_control;
469+
uvc_streaming_cls = uvc->desc.ss_streaming;
470+
uvc_streaming_std = uvc_ss_streaming;
471+
uvc_control_ep = &uvc_ss_control_ep;
472+
break;
473+
474+
case USB_SPEED_HIGH:
475+
uvc_control_desc = uvc->desc.fs_control;
476+
uvc_streaming_cls = uvc->desc.hs_streaming;
477+
uvc_streaming_std = uvc_hs_streaming;
478+
uvc_control_ep = &uvc_fs_control_ep;
479+
break;
480+
481+
case USB_SPEED_FULL:
482+
default:
483+
uvc_control_desc = uvc->desc.fs_control;
484+
uvc_streaming_cls = uvc->desc.fs_streaming;
485+
uvc_streaming_std = uvc_fs_streaming;
486+
uvc_control_ep = &uvc_fs_control_ep;
487+
break;
488+
}
388489

389490
/* Descriptors layout
390491
*
@@ -402,16 +503,24 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
402503
control_size = 0;
403504
streaming_size = 0;
404505
bytes = uvc_iad.bLength + uvc_control_intf.bLength
405-
+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength
506+
+ uvc_control_ep->bLength + uvc_control_cs_ep.bLength
406507
+ uvc_streaming_intf_alt0.bLength;
407-
n_desc = 5;
408508

409-
for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) {
509+
if (speed == USB_SPEED_SUPER) {
510+
bytes += uvc_ss_control_comp.bLength;
511+
n_desc = 6;
512+
} else {
513+
n_desc = 5;
514+
}
515+
516+
for (src = (const struct usb_descriptor_header **)uvc_control_desc;
517+
*src; ++src) {
410518
control_size += (*src)->bLength;
411519
bytes += (*src)->bLength;
412520
n_desc++;
413521
}
414-
for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) {
522+
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
523+
*src; ++src) {
415524
streaming_size += (*src)->bLength;
416525
bytes += (*src)->bLength;
417526
n_desc++;
@@ -435,20 +544,24 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
435544

436545
uvc_control_header = mem;
437546
UVC_COPY_DESCRIPTORS(mem, dst,
438-
(const struct usb_descriptor_header**)uvc->desc.control);
547+
(const struct usb_descriptor_header **)uvc_control_desc);
439548
uvc_control_header->wTotalLength = cpu_to_le16(control_size);
440549
uvc_control_header->bInCollection = 1;
441550
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
442551

443-
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
552+
UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
553+
if (speed == USB_SPEED_SUPER)
554+
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
555+
444556
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
445557
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
446558

447559
uvc_streaming_header = mem;
448560
UVC_COPY_DESCRIPTORS(mem, dst,
449561
(const struct usb_descriptor_header**)uvc_streaming_cls);
450562
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
451-
uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress;
563+
uvc_streaming_header->bEndpointAddress =
564+
uvc_fs_streaming_ep.bEndpointAddress;
452565

453566
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
454567

@@ -484,6 +597,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
484597

485598
kfree(f->descriptors);
486599
kfree(f->hs_descriptors);
600+
kfree(f->ss_descriptors);
487601

488602
kfree(uvc);
489603
}
@@ -498,16 +612,34 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
498612

499613
INFO(cdev, "uvc_function_bind\n");
500614

615+
/* sanity check the streaming endpoint module parameters */
616+
if (streaming_interval < 1)
617+
streaming_interval = 1;
618+
if (streaming_interval > 16)
619+
streaming_interval = 16;
620+
if (streaming_mult > 2)
621+
streaming_mult = 2;
622+
if (streaming_maxburst > 15)
623+
streaming_maxburst = 15;
624+
625+
/*
626+
* fill in the FS video streaming specific descriptors from the
627+
* module parameters
628+
*/
629+
uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
630+
1023 : streaming_maxpacket;
631+
uvc_fs_streaming_ep.bInterval = streaming_interval;
632+
501633
/* Allocate endpoints. */
502-
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
634+
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
503635
if (!ep) {
504636
INFO(cdev, "Unable to allocate control EP\n");
505637
goto error;
506638
}
507639
uvc->control_ep = ep;
508640
ep->driver_data = uvc;
509641

510-
ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
642+
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
511643
if (!ep) {
512644
INFO(cdev, "Unable to allocate streaming EP\n");
513645
goto error;
@@ -528,9 +660,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
528660
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
529661
uvc->streaming_intf = ret;
530662

531-
/* Copy descriptors. */
663+
/* sanity check the streaming endpoint module parameters */
664+
if (streaming_maxpacket > 1024)
665+
streaming_maxpacket = 1024;
666+
667+
/* Copy descriptors for FS. */
532668
f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
533-
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
669+
670+
/* support high speed hardware */
671+
if (gadget_is_dualspeed(cdev->gadget)) {
672+
/*
673+
* Fill in the HS descriptors from the module parameters for the
674+
* Video Streaming endpoint.
675+
* NOTE: We assume that the user knows what they are doing and
676+
* won't give parameters that their UDC doesn't support.
677+
*/
678+
uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
679+
uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
680+
uvc_hs_streaming_ep.bInterval = streaming_interval;
681+
uvc_hs_streaming_ep.bEndpointAddress =
682+
uvc_fs_streaming_ep.bEndpointAddress;
683+
684+
/* Copy descriptors. */
685+
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
686+
}
687+
688+
/* support super speed hardware */
689+
if (gadget_is_superspeed(c->cdev->gadget)) {
690+
/*
691+
* Fill in the SS descriptors from the module parameters for the
692+
* Video Streaming endpoint.
693+
* NOTE: We assume that the user knows what they are doing and
694+
* won't give parameters that their UDC doesn't support.
695+
*/
696+
uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
697+
uvc_ss_streaming_ep.bInterval = streaming_interval;
698+
uvc_ss_streaming_comp.bmAttributes = streaming_mult;
699+
uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
700+
uvc_ss_streaming_comp.wBytesPerInterval =
701+
streaming_maxpacket * (streaming_mult + 1) *
702+
(streaming_maxburst + 1);
703+
uvc_ss_streaming_ep.bEndpointAddress =
704+
uvc_fs_streaming_ep.bEndpointAddress;
705+
706+
/* Copy descriptors. */
707+
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
708+
}
534709

535710
/* Preallocate control endpoint request. */
536711
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@@ -585,9 +760,11 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
585760
*/
586761
int __init
587762
uvc_bind_config(struct usb_configuration *c,
588-
const struct uvc_descriptor_header * const *control,
763+
const struct uvc_descriptor_header * const *fs_control,
764+
const struct uvc_descriptor_header * const *ss_control,
589765
const struct uvc_descriptor_header * const *fs_streaming,
590-
const struct uvc_descriptor_header * const *hs_streaming)
766+
const struct uvc_descriptor_header * const *hs_streaming,
767+
const struct uvc_descriptor_header * const *ss_streaming)
591768
{
592769
struct uvc_device *uvc;
593770
int ret = 0;
@@ -605,21 +782,31 @@ uvc_bind_config(struct usb_configuration *c,
605782
uvc->state = UVC_STATE_DISCONNECTED;
606783

607784
/* Validate the descriptors. */
608-
if (control == NULL || control[0] == NULL ||
609-
control[0]->bDescriptorSubType != UVC_VC_HEADER)
785+
if (fs_control == NULL || fs_control[0] == NULL ||
786+
fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
787+
goto error;
788+
789+
if (ss_control == NULL || ss_control[0] == NULL ||
790+
ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
610791
goto error;
611792

612793
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
613-
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
794+
fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
614795
goto error;
615796

616797
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
617-
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
798+
hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
799+
goto error;
800+
801+
if (ss_streaming == NULL || ss_streaming[0] == NULL ||
802+
ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
618803
goto error;
619804

620-
uvc->desc.control = control;
805+
uvc->desc.fs_control = fs_control;
806+
uvc->desc.ss_control = ss_control;
621807
uvc->desc.fs_streaming = fs_streaming;
622808
uvc->desc.hs_streaming = hs_streaming;
809+
uvc->desc.ss_streaming = ss_streaming;
623810

624811
/* maybe allocate device-global string IDs, and patch descriptors */
625812
if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {

0 commit comments

Comments
 (0)