caiaq endianness fix
[safe/jmp/linux-2.6] / sound / usb / usbaudio.c
index 8ebc1ad..410be4a 100644 (file)
@@ -38,7 +38,6 @@
  */
 
 
-#include <sound/driver.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -65,9 +64,10 @@ 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 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*/
@@ -123,7 +123,6 @@ struct audioformat {
        unsigned int rate_min, rate_max;        /* min/max rates */
        unsigned int nr_rates;          /* number of rate table entries */
        unsigned int *rate_table;       /* rate table */
-       unsigned int needs_knot;        /* any unusual rates? */
 };
 
 struct snd_usb_substream;
@@ -481,6 +480,33 @@ static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs,
        return 0;
 }
 
+/*
+ * 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)
 {
@@ -662,7 +688,7 @@ static void snd_complete_urb(struct urb *urb)
        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);
@@ -685,7 +711,7 @@ static void snd_complete_sync_urb(struct urb *urb)
        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);
@@ -715,7 +741,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t s
                vfree(runtime->dma_area);
        }
        runtime->dma_area = vmalloc(size);
-       if (! runtime->dma_area)
+       if (!runtime->dma_area)
                return -ENOMEM;
        runtime->dma_bytes = size;
        return 0;
@@ -747,12 +773,12 @@ static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sl
 
        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)
                                        usb_unlink_urb(u);
@@ -764,7 +790,7 @@ static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sl
        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)
                                                usb_unlink_urb(u);
@@ -1112,12 +1138,12 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                if (subs->fmt_type == USB_FORMAT_TYPE_II)
                        u->packets++; /* for transfer delimiter */
                u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
-               if (! u->urb)
+               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)
+               if (!u->urb->transfer_buffer)
                        goto out_of_memory;
                u->urb->pipe = subs->datapipe;
                u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
@@ -1130,7 +1156,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                /* allocate and initialize sync urbs */
                subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
                                                 GFP_KERNEL, &subs->sync_dma);
-               if (! subs->syncbuf)
+               if (!subs->syncbuf)
                        goto out_of_memory;
                for (i = 0; i < SYNC_URBS; i++) {
                        struct snd_urb_ctx *u = &subs->syncurb[i];
@@ -1138,7 +1164,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri
                        u->subs = subs;
                        u->packets = 1;
                        u->urb = usb_alloc_urb(1, GFP_KERNEL);
-                       if (! u->urb)
+                       if (!u->urb)
                                goto out_of_memory;
                        u->urb->transfer_buffer = subs->syncbuf + i * 4;
                        u->urb->transfer_dma = subs->sync_dma + i * 4;
@@ -1309,7 +1335,11 @@ static int set_format(struct snd_usb_substream *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;
        }
@@ -1398,8 +1428,8 @@ static int set_format(struct snd_usb_substream *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
@@ -1434,7 +1464,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
        rate = params_rate(hw_params);
        channels = params_channels(hw_params);
        fmt = find_format(subs, format, rate, channels);
-       if (! fmt) {
+       if (!fmt) {
                snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
                           format, rate, channels);
                return -EINVAL;
@@ -1555,7 +1585,7 @@ static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audiof
        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;
        }
@@ -1591,7 +1621,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *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)
@@ -1604,7 +1634,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params,
                }
        }
 
-       if (! changed) {
+       if (!changed) {
                hwc_debug("  --> get empty\n");
                it->empty = 1;
                return -EINVAL;
@@ -1645,7 +1675,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *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)
@@ -1658,7 +1688,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params,
                }
        }
 
-       if (! changed) {
+       if (!changed) {
                hwc_debug("  --> get empty\n");
                it->empty = 1;
                return -EINVAL;
@@ -1698,7 +1728,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *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);
        }
@@ -1707,7 +1737,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *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;
        }
@@ -1733,6 +1763,10 @@ static int check_hw_params_convention(struct snd_usb_substream *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;
@@ -1761,7 +1795,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs)
                channels[f->format] |= (1 << f->channels);
                rates[f->format] |= f->rates;
                /* needs knot? */
-               if (f->needs_knot)
+               if (f->rates & SNDRV_PCM_RATE_KNOT)
                        goto __out;
        }
        /* check whether channels and rates match for all formats */
@@ -1817,7 +1851,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
                if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
                        return 0;
                count += fp->nr_rates;
-               if (fp->needs_knot)
+               if (fp->rates & SNDRV_PCM_RATE_KNOT)
                        needs_knot = 1;
        }
        if (!needs_knot)
@@ -1885,7 +1919,10 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
                                     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,
@@ -2075,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),
@@ -2089,6 +2134,8 @@ static struct usb_driver usb_audio_driver = {
        .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,
 };
 
@@ -2181,7 +2228,7 @@ static void proc_pcm_format_add(struct snd_usb_stream *stream)
        struct snd_card *card = stream->chip->card;
 
        sprintf(name, "stream%d", stream->pcm_index);
-       if (! snd_card_proc_new(card, name, &entry))
+       if (!snd_card_proc_new(card, name, &entry))
                snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
 }
 
@@ -2207,10 +2254,17 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo
        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];
+               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);
@@ -2230,7 +2284,7 @@ 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);
@@ -2280,7 +2334,7 @@ static int add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct aud
                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);
@@ -2306,7 +2360,7 @@ static int add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct aud
 
        /* create a new pcm */
        as = kzalloc(sizeof(*as), GFP_KERNEL);
-       if (! as)
+       if (!as)
                return -ENOMEM;
        as->pcm_index = chip->pcm_devs;
        as->chip = chip;
@@ -2350,7 +2404,9 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *
                        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;
 }
@@ -2413,11 +2469,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor
                }
                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;
@@ -2451,7 +2508,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                                    unsigned char *fmt, int offset)
 {
        int nr_rates = fmt[offset];
-       int found;
+
        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);
@@ -2462,20 +2519,15 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                /*
                 * build the rate table and bitmap flags
                 */
-               int r, idx, c;
+               int r, idx;
                unsigned int nonzero_rates = 0;
-               /* 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
-               };
+
                fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
                if (fp->rate_table == NULL) {
                        snd_printk(KERN_ERR "cannot malloc\n");
                        return -1;
                }
 
-               fp->needs_knot = 0;
                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) {
@@ -2491,23 +2543,12 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                                fp->rate_min = rate;
                        else if (rate > fp->rate_max)
                                fp->rate_max = rate;
-                       found = 0;
-                       for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) {
-                               if (rate == conv_rates[c]) {
-                                       found = 1;
-                                       fp->rates |= (1 << c);
-                                       break;
-                               }
-                       }
-                       if (!found)
-                               fp->needs_knot = 1;
+                       fp->rates |= snd_pcm_rate_to_rate_bit(rate);
                }
                if (!nonzero_rates) {
                        hwc_debug("All rates were zero. Skipping format!\n");
                        return -1;
                }
-               if (fp->needs_knot)
-                       fp->rates |= SNDRV_PCM_RATE_KNOT;
        } else {
                /* continuous rates */
                fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
@@ -2530,7 +2571,18 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *
                 *        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)
@@ -2626,12 +2678,23 @@ static int parse_audio_endpoints(struct snd_usb_audio *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 */
@@ -2844,6 +2907,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *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);
@@ -2863,7 +2930,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
        struct audioformat *fp;
        struct usb_host_interface *alts;
        int stream, err;
-       int *rate_table = NULL;
+       unsigned *rate_table = NULL;
 
        fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
        if (! fp) {
@@ -3251,6 +3318,11 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
 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)
@@ -3321,14 +3393,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip,
 static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
        struct snd_usb_audio *chip = entry->private_data;
-       if (! chip->shutdown)
+       if (!chip->shutdown)
                snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum);
 }
 
 static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
        struct snd_usb_audio *chip = entry->private_data;
-       if (! chip->shutdown)
+       if (!chip->shutdown)
                snd_iprintf(buffer, "%04x:%04x\n", 
                            USB_ID_VENDOR(chip->usb_id),
                            USB_ID_PRODUCT(chip->usb_id));
@@ -3337,9 +3409,9 @@ static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_
 static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
 {
        struct snd_info_entry *entry;
-       if (! snd_card_proc_new(chip->card, "usbbus", &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))
+       if (!snd_card_proc_new(chip->card, "usbid", &entry))
                snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
 }
 
@@ -3352,7 +3424,6 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
 
 static int snd_usb_audio_free(struct snd_usb_audio *chip)
 {
-       usb_chip[chip->index] = NULL;
        kfree(chip);
        return 0;
 }
@@ -3381,7 +3452,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
 
        *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;
@@ -3455,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);
@@ -3543,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;
                }
        }
@@ -3614,6 +3688,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
                list_for_each(p, &chip->mixer_list) {
                        snd_usb_mixer_disconnect(p);
                }
+               usb_chip[chip->index] = NULL;
                mutex_unlock(&register_mutex);
                snd_card_free_when_closed(card);
        } else {
@@ -3642,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)
 {