You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================


ChangeSet@1.647, 2002-10-01 09:25:18+02:00, perex@suse.cz
  ALSA update 2002/08/14 :
    - added USB Audio and USB MIDI drivers
    - VIA686
      - AC97 cold reset only when AC-link is down


 include/sound/version.h |    2 
 sound/Makefile          |    2 
 sound/pci/via686.c      |   10 
 sound/usb/Config.help   |    5 
 sound/usb/Config.in     |    9 
 sound/usb/Makefile      |   12 
 sound/usb/usbaudio.c    | 2058 ++++++++++++++++++++++++++++++++++++++++++++++++
 sound/usb/usbaudio.h    |  150 +++
 sound/usb/usbmidi.c     | 1398 ++++++++++++++++++++++++++++++++
 sound/usb/usbmixer.c    | 1286 +++++++++++++++++++++++++++++
 10 files changed, 4930 insertions(+), 2 deletions(-)


diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Tue Oct  1 17:06:48 2002
+++ b/include/sound/version.h	Tue Oct  1 17:06:48 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc2"
-#define CONFIG_SND_DATE " (Tue Aug 13 16:29:18 2002 UTC)"
+#define CONFIG_SND_DATE " (Wed Aug 14 17:22:18 2002 UTC)"
diff -Nru a/sound/Makefile b/sound/Makefile
--- a/sound/Makefile	Tue Oct  1 17:06:48 2002
+++ b/sound/Makefile	Tue Oct  1 17:06:48 2002
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ sparc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c
--- a/sound/pci/via686.c	Tue Oct  1 17:06:48 2002
+++ b/sound/pci/via686.c	Tue Oct  1 17:06:48 2002
@@ -877,6 +877,16 @@
 		pci_write_config_byte(chip->pci, 0x41, 0xcc);
 		udelay(100);
 	}
+	
+	/* Make sure VRA is enabled, in case we didn't do a
+	 * complete codec reset, above */
+	pci_read_config_byte(chip->pci, 0x41, &pval);
+	if ((pval & 0xcc) != 0xcc) {
+		/* ACLink on, deassert ACLink reset, VSR, SGD data out */
+		/* note - FM data out has trouble with non VRA codecs !! */
+		pci_write_config_byte(chip->pci, 0x41, 0xcc);
+		udelay(100);
+	}
 
 	/* wait until codec ready */
 	max_count = ((3 * HZ) / 4) + 1;
diff -Nru a/sound/usb/Config.help b/sound/usb/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/Config.help	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,5 @@
+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.
diff -Nru a/sound/usb/Config.in b/sound/usb/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/Config.in	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,9 @@
+# ALSA USB drivers
+
+mainmenu_option next_comment
+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
diff -Nru a/sound/usb/Makefile b/sound/usb/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/Makefile	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,12 @@
+#
+# Makefile for ALSA
+#
+
+snd-usb-audio-objs := usbaudio.o usbmixer.o
+snd-usb-midi-objs := usbmidi.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o
+obj-$(CONFIG_SND_USB_MIDI) += snd-usb-midi.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/usbaudio.c	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,2058 @@
+/*
+ *   (Tentative) USB Audio Driver for ALSA
+ *
+ *   Main and PCM part
+ *
+ *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
+ *
+ *   Many codes borrowed from audio.c by 
+ *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
+ *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *
+ *   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
+ */
+
+
+#include <sound/driver.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+#include "usbaudio.h"
+
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("USB Audio");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Generic,USB Audio}}");
+
+
+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 */
+
+MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_index, "Index value for the USB audio adapter.");
+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 the USB audio adapter.");
+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 audio adapter.");
+MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+
+
+/*
+ *
+ */
+
+#define NRPACKS		4	/* 4ms per urb */
+#define MAX_URBS	5	/* max. 20ms long packets */
+#define SYNC_URBS	2	/* always two urbs for sync */
+#define MIN_PACKS_URB	1	/* minimum 1 packet per urb */
+
+typedef struct snd_usb_substream snd_usb_substream_t;
+typedef struct snd_usb_stream snd_usb_stream_t;
+typedef struct snd_urb_ctx snd_urb_ctx_t;
+
+struct audioformat {
+	struct list_head list;
+	snd_pcm_format_t format;	/* format type */
+	int channels;			/* # channels */
+	unsigned char altsetting;	/* corresponding alternate setting */
+	unsigned char altset_idx;	/* array index of altenate setting */
+	unsigned char attributes;	/* corresponding attributes of cs endpoint */
+	unsigned char endpoint;		/* endpoint */
+	unsigned char ep_attr;		/* endpoint attributes */
+	unsigned int rates;		/* rate bitmasks */
+	int rate_min, rate_max;		/* min/max rates */
+	int nr_rates;			/* number of rate table entries */
+	int *rate_table;		/* rate table */
+};
+
+struct snd_urb_ctx {
+	struct urb *urb;
+	snd_usb_substream_t *subs;
+	int index;	/* index for urb array */
+	int packets;	/* number of packets per urb */
+	int transfer;	/* transferred size */
+	char *buf;	/* buffer for capture */
+};
+
+struct snd_urb_ops {
+	int (*prepare)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u);
+	int (*retire)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u);
+	int (*prepare_sync)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u);
+	int (*retire_sync)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u);
+};
+
+struct snd_usb_substream {
+	snd_usb_stream_t *stream;
+	struct usb_device *dev;
+	snd_pcm_substream_t *pcm_substream;
+	int interface;           /* Interface number, -1 means not used */
+	unsigned int format;     /* USB data format */
+	unsigned int datapipe;   /* the data i/o pipe */
+	unsigned int syncpipe;   /* 1 - async out or adaptive in */
+	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
+	unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+	unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+	unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
+	unsigned int phase;      /* phase accumulator */
+	unsigned int maxpacksize;	/* max packet size in bytes */
+	unsigned int maxframesize;	/* max packet size in frames */
+	unsigned int curpacksize;	/* current packet size in bytes */
+	unsigned int curframesize;	/* current packet size in frames */
+	unsigned int fill_max: 1;	/* fill max packet size always */
+
+	unsigned int running: 1;	/* running status */
+
+	int hwptr;			/* free frame position in the buffer (only for playback) */
+	int hwptr_done;			/* processed frame position in the buffer */
+	int transfer_sched;		/* scheduled frames since last period (for playback) */
+	int transfer_done;		/* processed frames since last period update */
+	unsigned long active_mask;	/* bitmask of active urbs */
+	unsigned long unlink_mask;	/* bitmask of unlinked urbs */
+
+	int nurbs;			/* # urbs */
+	snd_urb_ctx_t dataurb[MAX_URBS];	/* data urb table */
+	snd_urb_ctx_t syncurb[SYNC_URBS];	/* sync urb table */
+	char syncbuf[SYNC_URBS * NRPACKS * 3]; /* sync buffer; it's so small - let's get static */
+	char *tmpbuf;			/* temporary buffer for playback */
+
+	u64 formats;			/* format bitmasks (all or'ed) */
+	int num_formats;		/* number of supported audio formats (list) */
+	struct list_head fmt_list;	/* format list */
+	spinlock_t lock;
+
+	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */
+};
+
+
+struct snd_usb_stream {
+	snd_usb_audio_t *chip;
+	snd_pcm_t *pcm;
+	int pcm_index;
+	snd_usb_substream_t substream[2];
+	struct list_head list;
+	snd_info_entry_t *proc_entry;
+};
+
+#define chip_t snd_usb_stream_t
+
+
+/*
+ * we keep the snd_usb_audio_t instances by ourselves for merging
+ * the all interfaces on the same card as one sound device.
+ */
+
+static DECLARE_MUTEX(register_mutex);
+static snd_usb_audio_t *usb_chip[SNDRV_CARDS];
+
+
+/*
+ * convert a sampling rate into USB format (fs/1000 in Q10.14)
+ * this will overflow at approx 2MSPS
+ */
+inline static unsigned get_usb_rate(unsigned int rate)
+{
+	return ((rate << 11) + 62) / 125;
+}
+
+
+/*
+ * prepare urb for capture sync pipe
+ *
+ * fill the length and offset of each urb descriptor.
+ * the fixed 10.14 frequency is passed through the pipe.
+ */
+static int prepare_capture_sync_urb(snd_usb_substream_t *subs,
+				    snd_pcm_runtime_t *runtime,
+				    struct urb *urb)
+{
+	unsigned char *cp = urb->transfer_buffer;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+	int i, offs;
+
+	urb->number_of_packets = ctx->packets;
+	urb->dev = ctx->subs->dev; /* we need to set this at each time */
+	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3, cp += 3) {
+		urb->iso_frame_desc[i].length = 3;
+		urb->iso_frame_desc[i].offset = offs;
+		cp[0] = subs->freqn;
+		cp[1] = subs->freqn >> 8;
+		cp[2] = subs->freqn >> 16;
+	}
+	urb->interval = 1;
+	return 0;
+}
+
+/*
+ * process after capture sync complete
+ * - nothing to do
+ */
+static int retire_capture_sync_urb(snd_usb_substream_t *subs,
+				   snd_pcm_runtime_t *runtime,
+				   struct urb *urb)
+{
+	return 0;
+}
+
+/*
+ * prepare urb for capture data pipe
+ *
+ * fill the offset and length of each descriptor.
+ *
+ * we use a temporary buffer to write the captured data.
+ * since the length of written data is determined by host, we cannot
+ * write onto the pcm buffer directly...  the data is thus copied
+ * later at complete callback to the global buffer.
+ */
+static int prepare_capture_urb(snd_usb_substream_t *subs,
+			       snd_pcm_runtime_t *runtime,
+			       struct urb *urb)
+{
+	int i, offs;
+	unsigned long flags;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+
+	offs = 0;
+	urb->dev = ctx->subs->dev; /* we need to set this at each time */
+	urb->number_of_packets = 0;
+	spin_lock_irqsave(&subs->lock, flags);
+	for (i = 0; i < ctx->packets; i++) {
+		urb->iso_frame_desc[i].offset = offs;
+		urb->iso_frame_desc[i].length = subs->curpacksize;
+		offs += subs->curpacksize;
+		urb->number_of_packets++;
+		subs->transfer_sched += subs->curframesize;
+		if (subs->transfer_sched >= runtime->period_size) {
+			subs->transfer_sched -= runtime->period_size;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&subs->lock, flags);
+	urb->transfer_buffer = ctx->buf;
+	urb->transfer_buffer_length = offs;
+	urb->interval = 1;
+	return 0;
+}
+
+/*
+ * process after capture complete
+ *
+ * copy the data from each desctiptor to the pcm buffer, and
+ * update the current position.
+ */
+static int retire_capture_urb(snd_usb_substream_t *subs,
+			      snd_pcm_runtime_t *runtime,
+			      struct urb *urb)
+{
+	unsigned long flags;
+	unsigned char *cp;
+	int stride, i, len, oldptr;
+
+	stride = runtime->frame_bits >> 3;
+
+	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;
+		len = urb->iso_frame_desc[i].actual_length / stride;
+		if (! len)
+			continue;
+		/* update the current pointer */
+		spin_lock_irqsave(&subs->lock, flags);
+		oldptr = subs->hwptr_done;
+		subs->hwptr_done += len;
+		if (subs->hwptr_done >= runtime->buffer_size)
+			subs->hwptr_done -= runtime->buffer_size;
+		subs->transfer_done += len;
+		spin_unlock_irqrestore(&subs->lock, flags);
+		/* copy a data chunk */
+		if (oldptr + len > runtime->buffer_size) {
+			int cnt = runtime->buffer_size - oldptr;
+			int blen = cnt * stride;
+			memcpy(runtime->dma_area + oldptr * stride, cp, blen);
+			memcpy(runtime->dma_area, cp + blen, len * stride - blen);
+		} else {
+			memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
+		}
+		/* update the pointer, call callback if necessary */
+		spin_lock_irqsave(&subs->lock, flags);
+		if (subs->transfer_done >= runtime->period_size) {
+			subs->transfer_done -= runtime->period_size;
+			spin_unlock_irqrestore(&subs->lock, flags);
+			snd_pcm_period_elapsed(subs->pcm_substream);
+		} else
+			spin_unlock_irqrestore(&subs->lock, flags);
+	}
+	return 0;
+}
+
+
+/*
+ * prepare urb for playback sync pipe
+ *
+ * set up the offset and length to receive the current frequency.
+ */
+
+static int prepare_playback_sync_urb(snd_usb_substream_t *subs,
+				     snd_pcm_runtime_t *runtime,
+				     struct urb *urb)
+{
+	int i, offs;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+
+	urb->number_of_packets = ctx->packets;
+	urb->dev = ctx->subs->dev; /* we need to set this at each time */
+	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3) {
+		urb->iso_frame_desc[i].length = 3;
+		urb->iso_frame_desc[i].offset = offs;
+	}
+	return 0;
+}
+
+/*
+ * process after playback sync complete
+ *
+ * retrieve the current 10.14 frequency from pipe, and set it.
+ * the value is referred in prepare_playback_urb().
+ */
+static int retire_playback_sync_urb(snd_usb_substream_t *subs,
+				    snd_pcm_runtime_t *runtime,
+				    struct urb *urb)
+{
+	unsigned int f, i, found;
+	unsigned char *cp = urb->transfer_buffer;
+	unsigned long flags;
+
+	found = 0;
+	for (i = 0; i < urb->number_of_packets; i++, cp += 3) {
+		if (urb->iso_frame_desc[i].status ||
+		    urb->iso_frame_desc[i].actual_length < 3)
+			continue;
+		f = combine_triple(cp);
+		if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) {
+			snd_printd(KERN_WARNING "requested frequency %u (nominal %u) out of range!\n", f, subs->freqn);
+			continue;
+		}
+		found = f;
+	}
+	if (found) {
+		spin_lock_irqsave(&subs->lock, flags);
+		subs->freqm = found;
+		spin_unlock_irqrestore(&subs->lock, flags);
+	}
+
+	return 0;
+}
+
+/*
+ * prepare urb for playback data pipe
+ *
+ * we copy the data directly from the pcm buffer.
+ * the current position to be copied is held in hwptr field.
+ * since a urb can handle only a single linear buffer, if the total
+ * transferred area overflows the buffer boundary, we cannot send
+ * it directly from the buffer.  thus the data is once copied to
+ * a temporary buffer and urb points to that.
+ */
+static int prepare_playback_urb(snd_usb_substream_t *subs,
+				snd_pcm_runtime_t *runtime,
+				struct urb *urb)
+{
+	int i, stride, offs;
+	int counts;
+	unsigned long flags;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+
+	stride = runtime->frame_bits >> 3;
+
+	offs = 0;
+	urb->dev = ctx->subs->dev; /* we need to set this at each time */
+	urb->number_of_packets = 0;
+	spin_lock_irqsave(&subs->lock, flags);
+	for (i = 0; i < ctx->packets; i++) {
+		/* calculate the size of a packet */
+		if (subs->fill_max)
+			counts = subs->maxframesize; /* fixed */
+		else {
+			subs->phase = (subs->phase & 0x3fff) + subs->freqm;
+			counts = subs->phase >> 14;
+			if (counts > subs->maxframesize)
+				counts = subs->maxframesize;
+		}
+		/* set up descriptor */
+		urb->iso_frame_desc[i].offset = offs * stride;
+		urb->iso_frame_desc[i].length = counts * stride;
+		offs += counts;
+		urb->number_of_packets++;
+		subs->transfer_sched += counts;
+		if (subs->transfer_sched >= runtime->period_size) {
+			subs->transfer_sched -= runtime->period_size;
+			break;
+ 		}
+	}
+	if (subs->hwptr + offs > runtime->buffer_size) {
+		/* err, the transferred area goes over buffer boundary.
+		 * copy the data to the temp buffer.
+		 */
+		int len;
+		len = runtime->buffer_size - subs->hwptr;
+		urb->transfer_buffer = subs->tmpbuf;
+		memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride);
+		memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride);
+		subs->hwptr += offs;
+		subs->hwptr -= runtime->buffer_size;
+	} else {
+		/* set the buffer pointer */
+		urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
+		subs->hwptr += offs;
+	}
+	spin_unlock_irqrestore(&subs->lock, flags);
+	urb->transfer_buffer_length = offs * stride;
+	ctx->transfer = offs;
+
+	return 0;
+}
+
+/*
+ * process after playback data complete
+ *
+ * update the current position and call callback if a period is processed.
+ */
+static int retire_playback_urb(snd_usb_substream_t *subs,
+			       snd_pcm_runtime_t *runtime,
+			       struct urb *urb)
+{
+	unsigned long flags;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+
+	spin_lock_irqsave(&subs->lock, flags);
+	subs->transfer_done += ctx->transfer;
+	subs->hwptr_done += ctx->transfer;
+	ctx->transfer = 0;
+	if (subs->hwptr_done >= runtime->buffer_size)
+		subs->hwptr_done -= runtime->buffer_size;
+	if (subs->transfer_done >= runtime->period_size) {
+		subs->transfer_done -= runtime->period_size;
+		spin_unlock_irqrestore(&subs->lock, flags);
+		snd_pcm_period_elapsed(subs->pcm_substream);
+	} else
+		spin_unlock_irqrestore(&subs->lock, flags);
+	return 0;
+}
+
+
+/*
+ * complete callback from data urb
+ */
+static void snd_complete_urb(struct urb *urb)
+{
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+	snd_usb_substream_t *subs = ctx->subs;
+	snd_pcm_substream_t *substream = ctx->subs->pcm_substream;
+	int err;
+
+	clear_bit(ctx->index, &subs->active_mask);
+	if (subs->running && subs->ops.retire(subs, substream->runtime, urb))
+		return;
+	if (! subs->running) /* can be stopped during retire callback */
+		return;
+	if ((err = subs->ops.prepare(subs, substream->runtime, urb) < 0) ||
+	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+		return;
+	}
+	set_bit(ctx->index, &subs->active_mask);
+}
+
+
+/*
+ * complete callback from sync urb
+ */
+static void snd_complete_sync_urb(struct urb *urb)
+{
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+	snd_usb_substream_t *subs = ctx->subs;
+	snd_pcm_substream_t *substream = ctx->subs->pcm_substream;
+	int err;
+
+	clear_bit(ctx->index + 16, &subs->active_mask);
+	if (subs->running && subs->ops.retire_sync(subs, substream->runtime, urb))
+		return;
+	if (! subs->running) /* can be stopped during retire callback */
+		return;
+	if ((err = subs->ops.prepare_sync(subs, substream->runtime, urb))  < 0 ||
+	    (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+		return;
+	}
+	set_bit(ctx->index + 16, &subs->active_mask);
+}
+
+
+/*
+ * unlink active urbs.
+ * return the number of active urbs.
+ */
+static int deactivate_urbs(snd_usb_substream_t *subs)
+{
+	int i, alive;
+
+	subs->running = 0;
+
+	alive = 0;
+	for (i = 0; i < subs->nurbs; i++) {
+		if (test_bit(i, &subs->active_mask)) {
+			alive++;
+			if (! test_and_set_bit(i, &subs->unlink_mask))
+				usb_unlink_urb(subs->dataurb[i].urb);
+		}
+	}
+	if (subs->syncpipe) {
+		for (i = 0; i < SYNC_URBS; i++) {
+			if (test_bit(i+16, &subs->active_mask)) {
+				alive++;
+ 				if (! test_and_set_bit(i+16, &subs->unlink_mask))
+					usb_unlink_urb(subs->syncurb[i].urb);
+			}
+		}
+	}
+	return alive;
+}
+
+
+/*
+ * set up and start data/sync urbs
+ */
+static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+{
+	int i, err;
+
+	for (i = 0; i < subs->nurbs; i++) {
+		snd_assert(subs->dataurb[i].urb, return -EINVAL);
+		if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
+			snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
+			goto __error;
+		}
+	}
+	if (subs->syncpipe) {
+		for (i = 0; i < SYNC_URBS; i++) {
+			snd_assert(subs->syncurb[i].urb, return -EINVAL);
+			if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
+				snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
+				goto __error;
+			}
+		}
+	}
+
+	subs->running = 1;
+	for (i = 0; i < subs->nurbs; i++) {
+		if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_KERNEL)) < 0) {
+			snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+			goto __error;
+		}
+		set_bit(i, &subs->active_mask);
+	}
+	if (subs->syncpipe) {
+		for (i = 0; i < SYNC_URBS; i++) {
+			if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_KERNEL)) < 0) {
+				snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err);
+				goto __error;
+			}
+			set_bit(i + 16, &subs->active_mask);
+		}
+	}
+	return 0;
+
+ __error:
+	// snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
+	deactivate_urbs(subs);
+	return -EPIPE;
+}
+
+
+/* 
+ *  wait until all urbs are processed.
+ */
+static int wait_clear_urbs(snd_usb_substream_t *subs)
+{
+	int timeout = HZ;
+	int i, alive;
+
+	do {
+		alive = 0;
+		for (i = 0; i < subs->nurbs; i++) {
+			if (test_bit(i, &subs->active_mask))
+				alive++;
+		}
+		if (subs->syncpipe) {
+			for (i = 0; i < SYNC_URBS; i++) {
+				if (test_bit(i + 16, &subs->active_mask))
+					alive++;
+			}
+		}
+		if (! alive)
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		set_current_state(TASK_RUNNING);
+	} while (--timeout > 0);
+	if (alive)
+		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+	return 0;
+}
+
+
+/*
+ * return the current pcm pointer.  just return the hwptr_done value.
+ */
+static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream)
+{
+	snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
+	return subs->hwptr_done;
+}
+
+
+/*
+ * start/stop substream
+ */
+static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
+	int err;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = start_urbs(subs, substream->runtime);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err = deactivate_urbs(subs);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err < 0 ? err : 0;
+}
+
+
+/*
+ * release a urb data
+ */
+static void release_urb_ctx(snd_urb_ctx_t *u)
+{
+	if (u->urb) {
+		usb_free_urb(u->urb);
+		u->urb = 0;
+	}
+	if (u->buf) {
+		kfree(u->buf);
+		u->buf = 0;
+	}
+}
+
+/*
+ * release a substream
+ */
+static void release_substream_urbs(snd_usb_substream_t *subs)
+{
+	int i;
+
+	/* stop urbs (to be sure) */
+	if (deactivate_urbs(subs) > 0)
+		wait_clear_urbs(subs);
+
+	for (i = 0; i < MAX_URBS; i++)
+		release_urb_ctx(&subs->dataurb[i]);
+	for (i = 0; i < SYNC_URBS; i++)
+		release_urb_ctx(&subs->syncurb[i]);
+	if (subs->tmpbuf) {
+		kfree(subs->tmpbuf);
+		subs->tmpbuf = 0;
+	}
+	subs->nurbs = 0;
+}
+
+/*
+ * initialize a substream for plaback/capture
+ */
+static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+{
+	int maxsize, n, i;
+	int is_playback = subs->pcm_substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int npacks[MAX_URBS], total_packs;
+
+	/* calculate the frequency in 10.14 format */
+	subs->freqn = subs->freqm = get_usb_rate(runtime->rate);
+	subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
+	subs->phase = 0;
+
+	/* reset the pointer */
+	subs->hwptr = 0;
+	subs->hwptr_done = 0;
+	subs->transfer_sched = 0;
+	subs->transfer_done = 0;
+	subs->active_mask = 0;
+	subs->unlink_mask = 0;
+
+	/* calculate the max. size of packet */
+	maxsize = ((subs->freqmax + 0x3fff) * (runtime->frame_bits >> 3)) >> 14;
+	if (subs->maxpacksize && maxsize > subs->maxpacksize) {
+		//snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
+		//	   maxsize, subs->maxpacksize);
+		maxsize = subs->maxpacksize;
+	}
+
+	if (subs->fill_max)
+		subs->curpacksize = subs->maxpacksize;
+	else
+		subs->curpacksize = maxsize;
+
+	/* allocate a temporary buffer for playback */
+	if (is_playback) {
+		subs->tmpbuf = kmalloc(maxsize * NRPACKS, GFP_KERNEL);
+		if (! subs->tmpbuf) {
+			snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* decide how many packets to be used */
+	total_packs = (frames_to_bytes(runtime, runtime->period_size) + maxsize - 1) / maxsize;
+	if (total_packs < 2 * MIN_PACKS_URB)
+		total_packs = 2 * MIN_PACKS_URB;
+	subs->nurbs = (total_packs + NRPACKS - 1) / NRPACKS;
+	if (subs->nurbs > MAX_URBS) {
+		/* too much... */
+		subs->nurbs = MAX_URBS;
+		total_packs = MAX_URBS * NRPACKS;
+	}
+	n = total_packs;
+	for (i = 0; i < subs->nurbs; i++) {
+		npacks[i] = n > NRPACKS ? NRPACKS : n;
+		n -= NRPACKS;
+	}
+	if (subs->nurbs <= 1) {
+		/* too little - we need at least two packets
+		 * to ensure contiguous playback/capture
+		 */
+		subs->nurbs = 2;
+		npacks[0] = (total_packs + 1) / 2;
+		npacks[1] = total_packs - npacks[0];
+	} else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) {
+		/* the last packet is too small.. */
+		if (subs->nurbs > 2) {
+			/* merge to the first one */
+			npacks[0] += npacks[subs->nurbs - 1];
+			subs->nurbs--;
+		} else {
+			/* divide to two */
+			subs->nurbs = 2;
+			npacks[0] = (total_packs + 1) / 2;
+			npacks[1] = total_packs - npacks[0];
+		}
+	}
+
+	/* allocate and initialize data urbs */
+	for (i = 0; i < subs->nurbs; i++) {
+		snd_urb_ctx_t *u = &subs->dataurb[i];
+		u->index = i;
+		u->subs = subs;
+		u->transfer = 0;
+		u->packets = npacks[i];
+		if (! is_playback) {
+			/* allocate a capture buffer per urb */
+			u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
+			if (! u->buf) {
+				release_substream_urbs(subs);
+				return -ENOMEM;
+			}
+		}
+		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
+		if (! u->urb) {
+			release_substream_urbs(subs);
+			return -ENOMEM;
+		}
+		u->urb->dev = subs->dev;
+		u->urb->pipe = subs->datapipe;
+		u->urb->transfer_flags = USB_ISO_ASAP | USB_ASYNC_UNLINK;
+		u->urb->number_of_packets = u->packets;
+		u->urb->context = u;
+		u->urb->complete = snd_complete_urb;
+	}
+
+	if (subs->syncpipe) {
+		/* allocate and initialize sync urbs */
+		for (i = 0; i < SYNC_URBS; i++) {
+			snd_urb_ctx_t *u = &subs->syncurb[i];
+			u->index = i;
+			u->subs = subs;
+			u->packets = NRPACKS;
+			u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
+			if (! u->urb) {
+				release_substream_urbs(subs);
+				return -ENOMEM;
+			}
+			u->urb->transfer_buffer = subs->syncbuf + i * NRPACKS * 3;
+			u->urb->transfer_buffer_length = NRPACKS * 3;
+			u->urb->dev = subs->dev;
+			u->urb->pipe = subs->syncpipe;
+			u->urb->transfer_flags = USB_ISO_ASAP | USB_ASYNC_UNLINK;
+			u->urb->number_of_packets = u->packets;
+			u->urb->context = u;
+			u->urb->complete = snd_complete_sync_urb;
+		}
+	}
+	return 0;
+}
+
+
+/*
+ * find a matching audio format
+ */
+static struct audioformat *find_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+{
+	struct list_head *p;
+
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *fp;
+		fp = list_entry(p, struct audioformat, list);
+		if (fp->format != runtime->format ||
+		    fp->channels != runtime->channels)
+			continue;
+		if (runtime->rate < fp->rate_min || runtime->rate > fp->rate_max)
+			continue;
+		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
+			return fp;
+		else {
+			int i;
+			for (i = 0; i < fp->nr_rates; i++)
+				if (fp->rate_table[i] == runtime->rate)
+					return fp;
+		}
+	}
+	return NULL;
+}
+
+
+/*
+ * find a matching format and set up the interface
+ */
+static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+{
+	struct usb_device *dev = subs->dev;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface_descriptor *alts;
+	struct usb_interface *iface;	
+	struct audioformat *fmt;
+	unsigned int ep, attr;
+	unsigned char data[3];
+	int is_playback = subs->pcm_substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int err;
+
+	fmt = find_format(subs, runtime);
+	if (! fmt) {
+		snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
+			   snd_pcm_format_name(runtime->format), runtime->rate, runtime->channels);
+		return -EINVAL;
+	}
+
+	iface = &config->interface[subs->interface];
+	alts = &iface->altsetting[fmt->altset_idx];
+	snd_assert(alts->bAlternateSetting == fmt->altsetting, return -EINVAL);
+
+	/* create a data pipe */
+	ep = alts->endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	if (is_playback)
+		subs->datapipe = usb_sndisocpipe(dev, ep);
+	else
+		subs->datapipe = usb_rcvisocpipe(dev, ep);
+	subs->format = fmt->altset_idx;
+	subs->syncpipe = subs->syncinterval = 0;
+	subs->maxpacksize = alts->endpoint[0].wMaxPacketSize;
+	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
+	subs->fill_max = 0;
+
+	/* we need a sync pipe in async OUT or adaptive IN mode */
+	attr = alts->endpoint[0].bmAttributes & EP_ATTR_MASK;
+	if ((is_playback && attr == EP_ATTR_ASYNC) ||
+	    (! is_playback && attr == EP_ATTR_ADAPTIVE)) {
+		/* check endpoint */
+		if (alts->bNumEndpoints < 2 ||
+		    alts->endpoint[1].bmAttributes != 0x01 ||
+		    alts->endpoint[1].bSynchAddress != 0) {
+			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
+				   dev->devnum, subs->interface, fmt->altsetting);
+			return -EINVAL;
+		}
+		ep = alts->endpoint[1].bEndpointAddress;
+		if ((is_playback && ep != (alts->endpoint[0].bSynchAddress | USB_DIR_IN)) ||
+		    (! is_playback && ep != (alts->endpoint[0].bSynchAddress & ~USB_DIR_IN))) {
+			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
+				   dev->devnum, subs->interface, fmt->altsetting);
+			return -EINVAL;
+		}
+		ep &= USB_ENDPOINT_NUMBER_MASK;
+		if (is_playback)
+			subs->syncpipe = usb_rcvisocpipe(dev, ep);
+		else
+			subs->syncpipe = usb_sndisocpipe(dev, ep);
+		subs->syncinterval = alts->endpoint[1].bRefresh;
+	}
+
+	/* set interface */
+	if (usb_set_interface(dev, subs->interface, fmt->altset_idx) < 0) {
+		snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
+			   dev->devnum, subs->interface, fmt->altsetting);
+		return -EIO;
+	}
+
+	ep = usb_pipeendpoint(subs->datapipe) | (subs->datapipe & USB_DIR_IN);
+	/* if endpoint has pitch control, enable it */
+	if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) {
+		data[0] = 1;
+		if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+			snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
+				   dev->devnum, subs->interface, ep);
+			return err;
+		}
+	}
+	/* if endpoint has sampling rate control, set it */
+	if (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) {
+		data[0] = runtime->rate;
+		data[1] = runtime->rate >> 8;
+		data[2] = runtime->rate >> 16;
+		if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+			snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
+				   dev->devnum, subs->interface, fmt->altsetting, runtime->rate, ep);
+			return err;
+		}
+		if ((err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
+					   USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+			snd_printk(KERN_ERR "%d:%d:%d: cannot get freq at ep 0x%x\n",
+				   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);
+	}
+	/* always fill max packet size */
+	if (fmt->attributes & EP_CS_ATTR_FILL_MAX)
+		subs->fill_max = 1;
+
+#if 0
+	printk("setting done: format = %d, rate = %d, channels = %d\n",
+	       runtime->format, runtime->rate, runtime->channels);
+	printk("  datapipe = 0x%0x, syncpipe = 0x%0x\n",
+	       subs->datapipe, subs->syncpipe);
+#endif
+
+	return 0;
+}
+
+/*
+ * allocate a buffer.
+ *
+ * so far we use a physically linear buffer although packetize transfer
+ * doesn't need a continuous area.
+ * if sg buffer is supported on the later version of alsa, we'll follow
+ * that.
+ */
+static int snd_usb_hw_params(snd_pcm_substream_t *substream,
+			     snd_pcm_hw_params_t *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+/*
+ * free the buffer
+ */
+static int snd_usb_hw_free(snd_pcm_substream_t *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ * prepare callback
+ *
+ * set format and initialize urbs
+ */
+static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data;
+	int err;
+
+	release_substream_urbs(subs);
+	if ((err = set_format(subs, runtime)) < 0)
+		return err;
+
+	return init_substream_urbs(subs, runtime);
+}
+
+static snd_pcm_hardware_t snd_usb_playback =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.buffer_bytes_max =	(128*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(128*1024),
+	.periods_min =		2,
+	.periods_max =		1024,
+};
+
+static snd_pcm_hardware_t snd_usb_capture =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.buffer_bytes_max =	(128*1024),
+	.period_bytes_min =	64,
+	.period_bytes_max =	(128*1024),
+	.periods_min =		2,
+	.periods_max =		1024,
+};
+
+/*
+ * set up the runtime hardware information.
+ */
+
+static void setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
+{
+	struct list_head *p;
+
+	runtime->hw.formats = subs->formats;
+
+	runtime->hw.rate_min = 0x7fffffff;
+	runtime->hw.rate_max = 0;
+	runtime->hw.channels_min = 256;
+	runtime->hw.channels_max = 0;
+	runtime->hw.rates = 0;
+	/* check min/max rates and channels */
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *fp;
+		fp = list_entry(p, struct audioformat, list);
+		runtime->hw.rates |= fp->rates;
+		if (runtime->hw.rate_min > fp->rate_min)
+			runtime->hw.rate_min = fp->rate_min;
+		if (runtime->hw.rate_max < fp->rate_max)
+			runtime->hw.rate_max = fp->rate_max;
+		if (runtime->hw.channels_min > fp->channels)
+			runtime->hw.channels_min = fp->channels;
+		if (runtime->hw.channels_max < fp->channels)
+			runtime->hw.channels_max = fp->channels;
+	}
+
+	/* set the period time minimum 1ms */
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+				     1000 * MIN_PACKS_URB,
+				     /*(NRPACKS * MAX_URBS) * 1000*/ UINT_MAX);
+
+	/* FIXME: we need more constraints to restrict the format type,
+	 * channels and rates according to the audioformat list!
+	 */
+}
+
+static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction,
+			    snd_pcm_hardware_t *hw)
+{
+	snd_usb_stream_t *as = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_usb_substream_t *subs = &as->substream[direction];
+
+	runtime->hw = *hw;
+	runtime->private_data = subs;
+	subs->pcm_substream = substream;
+	setup_hw_info(runtime, subs);
+
+	return 0;
+}
+
+static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction)
+{
+	snd_usb_stream_t *as = snd_pcm_substream_chip(substream);
+	snd_usb_substream_t *subs = &as->substream[direction];
+	release_substream_urbs(subs);
+	usb_set_interface(subs->dev, subs->interface, 0);
+	subs->pcm_substream = NULL;
+	return 0;
+}
+
+static int snd_usb_playback_open(snd_pcm_substream_t *substream)
+{
+	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback);
+}
+
+static int snd_usb_playback_close(snd_pcm_substream_t *substream)
+{
+	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static int snd_usb_capture_open(snd_pcm_substream_t *substream)
+{
+	return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture);
+}
+
+static int snd_usb_capture_close(snd_pcm_substream_t *substream)
+{
+	return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static snd_pcm_ops_t snd_usb_playback_ops = {
+	.open =		snd_usb_playback_open,
+	.close =	snd_usb_playback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_usb_hw_params,
+	.hw_free =	snd_usb_hw_free,
+	.prepare =	snd_usb_pcm_prepare,
+	.trigger =	snd_usb_pcm_trigger,
+	.pointer =	snd_usb_pcm_pointer,
+};
+
+static snd_pcm_ops_t snd_usb_capture_ops = {
+	.open =		snd_usb_capture_open,
+	.close =	snd_usb_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_usb_hw_params,
+	.hw_free =	snd_usb_hw_free,
+	.prepare =	snd_usb_pcm_prepare,
+	.trigger =	snd_usb_pcm_trigger,
+	.pointer =	snd_usb_pcm_pointer,
+};
+
+
+
+/*
+ * helper functions
+ */
+
+/*
+ * combine bytes and get an integer value
+ */
+unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size)
+{
+	switch (size) {
+	case 1:  return *bytes;
+	case 2:  return combine_word(bytes);
+	case 3:  return combine_triple(bytes);
+	case 4:  return combine_quad(bytes);
+	default: return 0;
+	}
+}
+
+/*
+ * parse descriptor buffer and return the pointer starting the given
+ * descriptor type and interface.
+ * if altsetting is not -1, seek the buffer until the matching alternate
+ * setting is found.
+ */
+void *snd_usb_find_desc(void *descstart, int desclen, void *after, 
+			u8 dtype, int iface, int altsetting)
+{
+	u8 *p, *end, *next;
+	int ifc = -1, as = -1;
+
+	p = descstart;
+	end = p + desclen;
+	for (; p < end;) {
+		if (p[0] < 2)
+			return NULL;
+		next = p + p[0];
+		if (next > end)
+			return NULL;
+		if (p[1] == USB_DT_INTERFACE) {
+			/* minimum length of interface descriptor */
+			if (p[0] < 9)
+				return NULL;
+			ifc = p[2];
+			as = p[3];
+		}
+		if (p[1] == dtype && (!after || (void *)p > after) &&
+		    (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
+			return p;
+		}
+		p = next;
+	}
+	return NULL;
+}
+
+/*
+ * find a class-specified interface descriptor with the given subtype.
+ */
+void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype, int iface, int altsetting)
+{
+	unsigned char *p = after;
+
+	while ((p = snd_usb_find_desc(buffer, buflen, p,
+				      USB_DT_CS_INTERFACE, iface, altsetting)) != NULL) {
+		if (p[0] >= 3 && p[2] == dsubtype)
+			return p;
+	}
+	return NULL;
+}
+
+
+/*
+ * entry point for linux usb interface
+ */
+
+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);
+
+static struct usb_device_id usb_audio_ids [] = {
+    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
+      .bInterfaceClass = USB_CLASS_AUDIO,
+      .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL },
+    { }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_audio_ids);
+
+static struct usb_driver usb_audio_driver = {
+	.name =		"snd-usb-audio",
+	.probe =	usb_audio_probe,
+	.disconnect =	usb_audio_disconnect,
+	.driver_list =	LIST_HEAD_INIT(usb_audio_driver.driver_list), 
+	.id_table =	usb_audio_ids,
+};
+
+
+/*
+ * intialize the substream instance.
+ */
+
+static void init_substream(snd_usb_stream_t *stream, snd_usb_substream_t *subs,
+			   int iface_no, int is_input,
+			   unsigned char *buffer, int buflen)
+{
+	struct usb_device *dev;
+	struct usb_config_descriptor *config;
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *alts;
+	int i, pcm_format, altno;
+	int format, channels, format_type, nr_rates;
+	struct audioformat *fp;
+	unsigned char *fmt, *csep;
+
+	dev = stream->chip->dev;
+	config = dev->actconfig;
+
+	subs->stream = stream;
+	subs->dev = dev;
+	subs->interface = iface_no;
+	INIT_LIST_HEAD(&subs->fmt_list);
+	spin_lock_init(&subs->lock);
+	if (is_input) {
+		subs->ops.prepare = prepare_capture_urb;
+		subs->ops.retire = retire_capture_urb;
+		subs->ops.prepare_sync = prepare_capture_sync_urb;
+		subs->ops.retire_sync = retire_capture_sync_urb;
+	} else {
+		subs->ops.prepare = prepare_playback_urb;
+		subs->ops.retire = retire_playback_urb;
+		subs->ops.prepare_sync = prepare_playback_sync_urb;
+		subs->ops.retire_sync = retire_playback_sync_urb;
+	}
+
+	if (iface_no < 0)
+		return;
+
+	/* parse the interface's altsettings */
+	iface = &config->interface[iface_no];
+	for (i = 0; i < iface->num_altsetting; i++) {
+		alts = &iface->altsetting[i];
+		/* skip invalid one */
+		if (alts->bInterfaceClass != USB_CLASS_AUDIO ||
+		    alts->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING ||
+		    alts->bNumEndpoints < 1)
+			continue;
+		/* must be isochronous */
+		if ((alts->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+		    USB_ENDPOINT_XFER_ISOC)
+			continue;
+		/* check direction */
+		if (alts->endpoint[0].bEndpointAddress & USB_DIR_IN) {
+			if (! is_input)
+				continue;
+		} else {
+			if (is_input)
+				continue;
+		}
+
+		altno = alts->bAlternateSetting;
+
+		/* get audio formats */
+		fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, AS_GENERAL, iface_no, altno);
+		if (!fmt) {
+			snd_printk(KERN_ERR "%d:%u:%d : AS_GENERAL descriptor not found\n",
+				   dev->devnum, iface_no, altno);
+			continue;
+		}
+
+		if (fmt[0] < 7) {
+			snd_printk(KERN_ERR "%d:%u:%d : invalid AS_GENERAL desc\n", 
+				   dev->devnum, iface_no, altno);
+			continue;
+		}
+
+		format = (fmt[6] << 8) | fmt[5]; /* remember the format value */
+			
+		/* get format type */
+		fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, FORMAT_TYPE, iface_no, altno);
+		if (!fmt) {
+			snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n", 
+				   dev->devnum, iface_no, altno);
+			continue;
+		}
+		if (fmt[0] < 8) {
+			snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", 
+				   dev->devnum, iface_no, altno);
+			continue;
+		}
+
+		format_type = fmt[3];
+		/* FIXME: needed support for TYPE II and III */
+		if (format_type != USB_FORMAT_TYPE_I) {
+			snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
+				   dev->devnum, iface_no, altno, format_type);
+			continue;
+		}
+
+		nr_rates = fmt[7];
+		if (fmt[0] < 8 + 3 * (nr_rates ? nr_rates : 2)) {
+			snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", 
+				   dev->devnum, iface_no, altno);
+			continue;
+		}
+
+		/* FIXME: correct endianess and sign? */
+		pcm_format = -1;
+		switch (format) {
+		case USB_AUDIO_FORMAT_PCM:
+			/* check the format byte size */
+			switch (fmt[6]) {
+			case 8:
+				subs->formats |= SNDRV_PCM_FMTBIT_U8;
+				pcm_format = SNDRV_PCM_FORMAT_U8;
+				break;
+			case 16:
+				subs->formats |= SNDRV_PCM_FMTBIT_S16_LE;
+				pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+				break;
+			case 18:
+			case 20:
+				if (fmt[5] == 3) {
+					subs->formats |= SNDRV_PCM_FMTBIT_S24_3LE;
+					pcm_format = SNDRV_PCM_FORMAT_S24_3LE;
+				} else {
+					snd_printk(KERN_ERR "%d:%u:%d : non-supported sample bit %d in %d bytes\n",
+						   dev->devnum, iface_no, altno, fmt[6], fmt[5]);
+				}
+				break;
+			case 24:
+				if (fmt[5] == 4) {
+					/* FIXME: correct?  or S32_LE? */
+					subs->formats |= SNDRV_PCM_FMTBIT_S24_LE;
+					pcm_format = SNDRV_PCM_FORMAT_S24_LE;
+				} else if (fmt[5] == 3) {
+					subs->formats |= SNDRV_PCM_FMTBIT_S24_3LE;
+					pcm_format = SNDRV_PCM_FORMAT_S24_3LE;
+				} else {
+					snd_printk(KERN_ERR "%d:%u:%d : non-supported sample bit %d in %d bytes\n",
+						   dev->devnum, iface_no, altno, format, fmt[5]);
+				}
+				break;
+			case 32:
+				subs->formats |= SNDRV_PCM_FMTBIT_S32_LE;
+				pcm_format = SNDRV_PCM_FORMAT_S32_LE;
+				break;
+			default:
+				snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
+					   dev->devnum, iface_no, altno, fmt[6], fmt[5]);
+				break;
+			}
+			break;
+		case USB_AUDIO_FORMAT_PCM8:
+			/* Dallas DS4201 workaround */
+			if (dev->descriptor.idVendor == 0x04fa && dev->descriptor.idProduct == 0x4201) {
+				subs->formats |= ~SNDRV_PCM_FMTBIT_S8;
+				pcm_format = SNDRV_PCM_FORMAT_S8;
+			} else {
+				subs->formats |= SNDRV_PCM_FMTBIT_U8;
+				pcm_format = SNDRV_PCM_FORMAT_U8;
+			}
+			break;
+		case USB_AUDIO_FORMAT_IEEE_FLOAT:
+			subs->formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
+			pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE;
+			break;
+		case USB_AUDIO_FORMAT_ALAW:
+			subs->formats |= SNDRV_PCM_FMTBIT_A_LAW;
+			pcm_format = SNDRV_PCM_FORMAT_A_LAW;
+			break;
+		case USB_AUDIO_FORMAT_MU_LAW:
+			subs->formats |= SNDRV_PCM_FMTBIT_MU_LAW;
+			pcm_format = SNDRV_PCM_FORMAT_MU_LAW;
+			break;
+		default:
+			snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n",
+				   dev->devnum, iface_no, altno, format);
+			break;
+		}
+
+		if (pcm_format < 0)
+			continue;
+
+		channels = fmt[4];
+		if (channels < 1) {
+			snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
+				   dev->devnum, iface_no, altno, channels);
+			continue;
+		}
+
+		csep = snd_usb_find_desc(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, iface_no, altno);
+		if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
+			snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n", 
+				   dev->devnum, iface_no, altno);
+			continue;
+		}
+
+		fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+		if (! fp) {
+			snd_printk(KERN_ERR "cannot malloc\n");
+			break;
+		}
+
+		memset(fp, 0, sizeof(*fp));
+		fp->format = pcm_format;
+		fp->altsetting = altno;
+		fp->altset_idx = i;
+		fp->endpoint = alts->endpoint[0].bEndpointAddress;
+		fp->ep_attr = alts->endpoint[0].bmAttributes;
+		fp->channels = channels;
+		fp->attributes = csep[3];
+
+		if (nr_rates) {
+			/*
+			 * build the rate table and bitmap flags
+			 */
+			int r, idx, c;
+			/* this table corresponds to the SNDRV_PCM_RATE_XXX bit */
+			static int conv_rates[] = {
+				5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
+				64000, 88200, 96000, 176400, 192000
+			};
+			fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
+			if (fp->rate_table == NULL) {
+				snd_printk(KERN_ERR "cannot malloc\n");
+				kfree(fp);
+				break;
+			}
+
+			fp->nr_rates = nr_rates;
+			fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
+			for (r = 0, idx = 8; r < nr_rates; r++, idx += 3) {
+				int rate = fp->rate_table[r] = combine_triple(&fmt[idx]);
+				if (rate < fp->rate_min)
+					fp->rate_min = rate;
+				else if (rate > fp->rate_max)
+					fp->rate_max = rate;
+				for (c = 0; c < 13; c++) {
+					if (rate == conv_rates[c]) {
+						fp->rates |= (1 << c);
+						break;
+					}
+				}
+#if 0 // FIXME - we need to define constraint
+				if (c >= 13)
+					fp->rates |= SNDRV_PCM_KNOT; /* unconventional rate */
+#endif
+			}
+
+		} else {
+			/* continuous rates */
+			fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
+			fp->rate_min = combine_triple(&fmt[8]);
+			fp->rate_max = combine_triple(&fmt[11]);
+		}
+
+		list_add_tail(&fp->list, &subs->fmt_list);
+		subs->num_formats++;
+	}
+}
+
+
+/*
+ * free a substream
+ */
+static void free_substream(snd_usb_substream_t *subs)
+{
+	struct list_head *p, *n;
+
+	if (subs->interface < 0)
+		return;
+
+	list_for_each_safe(p, n, &subs->fmt_list) {
+		struct audioformat *fp = list_entry(p, struct audioformat, list);
+		if (fp->rate_table)
+			kfree(fp->rate_table);
+		kfree(fp);
+	}
+}
+
+
+/*
+ * proc interface for list the supported pcm formats
+ */
+static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buffer_t *buffer)
+{
+	struct list_head *p;
+	static char *sync_types[4] = {
+		"NONE", "ASYNC", "ADAPTIVE", "SYNC"
+	};
+
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *fp;
+		fp = list_entry(p, struct audioformat, list);
+		snd_iprintf(buffer, "  Altset %d\n", fp->altset_idx);
+		snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
+		snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
+		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
+			    fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
+			    fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
+			    sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]);
+		if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
+			snd_iprintf(buffer, "    Rates: %d - %d (continous)\n",
+				    fp->rate_min, fp->rate_max);
+		} else {
+			int i;
+			snd_iprintf(buffer, "    Rates: ");
+			for (i = 0; i < fp->nr_rates; i++) {
+				if (i > 0)
+					snd_iprintf(buffer, ", ");
+				snd_iprintf(buffer, "%d", fp->rate_table[i]);
+			}
+			snd_iprintf(buffer, "\n");
+		}
+	}
+}
+
+static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffer_t *buffer)
+{
+	if (subs->running) {
+		int i;
+		snd_iprintf(buffer, "  Status: Running\n");
+		snd_iprintf(buffer, "    Altset = %d\n", subs->format);
+		snd_iprintf(buffer, "    URBs = %d [ ", subs->nurbs);
+		for (i = 0; i < subs->nurbs; i++)
+			snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
+		snd_iprintf(buffer, "]\n");
+		snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize);
+		snd_iprintf(buffer, "    Momentary freq = %d,%03d Hz\n",
+			    subs->freqm >> 14,
+			    ((subs->freqm & ((1 << 14) - 1)) * 1000) / ((1 << 14) - 1));
+	} else {
+		snd_iprintf(buffer, "  Status: Stop\n");
+	}
+}
+
+static void proc_pcm_format_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+{
+	snd_usb_stream_t *stream = snd_magic_cast(snd_usb_stream_t, entry->private_data, return);
+	
+	snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name);
+
+	if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) {
+		snd_iprintf(buffer, "\nPlayback:\n");
+		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);
+		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);
+	}
+	if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) {
+		snd_iprintf(buffer, "\nCapture:\n");
+		proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);
+		proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);
+	}
+}
+
+static void proc_pcm_format_add(snd_usb_stream_t *stream)
+{
+	snd_info_entry_t *entry;
+	char name[32];
+	snd_card_t *card = stream->chip->card;
+
+	sprintf(name, "stream%d", stream->pcm_index);
+	if ((entry = snd_info_create_card_entry(card, name, card->proc_root)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = stream;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 4096;
+		entry->c.text.read = proc_pcm_format_read;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	stream->proc_entry = entry;
+}
+
+
+/*
+ * free a usb stream instance
+ */
+static void snd_usb_audio_stream_free(snd_usb_stream_t *stream)
+{
+	if (stream->proc_entry) {
+		snd_info_unregister(stream->proc_entry);
+		stream->proc_entry = NULL;
+	}
+	free_substream(&stream->substream[0]);
+	free_substream(&stream->substream[1]);
+	list_del(&stream->list);
+	snd_magic_kfree(stream);
+}
+
+static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
+{
+	snd_usb_stream_t *stream = pcm->private_data;
+	if (stream) {
+		stream->pcm = NULL;
+		snd_pcm_lib_preallocate_free_for_all(pcm);
+		snd_usb_audio_stream_free(stream);
+	}
+}
+
+static int snd_usb_audio_stream_new(snd_usb_audio_t *chip, unsigned char *buffer, int buflen, int asifin, int asifout)
+{
+	snd_usb_stream_t *as;
+	snd_pcm_t *pcm;
+	char name[32];
+	int err;
+
+	as = snd_magic_kmalloc(snd_usb_stream_t, 0, GFP_KERNEL);
+	if (as == NULL) {
+		snd_printk(KERN_ERR "cannot malloc\n");
+		return -ENOMEM;
+	}
+	memset(as, 0, sizeof(*as));
+	as->chip = chip;
+	INIT_LIST_HEAD(&as->list);
+
+	init_substream(as, &as->substream[SNDRV_PCM_STREAM_PLAYBACK], asifout, 0, buffer, buflen);
+	init_substream(as, &as->substream[SNDRV_PCM_STREAM_CAPTURE], asifin, 1, buffer, buflen);
+
+	if (as->substream[0].num_formats == 0 && as->substream[1].num_formats == 0) {
+		snd_usb_audio_stream_free(as);
+		return 0;
+	}
+
+	if (chip->pcm_devs > 0)
+		sprintf(name, "USB Audio #%d", chip->pcm_devs);
+	else
+		strcpy(name, "USB Audio");
+	err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
+			  as->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats ? 1 : 0,
+			  as->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats ? 1 : 0,
+			  &pcm);
+	if (err < 0) {
+		snd_usb_audio_stream_free(as);
+		return err;
+	}
+
+	as->pcm = pcm;
+	as->pcm_index = chip->pcm_devs;
+	if (as->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback_ops);
+	if (as->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats)
+		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture_ops);
+
+	pcm->private_data = as;
+	pcm->private_free = snd_usb_audio_pcm_free;
+	pcm->info_flags = 0;
+
+	strcpy(pcm->name, name);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, 64*1024, 128*1024, GFP_ATOMIC);
+	list_add(&as->list, &chip->pcm_list);
+	chip->pcm_devs++;
+
+	proc_pcm_format_add(as);
+
+	return 0;
+}
+
+
+/*
+ * parse audio control descriptor and create pcm streams
+ */
+
+static int snd_usb_create_pcm(snd_usb_audio_t *chip, int ctrlif,
+			      unsigned char *buffer, int buflen)
+{
+	struct usb_device *dev = chip->dev;
+	struct usb_config_descriptor *config;
+	struct usb_interface *iface;
+	unsigned char *p1;
+	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
+	int numifin = 0, numifout = 0;
+	int i, j, k;
+
+	/* find audiocontrol interface */
+	if (!(p1 = snd_usb_find_csint_desc(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
+		snd_printk(KERN_ERR "cannot find HEADER\n");
+		return -EINVAL;
+	}
+	if (! p1[7] || p1[0] < 8 + p1[7]) {
+		snd_printk(KERN_ERR "invalid HEADER\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * parse all USB audio streaming interfaces
+	 */
+	config = dev->actconfig;
+	for (i = 0; i < p1[7]; i++) {
+		j = p1[8 + i];
+		if (j >= config->bNumInterfaces) {
+			snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
+				   dev->devnum, ctrlif, j);
+			continue;
+		}
+		iface = &config->interface[j];
+		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);
+			/* skip non-supported classes */
+			continue;
+		}
+		if (iface->num_altsetting < 2) {
+			snd_printdd(KERN_ERR "%d:%u:%d: skipping - no valid interface.\n",
+				    dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->altsetting[0].bNumEndpoints > 0) {
+			/* Check all endpoints; should they all have a bandwidth of 0 ? */
+			for (k = 0; k < iface->altsetting[0].bNumEndpoints; k++) {
+				if (iface->altsetting[0].endpoint[k].wMaxPacketSize > 0) {
+					snd_printk(KERN_ERR "%d:%u:%d ep%d : have no bandwith at alt[0]\n", dev->devnum, ctrlif, j, k);
+					break;
+				}
+			}
+			if (k < iface->altsetting[0].bNumEndpoints)
+				continue;
+		}
+		if (iface->altsetting[1].bNumEndpoints < 1) {
+			snd_printk(KERN_ERR "%d:%u:%d : has no endpoint\n",
+				   dev->devnum, ctrlif, j);
+			continue;
+		}
+		/* note: this requires the data endpoint to be ep0 and
+		 * the optional sync ep to be ep1, which seems to be the case
+		 */
+		if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) {
+			if (numifin < USB_MAXINTERFACES) {
+				snd_printdd(KERN_INFO "adding an input interface %d:%u:%d\n", dev->devnum, ctrlif, j);
+				ifin[numifin++] = j;
+				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
+			}
+		} else {
+			if (numifout < USB_MAXINTERFACES) {
+				snd_printdd(KERN_INFO "adding an output interface %d:%u:%d\n", dev->devnum, ctrlif, j);
+				ifout[numifout++] = j;
+				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
+			}
+		}
+	}
+
+	/* all endpoints are parsed.  now create pcm streams */
+	for (i = 0; i < numifin && i < numifout; i++)
+		snd_usb_audio_stream_new(chip, buffer, buflen, ifin[i], ifout[i]);
+	for (j = i; j < numifin; j++)
+		snd_usb_audio_stream_new(chip, buffer, buflen, ifin[i], -1);
+	for (j = i; j < numifout; j++)
+		snd_usb_audio_stream_new(chip, buffer, buflen, -1, ifout[i]);
+
+	return 0;
+}
+
+
+/*
+ * free the chip instance
+ *
+ * here we have to do not much, since pcm and controls are already freed
+ *
+ */
+
+static int snd_usb_audio_free(snd_usb_audio_t *chip)
+{
+	down(&register_mutex);
+	usb_chip[chip->index] = NULL;
+	up(&register_mutex);
+	snd_magic_kfree(chip);
+	return 0;
+}
+
+static int snd_usb_audio_dev_free(snd_device_t *device)
+{
+	snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, device->device_data, return -ENXIO);
+	return snd_usb_audio_free(chip);
+}
+
+
+/*
+ * 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)
+{
+	snd_usb_audio_t *chip;
+	int err, len;
+	static snd_device_ops_t ops = {
+		dev_free:	snd_usb_audio_dev_free,
+	};
+	
+	*rchip = NULL;
+	chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL);
+	if (! chip)
+		return -ENOMEM;
+
+	chip->dev = dev;
+	chip->card = card;
+	INIT_LIST_HEAD(&chip->pcm_list);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_usb_audio_free(chip);
+		return err;
+	}
+
+	strcpy(card->driver, "USB-Audio");
+	strcpy(card->shortname, "USB Audio Driver");
+
+	/* retrieve the vendor and device strings as longname */
+	len = usb_string(dev, 1, card->longname, sizeof(card->longname) - 1);
+	if (len <= 0)
+		len = 0;
+	else {
+		card->longname[len] = ' ';
+		len++;
+	}
+	card->longname[len] = 0;
+	usb_string(dev, 2, card->longname + len, sizeof(card->longname) - len);
+
+	*rchip = chip;
+	return 0;
+}
+
+
+/*
+ * allocate and get description buffer
+ * must be freed later.
+ */
+static int alloc_desc_buffer(struct usb_device *dev, int index, unsigned char **bufptr)
+{
+	int err, buflen;
+	unsigned char buf[8];
+	unsigned char *buffer;
+
+	*bufptr = 0;
+	err = usb_get_descriptor(dev, USB_DT_CONFIG, index, buf, 8);
+	if (err < 0) {
+		snd_printk(KERN_ERR "%d:%d: cannot get first 8 bytes\n", index, dev->devnum);
+		return err;
+	}
+	if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
+		snd_printk(KERN_ERR "%d:%d: invalid config desc\n", index, dev->devnum);
+		return -EINVAL;
+	}
+	buflen = combine_word(&buf[2]);
+	if (!(buffer = kmalloc(buflen, GFP_KERNEL))) {
+		snd_printk(KERN_ERR "cannot malloc descriptor (size = %d)\n", buflen);
+		return -ENOMEM;
+	}
+	err = usb_get_descriptor(dev, USB_DT_CONFIG, index, buffer, buflen);
+	if (err < 0) {
+		snd_printk(KERN_ERR "%d:%d: cannot get DT_CONFIG: error %d\n", index, dev->devnum, err);
+		kfree(buffer);
+		return err;
+	}
+	*bufptr = buffer;
+	return buflen;
+}
+
+
+/*
+ * probe the active usb device
+ *
+ * note that this can be called multiple times per a device, when it
+ * includes multiple audio control interfaces.
+ *
+ * thus we check the usb device pointer and creates the card instance
+ * only at the first time.  the successive calls of this function will
+ * append the pcm interface to the corresponding card.
+ */
+static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
+			     const struct usb_device_id *id)
+{
+	struct usb_config_descriptor *config = dev->actconfig;	
+	unsigned char *buffer;
+	unsigned int index;
+	int i, buflen;
+	snd_card_t *card;
+	snd_usb_audio_t *chip;
+
+	if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
+		snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", config->bConfigurationValue);
+		return NULL;
+	}
+
+	index = dev->actconfig - config;
+	buflen = alloc_desc_buffer(dev, index, &buffer);
+	if (buflen <= 0)
+		return NULL;
+
+	/*
+	 * found a config.  now register to ALSA
+	 */
+
+	/* check whether it's already registered */
+	chip = NULL;
+	down(&register_mutex);
+	for (i = 0; i < SNDRV_CARDS; i++) {
+		if (usb_chip[i] && usb_chip[i]->dev == dev) {
+			chip = usb_chip[i];
+			break;
+		}
+	}
+	if (! chip) {
+		/* it's a fresh one.
+		 * now look for an empty slot and create a new card instance
+		 */
+		for (i = 0; i < SNDRV_CARDS; i++)
+			if (snd_enable[i] && ! usb_chip[i]) {
+				card = snd_card_new(snd_index[i], snd_id[i], THIS_MODULE, 0);
+				if (card == NULL) {
+					snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
+					goto __error;
+				}
+				if (snd_usb_audio_create(card, dev, &chip) < 0) {
+					snd_card_free(card);
+					goto __error;
+				}
+				chip->index = i;
+				usb_chip[i] = chip;
+				break;
+			}
+		if (! chip) {
+			snd_printk(KERN_ERR "no available usb audio device\n");
+			goto __error;
+		}
+	}
+
+	if (snd_usb_create_pcm(chip, ifnum, buffer, buflen) < 0)
+		goto __error;
+	if (snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0)
+		goto __error;
+
+	/* we are allowed to call snd_card_register() many times */
+	if (snd_card_register(chip->card) < 0) {
+		if (! chip->num_interfaces)
+			snd_card_free(chip->card);
+		goto __error;
+	}
+
+	chip->num_interfaces++;
+	up(&register_mutex);
+	kfree(buffer);
+	return chip;
+
+ __error:
+	up(&register_mutex);
+	kfree(buffer);
+	return NULL;
+}
+
+
+/*
+ * we need to take care of counter, since disconnection can be called also
+ * many times as well as usb_audio_probe(). 
+ */
+static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
+{
+	snd_usb_audio_t *chip;
+
+	if (ptr == (void *)-1)
+		return;
+
+	chip = snd_magic_cast(snd_usb_audio_t, ptr, return);
+	chip->num_interfaces--;
+	if (chip->num_interfaces <= 0)
+		snd_card_free(chip->card);
+}
+
+static int __init snd_usb_audio_init(void)
+{
+	usb_register(&usb_audio_driver);
+	return 0;
+}
+
+
+static void __exit snd_usb_audio_cleanup(void)
+{
+	usb_deregister(&usb_audio_driver);
+}
+
+module_init(snd_usb_audio_init);
+module_exit(snd_usb_audio_cleanup);
+
+#ifndef MODULE
+/*
+ * format is snd-usb-audio=snd_enable,snd_index,snd_id
+ */
+static int __init snd_usb_audio_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);
+	++nr_dev;
+	return 1;
+}
+
+__setup("snd-usb-audio=", snd_usb_audio_module_setup);
+
+#endif /* !MODULE */
diff -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/usbaudio.h	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,150 @@
+#ifndef __USBAUDIO_H
+#define __USBAUDIO_H
+/*
+ *   (Tentative) USB Audio Driver for ALSA
+ *
+ *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.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
+ */
+
+
+/*
+ */
+
+#define USB_SUBCLASS_AUDIO_CONTROL	0x01
+#define USB_SUBCLASS_AUDIO_STREAMING	0x02
+
+#define USB_DT_CS_DEVICE                0x21
+#define USB_DT_CS_CONFIG                0x22
+#define USB_DT_CS_STRING                0x23
+#define USB_DT_CS_INTERFACE             0x24
+#define USB_DT_CS_ENDPOINT              0x25
+
+#define CS_AUDIO_UNDEFINED		0x20
+#define CS_AUDIO_DEVICE			0x21
+#define CS_AUDIO_CONFIGURATION		0x22
+#define CS_AUDIO_STRING			0x23
+#define CS_AUDIO_INTERFACE		0x24
+#define CS_AUDIO_ENDPOINT		0x25
+
+#define HEADER				0x01
+#define INPUT_TERMINAL			0x02
+#define OUTPUT_TERMINAL			0x03
+#define MIXER_UNIT			0x04
+#define SELECTOR_UNIT			0x05
+#define FEATURE_UNIT			0x06
+#define PROCESSING_UNIT			0x07
+#define EXTENSION_UNIT			0x08
+
+#define AS_GENERAL			0x01
+#define FORMAT_TYPE			0x02
+#define FORMAT_SPECIFIC			0x03
+
+#define EP_GENERAL			0x01
+
+/* endpoint attributes */
+#define EP_ATTR_MASK			0x0c
+#define EP_ATTR_ASYNC			0x04
+#define EP_ATTR_ADAPTIVE		0x08
+#define EP_ATTR_SYNC			0x0c
+
+/* cs endpoint attributes */
+#define EP_CS_ATTR_SAMPLE_RATE		0x01
+#define EP_CS_ATTR_PITCH_CONTROL	0x02
+#define EP_CS_ATTR_FILL_MAX		0x80
+
+/* Audio Class specific Request Codes */
+
+#define SET_CUR    0x01
+#define GET_CUR    0x81
+#define SET_MIN    0x02
+#define GET_MIN    0x82
+#define SET_MAX    0x03
+#define GET_MAX    0x83
+#define SET_RES    0x04
+#define GET_RES    0x84
+#define SET_MEM    0x05
+#define GET_MEM    0x85
+#define GET_STAT   0xff
+
+/* Terminal Control Selectors */
+
+#define COPY_PROTECT_CONTROL       0x01
+
+/* Endpoint Control Selectors */
+
+#define SAMPLING_FREQ_CONTROL      0x01
+#define PITCH_CONTROL              0x02
+
+/* Format Types */
+#define USB_FORMAT_TYPE_I	0x01
+#define USB_FORMAT_TYPE_II	0x02
+#define USB_FORMAT_TYPE_III	0x03
+
+/* type I */
+#define USB_AUDIO_FORMAT_PCM	0x01
+#define USB_AUDIO_FORMAT_PCM8	0x02
+#define USB_AUDIO_FORMAT_IEEE_FLOAT	0x03
+#define USB_AUDIO_FORMAT_ALAW	0x04
+#define USB_AUDIO_FORMAT_MU_LAW	0x05
+
+/* type II */
+#define USB_AUDIO_FORMAT_MPEG	0x1001
+#define USB_AUDIO_FORMAT_AC3	0x1002
+
+/* type III */
+#define USB_AUDIO_FORMAT_IEC1937_AC3	0x2001
+#define USB_AUDIO_FORMAT_IEC1937_MPEG1_LAYER1	0x2002
+#define USB_AUDIO_FORMAT_IEC1937_MPEG2_NOEXT	0x2003
+#define USB_AUDIO_FORMAT_IEC1937_MPEG2_EXT	0x2004
+#define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER1_LS	0x2005
+#define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER23_LS	0x2006
+
+
+/*
+ */
+
+typedef struct snd_usb_audio snd_usb_audio_t;
+
+struct snd_usb_audio {
+	
+	int index;
+	struct usb_device *dev;
+	snd_card_t *card;
+	int num_interfaces;
+
+	struct list_head pcm_list;	/* list of pcm streams */
+	int pcm_devs;
+
+};  
+
+
+/*
+ */
+
+#define combine_word(s)    ((*s) | ((unsigned int)(s)[1] << 8))
+#define combine_triple(s)  (combine_word(s) | ((unsigned int)(s)[2] << 16))
+#define combine_quad(s)    (combine_triple(s) | ((unsigned int)(s)[3] << 24))
+
+unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);
+
+void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype, int iface, int altsetting);
+void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype, int iface, int altsetting);
+
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, int buflen);
+
+#endif /* __USBAUDIO_H */
diff -Nru a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/usbmidi.c	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,1398 @@
+/*
+ * usbmidi.c - ALSA USB MIDI driver
+ *
+ * Copyright (c) 2002 Clemens Ladisch
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed and/or modified 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 SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sound/driver.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#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>
+#include <sound/seq_device.h>
+#include <sound/seq_kernel.h>
+#include <sound/seq_virmidi.h>
+#include <sound/seq_midi_event.h>
+#define SNDRV_GET_ID
+#include <sound/initval.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-90},"
+		"{Roland/EDIROL,SK-500},"
+		"{Roland/EDIROL,U-8},"
+		"{Roland/EDIROL,UA-100(G)},"
+		"{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
+
+/* 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;
+typedef struct usb_interface usb_interface_t;
+typedef struct usb_interface_descriptor usb_interface_descriptor_t;
+typedef struct usb_ms_header_descriptor usb_ms_header_descriptor_t;
+typedef struct usb_endpoint_descriptor usb_endpoint_descriptor_t;
+typedef struct usb_ms_endpoint_descriptor usb_ms_endpoint_descriptor_t;
+
+struct usb_ms_header_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubtype;
+	__u8  bcdMSC[2];
+	__u16 wTotalLength;
+} __attribute__ ((packed));
+
+struct usb_ms_endpoint_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bDescriptorSubtype;
+	__u8  bNumEmbMIDIJack;
+	__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;
+	urb_t* urb;
+	int max_transfer;		/* size of urb buffer */
+	struct tasklet_struct tasklet;
+
+	uint8_t buffer[OUTPUT_BUFFER_SIZE]; /* ring buffer */
+	int data_begin;
+	int data_size;
+	spinlock_t buffer_lock;
+
+	struct usbmidi_out_port {
+		usbmidi_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;
+	urb_t* urb;
+	struct usbmidi_in_port {
+		int seq_port;
+		snd_midi_event_t* midi_event;
+	} 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);
+
+/*
+ * Submits the URB, with error handling.
+ */
+static int snd_usbmidi_submit_urb(urb_t* urb, int flags)
+{
+	int err = usb_submit_urb(urb, flags);
+	if (err < 0 && err != -ENODEV)
+		printk(KERN_ERR "snd-usb-midi: usb_submit_urb: %d\n", err);
+	return err;
+}
+
+/*
+ * Error handling for URB completion functions.
+ */
+static int snd_usbmidi_urb_error(int status)
+{
+	if (status == -ENOENT)
+		return status; /* killed */
+	if (status == -ENODEV ||
+	    status == -EILSEQ ||
+	    status == -ETIMEDOUT)
+		return -ENODEV; /* device removed */
+	printk(KERN_ERR "snd-usb-midi: urb status %d\n", status);
+	return 0; /* continue */
+}
+
+/*
+ * Converts a USB MIDI packet into an ALSA sequencer event.
+ */
+static void snd_usbmidi_input_packet(usbmidi_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;
+
+	if (!port->midi_event)
+		return;
+	memset(&ev, 0, sizeof(ev));
+	if (snd_midi_event_encode(port->midi_event, &packet[1],
+				  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;
+		snd_seq_kernel_client_dispatch(ep->umidi->seq_client,
+					       &ev, 1, 0);
+		if (ep->ep->rmidi[cable])
+			snd_virmidi_receive(ep->ep->rmidi[cable], &ev);
+	}
+}
+
+/*
+ * Processes the data read from the device.
+ */
+static void snd_usbmidi_in_urb_complete(urb_t* urb)
+{
+	usbmidi_in_endpoint_t* ep = snd_magic_cast(usbmidi_in_endpoint_t, urb->context, return);
+
+	if (urb->status == 0) {
+		uint8_t* buffer = (uint8_t*)ep->urb->transfer_buffer;
+		int i;
+
+		for (i = 0; i + 4 <= urb->actual_length; i += 4)
+			if (buffer[i] != 0)
+				snd_usbmidi_input_packet(ep, &buffer[i]);
+	} else {
+		if (snd_usbmidi_urb_error(urb->status) < 0)
+			return;
+	}
+
+	if (!usb_pipeint(urb->pipe)) {
+		urb->dev = ep->umidi->usb_device;
+		snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
+	}
+}
+
+static void snd_usbmidi_out_urb_complete(urb_t* urb)
+{
+	usbmidi_out_endpoint_t* ep = snd_magic_cast(usbmidi_out_endpoint_t, urb->context, return);
+	unsigned long flags;
+
+	if (urb->status < 0) {
+		if (snd_usbmidi_urb_error(urb->status) < 0)
+			return;
+	}
+	spin_lock_irqsave(&ep->buffer_lock, flags);
+	snd_usbmidi_do_output(ep);
+	spin_unlock_irqrestore(&ep->buffer_lock, flags);
+}
+
+/*
+ * This is called when some data should be transferred to the device
+ * (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)
+{
+	int len;
+	uint8_t* buffer;
+
+	if (ep->urb->status == -EINPROGRESS ||
+	    ep->data_size == 0)
+		return;
+	buffer = (uint8_t*)ep->urb->transfer_buffer;
+
+	/* first chunk, up to the end of the buffer */
+	len = OUTPUT_BUFFER_SIZE - ep->data_begin;
+	if (len > ep->data_size)
+		len = ep->data_size;
+	if (len > ep->max_transfer)
+		len = ep->max_transfer;
+	if (len > 0) {
+		memcpy(buffer, ep->buffer + ep->data_begin, len);
+		ep->data_begin = (ep->data_begin + len) % OUTPUT_BUFFER_SIZE;
+		ep->data_size -= len;
+		buffer += len;
+		ep->urb->transfer_buffer_length = len;
+	}
+
+	/* second chunk (after wraparound) */
+	if (ep->data_begin == 0 && ep->data_size > 0 &&
+	    len < ep->max_transfer) {
+		len = ep->max_transfer - len;
+		if (len > ep->data_size)
+			len = ep->data_size;
+		memcpy(buffer, ep->buffer, len);
+		ep->data_begin = len;
+		ep->data_size -= len;
+		ep->urb->transfer_buffer_length += len;
+	}
+
+	if (len > 0) {
+		ep->urb->dev = ep->umidi->usb_device;
+		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);
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ep->buffer_lock, flags);
+	snd_usbmidi_do_output(ep);
+	spin_unlock_irqrestore(&ep->buffer_lock, flags);
+}
+
+/*
+ * Adds one USB MIDI packet to the output buffer.
+ */
+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;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ep->buffer_lock, flags);
+	if (ep->data_size < OUTPUT_BUFFER_SIZE) {
+		uint8_t* buf = ep->buffer + (ep->data_begin + ep->data_size) % OUTPUT_BUFFER_SIZE;
+		buf[0] = p0;
+		buf[1] = p1;
+		buf[2] = p2;
+		buf[3] = p3;
+		ep->data_size += 4;
+		if (ep->data_size == ep->max_transfer)
+			snd_usbmidi_do_output(ep);
+	}
+	spin_unlock_irqrestore(&ep->buffer_lock, flags);
+}
+
+/*
+ * Callback for snd_seq_dump_var_event.
+ */
+static int snd_usbmidi_sysex_dump(void* ptr, void* buf, int count)
+{
+	usbmidi_out_port_t* port = (usbmidi_out_port_t*)ptr;
+	const uint8_t* dump = (const uint8_t*)buf;
+
+	for (; count; --count) {
+		uint8_t byte = *dump++;
+
+		if (byte == 0xf0 && port->sysex_len > 0) {
+			/*
+			 * The previous SysEx wasn't terminated correctly.
+			 * Send the last bytes anyway, and hope that the
+			 * receiving device won't be too upset about the
+			 * missing F7.
+			 */
+			output_packet(port,
+				      port->cable | (0x04 + port->sysex_len),
+				      port->sysex[0],
+				      port->sysex_len >= 2 ? port->sysex[1] : 0,
+				      0);
+			port->sysex_len = 0;
+		}
+		if (byte != 0xf7) {
+			if (port->sysex_len >= 2) {
+				output_packet(port,
+					      port->cable | 0x04,
+					      port->sysex[0],
+					      port->sysex[1],
+					      byte);
+				port->sysex_len = 0;
+			} else {
+				port->sysex[port->sysex_len++] = byte;
+			}
+		} else {
+			uint8_t cin, data[3];
+			int i;
+
+			for (i = 0; i < port->sysex_len; ++i)
+				data[i] = port->sysex[i];
+			data[i++] = 0xf7;
+			cin = port->cable | (0x04 + i);
+			for (; i < 3; ++i)
+				data[i] = 0;
+			/*
+			 * cin,data[] is x5,{F7 00 00}
+			 *            or x6,{xx F7 00}
+			 *            or x7,{xx xx F7}
+			 */
+			output_packet(port, cin, data[0], data[1], data[2]);
+			port->sysex_len = 0;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Converts an ALSA sequencer event into USB MIDI packets.
+ */
+static int snd_usbmidi_event_input(snd_seq_event_t* ev, int direct,
+				   void* private_data, int atomic, int hop)
+{
+	usbmidi_out_port_t* port = (usbmidi_out_port_t*)private_data;
+	int err;
+	uint8_t p0, p1;
+
+	p0 = port->cable;
+	p1 = ev->data.note.channel & 0xf;
+
+	switch (ev->type) {
+	case SNDRV_SEQ_EVENT_NOTEON:
+		output_packet(port, p0 | 0x09, p1 | 0x90,
+			      ev->data.note.note & 0x7f,
+			      ev->data.note.velocity & 0x7f);
+		break;
+	case SNDRV_SEQ_EVENT_NOTEOFF:
+		output_packet(port, p0 | 0x08, p1 | 0x80,
+			      ev->data.note.note & 0x7f,
+			      ev->data.note.velocity & 0x7f);
+		break;
+	case SNDRV_SEQ_EVENT_KEYPRESS:
+		output_packet(port, p0 | 0x0a, p1 | 0xa0,
+			      ev->data.note.note & 0x7f,
+			      ev->data.note.velocity & 0x7f);
+		break;
+	case SNDRV_SEQ_EVENT_CONTROLLER:
+		output_packet(port, p0 | 0x0b, p1 | 0xb0,
+			      ev->data.control.param & 0x7f,
+			      ev->data.control.value & 0x7f);
+		break;
+	case SNDRV_SEQ_EVENT_PGMCHANGE:
+		output_packet(port, p0 | 0x0c, p1 | 0xc0,
+			      ev->data.control.value & 0x7f, 0);
+		break;
+	case SNDRV_SEQ_EVENT_CHANPRESS:
+		output_packet(port, p0 | 0x0d, p1 | 0xd0,
+			      ev->data.control.value & 0x7f, 0);
+		break;
+	case SNDRV_SEQ_EVENT_PITCHBEND:
+		output_packet(port, p0 | 0x0e, p1 | 0xe0,
+			      (ev->data.control.value + 0x2000) & 0x7f,
+			      ((ev->data.control.value + 0x2000) >> 7) & 0x7f);
+		break;
+	case SNDRV_SEQ_EVENT_CONTROL14:
+		if (ev->data.control.param < 0x20) {
+			output_packet(port, p0 | 0x0b, p1 | 0xb0,
+				      ev->data.control.param,
+				      (ev->data.control.value >> 7) & 0x7f);
+			output_packet(port, p0 | 0x0b, p1 | 0xb0,
+				      ev->data.control.param + 0x20,
+				      ev->data.control.value & 0x7f);
+		} else {
+			output_packet(port, p0 | 0x0b, p1 | 0xb0,
+				      ev->data.control.param & 0x7f,
+				      ev->data.control.value & 0x7f);
+		}
+		break;
+	case SNDRV_SEQ_EVENT_SONGPOS:
+		output_packet(port, p0 | 0x03, 0xf2,
+			      ev->data.control.value & 0x7f,
+			      (ev->data.control.value >> 7) & 0x7f);
+		break;
+	case SNDRV_SEQ_EVENT_SONGSEL:
+		output_packet(port, p0 | 0x02, 0xf3,
+			      ev->data.control.value & 0x7f, 0);
+		break;
+	case SNDRV_SEQ_EVENT_QFRAME:
+		output_packet(port, p0 | 0x02, 0xf1,
+			      ev->data.control.value & 0x7f, 0);
+		break;
+	case SNDRV_SEQ_EVENT_START:
+		output_packet(port, p0 | 0x0f, 0xfa, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_CONTINUE:
+		output_packet(port, p0 | 0x0f, 0xfb, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_STOP:
+		output_packet(port, p0 | 0x0f, 0xfc, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_CLOCK:
+		output_packet(port, p0 | 0x0f, 0xf8, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_TUNE_REQUEST:
+		output_packet(port, p0 | 0x05, 0xf6, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_RESET:
+		output_packet(port, p0 | 0x0f, 0xff, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_SENSING:
+		output_packet(port, p0 | 0x0f, 0xfe, 0, 0);
+		break;
+	case SNDRV_SEQ_EVENT_SYSEX:
+		err = snd_seq_dump_var_event(ev, snd_usbmidi_sysex_dump, port);
+		if (err < 0)
+			return err;
+		break;
+	default:
+		return 0;
+	}
+	tasklet_hi_schedule(&port->ep->tasklet);
+	return 0;
+}
+
+/*
+ * 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)
+{
+	int i;
+
+	if (ep->urb) {
+		if (ep->urb->transfer_buffer) {
+			usb_unlink_urb(ep->urb);
+			kfree(ep->urb->transfer_buffer);
+		}
+		usb_free_urb(ep->urb);
+	}
+	for (i = 0; i < 0x10; ++i)
+		if (ep->ports[i].midi_event)
+			snd_midi_event_free(ep->ports[i].midi_event);
+	snd_magic_kfree(ep);
+}
+
+/*
+ * Searches for an alternate setting in which the endpoint uses interrupt
+ * transfers for input.
+ */
+static int snd_usbmidi_get_int_ep(usbmidi_t* umidi, uint8_t epnum,
+				  usb_endpoint_descriptor_t** descriptor)
+{
+	usb_interface_t* intf;
+	int i, j;
+
+	*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;
+}
+
+/*
+ * 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)
+{
+	usbmidi_in_endpoint_t* ep;
+	int do_int_transfer;
+	usb_endpoint_descriptor_t* epd;
+	void* buffer;
+	unsigned int pipe;
+	int length, i, err;
+
+	rep->in = NULL;
+	ep = snd_magic_kcalloc(usbmidi_in_endpoint_t, 0, GFP_KERNEL);
+	if (!ep)
+		return -ENOMEM;
+	ep->umidi = umidi;
+	ep->ep = rep;
+	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;
+		}
+	}
+
+	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);
+	else
+		pipe = usb_rcvbulkpipe(umidi->usb_device, ep_info->epnum);
+	length = usb_maxpacket(umidi->usb_device, 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);
+	else
+		FILL_BULK_URB(ep->urb, umidi->usb_device, pipe, buffer, length,
+			      snd_usbmidi_in_urb_complete, ep);
+
+	for (i = 0; i < 0x10; ++i)
+		if (ep_info->in_cables & (1 << i)) {
+			err = snd_midi_event_new(INPUT_BUFFER_SIZE,
+				 		 &ep->ports[i].midi_event);
+			if (err < 0) {
+				snd_usbmidi_in_endpoint_delete(ep);
+				return -ENOMEM;
+			}
+		}
+
+	rep->in = ep;
+	return 0;
+}
+
+static int snd_usbmidi_count_bits(uint16_t x)
+{
+	int i, bits = 0;
+
+	for (i = 0; i < 16; ++i)
+		bits += (x & (1 << i)) != 0;
+	return bits;
+}
+
+/*
+ * 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)
+{
+	if (ep->tasklet.func)
+		tasklet_kill(&ep->tasklet);
+	if (ep->urb) {
+		if (ep->urb->transfer_buffer) {
+			usb_unlink_urb(ep->urb);
+			kfree(ep->urb->transfer_buffer);
+		}
+		usb_free_urb(ep->urb);
+	}
+	snd_magic_kfree(ep);
+}
+
+/*
+ * 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)
+{
+	usbmidi_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);
+	if (!ep)
+		return -ENOMEM;
+	ep->umidi = umidi;
+
+	ep->urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!ep->urb) {
+		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;
+	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,
+		      ep->max_transfer, snd_usbmidi_out_urb_complete, ep);
+
+	spin_lock_init(&ep->buffer_lock);
+	tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
+
+	for (i = 0; i < 0x10; ++i)
+		if (ep_info->out_cables & (1 << i)) {
+			ep->ports[i].ep = ep;
+			ep->ports[i].cable = i << 4;
+		}
+
+	rep->out = ep;
+	return 0;
+}
+
+/*
+ * Frees the sequencer client, endpoints and ports.
+ */
+static int snd_usbmidi_seq_device_delete(snd_seq_device_t* seq_device)
+{
+	usbmidi_t* umidi;
+	int i, j;
+
+	umidi = (usbmidi_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];
+		if (ep->out) {
+			snd_usbmidi_out_endpoint_delete(ep->out);
+			ep->out = NULL;
+		}
+		if (ep->in) {
+			snd_usbmidi_in_endpoint_delete(ep->in);
+			ep->in = NULL;
+		}
+		for (j = 0; j < 0x10; ++j)
+			if (ep->rmidi[j]) {
+				snd_device_free(umidi->card, ep->rmidi[j]);
+				ep->rmidi[j] = NULL;
+			}
+	}
+	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(usbmidi_t* umidi, int ep,
+					     int* port_idx)
+{
+	usbmidi_endpoint_info_t* ep_info = &umidi->device_info.endpoints[ep];
+	int c, err;
+	int cap, type, port;
+	int out, in;
+	snd_seq_port_callback_t port_callback;
+	char port_name[48];
+
+	for (c = 0; c < 0x10; ++c) {
+		out = ep_info->out_cables & (1 << c);
+		in = ep_info->in_cables & (1 << c);
+		if (!(in || out))
+			continue;
+		cap = 0;
+		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 */
+		sprintf(port_name, "%s Port %d",
+			umidi->device_info.product, *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)
+			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->card, *port_idx, &rmidi);
+			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->card, rmidi);
+			if (err < 0) {
+				snd_device_free(umidi->card, rmidi);
+				return err;
+			}
+			umidi->endpoints[ep].rmidi[c] = rmidi;
+		}
+		++*port_idx;
+	}
+	return 0;
+}
+
+/*
+ * Create the endpoints and their ports.
+ */
+static int snd_usbmidi_create_endpoints(usbmidi_t* umidi)
+{
+	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)
+			continue;
+		if (ep_info->out_cables) {
+			err = snd_usbmidi_out_endpoint_create(umidi, ep_info,
+							      &umidi->endpoints[i]);
+			if (err < 0)
+				return err;
+		}
+		if (ep_info->in_cables) {
+			err = snd_usbmidi_in_endpoint_create(umidi, ep_info,
+							     &umidi->endpoints[i]);
+			if (err < 0)
+				return err;
+		}
+		err = snd_usbmidi_create_endpoint_ports(umidi, i, &port_idx);
+		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));
+	}
+	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.
+ */
+static int snd_usbmidi_get_ms_info(usb_device_t* usb_device,
+				   unsigned int ifnum,
+				   usbmidi_device_info_t* device_info)
+{
+	usb_interface_t* intf;
+	usb_interface_descriptor_t* intfd;
+	usb_ms_header_descriptor_t* ms_header;
+	usb_endpoint_descriptor_t* ep;
+	usb_ms_endpoint_descriptor_t* ms_ep;
+	int i, epidx;
+
+	memset(device_info, 0, sizeof(*device_info));
+
+	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);
+	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;
+	}
+	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 &&
+	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
+	    ms_header->bDescriptorSubtype == USB_DST_MS_HEADER)
+		printk(KERN_INFO "snd-usb-midi: MIDIStreaming version %02x.%02x\n",
+		       ms_header->bcdMSC[1], ms_header->bcdMSC[0]);
+	else
+		printk(KERN_WARNING "snd-usb-midi: MIDIStreaming interface descriptor not found\n");
+
+	epidx = 0;
+	for (i = 0; i < intfd->bNumEndpoints; ++i) {
+		ep = &intfd->endpoint[i];
+		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 ||
+		    ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
+		    ms_ep->bDescriptorSubtype != USB_DST_MS_GENERAL)
+			continue;
+		if (device_info->endpoints[epidx].epnum != 0 &&
+		    device_info->endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
+			++epidx;
+			if (epidx >= MAX_ENDPOINTS) {
+				printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
+				break;
+			}
+		}
+		device_info->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;
+		} else {
+			device_info->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;
+	}
+	return 0;
+}
+
+/*
+ * Probes for a supported device.
+ */
+static void* snd_usbmidi_usb_probe(usb_device_t* device,
+				   unsigned int ifnum,
+				   const usb_device_id_t* device_id)
+{
+	usbmidi_device_info_t device_info;
+	snd_card_t* card = NULL;
+	int err;
+
+	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);
+	}
+	return card;
+}
+
+/*
+ * Frees the device.
+ */
+static void snd_usbmidi_usb_disconnect(usb_device_t* usb_device, void* ptr)
+{
+	snd_card_t* card = (snd_card_t*)ptr;
+	int dev = (int)card->private_data;
+
+	snd_card_free(card);
+	down(&snd_usbmidi_open_mutex);
+	snd_usbmidi_card_used[dev] = 0;
+	up(&snd_usbmidi_open_mutex);
+}
+
+/*
+ * 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 }}
+};
+
+#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) },
+	{ /* terminator */ }
+};
+
+MODULE_DEVICE_TABLE(usb, snd_usbmidi_usb_id_table);
+
+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)
+};
+
+static int __init snd_usbmidi_module_init(void)
+{
+	static snd_seq_dev_ops_t ops = {
+		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;
+}
+
+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 -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/usbmixer.c	Tue Oct  1 17:06:48 2002
@@ -0,0 +1,1286 @@
+/*
+ *   (Tentative) USB Audio Driver for ALSA
+ *
+ *   Mixer control part
+ *
+ *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
+ *
+ *   Many codes borrowed from audio.c by 
+ *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
+ *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *
+ *   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
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "usbaudio.h"
+
+
+/*
+ */
+
+typedef struct usb_mixer_build mixer_build_t;
+typedef struct usb_audio_term usb_audio_term_t;
+typedef struct usb_mixer_elem_info usb_mixer_elem_info_t;
+
+
+struct usb_audio_term {
+	int id;
+	int type;
+	int channels;
+	unsigned int chconfig;
+	int name;
+};
+
+struct usb_mixer_build {
+	snd_usb_audio_t *chip;
+	unsigned char *buffer;
+	unsigned int buflen;
+	unsigned int ctrlif;
+	unsigned long unitbitmap[32/sizeof(unsigned long)];
+	usb_audio_term_t oterm;
+};
+
+struct usb_mixer_elem_info {
+	snd_usb_audio_t *chip;
+	unsigned int ctrlif;
+	unsigned int id;
+	unsigned int control;
+	unsigned int cmask; /* channel mask bitmap: 0 = master */ 
+	int channels;
+	int val_type;
+	int min, max;
+};
+
+
+enum {
+	USB_FEATURE_MUTE = 0,
+	USB_FEATURE_VOLUME,
+	USB_FEATURE_BASS,
+	USB_FEATURE_MID,
+	USB_FEATURE_TREBLE,
+	USB_FEATURE_GEQ,
+	USB_FEATURE_AGC,
+	USB_FEATURE_DELAY,
+	USB_FEATURE_BASSBOOST,
+	FSB_FEATURE_LOUDNESS
+};
+
+enum {
+	USB_MIXER_BOOLEAN,
+	USB_MIXER_INV_BOOLEAN,
+	USB_MIXER_S8,
+	USB_MIXER_U8,
+	USB_MIXER_S16,
+	USB_MIXER_U16,
+};
+
+#define MAX_CHANNELS	10	/* max logical channels */
+
+
+/*
+ * find an audio control unit with the given unit id
+ */
+static void *find_audio_control_unit(mixer_build_t *state, unsigned char unit)
+{
+	unsigned char *p;
+
+	p = NULL;
+	while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
+				      USB_DT_CS_INTERFACE, state->ctrlif, -1)) != NULL) {
+		if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
+			return p;
+	}
+	return NULL;
+}
+
+
+/*
+ * copy a string with the given id
+ */
+static int snd_usb_copy_string_desc(mixer_build_t *state, int index, char *buf, int maxlen)
+{
+	int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
+	buf[len] = 0;
+	return len;
+}
+
+/*
+ * convert from the byte/word on usb descriptor to the zero-based integer
+ */
+static int convert_signed_value(usb_mixer_elem_info_t *cval, int val)
+{
+	switch (cval->val_type) {
+	case USB_MIXER_BOOLEAN:
+		return !!val;
+	case USB_MIXER_INV_BOOLEAN:
+		return !val;
+	case USB_MIXER_U8:
+		val &= 0xff;
+		break;
+	case USB_MIXER_S8:
+		val &= 0xff;
+		if (val >= 0x80)
+			val -= 0x100;
+		break;
+	case USB_MIXER_U16:
+		val &= 0xffff;
+		break;
+	case USB_MIXER_S16:
+		val &= 0xffff;
+		if (val >= 0x8000)
+			val -= 0x10000;
+		break;
+	}
+	return val;
+}
+
+/*
+ * convert from the zero-based int to the byte/word for usb descriptor
+ */
+static int convert_bytes_value(usb_mixer_elem_info_t *cval, int val)
+{
+	switch (cval->val_type) {
+	case USB_MIXER_BOOLEAN:
+		return !!val;
+	case USB_MIXER_INV_BOOLEAN:
+		return !val;
+	case USB_MIXER_S8:
+	case USB_MIXER_U8:
+		return val & 0xff;
+	case USB_MIXER_S16:
+	case USB_MIXER_U16:
+		return val & 0xffff;
+	}
+	return 0; /* not reached */
+}
+
+static int get_relative_value(usb_mixer_elem_info_t *cval, int val)
+{
+	if (val < cval->min)
+		return 0;
+	else if (val > cval->max)
+		return cval->max - cval->min;
+	else
+		return val - cval->min;
+}
+
+static int get_abs_value(usb_mixer_elem_info_t *cval, int val)
+{
+	if (val < 0)
+		return cval->min;
+	val += cval->min;
+	if (val > cval->max)
+		return cval->max;
+	return val;
+}
+
+
+/*
+ * retrieve a mixer value
+ */
+
+static int get_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, int *value_ret)
+{
+	unsigned char buf[2];
+	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
+ 
+	if (usb_control_msg(cval->chip->dev, usb_rcvctrlpipe(cval->chip->dev, 0),
+			    request,
+			    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+			    validx, cval->ctrlif | (cval->id << 8),
+			    buf, val_len, HZ) < 0)
+		return -EINVAL;
+	*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
+	return 0;
+}
+
+static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value)
+{
+	return get_ctl_value(cval, GET_CUR, validx, value);
+}
+
+/* channel = 0: master, 1 = first channel */
+inline static int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value)
+{
+	return get_ctl_value(cval, GET_CUR, ((cval->control + 1) << 8) | channel, value);
+}
+
+/*
+ * set a mixer value
+ */
+
+static int set_ctl_value(usb_mixer_elem_info_t *cval, int request, int validx, int value_set)
+{
+	unsigned char buf[2];
+	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
+ 
+	value_set = convert_bytes_value(cval, value_set);
+	buf[0] = value_set & 0xff;
+	buf[1] = (value_set >> 8) & 0xff;
+	return usb_control_msg(cval->chip->dev, usb_sndctrlpipe(cval->chip->dev, 0),
+			       request,
+			       USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+			       validx, cval->ctrlif | (cval->id << 8),
+			       buf, val_len, HZ);
+}
+
+static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value)
+{
+	return set_ctl_value(cval, SET_CUR, validx, value);
+}
+
+inline static int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value)
+{
+	return set_ctl_value(cval, SET_CUR, ((cval->control + 1) << 8) | channel, value);
+}
+
+
+/*
+ * parser routines begin here... 
+ */
+
+static int parse_audio_unit(mixer_build_t *state, int unitid);
+
+
+/*
+ * check if the input/output channel routing is enabled on the given bitmap.
+ * used for mixer unit parser
+ */
+static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_outs)
+{
+	int idx = ich * num_outs + och;
+	return bmap[-(idx >> 3)] & (0x80 >> (idx & 7));
+}
+
+
+/*
+ * add an alsa control element
+ * search and increment the index until an empty slot is found.
+ *
+ * if failed, give up and free the control instance.
+ */
+
+static int add_control_to_empty(snd_card_t *card, snd_kcontrol_t *kctl)
+{
+	int err;
+	while (snd_ctl_find_id(card, &kctl->id))
+		kctl->id.index++;
+	if ((err = snd_ctl_add(card, kctl)) < 0) {
+		snd_printk(KERN_ERR "cannot add control\n");
+		snd_ctl_free_one(kctl);
+	}
+	return err;
+}
+
+
+/*
+ * get a terminal name string
+ */
+
+static struct iterm_name_combo {
+	int type;
+	char *name;
+} iterm_names[] = {
+	{ 0x0300, "Output" },
+	{ 0x0301, "Speaker" },
+	{ 0x0302, "Headphone" },
+	{ 0x0303, "HMD Audio" },
+	{ 0x0304, "Desktop Speaker" },
+	{ 0x0305, "Room Speaker" },
+	{ 0x0306, "Com Speaker" },
+	{ 0x0307, "LFE" },
+	{ 0x0600, "External In" },
+	{ 0x0601, "Analog In" },
+	{ 0x0602, "Digital In" },
+	{ 0x0603, "Line" },
+	{ 0x0604, "Legacy In" },
+	{ 0x0605, "IEC958 In" },
+	{ 0x0606, "1394 DA Stream" },
+	{ 0x0607, "1394 DV Stream" },
+	{ 0x0700, "Embedded" },
+	{ 0x0701, "Noise Source" },
+	{ 0x0702, "Equalization Noise" },
+	{ 0x0703, "CD" },
+	{ 0x0704, "DAT" },
+	{ 0x0705, "DCC" },
+	{ 0x0706, "MiniDisk" },
+	{ 0x0707, "Analog Tape" },
+	{ 0x0708, "Phonograph" },
+	{ 0x0709, "VCR Audio" },
+	{ 0x070a, "Video Disk Audio" },
+	{ 0x070b, "DVD Audio" },
+	{ 0x070c, "TV Tuner Audio" },
+	{ 0x070d, "Satellite Rec Audio" },
+	{ 0x070e, "Cable Tuner Audio" },
+	{ 0x070f, "DSS Audio" },
+	{ 0x0710, "Radio Receiver" },
+	{ 0x0711, "Radio Transmitter" },
+	{ 0x0712, "Multi-Track Recorder" },
+	{ 0x0713, "Synthesizer" },
+	{ 0 },
+};	
+
+static int get_term_name(mixer_build_t *state, usb_audio_term_t *iterm,
+			 unsigned char *name, int maxlen, int term_only)
+{
+	struct iterm_name_combo *names;
+
+	if (iterm->name)
+		return snd_usb_copy_string_desc(state, iterm->name, name, maxlen);
+
+	/* virtual type - not a real terminal */
+	if (iterm->type >> 16) {
+		if (term_only)
+			return 0;
+		switch (iterm->type >> 16) {
+		case SELECTOR_UNIT:
+			strcpy(name, "Selector"); return 8;
+		case PROCESSING_UNIT:
+			strcpy(name, "Process Unit"); return 12;
+		case EXTENSION_UNIT:
+			strcpy(name, "Ext Unit"); return 8;
+		case MIXER_UNIT:
+			strcpy(name, "Mixer"); return 5;
+		default:
+			return sprintf(name, "Unit %d", iterm->id);
+		}
+	}
+
+	switch (iterm->type & 0xff00) {
+	case 0x0100:
+		strcpy(name, "PCM"); return 3;
+	case 0x0200:
+		strcpy(name, "Mic"); return 3;
+	case 0x0400:
+		strcpy(name, "Headset"); return 7;
+	case 0x0500:
+		strcpy(name, "Phone"); return 5;
+	}
+
+	for (names = iterm_names; names->type; names++)
+		if (names->type == iterm->type) {
+			strcpy(name, names->name);
+			return strlen(names->name);
+		}
+	return 0;
+}
+
+
+/*
+ * parse the source unit recursively until it reaches to a terminal
+ * or a branched unit.
+ */
+static int check_input_term(mixer_build_t *state, int id, usb_audio_term_t *term)
+{
+	unsigned char *p1;
+
+	memset(term, 0, sizeof(*term));
+	while ((p1 = find_audio_control_unit(state, id)) != NULL) {
+		term->id = id;
+		switch (p1[2]) {
+		case INPUT_TERMINAL:
+			term->type = combine_word(p1 + 4);
+			term->channels = p1[7];
+			term->chconfig = combine_word(p1 + 8);
+			term->name = p1[11];
+			return 0;
+		case FEATURE_UNIT:
+			id = p1[4];
+			break; /* continue to parse */
+		case MIXER_UNIT:
+			term->type = p1[2] << 16; /* virtual type */
+			term->channels = p1[5 + p1[4]];
+			term->chconfig = combine_word(p1 + 6 + p1[4]);
+			term->name = p1[p1[0] - 1];
+			return 0;
+		case SELECTOR_UNIT:
+			/* call recursively to retrieve the channel info */
+			if (check_input_term(state, p1[5], term) < 0)
+				return -ENODEV;
+			term->type = p1[2] << 16; /* virtual type */
+			term->id = id;
+			term->name = p1[9 + p1[0] - 1];
+			return 0;
+		case PROCESSING_UNIT:
+		case EXTENSION_UNIT:
+			if (p1[6] == 1) {
+				id = p1[7];
+				break; /* continue to parse */
+			}
+			term->type = p1[2] << 16; /* virtual type */
+			term->channels = p1[7 + p1[6]];
+			term->chconfig = combine_word(p1 + 8 + p1[6]);
+			term->name = p1[12 + p1[6] + p1[11 + p1[6]]];
+			return 0;
+		default:
+			return -ENODEV;
+		}
+	}
+	return -ENODEV;
+}
+
+
+/*
+ * Feature Unit
+ */
+
+/* feature unit control information */
+struct usb_feature_control_info {
+	const char *name;
+	unsigned int type;	/* control type (mute, volume, etc.) */
+};
+
+static struct usb_feature_control_info audio_feature_info[] = {
+	{ "Mute",		USB_MIXER_INV_BOOLEAN },
+	{ "Volume",		USB_MIXER_S16 },
+	{ "Tone Control - Bass",	USB_MIXER_S8 },
+	{ "Tone Control - Mid",		USB_MIXER_S8 },
+	{ "Tone Control - Treble",	USB_MIXER_S8 },
+	{ "Graphic Equalizer",		USB_MIXER_S8 }, /* FIXME: not implemeted yet */
+	{ "Auto Gain Control",	USB_MIXER_BOOLEAN },
+	{ "Delay Control",	USB_MIXER_U16 },
+	{ "Bass Boost",		USB_MIXER_BOOLEAN },
+	{ "Loudness",		USB_MIXER_BOOLEAN },
+};
+
+
+/* private_free callback */
+static void usb_mixer_elem_free(snd_kcontrol_t *kctl)
+{
+	if (kctl->private_data) {
+		snd_magic_kfree((void *)kctl->private_data);
+		kctl->private_data = 0;
+	}
+}
+
+
+/*
+ * interface to ALSA control for feature/mixer units
+ */
+
+/* get a feature/mixer unit info */
+static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{	
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+
+	if (cval->val_type == USB_MIXER_BOOLEAN ||
+	    cval->val_type == USB_MIXER_INV_BOOLEAN)
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	else
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = cval->channels;
+	if (cval->val_type == USB_MIXER_BOOLEAN ||
+	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
+		uinfo->value.integer.min = 0;
+		uinfo->value.integer.max = 1;
+	} else {
+		uinfo->value.integer.min = 0;
+		uinfo->value.integer.max = cval->max - cval->min;
+	}
+	return 0;
+}
+
+/* get the current value from feature/mixer unit */
+static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	int c, cnt, val, err;
+
+	if (cval->cmask) {
+		cnt = 0;
+		for (c = 0; c < MAX_CHANNELS; c++) {
+			if (cval->cmask & (1 << c)) {
+				err = get_cur_mix_value(cval, c + 1, &val);
+				if (err < 0)
+					return err;
+				val = get_relative_value(cval, val);
+				ucontrol->value.integer.value[cnt] = val;
+				cnt++;
+			}
+		}
+	} else {
+		/* master channel */
+		err = get_cur_mix_value(cval, 0, &val);
+		if (err < 0)
+			return err;
+		val = get_relative_value(cval, val);
+		ucontrol->value.integer.value[0] = val;
+	}
+	return 0;
+}
+
+/* put the current value to feature/mixer unit */
+static int mixer_ctl_feature_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	int c, cnt, val, oval, err;
+	int changed = 0;
+
+	if (cval->cmask) {
+		cnt = 0;
+		for (c = 0; c < MAX_CHANNELS; c++) {
+			if (cval->cmask & (1 << c)) {
+				err = get_cur_mix_value(cval, c + 1, &oval);
+				if (err < 0)
+					return err;
+				val = ucontrol->value.integer.value[cnt];
+				val = get_abs_value(cval, val);
+				if (oval != val) {
+					set_cur_mix_value(cval, c + 1, val);
+					changed = 1;
+				}
+				cnt++;
+			}
+		}
+	} else {
+		/* master channel */
+		err = get_cur_mix_value(cval, 0, &oval);
+		if (err < 0)
+			return err;
+		val = ucontrol->value.integer.value[0];
+		val = get_abs_value(cval, val);
+		if (val != oval) {
+			set_cur_mix_value(cval, 0, val);
+			changed = 1;
+		}
+	}
+	return changed;
+}
+
+static snd_kcontrol_new_t usb_feature_unit_ctl = {
+	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
+	name: "", /* will be filled later manually */
+	info: mixer_ctl_feature_info,
+	get: mixer_ctl_feature_get,
+	put: mixer_ctl_feature_put,
+};
+
+
+/*
+ * build a feature control
+ */
+
+static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
+			      unsigned int ctl_mask, int control,
+			      usb_audio_term_t *iterm, int unitid)
+{
+	int len = 0;
+	int nameid = desc[desc[0] - 1];
+	snd_kcontrol_t *kctl;
+	usb_mixer_elem_info_t *cval;
+
+	if (control == USB_FEATURE_GEQ) {
+		/* FIXME: not supported yet */
+		return;
+	}
+
+	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
+	if (! cval) {
+		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		return;
+	}
+	cval->chip = state->chip;
+	cval->ctrlif = state->ctrlif;
+	cval->id = unitid;
+	cval->control = control;
+	cval->cmask = ctl_mask;
+	cval->val_type = audio_feature_info[control].type;
+	if (ctl_mask == 0)
+		cval->channels = 1;	/* master channel */
+	else {
+		int i, c = 0;
+		for (i = 0; i < 16; i++)
+			if (ctl_mask & (1 << i))
+				c++;
+		cval->channels = c;
+	}
+
+	/* get min/max values */
+	if (cval->val_type == USB_MIXER_BOOLEAN ||
+	    cval->val_type == USB_MIXER_INV_BOOLEAN)
+		cval->max = 1;
+	else {
+		if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | (ctl_mask ? 1 : 0), &cval->max) < 0 ||
+		    get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | (ctl_mask ? 1 : 0), &cval->min) < 0) {
+			snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, control);
+			snd_magic_kfree(cval);
+			return;
+		}
+	}
+
+	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
+	if (! kctl) {
+		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_magic_kfree(cval);
+		return;
+	}
+	kctl->private_free = usb_mixer_elem_free;
+
+	if (nameid)
+		len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
+
+	switch (control) {
+	case USB_FEATURE_MUTE:
+	case USB_FEATURE_VOLUME:
+		/* determine the control name.  the rule is:
+		 * - if a name id is given in descriptor, use it.
+		 * - if the connected input can be determined, then use the name
+		 *   of terminal type.
+		 * - if the connected output can be determined, use it.
+		 * - otherwise, anonymous name.
+		 */
+		if (! nameid) {
+			len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 1);
+			if (! len)
+				len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1);
+			if (! len)
+				len = sprintf(kctl->id.name, "Feature %d", unitid);
+		}
+		/* determine the stream direction:
+		 * if the connected output is USB stream, then it's likely a
+		 * capture stream.  otherwise it should be playback (hopefully :)
+		 */
+		if (! (state->oterm.type >> 16)) {
+			if ((state->oterm.type & 0xff00) == 0x0100) {
+				strcpy(kctl->id.name + len, " Capture");
+				len += 8;
+			} else {
+				strcpy(kctl->id.name + len, " Playback");
+				len += 9;
+			}
+		}
+		strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume");
+		break;
+
+	default:
+		if (! nameid)
+			strcpy(kctl->id.name, audio_feature_info[control].name);
+		break;
+	}
+
+	snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d\n",
+		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
+	add_control_to_empty(state->chip->card, kctl);
+}
+
+
+
+/*
+ * parse a feature unit
+ *
+ * most of controlls are defined here.
+ */
+static int parse_audio_feature_unit(mixer_build_t *state, int unitid, unsigned char *ftr)
+{
+	int channels, i, j;
+	usb_audio_term_t iterm;
+	unsigned int master_bits, first_ch_bits;
+	int err, csize;
+
+	if (ftr[0] < 7 || ! (csize = ftr[5]) || ftr[0] < 7 + csize) {
+		snd_printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
+		return -EINVAL;
+	}
+
+	/* parse the source unit */
+	if ((err = parse_audio_unit(state, ftr[4])) < 0)
+		return err;
+
+	/* determine the input source type and name */
+	if (check_input_term(state, ftr[4], &iterm) < 0)
+		return -EINVAL;
+
+	channels = (ftr[0] - 7) / csize - 1;
+
+	master_bits = snd_usb_combine_bytes(ftr + 6, csize);
+	if (channels > 0)
+		first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize);
+	else
+		first_ch_bits = 0;
+	/* check all control types */
+	for (i = 0; i < 10; i++) {
+		unsigned int ch_bits = 0;
+		for (j = 0; j < channels; j++) {
+			unsigned int mask = snd_usb_combine_bytes(ftr + 6 + csize * (j+1), csize);
+			if (mask & (1 << i))
+				ch_bits |= (1 << j);
+		}
+		if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
+			build_feature_ctl(state, ftr, ch_bits, i, &iterm, unitid);
+		if (master_bits & (1 << i))
+			build_feature_ctl(state, ftr, 0, i, &iterm, unitid);
+	}
+	
+	return 0;
+}
+
+
+/*
+ * Mixer Unit
+ */
+
+/*
+ * build a mixer unit control
+ *
+ * the callbacks are identical with feature unit.
+ * input channel number (zero based) is given in control field instead.
+ */
+
+static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
+				 int in_ch, int unitid)
+{
+	usb_mixer_elem_info_t *cval;
+	int num_ins = desc[4];
+	int num_outs = desc[5 + num_ins];
+	int i, len;
+	snd_kcontrol_t *kctl;
+	usb_audio_term_t iterm;
+
+	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
+	if (! cval)
+		return;
+
+	if (check_input_term(state, desc[5 + in_ch], &iterm) < 0)
+		return;
+
+	cval->chip = state->chip;
+	cval->ctrlif = state->ctrlif;
+	cval->id = unitid;
+	cval->control = in_ch;
+	cval->val_type = USB_MIXER_S16;
+	for (i = 0; i < num_outs; i++) {
+		if (check_matrix_bitmap(desc + 9 + num_ins, in_ch, i, num_outs)) {
+			cval->cmask |= (1 << i);
+			cval->channels++;
+		}
+	}
+
+	/* get min/max values */
+	if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | 1, &cval->max) < 0 ||
+	    get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | 1, &cval->min) < 0) {
+		snd_printk(KERN_ERR "cannot get min/max values for mixer\n");
+		snd_magic_kfree(cval);
+		return;
+	}
+
+	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
+	if (! kctl) {
+		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_magic_kfree(cval);
+		return;
+	}
+	kctl->private_free = usb_mixer_elem_free;
+
+	len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0);
+	if (! len)
+		len = sprintf(kctl->id.name, "Mixer Source %d", in_ch);
+	strcpy(kctl->id.name + len, " Volume");
+
+	snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
+		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
+	add_control_to_empty(state->chip->card, kctl);
+}
+
+
+/*
+ * parse a mixer unit
+ */
+static int parse_audio_mixer_unit(mixer_build_t *state, int unitid, unsigned char *desc)
+{
+	int num_ins, num_outs;
+	int i, err;
+	if (desc[0] < 12 || ! (num_ins = desc[4]) || ! (num_outs = desc[5 + num_ins]))
+		return -EINVAL;
+
+	for (i = 0; i < num_ins; i++) {
+		err = parse_audio_unit(state, desc[5 + i]);
+		if (err < 0)
+			return err;
+		if (check_matrix_bitmap(desc + 9 + num_ins, i, 0, num_outs))
+			build_mixer_unit_ctl(state, desc, i, unitid);
+	}
+	return 0;
+}
+
+
+/*
+ * Processing Unit / Extension Unit
+ */
+
+/* get callback for processing/extension unit */
+static int mixer_ctl_procunit_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	int err, val;
+
+	err = get_cur_ctl_value(cval, cval->control, &val);
+	if (err < 0)
+		return err;
+	val = get_relative_value(cval, val);
+	ucontrol->value.integer.value[0] = val;
+	return 0;
+}
+
+/* put callback for processing/extension unit */
+static int mixer_ctl_procunit_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	int val, oval, err;
+
+	err = get_cur_ctl_value(cval, cval->control, &oval);
+	if (err < 0)
+		return err;
+	val = ucontrol->value.integer.value[0];
+	val = get_abs_value(cval, val);
+	if (val != oval) {
+		set_cur_ctl_value(cval, cval->control, val);
+		return 1;
+	}
+	return 0;
+}
+
+/* alsa control interface for processing/extension unit */
+static snd_kcontrol_new_t mixer_procunit_ctl = {
+	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
+	name: "", /* will be filled later */
+	info: mixer_ctl_feature_info,
+	get: mixer_ctl_procunit_get,
+	put: mixer_ctl_procunit_put,
+};
+
+
+/*
+ * predefined data for processing units
+ */
+struct procunit_value_info {
+	int control;
+	char *suffix;
+	int val_type;
+};
+
+struct procunit_info {
+	int type;
+	char *name;
+	struct procunit_value_info *values;
+};
+
+static struct procunit_value_info updown_proc_info[] = {
+	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+	{ 0x02, "Mode Select", USB_MIXER_U8 },
+	{ 0 }
+};
+static struct procunit_value_info prologic_proc_info[] = {
+	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+	{ 0x02, "Mode Select", USB_MIXER_U8 },
+	{ 0 }
+};
+static struct procunit_value_info threed_enh_proc_info[] = {
+	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+	{ 0x02, "Spaciousness", USB_MIXER_U8 },
+	{ 0 }
+};
+static struct procunit_value_info reverb_proc_info[] = {
+	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+	{ 0x02, "Level", USB_MIXER_U8 },
+	{ 0x03, "Time", USB_MIXER_U16 },
+	{ 0x04, "Delay", USB_MIXER_U8 },
+	{ 0 }
+};
+static struct procunit_value_info chorus_proc_info[] = {
+	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+	{ 0x02, "Level", USB_MIXER_U8 },
+	{ 0x03, "Rate", USB_MIXER_U16 },
+	{ 0x04, "Depth", USB_MIXER_U16 },
+	{ 0 }
+};
+static struct procunit_value_info dcr_proc_info[] = {
+	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+	{ 0x02, "Ratio", USB_MIXER_U16 },
+	{ 0x03, "Max Amp", USB_MIXER_S16 },
+	{ 0x04, "Threshold", USB_MIXER_S16 },
+	{ 0x05, "Attack Time", USB_MIXER_U16 },
+	{ 0x06, "Release Time", USB_MIXER_U16 },
+	{ 0 }
+};
+
+static struct procunit_info procunits[] = {
+	{ 0x01, "Up Down", updown_proc_info },
+	{ 0x02, "Dolby Prologic", prologic_proc_info },
+	{ 0x03, "3D Stereo Extender", threed_enh_proc_info },
+	{ 0x04, "Reverb", reverb_proc_info },
+	{ 0x05, "Chorus", chorus_proc_info },
+	{ 0x06, "DCR", dcr_proc_info },
+	{ 0 },
+};
+
+/*
+ * build a processing/extension unit
+ */
+static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char *dsc, struct procunit_info *list, char *name)
+{
+	int num_ins = dsc[6];
+	usb_mixer_elem_info_t *cval;
+	snd_kcontrol_t *kctl;
+	int i, err, nameid, type;
+	struct procunit_info *info;
+	struct procunit_value_info *valinfo;
+	static struct procunit_value_info default_value_info[] = {
+		{ 0x01, "Switch", USB_MIXER_BOOLEAN },
+		{ 0 }
+	};
+	static struct procunit_info default_info = {
+		0, NULL, default_value_info
+	};
+
+	if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) {
+		snd_printk(KERN_ERR "invalid %s descriptor %d\n", name, unitid);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_ins; i++) {
+		if ((err = parse_audio_unit(state, dsc[7 + i])) < 0)
+			return err;
+	}
+
+	type = combine_word(&dsc[4]);
+	if (! type)
+		return 0; /* undefined? */
+
+	for (info = list; info && info->type; info++)
+		if (info->type == type)
+			break;
+	if (! info || ! info->type)
+		info = &default_info;
+
+	for (valinfo = info->values; valinfo->control; valinfo++) {
+		/* FIXME: bitmap might be longer than 8bit */
+		if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1))))
+			continue;
+		cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
+		if (! cval) {
+			snd_printk(KERN_ERR "cannot malloc kcontrol");
+			return -ENOMEM;
+		}
+		cval->chip = state->chip;
+		cval->ctrlif = state->ctrlif;
+		cval->id = unitid;
+		cval->control = valinfo->control;
+		cval->val_type = valinfo->val_type;
+		cval->channels = 1;
+
+		/* get min/max values */
+		if (get_ctl_value(cval, GET_MAX, cval->control, &cval->max) < 0 ||
+		    get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0) {
+			snd_printk(KERN_ERR "cannot get min/max values for proc/ext unit\n");
+			snd_magic_kfree(cval);
+			continue;
+		}
+
+		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
+		if (! kctl) {
+			snd_printk(KERN_ERR "cannot malloc kcontrol");
+			snd_magic_kfree(cval);
+			return -ENOMEM;
+		}
+		kctl->private_free = usb_mixer_elem_free;
+
+		if (info->name)
+			sprintf(kctl->id.name, "%s %s", info->name, valinfo->suffix);
+		else {
+			nameid = dsc[12 + num_ins + dsc[11 + num_ins]];
+			if (nameid) {
+				int len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
+				strcpy(kctl->id.name + len, valinfo->suffix);
+			} else
+				sprintf(kctl->id.name, "%s %s", name, valinfo->suffix);
+		}
+
+		snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
+			    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
+		if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
+			return err;
+	}
+	return 0;
+}
+
+
+static int parse_audio_processing_unit(mixer_build_t *state, int unitid, unsigned char *desc)
+{
+	return build_audio_procunit(state, unitid, desc, procunits, "Processing Unit");
+}
+
+static int parse_audio_extension_unit(mixer_build_t *state, int unitid, unsigned char *desc)
+{
+	return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit");
+}
+
+
+/*
+ * Selector Unit
+ */
+
+/* info callback for selector unit
+ * use an enumerator type for routing
+ */
+static int mixer_ctl_selector_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{	
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	char **itemlist = (char **)kcontrol->private_value;
+
+	snd_assert(itemlist, return -EINVAL);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = cval->max;
+	if (uinfo->value.enumerated.item >= cval->max)
+		uinfo->value.enumerated.item = cval->max - 1;
+	strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+/* get callback for selector unit */
+static int mixer_ctl_selector_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	int val, err;
+
+	err = get_cur_ctl_value(cval, 0, &val);
+	if (err < 0)
+		return err;
+	val = get_relative_value(cval, val);
+	ucontrol->value.enumerated.item[0] = val;
+	return 0;
+}
+
+/* put callback for selector unit */
+static int mixer_ctl_selector_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kcontrol->private_data, return -EINVAL);
+	int val, oval, err;
+
+	err = get_cur_ctl_value(cval, 0, &oval);
+	if (err < 0)
+		return err;
+	val = ucontrol->value.enumerated.item[0];
+	val = get_abs_value(cval, val);
+	if (val != oval) {
+		set_cur_ctl_value(cval, 0, val);
+		return 1;
+	}
+	return 0;
+}
+
+/* alsa control interface for selector unit */
+static snd_kcontrol_new_t mixer_selectunit_ctl = {
+	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
+	name: "", /* will be filled later */
+	info: mixer_ctl_selector_info,
+	get: mixer_ctl_selector_get,
+	put: mixer_ctl_selector_put,
+};
+
+
+/* private free callback.
+ * free both private_data and private_value
+ */
+static void usb_mixer_selector_elem_free(snd_kcontrol_t *kctl)
+{
+	int i, num_ins = 0;
+
+	if (kctl->private_data) {
+		usb_mixer_elem_info_t *cval = snd_magic_cast(usb_mixer_elem_info_t, kctl->private_data,);
+		num_ins = cval->max;
+		snd_magic_kfree(cval);
+		kctl->private_data = 0;
+	}
+	if (kctl->private_value) {
+		char **itemlist = (char **)kctl->private_value;
+		for (i = 0; i < num_ins; i++)
+			kfree(itemlist[i]);
+		kfree(itemlist);
+		kctl->private_value = 0;
+	}
+}
+
+/*
+ * parse a selector unit
+ */
+static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned char *desc)
+{
+	int num_ins = desc[4];
+	int i, err, nameid;
+	usb_mixer_elem_info_t *cval;
+	snd_kcontrol_t *kctl;
+	char **namelist;
+
+	if (! num_ins || desc[0] < 6 + num_ins) {
+		snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_ins; i++) {
+		if ((err = parse_audio_unit(state, desc[5 + i])) < 0)
+			return err;
+	}
+
+	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
+	if (! cval) {
+		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		return -ENOMEM;
+	}
+	cval->chip = state->chip;
+	cval->ctrlif = state->ctrlif;
+	cval->id = unitid;
+	cval->val_type = USB_MIXER_U8;
+	cval->channels = 1;
+	cval->min = 1;
+	cval->max = num_ins;
+
+	namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL);
+	if (! namelist) {
+		snd_printk(KERN_ERR "cannot malloc\n");
+		snd_magic_kfree(cval);
+		return -ENOMEM;
+	}
+#define MAX_ITEM_NAME_LEN	64
+	for (i = 0; i < num_ins; i++) {
+		usb_audio_term_t iterm;
+		int len = 0;
+		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
+		if (! namelist[i]) {
+			snd_printk(KERN_ERR "cannot malloc\n");
+			while (--i > 0)
+				kfree(namelist[i]);
+			kfree(namelist);
+			snd_magic_kfree(cval);
+			return -ENOMEM;
+		}
+		if (check_input_term(state, desc[5 + i], &iterm) >= 0)
+			len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);
+		if (! len)
+			sprintf(namelist[i], "Input %d", i);
+	}
+
+	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
+	if (! kctl) {
+		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_magic_kfree(cval);
+		return -ENOMEM;
+	}
+	kctl->private_value = (unsigned long)namelist;
+	kctl->private_free = usb_mixer_selector_elem_free;
+
+	nameid = desc[desc[0] - 1];
+	if (nameid)
+		snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
+	else {
+		int len = get_term_name(state, &state->oterm,
+					kctl->id.name, sizeof(kctl->id.name), 0);
+		if (! len)
+			len = sprintf(kctl->id.name, "USB");
+		if ((state->oterm.type & 0xff00) == 0x0100)
+			strcpy(kctl->id.name + len, " Capture Source");
+		else
+			strcpy(kctl->id.name + len, " Playback Source");
+	}
+
+	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
+		    cval->id, kctl->id.name, num_ins);
+	if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
+		return err;
+
+	return 0;
+}
+
+
+/*
+ * parse an audio unit recursively
+ */
+
+static int parse_audio_unit(mixer_build_t *state, int unitid)
+{
+	unsigned char *p1;
+
+	if (test_and_set_bit(unitid, &state->unitbitmap))
+		return 0; /* the unit already visited */
+
+	p1 = find_audio_control_unit(state, unitid);
+	if (!p1) {
+		snd_printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
+		return -EINVAL;
+	}
+
+	switch (p1[2]) {
+	case INPUT_TERMINAL:
+		return 0; /* NOP */
+	case MIXER_UNIT:
+		return parse_audio_mixer_unit(state, unitid, p1);
+	case SELECTOR_UNIT:
+		return parse_audio_selector_unit(state, unitid, p1);
+	case FEATURE_UNIT:
+		return parse_audio_feature_unit(state, unitid, p1);
+	case PROCESSING_UNIT:
+		return parse_audio_processing_unit(state, unitid, p1);
+	case EXTENSION_UNIT:
+		return parse_audio_extension_unit(state, unitid, p1);
+	default:
+		snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+		return -EINVAL;
+	}
+}
+
+/*
+ * create mixer controls
+ *
+ * walk through all OUTPUT_TERMINAL descriptors to search for mixers
+ */
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, int buflen)
+{
+	unsigned char *desc;
+	mixer_build_t state;
+	int err;
+
+	strcpy(chip->card->mixername, "USB Mixer");
+
+	memset(&state, 0, sizeof(state));
+	state.chip = chip;
+	state.buffer = buffer;
+	state.buflen = buflen;
+	state.ctrlif = ctrlif;
+	desc = NULL;
+	while ((desc = snd_usb_find_csint_desc(buffer, buflen, desc, OUTPUT_TERMINAL, ctrlif, -1)) != NULL) {
+		if (desc[0] < 9)
+			continue; /* invalid descriptor? */
+		set_bit(desc[3], &state.unitbitmap);  /* mark terminal ID as visited */
+		state.oterm.id = desc[3];
+		state.oterm.type = combine_word(&desc[4]);
+		state.oterm.name = desc[8];
+		err = parse_audio_unit(&state, desc[7]);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}

===================================================================


This BitKeeper patch contains the following changesets:
1.647
## Wrapped with gzip_uu ##


begin 664 bkpatch22905
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
IU>9W]S*$=,0T<\M_$Q<=),S$2$?3N\-2^;I[$Y2ZR_\O,,=#D3Q$`@``
`
end
