From patchwork Thu Jun 21 15:22:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eugeniu Rosca X-Patchwork-Id: 10480073 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 15934604D3 for ; Thu, 21 Jun 2018 15:35:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0254D27FA3 for ; Thu, 21 Jun 2018 15:35:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EAD92285F0; Thu, 21 Jun 2018 15:35:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 183CD27FA3 for ; Thu, 21 Jun 2018 15:35:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933277AbeFUPfC (ORCPT ); Thu, 21 Jun 2018 11:35:02 -0400 Received: from smtp1.de.adit-jv.com ([62.225.105.245]:52191 "EHLO smtp1.de.adit-jv.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933269AbeFUPe7 (ORCPT ); Thu, 21 Jun 2018 11:34:59 -0400 Received: from localhost (smtp1.de.adit-jv.com [127.0.0.1]) by smtp1.de.adit-jv.com (Postfix) with ESMTP id C303B3C09B6; Thu, 21 Jun 2018 17:25:12 +0200 (CEST) Received: from smtp1.de.adit-jv.com ([127.0.0.1]) by localhost (smtp1.de.adit-jv.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EDvrbOkYqU-J; Thu, 21 Jun 2018 17:25:05 +0200 (CEST) Received: from HI2EXCH01.adit-jv.com (hi2exch01.adit-jv.com [10.72.92.24]) (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp1.de.adit-jv.com (Postfix) with ESMTPS id 75A603C09B2; Thu, 21 Jun 2018 17:25:05 +0200 (CEST) Received: from vmlxhi-102.adit-jv.com (10.72.93.184) by HI2EXCH01.adit-jv.com (10.72.92.24) with Microsoft SMTP Server (TLS) id 14.3.399.0; Thu, 21 Jun 2018 17:25:04 +0200 From: Eugeniu Rosca To: Felipe Balbi , Felipe Balbi , Ruslan Bilovol , Jassi Brar CC: Andrzej Pietrasiewicz , Daniel Mack , Robert Baldyga , Peter Chen , Christoph Hellwig , Eugeniu Rosca , Eugeniu Rosca , Vladimir Zapolskiy , Joshua Frkuska , , Andreas Pape Subject: [PATCH 6/7] usb: gadget: f_uac2: disable IN/OUT ep if unused Date: Thu, 21 Jun 2018 17:22:51 +0200 Message-ID: <20180621152252.8313-7-erosca@de.adit-jv.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180621152252.8313-1-erosca@de.adit-jv.com> References: <20180621152252.8313-1-erosca@de.adit-jv.com> MIME-Version: 1.0 X-Originating-IP: [10.72.93.184] Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andreas Pape 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 Signed-off-by: Eugeniu Rosca --- drivers/usb/gadget/function/f_uac2.c | 216 +++++++++++++++++++++------ 1 file changed, 172 insertions(+), 44 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 6954db22c2f3..87fa6f14efcf 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -22,12 +22,8 @@ * controlled by two clock sources : * CLK_5 := c_srate, and CLK_6 := p_srate */ -#define USB_OUT_IT_ID 1 -#define IO_IN_IT_ID 2 -#define IO_OUT_OT_ID 3 -#define USB_IN_OT_ID 4 -#define USB_OUT_CLK_ID 5 -#define USB_IN_CLK_ID 6 +#define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) +#define USB_IN_CLK_ID (in_clk_src_desc.bClockID) #define CONTROL_ABSENT 0 #define CONTROL_RDONLY 1 @@ -43,6 +39,9 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 +#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) +#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) + struct f_uac2 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; @@ -135,7 +134,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, - .bClockID = USB_IN_CLK_ID, + /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), .bAssocTerminal = 0, @@ -147,7 +146,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC2_CLOCK_SOURCE, - .bClockID = USB_OUT_CLK_ID, + /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), .bAssocTerminal = 0, @@ -159,10 +158,10 @@ static struct uac2_input_terminal_descriptor usb_out_it_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = USB_OUT_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .bCSourceID = USB_OUT_CLK_ID, + /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -173,10 +172,10 @@ static struct uac2_input_terminal_descriptor io_in_it_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = IO_IN_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED), .bAssocTerminal = 0, - .bCSourceID = USB_IN_CLK_ID, + /* .bCSourceID = DYNAMIC */ .iChannelNames = 0, .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -187,11 +186,11 @@ static struct uac2_output_terminal_descriptor usb_in_ot_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = USB_IN_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .bSourceID = IO_IN_IT_ID, - .bCSourceID = USB_IN_CLK_ID, + /* .bSourceID = DYNAMIC */ + /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -201,11 +200,11 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = IO_OUT_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED), .bAssocTerminal = 0, - .bSourceID = USB_OUT_IT_ID, - .bCSourceID = USB_OUT_CLK_ID, + /* .bSourceID = DYNAMIC */ + /* .bCSourceID = DYNAMIC */ .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; @@ -253,7 +252,7 @@ static struct uac2_as_header_descriptor as_out_hdr_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_OUT_IT_ID, + /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), @@ -330,7 +329,7 @@ static struct uac2_as_header_descriptor as_in_hdr_desc = { .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_IN_OT_ID, + /* .bTerminalLink = DYNAMIC */ .bmControls = 0, .bFormatType = UAC_FORMAT_TYPE_I, .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), @@ -471,6 +470,125 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, le16_to_cpu(ep_desc->wMaxPacketSize))); } +/* Use macro to overcome line length limitation */ +#define USBDHDR(p) (struct usb_descriptor_header *)(p) + +static void setup_descriptor(struct f_uac2_opts *opts) +{ + /* patch descriptors */ + int i = 1; /* ID's start with 1 */ + + if (EPOUT_EN(opts)) + usb_out_it_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + io_in_it_desc.bTerminalID = i++; + if (EPOUT_EN(opts)) + io_out_ot_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + usb_in_ot_desc.bTerminalID = i++; + if (EPOUT_EN(opts)) + out_clk_src_desc.bClockID = i++; + if (EPIN_EN(opts)) + in_clk_src_desc.bClockID = i++; + + usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; + io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; + io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; + as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; + + iad_desc.bInterfaceCount = 1; + ac_hdr_desc.wTotalLength = 0; + + if (EPIN_EN(opts)) { + u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); + + len += sizeof(in_clk_src_desc); + len += sizeof(usb_in_ot_desc); + len += sizeof(io_in_it_desc); + ac_hdr_desc.wTotalLength = cpu_to_le16(len); + iad_desc.bInterfaceCount++; + } + if (EPOUT_EN(opts)) { + u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); + + len += sizeof(out_clk_src_desc); + len += sizeof(usb_out_it_desc); + len += sizeof(io_out_ot_desc); + ac_hdr_desc.wTotalLength = cpu_to_le16(len); + iad_desc.bInterfaceCount++; + } + + i = 0; + fs_audio_desc[i++] = USBDHDR(&iad_desc); + fs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); + fs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); + if (EPIN_EN(opts)) + fs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); + if (EPOUT_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); + fs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + } + if (EPIN_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&io_in_it_desc); + fs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + } + if (EPOUT_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + fs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); + fs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); + fs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); + fs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); + fs_audio_desc[i++] = USBDHDR(&fs_epout_desc); + fs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + fs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); + fs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); + fs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); + fs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); + fs_audio_desc[i++] = USBDHDR(&fs_epin_desc); + fs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + fs_audio_desc[i] = NULL; + + i = 0; + hs_audio_desc[i++] = USBDHDR(&iad_desc); + hs_audio_desc[i++] = USBDHDR(&std_ac_if_desc); + hs_audio_desc[i++] = USBDHDR(&ac_hdr_desc); + if (EPIN_EN(opts)) + hs_audio_desc[i++] = USBDHDR(&in_clk_src_desc); + if (EPOUT_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&out_clk_src_desc); + hs_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + } + if (EPIN_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&io_in_it_desc); + hs_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + } + if (EPOUT_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + hs_audio_desc[i++] = USBDHDR(&std_as_out_if0_desc); + hs_audio_desc[i++] = USBDHDR(&std_as_out_if1_desc); + hs_audio_desc[i++] = USBDHDR(&as_out_hdr_desc); + hs_audio_desc[i++] = USBDHDR(&as_out_fmt1_desc); + hs_audio_desc[i++] = USBDHDR(&hs_epout_desc); + hs_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + hs_audio_desc[i++] = USBDHDR(&std_as_in_if0_desc); + hs_audio_desc[i++] = USBDHDR(&std_as_in_if1_desc); + hs_audio_desc[i++] = USBDHDR(&as_in_hdr_desc); + hs_audio_desc[i++] = USBDHDR(&as_in_fmt1_desc); + hs_audio_desc[i++] = USBDHDR(&hs_epin_desc); + hs_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + hs_audio_desc[i] = NULL; +} + static int afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) { @@ -530,25 +648,29 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) uac2->ac_intf = ret; uac2->ac_alt = 0; - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + if (EPOUT_EN(uac2_opts)) { + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } + std_as_out_if0_desc.bInterfaceNumber = ret; + std_as_out_if1_desc.bInterfaceNumber = ret; + uac2->as_out_intf = ret; + uac2->as_out_alt = 0; } - std_as_out_if0_desc.bInterfaceNumber = ret; - std_as_out_if1_desc.bInterfaceNumber = ret; - uac2->as_out_intf = ret; - uac2->as_out_alt = 0; - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + if (EPIN_EN(uac2_opts)) { + ret = usb_interface_id(cfg, fn); + if (ret < 0) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return ret; + } + std_as_in_if0_desc.bInterfaceNumber = ret; + std_as_in_if1_desc.bInterfaceNumber = ret; + uac2->as_in_intf = ret; + uac2->as_in_alt = 0; } - std_as_in_if0_desc.bInterfaceNumber = ret; - std_as_in_if1_desc.bInterfaceNumber = ret; - uac2->as_in_intf = ret; - uac2->as_in_alt = 0; /* Calculate wMaxPacketSize according to audio bandwidth */ set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); @@ -556,16 +678,20 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); - agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); - if (!agdev->out_ep) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + if (EPOUT_EN(uac2_opts)) { + agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); + if (!agdev->out_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return -ENODEV; + } } - agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); - if (!agdev->in_ep) { - dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + if (EPIN_EN(uac2_opts)) { + agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); + if (!agdev->in_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + return -ENODEV; + } } agdev->in_ep_maxpsize = max_t(u16, @@ -578,6 +704,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; + setup_descriptor(uac2_opts); + ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL, NULL); if (ret)