📄 qq2440-audio.c
字号:
if ((buffer - buffer0)) ret = buffer - buffer0; dprintk("audio_write : end count=%d\n\n", ret); return ret;}static ssize_tsbc2440_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos){ const char *buffer0 = buffer; audio_stream_t *s = &input_stream; int chunksize, ret = 0; dprintk("audio_read: count=%d\n", count);/* gxf delete *//* if (ppos != &file->f_pos) *//* { *//* dprintk("gxf error1\n"); *//* return -ESPIPE; *//* } */ if (!s->buffers) { int i; if (audio_setup_buf(s)) { return -ENOMEM; } 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 intsbc2440_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_tsbc2440_audio_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}static intsbc2440_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); dprintk("set dsp speed\n"); 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 intsbc2440_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 sbc2440_mixer_ioctl(inode, file, cmd, arg); } return 0;}static intsbc2440_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++; } else return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -