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

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

时间:11-11 来源:互联网 点击:

至此,已经完成了dma等相关部分的初始化,最后调用oss驱动提供的接口注册音频相关的回调函数:

static struct file_operations smdk2410_audio_fops = {llseek: smdk2410_audio_llseek,write: smdk2410_audio_write,read: smdk2410_audio_read,poll: smdk2410_audio_poll,ioctl: smdk2410_audio_ioctl,open: smdk2410_audio_open,release: smdk2410_audio_release};static struct file_operations smdk2410_mixer_fops = {ioctl: smdk2410_mixer_ioctl,open: smdk2410_mixer_open,release: smdk2410_mixer_release};
接下来分析其中的open函数:
static int smdk2410_audio_open(struct inode *inode, struct file *file){//检查读写计数int cold = !audio_active;DPRINTK("audio_open\n");if ((file->f_flags & O_ACCMODE) == O_RDONLY) {if (audio_rd_refcount || audio_wr_refcount)return -EBUSY;audio_rd_refcount++;} else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {if (audio_wr_refcount)return -EBUSY;audio_wr_refcount++;} else if ((file->f_flags & O_ACCMODE) == O_RDWR) {if (audio_rd_refcount || audio_wr_refcount)return -EBUSY;audio_rd_refcount++;audio_wr_refcount++;} elsereturn -EINVAL;if (cold) {//第一次open,赋初值//44100audio_rate = AUDIO_RATE_DEFAULT;//2audio_channels = AUDIO_CHANNELS_DEFAULT;//8192,8kaudio_fragsize = AUDIO_FRAGSIZE_DEFAULT;//8audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;if ((file->f_mode & FMODE_WRITE)){//初始化iis接口的几个寄存器,为发送做准备init_s3c2410_iis_bus_tx();//清除输出流,后文见实现细节audio_clear_buf(&output_stream);}if ((file->f_mode & FMODE_READ)){init_s3c2410_iis_bus_rx();audio_clear_buf(&input_stream);}}return 0;}

clear stream的实现:

static void audio_clear_buf(audio_stream_t * s){DPRINTK("audio_clear_buf\n");//flush dma 通道if(s->dma_ok) s3c2410_dma_ctrl(s->dma_ch, S3C2410_DMAOP_FLUSH);if (s->buffers) {//如果已经分配了缓冲区,即不是第一次使用了,执行以下操作int frag;//对链上的每个非空的dma缓冲区进行释放,这些值的具体含义要到后文分配dma缓冲区的时候分析//看了audio_setup_buf后再看这段代码就明白了for (frag = 0; frag < s->nbfrags; frag++) {if (!s->buffers[frag].master)continue;dma_free_coherent(NULL,s->buffers[frag].master,s->buffers[frag].start,s->buffers[frag].dma_addr);}kfree(s->buffers);s->buffers = NULL;}s->buf_idx = 0;s->buf = NULL;}

接下来分析write函数,这里面会涉及到dma缓冲区申请等操作:

static ssize_t smdk2410_audio_write(struct file *file, const char *buffer,size_t count, loff_t * ppos){const char *buffer0 = buffer;audio_stream_t *s = &output_stream;int chunksize, ret = 0;switch (file->f_flags & O_ACCMODE) {case O_WRONLY:case O_RDWR:break;default:return -EPERM;}//如果还没有分配缓冲区,则调用audio_setup_buf,后文分析if (!s->buffers && audio_setup_buf(s))return -ENOMEM;//FIXME:将count的低2位置0,不知道目的是什么?count &= ~0x03;while (count > 0) {//b指向当前的fragmentaudio_buf_t *b = s->buf;//获取信号量,有阻塞和非阻塞两种方式if (file->f_flags & O_NONBLOCK) {ret = -EAGAIN;if (down_trylock(&b->sem))break;} else {ret = -ERESTARTSYS;if (down_interruptible(&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_fr            

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

网站地图

Top