📄 at91_audio.c
字号:
buflp = (unsigned short *)(b->start + s->fragsize - b->size); for(i = 0;i < chunksize;i+=2) { *appbuflp++ = (((unsigned long) *buflp) << 16) | *buflp; buflp++; } tmpint2 = chunksize/2; b->size -= chunksize; bufcnt -= tmpint2 ; if(a9200_stereo == 1) tmpint2 <<= 1; if(a9200_bits == 16) tmpint2 <<= 1; tmpint += tmpint2 ; if (b->size > 0) { up(&b->sem); break; } /* Make current buffer available for DMA again */ at91rm9200_dma_queue_buffer(s->dma, (void *) b, b->dma_addr, s->fragsize); wmb(); NEXT_BUF(s, buf); wmb(); b = s->buf; } ssc_regs->SSC_CR |= AT91C_SSC_RXDIS; pdc_regs->PDC_PTCR |= AT91C_PDC_RXTDIS; ret = tmpint; DPRINTK("audio_read: return=%d\n", ret); return ret;}/*----------------------------------------------------- * Name : at91_audio_write() * Function: Write Data to Audio * Last rework data: 06-04-13 wujh@hyesco.com *----------------------------------------------------*/static ssize_t at91_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; unsigned int bufcnt; DPRINTK("audio_write: count=%d\n", count); if (*ppos != file->f_pos) return -ESPIPE; if (!s->active) { if (!s->buffers && at91_audio_setup_buf(s)) return -ENOMEM; } bufcnt = count & ~0x3; while (bufcnt) { audio_buf_t *b = s->buf; /* Wait for a buffer to become free */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; if (down_trylock(&b->sem)) break; } else { ret = -ERESTARTSYS; if (down_interruptible(&b->sem)) break; } /* Feed the current buffer */ chunksize = s->fragsize - b->size; if (chunksize > bufcnt) chunksize = bufcnt; DPRINTK("write %d to %d\n", chunksize, s->buf_idx); if (copy_from_user(b->start + b->size, buffer, chunksize)) { up(&b->sem); return -EFAULT; } b->size += chunksize; buffer += chunksize; bufcnt -= chunksize; if (b->size < s->fragsize) { up(&b->sem); break; } /* Send current buffer to dma */ s->active = 1; at91rm9200_dma_queue_buffer(s->dma, (void *) b, b->dma_addr, b->size); b->size = 0; /* indicate that the buffer has been sent */ NEXT_BUF(s, buf); } if ((buffer - buffer0)) ret = buffer - buffer0; DPRINTK("audio_write: return=%d\n", ret); return ret; }/*----------------------------------------------------- * Name : at91_audio_out_done_callback() * Function: Out done callback function * Last rework data: 06-04-14 wujh@hyesco.com *----------------------------------------------------*/void at91_audio_out_done_callback(void *buf_id, int size){ audio_buf_t *b = (audio_buf_t *) buf_id; audio_stream_t *s = b->stream; //release sem up(&b->sem); b->size = 0; /* And any process polling on write. */ wake_up(&s->wq); }/*----------------------------------------------------- * Name : audio_in_done_callback() * Function: In done callback function * Last rework data: 06-04-14 wujh@hyesco.com *----------------------------------------------------*/void at91_audio_in_done_callback(void *buf_id, int size){ audio_buf_t *b = (audio_buf_t *) buf_id; audio_stream_t *s = b->stream; //release sem b->size = size; wmb(); up(&b->sem); /* And any process polling on write. */ wake_up(&s->wq); }/*----------------------------------------------------- * Name : at91_audio_out_irq_oper() * Function: diable or enable endtx irq function * Last rework data: 06-04-14 wujh@hyesco.com *----------------------------------------------------*/void at91_audio_out_irq_oper(U8 size){ if(size) { // enable endtx interrupt //ssc_regs->SSC_CR |= AT91C_SSC_TXEN; ssc_regs->SSC_IER |= (AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE) ; //pdc_regs->PDC_PTCR |= AT91C_PDC_TXTEN; } else { //Disable ssc Rx and endrx irq ssc_regs->SSC_IDR |= (AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE); //ssc_regs->SSC_CR |= (AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE) ; //pdc_regs->PDC_PTCR |= AT91C_PDC_TXTDIS; } }/*----------------------------------------------------- * Name : at91_audio_in_irq_oper() * Function: diable or enable endrx irq function * Last rework data: 06-04-14 wujh@hyesco.com *----------------------------------------------------*/void at91_audio_in_irq_oper(U8 size){ if(size) { // enable endrx interrupt //ssc_regs->SSC_CR |= AT91C_SSC_RXEN ; ssc_regs->SSC_IER |= (AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF); //pdc_regs->PDC_PTCR |= AT91C_PDC_RXTEN; } else { //Disable ssc Rx and endrx irq ssc_regs->SSC_IDR |= (AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF); //ssc_regs->SSC_CR |= AT91C_SSC_RXDIS; //pdc_regs->PDC_PTCR |= AT91C_PDC_RXTDIS; } }/*----------------------------------------------------- * Name : at91_audio_in_done_callback() * Function: In done callback function * Last rework data: 06-04-14 wujh@hyesco.com *----------------------------------------------------*/void at91_audio_status_callback(U8* status){ int temp,temp2; temp = ssc_regs->SSC_SR; temp2 = ssc_regs->SSC_IMR; if((temp & AT91C_SSC_TXBUFE) && (temp2 & AT91C_SSC_TXBUFE)) *status = 2; else if((temp & AT91C_SSC_ENDTX) && (temp2 & AT91C_SSC_ENDTX)) *status = 1; else if((temp & AT91C_SSC_RXBUFF) && (temp2 & AT91C_SSC_RXBUFF)) *status = 4; else if((temp & AT91C_SSC_ENDRX) && (temp2 & AT91C_SSC_ENDRX)) *status = 3; else *status = 0 ; }/*----------------------------------------------------- * Name : at91_audio_poll() * Function: support poll sys-call function * Last rework data: 06-04-14 wujh@hyesco.com *----------------------------------------------------*/static unsigned int at91_audio_poll(struct file *file, struct poll_table_struct *wait){ audio_stream_t *is = &input_stream; audio_stream_t *os = &output_stream; unsigned int mask = 0; int i; DPRINTK("audio_poll(): mode=%s%s\n", (file->f_mode & FMODE_READ) ? "r" : "", (file->f_mode & FMODE_WRITE) ? "w" : ""); if (file->f_mode & FMODE_READ) { /* Start ssc input if not already active */ if (!is->active) { if (!is->buffers && at91_audio_setup_buf(is)) return -ENOMEM; at91_audio_prime_dma(is); } poll_wait(file, &is->wq, wait); } if (file->f_mode & FMODE_WRITE) { if (!os->buffers && at91_audio_setup_buf(os)) return -ENOMEM; poll_wait(file, &os->wq, wait); } if (file->f_mode & FMODE_READ) { for (i = 0; i < is->nbfrags; i++) { if (atomic_read(&is->buffers[i].sem.count) > 0) { mask |= POLLIN | POLLRDNORM; break; } } } if (file->f_mode & FMODE_WRITE) { for (i = 0; i < os->nbfrags; i++) { if (atomic_read(&os->buffers[i].sem.count) > 0) { mask |= POLLOUT | POLLWRNORM; break; } } } DPRINTK("audio_poll() returned mask of %s%s\n", (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : ""); return mask;}/* file operation stuct for Audio */ struct file_operations at91_audio_fops = { owner: THIS_MODULE, open: at91_audio_open, release: at91_audio_release, read: at91_audio_read, write: at91_audio_write, ioctl: at91_audio_ioctl, poll: at91_audio_poll, }; /*----------------------------------------------------- * Name : AUDIO_At91_Init() * Function: Init Audio driver module * Last rework data: 06-04-13 wujh@hyesco.com *----------------------------------------------------*/ static int __init AUDIO_At91_Init(void){ unsigned int err=0; DPRINTK("AT91RM9200 audio driver version 0.1, build time:" __TIME__ "\n"); audio_dev_dsp = register_sound_dsp(&at91_audio_fops, -1); // Init SSC regs SSC_init(); //init the output at91rm9200_dma_t struct output_stream.fragsize = AUDIO_FRAGSIZE_DEFAULT; output_stream.nbfrags = AUDIO_NBFRAGS_DEFAULT; output_stream.dma = &dma_chan[OUT_CHAN]; output_stream.active = 0; init_waitqueue_head(&(output_stream.wq)); dma_chan[IN_CHAN].flag = 0 ; dma_chan[OUT_CHAN].regs = pdc_regs ; dma_chan[OUT_CHAN].irq_on_off = at91_audio_out_irq_oper ; dma_chan[OUT_CHAN].callback = at91_audio_out_done_callback ; dma_chan[OUT_CHAN].type = SLOT_BY_FRAME; dma_chan[OUT_CHAN].dma_channel = 2; //init the input at91rm9200_dma_t struct input_stream.fragsize = AUDIO_FRAGSIZE_DEFAULT; input_stream.nbfrags = AUDIO_NBFRAGS_DEFAULT; input_stream.dma = &dma_chan[IN_CHAN]; init_waitqueue_head(&(input_stream.wq)); input_stream.active = 0; dma_chan[IN_CHAN].flag = 1 ; dma_chan[IN_CHAN].regs = pdc_regs ; dma_chan[IN_CHAN].irq_on_off = at91_audio_in_irq_oper ; dma_chan[IN_CHAN].callback = at91_audio_in_done_callback ; dma_chan[IN_CHAN].type = SLOT_BY_FRAME; dma_chan[IN_CHAN].dma_channel = 2; audio_state.irq = AT91C_ID_SSC1 ; audio_state.device_id = AUDIO_MODULE_NAME ; audio_state.readstatback = at91_audio_status_callback ; audio_state.out_chan = &dma_chan[OUT_CHAN]; audio_state.in_chan = &dma_chan[IN_CHAN]; //register the at91rm9200_dma irq err = at91rm9200_dma_init(&audio_state); if(err) { DPRINTK("<1>init out at91rm9200_dma_t err! \n"); return err; } I2C_test(); codec_init(uda1380_rx_init); return 0;}/*----------------------------------------------------- * Name : AUDIO_At91_Cleanup() * Function: Exit Audio driver module * Last rework data: 06-04-13 wujh@hyesco.com *----------------------------------------------------*/static void __exit AUDIO_At91_Cleanup(void){ DPRINTK("Rmmod audio driver.\n"); at91rm9200_free_dma(&audio_state); at91_audio_clear_buf(&input_stream); at91_audio_clear_buf(&output_stream); unregister_sound_dsp(audio_dev_dsp);} module_init(AUDIO_At91_Init);module_exit(AUDIO_At91_Cleanup);/*-----------------------------------------------------*/MODULE_AUTHOR("casiawu <wujh@hyesco.com>");MODULE_DESCRIPTION("AT91 AUDIO Driver (AT91_AUDIO)");MODULE_LICENSE("Proprietary");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -