⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i810_audio.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Intel i810 and friends ICH driver for Linux *	Alan Cox <alan@redhat.com> * *  Built from: *	Low level code:  Zach Brown (original nonworking i810 OSS driver) *			 Jaroslav Kysela <perex@suse.cz> (working ALSA driver) * *	Framework: Thomas Sailer <sailer@ife.ee.ethz.ch> *	Extended by: Zach Brown <zab@redhat.com>   *			and others.. * *  Hardware Provided By: *	Analog Devices (A major AC97 codec maker) *	Intel Corp  (you've probably heard of them already) * *  AC97 clues and assistance provided by *	Analog Devices *	Zach 'Fufu' Brown *	Jeff Garzik * *	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., 675 Mass Ave, Cambridge, MA 02139, USA. * * *	Intel 810 theory of operation * *	The chipset provides three DMA channels that talk to an AC97 *	CODEC (AC97 is a digital/analog mixer standard). At its simplest *	you get 48Khz audio with basic volume and mixer controls. At the *	best you get rate adaption in the codec. We set the card up so *	that we never take completion interrupts but instead keep the card *	chasing its tail around a ring buffer. This is needed for mmap *	mode audio and happens to work rather well for non-mmap modes too. * *	The board has one output channel for PCM audio (supported) and *	a stereo line in and mono microphone input. Again these are normally *	locked to 48Khz only. Right now recording is not finished. * *	There is no midi support, no synth support. Use timidity. To get *	esd working you need to use esd -r 48000 as it won't probe 48KHz *	by default. mpg123 can't handle 48Khz only audio so use xmms. * *	Fix The Sound On Dell * *	Not everyone uses 48KHz. We know of no way to detect this reliably *	and certainly not to get the right data. If your i810 audio sounds *	stupid you may need to investigate other speeds. According to Analog *	they tend to use a 14.318MHz clock which gives you a base rate of *	41194Hz. * *	This is available via the 'ftsodell=1' option.  * *	If you need to force a specific rate set the clocking= option * *	This driver is cursed. (Ben LaHaise) */ #include <linux/module.h>#include <linux/version.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/sound.h>#include <linux/slab.h>#include <linux/soundcard.h>#include <linux/pci.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/ac97_codec.h>#include <linux/wrapper.h>#include <asm/uaccess.h>#include <asm/hardirq.h>#ifndef PCI_DEVICE_ID_INTEL_82801#define PCI_DEVICE_ID_INTEL_82801	0x2415#endif#ifndef PCI_DEVICE_ID_INTEL_82901#define PCI_DEVICE_ID_INTEL_82901	0x2425#endif#ifndef PCI_DEVICE_ID_INTEL_ICH2#define PCI_DEVICE_ID_INTEL_ICH2	0x2445#endif#ifndef PCI_DEVICE_ID_INTEL_ICH3#define PCI_DEVICE_ID_INTEL_ICH3	0x2485#endif#ifndef PCI_DEVICE_ID_INTEL_440MX#define PCI_DEVICE_ID_INTEL_440MX	0x7195#endif#ifndef PCI_DEVICE_ID_SI_7012#define PCI_DEVICE_ID_SI_7012		0x7012#endif#ifndef PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO	0x01b1#endifstatic int ftsodell=0;static int strict_clocking=0;static unsigned int clocking=0;static int spdif_locked=0;//#define DEBUG//#define DEBUG2//#define DEBUG_INTERRUPTS//#define DEBUG_MMAP#define ADC_RUNNING	1#define DAC_RUNNING	2#define I810_FMT_16BIT	1#define I810_FMT_STEREO	2#define I810_FMT_MASK	3#define SPDIF_ON	0x0004#define SURR_ON		0x0010#define CENTER_LFE_ON	0x0020#define VOL_MUTED	0x8000/* the 810's array of pointers to data buffers */struct sg_item {#define BUSADDR_MASK	0xFFFFFFFE	u32 busaddr;	#define CON_IOC 	0x80000000 /* interrupt on completion */#define CON_BUFPAD	0x40000000 /* pad underrun with last sample, else 0 */#define CON_BUFLEN_MASK	0x0000ffff /* buffer length in samples */	u32 control;};/* an instance of the i810 channel */#define SG_LEN 32struct i810_channel {	/* these sg guys should probably be allocated	   seperately as nocache. Must be 8 byte aligned */	struct sg_item sg[SG_LEN];	/* 32*8 */	u32 offset;			/* 4 */	u32 port;			/* 4 */	u32 used;	u32 num;};/* * we have 3 seperate dma engines.  pcm in, pcm out, and mic. * each dma engine has controlling registers.  These goofy * names are from the datasheet, but make it easy to write * code while leafing through it. */#define ENUM_ENGINE(PRE,DIG) 									\enum {												\	PRE##_BDBAR =	0x##DIG##0,		/* Buffer Descriptor list Base Address */	\	PRE##_CIV =	0x##DIG##4,		/* Current Index Value */			\	PRE##_LVI =	0x##DIG##5,		/* Last Valid Index */				\	PRE##_SR =	0x##DIG##6,		/* Status Register */				\	PRE##_PICB =	0x##DIG##8,		/* Position In Current Buffer */		\	PRE##_PIV =	0x##DIG##a,		/* Prefetched Index Value */			\	PRE##_CR =	0x##DIG##b		/* Control Register */				\}ENUM_ENGINE(OFF,0);	/* Offsets */ENUM_ENGINE(PI,0);	/* PCM In */ENUM_ENGINE(PO,1);	/* PCM Out */ENUM_ENGINE(MC,2);	/* Mic In */enum {	GLOB_CNT =	0x2c,			/* Global Control */	GLOB_STA = 	0x30,			/* Global Status */	CAS	 = 	0x34			/* Codec Write Semaphore Register */};/* interrupts for a dma engine */#define DMA_INT_FIFO		(1<<4)  /* fifo under/over flow */#define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */#define DMA_INT_LVI		(1<<2)  /* last valid done */#define DMA_INT_CELV		(1<<1)  /* last valid is current */#define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)/* interrupts for the whole chip */#define INT_SEC		(1<<11)#define INT_PRI		(1<<10)#define INT_MC		(1<<7)#define INT_PO		(1<<6)#define INT_PI		(1<<5)#define INT_MO		(1<<2)#define INT_NI		(1<<1)#define INT_GPI		(1<<0)#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)#define DRIVER_VERSION "0.21"/* magic numbers to protect our data structures */#define I810_CARD_MAGIC		0x5072696E /* "Prin" */#define I810_STATE_MAGIC	0x63657373 /* "cess" */#define I810_DMA_MASK		0xffffffff /* DMA buffer mask for pci_alloc_consist */#define NR_HW_CH		3/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */#define NR_AC97		2/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit *//* stream at a minimum for this card to be happy */static const unsigned sample_size[] = { 1, 2, 2, 4 };/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift *//* values are one less than might be expected */static const unsigned sample_shift[] = { -1, 0, 0, 1 };enum {	ICH82801AA = 0,	ICH82901AB,	INTEL440MX,	INTELICH2,	INTELICH3,	SI7012,	NVIDIA_NFORCE};static char * card_names[] = {	"Intel ICH 82801AA",	"Intel ICH 82901AB",	"Intel 440MX",	"Intel ICH2",	"Intel ICH3",	"SiS 7012",	"NVIDIA nForce Audio"};static struct pci_device_id i810_pci_tbl [] __initdata = {	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82901,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB},	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX},	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH2,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2},	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH3,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3},	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012},	{PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},	{0,}};MODULE_DEVICE_TABLE (pci, i810_pci_tbl);#ifdef CONFIG_PM#define PM_SUSPENDED(card) (card->pm_suspended)#else#define PM_SUSPENDED(card) (0)#endif/* "software" or virtual channel, an instance of opened /dev/dsp */struct i810_state {	unsigned int magic;	struct i810_card *card;	/* Card info */	/* single open lock mechanism, only used for recording */	struct semaphore open_sem;	wait_queue_head_t open_wait;	/* file mode */	mode_t open_mode;	/* virtual channel number */	int virt;#ifdef CONFIG_PM	unsigned int pm_saved_dac_rate,pm_saved_adc_rate;#endif	struct dmabuf {		/* wave sample stuff */		unsigned int rate;		unsigned char fmt, enable, trigger;		/* hardware channel */		struct i810_channel *read_channel;		struct i810_channel *write_channel;		/* OSS buffer management stuff */		void *rawbuf;		dma_addr_t dma_handle;		unsigned buforder;		unsigned numfrag;		unsigned fragshift;		/* our buffer acts like a circular ring */		unsigned hwptr;		/* where dma last started, updated by update_ptr */		unsigned swptr;		/* where driver last clear/filled, updated by read/write */		int count;		/* bytes to be consumed or been generated by dma machine */		unsigned total_bytes;	/* total bytes dmaed by hardware */		unsigned error;		/* number of over/underruns */		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */		/* redundant, but makes calculations easier */		/* what the hardware uses */		unsigned dmasize;		unsigned fragsize;		unsigned fragsamples;		/* what we tell the user to expect */		unsigned userfrags;		unsigned userfragsize;		/* OSS stuff */		unsigned mapped:1;		unsigned ready:1;		unsigned update_flag;		unsigned ossfragsize;		unsigned ossmaxfrags;		unsigned subdivision;	} dmabuf;};struct i810_card {	struct i810_channel channel[3];	unsigned int magic;	/* We keep i810 cards in a linked list */	struct i810_card *next;	/* The i810 has a certain amount of cross channel interaction	   so we use a single per card lock */	spinlock_t lock;	/* PCI device stuff */	struct pci_dev * pci_dev;	u16 pci_id;#ifdef CONFIG_PM		u16 pm_suspended;	u32 pm_save_state[64/sizeof(u32)];	int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];#endif	/* soundcore stuff */	int dev_audio;	/* structures for abstraction of hardware facilities, codecs, banks and channels*/	struct ac97_codec *ac97_codec[NR_AC97];	struct i810_state *states[NR_HW_CH];	u16 ac97_features;	u16 ac97_status;	u16 channels;		/* hardware resources */	unsigned long iobase;	unsigned long ac97base;	u32 irq;		/* Function support */	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);	struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);	struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);	void (*free_pcm_channel)(struct i810_card *, int chan);	/* We have a *very* long init time possibly, so use this to block */	/* attempts to open our devices before we are ready (stops oops'es) */	int initializing;};static struct i810_card *devs = NULL;static int i810_open_mixdev(struct inode *inode, struct file *file);static int i810_ioctl_mixdev(struct inode *inode, struct file *file,			     unsigned int cmd, unsigned long arg);static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card){	if(card->channel[1].used==1)		return NULL;	card->channel[1].used=1;	return &card->channel[1];}static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card){	if(card->channel[0].used==1)		return NULL;	card->channel[0].used=1;	return &card->channel[0];}static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card){	if(card->channel[2].used==1)		return NULL;	card->channel[2].used=1;	return &card->channel[2];}static void i810_free_pcm_channel(struct i810_card *card, int channel){	card->channel[channel].used=0;}static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate ){	unsigned long id = 0L;	id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16);	id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;#ifdef DEBUG	printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id);#endif	switch ( id ) {		case 0x41445361: /* AD1886 */			if (rate == 48000) {				return 1;			}			break;		default: /* all other codecs, until we know otherwiae */			if (rate == 48000 || rate == 44100 || rate == 32000) {				return 1;			}			break;	}	return (0);}/* i810_set_spdif_output *  *  Configure the S/PDIF output transmitter. When we turn on

⌨️ 快捷键说明

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