分类:
2008-07-30 15:43:21
staticssize_t smdk2410_audio_write(structfile*file,constchar*buffer, size_tcount,loff_t*ppos) { constchar*buffer0=buffer; audio_stream_t*s=&output_stream; intchunksize,ret=0; switch(file->f_flags&O_ACCMODE){ caseO_WRONLY: caseO_RDWR: break; default: return-EPERM; } //如果s->buffers=NUll,则初始化s,也即初始化output_stream,由此可知,output_stream只在第一次调用smdk2410_audio_write的时候被初始化。 if(!s->buffers&&audio_setup_buf(s)) return-ENOMEM; count&=~0x03; while(count>0){ audio_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)){//对b->sem执行down操作,以互斥。 // return ret; break; } } if(audio_channels==2){ chunksize=s->fragsize-b->size;//确定每次传输的字节数。b->size=0 if(chunksize>count) chunksize=count; if(copy_from_user(b->start+b->size,buffer,chunksize)){ up(&b->sem);//出错后则up信号量,并返回 return-EFAULT; } b->size+=chunksize; }else{//对于本驱动而言,audio_channels被成了2,所以这下面的是不会被执行的 chunksize=(s->fragsize-b->size)>>1; if(chunksize>count) chunksize=count; if(copy_from_user_mono_stereo(b->start+b->size, buffer,chunksize)){ up(&b->sem); return-EFAULT; } b->size+=chunksize*2; } buffer+=chunksize;//更新buffer位置 count-=chunksize;// 更新还需传输字节数 if(b->size<s->fragsize){//不知道这里的意思是什么 up(&b->sem); break; } ret=s3c2410_dma_enqueue(s->dmach,(void*)b,b->dma_addr,b->size);//提交b到dma对列中 if(ret){ printk("dma enqueue failed.\n"); returnret; } b->size=0; NEXT_BUF(s,buf);//让s->buf指向s->buffers中的下一个位置 } if((buffer-buffer0)) ret=buffer-buffer0; printk(KERN_WARNING"ret is %d\n",ret); returnret; } |
statcvoidaudio_dmaout_done_callback(structs3c2410_dma_chan*ch,void*buf,intsize,enums3c2410_dma_buffresult result) { audio_buf_t*b=(audio_buf_t*)buf; up(&b->sem); wake_up(&b->sem.wait); } |
ints3c2410_dma_enqueue(unsignedintchannel,void*id, dma_addr_t data,intsize) { .................. if(chan->flags&S3C2410_DMAF_AUTOSTART){ s3c2410_dma_ctrl(chan->number,S3C2410_DMAOP_START); } ................... local_irq_restore(flags); return0; } |