aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-05-31 07:35:37 -0400
committerTakashi Iwai <tiwai@suse.de>2010-05-31 12:15:57 -0400
commita6a3325913efbe35a10e87fd3e9c3ce621fd32c7 (patch)
tree4b3300083115516ff8fff200da4d4300dea3b853
parentdcbe7bcfa32c5bc4f9bb6c75d4d41bb4db8c36fc (diff)
ALSA: usb-audio: support partially write-protected UAC2 controls
So far, UAC2 controls are marked read-only if any of the channels are marked read-only in the descriptors. Change this behaviour and - mark them writeable unless all channels are read-only - store the read-only mask in usb_mixer_elem_info and - check the mask again in set_cur_mix_value(), and bail out for write-protected channels. Signed-off-by: Daniel Mack <daniel@caiaq.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/mixer.c30
-rw-r--r--sound/usb/mixer.h2
2 files changed, 26 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)
958static void build_feature_ctl(struct mixer_build *state, void *raw_desc, 968static 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));
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 130123854a6c..a7cf1007fbb0 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -34,6 +34,8 @@ struct usb_mixer_elem_info {
34 unsigned int id; 34 unsigned int id;
35 unsigned int control; /* CS or ICN (high byte) */ 35 unsigned int control; /* CS or ICN (high byte) */
36 unsigned int cmask; /* channel mask bitmap: 0 = master */ 36 unsigned int cmask; /* channel mask bitmap: 0 = master */
37 unsigned int ch_readonly;
38 unsigned int master_readonly;
37 int channels; 39 int channels;
38 int val_type; 40 int val_type;
39 int min, max, res; 41 int min, max, res;