/home/lenb/src/to-linus branch 'acpi-2.6.12'
[powerpc.git] / sound / usb / usbaudio.c
index e1a648d..b5e734d 100644 (file)
@@ -98,7 +98,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
 #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 */
+#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;
@@ -177,7 +177,7 @@ struct snd_usb_substream {
        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 * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */
+       char syncbuf[SYNC_URBS * 4];    /* sync buffer; it's so small - let's get static */
        char *tmpbuf;                   /* temporary buffer for playback */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
@@ -212,7 +212,7 @@ static snd_usb_audio_t *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 +221,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;
 }
@@ -251,17 +251,13 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs,
 {
        unsigned char *cp = urb->transfer_buffer;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
-       int i, offs;
 
-       urb->number_of_packets = ctx->packets;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
-               urb->iso_frame_desc[i].length = 3;
-               urb->iso_frame_desc[i].offset = offs;
-               cp[0] = subs->freqn >> 2;
-               cp[1] = subs->freqn >> 10;
-               cp[2] = subs->freqn >> 18;
-       }
+       urb->iso_frame_desc[0].length = 3;
+       urb->iso_frame_desc[0].offset = 0;
+       cp[0] = subs->freqn >> 2;
+       cp[1] = subs->freqn >> 10;
+       cp[2] = subs->freqn >> 18;
        return 0;
 }
 
@@ -277,18 +273,14 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs,
 {
        unsigned char *cp = urb->transfer_buffer;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
-       int i, offs;
 
-       urb->number_of_packets = ctx->packets;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
-               urb->iso_frame_desc[i].length = 4;
-               urb->iso_frame_desc[i].offset = offs;
-               cp[0] = subs->freqn;
-               cp[1] = subs->freqn >> 8;
-               cp[2] = subs->freqn >> 16;
-               cp[3] = subs->freqn >> 24;
-       }
+       urb->iso_frame_desc[0].length = 4;
+       urb->iso_frame_desc[0].offset = 0;
+       cp[0] = subs->freqn;
+       cp[1] = subs->freqn >> 8;
+       cp[2] = subs->freqn >> 16;
+       cp[3] = subs->freqn >> 24;
        return 0;
 }
 
@@ -418,15 +410,11 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs,
                                     snd_pcm_runtime_t *runtime,
                                     struct urb *urb)
 {
-       int i, offs;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
 
-       urb->number_of_packets = ctx->packets;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
-               urb->iso_frame_desc[i].length = 3;
-               urb->iso_frame_desc[i].offset = offs;
-       }
+       urb->iso_frame_desc[0].length = 3;
+       urb->iso_frame_desc[0].offset = 0;
        return 0;
 }
 
@@ -440,15 +428,11 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs,
                                        snd_pcm_runtime_t *runtime,
                                        struct urb *urb)
 {
-       int i, offs;
        snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
 
-       urb->number_of_packets = ctx->packets;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
-               urb->iso_frame_desc[i].length = 4;
-               urb->iso_frame_desc[i].offset = offs;
-       }
+       urb->iso_frame_desc[0].length = 4;
+       urb->iso_frame_desc[0].offset = 0;
        return 0;
 }
 
@@ -462,31 +446,17 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs,
                                    snd_pcm_runtime_t *runtime,
                                    struct urb *urb)
 {
-       int i;
-       unsigned int f, found;
-       unsigned char *cp = urb->transfer_buffer;
+       unsigned int f;
        unsigned long flags;
 
-       found = 0;
-       for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
-               if (urb->iso_frame_desc[i].status ||
-                   urb->iso_frame_desc[i].actual_length < 3)
-                       continue;
-               f = combine_triple(cp) << 2;
-#if 0
-               if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) {
-                       snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n",
-                                  f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1),
-                                  subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1));
-                       continue;
+       if (urb->iso_frame_desc[0].status == 0 &&
+           urb->iso_frame_desc[0].actual_length == 3) {
+               f = combine_triple((u8*)urb->transfer_buffer) << 2;
+               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);
                }
-#endif
-               found = f;
-       }
-       if (found) {
-               spin_lock_irqsave(&subs->lock, flags);
-               subs->freqm = found;
-               spin_unlock_irqrestore(&subs->lock, flags);
        }
 
        return 0;
@@ -502,22 +472,17 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
                                       snd_pcm_runtime_t *runtime,
                                       struct urb *urb)
 {
-       int i;
-       unsigned int found;
-       unsigned char *cp = urb->transfer_buffer;
+       unsigned int f;
        unsigned long flags;
 
-       found = 0;
-       for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
-               if (urb->iso_frame_desc[i].status ||
-                   urb->iso_frame_desc[i].actual_length < 4)
-                       continue;
-               found = combine_quad(cp) & 0x0fffffff;
-       }
-       if (found) {
-               spin_lock_irqsave(&subs->lock, flags);
-               subs->freqm = found;
-               spin_unlock_irqrestore(&subs->lock, 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;
+               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;
@@ -600,6 +565,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
                /* 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;
        }
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = offs * stride;
@@ -892,10 +859,8 @@ static void release_urb_ctx(snd_urb_ctx_t *u)
                usb_free_urb(u->urb);
                u->urb = NULL;
        }
-       if (u->buf) {
-               kfree(u->buf);
-               u->buf = NULL;
-       }
+       kfree(u->buf);
+       u->buf = NULL;
 }
 
 /*
@@ -913,10 +878,8 @@ 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;
-       }
+       kfree(subs->tmpbuf);
+       subs->tmpbuf = NULL;
        subs->nurbs = 0;
 }
 
@@ -1039,18 +1002,18 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
                        snd_urb_ctx_t *u = &subs->syncurb[i];
                        u->index = i;
                        u->subs = subs;
-                       u->packets = nrpacks;
-                       u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
+                       u->packets = 1;
+                       u->urb = usb_alloc_urb(1, GFP_KERNEL);
                        if (! u->urb) {
                                release_substream_urbs(subs, 0);
                                return -ENOMEM;
                        }
-                       u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4;
-                       u->urb->transfer_buffer_length = nrpacks * 4;
+                       u->urb->transfer_buffer = subs->syncbuf + 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->number_of_packets = u->packets;
+                       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);
@@ -1273,8 +1236,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 */
@@ -2530,32 +2498,31 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 
                /* some quirks for attributes here */
 
-               /* workaround for AudioTrak Optoplay */
-               if (chip->usb_id == USB_ID(0x0a92, 0x0053)) {
+               switch (chip->usb_id) {
+               case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
                        /* Optoplay sets the sample rate attribute although
                         * it seems not supporting it in fact.
                         */
                        fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE;
-               }
-
-               /* workaround for M-Audio Audiophile USB */
-               if (chip->usb_id == USB_ID(0x0763, 0x2003)) {
+                       break;
+               case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
+               case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
                        /* doesn't set the sample rate attribute, but supports it */
                        fp->attributes |= EP_CS_ATTR_SAMPLE_RATE;
-               }
-
+                       break;
+               case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
+               case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
+                                               an older model 77d:223) */
                /*
                 * plantronics headset and Griffin iMic have set adaptive-in
                 * although it's really not...
                 */
-               if (chip->usb_id == USB_ID(0x047f, 0x0ca1) ||
-                   /* Griffin iMic (note that there is an older model 77d:223) */
-                   chip->usb_id == USB_ID(0x077d, 0x07af)) {
                        fp->ep_attr &= ~EP_ATTR_MASK;
                        if (stream == SNDRV_PCM_STREAM_PLAYBACK)
                                fp->ep_attr |= EP_ATTR_ADAPTIVE;
                        else
                                fp->ep_attr |= EP_ATTR_SYNC;
+                       break;
                }
 
                /* ok, let's parse further... */
@@ -2957,6 +2924,25 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
        return 0;
 }
 
+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,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                       0, 0, &buf, 1, 1000);
+       if (buf == 0) {
+               snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                               1, 2000, NULL, 0, 1000);
+               return -ENODEV;
+       }
+#endif
+       return 0;
+}
+
 
 /*
  * audio-interface quirks
@@ -3142,8 +3128,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
 
        snd_usb_audio_create_proc(chip);
 
-       snd_card_set_dev(card, &dev->dev);
-
        *rchip = chip;
        return 0;
 }
@@ -3186,6 +3170,11 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                        goto __err_val;
                config = dev->actconfig;
        }
+       /* SB Audigy 2 NX needs its own boot-up magic, too */
+       if (id == USB_ID(0x041e, 0x3020)) {
+               if (snd_usb_audigy2nx_boot_quirk(dev) < 0)
+                       goto __err_val;
+       }
 
        /*
         * found a config.  now register to ALSA
@@ -3220,6 +3209,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
                                if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
                                        goto __error;
                                }
+                               snd_card_set_dev(chip->card, &intf->dev);
                                break;
                        }
                if (! chip) {