diff options
author | Andrew Chant <achant@google.com> | 2018-03-22 17:39:55 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2018-03-23 05:25:03 -0400 |
commit | 21e9b3e931f78497b19b1f8f3d59d19412c1a28f (patch) | |
tree | ceafcd8610b694895129a9d52da56672229ac791 | |
parent | 9a2fe9b801f585baccf8352d82839dcd54b300cf (diff) |
ALSA: usb-audio: fix uac control query argument
This patch fixes code readability and should have no functional change.
Correct uac control query functions to account for the 1-based indexing
of USB Audio Class control identifiers.
The function parameter, u8 control, should be the
constant defined in audio-v2.h to identify the control to be checked for
readability or writeability.
This patch fixes all callers that had adjusted, and makes explicit
the mapping between audio_feature_info[] array index and the associated
control identifier.
Signed-off-by: Andrew Chant <achant@google.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | include/linux/usb/audio-v2.h | 4 | ||||
-rw-r--r-- | sound/usb/clock.c | 5 | ||||
-rw-r--r-- | sound/usb/mixer.c | 69 |
3 files changed, 48 insertions, 30 deletions
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 2db83a191e78..aaafecf073ff 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h | |||
@@ -36,12 +36,12 @@ | |||
36 | 36 | ||
37 | static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control) | 37 | static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control) |
38 | { | 38 | { |
39 | return (bmControls >> (control * 2)) & 0x1; | 39 | return (bmControls >> ((control - 1) * 2)) & 0x1; |
40 | } | 40 | } |
41 | 41 | ||
42 | static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control) | 42 | static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control) |
43 | { | 43 | { |
44 | return (bmControls >> (control * 2)) & 0x2; | 44 | return (bmControls >> ((control - 1) * 2)) & 0x2; |
45 | } | 45 | } |
46 | 46 | ||
47 | /* 4.7.2 Class-Specific AC Interface Descriptor */ | 47 | /* 4.7.2 Class-Specific AC Interface Descriptor */ |
diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 25de7fe285d9..ab39ccb974c6 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c | |||
@@ -214,7 +214,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, | |||
214 | 214 | ||
215 | /* If a clock source can't tell us whether it's valid, we assume it is */ | 215 | /* If a clock source can't tell us whether it's valid, we assume it is */ |
216 | if (!uac_v2v3_control_is_readable(bmControls, | 216 | if (!uac_v2v3_control_is_readable(bmControls, |
217 | UAC2_CS_CONTROL_CLOCK_VALID - 1)) | 217 | UAC2_CS_CONTROL_CLOCK_VALID)) |
218 | return 1; | 218 | return 1; |
219 | 219 | ||
220 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | 220 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, |
@@ -552,7 +552,8 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, | |||
552 | bmControls = cs_desc->bmControls; | 552 | bmControls = cs_desc->bmControls; |
553 | } | 553 | } |
554 | 554 | ||
555 | writeable = uac_v2v3_control_is_writeable(bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1); | 555 | writeable = uac_v2v3_control_is_writeable(bmControls, |
556 | UAC2_CS_CONTROL_SAM_FREQ); | ||
556 | if (writeable) { | 557 | if (writeable) { |
557 | data = cpu_to_le32(rate); | 558 | data = cpu_to_le32(rate); |
558 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | 559 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 1c02f7373eda..3075ac50a391 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -879,26 +879,27 @@ static int check_input_term(struct mixer_build *state, int id, | |||
879 | 879 | ||
880 | /* feature unit control information */ | 880 | /* feature unit control information */ |
881 | struct usb_feature_control_info { | 881 | struct usb_feature_control_info { |
882 | int control; | ||
882 | const char *name; | 883 | const char *name; |
883 | int type; /* data type for uac1 */ | 884 | int type; /* data type for uac1 */ |
884 | int type_uac2; /* data type for uac2 if different from uac1, else -1 */ | 885 | int type_uac2; /* data type for uac2 if different from uac1, else -1 */ |
885 | }; | 886 | }; |
886 | 887 | ||
887 | static struct usb_feature_control_info audio_feature_info[] = { | 888 | static struct usb_feature_control_info audio_feature_info[] = { |
888 | { "Mute", USB_MIXER_INV_BOOLEAN, -1 }, | 889 | { UAC_FU_MUTE, "Mute", USB_MIXER_INV_BOOLEAN, -1 }, |
889 | { "Volume", USB_MIXER_S16, -1 }, | 890 | { UAC_FU_VOLUME, "Volume", USB_MIXER_S16, -1 }, |
890 | { "Tone Control - Bass", USB_MIXER_S8, -1 }, | 891 | { UAC_FU_BASS, "Tone Control - Bass", USB_MIXER_S8, -1 }, |
891 | { "Tone Control - Mid", USB_MIXER_S8, -1 }, | 892 | { UAC_FU_MID, "Tone Control - Mid", USB_MIXER_S8, -1 }, |
892 | { "Tone Control - Treble", USB_MIXER_S8, -1 }, | 893 | { UAC_FU_TREBLE, "Tone Control - Treble", USB_MIXER_S8, -1 }, |
893 | { "Graphic Equalizer", USB_MIXER_S8, -1 }, /* FIXME: not implemeted yet */ | 894 | { UAC_FU_GRAPHIC_EQUALIZER, "Graphic Equalizer", USB_MIXER_S8, -1 }, /* FIXME: not implemented yet */ |
894 | { "Auto Gain Control", USB_MIXER_BOOLEAN, -1 }, | 895 | { UAC_FU_AUTOMATIC_GAIN, "Auto Gain Control", USB_MIXER_BOOLEAN, -1 }, |
895 | { "Delay Control", USB_MIXER_U16, USB_MIXER_U32 }, | 896 | { UAC_FU_DELAY, "Delay Control", USB_MIXER_U16, USB_MIXER_U32 }, |
896 | { "Bass Boost", USB_MIXER_BOOLEAN, -1 }, | 897 | { UAC_FU_BASS_BOOST, "Bass Boost", USB_MIXER_BOOLEAN, -1 }, |
897 | { "Loudness", USB_MIXER_BOOLEAN, -1 }, | 898 | { UAC_FU_LOUDNESS, "Loudness", USB_MIXER_BOOLEAN, -1 }, |
898 | /* UAC2 specific */ | 899 | /* UAC2 specific */ |
899 | { "Input Gain Control", USB_MIXER_S16, -1 }, | 900 | { UAC2_FU_INPUT_GAIN, "Input Gain Control", USB_MIXER_S16, -1 }, |
900 | { "Input Gain Pad Control", USB_MIXER_S16, -1 }, | 901 | { UAC2_FU_INPUT_GAIN_PAD, "Input Gain Pad Control", USB_MIXER_S16, -1 }, |
901 | { "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, | 902 | { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, |
902 | }; | 903 | }; |
903 | 904 | ||
904 | /* private_free callback */ | 905 | /* private_free callback */ |
@@ -1293,6 +1294,17 @@ static void check_no_speaker_on_headset(struct snd_kcontrol *kctl, | |||
1293 | strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name)); | 1294 | strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name)); |
1294 | } | 1295 | } |
1295 | 1296 | ||
1297 | static struct usb_feature_control_info *get_feature_control_info(int control) | ||
1298 | { | ||
1299 | int i; | ||
1300 | |||
1301 | for (i = 0; i < ARRAY_SIZE(audio_feature_info); ++i) { | ||
1302 | if (audio_feature_info[i].control == control) | ||
1303 | return &audio_feature_info[i]; | ||
1304 | } | ||
1305 | return NULL; | ||
1306 | } | ||
1307 | |||
1296 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 1308 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
1297 | unsigned int ctl_mask, int control, | 1309 | unsigned int ctl_mask, int control, |
1298 | struct usb_audio_term *iterm, int unitid, | 1310 | struct usb_audio_term *iterm, int unitid, |
@@ -1308,8 +1320,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1308 | const struct usbmix_name_map *map; | 1320 | const struct usbmix_name_map *map; |
1309 | unsigned int range; | 1321 | unsigned int range; |
1310 | 1322 | ||
1311 | control++; /* change from zero-based to 1-based value */ | ||
1312 | |||
1313 | if (control == UAC_FU_GRAPHIC_EQUALIZER) { | 1323 | if (control == UAC_FU_GRAPHIC_EQUALIZER) { |
1314 | /* FIXME: not supported yet */ | 1324 | /* FIXME: not supported yet */ |
1315 | return; | 1325 | return; |
@@ -1325,7 +1335,10 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1325 | snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); | 1335 | snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); |
1326 | cval->control = control; | 1336 | cval->control = control; |
1327 | cval->cmask = ctl_mask; | 1337 | cval->cmask = ctl_mask; |
1328 | ctl_info = &audio_feature_info[control-1]; | 1338 | |
1339 | ctl_info = get_feature_control_info(control); | ||
1340 | if (!ctl_info) | ||
1341 | return; | ||
1329 | if (state->mixer->protocol == UAC_VERSION_1) | 1342 | if (state->mixer->protocol == UAC_VERSION_1) |
1330 | cval->val_type = ctl_info->type; | 1343 | cval->val_type = ctl_info->type; |
1331 | else /* UAC_VERSION_2 */ | 1344 | else /* UAC_VERSION_2 */ |
@@ -1475,7 +1488,7 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, | |||
1475 | * clock source validity. If that isn't readable, just bail out. | 1488 | * clock source validity. If that isn't readable, just bail out. |
1476 | */ | 1489 | */ |
1477 | if (!uac_v2v3_control_is_readable(hdr->bmControls, | 1490 | if (!uac_v2v3_control_is_readable(hdr->bmControls, |
1478 | ilog2(UAC2_CS_CONTROL_CLOCK_VALID))) | 1491 | UAC2_CS_CONTROL_CLOCK_VALID)) |
1479 | return 0; | 1492 | return 0; |
1480 | 1493 | ||
1481 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1494 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -1491,7 +1504,7 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, | |||
1491 | cval->control = UAC2_CS_CONTROL_CLOCK_VALID; | 1504 | cval->control = UAC2_CS_CONTROL_CLOCK_VALID; |
1492 | 1505 | ||
1493 | if (uac_v2v3_control_is_writeable(hdr->bmControls, | 1506 | if (uac_v2v3_control_is_writeable(hdr->bmControls, |
1494 | ilog2(UAC2_CS_CONTROL_CLOCK_VALID))) | 1507 | UAC2_CS_CONTROL_CLOCK_VALID)) |
1495 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1508 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
1496 | else { | 1509 | else { |
1497 | cval->master_readonly = 1; | 1510 | cval->master_readonly = 1; |
@@ -1625,6 +1638,8 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1625 | /* check all control types */ | 1638 | /* check all control types */ |
1626 | for (i = 0; i < 10; i++) { | 1639 | for (i = 0; i < 10; i++) { |
1627 | unsigned int ch_bits = 0; | 1640 | unsigned int ch_bits = 0; |
1641 | int control = audio_feature_info[i].control; | ||
1642 | |||
1628 | for (j = 0; j < channels; j++) { | 1643 | for (j = 0; j < channels; j++) { |
1629 | unsigned int mask; | 1644 | unsigned int mask; |
1630 | 1645 | ||
@@ -1640,25 +1655,26 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1640 | * (for ease of programming). | 1655 | * (for ease of programming). |
1641 | */ | 1656 | */ |
1642 | if (ch_bits & 1) | 1657 | if (ch_bits & 1) |
1643 | build_feature_ctl(state, _ftr, ch_bits, i, | 1658 | build_feature_ctl(state, _ftr, ch_bits, control, |
1644 | &iterm, unitid, 0); | 1659 | &iterm, unitid, 0); |
1645 | if (master_bits & (1 << i)) | 1660 | if (master_bits & (1 << i)) |
1646 | build_feature_ctl(state, _ftr, 0, i, &iterm, | 1661 | build_feature_ctl(state, _ftr, 0, control, |
1647 | unitid, 0); | 1662 | &iterm, unitid, 0); |
1648 | } | 1663 | } |
1649 | } else { /* UAC_VERSION_2/3 */ | 1664 | } else { /* UAC_VERSION_2/3 */ |
1650 | for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) { | 1665 | for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) { |
1651 | unsigned int ch_bits = 0; | 1666 | unsigned int ch_bits = 0; |
1652 | unsigned int ch_read_only = 0; | 1667 | unsigned int ch_read_only = 0; |
1668 | int control = audio_feature_info[i].control; | ||
1653 | 1669 | ||
1654 | for (j = 0; j < channels; j++) { | 1670 | for (j = 0; j < channels; j++) { |
1655 | unsigned int mask; | 1671 | unsigned int mask; |
1656 | 1672 | ||
1657 | mask = snd_usb_combine_bytes(bmaControls + | 1673 | mask = snd_usb_combine_bytes(bmaControls + |
1658 | csize * (j+1), csize); | 1674 | csize * (j+1), csize); |
1659 | if (uac_v2v3_control_is_readable(mask, i)) { | 1675 | if (uac_v2v3_control_is_readable(mask, control)) { |
1660 | ch_bits |= (1 << j); | 1676 | ch_bits |= (1 << j); |
1661 | if (!uac_v2v3_control_is_writeable(mask, i)) | 1677 | if (!uac_v2v3_control_is_writeable(mask, control)) |
1662 | ch_read_only |= (1 << j); | 1678 | ch_read_only |= (1 << j); |
1663 | } | 1679 | } |
1664 | } | 1680 | } |
@@ -1677,11 +1693,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1677 | * (for ease of programming). | 1693 | * (for ease of programming). |
1678 | */ | 1694 | */ |
1679 | if (ch_bits & 1) | 1695 | if (ch_bits & 1) |
1680 | build_feature_ctl(state, _ftr, ch_bits, i, | 1696 | build_feature_ctl(state, _ftr, ch_bits, control, |
1681 | &iterm, unitid, ch_read_only); | 1697 | &iterm, unitid, ch_read_only); |
1682 | if (uac_v2v3_control_is_readable(master_bits, i)) | 1698 | if (uac_v2v3_control_is_readable(master_bits, control)) |
1683 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, | 1699 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, |
1684 | !uac_v2v3_control_is_writeable(master_bits, i)); | 1700 | !uac_v2v3_control_is_writeable(master_bits, |
1701 | control)); | ||
1685 | } | 1702 | } |
1686 | } | 1703 | } |
1687 | 1704 | ||