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

📄 ali5451.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  Matt Wu <Matt_Wu@acersoftech.com.cn> *  Apr 26, 2001 *  Routines for control of ALi pci audio M5451 * *  BUGS: *    -- * *  TODO: *    -- * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public Lcodecnse as published by *   the Free Software Foundation; either version 2 of the Lcodecnse, 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 Lcodecnse for more details. * *   You should have received a copy of the GNU General Public Lcodecnse *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#include <sound/driver.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/info.h>#include <sound/ac97_codec.h>#include <sound/mpu401.h>#include <sound/initval.h>MODULE_AUTHOR("Matt Wu <Matt_Wu@acersoftech.com.cn>");MODULE_DESCRIPTION("ALI M5451");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}");static int index = SNDRV_DEFAULT_IDX1;	/* Index */static char *id = SNDRV_DEFAULT_STR1;	/* ID for this card */static int pcm_channels = 32;static int spdif = 0;module_param(index, int, 0444);MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");module_param(id, charp, 0444);MODULE_PARM_DESC(id, "ID string for ALI M5451 PCI Audio.");module_param(pcm_channels, int, 0444);MODULE_PARM_DESC(pcm_channels, "PCM Channels");module_param(spdif, bool, 0444);MODULE_PARM_DESC(spdif, "Support SPDIF I/O");/* just for backward compatibility */static int enable;module_param(enable, bool, 0444);/* *  Debug part definitions *///#define ALI_DEBUG#ifdef ALI_DEBUG#define snd_ali_printk(format, args...) printk(format, ##args);#else#define snd_ali_printk(format, args...)#endif/* *  Constants definition */#define DEVICE_ID_ALI5451	((PCI_VENDOR_ID_AL<<16)|PCI_DEVICE_ID_AL_M5451)#define ALI_CHANNELS		32#define ALI_PCM_IN_CHANNEL	31#define ALI_SPDIF_IN_CHANNEL	19#define ALI_SPDIF_OUT_CHANNEL	15#define ALI_CENTER_CHANNEL	24#define ALI_LEF_CHANNEL		23#define ALI_SURR_LEFT_CHANNEL	26#define ALI_SURR_RIGHT_CHANNEL	25#define ALI_MODEM_IN_CHANNEL    21#define ALI_MODEM_OUT_CHANNEL   20#define	SNDRV_ALI_VOICE_TYPE_PCM	01#define SNDRV_ALI_VOICE_TYPE_OTH	02#define	ALI_5451_V02		0x02/* *  Direct Registers */#define ALI_LEGACY_DMAR0        0x00  // ADR0#define ALI_LEGACY_DMAR4        0x04  // CNT0#define ALI_LEGACY_DMAR11       0x0b  // MOD #define ALI_LEGACY_DMAR15       0x0f  // MMR #define ALI_MPUR0		0x20#define ALI_MPUR1		0x21#define ALI_MPUR2		0x22#define ALI_MPUR3		0x23#define	ALI_AC97_WRITE		0x40#define ALI_AC97_READ		0x44#define ALI_SCTRL		0x48#define   ALI_SPDIF_OUT_ENABLE		0x20#define   ALI_SCTRL_LINE_IN2		(1 << 9)#define   ALI_SCTRL_GPIO_IN2		(1 << 13)#define   ALI_SCTRL_LINE_OUT_EN 	(1 << 20)#define   ALI_SCTRL_GPIO_OUT_EN 	(1 << 23)#define   ALI_SCTRL_CODEC1_READY	(1 << 24)#define   ALI_SCTRL_CODEC2_READY	(1 << 25)#define ALI_AC97_GPIO		0x4c#define   ALI_AC97_GPIO_ENABLE		0x8000#define   ALI_AC97_GPIO_DATA_SHIFT	16#define ALI_SPDIF_CS		0x70#define ALI_SPDIF_CTRL		0x74#define   ALI_SPDIF_IN_FUNC_ENABLE	0x02#define   ALI_SPDIF_IN_CH_STATUS	0x40#define   ALI_SPDIF_OUT_CH_STATUS	0xbf#define ALI_START		0x80#define ALI_STOP		0x84#define ALI_CSPF		0x90#define ALI_AINT		0x98#define ALI_GC_CIR		0xa0	#define ENDLP_IE		0x00001000	#define MIDLP_IE		0x00002000#define ALI_AINTEN		0xa4#define ALI_VOLUME		0xa8#define ALI_SBDELTA_DELTA_R     0xac#define ALI_MISCINT		0xb0	#define ADDRESS_IRQ		0x00000020	#define TARGET_REACHED		0x00008000	#define MIXER_OVERFLOW		0x00000800	#define MIXER_UNDERFLOW		0x00000400	#define GPIO_IRQ		0x01000000#define ALI_SBBL_SBCL           0xc0#define ALI_SBCTRL_SBE2R_SBDD   0xc4#define ALI_STIMER		0xc8#define ALI_GLOBAL_CONTROL	0xd4#define   ALI_SPDIF_OUT_SEL_PCM		0x00000400 /* bit 10 */#define   ALI_SPDIF_IN_SUPPORT		0x00000800 /* bit 11 */#define   ALI_SPDIF_OUT_CH_ENABLE	0x00008000 /* bit 15 */#define   ALI_SPDIF_IN_CH_ENABLE	0x00080000 /* bit 19 */#define   ALI_PCM_IN_ENABLE		0x80000000 /* bit 31 */#define ALI_CSO_ALPHA_FMS	0xe0#define ALI_LBA			0xe4#define ALI_ESO_DELTA		0xe8#define ALI_GVSEL_PAN_VOC_CTRL_EC	0xf0#define ALI_EBUF1		0xf4#define ALI_EBUF2		0xf8#define ALI_REG(codec, x) ((codec)->port + x)#define MAX_CODECS 2typedef struct snd_stru_ali ali_t;typedef struct snd_ali_stru_voice snd_ali_voice_t;typedef struct snd_ali_channel_control {	// register data	struct REGDATA {		unsigned int start;		unsigned int stop;		unsigned int aint;		unsigned int ainten;	} data;			// register addresses	struct REGS {		unsigned int start;		unsigned int stop;		unsigned int aint;		unsigned int ainten;		unsigned int ac97read;		unsigned int ac97write;	} regs;} snd_ali_channel_control_t;struct snd_ali_stru_voice {	unsigned int number;	unsigned int use: 1,	    pcm: 1,	    midi: 1,	    mode: 1,	    synth: 1;	/* PCM data */	ali_t *codec;	snd_pcm_substream_t *substream;	snd_ali_voice_t *extra;		unsigned int running: 1;	int eso;                /* final ESO value for channel */	int count;              /* runtime->period_size */	/* --- */	void *private_data;	void (*private_free)(void *private_data);};typedef struct snd_stru_alidev {	snd_ali_voice_t voices[ALI_CHANNELS];		unsigned int	chcnt;			/* num of opened channels */	unsigned int	chmap;			/* bitmap for opened channels */	unsigned int synthcount;} alidev_t;#ifdef CONFIG_PM#define ALI_GLOBAL_REGS		56#define ALI_CHANNEL_REGS	8typedef struct snd_ali_image {	unsigned long regs[ALI_GLOBAL_REGS];	unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];} ali_image_t;#endifstruct snd_stru_ali {	unsigned long	irq;	unsigned long	port;	unsigned char	revision;	unsigned int hw_initialized: 1;	unsigned int spdif_support: 1;	struct pci_dev	*pci;	struct pci_dev	*pci_m1533;	struct pci_dev	*pci_m7101;	snd_card_t	*card;	snd_pcm_t	*pcm[MAX_CODECS];	alidev_t	synth;	snd_ali_channel_control_t chregs;	/* S/PDIF Mask */	unsigned int	spdif_mask;	unsigned int spurious_irq_count;	unsigned int spurious_irq_max_delta;	unsigned int num_of_codecs;	ac97_bus_t *ac97_bus;	ac97_t *ac97[MAX_CODECS];	unsigned short	ac97_ext_id;	unsigned short	ac97_ext_status;	spinlock_t	reg_lock;	spinlock_t	voice_alloc;#ifdef CONFIG_PM	ali_image_t *image;#endif};static struct pci_device_id snd_ali_ids[] = {	{0x10b9, 0x5451, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },	{0, }};MODULE_DEVICE_TABLE(pci, snd_ali_ids);static void snd_ali_clear_voices(ali_t *, unsigned int, unsigned int);static unsigned short snd_ali_codec_peek(ali_t *, int, unsigned short);static void snd_ali_codec_poke(ali_t *, int, unsigned short, unsigned short);/* *  Debug Part */#ifdef ALI_DEBUGstatic void ali_read_regs(ali_t *codec, int channel){	int i,j;	unsigned int dwVal;	printk("channel %d registers map:\n", channel);	outb((unsigned char)(channel & 0x001f), ALI_REG(codec,ALI_GC_CIR));	printk("    ");	for(j=0;j<8;j++)		printk("%2.2x       ", j*4);	printk("\n");	for (i=0; i<=0xf8/4;i++) {		if(i%8 == 0)			printk("%2.2x  ", (i*4/0x10)*0x10);		dwVal = inl(ALI_REG(codec,i*4));		printk("%8.8x ", dwVal);		if ((i+1)%8 == 0)			printk("\n");	}	printk("\n");}static void ali_read_cfg(unsigned int vendor, unsigned deviceid){	unsigned int dwVal;	struct pci_dev *pci_dev;	int i,j;	pci_dev = pci_get_device(vendor, deviceid, NULL);	if (pci_dev == NULL)		return ;	printk("\nM%x PCI CFG\n", deviceid);	printk("    ");	for(j=0;j<8;j++)		printk("%d        ",j);	printk("\n");	for(i=0;i<8;i++) {		printk("%d   ",i);		for(j=0;j<8;j++)		{			pci_read_config_dword(pci_dev, i*0x20+j*4, &dwVal);			printk("%8.8x ", dwVal);		}		printk("\n");	}	pci_dev_put(pci_dev); }static void ali_read_ac97regs(ali_t *codec, int secondary){	unsigned short i,j;	unsigned short wVal;	printk("\ncodec %d registers map:\n", secondary);	printk("    ");	for(j=0;j<8;j++)		printk("%2.2x   ",j*2);	printk("\n");	for (i=0; i<64;i++) {		if(i%8 == 0)			printk("%2.2x  ", (i/8)*0x10);		wVal = snd_ali_codec_peek(codec, secondary, i*2);		printk("%4.4x ", wVal);		if ((i+1)%8 == 0)			printk("\n");	}	printk("\n");}#endif/* *  AC97 ACCESS */static inline unsigned int snd_ali_5451_peek(ali_t *codec,						unsigned int port ){	return (unsigned int)inl(ALI_REG(codec, port)); }static inline void snd_ali_5451_poke(	ali_t *codec,					unsigned int port,					unsigned int val ){	outl((unsigned int)val, ALI_REG(codec, port));}static int snd_ali_codec_ready(	ali_t *codec,				unsigned int port,				int sched ){	unsigned long end_time;	unsigned int res;		end_time = jiffies + 10 * msecs_to_jiffies(250);	do {		res = snd_ali_5451_peek(codec,port);		if (! (res & 0x8000))			return 0;		if (sched)			schedule_timeout_uninterruptible(1);	} while (time_after_eq(end_time, jiffies));	snd_ali_5451_poke(codec, port, res & ~0x8000);	snd_printdd("ali_codec_ready: codec is not ready.\n ");	return -EIO;}static int snd_ali_stimer_ready(ali_t *codec, int sched){	unsigned long end_time;	unsigned long dwChk1,dwChk2;		dwChk1 = snd_ali_5451_peek(codec, ALI_STIMER);	dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);	end_time = jiffies + 10 * msecs_to_jiffies(250);	do {		dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);		if (dwChk2 != dwChk1)			return 0;		if (sched)			schedule_timeout_uninterruptible(1);	} while (time_after_eq(end_time, jiffies));	snd_printk(KERN_ERR "ali_stimer_read: stimer is not ready.\n");	return -EIO;}static void snd_ali_codec_poke(ali_t *codec,int secondary,				     unsigned short reg,				     unsigned short val){	unsigned int dwVal = 0;	unsigned int port = 0;	if (reg >= 0x80) {		snd_printk(KERN_ERR "ali_codec_poke: reg(%xh) invalid.\n", reg);		return;	}	port = codec->chregs.regs.ac97write;	if (snd_ali_codec_ready(codec, port, 0) < 0)		return;	if (snd_ali_stimer_ready(codec, 0) < 0)		return;	dwVal  = (unsigned int) (reg & 0xff);	dwVal |= 0x8000 | (val << 16);	if (secondary) dwVal |= 0x0080;	if (codec->revision == ALI_5451_V02) dwVal |= 0x0100;	snd_ali_5451_poke(codec,port,dwVal);	return ;}static unsigned short snd_ali_codec_peek( ali_t *codec,					  int secondary,					  unsigned short reg){	unsigned int dwVal = 0;	unsigned int port = 0;	if (reg >= 0x80) {		snd_printk(KERN_ERR "ali_codec_peek: reg(%xh) invalid.\n", reg);		return ~0;	}	port = codec->chregs.regs.ac97read;	if (snd_ali_codec_ready(codec, port, 0) < 0)		return ~0;	if (snd_ali_stimer_ready(codec, 0) < 0)		return ~0;	dwVal  = (unsigned int) (reg & 0xff);	dwVal |= 0x8000;				/* bit 15*/	if (secondary) dwVal |= 0x0080;	snd_ali_5451_poke(codec, port, dwVal);	if (snd_ali_stimer_ready(codec, 0) < 0)		return ~0;	if (snd_ali_codec_ready(codec, port, 0) < 0)		return ~0;		return (snd_ali_5451_peek(codec, port) & 0xffff0000)>>16;}static void snd_ali_codec_write(ac97_t *ac97,				unsigned short reg,				unsigned short val ){	ali_t *codec = ac97->private_data;	snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val);	if(reg == AC97_GPIO_STATUS) {		outl((val << ALI_AC97_GPIO_DATA_SHIFT)|ALI_AC97_GPIO_ENABLE,			ALI_REG(codec, ALI_AC97_GPIO));		return;	}	snd_ali_codec_poke(codec, ac97->num, reg, val);	return ;}static unsigned short snd_ali_codec_read(ac97_t *ac97, unsigned short reg){	ali_t *codec = ac97->private_data;	snd_ali_printk("codec_read reg=%xh.\n", reg);	return (snd_ali_codec_peek(codec, ac97->num, reg));}/* *	AC97 Reset */static int snd_ali_reset_5451(ali_t *codec){	struct pci_dev *pci_dev = NULL;	unsigned short wCount, wReg;	unsigned int   dwVal;		if ((pci_dev = codec->pci_m1533) != NULL) {		pci_read_config_dword(pci_dev, 0x7c, &dwVal);		pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000);		udelay(5000);		pci_read_config_dword(pci_dev, 0x7c, &dwVal);		pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);		udelay(5000);	}		pci_dev = codec->pci;	pci_read_config_dword(pci_dev, 0x44, &dwVal);	pci_write_config_dword(pci_dev, 0x44, dwVal | 0x000c0000);	udelay(500);	pci_read_config_dword(pci_dev, 0x44, &dwVal);	pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff);	udelay(5000);		wCount = 200;	while(wCount--) {		wReg = snd_ali_codec_peek(codec, 0, AC97_POWERDOWN);		if((wReg & 0x000f) == 0x000f)			return 0;		udelay(5000);	}	/* non-fatal if you have a non PM capable codec */	/* snd_printk(KERN_WARNING "ali5451: reset time out\n"); */	return 0;}#ifdef CODEC_RESETstatic int snd_ali_reset_codec(ali_t *codec){	struct pci_dev *pci_dev = NULL;	unsigned char bVal = 0;	unsigned int   dwVal;	unsigned short wCount, wReg;	pci_dev = codec->pci_m1533;		pci_read_config_dword(pci_dev, 0x7c, &dwVal);	pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000);	udelay(5000);	pci_read_config_dword(pci_dev, 0x7c, &dwVal);	pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);	udelay(5000);	bVal = inb(ALI_REG(codec,ALI_SCTRL));	bVal |= 0x02;	outb(ALI_REG(codec,ALI_SCTRL),bVal);	udelay(5000);	bVal = inb(ALI_REG(codec,ALI_SCTRL));	bVal &= 0xfd;	outb(ALI_REG(codec,ALI_SCTRL),bVal);	udelay(15000);	wCount = 200;	while(wCount--) {		wReg = snd_ali_codec_read(codec->ac97, AC97_POWERDOWN);		if((wReg & 0x000f) == 0x000f)			return 0;		udelay(5000);	}	return -1;}#endif/* *  ALI 5451 Controller */static void snd_ali_enable_special_channel(ali_t *codec, unsigned int channel){	unsigned long dwVal = 0;	dwVal  = inl(ALI_REG(codec,ALI_GLOBAL_CONTROL));	dwVal |= 1 << (channel & 0x0000001f);	outl(dwVal, ALI_REG(codec,ALI_GLOBAL_CONTROL));}

⌨️ 快捷键说明

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