+ -
当前位置:首页 → 问答吧 → oss uda1341移植到linux-2.6.22(s3c2410)的痛苦,各位大侠救命啊!

oss uda1341移植到linux-2.6.22(s3c2410)的痛苦,各位大侠救命啊!

时间:2007-11-14

来源:互联网

我现在在向linux-2.6.22 移植uda3141的oss驱动。现在连声音也没有,希望大侠能指点一下。附件是uda1341的代码

问题如下:
1. Audio驱动,我的理解是 打开I2S--> I2S往UDA1341传PCM数据 -->I2S FIFO空 --> 自动从要求DMA传数据 --> DMA所有数据传输完成 --> 传送新的数据给DMA BUFFER。
   我如何确定,是I2S根本没有启动传送,还是DMA问题。如何处理?

2. 2.6.22的DMA部分有改动,你有移植过吗?

3. 无声音输出,你觉得是什么问题。

4. 我一直怀疑,我是否因为硬件的内存映射有问题,造成根本就没有实际写到硬件寄存器。如何判断。我也不知道!

希望得到您的回复。


//----------------------------------------------------------
// 启动,初始化uda1341声卡信息。看起来没啥问题。
driver_register : s3c2410iis_driver...
L3_addr:0x16
L3_data:0x40
L3_data:0x29
L3_data:0x83
L3_addr:0x14
L3_data:0x0
L3_data:0x40
L3_data:0x80
L3_data:0xc2
L3_data:0xf9
s3c2410iis_probe(): DMA_CH2 for UDA1341 out
search the channel map for first free, dma_channels:4
mapped channel 2 to 0
s3c2410iis_probe(): DMA_CH1 for UDA1341 in
search the channel map for first free, dma_channels:4
mapped channel 1 to 1
UDA1341 audio driver initialized




//-------------------------------------------------------------------
// cat 一个文件,如下信息。停在最后一行不动了。似乎是只灌完4个buffer,由于没一个buffer空,所以DMA不再请求。
# cat wp.wav > /dev/dsp
audio_open
initialization s3c2410 iis bus.
prescaler = 2
prescaler = 2
s3c2410-uda1341: audio_set_dsp_speed:44100 prescaler:66
write IISCON,[0xf0d00000]:0x33
write IISMOD,[0xf0d0000c]:0xffff
write IISFCON,[0xf0d00004]:0xdd
audio_clear_buf
audio_write : start count=8192
audio_setup_buf(),nbfrags:4,fragsize:8192             (我把buffer改成了4个)
buf 0: start ffc27000 dma 859963392
buf 1: start ffc29000 dma 859971584
buf 2: start ffc2b000 dma 859979776
buf 3: start ffc2d000 dma 859987968
ACH2:write 8192 to 0
audio_write : end count=8192

audio_write : start count=8192
ACH:write 8192 to 1
audio_write : end count=8192

audio_write : start count=8192
ACH2:write 8192 to 2
audio_write : end count=8192

audio_write : start count=8192
ACH2:write 8192 to 3
audio_write : end count=8192

audio_write : start count=8192
audio_write : end count=-512       (为什么有负数)
(停在这里不动了。)

//-------------------------------------------------------------------
// 查看中断情况,发现I2SSDO,I2SSDI 中断次数为0. 也就是将DMA确实根本没中断过。

# cat /proc/interrupts
           CPU0
25:          0         s3c  s3c2410-wdt
30:     345303         s3c  S3C2410 Timer Tick
32:          0         s3c  s3c2410-lcd
33:          0         s3c  I2SSDO
34:          0         s3c  I2SSDI
43:          0         s3c  s3c2410-i2c
53:          1     s3c-ext  eth0
70:        176   s3c-uart0  s3c2410-uart
71:        415   s3c-uart0  s3c2410-uart
Err:          0
#
#      

作者: manwjh   发布时间: 2007-11-14

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;
}      

作者: manwjh   发布时间: 2007-11-14

static int s3c2410iis_probe(struct device *dev) {
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *res;

        unsigned long flags;

        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                printk(KERN_INFO PFX "failed to get memory region resouce\n");
                return -ENOENT;
        }
//                DPRINTK("s3c2410iis_probe(): get resource...\n");                //wjh debug
        iis_base = (void *)S3C24XX_VA_IIS ;
        if (iis_base == 0) {
                printk(KERN_INFO PFX "failed to ioremap() region\n");
                return -EINVAL;
        }
//                DPRINTK("s3c2410iis_probe()-iis_base:%d\n",iis_base);                //wjh debug
        iis_clock = clk_get(dev, "iis");
        if (iis_clock == NULL) {
                printk(KERN_INFO PFX "failed to find clock source\n");
                return -ENOENT;
        }
//                DPRINTK("s3c2410iis_probe()-iis_clock:%d\n",iis_clock);                //wjh debug
               clk_enable(iis_clock);

        local_irq_save(flags);

        /* GPB 4: L3CLOCK, OUTPUT */
        s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
//        s3c2410_gpio_pullup(S3C2410_GPB4, 1);
        /* GPB 3: L3DATA, OUTPUT */
        s3c2410_gpio_cfgpin(S3C2410_GPB3,S3C2410_GPB3_OUTP);
        /* GPB 2: L3MODE, OUTPUT */
        s3c2410_gpio_cfgpin(S3C2410_GPB2,S3C2410_GPB2_OUTP);
//        s3c2410_gpio_pullup(S3C2410_GPB2, 1);
        /* GPE 3: I2SSDI */
        s3c2410_gpio_cfgpin(S3C2410_GPE3,S3C2410_GPE3_I2SSDI);      
        s3c2410_gpio_pullup(S3C2410_GPE3, 1);
        /* GPE 0: I2SLRCK */
        s3c2410_gpio_cfgpin(S3C2410_GPE0,S3C2410_GPE0_I2SLRCK);
        s3c2410_gpio_pullup(S3C2410_GPE0, 1);
        /* GPE 1: I2SSCLK */
        s3c2410_gpio_cfgpin(S3C2410_GPE1,S3C2410_GPE1_I2SSCLK);      
        s3c2410_gpio_pullup(S3C2410_GPE1, 1);
        /* GPE 2: CDCLK */
        s3c2410_gpio_cfgpin(S3C2410_GPE2,S3C2410_GPE2_CDCLK);               
        s3c2410_gpio_pullup(S3C2410_GPE2, 1);
        /* GPE 4: I2SSDO */
        s3c2410_gpio_cfgpin(S3C2410_GPE4,S3C2410_GPE4_I2SSDO);
        s3c2410_gpio_pullup(S3C2410_GPE4, 1);

        local_irq_restore(flags);

        init_s3c2410_iis_bus();        /* clear I2S controller of S3C2410, IISPSR,IISCON,IISMOD,IISFCON = 0x0s */

        init_uda1341();

//audio DMA initialization
                DPRINTK("s3c2410iis_probe(): DMA_CH2 for UDA1341 out\n");                //wjh debug
        output_stream.dma_ch = DMA_CH2;
        if (audio_init_dma(&output_stream, "UDA1341 out")) {
                audio_clear_dma(&output_stream,&s3c2410iis_dma_out);
                printk( KERN_WARNING AUDIO_NAME_VERBOSE
                        ": unable to get DMA channels\n" );
                return -EBUSY;
                       }
               
                DPRINTK("s3c2410iis_probe(): DMA_CH1 for UDA1341 in\n");                //wjh debug
        input_stream.dma_ch = DMA_CH1;

           if (audio_init_dma(&input_stream, "UDA1341 in")) {
                        audio_clear_dma(&input_stream,&s3c2410iis_dma_in);
                        printk( KERN_WARNING AUDIO_NAME_VERBOSE
                        ": unable to get DMA channels\n" );
                        return -EBUSY;
                }

        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;
}      

作者: manwjh   发布时间: 2007-11-14