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

📄 cmpci.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************//* *      cmpci.c  --  C-Media PCI audio driver. * *      Copyright (C) 1999  ChenLi Tien (cltien@home.com) * *	Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch) * *      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 *    20 09 99   0.13  merged the generic changes in sonicvibes since this *		       diverged. *    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. *    $Log: cmpci.c,v $ *    Revision 2.41  1999/10/27 02:00:05  cltien *    Now the fragsize for modem is activated by parameter. * *    Revision 2.40  1999/10/26 23:38:26  cltien *    Remove debugging message in cm_write which may cause module counter not 0. * *    Revision 2.39  1999/10/26 21:52:50  cltien *    I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO. *    Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer. * *    Revision 2.38  1999/10/08 21:59:03  cltien *    Set FLINKON and reset FLINKOFF for modem. * *    Revision 2.37  1999/09/28 02:57:04  cltien *    Add set_bus_master() to make sure bus master enabled. * *    Revision 2.36  1999/09/22 14:15:03  cltien *    Use open_sem to avoid multiple access to open_mode. *    Use wakeup in IntrClose to activate process in waiting queue. * *    Revision 2.35  1999/09/22 13:20:53  cltien *    Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely. * *    Revision 2.34  1999/09/22 03:29:57  cltien *    Use module count to decide which one to access the dac. * * */ /*****************************************************************************/      #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/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 "dm.h"/* --------------------------------------------------------------------- */#undef OSS_DOCUMENTED_MIXER_SEMANTICS/* --------------------------------------------------------------------- */#ifndef PCI_VENDOR_ID_CMEDIA#define PCI_VENDOR_ID_CMEDIA         0x13F6#endif#ifndef PCI_DEVICE_ID_CMEDIA_CM8338A#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100#endif#ifndef PCI_DEVICE_ID_CMEDIA_CM8338B#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101#endif#ifndef PCI_DEVICE_ID_CMEDIA_CM8738#define PCI_DEVICE_ID_CMEDIA_CM8738  0x0111#endif#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)#define UCHAR	unsigned char/***  Mixer registers for SB16*/#define DSP_MIX_DATARESETIDX    ((UCHAR)(0x00))#define DSP_MIX_MASTERVOLIDX_L  ((UCHAR)(0x30))#define DSP_MIX_MASTERVOLIDX_R  ((UCHAR)(0x31))#define DSP_MIX_VOICEVOLIDX_L   ((UCHAR)(0x32))#define DSP_MIX_VOICEVOLIDX_R   ((UCHAR)(0x33))#define DSP_MIX_FMVOLIDX_L      ((UCHAR)(0x34))#define DSP_MIX_FMVOLIDX_R      ((UCHAR)(0x35))#define DSP_MIX_CDVOLIDX_L      ((UCHAR)(0x36))#define DSP_MIX_CDVOLIDX_R      ((UCHAR)(0x37))#define DSP_MIX_LINEVOLIDX_L    ((UCHAR)(0x38))#define DSP_MIX_LINEVOLIDX_R    ((UCHAR)(0x39))#define DSP_MIX_MICVOLIDX       ((UCHAR)(0x3A))#define DSP_MIX_SPKRVOLIDX      ((UCHAR)(0x3B))#define DSP_MIX_OUTMIXIDX       ((UCHAR)(0x3C))#define DSP_MIX_ADCMIXIDX_L     ((UCHAR)(0x3D))#define DSP_MIX_ADCMIXIDX_R     ((UCHAR)(0x3E))#define DSP_MIX_INGAINIDX_L     ((UCHAR)(0x3F))#define DSP_MIX_INGAINIDX_R     ((UCHAR)(0x40))#define DSP_MIX_OUTGAINIDX_L    ((UCHAR)(0x41))#define DSP_MIX_OUTGAINIDX_R    ((UCHAR)(0x42))#define DSP_MIX_AGCIDX          ((UCHAR)(0x43))#define DSP_MIX_TREBLEIDX_L     ((UCHAR)(0x44))#define DSP_MIX_TREBLEIDX_R     ((UCHAR)(0x45))#define DSP_MIX_BASSIDX_L       ((UCHAR)(0x46))#define DSP_MIX_BASSIDX_R       ((UCHAR)(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   0   #define CM_CFMT_ADCSHIFT   2static const unsigned sample_size[] = { 1, 2, 2, 4 };static const unsigned sample_shift[] = { 0, 1, 1, 2 };#define CM_CENABLE_RE      0x2#define CM_CENABLE_PE      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/* --------------------------------------------------------------------- */struct cm_state {	/* magic */	unsigned int magic;	/* we keep cm cards in a linked list */	struct cm_state *next;	/* soundcore stuff */	int dev_audio;	int dev_mixer;	int dev_midi;	int dev_dmfm;	/* hardware resources */	unsigned int iosb, iobase, iosynth, iomidi, iogame, irq;        /* mixer stuff */        struct {                unsigned int modcnt;#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS		unsigned short vol[13];#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */        } mix;	/* wave stuff */	unsigned int rateadc, ratedac;	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 buforder;		unsigned numfrag;		unsigned fragshift;		unsigned hwptr, swptr;		unsigned total_bytes;		int count;		unsigned error; /* over/underrun */		wait_queue_head_t wait;		/* redundant, but makes calculations easier */		unsigned fragsize;		unsigned dmasize;		unsigned fragsamples;		unsigned dmasamples;		/* OSS stuff */		unsigned mapped:1;		unsigned ready:1;		unsigned endcleared:1;		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;};/* --------------------------------------------------------------------- */static struct cm_state *devs = NULL;static unsigned long wavetable_mem = 0;/* --------------------------------------------------------------------- */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;}/* * hweightN: returns the hamming weight (i.e. the number * of bits set) of a N-bit word */#ifdef hweight32#undef hweight32#endifextern __inline__ unsigned int hweight32(unsigned int w){        unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);        res = (res & 0x33333333) + ((res >> 2) & 0x33333333);        res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);        res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);        return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);}/* --------------------------------------------------------------------- */static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count){	count--;	outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);	outw(count, s->iobase + CODEC_CMI_CH0_FRAME2);	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0);//	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);}static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count){	count--;	outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);	outw(count, s->iobase + CODEC_CMI_CH1_FRAME2);	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0);//	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);}extern __inline__ unsigned get_dmadac(struct cm_state *s){	unsigned int curr_addr;	if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE))		return 0;	curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);	curr_addr -= virt_to_bus(s->dma_dac.rawbuf);	curr_addr = s->dma_dac.dmasize - curr_addr;	curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]-1);	return curr_addr;}extern __inline__ unsigned get_dmaadc(struct cm_state *s){	unsigned int curr_addr;	if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE))		return 0;	curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);	curr_addr -= virt_to_bus(s->dma_adc.rawbuf);	curr_addr = s->dma_adc.dmasize - curr_addr;	curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]-1);	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;	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	v = inb(s->iobase + CODEC_SB16_DATA);	udelay(10);	return v;}static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	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);	spin_unlock_irqrestore(&s->lock, flags);	udelay(10);}static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data){	outb(idx, s->iobase + CODEC_SB16_ADDR);	udelay(10);	outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);	udelay(10);}static struct {	unsigned	rate;	unsigned	lower;	unsigned	upper;

⌨️ 快捷键说明

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