| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * (Tentative) USB Audio Driver for ALSA |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * Many codes borrowed from audio.c by |
|---|
| 9 | 10 | * Alan Cox (alan@lxorguk.ukuu.org.uk) |
|---|
| 10 | 11 | * Thomas Sailer (sailer@ife.ee.ethz.ch) |
|---|
| 11 | | - * |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 14 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 15 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 16 | | - * (at your option) any later version. |
|---|
| 17 | | - * |
|---|
| 18 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 19 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 20 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 21 | | - * GNU General Public License for more details. |
|---|
| 22 | | - * |
|---|
| 23 | | - * You should have received a copy of the GNU General Public License |
|---|
| 24 | | - * along with this program; if not, write to the Free Software |
|---|
| 25 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 26 | | - * |
|---|
| 27 | 12 | */ |
|---|
| 28 | 13 | |
|---|
| 29 | 14 | /* |
|---|
| .. | .. |
|---|
| 307 | 292 | * retrieve a mixer value |
|---|
| 308 | 293 | */ |
|---|
| 309 | 294 | |
|---|
| 295 | +static inline int mixer_ctrl_intf(struct usb_mixer_interface *mixer) |
|---|
| 296 | +{ |
|---|
| 297 | + return get_iface_desc(mixer->hostif)->bInterfaceNumber; |
|---|
| 298 | +} |
|---|
| 299 | + |
|---|
| 310 | 300 | static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, |
|---|
| 311 | 301 | int validx, int *value_ret) |
|---|
| 312 | 302 | { |
|---|
| .. | .. |
|---|
| 321 | 311 | return -EIO; |
|---|
| 322 | 312 | |
|---|
| 323 | 313 | while (timeout-- > 0) { |
|---|
| 324 | | - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); |
|---|
| 314 | + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); |
|---|
| 325 | 315 | err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, |
|---|
| 326 | 316 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
|---|
| 327 | 317 | validx, idx, buf, val_len); |
|---|
| .. | .. |
|---|
| 369 | 359 | if (ret) |
|---|
| 370 | 360 | goto error; |
|---|
| 371 | 361 | |
|---|
| 372 | | - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); |
|---|
| 362 | + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); |
|---|
| 373 | 363 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, |
|---|
| 374 | 364 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
|---|
| 375 | 365 | validx, idx, buf, size); |
|---|
| .. | .. |
|---|
| 494 | 484 | return -EIO; |
|---|
| 495 | 485 | |
|---|
| 496 | 486 | while (timeout-- > 0) { |
|---|
| 497 | | - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); |
|---|
| 487 | + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); |
|---|
| 498 | 488 | err = snd_usb_ctl_msg(chip->dev, |
|---|
| 499 | 489 | usb_sndctrlpipe(chip->dev, 0), request, |
|---|
| 500 | 490 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, |
|---|
| .. | .. |
|---|
| 918 | 908 | struct usb_audio_term *term, |
|---|
| 919 | 909 | void *p1, int id) |
|---|
| 920 | 910 | { |
|---|
| 911 | + struct uac2_effect_unit_descriptor *d = p1; |
|---|
| 912 | + int err; |
|---|
| 913 | + |
|---|
| 914 | + err = __check_input_term(state, d->bSourceID, term); |
|---|
| 915 | + if (err < 0) |
|---|
| 916 | + return err; |
|---|
| 921 | 917 | term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ |
|---|
| 922 | 918 | term->id = id; |
|---|
| 923 | 919 | return 0; |
|---|
| .. | .. |
|---|
| 1228 | 1224 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
|---|
| 1229 | 1225 | usb_audio_err(cval->head.mixer->chip, |
|---|
| 1230 | 1226 | "%d:%d: cannot get min/max values for control %d (id %d)\n", |
|---|
| 1231 | | - cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip), |
|---|
| 1227 | + cval->head.id, mixer_ctrl_intf(cval->head.mixer), |
|---|
| 1232 | 1228 | cval->control, cval->head.id); |
|---|
| 1233 | 1229 | return -EINVAL; |
|---|
| 1234 | 1230 | } |
|---|
| .. | .. |
|---|
| 1304 | 1300 | if (cval->dBmin > cval->dBmax) { |
|---|
| 1305 | 1301 | /* totally crap, return an error */ |
|---|
| 1306 | 1302 | return -EINVAL; |
|---|
| 1303 | + } |
|---|
| 1304 | + } else { |
|---|
| 1305 | + /* if the max volume is too low, it's likely a bogus range; |
|---|
| 1306 | + * here we use -96dB as the threshold |
|---|
| 1307 | + */ |
|---|
| 1308 | + if (cval->dBmax <= -9600) { |
|---|
| 1309 | + usb_audio_info(cval->head.mixer->chip, |
|---|
| 1310 | + "%d:%d: bogus dB values (%d/%d), disabling dB reporting\n", |
|---|
| 1311 | + cval->head.id, mixer_ctrl_intf(cval->head.mixer), |
|---|
| 1312 | + cval->dBmin, cval->dBmax); |
|---|
| 1313 | + cval->dBmin = cval->dBmax = 0; |
|---|
| 1307 | 1314 | } |
|---|
| 1308 | 1315 | } |
|---|
| 1309 | 1316 | |
|---|
| .. | .. |
|---|
| 1447 | 1454 | if (ret) |
|---|
| 1448 | 1455 | goto error; |
|---|
| 1449 | 1456 | |
|---|
| 1450 | | - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); |
|---|
| 1457 | + idx = mixer_ctrl_intf(cval->head.mixer) | (cval->head.id << 8); |
|---|
| 1451 | 1458 | if (cval->head.mixer->protocol == UAC_VERSION_2) { |
|---|
| 1452 | 1459 | struct uac2_connectors_ctl_blk uac2_conn; |
|---|
| 1453 | 1460 | |
|---|
| .. | .. |
|---|
| 1467 | 1474 | snd_usb_unlock_shutdown(chip); |
|---|
| 1468 | 1475 | |
|---|
| 1469 | 1476 | if (ret < 0) { |
|---|
| 1477 | + if (strstr(kcontrol->id.name, "Speaker")) { |
|---|
| 1478 | + ucontrol->value.integer.value[0] = 1; |
|---|
| 1479 | + return 0; |
|---|
| 1480 | + } |
|---|
| 1470 | 1481 | error: |
|---|
| 1471 | 1482 | usb_audio_err(chip, |
|---|
| 1472 | 1483 | "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
|---|
| .. | .. |
|---|
| 1478 | 1489 | return 0; |
|---|
| 1479 | 1490 | } |
|---|
| 1480 | 1491 | |
|---|
| 1481 | | -static struct snd_kcontrol_new usb_feature_unit_ctl = { |
|---|
| 1492 | +static const struct snd_kcontrol_new usb_feature_unit_ctl = { |
|---|
| 1482 | 1493 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
|---|
| 1483 | 1494 | .name = "", /* will be filled later manually */ |
|---|
| 1484 | 1495 | .info = mixer_ctl_feature_info, |
|---|
| .. | .. |
|---|
| 1499 | 1510 | * A control which shows the boolean value from reading a UAC control on |
|---|
| 1500 | 1511 | * the master channel. |
|---|
| 1501 | 1512 | */ |
|---|
| 1502 | | -static struct snd_kcontrol_new usb_bool_master_control_ctl_ro = { |
|---|
| 1513 | +static const struct snd_kcontrol_new usb_bool_master_control_ctl_ro = { |
|---|
| 1503 | 1514 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
|---|
| 1504 | 1515 | .name = "", /* will be filled later manually */ |
|---|
| 1505 | 1516 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
|---|
| .. | .. |
|---|
| 1521 | 1532 | * This symbol is exported in order to allow the mixer quirks to |
|---|
| 1522 | 1533 | * hook up to the standard feature unit control mechanism |
|---|
| 1523 | 1534 | */ |
|---|
| 1524 | | -struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl; |
|---|
| 1535 | +const struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl; |
|---|
| 1525 | 1536 | |
|---|
| 1526 | 1537 | /* |
|---|
| 1527 | 1538 | * build a feature control |
|---|
| .. | .. |
|---|
| 1899 | 1910 | { |
|---|
| 1900 | 1911 | int channels, i, j; |
|---|
| 1901 | 1912 | struct usb_audio_term iterm; |
|---|
| 1902 | | - unsigned int master_bits, first_ch_bits; |
|---|
| 1913 | + unsigned int master_bits; |
|---|
| 1903 | 1914 | int err, csize; |
|---|
| 1904 | 1915 | struct uac_feature_unit_descriptor *hdr = _ftr; |
|---|
| 1905 | 1916 | __u8 *bmaControls; |
|---|
| .. | .. |
|---|
| 1948 | 1959 | break; |
|---|
| 1949 | 1960 | |
|---|
| 1950 | 1961 | } |
|---|
| 1951 | | - if (channels > 0) |
|---|
| 1952 | | - first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); |
|---|
| 1953 | | - else |
|---|
| 1954 | | - first_ch_bits = 0; |
|---|
| 1955 | 1962 | |
|---|
| 1956 | 1963 | if (state->mixer->protocol == UAC_VERSION_1) { |
|---|
| 1957 | 1964 | /* check all control types */ |
|---|
| .. | .. |
|---|
| 2375 | 2382 | int num_ins; |
|---|
| 2376 | 2383 | struct usb_mixer_elem_info *cval; |
|---|
| 2377 | 2384 | struct snd_kcontrol *kctl; |
|---|
| 2378 | | - int i, err, nameid, type, len; |
|---|
| 2385 | + int i, err, nameid, type, len, val; |
|---|
| 2379 | 2386 | const struct procunit_info *info; |
|---|
| 2380 | 2387 | const struct procunit_value_info *valinfo; |
|---|
| 2381 | 2388 | const struct usbmix_name_map *map; |
|---|
| .. | .. |
|---|
| 2476 | 2483 | default: |
|---|
| 2477 | 2484 | get_min_max(cval, valinfo->min_value); |
|---|
| 2478 | 2485 | break; |
|---|
| 2486 | + } |
|---|
| 2487 | + |
|---|
| 2488 | + err = get_cur_ctl_value(cval, cval->control << 8, &val); |
|---|
| 2489 | + if (err < 0) { |
|---|
| 2490 | + usb_mixer_elem_info_free(cval); |
|---|
| 2491 | + return -EINVAL; |
|---|
| 2479 | 2492 | } |
|---|
| 2480 | 2493 | |
|---|
| 2481 | 2494 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); |
|---|
| .. | .. |
|---|
| 3261 | 3274 | { |
|---|
| 3262 | 3275 | struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); |
|---|
| 3263 | 3276 | static const char * const val_types[] = { |
|---|
| 3264 | | - "BOOLEAN", "INV_BOOLEAN", "S8", "U8", "S16", "U16", "S32", "U32", |
|---|
| 3277 | + [USB_MIXER_BOOLEAN] = "BOOLEAN", |
|---|
| 3278 | + [USB_MIXER_INV_BOOLEAN] = "INV_BOOLEAN", |
|---|
| 3279 | + [USB_MIXER_S8] = "S8", |
|---|
| 3280 | + [USB_MIXER_U8] = "U8", |
|---|
| 3281 | + [USB_MIXER_S16] = "S16", |
|---|
| 3282 | + [USB_MIXER_U16] = "U16", |
|---|
| 3283 | + [USB_MIXER_S32] = "S32", |
|---|
| 3284 | + [USB_MIXER_U32] = "U32", |
|---|
| 3285 | + [USB_MIXER_BESPOKEN] = "BESPOKEN", |
|---|
| 3265 | 3286 | }; |
|---|
| 3266 | 3287 | snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " |
|---|
| 3267 | 3288 | "channels=%i, type=\"%s\"\n", cval->head.id, |
|---|
| .. | .. |
|---|
| 3282 | 3303 | list_for_each_entry(mixer, &chip->mixer_list, list) { |
|---|
| 3283 | 3304 | snd_iprintf(buffer, |
|---|
| 3284 | 3305 | "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n", |
|---|
| 3285 | | - chip->usb_id, snd_usb_ctrl_intf(chip), |
|---|
| 3306 | + chip->usb_id, mixer_ctrl_intf(mixer), |
|---|
| 3286 | 3307 | mixer->ignore_ctl_error); |
|---|
| 3287 | 3308 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); |
|---|
| 3288 | 3309 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { |
|---|
| .. | .. |
|---|
| 3498 | 3519 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, |
|---|
| 3499 | 3520 | int ignore_error) |
|---|
| 3500 | 3521 | { |
|---|
| 3501 | | - static struct snd_device_ops dev_ops = { |
|---|
| 3522 | + static const struct snd_device_ops dev_ops = { |
|---|
| 3502 | 3523 | .dev_free = snd_usb_mixer_dev_free |
|---|
| 3503 | 3524 | }; |
|---|
| 3504 | 3525 | struct usb_mixer_interface *mixer; |
|---|
| 3505 | | - struct snd_info_entry *entry; |
|---|
| 3506 | 3526 | int err; |
|---|
| 3507 | 3527 | |
|---|
| 3508 | 3528 | strcpy(chip->card->mixername, "USB Mixer"); |
|---|
| .. | .. |
|---|
| 3560 | 3580 | if (err < 0) |
|---|
| 3561 | 3581 | goto _error; |
|---|
| 3562 | 3582 | |
|---|
| 3563 | | - if (list_empty(&chip->mixer_list) && |
|---|
| 3564 | | - !snd_card_proc_new(chip->card, "usbmixer", &entry)) |
|---|
| 3565 | | - snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read); |
|---|
| 3583 | + if (list_empty(&chip->mixer_list)) |
|---|
| 3584 | + snd_card_ro_proc_new(chip->card, "usbmixer", chip, |
|---|
| 3585 | + snd_usb_mixer_proc_read); |
|---|
| 3566 | 3586 | |
|---|
| 3567 | 3587 | list_add(&mixer->list, &chip->mixer_list); |
|---|
| 3568 | 3588 | return 0; |
|---|
| .. | .. |
|---|
| 3580 | 3600 | usb_kill_urb(mixer->urb); |
|---|
| 3581 | 3601 | if (mixer->rc_urb) |
|---|
| 3582 | 3602 | usb_kill_urb(mixer->rc_urb); |
|---|
| 3603 | + if (mixer->private_free) |
|---|
| 3604 | + mixer->private_free(mixer); |
|---|
| 3583 | 3605 | mixer->disconnected = true; |
|---|
| 3584 | 3606 | } |
|---|
| 3585 | 3607 | |
|---|
| .. | .. |
|---|
| 3607 | 3629 | int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) |
|---|
| 3608 | 3630 | { |
|---|
| 3609 | 3631 | snd_usb_mixer_inactivate(mixer); |
|---|
| 3632 | + if (mixer->private_suspend) |
|---|
| 3633 | + mixer->private_suspend(mixer); |
|---|
| 3610 | 3634 | return 0; |
|---|
| 3611 | 3635 | } |
|---|
| 3612 | 3636 | |
|---|
| .. | .. |
|---|
| 3615 | 3639 | struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); |
|---|
| 3616 | 3640 | int c, err, idx; |
|---|
| 3617 | 3641 | |
|---|
| 3642 | + if (cval->val_type == USB_MIXER_BESPOKEN) |
|---|
| 3643 | + return 0; |
|---|
| 3644 | + |
|---|
| 3618 | 3645 | if (cval->cmask) { |
|---|
| 3619 | 3646 | idx = 0; |
|---|
| 3620 | 3647 | for (c = 0; c < MAX_CHANNELS; c++) { |
|---|