From patchwork Mon Mar 1 11:49:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 390735 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E0113C433E0 for ; Mon, 1 Mar 2021 11:51:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 94EBA64E6B for ; Mon, 1 Mar 2021 11:51:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234374AbhCALvp (ORCPT ); Mon, 1 Mar 2021 06:51:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33636 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234334AbhCALv3 (ORCPT ); Mon, 1 Mar 2021 06:51:29 -0500 Received: from mail-lf1-x12a.google.com (mail-lf1-x12a.google.com [IPv6:2a00:1450:4864:20::12a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 021D0C0617A9; Mon, 1 Mar 2021 03:50:21 -0800 (PST) Received: by mail-lf1-x12a.google.com with SMTP id v5so24966385lft.13; Mon, 01 Mar 2021 03:50:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=kCSnrPgWBKPuGz6BcK3jpWW2wafXy8uYMenYAYQXXAo=; b=ixXnxuODlm2F2/qR4/+z9QOP7DQ2Tv9Y9+M9g3Ly/2uj5LrZUXvMEU0cXAZTtg2aUw +bLH402RiaO1KQ4eW/1Kv8q/cYudmsh/h47IiEKzgW+BzePOV44pvxD5lV9EkRlLnlEQ /NTlBceHzJLbwmqDOTbLJUrI56z+CO/oF99kdd73HJsq+i6ml99ShEHtm4aI9rZWSdas IoU+VF5aBBOVNtoIA9kV5HB3HYjAgAd2IPOk+BKUHcsT3FdqrFCNL9+/knCYcfStpZna 4BlYbOSBBri7nDNXt8YDSeDiyOqJKzQfncczK7UxMzUeixOmmTHNUXrgbZKv8RFxOczN 0auA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=kCSnrPgWBKPuGz6BcK3jpWW2wafXy8uYMenYAYQXXAo=; b=nwYoe4JTtJwhfM8BYWW96tmfUj2CX4qzA3EyQpLPAionhDeSRdh3ZsLF7GNNhYcO3Z ABD8oBLrNVb4x2WXr7P+woR6Q2zsliwhyGcRRltsPyrWMbxBAcm8MiGDV3pPZxhCe68f /5HLOPXa4TJOOp0l0uroe76ULhyiuR1pM7H0taklZPIbnzKMuUp9TdgvzbxEZCa0eSni KHYkKZJiy4WB8epFfBcbYEkVBckBtjFZtSZ7zFknvbPPPluNgqNYRaMKdqty93X/J63B Kk1HAhlA05S39H8JczUe567e/cMAHUaI6AYvcFHcfRX2yWvTwo4c2+iXag/gCJG5HiGu DBPQ== X-Gm-Message-State: AOAM531lxVYlR6LPvSxS0bodiA0hbzY/czRvBqbIhlN2Kn7zBeLGai8w wvZQsB3a1pnhucX1wwV93Ew= X-Google-Smtp-Source: ABdhPJyokDtKQtzOKsb/vCYkQe0nbmlLP3DSQqMH7gBZQQStxdlyXqta4Ik8QM5CqEZ1N2Zax6ZzhA== X-Received: by 2002:ac2:48b1:: with SMTP id u17mr9958917lfg.627.1614599419562; Mon, 01 Mar 2021 03:50:19 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id u3sm2284253lff.225.2021.03.01.03.50.18 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Mon, 01 Mar 2021 03:50:18 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol , Peter Chen , Subject: [PATCH v2 1/5] usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio slot Date: Mon, 1 Mar 2021 13:49:31 +0200 Message-Id: <1614599375-8803-2-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> References: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org As per UAC2 Audio Data Formats spec (2.3.1.1 USB Packets), if the sampling rate is a constant, the allowable variation of number of audio slots per virtual frame is +/- 1 audio slot. It means that endpoint should be able to accept/send +1 audio slot. Previous endpoint max_packet_size calculation code was adding sometimes +1 audio slot due to DIV_ROUND_UP behaviour which was rounding up to closest integer. However this doesn't work if the numbers are divisible. It had no any impact with Linux hosts which ignore this issue, but in case of more strict Windows it caused rejected enumeration Thus always add +1 audio slot to endpoint's max packet size Fixes: 913e4a90b6f9 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth") Cc: Peter Chen Cc: #v4.3+ Signed-off-by: Ruslan Bilovol --- drivers/usb/gadget/function/f_uac2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 740cb64..c62cccb 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -478,7 +478,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, } max_size_bw = num_channels(chmask) * ssize * - DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); + ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, max_size_ep)); From patchwork Mon Mar 1 11:49:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 390734 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 710D1C433E0 for ; Mon, 1 Mar 2021 11:52:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2A05764ED5 for ; Mon, 1 Mar 2021 11:52:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234411AbhCALwM (ORCPT ); Mon, 1 Mar 2021 06:52:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33660 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234338AbhCALvg (ORCPT ); Mon, 1 Mar 2021 06:51:36 -0500 Received: from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com [IPv6:2a00:1450:4864:20::22c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5F8ADC0617AB; Mon, 1 Mar 2021 03:50:25 -0800 (PST) Received: by mail-lj1-x22c.google.com with SMTP id h4so18849376ljl.0; Mon, 01 Mar 2021 03:50:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=a3fR6Ve9ApfA3U9S3BpD3B/5uX3W9BFd2HZqD0/PdZ8=; b=q66A64NZPNqkvC4oe3MmZyrXQypU9F6L0QalEafsT9IWPw19JIBFuqXDETzroRjd1K aTBI+nGokloLb9t2fOcmIHr0b3W3fAU9Jox9Xb5NyJqevHm1GuSyyhDk58dI7i9+T+oc 11PY092Bc8jd4b/kRAoSCqdiHMACpA2VS9oA5Bo84+rkK/a+uab8SXznuNAs1RGiHanj VRjQ8UW4wRNOacj6TDZtQDtZ4Z1xZb+25zwlQvkJxnpHXuqg7fcuKP064HGEyublsn5q lUV4C1et6KNBO2LEsbsc7DTYPGtKWDKRXIPkLUOUzMmWa7rabhDbsY9dfQGA1Irc0ZJf KvFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=a3fR6Ve9ApfA3U9S3BpD3B/5uX3W9BFd2HZqD0/PdZ8=; b=CckZf1poLubYIl+dM7gKYT3KcBwpYc6eBWCjHJE9hETqdz1HRhVg9Htv6aZ6WMmyEr eCusnviBZIxzhJrMYwtnSvWNaxt+MkBXDSQLt6SdQsOrH0vsRoUXoB3W8d02NEBrVlJe RPcLsUlHucJB6q95W2h6Wf1hHrW5yGBDPx2E/p/+6rE7UlxRGkQHMiUV+taNI6XR9cRz 3fPrA0lRr8z3YEiSH6RdFQPXDQKoZBRAFizXNs9Cu51PEFRiSFznRAmCj9z6NkzTxQjo JoZrHryPOnI7lI/jIxG8cH4Qt/Pkb/PO+YLJLNFl1Nx0LqRo5bh03Yzb4jAfj4Yhqs5y /Nhw== X-Gm-Message-State: AOAM531zXtc7zooK61N2o4sxJQJcrjMzhfgQSklAVGsnzhV9k4UgTeg8 6FUWpDywZ1V3B/CKGb7gqkI= X-Google-Smtp-Source: ABdhPJwnSYhbab864Cs0ltPO/LykuBv5ECJo3g7ntR84sDrjyLYIJtC1UNNaaUGeIvpxBWwmIghnVQ== X-Received: by 2002:a2e:7d03:: with SMTP id y3mr7332648ljc.0.1614599423944; Mon, 01 Mar 2021 03:50:23 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id y26sm2281587lfh.279.2021.03.01.03.50.21 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Mon, 01 Mar 2021 03:50:22 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol , Subject: [PATCH v2 2/5] usb: gadget: f_uac1: stop playback on function disable Date: Mon, 1 Mar 2021 13:49:32 +0200 Message-Id: <1614599375-8803-3-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> References: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org There is missing playback stop/cleanup in case of gadget's ->disable callback that happens on events like USB host resetting or gadget disconnection Fixes: 0591bc236015 ("usb: gadget: add f_uac1 variant based on a new u_audio api") Cc: # 4.13+ Signed-off-by: Ruslan Bilovol --- drivers/usb/gadget/function/f_uac1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 00d3469..560382e 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -499,6 +499,7 @@ static void f_audio_disable(struct usb_function *f) uac1->as_out_alt = 0; uac1->as_in_alt = 0; + u_audio_stop_playback(&uac1->g_audio); u_audio_stop_capture(&uac1->g_audio); } From patchwork Mon Mar 1 11:49:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 388997 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0DCDC433E0 for ; Mon, 1 Mar 2021 11:52:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 84DBC64E31 for ; Mon, 1 Mar 2021 11:52:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234427AbhCALwT (ORCPT ); Mon, 1 Mar 2021 06:52:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33662 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234160AbhCALvg (ORCPT ); Mon, 1 Mar 2021 06:51:36 -0500 Received: from mail-lf1-x12b.google.com (mail-lf1-x12b.google.com [IPv6:2a00:1450:4864:20::12b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D02CDC061356; Mon, 1 Mar 2021 03:50:28 -0800 (PST) Received: by mail-lf1-x12b.google.com with SMTP id v9so7213075lfa.1; Mon, 01 Mar 2021 03:50:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=QcE+g+g7mExT314EzRI5jC4aCY5l0a1ys6s5hUq2MwM=; b=Yp2JyZjYmI/daDo/mX5UOoQxVnnl2YixWYLv+a8V2Kzk60ROjp0ILUnJkLXbmk+thL 3fVp6lam5ylo8Xb8ltWl9XAa1okftI2v59fei8b+9ybrS/mrFqzXPFJjhiE0IpCdZTrW y+69DnJuCSjvh5MbU70toE01zJCf0fM3mJquPv9Rh8NvhMZ4wDD/yOcZojVXK7zZxvmz gSXIGmyy0t7OZgppt4DinuXjUbHvCWJZN4LC59xr+O7zqiONtGkVLgsou6+7o3sL4aQJ h6aK8Y6n5mZOefHqt+QUFqlBmVwbIVDFDWhkq3U/nKv4jipK86uw87QNWHfD5okorqW6 L58w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=QcE+g+g7mExT314EzRI5jC4aCY5l0a1ys6s5hUq2MwM=; b=i1GNuCmAHUmg5lZvYXqILjUtORRuDsAgNU/hV34UOOw9krsPUxog0N2whjfgEfcXMk s/uMdoxgRm53YoPWdCJ0JEz0nR7iSu8mkuNqxZHwaDd+6pSlXDInk0x6xPCXNAhO8Qn5 CWvC84IqAjC9d9iLU2brUUSXOSIizQ9Tsc7nnNZXD8MjmrJPAtmNblBkt7qa5J25KEvE kFfpeHUj8FgLs7gxN2Kd49mX+fF8I6uH7LaysS9lgNIoAAlP1J7ZzylRcpn1Y2X4auwx 46F7821fxTffJZjyMChHqn/KORryqJxDdiCC4FyMvyUHJFjDCyFxI8WFzud+I1ExLc2E yC9g== X-Gm-Message-State: AOAM530j9+lVPYy6mQG5ZalyGGeMm0+QejQqmfmcWSj3gqTMzkVqCxRs Pa1GxP5Ko/gcoOJpwkg7Yno= X-Google-Smtp-Source: ABdhPJw2Mb/eFZcxsY+8huTbGYWv916iF17UqBxLrcZs4cZqi1b0uQLVHgIRFLze956o6Qf94+Sl9g== X-Received: by 2002:a05:6512:203a:: with SMTP id s26mr9572800lfs.535.1614599427398; Mon, 01 Mar 2021 03:50:27 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id m1sm2431356ljg.111.2021.03.01.03.50.26 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Mon, 01 Mar 2021 03:50:26 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol Subject: [PATCH v2 3/5] usb: gadget: f_uac2: validate input parameters Date: Mon, 1 Mar 2021 13:49:33 +0200 Message-Id: <1614599375-8803-4-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> References: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Currently user can configure UAC2 function with parameters that violate UAC2 spec or are not supported by UAC2 gadget implementation. This can lead to incorrect behavior if such gadget is connected to the host - like enumeration failure or other issues depending on host's UAC2 driver implementation, bringing user to a long hours of debugging the issue. Instead of silently accept these parameters, throw an error if they are not valid. Signed-off-by: Ruslan Bilovol --- drivers/usb/gadget/function/f_uac2.c | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index c62cccb..f868e38 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -14,6 +14,9 @@ #include "u_audio.h" #include "u_uac2.h" +/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ +#define UAC2_CHANNEL_MASK 0x07FFFFFF + /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -604,6 +607,36 @@ static void setup_descriptor(struct f_uac2_opts *opts) hs_audio_desc[i] = NULL; } +static int afunc_validate_opts(struct g_audio *agdev, struct device *dev) +{ + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + + if (!opts->p_chmask && !opts->c_chmask) { + dev_err(dev, "Error: no playback and capture channels\n"); + return -EINVAL; + } else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported playback channels mask\n"); + return -EINVAL; + } else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported capture channels mask\n"); + return -EINVAL; + } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) { + dev_err(dev, "Error: incorrect playback sample size\n"); + return -EINVAL; + } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) { + dev_err(dev, "Error: incorrect capture sample size\n"); + return -EINVAL; + } else if (!opts->p_srate) { + dev_err(dev, "Error: incorrect playback sampling rate\n"); + return -EINVAL; + } else if (!opts->c_srate) { + dev_err(dev, "Error: incorrect capture sampling rate\n"); + return -EINVAL; + } + + return 0; +} + static int afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) { @@ -612,11 +645,13 @@ static void setup_descriptor(struct f_uac2_opts *opts) struct usb_composite_dev *cdev = cfg->cdev; struct usb_gadget *gadget = cdev->gadget; struct device *dev = &gadget->dev; - struct f_uac2_opts *uac2_opts; + struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev); struct usb_string *us; int ret; - uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst); + ret = afunc_validate_opts(agdev, dev); + if (ret) + return ret; us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); if (IS_ERR(us)) From patchwork Mon Mar 1 11:49:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 388996 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E9B0C433DB for ; Mon, 1 Mar 2021 11:53:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 27FCF64EDE for ; Mon, 1 Mar 2021 11:53:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234330AbhCALwj (ORCPT ); Mon, 1 Mar 2021 06:52:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33664 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234342AbhCALvg (ORCPT ); Mon, 1 Mar 2021 06:51:36 -0500 Received: from mail-lf1-x136.google.com (mail-lf1-x136.google.com [IPv6:2a00:1450:4864:20::136]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DDA3DC06121D; Mon, 1 Mar 2021 03:50:31 -0800 (PST) Received: by mail-lf1-x136.google.com with SMTP id f1so25026036lfu.3; Mon, 01 Mar 2021 03:50:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=FU3j+Yt9GOZUp/owCA8DjVj1xEHIaeTECTvQ0R9OrLU=; b=VALCemYR51ioQCbxWYoXkchKSMfpJwzMDT1RN7uSrtE7wPvD1D1lIM/1rvS75D+Uo1 +e13w7+Pq0lB5CLuM4G28FFu2JtJre9i4T2z+Bjhk5eyDewZq+bJS9UH6FMO5pcFTZYT wO5eSTAjtZfbSigRwfkGBA8pDvCrPJctPoF6d8vpsO0kXpTB4GEToPrZYrI49X7tMBqP p/XvkVQCbsmvmISw5hbC+8jlWC/vHcYK+35OP5MKj/+8oLue8t2a4xqAjOOCbbG7oE43 xORK5+izY+V5byp1BuuCs/Ws42dWOdG4xVu1lgANdnPajt+RSJagLFsPCaqxBe9HhoO9 zbOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=FU3j+Yt9GOZUp/owCA8DjVj1xEHIaeTECTvQ0R9OrLU=; b=Y7mLVmz9zXr6odY9cNEonST+jyw+nOiaJYFelBVes7tbg+3CUgYqQ/P1iXkPG0Spqu yhPIurL5PIZgKVjYQIgpbQ8Ne0QqyCEBQ2hEokYBxVtqpe3Kg98eSPo/LsJUVzKHKP1W ZG2wXoTjYaDFp/Pxii1qKLf5kxa/7w0Cq7DxQbhwd66T59wTUTxbjRbDaJOFFicbn1qy QoDwZpxy6zCsUiBvL2GMy0CL4/KMtFRR6GHa3+qqByynp3/4VsfgylRsZ3aaZoc0rJ0M LsbarAjXWb/v3rOcSiMjGwz0jnVz3IPX4jqoc/uQGWBhOM1VUmc0n4kYNenBe/wjc3Qo QxVQ== X-Gm-Message-State: AOAM530Gw+NwwGssO9M7S8/3zORrX4nP9wxRObR3F0mls3mpwtLTugHw WHW04iAdhSJSk75+/e+m8Xs= X-Google-Smtp-Source: ABdhPJwosJC9Ij9odXOpLDCtX35Hr86P3DVu4j0ngN7hxJ61oc7BJm7CvH+xkLtRAnf8FqWUYOPhGg== X-Received: by 2002:ac2:5617:: with SMTP id v23mr6071463lfd.123.1614599430449; Mon, 01 Mar 2021 03:50:30 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id x74sm2134485lff.137.2021.03.01.03.50.29 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Mon, 01 Mar 2021 03:50:29 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol Subject: [PATCH v2 4/5] usb: gadget: f_uac1: validate input parameters Date: Mon, 1 Mar 2021 13:49:34 +0200 Message-Id: <1614599375-8803-5-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> References: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Currently user can configure UAC1 function with parameters that violate UAC1 spec or are not supported by UAC1 gadget implementation. This can lead to incorrect behavior if such gadget is connected to the host - like enumeration failure or other issues depending on host's UAC1 driver implementation, bringing user to a long hours of debugging the issue. Instead of silently accept these parameters, throw an error if they are not valid. Signed-off-by: Ruslan Bilovol --- drivers/usb/gadget/function/f_uac1.c | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index 560382e..e65f474 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -19,6 +19,9 @@ #include "u_audio.h" #include "u_uac1.h" +/* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */ +#define UAC1_CHANNEL_MASK 0x0FFF + struct f_uac1 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; @@ -30,6 +33,11 @@ static inline struct f_uac1 *func_to_uac1(struct usb_function *f) return container_of(f, struct f_uac1, g_audio.func); } +static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) +{ + return container_of(audio->func.fi, struct f_uac1_opts, func_inst); +} + /* * DESCRIPTORS ... most are static, but strings and full * configuration descriptors are built on demand. @@ -505,11 +513,42 @@ static void f_audio_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ +static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) +{ + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + + if (!opts->p_chmask && !opts->c_chmask) { + dev_err(dev, "Error: no playback and capture channels\n"); + return -EINVAL; + } else if (opts->p_chmask & ~UAC1_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported playback channels mask\n"); + return -EINVAL; + } else if (opts->c_chmask & ~UAC1_CHANNEL_MASK) { + dev_err(dev, "Error: unsupported capture channels mask\n"); + return -EINVAL; + } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) { + dev_err(dev, "Error: incorrect playback sample size\n"); + return -EINVAL; + } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) { + dev_err(dev, "Error: incorrect capture sample size\n"); + return -EINVAL; + } else if (!opts->p_srate) { + dev_err(dev, "Error: incorrect playback sampling rate\n"); + return -EINVAL; + } else if (!opts->c_srate) { + dev_err(dev, "Error: incorrect capture sampling rate\n"); + return -EINVAL; + } + + return 0; +} + /* audio function driver setup/binding */ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct usb_gadget *gadget = cdev->gadget; + struct device *dev = &gadget->dev; struct f_uac1 *uac1 = func_to_uac1(f); struct g_audio *audio = func_to_g_audio(f); struct f_uac1_opts *audio_opts; @@ -519,6 +558,10 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) int rate; int status; + status = f_audio_validate_opts(audio, dev); + if (status) + return status; + audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst); us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); From patchwork Mon Mar 1 11:49:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 390733 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 37AF5C433DB for ; Mon, 1 Mar 2021 11:52:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DCF5B64E37 for ; Mon, 1 Mar 2021 11:52:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234428AbhCALwa (ORCPT ); Mon, 1 Mar 2021 06:52:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234348AbhCALvg (ORCPT ); Mon, 1 Mar 2021 06:51:36 -0500 Received: from mail-lf1-x12d.google.com (mail-lf1-x12d.google.com [IPv6:2a00:1450:4864:20::12d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 56123C06121E; Mon, 1 Mar 2021 03:50:35 -0800 (PST) Received: by mail-lf1-x12d.google.com with SMTP id b1so14217753lfb.7; Mon, 01 Mar 2021 03:50:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=uaGW7tC2JjBnOktvFMM63m8EOA/LiWD+e5WC31mYaBk=; b=qTxPtxpNonuWNMhbqKjbXTWw6Kwjym6JSJZmZKt+AMHHwgKROtKj494u89JcM3a2/7 mGLOpjM69EbF5zvFXyo6ceJOwJqwet4f36DXf3udVGdOmzJWMKRUVwRnE5wzAFTkk2lq 4aSvAtEUAegBsVpfvETYCW9K7I9a00Rxqr5Li+Xq7oulP++wK/yt87qOYVx93W+Ue0AL baUND4wuJqizwlfbYCwgirh1du/jErOGsxJ+S03PNc3imtcJ6WYYZwBEwwu+zB/AqUXk IaUWp9JfHsIDQ1jWBwqdh9p5XRmerjqHqhets6+xxZP/Uqwi6KbqynijlMWumYQw941x XVbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uaGW7tC2JjBnOktvFMM63m8EOA/LiWD+e5WC31mYaBk=; b=lLu1BAkCBHtf2gfLGMrRt6islTOP6J1LSeiQl0lnCYUudsmb9BMC9jrgH9EP5e+gAP gVLdC1rAlS4Ft6yqOfw37mguAqefTECpkPFtGC7LIuUPYv50E3r7WcHJHCFCZRSS3rsd 4IZNBl6beEevYxy8q2qMGzt9Ve6L1Rwe5BqVHMWo/nchnmxLAE9kYwOGM62XYI+QzllR /FCC4kPorzktIRspUcThw8EwofuE6hZI+xoM64wSct6xOFRZzIUm+t6pfFMOukdt22UX JEbNDaBCRFqO1Ub3tpoJj0wXUb6O0zuyK4eUKhrHpz0udrpzhdxVcPpgtlMTQVTfZO3e Qr1A== X-Gm-Message-State: AOAM5302OE8Gn21udt6xewF+BSrc9BBQsjw5Pt2OiNcipd+va90+wCIU srSc9GxzC3PdNF1JWdENiDw= X-Google-Smtp-Source: ABdhPJz1oJ1zKO66YIImBxNlFXxSqVoUta3F8d7Ag/YG4Hwpx365myKQ4z24TANQYAIprnm7efX13Q== X-Received: by 2002:a19:5d56:: with SMTP id p22mr3648808lfj.265.1614599433838; Mon, 01 Mar 2021 03:50:33 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id o27sm2272176lfi.183.2021.03.01.03.50.32 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Mon, 01 Mar 2021 03:50:33 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol Subject: [PATCH v2 5/5] usb: gadget: f_uac1: disable IN/OUT ep if unused Date: Mon, 1 Mar 2021 13:49:35 +0200 Message-Id: <1614599375-8803-6-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> References: <1614599375-8803-1-git-send-email-ruslan.bilovol@gmail.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org 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 --- drivers/usb/gadget/function/f_uac1.c | 229 +++++++++++++++++++++++++---------- 1 file changed, 163 insertions(+), 66 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index e65f474..d047075 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -22,6 +22,9 @@ /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */ #define UAC1_CHANNEL_MASK 0x0FFF +#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) +#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) + struct f_uac1 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; @@ -50,11 +53,6 @@ static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN */ -#define F_AUDIO_AC_INTERFACE 0 -#define F_AUDIO_AS_OUT_INTERFACE 1 -#define F_AUDIO_AS_IN_INTERFACE 2 -/* Number of streaming interfaces */ -#define F_AUDIO_NUM_INTERFACES 2 /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc = { @@ -65,73 +63,47 @@ static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, }; -/* - * The number of AudioStreaming and MIDIStreaming interfaces - * in the Audio Interface Collection - */ -DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); - -#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) -/* 2 input terminals and 2 output terminals */ -#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ - + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE) /* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_2 ac_header_desc = { - .bLength = UAC_DT_AC_HEADER_LENGTH, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_HEADER, - .bcdADC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH), - .bInCollection = F_AUDIO_NUM_INTERFACES, - .baInterfaceNr = { - /* Interface number of the AudioStream interfaces */ - [0] = 1, - [1] = 2, - } -}; +static struct uac1_ac_header_descriptor *ac_header_desc; -#define USB_OUT_IT_ID 1 static struct uac_input_terminal_descriptor usb_out_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .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, .wChannelConfig = cpu_to_le16(0x3), }; -#define IO_OUT_OT_ID 2 static struct uac1_output_terminal_descriptor io_out_ot_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = IO_OUT_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), .bAssocTerminal = 0, - .bSourceID = USB_OUT_IT_ID, + /* .bSourceID = DYNAMIC */ }; -#define IO_IN_IT_ID 3 static struct uac_input_terminal_descriptor io_in_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = IO_IN_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), .bAssocTerminal = 0, .wChannelConfig = cpu_to_le16(0x3), }; -#define USB_IN_OT_ID 4 static struct uac1_output_terminal_descriptor usb_in_ot_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .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, + /* .bSourceID = DYNAMIC */ }; /* B.4.1 Standard AS Interface Descriptor */ @@ -176,7 +148,7 @@ static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_OUT_IT_ID, + /* .bTerminalLink = DYNAMIC */ .bDelay = 1, .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; @@ -185,7 +157,7 @@ static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_IN_OT_ID, + /* .bTerminalLink = DYNAMIC */ .bDelay = 1, .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; @@ -513,6 +485,108 @@ static void f_audio_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ +static struct +uac1_ac_header_descriptor *build_ac_header_desc(struct f_uac1_opts *opts) +{ + struct uac1_ac_header_descriptor *ac_desc; + int ac_header_desc_size; + int num_ifaces = 0; + + if (EPOUT_EN(opts)) + num_ifaces++; + if (EPIN_EN(opts)) + num_ifaces++; + + ac_header_desc_size = UAC_DT_AC_HEADER_SIZE(num_ifaces); + + ac_desc = kzalloc(ac_header_desc_size, GFP_KERNEL); + if (!ac_desc) + return NULL; + + ac_desc->bLength = ac_header_desc_size; + ac_desc->bDescriptorType = USB_DT_CS_INTERFACE; + ac_desc->bDescriptorSubtype = UAC_HEADER; + ac_desc->bcdADC = cpu_to_le16(0x0100); + ac_desc->bInCollection = num_ifaces; + + /* wTotalLength and baInterfaceNr will be defined later */ + + return ac_desc; +} + +/* Use macro to overcome line length limitation */ +#define USBDHDR(p) (struct usb_descriptor_header *)(p) + +static void setup_descriptor(struct f_uac1_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++; + + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + + as_out_header_desc.bTerminalLink = usb_out_it_desc.bTerminalID; + as_in_header_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; + + ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc->bLength); + + if (EPIN_EN(opts)) { + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); + + len += sizeof(usb_in_ot_desc); + len += sizeof(io_in_it_desc); + ac_header_desc->wTotalLength = cpu_to_le16(len); + } + if (EPOUT_EN(opts)) { + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); + + len += sizeof(usb_out_it_desc); + len += sizeof(io_out_ot_desc); + ac_header_desc->wTotalLength = cpu_to_le16(len); + } + + i = 0; + f_audio_desc[i++] = USBDHDR(&ac_interface_desc); + f_audio_desc[i++] = USBDHDR(ac_header_desc); + + if (EPOUT_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + f_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + } + + if (EPIN_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&io_in_it_desc); + f_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + } + + if (EPOUT_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_0_desc); + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_1_desc); + f_audio_desc[i++] = USBDHDR(&as_out_header_desc); + f_audio_desc[i++] = USBDHDR(&as_out_type_i_desc); + f_audio_desc[i++] = USBDHDR(&as_out_ep_desc); + f_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_0_desc); + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_1_desc); + f_audio_desc[i++] = USBDHDR(&as_in_header_desc); + f_audio_desc[i++] = USBDHDR(&as_in_type_i_desc); + f_audio_desc[i++] = USBDHDR(&as_in_ep_desc); + f_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + f_audio_desc[i] = NULL; +} + static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) { struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); @@ -556,6 +630,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) struct usb_string *us; u8 *sam_freq; int rate; + int ba_iface_id; int status; status = f_audio_validate_opts(audio, dev); @@ -567,6 +642,11 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); if (IS_ERR(us)) return PTR_ERR(us); + + ac_header_desc = build_ac_header_desc(audio_opts); + if (!ac_header_desc) + return -ENOMEM; + ac_interface_desc.iInterface = us[STR_AC_IF].id; usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id; usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id; @@ -607,40 +687,52 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) uac1->ac_intf = status; uac1->ac_alt = 0; - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - as_out_interface_alt_0_desc.bInterfaceNumber = status; - as_out_interface_alt_1_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[0] = status; - uac1->as_out_intf = status; - uac1->as_out_alt = 0; + ba_iface_id = 0; + + if (EPOUT_EN(audio_opts)) { + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + as_out_interface_alt_0_desc.bInterfaceNumber = status; + as_out_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; + uac1->as_out_intf = status; + uac1->as_out_alt = 0; + } - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - as_in_interface_alt_0_desc.bInterfaceNumber = status; - as_in_interface_alt_1_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[1] = status; - uac1->as_in_intf = status; - uac1->as_in_alt = 0; + if (EPIN_EN(audio_opts)) { + status = usb_interface_id(c, f); + if (status < 0) + goto fail; + as_in_interface_alt_0_desc.bInterfaceNumber = status; + as_in_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; + uac1->as_in_intf = status; + uac1->as_in_alt = 0; + } audio->gadget = gadget; status = -ENODEV; /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); - if (!ep) - goto fail; - audio->out_ep = ep; - audio->out_ep->desc = &as_out_ep_desc; + if (EPOUT_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); + if (!ep) + goto fail; + audio->out_ep = ep; + audio->out_ep->desc = &as_out_ep_desc; + } - ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); - if (!ep) - goto fail; - audio->in_ep = ep; - audio->in_ep->desc = &as_in_ep_desc; + if (EPIN_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); + if (!ep) + goto fail; + audio->in_ep = ep; + audio->in_ep->desc = &as_in_ep_desc; + } + + setup_descriptor(audio_opts); /* copy descriptors, and track endpoint copies */ status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, @@ -667,6 +759,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) err_card_register: usb_free_all_descriptors(f); fail: + kfree(ac_header_desc); + ac_header_desc = NULL; return status; } @@ -809,6 +903,9 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) g_audio_cleanup(audio); usb_free_all_descriptors(f); + kfree(ac_header_desc); + ac_header_desc = NULL; + audio->gadget = NULL; }