[alsa-devel] sound: usb-audio: full capture/playback/spdif support for Digidesign Mbox 2
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
On 11/24/2010 04:59 AM, Damien Zammit wrote:
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.
Cool, thanks for sharing this.
Could you put your changes into a real patch, preferably generated by git, and post it again please? That makes reviewing much easier.
Thanks, Daniel
Hi Daniel,
I am confused by the git repository of alsa. There seems to be two copies of it, one in alsa-kernel and one in alsa-driver. alsa-driver seems to "patch" the alsa-kernel and then build it. I have taken one of the latest snapshots of alsa-driver and modified the alsa-kernel directory and it now compiles and the device works. What do I generate the patch against?
I can't be expected to fill in all the detail regarding #if KERNEL_VERSION < .... etc I am not that familiar with the kernel. What do you suggest to make your life easier for reviewing?
Thanks, Damien
On Fri, Nov 26, 2010 at 8:39 AM, Daniel Mack zonque@gmail.com wrote:
On 11/24/2010 04:59 AM, Damien Zammit wrote:
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.
Cool, thanks for sharing this.
Could you put your changes into a real patch, preferably generated by git, and post it again please? That makes reviewing much easier.
Thanks, Daniel _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
At Tue, 30 Nov 2010 00:03:26 +1100, Damien Zammit wrote:
Hi Daniel,
I am confused by the git repository of alsa. There seems to be two copies of it, one in alsa-kernel and one in alsa-driver. alsa-driver seems to "patch" the alsa-kernel and then build it. I have taken one of the latest snapshots of alsa-driver and modified the alsa-kernel directory and it now compiles and the device works. What do I generate the patch against?
You can use sound git repo below. git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
Base on topic/misc branch or master branch.
Takashi
Hi all,
I have generated a patch against sound-2.6 git for the Digidesign Mbox 2. I did a git commit -a and then git diff HEAD^1 to generate this patch. Unfortunately I am sending this email from gmail, so I'm not sure about line formatting, yikes.
Damien
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 25bce7e..5dace7e 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2122,6 +2122,18 @@ 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; + /* + * 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->dev, 6, 0); + memcpy(&endpoints[0], quirk->data, + sizeof(struct snd_usb_midi_endpoint_info)); + err = 0; + 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 ad7079d..f0b6520 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2477,6 +2477,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_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 + } + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index cf8bf08..d66a638 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -287,6 +287,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, @@ -479,6 +480,9 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip, if (chip->usb_id == USB_ID(0x0763, 0x2003)) return audiophile_skip_setting_quirk(chip, iface, altno);
+ if (chip->usb_id == USB_ID(0x0dba, 0x3000)) + return mbox2_skip_setting_quirk(chip, iface, altno); + return 0; }
@@ -510,6 +514,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, if (id == USB_ID(0x133e, 0x0815)) return snd_usb_accessmusic_boot_quirk(dev);
+ /* Digidesign Mbox 2 */ + if (id == USB_ID(0x0dba, 0x3000)) + return snd_usb_mbox2_boot_quirk(dev); + return 0; }
@@ -527,6 +535,9 @@ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat if (chip->setup == 0x00 || fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3) return 1; + break; + case USB_ID(0x0dba, 0x3000): /* Digidesign Mbox 2 */ + return 1; } return 0; } @@ -594,3 +605,170 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } }
+#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 48 kHz 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; +} + +#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 (chip->setup == MBOX2_SET_48K_SPDIF || + chip->setup == 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 (chip->setup == 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 (chip->setup == MBOX2_SET_44K_SPDIF || + chip->setup == 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; +} + + diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 03e5e94..13fd3ad 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -20,4 +20,9 @@ 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);
+static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno); + +static int snd_usb_mbox2_boot_quirk(struct usb_device *dev); + #endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index db3eb21..128c3f4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -70,6 +70,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,
On Tue, Nov 30, 2010 at 1:50 AM, Takashi Iwai tiwai@suse.de wrote:
At Tue, 30 Nov 2010 00:03:26 +1100, Damien Zammit wrote:
Hi Daniel,
I am confused by the git repository of alsa. There seems to be two copies of it, one in alsa-kernel and one in alsa-driver. alsa-driver seems to "patch" the alsa-kernel and then build it. I have taken one of the latest snapshots of alsa-driver and modified the alsa-kernel directory and it now compiles and the device works. What do I generate the patch against?
You can use sound git repo below. git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
Base on topic/misc branch or master branch.
Takashi
Damien Zammit wrote:
Unfortunately I am sending this email from gmail, so I'm not sure about line formatting, yikes.
Long lines are wrapped.
/*
* 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->dev, 6, 0);
Why? Is this another duplicate endpoint number?
memcpy(&endpoints[0], quirk->data,
sizeof(struct snd_usb_midi_endpoint_info));
I think you should be able to call snd_usbmidi_detect_per_port_endpoints here.
+/* DIGIDESIGN MBOX 2 */ +{
/* Damien Zammit <damien.zammit@gmail.com> */
This usually goes into the commit log.
USB_DEVICE(0x0dba, 0x3000),
The entries are supposed to be ordered by their IDs.
* but now we will try sending
capture/playback enable magic
*
* 80 bb 00 = 24bit mode - S24_3BE
* 44 ac 00 = 16bit mode?
Why the question mark?
//enablemagic[0]=0x44;
//enablemagic[1]=0xac;
//enablemagic[2]=0x00;
Why is this commented out?
+#define MBOX2_SET_48K_SPDIF 0 +#define MBOX2_SET_44K_SPDIF 1 +#define MBOX2_SET_48K_ANALOG 2 +#define MBOX2_SET_44K_ANALOG 3
In theory, this should be some control instead of a module parameter.
+static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
This function isn't consistently indented with tabs.
Regards, Clemens
My previous patch did not enable capture, this patch works and duplex mode is flawless.
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 25bce7e..5dace7e 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2122,6 +2122,18 @@ 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; + /* + * 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->dev, 6, 0); + memcpy(&endpoints[0], quirk->data, + sizeof(struct snd_usb_midi_endpoint_info)); + err = 0; + 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 ad7079d..2ea3636 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2477,6 +2477,58 @@ 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_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_IGNORE_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, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index cf8bf08..fe4b8e2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -287,6 +287,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, @@ -479,6 +480,9 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip, if (chip->usb_id == USB_ID(0x0763, 0x2003)) return audiophile_skip_setting_quirk(chip, iface, altno);
+ if (chip->usb_id == USB_ID(0x0dba, 0x3000)) + return mbox2_skip_setting_quirk(chip, iface, altno); + return 0; }
@@ -510,6 +514,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, if (id == USB_ID(0x133e, 0x0815)) return snd_usb_accessmusic_boot_quirk(dev);
+ /* Digidesign Mbox 2 */ + if (id == USB_ID(0x0dba, 0x3000)) + return snd_usb_mbox2_boot_quirk(dev); + return 0; }
@@ -527,6 +535,9 @@ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat if (chip->setup == 0x00 || fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3) return 1; + break; + case USB_ID(0x0dba, 0x3000): /* Digidesign Mbox 2 */ + return 1; } return 0; } @@ -594,3 +605,170 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } }
+#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; + u8 temp[12]; + 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 = 48kHz + * 44 ac 00 = 44.1kHz + * + */ + /* 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, 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; +} + +#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]; + u8 temp[12]; + + /* Reset ifaces 2-5 to 0 altsetting. */ + usb_set_interface(chip->dev, iface, 0); + + if (chip->setup == MBOX2_SET_48K_SPDIF || + chip->setup == 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_rcvctrlpipe(chip->dev, 0), + 0x01, 0x22, 0x0100, 0x0085, &temp, 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 (chip->setup == 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_rcvctrlpipe(chip->dev, 0), + 0x01, 0x22, 0x0100, 0x0085, &temp, 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 (chip->setup == MBOX2_SET_44K_SPDIF || + chip->setup == 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; +} + + diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 03e5e94..13fd3ad 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -20,4 +20,9 @@ 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);
+static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno); + +static int snd_usb_mbox2_boot_quirk(struct usb_device *dev); + #endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index db3eb21..128c3f4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -70,6 +70,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,
On Wed, Dec 1, 2010 at 2:26 AM, Clemens Ladisch clemens@ladisch.de wrote:
Damien Zammit wrote:
Unfortunately I am sending this email from gmail, so I'm not sure about line formatting, yikes.
Long lines are wrapped.
- /*
- * 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->dev, 6, 0);
Why? Is this another duplicate endpoint number?
- memcpy(&endpoints[0], quirk->data,
- sizeof(struct snd_usb_midi_endpoint_info));
I think you should be able to call snd_usbmidi_detect_per_port_endpoints here.
+/* DIGIDESIGN MBOX 2 */ +{
- /* Damien Zammit damien.zammit@gmail.com */
This usually goes into the commit log.
- USB_DEVICE(0x0dba, 0x3000),
The entries are supposed to be ordered by their IDs.
- * but now we will try sending
capture/playback enable magic
- *
- * 80 bb 00 = 24bit mode - S24_3BE
- * 44 ac 00 = 16bit mode?
Why the question mark?
- //enablemagic[0]=0x44;
- //enablemagic[1]=0xac;
- //enablemagic[2]=0x00;
Why is this commented out?
+#define MBOX2_SET_48K_SPDIF 0 +#define MBOX2_SET_44K_SPDIF 1 +#define MBOX2_SET_48K_ANALOG 2 +#define MBOX2_SET_44K_ANALOG 3
In theory, this should be some control instead of a module parameter.
+static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
- int iface, int altno)
This function isn't consistently indented with tabs.
Regards, Clemens
On Wed, Dec 1, 2010 at 2:26 AM, Clemens Ladisch clemens@ladisch.de wrote:
Damien Zammit wrote:
Unfortunately I am sending this email from gmail, so I'm not sure about line formatting, yikes.
Long lines are wrapped.
Not much i can do about that, i dont have a plain text email client.
- /*
- * 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->dev, 6, 0);
Why? Is this another duplicate endpoint number?
The windows driver did this, and it doesn't work unless this code is here.
- memcpy(&endpoints[0], quirk->data,
- sizeof(struct snd_usb_midi_endpoint_info));
I think you should be able to call snd_usbmidi_detect_per_port_endpoints here.
Can you explain this a bit further, i'm not sure what this means.
+/* DIGIDESIGN MBOX 2 */ +{
- /* Damien Zammit damien.zammit@gmail.com */
This usually goes into the commit log.
I removed this from my patch
- USB_DEVICE(0x0dba, 0x3000),
The entries are supposed to be ordered by their IDs.
I put this in order
- * but now we will try sending
capture/playback enable magic
- *
- * 80 bb 00 = 24bit mode - S24_3BE
- * 44 ac 00 = 16bit mode?
Why the question mark?
These are actually old comments which are irrelevant, i have removed this.
- //enablemagic[0]=0x44;
- //enablemagic[1]=0xac;
- //enablemagic[2]=0x00;
Why is this commented out?
Again, i was testing different sample rates, this is unnecessary and has been removed.
+#define MBOX2_SET_48K_SPDIF 0 +#define MBOX2_SET_44K_SPDIF 1 +#define MBOX2_SET_48K_ANALOG 2 +#define MBOX2_SET_44K_ANALOG 3
In theory, this should be some control instead of a module parameter.
I have removed support for spdif mode because the rest of the driver doesnt support sending the full spdif frames anyway.
+static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
- int iface, int altno)
This function isn't consistently indented with tabs.
I fixed the tab indentation
Clemens wrote last year:
+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;
}
This could be made a loop. And it could run infinitely long; maybe you should add a timeout. (How long does it usually need?)
Can you help me write a loop with a timeout that is RT safe? I don't know how to "sleep" for say 300ms in a safe way for all kernel versions. The device responds before 5 seconds from zero power to bootup.
I am eager to get support into the kernel for this device because it is very popular among audio enthusiasts. SPDIF isnt all that important i think, but I made duplex mode work a few weeks ago and could just enable that by default without the device_setup parameter if that is preferred by the kernel developers.
Damien
Hi I thought I would post an update on this thread. I realise it is quite old but what I have now is relevant.
/* * Digidesign Mbox 2 * * Interface list: * 0 Firmware * 1 Control * 2 Playback (Async) * 3 IEC958 (Ignore) * 4 Record (Sync) * 5 Record (Async) (Ignore) * 6 MIDI * */
My previous posts may have demonstrated a lack of understanding of how USB audio devices work, but I believe I have learnt a bit more since last time I posted.
I have determined that there is a combination of altsettings for this device that allows hardcoding of them and still provides duplex support, ie, the fact that it supports multiple endpoints is irrelevant. If you use interfaces 2 and 4 both with #2 altsetting, hardcode the samplerate to 48000Hz (max) and the bit depth at 24 (max) and send some control magic to set it up, it works great!
It also requires a boot quirk to load firmware into the device from an onboard memory chip. I determined the control sequence to do so but it also needs a 3 second delay while the firmware activates and I dont have the knowledge to do a proper in-kernel delay.
In summary there are 3 parts to make this device work: 1) Boot quirk - load firmware and wait 3 seconds 2) Set up samplerate/bitrate in the device once and force S24_3BE format. 3) Select interfaces 2 and 4 both with altsetting 2, and interface 6 for midi.
I can provide working code for all three steps (except the waiting part is dodgey). I can't submit a proper patch. I hope we can get this accepted into your alsa usb driver soon because maintaining a small quirk is time consuming for me. I don't feel right cloning your entire code and attaching a tiny quirk to it and releasing it on my website for others, but so far it's the only way people have been able to use this device in linux. I have about 200 valid comments on my blog post about it.
Here is the quirk part:
{ USB_DEVICE(0x0dba, 0x3000), .driver_info = (unsigned long) & (const struct snd_mbox2_quirk) { .vendor_name = "Digidesign", .product_name = "Mbox 2", .ifnum = QUIRK_ANY_INTERFACE, .type = QUIRK_COMPOSITE, .data = (const struct snd_mbox2_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 } } } },
At Thu, 13 Dec 2012 17:21:55 +1100, Damien Zammit wrote:
Hi I thought I would post an update on this thread. I realise it is quite old but what I have now is relevant.
/*
- Digidesign Mbox 2
- Interface list:
- 0 Firmware
- 1 Control
- 2 Playback (Async)
- 3 IEC958 (Ignore)
- 4 Record (Sync)
- 5 Record (Async) (Ignore)
- 6 MIDI
*/
My previous posts may have demonstrated a lack of understanding of how USB audio devices work, but I believe I have learnt a bit more since last time I posted.
I have determined that there is a combination of altsettings for this device that allows hardcoding of them and still provides duplex support, ie, the fact that it supports multiple endpoints is irrelevant. If you use interfaces 2 and 4 both with #2 altsetting, hardcode the samplerate to 48000Hz (max) and the bit depth at 24 (max) and send some control magic to set it up, it works great!
It also requires a boot quirk to load firmware into the device from an onboard memory chip. I determined the control sequence to do so but it also needs a 3 second delay while the firmware activates and I dont have the knowledge to do a proper in-kernel delay.
In summary there are 3 parts to make this device work:
- Boot quirk - load firmware and wait 3 seconds
- Set up samplerate/bitrate in the device once and force S24_3BE format.
- Select interfaces 2 and 4 both with altsetting 2, and interface 6 for midi.
I can provide working code for all three steps (except the waiting part is dodgey). I can't submit a proper patch.
Why not...?
Takashi
Here is a patch based on for-next that does the job.
I haven't tested this particular merge on the hardware because I would have to recompile the whole kernel, but it does compile without warnings out of tree, and I haven't changed anything much from my version other than semantics to make it fit with your newer code.
Please find attached the actual patch in case gmail wraps my lines.
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..dde20f4 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..9803962 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,107 @@ 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; + + if ((fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength)) == 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; /* Succesful 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,
At Fri, 14 Dec 2012 00:09:08 +1100, Damien Zammit wrote:
Here is a patch based on for-next that does the job.
I haven't tested this particular merge on the hardware because I would have to recompile the whole kernel, but it does compile without warnings out of tree, and I haven't changed anything much from my version other than semantics to make it fit with your newer code.
Please find attached the actual patch in case gmail wraps my lines.
Thanks. Through a quick look, no serious problem is seen but could you fix the coding style? Try scripts/checkpatch.pl against your patch, and fix as much as possible.
Some errors like space around '&' can be ignored. Also 80 chars width warnings can be ignored. But most of other errors should be corrected.
Takashi
At Thu, 13 Dec 2012 14:18:16 +0100, Takashi Iwai wrote:
At Fri, 14 Dec 2012 00:09:08 +1100, Damien Zammit wrote:
Here is a patch based on for-next that does the job.
I haven't tested this particular merge on the hardware because I would have to recompile the whole kernel, but it does compile without warnings out of tree, and I haven't changed anything much from my version other than semantics to make it fit with your newer code.
Please find attached the actual patch in case gmail wraps my lines.
Thanks. Through a quick look, no serious problem is seen but could you fix the coding style? Try scripts/checkpatch.pl against your patch, and fix as much as possible.
Some errors like space around '&' can be ignored. Also 80 chars width warnings can be ignored. But most of other errors should be corrected.
Oh and a big missing thing: please give your sign off and a proper changelog text. The sign-off is a line containing like
Signed-off-by: Your Name foo@bar.com
The details about the sign off is found in Documentation/SubmittingPatches, section "Sign your work".
The changelog is one of the most important part in a patch process. Describe what the patch actually does and is provided for which purpose. In your case, which functionality works, what not, etc, are good to mention, too. It should be concise, but should provide enough information.
Takashi
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 damien@zamaudio.com
---
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,
At Fri, 14 Dec 2012 01:20:59 +1100, Damien Zammit wrote:
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 damien@zamaudio.com
Thanks for the quick update.
One more hint: put "[PATCH]" prefix to the subject so that people notice it's to review or merge more clearly.
Some nitpicking about codes below:
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;
If the quirk handling is as same as QUIRK_MIDI_MIDIMAN, can't we just reuse it instead of adding yet a new type?
+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) {
Here you can reduce the indentation depth by simply returning the error like
if (fwsize != MBOX_FIRMWARE_SIZE) { snd_printk(KERN_ERR "usb-audio: Invalid firmware size: %d\n", fwsize); return -ENODEV; }
.... // the reset
(And, as you see, always put KERN_* prefix to *_printk(). Not necessarily for snd_printd() and snd_printdd(), if it's a debug message. Also better to put some suffix to the message, too.)
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 */
Use msleep() for such a long 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) {
The same as firwamre size check. Handle the short error case and abort here. This reduces the indent level and improves the readability much better -- you don't have to consider a too long branching in your head while reading the code.
snd_printk("device initialised!\n");
Isn't it a debug message?
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);
The magic code is same as used in mbox2_skip_setting_quirk(). Move the code to a function and just call it from both places instead of keeping two open codes.
thanks,
Takashi
Takashi Iwai wrote:
Damien Zammit wrote:
- 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;
If the quirk handling is as same as QUIRK_MIDI_MIDIMAN, can't we just reuse it instead of adding yet a new type?
The endpoint detection is different; that comment applies only to the next single line.
But while technically correct, the comment is superfluous because it doesn't say anything that isn't obvious from the code.
Regards, Clemens
On 14 December 2012 01:59, Takashi Iwai tiwai@suse.de wrote:
Some nitpicking about codes below:
Here you can reduce the indentation depth by simply returning the error
Check
(And, as you see, always put KERN_* prefix to *_printk(). Not necessarily for snd_printd() and snd_printdd(), if it's a debug message.
Check
Use msleep() for such a long delay.
Check
The same as firwamre size check. Handle the short error case and abort here. This reduces the indent level and improves the readability much better -- you don't have to consider a too long branching in your head while reading the code.
Check
snd_printk("device initialised!\n");
Isn't it a debug message?
Check
The magic code is same as used in mbox2_skip_setting_quirk(). Move the code to a function and just call it from both places instead of keeping two open codes.
Check
Clemens wrote:
But while technically correct, the comment is superfluous because it doesn't say anything that isn't obvious from the code.
Check
See attached revised patch (version 3).
Regards, Damien
On 16 December 2012 21:49, Damien Zammit damien.zammit@gmail.com wrote:
See attached revised patch (version 3).
Sorry, there was a mistake in version 3, see attached patch (version 4) which compiles.
Regards, Damien
At Sun, 16 Dec 2012 22:06:25 +1100, Damien Zammit wrote:
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 damien@zamaudio.com
Thanks for the revised patch. It looks almost good, but just a few things below:
@@ -761,6 +766,108 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } }
+void mbox2_setup_48_24_magic(struct usb_device *dev)
This doesn't have to be global. Make it 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;
- u8 temp[12];
enablemagic[] and temp[] aren't used in this function. Remove them.
- if (bootresponse != MBOX2_BOOT_READY) {
snd_printk(KERN_ERR "usb-audio: Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse);
return -ENODEV;
- }
- snd_printd("usb-audio: device initialised!\n");
I'd say this could be snd_printdd() (as you'll see anyway the message below at each time), and...
- 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);
... make it to snd_printd(), as this is good to know for debugging,
- err = usb_reset_configuration(dev);
- if (err < 0)
snd_printdd("error usb_reset_configuration: %d\n", err);
... ditto, make snd_printd().
- snd_printdd("mbox2_boot: new boot length = %d\n",
le16_to_cpu(get_cfg_desc(config)->wTotalLength));
- mbox2_setup_48_24_magic(dev);
- snd_printk(KERN_INFO "usb-audio: Digidesign Mbox 2: 24bit 48kHz");
- return 0; /* Successful boot */
+}
+int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
Where is this function called? I don't see the caller in your latest patch.
thanks,
Takashi
On 17 December 2012 21:25, Takashi Iwai tiwai@suse.de wrote:
Thanks for the revised patch.
No worries! Hope we can get it in soon.
+void mbox2_setup_48_24_magic(struct usb_device *dev)
This doesn't have to be global. Make it static.
Check
enablemagic[] and temp[] aren't used in this function. Remove them.
Check
(snd_printdd and snd_printd messages) Check
+int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
Where is this function called? I don't see the caller in your latest patch.
Well spotted! I believe this function is not required anymore because I have hardcoded the altsettings in the quirk definition.
Patch version 5 attached.
Regards, Damien
At Tue, 18 Dec 2012 23:09:54 +1100, Damien Zammit wrote:
On 17 December 2012 21:25, Takashi Iwai tiwai@suse.de wrote:
Thanks for the revised patch.
No worries! Hope we can get it in soon.
+void mbox2_setup_48_24_magic(struct usb_device *dev)
This doesn't have to be global. Make it static.
Check
enablemagic[] and temp[] aren't used in this function. Remove them.
Check
(snd_printdd and snd_printd messages) Check
+int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
Where is this function called? I don't see the caller in your latest patch.
Well spotted! I believe this function is not required anymore because I have hardcoded the altsettings in the quirk definition.
Patch version 5 attached.
Thanks! One last favor...
+int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
This doesn't have to be a global one, as it's called only in the same file. You can move this function before the caller for avoiding the function declaration, and ...
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 0ca9e91..e7e9530 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -24,6 +24,8 @@ 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 snd_usb_mbox2_boot_quirk(struct usb_device *dev);
... drop this.
Takashi
At Tue, 18 Dec 2012 14:08:12 +0100, Takashi Iwai wrote:
At Tue, 18 Dec 2012 23:09:54 +1100, Damien Zammit wrote:
On 17 December 2012 21:25, Takashi Iwai tiwai@suse.de wrote:
Thanks for the revised patch.
No worries! Hope we can get it in soon.
+void mbox2_setup_48_24_magic(struct usb_device *dev)
This doesn't have to be global. Make it static.
Check
enablemagic[] and temp[] aren't used in this function. Remove them.
Check
(snd_printdd and snd_printd messages) Check
+int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
Where is this function called? I don't see the caller in your latest patch.
Well spotted! I believe this function is not required anymore because I have hardcoded the altsettings in the quirk definition.
Patch version 5 attached.
Thanks! One last favor...
+int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
This doesn't have to be a global one, as it's called only in the same file. You can move this function before the caller for avoiding the function declaration, and ...
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 0ca9e91..e7e9530 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -24,6 +24,8 @@ 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 snd_usb_mbox2_boot_quirk(struct usb_device *dev);
... drop this.
Never mind, I fixed this by myself and merged the patch now. It'll be included in 3.8-rc1.
thanks,
Takashi
On 19 December 2012 21:30, Takashi Iwai tiwai@suse.de wrote:
Never mind, I fixed this by myself and merged the patch now. It'll be included in 3.8-rc1.
Thanks Takashi!
I will be sure to compile this kernel when it comes out and double check it on the hardware!
Regards, Damien
On 19 December 2012 21:37, Damien Zammit damien.zammit@gmail.com wrote:
I will be sure to compile this kernel when it comes out and double check it on the hardware!
Bad news, the kernel panics when I plug in the device on this kernel. I compiled the kernel yesterday with default options except I changed HZ=1000 and used generic X86_64 with kernel preemption:
$ uname -a Linux zamserv 3.8.0-rc1 #1 SMP PREEMPT Sat Dec 22 21:56:06 EST 2012 x86_64 GNU/Linux
Attached is a panic dump.
Damien
Hi,
Not sure if this is relevant, but when I compile the module with a few changes, then try to insert the modules snd-usbmidi-lib and snd-usb-audio, I get
$ sudo insmod ./snd-usbmidi-lib.ko Error: could not insert module ./snd-usbmidi-lib.ko: Unknown symbol in module
Also, I think I might have found the bug but I cant test it due to the above.
Damien
On 23 December 2012 10:38, Damien Zammit damien.zammit@gmail.com wrote:
On 19 December 2012 21:37, Damien Zammit damien.zammit@gmail.com wrote:
I will be sure to compile this kernel when it comes out and double check it on the hardware!
Bad news, the kernel panics when I plug in the device on this kernel. I compiled the kernel yesterday with default options except I changed HZ=1000 and used generic X86_64 with kernel preemption:
$ uname -a Linux zamserv 3.8.0-rc1 #1 SMP PREEMPT Sat Dec 22 21:56:06 EST 2012 x86_64 GNU/Linux
Attached is a panic dump.
Damien
Hi guys,
I fixed the kernel panic, I had forgotten to allocate 12 bytes (I only allocated 1 byte) for a usb control message return value whose size was 12. I used 12 even though I am only reading the first byte because the windows driver also reads 12 bytes. Maybe in some strange cases it might return this many.
See attached patch.
By the way, the sound quality is much much better than it used to be in older kernels. I am not getting any hiss or strange noise from other usb devices being plugged in like with other kernels.
Thanks, Damien
Hi,
I have also fixed the "urb status -32" broken pipe issue that arose because I had not tested it on the hardware. It was midi related.
I realise you guys have already reviewed version 5 of my patch and accepted it. Version 6 is identical except for some changes that fix the kernel panic issue. Sorry, I am a beginner with git. How do I commit the version 5 changes locally and create a new patch based on version 5? It would make it easier to review for you guys I think.
I have fixed both the kernel panic and the broken pipe issue with midi. I believe this completes the patch, I just don't know how to submit it to you.
Damien
participants (4)
-
Clemens Ladisch
-
Damien Zammit
-
Daniel Mack
-
Takashi Iwai