[alsa-devel] [PATCH - microII 1/1] ALSA: usb-audio: Add Audio Advantage Micro II
Takashi Iwai
tiwai at suse.de
Fri Jun 28 13:39:03 CEST 2013
At Fri, 28 Jun 2013 13:07:22 +0200,
Przemysław Rudy wrote:
>
> Sure Takashi, here you are:
>
> ------------------
> 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.
> ------------------
OK, I applied the patch with the description above.
thanks,
Takashi
>
> Best,
> Przemek
>
> On 2013-06-28 12:10, Takashi Iwai wrote:
> > At Thu, 27 Jun 2013 23:52:33 +0200,
> > Przemek Rudy wrote:
> >>
> >>
> >> Signed-off-by: Przemek Rudy <prudy1 at o2.pl>
> >
> > The changes look OK to me, but the patch description is completely
> > missing. Please give a bit more details in the patch description
> > part.
> >
> >
> > thanks,
> >
> > Takashi
> >
> >> diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
> >> index ebe9144..d42a584 100644
> >> --- a/sound/usb/mixer_quirks.c
> >> +++ b/sound/usb/mixer_quirks.c
> >> @@ -9,6 +9,8 @@
> >> * Alan Cox (alan at lxorguk.ukuu.org.uk)
> >> * Thomas Sailer (sailer at ife.ee.ethz.ch)
> >> *
> >> + * Audio Advantage Micro II support added by:
> >> + * Przemek Rudy (prudy1 at o2.pl)
> >> *
> >> * This program is free software; you can redistribute it and/or modify
> >> * it under the terms of the GNU General Public License as published by
> >> @@ -30,6 +32,7 @@
> >> #include <linux/usb.h>
> >> #include <linux/usb/audio.h>
> >>
> >> +#include <sound/asoundef.h>
> >> #include <sound/core.h>
> >> #include <sound/control.h>
> >> #include <sound/hwdep.h>
> >> @@ -1315,6 +1318,211 @@ static struct std_mono_table ebox44_table[] = {
> >> {}
> >> };
> >>
> >> +/* Audio Advantage Micro II findings:
> >> + *
> >> + * Mapping spdif AES bits to vendor register.bit:
> >> + * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00
> >> + * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01
> >> + * AES2: [0 0 0 0 0 0 0 0]
> >> + * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request
> >> + * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices
> >> + *
> >> + * power on values:
> >> + * r2: 0x10
> >> + * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set
> >> + * just after it to 0xa0, presumably it disables/mutes some analog
> >> + * parts when there is no audio.)
> >> + * r9: 0x28
> >> + *
> >> + * Optical transmitter on/off:
> >> + * vendor register.bit: 9.1
> >> + * 0 - on (0x28 register value)
> >> + * 1 - off (0x2a register value)
> >> + *
> >> + */
> >> +static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
> >> + struct snd_ctl_elem_info *uinfo)
> >> +{
> >> + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
> >> + uinfo->count = 1;
> >> + return 0;
> >> +}
> >> +
> >> +static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
> >> + struct snd_ctl_elem_value *ucontrol)
> >> +{
> >> + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
> >> + int err;
> >> + struct usb_interface *iface;
> >> + struct usb_host_interface *alts;
> >> + unsigned int ep;
> >> + unsigned char data[3];
> >> + int rate;
> >> +
> >> + ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
> >> + ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
> >> + ucontrol->value.iec958.status[2] = 0x00;
> >> +
> >> + /* use known values for that card: interface#1 altsetting#1 */
> >> + iface = usb_ifnum_to_if(mixer->chip->dev, 1);
> >> + alts = &iface->altsetting[1];
> >> + ep = get_endpoint(alts, 0)->bEndpointAddress;
> >> +
> >> + err = snd_usb_ctl_msg(mixer->chip->dev,
> >> + usb_rcvctrlpipe(mixer->chip->dev, 0),
> >> + UAC_GET_CUR,
> >> + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
> >> + UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
> >> + ep,
> >> + data,
> >> + sizeof(data));
> >> + if (err < 0)
> >> + goto end;
> >> +
> >> + rate = data[0] | (data[1] << 8) | (data[2] << 16);
> >> + ucontrol->value.iec958.status[3] = (rate == 48000) ?
> >> + IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
> >> +
> >> + err = 0;
> >> +end:
> >> + return err;
> >> +}
> >> +
> >> +static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
> >> + struct snd_ctl_elem_value *ucontrol)
> >> +{
> >> + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
> >> + int err;
> >> + u8 reg;
> >> + unsigned long priv_backup = kcontrol->private_value;
> >> +
> >> + reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
> >> + (ucontrol->value.iec958.status[0] & 0x0f);
> >> + err = snd_usb_ctl_msg(mixer->chip->dev,
> >> + usb_sndctrlpipe(mixer->chip->dev, 0),
> >> + UAC_SET_CUR,
> >> + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
> >> + reg,
> >> + 2,
> >> + NULL,
> >> + 0);
> >> + if (err < 0)
> >> + goto end;
> >> +
> >> + kcontrol->private_value &= 0xfffff0f0;
> >> + kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
> >> + kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
> >> +
> >> + reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
> >> + 0xa0 : 0x20;
> >> + reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
> >> + err = snd_usb_ctl_msg(mixer->chip->dev,
> >> + usb_sndctrlpipe(mixer->chip->dev, 0),
> >> + UAC_SET_CUR,
> >> + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
> >> + reg,
> >> + 3,
> >> + NULL,
> >> + 0);
> >> + if (err < 0)
> >> + goto end;
> >> +
> >> + kcontrol->private_value &= 0xffff0fff;
> >> + kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
> >> +
> >> + /* The frequency bits in AES3 cannot be set via register access. */
> >> +
> >> + /* Silently ignore any bits from the request that cannot be set. */
> >> +
> >> + err = (priv_backup != kcontrol->private_value);
> >> +end:
> >> + return err;
> >> +}
> >> +
> >> +static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
> >> + struct snd_ctl_elem_value *ucontrol)
> >> +{
> >> + ucontrol->value.iec958.status[0] = 0x0f;
> >> + ucontrol->value.iec958.status[1] = 0xff;
> >> + ucontrol->value.iec958.status[2] = 0x00;
> >> + ucontrol->value.iec958.status[3] = 0x00;
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
> >> + struct snd_ctl_elem_value *ucontrol)
> >> +{
> >> + ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
> >> + struct snd_ctl_elem_value *ucontrol)
> >> +{
> >> + struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
> >> + int err;
> >> + u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
> >> +
> >> + err = snd_usb_ctl_msg(mixer->chip->dev,
> >> + usb_sndctrlpipe(mixer->chip->dev, 0),
> >> + UAC_SET_CUR,
> >> + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
> >> + reg,
> >> + 9,
> >> + NULL,
> >> + 0);
> >> +
> >> + if (!err) {
> >> + err = (reg != (kcontrol->private_value & 0x0ff));
> >> + if (err)
> >> + kcontrol->private_value = reg;
> >> + }
> >> +
> >> + return err;
> >> +}
> >> +
> >> +static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
> >> + {
> >> + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
> >> + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
> >> + .info = snd_microii_spdif_info,
> >> + .get = snd_microii_spdif_default_get,
> >> + .put = snd_microii_spdif_default_put,
> >> + .private_value = 0x00000100UL,/* reset value */
> >> + },
> >> + {
> >> + .access = SNDRV_CTL_ELEM_ACCESS_READ,
> >> + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
> >> + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
> >> + .info = snd_microii_spdif_info,
> >> + .get = snd_microii_spdif_mask_get,
> >> + },
> >> + {
> >> + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
> >> + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
> >> + .info = snd_ctl_boolean_mono_info,
> >> + .get = snd_microii_spdif_switch_get,
> >> + .put = snd_microii_spdif_switch_put,
> >> + .private_value = 0x00000028UL,/* reset value */
> >> + }
> >> +};
> >> +
> >> +static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
> >> +{
> >> + int err, i;
> >> +
> >> + for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
> >> + err = snd_ctl_add(mixer->chip->card,
> >> + snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
> >> + if (err < 0)
> >> + return err;
> >> + }
> >> +
> >> + return err;
> >> +}
> >> +
> >> int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
> >> {
> >> int err = 0;
> >> @@ -1353,6 +1561,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
> >> err = snd_xonar_u1_controls_create(mixer);
> >> break;
> >>
> >> + case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */
> >> + err = snd_microii_controls_create(mixer);
> >> + break;
> >> +
> >> case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
> >> err = snd_nativeinstruments_create_mixer(mixer,
> >> snd_nativeinstruments_ta6_mixers,
> >> diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
> >> index 8b75bcf..2be7410 100644
> >> --- a/sound/usb/quirks-table.h
> >> +++ b/sound/usb/quirks-table.h
> >> @@ -3434,4 +3434,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
> >> }
> >> },
> >>
> >> +{
> >> + /*
> >> + * The original product_name is "USB Sound Device", however this name
> >> + * is also used by the CM106 based cards, so make it unique.
> >> + */
> >> + USB_DEVICE(0x0d8c, 0x0103),
> >> + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
> >> + .product_name = "Audio Advantage MicroII",
> >> + .ifnum = QUIRK_NO_INTERFACE
> >> + }
> >> +},
> >> +
> >> #undef USB_DEVICE_VENDOR_SPEC
> >> --
> >> 1.8.1.4
> >>
> > _______________________________________________
> > Alsa-devel mailing list
> > Alsa-devel at alsa-project.org
> > http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> >
>
More information about the Alsa-devel
mailing list