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

📄 cmpci.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************//* *      cmpci.c  --  C-Media PCI audio driver. * *      Copyright (C) 1999  ChenLi Tien (cltien@cmedia.com.tw) *      		    C-media support (support@cmedia.com.tw) * *      Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch) * * 	For update, visit: * 		http://members.home.net/puresoft/cmedia.html * 		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 * *//*****************************************************************************/      #include <linux/version.h>#include <linux/config.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/wrapper.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/hardirq.h>#include <linux/bitops.h>#include "dm.h"/* --------------------------------------------------------------------- */#undef OSS_DOCUMENTED_MIXER_SEMANTICS#undef DMABYTEIO/* --------------------------------------------------------------------- */#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_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 CM_CH0_RESET			0x04#define CM_CH1_RESET			0x08#define CM_EXTENT_CODEC			0x100#define CM_EXTENT_MIDI			0x2#define CM_EXTENT_SYNTH			0x4#define CM_INT_CH0			1#define CM_INT_CH1			2#define CM_CFMT_STEREO			0x01#define CM_CFMT_16BIT			0x02#define CM_CFMT_MASK			0x03#define CM_CFMT_DACSHIFT		2#define CM_CFMT_ADCSHIFT		0static const unsigned sample_shift[]	= { 0, 1, 1, 2 };#define CM_ENABLE_CH1      0x2#define CM_ENABLE_CH0      0x1/* MIDI buffer sizes **************************/#define MIDIINBUF  256#define MIDIOUTBUF 256#define FMODE_MIDI_SHIFT 2#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)#define FMODE_DMFM 0x10#define SND_DEV_DSP16   5 #define NR_DEVICE 3		/* maximum number of devices *//*********************************************/struct cm_state {	unsigned int magic;		/* magic */	struct cm_state *next;		/* we keep cm cards in a linked list */	int dev_audio;			/* soundcore stuff */	int dev_mixer;	int dev_midi;	int dev_dmfm;	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;		unsigned rawphys;		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 ossfragshift;		int ossmaxfrags;		unsigned subdivision;	} dma_dac, dma_adc;	struct {			/* midi stuff */		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;		int	chip_version;			int	max_channels;	int	curr_channels;			int	speakers;		/* number of speakers */	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#define	DO_MULTI_CH		(DO_MULTI_CH_HW | DO_DUAL_DAC)#define	DO_LINE_AS_REAR		0x00000010		/* 033 or later */#define	DO_LINE_AS_BASS		0x00000020		/* 039 or later */#define	DO_MIC_AS_BASS		0x00000040		/* 039 or later */#define	DO_SPDIF_OUT		0x00000100#define	DO_SPDIF_IN		0x00000200#define	DO_SPDIF_LOOP		0x00000400static struct cm_state *devs;static unsigned long wavetable_mem;/* --------------------------------------------------------------------- */static inline unsigned ld2(unsigned int x){	unsigned exp=16,l=5,r=0;	static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000};	/* num: 2, 4, 16, 256, 65536 */	/* exp: 1, 2,  4,   8,    16 */		while(l--) {		if( x >= num[l] ) {			if(num[l]>2) x >>= exp;			r+=exp;		}		exp>>=1;	}	return r;}/* --------------------------------------------------------------------- */static void maskb(unsigned int addr, unsigned int mask, unsigned int value){	outb((inb(addr) & mask) | value, addr);}static void maskw(unsigned int addr, unsigned int mask, unsigned int value){	outw((inw(addr) & mask) | value, addr);}static void maskl(unsigned int addr, unsigned int mask, unsigned int value){	outl((inl(addr) & mask) | value, addr);}static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count){	if (addr)	    outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~1, 0);}static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count){	outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 1);}static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count){	outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);	outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2);	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 0);	if (s->status & DO_DUAL_DAC)		set_dmadac1(s, 0, count);}static void set_countadc(struct cm_state *s, unsigned count){	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);}static void set_countdac(struct cm_state *s, unsigned count){	outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);	if (s->status & DO_DUAL_DAC)	    set_countadc(s, count);}static inline unsigned get_dmadac(struct cm_state *s){	unsigned int curr_addr;	curr_addr = inw(s->iobase + CODEC_CMI_CH1_FRAME2) + 1;	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];	curr_addr = s->dma_dac.dmasize - curr_addr;	return curr_addr;}static inline unsigned get_dmaadc(struct cm_state *s){	unsigned int curr_addr;	curr_addr = inw(s->iobase + CODEC_CMI_CH0_FRAME2) + 1;	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];	curr_addr = s->dma_adc.dmasize - curr_addr;	return curr_addr;}static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data){	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	outb(data, s->iobase + CODEC_SB16_DATA);	udelay(10);}static unsigned char rdmixer(struct cm_state *s, unsigned char idx){	unsigned char v;	unsigned long flags;		spin_lock_irqsave(&s->lock, flags);	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	v = inb(s->iobase + CODEC_SB16_DATA);	udelay(10);	spin_unlock_irqrestore(&s->lock, flags);	return v;}static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data){	if (mask)	{		s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);		udelay(10);	}	s->fmt = (s->fmt & mask) | data;	outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);	udelay(10);}

⌨️ 快捷键说明

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