caiaq endianness fix
[safe/jmp/linux-2.6] / sound / usb / usbaudio.c
index 076da19..410be4a 100644 (file)
  */
 
 
-#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 <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -63,11 +64,13 @@ MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;     /* Enable this card */
-static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
-static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
-static int nrpacks = 4;                /* max. number of packets per urb */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
+/* Vendor/product IDs for this card */
+static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
+static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
+static int nrpacks = 8;                /* max. number of packets per urb */
 static int async_unlink = 1;
+static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -79,10 +82,12 @@ module_param_array(vid, int, NULL, 0444);
 MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
 module_param_array(pid, int, NULL, 0444);
 MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
-module_param(nrpacks, int, 0444);
+module_param(nrpacks, int, 0644);
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
+module_param_array(device_setup, int, NULL, 0444);
+MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
 
 
 /*
@@ -95,16 +100,12 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
  *
  */
 
-#define MAX_PACKS      10
+#define MAX_PACKS      20
 #define MAX_PACKS_HS   (MAX_PACKS * 8) /* in high speed mode */
-#define MAX_URBS       5       /* max. 20ms long packets */
-#define SYNC_URBS      2       /* always two urbs for sync */
+#define MAX_URBS       8
+#define SYNC_URBS      4       /* always four 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 */
@@ -124,26 +125,27 @@ struct audioformat {
        unsigned int *rate_table;       /* rate table */
 };
 
+struct snd_usb_substream;
+
 struct snd_urb_ctx {
        struct urb *urb;
-       snd_usb_substream_t *subs;
+       unsigned int buffer_size;       /* size of data buffer, if data URB */
+       struct snd_usb_substream *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);
+       int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
+       int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
+       int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
+       int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
 };
 
 struct snd_usb_substream {
-       snd_usb_stream_t *stream;
+       struct snd_usb_stream *stream;
        struct usb_device *dev;
-       snd_pcm_substream_t *pcm_substream;
+       struct snd_pcm_substream *pcm_substream;
        int direction;  /* playback or capture */
        int interface;  /* current interface */
        int endpoint;   /* assigned endpoint */
@@ -153,6 +155,7 @@ struct snd_usb_substream {
        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 datainterval;      /* log_2 of data packet interval */
        unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
        unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */
        unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */
@@ -164,25 +167,25 @@ struct snd_usb_substream {
        unsigned int curframesize;      /* current packet size in frames (for capture) */
        unsigned int fill_max: 1;       /* fill max packet size always */
        unsigned int fmt_type;          /* USB audio format type (1-3) */
+       unsigned int packs_per_ms;      /* packets per millisecond (for playback) */
 
        unsigned int running: 1;        /* running status */
 
-       unsigned int hwptr;                     /* free frame position in the buffer (only for playback) */
        unsigned int hwptr_done;                        /* processed frame position in the buffer */
-       unsigned int transfer_sched;            /* scheduled frames since last period (for playback) */
        unsigned 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 */
 
        unsigned 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 * 4];    /* sync buffer; it's so small - let's get static */
-       char *tmpbuf;                   /* temporary buffer for playback */
+       struct snd_urb_ctx dataurb[MAX_URBS];   /* data urb table */
+       struct snd_urb_ctx syncurb[SYNC_URBS];  /* sync urb table */
+       char *syncbuf;                          /* sync buffer for all sync URBs */
+       dma_addr_t sync_dma;                    /* DMA address of syncbuf */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
        struct list_head fmt_list;      /* format list */
+       struct snd_pcm_hw_constraint_list rate_list;    /* limited rates */
        spinlock_t lock;
 
        struct snd_urb_ops ops;         /* callbacks (must be filled at init) */
@@ -190,11 +193,11 @@ struct snd_usb_substream {
 
 
 struct snd_usb_stream {
-       snd_usb_audio_t *chip;
-       snd_pcm_t *pcm;
+       struct snd_usb_audio *chip;
+       struct snd_pcm *pcm;
        int pcm_index;
        unsigned int fmt_type;          /* USB audio format type (1-3) */
-       snd_usb_substream_t substream[2];
+       struct snd_usb_substream substream[2];
        struct list_head list;
 };
 
@@ -204,15 +207,15 @@ struct snd_usb_stream {
  * 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];
+static DEFINE_MUTEX(register_mutex);
+static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
 
 
 /*
  * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
  * this will overflow at approx 524 kHz
  */
-inline static unsigned get_usb_full_speed_rate(unsigned int rate)
+static inline unsigned get_usb_full_speed_rate(unsigned int rate)
 {
        return ((rate << 13) + 62) / 125;
 }
@@ -221,19 +224,19 @@ inline static unsigned get_usb_full_speed_rate(unsigned int rate)
  * convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
  * this will overflow at approx 4 MHz
  */
-inline static unsigned get_usb_high_speed_rate(unsigned int rate)
+static inline unsigned get_usb_high_speed_rate(unsigned int rate)
 {
        return ((rate << 10) + 62) / 125;
 }
 
 /* convert our full speed USB rate into sampling rate in Hz */
-inline static unsigned get_full_speed_hz(unsigned int usb_rate)
+static inline unsigned get_full_speed_hz(unsigned int usb_rate)
 {
        return (usb_rate * 125 + (1 << 12)) >> 13;
 }
 
 /* convert our high speed USB rate into sampling rate in Hz */
-inline static unsigned get_high_speed_hz(unsigned int usb_rate)
+static inline unsigned get_high_speed_hz(unsigned int usb_rate)
 {
        return (usb_rate * 125 + (1 << 9)) >> 10;
 }
@@ -245,12 +248,12 @@ inline static unsigned get_high_speed_hz(unsigned int usb_rate)
  * 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,
+static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
+                                   struct snd_pcm_runtime *runtime,
                                    struct urb *urb)
 {
        unsigned char *cp = urb->transfer_buffer;
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       struct snd_urb_ctx *ctx = urb->context;
 
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
        urb->iso_frame_desc[0].length = 3;
@@ -267,12 +270,12 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs,
  * fill the length and offset of each urb descriptor.
  * the fixed 12.13 frequency is passed as 16.16 through the pipe.
  */
-static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs,
-                                      snd_pcm_runtime_t *runtime,
+static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
+                                      struct snd_pcm_runtime *runtime,
                                       struct urb *urb)
 {
        unsigned char *cp = urb->transfer_buffer;
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       struct snd_urb_ctx *ctx = urb->context;
 
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
        urb->iso_frame_desc[0].length = 4;
@@ -288,8 +291,8 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs,
  * process after capture sync complete
  * - nothing to do
  */
-static int retire_capture_sync_urb(snd_usb_substream_t *subs,
-                                  snd_pcm_runtime_t *runtime,
+static int retire_capture_sync_urb(struct snd_usb_substream *subs,
+                                  struct snd_pcm_runtime *runtime,
                                   struct urb *urb)
 {
        return 0;
@@ -305,42 +308,22 @@ static int retire_capture_sync_urb(snd_usb_substream_t *subs,
  * 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,
+static int prepare_capture_urb(struct snd_usb_substream *subs,
+                              struct snd_pcm_runtime *runtime,
                               struct urb *urb)
 {
        int i, offs;
-       unsigned long flags;
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       struct snd_urb_ctx *ctx = 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;
-#if 0 // for check
-       if (! urb->bandwidth) {
-               int bustime;
-               bustime = usb_check_bandwidth(urb->dev, urb);
-               if (bustime < 0)
-                       return bustime;
-               printk("urb %d: bandwidth = %d (packets = %d)\n", ctx->index, bustime, urb->number_of_packets);
-               usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-       }
-#endif // for check
+       urb->number_of_packets = ctx->packets;
        return 0;
 }
 
@@ -350,14 +333,15 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
  * 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,
+static int retire_capture_urb(struct snd_usb_substream *subs,
+                             struct snd_pcm_runtime *runtime,
                              struct urb *urb)
 {
        unsigned long flags;
        unsigned char *cp;
        int i;
        unsigned int stride, len, oldptr;
+       int period_elapsed = 0;
 
        stride = runtime->frame_bits >> 3;
 
@@ -377,6 +361,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
                if (subs->hwptr_done >= runtime->buffer_size)
                        subs->hwptr_done -= runtime->buffer_size;
                subs->transfer_done += len;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
+               }
                spin_unlock_irqrestore(&subs->lock, flags);
                /* copy a data chunk */
                if (oldptr + len > runtime->buffer_size) {
@@ -387,15 +375,19 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
                } 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);
        }
+       if (period_elapsed)
+               snd_pcm_period_elapsed(subs->pcm_substream);
+       return 0;
+}
+
+/*
+ * Process after capture complete when paused.  Nothing to do.
+ */
+static int retire_paused_capture_urb(struct snd_usb_substream *subs,
+                                    struct snd_pcm_runtime *runtime,
+                                    struct urb *urb)
+{
        return 0;
 }
 
@@ -406,11 +398,11 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
  * 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,
+static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
+                                    struct snd_pcm_runtime *runtime,
                                     struct urb *urb)
 {
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       struct snd_urb_ctx *ctx = urb->context;
 
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
        urb->iso_frame_desc[0].length = 3;
@@ -424,11 +416,11 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs,
  * set up the offset and length to receive the current frequency.
  */
 
-static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs,
-                                       snd_pcm_runtime_t *runtime,
+static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs,
+                                       struct snd_pcm_runtime *runtime,
                                        struct urb *urb)
 {
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       struct snd_urb_ctx *ctx = urb->context;
 
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
        urb->iso_frame_desc[0].length = 4;
@@ -442,8 +434,8 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs,
  * 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,
+static int retire_playback_sync_urb(struct snd_usb_substream *subs,
+                                   struct snd_pcm_runtime *runtime,
                                    struct urb *urb)
 {
        unsigned int f;
@@ -468,8 +460,8 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs,
  * retrieve the current 12.13 frequency from pipe, and set it.
  * the value is referred in prepare_playback_urb().
  */
-static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
-                                      snd_pcm_runtime_t *runtime,
+static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs,
+                                      struct snd_pcm_runtime *runtime,
                                       struct urb *urb)
 {
        unsigned int f;
@@ -489,23 +481,90 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
 }
 
 /*
+ * process after E-Mu 0202/0404 high speed playback sync complete
+ *
+ * These devices return the number of samples per packet instead of the number
+ * of samples per microframe.
+ */
+static int retire_playback_sync_urb_hs_emu(struct snd_usb_substream *subs,
+                                          struct snd_pcm_runtime *runtime,
+                                          struct urb *urb)
+{
+       unsigned int f;
+       unsigned long flags;
+
+       if (urb->iso_frame_desc[0].status == 0 &&
+           urb->iso_frame_desc[0].actual_length == 4) {
+               f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff;
+               f >>= subs->datainterval;
+               if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) {
+                       spin_lock_irqsave(&subs->lock, flags);
+                       subs->freqm = f;
+                       spin_unlock_irqrestore(&subs->lock, flags);
+               }
+       }
+
+       return 0;
+}
+
+/* determine the number of frames in the next packet */
+static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
+{
+       if (subs->fill_max)
+               return subs->maxframesize;
+       else {
+               subs->phase = (subs->phase & 0xffff)
+                       + (subs->freqm << subs->datainterval);
+               return min(subs->phase >> 16, subs->maxframesize);
+       }
+}
+
+/*
+ * Prepare urb for streaming before playback starts or when paused.
+ *
+ * We don't have any data, so we send a frame of silence.
+ */
+static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
+                                      struct snd_pcm_runtime *runtime,
+                                      struct urb *urb)
+{
+       unsigned int i, offs, counts;
+       struct snd_urb_ctx *ctx = urb->context;
+       int stride = runtime->frame_bits >> 3;
+
+       offs = 0;
+       urb->dev = ctx->subs->dev;
+       urb->number_of_packets = subs->packs_per_ms;
+       for (i = 0; i < subs->packs_per_ms; ++i) {
+               counts = snd_usb_audio_next_packet_size(subs);
+               urb->iso_frame_desc[i].offset = offs * stride;
+               urb->iso_frame_desc[i].length = counts * stride;
+               offs += counts;
+       }
+       urb->transfer_buffer_length = offs * stride;
+       memset(urb->transfer_buffer,
+              subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
+              offs * stride);
+       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,
+ * Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
+ */
+static int prepare_playback_urb(struct snd_usb_substream *subs,
+                               struct snd_pcm_runtime *runtime,
                                struct urb *urb)
 {
        int i, stride, offs;
        unsigned int counts;
        unsigned long flags;
-       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       int period_elapsed = 0;
+       struct snd_urb_ctx *ctx = urb->context;
 
        stride = runtime->frame_bits >> 3;
 
@@ -514,91 +573,74 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
        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 & 0xffff) + subs->freqm;
-                       counts = subs->phase >> 16;
-                       if (counts > subs->maxframesize)
-                               counts = subs->maxframesize;
-               }
+               counts = snd_usb_audio_next_packet_size(subs);
                /* 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;
+               subs->transfer_done += counts;
+               if (subs->transfer_done >= runtime->period_size) {
+                       subs->transfer_done -= runtime->period_size;
+                       period_elapsed = 1;
                        if (subs->fmt_type == USB_FORMAT_TYPE_II) {
-                               if (subs->transfer_sched > 0) {
-                                       /* FIXME: fill-max mode is not supported yet */
-                                       offs -= subs->transfer_sched;
-                                       counts -= subs->transfer_sched;
-                                       urb->iso_frame_desc[i].length = counts * stride;
-                                       subs->transfer_sched = 0;
+                               if (subs->transfer_done > 0) {
+                                       /* FIXME: fill-max mode is not
+                                        * supported yet */
+                                       offs -= subs->transfer_done;
+                                       counts -= subs->transfer_done;
+                                       urb->iso_frame_desc[i].length =
+                                               counts * stride;
+                                       subs->transfer_done = 0;
                                }
                                i++;
                                if (i < ctx->packets) {
                                        /* add a transfer delimiter */
-                                       urb->iso_frame_desc[i].offset = offs * stride;
+                                       urb->iso_frame_desc[i].offset =
+                                               offs * stride;
                                        urb->iso_frame_desc[i].length = 0;
                                        urb->number_of_packets++;
                                }
+                               break;
                        }
-                       break;
                }
+               /* finish at the frame boundary at/after the period boundary */
+               if (period_elapsed &&
+                   (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1)
+                       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;
+       if (subs->hwptr_done + offs > runtime->buffer_size) {
+               /* err, the transferred area goes over buffer boundary. */
+               unsigned int len = runtime->buffer_size - subs->hwptr_done;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done * stride,
+                      len * stride);
+               memcpy(urb->transfer_buffer + len * stride,
+                      runtime->dma_area,
+                      (offs - len) * stride);
        } else {
-               /* set the buffer pointer */
-               urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
-               subs->hwptr += offs;
-               if (subs->hwptr == runtime->buffer_size)
-                       subs->hwptr = 0;
+               memcpy(urb->transfer_buffer,
+                      runtime->dma_area + subs->hwptr_done * stride,
+                      offs * stride);
        }
+       subs->hwptr_done += offs;
+       if (subs->hwptr_done >= runtime->buffer_size)
+               subs->hwptr_done -= runtime->buffer_size;
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = offs * stride;
-       ctx->transfer = offs;
-
+       if (period_elapsed)
+               snd_pcm_period_elapsed(subs->pcm_substream);
        return 0;
 }
 
 /*
  * process after playback data complete
- *
- * update the current position and call callback if a period is processed.
+ * - nothing to do
  */
-static int retire_playback_urb(snd_usb_substream_t *subs,
-                              snd_pcm_runtime_t *runtime,
+static int retire_playback_urb(struct snd_usb_substream *subs,
+                              struct snd_pcm_runtime *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;
 }
 
@@ -607,7 +649,7 @@ static int retire_playback_urb(snd_usb_substream_t *subs,
  */
 static struct snd_urb_ops audio_urb_ops[2] = {
        {
-               .prepare =      prepare_playback_urb,
+               .prepare =      prepare_nodata_playback_urb,
                .retire =       retire_playback_urb,
                .prepare_sync = prepare_playback_sync_urb,
                .retire_sync =  retire_playback_sync_urb,
@@ -622,7 +664,7 @@ static struct snd_urb_ops audio_urb_ops[2] = {
 
 static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
        {
-               .prepare =      prepare_playback_urb,
+               .prepare =      prepare_nodata_playback_urb,
                .retire =       retire_playback_urb,
                .prepare_sync = prepare_playback_sync_urb_hs,
                .retire_sync =  retire_playback_sync_urb_hs,
@@ -638,15 +680,15 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
 /*
  * complete callback from data urb
  */
-static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
+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;
+       struct snd_urb_ctx *ctx = urb->context;
+       struct snd_usb_substream *subs = ctx->subs;
+       struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
        int err = 0;
 
        if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
-           ! subs->running || /* can be stopped during retire callback */
+           !subs->running || /* can be stopped during retire callback */
            (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
            (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
                clear_bit(ctx->index, &subs->active_mask);
@@ -661,15 +703,15 @@ static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
 /*
  * complete callback from sync urb
  */
-static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
+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;
+       struct snd_urb_ctx *ctx = urb->context;
+       struct snd_usb_substream *subs = ctx->subs;
+       struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
        int err = 0;
 
        if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
-           ! subs->running || /* can be stopped during retire callback */
+           !subs->running || /* can be stopped during retire callback */
            (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
            (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
                clear_bit(ctx->index + 16, &subs->active_mask);
@@ -681,10 +723,45 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
 }
 
 
+/* get the physical page pointer at the given offset */
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+                                            unsigned long offset)
+{
+       void *pageptr = subs->runtime->dma_area + offset;
+       return vmalloc_to_page(pageptr);
+}
+
+/* allocate virtual buffer; may be called more than once */
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size)
+{
+       struct snd_pcm_runtime *runtime = subs->runtime;
+       if (runtime->dma_area) {
+               if (runtime->dma_bytes >= size)
+                       return 0; /* already large enough */
+               vfree(runtime->dma_area);
+       }
+       runtime->dma_area = vmalloc(size);
+       if (!runtime->dma_area)
+               return -ENOMEM;
+       runtime->dma_bytes = size;
+       return 0;
+}
+
+/* free virtual buffer; may be called more than once */
+static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
+{
+       struct snd_pcm_runtime *runtime = subs->runtime;
+
+       vfree(runtime->dma_area);
+       runtime->dma_area = NULL;
+       return 0;
+}
+
+
 /*
  * unlink active urbs.
  */
-static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
+static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
 {
        unsigned int i;
        int async;
@@ -696,17 +773,16 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
 
        async = !can_sleep && async_unlink;
 
-       if (! async && in_interrupt())
+       if (!async && in_interrupt())
                return 0;
 
        for (i = 0; i < subs->nurbs; i++) {
                if (test_bit(i, &subs->active_mask)) {
-                       if (! test_and_set_bit(i, &subs->unlink_mask)) {
+                       if (!test_and_set_bit(i, &subs->unlink_mask)) {
                                struct urb *u = subs->dataurb[i].urb;
-                               if (async) {
-                                       u->transfer_flags |= URB_ASYNC_UNLINK;
+                               if (async)
                                        usb_unlink_urb(u);
-                               else
+                               else
                                        usb_kill_urb(u);
                        }
                }
@@ -714,12 +790,11 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
        if (subs->syncpipe) {
                for (i = 0; i < SYNC_URBS; i++) {
                        if (test_bit(i+16, &subs->active_mask)) {
-                               if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
+                               if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
                                        struct urb *u = subs->syncurb[i].urb;
-                                       if (async) {
-                                               u->transfer_flags |= URB_ASYNC_UNLINK;
+                                       if (async)
                                                usb_unlink_urb(u);
-                                       else
+                                       else
                                                usb_kill_urb(u);
                                }
                        }
@@ -729,10 +804,39 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
 }
 
 
+static const char *usb_error_string(int err)
+{
+       switch (err) {
+       case -ENODEV:
+               return "no device";
+       case -ENOENT:
+               return "endpoint not enabled";
+       case -EPIPE:
+               return "endpoint stalled";
+       case -ENOSPC:
+               return "not enough bandwidth";
+       case -ESHUTDOWN:
+               return "device disabled";
+       case -EHOSTUNREACH:
+               return "device suspended";
+#ifndef CONFIG_USB_EHCI_SPLIT_ISO
+       case -ENOSYS:
+               return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub";
+#endif
+       case -EINVAL:
+       case -EAGAIN:
+       case -EFBIG:
+       case -EMSGSIZE:
+               return "internal error";
+       default:
+               return "unknown error";
+       }
+}
+
 /*
  * set up and start data/sync urbs
  */
-static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
+static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
 {
        unsigned int i;
        int err;
@@ -761,16 +865,22 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
        subs->unlink_mask = 0;
        subs->running = 1;
        for (i = 0; i < subs->nurbs; i++) {
-               if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC)) < 0) {
-                       snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+               err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
+               if (err < 0) {
+                       snd_printk(KERN_ERR "cannot submit datapipe "
+                                  "for urb %d, error %d: %s\n",
+                                  i, err, usb_error_string(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_ATOMIC)) < 0) {
-                               snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err);
+                       err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
+                       if (err < 0) {
+                               snd_printk(KERN_ERR "cannot submit syncpipe "
+                                          "for urb %d, error %d: %s\n",
+                                          i, err, usb_error_string(err));
                                goto __error;
                        }
                        set_bit(i + 16, &subs->active_mask);
@@ -788,9 +898,9 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
 /*
  *  wait until all urbs are processed.
  */
-static int wait_clear_urbs(snd_usb_substream_t *subs)
+static int wait_clear_urbs(struct snd_usb_substream *subs)
 {
-       int timeout = HZ;
+       unsigned long end_time = jiffies + msecs_to_jiffies(1000);
        unsigned int i;
        int alive;
 
@@ -808,9 +918,8 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
                }
                if (! alive)
                        break;
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-       } while (--timeout > 0);
+               schedule_timeout_uninterruptible(1);
+       } while (time_before(jiffies, end_time));
        if (alive)
                snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
        return 0;
@@ -820,55 +929,87 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
 /*
  * 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)
+static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
-       return subs->hwptr_done;
+       struct snd_usb_substream *subs;
+       snd_pcm_uframes_t hwptr_done;
+       
+       subs = (struct snd_usb_substream *)substream->runtime->private_data;
+       spin_lock(&subs->lock);
+       hwptr_done = subs->hwptr_done;
+       spin_unlock(&subs->lock);
+       return hwptr_done;
 }
 
 
 /*
- * start/stop substream
+ * start/stop playback substream
  */
-static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+static int snd_usb_pcm_playback_trigger(struct snd_pcm_substream *substream,
+                                       int cmd)
 {
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
-       int err;
+       struct snd_usb_substream *subs = substream->runtime->private_data;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               err = start_urbs(subs, substream->runtime);
-               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               subs->ops.prepare = prepare_playback_urb;
+               return 0;
        case SNDRV_PCM_TRIGGER_STOP:
-               err = deactivate_urbs(subs, 0, 0);
-               break;
+               return deactivate_urbs(subs, 0, 0);
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               subs->ops.prepare = prepare_nodata_playback_urb;
+               return 0;
        default:
-               err = -EINVAL;
-               break;
+               return -EINVAL;
+       }
+}
+
+/*
+ * start/stop capture substream
+ */
+static int snd_usb_pcm_capture_trigger(struct snd_pcm_substream *substream,
+                                      int cmd)
+{
+       struct snd_usb_substream *subs = substream->runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               subs->ops.retire = retire_capture_urb;
+               return start_urbs(subs, substream->runtime);
+       case SNDRV_PCM_TRIGGER_STOP:
+               return deactivate_urbs(subs, 0, 0);
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               subs->ops.retire = retire_paused_capture_urb;
+               return 0;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               subs->ops.retire = retire_capture_urb;
+               return 0;
+       default:
+               return -EINVAL;
        }
-       return err < 0 ? err : 0;
 }
 
 
 /*
  * release a urb data
  */
-static void release_urb_ctx(snd_urb_ctx_t *u)
+static void release_urb_ctx(struct snd_urb_ctx *u)
 {
        if (u->urb) {
+               if (u->buffer_size)
+                       usb_buffer_free(u->subs->dev, u->buffer_size,
+                                       u->urb->transfer_buffer,
+                                       u->urb->transfer_dma);
                usb_free_urb(u->urb);
                u->urb = NULL;
        }
-       if (u->buf) {
-               kfree(u->buf);
-               u->buf = NULL;
-       }
 }
 
 /*
  * release a substream
  */
-static void release_substream_urbs(snd_usb_substream_t *subs, int force)
+static void release_substream_urbs(struct snd_usb_substream *subs, int force)
 {
        int i;
 
@@ -880,22 +1021,21 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
                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 = NULL;
-       }
+       usb_buffer_free(subs->dev, SYNC_URBS * 4,
+                       subs->syncbuf, subs->sync_dma);
+       subs->syncbuf = NULL;
        subs->nurbs = 0;
 }
 
 /*
  * initialize a substream for plaback/capture
  */
-static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_bytes,
+static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes,
                               unsigned int rate, unsigned int frame_bits)
 {
        unsigned int maxsize, n, i;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int npacks[MAX_URBS], urb_packs, total_packs;
+       unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
 
        /* calculate the frequency in 16.16 format */
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -903,40 +1043,59 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
        else
                subs->freqn = get_usb_high_speed_rate(rate);
        subs->freqm = subs->freqn;
-       subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
-       subs->phase = 0;
-
-       /* calculate the max. size of packet */
-       maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16;
-       if (subs->maxpacksize && maxsize > subs->maxpacksize) {
-               //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
-               //         maxsize, subs->maxpacksize);
+       /* calculate max. frequency */
+       if (subs->maxpacksize) {
+               /* whatever fits into a max. size packet */
                maxsize = subs->maxpacksize;
+               subs->freqmax = (maxsize / (frame_bits >> 3))
+                               << (16 - subs->datainterval);
+       } else {
+               /* no max. packet size: just take 25% higher than nominal */
+               subs->freqmax = subs->freqn + (subs->freqn >> 2);
+               maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
+                               >> (16 - subs->datainterval);
        }
+       subs->phase = 0;
 
        if (subs->fill_max)
                subs->curpacksize = subs->maxpacksize;
        else
                subs->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
-               urb_packs = nrpacks;
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+               packs_per_ms = 8 >> subs->datainterval;
        else
-               urb_packs = nrpacks * 8;
+               packs_per_ms = 1;
+       subs->packs_per_ms = packs_per_ms;
 
-       /* allocate a temporary buffer for playback */
        if (is_playback) {
-               subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
-               if (! subs->tmpbuf) {
-                       snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
-                       return -ENOMEM;
-               }
-       }
+               urb_packs = nrpacks;
+               urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
+               urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
+       } else
+               urb_packs = 1;
+       urb_packs *= packs_per_ms;
 
        /* decide how many packets to be used */
-       total_packs = (period_bytes + maxsize - 1) / maxsize;
-       if (total_packs < 2 * MIN_PACKS_URB)
-               total_packs = 2 * MIN_PACKS_URB;
+       if (is_playback) {
+               unsigned int minsize;
+               /* determine how small a packet can be */
+               minsize = (subs->freqn >> (16 - subs->datainterval))
+                         * (frame_bits >> 3);
+               /* with sync from device, assume it can be 12% lower */
+               if (subs->syncpipe)
+                       minsize -= minsize >> 3;
+               minsize = max(minsize, 1u);
+               total_packs = (period_bytes + minsize - 1) / minsize;
+               /* round up to multiple of packs_per_ms */
+               total_packs = (total_packs + packs_per_ms - 1)
+                               & ~(packs_per_ms - 1);
+               /* we need at least two URBs for queueing */
+               if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
+                       total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+       } else {
+               total_packs = MAX_URBS * urb_packs;
+       }
        subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
        if (subs->nurbs > MAX_URBS) {
                /* too much... */
@@ -955,7 +1114,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                subs->nurbs = 2;
                npacks[0] = (total_packs + 1) / 2;
                npacks[1] = total_packs - npacks[0];
-       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) {
+       } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
                /* the last packet is too small.. */
                if (subs->nurbs > 2) {
                        /* merge to the first one */
@@ -971,66 +1130,66 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
 
        /* allocate and initialize data urbs */
        for (i = 0; i < subs->nurbs; i++) {
-               snd_urb_ctx_t *u = &subs->dataurb[i];
+               struct snd_urb_ctx *u = &subs->dataurb[i];
                u->index = i;
                u->subs = subs;
-               u->transfer = 0;
                u->packets = npacks[i];
+               u->buffer_size = maxsize * u->packets;
                if (subs->fmt_type == USB_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
-               if (! is_playback) {
-                       /* allocate a capture buffer per urb */
-                       u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
-                       if (! u->buf) {
-                               release_substream_urbs(subs, 0);
-                               return -ENOMEM;
-                       }
-               }
                u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
-               if (! u->urb) {
-                       release_substream_urbs(subs, 0);
-                       return -ENOMEM;
-               }
-               u->urb->dev = subs->dev;
+               if (!u->urb)
+                       goto out_of_memory;
+               u->urb->transfer_buffer =
+                       usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
+                                        &u->urb->transfer_dma);
+               if (!u->urb->transfer_buffer)
+                       goto out_of_memory;
                u->urb->pipe = subs->datapipe;
-               u->urb->transfer_flags = URB_ISO_ASAP;
-               u->urb->number_of_packets = u->packets;
-               u->urb->interval = 1;
+               u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               u->urb->interval = 1 << subs->datainterval;
                u->urb->context = u;
-               u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
+               u->urb->complete = snd_complete_urb;
        }
 
        if (subs->syncpipe) {
                /* allocate and initialize sync urbs */
+               subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
+                                                GFP_KERNEL, &subs->sync_dma);
+               if (!subs->syncbuf)
+                       goto out_of_memory;
                for (i = 0; i < SYNC_URBS; i++) {
-                       snd_urb_ctx_t *u = &subs->syncurb[i];
+                       struct snd_urb_ctx *u = &subs->syncurb[i];
                        u->index = i;
                        u->subs = subs;
                        u->packets = 1;
                        u->urb = usb_alloc_urb(1, GFP_KERNEL);
-                       if (! u->urb) {
-                               release_substream_urbs(subs, 0);
-                               return -ENOMEM;
-                       }
+                       if (!u->urb)
+                               goto out_of_memory;
                        u->urb->transfer_buffer = subs->syncbuf + i * 4;
+                       u->urb->transfer_dma = subs->sync_dma + i * 4;
                        u->urb->transfer_buffer_length = 4;
-                       u->urb->dev = subs->dev;
                        u->urb->pipe = subs->syncpipe;
-                       u->urb->transfer_flags = URB_ISO_ASAP;
+                       u->urb->transfer_flags = URB_ISO_ASAP |
+                                                URB_NO_TRANSFER_DMA_MAP;
                        u->urb->number_of_packets = 1;
                        u->urb->interval = 1 << subs->syncinterval;
                        u->urb->context = u;
-                       u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb);
+                       u->urb->complete = snd_complete_sync_urb;
                }
        }
        return 0;
+
+out_of_memory:
+       release_substream_urbs(subs, 0);
+       return -ENOMEM;
 }
 
 
 /*
  * find a matching audio format
  */
-static struct audioformat *find_format(snd_usb_substream_t *subs, unsigned int format,
+static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format,
                                       unsigned int rate, unsigned int channels)
 {
        struct list_head *p;
@@ -1155,7 +1314,7 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
 /*
  * find a matching format and set up the interface
  */
-static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
+static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 {
        struct usb_device *dev = subs->dev;
        struct usb_host_interface *alts;
@@ -1176,7 +1335,11 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
 
        /* close the old interface */
        if (subs->interface >= 0 && subs->interface != fmt->iface) {
-               usb_set_interface(subs->dev, subs->interface, 0);
+               if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
+                       snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n",
+                               dev->devnum, fmt->iface, fmt->altsetting);
+                       return -EIO;
+               }
                subs->interface = -1;
                subs->format = 0;
        }
@@ -1199,6 +1362,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
                subs->datapipe = usb_sndisocpipe(dev, ep);
        else
                subs->datapipe = usb_rcvisocpipe(dev, ep);
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH &&
+           get_endpoint(alts, 0)->bInterval >= 1 &&
+           get_endpoint(alts, 0)->bInterval <= 4)
+               subs->datainterval = get_endpoint(alts, 0)->bInterval - 1;
+       else
+               subs->datainterval = 0;
        subs->syncpipe = subs->syncinterval = 0;
        subs->maxpacksize = fmt->maxpacksize;
        subs->fill_max = 0;
@@ -1240,8 +1409,13 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
                    get_endpoint(alts, 1)->bRefresh >= 1 &&
                    get_endpoint(alts, 1)->bRefresh <= 9)
                        subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
-               else
+               else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
                        subs->syncinterval = 1;
+               else if (get_endpoint(alts, 1)->bInterval >= 1 &&
+                        get_endpoint(alts, 1)->bInterval <= 16)
+                       subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+               else
+                       subs->syncinterval = 3;
        }
 
        /* always fill max packet size */
@@ -1254,8 +1428,8 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
        subs->cur_audiofmt = fmt;
 
 #if 0
-       printk("setting done: format = %d, rate = %d, channels = %d\n",
-              fmt->format, fmt->rate, fmt->channels);
+       printk("setting done: format = %d, rate = %d..%d, channels = %d\n",
+              fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
        printk("  datapipe = 0x%0x, syncpipe = 0x%0x\n",
               subs->datapipe, subs->syncpipe);
 #endif
@@ -1273,15 +1447,16 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
  * 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)
+static int snd_usb_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
 {
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
+       struct snd_usb_substream *subs = substream->runtime->private_data;
        struct audioformat *fmt;
        unsigned int channels, rate, format;
        int ret, changed;
 
-       ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+       ret = snd_pcm_alloc_vmalloc_buffer(substream,
+                                          params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
 
@@ -1289,9 +1464,9 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
        rate = params_rate(hw_params);
        channels = params_channels(hw_params);
        fmt = find_format(subs, format, rate, channels);
-       if (! fmt) {
-               snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
-                          snd_pcm_format_name(format), rate, channels);
+       if (!fmt) {
+               snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
+                          format, rate, channels);
                return -EINVAL;
        }
 
@@ -1329,15 +1504,16 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
  *
  * reset the audio format and release the buffer
  */
-static int snd_usb_hw_free(snd_pcm_substream_t *substream)
+static int snd_usb_hw_free(struct snd_pcm_substream *substream)
 {
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
+       struct snd_usb_substream *subs = substream->runtime->private_data;
 
        subs->cur_audiofmt = NULL;
        subs->cur_rate = 0;
        subs->period_bytes = 0;
-       release_substream_urbs(subs, 0);
-       return snd_pcm_lib_free_pages(substream);
+       if (!subs->stream->chip->shutdown)
+               release_substream_urbs(subs, 0);
+       return snd_pcm_free_vmalloc_buffer(substream);
 }
 
 /*
@@ -1345,10 +1521,10 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
  *
  * only a few subtle things...
  */
-static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
+static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       snd_pcm_runtime_t *runtime = substream->runtime;
-       snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_usb_substream *subs = runtime->private_data;
 
        if (! subs->cur_audiofmt) {
                snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
@@ -1360,9 +1536,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
        subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
 
        /* reset the pointer */
-       subs->hwptr = 0;
        subs->hwptr_done = 0;
-       subs->transfer_sched = 0;
        subs->transfer_done = 0;
        subs->phase = 0;
 
@@ -1370,29 +1544,26 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
        deactivate_urbs(subs, 0, 1);
        wait_clear_urbs(subs);
 
-       return 0;
+       /* for playback, submit the URBs now; otherwise, the first hwptr_done
+        * updates for all URBs would happen at the same time when starting */
+       if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+               subs->ops.prepare = prepare_nodata_playback_urb;
+               return start_urbs(subs, runtime);
+       } else
+               return 0;
 }
 
-static snd_pcm_hardware_t snd_usb_playback =
+static struct snd_pcm_hardware snd_usb_hardware =
 {
-       .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                SNDRV_PCM_INFO_MMAP_VALID),
-       .buffer_bytes_max =     (128*1024),
+       .info =                 SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_BATCH |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                               SNDRV_PCM_INFO_PAUSE,
+       .buffer_bytes_max =     1024 * 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),
+       .period_bytes_max =     512 * 1024,
        .periods_min =          2,
        .periods_max =          1024,
 };
@@ -1407,14 +1578,14 @@ static snd_pcm_hardware_t snd_usb_capture =
 #define hwc_debug(fmt, args...) /**/
 #endif
 
-static int hw_check_valid_format(snd_pcm_hw_params_t *params, struct audioformat *fp)
+static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audioformat *fp)
 {
-       snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-       snd_interval_t *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-       snd_mask_t *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 
        /* check the format */
-       if (! snd_mask_test(fmts, fp->format)) {
+       if (!snd_mask_test(fmts, fp->format)) {
                hwc_debug("   > check: no supported format %d\n", fp->format);
                return 0;
        }
@@ -1435,12 +1606,12 @@ static int hw_check_valid_format(snd_pcm_hw_params_t *params, struct audioformat
        return 1;
 }
 
-static int hw_rule_rate(snd_pcm_hw_params_t *params,
-                       snd_pcm_hw_rule_t *rule)
+static int hw_rule_rate(struct snd_pcm_hw_params *params,
+                       struct snd_pcm_hw_rule *rule)
 {
-       snd_usb_substream_t *subs = rule->private;
+       struct snd_usb_substream *subs = rule->private;
        struct list_head *p;
-       snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        unsigned int rmin, rmax;
        int changed;
 
@@ -1450,7 +1621,7 @@ static int hw_rule_rate(snd_pcm_hw_params_t *params,
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (! hw_check_valid_format(params, fp))
+               if (!hw_check_valid_format(params, fp))
                        continue;
                if (changed++) {
                        if (rmin > fp->rate_min)
@@ -1463,7 +1634,7 @@ static int hw_rule_rate(snd_pcm_hw_params_t *params,
                }
        }
 
-       if (! changed) {
+       if (!changed) {
                hwc_debug("  --> get empty\n");
                it->empty = 1;
                return -EINVAL;
@@ -1489,12 +1660,12 @@ static int hw_rule_rate(snd_pcm_hw_params_t *params,
 }
 
 
-static int hw_rule_channels(snd_pcm_hw_params_t *params,
-                           snd_pcm_hw_rule_t *rule)
+static int hw_rule_channels(struct snd_pcm_hw_params *params,
+                           struct snd_pcm_hw_rule *rule)
 {
-       snd_usb_substream_t *subs = rule->private;
+       struct snd_usb_substream *subs = rule->private;
        struct list_head *p;
-       snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+       struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        unsigned int rmin, rmax;
        int changed;
 
@@ -1504,7 +1675,7 @@ static int hw_rule_channels(snd_pcm_hw_params_t *params,
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (! hw_check_valid_format(params, fp))
+               if (!hw_check_valid_format(params, fp))
                        continue;
                if (changed++) {
                        if (rmin > fp->channels)
@@ -1517,7 +1688,7 @@ static int hw_rule_channels(snd_pcm_hw_params_t *params,
                }
        }
 
-       if (! changed) {
+       if (!changed) {
                hwc_debug("  --> get empty\n");
                it->empty = 1;
                return -EINVAL;
@@ -1542,12 +1713,12 @@ static int hw_rule_channels(snd_pcm_hw_params_t *params,
        return changed;
 }
 
-static int hw_rule_format(snd_pcm_hw_params_t *params,
-                         snd_pcm_hw_rule_t *rule)
+static int hw_rule_format(struct snd_pcm_hw_params *params,
+                         struct snd_pcm_hw_rule *rule)
 {
-       snd_usb_substream_t *subs = rule->private;
+       struct snd_usb_substream *subs = rule->private;
        struct list_head *p;
-       snd_mask_t *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
        u64 fbits;
        u32 oldbits[2];
        int changed;
@@ -1557,7 +1728,7 @@ static int hw_rule_format(snd_pcm_hw_params_t *params,
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (! hw_check_valid_format(params, fp))
+               if (!hw_check_valid_format(params, fp))
                        continue;
                fbits |= (1ULL << fp->format);
        }
@@ -1566,7 +1737,7 @@ static int hw_rule_format(snd_pcm_hw_params_t *params,
        oldbits[1] = fmt->bits[1];
        fmt->bits[0] &= (u32)fbits;
        fmt->bits[1] &= (u32)(fbits >> 32);
-       if (! fmt->bits[0] && ! fmt->bits[1]) {
+       if (!fmt->bits[0] && !fmt->bits[1]) {
                hwc_debug("  --> get empty\n");
                return -EINVAL;
        }
@@ -1580,7 +1751,7 @@ static int hw_rule_format(snd_pcm_hw_params_t *params,
 /*
  * check whether the registered audio formats need special hw-constraints
  */
-static int check_hw_params_convention(snd_usb_substream_t *subs)
+static int check_hw_params_convention(struct snd_usb_substream *subs)
 {
        int i;
        u32 *channels;
@@ -1592,6 +1763,10 @@ static int check_hw_params_convention(snd_usb_substream_t *subs)
 
        channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
        rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL);
+       if (!channels || !rates) {
+               err = -ENOMEM;
+               goto __out;
+       }
 
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *f;
@@ -1619,6 +1794,9 @@ static int check_hw_params_convention(snd_usb_substream_t *subs)
                }
                channels[f->format] |= (1 << f->channels);
                rates[f->format] |= f->rates;
+               /* needs knot? */
+               if (f->rates & SNDRV_PCM_RATE_KNOT)
+                       goto __out;
        }
        /* check whether channels and rates match for all formats */
        cmaster = rmaster = 0;
@@ -1659,12 +1837,49 @@ static int check_hw_params_convention(snd_usb_substream_t *subs)
        return err;
 }
 
+/*
+ *  If the device supports unusual bit rates, does the request meet these?
+ */
+static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
+                                 struct snd_usb_substream *subs)
+{
+       struct audioformat *fp;
+       int count = 0, needs_knot = 0;
+       int err;
+
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
+                       return 0;
+               count += fp->nr_rates;
+               if (fp->rates & SNDRV_PCM_RATE_KNOT)
+                       needs_knot = 1;
+       }
+       if (!needs_knot)
+               return 0;
+
+       subs->rate_list.count = count;
+       subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+       subs->rate_list.mask = 0;
+       count = 0;
+       list_for_each_entry(fp, &subs->fmt_list, list) {
+               int i;
+               for (i = 0; i < fp->nr_rates; i++)
+                       subs->rate_list.list[count++] = fp->rate_table[i];
+       }
+       err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                        &subs->rate_list);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 
 /*
  * set up the runtime hardware information.
  */
 
-static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
+static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)
 {
        struct list_head *p;
        int err;
@@ -1697,11 +1912,17 @@ static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
        }
 
        /* set the period time minimum 1ms */
+       /* FIXME: high-speed mode allows 125us minimum period, but many parts
+        * in the current code assume the 1ms period.
+        */
        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
                                     1000 * MIN_PACKS_URB,
                                     /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX);
 
-       if (check_hw_params_convention(subs)) {
+       err = check_hw_params_convention(subs);
+       if (err < 0)
+               return err;
+       else if (err) {
                hwc_debug("setting extra hw constraints...\n");
                if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                               hw_rule_rate, subs,
@@ -1721,29 +1942,30 @@ static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
                                               SNDRV_PCM_HW_PARAM_CHANNELS,
                                               -1)) < 0)
                        return err;
+               if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
+                       return err;
        }
        return 0;
 }
 
-static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction,
-                           snd_pcm_hardware_t *hw)
+static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
 {
-       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];
+       struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_usb_substream *subs = &as->substream[direction];
 
        subs->interface = -1;
        subs->format = 0;
-       runtime->hw = *hw;
+       runtime->hw = snd_usb_hardware;
        runtime->private_data = subs;
        subs->pcm_substream = substream;
        return setup_hw_info(runtime, subs);
 }
 
-static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction)
+static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
 {
-       snd_usb_stream_t *as = snd_pcm_substream_chip(substream);
-       snd_usb_substream_t *subs = &as->substream[direction];
+       struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
+       struct snd_usb_substream *subs = &as->substream[direction];
 
        if (subs->interface >= 0) {
                usb_set_interface(subs->dev, subs->interface, 0);
@@ -1753,46 +1975,48 @@ static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction)
        return 0;
 }
 
-static int snd_usb_playback_open(snd_pcm_substream_t *substream)
+static int snd_usb_playback_open(struct snd_pcm_substream *substream)
 {
-       return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback);
+       return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
-static int snd_usb_playback_close(snd_pcm_substream_t *substream)
+static int snd_usb_playback_close(struct snd_pcm_substream *substream)
 {
        return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
-static int snd_usb_capture_open(snd_pcm_substream_t *substream)
+static int snd_usb_capture_open(struct snd_pcm_substream *substream)
 {
-       return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture);
+       return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE);
 }
 
-static int snd_usb_capture_close(snd_pcm_substream_t *substream)
+static int snd_usb_capture_close(struct snd_pcm_substream *substream)
 {
        return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
 }
 
-static snd_pcm_ops_t snd_usb_playback_ops = {
+static struct snd_pcm_ops 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,
+       .trigger =      snd_usb_pcm_playback_trigger,
        .pointer =      snd_usb_pcm_pointer,
+       .page =         snd_pcm_get_vmalloc_page,
 };
 
-static snd_pcm_ops_t snd_usb_capture_ops = {
+static struct snd_pcm_ops 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,
+       .trigger =      snd_usb_pcm_capture_trigger,
        .pointer =      snd_usb_pcm_pointer,
+       .page =         snd_pcm_get_vmalloc_page,
 };
 
 
@@ -1866,10 +2090,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
        void *buf = NULL;
 
        if (size > 0) {
-               buf = kmalloc(size, GFP_KERNEL);
+               buf = kmemdup(data, size, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
-               memcpy(buf, data, size);
        }
        err = usb_control_msg(dev, pipe, request, requesttype,
                              value, index, buf, size, timeout);
@@ -1889,6 +2112,14 @@ static int usb_audio_probe(struct usb_interface *intf,
                           const struct usb_device_id *id);
 static void usb_audio_disconnect(struct usb_interface *intf);
 
+#ifdef CONFIG_PM
+static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message);
+static int usb_audio_resume(struct usb_interface *intf);
+#else
+#define usb_audio_suspend NULL
+#define usb_audio_resume NULL
+#endif
+
 static struct usb_device_id usb_audio_ids [] = {
 #include "usbquirks.h"
     { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
@@ -1900,18 +2131,21 @@ static struct usb_device_id usb_audio_ids [] = {
 MODULE_DEVICE_TABLE (usb, usb_audio_ids);
 
 static struct usb_driver usb_audio_driver = {
-       .owner =        THIS_MODULE,
        .name =         "snd-usb-audio",
        .probe =        usb_audio_probe,
        .disconnect =   usb_audio_disconnect,
+       .suspend =      usb_audio_suspend,
+       .resume =       usb_audio_resume,
        .id_table =     usb_audio_ids,
 };
 
 
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
 /*
  * proc interface for list the supported pcm formats
  */
-static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buffer_t *buffer)
+static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
 {
        struct list_head *p;
        static char *sync_types[4] = {
@@ -1923,7 +2157,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff
                fp = list_entry(p, struct audioformat, list);
                snd_iprintf(buffer, "  Interface %d\n", fp->iface);
                snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
-               snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
+               snd_iprintf(buffer, "    Format: 0x%x\n", fp->format);
                snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
                            fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
@@ -1947,7 +2181,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff
        }
 }
 
-static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffer_t *buffer)
+static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
 {
        if (subs->running) {
                unsigned int i;
@@ -1969,9 +2203,9 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe
        }
 }
 
-static void proc_pcm_format_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       snd_usb_stream_t *stream = entry->private_data;
+       struct snd_usb_stream *stream = entry->private_data;
 
        snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name);
 
@@ -1987,25 +2221,32 @@ static void proc_pcm_format_read(snd_info_entry_t *entry, snd_info_buffer_t *buf
        }
 }
 
-static void proc_pcm_format_add(snd_usb_stream_t *stream)
+static void proc_pcm_format_add(struct snd_usb_stream *stream)
 {
-       snd_info_entry_t *entry;
+       struct snd_info_entry *entry;
        char name[32];
-       snd_card_t *card = stream->chip->card;
+       struct snd_card *card = stream->chip->card;
 
        sprintf(name, "stream%d", stream->pcm_index);
-       if (! snd_card_proc_new(card, name, &entry))
-               snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read);
+       if (!snd_card_proc_new(card, name, &entry))
+               snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
 }
 
+#else
+
+static inline void proc_pcm_format_add(struct snd_usb_stream *stream)
+{
+}
+
+#endif
 
 /*
  * initialize the substream instance.
  */
 
-static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat *fp)
+static void init_substream(struct snd_usb_stream *as, int stream, struct audioformat *fp)
 {
-       snd_usb_substream_t *subs = &as->substream[stream];
+       struct snd_usb_substream *subs = &as->substream[stream];
 
        INIT_LIST_HEAD(&subs->fmt_list);
        spin_lock_init(&subs->lock);
@@ -2013,14 +2254,17 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
        subs->stream = as;
        subs->direction = stream;
        subs->dev = as->chip->dev;
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) {
                subs->ops = audio_urb_ops[stream];
-       else
+       } else {
                subs->ops = audio_urb_ops_high_speed[stream];
-       snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
-                                     SNDRV_DMA_TYPE_CONTINUOUS,
-                                     snd_dma_continuous_data(GFP_KERNEL),
-                                     64 * 1024, 128 * 1024);
+               switch (as->chip->usb_id) {
+               case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
+               case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
+                       subs->ops.retire_sync = retire_playback_sync_urb_hs_emu;
+                       break;
+               }
+       }
        snd_pcm_set_ops(as->pcm, stream,
                        stream == SNDRV_PCM_STREAM_PLAYBACK ?
                        &snd_usb_playback_ops : &snd_usb_capture_ops);
@@ -2036,24 +2280,25 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
 /*
  * free a substream
  */
-static void free_substream(snd_usb_substream_t *subs)
+static void free_substream(struct snd_usb_substream *subs)
 {
        struct list_head *p, *n;
 
-       if (! subs->num_formats)
+       if (!subs->num_formats)
                return; /* not initialized */
        list_for_each_safe(p, n, &subs->fmt_list) {
                struct audioformat *fp = list_entry(p, struct audioformat, list);
                kfree(fp->rate_table);
                kfree(fp);
        }
+       kfree(subs->rate_list.list);
 }
 
 
 /*
  * free a usb stream instance
  */
-static void snd_usb_audio_stream_free(snd_usb_stream_t *stream)
+static void snd_usb_audio_stream_free(struct snd_usb_stream *stream)
 {
        free_substream(&stream->substream[0]);
        free_substream(&stream->substream[1]);
@@ -2061,12 +2306,11 @@ static void snd_usb_audio_stream_free(snd_usb_stream_t *stream)
        kfree(stream);
 }
 
-static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
+static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
 {
-       snd_usb_stream_t *stream = pcm->private_data;
+       struct snd_usb_stream *stream = pcm->private_data;
        if (stream) {
                stream->pcm = NULL;
-               snd_pcm_lib_preallocate_free_for_all(pcm);
                snd_usb_audio_stream_free(stream);
        }
 }
@@ -2077,20 +2321,20 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
  * if a stream with the same endpoint already exists, append to it.
  * if not, create a new pcm stream.
  */
-static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audioformat *fp)
+static int add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp)
 {
        struct list_head *p;
-       snd_usb_stream_t *as;
-       snd_usb_substream_t *subs;
-       snd_pcm_t *pcm;
+       struct snd_usb_stream *as;
+       struct snd_usb_substream *subs;
+       struct snd_pcm *pcm;
        int err;
 
        list_for_each(p, &chip->pcm_list) {
-               as = list_entry(p, snd_usb_stream_t, list);
+               as = list_entry(p, struct snd_usb_stream, list);
                if (as->fmt_type != fp->fmt_type)
                        continue;
                subs = &as->substream[stream];
-               if (! subs->endpoint)
+               if (!subs->endpoint)
                        continue;
                if (subs->endpoint == fp->endpoint) {
                        list_add_tail(&fp->list, &subs->fmt_list);
@@ -2101,7 +2345,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
        }
        /* look for an empty stream */
        list_for_each(p, &chip->pcm_list) {
-               as = list_entry(p, snd_usb_stream_t, list);
+               as = list_entry(p, struct snd_usb_stream, list);
                if (as->fmt_type != fp->fmt_type)
                        continue;
                subs = &as->substream[stream];
@@ -2115,10 +2359,9 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
        }
 
        /* create a new pcm */
-       as = kmalloc(sizeof(*as), GFP_KERNEL);
-       if (! as)
+       as = kzalloc(sizeof(*as), GFP_KERNEL);
+       if (!as)
                return -ENOMEM;
-       memset(as, 0, sizeof(*as));
        as->pcm_index = chip->pcm_devs;
        as->chip = chip;
        as->fmt_type = fp->fmt_type;
@@ -2153,7 +2396,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
 /*
  * check if the device uses big-endian samples
  */
-static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp)
+static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp)
 {
        switch (chip->usb_id) {
        case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */
@@ -2161,7 +2404,9 @@ static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp)
                        return 1;
                break;
        case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-               return 1;
+               if (device_setup[chip->index] == 0x00 ||
+                   fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
+                       return 1;
        }
        return 0;
 }
@@ -2175,7 +2420,7 @@ static int is_big_endian_format(snd_usb_audio_t *chip, struct audioformat *fp)
  * @format: the format tag (wFormatTag)
  * @fmt: the format type descriptor
  */
-static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *fp,
+static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audioformat *fp,
                                     int format, unsigned char *fmt)
 {
        int pcm_format;
@@ -2224,11 +2469,12 @@ static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *
                }
                break;
        case USB_AUDIO_FORMAT_PCM8:
-               /* Dallas DS4201 workaround */
+               pcm_format = SNDRV_PCM_FORMAT_U8;
+
+               /* Dallas DS4201 workaround: it advertises U8 format, but really
+                  supports S8. */
                if (chip->usb_id == USB_ID(0x04fa, 0x4201))
                        pcm_format = SNDRV_PCM_FORMAT_S8;
-               else
-                       pcm_format = SNDRV_PCM_FORMAT_U8;
                break;
        case USB_AUDIO_FORMAT_IEEE_FLOAT:
                pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE;
@@ -2258,10 +2504,11 @@ static int parse_audio_format_i_type(snd_usb_audio_t *chip, struct audioformat *
  * @offset: the start offset of descriptor pointing the rate type
  *          (7 for type I and II, 8 for type II)
  */
-static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *fp,
+static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioformat *fp,
                                    unsigned char *fmt, int offset)
 {
        int nr_rates = fmt[offset];
+
        if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
                snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
                                   chip->dev->devnum, fp->iface, fp->altsetting);
@@ -2272,12 +2519,9 @@ static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *f
                /*
                 * build the rate table and bitmap flags
                 */
-               int r, idx, c;
-               /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */
-               static unsigned int conv_rates[] = {
-                       5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
-                       64000, 88200, 96000, 176400, 192000
-               };
+               int r, idx;
+               unsigned int nonzero_rates = 0;
+
                fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
                if (fp->rate_table == NULL) {
                        snd_printk(KERN_ERR "cannot malloc\n");
@@ -2287,17 +2531,23 @@ static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *f
                fp->nr_rates = nr_rates;
                fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
                for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
-                       unsigned int rate = fp->rate_table[r] = combine_triple(&fmt[idx]);
+                       unsigned int rate = combine_triple(&fmt[idx]);
+                       /* C-Media CM6501 mislabels its 96 kHz altsetting */
+                       if (rate == 48000 && nr_rates == 1 &&
+                           chip->usb_id == USB_ID(0x0d8c, 0x0201) &&
+                           fp->altsetting == 5 && fp->maxpacksize == 392)
+                               rate = 96000;
+                       fp->rate_table[r] = rate;
+                       nonzero_rates |= rate;
                        if (rate < fp->rate_min)
                                fp->rate_min = rate;
                        else if (rate > fp->rate_max)
                                fp->rate_max = rate;
-                       for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
-                               if (rate == conv_rates[c]) {
-                                       fp->rates |= (1 << c);
-                                       break;
-                               }
-                       }
+                       fp->rates |= snd_pcm_rate_to_rate_bit(rate);
+               }
+               if (!nonzero_rates) {
+                       hwc_debug("All rates were zero. Skipping format!\n");
+                       return -1;
                }
        } else {
                /* continuous rates */
@@ -2311,7 +2561,7 @@ static int parse_audio_format_rates(snd_usb_audio_t *chip, struct audioformat *f
 /*
  * parse the format type I and III descriptors
  */
-static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp,
+static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *fp,
                                int format, unsigned char *fmt)
 {
        int pcm_format;
@@ -2321,7 +2571,18 @@ static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp,
                 *        but we give normal PCM format to get the existing
                 *        apps working...
                 */
-               pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+               switch (chip->usb_id) {
+
+               case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+                       if (device_setup[chip->index] == 0x00 && 
+                           fp->altsetting == 6)
+                               pcm_format = SNDRV_PCM_FORMAT_S16_BE;
+                       else
+                               pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+                       break;
+               default:
+                       pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+               }
        } else {
                pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
                if (pcm_format < 0)
@@ -2340,7 +2601,7 @@ static int parse_audio_format_i(snd_usb_audio_t *chip, struct audioformat *fp,
 /*
  * prase the format type II descriptor
  */
-static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp,
+static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat *fp,
                                 int format, unsigned char *fmt)
 {
        int brate, framesize;
@@ -2367,7 +2628,7 @@ static int parse_audio_format_ii(snd_usb_audio_t *chip, struct audioformat *fp,
        return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */
 }
 
-static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp,
+static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
                              int format, unsigned char *fmt, int stream)
 {
        int err;
@@ -2389,23 +2650,25 @@ static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp,
        if (err < 0)
                return err;
 #if 1
-       /* FIXME: temporary hack for extigy/audigy 2 nx */
+       /* FIXME: temporary hack for extigy/audigy 2 nx/zs */
        /* extigy apparently supports sample rates other than 48k
         * but not in ordinary way.  so we enable only 48k atm.
         */
        if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
-           chip->usb_id == USB_ID(0x041e, 0x3020)) {
+           chip->usb_id == USB_ID(0x041e, 0x3020) ||
+           chip->usb_id == USB_ID(0x041e, 0x3061)) {
                if (fmt[3] == USB_FORMAT_TYPE_I &&
-                   stream == SNDRV_PCM_STREAM_PLAYBACK &&
                    fp->rates != SNDRV_PCM_RATE_48000 &&
                    fp->rates != SNDRV_PCM_RATE_96000)
-                       return -1; /* use 48k only */
+                       return -1;
        }
 #endif
        return 0;
 }
 
-static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+                                        int iface, int altno);
+static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
        struct usb_device *dev;
        struct usb_interface *iface;
@@ -2415,12 +2678,23 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
        int format;
        struct audioformat *fp;
        unsigned char *fmt, *csep;
+       int num;
 
        dev = chip->dev;
 
        /* parse the interface's altsettings */
        iface = usb_ifnum_to_if(dev, iface_no);
-       for (i = 0; i < iface->num_altsetting; i++) {
+
+       num = iface->num_altsetting;
+
+       /*
+        * Dallas DS4201 workaround: It presents 5 altsettings, but the last
+        * one misses syncpipe, and does not produce any sound.
+        */
+       if (chip->usb_id == USB_ID(0x04fa, 0x4201))
+               num = 4;
+
+       for (i = 0; i < num; i++) {
                alts = &iface->altsetting[i];
                altsd = get_iface_desc(alts);
                /* skip invalid one */
@@ -2439,6 +2713,12 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
                        SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
                altno = altsd->bAlternateSetting;
+       
+               /* audiophile usb: skip altsets incompatible with device_setup
+                */
+               if (chip->usb_id == USB_ID(0x0763, 0x2003) && 
+                   audiophile_skip_setting_quirk(chip, iface_no, altno))
+                       continue;
 
                /* get audio formats */
                fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL);
@@ -2474,26 +2754,28 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                if (!csep && altsd->bNumEndpoints >= 2)
                        csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
                if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-                       snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n",
+                       snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
+                                  " class specific endpoint descriptor\n",
                                   dev->devnum, iface_no, altno);
-                       continue;
+                       csep = NULL;
                }
 
-               fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+               fp = kzalloc(sizeof(*fp), GFP_KERNEL);
                if (! fp) {
                        snd_printk(KERN_ERR "cannot malloc\n");
                        return -ENOMEM;
                }
 
-               memset(fp, 0, sizeof(*fp));
                fp->iface = iface_no;
                fp->altsetting = altno;
                fp->altset_idx = i;
                fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
                fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
-               /* FIXME: decode wMaxPacketSize of high bandwith endpoints */
                fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
-               fp->attributes = csep[3];
+               if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
+                       fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
+                                       * (fp->maxpacksize & 0x7ff);
+               fp->attributes = csep ? csep[3] : 0;
 
                /* some quirks for attributes here */
 
@@ -2531,7 +2813,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                        continue;
                }
 
-               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint);
+               snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
                err = add_audio_endpoint(chip, stream, fp);
                if (err < 0) {
                        kfree(fp->rate_table);
@@ -2554,10 +2836,10 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 static void snd_usb_stream_disconnect(struct list_head *head)
 {
        int idx;
-       snd_usb_stream_t *as;
-       snd_usb_substream_t *subs;
+       struct snd_usb_stream *as;
+       struct snd_usb_substream *subs;
 
-       as = list_entry(head, snd_usb_stream_t, list);
+       as = list_entry(head, struct snd_usb_stream, list);
        for (idx = 0; idx < 2; idx++) {
                subs = &as->substream[idx];
                if (!subs->num_formats)
@@ -2570,7 +2852,7 @@ static void snd_usb_stream_disconnect(struct list_head *head)
 /*
  * parse audio control descriptor and create pcm/midi streams
  */
-static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
+static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
 {
        struct usb_device *dev = chip->dev;
        struct usb_host_interface *host_iface;
@@ -2625,6 +2907,10 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
                        /* skip non-supported classes */
                        continue;
                }
+               if (snd_usb_get_speed(dev) == USB_SPEED_LOW) {
+                       snd_printk(KERN_ERR "low speed audio streaming not supported\n");
+                       continue;
+               }
                if (! parse_audio_endpoints(chip, j)) {
                        usb_set_interface(dev, j, 0); /* reset the current interface */
                        usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
@@ -2637,21 +2923,20 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
 /*
  * create a stream for an endpoint/altsetting without proper descriptors
  */
-static int create_fixed_stream_quirk(snd_usb_audio_t *chip,
+static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
                                     struct usb_interface *iface,
-                                    const snd_usb_audio_quirk_t *quirk)
+                                    const struct snd_usb_audio_quirk *quirk)
 {
        struct audioformat *fp;
        struct usb_host_interface *alts;
        int stream, err;
-       int *rate_table = NULL;
+       unsigned *rate_table = NULL;
 
-       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
        if (! fp) {
-               snd_printk(KERN_ERR "cannot malloc\n");
+               snd_printk(KERN_ERR "cannot memdup\n");
                return -ENOMEM;
        }
-       memcpy(fp, quirk->data, sizeof(*fp));
        if (fp->nr_rates > 0) {
                rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
                if (!rate_table) {
@@ -2686,9 +2971,9 @@ static int create_fixed_stream_quirk(snd_usb_audio_t *chip,
 /*
  * create a stream for an interface with proper descriptors
  */
-static int create_standard_interface_quirk(snd_usb_audio_t *chip,
-                                          struct usb_interface *iface,
-                                          const snd_usb_audio_quirk_t *quirk)
+static int create_standard_audio_quirk(struct snd_usb_audio *chip,
+                                      struct usb_interface *iface,
+                                      const struct snd_usb_audio_quirk *quirk)
 {
        struct usb_host_interface *alts;
        struct usb_interface_descriptor *altsd;
@@ -2696,24 +2981,14 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip,
 
        alts = &iface->altsetting[0];
        altsd = get_iface_desc(alts);
-       switch (quirk->type) {
-       case QUIRK_AUDIO_STANDARD_INTERFACE:
-               err = parse_audio_endpoints(chip, altsd->bInterfaceNumber);
-               if (!err)
-                       usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* reset the current interface */
-               break;
-       case QUIRK_MIDI_STANDARD_INTERFACE:
-               err = snd_usb_create_midi_interface(chip, iface, NULL);
-               break;
-       default:
-               snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
-               return -ENXIO;
-       }
+       err = parse_audio_endpoints(chip, altsd->bInterfaceNumber);
        if (err < 0) {
                snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
                           altsd->bInterfaceNumber, err);
                return err;
        }
+       /* reset the current interface */
+       usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0);
        return 0;
 }
 
@@ -2721,8 +2996,9 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip,
  * Create a stream for an Edirol UA-700/UA-25 interface.  The only way
  * to detect the sample rate is by looking at wMaxPacketSize.
  */
-static int create_ua700_ua25_quirk(snd_usb_audio_t *chip,
-                                  struct usb_interface *iface)
+static int create_ua700_ua25_quirk(struct snd_usb_audio *chip,
+                                  struct usb_interface *iface,
+                                  const struct snd_usb_audio_quirk *quirk)
 {
        static const struct audioformat ua_format = {
                .format = SNDRV_PCM_FORMAT_S24_3LE,
@@ -2744,19 +3020,19 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip,
        altsd = get_iface_desc(alts);
 
        if (altsd->bNumEndpoints == 2) {
-               static const snd_usb_midi_endpoint_info_t ua700_ep = {
+               static const struct snd_usb_midi_endpoint_info ua700_ep = {
                        .out_cables = 0x0003,
                        .in_cables  = 0x0003
                };
-               static const snd_usb_audio_quirk_t ua700_quirk = {
+               static const struct snd_usb_audio_quirk ua700_quirk = {
                        .type = QUIRK_MIDI_FIXED_ENDPOINT,
                        .data = &ua700_ep
                };
-               static const snd_usb_midi_endpoint_info_t ua25_ep = {
+               static const struct snd_usb_midi_endpoint_info ua25_ep = {
                        .out_cables = 0x0001,
                        .in_cables  = 0x0001
                };
-               static const snd_usb_audio_quirk_t ua25_quirk = {
+               static const struct snd_usb_audio_quirk ua25_quirk = {
                        .type = QUIRK_MIDI_FIXED_ENDPOINT,
                        .data = &ua25_ep
                };
@@ -2813,7 +3089,9 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip,
 /*
  * Create a stream for an Edirol UA-1000 interface.
  */
-static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *iface)
+static int create_ua1000_quirk(struct snd_usb_audio *chip,
+                              struct usb_interface *iface,
+                              const struct snd_usb_audio_quirk *quirk)
 {
        static const struct audioformat ua1000_format = {
                .format = SNDRV_PCM_FORMAT_S32_LE,
@@ -2832,14 +3110,13 @@ static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *ifac
                return -ENXIO;
        alts = &iface->altsetting[1];
        altsd = get_iface_desc(alts);
-       if (alts->extralen != 11 || alts->extra[1] != CS_AUDIO_INTERFACE ||
+       if (alts->extralen != 11 || alts->extra[1] != USB_DT_CS_INTERFACE ||
            altsd->bNumEndpoints != 1)
                return -ENXIO;
 
-       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       fp = kmemdup(&ua1000_format, sizeof(*fp), GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
-       memcpy(fp, &ua1000_format, sizeof(*fp));
 
        fp->channels = alts->extra[4];
        fp->iface = altsd->bInterfaceNumber;
@@ -2860,16 +3137,68 @@ static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *ifac
        return 0;
 }
 
-static int snd_usb_create_quirk(snd_usb_audio_t *chip,
+/*
+ * Create a stream for an Edirol UA-101 interface.
+ * Copy, paste and modify from Edirol UA-1000
+ */
+static int create_ua101_quirk(struct snd_usb_audio *chip,
+                              struct usb_interface *iface,
+                              const struct snd_usb_audio_quirk *quirk)
+{
+       static const struct audioformat ua101_format = {
+               .format = SNDRV_PCM_FORMAT_S32_LE,
+               .fmt_type = USB_FORMAT_TYPE_I,
+               .altsetting = 1,
+               .altset_idx = 1,
+               .attributes = 0,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+       };
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct audioformat *fp;
+       int stream, err;
+
+       if (iface->num_altsetting != 2)
+               return -ENXIO;
+       alts = &iface->altsetting[1];
+       altsd = get_iface_desc(alts);
+       if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE ||
+           altsd->bNumEndpoints != 1)
+               return -ENXIO;
+
+       fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL);
+       if (!fp)
+               return -ENOMEM;
+
+       fp->channels = alts->extra[11];
+       fp->iface = altsd->bInterfaceNumber;
+       fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+       fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+       fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+       fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]);
+
+       stream = (fp->endpoint & USB_DIR_IN)
+               ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+       err = add_audio_endpoint(chip, stream, fp);
+       if (err < 0) {
+               kfree(fp);
+               return err;
+       }
+       /* FIXME: playback must be synchronized to capture */
+       usb_set_interface(chip->dev, fp->iface, 0);
+       return 0;
+}
+
+static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                                struct usb_interface *iface,
-                               const snd_usb_audio_quirk_t *quirk);
+                               const struct snd_usb_audio_quirk *quirk);
 
 /*
  * handle the quirks for the contained interfaces
  */
-static int create_composite_quirk(snd_usb_audio_t *chip,
+static int create_composite_quirk(struct snd_usb_audio *chip,
                                  struct usb_interface *iface,
-                                 const snd_usb_audio_quirk_t *quirk)
+                                 const struct snd_usb_audio_quirk *quirk)
 {
        int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
        int err;
@@ -2890,6 +3219,13 @@ static int create_composite_quirk(snd_usb_audio_t *chip,
        return 0;
 }
 
+static int ignore_interface_quirk(struct snd_usb_audio *chip,
+                                 struct usb_interface *iface,
+                                 const struct snd_usb_audio_quirk *quirk)
+{
+       return 0;
+}
+
 
 /*
  * boot quirks
@@ -2925,8 +3261,6 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
 
 static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
 {
-#if 0
-       /* TODO: enable this when high speed synchronization actually works */
        u8 buf = 1;
 
        snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
@@ -2938,10 +3272,79 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
                                1, 2000, NULL, 0, 1000);
                return -ENODEV;
        }
-#endif
        return 0;
 }
 
+/*
+ * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
+ * documented in the device's data sheet.
+ */
+static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value)
+{
+       u8 buf[4];
+       buf[0] = 0x20;
+       buf[1] = value & 0xff;
+       buf[2] = (value >> 8) & 0xff;
+       buf[3] = reg;
+       return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
+                              USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+                              0, 0, &buf, 4, 1000);
+}
+
+static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
+{
+       /*
+        * Enable line-out driver mode, set headphone source to front
+        * channels, enable stereo mic.
+        */
+       return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
+}
+
+
+/*
+ * Setup quirks
+ */
+#define AUDIOPHILE_SET                 0x01 /* if set, parse device_setup */
+#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */
+#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
+#define AUDIOPHILE_SET_24B             0x08 /* 24bits sample if set, 16bits otherwise */
+#define AUDIOPHILE_SET_DI              0x10 /* if set, enable Digital Input */
+#define AUDIOPHILE_SET_MASK            0x1F /* bit mask for setup value */
+#define AUDIOPHILE_SET_24B_48K_DI      0x19 /* value for 24bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_24B_48K_NOTDI   0x09 /* value for 24bits+48KHz+No Digital Input */
+#define AUDIOPHILE_SET_16B_48K_DI      0x11 /* value for 16bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_16B_48K_NOTDI   0x01 /* value for 16bits+48KHz+No Digital Input */
+
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+                                        int iface, int altno)
+{
+       /* Reset ALL ifaces to 0 altsetting.
+        * Call it for every possible altsetting of every interface.
+        */
+       usb_set_interface(chip->dev, iface, 0);
+
+       if (device_setup[chip->index] & AUDIOPHILE_SET) {
+               if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
+                   && altno != 6)
+                       return 1; /* skip this altsetting */
+               if ((device_setup[chip->index] & AUDIOPHILE_SET_96K)
+                   && altno != 1)
+                       return 1; /* skip this altsetting */
+               if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+                   AUDIOPHILE_SET_24B_48K_DI && altno != 2)
+                       return 1; /* skip this altsetting */
+               if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+                   AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3)
+                       return 1; /* skip this altsetting */
+               if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+                   AUDIOPHILE_SET_16B_48K_DI && altno != 4)
+                       return 1; /* skip this altsetting */
+               if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+                   AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5)
+                       return 1; /* skip this altsetting */
+       }       
+       return 0; /* keep this altsetting */
+}
 
 /*
  * audio-interface quirks
@@ -2951,32 +3354,33 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
  * after this.
  * returns a negative value at error.
  */
-static int snd_usb_create_quirk(snd_usb_audio_t *chip,
+static int snd_usb_create_quirk(struct snd_usb_audio *chip,
                                struct usb_interface *iface,
-                               const snd_usb_audio_quirk_t *quirk)
-{
-       switch (quirk->type) {
-       case QUIRK_MIDI_FIXED_ENDPOINT:
-       case QUIRK_MIDI_YAMAHA:
-       case QUIRK_MIDI_MIDIMAN:
-       case QUIRK_MIDI_NOVATION:
-       case QUIRK_MIDI_MOTU:
-       case QUIRK_MIDI_EMAGIC:
-               return snd_usb_create_midi_interface(chip, iface, quirk);
-       case QUIRK_COMPOSITE:
-               return create_composite_quirk(chip, iface, quirk);
-       case QUIRK_AUDIO_FIXED_ENDPOINT:
-               return create_fixed_stream_quirk(chip, iface, quirk);
-       case QUIRK_AUDIO_STANDARD_INTERFACE:
-       case QUIRK_MIDI_STANDARD_INTERFACE:
-               return create_standard_interface_quirk(chip, iface, quirk);
-       case QUIRK_AUDIO_EDIROL_UA700_UA25:
-               return create_ua700_ua25_quirk(chip, iface);
-       case QUIRK_AUDIO_EDIROL_UA1000:
-               return create_ua1000_quirk(chip, iface);
-       case QUIRK_IGNORE_INTERFACE:
-               return 0;
-       default:
+                               const struct snd_usb_audio_quirk *quirk)
+{
+       typedef int (*quirk_func_t)(struct snd_usb_audio *, struct usb_interface *,
+                                   const struct snd_usb_audio_quirk *);
+       static const quirk_func_t quirk_funcs[] = {
+               [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
+               [QUIRK_COMPOSITE] = create_composite_quirk,
+               [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
+               [QUIRK_MIDI_CME] = snd_usb_create_midi_interface,
+               [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
+               [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
+               [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
+               [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
+               [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk,
+       };
+
+       if (quirk->type < QUIRK_TYPE_COUNT) {
+               return quirk_funcs[quirk->type](chip, iface, quirk);
+       } else {
                snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
                return -ENXIO;
        }
@@ -2986,29 +3390,29 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip,
 /*
  * common proc files to show the usb device info
  */
-static void proc_audio_usbbus_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       snd_usb_audio_t *chip = entry->private_data;
-       if (! chip->shutdown)
+       struct snd_usb_audio *chip = entry->private_data;
+       if (!chip->shutdown)
                snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum);
 }
 
-static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
+static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       snd_usb_audio_t *chip = entry->private_data;
-       if (! chip->shutdown)
+       struct snd_usb_audio *chip = entry->private_data;
+       if (!chip->shutdown)
                snd_iprintf(buffer, "%04x:%04x\n", 
                            USB_ID_VENDOR(chip->usb_id),
                            USB_ID_PRODUCT(chip->usb_id));
 }
 
-static void snd_usb_audio_create_proc(snd_usb_audio_t *chip)
+static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
 {
-       snd_info_entry_t *entry;
-       if (! snd_card_proc_new(chip->card, "usbbus", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read);
-       if (! snd_card_proc_new(chip->card, "usbid", &entry))
-               snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read);
+       struct snd_info_entry *entry;
+       if (!snd_card_proc_new(chip->card, "usbbus", &entry))
+               snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read);
+       if (!snd_card_proc_new(chip->card, "usbid", &entry))
+               snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
 }
 
 /*
@@ -3018,15 +3422,15 @@ static void snd_usb_audio_create_proc(snd_usb_audio_t *chip)
  *
  */
 
-static int snd_usb_audio_free(snd_usb_audio_t *chip)
+static int snd_usb_audio_free(struct snd_usb_audio *chip)
 {
        kfree(chip);
        return 0;
 }
 
-static int snd_usb_audio_dev_free(snd_device_t *device)
+static int snd_usb_audio_dev_free(struct snd_device *device)
 {
-       snd_usb_audio_t *chip = device->device_data;
+       struct snd_usb_audio *chip = device->device_data;
        return snd_usb_audio_free(chip);
 }
 
@@ -3035,20 +3439,21 @@ static int snd_usb_audio_dev_free(snd_device_t *device)
  * create a chip instance and set its names.
  */
 static int snd_usb_audio_create(struct usb_device *dev, int idx,
-                               const snd_usb_audio_quirk_t *quirk,
-                               snd_usb_audio_t **rchip)
+                               const struct snd_usb_audio_quirk *quirk,
+                               struct snd_usb_audio **rchip)
 {
-       snd_card_t *card;
-       snd_usb_audio_t *chip;
+       struct snd_card *card;
+       struct snd_usb_audio *chip;
        int err, len;
        char component[14];
-       static snd_device_ops_t ops = {
+       static struct snd_device_ops ops = {
                .dev_free =     snd_usb_audio_dev_free,
        };
 
        *rchip = NULL;
 
-       if (snd_usb_get_speed(dev) != USB_SPEED_FULL &&
+       if (snd_usb_get_speed(dev) != USB_SPEED_LOW &&
+           snd_usb_get_speed(dev) != USB_SPEED_FULL &&
            snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
                snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
                return -ENXIO;
@@ -3060,7 +3465,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                return -ENOMEM;
        }
 
-       chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (! chip) {
                snd_card_free(card);
                return -ENOMEM;
@@ -3122,7 +3527,9 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
 
        strlcat(card->longname,
-               snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed",
+               snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" :
+               snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" :
+               ", high speed",
                sizeof(card->longname));
 
        snd_usb_audio_create_proc(chip);
@@ -3146,10 +3553,9 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                                 struct usb_interface *intf,
                                 const struct usb_device_id *usb_id)
 {
-       struct usb_host_config *config = dev->actconfig;
-       const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info;
+       const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info;
        int i, err;
-       snd_usb_audio_t *chip;
+       struct snd_usb_audio *chip;
        struct usb_host_interface *alts;
        int ifnum;
        u32 id;
@@ -3167,7 +3573,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
        if (id == USB_ID(0x041e, 0x3000)) {
                if (snd_usb_extigy_boot_quirk(dev, intf) < 0)
                        goto __err_val;
-               config = dev->actconfig;
        }
        /* SB Audigy 2 NX needs its own boot-up magic, too */
        if (id == USB_ID(0x041e, 0x3020)) {
@@ -3175,13 +3580,19 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                        goto __err_val;
        }
 
+       /* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
+       if (id == USB_ID(0x10f5, 0x0200)) {
+               if (snd_usb_cm106_boot_quirk(dev) < 0)
+                       goto __err_val;
+       }
+
        /*
         * found a config.  now register to ALSA
         */
 
        /* check whether it's already registered */
        chip = NULL;
-       down(&register_mutex);
+       mutex_lock(&register_mutex);
        for (i = 0; i < SNDRV_CARDS; i++) {
                if (usb_chip[i] && usb_chip[i]->dev == dev) {
                        if (usb_chip[i]->shutdown) {
@@ -3196,11 +3607,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                /* it's a fresh one.
                 * now look for an empty slot and create a new card instance
                 */
-               /* first, set the current configuration for this device */
-               if (usb_reset_configuration(dev) < 0) {
-                       snd_printk(KERN_ERR "cannot reset configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue);
-                       goto __error;
-               }
                for (i = 0; i < SNDRV_CARDS; i++)
                        if (enable[i] && ! usb_chip[i] &&
                            (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
@@ -3211,8 +3617,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                                snd_card_set_dev(chip->card, &intf->dev);
                                break;
                        }
-               if (! chip) {
-                       snd_printk(KERN_ERR "no available usb audio device\n");
+               if (!chip) {
+                       printk(KERN_ERR "no available usb audio device\n");
                        goto __error;
                }
        }
@@ -3239,13 +3645,13 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
 
        usb_chip[chip->index] = chip;
        chip->num_interfaces++;
-       up(&register_mutex);
+       mutex_unlock(&register_mutex);
        return chip;
 
  __error:
        if (chip && !chip->num_interfaces)
                snd_card_free(chip->card);
-       up(&register_mutex);
+       mutex_unlock(&register_mutex);
  __err_val:
        return NULL;
 }
@@ -3256,8 +3662,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
  */
 static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
 {
-       snd_usb_audio_t *chip;
-       snd_card_t *card;
+       struct snd_usb_audio *chip;
+       struct snd_card *card;
        struct list_head *p;
 
        if (ptr == (void *)-1L)
@@ -3265,7 +3671,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
 
        chip = ptr;
        card = chip->card;
-       down(&register_mutex);
+       mutex_lock(&register_mutex);
        chip->shutdown = 1;
        chip->num_interfaces--;
        if (chip->num_interfaces <= 0) {
@@ -3283,10 +3689,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
                        snd_usb_mixer_disconnect(p);
                }
                usb_chip[chip->index] = NULL;
-               up(&register_mutex);
-               snd_card_free(card);
+               mutex_unlock(&register_mutex);
+               snd_card_free_when_closed(card);
        } else {
-               up(&register_mutex);
+               mutex_unlock(&register_mutex);
        }
 }
 
@@ -3311,6 +3717,45 @@ static void usb_audio_disconnect(struct usb_interface *intf)
                                 dev_get_drvdata(&intf->dev));
 }
 
+#ifdef CONFIG_PM
+static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev);
+       struct list_head *p;
+       struct snd_usb_stream *as;
+
+       if (chip == (void *)-1L)
+               return 0;
+
+       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+       if (!chip->num_suspended_intf++) {
+               list_for_each(p, &chip->pcm_list) {
+                       as = list_entry(p, struct snd_usb_stream, list);
+                       snd_pcm_suspend_all(as->pcm);
+               }
+       }
+
+       return 0;
+}
+
+static int usb_audio_resume(struct usb_interface *intf)
+{
+       struct snd_usb_audio *chip = dev_get_drvdata(&intf->dev);
+
+       if (chip == (void *)-1L)
+               return 0;
+       if (--chip->num_suspended_intf)
+               return 0;
+       /*
+        * ALSA leaves material resumption to user space
+        * we just notify
+        */
+
+       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+
+       return 0;
+}
+#endif         /* CONFIG_PM */
 
 static int __init snd_usb_audio_init(void)
 {
@@ -3318,8 +3763,7 @@ static int __init snd_usb_audio_init(void)
                printk(KERN_WARNING "invalid nrpacks value.\n");
                return -EINVAL;
        }
-       usb_register(&usb_audio_driver);
-       return 0;
+       return usb_register(&usb_audio_driver);
 }