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>
This commit is contained in:
Daniel Mack 2010-05-31 13:35:37 +02:00 committed by Takashi Iwai
parent dcbe7bcfa3
commit a6a3325913
2 changed files with 26 additions and 6 deletions

View file

@ -462,6 +462,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
int index, int value) int index, int value)
{ {
int err; int err;
unsigned int read_only = (channel == 0) ?
cval->master_readonly :
cval->ch_readonly & (1 << (channel - 1));
if (read_only) {
snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n",
__func__, channel, cval->control);
return 0;
}
err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,
value); value);
if (err < 0) if (err < 0)
@ -958,7 +968,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
static void build_feature_ctl(struct mixer_build *state, void *raw_desc, static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
unsigned int ctl_mask, int control, unsigned int ctl_mask, int control,
struct usb_audio_term *iterm, int unitid, struct usb_audio_term *iterm, int unitid,
int read_only) int readonly_mask)
{ {
struct uac_feature_unit_descriptor *desc = raw_desc; struct uac_feature_unit_descriptor *desc = raw_desc;
unsigned int len = 0; unsigned int len = 0;
@ -989,20 +999,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
cval->control = control; cval->control = control;
cval->cmask = ctl_mask; cval->cmask = ctl_mask;
cval->val_type = audio_feature_info[control-1].type; cval->val_type = audio_feature_info[control-1].type;
if (ctl_mask == 0) if (ctl_mask == 0) {
cval->channels = 1; /* master channel */ cval->channels = 1; /* master channel */
else { cval->master_readonly = readonly_mask;
} else {
int i, c = 0; int i, c = 0;
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
if (ctl_mask & (1 << i)) if (ctl_mask & (1 << i))
c++; c++;
cval->channels = c; cval->channels = c;
cval->ch_readonly = readonly_mask;
} }
/* get min/max values */ /* get min/max values */
get_min_max(cval, 0); get_min_max(cval, 0);
if (read_only) /* if all channels in the mask are marked read-only, make the control
* read-only. set_cur_mix_value() will check the mask again and won't
* issue write commands to read-only channels. */
if (cval->channels == readonly_mask)
kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval);
else else
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); 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
} }
} }
/* FIXME: the whole unit is read-only if any of the channels is marked read-only */ /* NOTE: build_feature_ctl() will mark the control read-only if all channels
* are marked read-only in the descriptors. Otherwise, the control will be
* reported as writeable, but the driver will not actually issue a write
* command for read-only channels */
if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only);
if (uac2_control_is_readable(master_bits, i)) if (uac2_control_is_readable(master_bits, i))
build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, build_feature_ctl(state, _ftr, 0, i, &iterm, unitid,
!uac2_control_is_writeable(master_bits, i)); !uac2_control_is_writeable(master_bits, i));

View file

@ -34,6 +34,8 @@ struct usb_mixer_elem_info {
unsigned int id; unsigned int id;
unsigned int control; /* CS or ICN (high byte) */ unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */ unsigned int cmask; /* channel mask bitmap: 0 = master */
unsigned int ch_readonly;
unsigned int master_readonly;
int channels; int channels;
int val_type; int val_type;
int min, max, res; int min, max, res;