From patchwork Fri Apr 13 22:24:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ruslan Bilovol X-Patchwork-Id: 10340845 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 824C260329 for ; Fri, 13 Apr 2018 22:25:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8C548287C1 for ; Fri, 13 Apr 2018 22:25:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7ECF528A2E; Fri, 13 Apr 2018 22:25:00 +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=-2.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 04DCD287C1 for ; Fri, 13 Apr 2018 22:24:59 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 9369026733D; Sat, 14 Apr 2018 00:24:49 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id E78762672B4; Sat, 14 Apr 2018 00:24:44 +0200 (CEST) Received: from mail-lf0-f68.google.com (mail-lf0-f68.google.com [209.85.215.68]) by alsa0.perex.cz (Postfix) with ESMTP id 6C85D26723C for ; Sat, 14 Apr 2018 00:24:42 +0200 (CEST) Received: by mail-lf0-f68.google.com with SMTP id b189-v6so14621739lfe.2 for ; Fri, 13 Apr 2018 15:24:42 -0700 (PDT) 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=YJRLFP1XCCMVEAz/VMRMR+yNrijKaZ0TMiOKsF9k2tc=; b=parwscKzxjM0o0IuVAwsgfNwcHy5afQq6KtdfP/ua8NEI+iSsOh0y6+bE0T5mq790X 2C92fzKE5scmxUtf0ll19k9ZdyF6936+oNV5LBzYsYjU8PBzLURuapZJp15uKZeZ6BfR oW8+yRmAJrZEB+Vqkrd6ow5aTRr2fqkox9+zIv9tPxQzXLoAk0ko74gUbGy4zFUy/oHH fCuFlZuzH0q7NM5Xk3XcWZgLC2+XBd91bF5TuYjnCH2UAAhk6w9I6sJ+3OWES1V/uTpL 1XZTmPAFnJ2ysudyS9tH/RfFLMHQyiRT+OvGzUGvEBfJGbjj3Au0pegF68Mz3fPMhbWJ UoRQ== 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=YJRLFP1XCCMVEAz/VMRMR+yNrijKaZ0TMiOKsF9k2tc=; b=QAabRbTi47FcocmRf3zFqrPOpC6pj9BaWbdbTXuJ1y2uVbgZxieIZdQF6MiCF8gUWY 14md8SWuBwKNWwxgGu+evi3wITrQEHBSHWr9Gfanx0JhxNJpJH3I9vwOO7yA68rCRM0m 2f1nFyQ7H+T7X/K/54BCMv6esRnLhYnAZdeFXGpzk/NJ1eNp6DtUT37oWn02jbYRtdl1 YO9p0RT8tS5aHBPURpegbvdeVYX8neI/UaLpZ4tDspGfgkjMlLDNQpJLHitEvTqyqeM2 wTLGCVx3+1/P/rpCHysEQ6xUI+MQyk1NpO5M+HA57wjMMrC1fpNpx/iIWoMPQ7Q9/Ox6 U2gw== X-Gm-Message-State: ALQs6tBDU7numoDOT3x8NZmXDkaHWDZLs5bagSlTZ/+CcW9RTzIMeY+s u5nNiFBHrao4CmHiY1p20CI= X-Google-Smtp-Source: AIpwx4+JmLtP0XxYUATrKHaxvqaSTDsKYd2y0IvD1cle6TQMt7OfRNCYHyRHvzxO079Z1ddRl97tPQ== X-Received: by 2002:a19:e501:: with SMTP id c1-v6mr9644744lfh.65.1523658281364; Fri, 13 Apr 2018 15:24:41 -0700 (PDT) Received: from localhost ([62.216.62.149]) by smtp.gmail.com with ESMTPSA id r16-v6sm695214lfr.54.2018.04.13.15.24.40 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Fri, 13 Apr 2018 15:24:40 -0700 (PDT) From: Ruslan Bilovol To: Takashi Iwai Date: Sat, 14 Apr 2018 01:24:23 +0300 Message-Id: <1523658266-2259-2-git-send-email-ruslan.bilovol@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1523658266-2259-1-git-send-email-ruslan.bilovol@gmail.com> References: <1523658266-2259-1-git-send-email-ruslan.bilovol@gmail.com> Cc: Jorge , alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman Subject: [alsa-devel] [PATCH 1/4] ALSA: usb: stream: refactor audio interface parsing X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Offload snd_usb_parse_audio_interface() function which became quite long after adding UAC3 spec support. Move class-specific parts to separate functions which now produce audioformat structure that is ready to be fed to snd_usb_add_audio_stream(). This also broke Blue Microphones workaround (which relies on audioformat decoded from previous altsetting) into two parts: prepare quirk flag analyzing previous altsetting then use it with current altsetting. Signed-off-by: Ruslan Bilovol --- sound/usb/stream.c | 613 +++++++++++++++++++++++++++++------------------------ 1 file changed, 334 insertions(+), 279 deletions(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 6a8f584..586d664 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -626,6 +626,319 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, return NULL; } +static struct audioformat * +snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int protocol, int iface_no, + int altno, int stream, int bm_quirk) +{ + struct usb_device *dev = chip->dev; + struct uac_format_type_i_continuous_descriptor *fmt; + unsigned int num_channels = 0, chconfig = 0; + struct audioformat *fp; + int clock = 0; + u64 format; + + /* get audio formats */ + if (protocol == UAC_VERSION_1) { + struct uac1_as_header_descriptor *as = + snd_usb_find_csint_desc(alts->extra, alts->extralen, + NULL, UAC_AS_GENERAL); + struct uac_input_terminal_descriptor *iterm; + + if (!as) { + dev_err(&dev->dev, + "%u:%d : UAC_AS_GENERAL descriptor not found\n", + iface_no, altno); + return NULL; + } + + if (as->bLength < sizeof(*as)) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_AS_GENERAL desc\n", + iface_no, altno); + return NULL; + } + + format = le16_to_cpu(as->wFormatTag); /* remember the format value */ + + iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (iterm) { + num_channels = iterm->bNrChannels; + chconfig = le16_to_cpu(iterm->wChannelConfig); + } + } else { /* UAC_VERSION_2 */ + struct uac2_input_terminal_descriptor *input_term; + struct uac2_output_terminal_descriptor *output_term; + struct uac2_as_header_descriptor *as = + snd_usb_find_csint_desc(alts->extra, alts->extralen, + NULL, UAC_AS_GENERAL); + + if (!as) { + dev_err(&dev->dev, + "%u:%d : UAC_AS_GENERAL descriptor not found\n", + iface_no, altno); + return NULL; + } + + if (as->bLength < sizeof(*as)) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_AS_GENERAL desc\n", + iface_no, altno); + return NULL; + } + + num_channels = as->bNrChannels; + format = le32_to_cpu(as->bmFormats); + chconfig = le32_to_cpu(as->bmChannelConfig); + + /* + * lookup the terminal associated to this interface + * to extract the clock + */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (input_term) { + clock = input_term->bCSourceID; + if (!chconfig && (num_channels == input_term->bNrChannels)) + chconfig = le32_to_cpu(input_term->bmChannelConfig); + goto found_clock; + } + + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (output_term) { + clock = output_term->bCSourceID; + goto found_clock; + } + + dev_err(&dev->dev, + "%u:%d : bogus bTerminalLink %d\n", + iface_no, altno, as->bTerminalLink); + return NULL; + } + +found_clock: + /* get format type */ + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, + NULL, UAC_FORMAT_TYPE); + if (!fmt) { + dev_err(&dev->dev, + "%u:%d : no UAC_FORMAT_TYPE desc\n", + iface_no, altno); + return NULL; + } + if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) + || ((protocol == UAC_VERSION_2) && + (fmt->bLength < 6))) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_FORMAT_TYPE desc\n", + iface_no, altno); + return NULL; + } + + /* + * Blue Microphones workaround: The last altsetting is + * identical with the previous one, except for a larger + * packet size, but is actually a mislabeled two-channel + * setting; ignore it. + * + * Part 2: analyze quirk flag and format + */ + if (bm_quirk && fmt->bNrChannels == 1 && fmt->bSubframeSize == 2) + return NULL; + + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) + return ERR_PTR(-ENOMEM); + + fp->iface = iface_no; + fp->altsetting = altno; + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = snd_usb_parse_datainterval(chip, alts); + fp->protocol = protocol; + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + fp->channels = num_channels; + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) + * (fp->maxpacksize & 0x7ff); + fp->attributes = parse_uac_endpoint_attributes(chip, alts, + protocol, iface_no); + fp->clock = clock; + INIT_LIST_HEAD(&fp->list); + + /* some quirks for attributes here */ + snd_usb_audioformat_attributes_quirk(chip, fp, stream); + + /* ok, let's parse further... */ + if (snd_usb_parse_audio_format(chip, fp, format, + fmt, stream) < 0) { + kfree(fp->rate_table); + kfree(fp); + return NULL; + } + + /* Create chmap */ + if (fp->channels != num_channels) + chconfig = 0; + + fp->chmap = convert_chmap(fp->channels, chconfig, protocol); + + return fp; +} + +static struct audioformat * +snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, + struct usb_host_interface *alts, + int iface_no, int altno, int stream) +{ + struct usb_device *dev = chip->dev; + struct uac3_input_terminal_descriptor *input_term; + struct uac3_output_terminal_descriptor *output_term; + struct uac3_cluster_header_descriptor *cluster; + struct uac3_as_header_descriptor *as; + struct uac3_hc_descriptor_header hc_header; + struct snd_pcm_chmap_elem *chmap; + unsigned int num_channels; + struct audioformat *fp; + u16 cluster_id, wLength; + int clock = 0; + int err; + + as = snd_usb_find_csint_desc(alts->extra, alts->extralen, + NULL, UAC_AS_GENERAL); + if (!as) { + dev_err(&dev->dev, + "%u:%d : UAC_AS_GENERAL descriptor not found\n", + iface_no, altno); + return NULL; + } + + if (as->bLength < sizeof(*as)) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_AS_GENERAL desc\n", + iface_no, altno); + return NULL; + } + + cluster_id = le16_to_cpu(as->wClusterDescrID); + if (!cluster_id) { + dev_err(&dev->dev, + "%u:%d : no cluster descriptor\n", + iface_no, altno); + return NULL; + } + + /* + * Get number of channels and channel map through + * High Capability Cluster Descriptor + * + * First step: get High Capability header and + * read size of Cluster Descriptor + */ + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, + snd_usb_ctrl_intf(chip), + &hc_header, sizeof(hc_header)); + if (err < 0) + return ERR_PTR(err); + else if (err != sizeof(hc_header)) { + dev_err(&dev->dev, + "%u:%d : can't get High Capability descriptor\n", + iface_no, altno); + return ERR_PTR(-EIO); + } + + /* + * Second step: allocate needed amount of memory + * and request Cluster Descriptor + */ + wLength = le16_to_cpu(hc_header.wLength); + cluster = kzalloc(wLength, GFP_KERNEL); + if (!cluster) + return ERR_PTR(-ENOMEM); + err = snd_usb_ctl_msg(chip->dev, + usb_rcvctrlpipe(chip->dev, 0), + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, + snd_usb_ctrl_intf(chip), + cluster, wLength); + if (err < 0) { + kfree(cluster); + return ERR_PTR(err); + } else if (err != wLength) { + dev_err(&dev->dev, + "%u:%d : can't get Cluster Descriptor\n", + iface_no, altno); + kfree(cluster); + return ERR_PTR(-EIO); + } + + num_channels = cluster->bNrChannels; + chmap = convert_chmap_v3(cluster); + kfree(cluster); + + /* + * lookup the terminal associated to this interface + * to extract the clock + */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (input_term) { + clock = input_term->bCSourceID; + goto found_clock; + } + + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (output_term) { + clock = output_term->bCSourceID; + goto found_clock; + } + + dev_err(&dev->dev, "%u:%d : bogus bTerminalLink %d\n", + iface_no, altno, as->bTerminalLink); + return NULL; + +found_clock: + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) + return ERR_PTR(-ENOMEM); + + fp->iface = iface_no; + fp->altsetting = altno; + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = snd_usb_parse_datainterval(chip, alts); + fp->protocol = UAC_VERSION_3; + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + fp->channels = num_channels; + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) + * (fp->maxpacksize & 0x7ff); + fp->attributes = parse_uac_endpoint_attributes(chip, alts, + UAC_VERSION_3, + iface_no); + fp->clock = clock; + fp->chmap = chmap; + INIT_LIST_HEAD(&fp->list); + + /* ok, let's parse further... */ + if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { + kfree(fp->rate_table); + kfree(fp); + return NULL; + } + + return fp; +} + int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) { struct usb_device *dev; @@ -633,13 +946,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; int i, altno, err, stream; - u64 format = 0; - unsigned int num_channels = 0; struct audioformat *fp = NULL; - int num, protocol, clock = 0; - struct uac_format_type_i_continuous_descriptor *fmt = NULL; - struct snd_pcm_chmap_elem *chmap_v3 = NULL; - unsigned int chconfig; + int num, protocol; dev = chip->dev; @@ -688,303 +996,50 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) protocol <= 2) protocol = UAC_VERSION_1; - chconfig = 0; - /* get audio formats */ switch (protocol) { default: dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n", iface_no, altno, protocol); protocol = UAC_VERSION_1; /* fall through */ - - case UAC_VERSION_1: { - struct uac1_as_header_descriptor *as = - snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - struct uac_input_terminal_descriptor *iterm; - - if (!as) { - dev_err(&dev->dev, - "%u:%d : UAC_AS_GENERAL descriptor not found\n", - iface_no, altno); - continue; - } - - if (as->bLength < sizeof(*as)) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_AS_GENERAL desc\n", - iface_no, altno); - continue; - } - - format = le16_to_cpu(as->wFormatTag); /* remember the format value */ - - iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (iterm) { - num_channels = iterm->bNrChannels; - chconfig = le16_to_cpu(iterm->wChannelConfig); - } - - break; - } - + case UAC_VERSION_1: + /* fall through */ case UAC_VERSION_2: { - struct uac2_input_terminal_descriptor *input_term; - struct uac2_output_terminal_descriptor *output_term; - struct uac2_as_header_descriptor *as = - snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); - - if (!as) { - dev_err(&dev->dev, - "%u:%d : UAC_AS_GENERAL descriptor not found\n", - iface_no, altno); - continue; - } - - if (as->bLength < sizeof(*as)) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_AS_GENERAL desc\n", - iface_no, altno); - continue; - } - - num_channels = as->bNrChannels; - format = le32_to_cpu(as->bmFormats); - chconfig = le32_to_cpu(as->bmChannelConfig); - - /* lookup the terminal associated to this interface - * to extract the clock */ - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (input_term) { - clock = input_term->bCSourceID; - if (!chconfig && (num_channels == input_term->bNrChannels)) - chconfig = le32_to_cpu(input_term->bmChannelConfig); - break; - } - - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (output_term) { - clock = output_term->bCSourceID; - break; - } - - dev_err(&dev->dev, - "%u:%d : bogus bTerminalLink %d\n", - iface_no, altno, as->bTerminalLink); - continue; - } - - case UAC_VERSION_3: { - struct uac3_input_terminal_descriptor *input_term; - struct uac3_output_terminal_descriptor *output_term; - struct uac3_as_header_descriptor *as; - struct uac3_cluster_header_descriptor *cluster; - struct uac3_hc_descriptor_header hc_header; - u16 cluster_id, wLength; - - as = snd_usb_find_csint_desc(alts->extra, - alts->extralen, - NULL, UAC_AS_GENERAL); - - if (!as) { - dev_err(&dev->dev, - "%u:%d : UAC_AS_GENERAL descriptor not found\n", - iface_no, altno); - continue; - } - - if (as->bLength < sizeof(*as)) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_AS_GENERAL desc\n", - iface_no, altno); - continue; - } - - cluster_id = le16_to_cpu(as->wClusterDescrID); - if (!cluster_id) { - dev_err(&dev->dev, - "%u:%d : no cluster descriptor\n", - iface_no, altno); - continue; - } - - /* - * Get number of channels and channel map through - * High Capability Cluster Descriptor - * - * First step: get High Capability header and - * read size of Cluster Descriptor - */ - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), - UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - cluster_id, - snd_usb_ctrl_intf(chip), - &hc_header, sizeof(hc_header)); - if (err < 0) - return err; - else if (err != sizeof(hc_header)) { - dev_err(&dev->dev, - "%u:%d : can't get High Capability descriptor\n", - iface_no, altno); - return -EIO; - } - - /* - * Second step: allocate needed amount of memory - * and request Cluster Descriptor - */ - wLength = le16_to_cpu(hc_header.wLength); - cluster = kzalloc(wLength, GFP_KERNEL); - if (!cluster) - return -ENOMEM; - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), - UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - cluster_id, - snd_usb_ctrl_intf(chip), - cluster, wLength); - if (err < 0) { - kfree(cluster); - return err; - } else if (err != wLength) { - dev_err(&dev->dev, - "%u:%d : can't get Cluster Descriptor\n", - iface_no, altno); - kfree(cluster); - return -EIO; - } - - num_channels = cluster->bNrChannels; - chmap_v3 = convert_chmap_v3(cluster); - - kfree(cluster); - - format = le64_to_cpu(as->bmFormats); - - /* lookup the terminal associated to this interface - * to extract the clock */ - input_term = snd_usb_find_input_terminal_descriptor( - chip->ctrl_intf, - as->bTerminalLink); - - if (input_term) { - clock = input_term->bCSourceID; - break; - } - - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (output_term) { - clock = output_term->bCSourceID; - break; - } - - dev_err(&dev->dev, - "%u:%d : bogus bTerminalLink %d\n", - iface_no, altno, as->bTerminalLink); - continue; - } - } - - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - /* get format type */ - fmt = snd_usb_find_csint_desc(alts->extra, - alts->extralen, - NULL, UAC_FORMAT_TYPE); - if (!fmt) { - dev_err(&dev->dev, - "%u:%d : no UAC_FORMAT_TYPE desc\n", - iface_no, altno); - continue; - } - if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) - || ((protocol == UAC_VERSION_2) && - (fmt->bLength < 6))) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_FORMAT_TYPE desc\n", - iface_no, altno); - continue; - } + int bm_quirk = 0; /* * Blue Microphones workaround: The last altsetting is * identical with the previous one, except for a larger * packet size, but is actually a mislabeled two-channel * setting; ignore it. + * + * Part 1: prepare quirk flag */ - if (fmt->bNrChannels == 1 && - fmt->bSubframeSize == 2 && - altno == 2 && num == 3 && + if (altno == 2 && num == 3 && fp && fp->altsetting == 1 && fp->channels == 1 && fp->formats == SNDRV_PCM_FMTBIT_S16_LE && protocol == UAC_VERSION_1 && le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == fp->maxpacksize * 2) - continue; + bm_quirk = 1; + + fp = snd_usb_get_audioformat_uac12(chip, alts, protocol, + iface_no, altno, + stream, bm_quirk); + break; + } + case UAC_VERSION_3: + fp = snd_usb_get_audioformat_uac3(chip, alts, + iface_no, altno, stream); + break; } - fp = kzalloc(sizeof(*fp), GFP_KERNEL); if (!fp) - return -ENOMEM; + continue; + else if (IS_ERR(fp)) + return PTR_ERR(fp); - fp->iface = iface_no; - fp->altsetting = altno; fp->altset_idx = i; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->datainterval = snd_usb_parse_datainterval(chip, alts); - fp->protocol = protocol; - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - fp->channels = num_channels; - if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) - fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) - * (fp->maxpacksize & 0x7ff); - fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); - fp->clock = clock; - INIT_LIST_HEAD(&fp->list); - - /* some quirks for attributes here */ - snd_usb_audioformat_attributes_quirk(chip, fp, stream); - - /* ok, let's parse further... */ - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - if (snd_usb_parse_audio_format(chip, fp, format, - fmt, stream) < 0) { - kfree(fp->rate_table); - kfree(fp); - fp = NULL; - continue; - } - } else { - struct uac3_as_header_descriptor *as; - - as = snd_usb_find_csint_desc(alts->extra, - alts->extralen, - NULL, UAC_AS_GENERAL); - - if (snd_usb_parse_audio_format_v3(chip, fp, as, - stream) < 0) { - kfree(fp->rate_table); - kfree(fp); - fp = NULL; - continue; - } - } - - /* Create chmap */ - if (fp->channels != num_channels) - chconfig = 0; - - if (protocol == UAC_VERSION_3) - fp->chmap = chmap_v3; - else - fp->chmap = convert_chmap(fp->channels, chconfig, - protocol); dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); err = snd_usb_add_audio_stream(chip, stream, fp);