summaryrefslogtreecommitdiff
path: root/sound/usb/mixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r--sound/usb/mixer.c157
1 files changed, 82 insertions, 75 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 409fc1164694..11be79af26db 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -433,7 +433,7 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
{
int err;
- if (cval->cached & (1 << channel)) {
+ if (cval->cached & BIT(channel)) {
*value = cval->cache_val[index];
return 0;
}
@@ -445,7 +445,7 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
cval->control, channel, err);
return err;
}
- cval->cached |= 1 << channel;
+ cval->cached |= BIT(channel);
cval->cache_val[index] = *value;
return 0;
}
@@ -522,7 +522,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
int err;
unsigned int read_only = (channel == 0) ?
cval->master_readonly :
- cval->ch_readonly & (1 << (channel - 1));
+ cval->ch_readonly & BIT(channel - 1);
if (read_only) {
usb_audio_dbg(cval->head.mixer->chip,
@@ -536,7 +536,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
value);
if (err < 0)
return err;
- cval->cached |= 1 << channel;
+ cval->cached |= BIT(channel);
cval->cache_val[index] = value;
return 0;
}
@@ -547,7 +547,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
DECLARE_TLV_DB_MINMAX(scale, 0, 0);
if (size < sizeof(scale))
@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
cluster_id,
- snd_usb_ctrl_intf(state->chip),
+ snd_usb_ctrl_intf(state->mixer->hostif),
&c_header, sizeof(c_header));
if (err < 0)
goto error;
@@ -1084,6 +1084,21 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
struct snd_kcontrol *kctl)
{
struct snd_usb_audio *chip = cval->head.mixer->chip;
+
+ if (chip->quirk_flags & QUIRK_FLAG_MIC_RES_384) {
+ if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+ usb_audio_info(chip,
+ "set resolution quirk: cval->res = 384\n");
+ cval->res = 384;
+ }
+ } else if (chip->quirk_flags & QUIRK_FLAG_MIC_RES_16) {
+ if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
+ usb_audio_info(chip,
+ "set resolution quirk: cval->res = 16\n");
+ cval->res = 16;
+ }
+ }
+
switch (chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
@@ -1168,27 +1183,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
}
break;
- case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
- case USB_ID(0x046d, 0x0808):
- case USB_ID(0x046d, 0x0809):
- case USB_ID(0x046d, 0x0819): /* Logitech Webcam C210 */
- case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
- case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
- case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */
- case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */
- case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */
- case USB_ID(0x046d, 0x0991):
- case USB_ID(0x046d, 0x09a2): /* QuickCam Communicate Deluxe/S7500 */
- /* Most audio usb devices lie about volume resolution.
- * Most Logitech webcams have res = 384.
- * Probably there is some logitech magic behind this number --fishor
- */
- if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
- usb_audio_info(chip,
- "set resolution quirk: cval->res = 384\n");
- cval->res = 384;
- }
- break;
case USB_ID(0x0495, 0x3042): /* ESS Technology Asus USB DAC */
if ((strstr(kctl->id.name, "Playback Volume") != NULL) ||
strstr(kctl->id.name, "Capture Volume") != NULL) {
@@ -1197,20 +1191,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
cval->res = 1;
}
break;
- case USB_ID(0x1224, 0x2a25): /* Jieli Technology USB PHY 2.0 */
- if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
- usb_audio_info(chip,
- "set resolution quirk: cval->res = 16\n");
- cval->res = 16;
- }
- break;
- case USB_ID(0x1bcf, 0x2283): /* NexiGo N930AF FHD Webcam */
- if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
- usb_audio_info(chip,
- "set resolution quirk: cval->res = 16\n");
- cval->res = 16;
- }
- break;
}
}
@@ -1253,7 +1233,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
int minchn = 0;
if (cval->cmask) {
for (i = 0; i < MAX_CHANNELS; i++)
- if (cval->cmask & (1 << i)) {
+ if (cval->cmask & BIT(i)) {
minchn = i + 1;
break;
}
@@ -1358,7 +1338,7 @@ no_res_check:
} else {
idx = 0;
for (i = 0; i < MAX_CHANNELS; i++) {
- if (cval->cmask & (1 << i)) {
+ if (cval->cmask & BIT(i)) {
init_cur_mix_raw(cval, i + 1, idx);
idx++;
}
@@ -1370,11 +1350,24 @@ no_res_check:
#define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL)
+/* get the max value advertised via control API */
+static int get_max_exposed(struct usb_mixer_elem_info *cval)
+{
+ if (!cval->max_exposed) {
+ if (cval->res)
+ cval->max_exposed =
+ DIV_ROUND_UP(cval->max - cval->min, cval->res);
+ else
+ cval->max_exposed = cval->max - cval->min;
+ }
+ return cval->max_exposed;
+}
+
/* get a feature/mixer unit info */
static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
if (cval->val_type == USB_MIXER_BOOLEAN ||
cval->val_type == USB_MIXER_INV_BOOLEAN)
@@ -1382,11 +1375,8 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
else
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = cval->channels;
- if (cval->val_type == USB_MIXER_BOOLEAN ||
- cval->val_type == USB_MIXER_INV_BOOLEAN) {
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- } else {
+ if (cval->val_type != USB_MIXER_BOOLEAN &&
+ cval->val_type != USB_MIXER_INV_BOOLEAN) {
if (!cval->initialized) {
get_min_max_with_quirks(cval, 0, kcontrol);
if (cval->initialized && cval->dBmin >= cval->dBmax) {
@@ -1398,10 +1388,10 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
&kcontrol->id);
}
}
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max =
- DIV_ROUND_UP(cval->max - cval->min, cval->res);
}
+
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = get_max_exposed(cval);
return 0;
}
@@ -1409,14 +1399,14 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int c, cnt, val, err;
ucontrol->value.integer.value[0] = cval->min;
if (cval->cmask) {
cnt = 0;
for (c = 0; c < MAX_CHANNELS; c++) {
- if (!(cval->cmask & (1 << c)))
+ if (!(cval->cmask & BIT(c)))
continue;
err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val);
if (err < 0)
@@ -1441,19 +1431,22 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
+ int max_val = get_max_exposed(cval);
int c, cnt, val, oval, err;
int changed = 0;
if (cval->cmask) {
cnt = 0;
for (c = 0; c < MAX_CHANNELS; c++) {
- if (!(cval->cmask & (1 << c)))
+ if (!(cval->cmask & BIT(c)))
continue;
err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval);
if (err < 0)
return filter_error(cval, err);
val = ucontrol->value.integer.value[cnt];
+ if (val < 0 || val > max_val)
+ return -EINVAL;
val = get_abs_value(cval, val);
if (oval != val) {
snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
@@ -1467,6 +1460,8 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
if (err < 0)
return filter_error(cval, err);
val = ucontrol->value.integer.value[0];
+ if (val < 0 || val > max_val)
+ return -EINVAL;
val = get_abs_value(cval, val);
if (val != oval) {
snd_usb_set_cur_mix_value(cval, 0, 0, val);
@@ -1480,7 +1475,7 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int val, err;
err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
@@ -1548,7 +1543,7 @@ error:
static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int ret, val;
ret = get_connector_value(cval, kcontrol->id.name, &val);
@@ -1700,7 +1695,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer,
} else {
int i, c = 0;
for (i = 0; i < 16; i++)
- if (ctl_mask & (1 << i))
+ if (ctl_mask & BIT(i))
c++;
cval->channels = c;
cval->ch_readonly = readonly_mask;
@@ -2014,6 +2009,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
bmaControls = ftr->bmaControls;
}
+ if (channels > 32) {
+ usb_audio_info(state->chip,
+ "usbmixer: too many channels (%d) in unit %d\n",
+ channels, unitid);
+ return -EINVAL;
+ }
+
/* parse the source unit */
err = parse_audio_unit(state, hdr->bSourceID);
if (err < 0)
@@ -2053,8 +2055,8 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
mask = snd_usb_combine_bytes(bmaControls +
csize * (j+1), csize);
- if (mask & (1 << i))
- ch_bits |= (1 << j);
+ if (mask & BIT(i))
+ ch_bits |= BIT(j);
}
/* audio class v1 controls are never read-only */
@@ -2065,7 +2067,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
if (ch_bits & 1)
build_feature_ctl(state, _ftr, ch_bits, control,
&iterm, unitid, 0);
- if (master_bits & (1 << i))
+ if (master_bits & BIT(i))
build_feature_ctl(state, _ftr, 0, control,
&iterm, unitid, 0);
}
@@ -2081,9 +2083,9 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
mask = snd_usb_combine_bytes(bmaControls +
csize * (j+1), csize);
if (uac_v2v3_control_is_readable(mask, control)) {
- ch_bits |= (1 << j);
+ ch_bits |= BIT(j);
if (!uac_v2v3_control_is_writeable(mask, control))
- ch_read_only |= (1 << j);
+ ch_read_only |= BIT(j);
}
}
@@ -2174,7 +2176,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
__u8 *c = uac_mixer_unit_bmControls(desc, state->mixer->protocol);
if (check_matrix_bitmap(c, in_ch, i, num_outs)) {
- cval->cmask |= (1 << i);
+ cval->cmask |= BIT(i);
cval->channels++;
}
}
@@ -2195,7 +2197,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
len = get_term_name(state->chip, iterm, kctl->id.name,
sizeof(kctl->id.name), 0);
if (!len)
- len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
+ snprintf(kctl->id.name, sizeof(kctl->id.name), "Mixer Source %d", in_ch + 1);
+
append_ctl_name(kctl, " Volume");
usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
@@ -2299,7 +2302,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int err, val;
err = get_cur_ctl_value(cval, cval->control << 8, &val);
@@ -2316,13 +2319,15 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol,
static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int val, oval, err;
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
if (err < 0)
return filter_error(cval, err);
val = ucontrol->value.integer.value[0];
+ if (val < 0 || val > get_max_exposed(cval))
+ return -EINVAL;
val = get_abs_value(cval, val);
if (val != oval) {
set_cur_ctl_value(cval, cval->control << 8, val);
@@ -2497,7 +2502,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
if (state->mixer->protocol == UAC_VERSION_1) {
if (!(controls[valinfo->control / 8] &
- (1 << ((valinfo->control % 8) - 1))))
+ BIT((valinfo->control % 8) - 1)))
continue;
} else { /* UAC_VERSION_2/3 */
if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8],
@@ -2649,7 +2654,7 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
const char **itemlist = (const char **)kcontrol->private_value;
if (snd_BUG_ON(!itemlist))
@@ -2661,7 +2666,7 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol,
static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int val, err;
err = get_cur_ctl_value(cval, cval->control << 8, &val);
@@ -2678,13 +2683,15 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol,
static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval = kcontrol->private_data;
+ struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol);
int val, oval, err;
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
if (err < 0)
return filter_error(cval, err);
val = ucontrol->value.enumerated.item[0];
+ if (val < 0 || val >= cval->max) /* here cval->max = # elements */
+ return -EINVAL;
val = get_abs_value(cval, val);
if (val != oval) {
set_cur_ctl_value(cval, cval->control << 8, val);
@@ -3441,7 +3448,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
case UAC2_CS_CUR:
/* invalidate cache, so the value is read from the device */
if (channel)
- info->cached &= ~(1 << channel);
+ info->cached &= ~BIT(channel);
else /* master channel */
info->cached = 0;
@@ -3677,9 +3684,9 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list)
if (cval->cmask) {
idx = 0;
for (c = 0; c < MAX_CHANNELS; c++) {
- if (!(cval->cmask & (1 << c)))
+ if (!(cval->cmask & BIT(c)))
continue;
- if (cval->cached & (1 << (c + 1))) {
+ if (cval->cached & BIT(c + 1)) {
err = snd_usb_set_cur_mix_value(cval, c + 1, idx,
cval->cache_val[idx]);
if (err < 0)