forked from Minki/linux
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:
parent
dcbe7bcfa3
commit
a6a3325913
@ -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));
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user