X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Fusb%2Fusbaudio.c;h=4e614ac39f2194e22c227ca7854377a6964bed18;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=aae66144d411ce579eee7185b8e3cca84e730d9e;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index aae66144d..4e614ac39 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -45,7 +45,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -68,6 +70,7 @@ static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ static int nrpacks = 4; /* max. number of packets per urb */ static int async_unlink = 1; +static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -79,10 +82,12 @@ module_param_array(vid, int, NULL, 0444); MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device."); module_param_array(pid, int, NULL, 0444); MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); -module_param(nrpacks, int, 0444); +module_param(nrpacks, int, 0644); MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); module_param(async_unlink, bool, 0444); MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); +module_param_array(device_setup, int, NULL, 0444); +MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); /* @@ -97,14 +102,10 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); #define MAX_PACKS 10 #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ -#define MAX_URBS 5 /* max. 20ms long packets */ -#define SYNC_URBS 2 /* always two urbs for sync */ +#define MAX_URBS 8 +#define SYNC_URBS 4 /* always four urbs for sync */ #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ -typedef struct snd_usb_substream snd_usb_substream_t; -typedef struct snd_usb_stream snd_usb_stream_t; -typedef struct snd_urb_ctx snd_urb_ctx_t; - struct audioformat { struct list_head list; snd_pcm_format_t format; /* format type */ @@ -124,26 +125,27 @@ struct audioformat { unsigned int *rate_table; /* rate table */ }; +struct snd_usb_substream; + struct snd_urb_ctx { struct urb *urb; - snd_usb_substream_t *subs; + unsigned int buffer_size; /* size of data buffer, if data URB */ + struct snd_usb_substream *subs; int index; /* index for urb array */ int packets; /* number of packets per urb */ - int transfer; /* transferred size */ - char *buf; /* buffer for capture */ }; struct snd_urb_ops { - int (*prepare)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u); - int (*retire)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u); - int (*prepare_sync)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u); - int (*retire_sync)(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime, struct urb *u); + 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 { - snd_usb_stream_t *stream; + struct snd_usb_stream *stream; struct usb_device *dev; - snd_pcm_substream_t *pcm_substream; + struct snd_pcm_substream *pcm_substream; int direction; /* playback or capture */ int interface; /* current interface */ int endpoint; /* assigned endpoint */ @@ -153,6 +155,7 @@ struct snd_usb_substream { unsigned int format; /* USB data format */ 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 */ @@ -164,21 +167,20 @@ struct snd_usb_substream { unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ unsigned int fmt_type; /* USB audio format type (1-3) */ + unsigned int packs_per_ms; /* packets per millisecond (for playback) */ unsigned int running: 1; /* running status */ - unsigned int hwptr; /* free frame position in the buffer (only for playback) */ unsigned int hwptr_done; /* processed frame position in the buffer */ - unsigned int transfer_sched; /* scheduled frames since last period (for playback) */ 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 */ - snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ - snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ - char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */ - char *tmpbuf; /* temporary buffer for playback */ + 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 */ u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ @@ -190,11 +192,11 @@ struct snd_usb_substream { struct snd_usb_stream { - snd_usb_audio_t *chip; - snd_pcm_t *pcm; + struct snd_usb_audio *chip; + struct snd_pcm *pcm; int pcm_index; unsigned int fmt_type; /* USB audio format type (1-3) */ - snd_usb_substream_t substream[2]; + struct snd_usb_substream substream[2]; struct list_head list; }; @@ -204,15 +206,15 @@ struct snd_usb_stream { * the all interfaces on the same card as one sound device. */ -static DECLARE_MUTEX(register_mutex); -static snd_usb_audio_t *usb_chip[SNDRV_CARDS]; +static DEFINE_MUTEX(register_mutex); +static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; /* * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz */ -inline static unsigned get_usb_full_speed_rate(unsigned int rate) +static inline unsigned get_usb_full_speed_rate(unsigned int rate) { return ((rate << 13) + 62) / 125; } @@ -221,19 +223,19 @@ inline static unsigned get_usb_full_speed_rate(unsigned int rate) * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) * this will overflow at approx 4 MHz */ -inline static unsigned get_usb_high_speed_rate(unsigned int rate) +static inline unsigned get_usb_high_speed_rate(unsigned int rate) { return ((rate << 10) + 62) / 125; } /* convert our full speed USB rate into sampling rate in Hz */ -inline static unsigned get_full_speed_hz(unsigned int usb_rate) +static inline unsigned get_full_speed_hz(unsigned int usb_rate) { return (usb_rate * 125 + (1 << 12)) >> 13; } /* convert our high speed USB rate into sampling rate in Hz */ -inline static unsigned get_high_speed_hz(unsigned int usb_rate) +static inline unsigned get_high_speed_hz(unsigned int usb_rate) { return (usb_rate * 125 + (1 << 9)) >> 10; } @@ -245,23 +247,19 @@ inline static unsigned get_high_speed_hz(unsigned int usb_rate) * 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(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +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; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; + struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn >> 2; - cp[1] = subs->freqn >> 10; - cp[2] = subs->freqn >> 18; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn >> 2; + cp[1] = subs->freqn >> 10; + cp[2] = subs->freqn >> 18; return 0; } @@ -271,24 +269,20 @@ static int prepare_capture_sync_urb(snd_usb_substream_t *subs, * fill the length and offset of each urb descriptor. * the fixed 12.13 frequency is passed as 16.16 through the pipe. */ -static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +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; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - int i, offs; + struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - cp[0] = subs->freqn; - cp[1] = subs->freqn >> 8; - cp[2] = subs->freqn >> 16; - cp[3] = subs->freqn >> 24; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn; + cp[1] = subs->freqn >> 8; + cp[2] = subs->freqn >> 16; + cp[3] = subs->freqn >> 24; return 0; } @@ -296,8 +290,8 @@ static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs, * process after capture sync complete * - nothing to do */ -static int retire_capture_sync_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int retire_capture_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { return 0; @@ -313,32 +307,22 @@ static int retire_capture_sync_urb(snd_usb_substream_t *subs, * write onto the pcm buffer directly... the data is thus copied * later at complete callback to the global buffer. */ -static int prepare_capture_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int prepare_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { int i, offs; - unsigned long flags; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; + struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; offs = 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++) { urb->iso_frame_desc[i].offset = offs; urb->iso_frame_desc[i].length = subs->curpacksize; offs += subs->curpacksize; - urb->number_of_packets++; - subs->transfer_sched += subs->curframesize; - if (subs->transfer_sched >= runtime->period_size) { - subs->transfer_sched -= runtime->period_size; - break; - } } - spin_unlock_irqrestore(&subs->lock, flags); - urb->transfer_buffer = ctx->buf; urb->transfer_buffer_length = offs; + urb->number_of_packets = ctx->packets; #if 0 // for check if (! urb->bandwidth) { int bustime; @@ -358,14 +342,15 @@ static int prepare_capture_urb(snd_usb_substream_t *subs, * copy the data from each desctiptor to the pcm buffer, and * update the current position. */ -static int retire_capture_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +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, len, oldptr; + int period_elapsed = 0; stride = runtime->frame_bits >> 3; @@ -385,6 +370,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs, if (subs->hwptr_done >= runtime->buffer_size) subs->hwptr_done -= runtime->buffer_size; subs->transfer_done += len; + 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 + len > runtime->buffer_size) { @@ -395,15 +384,9 @@ static int retire_capture_urb(snd_usb_substream_t *subs, } else { memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); } - /* update the pointer, call callback if necessary */ - spin_lock_irqsave(&subs->lock, flags); - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - spin_unlock_irqrestore(&subs->lock, flags); - snd_pcm_period_elapsed(subs->pcm_substream); - } else - spin_unlock_irqrestore(&subs->lock, flags); } + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); return 0; } @@ -414,19 +397,15 @@ static int retire_capture_urb(snd_usb_substream_t *subs, * set up the offset and length to receive the current frequency. */ -static int prepare_playback_sync_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int prepare_playback_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { - int i, offs; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; + struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 3; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -436,19 +415,15 @@ static int prepare_playback_sync_urb(snd_usb_substream_t *subs, * set up the offset and length to receive the current frequency. */ -static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int prepare_playback_sync_urb_hs(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { - int i, offs; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; + struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; - urb->number_of_packets = ctx->packets; urb->dev = ctx->subs->dev; /* we need to set this at each time */ - for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) { - urb->iso_frame_desc[i].length = 4; - urb->iso_frame_desc[i].offset = offs; - } + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; return 0; } @@ -458,35 +433,21 @@ static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs, * retrieve the current 10.14 frequency from pipe, and set it. * the value is referred in prepare_playback_urb(). */ -static int retire_playback_sync_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int retire_playback_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { - int i; - unsigned int f, found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 3) - continue; - f = combine_triple(cp) << 2; -#if 0 - if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { - snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", - f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1), - subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1)); - continue; + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 3) { + f = combine_triple((u8*)urb->transfer_buffer) << 2; + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); } -#endif - found = f; - } - if (found) { - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; - spin_unlock_irqrestore(&subs->lock, flags); } return 0; @@ -498,49 +459,84 @@ static int retire_playback_sync_urb(snd_usb_substream_t *subs, * retrieve the current 12.13 frequency from pipe, and set it. * the value is referred in prepare_playback_urb(). */ -static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int retire_playback_sync_urb_hs(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { - int i; - unsigned int found; - unsigned char *cp = urb->transfer_buffer; + unsigned int f; unsigned long flags; - found = 0; - for (i = 0; i < urb->number_of_packets; i++, cp += 4) { - if (urb->iso_frame_desc[i].status || - urb->iso_frame_desc[i].actual_length < 4) - continue; - found = combine_quad(cp) & 0x0fffffff; + if (urb->iso_frame_desc[0].status == 0 && + urb->iso_frame_desc[0].actual_length == 4) { + f = combine_quad((u8*)urb->transfer_buffer) & 0x0fffffff; + if (f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax) { + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); + } } - if (found) { - spin_lock_irqsave(&subs->lock, flags); - subs->freqm = found; - spin_unlock_irqrestore(&subs->lock, flags); + + 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. + * + * We don't yet have data, so we send a frame of silence. + */ +static int prepare_startup_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; + urb->number_of_packets = subs->packs_per_ms; + for (i = 0; i < subs->packs_per_ms; ++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->transfer_buffer_length = offs * stride; + memset(urb->transfer_buffer, + subs->cur_audiofmt->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0, + offs * stride); return 0; } /* * prepare urb for playback data pipe * - * we copy the data directly from the pcm buffer. - * the current position to be copied is held in hwptr field. - * since a urb can handle only a single linear buffer, if the total - * transferred area overflows the buffer boundary, we cannot send - * it directly from the buffer. thus the data is once copied to - * a temporary buffer and urb points to that. - */ -static int prepare_playback_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, + * 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, offs; unsigned int counts; unsigned long flags; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; + int period_elapsed = 0; + struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context; stride = runtime->frame_bits >> 3; @@ -549,89 +545,74 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, urb->number_of_packets = 0; spin_lock_irqsave(&subs->lock, flags); for (i = 0; i < ctx->packets; i++) { - /* calculate the size of a packet */ - if (subs->fill_max) - counts = subs->maxframesize; /* fixed */ - else { - subs->phase = (subs->phase & 0xffff) + subs->freqm; - counts = subs->phase >> 16; - if (counts > subs->maxframesize) - counts = subs->maxframesize; - } + counts = snd_usb_audio_next_packet_size(subs); /* set up descriptor */ urb->iso_frame_desc[i].offset = offs * stride; urb->iso_frame_desc[i].length = counts * stride; offs += counts; urb->number_of_packets++; - subs->transfer_sched += counts; - if (subs->transfer_sched >= runtime->period_size) { - subs->transfer_sched -= runtime->period_size; + subs->transfer_done += counts; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; if (subs->fmt_type == USB_FORMAT_TYPE_II) { - if (subs->transfer_sched > 0) { - /* FIXME: fill-max mode is not supported yet */ - offs -= subs->transfer_sched; - counts -= subs->transfer_sched; - urb->iso_frame_desc[i].length = counts * stride; - subs->transfer_sched = 0; + if (subs->transfer_done > 0) { + /* FIXME: fill-max mode is not + * supported yet */ + offs -= 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 = offs * stride; + urb->iso_frame_desc[i].offset = + offs * stride; urb->iso_frame_desc[i].length = 0; urb->number_of_packets++; } + break; } - break; } + /* finish at the frame boundary at/after the period boundary */ + if (period_elapsed && + (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1) + break; } - if (subs->hwptr + offs > runtime->buffer_size) { - /* err, the transferred area goes over buffer boundary. - * copy the data to the temp buffer. - */ - int len; - len = runtime->buffer_size - subs->hwptr; - urb->transfer_buffer = subs->tmpbuf; - memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride); - memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride); - subs->hwptr += offs; - subs->hwptr -= runtime->buffer_size; + if (subs->hwptr_done + offs > runtime->buffer_size) { + /* err, the transferred area goes over buffer boundary. */ + unsigned int len = runtime->buffer_size - subs->hwptr_done; + memcpy(urb->transfer_buffer, + runtime->dma_area + subs->hwptr_done * stride, + len * stride); + memcpy(urb->transfer_buffer + len * stride, + runtime->dma_area, + (offs - len) * stride); } else { - /* set the buffer pointer */ - urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride; - subs->hwptr += offs; + memcpy(urb->transfer_buffer, + runtime->dma_area + subs->hwptr_done * stride, + offs * stride); } + subs->hwptr_done += offs; + if (subs->hwptr_done >= runtime->buffer_size) + subs->hwptr_done -= runtime->buffer_size; spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; - ctx->transfer = offs; - + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); return 0; } /* * process after playback data complete - * - * update the current position and call callback if a period is processed. + * - nothing to do */ -static int retire_playback_urb(snd_usb_substream_t *subs, - snd_pcm_runtime_t *runtime, +static int retire_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, struct urb *urb) { - unsigned long flags; - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - - spin_lock_irqsave(&subs->lock, flags); - subs->transfer_done += ctx->transfer; - subs->hwptr_done += ctx->transfer; - ctx->transfer = 0; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - spin_unlock_irqrestore(&subs->lock, flags); - snd_pcm_period_elapsed(subs->pcm_substream); - } else - spin_unlock_irqrestore(&subs->lock, flags); return 0; } @@ -640,7 +621,7 @@ static int retire_playback_urb(snd_usb_substream_t *subs, */ static struct snd_urb_ops audio_urb_ops[2] = { { - .prepare = prepare_playback_urb, + .prepare = prepare_startup_playback_urb, .retire = retire_playback_urb, .prepare_sync = prepare_playback_sync_urb, .retire_sync = retire_playback_sync_urb, @@ -655,7 +636,7 @@ static struct snd_urb_ops audio_urb_ops[2] = { static struct snd_urb_ops audio_urb_ops_high_speed[2] = { { - .prepare = prepare_playback_urb, + .prepare = prepare_startup_playback_urb, .retire = retire_playback_urb, .prepare_sync = prepare_playback_sync_urb_hs, .retire_sync = retire_playback_sync_urb_hs, @@ -673,9 +654,9 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = { */ static void snd_complete_urb(struct urb *urb, struct pt_regs *regs) { - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - snd_usb_substream_t *subs = ctx->subs; - snd_pcm_substream_t *substream = ctx->subs->pcm_substream; + struct snd_urb_ctx *ctx = (struct snd_urb_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)) || @@ -696,9 +677,9 @@ static void snd_complete_urb(struct urb *urb, struct pt_regs *regs) */ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs) { - snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; - snd_usb_substream_t *subs = ctx->subs; - snd_pcm_substream_t *substream = ctx->subs->pcm_substream; + struct snd_urb_ctx *ctx = (struct snd_urb_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)) || @@ -714,10 +695,45 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs) } +/* get the physical page pointer at the given offset */ +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +/* allocate virtual buffer; may be called more than once */ +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already large enough */ + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (! runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 0; +} + +/* free virtual buffer; may be called more than once */ +static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + vfree(runtime->dma_area); + runtime->dma_area = NULL; + return 0; +} + + /* * unlink active urbs. */ -static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) +static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) { unsigned int i; int async; @@ -736,10 +752,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) 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) { - u->transfer_flags |= URB_ASYNC_UNLINK; + if (async) usb_unlink_urb(u); - } else + else usb_kill_urb(u); } } @@ -749,10 +764,9 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) 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) { - u->transfer_flags |= URB_ASYNC_UNLINK; + if (async) usb_unlink_urb(u); - } else + else usb_kill_urb(u); } } @@ -762,10 +776,39 @@ static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) } +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"; +#ifndef CONFIG_USB_EHCI_SPLIT_ISO + case -ENOSYS: + return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub"; +#endif + 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(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) +static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime) { unsigned int i; int err; @@ -794,16 +837,22 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) subs->unlink_mask = 0; subs->running = 1; for (i = 0; i < subs->nurbs; i++) { - if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC)) < 0) { - snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err); + 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++) { - if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC)) < 0) { - snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err); + 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); @@ -821,9 +870,9 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) /* * wait until all urbs are processed. */ -static int wait_clear_urbs(snd_usb_substream_t *subs) +static int wait_clear_urbs(struct snd_usb_substream *subs) { - int timeout = HZ; + unsigned long end_time = jiffies + msecs_to_jiffies(1000); unsigned int i; int alive; @@ -841,9 +890,8 @@ static int wait_clear_urbs(snd_usb_substream_t *subs) } if (! alive) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } while (--timeout > 0); + 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; @@ -853,55 +901,76 @@ static int wait_clear_urbs(snd_usb_substream_t *subs) /* * return the current pcm pointer. just return the hwptr_done value. */ -static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream) +static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) { - snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; - return subs->hwptr_done; + struct snd_usb_substream *subs; + snd_pcm_uframes_t hwptr_done; + + subs = (struct snd_usb_substream *)substream->runtime->private_data; + spin_lock(&subs->lock); + hwptr_done = subs->hwptr_done; + spin_unlock(&subs->lock); + return hwptr_done; } /* - * start/stop substream + * start/stop playback substream */ -static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) +static int snd_usb_pcm_playback_trigger(struct snd_pcm_substream *substream, + int cmd) { - snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; - int err; + struct snd_usb_substream *subs = substream->runtime->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - err = start_urbs(subs, substream->runtime); - break; + subs->ops.prepare = prepare_playback_urb; + return 0; case SNDRV_PCM_TRIGGER_STOP: - err = deactivate_urbs(subs, 0, 0); - break; + return deactivate_urbs(subs, 0, 0); default: - err = -EINVAL; - break; + return -EINVAL; + } +} + +/* + * start/stop capture substream + */ +static int snd_usb_pcm_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: + return start_urbs(subs, substream->runtime); + case SNDRV_PCM_TRIGGER_STOP: + return deactivate_urbs(subs, 0, 0); + default: + return -EINVAL; } - return err < 0 ? err : 0; } /* * release a urb data */ -static void release_urb_ctx(snd_urb_ctx_t *u) +static void release_urb_ctx(struct snd_urb_ctx *u) { if (u->urb) { + if (u->buffer_size) + usb_buffer_free(u->subs->dev, u->buffer_size, + u->urb->transfer_buffer, + u->urb->transfer_dma); usb_free_urb(u->urb); u->urb = NULL; } - if (u->buf) { - kfree(u->buf); - u->buf = NULL; - } } /* * release a substream */ -static void release_substream_urbs(snd_usb_substream_t *subs, int force) +static void release_substream_urbs(struct snd_usb_substream *subs, int force) { int i; @@ -913,22 +982,21 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) release_urb_ctx(&subs->dataurb[i]); for (i = 0; i < SYNC_URBS; i++) release_urb_ctx(&subs->syncurb[i]); - if (subs->tmpbuf) { - kfree(subs->tmpbuf); - subs->tmpbuf = NULL; - } + usb_buffer_free(subs->dev, SYNC_URBS * 4, + subs->syncbuf, subs->sync_dma); + subs->syncbuf = NULL; subs->nurbs = 0; } /* * initialize a substream for plaback/capture */ -static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_bytes, +static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int period_bytes, unsigned int rate, unsigned int frame_bits) { unsigned int maxsize, n, i; int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; - unsigned int npacks[MAX_URBS], urb_packs, total_packs; + unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms; /* calculate the frequency in 16.16 format */ if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) @@ -936,40 +1004,59 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by else subs->freqn = get_usb_high_speed_rate(rate); subs->freqm = subs->freqn; - subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */ - subs->phase = 0; - - /* calculate the max. size of packet */ - maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16; - if (subs->maxpacksize && maxsize > subs->maxpacksize) { - //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n", - // maxsize, subs->maxpacksize); + /* 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) - urb_packs = nrpacks; + if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) + packs_per_ms = 8 >> subs->datainterval; else - urb_packs = nrpacks * 8; + packs_per_ms = 1; + subs->packs_per_ms = packs_per_ms; - /* allocate a temporary buffer for playback */ if (is_playback) { - subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL); - if (! subs->tmpbuf) { - snd_printk(KERN_ERR "cannot malloc tmpbuf\n"); - return -ENOMEM; - } - } + urb_packs = nrpacks; + urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB); + urb_packs = min(urb_packs, (unsigned int)MAX_PACKS); + } else + urb_packs = 1; + urb_packs *= packs_per_ms; /* decide how many packets to be used */ - total_packs = (period_bytes + maxsize - 1) / maxsize; - if (total_packs < 2 * MIN_PACKS_URB) - total_packs = 2 * MIN_PACKS_URB; + if (is_playback) { + unsigned int minsize; + /* 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; + /* round up to multiple of packs_per_ms */ + total_packs = (total_packs + packs_per_ms - 1) + & ~(packs_per_ms - 1); + /* we need at least two URBs for queueing */ + if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms) + total_packs = 2 * MIN_PACKS_URB * packs_per_ms; + } else { + total_packs = MAX_URBS * urb_packs; + } subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; if (subs->nurbs > MAX_URBS) { /* too much... */ @@ -988,7 +1075,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by subs->nurbs = 2; npacks[0] = (total_packs + 1) / 2; npacks[1] = total_packs - npacks[0]; - } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) { + } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) { /* the last packet is too small.. */ if (subs->nurbs > 2) { /* merge to the first one */ @@ -1004,69 +1091,66 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by /* allocate and initialize data urbs */ for (i = 0; i < subs->nurbs; i++) { - snd_urb_ctx_t *u = &subs->dataurb[i]; + struct snd_urb_ctx *u = &subs->dataurb[i]; u->index = i; u->subs = subs; - u->transfer = 0; u->packets = npacks[i]; + u->buffer_size = maxsize * u->packets; if (subs->fmt_type == USB_FORMAT_TYPE_II) u->packets++; /* for transfer delimiter */ - if (! is_playback) { - /* allocate a capture buffer per urb */ - u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL); - if (! u->buf) { - release_substream_urbs(subs, 0); - return -ENOMEM; - } - } u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); - if (! u->urb) { - release_substream_urbs(subs, 0); - return -ENOMEM; - } - u->urb->dev = subs->dev; + if (! u->urb) + goto out_of_memory; + u->urb->transfer_buffer = + usb_buffer_alloc(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; - u->urb->number_of_packets = u->packets; - u->urb->interval = 1; + 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_usb_complete_callback(snd_complete_urb); + u->urb->complete = snd_complete_urb; } if (subs->syncpipe) { /* allocate and initialize sync urbs */ + subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4, + GFP_KERNEL, &subs->sync_dma); + if (! subs->syncbuf) + goto out_of_memory; for (i = 0; i < SYNC_URBS; i++) { - snd_urb_ctx_t *u = &subs->syncurb[i]; + struct snd_urb_ctx *u = &subs->syncurb[i]; u->index = i; u->subs = subs; - u->packets = nrpacks; - u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); - if (! u->urb) { - release_substream_urbs(subs, 0); - return -ENOMEM; - } - u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4; - u->urb->transfer_buffer_length = nrpacks * 4; - u->urb->dev = subs->dev; + 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; - u->urb->number_of_packets = u->packets; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) - u->urb->interval = 8; - else - u->urb->interval = 1; + 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_usb_complete_callback(snd_complete_sync_urb); + u->urb->complete = snd_complete_sync_urb; } } return 0; + +out_of_memory: + release_substream_urbs(subs, 0); + return -ENOMEM; } /* * find a matching audio format */ -static struct audioformat *find_format(snd_usb_substream_t *subs, unsigned int format, +static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, unsigned int rate, unsigned int channels) { struct list_head *p; @@ -1191,7 +1275,7 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, /* * find a matching format and set up the interface */ -static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) +static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) { struct usb_device *dev = subs->dev; struct usb_host_interface *alts; @@ -1235,6 +1319,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) subs->datapipe = usb_sndisocpipe(dev, ep); else subs->datapipe = usb_rcvisocpipe(dev, ep); + if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH && + get_endpoint(alts, 0)->bInterval >= 1 && + get_endpoint(alts, 0)->bInterval <= 4) + subs->datainterval = get_endpoint(alts, 0)->bInterval - 1; + else + subs->datainterval = 0; subs->syncpipe = subs->syncinterval = 0; subs->maxpacksize = fmt->maxpacksize; subs->fill_max = 0; @@ -1272,7 +1362,17 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) subs->syncpipe = usb_rcvisocpipe(dev, ep); else subs->syncpipe = usb_sndisocpipe(dev, ep); - subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + 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; } /* always fill max packet size */ @@ -1304,15 +1404,16 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt) * if sg buffer is supported on the later version of alsa, we'll follow * that. */ -static int snd_usb_hw_params(snd_pcm_substream_t *substream, - snd_pcm_hw_params_t *hw_params) +static int snd_usb_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; + struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data; struct audioformat *fmt; unsigned int channels, rate, format; int ret, changed; - ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); if (ret < 0) return ret; @@ -1321,8 +1422,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream, channels = params_channels(hw_params); fmt = find_format(subs, format, rate, channels); if (! fmt) { - snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n", - snd_pcm_format_name(format), rate, channels); + snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n", + format, rate, channels); return -EINVAL; } @@ -1360,15 +1461,15 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream, * * reset the audio format and release the buffer */ -static int snd_usb_hw_free(snd_pcm_substream_t *substream) +static int snd_usb_hw_free(struct snd_pcm_substream *substream) { - snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; + struct snd_usb_substream *subs = (struct snd_usb_substream *)substream->runtime->private_data; subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; release_substream_urbs(subs, 0); - return snd_pcm_lib_free_pages(substream); + return snd_pcm_free_vmalloc_buffer(substream); } /* @@ -1376,10 +1477,10 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream) * * only a few subtle things... */ -static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) +static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) { - snd_pcm_runtime_t *runtime = substream->runtime; - snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_usb_substream *subs = runtime->private_data; if (! subs->cur_audiofmt) { snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); @@ -1391,9 +1492,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); /* reset the pointer */ - subs->hwptr = 0; subs->hwptr_done = 0; - subs->transfer_sched = 0; subs->transfer_done = 0; subs->phase = 0; @@ -1401,29 +1500,39 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) deactivate_urbs(subs, 0, 1); wait_clear_urbs(subs); - return 0; + /* 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_startup_playback_urb; + return start_urbs(subs, runtime); + } else + return 0; } -static snd_pcm_hardware_t snd_usb_playback = +static struct snd_pcm_hardware snd_usb_playback = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .buffer_bytes_max = (128*1024), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .buffer_bytes_max = 1024 * 1024, .period_bytes_min = 64, - .period_bytes_max = (128*1024), + .period_bytes_max = 512 * 1024, .periods_min = 2, .periods_max = 1024, }; -static snd_pcm_hardware_t snd_usb_capture = +static struct snd_pcm_hardware snd_usb_capture = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .buffer_bytes_max = (128*1024), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .buffer_bytes_max = 1024 * 1024, .period_bytes_min = 64, - .period_bytes_max = (128*1024), + .period_bytes_max = 512 * 1024, .periods_min = 2, .periods_max = 1024, }; @@ -1438,11 +1547,11 @@ static snd_pcm_hardware_t snd_usb_capture = #define hwc_debug(fmt, args...) /**/ #endif -static int hw_check_valid_format(snd_pcm_hw_params_t *params, struct audioformat *fp) +static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audioformat *fp) { - snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - snd_interval_t *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - snd_mask_t *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); /* check the format */ if (! snd_mask_test(fmts, fp->format)) { @@ -1466,12 +1575,12 @@ static int hw_check_valid_format(snd_pcm_hw_params_t *params, struct audioformat return 1; } -static int hw_rule_rate(snd_pcm_hw_params_t *params, - snd_pcm_hw_rule_t *rule) +static int hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { - snd_usb_substream_t *subs = rule->private; + struct snd_usb_substream *subs = rule->private; struct list_head *p; - snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); unsigned int rmin, rmax; int changed; @@ -1520,12 +1629,12 @@ static int hw_rule_rate(snd_pcm_hw_params_t *params, } -static int hw_rule_channels(snd_pcm_hw_params_t *params, - snd_pcm_hw_rule_t *rule) +static int hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { - snd_usb_substream_t *subs = rule->private; + struct snd_usb_substream *subs = rule->private; struct list_head *p; - snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); unsigned int rmin, rmax; int changed; @@ -1573,12 +1682,12 @@ static int hw_rule_channels(snd_pcm_hw_params_t *params, return changed; } -static int hw_rule_format(snd_pcm_hw_params_t *params, - snd_pcm_hw_rule_t *rule) +static int hw_rule_format(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) { - snd_usb_substream_t *subs = rule->private; + struct snd_usb_substream *subs = rule->private; struct list_head *p; - snd_mask_t *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); u64 fbits; u32 oldbits[2]; int changed; @@ -1611,7 +1720,7 @@ static int hw_rule_format(snd_pcm_hw_params_t *params, /* * check whether the registered audio formats need special hw-constraints */ -static int check_hw_params_convention(snd_usb_substream_t *subs) +static int check_hw_params_convention(struct snd_usb_substream *subs) { int i; u32 *channels; @@ -1695,7 +1804,7 @@ static int check_hw_params_convention(snd_usb_substream_t *subs) * set up the runtime hardware information. */ -static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs) +static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { struct list_head *p; int err; @@ -1756,12 +1865,12 @@ static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs) return 0; } -static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction, - snd_pcm_hardware_t *hw) +static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction, + struct snd_pcm_hardware *hw) { - snd_usb_stream_t *as = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - snd_usb_substream_t *subs = &as->substream[direction]; + struct snd_usb_stream *as = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_usb_substream *subs = &as->substream[direction]; subs->interface = -1; subs->format = 0; @@ -1771,10 +1880,10 @@ static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction, return setup_hw_info(runtime, subs); } -static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction) +static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) { - snd_usb_stream_t *as = snd_pcm_substream_chip(substream); - snd_usb_substream_t *subs = &as->substream[direction]; + struct snd_usb_stream *as = snd_pcm_substream_chip(substream); + struct snd_usb_substream *subs = &as->substream[direction]; if (subs->interface >= 0) { usb_set_interface(subs->dev, subs->interface, 0); @@ -1784,46 +1893,48 @@ static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction) return 0; } -static int snd_usb_playback_open(snd_pcm_substream_t *substream) +static int snd_usb_playback_open(struct snd_pcm_substream *substream) { return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK, &snd_usb_playback); } -static int snd_usb_playback_close(snd_pcm_substream_t *substream) +static int snd_usb_playback_close(struct snd_pcm_substream *substream) { return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK); } -static int snd_usb_capture_open(snd_pcm_substream_t *substream) +static int snd_usb_capture_open(struct snd_pcm_substream *substream) { return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE, &snd_usb_capture); } -static int snd_usb_capture_close(snd_pcm_substream_t *substream) +static int snd_usb_capture_close(struct snd_pcm_substream *substream) { return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); } -static snd_pcm_ops_t snd_usb_playback_ops = { +static struct snd_pcm_ops snd_usb_playback_ops = { .open = snd_usb_playback_open, .close = snd_usb_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_pcm_trigger, + .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, }; -static snd_pcm_ops_t snd_usb_capture_ops = { +static struct snd_pcm_ops snd_usb_capture_ops = { .open = snd_usb_capture_open, .close = snd_usb_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_pcm_trigger, + .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, }; @@ -1931,7 +2042,6 @@ static struct usb_device_id usb_audio_ids [] = { MODULE_DEVICE_TABLE (usb, usb_audio_ids); static struct usb_driver usb_audio_driver = { - .owner = THIS_MODULE, .name = "snd-usb-audio", .probe = usb_audio_probe, .disconnect = usb_audio_disconnect, @@ -1939,10 +2049,12 @@ static struct usb_driver usb_audio_driver = { }; +#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS) + /* * proc interface for list the supported pcm formats */ -static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buffer_t *buffer) +static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) { struct list_head *p; static char *sync_types[4] = { @@ -1954,7 +2066,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff fp = list_entry(p, struct audioformat, list); snd_iprintf(buffer, " Interface %d\n", fp->iface); snd_iprintf(buffer, " Altset %d\n", fp->altsetting); - snd_iprintf(buffer, " Format: %s\n", snd_pcm_format_name(fp->format)); + snd_iprintf(buffer, " Format: 0x%x\n", fp->format); snd_iprintf(buffer, " Channels: %d\n", fp->channels); snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", fp->endpoint & USB_ENDPOINT_NUMBER_MASK, @@ -1978,7 +2090,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff } } -static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffer_t *buffer) +static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) { if (subs->running) { unsigned int i; @@ -1990,18 +2102,19 @@ static void proc_dump_substream_status(snd_usb_substream_t *subs, snd_info_buffe snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); - snd_iprintf(buffer, " Momentary freq = %u Hz\n", + 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)); + : get_high_speed_hz(subs->freqm), + subs->freqm >> 16, subs->freqm & 0xffff); } else { snd_iprintf(buffer, " Status: Stop\n"); } } -static void proc_pcm_format_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_usb_stream_t *stream = entry->private_data; + struct snd_usb_stream *stream = entry->private_data; snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name); @@ -2017,25 +2130,32 @@ static void proc_pcm_format_read(snd_info_entry_t *entry, snd_info_buffer_t *buf } } -static void proc_pcm_format_add(snd_usb_stream_t *stream) +static void proc_pcm_format_add(struct snd_usb_stream *stream) { - snd_info_entry_t *entry; + struct snd_info_entry *entry; char name[32]; - snd_card_t *card = stream->chip->card; + struct snd_card *card = stream->chip->card; sprintf(name, "stream%d", stream->pcm_index); if (! snd_card_proc_new(card, name, &entry)) snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read); } +#else + +static inline void proc_pcm_format_add(struct snd_usb_stream *stream) +{ +} + +#endif /* * initialize the substream instance. */ -static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat *fp) +static void init_substream(struct snd_usb_stream *as, int stream, struct audioformat *fp) { - snd_usb_substream_t *subs = &as->substream[stream]; + struct snd_usb_substream *subs = &as->substream[stream]; INIT_LIST_HEAD(&subs->fmt_list); spin_lock_init(&subs->lock); @@ -2047,10 +2167,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat subs->ops = audio_urb_ops[stream]; else subs->ops = audio_urb_ops_high_speed[stream]; - snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 64 * 1024, 128 * 1024); snd_pcm_set_ops(as->pcm, stream, stream == SNDRV_PCM_STREAM_PLAYBACK ? &snd_usb_playback_ops : &snd_usb_capture_ops); @@ -2066,7 +2182,7 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat /* * free a substream */ -static void free_substream(snd_usb_substream_t *subs) +static void free_substream(struct snd_usb_substream *subs) { struct list_head *p, *n; @@ -2083,7 +2199,7 @@ static void free_substream(snd_usb_substream_t *subs) /* * free a usb stream instance */ -static void snd_usb_audio_stream_free(snd_usb_stream_t *stream) +static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) { free_substream(&stream->substream[0]); free_substream(&stream->substream[1]); @@ -2091,12 +2207,11 @@ static void snd_usb_audio_stream_free(snd_usb_stream_t *stream) kfree(stream); } -static void snd_usb_audio_pcm_free(snd_pcm_t *pcm) +static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) { - snd_usb_stream_t *stream = pcm->private_data; + struct snd_usb_stream *stream = pcm->private_data; if (stream) { stream->pcm = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); snd_usb_audio_stream_free(stream); } } @@ -2107,16 +2222,16 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm) * if a stream with the same endpoint already exists, append to it. * if not, create a new pcm stream. */ -static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audioformat *fp) +static int add_audio_endpoint(struct snd_usb_audio *chip, int stream, struct audioformat *fp) { struct list_head *p; - snd_usb_stream_t *as; - snd_usb_substream_t *subs; - snd_pcm_t *pcm; + 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, snd_usb_stream_t, list); + as = list_entry(p, struct snd_usb_stream, list); if (as->fmt_type != fp->fmt_type) continue; subs = &as->substream[stream]; @@ -2131,7 +2246,7 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor } /* look for an empty stream */ list_for_each(p, &chip->pcm_list) { - as = list_entry(p, snd_usb_stream_t, list); + as = list_entry(p, struct snd_usb_stream, list); if (as->fmt_type != fp->fmt_type) continue; subs = &as->substream[stream]; @@ -2183,17 +2298,15 @@ static int add_audio_endpoint(snd_usb_audio_t *chip, int stream, struct audiofor /* * check if the device uses big-endian samples */ -static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) +static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp) { - /* M-Audio */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763) { - /* Quattro: captured data only */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2001 && - fp->endpoint & USB_DIR_IN) - return 1; - /* Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idProduct) == 0x2003) + switch (chip->usb_id) { + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */ + if (fp->endpoint & USB_DIR_IN) return 1; + break; + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + return 1; } return 0; } @@ -2207,7 +2320,7 @@ static int is_big_endian_format(struct usb_device *dev, struct audioformat *fp) * @format: the format tag (wFormatTag) * @fmt: the format type descriptor */ -static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2220,12 +2333,12 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat switch (format) { case 0: /* some devices don't define this correctly... */ snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); /* fall-through */ case USB_AUDIO_FORMAT_PCM: if (sample_width > sample_bytes * 8) { snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", - dev->devnum, fp->iface, fp->altsetting, + chip->dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); } /* check the format byte size */ @@ -2234,13 +2347,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - if (is_big_endian_format(dev, fp)) + if (is_big_endian_format(chip, fp)) pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ else pcm_format = SNDRV_PCM_FORMAT_S24_3LE; @@ -2250,14 +2363,14 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", - dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); + chip->dev->devnum, fp->iface, + fp->altsetting, sample_width, sample_bytes); break; } break; case USB_AUDIO_FORMAT_PCM8: /* Dallas DS4201 workaround */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && - le16_to_cpu(dev->descriptor.idProduct) == 0x4201) + if (chip->usb_id == USB_ID(0x04fa, 0x4201)) pcm_format = SNDRV_PCM_FORMAT_S8; else pcm_format = SNDRV_PCM_FORMAT_U8; @@ -2273,7 +2386,7 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); break; } return pcm_format; @@ -2290,13 +2403,13 @@ static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat * @offset: the start offset of descriptor pointing the rate type * (7 for type I and II, 8 for type II) */ -static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioformat *fp, unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", - dev->devnum, fp->iface, fp->altsetting); + chip->dev->devnum, fp->iface, fp->altsetting); return -1; } @@ -2343,7 +2456,7 @@ static int parse_audio_format_rates(struct usb_device *dev, struct audioformat * /* * parse the format type I and III descriptors */ -static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *fp, int format, unsigned char *fmt) { int pcm_format; @@ -2355,7 +2468,7 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, */ pcm_format = SNDRV_PCM_FORMAT_S16_LE; } else { - pcm_format = parse_audio_format_i_type(dev, fp, format, fmt); + pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); if (pcm_format < 0) return -1; } @@ -2363,16 +2476,16 @@ static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, fp->channels = fmt[4]; if (fp->channels < 1) { snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", - dev->devnum, fp->iface, fp->altsetting, fp->channels); + chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); return -1; } - return parse_audio_format_rates(dev, fp, fmt, 7); + return parse_audio_format_rates(chip, fp, fmt, 7); } /* * prase the format type II descriptor */ -static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat *fp, int format, unsigned char *fmt) { int brate, framesize; @@ -2387,7 +2500,7 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, break; default: snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", - dev->devnum, fp->iface, fp->altsetting, format); + chip->dev->devnum, fp->iface, fp->altsetting, format); fp->format = SNDRV_PCM_FORMAT_MPEG; break; } @@ -2396,10 +2509,10 @@ static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); fp->frame_size = framesize; - return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */ + return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ } -static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, +static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, int format, unsigned char *fmt, int stream) { int err; @@ -2407,36 +2520,39 @@ static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, switch (fmt[3]) { case USB_FORMAT_TYPE_I: case USB_FORMAT_TYPE_III: - err = parse_audio_format_i(dev, fp, format, fmt); + err = parse_audio_format_i(chip, fp, format, fmt); break; case USB_FORMAT_TYPE_II: - err = parse_audio_format_ii(dev, fp, format, fmt); + err = parse_audio_format_ii(chip, fp, format, fmt); break; default: snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", - dev->devnum, fp->iface, fp->altsetting, fmt[3]); + chip->dev->devnum, fp->iface, fp->altsetting, fmt[3]); return -1; } fp->fmt_type = fmt[3]; if (err < 0) return err; #if 1 - /* FIXME: temporary hack for extigy */ + /* FIXME: temporary hack for extigy/audigy 2 nx/zs */ /* extigy apparently supports sample rates other than 48k * but not in ordinary way. so we enable only 48k atm. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + if (chip->usb_id == USB_ID(0x041e, 0x3000) || + chip->usb_id == USB_ID(0x041e, 0x3020) || + chip->usb_id == USB_ID(0x041e, 0x3061)) { if (fmt[3] == USB_FORMAT_TYPE_I && - stream == SNDRV_PCM_STREAM_PLAYBACK && - fp->rates != SNDRV_PCM_RATE_48000) - return -1; /* use 48k only */ + fp->rates != SNDRV_PCM_RATE_48000 && + fp->rates != SNDRV_PCM_RATE_96000) + return -1; } #endif return 0; } -static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) +static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno); +static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) { struct usb_device *dev; struct usb_interface *iface; @@ -2470,6 +2586,12 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; altno = altsd->bAlternateSetting; + + /* audiophile usb: skip altsets incompatible with device_setup + */ + if (chip->usb_id == USB_ID(0x0763, 0x2003) && + audiophile_skip_setting_quirk(chip, iface_no, altno)) + continue; /* get audio formats */ fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL); @@ -2522,52 +2644,49 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) fp->altset_idx = i; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - /* FIXME: decode wMaxPacketSize of high bandwith endpoints */ fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) + * (fp->maxpacksize & 0x7ff); fp->attributes = csep[3]; /* some quirks for attributes here */ - /* workaround for AudioTrak Optoplay */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0a92 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0053) { + switch (chip->usb_id) { + case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ /* Optoplay sets the sample rate attribute although * it seems not supporting it in fact. */ fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; - } - - /* workaround for M-Audio Audiophile USB */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x0763 && - le16_to_cpu(dev->descriptor.idProduct) == 0x2003) { + break; + case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; - } - + break; + case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ + case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is + an older model 77d:223) */ /* * plantronics headset and Griffin iMic have set adaptive-in * although it's really not... */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x047f && - le16_to_cpu(dev->descriptor.idProduct) == 0x0ca1) || - /* Griffin iMic (note that there is an older model 77d:223) */ - (le16_to_cpu(dev->descriptor.idVendor) == 0x077d && - le16_to_cpu(dev->descriptor.idProduct) == 0x07af)) { fp->ep_attr &= ~EP_ATTR_MASK; if (stream == SNDRV_PCM_STREAM_PLAYBACK) fp->ep_attr |= EP_ATTR_ADAPTIVE; else fp->ep_attr |= EP_ATTR_SYNC; + break; } /* ok, let's parse further... */ - if (parse_audio_format(dev, fp, format, fmt, stream) < 0) { + if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { kfree(fp->rate_table); kfree(fp); continue; } - snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint); + snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint); err = add_audio_endpoint(chip, stream, fp); if (err < 0) { kfree(fp->rate_table); @@ -2587,13 +2706,13 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) * disconnect streams * called from snd_usb_audio_disconnect() */ -static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver *driver) +static void snd_usb_stream_disconnect(struct list_head *head) { int idx; - snd_usb_stream_t *as; - snd_usb_substream_t *subs; + struct snd_usb_stream *as; + struct snd_usb_substream *subs; - as = list_entry(head, snd_usb_stream_t, list); + as = list_entry(head, struct snd_usb_stream, list); for (idx = 0; idx < 2; idx++) { subs = &as->substream[idx]; if (!subs->num_formats) @@ -2606,7 +2725,7 @@ static void snd_usb_stream_disconnect(struct list_head *head, struct usb_driver /* * parse audio control descriptor and create pcm/midi streams */ -static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif) +static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) { struct usb_device *dev = chip->dev; struct usb_host_interface *host_iface; @@ -2673,9 +2792,9 @@ static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif) /* * create a stream for an endpoint/altsetting without proper descriptors */ -static int create_fixed_stream_quirk(snd_usb_audio_t *chip, +static int create_fixed_stream_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, - const snd_usb_audio_quirk_t *quirk) + const struct snd_usb_audio_quirk *quirk) { struct audioformat *fp; struct usb_host_interface *alts; @@ -2722,9 +2841,9 @@ static int create_fixed_stream_quirk(snd_usb_audio_t *chip, /* * create a stream for an interface with proper descriptors */ -static int create_standard_interface_quirk(snd_usb_audio_t *chip, - struct usb_interface *iface, - const snd_usb_audio_quirk_t *quirk) +static int create_standard_audio_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) { struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; @@ -2732,24 +2851,14 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip, alts = &iface->altsetting[0]; altsd = get_iface_desc(alts); - switch (quirk->type) { - case QUIRK_AUDIO_STANDARD_INTERFACE: - err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); - if (!err) - usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* reset the current interface */ - break; - case QUIRK_MIDI_STANDARD_INTERFACE: - err = snd_usb_create_midi_interface(chip, iface, NULL); - break; - default: - snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); - return -ENXIO; - } + err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); if (err < 0) { snd_printk(KERN_ERR "cannot setup if %d: error %d\n", altsd->bInterfaceNumber, err); return err; } + /* reset the current interface */ + usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); return 0; } @@ -2757,8 +2866,9 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip, * Create a stream for an Edirol UA-700/UA-25 interface. The only way * to detect the sample rate is by looking at wMaxPacketSize. */ -static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, - struct usb_interface *iface) +static int create_ua700_ua25_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) { static const struct audioformat ua_format = { .format = SNDRV_PCM_FORMAT_S24_3LE, @@ -2780,23 +2890,23 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, altsd = get_iface_desc(alts); if (altsd->bNumEndpoints == 2) { - static const snd_usb_midi_endpoint_info_t ua700_ep = { + static const struct snd_usb_midi_endpoint_info ua700_ep = { .out_cables = 0x0003, .in_cables = 0x0003 }; - static const snd_usb_audio_quirk_t ua700_quirk = { + static const struct snd_usb_audio_quirk ua700_quirk = { .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &ua700_ep }; - static const snd_usb_midi_endpoint_info_t ua25_ep = { + static const struct snd_usb_midi_endpoint_info ua25_ep = { .out_cables = 0x0001, .in_cables = 0x0001 }; - static const snd_usb_audio_quirk_t ua25_quirk = { + static const struct snd_usb_audio_quirk ua25_quirk = { .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &ua25_ep }; - if (le16_to_cpu(chip->dev->descriptor.idProduct) == 0x002b) + if (chip->usb_id == USB_ID(0x0582, 0x002b)) return snd_usb_create_midi_interface(chip, iface, &ua700_quirk); else @@ -2849,7 +2959,9 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip, /* * Create a stream for an Edirol UA-1000 interface. */ -static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *iface) +static int create_ua1000_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) { static const struct audioformat ua1000_format = { .format = SNDRV_PCM_FORMAT_S32_LE, @@ -2896,16 +3008,16 @@ static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *ifac return 0; } -static int snd_usb_create_quirk(snd_usb_audio_t *chip, +static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, - const snd_usb_audio_quirk_t *quirk); + const struct snd_usb_audio_quirk *quirk); /* * handle the quirks for the contained interfaces */ -static int create_composite_quirk(snd_usb_audio_t *chip, +static int create_composite_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, - const snd_usb_audio_quirk_t *quirk) + const struct snd_usb_audio_quirk *quirk) { int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber; int err; @@ -2926,6 +3038,13 @@ static int create_composite_quirk(snd_usb_audio_t *chip, return 0; } +static int ignore_interface_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) +{ + return 0; +} + /* * boot quirks @@ -2959,6 +3078,61 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac return 0; } +static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev) +{ + u8 buf = 1; + + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 0, 0, &buf, 1, 1000); + if (buf == 0) { + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, + 1, 2000, NULL, 0, 1000); + return -ENODEV; + } + return 0; +} + +/* + * Setup quirks + */ +#define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ +#define AUDIOPHILE_SET_DTS 0x02 /* if set, enable DTS Digital Output */ +#define AUDIOPHILE_SET_96K 0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */ +#define AUDIOPHILE_SET_24B 0x08 /* 24bits sample if set, 16bits otherwise */ +#define AUDIOPHILE_SET_DI 0x10 /* if set, enable Digital Input */ +#define AUDIOPHILE_SET_MASK 0x1F /* bit mask for setup value */ +#define AUDIOPHILE_SET_24B_48K_DI 0x19 /* value for 24bits+48KHz+Digital Input */ +#define AUDIOPHILE_SET_24B_48K_NOTDI 0x09 /* value for 24bits+48KHz+No Digital Input */ +#define AUDIOPHILE_SET_16B_48K_DI 0x11 /* value for 16bits+48KHz+Digital Input */ +#define AUDIOPHILE_SET_16B_48K_NOTDI 0x01 /* value for 16bits+48KHz+No Digital Input */ + +static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, + int iface, int altno) +{ + if (device_setup[chip->index] & AUDIOPHILE_SET) { + if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS) + && altno != 6) + return 1; /* skip this altsetting */ + if ((device_setup[chip->index] & AUDIOPHILE_SET_96K) + && altno != 1) + return 1; /* skip this altsetting */ + if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == + AUDIOPHILE_SET_24B_48K_DI && altno != 2) + return 1; /* skip this altsetting */ + if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == + AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3) + return 1; /* skip this altsetting */ + if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == + AUDIOPHILE_SET_16B_48K_DI && altno != 4) + return 1; /* skip this altsetting */ + if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) == + AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5) + return 1; /* skip this altsetting */ + } + return 0; /* keep this altsetting */ +} /* * audio-interface quirks @@ -2968,32 +3142,32 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac * after this. * returns a negative value at error. */ -static int snd_usb_create_quirk(snd_usb_audio_t *chip, +static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, - const snd_usb_audio_quirk_t *quirk) -{ - switch (quirk->type) { - case QUIRK_MIDI_FIXED_ENDPOINT: - case QUIRK_MIDI_YAMAHA: - case QUIRK_MIDI_MIDIMAN: - case QUIRK_MIDI_NOVATION: - case QUIRK_MIDI_MOTU: - case QUIRK_MIDI_EMAGIC: - return snd_usb_create_midi_interface(chip, iface, quirk); - case QUIRK_COMPOSITE: - return create_composite_quirk(chip, iface, quirk); - case QUIRK_AUDIO_FIXED_ENDPOINT: - return create_fixed_stream_quirk(chip, iface, quirk); - case QUIRK_AUDIO_STANDARD_INTERFACE: - case QUIRK_MIDI_STANDARD_INTERFACE: - return create_standard_interface_quirk(chip, iface, quirk); - case QUIRK_AUDIO_EDIROL_UA700_UA25: - return create_ua700_ua25_quirk(chip, iface); - case QUIRK_AUDIO_EDIROL_UA1000: - return create_ua1000_quirk(chip, iface); - case QUIRK_IGNORE_INTERFACE: - return 0; - default: + const struct snd_usb_audio_quirk *quirk) +{ + typedef int (*quirk_func_t)(struct snd_usb_audio *, struct usb_interface *, + const struct snd_usb_audio_quirk *); + static const quirk_func_t quirk_funcs[] = { + [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, + [QUIRK_COMPOSITE] = create_composite_quirk, + [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, + [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, + [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, + [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, + [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, + [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface, + [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, + [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, + [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, + [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, + [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, + [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, + }; + + if (quirk->type < QUIRK_TYPE_COUNT) { + return quirk_funcs[quirk->type](chip, iface, quirk); + } else { snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); return -ENXIO; } @@ -3003,25 +3177,25 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip, /* * common proc files to show the usb device info */ -static void proc_audio_usbbus_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_usb_audio_t *chip = entry->private_data; + struct snd_usb_audio *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); } -static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_usb_audio_t *chip = entry->private_data; + struct snd_usb_audio *chip = entry->private_data; if (! chip->shutdown) snd_iprintf(buffer, "%04x:%04x\n", - le16_to_cpu(chip->dev->descriptor.idVendor), - le16_to_cpu(chip->dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } -static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) +static void snd_usb_audio_create_proc(struct snd_usb_audio *chip) { - snd_info_entry_t *entry; + struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "usbbus", &entry)) snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read); if (! snd_card_proc_new(chip->card, "usbid", &entry)) @@ -3035,15 +3209,15 @@ static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) * */ -static int snd_usb_audio_free(snd_usb_audio_t *chip) +static int snd_usb_audio_free(struct snd_usb_audio *chip) { kfree(chip); return 0; } -static int snd_usb_audio_dev_free(snd_device_t *device) +static int snd_usb_audio_dev_free(struct snd_device *device) { - snd_usb_audio_t *chip = device->device_data; + struct snd_usb_audio *chip = device->device_data; return snd_usb_audio_free(chip); } @@ -3052,14 +3226,14 @@ static int snd_usb_audio_dev_free(snd_device_t *device) * create a chip instance and set its names. */ static int snd_usb_audio_create(struct usb_device *dev, int idx, - const snd_usb_audio_quirk_t *quirk, - snd_usb_audio_t **rchip) + const struct snd_usb_audio_quirk *quirk, + struct snd_usb_audio **rchip) { - snd_card_t *card; - snd_usb_audio_t *chip; + struct snd_card *card; + struct snd_usb_audio *chip; int err, len; char component[14]; - static snd_device_ops_t ops = { + static struct snd_device_ops ops = { .dev_free = snd_usb_audio_dev_free, }; @@ -3077,7 +3251,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, return -ENOMEM; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_card_free(card); return -ENOMEM; @@ -3086,8 +3260,11 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->index = idx; chip->dev = dev; chip->card = card; + 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->midi_list); + INIT_LIST_HEAD(&chip->mixer_list); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_usb_audio_free(chip); @@ -3097,8 +3274,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, strcpy(card->driver, "USB-Audio"); sprintf(component, "USB%04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); snd_component_add(card, component); /* retrieve the device string as shortname */ @@ -3110,8 +3286,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, card->shortname, sizeof(card->shortname)) <= 0) { /* no name available from anywhere, so use ID */ sprintf(card->shortname, "USB Device %#04x:%#04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); + USB_ID_VENDOR(chip->usb_id), + USB_ID_PRODUCT(chip->usb_id)); } } @@ -3142,8 +3318,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, snd_usb_audio_create_proc(chip); - snd_card_set_dev(card, &dev->dev); - *rchip = chip; return 0; } @@ -3163,26 +3337,31 @@ static void *snd_usb_audio_probe(struct usb_device *dev, struct usb_interface *intf, const struct usb_device_id *usb_id) { - struct usb_host_config *config = dev->actconfig; - const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info; + const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info; int i, err; - snd_usb_audio_t *chip; + struct snd_usb_audio *chip; struct usb_host_interface *alts; int ifnum; + u32 id; alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; + id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) goto __err_val; /* SB Extigy needs special boot-up sequence */ /* if more models come, this will go to the quirk list. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x041e && - le16_to_cpu(dev->descriptor.idProduct) == 0x3000) { + if (id == USB_ID(0x041e, 0x3000)) { if (snd_usb_extigy_boot_quirk(dev, intf) < 0) goto __err_val; - config = dev->actconfig; + } + /* SB Audigy 2 NX needs its own boot-up magic, too */ + if (id == USB_ID(0x041e, 0x3020)) { + if (snd_usb_audigy2nx_boot_quirk(dev) < 0) + goto __err_val; } /* @@ -3191,7 +3370,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, /* check whether it's already registered */ chip = NULL; - down(®ister_mutex); + mutex_lock(®ister_mutex); for (i = 0; i < SNDRV_CARDS; i++) { if (usb_chip[i] && usb_chip[i]->dev == dev) { if (usb_chip[i]->shutdown) { @@ -3206,18 +3385,14 @@ static void *snd_usb_audio_probe(struct usb_device *dev, /* it's a fresh one. * now look for an empty slot and create a new card instance */ - /* first, set the current configuration for this device */ - if (usb_reset_configuration(dev) < 0) { - snd_printk(KERN_ERR "cannot reset configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue); - goto __error; - } for (i = 0; i < SNDRV_CARDS; i++) if (enable[i] && ! usb_chip[i] && - (vid[i] == -1 || vid[i] == le16_to_cpu(dev->descriptor.idVendor)) && - (pid[i] == -1 || pid[i] == le16_to_cpu(dev->descriptor.idProduct))) { + (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && + (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) { goto __error; } + snd_card_set_dev(chip->card, &intf->dev); break; } if (! chip) { @@ -3248,13 +3423,13 @@ static void *snd_usb_audio_probe(struct usb_device *dev, usb_chip[chip->index] = chip; chip->num_interfaces++; - up(®ister_mutex); + mutex_unlock(®ister_mutex); return chip; __error: if (chip && !chip->num_interfaces) snd_card_free(chip->card); - up(®ister_mutex); + mutex_unlock(®ister_mutex); __err_val: return NULL; } @@ -3265,8 +3440,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, */ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) { - snd_usb_audio_t *chip; - snd_card_t *card; + struct snd_usb_audio *chip; + struct snd_card *card; struct list_head *p; if (ptr == (void *)-1L) @@ -3274,24 +3449,28 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) chip = ptr; card = chip->card; - down(®ister_mutex); + mutex_lock(®ister_mutex); chip->shutdown = 1; chip->num_interfaces--; if (chip->num_interfaces <= 0) { snd_card_disconnect(card); /* release the pcm resources */ list_for_each(p, &chip->pcm_list) { - snd_usb_stream_disconnect(p, &usb_audio_driver); + snd_usb_stream_disconnect(p); } /* release the midi resources */ list_for_each(p, &chip->midi_list) { - snd_usbmidi_disconnect(p, &usb_audio_driver); + snd_usbmidi_disconnect(p); + } + /* release mixer resources */ + list_for_each(p, &chip->mixer_list) { + snd_usb_mixer_disconnect(p); } usb_chip[chip->index] = NULL; - up(®ister_mutex); + mutex_unlock(®ister_mutex); snd_card_free(card); } else { - up(®ister_mutex); + mutex_unlock(®ister_mutex); } }