📄 ali5451.c
字号:
/* * 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_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;static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 32};static int spdif[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for ALI M5451 PCI Audio.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable ALI 5451 PCI Audio.");module_param_array(pcm_channels, int, NULL, 0444);MODULE_PARM_DESC(pcm_channels, "PCM Channels");module_param_array(spdif, bool, NULL, 0444);MODULE_PARM_DESC(spdif, "Support SPDIF I/O");/* * 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 */#ifndef PCI_VENDOR_ID_ALI#define PCI_VENDOR_ID_ALI 0x10b9#endif#ifndef PCI_DEVICE_ID_ALI_5451#define PCI_DEVICE_ID_ALI_5451 0x5451#endif#define DEVICE_ID_ALI5451 ((PCI_VENDOR_ID_ALI<<16)|PCI_DEVICE_ID_ALI_5451)#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 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_AC97_GPIO 0x4c#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 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)typedef 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; 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; 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; 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; ac97_bus_t *ac97_bus; ac97_t *ac97; 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 = NULL; int i,j; pci_dev = pci_find_device(vendor, deviceid, pci_dev); 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"); } }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 * (HZ >> 2); do { res = snd_ali_5451_peek(codec,port); if (! (res & 0x8000)) return 0; if (sched) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(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 * (HZ >> 2); do { dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER); if (dwChk2 != dwChk1) return 0; if (sched) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } } while (time_after_eq(end_time, jiffies)); snd_printk("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("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("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); snd_ali_codec_poke(codec, 0, 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, 0, 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -