diff --git a/include/sound/version.h b/include/sound/version.h
index bafde4fbc0703666a53c198d16f6b66f3090b3fa..ba48af7a3099e9817ddc54bf028419f975cb793f 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #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)"
diff --git a/sound/core/info.c b/sound/core/info.c
index 750bf080115e9cc5554f4fd3bab9e05075fb630a..96dbae13331d91a509aa76b7287f51c7d925ba19 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -960,7 +960,6 @@ void snd_info_free_device(snd_info_entry_t * entry)
 {
 #ifdef CONFIG_DEVFS_FS
 	char dname[32];
-	devfs_handle_t master;
 #endif
 
 	snd_runtime_check(entry, return);
@@ -970,12 +969,7 @@ void snd_info_free_device(snd_info_entry_t * entry)
 #ifdef CONFIG_DEVFS_FS
 	if (entry->p && strncmp(entry->name, "controlC", 8)) {
 		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);
-#endif
 	}
 #endif
 	snd_info_free_entry(entry);
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 7fbf2bd70dfb4b21fbe4131667c9da600ad15b3e..6a7056336c57967de186a519dda740ba9e922a73 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -358,21 +358,12 @@ static int __init alsa_sound_init(void)
 static void __exit alsa_sound_exit(void)
 {
 #ifdef CONFIG_DEVFS_FS
-	devfs_handle_t master;
 	char controlname[24];
 	short controlnum;
 
 	for (controlnum = 0; controlnum < snd_cards_limit; 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);
-#endif
 	}
 #endif
 	
diff --git a/sound/pci/Config.in b/sound/pci/Config.in
index 4f7cb24ec97a579c7e90b80f6a26ccd242fe3247..e020e40443387a9a91aabd838d7e15a950f96bd1 100644
--- a/sound/pci/Config.in
+++ b/sound/pci/Config.in
@@ -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_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 '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 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $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
 dep_tristate 'ESS Allegro/Maestro3' CONFIG_SND_MAESTRO3 $CONFIG_SND
 dep_tristate 'ForteMedia FM801' CONFIG_SND_FM801 $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 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND
 
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index ac8cf40803ba0779d5f6a59b7a22bd572cb1a4c7..c2c120bc77940a1ce69dbdffd31f16a36562f375 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -1577,7 +1577,6 @@ int  cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
 int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
-	unsigned int flags;
 
 	/* turn on amplifier */
 	chip->active_ctrl(chip, 1);
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 4edfd66ced929c13e0b6aeec3957025c4419d9b6..28a6dfa0b5510c1ec9df4eb2a732c14fe4186c10 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -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_scb_descriptor_t * parent_scb;
-	unsigned int flags;
 
 	snd_assert (src->parent_scb_ptr == NULL,   return -EINVAL );
 	snd_assert(ins->master_mix_scb !=NULL,   return -EINVAL );
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 3fa15e955e195d7fbee9179ae74e52f471e70f02..728ffff4135fca72a5fdd699d4e05d8547a13244 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -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
  */
  
-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)
 	{
@@ -130,13 +130,12 @@ static void __sound_remove_unit(struct sound_unit **list, int unit)
 		if(p->unit_minor==unit)
 		{
 			*list=p->next;
-			devfs_unregister (p->de);
-			kfree(p);
-			return;
+			return p;
 		}
 		list=&(p->next);
 	}
 	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
  	
 static void sound_remove_unit(struct sound_unit **list, int unit)
 {
+	struct sound_unit *p;
+
 	spin_lock(&sound_loader_lock);
-	__sound_remove_unit(list, unit);
+	p = __sound_remove_unit(list, unit);
 	spin_unlock(&sound_loader_lock);
+	if (p) {
+		devfs_unregister (p->de);
+		kfree(p);
+	}
 }
 
 /*
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 67b4ffc6934e33004114ae815fbfe3b9faad6bfa..a71a1586543e990f6cc1df62ae0932d6341024e7 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -284,6 +284,16 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
 	urb->transfer_buffer = ctx->buf;
 	urb->transfer_buffer_length = offs;
 	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;
 }
 
@@ -305,8 +315,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
 
 	for (i = 0; i < urb->number_of_packets; i++) {
 		cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-		if (urb->iso_frame_desc[i].status) /* active? hmm, skip this */
-			continue;
+		if (urb->iso_frame_desc[i].status) {
+			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;
 		if (! len)
 			continue;
@@ -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 (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) {
+		int crate;
 		data[0] = runtime->rate;
 		data[1] = runtime->rate >> 8;
 		data[2] = runtime->rate >> 16;
@@ -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);
 			return err;
 		}
-		runtime->rate = data[0] | (data[1] << 8) | (data[2] << 16);
-		// printk("ok, getting back rate to %d\n", runtime->rate);
+		crate = data[0] | (data[1] << 8) | (data[2] << 16);
+		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 */
 	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
  * entry point for linux usb interface
  */
 
-#ifndef OLD_USB
+#ifdef OLD_USB
+static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
+			      const struct usb_device_id *id);
+static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
+#else
 static int usb_audio_probe(struct usb_interface *intf,
 			   const struct usb_device_id *id);
 static void usb_audio_disconnect(struct usb_interface *intf);
-#else
-static void * usb_audio_probe(usb_device *dev, unsigned int ifnum,
-			      const struct usb_device_id *id);
-static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
 #endif
 
 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
  * 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);
 
 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 &&
 		    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);
 				continue;
 			}
@@ -1871,7 +1888,8 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
 	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)
 {
 #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,
 	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->iface = iface;
+	umidi->ifnum = iface->altsetting->bInterfaceNumber;
 	umidi->quirk = quirk;
 	umidi->seq_client = -1;
 #endif
 	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)
 {
 	/* 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 **
  * only at the first time.  the successive calls of this function will
  * append the pcm interface to the corresponding card.
  */
-#ifndef OLD_USB
-static int usb_audio_probe(struct usb_interface *intf,
-			   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
+static void *snd_usb_audio_probe(struct usb_device *dev,
+				 struct usb_interface *intf,
+				 const struct usb_device_id *id)
 {
-#ifndef OLD_USB
-	struct usb_device *dev = interface_to_usbdev(intf);
-	int ifnum = intf->altsetting->bInterfaceNumber;
-#endif
 	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;
+	int i;
 	snd_card_t *card;
 	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;
 
 	if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
@@ -2078,11 +2089,6 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
 		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
 	 */
@@ -2124,12 +2130,24 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
 	}
 
 	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;
-		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;
+		}
+		kfree(buffer);
 	} else {
-		if (snd_usb_create_quirk(chip, ifnum, quirk) < 0)
+		/* USB midi interface */
+		if (snd_usb_create_quirk(chip, intf, quirk) < 0)
 			goto __error;
 	}
 
@@ -2142,38 +2160,20 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
 
 	chip->num_interfaces++;
 	up(&register_mutex);
-	kfree(buffer);
-#ifndef OLD_USB
-	return 0;
-#else
 	return chip;
-#endif
 
  __error:
 	up(&register_mutex);
-	kfree(buffer);
  __err_val:
-#ifndef OLD_USB
-	return -EIO;
-#else
 	return NULL;
-#endif
 }
 
-
 /*
  * we need to take care of counter, since disconnection can be called also
  * many times as well as usb_audio_probe(). 
  */
-#ifndef OLD_USB
-static void usb_audio_disconnect(struct usb_interface *intf)
-#else
-static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
-#endif
+static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
 {
-#ifndef OLD_USB
-	void *ptr = dev_get_drvdata(&intf->dev);
-#endif
 	snd_usb_audio_t *chip;
 
 	if (ptr == (void *)-1)
@@ -2185,6 +2185,49 @@ static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
 		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)
 {
 	usb_register(&usb_audio_driver);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index ae40a9b4ecd9fcfdf9c9eb69d34c7451cdd765fc..208033a871894f6a05353f08a303d74690ea33ef 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -58,6 +58,8 @@
 #define EP_GENERAL			0x01
 
 #define MS_GENERAL			0x01
+#define MIDI_IN_JACK			0x02
+#define MIDI_OUT_JACK			0x03
 
 /* endpoint attributes */
 #define EP_ATTR_MASK			0x0c
@@ -146,22 +148,34 @@ struct snd_usb_audio {
 /*
  * 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_midi_endpoint_info snd_usb_midi_endpoint_info_t;
 
 struct snd_usb_audio_quirk {
 	const char *vendor_name;
 	const char *product_name;
-	int ifnum;
+	int16_t ifnum;
+	int16_t type;
+	const void *data;
+};
 
-	/* 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];
+/* data for QUIRK_MIDI_FIXED_ENDPOINT */
+struct snd_usb_midi_endpoint_info {
+	int16_t epnum;		/* ep number, -1 autodetect */
+	uint16_t out_cables;	/* bitmask */
+	uint16_t in_cables;	/* bitmask */
 };
 
+/* for QUIRK_MIDI_YAMAHA, data is NULL */
+
+/* for QUIRK_MIDI_MIDIMAN, data is the number of ports */
+
 /*
  * USB MIDI sequencer device data
  */
@@ -173,6 +187,7 @@ 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;
+	struct usb_interface *iface;
 	int ifnum;
 	const snd_usb_audio_quirk_t *quirk;
 
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 98e5656a4b5262207336d3d83a42adf7b4aa179e..a0b54139e7c47b60dc92844baceddccd29dd91b6 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -4,6 +4,10 @@
  * Copyright (c) 2002 Clemens Ladisch
  * 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
  * modification, are permitted provided that the following conditions
  * are met:
@@ -120,6 +124,10 @@ struct snd_usb_midi_in_endpoint {
 
 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.
  */
@@ -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,
 				     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;
 	usbmidi_in_port_t* port = &ep->ports[cable];
 	snd_seq_event_t ev;
@@ -163,7 +168,7 @@ static void snd_usbmidi_input_packet(snd_usb_midi_in_endpoint_t* ep,
 		return;
 	memset(&ev, 0, sizeof(ev));
 	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.source.port = port->seq_port;
 		ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
@@ -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)
 {
 	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)
 	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
  * (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)
 	}
 
 	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;
 		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)
 	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
  * transfers for input.
@@ -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)
 		return NULL;
-	intf = local_usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
+	intf = umidi->iface;
 	if (!intf || intf->num_altsetting != 2)
 		return NULL;
 
@@ -528,6 +569,14 @@ static usb_endpoint_descriptor_t* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi,
 	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.
  * ALSA ports are created later.
@@ -551,7 +600,10 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
 	for (i = 0; i < 0x10; ++i)
 		ep->ports[i].seq_port = -1;
 
-	int_epd = snd_usbmidi_get_int_epd(umidi, ep_info->epnum);
+	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);
 
 	ep->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!ep->urb) {
@@ -696,73 +748,107 @@ static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
 	return 0;
 }
 
+/*
+ * Creates a sequencer port for an input/output cable pair.
+ */
+static int snd_usbmidi_create_port(snd_usb_midi_t* umidi,
+				   snd_usb_midi_out_endpoint_t* out_ep,
+				   snd_usb_midi_in_endpoint_t* in_ep,
+				   int cable, int port_idx)
+{
+	int cap, type, port;
+	snd_seq_port_callback_t port_callback;
+	char port_name[48];
+
+	cap = 0;
+	memset(&port_callback, 0, sizeof(port_callback));
+	port_callback.owner = THIS_MODULE;
+	if (out_ep) {
+		port_callback.event_input = snd_usbmidi_event_input;
+		port_callback.private_data = &out_ep->ports[cable];
+		cap |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
+	}
+	if (in_ep) {
+		cap |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
+	}
+	if (out_ep && in_ep) {
+		cap |= SNDRV_SEQ_PORT_CAP_DUPLEX;
+	}
+	/* TODO: read type bits from element descriptor */
+	type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
+	/* TODO: read port name from jack descriptor */
+	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);
+	if (port < 0) {
+		snd_printk(KERN_ERR "cannot create port (error code %d)\n", port);
+		return port;
+	}
+	if (in_ep)
+		in_ep->ports[cable].seq_port = port;
+	return port;
+}
+
+/*
+ * 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_virmidi_dev_t *rdev;
+	int err;
+
+	*rrmidi = NULL;
+	err = snd_virmidi_new(umidi->chip->card, port_idx, &rmidi);
+	if (err < 0)
+		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->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH;
+	rdev->client = umidi->seq_client;
+	rdev->port = port;
+	err = snd_device_register(umidi->chip->card, rmidi);
+	if (err < 0) {
+		snd_device_free(umidi->chip->card, rmidi);
+		return err;
+	}
+	*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, int ep, int* port_idx,
+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 c, err;
-	int cap, type, port;
-	int out, in;
-	snd_seq_port_callback_t port_callback;
-	char port_name[48];
+	int cable;
 
-	for (c = 0; c < 0x10; ++c) {
-		out = ep_info->out_cables & (1 << c);
-		in = ep_info->in_cables & (1 << c);
+	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;
-		cap = 0;
-		memset(&port_callback, 0, sizeof(port_callback));
-		port_callback.owner = THIS_MODULE;
-		if (out) {
-			port_callback.event_input = snd_usbmidi_event_input;
-			port_callback.private_data = &umidi->endpoints[ep].out->ports[c];
-			cap |= SNDRV_SEQ_PORT_CAP_WRITE |
-				SNDRV_SEQ_PORT_CAP_SUBS_WRITE;	
-		}
-		if (in) {
-			cap |= SNDRV_SEQ_PORT_CAP_READ |
-				SNDRV_SEQ_PORT_CAP_SUBS_READ;
-		}
-		if (out && in) {
-			cap |= SNDRV_SEQ_PORT_CAP_DUPLEX;
-		}
-		/* TODO: read type bits from element descriptor */
-		type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
-		/* TODO: read port name from jack descriptor */
-		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);
-		if (port < 0) {
-			snd_printk(KERN_ERR "cannot create port (error code %d)\n", port);
+
+		port = snd_usbmidi_create_port(umidi,
+					       out ? endpoint->out : NULL,
+					       in ? endpoint->in : NULL,
+					       cable, *port_idx);
+		if (port < 0)
 			return port;
-		}
-		if (in)
-			umidi->endpoints[ep].in->ports[c].seq_port = port;
 
 		if (*port_idx < SNDRV_MINOR_RAWMIDIS) {
-			snd_rawmidi_t *rmidi;
-			snd_virmidi_dev_t *rdev;
-			err = snd_virmidi_new(umidi->chip->card, *port_idx, &rmidi);
+			err = snd_usbmidi_create_virmidi(umidi, port, *port_idx,
+			      				 &endpoint->rmidi[cable]);
 			if (err < 0)
 				return err;
-			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->client = umidi->seq_client;
-			rdev->port = port;
-			err = snd_device_register(umidi->chip->card, rmidi);
-			if (err < 0) {
-				snd_device_free(umidi->chip->card, rmidi);
-				return err;
-			}
-			umidi->endpoints[ep].rmidi[c] = rmidi;
 		}
 		++*port_idx;
 	}
@@ -792,8 +878,8 @@ static int snd_usbmidi_create_endpoints(snd_usb_midi_t* umidi,
 			if (err < 0)
 				return err;
 		}
-		err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx,
-							&endpoints[i]);
+		err = snd_usbmidi_create_endpoint_ports(umidi, &umidi->endpoints[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",
@@ -817,9 +903,7 @@ static int snd_usbmidi_get_ms_info(snd_usb_midi_t* umidi,
 	usb_ms_endpoint_descriptor_t* ms_ep;
 	int i, epidx;
 
-	memset(endpoints, 0, sizeof(*endpoints) * MIDI_MAX_ENDPOINTS);
-
-	intf = local_usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
+	intf = umidi->iface;
 	if (!intf)
 		return -ENXIO;
 	intfd = &intf->altsetting[0];
@@ -878,7 +962,7 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
 	usb_endpoint_descriptor_t* epd;
 
 	if (endpoint->epnum == -1) {
-		intf = local_usb_ifnum_to_if(umidi->chip->dev, umidi->ifnum);
+		intf = umidi->iface;
 		if (!intf || intf->num_altsetting < 1)
 			return -ENOENT;
 		intfd = intf->altsetting;
@@ -890,6 +974,120 @@ static int snd_usbmidi_detect_endpoint(snd_usb_midi_t* umidi,
 	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.
  */
@@ -912,6 +1110,7 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
 	if (umidi->seq_client < 0)
 		return umidi->seq_client;
 
+	/* set the client name */
 	memset(&client_info, 0, sizeof(client_info));
 	client_info.client = umidi->seq_client;
 	client_info.type = KERNEL_CLIENT;
@@ -935,17 +1134,37 @@ static int snd_usbmidi_seq_device_new(snd_seq_device_t* seq_device)
 				  SNDRV_SEQ_IOCTL_SET_CLIENT_INFO,
 				  &client_info);
 
-	if (umidi->quirk) {
-		memcpy(endpoints, umidi->quirk->endpoints, sizeof(endpoints));
-		err = snd_usbmidi_detect_endpoint(umidi, &endpoints[0]);
-	} else {
+	/* detect the endpoint(s) to use */
+	memset(endpoints, 0, sizeof(endpoints));
+	if (!umidi->quirk) {
 		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) {
 		snd_usbmidi_seq_device_delete(seq_device);
 		return err;
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 74336ec8841d054c52dea98a88d6bc53d67e4f2d..87348c929f59dce507a288a5de48ab531aee2f42 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -26,45 +26,143 @@
  * 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)
 
+/* Yamaha devices */
 {
-	/* from NetBSD's umidi driver */
-	USB_DEVICE(0x0499, 0x1000), /* Yamaha UX256 */
+	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1000),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
-		.ifnum = 0,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0xffff,
-				.in_cables  = 0x00ff
-			}
-		}
+		.vendor_name = "Yamaha",
+		.product_name = "UX256",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_MIDI_YAMAHA
 	}
 },
 {
-	/* from Nagano Daisuke's usb-midi driver */
-	USB_DEVICE(0x0499, 0x1001), /* Yamaha MU1000 */
+	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1001),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
-		.ifnum = 0,
-		.endpoints = {
-			{
-				.epnum = 1,
-				.out_cables = 0x000f,
-				.in_cables  = 0x0001
-			}
-		}
+		.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
+	}
+},
+{
+	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1003),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Yamaha",
+		.product_name = "MU500",
+		.ifnum = QUIRK_ANY_INTERFACE,
+		.type = QUIRK_MIDI_YAMAHA
+	}
+},
+{
+	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
@@ -79,259 +177,316 @@
  * class-specific descriptors.
  */
 {
-	USB_DEVICE(0x0582, 0x0000),
+	USB_DEVICE_VENDOR_SPEC(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
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-4",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x000f,
-				.in_cables  = 0x000f
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "SC-8850",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x003f,
-				.in_cables  = 0x003f
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "U-8",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0003,
-				.in_cables  = 0x0003
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-2",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0003,
-				.in_cables  = 0x0003
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "SC-8820",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0013,
-				.in_cables  = 0x0013
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "PC-300",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0001,
-				.in_cables  = 0x0001
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-1",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0001,
-				.in_cables  = 0x0001
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "SK-500",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0013,
-				.in_cables  = 0x0013
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "SC-D70",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0007,
-				.in_cables  = 0x0007
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "Roland",
 		.product_name = "XV-5050",
 		.ifnum = 0,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0001,
-				.in_cables  = 0x0001
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-880",
 		.ifnum = 0,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x01ff,
-				.in_cables  = 0x01ff
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "SD-90",
 		.ifnum = 2,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x000f,
-				.in_cables  = 0x000f
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-550",
 		.ifnum = 0,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x003f,
-				.in_cables  = 0x003f
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "SD-20",
 		.ifnum = 0,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0003,
-				.in_cables  = 0x0007
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_cables = 0x0003,
+			.in_cables  = 0x0007
 		}
 	}
 },
 {
-	USB_DEVICE(0x0582, 0x0029),
+	USB_DEVICE_VENDOR_SPEC(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
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) {
 		.vendor_name = "EDIROL",
 		.product_name = "UA-700",
 		.ifnum = 3,
-		.endpoints = {
-			{
-				.epnum = -1,
-				.out_cables = 0x0003,
-				.in_cables  = 0x0003
-			}
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const snd_usb_midi_endpoint_info_t) {
+			.epnum = -1,
+			.out_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) */
+
+#undef USB_DEVICE_VENDOR_SPEC