intel8x0.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,234 行 · 第 1/5 页
C
2,234 行
/* * ALSA driver for Intel ICH (i8x0) chipsets * * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> * * * This code also contains alpha support for SiS 735 chipsets provided * by Mike Pieper <mptei@users.sourceforge.net>. We have no datasheet * for SiS735, so the code is not fully functional. * * * 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., 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/gameport.h>#include <linux/moduleparam.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/ac97_codec.h>#include <sound/info.h>#include <sound/mpu401.h>#include <sound/initval.h>/* for 440MX workaround */#include <asm/pgtable.h>#include <asm/cacheflush.h>MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{Intel,82901AB-ICH0}," "{Intel,82801BA-ICH2}," "{Intel,82801CA-ICH3}," "{Intel,82801DB-ICH4}," "{Intel,ICH5}," "{Intel,ICH6}," "{Intel,6300ESB}," "{Intel,MX440}," "{SiS,SI7012}," "{NVidia,nForce Audio}," "{NVidia,nForce2 Audio}," "{AMD,AMD768}," "{AMD,AMD8111}," "{ALI,M5455}}");#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))#define SUPPORT_JOYSTICK 1#endif#define SUPPORT_MIDI 1static 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; /* Enable this card */static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};static int ac97_quirk[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = AC97_TUNE_DEFAULT};static int buggy_irq[SNDRV_CARDS];#ifdef SUPPORT_JOYSTICKstatic int joystick[SNDRV_CARDS];#endif#ifdef SUPPORT_MIDIstatic int mpu_port[SNDRV_CARDS]; /* disabled */#endifstatic int boot_devs;module_param_array(index, int, boot_devs, 0444);MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");module_param_array(id, charp, boot_devs, 0444);MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard.");module_param_array(enable, bool, boot_devs, 0444);MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard.");module_param_array(ac97_clock, int, boot_devs, 0444);MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");module_param_array(ac97_quirk, int, boot_devs, 0444);MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");module_param_array(buggy_irq, bool, boot_devs, 0444);MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");#ifdef SUPPORT_JOYSTICKmodule_param_array(joystick, bool, boot_devs, 0444);MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard.");#endif#ifdef SUPPORT_MIDImodule_param_array(mpu_port, int, boot_devs, 0444);MODULE_PARM_DESC(mpu_port, "MPU401 port # for Intel i8x0 driver.");#endif/* * Direct registers */#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_82801BA#define PCI_DEVICE_ID_INTEL_82801BA 0x2445#endif#ifndef PCI_DEVICE_ID_INTEL_440MX#define PCI_DEVICE_ID_INTEL_440MX 0x7195#endif#ifndef PCI_DEVICE_ID_INTEL_ICH3#define PCI_DEVICE_ID_INTEL_ICH3 0x2485#endif#ifndef PCI_DEVICE_ID_INTEL_ICH4#define PCI_DEVICE_ID_INTEL_ICH4 0x24c5#endif#ifndef PCI_DEVICE_ID_INTEL_ICH5#define PCI_DEVICE_ID_INTEL_ICH5 0x24d5#endif#ifndef PCI_DEVICE_ID_INTEL_ESB_5#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6#endif#ifndef PCI_DEVICE_ID_INTEL_ICH6_3#define PCI_DEVICE_ID_INTEL_ICH6_3 0x266e#endif#ifndef PCI_DEVICE_ID_SI_7012#define PCI_DEVICE_ID_SI_7012 0x7012#endif#ifndef PCI_DEVICE_ID_NVIDIA_MCP_AUDIO#define PCI_DEVICE_ID_NVIDIA_MCP_AUDIO 0x01b1#endif#ifndef PCI_DEVICE_ID_NVIDIA_CK804_AUDIO#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059#endif#ifndef PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a#endif#ifndef PCI_DEVICE_ID_NVIDIA_CK8_AUDIO#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a#endif#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da#endif#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea#endifenum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE };#define ICHREG(x) ICH_REG_##x#define DEFINE_REGSET(name,base) \enum { \ ICH_REG_##name##_BDBAR = base + 0x0, /* dword - buffer descriptor list base address */ \ ICH_REG_##name##_CIV = base + 0x04, /* byte - current index value */ \ ICH_REG_##name##_LVI = base + 0x05, /* byte - last valid index */ \ ICH_REG_##name##_SR = base + 0x06, /* byte - status register */ \ ICH_REG_##name##_PICB = base + 0x08, /* word - position in current buffer */ \ ICH_REG_##name##_PIV = base + 0x0a, /* byte - prefetched index value */ \ ICH_REG_##name##_CR = base + 0x0b, /* byte - control register */ \};/* busmaster blocks */DEFINE_REGSET(OFF, 0); /* offset */DEFINE_REGSET(PI, 0x00); /* PCM in */DEFINE_REGSET(PO, 0x10); /* PCM out */DEFINE_REGSET(MC, 0x20); /* Mic in *//* ICH4 busmaster blocks */DEFINE_REGSET(MC2, 0x40); /* Mic in 2 */DEFINE_REGSET(PI2, 0x50); /* PCM in 2 */DEFINE_REGSET(SP, 0x60); /* SPDIF out *//* values for each busmaster block *//* LVI */#define ICH_REG_LVI_MASK 0x1f/* SR */#define ICH_FIFOE 0x10 /* FIFO error */#define ICH_BCIS 0x08 /* buffer completion interrupt status */#define ICH_LVBCI 0x04 /* last valid buffer completion interrupt */#define ICH_CELV 0x02 /* current equals last valid */#define ICH_DCH 0x01 /* DMA controller halted *//* PIV */#define ICH_REG_PIV_MASK 0x1f /* mask *//* CR */#define ICH_IOCE 0x10 /* interrupt on completion enable */#define ICH_FEIE 0x08 /* fifo error interrupt enable */#define ICH_LVBIE 0x04 /* last valid buffer interrupt enable */#define ICH_RESETREGS 0x02 /* reset busmaster registers */#define ICH_STARTBM 0x01 /* start busmaster operation *//* global block */#define ICH_REG_GLOB_CNT 0x2c /* dword - global control */#define ICH_PCM_SPDIF_MASK 0xc0000000 /* s/pdif pcm slot mask (ICH4) */#define ICH_PCM_SPDIF_NONE 0x00000000 /* reserved - undefined */#define ICH_PCM_SPDIF_78 0x40000000 /* s/pdif pcm on slots 7&8 */#define ICH_PCM_SPDIF_69 0x80000000 /* s/pdif pcm on slots 6&9 */#define ICH_PCM_SPDIF_1011 0xc0000000 /* s/pdif pcm on slots 10&11 */#define ICH_PCM_20BIT 0x00400000 /* 20-bit samples (ICH4) */#define ICH_PCM_246_MASK 0x00300000 /* 6 channels (not all chips) */#define ICH_PCM_6 0x00200000 /* 6 channels (not all chips) */#define ICH_PCM_4 0x00100000 /* 4 channels (not all chips) */#define ICH_PCM_2 0x00000000 /* 2 channels (stereo) */#define ICH_SIS_PCM_246_MASK 0x000000c0 /* 6 channels (SIS7012) */#define ICH_SIS_PCM_6 0x00000080 /* 6 channels (SIS7012) */#define ICH_SIS_PCM_4 0x00000040 /* 4 channels (SIS7012) */#define ICH_SIS_PCM_2 0x00000000 /* 2 channels (SIS7012) */#define ICH_TRIE 0x00000040 /* tertiary resume interrupt enable */#define ICH_SRIE 0x00000020 /* secondary resume interrupt enable */#define ICH_PRIE 0x00000010 /* primary resume interrupt enable */#define ICH_ACLINK 0x00000008 /* AClink shut off */#define ICH_AC97WARM 0x00000004 /* AC'97 warm reset */#define ICH_AC97COLD 0x00000002 /* AC'97 cold reset */#define ICH_GIE 0x00000001 /* GPI interrupt enable */#define ICH_REG_GLOB_STA 0x30 /* dword - global status */#define ICH_TRI 0x20000000 /* ICH4: tertiary (AC_SDIN2) resume interrupt */#define ICH_TCR 0x10000000 /* ICH4: tertiary (AC_SDIN2) codec ready */#define ICH_BCS 0x08000000 /* ICH4: bit clock stopped */#define ICH_SPINT 0x04000000 /* ICH4: S/PDIF interrupt */#define ICH_P2INT 0x02000000 /* ICH4: PCM2-In interrupt */#define ICH_M2INT 0x01000000 /* ICH4: Mic2-In interrupt */#define ICH_SAMPLE_CAP 0x00c00000 /* ICH4: sample capability bits (RO) */#define ICH_SAMPLE_16_20 0x00400000 /* ICH4: 16- and 20-bit samples */#define ICH_MULTICHAN_CAP 0x00300000 /* ICH4: multi-channel capability bits (RO) */#define ICH_MD3 0x00020000 /* modem power down semaphore */#define ICH_AD3 0x00010000 /* audio power down semaphore */#define ICH_RCS 0x00008000 /* read completion status */#define ICH_BIT3 0x00004000 /* bit 3 slot 12 */#define ICH_BIT2 0x00002000 /* bit 2 slot 12 */#define ICH_BIT1 0x00001000 /* bit 1 slot 12 */#define ICH_SRI 0x00000800 /* secondary (AC_SDIN1) resume interrupt */#define ICH_PRI 0x00000400 /* primary (AC_SDIN0) resume interrupt */#define ICH_SCR 0x00000200 /* secondary (AC_SDIN1) codec ready */#define ICH_PCR 0x00000100 /* primary (AC_SDIN0) codec ready */#define ICH_MCINT 0x00000080 /* MIC capture interrupt */#define ICH_POINT 0x00000040 /* playback interrupt */#define ICH_PIINT 0x00000020 /* capture interrupt */#define ICH_NVSPINT 0x00000010 /* nforce spdif interrupt */#define ICH_MOINT 0x00000004 /* modem playback interrupt */#define ICH_MIINT 0x00000002 /* modem capture interrupt */#define ICH_GSCI 0x00000001 /* GPI status change interrupt */#define ICH_REG_ACC_SEMA 0x34 /* byte - codec write semaphore */#define ICH_CAS 0x01 /* codec access semaphore */#define ICH_REG_SDM 0x80#define ICH_DI2L_MASK 0x000000c0 /* PCM In 2, Mic In 2 data in line */#define ICH_DI2L_SHIFT 6#define ICH_DI1L_MASK 0x00000030 /* PCM In 1, Mic In 1 data in line */#define ICH_DI1L_SHIFT 4#define ICH_SE 0x00000008 /* steer enable */#define ICH_LDI_MASK 0x00000003 /* last codec read data input */#define ICH_MAX_FRAGS 32 /* max hw frags *//* * registers for Ali5455 *//* ALi 5455 busmaster blocks */DEFINE_REGSET(AL_PI, 0x40); /* ALi PCM in */DEFINE_REGSET(AL_PO, 0x50); /* Ali PCM out */DEFINE_REGSET(AL_MC, 0x60); /* Ali Mic in */DEFINE_REGSET(AL_CDC_SPO, 0x70); /* Ali Codec SPDIF out */DEFINE_REGSET(AL_CENTER, 0x80); /* Ali center out */DEFINE_REGSET(AL_LFE, 0x90); /* Ali center out */DEFINE_REGSET(AL_CLR_SPI, 0xa0); /* Ali Controller SPDIF in */DEFINE_REGSET(AL_CLR_SPO, 0xb0); /* Ali Controller SPDIF out */DEFINE_REGSET(AL_I2S, 0xc0); /* Ali I2S in */DEFINE_REGSET(AL_PI2, 0xd0); /* Ali PCM2 in */DEFINE_REGSET(AL_MC2, 0xe0); /* Ali Mic2 in */enum { ICH_REG_ALI_SCR = 0x00, /* System Control Register */ ICH_REG_ALI_SSR = 0x04, /* System Status Register */ ICH_REG_ALI_DMACR = 0x08, /* DMA Control Register */ ICH_REG_ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */ ICH_REG_ALI_INTERFACECR = 0x10, /* Interface Control Register */ ICH_REG_ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */ ICH_REG_ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */ ICH_REG_ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */ ICH_REG_ALI_CPR = 0x20, /* Command Port Register */ ICH_REG_ALI_CPR_ADDR = 0x22, /* ac97 addr write */ ICH_REG_ALI_SPR = 0x24, /* Status Port Register */ ICH_REG_ALI_SPR_ADDR = 0x26, /* ac97 addr read */ ICH_REG_ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */ ICH_REG_ALI_TTSR = 0x30, /* Transmit Tag Slot Register */ ICH_REG_ALI_RTSR = 0x34, /* Receive Tag Slot Register */ ICH_REG_ALI_CSPSR = 0x38, /* Command/Status Port Status Register */ ICH_REG_ALI_CAS = 0x3c, /* Codec Write Semaphore Register */ ICH_REG_ALI_HWVOL = 0xf0, /* hardware volume control/status */ ICH_REG_ALI_I2SCR = 0xf4, /* I2S control/status */ ICH_REG_ALI_SPDIFCSR = 0xf8, /* spdif channel status register */ ICH_REG_ALI_SPDIFICS = 0xfc, /* spdif interface control/status */};#define ALI_CAS_SEM_BUSY 0x80000000#define ALI_CPR_ADDR_SECONDARY 0x100#define ALI_CPR_ADDR_READ 0x80#define ALI_CSPSR_CODEC_READY 0x08#define ALI_CSPSR_READ_OK 0x02#define ALI_CSPSR_WRITE_OK 0x01/* interrupts for the whole chip by interrupt status register finish */ #define ALI_INT_MICIN2 (1<<26)#define ALI_INT_PCMIN2 (1<<25)#define ALI_INT_I2SIN (1<<24)#define ALI_INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */#define ALI_INT_SPDIFIN (1<<22)#define ALI_INT_LFEOUT (1<<21)#define ALI_INT_CENTEROUT (1<<20)#define ALI_INT_CODECSPDIFOUT (1<<19)#define ALI_INT_MICIN (1<<18)#define ALI_INT_PCMOUT (1<<17)#define ALI_INT_PCMIN (1<<16)#define ALI_INT_CPRAIS (1<<7) /* command port available */#define ALI_INT_SPRAIS (1<<5) /* status port available */#define ALI_INT_GPIO (1<<1)#define ALI_INT_MASK (ALI_INT_SPDIFOUT|ALI_INT_CODECSPDIFOUT|ALI_INT_MICIN|ALI_INT_PCMOUT|ALI_INT_PCMIN)#define ICH_ALI_SC_RESET (1<<31) /* master reset */#define ICH_ALI_SC_AC97_DBL (1<<30)#define ICH_ALI_SC_CODEC_SPDF (3<<20) /* 1=7/8, 2=6/9, 3=10/11 */#define ICH_ALI_SC_IN_BITS (3<<18)#define ICH_ALI_SC_OUT_BITS (3<<16)#define ICH_ALI_SC_6CH_CFG (3<<14)#define ICH_ALI_SC_PCM_4 (1<<8)#define ICH_ALI_SC_PCM_6 (2<<8)#define ICH_ALI_SC_PCM_246_MASK (3<<8)#define ICH_ALI_SS_SEC_ID (3<<5)#define ICH_ALI_SS_PRI_ID (3<<3)#define ICH_ALI_IF_AC97SP (1<<21)#define ICH_ALI_IF_MC (1<<20)#define ICH_ALI_IF_PI (1<<19)#define ICH_ALI_IF_MC2 (1<<18)#define ICH_ALI_IF_PI2 (1<<17)#define ICH_ALI_IF_LINE_SRC (1<<15) /* 0/1 = slot 3/6 */#define ICH_ALI_IF_MIC_SRC (1<<14) /* 0/1 = slot 3/6 */#define ICH_ALI_IF_SPDF_SRC (3<<12) /* 00 = PCM, 01 = AC97-in, 10 = spdif-in, 11 = i2s */#define ICH_ALI_IF_AC97_OUT (3<<8) /* 00 = PCM, 10 = spdif-in, 11 = i2s */#define ICH_ALI_IF_PO_SPDF (1<<3)#define ICH_ALI_IF_PO (1<<1)/* * */enum { ICHD_PCMIN, ICHD_PCMOUT, ICHD_MIC, ICHD_MIC2, ICHD_PCM2IN, ICHD_SPBAR, ICHD_LAST = ICHD_SPBAR };enum { NVD_PCMIN, NVD_PCMOUT, NVD_MIC, NVD_SPBAR, NVD_LAST = NVD_SPBAR };enum { ALID_PCMIN, ALID_PCMOUT, ALID_MIC, ALID_AC97SPDIFOUT, ALID_SPDIFIN, ALID_SPDIFOUT, ALID_LAST = ALID_SPDIFOUT };#define get_ichdev(substream) (ichdev_t *)(substream->runtime->private_data)typedef struct { unsigned int ichd; /* ich device number */ unsigned long reg_offset; /* offset to bmaddr */ u32 *bdbar; /* CPU address (32bit) */ unsigned int bdbar_addr; /* PCI bus address (32bit) */ snd_pcm_substream_t *substream; unsigned int physbuf; /* physical address (32bit) */ unsigned int size; unsigned int fragsize; unsigned int fragsize1; unsigned int position; unsigned int pos_shift; int frags; int lvi; int lvi_frag; int civ; int ack; int ack_reload; unsigned int ack_bit; unsigned int roff_sr; unsigned int roff_picb; unsigned int int_sta_mask; /* interrupt status mask */ unsigned int ali_slot; /* ALI DMA slot */ struct ac97_pcm *pcm; int pcm_open_flag;} ichdev_t;typedef struct _snd_intel8x0 intel8x0_t;struct _snd_intel8x0 { unsigned int device_type; int irq; unsigned int mmio; unsigned long addr; void __iomem * remap_addr; unsigned int bm_mmio; unsigned long bmaddr; void __iomem * remap_bmaddr; struct pci_dev *pci; snd_card_t *card; int pcm_devs; snd_pcm_t *pcm[6]; ichdev_t ichd[6]; unsigned multi4: 1, multi6: 1, smp20bit: 1; unsigned in_ac97_init: 1, in_sdin_init: 1; unsigned fix_nocache: 1; /* workaround for 440MX */ unsigned buggy_irq: 1; /* workaround for buggy mobos */ ac97_bus_t *ac97_bus; ac97_t *ac97[3]; unsigned int ac97_sdin[3]; snd_rawmidi_t *rmidi; spinlock_t reg_lock; spinlock_t ac97_lock; u32 bdbars_count; struct snd_dma_buffer bdbars; u32 int_sta_reg; /* interrupt status register */ u32 int_sta_mask; /* interrupt status mask */};static struct pci_device_id snd_intel8x0_ids[] = { { 0x8086, 0x2415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */ { 0x8086, 0x2425, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */ { 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?