Received: by 10.192.165.148 with SMTP id m20csp4914876imm; Tue, 24 Apr 2018 10:27:15 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+1Qb9uKRC1+MANdugJY3vf/JzY7g4SS1vbxJtX7zOgqYAMKw3Cy/ZUX3adtdwMyrZLfF9T X-Received: by 10.99.124.15 with SMTP id x15mr21386614pgc.308.1524590835591; Tue, 24 Apr 2018 10:27:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524590835; cv=none; d=google.com; s=arc-20160816; b=q0RDn0s1rzB9Bx4AyqRmhKSz0IXwzAZ7hp8vv/tBoD4MZeuhnsqj4FvHg1UKNtIxgb LE0KKzw5l8k3jpKncs6kavlPDylbvC9R1eLzA9tsFfnKphRs8TbQYQr63h+DQVvalrfc 1ctmG9vHHYuk1Y1ATZAu+ha2aRCf35328jxljDo/moo+SGg3yWqK8+gEloM3MAH96NGO 83UHwHkcKvqXTNuBN4kjuBqrTr2hycZG+4im23HAG7ZVUc3YJsa9IFaxmyMjJxw4/m4V ziE2sqhTKkSgFLlhW1YcxMSyiyb8PIo7CcXB0yM3U7BVLqOoMXzlfYhfh0L42kFrXse5 0yYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=oBubmxQyIRqsanFATxlxmJ+9euxXwX1ZdZP2kxuoJpU=; b=jIZxsaV0SlqZn05BoUTaKcuEElpVD8VebIANNiQnQlaq52f/mutGTC4xMv/RVkZLAq Kc0s/95SZEWLSrs+kuNbcZnHDfOEPMIw1Ei5q2JpGePkmbCaqX+R2ntLRN09WO8ICNhH MfBJk6L4VE+TZ/9cBisKY/hewjbUouVUzF1MZjTULth3NjYSCga1/yfJ9tmgYDq4LG8R VyYdSLILnhM8klIku34ckgZG4sdXCibLIJLoUPh71YKh9bNiMnhSrL6ovUZEZMGEDrjX 4ZCcizLDeGmzs/c2TSTo7b+wY5f0cM8ZnYTTfnvToqzMCUBuEWqbPNylaFLQjVOGEoVF cmJQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=codethink.co.uk Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g9si11982862pgc.318.2018.04.24.10.27.01; Tue, 24 Apr 2018 10:27:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=codethink.co.uk Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752625AbeDXRZF (ORCPT + 99 others); Tue, 24 Apr 2018 13:25:05 -0400 Received: from imap1.codethink.co.uk ([176.9.8.82]:46168 "EHLO imap1.codethink.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750841AbeDXRY6 (ORCPT ); Tue, 24 Apr 2018 13:24:58 -0400 Received: from 167-98-27-229.cust-167.exponential-e.net ([167.98.27.229] helo=ct-lt-1121.codethink.co.uk) by imap1.codethink.co.uk with esmtpsa (Exim 4.84_2 #1 (Debian)) id 1fB1gT-0005ev-W6; Tue, 24 Apr 2018 18:24:54 +0100 From: Jorge Sanjuan To: tiwai@suse.com Cc: alsa-devel@alsa-project.org, gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org, Jorge Sanjuan Subject: [PATCH v2 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit. Date: Tue, 24 Apr 2018 18:24:42 +0100 Message-Id: <20180424172445.31928-2-jorge.sanjuan@codethink.co.uk> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180424172445.31928-1-jorge.sanjuan@codethink.co.uk> References: <20180420170327.31569-1-jorge.sanjuan@codethink.co.uk> <20180424172445.31928-1-jorge.sanjuan@codethink.co.uk> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This adds support for the MIXER UNIT in UAC3. All the information is obtained from the (HIGH CAPABILITY) Cluster's header. We don't read the rest of the logical cluster to obtain the channel config as that wont make any difference in the current mixer behaviour. The name of the mixer unit is not yet requested as there is not support for the UAC3 Class Specific String requests. Tested in an UAC3 device working as a HEADSET with a basic mixer unit (same as the one in the BADD spec) with no controls. Signed-off-by: Jorge Sanjuan --- include/uapi/linux/usb/audio.h | 13 +++++-- sound/usb/mixer.c | 87 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index 3a78e7145689..f9be472cd025 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h @@ -285,9 +285,16 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc, int protocol) { - return (protocol == UAC_VERSION_1) ? - &desc->baSourceID[desc->bNrInPins + 4] : - &desc->baSourceID[desc->bNrInPins + 6]; + switch (protocol) { + case UAC_VERSION_1: + return &desc->baSourceID[desc->bNrInPins + 4]; + case UAC_VERSION_2: + return &desc->baSourceID[desc->bNrInPins + 6]; + case UAC_VERSION_3: + return &desc->baSourceID[desc->bNrInPins + 2]; + default: + return NULL; + } } static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 301ad61ed426..bf701b466a4e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm } /* + * Get logical cluster information for UAC3 devices. + */ +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int cluster_id) +{ + struct uac3_cluster_header_descriptor c_header; + int err; + + err = snd_usb_ctl_msg(state->chip->dev, + usb_rcvctrlpipe(state->chip->dev, 0), + UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, + cluster_id, + snd_usb_ctrl_intf(state->chip), + &c_header, sizeof(c_header)); + if (err < 0) + goto error; + if (err != sizeof(c_header)) { + err = -EIO; + goto error; + } + + return c_header.bNrChannels; + +error: + usb_audio_err(state->chip, "cannot request logical cluster ID: %d (err: %d)\n", cluster_id, err); + return err; +} + +/* + * Get number of channels for a Mixer Unit. + */ +static int uac_mixer_unit_get_channels(struct mixer_build *state, + struct uac_mixer_unit_descriptor *desc) +{ + int mu_channels; + + if (desc->bLength < 11) + return -EINVAL; + if (!desc->bNrInPins) + return -EINVAL; + + switch (state->mixer->protocol) { + case UAC_VERSION_1: + case UAC_VERSION_2: + default: + mu_channels = uac_mixer_unit_bNrChannels(desc); + break; + case UAC_VERSION_3: + mu_channels = get_cluster_channels_v3(state, + le16_to_cpu(desc->baSourceID[desc->bNrInPins])); + break; + } + + if (!mu_channels) + return -EINVAL; + + return mu_channels; +} + +/* * parse the source unit recursively until it reaches to a terminal * or a branched unit. */ @@ -865,6 +925,18 @@ static int check_input_term(struct mixer_build *state, int id, term->name = le16_to_cpu(d->wClockSourceStr); return 0; } + case UAC3_MIXER_UNIT: { + struct uac_mixer_unit_descriptor *d = p1; + + err = uac_mixer_unit_get_channels(state, d); + if (err < 0) + return err; + + term->channels = err; + term->type = d->bDescriptorSubtype << 16; /* virtual type */ + + return 0; + } default: return -ENODEV; } @@ -1801,7 +1873,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, struct usb_audio_term *iterm) { struct usb_mixer_elem_info *cval; - unsigned int num_outs = uac_mixer_unit_bNrChannels(desc); + unsigned int num_outs; unsigned int i, len; struct snd_kcontrol *kctl; const struct usbmix_name_map *map; @@ -1814,6 +1886,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, if (!cval) return; + num_outs = uac_mixer_unit_get_channels(state, desc); + if (num_outs < 0) + return; + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->control = in_ch + 1; /* based on 1 */ cval->val_type = USB_MIXER_S16; @@ -1878,14 +1954,17 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, int input_pins, num_ins, num_outs; int pin, ich, err; - if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || - !(num_outs = uac_mixer_unit_bNrChannels(desc))) { + err = uac_mixer_unit_get_channels(state, desc); + if (err < 0) { usb_audio_err(state->chip, "invalid MIXER UNIT descriptor %d\n", unitid); - return -EINVAL; + return err; } + num_outs = err; + input_pins = desc->bNrInPins; + num_ins = 0; ich = 0; for (pin = 0; pin < input_pins; pin++) { -- 2.11.0