Skip to content

Commit 3473185

Browse files
geoffreybennetttiwai
authored andcommitted
ALSA: scarlett2: Remap Level Meter values
The values previously returned by the Level Meter control were passed through from the interface without interpretation, but it has been discovered that the order of the values matches the mux assignment order (which is not presented to userspace). In addition, the values for disabled mux outputs, and mux outputs which share a source are invalid. This patch adds a per-device meter_map[], and a dynamic meter_level_map[] which is updated on routing changes. The meter level map gets used by scarlett2_meter_ctl_get() to both present the values in a standard order, and to fix up the invalid values by zeroing them (for disabled outputs) and copying them (for mux outputs which share a source). Signed-off-by: Geoffrey D. Bennett <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 2190b9a commit 3473185

File tree

1 file changed

+186
-2
lines changed

1 file changed

+186
-2
lines changed

sound/usb/mixer_scarlett2.c

Lines changed: 186 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = {
210210
*/
211211
#define SCARLETT2_MUX_MAX 77
212212

213+
/* Maximum number of sources (sum of input port counts) */
214+
#define SCARLETT2_MAX_SRCS 52
215+
213216
/* Maximum number of meters (sum of output port counts) */
214217
#define SCARLETT2_MAX_METERS 65
215218

@@ -328,6 +331,18 @@ struct scarlett2_mux_entry {
328331
u8 count;
329332
};
330333

334+
/* Maximum number of entries in a mux table */
335+
#define SCARLETT2_MAX_METER_ENTRIES 9
336+
337+
/* One entry within meter_assignment defines the range of mux outputs
338+
* that consecutive meter entries are mapped to. The end of the list
339+
* is marked with count == 0.
340+
*/
341+
struct scarlett2_meter_entry {
342+
u8 start;
343+
u8 count;
344+
};
345+
331346
struct scarlett2_device_info {
332347
/* Gen 3 devices have an internal MSD mode switch that needs
333348
* to be disabled in order to access the full functionality of
@@ -381,6 +396,7 @@ struct scarlett2_device_info {
381396
*/
382397
u8 line_out_remap_enable;
383398
u8 line_out_remap[SCARLETT2_ANALOGUE_MAX];
399+
u8 line_out_unmap[SCARLETT2_ANALOGUE_MAX];
384400

385401
/* additional description for the line out volume controls */
386402
const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
@@ -391,6 +407,12 @@ struct scarlett2_device_info {
391407
/* layout/order of the entries in the set_mux message */
392408
struct scarlett2_mux_entry mux_assignment[SCARLETT2_MUX_TABLES]
393409
[SCARLETT2_MAX_MUX_ENTRIES];
410+
411+
/* map from meter level order returned by
412+
* SCARLETT2_USB_GET_METER to index into mux[] entries (same
413+
* as the order returned by scarlett2_meter_ctl_get())
414+
*/
415+
struct scarlett2_meter_entry meter_map[SCARLETT2_MAX_METER_ENTRIES];
394416
};
395417

396418
struct scarlett2_data {
@@ -431,6 +453,7 @@ struct scarlett2_data {
431453
u8 talkback_map[SCARLETT2_OUTPUT_MIX_MAX];
432454
u8 msd_switch;
433455
u8 standalone_switch;
456+
u8 meter_level_map[SCARLETT2_MAX_METERS];
434457
struct snd_kcontrol *sync_ctl;
435458
struct snd_kcontrol *master_vol_ctl;
436459
struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX];
@@ -493,6 +516,12 @@ static const struct scarlett2_device_info s6i6_gen2_info = {
493516
{ SCARLETT2_PORT_TYPE_NONE, 0, 8 },
494517
{ 0, 0, 0 },
495518
} },
519+
520+
.meter_map = {
521+
{ 24, 6 },
522+
{ 0, 24 },
523+
{ 0, 0 },
524+
}
496525
};
497526

498527
static const struct scarlett2_device_info s18i8_gen2_info = {
@@ -540,6 +569,12 @@ static const struct scarlett2_device_info s18i8_gen2_info = {
540569
{ SCARLETT2_PORT_TYPE_NONE, 0, 4 },
541570
{ 0, 0, 0 },
542571
} },
572+
573+
.meter_map = {
574+
{ 26, 18 },
575+
{ 0, 26 },
576+
{ 0, 0 },
577+
}
543578
};
544579

545580
static const struct scarlett2_device_info s18i20_gen2_info = {
@@ -592,6 +627,12 @@ static const struct scarlett2_device_info s18i20_gen2_info = {
592627
{ SCARLETT2_PORT_TYPE_NONE, 0, 6 },
593628
{ 0, 0, 0 },
594629
} },
630+
631+
.meter_map = {
632+
{ 38, 18 },
633+
{ 0, 38 },
634+
{ 0, 0 },
635+
}
595636
};
596637

597638
static const struct scarlett2_device_info solo_gen3_info = {
@@ -657,6 +698,12 @@ static const struct scarlett2_device_info s4i4_gen3_info = {
657698
{ SCARLETT2_PORT_TYPE_NONE, 0, 16 },
658699
{ 0, 0, 0 },
659700
} },
701+
702+
.meter_map = {
703+
{ 12, 6 },
704+
{ 0, 12 },
705+
{ 0, 0 },
706+
}
660707
};
661708

662709
static const struct scarlett2_device_info s8i6_gen3_info = {
@@ -708,6 +755,14 @@ static const struct scarlett2_device_info s8i6_gen3_info = {
708755
{ SCARLETT2_PORT_TYPE_NONE, 0, 18 },
709756
{ 0, 0, 0 },
710757
} },
758+
759+
.meter_map = {
760+
{ 14, 8 },
761+
{ 0, 6 },
762+
{ 22, 2 },
763+
{ 6, 8 },
764+
{ 0, 0 },
765+
}
711766
};
712767

713768
static const struct scarlett2_device_info s18i8_gen3_info = {
@@ -723,6 +778,7 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
723778

724779
.line_out_remap_enable = 1,
725780
.line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 },
781+
.line_out_unmap = { 0, 1, 4, 5, 6, 7, 2, 3 },
726782

727783
.line_out_descrs = {
728784
"Monitor L",
@@ -776,6 +832,18 @@ static const struct scarlett2_device_info s18i8_gen3_info = {
776832
{ SCARLETT2_PORT_TYPE_NONE, 0, 10 },
777833
{ 0, 0, 0 },
778834
} },
835+
836+
.meter_map = {
837+
{ 30, 10 },
838+
{ 42, 8 },
839+
{ 0, 2 },
840+
{ 6, 2 },
841+
{ 2, 4 },
842+
{ 8, 2 },
843+
{ 40, 2 },
844+
{ 10, 20 },
845+
{ 0, 0 }
846+
}
779847
};
780848

781849
static const struct scarlett2_device_info s18i20_gen3_info = {
@@ -839,6 +907,15 @@ static const struct scarlett2_device_info s18i20_gen3_info = {
839907
{ SCARLETT2_PORT_TYPE_NONE, 0, 24 },
840908
{ 0, 0, 0 },
841909
} },
910+
911+
.meter_map = {
912+
{ 45, 8 },
913+
{ 55, 10 },
914+
{ 0, 20 },
915+
{ 53, 2 },
916+
{ 20, 25 },
917+
{ 0, 0 },
918+
}
842919
};
843920

844921
static const struct scarlett2_device_info clarett_2pre_info = {
@@ -881,6 +958,12 @@ static const struct scarlett2_device_info clarett_2pre_info = {
881958
{ SCARLETT2_PORT_TYPE_NONE, 0, 26 },
882959
{ 0, 0, 0 },
883960
} },
961+
962+
.meter_map = {
963+
{ 22, 12 },
964+
{ 0, 22 },
965+
{ 0, 0 }
966+
}
884967
};
885968

886969
static const struct scarlett2_device_info clarett_4pre_info = {
@@ -928,6 +1011,12 @@ static const struct scarlett2_device_info clarett_4pre_info = {
9281011
{ SCARLETT2_PORT_TYPE_NONE, 0, 24 },
9291012
{ 0, 0, 0 },
9301013
} },
1014+
1015+
.meter_map = {
1016+
{ 26, 18 },
1017+
{ 0, 26 },
1018+
{ 0, 0 }
1019+
}
9311020
};
9321021

9331022
static const struct scarlett2_device_info clarett_8pre_info = {
@@ -981,6 +1070,12 @@ static const struct scarlett2_device_info clarett_8pre_info = {
9811070
{ SCARLETT2_PORT_TYPE_NONE, 0, 22 },
9821071
{ 0, 0, 0 },
9831072
} },
1073+
1074+
.meter_map = {
1075+
{ 38, 18 },
1076+
{ 0, 38 },
1077+
{ 0, 0 }
1078+
}
9841079
};
9851080

9861081
struct scarlett2_device_entry {
@@ -1688,6 +1783,79 @@ static void scarlett2_usb_populate_mux(struct scarlett2_data *private,
16881783
private->mux[dst_idx] = src_idx;
16891784
}
16901785

1786+
/* Update the meter level map
1787+
*
1788+
* The meter level data from the interface (SCARLETT2_USB_GET_METER
1789+
* request) is returned in mux_assignment order, but to avoid exposing
1790+
* that to userspace, scarlett2_meter_ctl_get() rearranges the data
1791+
* into scarlett2_ports order using the meter_level_map[] array which
1792+
* is set up by this function.
1793+
*
1794+
* In addition, the meter level data values returned from the
1795+
* interface are invalid for destinations where:
1796+
*
1797+
* - the source is "Off"; therefore we set those values to zero (map
1798+
* value of 255)
1799+
*
1800+
* - the source is assigned to a previous (with respect to the
1801+
* mux_assignment order) destination; therefore we set those values
1802+
* to the value previously reported for that source
1803+
*/
1804+
static void scarlett2_update_meter_level_map(struct scarlett2_data *private)
1805+
{
1806+
const struct scarlett2_device_info *info = private->info;
1807+
const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
1808+
int line_out_count =
1809+
port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT];
1810+
const struct scarlett2_meter_entry *entry;
1811+
1812+
/* sources already assigned to a destination
1813+
* value is 255 for None, otherwise the value of i
1814+
* (index into array returned by
1815+
* scarlett2_usb_get_meter_levels())
1816+
*/
1817+
u8 seen_src[SCARLETT2_MAX_SRCS] = { 1 };
1818+
u8 seen_src_value[SCARLETT2_MAX_SRCS] = { 255 };
1819+
1820+
/* index in meter_map[] order */
1821+
int i = 0;
1822+
1823+
/* go through the meter_map[] entries */
1824+
for (entry = info->meter_map;
1825+
entry->count;
1826+
entry++) {
1827+
1828+
/* fill in each meter_level_map[] entry */
1829+
int j, mux_idx;
1830+
1831+
for (j = 0, mux_idx = entry->start;
1832+
j < entry->count;
1833+
i++, j++, mux_idx++) {
1834+
1835+
/* convert mux_idx using line_out_unmap[] */
1836+
int map_mux_idx = (
1837+
info->line_out_remap_enable &&
1838+
mux_idx < line_out_count
1839+
) ? info->line_out_unmap[mux_idx]
1840+
: mux_idx;
1841+
1842+
/* check which source is connected, and if
1843+
* that source is already connected elsewhere,
1844+
* use that existing connection's destination
1845+
* for this meter entry instead
1846+
*/
1847+
int mux_src = private->mux[mux_idx];
1848+
1849+
if (!seen_src[mux_src]) {
1850+
seen_src[mux_src] = 1;
1851+
seen_src_value[mux_src] = i;
1852+
}
1853+
private->meter_level_map[map_mux_idx] =
1854+
seen_src_value[mux_src];
1855+
}
1856+
}
1857+
}
1858+
16911859
/* Send USB message to get mux inputs and then populate private->mux[] */
16921860
static int scarlett2_usb_get_mux(struct usb_mixer_interface *mixer)
16931861
{
@@ -1716,6 +1884,8 @@ static int scarlett2_usb_get_mux(struct usb_mixer_interface *mixer)
17161884
for (i = 0; i < count; i++)
17171885
scarlett2_usb_populate_mux(private, le32_to_cpu(data[i]));
17181886

1887+
scarlett2_update_meter_level_map(private);
1888+
17191889
return 0;
17201890
}
17211891

@@ -1782,6 +1952,8 @@ static int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer)
17821952
return err;
17831953
}
17841954

1955+
scarlett2_update_meter_level_map(private);
1956+
17851957
return 0;
17861958
}
17871959

@@ -3619,6 +3791,8 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl,
36193791
struct snd_ctl_elem_value *ucontrol)
36203792
{
36213793
struct usb_mixer_elem_info *elem = kctl->private_data;
3794+
struct scarlett2_data *private = elem->head.mixer->private_data;
3795+
u8 *meter_level_map = private->meter_level_map;
36223796
u16 meter_levels[SCARLETT2_MAX_METERS];
36233797
int i, err;
36243798

@@ -3627,8 +3801,18 @@ static int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl,
36273801
if (err < 0)
36283802
return err;
36293803

3630-
for (i = 0; i < elem->channels; i++)
3631-
ucontrol->value.integer.value[i] = meter_levels[i];
3804+
/* copy & translate from meter_levels[] using meter_level_map[] */
3805+
for (i = 0; i < elem->channels; i++) {
3806+
int idx = meter_level_map[i];
3807+
int value;
3808+
3809+
if (idx == 255)
3810+
value = 0;
3811+
else
3812+
value = meter_levels[idx];
3813+
3814+
ucontrol->value.integer.value[i] = value;
3815+
}
36323816

36333817
return 0;
36343818
}

0 commit comments

Comments
 (0)