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

usb: gadget: f_uac2: disable IN/OUT ep if unused

Via p_chmask/c_chmask the user can define whether uac2 shall support
playback and/or capture. This has only effect on the created ALSA device,
but not on the USB descriptor. This patch adds playback/capture descriptors
dependent on that parameter.

Signed-off-by: Andreas Pape <apape@de.adit-jv.com>
Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>

authored by

Andreas Pape and committed by
Felipe Balbi
3fa4eaa6 0a55187a

+172 -44
+172 -44
drivers/usb/gadget/function/f_uac2.c
··· 22 22 * controlled by two clock sources : 23 23 * CLK_5 := c_srate, and CLK_6 := p_srate 24 24 */ 25 - #define USB_OUT_IT_ID 1 26 - #define IO_IN_IT_ID 2 27 - #define IO_OUT_OT_ID 3 28 - #define USB_IN_OT_ID 4 29 - #define USB_OUT_CLK_ID 5 30 - #define USB_IN_CLK_ID 6 25 + #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) 26 + #define USB_IN_CLK_ID (in_clk_src_desc.bClockID) 31 27 32 28 #define CONTROL_ABSENT 0 33 29 #define CONTROL_RDONLY 1 ··· 38 42 #define CLSTR_CTRL 6 39 43 #define UNFLW_CTRL 8 40 44 #define OVFLW_CTRL 10 45 + 46 + #define EPIN_EN(_opts) ((_opts)->p_chmask != 0) 47 + #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) 41 48 42 49 struct f_uac2 { 43 50 struct g_audio g_audio; ··· 134 135 .bDescriptorType = USB_DT_CS_INTERFACE, 135 136 136 137 .bDescriptorSubtype = UAC2_CLOCK_SOURCE, 137 - .bClockID = USB_IN_CLK_ID, 138 + /* .bClockID = DYNAMIC */ 138 139 .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, 139 140 .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), 140 141 .bAssocTerminal = 0, ··· 146 147 .bDescriptorType = USB_DT_CS_INTERFACE, 147 148 148 149 .bDescriptorSubtype = UAC2_CLOCK_SOURCE, 149 - .bClockID = USB_OUT_CLK_ID, 150 + /* .bClockID = DYNAMIC */ 150 151 .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, 151 152 .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), 152 153 .bAssocTerminal = 0, ··· 158 159 .bDescriptorType = USB_DT_CS_INTERFACE, 159 160 160 161 .bDescriptorSubtype = UAC_INPUT_TERMINAL, 161 - .bTerminalID = USB_OUT_IT_ID, 162 + /* .bTerminalID = DYNAMIC */ 162 163 .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), 163 164 .bAssocTerminal = 0, 164 - .bCSourceID = USB_OUT_CLK_ID, 165 + /* .bCSourceID = DYNAMIC */ 165 166 .iChannelNames = 0, 166 167 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 167 168 }; ··· 172 173 .bDescriptorType = USB_DT_CS_INTERFACE, 173 174 174 175 .bDescriptorSubtype = UAC_INPUT_TERMINAL, 175 - .bTerminalID = IO_IN_IT_ID, 176 + /* .bTerminalID = DYNAMIC */ 176 177 .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED), 177 178 .bAssocTerminal = 0, 178 - .bCSourceID = USB_IN_CLK_ID, 179 + /* .bCSourceID = DYNAMIC */ 179 180 .iChannelNames = 0, 180 181 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 181 182 }; ··· 186 187 .bDescriptorType = USB_DT_CS_INTERFACE, 187 188 188 189 .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 189 - .bTerminalID = USB_IN_OT_ID, 190 + /* .bTerminalID = DYNAMIC */ 190 191 .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), 191 192 .bAssocTerminal = 0, 192 - .bSourceID = IO_IN_IT_ID, 193 - .bCSourceID = USB_IN_CLK_ID, 193 + /* .bSourceID = DYNAMIC */ 194 + /* .bCSourceID = DYNAMIC */ 194 195 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 195 196 }; 196 197 ··· 200 201 .bDescriptorType = USB_DT_CS_INTERFACE, 201 202 202 203 .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 203 - .bTerminalID = IO_OUT_OT_ID, 204 + /* .bTerminalID = DYNAMIC */ 204 205 .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED), 205 206 .bAssocTerminal = 0, 206 - .bSourceID = USB_OUT_IT_ID, 207 - .bCSourceID = USB_OUT_CLK_ID, 207 + /* .bSourceID = DYNAMIC */ 208 + /* .bCSourceID = DYNAMIC */ 208 209 .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), 209 210 }; 210 211 ··· 252 253 .bDescriptorType = USB_DT_CS_INTERFACE, 253 254 254 255 .bDescriptorSubtype = UAC_AS_GENERAL, 255 - .bTerminalLink = USB_OUT_IT_ID, 256 + /* .bTerminalLink = DYNAMIC */ 256 257 .bmControls = 0, 257 258 .bFormatType = UAC_FORMAT_TYPE_I, 258 259 .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), ··· 329 330 .bDescriptorType = USB_DT_CS_INTERFACE, 330 331 331 332 .bDescriptorSubtype = UAC_AS_GENERAL, 332 - .bTerminalLink = USB_IN_OT_ID, 333 + /* .bTerminalLink = DYNAMIC */ 333 334 .bmControls = 0, 334 335 .bFormatType = UAC_FORMAT_TYPE_I, 335 336 .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), ··· 470 471 le16_to_cpu(ep_desc->wMaxPacketSize))); 471 472 } 472 473 474 + /* Use macro to overcome line length limitation */ 475 + #define USBDHDR(p) (struct usb_descriptor_header *)(p) 476 + 477 + static void setup_descriptor(struct f_uac2_opts *opts) 478 + { 479 + /* patch descriptors */ 480 + int i = 1; /* ID's start with 1 */ 481 + 482 + if (EPOUT_EN(opts)) 483 + usb_out_it_desc.bTerminalID = i++; 484 + if (EPIN_EN(opts)) 485 + io_in_it_desc.bTerminalID = i++; 486 + if (EPOUT_EN(opts)) 487 + io_out_ot_desc.bTerminalID = i++; 488 + if (EPIN_EN(opts)) 489 + usb_in_ot_desc.bTerminalID = i++; 490 + if (EPOUT_EN(opts)) 491 + out_clk_src_desc.bClockID = i++; 492 + if (EPIN_EN(opts)) 493 + in_clk_src_desc.bClockID = i++; 494 + 495 + usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; 496 + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; 497 + usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; 498 + io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; 499 + io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; 500 + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; 501 + as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; 502 + as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; 503 + 504 + iad_desc.bInterfaceCount = 1; 505 + ac_hdr_desc.wTotalLength = 0; 506 + 507 + if (EPIN_EN(opts)) { 508 + u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); 509 + 510 + len += sizeof(in_clk_src_desc); 511 + len += sizeof(usb_in_ot_desc); 512 + len += sizeof(io_in_it_desc); 513 + ac_hdr_desc.wTotalLength = cpu_to_le16(len); 514 + iad_desc.bInterfaceCount++; 515 + } 516 + if (EPOUT_EN(opts)) { 517 + u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); 518 + 519 + len += sizeof(out_clk_src_desc); 520 + len += sizeof(usb_out_it_desc); 521 + len += sizeof(io_out_ot_desc); 522 + ac_hdr_desc.wTotalLength = cpu_to_le16(len); 523 + iad_desc.bInterfaceCount++; 524 + } 525 + 526 + i = 0; 527 + fs_audio_desc[i++] = USBDHDR(&iad_desc); 528 + fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); 529 + fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); 530 + if (EPIN_EN(opts)) 531 + fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); 532 + if (EPOUT_EN(opts)) { 533 + fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); 534 + fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); 535 + } 536 + if (EPIN_EN(opts)) { 537 + fs_audio_desc[i++] = USBDHDR(&io_in_it_desc); 538 + fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); 539 + } 540 + if (EPOUT_EN(opts)) { 541 + fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); 542 + fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); 543 + fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); 544 + fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); 545 + fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); 546 + fs_audio_desc[i++] = USBDHDR(&fs_epout_desc); 547 + fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); 548 + } 549 + if (EPIN_EN(opts)) { 550 + fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); 551 + fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); 552 + fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); 553 + fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); 554 + fs_audio_desc[i++] = USBDHDR(&fs_epin_desc); 555 + fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); 556 + } 557 + fs_audio_desc[i] = NULL; 558 + 559 + i = 0; 560 + hs_audio_desc[i++] = USBDHDR(&iad_desc); 561 + hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); 562 + hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); 563 + if (EPIN_EN(opts)) 564 + hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); 565 + if (EPOUT_EN(opts)) { 566 + hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); 567 + hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); 568 + } 569 + if (EPIN_EN(opts)) { 570 + hs_audio_desc[i++] = USBDHDR(&io_in_it_desc); 571 + hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); 572 + } 573 + if (EPOUT_EN(opts)) { 574 + hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); 575 + hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); 576 + hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); 577 + hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); 578 + hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); 579 + hs_audio_desc[i++] = USBDHDR(&hs_epout_desc); 580 + hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); 581 + } 582 + if (EPIN_EN(opts)) { 583 + hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); 584 + hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); 585 + hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); 586 + hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); 587 + hs_audio_desc[i++] = USBDHDR(&hs_epin_desc); 588 + hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); 589 + } 590 + hs_audio_desc[i] = NULL; 591 + } 592 + 473 593 static int 474 594 afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) 475 595 { ··· 648 530 uac2->ac_intf = ret; 649 531 uac2->ac_alt = 0; 650 532 651 - ret = usb_interface_id(cfg, fn); 652 - if (ret < 0) { 653 - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 654 - return ret; 533 + if (EPOUT_EN(uac2_opts)) { 534 + ret = usb_interface_id(cfg, fn); 535 + if (ret < 0) { 536 + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 537 + return ret; 538 + } 539 + std_as_out_if0_desc.bInterfaceNumber = ret; 540 + std_as_out_if1_desc.bInterfaceNumber = ret; 541 + uac2->as_out_intf = ret; 542 + uac2->as_out_alt = 0; 655 543 } 656 - std_as_out_if0_desc.bInterfaceNumber = ret; 657 - std_as_out_if1_desc.bInterfaceNumber = ret; 658 - uac2->as_out_intf = ret; 659 - uac2->as_out_alt = 0; 660 544 661 - ret = usb_interface_id(cfg, fn); 662 - if (ret < 0) { 663 - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 664 - return ret; 545 + if (EPIN_EN(uac2_opts)) { 546 + ret = usb_interface_id(cfg, fn); 547 + if (ret < 0) { 548 + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 549 + return ret; 550 + } 551 + std_as_in_if0_desc.bInterfaceNumber = ret; 552 + std_as_in_if1_desc.bInterfaceNumber = ret; 553 + uac2->as_in_intf = ret; 554 + uac2->as_in_alt = 0; 665 555 } 666 - std_as_in_if0_desc.bInterfaceNumber = ret; 667 - std_as_in_if1_desc.bInterfaceNumber = ret; 668 - uac2->as_in_intf = ret; 669 - uac2->as_in_alt = 0; 670 556 671 557 /* Calculate wMaxPacketSize according to audio bandwidth */ 672 558 set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); ··· 678 556 set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); 679 557 set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); 680 558 681 - agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); 682 - if (!agdev->out_ep) { 683 - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 684 - return -ENODEV; 559 + if (EPOUT_EN(uac2_opts)) { 560 + agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); 561 + if (!agdev->out_ep) { 562 + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 563 + return -ENODEV; 564 + } 685 565 } 686 566 687 - agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); 688 - if (!agdev->in_ep) { 689 - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 690 - return -ENODEV; 567 + if (EPIN_EN(uac2_opts)) { 568 + agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); 569 + if (!agdev->in_ep) { 570 + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); 571 + return -ENODEV; 572 + } 691 573 } 692 574 693 575 agdev->in_ep_maxpsize = max_t(u16, ··· 703 577 704 578 hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; 705 579 hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; 580 + 581 + setup_descriptor(uac2_opts); 706 582 707 583 ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, 708 584 NULL);