All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] integrate snd-usb-midi into snd-usb-audio
@ 2002-08-26 14:09 Clemens Ladisch
  2002-08-26 16:10 ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Clemens Ladisch @ 2002-08-26 14:09 UTC (permalink / raw)
  To: alsa-devel



Index: acore/seq/Makefile
===================================================================
RCS file: /cvsroot/alsa/alsa-driver/acore/seq/Makefile,v
retrieving revision 1.2
diff -u -r1.2 Makefile
--- acore/seq/Makefile	3 Jul 2002 08:29:29 -0000	1.2
+++ acore/seq/Makefile	26 Aug 2002 13:54:22 -0000
@@ -3,7 +3,9 @@
 include $(TOPDIR)/toplevel.config
 include $(TOPDIR)/Makefile.conf
 
-obj-$(CONFIG_SND_USB_MIDI) += snd-seq-virmidi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
+ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
+obj-$(CONFIG_SND_USB_AUDIO) += snd-seq-virmidi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
+endif
 
 TOPDIR = $(MAINSRCDIR)
 include $(TOPDIR)/alsa-kernel/core/seq/Makefile




Index: include/sndmagic.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/include/sndmagic.h,v
retrieving revision 1.10
diff -u -r1.10 sndmagic.h
--- include/sndmagic.h	16 Aug 2002 11:12:45 -0000	1.10
+++ include/sndmagic.h	26 Aug 2002 13:59:02 -0000
@@ -140,9 +140,9 @@
 #define snd_usb_audio_t_magic			0xa15a3e01
 #define usb_mixer_elem_info_t_magic		0xa15a3e02
 #define snd_usb_stream_t_magic			0xa15a3e03
-#define usbmidi_t_magic				0xa15a3f01
-#define usbmidi_out_endpoint_t_magic		0xa15a3f02
-#define usbmidi_in_endpoint_t_magic		0xa15a3f03
+#define snd_usb_midi_t_magic			0xa15a3f01
+#define snd_usb_midi_out_endpoint_t_magic	0xa15a3f02
+#define snd_usb_midi_in_endpoint_t_magic	0xa15a3f03
 
 
 #else
Index: scripts/Modules.dep
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/scripts/Modules.dep,v
retrieving revision 1.16
diff -u -r1.16 Modules.dep
--- scripts/Modules.dep	14 Aug 2002 17:21:36 -0000	1.16
+++ scripts/Modules.dep	26 Aug 2002 13:59:02 -0000
@@ -203,4 +203,4 @@
 
 %dir linux/sound/usb
 |snd-usb-audio snd-pcm
-|snd-usb-midi @if_sequencer snd-seq-device snd-seq-midi-event
+snd-usb-midi @if_sequencer snd-seq-device snd-seq-midi-event
Index: usb/Config.help
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/Config.help,v
retrieving revision 1.1
diff -u -r1.1 Config.help
--- usb/Config.help	14 Aug 2002 17:22:18 -0000	1.1
+++ usb/Config.help	26 Aug 2002 13:59:02 -0000
@@ -1,5 +1,2 @@
 CONFIG_SND_USB_AUDIO
   Say 'Y' or 'M' to include support for USB audio devices.
-
-CONFIG_SND_USB_MIDI
-  Say 'Y' or 'M' to include support for MIDI devices connected via USB.
Index: usb/Config.in
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/Config.in,v
retrieving revision 1.1
diff -u -r1.1 Config.in
--- usb/Config.in	14 Aug 2002 17:22:18 -0000	1.1
+++ usb/Config.in	26 Aug 2002 13:59:02 -0000
@@ -4,6 +4,5 @@
 comment 'ALSA USB devices'
 
 dep_tristate 'USB Audio driver' CONFIG_SND_USB_AUDIO $CONFIG_SND
-dep_tristate 'USB MIDI driver' CONFIG_SND_USB_MIDI $CONFIG_SND $CONFIG_SND_SEQUENCER
 
 endmenu
Index: usb/Makefile
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/Makefile,v
retrieving revision 1.1
diff -u -r1.1 Makefile
--- usb/Makefile	14 Aug 2002 17:22:18 -0000	1.1
+++ usb/Makefile	26 Aug 2002 13:59:02 -0000
@@ -3,10 +3,14 @@
 #
 
 snd-usb-audio-objs := usbaudio.o usbmixer.o
+ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
 snd-usb-midi-objs := usbmidi.o
+endif
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o
-obj-$(CONFIG_SND_USB_MIDI) += snd-usb-midi.o
+ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
+obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-midi.o
+endif
 
 include $(TOPDIR)/Rules.make
Index: usb/usbaudio.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.c,v
retrieving revision 1.2
diff -u -r1.2 usbaudio.c
--- usb/usbaudio.c	15 Aug 2002 12:13:10 -0000	1.2
+++ usb/usbaudio.c	26 Aug 2002 13:59:02 -0000
@@ -36,6 +36,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
+#include <sound/seq_device.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
 
@@ -1234,6 +1235,7 @@
 static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
 
 static struct usb_device_id usb_audio_ids [] = {
+#include "usbquirks.h"
     { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
       .bInterfaceClass = USB_CLASS_AUDIO,
       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL },
@@ -1716,11 +1718,14 @@
 
 
 /*
- * parse audio control descriptor and create pcm streams
+ * parse audio control descriptor and create pcm/midi streams
  */
 
-static int snd_usb_create_pcm(snd_usb_audio_t *chip, int ctrlif,
-			      unsigned char *buffer, int buflen)
+static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum,
+					 const snd_usb_audio_quirk_t *quirk);
+
+static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
+				  unsigned char *buffer, int buflen)
 {
 	struct usb_device *dev = chip->dev;
 	struct usb_config_descriptor *config;
@@ -1752,6 +1757,15 @@
 			continue;
 		}
 		iface = &config->interface[j];
+		if (iface->altsetting[0].bInterfaceClass == USB_CLASS_AUDIO &&
+		    iface->altsetting[0].bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
+			if (snd_usb_create_midi_interface(chip, j, NULL) < 0) {
+				snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
+				continue;
+			}
+			usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
+			continue;
+		}
 		if (iface->altsetting[0].bInterfaceClass != USB_CLASS_AUDIO ||
 		    iface->altsetting[0].bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
 			snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j,
iface->altsetting[0].bInterfaceClass);
@@ -1808,6 +1822,37 @@
 	return 0;
 }
 
+static int snd_usb_create_midi_interface(snd_usb_audio_t *chip, int ifnum,
+					 const snd_usb_audio_quirk_t *quirk)
+{
+#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+	snd_seq_device_t *seq_device;
+	snd_usb_midi_t *umidi;
+	int err;
+
+	err = snd_seq_device_new(chip->card, chip->next_seq_device,
+				 SNDRV_SEQ_DEV_ID_USBMIDI,
+				 sizeof(snd_usb_midi_t), &seq_device);
+	if (err < 0)
+		return err;
+	chip->next_seq_device++;
+	strcpy(seq_device->name, chip->card->shortname);
+	umidi = (snd_usb_midi_t *)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
+	umidi->chip = chip;
+	umidi->ifnum = ifnum;
+	umidi->quirk = quirk;
+	umidi->seq_client = -1;
+#endif
+	return 0;
+}
+
+static inline int snd_usb_create_quirk(snd_usb_audio_t *chip, int ifnum,
+	       			       const snd_usb_audio_quirk_t *quirk)
+{
+	/* in the future, there may be quirks for PCM devices */
+	return snd_usb_create_midi_interface(chip, ifnum, quirk);
+}
+
 
 /*
  * free the chip instance
@@ -1835,7 +1880,9 @@
 /*
  * create a chip instance and set its names.
  */
-static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev, snd_usb_audio_t **rchip)
+static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
+				const snd_usb_audio_quirk_t *quirk,
+				snd_usb_audio_t **rchip)
 {
 	snd_usb_audio_t *chip;
 	int err, len;
@@ -1858,18 +1905,50 @@
 	}
 
 	strcpy(card->driver, "USB-Audio");
-	strcpy(card->shortname, "USB Audio Driver");
+
+	/* retrieve the device string as shortname */
+	if (dev->descriptor.iProduct)
+		len = usb_string(dev, dev->descriptor.iProduct,
+				 card->shortname, sizeof(card->shortname));
+	else
+		len = 0;
+	if (len <= 0) {
+ 		if (quirk && quirk->product_name) {
+			strncpy(card->shortname, quirk->product_name, sizeof(card->shortname) - 1);
+			card->shortname[sizeof(card->shortname) - 1] = '\0';
+		} else {
+			sprintf(card->shortname, "USB Device %#04x:%#04x",
+				dev->descriptor.idVendor, dev->descriptor.idProduct);
+		}
+	}
 
 	/* retrieve the vendor and device strings as longname */
-	len = usb_string(dev, 1, card->longname, sizeof(card->longname) - 1);
-	if (len <= 0)
+	if (dev->descriptor.iManufacturer)
+		len = usb_string(dev, dev->descriptor.iManufacturer,
+				 card->longname, sizeof(card->longname) - 1);
+	else
 		len = 0;
-	else {
+	if (len <= 0) {
+		if (quirk && quirk->vendor_name) {
+			strncpy(card->longname, quirk->vendor_name, sizeof(card->longname) - 2);
+			card->longname[sizeof(card->longname) - 2] = '\0';
+			len = strlen(card->longname);
+		} else {
+			len = 0;
+		}
+	}
+	if (len > 0) {
 		card->longname[len] = ' ';
 		len++;
 	}
-	card->longname[len] = 0;
-	usb_string(dev, 2, card->longname + len, sizeof(card->longname) - len);
+	card->longname[len] = '\0';
+	if ((!dev->descriptor.iProduct
+	     || usb_string(dev, dev->descriptor.iProduct,
+	    		   card->longname + len, sizeof(card->longname) - len) <= 0)
+	    && quirk && quirk->product_name) {
+		strncpy(card->longname + len, quirk->product_name, sizeof(card->longname) - len - 1);
+		card->longname[sizeof(card->longname) - 1] = '\0';
+	}
 
 	*rchip = chip;
 	return 0;
@@ -1926,12 +2005,16 @@
 			     const struct usb_device_id *id)
 {
 	struct usb_config_descriptor *config = dev->actconfig;	
+	const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)id->driver_info;
 	unsigned char *buffer;
 	unsigned int index;
 	int i, buflen;
 	snd_card_t *card;
 	snd_usb_audio_t *chip;
 
+	if (quirk && ifnum != quirk->ifnum)
+		return NULL;
+
 	if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
 		snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", config->bConfigurationValue);
 		return NULL;
@@ -1966,7 +2049,7 @@
 					snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
 					goto __error;
 				}
-				if (snd_usb_audio_create(card, dev, &chip) < 0) {
+				if (snd_usb_audio_create(card, dev, quirk, &chip) < 0) {
 					snd_card_free(card);
 					goto __error;
 				}
@@ -1980,10 +2063,15 @@
 		}
 	}
 
-	if (snd_usb_create_pcm(chip, ifnum, buffer, buflen) < 0)
-		goto __error;
-	if (snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0)
-		goto __error;
+	if (!quirk) {
+		if (snd_usb_create_streams(chip, ifnum, buffer, buflen) < 0)
+			goto __error;
+		if (snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0)
+			goto __error;
+	} else {
+		if (snd_usb_create_quirk(chip, ifnum, quirk) < 0)
+			goto __error;
+	}
 
 	/* we are allowed to call snd_card_register() many times */
 	if (snd_card_register(chip->card) < 0) {
Index: usb/usbaudio.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.h,v
retrieving revision 1.1
diff -u -r1.1 usbaudio.h
--- usb/usbaudio.h	14 Aug 2002 17:22:18 -0000	1.1
+++ usb/usbaudio.h	26 Aug 2002 13:59:02 -0000
@@ -27,6 +27,7 @@
 
 #define USB_SUBCLASS_AUDIO_CONTROL	0x01
 #define USB_SUBCLASS_AUDIO_STREAMING	0x02
+#define USB_SUBCLASS_MIDI_STREAMING	0x03
 
 #define USB_DT_CS_DEVICE                0x21
 #define USB_DT_CS_CONFIG                0x22
@@ -56,6 +57,8 @@
 
 #define EP_GENERAL			0x01
 
+#define MS_GENERAL			0x01
+
 /* endpoint attributes */
 #define EP_ATTR_MASK			0x0c
 #define EP_ATTR_ASYNC			0x04
@@ -115,6 +118,11 @@
 #define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER23_LS	0x2006
 
 
+/* maximum number of endpoints per interface */
+#define MIDI_MAX_ENDPOINTS 2
+
+#define SNDRV_SEQ_DEV_ID_USBMIDI "usb-midi"
+
 /*
  */
 
@@ -130,7 +138,52 @@
 	struct list_head pcm_list;	/* list of pcm streams */
 	int pcm_devs;
 
+#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+	int next_seq_device;
+#endif
 };  
+
+/*
+ * Information about devices with broken descriptors
+ */
+typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
+typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
+
+struct snd_usb_audio_quirk {
+	const char *vendor_name;
+	const char *product_name;
+	int ifnum;
+
+	/* MIDI specific */
+	struct snd_usb_midi_endpoint_info {
+		int16_t epnum;		/* ep number, -1 autodetect */
+		uint16_t out_cables;	/* bitmask */
+		uint16_t in_cables;	/* bitmask */
+	} endpoints[MIDI_MAX_ENDPOINTS];
+};
+
+/*
+ * USB MIDI sequencer device data
+ */
+typedef struct snd_usb_midi snd_usb_midi_t;
+typedef struct snd_usb_midi_endpoint snd_usb_midi_endpoint_t;
+typedef struct snd_usb_midi_out_endpoint snd_usb_midi_out_endpoint_t;
+typedef struct snd_usb_midi_in_endpoint snd_usb_midi_in_endpoint_t;
+
+struct snd_usb_midi {
+	/* filled by usbaudio.c */
+	snd_usb_audio_t *chip;
+	int ifnum;
+	const snd_usb_audio_quirk_t *quirk;
+
+	/* used internally in usbmidi.c */
+	int seq_client;
+	struct snd_usb_midi_endpoint {
+		snd_usb_midi_out_endpoint_t *out;
+		snd_usb_midi_in_endpoint_t *in;
+		snd_rawmidi_t *rmidi[0x10];
+	} endpoints[MIDI_MAX_ENDPOINTS];
+};
 
 
 /*
Index: usb/usbmidi.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbmidi.c,v
retrieving revision 1.3
diff -u -r1.3 usbmidi.c
--- usb/usbmidi.c	19 Aug 2002 16:19:03 -0000	1.3
+++ usb/usbmidi.c	26 Aug 2002 13:59:02 -0000
@@ -40,7 +40,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
-#include <asm/semaphore.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/asequencer.h>
@@ -48,59 +47,13 @@
 #include <sound/seq_kernel.h>
 #include <sound/seq_virmidi.h>
 #include <sound/seq_midi_event.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
+#include "usbaudio.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("USB MIDI");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{Generic,USB MIDI},"
-		"{Roland/EDIROL,PC-300},"
-		"{Roland/EDIROL,SC-8820},"
-		"{Roland/EDIROL,SC-8850},"
-		"{Roland/EDIROL,SC-D70},"
-		"{Roland/EDIROL,SD-20},"
-		"{Roland/EDIROL,SD-80},"
-		"{Roland/EDIROL,SD-90},"
-		"{Roland/EDIROL,SK-500},"
-		"{Roland/EDIROL,U-8},"
-		"{Roland/EDIROL,UA-100(G)},"
-		"{Roland/EDIROL,UA-700},"
-		"{Roland/EDIROL,UM-1(S)},"
-		"{Roland/EDIROL,UM-2(E)},"
-		"{Roland/EDIROL,UM-4},"
-		"{Roland/EDIROL,UM-550},"
-		"{Roland/EDIROL,UM-880},"
-		"{Roland/EDIROL,XV-5050},"
-		"{Yamaha,MU1000},"
-		"{Yamaha,UX256}}");
-
-static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
-static char* snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
-static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
-static int snd_vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor id of this card */
-static int snd_pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product id of this card */
-static int snd_int_transfer[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Use interrupt transfers for this card */
-
-MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_index, "Index value for USB MIDI.");
-MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
-MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
-MODULE_PARM_DESC(snd_id, "ID string for USB MIDI.");
-MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
-MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_enable, "Enable USB MIDI.");
-MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(snd_vid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_vid, "USB Vendor ID for USB MIDI.");
-MODULE_PARM_SYNTAX(snd_vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
-MODULE_PARM(snd_pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_pid, "USB Product ID for USB MIDI.");
-MODULE_PARM_SYNTAX(snd_pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
-MODULE_PARM(snd_int_transfer, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_int_transfer, "Use interrupt transfers for USB MIDI input.");
-MODULE_PARM_SYNTAX(snd_int_transfer, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC ",skill:advanced");
 
 /* size of the per-endpoint output buffer, must be a multiple of 4 */
 #define OUTPUT_BUFFER_SIZE 0x400
@@ -108,26 +61,6 @@
 /* max. size of incoming sysex messages */
 #define INPUT_BUFFER_SIZE 0x200
 
-#define MAX_ENDPOINTS 2
-
-#define SNDRV_SEQ_DEV_ID_USBMIDI "usb-midi"
-
-#ifndef USB_SUBCLASS_MIDISTREAMING
-#define USB_SUBCLASS_MIDISTREAMING 3
-#endif
-
-#ifndef USB_DT_CS_INTERFACE
-#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
-#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
-#endif
-
-#ifndef USB_DST_MS_HEADER
-#define USB_DST_MS_HEADER 0x01
-#define USB_DST_MS_GENERAL 0x01
-#define USB_DST_MS_HEADER_SIZE 7
-#define USB_DST_MS_GENERAL_SIZE 4
-#endif
-
 typedef struct usb_driver usb_driver_t;
 typedef struct usb_device usb_device_t;
 typedef struct usb_device_id usb_device_id_t;
@@ -153,47 +86,11 @@
 	__u8  baAssocJackID[0];
 } __attribute__ ((packed));
 
-typedef struct usbmidi usbmidi_t;
-typedef struct usbmidi_device_info usbmidi_device_info_t;
-typedef struct usbmidi_endpoint_info usbmidi_endpoint_info_t;
-typedef struct usbmidi_endpoint usbmidi_endpoint_t;
-typedef struct usbmidi_out_endpoint usbmidi_out_endpoint_t;
 typedef struct usbmidi_out_port usbmidi_out_port_t;
-typedef struct usbmidi_in_endpoint usbmidi_in_endpoint_t;
 typedef struct usbmidi_in_port usbmidi_in_port_t;
 
-/*
- * Describes the capabilities of a USB MIDI device.
- * This structure is filled after parsing the USB descriptors,
- * or is supplied explicitly for broken devices.
- */
-struct usbmidi_device_info {
-	char vendor[32];		/* vendor name */
-	char product[32];		/* device name */
-	int16_t ifnum;			/* interface number */
-	struct usbmidi_endpoint_info {
-		int16_t epnum;		/* endpoint number,
-					   -1: autodetect (first ep only) */
-		uint16_t out_cables;	/* bitmask */
-		uint16_t in_cables;	/* bitmask */
-	} endpoints[MAX_ENDPOINTS];
-};
-
-struct usbmidi {
-	snd_card_t* card;
-	usb_device_t* usb_device;
-	int dev;
-	int seq_client;
-	usbmidi_device_info_t device_info;
-	struct usbmidi_endpoint {
-		usbmidi_out_endpoint_t* out;
-		usbmidi_in_endpoint_t* in;
-		snd_rawmidi_t* rmidi[0x10];
-	} endpoints[MAX_ENDPOINTS];
-};
-
-struct usbmidi_out_endpoint {
-	usbmidi_t* umidi;
+struct snd_usb_midi_out_endpoint {
+	snd_usb_midi_t* umidi;
 	struct urb* urb;
 	int max_transfer;		/* size of urb buffer */
 	struct tasklet_struct tasklet;
@@ -204,16 +101,16 @@
 	spinlock_t buffer_lock;
 
 	struct usbmidi_out_port {
-		usbmidi_out_endpoint_t* ep;
+		snd_usb_midi_out_endpoint_t* ep;
 		uint8_t cable;		/* cable number << 4 */
 		uint8_t sysex_len;
 		uint8_t sysex[2];
 	} ports[0x10];
 };
 
-struct usbmidi_in_endpoint {
-	usbmidi_t* umidi;
-	usbmidi_endpoint_t* ep;
+struct snd_usb_midi_in_endpoint {
+	snd_usb_midi_t* umidi;
+	snd_usb_midi_endpoint_t* ep;
 	struct urb* urb;
 	struct usbmidi_in_port {
 		int seq_port;
@@ -221,10 +118,7 @@
 	} ports[0x10];
 };
 
-static int snd_usbmidi_card_used[SNDRV_CARDS];
-static DECLARE_MUTEX(snd_usbmidi_open_mutex);
-
-static void snd_usbmidi_do_output(usbmidi_out_endpoint_t* ep);
+static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep);
 
 /*
  * Submits the URB, with error handling.
@@ -255,7 +149,7 @@
 /*
  * Converts a USB MIDI packet into an ALSA sequencer event.
  */
-static void snd_usbmidi_input_packet(usbmidi_in_endpoint_t* ep,
+static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
 				     uint8_t packet[4])
 {
 	static const uint8_t cin_length[] = {
@@ -285,7 +179,7 @@
  */
 static void snd_usbmidi_in_urb_complete(struct urb* urb)
 {
-	usbmidi_in_endpoint_t* ep = snd_magic_cast(usbmidi_in_endpoint_t, urb->context, return);
+	snd_usb_midi_in_endpoint_t* ep = snd_magic_cast(snd_usb_midi_in_endpoint_t, urb->context, return);
 
 	if (urb->status == 0) {
 		uint8_t* buffer = (uint8_t*)ep->urb->transfer_buffer;
@@ -300,14 +194,14 @@
 	}
 
 	if (!usb_pipeint(urb->pipe)) {
-		urb->dev = ep->umidi->usb_device;
+		urb->dev = ep->umidi->chip->dev;
 		snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
 	}
 }
 
 static void snd_usbmidi_out_urb_complete(struct urb* urb)
 {
-	usbmidi_out_endpoint_t* ep = snd_magic_cast(usbmidi_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);
 	unsigned long flags;
 
 	if (urb->status < 0) {
@@ -324,7 +218,7 @@
  * (after the reception of one or more sequencer events, or after completion
  * of the previous transfer). ep->buffer_lock must be held.
  */
-static void snd_usbmidi_do_output(usbmidi_out_endpoint_t* ep)
+static void snd_usbmidi_do_output(snd_usb_midi_out_endpoint_t* ep)
 {
 	int len;
 	uint8_t* buffer;
@@ -361,14 +255,14 @@
 	}
 
 	if (len > 0) {
-		ep->urb->dev = ep->umidi->usb_device;
+		ep->urb->dev = ep->umidi->chip->dev;
 		snd_usbmidi_submit_urb(ep->urb, GFP_ATOMIC);
 	}
 }
 
 static void snd_usbmidi_out_tasklet(unsigned long data)
 {
-	usbmidi_out_endpoint_t* ep = snd_magic_cast(usbmidi_out_endpoint_t, (void*)data, return);
+	snd_usb_midi_out_endpoint_t* ep = snd_magic_cast(snd_usb_midi_out_endpoint_t, (void*)data, return);
 	unsigned long flags;
 	
 	spin_lock_irqsave(&ep->buffer_lock, flags);
@@ -382,7 +276,7 @@
 static void output_packet(usbmidi_out_port_t* port,
 			  uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3)
 {
-	usbmidi_out_endpoint_t* ep = port->ep;
+	snd_usb_midi_out_endpoint_t* ep = port->ep;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ep->buffer_lock, flags);
@@ -568,7 +462,7 @@
  * Frees an input endpoint.
  * May be called when ep hasn't been initialized completely.
  */
-static void snd_usbmidi_in_endpoint_delete(usbmidi_in_endpoint_t* ep)
+static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
 {
 	int i;
 
@@ -586,53 +480,54 @@
 }
 
 /*
- * Searches for an alternate setting in which the endpoint uses interrupt
+ * For Roland devices, use the alternate setting which uses interrupt
  * transfers for input.
  */
-static int snd_usbmidi_get_int_ep(usbmidi_t* umidi, uint8_t epnum,
-				  usb_endpoint_descriptor_t** descriptor)
+static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
+							  uint8_t epnum)
 {
 	usb_interface_t* intf;
-	int i, j;
+	usb_interface_descriptor_t* intfd;
 
-	*descriptor = NULL;
-	intf = usb_ifnum_to_if(umidi->usb_device, umidi->device_info.ifnum);
-	if (!intf)
-		return -ENXIO;
-	for (i = 0; i < intf->num_altsetting; ++i) {
-		usb_interface_descriptor_t* intfd = &intf->altsetting[i];
-		for (j = 0; j < intfd->bNumEndpoints; ++j) {
-			usb_endpoint_descriptor_t* epd = &intfd->endpoint[j];
-			if ((epd->bEndpointAddress & (USB_ENDPOINT_NUMBER_MASK | USB_ENDPOINT_DIR_MASK)) == (epnum | USB_DIR_IN) &&
-			    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
-				usb_set_interface(umidi->usb_device,
-						  intfd->bInterfaceNumber,
-						  intfd->bAlternateSetting);
-				*descriptor = &intfd->endpoint[j];
-				return 0;
-			}
-		}
-	}
-	return -ENXIO;
+	if (umidi->chip->dev->descriptor.idVendor != 0x0582)
+		return NULL;
+	intf = usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
+	if (!intf || intf->num_altsetting != 2)
+		return NULL;
+
+	intfd = &intf->altsetting[0];
+	if (intfd->bNumEndpoints != 2 ||
+	    (intfd->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
+	    (intfd->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
+		return NULL;
+
+	intfd = &intf->altsetting[1];
+	if (intfd->bNumEndpoints != 2 ||
+	    (intfd->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
+	    (intfd->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
+		return NULL;
+
+	usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
+			  intfd->bAlternateSetting);
+	return &intfd->endpoint[1];
 }
 
 /*
  * Creates an input endpoint, and initalizes input ports.
  * ALSA ports are created later.
  */
-static int snd_usbmidi_in_endpoint_create(usbmidi_t* umidi,
-					  usbmidi_endpoint_info_t* ep_info,
-					  usbmidi_endpoint_t* rep)
+static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
+					  snd_usb_midi_endpoint_info_t* ep_info,
+					  snd_usb_midi_endpoint_t* rep)
 {
-	usbmidi_in_endpoint_t* ep;
-	int do_int_transfer;
-	usb_endpoint_descriptor_t* epd;
+	snd_usb_midi_in_endpoint_t* ep;
+	usb_endpoint_descriptor_t* int_epd;
 	void* buffer;
 	unsigned int pipe;
 	int length, i, err;
 
 	rep->in = NULL;
-	ep = snd_magic_kcalloc(usbmidi_in_endpoint_t, 0, GFP_KERNEL);
+	ep = snd_magic_kcalloc(snd_usb_midi_in_endpoint_t, 0, GFP_KERNEL);
 	if (!ep)
 		return -ENOMEM;
 	ep->umidi = umidi;
@@ -640,34 +535,28 @@
 	for (i = 0; i < 0x10; ++i)
 		ep->ports[i].seq_port = -1;
 
-	do_int_transfer = snd_int_transfer[umidi->dev];
-	if (do_int_transfer) {
-		if (snd_usbmidi_get_int_ep(umidi, ep_info->epnum, &epd) < 0) {
-			printk(KERN_WARNING "snd-usb-midi: interrupt endpoint not found\n");
-			do_int_transfer = 0;
-		}
-	}
+	int_epd = snd_usbmidi_get_int_epd(umidi, ep_info->epnum);
 
 	ep->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!ep->urb) {
 		snd_usbmidi_in_endpoint_delete(ep);
 		return -ENOMEM;
 	}
-	if (do_int_transfer)
-		pipe = usb_rcvintpipe(umidi->usb_device, ep_info->epnum);
+	if (int_epd)
+		pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->epnum);
 	else
-		pipe = usb_rcvbulkpipe(umidi->usb_device, ep_info->epnum);
-	length = usb_maxpacket(umidi->usb_device, pipe, 0);
+		pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->epnum);
+	length = usb_maxpacket(umidi->chip->dev, pipe, 0);
 	buffer = kmalloc(length, GFP_KERNEL);
 	if (!buffer) {
 		snd_usbmidi_in_endpoint_delete(ep);
 		return -ENOMEM;
 	}
-	if (do_int_transfer)
-		FILL_INT_URB(ep->urb, umidi->usb_device, pipe, buffer, length,
-			     snd_usbmidi_in_urb_complete, ep, epd->bInterval);
+	if (int_epd)
+		FILL_INT_URB(ep->urb, umidi->chip->dev, pipe, buffer, length,
+			     snd_usbmidi_in_urb_complete, ep, int_epd->bInterval);
 	else
-		FILL_BULK_URB(ep->urb, umidi->usb_device, pipe, buffer, length,
+		FILL_BULK_URB(ep->urb, umidi->chip->dev, pipe, buffer, length,
 			      snd_usbmidi_in_urb_complete, ep);
 
 	for (i = 0; i < 0x10; ++i)
@@ -697,7 +586,7 @@
  * Frees an output endpoint.
  * May be called when ep hasn't been initialized completely.
  */
-static void snd_usbmidi_out_endpoint_delete(usbmidi_out_endpoint_t* ep)
+static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
 {
 	if (ep->tasklet.func)
 		tasklet_kill(&ep->tasklet);
@@ -715,17 +604,17 @@
  * Creates an output endpoint, and initializes output ports.
  * ALSA ports are created later.
  */
-static int snd_usbmidi_out_endpoint_create(usbmidi_t* umidi,
-					   usbmidi_endpoint_info_t* ep_info,
-			 		   usbmidi_endpoint_t* rep)
+static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
+					   snd_usb_midi_endpoint_info_t* ep_info,
+			 		   snd_usb_midi_endpoint_t* rep)
 {
-	usbmidi_out_endpoint_t* ep;
+	snd_usb_midi_out_endpoint_t* ep;
 	int i;
 	unsigned int pipe;
 	void* buffer;
 
 	rep->out = NULL;
-	ep = snd_magic_kcalloc(usbmidi_out_endpoint_t, 0, GFP_KERNEL);
+	ep = snd_magic_kcalloc(snd_usb_midi_out_endpoint_t, 0, GFP_KERNEL);
 	if (!ep)
 		return -ENOMEM;
 	ep->umidi = umidi;
@@ -735,14 +624,14 @@
 		snd_usbmidi_out_endpoint_delete(ep);
 		return -ENOMEM;
 	}
-	pipe = usb_sndbulkpipe(umidi->usb_device, ep_info->epnum);
-	ep->max_transfer = usb_maxpacket(umidi->usb_device, pipe, 1) & ~3;
+	pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->epnum);
+	ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1) & ~3;
 	buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
 	if (!buffer) {
 		snd_usbmidi_out_endpoint_delete(ep);
 		return -ENOMEM;
 	}
-	FILL_BULK_URB(ep->urb, umidi->usb_device, pipe, buffer,
+	FILL_BULK_URB(ep->urb, umidi->chip->dev, pipe, buffer,
 		      ep->max_transfer, snd_usbmidi_out_urb_complete, ep);
 
 	spin_lock_init(&ep->buffer_lock);
@@ -763,17 +652,17 @@
  */
 static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
 {
-	usbmidi_t* umidi;
+	snd_usb_midi_t* umidi;
 	int i, j;
 
-	umidi = (usbmidi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
+	umidi = (snd_usb_midi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
 
 	if (umidi->seq_client >= 0) {
 		snd_seq_delete_kernel_client(umidi->seq_client);
 		umidi->seq_client = -1;
 	}
-	for (i = 0; i < MAX_ENDPOINTS; ++i) {
-		usbmidi_endpoint_t* ep = &umidi->endpoints[i];
+	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+		snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
 		if (ep->out) {
 			snd_usbmidi_out_endpoint_delete(ep->out);
 			ep->out = NULL;
@@ -784,7 +673,7 @@
 		}
 		for (j = 0; j < 0x10; ++j)
 			if (ep->rmidi[j]) {
-				snd_device_free(umidi->card, ep->rmidi[j]);
+				snd_device_free(umidi->chip->card, ep->rmidi[j]);
 				ep->rmidi[j] = NULL;
 			}
 	}
@@ -796,10 +685,9 @@
  * 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(usbmidi_t* umidi, int ep,
-					     int* port_idx)
+static int snd_usbmidi_create_endpoint_ports(snd_usb_midi_t* umidi, int ep, int* port_idx,
+					     snd_usb_midi_endpoint_info_t* ep_info)
 {
-	usbmidi_endpoint_info_t* ep_info = &umidi->device_info.endpoints[ep];
 	int c, err;
 	int cap, type, port;
 	int out, in;
@@ -830,8 +718,8 @@
 		/* TODO: read type bits from element descriptor */
 		type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
 		/* TODO: read port name from jack descriptor */
-		sprintf(port_name, "%s Port %d",
-			umidi->device_info.product, *port_idx);
+		snprintf(port_name, sizeof(port_name), "%s Port %d",
+			 umidi->chip->card->shortname, *port_idx);
 		port = snd_seq_event_port_attach(umidi->seq_client,
 						 &port_callback,
 						 cap, type, port_name);
@@ -845,7 +733,7 @@
 		if (*port_idx < SNDRV_MINOR_RAWMIDIS) {
 			snd_rawmidi_t *rmidi;
 			snd_virmidi_dev_t *rdev;
-			err = snd_virmidi_new(umidi->card, *port_idx, &rmidi);
+			err = snd_virmidi_new(umidi->chip->card, *port_idx, &rmidi);
 			if (err < 0)
 				return err;
 			rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -ENXIO);
@@ -853,9 +741,9 @@
 			rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;
 			rdev->client = umidi->seq_client;
 			rdev->port = port;
-			err = snd_device_register(umidi->card, rmidi);
+			err = snd_device_register(umidi->chip->card, rmidi);
 			if (err < 0) {
-				snd_device_free(umidi->card, rmidi);
+				snd_device_free(umidi->chip->card, rmidi);
 				return err;
 			}
 			umidi->endpoints[ep].rmidi[c] = rmidi;
@@ -866,219 +754,45 @@
 }
 
 /*
- * Create the endpoints and their ports.
+ * Creates the endpoints and their ports.
  */
-static int snd_usbmidi_create_endpoints(usbmidi_t* umidi)
+static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
+					snd_usb_midi_endpoint_info_t* endpoints)
 {
 	int i, err, port_idx = 0;
 
-	for (i = 0; i < MAX_ENDPOINTS; ++i) {
-		usbmidi_endpoint_info_t* ep_info = &umidi->device_info.endpoints[i];
-
-		if (!ep_info->epnum)
+	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+		if (!endpoints[i].epnum)
 			continue;
-		if (ep_info->out_cables) {
-			err = snd_usbmidi_out_endpoint_create(umidi, ep_info,
+		if (endpoints[i].out_cables) {
+			err = snd_usbmidi_out_endpoint_create(umidi, &endpoints[i],
 							      &umidi->endpoints[i]);
 			if (err < 0)
 				return err;
 		}
-		if (ep_info->in_cables) {
-			err = snd_usbmidi_in_endpoint_create(umidi, ep_info,
+		if (endpoints[i].in_cables) {
+			err = snd_usbmidi_in_endpoint_create(umidi, &endpoints[i],
 							     &umidi->endpoints[i]);
 			if (err < 0)
 				return err;
 		}
-		err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx);
+		err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx,
+							&endpoints[i]);
 		if (err < 0)
 			return err;
 		printk(KERN_INFO "snd-usb-midi: endpoint %d: created %d output and %d input ports\n",
-		       ep_info->epnum,
-		       snd_usbmidi_count_bits(ep_info->out_cables),
-		       snd_usbmidi_count_bits(ep_info->in_cables));
+		       endpoints[i].epnum,
+		       snd_usbmidi_count_bits(endpoints[i].out_cables),
+		       snd_usbmidi_count_bits(endpoints[i].in_cables));
 	}
 	return 0;
 }
 
 /*
- * Initialize the sequencer device.
- */
-static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
-{
-	usbmidi_t* umidi;
-	snd_seq_client_callback_t client_callback;
-	snd_seq_client_info_t client_info;
-	int i, err;
-
-	umidi = (usbmidi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
-
-	memset(&client_callback, 0, sizeof(client_callback));
-	client_callback.allow_output = 1;
-	client_callback.allow_input = 1;
-	umidi->seq_client = snd_seq_create_kernel_client(umidi->card, 0,
-							 &client_callback);
-	if (umidi->seq_client < 0)
-		return umidi->seq_client;
-
-	memset(&client_info, 0, sizeof(client_info));
-	client_info.client = umidi->seq_client;
-	client_info.type = KERNEL_CLIENT;
-	sprintf(client_info.name, "%s %s",
-		umidi->device_info.vendor, umidi->device_info.product);
-	snd_seq_kernel_client_ctl(umidi->seq_client,
-				  SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
-				  &client_info);
-
-	err = snd_usbmidi_create_endpoints(umidi);
-	if (err < 0) {
-		snd_usbmidi_seq_device_delete(seq_device);
-		return err;
-	}
-
-	for (i = 0; i < MAX_ENDPOINTS; ++i)
-		if (umidi->endpoints[i].in)
-			snd_usbmidi_submit_urb(umidi->endpoints[i].in->urb,
-					       GFP_KERNEL);
-	return 0;
-}
-
-static int snd_usbmidi_card_create(usb_device_t* usb_device,
-				   usbmidi_device_info_t* device_info,
-				   snd_card_t** rcard)
-{
-	snd_card_t* card;
-	snd_seq_device_t* seq_device;
-	usbmidi_t* umidi;
-	int dev, err;
-
-	if (rcard)
-		*rcard = NULL;
-
-	down(&snd_usbmidi_open_mutex);
-
-	for (dev = 0; dev < SNDRV_CARDS; ++dev) {
-		if (snd_enable[dev] && !snd_usbmidi_card_used[dev] &&
-		    (snd_vid[dev] == -1 || 
-		     snd_vid[dev] == usb_device->descriptor.idVendor) &&
-		    (snd_pid[dev] == -1 ||
-		     snd_pid[dev] == usb_device->descriptor.idProduct))
-			break;
-	}
-	if (dev >= SNDRV_CARDS) {
-		up(&snd_usbmidi_open_mutex);
-		return -ENOENT;
-	}
-
-	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
-	if (!card) {
-		up(&snd_usbmidi_open_mutex);
-		return -ENOMEM;
-	}
-	strcpy(card->driver, "USB MIDI");
-	snprintf(card->shortname, sizeof(card->shortname), "%s %s",
-		 device_info->vendor, device_info->product);
-	snprintf(card->longname, sizeof(card->longname), "%s %s at %03d/%03d if %d",
-		 device_info->vendor, device_info->product,
-		 usb_device->bus->busnum, usb_device->devnum,
-		 device_info->ifnum);
-	card->private_data = (void*)dev;
-
-	err = snd_seq_device_new(card, 0, SNDRV_SEQ_DEV_ID_USBMIDI,
-				 sizeof(usbmidi_t), &seq_device);
-	if (err < 0) {
-		snd_card_free(card);
-		up(&snd_usbmidi_open_mutex);
-		return err;
-	}
-	strcpy(seq_device->name, card->shortname);
-	umidi = (usbmidi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
-	umidi->card = card;
-	umidi->usb_device = usb_device;
-	umidi->dev = dev;
-	umidi->seq_client = -1;
-	umidi->device_info = *device_info;
-
-	err = snd_card_register(card);
-	if (err < 0) {
-		snd_card_free(card);
-		up(&snd_usbmidi_open_mutex);
-		return err;
-	}
-	snd_usbmidi_card_used[dev] = 1;
-	up(&snd_usbmidi_open_mutex);
-	if (rcard)
-		*rcard = card;
-	return 0;
-}
-
-/*
- * If the first endpoint isn't specified, use the first endpoint in the
- * first alternate setting of the interface.
- */
-static int snd_usbmidi_detect_endpoint(usb_device_t* usb_device, 
-			       	       usbmidi_device_info_t* device_info)
-{
-	usb_interface_t* intf;
-	usb_interface_descriptor_t* intfd;
-	usb_endpoint_descriptor_t* epd;
-
-	if (device_info->endpoints[0].epnum == -1) {
-		intf = usb_ifnum_to_if(usb_device, device_info->ifnum);
-		if (!intf || intf->num_altsetting < 1)
-			return -ENOENT;
-		intfd = intf->altsetting;
-		if (intfd->bNumEndpoints < 1)
-			return -ENOENT;
-		epd = intfd->endpoint;
-		device_info->endpoints[0].epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	}
-	return 0;
-}
-
-/*
- * Searches for the alternate setting with the greatest number of bulk transfer
- * endpoints.
- */
-static usb_interface_descriptor_t* snd_usbmidi_get_altsetting(usb_device_t* usb_device,
-							      usb_interface_t* intf)
-{
-	int i, best = -1;
-	int best_out = 0, best_in = 0;
-	usb_interface_descriptor_t* intfd;
-
-	if (intf->num_altsetting == 1)
-		return &intf->altsetting[0];
-	for (i = 0; i < intf->num_altsetting; ++i) {
-		int out = 0, in = 0, j;
-		for (j = 0; j < intf->altsetting[i].bNumEndpoints; ++j) {
-			usb_endpoint_descriptor_t* ep = &intf->altsetting[i].endpoint[j];
-			if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
-				if (ep->bEndpointAddress & USB_DIR_IN)
-					++in;
-				else
-					++out;
-			}
-		}
-		if ((out >= best_out && in >= best_in) &&
-		    (out > best_out || in > best_in)) {
-			best_out = out;
-			best_in = in;
-			best = i;
-		}
-	}
-	if (best < 0)
-		return NULL;
-	intfd = &intf->altsetting[best];
-	usb_set_interface(usb_device, intfd->bInterfaceNumber, intfd->bAlternateSetting);
-	return intfd;
-}
-
-/*
- * Returns MIDIStreaming device capabilities in device_info.
+ * Returns MIDIStreaming device capabilities.
  */
-static int snd_usbmidi_get_ms_info(usb_device_t* usb_device,
-				   unsigned int ifnum,
-				   usbmidi_device_info_t* device_info)
+static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
+			   	   snd_usb_midi_endpoint_info_t* endpoints)
 {
 	usb_interface_t* intf;
 	usb_interface_descriptor_t* intfd;
@@ -1087,34 +801,17 @@
 	usb_ms_endpoint_descriptor_t* ms_ep;
 	int i, epidx;
 
-	memset(device_info, 0, sizeof(*device_info));
+	memset(endpoints, 0, sizeof(*endpoints) * MIDI_MAX_ENDPOINTS);
 
-	if (usb_device->descriptor.iManufacturer == 0 ||
-	    usb_string(usb_device, usb_device->descriptor.iManufacturer,
-		       device_info->vendor, sizeof(device_info->vendor)) < 0)
-		sprintf(device_info->vendor, "Unknown Vendor %x", usb_device->descriptor.idVendor);
-	if (usb_device->descriptor.iProduct == 0 ||
-	    usb_string(usb_device, usb_device->descriptor.iProduct,
-		       device_info->product, sizeof(device_info->product)) < 0)
-		sprintf(device_info->product, "Unknown Device %x", usb_device->descriptor.idProduct);
-
-	intf = usb_ifnum_to_if(usb_device, ifnum);
+	intf = usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
 	if (!intf)
 		return -ENXIO;
-	device_info->ifnum = ifnum;
-	printk(KERN_INFO "snd-usb-midi: using interface %d\n",
-	       intf->altsetting[0].bInterfaceNumber);
-
-	intfd = snd_usbmidi_get_altsetting(usb_device, intf);
-	if (!intfd) {
-		printk(KERN_ERR "snd-usb-midi: could not determine altsetting\n");
-		return -ENXIO;
-	}
+	intfd = &intf->altsetting[0];
 	ms_header = (usb_ms_header_descriptor_t*)intfd->extra;
-	if (intfd->extralen >= USB_DST_MS_HEADER_SIZE &&
-	    ms_header->bLength >= USB_DST_MS_HEADER_SIZE &&
+	if (intfd->extralen >= 7 &&
+	    ms_header->bLength >= 7 &&
 	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
-	    ms_header->bDescriptorSubtype == USB_DST_MS_HEADER)
+	    ms_header->bDescriptorSubtype == HEADER)
 		printk(KERN_INFO "snd-usb-midi: MIDIStreaming version %02x.%02x\n",
 		       ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
 	else
@@ -1126,242 +823,124 @@
 		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
 			continue;
 		ms_ep = (usb_ms_endpoint_descriptor_t*)ep->extra;
-		if (ep->extralen < USB_DST_MS_GENERAL_SIZE ||
-		    ms_ep->bLength < USB_DST_MS_GENERAL_SIZE ||
+		if (ep->extralen < 4 ||
+		    ms_ep->bLength < 4 ||
 		    ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
-		    ms_ep->bDescriptorSubtype != USB_DST_MS_GENERAL)
+		    ms_ep->bDescriptorSubtype != MS_GENERAL)
 			continue;
-		if (device_info->endpoints[epidx].epnum != 0 &&
-		    device_info->endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
+		if (endpoints[epidx].epnum != 0 &&
+		    endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
 			++epidx;
-			if (epidx >= MAX_ENDPOINTS) {
+			if (epidx >= MIDI_MAX_ENDPOINTS) {
 				printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
 				break;
 			}
 		}
-		device_info->endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+		endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 		if (ep->bEndpointAddress & USB_DIR_IN) {
-			device_info->endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
+			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
 		} else {
-			device_info->endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
+			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
 		}
 		printk(KERN_INFO "snd-usb-midi: detected %d %s jack(s) on endpoint %d\n",
 		       ms_ep->bNumEmbMIDIJack,
 		       ep->bEndpointAddress & USB_DIR_IN ? "input" : "output",
-		       device_info->endpoints[epidx].epnum);
-	}
-	return 0;
-}
-
-/*
- * Returns device capabilities, either explicitly supplied or from the
- * class-specific descriptors.
- */
-static int snd_usbmidi_get_device_info(usb_device_t* usb_device,
-				       unsigned int ifnum,
-				       const usb_device_id_t* usb_device_id,
-				       usbmidi_device_info_t* device_info)
-{
-	if (usb_device_id->driver_info) {
-		usbmidi_device_info_t* id_info = (usbmidi_device_info_t*)usb_device_id->driver_info;
-		if (ifnum != id_info->ifnum)
-			return -ENXIO;
-		*device_info = *id_info;
-		if (snd_usbmidi_detect_endpoint(usb_device, device_info) < 0)
-			return -ENXIO;
-	} else {
-		if (snd_usbmidi_get_ms_info(usb_device, ifnum, device_info) < 0)
-			return -ENXIO;
+		       endpoints[epidx].epnum);
 	}
 	return 0;
 }
 
 /*
- * Probes for a supported device.
+ * If the first endpoint isn't specified, use the first endpoint in the
+ * first alternate setting of the interface.
  */
-static void* snd_usbmidi_usb_probe(usb_device_t* device,
-				   unsigned int ifnum,
-				   const usb_device_id_t* device_id)
+static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi, 
+			       	       snd_usb_midi_endpoint_info_t* endpoint)
 {
-	usbmidi_device_info_t device_info;
-	snd_card_t* card = NULL;
-	int err;
+	usb_interface_t* intf;
+	usb_interface_descriptor_t* intfd;
+	usb_endpoint_descriptor_t* epd;
 
-	if (snd_usbmidi_get_device_info(device, ifnum, device_id,
-					&device_info) == 0) {
-		printk(KERN_INFO "snd-usb-midi: detected %s %s\n",
-		       device_info.vendor, device_info.product);
-		err = snd_usbmidi_card_create(device, &device_info, &card);
-		if (err < 0)
-			snd_printk(KERN_ERR "cannot create card (error code %d)\n", err);
+	if (endpoint->epnum == -1) {
+		intf = usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
+		if (!intf || intf->num_altsetting < 1)
+			return -ENOENT;
+		intfd = intf->altsetting;
+		if (intfd->bNumEndpoints < 1)
+			return -ENOENT;
+		epd = intfd->endpoint;
+		endpoint->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 	}
-	return card;
+	return 0;
 }
 
 /*
- * Frees the device.
+ * Initialize the sequencer device.
  */
-static void snd_usbmidi_usb_disconnect(usb_device_t* usb_device, void* ptr)
+static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
 {
-	snd_card_t* card = (snd_card_t*)ptr;
-	int dev = (int)card->private_data;
+	snd_usb_midi_t* umidi;
+	usb_device_t* dev;
+	snd_seq_client_callback_t client_callback;
+	snd_seq_client_info_t client_info;
+	snd_usb_midi_endpoint_info_t endpoints[MIDI_MAX_ENDPOINTS];
+	int i, err;
 
-	snd_card_free(card);
-	down(&snd_usbmidi_open_mutex);
-	snd_usbmidi_card_used[dev] = 0;
-	up(&snd_usbmidi_open_mutex);
-}
+	umidi = (snd_usb_midi_t*)SNDRV_SEQ_DEVICE_ARGPTR(seq_device);
 
-/*
- * Information about devices with broken descriptors.
- */
-
-static usbmidi_device_info_t snd_usbmidi_yamaha_ux256_info = {
-	/* from NetBSD's umidi driver */
-	.vendor = "Yamaha", .product = "UX256",
-	.ifnum = 0,
-	.endpoints = {{ -1, 0xffff, 0x00ff }}
-};
-static usbmidi_device_info_t snd_usbmidi_yamaha_mu1000_info = {
-	/* from Nagano Daisuke's usb-midi driver */
-	.vendor = "Yamaha", .product = "MU1000",
-	.ifnum = 0,
-	.endpoints = {{ 1, 0x000f, 0x0001 }}
-};
-/*
- * There ain't no such thing as a standard-compliant Roland device.
- * Apparently, Roland decided not to risk to have wrong entries in the USB
- * descriptors. The consequence is that class-specific descriptors are
- * conspicuous by their absence.
- *
- * And now you may guess which company was responsible for writing the
- * USB Device Class Definition for MIDI Devices.
- */
-static usbmidi_device_info_t snd_usbmidi_roland_ua100_info = {
-	.vendor = "Roland", .product = "UA-100",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0007, 0x0007 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_um4_info = {
-	.vendor = "EDIROL", .product = "UM-4",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x000f, 0x000f }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_sc8850_info = {
-	.vendor = "Roland", .product = "SC-8850",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x003f, 0x003f }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_u8_info = {
-	.vendor = "Roland", .product = "U-8",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0003, 0x0003 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_um2_info = {
-	.vendor = "EDIROL", .product = "UM-2",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0003, 0x0003 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_sc8820_info = {
-	.vendor = "Roland", .product = "SC-8820",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0013, 0x0013 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_pc300_info = {
-	.vendor = "Roland", .product = "PC-300",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0001, 0x0001 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_um1_info = {
-	.vendor = "EDIROL", .product = "UM-1",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0001, 0x0001 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_sk500_info = {
-	.vendor = "Roland", .product = "SK-500",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0013, 0x0013 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_scd70_info = {
-	.vendor = "Roland", .product = "SC-D70",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x0007, 0x0007 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_xv5050_info = {
-	.vendor = "Roland", .product = "XV-5050",
-	.ifnum = 0,
-	.endpoints = {{ -1, 0x0001, 0x0001 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_um880_info = {
-	.vendor = "EDIROL", .product = "UM-880",
-	.ifnum = 0,
-	.endpoints = {{ -1, 0x01ff, 0x01ff }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_sd90_info = {
-	.vendor = "EDIROL", .product = "SD-90",
-	.ifnum = 2,
-	.endpoints = {{ -1, 0x000f, 0x000f }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_um550_info = {
-	.vendor = "EDIROL", .product = "UM-550",
-	.ifnum = 0,
-	.endpoints = {{ -1, 0x003f, 0x003f }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_sd20_info = {
-	.vendor = "EDIROL", .product = "SD-20",
-	.ifnum = 0,
-	.endpoints = {{ -1, 0x0003, 0x0007 }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_sd80_info = {
-	.vendor = "EDIROL", .product = "SD-80",
-	.ifnum = 0,
-	.endpoints = {{ -1, 0x000f, 0x000f }}
-};
-static usbmidi_device_info_t snd_usbmidi_roland_ua700_info = {
-	.vendor = "EDIROL", .product = "UA-700",
-	.ifnum = 3,
-	.endpoints = {{ -1, 0x0003, 0x0003 }}
-};
+	memset(&client_callback, 0, sizeof(client_callback));
+	client_callback.allow_output = 1;
+	client_callback.allow_input = 1;
+	umidi->seq_client = snd_seq_create_kernel_client(umidi->chip->card, 0,
+							 &client_callback);
+	if (umidi->seq_client < 0)
+		return umidi->seq_client;
 
-#define USBMIDI_NONCOMPLIANT_DEVICE(vid, pid, name) \
-		USB_DEVICE(vid, pid), \
-		driver_info: (unsigned long)&snd_usbmidi_##name##_info
-static usb_device_id_t snd_usbmidi_usb_id_table[] = {
-	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS |
-		       USB_DEVICE_ID_MATCH_INT_SUBCLASS,
-	  bInterfaceClass: USB_CLASS_AUDIO,
-	  bInterfaceSubClass: USB_SUBCLASS_MIDISTREAMING },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0499, 0x1000, yamaha_ux256) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0499, 0x1001, yamaha_mu1000) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0000, roland_ua100) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0002, roland_um4) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0003, roland_sc8850) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0004, roland_u8) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0005, roland_um2) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0007, roland_sc8820) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0008, roland_pc300) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0009, roland_um1) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x000b, roland_sk500) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x000c, roland_scd70) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0012, roland_xv5050) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0014, roland_um880) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0016, roland_sd90) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0023, roland_um550) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0027, roland_sd20) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x0029, roland_sd80) },
-	{ USBMIDI_NONCOMPLIANT_DEVICE(0x0582, 0x002b, roland_ua700) },
-	{ /* terminator */ }
-};
+	memset(&client_info, 0, sizeof(client_info));
+	client_info.client = umidi->seq_client;
+	client_info.type = KERNEL_CLIENT;
+	dev = umidi->chip->dev;
+	if (dev->descriptor.iProduct)
+		err = usb_string(dev, dev->descriptor.iProduct,
+				 client_info.name, sizeof(client_info.name));
+	else
+		err = 0;
+	if (err <= 0) {
+		if (umidi->quirk && umidi->quirk->product_name) {
+			strncpy(client_info.name, umidi->quirk->product_name,
+				sizeof(client_info.name) - 1);
+			client_info.name[sizeof(client_info.name) - 1] = '\0';
+		} else {
+			sprintf(client_info.name, "USB Device %#04x:%#04x",
+				dev->descriptor.idVendor, dev->descriptor.idProduct);
+		}
+	}
+	snd_seq_kernel_client_ctl(umidi->seq_client,
+				  SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
+				  &client_info);
 
-MODULE_DEVICE_TABLE(usb, snd_usbmidi_usb_id_table);
+	if (umidi->quirk) {
+		memcpy(endpoints, umidi->quirk->endpoints, sizeof(endpoints));
+		err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]);
+	} else {
+		err = snd_usbmidi_get_ms_info(umidi, endpoints);
+	}
+	if (err < 0) {
+		snd_usbmidi_seq_device_delete(seq_device);
+		return err;
+	}
+	err = snd_usbmidi_create_endpoints(umidi, endpoints);
+	if (err < 0) {
+		snd_usbmidi_seq_device_delete(seq_device);
+		return err;
+	}
 
-static usb_driver_t snd_usbmidi_usb_driver = {
-	.name = "snd-usb-midi",
-	.probe = snd_usbmidi_usb_probe,
-	.disconnect = snd_usbmidi_usb_disconnect,
-	.id_table = snd_usbmidi_usb_id_table,
-	.driver_list = LIST_HEAD_INIT(snd_usbmidi_usb_driver.driver_list)
-};
+	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
+		if (umidi->endpoints[i].in)
+			snd_usbmidi_submit_urb(umidi->endpoints[i].in->urb,
+					       GFP_KERNEL);
+	return 0;
+}
 
 static int __init snd_usbmidi_module_init(void)
 {
@@ -1369,51 +948,15 @@
 		snd_usbmidi_seq_device_new,
 		snd_usbmidi_seq_device_delete
 	};
-	int err;
 
-	err = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_USBMIDI, &ops,
-					     sizeof(usbmidi_t));
-	if (err < 0)
-		return err;
-	err = usb_register(&snd_usbmidi_usb_driver);
-	if (err < 0) {
-		snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_USBMIDI);
-		return err;
-	}
-	return 0;
+	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_USBMIDI, &ops,
+	 				      sizeof(snd_usb_midi_t));
 }
 
 static void __exit snd_usbmidi_module_exit(void)
 {
-	usb_deregister(&snd_usbmidi_usb_driver);
 	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_USBMIDI);
 }
 
 module_init(snd_usbmidi_module_init)
 module_exit(snd_usbmidi_module_exit)
-
-#ifndef MODULE
-
-/*
- * format is snd-usb-midi=snd_enable,snd_index,snd_id,
- *                        snd_vid,snd_pid,snd_int_transfer
- */
-static int __init snd_usbmidi_module_setup(char* str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str, &snd_enable[nr_dev]) == 2 &&
-	       get_option(&str, &snd_index[nr_dev]) == 2 &&
-	       get_id(&str, &snd_id[nr_dev]) == 2 &&
-	       get_option(&str, &snd_vid[nr_dev]) == 2 &&
-	       get_option(&str, &snd_pid[nr_dev]) == 2 &&
-	       get_option(&str, &snd_int_transfer[nr_dev]) == 2);
-	++nr_dev;
-	return 1;
-}
-
-__setup("snd-usb-midi=", snd_usbmidi_module_setup);
-
-#endif /* !MODULE */
diff -uP /dev/null usb/usbquirks.h
--- /dev/null	Thu Jan  1 01:00:00 1970
+++ usb/usbquirks.h	Mon Aug 26 15:48:15 2002
@@ -0,0 +1,337 @@
+/*
+ * ALSA USB Audio Driver
+ *
+ * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>,
+ *                       Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * The contents of this file are part of the driver's id_table.
+ *
+ * In a perfect world, this file would be empty.
+ */
+
+#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+
+{
+	/* from NetBSD's umidi driver */
+	USB_DEVICE(0x0499, 0x1000), /* Yamaha UX256 */
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0xffff,
+				.in_cables  = 0x00ff
+			}
+		}
+	}
+},
+{
+	/* from Nagano Daisuke's usb-midi driver */
+	USB_DEVICE(0x0499, 0x1001), /* Yamaha MU1000 */
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = 1,
+				.out_cables = 0x000f,
+				.in_cables  = 0x0001
+			}
+		}
+	}
+},
+/*
+ * 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
+ * standard for USB MIDI devices, so that device drivers would not be forced
+ * to know about the quirks of specific devices?"  So Roland went ahead and
+ * wrote the USB Device Class Definition for MIDI Devices, and the USB-IF
+ * endorsed it, and now everybody designing USB MIDI devices does so in
+ * agreement with this standard (or at least tries to).
+ *
+ * And if you prefer a happy end, you can imagine that Roland devices set a
+ * good example. Instead of being completely fucked up due to the lack of
+ * class-specific descriptors.
+ */
+{
+	USB_DEVICE(0x0582, 0x0000),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "UA-100",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0007,
+				.in_cables  = 0x0007
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0002),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-4",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x000f,
+				.in_cables  = 0x000f
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0003),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "SC-8850",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x003f,
+				.in_cables  = 0x003f
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0004),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "U-8",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0003,
+				.in_cables  = 0x0003
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0005),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-2",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0003,
+				.in_cables  = 0x0003
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0007),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "SC-8820",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0013,
+				.in_cables  = 0x0013
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0008),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "PC-300",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0001,
+				.in_cables  = 0x0001
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0009),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-1",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0001,
+				.in_cables  = 0x0001
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x000b),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "SK-500",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0013,
+				.in_cables  = 0x0013
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x000c),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "SC-D70",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0007,
+				.in_cables  = 0x0007
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0012),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Roland",
+		.product_name = "XV-5050",
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0001,
+				.in_cables  = 0x0001
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0014),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-880",
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x01ff,
+				.in_cables  = 0x01ff
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0016),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "SD-90",
+		.ifnum = 2,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x000f,
+				.in_cables  = 0x000f
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0023),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-550",
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x003f,
+				.in_cables  = 0x003f
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0027),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "SD-20",
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0003,
+				.in_cables  = 0x0007
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x0029),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "SD-80",
+		.ifnum = 0,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x000f,
+				.in_cables  = 0x000f
+			}
+		}
+	}
+},
+{
+	USB_DEVICE(0x0582, 0x002b),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "EDIROL",
+		.product_name = "UA-700",
+		.ifnum = 3,
+		.endpoints = {
+			{
+				.epnum = -1,
+				.out_cables = 0x0003,
+				.in_cables  = 0x0003
+			}
+		}
+	}
+},
+
+#endif /* CONFIG_SND_SEQUENCER(_MODULE) */


-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] integrate snd-usb-midi into snd-usb-audio
  2002-08-26 14:09 [PATCH] integrate snd-usb-midi into snd-usb-audio Clemens Ladisch
@ 2002-08-26 16:10 ` Takashi Iwai
  2002-08-26 17:03   ` Martin Langer
  2002-09-03 14:27   ` karsten wiese
  0 siblings, 2 replies; 5+ messages in thread
From: Takashi Iwai @ 2002-08-26 16:10 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, karsten wiese

Hi,

thanks.  the patch is applied now to cvs.
could you check whether it works for you?


Karsten, can you rewrite the patch for your tascam driver based on
this new mechanism?  if any other changes are needed, please let us
know.


Takashi


-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] integrate snd-usb-midi into snd-usb-audio
  2002-08-26 16:10 ` Takashi Iwai
@ 2002-08-26 17:03   ` Martin Langer
  2002-08-26 17:07     ` Takashi Iwai
  2002-09-03 14:27   ` karsten wiese
  1 sibling, 1 reply; 5+ messages in thread
From: Martin Langer @ 2002-08-26 17:03 UTC (permalink / raw)
  To: Takashi Iwai, alsa-devel, clemens

On Mon, Aug 26, 2002 at 06:10:33PM +0200, Takashi Iwai wrote:
> 
> could you check whether it works for you?
> 

My Evolution MK-249C works perfect! Both driver parts are loaded, only one
card is listed and sound is there. Wonderful. 


Thanks!
martin


-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] integrate snd-usb-midi into snd-usb-audio
  2002-08-26 17:03   ` Martin Langer
@ 2002-08-26 17:07     ` Takashi Iwai
  0 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2002-08-26 17:07 UTC (permalink / raw)
  To: martin-langer; +Cc: alsa-devel

At Mon, 26 Aug 2002 19:03:17 +0200,
Martin Langer wrote:
> 
> On Mon, Aug 26, 2002 at 06:10:33PM +0200, Takashi Iwai wrote:
> > 
> > could you check whether it works for you?
> > 
> 
> My Evolution MK-249C works perfect! Both driver parts are loaded, only one
> card is listed and sound is there. Wonderful. 

ok, then great kudo to Clemens!


Takashi


-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] integrate snd-usb-midi into snd-usb-audio
  2002-08-26 16:10 ` Takashi Iwai
  2002-08-26 17:03   ` Martin Langer
@ 2002-09-03 14:27   ` karsten wiese
  1 sibling, 0 replies; 5+ messages in thread
From: karsten wiese @ 2002-09-03 14:27 UTC (permalink / raw)
  To: tiwai, clemens; +Cc: alsa-devel, karsten wiese

 --- Takashi Iwai <tiwai@suse.de> schrieb: > Hi,
> 
> thanks.  the patch is applied now to cvs.
> could you check whether it works for you?
> 
> 
> Karsten, can you rewrite the patch for your tascam
> driver based on
> this new mechanism?  if any other changes are
> needed, please let us
> know.
> 
no changes needed. works well as it is now.
changed tascam driver available via email.
Tascam did not answer yet our calls to allow us the
use of their firmware.

proposal for autoloading snd-usb-midi from
snd-usb-audio if needed:

	request_module( "snd-usb-midi");

this way the tascam driver releaves the user from
taking care that snd-usb-midi is present.

Karsten

__________________________________________________________________

Gesendet von Yahoo! Mail - http://mail.yahoo.de
Möchten Sie mit einem Gruß antworten? http://grusskarten.yahoo.de


-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2002-09-03 14:27 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-08-26 14:09 [PATCH] integrate snd-usb-midi into snd-usb-audio Clemens Ladisch
2002-08-26 16:10 ` Takashi Iwai
2002-08-26 17:03   ` Martin Langer
2002-08-26 17:07     ` Takashi Iwai
2002-09-03 14:27   ` karsten wiese

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.