Commit 9fd6aa65 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-sound.bkbits.net/linux-sound

into home.transmeta.com:/home/torvalds/v2.5/linux
parents ab1180be 273639ad
/* include/version.h. Generated automatically by configure. */ /* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc3" #define CONFIG_SND_VERSION "0.9.0rc3"
#define CONFIG_SND_DATE " (Tue Oct 01 14:40:23 2002 UTC)" #define CONFIG_SND_DATE " (Fri Oct 04 13:09:13 2002 UTC)"
...@@ -960,7 +960,6 @@ void snd_info_free_device(snd_info_entry_t * entry) ...@@ -960,7 +960,6 @@ void snd_info_free_device(snd_info_entry_t * entry)
{ {
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
char dname[32]; char dname[32];
devfs_handle_t master;
#endif #endif
snd_runtime_check(entry, return); snd_runtime_check(entry, return);
...@@ -970,12 +969,7 @@ void snd_info_free_device(snd_info_entry_t * entry) ...@@ -970,12 +969,7 @@ void snd_info_free_device(snd_info_entry_t * entry)
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
if (entry->p && strncmp(entry->name, "controlC", 8)) { if (entry->p && strncmp(entry->name, "controlC", 8)) {
sprintf(dname, "snd/%s", entry->name); sprintf(dname, "snd/%s", entry->name);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
master = devfs_find_handle(NULL, dname, strlen(dname), 0, 0, DEVFS_SPECIAL_CHR, 0);
devfs_unregister(master);
#else
devfs_find_and_unregister(NULL, dname, 0, 0, DEVFS_SPECIAL_CHR, 0); devfs_find_and_unregister(NULL, dname, 0, 0, DEVFS_SPECIAL_CHR, 0);
#endif
} }
#endif #endif
snd_info_free_entry(entry); snd_info_free_entry(entry);
......
...@@ -358,21 +358,12 @@ static int __init alsa_sound_init(void) ...@@ -358,21 +358,12 @@ static int __init alsa_sound_init(void)
static void __exit alsa_sound_exit(void) static void __exit alsa_sound_exit(void)
{ {
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
devfs_handle_t master;
char controlname[24]; char controlname[24];
short controlnum; short controlnum;
for (controlnum = 0; controlnum < snd_cards_limit; controlnum++) { for (controlnum = 0; controlnum < snd_cards_limit; controlnum++) {
sprintf(controlname, "snd/controlC%d", controlnum); sprintf(controlname, "snd/controlC%d", controlnum);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
master = devfs_find_handle(NULL, controlname, strlen(controlname), 0, 0, DEVFS_SPECIAL_CHR, 0);
devfs_unregister(master);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
master = devfs_find_handle(NULL, controlname, 0, 0, DEVFS_SPECIAL_CHR, 0);
devfs_unregister(master);
#else
devfs_find_and_unregister(NULL, controlname, 0, 0, DEVFS_SPECIAL_CHR, 0); devfs_find_and_unregister(NULL, controlname, 0, 0, DEVFS_SPECIAL_CHR, 0);
#endif
} }
#endif #endif
......
...@@ -7,7 +7,7 @@ dep_tristate 'ALi PCI Audio M5451' CONFIG_SND_ALI5451 $CONFIG_SND ...@@ -7,7 +7,7 @@ dep_tristate 'ALi PCI Audio M5451' CONFIG_SND_ALI5451 $CONFIG_SND
dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND
dep_mbool ' Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)' CONFIG_SND_CS46XX_NEW_DSP $CONFIG_SND_CS46XX $CONFIG_EXPERIMENTAL dep_mbool ' Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)' CONFIG_SND_CS46XX_NEW_DSP $CONFIG_SND_CS46XX $CONFIG_EXPERIMENTAL
dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND dep_tristate 'EMU10K1 (SB Live! & Audigy, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
dep_tristate 'RME Digi32, 32/8, 32 PRO' CONFIG_SND_RME32 $CONFIG_SND dep_tristate 'RME Digi32, 32/8, 32 PRO' CONFIG_SND_RME32 $CONFIG_SND
...@@ -25,7 +25,7 @@ dep_tristate 'ESS ES1968/1978 (Maestro-1/2/2E)' CONFIG_SND_ES1968 $CONFIG_SND ...@@ -25,7 +25,7 @@ dep_tristate 'ESS ES1968/1978 (Maestro-1/2/2E)' CONFIG_SND_ES1968 $CONFIG_SND
dep_tristate 'ESS Allegro/Maestro3' CONFIG_SND_MAESTRO3 $CONFIG_SND dep_tristate 'ESS Allegro/Maestro3' CONFIG_SND_MAESTRO3 $CONFIG_SND
dep_tristate 'ForteMedia FM801' CONFIG_SND_FM801 $CONFIG_SND dep_tristate 'ForteMedia FM801' CONFIG_SND_FM801 $CONFIG_SND
dep_tristate 'ICEnsemble ICE1712 (Envy24)' CONFIG_SND_ICE1712 $CONFIG_SND dep_tristate 'ICEnsemble ICE1712 (Envy24)' CONFIG_SND_ICE1712 $CONFIG_SND
dep_tristate 'Intel i810/i820/i830/i840/MX440 integrated audio' CONFIG_SND_INTEL8X0 $CONFIG_SND dep_tristate 'Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111' CONFIG_SND_INTEL8X0 $CONFIG_SND
dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND
dep_tristate 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND dep_tristate 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND
......
...@@ -1577,7 +1577,6 @@ int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip) ...@@ -1577,7 +1577,6 @@ int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip) int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
{ {
dsp_spos_instance_t * ins = chip->dsp_spos_instance; dsp_spos_instance_t * ins = chip->dsp_spos_instance;
unsigned int flags;
/* turn on amplifier */ /* turn on amplifier */
chip->active_ctrl(chip, 1); chip->active_ctrl(chip, 1);
......
...@@ -1410,7 +1410,6 @@ int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src) ...@@ -1410,7 +1410,6 @@ int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
{ {
dsp_spos_instance_t * ins = chip->dsp_spos_instance; dsp_spos_instance_t * ins = chip->dsp_spos_instance;
dsp_scb_descriptor_t * parent_scb; dsp_scb_descriptor_t * parent_scb;
unsigned int flags;
snd_assert (src->parent_scb_ptr == NULL, return -EINVAL ); snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
snd_assert(ins->master_mix_scb !=NULL, return -EINVAL ); snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
......
...@@ -122,7 +122,7 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, ...@@ -122,7 +122,7 @@ static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list,
* Remove a node from the chain. Called with the lock asserted * Remove a node from the chain. Called with the lock asserted
*/ */
static void __sound_remove_unit(struct sound_unit **list, int unit) static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
{ {
while(*list) while(*list)
{ {
...@@ -130,13 +130,12 @@ static void __sound_remove_unit(struct sound_unit **list, int unit) ...@@ -130,13 +130,12 @@ static void __sound_remove_unit(struct sound_unit **list, int unit)
if(p->unit_minor==unit) if(p->unit_minor==unit)
{ {
*list=p->next; *list=p->next;
devfs_unregister (p->de); return p;
kfree(p);
return;
} }
list=&(p->next); list=&(p->next);
} }
printk(KERN_ERR "Sound device %d went missing!\n", unit); printk(KERN_ERR "Sound device %d went missing!\n", unit);
return NULL;
} }
/* /*
...@@ -189,9 +188,15 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f ...@@ -189,9 +188,15 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
static void sound_remove_unit(struct sound_unit **list, int unit) static void sound_remove_unit(struct sound_unit **list, int unit)
{ {
struct sound_unit *p;
spin_lock(&sound_loader_lock); spin_lock(&sound_loader_lock);
__sound_remove_unit(list, unit); p = __sound_remove_unit(list, unit);
spin_unlock(&sound_loader_lock); spin_unlock(&sound_loader_lock);
if (p) {
devfs_unregister (p->de);
kfree(p);
}
} }
/* /*
......
...@@ -284,6 +284,16 @@ static int prepare_capture_urb(snd_usb_substream_t *subs, ...@@ -284,6 +284,16 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
urb->transfer_buffer = ctx->buf; urb->transfer_buffer = ctx->buf;
urb->transfer_buffer_length = offs; urb->transfer_buffer_length = offs;
urb->interval = 1; urb->interval = 1;
#if 0 // for check
if (! urb->bandwidth) {
int bustime;
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0)
return bustime;
printk("urb %d: bandwidth = %d (packets = %d)\n", ctx->index, bustime, urb->number_of_packets);
usb_claim_bandwidth(urb->dev, urb, bustime, 1);
}
#endif // for check
return 0; return 0;
} }
...@@ -305,8 +315,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs, ...@@ -305,8 +315,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
for (i = 0; i < urb->number_of_packets; i++) { for (i = 0; i < urb->number_of_packets; i++) {
cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (urb->iso_frame_desc[i].status) /* active? hmm, skip this */ if (urb->iso_frame_desc[i].status) {
continue; snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
// continue;
}
len = urb->iso_frame_desc[i].actual_length / stride; len = urb->iso_frame_desc[i].actual_length / stride;
if (! len) if (! len)
continue; continue;
...@@ -1009,6 +1021,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) ...@@ -1009,6 +1021,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
} }
/* if endpoint has sampling rate control, set it */ /* if endpoint has sampling rate control, set it */
if (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) { if (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) {
int crate;
data[0] = runtime->rate; data[0] = runtime->rate;
data[1] = runtime->rate >> 8; data[1] = runtime->rate >> 8;
data[2] = runtime->rate >> 16; data[2] = runtime->rate >> 16;
...@@ -1026,8 +1039,11 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) ...@@ -1026,8 +1039,11 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
dev->devnum, subs->interface, fmt->altsetting, ep); dev->devnum, subs->interface, fmt->altsetting, ep);
return err; return err;
} }
runtime->rate = data[0] | (data[1] << 8) | (data[2] << 16); crate = data[0] | (data[1] << 8) | (data[2] << 16);
// printk("ok, getting back rate to %d\n", runtime->rate); if (crate != runtime->rate) {
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, runtime->rate);
// runtime->rate = crate;
}
} }
/* always fill max packet size */ /* always fill max packet size */
if (fmt->attributes & EP_CS_ATTR_FILL_MAX) if (fmt->attributes & EP_CS_ATTR_FILL_MAX)
...@@ -1292,14 +1308,14 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype ...@@ -1292,14 +1308,14 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
* entry point for linux usb interface * entry point for linux usb interface
*/ */
#ifndef OLD_USB #ifdef OLD_USB
static int usb_audio_probe(struct usb_interface *intf, static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id); const struct usb_device_id *id);
static void usb_audio_disconnect(struct usb_interface *intf); static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
#else #else
static void * usb_audio_probe(usb_device *dev, unsigned int ifnum, static int usb_audio_probe(struct usb_interface *intf,
const struct usb_device_id *id); const struct usb_device_id *id);
static void usb_audio_disconnect(struct usb_device *dev, void *ptr); static void usb_audio_disconnect(struct usb_interface *intf);
#endif #endif
static struct usb_device_id usb_audio_ids [] = { static struct usb_device_id usb_audio_ids [] = {
...@@ -1810,7 +1826,8 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, i ...@@ -1810,7 +1826,8 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, i
* parse audio control descriptor and create pcm/midi streams * parse audio control descriptor and create pcm/midi streams
*/ */
static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum, static int snd_usb_create_midi_interface(snd_usb_audio_t *chip,
struct usb_interface *iface,
const snd_usb_audio_quirk_t *quirk); const snd_usb_audio_quirk_t *quirk);
static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif, static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
...@@ -1850,7 +1867,7 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif, ...@@ -1850,7 +1867,7 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
} }
if (iface->altsetting[0].bInterfaceClass == USB_CLASS_AUDIO && if (iface->altsetting[0].bInterfaceClass == USB_CLASS_AUDIO &&
iface->altsetting[0].bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { iface->altsetting[0].bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
if (snd_usb_create_midi_interface(chip, j, NULL) < 0) { if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
continue; continue;
} }
...@@ -1871,7 +1888,8 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif, ...@@ -1871,7 +1888,8 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
return 0; return 0;
} }
static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum, static int snd_usb_create_midi_interface(snd_usb_audio_t *chip,
struct usb_interface *iface,
const snd_usb_audio_quirk_t *quirk) const snd_usb_audio_quirk_t *quirk)
{ {
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
...@@ -1888,18 +1906,20 @@ static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum, ...@@ -1888,18 +1906,20 @@ static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum,
strcpy(seq_device->name, chip->card->shortname); strcpy(seq_device->name, chip->card->shortname);
umidi = (snd_usb_midi_t *)SNDRV_SEQ_DEVICE_ARGPTR(seq_device); umidi = (snd_usb_midi_t *)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
umidi->chip = chip; umidi->chip = chip;
umidi->ifnum = ifnum; umidi->iface = iface;
umidi->ifnum = iface->altsetting->bInterfaceNumber;
umidi->quirk = quirk; umidi->quirk = quirk;
umidi->seq_client = -1; umidi->seq_client = -1;
#endif #endif
return 0; return 0;
} }
static inline int snd_usb_create_quirk(snd_usb_audio_t *chip, int ifnum, static inline int snd_usb_create_quirk(snd_usb_audio_t *chip,
struct usb_interface *iface,
const snd_usb_audio_quirk_t *quirk) const snd_usb_audio_quirk_t *quirk)
{ {
/* in the future, there may be quirks for PCM devices */ /* in the future, there may be quirks for PCM devices */
return snd_usb_create_midi_interface(chip, ifnum, quirk); return snd_usb_create_midi_interface(chip, iface, quirk);
} }
...@@ -2050,27 +2070,18 @@ static int alloc_desc_buffer(struct usb_device *dev, int index, unsigned char ** ...@@ -2050,27 +2070,18 @@ static int alloc_desc_buffer(struct usb_device *dev, int index, unsigned char **
* only at the first time. the successive calls of this function will * only at the first time. the successive calls of this function will
* append the pcm interface to the corresponding card. * append the pcm interface to the corresponding card.
*/ */
#ifndef OLD_USB static void *snd_usb_audio_probe(struct usb_device *dev,
static int usb_audio_probe(struct usb_interface *intf, struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
#else
static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
#endif
{ {
#ifndef OLD_USB
struct usb_device *dev = interface_to_usbdev(intf);
int ifnum = intf->altsetting->bInterfaceNumber;
#endif
struct usb_config_descriptor *config = dev->actconfig; struct usb_config_descriptor *config = dev->actconfig;
const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)id->driver_info; const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)id->driver_info;
unsigned char *buffer; int i;
unsigned int index;
int i, buflen;
snd_card_t *card; snd_card_t *card;
snd_usb_audio_t *chip; snd_usb_audio_t *chip;
int ifnum = intf->altsetting->bInterfaceNumber;
if (quirk && ifnum != quirk->ifnum) if (quirk && quirk->ifnum != QUIRK_ANY_INTERFACE && ifnum != quirk->ifnum)
goto __err_val; goto __err_val;
if (usb_set_configuration(dev, config->bConfigurationValue) < 0) { if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
...@@ -2078,11 +2089,6 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -2078,11 +2089,6 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
goto __err_val; goto __err_val;
} }
index = dev->actconfig - config;
buflen = alloc_desc_buffer(dev, index, &buffer);
if (buflen <= 0)
goto __err_val;
/* /*
* found a config. now register to ALSA * found a config. now register to ALSA
*/ */
...@@ -2124,12 +2130,24 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -2124,12 +2130,24 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
} }
if (!quirk) { if (!quirk) {
if (snd_usb_create_streams(chip, ifnum, buffer, buflen) < 0) /* USB audio interface */
unsigned char *buffer;
unsigned int index;
int buflen;
index = dev->actconfig - config;
buflen = alloc_desc_buffer(dev, index, &buffer);
if (buflen <= 0)
goto __error; goto __error;
if (snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0) if (snd_usb_create_streams(chip, ifnum, buffer, buflen) < 0 ||
snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0) {
kfree(buffer);
goto __error; goto __error;
}
kfree(buffer);
} else { } else {
if (snd_usb_create_quirk(chip, ifnum, quirk) < 0) /* USB midi interface */
if (snd_usb_create_quirk(chip, intf, quirk) < 0)
goto __error; goto __error;
} }
...@@ -2142,38 +2160,20 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -2142,38 +2160,20 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
chip->num_interfaces++; chip->num_interfaces++;
up(&register_mutex); up(&register_mutex);
kfree(buffer);
#ifndef OLD_USB
return 0;
#else
return chip; return chip;
#endif
__error: __error:
up(&register_mutex); up(&register_mutex);
kfree(buffer);
__err_val: __err_val:
#ifndef OLD_USB
return -EIO;
#else
return NULL; return NULL;
#endif
} }
/* /*
* we need to take care of counter, since disconnection can be called also * we need to take care of counter, since disconnection can be called also
* many times as well as usb_audio_probe(). * many times as well as usb_audio_probe().
*/ */
#ifndef OLD_USB static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
static void usb_audio_disconnect(struct usb_interface *intf)
#else
static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
#endif
{ {
#ifndef OLD_USB
void *ptr = dev_get_drvdata(&intf->dev);
#endif
snd_usb_audio_t *chip; snd_usb_audio_t *chip;
if (ptr == (void *)-1) if (ptr == (void *)-1)
...@@ -2185,6 +2185,49 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr) ...@@ -2185,6 +2185,49 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
snd_card_free(chip->card); snd_card_free(chip->card);
} }
#ifdef OLD_USB
/*
* 2.4 USB kernel API
*/
static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
return snd_usb_audio_probe(dev, usb_ifnum_to_if(dev, ifnum), id);
}
static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
{
snd_usb_audio_disconnect(dev, ptr);
}
#else
/*
* new 2.5 USB kernel API
*/
static int usb_audio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
void *chip;
chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
if (chip) {
dev_set_drvdata(&intf->dev, chip);
return 0;
} else
return -EIO;
}
static void usb_audio_disconnect(struct usb_interface *intf)
{
snd_usb_audio_disconnect(interface_to_usbdev(intf),
dev_get_drvdata(&intf->dev));
}
#endif
static int __init snd_usb_audio_init(void) static int __init snd_usb_audio_init(void)
{ {
usb_register(&usb_audio_driver); usb_register(&usb_audio_driver);
......
...@@ -58,6 +58,8 @@ ...@@ -58,6 +58,8 @@
#define EP_GENERAL 0x01 #define EP_GENERAL 0x01
#define MS_GENERAL 0x01 #define MS_GENERAL 0x01
#define MIDI_IN_JACK 0x02
#define MIDI_OUT_JACK 0x03
/* endpoint attributes */ /* endpoint attributes */
#define EP_ATTR_MASK 0x0c #define EP_ATTR_MASK 0x0c
...@@ -146,22 +148,34 @@ struct snd_usb_audio { ...@@ -146,22 +148,34 @@ struct snd_usb_audio {
/* /*
* Information about devices with broken descriptors * Information about devices with broken descriptors
*/ */
#define QUIRK_ANY_INTERFACE -1
#define QUIRK_MIDI_FIXED_ENDPOINT 0
#define QUIRK_MIDI_YAMAHA 1
#define QUIRK_MIDI_MIDIMAN 2
typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t; typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t; typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
struct snd_usb_audio_quirk { struct snd_usb_audio_quirk {
const char *vendor_name; const char *vendor_name;
const char *product_name; const char *product_name;
int ifnum; int16_t ifnum;
int16_t type;
const void *data;
};
/* MIDI specific */ /* data for QUIRK_MIDI_FIXED_ENDPOINT */
struct snd_usb_midi_endpoint_info { struct snd_usb_midi_endpoint_info {
int16_t epnum; /* ep number, -1 autodetect */ int16_t epnum; /* ep number, -1 autodetect */
uint16_t out_cables; /* bitmask */ uint16_t out_cables; /* bitmask */
uint16_t in_cables; /* bitmask */ uint16_t in_cables; /* bitmask */
} endpoints[MIDI_MAX_ENDPOINTS];
}; };
/* for QUIRK_MIDI_YAMAHA, data is NULL */
/* for QUIRK_MIDI_MIDIMAN, data is the number of ports */
/* /*
* USB MIDI sequencer device data * USB MIDI sequencer device data
*/ */
...@@ -173,6 +187,7 @@ typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t; ...@@ -173,6 +187,7 @@ typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t;
struct snd_usb_midi { struct snd_usb_midi {
/* filled by usbaudio.c */ /* filled by usbaudio.c */
snd_usb_audio_t *chip; snd_usb_audio_t *chip;
struct usb_interface *iface;
int ifnum; int ifnum;
const snd_usb_audio_quirk_t *quirk; const snd_usb_audio_quirk_t *quirk;
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
* Copyright (c) 2002 Clemens Ladisch * Copyright (c) 2002 Clemens Ladisch
* All rights reserved. * All rights reserved.
* *
* Based on the OSS usb-midi driver by NAGANO Daisuke,
* NetBSD's umidi driver by Takuya SHIOZAKI,
* the "USB Device Class Definition for MIDI Devices" by Roland
*
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
...@@ -120,6 +124,10 @@ struct snd_usb_midi_in_endpoint { ...@@ -120,6 +124,10 @@ struct snd_usb_midi_in_endpoint {
static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep); static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep);
static const uint8_t snd_usbmidi_cin_length[] = {
0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
};
/* /*
* Submits the URB, with error handling. * Submits the URB, with error handling.
*/ */
...@@ -152,9 +160,6 @@ static int snd_usbmidi_urb_error(int status) ...@@ -152,9 +160,6 @@ static int snd_usbmidi_urb_error(int status)
static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep, static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
uint8_t packet[4]) uint8_t packet[4])
{ {
static const uint8_t cin_length[] = {
0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
};
int cable = packet[0] >> 4; int cable = packet[0] >> 4;
usbmidi_in_port_t* port = &ep->ports[cable]; usbmidi_in_port_t* port = &ep->ports[cable];
snd_seq_event_t ev; snd_seq_event_t ev;
...@@ -163,7 +168,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep, ...@@ -163,7 +168,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
return; return;
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
if (snd_midi_event_encode(port->midi_event, &packet[1], if (snd_midi_event_encode(port->midi_event, &packet[1],
cin_length[packet[0] & 0x0f], &ev) > 0 snd_usbmidi_cin_length[packet[0] & 0x0f], &ev) > 0
&& ev.type != SNDRV_SEQ_EVENT_NONE) { && ev.type != SNDRV_SEQ_EVENT_NONE) {
ev.source.port = port->seq_port; ev.source.port = port->seq_port;
ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
...@@ -199,6 +204,38 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) ...@@ -199,6 +204,38 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb)
} }
} }
/*
* Converts the data read from a Midiman device to standard USB MIDI packets.
*/
static void snd_usbmidi_in_midiman_complete(struct urb* urb)
{
if (urb->status == 0) {
uint8_t* buffer = (uint8_t*)urb->transfer_buffer;
int i;
for (i = 0; i + 4 <= urb->actual_length; i += 4) {
if (buffer[i + 3] != 0) {
/*
* snd_usbmidi_input_packet() doesn't check the
* contents of the message, so we simply use
* some random CIN with the desired length.
*/
static const uint8_t cin[4] = {
0x0, 0xf, 0x2, 0x3
};
uint8_t ctl = buffer[i + 3];
buffer[i + 3] = buffer[i + 2];
buffer[i + 2] = buffer[i + 1];
buffer[i + 1] = buffer[i + 0];
buffer[i + 0] = (ctl & 0xf0) | cin[ctl & 3];
} else {
buffer[i + 0] = 0;
}
}
}
snd_usbmidi_in_urb_complete(urb);
}
static void snd_usbmidi_out_urb_complete(struct urb* urb) static void snd_usbmidi_out_urb_complete(struct urb* urb)
{ {
snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, urb->context, return); snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, urb->context, return);
...@@ -213,6 +250,23 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb) ...@@ -213,6 +250,23 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
spin_unlock_irqrestore(&ep->buffer_lock, flags); spin_unlock_irqrestore(&ep->buffer_lock, flags);
} }
/*
* Converts standard USB MIDI packets to what Midman devices expect.
*/
static void snd_usbmidi_convert_to_midiman(struct urb* urb)
{
uint8_t* buffer = (uint8_t*)urb->transfer_buffer;
int i;
for (i = 0; i + 4 <= urb->transfer_buffer_length; i += 4) {
uint8_t cin = buffer[i];
buffer[i + 0] = buffer[i + 1];
buffer[i + 1] = buffer[i + 2];
buffer[i + 2] = buffer[i + 3];
buffer[i + 3] = (cin & 0xf0) | snd_usbmidi_cin_length[cin & 0x0f];
}
}
/* /*
* This is called when some data should be transferred to the device * This is called when some data should be transferred to the device
* (after the reception of one or more sequencer events, or after completion * (after the reception of one or more sequencer events, or after completion
...@@ -255,6 +309,9 @@ static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep) ...@@ -255,6 +309,9 @@ static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
} }
if (len > 0) { if (len > 0) {
if (ep->umidi->quirk && ep->umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
snd_usbmidi_convert_to_midiman(ep->urb);
ep->urb->dev = ep->umidi->chip->dev; ep->urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(ep->urb, GFP_ATOMIC); snd_usbmidi_submit_urb(ep->urb, GFP_ATOMIC);
} }
...@@ -479,22 +536,6 @@ static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep) ...@@ -479,22 +536,6 @@ static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
snd_magic_kfree(ep); snd_magic_kfree(ep);
} }
#ifndef OLD_USB
/* this code is not exported from USB core anymore */
struct usb_interface *local_usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
int i;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
return &dev->actconfig->interface[i];
return NULL;
}
#else
#define local_usb_ifnum_to_if usb_ifnum_to_if
#endif
/* /*
* For Roland devices, use the alternate setting which uses interrupt * For Roland devices, use the alternate setting which uses interrupt
* transfers for input. * transfers for input.
...@@ -507,7 +548,7 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi, ...@@ -507,7 +548,7 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
if (umidi->chip->dev->descriptor.idVendor != 0x0582) if (umidi->chip->dev->descriptor.idVendor != 0x0582)
return NULL; return NULL;
intf = local_usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum); intf = umidi->iface;
if (!intf || intf->num_altsetting != 2) if (!intf || intf->num_altsetting != 2)
return NULL; return NULL;
...@@ -528,6 +569,14 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi, ...@@ -528,6 +569,14 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
return &intfd->endpoint[1]; return &intfd->endpoint[1];
} }
static usb_endpoint_descriptor_t* snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* umidi)
{
usb_interface_t* intf = umidi->iface;
if (!intf)
return NULL;
return &intf->altsetting[0].endpoint[0];
}
/* /*
* Creates an input endpoint, and initalizes input ports. * Creates an input endpoint, and initalizes input ports.
* ALSA ports are created later. * ALSA ports are created later.
...@@ -551,6 +600,9 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi, ...@@ -551,6 +600,9 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
for (i = 0; i < 0x10; ++i) for (i = 0; i < 0x10; ++i)
ep->ports[i].seq_port = -1; ep->ports[i].seq_port = -1;
if (umidi->quirk && umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
int_epd = snd_usbmidi_get_midiman_int_epd(umidi);
else
int_epd = snd_usbmidi_get_int_epd(umidi, ep_info->epnum); int_epd = snd_usbmidi_get_int_epd(umidi, ep_info->epnum);
ep->urb = usb_alloc_urb(0, GFP_KERNEL); ep->urb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -697,63 +749,63 @@ static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device) ...@@ -697,63 +749,63 @@ static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
} }
/* /*
* After input and output endpoints have been initialized, create * Creates a sequencer port for an input/output cable pair.
* the ALSA port for each input/output port pair in the endpoint.
* *port_idx is the port number, which must be unique over all endpoints.
*/ */
static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi, int ep, int* port_idx, static int snd_usbmidi_create_port(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* ep_info) snd_usb_midi_out_endpoint_t* out_ep,
snd_usb_midi_in_endpoint_t* in_ep,
int cable, int port_idx)
{ {
int c, err;
int cap, type, port; int cap, type, port;
int out, in;
snd_seq_port_callback_t port_callback; snd_seq_port_callback_t port_callback;
char port_name[48]; char port_name[48];
for (c = 0; c < 0x10; ++c) {
out = ep_info->out_cables & (1 << c);
in = ep_info->in_cables & (1 << c);
if (!(in || out))
continue;
cap = 0; cap = 0;
memset(&port_callback, 0, sizeof(port_callback)); memset(&port_callback, 0, sizeof(port_callback));
port_callback.owner = THIS_MODULE; port_callback.owner = THIS_MODULE;
if (out) { if (out_ep) {
port_callback.event_input = snd_usbmidi_event_input; port_callback.event_input = snd_usbmidi_event_input;
port_callback.private_data = &umidi->endpoints[ep].out->ports[c]; port_callback.private_data = &out_ep->ports[cable];
cap |= SNDRV_SEQ_PORT_CAP_WRITE | cap |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
} }
if (in) { if (in_ep) {
cap |= SNDRV_SEQ_PORT_CAP_READ | cap |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
SNDRV_SEQ_PORT_CAP_SUBS_READ;
} }
if (out && in) { if (out_ep && in_ep) {
cap |= SNDRV_SEQ_PORT_CAP_DUPLEX; cap |= SNDRV_SEQ_PORT_CAP_DUPLEX;
} }
/* TODO: read type bits from element descriptor */ /* TODO: read type bits from element descriptor */
type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
/* TODO: read port name from jack descriptor */ /* TODO: read port name from jack descriptor */
snprintf(port_name, sizeof(port_name), "%s Port %d", snprintf(port_name, sizeof(port_name), "%s Port %d",
umidi->chip->card->shortname, *port_idx); umidi->chip->card->shortname, port_idx);
port = snd_seq_event_port_attach(umidi->seq_client, port = snd_seq_event_port_attach(umidi->seq_client, &port_callback,
&port_callback,
cap, type, port_name); cap, type, port_name);
if (port < 0) { if (port < 0) {
snd_printk(KERN_ERR "cannot create port (error code %d)\n", port); snd_printk(KERN_ERR "cannot create port (error code %d)\n", port);
return port; return port;
} }
if (in) if (in_ep)
umidi->endpoints[ep].in->ports[c].seq_port = port; in_ep->ports[cable].seq_port = port;
return port;
}
if (*port_idx < SNDRV_MINOR_RAWMIDIS) { /*
* Creates a virmidi port emulating rawmidi for the sequencer port.
*/
static int snd_usbmidi_create_virmidi(snd_usb_midi_t* umidi, int port,
int port_idx, snd_rawmidi_t** rrmidi)
{
snd_rawmidi_t *rmidi; snd_rawmidi_t *rmidi;
snd_virmidi_dev_t *rdev; snd_virmidi_dev_t *rdev;
err = snd_virmidi_new(umidi->chip->card, *port_idx, &rmidi); int err;
*rrmidi = NULL;
err = snd_virmidi_new(umidi->chip->card, port_idx, &rmidi);
if (err < 0) if (err < 0)
return err; return err;
sprintf(rmidi->name, "%s MIDI %d", umidi->chip->card->shortname, port_idx);
rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO); rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO);
strcpy(rmidi->name, port_name);
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH; rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;
rdev->client = umidi->seq_client; rdev->client = umidi->seq_client;
rdev->port = port; rdev->port = port;
...@@ -762,7 +814,41 @@ static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi, int ep, int* ...@@ -762,7 +814,41 @@ static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi, int ep, int*
snd_device_free(umidi->chip->card, rmidi); snd_device_free(umidi->chip->card, rmidi);
return err; return err;
} }
umidi->endpoints[ep].rmidi[c] = rmidi; *rrmidi = rmidi;
return 0;
}
/*
* After input and output endpoints have been initialized, create
* the ALSA port for each input/output port pair in the endpoint.
* *port_idx is the port number, which must be unique over all endpoints.
*/
static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_t* endpoint,
int* port_idx,
snd_usb_midi_endpoint_info_t* ep_info)
{
int cable;
for (cable = 0; cable < 0x10; ++cable) {
int port, err;
int out = ep_info->out_cables & (1 << cable);
int in = ep_info->in_cables & (1 << cable);
if (!(in || out))
continue;
port = snd_usbmidi_create_port(umidi,
out ? endpoint->out : NULL,
in ? endpoint->in : NULL,
cable, *port_idx);
if (port < 0)
return port;
if (*port_idx < SNDRV_MINOR_RAWMIDIS) {
err = snd_usbmidi_create_virmidi(umidi, port, *port_idx,
&endpoint->rmidi[cable]);
if (err < 0)
return err;
} }
++*port_idx; ++*port_idx;
} }
...@@ -792,8 +878,8 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi, ...@@ -792,8 +878,8 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
if (err < 0) if (err < 0)
return err; return err;
} }
err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx, err = snd_usbmidi_create_endpoint_ports(umidi, &umidi->endpoints[i],
&endpoints[i]); &port_idx, &endpoints[i]);
if (err < 0) if (err < 0)
return err; return err;
printk(KERN_INFO "snd-usb-midi: endpoint %d: created %d output and %d input ports\n", printk(KERN_INFO "snd-usb-midi: endpoint %d: created %d output and %d input ports\n",
...@@ -817,9 +903,7 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi, ...@@ -817,9 +903,7 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
usb_ms_endpoint_descriptor_t* ms_ep; usb_ms_endpoint_descriptor_t* ms_ep;
int i, epidx; int i, epidx;
memset(endpoints, 0, sizeof(*endpoints) * MIDI_MAX_ENDPOINTS); intf = umidi->iface;
intf = local_usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
if (!intf) if (!intf)
return -ENXIO; return -ENXIO;
intfd = &intf->altsetting[0]; intfd = &intf->altsetting[0];
...@@ -878,7 +962,7 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi, ...@@ -878,7 +962,7 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
usb_endpoint_descriptor_t* epd; usb_endpoint_descriptor_t* epd;
if (endpoint->epnum == -1) { if (endpoint->epnum == -1) {
intf = local_usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum); intf = umidi->iface;
if (!intf || intf->num_altsetting < 1) if (!intf || intf->num_altsetting < 1)
return -ENOENT; return -ENOENT;
intfd = intf->altsetting; intfd = intf->altsetting;
...@@ -890,6 +974,120 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi, ...@@ -890,6 +974,120 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
return 0; return 0;
} }
/*
* Detects the endpoints and ports of Yamaha devices.
*/
static int snd_usbmidi_detect_yamaha(snd_usb_midi_t* umidi,
snd_usb_midi_endpoint_info_t* endpoint)
{
usb_interface_t* intf;
usb_interface_descriptor_t* intfd;
uint8_t* cs_desc;
intf = umidi->iface;
if (!intf)
return -ENOENT;
intfd = intf->altsetting;
if (intfd->bNumEndpoints < 1)
return -ENOENT;
for (cs_desc = intfd->extra;
cs_desc < intfd->extra + intfd->extralen && cs_desc[0] >= 2;
cs_desc += cs_desc[0]) {
if (cs_desc[1] == CS_AUDIO_INTERFACE) {
if (cs_desc[2] == MIDI_IN_JACK)
endpoint->in_cables = (endpoint->in_cables << 1) | 1;
else if (cs_desc[2] == MIDI_OUT_JACK)
endpoint->out_cables = (endpoint->out_cables << 1) | 1;
}
}
if (!endpoint->in_cables && !endpoint->out_cables)
return -ENOENT;
endpoint->epnum = -1;
return snd_usbmidi_detect_endpoint(umidi, endpoint);
}
/*
* Creates the endpoints and their ports for Midiman devices.
*/
static int snd_usbmidi_create_endpoints_midiman(snd_usb_midi_t* umidi, int ports)
{
snd_usb_midi_endpoint_info_t ep_info;
usb_interface_t* intf;
usb_interface_descriptor_t* intfd;
usb_endpoint_descriptor_t* epd;
int cable, err;
intf = umidi->iface;
if (!intf)
return -ENOENT;
intfd = intf->altsetting;
if (intfd->bNumEndpoints < (ports > 1 ? 5 : 3)) {
snd_printdd(KERN_ERR "not enough endpoints\n");
return -ENOENT;
}
epd = &intfd->endpoint[0];
if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ||
(epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n");
return -ENXIO;
}
epd = &intfd->endpoint[2];
if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||
(epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");
return -ENXIO;
}
if (ports > 1) {
epd = &intfd->endpoint[4];
if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||
(epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n");
return -ENXIO;
}
}
ep_info.epnum = intfd->endpoint[2].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_cables = 0x5555 & ((1 << ports) - 1);
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
return err;
ep_info.epnum = intfd->endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.in_cables = (1 << ports) - 1;
err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
return err;
umidi->endpoints[0].in->urb->complete = snd_usbmidi_in_midiman_complete;
if (ports > 1) {
ep_info.epnum = intfd->endpoint[4].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep_info.out_cables = 0xaaaa & ((1 << ports) - 1);
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]);
if (err < 0)
return err;
}
for (cable = 0; cable < ports; ++cable) {
int port = snd_usbmidi_create_port(umidi,
umidi->endpoints[cable & 1].out,
umidi->endpoints[0].in,
cable, cable);
if (port < 0)
return port;
if (cable < SNDRV_MINOR_RAWMIDIS) {
int err = snd_usbmidi_create_virmidi(umidi, port, cable,
&umidi->endpoints[0].rmidi[cable]);
if (err < 0)
return err;
}
}
return 0;
}
/* /*
* Initialize the sequencer device. * Initialize the sequencer device.
*/ */
...@@ -912,6 +1110,7 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device) ...@@ -912,6 +1110,7 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
if (umidi->seq_client < 0) if (umidi->seq_client < 0)
return umidi->seq_client; return umidi->seq_client;
/* set the client name */
memset(&client_info, 0, sizeof(client_info)); memset(&client_info, 0, sizeof(client_info));
client_info.client = umidi->seq_client; client_info.client = umidi->seq_client;
client_info.type = KERNEL_CLIENT; client_info.type = KERNEL_CLIENT;
...@@ -935,17 +1134,37 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device) ...@@ -935,17 +1134,37 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
&client_info); &client_info);
if (umidi->quirk) { /* detect the endpoint(s) to use */
memcpy(endpoints, umidi->quirk->endpoints, sizeof(endpoints)); memset(endpoints, 0, sizeof(endpoints));
err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]); if (!umidi->quirk) {
} else {
err = snd_usbmidi_get_ms_info(umidi, endpoints); err = snd_usbmidi_get_ms_info(umidi, endpoints);
} else {
switch (umidi->quirk->type) {
case QUIRK_MIDI_FIXED_ENDPOINT:
memcpy(&endpoints[0], umidi->quirk->data,
sizeof(snd_usb_midi_endpoint_info_t));
err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]);
break;
case QUIRK_MIDI_YAMAHA:
err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
break;
case QUIRK_MIDI_MIDIMAN:
err = 0;
break;
default:
snd_printd(KERN_ERR "invalid quirk type %d\n", umidi->quirk->type);
err = -ENXIO;
break;
} }
if (err < 0) {
snd_usbmidi_seq_device_delete(seq_device);
return err;
} }
/* create ports */
if (err >= 0) {
if (umidi->quirk && umidi->quirk->type == QUIRK_MIDI_MIDIMAN)
err = snd_usbmidi_create_endpoints_midiman(umidi, (int)umidi->quirk->data);
else
err = snd_usbmidi_create_endpoints(umidi, endpoints); err = snd_usbmidi_create_endpoints(umidi, endpoints);
}
if (err < 0) { if (err < 0) {
snd_usbmidi_seq_device_delete(seq_device); snd_usbmidi_seq_device_delete(seq_device);
return err; return err;
......
...@@ -26,45 +26,143 @@ ...@@ -26,45 +26,143 @@
* In a perfect world, this file would be empty. * In a perfect world, this file would be empty.
*/ */
#define USB_DEVICE_VENDOR_SPEC(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | \
USB_DEVICE_ID_MATCH_PRODUCT | \
USB_DEVICE_ID_MATCH_INT_CLASS, \
.idVendor = vend, \
.idProduct = prod, \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
/* Yamaha devices */
{ {
/* from NetBSD's umidi driver */ USB_DEVICE_VENDOR_SPEC(0x0499, 0x1000),
USB_DEVICE(0x0499, 0x1000), /* Yamaha UX256 */
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.ifnum = 0, .vendor_name = "Yamaha",
.endpoints = { .product_name = "UX256",
{ .ifnum = QUIRK_ANY_INTERFACE,
.epnum = -1, .type = QUIRK_MIDI_YAMAHA
.out_cables = 0xffff,
.in_cables = 0x00ff
} }
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1001),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "MU1000",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
} }
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1002),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "MU2000",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
} }
}, },
{ {
/* from Nagano Daisuke's usb-midi driver */ USB_DEVICE_VENDOR_SPEC(0x0499, 0x1003),
USB_DEVICE(0x0499, 0x1001), /* Yamaha MU1000 */
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.ifnum = 0, .vendor_name = "Yamaha",
.endpoints = { .product_name = "MU500",
{ .ifnum = QUIRK_ANY_INTERFACE,
.epnum = 1, .type = QUIRK_MIDI_YAMAHA
.out_cables = 0x000f,
.in_cables = 0x0001
} }
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1004),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "UW500",
.ifnum = 3,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1005),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "MOTIF6",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
} }
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1006),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "MOTIF7",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1007),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "MOTIF8",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1008),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "UX96",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1009),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "UX16",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x100a),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "EOS BX",
.ifnum = 3,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x100e),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "S08",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x100f),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "CLP-150",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0499, 0x1010),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Yamaha",
.product_name = "CLP-170",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_YAMAHA
} }
}, },
/*
* I don't know whether the following Yamaha devices need entries or not:
* 0x1002 MU2000 0x1008 UX96
* 0x1003 MU500 0x1009 UX16
* 0x1004 UW500 0x100e S08
* 0x1005 MOTIF6 0x100f CLP-150
* 0x1006 MOTIF7 0x1010 CLP-170
* 0x1007 MOTIF8
*/
/* /*
* Once upon a time people thought, "Wouldn't it be nice if there was a * Once upon a time people thought, "Wouldn't it be nice if there was a
...@@ -79,259 +177,316 @@ ...@@ -79,259 +177,316 @@
* class-specific descriptors. * class-specific descriptors.
*/ */
{ {
USB_DEVICE(0x0582, 0x0000), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0000),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "UA-100", .product_name = "UA-100",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0007, .out_cables = 0x0007,
.in_cables = 0x0007 .in_cables = 0x0007
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0002), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0002),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "UM-4", .product_name = "UM-4",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x000f, .out_cables = 0x000f,
.in_cables = 0x000f .in_cables = 0x000f
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0003), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0003),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "SC-8850", .product_name = "SC-8850",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x003f, .out_cables = 0x003f,
.in_cables = 0x003f .in_cables = 0x003f
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0004), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0004),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "U-8", .product_name = "U-8",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0003, .out_cables = 0x0003,
.in_cables = 0x0003 .in_cables = 0x0003
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0005), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0005),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "UM-2", .product_name = "UM-2",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0003, .out_cables = 0x0003,
.in_cables = 0x0003 .in_cables = 0x0003
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0007), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0007),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "SC-8820", .product_name = "SC-8820",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0013, .out_cables = 0x0013,
.in_cables = 0x0013 .in_cables = 0x0013
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0008), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0008),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "PC-300", .product_name = "PC-300",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0001, .out_cables = 0x0001,
.in_cables = 0x0001 .in_cables = 0x0001
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0009), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0009),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "UM-1", .product_name = "UM-1",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0001, .out_cables = 0x0001,
.in_cables = 0x0001 .in_cables = 0x0001
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x000b), USB_DEVICE_VENDOR_SPEC(0x0582, 0x000b),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "SK-500", .product_name = "SK-500",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0013, .out_cables = 0x0013,
.in_cables = 0x0013 .in_cables = 0x0013
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x000c), USB_DEVICE_VENDOR_SPEC(0x0582, 0x000c),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "SC-D70", .product_name = "SC-D70",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0007, .out_cables = 0x0007,
.in_cables = 0x0007 .in_cables = 0x0007
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0012), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0012),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "Roland", .vendor_name = "Roland",
.product_name = "XV-5050", .product_name = "XV-5050",
.ifnum = 0, .ifnum = 0,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0001, .out_cables = 0x0001,
.in_cables = 0x0001 .in_cables = 0x0001
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0014), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0014),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "UM-880", .product_name = "UM-880",
.ifnum = 0, .ifnum = 0,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x01ff, .out_cables = 0x01ff,
.in_cables = 0x01ff .in_cables = 0x01ff
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0016), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0016),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "SD-90", .product_name = "SD-90",
.ifnum = 2, .ifnum = 2,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x000f, .out_cables = 0x000f,
.in_cables = 0x000f .in_cables = 0x000f
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0023), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0023),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "UM-550", .product_name = "UM-550",
.ifnum = 0, .ifnum = 0,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x003f, .out_cables = 0x003f,
.in_cables = 0x003f .in_cables = 0x003f
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0027), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0027),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "SD-20", .product_name = "SD-20",
.ifnum = 0, .ifnum = 0,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0003, .out_cables = 0x0003,
.in_cables = 0x0007 .in_cables = 0x0007
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x0029), USB_DEVICE_VENDOR_SPEC(0x0582, 0x0029),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "SD-80", .product_name = "SD-80",
.ifnum = 0, .ifnum = 0,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x000f, .out_cables = 0x000f,
.in_cables = 0x000f .in_cables = 0x000f
} }
} }
}
}, },
{ {
USB_DEVICE(0x0582, 0x002b), USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "EDIROL", .vendor_name = "EDIROL",
.product_name = "UA-700", .product_name = "UA-700",
.ifnum = 3, .ifnum = 3,
.endpoints = { .type = QUIRK_MIDI_FIXED_ENDPOINT,
{ .data = & (const snd_usb_midi_endpoint_info_t) {
.epnum = -1, .epnum = -1,
.out_cables = 0x0003, .out_cables = 0x0003,
.in_cables = 0x0003 .in_cables = 0x0003
} }
} }
},
/* Midiman/M-Audio devices */
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x1002),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "MidiSport 2x2",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 2
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x1011),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "MidiSport 1x1",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x1015),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "Keystation",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x1021),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "MidiSport 4x4",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 4
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x1033),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "MidiSport 8x8",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 9
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x2001),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "Quattro",
.ifnum = 9,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
}
},
{
USB_DEVICE_VENDOR_SPEC(0x0763, 0x2003),
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "M-Audio",
.product_name = "AudioPhile",
.ifnum = 9,
.type = QUIRK_MIDI_MIDIMAN,
.data = (void*) 1
} }
}, },
#endif /* CONFIG_SND_SEQUENCER(_MODULE) */ #endif /* CONFIG_SND_SEQUENCER(_MODULE) */
#undef USB_DEVICE_VENDOR_SPEC
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment