微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > s3c2410上iis接口的uda341驱动的学习

s3c2410上iis接口的uda341驱动的学习

时间:11-11 来源:互联网 点击:
ible(&b->sem))break;}if (audio_channels == 2) {//chunksize等于一个fragment的size(8k)减去这个fragment已经有了的数据的size(b->size),也就是还能容纳的字节数chunksize = s->fragsize - b->size;if (chunksize > count)chunksize = count;//从用户空间的buffer拷贝chunksize个字节到当前fragment的空闲位置if (copy_from_user(b->start + b->size, buffer, chunksize)) {up(&b->sem);return -EFAULT;}//已经有了的数据size加上本次复制的数据b->size += chunksize;} else {//单声道只写一半的数据,但是另一半的空间的还是要空出来chunksize = (s->fragsize - b->size) >> 1;if (chunksize > count)chunksize = count;DPRINTK("write %d to %d\n", chunksize*2, s->buf_idx);//单声道数据的拷贝办法,没看懂,和oss应用传递的数据格式有关,以后再看if (copy_from_user_mono_stereo(b->start + b->size,buffer, chunksize)) {up(&b->sem);return -EFAULT;}b->size += chunksize*2;}buffer += chunksize;count -= chunksize;if (b->size < s->fragsize) {//这次写的数据还没有写满这个fragment,退出,因为要写满才开始dma传输up(&b->sem);break;}//将本次的数据加入dma模块的待传输队列中,详见后文分析if((ret = s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, b->size))) {printk(PFX"dma enqueue failed.\n");return ret;}b->size = 0;//FIXME:感觉这里的代码有问题,next_buf会指向一个fragment,但是没有考虑到setup buffer的时候没有分配到8个fragment的情况.//这个时候下一个fragment的数据是无效的NEXT_BUF(s, buf);}if ((buffer - buffer0))ret = buffer - buffer0;DPRINTK("audio_write : end count=%d\n\n", ret);return ret;}

建立流的实现:

static int audio_setup_buf(audio_stream_t * s){int frag;int dmasize = 0;char *dmabuf = 0;dma_addr_t dmaphys = 0;//缓冲区一共由8个fragment构成,每个fragment的size是8kif (s->buffers)return -EBUSY;s->nbfrags = audio_nbfrags;s->fragsize = audio_fragsize;//用kmalloc分配描述8个fragment的数据结构的空间,下面是这个数据结构的定义,它将会保存dma缓冲区的地址,大小等//typedef struct {//int size; /* buffer size *///char *start; /* point to actual buffer *///dma_addr_t dma_addr; /* physical buffer address *///struct semaphore sem; /* down before touching the buffer *///int master; /* owner for buffer allocation, contain size when true *///} audio_buf_t;s->buffers = (audio_buf_t *)kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);if (!s->buffers)goto err;memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);for (frag = 0; frag < s->nbfrags; frag++) {//循环8次,初始化这8个fragmentaudio_buf_t *b = &s->buffers[frag];if (!dmasize) {//第一个fragment首先尝试分配8*8k大小的dma缓冲区dmasize = (s->nbfrags - frag) * s->fragsize;do {//FIXME:采用的一致性dma映射方式,而不是流式,此处值得考究//LDD3中建议采用的流式映射,而且最后的GFP_DMA参数按理说是老式设备(不能寻址32位地址)才需要用到的//第一个struct device* 参数为null,不知道有没有影响dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL|GFP_DMA);if (!dmabuf)//如果分配失败,就减小8k,继续尝试分配,直到分配成功或连最小的8k都无法分配idmasize -= s->fragsize;} while (!dmabuf && dmasize);//这个fragment没有分配到dma缓冲区,则报错if (!dmabuf)goto err;//分配成功后,fragment里面的master字段保存这个dma缓冲区的大小b->master = dmasize;}//start字段保存dma缓冲区的起始内核虚拟地址b->start = dmabuf;//dma_addr字段保存dma缓冲区的总线地址b->dma_addr = dmaphys;sema_init(&b->sem, 1);DPRINTK("buf %d: start %p dma %d\n", frag, b->start, b->dma_addr);//修改几个变量,将会用于下一个fragment的赋值dmabuf += s->fragsize;dmaphys += s->fragsize;dmasize -= s->fragsize;}//更新当前buffer的index和指针s->buf_idx = 0;s->buf = &s->buffers[0];return 0;err:printk(AUDIO_NAME ": unable to allocate audio memory\n ");audio_clear_buf(s);return -ENOMEM;}

从audio_setup_buf的实现可以看出,虽然指定了8个fragment,但是只有第一次进入循环的时候才

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top