Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
- index 0fd3fbd..f7120e9 100644
- --- a/include/linux/usb/ch9.h
- +++ b/include/linux/usb/ch9.h
- @@ -377,11 +377,10 @@ struct usb_endpoint_descriptor {
- #define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
- #define USB_ENDPOINT_DIR_MASK 0x80
- -#define USB_ENDPOINT_SYNCTYPE 0x0c
- -#define USB_ENDPOINT_SYNC_NONE (0 << 2)
- -#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
- -#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
- -#define USB_ENDPOINT_SYNC_SYNC (3 << 2)
- +#define USB_ENDPOINT_USAGE_MASK 0x30
- +#define USB_ENDPOINT_USAGE_DATA 0x00
- +#define USB_ENDPOINT_USAGE_FEEDBACK 0x10
- +#define USB_ENDPOINT_USAGE_IMPLICIT_FB 0x20 /* Implicit feedback Data endpoint */
- #define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
- #define USB_ENDPOINT_XFER_CONTROL 0
- @@ -390,6 +389,12 @@ struct usb_endpoint_descriptor {
- #define USB_ENDPOINT_XFER_INT 3
- #define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
- +#define USB_ENDPOINT_SYNCTYPE 0x0c
- +#define USB_ENDPOINT_SYNC_NONE (0 << 2)
- +#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
- +#define USB_ENDPOINT_SYNC_ADAPTIVE (2 << 2)
- +#define USB_ENDPOINT_SYNC_SYNC (3 << 2)
- +
- /*-------------------------------------------------------------------------*/
- /**
- diff --git a/sound/usb/Makefile b/sound/usb/Makefile
- index cf9ed66..ac256dc 100644
- --- a/sound/usb/Makefile
- +++ b/sound/usb/Makefile
- @@ -3,16 +3,16 @@
- #
- snd-usb-audio-objs := card.o \
- + clock.o \
- + endpoint.o \
- + format.o \
- + helper.o \
- mixer.o \
- mixer_quirks.o \
- + pcm.o \
- proc.o \
- quirks.o \
- - format.o \
- - endpoint.o \
- - urb.o \
- - pcm.o \
- - helper.o \
- - clock.o
- + stream.o
- snd-usbmidi-lib-objs := midi.o
- diff --git a/sound/usb/card.c b/sound/usb/card.c
- index 781d9e6..2029465 100644
- --- a/sound/usb/card.c
- +++ b/sound/usb/card.c
- @@ -65,9 +65,9 @@
- #include "helper.h"
- #include "debug.h"
- #include "pcm.h"
- -#include "urb.h"
- #include "format.h"
- #include "power.h"
- +#include "stream.h"
- MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
- MODULE_DESCRIPTION("USB Audio");
- @@ -130,7 +130,7 @@ static void snd_usb_stream_disconnect(struct list_head *head)
- subs = &as->substream[idx];
- if (!subs->num_formats)
- continue;
- - snd_usb_release_substream_urbs(subs, 1);
- +
- subs->interface = -1;
- }
- }
- @@ -185,7 +185,7 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
- return -EINVAL;
- }
- - if (! snd_usb_parse_audio_endpoints(chip, interface)) {
- + if (! snd_usb_parse_audio_interface(chip, interface)) {
- usb_set_interface(dev, interface, 0); /* reset the current interface */
- usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
- return -EINVAL;
- @@ -347,6 +347,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
- chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
- INIT_LIST_HEAD(&chip->pcm_list);
- + INIT_LIST_HEAD(&chip->ep_list);
- INIT_LIST_HEAD(&chip->midi_list);
- INIT_LIST_HEAD(&chip->mixer_list);
- @@ -561,6 +562,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
- list_for_each(p, &chip->pcm_list) {
- snd_usb_stream_disconnect(p);
- }
- + /* release the endpoint resources */
- + list_for_each(p, &chip->ep_list) {
- + snd_usb_endpoint_free(p);
- + }
- /* release the midi resources */
- list_for_each(p, &chip->midi_list) {
- snd_usbmidi_disconnect(p);
- diff --git a/sound/usb/card.h b/sound/usb/card.h
- index ae4251d..63f9e09 100644
- --- a/sound/usb/card.h
- +++ b/sound/usb/card.h
- @@ -3,7 +3,7 @@
- #define MAX_PACKS 20
- #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
- -#define MAX_URBS 8
- +#define MAX_URBS 16
- #define SYNC_URBS 4 /* always four urbs for sync */
- #define MAX_QUEUE 24 /* try not to exceed this queue length, in ms */
- @@ -28,21 +28,62 @@ struct audioformat {
- unsigned char clock; /* associated clock */
- };
- -struct snd_usb_substream;
- +struct snd_usb_endpoint;
- struct snd_urb_ctx {
- struct urb *urb;
- unsigned int buffer_size; /* size of data buffer, if data URB */
- - struct snd_usb_substream *subs;
- + struct snd_usb_endpoint *ep;
- int index; /* index for urb array */
- int packets; /* number of packets per urb */
- + int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
- };
- -struct snd_urb_ops {
- - int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- - int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- - int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- - int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- +struct snd_usb_substream;
- +
- +struct snd_usb_endpoint {
- + struct snd_usb_audio *chip;
- +
- + int use_count;
- + int ep_num; /* the referenced endpoint number */
- + int type; /* SND_USB_ENDPOINT_TYPE_* */
- +
- + void (* prepare_data_urb) (struct snd_usb_substream *subs,
- + struct urb *urb);
- + void (* retire_data_urb) (struct snd_usb_substream *subs,
- + struct urb *urb);
- +
- + struct snd_usb_substream *data_subs;
- + struct snd_usb_endpoint *sync_master;
- + struct snd_usb_endpoint *sync_slave;
- +
- + struct snd_urb_ctx urb[MAX_URBS];
- + unsigned int nurbs; /* # urbs */
- + unsigned long active_mask; /* bitmask of active urbs */
- + unsigned long unlink_mask; /* bitmask of unlinked urbs */
- + char *syncbuf; /* sync buffer for all sync URBs */
- + dma_addr_t sync_dma; /* DMA address of syncbuf */
- +
- + unsigned int pipe; /* the data i/o pipe */
- + 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 */
- + int freqshift; /* how much to shift the feedback value to get Q16.16 */
- + unsigned int freqmax; /* maximum sampling rate, used for buffer management */
- + unsigned int phase; /* phase accumulator */
- + unsigned int maxpacksize; /* max packet size in bytes */
- + unsigned int maxframesize; /* max packet size in frames */
- + unsigned int curpacksize; /* current packet size in bytes (for capture) */
- + unsigned int curframesize; /* current packet size in frames (for capture) */
- + unsigned int syncmaxsize; /* sync endpoint packet size */
- + unsigned int fill_max: 1; /* fill max packet size always */
- + unsigned int datainterval; /* log_2 of data packet interval */
- + unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
- + unsigned char silence_value;
- + unsigned int stride;
- + int iface, alt_idx;
- +
- + spinlock_t lock;
- + struct list_head list;
- };
- struct snd_usb_substream {
- @@ -51,49 +92,27 @@ struct snd_usb_substream {
- struct snd_pcm_substream *pcm_substream;
- int direction; /* playback or capture */
- int interface; /* current interface */
- - int endpoint; /* assigned endpoint */
- struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
- unsigned int cur_rate; /* current rate (for hw_params callback) */
- unsigned int period_bytes; /* current period bytes (for hw_params callback) */
- unsigned int altset_idx; /* USB data format: index of alternate setting */
- - unsigned int datapipe; /* the data i/o pipe */
- - unsigned int syncpipe; /* 1 - async out or adaptive in */
- - unsigned int datainterval; /* log_2 of data packet interval */
- - unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
- - 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 */
- - int freqshift; /* how much to shift the feedback value to get Q16.16 */
- - unsigned int freqmax; /* maximum sampling rate, used for buffer management */
- - unsigned int phase; /* phase accumulator */
- - unsigned int maxpacksize; /* max packet size in bytes */
- - unsigned int maxframesize; /* max packet size in frames */
- - unsigned int curpacksize; /* current packet size in bytes (for capture) */
- - unsigned int curframesize; /* current packet size in frames (for capture) */
- - unsigned int syncmaxsize; /* sync endpoint packet size */
- - unsigned int fill_max: 1; /* fill max packet size always */
- unsigned int txfr_quirk:1; /* allow sub-frame alignment */
- unsigned int fmt_type; /* USB audio format type (1-3) */
- - unsigned int running: 1; /* running status */
- -
- unsigned int hwptr_done; /* processed byte position in the buffer */
- unsigned int transfer_done; /* processed frames since last period update */
- - unsigned long active_mask; /* bitmask of active urbs */
- - unsigned long unlink_mask; /* bitmask of unlinked urbs */
- - unsigned int nurbs; /* # urbs */
- - struct snd_urb_ctx dataurb[MAX_URBS]; /* data urb table */
- - struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */
- - char *syncbuf; /* sync buffer for all sync URBs */
- - dma_addr_t sync_dma; /* DMA address of syncbuf */
- + /* data and sync endpoints for this stream */
- + struct snd_usb_endpoint *data_endpoint;
- + struct snd_usb_endpoint *sync_endpoint;
- + unsigned int data_endpoint_started:1;
- + unsigned int sync_endpoint_started:1;
- u64 formats; /* format bitmasks (all or'ed) */
- unsigned int num_formats; /* number of supported audio formats (list) */
- struct list_head fmt_list; /* format list */
- struct snd_pcm_hw_constraint_list rate_list; /* limited rates */
- spinlock_t lock;
- -
- - struct snd_urb_ops ops; /* callbacks (must be filled at init) */
- };
- struct snd_usb_stream {
- diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
- index 7d46e48..2dd7b50 100644
- --- a/sound/usb/endpoint.c
- +++ b/sound/usb/endpoint.c
- @@ -15,436 +15,847 @@
- *
- */
- +#include <linux/gfp.h>
- #include <linux/init.h>
- -#include <linux/slab.h>
- #include <linux/usb.h>
- #include <linux/usb/audio.h>
- -#include <linux/usb/audio-v2.h>
- +#include <linux/slab.h>
- #include <sound/core.h>
- #include <sound/pcm.h>
- +#include <sound/pcm_params.h>
- #include "usbaudio.h"
- +#include "helper.h"
- #include "card.h"
- -#include "proc.h"
- -#include "quirks.h"
- #include "endpoint.h"
- -#include "urb.h"
- #include "pcm.h"
- -#include "helper.h"
- -#include "format.h"
- -#include "clock.h"
- /*
- - * free a substream
- + * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
- + * this will overflow at approx 524 kHz
- */
- -static void free_substream(struct snd_usb_substream *subs)
- +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
- + */
- +static unsigned get_usb_high_speed_rate(unsigned int rate)
- +{
- + return ((rate << 10) + 62) / 125;
- +}
- +
- +int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
- +{
- + return ep->sync_master &&
- + ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
- + ep->type == SND_USB_ENDPOINT_TYPE_DATA &&
- + usb_pipeout(ep->pipe);
- +}
- +
- +/* determine the number of frames in the next packet */
- +static int next_packet_size(struct snd_usb_endpoint *ep)
- {
- - struct list_head *p, *n;
- -
- - 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);
- - kfree(fp->rate_table);
- - kfree(fp);
- + if (ep->fill_max)
- + return ep->maxframesize;
- + else {
- + ep->phase = (ep->phase & 0xffff)
- + + (ep->freqm << ep->datainterval);
- + return min(ep->phase >> 16, ep->maxframesize);
- }
- - kfree(subs->rate_list.list);
- }
- +static void retire_outbound_urb(struct snd_usb_endpoint *ep,
- + struct snd_urb_ctx *urb_ctx)
- +{
- + if (ep->retire_data_urb)
- + ep->retire_data_urb(ep->data_subs, urb_ctx->urb);
- +}
- +
- +static void retire_inbound_urb(struct snd_usb_endpoint *ep,
- + struct snd_urb_ctx *urb_ctx)
- +{
- + struct urb *urb = urb_ctx->urb;
- +
- + if (ep->sync_slave)
- + snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
- +
- + if (ep->retire_data_urb)
- + ep->retire_data_urb(ep->data_subs, urb);
- +}
- +
- +static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep,
- + struct snd_urb_ctx *ctx)
- +{
- + int i;
- +
- + for (i = 0; i < ctx->packets; ++i)
- + ctx->packet_size[i] = next_packet_size(ep);
- +}
- /*
- - * free a usb stream instance
- + * Prepare a PLAYBACK urb for submission to the bus.
- */
- -static void snd_usb_audio_stream_free(struct snd_usb_stream *stream)
- +static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
- + struct snd_urb_ctx *ctx)
- {
- - free_substream(&stream->substream[0]);
- - free_substream(&stream->substream[1]);
- - list_del(&stream->list);
- - kfree(stream);
- + int i;
- + struct urb *urb = ctx->urb;
- + unsigned char *cp = urb->transfer_buffer;
- +
- + urb->dev = ep->chip->dev; /* we need to set this at each time */
- +
- + switch (ep->type) {
- + case SND_USB_ENDPOINT_TYPE_DATA:
- + if (ep->prepare_data_urb) {
- + ep->prepare_data_urb(ep->data_subs, urb);
- + } else {
- + /* no data provider, so send silence */
- + unsigned int offs = 0;
- + for (i = 0; i < ctx->packets; ++i) {
- + int counts = ctx->packet_size[i];
- + urb->iso_frame_desc[i].offset = offs * ep->stride;
- + urb->iso_frame_desc[i].length = counts * ep->stride;
- + offs += counts;
- + }
- +
- + urb->number_of_packets = ctx->packets;
- + urb->transfer_buffer_length = offs * ep->stride;
- + memset(urb->transfer_buffer, ep->silence_value,
- + offs * ep->stride);
- + }
- + break;
- +
- + case SND_USB_ENDPOINT_TYPE_SYNC:
- + if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {
- + /*
- + * fill the length and offset of each urb descriptor.
- + * the fixed 12.13 frequency is passed as 16.16 through the pipe.
- + */
- + urb->iso_frame_desc[0].length = 4;
- + urb->iso_frame_desc[0].offset = 0;
- + cp[0] = ep->freqn;
- + cp[1] = ep->freqn >> 8;
- + cp[2] = ep->freqn >> 16;
- + cp[3] = ep->freqn >> 24;
- + } else {
- + /*
- + * fill the length and offset of each urb descriptor.
- + * the fixed 10.14 frequency is passed through the pipe.
- + */
- + urb->iso_frame_desc[0].length = 3;
- + urb->iso_frame_desc[0].offset = 0;
- + cp[0] = ep->freqn >> 2;
- + cp[1] = ep->freqn >> 10;
- + cp[2] = ep->freqn >> 18;
- + }
- +
- + break;
- + }
- }
- -static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
- +/*
- + * Prepare a CAPTURE or SYNC urb for submission to the bus.
- + */
- +static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
- + struct snd_urb_ctx *urb_ctx)
- {
- - struct snd_usb_stream *stream = pcm->private_data;
- - if (stream) {
- - stream->pcm = NULL;
- - snd_usb_audio_stream_free(stream);
- + int i, offs;
- + struct urb *urb = urb_ctx->urb;
- +
- + urb->dev = ep->chip->dev; /* we need to set this at each time */
- +
- + switch (ep->type) {
- + case SND_USB_ENDPOINT_TYPE_DATA:
- + offs = 0;
- + for (i = 0; i < urb_ctx->packets; i++) {
- + urb->iso_frame_desc[i].offset = offs;
- + urb->iso_frame_desc[i].length = ep->curpacksize;
- + offs += ep->curpacksize;
- + }
- +
- + urb->transfer_buffer_length = offs;
- + urb->number_of_packets = urb_ctx->packets;
- + break;
- +
- + case SND_USB_ENDPOINT_TYPE_SYNC:
- + urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize);
- + urb->iso_frame_desc[0].offset = 0;
- + break;
- }
- }
- -
- /*
- - * add this endpoint to the chip instance.
- - * if a stream with the same endpoint already exists, append to it.
- - * if not, create a new pcm stream.
- + * complete callback for urbs
- */
- -int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp)
- +static void snd_complete_urb(struct urb *urb)
- {
- - struct list_head *p;
- - struct snd_usb_stream *as;
- - struct snd_usb_substream *subs;
- - struct snd_pcm *pcm;
- + struct snd_urb_ctx *ctx = urb->context;
- + struct snd_usb_endpoint *ep = ctx->ep;
- int err;
- - list_for_each(p, &chip->pcm_list) {
- - as = list_entry(p, struct snd_usb_stream, list);
- - if (as->fmt_type != fp->fmt_type)
- - continue;
- - subs = &as->substream[stream];
- - if (!subs->endpoint)
- - continue;
- - if (subs->endpoint == fp->endpoint) {
- - list_add_tail(&fp->list, &subs->fmt_list);
- - subs->num_formats++;
- - subs->formats |= fp->formats;
- - return 0;
- + if (ep->use_count == 0)
- + goto exit_clear;
- +
- + if (usb_pipeout(ep->pipe)) {
- + retire_outbound_urb(ep, ctx);
- + if (ep->use_count == 0) /* can be stopped during retire callback */
- + goto exit_clear;
- +
- + if (snd_usb_endpoint_implict_feedback_sink(ep))
- + goto exit_clear;
- +
- + prepare_outbound_urb_sizes(ep, ctx);
- + prepare_outbound_urb(ep, ctx);
- + } else {
- + retire_inbound_urb(ep, ctx);
- + if (ep->use_count == 0) /* can be stopped during retire callback */
- + goto exit_clear;
- +
- + prepare_inbound_urb(ep, ctx);
- + }
- +
- + err = usb_submit_urb(urb, GFP_ATOMIC);
- + if (err == 0)
- + return;
- +
- + snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
- + //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- +
- +exit_clear:
- + clear_bit(ctx->index, &ep->active_mask);
- +}
- +
- +struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
- + struct usb_host_interface *alts,
- + int ep_num, int direction, int type)
- +{
- + struct list_head *p;
- + struct snd_usb_endpoint *ep;
- + int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
- +
- + list_for_each(p, &chip->ep_list) {
- + ep = list_entry(p, struct snd_usb_endpoint, list);
- + if (ep->ep_num == ep_num) {
- + snd_printk("Re-using EP %x @%p\n", ep_num, ep);
- + return ep;
- }
- }
- - /* look for an empty stream */
- - list_for_each(p, &chip->pcm_list) {
- - as = list_entry(p, struct snd_usb_stream, list);
- - if (as->fmt_type != fp->fmt_type)
- - continue;
- - subs = &as->substream[stream];
- - if (subs->endpoint)
- - continue;
- - err = snd_pcm_new_stream(as->pcm, stream, 1);
- - if (err < 0)
- - return err;
- - snd_usb_init_substream(as, stream, fp);
- - return 0;
- +
- + snd_printk("Creating new %s %s endpoint #%x\n",
- + is_playback ? "playback" : "capture",
- + type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
- + ep_num);
- +
- + ep = kzalloc(sizeof(*ep), GFP_KERNEL);
- + if (!ep)
- + return NULL;
- +
- + spin_lock_init(&ep->lock);
- +
- + ep->chip = chip;
- + ep->type = type;
- + ep->ep_num = ep_num;
- + ep->iface = alts->desc.bInterfaceNumber;
- + ep->alt_idx = alts->desc.bAlternateSetting;
- +
- + /* select the alt setting once so the endpoints become valid */
- + usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
- +
- + ep_num &= USB_ENDPOINT_NUMBER_MASK;
- +
- + if (is_playback)
- + ep->pipe = usb_sndisocpipe(chip->dev, ep_num);
- + else
- + ep->pipe = usb_rcvisocpipe(chip->dev, ep_num);
- +
- + switch (type) {
- + case SND_USB_ENDPOINT_TYPE_DATA:
- + break;
- + case SND_USB_ENDPOINT_TYPE_SYNC:
- + if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- + get_endpoint(alts, 1)->bRefresh >= 1 &&
- + get_endpoint(alts, 1)->bRefresh <= 9)
- + ep->syncinterval = get_endpoint(alts, 1)->bRefresh;
- + else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL)
- + ep->syncinterval = 1;
- + else if (get_endpoint(alts, 1)->bInterval >= 1 &&
- + get_endpoint(alts, 1)->bInterval <= 16)
- + ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
- + else
- + ep->syncinterval = 3;
- + ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
- +
- + break;
- }
- - /* create a new pcm */
- - as = kzalloc(sizeof(*as), GFP_KERNEL);
- - if (!as)
- - return -ENOMEM;
- - as->pcm_index = chip->pcm_devs;
- - as->chip = chip;
- - as->fmt_type = fp->fmt_type;
- - err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
- - stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
- - stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
- - &pcm);
- - if (err < 0) {
- - kfree(as);
- - return err;
- + list_add_tail(&ep->list, &chip->ep_list);
- +
- + return ep;
- +}
- +
- +static const char *usb_error_string(int err)
- +{
- + switch (err) {
- + case -ENODEV:
- + return "no device";
- + case -ENOENT:
- + return "endpoint not enabled";
- + case -EPIPE:
- + return "endpoint stalled";
- + case -ENOSPC:
- + return "not enough bandwidth";
- + case -ESHUTDOWN:
- + return "device disabled";
- + case -EHOSTUNREACH:
- + return "device suspended";
- + case -EINVAL:
- + case -EAGAIN:
- + case -EFBIG:
- + case -EMSGSIZE:
- + return "internal error";
- + default:
- + return "unknown error";
- }
- - as->pcm = pcm;
- - pcm->private_data = as;
- - pcm->private_free = snd_usb_audio_pcm_free;
- - pcm->info_flags = 0;
- - if (chip->pcm_devs > 0)
- - sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
- - else
- - strcpy(pcm->name, "USB Audio");
- +}
- - snd_usb_init_substream(as, stream, fp);
- +/*
- + * release a urb data
- + */
- +static void release_urb_ctx(struct snd_urb_ctx *u)
- +{
- + if (!u->urb)
- + return;
- +
- + if (u->buffer_size)
- + usb_free_coherent(u->ep->chip->dev, u->buffer_size,
- + u->urb->transfer_buffer,
- + u->urb->transfer_dma);
- + usb_free_urb(u->urb);
- + u->urb = NULL;
- +}
- - list_add(&as->list, &chip->pcm_list);
- - chip->pcm_devs++;
- +/*
- + * wait until all urbs are processed.
- + */
- +static int wait_clear_urbs(struct snd_usb_endpoint *ep)
- +{
- + unsigned long end_time = jiffies + msecs_to_jiffies(1000);
- + unsigned int i;
- + int alive;
- - snd_usb_proc_pcm_format_add(as);
- + do {
- + alive = 0;
- + for (i = 0; i < ep->nurbs; i++)
- + if (test_bit(i, &ep->active_mask))
- + alive++;
- +
- + if (! alive)
- + break;
- +
- + schedule_timeout_uninterruptible(1);
- + } while (time_before(jiffies, end_time));
- +
- + if (alive)
- + snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
- + alive, ep->ep_num);
- return 0;
- }
- -static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
- - struct usb_host_interface *alts,
- - int protocol, int iface_no)
- +/*
- + * unlink active urbs.
- + */
- +static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep)
- {
- - /* parsed with a v1 header here. that's ok as we only look at the
- - * header first which is the same for both versions */
- - struct uac_iso_endpoint_descriptor *csep;
- - struct usb_interface_descriptor *altsd = get_iface_desc(alts);
- - int attributes = 0;
- -
- - csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
- -
- - /* Creamware Noah has this descriptor after the 2nd endpoint */
- - if (!csep && altsd->bNumEndpoints >= 2)
- - csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
- -
- - if (!csep || csep->bLength < 7 ||
- - csep->bDescriptorSubtype != UAC_EP_GENERAL) {
- - snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
- - " class specific endpoint descriptor\n",
- - chip->dev->devnum, iface_no,
- - altsd->bAlternateSetting);
- + unsigned int i;
- + int async;
- +
- + if (!force && ep->chip->shutdown) /* to be sure... */
- + return -EBADFD;
- +
- + async = !can_sleep && ep->chip->async_unlink;
- +
- + if (!async && in_interrupt())
- return 0;
- +
- + for (i = 0; i < ep->nurbs; i++) {
- + if (test_bit(i, &ep->active_mask)) {
- + if (!test_and_set_bit(i, &ep->unlink_mask)) {
- + struct urb *u = ep->urb[i].urb;
- + if (async)
- + usb_unlink_urb(u);
- + else
- + usb_kill_urb(u);
- + }
- + }
- }
- - if (protocol == UAC_VERSION_1) {
- - attributes = csep->bmAttributes;
- + return 0;
- +}
- +
- +/*
- + * release an endpoint's urbs
- + */
- +static void release_urbs(struct snd_usb_endpoint *ep, int force)
- +{
- + int i;
- +
- + /* route incoming urbs to nirvana */
- + ep->retire_data_urb = NULL;
- + ep->prepare_data_urb = NULL;
- +
- + /* stop urbs */
- + deactivate_urbs(ep, force, 1);
- + wait_clear_urbs(ep);
- +
- + for (i = 0; i < ep->nurbs; i++)
- + release_urb_ctx(&ep->urb[i]);
- +
- + if (ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
- + usb_free_coherent(ep->chip->dev, SYNC_URBS * 4,
- + ep->syncbuf, ep->sync_dma);
- + ep->syncbuf = NULL;
- + ep->nurbs = 0;
- +}
- +
- +static int data_ep_set_params(struct snd_usb_endpoint *ep,
- + struct snd_pcm_hw_params *hw_params,
- + struct audioformat *fmt,
- + struct snd_usb_endpoint *sync_ep)
- +{
- + unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
- + int period_bytes = params_period_bytes(hw_params);
- + int format = params_format(hw_params);
- + int is_playback = usb_pipeout(ep->pipe);
- + int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
- + params_channels(hw_params);
- +
- + ep->datainterval = fmt->datainterval;
- + ep->stride = frame_bits >> 3;
- + ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
- +
- + /* calculate max. frequency */
- + if (ep->maxpacksize) {
- + /* whatever fits into a max. size packet */
- + maxsize = ep->maxpacksize;
- + ep->freqmax = (maxsize / (frame_bits >> 3))
- + << (16 - ep->datainterval);
- } else {
- - struct uac2_iso_endpoint_descriptor *csep2 =
- - (struct uac2_iso_endpoint_descriptor *) csep;
- + /* no max. packet size: just take 25% higher than nominal */
- + ep->freqmax = ep->freqn + (ep->freqn >> 2);
- + maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
- + >> (16 - ep->datainterval);
- + }
- +
- + if (ep->fill_max)
- + ep->curpacksize = ep->maxpacksize;
- + else
- + ep->curpacksize = maxsize;
- - attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
- + if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
- + packs_per_ms = 8 >> ep->datainterval;
- + else
- + packs_per_ms = 1;
- +
- + if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
- + urb_packs = max(ep->chip->nrpacks, 1);
- + urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
- + } else {
- + urb_packs = 1;
- + }
- +
- + urb_packs *= packs_per_ms;
- +
- + if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
- + urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
- +
- + /* decide how many packets to be used */
- + if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
- + unsigned int minsize, maxpacks;
- + /* determine how small a packet can be */
- + minsize = (ep->freqn >> (16 - ep->datainterval))
- + * (frame_bits >> 3);
- + /* with sync from device, assume it can be 12% lower */
- + if (sync_ep)
- + minsize -= minsize >> 3;
- + minsize = max(minsize, 1u);
- + total_packs = (period_bytes + minsize - 1) / minsize;
- + /* we need at least two URBs for queueing */
- + if (total_packs < 2) {
- + total_packs = 2;
- + } else {
- + /* and we don't want too long a queue either */
- + maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
- + total_packs = min(total_packs, maxpacks);
- + }
- + } else {
- + while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
- + urb_packs >>= 1;
- + total_packs = MAX_URBS * urb_packs;
- + }
- +
- + snd_printk("is_playback? %d impf %d, total_packs %d urb_packs %d\n",
- + is_playback, snd_usb_endpoint_implict_feedback_sink(ep), total_packs, urb_packs);
- +
- + ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
- + if (ep->nurbs > MAX_URBS) {
- + /* too much... */
- + ep->nurbs = MAX_URBS;
- + total_packs = MAX_URBS * urb_packs;
- + } else if (ep->nurbs < 2) {
- + /* too little - we need at least two packets
- + * to ensure contiguous playback/capture
- + */
- + ep->nurbs = 2;
- + }
- - /* emulate the endpoint attributes of a v1 device */
- - if (csep2->bmControls & UAC2_CONTROL_PITCH)
- - attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
- + /* allocate and initialize data urbs */
- + for (i = 0; i < ep->nurbs; i++) {
- + struct snd_urb_ctx *u = &ep->urb[i];
- + u->index = i;
- + u->ep = ep;
- + u->packets = (i + 1) * total_packs / ep->nurbs
- + - i * total_packs / ep->nurbs;
- + u->buffer_size = maxsize * u->packets;
- + snd_printk(" ep %p:: buffer_size %d maxsize %d packets %d\n", ep, u->buffer_size, maxsize, u->packets);
- + if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
- + u->packets++; /* for transfer delimiter */
- + u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
- + if (!u->urb)
- + goto out_of_memory;
- +
- + u->urb->transfer_buffer =
- + usb_alloc_coherent(ep->chip->dev, u->buffer_size,
- + GFP_KERNEL, &u->urb->transfer_dma);
- + if (!u->urb->transfer_buffer)
- + goto out_of_memory;
- + u->urb->pipe = ep->pipe;
- + u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- + u->urb->interval = 1 << ep->datainterval;
- + u->urb->context = u;
- + u->urb->complete = snd_complete_urb;
- }
- - return attributes;
- + return 0;
- +
- +out_of_memory:
- + release_urbs(ep, 0);
- + return -ENOMEM;
- }
- -static struct uac2_input_terminal_descriptor *
- - snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
- - int terminal_id)
- +static int sync_ep_set_params(struct snd_usb_endpoint *ep,
- + struct snd_pcm_hw_params *hw_params,
- + struct audioformat *fmt)
- {
- - struct uac2_input_terminal_descriptor *term = NULL;
- -
- - while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
- - ctrl_iface->extralen,
- - term, UAC_INPUT_TERMINAL))) {
- - if (term->bTerminalID == terminal_id)
- - return term;
- + int i;
- +
- + ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4,
- + GFP_KERNEL, &ep->sync_dma);
- + if (!ep->syncbuf)
- + goto out_of_memory;
- +
- + for (i = 0; i < SYNC_URBS; i++) {
- + struct snd_urb_ctx *u = &ep->urb[i];
- + u->index = i;
- + u->ep = ep;
- + u->packets = 1;
- + u->urb = usb_alloc_urb(1, GFP_KERNEL);
- + if (!u->urb)
- + goto out_of_memory;
- + u->urb->transfer_buffer = ep->syncbuf + i * 4;
- + u->urb->transfer_dma = ep->sync_dma + i * 4;
- + u->urb->transfer_buffer_length = 4;
- + u->urb->pipe = ep->pipe;
- + u->urb->transfer_flags = URB_ISO_ASAP |
- + URB_NO_TRANSFER_DMA_MAP;
- + u->urb->number_of_packets = 1;
- + u->urb->interval = 1 << ep->syncinterval;
- + u->urb->context = u;
- + u->urb->complete = snd_complete_urb;
- }
- - return NULL;
- + ep->nurbs = SYNC_URBS;
- +
- + return 0;
- +
- +out_of_memory:
- + release_urbs(ep, 0);
- + return -ENOMEM;
- }
- -static struct uac2_output_terminal_descriptor *
- - snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
- - int terminal_id)
- +int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
- + struct snd_pcm_hw_params *hw_params,
- + struct audioformat *fmt,
- + struct snd_usb_endpoint *sync_ep)
- {
- - struct uac2_output_terminal_descriptor *term = NULL;
- + int err;
- +
- + if (ep->use_count > 0) {
- + snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
- + ep->ep_num);
- + return -EBUSY;
- + }
- - while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
- - ctrl_iface->extralen,
- - term, UAC_OUTPUT_TERMINAL))) {
- - if (term->bTerminalID == terminal_id)
- - return term;
- + ep->datainterval = fmt->datainterval;
- + ep->maxpacksize = fmt->maxpacksize;
- + ep->fill_max = fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX;
- +
- + if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
- + ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
- + else
- + ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
- +
- + /* calculate the frequency in 16.16 format */
- + ep->freqm = ep->freqn;
- + ep->freqshift = INT_MIN;
- +
- + ep->phase = 0;
- +
- + switch (ep->type) {
- + case SND_USB_ENDPOINT_TYPE_DATA:
- + err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
- + break;
- + case SND_USB_ENDPOINT_TYPE_SYNC:
- + err = sync_ep_set_params(ep, hw_params, fmt);
- + break;
- + default:
- + err = -EINVAL;
- }
- - return NULL;
- + snd_printk("Setting params for ep #%x (type %d, %d urbs) -> %d\n",
- + ep->ep_num, ep->type, ep->nurbs, err);
- +
- + return err;
- }
- -int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
- +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
- {
- - struct usb_device *dev;
- - struct usb_interface *iface;
- - struct usb_host_interface *alts;
- - struct usb_interface_descriptor *altsd;
- - int i, altno, err, stream;
- - int format = 0, num_channels = 0;
- - struct audioformat *fp = NULL;
- - int num, protocol, clock = 0;
- - struct uac_format_type_i_continuous_descriptor *fmt;
- -
- - dev = chip->dev;
- -
- - /* parse the interface's altsettings */
- - iface = usb_ifnum_to_if(dev, iface_no);
- -
- - num = iface->num_altsetting;
- -
- - /*
- - * Dallas DS4201 workaround: It presents 5 altsettings, but the last
- - * one misses syncpipe, and does not produce any sound.
- + int err;
- + unsigned int i;
- +
- + if (ep->chip->shutdown)
- + return -EBADFD;
- +
- + snd_printk("%s(%p) type %s\n", __func__, ep,
- + ep->type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync");
- +
- + /* already running? */
- + if (++ep->use_count != 1)
- + return 0;
- +
- + ep->phase = 0;
- + ep->active_mask = 0;
- + ep->unlink_mask = 0;
- +
- + /* in implicit feedback mode, don't start the urbs here.
- + * instead, wait for the record urbs to arrive and queue the
- + * urbs from that context.
- */
- - 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);
- - protocol = altsd->bInterfaceProtocol;
- - /* skip invalid one */
- - if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
- - altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
- - (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
- - altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
- - altsd->bNumEndpoints < 1 ||
- - le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
- - continue;
- - /* must be isochronous */
- - if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
- - USB_ENDPOINT_XFER_ISOC)
- - continue;
- - /* check direction */
- - stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
- - SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
- - altno = altsd->bAlternateSetting;
- -
- - if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
- - continue;
- -
- - /* get audio formats */
- - switch (protocol) {
- - default:
- - snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n",
- - dev->devnum, iface_no, altno, protocol);
- - protocol = UAC_VERSION_1;
- - /* fall through */
- -
- - case UAC_VERSION_1: {
- - struct uac1_as_header_descriptor *as =
- - snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
- -
- - if (!as) {
- - snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
- - dev->devnum, iface_no, altno);
- - continue;
- - }
- - if (as->bLength < sizeof(*as)) {
- - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
- - dev->devnum, iface_no, altno);
- - continue;
- - }
- + if (snd_usb_endpoint_implict_feedback_sink(ep))
- + return 0;
- - format = le16_to_cpu(as->wFormatTag); /* remember the format value */
- - break;
- + for (i = 0; i < ep->nurbs; i++) {
- + struct urb *urb = ep->urb[i].urb;
- +
- + if (snd_BUG_ON(!urb))
- + return -EINVAL;
- +
- + if (usb_pipeout(ep->pipe)) {
- + prepare_outbound_urb_sizes(ep, urb->context);
- + prepare_outbound_urb(ep, urb->context);
- + } else {
- + prepare_inbound_urb(ep, urb->context);
- }
- + }
- - case UAC_VERSION_2: {
- - struct uac2_input_terminal_descriptor *input_term;
- - struct uac2_output_terminal_descriptor *output_term;
- - struct uac2_as_header_descriptor *as =
- - snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
- + for (i = 0; i < ep->nurbs; i++) {
- + err = usb_submit_urb(ep->urb[i].urb, GFP_ATOMIC);
- + snd_printk("Submmiting urb %d/%d (in? %d buf %p len %d) ... -> %d\n",
- + i, ep->nurbs, usb_pipein(ep->pipe),
- + ep->urb[i].urb->transfer_buffer,
- + ep->urb[i].urb->transfer_buffer_length,
- + err);
- + if (err < 0) {
- + snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
- + i, err, usb_error_string(err));
- + goto __error;
- + }
- + set_bit(i, &ep->active_mask);
- + }
- + return 0;
- - if (!as) {
- - snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
- - dev->devnum, iface_no, altno);
- - continue;
- - }
- + __error:
- + deactivate_urbs(ep, 0, 0);
- + return -EPIPE;
- +}
- - if (as->bLength < sizeof(*as)) {
- - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
- - dev->devnum, iface_no, altno);
- - continue;
- - }
- +void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
- +{
- + if (!ep)
- + return;
- - num_channels = as->bNrChannels;
- - format = le32_to_cpu(as->bmFormats);
- + if (snd_BUG_ON(ep->use_count == 0))
- + return;
- - /* lookup the terminal associated to this interface
- - * to extract the clock */
- - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
- - as->bTerminalLink);
- - if (input_term) {
- - clock = input_term->bCSourceID;
- - break;
- - }
- + if (--ep->use_count == 0)
- + deactivate_urbs(ep, 0, 0);
- +}
- +
- +void snd_usb_endpoint_free(struct list_head *head)
- +{
- + struct snd_usb_endpoint *ep;
- + ep = list_entry(head, struct snd_usb_endpoint, list);
- + release_urbs(ep, 1);
- +}
- +
- +/*
- + * process after playback sync complete
- + *
- + * Full speed devices report feedback values in 10.14 format as samples per
- + * frame, high speed devices in 16.16 format as samples per microframe.
- + * Because the Audio Class 1 spec was written before USB 2.0, many high speed
- + * devices use a wrong interpretation, some others use an entirely different
- + * format. Therefore, we cannot predict what format any particular device uses
- + * and must detect it automatically.
- + */
- +void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
- + struct snd_usb_endpoint *sender,
- + const struct urb *urb)
- +{
- + int shift;
- + unsigned int f;
- + unsigned long flags;
- +
- + snd_BUG_ON(ep == sender);
- - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
- - as->bTerminalLink);
- - if (output_term) {
- - clock = output_term->bCSourceID;
- + if (snd_usb_endpoint_implict_feedback_sink(ep) && ep->use_count > 0) {
- + /* implicit feedback case */
- + int i, err, bytes = 0;
- + struct urb *out_urb = NULL;
- + struct snd_urb_ctx *in_ctx, *out_ctx;
- +
- + in_ctx = urb->context;
- +
- + /* Count overall packet size */
- + for (i = 0; i < in_ctx->packets; i++)
- + if (urb->iso_frame_desc[i].status == 0)
- + bytes += urb->iso_frame_desc[i].actual_length;
- +
- + /* skip empty packets. At least M-Audio's Fast Track Ultra stops
- + * streaming once it received a 0-byte OUT URB */
- + if (bytes == 0)
- + return;
- +
- + for (i = 0; i < ep->nurbs; i++)
- + if (!test_and_set_bit(i, &ep->active_mask)) {
- + out_urb = ep->urb[i].urb;
- break;
- }
- - snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
- - dev->devnum, iface_no, altno, as->bTerminalLink);
- - continue;
- - }
- + if (!out_urb) {
- + snd_printk("Unable to find an urb for playback (nurbs %d)\n", ep->nurbs);
- + return;
- }
- - /* get format type */
- - fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
- - if (!fmt) {
- - snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
- - dev->devnum, iface_no, altno);
- - continue;
- - }
- - if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
- - ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
- - snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
- - dev->devnum, iface_no, altno);
- - continue;
- - }
- + out_ctx = out_urb->context;
- + out_ctx->packets = in_ctx->packets;
- /*
- - * Blue Microphones workaround: The last altsetting is identical
- - * with the previous one, except for a larger packet size, but
- - * is actually a mislabeled two-channel setting; ignore it.
- + * Iterate through the inbound packet and prepare the lengths
- + * for the output packet. The OUT packet we are about to send
- + * will have the same amount of payload than the IN packet we
- + * just received.
- */
- - if (fmt->bNrChannels == 1 &&
- - fmt->bSubframeSize == 2 &&
- - altno == 2 && num == 3 &&
- - fp && fp->altsetting == 1 && fp->channels == 1 &&
- - fp->formats == SNDRV_PCM_FMTBIT_S16_LE &&
- - protocol == UAC_VERSION_1 &&
- - le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
- - fp->maxpacksize * 2)
- - continue;
- -
- - fp = kzalloc(sizeof(*fp), GFP_KERNEL);
- - if (! fp) {
- - snd_printk(KERN_ERR "cannot malloc\n");
- - return -ENOMEM;
- - }
- - fp->iface = iface_no;
- - fp->altsetting = altno;
- - fp->altset_idx = i;
- - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
- - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
- - fp->datainterval = snd_usb_parse_datainterval(chip, alts);
- - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
- - /* num_channels is only set for v2 interfaces */
- - fp->channels = num_channels;
- - if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
- - fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
- - * (fp->maxpacksize & 0x7ff);
- - fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
- - fp->clock = clock;
- -
- - /* some quirks for attributes here */
- -
- - 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 &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
- - 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 |= UAC_EP_CS_ATTR_SAMPLE_RATE;
- - break;
- - case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */
- - case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */
- - 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...
- - */
- - fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
- - if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- - fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
- + for (i = 0; i < in_ctx->packets; i++) {
- + if (urb->iso_frame_desc[i].status == 0)
- + out_ctx->packet_size[i] =
- + urb->iso_frame_desc[i].actual_length / ep->stride;
- else
- - fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
- - break;
- + out_ctx->packet_size[i] = 0;
- }
- - /* ok, let's parse further... */
- - if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
- - kfree(fp->rate_table);
- - kfree(fp);
- - fp = NULL;
- - continue;
- + prepare_outbound_urb(ep, out_ctx);
- +
- +
- + for (i = 0; i < in_ctx->packets; i++) {
- + if (urb->iso_frame_desc[i].status != 0)
- + continue;
- +
- + if (urb->iso_frame_desc[i].actual_length !=
- + out_urb->iso_frame_desc[i].length)
- + snd_printk(" index %d: in %d, out %d (%d) stride %d\n", i,
- + urb->iso_frame_desc[i].actual_length,
- + out_urb->iso_frame_desc[i].length,
- + out_ctx->packet_size[i], ep->stride);
- }
- - snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
- - err = snd_usb_add_audio_endpoint(chip, stream, fp);
- +
- + err = usb_submit_urb(out_urb, GFP_ATOMIC);
- if (err < 0) {
- - kfree(fp->rate_table);
- - kfree(fp);
- - return err;
- + snd_printk("Unable to submit urb #%d: %d (urb %p)\n", out_ctx->index, err, out_urb);
- + clear_bit(out_ctx->index, &ep->active_mask);
- }
- - /* try to set the interface... */
- - usb_set_interface(chip->dev, iface_no, altno);
- - snd_usb_init_pitch(chip, iface_no, alts, fp);
- - snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max);
- +
- + return;
- + }
- +
- + if (urb->iso_frame_desc[0].status != 0 ||
- + urb->iso_frame_desc[0].actual_length < 3)
- + return;
- +
- + f = le32_to_cpup(urb->transfer_buffer);
- + if (urb->iso_frame_desc[0].actual_length == 3)
- + f &= 0x00ffffff;
- + else
- + f &= 0x0fffffff;
- +
- + if (f == 0)
- + return;
- +
- + if (unlikely(ep->freqshift == INT_MIN)) {
- + /*
- + * The first time we see a feedback value, determine its format
- + * by shifting it left or right until it matches the nominal
- + * frequency value. This assumes that the feedback does not
- + * differ from the nominal value more than +50% or -25%.
- + */
- + shift = 0;
- + while (f < ep->freqn - ep->freqn / 4) {
- + f <<= 1;
- + shift++;
- + }
- + while (f > ep->freqn + ep->freqn / 2) {
- + f >>= 1;
- + shift--;
- + }
- + ep->freqshift = shift;
- + }
- + else if (ep->freqshift >= 0)
- + f <<= ep->freqshift;
- + else
- + f >>= -ep->freqshift;
- +
- + if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) {
- + /*
- + * If the frequency looks valid, set it.
- + * This value is referred to in prepare_playback_urb().
- + */
- + spin_lock_irqsave(&ep->lock, flags);
- + ep->freqm = f;
- + spin_unlock_irqrestore(&ep->lock, flags);
- + } else {
- + /*
- + * Out of range; maybe the shift value is wrong.
- + * Reset it so that we autodetect again the next time.
- + */
- + ep->freqshift = INT_MIN;
- }
- - return 0;
- }
- diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
- index 64dd0db..fcbcf9c 100644
- --- a/sound/usb/endpoint.h
- +++ b/sound/usb/endpoint.h
- @@ -1,11 +1,26 @@
- #ifndef __USBAUDIO_ENDPOINT_H
- #define __USBAUDIO_ENDPOINT_H
- -int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip,
- - int iface_no);
- +#define SND_USB_ENDPOINT_TYPE_DATA 0
- +#define SND_USB_ENDPOINT_TYPE_SYNC 1
- -int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip,
- - int stream,
- - struct audioformat *fp);
- +struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
- + struct usb_host_interface *alts,
- + int ep_num, int direction, int type);
- +
- +int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
- + struct snd_pcm_hw_params *hw_params,
- + struct audioformat *fmt,
- + struct snd_usb_endpoint *sync_ep);
- +
- +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
- +void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep);
- +void snd_usb_endpoint_free(struct list_head *head);
- +
- +int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
- +
- +void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
- + struct snd_usb_endpoint *sender,
- + const struct urb *urb);
- #endif /* __USBAUDIO_ENDPOINT_H */
- diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
- index b8dcbf4..fd71ed6 100644
- --- a/sound/usb/pcm.c
- +++ b/sound/usb/pcm.c
- @@ -28,7 +28,7 @@
- #include "card.h"
- #include "quirks.h"
- #include "debug.h"
- -#include "urb.h"
- +#include "endpoint.h"
- #include "helper.h"
- #include "pcm.h"
- #include "clock.h"
- @@ -182,6 +182,64 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
- }
- }
- +static int start_endpoints(struct snd_usb_substream *subs)
- +{
- + int err;
- +
- + if (!subs->data_endpoint)
- + return -EINVAL;
- +
- + if (!subs->data_endpoint_started) {
- + struct snd_usb_endpoint *ep = subs->data_endpoint;
- +
- + snd_printk("Starting data EP @%p\n", ep);
- +
- + //ep->prepare_data_urb = NULL;
- + //ep->retire_data_urb = NULL;
- + ep->data_subs = subs;
- +
- + err = snd_usb_endpoint_start(ep);
- + if (err < 0)
- + return err;
- +
- + subs->data_endpoint_started = 1;
- + }
- +
- + if (!subs->sync_endpoint_started && subs->sync_endpoint) {
- + struct snd_usb_endpoint *ep = subs->sync_endpoint;
- +
- + snd_printk("Starting sync EP @%p\n", ep);
- +
- + ep->sync_slave = subs->data_endpoint;
- + err = snd_usb_endpoint_start(ep);
- + if (err < 0)
- + return err;
- +
- + subs->sync_endpoint_started = 1;
- + }
- +
- + return 0;
- +}
- +
- +static void stop_endpoints(struct snd_usb_substream *subs)
- +{
- + snd_printk("%s()\n", __func__);
- +
- + if (subs->sync_endpoint_started) {
- + subs->sync_endpoint->sync_slave = NULL;
- + snd_usb_endpoint_stop(subs->sync_endpoint);
- + subs->sync_endpoint_started = 0;
- + }
- +
- + if (subs->data_endpoint_started) {
- + subs->data_endpoint->retire_data_urb = NULL;
- + subs->data_endpoint->prepare_data_urb = NULL;
- + subs->data_endpoint->sync_master = NULL;
- + snd_usb_endpoint_stop(subs->data_endpoint);
- + subs->data_endpoint_started = 0;
- + }
- +}
- +
- /*
- * find a matching format and set up the interface
- */
- @@ -229,17 +287,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
- subs->altset_idx = fmt->altset_idx;
- }
- - /* create a data pipe */
- - ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
- - if (is_playback)
- - subs->datapipe = usb_sndisocpipe(dev, ep);
- - else
- - subs->datapipe = usb_rcvisocpipe(dev, ep);
- - subs->datainterval = fmt->datainterval;
- - subs->syncpipe = subs->syncinterval = 0;
- - subs->maxpacksize = fmt->maxpacksize;
- - subs->syncmaxsize = 0;
- - subs->fill_max = 0;
- + subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
- + alts, fmt->endpoint, subs->direction,
- + SND_USB_ENDPOINT_TYPE_DATA);
- + if (!subs->data_endpoint)
- + return -EINVAL;
- /* we need a sync pipe in async OUT or adaptive IN mode */
- /* check the number of EP, since some devices have broken
- @@ -247,50 +299,59 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
- * assume it as adaptive-out or sync-in.
- */
- attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
- + snd_printk("attr %x\n", attr);
- if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
- (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
- altsd->bNumEndpoints >= 2) {
- + int implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
- + == USB_ENDPOINT_USAGE_IMPLICIT_FB;
- +
- + switch (subs->stream->chip->usb_id) {
- + case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
- + case USB_ID(0x0763, 0x2081):
- + implicit_fb = 1;
- + ep = 0x81;
- + iface = usb_ifnum_to_if(dev, 2);
- + alts = &iface->altsetting[1];
- + goto add_sync_ep;
- + }
- +
- /* check sync-pipe endpoint */
- /* ... and check descriptor size before accessing bSynchAddress
- because there is a version of the SB Audigy 2 NX firmware lacking
- the audio fields in the endpoint descriptors */
- if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
- (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- - get_endpoint(alts, 1)->bSynchAddress != 0)) {
- + get_endpoint(alts, 1)->bSynchAddress != 0 &&
- + !implicit_fb)) {
- snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
- dev->devnum, fmt->iface, fmt->altsetting);
- return -EINVAL;
- }
- ep = get_endpoint(alts, 1)->bEndpointAddress;
- +
- if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
- - (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
- + (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) ||
- + ( is_playback && !implicit_fb))) {
- snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
- dev->devnum, fmt->iface, fmt->altsetting);
- return -EINVAL;
- }
- - ep &= USB_ENDPOINT_NUMBER_MASK;
- - if (is_playback)
- - subs->syncpipe = usb_rcvisocpipe(dev, ep);
- - else
- - subs->syncpipe = usb_sndisocpipe(dev, ep);
- - if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- - get_endpoint(alts, 1)->bRefresh >= 1 &&
- - get_endpoint(alts, 1)->bRefresh <= 9)
- - subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
- - 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;
- - subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
- - }
- -
- - /* always fill max packet size */
- - if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
- - subs->fill_max = 1;
- +add_sync_ep:
- + subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
- + alts, ep, !subs->direction,
- + implicit_fb ?
- + SND_USB_ENDPOINT_TYPE_DATA :
- + SND_USB_ENDPOINT_TYPE_SYNC);
- +
- + snd_printk(" -- imlicit_fb %d\n", implicit_fb);
- +
- + if (!subs->sync_endpoint)
- + return -EINVAL;
- +
- + subs->data_endpoint->sync_master = subs->sync_endpoint;
- + }
- if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
- return err;
- @@ -364,12 +425,18 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
- if (changed) {
- mutex_lock(&subs->stream->chip->shutdown_mutex);
- /* format changed */
- - snd_usb_release_substream_urbs(subs, 0);
- - /* influenced: period_bytes, channels, rate, format, */
- - ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params),
- - params_rate(hw_params),
- - snd_pcm_format_physical_width(params_format(hw_params)) *
- - params_channels(hw_params));
- + stop_endpoints(subs);
- +
- + snd_printk(" -- data %p\n", subs->data_endpoint);
- + snd_printk(" -- sync %p\n", subs->sync_endpoint);
- +
- + ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
- + subs->sync_endpoint);
- + if (ret == 0) {
- + if (subs->sync_endpoint)
- + ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
- + hw_params, fmt, NULL);
- + }
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
- }
- @@ -389,7 +456,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
- subs->cur_rate = 0;
- subs->period_bytes = 0;
- mutex_lock(&subs->stream->chip->shutdown_mutex);
- - snd_usb_release_substream_urbs(subs, 0);
- + stop_endpoints(subs);
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
- return snd_pcm_lib_free_vmalloc_buffer(substream);
- }
- @@ -409,17 +476,26 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
- return -ENXIO;
- }
- + if (snd_BUG_ON(!subs->data_endpoint))
- + return -EIO;
- +
- /* some unit conversions in runtime */
- - subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
- - subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
- + subs->data_endpoint->maxframesize =
- + bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
- + subs->data_endpoint->curframesize =
- + bytes_to_frames(runtime, subs->data_endpoint->curpacksize);
- /* reset the pointer */
- subs->hwptr_done = 0;
- subs->transfer_done = 0;
- - subs->phase = 0;
- runtime->delay = 0;
- - return snd_usb_substream_prepare(subs, runtime);
- + /* for playback, submit the URBs now; otherwise, the first hwptr_done
- + * updates for all URBs would happen at the same time when starting */
- + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
- + return start_endpoints(subs);
- +
- + return -EINVAL;
- }
- static struct snd_pcm_hardware snd_usb_hardware =
- @@ -824,6 +900,161 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
- return 0;
- }
- +/* Since a URB can handle only a single linear buffer, we must use double
- + * buffering when the data to be transferred overflows the buffer boundary.
- + * To avoid inconsistencies when updating hwptr_done, we use double buffering
- + * for all URBs.
- + */
- +static void retire_capture_urb(struct snd_usb_substream *subs,
- + struct urb *urb)
- +{
- + struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
- + unsigned int stride, frames, bytes, oldptr;
- + int i, period_elapsed = 0;
- + unsigned long flags;
- + unsigned char *cp;
- +
- + stride = runtime->frame_bits >> 3;
- +
- + for (i = 0; i < urb->number_of_packets; i++) {
- + cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- + if (urb->iso_frame_desc[i].status) {
- + snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
- + // continue;
- + }
- + bytes = urb->iso_frame_desc[i].actual_length;
- + frames = bytes / stride;
- + if (!subs->txfr_quirk)
- + bytes = frames * stride;
- + if (bytes % (runtime->sample_bits >> 3) != 0) {
- +#ifdef CONFIG_SND_DEBUG_VERBOSE
- + int oldbytes = bytes;
- +#endif
- + bytes = frames * stride;
- + snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
- + oldbytes, bytes);
- + }
- + /* update the current pointer */
- + spin_lock_irqsave(&subs->lock, flags);
- + oldptr = subs->hwptr_done;
- + subs->hwptr_done += bytes;
- + if (subs->hwptr_done >= runtime->buffer_size * stride)
- + subs->hwptr_done -= runtime->buffer_size * stride;
- + frames = (bytes + (oldptr % stride)) / stride;
- + subs->transfer_done += frames;
- + if (subs->transfer_done >= runtime->period_size) {
- + subs->transfer_done -= runtime->period_size;
- + period_elapsed = 1;
- + }
- + spin_unlock_irqrestore(&subs->lock, flags);
- + /* copy a data chunk */
- + if (oldptr + bytes > runtime->buffer_size * stride) {
- + unsigned int bytes1 =
- + runtime->buffer_size * stride - oldptr;
- + memcpy(runtime->dma_area + oldptr, cp, bytes1);
- + memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
- + } else {
- + memcpy(runtime->dma_area + oldptr, cp, bytes);
- + }
- + }
- +
- + if (period_elapsed)
- + snd_pcm_period_elapsed(subs->pcm_substream);
- +}
- +
- +static void prepare_playback_urb(struct snd_usb_substream *subs,
- + struct urb *urb)
- +{
- + struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
- + struct snd_urb_ctx *ctx = urb->context;
- + unsigned int counts, frames, bytes;
- + int i, stride, period_elapsed = 0;
- + unsigned long flags;
- +
- + stride = runtime->frame_bits >> 3;
- +
- + frames = 0;
- + urb->number_of_packets = 0;
- + spin_lock_irqsave(&subs->lock, flags);
- + for (i = 0; i < ctx->packets; i++) {
- + counts = ctx->packet_size[i];
- + /* set up descriptor */
- + urb->iso_frame_desc[i].offset = frames * stride;
- + urb->iso_frame_desc[i].length = counts * stride;
- + frames += counts;
- + urb->number_of_packets++;
- + subs->transfer_done += counts;
- + if (subs->transfer_done >= runtime->period_size) {
- + subs->transfer_done -= runtime->period_size;
- + period_elapsed = 1;
- + if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
- + if (subs->transfer_done > 0) {
- + /* FIXME: fill-max mode is not
- + * supported yet */
- + frames -= subs->transfer_done;
- + counts -= subs->transfer_done;
- + urb->iso_frame_desc[i].length =
- + counts * stride;
- + subs->transfer_done = 0;
- + }
- + i++;
- + if (i < ctx->packets) {
- + /* add a transfer delimiter */
- + urb->iso_frame_desc[i].offset =
- + frames * stride;
- + urb->iso_frame_desc[i].length = 0;
- + urb->number_of_packets++;
- + }
- + break;
- + }
- + }
- + if (period_elapsed &&
- + !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
- + break;
- + }
- + bytes = frames * stride;
- + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
- + /* err, the transferred area goes over buffer boundary. */
- + unsigned int bytes1 =
- + runtime->buffer_size * stride - subs->hwptr_done;
- + memcpy(urb->transfer_buffer,
- + runtime->dma_area + subs->hwptr_done, bytes1);
- + memcpy(urb->transfer_buffer + bytes1,
- + runtime->dma_area, bytes - bytes1);
- + } else {
- + memcpy(urb->transfer_buffer,
- + runtime->dma_area + subs->hwptr_done, bytes);
- + }
- + subs->hwptr_done += bytes;
- + if (subs->hwptr_done >= runtime->buffer_size * stride)
- + subs->hwptr_done -= runtime->buffer_size * stride;
- + runtime->delay += frames;
- + spin_unlock_irqrestore(&subs->lock, flags);
- + urb->transfer_buffer_length = bytes;
- + if (period_elapsed)
- + snd_pcm_period_elapsed(subs->pcm_substream);
- +}
- +
- +/*
- + * process after playback data complete
- + * - decrease the delay count again
- + */
- +static void retire_playback_urb(struct snd_usb_substream *subs,
- + struct urb *urb)
- +{
- + unsigned long flags;
- + struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
- + int stride = runtime->frame_bits >> 3;
- + int processed = urb->transfer_buffer_length / stride;
- +
- + spin_lock_irqsave(&subs->lock, flags);
- + if (processed > runtime->delay)
- + runtime->delay = 0;
- + else
- + runtime->delay -= processed;
- + spin_unlock_irqrestore(&subs->lock, flags);
- +}
- +
- static int snd_usb_playback_open(struct snd_pcm_substream *substream)
- {
- return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK);
- @@ -844,6 +1075,58 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream)
- return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
- }
- +static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
- + int cmd)
- +{
- + struct snd_usb_substream *subs = substream->runtime->private_data;
- +
- + switch (cmd) {
- + case SNDRV_PCM_TRIGGER_START:
- + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- + snd_printk("START!\n");
- + subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
- + subs->data_endpoint->retire_data_urb = retire_playback_urb;
- + return 0;
- + case SNDRV_PCM_TRIGGER_STOP:
- + stop_endpoints(subs);
- + return 0;
- + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- + snd_printk("PAUSE!\n");
- + subs->data_endpoint->prepare_data_urb = NULL;
- + subs->data_endpoint->retire_data_urb = NULL;
- + return 0;
- + }
- +
- + return -EINVAL;
- +}
- +
- +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
- +{
- + int err;
- + struct snd_usb_substream *subs = substream->runtime->private_data;
- +
- + switch (cmd) {
- + case SNDRV_PCM_TRIGGER_START:
- + err = start_endpoints(subs);
- + if (err < 0)
- + return err;
- +
- + subs->data_endpoint->retire_data_urb = retire_capture_urb;
- + return 0;
- + case SNDRV_PCM_TRIGGER_STOP:
- + stop_endpoints(subs);
- + return 0;
- + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- + subs->data_endpoint->retire_data_urb = NULL;
- + return 0;
- + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- + subs->data_endpoint->retire_data_urb = retire_capture_urb;
- + return 0;
- + }
- +
- + return -EINVAL;
- +}
- +
- static struct snd_pcm_ops snd_usb_playback_ops = {
- .open = snd_usb_playback_open,
- .close = snd_usb_playback_close,
- diff --git a/sound/usb/proc.c b/sound/usb/proc.c
- index 961c9a2..c4472f6 100644
- --- a/sound/usb/proc.c
- +++ b/sound/usb/proc.c
- @@ -117,26 +117,28 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
- static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
- {
- - if (subs->running) {
- + struct snd_usb_endpoint *ep = subs->data_endpoint;
- +
- + if (ep) {
- unsigned int i;
- snd_iprintf(buffer, " Status: Running\n");
- snd_iprintf(buffer, " Interface = %d\n", subs->interface);
- snd_iprintf(buffer, " Altset = %d\n", subs->altset_idx);
- - snd_iprintf(buffer, " URBs = %d [ ", subs->nurbs);
- - for (i = 0; i < subs->nurbs; i++)
- - snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
- + snd_iprintf(buffer, " URBs = %d [ ", ep->nurbs);
- + for (i = 0; i < ep->nurbs; i++)
- + snd_iprintf(buffer, "%d ", ep->urb[i].packets);
- snd_iprintf(buffer, "]\n");
- - snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
- + snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize);
- snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
- - snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
- - ? get_full_speed_hz(subs->freqm)
- - : get_high_speed_hz(subs->freqm),
- - subs->freqm >> 16, subs->freqm & 0xffff);
- - if (subs->freqshift != INT_MIN)
- + snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL
- + ? get_full_speed_hz(ep->freqm)
- + : get_high_speed_hz(ep->freqm),
- + ep->freqm >> 16, ep->freqm & 0xffff);
- + if (ep->freqshift != INT_MIN)
- snd_iprintf(buffer, " Feedback Format = %d.%d\n",
- - (subs->syncmaxsize > 3 ? 32 : 24)
- - - (16 - subs->freqshift),
- - 16 - subs->freqshift);
- + (ep->syncmaxsize > 3 ? 32 : 24)
- + - (16 - ep->freqshift),
- + 16 - ep->freqshift);
- } else {
- snd_iprintf(buffer, " Status: Stop\n");
- }
- diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
- index a42e3ef..7035073 100644
- --- a/sound/usb/quirks-table.h
- +++ b/sound/usb/quirks-table.h
- @@ -2065,7 +2065,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
- .altset_idx = 1,
- .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
- .endpoint = 0x01,
- - .ep_attr = 0x09,
- + .ep_attr = 0x05,
- .rates = SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 |
- diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
- index 81e07d8..1fc5668 100644
- --- a/sound/usb/quirks.c
- +++ b/sound/usb/quirks.c
- @@ -34,6 +34,7 @@
- #include "endpoint.h"
- #include "pcm.h"
- #include "clock.h"
- +#include "stream.h"
- /*
- * handle the quirks for the contained interfaces
- @@ -106,7 +107,7 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
- alts = &iface->altsetting[0];
- altsd = get_iface_desc(alts);
- - err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber);
- + err = snd_usb_parse_audio_interface(chip, altsd->bInterfaceNumber);
- if (err < 0) {
- snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
- altsd->bInterfaceNumber, err);
- @@ -147,7 +148,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
- stream = (fp->endpoint & USB_DIR_IN)
- ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
- - err = snd_usb_add_audio_endpoint(chip, stream, fp);
- + err = snd_usb_add_audio_stream(chip, stream, fp);
- if (err < 0) {
- kfree(fp);
- kfree(rate_table);
- @@ -254,7 +255,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
- stream = (fp->endpoint & USB_DIR_IN)
- ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
- - err = snd_usb_add_audio_endpoint(chip, stream, fp);
- + err = snd_usb_add_audio_stream(chip, stream, fp);
- if (err < 0) {
- kfree(fp);
- return err;
- diff --git a/sound/usb/stream.c b/sound/usb/stream.c
- new file mode 100644
- index 0000000..6b7d7a2
- --- /dev/null
- +++ b/sound/usb/stream.c
- @@ -0,0 +1,477 @@
- +/*
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- + */
- +
- +
- +#include <linux/init.h>
- +#include <linux/slab.h>
- +#include <linux/usb.h>
- +#include <linux/usb/audio.h>
- +#include <linux/usb/audio-v2.h>
- +
- +#include <sound/core.h>
- +#include <sound/pcm.h>
- +
- +#include "usbaudio.h"
- +#include "card.h"
- +#include "proc.h"
- +#include "quirks.h"
- +#include "endpoint.h"
- +#include "pcm.h"
- +#include "helper.h"
- +#include "format.h"
- +#include "clock.h"
- +#include "stream.h"
- +
- +/*
- + * free a substream
- + */
- +static void free_substream(struct snd_usb_substream *subs)
- +{
- + struct list_head *p, *n;
- +
- + 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);
- + kfree(fp->rate_table);
- + kfree(fp);
- + }
- + kfree(subs->rate_list.list);
- +}
- +
- +
- +/*
- + * free a usb stream instance
- + */
- +static void snd_usb_audio_stream_free(struct snd_usb_stream *stream)
- +{
- + free_substream(&stream->substream[0]);
- + free_substream(&stream->substream[1]);
- + list_del(&stream->list);
- + kfree(stream);
- +}
- +
- +static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
- +{
- + struct snd_usb_stream *stream = pcm->private_data;
- + if (stream) {
- + stream->pcm = NULL;
- + snd_usb_audio_stream_free(stream);
- + }
- +}
- +
- +/*
- + * initialize the substream instance.
- + */
- +
- +static void snd_usb_init_substream(struct snd_usb_stream *as,
- + int stream,
- + struct audioformat *fp)
- +{
- + struct snd_usb_substream *subs = &as->substream[stream];
- +
- + INIT_LIST_HEAD(&subs->fmt_list);
- + spin_lock_init(&subs->lock);
- +
- + subs->stream = as;
- + subs->direction = stream;
- + subs->dev = as->chip->dev;
- + subs->txfr_quirk = as->chip->txfr_quirk;
- +
- + snd_usb_set_pcm_ops(as->pcm, stream);
- +
- + list_add_tail(&fp->list, &subs->fmt_list);
- + subs->formats |= fp->formats;
- + subs->num_formats++;
- + subs->fmt_type = fp->fmt_type;
- +}
- +
- +/*
- + * add this endpoint to the chip instance.
- + * if a stream with the same endpoint already exists, append to it.
- + * if not, create a new pcm stream.
- + */
- +int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- + int stream,
- + struct audioformat *fp)
- +{
- + struct list_head *p;
- + struct snd_usb_stream *as;
- + struct snd_usb_substream *subs;
- + struct snd_pcm *pcm;
- + int err;
- +
- + list_for_each(p, &chip->pcm_list) {
- + as = list_entry(p, struct snd_usb_stream, list);
- + if (as->fmt_type != fp->fmt_type)
- + continue;
- + subs = &as->substream[stream];
- + if (!subs->data_endpoint)
- + continue;
- + if (subs->data_endpoint->ep_num == fp->endpoint) {
- + list_add_tail(&fp->list, &subs->fmt_list);
- + subs->num_formats++;
- + subs->formats |= fp->formats;
- + return 0;
- + }
- + }
- + /* look for an empty stream */
- + list_for_each(p, &chip->pcm_list) {
- + as = list_entry(p, struct snd_usb_stream, list);
- + if (as->fmt_type != fp->fmt_type)
- + continue;
- + subs = &as->substream[stream];
- + if (subs->data_endpoint)
- + continue;
- + err = snd_pcm_new_stream(as->pcm, stream, 1);
- + if (err < 0)
- + return err;
- + snd_usb_init_substream(as, stream, fp);
- + return 0;
- + }
- +
- + /* create a new pcm */
- + as = kzalloc(sizeof(*as), GFP_KERNEL);
- + if (!as)
- + return -ENOMEM;
- + as->pcm_index = chip->pcm_devs;
- + as->chip = chip;
- + as->fmt_type = fp->fmt_type;
- + err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
- + stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
- + stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
- + &pcm);
- + if (err < 0) {
- + kfree(as);
- + return err;
- + }
- + as->pcm = pcm;
- + pcm->private_data = as;
- + pcm->private_free = snd_usb_audio_pcm_free;
- + pcm->info_flags = 0;
- + if (chip->pcm_devs > 0)
- + sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs);
- + else
- + strcpy(pcm->name, "USB Audio");
- +
- + snd_usb_init_substream(as, stream, fp);
- +
- + list_add(&as->list, &chip->pcm_list);
- + chip->pcm_devs++;
- +
- + snd_usb_proc_pcm_format_add(as);
- +
- + return 0;
- +}
- +
- +static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
- + struct usb_host_interface *alts,
- + int protocol, int iface_no)
- +{
- + /* parsed with a v1 header here. that's ok as we only look at the
- + * header first which is the same for both versions */
- + struct uac_iso_endpoint_descriptor *csep;
- + struct usb_interface_descriptor *altsd = get_iface_desc(alts);
- + int attributes = 0;
- +
- + csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
- +
- + /* Creamware Noah has this descriptor after the 2nd endpoint */
- + if (!csep && altsd->bNumEndpoints >= 2)
- + csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
- +
- + if (!csep || csep->bLength < 7 ||
- + csep->bDescriptorSubtype != UAC_EP_GENERAL) {
- + snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
- + " class specific endpoint descriptor\n",
- + chip->dev->devnum, iface_no,
- + altsd->bAlternateSetting);
- + return 0;
- + }
- +
- + if (protocol == UAC_VERSION_1) {
- + attributes = csep->bmAttributes;
- + } else {
- + struct uac2_iso_endpoint_descriptor *csep2 =
- + (struct uac2_iso_endpoint_descriptor *) csep;
- +
- + attributes = csep->bmAttributes & UAC_EP_CS_ATTR_FILL_MAX;
- +
- + /* emulate the endpoint attributes of a v1 device */
- + if (csep2->bmControls & UAC2_CONTROL_PITCH)
- + attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
- + }
- +
- + return attributes;
- +}
- +
- +static struct uac2_input_terminal_descriptor *
- + snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
- + int terminal_id)
- +{
- + struct uac2_input_terminal_descriptor *term = NULL;
- +
- + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
- + ctrl_iface->extralen,
- + term, UAC_INPUT_TERMINAL))) {
- + if (term->bTerminalID == terminal_id)
- + return term;
- + }
- +
- + return NULL;
- +}
- +
- +static struct uac2_output_terminal_descriptor *
- + snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
- + int terminal_id)
- +{
- + struct uac2_output_terminal_descriptor *term = NULL;
- +
- + while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
- + ctrl_iface->extralen,
- + term, UAC_OUTPUT_TERMINAL))) {
- + if (term->bTerminalID == terminal_id)
- + return term;
- + }
- +
- + return NULL;
- +}
- +
- +int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
- +{
- + struct usb_device *dev;
- + struct usb_interface *iface;
- + struct usb_host_interface *alts;
- + struct usb_interface_descriptor *altsd;
- + int i, altno, err, stream;
- + int format = 0, num_channels = 0;
- + struct audioformat *fp = NULL;
- + int num, protocol, clock = 0;
- + struct uac_format_type_i_continuous_descriptor *fmt;
- +
- + dev = chip->dev;
- +
- + /* parse the interface's altsettings */
- + iface = usb_ifnum_to_if(dev, iface_no);
- +
- + 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);
- + protocol = altsd->bInterfaceProtocol;
- + /* skip invalid one */
- + if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
- + altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
- + (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
- + altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
- + altsd->bNumEndpoints < 1 ||
- + le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
- + continue;
- + /* must be isochronous */
- + if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
- + USB_ENDPOINT_XFER_ISOC)
- + continue;
- + /* check direction */
- + stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
- + SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
- + altno = altsd->bAlternateSetting;
- +
- + if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
- + continue;
- +
- + /* get audio formats */
- + switch (protocol) {
- + default:
- + snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n",
- + dev->devnum, iface_no, altno, protocol);
- + protocol = UAC_VERSION_1;
- + /* fall through */
- +
- + case UAC_VERSION_1: {
- + struct uac1_as_header_descriptor *as =
- + snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
- +
- + if (!as) {
- + snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
- + dev->devnum, iface_no, altno);
- + continue;
- + }
- +
- + if (as->bLength < sizeof(*as)) {
- + snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
- + dev->devnum, iface_no, altno);
- + continue;
- + }
- +
- + format = le16_to_cpu(as->wFormatTag); /* remember the format value */
- + break;
- + }
- +
- + case UAC_VERSION_2: {
- + struct uac2_input_terminal_descriptor *input_term;
- + struct uac2_output_terminal_descriptor *output_term;
- + struct uac2_as_header_descriptor *as =
- + snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
- +
- + if (!as) {
- + snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n",
- + dev->devnum, iface_no, altno);
- + continue;
- + }
- +
- + if (as->bLength < sizeof(*as)) {
- + snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n",
- + dev->devnum, iface_no, altno);
- + continue;
- + }
- +
- + num_channels = as->bNrChannels;
- + format = le32_to_cpu(as->bmFormats);
- +
- + /* lookup the terminal associated to this interface
- + * to extract the clock */
- + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
- + as->bTerminalLink);
- + if (input_term) {
- + clock = input_term->bCSourceID;
- + break;
- + }
- +
- + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
- + as->bTerminalLink);
- + if (output_term) {
- + clock = output_term->bCSourceID;
- + break;
- + }
- +
- + snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
- + dev->devnum, iface_no, altno, as->bTerminalLink);
- + continue;
- + }
- + }
- +
- + /* get format type */
- + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE);
- + if (!fmt) {
- + snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n",
- + dev->devnum, iface_no, altno);
- + continue;
- + }
- + if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) ||
- + ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) {
- + snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
- + dev->devnum, iface_no, altno);
- + continue;
- + }
- +
- + /*
- + * Blue Microphones workaround: The last altsetting is identical
- + * with the previous one, except for a larger packet size, but
- + * is actually a mislabeled two-channel setting; ignore it.
- + */
- + if (fmt->bNrChannels == 1 &&
- + fmt->bSubframeSize == 2 &&
- + altno == 2 && num == 3 &&
- + fp && fp->altsetting == 1 && fp->channels == 1 &&
- + fp->formats == SNDRV_PCM_FMTBIT_S16_LE &&
- + protocol == UAC_VERSION_1 &&
- + le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) ==
- + fp->maxpacksize * 2)
- + continue;
- +
- + fp = kzalloc(sizeof(*fp), GFP_KERNEL);
- + if (! fp) {
- + snd_printk(KERN_ERR "cannot malloc\n");
- + return -ENOMEM;
- + }
- +
- + fp->iface = iface_no;
- + fp->altsetting = altno;
- + fp->altset_idx = i;
- + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
- + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
- + fp->datainterval = snd_usb_parse_datainterval(chip, alts);
- + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
- + /* num_channels is only set for v2 interfaces */
- + fp->channels = num_channels;
- + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
- + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
- + * (fp->maxpacksize & 0x7ff);
- + fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
- + fp->clock = clock;
- +
- + /* some quirks for attributes here */
- +
- + 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 &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
- + 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 |= UAC_EP_CS_ATTR_SAMPLE_RATE;
- + break;
- + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */
- + case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */
- + 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...
- + */
- + fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
- + if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- + fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
- + else
- + fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
- + break;
- + }
- +
- + /* ok, let's parse further... */
- + if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
- + kfree(fp->rate_table);
- + kfree(fp);
- + fp = NULL;
- + continue;
- + }
- +
- + snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
- + err = snd_usb_add_audio_stream(chip, stream, fp);
- + if (err < 0) {
- + kfree(fp->rate_table);
- + kfree(fp);
- + return err;
- + }
- + /* try to set the interface... */
- + usb_set_interface(chip->dev, iface_no, altno);
- + snd_usb_init_pitch(chip, iface_no, alts, fp);
- + snd_usb_init_sample_rate(chip, iface_no, alts, fp, fp->rate_max);
- + }
- + return 0;
- +}
- +
- diff --git a/sound/usb/stream.h b/sound/usb/stream.h
- new file mode 100644
- index 0000000..c97f679
- --- /dev/null
- +++ b/sound/usb/stream.h
- @@ -0,0 +1,12 @@
- +#ifndef __USBAUDIO_STREAM_H
- +#define __USBAUDIO_STREAM_H
- +
- +int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,
- + int iface_no);
- +
- +int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- + int stream,
- + struct audioformat *fp);
- +
- +#endif /* __USBAUDIO_STREAM_H */
- +
- diff --git a/sound/usb/urb.c b/sound/usb/urb.c
- deleted file mode 100644
- index e184349..0000000
- --- a/sound/usb/urb.c
- +++ /dev/null
- @@ -1,941 +0,0 @@
- -/*
- - * This program is free software; you can redistribute it and/or modify
- - * it under the terms of the GNU General Public License as published by
- - * the Free Software Foundation; either version 2 of the License, or
- - * (at your option) any later version.
- - *
- - * This program is distributed in the hope that it will be useful,
- - * but WITHOUT ANY WARRANTY; without even the implied warranty of
- - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - * GNU General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with this program; if not, write to the Free Software
- - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- - *
- - */
- -
- -#include <linux/gfp.h>
- -#include <linux/init.h>
- -#include <linux/usb.h>
- -#include <linux/usb/audio.h>
- -
- -#include <sound/core.h>
- -#include <sound/pcm.h>
- -
- -#include "usbaudio.h"
- -#include "helper.h"
- -#include "card.h"
- -#include "urb.h"
- -#include "pcm.h"
- -
- -/*
- - * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
- - * this will overflow at approx 524 kHz
- - */
- -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
- - */
- -static inline unsigned get_usb_high_speed_rate(unsigned int rate)
- -{
- - return ((rate << 10) + 62) / 125;
- -}
- -
- -/*
- - * unlink active urbs.
- - */
- -static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
- -{
- - struct snd_usb_audio *chip = subs->stream->chip;
- - unsigned int i;
- - int async;
- -
- - subs->running = 0;
- -
- - if (!force && subs->stream->chip->shutdown) /* to be sure... */
- - return -EBADFD;
- -
- - async = !can_sleep && chip->async_unlink;
- -
- - 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)) {
- - struct urb *u = subs->dataurb[i].urb;
- - if (async)
- - usb_unlink_urb(u);
- - else
- - usb_kill_urb(u);
- - }
- - }
- - }
- - 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)) {
- - struct urb *u = subs->syncurb[i].urb;
- - if (async)
- - usb_unlink_urb(u);
- - else
- - usb_kill_urb(u);
- - }
- - }
- - }
- - }
- - return 0;
- -}
- -
- -
- -/*
- - * release a urb data
- - */
- -static void release_urb_ctx(struct snd_urb_ctx *u)
- -{
- - if (u->urb) {
- - if (u->buffer_size)
- - usb_free_coherent(u->subs->dev, u->buffer_size,
- - u->urb->transfer_buffer,
- - u->urb->transfer_dma);
- - usb_free_urb(u->urb);
- - u->urb = NULL;
- - }
- -}
- -
- -/*
- - * wait until all urbs are processed.
- - */
- -static int wait_clear_urbs(struct snd_usb_substream *subs)
- -{
- - unsigned long end_time = jiffies + msecs_to_jiffies(1000);
- - unsigned int i;
- - int alive;
- -
- - do {
- - alive = 0;
- - for (i = 0; i < subs->nurbs; i++) {
- - if (test_bit(i, &subs->active_mask))
- - alive++;
- - }
- - if (subs->syncpipe) {
- - for (i = 0; i < SYNC_URBS; i++) {
- - if (test_bit(i + 16, &subs->active_mask))
- - alive++;
- - }
- - }
- - if (! alive)
- - break;
- - schedule_timeout_uninterruptible(1);
- - } while (time_before(jiffies, end_time));
- - if (alive)
- - snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
- - return 0;
- -}
- -
- -/*
- - * release a substream
- - */
- -void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
- -{
- - int i;
- -
- - /* stop urbs (to be sure) */
- - deactivate_urbs(subs, force, 1);
- - wait_clear_urbs(subs);
- -
- - for (i = 0; i < MAX_URBS; i++)
- - release_urb_ctx(&subs->dataurb[i]);
- - for (i = 0; i < SYNC_URBS; i++)
- - release_urb_ctx(&subs->syncurb[i]);
- - usb_free_coherent(subs->dev, SYNC_URBS * 4,
- - subs->syncbuf, subs->sync_dma);
- - subs->syncbuf = NULL;
- - subs->nurbs = 0;
- -}
- -
- -/*
- - * complete callback from data urb
- - */
- -static void snd_complete_urb(struct urb *urb)
- -{
- - struct snd_urb_ctx *ctx = urb->context;
- - struct snd_usb_substream *subs = ctx->subs;
- - struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
- - int err = 0;
- -
- - if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
- - !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);
- - if (err < 0) {
- - snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
- - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- - }
- - }
- -}
- -
- -
- -/*
- - * complete callback from sync urb
- - */
- -static void snd_complete_sync_urb(struct urb *urb)
- -{
- - struct snd_urb_ctx *ctx = urb->context;
- - struct snd_usb_substream *subs = ctx->subs;
- - struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
- - int err = 0;
- -
- - if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
- - !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);
- - if (err < 0) {
- - snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
- - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- - }
- - }
- -}
- -
- -
- -/*
- - * initialize a substream for plaback/capture
- - */
- -int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
- - unsigned int period_bytes,
- - unsigned int rate,
- - unsigned int frame_bits)
- -{
- - unsigned int maxsize, i;
- - int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
- - unsigned int urb_packs, total_packs, packs_per_ms;
- - struct snd_usb_audio *chip = subs->stream->chip;
- -
- - /* calculate the frequency in 16.16 format */
- - if (snd_usb_get_speed(subs->dev) == 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->freqshift = INT_MIN;
- - /* calculate max. frequency */
- - if (subs->maxpacksize) {
- - /* whatever fits into a max. size packet */
- - maxsize = subs->maxpacksize;
- - subs->freqmax = (maxsize / (frame_bits >> 3))
- - << (16 - subs->datainterval);
- - } else {
- - /* no max. packet size: just take 25% higher than nominal */
- - subs->freqmax = subs->freqn + (subs->freqn >> 2);
- - maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
- - >> (16 - subs->datainterval);
- - }
- - subs->phase = 0;
- -
- - if (subs->fill_max)
- - subs->curpacksize = subs->maxpacksize;
- - else
- - subs->curpacksize = maxsize;
- -
- - if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
- - packs_per_ms = 8 >> subs->datainterval;
- - else
- - packs_per_ms = 1;
- -
- - if (is_playback) {
- - urb_packs = max(chip->nrpacks, 1);
- - urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
- - } else
- - urb_packs = 1;
- - urb_packs *= packs_per_ms;
- - if (subs->syncpipe)
- - urb_packs = min(urb_packs, 1U << subs->syncinterval);
- -
- - /* decide how many packets to be used */
- - if (is_playback) {
- - unsigned int minsize, maxpacks;
- - /* determine how small a packet can be */
- - minsize = (subs->freqn >> (16 - subs->datainterval))
- - * (frame_bits >> 3);
- - /* with sync from device, assume it can be 12% lower */
- - if (subs->syncpipe)
- - minsize -= minsize >> 3;
- - minsize = max(minsize, 1u);
- - total_packs = (period_bytes + minsize - 1) / minsize;
- - /* we need at least two URBs for queueing */
- - if (total_packs < 2) {
- - total_packs = 2;
- - } else {
- - /* and we don't want too long a queue either */
- - maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
- - total_packs = min(total_packs, maxpacks);
- - }
- - } else {
- - while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
- - urb_packs >>= 1;
- - total_packs = MAX_URBS * urb_packs;
- - }
- - subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
- - if (subs->nurbs > MAX_URBS) {
- - /* too much... */
- - subs->nurbs = MAX_URBS;
- - total_packs = MAX_URBS * urb_packs;
- - } else if (subs->nurbs < 2) {
- - /* too little - we need at least two packets
- - * to ensure contiguous playback/capture
- - */
- - subs->nurbs = 2;
- - }
- -
- - /* allocate and initialize data urbs */
- - for (i = 0; i < subs->nurbs; i++) {
- - struct snd_urb_ctx *u = &subs->dataurb[i];
- - u->index = i;
- - u->subs = subs;
- - u->packets = (i + 1) * total_packs / subs->nurbs
- - - i * total_packs / subs->nurbs;
- - u->buffer_size = maxsize * u->packets;
- - if (subs->fmt_type == UAC_FORMAT_TYPE_II)
- - u->packets++; /* for transfer delimiter */
- - u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
- - if (!u->urb)
- - goto out_of_memory;
- - u->urb->transfer_buffer =
- - usb_alloc_coherent(subs->dev, u->buffer_size,
- - GFP_KERNEL, &u->urb->transfer_dma);
- - 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;
- - u->urb->interval = 1 << subs->datainterval;
- - u->urb->context = u;
- - u->urb->complete = snd_complete_urb;
- - }
- -
- - if (subs->syncpipe) {
- - /* allocate and initialize sync urbs */
- - subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
- - GFP_KERNEL, &subs->sync_dma);
- - if (!subs->syncbuf)
- - goto out_of_memory;
- - for (i = 0; i < SYNC_URBS; i++) {
- - struct snd_urb_ctx *u = &subs->syncurb[i];
- - u->index = i;
- - u->subs = subs;
- - u->packets = 1;
- - u->urb = usb_alloc_urb(1, GFP_KERNEL);
- - if (!u->urb)
- - goto out_of_memory;
- - u->urb->transfer_buffer = subs->syncbuf + i * 4;
- - u->urb->transfer_dma = subs->sync_dma + i * 4;
- - u->urb->transfer_buffer_length = 4;
- - u->urb->pipe = subs->syncpipe;
- - u->urb->transfer_flags = URB_ISO_ASAP |
- - URB_NO_TRANSFER_DMA_MAP;
- - u->urb->number_of_packets = 1;
- - u->urb->interval = 1 << subs->syncinterval;
- - u->urb->context = u;
- - u->urb->complete = snd_complete_sync_urb;
- - }
- - }
- - return 0;
- -
- -out_of_memory:
- - snd_usb_release_substream_urbs(subs, 0);
- - return -ENOMEM;
- -}
- -
- -/*
- - * 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.
- - */
- -static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - unsigned char *cp = urb->transfer_buffer;
- - struct snd_urb_ctx *ctx = urb->context;
- -
- - urb->dev = ctx->subs->dev; /* we need to set this at each time */
- - 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;
- -}
- -
- -/*
- - * 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(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - unsigned char *cp = urb->transfer_buffer;
- - struct snd_urb_ctx *ctx = urb->context;
- -
- - urb->dev = ctx->subs->dev; /* we need to set this at each time */
- - 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;
- -}
- -
- -/*
- - * process after capture sync complete
- - * - nothing to do
- - */
- -static int retire_capture_sync_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - return 0;
- -}
- -
- -/*
- - * prepare urb for capture data pipe
- - *
- - * fill the offset and length of each descriptor.
- - *
- - * we use a temporary buffer to write the captured data.
- - * since the length of written data is determined by host, we cannot
- - * write onto the pcm buffer directly... the data is thus copied
- - * later at complete callback to the global buffer.
- - */
- -static int prepare_capture_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - int i, offs;
- - struct snd_urb_ctx *ctx = urb->context;
- -
- - offs = 0;
- - urb->dev = ctx->subs->dev; /* we need to set this at each time */
- - for (i = 0; i < ctx->packets; i++) {
- - urb->iso_frame_desc[i].offset = offs;
- - urb->iso_frame_desc[i].length = subs->curpacksize;
- - offs += subs->curpacksize;
- - }
- - urb->transfer_buffer_length = offs;
- - urb->number_of_packets = ctx->packets;
- - return 0;
- -}
- -
- -/*
- - * process after capture complete
- - *
- - * copy the data from each desctiptor to the pcm buffer, and
- - * update the current position.
- - */
- -static int retire_capture_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - unsigned long flags;
- - unsigned char *cp;
- - int i;
- - unsigned int stride, frames, bytes, oldptr;
- - int period_elapsed = 0;
- -
- - stride = runtime->frame_bits >> 3;
- -
- - for (i = 0; i < urb->number_of_packets; i++) {
- - cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- - if (urb->iso_frame_desc[i].status) {
- - snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
- - // continue;
- - }
- - bytes = urb->iso_frame_desc[i].actual_length;
- - frames = bytes / stride;
- - if (!subs->txfr_quirk)
- - bytes = frames * stride;
- - if (bytes % (runtime->sample_bits >> 3) != 0) {
- -#ifdef CONFIG_SND_DEBUG_VERBOSE
- - int oldbytes = bytes;
- -#endif
- - bytes = frames * stride;
- - snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
- - oldbytes, bytes);
- - }
- - /* update the current pointer */
- - spin_lock_irqsave(&subs->lock, flags);
- - oldptr = subs->hwptr_done;
- - subs->hwptr_done += bytes;
- - if (subs->hwptr_done >= runtime->buffer_size * stride)
- - subs->hwptr_done -= runtime->buffer_size * stride;
- - frames = (bytes + (oldptr % stride)) / stride;
- - subs->transfer_done += frames;
- - if (subs->transfer_done >= runtime->period_size) {
- - subs->transfer_done -= runtime->period_size;
- - period_elapsed = 1;
- - }
- - spin_unlock_irqrestore(&subs->lock, flags);
- - /* copy a data chunk */
- - if (oldptr + bytes > runtime->buffer_size * stride) {
- - unsigned int bytes1 =
- - runtime->buffer_size * stride - oldptr;
- - memcpy(runtime->dma_area + oldptr, cp, bytes1);
- - memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
- - } else {
- - memcpy(runtime->dma_area + oldptr, cp, bytes);
- - }
- - }
- - if (period_elapsed)
- - snd_pcm_period_elapsed(subs->pcm_substream);
- - return 0;
- -}
- -
- -/*
- - * Process after capture complete when paused. Nothing to do.
- - */
- -static int retire_paused_capture_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - return 0;
- -}
- -
- -
- -/*
- - * prepare urb for playback sync pipe
- - *
- - * set up the offset and length to receive the current frequency.
- - */
- -static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - struct snd_urb_ctx *ctx = urb->context;
- -
- - urb->dev = ctx->subs->dev; /* we need to set this at each time */
- - urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
- - urb->iso_frame_desc[0].offset = 0;
- - return 0;
- -}
- -
- -/*
- - * process after playback sync complete
- - *
- - * Full speed devices report feedback values in 10.14 format as samples per
- - * frame, high speed devices in 16.16 format as samples per microframe.
- - * Because the Audio Class 1 spec was written before USB 2.0, many high speed
- - * devices use a wrong interpretation, some others use an entirely different
- - * format. Therefore, we cannot predict what format any particular device uses
- - * and must detect it automatically.
- - */
- -static int retire_playback_sync_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - unsigned int f;
- - int shift;
- - unsigned long flags;
- -
- - if (urb->iso_frame_desc[0].status != 0 ||
- - urb->iso_frame_desc[0].actual_length < 3)
- - return 0;
- -
- - f = le32_to_cpup(urb->transfer_buffer);
- - if (urb->iso_frame_desc[0].actual_length == 3)
- - f &= 0x00ffffff;
- - else
- - f &= 0x0fffffff;
- - if (f == 0)
- - return 0;
- -
- - if (unlikely(subs->freqshift == INT_MIN)) {
- - /*
- - * The first time we see a feedback value, determine its format
- - * by shifting it left or right until it matches the nominal
- - * frequency value. This assumes that the feedback does not
- - * differ from the nominal value more than +50% or -25%.
- - */
- - shift = 0;
- - while (f < subs->freqn - subs->freqn / 4) {
- - f <<= 1;
- - shift++;
- - }
- - while (f > subs->freqn + subs->freqn / 2) {
- - f >>= 1;
- - shift--;
- - }
- - subs->freqshift = shift;
- - }
- - else if (subs->freqshift >= 0)
- - f <<= subs->freqshift;
- - else
- - f >>= -subs->freqshift;
- -
- - if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
- - /*
- - * If the frequency looks valid, set it.
- - * This value is referred to in prepare_playback_urb().
- - */
- - spin_lock_irqsave(&subs->lock, flags);
- - subs->freqm = f;
- - spin_unlock_irqrestore(&subs->lock, flags);
- - } else {
- - /*
- - * Out of range; maybe the shift value is wrong.
- - * Reset it so that we autodetect again the next time.
- - */
- - subs->freqshift = INT_MIN;
- - }
- -
- - return 0;
- -}
- -
- -/* determine the number of frames in the next packet */
- -static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
- -{
- - if (subs->fill_max)
- - return subs->maxframesize;
- - else {
- - subs->phase = (subs->phase & 0xffff)
- - + (subs->freqm << subs->datainterval);
- - return min(subs->phase >> 16, subs->maxframesize);
- - }
- -}
- -
- -/*
- - * Prepare urb for streaming before playback starts or when paused.
- - *
- - * We don't have any data, so we send silence.
- - */
- -static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - unsigned int i, offs, counts;
- - struct snd_urb_ctx *ctx = urb->context;
- - int stride = runtime->frame_bits >> 3;
- -
- - offs = 0;
- - urb->dev = ctx->subs->dev;
- - for (i = 0; i < ctx->packets; ++i) {
- - counts = snd_usb_audio_next_packet_size(subs);
- - urb->iso_frame_desc[i].offset = offs * stride;
- - urb->iso_frame_desc[i].length = counts * stride;
- - offs += counts;
- - }
- - urb->number_of_packets = ctx->packets;
- - urb->transfer_buffer_length = offs * stride;
- - memset(urb->transfer_buffer,
- - runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
- - offs * stride);
- - return 0;
- -}
- -
- -/*
- - * prepare urb for playback data pipe
- - *
- - * Since a URB can handle only a single linear buffer, we must use double
- - * buffering when the data to be transferred overflows the buffer boundary.
- - * To avoid inconsistencies when updating hwptr_done, we use double buffering
- - * for all URBs.
- - */
- -static int prepare_playback_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - int i, stride;
- - unsigned int counts, frames, bytes;
- - unsigned long flags;
- - int period_elapsed = 0;
- - struct snd_urb_ctx *ctx = urb->context;
- -
- - stride = runtime->frame_bits >> 3;
- -
- - frames = 0;
- - urb->dev = ctx->subs->dev; /* we need to set this at each time */
- - urb->number_of_packets = 0;
- - spin_lock_irqsave(&subs->lock, flags);
- - for (i = 0; i < ctx->packets; i++) {
- - counts = snd_usb_audio_next_packet_size(subs);
- - /* set up descriptor */
- - urb->iso_frame_desc[i].offset = frames * stride;
- - urb->iso_frame_desc[i].length = counts * stride;
- - frames += counts;
- - urb->number_of_packets++;
- - subs->transfer_done += counts;
- - if (subs->transfer_done >= runtime->period_size) {
- - subs->transfer_done -= runtime->period_size;
- - period_elapsed = 1;
- - if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
- - if (subs->transfer_done > 0) {
- - /* FIXME: fill-max mode is not
- - * supported yet */
- - frames -= subs->transfer_done;
- - counts -= subs->transfer_done;
- - urb->iso_frame_desc[i].length =
- - counts * stride;
- - subs->transfer_done = 0;
- - }
- - i++;
- - if (i < ctx->packets) {
- - /* add a transfer delimiter */
- - urb->iso_frame_desc[i].offset =
- - frames * stride;
- - urb->iso_frame_desc[i].length = 0;
- - urb->number_of_packets++;
- - }
- - break;
- - }
- - }
- - if (period_elapsed) /* finish at the period boundary */
- - break;
- - }
- - bytes = frames * stride;
- - if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
- - /* err, the transferred area goes over buffer boundary. */
- - unsigned int bytes1 =
- - runtime->buffer_size * stride - subs->hwptr_done;
- - memcpy(urb->transfer_buffer,
- - runtime->dma_area + subs->hwptr_done, bytes1);
- - memcpy(urb->transfer_buffer + bytes1,
- - runtime->dma_area, bytes - bytes1);
- - } else {
- - memcpy(urb->transfer_buffer,
- - runtime->dma_area + subs->hwptr_done, bytes);
- - }
- - subs->hwptr_done += bytes;
- - if (subs->hwptr_done >= runtime->buffer_size * stride)
- - subs->hwptr_done -= runtime->buffer_size * stride;
- - runtime->delay += frames;
- - spin_unlock_irqrestore(&subs->lock, flags);
- - urb->transfer_buffer_length = bytes;
- - if (period_elapsed)
- - snd_pcm_period_elapsed(subs->pcm_substream);
- - return 0;
- -}
- -
- -/*
- - * process after playback data complete
- - * - decrease the delay count again
- - */
- -static int retire_playback_urb(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime,
- - struct urb *urb)
- -{
- - unsigned long flags;
- - int stride = runtime->frame_bits >> 3;
- - int processed = urb->transfer_buffer_length / stride;
- -
- - spin_lock_irqsave(&subs->lock, flags);
- - if (processed > runtime->delay)
- - runtime->delay = 0;
- - else
- - runtime->delay -= processed;
- - spin_unlock_irqrestore(&subs->lock, flags);
- - return 0;
- -}
- -
- -static const char *usb_error_string(int err)
- -{
- - switch (err) {
- - case -ENODEV:
- - return "no device";
- - case -ENOENT:
- - return "endpoint not enabled";
- - case -EPIPE:
- - return "endpoint stalled";
- - case -ENOSPC:
- - return "not enough bandwidth";
- - case -ESHUTDOWN:
- - return "device disabled";
- - case -EHOSTUNREACH:
- - return "device suspended";
- - case -EINVAL:
- - case -EAGAIN:
- - case -EFBIG:
- - case -EMSGSIZE:
- - return "internal error";
- - default:
- - return "unknown error";
- - }
- -}
- -
- -/*
- - * set up and start data/sync urbs
- - */
- -static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
- -{
- - unsigned int i;
- - int err;
- -
- - if (subs->stream->chip->shutdown)
- - return -EBADFD;
- -
- - for (i = 0; i < subs->nurbs; i++) {
- - if (snd_BUG_ON(!subs->dataurb[i].urb))
- - return -EINVAL;
- - if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
- - snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
- - goto __error;
- - }
- - }
- - if (subs->syncpipe) {
- - for (i = 0; i < SYNC_URBS; i++) {
- - if (snd_BUG_ON(!subs->syncurb[i].urb))
- - return -EINVAL;
- - if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
- - snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
- - goto __error;
- - }
- - }
- - }
- -
- - subs->active_mask = 0;
- - subs->unlink_mask = 0;
- - subs->running = 1;
- - for (i = 0; i < subs->nurbs; i++) {
- - err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
- - if (err < 0) {
- - snd_printk(KERN_ERR "cannot submit datapipe "
- - "for urb %d, error %d: %s\n",
- - i, err, usb_error_string(err));
- - goto __error;
- - }
- - set_bit(i, &subs->active_mask);
- - }
- - if (subs->syncpipe) {
- - for (i = 0; i < SYNC_URBS; i++) {
- - err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
- - if (err < 0) {
- - snd_printk(KERN_ERR "cannot submit syncpipe "
- - "for urb %d, error %d: %s\n",
- - i, err, usb_error_string(err));
- - goto __error;
- - }
- - set_bit(i + 16, &subs->active_mask);
- - }
- - }
- - return 0;
- -
- - __error:
- - // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
- - deactivate_urbs(subs, 0, 0);
- - return -EPIPE;
- -}
- -
- -
- -/*
- - */
- -static struct snd_urb_ops audio_urb_ops[2] = {
- - {
- - .prepare = prepare_nodata_playback_urb,
- - .retire = retire_playback_urb,
- - .prepare_sync = prepare_playback_sync_urb,
- - .retire_sync = retire_playback_sync_urb,
- - },
- - {
- - .prepare = prepare_capture_urb,
- - .retire = retire_capture_urb,
- - .prepare_sync = prepare_capture_sync_urb,
- - .retire_sync = retire_capture_sync_urb,
- - },
- -};
- -
- -/*
- - * initialize the substream instance.
- - */
- -
- -void snd_usb_init_substream(struct snd_usb_stream *as,
- - int stream, struct audioformat *fp)
- -{
- - struct snd_usb_substream *subs = &as->substream[stream];
- -
- - INIT_LIST_HEAD(&subs->fmt_list);
- - spin_lock_init(&subs->lock);
- -
- - subs->stream = as;
- - subs->direction = stream;
- - subs->dev = as->chip->dev;
- - subs->txfr_quirk = as->chip->txfr_quirk;
- - subs->ops = audio_urb_ops[stream];
- - if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
- - subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
- -
- - snd_usb_set_pcm_ops(as->pcm, stream);
- -
- - list_add_tail(&fp->list, &subs->fmt_list);
- - subs->formats |= fp->formats;
- - subs->endpoint = fp->endpoint;
- - subs->num_formats++;
- - subs->fmt_type = fp->fmt_type;
- -}
- -
- -int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd)
- -{
- - struct snd_usb_substream *subs = substream->runtime->private_data;
- -
- - switch (cmd) {
- - case SNDRV_PCM_TRIGGER_START:
- - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- - subs->ops.prepare = prepare_playback_urb;
- - return 0;
- - case SNDRV_PCM_TRIGGER_STOP:
- - return deactivate_urbs(subs, 0, 0);
- - case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- - subs->ops.prepare = prepare_nodata_playback_urb;
- - return 0;
- - }
- -
- - return -EINVAL;
- -}
- -
- -int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
- -{
- - struct snd_usb_substream *subs = substream->runtime->private_data;
- -
- - switch (cmd) {
- - case SNDRV_PCM_TRIGGER_START:
- - subs->ops.retire = retire_capture_urb;
- - return start_urbs(subs, substream->runtime);
- - case SNDRV_PCM_TRIGGER_STOP:
- - return deactivate_urbs(subs, 0, 0);
- - case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- - subs->ops.retire = retire_paused_capture_urb;
- - return 0;
- - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- - subs->ops.retire = retire_capture_urb;
- - return 0;
- - }
- -
- - return -EINVAL;
- -}
- -
- -int snd_usb_substream_prepare(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime)
- -{
- - /* clear urbs (to be sure) */
- - deactivate_urbs(subs, 0, 1);
- - wait_clear_urbs(subs);
- -
- - /* for playback, submit the URBs now; otherwise, the first hwptr_done
- - * updates for all URBs would happen at the same time when starting */
- - if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
- - subs->ops.prepare = prepare_nodata_playback_urb;
- - return start_urbs(subs, runtime);
- - }
- -
- - return 0;
- -}
- -
- diff --git a/sound/usb/urb.h b/sound/usb/urb.h
- deleted file mode 100644
- index 888da38..0000000
- --- a/sound/usb/urb.h
- +++ /dev/null
- @@ -1,21 +0,0 @@
- -#ifndef __USBAUDIO_URB_H
- -#define __USBAUDIO_URB_H
- -
- -void snd_usb_init_substream(struct snd_usb_stream *as,
- - int stream,
- - struct audioformat *fp);
- -
- -int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
- - unsigned int period_bytes,
- - unsigned int rate,
- - unsigned int frame_bits);
- -
- -void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
- -
- -int snd_usb_substream_prepare(struct snd_usb_substream *subs,
- - struct snd_pcm_runtime *runtime);
- -
- -int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
- -int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
- -
- -#endif /* __USBAUDIO_URB_H */
- diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
- index 1e79986..4aa9e11 100644
- --- a/sound/usb/usbaudio.h
- +++ b/sound/usb/usbaudio.h
- @@ -39,13 +39,14 @@ struct snd_usb_audio {
- struct mutex shutdown_mutex;
- unsigned int shutdown:1;
- unsigned int probing:1;
- - unsigned int autosuspended:1;
- + unsigned int autosuspended:1;
- unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
- -
- +
- int num_interfaces;
- int num_suspended_intf;
- struct list_head pcm_list; /* list of pcm streams */
- + struct list_head ep_list; /* list of audio-related endpoints */
- int pcm_devs;
- struct list_head midi_list; /* list of midi interfaces */
Add Comment
Please, Sign In to add comment