Update of /cvsroot/alsa/alsa-kernel/usb
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22583

Modified Files:
        usbaudio.c 
Log Message:
high speed support

Index: usbaudio.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.c,v
retrieving revision 1.91
retrieving revision 1.92
diff -u -r1.91 -r1.92
--- usbaudio.c  18 Mar 2004 14:57:03 -0000      1.91
+++ usbaudio.c  19 Mar 2004 07:46:03 -0000      1.92
@@ -104,6 +104,7 @@
  */
 
 #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 MIN_PACKS_URB  1       /* minimum 1 packet per urb */
@@ -161,8 +162,8 @@
        unsigned int datapipe;   /* the data i/o pipe */
        unsigned int syncpipe;   /* 1 - async out or adaptive in */
        unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
-       unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 
in Q10.14 */
-       unsigned int freqm;      /* momentary sampling rate in USB format, i.e. 
fs/1000 in Q10.14 */
+       unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */
+       unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format 
*/
        unsigned int freqmax;    /* maximum sampling rate, used for buffer management 
*/
        unsigned int phase;      /* phase accumulator */
        unsigned int maxpacksize;       /* max packet size in bytes */
@@ -184,7 +185,7 @@
        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 * 3]; /* sync buffer; it's so small - let's 
get static */
+       char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's 
get static */
        char *tmpbuf;                   /* temporary buffer for playback */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
@@ -218,17 +219,38 @@
 
 
 /*
- * convert a sampling rate into USB format (fs/1000 in Q10.14)
- * this will overflow at approx 2MSPS
+ * 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_rate(unsigned int rate)
+inline static unsigned get_usb_full_speed_rate(unsigned int rate)
 {
-       return ((rate << 11) + 62) / 125;
+       return ((rate << 13) + 62) / 125;
+}
+
+/*
+ * 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)
+{
+       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)
+{
+       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)
+{
+       return (usb_rate * 125 + (1 << 9)) >> 10;
 }
 
 
 /*
- * prepare urb for capture sync pipe
+ * prepare urb for full speed capture sync pipe
  *
  * fill the length and offset of each urb descriptor.
  * the fixed 10.14 frequency is passed through the pipe.
@@ -243,14 +265,40 @@
 
        urb->number_of_packets = ctx->packets;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3, cp += 3) {
+       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;
+       }
+       return 0;
+}
+
+/*
+ * prepare urb for high speed capture sync pipe
+ *
+ * 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,
+                                      struct urb *urb)
+{
+       unsigned char *cp = urb->transfer_buffer;
+       snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+       int i, offs;
+
+       urb->number_of_packets = ctx->packets;
+       urb->dev = ctx->subs->dev; /* we need to set this at each time */
+       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 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->interval = 1;
        return 0;
 }
 
@@ -301,7 +349,6 @@
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer = ctx->buf;
        urb->transfer_buffer_length = offs;
-       urb->interval = 1;
 #if 0 // for check
        if (! urb->bandwidth) {
                int bustime;
@@ -372,7 +419,7 @@
 
 
 /*
- * prepare urb for playback sync pipe
+ * prepare urb for full speed playback sync pipe
  *
  * set up the offset and length to receive the current frequency.
  */
@@ -386,16 +433,37 @@
 
        urb->number_of_packets = ctx->packets;
        urb->dev = ctx->subs->dev; /* we need to set this at each time */
-       for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3) {
+       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->interval = 1;
        return 0;
 }
 
 /*
- * process after playback sync complete
+ * prepare urb for high speed playback sync pipe
+ *
+ * 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,
+                                       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;
+       }
+       return 0;
+}
+
+/*
+ * process after full speed playback sync complete
  *
  * retrieve the current 10.14 frequency from pipe, and set it.
  * the value is referred in prepare_playback_urb().
@@ -410,11 +478,11 @@
        unsigned long flags;
 
        found = 0;
-       for (i = 0; i < urb->number_of_packets; i++, cp += 3) {
+       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);
+               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",
@@ -435,6 +503,37 @@
 }
 
 /*
+ * process after high speed playback sync complete
+ *
+ * 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,
+                                      struct urb *urb)
+{
+       int i;
+       unsigned int found;
+       unsigned char *cp = urb->transfer_buffer;
+       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);
+       }
+
+       return 0;
+}
+
+/*
  * prepare urb for playback data pipe
  *
  * we copy the data directly from the pcm buffer.
@@ -464,8 +563,8 @@
                if (subs->fill_max)
                        counts = subs->maxframesize; /* fixed */
                else {
-                       subs->phase = (subs->phase & 0x3fff) + subs->freqm;
-                       counts = subs->phase >> 14;
+                       subs->phase = (subs->phase & 0xffff) + subs->freqm;
+                       counts = subs->phase >> 16;
                        if (counts > subs->maxframesize)
                                counts = subs->maxframesize;
                }
@@ -515,7 +614,6 @@
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = offs * stride;
        ctx->transfer = offs;
-       urb->interval = 1;
 
        return 0;
 }
@@ -565,6 +663,21 @@
        },
 };
 
+static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
+       {
+               .prepare =      prepare_playback_urb,
+               .retire =       retire_playback_urb,
+               .prepare_sync = prepare_playback_sync_urb_hs,
+               .retire_sync =  retire_playback_sync_urb_hs,
+       },
+       {
+               .prepare =      prepare_capture_urb,
+               .retire =       retire_capture_urb,
+               .prepare_sync = prepare_capture_sync_urb_hs,
+               .retire_sync =  retire_capture_sync_urb,
+       },
+};
+
 /*
  * complete callback from data urb
  */
@@ -822,15 +935,19 @@
 {
        unsigned int maxsize, n, i;
        int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-       unsigned int npacks[MAX_URBS], total_packs;
+       unsigned int npacks[MAX_URBS], urb_packs, total_packs;
 
-       /* calculate the frequency in 10.14 format */
-       subs->freqn = subs->freqm = get_usb_rate(rate);
+       /* calculate the frequency in 16.16 format */
+       if (subs->dev->speed == USB_SPEED_FULL)
+               subs->freqn = get_usb_full_speed_rate(rate);
+       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 + 0x3fff) * (frame_bits >> 3)) >> 14;
+       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);
@@ -842,9 +959,14 @@
        else
                subs->curpacksize = maxsize;
 
+       if (subs->dev->speed == USB_SPEED_FULL)
+               urb_packs = nrpacks;
+       else
+               urb_packs = nrpacks * 8;
+
        /* allocate a temporary buffer for playback */
        if (is_playback) {
-               subs->tmpbuf = kmalloc(maxsize * nrpacks, GFP_KERNEL);
+               subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
                if (! subs->tmpbuf) {
                        snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
                        return -ENOMEM;
@@ -855,16 +977,16 @@
        total_packs = (period_bytes + maxsize - 1) / maxsize;
        if (total_packs < 2 * MIN_PACKS_URB)
                total_packs = 2 * MIN_PACKS_URB;
-       subs->nurbs = (total_packs + nrpacks - 1) / nrpacks;
+       subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
        if (subs->nurbs > MAX_URBS) {
                /* too much... */
                subs->nurbs = MAX_URBS;
-               total_packs = MAX_URBS * nrpacks;
+               total_packs = MAX_URBS * urb_packs;
        }
        n = total_packs;
        for (i = 0; i < subs->nurbs; i++) {
-               npacks[i] = n > nrpacks ? nrpacks : n;
-               n -= nrpacks;
+               npacks[i] = n > urb_packs ? urb_packs : n;
+               n -= urb_packs;
        }
        if (subs->nurbs <= 1) {
                /* too little - we need at least two packets
@@ -913,6 +1035,7 @@
                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->context = u;
                u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
        }
@@ -929,12 +1052,13 @@
                                release_substream_urbs(subs, 0);
                                return -ENOMEM;
                        }
-                       u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 3;
-                       u->urb->transfer_buffer_length = nrpacks * 3;
+                       u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4;
+                       u->urb->transfer_buffer_length = nrpacks * 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->interval = subs->dev->speed == USB_SPEED_HIGH ? 8 : 1;
                        u->urb->context = u;
                        u->urb->complete = 
snd_usb_complete_callback(snd_complete_sync_urb);
                }
@@ -1116,7 +1240,7 @@
        else
                subs->datapipe = usb_rcvisocpipe(dev, ep);
        subs->syncpipe = subs->syncinterval = 0;
-       subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
+       subs->maxpacksize = fmt->maxpacksize;
        subs->fill_max = 0;
 
        /* we need a sync pipe in async OUT or adaptive IN mode */
@@ -1836,11 +1960,10 @@
                        snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
                snd_iprintf(buffer, "]\n");
                snd_iprintf(buffer, "    Packet Size = %d\n", subs->curpacksize);
-               snd_iprintf(buffer, "    Momentary freq = %d.%d Hz\n",
-                           (subs->freqm * 125) >> 11,
-                           (subs->freqm >> 10) * 625
-                           + (((subs->freqm & ((1 << 10) - 1)) * 625) >> 10)
-                           - 10 * ((subs->freqm * 125) >> 11));
+               snd_iprintf(buffer, "    Momentary freq = %u Hz\n",
+                           subs->dev->speed == USB_SPEED_FULL
+                           ? get_full_speed_hz(subs->freqm)
+                           : get_high_speed_hz(subs->freqm));
        } else {
                snd_iprintf(buffer, "  Status: Stop\n");
        }
@@ -1890,7 +2013,10 @@
        subs->stream = as;
        subs->direction = stream;
        subs->dev = as->chip->dev;
-       subs->ops = audio_urb_ops[stream];
+       if (subs->dev->speed == USB_SPEED_FULL)
+               subs->ops = audio_urb_ops[stream];
+       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),
@@ -2351,6 +2477,7 @@
                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 = get_endpoint(alts, 0)->wMaxPacketSize;
                fp->attributes = csep[3];
 
@@ -2728,6 +2855,14 @@
        };
        
        *rchip = NULL;
+
+       if (dev->speed != USB_SPEED_FULL &&
+           dev->speed != USB_SPEED_HIGH) {
+               snd_printk(KERN_ERR "unknown device speed %d\n", dev->speed);
+               snd_usb_audio_free(chip);
+               return -ENXIO;
+       }
+
        chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL);
        if (! chip)
                return -ENOMEM;
@@ -2781,6 +2916,10 @@
        if (len < sizeof(card->longname))
                usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
 
+       strlcat(card->longname,
+               dev->speed == USB_SPEED_FULL ? ", full speed" : ", high speed",
+               sizeof(card->longname));
+
        snd_usb_audio_create_proc(chip);
 
        snd_card_set_dev(card, &dev->dev);



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to