Provides magic boot sequence which activates the device, must loop until device is ready, (returns status bytes). Provides extra magic to set the device into 24 bit mode.
-Playback works @ 24-bit -MIDI I/O works -Capture is untested, but PCM stream is active -S/PDIF (RCA) I/O is untested, but lights activate on the device
S/PDIF mode works by setting the required flag in usbaudio.c. I think the device can't do both simultaneously, since different altsettings are required to set it.
Remaining issues: 1) Double check endianess of 24 bit capture. 2) Check duplex stability 3) Tell ALSA to correctly detect S24_3BE on the device. Currently, speaker-test assumes S16_LE and won't allow S24_3BE mode, but jackd 0.116-2 detects and plays S24_3BE ? 4) Create a kernel module switch to select spdif/analogue I/O
Playback sample format : S24_3BE MIDI format : MIDIMAN protocol
Signed-off-by: Damien Zammit damien.zammit@gmail.com
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 43d7d88..3060941 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -943,7 +943,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream { struct snd_usb_substream *subs; snd_pcm_uframes_t hwptr_done; - + subs = (struct snd_usb_substream *)substream->runtime->private_data; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; @@ -2441,6 +2441,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor fp->altsetting, sample_width, sample_bytes); break; } + + /* Digidesign Mbox 2 workaround: + * supports S24_3BE BIG ENDIAN */ + if (chip->usb_id == USB_ID(0x0dba, 0x3000)) + pcm_format = SNDRV_PCM_FORMAT_S24_3BE; + break; case USB_AUDIO_FORMAT_PCM8: pcm_format = SNDRV_PCM_FORMAT_U8; @@ -2550,13 +2556,20 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat * switch (chip->usb_id) {
case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ - if (device_setup[chip->index] == 0x00 && + if (device_setup[chip->index] == 0x00 && fp->altsetting == 6) pcm_format = SNDRV_PCM_FORMAT_S16_BE; else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; - default: + + /* Digidesign Mbox 2 supports SPDIF 24 bit (havent tested endianess) */ + case USB_ID(0x0dba, 0x3000): + pcm_format = SNDRV_PCM_FORMAT_S24_3BE; + break; + + default: + snd_printdd("Format III detected, setting default S16_LE\n"); pcm_format = SNDRV_PCM_FORMAT_S16_LE; } } else { @@ -2655,6 +2668,8 @@ static unsigned char parse_datainterval(struct snd_usb_audio *chip,
static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, int iface, int altno); +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) { struct usb_device *dev; @@ -2700,13 +2715,19 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; altno = altsd->bAlternateSetting; - + /* audiophile usb: skip altsets incompatible with device_setup */ - if (chip->usb_id == USB_ID(0x0763, 0x2003) && + if (chip->usb_id == USB_ID(0x0763, 0x2003) && audiophile_skip_setting_quirk(chip, iface_no, altno)) continue;
+ /* 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; + /* get audio formats */ fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL); if (!fmt) { @@ -2995,7 +3016,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip, }
/* - * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface. + * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface. * The only way to detect the sample rate is by looking at wMaxPacketSize. */ static int create_uaxx_quirk(struct snd_usb_audio *chip, @@ -3264,6 +3285,97 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac 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? + * + */ + //enablemagic[0]=0x44; + //enablemagic[1]=0xac; + //enablemagic[2]=0x00; + + /* We want 24 bit 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_printdd("Invalid firmware size: %d\n",fwsize); + return -ENODEV; +} + static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) { u8 buf = 1; @@ -3366,10 +3478,79 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5) return 1; /* skip this altsetting */ - } + } return 0; /* keep this altsetting */ }
+/* Digidesign Mbox 2 I/O selector + * Uncomment this line to enable SPDIF */ +//#define MBOX2_SPDIF_IO + +#define MBOX2_FIRMWARE_INTERFACE 0 +#define MBOX2_CONTROL_INTERFACE 1 +#define MBOX2_MIDI_INTERFACE 6 + +static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno) +{ + /* Reset ifaces 2-5 to 0 altsetting. */ + usb_set_interface(chip->dev, iface, 0); + +#ifdef MBOX2_SPDIF_IO + /* Enable SPDIF altsettings */ + switch (iface) { + case MBOX2_FIRMWARE_INTERFACE: + case MBOX2_CONTROL_INTERFACE: + return 0; /*keep*/ + break; + case 2: + if (altno == 2) return 0; else return 1; + break; + case 3: + return 1; + break; + case 4: + if (altno == 2) return 0; else return 1; + break; + case 5: + return 1; + break; + case MBOX2_MIDI_INTERFACE: + return 0; /*keep*/ + break; + default: + snd_printdd("Invalid interface for Mbox 2: %d\n",iface); + return 1; /* skip altsetting */ + } +#else + /* Use analogue I/O */ + switch (iface) { + case MBOX2_FIRMWARE_INTERFACE: + case MBOX2_CONTROL_INTERFACE: + return 0; + break; + case 2: + if (altno == 3) return 0; else return 1; + break; + case 3: + if (altno == 6) return 0; else return 1; + break; + case 4: + if (altno == 3) return 0; else return 1; + break; + case 5: + if (altno == 3) return 0; else return 1; + break; + case MBOX2_MIDI_INTERFACE: + return 0; + break; + default: + snd_printdd("Invalid interface for Mbox 2: %d\n",iface); + return 1; /* skip altsetting */ + } +#endif +} + /* * audio-interface quirks * @@ -3392,6 +3573,7 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, + [QUIRK_MIDI_MBOX2] = snd_usb_create_midi_interface, [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface, [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, @@ -3425,7 +3607,7 @@ static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_ { struct snd_usb_audio *chip = entry->private_data; if (!chip->shutdown) - snd_iprintf(buffer, "%04x:%04x\n", + snd_iprintf(buffer, "%04x:%04x\n", USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); } @@ -3616,6 +3798,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __err_val; }
+ /* Digidesign Mbox 2 needs magic boot sequence */ + if (id == USB_ID(0x0dba, 0x3000)) { + if (snd_usb_mbox2_boot_quirk(dev) < 0) + goto __err_val; + } + /* * found a config. now register to ALSA */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 8e7f789..21aab48 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -157,6 +157,7 @@ enum quirk_type { QUIRK_MIDI_EMAGIC, QUIRK_MIDI_CME, QUIRK_MIDI_US122L, + QUIRK_MIDI_MBOX2, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA1000, diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 0eff19c..bc11fe4 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -423,7 +423,7 @@ static void snd_usbmidi_maudio_broken_running_status_input( u8 cin = buffer[i] & 0x0f; struct usbmidi_in_port *port = &ep->ports[cable]; int length; - + length = snd_usbmidi_cin_length[cin]; if (cin == 0xf && buffer[i + 1] >= 0xf8) ; /* realtime msg: no running status change */ @@ -617,13 +617,13 @@ static struct usb_protocol_ops snd_usbmidi_standard_ops = {
static struct usb_protocol_ops snd_usbmidi_midiman_ops = { .input = snd_usbmidi_midiman_input, - .output = snd_usbmidi_standard_output, + .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_midiman_packet, };
static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { .input = snd_usbmidi_maudio_broken_running_status_input, - .output = snd_usbmidi_standard_output, + .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, };
@@ -1577,7 +1577,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, snd_usbmidi_switch_roland_altsetting(umidi);
if (endpoint[0].out_ep || endpoint[0].in_ep) - return 0; + return 0;
intf = umidi->iface; if (!intf || intf->num_altsetting < 1) @@ -1615,7 +1615,7 @@ static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi* umidi, struct snd_usb_midi_endpoint_info* endpoints) { int err, i; - + err = snd_usbmidi_detect_endpoints(umidi, endpoints, MIDI_MAX_ENDPOINTS); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { if (endpoints[i].out_ep) @@ -1876,6 +1876,18 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, 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; + /* + * 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; case QUIRK_MIDI_FASTLANE: umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; /* diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f6f201e..e961f5e 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -2082,6 +2082,60 @@ YAMAHA_DEVICE(0x7010, "UB99"), } },
+/* DIGIDESIGN MBOX 2 */ +{ + /* Damien Zammit damien.zammit@gmail.com */ + + 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_AUDIO_STANDARD_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 + } + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface,