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

📄 cs4281.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	writel(ac97_slotid, card->pBA0 + BA0_SRCSA);	// (75ch)	// Set 'Half Terminal Count Interrupt Enable' and 'Terminal	// Count Interrupt Enable' in DMA Control Registers 0 & 1.	// Set 'MSK' flag to 1 to keep the DMA engines paused.	temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK);	// (00030001h)	writel(temp1, card->pBA0 + BA0_DCR0);	// (154h	writel(temp1, card->pBA0 + BA0_DCR1);	// (15ch)	// Set 'Auto-Initialize Control' to 'enabled'; For playback,	// set 'Transfer Type Control'(TR[1:0]) to 'read transfer',	// for record, set Transfer Type Control to 'write transfer'.	// All other bits set to zero;  Some will be changed @ transfer start.	temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ);	// (20000018h)	writel(temp1, card->pBA0 + BA0_DMR0);	// (150h)	temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE);	// (20000014h)	writel(temp1, card->pBA0 + BA0_DMR1);	// (158h)	// Enable DMA interrupts generally, and	// DMA0 & DMA1 interrupts specifically.	temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;	writel(temp1, card->pBA0 + BA0_HIMR);	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n"));	return 0;}//******************************************************************************// "cs4281_play_rate()" --//******************************************************************************static void cs4281_play_rate(struct cs4281_state *card, u32 playrate){	u32 DACSRvalue = 1;	// Based on the sample rate, program the DACSR register.	if (playrate == 8000)		DACSRvalue = 5;	if (playrate == 11025)		DACSRvalue = 4;	else if (playrate == 22050)		DACSRvalue = 2;	else if (playrate == 44100)		DACSRvalue = 1;	else if ((playrate <= 48000) && (playrate >= 6023))		DACSRvalue = 24576000 / (playrate * 16);	else if (playrate < 6023)		// Not allowed by open.		return;	else if (playrate > 48000)		// Not allowed by open.		return;	CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO						      "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",						      DACSRvalue,						      playrate));	//  Write the 'sample rate select code'	//  to the 'DAC Sample Rate' register.	writel(DACSRvalue, card->pBA0 + BA0_DACSR);	// (744h)}//******************************************************************************// "cs4281_record_rate()" -- Initialize the record sample rate converter.//******************************************************************************static void cs4281_record_rate(struct cs4281_state *card, u32 outrate){	u32 ADCSRvalue = 1;	//	// Based on the sample rate, program the ADCSR register	//	if (outrate == 8000)		ADCSRvalue = 5;	if (outrate == 11025)		ADCSRvalue = 4;	else if (outrate == 22050)		ADCSRvalue = 2;	else if (outrate == 44100)		ADCSRvalue = 1;	else if ((outrate <= 48000) && (outrate >= 6023))		ADCSRvalue = 24576000 / (outrate * 16);	else if (outrate < 6023) {		// Not allowed by open.		return;	} else if (outrate > 48000) {		// Not allowed by open.		return;	}	CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO						     "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",						     ADCSRvalue, outrate));	//  Write the 'sample rate select code	//  to the 'ADC Sample Rate' register.	writel(ADCSRvalue, card->pBA0 + BA0_ADCSR);	// (748h)}static void stop_dac(struct cs4281_state *s){	unsigned long flags;	unsigned temp1;	CS_DBGOUT(CS_WAVE_WRITE, 3,		  printk(KERN_INFO "cs4281: stop_dac():\n"));	spin_lock_irqsave(&s->lock, flags);	s->ena &= ~FMODE_WRITE;	temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK;	writel(temp1, s->pBA0 + BA0_DCR0);	spin_unlock_irqrestore(&s->lock, flags);}static void start_dac(struct cs4281_state *s){	unsigned long flags;	unsigned temp1;	CS_DBGOUT(CS_FUNCTION, 3,		  printk(KERN_INFO "cs4281: start_dac()+\n"));	spin_lock_irqsave(&s->lock, flags);	if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||					s->dma_dac.count > 0)	    && s->dma_dac.ready) {		s->ena |= FMODE_WRITE;		temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK;	// Clear DMA0 channel mask.		writel(temp1, s->pBA0 + BA0_DCR0);	// Start DMA'ing.		writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);	// Enable interrupts.              		writel(7, s->pBA0 + BA0_PPRVC);		writel(7, s->pBA0 + BA0_PPLVC);		CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO							      "cs4281: start_dac(): writel 0x%x start dma\n",							      temp1));	}	spin_unlock_irqrestore(&s->lock, flags);	CS_DBGOUT(CS_FUNCTION, 3,		  printk(KERN_INFO "cs4281: start_dac()-\n"));}static void stop_adc(struct cs4281_state *s){	unsigned long flags;	unsigned temp1;	CS_DBGOUT(CS_FUNCTION, 3,		  printk(KERN_INFO "cs4281: stop_adc()+\n"));	spin_lock_irqsave(&s->lock, flags);	s->ena &= ~FMODE_READ;	if (s->conversion == 1) {		s->conversion = 0;		s->prop_adc.fmt = s->prop_adc.fmt_original;	}	temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK;	writel(temp1, s->pBA0 + BA0_DCR1);	spin_unlock_irqrestore(&s->lock, flags);	CS_DBGOUT(CS_FUNCTION, 3,		  printk(KERN_INFO "cs4281: stop_adc()-\n"));}static void start_adc(struct cs4281_state *s){	unsigned long flags;	unsigned temp1;	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: start_adc()+\n"));	spin_lock_irqsave(&s->lock, flags);	if (!(s->ena & FMODE_READ) &&	    (s->dma_adc.mapped || s->dma_adc.count <=	     (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize))	    && s->dma_adc.ready) {		if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) {			// 			// now only use 16 bit capture, due to truncation issue			// in the chip, noticable distortion occurs.			// allocate buffer and then convert from 16 bit to 			// 8 bit for the user buffer.			//			s->prop_adc.fmt_original = s->prop_adc.fmt;			if (s->prop_adc.fmt & AFMT_S8) {				s->prop_adc.fmt &= ~AFMT_S8;				s->prop_adc.fmt |= AFMT_S16_LE;			}			if (s->prop_adc.fmt & AFMT_U8) {				s->prop_adc.fmt &= ~AFMT_U8;				s->prop_adc.fmt |= AFMT_U16_LE;			}			//			// prog_dmabuf_adc performs a stop_adc() but that is			// ok since we really haven't started the DMA yet.			//			prog_codec(s, CS_TYPE_ADC);			if (prog_dmabuf_adc(s) != 0) {				CS_DBGOUT(CS_ERROR, 3,					  printk(KERN_INFO						 "cs4281: start_adc(): error in prog_dmabuf_adc\n"));			}			s->conversion = 1;		}		s->ena |= FMODE_READ;		temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK;	// Clear DMA1 channel mask bit.		writel(temp1, s->pBA0 + BA0_DCR1);	// Start recording		writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);	// Enable interrupts.		CS_DBGOUT(CS_PARMS, 6,			  printk(KERN_INFO				 "cs4281: start_adc(): writel 0x%x \n",				 temp1));	}	spin_unlock_irqrestore(&s->lock, flags);	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: start_adc()-\n"));}// --------------------------------------------------------------------- // use 64k (+1) rather than 32k as some of the higher frequencies need a larger buffer.// comments reflect 32k.#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT+1)	// == 3(for PC), = log base 2( buff sz = 32k).#define DMABUF_MINORDER 1	// ==> min buffer size = 8K.extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db){	struct page *map, *mapend;	if (db->rawbuf) {		// Undo prog_dmabuf()'s marking the pages as reserved 		mapend =		    virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -				 1);		for (map = virt_to_page(db->rawbuf); map <= mapend; map++)			mem_map_unreserve(map);		pci_free_consistent(s->pcidev, PAGE_SIZE << db->buforder,				    db->rawbuf, db->dmaaddr);	}	if (s->tmpbuff && (db->type == CS_TYPE_ADC)) {		// Undo prog_dmabuf()'s marking the pages as reserved 		mapend =		    virt_to_page(s->tmpbuff +				 (PAGE_SIZE << s->buforder_tmpbuff) - 1);		for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)			mem_map_unreserve(map);		pci_free_consistent(s->pcidev,				    PAGE_SIZE << s->buforder_tmpbuff,				    s->tmpbuff, s->dmaaddr_tmpbuff);	}	s->tmpbuff = NULL;	db->rawbuf = NULL;	db->mapped = db->ready = 0;}static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db){	int order;	unsigned bytespersec, temp1;	unsigned bufs, sample_shift = 0;	struct page *map, *mapend;	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: prog_dmabuf()+\n"));	db->hwptr = db->swptr = db->total_bytes = db->count = db->error =	    db->endcleared = db->blocks = db->wakeup = 0;	if (!db->rawbuf) {		db->ready = db->mapped = 0;		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER;		     order--)			if (			    (db->rawbuf =			     (void *) pci_alloc_consistent(s->pcidev,							   PAGE_SIZE <<							   order,							   &db->							   dmaaddr)))				    break;		if (!db->rawbuf) {			CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR						      "cs4281: prog_dmabuf(): unable to allocate rawbuf\n"));			return -ENOMEM;		}		db->buforder = order;		// Now mark the pages as reserved; otherwise the 		// remap_page_range() in cs4281_mmap doesn't work.		// 1. get index to last page in mem_map array for rawbuf.		mapend =		    virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -				 1);		// 2. mark each physical page in range as 'reserved'.		for (map = virt_to_page(db->rawbuf); map <= mapend; map++)			mem_map_reserve(map);	}	if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER;		     order--)			if (			    (s->tmpbuff =			     (void *) pci_alloc_consistent(s->pcidev,							   PAGE_SIZE <<							   order,							   &s->							   dmaaddr_tmpbuff)))				    break;		if (!s->tmpbuff) {			CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR						      "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n"));			return -ENOMEM;		}		s->buforder_tmpbuff = order;		// Now mark the pages as reserved; otherwise the 		// remap_page_range() in cs4281_mmap doesn't work.		// 1. get index to last page in mem_map array for rawbuf.		mapend =		    virt_to_page(s->tmpbuff +				 (PAGE_SIZE << s->buforder_tmpbuff) - 1);		// 2. mark each physical page in range as 'reserved'.		for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)			mem_map_reserve(map);	}	if (db->type == CS_TYPE_DAC) {		if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))			sample_shift++;		if (s->prop_dac.channels > 1)			sample_shift++;		bytespersec = s->prop_dac.rate << sample_shift;	} else			// CS_TYPE_ADC	{		if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))			sample_shift++;		if (s->prop_adc.channels > 1)			sample_shift++;		bytespersec = s->prop_adc.rate << sample_shift;	}	bufs = PAGE_SIZE << db->buforder;#define INTERRUPT_RATE_MS       100	// Interrupt rate in milliseconds.	db->numfrag = 2;	temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS);	// Nominal frag size(bytes/interrupt)	db->fragshift = 8;	// Min 256 bytes.	while (1 << db->fragshift < temp1)	// Calc power of 2 frag size.		db->fragshift += 1;	db->fragsize = 1 << db->fragshift;	db->dmasize = db->fragsize * 2;	db->fragsamples = db->fragsize >> sample_shift;	// # samples/fragment.// If the calculated size is larger than the allocated//  buffer, divide the allocated buffer into 2 fragments.	if (db->dmasize > bufs) {		db->numfrag = 2;	// Two fragments.		db->fragsize = bufs >> 1;	// Each 1/2 the alloc'ed buffer.		db->fragsamples = db->fragsize >> sample_shift;	// # samples/fragment.		db->dmasize = bufs;	// Use all the alloc'ed buffer.		db->fragshift = 0;	// Calculate 'fragshift'.		temp1 = db->fragsize;	// update_ptr() uses it 		while ((temp1 >>= 1) > 1)	// to calc 'total-bytes'			db->fragshift += 1;	// returned in DSP_GETI/OPTR. 	}	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));	CS_DBGOUT(CS_PARMS, 8,		  printk(KERN_INFO			 "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n",			 db->numfrag, db->fragsize, db->fragsamples,			 db->fragshift, bufs,			 (db->type ==			  CS_TYPE_DAC) ? s->prop_dac.fmt : s->prop_adc.fmt,			 (db->type ==			  CS_TYPE_DAC) ? s->prop_dac.channels : s->			 prop_adc.channels));	return 0;}static int prog_dmabuf_adc(struct cs4281_state *s){	unsigned long va;	unsigned count;	int c;	stop_adc(s);	s->dma_adc.type = CS_TYPE_ADC;	if ((c = prog_dmabuf(s, &s->dma_adc)))		return c;	if (s->dma_adc.rawbuf) {		memset(s->dma_adc.rawbuf,		       (s->prop_adc.			fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,		       s->dma_adc.dmasize);	}	if (s->tmpbuff) {		memset(s->tmpbuff,		       (s->prop_adc.			fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,		       PAGE_SIZE << s->buforder_tmpbuff);	}	va = virt_to_bus(s->dma_adc.rawbuf);	count = s->dma_adc.dmasize;	if (s->prop_adc.	    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))		    count /= 2;	// 16-bit.	if (s->prop_adc.channels > 1)		count /= 2;	// Assume stereo.	CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO					  "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n",					  count, (unsigned) va));	writel(va, s->pBA0 + BA0_DBA1);	// Set buffer start address.	writel(count - 1, s->pBA0 + BA0_DBC1);	// Set count. 	s->dma_adc.ready = 1;	return 0;}static int prog_dmabuf_dac(struct cs4281_state *s)

⌨️ 快捷键说明

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