Support for Digidesign Mbox 2 USB sound card: This patch is the result of a lot of trial and error, since there are no specs available for the device. Full duplex support is provided, i.e. playback and recording in stereo. The format is hardcoded at 48000Hz @ 24 bit, which is the maximum that the device supports. Also, MIDI in and MIDI out both work. Users will notice that the S/PDIF light also flashes when playback or recording is active. I believe this means that S/PDIF input/output is simultaneously activated with the analogue i/o during use. But this particular functionality remains untested. Note that this particular version of the patch is so far untested on the physical hardware because I have not compiled a full kernel with the changes. However, extensive testing has been done by many users of the hardware who believe other versions of my patch have worked since circa 2009. Signed-off-by: Damien Zammit --- diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 34b9bb7..45532dd 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2181,6 +2181,11 @@ int snd_usbmidi_create(struct snd_card *card, umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; + case QUIRK_MIDI_MBOX2: + /* Digidesign Mbox 2 uses MIDIMAN MIDI protocol */ + umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops; + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; case QUIRK_MIDI_RAW_BYTES: umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; /* diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 49f9af9..c60eea2 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3078,6 +3078,93 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* DIGIDESIGN MBOX 2 */ +{ + 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_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 2, + .altsetting = 2, + .altset_idx = 1, + .attributes = 0x00, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_SYNC_ASYNC, + .maxpacksize = 0x128, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 3, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 4, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 4, + .altsetting = 2, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x85, + .ep_attr = USB_ENDPOINT_SYNC_SYNC, + .maxpacksize = 0x128, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 5, + .type = QUIRK_IGNORE_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 + } + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 0f58b4b..3510f87 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -306,6 +306,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_MBOX2] = create_any_midi_quirk, [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, [QUIRK_MIDI_CME] = create_any_midi_quirk, @@ -655,6 +656,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */ return snd_usb_cm6206_boot_quirk(dev); + case USB_ID(0x0dba, 0x3000): + /* Digidesign Mbox 2 */ + return snd_usb_mbox2_boot_quirk(dev); + case USB_ID(0x133e, 0x0815): /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); @@ -761,6 +766,112 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } } +/* Digidesign Mbox 2 needs to load firmware onboard + * and driver must wait a few seconds for initialisation. + */ + +#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 */ + +int snd_usb_mbox2_boot_quirk(struct usb_device *dev) +{ + struct usb_host_config *config = dev->actconfig; + int err; + u8 enablemagic[3]; + u8 bootresponse; + u8 temp[12]; + int fwsize; + int count; + + fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength); + + if (fwsize == MBOX2_FIRMWARE_SIZE) { + snd_printk("Sending Digidesign Mbox 2 boot sequence...\n"); + + count = 0; + bootresponse = MBOX2_BOOT_LOADING; + while ((bootresponse == MBOX2_BOOT_LOADING) && (count < 10)) { + mdelay(500); /* 0.5 second delay */ + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012); + if (bootresponse == MBOX2_BOOT_READY) + break; + + snd_printk("device not ready, resending boot sequence...\n"); + count++; + } + + if (bootresponse == MBOX2_BOOT_READY) { + snd_printk("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)); + + /* We want 48 kHz mode for now */ + enablemagic[0] = 0x80; + enablemagic[1] = 0xbb; + enablemagic[2] = 0x00; + + /* Send the magic! */ + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0085, &enablemagic, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0086, &enablemagic, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0003, &enablemagic, 0x0003); + snd_printk(KERN_INFO "Digidesign Mbox 2: 24 Bit 48kHz Analogue"); + + return 0; /* Successful boot */ + } + + snd_printk("Unknown bootresponse, or timed out, ignoring device: %d\n", bootresponse); + return -ENODEV; + } + snd_printk("Invalid firmware size: %d\n", fwsize); + return -ENODEV; +} + +int mbox2_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno) +{ + u8 srate[3]; + u8 temp[12]; + + /* Reset ifaces 2,4 to 0 altsetting like the Windows driver does */ + usb_set_interface(chip->dev, iface, 0); + + /* Choose 48000Hz permanently */ + srate[0] = 0x80; + srate[1] = 0xbb; + srate[2] = 0x00; + + /* Send the magic! */ + snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), + 0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003); + snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + 0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003); + snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + 0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003); + snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + 0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003); + + if (altno != 3) + return 1; + + return 0; +} + void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) { /* diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 0ca9e91..087a5b6 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -24,6 +24,11 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp); +int mbox2_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno); + +int snd_usb_mbox2_boot_quirk(struct usb_device *dev); + void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 1ac3fd9..a8172c1 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -76,6 +76,7 @@ enum quirk_type { QUIRK_MIDI_YAMAHA, QUIRK_MIDI_MIDIMAN, QUIRK_MIDI_NOVATION, + QUIRK_MIDI_MBOX2, QUIRK_MIDI_RAW_BYTES, QUIRK_MIDI_EMAGIC, QUIRK_MIDI_CME,