📄 wtaudioout.c
字号:
/* INTPUTCLK, PDOR3, SCLKINVERT*/ *mcf2Reg32p(MCFA_IIS1CONFIG) |= 0x00000800; *mcf2Reg32p(MCFA_IIS1CONFIG) = MCFA_IIS_CLKINPUT | MCFA_IIS_TXSRC_PDOR3 | MCFA_IIS_16BIT | MCFA_IIS_MODE_IIS | MCFA_IIS_LRCK64BIT;// |MCFA_IIS_SCLKINV; *mcf2Reg32p(MCFA_DATAINCTRL) = 0;}//*************************************************************/* * Configure and start DMA engine. */void __inline__ WTAudio_tx_dmarun(void){#if DEBUG printk("WTAudio_tx_dmarun(): dma=%d count=%d\n", AudioDev.tx_nDmaStart, AudioDev.tx_nDmaCount);#endif set_dma_mode(WTAUDIO_TXDMA, DMA_MODE_WRITE | DMA_MODE_LONG_BIT); //set_dma_mode(WTAUDIO_TXDMA, DMA_MODE_WRITE); set_dma_device_addr(WTAUDIO_TXDMA, (MCF_MBAR2 + MCFA_PDOR3)); set_dma_addr(WTAUDIO_TXDMA,(int) &WTAudio_buf[AudioDev.tx_nDmaStart*AudioDev.packsize]); set_dma_count(WTAUDIO_TXDMA, AudioDev.tx_nDmaCount*AudioDev.packsize); WTAudio_txdmaing = 1; WTAudio_txbusy = 1; KDEBUG("CTL 0[%x] 1[%x]\n",DMA0_CTL,DMA1_CTL); KDEBUG("SA 0[%x] 1[%x]\n",DMA0_SA,DMA1_SA); KDEBUG("DA 0[%x] 1[%x]\n",DMA0_DA,DMA1_DA); KDEBUG("BC 0[%x] 1[%x]\n",DMA0_BC,DMA1_BC); enable_dma(WTAUDIO_TXDMA); }/* * Start DMA'ing a new buffer of data if any available. */void WTAudio_tx_dmabuf(void){#if DEBUG printk("WTAudio_tx_dmabuf()\n");#endif KDEBUG("DMA [%d]\n",WTAudio_txdmaing); /* If already running then nothing to do... */ if (WTAudio_txdmaing) return; /* 设置这次DMA需要传送的包个数*/ AudioDev.tx_nDmaCount = (AudioDev.tx_nBufT>= AudioDev.tx_nDmaStart) ? (AudioDev.tx_nBufT-AudioDev.tx_nDmaStart) :(PACKCOUNT - AudioDev.tx_nDmaStart); if (AudioDev.tx_nDmaCount > DMACOUNT) AudioDev.tx_nDmaCount = DMACOUNT; /* 调整nBufB指针 */ /* AudioDev.tx_nBufB += AudioDev.tx_nDmaCount; if (AudioDev.tx_nBufB >= PACKCOUNT) AudioDev.tx_nBufB = 0;*/ printk("nDmaCount =%d\n",AudioDev.tx_nDmaCount); if (AudioDev.tx_nDmaCount > 0){ WTAudio_tx_dmarun(); } else{ WTAudio_txbusy = 0; } }/* * Interrupt from DMA engine. */void WTAudio_tx_dmaisr(int irq, void *dev_id, struct pt_regs *regs){#if DEBUG printk("WTAudio_tx_dmaisr(irq=%d)\n", irq);#endif printk("t isr statue[%x]\n",DMA0_STATUE); /* Clear DMA interrupt */ disable_dma(WTAUDIO_TXDMA); WTAudio_txdmaing = 0; printk("statue[%x]\n",DMA0_STATUE); /* 修改DMA读写头指示(以包为单位)*/ AudioDev.tx_nDmaStart += AudioDev.tx_nDmaCount; if (AudioDev.tx_nDmaStart >= PACKCOUNT)AudioDev.tx_nDmaStart = 0; AudioDev.tx_nDmaCount = 0; /* Start new DMA buffer if we can */ WTAudio_tx_dmabuf();}/****************************************************************************/void WTAudio_txdrain(void){#ifdef DEBUG printk("WTAudio_txdrain()\n");#endif WTAudio_txbusy=0; current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); return; while (!signal_pending(current)) { if (WTAudio_txbusy == 0) break; }}/****************************************************************************/int WTAudio_open(struct inode *inode, struct file *filp){#if DEBUG printk("WTAudio_open()\n");#endif#ifdef MODULE MOD_INC_USE_COUNT;#endif if (WTAudio_isopen) return (-EBUSY); WTAudio_isopen = 1; WTAudio_txdmaing = 0; return (0);}int WTAudio_release(struct inode *inode, struct file *filp){#if DEBUG printk("WTAudio_release()\n");#endif#ifdef MODULE MOD_DEC_USE_COUNT;#endif WTAudio_txdrain(); disable_dma(WTAUDIO_TXDMA); WTAudio_txdmaing = 0; *mcf2Reg32p(MCFA_PDOR3) = 0; WTAudio_txbusy = 0; AudioDev.tx_nDmaStart= 0; AudioDev.tx_nDmaCount= 0; // AudioDev.tx_nBufB= 0; AudioDev.tx_nBufT= 0; WTAudio_isopen = 0; return (0);}/****************************************************************************/ssize_tWTAudio_write(struct file * filp, const char *buf, size_t count, loff_t * ppos){ unsigned int start,end,packcount,ret;#ifdef DEBUG printk("m5249_write(buf=%x,count=%d)\n", (int) buf, count);#endif packcount = (count/AudioDev.packsize); //计算当前用户写了多少包到缓冲区tryagain: start = AudioDev.tx_nDmaStart; end = AudioDev.tx_nBufT; if((end+packcount)%PACKCOUNT == start){ KDEBUG("FULL\n"); if (signal_pending(current)) return (-ERESTARTSYS); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); goto tryagain; } end += packcount; if(end>=PACKCOUNT) end=0; AudioDev.tx_nBufT = end; ret = end; KDEBUG("T[%d] START[%d]\n ", AudioDev.tx_nBufT, AudioDev.tx_nDmaStart); //KDEBUG("DMA Method of write.\n"); WTAudio_tx_dmabuf(); return (ret);}int WTAudio_map(struct file *filp, struct vm_area_struct *vma){ KDEBUG("mmap()\n"); //if(offset >= _pa(high_memory) || (file->f_flags & O_SYNC)) // vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; //if((WTAudio_buf == NULL) || remap_page_range(vma->vm_start,__pa(WTAudio_buf),BUFSIZE,PAGE_SHARED)) vma->vm_start = vma->vm_offset + AudioDev.mmstart; //return -EAGAIN; return 0;}int WTAudio_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg){ int err =0; int ret = 0; int val; WTDevBufStatus BufStatus; if(_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; switch(cmd){ case IOCASTOP: WTAudio_txdrain(); disable_dma(WTAUDIO_TXDMA); *mcf2Reg32p(MCFA_PDOR3) = 0; //AudioDev.tx_nBufB = 0; AudioDev.tx_nBufT = 0; AudioDev.tx_nDmaStart =0; AudioDev.tx_nDmaCount =0; KDEBUG("Stop!\n"); break; case IOCASTART: *mcf2Reg32p(MCFA_PDOR3) = 0; WTAudio_tx_dmabuf(); KDEBUG("Start!\n"); break; case IOCASPACKSIZE: KDEBUG("Reset pack size\n"); ret = get_user(val, (int*)arg); if(val == AudioDev.packsize){ //printk("k [%x %x]\n",AudioDev.rxmmstart,AudioDev.mmstart); break; } WTAudio_txdrain(); disable_dma(WTAUDIO_TXDMA); *mcf2Reg32p(MCFA_PDOR3) = 0; //AudioDev.tx_nBufB = 0; AudioDev.tx_nBufT = 0; AudioDev.tx_nDmaStart =0; AudioDev.tx_nDmaCount =0; kfree(WTAudio_buf); AudioDev.packsize = val; AudioDev.mmsize = (val*AudioDev.mmcount); AudioDev.dmasize = (val*AudioDev.dmacount); WTAudio_buf = kmalloc(AudioDev.mmsize, GFP_KERNEL); AudioDev.mmstart = (unsigned long)WTAudio_buf; break; case IOCAGDEVBUFSTATUS: //BufStatus.tx_nBufB = AudioDev.tx_nBufB; BufStatus.tx_nBufT = AudioDev.tx_nBufT; BufStatus.tx_nDmaStart = AudioDev.tx_nDmaStart; //WTAudio_txdrain(); ret = copy_to_user((WTDevBufStatus*)arg, &BufStatus, sizeof(struct WTDevBufStatus) ); break; case IOCAGDEVSTATUS: ret = copy_to_user((WTAudio_dev *)arg, &AudioDev, sizeof(struct WTAudio_dev)); break; default : return -ENOTTY; } return ret; }/****************************************************************************//****************************************************************************/struct file_operations WTAudio_fops = { open:WTAudio_open, /* open */ release:WTAudio_release, /* release */ write:WTAudio_write, /* write */ ioctl:WTAudio_ioctl, /* ioctl */ mmap:WTAudio_map, /* map */};/****************************************************************************/int __init WTAudio_init(void){ if (register_chrdev(AudioDev.major, "WTAUDIO", &WTAudio_fops) < 0) { printk(KERN_WARNING "WTAUDIO: failed to register major %d\n", AudioDev.major); return (0); } WTAudio_buf = kmalloc(AudioDev.mmsize, GFP_KERNEL); if (WTAudio_buf == NULL) { printk("WTAUDIO: failed to allocate DMA[%d] buffer\n", BUFSIZE); } AudioDev.mmstart = (unsigned long)WTAudio_buf;#ifdef MOUDLE SET_MODULE_OWNER(&WTAudio_fops);#endif printk("WTAUDIO: DMA channel=%d, irq=%d\n", WTAUDIO_TXDMA, WTAUDIO_TXDMAIRQ); if (request_irq(WTAUDIO_TXDMAIRQ, WTAudio_tx_dmaisr, (SA_INTERRUPT | IRQ_FLG_FAST), "AUDIO_OUT(DMA)", NULL)) { printk("WTAUDIO: DMA IRQ %d already in use?\n", WTAUDIO_TXDMAIRQ); } //dmap = (BYTE *) dma_base_addr[WTAUDIO_TXDMA]; //选择通道 //dmap[MCFDMA_DIVR] = WTAUDIO_TXDMAIRQ; //设置DMA中断向量:120 *mcfReg8p(MCFDMA_INTVR0) = WTAUDIO_TXDMAIRQ; /* Set interrupt level and priority */ //*mcfReg8p(MCFSIM_ICRDMA0) = MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3; *mcfReg8p(MCFSIM_ICRDMA0) = MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI2; //*((DWORD*) (MCF_MBAR + MCFSIM_IMR)) &=~MCFSIM_IMR_DMA0; *mcfReg32p(MCFSIM_IMR) &=~MCFSIM_IMR_DMA0; /* Set DMA to use channel 0 for audio */ *mcf2Reg8p(MCFA_DMACONF) |= MCFA_DMA_0REQ; // *mcf2Reg32p(MCFSIM2_DMAROUTE) = 0x00000080; //dam0 audio source 1 if (request_dma(WTAUDIO_TXDMA, "AUDIO_OUT")) { printk("WTAUDIO: DMA channel %d already in use?\n", WTAUDIO_TXDMA); } WTAudio_chipinit();// sema_init (&sem,1);// memset((void *)DelayBuf,0,AudioDev.packsize); /* Dummy write to start outputing */ *mcf2Reg32p(MCFA_PDOR3) = 0; return (0);}#ifdef MODULEvoid WTAudio_cleanup(void){ kfree(WTAudio_buf); free_dma(WTAUDIO_TXDMA); unregister_chrdev(AUDIOMAJOR, "WTAUDIO"); printk("release WTAUDIO!!!\n");}module_init(WTAudio_init);module_exit(WTAudio_cleanup);MODULE_LICENSE("GPL");#endif/****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -