diff options
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 43d6417b811e..9149a84c716f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -462,6 +462,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, | |||
462 | int index, int value) | 462 | int index, int value) |
463 | { | 463 | { |
464 | int err; | 464 | int err; |
465 | unsigned int read_only = (channel == 0) ? | ||
466 | cval->master_readonly : | ||
467 | cval->ch_readonly & (1 << (channel - 1)); | ||
468 | |||
469 | if (read_only) { | ||
470 | snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n", | ||
471 | __func__, channel, cval->control); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
465 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, | 475 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, |
466 | value); | 476 | value); |
467 | if (err < 0) | 477 | if (err < 0) |
@@ -958,7 +968,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) | |||
958 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 968 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
959 | unsigned int ctl_mask, int control, | 969 | unsigned int ctl_mask, int control, |
960 | struct usb_audio_term *iterm, int unitid, | 970 | struct usb_audio_term *iterm, int unitid, |
961 | int read_only) | 971 | int readonly_mask) |
962 | { | 972 | { |
963 | struct uac_feature_unit_descriptor *desc = raw_desc; | 973 | struct uac_feature_unit_descriptor *desc = raw_desc; |
964 | unsigned int len = 0; | 974 | unsigned int len = 0; |
@@ -989,20 +999,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
989 | cval->control = control; | 999 | cval->control = control; |
990 | cval->cmask = ctl_mask; | 1000 | cval->cmask = ctl_mask; |
991 | cval->val_type = audio_feature_info[control-1].type; | 1001 | cval->val_type = audio_feature_info[control-1].type; |
992 | if (ctl_mask == 0) | 1002 | if (ctl_mask == 0) { |
993 | cval->channels = 1; /* master channel */ | 1003 | cval->channels = 1; /* master channel */ |
994 | else { | 1004 | cval->master_readonly = readonly_mask; |
1005 | } else { | ||
995 | int i, c = 0; | 1006 | int i, c = 0; |
996 | for (i = 0; i < 16; i++) | 1007 | for (i = 0; i < 16; i++) |
997 | if (ctl_mask & (1 << i)) | 1008 | if (ctl_mask & (1 << i)) |
998 | c++; | 1009 | c++; |
999 | cval->channels = c; | 1010 | cval->channels = c; |
1011 | cval->ch_readonly = readonly_mask; | ||
1000 | } | 1012 | } |
1001 | 1013 | ||
1002 | /* get min/max values */ | 1014 | /* get min/max values */ |
1003 | get_min_max(cval, 0); | 1015 | get_min_max(cval, 0); |
1004 | 1016 | ||
1005 | if (read_only) | 1017 | /* if all channels in the mask are marked read-only, make the control |
1018 | * read-only. set_cur_mix_value() will check the mask again and won't | ||
1019 | * issue write commands to read-only channels. */ | ||
1020 | if (cval->channels == readonly_mask) | ||
1006 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); | 1021 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); |
1007 | else | 1022 | else |
1008 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1023 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
@@ -1195,9 +1210,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1195 | } | 1210 | } |
1196 | } | 1211 | } |
1197 | 1212 | ||
1198 | /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ | 1213 | /* NOTE: build_feature_ctl() will mark the control read-only if all channels |
1214 | * are marked read-only in the descriptors. Otherwise, the control will be | ||
1215 | * reported as writeable, but the driver will not actually issue a write | ||
1216 | * command for read-only channels */ | ||
1199 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1217 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ |
1200 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); | 1218 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only); |
1201 | if (uac2_control_is_readable(master_bits, i)) | 1219 | if (uac2_control_is_readable(master_bits, i)) |
1202 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, | 1220 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, |
1203 | !uac2_control_is_writeable(master_bits, i)); | 1221 | !uac2_control_is_writeable(master_bits, i)); |