⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qq2440-audio.c

📁 uda1341 linux driver for s3c2440.
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -