vserver 2.0-rc4
[linux-2.6.git] / sound / usb / usbaudio.c
index 1a7ab1b..5ea0251 100644 (file)
@@ -5,7 +5,7 @@
  *
  *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
  *
- *   Many codes borrowed from audio.c by 
+ *   Many codes borrowed from audio.c by
  *         Alan Cox (alan@lxorguk.ukuu.org.uk)
  *         Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/usb.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#define SNDRV_GET_ID
 #include <sound/initval.h>
 
 #include "usbaudio.h"
@@ -58,8 +58,7 @@
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("USB Audio");
 MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{Generic,USB Audio}}");
+MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}");
 
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
@@ -70,27 +69,20 @@ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID fo
 static int nrpacks = 4;                /* max. number of packets per urb */
 static int async_unlink = 1;
 
-MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
-MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
-MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+module_param_array(id, charp, NULL, 0444);
 MODULE_PARM_DESC(id, "ID string for the USB audio adapter.");
-MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable USB audio adapter.");
-MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(vid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(vid, int, NULL, 0444);
 MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
-MODULE_PARM_SYNTAX(vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
-MODULE_PARM(pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(pid, int, NULL, 0444);
 MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
-MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
-MODULE_PARM(nrpacks, "i");
+module_param(nrpacks, int, 0444);
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
-MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{1,10}}");
-MODULE_PARM(async_unlink, "i");
+module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
-MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC);
 
 
 /*
@@ -103,7 +95,7 @@ MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC);
  *
  */
 
-#define MAX_PACKS      10      
+#define MAX_PACKS      10
 #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 */
@@ -206,8 +198,6 @@ struct snd_usb_stream {
        struct list_head list;
 };
 
-#define chip_t snd_usb_stream_t
-
 
 /*
  * we keep the snd_usb_audio_t instances by ourselves for merging
@@ -353,7 +343,7 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
        if (! urb->bandwidth) {
                int bustime;
                bustime = usb_check_bandwidth(urb->dev, urb);
-               if (bustime < 0) 
+               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);
@@ -735,7 +725,7 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
        subs->running = 0;
 
        if (!force && subs->stream->chip->shutdown) /* to be sure... */
-               return 0;
+               return -EBADFD;
 
        async = !can_sleep && async_unlink;
 
@@ -746,11 +736,11 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
                if (test_bit(i, &subs->active_mask)) {
                        if (! test_and_set_bit(i, &subs->unlink_mask)) {
                                struct urb *u = subs->dataurb[i].urb;
-                               if (async)
+                               if (async) {
                                        u->transfer_flags |= URB_ASYNC_UNLINK;
-                               else
-                                       u->transfer_flags &= ~URB_ASYNC_UNLINK;
-                               usb_unlink_urb(u);
+                                       usb_unlink_urb(u);
+                               } else
+                                       usb_kill_urb(u);
                        }
                }
        }
@@ -759,11 +749,11 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep)
                        if (test_bit(i+16, &subs->active_mask)) {
                                if (! test_and_set_bit(i+16, &subs->unlink_mask)) {
                                        struct urb *u = subs->syncurb[i].urb;
-                                       if (async)
+                                       if (async) {
                                                u->transfer_flags |= URB_ASYNC_UNLINK;
-                                       else
-                                               u->transfer_flags &= ~URB_ASYNC_UNLINK;
-                                       usb_unlink_urb(u);
+                                               usb_unlink_urb(u);
+                                       } else
+                                               usb_kill_urb(u);
                                }
                        }
                }
@@ -780,6 +770,9 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
        unsigned int i;
        int err;
 
+       if (subs->stream->chip->shutdown)
+               return -EBADFD;
+
        for (i = 0; i < subs->nurbs; i++) {
                snd_assert(subs->dataurb[i].urb, return -EINVAL);
                if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
@@ -825,7 +818,7 @@ 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)
@@ -897,11 +890,11 @@ static void release_urb_ctx(snd_urb_ctx_t *u)
 {
        if (u->urb) {
                usb_free_urb(u->urb);
-               u->urb = 0;
+               u->urb = NULL;
        }
        if (u->buf) {
                kfree(u->buf);
-               u->buf = 0;
+               u->buf = NULL;
        }
 }
 
@@ -922,7 +915,7 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
                release_urb_ctx(&subs->syncurb[i]);
        if (subs->tmpbuf) {
                kfree(subs->tmpbuf);
-               subs->tmpbuf = 0;
+               subs->tmpbuf = NULL;
        }
        subs->nurbs = 0;
 }
@@ -1146,8 +1139,8 @@ static int init_usb_pitch(struct usb_device *dev, int iface,
        /* if endpoint has pitch control, enable it */
        if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) {
                data[0] = 1;
-               if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
-                                          USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+               if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+                                          USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
                                           PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
                        snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n",
                                   dev->devnum, iface, ep);
@@ -1172,19 +1165,19 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
                data[0] = rate;
                data[1] = rate >> 8;
                data[2] = rate >> 16;
-               if ((err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
-                                          USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+               if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR,
+                                          USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
                                           SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
                        snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep 0x%x\n",
                                   dev->devnum, iface, fmt->altsetting, rate, ep);
                        return err;
                }
-               if ((err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
+               if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR,
                                           USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
                                           SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
-                       snd_printk(KERN_ERR "%d:%d:%d: cannot get freq at ep 0x%x\n",
+                       snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep 0x%x\n",
                                   dev->devnum, iface, fmt->altsetting, ep);
-                       return err;
+                       return 0; /* some devices don't support reading */
                }
                crate = data[0] | (data[1] << 8) | (data[2] << 16);
                if (crate != rate) {
@@ -1231,7 +1224,7 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
                                   dev->devnum, fmt->iface, fmt->altsetting);
                        return -EIO;
                }
-               snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altset_idx);
+               snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting);
                subs->interface = fmt->iface;
                subs->format = fmt->altset_idx;
        }
@@ -1322,7 +1315,7 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
        ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
-       
+
        format = params_format(hw_params);
        rate = params_rate(hw_params);
        channels = params_channels(hw_params);
@@ -1481,7 +1474,7 @@ static int hw_rule_rate(snd_pcm_hw_params_t *params,
        snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
        unsigned int rmin, rmax;
        int changed;
-       
+
        hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max);
        changed = 0;
        rmin = rmax = 0;
@@ -1535,7 +1528,7 @@ static int hw_rule_channels(snd_pcm_hw_params_t *params,
        snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
        unsigned int rmin, rmax;
        int changed;
-       
+
        hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max);
        changed = 0;
        rmin = rmax = 0;
@@ -1589,7 +1582,7 @@ static int hw_rule_format(snd_pcm_hw_params_t *params,
        u64 fbits;
        u32 oldbits[2];
        int changed;
-       
+
        hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
        fbits = 0;
        list_for_each(p, &subs->fmt_list) {
@@ -1733,13 +1726,13 @@ static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
 
        if (check_hw_params_convention(subs)) {
                hwc_debug("setting extra hw constraints...\n");
-               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 
+               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                               hw_rule_rate, subs,
                                               SNDRV_PCM_HW_PARAM_FORMAT,
                                               SNDRV_PCM_HW_PARAM_CHANNELS,
                                               -1)) < 0)
                        return err;
-               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 
+               if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
                                               hw_rule_channels, subs,
                                               SNDRV_PCM_HW_PARAM_FORMAT,
                                               SNDRV_PCM_HW_PARAM_RATE,
@@ -1884,6 +1877,32 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
        return NULL;
 }
 
+/*
+ * Wrapper for usb_control_msg().
+ * Allocates a temp buffer to prevent dmaing from/to the stack.
+ */
+int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
+                   __u8 requesttype, __u16 value, __u16 index, void *data,
+                   __u16 size, int timeout)
+{
+       int err;
+       void *buf = NULL;
+
+       if (size > 0) {
+               buf = kmalloc(size, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+               memcpy(buf, data, size);
+       }
+       err = usb_control_msg(dev, pipe, request, requesttype,
+                             value, index, buf, size, timeout);
+       if (size > 0) {
+               memcpy(data, buf, size);
+               kfree(buf);
+       }
+       return err;
+}
+
 
 /*
  * entry point for linux usb interface
@@ -1926,7 +1945,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
                snd_iprintf(buffer, "  Interface %d\n", fp->iface);
-               snd_iprintf(buffer, "    Altset %d\n", fp->altset_idx);
+               snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
                snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
                snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
                snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
@@ -1974,8 +1993,8 @@ 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)
 {
-       snd_usb_stream_t *stream = snd_magic_cast(snd_usb_stream_t, entry->private_data, return);
-       
+       snd_usb_stream_t *stream = entry->private_data;
+
        snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name);
 
        if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) {
@@ -2047,8 +2066,7 @@ static void free_substream(snd_usb_substream_t *subs)
                return; /* not initialized */
        list_for_each_safe(p, n, &subs->fmt_list) {
                struct audioformat *fp = list_entry(p, struct audioformat, list);
-               if (fp->rate_table)
-                       kfree(fp->rate_table);
+               kfree(fp->rate_table);
                kfree(fp);
        }
 }
@@ -2062,7 +2080,7 @@ static void snd_usb_audio_stream_free(snd_usb_stream_t *stream)
        free_substream(&stream->substream[0]);
        free_substream(&stream->substream[1]);
        list_del(&stream->list);
-       snd_magic_kfree(stream);
+       kfree(stream);
 }
 
 static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
@@ -2119,7 +2137,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
        }
 
        /* create a new pcm */
-       as = snd_magic_kmalloc(snd_usb_stream_t, 0, GFP_KERNEL);
+       as = kmalloc(sizeof(*as), GFP_KERNEL);
        if (! as)
                return -ENOMEM;
        memset(as, 0, sizeof(*as));
@@ -2131,13 +2149,13 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor
                          stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
                          &pcm);
        if (err < 0) {
-               snd_magic_kfree(as);
+               kfree(as);
                return err;
        }
        as->pcm = pcm;
        pcm->private_data = as;
        pcm->private_free = snd_usb_audio_pcm_free;
-       pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS;
+       pcm->info_flags = 0;
        if (chip->pcm_devs > 0)
                sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
        else
@@ -2154,6 +2172,24 @@ 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(struct usb_device *dev, struct audioformat *fp)
+{
+       /* M-Audio */
+       if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) {
+               /* Quattro: captured data only */
+               if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 &&
+                   fp->endpoint & USB_DIR_IN)
+                       return 1;
+               /* Audiophile USB */
+               if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003)
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * parse the audio format type I descriptor
  * and returns the corresponding pcm format
@@ -2190,17 +2226,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat
                        pcm_format = SNDRV_PCM_FORMAT_S8;
                        break;
                case 2:
-                       /* M-Audio audiophile USB workaround */
-                       if (dev->descriptor.idVendor == 0x0763 &&
-                           dev->descriptor.idProduct == 0x2003)
+                       if (is_big_endian_format(dev, fp))
                                pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */
                        else
                                pcm_format = SNDRV_PCM_FORMAT_S16_LE;
                        break;
                case 3:
-                       /* M-Audio audiophile USB workaround */
-                       if (dev->descriptor.idVendor == 0x0763 &&
-                           dev->descriptor.idProduct == 0x2003)
+                       if (is_big_endian_format(dev, fp))
                                pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */
                        else
                                pcm_format = SNDRV_PCM_FORMAT_S24_3LE;
@@ -2216,7 +2248,8 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat
                break;
        case USB_AUDIO_FORMAT_PCM8:
                /* Dallas DS4201 workaround */
-               if (dev->descriptor.idVendor == 0x04fa && dev->descriptor.idProduct == 0x4201)
+               if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa &&
+                   le16_to_cpu(dev->descriptor.idProduct) == 0x4201)
                        pcm_format = SNDRV_PCM_FORMAT_S8;
                else
                        pcm_format = SNDRV_PCM_FORMAT_U8;
@@ -2254,7 +2287,7 @@ static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *
 {
        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", 
+               snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
                                   dev->devnum, fp->iface, fp->altsetting);
                return -1;
        }
@@ -2384,7 +2417,8 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp,
        /* extigy apparently supports sample rates other than 48k
         * but not in ordinary way.  so we enable only 48k atm.
         */
-       if (dev->descriptor.idVendor == 0x041e && dev->descriptor.idProduct == 0x3000) {
+       if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && 
+           le16_to_cpu(dev->descriptor.idProduct) == 0x3000) {
                if (fmt[3] == USB_FORMAT_TYPE_I &&
                    stream == SNDRV_PCM_STREAM_PLAYBACK &&
                    fp->rates != SNDRV_PCM_RATE_48000)
@@ -2392,7 +2426,7 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp,
        }
 #endif
        return 0;
-}      
+}
 
 static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 {
@@ -2418,7 +2452,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                    (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING &&
                     altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
                    altsd->bNumEndpoints < 1 ||
-                   get_endpoint(alts, 0)->wMaxPacketSize == 0)
+                   le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
                        continue;
                /* must be isochronous */
                if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
@@ -2438,22 +2472,22 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                }
 
                if (fmt[0] < 7) {
-                       snd_printk(KERN_ERR "%d:%u:%d : invalid AS_GENERAL desc\n", 
+                       snd_printk(KERN_ERR "%d:%u:%d : invalid AS_GENERAL desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
                }
 
                format = (fmt[6] << 8) | fmt[5]; /* remember the format value */
-                       
+
                /* get format type */
                fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, FORMAT_TYPE);
                if (!fmt) {
-                       snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n", 
+                       snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
                }
                if (fmt[0] < 8) {
-                       snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", 
+                       snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
                        continue;
                }
@@ -2463,7 +2497,7 @@ 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_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n",
                                   dev->devnum, iface_no, altno);
                        continue;
                }
@@ -2481,14 +2515,14 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
                fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
                /* FIXME: decode wMaxPacketSize of high bandwith endpoints */
-               fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
+               fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
                fp->attributes = csep[3];
 
                /* some quirks for attributes here */
 
                /* workaround for AudioTrak Optoplay */
-               if (dev->descriptor.idVendor == 0x0a92 &&
-                   dev->descriptor.idProduct == 0x0053) {
+               if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 &&
+                   le16_to_cpu(dev->descriptor.idProduct) == 0x0053) {
                        /* Optoplay sets the sample rate attribute although
                         * it seems not supporting it in fact.
                         */
@@ -2496,8 +2530,8 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                }
 
                /* workaround for M-Audio Audiophile USB */
-               if (dev->descriptor.idVendor == 0x0763 &&
-                   dev->descriptor.idProduct == 0x2003) {
+               if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 &&
+                   le16_to_cpu(dev->descriptor.idProduct) == 0x2003) {
                        /* doesn't set the sample rate attribute, but supports it */
                        fp->attributes |= EP_CS_ATTR_SAMPLE_RATE;
                }
@@ -2506,11 +2540,11 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                 * plantronics headset and Griffin iMic have set adaptive-in
                 * although it's really not...
                 */
-               if ((dev->descriptor.idVendor == 0x047f &&
-                    dev->descriptor.idProduct == 0x0ca1) ||
+               if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f &&
+                    le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) ||
                    /* Griffin iMic (note that there is an older model 77d:223) */
-                   (dev->descriptor.idVendor == 0x077d &&
-                    dev->descriptor.idProduct == 0x07af)) {
+                   (le16_to_cpu(dev->descriptor.idVendor) == 0x077d &&
+                    le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) {
                        fp->ep_attr &= ~EP_ATTR_MASK;
                        if (stream == SNDRV_PCM_STREAM_PLAYBACK)
                                fp->ep_attr |= EP_ATTR_ADAPTIVE;
@@ -2520,8 +2554,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 
                /* ok, let's parse further... */
                if (parse_audio_format(dev, fp, format, fmt, stream) < 0) {
-                       if (fp->rate_table)
-                               kfree(fp->rate_table);
+                       kfree(fp->rate_table);
                        kfree(fp);
                        continue;
                }
@@ -2529,8 +2562,7 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
                snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint);
                err = add_audio_endpoint(chip, stream, fp);
                if (err < 0) {
-                       if (fp->rate_table)
-                               kfree(fp->rate_table);
+                       kfree(fp->rate_table);
                        kfree(fp);
                        return err;
                }
@@ -2640,6 +2672,7 @@ static int create_fixed_stream_quirk(snd_usb_audio_t *chip,
        struct audioformat *fp;
        struct usb_host_interface *alts;
        int stream, err;
+       int *rate_table = NULL;
 
        fp = kmalloc(sizeof(*fp), GFP_KERNEL);
        if (! fp) {
@@ -2647,16 +2680,28 @@ static int create_fixed_stream_quirk(snd_usb_audio_t *chip,
                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) {
+                       kfree(fp);
+                       return -ENOMEM;
+               }
+               memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates);
+               fp->rate_table = rate_table;
+       }
+
        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);
+               kfree(rate_table);
                return err;
        }
        if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
            fp->altset_idx >= iface->num_altsetting) {
                kfree(fp);
+               kfree(rate_table);
                return -EINVAL;
        }
        alts = &iface->altsetting[fp->altset_idx];
@@ -2700,6 +2745,149 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip,
        return 0;
 }
 
+/*
+ * 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 const struct audioformat ua_format = {
+               .format = SNDRV_PCM_FORMAT_S24_3LE,
+               .channels = 2,
+               .fmt_type = USB_FORMAT_TYPE_I,
+               .altsetting = 1,
+               .altset_idx = 1,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+       };
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       struct audioformat *fp;
+       int stream, err;
+
+       /* both PCM and MIDI interfaces have 2 altsettings */
+       if (iface->num_altsetting != 2)
+               return -ENXIO;
+       alts = &iface->altsetting[1];
+       altsd = get_iface_desc(alts);
+
+       if (altsd->bNumEndpoints == 2) {
+               static const snd_usb_midi_endpoint_info_t ua700_ep = {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0003
+               };
+               static const snd_usb_audio_quirk_t ua700_quirk = {
+                       .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                       .data = &ua700_ep
+               };
+               static const snd_usb_midi_endpoint_info_t ua25_ep = {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               };
+               static const snd_usb_audio_quirk_t ua25_quirk = {
+                       .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                       .data = &ua25_ep
+               };
+               if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b)
+                       return snd_usb_create_midi_interface(chip, iface,
+                                                            &ua700_quirk);
+               else
+                       return snd_usb_create_midi_interface(chip, iface,
+                                                            &ua25_quirk);
+       }
+
+       if (altsd->bNumEndpoints != 1)
+               return -ENXIO;
+
+       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       if (!fp)
+               return -ENOMEM;
+       memcpy(fp, &ua_format, sizeof(*fp));
+
+       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);
+
+       switch (fp->maxpacksize) {
+       case 0x120:
+               fp->rate_max = fp->rate_min = 44100;
+               break;
+       case 0x138:
+       case 0x140:
+               fp->rate_max = fp->rate_min = 48000;
+               break;
+       case 0x258:
+       case 0x260:
+               fp->rate_max = fp->rate_min = 96000;
+               break;
+       default:
+               snd_printk(KERN_ERR "unknown sample rate\n");
+               kfree(fp);
+               return -ENXIO;
+       }
+
+       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;
+       }
+       usb_set_interface(chip->dev, fp->iface, 0);
+       return 0;
+}
+
+/*
+ * Create a stream for an Edirol UA-1000 interface.
+ */
+static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *iface)
+{
+       static const struct audioformat ua1000_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 != 11 || alts->extra[1] != CS_AUDIO_INTERFACE ||
+           altsd->bNumEndpoints != 1)
+               return -ENXIO;
+
+       fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+       if (!fp)
+               return -ENOMEM;
+       memcpy(fp, &ua1000_format, sizeof(*fp));
+
+       fp->channels = alts->extra[4];
+       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[8]);
+
+       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(snd_usb_audio_t *chip,
                                struct usb_interface *iface,
                                const snd_usb_audio_quirk_t *quirk);
@@ -2743,11 +2931,11 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
        struct usb_host_config *config = dev->actconfig;
        int err;
 
-       if (get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_OLD ||
-           get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_NEW) {
+       if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
+           le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) {
                snd_printdd("sending Extigy boot sequence...\n");
                /* Send message to force it to reconnect with full interface. */
-               err = usb_control_msg(dev, usb_sndctrlpipe(dev,0),
+               err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
                                      0x10, 0x43, 0x0001, 0x000a, NULL, 0, HZ);
                if (err < 0) snd_printdd("error sending boot message: %d\n", err);
                err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
@@ -2756,7 +2944,8 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
                if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err);
                err = usb_reset_configuration(dev);
                if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err);
-               snd_printdd("extigy_boot: new boot length = %d\n", get_cfg_desc(config)->wTotalLength);
+               snd_printdd("extigy_boot: new boot length = %d\n",
+                           le16_to_cpu(get_cfg_desc(config)->wTotalLength));
                return -ENODEV; /* quit this anyway */
        }
        return 0;
@@ -2787,6 +2976,10 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip,
        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);
        default:
                snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
                return -ENXIO;
@@ -2799,16 +2992,18 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip,
  */
 static void proc_audio_usbbus_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
 {
-       snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return);
+       snd_usb_audio_t *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)
 {
-       snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return);
+       snd_usb_audio_t *chip = entry->private_data;
        if (! chip->shutdown)
-               snd_iprintf(buffer, "%04x:%04x\n", chip->dev->descriptor.idVendor, chip->dev->descriptor.idProduct);
+               snd_iprintf(buffer, "%04x:%04x\n", 
+                           le16_to_cpu(chip->dev->descriptor.idVendor),
+                           le16_to_cpu(chip->dev->descriptor.idProduct));
 }
 
 static void snd_usb_audio_create_proc(snd_usb_audio_t *chip)
@@ -2829,13 +3024,13 @@ static void snd_usb_audio_create_proc(snd_usb_audio_t *chip)
 
 static int snd_usb_audio_free(snd_usb_audio_t *chip)
 {
-       snd_magic_kfree(chip);
+       kfree(chip);
        return 0;
 }
 
 static int snd_usb_audio_dev_free(snd_device_t *device)
 {
-       snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, device->device_data, return -ENXIO);
+       snd_usb_audio_t *chip = device->device_data;
        return snd_usb_audio_free(chip);
 }
 
@@ -2854,7 +3049,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        static snd_device_ops_t ops = {
                .dev_free =     snd_usb_audio_dev_free,
        };
-       
+
        *rchip = NULL;
 
        if (snd_usb_get_speed(dev) != USB_SPEED_FULL &&
@@ -2869,7 +3064,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                return -ENOMEM;
        }
 
-       chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL);
+       chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
        if (! chip) {
                snd_card_free(card);
                return -ENOMEM;
@@ -2889,7 +3084,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
 
        strcpy(card->driver, "USB-Audio");
        sprintf(component, "USB%04x:%04x",
-               dev->descriptor.idVendor, dev->descriptor.idProduct);
+               le16_to_cpu(dev->descriptor.idVendor),
+               le16_to_cpu(dev->descriptor.idProduct));
        snd_component_add(card, component);
 
        /* retrieve the device string as shortname */
@@ -2901,7 +3097,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                               card->shortname, sizeof(card->shortname)) <= 0) {
                        /* no name available from anywhere, so use ID */
                        sprintf(card->shortname, "USB Device %#04x:%#04x",
-                               dev->descriptor.idVendor, dev->descriptor.idProduct);
+                               le16_to_cpu(dev->descriptor.idVendor),
+                               le16_to_cpu(dev->descriptor.idProduct));
                }
        }
 
@@ -2968,7 +3165,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
 
        /* SB Extigy needs special boot-up sequence */
        /* if more models come, this will go to the quirk list. */
-       if (dev->descriptor.idVendor == 0x041e && dev->descriptor.idProduct == 0x3000) {
+       if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && 
+           le16_to_cpu(dev->descriptor.idProduct) == 0x3000) {
                if (snd_usb_extigy_boot_quirk(dev, intf) < 0)
                        goto __err_val;
                config = dev->actconfig;
@@ -3002,8 +3200,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                }
                for (i = 0; i < SNDRV_CARDS; i++)
                        if (enable[i] && ! usb_chip[i] &&
-                           (vid[i] == -1 || vid[i] == dev->descriptor.idVendor) &&
-                           (pid[i] == -1 || pid[i] == dev->descriptor.idProduct)) {
+                           (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) &&
+                           (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) {
                                if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
                                        goto __error;
                                }
@@ -3050,7 +3248,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
 
 /*
  * we need to take care of counter, since disconnection can be called also
- * many times as well as usb_audio_probe(). 
+ * many times as well as usb_audio_probe().
  */
 static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
 {
@@ -3061,7 +3259,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
        if (ptr == (void *)-1L)
                return;
 
-       chip = snd_magic_cast(snd_usb_audio_t, ptr, return);
+       chip = ptr;
        card = chip->card;
        down(&register_mutex);
        chip->shutdown = 1;
@@ -3078,7 +3276,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
                }
                usb_chip[chip->index] = NULL;
                up(&register_mutex);
-               snd_card_free_in_thread(card);
+               snd_card_free(card);
        } else {
                up(&register_mutex);
        }
@@ -3124,26 +3322,3 @@ static void __exit snd_usb_audio_cleanup(void)
 
 module_init(snd_usb_audio_init);
 module_exit(snd_usb_audio_cleanup);
-
-#ifndef MODULE
-/*
- * format is snd-usb-audio=enable,index,id,vid,pid
- */
-static int __init snd_usb_audio_module_setup(char* str)
-{
-       static unsigned __initdata nr_dev = 0;
-
-       if (nr_dev >= SNDRV_CARDS)
-               return 0;
-       (void)(get_option(&str, &enable[nr_dev]) == 2 &&
-              get_option(&str, &index[nr_dev]) == 2 &&
-              get_id(&str, &id[nr_dev]) == 2 &&
-              get_option(&str, &vid[nr_dev]) == 2 &&
-              get_option(&str, &pid[nr_dev]) == 2);
-       ++nr_dev;
-       return 1;
-}
-
-__setup("snd-usb-audio=", snd_usb_audio_module_setup);
-
-#endif /* !MODULE */