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

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

User can configure f_uac1 function via p_chmask/c_chmask
whether uac1 shall support playback and/or capture,
but it has only effect on the created ALSA device,
but not on the USB descriptor.

This patch adds playback/capture descriptors
dependent on that parameter. It is similar to
the same conversion done earlier for f_uac2

Signed-off-by: Ruslan Bilovol <ruslan.bilovol@gmail.com>
Link: https://lore.kernel.org/r/1614599375-8803-6-git-send-email-ruslan.bilovol@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ruslan Bilovol and committed by
Greg Kroah-Hartman
254cb1e0 a59c68a6

+163 -66
+163 -66
drivers/usb/gadget/function/f_uac1.c
··· 22 22 /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */ 23 23 #define UAC1_CHANNEL_MASK 0x0FFF 24 24 25 + #define EPIN_EN(_opts) ((_opts)->p_chmask != 0) 26 + #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) 27 + 25 28 struct f_uac1 { 26 29 struct g_audio g_audio; 27 30 u8 ac_intf, as_in_intf, as_out_intf; ··· 53 50 * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture 54 51 * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN 55 52 */ 56 - #define F_AUDIO_AC_INTERFACE 0 57 - #define F_AUDIO_AS_OUT_INTERFACE 1 58 - #define F_AUDIO_AS_IN_INTERFACE 2 59 - /* Number of streaming interfaces */ 60 - #define F_AUDIO_NUM_INTERFACES 2 61 53 62 54 /* B.3.1 Standard AC Interface Descriptor */ 63 55 static struct usb_interface_descriptor ac_interface_desc = { ··· 63 65 .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, 64 66 }; 65 67 66 - /* 67 - * The number of AudioStreaming and MIDIStreaming interfaces 68 - * in the Audio Interface Collection 69 - */ 70 - DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); 71 - 72 - #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) 73 - /* 2 input terminals and 2 output terminals */ 74 - #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ 75 - + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE) 76 68 /* B.3.2 Class-Specific AC Interface Descriptor */ 77 - static struct uac1_ac_header_descriptor_2 ac_header_desc = { 78 - .bLength = UAC_DT_AC_HEADER_LENGTH, 79 - .bDescriptorType = USB_DT_CS_INTERFACE, 80 - .bDescriptorSubtype = UAC_HEADER, 81 - .bcdADC = cpu_to_le16(0x0100), 82 - .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH), 83 - .bInCollection = F_AUDIO_NUM_INTERFACES, 84 - .baInterfaceNr = { 85 - /* Interface number of the AudioStream interfaces */ 86 - [0] = 1, 87 - [1] = 2, 88 - } 89 - }; 69 + static struct uac1_ac_header_descriptor *ac_header_desc; 90 70 91 - #define USB_OUT_IT_ID 1 92 71 static struct uac_input_terminal_descriptor usb_out_it_desc = { 93 72 .bLength = UAC_DT_INPUT_TERMINAL_SIZE, 94 73 .bDescriptorType = USB_DT_CS_INTERFACE, 95 74 .bDescriptorSubtype = UAC_INPUT_TERMINAL, 96 - .bTerminalID = USB_OUT_IT_ID, 75 + /* .bTerminalID = DYNAMIC */ 97 76 .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), 98 77 .bAssocTerminal = 0, 99 78 .wChannelConfig = cpu_to_le16(0x3), 100 79 }; 101 80 102 - #define IO_OUT_OT_ID 2 103 81 static struct uac1_output_terminal_descriptor io_out_ot_desc = { 104 82 .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, 105 83 .bDescriptorType = USB_DT_CS_INTERFACE, 106 84 .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 107 - .bTerminalID = IO_OUT_OT_ID, 85 + /* .bTerminalID = DYNAMIC */ 108 86 .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), 109 87 .bAssocTerminal = 0, 110 - .bSourceID = USB_OUT_IT_ID, 88 + /* .bSourceID = DYNAMIC */ 111 89 }; 112 90 113 - #define IO_IN_IT_ID 3 114 91 static struct uac_input_terminal_descriptor io_in_it_desc = { 115 92 .bLength = UAC_DT_INPUT_TERMINAL_SIZE, 116 93 .bDescriptorType = USB_DT_CS_INTERFACE, 117 94 .bDescriptorSubtype = UAC_INPUT_TERMINAL, 118 - .bTerminalID = IO_IN_IT_ID, 95 + /* .bTerminalID = DYNAMIC */ 119 96 .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), 120 97 .bAssocTerminal = 0, 121 98 .wChannelConfig = cpu_to_le16(0x3), 122 99 }; 123 100 124 - #define USB_IN_OT_ID 4 125 101 static struct uac1_output_terminal_descriptor usb_in_ot_desc = { 126 102 .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, 127 103 .bDescriptorType = USB_DT_CS_INTERFACE, 128 104 .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, 129 - .bTerminalID = USB_IN_OT_ID, 105 + /* .bTerminalID = DYNAMIC */ 130 106 .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), 131 107 .bAssocTerminal = 0, 132 - .bSourceID = IO_IN_IT_ID, 108 + /* .bSourceID = DYNAMIC */ 133 109 }; 134 110 135 111 /* B.4.1 Standard AS Interface Descriptor */ ··· 148 176 .bLength = UAC_DT_AS_HEADER_SIZE, 149 177 .bDescriptorType = USB_DT_CS_INTERFACE, 150 178 .bDescriptorSubtype = UAC_AS_GENERAL, 151 - .bTerminalLink = USB_OUT_IT_ID, 179 + /* .bTerminalLink = DYNAMIC */ 152 180 .bDelay = 1, 153 181 .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), 154 182 }; ··· 157 185 .bLength = UAC_DT_AS_HEADER_SIZE, 158 186 .bDescriptorType = USB_DT_CS_INTERFACE, 159 187 .bDescriptorSubtype = UAC_AS_GENERAL, 160 - .bTerminalLink = USB_IN_OT_ID, 188 + /* .bTerminalLink = DYNAMIC */ 161 189 .bDelay = 1, 162 190 .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), 163 191 }; ··· 485 513 486 514 /*-------------------------------------------------------------------------*/ 487 515 516 + static struct 517 + uac1_ac_header_descriptor *build_ac_header_desc(struct f_uac1_opts *opts) 518 + { 519 + struct uac1_ac_header_descriptor *ac_desc; 520 + int ac_header_desc_size; 521 + int num_ifaces = 0; 522 + 523 + if (EPOUT_EN(opts)) 524 + num_ifaces++; 525 + if (EPIN_EN(opts)) 526 + num_ifaces++; 527 + 528 + ac_header_desc_size = UAC_DT_AC_HEADER_SIZE(num_ifaces); 529 + 530 + ac_desc = kzalloc(ac_header_desc_size, GFP_KERNEL); 531 + if (!ac_desc) 532 + return NULL; 533 + 534 + ac_desc->bLength = ac_header_desc_size; 535 + ac_desc->bDescriptorType = USB_DT_CS_INTERFACE; 536 + ac_desc->bDescriptorSubtype = UAC_HEADER; 537 + ac_desc->bcdADC = cpu_to_le16(0x0100); 538 + ac_desc->bInCollection = num_ifaces; 539 + 540 + /* wTotalLength and baInterfaceNr will be defined later */ 541 + 542 + return ac_desc; 543 + } 544 + 545 + /* Use macro to overcome line length limitation */ 546 + #define USBDHDR(p) (struct usb_descriptor_header *)(p) 547 + 548 + static void setup_descriptor(struct f_uac1_opts *opts) 549 + { 550 + /* patch descriptors */ 551 + int i = 1; /* ID's start with 1 */ 552 + 553 + if (EPOUT_EN(opts)) 554 + usb_out_it_desc.bTerminalID = i++; 555 + if (EPIN_EN(opts)) 556 + io_in_it_desc.bTerminalID = i++; 557 + if (EPOUT_EN(opts)) 558 + io_out_ot_desc.bTerminalID = i++; 559 + if (EPIN_EN(opts)) 560 + usb_in_ot_desc.bTerminalID = i++; 561 + 562 + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; 563 + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; 564 + 565 + as_out_header_desc.bTerminalLink = usb_out_it_desc.bTerminalID; 566 + as_in_header_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; 567 + 568 + ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc->bLength); 569 + 570 + if (EPIN_EN(opts)) { 571 + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); 572 + 573 + len += sizeof(usb_in_ot_desc); 574 + len += sizeof(io_in_it_desc); 575 + ac_header_desc->wTotalLength = cpu_to_le16(len); 576 + } 577 + if (EPOUT_EN(opts)) { 578 + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); 579 + 580 + len += sizeof(usb_out_it_desc); 581 + len += sizeof(io_out_ot_desc); 582 + ac_header_desc->wTotalLength = cpu_to_le16(len); 583 + } 584 + 585 + i = 0; 586 + f_audio_desc[i++] = USBDHDR(&ac_interface_desc); 587 + f_audio_desc[i++] = USBDHDR(ac_header_desc); 588 + 589 + if (EPOUT_EN(opts)) { 590 + f_audio_desc[i++] = USBDHDR(&usb_out_it_desc); 591 + f_audio_desc[i++] = USBDHDR(&io_out_ot_desc); 592 + } 593 + 594 + if (EPIN_EN(opts)) { 595 + f_audio_desc[i++] = USBDHDR(&io_in_it_desc); 596 + f_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); 597 + } 598 + 599 + if (EPOUT_EN(opts)) { 600 + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_0_desc); 601 + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_1_desc); 602 + f_audio_desc[i++] = USBDHDR(&as_out_header_desc); 603 + f_audio_desc[i++] = USBDHDR(&as_out_type_i_desc); 604 + f_audio_desc[i++] = USBDHDR(&as_out_ep_desc); 605 + f_audio_desc[i++] = USBDHDR(&as_iso_out_desc); 606 + } 607 + if (EPIN_EN(opts)) { 608 + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_0_desc); 609 + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_1_desc); 610 + f_audio_desc[i++] = USBDHDR(&as_in_header_desc); 611 + f_audio_desc[i++] = USBDHDR(&as_in_type_i_desc); 612 + f_audio_desc[i++] = USBDHDR(&as_in_ep_desc); 613 + f_audio_desc[i++] = USBDHDR(&as_iso_in_desc); 614 + } 615 + f_audio_desc[i] = NULL; 616 + } 617 + 488 618 static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) 489 619 { 490 620 struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); ··· 630 556 struct usb_string *us; 631 557 u8 *sam_freq; 632 558 int rate; 559 + int ba_iface_id; 633 560 int status; 634 561 635 562 status = f_audio_validate_opts(audio, dev); ··· 642 567 us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); 643 568 if (IS_ERR(us)) 644 569 return PTR_ERR(us); 570 + 571 + ac_header_desc = build_ac_header_desc(audio_opts); 572 + if (!ac_header_desc) 573 + return -ENOMEM; 574 + 645 575 ac_interface_desc.iInterface = us[STR_AC_IF].id; 646 576 usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id; 647 577 usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id; ··· 687 607 uac1->ac_intf = status; 688 608 uac1->ac_alt = 0; 689 609 690 - status = usb_interface_id(c, f); 691 - if (status < 0) 692 - goto fail; 693 - as_out_interface_alt_0_desc.bInterfaceNumber = status; 694 - as_out_interface_alt_1_desc.bInterfaceNumber = status; 695 - ac_header_desc.baInterfaceNr[0] = status; 696 - uac1->as_out_intf = status; 697 - uac1->as_out_alt = 0; 610 + ba_iface_id = 0; 698 611 699 - status = usb_interface_id(c, f); 700 - if (status < 0) 701 - goto fail; 702 - as_in_interface_alt_0_desc.bInterfaceNumber = status; 703 - as_in_interface_alt_1_desc.bInterfaceNumber = status; 704 - ac_header_desc.baInterfaceNr[1] = status; 705 - uac1->as_in_intf = status; 706 - uac1->as_in_alt = 0; 612 + if (EPOUT_EN(audio_opts)) { 613 + status = usb_interface_id(c, f); 614 + if (status < 0) 615 + goto fail; 616 + as_out_interface_alt_0_desc.bInterfaceNumber = status; 617 + as_out_interface_alt_1_desc.bInterfaceNumber = status; 618 + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; 619 + uac1->as_out_intf = status; 620 + uac1->as_out_alt = 0; 621 + } 622 + 623 + if (EPIN_EN(audio_opts)) { 624 + status = usb_interface_id(c, f); 625 + if (status < 0) 626 + goto fail; 627 + as_in_interface_alt_0_desc.bInterfaceNumber = status; 628 + as_in_interface_alt_1_desc.bInterfaceNumber = status; 629 + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; 630 + uac1->as_in_intf = status; 631 + uac1->as_in_alt = 0; 632 + } 707 633 708 634 audio->gadget = gadget; 709 635 710 636 status = -ENODEV; 711 637 712 638 /* allocate instance-specific endpoints */ 713 - ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); 714 - if (!ep) 715 - goto fail; 716 - audio->out_ep = ep; 717 - audio->out_ep->desc = &as_out_ep_desc; 639 + if (EPOUT_EN(audio_opts)) { 640 + ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); 641 + if (!ep) 642 + goto fail; 643 + audio->out_ep = ep; 644 + audio->out_ep->desc = &as_out_ep_desc; 645 + } 718 646 719 - ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); 720 - if (!ep) 721 - goto fail; 722 - audio->in_ep = ep; 723 - audio->in_ep->desc = &as_in_ep_desc; 647 + if (EPIN_EN(audio_opts)) { 648 + ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); 649 + if (!ep) 650 + goto fail; 651 + audio->in_ep = ep; 652 + audio->in_ep->desc = &as_in_ep_desc; 653 + } 654 + 655 + setup_descriptor(audio_opts); 724 656 725 657 /* copy descriptors, and track endpoint copies */ 726 658 status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, ··· 759 667 err_card_register: 760 668 usb_free_all_descriptors(f); 761 669 fail: 670 + kfree(ac_header_desc); 671 + ac_header_desc = NULL; 762 672 return status; 763 673 } 764 674 ··· 902 808 903 809 g_audio_cleanup(audio); 904 810 usb_free_all_descriptors(f); 811 + 812 + kfree(ac_header_desc); 813 + ac_header_desc = NULL; 905 814 906 815 audio->gadget = NULL; 907 816 }