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、总结



  • 相关阅读:
    GPU
    Windows系统之hosts文件
    条形码定位算法
    entity framework extended library , bulk execute,deleting and updating ,opensource
    sharepoint 2013 sp1
    windows azure programing
    windows azure tools for mac
    online web design tool
    toastr
    sharepoint online
  • 原文地址:https://www.cnblogs.com/alan666/p/8311868.html
Copyright © 2011-2022 走看看