diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/f_uvc.c | 241 | ||||
-rw-r--r-- | drivers/usb/gadget/f_uvc.h | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/uvc.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/webcam.c | 29 |
4 files changed, 247 insertions, 35 deletions
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index dd7d7a98ed43..2a8bf0655c60 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c | |||
@@ -29,6 +29,25 @@ | |||
29 | 29 | ||
30 | unsigned int uvc_gadget_trace_param; | 30 | unsigned int uvc_gadget_trace_param; |
31 | 31 | ||
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 | |||
32 | /* -------------------------------------------------------------------------- | 51 | /* -------------------------------------------------------------------------- |
33 | * Function descriptors | 52 | * Function descriptors |
34 | */ | 53 | */ |
@@ -84,7 +103,7 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { | |||
84 | .iInterface = 0, | 103 | .iInterface = 0, |
85 | }; | 104 | }; |
86 | 105 | ||
87 | static struct usb_endpoint_descriptor uvc_control_ep __initdata = { | 106 | static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { |
88 | .bLength = USB_DT_ENDPOINT_SIZE, | 107 | .bLength = USB_DT_ENDPOINT_SIZE, |
89 | .bDescriptorType = USB_DT_ENDPOINT, | 108 | .bDescriptorType = USB_DT_ENDPOINT, |
90 | .bEndpointAddress = USB_DIR_IN, | 109 | .bEndpointAddress = USB_DIR_IN, |
@@ -124,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { | |||
124 | .iInterface = 0, | 143 | .iInterface = 0, |
125 | }; | 144 | }; |
126 | 145 | ||
127 | static struct usb_endpoint_descriptor uvc_streaming_ep = { | 146 | static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { |
128 | .bLength = USB_DT_ENDPOINT_SIZE, | 147 | .bLength = USB_DT_ENDPOINT_SIZE, |
129 | .bDescriptorType = USB_DT_ENDPOINT, | 148 | .bDescriptorType = USB_DT_ENDPOINT, |
130 | .bEndpointAddress = USB_DIR_IN, | 149 | .bEndpointAddress = USB_DIR_IN, |
@@ -133,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = { | |||
133 | .bInterval = 1, | 152 | .bInterval = 1, |
134 | }; | 153 | }; |
135 | 154 | ||
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 | |||
136 | static const struct usb_descriptor_header * const uvc_fs_streaming[] = { | 205 | static const struct usb_descriptor_header * const uvc_fs_streaming[] = { |
137 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, | 206 | (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, |
139 | NULL, | 208 | NULL, |
140 | }; | 209 | }; |
141 | 210 | ||
142 | static const struct usb_descriptor_header * const uvc_hs_streaming[] = { | 211 | static const struct usb_descriptor_header * const uvc_hs_streaming[] = { |
143 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, | 212 | (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, | ||
145 | NULL, | 221 | NULL, |
146 | }; | 222 | }; |
147 | 223 | ||
@@ -217,6 +293,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | |||
217 | struct uvc_device *uvc = to_uvc(f); | 293 | struct uvc_device *uvc = to_uvc(f); |
218 | struct v4l2_event v4l2_event; | 294 | struct v4l2_event v4l2_event; |
219 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | 295 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; |
296 | int ret; | ||
220 | 297 | ||
221 | INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); | 298 | INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); |
222 | 299 | ||
@@ -264,7 +341,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | |||
264 | return 0; | 341 | return 0; |
265 | 342 | ||
266 | if (uvc->video.ep) { | 343 | 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; | ||
268 | usb_ep_enable(uvc->video.ep); | 348 | usb_ep_enable(uvc->video.ep); |
269 | } | 349 | } |
270 | 350 | ||
@@ -370,9 +450,11 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
370 | { | 450 | { |
371 | struct uvc_input_header_descriptor *uvc_streaming_header; | 451 | struct uvc_input_header_descriptor *uvc_streaming_header; |
372 | struct uvc_header_descriptor *uvc_control_header; | 452 | struct uvc_header_descriptor *uvc_control_header; |
453 | const struct uvc_descriptor_header * const *uvc_control_desc; | ||
373 | const struct uvc_descriptor_header * const *uvc_streaming_cls; | 454 | const struct uvc_descriptor_header * const *uvc_streaming_cls; |
374 | const struct usb_descriptor_header * const *uvc_streaming_std; | 455 | const struct usb_descriptor_header * const *uvc_streaming_std; |
375 | const struct usb_descriptor_header * const *src; | 456 | const struct usb_descriptor_header * const *src; |
457 | static struct usb_endpoint_descriptor *uvc_control_ep; | ||
376 | struct usb_descriptor_header **dst; | 458 | struct usb_descriptor_header **dst; |
377 | struct usb_descriptor_header **hdr; | 459 | struct usb_descriptor_header **hdr; |
378 | unsigned int control_size; | 460 | unsigned int control_size; |
@@ -381,10 +463,29 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
381 | unsigned int bytes; | 463 | unsigned int bytes; |
382 | void *mem; | 464 | void *mem; |
383 | 465 | ||
384 | uvc_streaming_cls = (speed == USB_SPEED_FULL) | 466 | switch (speed) { |
385 | ? uvc->desc.fs_streaming : uvc->desc.hs_streaming; | 467 | case USB_SPEED_SUPER: |
386 | uvc_streaming_std = (speed == USB_SPEED_FULL) | 468 | uvc_control_desc = uvc->desc.ss_control; |
387 | ? uvc_fs_streaming : uvc_hs_streaming; | 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 | } | ||
388 | 489 | ||
389 | /* Descriptors layout | 490 | /* Descriptors layout |
390 | * | 491 | * |
@@ -402,16 +503,24 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
402 | control_size = 0; | 503 | control_size = 0; |
403 | streaming_size = 0; | 504 | streaming_size = 0; |
404 | bytes = uvc_iad.bLength + uvc_control_intf.bLength | 505 | 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 |
406 | + uvc_streaming_intf_alt0.bLength; | 507 | + uvc_streaming_intf_alt0.bLength; |
407 | n_desc = 5; | ||
408 | 508 | ||
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) { | ||
410 | control_size += (*src)->bLength; | 518 | control_size += (*src)->bLength; |
411 | bytes += (*src)->bLength; | 519 | bytes += (*src)->bLength; |
412 | n_desc++; | 520 | n_desc++; |
413 | } | 521 | } |
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) { | ||
415 | streaming_size += (*src)->bLength; | 524 | streaming_size += (*src)->bLength; |
416 | bytes += (*src)->bLength; | 525 | bytes += (*src)->bLength; |
417 | n_desc++; | 526 | n_desc++; |
@@ -435,12 +544,15 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
435 | 544 | ||
436 | uvc_control_header = mem; | 545 | uvc_control_header = mem; |
437 | UVC_COPY_DESCRIPTORS(mem, dst, | 546 | UVC_COPY_DESCRIPTORS(mem, dst, |
438 | (const struct usb_descriptor_header**)uvc->desc.control); | 547 | (const struct usb_descriptor_header **)uvc_control_desc); |
439 | uvc_control_header->wTotalLength = cpu_to_le16(control_size); | 548 | uvc_control_header->wTotalLength = cpu_to_le16(control_size); |
440 | uvc_control_header->bInCollection = 1; | 549 | uvc_control_header->bInCollection = 1; |
441 | uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; | 550 | uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; |
442 | 551 | ||
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 | |||
444 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); | 556 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); |
445 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); | 557 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); |
446 | 558 | ||
@@ -448,7 +560,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
448 | UVC_COPY_DESCRIPTORS(mem, dst, | 560 | UVC_COPY_DESCRIPTORS(mem, dst, |
449 | (const struct usb_descriptor_header**)uvc_streaming_cls); | 561 | (const struct usb_descriptor_header**)uvc_streaming_cls); |
450 | uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); | 562 | 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; | ||
452 | 565 | ||
453 | UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); | 566 | UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); |
454 | 567 | ||
@@ -484,6 +597,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) | |||
484 | 597 | ||
485 | kfree(f->descriptors); | 598 | kfree(f->descriptors); |
486 | kfree(f->hs_descriptors); | 599 | kfree(f->hs_descriptors); |
600 | kfree(f->ss_descriptors); | ||
487 | 601 | ||
488 | kfree(uvc); | 602 | kfree(uvc); |
489 | } | 603 | } |
@@ -498,8 +612,26 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
498 | 612 | ||
499 | INFO(cdev, "uvc_function_bind\n"); | 613 | INFO(cdev, "uvc_function_bind\n"); |
500 | 614 | ||
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 | |||
501 | /* Allocate endpoints. */ | 633 | /* Allocate endpoints. */ |
502 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); | 634 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep); |
503 | if (!ep) { | 635 | if (!ep) { |
504 | INFO(cdev, "Unable to allocate control EP\n"); | 636 | INFO(cdev, "Unable to allocate control EP\n"); |
505 | goto error; | 637 | goto error; |
@@ -507,7 +639,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
507 | uvc->control_ep = ep; | 639 | uvc->control_ep = ep; |
508 | ep->driver_data = uvc; | 640 | ep->driver_data = uvc; |
509 | 641 | ||
510 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep); | 642 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); |
511 | if (!ep) { | 643 | if (!ep) { |
512 | INFO(cdev, "Unable to allocate streaming EP\n"); | 644 | INFO(cdev, "Unable to allocate streaming EP\n"); |
513 | goto error; | 645 | goto error; |
@@ -528,9 +660,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
528 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; | 660 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; |
529 | uvc->streaming_intf = ret; | 661 | uvc->streaming_intf = ret; |
530 | 662 | ||
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. */ | ||
532 | f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); | 668 | 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 | } | ||
534 | 709 | ||
535 | /* Preallocate control endpoint request. */ | 710 | /* Preallocate control endpoint request. */ |
536 | uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); | 711 | uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); |
@@ -585,9 +760,11 @@ error: | |||
585 | */ | 760 | */ |
586 | int __init | 761 | int __init |
587 | uvc_bind_config(struct usb_configuration *c, | 762 | 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, | ||
589 | const struct uvc_descriptor_header * const *fs_streaming, | 765 | 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) | ||
591 | { | 768 | { |
592 | struct uvc_device *uvc; | 769 | struct uvc_device *uvc; |
593 | int ret = 0; | 770 | int ret = 0; |
@@ -605,21 +782,31 @@ uvc_bind_config(struct usb_configuration *c, | |||
605 | uvc->state = UVC_STATE_DISCONNECTED; | 782 | uvc->state = UVC_STATE_DISCONNECTED; |
606 | 783 | ||
607 | /* Validate the descriptors. */ | 784 | /* Validate the descriptors. */ |
608 | if (control == NULL || control[0] == NULL || | 785 | if (fs_control == NULL || fs_control[0] == NULL || |
609 | control[0]->bDescriptorSubType != UVC_VC_HEADER) | 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) | ||
610 | goto error; | 791 | goto error; |
611 | 792 | ||
612 | if (fs_streaming == NULL || fs_streaming[0] == NULL || | 793 | 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) |
614 | goto error; | 795 | goto error; |
615 | 796 | ||
616 | if (hs_streaming == NULL || hs_streaming[0] == NULL || | 797 | 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) | ||
618 | goto error; | 803 | goto error; |
619 | 804 | ||
620 | uvc->desc.control = control; | 805 | uvc->desc.fs_control = fs_control; |
806 | uvc->desc.ss_control = ss_control; | ||
621 | uvc->desc.fs_streaming = fs_streaming; | 807 | uvc->desc.fs_streaming = fs_streaming; |
622 | uvc->desc.hs_streaming = hs_streaming; | 808 | uvc->desc.hs_streaming = hs_streaming; |
809 | uvc->desc.ss_streaming = ss_streaming; | ||
623 | 810 | ||
624 | /* maybe allocate device-global string IDs, and patch descriptors */ | 811 | /* maybe allocate device-global string IDs, and patch descriptors */ |
625 | if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { | 812 | if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { |
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h index abf832935134..c3d258d30188 100644 --- a/drivers/usb/gadget/f_uvc.h +++ b/drivers/usb/gadget/f_uvc.h | |||
@@ -17,9 +17,11 @@ | |||
17 | #include <linux/usb/video.h> | 17 | #include <linux/usb/video.h> |
18 | 18 | ||
19 | extern int uvc_bind_config(struct usb_configuration *c, | 19 | extern int uvc_bind_config(struct usb_configuration *c, |
20 | const struct uvc_descriptor_header * const *control, | 20 | const struct uvc_descriptor_header * const *fs_control, |
21 | const struct uvc_descriptor_header * const *fs_streaming, | 21 | const struct uvc_descriptor_header * const *hs_control, |
22 | const struct uvc_descriptor_header * const *hs_streaming); | 22 | const struct uvc_descriptor_header * const *fs_streaming, |
23 | const struct uvc_descriptor_header * const *hs_streaming, | ||
24 | const struct uvc_descriptor_header * const *ss_streaming); | ||
23 | 25 | ||
24 | #endif /* _F_UVC_H_ */ | 26 | #endif /* _F_UVC_H_ */ |
25 | 27 | ||
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h index ca4e03a1c73a..93b0c1191115 100644 --- a/drivers/usb/gadget/uvc.h +++ b/drivers/usb/gadget/uvc.h | |||
@@ -153,9 +153,11 @@ struct uvc_device | |||
153 | 153 | ||
154 | /* Descriptors */ | 154 | /* Descriptors */ |
155 | struct { | 155 | struct { |
156 | const struct uvc_descriptor_header * const *control; | 156 | const struct uvc_descriptor_header * const *fs_control; |
157 | const struct uvc_descriptor_header * const *ss_control; | ||
157 | const struct uvc_descriptor_header * const *fs_streaming; | 158 | const struct uvc_descriptor_header * const *fs_streaming; |
158 | const struct uvc_descriptor_header * const *hs_streaming; | 159 | const struct uvc_descriptor_header * const *hs_streaming; |
160 | const struct uvc_descriptor_header * const *ss_streaming; | ||
159 | } desc; | 161 | } desc; |
160 | 162 | ||
161 | unsigned int control_intf; | 163 | unsigned int control_intf; |
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c index 668fe128f2ef..120e134e805e 100644 --- a/drivers/usb/gadget/webcam.c +++ b/drivers/usb/gadget/webcam.c | |||
@@ -272,7 +272,15 @@ static const struct uvc_color_matching_descriptor uvc_color_matching = { | |||
272 | .bMatrixCoefficients = 4, | 272 | .bMatrixCoefficients = 4, |
273 | }; | 273 | }; |
274 | 274 | ||
275 | static const struct uvc_descriptor_header * const uvc_control_cls[] = { | 275 | static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = { |
276 | (const struct uvc_descriptor_header *) &uvc_control_header, | ||
277 | (const struct uvc_descriptor_header *) &uvc_camera_terminal, | ||
278 | (const struct uvc_descriptor_header *) &uvc_processing, | ||
279 | (const struct uvc_descriptor_header *) &uvc_output_terminal, | ||
280 | NULL, | ||
281 | }; | ||
282 | |||
283 | static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = { | ||
276 | (const struct uvc_descriptor_header *) &uvc_control_header, | 284 | (const struct uvc_descriptor_header *) &uvc_control_header, |
277 | (const struct uvc_descriptor_header *) &uvc_camera_terminal, | 285 | (const struct uvc_descriptor_header *) &uvc_camera_terminal, |
278 | (const struct uvc_descriptor_header *) &uvc_processing, | 286 | (const struct uvc_descriptor_header *) &uvc_processing, |
@@ -304,6 +312,18 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { | |||
304 | NULL, | 312 | NULL, |
305 | }; | 313 | }; |
306 | 314 | ||
315 | static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { | ||
316 | (const struct uvc_descriptor_header *) &uvc_input_header, | ||
317 | (const struct uvc_descriptor_header *) &uvc_format_yuv, | ||
318 | (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, | ||
319 | (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, | ||
320 | (const struct uvc_descriptor_header *) &uvc_format_mjpg, | ||
321 | (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, | ||
322 | (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, | ||
323 | (const struct uvc_descriptor_header *) &uvc_color_matching, | ||
324 | NULL, | ||
325 | }; | ||
326 | |||
307 | /* -------------------------------------------------------------------------- | 327 | /* -------------------------------------------------------------------------- |
308 | * USB configuration | 328 | * USB configuration |
309 | */ | 329 | */ |
@@ -311,8 +331,9 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { | |||
311 | static int __init | 331 | static int __init |
312 | webcam_config_bind(struct usb_configuration *c) | 332 | webcam_config_bind(struct usb_configuration *c) |
313 | { | 333 | { |
314 | return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls, | 334 | return uvc_bind_config(c, uvc_fs_control_cls, uvc_ss_control_cls, |
315 | uvc_hs_streaming_cls); | 335 | uvc_fs_streaming_cls, uvc_hs_streaming_cls, |
336 | uvc_ss_streaming_cls); | ||
316 | } | 337 | } |
317 | 338 | ||
318 | static struct usb_configuration webcam_config_driver = { | 339 | static struct usb_configuration webcam_config_driver = { |
@@ -373,7 +394,7 @@ static struct usb_composite_driver webcam_driver = { | |||
373 | .name = "g_webcam", | 394 | .name = "g_webcam", |
374 | .dev = &webcam_device_descriptor, | 395 | .dev = &webcam_device_descriptor, |
375 | .strings = webcam_device_strings, | 396 | .strings = webcam_device_strings, |
376 | .max_speed = USB_SPEED_HIGH, | 397 | .max_speed = USB_SPEED_SUPER, |
377 | .unbind = webcam_unbind, | 398 | .unbind = webcam_unbind, |
378 | }; | 399 | }; |
379 | 400 | ||