From patchwork Tue Dec 19 17:36:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498626 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EC43637D03 for ; Tue, 19 Dec 2023 17:36:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="GyQqenbQ" Received: by m.b4.vu (Postfix, from userid 1000) id 432C4604B9F7; Wed, 20 Dec 2023 04:06:42 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 432C4604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007402; bh=w71tYLCSurTXhcu4POdZy7nJlWAOIgIw63TgCjTYSMY=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=GyQqenbQjZ1WXJfzAHedLWE2CsJXMwI+zmf0qoABFBAm81FglS1donj/rCe4Iifpw 9BZToDtCMQK2we0ynaLW+JYIOaunU1BeKpQ7LL32vXrB5ifTSuuturw0vGCSoTH+NJ kANqPvRV/2vr9JBoxGVr/9SXJgqQl2tjMkHjWIwvmaZHh/AsT0giCAMWkCSgXJC2B3 RHb+4dUJhoMuiC291AqHlQ1mTRZX0asnMAkfuxtmnLcLS4+VkqufHC0liDWCaWXllB 9NJGKNMciXVrIj33wEZcOlyOcJCpqDqFt0mevqXkzjs7Ek6SFS0G6x/98hqDzyPrcb bXDUo5q0LCVog== Date: Wed, 20 Dec 2023 04:06:42 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 01/11] ALSA: scarlett2: Update maintainer info Message-ID: <62f32404eaa8663cc304648354b85bcb5914ce72.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Update MAINTAINERS and "enabled" message with GitHub repository links. Signed-off-by: Geoffrey D. Bennett --- MAINTAINERS | 6 ++++-- sound/usb/mixer_scarlett2.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ea790149af79..ae3f72f57854 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8272,11 +8272,13 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/joystick/fsia6b.c -FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER +FOCUSRITE SCARLETT2 MIXER DRIVER (Scarlett Gen 2+ and Clarett) M: Geoffrey D. Bennett L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git +W: https://github.com/geoffreybennett/scarlett-gen2 +B: https://github.com/geoffreybennett/scarlett-gen2/issues +T: git https://github.com/geoffreybennett/scarlett-gen2.git F: sound/usb/mixer_scarlett2.c FORCEDETH GIGABIT ETHERNET DRIVER diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index f7c57a2c3028..a0dbdf921745 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -4534,7 +4534,8 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer) usb_audio_info(chip, "Focusrite %s Mixer Driver enabled (pid=0x%04x); " - "report any issues to g@b4.vu", + "report any issues to " + "https://github.com/geoffreybennett/scarlett-gen2/issues", entry->series_name, USB_ID_PRODUCT(chip->usb_id)); From patchwork Tue Dec 19 17:37:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498627 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1D9E37D03 for ; Tue, 19 Dec 2023 17:37:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="faHNPnoB" Received: by m.b4.vu (Postfix, from userid 1000) id 59CC3604B9F7; Wed, 20 Dec 2023 04:07:00 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 59CC3604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007420; bh=8ETulCIE9Z69wcqSdAOg8PPnM13gfiYjvR7IHw2Ie3U=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=faHNPnoB6i6kSJXkV/pAFKVpIboUm0LoeTJRYsqr9OXWofxsLJn1SHa22hFq0tnnT MrjzCx86UGM5/zjM7oTE+a6pdP7oRRUsOuGfeEncgBHQ5bc0LPGKujdVlNcJW4Eoel +GyLuofT5vv/WukZdH+JhqMn9lINj80ByvrCVEgla5lQBnoahUZiI0PmbcLm2gqpCa y6k0soNGslDdXgXMECZhzHat/rgA7vOPnFktH9sRzowChN2Fvbce9QgRuTHz9U179t 5a4dHApBLaXQDlL75ITrz7TxlKWYK2Ol+lqVbEhV3sIo7GtW9k8jaMmoOIfSjd4ZwM V8/RuV0TH+ZWQ== Date: Wed, 20 Dec 2023 04:07:00 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 02/11] ALSA: scarlett2: Add missing error check to scarlett2_config_save() Message-ID: References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: scarlett2_config_save() was ignoring the return value from scarlett2_usb(). As this function is not called from user-space we can't return the error, so call usb_audio_err() instead. Signed-off-by: Geoffrey D. Bennett Fixes: 9e4d5c1be21f ("ALSA: usb-audio: Scarlett Gen 2 mixer interface") --- sound/usb/mixer_scarlett2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index a0dbdf921745..a0ba53372f7b 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -1524,9 +1524,11 @@ static void scarlett2_config_save(struct usb_mixer_interface *mixer) { __le32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE); - scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, - &req, sizeof(u32), - NULL, 0); + int err = scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, + &req, sizeof(u32), + NULL, 0); + if (err < 0) + usb_audio_err(mixer->chip, "config save failed: %d\n", err); } /* Delayed work to save config */ From patchwork Tue Dec 19 17:37:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498628 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AA85E37864 for ; Tue, 19 Dec 2023 17:37:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="J40YY9LR" Received: by m.b4.vu (Postfix, from userid 1000) id 3DAD0604B9F7; Wed, 20 Dec 2023 04:07:21 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 3DAD0604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007441; bh=UPNbemMDS4lDUP7V/e0nZI2I2ad47Wkcxstixw5X+Xs=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=J40YY9LRwCJPGApJEpHdQEhpI3svsHm+iZXZ65R5cUmPvpQpsnKs5HSoh3Gi+dVc3 vi97nhwn/8PFD4d4dJ92ylslHyLe/mLU0Cno6DwFSRrvOmVPz0D3JajAGKihthSf19 d1Wd2P9YYhtHa4sHVkd04I/QFD5Q1N0O/eomZEySqzJoTBnix+/IkvwNLrn+027Puk o7wXGk+2HtAuBrT8cKtMuFg3IXWmTiJMkfG0xxuXJ0+l3LKGA9h6DsTMtwhabWY2OX Wc+HpHDRv3sjjvBeDsy5T4nJflAanRYDi+jpqYbVs9bNxL57MCf84h1CIGYYypIeyv 1X83Dfnk905Rw== Date: Wed, 20 Dec 2023 04:07:21 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 03/11] ALSA: scarlett2: Add missing error check to scarlett2_usb_set_config() Message-ID: References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: scarlett2_usb_set_config() calls scarlett2_usb_get() but was not checking the result. Return the error if it fails rather than continuing with an invalid value. Signed-off-by: Geoffrey D. Bennett Fixes: 9e15fae6c51a ("ALSA: usb-audio: scarlett2: Allow bit-level access to config") --- sound/usb/mixer_scarlett2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index a0ba53372f7b..22285d8038c1 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -1577,7 +1577,10 @@ static int scarlett2_usb_set_config( size = 1; offset = config_item->offset; - scarlett2_usb_get(mixer, offset, &tmp, 1); + err = scarlett2_usb_get(mixer, offset, &tmp, 1); + if (err < 0) + return err; + if (value) tmp |= (1 << index); else From patchwork Tue Dec 19 17:37:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498646 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 460F731755 for ; Tue, 19 Dec 2023 17:37:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="cKc80OEX" Received: by m.b4.vu (Postfix, from userid 1000) id 6BB85604B9F7; Wed, 20 Dec 2023 04:07:37 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 6BB85604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007457; bh=/ntwoBmCyYetrlV6KCRYSBLcValc73eGigSnWiDbGIw=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=cKc80OEXhySWbhrhuIzUN9bsLXK8Y0Ns7HDb5SvWSrb/+7A8oyD4AIMbWmj+/Dcq7 3YHOQSvZopiPlBoAIzsVMK+69Ag8GEOqOlz899uu06cfzYzW0O4Twm7XmBKC+Y8VfJ FCAxaP0+AmQLTOq2+6qY7/YXIX41HFxzdzrTAY1tiJJ11gvOhuv6we+8M5JwgDG4U0 CE+Y0k1OFXlWWNHOrAxvgv2fzqkBZDuzg49AjYK/MQ6s/72+olYmtXWRNBSBiO1ItX WGb1vk0rp3GYEyiloiGXFtpziQtM1ylJA+flYNXgiubG4mF53pquh6V0laW030GdK2 sf3XiXVB7dpeg== Date: Wed, 20 Dec 2023 04:07:37 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 04/11] ALSA: scarlett2: Add missing error checks to *_ctl_get() Message-ID: <32a5fdc83b05fa74e0fcdd672fbf71d75c5f0a6d.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The *_ctl_get() functions which call scarlett2_update_*() were not checking the return value. Fix to check the return value and pass to the caller. Signed-off-by: Geoffrey D. Bennett Fixes: 9e4d5c1be21f ("ALSA: usb-audio: Scarlett Gen 2 mixer interface") --- sound/usb/mixer_scarlett2.c | 182 +++++++++++++++++++++++++----------- 1 file changed, 130 insertions(+), 52 deletions(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 22285d8038c1..373911937487 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -2100,14 +2100,20 @@ static int scarlett2_sync_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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->sync_updated) - scarlett2_update_sync(mixer); + + if (private->sync_updated) { + err = scarlett2_update_sync(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.enumerated.item[0] = private->sync; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static const struct snd_kcontrol_new scarlett2_sync_ctl = { @@ -2190,14 +2196,20 @@ static int scarlett2_master_volume_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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->vol_updated) - scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); + if (private->vol_updated) { + err = scarlett2_update_volumes(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->master_vol; - return 0; + +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int line_out_remap(struct scarlett2_data *private, int index) @@ -2223,14 +2235,20 @@ static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); + int err = 0; mutex_lock(&private->data_mutex); - if (private->vol_updated) - scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); + if (private->vol_updated) { + err = scarlett2_update_volumes(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->vol[index]; - return 0; + +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, @@ -2297,14 +2315,20 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); + int err = 0; mutex_lock(&private->data_mutex); - if (private->vol_updated) - scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); + if (private->vol_updated) { + err = scarlett2_update_volumes(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->mute_switch[index]; - return 0; + +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl, @@ -2550,14 +2574,20 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, const struct scarlett2_device_info *info = private->info; int index = elem->control + info->level_input_first; + int err = 0; mutex_lock(&private->data_mutex); - if (private->input_other_updated) - scarlett2_update_input_other(mixer); + + if (private->input_other_updated) { + err = scarlett2_update_input_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.enumerated.item[0] = private->level_switch[index]; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, @@ -2608,15 +2638,21 @@ static int scarlett2_pad_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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->input_other_updated) - scarlett2_update_input_other(mixer); + + if (private->input_other_updated) { + err = scarlett2_update_input_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->pad_switch[elem->control]; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, @@ -2666,14 +2702,20 @@ static int scarlett2_air_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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->input_other_updated) - scarlett2_update_input_other(mixer); + + if (private->input_other_updated) { + err = scarlett2_update_input_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->air_switch[elem->control]; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl, @@ -2723,15 +2765,21 @@ static int scarlett2_phantom_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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->input_other_updated) - scarlett2_update_input_other(mixer); + + if (private->input_other_updated) { + err = scarlett2_update_input_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->phantom_switch[elem->control]; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, @@ -2903,14 +2951,20 @@ static int scarlett2_direct_monitor_ctl_get( 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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->monitor_other_updated) - scarlett2_update_monitor_other(mixer); + + if (private->monitor_other_updated) { + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.enumerated.item[0] = private->direct_monitor_switch; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_direct_monitor_ctl_put( @@ -3010,14 +3064,20 @@ static int scarlett2_speaker_switch_enum_ctl_get( 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 err = 0; mutex_lock(&private->data_mutex); - if (private->monitor_other_updated) - scarlett2_update_monitor_other(mixer); + + if (private->monitor_other_updated) { + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.enumerated.item[0] = private->speaker_switching_switch; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } /* when speaker switching gets enabled, switch the main/alt speakers @@ -3165,14 +3225,20 @@ static int scarlett2_talkback_enum_ctl_get( 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 err = 0; mutex_lock(&private->data_mutex); - if (private->monitor_other_updated) - scarlett2_update_monitor_other(mixer); + + if (private->monitor_other_updated) { + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.enumerated.item[0] = private->talkback_switch; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_talkback_enum_ctl_put( @@ -3320,14 +3386,20 @@ static int scarlett2_dim_mute_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; + int err = 0; mutex_lock(&private->data_mutex); - if (private->vol_updated) - scarlett2_update_volumes(mixer); - mutex_unlock(&private->data_mutex); + if (private->vol_updated) { + err = scarlett2_update_volumes(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.integer.value[0] = private->dim_mute[elem->control]; - return 0; + +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, @@ -3698,14 +3770,20 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, elem->control); + int err = 0; mutex_lock(&private->data_mutex); - if (private->mux_updated) - scarlett2_usb_get_mux(mixer); + + if (private->mux_updated) { + err = scarlett2_usb_get_mux(mixer); + if (err < 0) + goto unlock; + } ucontrol->value.enumerated.item[0] = private->mux[index]; - mutex_unlock(&private->data_mutex); - return 0; +unlock: + mutex_unlock(&private->data_mutex); + return err; } static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, From patchwork Tue Dec 19 17:37:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498647 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE307374F8 for ; Tue, 19 Dec 2023 17:37:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="dndQ2jbx" Received: by m.b4.vu (Postfix, from userid 1000) id C4771604B9F7; Wed, 20 Dec 2023 04:07:52 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu C4771604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007472; bh=MhoIaixpik1iUNQTcsUyfLxvHJVzpPig+kV+sgoyrFM=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=dndQ2jbxuzrpogsvzNNG1rKGRTJVLQ+bk1KG4wUT0CwmXAhvvOHsrJ1o2fbr/jp/H xFqv2k/7SMQQ7St6iunL7OyEvOzTP5K918cV1e47/RHs8cVb/6BrFl65qs/DhXsDTz mm9qZhZyxAWpaWizhkM/A7lrPqwawQifWfi1Cu1s6I706rB4nAn57vtLT/el+5GvBC OmlcrJhq8wcNU2gwER6r6Js6Rn/ISWNKVeXz6vuUdW1H8F/ejD2KH+W7+zBeOKfEMY 6cF76oOA6X91eouHojc186I5vHnKAGh9VD6O+g30TZ5XHBhJnqEPwucSe5OF69CI3L NwCtgr0sS4gLw== Date: Wed, 20 Dec 2023 04:07:52 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 05/11] ALSA: scarlett2: Add clamp() in scarlett2_mixer_ctl_put() Message-ID: <3b19fb3da641b587749b85fe1daa1b4e696c0c1b.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Ensure the value passed to scarlett2_mixer_ctl_put() is between 0 and SCARLETT2_MIXER_MAX_VALUE so we don't attempt to access outside scarlett2_mixer_values[]. Signed-off-by: Geoffrey D. Bennett Fixes: 9e4d5c1be21f ("ALSA: usb-audio: Scarlett Gen 2 mixer interface") --- sound/usb/mixer_scarlett2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 373911937487..f1636a1614da 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -3663,7 +3663,8 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); oval = private->mix[index]; - val = ucontrol->value.integer.value[0]; + val = clamp(ucontrol->value.integer.value[0], + 0L, (long)SCARLETT2_MIXER_MAX_VALUE); num_mixer_in = port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT]; mix_num = index / num_mixer_in; From patchwork Tue Dec 19 17:38:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498648 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 58DC737D00 for ; Tue, 19 Dec 2023 17:38:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="oT6NOiH7" Received: by m.b4.vu (Postfix, from userid 1000) id 5CB6D604B9F7; Wed, 20 Dec 2023 04:08:09 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 5CB6D604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007489; bh=7GVO3MNMTMsgTji6rIpd6tjr7bcMr8xM2wntNzv+XCk=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=oT6NOiH7qkCP5Ea27LIagVg1gtBMTTHvX0ojS716+ZvMAlTdvHCoWdmNoB/W06Ksx uqb3TYrYmkSNgd3dnCFlbMNYTA2ujK3FVrUpxqWwTccbPapdYovQMbfui+zOs9do+Q u+1URU3/Su+fctIP3uy4rVqV7qxWmhnvXjwHoqg9leZ2FkTZzwPtcqw0iU8EiIuJ2j Uh0UBl1mE7ji5b0dxNiUQW4yDNk97ZS+v8XcfaTJxbXrWii2YpTflPG8ksgXGM5zwS vA83ZSWRAbrfBtDyTlH9dASS8tY2e0WKhxpqqXqal9muo5b36slVjCLvEUermz6QWE R95dXIHBdYnjw== Date: Wed, 20 Dec 2023 04:08:09 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 06/11] ALSA: scarlett2: Add missing mutex lock around get meter levels Message-ID: <77e093c27402c83d0730681448fa4f57583349dd.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: As scarlett2_meter_ctl_get() uses meter_level_map[], the data_mutex should be locked while accessing it. Signed-off-by: Geoffrey D. Bennett Fixes: 2b17abb0dec4 ("ALSA: scarlett2: Remap Level Meter values") --- sound/usb/mixer_scarlett2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index f1636a1614da..73f5badceb19 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -3880,10 +3880,12 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, u16 meter_levels[SCARLETT2_MAX_METERS]; int i, err; + mutex_lock(&private->data_mutex); + err = scarlett2_usb_get_meter_levels(elem->head.mixer, elem->channels, meter_levels); if (err < 0) - return err; + goto unlock; /* copy & translate from meter_levels[] using meter_level_map[] */ for (i = 0; i < elem->channels; i++) { @@ -3898,7 +3900,10 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, ucontrol->value.integer.value[i] = value; } - return 0; +unlock: + mutex_unlock(&private->data_mutex); + + return err; } static const struct snd_kcontrol_new scarlett2_meter_ctl = { From patchwork Tue Dec 19 17:38:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498649 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D413E2E633 for ; Tue, 19 Dec 2023 17:38:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="tb1sscCU" Received: by m.b4.vu (Postfix, from userid 1000) id 141F8604B9F7; Wed, 20 Dec 2023 04:08:42 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 141F8604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007522; bh=NHjcjEOW30LqDt4IfDXMQ9aPNo751eyY/StHwOP1mLE=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=tb1sscCUykSPgoRHHihX2OnSiwKUlM4LfDpvrTM051ia1FS8gbOhavuqhCSA5ntM2 yTVn7+GHII6JVFG0GhvPMIUBenDodRJLJ8oIrp0auU2hvTTKr74qkEnG7wHKvxaGVa EmPZ17k1Jx1/Lu4e8dDehEHI5+6AJTrA5lcT1CuPeDculRlxbQ7kFDR1K87c9asAgt yJ79e9ldGlDQE057gNlGeYuo9alfHvwgeYvLa4XpxfE6bZ6bErxR9Zp0d4KMADjcz5 CCKH6Vnyf+Z2lJcGviZl0sMf2oUBVRg0SbW8XAPFbjWkzWFDKeJqzCBTBVJmZxHjBN ge5JBCR2l3bTg== Date: Wed, 20 Dec 2023 04:08:42 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 07/11] ALSA: scarlett2: Add #defines for firmware upgrade Message-ID: <3077651c21bc8d4f046c68b79ec387aa16fcc5e4.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add #defines for SCARLETT2_USB_* needed for firmware upgrade: reboot, info-flash, info-segment, erase-segment, get-erase, and write-segment. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett2.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 73f5badceb19..129b9c97871a 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -1137,17 +1137,23 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_CMD_REQ 2 #define SCARLETT2_USB_CMD_RESP 3 -#define SCARLETT2_USB_INIT_1 0x00000000 -#define SCARLETT2_USB_INIT_2 0x00000002 -#define SCARLETT2_USB_GET_METER 0x00001001 -#define SCARLETT2_USB_GET_MIX 0x00002001 -#define SCARLETT2_USB_SET_MIX 0x00002002 -#define SCARLETT2_USB_GET_MUX 0x00003001 -#define SCARLETT2_USB_SET_MUX 0x00003002 -#define SCARLETT2_USB_GET_SYNC 0x00006004 -#define SCARLETT2_USB_GET_DATA 0x00800000 -#define SCARLETT2_USB_SET_DATA 0x00800001 -#define SCARLETT2_USB_DATA_CMD 0x00800002 +#define SCARLETT2_USB_INIT_1 0x00000000 +#define SCARLETT2_USB_INIT_2 0x00000002 +#define SCARLETT2_USB_REBOOT 0x00000003 +#define SCARLETT2_USB_GET_METER 0x00001001 +#define SCARLETT2_USB_GET_MIX 0x00002001 +#define SCARLETT2_USB_SET_MIX 0x00002002 +#define SCARLETT2_USB_GET_MUX 0x00003001 +#define SCARLETT2_USB_SET_MUX 0x00003002 +#define SCARLETT2_USB_INFO_FLASH 0x00004000 +#define SCARLETT2_USB_INFO_SEGMENT 0x00004001 +#define SCARLETT2_USB_ERASE_SEGMENT 0x00004002 +#define SCARLETT2_USB_GET_ERASE 0x00004003 +#define SCARLETT2_USB_WRITE_SEGMENT 0x00004004 +#define SCARLETT2_USB_GET_SYNC 0x00006004 +#define SCARLETT2_USB_GET_DATA 0x00800000 +#define SCARLETT2_USB_SET_DATA 0x00800001 +#define SCARLETT2_USB_DATA_CMD 0x00800002 #define SCARLETT2_USB_CONFIG_SAVE 6 From patchwork Tue Dec 19 17:38:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498650 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC13337D05 for ; Tue, 19 Dec 2023 17:39:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="SwQYEH/r" Received: by m.b4.vu (Postfix, from userid 1000) id 9E3C6604B9F7; Wed, 20 Dec 2023 04:08:58 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 9E3C6604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007538; bh=i2UBZbVX9JemXjLTX5TBcZIY/bD71bJlRplkQc6myNQ=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=SwQYEH/r64tuYyekgUqn6HmGTxbZ1Ur+jtB5tLCTWIGBbAVFXBw3dFf1QcQvahJ6J iLBoe0FgybnuffxK4MTqG+/uWXDpfWj8z0MVwv/6CXYPPQH3mtu2wig5asCwEUrGaJ 8oOoD9kITWi4btYA5hRubJIF6l/6UmEdlk+IiZCkrx2zsjmemqcy0DU6+RagIBPns/ KoZtxPfHdWtwsAEB/6xuJ/xLMOs6F9pN0B3JZuRD0GymlSYv9Phz1CQAwQvg5a6GXa oQbT8TVnkkOe+H3NXVxbBqpmErbcrwEGENX/lBS3VbNENPpW2eYrkVBArTsroelGI0 PFuP10NQQ8YQg== Date: Wed, 20 Dec 2023 04:08:58 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 08/11] ALSA: scarlett2: Retrieve useful flash segment numbers Message-ID: <70f0108a9cf99b69f7aa920c4bcdb0cf4bf3da98.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Call SCARLETT2_USB_INFO_FLASH and SCARLETT2_USB_INFO_SEGMENT to find the App_Settings and App_Upgrade flash segment numbers, and store them in the scarlett2_data struct. These will be used later to implement reset to factory defaults and firmware upgrade functions. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett2.c | 103 ++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 129b9c97871a..34878f9f9a55 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -190,6 +190,11 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 16345 }; +/* Flash segments that we may manipulate */ +#define SCARLETT2_SEGMENT_ID_SETTINGS 0 +#define SCARLETT2_SEGMENT_ID_FIRMWARE 1 +#define SCARLETT2_SEGMENT_ID_COUNT 2 + /* Maximum number of analogue outputs */ #define SCARLETT2_ANALOGUE_MAX 10 @@ -429,6 +434,8 @@ struct scarlett2_data { int num_mux_srcs; int num_mux_dsts; u32 firmware_version; + u8 flash_segment_nums[SCARLETT2_SEGMENT_ID_COUNT]; + u8 flash_segment_blocks[SCARLETT2_SEGMENT_ID_COUNT]; u16 scarlett2_seq; u8 sync_updated; u8 vol_updated; @@ -1160,6 +1167,13 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31 #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 +#define SCARLETT2_FLASH_BLOCK_SIZE 4096 +#define SCARLETT2_SEGMENT_NUM_MIN 1 +#define SCARLETT2_SEGMENT_NUM_MAX 4 + +#define SCARLETT2_SEGMENT_SETTINGS_NAME "App_Settings" +#define SCARLETT2_SEGMENT_FIRMWARE_NAME "App_Upgrade" + /* volume status is read together (matches scarlett2_config_items[1]) */ struct scarlett2_usb_volume_status { /* dim/mute buttons */ @@ -4202,6 +4216,90 @@ static int scarlett2_usb_init(struct usb_mixer_interface *mixer) return 0; } +/* Get the flash segment numbers for the App_Settings and App_Upgrade + * segments and put them in the private data + */ +static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + int err, count, i; + + struct { + __le32 size; + __le32 count; + u8 unknown[8]; + } __packed flash_info; + + struct { + __le32 size; + __le32 flags; + char name[16]; + } __packed segment_info; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH, + NULL, 0, + &flash_info, sizeof(flash_info)); + if (err < 0) + return err; + + count = le32_to_cpu(flash_info.count); + + /* sanity check count */ + if (count < SCARLETT2_SEGMENT_NUM_MIN || + count > SCARLETT2_SEGMENT_NUM_MAX + 1) { + usb_audio_err(mixer->chip, + "invalid flash segment count: %d\n", count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + __le32 segment_num_req = cpu_to_le32(i); + int flash_segment_id; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT, + &segment_num_req, sizeof(segment_num_req), + &segment_info, sizeof(segment_info)); + if (err < 0) { + usb_audio_err(mixer->chip, + "failed to get flash segment info %d: %d\n", + i, err); + return err; + } + + if (!strncmp(segment_info.name, + SCARLETT2_SEGMENT_SETTINGS_NAME, 16)) + flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS; + else if (!strncmp(segment_info.name, + SCARLETT2_SEGMENT_FIRMWARE_NAME, 16)) + flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE; + else + continue; + + private->flash_segment_nums[flash_segment_id] = i; + private->flash_segment_blocks[flash_segment_id] = + le32_to_cpu(segment_info.size) / + SCARLETT2_FLASH_BLOCK_SIZE; + } + + /* segment 0 is App_Gold and we never want to touch that, so + * use 0 as the "not-found" value + */ + if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) { + usb_audio_err(mixer->chip, + "failed to find flash segment %s\n", + SCARLETT2_SEGMENT_SETTINGS_NAME); + return -EINVAL; + } + if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) { + usb_audio_err(mixer->chip, + "failed to find flash segment %s\n", + SCARLETT2_SEGMENT_FIRMWARE_NAME); + return -EINVAL; + } + + return 0; +} + /* Read configuration from the interface on start */ static int scarlett2_read_configs(struct usb_mixer_interface *mixer) { @@ -4517,6 +4615,11 @@ static int snd_scarlett2_controls_create( if (err < 0) return err; + /* Get the upgrade & settings flash segment numbers */ + err = scarlett2_get_flash_segment_nums(mixer); + if (err < 0) + return err; + /* Add firmware version control */ err = scarlett2_add_firmware_version_ctl(mixer); if (err < 0) From patchwork Tue Dec 19 17:39:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498651 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 89EED37D39 for ; Tue, 19 Dec 2023 17:39:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="G/3eEbQ+" Received: by m.b4.vu (Postfix, from userid 1000) id 50551604B9F7; Wed, 20 Dec 2023 04:09:23 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 50551604B9F7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703007563; bh=Wwcw9RjvBs9K31sVeM8U0U+Xy1IA51F7Ah/eptGSN5w=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=G/3eEbQ+yZ3imjDf8F2iRnOtUYpPbT2B/0/463WiEEpnVTl3GereBH1U4xfklNAHr 7nLn6XxQEZ0cAZoGIB4bvbHbKof1oHYqFU03rTkvs+hda78fNlyeLDaGl/CBjWX/cr gfSTGBYlS4y3clVICar56hK2kXPkEtG946OSvyRd0cELVvWQpVm+6RXcFlt1LxUX5o J4BQKc6CopqCgNYRGCiaDwQP2lki9tntrv8iFuQ9KZPr2RkTx4bZPtaARF5XBD/1h5 cbyT+mR1sSBZgZ36wmWYA7Lb0o73GYopSMXahHYaynnLfqz8MbAPub9AiKij4gzxwT oaKuS3GTpmUsQ== Date: Wed, 20 Dec 2023 04:09:23 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 09/11] ALSA: scarlett2: Add skeleton hwdep/ioctl interface Message-ID: <24ffcd47a8a02ebad3c8b2438104af8f0169164e.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add skeleton hwdep/ioctl interface, beginning with SCARLETT2_IOCTL_PVERSION and SCARLETT2_IOCTL_REBOOT. Signed-off-by: Geoffrey D. Bennett --- MAINTAINERS | 1 + include/uapi/sound/scarlett2.h | 34 +++++++++++++++++ sound/usb/mixer_scarlett2.c | 67 +++++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 include/uapi/sound/scarlett2.h diff --git a/MAINTAINERS b/MAINTAINERS index ae3f72f57854..80c65096538c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8279,6 +8279,7 @@ S: Maintained W: https://github.com/geoffreybennett/scarlett-gen2 B: https://github.com/geoffreybennett/scarlett-gen2/issues T: git https://github.com/geoffreybennett/scarlett-gen2.git +F: include/uapi/sound/scarlett2.h F: sound/usb/mixer_scarlett2.c FORCEDETH GIGABIT ETHERNET DRIVER diff --git a/include/uapi/sound/scarlett2.h b/include/uapi/sound/scarlett2.h new file mode 100644 index 000000000000..ec0b7da335ff --- /dev/null +++ b/include/uapi/sound/scarlett2.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Focusrite Scarlett 2 Protocol Driver for ALSA + * (including Scarlett 2nd Gen, 3rd Gen, Clarett USB, and Clarett+ + * series products) + * + * Copyright (c) 2023 by Geoffrey D. Bennett + */ +#ifndef __UAPI_SOUND_SCARLETT2_H +#define __UAPI_SOUND_SCARLETT2_H + +#include +#include + +#define SCARLETT2_HWDEP_MAJOR 1 +#define SCARLETT2_HWDEP_MINOR 0 +#define SCARLETT2_HWDEP_SUBMINOR 0 + +#define SCARLETT2_HWDEP_VERSION \ + ((SCARLETT2_HWDEP_MAJOR << 16) | \ + (SCARLETT2_HWDEP_MINOR << 8) | \ + SCARLETT2_HWDEP_SUBMINOR) + +#define SCARLETT2_HWDEP_VERSION_MAJOR(v) (((v) >> 16) & 0xFF) +#define SCARLETT2_HWDEP_VERSION_MINOR(v) (((v) >> 8) & 0xFF) +#define SCARLETT2_HWDEP_VERSION_SUBMINOR(v) ((v) & 0xFF) + +/* Get protocol version */ +#define SCARLETT2_IOCTL_PVERSION _IOR('S', 0x60, int) + +/* Reboot */ +#define SCARLETT2_IOCTL_REBOOT _IO('S', 0x61) + +#endif /* __UAPI_SOUND_SCARLETT2_H */ diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 34878f9f9a55..c0c96d7c19fb 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -146,6 +146,9 @@ #include #include +#include + +#include #include "usbaudio.h" #include "mixer.h" @@ -1439,6 +1442,16 @@ static int scarlett2_usb( /* validate the response */ if (err != resp_buf_size) { + + /* ESHUTDOWN and EPROTO are valid responses to a + * reboot request + */ + if (cmd == SCARLETT2_USB_REBOOT && + (err == -ESHUTDOWN || err == -EPROTO)) { + err = 0; + goto unlock; + } + usb_audio_err( mixer->chip, "%s USB response result cmd %x was %d expected %zu\n", @@ -4697,6 +4710,49 @@ static int snd_scarlett2_controls_create( return 0; } +/*** hwdep interface ***/ + +/* Reboot the device. */ +static int scarlett2_reboot(struct usb_mixer_interface *mixer) +{ + return scarlett2_usb(mixer, SCARLETT2_USB_REBOOT, NULL, 0, NULL, 0); +} + +static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct usb_mixer_interface *mixer = hw->private_data; + + switch (cmd) { + + case SCARLETT2_IOCTL_PVERSION: + return put_user(SCARLETT2_HWDEP_VERSION, + (int __user *)arg) ? -EFAULT : 0; + + case SCARLETT2_IOCTL_REBOOT: + return scarlett2_reboot(mixer); + + default: + return -ENOIOCTLCMD; + } +} + +static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) +{ + struct snd_hwdep *hw; + int err; + + err = snd_hwdep_new(mixer->chip->card, "Focusrite Control", 0, &hw); + if (err < 0) + return err; + + hw->private_data = mixer; + hw->exclusive = 1; + hw->ops.ioctl = scarlett2_hwdep_ioctl; + + return 0; +} + int snd_scarlett2_init(struct usb_mixer_interface *mixer) { struct snd_usb_audio *chip = mixer->chip; @@ -4738,11 +4794,20 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer) USB_ID_PRODUCT(chip->usb_id)); err = snd_scarlett2_controls_create(mixer, entry); - if (err < 0) + if (err < 0) { usb_audio_err(mixer->chip, "Error initialising %s Mixer Driver: %d", entry->series_name, err); + return err; + } + + err = scarlett2_hwdep_init(mixer); + if (err < 0) + usb_audio_err(mixer->chip, + "Error creating %s hwdep device: %d", + entry->series_name, + err); return err; } From patchwork Tue Dec 19 17:50:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498747 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 460493986E for ; Tue, 19 Dec 2023 17:50:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="PcoK4Bd4" Received: by m.b4.vu (Postfix, from userid 1000) id 2DB47604B9CB; Wed, 20 Dec 2023 04:20:29 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 2DB47604B9CB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703008229; bh=sN4jUcW5JJHf7WnupT3n8E5DZ78kAC8RXYMuPJPd1lA=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=PcoK4Bd46l8EQ7acWYWmb1jheHdchWqfFjHSa8NXp8RJ4/lDeNdQwPEYCVeynKfvR ArGk+S2om4IixF8grZwYPklyn7JQcHlTasrnNIQDXdOrXOn9C+xRLBxzeM0xNVqlmk NaBhe/27Jb+ljLkOa19qat9Dq02K2oxBwi3x+O+Of45FidQ/lwYib+Yr0JM2+ShdMH W90odDy21LEB5fhSjJoAYutNfFc4LNpIfmiL6HiJqKeoYDO/QhWwSHSFih1ijQlO6N LIMB0at8ofQlHUxtCfWqi6Zf4WH4ybQ9+V6xiirJjtFvK+yOfIeHEDST/H+XdAWOZS Mjp9G9HP6i/8A== Date: Wed, 20 Dec 2023 04:20:29 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 10/11] ALSA: scarlett2: Add ioctl commands to erase flash segments Message-ID: <227409adb672f174bf3db211e9bda016fb4646ea.1703001053.git.g@b4.vu> References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add ioctls: - SCARLETT2_IOCTL_SELECT_FLASH_SEGMENT - SCARLETT2_IOCTL_ERASE_FLASH_SEGMENT - SCARLETT2_IOCTL_GET_ERASE_PROGRESS The settings or the firmware flash segment can be selected and then erased (asynchronous operation), and the erase progress can be monitored. If the erase progress is not monitored, then subsequent hwdep operations will block until the erase is complete. Once the erase is started, ALSA controls that communicate with the device will all return -EBUSY, and the device must be rebooted. Signed-off-by: Geoffrey D. Bennett --- include/uapi/sound/scarlett2.h | 20 ++ sound/usb/mixer_scarlett2.c | 428 ++++++++++++++++++++++++++++++++- 2 files changed, 442 insertions(+), 6 deletions(-) diff --git a/include/uapi/sound/scarlett2.h b/include/uapi/sound/scarlett2.h index ec0b7da335ff..d0ff38ffa154 100644 --- a/include/uapi/sound/scarlett2.h +++ b/include/uapi/sound/scarlett2.h @@ -31,4 +31,24 @@ /* Reboot */ #define SCARLETT2_IOCTL_REBOOT _IO('S', 0x61) +/* Select flash segment */ +#define SCARLETT2_SEGMENT_ID_SETTINGS 0 +#define SCARLETT2_SEGMENT_ID_FIRMWARE 1 +#define SCARLETT2_SEGMENT_ID_COUNT 2 + +#define SCARLETT2_IOCTL_SELECT_FLASH_SEGMENT _IOW('S', 0x62, int) + +/* Erase selected flash segment */ +#define SCARLETT2_IOCTL_ERASE_FLASH_SEGMENT _IO('S', 0x63) + +/* Get selected flash segment erase progress + * 1 through to num_blocks, or 255 for complete + */ +struct scarlett2_flash_segment_erase_progress { + unsigned char progress; + unsigned char num_blocks; +}; +#define SCARLETT2_IOCTL_GET_ERASE_PROGRESS \ + _IOR('S', 0x64, struct scarlett2_flash_segment_erase_progress) + #endif /* __UAPI_SOUND_SCARLETT2_H */ diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index c0c96d7c19fb..ca09d0cd0cae 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -193,11 +193,6 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 16345 }; -/* Flash segments that we may manipulate */ -#define SCARLETT2_SEGMENT_ID_SETTINGS 0 -#define SCARLETT2_SEGMENT_ID_FIRMWARE 1 -#define SCARLETT2_SEGMENT_ID_COUNT 2 - /* Maximum number of analogue outputs */ #define SCARLETT2_ANALOGUE_MAX 10 @@ -267,6 +262,13 @@ enum { SCARLETT2_DIM_MUTE_COUNT = 2, }; +/* Flash Write State */ +enum { + SCARLETT2_FLASH_WRITE_STATE_IDLE = 0, + SCARLETT2_FLASH_WRITE_STATE_SELECTED = 1, + SCARLETT2_FLASH_WRITE_STATE_ERASING = 2 +}; + static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { "Mute Playback Switch", "Dim Playback Switch" }; @@ -427,6 +429,9 @@ struct scarlett2_data { struct usb_mixer_interface *mixer; struct mutex usb_mutex; /* prevent sending concurrent USB requests */ struct mutex data_mutex; /* lock access to this data */ + u8 hwdep_in_use; + u8 selected_flash_segment_id; + u8 flash_write_state; struct delayed_work work; const struct scarlett2_device_info *info; const char *series_name; @@ -2137,6 +2142,11 @@ static int scarlett2_sync_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->sync_updated) { err = scarlett2_update_sync(mixer); if (err < 0) @@ -2233,6 +2243,11 @@ static int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) @@ -2272,6 +2287,11 @@ static int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) @@ -2295,6 +2315,11 @@ static int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->vol[index]; val = ucontrol->value.integer.value[0]; @@ -2352,6 +2377,11 @@ static int scarlett2_mute_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) @@ -2375,6 +2405,11 @@ static int scarlett2_mute_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->mute_switch[index]; val = !!ucontrol->value.integer.value[0]; @@ -2514,6 +2549,11 @@ static int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->vol_sw_hw_switch[index]; val = !!ucontrol->value.enumerated.item[0]; @@ -2611,6 +2651,11 @@ static int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->input_other_updated) { err = scarlett2_update_input_other(mixer); if (err < 0) @@ -2636,6 +2681,11 @@ static int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->level_switch[index]; val = !!ucontrol->value.enumerated.item[0]; @@ -2675,6 +2725,11 @@ static int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->input_other_updated) { err = scarlett2_update_input_other(mixer); if (err < 0) @@ -2700,6 +2755,11 @@ static int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->pad_switch[index]; val = !!ucontrol->value.integer.value[0]; @@ -2739,6 +2799,11 @@ static int scarlett2_air_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->input_other_updated) { err = scarlett2_update_input_other(mixer); if (err < 0) @@ -2763,6 +2828,11 @@ static int scarlett2_air_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->air_switch[index]; val = !!ucontrol->value.integer.value[0]; @@ -2802,6 +2872,11 @@ static int scarlett2_phantom_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->input_other_updated) { err = scarlett2_update_input_other(mixer); if (err < 0) @@ -2827,6 +2902,11 @@ static int scarlett2_phantom_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->phantom_switch[index]; val = !!ucontrol->value.integer.value[0]; @@ -2878,6 +2958,11 @@ static int scarlett2_phantom_persistence_ctl_put( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->phantom_persistence; val = !!ucontrol->value.integer.value[0]; @@ -2988,6 +3073,11 @@ static int scarlett2_direct_monitor_ctl_get( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->monitor_other_updated) { err = scarlett2_update_monitor_other(mixer); if (err < 0) @@ -3012,6 +3102,11 @@ static int scarlett2_direct_monitor_ctl_put( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->direct_monitor_switch; val = min(ucontrol->value.enumerated.item[0], 2U); @@ -3101,6 +3196,11 @@ static int scarlett2_speaker_switch_enum_ctl_get( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->monitor_other_updated) { err = scarlett2_update_monitor_other(mixer); if (err < 0) @@ -3181,6 +3281,11 @@ static int scarlett2_speaker_switch_enum_ctl_put( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->speaker_switching_switch; val = min(ucontrol->value.enumerated.item[0], 2U); @@ -3262,6 +3367,11 @@ static int scarlett2_talkback_enum_ctl_get( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->monitor_other_updated) { err = scarlett2_update_monitor_other(mixer); if (err < 0) @@ -3285,6 +3395,11 @@ static int scarlett2_talkback_enum_ctl_put( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->talkback_switch; val = min(ucontrol->value.enumerated.item[0], 2U); @@ -3349,6 +3464,11 @@ static int scarlett2_talkback_map_ctl_put( mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->talkback_map[index]; val = !!ucontrol->value.integer.value[0]; @@ -3423,6 +3543,11 @@ static int scarlett2_dim_mute_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->vol_updated) { err = scarlett2_update_volumes(mixer); if (err < 0) @@ -3451,6 +3576,11 @@ static int scarlett2_dim_mute_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->dim_mute[index]; val = !!ucontrol->value.integer.value[0]; @@ -3695,6 +3825,11 @@ static int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->mix[index]; val = clamp(ucontrol->value.integer.value[0], 0L, (long)SCARLETT2_MIXER_MAX_VALUE); @@ -3808,6 +3943,11 @@ static int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + if (private->mux_updated) { err = scarlett2_usb_get_mux(mixer); if (err < 0) @@ -3831,6 +3971,11 @@ static int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->mux[index]; val = min(ucontrol->value.enumerated.item[0], private->num_mux_srcs - 1U); @@ -3915,6 +4060,11 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + err = scarlett2_usb_get_meter_levels(elem->head.mixer, elem->channels, meter_levels); if (err < 0) @@ -3983,6 +4133,11 @@ static int scarlett2_msd_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->msd_switch; val = !!ucontrol->value.integer.value[0]; @@ -4050,6 +4205,11 @@ static int scarlett2_standalone_ctl_put(struct snd_kcontrol *kctl, mutex_lock(&private->data_mutex); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + oval = private->standalone_switch; val = !!ucontrol->value.integer.value[0]; @@ -4712,12 +4872,241 @@ static int snd_scarlett2_controls_create( /*** hwdep interface ***/ -/* Reboot the device. */ +/* Set private->hwdep_in_use; prevents access to the ALSA controls + * while doing a config erase/firmware upgrade. + */ +static void scarlett2_lock(struct scarlett2_data *private) +{ + mutex_lock(&private->data_mutex); + private->hwdep_in_use = 1; + mutex_unlock(&private->data_mutex); +} + +/* Call SCARLETT2_USB_GET_ERASE to get the erase progress */ +static int scarlett2_get_erase_progress(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + int segment_id, segment_num, err; + u8 erase_resp; + + struct { + __le32 segment_num; + __le32 pad; + } __packed erase_req; + + segment_id = private->selected_flash_segment_id; + segment_num = private->flash_segment_nums[segment_id]; + + if (segment_num < SCARLETT2_SEGMENT_NUM_MIN || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) + return -EFAULT; + + /* Send the erase progress request */ + erase_req.segment_num = cpu_to_le32(segment_num); + erase_req.pad = 0; + + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_ERASE, + &erase_req, sizeof(erase_req), + &erase_resp, sizeof(erase_resp)); + if (err < 0) + return err; + + return erase_resp; +} + +/* Repeatedly call scarlett2_get_erase_progress() until it returns + * 0xff (erase complete) or we've waited 10 seconds (it usually takes + * <3 seconds). + */ +static int scarlett2_wait_for_erase(struct usb_mixer_interface *mixer) +{ + int i, err; + + for (i = 0; i < 100; i++) { + err = scarlett2_get_erase_progress(mixer); + if (err < 0) + return err; + + if (err == 0xff) + return 0; + + msleep(100); + } + + return -ETIMEDOUT; +} + +/* Reboot the device; wait for the erase to complete if one is in + * progress. + */ static int scarlett2_reboot(struct usb_mixer_interface *mixer) { + struct scarlett2_data *private = mixer->private_data; + + if (private->flash_write_state == + SCARLETT2_FLASH_WRITE_STATE_ERASING) { + int err = scarlett2_wait_for_erase(mixer); + + if (err < 0) + return err; + } + return scarlett2_usb(mixer, SCARLETT2_USB_REBOOT, NULL, 0, NULL, 0); } +/* Select a flash segment for erasing (and possibly writing to) */ +static int scarlett2_ioctl_select_flash_segment( + struct usb_mixer_interface *mixer, + unsigned long arg) +{ + struct scarlett2_data *private = mixer->private_data; + int segment_id, segment_num; + + if (get_user(segment_id, (int __user *)arg)) + return -EFAULT; + + /* Check the segment ID and segment number */ + if (segment_id < 0 || segment_id >= SCARLETT2_SEGMENT_ID_COUNT) + return -EINVAL; + + segment_num = private->flash_segment_nums[segment_id]; + if (segment_num < SCARLETT2_SEGMENT_NUM_MIN || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) { + usb_audio_err(mixer->chip, + "%s: invalid segment number %d\n", + __func__, segment_id); + return -EFAULT; + } + + /* If erasing, wait for it to complete */ + if (private->flash_write_state == SCARLETT2_FLASH_WRITE_STATE_ERASING) { + int err = scarlett2_wait_for_erase(mixer); + + if (err < 0) + return err; + } + + /* Save the selected segment ID and set the state to SELECTED */ + private->selected_flash_segment_id = segment_id; + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_SELECTED; + + return 0; +} + +/* Erase the previously-selected flash segment */ +static int scarlett2_ioctl_erase_flash_segment( + struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + int segment_id, segment_num, err; + + struct { + __le32 segment_num; + __le32 pad; + } __packed erase_req; + + if (private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_SELECTED) + return -EINVAL; + + segment_id = private->selected_flash_segment_id; + segment_num = private->flash_segment_nums[segment_id]; + + if (segment_num < SCARLETT2_SEGMENT_NUM_MIN || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) + return -EFAULT; + + /* Prevent access to ALSA controls that access the device from + * here on + */ + scarlett2_lock(private); + + /* Send the erase request */ + erase_req.segment_num = cpu_to_le32(segment_num); + erase_req.pad = 0; + + err = scarlett2_usb(mixer, SCARLETT2_USB_ERASE_SEGMENT, + &erase_req, sizeof(erase_req), + NULL, 0); + if (err < 0) + return err; + + /* On success, change the state from SELECTED to ERASING */ + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_ERASING; + + return 0; +} + +/* Get the erase progress from the device */ +static int scarlett2_ioctl_get_erase_progress( + struct usb_mixer_interface *mixer, + unsigned long arg) +{ + struct scarlett2_data *private = mixer->private_data; + struct scarlett2_flash_segment_erase_progress progress; + int segment_id, segment_num, err; + u8 erase_resp; + + struct { + __le32 segment_num; + __le32 pad; + } __packed erase_req; + + /* Check that we're erasing */ + if (private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_ERASING) + return -EINVAL; + + segment_id = private->selected_flash_segment_id; + segment_num = private->flash_segment_nums[segment_id]; + + if (segment_num < SCARLETT2_SEGMENT_NUM_MIN || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) + return -EFAULT; + + /* Send the erase progress request */ + erase_req.segment_num = cpu_to_le32(segment_num); + erase_req.pad = 0; + + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_ERASE, + &erase_req, sizeof(erase_req), + &erase_resp, sizeof(erase_resp)); + if (err < 0) + return err; + + progress.progress = erase_resp; + progress.num_blocks = private->flash_segment_blocks[segment_id]; + + if (copy_to_user((void __user *)arg, &progress, sizeof(progress))) + return -EFAULT; + + /* If the erase is complete, change the state from ERASING to + * IDLE. + */ + if (progress.progress == 0xff) + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_IDLE; + + return 0; +} + +static int scarlett2_hwdep_open(struct snd_hwdep *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + struct scarlett2_data *private = mixer->private_data; + + /* If erasing, wait for it to complete */ + if (private->flash_write_state == + SCARLETT2_FLASH_WRITE_STATE_ERASING) { + int err = scarlett2_wait_for_erase(mixer); + + if (err < 0) + return err; + } + + /* Set the state to IDLE */ + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_IDLE; + + return 0; +} + static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) { @@ -4732,11 +5121,36 @@ static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, case SCARLETT2_IOCTL_REBOOT: return scarlett2_reboot(mixer); + case SCARLETT2_IOCTL_SELECT_FLASH_SEGMENT: + return scarlett2_ioctl_select_flash_segment(mixer, arg); + + case SCARLETT2_IOCTL_ERASE_FLASH_SEGMENT: + return scarlett2_ioctl_erase_flash_segment(mixer); + + case SCARLETT2_IOCTL_GET_ERASE_PROGRESS: + return scarlett2_ioctl_get_erase_progress(mixer, arg); + default: return -ENOIOCTLCMD; } } +static int scarlett2_hwdep_release(struct snd_hwdep *hw, struct file *file) +{ + struct usb_mixer_interface *mixer = hw->private_data; + struct scarlett2_data *private = mixer->private_data; + + /* Return from the SELECTED or WRITE state to IDLE. + * The ERASING state is left as-is, and checked on next open. + */ + if (private && + private->hwdep_in_use && + private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_ERASING) + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_IDLE; + + return 0; +} + static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) { struct snd_hwdep *hw; @@ -4748,7 +5162,9 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) hw->private_data = mixer; hw->exclusive = 1; + hw->ops.open = scarlett2_hwdep_open; hw->ops.ioctl = scarlett2_hwdep_ioctl; + hw->ops.release = scarlett2_hwdep_release; return 0; } From patchwork Tue Dec 19 17:50:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Geoffrey D. Bennett" X-Patchwork-Id: 13498748 Received: from m.b4.vu (m.b4.vu [203.16.231.148]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 093AB41C7C for ; Tue, 19 Dec 2023 17:50:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=b4.vu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=b4.vu Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=b4.vu header.i=@b4.vu header.b="nAPSaB7k" Received: by m.b4.vu (Postfix, from userid 1000) id 06DC2604B9CB; Wed, 20 Dec 2023 04:20:56 +1030 (ACDT) DKIM-Filter: OpenDKIM Filter v2.11.0 m.b4.vu 06DC2604B9CB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=b4.vu; s=m1; t=1703008256; bh=YyQGcbQaeEvepBxl5EF5haAlnb5x8IHq3wQvDFU7jms=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=nAPSaB7kQaugVz5gFx3T0aKFuxVzssY/gyK9+M5uiQagQrnc3ykw6Jb1hQ1aeAg09 qy8B0GdnjrEo88fC1S93SGHzxqui8g6kW70Zp1zQAoVV7R5bLCy4sDmUrDpz2Ucax+ i92qzSHY1mOfuZDCGMHbgZcDSCXHIXUcA5Z+FHQz4AFaPzOFZhbYKo2I+a9Q4vOcWQ nzhaIhpE1asHH0azzv0cpZXIa6UgIj6wBFxt8AnsZpXHo8DZg28avLeurufWkmk2Lu AB2a3P+bbxAa7RPZIYXqgthLFKCaONqXDrkxtGewxl7zGMPl4yyyhjhCHui8LShoCn 6kVs0qOTiJQ7g== Date: Wed, 20 Dec 2023 04:20:55 +1030 From: "Geoffrey D. Bennett" To: Takashi Iwai Cc: Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-sound@vger.kernel.org Subject: [PATCH 11/11] ALSA: scarlett2: Add support for uploading new firmware Message-ID: References: Precedence: bulk X-Mailing-List: linux-sound@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add ops.write to the hwdep interface. Once the upgrade firmware flash segment has been erased, writes to the hwdep fd are permitted, and translated to SCARLETT2_USB_WRITE_SEGMENT commands to the device. Signed-off-by: Geoffrey D. Bennett --- sound/usb/mixer_scarlett2.c | 96 +++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index ca09d0cd0cae..f1337a379833 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -266,7 +266,8 @@ enum { enum { SCARLETT2_FLASH_WRITE_STATE_IDLE = 0, SCARLETT2_FLASH_WRITE_STATE_SELECTED = 1, - SCARLETT2_FLASH_WRITE_STATE_ERASING = 2 + SCARLETT2_FLASH_WRITE_STATE_ERASING = 2, + SCARLETT2_FLASH_WRITE_STATE_WRITE = 3 }; static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { @@ -1176,6 +1177,7 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 #define SCARLETT2_FLASH_BLOCK_SIZE 4096 +#define SCARLETT2_FLASH_WRITE_MAX 1024 #define SCARLETT2_SEGMENT_NUM_MIN 1 #define SCARLETT2_SEGMENT_NUM_MAX 4 @@ -5079,10 +5081,10 @@ static int scarlett2_ioctl_get_erase_progress( return -EFAULT; /* If the erase is complete, change the state from ERASING to - * IDLE. + * WRITE. */ if (progress.progress == 0xff) - private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_IDLE; + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_WRITE; return 0; } @@ -5135,6 +5137,93 @@ static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, } } +static long scarlett2_hwdep_write(struct snd_hwdep *hw, + const char __user *buf, + long count, loff_t *offset) +{ + struct usb_mixer_interface *mixer = hw->private_data; + struct scarlett2_data *private = mixer->private_data; + int segment_id, segment_num, err, len; + int flash_size; + + /* SCARLETT2_USB_WRITE_SEGMENT request data */ + struct { + __le32 segment_num; + __le32 offset; + __le32 pad; + u8 data[]; + } __packed *req; + + /* Calculate the maximum permitted in data[] */ + const size_t max_data_size = SCARLETT2_FLASH_WRITE_MAX - + offsetof(typeof(*req), data); + + /* If erasing, wait for it to complete */ + if (private->flash_write_state == + SCARLETT2_FLASH_WRITE_STATE_ERASING) { + err = scarlett2_wait_for_erase(mixer); + if (err < 0) + return err; + private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_WRITE; + + /* Check that an erase has been done & completed */ + } else if (private->flash_write_state != + SCARLETT2_FLASH_WRITE_STATE_WRITE) { + return -EINVAL; + } + + /* Check that we're writing to the upgrade firmware */ + segment_id = private->selected_flash_segment_id; + if (segment_id != SCARLETT2_SEGMENT_ID_FIRMWARE) + return -EINVAL; + + segment_num = private->flash_segment_nums[segment_id]; + if (segment_num < SCARLETT2_SEGMENT_NUM_MIN || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) + return -EFAULT; + + /* Validate the offset and count */ + flash_size = private->flash_segment_blocks[segment_id] * + SCARLETT2_FLASH_BLOCK_SIZE; + + if (count < 0 || *offset < 0 || *offset + count >= flash_size) + return -EINVAL; + + if (!count) + return 0; + + /* Limit the *req size to SCARLETT2_FLASH_WRITE_MAX */ + if (count > max_data_size) + count = max_data_size; + + /* Create and send the request */ + len = struct_size(req, data, count); + req = kzalloc(len, GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->segment_num = cpu_to_le32(segment_num); + req->offset = cpu_to_le32(*offset); + req->pad = 0; + + if (copy_from_user(req->data, buf, count)) { + err = -EFAULT; + goto error; + } + + err = scarlett2_usb(mixer, SCARLETT2_USB_WRITE_SEGMENT, + req, len, NULL, 0); + if (err < 0) + goto error; + + *offset += count; + +error: + kfree(req); + + return count; +} + static int scarlett2_hwdep_release(struct snd_hwdep *hw, struct file *file) { struct usb_mixer_interface *mixer = hw->private_data; @@ -5164,6 +5253,7 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) hw->exclusive = 1; hw->ops.open = scarlett2_hwdep_open; hw->ops.ioctl = scarlett2_hwdep_ioctl; + hw->ops.write = scarlett2_hwdep_write; hw->ops.release = scarlett2_hwdep_release; return 0;