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

📄 cs4281.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
//*****************************************************************************////      "cs4281.c" --  Cirrus Logic-Crystal CS4281 linux audio driver.////      Copyright (C) 2000  Cirrus Logic Corp.  //            -- adapted from drivers by Thomas Sailer, //            -- but don't bug him; Problems should go to://            -- gw boynton (wesb@crystal.cirrus.com) or//            -- tom woller (twoller@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()//// *****************************************************************************#include <linux/config.h>#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/malloc.h>#include <linux/soundcard.h>#include <linux/pci.h>#include <linux/bitops.h>#include <linux/spinlock.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/smp_lock.h>#include <linux/wrapper.h>#include <asm/uaccess.h>#include <asm/hardirq.h>//#include <linux/vmalloc.h>#include "dm.h"#include "cs4281_hwdefs.h"EXPORT_NO_SYMBOLS;#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)// Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG//#define CSDEBUG_INTERFACE 1#define CSDEBUG 1//// 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 CSDEBUGextern unsigned long cs_debugmask;extern unsigned long cs_debuglevel;#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}#else#define CS_DBGOUT(mask,level,x)#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_TMP		0x10000000	// tmp debug mask bit#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 values#if MODULEMODULE_PARM(cs_debuglevel, "i");MODULE_PARM(cs_debugmask, "i");#endif#endif// 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 RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \	 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \	 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)#define CS4281_MAJOR_VERSION 	1#define CS4281_MINOR_VERSION 	1#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 1struct 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;	// soundcore stuff 	int dev_audio;	int dev_mixer;	int dev_midi;	// hardware resources 	unsigned int pBA0phys, pBA1phys;	char *pBA0, *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 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;};#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 SNDCTL_DSP_CS_GETDBGLEVEL 	_SIOWR('P', 50, int)#define SNDCTL_DSP_CS_SETDBGLEVEL 	_SIOWR('P', 51, int)#define SNDCTL_DSP_CS_GETDBGMASK 	_SIOWR('P', 52, int)#define SNDCTL_DSP_CS_SETDBGMASK 	_SIOWR('P', 53, int)static void 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,			  printk("SOUND_PCM_READ_CHANNELS:\n"));		break;	case SOUND_PCM_READ_BITS:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n"));		break;	case SOUND_PCM_WRITE_FILTER:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SOUND_PCM_WRITE_FILTER:\n"));		break;	case SNDCTL_DSP_SETSYNCRO:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n"));		break;	case SOUND_PCM_READ_FILTER:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n"));		break;	case SNDCTL_DSP_CS_GETDBGMASK:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SNDCTL_DSP_CS_GETDBGMASK:\n"));		break;	case SNDCTL_DSP_CS_GETDBGLEVEL:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SNDCTL_DSP_CS_GETDBGLEVEL:\n"));		break;	case SNDCTL_DSP_CS_SETDBGMASK:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SNDCTL_DSP_CS_SETDBGMASK:\n"));		break;	case SNDCTL_DSP_CS_SETDBGLEVEL:		CS_DBGOUT(CS_IOCTL, 4,			  printk("SNDCTL_DSP_CS_SETDBGLEVEL:\n"));		break;	case SOUND_MIXER_PRIVATE1:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n"));		break;	case SOUND_MIXER_PRIVATE2:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n"));		break;	case SOUND_MIXER_PRIVATE3:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n"));		break;	case SOUND_MIXER_PRIVATE4:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n"));		break;	case SOUND_MIXER_PRIVATE5:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n"));		break;	case SOUND_MIXER_INFO:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n"));		break;	case SOUND_OLD_MIXER_INFO:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n"));		break;	default:		switch (_IOC_NR(x)) {		case SOUND_MIXER_VOLUME:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_VOLUME:\n"));			break;		case SOUND_MIXER_SPEAKER:			CS_DBGOUT(CS_IOCTL, 4,				  printk("SOUND_MIXER_SPEAKER:\n"));			break;		case SOUND_MIXER_RECLEV:			CS_DBGOUT(CS_IOCTL, 4,

⌨️ 快捷键说明

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