• 36、ALSA声卡驱动和应用


    (注意;内核上电的时候会把一些没运行的控制器模块的时钟都关掉,所有在写驱动的时候需要在使用的使用使用clk_get和clk_enable使能时钟)

    (说明:与ALSA声卡对应的是OSS架构,第二期视频中的声卡驱动就是指的OSS架构驱动,ALSA可以模拟OSS)

    (amixer controls执行后返回的可设置属性里面input mux表示录音的时候的通道,在mini2440和tq2440上两者不同,需要修改)

    1.裸板
    WAV文件格式:http://blog.chinaunix.net/uid-21977330-id-3976817.html

    涉及的操作:A、SOC(2440)部分的IIS操作,DMA操作(一般就是设置IIS管脚和寄存器,通过DMA把数据拷贝到IIS的FIFO寄存器)

          B、Codec(编解码芯片)部分的设置(初始化、格式、音量)

               C、Machine(单板)部分的控制引脚不同,使用控制引脚来初始化Codec

    裸版程序也是分为这三个部分来操作

    2.驱动

    sound.c是顶层驱动框架,里面会注册个file_operations,其只有一个open函数,在open函数中已次设备号在snd_minors数组中找到一项,取出真正的file_operation结构体,入口函数会创建一个字符设备register_chrdev

    说明:

    snd_card_create(init.c)

      snd_ctl_create(同一个声卡有多个逻辑设备,ctl应该是控制类的逻辑设备)

        .dev_register = snd_ctl_dev_register

        snd_device_new(创建声卡的ctl逻辑设备,通过参数SNDRV_DEV_CONTROL指定,其会导致dev_register 被调用,也就是snd_ctl_dev_register被调用)    

          snd_ctl_dev_register(control.c中)

            snd_register_device(这个函数有个参数snd_ctl_f_ops,其是真正的file_operation结构体)

              snd_register_device_for_dev(用数据填充preg)

                snd_minors[minor]=preg;

                device_create(在class下创建设备)

    snd_pcm_new(某个声卡驱动里面调用snd_pcm_new)

      _snd_pcm_new

        snd_pcm_new_stream(pcm,.....PLAYBACK,playback_count);//创建播放 

        snd_pcm_new_stream(pcm,.....CAPTURE,capture_count);//创建录音

        .dev_register = snd_pcm_dev_register

           snd_device_new(创建声卡的pcm逻辑设备,通过参数SNDRV_DEV_PCM指定,其会导致dev_register 被调用,也就是snd_pcm_dev_register被调用)   

          snd_pcm_dev_register()

            for(执行两次,声卡具有录音和播放功能)

              snd_register_device_for_dev(pcm.c中)(有个snd_pcm_f_ops[]数组,是真正的file_operation结构体)

                snd_minors[minor]=preg;

                device_create(在class下创建设备,class是在sound_core.c中的init_soundcore中被调用)

    怎么写ALSA声卡驱动?(参考:Linux ALSA声卡驱动.pdf)

    1、调用snd_card_create接口创建snd_card的一个实例

    2、初始化,调用snd_pcm_new和snd_ctl_create(snd_ctl_create在snd_card_create中已被默认调用)等接口创建声卡的功能部件(逻辑设备)

    3、snd_card_register

    linux在ALSA架构的基础上又封装了一个ASOC(alsa system on chip),使用ASOC的代码不用安装ALSA的架构写驱动,ASOC把驱动分为三部分:

    1、machine:单板相关,表面platform是哪个,cpu DAI是哪个(cpu与codes相连的接口是哪个),DMA是哪个(负责数据传输)

                表面codec是哪个,codec DAI是哪个(codec与cpu相连的接口是哪个)

    machine这块的代码对应linux内核中s3c24xx_uda134x.c,通过注册一个platform_driver,当通过总线发现有同名时,调用probe(A)函数,在内核中搜索注册的名字,发现在mach-mini2440.c中有个platform_device;

    同时,在probe(A)函数中会通过platform_device_alloc("soc-audio")来创建一个device,因此肯定会有一个同名的driver,在内核中搜索,发现在soc-core.c中有个同名的driver,查看此结构中probe(B),其会调用snd_soc_register_card(card),这个card就是在probe(A)中通过platform_set_drvdata设置的核心结构体(struct snd_soc_card) snd_soc_s3c24XX_uda134x,这个核心结构体有一个dai_link的子结构体,里面有很多名字,比如:

    codec_name = "uda134x-codec"//指定了用哪个codec

    codec_dai_name = "uda134x-hifi"//指定了用codec芯片里的哪一个DAI(比如哪个IIS接口)

    cpu_dai_name = "s3c24xx-iis"//指定了用CPU(比如2440)的那个DAI(比如哪个IIS接口)

    platform_name = "samsung_audio"//指定了CPU端的DMA

    根据这里设置的名字来找到对应的platform和codec驱动程序

    2、platform:DAI  设置接口用来初始化codec及数据传输(对外),需要构造struct snd_soc_dai_driver s3c24xx_i2s_dai结构体(里面有接口支持的最小和最大通道数(左右声道))

          DMA 数据传输(内部),需要构造struct snd_soc_platform_driver samsung_asoc_platform结构体

    根据 "s3c24xx-iis"名字在内核中搜索,找到s3c24xx-i2s.c文件中的platform_driver,devs.c文件中的platrom_device,这两者是一对,platform_driver中的probe函数调用snd_soc_register_dai(注册了一个dai),有个核心的结构体s3c24xx_i2s_dai,该结构体里面的函数用于操作cpu-DAI(比如提供设置2440端IIS控制器的函数等)

    根据 "samsung_audio"名字在内核中搜索,找到sound/soc/samsung/dma.c文件中的platform_driver,sound/arm/plat-samsung/devs.c文件中的platrom_device,这两者是一对,platform_driver中的probe函数调用snd_soc_register_platform,其也有个核心结构体samsung_asoc_platform,该结构体里面的函数用于操作cpu的DMA

    3、codec:DAI 要实现uda134x_dai

         控制接口 要实现soc_codec_dev_uda134x

    根据 "uda134x-codec"名字在内核中搜索,找到sound/soc/codecs/uda134x.c文件中的platform_driver,arch/arm/mach-s3c24xx/mach-mini2440.c文件中的platrom_device,这两者是一对,platform_driver中的probe函数调用snd_soc_register_codec,关键结构体有struct snd_soc_codec_driver  soc_codec_dev_uda134x和struct snd_soc_dai_driver uda134x_dai,其中soc_codec_dev_uda134x就是提供了函数来完成控制接口初始化的工作,uda134x_dai提供DAI接口相关操作和参数

    ASOC和ALSA这么关联起来:

    1. platform:
    1.1 s3c24xx-i2s.c : 把s3c24xx_i2s_dai放入链表dai_list, .name = "s3c24xx-iis",
    s3c24xx_iis_dev_probe
      snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
        list_add(&dai->list, &dai_list);

    1.2 sound/soc/samsung/dma.c : 把samsung_asoc_platform放入了链表platform_list, .name = "samsung-audio",
    samsung_asoc_platform_probe
      snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
        list_add(&platform->list, &platform_list);

    2. codec: uda134x.c
    uda134x_codec_probe
      snd_soc_register_codec(&pdev->dev,&soc_codec_dev_uda134x, &uda134x_dai, 1);
        struct snd_soc_codec *codec;
        codec->driver = codec_drv; (codec_drv= &soc_codec_dev_uda134x)

        snd_soc_register_dais(dev, dai_drv, num_dai); // dai_drv就是uda134x_dai
          list_add(&dai->list, &dai_list); : 把uda134x_dai放入了链表dai_list,dai_list里面既有uda134x_dai,也有s3c24xx_i2s_dai
        list_add(&codec->list, &codec_list);

    3. machine:
    s3c24xx_uda134x_probe
      s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
      platform_set_drvdata(s3c24xx_uda134x_snd_device, &snd_soc_s3c24xx_uda134x);
      platform_device_add(s3c24xx_uda134x_snd_device);//device添加的时候会导致soc-core.c里面的同名(名字是在上面设置的"soc-audio")driver的probe(soc_probe)函数被调用

        .....
        soc_probe
          snd_soc_register_card(card); // card = &snd_soc_s3c24xx_uda134x

            card->rtd = devm_kzalloc(card->dev,...
            card->rtd[i].dai_link = &card->dai_link[i]; // &s3c24xx_uda134x_dai_link

            list_add(&card->list, &card_list);

            snd_soc_instantiate_cards(); // 实例化声卡

              //对card_list里面的每一个card调用snd_soc_instantiate_card
              snd_soc_instantiate_card(card);
                3.1 /* bind DAIs */
                for (i = 0; i < card->num_links; i++)//soc-core.c是公共函数,这里的num_links是指的源码里面的各个平台的数目,比如samsung、mips、atmel,对各个平台的card绑定machine、platform、codec
                  soc_bind_dai_link(card, i);
                    3.1.1 /*根据名字在dai_list 中find CPU DAI */
                    rtd->cpu_dai = cpu_dai; = //&s3c24xx_i2s_dai
                    3.1.2 /*根据名字在codec_list 中 find_codec */
                    rtd->codec = codec; = // codec, codec->driver=&soc_codec_dev_uda134x
                    3.1.3 /*根据名字在dai_list 中 find CODEC DAI */
                    rtd->codec_dai = codec_dai; // = &uda134x_dai
                    3.1.4 /*根据名字在platform_list 中 find_platform(DMA) */
                    rtd->platform = platform; // = &samsung_asoc_platform
                3.2 /* initialize the register cache for each available codec */
                ret = snd_soc_init_codec_cache(codec, compress_type);//初始化codec的寄存器

                3.3 snd_card_create(这里开始是ALSA驱动框架了,可以看前面的怎么写ALSA驱动)

                3.4 /* early DAI link probe */
                soc_probe_dai_link
                  /* probe the cpu_dai *///调用cpu_dai的probe函数来做一些初始化,下面的一样
                  /* probe the CODEC */
                  /* probe the platform */ 
                  /* probe the CODEC DAI */
                  /* create the pcm */
                  ret = soc_new_pcm(rtd, num);
                    struct snd_pcm_ops *soc_pcm_ops = &rtd->ops;
                    soc_pcm_ops->open = soc_pcm_open;
                    soc_pcm_ops->close = soc_pcm_close;
                    soc_pcm_ops->hw_params = soc_pcm_hw_params;
                    soc_pcm_ops->hw_free = soc_pcm_hw_free;
                    soc_pcm_ops->prepare = soc_pcm_prepare;
                    soc_pcm_ops->trigger = soc_pcm_trigger;
                    soc_pcm_ops->pointer = soc_pcm_pointer;
                
                    snd_pcm_new (这里开始是ALSA驱动框架了,可以看前面的怎么写ALSA驱动)


                3.5 snd_card_register(这里开始是ALSA驱动框架了,可以看前面的怎么写ALSA驱动)


    2.1 配置内核支持UDA1341:
    CONFIG_SND_S3C24XX_I2S // s3c24xx-i2s.c
    CONFIG_SND_SOC_SAMSUNG // dma.c

    CONFIG_SND_SOC_UDA134X // uda134x.c

    CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X // s3c24xx_uda134x.c

    CONFIG_S3C24XX_DMA

    -> Device Drivers
      -> Sound card support
        -> Advanced Linux Sound Architecture
          -> ALSA for SoC audio support
           <*> ASoC support for Samsung // CONFIG_SND_SOC_SAMSUNG
           <*> SoC I2S Audio support UDA134X wired to a S3C24XX // CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X // s3c24xx_uda134x.c

    -> System Type
      [*] S3C2410 DMA support

    2.2 修改代码

    (根据上面的分析platform_device都是在mach_mini2440.c中被注册(定义有的在dev.c中),我们jz2440需要照样修改,如下)
    a. 修改mach-smdk2440.c 添加"s3c24xx_uda134x"平台设备(machine)
    b. 修改mach-smdk2440.c 添加"s3c24xx-iis"平台设备(platform IIS)
    c. 修改mach-smdk2440.c 添加"samsung-audio"平台设备(platform DMA)
    d. 修改mach-smdk2440.c 添加"uda134x-codec"平台设备

    2.3 修改bug: soundsocsamsungdma.c
    pos += prtd->dma_period;
    改为
    pos += prtd->dma_period*limit;


    3. 编译alsa-lib, alsa-util以使用声卡:
    3.1 alsa-lib(是库,应用程序使用库可以简化对声卡的操作)  :
    sudo mv /usr /usr_bak
    export PATH=/usr_bak/local/sbin:/usr_bak/local/bin:/usr_bak/sbin:/usr_bak/bin:/sbin:/bin:/usr_bak/games:/usr_bak/local/arm/4.3.2/bin
    ./configure --host=arm-linux(alsa-lib在编译的时候如果指定了prefix=A,即安装目录A,则必须把生成的库放到开发板上同名目录A,如果不指定则默认的是/usr,而PC机上usr目录下有很多问题,这样安装会破坏PC机usr目录,所有有上面的mv操作,先保存usr)
    make
    sudo mkdir /usr
    sudo chown book:book /usr
    make install
    sudo cp -rf /usr /work/projects/alsa/
    sudo rm -rf /usr
    sudo mv /usr_bak /usr
    export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/arm/4.3.2/bin

    把头文件和库复制进交叉工具链里
    cd /work/projects/alsa/usr/include
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

    cd /work/projects/alsa/usr/lib
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

    把库复制到根文件系统的lib目录下
    cd /work/projects/alsa
    sudo -rfd usr /work/nfs_root/fs_mini_mdev_new

    3.2 alsa-util(是应用程序,通过alse-lib来访问声卡)
    3.2.1 先编译依赖:ncurses-5.9.tar.gz
    ./configure --host=arm-linux --prefix=$PWD/tmp --with-shared(./configure --help会看到--with-shared表示会生成共享lib)
    make && make install(会出错,不用理会,在tmp目录下已经生成lib了)

    把头文件和库复制进交叉工具链里
    cd /work/projects/alsa/ncurses-5.9/tmp/include/ncurses(必须还把ncurses目录拷贝到include中去,因为有些头文件回去ncurses目录下去找)
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
    cd /work/projects/alsa/ncurses-5.9/tmp/include/
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

    cd /work/projects/alsa/ncurses-5.9/tmp/lib
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

    把库复制到根文件系统的lib目录下
    cd /work/projects/alsa/ncurses-5.9/tmp/lib
    sudo cp *so* -rfd /work/nfs_root/fs_mini_mdev_new/lib


    3.2.2 编译alsa-util:
    ./configure --host=arm-linux --prefix=$PWD/tmp --with-curses=ncurses --disable-xmlto --disable-nls
    make
    sudo make install 

    cd ./tmp

    sudo cp * -rfd /work/nfs_root/fs_mini_mdev_new/usr

    3.2.3 测试(alsa-util生成的应用程序是访问/dev/snd下的声卡设备节点,所有需要生成链接文件)
    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c

    播放:
    aplay Windows.wav
    调音量:
    amixer controls

    (执行上面的指令后会获得可以设置声卡的哪些属性,有个numid,再通过numid来设置具体的值)
    amixer cget numid=1
    amixer cset numid=1 30


    4. 编译新的strace工具以跟踪声卡调用过程:(旧的工具识别不了alsa-util的ioctl)

    见第二期视频blog,编译完成后把生成的bin目录下的工具全部拷贝到网络文件系统的bin目录下

    执行strace -o aplay.log aplay Windows.wax  生成的log见后面或者“asoc分析.txt”

    strace分析: aplay Windows.wav
    1. /dev/snd/controlC0 对应的file_operations是snd_ctl_f_ops
    open : snd_ctl_open
    SNDRV_CTL_IOCTL_PVERSION : snd_ctl_ioctl -> put_user(SNDRV_CTL_VERSION, ip)
    SNDRV_CTL_IOCTL_CARD_INFO : snd_ctl_ioctl -> snd_ctl_card_info(card, ctl, cmd, argp);
                            copy_to_user

    SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE : snd_ctl_ioctl -> snd_pcm_control_ioctl -> get_user后control->prefer_pcm_subdevice = val;
    (snd_ctl_ioctl 没有SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE 命令,其是在snd_control_ioctls这个东西中取出snd_pcm_control_ioctl结构体,snd_pcm_control_ioctl在alsa_pcm_init函数中通过snd_ctl_register_ioctl函数注册到 snd_control_ioctls中
    close
    上述三个ioctl不涉及硬件操作

    2. /dev/snd/pcmC0D0p 对应的file_operations是snd_pcm_f_ops[0]
    open : snd_pcm_playback_open
      snd_pcm_open
        snd_pcm_open_file
          struct snd_pcm_substream *substream;(这个结构体很有用)
          snd_pcm_open_substream(会对*substream;赋值)
            err = snd_pcm_hw_constraints_init(substream);
                snd_mask_any
                snd_interval_any
                ......
            err = substream->ops->open(substream) // substream->ops : snd_pcm_ops结构体(就是在soc_new_pcm里面设置的soc_pcm_ops)
                        soc_pcm_open
                          依次调用cpu_dai, dma, codec_dai, machine的open或startup函数
    uda134x_startup 里:snd_pcm_hw_constraint_minmax(SNDRV_PCM_HW_PARAM_RATE),snd_pcm_hw_constraint_minmax(SNDRV_PCM_HW_PARAM_SAMPLE_BITS)
    dma_open里: snd_pcm_hw_constraint_integer,snd_soc_set_runtime_hwparams
    runtime->hw.info = hw->info; = SNDRV_PCM_INFO_INTERLEAVED |
        SNDRV_PCM_INFO_BLOCK_TRANSFER |
        SNDRV_PCM_INFO_MMAP |
        SNDRV_PCM_INFO_MMAP_VALID |
        SNDRV_PCM_INFO_PAUSE |
        SNDRV_PCM_INFO_RESUME,
            snd_pcm_hw_constraints_complete
          pcm_file->substream = substream;
          file->private_data = pcm_file;

    注意:substream->ops = soc_new_pcm函数里的soc_pcm_ops

    以下的ioctl入口都是:snd_pcm_playback_ioctl
    SNDRV_PCM_IOCTL_INFO : snd_pcm_info_user(substream, arg);
                    substream->ops->ioctl(substream,
                      snd_pcm_lib_ioctl

    SNDRV_PCM_IOCTL_PVERSION : put_user(SNDRV_PCM_VERSION, (int __user *)arg)
    SNDRV_PCM_IOCTL_TTSTAMP : snd_pcm_tstamp(substream, arg);

    SNDRV_PCM_IOCTL_SYNC_PTR : snd_pcm_sync_ptr(substream, arg); 先不管

    SNDRV_PCM_IOCTL_HW_REFINE(规范硬件参数) .... : snd_pcm_hw_refine_user(substream, arg);
                                memdup_user(获取用户空间的参数)
                                snd_pcm_hw_refine(substream, params); (把参数根据硬件修改下)先不管
                                copy_to_user(把修改的参数传回去)
    SNDRV_PCM_IOCTL_HW_PARAMS : snd_pcm_hw_params_user(substream, arg);
    (设置硬件参数)             memdup_user
                        snd_pcm_hw_params
                          substream->ops->hw_params(substream, params);(substream->ops就是在 soc_new_pcm函数里设置的soc_pcm_ops

                             soc_pcm_hw_params
                                依次调用dai_link(machine),codec_dai,cpu_dai,platform(dma)的hw_params函数
    SNDRV_PCM_IOCTL_SYNC_PTR (同步指针)
    SNDRV_PCM_IOCTL_SW_PARAMS : snd_pcm_sw_params_user(substream, arg);
    (软件参数设置)             snd_pcm_sw_params 不涉及硬件操作

    SNDRV_PCM_IOCTL_SYNC_PTR
    SNDRV_PCM_IOCTL_PREPARE : snd_pcm_prepare(substream, file);
                      snd_power_wait // 电源管理相关,先不管
                      .... 调用到platform里的prepare

    SNDRV_PCM_IOCTL_SYNC_PTR
    SNDRV_PCM_IOCTL_SW_PARAMS

    循环:
    SNDRV_PCM_IOCTL_WRITEI_FRAMES : copy_from_user(从用户空间拿到音频相关数据)
                       snd_pcm_lib_write
                        snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_write_transfer)
                          snd_pcm_lib_write_transfer
                            copy_from_user
                            snd_pcm_start(substream); // 启动传输,依次调用dai_link(machine),codec_dai,cpu_dai,platform(dma)的trigger函数


    SNDRV_PCM_IOCTL_SYNC_PTR

    SNDRV_PCM_IOCTL_DRAIN
    SNDRV_PCM_IOCTL_DROP
    SNDRV_PCM_IOCTL_HW_FREE
    close

    strace分析: amixer cset numid=1 30 (设置音量)
    /dev/snd/controlC0
    open
    SNDRV_CTL_IOCTL_CARD_INFO
    SNDRV_CTL_IOCTL_PVERSION
    SNDRV_CTL_IOCTL_ELEM_INFO
    SNDRV_CTL_IOCTL_ELEM_READ
    SNDRV_CTL_IOCTL_ELEM_WRITE : snd_ctl_elem_write_user
                      snd_ctl_elem_write
                        // 找到一个snd_kcontrol
                        kctl = snd_ctl_find_id(card, &control->id);
                        // 调用它的put
                        result = kctl->put(kctl, control);

    (在内核源码uda134X.c中定义两个snd_kcontrol_new结构体,这个结构体提供了声卡芯片的属性参数信息及操作函数,然后用snd_soc_add_codec_controls函数根据这个结构体来构造snd_kcontrol)


    附:
    static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
    .name = "S3C24XX_UDA134X",
    .owner = THIS_MODULE,
    .dai_link = &s3c24xx_uda134x_dai_link,
    .num_links = 1,
    };

    static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
    .name = "UDA134X",
    .stream_name = "UDA134X",
    .codec_name = "uda134x-codec",
    .codec_dai_name = "uda134x-hifi",
    .cpu_dai_name = "s3c24xx-iis",
    .ops = &s3c24xx_uda134x_ops,
    .platform_name = "samsung-audio",
    };

    5. 从零写ALSA声卡驱动
    5.1 写框架

    见代码
    5.2 实现参数设置
    open: soc_pcm_open 依次调用cpu_dai, dma, codec_dai, machine的open或startup函数

    只在dma的open函数里添加参数相关的代码

    SNDRV_PCM_IOCTL_HW_PARAMS: soc_pcm_hw_params 依次调用machine,codec_dai,cpu_dai,platform(dma)的hw_params函数来设置参数

    在uda1341.c, s3c2440-iis.c里实现hw_params函数

    (s3c2440-dma.c 主要涉及数据传输(dma寄存器的设置),在下一节实现hw_params函数)

    (uda1341的寄存器值支持写,不支持读,所有说如果不保存设置寄存器的时候写入的值时,根本不知道寄存器里面的值,所以需要在写入前先保存)
    5.3 实现数据传输

    5.4 调试

    a. 修改语法错误 11th_myalsa
    b. 配置内核去掉原来的声卡驱动
    -> Device Drivers
    -> Sound card support
    -> Advanced Linux Sound Architecture
    -> ALSA for SoC audio support

    c. 使用新内核启动

    d. 安装新驱动

    insmod alsa/driver/myalsa/platform/s3c2440_iis.ko
    insmod alsa/driver/myalsa/platform/s3c2440_dma.ko
    insmod alsa/driver/myalsa/codec/uda1341.ko
    insmod alsa/driver/myalsa/machine/s3c2440_uda1341.ko
    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c
    cd /


    e. aplay来测试

    insmod ker_rw.ko
    regeditor r32 0x4B000080 9
    regeditor r32 0x55000000 5

    5.5 添加音量控制

    5.6 从零写WM8976声卡驱动程序
    insmod alsa/driver/myalsa/platform/s3c2440_iis.ko
    insmod alsa/driver/myalsa/platform/s3c2440_dma.ko
    insmod alsa/driver/myalsa/codec/wm8976.ko
    insmod alsa/driver/myalsa/machine/s3c2440_uda1341.ko
    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c
    cd /

    aplay Groove_Coverage-she.wav &

    amixer controls
    amixer cget numid=1
    amixer cset numid=1 30

    5.7 移植WM8976声卡驱动程序(源码中01th_wm8976都是在自己写的驱动中测试)
    http://www.wolfsonmicro.com/products/audio-hubs-%28codecs%29/stereo-low-power-codecs/wm8976/
    http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices
    https://gitorious.org/slimlogic/linux-omap/source/36d409f2c6306cb407f5d862afe987ba245e455a:sound/soc/codecs/wm8976.c

    insmod alsa/driver/myalsa/platform/s3c2440_iis.ko
    insmod alsa/driver/myalsa/platform/s3c2440_dma.ko
    insmod alsa/driver/myalsa/codec/wm8976.ko
    insmod alsa/driver/myalsa/machine/s3c2440_uda1341.ko
    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c
    cd /

    aplay Groove_Coverage-she.wav &

    amixer cset numid=45 30


    把wm8976放入内核:
    a. 把wm8976.c, wm8976.h放入soundsoccodecs目录
    b. 修改soundsoccodecs的Makefile, Kconfig
    c. 把soundsocsamsungs3c24xx_uda134x.c复制为s3c2440_wm8976.c
    修改codec, codec_dai的name
    d. 修改soundsocsamsung的Makefile, Kconfig

    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c
    cd /

    aplay Groove_Coverage-she.wav &
    amixer cset numid=45 30


    5.8 修改内核声卡BUG

    1、sound/soc/samsung/dma.c中

    (dma传输完成后调用audio_buffdone处理dma中已取数据的period,period是用链表串起来,之前的代码在audio_buffdone和dma_enqueue中都执行了移动当前period指针的操作,多做了一次,所有需要先删除audio_buffdone中的移动操作,把执行的从链表中删除period的操作提前,之后移动当前指针,并将已使用的period加入链表最后面,最后数据都处理好后才是snd_pcm_period_elapsed更新参数到内核)(其实这里的链表应该说成队列跟合适)

    static void audio_buffdone(void *data)
    {
    struct snd_pcm_substream *substream = data;
    struct runtime_data *prtd = substream->runtime->private_data;

    pr_debug("Entered %s ", __func__);

    if (prtd->state & ST_RUNNING) {
    prtd->dma_pos += prtd->dma_period;//去掉
    if (prtd->dma_pos >= prtd->dma_end);//去掉
    prtd->dma_pos = prtd->dma_start;;//去掉

    if (substream)
    snd_pcm_period_elapsed(substream);

    spin_lock(&prtd->lock);    //下面所有代码移动到上面删除的地方
    if (!samsung_dma_has_circular()) {
    prtd->dma_loaded--;
    dma_enqueue(substream);
    }
    spin_unlock(&prtd->lock);
    }
    }

    static void dma_enqueue(struct snd_pcm_substream *substream)
    {

      dma_info.len = prtd->dma_period*limit;改为dma_info.len = prtd->dma_period

    }


    5.9 编写简单的声卡应用程序
    a. ALSA声卡使用体验:使用arecord录音,使用aplay播放
    准备:
    cd linux-3.4.2
    patch -p1 < ../linux-3.4.2_alsa_wm8976_uda1341_jz2440_mini2440_tq2440.patch
    cp config_wm8976_jz2440 .config 或 cp config_uda1341_tq2440_mini2440 .config
    make uImage


    jz2440:
    i. 声音差
    arecord test.wav(录音指令)
    aplay test.wav

    ii. 声音好
    arecord -f cd test.wav
    aplay test.wav

    mini2440:
    把MIC2通道打开(uda1341有两个录音接口,根据看电路图看麦克风链接到那个接口来设置)
    amixer cset numid=11 2

    i. 声音差
    arecord test.wav

    (录音的时候wm8976.c中的struct snd_soc_dai_driver wm8976_dai变量的capture对应的channels_min和max都是1(变量录音只能单声道),而s3c24xx-i2s.c的struct snd_soc_dai_driver s3c24xx_i2s_dai变量的capture对应的channels_min和max都是2(表示录音只能双声道),把wm8976.c中的channels_max改为2就可以了,表示两者都支持)

    aplay test.wav

    ii. 声音好
    arecord -f cd test.wav(修改采样率和数据位数可以提高声音质量)
    aplay test.wav

    tq2440:
    把MIC1通道打开
    amixer cset numid=11 1

    i. 声音差
    arecord test.wav
    aplay test.wav

    ii. 声音好
    arecord -f cd test.wav
    aplay test.wav


    b. 编写一个应用程序:一边录音一边播放(可以仿照alsa_util的源码,两者都在源码的aplay.c中)
    A Tutorial on Using the ALSA Audio API:
    alsa-lib使用方法
    open_the_device();
    set_the_parameters_of_the_device();
    while (!done) {
    /* one or both of these */
    receive_audio_data_from_the_device();
    deliver_audio_data_to_the_device();
    }
    close the device

     应用程序依赖alse-lib库,可以去查看我们之前编译的alse-lib,查看find -name "*so*",发现基本都是libasound.so,所有我们在应用程序中执行arm-linux-gcc的时候加上-lasound就可以


    Alsa中PCM参数设置
    http://blog.chinaunix.net/uid-10995602-id-2918643.html

    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c

    修改: archarmmach-s3c24xxmach-smdk2440.c

    CONFIG_SND_SOC_SAMSUNG
    CONFIG_SND_S3C24XX_I2S

    CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X

    CONFIG_SND_SOC_UDA134X
    CONFIG_S3C24XX_DMA


    tar xjf alsa-lib-1.0.27.2.tar.bz2
    ./configure --host=arm-linux
    make


    ncurse:
    ./configure --host=arm-linux --prefix=$PWD/tmp --with-curses=ncurses
    make
    make install
    cd tmp/lib
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
    cd tmp/include/ncurses
    sudo cp * -rfd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include


    tar xjf alsa-utils-1.0.27.2
    ./configure --host=arm-linux --prefix=$PWD/tmp --with-curses=ncurses --disable-xmlto --disable-nls
    aplay /Windows.wav
    ALSA lib conf.c:3707:(snd_config_update_r) Cannot access file /work/projects/alsa/alsa-lib-1.0.27.2/tmp/share/alsa/alsa.conf

    ./configure --host=arm-linux --with-curses=ncurses --disable-xmlto --disable-nls


    make

    sudo make install

    configure: error: required curses helper header not found

    要先编译安装ncurses-5.9
    ./configure --host=arm-linux --prefix=$PWD/tmp --with-shared


    /bin/bash: xmlto: command not found
    http://blog.csdn.net/lamdoc/article/details/12563061
    sudo apt-get install xmlto // 安装失败, 配置时加上 --disable-xmlto

    sudo apt-get install gettext

    3.应用

    soundcoresound.c
    register_chrdev(major, "alsa", &snd_fops)


    snd_open
    struct snd_minor *mptr = NULL;
    mptr = snd_minors[minor];
    file->f_op = fops_get(mptr->f_ops);
    err = file->f_op->open(inode, file);


    用strace跟踪:
    open("/dev/snd/controlC0", O_RDWR|0x80000 /* O_??? */) = 3
    ioctl(3, USBDEVFS_CONTROL, 0xbe96a5bc) = 0 SNDRV_CTL_IOCTL_PVERSION
    ioctl(3, 0x40045532, 0xbe96a5a8) = 0 #define _IOW('U',0x32,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
    SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE
    close(3) = 0

    SNDRV_CTL_IOCTL_CARD_INFO
    SNDRV_CTL_IOCTL_PVERSION
    SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE

    alsa_pcm_init
    snd_ctl_register_ioctl(snd_pcm_control_ioctl);
    _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);

    snd_ctl_ioctl 用到 snd_control_ioctls

    static const struct file_operations snd_ctl_f_ops =
    .unlocked_ioctl = snd_ctl_ioctl,
    }

    snd_card_create
    snd_ctl_create
    snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops) , ops里有 snd_ctl_dev_register > snd_register_device (snd_ctl_f_ops)

    snd_card_register
    snd_device_register_all
    dev->ops->dev_register
    snd_ctl_dev_register
    snd_register_device


    open("/dev/snd/pcmC0D0p", O_RDWR|O_NONBLOCK|0x80000) = 4

    soc_probe
    snd_soc_register_card
    snd_soc_instantiate_cards
    snd_soc_instantiate_card
    soc_probe_dai_link
    soc_new_pcm

    soc_pcm_ops->open = soc_pcm_open;
    soc_pcm_ops->close = soc_pcm_close;
    soc_pcm_ops->hw_params = soc_pcm_hw_params;
    soc_pcm_ops->hw_free = soc_pcm_hw_free;
    soc_pcm_ops->prepare = soc_pcm_prepare;
    soc_pcm_ops->trigger = soc_pcm_trigger;
    soc_pcm_ops->pointer = soc_pcm_pointer;

    snd_pcm_new
    static struct snd_device_ops ops = {
    .dev_free = snd_pcm_dev_free,
    .dev_register = snd_pcm_dev_register,
    .dev_disconnect = snd_pcm_dev_disconnect,
    };

    snd_device_new

    if (playback)
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);

    if (capture)
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);

    snd_pcm_dev_register
    err = snd_register_device_for_dev(devtype, pcm->card,
    pcm->device,
    &snd_pcm_f_ops[cidx],
    pcm, str, dev);

    pcm设备的 file_operations 来自 snd_pcm_f_ops

    #define _IOC_NRSHIFT 0
    #define _IOC_TYPESHIFT 8
    #define _IOC_SIZESHIFT 16
    #define _IOC_DIRSHIFT 30


    open("/dev/snd/pcmC0D0p", O_RDWR|O_NONBLOCK|0x80000) = 4

    SNDRV_PCM_IOCTL_INFO : snd_pcm_info_user
    SNDRV_PCM_IOCTL_PVERSION : put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
    SNDRV_PCM_IOCTL_TTSTAMP : snd_pcm_tstamp(substream, arg), 传入的值是SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY或SNDRV_PCM_TSTAMP_TYPE_MONOTONIC
    SNDRV_PCM_IOCTL_SYNC_PTR : snd_pcm_sync_ptr(substream, arg)
    SNDRV_PCM_IOCTL_HW_REFINE : snd_pcm_hw_refine_user(substream, arg) > snd_pcm_hw_refine >
    SNDRV_PCM_IOCTL_SYNC_PTR :
    SNDRV_PCM_IOCTL_SW_PARAMS : snd_pcm_sw_params_user(substream, arg) > snd_pcm_sw_params >
    SNDRV_PCM_IOCTL_SYNC_PTR
    SNDRV_PCM_IOCTL_PREPARE : snd_pcm_prepare(substream, file) >
    SNDRV_PCM_IOCTL_SYNC_PTR
    SNDRV_PCM_IOCTL_SW_PARAMS
    SNDRV_PCM_IOCTL_WRITEI_FRAMES : snd_pcm_lib_write >
    SNDRV_PCM_IOCTL_SYNC_PTR
    SNDRV_PCM_IOCTL_DRAIN : snd_pcm_drain
    SNDRV_PCM_IOCTL_DROP : snd_pcm_drop(substream)
    SNDRV_PCM_IOCTL_HW_FREE : snd_pcm_hw_free(substream)

    fcntl64(4, F_SETFD, FD_CLOEXEC) = 0
    ioctl(4, AGPIOC_ACQUIRE or APM_IOC_STANDBY, 0xbe9a749c) = 0 SNDRV_PCM_IOCTL_INFO
    fcntl64(4, F_GETFL) = 0x80802 (flags O_RDWR|O_NONBLOCK|0x80000)
    ioctl(4, AGPIOC_INFO, 0xbe9a75c0) = 0 SNDRV_PCM_IOCTL_PVERSION
    ioctl(4, AGPIOC_SETUP, 0xbe9a7490) = 0 SNDRV_PCM_IOCTL_TTSTAMP
    ioctl(4, 0xc0844123, 0xbe9a73b8) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    fcntl64(4, F_GETFL) = 0x80802 (flags O_RDWR|O_NONBLOCK|0x80000)
    fcntl64(4, F_SETFL, O_RDWR|0x80000 /* O_??? */) = 0
    ioctl(4, AGPIOC_ACQUIRE or APM_IOC_STANDBY, 0xbe9a7be8) = 0 SNDRV_PCM_IOCTL_INFO
    ioctl(4, 0xc25c4110, 0xbe9a7520) = 0 SNDRV_PCM_IOCTL_HW_REFINE
    ioctl(4, 0xc25c4110, 0xbe9a7180) = 0 SNDRV_PCM_IOCTL_HW_REFINE
    ioctl(4, 0xc25c4110, 0xbe9a7180) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7520) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7180) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7180) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7520) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6ee0) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7280) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a69c8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a69c8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a69c8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a69c8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a69c8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6d68) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a6fd8) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7470) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7470) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7470) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7470) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7418) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7418) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7418) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7418) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7418) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7490) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7490) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7490) = 0
    ioctl(4, 0xc25c4110, 0xbe9a7860) = 0
    ioctl(4, 0xc25c4111, 0xbe9a7860) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    ioctl(4, 0xc0684113, 0xbe9a7404) = 0 SNDRV_PCM_IOCTL_SW_PARAMS
    ioctl(4, 0xc0844123, 0x2e868) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    ioctl(4, 0x4140, 0xc54f8) = 0 SNDRV_PCM_IOCTL_PREPARE
    ioctl(4, 0xc0844123, 0x2e868) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    ioctl(4, 0xc0684113, 0xbe9a77f0) = 0 SNDRV_PCM_IOCTL_SW_PARAMS
    read(3, "^36337753743773375377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0 SNDRV_PCM_IOCTL_WRITEI_FRAMES
    ioctl(4, 0xc0844123, 0x2e868) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    read(3, "2223,2071%1$377261133037424615373377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, ",5246374(52743753174365376304N00133231"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "Z 2146345 3536265 26736 ,7+ 217310354"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "262 20 s Jf370 ;vL 25 F1035010&72367"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "30217 22203v305205731216211217f1376313"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "Z 4172fh16356 x 36610Efl6314 .334010224"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "^30310371273 3611245 )4uv\630f2637"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "36236533127_36727327g36737326323366.25302"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "30525N 20222%fS2022316q16C20Ov35520/7342"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "&3)53745y2?10363377w10303374X10276371273"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "l37423373g37016371345363(367375356.365{351"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "O4G6R6-076 2227371v23410221 K 363 ]v"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "237320d327*33231733332534234434122735221351"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "214337*342i343260346276346B352n350 355j353"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "3403263543569324b35724324305356270321e355"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "35423351M21M3320 234523522677224372m "..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "3776`362257322436735361374;3733112365"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "Q20342323037t537,]6311/U040136012410m1w"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "353371f370c373252366336374[364316373317361"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "305363n365i371216365*1e367% 1037235017 376"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "C372003536336|32*34:25213032517626235 "..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "266163052177f:2Av3111Vv37724v1775207"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "C330m330331262377376335224376234345324374"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "34433327.374 2721737025424636726121207"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "2141725137332627B375>3532737620237311262"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "\f357374213 2443752546I376x5224376*5204"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "2343T363S2177366+253371/37653732033748373"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "26762333772126>133352171 5172%5k4274"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "37310222351`7 35027455347O040346%3213345"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "241373336372317373e372r374225371"375231370"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, " 367301370]366m370315365W370204365243370236"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "e3227376f326037624533243763453353376 4347"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "11037630237722376o377+3763770376205376"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "334372317376305372>3772713722503773013726"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "2253770423437727425437734232513772353220"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "316v345364377366326377373255377371"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "30713501336124713461g13451!13331321"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "267377341270377G1301377p13203772161344377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "351377 2D33e+203009234C262"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "240R377232L377232O377237R377244Y377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "257377)276377243173777344377377377367"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "21037717215377 2273772225037725267"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "16x6xy373377v365377r361377r"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "162f5 7 f1621162420"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "356377 3633772336537736370377$373377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "337377337377334377341377332377344377330377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, ""353377 351377373523773535037731"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "370377370377370377377377371377376377"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, " 171 ff"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0
    ioctl(4, 0xc0844123, 0x2e868) = 0
    read(3, "71610165177 6f6 5"..., 8192) = 8192
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0 SNDRV_PCM_IOCTL_WRITEI_FRAMES
    ioctl(4, 0xc0844123, 0x2e868) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    read(3, ""..., 6808) = 6808
    ioctl(4, 0x400c4150, 0xbe9a7ab8) = 0 SNDRV_PCM_IOCTL_WRITEI_FRAMES
    ioctl(4, 0xc0844123, 0x2e868) = 0 SNDRV_PCM_IOCTL_SYNC_PTR
    fcntl64(4, F_GETFL) = 0x80002 (flags O_RDWR|0x80000)
    fcntl64(4, F_SETFL, O_RDWR|0x80000 /* O_??? */) = 0
    ioctl(4, 0x4144, 0xc50a4) = 0 SNDRV_PCM_IOCTL_DRAIN
    fcntl64(4, F_GETFL) = 0x80002 (flags O_RDWR|0x80000)
    fcntl64(4, F_SETFL, O_RDWR|0x80000 /* O_??? */) = 0
    close(3) = 0
    ioctl(4, 0x4143, 0xc51ac) = 0 SNDRV_PCM_IOCTL_DROP
    ioctl(4, 0x4112, 0) = 0 SNDRV_PCM_IOCTL_HW_FREE
    close(4) = 0

    insmod regmap-i2c.ko
    insmod regmap-spi.ko
    insmod snd-soc-core.ko

    echo "8 4 1 7" > /proc/sys/kernel/printk
    insmod alsa/driver/platform/s3c2440-i2s.ko
    insmod alsa/driver/platform/s3c2440-dma.ko
    insmod alsa/driver/codec/uda1341.ko
    insmod alsa/driver/machine/s3c2440_sound.ko
    mkdir /dev/snd
    cd /dev/snd/
    ln -s /dev/controlC0
    ln -s /dev/pcmC0D0p
    ln -s /dev/pcmC0D0c
    cd /
    echo "8 4 1 7" > /proc/sys/kernel/printk

    regeditor r32 0x55000000 5; regeditor r32 0x4B000080 9

    修改BUG:soundsocsamsungdma.c

    static void dma_enqueue(struct snd_pcm_substream *substream)

    //pos += prtd->dma_period;
    pos += prtd->dma_period*limit;

    http://wenku.baidu.com/link?url=B2U2f2vK5gHvVVUrMrgmEaS3N0xAampnfPj5-MNfJsF63BwL3qU7bNOhf0Jmwrqx75y5LSk8C13ppaHvfw24YOjtf6GppFOI25INP7WVKOO

    A close look at ALSA
    http://www.volkerschatz.com/noise/alsa.html


    Linux音频子系统 - DroidPhone的专栏 - 博客频道 - CSDN.NET.htm
    http://blog.csdn.net/droidphone/article/category/1118446


    Linux ALSA声卡驱动之一:ALSA架构简介
    http://blog.csdn.net/droidphone/article/details/6271122

    Linux ALSA声卡驱动之二:声卡的创建
    http://blog.csdn.net/droidphone/article/details/6289712

    Linux ALSA声卡驱动之三:PCM设备的创建
    http://blog.csdn.net/droidphone/article/details/6308006

    Linux ALSA声卡驱动之四:Control设备的创建
    http://blog.csdn.net/droidphone/article/details/6409983

    Linux ALSA声卡驱动之五:移动设备中的ALSA(ASoC)
    http://blog.csdn.net/droidphone/article/details/7165482

    Linux ALSA声卡驱动之六:ASoC架构中的Machine
    http://blog.csdn.net/droidphone/article/details/7231605

    Linux ALSA声卡驱动之七:ASoC架构中的Codec
    http://blog.csdn.net/droidphone/article/details/7283833

    Linux ALSA声卡驱动之八:ASoC架构中的Platform
    http://blog.csdn.net/droidphone/article/details/7316061

    snd_soc_register_codec(,snd_soc_codec_driver,snd_soc_dai_driver,num_dai)

    alsa:

     

    alsa分析:

     

    alsa驱动:

     

    从零写alsa驱动:

     

  • 相关阅读:
    Python好酷|JSON字段校验库DeepDiff
    如何推动团队测试转型自动化测试
    Python好酷|allpairspy一款高效的正交实验法生成用例工具
    性能测试很简单JMeter性能测试实践
    接口测试框架开发实践2:接口自动化测试框架设计思路
    vscode添加python文件头模板(Mac版)
    Python|200行代码实现贪吃蛇小游戏
    如何有效提升软件测试质量?

    我的正版游戏
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/8933272.html
Copyright © 2020-2023  润新知