s3c2410上iis接口的uda341驱动的学习
时间:11-11
来源:互联网
点击:
调用 dma_alloc_coherent进行了dma缓冲区的申请操作,如果不能一次申请到8个fragment size的空间,就减1,尝试7个,依次类推.比如最终只申请到2*8k的dma缓冲区,那么fragment0就保存它的起始虚拟地址和起始总线地址, 并且设置master字段为整个dma缓冲区的size,这也标志了fragment0是保存的整个dma缓冲区的起始地址.fragment1的起始虚拟地址就是整个dma缓冲区的起始虚拟地址加8k(fragment size),fragment2即以后的fragment就是无效的.
2.6.10内核中s3c2410_dma_enqueue的分析,最新的内核修改了这个部分.
int s3c2410_dma_enqueue(unsigned int channel, void *id,dma_addr_t data, int size){s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];s3c2410_dma_buf_t *buf;unsigned long flags;check_channel(channel);//分配描述本次dma传输的数据块信息的数据结构,每次调用都会分配一个这个结构,并且加到它们构成的链表的末尾//因为调用这个函数的时候之前的传输可能还没有完成buf = (s3c2410_dma_buf_t *)kmalloc(sizeof(*buf), GFP_ATOMIC);if (buf == NULL) {pr_debug("%s: out of memory (%d alloc)\n",__FUNCTION__, sizeof(*buf));return -ENOMEM;}pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);//dbg_showchan(chan);buf->next = NULL;buf->data = buf->ptr = data;buf->size = size;buf->id = id;buf->magic = BUF_MAGIC;local_irq_save(flags);if (chan->curr == NULL) {//这个dma channel上的链表还是空的chan->curr = buf;chan->end = buf;chan->next = NULL;} else {//这个dma channel已经有数据在传输了,加到链表末尾chan->end->next = buf;chan->end = buf;}//下一个要load的bufif (chan->next == NULL)chan->next = buf;/* check to see if we can load a buffer */if (chan->state == S3C2410_DMA_RUNNING) {if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {printk(KERN_ERR "dma%d: loadbuffer:""timeout loading buffer\n",chan->number);dbg_showchan(chan);local_irq_restore(flags);return -EINVAL;}}while (s3c2410_dma_canload(chan) && chan->next != NULL) {s3c2410_dma_loadbuffer(chan, chan->next);}} else if (chan->state == S3C2410_DMA_IDLE) {if (chan->flags & S3C2410_DMAF_AUTOSTART) {//如果允许自动开始,那么加入队列后就启动dma传输s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);}}local_irq_restore(flags);return 0;}
dma完成一次传输后的回调函数:
static void audio_dmaout_done_callback(s3c2410_dma_chan_t *ch, void *buf, int size,s3c2410_dma_buffresult_t result){audio_buf_t *b = (audio_buf_t *) buf;//释放信号量,可以在写函数里面处理下一个fragment了up(&b->sem);wake_up(&b->sem.wait);}
至此就可以实现音频的播放了.
看懂以上代码后再看read函数就没什么难度了,整个read的流程如下:
如果第一次调用,那么建立8个用于dma的fragment,并且加入到dma队列里面开始接收数据
读取一个fragment开始,读取里面的数据
重新将该fragment提交给dma模块用于接收数据
s3c2410iis接口uda341驱 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)