diff options
| author | Daniel Mack <daniel@caiaq.de> | 2010-05-31 13:35:37 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2010-05-31 18:15:57 +0200 | 
| commit | a6a3325913efbe35a10e87fd3e9c3ce621fd32c7 (patch) | |
| tree | 4b3300083115516ff8fff200da4d4300dea3b853 | |
| parent | dcbe7bcfa32c5bc4f9bb6c75d4d41bb4db8c36fc (diff) | |
| download | olio-linux-3.10-a6a3325913efbe35a10e87fd3e9c3ce621fd32c7.tar.xz olio-linux-3.10-a6a3325913efbe35a10e87fd3e9c3ce621fd32c7.zip  | |
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.c | 30 | ||||
| -rw-r--r-- | sound/usb/mixer.h | 2 | 
2 files changed, 26 insertions, 6 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 43d6417b811..9149a84c716 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,  			     int index, int value)  {  	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,  			    value);  	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,  			      unsigned int ctl_mask, int control,  			      struct usb_audio_term *iterm, int unitid, -			      int read_only) +			      int readonly_mask)  {  	struct uac_feature_unit_descriptor *desc = raw_desc;  	unsigned int len = 0; @@ -989,20 +999,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,  	cval->control = control;  	cval->cmask = ctl_mask;  	cval->val_type = audio_feature_info[control-1].type; -	if (ctl_mask == 0) +	if (ctl_mask == 0) {  		cval->channels = 1;	/* master channel */ -	else { +		cval->master_readonly = readonly_mask; +	} else {  		int i, c = 0;  		for (i = 0; i < 16; i++)  			if (ctl_mask & (1 << i))  				c++;  		cval->channels = c; +		cval->ch_readonly = readonly_mask;  	}  	/* get min/max values */  	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);  	else  		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) */ -				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))  				build_feature_ctl(state, _ftr, 0, i, &iterm, unitid,  						  !uac2_control_is_writeable(master_bits, i)); diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 130123854a6..a7cf1007fbb 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -34,6 +34,8 @@ struct usb_mixer_elem_info {  	unsigned int id;  	unsigned int control;	/* CS or ICN (high byte) */  	unsigned int cmask; /* channel mask bitmap: 0 = master */ +	unsigned int ch_readonly; +	unsigned int master_readonly;  	int channels;  	int val_type;  	int min, max, res;  |