[alsa-devel] sound: usb-audio: full capture/playback/spdif support for Digidesign Mbox 2
Damien Zammit
damien.zammit at gmail.com
Wed Nov 24 13:59:38 CET 2010
Hi folks,
I have put together full support for Digidesign Mbox 2, but it needs
someone to help me merge it into alsa. I haven't seen the latest
snd-usb-audio code since last year, it seems to have branched into
multiple files.
I have worked out how the Digidesign Mbox 2 needs to be configured, it
supports SPDIF i/o simultaneously with analogue but can be toggled on
and off by using different altsettings.
Also the sample clock rate must be configured via a special method.
Therefore I have provided for this in a device_setup parameter with 4 settings:
48Khz Spdif+analog = 0
44.1Khz Spdif+analog = 1
48Khz Analog only = 2
44.1Khz Analog only = 3
###### audio
/* Digidesign Mbox 2 workaround:
* supports S24_3BE BIG ENDIAN in an unusual way */
if (chip->usb_id == USB_ID(0x0dba, 0x3000))
pcm_format = SNDRV_PCM_FORMAT_S24_3BE;
static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno);
static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
{
.....
.....
/* Digidesign Mbox 2: skip altsets incompatible with device_setup
*/
if (chip->usb_id == USB_ID(0x0dba, 0x3000) &&
mbox2_skip_setting_quirk(chip, iface_no, altno))
continue;
.....
}
#define MBOX2_SET_48K_SPDIF 0
#define MBOX2_SET_44K_SPDIF 1
#define MBOX2_SET_48K_ANALOG 2
#define MBOX2_SET_44K_ANALOG 3
static int mbox2_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
{
u8 srate[3];
/* Reset ifaces 2-5 to 0 altsetting. */
usb_set_interface(chip->dev, iface, 0);
if (device_setup[chip->index] == MBOX2_SET_48K_SPDIF ||
device_setup[chip->index] == MBOX2_SET_48K_ANALOG) {
//setup 48k
srate[0]=0x80;
srate[1]=0xbb;
srate[2]=0x00;
/* Send the magic! */
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x01, 0x22, 0x0100, 0x0085, &srate,
0x0003, 1000);
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x81, 0xa2, 0x0100, 0x0085, &srate,
0x0003, 1000);
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x81, 0xa2, 0x0100, 0x0086, &srate,
0x0003, 1000);
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x81, 0xa2, 0x0100, 0x0003, &srate,
0x0003, 1000);
snd_printk(KERN_INFO "Digidesign Mbox 2: 24 Bit 48000Hz");
if (device_setup[chip->index] == MBOX2_SET_48K_SPDIF) {
//setup spdif
snd_printk(KERN_INFO ", SPDIF\n");
if (altno != 2) return 1;
} else {
//setup analog
snd_printk(KERN_INFO ", ANALOGUE\n");
if (altno != 3) return 1;
}
} else {
//setup 44k
srate[0]=0x44;
srate[1]=0xac;
srate[2]=0x00;
/* Send the magic! */
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x01, 0x22, 0x0100, 0x0085, &srate,
0x0003, 1000);
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x81, 0xa2, 0x0100, 0x0085, &srate,
0x0003, 1000);
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x81, 0xa2, 0x0100, 0x0086, &srate,
0x0003, 1000);
snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0),
0x81, 0xa2, 0x0100, 0x0003, &srate,
0x0003, 1000);
snd_printk(KERN_INFO "Digidesign Mbox 2: 24 Bit 44100Hz");
if (device_setup[chip->index] == MBOX2_SET_44K_SPDIF ||
device_setup[chip->index] == MBOX2_SET_44K_ANALOG) {
//setup spdif
snd_printk(KERN_INFO ", SPDIF\n");
if (altno != 2) return 1;
} else {
//setup analog
snd_printk(KERN_INFO ", ANALOGUE\n");
if (altno != 3) return 1;
}
}
return 0;
}
#define MBOX2_FIRMWARE_SIZE 646
#define MBOX2_BOOT_LOADING 0x01 /* Hard coded into the device */
#define MBOX2_BOOT_READY 0x02 /* Hard coded into the device */
static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
{
struct usb_host_config *config = dev->actconfig;
int err;
u8 enablemagic[3];
u8 bootresponse;
int fwsize;
if ((fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength))
== MBOX2_FIRMWARE_SIZE) {
snd_printdd("Sending Digidesign Mbox 2 boot sequence...\n");
/* From USB Snoop,
*
* SetupPacket = RT RQ VHVL INDX SIZE
* RT = 0xRT Request Type
* RQ = 0xRQ Request
* VHVL = 0xVLVH Value in reverse byte order
* INDX = 0xDXIN Index in reverse byte order
* SIZE = 0xZESI Size in reverse byte order
*
* Magic boot code setup packet: c0 85 01 00 00 00 12 00
* RQ RT VLVH DXIN
ZESI
* becomes 0x85, 0xc0, 0x0001, 0x0000,
&RETURNDATA, 0x0012, TIMEOUT
* for snd_usb_ctl_msg()
*/
mbox2_reboot:
snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
0x85, 0xc0, 0x0001, 0x0000, &bootresponse,
0x0012, 1000);
if (bootresponse == MBOX2_BOOT_LOADING) {
snd_printdd("device not ready, resending boot
sequence...\n");
goto mbox2_reboot;
}
if (bootresponse == MBOX2_BOOT_READY) {
snd_printdd("device initialised!\n");
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
&dev->descriptor, sizeof(dev->descriptor));
config = dev->actconfig;
if (err < 0) snd_printdd("error
usb_get_descriptor: %d\n", err);
err = usb_reset_configuration(dev);
if (err < 0) snd_printdd("error
usb_reset_configuration: %d\n", err);
snd_printdd("mbox2_boot: new boot length = %d\n",
le16_to_cpu(get_cfg_desc(config)->wTotalLength));
/* Successful boot, (should reset all
altsettings to 0 like windows does, but works without it)
* but now we will try sending
capture/playback enable magic
*
* 80 bb 00 = 24bit mode - S24_3BE
* 44 ac 00 = 16bit mode?
*
*/
/* We want 48khz mode for now */
enablemagic[0]=0x80;
enablemagic[1]=0xbb;
enablemagic[2]=0x00;
/* Send the magic! */
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
0x01, 0x22, 0x0100, 0x0085,
&enablemagic, 0x0003, 1000);
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
0x81, 0xa2, 0x0100, 0x0085,
&enablemagic, 0x0003, 1000);
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
0x81, 0xa2, 0x0100, 0x0086,
&enablemagic, 0x0003, 1000);
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
0x81, 0xa2, 0x0100, 0x0003,
&enablemagic, 0x0003, 1000);
return 0; /* Succesful boot */
}
snd_printdd("unknown bootresponse, ignoring device:
%d\n",bootresponse);
return -ENODEV;
}
snd_printk("Invalid firmware size: %d\n",fwsize);
return -ENODEV;
}
####### quirk:
{
USB_DEVICE(0x0dba, 0x3000),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.vendor_name = "Digidesign",
.product_name = "Mbox 2",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = (const struct snd_usb_audio_quirk[]) {
{
.ifnum = 0,
.type = QUIRK_IGNORE_INTERFACE
},
{
.ifnum = 1,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 2,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 3,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 4,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 5,
.type = QUIRK_AUDIO_STANDARD_INTERFACE
},
{
.ifnum = 6,
.type = QUIRK_MIDI_MBOX2,
.data = & (const struct
snd_usb_midi_endpoint_info) {
.out_ep = 0x02,
.out_cables = 0x0001,
.in_ep = 0x81,
.in_interval = 0x01,
.in_cables = 0x0001
}
},
{
.ifnum = -1
}
}
}
},
##### midi
case QUIRK_MIDI_MBOX2:
/* Digidesign Mbox 2 uses MIDIMAN MIDI protocol */
umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
/*
* We have to make sure that the USB core looks
* again at interface 6 by calling usb_set_interface() on it.
*/
usb_set_interface(umidi->chip->dev, 6, 0);
memcpy(&endpoints[0], quirk->data,
sizeof(struct snd_usb_midi_endpoint_info));
err = 0;
break;
Damien
More information about the Alsa-devel
mailing list