Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Bhupesh Sharma and committed by
Felipe Balbi
fbcaba0e 57976636

+247 -35
+214 -27
drivers/usb/gadget/f_uvc.c
··· 29 29 30 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 52 * Function descriptors 34 53 */ ··· 103 84 .iInterface = 0, 104 85 }; 105 86 106 - static struct usb_endpoint_descriptor uvc_control_ep __initdata = { 87 + static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { 107 88 .bLength = USB_DT_ENDPOINT_SIZE, 108 89 .bDescriptorType = USB_DT_ENDPOINT, 109 90 .bEndpointAddress = USB_DIR_IN, ··· 143 124 .iInterface = 0, 144 125 }; 145 126 146 - static struct usb_endpoint_descriptor uvc_streaming_ep = { 127 + static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { 147 128 .bLength = USB_DT_ENDPOINT_SIZE, 148 129 .bDescriptorType = USB_DT_ENDPOINT, 149 130 .bEndpointAddress = USB_DIR_IN, ··· 152 133 .bInterval = 1, 153 134 }; 154 135 136 + static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { 137 + .bLength = USB_DT_ENDPOINT_SIZE, 138 + .bDescriptorType = USB_DT_ENDPOINT, 139 + .bEndpointAddress = USB_DIR_IN, 140 + .bmAttributes = USB_ENDPOINT_XFER_ISOC, 141 + .wMaxPacketSize = cpu_to_le16(1024), 142 + .bInterval = 1, 143 + }; 144 + 145 + /* super speed support */ 146 + static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { 147 + .bLength = USB_DT_ENDPOINT_SIZE, 148 + .bDescriptorType = USB_DT_ENDPOINT, 149 + 150 + .bEndpointAddress = USB_DIR_IN, 151 + .bmAttributes = USB_ENDPOINT_XFER_INT, 152 + .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), 153 + .bInterval = 8, 154 + }; 155 + 156 + static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = { 157 + .bLength = sizeof uvc_ss_control_comp, 158 + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 159 + 160 + /* the following 3 values can be tweaked if necessary */ 161 + /* .bMaxBurst = 0, */ 162 + /* .bmAttributes = 0, */ 163 + .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT), 164 + }; 165 + 166 + static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = { 167 + .bLength = USB_DT_ENDPOINT_SIZE, 168 + .bDescriptorType = USB_DT_ENDPOINT, 169 + 170 + .bEndpointAddress = USB_DIR_IN, 171 + .bmAttributes = USB_ENDPOINT_XFER_ISOC, 172 + .wMaxPacketSize = cpu_to_le16(1024), 173 + .bInterval = 4, 174 + }; 175 + 176 + static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { 177 + .bLength = sizeof uvc_ss_streaming_comp, 178 + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 179 + 180 + /* the following 3 values can be tweaked if necessary */ 181 + .bMaxBurst = 0, 182 + .bmAttributes = 0, 183 + .wBytesPerInterval = cpu_to_le16(1024), 184 + }; 185 + 155 186 static const struct usb_descriptor_header * const uvc_fs_streaming[] = { 156 187 (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, 157 - (struct usb_descriptor_header *) &uvc_streaming_ep, 188 + (struct usb_descriptor_header *) &uvc_fs_streaming_ep, 158 189 NULL, 159 190 }; 160 191 161 192 static const struct usb_descriptor_header * const uvc_hs_streaming[] = { 162 193 (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, 163 - (struct usb_descriptor_header *) &uvc_streaming_ep, 194 + (struct usb_descriptor_header *) &uvc_hs_streaming_ep, 195 + NULL, 196 + }; 197 + 198 + static const struct usb_descriptor_header * const uvc_ss_streaming[] = { 199 + (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, 200 + (struct usb_descriptor_header *) &uvc_ss_streaming_ep, 201 + (struct usb_descriptor_header *) &uvc_ss_streaming_comp, 164 202 NULL, 165 203 }; 166 204 ··· 293 217 struct uvc_device *uvc = to_uvc(f); 294 218 struct v4l2_event v4l2_event; 295 219 struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; 220 + int ret; 296 221 297 222 INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); 298 223 ··· 341 264 return 0; 342 265 343 266 if (uvc->video.ep) { 344 - uvc->video.ep->desc = &uvc_streaming_ep; 267 + ret = config_ep_by_speed(f->config->cdev->gadget, 268 + &(uvc->func), uvc->video.ep); 269 + if (ret) 270 + return ret; 345 271 usb_ep_enable(uvc->video.ep); 346 272 } 347 273 ··· 450 370 { 451 371 struct uvc_input_header_descriptor *uvc_streaming_header; 452 372 struct uvc_header_descriptor *uvc_control_header; 373 + const struct uvc_descriptor_header * const *uvc_control_desc; 453 374 const struct uvc_descriptor_header * const *uvc_streaming_cls; 454 375 const struct usb_descriptor_header * const *uvc_streaming_std; 455 376 const struct usb_descriptor_header * const *src; 377 + static struct usb_endpoint_descriptor *uvc_control_ep; 456 378 struct usb_descriptor_header **dst; 457 379 struct usb_descriptor_header **hdr; 458 380 unsigned int control_size; ··· 463 381 unsigned int bytes; 464 382 void *mem; 465 383 466 - uvc_streaming_cls = (speed == USB_SPEED_FULL) 467 - ? uvc->desc.fs_streaming : uvc->desc.hs_streaming; 468 - uvc_streaming_std = (speed == USB_SPEED_FULL) 469 - ? uvc_fs_streaming : uvc_hs_streaming; 384 + switch (speed) { 385 + case USB_SPEED_SUPER: 386 + uvc_control_desc = uvc->desc.ss_control; 387 + uvc_streaming_cls = uvc->desc.ss_streaming; 388 + uvc_streaming_std = uvc_ss_streaming; 389 + uvc_control_ep = &uvc_ss_control_ep; 390 + break; 391 + 392 + case USB_SPEED_HIGH: 393 + uvc_control_desc = uvc->desc.fs_control; 394 + uvc_streaming_cls = uvc->desc.hs_streaming; 395 + uvc_streaming_std = uvc_hs_streaming; 396 + uvc_control_ep = &uvc_fs_control_ep; 397 + break; 398 + 399 + case USB_SPEED_FULL: 400 + default: 401 + uvc_control_desc = uvc->desc.fs_control; 402 + uvc_streaming_cls = uvc->desc.fs_streaming; 403 + uvc_streaming_std = uvc_fs_streaming; 404 + uvc_control_ep = &uvc_fs_control_ep; 405 + break; 406 + } 470 407 471 408 /* Descriptors layout 472 409 * ··· 503 402 control_size = 0; 504 403 streaming_size = 0; 505 404 bytes = uvc_iad.bLength + uvc_control_intf.bLength 506 - + uvc_control_ep.bLength + uvc_control_cs_ep.bLength 405 + + uvc_control_ep->bLength + uvc_control_cs_ep.bLength 507 406 + uvc_streaming_intf_alt0.bLength; 508 - n_desc = 5; 509 407 510 - for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) { 408 + if (speed == USB_SPEED_SUPER) { 409 + bytes += uvc_ss_control_comp.bLength; 410 + n_desc = 6; 411 + } else { 412 + n_desc = 5; 413 + } 414 + 415 + for (src = (const struct usb_descriptor_header **)uvc_control_desc; 416 + *src; ++src) { 511 417 control_size += (*src)->bLength; 512 418 bytes += (*src)->bLength; 513 419 n_desc++; 514 420 } 515 - for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) { 421 + for (src = (const struct usb_descriptor_header **)uvc_streaming_cls; 422 + *src; ++src) { 516 423 streaming_size += (*src)->bLength; 517 424 bytes += (*src)->bLength; 518 425 n_desc++; ··· 544 435 545 436 uvc_control_header = mem; 546 437 UVC_COPY_DESCRIPTORS(mem, dst, 547 - (const struct usb_descriptor_header**)uvc->desc.control); 438 + (const struct usb_descriptor_header **)uvc_control_desc); 548 439 uvc_control_header->wTotalLength = cpu_to_le16(control_size); 549 440 uvc_control_header->bInCollection = 1; 550 441 uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; 551 442 552 - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep); 443 + UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep); 444 + if (speed == USB_SPEED_SUPER) 445 + UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp); 446 + 553 447 UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); 554 448 UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); 555 449 ··· 560 448 UVC_COPY_DESCRIPTORS(mem, dst, 561 449 (const struct usb_descriptor_header**)uvc_streaming_cls); 562 450 uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); 563 - uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress; 451 + uvc_streaming_header->bEndpointAddress = 452 + uvc_fs_streaming_ep.bEndpointAddress; 564 453 565 454 UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); 566 455 ··· 597 484 598 485 kfree(f->descriptors); 599 486 kfree(f->hs_descriptors); 487 + kfree(f->ss_descriptors); 600 488 601 489 kfree(uvc); 602 490 } ··· 612 498 613 499 INFO(cdev, "uvc_function_bind\n"); 614 500 501 + /* sanity check the streaming endpoint module parameters */ 502 + if (streaming_interval < 1) 503 + streaming_interval = 1; 504 + if (streaming_interval > 16) 505 + streaming_interval = 16; 506 + if (streaming_mult > 2) 507 + streaming_mult = 2; 508 + if (streaming_maxburst > 15) 509 + streaming_maxburst = 15; 510 + 511 + /* 512 + * fill in the FS video streaming specific descriptors from the 513 + * module parameters 514 + */ 515 + uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ? 516 + 1023 : streaming_maxpacket; 517 + uvc_fs_streaming_ep.bInterval = streaming_interval; 518 + 615 519 /* Allocate endpoints. */ 616 - ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); 520 + ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep); 617 521 if (!ep) { 618 522 INFO(cdev, "Unable to allocate control EP\n"); 619 523 goto error; ··· 639 507 uvc->control_ep = ep; 640 508 ep->driver_data = uvc; 641 509 642 - ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep); 510 + ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); 643 511 if (!ep) { 644 512 INFO(cdev, "Unable to allocate streaming EP\n"); 645 513 goto error; ··· 660 528 uvc_streaming_intf_alt1.bInterfaceNumber = ret; 661 529 uvc->streaming_intf = ret; 662 530 663 - /* Copy descriptors. */ 531 + /* sanity check the streaming endpoint module parameters */ 532 + if (streaming_maxpacket > 1024) 533 + streaming_maxpacket = 1024; 534 + 535 + /* Copy descriptors for FS. */ 664 536 f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); 665 - f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); 537 + 538 + /* support high speed hardware */ 539 + if (gadget_is_dualspeed(cdev->gadget)) { 540 + /* 541 + * Fill in the HS descriptors from the module parameters for the 542 + * Video Streaming endpoint. 543 + * NOTE: We assume that the user knows what they are doing and 544 + * won't give parameters that their UDC doesn't support. 545 + */ 546 + uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket; 547 + uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11; 548 + uvc_hs_streaming_ep.bInterval = streaming_interval; 549 + uvc_hs_streaming_ep.bEndpointAddress = 550 + uvc_fs_streaming_ep.bEndpointAddress; 551 + 552 + /* Copy descriptors. */ 553 + f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); 554 + } 555 + 556 + /* support super speed hardware */ 557 + if (gadget_is_superspeed(c->cdev->gadget)) { 558 + /* 559 + * Fill in the SS descriptors from the module parameters for the 560 + * Video Streaming endpoint. 561 + * NOTE: We assume that the user knows what they are doing and 562 + * won't give parameters that their UDC doesn't support. 563 + */ 564 + uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket; 565 + uvc_ss_streaming_ep.bInterval = streaming_interval; 566 + uvc_ss_streaming_comp.bmAttributes = streaming_mult; 567 + uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; 568 + uvc_ss_streaming_comp.wBytesPerInterval = 569 + streaming_maxpacket * (streaming_mult + 1) * 570 + (streaming_maxburst + 1); 571 + uvc_ss_streaming_ep.bEndpointAddress = 572 + uvc_fs_streaming_ep.bEndpointAddress; 573 + 574 + /* Copy descriptors. */ 575 + f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); 576 + } 666 577 667 578 /* Preallocate control endpoint request. */ 668 579 uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); ··· 760 585 */ 761 586 int __init 762 587 uvc_bind_config(struct usb_configuration *c, 763 - const struct uvc_descriptor_header * const *control, 588 + const struct uvc_descriptor_header * const *fs_control, 589 + const struct uvc_descriptor_header * const *ss_control, 764 590 const struct uvc_descriptor_header * const *fs_streaming, 765 - const struct uvc_descriptor_header * const *hs_streaming) 591 + const struct uvc_descriptor_header * const *hs_streaming, 592 + const struct uvc_descriptor_header * const *ss_streaming) 766 593 { 767 594 struct uvc_device *uvc; 768 595 int ret = 0; ··· 782 605 uvc->state = UVC_STATE_DISCONNECTED; 783 606 784 607 /* Validate the descriptors. */ 785 - if (control == NULL || control[0] == NULL || 786 - control[0]->bDescriptorSubType != UVC_VC_HEADER) 608 + if (fs_control == NULL || fs_control[0] == NULL || 609 + fs_control[0]->bDescriptorSubType != UVC_VC_HEADER) 610 + goto error; 611 + 612 + if (ss_control == NULL || ss_control[0] == NULL || 613 + ss_control[0]->bDescriptorSubType != UVC_VC_HEADER) 787 614 goto error; 788 615 789 616 if (fs_streaming == NULL || fs_streaming[0] == NULL || 790 - fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) 617 + fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) 791 618 goto error; 792 619 793 620 if (hs_streaming == NULL || hs_streaming[0] == NULL || 794 - hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) 621 + hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) 795 622 goto error; 796 623 797 - uvc->desc.control = control; 624 + if (ss_streaming == NULL || ss_streaming[0] == NULL || 625 + ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) 626 + goto error; 627 + 628 + uvc->desc.fs_control = fs_control; 629 + uvc->desc.ss_control = ss_control; 798 630 uvc->desc.fs_streaming = fs_streaming; 799 631 uvc->desc.hs_streaming = hs_streaming; 632 + uvc->desc.ss_streaming = ss_streaming; 800 633 801 634 /* maybe allocate device-global string IDs, and patch descriptors */ 802 635 if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
+5 -3
drivers/usb/gadget/f_uvc.h
··· 17 17 #include <linux/usb/video.h> 18 18 19 19 extern int uvc_bind_config(struct usb_configuration *c, 20 - const struct uvc_descriptor_header * const *control, 21 - const struct uvc_descriptor_header * const *fs_streaming, 22 - const struct uvc_descriptor_header * const *hs_streaming); 20 + const struct uvc_descriptor_header * const *fs_control, 21 + const struct uvc_descriptor_header * const *hs_control, 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 26 #endif /* _F_UVC_H_ */ 25 27
+3 -1
drivers/usb/gadget/uvc.h
··· 153 153 154 154 /* Descriptors */ 155 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 158 const struct uvc_descriptor_header * const *fs_streaming; 158 159 const struct uvc_descriptor_header * const *hs_streaming; 160 + const struct uvc_descriptor_header * const *ss_streaming; 159 161 } desc; 160 162 161 163 unsigned int control_intf;
+25 -4
drivers/usb/gadget/webcam.c
··· 272 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 284 (const struct uvc_descriptor_header *) &uvc_control_header, 277 285 (const struct uvc_descriptor_header *) &uvc_camera_terminal, 278 286 (const struct uvc_descriptor_header *) &uvc_processing, ··· 312 304 NULL, 313 305 }; 314 306 307 + static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = { 308 + (const struct uvc_descriptor_header *) &uvc_input_header, 309 + (const struct uvc_descriptor_header *) &uvc_format_yuv, 310 + (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, 311 + (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, 312 + (const struct uvc_descriptor_header *) &uvc_format_mjpg, 313 + (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, 314 + (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, 315 + (const struct uvc_descriptor_header *) &uvc_color_matching, 316 + NULL, 317 + }; 318 + 315 319 /* -------------------------------------------------------------------------- 316 320 * USB configuration 317 321 */ ··· 331 311 static int __init 332 312 webcam_config_bind(struct usb_configuration *c) 333 313 { 334 - return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls, 335 - uvc_hs_streaming_cls); 314 + return uvc_bind_config(c, uvc_fs_control_cls, uvc_ss_control_cls, 315 + uvc_fs_streaming_cls, uvc_hs_streaming_cls, 316 + uvc_ss_streaming_cls); 336 317 } 337 318 338 319 static struct usb_configuration webcam_config_driver = { ··· 394 373 .name = "g_webcam", 395 374 .dev = &webcam_device_descriptor, 396 375 .strings = webcam_device_strings, 397 - .max_speed = USB_SPEED_HIGH, 376 + .max_speed = USB_SPEED_SUPER, 398 377 .unbind = webcam_unbind, 399 378 }; 400 379