📄 sonicvibes.c
字号:
/* * Driver for S3 SonicVibes soundcard * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * BUGS: * It looks like 86c617 rev 3 doesn't supports DDMA buffers above 16MB? * Driver sometimes hangs... Nobody knows why at this moment... * * 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 <linux/delay.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/gameport.h>#include <linux/moduleparam.h>#include <linux/dma-mapping.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/info.h>#include <sound/control.h>#include <sound/mpu401.h>#include <sound/opl3.h>#include <sound/initval.h>#include <asm/io.h>MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");MODULE_DESCRIPTION("S3 SonicVibes PCI");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))#define SUPPORT_JOYSTICK 1#endifstatic 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 reverb[SNDRV_CARDS];static int mge[SNDRV_CARDS];static unsigned int dmaio = 0x7a00; /* DDMA i/o address */module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for S3 SonicVibes soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for S3 SonicVibes soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable S3 SonicVibes soundcard.");module_param_array(reverb, bool, NULL, 0444);MODULE_PARM_DESC(reverb, "Enable reverb (SRAM is present) for S3 SonicVibes soundcard.");module_param_array(mge, bool, NULL, 0444);MODULE_PARM_DESC(mge, "MIC Gain Enable for S3 SonicVibes soundcard.");module_param(dmaio, uint, 0444);MODULE_PARM_DESC(dmaio, "DDMA i/o base address for S3 SonicVibes soundcard.");/* * Enhanced port direct registers */#define SV_REG(sonic, x) ((sonic)->enh_port + SV_REG_##x)#define SV_REG_CONTROL 0x00 /* R/W: CODEC/Mixer control register */#define SV_ENHANCED 0x01 /* audio mode select - enhanced mode */#define SV_TEST 0x02 /* test bit */#define SV_REVERB 0x04 /* reverb enable */#define SV_WAVETABLE 0x08 /* wavetable active / FM active if not set */#define SV_INTA 0x20 /* INTA driving - should be always 1 */#define SV_RESET 0x80 /* reset chip */#define SV_REG_IRQMASK 0x01 /* R/W: CODEC/Mixer interrupt mask register */#define SV_DMAA_MASK 0x01 /* mask DMA-A interrupt */#define SV_DMAC_MASK 0x04 /* mask DMA-C interrupt */#define SV_SPEC_MASK 0x08 /* special interrupt mask - should be always masked */#define SV_UD_MASK 0x40 /* Up/Down button interrupt mask */#define SV_MIDI_MASK 0x80 /* mask MIDI interrupt */#define SV_REG_STATUS 0x02 /* R/O: CODEC/Mixer status register */#define SV_DMAA_IRQ 0x01 /* DMA-A interrupt */#define SV_DMAC_IRQ 0x04 /* DMA-C interrupt */#define SV_SPEC_IRQ 0x08 /* special interrupt */#define SV_UD_IRQ 0x40 /* Up/Down interrupt */#define SV_MIDI_IRQ 0x80 /* MIDI interrupt */#define SV_REG_INDEX 0x04 /* R/W: CODEC/Mixer index address register */#define SV_MCE 0x40 /* mode change enable */#define SV_TRD 0x80 /* DMA transfer request disabled */#define SV_REG_DATA 0x05 /* R/W: CODEC/Mixer index data register *//* * Enhanced port indirect registers */#define SV_IREG_LEFT_ADC 0x00 /* Left ADC Input Control */#define SV_IREG_RIGHT_ADC 0x01 /* Right ADC Input Control */#define SV_IREG_LEFT_AUX1 0x02 /* Left AUX1 Input Control */#define SV_IREG_RIGHT_AUX1 0x03 /* Right AUX1 Input Control */#define SV_IREG_LEFT_CD 0x04 /* Left CD Input Control */#define SV_IREG_RIGHT_CD 0x05 /* Right CD Input Control */#define SV_IREG_LEFT_LINE 0x06 /* Left Line Input Control */#define SV_IREG_RIGHT_LINE 0x07 /* Right Line Input Control */#define SV_IREG_MIC 0x08 /* MIC Input Control */#define SV_IREG_GAME_PORT 0x09 /* Game Port Control */#define SV_IREG_LEFT_SYNTH 0x0a /* Left Synth Input Control */#define SV_IREG_RIGHT_SYNTH 0x0b /* Right Synth Input Control */#define SV_IREG_LEFT_AUX2 0x0c /* Left AUX2 Input Control */#define SV_IREG_RIGHT_AUX2 0x0d /* Right AUX2 Input Control */#define SV_IREG_LEFT_ANALOG 0x0e /* Left Analog Mixer Output Control */#define SV_IREG_RIGHT_ANALOG 0x0f /* Right Analog Mixer Output Control */#define SV_IREG_LEFT_PCM 0x10 /* Left PCM Input Control */#define SV_IREG_RIGHT_PCM 0x11 /* Right PCM Input Control */#define SV_IREG_DMA_DATA_FMT 0x12 /* DMA Data Format */#define SV_IREG_PC_ENABLE 0x13 /* Playback/Capture Enable Register */#define SV_IREG_UD_BUTTON 0x14 /* Up/Down Button Register */#define SV_IREG_REVISION 0x15 /* Revision */#define SV_IREG_ADC_OUTPUT_CTRL 0x16 /* ADC Output Control */#define SV_IREG_DMA_A_UPPER 0x18 /* DMA A Upper Base Count */#define SV_IREG_DMA_A_LOWER 0x19 /* DMA A Lower Base Count */#define SV_IREG_DMA_C_UPPER 0x1c /* DMA C Upper Base Count */#define SV_IREG_DMA_C_LOWER 0x1d /* DMA C Lower Base Count */#define SV_IREG_PCM_RATE_LOW 0x1e /* PCM Sampling Rate Low Byte */#define SV_IREG_PCM_RATE_HIGH 0x1f /* PCM Sampling Rate High Byte */#define SV_IREG_SYNTH_RATE_LOW 0x20 /* Synthesizer Sampling Rate Low Byte */#define SV_IREG_SYNTH_RATE_HIGH 0x21 /* Synthesizer Sampling Rate High Byte */#define SV_IREG_ADC_CLOCK 0x22 /* ADC Clock Source Selection */#define SV_IREG_ADC_ALT_RATE 0x23 /* ADC Alternative Sampling Rate Selection */#define SV_IREG_ADC_PLL_M 0x24 /* ADC PLL M Register */#define SV_IREG_ADC_PLL_N 0x25 /* ADC PLL N Register */#define SV_IREG_SYNTH_PLL_M 0x26 /* Synthesizer PLL M Register */#define SV_IREG_SYNTH_PLL_N 0x27 /* Synthesizer PLL N Register */#define SV_IREG_MPU401 0x2a /* MPU-401 UART Operation */#define SV_IREG_DRIVE_CTRL 0x2b /* Drive Control */#define SV_IREG_SRS_SPACE 0x2c /* SRS Space Control */#define SV_IREG_SRS_CENTER 0x2d /* SRS Center Control */#define SV_IREG_WAVE_SOURCE 0x2e /* Wavetable Sample Source Select */#define SV_IREG_ANALOG_POWER 0x30 /* Analog Power Down Control */#define SV_IREG_DIGITAL_POWER 0x31 /* Digital Power Down Control */#define SV_IREG_ADC_PLL SV_IREG_ADC_PLL_M#define SV_IREG_SYNTH_PLL SV_IREG_SYNTH_PLL_M/* * DMA registers */#define SV_DMA_ADDR0 0x00#define SV_DMA_ADDR1 0x01#define SV_DMA_ADDR2 0x02#define SV_DMA_ADDR3 0x03#define SV_DMA_COUNT0 0x04#define SV_DMA_COUNT1 0x05#define SV_DMA_COUNT2 0x06#define SV_DMA_MODE 0x0b#define SV_DMA_RESET 0x0d#define SV_DMA_MASK 0x0f/* * Record sources */#define SV_RECSRC_RESERVED (0x00<<5)#define SV_RECSRC_CD (0x01<<5)#define SV_RECSRC_DAC (0x02<<5)#define SV_RECSRC_AUX2 (0x03<<5)#define SV_RECSRC_LINE (0x04<<5)#define SV_RECSRC_AUX1 (0x05<<5)#define SV_RECSRC_MIC (0x06<<5)#define SV_RECSRC_OUT (0x07<<5)/* * constants */#define SV_FULLRATE 48000#define SV_REFFREQUENCY 24576000#define SV_ADCMULT 512#define SV_MODE_PLAY 1#define SV_MODE_CAPTURE 2/* */struct sonicvibes { unsigned long dma1size; unsigned long dma2size; int irq; unsigned long sb_port; unsigned long enh_port; unsigned long synth_port; unsigned long midi_port; unsigned long game_port; unsigned int dmaa_port; struct resource *res_dmaa; unsigned int dmac_port; struct resource *res_dmac; unsigned char enable; unsigned char irqmask; unsigned char revision; unsigned char format; unsigned char srs_space; unsigned char srs_center; unsigned char mpu_switch; unsigned char wave_source; unsigned int mode; struct pci_dev *pci; struct snd_card *card; struct snd_pcm *pcm; struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; struct snd_rawmidi *rmidi; struct snd_hwdep *fmsynth; /* S3FM */ spinlock_t reg_lock; unsigned int p_dma_size; unsigned int c_dma_size; struct snd_kcontrol *master_mute; struct snd_kcontrol *master_volume;#ifdef SUPPORT_JOYSTICK struct gameport *gameport;#endif};static struct pci_device_id snd_sonic_ids[] = { { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { 0, }};MODULE_DEVICE_TABLE(pci, snd_sonic_ids);static struct snd_ratden sonicvibes_adc_clock = { .num_min = 4000 * 65536, .num_max = 48000UL * 65536, .num_step = 1, .den = 65536,};static struct snd_pcm_hw_constraint_ratdens snd_sonicvibes_hw_constraints_adc_clock = { .nrats = 1, .rats = &sonicvibes_adc_clock,};/* * common I/O routines */static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic, unsigned int addr, unsigned int count){ count--; outl(addr, sonic->dmaa_port + SV_DMA_ADDR0); outl(count, sonic->dmaa_port + SV_DMA_COUNT0); outb(0x18, sonic->dmaa_port + SV_DMA_MODE);#if 0 printk("program dmaa: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));#endif}static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic, unsigned int addr, unsigned int count){ /* note: dmac is working in word mode!!! */ count >>= 1; count--; outl(addr, sonic->dmac_port + SV_DMA_ADDR0); outl(count, sonic->dmac_port + SV_DMA_COUNT0); outb(0x14, sonic->dmac_port + SV_DMA_MODE);#if 0 printk("program dmac: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmac_port + SV_DMA_ADDR0));#endif}static inline unsigned int snd_sonicvibes_getdmaa(struct sonicvibes * sonic){ return (inl(sonic->dmaa_port + SV_DMA_COUNT0) & 0xffffff) + 1;}static inline unsigned int snd_sonicvibes_getdmac(struct sonicvibes * sonic){ /* note: dmac is working in word mode!!! */ return ((inl(sonic->dmac_port + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;}static void snd_sonicvibes_out1(struct sonicvibes * sonic, unsigned char reg, unsigned char value){ outb(reg, SV_REG(sonic, INDEX)); udelay(10); outb(value, SV_REG(sonic, DATA)); udelay(10);}static void snd_sonicvibes_out(struct sonicvibes * sonic, unsigned char reg, unsigned char value){ unsigned long flags; spin_lock_irqsave(&sonic->reg_lock, flags); outb(reg, SV_REG(sonic, INDEX)); udelay(10); outb(value, SV_REG(sonic, DATA)); udelay(10); spin_unlock_irqrestore(&sonic->reg_lock, flags);}static unsigned char snd_sonicvibes_in1(struct sonicvibes * sonic, unsigned char reg){ unsigned char value; outb(reg, SV_REG(sonic, INDEX)); udelay(10); value = inb(SV_REG(sonic, DATA)); udelay(10); return value;}static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char reg){ unsigned long flags; unsigned char value; spin_lock_irqsave(&sonic->reg_lock, flags); outb(reg, SV_REG(sonic, INDEX)); udelay(10); value = inb(SV_REG(sonic, DATA)); udelay(10); spin_unlock_irqrestore(&sonic->reg_lock, flags); return value;}#if 0static void snd_sonicvibes_debug(struct sonicvibes * sonic){ printk("SV REGS: INDEX = 0x%02x ", inb(SV_REG(sonic, INDEX))); printk(" STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS))); printk(" 0x00: left input = 0x%02x ", snd_sonicvibes_in(sonic, 0x00)); printk(" 0x20: synth rate low = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20)); printk(" 0x01: right input = 0x%02x ", snd_sonicvibes_in(sonic, 0x01)); printk(" 0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21)); printk(" 0x02: left AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x02)); printk(" 0x22: ADC clock = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22)); printk(" 0x03: right AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x03)); printk(" 0x23: ADC alt rate = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23)); printk(" 0x04: left CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x04)); printk(" 0x24: ADC pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24)); printk(" 0x05: right CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x05)); printk(" 0x25: ADC pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25)); printk(" 0x06: left line = 0x%02x ", snd_sonicvibes_in(sonic, 0x06)); printk(" 0x26: Synth pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26)); printk(" 0x07: right line = 0x%02x ", snd_sonicvibes_in(sonic, 0x07)); printk(" 0x27: Synth pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27)); printk(" 0x08: MIC = 0x%02x ", snd_sonicvibes_in(sonic, 0x08)); printk(" 0x28: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28)); printk(" 0x09: Game port = 0x%02x ", snd_sonicvibes_in(sonic, 0x09));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -