Commit 066624c6a1733a72a67f1d06d35a2153e7d9082b
Committed by
Takashi Iwai
1 parent
accaf69da1
Exists in
master
and in
20 other branches
ALSA: usb-audio: Add Audio Advantage Micro II
This patch is adding extensive support (beside standard usb audio class) for Audio Advantage Micro II usb sound card. Features included: - Access to AES bits (so now sending the IEC61937 compliant stream is possible). - Mixer SPDIF control added to turn on/off the optical transmitter. Signed-off-by: Przemek Rudy <prudy1@o2.pl> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 2 changed files with 224 additions and 0 deletions Side-by-side Diff
sound/usb/mixer_quirks.c
... | ... | @@ -9,6 +9,8 @@ |
9 | 9 | * Alan Cox (alan@lxorguk.ukuu.org.uk) |
10 | 10 | * Thomas Sailer (sailer@ife.ee.ethz.ch) |
11 | 11 | * |
12 | + * Audio Advantage Micro II support added by: | |
13 | + * Przemek Rudy (prudy1@o2.pl) | |
12 | 14 | * |
13 | 15 | * This program is free software; you can redistribute it and/or modify |
14 | 16 | * it under the terms of the GNU General Public License as published by |
... | ... | @@ -30,6 +32,7 @@ |
30 | 32 | #include <linux/usb.h> |
31 | 33 | #include <linux/usb/audio.h> |
32 | 34 | |
35 | +#include <sound/asoundef.h> | |
33 | 36 | #include <sound/core.h> |
34 | 37 | #include <sound/control.h> |
35 | 38 | #include <sound/hwdep.h> |
... | ... | @@ -1315,6 +1318,211 @@ |
1315 | 1318 | {} |
1316 | 1319 | }; |
1317 | 1320 | |
1321 | +/* Audio Advantage Micro II findings: | |
1322 | + * | |
1323 | + * Mapping spdif AES bits to vendor register.bit: | |
1324 | + * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00 | |
1325 | + * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01 | |
1326 | + * AES2: [0 0 0 0 0 0 0 0] | |
1327 | + * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request | |
1328 | + * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices | |
1329 | + * | |
1330 | + * power on values: | |
1331 | + * r2: 0x10 | |
1332 | + * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set | |
1333 | + * just after it to 0xa0, presumably it disables/mutes some analog | |
1334 | + * parts when there is no audio.) | |
1335 | + * r9: 0x28 | |
1336 | + * | |
1337 | + * Optical transmitter on/off: | |
1338 | + * vendor register.bit: 9.1 | |
1339 | + * 0 - on (0x28 register value) | |
1340 | + * 1 - off (0x2a register value) | |
1341 | + * | |
1342 | + */ | |
1343 | +static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, | |
1344 | + struct snd_ctl_elem_info *uinfo) | |
1345 | +{ | |
1346 | + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
1347 | + uinfo->count = 1; | |
1348 | + return 0; | |
1349 | +} | |
1350 | + | |
1351 | +static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, | |
1352 | + struct snd_ctl_elem_value *ucontrol) | |
1353 | +{ | |
1354 | + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | |
1355 | + int err; | |
1356 | + struct usb_interface *iface; | |
1357 | + struct usb_host_interface *alts; | |
1358 | + unsigned int ep; | |
1359 | + unsigned char data[3]; | |
1360 | + int rate; | |
1361 | + | |
1362 | + ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; | |
1363 | + ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; | |
1364 | + ucontrol->value.iec958.status[2] = 0x00; | |
1365 | + | |
1366 | + /* use known values for that card: interface#1 altsetting#1 */ | |
1367 | + iface = usb_ifnum_to_if(mixer->chip->dev, 1); | |
1368 | + alts = &iface->altsetting[1]; | |
1369 | + ep = get_endpoint(alts, 0)->bEndpointAddress; | |
1370 | + | |
1371 | + err = snd_usb_ctl_msg(mixer->chip->dev, | |
1372 | + usb_rcvctrlpipe(mixer->chip->dev, 0), | |
1373 | + UAC_GET_CUR, | |
1374 | + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, | |
1375 | + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, | |
1376 | + ep, | |
1377 | + data, | |
1378 | + sizeof(data)); | |
1379 | + if (err < 0) | |
1380 | + goto end; | |
1381 | + | |
1382 | + rate = data[0] | (data[1] << 8) | (data[2] << 16); | |
1383 | + ucontrol->value.iec958.status[3] = (rate == 48000) ? | |
1384 | + IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; | |
1385 | + | |
1386 | + err = 0; | |
1387 | +end: | |
1388 | + return err; | |
1389 | +} | |
1390 | + | |
1391 | +static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, | |
1392 | + struct snd_ctl_elem_value *ucontrol) | |
1393 | +{ | |
1394 | + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | |
1395 | + int err; | |
1396 | + u8 reg; | |
1397 | + unsigned long priv_backup = kcontrol->private_value; | |
1398 | + | |
1399 | + reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) | | |
1400 | + (ucontrol->value.iec958.status[0] & 0x0f); | |
1401 | + err = snd_usb_ctl_msg(mixer->chip->dev, | |
1402 | + usb_sndctrlpipe(mixer->chip->dev, 0), | |
1403 | + UAC_SET_CUR, | |
1404 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | |
1405 | + reg, | |
1406 | + 2, | |
1407 | + NULL, | |
1408 | + 0); | |
1409 | + if (err < 0) | |
1410 | + goto end; | |
1411 | + | |
1412 | + kcontrol->private_value &= 0xfffff0f0; | |
1413 | + kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; | |
1414 | + kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f); | |
1415 | + | |
1416 | + reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ? | |
1417 | + 0xa0 : 0x20; | |
1418 | + reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f; | |
1419 | + err = snd_usb_ctl_msg(mixer->chip->dev, | |
1420 | + usb_sndctrlpipe(mixer->chip->dev, 0), | |
1421 | + UAC_SET_CUR, | |
1422 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | |
1423 | + reg, | |
1424 | + 3, | |
1425 | + NULL, | |
1426 | + 0); | |
1427 | + if (err < 0) | |
1428 | + goto end; | |
1429 | + | |
1430 | + kcontrol->private_value &= 0xffff0fff; | |
1431 | + kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; | |
1432 | + | |
1433 | + /* The frequency bits in AES3 cannot be set via register access. */ | |
1434 | + | |
1435 | + /* Silently ignore any bits from the request that cannot be set. */ | |
1436 | + | |
1437 | + err = (priv_backup != kcontrol->private_value); | |
1438 | +end: | |
1439 | + return err; | |
1440 | +} | |
1441 | + | |
1442 | +static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, | |
1443 | + struct snd_ctl_elem_value *ucontrol) | |
1444 | +{ | |
1445 | + ucontrol->value.iec958.status[0] = 0x0f; | |
1446 | + ucontrol->value.iec958.status[1] = 0xff; | |
1447 | + ucontrol->value.iec958.status[2] = 0x00; | |
1448 | + ucontrol->value.iec958.status[3] = 0x00; | |
1449 | + | |
1450 | + return 0; | |
1451 | +} | |
1452 | + | |
1453 | +static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, | |
1454 | + struct snd_ctl_elem_value *ucontrol) | |
1455 | +{ | |
1456 | + ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); | |
1457 | + | |
1458 | + return 0; | |
1459 | +} | |
1460 | + | |
1461 | +static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, | |
1462 | + struct snd_ctl_elem_value *ucontrol) | |
1463 | +{ | |
1464 | + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | |
1465 | + int err; | |
1466 | + u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; | |
1467 | + | |
1468 | + err = snd_usb_ctl_msg(mixer->chip->dev, | |
1469 | + usb_sndctrlpipe(mixer->chip->dev, 0), | |
1470 | + UAC_SET_CUR, | |
1471 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | |
1472 | + reg, | |
1473 | + 9, | |
1474 | + NULL, | |
1475 | + 0); | |
1476 | + | |
1477 | + if (!err) { | |
1478 | + err = (reg != (kcontrol->private_value & 0x0ff)); | |
1479 | + if (err) | |
1480 | + kcontrol->private_value = reg; | |
1481 | + } | |
1482 | + | |
1483 | + return err; | |
1484 | +} | |
1485 | + | |
1486 | +static struct snd_kcontrol_new snd_microii_mixer_spdif[] = { | |
1487 | + { | |
1488 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
1489 | + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | |
1490 | + .info = snd_microii_spdif_info, | |
1491 | + .get = snd_microii_spdif_default_get, | |
1492 | + .put = snd_microii_spdif_default_put, | |
1493 | + .private_value = 0x00000100UL,/* reset value */ | |
1494 | + }, | |
1495 | + { | |
1496 | + .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
1497 | + .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
1498 | + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), | |
1499 | + .info = snd_microii_spdif_info, | |
1500 | + .get = snd_microii_spdif_mask_get, | |
1501 | + }, | |
1502 | + { | |
1503 | + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
1504 | + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), | |
1505 | + .info = snd_ctl_boolean_mono_info, | |
1506 | + .get = snd_microii_spdif_switch_get, | |
1507 | + .put = snd_microii_spdif_switch_put, | |
1508 | + .private_value = 0x00000028UL,/* reset value */ | |
1509 | + } | |
1510 | +}; | |
1511 | + | |
1512 | +static int snd_microii_controls_create(struct usb_mixer_interface *mixer) | |
1513 | +{ | |
1514 | + int err, i; | |
1515 | + | |
1516 | + for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { | |
1517 | + err = snd_ctl_add(mixer->chip->card, | |
1518 | + snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer)); | |
1519 | + if (err < 0) | |
1520 | + return err; | |
1521 | + } | |
1522 | + | |
1523 | + return err; | |
1524 | +} | |
1525 | + | |
1318 | 1526 | int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) |
1319 | 1527 | { |
1320 | 1528 | int err = 0; |
... | ... | @@ -1351,6 +1559,10 @@ |
1351 | 1559 | case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ |
1352 | 1560 | case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ |
1353 | 1561 | err = snd_xonar_u1_controls_create(mixer); |
1562 | + break; | |
1563 | + | |
1564 | + case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */ | |
1565 | + err = snd_microii_controls_create(mixer); | |
1354 | 1566 | break; |
1355 | 1567 | |
1356 | 1568 | case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ |
sound/usb/quirks-table.h
... | ... | @@ -3119,5 +3119,17 @@ |
3119 | 3119 | } |
3120 | 3120 | }, |
3121 | 3121 | |
3122 | +{ | |
3123 | + /* | |
3124 | + * The original product_name is "USB Sound Device", however this name | |
3125 | + * is also used by the CM106 based cards, so make it unique. | |
3126 | + */ | |
3127 | + USB_DEVICE(0x0d8c, 0x0103), | |
3128 | + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | |
3129 | + .product_name = "Audio Advantage MicroII", | |
3130 | + .ifnum = QUIRK_NO_INTERFACE | |
3131 | + } | |
3132 | +}, | |
3133 | + | |
3122 | 3134 | #undef USB_DEVICE_VENDOR_SPEC |