📄 ite8172.c
字号:
/* * ite8172.c -- ITE IT8172G Sound Driver. * * Copyright 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. * stevel@mvista.com or source@mvista.com * * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * 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. * * * Module command line parameters: * * Supported devices: * /dev/dsp standard OSS /dev/dsp device * /dev/mixer standard OSS /dev/mixer device * * Notes: * * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are * taken, slightly modified or not at all, from the ES1371 driver, * so refer to the credits in es1371.c for those. The rest of the * code (probe, open, read, write, the ISR, etc.) is new. * 2. The following support is untested: * * Memory mapping the audio buffers, and the ioctl controls that go * with it. * * S/PDIF output. * 3. The following is not supported: * * I2S input. * * legacy audio mode. * 4. Support for volume button interrupts is implemented but doesn't * work yet. * * Revision history * 02.08.2001 0.1 Initial release */#include <linux/version.h>#include <linux/module.h>#include <linux/string.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 <linux/init.h>#include <linux/poll.h>#include <linux/bitops.h>#include <linux/proc_fs.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/ac97_codec.h>#include <linux/wrapper.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <asm/hardirq.h>#include <asm/it8172/it8172.h>/* --------------------------------------------------------------------- */#undef OSS_DOCUMENTED_MIXER_SEMANTICS#define IT8172_DEBUG#undef IT8172_VERBOSE_DEBUG#define DBG(x) {}static const unsigned sample_shift[] = { 0, 1, 1, 2 };/* * Audio Controller register bit definitions follow. See * include/asm/it8172/it8172.h for register offsets. *//* PCM Out Volume Reg */#define PCMOV_PCMOM (1<<15) /* PCM Out Mute default 1: mute */#define PCMOV_PCMRCG_BIT 8 /* PCM Right channel Gain */#define PCMOV_PCMRCG_MASK (0x1f<<PCMOV_PCMRCG_BIT)#define PCMOV_PCMLCG_BIT 0 /* PCM Left channel gain */#define PCMOV_PCMLCG_MASK 0x1f/* FM Out Volume Reg */#define FMOV_FMOM (1<<15) /* FM Out Mute default 1: mute */#define FMOV_FMRCG_BIT 8 /* FM Right channel Gain */#define FMOV_FMRCG_MASK (0x1f<<FMOV_FMRCG_BIT)#define FMOV_FMLCG_BIT 0 /* FM Left channel gain */#define FMOV_FMLCG_MASK 0x1f/* I2S Out Volume Reg */#define I2SV_I2SOM (1<<15) /* I2S Out Mute default 1: mute */#define I2SV_I2SRCG_BIT 8 /* I2S Right channel Gain */#define I2SV_I2SRCG_MASK (0x1f<<I2SV_I2SRCG_BIT)#define I2SV_I2SLCG_BIT 0 /* I2S Left channel gain */#define I2SV_I2SLCG_MASK 0x1f/* Digital Recording Source Select Reg */#define DRSS_BIT 0#define DRSS_MASK 0x07#define DRSS_AC97_PRIM 0#define DRSS_FM 1#define DRSS_I2S 2#define DRSS_PCM 3#define DRSS_AC97_SEC 4/* Playback/Capture Channel Control Registers */#define CC_SM (1<<15) /* Stereo, Mone 0: mono 1: stereo */#define CC_DF (1<<14) /* Data Format 0: 8 bit 1: 16 bit */#define CC_FMT_BIT 14#define CC_FMT_MASK (0x03<<CC_FMT_BIT)#define CC_CF_BIT 12 /* Channel format (Playback only) */#define CC_CF_MASK (0x03<<CC_CF_BIT)#define CC_CF_2 0#define CC_CF_4 (1<<CC_CF_BIT)#define CC_CF_6 (2<<CC_CF_BIT)#define CC_SR_BIT 8 /* sample Rate */#define CC_SR_MASK (0x0f<<CC_SR_BIT)#define CC_SR_5500 0#define CC_SR_8000 (1<<CC_SR_BIT)#define CC_SR_9600 (2<<CC_SR_BIT)#define CC_SR_11025 (3<<CC_SR_BIT)#define CC_SR_16000 (4<<CC_SR_BIT)#define CC_SR_19200 (5<<CC_SR_BIT)#define CC_SR_22050 (6<<CC_SR_BIT)#define CC_SR_32000 (7<<CC_SR_BIT)#define CC_SR_38400 (8<<CC_SR_BIT)#define CC_SR_44100 (9<<CC_SR_BIT)#define CC_SR_48000 (10<<CC_SR_BIT)#define CC_CSP (1<<7) /* Channel stop * 0: End of Current buffer * 1: Immediately stop when rec stop */#define CC_CP (1<<6) /* Channel pause 0: normal, 1: pause */#define CC_CA (1<<5) /* Channel Action 0: Stop , 1: start */#define CC_CB2L (1<<2) /* Cur. buf. 2 xfr is last 0: No, 1: Yes */#define CC_CB1L (1<<1) /* Cur. buf. 1 xfr is last 0: No, 1: Yes */#define CC_DE 1 /* DFC/DFIFO Data Empty 1: empty, 0: not empty * (Playback only) *//* Codec Control Reg */#define CODECC_GME (1<<9) /* AC97 GPIO Mode enable */#define CODECC_ATM (1<<8) /* AC97 ATE test mode 0: test 1: normal */#define CODECC_WR (1<<6) /* AC97 Warn reset 1: warm reset , 0: Normal */#define CODECC_CR (1<<5) /* AC97 Cold reset 1: Cold reset , 0: Normal *//* I2S Control Reg */#define I2SMC_SR_BIT 6 /* I2S Sampling rate * 00: 48KHz, 01: 44.1 KHz, 10: 32 32 KHz */#define I2SMC_SR_MASK (0x03<<I2SMC_SR_BIT)#define I2SMC_SR_48000 0#define I2SMC_SR_44100 (1<<I2SMC_SR_BIT)#define I2SMC_SR_32000 (2<<I2SMC_SR_BIT)#define I2SMC_SRSS (1<<5) /* Sample Rate Source Select 1:S/W, 0: H/W */#define I2SMC_I2SF_BIT 0 /* I2S Format */#define I2SMC_I2SF_MASK 0x03#define I2SMC_I2SF_DAC 0#define I2SMC_I2SF_ADC 2#define I2SMC_I2SF_I2S 3/* Volume up, Down, Mute */#define VS_VMP (1<<2) /* Volume mute 1: pushed, 0: not */#define VS_VDP (1<<1) /* Volume Down 1: pushed, 0: not */#define VS_VUP 1 /* Volime Up 1: pushed, 0: not *//* SRC, Mixer test control/DFC status reg */#define SRCS_DPUSC (1<<5) /* DFC Playback underrun Status/clear */#define SRCS_DCOSC (1<<4) /* DFC Capture Overrun Status/clear */#define SRCS_SIS (1<<3) /* SRC input select 1: Mixer, 0: Codec I/F */#define SRCS_CDIS_BIT 0 /* Codec Data Input Select */#define SRCS_CDIS_MASK 0x07#define SRCS_CDIS_MIXER 0#define SRCS_CDIS_PCM 1#define SRCS_CDIS_I2S 2#define SRCS_CDIS_FM 3#define SRCS_CDIS_DFC 4/* Codec Index Reg command Port */#define CIRCP_CID_BIT 10#define CIRCP_CID_MASK (0x03<<CIRCP_CID_BIT)#define CIRCP_CPS (1<<9) /* Command Port Status 0: ready, 1: busy */#define CIRCP_DPVF (1<<8) /* Data Port Valid Flag 0: invalis, 1: valid */#define CIRCP_RWC (1<<7) /* Read/write command */#define CIRCP_CIA_BIT 0#define CIRCP_CIA_MASK 0x007F /* Codec Index Address *//* Test Mode Control/Test group Select Control *//* General Control Reg */#define GC_VDC_BIT 6 /* Volume Division Control */#define GC_VDC_MASK (0x03<<GC_VDC_BIT)#define GC_VDC_NONE 0#define GC_VDC_DIV2 (1<<GC_VDC_BIT)#define GC_VDC_DIV4 (2<<GC_VDC_BIT)#define GC_SOE (1<<2) /* S/PDIF Output enable */#define GC_SWR 1 /* Software warn reset *//* Interrupt mask Control Reg */#define IMC_VCIM (1<<6) /* Volume CNTL interrupt mask */#define IMC_CCIM (1<<1) /* Capture Chan. iterrupt mask */#define IMC_PCIM 1 /* Playback Chan. interrupt mask *//* Interrupt status/clear reg */#define ISC_VCI (1<<6) /* Volume CNTL interrupt 1: clears */#define ISC_CCI (1<<1) /* Capture Chan. interrupt 1: clears */#define ISC_PCI 1 /* Playback Chan. interrupt 1: clears *//* misc stuff */#define POLL_COUNT 0x5000#define IT8172_MODULE_NAME "IT8172 audio"#define PFX IT8172_MODULE_NAME ": "/* --------------------------------------------------------------------- */struct it8172_state { /* list of it8172 devices */ struct list_head devs; /* the corresponding pci_dev structure */ struct pci_dev *dev; /* soundcore stuff */ int dev_audio; /* hardware resources */ unsigned long io; unsigned int irq; /* PCI ID's */ u16 vendor; u16 device; u8 rev; /* the chip revision */ /* options */ int spdif_volume; /* S/PDIF output is enabled if != -1 */#ifdef IT8172_DEBUG /* debug /proc entry */ struct proc_dir_entry *ps; struct proc_dir_entry *ac97_ps;#endif /* IT8172_DEBUG */ struct ac97_codec codec; unsigned short pcc, capcc; unsigned dacrate, adcrate; spinlock_t lock; struct semaphore open_sem; mode_t open_mode; wait_queue_head_t open_wait; struct dmabuf { void *rawbuf; dma_addr_t dmaaddr; unsigned buforder; unsigned numfrag; unsigned fragshift; void* nextIn; void* nextOut; int count; int curBufPtr; unsigned total_bytes; unsigned error; /* over/underrun */ wait_queue_head_t wait; /* redundant, but makes calculations easier */ unsigned fragsize; unsigned dmasize; unsigned fragsamples; /* OSS stuff */ unsigned mapped:1; unsigned ready:1; unsigned stopped:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; } dma_dac, dma_adc;};/* --------------------------------------------------------------------- */static LIST_HEAD(devs);/* --------------------------------------------------------------------- */extern inline unsigned ld2(unsigned int x){ unsigned r = 0; if (x >= 0x10000) { x >>= 16; r += 16; } if (x >= 0x100) { x >>= 8; r += 8; } if (x >= 0x10) { x >>= 4; r += 4; } if (x >= 4) { x >>= 2; r += 2; } if (x >= 2) r++; return r;}/* --------------------------------------------------------------------- */static void it8172_delay(int msec){ unsigned long tmo; signed long tmo2; if (in_interrupt()) return; tmo = jiffies + (msec*HZ)/1000; for (;;) { tmo2 = tmo - jiffies; if (tmo2 <= 0) break; schedule_timeout(tmo2); }}static unsigned shortget_compat_rate(unsigned* rate){ unsigned rate_out = *rate; unsigned short sr; if (rate_out >= 46050) { sr = CC_SR_48000; rate_out = 48000; } else if (rate_out >= 41250) { sr = CC_SR_44100; rate_out = 44100; } else if (rate_out >= 35200) { sr = CC_SR_38400; rate_out = 38400; } else if (rate_out >= 27025) { sr = CC_SR_32000; rate_out = 32000; } else if (rate_out >= 20625) { sr = CC_SR_22050; rate_out = 22050; } else if (rate_out >= 17600) { sr = CC_SR_19200; rate_out = 19200; } else if (rate_out >= 13513) { sr = CC_SR_16000; rate_out = 16000; } else if (rate_out >= 10313) { sr = CC_SR_11025; rate_out = 11025; } else if (rate_out >= 8800) { sr = CC_SR_9600; rate_out = 9600; } else if (rate_out >= 6750) { sr = CC_SR_8000; rate_out = 8000; } else { sr = CC_SR_5500; rate_out = 5500; } *rate = rate_out; return sr;}static void set_adc_rate(struct it8172_state *s, unsigned rate){ unsigned long flags; unsigned short sr; sr = get_compat_rate(&rate); spin_lock_irqsave(&s->lock, flags); s->capcc &= ~CC_SR_MASK; s->capcc |= sr; outw(s->capcc, s->io+IT_AC_CAPCC); spin_unlock_irqrestore(&s->lock, flags); s->adcrate = rate;}static void set_dac_rate(struct it8172_state *s, unsigned rate){ unsigned long flags; unsigned short sr; sr = get_compat_rate(&rate); spin_lock_irqsave(&s->lock, flags); s->pcc &= ~CC_SR_MASK; s->pcc |= sr; outw(s->pcc, s->io+IT_AC_PCC); spin_unlock_irqrestore(&s->lock, flags); s->dacrate = rate;}/* --------------------------------------------------------------------- */static u16 rdcodec(struct ac97_codec *codec, u8 addr){ struct it8172_state *s = (struct it8172_state *)codec->private_data; unsigned long flags; unsigned short circp, data; int i; spin_lock_irqsave(&s->lock, flags); for (i = 0; i < POLL_COUNT; i++) if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) break; if (i == POLL_COUNT) printk(KERN_INFO PFX "rdcodec: codec ready poll expired!\n"); circp = addr & CIRCP_CIA_MASK; circp |= (codec->id << CIRCP_CID_BIT); circp |= CIRCP_RWC; // read command outw(circp, s->io+IT_AC_CIRCP); /* now wait for the data */ for (i = 0; i < POLL_COUNT; i++) if (inw(s->io+IT_AC_CIRCP) & CIRCP_DPVF) break; if (i == POLL_COUNT) printk(KERN_INFO PFX "rdcodec: read poll expired!\n"); data = inw(s->io+IT_AC_CIRDP); spin_unlock_irqrestore(&s->lock, flags); return data;}static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data){ struct it8172_state *s = (struct it8172_state *)codec->private_data; unsigned long flags; unsigned short circp; int i; spin_lock_irqsave(&s->lock, flags); for (i = 0; i < POLL_COUNT; i++) if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS)) break; if (i == POLL_COUNT) printk(KERN_INFO PFX "wrcodec: codec ready poll expired!\n"); circp = addr & CIRCP_CIA_MASK; circp |= (codec->id << CIRCP_CID_BIT); circp &= ~CIRCP_RWC; // write command outw(data, s->io+IT_AC_CIRDP); // send data first outw(circp, s->io+IT_AC_CIRCP); spin_unlock_irqrestore(&s->lock, flags);}static void waitcodec(struct ac97_codec *codec){ unsigned short temp; /* codec_wait is used to wait for a ready state after an AC97_RESET. */ it8172_delay(10);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -