diff options
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 157 |
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) |