Skip to content

Commit 9930c26

Browse files
geoffreybennetttiwai
authored andcommitted
ALSA: scarlett2: Add support for device map retrieval
Add support for retrieving the device map from Focusrite Scarlett 4th Gen and Vocaster devices. The device map is a base64-encoded, zlib-compressed JSON description of the device's capabilities and configuration. This patch adds: - a has_devmap field to the scarlett2_device_info struct - a /proc/asound/cardX/device-map.json.zz.b64 file when supported Signed-off-by: Geoffrey D. Bennett <[email protected]> Signed-off-by: Takashi Iwai <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 8eba063 commit 9930c26

File tree

1 file changed

+138
-1
lines changed

1 file changed

+138
-1
lines changed

sound/usb/mixer_scarlett2.c

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,9 @@ struct scarlett2_device_info {
10791079
/* minimum firmware version required */
10801080
u16 min_firmware_version;
10811081

1082+
/* has a downloadable device map */
1083+
u8 has_devmap;
1084+
10821085
/* support for main/alt speaker switching */
10831086
u8 has_speaker_switching;
10841087

@@ -1773,6 +1776,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
17731776
static const struct scarlett2_device_info vocaster_one_info = {
17741777
.config_set = &scarlett2_config_set_vocaster,
17751778
.min_firmware_version = 1769,
1779+
.has_devmap = 1,
17761780

17771781
.phantom_count = 1,
17781782
.inputs_per_phantom = 1,
@@ -1815,6 +1819,7 @@ static const struct scarlett2_device_info vocaster_one_info = {
18151819
static const struct scarlett2_device_info vocaster_two_info = {
18161820
.config_set = &scarlett2_config_set_vocaster,
18171821
.min_firmware_version = 1769,
1822+
.has_devmap = 1,
18181823

18191824
.phantom_count = 2,
18201825
.inputs_per_phantom = 1,
@@ -1858,6 +1863,7 @@ static const struct scarlett2_device_info vocaster_two_info = {
18581863
static const struct scarlett2_device_info solo_gen4_info = {
18591864
.config_set = &scarlett2_config_set_gen4_solo,
18601865
.min_firmware_version = 2115,
1866+
.has_devmap = 1,
18611867

18621868
.level_input_count = 1,
18631869
.air_input_count = 1,
@@ -1912,6 +1918,7 @@ static const struct scarlett2_device_info solo_gen4_info = {
19121918
static const struct scarlett2_device_info s2i2_gen4_info = {
19131919
.config_set = &scarlett2_config_set_gen4_2i2,
19141920
.min_firmware_version = 2115,
1921+
.has_devmap = 1,
19151922

19161923
.level_input_count = 2,
19171924
.air_input_count = 2,
@@ -1966,6 +1973,7 @@ static const struct scarlett2_device_info s2i2_gen4_info = {
19661973
static const struct scarlett2_device_info s4i4_gen4_info = {
19671974
.config_set = &scarlett2_config_set_gen4_4i4,
19681975
.min_firmware_version = 2089,
1976+
.has_devmap = 1,
19691977

19701978
.level_input_count = 2,
19711979
.air_input_count = 2,
@@ -2264,6 +2272,8 @@ static int scarlett2_get_port_start_num(
22642272
#define SCARLETT2_USB_GET_DATA 0x00800000
22652273
#define SCARLETT2_USB_SET_DATA 0x00800001
22662274
#define SCARLETT2_USB_DATA_CMD 0x00800002
2275+
#define SCARLETT2_USB_INFO_DEVMAP 0x0080000c
2276+
#define SCARLETT2_USB_GET_DEVMAP 0x0080000d
22672277

22682278
#define SCARLETT2_USB_CONFIG_SAVE 6
22692279

@@ -2277,6 +2287,14 @@ static int scarlett2_get_port_start_num(
22772287
#define SCARLETT2_SEGMENT_SETTINGS_NAME "App_Settings"
22782288
#define SCARLETT2_SEGMENT_FIRMWARE_NAME "App_Upgrade"
22792289

2290+
/* Gen 4 device firmware provides access to a base64-encoded
2291+
* zlib-compressed JSON description of the device's capabilities and
2292+
* configuration. This device map is made available in
2293+
* /proc/asound/cardX/device-map.json.zz.b64
2294+
*/
2295+
#define SCARLETT2_DEVMAP_BLOCK_SIZE 1024
2296+
#define SCARLETT2_DEVMAP_FILENAME "device-map.json.zz.b64"
2297+
22802298
/* proprietary request/response format */
22812299
struct scarlett2_usb_packet {
22822300
__le32 cmd;
@@ -9562,6 +9580,116 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer)
95629580
return 0;
95639581
}
95649582

9583+
/*** device-map file ***/
9584+
9585+
static ssize_t scarlett2_devmap_read(
9586+
struct snd_info_entry *entry,
9587+
void *file_private_data,
9588+
struct file *file,
9589+
char __user *buf,
9590+
size_t count,
9591+
loff_t pos)
9592+
{
9593+
struct usb_mixer_interface *mixer = entry->private_data;
9594+
u8 *resp_buf;
9595+
const size_t block_size = SCARLETT2_DEVMAP_BLOCK_SIZE;
9596+
size_t copied = 0;
9597+
9598+
if (pos >= entry->size)
9599+
return 0;
9600+
9601+
if (pos + count > entry->size)
9602+
count = entry->size - pos;
9603+
9604+
resp_buf = kmalloc(block_size, GFP_KERNEL);
9605+
if (!resp_buf)
9606+
return -ENOMEM;
9607+
9608+
while (count > 0) {
9609+
/* SCARLETT2_USB_GET_DEVMAP reads only on block boundaries,
9610+
* so we need to read a whole block and copy the requested
9611+
* chunk to userspace.
9612+
*/
9613+
9614+
__le32 req;
9615+
int err;
9616+
9617+
/* offset within the block that we're reading */
9618+
size_t offset = pos % block_size;
9619+
9620+
/* read_size is block_size except for the last block */
9621+
size_t block_start = pos - offset;
9622+
size_t read_size = min_t(size_t,
9623+
block_size,
9624+
entry->size - block_start);
9625+
9626+
/* size of the chunk to copy to userspace */
9627+
size_t copy_size = min_t(size_t, count, read_size - offset);
9628+
9629+
/* request the block */
9630+
req = cpu_to_le32(pos / block_size);
9631+
err = scarlett2_usb(mixer, SCARLETT2_USB_GET_DEVMAP,
9632+
&req, sizeof(req), resp_buf, read_size);
9633+
if (err < 0) {
9634+
kfree(resp_buf);
9635+
return copied ? copied : err;
9636+
}
9637+
9638+
if (copy_to_user(buf, resp_buf + offset, copy_size)) {
9639+
kfree(resp_buf);
9640+
return -EFAULT;
9641+
}
9642+
9643+
buf += copy_size;
9644+
pos += copy_size;
9645+
copied += copy_size;
9646+
count -= copy_size;
9647+
}
9648+
9649+
kfree(resp_buf);
9650+
return copied;
9651+
}
9652+
9653+
static const struct snd_info_entry_ops scarlett2_devmap_ops = {
9654+
.read = scarlett2_devmap_read,
9655+
};
9656+
9657+
static int scarlett2_devmap_init(struct usb_mixer_interface *mixer)
9658+
{
9659+
struct snd_card *card = mixer->chip->card;
9660+
struct scarlett2_data *private = mixer->private_data;
9661+
const struct scarlett2_device_info *info = private->info;
9662+
__le16 config_len_buf[2];
9663+
int config_len;
9664+
struct snd_info_entry *entry;
9665+
int err;
9666+
9667+
/* If the device doesn't support the DEVMAP commands, don't
9668+
* create the /proc/asound/cardX/scarlett.json.zlib entry
9669+
*/
9670+
if (!info->has_devmap)
9671+
return 0;
9672+
9673+
err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_DEVMAP,
9674+
NULL, 0, &config_len_buf, sizeof(config_len_buf));
9675+
if (err < 0)
9676+
return err;
9677+
9678+
config_len = le16_to_cpu(config_len_buf[1]);
9679+
9680+
err = snd_card_proc_new(card, SCARLETT2_DEVMAP_FILENAME, &entry);
9681+
if (err < 0)
9682+
return err;
9683+
9684+
entry->content = SNDRV_INFO_CONTENT_DATA;
9685+
entry->private_data = mixer;
9686+
entry->c.ops = &scarlett2_devmap_ops;
9687+
entry->size = config_len;
9688+
entry->mode = S_IFREG | 0444;
9689+
9690+
return 0;
9691+
}
9692+
95659693
int snd_scarlett2_init(struct usb_mixer_interface *mixer)
95669694
{
95679695
struct snd_usb_audio *chip = mixer->chip;
@@ -9612,11 +9740,20 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer)
96129740
}
96139741

96149742
err = scarlett2_hwdep_init(mixer);
9615-
if (err < 0)
9743+
if (err < 0) {
96169744
usb_audio_err(mixer->chip,
96179745
"Error creating %s hwdep device: %d",
96189746
entry->series_name,
96199747
err);
9748+
return err;
9749+
}
9750+
9751+
err = scarlett2_devmap_init(mixer);
9752+
if (err < 0)
9753+
usb_audio_err(mixer->chip,
9754+
"Error creating %s devmap entry: %d",
9755+
entry->series_name,
9756+
err);
96209757

96219758
return err;
96229759
}

0 commit comments

Comments
 (0)