zoukankan      html  css  js  c++  java
  • ALSA声卡08_从零编写之框架_学习笔记

    1、整体框架

    (1)图示((DAI(全称Digital Audio Interface)接口

     在嵌入式系统里面,声卡驱动是ASOC,是在ALSA驱动上封装的一层,包括以下三大块


    (2)程序框架


    machine:s3c2440_uda1341.c

    codec: UDA1341,WM8976

    platform:IIS ,DMA



    2、s3c2440_uda1341.c(参考s3c24xx_uda134x.c)

    (1)分配一个平台为soc-audio的平台设备,


    在这平台设备里面有一个核心结构体snd_soc_s3c24xx_uda134x设置到私有数据里面


    snd_soc_s3c24xx_uda134x结构体是snd_soc_card类型的,里面有dai_link(我们需要重点关注的),dai_link确定了声卡各部分所对应的驱动程序


    (2)名为soc-audio的平台设备,注册后会跟内核里面soc-core.c文件注册的同名driver匹配,最后调用probe,进行一系列的声卡注册。



    3、s3c2440_uda1341.c编写

    /* 参考soundsocsamsungs3c24xx_uda134x.c
     */
    /*
     * 1. 分配注册一个名为soc-audio的平台设备
     * 2. 这个平台设备有一个私有数据 snd_soc_card(结构体)
     *    snd_soc_card里有一项snd_soc_dai_link(结构体)
     *    snd_soc_dai_link被用来决定ASOC各部分的驱动
     */



    static struct snd_soc_ops s3c2440_uda1341_ops = {
    //.hw_params = s3c24xx_uda134x_hw_params,//设置参数
    };


    static struct snd_soc_dai_link s3c2440_uda1341_dai_link = {
    .name = "100ask_UDA1341",//结构体的名字
    .stream_name = "100ask_UDA1341",//
    .codec_name = "uda1341-codec",//使用哪一个编解码芯片
    .codec_dai_name = "uda1341-iis",//编解码芯片里面哪一个DAI
    .cpu_dai_name = "s3c2440-iis",//2440的DAI(平台部分的)
    .ops = &s3c2440_uda1341_ops,//操作函数
    .platform_name= "s3c2440-dma", //平台的名字
    };




    static struct snd_soc_card myalsa_card = {
    .name = "S3C2440_UDA1341",//结构体的名字
    .owner = THIS_MODULE,
    .dai_link = &s3c2440_uda1341_dai_link,
    .num_links = 1,
    };


    static void asoc_release(struct device * dev)
    {
    }

    //定义一个名为soc-audio的平台设备
    static struct platform_device asoc_dev = {
        .name         = "soc-audio",
        .id       = -1,
        .dev = { 
        .release = asoc_release, //release函数必须要写,否则有警告信息
    },
    };

    //入口函数
    static int s3c2440_uda1341_init(void)
    {
    platform_set_drvdata(&asoc_dev, &myalsa_card);//把snd_soc_card结构体当做平台设备的私有数据
        platform_device_register(&asoc_dev);    //注册平台设备
        return 0;
    }

    //出口函数
    static void s3c2440_uda1341_exit(void)
    {
        platform_device_unregister(&asoc_dev);//卸载平台设备
    }


    4、uda1341.c(codec)


    小技巧:本来想在初始化的函数里调用snd_soc_register_codec函数,但是这个函数里有device参数。所以要自己构建一个平台设备和平台驱动。

    int snd_soc_register_codec(struct device *dev,
      const struct snd_soc_codec_driver *codec_drv,
      struct snd_soc_dai_driver *dai_drv,
      int num_dai)

    通过注册平台设备、平台驱动来实现对snd_soc_register_codec的调用(通过平台设备和平台驱动匹配后调用probe函数)


    两个核心结构体


    /* 参考 soundsoccodecsuda134x.c
     */

    /*

    * 1. 构造一个snd_soc_dai_driver(结构体)
     * 2. 构造一个snd_soc_codec_driver(结构体)
     * 3. 注册它们
     */

    static struct snd_soc_codec_driver soc_codec_dev_uda1341 = {
        .probe = uda1341_soc_probe,

    };



    static const struct snd_soc_dai_ops uda1341_dai_ops = {
    .hw_params = uda1341_hw_params,
    };


    static struct snd_soc_dai_driver uda1341_dai = {
    .name = "uda1341-iis",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体,编解码芯片里面哪一个DAI

    根据编解码芯片的数据手册确定的
    /* playback capabilities */播放相关的属性
    .playback = {
    .stream_name = "Playback",
    .channels_min = 1,
    .channels_max = 2,
    .rates = UDA134X_RATES,//编解码芯片支持的声音采样率
    .formats = UDA134X_FORMATS,//编解码芯片支持哪种格式
    },
    /* capture capabilities */捕抓属性
    .capture = {
    .stream_name = "Capture",
    .channels_min = 1,
    .channels_max = 2,
    .rates = UDA134X_RATES,
    .formats = UDA134X_FORMATS,
    },
    /* pcm operations */含操作相关函数的结构体
    .ops = &uda1341_dai_ops,
    };




    /* 通过注册平台设备、平台驱动来实现对snd_soc_register_codec的调用(通过平台设备和平台驱动匹配后调用probe函数)
     *
     */



    static void uda1341_dev_release(struct device * dev)
    {
    }

    //probe函数
    static int uda1341_probe(struct platform_device *pdev)
    {
    return snd_soc_register_codec(&pdev->dev,   //注册结构体snd_soc_dai_driver snd_soc_codec_driver,用哪一个codec,哪一个DAI
    &soc_codec_dev_uda1341, &uda1341_dai, 1);
    }

    //remove函数
    static int uda1341_remove(struct platform_device *pdev)
    {
        snd_soc_unregister_codec(&pdev->dev);
        return 0;
    }

    //平台设备
    static struct platform_device uda1341_dev = {
        .name         = "uda1341-codec",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体
        .id       = -1,
        .dev = { 
        .release = uda1341_dev_release
    },
    };

    //平台驱动
    struct platform_driveruda1341_drv = {
    .probe= uda1341_probe,//probe函数
    .remove= uda1341_remove,
    .driver= {
    .name= "uda1341-codec",
    }
    };


    static int uda1341_init(void)
    {
        
        platform_device_register(&uda1341_dev);//注册平台设备
        platform_driver_register(&uda1341_drv);//注册平台驱动
        return 0;
    }


    static void uda1341_exit(void)
    {
        platform_device_unregister(&uda1341_dev);//卸载平台设备
        platform_driver_unregister(&uda1341_drv);//卸载平台驱动
    }


    5、s3c2440_iis.c(Platform)


    /* 参考soundsocsamsungs3c24xx-i2s.c
     */
    //操作函数相关的结构体
    static const struct snd_soc_dai_ops s3c2440_i2s_dai_ops = {
    .hw_params = s3c2440_i2s_hw_params,//设置参数
    .trigger = s3c2440_i2s_trigger,//触发传输
    };



    //我们的dai_driver没有名字,而我们的machine怎么知道使用哪一个CPU DAI,没有名字,名字在注册的时候从平台设备哦继承而来snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);

    表示能够支持的属性
    static struct snd_soc_dai_driver s3c2440_i2s_dai = {
    .playback = {
    .channels_min = 2,
    .channels_max = 2,
    .rates = S3C24XX_I2S_RATES,//支持的采样率
    .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},//支持的格式
    .capture = {
    .channels_min = 2,
    .channels_max = 2,
    .rates = S3C24XX_I2S_RATES,
    .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
    .ops = &s3c2440_i2s_dai_ops,//操作函数相关的结构体
    };

    //probe函数(注册)
    static int s3c2440_iis_probe(struct platform_device *pdev)
    {
    return snd_soc_register_dai(&pdev->dev, &s3c2440_i2s_dai);//注册cpu dai
    }


    remove函数(卸载)
    static int s3c2440_iis_remove(struct platform_device *pdev)
    {
    snd_soc_unregister_dai(&pdev->dev);
        return 0;
    }


    static void s3c2440_iis_release(struct device * dev)
    {
    }

    //注册平台设备
    static struct platform_device s3c2440_iis_dev = {
        .name         = "s3c2440-iis",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体
        .id       = -1,
        .dev = { 
        .release = s3c2440_iis_release, 
    },
    };

    //注册平台驱动
    struct platform_driver s3c2440_iis_drv = {
    .probe= s3c2440_iis_probe,
    .remove= s3c2440_iis_remove,
    .driver= {
    .name= "s3c2440-iis",//这个名字取的是machine部分的s3c2440_uda1341.c文件的 snd_soc_dai_link结构体
    }
    };

    //入口函数
    static int s3c2440_iis_init(void)
    {
      
        platform_device_register(&s3c2440_iis_dev);//注册平台设备
        platform_driver_register(&s3c2440_iis_drv);//注册平台驱动
        return 0;
    }

    //出口函数
    static void s3c2440_iis_exit(void)
    {
        
        platform_device_unregister(&s3c2440_iis_dev);//卸载平台设备
        platform_driver_unregister(&s3c2440_iis_drv);//卸载平台驱动
       
        

    }



    6、s3c2440_dma.c(Platform)


    /* 参考 soundsocsamsungdma.c
     */


    /* 1. 分配DMA BUFFER
     * 2. 从BUFFER取出period
     * 3. 启动DMA传输
     * 4. 传输完毕,更新状态(hw_ptr)
     *    2,3,4这部分主要有: request_irq, 触发DMA传输, 中断处理
     */


    //操作函数相关的结构体
    static struct snd_pcm_ops s3c2440_dma_ops = {
    .open= s3c2440_dma_open,
    .close = s3c2440_dma_close,
    .ioctl = snd_pcm_lib_ioctl,
    .hw_params = s3c2440_dma_hw_params,
    .prepare    = s3c2440_dma_prepare,
    .trigger = s3c2440_dma_trigger,
    .pointer = s3c2440_dma_pointer,
    };


    static struct snd_soc_platform_driver s3c2440_dma_platform = {
    .ops= &s3c2440_dma_ops,//操作函数相关的结构体
    .pcm_new = s3c2440_dma_new,
    .pcm_free = s3c2440_dma_free,
    };

    //probe 函数
    static int s3c2440_dma_probe(struct platform_device *pdev)
    {
    return snd_soc_register_platform(&pdev->dev, &s3c2440_dma_platform);//注册平台结构体,//我们的s3c2440_dma_platform没有名字,而我们的machine怎么知道使用哪一个CPU DAI,没有名字,名字在注册的时候从平台设备哦继承而来snd_soc_register_platform(&pdev->dev, &s3c2440_dma_platform);
    }
    static int s3c2440_dma_remove(struct platform_device *pdev)
    {
    snd_soc_unregister_platform(&pdev->dev);
        return 0;
    }


    static void s3c2440_dma_release(struct device * dev)
    {
    }

    //平台设备
    static struct platform_device s3c2440_dma_dev = {
        .name         = "s3c2440-dma",
        .id       = -1,
        .dev = { 
        .release = s3c2440_dma_release, 
    },
    };

    //平台驱动
    struct platform_drivers3c2440_dma_drv = {
    .probe= s3c2440_dma_probe,//probe函数
    .remove= s3c2440_dma_remove,
    .driver= {
    .name= "s3c2440-dma",
    }
    };


    static int s3c2440_dma_init(void)
    {
        platform_device_register(&s3c2440_dma_dev);/注册平台设备
        platform_driver_register(&s3c2440_dma_drv);//注册平台驱动
        return 0;
    }


    static void s3c2440_dma_exit(void)
    {
        platform_device_unregister(&s3c2440_dma_dev);
        platform_driver_unregister(&s3c2440_dma_drv);
        iounmap(dma_regs);
    }



    7、总结



  • 相关阅读:
    HDU 2116 Has the sum exceeded
    HDU 1233 还是畅通工程
    HDU 1234 开门人和关门人
    HDU 1283 最简单的计算机
    HDU 2552 三足鼎立
    HDU 1202 The calculation of GPA
    HDU 1248 寒冰王座
    HDU 1863 畅通工程
    HDU 1879 继续畅通工程
    颜色对话框CColorDialog,字体对话框CFontDialog使用实例
  • 原文地址:https://www.cnblogs.com/alan666/p/8311868.html
Copyright © 2011-2022 走看看