⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs4281m.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/*********************************************************************************      "cs4281.c" --  Cirrus Logic-Crystal CS4281 linux audio driver.**      Copyright (C) 2000,2001  Cirrus Logic Corp.  *            -- adapted from drivers by Thomas Sailer, *            -- but don't bug him; Problems should go to:*            -- tom woller (twoller@crystal.cirrus.com) or*               (audio@crystal.cirrus.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 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.** Module command line parameters:*   none**  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** Modification History* 08/20/00 trw - silence and no stopping DAC until release* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop.* 09/18/00 trw - added 16bit only record with conversion * 09/24/00 trw - added Enhanced Full duplex (separate simultaneous *                capture/playback rates)* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin  *                libOSSm.so)* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal)* 11/03/00 trw - fixed interrupt loss/stutter, added debug.* 11/10/00 bkz - added __devinit to cs4281_hw_init()* 11/10/00 trw - fixed SMP and capture spinlock hang.* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm.* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix.* 12/08/00 trw - added PM support. * 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 *		 (RH/Dell base), 2.2.18, 2.2.12.  cleaned up code mods by ident.* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup.* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use *		 defaultorder-100 as power of 2 for the buffer size. example:*		 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.********************************************************************************//* uncomment the following line to disable building PM support into the driver *///#define NOT_CS4281_PM 1 #include <linux/list.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/bitops.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/poll.h>#include <linux/fs.h>#include <linux/wait.h>#include <asm/current.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/page.h>#include <asm/uaccess.h>//#include "cs_dm.h"#include "cs4281_hwdefs.h"#include "cs4281pm.h"struct cs4281_state;static void stop_dac(struct cs4281_state *s);static void stop_adc(struct cs4281_state *s);static void start_dac(struct cs4281_state *s);static void start_adc(struct cs4281_state *s);#undef OSS_DOCUMENTED_MIXER_SEMANTICS// --------------------------------------------------------------------- #ifndef PCI_VENDOR_ID_CIRRUS#define PCI_VENDOR_ID_CIRRUS          0x1013#endif#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281#define PCI_DEVICE_ID_CRYSTAL_CS4281  0x6005#endif#define CS4281_MAGIC  ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)#define	CS4281_CFLR_DEFAULT	0x00000001  /* CFLR must be in AC97 link mode */// buffer order determines the size of the dma buffer for the driver.// under Linux, a smaller buffer allows more responsiveness from many of the // applications (e.g. games).  A larger buffer allows some of the apps (esound) // to not underrun the dma buffer as easily.  As default, use 32k (order=3)// rather than 64k as some of the games work more responsively.// log base 2( buff sz = 32k).static unsigned long defaultorder = 3;module_param(defaultorder, ulong, 0);//// Turn on/off debugging compilation by commenting out "#define CSDEBUG"//#define CSDEBUG 1#if CSDEBUG#define CSDEBUG_INTERFACE 1#else#undef CSDEBUG_INTERFACE#endif//// cs_debugmask areas//#define CS_INIT	 	0x00000001	// initialization and probe functions#define CS_ERROR 	0x00000002	// tmp debugging bit placeholder#define CS_INTERRUPT	0x00000004	// interrupt handler (separate from all other)#define CS_FUNCTION 	0x00000008	// enter/leave functions#define CS_WAVE_WRITE 	0x00000010	// write information for wave#define CS_WAVE_READ 	0x00000020	// read information for wave#define CS_MIDI_WRITE 	0x00000040	// write information for midi#define CS_MIDI_READ 	0x00000080	// read information for midi#define CS_MPU401_WRITE 0x00000100	// write information for mpu401#define CS_MPU401_READ 	0x00000200	// read information for mpu401#define CS_OPEN		0x00000400	// all open functions in the driver#define CS_RELEASE	0x00000800	// all release functions in the driver#define CS_PARMS	0x00001000	// functional and operational parameters#define CS_IOCTL	0x00002000	// ioctl (non-mixer)#define CS_PM		0x00004000	// power management #define CS_TMP		0x10000000	// tmp debug mask bit#define CS_IOCTL_CMD_SUSPEND	0x1	// suspend#define CS_IOCTL_CMD_RESUME	0x2	// resume//// CSDEBUG is usual mode is set to 1, then use the// cs_debuglevel and cs_debugmask to turn on or off debugging.// Debug level of 1 has been defined to be kernel errors and info// that should be printed on any released driver.//#if CSDEBUG#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}#else#define CS_DBGOUT(mask,level,x)#endif#if CSDEBUGstatic unsigned long cs_debuglevel = 1;	// levels range from 1-9static unsigned long cs_debugmask = CS_INIT | CS_ERROR;	// use CS_DBGOUT with various mask valuesmodule_param(cs_debuglevel, ulong, 0);module_param(cs_debugmask, ulong, 0);#endif#define CS_TRUE 	1#define CS_FALSE 	0// MIDI buffer sizes #define MIDIINBUF  500#define MIDIOUTBUF 500#define FMODE_MIDI_SHIFT 3#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)#define CS4281_MAJOR_VERSION 	1#define CS4281_MINOR_VERSION 	13#ifdef __ia64__#define CS4281_ARCH	     	64	//architecture key#else#define CS4281_ARCH	     	32	//architecture key#endif#define CS_TYPE_ADC 0#define CS_TYPE_DAC 1static const char invalid_magic[] =    KERN_CRIT "cs4281: invalid magic value\n";#define VALIDATE_STATE(s)                         \({                                                \        if (!(s) || (s)->magic != CS4281_MAGIC) { \                printk(invalid_magic);            \                return -ENXIO;                    \        }                                         \})//LIST_HEAD(cs4281_devs);static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs };struct cs4281_state; #include "cs4281_wrapper-24.c"struct cs4281_state {	// magic 	unsigned int magic;	// we keep the cards in a linked list 	struct cs4281_state *next;	// pcidev is needed to turn off the DDMA controller at driver shutdown 	struct pci_dev *pcidev;	struct list_head list;	// soundcore stuff 	int dev_audio;	int dev_mixer;	int dev_midi;	// hardware resources 	unsigned int pBA0phys, pBA1phys;	char __iomem *pBA0;	char __iomem *pBA1;	unsigned int irq;	// mixer registers 	struct {		unsigned short vol[10];		unsigned int recsrc;		unsigned int modcnt;		unsigned short micpreamp;	} mix;	// wave stuff   	struct properties {		unsigned fmt;		unsigned fmt_original;	// original requested format		unsigned channels;		unsigned rate;		unsigned char clkdiv;	} prop_dac, prop_adc;	unsigned conversion:1;	// conversion from 16 to 8 bit in progress	void *tmpbuff;		// tmp buffer for sample conversions	unsigned ena;	spinlock_t lock;	struct semaphore open_sem;	struct semaphore open_sem_adc;	struct semaphore open_sem_dac;	mode_t open_mode;	wait_queue_head_t open_wait;	wait_queue_head_t open_wait_adc;	wait_queue_head_t open_wait_dac;	dma_addr_t dmaaddr_tmpbuff;	unsigned buforder_tmpbuff;	// Log base 2 of 'rawbuf' size in bytes..	struct dmabuf {		void *rawbuf;	// Physical address of  		dma_addr_t dmaaddr;		unsigned buforder;	// Log base 2 of 'rawbuf' size in bytes..		unsigned numfrag;	// # of 'fragments' in the buffer.		unsigned fragshift;	// Log base 2 of fragment size.		unsigned hwptr, swptr;		unsigned total_bytes;	// # bytes process since open.		unsigned blocks;	// last returned blocks value GETOPTR		unsigned wakeup;	// interrupt occurred on block 		int count;		unsigned underrun;	// underrun flag		unsigned error;	// over/underrun 		wait_queue_head_t wait;		// redundant, but makes calculations easier 		unsigned fragsize;	// 2**fragshift..		unsigned dmasize;	// 2**buforder.		unsigned fragsamples;		// OSS stuff 		unsigned mapped:1;	// Buffer mapped in cs4281_mmap()?		unsigned ready:1;	// prog_dmabuf_dac()/adc() successful?		unsigned endcleared:1;		unsigned type:1;	// adc or dac buffer (CS_TYPE_XXX)		unsigned ossfragshift;		int ossmaxfrags;		unsigned subdivision;	} dma_dac, dma_adc;	// midi stuff 	struct {		unsigned ird, iwr, icnt;		unsigned ord, owr, ocnt;		wait_queue_head_t iwait;		wait_queue_head_t owait;		struct timer_list timer;		unsigned char ibuf[MIDIINBUF];		unsigned char obuf[MIDIOUTBUF];	} midi;	struct cs4281_pm pm;	struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];};#include <linux/pm_legacy.h>#include "cs4281pm-24.c"#if CSDEBUG// DEBUG ROUTINES#define SOUND_MIXER_CS_GETDBGLEVEL 	_SIOWR('M',120, int)#define SOUND_MIXER_CS_SETDBGLEVEL 	_SIOWR('M',121, int)#define SOUND_MIXER_CS_GETDBGMASK 	_SIOWR('M',122, int)#define SOUND_MIXER_CS_SETDBGMASK 	_SIOWR('M',123, int)#define SOUND_MIXER_CS_APM	 	_SIOWR('M',124, int)static void cs_printioctl(unsigned int x){	unsigned int i;	unsigned char vidx;	// Index of mixtable1[] member is Device ID 	// and must be <= SOUND_MIXER_NRDEVICES.	// Value of array member is index into s->mix.vol[]	static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {		[SOUND_MIXER_PCM] = 1,	// voice 		[SOUND_MIXER_LINE1] = 2,	// AUX		[SOUND_MIXER_CD] = 3,	// CD 		[SOUND_MIXER_LINE] = 4,	// Line 		[SOUND_MIXER_SYNTH] = 5,	// FM		[SOUND_MIXER_MIC] = 6,	// Mic 		[SOUND_MIXER_SPEAKER] = 7,	// Speaker 		[SOUND_MIXER_RECLEV] = 8,	// Recording level 		[SOUND_MIXER_VOLUME] = 9	// Master Volume 	};	switch (x) {	case SOUND_MIXER_CS_GETDBGMASK:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SOUND_MIXER_CS_GETDBGMASK:\n"));		break;	case SOUND_MIXER_CS_GETDBGLEVEL:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SOUND_MIXER_CS_GETDBGLEVEL:\n"));		break;	case SOUND_MIXER_CS_SETDBGMASK:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SOUND_MIXER_CS_SETDBGMASK:\n"));		break;	case SOUND_MIXER_CS_SETDBGLEVEL:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SOUND_MIXER_CS_SETDBGLEVEL:\n"));		break;	case OSS_GETVERSION:		CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n"));		break;	case SNDCTL_DSP_SYNC:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n"));		break;	case SNDCTL_DSP_SETDUPLEX:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n"));		break;	case SNDCTL_DSP_GETCAPS:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n"));		break;	case SNDCTL_DSP_RESET:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n"));		break;	case SNDCTL_DSP_SPEED:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n"));		break;	case SNDCTL_DSP_STEREO:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n"));		break;	case SNDCTL_DSP_CHANNELS:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n"));		break;	case SNDCTL_DSP_GETFMTS:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n"));		break;	case SNDCTL_DSP_SETFMT:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n"));		break;	case SNDCTL_DSP_POST:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n"));		break;	case SNDCTL_DSP_GETTRIGGER:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n"));		break;	case SNDCTL_DSP_SETTRIGGER:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n"));		break;	case SNDCTL_DSP_GETOSPACE:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n"));		break;	case SNDCTL_DSP_GETISPACE:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n"));		break;	case SNDCTL_DSP_NONBLOCK:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n"));		break;	case SNDCTL_DSP_GETODELAY:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n"));		break;	case SNDCTL_DSP_GETIPTR:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n"));		break;	case SNDCTL_DSP_GETOPTR:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n"));		break;	case SNDCTL_DSP_GETBLKSIZE:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n"));		break;	case SNDCTL_DSP_SETFRAGMENT:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SNDCTL_DSP_SETFRAGMENT:\n"));		break;	case SNDCTL_DSP_SUBDIVIDE:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n"));		break;	case SOUND_PCM_READ_RATE:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n"));		break;	case SOUND_PCM_READ_CHANNELS:		CS_DBGOUT(CS_IOCTL, 4,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -