From patchwork Tue Jun 22 17:00:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465930 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 8B36FC2B9F4 for ; Tue, 22 Jun 2021 17:02:36 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1AF8E6128C for ; Tue, 22 Jun 2021 17:02:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1AF8E6128C Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 265D7165E; Tue, 22 Jun 2021 19:01:43 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 265D7165E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381353; bh=pz/ux5V8UC0Xrqj0XkIZjjbz8X2oljWdFEzP+cyQd6k=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Eyip0m4/Iw+kKlWSKpSWumAYWEP0nnLRqFI2ZlPthsYLVmWkYaQ8QvBWHSUOc//5E V+Y/oiEAxZuVGvnFB5n5+DwqCtHU6SmQY8XA1VJ+f4EQkb7pOeXUJ67C27/b5BmN8Z FOhw5FMspqmriqYUSv7jjKKRS7yqdGcL3HHDT0Sg= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 527F4F80271; Tue, 22 Jun 2021 19:01:05 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 4014AF80161; Tue, 22 Jun 2021 19:01:04 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 20FC3F800E1 for ; Tue, 22 Jun 2021 19:00:58 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 20FC3F800E1 Received: by m.b4.vu (Postfix, from userid 1000) id B7A1061E286D; Wed, 23 Jun 2021 02:30:49 +0930 (ACST) Date: Wed, 23 Jun 2021 02:30:49 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 01/17] ALSA: usb-audio: scarlett2: Fix wrong resume call Message-ID: <49721219f45b7e175e729b0d9d9c142fd8f4342a.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" From: Takashi Iwai The current way of the scarlett2 mixer code managing the usb_mixer_elem_info object is wrong in two ways: it passes its internal index to the head.id field, and the val_type field is uninitialized. This ended up with the wrong execution at the resume because a bogus unit id is passed wrongly. Also, in the later code extensions, we'll have more mixer elements, and passing the index will overflow the unit id size (of 256). This patch corrects those issues. It introduces a new value type, USB_MIXER_BESPOKEN, which indicates a non-standard mixer element, and use this type for all scarlett2 mixer elements, as well as initializing the fixed unit id 0 for avoiding the overflow. Tested-by: Geoffrey D. Bennett Cc: Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 3 +++ sound/usb/mixer.h | 1 + sound/usb/mixer_scarlett_gen2.c | 7 ++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 428d581f988f..0f578dabd094 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3605,6 +3605,9 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); int c, err, idx; + if (cval->val_type == USB_MIXER_BESPOKEN) + return 0; + if (cval->cmask) { idx = 0; for (c = 0; c < MAX_CHANNELS; c++) { diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index e5a01f17bf3c..ea41e7a1f7bf 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -55,6 +55,7 @@ enum { USB_MIXER_U16, USB_MIXER_S32, USB_MIXER_U32, + USB_MIXER_BESPOKEN, /* non-standard type */ }; typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer, diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index dde008ea21d7..c4689c401d6e 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1136,10 +1136,15 @@ static int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, if (!elem) return -ENOMEM; + /* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code + * ignores them for resume and other operations. + * Also, the head.id field is set to 0, as we don't use this field. + */ elem->head.mixer = mixer; elem->control = index; - elem->head.id = index; + elem->head.id = 0; elem->channels = channels; + elem->val_type = USB_MIXER_BESPOKEN; kctl = snd_ctl_new1(ncontrol, elem); if (!kctl) { From patchwork Tue Jun 22 17:01:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465195 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 188B1C2B9F4 for ; Tue, 22 Jun 2021 17:02:42 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 914D060FE9 for ; Tue, 22 Jun 2021 17:02:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 914D060FE9 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 152711671; Tue, 22 Jun 2021 19:01:50 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 152711671 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381360; bh=S2AvcDNqMkBVmqWCImDDrrScDFigQmW3TcA4CE7WTBU=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=NEUg9Y3CjJOl2AbCaVllkY/CxEhEqwX6NaOJDtdENeNuVAIUVbE4vlRMjhDTKEC9X Ww1HueQtSqmzNF0cJ0JSd7jzjsjNTSjoiErFjMiE6RNR1iiLXNw64Fhk7iYDyh/dCC ycV7NNp2RN/n9rG5EbOpSUA81eu3sDAXY/e9tg1k= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 39946F80424; Tue, 22 Jun 2021 19:01:47 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5830CF804C3; Tue, 22 Jun 2021 19:01:46 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id BED54F80424 for ; Tue, 22 Jun 2021 19:01:39 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz BED54F80424 Received: by m.b4.vu (Postfix, from userid 1000) id 4B77F61E286E; Wed, 23 Jun 2021 02:31:37 +0930 (ACST) Date: Wed, 23 Jun 2021 02:31:37 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 02/17] ALSA: usb-audio: scarlett2: Add Gen 3 mixer support Message-ID: <22d0dc877dec026eb19630edec217ab72ebcd50a.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add mixer support for the Focusrite Scarlett 4i4, 8i6, 18i8, and 18i20 Gen 3 devices. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_quirks.c | 4 + sound/usb/mixer_scarlett_gen2.c | 260 +++++++++++++++++++++++++++++--- 2 files changed, 245 insertions(+), 19 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 37ad77524c0b..df7492594e91 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3060,6 +3060,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */ case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */ case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */ + case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */ + case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ + case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ + case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ err = snd_scarlett_gen2_init(mixer); break; diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index c4689c401d6e..d742c939eed0 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Focusrite Scarlett 6i6/18i8/18i20 Gen 2 Driver for ALSA + * Focusrite Scarlett Gen 2/3 Driver for ALSA * - * Copyright (c) 2018-2019 by Geoffrey D. Bennett + * Supported models: + * - 6i6/18i8/18i20 Gen 2 + * - 4i4/8i6/18i8/18i20 Gen 3 + * + * Copyright (c) 2018-2021 by Geoffrey D. Bennett * * Based on the Scarlett (Gen 1) Driver for ALSA: * @@ -19,10 +23,6 @@ * David Henningsson */ -/* Mixer Interface for the Focusrite Scarlett 6i6/18i8/18i20 Gen 2 audio - * interface. Based on the Gen 1 driver and rewritten. - */ - /* The protocol was reverse engineered by looking at the communication * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20 * (firmware 1083) using usbmon in July-August 2018. @@ -32,13 +32,21 @@ * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann * for providing usbmon output and testing). * + * Scarlett 4i4/8i6 Gen 3 support added in May 2020 (thanks to Laurent + * Debricon for donating a 4i4 and to Fredrik Unger for providing 8i6 + * usbmon output and testing). + * + * Scarlett 18i8/18i20 Gen 3 support added in June 2020 (thanks to + * Darren Jaeckel, Alex Sedlack, and Clovis Lunel for providing usbmon + * output, protocol traces and testing). + * * Support for loading mixer volume and mux configuration from the * interface during driver initialisation added in May 2021 (thanks to * Vladimir Sadovnikov for figuring out how). * * This ALSA mixer gives access to: * - input, output, mixer-matrix muxes - * - 18x10 mixer-matrix gain stages + * - mixer-matrix gain stages * - gain/volume/mute controls * - level meters * - line/inst level and pad controls @@ -148,21 +156,21 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { /* Maximum number of level and pad switches */ #define SCARLETT2_LEVEL_SWITCH_MAX 2 -#define SCARLETT2_PAD_SWITCH_MAX 4 +#define SCARLETT2_PAD_SWITCH_MAX 8 /* Maximum number of inputs to the mixer */ -#define SCARLETT2_INPUT_MIX_MAX 18 +#define SCARLETT2_INPUT_MIX_MAX 25 /* Maximum number of outputs from the mixer */ -#define SCARLETT2_OUTPUT_MIX_MAX 10 +#define SCARLETT2_OUTPUT_MIX_MAX 12 /* Maximum size of the data in the USB mux assignment message: - * 18 inputs, 20 outputs, 18 matrix inputs, 8 spare + * 20 inputs, 20 outputs, 25 matrix inputs, 12 spare */ -#define SCARLETT2_MUX_MAX 64 +#define SCARLETT2_MUX_MAX 77 /* Maximum number of meters (sum of output port counts) */ -#define SCARLETT2_MAX_METERS 56 +#define SCARLETT2_MAX_METERS 65 /* Hardware port types: * - None (no input to mux) @@ -256,7 +264,7 @@ static const struct scarlett2_port scarlett2_ports[SCARLETT2_PORT_TYPE_COUNT] = #define SCARLETT2_MUX_TABLES 3 /* Maximum number of entries in a mux table */ -#define SCARLETT2_MAX_MUX_ENTRIES 7 +#define SCARLETT2_MAX_MUX_ENTRIES 10 /* One entry within mux_assignment defines the port type and range of * ports to add to the set_mux message. The end of the list is marked @@ -475,12 +483,226 @@ static const struct scarlett2_device_info s18i20_gen2_info = { } }, }; +static const struct scarlett2_device_info s4i4_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8212), + + .level_input_count = 2, + .pad_input_count = 2, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + "Headphones L", + "Headphones R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 4, 4 }, + [SCARLETT2_PORT_TYPE_MIX] = { 6, 8 }, + [SCARLETT2_PORT_TYPE_PCM] = { 4, 6 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 16 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 16 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 16 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info s8i6_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8213), + + .level_input_count = 2, + .pad_input_count = 2, + + .line_out_descrs = { + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 6, 4 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_MIX] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_PCM] = { 6, 10 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 18 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 18 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 8 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 18 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info s18i8_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8214), + + .line_out_hw_vol = 1, + .level_input_count = 2, + .pad_input_count = 2, + + .line_out_descrs = { + "Monitor L", + "Monitor R", + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + "Alt Monitor L", + "Alt Monitor R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_ADAT] = { 8, 0 }, + [SCARLETT2_PORT_TYPE_MIX] = { 10, 20 }, + [SCARLETT2_PORT_TYPE_PCM] = { 8, 20 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_PCM, 12, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 6, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 2, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 20 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_PCM, 12, 4 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 6, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 2, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 20 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 6, 2 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 2, 4 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 20 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + } }, +}; + +static const struct scarlett2_device_info s18i20_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8215), + + .line_out_hw_vol = 1, + .level_input_count = 2, + .pad_input_count = 8, + + .line_out_descrs = { + "Monitor 1 L", + "Monitor 1 R", + "Monitor 2 L", + "Monitor 2 R", + NULL, + NULL, + "Headphones 1 L", + "Headphones 1 R", + "Headphones 2 L", + "Headphones 2 R", + }, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 9, 10 }, + [SCARLETT2_PORT_TYPE_SPDIF] = { 2, 2 }, + [SCARLETT2_PORT_TYPE_ADAT] = { 8, 8 }, + [SCARLETT2_PORT_TYPE_MIX] = { 12, 25 }, + [SCARLETT2_PORT_TYPE_PCM] = { 20, 20 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_ADAT, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 25 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 12 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 10, 8 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_ADAT, 0, 8 }, + { SCARLETT2_PORT_TYPE_PCM, 8, 2 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 25 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 10 }, + { 0, 0, 0 }, + }, { + { SCARLETT2_PORT_TYPE_PCM, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 10 }, + { SCARLETT2_PORT_TYPE_SPDIF, 0, 2 }, + { SCARLETT2_PORT_TYPE_NONE, 0, 24 }, + { 0, 0, 0 }, + } }, +}; + static const struct scarlett2_device_info *scarlett2_devices[] = { /* Supported Gen 2 devices */ &s6i6_gen2_info, &s18i8_gen2_info, &s18i20_gen2_info, + /* Supported Gen 3 devices */ + &s4i4_gen3_info, + &s8i6_gen3_info, + &s18i8_gen3_info, + &s18i20_gen3_info, + /* End of list */ NULL }; @@ -674,7 +896,7 @@ static int scarlett2_usb( if (err != req_buf_size) { usb_audio_err( mixer->chip, - "Scarlett Gen 2 USB request result cmd %x was %d\n", + "Scarlett Gen 2/3 USB request result cmd %x was %d\n", cmd, err); err = -EINVAL; goto unlock; @@ -691,7 +913,7 @@ static int scarlett2_usb( if (err != resp_buf_size) { usb_audio_err( mixer->chip, - "Scarlett Gen 2 USB response result cmd %x was %d " + "Scarlett Gen 2/3 USB response result cmd %x was %d " "expected %d\n", cmd, err, resp_buf_size); err = -EINVAL; @@ -709,7 +931,7 @@ static int scarlett2_usb( resp->pad) { usb_audio_err( mixer->chip, - "Scarlett Gen 2 USB invalid response; " + "Scarlett Gen 2/3 USB invalid response; " "cmd tx/rx %d/%d seq %d/%d size %d/%d " "error %d pad %d\n", le32_to_cpu(req->cmd), le32_to_cpu(resp->cmd), @@ -2490,7 +2712,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer) if (!(chip->setup & SCARLETT2_ENABLE)) { usb_audio_info(chip, - "Focusrite Scarlett Gen 2 Mixer Driver disabled; " + "Focusrite Scarlett Gen 2/3 Mixer Driver disabled; " "use options snd_usb_audio vid=0x%04x pid=0x%04x " "device_setup=1 to enable and report any issues " "to g@b4.vu", @@ -2500,7 +2722,7 @@ int snd_scarlett_gen2_init(struct usb_mixer_interface *mixer) } usb_audio_info(chip, - "Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x", + "Focusrite Scarlett Gen 2/3 Mixer Driver enabled pid=0x%04x", USB_ID_PRODUCT(chip->usb_id)); err = snd_scarlett_gen2_controls_create(mixer); From patchwork Tue Jun 22 17:01:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465929 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 974EFC2B9F4 for ; Tue, 22 Jun 2021 17:03:15 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 18AF16054E for ; Tue, 22 Jun 2021 17:03:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 18AF16054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A4648167A; Tue, 22 Jun 2021 19:02:23 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A4648167A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381393; bh=1Uv26hc26a9gxk5XFtA4TNlmxyNQkNJU7xhOJHrSV8k=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=OrDIeKsVMFty/OcP2TxwVPa+ZKSWMHG4Vkk7jxZQNORonlHoLyprqHI3yGxcoO4va fOcfhAK7lFU5GfB45WZYFKmeIqEZ/dwSYIVXS/m0RT8X2UEYO4+n6Zvin5jqHYuV8X gvLqds2Ze/znJGSaOB8VOMrFsDonlXM0YnXw/t3E= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 0F5BBF804D6; Tue, 22 Jun 2021 19:01:55 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5B1DEF804D6; Tue, 22 Jun 2021 19:01:54 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 6DE7EF804C3 for ; Tue, 22 Jun 2021 19:01:47 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 6DE7EF804C3 Received: by m.b4.vu (Postfix, from userid 1000) id F1B4E61E286F; Wed, 23 Jun 2021 02:31:44 +0930 (ACST) Date: Wed, 23 Jun 2021 02:31:44 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 03/17] ALSA: usb-audio: scarlett2: Add support for "input-other" notify Message-ID: <06289a7697455e96b7dbdfd2d384d4b20f8df6e0.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Some models allow the level and pad settings to be controlled from the front-panel of the device. For these, the device will send an "input-other" notification to prompt the driver to re-read the status of those settings. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 99 ++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 26 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index d742c939eed0..06454d4e58bf 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -318,6 +318,7 @@ struct scarlett2_data { u16 scarlett2_seq; u8 sync_updated; u8 vol_updated; + u8 input_other_updated; u8 sync; u8 master_vol; u8 vol[SCARLETT2_ANALOGUE_MAX]; @@ -331,6 +332,8 @@ struct scarlett2_data { struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT]; + struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; + struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -723,9 +726,10 @@ static int scarlett2_get_port_start_num( /*** USB Interactions ***/ /* Notifications from the interface */ -#define SCARLETT2_USB_NOTIFY_SYNC 0x00000008 -#define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000 -#define SCARLETT2_USB_NOTIFY_MONITOR 0x00400000 +#define SCARLETT2_USB_NOTIFY_SYNC 0x00000008 +#define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000 +#define SCARLETT2_USB_NOTIFY_MONITOR 0x00400000 +#define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000 /* Commands for sending/receiving requests/responses */ #define SCARLETT2_USB_CMD_INIT 0 @@ -1745,6 +1749,32 @@ static const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = { /*** Line Level/Instrument Level Switch Controls ***/ +static int scarlett2_update_input_other(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->input_other_updated = 0; + + if (info->level_input_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, + info->level_input_count, private->level_switch); + if (err < 0) + return err; + } + + if (info->pad_input_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PAD_SWITCH, + info->pad_input_count, private->pad_switch); + if (err < 0) + return err; + } + + return 0; +} + static int scarlett2_level_enum_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -1759,10 +1789,16 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_data *private = elem->head.mixer->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); ucontrol->value.enumerated.item[0] = private->level_switch[elem->control]; + mutex_unlock(&private->data_mutex); + return 0; } @@ -1811,10 +1847,16 @@ static int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_data *private = elem->head.mixer->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); ucontrol->value.integer.value[0] = private->pad_switch[elem->control]; + mutex_unlock(&private->data_mutex); + return 0; } @@ -2025,7 +2067,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) for (i = 0; i < info->level_input_count; i++) { snprintf(s, sizeof(s), fmt, i + 1, "Level", "Enum"); err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl, - i, 1, s, NULL); + i, 1, s, &private->level_ctls[i]); if (err < 0) return err; } @@ -2034,7 +2076,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) for (i = 0; i < info->pad_input_count; i++) { snprintf(s, sizeof(s), fmt, i + 1, "Pad", "Switch"); err = scarlett2_add_new_ctl(mixer, &scarlett2_pad_ctl, - i, 1, s, NULL); + i, 1, s, &private->pad_ctls[i]); if (err < 0) return err; } @@ -2446,25 +2488,9 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) struct scarlett2_usb_volume_status volume_status; int err, i; - if (info->level_input_count) { - err = scarlett2_usb_get_config( - mixer, - SCARLETT2_CONFIG_LEVEL_SWITCH, - info->level_input_count, - private->level_switch); - if (err < 0) - return err; - } - - if (info->pad_input_count) { - err = scarlett2_usb_get_config( - mixer, - SCARLETT2_CONFIG_PAD_SWITCH, - info->pad_input_count, - private->pad_switch); - if (err < 0) - return err; - } + err = scarlett2_update_input_other(mixer); + if (err < 0) + return err; err = scarlett2_update_sync(mixer); if (err < 0) @@ -2578,6 +2604,25 @@ static void scarlett2_notify_dim_mute( &private->mute_ctls[i]->id); } +/* Notify on "input other" change (level/pad) */ +static void scarlett2_notify_input_other( + struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int i; + + private->input_other_updated = 1; + + for (i = 0; i < info->level_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->level_ctls[i]->id); + for (i = 0; i < info->pad_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->pad_ctls[i]->id); +} + /* Interrupt callback */ static void scarlett2_notify(struct urb *urb) { @@ -2596,6 +2641,8 @@ static void scarlett2_notify(struct urb *urb) scarlett2_notify_monitor(mixer); if (data & SCARLETT2_USB_NOTIFY_DIM_MUTE) scarlett2_notify_dim_mute(mixer); + if (data & SCARLETT2_USB_NOTIFY_INPUT_OTHER) + scarlett2_notify_input_other(mixer); requeue: if (ustatus != -ENOENT && From patchwork Tue Jun 22 17:01:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465194 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 7D574C2B9F4 for ; Tue, 22 Jun 2021 17:03:46 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8001660FE9 for ; Tue, 22 Jun 2021 17:03:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8001660FE9 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 112A4166E; Tue, 22 Jun 2021 19:02:54 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 112A4166E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381424; bh=uy53UBSqK93zjTXxC1JwL9rGXDuCEmtuJWEU02y4JSE=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=QehCxD/vXLX7IBFF5RsldTqROEhbaGMHJJHEDc/gqIpKI5YJPCF2NHzPmxtjwNnN9 HlssaJWmgZ1GLz0oWV5z910rfuu1pH98ZbXqmQxkLYeE8SGhRgYcS9109lop0Kvb8w qchi3+tZP7Rok5T+nQ5DbXjJPru9h619MRudGfOg= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id C3F97F804E2; Tue, 22 Jun 2021 19:02:03 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 0CF61F804E5; Tue, 22 Jun 2021 19:02:02 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 2620BF804D8 for ; Tue, 22 Jun 2021 19:01:55 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 2620BF804D8 Received: by m.b4.vu (Postfix, from userid 1000) id A58D261E286D; Wed, 23 Jun 2021 02:31:52 +0930 (ACST) Date: Wed, 23 Jun 2021 02:31:52 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 04/17] ALSA: usb-audio: scarlett2: Add Gen 3 MSD mode switch Message-ID: <1cb93bbe585f6b0a74f5dc27450bc87e1f3776dc.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add a control to disable the Gen 3 MSD mode so that the full functionality of the device is available. Don't create the other controls until MSD mode is disabled. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 120 +++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 06454d4e58bf..f35420369042 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -44,12 +44,13 @@ * interface during driver initialisation added in May 2021 (thanks to * Vladimir Sadovnikov for figuring out how). * - * This ALSA mixer gives access to: + * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes * - mixer-matrix gain stages * - gain/volume/mute controls * - level meters * - line/inst level and pad controls + * - disable/enable MSD mode * * * /--------------\ 18chn 20chn /--------------\ @@ -102,6 +103,14 @@ * \--------------/ * * + * Gen 3 devices have a Mass Storage Device (MSD) mode where a small + * disk with registration and driver download information is presented + * to the host. To access the full functionality of the device without + * proprietary software, MSD mode can be disabled by: + * - holding down the 48V button for five seconds while powering on + * the device, or + * - using this driver and alsamixer to change the "MSD Mode" setting + * to Off and power-cycling the device */ #include @@ -120,6 +129,9 @@ /* device_setup value to enable */ #define SCARLETT2_ENABLE 0x01 +/* device_setup value to allow turning MSD mode back on */ +#define SCARLETT2_MSD_ENABLE 0x02 + /* some gui mixers can't handle negative ctl values */ #define SCARLETT2_VOLUME_BIAS 127 @@ -279,6 +291,12 @@ struct scarlett2_mux_entry { struct scarlett2_device_info { u32 usb_id; /* USB device identifier */ + /* Gen 3 devices have an internal MSD mode switch that needs + * to be disabled in order to access the full functionality of + * the device. + */ + u8 has_msd_mode; + /* line out hw volume is sw controlled */ u8 line_out_hw_vol; @@ -327,6 +345,7 @@ struct scarlett2_data { u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; + u8 msd_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; @@ -489,6 +508,7 @@ static const struct scarlett2_device_info s18i20_gen2_info = { static const struct scarlett2_device_info s4i4_gen3_info = { .usb_id = USB_ID(0x1235, 0x8212), + .has_msd_mode = 1, .level_input_count = 2, .pad_input_count = 2, @@ -530,6 +550,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = { static const struct scarlett2_device_info s8i6_gen3_info = { .usb_id = USB_ID(0x1235, 0x8213), + .has_msd_mode = 1, .level_input_count = 2, .pad_input_count = 2, @@ -578,6 +599,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = { static const struct scarlett2_device_info s18i8_gen3_info = { .usb_id = USB_ID(0x1235, 0x8214), + .has_msd_mode = 1, .line_out_hw_vol = 1, .level_input_count = 2, .pad_input_count = 2, @@ -639,6 +661,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = { static const struct scarlett2_device_info s18i20_gen3_info = { .usb_id = USB_ID(0x1235, 0x8215), + .has_msd_mode = 1, .line_out_hw_vol = 1, .level_input_count = 2, .pad_input_count = 8, @@ -786,7 +809,8 @@ enum { SCARLETT2_CONFIG_SW_HW_SWITCH = 3, SCARLETT2_CONFIG_LEVEL_SWITCH = 4, SCARLETT2_CONFIG_PAD_SWITCH = 5, - SCARLETT2_CONFIG_COUNT = 6 + SCARLETT2_CONFIG_MSD_SWITCH = 6, + SCARLETT2_CONFIG_COUNT = 7 }; /* Location, size, and activation command number for the configuration @@ -817,6 +841,9 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_PAD_SWITCH] = { .offset = 0x84, .size = 1, .activate = 8 }, + + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x9d, .size = 1, .activate = 6 }, }; /* proprietary request/response format */ @@ -1016,7 +1043,8 @@ static int scarlett2_usb_set_config( return err; /* Schedule the change to be written to NVRAM */ - schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); + if (config_item->activate != SCARLETT2_USB_CONFIG_SAVE) + schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); return 0; } @@ -2351,6 +2379,71 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) "Level Meter", NULL); } +/*** MSD Controls ***/ + +static int scarlett2_msd_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->msd_switch; + return 0; +} + +static int scarlett2_msd_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->msd_switch; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->msd_switch = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_MSD_SWITCH, + 0, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_msd_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_msd_ctl_get, + .put = scarlett2_msd_ctl_put, +}; + +static int scarlett2_add_msd_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + if (!info->has_msd_mode) + return 0; + + /* If MSD mode is off, hide the switch by default */ + if (!private->msd_switch && !(mixer->chip->setup & SCARLETT2_MSD_ENABLE)) + return 0; + + /* Add MSD control */ + return scarlett2_add_new_ctl(mixer, &scarlett2_msd_ctl, + 0, 1, "MSD Mode", NULL); +} + /*** Cleanup/Suspend Callbacks ***/ static void scarlett2_private_free(struct usb_mixer_interface *mixer) @@ -2488,6 +2581,18 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) struct scarlett2_usb_volume_status volume_status; int err, i; + if (info->has_msd_mode) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MSD_SWITCH, + 1, &private->msd_switch); + if (err < 0) + return err; + + /* no other controls are created if MSD mode is on */ + if (private->msd_switch) + return 0; + } + err = scarlett2_update_input_other(mixer); if (err < 0) return err; @@ -2710,6 +2815,15 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) if (err < 0) return err; + /* Create the MSD control */ + err = scarlett2_add_msd_ctl(mixer); + if (err < 0) + return err; + + /* If MSD mode is enabled, don't create any other controls */ + if (((struct scarlett2_data *)mixer->private_data)->msd_switch) + return 0; + /* Create the analogue output controls */ err = scarlett2_add_line_out_ctls(mixer); if (err < 0) From patchwork Tue Jun 22 17:02:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465928 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 2871CC2B9F4 for ; Tue, 22 Jun 2021 17:04:06 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A05FD6054E for ; Tue, 22 Jun 2021 17:04:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A05FD6054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 33E98166B; Tue, 22 Jun 2021 19:03:14 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 33E98166B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381444; bh=P4NxamtGL4Q6Rkyv1pK2MSFiVUtdTDl6AXcan80CgiA=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=VgqCn/jP2/XJ9ms7K4EWC41y+vEIt2+Adzi6KpR8B1OYYQX3ZvOLIb7pFinklWTzk sug4fMFmWNdyDBJ228jqvS+DiVR6pXghXHBrs5bPH0OUCaWYR17ykTj4YrkaoLCbqe CDQ/B+5FIZZjAxSr5VzDC8wovaqbBDln091JSrb4= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id C3C84F804E7; Tue, 22 Jun 2021 19:02:16 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id E5CA0F804EB; Tue, 22 Jun 2021 19:02:14 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 535EDF804E6 for ; Tue, 22 Jun 2021 19:02:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 535EDF804E6 Received: by m.b4.vu (Postfix, from userid 1000) id 316A061E286D; Wed, 23 Jun 2021 02:32:09 +0930 (ACST) Date: Wed, 23 Jun 2021 02:32:09 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 05/17] ALSA: usb-audio: scarlett2: Move get config above set config Message-ID: <1549f8e44548be679119f0b1462f888f4a03812d.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Move scarlett2_usb_get() and scarlett2_usb_get_config() above the functions relating to updating the configuration so that scarlett2_usb_set_config() can call scarlett2_usb_get() in a subsequent patch. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 56 ++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index f35420369042..7a5346c68603 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -985,6 +985,34 @@ static int scarlett2_usb( return err; } +/* Send a USB message to get data; result placed in *buf */ +static int scarlett2_usb_get( + struct usb_mixer_interface *mixer, + int offset, void *buf, int size) +{ + struct { + __le32 offset; + __le32 size; + } __packed req; + + req.offset = cpu_to_le32(offset); + req.size = cpu_to_le32(size); + return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA, + &req, sizeof(req), buf, size); +} + +/* Send a USB message to get configuration parameters; result placed in *buf */ +static int scarlett2_usb_get_config( + struct usb_mixer_interface *mixer, + int config_item_num, int count, void *buf) +{ + const struct scarlett2_config *config_item = + &scarlett2_config_items[config_item_num]; + int size = config_item->size * count; + + return scarlett2_usb_get(mixer, config_item->offset, buf, size); +} + /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ static void scarlett2_config_save(struct usb_mixer_interface *mixer) { @@ -1049,34 +1077,6 @@ static int scarlett2_usb_set_config( return 0; } -/* Send a USB message to get data; result placed in *buf */ -static int scarlett2_usb_get( - struct usb_mixer_interface *mixer, - int offset, void *buf, int size) -{ - struct { - __le32 offset; - __le32 size; - } __packed req; - - req.offset = cpu_to_le32(offset); - req.size = cpu_to_le32(size); - return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA, - &req, sizeof(req), buf, size); -} - -/* Send a USB message to get configuration parameters; result placed in *buf */ -static int scarlett2_usb_get_config( - struct usb_mixer_interface *mixer, - int config_item_num, int count, void *buf) -{ - const struct scarlett2_config *config_item = - &scarlett2_config_items[config_item_num]; - int size = config_item->size * count; - - return scarlett2_usb_get(mixer, config_item->offset, buf, size); -} - /* Send a USB message to get sync status; result placed in *sync */ static int scarlett2_usb_get_sync_status( struct usb_mixer_interface *mixer, From patchwork Tue Jun 22 17:02:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465193 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 188A5C2B9F4 for ; Tue, 22 Jun 2021 17:04:24 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 874C660FE9 for ; Tue, 22 Jun 2021 17:04:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 874C660FE9 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 1BE971674; Tue, 22 Jun 2021 19:03:32 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 1BE971674 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381462; bh=IDwnmqQoeDlhe6gRYHC758tw7Ig1qOJWldr3RNoUhCg=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=l0Yh0lUdMk3i0Db4nwK6/md9Mn+I2GlzQ4Sj17o+W5Q9qD/H09Ak5DPmVHz5ELUfz GBOF1D84oTVyJhikKg0v/Paj6dTQY+wM+cwFFG+/jIExUCybf1X0/q163YCsj6yYMB noljzFcu2+suyuc6UbQxE9BBqquZ2j/PLhd10A6Q= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 6F310F8026A; Tue, 22 Jun 2021 19:02:35 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 600DAF804C3; Tue, 22 Jun 2021 19:02:34 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 81ECBF804C3 for ; Tue, 22 Jun 2021 19:02:27 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 81ECBF804C3 Received: by m.b4.vu (Postfix, from userid 1000) id 112CB61E286D; Wed, 23 Jun 2021 02:32:25 +0930 (ACST) Date: Wed, 23 Jun 2021 02:32:25 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 06/17] ALSA: usb-audio: scarlett2: Allow bit-level access to config Message-ID: <4e54e9e106ec7029c1a668c51b4fc769a7eb4ed0.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add support for accessing configuration values when multiple values are stored in one byte. Needed by the upcoming Solo and 2i2 Gen 3 support. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 68 ++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 7a5346c68603..08e7b687484e 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -814,7 +814,7 @@ enum { }; /* Location, size, and activation command number for the configuration - * parameters + * parameters. Size is in bits and may be 1, 8, or 16. */ struct scarlett2_config { u8 offset; @@ -825,25 +825,25 @@ struct scarlett2_config { static const struct scarlett2_config scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = { [SCARLETT2_CONFIG_DIM_MUTE] = { - .offset = 0x31, .size = 1, .activate = 2 }, + .offset = 0x31, .size = 8, .activate = 2 }, [SCARLETT2_CONFIG_LINE_OUT_VOLUME] = { - .offset = 0x34, .size = 2, .activate = 1 }, + .offset = 0x34, .size = 16, .activate = 1 }, [SCARLETT2_CONFIG_MUTE_SWITCH] = { - .offset = 0x5c, .size = 1, .activate = 1 }, + .offset = 0x5c, .size = 8, .activate = 1 }, [SCARLETT2_CONFIG_SW_HW_SWITCH] = { - .offset = 0x66, .size = 1, .activate = 3 }, + .offset = 0x66, .size = 8, .activate = 3 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x7c, .size = 1, .activate = 7 }, + .offset = 0x7c, .size = 8, .activate = 7 }, [SCARLETT2_CONFIG_PAD_SWITCH] = { - .offset = 0x84, .size = 1, .activate = 8 }, + .offset = 0x84, .size = 8, .activate = 8 }, [SCARLETT2_CONFIG_MSD_SWITCH] = { - .offset = 0x9d, .size = 1, .activate = 6 }, + .offset = 0x9d, .size = 8, .activate = 6 }, }; /* proprietary request/response format */ @@ -1008,9 +1008,25 @@ static int scarlett2_usb_get_config( { const struct scarlett2_config *config_item = &scarlett2_config_items[config_item_num]; - int size = config_item->size * count; + int size, err, i; + u8 value; - return scarlett2_usb_get(mixer, config_item->offset, buf, size); + /* For byte-sized parameters, retrieve directly into buf */ + if (config_item->size >= 8) { + size = config_item->size / 8 * count; + return scarlett2_usb_get(mixer, config_item->offset, buf, size); + } + + /* For bit-sized parameters, retrieve into value */ + err = scarlett2_usb_get(mixer, config_item->offset, &value, 1); + if (err < 0) + return err; + + /* then unpack from value into buf[] */ + for (i = 0; i < 8 && i < count; i++, value >>= 1) + *(u8 *)buf++ = value & 1; + + return 0; } /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ @@ -1047,18 +1063,44 @@ static int scarlett2_usb_set_config( __le32 value; } __packed req; __le32 req2; + int offset, size; int err; struct scarlett2_data *private = mixer->private_data; /* Cancel any pending NVRAM save */ cancel_delayed_work_sync(&private->work); + /* Convert config_item->size in bits to size in bytes and + * calculate offset + */ + if (config_item->size >= 8) { + size = config_item->size / 8; + offset = config_item->offset + index * size; + + /* If updating a bit, retrieve the old value, set/clear the + * bit as needed, and update value + */ + } else { + u8 tmp; + + size = 1; + offset = config_item->offset; + + scarlett2_usb_get(mixer, offset, &tmp, 1); + if (value) + tmp |= (1 << index); + else + tmp &= ~(1 << index); + + value = tmp; + } + /* Send the configuration parameter data */ - req.offset = cpu_to_le32(config_item->offset + index * config_item->size); - req.bytes = cpu_to_le32(config_item->size); + req.offset = cpu_to_le32(offset); + req.bytes = cpu_to_le32(size); req.value = cpu_to_le32(value); err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA, - &req, sizeof(u32) * 2 + config_item->size, + &req, sizeof(u32) * 2 + size, NULL, 0); if (err < 0) return err; From patchwork Tue Jun 22 17:02:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465927 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 DDFEDC2B9F4 for ; Tue, 22 Jun 2021 17:04:44 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 62C706054E for ; Tue, 22 Jun 2021 17:04:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 62C706054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 0823C1683; Tue, 22 Jun 2021 19:03:53 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 0823C1683 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381483; bh=JeIJF9cr34zk6UA82PlAV6irjOyoINjRl4auQMxO1gI=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=kkS3QglT0m6ca2BcCtIvYTVGTiodgWUivuXxw9yY+1g0yH3FjwZyEhkeGPkDLowTM U9OfCfM04UPLDoD/VamnvawGSVwg5pfK1Itov5FQt+EUpRpmzYEFRyoGeqF4KPEBHP OrjFYq9ppQGiPcLTXx2TuJC0aKh8oVuzz9wSME5I= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 30AE3F804EB; Tue, 22 Jun 2021 19:02:39 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id C121EF804E0; Tue, 22 Jun 2021 19:02:37 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 6D2B6F804C3 for ; Tue, 22 Jun 2021 19:02:34 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 6D2B6F804C3 Received: by m.b4.vu (Postfix, from userid 1000) id E700061E286E; Wed, 23 Jun 2021 02:32:31 +0930 (ACST) Date: Wed, 23 Jun 2021 02:32:31 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 07/17] ALSA: usb-audio: scarlett2: Add support for Solo and 2i2 Gen 3 Message-ID: <190b90f6f1f8f8d4dfb5f0a7761ff8ae5c40fdde.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add initial support for the Focusrite Scarlett Solo and 2i2 devices: - They have no mixer - They don't support reporting sync status or levels - The configuration space is laid out differently to the other models - There is no level (line/inst) switch on input 1 of the Solo Co-developed-by: Vladimir Sadovnikov Signed-off-by: Vladimir Sadovnikov Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_quirks.c | 2 + sound/usb/mixer_scarlett_gen2.c | 94 ++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 12 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index df7492594e91..0a3cb8fd7d00 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3060,6 +3060,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */ case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */ case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */ + case USB_ID(0x1235, 0x8211): /* Focusrite Scarlett Solo 3rd Gen */ + case USB_ID(0x1235, 0x8210): /* Focusrite Scarlett 2i2 3rd Gen */ case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */ case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 08e7b687484e..0a56211a65ab 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -4,9 +4,10 @@ * * Supported models: * - 6i6/18i8/18i20 Gen 2 - * - 4i4/8i6/18i8/18i20 Gen 3 + * - Solo/2i2/4i4/8i6/18i8/18i20 Gen 3 * * Copyright (c) 2018-2021 by Geoffrey D. Bennett + * Copyright (c) 2020-2021 by Vladimir Sadovnikov * * Based on the Scarlett (Gen 1) Driver for ALSA: * @@ -44,6 +45,9 @@ * interface during driver initialisation added in May 2021 (thanks to * Vladimir Sadovnikov for figuring out how). * + * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander + * Vorona for 2i2 protocol traces). + * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes * - mixer-matrix gain stages @@ -297,6 +301,11 @@ struct scarlett2_device_info { */ u8 has_msd_mode; + /* Gen 3 devices without a mixer have a different + * configuration set + */ + u8 has_mixer; + /* line out hw volume is sw controlled */ u8 line_out_hw_vol; @@ -305,6 +314,9 @@ struct scarlett2_device_info { */ u8 level_input_count; + /* the first input with a level control (0-based) */ + u8 level_input_first; + /* the number of analogue inputs with a software switchable * 10dB pad control */ @@ -362,6 +374,7 @@ struct scarlett2_data { static const struct scarlett2_device_info s6i6_gen2_info = { .usb_id = USB_ID(0x1235, 0x8203), + .has_mixer = 1, .level_input_count = 2, .pad_input_count = 2, @@ -407,6 +420,7 @@ static const struct scarlett2_device_info s6i6_gen2_info = { static const struct scarlett2_device_info s18i8_gen2_info = { .usb_id = USB_ID(0x1235, 0x8204), + .has_mixer = 1, .level_input_count = 2, .pad_input_count = 4, @@ -455,6 +469,7 @@ static const struct scarlett2_device_info s18i8_gen2_info = { static const struct scarlett2_device_info s18i20_gen2_info = { .usb_id = USB_ID(0x1235, 0x8201), + .has_mixer = 1, .line_out_hw_vol = 1, .line_out_descrs = { @@ -505,10 +520,26 @@ static const struct scarlett2_device_info s18i20_gen2_info = { } }, }; +static const struct scarlett2_device_info solo_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8211), + + .has_msd_mode = 1, + .level_input_count = 1, + .level_input_first = 1, +}; + +static const struct scarlett2_device_info s2i2_gen3_info = { + .usb_id = USB_ID(0x1235, 0x8210), + + .has_msd_mode = 1, + .level_input_count = 2, +}; + static const struct scarlett2_device_info s4i4_gen3_info = { .usb_id = USB_ID(0x1235, 0x8212), .has_msd_mode = 1, + .has_mixer = 1, .level_input_count = 2, .pad_input_count = 2, @@ -551,6 +582,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = { .usb_id = USB_ID(0x1235, 0x8213), .has_msd_mode = 1, + .has_mixer = 1, .level_input_count = 2, .pad_input_count = 2, @@ -600,6 +632,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .usb_id = USB_ID(0x1235, 0x8214), .has_msd_mode = 1, + .has_mixer = 1, .line_out_hw_vol = 1, .level_input_count = 2, .pad_input_count = 2, @@ -662,6 +695,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .usb_id = USB_ID(0x1235, 0x8215), .has_msd_mode = 1, + .has_mixer = 1, .line_out_hw_vol = 1, .level_input_count = 2, .pad_input_count = 8, @@ -724,6 +758,8 @@ static const struct scarlett2_device_info *scarlett2_devices[] = { &s18i20_gen2_info, /* Supported Gen 3 devices */ + &solo_gen3_info, + &s2i2_gen3_info, &s4i4_gen3_info, &s8i6_gen3_info, &s18i8_gen3_info, @@ -776,7 +812,7 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31 #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 -/* volume status is read together (matches scarlett2_config_items[]) */ +/* volume status is read together (matches scarlett2_config_items[1]) */ struct scarlett2_usb_volume_status { /* dim/mute buttons */ u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; @@ -822,8 +858,22 @@ struct scarlett2_config { u8 activate; }; +/* scarlett2_config_items[0] is for devices without a mixer + * scarlett2_config_items[1] is for devices with a mixer + */ static const struct scarlett2_config - scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = { + scarlett2_config_items[2][SCARLETT2_CONFIG_COUNT] = + +/* Devices without a mixer (Solo and 2i2 Gen 3) */ +{ { + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x04, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { + .offset = 0x08, .size = 1, .activate = 7 }, + +/* Devices with a mixer (Gen 2 and all other Gen 3) */ +}, { [SCARLETT2_CONFIG_DIM_MUTE] = { .offset = 0x31, .size = 8, .activate = 2 }, @@ -844,7 +894,7 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x9d, .size = 8, .activate = 6 }, -}; +} }; /* proprietary request/response format */ struct scarlett2_usb_packet { @@ -1006,8 +1056,10 @@ static int scarlett2_usb_get_config( struct usb_mixer_interface *mixer, int config_item_num, int count, void *buf) { + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; const struct scarlett2_config *config_item = - &scarlett2_config_items[config_item_num]; + &scarlett2_config_items[info->has_mixer][config_item_num]; int size, err, i; u8 value; @@ -1055,8 +1107,10 @@ static int scarlett2_usb_set_config( struct usb_mixer_interface *mixer, int config_item_num, int index, int value) { + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; const struct scarlett2_config *config_item = - &scarlett2_config_items[config_item_num]; + &scarlett2_config_items[info->has_mixer][config_item_num]; struct { __le32 offset; __le32 bytes; @@ -1065,7 +1119,6 @@ static int scarlett2_usb_set_config( __le32 req2; int offset, size; int err; - struct scarlett2_data *private = mixer->private_data; /* Cancel any pending NVRAM save */ cancel_delayed_work_sync(&private->work); @@ -1511,6 +1564,10 @@ static int scarlett2_add_sync_ctl(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; + /* devices without a mixer also don't support reporting sync status */ + if (!private->info->has_mixer) + return 0; + return scarlett2_add_new_ctl(mixer, &scarlett2_sync_ctl, 0, 1, "Sync Status", &private->sync_ctl); } @@ -1829,7 +1886,8 @@ static int scarlett2_update_input_other(struct usb_mixer_interface *mixer) if (info->level_input_count) { int err = scarlett2_usb_get_config( mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, - info->level_input_count, private->level_switch); + info->level_input_count + info->level_input_first, + private->level_switch); if (err < 0) return err; } @@ -1861,12 +1919,14 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + int index = elem->control + info->level_input_first; mutex_lock(&private->data_mutex); if (private->input_other_updated) scarlett2_update_input_other(mixer); - ucontrol->value.enumerated.item[0] = - private->level_switch[elem->control]; + ucontrol->value.enumerated.item[0] = private->level_switch[index]; mutex_unlock(&private->data_mutex); return 0; @@ -1878,8 +1938,9 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; - int index = elem->control; + int index = elem->control + info->level_input_first; int oval, val, err = 0; mutex_lock(&private->data_mutex); @@ -2135,7 +2196,8 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) /* Add input level (line/inst) controls */ for (i = 0; i < info->level_input_count; i++) { - snprintf(s, sizeof(s), fmt, i + 1, "Level", "Enum"); + snprintf(s, sizeof(s), fmt, i + 1 + info->level_input_first, + "Level", "Enum"); err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl, i, 1, s, &private->level_ctls[i]); if (err < 0) @@ -2416,6 +2478,10 @@ static int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; + /* devices without a mixer also don't support reporting levels */ + if (!private->info->has_mixer) + return 0; + return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl, 0, private->num_mux_dsts, "Level Meter", NULL); @@ -2639,6 +2705,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) if (err < 0) return err; + /* the rest of the configuration is for devices with a mixer */ + if (!info->has_mixer) + return 0; + err = scarlett2_update_sync(mixer); if (err < 0) return err; From patchwork Tue Jun 22 17:02:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465192 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 A7815C2B9F4 for ; Tue, 22 Jun 2021 17:05:16 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3036F61358 for ; Tue, 22 Jun 2021 17:05:16 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3036F61358 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id B85E91675; Tue, 22 Jun 2021 19:04:24 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz B85E91675 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381514; bh=yjaAXGMGdUTCVlfLPhzELS0zy9TQYPT0XEfZEiR4H/o=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=rjlw6nxoJCsdLPHNpIZGSyNi0WX9hnpzW1eUrm1ocrHVUCnqC+MQQvGoZN6U/tnwi 0+yXYmlDpoAU3R807IlDyB7waT+0+Xn4JgBTPHngvpnDF3nnKf+2fCQ6i4risHGIvQ nknDwFsbbqoZD6AQB+NqM8p21Ywm592S8Hj0IlOw= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id A5CBCF804FD; Tue, 22 Jun 2021 19:02:43 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 3E849F804FE; Tue, 22 Jun 2021 19:02:42 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E63FEF804F3 for ; Tue, 22 Jun 2021 19:02:38 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E63FEF804F3 Received: by m.b4.vu (Postfix, from userid 1000) id 7487F61E286F; Wed, 23 Jun 2021 02:32:36 +0930 (ACST) Date: Wed, 23 Jun 2021 02:32:36 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 08/17] ALSA: usb-audio: scarlett2: Add "air" switch support Message-ID: <44d448a4150b9c068754759c9fdd2bfe21484487.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Some inputs on Gen 3 models have an "air" feature which can be enabled from the driver or (model-dependent) from the front panel. Add support for getting and setting the state of those switches. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 106 ++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 6 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 0a56211a65ab..696d9703436a 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -53,7 +53,7 @@ * - mixer-matrix gain stages * - gain/volume/mute controls * - level meters - * - line/inst level and pad controls + * - line/inst level, pad, and air controls * - disable/enable MSD mode * * @@ -173,6 +173,7 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { /* Maximum number of level and pad switches */ #define SCARLETT2_LEVEL_SWITCH_MAX 2 #define SCARLETT2_PAD_SWITCH_MAX 8 +#define SCARLETT2_AIR_SWITCH_MAX 8 /* Maximum number of inputs to the mixer */ #define SCARLETT2_INPUT_MIX_MAX 25 @@ -322,6 +323,11 @@ struct scarlett2_device_info { */ u8 pad_input_count; + /* the number of analogue inputs with a software switchable + * "air" control + */ + u8 air_input_count; + /* additional description for the line out volume controls */ const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; @@ -357,6 +363,7 @@ struct scarlett2_data { u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; + u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; u8 msd_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -365,6 +372,7 @@ struct scarlett2_data { struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT]; struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; + struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -526,6 +534,7 @@ static const struct scarlett2_device_info solo_gen3_info = { .has_msd_mode = 1, .level_input_count = 1, .level_input_first = 1, + .air_input_count = 1, }; static const struct scarlett2_device_info s2i2_gen3_info = { @@ -533,6 +542,7 @@ static const struct scarlett2_device_info s2i2_gen3_info = { .has_msd_mode = 1, .level_input_count = 2, + .air_input_count = 2, }; static const struct scarlett2_device_info s4i4_gen3_info = { @@ -542,6 +552,7 @@ static const struct scarlett2_device_info s4i4_gen3_info = { .has_mixer = 1, .level_input_count = 2, .pad_input_count = 2, + .air_input_count = 2, .line_out_descrs = { "Monitor L", @@ -585,6 +596,7 @@ static const struct scarlett2_device_info s8i6_gen3_info = { .has_mixer = 1, .level_input_count = 2, .pad_input_count = 2, + .air_input_count = 2, .line_out_descrs = { "Headphones 1 L", @@ -636,6 +648,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .line_out_hw_vol = 1, .level_input_count = 2, .pad_input_count = 2, + .air_input_count = 4, .line_out_descrs = { "Monitor L", @@ -699,6 +712,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .line_out_hw_vol = 1, .level_input_count = 2, .pad_input_count = 8, + .air_input_count = 8, .line_out_descrs = { "Monitor 1 L", @@ -846,7 +860,8 @@ enum { SCARLETT2_CONFIG_LEVEL_SWITCH = 4, SCARLETT2_CONFIG_PAD_SWITCH = 5, SCARLETT2_CONFIG_MSD_SWITCH = 6, - SCARLETT2_CONFIG_COUNT = 7 + SCARLETT2_CONFIG_AIR_SWITCH = 7, + SCARLETT2_CONFIG_COUNT = 8 }; /* Location, size, and activation command number for the configuration @@ -872,6 +887,9 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_LEVEL_SWITCH] = { .offset = 0x08, .size = 1, .activate = 7 }, + [SCARLETT2_CONFIG_AIR_SWITCH] = { + .offset = 0x09, .size = 1, .activate = 8 }, + /* Devices with a mixer (Gen 2 and all other Gen 3) */ }, { [SCARLETT2_CONFIG_DIM_MUTE] = { @@ -892,6 +910,9 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_PAD_SWITCH] = { .offset = 0x84, .size = 8, .activate = 8 }, + [SCARLETT2_CONFIG_AIR_SWITCH] = { + .offset = 0x8c, .size = 8, .activate = 8 }, + [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x9d, .size = 8, .activate = 6 }, } }; @@ -1100,9 +1121,7 @@ static void scarlett2_config_save_work(struct work_struct *work) scarlett2_config_save(private->mixer); } -/* Send a USB message to set a configuration parameter (volume level, - * sw/hw volume switch, line/inst level switch, or pad switch) - */ +/* Send a USB message to set a SCARLETT2_CONFIG_* parameter */ static int scarlett2_usb_set_config( struct usb_mixer_interface *mixer, int config_item_num, int index, int value) @@ -1900,6 +1919,14 @@ static int scarlett2_update_input_other(struct usb_mixer_interface *mixer) return err; } + if (info->air_input_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_AIR_SWITCH, + info->air_input_count, private->air_switch); + if (err < 0) + return err; + } + return 0; } @@ -2030,6 +2057,61 @@ static const struct snd_kcontrol_new scarlett2_pad_ctl = { .put = scarlett2_pad_ctl_put, }; +/*** Air Switch Controls ***/ + +static int scarlett2_air_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); + ucontrol->value.integer.value[0] = private->air_switch[elem->control]; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->air_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->air_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_AIR_SWITCH, + index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_air_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_air_ctl_get, + .put = scarlett2_air_ctl_put, +}; + /*** Dim/Mute Controls ***/ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, @@ -2213,6 +2295,15 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) return err; } + /* Add input air controls */ + for (i = 0; i < info->air_input_count; i++) { + snprintf(s, sizeof(s), fmt, i + 1, "Air", "Switch"); + err = scarlett2_add_new_ctl(mixer, &scarlett2_air_ctl, + i, 1, s, &private->air_ctls[i]); + if (err < 0) + return err; + } + return 0; } @@ -2821,7 +2912,7 @@ static void scarlett2_notify_dim_mute( &private->mute_ctls[i]->id); } -/* Notify on "input other" change (level/pad) */ +/* Notify on "input other" change (level/pad/air) */ static void scarlett2_notify_input_other( struct usb_mixer_interface *mixer) { @@ -2838,6 +2929,9 @@ static void scarlett2_notify_input_other( for (i = 0; i < info->pad_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->pad_ctls[i]->id); + for (i = 0; i < info->air_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->air_ctls[i]->id); } /* Interrupt callback */ From patchwork Tue Jun 22 17:02:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465926 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 7A0E7C2B9F4 for ; Tue, 22 Jun 2021 17:05:35 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9F5CA6054E for ; Tue, 22 Jun 2021 17:05:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9F5CA6054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3B07B1689; Tue, 22 Jun 2021 19:04:43 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3B07B1689 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381533; bh=W28cl9AYmaGHLqW8is47jipNJPsznQ1iAvxRadPUjm0=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=GeB+U/P68STGL/oHM+SUqU4SJfhDcCooIgUsp/+eTlbLH0ehI+Nla22Ek885eHnoz /Tx22V1nXZoWtq0A8tBSkqG87YwYeCNAydOJha3exmGXFJymtUe2nG/+B2tOZiVkYL 1smbM97os/vRW6D+y2ZO1RGa9O8sk5g9dbg8vIEI= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 94DC9F804FF; Tue, 22 Jun 2021 19:02:47 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id B32D3F804FF; Tue, 22 Jun 2021 19:02:46 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 28C50F80506 for ; Tue, 22 Jun 2021 19:02:43 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 28C50F80506 Received: by m.b4.vu (Postfix, from userid 1000) id A91AB61E287C; Wed, 23 Jun 2021 02:32:40 +0930 (ACST) Date: Wed, 23 Jun 2021 02:32:40 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 09/17] ALSA: usb-audio: scarlett2: Add phantom power switch support Message-ID: <5837ce8a8c686560fc8f40b4204dd2a10721869b.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Some inputs on Gen 3 models support software-selectable phantom power. Add support for getting and setting the state of those switches and the "Phantom Power Persistence" switch. Co-developed-by: Vladimir Sadovnikov Signed-off-by: Vladimir Sadovnikov Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 197 +++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 696d9703436a..bc4f29cfb2f3 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -48,12 +48,15 @@ * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander * Vorona for 2i2 protocol traces). * + * Support for phantom power added in May 2021. + * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes * - mixer-matrix gain stages * - gain/volume/mute controls * - level meters * - line/inst level, pad, and air controls + * - phantom power controls * - disable/enable MSD mode * * @@ -174,6 +177,7 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { #define SCARLETT2_LEVEL_SWITCH_MAX 2 #define SCARLETT2_PAD_SWITCH_MAX 8 #define SCARLETT2_AIR_SWITCH_MAX 8 +#define SCARLETT2_PHANTOM_SWITCH_MAX 2 /* Maximum number of inputs to the mixer */ #define SCARLETT2_INPUT_MIX_MAX 25 @@ -328,6 +332,12 @@ struct scarlett2_device_info { */ u8 air_input_count; + /* the number of phantom (48V) software switchable controls */ + u8 phantom_count; + + /* the number of inputs each phantom switch controls */ + u8 inputs_per_phantom; + /* additional description for the line out volume controls */ const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; @@ -364,6 +374,8 @@ struct scarlett2_data { u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; + u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; + u8 phantom_persistence; u8 msd_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -373,6 +385,7 @@ struct scarlett2_data { struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; + struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -535,6 +548,8 @@ static const struct scarlett2_device_info solo_gen3_info = { .level_input_count = 1, .level_input_first = 1, .air_input_count = 1, + .phantom_count = 1, + .inputs_per_phantom = 1, }; static const struct scarlett2_device_info s2i2_gen3_info = { @@ -543,6 +558,8 @@ static const struct scarlett2_device_info s2i2_gen3_info = { .has_msd_mode = 1, .level_input_count = 2, .air_input_count = 2, + .phantom_count = 1, + .inputs_per_phantom = 2, }; static const struct scarlett2_device_info s4i4_gen3_info = { @@ -553,6 +570,8 @@ static const struct scarlett2_device_info s4i4_gen3_info = { .level_input_count = 2, .pad_input_count = 2, .air_input_count = 2, + .phantom_count = 1, + .inputs_per_phantom = 2, .line_out_descrs = { "Monitor L", @@ -597,6 +616,8 @@ static const struct scarlett2_device_info s8i6_gen3_info = { .level_input_count = 2, .pad_input_count = 2, .air_input_count = 2, + .phantom_count = 1, + .inputs_per_phantom = 2, .line_out_descrs = { "Headphones 1 L", @@ -649,6 +670,8 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .level_input_count = 2, .pad_input_count = 2, .air_input_count = 4, + .phantom_count = 2, + .inputs_per_phantom = 2, .line_out_descrs = { "Monitor L", @@ -713,6 +736,8 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .level_input_count = 2, .pad_input_count = 8, .air_input_count = 8, + .phantom_count = 2, + .inputs_per_phantom = 4, .line_out_descrs = { "Monitor 1 L", @@ -861,7 +886,9 @@ enum { SCARLETT2_CONFIG_PAD_SWITCH = 5, SCARLETT2_CONFIG_MSD_SWITCH = 6, SCARLETT2_CONFIG_AIR_SWITCH = 7, - SCARLETT2_CONFIG_COUNT = 8 + SCARLETT2_CONFIG_PHANTOM_SWITCH = 8, + SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9, + SCARLETT2_CONFIG_COUNT = 10 }; /* Location, size, and activation command number for the configuration @@ -884,6 +911,12 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x04, .size = 8, .activate = 6 }, + [SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = { + .offset = 0x05, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x06, .size = 8, .activate = 3 }, + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { .offset = 0x08, .size = 1, .activate = 7 }, @@ -913,8 +946,14 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_AIR_SWITCH] = { .offset = 0x8c, .size = 8, .activate = 8 }, + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x9c, .size = 1, .activate = 8 }, + [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x9d, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = { + .offset = 0x9e, .size = 8, .activate = 6 }, } }; /* proprietary request/response format */ @@ -1927,6 +1966,20 @@ static int scarlett2_update_input_other(struct usb_mixer_interface *mixer) return err; } + if (info->phantom_count) { + int err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH, + info->phantom_count, private->phantom_switch); + if (err < 0) + return err; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, + 1, &private->phantom_persistence); + if (err < 0) + return err; + } + return 0; } @@ -2112,6 +2165,111 @@ static const struct snd_kcontrol_new scarlett2_air_ctl = { .put = scarlett2_air_ctl_put, }; +/*** Phantom Switch Controls ***/ + +static int scarlett2_phantom_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->input_other_updated) + scarlett2_update_input_other(mixer); + ucontrol->value.integer.value[0] = + private->phantom_switch[elem->control]; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->phantom_switch[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->phantom_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PHANTOM_SWITCH, + index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_phantom_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_phantom_ctl_get, + .put = scarlett2_phantom_ctl_put, +}; + +/*** Phantom Persistence Control ***/ + +static int scarlett2_phantom_persistence_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + + ucontrol->value.integer.value[0] = private->phantom_persistence; + return 0; +} + +static int scarlett2_phantom_persistence_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->phantom_persistence; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->phantom_persistence = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_phantom_persistence_ctl_get, + .put = scarlett2_phantom_persistence_ctl_put, +}; + /*** Dim/Mute Controls ***/ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, @@ -2275,6 +2433,7 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) int err, i; char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; const char *fmt = "Line In %d %s Capture %s"; + const char *fmt2 = "Line In %d-%d %s Capture %s"; /* Add input level (line/inst) controls */ for (i = 0; i < info->level_input_count; i++) { @@ -2304,6 +2463,39 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) return err; } + /* Add input phantom controls */ + if (info->inputs_per_phantom == 1) { + for (i = 0; i < info->phantom_count; i++) { + snprintf(s, sizeof(s), fmt, i + 1, + "Phantom Power", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_phantom_ctl, + i, 1, s, &private->phantom_ctls[i]); + if (err < 0) + return err; + } + } else if (info->inputs_per_phantom > 1) { + for (i = 0; i < info->phantom_count; i++) { + int from = i * info->inputs_per_phantom + 1; + int to = (i + 1) * info->inputs_per_phantom; + + snprintf(s, sizeof(s), fmt2, from, to, + "Phantom Power", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_phantom_ctl, + i, 1, s, &private->phantom_ctls[i]); + if (err < 0) + return err; + } + } + if (info->phantom_count) { + err = scarlett2_add_new_ctl( + mixer, &scarlett2_phantom_persistence_ctl, 0, 1, + "Phantom Power Persistence Capture Switch", NULL); + if (err < 0) + return err; + } + return 0; } @@ -2932,6 +3124,9 @@ static void scarlett2_notify_input_other( for (i = 0; i < info->air_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->air_ctls[i]->id); + for (i = 0; i < info->phantom_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->phantom_ctls[i]->id); } /* Interrupt callback */ From patchwork Tue Jun 22 17:03:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465191 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 A30DEC2B9F4 for ; Tue, 22 Jun 2021 17:05:57 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C911961353 for ; Tue, 22 Jun 2021 17:05:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C911961353 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 5E3171660; Tue, 22 Jun 2021 19:05:05 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 5E3171660 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381555; bh=DShmZevEwEeYro5hYDl4vzj1Fb6tHPol8gYIr4fQ6tk=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=t4DKlPkSe/ZE+Tak/E8fqbBQNe9Akuse59o7VDamjF1JOu90M0KD1Z3ND83/VSZPV oGAMe6yr6JKWmq50GpWoEsjSRtlZ0wpBzwX79bBbE89EJvKIKr6Czz7S3KGoJ8/n6L LprfsiAlz/uRTU/CfFEHAp0cKOPsto4xPx5OTPg0= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 2358BF804D8; Tue, 22 Jun 2021 19:03:15 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 53242F804E3; Tue, 22 Jun 2021 19:03:14 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 2AC76F80268 for ; Tue, 22 Jun 2021 19:03:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 2AC76F80268 Received: by m.b4.vu (Postfix, from userid 1000) id 90BEA61E286D; Wed, 23 Jun 2021 02:33:08 +0930 (ACST) Date: Wed, 23 Jun 2021 02:33:08 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 10/17] ALSA: usb-audio: scarlett2: Add direct monitor support Message-ID: <61d23dc4feb3b046d870ad7203e66ff2bd1d278c.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" The Solo and 2i2 devices don't have a mixer but they do have a "direct monitor" switch. Add support for getting and setting the state of this switch. Co-developed-by: Vladimir Sadovnikov Signed-off-by: Vladimir Sadovnikov Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 161 ++++++++++++++++++++++++++++++-- 1 file changed, 154 insertions(+), 7 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index bc4f29cfb2f3..2912854f64c1 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -48,7 +48,8 @@ * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander * Vorona for 2i2 protocol traces). * - * Support for phantom power added in May 2021. + * Support for phantom power and direct monitoring added in May-June + * 2021. * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes @@ -56,7 +57,7 @@ * - gain/volume/mute controls * - level meters * - line/inst level, pad, and air controls - * - phantom power controls + * - phantom power and direct monitor controls * - disable/enable MSD mode * * @@ -338,6 +339,11 @@ struct scarlett2_device_info { /* the number of inputs each phantom switch controls */ u8 inputs_per_phantom; + /* the number of direct monitor options + * (0 = none, 1 = mono only, 2 = mono/stereo) + */ + u8 direct_monitor; + /* additional description for the line out volume controls */ const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; @@ -365,6 +371,7 @@ struct scarlett2_data { u8 sync_updated; u8 vol_updated; u8 input_other_updated; + u8 monitor_other_updated; u8 sync; u8 master_vol; u8 vol[SCARLETT2_ANALOGUE_MAX]; @@ -376,6 +383,7 @@ struct scarlett2_data { u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 phantom_persistence; + u8 direct_monitor_switch; u8 msd_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -386,6 +394,7 @@ struct scarlett2_data { struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; + struct snd_kcontrol *direct_monitor_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -550,6 +559,7 @@ static const struct scarlett2_device_info solo_gen3_info = { .air_input_count = 1, .phantom_count = 1, .inputs_per_phantom = 1, + .direct_monitor = 1, }; static const struct scarlett2_device_info s2i2_gen3_info = { @@ -560,6 +570,7 @@ static const struct scarlett2_device_info s2i2_gen3_info = { .air_input_count = 2, .phantom_count = 1, .inputs_per_phantom = 2, + .direct_monitor = 2, }; static const struct scarlett2_device_info s4i4_gen3_info = { @@ -824,10 +835,11 @@ static int scarlett2_get_port_start_num( /*** USB Interactions ***/ /* Notifications from the interface */ -#define SCARLETT2_USB_NOTIFY_SYNC 0x00000008 -#define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000 -#define SCARLETT2_USB_NOTIFY_MONITOR 0x00400000 -#define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000 +#define SCARLETT2_USB_NOTIFY_SYNC 0x00000008 +#define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000 +#define SCARLETT2_USB_NOTIFY_MONITOR 0x00400000 +#define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000 +#define SCARLETT2_USB_NOTIFY_MONITOR_OTHER 0x01000000 /* Commands for sending/receiving requests/responses */ #define SCARLETT2_USB_CMD_INIT 0 @@ -888,7 +900,8 @@ enum { SCARLETT2_CONFIG_AIR_SWITCH = 7, SCARLETT2_CONFIG_PHANTOM_SWITCH = 8, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9, - SCARLETT2_CONFIG_COUNT = 10 + SCARLETT2_CONFIG_DIRECT_MONITOR = 10, + SCARLETT2_CONFIG_COUNT = 11 }; /* Location, size, and activation command number for the configuration @@ -917,6 +930,9 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { .offset = 0x06, .size = 8, .activate = 3 }, + [SCARLETT2_CONFIG_DIRECT_MONITOR] = { + .offset = 0x07, .size = 8, .activate = 4 }, + [SCARLETT2_CONFIG_LEVEL_SWITCH] = { .offset = 0x08, .size = 1, .activate = 7 }, @@ -2270,6 +2286,112 @@ static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = { .put = scarlett2_phantom_persistence_ctl_put, }; +/*** Direct Monitor Control ***/ + +static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->monitor_other_updated = 0; + + if (info->direct_monitor) + return scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, + 1, &private->direct_monitor_switch); + + return 0; +} + +static int scarlett2_direct_monitor_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = elem->head.mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->monitor_other_updated) + scarlett2_update_monitor_other(mixer); + ucontrol->value.enumerated.item[0] = private->direct_monitor_switch; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_direct_monitor_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->direct_monitor_switch; + val = min(ucontrol->value.enumerated.item[0], 2U); + + if (oval == val) + goto unlock; + + private->direct_monitor_switch = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, index, val); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_direct_monitor_stereo_enum_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[3] = { + "Off", "Mono", "Stereo" + }; + + return snd_ctl_enum_info(uinfo, 1, 3, values); +} + +/* Direct Monitor for Solo is mono-only and only needs a boolean control + * Direct Monitor for 2i2 is selectable between Off/Mono/Stereo + */ +static const struct snd_kcontrol_new scarlett2_direct_monitor_ctl[2] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_direct_monitor_ctl_get, + .put = scarlett2_direct_monitor_ctl_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_direct_monitor_stereo_enum_ctl_info, + .get = scarlett2_direct_monitor_ctl_get, + .put = scarlett2_direct_monitor_ctl_put, + } +}; + +static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + if (!info->direct_monitor) + return 0; + + return scarlett2_add_new_ctl( + mixer, &scarlett2_direct_monitor_ctl[info->direct_monitor - 1], + 0, 1, "Direct Monitor Playback Switch", + &private->direct_monitor_ctl); +} + /*** Dim/Mute Controls ***/ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, @@ -2988,6 +3110,10 @@ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) if (err < 0) return err; + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + return err; + /* the rest of the configuration is for devices with a mixer */ if (!info->has_mixer) return 0; @@ -3129,6 +3255,20 @@ static void scarlett2_notify_input_other( &private->phantom_ctls[i]->id); } +/* Notify on "monitor other" change (direct monitor) */ +static void scarlett2_notify_monitor_other( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + struct snd_card *card = mixer->chip->card; + + private->monitor_other_updated = 1; + + if (private->info->direct_monitor) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->direct_monitor_ctl->id); +} + /* Interrupt callback */ static void scarlett2_notify(struct urb *urb) { @@ -3149,6 +3289,8 @@ static void scarlett2_notify(struct urb *urb) scarlett2_notify_dim_mute(mixer); if (data & SCARLETT2_USB_NOTIFY_INPUT_OTHER) scarlett2_notify_input_other(mixer); + if (data & SCARLETT2_USB_NOTIFY_MONITOR_OTHER) + scarlett2_notify_monitor_other(mixer); requeue: if (ustatus != -ENOENT && @@ -3255,6 +3397,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) if (err < 0) return err; + /* Create the direct monitor control */ + err = scarlett2_add_direct_monitor_ctl(mixer); + if (err < 0) + return err; + /* Set up the interrupt polling */ err = scarlett2_init_notify(mixer); if (err < 0) From patchwork Tue Jun 22 17:03:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465925 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 7D743C2B9F4 for ; Tue, 22 Jun 2021 17:06:28 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 01AD461353 for ; Tue, 22 Jun 2021 17:06:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 01AD461353 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 92A7811C; Tue, 22 Jun 2021 19:05:36 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 92A7811C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381586; bh=Og8T15ximoyQDWmdtAd184cs66zTSMMEnbO8PHBAanA=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Fxy6HXxuNfhUY2pgqE2MZ0rnAinUE6x1Z15rEPuOKVYVtjRzXaSqbaZfgS7IfkEP8 jwL6wT7IPP+VqZnay0WDTuTKYClFXjwNUc2JCzjo+crODBeAR6t8ganiXK0/WZRqDd pS3eLGqML1gzrZn9zt9i3Da5/05UEX+TtAiAa5f0= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 63EF2F80511; Tue, 22 Jun 2021 19:03:23 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 66A55F80517; Tue, 22 Jun 2021 19:03:22 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 29B55F804C2 for ; Tue, 22 Jun 2021 19:03:19 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 29B55F804C2 Received: by m.b4.vu (Postfix, from userid 1000) id A5E1861E286F; Wed, 23 Jun 2021 02:33:16 +0930 (ACST) Date: Wed, 23 Jun 2021 02:33:16 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 11/17] ALSA: usb-audio: scarlett2: Label 18i8 Gen 3 line outputs correctly Message-ID: <461acb911509e60e9ab48109ece3bbadae7440c8.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" The 18i8 Gen 3 analogue 7/8 outputs are identified as line 3/4 on the rear of the unit. Add support for remapping the channel numbers to match the labelling. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 82 ++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 23 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 2912854f64c1..59c9147c5cb5 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -344,6 +344,12 @@ struct scarlett2_device_info { */ u8 direct_monitor; + /* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected + * internally to the analogue 7/8 outputs + */ + u8 line_out_remap_enable; + u8 line_out_remap[SCARLETT2_ANALOGUE_MAX]; + /* additional description for the line out volume controls */ const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; @@ -684,15 +690,18 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .phantom_count = 2, .inputs_per_phantom = 2, + .line_out_remap_enable = 1, + .line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 }, + .line_out_descrs = { "Monitor L", "Monitor R", + "Alt Monitor L", + "Alt Monitor R", "Headphones 1 L", "Headphones 1 R", "Headphones 2 L", "Headphones 2 R", - "Alt Monitor L", - "Alt Monitor R", }, .port_count = { @@ -1716,13 +1725,22 @@ static int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl, return 0; } +static int line_out_remap(struct scarlett2_data *private, int index) +{ + const struct scarlett2_device_info *info = private->info; + + if (!info->line_out_remap_enable) + return index; + return info->line_out_remap[index]; +} + static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; + int index = line_out_remap(private, elem->control); mutex_lock(&private->data_mutex); if (private->vol_updated) @@ -1739,7 +1757,7 @@ static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; + int index = line_out_remap(private, elem->control); int oval, val, err = 0; mutex_lock(&private->data_mutex); @@ -1795,7 +1813,7 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct scarlett2_data *private = elem->head.mixer->private_data; - int index = elem->control; + int index = line_out_remap(private, elem->control); ucontrol->value.integer.value[0] = private->mute_switch[index]; return 0; @@ -1807,7 +1825,7 @@ static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int index = elem->control; + int index = line_out_remap(private, elem->control); int oval, val, err = 0; mutex_lock(&private->data_mutex); @@ -1854,9 +1872,9 @@ static int scarlett2_sw_hw_enum_ctl_get(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct scarlett2_data *private = elem->head.mixer->private_data; + int index = line_out_remap(private, elem->control); - ucontrol->value.enumerated.item[0] = - private->vol_sw_hw_switch[elem->control]; + ucontrol->value.enumerated.item[0] = private->vol_sw_hw_switch[index]; return 0; } @@ -1892,8 +1910,8 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - - int index = elem->control; + int ctl_index = elem->control; + int index = line_out_remap(private, ctl_index); int oval, val, err = 0; mutex_lock(&private->data_mutex); @@ -1909,7 +1927,7 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, /* Change access mode to RO (hardware controlled volume) * or RW (software controlled volume) */ - scarlett2_vol_ctl_set_writable(mixer, index, !val); + scarlett2_vol_ctl_set_writable(mixer, ctl_index, !val); /* Reset volume/mute to master volume/mute */ private->vol[index] = private->master_vol; @@ -2441,13 +2459,16 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, err = 1; if (index == SCARLETT2_BUTTON_MUTE) - for (i = 0; i < num_line_out; i++) - if (private->vol_sw_hw_switch[i]) { - private->mute_switch[i] = val; + for (i = 0; i < num_line_out; i++) { + int line_index = line_out_remap(private, i); + + if (private->vol_sw_hw_switch[line_index]) { + private->mute_switch[line_index] = val; snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO, &private->mute_ctls[i]->id); } + } unlock: mutex_unlock(&private->data_mutex); @@ -2486,6 +2507,7 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) /* Add volume controls */ for (i = 0; i < num_line_out; i++) { + int index = line_out_remap(private, i); /* Fader */ if (info->line_out_descrs[i]) @@ -2516,7 +2538,7 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) /* Make the fader and mute controls read-only if the * SW/HW switch is set to HW */ - if (private->vol_sw_hw_switch[i]) + if (private->vol_sw_hw_switch[index]) scarlett2_vol_ctl_set_writable(mixer, i, 0); /* SW/HW Switch */ @@ -2765,8 +2787,16 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, { struct usb_mixer_elem_info *elem = kctl->private_data; struct scarlett2_data *private = elem->head.mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int line_out_count = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + int index = elem->control; + + if (index < line_out_count) + index = line_out_remap(private, index); - ucontrol->value.enumerated.item[0] = private->mux[elem->control]; + ucontrol->value.enumerated.item[0] = private->mux[index]; return 0; } @@ -2776,9 +2806,16 @@ static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int line_out_count = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; int index = elem->control; int oval, val, err = 0; + if (index < line_out_count) + index = line_out_remap(private, index); + mutex_lock(&private->data_mutex); oval = private->mux[index]; @@ -3179,6 +3216,7 @@ static void scarlett2_notify_sync( static void scarlett2_notify_monitor( struct usb_mixer_interface *mixer) { + struct snd_card *card = mixer->chip->card; struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; @@ -3195,12 +3233,10 @@ static void scarlett2_notify_monitor( snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &private->master_vol_ctl->id); - for (i = 0; i < num_line_out; i++) { - if (!private->vol_sw_hw_switch[i]) - continue; - snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, - &private->vol_ctls[i]->id); - } + for (i = 0; i < num_line_out; i++) + if (private->vol_sw_hw_switch[line_out_remap(private, i)]) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->vol_ctls[i]->id); } /* Notify on dim/mute change */ @@ -3225,7 +3261,7 @@ static void scarlett2_notify_dim_mute( &private->dim_mute_ctls[i]->id); for (i = 0; i < num_line_out; i++) - if (private->vol_sw_hw_switch[i]) + if (private->vol_sw_hw_switch[line_out_remap(private, i)]) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->mute_ctls[i]->id); } From patchwork Tue Jun 22 17:03:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465190 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 05D10C2B9F4 for ; Tue, 22 Jun 2021 17:06:47 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7FD246054E for ; Tue, 22 Jun 2021 17:06:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7FD246054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 222179F6; Tue, 22 Jun 2021 19:05:55 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 222179F6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381605; bh=Cc9KT2WY2cGEPBwuA7xKDFlK6aTN+Dm+jv1v454vW+4=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=kW21fZdrHVPJhoIfKlpVTquv44X7v9ShH3kRku2lHHrdcJcj8oniQvg3FMH8Cfkhs IwXhxp2dxn0aJTRA+to85czC/4/ixFdCzLP3/tUCZSInp9LbTVlf1+95iIcwsgPRhg R2PRjD0sgdpLWvvQaideKT5ZfUbeVSzvYRSfbe1M= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 4E325F80271; Tue, 22 Jun 2021 19:03:47 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 82D07F804E2; Tue, 22 Jun 2021 19:03:45 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id EC41CF804D9 for ; Tue, 22 Jun 2021 19:03:38 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz EC41CF804D9 Received: by m.b4.vu (Postfix, from userid 1000) id 766DC61E286E; Wed, 23 Jun 2021 02:33:36 +0930 (ACST) Date: Wed, 23 Jun 2021 02:33:36 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 12/17] ALSA: usb-audio: scarlett2: Split up sw_hw_enum_ctl_put() Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Split part of scarlett2_sw_hw_enum_ctl_put() out into scarlett2_sw_hw_change() so that the code which actually makes the change is available in its own function. This will be used by the speaker switching support which needs to set the SW/HW switch to HW when speaker switching is enabled. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 46 ++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 59c9147c5cb5..37e35016db12 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1904,23 +1904,12 @@ static void scarlett2_vol_ctl_set_writable(struct usb_mixer_interface *mixer, &private->mute_ctls[index]->id); } -static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +static int scarlett2_sw_hw_change(struct usb_mixer_interface *mixer, + int ctl_index, int val) { - struct usb_mixer_elem_info *elem = kctl->private_data; - struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; - int ctl_index = elem->control; int index = line_out_remap(private, ctl_index); - int oval, val, err = 0; - - mutex_lock(&private->data_mutex); - - oval = private->vol_sw_hw_switch[index]; - val = !!ucontrol->value.enumerated.item[0]; - - if (oval == val) - goto unlock; + int err; private->vol_sw_hw_switch[index] = val; @@ -1938,18 +1927,39 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, index, private->master_vol - SCARLETT2_VOLUME_BIAS); if (err < 0) - goto unlock; + return err; /* Set SW mute to current HW mute */ err = scarlett2_usb_set_config( mixer, SCARLETT2_CONFIG_MUTE_SWITCH, index, private->dim_mute[SCARLETT2_BUTTON_MUTE]); if (err < 0) - goto unlock; + return err; /* Send SW/HW switch change to the device */ - err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, - index, val); + return scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, + index, val); +} + +static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int ctl_index = elem->control; + int index = line_out_remap(private, ctl_index); + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->vol_sw_hw_switch[index]; + val = !!ucontrol->value.enumerated.item[0]; + + if (oval == val) + goto unlock; + + err = scarlett2_sw_hw_change(mixer, ctl_index, val); if (err == 0) err = 1; From patchwork Tue Jun 22 17:03:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465924 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,URIBL_BLOCKED,USER_AGENT_SANE_1 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 C32FDC2B9F4 for ; Tue, 22 Jun 2021 17:07:09 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 35E036054E for ; Tue, 22 Jun 2021 17:07:09 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 35E036054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id C17661658; Tue, 22 Jun 2021 19:06:17 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz C17661658 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381627; bh=bMDdhjT4S3Hs5YCmOGFzVrJSJCDaM2pn166I0ErcFSU=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=KzXbba6qHERov0sOBhcWTnpiErSAOPRnchQXA/xJCqMPv0kaHBwszQagW4m8V73Zq KeIy9e90Zv0tT24iynw+sojVAVd0xR2oLMH68VCbnD9b9FsojSUCkwIafm83VUBta/ RIjGyZ6ofslQmEK8KpBOL7USaTt0wOeuO1T0UYEQ= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id EBD70F80519; Tue, 22 Jun 2021 19:03:50 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 35CD9F8051A; Tue, 22 Jun 2021 19:03:50 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id A1AE0F804DF for ; Tue, 22 Jun 2021 19:03:47 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz A1AE0F804DF Received: by m.b4.vu (Postfix, from userid 1000) id 30BC961E286D; Wed, 23 Jun 2021 02:33:45 +0930 (ACST) Date: Wed, 23 Jun 2021 02:33:45 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 13/17] ALSA: usb-audio: scarlett2: Add sw_hw_ctls and mux_ctls Message-ID: <269d89181bf29dbea80ba6f8cfff84fb23b77f86.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Save the struct snd_kcontrol pointers for the sw_hw and mux controls. This is in preparation for speaker switching support which needs to be able to update those controls. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 37e35016db12..b3e1cb943c3c 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -394,12 +394,14 @@ struct scarlett2_data { struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; + struct snd_kcontrol *sw_hw_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *mute_ctls[SCARLETT2_ANALOGUE_MAX]; struct snd_kcontrol *dim_mute_ctls[SCARLETT2_DIM_MUTE_COUNT]; struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; + struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX]; struct snd_kcontrol *direct_monitor_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; @@ -2558,7 +2560,8 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) i + 1); err = scarlett2_add_new_ctl(mixer, &scarlett2_sw_hw_enum_ctl, - i, 1, s, NULL); + i, 1, s, + &private->sw_hw_ctls[i]); if (err < 0) return err; } @@ -2876,7 +2879,8 @@ static int scarlett2_add_mux_enums(struct usb_mixer_interface *mixer) err = scarlett2_add_new_ctl(mixer, &scarlett2_mux_src_enum_ctl, - i, 1, s, NULL); + i, 1, s, + &private->mux_ctls[i]); if (err < 0) return err; } From patchwork Tue Jun 22 17:03:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465189 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 A087CC48BE5 for ; Tue, 22 Jun 2021 17:07:26 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 26C006054E for ; Tue, 22 Jun 2021 17:07:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 26C006054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A70571692; Tue, 22 Jun 2021 19:06:34 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A70571692 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381644; bh=PggDVsK4dUhBzKbIp3aGFGqgVY0EVV6PXY0XT6a8mSc=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=DYMsBzXTX8RjEcUkq932ZNYr/xABtdyyHMCJz6UGHtDIKDs7Bvn1zTOUW1lixdDWn uc1fz6nzSBHhYd/oW0fF9PiHLVoWaT4EXlgY0lo7RF1TPF2HrZtJ9AaP1Uo/Mtv3G7 sW7lxABGQb9E4vNq14Ns9+pjlLn60P8D70orhw04= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id A7737F8051C; Tue, 22 Jun 2021 19:03:56 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 2722CF8051D; Tue, 22 Jun 2021 19:03:55 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id AA0CCF804E4 for ; Tue, 22 Jun 2021 19:03:52 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz AA0CCF804E4 Received: by m.b4.vu (Postfix, from userid 1000) id 37C7561E286E; Wed, 23 Jun 2021 02:33:50 +0930 (ACST) Date: Wed, 23 Jun 2021 02:33:50 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 14/17] ALSA: usb-audio: scarlett2: Update mux controls to allow updates Message-ID: <5ce3bb9fe4006b550d18c783c5ff640fe0bfbfcb.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Enabling/disabling speaker switching will update the mux configuration. To prepare for this, add a private->mux_updated flag and update the scarlett2_mux_src_enum_ctl_get() callback to check it. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index b3e1cb943c3c..279196feb811 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -378,6 +378,7 @@ struct scarlett2_data { u8 vol_updated; u8 input_other_updated; u8 monitor_other_updated; + u8 mux_updated; u8 sync; u8 master_vol; u8 vol[SCARLETT2_ANALOGUE_MAX]; @@ -1446,6 +1447,8 @@ static int scarlett2_usb_get_mux(struct usb_mixer_interface *mixer) __le32 data[SCARLETT2_MUX_MAX]; + private->mux_updated = 0; + req.num = 0; req.count = cpu_to_le16(count); @@ -2799,7 +2802,8 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { struct usb_mixer_elem_info *elem = kctl->private_data; - struct scarlett2_data *private = elem->head.mixer->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; int line_out_count = @@ -2809,7 +2813,12 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, if (index < line_out_count) index = line_out_remap(private, index); + mutex_lock(&private->data_mutex); + if (private->mux_updated) + scarlett2_usb_get_mux(mixer); ucontrol->value.enumerated.item[0] = private->mux[index]; + mutex_unlock(&private->data_mutex); + return 0; } From patchwork Tue Jun 22 17:03:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465923 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 56B16C2B9F4 for ; Tue, 22 Jun 2021 17:07:48 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D589B61360 for ; Tue, 22 Jun 2021 17:07:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D589B61360 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 6F3611694; Tue, 22 Jun 2021 19:06:56 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 6F3611694 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381666; bh=dZ35OdHPM/kas2O7erHCa3xe7bhepZw+yHeAebAs+n0=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=BTmS4G923XYc3GfNse2Lp0hyuurW2sDA44lFqQ18u1FEYg6QaHBhQxRMPiTUU5CJn sN87m8kqc5EcZIKV0hVxcb+uINV27AZvgMadnWi9yRrlCOvbOLhx0LVFeDbODYVaCs 8iX8h6QfAfni7hm+Sse1t301LCbQOQSqFqG+S5yU= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 91158F804E6; Tue, 22 Jun 2021 19:04:09 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 37945F804E7; Tue, 22 Jun 2021 19:04:08 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 3EB35F8051B for ; Tue, 22 Jun 2021 19:04:01 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 3EB35F8051B Received: by m.b4.vu (Postfix, from userid 1000) id C00F761E287C; Wed, 23 Jun 2021 02:33:58 +0930 (ACST) Date: Wed, 23 Jun 2021 02:33:58 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 15/17] ALSA: usb-audio: scarlett2: Add speaker switching support Message-ID: <874193a534cd0aeb6f2e108ae761cadd2dc25ad2.1624379707.git.g@b4.vu> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" The 18i8 and 18i20 Gen 3 support "speaker switching". Add a Speaker Switch control which can be set to Off/Main/Alt. When speaker switching is enabled or disabled, the interface may change the state of the Analog Outputs 3 and 4 routing and the global mute button, so use a flag private->speaker_switching_switched to note that those should be checked when the next "monitor other" notification is received. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 248 +++++++++++++++++++++++++++++++- 1 file changed, 241 insertions(+), 7 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 279196feb811..ffa2ee8d034c 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -48,8 +48,8 @@ * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander * Vorona for 2i2 protocol traces). * - * Support for phantom power and direct monitoring added in May-June - * 2021. + * Support for phantom power, direct monitoring, and speaker switching + * added in May-June 2021. * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes @@ -57,7 +57,7 @@ * - gain/volume/mute controls * - level meters * - line/inst level, pad, and air controls - * - phantom power and direct monitor controls + * - phantom power, direct monitor, and speaker switching controls * - disable/enable MSD mode * * @@ -315,6 +315,9 @@ struct scarlett2_device_info { /* line out hw volume is sw controlled */ u8 line_out_hw_vol; + /* support for main/alt speaker switching */ + u8 has_speaker_switching; + /* the number of analogue inputs with a software switchable * level control that can be set to line or instrument */ @@ -379,6 +382,7 @@ struct scarlett2_data { u8 input_other_updated; u8 monitor_other_updated; u8 mux_updated; + u8 speaker_switching_switched; u8 sync; u8 master_vol; u8 vol[SCARLETT2_ANALOGUE_MAX]; @@ -391,6 +395,7 @@ struct scarlett2_data { u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 phantom_persistence; u8 direct_monitor_switch; + u8 speaker_switching_switch; u8 msd_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -404,6 +409,7 @@ struct scarlett2_data { struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX]; struct snd_kcontrol *direct_monitor_ctl; + struct snd_kcontrol *speaker_switching_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -687,6 +693,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .has_msd_mode = 1, .has_mixer = 1, .line_out_hw_vol = 1, + .has_speaker_switching = 1, .level_input_count = 2, .pad_input_count = 2, .air_input_count = 4, @@ -756,6 +763,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .has_msd_mode = 1, .has_mixer = 1, .line_out_hw_vol = 1, + .has_speaker_switching = 1, .level_input_count = 2, .pad_input_count = 8, .air_input_count = 8, @@ -913,7 +921,9 @@ enum { SCARLETT2_CONFIG_PHANTOM_SWITCH = 8, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 9, SCARLETT2_CONFIG_DIRECT_MONITOR = 10, - SCARLETT2_CONFIG_COUNT = 11 + SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 11, + SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 12, + SCARLETT2_CONFIG_COUNT = 13 }; /* Location, size, and activation command number for the configuration @@ -982,6 +992,12 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_PHANTOM_PERSISTENCE] = { .offset = 0x9e, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH] = { + .offset = 0x9f, .size = 1, .activate = 10 }, + + [SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE] = { + .offset = 0xa0, .size = 1, .activate = 10 }, } }; /* proprietary request/response format */ @@ -1862,6 +1878,18 @@ static const struct snd_kcontrol_new scarlett2_mute_ctl = { /*** HW/SW Volume Switch Controls ***/ +static void scarlett2_sw_hw_ctl_ro(struct scarlett2_data *private, int index) +{ + private->sw_hw_ctls[index]->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_WRITE; +} + +static void scarlett2_sw_hw_ctl_rw(struct scarlett2_data *private, int index) +{ + private->sw_hw_ctls[index]->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_WRITE; +} + static int scarlett2_sw_hw_enum_ctl_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -2325,6 +2353,13 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; + int err; + + /* monitor_other_enable[0] enables speaker switching */ + u8 monitor_other_enable[2]; + + /* monitor_other_switch[0] activates the alternate speakers */ + u8 monitor_other_switch[2]; private->monitor_other_updated = 0; @@ -2333,6 +2368,26 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, 1, &private->direct_monitor_switch); + if (!info->has_speaker_switching) + return 0; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, + 2, monitor_other_enable); + if (err < 0) + return err; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, + 2, monitor_other_switch); + if (err < 0) + return err; + + if (!monitor_other_enable[0]) + private->speaker_switching_switch = 0; + else + private->speaker_switching_switch = monitor_other_switch[0] + 1; + return 0; } @@ -2425,6 +2480,151 @@ static int scarlett2_add_direct_monitor_ctl(struct usb_mixer_interface *mixer) &private->direct_monitor_ctl); } +/*** Speaker Switching Control ***/ + +static int scarlett2_speaker_switch_enum_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[3] = { + "Off", "Main", "Alt" + }; + + return snd_ctl_enum_info(uinfo, 1, 3, values); +} + +static int scarlett2_speaker_switch_enum_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->monitor_other_updated) + scarlett2_update_monitor_other(mixer); + ucontrol->value.enumerated.item[0] = private->speaker_switching_switch; + mutex_unlock(&private->data_mutex); + + return 0; +} + +/* when speaker switching gets enabled, switch the main/alt speakers + * to HW volume and disable those controls + */ +static void scarlett2_speaker_switch_enable(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + int i; + + for (i = 0; i < 4; i++) { + int index = line_out_remap(private, i); + + /* switch the main/alt speakers to HW volume */ + if (!private->vol_sw_hw_switch[index]) + scarlett2_sw_hw_change(private->mixer, i, 1); + + /* disable the line out SW/HW switch */ + scarlett2_sw_hw_ctl_ro(private, i); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->sw_hw_ctls[i]->id); + } + + /* when the next monitor-other notify comes in, update the mux + * configuration + */ + private->speaker_switching_switched = 1; +} + +/* when speaker switching gets disabled, reenable the hw/sw controls + * and invalidate the routing + */ +static void scarlett2_speaker_switch_disable(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + int i; + + /* enable the line out SW/HW switch */ + for (i = 0; i < 4; i++) { + scarlett2_sw_hw_ctl_rw(private, i); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->sw_hw_ctls[i]->id); + } + + /* when the next monitor-other notify comes in, update the mux + * configuration + */ + private->speaker_switching_switched = 1; +} + +static int scarlett2_speaker_switch_enum_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->speaker_switching_switch; + val = min(ucontrol->value.enumerated.item[0], 2U); + + if (oval == val) + goto unlock; + + private->speaker_switching_switch = val; + + /* enable/disable speaker switching */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, + 0, !!val); + if (err < 0) + goto unlock; + + /* if speaker switching is enabled, select main or alt */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, + 0, val == 2); + if (err < 0) + goto unlock; + + /* update controls if speaker switching gets enabled or disabled */ + if (!oval && val) + scarlett2_speaker_switch_enable(mixer); + else if (oval && !val) + scarlett2_speaker_switch_disable(mixer); + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_speaker_switch_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_speaker_switch_enum_ctl_info, + .get = scarlett2_speaker_switch_enum_ctl_get, + .put = scarlett2_speaker_switch_enum_ctl_put, +}; + +static int scarlett2_add_speaker_switch_ctl( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + if (!info->has_speaker_switching) + return 0; + + return scarlett2_add_new_ctl( + mixer, &scarlett2_speaker_switch_enum_ctl, + 0, 1, "Speaker Switching Playback Enum", + &private->speaker_switching_ctl); +} + /*** Dim/Mute Controls ***/ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, @@ -2567,6 +2767,12 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) &private->sw_hw_ctls[i]); if (err < 0) return err; + + /* Make the switch read-only if the line is + * involved in speaker switching + */ + if (private->speaker_switching_switch && i < 4) + scarlett2_sw_hw_ctl_ro(private, i); } } @@ -3314,18 +3520,41 @@ static void scarlett2_notify_input_other( &private->phantom_ctls[i]->id); } -/* Notify on "monitor other" change (direct monitor) */ +/* Notify on "monitor other" change (direct monitor, speaker switching) */ static void scarlett2_notify_monitor_other( struct usb_mixer_interface *mixer) { - struct scarlett2_data *private = mixer->private_data; struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; private->monitor_other_updated = 1; - if (private->info->direct_monitor) + if (info->direct_monitor) { snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->direct_monitor_ctl->id); + return; + } + + if (info->has_speaker_switching) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->speaker_switching_ctl->id); + + /* if speaker switching was recently enabled or disabled, + * invalidate the dim/mute and mux enum controls + */ + if (private->speaker_switching_switched) { + int i; + + scarlett2_notify_dim_mute(mixer); + + private->speaker_switching_switched = 0; + private->mux_updated = 1; + + for (i = 0; i < private->num_mux_dsts; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->mux_ctls[i]->id); + } } /* Interrupt callback */ @@ -3461,6 +3690,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) if (err < 0) return err; + /* Create the speaker switching control */ + err = scarlett2_add_speaker_switch_ctl(mixer); + if (err < 0) + return err; + /* Set up the interrupt polling */ err = scarlett2_init_notify(mixer); if (err < 0) From patchwork Tue Jun 22 17:04:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465188 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.2 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_SANE_1 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 72593C2B9F4 for ; Tue, 22 Jun 2021 17:08:19 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F26E66054E for ; Tue, 22 Jun 2021 17:08:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F26E66054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A0BF3166B; Tue, 22 Jun 2021 19:07:27 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A0BF3166B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381697; bh=xyEPY7GuuG1769GlWf419l+lZxBO9frFDb9VuH8BCdg=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=KrM6OAZF8/26KoLUpkMXAh2XEeKl4w23gk+4/WJgqf3jyuv40e7YcJTKCbLcNhPoJ Yk1WbxE7VLAdD0ASwVXdV46bydwlOzMgJpoKjBJk8bodzItCrJXmlGg7GR+OpKw4iI oowz5Nq+Mjr5f7Fx18q+uvnm6GhdZPOabqhat5go= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id AA5FEF80526; Tue, 22 Jun 2021 19:04:19 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 7E9EEF80528; Tue, 22 Jun 2021 19:04:18 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 1D1A9F80526 for ; Tue, 22 Jun 2021 19:04:12 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 1D1A9F80526 Received: by m.b4.vu (Postfix, from userid 1000) id 9DCF761E286E; Wed, 23 Jun 2021 02:34:09 +0930 (ACST) Date: Wed, 23 Jun 2021 02:34:09 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 16/17] ALSA: usb-audio: scarlett2: Update get_config to do endian conversion Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" For configuration items with a size of 16, scarlett2_usb_get_config() was filling *buf with little-endian data. Update it to convert to CPU endian. This function is not currently used so affects nothing yet; will be used by the upcoming talkback feature. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index ffa2ee8d034c..f26ab6c39859 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -1170,7 +1170,13 @@ static int scarlett2_usb_get_config( /* For byte-sized parameters, retrieve directly into buf */ if (config_item->size >= 8) { size = config_item->size / 8 * count; - return scarlett2_usb_get(mixer, config_item->offset, buf, size); + err = scarlett2_usb_get(mixer, config_item->offset, buf, size); + if (err < 0) + return err; + if (size == 2) + for (i = 0; i < count; i++, (u16 *)buf++) + *(u16 *)buf = le16_to_cpu(*(__le16 *)buf); + return 0; } /* For bit-sized parameters, retrieve into value */ From patchwork Tue Jun 22 17:04:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 465922 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=-12.4 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_SANE_1 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 789D8C2B9F4 for ; Tue, 22 Jun 2021 17:08:37 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 001C36054E for ; Tue, 22 Jun 2021 17:08:36 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 001C36054E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=b4.vu Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 94147851; Tue, 22 Jun 2021 19:07:45 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 94147851 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1624381715; bh=7SHU1wTjK1dKrRRED+GLGH4wcmj8sG7LMb3ymuQWrMc=; h=Date:From:To:Subject:References:In-Reply-To:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=DKRFNphY1RGZCKCiAMp7+MY50hG+bvau91vCT+FqmSgu8wBNho/sa25G3p3N/ZO1k rrpxqQLPXYQmT4JSqoRlpohJh25fpkNZ1wG1NNgeN2MtHxEPZXKWov4qXpMkN8Clsz RZZ2Y2rtet7S0tCkEk9QbXz+Z8seV3XKHrcqfiIQ= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id AD9F0F80529; Tue, 22 Jun 2021 19:04:21 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 38121F8051B; Tue, 22 Jun 2021 19:04:20 +0200 (CEST) Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id DDFC4F8051B for ; Tue, 22 Jun 2021 19:04:15 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz DDFC4F8051B Received: by m.b4.vu (Postfix, from userid 1000) id 7153E61E286D; Wed, 23 Jun 2021 02:34:13 +0930 (ACST) Date: Wed, 23 Jun 2021 02:34:13 +0930 From: "Geoffrey D. Bennett" To: alsa-devel@alsa-project.org, Takashi Iwai Subject: [PATCH 17/17] ALSA: usb-audio: scarlett2: Add support for the talkback feature Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Hin-Tak Leung , Vladimir Sadovnikov X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 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: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add support for the talkback feature of the 18i20 Gen 3. Co-developed-by: Vladimir Sadovnikov Signed-off-by: Vladimir Sadovnikov Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett_gen2.c | 229 +++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 7 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index f26ab6c39859..fcba682cd422 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -48,8 +48,8 @@ * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander * Vorona for 2i2 protocol traces). * - * Support for phantom power, direct monitoring, and speaker switching - * added in May-June 2021. + * Support for phantom power, direct monitoring, speaker switching, + * and talkback added in May-June 2021. * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes @@ -57,7 +57,8 @@ * - gain/volume/mute controls * - level meters * - line/inst level, pad, and air controls - * - phantom power, direct monitor, and speaker switching controls + * - phantom power, direct monitor, speaker switching, and talkback + * controls * - disable/enable MSD mode * * @@ -318,6 +319,9 @@ struct scarlett2_device_info { /* support for main/alt speaker switching */ u8 has_speaker_switching; + /* support for talkback microphone */ + u8 has_talkback; + /* the number of analogue inputs with a software switchable * level control that can be set to line or instrument */ @@ -396,6 +400,8 @@ struct scarlett2_data { u8 phantom_persistence; u8 direct_monitor_switch; u8 speaker_switching_switch; + u8 talkback_switch; + u8 talkback_map[SCARLETT2_OUTPUT_MIX_MAX]; u8 msd_switch; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -410,6 +416,7 @@ struct scarlett2_data { struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX]; struct snd_kcontrol *direct_monitor_ctl; struct snd_kcontrol *speaker_switching_ctl; + struct snd_kcontrol *talkback_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; }; @@ -764,6 +771,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .has_mixer = 1, .line_out_hw_vol = 1, .has_speaker_switching = 1, + .has_talkback = 1, .level_input_count = 2, .pad_input_count = 8, .air_input_count = 8, @@ -923,7 +931,8 @@ enum { SCARLETT2_CONFIG_DIRECT_MONITOR = 10, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 11, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 12, - SCARLETT2_CONFIG_COUNT = 13 + SCARLETT2_CONFIG_TALKBACK_MAP = 13, + SCARLETT2_CONFIG_COUNT = 14 }; /* Location, size, and activation command number for the configuration @@ -998,6 +1007,9 @@ static const struct scarlett2_config [SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE] = { .offset = 0xa0, .size = 1, .activate = 10 }, + + [SCARLETT2_CONFIG_TALKBACK_MAP] = { + .offset = 0xb0, .size = 16, .activate = 10 }, } }; /* proprietary request/response format */ @@ -2361,10 +2373,14 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int err; - /* monitor_other_enable[0] enables speaker switching */ + /* monitor_other_enable[0] enables speaker switching + * monitor_other_enable[1] enables talkback + */ u8 monitor_other_enable[2]; - /* monitor_other_switch[0] activates the alternate speakers */ + /* monitor_other_switch[0] activates the alternate speakers + * monitor_other_switch[1] activates talkback + */ u8 monitor_other_switch[2]; private->monitor_other_updated = 0; @@ -2374,6 +2390,9 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) mixer, SCARLETT2_CONFIG_DIRECT_MONITOR, 1, &private->direct_monitor_switch); + /* if it doesn't do speaker switching then it also doesn't do + * talkback + */ if (!info->has_speaker_switching) return 0; @@ -2394,6 +2413,26 @@ static int scarlett2_update_monitor_other(struct usb_mixer_interface *mixer) else private->speaker_switching_switch = monitor_other_switch[0] + 1; + if (info->has_talkback) { + const int (*port_count)[SCARLETT2_PORT_DIRNS] = + info->port_count; + int num_mixes = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; + u16 bitmap; + int i; + + if (!monitor_other_enable[1]) + private->talkback_switch = 0; + else + private->talkback_switch = monitor_other_switch[1] + 1; + + err = scarlett2_usb_get_config(mixer, + SCARLETT2_CONFIG_TALKBACK_MAP, + 1, &bitmap); + for (i = 0; i < num_mixes; i++, bitmap >>= 1) + private->talkback_map[i] = bitmap & 1; + } + return 0; } @@ -2631,6 +2670,171 @@ static int scarlett2_add_speaker_switch_ctl( &private->speaker_switching_ctl); } +/*** Talkback and Talkback Map Controls ***/ + +static int scarlett2_talkback_enum_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + static const char *const values[3] = { + "Disabled", "Off", "On" + }; + + return snd_ctl_enum_info(uinfo, 1, 3, values); +} + +static int scarlett2_talkback_enum_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + mutex_lock(&private->data_mutex); + if (private->monitor_other_updated) + scarlett2_update_monitor_other(mixer); + ucontrol->value.enumerated.item[0] = private->talkback_switch; + mutex_unlock(&private->data_mutex); + + return 0; +} + +static int scarlett2_talkback_enum_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int oval, val, err = 0; + + mutex_lock(&private->data_mutex); + + oval = private->talkback_switch; + val = min(ucontrol->value.enumerated.item[0], 2U); + + if (oval == val) + goto unlock; + + private->talkback_switch = val; + + /* enable/disable talkback */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE, + 1, !!val); + if (err < 0) + goto unlock; + + /* if talkback is enabled, select main or alt */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, + 1, val == 2); + if (err < 0) + goto unlock; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_talkback_enum_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_talkback_enum_ctl_info, + .get = scarlett2_talkback_enum_ctl_get, + .put = scarlett2_talkback_enum_ctl_put, +}; + +static int scarlett2_talkback_map_ctl_get( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + int index = elem->control; + + ucontrol->value.integer.value[0] = private->talkback_map[index]; + + return 0; +} + +static int scarlett2_talkback_map_ctl_put( + struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = + private->info->port_count; + int num_mixes = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; + + int index = elem->control; + int oval, val, err = 0, i; + u16 bitmap = 0; + + mutex_lock(&private->data_mutex); + + oval = private->talkback_map[index]; + val = !!ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->talkback_map[index] = val; + + for (i = 0; i < num_mixes; i++) + bitmap |= private->talkback_map[i] << i; + + /* Send updated bitmap to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_TALKBACK_MAP, + 0, bitmap); + if (err < 0) + goto unlock; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_talkback_map_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_talkback_map_ctl_get, + .put = scarlett2_talkback_map_ctl_put, +}; + +static int scarlett2_add_talkback_ctls( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int num_mixes = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN]; + int err, i; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + if (!info->has_talkback) + return 0; + + err = scarlett2_add_new_ctl( + mixer, &scarlett2_talkback_enum_ctl, + 0, 1, "Talkback Playback Enum", + &private->talkback_ctl); + if (err < 0) + return err; + + for (i = 0; i < num_mixes; i++) { + snprintf(s, sizeof(s), + "Talkback Mix %c Playback Switch", i + 'A'); + err = scarlett2_add_new_ctl(mixer, &scarlett2_talkback_map_ctl, + i, 1, s, NULL); + if (err < 0) + return err; + } + + return 0; +} + /*** Dim/Mute Controls ***/ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, @@ -3526,7 +3730,9 @@ static void scarlett2_notify_input_other( &private->phantom_ctls[i]->id); } -/* Notify on "monitor other" change (direct monitor, speaker switching) */ +/* Notify on "monitor other" change (direct monitor, speaker + * switching, talkback) + */ static void scarlett2_notify_monitor_other( struct usb_mixer_interface *mixer) { @@ -3546,6 +3752,10 @@ static void scarlett2_notify_monitor_other( snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->speaker_switching_ctl->id); + if (info->has_talkback) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->talkback_ctl->id); + /* if speaker switching was recently enabled or disabled, * invalidate the dim/mute and mux enum controls */ @@ -3701,6 +3911,11 @@ static int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer) if (err < 0) return err; + /* Create the talkback controls */ + err = scarlett2_add_talkback_ctls(mixer); + if (err < 0) + return err; + /* Set up the interrupt polling */ err = scarlett2_init_notify(mixer); if (err < 0)