s3c2410-uda1341.c 代码
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;
DPRINTK("audio_write : start count=%d\n", count);
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 (audio_channels == 2) {
chunksize = s->fragsize - b->size; //
if (chunksize > count)
chunksize = count;
DPRINTK("ACH2: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;
}
if((ret = s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, b->size))) {
printk(PFX"dma enqueue failed.\n");
return ret;
}
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 int smdk2410_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)
if (audio_rd_refcount) //mdy by wjh, 有人认为这是不能同时录放的原因
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;
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();
if ((file->f_mode & FMODE_WRITE)){
// init_s3c2410_iis_bus_tx();//del by wjh
audio_clear_buf(&output_stream);
}
if ((file->f_mode & FMODE_READ)){
// init_s3c2410_iis_bus_rx(); //del by wjh
audio_clear_buf(&input_stream);
}
}
return 0;
}
static void init_uda1341(void)
{
unsigned long flags;
uda1341_volume = 62 - ((DEF_VOLUME * 61) / 100);
uda1341_boost = 0;
uda_sampling = DATA2_DEEMP_NONE;
uda_sampling &= ~(DATA2_MUTE);
local_irq_save(flags);
s3c2410_gpio_setpin(S3C2410_GPB2,1); //L3MODE=1
s3c2410_gpio_setpin(S3C2410_GPB3,1); //L3MODE=1
s3c2410_gpio_setpin(S3C2410_GPB4,1); //L3CLOCK=1
local_irq_restore(flags);
//uda1341, initialization status control register
uda1341_l3_address(UDA1341_REG_STATUS); // reset uda1341
uda1341_l3_data(STAT0_RST);
uda1341_l3_data(STAT0_SC_256FS | STAT0_IF_MSB|STAT0_DC_FILTER);
uda1341_l3_data(STAT1 | STAT1_ADC_ON | STAT1_DAC_ON);
//uda1341, set DATA0,DATA1 register
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(DATA0 |DATA0_VOLUME(0x0)); // maximum volume
uda1341_l3_data(DATA1 |DATA1_BASS(uda1341_boost)| DATA1_TREBLE(0));
// uda1341_l3_data((DATA2 |DATA2_DEEMP_NONE) &~(DATA2_MUTE)); //??? wjh
uda1341_l3_data(DATA2 | uda_sampling); /* --;;*/
uda1341_l3_data(EXTADDR(EXT2));
uda1341_l3_data(EXTDATA(EXT2_MIC_GAIN(0x6)) | EXT2_MIXMODE_CH1);
}
/* DMA_CH1 input, DMA_CH2 output */
static int __init audio_init_dma(audio_stream_t * s, char *desc)
{
int ret ;
// s3c2410_dmasrc_t source; //mdy by wjh, because Linux-2.6.22, dma.h changed
enum s3c2410_dmasrc source;
int hwcfg;
unsigned long devaddr;
dmach_t channel;
int dcon;
unsigned int flags = 0;
// DPRINTK("audio init dma: Chanel %d,%s\n,",s->dma_ch,desc); //wjh debug
if(s->dma_ch == DMA_CH2){
channel = 2;
source = S3C2410_DMASRC_MEM;
hwcfg = 3;
devaddr = 0x55000010;
// dcon = 1<<31; //test wjh
// dcon = (1<<31) | (2<<24);
// dcon = 0xa0800000;
dcon = 0xa0900000;
flags = S3C2410_DMAF_AUTOSTART;
ret = s3c2410_dma_request(s->dma_ch, &s3c2410iis_dma_out, NULL);
s3c2410_dma_devconfig(channel, source, hwcfg, devaddr);
s3c2410_dma_config(channel, 2, dcon);
s3c2410_dma_set_buffdone_fn(channel, audio_dmaout_done_callback);
s3c2410_dma_setflags(channel, flags);
// ret = s3c2410_dma_request(s->dma_ch, &s3c2410iis_dma_out, NULL);
s->dma_ok = 1;
return ret;
}
else if(s->dma_ch == DMA_CH1){
channel = 1;
ret = s3c2410_dma_request(s->dma_ch, &s3c2410iis_dma_in, NULL);
s3c2410_dma_set_buffdone_fn(channel, audio_dmain_done_callback);
return ret ;
}
else
return 1;
}
|