#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;
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) */
* 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;
}
* 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;
}
{
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;
}
{
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;
}
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;
}
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;
}
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;
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;
/* 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;
usb_free_urb(u->urb);
u->urb = NULL;
}
- if (u->buf) {
- kfree(u->buf);
- u->buf = NULL;
- }
+ kfree(u->buf);
+ u->buf = NULL;
}
/*
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;
}
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);
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 */
/* 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... */
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
snd_usb_audio_create_proc(chip);
- snd_card_set_dev(card, &dev->dev);
-
*rchip = chip;
return 0;
}
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
if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
goto __error;
}
+ snd_card_set_dev(chip->card, &intf->dev);
break;
}
if (! chip) {