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

📄 cs4281m.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
// --------------------------------------------------------------------- #define DMABUF_MINORDER 1	// ==> min buffer size = 8K.static 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++)			ClearPageReserved(map);		free_dmabuf(s, db);	}	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++)			ClearPageReserved(map);		free_dmabuf2(s, db);	}	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;	unsigned long df;	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 = db->underrun = 0;/** check for order within limits, but do not overwrite value, check* later for a fractional defaultorder (i.e. 100+).*/	if((defaultorder > 0) && (defaultorder < 12))		df = defaultorder;	else		df = 1;		if (!db->rawbuf) {		db->ready = db->mapped = 0;		for (order = df; 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_pfn_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++)			SetPageReserved(map);	}	if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {		for (order = df; 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_pfn_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++)			SetPageReserved(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;/** added fractional "defaultorder" inputs. if >100 then use * defaultorder-100 as power of 2 for the buffer size. example:* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.*/	if(defaultorder >= 100)	{		bufs = 1 << (defaultorder-100);	}#define INTERRUPT_RATE_MS       100	// Interrupt rate in milliseconds.	db->numfrag = 2;/* * Nominal frag size(bytes/interrupt)*/	temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS);	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_PARMS, 3, 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));	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));	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){	unsigned long va;	unsigned count;	int c;	stop_dac(s);	s->dma_dac.type = CS_TYPE_DAC;	if ((c = prog_dmabuf(s, &s->dma_dac)))		return c;	memset(s->dma_dac.rawbuf,	       (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,	       s->dma_dac.dmasize);	va = virt_to_bus(s->dma_dac.rawbuf);	count = s->dma_dac.dmasize;	if (s->prop_dac.	    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))		    count /= 2;	// 16-bit.	if (s->prop_dac.channels > 1)		count /= 2;	// Assume stereo.	writel(va, s->pBA0 + BA0_DBA0);	// Set buffer start address.	writel(count - 1, s->pBA0 + BA0_DBC0);	// Set count.             	CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO		"cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",			count, (unsigned) va));	s->dma_dac.ready = 1;	return 0;}static void clear_advance(void *buf, unsigned bsize, unsigned bptr,			  unsigned len, unsigned char c){	if (bptr + len > bsize) {		unsigned x = bsize - bptr;		memset(((char *) buf) + bptr, c, x);		bptr = 0;		len -= x;	}	CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO		"cs4281: clear_advance(): memset %d at %p for %d size \n",			(unsigned)c, ((char *) buf) + bptr, len));	memset(((char *) buf) + bptr, c, len);}// call with spinlock held! static void cs4281_update_ptr(struct cs4281_state *s, int intflag){	int diff;	unsigned hwptr, va;	// update ADC pointer 	if (s->ena & FMODE_READ) {		hwptr = readl(s->pBA0 + BA0_DCA1);	// Read capture DMA address.		va = virt_to_bus(s->dma_adc.rawbuf);		hwptr -= (unsigned) va;		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 > s->dma_adc.dmasize)			s->dma_adc.count = s->dma_adc.dmasize;		if (s->dma_adc.mapped) {			if (s->dma_adc.count >=			    (signed) s->dma_adc.fragsize) wake_up(&s->								  dma_adc.								  wait);		} else {			if (s->dma_adc.count > 0)				wake_up(&s->dma_adc.wait);		}		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO			"cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",				s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count));	}	// update DAC pointer 	//	// check for end of buffer, means that we are going to wait for another interrupt	// to allow silence to fill the fifos on the part, to keep pops down to a minimum.	//	if (s->ena & FMODE_WRITE) {		hwptr = readl(s->pBA0 + BA0_DCA0);	// Read play DMA address.		va = virt_to_bus(s->dma_dac.rawbuf);		hwptr -= (unsigned) va;		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 >= s->dma_dac.fragsize) {				s->dma_dac.wakeup = 1;				wake_up(&s->dma_dac.wait);				if (s->dma_dac.count > s->dma_dac.dmasize)					s->dma_dac.count &=					    s->dma_dac.dmasize - 1;			}		} else {			s->dma_dac.count -= diff;			if (s->dma_dac.count <= 0) {				//				// fill with silence, and do not shut down the DAC.				// Continue to play silence until the _release.				//				CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO					"cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n",						(unsigned)(s->prop_dac.fmt & 						(AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, 						s->dma_dac.rawbuf, s->dma_dac.dmasize));				memset(s->dma_dac.rawbuf,				       (s->prop_dac.					fmt & (AFMT_U8 | AFMT_U16_LE)) ?				       0x80 : 0, s->dma_dac.dmasize);				if (s->dma_dac.count < 0) {					s->dma_dac.underrun = 1;					s->dma_dac.count = 0;					CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO					 "cs4281: cs4281_update_ptr(): underrun\n"));				}			} else if (s->dma_dac.count <=				   (signed) s->dma_dac.fragsize				   && !s->dma_dac.endcleared) {				clear_advance(s->dma_dac.rawbuf,					      s->dma_dac.dmasize,					      s->dma_dac.swptr,					      s->dma_dac.fragsize,					      (s->prop_dac.					       fmt & (AFMT_U8 |						      AFMT_U16_LE)) ? 0x80					      : 0);				s->dma_dac.endcleared = 1;			}			if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) ||				intflag)			{				wake_up(&s->dma_dac.wait);			}		}		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO			"cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",				s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count));	}}// --------------------------------------------------------------------- static void prog_codec(struct cs4281_state *s, unsigned type){	unsigned long flags;	unsigned temp1, format;	CS_DBGOUT(CS_FUNCTION, 2,		  printk(KERN_INFO "cs4281: prog_codec()+ \n"));	spin_lock_irqsave(&s->lock, flags);	if (type == CS_TYPE_ADC) {		temp1 = readl(s->pBA0 + BA0_DCR1);		writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1);	// Stop capture DMA, if active.		// program sampling rates  		// Note, for CS4281, capture & play rates can be set independently.		cs4281_record_rate(s, s->prop_adc.rate);		// program ADC parameters 		format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;		if (s->prop_adc.		    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) {	// 16-bit			if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE))	// Big-endian?				format |= DMRn_BEND;			if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))				format |= DMRn_USIGN;	// Unsigned.      		} else			format |= DMRn_SIZE8 | DMRn_USIGN;	// 8-bit, unsigned		if (s->prop_adc.channels < 2)			format |= DMRn_MONO;		writel(format, s->pBA0 + BA0_DMR1);		CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO			"cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",				(format & DMRn_SIZE8) ? "8" : "16",				(format & DMRn_USIGN) ?  "Unsigned" : "Signed", 				(format & DMRn_MONO) ? "Mono" : "Stereo", 				s->prop_adc.rate, format));		s->ena &= ~FMODE_READ;	// not capturing data yet	}	if (type == CS_TYPE_DAC) {		temp1 = readl(s->pBA0 + BA0_DCR0);		writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0);	// Stop play DMA, if active.		// program sampling rates  		// Note, for CS4281, capture & play rates can be set independently.		cs4281_play_rate(s, s->prop_dac.rate);		// program DAC parameters 		format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;		if (s->prop_dac.		    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U

⌨️ 快捷键说明

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