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

📄 cs46xx.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Crystal SoundFusion CS46xx driver * *	Copyright 1998-2000 Cirrus Logic Corporation <audio@crystal.cirrus.com> *	Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz> *	Copyright 2000 Alan Cox <alan@redhat.com> * *	The core of this code is taken from the ALSA project driver by  *	Jaroslav. Please send Jaroslav the credit for the driver and  *	report bugs in this port to <alan@redhat.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. * *	Current maintainers: *		Cirrus Logic Corporation, Thomas Woller (tw) *			<twoller@crystal.cirrus.com> *		Nils Faerber (nf) *			<nils@kernelconcepts.de> *		Thanks to David Pollard for testing. * *	Changes: *	20000909-nf	Changed cs_read, cs_write and drain_dac *	20001025-tw	Separate Playback/Capture structs and buffers. *			Added Scatter/Gather support for Playback. *			Added Capture. *	20001027-nf	Port to kernel 2.4.0-test9, some clean-ups *			Start of powermanagement support (CS46XX_PM). *	20001128-tw	Add module parm for default buffer order. *			added DMA_GFP flag to kmalloc dma buffer allocs. *			backfill silence to eliminate stuttering on *			underruns. *	20001201-tw	add resyncing of swptr on underruns. *	20001205-tw-nf	fixed GETOSPACE ioctl() after open() * * *	Status: *	Playback/Capture supported from 8k-48k. *	16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported. */ #include <linux/module.h>#include <linux/version.h>#include <linux/string.h>#include <linux/ctype.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>#ifdef CS46XX_PM#include <linux/pm.h>#endif#include <asm/io.h>#include <asm/dma.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/ac97_codec.h>#include <linux/wrapper.h>#include <asm/uaccess.h>#include <asm/hardirq.h>#include "cs461x.h"/* MIDI buffer sizes */#define CS_MIDIINBUF  500#define CS_MIDIOUTBUF 500#define ADC_RUNNING	1#define DAC_RUNNING	2#define CS_FMT_16BIT	1		/* These are fixed in fact */#define CS_FMT_STEREO	2#define CS_FMT_MASK	3#define CS_TYPE_ADC	1#define CS_TYPE_DAC	2/* *	CS461x definitions */ #define CS461X_BA0_SIZE		0x2000#define CS461X_BA1_DATA0_SIZE	0x3000#define CS461X_BA1_DATA1_SIZE	0x3800#define CS461X_BA1_PRG_SIZE	0x7000#define CS461X_BA1_REG_SIZE	0x0100#define GOF_PER_SEC	200#define CSDEBUG_INTERFACE 1#define CSDEBUG 1/* * Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG * * * 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/* * 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-9 */static unsigned long cs_debugmask=CS_INIT | CS_ERROR;	/* use CS_DBGOUT with various mask values */#endif#define DMABUF_DEFAULTORDER 3static unsigned long defaultorder=DMABUF_DEFAULTORDER;#if MODULEMODULE_PARM(defaultorder, "i");MODULE_PARM(cs_debuglevel, "i");MODULE_PARM(cs_debugmask, "i");#endifstatic int external_amp = 0;static int thinkpad = 0;/* An instance of the 4610 channel */struct cs_channel {	int used;	int num;	void *state;};#define DRIVER_VERSION "1.10"/* magic numbers to protect our data structures */#define CS_CARD_MAGIC		0x43525553 /* "CRUS" */#define CS_STATE_MAGIC		0x4c4f4749 /* "LOGI" */#define NR_HW_CH		3/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */#define NR_AC97		2static const unsigned sample_size[] = { 1, 2, 2, 4 };static const unsigned sample_shift[] = { 0, 1, 1, 2 };/* "software" or virtual channel, an instance of opened /dev/dsp */struct cs_state {	unsigned int magic;	struct cs_card *card;	/* Card info */	/* single open lock mechanism, only used for recording */	struct semaphore open_sem;	wait_queue_head_t open_wait;	/* file mode */	mode_t open_mode;	/* virtual channel number */	int virt;		struct dmabuf {		/* wave sample stuff */		unsigned int rate;		unsigned char fmt, enable;		/* hardware channel */		struct cs_channel *channel;		int pringbuf;		/* Software ring slot */		void *pbuf;		/* 4K hardware DMA buffer */		/* OSS buffer management stuff */		void *rawbuf;		dma_addr_t dma_handle;		unsigned buforder;		unsigned numfrag;		unsigned fragshift;		unsigned divisor;		unsigned type;		void *tmpbuff;			/* tmp buffer for sample conversions */		dma_addr_t dma_handle_tmpbuff;		unsigned buforder_tmpbuff;	/* Log base 2 of size in bytes.. */		/* our buffer acts like a circular ring */		unsigned hwptr;		/* where dma last started, updated by update_ptr */		unsigned swptr;		/* where driver last clear/filled, updated by read/write */		int count;		/* bytes to be comsumed or been generated by dma machine */		unsigned total_bytes;	/* total bytes dmaed by hardware */		unsigned blocks;	/* total blocks */		unsigned error;		/* number of over/underruns */		unsigned underrun;	/* underrun pending before next write has occurred */		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */		/* redundant, but makes calculations easier */		unsigned fragsize;		unsigned dmasize;		unsigned fragsamples;		/* OSS stuff */		unsigned mapped:1;		unsigned ready:1;		unsigned endcleared:1;		unsigned SGok:1;		unsigned update_flag;		unsigned ossfragshift;		int ossmaxfrags;		unsigned subdivision;	} dmabuf;};struct cs_card {	struct cs_channel channel[2];	unsigned int magic;	/* We keep cs461x cards in a linked list */	struct cs_card *next;	/* The cs461x has a certain amount of cross channel interaction	   so we use a single per card lock */	spinlock_t lock;	/* PCI device stuff */	struct pci_dev * pci_dev;	unsigned int pctl, cctl;	/* Hardware DMA flag sets */	/* soundcore stuff */	int dev_audio;	int dev_midi;	/* structures for abstraction of hardware facilities, codecs, banks and channels*/	struct ac97_codec *ac97_codec[NR_AC97];	struct cs_state *states[2];	u16 ac97_features;		int amplifier;			/* Amplifier control */	void (*amplifier_ctrl)(struct cs_card *, int);		int active;			/* Active clocking */	void (*active_ctrl)(struct cs_card *, int);		/* hardware resources */	unsigned long ba0_addr;	unsigned long ba1_addr;	u32 irq;		/* mappings */	void *ba0;	union	{		struct		{			u8 *data0;			u8 *data1;			u8 *pmem;			u8 *reg;		} name;		u8 *idx[4];	} ba1;		/* Function support */	struct cs_channel *(*alloc_pcm_channel)(struct cs_card *);	struct cs_channel *(*alloc_rec_pcm_channel)(struct cs_card *);	void (*free_pcm_channel)(struct cs_card *, int chan);	/* /dev/midi stuff */	struct {		unsigned ird, iwr, icnt;		unsigned ord, owr, ocnt;		wait_queue_head_t open_wait;		wait_queue_head_t iwait;		wait_queue_head_t owait;		spinlock_t lock;		unsigned char ibuf[CS_MIDIINBUF];		unsigned char obuf[CS_MIDIOUTBUF];		mode_t open_mode;		struct semaphore open_sem;	} midi;};static struct cs_card *devs = NULL;static int cs_open_mixdev(struct inode *inode, struct file *file);static int cs_release_mixdev(struct inode *inode, struct file *file);static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,				unsigned long arg);static loff_t cs_llseek(struct file *file, loff_t offset, int origin);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;}#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;	/* these values are incorrect for the ac97 driver, fix.         * 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: ") );		break;	case SOUND_MIXER_CS_GETDBGLEVEL:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGLEVEL: ") );		break;	case SOUND_MIXER_CS_SETDBGMASK:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGMASK: ") );		break;	case SOUND_MIXER_CS_SETDBGLEVEL:		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGLEVEL: ") );		break;        case OSS_GETVERSION:		CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION: ") );		break;        case SNDCTL_DSP_SYNC:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC: ") );		break;        case SNDCTL_DSP_SETDUPLEX:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX: ") );		break;        case SNDCTL_DSP_GETCAPS:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS: ") );		break;        case SNDCTL_DSP_RESET:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET: ") );		break;        case SNDCTL_DSP_SPEED:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED: ") );		break;        case SNDCTL_DSP_STEREO:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO: ") );		break;        case SNDCTL_DSP_CHANNELS:		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS: ") );		break;

⌨️ 快捷键说明

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