usbaudio.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,293 行 · 第 1/5 页

C
2,293
字号
/* *   (Tentative) USB Audio Driver for ALSA * *   Main and PCM part * *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> * *   Many codes borrowed from audio.c by *	    Alan Cox (alan@lxorguk.ukuu.org.uk) *	    Thomas Sailer (sailer@ife.ee.ethz.ch) * * *   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 * * *  NOTES: * *   - async unlink should be used for avoiding the sleep inside lock. *     2.4.22 usb-uhci seems buggy for async unlinking and results in *     oops.  in such a cse, pass async_unlink=0 option. *   - the linked URBs would be preferred but not used so far because of *     the instability of unlinking. *   - type II is not supported properly.  there is no device which supports *     this type *correctly*.  SB extigy looks as if it supports, but it's *     indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). */#include <sound/driver.h>#include <linux/bitops.h>#include <linux/init.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/usb.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/info.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/initval.h>#include "usbaudio.h"MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");MODULE_DESCRIPTION("USB Audio");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Generic,USB Audio}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */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 boot_devs;module_param_array(index, int, boot_devs, 0444);MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");module_param_array(id, charp, boot_devs, 0444);MODULE_PARM_DESC(id, "ID string for the USB audio adapter.");module_param_array(enable, bool, boot_devs, 0444);MODULE_PARM_DESC(enable, "Enable USB audio adapter.");module_param_array(vid, int, boot_devs, 0444);MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");module_param_array(pid, int, boot_devs, 0444);MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");module_param(nrpacks, int, 0444);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.");/* * debug the h/w constraints *//* #define HW_CONST_DEBUG *//* * */#define MAX_PACKS	10#define MAX_PACKS_HS	(MAX_PACKS * 8)	/* in high speed mode */#define MAX_URBS	5	/* max. 20ms long packets */#define SYNC_URBS	2	/* always two urbs for sync */#define MIN_PACKS_URB	1	/* minimum 1 packet per urb */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 */	unsigned int channels;		/* # channels */	unsigned int fmt_type;		/* USB audio format type (1-3) */	unsigned int frame_size;	/* samples per frame for non-audio */	int iface;			/* interface number */	unsigned char altsetting;	/* corresponding alternate setting */	unsigned char altset_idx;	/* array index of altenate setting */	unsigned char attributes;	/* corresponding attributes of cs endpoint */	unsigned char endpoint;		/* endpoint */	unsigned char ep_attr;		/* endpoint attributes */	unsigned int maxpacksize;	/* max. packet size */	unsigned int rates;		/* rate bitmasks */	unsigned int rate_min, rate_max;	/* min/max rates */	unsigned int nr_rates;		/* number of rate table entries */	unsigned int *rate_table;	/* rate table */};struct snd_urb_ctx {	struct urb *urb;	snd_usb_substream_t *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);};struct snd_usb_substream {	snd_usb_stream_t *stream;	struct usb_device *dev;	snd_pcm_substream_t *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 format;     /* USB data format */	unsigned int datapipe;   /* the data i/o pipe */	unsigned int syncpipe;   /* 1 - async out or adaptive in */	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */	unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */	unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */	unsigned int freqmax;    /* maximum sampling rate, used for buffer management */	unsigned int phase;      /* phase accumulator */	unsigned int maxpacksize;	/* max packet size in bytes */	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 fill_max: 1;	/* fill max packet size always */	unsigned int fmt_type;		/* USB audio format type (1-3) */	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 */	u64 formats;			/* format bitmasks (all or'ed) */	unsigned int num_formats;		/* number of supported audio formats (list) */	struct list_head fmt_list;	/* format list */	spinlock_t lock;	struct snd_urb_ops ops;		/* callbacks (must be filled at init) */};struct snd_usb_stream {	snd_usb_audio_t *chip;	snd_pcm_t *pcm;	int pcm_index;	unsigned int fmt_type;		/* USB audio format type (1-3) */	snd_usb_substream_t substream[2];	struct list_head list;};/* * we keep the snd_usb_audio_t instances by ourselves for merging * 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];/* * 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){	return ((rate << 13) + 62) / 125;}/* * convert a sampling rate into USB high speed format (fs/8000 in Q16.16) * this will overflow at approx 4 MHz */inline static unsigned get_usb_high_speed_rate(unsigned int rate){	return ((rate << 10) + 62) / 125;}/* convert our full speed USB rate into sampling rate in Hz */inline static unsigned get_full_speed_hz(unsigned int usb_rate){	return (usb_rate * 125 + (1 << 12)) >> 13;}/* convert our high speed USB rate into sampling rate in Hz */inline static unsigned get_high_speed_hz(unsigned int usb_rate){	return (usb_rate * 125 + (1 << 9)) >> 10;}/* * prepare urb for 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(snd_usb_substream_t *subs,				    snd_pcm_runtime_t *runtime,				    struct urb *urb){	unsigned char *cp = urb->transfer_buffer;	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;	int i, offs;	urb->number_of_packets = ctx->packets;	urb->dev = ctx->subs->dev; /* we need to set this at each time */	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {		urb->iso_frame_desc[i].length = 3;		urb->iso_frame_desc[i].offset = offs;		cp[0] = subs->freqn >> 2;		cp[1] = subs->freqn >> 10;		cp[2] = subs->freqn >> 18;	}	return 0;}/* * prepare urb for high speed capture sync pipe * * fill the length and offset of each urb descriptor. * the fixed 12.13 frequency is passed as 16.16 through the pipe. */static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs,				       snd_pcm_runtime_t *runtime,				       struct urb *urb){	unsigned char *cp = urb->transfer_buffer;	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;	int i, offs;	urb->number_of_packets = ctx->packets;	urb->dev = ctx->subs->dev; /* we need to set this at each time */	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {		urb->iso_frame_desc[i].length = 4;		urb->iso_frame_desc[i].offset = offs;		cp[0] = subs->freqn;		cp[1] = subs->freqn >> 8;		cp[2] = subs->freqn >> 16;		cp[3] = subs->freqn >> 24;	}	return 0;}/* * process after capture sync complete * - nothing to do */static int retire_capture_sync_urb(snd_usb_substream_t *subs,				   snd_pcm_runtime_t *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(snd_usb_substream_t *subs,			       snd_pcm_runtime_t *runtime,			       struct urb *urb){	int i, offs;	unsigned long flags;	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)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;#if 0 // for check	if (! urb->bandwidth) {		int bustime;		bustime = usb_check_bandwidth(urb->dev, urb);		if (bustime < 0)			return bustime;		printk("urb %d: bandwidth = %d (packets = %d)\n", ctx->index, bustime, urb->number_of_packets);		usb_claim_bandwidth(urb->dev, urb, bustime, 1);	}#endif // for check	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(snd_usb_substream_t *subs,			      snd_pcm_runtime_t *runtime,			      struct urb *urb){	unsigned long flags;	unsigned char *cp;	int i;	unsigned int stride, len, oldptr;	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;		}		len = urb->iso_frame_desc[i].actual_length / stride;		if (! len)			continue;		/* update the current pointer */		spin_lock_irqsave(&subs->lock, flags);		oldptr = subs->hwptr_done;		subs->hwptr_done += len;		if (subs->hwptr_done >= runtime->buffer_size)			subs->hwptr_done -= runtime->buffer_size;		subs->transfer_done += len;		spin_unlock_irqrestore(&subs->lock, flags);		/* copy a data chunk */		if (oldptr + len > runtime->buffer_size) {			unsigned int cnt = runtime->buffer_size - oldptr;			unsigned int blen = cnt * stride;			memcpy(runtime->dma_area + oldptr * stride, cp, blen);			memcpy(runtime->dma_area, cp + blen, len * stride - blen);		} 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);	}	return 0;}/* * prepare urb for full speed playback sync pipe * * 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,				     struct urb *urb){	int i, offs;	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;	urb->number_of_packets = ctx->packets;	urb->dev = ctx->subs->dev; /* we need to set this at each time */	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {		urb->iso_frame_desc[i].length = 3;		urb->iso_frame_desc[i].offset = offs;	}	return 0;}/* * prepare urb for high speed playback sync pipe * * set up the offset and length to receive the current frequency. */static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs,					snd_pcm_runtime_t *runtime,					struct urb *urb){	int i, offs;	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;	urb->number_of_packets = ctx->packets;	urb->dev = ctx->subs->dev; /* we need to set this at each time */	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {		urb->iso_frame_desc[i].length = 4;		urb->iso_frame_desc[i].offset = offs;	}	return 0;}/* * process after full speed playback sync complete * * retrieve the current 10.14 frequency from pipe, and set it.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?