utu2440-audio.c
来自「UDA1431 语音芯片的驱动源码及测试程序。在s3c2440开发板linux2」· C语言 代码 · 共 1,585 行 · 第 1/3 页
C
1,585 行
for (i = 0; i < s->nbfrags; i++) { audio_buf_t *b = s->buf; down(&b->sem); s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, s->fragsize); NEXT_BUF(s, buf); } } while (count > 0) { audio_buf_t *b = s->buf; /* * Wait for a buffer to become full */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; if (down_trylock(&b->sem)) break; } else { ret = -ERESTARTSYS; if (down_interruptible(&b->sem)) break; } chunksize = b->size; if (chunksize > count) chunksize = count; dprintk("read %d from %d\n", chunksize, s->buf_idx); if (copy_to_user(buffer, b->start + s->fragsize - b->size, chunksize)) { up(&b->sem); return -EFAULT; } b->size -= chunksize; buffer += chunksize; count -= chunksize; if (b->size > 0) { up(&b->sem); break; } /* * Make current buffer available for DMA again */ s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, s->fragsize); NEXT_BUF(s, buf); } if ((buffer - buffer0)) ret = buffer - buffer0; dprintk("audio_read: return=%d\n", ret); return ret;}static unsigned intutu2440_audio_poll(struct file *file, struct poll_table_struct *wait){ unsigned int mask = 0; int i; dprintk("audio_poll(): mode=%s\n", (file->f_mode & FMODE_WRITE) ? "w" : ""); if (file->f_mode & FMODE_READ) { if (!input_stream.active) { if (!input_stream.buffers && audio_setup_buf(&input_stream)) return -ENOMEM; } poll_wait(file, &input_stream.frag_wq, wait); for (i = 0; i < input_stream.nbfrags; i++) { if (atomic_read(&input_stream.buffers[i].sem.count) > 0) mask |= POLLIN | POLLWRNORM; break; } } if (file->f_mode & FMODE_WRITE) { if (!output_stream.active) { if (!output_stream.buffers && audio_setup_buf(&output_stream)) return -ENOMEM; poll_wait(file, &output_stream.frag_wq, wait); } for (i = 0; i < output_stream.nbfrags; i++) { if (atomic_read(&output_stream.buffers[i].sem.count) > 0) mask |= POLLOUT | POLLWRNORM; break; } } dprintk("audio_poll() returned mask of %s\n", (mask & POLLOUT) ? "w" : ""); return mask;}static loff_tutu2440_audio_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}static intutu2440_mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){ /* * We only accept mixer (type 'M') ioctls. */ if (_IOC_TYPE(cmd) != 'M') return -EINVAL; return l3_command(&uda1341, cmd, (void *) arg);}static intiispsr_value(int sample_rate){ int i; unsigned long fact0 = clk_get_rate(clk_get(NULL, "pclk")) / S_CLOCK_FREQ; unsigned long r0_sample_rate, r1_sample_rate = 0, r2_sample_rate; int prescaler = 0; dprintk("requested sample_rate = %d\n", sample_rate); for (i = 1; i < 32; i++) { r1_sample_rate = fact0 / i; if (r1_sample_rate < sample_rate) break; } r0_sample_rate = fact0 / (i + 1); r2_sample_rate = fact0 / (i - 1); dprintk("calculated (%d-1) freq = %ld, error = %d\n", i + 1, r0_sample_rate, abs(r0_sample_rate - sample_rate)); dprintk("calculated (%d-1) freq = %ld, error = %d\n", i, r1_sample_rate, abs(r1_sample_rate - sample_rate)); dprintk("calculated (%d-1) freq = %ld, error = %d\n", i - 1, r2_sample_rate, abs(r2_sample_rate - sample_rate)); prescaler = i; if (abs(r0_sample_rate - sample_rate) < abs(r1_sample_rate - sample_rate)) prescaler = i + 1; if (abs(r2_sample_rate - sample_rate) < abs(r1_sample_rate - sample_rate)) prescaler = i - 1; prescaler = max_t(int, 0, (prescaler - 1)); dprintk("selected prescale value = %d, freq = %ld, error = %d\n", prescaler, fact0 / (prescaler + 1), abs((fact0 / (prescaler + 1)) - sample_rate)); return prescaler;}static longaudio_set_dsp_speed(long val){ unsigned long tmp; int prescaler = 0; tmp = clk_get_rate(clk_get(NULL, "pclk")) / S_CLOCK_FREQ; dprintk("requested = %ld, limit = %ld\n", val, tmp); if (val > (tmp >> 1)) return -1; prescaler = iispsr_value(val); IISPSR = IISPSR_A(prescaler) | IISPSR_B(prescaler); audio_rate = val; output_stream.rate = input_stream.rate = audio_rate; // ghcstop fix dprintk("return audio_rate = %ld\n", (unsigned long) audio_rate); return audio_rate;}static intaudio_set_fragments(audio_stream_t * s, int val){ if (s->active) return -EBUSY; if (s->buffers) audio_clear_buf(s); s->nbfrags = (val >> 16) & 0x7FFF; val &= 0xffff; if (val < 4) val = 4; if (val > 15) val = 15; s->fragsize = 1 << val; if (s->nbfrags < 2) s->nbfrags = 2; if (s->nbfrags * s->fragsize > 128 * 1024) s->nbfrags = 128 * 1024 / s->fragsize; if (audio_setup_buf(s)) return -ENOMEM; return val | (s->nbfrags << 16);}static intutu2440_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){ long val;//printk("a_ioctl = 0x%08x, SNDCTL_DSP_GETOSPACE=0x%08x\n", cmd, SNDCTL_DSP_GETOSPACE); switch (cmd) { case SNDCTL_DSP_SETFMT: get_user(val, (long *) arg); if (val & AUDIO_FMT_MASK) { audio_fmt = val; break; } else return -EINVAL; case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_STEREO: get_user(val, (long *) arg); if (cmd == SNDCTL_DSP_STEREO) val = val ? 2 : 1; if (val != 1 && val != 2) return -EINVAL; audio_channels = val; break; case SOUND_PCM_READ_CHANNELS: put_user(audio_channels, (long *) arg); break; case SNDCTL_DSP_SPEED: get_user(val, (long *) arg); val = audio_set_dsp_speed(val); if (val < 0) return -EINVAL; put_user(val, (long *) arg); break; case SOUND_PCM_READ_RATE: put_user(audio_rate, (long *) arg); break; case SNDCTL_DSP_GETFMTS: put_user(AUDIO_FMT_MASK, (long *) arg); break; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) return put_user(output_stream.fragsize, (long *) arg); else return put_user(input_stream.fragsize, (int *) arg); case SNDCTL_DSP_SETFRAGMENT: if (get_user(val, (long *) arg)) return -EFAULT; if (file->f_mode & FMODE_READ) { int ret = audio_set_fragments(&input_stream, val); if (ret < 0) return ret; ret = put_user(ret, (int *) arg); if (ret) return ret; } if (file->f_mode & FMODE_WRITE) { int ret = audio_set_fragments(&output_stream, val); if (ret < 0) return ret; ret = put_user(ret, (int *) arg); if (ret) return ret; } return 0; case SNDCTL_DSP_SYNC: return audio_sync(file); case SNDCTL_DSP_GETOSPACE: { audio_stream_t *s = &output_stream; audio_buf_info *inf = (audio_buf_info *) arg; int err = !access_ok(VERIFY_WRITE, inf, sizeof(*inf)); int i; int frags = 0, bytes = 0, dma_send_bytes = 0; if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; if (err) return err; if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; for (i = 0; i < s->nbfrags; i++) { if (atomic_read(&s->buffers[i].sem.count) > 0) { if (s->buffers[i].size == 0) frags++; bytes += s->fragsize - s->buffers[i].size; } } put_user(frags, &inf->fragments); put_user(s->nbfrags, &inf->fragstotal); put_user(s->fragsize, &inf->fragsize); put_user(bytes, &inf->bytes); break; } case SNDCTL_DSP_GETISPACE: { audio_stream_t *s = &input_stream; audio_buf_info *inf = (audio_buf_info *) arg; int err = !access_ok(VERIFY_WRITE, inf, sizeof(*inf)); int i; int frags = 0, bytes = 0; if (!(file->f_mode & FMODE_READ)) return -EINVAL; if (err) return err; if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; for (i = 0; i < s->nbfrags; i++) { if (atomic_read(&s->buffers[i].sem.count) > 0) { if (s->buffers[i].size == s->fragsize) frags++; bytes += s->buffers[i].size; } } put_user(frags, &inf->fragments); put_user(s->nbfrags, &inf->fragstotal); put_user(s->fragsize, &inf->fragsize); put_user(bytes, &inf->bytes); break; } case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_READ) { audio_reset_buf(&input_stream); } if (file->f_mode & FMODE_WRITE) { audio_reset_buf(&output_stream); } return 0; case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_POST: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_GETCAPS: case SNDCTL_DSP_GETTRIGGER: case SNDCTL_DSP_SETTRIGGER: case SNDCTL_DSP_GETIPTR: case SNDCTL_DSP_GETOPTR: case SNDCTL_DSP_MAPINBUF: case SNDCTL_DSP_MAPOUTBUF: case SNDCTL_DSP_SETSYNCRO: case SNDCTL_DSP_SETDUPLEX: printk("request IOCTL %d \n", cmd); return -ENOSYS; default: return utu2440_mixer_ioctl(inode, file, cmd, arg); } return 0;}/********/static intutu2440_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) { printk("\n gao O_RDONLY error gao"); return -EBUSY; } audio_rd_refcount++; } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) { if (audio_wr_refcount) { printk("\n gao O_WRONLY error gao"); return -EBUSY; } audio_wr_refcount++; } else if ((file->f_flags & O_ACCMODE) == O_RDWR) { if (audio_rd_refcount || audio_wr_refcount) { printk("\n gao O_RDWR error gao"); return -EBUSY; } audio_rd_refcount++; audio_wr_refcount++; } else return -EINVAL; if (cold) { audio_rate = AUDIO_RATE_DEFAULT; audio_channels = AUDIO_CHANNELS_DEFAULT; audio_fragsize = AUDIO_FRAGSIZE_DEFAULT; audio_nbfrags = AUDIO_NBFRAGS_DEFAULT; init_s3c2410_iis_bus_txrx(); //audio_clear_buf(&output_stream); //audio_clear_buf(&input_stream); output_stream.fragsize = AUDIO_FRAGSIZE_DEFAULT; output_stream.nbfrags = AUDIO_NBFRAGS_DEFAULT; output_stream.channels = audio_channels; init_waitqueue_head(&output_stream.frag_wq); input_stream.fragsize = AUDIO_FRAGSIZE_DEFAULT; input_stream.nbfrags = AUDIO_NBFRAGS_DEFAULT; input_stream.channels = audio_channels; init_waitqueue_head(&input_stream.frag_wq); /* * the UDA1341 is stereo only ==> 2 channels */ if ((file->f_mode & FMODE_WRITE)) { //output_stream.fragsize = AUDIO_FRAGSIZE_DEFAULT; //output_stream.nbfrags = AUDIO_NBFRAGS_DEFAULT; //output_stream.channels = audio_channels; //start_utu2440_iis_bus_tx(); //init_s3c2410_iis_bus_txrx(); audio_clear_buf(&output_stream); init_waitqueue_head(&output_stream.frag_wq); } if ((file->f_mode & FMODE_READ)) { //input_stream.fragsize = AUDIO_FRAGSIZE_DEFAULT; //input_stream.nbfrags = AUDIO_NBFRAGS_DEFAULT; //input_stream.channels = audio_channels; //start_utu2440_iis_bus_rx(); //init_s3c2410_iis_bus_txrx(); audio_clear_buf(&input_stream); init_waitqueue_head(&input_stream.frag_wq); } } return 0;}static intutu2440_audio_release(struct inode *inode, struct file *file){ dprintk("audio_release\n"); if (file->f_mode & FMODE_READ) { if (audio_rd_refcount == 1) audio_clear_buf(&input_stream); audio_rd_refcount = 0; } if (file->f_mode & FMODE_WRITE) { if (audio_wr_refcount == 1) { audio_sync(file); audio_clear_buf(&output_stream); audio_wr_refcount = 0; } } return 0;}static voidstart_uda1341(void){#if 0 struct uda1341_cfg cfg; cfg.format = FMT_MSB; cfg.fs = S_CLOCK_FREQ; l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg);#endif}static voidstart_utu2440_iis_bus_rx(void){ IISCON = 0; IISMOD = 0; IISFIFOC = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?