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

📄 ali5455.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	ALI  ali5455 and friends ICH driver for Linux *	LEI HU <Lei_Hu@ali.com.tw> * *  Built from: *	drivers/sound/i810_audio * *  	The ALi 5455 is similar but not quite identical to the Intel ICH *	series of controllers. Its easier to keep the driver separated from *	the i810 driver. * *	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. * * *	ALi 5455 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. * *	If you need to force a specific rate set the clocking= option * */#include <linux/module.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/interrupt.h>#include <asm/uaccess.h>#ifndef PCI_DEVICE_ID_ALI_5455#define PCI_DEVICE_ID_ALI_5455	0x5455#endif#ifndef PCI_VENDOR_ID_ALI#define PCI_VENDOR_ID_ALI	0x10b9#endifstatic int strict_clocking = 0;static unsigned int clocking = 0;static unsigned int codec_pcmout_share_spdif_locked = 0;static unsigned int codec_independent_spdif_locked = 0;static unsigned int controller_pcmout_share_spdif_locked = 0;static unsigned int controller_independent_spdif_locked = 0;static unsigned int globel = 0;#define ADC_RUNNING	1#define DAC_RUNNING	2#define CODEC_SPDIFOUT_RUNNING 8#define CONTROLLER_SPDIFOUT_RUNNING 4#define SPDIF_ENABLE_OUTPUT	4	/* bits 0,1 are PCM */#define ALI5455_FMT_16BIT	1#define ALI5455_FMT_STEREO	2#define ALI5455_FMT_MASK	3#define SPDIF_ON	0x0004#define SURR_ON		0x0010#define CENTER_LFE_ON	0x0020#define VOL_MUTED	0x8000#define ALI_SPDIF_OUT_CH_STATUS 0xbf/* 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 ali channel */#define SG_LEN 32struct ali_channel {	/* these sg guys should probably be allocated	   separately 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 separate 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##_CR =	0x##DIG##b		/* Control Register */				\}ENUM_ENGINE(OFF, 0);		/* Offsets */ENUM_ENGINE(PI, 4);		/* PCM In */ENUM_ENGINE(PO, 5);		/* PCM Out */ENUM_ENGINE(MC, 6);		/* Mic In */ENUM_ENGINE(CODECSPDIFOUT, 7);	/* CODEC SPDIF OUT  */ENUM_ENGINE(CONTROLLERSPDIFIN, A);	/* CONTROLLER SPDIF In */ENUM_ENGINE(CONTROLLERSPDIFOUT, B);	/* CONTROLLER SPDIF OUT */enum {	ALI_SCR = 0x00,		/* System Control Register */	ALI_SSR = 0x04,		/* System Status Register  */	ALI_DMACR = 0x08,	/* DMA Control Register    */	ALI_FIFOCR1 = 0x0c,	/* FIFO Control Register 1  */	ALI_INTERFACECR = 0x10,	/* Interface Control Register */	ALI_INTERRUPTCR = 0x14,	/* Interrupt control Register */	ALI_INTERRUPTSR = 0x18,	/* Interrupt  Status Register */	ALI_FIFOCR2 = 0x1c,	/* FIFO Control Register 2   */	ALI_CPR = 0x20,		/* Command Port Register     */	ALI_SPR = 0x24,		/* Status Port Register      */	ALI_FIFOCR3 = 0x2c,	/* FIFO Control Register 3  */	ALI_TTSR = 0x30,	/* Transmit Tag Slot Register */	ALI_RTSR = 0x34,	/* Receive Tag Slot  Register */	ALI_CSPSR = 0x38,	/* Command/Status Port Status Register */	ALI_CAS = 0x3c,		/* Codec Write Semaphore Register */	ALI_SPDIFCSR = 0xf8,	/* spdif channel status register  */	ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */};// x-status register(x:pcm in ,pcm out, mic in,)/* 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) */	//not eqult intel#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)/* interrupts for the whole chip */// by interrupt status register finish#define INT_SPDIFOUT   (1<<23)	/* controller spdif out INTERRUPT */#define INT_SPDIFIN   (1<<22)#define INT_CODECSPDIFOUT   (1<<19)#define INT_MICIN   (1<<18)#define INT_PCMOUT   (1<<17)#define INT_PCMIN   (1<<16)#define INT_CPRAIS   (1<<7)#define INT_SPRAIS   (1<<5)#define INT_GPIO    (1<<1)#define INT_MASK   (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)#define DRIVER_VERSION "0.02ac"/* magic numbers to protect our data structures */#define ALI5455_CARD_MAGIC		0x5072696E	/* "Prin" */#define ALI5455_STATE_MAGIC		0x63657373	/* "cess" */#define ALI5455_DMA_MASK		0xffffffff	/* DMA buffer mask for pci_alloc_consist */#define NR_HW_CH			5	//I think 5 channel/* 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 };#define ALI5455static char *card_names[] = {	"ALI 5455"};static struct pci_device_id ali_pci_tbl[] = {	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},	{0,}};MODULE_DEVICE_TABLE(pci, ali_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 ali_state {	unsigned int magic;	struct ali_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 ali_channel *read_channel;		struct ali_channel *write_channel;		struct ali_channel *codec_spdifout_channel;		struct ali_channel *controller_spdifout_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 ali_card {	struct ali_channel channel[5];	unsigned int magic;	/* We keep ali5455 cards in a linked list */	struct ali_card *next;	/* The ali has a certain amount of cross channel interaction	   so we use a single per card lock */	spinlock_t lock;	spinlock_t ac97_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 ali_state *states[NR_HW_CH];	u16 ac97_features;	u16 ac97_status;	u16 channels;	/* hardware resources */	unsigned long iobase;	u32 irq;	/* Function support */	struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);	struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);	struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);	struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);	struct ali_channel *(*alloc_controller_spdifout_channel) (struct  ali_card *);	void (*free_pcm_channel) (struct ali_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 ali_card *devs = NULL;static int ali_open_mixdev(struct inode *inode, struct file *file);static int ali_ioctl_mixdev(struct inode *inode, struct file *file,			    unsigned int cmd, unsigned long arg);static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card){	if (card->channel[1].used == 1)		return NULL;	card->channel[1].used = 1;	return &card->channel[1];}static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card){	if (card->channel[0].used == 1)		return NULL;	card->channel[0].used = 1;	return &card->channel[0];}static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card){	if (card->channel[2].used == 1)		return NULL;	card->channel[2].used = 1;	return &card->channel[2];}static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card){	if (card->channel[3].used == 1)		return NULL;	card->channel[3].used = 1;	return &card->channel[3];}static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card){	if (card->channel[4].used == 1)		return NULL;	card->channel[4].used = 1;	return &card->channel[4];}static void ali_free_pcm_channel(struct ali_card *card, int channel){	card->channel[channel].used = 0;}//add support  codec spdif out static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate){	unsigned long id = 0L;	id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);	id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;	switch (id) {	case 0x41445361:	/* AD1886 */		if (rate == 48000) {			return 1;		}		break;	case 0x414c4720:	/* ALC650 */		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);}/* ali_set_spdif_output *  *  Configure the S/PDIF output transmitter. When we turn on *  S/PDIF, we turn off the analog output. This may not be *  the right thing to do. * *  Assumptions: *     The DSP sample rate must already be set to a supported *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort. */

⌨️ 快捷键说明

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