Commit bc18e31c authored by Julian Scheel's avatar Julian Scheel Committed by Takashi Iwai

ALSA: usb-audio: Fix parameter block size for UAC2 control requests

USB Audio Class version 2.0 supports three different parameter block sizes for
CUR requests, which are 1 byte (5.2.3.1 Layout 1 Parameter Block), 2 bytes
(5.2.3.2 Layout 2 Parameter Block) and 4 bytes (5.2.3.3 Layout 3 Parameter
Block). Use the correct size according to the specific control as it was
already done for UACv1. The allocated block size for control requests is
increased to support the 4 byte worst case.
Signed-off-by: default avatarJulian Scheel <julian@jusst.de>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 41450b1b
...@@ -282,6 +282,21 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val) ...@@ -282,6 +282,21 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
return val; return val;
} }
static int uac2_ctl_value_size(int val_type)
{
switch (val_type) {
case USB_MIXER_S32:
case USB_MIXER_U32:
return 4;
case USB_MIXER_S16:
case USB_MIXER_U16:
return 2;
default:
return 1;
}
return 0; /* unreachable */
}
/* /*
* retrieve a mixer value * retrieve a mixer value
...@@ -328,14 +343,14 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, ...@@ -328,14 +343,14 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
int validx, int *value_ret) int validx, int *value_ret)
{ {
struct snd_usb_audio *chip = cval->head.mixer->chip; struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */ unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */
unsigned char *val; unsigned char *val;
int idx = 0, ret, size; int idx = 0, ret, size;
__u8 bRequest; __u8 bRequest;
if (request == UAC_GET_CUR) { if (request == UAC_GET_CUR) {
bRequest = UAC2_CS_CUR; bRequest = UAC2_CS_CUR;
size = sizeof(__u16); size = uac2_ctl_value_size(cval->val_type);
} else { } else {
bRequest = UAC2_CS_RANGE; bRequest = UAC2_CS_RANGE;
size = sizeof(buf); size = sizeof(buf);
...@@ -446,7 +461,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, ...@@ -446,7 +461,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set) int request, int validx, int value_set)
{ {
struct snd_usb_audio *chip = cval->head.mixer->chip; struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2]; unsigned char buf[4];
int idx = 0, val_len, err, timeout = 10; int idx = 0, val_len, err, timeout = 10;
validx += cval->idx_off; validx += cval->idx_off;
...@@ -454,8 +469,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, ...@@ -454,8 +469,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
if (cval->head.mixer->protocol == UAC_VERSION_1) { if (cval->head.mixer->protocol == UAC_VERSION_1) {
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
} else { /* UAC_VERSION_2 */ } else { /* UAC_VERSION_2 */
/* audio class v2 controls are always 2 bytes in size */ val_len = uac2_ctl_value_size(cval->val_type);
val_len = sizeof(__u16);
/* FIXME */ /* FIXME */
if (request != UAC_SET_CUR) { if (request != UAC_SET_CUR) {
...@@ -469,6 +483,8 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, ...@@ -469,6 +483,8 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
value_set = convert_bytes_value(cval, value_set); value_set = convert_bytes_value(cval, value_set);
buf[0] = value_set & 0xff; buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff; buf[1] = (value_set >> 8) & 0xff;
buf[2] = (value_set >> 16) & 0xff;
buf[3] = (value_set >> 24) & 0xff;
err = snd_usb_autoresume(chip); err = snd_usb_autoresume(chip);
if (err < 0) if (err < 0)
return -EIO; return -EIO;
...@@ -798,24 +814,25 @@ static int check_input_term(struct mixer_build *state, int id, ...@@ -798,24 +814,25 @@ static int check_input_term(struct mixer_build *state, int id,
/* feature unit control information */ /* feature unit control information */
struct usb_feature_control_info { struct usb_feature_control_info {
const char *name; const char *name;
unsigned int type; /* control type (mute, volume, etc.) */ int type; /* data type for uac1 */
int type_uac2; /* data type for uac2 if different from uac1, else -1 */
}; };
static struct usb_feature_control_info audio_feature_info[] = { static struct usb_feature_control_info audio_feature_info[] = {
{ "Mute", USB_MIXER_INV_BOOLEAN }, { "Mute", USB_MIXER_INV_BOOLEAN, -1 },
{ "Volume", USB_MIXER_S16 }, { "Volume", USB_MIXER_S16, -1 },
{ "Tone Control - Bass", USB_MIXER_S8 }, { "Tone Control - Bass", USB_MIXER_S8, -1 },
{ "Tone Control - Mid", USB_MIXER_S8 }, { "Tone Control - Mid", USB_MIXER_S8, -1 },
{ "Tone Control - Treble", USB_MIXER_S8 }, { "Tone Control - Treble", USB_MIXER_S8, -1 },
{ "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ { "Graphic Equalizer", USB_MIXER_S8, -1 }, /* FIXME: not implemeted yet */
{ "Auto Gain Control", USB_MIXER_BOOLEAN }, { "Auto Gain Control", USB_MIXER_BOOLEAN, -1 },
{ "Delay Control", USB_MIXER_U16 }, /* FIXME: U32 in UAC2 */ { "Delay Control", USB_MIXER_U16, USB_MIXER_U32 },
{ "Bass Boost", USB_MIXER_BOOLEAN }, { "Bass Boost", USB_MIXER_BOOLEAN, -1 },
{ "Loudness", USB_MIXER_BOOLEAN }, { "Loudness", USB_MIXER_BOOLEAN, -1 },
/* UAC2 specific */ /* UAC2 specific */
{ "Input Gain Control", USB_MIXER_S16 }, { "Input Gain Control", USB_MIXER_S16, -1 },
{ "Input Gain Pad Control", USB_MIXER_S16 }, { "Input Gain Pad Control", USB_MIXER_S16, -1 },
{ "Phase Inverter Control", USB_MIXER_BOOLEAN }, { "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 },
}; };
/* private_free callback */ /* private_free callback */
...@@ -1215,6 +1232,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, ...@@ -1215,6 +1232,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
int readonly_mask) int readonly_mask)
{ {
struct uac_feature_unit_descriptor *desc = raw_desc; struct uac_feature_unit_descriptor *desc = raw_desc;
struct usb_feature_control_info *ctl_info;
unsigned int len = 0; unsigned int len = 0;
int mapped_name = 0; int mapped_name = 0;
int nameid = uac_feature_unit_iFeature(desc); int nameid = uac_feature_unit_iFeature(desc);
...@@ -1240,7 +1258,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, ...@@ -1240,7 +1258,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = control; cval->control = control;
cval->cmask = ctl_mask; cval->cmask = ctl_mask;
cval->val_type = audio_feature_info[control-1].type; ctl_info = &audio_feature_info[control-1];
if (state->mixer->protocol == UAC_VERSION_1)
cval->val_type = ctl_info->type;
else /* UAC_VERSION_2 */
cval->val_type = ctl_info->type_uac2 >= 0 ?
ctl_info->type_uac2 : ctl_info->type;
if (ctl_mask == 0) { if (ctl_mask == 0) {
cval->channels = 1; /* master channel */ cval->channels = 1; /* master channel */
cval->master_readonly = readonly_mask; cval->master_readonly = readonly_mask;
......
...@@ -33,6 +33,8 @@ enum { ...@@ -33,6 +33,8 @@ enum {
USB_MIXER_U8, USB_MIXER_U8,
USB_MIXER_S16, USB_MIXER_S16,
USB_MIXER_U16, USB_MIXER_U16,
USB_MIXER_S32,
USB_MIXER_U32,
}; };
typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer, typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment