From patchwork Tue Feb 16 22:24:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 12090675 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.7 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,URIBL_BLOCKED,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 5B09CC433E6 for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F05F64DFF for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229655AbhBPW0Q (ORCPT ); Tue, 16 Feb 2021 17:26:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230467AbhBPW0O (ORCPT ); Tue, 16 Feb 2021 17:26:14 -0500 Received: from mail-lj1-x232.google.com (mail-lj1-x232.google.com [IPv6:2a00:1450:4864:20::232]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 97B79C0613D6; Tue, 16 Feb 2021 14:25:33 -0800 (PST) Received: by mail-lj1-x232.google.com with SMTP id e17so13785999ljl.8; Tue, 16 Feb 2021 14:25:33 -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=SK5NfxgBu+E5KJUrttqO57iuGVHAR1k5YOscj4fR3SL+ak/NLBfSNAcn/hED4Jxx8F aUpCsbfPjqVbNgc4DxgP1hbVjNX6s0UBsm4Hq9hxfnpjmEM4io0adjDedF12dkuqjy03 UrHiJWEq6hT6t6Bd+zUdR3+LPGEbiTVlrRZU//iOutEMmuIuoG8kY9YW8NMiCz6VjHbp 9CEIjKNsLhzvaPfoByc7+MzGs9lACEJKS8A47ZiNY4E5CMHhP/J3pTzZK5dgLWIwIgJk WgFdfgIhY4FulL7CiuYFu/uhTGfyQcnwcJPDiPuXvKKdLocraQM3jV9sb/Q5q/LnobYG aPVA== 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=YJKStFZLOpqfoV95TJ6wSwmdWTVacfQ3HFUHncdSnq9WJsYDS0WieUBeqGEDKMM8Tz Y8NLB9K7rfQDIpaWyDQWS2MEt2KgWXuYAhdxGMX/kdkIffCkvUI62rIw/U+zjlDAGY57 /bWvo3+KHklQLPDa3kVefo0Mv8f2Q8iQhyDiguVua/O5f+Wy7tmTnDwFB1KsK/XBv9zM JgIi/mqrDYT8VHGrXVp5AaQKXlqqDOdWkh9tItU3KE8ZAgGbaNbtIWkrx8VE+dBdnD8k F8ZJivNemzaNn1oOZRq9js0i0fBepqSB3ffI4T1Jt691D65RgPGAJkhuW9QQnGG6Dc5u Zd3A== X-Gm-Message-State: AOAM5339dXtrVgHzb2NopgHWmfbQPtsK8hNBylqIQioRA8u9jl6XMhFa pPUhBdI/cSaPA/ugfsR9yO8= X-Google-Smtp-Source: ABdhPJw9d+5KpTmwKiZm0g7q5mdilyRlFpGRxfAsBx1Fn5lUxBQhhX40SoGa7lwTh8eIcIXz1YczRA== X-Received: by 2002:a2e:804b:: with SMTP id p11mr13667816ljg.141.1613514332055; Tue, 16 Feb 2021 14:25:32 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id d14sm21366lfg.128.2021.02.16.14.25.30 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 16 Feb 2021 14:25:31 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: Peter Chen , Daniel Mack , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol , Subject: [PATCH 1/5] usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio slot Date: Wed, 17 Feb 2021 00:24:55 +0200 Message-Id: <1613514299-20668-2-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1613514299-20668-1-git-send-email-ruslan.bilovol@gmail.com> References: <1613514299-20668-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 Tue Feb 16 22:24:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 12090673 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 97C46C43381 for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6472464E10 for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230520AbhBPW0T (ORCPT ); Tue, 16 Feb 2021 17:26:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40844 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230493AbhBPW0R (ORCPT ); Tue, 16 Feb 2021 17:26:17 -0500 Received: from mail-lf1-x135.google.com (mail-lf1-x135.google.com [IPv6:2a00:1450:4864:20::135]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17C02C061786; Tue, 16 Feb 2021 14:25:36 -0800 (PST) Received: by mail-lf1-x135.google.com with SMTP id f1so18500379lfu.3; Tue, 16 Feb 2021 14:25:36 -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=CcBmOTWx4rOfOO2ml/nx0N0ujuOh1Je+9ZyiWKlffqIiTEcwTwAbuvhiwMh9QOxfxE l/jJOrtMsJVKBJR9yj4J/FAIUsOixXDYcZDBPWCKWe85ongnmwwd7HdtSIyY6y8O2BF0 SJ0L9v5A7f93RRY3oshaAlXeLf6PSHX/uIxdjHp56A8/S903ylOhKu6AFyJ7ATWtUjO3 Gvalg23YbKGdSE1RDy8GgVswZ1FMvDvqbGeFaE0v+YsR4s3NlOjT75dTDlsczowqkMuP WQdXDOfrwFCr9qj1oA9+IDq2Z8tdqFKmJNi1TMgoO/odVmefA6HqbiYcUiv39BU1WUcl wM4g== 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=ICKs0CM7kL9Ve2o4Whrj4nmuUeymCwPohFBJzN1OPH67OK+HclVfZO1edQmONu3eCQ slCndE8aWJfKEukDziBP0e2ix0jLkn44LbETQOCqwoQFJvjES9hnt/IOlWaOgIREPJ6y G9zkWSRK8Yo39+pjJzuYjuyviFerMcRlAukuTbwySGf44ulZilOaS37EMxqOcbr6JXmK XUiyTpuJbxsBa5CmbOp9x8wFiWnswaoAfN7Iz3m034Z2YR5xbRiCH4qRmVVt2O5Lg/TZ nZ/bDyb/LlgYuOfN7NHtMYZS2gEhAG1l6fTjCAO/4NYv5gajzfWwt4YYGw8gAo6Be0vJ wE0g== X-Gm-Message-State: AOAM532DEqwS/p6a/RVP8cBEJj5xEjboJAzpGv3sUusv0gjdk9YEoj3u 6eNpexjY+zneadurQhRxDpo= X-Google-Smtp-Source: ABdhPJzjojN33CXGc02zMNdLELDHamwSH8r6REBZbOciEeRZ8HwwODGWc+lHqfms29I7Rz7j9l4kiQ== X-Received: by 2002:a05:6512:a8e:: with SMTP id m14mr13116313lfu.641.1613514334570; Tue, 16 Feb 2021 14:25:34 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id m14sm22593lfb.43.2021.02.16.14.25.32 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 16 Feb 2021 14:25:33 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: Peter Chen , Daniel Mack , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol , Subject: [PATCH 2/5] usb: gadget: f_uac1: stop playback on function disable Date: Wed, 17 Feb 2021 00:24:56 +0200 Message-Id: <1613514299-20668-3-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1613514299-20668-1-git-send-email-ruslan.bilovol@gmail.com> References: <1613514299-20668-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 Tue Feb 16 22:24:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 12090677 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 CF3B8C4332E for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A698A64E10 for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231129AbhBPW0X (ORCPT ); Tue, 16 Feb 2021 17:26:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40854 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230500AbhBPW0S (ORCPT ); Tue, 16 Feb 2021 17:26:18 -0500 Received: from mail-lj1-x22d.google.com (mail-lj1-x22d.google.com [IPv6:2a00:1450:4864:20::22d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0BF71C06174A; Tue, 16 Feb 2021 14:25:38 -0800 (PST) Received: by mail-lj1-x22d.google.com with SMTP id k22so13139168ljg.3; Tue, 16 Feb 2021 14:25:37 -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=N4o9VGOBWFA758XVAHeyCXnCwkuwkBvdGPfVojRuDf4=; b=lo7wNep8PSSvtzIJHYo0Fcpqgc8lww4iyzOFamqEMZ4fwcl5KadKkJrJq+F5sxMaY3 x3fS+85wd/GAmArt/kL55Dghkzr1ja28x80buIMyJOzmqzv7F0QjcTQ8cEJ0fsJn8aK7 jKXf0CeYaEokvSWXstfZCJkt/iSIWmHRCTCZ1ImPp816NfrUpLqFwHtLeDoU8fLgfZ+k QvIIOXjhqYiKTdMGAlvTe2wCeo/W5PisG1WacCAzUBsYlupnCyH4mUAU7HcvR3AV2zJT dkTIbeAOPGhbIiU+Y+bz634j5ms+EYPBmTXhxqx+GYqYAlRIKZgUyknHEasSL+8wFDgr EZEA== 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=N4o9VGOBWFA758XVAHeyCXnCwkuwkBvdGPfVojRuDf4=; b=QmzAf//lvd9sa3fP8F1zWUuTaSez0CrJR/kTjv1C4DZ+8gjvo8s7wMVH3eLTe3gb5k WM+FKiAb7NdJ5vm2dGD5wzXpH22dJwpG546KshIZGLmV45ogXs87RqAuPLd4v2S0msoe 0HJR/M8x8mc77WVocFw54V0vIfH01UIWZubAzOfBMbTqb50FW+W9ar4ESDvF8Kc3udH/ G79rBqWjsQtrcbTc4lrbaeO9pW/P+Z2osgNXlybIIyf0xI6dp5qKroxe7ixUWp9YEit8 IFLO1POiTkqR30YRdlE/1c0/l7frwWU3cCxyYqBUesQlbsPkX5ujqWRZFScXPL6Ee+X8 wL1Q== X-Gm-Message-State: AOAM53184YQ8BRSmDLYKt1uZAHZJW8+7lIvh3VTHapvRcnoH/mOLCHAO CkFD5tcWxtRajbdsMpRiiVo= X-Google-Smtp-Source: ABdhPJzPteoeNpzGpmRaYqH29fxrI8vRh7u7OkfwDt7HNocuHro6bqsaqaHlKLb9do4HaycQWtLFyQ== X-Received: by 2002:a05:651c:2c5:: with SMTP id f5mr13193149ljo.357.1613514336497; Tue, 16 Feb 2021 14:25:36 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id u1sm22628lff.58.2021.02.16.14.25.35 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 16 Feb 2021 14:25:35 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: Peter Chen , Daniel Mack , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol Subject: [PATCH 3/5] usb: gadget: f_uac2: validate input parameters Date: Wed, 17 Feb 2021 00:24:57 +0200 Message-Id: <1613514299-20668-4-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1613514299-20668-1-git-send-email-ruslan.bilovol@gmail.com> References: <1613514299-20668-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 | 40 ++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index c62cccb..d0e50fc 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,37 @@ static void setup_descriptor(struct f_uac2_opts *opts) hs_audio_desc[i] = NULL; } +static int afunc_validate_opts(struct g_audio *agdev) +{ + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + struct device *dev = &agdev->gadget->dev; + + 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 +646,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); + if (ret) + return ret; us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); if (IS_ERR(us)) From patchwork Tue Feb 16 22:24:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 12090679 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 0AAE9C4332B for ; Tue, 16 Feb 2021 22:26:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C229764EAF for ; Tue, 16 Feb 2021 22:26:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231142AbhBPW00 (ORCPT ); Tue, 16 Feb 2021 17:26:26 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40870 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231128AbhBPW0V (ORCPT ); Tue, 16 Feb 2021 17:26:21 -0500 Received: from mail-lf1-x12c.google.com (mail-lf1-x12c.google.com [IPv6:2a00:1450:4864:20::12c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1FCB7C061788; Tue, 16 Feb 2021 14:25:41 -0800 (PST) Received: by mail-lf1-x12c.google.com with SMTP id v24so18435039lfr.7; Tue, 16 Feb 2021 14:25:41 -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=0hv1vhtBNEC/VvoxA9ZstUBo9bWgHWvQ34dUYSl1J1w=; b=oHF4ywGln27m1vS1PqleNjrNrE/wr3Gc0ljAZmkKRlSGN4JFhhrG/MjmKBWaX0VBQ2 iE4LxdG3cxlNSTKHXVesfr0dWVuxDEcfHblVDhjQzcyvHaugtmUOW2qPxwQX9I/9wSoW JrfyeQKSXKiX6oZkPE1KQ3UU7YOWytwDQUIPsBWnYbC8Yc4r8M4tESlrvQvNokCWsQPa 7QLQCqibEA/mz4O73LAG3xAaB10NoaWNG8c+UxuhdYAJ9a3EJTTZJEBxKqCknlS4POr9 ChuSDAkIy5C+5JmVSXx0x67Y5Tfz97UgPRHYcJLPAffKMeaT4a73e19rSC5L1yPg1n/+ datg== 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=0hv1vhtBNEC/VvoxA9ZstUBo9bWgHWvQ34dUYSl1J1w=; b=W+6TlGmzWaEm3Vd2+AZgjdbW10q+zSSCtzQEEnuDcMsHTpYEpwbKgi6mHnBJyhIiTl zh+fEHd/wIQ3rwPCbrHVmqsYiUaoZ+tPhJcqFXGRA3eyBa4itUdDshArhpJ3sx/gq30a FxaTRjs9dr7RiYYcGZiXCWYTEdn7ArIUzkBNsND5hVSvk9z3IPR06iQ5W+BwDjVTzUsQ lCXfrFfvXku6oJwbMHr2JSZOAKL36btqwmLjaoIu8f4q9+HgYpvCqC27fHGlP2UlaMW2 YuuOF8ljaQ/bJlzBJdNqz5Z564gX9BOu9H7JCE34AF/jOAerhP4aSofcDgDRwCbOPiwY XkjA== X-Gm-Message-State: AOAM5335st+tMa8OpwOgOVXVhBHaVG2CdIw/afRNtjUNA/E4U09MjSm3 bFx+NFkzWdvZbG7mCmhxkPo= X-Google-Smtp-Source: ABdhPJxXXUMJgA0rF0ljoL5OtOjuh1W0mpQZYElrQig/3sWocVIMvHcPWEs/gLP0Li430oEmjtHM/A== X-Received: by 2002:a19:c48:: with SMTP id 69mr10513773lfm.573.1613514339626; Tue, 16 Feb 2021 14:25:39 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id w9sm18437lfn.308.2021.02.16.14.25.37 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 16 Feb 2021 14:25:38 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: Peter Chen , Daniel Mack , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol Subject: [PATCH 4/5] usb: gadget: f_uac1: validate input parameters Date: Wed, 17 Feb 2021 00:24:58 +0200 Message-Id: <1613514299-20668-5-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1613514299-20668-1-git-send-email-ruslan.bilovol@gmail.com> References: <1613514299-20668-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..cce9478f 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,6 +513,37 @@ static void f_audio_disable(struct usb_function *f) /*-------------------------------------------------------------------------*/ +static int f_audio_validate_opts(struct g_audio *audio) +{ + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + struct device *dev = &audio->gadget->dev; + + 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) { @@ -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); + 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 Tue Feb 16 22:24:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 12090681 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 E6A46C433E0 for ; Tue, 16 Feb 2021 22:27:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AE22864DFF for ; Tue, 16 Feb 2021 22:27:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231146AbhBPW0d (ORCPT ); Tue, 16 Feb 2021 17:26:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40888 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231145AbhBPW00 (ORCPT ); Tue, 16 Feb 2021 17:26:26 -0500 Received: from mail-lj1-x22b.google.com (mail-lj1-x22b.google.com [IPv6:2a00:1450:4864:20::22b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 71AABC06178B; Tue, 16 Feb 2021 14:25:43 -0800 (PST) Received: by mail-lj1-x22b.google.com with SMTP id j6so13805650ljo.5; Tue, 16 Feb 2021 14:25:43 -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=IZIKjZvRH0JG0Lcg6AA2/6CX7djFn2ikcnR41OtsUZ0=; b=SfyqlzOlCnjdHlwpFpzGA0bJKp/ekbetn95nPb4avPLGO0KH6dU46xKl7VEBkBnT+n 0LKpBqyKEGC27IsdtwrCPht++vjz1BqKmYfRifpASYjCIl1PGytcxgsSTds02tLMdxbg SyUeNTwzhaqloE9DByWjxH0VUR+mp3YwoDl/da8RMYj9rHKSnLV03TBHwSHSCaSDV3zH QEqQ1MWg36DleeVrSldh60of0jyukwscn7pS+Aw+66yM2QnPH5pI/Rv2dKxPdFohyE2o G//OL+EaojlcA3DWbB9NwGeSqtXs2f88WaHsqGR7JQhL3lwXh5beLxK6BiGvOoXABN+Q MaFw== 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=IZIKjZvRH0JG0Lcg6AA2/6CX7djFn2ikcnR41OtsUZ0=; b=arTw70l7FJwCBRmdKH7GaWby+MNRH4SyxQEX/OjWDVV3WZ6Yzoj4EI+QDTDuDz2Txa NVkA3MsHBA1CVa+ZSVU6RrjmgoXN/3+n7rrMRBuoTOGC5CtCMdmZ5O13ZdD+6dmN4AaV iHokvCa1egL6P6hH4uBEXQbNyUW7Yd8RQOgqHVS49S+lfNvTuMkYmnx60KG9K3pHJmIc 8M3rx8JnJCMBmLzQhLFu6QHNnQkDi8FiuVT0EQkSQXQzv3AiSomkHyMaGEvan4xzBiBR KX9h/KN2wn5WsedU9gz3vQpPOpoPmCqQCplO/XD5vo0dahVZc6o6TwudRhU2Z5Av0sg7 sFcw== X-Gm-Message-State: AOAM533O1v0ey3gCvQAxFeQinS5mvD2nLHNX+CkeWKz6RluVA/w1f6YP N7iSsmcrw56Ty9hCQQuee3M= X-Google-Smtp-Source: ABdhPJx6Bna1JOCqVOTG12ETQwwsa2+M9SDMx3Rw/2BGBPZETrJKqpzXyahb3RZlsZm8o1ioHx9Xcw== X-Received: by 2002:a2e:9d8a:: with SMTP id c10mr7946785ljj.394.1613514341794; Tue, 16 Feb 2021 14:25:41 -0800 (PST) Received: from localhost (crossness-hoof.volia.net. [93.72.107.198]) by smtp.gmail.com with ESMTPSA id u10sm22394lfq.73.2021.02.16.14.25.40 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 16 Feb 2021 14:25:40 -0800 (PST) From: Ruslan Bilovol To: Felipe Balbi , Greg Kroah-Hartman Cc: Peter Chen , Daniel Mack , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Ruslan Bilovol Subject: [PATCH 5/5] usb: gadget: f_uac1: disable IN/OUT ep if unused Date: Wed, 17 Feb 2021 00:24:59 +0200 Message-Id: <1613514299-20668-6-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1613514299-20668-1-git-send-email-ruslan.bilovol@gmail.com> References: <1613514299-20668-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 cce9478f..b535407 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 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); @@ -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; }