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

📄 utu2440-audio.c

📁 UDA1431 语音芯片的驱动源码及测试程序。在s3c2440开发板linux2.6内核实现语音双工。使用方法:在内核源码中找到相应的C源文件替换即可。压缩包内有语音同时输入输出的测试程序。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  * (C) Samsung Electronics 2004 * * Philips UDA1341 Audio Device Driver for SMDK board * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * * 2004-04-28 Kwanghyun La <nala.la@samsung.com> *   - modified for sharing module device driver of samsung arch * * 2004-07: SW.LEE *         comment : Originally made by MIZI Research For S3C2410 *	            ported to S3C2440A  */#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/l3/l3.h>#include <linux/l3/uda1341.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/dma.h>#include <asm/hardware/clock.h>#include <asm/arch/dma.h>#include <asm/arch/regs-iis.h>#include <asm-arm/arch-s3c2410/bitfield.h>#include <asm-arm/arch-s3c2410/regs-clock.h>#include <asm-arm/arch-s3c2410/hardware.h>#include <asm-arm/arch-sa1100/hardware.h>#include "utu2440-audio.h"#undef USE_SYSFS  #define USE_SYSFS ///////////////////////////////////********/#define GET_PCLK	0#define PCM_ABS(a)  (a < 0 ? -a : a)#define MPLLCON			bCLKCTL(oMPLLCON)#define oMPLLCON		0x04	#define CLK_CTL_BASE		0x4C000000#define bCLKCTL(Nb)		__REG(CLK_CTL_BASE + (Nb))#define GET_MDIV(x)	FExtr(x, fPLL_MDIV)#define GET_PDIV(x)	FExtr(x, fPLL_PDIV)#define GET_SDIV(x)	FExtr(x, fPLL_SDIV)#define Fld(Size, Shft) 	(((Size) << 16) + (Shft))#define fPLL_MDIV		Fld(8,12)//2410#define fPLL_PDIV		Fld(6,4)//2410#define fPLL_SDIV		Fld(2,0)//2410#define CLKDIVN			bCLKCTL(oCLKDIVN)#define oCLKDIVN		0x14	#define FIN 1#define __REGP(x)	((__regbase *)((x)&~4095))->offset[((x)&4095)>>2]#define __REG(x)	__REGP(io_p2v(x))#define CLK_CTL_BASE		0x4C000000#define io_p2v(x)	( ((x) | 0xbe000000) ^ (~((x) >> 1) & 0x06000000) )#define io_v2p( x )	( ((x) & 0x41ffffff) ^ ( ((x) & 0x06000000) << 1) )typedef struct { volatile u32 offset[4096]; } __regbase;#ifdef  GDEBUG#    define dprintk( x... )  printk( x )#else#    define dprintk( x... )#endif#define AUDIO_NAME		"UTU2440_UDA1341"#define AUDIO_NAME_VERBOSE	"UTU2440 UDA1341 audio driver"#define AUDIO_FMT_MASK          (AFMT_S16_LE)#define AUDIO_FMT_DEFAULT       (AFMT_S16_LE)/* the UDA1341 is stereo only */#define AUDIO_CHANNELS_DEFAULT	2#define AUDIO_RATE_DEFAULT	44100#define AUDIO_NBFRAGS_DEFAULT	8//#define AUDIO_FRAGSIZE_DEFAULT    8192#define AUDIO_FRAGSIZE_DEFAULT	16384typedef struct{    int             size;       /* buffer size */    char           *start;      /* point to actual buffer */    dma_addr_t      dma_addr;   /* physical buffer address */    struct semaphore sem;       /* down before touching the buffer */    int             master;     /* owner for buffer allocation, contain size when true */} audio_buf_t;typedef struct{    audio_buf_t    *buffers;    /* pointer to audio buffer structures */    audio_buf_t    *buf;        /* current buffer used by read/write */    u_int           buf_idx;    /* index for the pointer above */    u_int           fragsize;   /* fragment i.e. buffer size */    u_int           nbfrags;    /* nbr of fragments */    int             bytecount;  /* nbr of processed bytes */    int             fragcount;  /* nbr of fragment transitions */    u_int           channels;   /* audio channels 1:mono, 2:stereo */    u_int           rate;       /* audio rate */    dmach_t         dma_ch;     /* DMA channel (channel2 for audio) */    int             active:1;   /* actually in progress */    int             stopped:1;  /* might be active but stopped */    wait_queue_head_t frag_wq;  /* for poll(), etc. */    s3c2410_dma_client_t dmaclient; /* kernel 2.6 dma client */} audio_stream_t;/* * Mixer (UDA1341) interface  */static struct l3_client uda1341;static audio_stream_t output_stream;static audio_stream_t input_stream;static int ao_dcon = 0, ai_dcon = 0;#define NEXT_BUF(_s_,_b_) { \	(_s_)->_b_##_idx++; \	(_s_)->_b_##_idx %= (_s_)->nbfrags; \	(_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }static u_int    audio_rate;static int      audio_channels;static int      audio_fmt;static u_int audio_fragsize;static u_int audio_nbfrags;static int      audio_rd_refcount;static int      audio_wr_refcount;#define audio_active		(audio_rd_refcount | audio_wr_refcount)static void     start_utu2440_iis_bus_tx(void);static void     start_utu2440_iis_bus_rx(void);static void     init_s3c2410_iis_bus_txrx(void);//static int  iispsr_value_gao(int s_bit_clock, int sample_rate);////////////////////////////////////unsigned long s3c2410_get_bus_clk(int who);//unsigned long s3c2410_get_cpu_clk(void);//static inline unsigned long cal_bus_clk(unsigned long cpu_clk, unsigned long ratio, int who);static voidaudio_clear_buf(audio_stream_t * s){    dprintk("\n");    s->active = 0;    s->stopped = 0;    /*     * ensure DMA won't run anymore      */    //utu2440_dma_flush_all(s->dma_ch);    s3c2410_dma_ctrl(s->dma_ch, S3C2410_DMAOP_FLUSH);    if (s->buffers)    {        int             frag;        for (frag = 0; frag < s->nbfrags; frag++)        {            if (!s->buffers[frag].master)                continue;            dma_free_coherent( NULL, s->buffers[frag].master, s->buffers[frag].start,  s->buffers[frag].dma_addr);        }        kfree(s->buffers);        s->buffers = NULL;    }    s->buf_idx = 0;    s->buf = NULL;}/* * This function allocates the buffer structure array and buffer data space * according to the current number of fragments and fragment size. */static intaudio_setup_buf(audio_stream_t * s){    int             frag;    int             dmasize = 0;    char           *dmabuf = NULL;    dma_addr_t      dmaphys = 0;    if (s->buffers)        return -EBUSY;//printk("audio_setup_buf:=================\n");     s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);    if (!s->buffers)        goto err;    memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags);    for (frag = 0; frag < s->nbfrags; frag++)    {        audio_buf_t    *b = &s->buffers[frag];        /*         * Let's allocate non-cached memory for DMA buffers.         * We try to allocate all memory at once.         * If this fails (a common reason is memory fragmentation),         * then we allocate more smaller buffers.         */        if (!dmasize)        {            dmasize = (s->nbfrags - frag) * s->fragsize;            do            {            	dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL);                if (!dmabuf)                    dmasize -= s->fragsize;            }            while (!dmabuf && dmasize);            if (!dmabuf)                goto err;            b->master = dmasize;            memzero(dmabuf, dmasize);        }        b->start = dmabuf;        b->dma_addr = dmaphys;        // b->stream = s;        sema_init(&b->sem, 1);        dprintk("buf %d: start %p dma %ld\n", frag, b->start, (unsigned long)b->dma_addr);        dmabuf += s->fragsize;        dmaphys += s->fragsize;        dmasize -= s->fragsize;    }    s->buf_idx = 0;    s->buf = &s->buffers[0];    return 0;  err:    printk(AUDIO_NAME ": unable to allocate audio memory\n ");    audio_clear_buf(s);    return -ENOMEM;}/* * This function yanks all buffers from the DMA code's control and * resets them ready to be used again. */static voidaudio_reset_buf(audio_stream_t * s){    int             frag;    s->active = 0;    s->stopped = 0;    s3c2410_dma_ctrl(s->dma_ch, S3C2410_DMAOP_FLUSH);    if (s->buffers)    {        for (frag = 0; frag < s->nbfrags; frag++)        {            audio_buf_t    *b = &s->buffers[frag];            b->size = 0;            sema_init(&b->sem, 1);        }    }    s->bytecount = 0;    s->fragcount = 0;}static voidaudio_dmaout_done_callback(s3c2410_dma_chan_t *chp, void *buf, int size,  s3c2410_dma_buffresult_t result){    audio_buf_t    *b = (audio_buf_t *) buf;    up(&b->sem);    wake_up(&output_stream.frag_wq);	if( result != S3C2410_RES_OK )	{		dprintk("%s: tranter error\n", __FUNCTION__);	}}static voidaudio_dmain_done_callback(s3c2410_dma_chan_t *chp, void *buf, int size,  s3c2410_dma_buffresult_t result){    audio_buf_t    *b = (audio_buf_t *) buf;    b->size = size;    up(&b->sem);    wake_up(&input_stream.frag_wq);		if( result != S3C2410_RES_OK )	{		dprintk("%s: tranter error\n", __FUNCTION__);	}}static intaudio_sync(struct file *file){    audio_stream_t *s = &output_stream;    audio_buf_t    *b = s->buf;    dprintk("audio_sync\n");    if (!s->buffers)        return 0;    if (b->size != 0)    {        down(&b->sem);        s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, b->size);        b->size = 0;        NEXT_BUF(s, buf);    }    b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags);    if (down_interruptible(&b->sem))        return -EINTR;    up(&b->sem);    return 0;}static inline intcopy_from_user_mono_stereo(char *to, const char *from, int count){    u_int          *dst = (u_int *) to;    const char     *end = from + count;    if( !access_ok(VERIFY_READ, from, count) ) // access_ok啊 0捞搁        return -EFAULT;    if ((int) from & 0x2)    {        u_int           v;        __get_user(v, (const u_short *) from);        from += 2;        *dst++ = v | (v << 16);    }    while (from < end - 2)    {        u_int           v,                        x,                        y;        __get_user(v, (const u_int *) from);        from += 4;        x = v << 16;        x |= x >> 16;        y = v >> 16;        y |= y << 16;        *dst++ = x;        *dst++ = y;    }    if (from < end)    {        u_int           v;        __get_user(v, (const u_short *) from);        *dst = v | (v << 16);    }    return 0;}static          ssize_tutu2440_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;    dprintk("audio_write : start count=%d\n", count);    /////////////////////////////////////////////////    //gao    s->dma_ch= S3C2410_DMA_CH2;    switch (file->f_flags & O_ACCMODE)    {    case O_WRONLY:    case O_RDWR:        break;    default:        return -EPERM;    }    if (!s->buffers && audio_setup_buf(s))        return -ENOMEM;    count &= ~0x03;    while (count > 0)    {        audio_buf_t    *b = s->buf;        if (file->f_flags & O_NONBLOCK)        {            ret = -EAGAIN;            if (down_trylock(&b->sem))                break;        }        else        {            ret = -ERESTARTSYS;            if (down_interruptible(&b->sem))                break;        }        if (s->channels == 2)        {            chunksize = s->fragsize - b->size;            if (chunksize > count)                chunksize = count;            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;        }        else        {            chunksize = (s->fragsize - b->size) >> 1;            if (chunksize > count)                chunksize = count;            dprintk("write %d to %d\n", chunksize * 2, s->buf_idx);            if (copy_from_user_mono_stereo(b->start + b->size, buffer, chunksize))            {                up(&b->sem);                return -EFAULT;            }            b->size += chunksize * 2;        }        buffer += chunksize;        count -= chunksize;        if (b->size < s->fragsize)        {            up(&b->sem);            break;        }        s->active = 1;          // ghcstop add        s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, b->size);               b->size = 0;        NEXT_BUF(s, buf);    }    if ((buffer - buffer0))        ret = buffer - buffer0;    dprintk("audio_write : end count=%d\n\n", ret);    return ret;}static          ssize_tutu2440_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;    /////////////////////////////////////////////////    //gao    s->dma_ch= S3C2410_DMA_CH1;    dprintk("audio_read: count=%d\n", count);/****    if (ppos != &file->f_pos)        return -ESPIPE;****/    if (!s->buffers)    {        int             i;        if (audio_setup_buf(s))            return -ENOMEM;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -