diff options
Diffstat (limited to 'drivers/usb/gadget/f_uvc.c')
-rw-r--r-- | drivers/usb/gadget/f_uvc.c | 287 |
1 files changed, 241 insertions, 46 deletions
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index 2022fe492148..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 | */ |
@@ -59,6 +78,8 @@ static struct usb_gadget_strings *uvc_function_strings[] = { | |||
59 | #define UVC_INTF_VIDEO_CONTROL 0 | 78 | #define UVC_INTF_VIDEO_CONTROL 0 |
60 | #define UVC_INTF_VIDEO_STREAMING 1 | 79 | #define UVC_INTF_VIDEO_STREAMING 1 |
61 | 80 | ||
81 | #define STATUS_BYTECOUNT 16 /* 16 bytes status */ | ||
82 | |||
62 | static struct usb_interface_assoc_descriptor uvc_iad __initdata = { | 83 | static struct usb_interface_assoc_descriptor uvc_iad __initdata = { |
63 | .bLength = sizeof(uvc_iad), | 84 | .bLength = sizeof(uvc_iad), |
64 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, | 85 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, |
@@ -82,12 +103,12 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { | |||
82 | .iInterface = 0, | 103 | .iInterface = 0, |
83 | }; | 104 | }; |
84 | 105 | ||
85 | static struct usb_endpoint_descriptor uvc_control_ep __initdata = { | 106 | static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { |
86 | .bLength = USB_DT_ENDPOINT_SIZE, | 107 | .bLength = USB_DT_ENDPOINT_SIZE, |
87 | .bDescriptorType = USB_DT_ENDPOINT, | 108 | .bDescriptorType = USB_DT_ENDPOINT, |
88 | .bEndpointAddress = USB_DIR_IN, | 109 | .bEndpointAddress = USB_DIR_IN, |
89 | .bmAttributes = USB_ENDPOINT_XFER_INT, | 110 | .bmAttributes = USB_ENDPOINT_XFER_INT, |
90 | .wMaxPacketSize = cpu_to_le16(16), | 111 | .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), |
91 | .bInterval = 8, | 112 | .bInterval = 8, |
92 | }; | 113 | }; |
93 | 114 | ||
@@ -95,7 +116,7 @@ static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = { | |||
95 | .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, | 116 | .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, |
96 | .bDescriptorType = USB_DT_CS_ENDPOINT, | 117 | .bDescriptorType = USB_DT_CS_ENDPOINT, |
97 | .bDescriptorSubType = UVC_EP_INTERRUPT, | 118 | .bDescriptorSubType = UVC_EP_INTERRUPT, |
98 | .wMaxTransferSize = cpu_to_le16(16), | 119 | .wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT), |
99 | }; | 120 | }; |
100 | 121 | ||
101 | static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { | 122 | static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { |
@@ -122,7 +143,7 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { | |||
122 | .iInterface = 0, | 143 | .iInterface = 0, |
123 | }; | 144 | }; |
124 | 145 | ||
125 | static struct usb_endpoint_descriptor uvc_streaming_ep = { | 146 | static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { |
126 | .bLength = USB_DT_ENDPOINT_SIZE, | 147 | .bLength = USB_DT_ENDPOINT_SIZE, |
127 | .bDescriptorType = USB_DT_ENDPOINT, | 148 | .bDescriptorType = USB_DT_ENDPOINT, |
128 | .bEndpointAddress = USB_DIR_IN, | 149 | .bEndpointAddress = USB_DIR_IN, |
@@ -131,15 +152,72 @@ static struct usb_endpoint_descriptor uvc_streaming_ep = { | |||
131 | .bInterval = 1, | 152 | .bInterval = 1, |
132 | }; | 153 | }; |
133 | 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 | |||
134 | static const struct usb_descriptor_header * const uvc_fs_streaming[] = { | 205 | static const struct usb_descriptor_header * const uvc_fs_streaming[] = { |
135 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, | 206 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, |
136 | (struct usb_descriptor_header *) &uvc_streaming_ep, | 207 | (struct usb_descriptor_header *) &uvc_fs_streaming_ep, |
137 | NULL, | 208 | NULL, |
138 | }; | 209 | }; |
139 | 210 | ||
140 | static const struct usb_descriptor_header * const uvc_hs_streaming[] = { | 211 | static const struct usb_descriptor_header * const uvc_hs_streaming[] = { |
141 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, | 212 | (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, |
142 | (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, | ||
143 | NULL, | 221 | NULL, |
144 | }; | 222 | }; |
145 | 223 | ||
@@ -215,6 +293,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | |||
215 | struct uvc_device *uvc = to_uvc(f); | 293 | struct uvc_device *uvc = to_uvc(f); |
216 | struct v4l2_event v4l2_event; | 294 | struct v4l2_event v4l2_event; |
217 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; | 295 | struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; |
296 | int ret; | ||
218 | 297 | ||
219 | 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); |
220 | 299 | ||
@@ -262,7 +341,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) | |||
262 | return 0; | 341 | return 0; |
263 | 342 | ||
264 | if (uvc->video.ep) { | 343 | if (uvc->video.ep) { |
265 | 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; | ||
266 | usb_ep_enable(uvc->video.ep); | 348 | usb_ep_enable(uvc->video.ep); |
267 | } | 349 | } |
268 | 350 | ||
@@ -368,9 +450,11 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
368 | { | 450 | { |
369 | struct uvc_input_header_descriptor *uvc_streaming_header; | 451 | struct uvc_input_header_descriptor *uvc_streaming_header; |
370 | 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; | ||
371 | const struct uvc_descriptor_header * const *uvc_streaming_cls; | 454 | const struct uvc_descriptor_header * const *uvc_streaming_cls; |
372 | const struct usb_descriptor_header * const *uvc_streaming_std; | 455 | const struct usb_descriptor_header * const *uvc_streaming_std; |
373 | const struct usb_descriptor_header * const *src; | 456 | const struct usb_descriptor_header * const *src; |
457 | static struct usb_endpoint_descriptor *uvc_control_ep; | ||
374 | struct usb_descriptor_header **dst; | 458 | struct usb_descriptor_header **dst; |
375 | struct usb_descriptor_header **hdr; | 459 | struct usb_descriptor_header **hdr; |
376 | unsigned int control_size; | 460 | unsigned int control_size; |
@@ -379,10 +463,29 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
379 | unsigned int bytes; | 463 | unsigned int bytes; |
380 | void *mem; | 464 | void *mem; |
381 | 465 | ||
382 | uvc_streaming_cls = (speed == USB_SPEED_FULL) | 466 | switch (speed) { |
383 | ? uvc->desc.fs_streaming : uvc->desc.hs_streaming; | 467 | case USB_SPEED_SUPER: |
384 | uvc_streaming_std = (speed == USB_SPEED_FULL) | 468 | uvc_control_desc = uvc->desc.ss_control; |
385 | ? 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 | } | ||
386 | 489 | ||
387 | /* Descriptors layout | 490 | /* Descriptors layout |
388 | * | 491 | * |
@@ -400,16 +503,24 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
400 | control_size = 0; | 503 | control_size = 0; |
401 | streaming_size = 0; | 504 | streaming_size = 0; |
402 | bytes = uvc_iad.bLength + uvc_control_intf.bLength | 505 | bytes = uvc_iad.bLength + uvc_control_intf.bLength |
403 | + uvc_control_ep.bLength + uvc_control_cs_ep.bLength | 506 | + uvc_control_ep->bLength + uvc_control_cs_ep.bLength |
404 | + uvc_streaming_intf_alt0.bLength; | 507 | + uvc_streaming_intf_alt0.bLength; |
405 | n_desc = 5; | ||
406 | 508 | ||
407 | 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) { | ||
408 | control_size += (*src)->bLength; | 518 | control_size += (*src)->bLength; |
409 | bytes += (*src)->bLength; | 519 | bytes += (*src)->bLength; |
410 | n_desc++; | 520 | n_desc++; |
411 | } | 521 | } |
412 | 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) { | ||
413 | streaming_size += (*src)->bLength; | 524 | streaming_size += (*src)->bLength; |
414 | bytes += (*src)->bLength; | 525 | bytes += (*src)->bLength; |
415 | n_desc++; | 526 | n_desc++; |
@@ -433,12 +544,15 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
433 | 544 | ||
434 | uvc_control_header = mem; | 545 | uvc_control_header = mem; |
435 | UVC_COPY_DESCRIPTORS(mem, dst, | 546 | UVC_COPY_DESCRIPTORS(mem, dst, |
436 | (const struct usb_descriptor_header**)uvc->desc.control); | 547 | (const struct usb_descriptor_header **)uvc_control_desc); |
437 | uvc_control_header->wTotalLength = cpu_to_le16(control_size); | 548 | uvc_control_header->wTotalLength = cpu_to_le16(control_size); |
438 | uvc_control_header->bInCollection = 1; | 549 | uvc_control_header->bInCollection = 1; |
439 | uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; | 550 | uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; |
440 | 551 | ||
441 | 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 | |||
442 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); | 556 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); |
443 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); | 557 | UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); |
444 | 558 | ||
@@ -446,7 +560,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) | |||
446 | UVC_COPY_DESCRIPTORS(mem, dst, | 560 | UVC_COPY_DESCRIPTORS(mem, dst, |
447 | (const struct usb_descriptor_header**)uvc_streaming_cls); | 561 | (const struct usb_descriptor_header**)uvc_streaming_cls); |
448 | uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); | 562 | uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); |
449 | uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress; | 563 | uvc_streaming_header->bEndpointAddress = |
564 | uvc_fs_streaming_ep.bEndpointAddress; | ||
450 | 565 | ||
451 | UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); | 566 | UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); |
452 | 567 | ||
@@ -482,6 +597,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) | |||
482 | 597 | ||
483 | kfree(f->descriptors); | 598 | kfree(f->descriptors); |
484 | kfree(f->hs_descriptors); | 599 | kfree(f->hs_descriptors); |
600 | kfree(f->ss_descriptors); | ||
485 | 601 | ||
486 | kfree(uvc); | 602 | kfree(uvc); |
487 | } | 603 | } |
@@ -496,8 +612,26 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
496 | 612 | ||
497 | INFO(cdev, "uvc_function_bind\n"); | 613 | INFO(cdev, "uvc_function_bind\n"); |
498 | 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 | |||
499 | /* Allocate endpoints. */ | 633 | /* Allocate endpoints. */ |
500 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); | 634 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep); |
501 | if (!ep) { | 635 | if (!ep) { |
502 | INFO(cdev, "Unable to allocate control EP\n"); | 636 | INFO(cdev, "Unable to allocate control EP\n"); |
503 | goto error; | 637 | goto error; |
@@ -505,7 +639,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
505 | uvc->control_ep = ep; | 639 | uvc->control_ep = ep; |
506 | ep->driver_data = uvc; | 640 | ep->driver_data = uvc; |
507 | 641 | ||
508 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep); | 642 | ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); |
509 | if (!ep) { | 643 | if (!ep) { |
510 | INFO(cdev, "Unable to allocate streaming EP\n"); | 644 | INFO(cdev, "Unable to allocate streaming EP\n"); |
511 | goto error; | 645 | goto error; |
@@ -526,9 +660,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) | |||
526 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; | 660 | uvc_streaming_intf_alt1.bInterfaceNumber = ret; |
527 | uvc->streaming_intf = ret; | 661 | uvc->streaming_intf = ret; |
528 | 662 | ||
529 | /* 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. */ | ||
530 | f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); | 668 | f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); |
531 | 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 | } | ||
532 | 709 | ||
533 | /* Preallocate control endpoint request. */ | 710 | /* Preallocate control endpoint request. */ |
534 | 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); |
@@ -583,9 +760,11 @@ error: | |||
583 | */ | 760 | */ |
584 | int __init | 761 | int __init |
585 | uvc_bind_config(struct usb_configuration *c, | 762 | uvc_bind_config(struct usb_configuration *c, |
586 | 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, | ||
587 | const struct uvc_descriptor_header * const *fs_streaming, | 765 | const struct uvc_descriptor_header * const *fs_streaming, |
588 | 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) | ||
589 | { | 768 | { |
590 | struct uvc_device *uvc; | 769 | struct uvc_device *uvc; |
591 | int ret = 0; | 770 | int ret = 0; |
@@ -603,38 +782,54 @@ uvc_bind_config(struct usb_configuration *c, | |||
603 | uvc->state = UVC_STATE_DISCONNECTED; | 782 | uvc->state = UVC_STATE_DISCONNECTED; |
604 | 783 | ||
605 | /* Validate the descriptors. */ | 784 | /* Validate the descriptors. */ |
606 | if (control == NULL || control[0] == NULL || | 785 | if (fs_control == NULL || fs_control[0] == NULL || |
607 | control[0]->bDescriptorSubType != UVC_VC_HEADER) | 786 | fs_control[0]->bDescriptorSubType != UVC_VC_HEADER) |
608 | goto error; | 787 | goto error; |
609 | 788 | ||
610 | if (fs_streaming == NULL || fs_streaming[0] == NULL || | 789 | if (ss_control == NULL || ss_control[0] == NULL || |
611 | fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) | 790 | ss_control[0]->bDescriptorSubType != UVC_VC_HEADER) |
612 | goto error; | 791 | goto error; |
613 | 792 | ||
614 | if (hs_streaming == NULL || hs_streaming[0] == NULL || | 793 | if (fs_streaming == NULL || fs_streaming[0] == NULL || |
615 | hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) | 794 | fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) |
616 | goto error; | 795 | goto error; |
617 | 796 | ||
618 | uvc->desc.control = control; | 797 | if (hs_streaming == NULL || hs_streaming[0] == NULL || |
619 | uvc->desc.fs_streaming = fs_streaming; | 798 | hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) |
620 | uvc->desc.hs_streaming = hs_streaming; | ||
621 | |||
622 | /* Allocate string descriptor numbers. */ | ||
623 | if ((ret = usb_string_id(c->cdev)) < 0) | ||
624 | goto error; | 799 | goto error; |
625 | uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; | ||
626 | uvc_iad.iFunction = ret; | ||
627 | 800 | ||
628 | if ((ret = usb_string_id(c->cdev)) < 0) | 801 | if (ss_streaming == NULL || ss_streaming[0] == NULL || |
802 | ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) | ||
629 | goto error; | 803 | goto error; |
630 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; | ||
631 | uvc_control_intf.iInterface = ret; | ||
632 | 804 | ||
633 | if ((ret = usb_string_id(c->cdev)) < 0) | 805 | uvc->desc.fs_control = fs_control; |
634 | goto error; | 806 | uvc->desc.ss_control = ss_control; |
635 | uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; | 807 | uvc->desc.fs_streaming = fs_streaming; |
636 | uvc_streaming_intf_alt0.iInterface = ret; | 808 | uvc->desc.hs_streaming = hs_streaming; |
637 | uvc_streaming_intf_alt1.iInterface = ret; | 809 | uvc->desc.ss_streaming = ss_streaming; |
810 | |||
811 | /* maybe allocate device-global string IDs, and patch descriptors */ | ||
812 | if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { | ||
813 | /* Allocate string descriptor numbers. */ | ||
814 | ret = usb_string_id(c->cdev); | ||
815 | if (ret < 0) | ||
816 | goto error; | ||
817 | uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; | ||
818 | uvc_iad.iFunction = ret; | ||
819 | |||
820 | ret = usb_string_id(c->cdev); | ||
821 | if (ret < 0) | ||
822 | goto error; | ||
823 | uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; | ||
824 | uvc_control_intf.iInterface = ret; | ||
825 | |||
826 | ret = usb_string_id(c->cdev); | ||
827 | if (ret < 0) | ||
828 | goto error; | ||
829 | uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; | ||
830 | uvc_streaming_intf_alt0.iInterface = ret; | ||
831 | uvc_streaming_intf_alt1.iInterface = ret; | ||
832 | } | ||
638 | 833 | ||
639 | /* Register the function. */ | 834 | /* Register the function. */ |
640 | uvc->func.name = "uvc"; | 835 | uvc->func.name = "uvc"; |