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

📄 ali5451.c

📁 linux 内核源代码
💻 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 <linux/dma-mapping.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;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(KERN_DEBUG 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 2struct snd_ali;struct snd_ali_voice;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;};struct snd_ali_voice {	unsigned int number;	unsigned int use :1,		pcm :1,		midi :1,		mode :1,		synth :1,		running :1;	/* PCM data */	struct snd_ali *codec;	struct snd_pcm_substream *substream;	struct snd_ali_voice *extra;		int eso;                /* final ESO value for channel */	int count;              /* runtime->period_size */	/* --- */	void *private_data;	void (*private_free)(void *private_data);};struct snd_alidev {	struct snd_ali_voice voices[ALI_CHANNELS];		unsigned int	chcnt;			/* num of opened channels */	unsigned int	chmap;			/* bitmap for opened channels */	unsigned int synthcount;};#define ALI_GLOBAL_REGS		56#define ALI_CHANNEL_REGS	8struct snd_ali_image {	u32 regs[ALI_GLOBAL_REGS];	u32 channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];};struct snd_ali {	int		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;	struct snd_card	*card;	struct snd_pcm	*pcm[MAX_CODECS];	struct snd_alidev	synth;	struct snd_ali_channel_control chregs;	/* S/PDIF Mask */	unsigned int	spdif_mask;	unsigned int spurious_irq_count;	unsigned int spurious_irq_max_delta;	unsigned int num_of_codecs;	struct snd_ac97_bus *ac97_bus;	struct snd_ac97 *ac97[MAX_CODECS];	unsigned short	ac97_ext_id;	unsigned short	ac97_ext_status;	spinlock_t	reg_lock;	spinlock_t	voice_alloc;#ifdef CONFIG_PM	struct snd_ali_image *image;#endif};static struct pci_device_id snd_ali_ids[] = {	{PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0},	{0, }};MODULE_DEVICE_TABLE(pci, snd_ali_ids);static void snd_ali_clear_voices(struct snd_ali *, unsigned int, unsigned int);static unsigned short snd_ali_codec_peek(struct snd_ali *, int, unsigned short);static void snd_ali_codec_poke(struct snd_ali *, int, unsigned short,			       unsigned short);/* *  AC97 ACCESS */static inline unsigned int snd_ali_5451_peek(struct snd_ali *codec,					     unsigned int port){	return (unsigned int)inl(ALI_REG(codec, port)); }static inline void snd_ali_5451_poke(struct snd_ali *codec,				     unsigned int port,				     unsigned int val){	outl((unsigned int)val, ALI_REG(codec, port));}static int snd_ali_codec_ready(struct snd_ali *codec,			       unsigned int port){	unsigned long end_time;	unsigned int res;		end_time = jiffies + msecs_to_jiffies(250);	do {		res = snd_ali_5451_peek(codec,port);		if (!(res & 0x8000))			return 0;		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(struct snd_ali *codec){	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 + msecs_to_jiffies(250);	do {		dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);		if (dwChk2 != dwChk1)			return 0;		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(struct snd_ali *codec,int secondary,			       unsigned short reg,			       unsigned short val){	unsigned int dwVal;	unsigned int port;	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)		return;	if (snd_ali_stimer_ready(codec) < 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(struct snd_ali *codec,					 int secondary,					 unsigned short reg){	unsigned int dwVal;	unsigned int port;	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)		return ~0;	if (snd_ali_stimer_ready(codec) < 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)		return ~0;	if (snd_ali_codec_ready(codec, port) < 0)		return ~0;		return (snd_ali_5451_peek(codec, port) & 0xffff0000) >> 16;}static void snd_ali_codec_write(struct snd_ac97 *ac97,				unsigned short reg,				unsigned short val ){	struct snd_ali *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(struct snd_ac97 *ac97,					 unsigned short reg){	struct snd_ali *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(struct snd_ali *codec){	struct pci_dev *pci_dev;	unsigned short wCount, wReg;	unsigned int   dwVal;		pci_dev = codec->pci_m1533;	if (pci_dev) {		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(struct snd_ali *codec){	struct pci_dev *pci_dev;	unsigned char bVal;	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(struct snd_ali *codec,					   unsigned int channel){	unsigned long dwVal;	dwVal  = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));	dwVal |= 1 << (channel & 0x0000001f);	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));}static void snd_ali_disable_special_channel(struct snd_ali *codec,					    unsigned int channel){	unsigned long dwVal;	dwVal  = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL));	dwVal &= ~(1 << (channel & 0x0000001f));	outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL));}static void snd_ali_enable_address_interrupt(struct snd_ali *codec){	unsigned int gc;	gc  = inl(ALI_REG(codec, ALI_GC_CIR));	gc |= ENDLP_IE;	gc |= MIDLP_IE;	outl( gc, ALI_REG(codec, ALI_GC_CIR));}static void snd_ali_disable_address_interrupt(struct snd_ali *codec){	unsigned int gc;	gc  = inl(ALI_REG(codec, ALI_GC_CIR));	gc &= ~ENDLP_IE;	gc &= ~MIDLP_IE;	outl(gc, ALI_REG(codec, ALI_GC_CIR));}#if 0 /* not used */static void snd_ali_enable_voice_irq(struct snd_ali *codec,				     unsigned int channel){	unsigned int mask;	struct snd_ali_channel_control *pchregs = &(codec->chregs);	snd_ali_printk("enable_voice_irq channel=%d\n",channel);		mask = 1 << (channel & 0x1f);	pchregs->data.ainten  = inl(ALI_REG(codec, pchregs->regs.ainten));	pchregs->data.ainten |= mask;	outl(pchregs->data.ainten, ALI_REG(codec, pchregs->regs.ainten));}#endifstatic void snd_ali_disable_voice_irq(struct snd_ali *codec,				      unsigned int channel){	unsigned int mask;	struct snd_ali_channel_control *pchregs = &(codec->chregs);	snd_ali_printk("disable_voice_irq channel=%d\n",channel);	mask = 1 << (channel & 0x1f);	pchregs->data.ainten  = inl(ALI_REG(codec, pchregs->regs.ainten));	pchregs->data.ainten &= ~mask;	outl(pchregs->data.ainten, ALI_REG(codec, pchregs->regs.ainten));}static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel){	unsigned int idx =  channel & 0x1f;	if (codec->synth.chcnt >= ALI_CHANNELS){		snd_printk(KERN_ERR			   "ali_alloc_pcm_channel: no free channels.\n");		return -1;

⌨️ 快捷键说明

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