UDA1341驱动疑惑!!
static struct device *this_dev;
typedef 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 */
int dma_size;
} 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 */
// dmach_t dma_ch; /* DMA channel (channel2 for audio) */
int dma_ch;
} audio_stream_t;
static audio_stream_t output_stream;
static audio_stream_t input_stream; /* input */
static u_int rd_buf_tail;
static u_int wr_buf_tail;
static u_int play_dma_running;
#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_dev_dsp;
static int audio_dev_mixer;
static int audio_rd_refcount;
static int audio_wr_refcount;
#define audio_active (audio_rd_refcount | audio_wr_refcount)
static int uda1341_volume;
static int uda1341_boost;
static int mixer_igain = 0x4; /* -6db*/
#define L3MOD_HI() __raw_writel(__raw_readl(S3C2410_GPBDAT)|(1<<2), S3C2410_GPBDAT)
#define L3MOD_LOW() __raw_writel(__raw_readl(S3C2410_GPBDAT)&~(1<<2), S3C2410_GPBDAT)
#define L3DAT_HI() __raw_writel(__raw_readl(S3C2410_GPBDAT)|(1<<3), S3C2410_GPBDAT)
#define L3DAT_LOW() __raw_writel(__raw_readl(S3C2410_GPBDAT)&~(1<<3), S3C2410_GPBDAT)
#define L3CLK_HI() __raw_writel(__raw_readl(S3C2410_GPBDAT)|(1<<4), S3C2410_GPBDAT)
#define L3CLK_LOW() __raw_writel(__raw_readl(S3C2410_GPBDAT)&~(1<<4), S3C2410_GPBDAT)
static void uda1341_l3_address(u8 data)
{
int i;
unsigned long flags;
//qsm2007-05-25
#ifdef YLE2440_DEBUG
printk(KERN_ERR "line %d passed!\n",__LINE__);
#endif
local_irq_save(flags);
L3MOD_LOW();//write_gpio_bit(GPIO_L3MODE, 0);
L3DAT_LOW();//write_gpio_bit(GPIO_L3DATA, 0);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
for (i = 0; i < 8; i++) {
if (data & 0x1) {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_HI(); //write_gpio_bit(GPIO_L3DATA, 1);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
} else {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_LOW();//write_gpio_bit(GPIO_L3DATA, 0);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
}
data >>= 1; /*右移一位*/
}
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
udelay(1);
local_irq_restore(flags);
}
static void uda1341_l3_data(u8 data)
{
int i;
unsigned long flags;
//qsm2007-05-25
#ifdef YLE2440_DEBUG
printk(KERN_ERR "line %d passed!\n",__LINE__);
#endif
local_irq_save(flags);
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
udelay(1);
L3MOD_LOW();//write_gpio_bit(GPIO_L3MODE, 0);
udelay(1);
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
for (i = 0; i < 8; i++) {
if (data & 0x1) {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_HI(); //write_gpio_bit(GPIO_L3DATA, 1);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
} else {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_LOW();//write_gpio_bit(GPIO_L3DATA, 0);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
}
data >>= 1;
}
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
L3MOD_LOW();//write_gpio_bit(GPIO_L3MODE, 0);
udelay(1);
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
local_irq_restore(flags);
}
struct iis_psr_val {
__u32 rate;
__u16 psr;
__u16 fs;
};
/*PLCK/16/fs(384/256)=IISLRCK*/
static struct iis_psr_val iis_psr_para[] = {
{8000, 16, 384},
{11025, 11, 384},
{16000, 8, 384},
{22050, 6, 384},
{24000, 8, 256},
{32000, 4, 384},
{44100, 3, 384},
{48000, 4, 256}
};
static void init_s3c2410_iis_bus_rx(void)
{
//qsm2007-05-25
#ifdef YLE2440_DEBUG
printk(KERN_ERR "line %d passed!\n",__LINE__);
#endif
__raw_writel(0, S3C2410_IISCON);
__raw_writel(0, S3C2410_IISMOD);
__raw_writel(0, S3C2410_IISFCON);
/* 22.05 KHz , 384fs */
__raw_writel(((iis_psr_para[3].psr-1)<<5)|(iis_psr_para[3].psr-1), S3C2410_IISPSR);
__raw_writel(IISCON_RX_DMA /* Transmit DMA service request */
|IISCON_TX_IDLE /* Receive Channel idle */
|IISCON_PRESCALE, /* IIS Prescaler Enable */
S3C2410_IISCON);
__raw_writel(IISMOD_SEL_MA /* Master mode */
| IISMOD_SEL_RX /* Transmit */
| IISMOD_CH_RIGHT /* Low for left channel */
| IISMOD_FMT_MSB /* MSB-justified format */
| IISMOD_BIT_16 /* Serial data bit/channel is 16 bit */
| IISMOD_FREQ_384 /* Master clock freq = 384 fs */
| IISMOD_SFREQ_32, /* 32 fs */
S3C2410_IISMOD);
__raw_writel(IISFCON_RX_DMA /* Transmit FIFO access mode: DMA */
| IISFCON_RX_EN, /* Transmit FIFO enable */
S3C2410_IISFCON);
__raw_writel(__raw_readl(S3C2410_IISCON)|IISCON_EN, S3C2410_IISCON); /* IIS enable(start) */
}
static void init_s3c2410_iis_bus_tx(void)
{
//qsm21cn2007-05-25
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(0, S3C2410_IISCON);
printk(KERN_INFO "have done __raw_ writel() about S3C2410_IISCON-->(VIRTUAL).\n");
printk(KERN_INFO "S3C2410_IISCON=%08x.\n",S3C2410_IISCON);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(0, S3C2410_IISMOD);
printk(KERN_ERR "S3C2410_IISMOD=%08x.\n",S3C2410_IISMOD);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(0, S3C2410_IISFCON);
printk(KERN_ERR "S3C2410_IISFCON=%08x.\n",S3C2410_IISFCON);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
/* 22.05 KHz , 384fs */
__raw_writel(((iis_psr_para[3].psr-1)<<5)|(iis_psr_para[3].psr-1), S3C2410_IISPSR);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(IISCON_TX_DMA /* Transmit DMA service request */
|IISCON_RX_IDLE /* Receive Channel idle */
|IISCON_PRESCALE, /* IIS Prescaler Enable */
S3C2410_IISCON);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(IISMOD_SEL_MA /* Master mode */
| IISMOD_SEL_TX /* Transmit */
| IISMOD_CH_RIGHT /* Low for left channel */
| IISMOD_FMT_MSB /* MSB-justified format */
| IISMOD_BIT_16 /* Serial data bit/channel is 16 bit */
| IISMOD_FREQ_384 /* Master clock freq = 384 fs */
| IISMOD_SFREQ_32, /* 32 fs */
S3C2410_IISMOD);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(IISFCON_TX_DMA /* Transmit FIFO access mode: DMA */
| IISFCON_TX_EN, /* Transmit FIFO enable */
S3C2410_IISFCON);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(__raw_readl(S3C2410_IISCON)|IISCON_EN, S3C2410_IISCON); /* IIS enable(start) */
//printk(KERN_ERR "line %d passed!\n",__LINE__);
}
static void audio_clear_buf(audio_stream_t * s)
{
DPRINTK("audio_clear_buf\n");
//printk(KERN_ERR "line %d passed!\n",__LINE__);
// s3c2410_dma_flush_all(s->dma_ch);
if (s->buffers) {
int frag;
for (frag = 0; frag < s->nbfrags; frag++) {
if (!s->buffers[frag].master) //master = size
continue;
dma_free_writecombine(this_dev, 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;
}
static int audio_setup_buf(audio_stream_t * s)
{
int frag;
int dmasize = 0;
char *dmabuf = 0;
dma_addr_t dmaphys = 0;
//qsm21cn2007-05-25
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if (s->buffers)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EBUSY;
}
wr_buf_tail = rd_buf_tail = play_dma_running = 0;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
s->nbfrags = audio_nbfrags;
s->fragsize = audio_fragsize;
s->buffers = (audio_buf_t *)
kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
if (!s->buffers)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
goto err;
}
memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
for (frag = 0; frag < s->nbfrags; frag++) {
audio_buf_t *b = &s->buffers[frag];
/* if (!dmasize) {
dmasize = (s->nbfrags - frag) * s->fragsize;
do {
dmabuf = dma_alloc_writecombine(dev, dmasize, &dmaphys, GFP_KERNEL),
if (!dmabuf)
dmasize -= s->fragsize;
} while (!dmabuf && dmasize);
if (!dmabuf)
goto err;
b->master = dmasize;
}*/
dmabuf = dma_alloc_writecombine(this_dev, s->fragsize, &dmaphys, GFP_KERNEL);
if(!dmabuf) {
//printk("Unable to get DMA buffer\n");
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
goto err;
}
}
b->master = s->fragsize;
b->start = dmabuf;
b->dma_addr = dmaphys;
sema_init(&b->sem, 1);
DPRINTK("buf %d: start %p dma %d\n", frag, b->start, b->dma_addr);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
dmabuf += s->fragsize;
dmaphys += s->fragsize;
dmasize -= s->fragsize;
}
s->buf_idx = 0;
s->buf = &s->buffers[0];
return 0;
err:
//printk(KERN_ERR "line %d passed!\n",__LINE__);
printk(AUDIO_NAME ": unable to allocate audio memory\n ");
audio_clear_buf(s);
return -ENOMEM;
}
static irqreturn_t iisin_dma_done_handler(int irq, void *dev_id, struct pt_regs *regs)
{
//qsm21cn2007-05-25
//printk(KERN_ERR "line %d passed!\n",__LINE__);
// printk(KERN_DEBUG"%d\n", input_stream.buf_idx);
audio_stream_t *s = &input_stream;
if(s->buffers) {
audio_buf_t *b = s->buffers+rd_buf_tail;
rd_buf_tail++;
if(rd_buf_tail>=s->nbfrags)
rd_buf_tail = 0;
__raw_writel(s->buffers[rd_buf_tail].dma_addr, DIDST1);
__raw_writel(2, DMTRIG1);
if(s->buf_idx==rd_buf_tail) {
s->buf_idx++;
if(s->buf_idx>=s->nbfrags)
s->buf_idx = 0;
s->buf = s->buffers+s->buf_idx;
}
if(b->size==0)
up(&(b->sem));
b->size = s->fragsize;
}
return IRQ_HANDLED;
}
static irqreturn_t iisout_dma_done_handler(int irq, void *dev_id, struct pt_regs *regs)
{
audio_stream_t *s = &output_stream;
//printk(KERN_ERR "line %d passed! enter iisout_dma_done_handler()\n",__LINE__);
if(s->buffers) {
audio_buf_t *b = s->buffers+wr_buf_tail;
wr_buf_tail++;
if(wr_buf_tail>=s->nbfrags)
wr_buf_tail = 0;
up(&b->sem);
// wake_up(&b->sem.wait);
b = s->buffers+wr_buf_tail;
if(b!=s->buf) {
__raw_writel(b->dma_addr, DISRC2); //DMA src memory
// __raw_writel(0, DISRCC2); //AHB, address increase
// __raw_writel(0x55000010, DIDST2); //IISFIFO phy address
// __raw_writel(3, DIDSTC2); //APB, address fixed
__raw_writel(0xa0d00000|(b->dma_size>>1), DCON2); //set mode and length
__raw_writel(2, DMTRIG2); //set channel on
b->dma_size = 0;
} else
play_dma_running = 0;
}
return IRQ_HANDLED;
}
/* using when write */
static int audio_sync(struct file *file)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
audio_stream_t *s = &output_stream;
audio_buf_t *b = s->buf;
unsigned long flags;
DPRINTK("audio_sync\n");
if (!s->buffers)
return 0;
if (b->size != 0) {
down(&b->sem);
//s3c2410_dma_queue_buffer(s->dma_ch, (void *) b,
// b->dma_addr, b->size, DMA_BUF_WR);
local_irq_save(flags);
if(!play_dma_running) {
__raw_writel(b->dma_addr, DISRC2); //DMA src memory
__raw_writel(0, DISRCC2); //AHB, address increase
//__raw_writel(S3C2410_IISFIFO, DIDST2); //IISFIFO address
__raw_writel(0x55000010, DIDST2); //IISFIFO phy address
__raw_writel(3, DIDSTC2); //APB, address fixed
__raw_writel(0xa0d00000|(b->size>>1), DCON2); //set mode and length
__raw_writel(2, DMTRIG2); //set channel on
} else
b->dma_size = b->size;
b->size = 0;
NEXT_BUF(s, buf);
local_irq_restore(flags);
}
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 int copy_from_user_mono_stereo(char *to, const char *from, int count)
{
u_int *dst = (u_int *)to;
const char *end = from + count;
// printk(KERN_ERR "line %d passed!\n",__LINE__);
if (verify_area(VERIFY_READ, from, count))
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_t smdk2410_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;
unsigned long flags;
//qsm2007-05-25
// printk(KERN_ERR "line %d passed!\n",__LINE__);
DPRINTK("audio_write : start count=%d\n", count);
switch (file->f_flags & O_ACCMODE) {
case O_WRONLY:
case O_RDWR:
//printk(KERN_ERR "line %d passed!\n",__LINE__);
break;
default:
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EPERM;
}
if (!s->buffers && audio_setup_buf(s))
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -ENOMEM;
}
count &= ~0x03;
while (count > 0) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
audio_buf_t *b = s->buf;
if (file->f_flags & O_NONBLOCK) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
ret = -EAGAIN;
if (down_trylock(&b->sem))
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
break;
}
} else {
ret = -ERESTARTSYS;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if (down_interruptible(&b->sem))
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
break;
}
}
if (audio_channels == 2) {
//printk(KERN_ERR "line %d passed!audio_channels == 2\n",__LINE__);
chunksize = s->fragsize - b->size;
if (chunksize > count) //!!!
{
chunksize = count;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
}
DPRINTK("write %d to %d\n", chunksize, s->buf_idx);
if (copy_from_user(b->start + b->size, buffer, chunksize)) {
up(&b->sem);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EFAULT;
}
b->size += chunksize;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
} else {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
chunksize = (s->fragsize - b->size) >> 1;
if (chunksize > count)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
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);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EFAULT;
}
b->size += chunksize*2;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
}
//printk(KERN_ERR "line %d passed!\n",__LINE__);
buffer += chunksize;
count -= chunksize;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if (b->size < s->fragsize) { //!!!
//printk(KERN_ERR "line %d passed!\n",__LINE__);
up(&b->sem);
break; //jump out while
}
//in while
//s3c2410_dma_queue_buffer(s->dma_ch, (void *) b,
// b->dma_addr, b->size, DMA_BUF_WR);
local_irq_save(flags);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if(!play_dma_running) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
play_dma_running = 1;
__raw_writel(b->dma_addr, DISRC2); //DMA src memory
__raw_writel(0, DISRCC2); //AHB, address increase
//__raw_writel(S3C2410_IISFIFO, DIDST2); //IISFIFO address
__raw_writel(0x55000010, DIDST2); //IISFIFO phy address
__raw_writel(3, DIDSTC2); //APB, address fixed
__raw_writel(0xa0d00000|(b->size>>1), DCON2); //set mode and length
__raw_writel(2, DMTRIG2); //set channel on
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
//printk(KERN_ERR "line %d passed!\n",__LINE__);
//printk("%x\n", __raw_readl(S3C2410_IISCON));
//printk("%x\n", __raw_readl(S3C2410_IISMOD));
//printk("%x\n", __raw_readl(S3C2410_IISPSR));
//printk("%x\n", __raw_readl(S3C2410_IISFCON));
//printk("%x\n", __raw_readl(DISRC2));
//printk("%x\n", __raw_readl(DISRCC2));
//printk("%x\n", __raw_readl(DIDST2));
//printk("%x\n", __raw_readl(DIDSTC2));
//printk("%x\n", __raw_readl(DCON2));
//printk("%x\n", __raw_readl(DMTRIG2));
} else
//printk(KERN_ERR "line %d passed!\n",__LINE__);
b->dma_size = b->size;
b->size = 0;
NEXT_BUF(s, buf);
local_irq_restore(flags);
//in while
} //out while
if ((buffer - buffer0))
//printk(KERN_ERR "line %d passed!\n",__LINE__);
ret = buffer - buffer0;
DPRINTK("audio_write : end count=%d\n\n", ret);
//printk(KERN_ERR "line %d passed!audio_write : end count=%d\n",__LINE__);
return ret;
}
static ssize_t smdk2410_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;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
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;
for (i = 0; i < s->nbfrags; i++) {
audio_buf_t *b = s->buf;
down(&b->sem);
NEXT_BUF(s, buf);
}
// DMTRIG1 = 4;
// DISRC1 = 0x55000010; //DMA src IIS FIFO
// DISRCC1 = 3; //APB, address fixed
// DIDST1 = s->buf->dma_addr; //Memory address
// DIDSTC1 = 0; //AHB, address increase
// DCON1 = 0xa2d00000; //set mode and length
// DCON1 |= (s->fragsize>>1);
// DMTRIG1 = 2; //set channel on
// IISCON |= IISCON_EN; /* IIS enable(start) */
__raw_writel(4, DMTRIG1); //channel off
//__raw_writel(S3C2410_IISFIFO, DISRC1); //IISFIFO address
__raw_writel(0x55000010, DISRC1); //IISFIFO phy address
__raw_writel(3, DISRCC1); //APB, address fixed
__raw_writel(s->buf->dma_addr, DIDST1); //DMA dst memory
__raw_writel(0, DIDSTC1); //AHB, address increase
__raw_writel(0xa2d00000|(s->fragsize>>1), DCON1); //set mode and length
__raw_writel(2, DMTRIG1); //set channel on
__raw_writel(__raw_readl(S3C2410_IISCON)|IISCON_EN, S3C2410_IISCON); //IIS enable
}
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;
}
NEXT_BUF(s, buf);
}
if ((buffer - buffer0))
ret = buffer - buffer0;
DPRINTK("audio_read: return=%d\n", ret);
return ret;
}
static unsigned int smdk2410_audio_poll(struct file *file,
struct poll_table_struct *wait)
{
unsigned int mask = 0;
int i;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
DPRINTK("audio_poll(): mode=%s\n",
(file->f_mode & FMODE_WRITE) ? "w" : "");
if (file->f_mode & FMODE_READ) {
if (!input_stream.buffers && audio_setup_buf(&input_stream))
return -ENOMEM;
poll_wait(file, &input_stream.buf->sem.wait, wait);
for (i = 0; i < input_stream.nbfrags; i++) {
if (atomic_read(&input_stream.buffers.sem.count) > 0)
mask |= POLLIN | POLLWRNORM;
break;
}
}
if (file->f_mode & FMODE_WRITE) {
if (!output_stream.buffers && audio_setup_buf(&output_stream))
return -ENOMEM;
poll_wait(file, &output_stream.buf->sem.wait, wait);
for (i = 0; i < output_stream.nbfrags; i++) {
if (atomic_read(&output_stream.buffers.sem.count) > 0)
mask |= POLLOUT | POLLWRNORM;
break;
}
}
DPRINTK("audio_poll() returned mask of %s\n",
(mask & POLLOUT) ? "w" : "");
return mask;
}
static loff_t smdk2410_audio_llseek(struct file *file, loff_t offset,
int origin)
{
printk(KERN_ERR "line %d passed!\n",__LINE__);
return -ESPIPE;
}
static int audio_set_dsp_speed(__u32 val)
{
int i;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
switch (val) {
case 8000:
case 11025:
case 16000:
case 22050:
case 24000:
case 32000:
case 44100:
case 48000:
break;
default:
printk("Invalid value\n");
return -1;
}
for(i=0; i<ARRAY_SIZE(iis_psr_para); i++) {
if(iis_psr_para.rate==val)
break;
}
if(i>=ARRAY_SIZE(iis_psr_para)) {
printk("Invalid psr parameters\n");
return -1;
}
__raw_writel(((iis_psr_para.psr-1)<<5)|(iis_psr_para.psr-1), S3C2410_IISPSR);
uda1341_l3_address(UDA1341_REG_STATUS);
if(iis_psr_para.fs==256) {
uda1341_l3_data(STAT0_SC_256FS | STAT0_IF_MSB); // set 384 system clock, MSB
__raw_writel(__raw_readl(S3C2410_IISMOD)&~IISMOD_FREQ_384, S3C2410_IISMOD);
}
else {
uda1341_l3_data(STAT0_SC_384FS | STAT0_IF_MSB); // set 384 system clock, MSB
__raw_writel(__raw_readl(S3C2410_IISMOD)|IISMOD_FREQ_384, S3C2410_IISMOD);
}
i = val;
return i;
}
static int smdk2410_mixer_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
static __u32 audio_mix_modcnt = 0;
int ret;
long val = 0;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
audio_mix_modcnt++;
switch (cmd) {
case SOUND_MIXER_INFO:
{
mixer_info info;
memset(&info, 0, sizeof(info));
strncpy(info.id, "UDA1341", sizeof(info.id));
strncpy(info.name,"Philips UDA1341", sizeof(info.name));
info.modify_counter = audio_mix_modcnt;
return copy_to_user((void *)arg, &info, sizeof(info));
}
case SOUND_OLD_MIXER_INFO:
{
_old_mixer_info info;
memset(&info, 0, sizeof(info));
strncpy(info.id, "UDA1341", sizeof(info.id));
strncpy(info.name,"Philips UDA1341", sizeof(info.name));
return copy_to_user((void *)arg, &info, sizeof(info));
}
case SOUND_MIXER_READ_STEREODEVS:
return put_user(0, (long *) arg);
case SOUND_MIXER_READ_CAPS:
val = SOUND_CAP_EXCL_INPUT;
return put_user(val, (long *) arg);
case SOUND_MIXER_WRITE_VOLUME:
ret = get_user(val, (long *) arg);
if (ret)
return ret;
uda1341_volume = 63 - (((val & 0xff) + 1) * 63) / 100;
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(uda1341_volume);
break;
case SOUND_MIXER_READ_VOLUME:
val = ((63 - uda1341_volume) * 100) / 63;
val |= val << 8;
return put_user(val, (long *) arg);
case SOUND_MIXER_READ_IGAIN:
val = ((31- mixer_igain) * 100) / 31;
return put_user(val, (int *) arg);
case SOUND_MIXER_WRITE_IGAIN:
ret = get_user(val, (int *) arg);
if (ret)
return ret;
mixer_igain = 31 - (val * 31 / 100);
/* use mixer gain channel 1*/
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(EXTADDR(EXT0));
uda1341_l3_data(EXTDATA(EXT0_CH1_GAIN(mixer_igain)));
break;
default:
DPRINTK("mixer ioctl %u unknown\n", cmd);
return -ENOSYS;
}
return 0;
}
static int smdk2410_audio_ioctl(struct inode *inode, struct file *file,
uint cmd, ulong arg)
{
long val;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
switch (cmd) {
case OSS_GETVERSION:
return put_user(SOUND_VERSION, (int *)arg);
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(audio_fragsize, (long *) arg);
else
return put_user(audio_fragsize, (int *) arg);
case SNDCTL_DSP_SETFRAGMENT:
if (file->f_mode & FMODE_WRITE) {
if (output_stream.buffers)
return -EBUSY;
get_user(val, (long *) arg);
audio_fragsize = 1 << (val & 0xFFFF);
if (audio_fragsize < 16)
audio_fragsize = 16;
if (audio_fragsize > 16384)
audio_fragsize = 16384;
audio_nbfrags = (val >> 16) & 0x7FFF;
if (audio_nbfrags < 2)
audio_nbfrags = 2;
if (audio_nbfrags * audio_fragsize > 128 * 1024)
audio_nbfrags = 128 * 1024 / audio_fragsize;
if (audio_setup_buf(&output_stream))
return -ENOMEM;
}
if (file->f_mode & FMODE_READ) {
if (input_stream.buffers)
return -EBUSY;
get_user(val, (int *) arg);
audio_fragsize = 1 << (val & 0xFFFF);
if (audio_fragsize < 16)
audio_fragsize = 16;
if (audio_fragsize > 16384)
audio_fragsize = 16384;
audio_nbfrags = (val >> 16) & 0x7FFF;
if (audio_nbfrags < 2)
audio_nbfrags = 2;
if (audio_nbfrags * audio_fragsize > 128 * 1024)
audio_nbfrags = 128 * 1024 / audio_fragsize;
if (audio_setup_buf(&input_stream))
return -ENOMEM;
}
break;
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 = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
int i;
int frags = 0, bytes = 0;
if (err)
return err;
for (i = 0; i < s->nbfrags; i++) {
if (atomic_read(&s->buffers.sem.count) > 0) {
if (s->buffers.size == 0) frags++;
bytes += s->fragsize - s->buffers.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 = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
int i;
int frags = 0, bytes = 0;
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
if (err)
return err;
for(i = 0; i < s->nbfrags; i++){
if (atomic_read(&s->buffers.sem.count) > 0)
{
if (s->buffers.size == s->fragsize)
frags++;
bytes += s->buffers.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_clear_buf(&input_stream);
}
if (file->f_mode & FMODE_WRITE) {
audio_clear_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:
return -ENOSYS;
default:
return smdk2410_mixer_ioctl(inode, file, cmd, arg);
}
return 0;
}
static int smdk2410_audio_open(struct inode *inode, struct file *file)
{
int cold = !audio_active;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
DPRINTK("audio_open\n");
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if (audio_rd_refcount || audio_wr_refcount)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EBUSY;
}
//printk(KERN_ERR "line %d passed!\n",__LINE__);
audio_rd_refcount++;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
} else if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if (audio_rd_refcount || audio_wr_refcount)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EBUSY;
}
audio_wr_refcount++;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
} else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
if (audio_rd_refcount || audio_wr_refcount)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EBUSY;}
audio_rd_refcount++;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
audio_wr_refcount++;
} else
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return -EINVAL;
}
if (cold) {
//printk(KERN_ERR "line %d passed!\n",__LINE__);
audio_rate = AUDIO_RATE_DEFAULT;
audio_channels = AUDIO_CHANNELS_DEFAULT;
audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
if ((file->f_mode & FMODE_WRITE)){
//printk(KERN_ERR "line %d passed!\n",__LINE__);
init_s3c2410_iis_bus_tx();
audio_clear_buf(&output_stream);
}
if ((file->f_mode & FMODE_READ)){
//printk(KERN_ERR "line %d passed!\n",__LINE__);
init_s3c2410_iis_bus_rx();
audio_clear_buf(&input_stream);
}
}
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return 0;
}
static int smdk2410_audio_release(struct inode *inode, struct file *file)
{
DPRINTK("audio_release\n");
//printk(KERN_ERR "line %d passed!\n",__LINE__);
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 struct file_operations smdk2410_audio_fops = {
.owner = THIS_MODULE,
.llseek = smdk2410_audio_llseek,
.write = smdk2410_audio_write,
.read = smdk2410_audio_read,
.poll = smdk2410_audio_poll,
.ioctl = smdk2410_audio_ioctl,
.open = smdk2410_audio_open,
.release = smdk2410_audio_release,
};
static int smdk2410_mixer_open(struct inode *inode, struct file *file)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return 0;
}
static int smdk2410_mixer_release(struct inode *inode, struct file *file)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
return 0;
}
static struct file_operations smdk2410_mixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = smdk2410_mixer_ioctl,
.open = smdk2410_mixer_open,
.release = smdk2410_mixer_release,
};
static void init_uda1341(void)
{
unsigned long flags;
unsigned char uda_sampling;
//printk(KERN_ERR "line %d passed!\n",__LINE__);
uda1341_volume = 62 - ((DFT_VOLUME * 61) / 100);
uda1341_boost = 0;
uda_sampling = DATA2_DEEMP_NONE;
uda_sampling &= ~(DATA2_MUTE);
local_irq_save(flags);
L3MOD_HI();
L3CLK_HI();
local_irq_restore(flags);
uda1341_l3_address(UDA1341_REG_STATUS);
uda1341_l3_data(0x60); //reset uda1341
uda1341_l3_data(STAT0_SC_384FS | STAT0_IF_MSB); // set 384 system clock, MSB
uda1341_l3_data(STAT1 | STAT1_DAC_GAIN | STAT1_ADC_GAIN | STAT1_ADC_ON | STAT1_DAC_ON);
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(DATA0 |DATA0_VOLUME(uda1341_volume)); // maximum volume
uda1341_l3_data(DATA1 |DATA1_BASS(uda1341_boost)| DATA1_TREBLE(0));
uda1341_l3_data(uda_sampling);
uda1341_l3_data(EXTADDR(EXT2));
uda1341_l3_data(EXTDATA(EXT2_MIC_GAIN(0x6)) | EXT2_MIXMODE_CH1);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
}
static int __init s3c2410_uda1341_probe(struct device *dev)
{
unsigned long flags;
//qsm2007-05-25
#ifdef YLE2440_DEBUG
printk("just enter s3c2410_uda1341_probe()\n");
#endif
this_dev = dev;
printk("S3C2410-UDA1341 Probe\n");
local_irq_save(flags);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
//L3 mode=GPB2, dat=GPB3, clk=GPB4, output
__raw_writel(__raw_readl(S3C2410_GPBCON)&~(0x3f<<4), S3C2410_GPBCON);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(__raw_readl(S3C2410_GPBCON)|(0x15<<4), S3C2410_GPBCON);
#ifdef YLE2440_DEBUG
printk(KERN_ERR "line %d passed! have set L3 mode=GPB2, dat=GPB3, clk=GPB4, output\n",__LINE__);
#endif //IISLRCK=GPE0, IISSCLK=GPE1, CDCLK=GPE2, IISSDI=GPE3, IISSDO=GPE4
__raw_writel(__raw_readl(S3C2410_GPECON)&~0x3ff, S3C2410_GPECON);
//printk(KERN_ERR "line %d passed!\n",__LINE__);
__raw_writel(__raw_readl(S3C2410_GPECON)|0x2aa, S3C2410_GPECON);
#ifdef YLE2440_DEBUG
printk(KERN_ERR "line %d passed! \nhave set IISLRCK=GPE0, IISSCLK=GPE1, CDCLK=GPE2, IISSDI=GPE3, IISSDO=GPE4\n",__LINE__);
#endif
local_irq_restore(flags);
__raw_writel(__raw_readl(S3C2410_CLKCON)|(1<<17), S3C2410_CLKCON); //Enable IIS clock
//printk(KERN_ERR "line %d passed! have Enable IIS clock\n",__LINE__);
printk("have Enable IIS clock!\n");
init_uda1341();
/* output_stream.dma_ch = DMA_CH2;
if (audio_init_dma(&output_stream, "UDA1341 out")) {
audio_clear_dma(&output_stream);
printk( KERN_WARNING AUDIO_NAME_VERBOSE
": unable to get DMA channels\n" );
return -EBUSY;
}*/
/* input_stream.dma_ch = DMA_CH1;
if (audio_init_dma(&input_stream, "UDA1341 in")) {
audio_clear_dma(&input_stream);
printk( KERN_WARNING AUDIO_NAME_VERBOSE
": unable to get DMA channels\n" );
return -EBUSY;
}*/
if(request_irq(IRQ_DMA2, iisout_dma_done_handler, SA_INTERRUPT,
"IIS Play", NULL) < 0) {
printk( KERN_ERR AUDIO_NAME_VERBOSE
": unable to get DMA interrupts for play\n" );
return -EBUSY;
}
//qsm2007-05-25
#ifdef YLE2440_DEBUG
else printk(KERN_ERR "success register irq: iisout_dma_done_handler\n" );
#endif
if(request_irq(IRQ_DMA1, iisin_dma_done_handler, SA_INTERRUPT,
"IIS Record", NULL) < 0) {
free_irq(IRQ_DMA2, NULL);
printk( KERN_WARNING AUDIO_NAME_VERBOSE
": unable to get DMA interrupts for record\n" );
return -EBUSY;
}
#ifdef YLE2440_DEBUG
else printk(KERN_ERR "success register irq: iisin_dma_done_handler\n" );
#endif
audio_dev_dsp = register_sound_dsp(&smdk2410_audio_fops, -1);
audio_dev_mixer = register_sound_mixer(&smdk2410_mixer_fops, -1);
printk(AUDIO_NAME_VERBOSE " initialized\n");
return 0;
}
static int s3c2410_uda1341_remove(struct device *dev)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
printk(KERN_ERR "just enter s3c2410_uda1341_remove()\n");
unregister_sound_dsp(audio_dev_dsp);
unregister_sound_mixer(audio_dev_mixer);
// audio_clear_dma(&output_stream);
// audio_clear_dma(&input_stream); /* input */
__raw_writel(4, DMTRIG2); //DMA channel off
__raw_writel(4, DMTRIG1);
__raw_writel(__raw_readl(S3C2410_IISCON)&~IISCON_EN, S3C2410_IISCON); // IIS disable
__raw_writel(__raw_readl(S3C2410_CLKCON)&~(1<<17), S3C2410_CLKCON); //Disable IIS clock
free_irq(IRQ_DMA1, NULL);
free_irq(IRQ_DMA2, NULL);
printk(AUDIO_NAME_VERBOSE " unloaded\n");
return 0;
}
static struct device_driver s3c2410_uda1341_driver = {
.name = "s3c2410-iis",
.bus = &platform_bus_type,
.probe = s3c2410_uda1341_probe,
.remove = s3c2410_uda1341_remove,
//#ifdef CONFIG_PM
//.suspend = s3c2410_uda1341_suspend,
//.resume = s3c2410_uda1341_resume,
//#endif
};
static int __init s3c2410_uda1341_init(void)
{
int ret;
//qsm2007-05-25
#ifdef YLE2440_DEBUG
printk(KERN_ERR "line %d passed!\n",__LINE__);
printk(KERN_INFO "virtual address of s3c2410_va_iis=%08x.\n",S3C2410_IISCON); printk(KERN_ERR "next will do driver_register!\n");
#endif
ret = driver_register(&s3c2410_uda1341_driver);
if(ret)
printk("register device driver failed, return code is %d\n", ret);
#ifdef YLE2440_DEBUG
printk(KERN_ERR "driver uda1341 in /sound/oss/s3c2410-oss.c\n");
printk(KERN_ERR "line %d passed!\n",__LINE__);
#endif
return ret;
}
static void __exit s3c2410_uda1341_exit(void)
{
//printk(KERN_ERR "line %d passed!\n",__LINE__);
driver_unregister(&s3c2410_uda1341_driver);
}
#ifdef MODULE
MODULE_AUTHOR("antiscle http://www.ucdragon.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("S3C2410 + UDA1341TS driver for OSS");
//MODULE_CLASSES("{sound}");
//MODULE_DEVICES("{{UDA1341,FS2410}}");
#endif
module_init(s3c2410_uda1341_init);
module_exit(s3c2410_uda1341_exit);
这个驱动里面有:DSP,MIXER,UDA1341,IIS,DMA这几部分内容!
static struct device_driver s3c2410_uda1341_driver = {
.name = "s3c2410-iis",
.bus = &platform_bus_type,
.probe = s3c2410_uda1341_probe,
.remove = s3c2410_uda1341_remove,
};
就注册这个驱动程序就完成了整个注册!没有做DMA申请!怎么也可以工作!这个是2。6内核下面的!
在2。4内核里面,整个方式不是这样的!
1,对DAM申请,
2、初始化DMA,
3、register_DSP()和register_MIXER()
4、init_UDA1341芯片
5、IIS初始化
6、DMA中断读/写!
这个驱动里面汲到 :总线,设备,驱动程序!
这三个方面的内容!
在这个驱动里面三者是怎么关联在一起的!
代码也太长了点,我觉得你应该把问题描述清楚再贴代码