.. | .. |
---|
| 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++) { |
---|