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 + -
显示快捷键?