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