📄 cmpci.c
字号:
/* * cmpci.c -- C-Media PCI audio driver. * * Copyright (C) 1999 C-media support (support@cmedia.com.tw) * * Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch) * * For update, visit: * http://www.cmedia.com.tw * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Special thanks to David C. Niemi, Jan Pfeifer * * * Module command line parameters: * none so far * * * Supported devices: * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible * /dev/midi simple MIDI UART interface, no ioctl * * The card has both an FM and a Wavetable synth, but I have to figure * out first how to drive them... * * Revision history * 06.05.98 0.1 Initial release * 10.05.98 0.2 Fixed many bugs, esp. ADC rate calculation * First stab at a simple midi interface (no bells&whistles) * 13.05.98 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of * set_dac_rate in the FMODE_WRITE case in cm_open * Fix hwptr out of bounds (now mpg123 works) * 14.05.98 0.4 Don't allow excessive interrupt rates * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice * 03.08.98 0.6 Do not include modversions.h * Now mixer behaviour can basically be selected between * "OSS documented" and "OSS actual" behaviour * 31.08.98 0.7 Fix realplayer problems - dac.count issues * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs * 06.01.99 0.10 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl. * reported by Johan Maes <joma@telindus.be> * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK * read/write cannot be executed * 18.08.99 1.5 Only deallocate DMA buffer when unloading. * 02.09.99 1.6 Enable SPDIF LOOP * Change the mixer read back * 21.09.99 2.33 Use RCS version as driver version. * Add support for modem, S/PDIF loop and 4 channels. * (8738 only) * Fix bug cause x11amp cannot play. * * Fixes: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it * was calling prog_dmabuf with s->lock held, call missing * unlock_kernel in cm_midi_release * 08/10/2001 - use set_current_state in some more places * * Carlos Eduardo Gorges <carlos@techlinux.com.br> * Fri May 25 2001 * - SMP support ( spin[un]lock* revision ) * - speaker mixer support * Mon Aug 13 2001 * - optimizations and cleanups * * 03/01/2003 - open_mode fixes from Georg Acher <acher@in.tum.de> * Simon Braunschmidt <brasimon@web.de> * Sat Jan 31 2004 * - provide support for opl3 FM by releasing IO range after initialization * * ChenLi Tien <cltien@cmedia.com.tw> * Mar 9 2004 * - Fix S/PDIF out if spdif_loop enabled * - Load opl3 driver if enabled (fmio in proper range) * - Load mpu401 if enabled (mpuio in proper range) * Apr 5 2004 * - Fix DUAL_DAC dma synchronization bug * - Check exist FM/MPU401 I/O before activate. * - Add AFTM_S16_BE format support, so MPlayer/Xine can play AC3/mutlichannel * on Mac * - Change to support kernel 2.6 so only small patch needed * - All parameters default to 0 * - Add spdif_out to send PCM through S/PDIF out jack * - Add hw_copy to get 4-spaker output for general PCM/analog output * * Stefan Thater <stefan.thaeter@gmx.de> * Apr 5 2004 * - Fix mute single channel for CD/Line-in/AUX-in *//*****************************************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/string.h>#include <linux/interrupt.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/spinlock.h>#include <linux/smp_lock.h>#include <linux/bitops.h>#include <linux/wait.h>#include <asm/io.h>#include <asm/page.h>#include <asm/uaccess.h>#ifdef CONFIG_SOUND_CMPCI_MIDI#include "sound_config.h"#include "mpu401.h"#endif#ifdef CONFIG_SOUND_CMPCI_FM#include "opl3.h"#endif#ifdef CONFIG_SOUND_CMPCI_JOYSTICK#include <linux/gameport.h>#endif/* --------------------------------------------------------------------- */#undef OSS_DOCUMENTED_MIXER_SEMANTICS#undef DMABYTEIO#define DBG(x) {}/* --------------------------------------------------------------------- */#define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)/* CM8338 registers definition ****************/#define CODEC_CMI_FUNCTRL0 (0x00)#define CODEC_CMI_FUNCTRL1 (0x04)#define CODEC_CMI_CHFORMAT (0x08)#define CODEC_CMI_INT_HLDCLR (0x0C)#define CODEC_CMI_INT_STATUS (0x10)#define CODEC_CMI_LEGACY_CTRL (0x14)#define CODEC_CMI_MISC_CTRL (0x18)#define CODEC_CMI_TDMA_POS (0x1C)#define CODEC_CMI_MIXER (0x20)#define CODEC_SB16_DATA (0x22)#define CODEC_SB16_ADDR (0x23)#define CODEC_CMI_MIXER1 (0x24)#define CODEC_CMI_MIXER2 (0x25)#define CODEC_CMI_AUX_VOL (0x26)#define CODEC_CMI_MISC (0x27)#define CODEC_CMI_AC97 (0x28)#define CODEC_CMI_CH0_FRAME1 (0x80)#define CODEC_CMI_CH0_FRAME2 (0x84)#define CODEC_CMI_CH1_FRAME1 (0x88)#define CODEC_CMI_CH1_FRAME2 (0x8C)#define CODEC_CMI_SPDIF_CTRL (0x90)#define CODEC_CMI_MISC_CTRL2 (0x92)#define CODEC_CMI_EXT_REG (0xF0)/* Mixer registers for SB16 ******************/#define DSP_MIX_DATARESETIDX ((unsigned char)(0x00))#define DSP_MIX_MASTERVOLIDX_L ((unsigned char)(0x30))#define DSP_MIX_MASTERVOLIDX_R ((unsigned char)(0x31))#define DSP_MIX_VOICEVOLIDX_L ((unsigned char)(0x32))#define DSP_MIX_VOICEVOLIDX_R ((unsigned char)(0x33))#define DSP_MIX_FMVOLIDX_L ((unsigned char)(0x34))#define DSP_MIX_FMVOLIDX_R ((unsigned char)(0x35))#define DSP_MIX_CDVOLIDX_L ((unsigned char)(0x36))#define DSP_MIX_CDVOLIDX_R ((unsigned char)(0x37))#define DSP_MIX_LINEVOLIDX_L ((unsigned char)(0x38))#define DSP_MIX_LINEVOLIDX_R ((unsigned char)(0x39))#define DSP_MIX_MICVOLIDX ((unsigned char)(0x3A))#define DSP_MIX_SPKRVOLIDX ((unsigned char)(0x3B))#define DSP_MIX_OUTMIXIDX ((unsigned char)(0x3C))#define DSP_MIX_ADCMIXIDX_L ((unsigned char)(0x3D))#define DSP_MIX_ADCMIXIDX_R ((unsigned char)(0x3E))#define DSP_MIX_INGAINIDX_L ((unsigned char)(0x3F))#define DSP_MIX_INGAINIDX_R ((unsigned char)(0x40))#define DSP_MIX_OUTGAINIDX_L ((unsigned char)(0x41))#define DSP_MIX_OUTGAINIDX_R ((unsigned char)(0x42))#define DSP_MIX_AGCIDX ((unsigned char)(0x43))#define DSP_MIX_TREBLEIDX_L ((unsigned char)(0x44))#define DSP_MIX_TREBLEIDX_R ((unsigned char)(0x45))#define DSP_MIX_BASSIDX_L ((unsigned char)(0x46))#define DSP_MIX_BASSIDX_R ((unsigned char)(0x47))#define DSP_MIX_EXTENSION ((unsigned char)(0xf0))// pseudo register for AUX#define DSP_MIX_AUXVOL_L ((unsigned char)(0x50))#define DSP_MIX_AUXVOL_R ((unsigned char)(0x51))// I/O length#define CM_EXTENT_CODEC 0x100#define CM_EXTENT_MIDI 0x2#define CM_EXTENT_SYNTH 0x4#define CM_EXTENT_GAME 0x8// Function Control Register 0 (00h)#define CHADC0 0x01#define CHADC1 0x02#define PAUSE0 0x04#define PAUSE1 0x08// Function Control Register 0+2 (02h)#define CHEN0 0x01#define CHEN1 0x02#define RST_CH0 0x04#define RST_CH1 0x08// Function Control Register 1 (04h)#define JYSTK_EN 0x02#define UART_EN 0x04#define SPDO2DAC 0x40#define SPDFLOOP 0x80// Function Control Register 1+1 (05h)#define SPDF_0 0x01#define SPDF_1 0x02#define ASFC 0x1c#define DSFC 0xe0#define SPDIF2DAC (SPDF_1 << 8 | SPDO2DAC)// Channel Format Register (08h)#define CM_CFMT_STEREO 0x01#define CM_CFMT_16BIT 0x02#define CM_CFMT_MASK 0x03#define POLVALID 0x20#define INVSPDIFI 0x80// Channel Format Register+2 (0ah)#define SPD24SEL 0x20// Channel Format Register+3 (0bh)#define CHB3D 0x20#define CHB3D5C 0x80// Interrupt Hold/Clear Register+2 (0eh)#define CH0_INT_EN 0x01#define CH1_INT_EN 0x02// Interrupt Register (10h)#define CHINT0 0x01#define CHINT1 0x02#define CH0BUSY 0x04#define CH1BUSY 0x08// Legacy Control/Status Register+1 (15h)#define EXBASEN 0x10#define BASE2LIN 0x20#define CENTR2LIN 0x40#define CB2LIN (BASE2LIN | CENTR2LIN)#define CHB3D6C 0x80// Legacy Control/Status Register+2 (16h)#define DAC2SPDO 0x20#define SPDCOPYRHT 0x40#define ENSPDOUT 0x80// Legacy Control/Status Register+3 (17h)#define FMSEL 0x03#define VSBSEL 0x0c#define VMPU 0x60#define NXCHG 0x80// Miscellaneous Control Register (18h)#define REAR2LIN 0x20#define MUTECH1 0x40#define ENCENTER 0x80// Miscellaneous Control Register+1 (19h)#define SELSPDIFI2 0x01#define SPDF_AC97 0x80// Miscellaneous Control Register+2 (1ah)#define AC3_EN 0x04#define FM_EN 0x08#define SPD32SEL 0x20#define XCHGDAC 0x40#define ENDBDAC 0x80// Miscellaneous Control Register+3 (1bh)#define SPDIFI48K 0x01#define SPDO5V 0x02#define N4SPK3D 0x04#define RESET 0x40#define PWD 0x80#define SPDIF48K (SPDIFI48K << 24 | SPDF_AC97 << 8)// Mixer1 (24h)#define CDPLAY 0x01#define X3DEN 0x02#define REAR2FRONT 0x10#define SPK4 0x20#define WSMUTE 0x40#define FMMUTE 0x80// Miscellaneous Register (27h)#define SPDVALID 0x02#define CENTR2MIC 0x04// Miscellaneous Register2 (92h)#define SPD32KFMT 0x10#define CM_CFMT_DACSHIFT 2#define CM_CFMT_ADCSHIFT 0#define CM_FREQ_DACSHIFT 5#define CM_FREQ_ADCSHIFT 2#define RSTDAC RST_CH1#define RSTADC RST_CH0#define ENDAC CHEN1#define ENADC CHEN0#define PAUSEDAC PAUSE1#define PAUSEADC PAUSE0#define CODEC_CMI_ADC_FRAME1 CODEC_CMI_CH0_FRAME1#define CODEC_CMI_ADC_FRAME2 CODEC_CMI_CH0_FRAME2#define CODEC_CMI_DAC_FRAME1 CODEC_CMI_CH1_FRAME1#define CODEC_CMI_DAC_FRAME2 CODEC_CMI_CH1_FRAME2#define DACINT CHINT1#define ADCINT CHINT0#define DACBUSY CH1BUSY#define ADCBUSY CH0BUSY#define ENDACINT CH1_INT_EN#define ENADCINT CH0_INT_ENstatic const unsigned sample_size[] = { 1, 2, 2, 4 };static const unsigned sample_shift[] = { 0, 1, 1, 2 };#define SND_DEV_DSP16 5#define NR_DEVICE 3 /* maximum number of devices */#define set_dac1_rate set_adc_rate#define set_dac1_rate_unlocked set_adc_rate_unlocked#define stop_dac1 stop_adc#define stop_dac1_unlocked stop_adc_unlocked#define get_dmadac1 get_dmaadcstatic unsigned int devindex = 0;//*********************************************/struct cm_state { /* magic */ unsigned int magic; /* list of cmedia devices */ struct list_head devs; /* the corresponding pci_dev structure */ struct pci_dev *dev; int dev_audio; /* soundcore stuff */ int dev_mixer; unsigned int iosb, iobase, iosynth, iomidi, iogame, irq; /* hardware resources */ unsigned short deviceid; /* pci_id */ struct { /* mixer stuff */ unsigned int modcnt; unsigned short vol[13]; } mix; unsigned int rateadc, ratedac; /* wave stuff */ unsigned char fmt, enable; 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; unsigned hwptr, swptr; unsigned total_bytes; int count; unsigned error; /* over/underrun */ wait_queue_head_t wait; unsigned fragsize; /* redundant, but makes calculations easier */ unsigned dmasize; unsigned fragsamples; unsigned dmasamples; unsigned mapped:1; /* OSS stuff */ unsigned ready:1; unsigned endcleared:1; unsigned enabled:1; unsigned ossfragshift; int ossmaxfrags; unsigned subdivision; } dma_dac, dma_adc;#ifdef CONFIG_SOUND_CMPCI_MIDI int midi_devc; struct address_info mpu_data;#endif#ifdef CONFIG_SOUND_CMPCI_JOYSTICK struct gameport gameport;#endif int chip_version; int max_channels; int curr_channels; int capability; /* HW capability, various for chip versions */ int status; /* HW or SW state */ int spdif_counter; /* spdif frame counter */};/* flags used for capability */#define CAN_AC3_HW 0x00000001 /* 037 or later */#define CAN_AC3_SW 0x00000002 /* 033 or later */#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW)#define CAN_DUAL_DAC 0x00000004 /* 033 or later */#define CAN_MULTI_CH_HW 0x00000008 /* 039 or later */#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC)#define CAN_LINE_AS_REAR 0x00000010 /* 033 or later */#define CAN_LINE_AS_BASS 0x00000020 /* 039 or later */#define CAN_MIC_AS_BASS 0x00000040 /* 039 or later *//* flags used for status */#define DO_AC3_HW 0x00000001#define DO_AC3_SW 0x00000002#define DO_AC3 (DO_AC3_HW | DO_AC3_SW)#define DO_DUAL_DAC 0x00000004#define DO_MULTI_CH_HW 0x00000008
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -