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

📄 cmpci.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	unsigned char	freq;} rate_lookup[] ={	{ 5512,		(0 + 5512) / 2,		(5512 + 8000) / 2,	0 },	{ 8000,		(5512 + 8000) / 2,	(8000 + 11025) / 2,	4 },	{ 11025,	(8000 + 11025) / 2,	(11025 + 16000) / 2,	1 },	{ 16000,	(11025 + 16000) / 2,	(16000 + 22050) / 2,	5 },	{ 22050,	(16000 + 22050) / 2,	(22050 + 32000) / 2,	2 },	{ 32000,	(22050 + 32000) / 2,	(32000 + 44100) / 2,	6 },	{ 44100,	(32000 + 44100) / 2,	(44100 + 48000) / 2,	3 },	{ 48000,	(44100 + 48000) /2,	48000,			7 }};static void set_dac_rate(struct cm_state *s, unsigned rate){	unsigned long flags;	unsigned char freq = 4, val;	int	i;	if (rate > 48000)		rate = 48000;	if (rate < 5512)		rate = 5512;	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)	{		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)		{			rate = rate_lookup[i].rate;			freq = rate_lookup[i].freq;			break;	    	}	}	s->ratedac = rate;	freq <<= 2;	spin_lock_irqsave(&s->lock, flags);	val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0x1c; 	outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);	spin_unlock_irqrestore(&s->lock, flags);}static void set_adc_rate(struct cm_state *s, unsigned rate){	unsigned long flags;	unsigned char freq = 4, val;	int	i;	if (rate > 48000)		rate = 48000;	if (rate < 5512)		rate = 5512;	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)	{		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)		{			rate = rate_lookup[i].rate;			freq = rate_lookup[i].freq;			break;	    	}	}	s->rateadc = rate;	freq <<= 5;	spin_lock_irqsave(&s->lock, flags);	val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0xe0; 	outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);	spin_unlock_irqrestore(&s->lock, flags);}/* --------------------------------------------------------------------- */extern inline void stop_adc(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	/* disable channel */	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	s->enable &= ~CM_CENABLE_RE;	/* disable interrupt */	outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);	/* reset */	outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	udelay(10);	outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	spin_unlock_irqrestore(&s->lock, flags);}	extern inline void stop_dac(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	/* disable channel */	s->enable &= ~CM_CENABLE_PE;	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	/* disable interrupt */	outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);	/* reset */	outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	udelay(10);	outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	spin_unlock_irqrestore(&s->lock, flags);}	static void start_dac(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {		outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);		s->enable |= CM_CENABLE_PE;		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	}	spin_unlock_irqrestore(&s->lock, flags);}	static void start_adc(struct cm_state *s){	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 	    && s->dma_adc.ready) {		outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);		s->enable |= CM_CENABLE_RE;		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	}	spin_unlock_irqrestore(&s->lock, flags);}	/* --------------------------------------------------------------------- */#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)#define DMABUF_MINORDER 1static void dealloc_dmabuf(struct dmabuf *db){	struct page *pstart, *pend;	if (db->rawbuf) {		/* undo marking the pages as reserved */		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);		for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)			mem_map_unreserve(pstart);		free_pages((unsigned long)db->rawbuf, db->buforder);	}	db->rawbuf = NULL;	db->mapped = db->ready = 0;}/* Ch0 is used for playback, Ch1 is used for recording */static int prog_dmabuf(struct cm_state *s, unsigned rec){	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;	unsigned rate = rec ? s->rateadc : s->ratedac;	int order;	unsigned bytepersec;	unsigned bufs;	struct page *pstart, *pend;	unsigned char fmt;	unsigned long flags;	spin_lock_irqsave(&s->lock, flags);	fmt = s->fmt;	if (rec) {		s->enable &= ~CM_CENABLE_RE;		fmt >>= CM_CFMT_ADCSHIFT;	} else {		s->enable &= ~CM_CENABLE_PE;		fmt >>= CM_CFMT_DACSHIFT;	}	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);	spin_unlock_irqrestore(&s->lock, flags);	fmt &= CM_CFMT_MASK;	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;	if (!db->rawbuf) {		db->ready = db->mapped = 0;		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)			if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)))				break;		if (!db->rawbuf)			return -ENOMEM;		db->buforder = order;		if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)			printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 			       virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);		if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)			printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 			       virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);		for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)			mem_map_reserve(pstart);	}	bytepersec = rate << sample_shift[fmt];	bufs = PAGE_SIZE << db->buforder;	if (db->ossfragshift) {		if ((1000 << db->ossfragshift) < bytepersec)			db->fragshift = ld2(bytepersec/1000);		else			db->fragshift = db->ossfragshift;	} else {		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));		if (db->fragshift < 3)			db->fragshift = 3;	}	db->numfrag = bufs >> db->fragshift;	while (db->numfrag < 4 && db->fragshift > 3) {		db->fragshift--;		db->numfrag = bufs >> db->fragshift;	}	db->fragsize = 1 << db->fragshift;	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)		db->numfrag = db->ossmaxfrags; 	/* to make fragsize >= 4096 */#if 0 	 	if(s->modem) 	{	 	while (db->fragsize < 4096 && db->numfrag >= 4)		{			db->fragsize *= 2; 			db->fragshift++; 			db->numfrag /= 2; 		}	}#endif		db->fragsamples = db->fragsize >> sample_shift[fmt];	db->dmasize = db->numfrag << db->fragshift;	db->dmasamples = db->dmasize >> sample_shift[fmt];	memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);	spin_lock_irqsave(&s->lock, flags);	if (rec) {		set_dmaadc(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);		/* program sample counts */		outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);	} else {		set_dmadac(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);		/* program sample counts */		outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);	}	spin_unlock_irqrestore(&s->lock, flags);	db->ready = 1;	return 0;}extern __inline__ void clear_advance(struct cm_state *s){	unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;	unsigned char *buf = s->dma_dac.rawbuf;	unsigned bsize = s->dma_dac.dmasize;	unsigned bptr = s->dma_dac.swptr;	unsigned len = s->dma_dac.fragsize;	if (bptr + len > bsize) {		unsigned x = bsize - bptr;		memset(buf + bptr, c, x);		bptr = 0;		len -= x;	}	memset(buf + bptr, c, len);	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);}/* call with spinlock held! */static void cm_update_ptr(struct cm_state *s){	unsigned hwptr;	int diff;	/* update ADC pointer */	if (s->dma_adc.ready) {		hwptr = (s->dma_adc.dmasize - get_dmaadc(s)) % s->dma_adc.dmasize;		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;		s->dma_adc.hwptr = hwptr;		s->dma_adc.total_bytes += diff;		s->dma_adc.count += diff;		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 			wake_up(&s->dma_adc.wait);		if (!s->dma_adc.mapped) {			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {				s->enable &= ~CM_CENABLE_RE;				outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);				s->dma_adc.error++;			}		}	}	/* update DAC pointer */	if (s->dma_dac.ready) {		hwptr = (s->dma_dac.dmasize - get_dmadac(s)) % s->dma_dac.dmasize;		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;		s->dma_dac.hwptr = hwptr;		s->dma_dac.total_bytes += diff;		if (s->dma_dac.mapped) {			s->dma_dac.count += diff;			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)				wake_up(&s->dma_dac.wait);		} else {			s->dma_dac.count -= diff;			if (s->dma_dac.count <= 0) {				s->enable &= ~CM_CENABLE_PE;				outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);				s->dma_dac.error++;			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {				clear_advance(s);				s->dma_dac.endcleared = 1;			}			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)				wake_up(&s->dma_dac.wait);		}	}}/* hold spinlock for the following! */static void cm_handle_midi(struct cm_state *s){	unsigned char ch;	int wake;	wake = 0;	while (!(inb(s->iomidi+1) & 0x80)) {		ch = inb(s->iomidi);		if (s->midi.icnt < MIDIINBUF) {			s->midi.ibuf[s->midi.iwr] = ch;			s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;			s->midi.icnt++;		}		wake = 1;	}	if (wake)		wake_up(&s->midi.iwait);	wake = 0;	while (!(inb(s->iomidi+1) & 0x40) && s->midi.ocnt > 0) {		outb(s->midi.obuf[s->midi.ord], s->iomidi);		s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;		s->midi.ocnt--;		if (s->midi.ocnt < MIDIOUTBUF-16)			wake = 1;	}	if (wake)		wake_up(&s->midi.owait);}static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs){        struct cm_state *s = (struct cm_state *)dev_id;	unsigned int intsrc, intstat;		/* fastpath out, to ease interrupt sharing */	intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);	if (!(intsrc & 0x80000000))		return;	spin_lock(&s->lock);	intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);	/* acknowledge interrupt */	if (intsrc & CM_INT_CH0)	{		outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);		udelay(10);		outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);	}	if (intsrc & CM_INT_CH1)	{		outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);		udelay(10);		outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);	}	cm_update_ptr(s);	cm_handle_midi(s);	spin_unlock(&s->lock);}static void cm_midi_timer(unsigned long data){	struct cm_state *s = (struct cm_state *)data;	unsigned long flags;		spin_lock_irqsave(&s->lock, flags);	cm_handle_midi(s);	spin_unlock_irqrestore(&s->lock, flags);	s->midi.timer.expires = jiffies+1;	add_timer(&s->midi.timer);}/* --------------------------------------------------------------------- */static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";#ifdef CONFIG_SOUND_CMPCI	/* support multiple chips */#define VALIDATE_STATE(s)#else#define VALIDATE_STATE(s)                         \({                                                \	if (!(s) || (s)->magic != CM_MAGIC) { \		printk(invalid_magic);            \		return -ENXIO;                    \	}                                         \})#endif/* --------------------------------------------------------------------- */#define MT_4          1#define MT_5MUTE      2#define MT_4MUTEMONO  3#define MT_6MUTE      4#define MT_5MUTEMONO  5static const struct {	unsigned left;	unsigned right;	unsigned type;	unsigned rec;	unsigned play;} mixtable[SOUND_MIXER_NRDEVICES] = {	[SOUND_MIXER_CD]     = { DSP_MIX_CDVOLIDX_L,     DSP_MIX_CDVOLIDX_R,     MT_5MUTE,     0x04, 0x02 },	[SOUND_MIXER_LINE]   = { DSP_MIX_LINEVOLIDX_L,   DSP_MIX_LINEVOLIDX_R,   MT_5MUTE,     0x10, 0x08 },	[SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      DSP_MIX_MICVOLIDX,      MT_5MUTEMONO, 0x01, 0x01 },	[SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,  	 DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },	[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },	[SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 }};#ifdef OSS_DOCUMENTED_MIXER_SEMANTICSstatic int return_mixval(struct cm_state *s, unsigned i, int *arg){	unsigned long flags;	unsigned char l, r, rl, rr;	spin_lock_irqsave(&s->lock, flags);	l = rdmixer(s, mixtable[i].left);	r = rdmixer(s, mixtable[i].right);	spin_unlock_irqrestore(&s->lock, flags);	switch (mixtable[i].type) {	case MT_4:		r &= 0xf;		l &= 0xf;		rl = 10 + 6 * (l & 15);		rr = 10 + 6 * (r & 15);		break;	case MT_4MUTEMONO:		rl = 55 - 3 * (l & 15);		if (r & 0x10)			rl += 45;		rr = rl;		r = l;		break;	case MT_5MUTEMONO:		r = l;		rl = 100 - 3 * ((l >> 3) & 31);		rr = rl;

⌨️ 快捷键说明

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