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