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

📄 nec_vrc5477.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 4 页
字号:
	u32 dmaLength;	u32 temp;	spin_lock_irqsave(&s->lock, flags);	if (!db->stopped) {		spin_unlock_irqrestore(&s->lock, flags);		return;	}	/* we should at least have some free space in the buffer */	MIPS_ASSERT(db->count < db->fragTotalSize - db->fragSize * 2);	/* clear pending ones */	outl(VRC5477_INT_MASK_ADC1END | VRC5477_INT_MASK_ADC2END, 	     s->io +  VRC5477_INT_CLR);        /* enable interrupts */        temp = inl(s->io + VRC5477_INT_MASK);        temp |= VRC5477_INT_MASK_ADC1END | VRC5477_INT_MASK_ADC2END;        outl(temp, s->io +  VRC5477_INT_MASK);	/* setup dma base addr */	outl(db->lbufDma + db->nextIn, s->io + VRC5477_ADC1_BADDR);	outl(db->rbufDma + db->nextIn, s->io + VRC5477_ADC2_BADDR);	/* setup dma length */	dmaLength = db->fragSize >> 4;	outl(dmaLength, s->io + VRC5477_ADC1L);	outl(dmaLength, s->io + VRC5477_ADC2L);	/* activate dma */	outl(VRC5477_DMA_ACTIVATION, s->io + VRC5477_ADC1_CTRL);	outl(VRC5477_DMA_ACTIVATION, s->io + VRC5477_ADC2_CTRL);	/* enable adc slots */	temp = inl(s->io + VRC5477_CTRL);	temp |= (VRC5477_CTRL_ADC1ENB | VRC5477_CTRL_ADC2ENB);	outl (temp, s->io + VRC5477_CTRL);	/* it is time to setup next dma transfer */	temp = db->nextIn + db->fragSize;	if (temp >= db->fragTotalSize) {		MIPS_ASSERT(temp == db->fragTotalSize);		temp = 0;	}	outl(db->lbufDma + temp, s->io + VRC5477_ADC1_BADDR);	outl(db->rbufDma + temp, s->io + VRC5477_ADC2_BADDR);	db->stopped = 0;	spin_unlock_irqrestore(&s->lock, flags);}	/* --------------------------------------------------------------------- */#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)#define DMABUF_MINORDER 1extern inline void dealloc_dmabuf(struct vrc5477_ac97_state *s, 				  struct dmabuf *db){	if (db->lbuf) {		MIPS_ASSERT(db->rbuf);		pci_free_consistent(s->dev, PAGE_SIZE << db->bufOrder,				    db->lbuf, db->lbufDma);		pci_free_consistent(s->dev, PAGE_SIZE << db->bufOrder,				    db->rbuf, db->rbufDma);		db->lbuf = db->rbuf = NULL;	}	db->nextIn = db->nextOut = 0;	db->ready = 0;}static int prog_dmabuf(struct vrc5477_ac97_state *s, 		       struct dmabuf *db,		       unsigned rate){	int order;	unsigned bufsize;	if (!db->lbuf) {		MIPS_ASSERT(!db->rbuf);		db->ready = 0;		for (order = DMABUF_DEFAULTORDER; 		     order >= DMABUF_MINORDER; 		     order--) {			db->lbuf = pci_alloc_consistent(s->dev,							PAGE_SIZE << order,							&db->lbufDma);			db->rbuf = pci_alloc_consistent(s->dev,							PAGE_SIZE << order,							&db->rbufDma);			if (db->lbuf && db->rbuf) break;			if (db->lbuf) {			    MIPS_ASSERT(!db->rbuf);			    pci_free_consistent(s->dev, 						PAGE_SIZE << order,						db->lbuf,						db->lbufDma);			}		}		if (!db->lbuf) {			MIPS_ASSERT(!db->rbuf);			return -ENOMEM;		}		db->bufOrder = order;	}	db->count = 0;	db->nextIn = db->nextOut = 0;    	bufsize = PAGE_SIZE << db->bufOrder;	db->fragShift = ld2(rate * 2 / 100);	if (db->fragShift < 4) db->fragShift = 4;	db->numFrag = bufsize >> db->fragShift;	while (db->numFrag < 4 && db->fragShift > 4) {		db->fragShift--;		db->numFrag = bufsize >> db->fragShift;	}	db->fragSize = 1 << db->fragShift;	db->fragTotalSize = db->numFrag << db->fragShift;	memset(db->lbuf, 0, db->fragTotalSize);	memset(db->rbuf, 0, db->fragTotalSize);    	db->ready = 1;	return 0;}extern inline int prog_dmabuf_adc(struct vrc5477_ac97_state *s){    stop_adc(s);    return prog_dmabuf(s, &s->dma_adc, s->adcRate);}extern inline int prog_dmabuf_dac(struct vrc5477_ac97_state *s){    stop_dac(s);    return prog_dmabuf(s, &s->dma_dac, s->dacRate);}/* --------------------------------------------------------------------- *//* hold spinlock for the following! */static inline void vrc5477_ac97_adc_interrupt(struct vrc5477_ac97_state *s){	struct dmabuf* adc = &s->dma_adc;	unsigned temp;	/* we need two frags avaiable because one is already being used	 * and the other will be used when next interrupt happens.	 */	if (adc->count >= adc->fragTotalSize - adc->fragSize) {		stop_adc(s);		adc->error++;		printk(KERN_INFO PFX "adc overrun\n");		return;	}	/* set the base addr for next DMA transfer */	temp = adc->nextIn + 2*adc->fragSize;	if (temp >= adc->fragTotalSize) {		MIPS_ASSERT( (temp == adc->fragTotalSize) ||                             (temp == adc->fragTotalSize + adc->fragSize) );		temp -= adc->fragTotalSize;	}	outl(adc->lbufDma + temp, s->io + VRC5477_ADC1_BADDR);	outl(adc->rbufDma + temp, s->io + VRC5477_ADC2_BADDR);	/* adjust nextIn */	adc->nextIn += adc->fragSize;	if (adc->nextIn >= adc->fragTotalSize) {		MIPS_ASSERT(adc->nextIn == adc->fragTotalSize);		adc->nextIn = 0;	}	/* adjust count */	adc->count += adc->fragSize;	/* wake up anybody listening */	if (waitqueue_active(&adc->wait)) {		wake_up_interruptible(&adc->wait);	}	}static inline void vrc5477_ac97_dac_interrupt(struct vrc5477_ac97_state *s){	struct dmabuf* dac = &s->dma_dac;	unsigned temp;	/* next DMA transfer should already started */	MIPS_ASSERT(inl(s->io + VRC5477_DAC1_CTRL) & VRC5477_DMA_WIP);	MIPS_ASSERT(inl(s->io + VRC5477_DAC2_CTRL) & VRC5477_DMA_WIP);	/* let us set for next next DMA transfer */	temp = dac->nextOut + dac->fragSize*2;	if (temp >= dac->fragTotalSize) {		MIPS_ASSERT( (temp == dac->fragTotalSize) ||                              (temp == dac->fragTotalSize + dac->fragSize) );		temp -= dac->fragTotalSize;	}	outl(dac->lbufDma + temp, s->io + VRC5477_DAC1_BADDR);	if (s->dacChannels == 1) {		outl(dac->lbufDma + temp, s->io + VRC5477_DAC2_BADDR);	} else {		outl(dac->rbufDma + temp, s->io + VRC5477_DAC2_BADDR);	}#if defined(VRC5477_AC97_VERBOSE_DEBUG)	if (*(u16*)(dac->lbuf +  dac->nextOut) != outTicket) {		printk("assert fail: - %d vs %d\n", 		        *(u16*)(dac->lbuf +  dac->nextOut),                        outTicket);                MIPS_ASSERT(1 == 0);	}#endif	/* adjust nextOut pointer */	dac->nextOut += dac->fragSize;	if (dac->nextOut >= dac->fragTotalSize) {		MIPS_ASSERT(dac->nextOut == dac->fragTotalSize);		dac->nextOut = 0;	}	/* adjust count */	dac->count -= dac->fragSize;	if (dac->count <=0 ) {		MIPS_ASSERT(dac->count == 0);		MIPS_ASSERT(dac->nextIn == dac->nextOut);		/* buffer under run */		stop_dac(s);	}#if defined(VRC5477_AC97_VERBOSE_DEBUG)	if (dac->count) {		outTicket ++;		MIPS_ASSERT(*(u16*)(dac->lbuf +  dac->nextOut) == outTicket);	}#endif		/* we cannot have both under run and someone is waiting on us */	MIPS_ASSERT(! (waitqueue_active(&dac->wait) && (dac->count <= 0)) );	/* wake up anybody listening */	if (waitqueue_active(&dac->wait))		wake_up_interruptible(&dac->wait);}static void vrc5477_ac97_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)dev_id;	u32 irqStatus;	u32 adcInterrupts, dacInterrupts;	spin_lock(&s->lock);	/* get irqStatus and clear the detected ones */	irqStatus = inl(s->io + VRC5477_INT_STATUS);	outl(irqStatus, s->io + VRC5477_INT_CLR);	/* let us see what we get */	dacInterrupts = VRC5477_INT_MASK_DAC1END | VRC5477_INT_MASK_DAC2END;	adcInterrupts = VRC5477_INT_MASK_ADC1END | VRC5477_INT_MASK_ADC2END;	if (irqStatus & dacInterrupts) {		/* we should get both interrupts, but just in case ...  */		if (irqStatus & VRC5477_INT_MASK_DAC1END) {			vrc5477_ac97_dac_interrupt(s);		}		if ( (irqStatus & dacInterrupts) != dacInterrupts ) {			printk(KERN_WARNING "vrc5477_ac97 : dac interrupts not in sync!!!\n");			stop_dac(s);			start_dac(s);		}	} else if (irqStatus & adcInterrupts) {		/* we should get both interrupts, but just in case ...  */		if(irqStatus & VRC5477_INT_MASK_ADC1END) {			vrc5477_ac97_adc_interrupt(s);		} 		if ( (irqStatus & adcInterrupts) != adcInterrupts ) {			printk(KERN_WARNING "vrc5477_ac97 : adc interrupts not in sync!!!\n");			stop_adc(s);			start_adc(s);		}	}	spin_unlock(&s->lock);}/* --------------------------------------------------------------------- */static loff_t vrc5477_ac97_llseek(struct file *file, loff_t offset, int origin){	return -ESPIPE;}static int vrc5477_ac97_open_mixdev(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct list_head *list;	struct vrc5477_ac97_state *s;	for (list = devs.next; ; list = list->next) {		if (list == &devs)			return -ENODEV;		s = list_entry(list, struct vrc5477_ac97_state, devs);		if (s->codec.dev_mixer == minor)			break;	}	file->private_data = s;	return 0;}static int vrc5477_ac97_release_mixdev(struct inode *inode, struct file *file){	return 0;}static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,			unsigned long arg){	return codec->mixer_ioctl(codec, cmd, arg);}static int vrc5477_ac97_ioctl_mixdev(struct inode *inode, struct file *file,				     unsigned int cmd, unsigned long arg){    struct vrc5477_ac97_state *s = 	    (struct vrc5477_ac97_state *)file->private_data;    struct ac97_codec *codec = &s->codec;    return mixdev_ioctl(codec, cmd, arg);}static /*const*/ struct file_operations vrc5477_ac97_mixer_fops = {	owner:		THIS_MODULE,	llseek:		vrc5477_ac97_llseek,	ioctl:		vrc5477_ac97_ioctl_mixdev,	open:		vrc5477_ac97_open_mixdev,	release:	vrc5477_ac97_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct vrc5477_ac97_state *s, int nonblock){	unsigned long flags;	int count, tmo;		if (!s->dma_dac.ready)		return 0;	for (;;) {		spin_lock_irqsave(&s->lock, flags);		count = s->dma_dac.count;		spin_unlock_irqrestore(&s->lock, flags);		if (count <= 0)			break;		if (signal_pending(current))			break;		if (nonblock)			return -EBUSY;		tmo = 1000 * count / s->dacRate / 2;		vrc5477_ac97_delay(tmo);	}	if (signal_pending(current))		return -ERESTARTSYS;	return 0;}/* --------------------------------------------------------------------- */static int inline copy_two_channel_adc_to_user(struct vrc5477_ac97_state *s, 		             char *buffer, 			     int copyCount){	struct dmabuf *db = &s->dma_adc;	int bufStart = db->nextOut;	for (; copyCount > 0; ) {		int i;		int count = copyCount;		if (count > WORK_BUF_SIZE/2) count = WORK_BUF_SIZE/2;		for (i=0; i< count/2; i++) {			s->workBuf[i].lchannel = 				*(u16*)(db->lbuf + bufStart + i*2);			s->workBuf[i].rchannel = 				*(u16*)(db->rbuf + bufStart + i*2);		}		if (copy_to_user(buffer, s->workBuf, count*2)) {			return -1;		}		copyCount -= count;		bufStart += count;		MIPS_ASSERT(bufStart <= db->fragTotalSize);		buffer += count *2;	}	return 0;}/* return the total bytes that is copied */static int inline copy_adc_to_user(struct vrc5477_ac97_state *s,		 char * buffer,		 size_t count,		 int avail){	struct dmabuf *db = &s->dma_adc;	int copyCount=0;	int copyFragCount=0;	int totalCopyCount = 0;	int totalCopyFragCount = 0;	unsigned long flags;	/* adjust count to signel channel byte count */	count >>= s->adcChannels - 1;	/* we may have to "copy" twice as ring buffer wraps around */	for (; (avail > 0) && (count > 0); ) {		/* determine max possible copy count for single channel */		copyCount = count;		if (copyCount > avail) {			copyCount = avail;		}		if (copyCount + db->nextOut > db->fragTotalSize) {			copyCount = db->fragTotalSize - db->nextOut;			MIPS_ASSERT((copyCount % db->fragSize) == 0);		}		copyFragCount = (copyCount-1) >> db->fragShift;		copyFragCount = (copyFragCount+1) << db->fragShift;		MIPS_ASSERT(copyFragCount >= copyCount);		/* we copy differently based on adc channels */		if (s->adcChannels == 1) {			if (copy_to_user(buffer, 					 db->lbuf + db->nextOut, 					 copyCount)) 				return -1;		} else {			/* *sigh* we have to mix two streams into one  */			if (copy_two_channel_adc_to_user(s, buffer, copyCount))				return -1;		}			count -= copyCount;		totalCopyCount += copyCount;		avail -= copyFragCount;		totalCopyFragCount += copyFragCount;		buffer += copyCount << (s->adcChannels-1);		db->nextOut += copyFragCount;		if (db->nextOut >= db->fragTotalSize) {			MIPS_ASSERT(db->nextOut == db->fragTotalSize);			db->nextOut = 0;		}		MIPS_ASSERT((copyFragCount % db->fragSize) == 0);		MIPS_ASSERT( (count == 0) || (copyCount == copyFragCount));	}	spin_lock_irqsave(&s->lock, flags);        db->count -= totalCopyFragCount;        spin_unlock_irqrestore(&s->lock, flags);	return totalCopyCount << (s->adcChannels-1);}static ssize_t vrc5477_ac97_read(struct file *file, 		  char *buffer,		  size_t count, 		  loff_t *ppos){	struct vrc5477_ac97_state *s = 		(struct vrc5477_ac97_state *)file->private_data;	struct dmabuf *db = &s->dma_adc;	ssize_t ret = 0;	unsigned long flags;	int copyCount;	size_t avail;	if (ppos != &file->f_pos)		return -ESPIPE;	if (!access_ok(VERIFY_WRITE, buffer, count))		return -EFAULT;	MIPS_ASSERT(db->ready);	while (count > 0) {		// wait for samples in capture buffer		do {			spin_lock_irqsave(&s->lock, flags);			if (db->stopped)				start_adc(s);			avail = db->count;			spin_unlock_irqrestore(&s->lock, flags);			if (avail <= 0) {				if (file->f_flags & O_NONBLOCK) {					if (!ret)						ret = -EAGAIN;					return ret;				}				interruptible_sleep_on(&db->wait);

⌨️ 快捷键说明

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