[alsa-devel] sound: usb-audio: full capture/playback/spdif support for Digidesign Mbox 2

Damien Zammit damien.zammit at gmail.com
Wed Nov 24 13:59:38 CET 2010


Hi folks,

I have put together full support for Digidesign Mbox 2, but it needs
someone to help me merge it into alsa.  I haven't seen the latest
snd-usb-audio code since last year, it seems to have branched into
multiple files.

I have worked out how the Digidesign Mbox 2 needs to be configured, it
supports SPDIF i/o simultaneously with analogue but can be toggled on
and off by using different altsettings.
Also the sample clock rate must be configured via a special method.

Therefore I have provided for this in a device_setup parameter with 4 settings:
48Khz Spdif+analog = 0
44.1Khz Spdif+analog = 1
48Khz Analog only = 2
44.1Khz Analog only = 3

###### audio

        /* Digidesign Mbox 2 workaround:
         * supports S24_3BE BIG ENDIAN in an unusual way */
        if (chip->usb_id == USB_ID(0x0dba, 0x3000))
            pcm_format = SNDRV_PCM_FORMAT_S24_3BE;

static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
                                        int iface, int altno);
static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
{
 .....
.....
            /* Digidesign Mbox 2: skip altsets incompatible with device_setup
                 */
                if (chip->usb_id == USB_ID(0x0dba, 0x3000) &&
                    mbox2_skip_setting_quirk(chip, iface_no, altno))
                        continue;
.....
}


#define MBOX2_SET_48K_SPDIF            0
#define MBOX2_SET_44K_SPDIF            1
#define MBOX2_SET_48K_ANALOG           2
#define MBOX2_SET_44K_ANALOG           3

static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
                                        int iface, int altno)
{
        u8 srate[3];
        /* Reset ifaces 2-5 to 0 altsetting. */
        usb_set_interface(chip->dev, iface, 0);

    if (device_setup[chip->index] == MBOX2_SET_48K_SPDIF ||
        device_setup[chip->index] == MBOX2_SET_48K_ANALOG) {
            //setup 48k
                        srate[0]=0x80;
                        srate[1]=0xbb;
                        srate[2]=0x00;

                        /* Send the magic! */
                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x01, 0x22, 0x0100, 0x0085, &srate,
0x0003, 1000);

                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x81, 0xa2, 0x0100, 0x0085, &srate,
0x0003, 1000);

                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x81, 0xa2, 0x0100, 0x0086, &srate,
0x0003, 1000);

                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x81, 0xa2, 0x0100, 0x0003, &srate,
0x0003, 1000);
            snd_printk(KERN_INFO "Digidesign Mbox 2: 24 Bit 48000Hz");
        if (device_setup[chip->index] == MBOX2_SET_48K_SPDIF) {
            //setup spdif
            snd_printk(KERN_INFO ", SPDIF\n");
            if (altno != 2) return 1;
        } else {
            //setup analog
            snd_printk(KERN_INFO ", ANALOGUE\n");
            if (altno != 3) return 1;
        }
    } else {
            //setup 44k
                        srate[0]=0x44;
                        srate[1]=0xac;
                        srate[2]=0x00;

                        /* Send the magic! */
                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x01, 0x22, 0x0100, 0x0085, &srate,
0x0003, 1000);

                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x81, 0xa2, 0x0100, 0x0085, &srate,
0x0003, 1000);

                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x81, 0xa2, 0x0100, 0x0086, &srate,
0x0003, 1000);

                        snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
                                0x81, 0xa2, 0x0100, 0x0003, &srate,
0x0003, 1000);

            snd_printk(KERN_INFO "Digidesign Mbox 2: 24 Bit 44100Hz");
                        if (device_setup[chip->index] == MBOX2_SET_44K_SPDIF ||
                        device_setup[chip->index] == MBOX2_SET_44K_ANALOG) {

            //setup spdif
            snd_printk(KERN_INFO ", SPDIF\n");
            if (altno != 2) return 1;
        } else {
            //setup analog
            snd_printk(KERN_INFO ", ANALOGUE\n");
            if (altno != 3) return 1;
        }
    }

    return 0;
}


#define MBOX2_FIRMWARE_SIZE    646
#define MBOX2_BOOT_LOADING     0x01 /* Hard coded into the device */
#define MBOX2_BOOT_READY       0x02 /* Hard coded into the device */

static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
{
        struct usb_host_config *config = dev->actconfig;
        int err;
        u8 enablemagic[3];
        u8 bootresponse;
        int fwsize;

        if ((fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength))
== MBOX2_FIRMWARE_SIZE) {
                snd_printdd("Sending Digidesign Mbox 2 boot sequence...\n");

                        /* From USB Snoop,
                         *
                         * SetupPacket = RT RQ VHVL INDX SIZE
                         * RT = 0xRT Request Type
                         * RQ = 0xRQ Request
                         * VHVL = 0xVLVH Value in reverse byte order
                         * INDX = 0xDXIN Index in reverse byte order
                         * SIZE = 0xZESI Size in reverse byte order
                         *
                         * Magic boot code setup packet: c0 85 01 00 00 00 12 00
                         *           RQ    RT    VLVH    DXIN
       ZESI
                         * becomes 0x85, 0xc0, 0x0001, 0x0000,
&RETURNDATA, 0x0012, TIMEOUT
                         * for snd_usb_ctl_msg()
                         */

mbox2_reboot:
                snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
                        0x85, 0xc0, 0x0001, 0x0000, &bootresponse,
0x0012, 1000);

                if (bootresponse == MBOX2_BOOT_LOADING) {
                        snd_printdd("device not ready, resending boot
sequence...\n");
                        goto mbox2_reboot;
                }

                if (bootresponse == MBOX2_BOOT_READY) {
                        snd_printdd("device initialised!\n");

                        err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
                                &dev->descriptor, sizeof(dev->descriptor));
                        config = dev->actconfig;
                        if (err < 0) snd_printdd("error
usb_get_descriptor: %d\n", err);
                        err = usb_reset_configuration(dev);
                        if (err < 0) snd_printdd("error
usb_reset_configuration: %d\n", err);
                        snd_printdd("mbox2_boot: new boot length = %d\n",
                            le16_to_cpu(get_cfg_desc(config)->wTotalLength));

                        /* Successful boot, (should reset all
altsettings to 0 like windows does, but works without it)
                         * but now we will try sending
capture/playback enable magic
                         *
                         * 80 bb 00 = 24bit mode - S24_3BE
                         * 44 ac 00 = 16bit mode?
                         *
                         */

                        /* We want 48khz mode for now */
                        enablemagic[0]=0x80;
                        enablemagic[1]=0xbb;
                        enablemagic[2]=0x00;

                        /* Send the magic! */
                        snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
                                0x01, 0x22, 0x0100, 0x0085,
&enablemagic, 0x0003, 1000);

                        snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
                                0x81, 0xa2, 0x0100, 0x0085,
&enablemagic, 0x0003, 1000);

                        snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
                                0x81, 0xa2, 0x0100, 0x0086,
&enablemagic, 0x0003, 1000);

                        snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
                                0x81, 0xa2, 0x0100, 0x0003,
&enablemagic, 0x0003, 1000);

                        return 0; /* Succesful boot */
                }

                snd_printdd("unknown bootresponse, ignoring device:
%d\n",bootresponse);
                return -ENODEV;
        }
        snd_printk("Invalid firmware size: %d\n",fwsize);
        return -ENODEV;
}


#######   quirk:
{

       USB_DEVICE(0x0dba, 0x3000),
       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
               .vendor_name = "Digidesign",
               .product_name = "Mbox 2",
               .ifnum = QUIRK_ANY_INTERFACE,
               .type = QUIRK_COMPOSITE,
               .data = (const struct snd_usb_audio_quirk[]) {
                       {
                               .ifnum = 0,
                               .type = QUIRK_IGNORE_INTERFACE
                       },
                       {
                               .ifnum = 1,
                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                       },
                       {
                               .ifnum = 2,
                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                       },
                       {
                               .ifnum = 3,
                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                       },
                       {
                                .ifnum = 4,
                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                       },
                       {
                                .ifnum = 5,
                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                       },
                       {
                               .ifnum = 6,
                               .type = QUIRK_MIDI_MBOX2,
                               .data = & (const struct
snd_usb_midi_endpoint_info) {
                                       .out_ep =  0x02,
                                       .out_cables = 0x0001,
                                       .in_ep = 0x81,
                                       .in_interval = 0x01,
                                       .in_cables = 0x0001
                               }

                       },
                       {
                               .ifnum = -1
                       }
               }
       }
},

##### midi

        case QUIRK_MIDI_MBOX2:
                /* Digidesign Mbox 2 uses MIDIMAN MIDI protocol */
                umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
                /*
                 * We have to make sure that the USB core looks
                 * again at interface 6 by calling usb_set_interface() on it.
                 */
                usb_set_interface(umidi->chip->dev, 6, 0);
                memcpy(&endpoints[0], quirk->data,
                       sizeof(struct snd_usb_midi_endpoint_info));
                err = 0;
                break;


Damien


More information about the Alsa-devel mailing list