Chinaunix首页 | 论坛 | 博客
  • 博客访问: 104057
  • 博文数量: 30
  • 博客积分: 536
  • 博客等级: 中士
  • 技术积分: 224
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-29 09:23
文章分类
文章存档

2012年(16)

2011年(14)

我的朋友

分类: LINUX

2012-01-11 02:27:47

基于2.6.35内核
Asoc Bsp驱动在smdk_wm9713中

//初始化函数
static int __init smdk_init(void)
{
    int ret;
  //注册一个名为soc-audio的平台设备
    smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
    if (!smdk_snd_ac97_device)
        return -ENOMEM;
  //&smdk_snd_ac97_device->dev->p->driver_data = smdk_snd_ac97_devdata;
  /*
   *设置平台设备数据
   *将SoC Device中的数据信息保存为smdk_snd_ac97_device平台设备的私有数据中
   *这样做方便以后调用
   */
    platform_set_drvdata(smdk_snd_ac97_device, &smdk_snd_ac97_devdata);
    //把设备保存到soc-device中
    smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;

    ret = platform_device_add(smdk_snd_ac97_device);
    if (ret)
        platform_device_put(smdk_snd_ac97_device);
    //注册SoC platform interface
    ret = snd_soc_register_platform(&s3c24xx_soc_platform);
    if (ret)
        snd_soc_unregister_platform(&s3c24xx_soc_platform);

    return ret;
}

static void __exit smdk_exit(void)
{
    platform_device_unregister(smdk_snd_ac97_device);
}

module_init(smdk_init);
module_exit(smdk_exit);

/* Module information */
MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com");
MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
MODULE_LICENSE("GPL");

/*
 *linux内核中用这样一个结构体来描述音频子系统
 *SoC Device - the audio subsystem
 */
struct snd_soc_device {
    struct device *dev;
    struct snd_soc_card *card;//对于alsa音频设备驱动而言每个声卡都必须创建一个这样的实例
    struct snd_soc_codec_device *codec_dev;//编码器设备
    void *codec_data;//编码器数据
};

/*
 *比如smdk系列的Soc设备
 */
 static struct snd_soc_device smdk_snd_ac97_devdata = {
    .card = &smdk,
    .codec_dev = &soc_codec_dev_wm9713,
};

/*
 *正如上面所说对于每一个声卡都必须创建一个实例
 *该实例用下面这个结构来描述
 * SoC card
 */
struct snd_soc_card {
    char *name;            //身卡名字
    struct device *dev;

    struct list_head list;//声卡链表

    int instantiated;    //是否已经实例化

    int (*probe)(struct platform_device *pdev);
    int (*remove)(struct platform_device *pdev);

    /* the pre and post PM functions are used to do any PM work before and
     * after the codec and DAI's do any PM work. */
    int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
    int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
    int (*resume_pre)(struct platform_device *pdev);
    int (*resume_post)(struct platform_device *pdev);

    /* callbacks */
    int (*set_bias_level)(struct snd_soc_card *,
                  enum snd_soc_bias_level level);

    long pmdown_time;

    /* CPU <--> Codec DAI links  */
    struct snd_soc_dai_link *dai_link;//CPU端平台驱动和编码器驱动绑定的桥梁
    int num_links;

    struct snd_soc_device *socdev; //Soc device

    struct snd_soc_codec *codec;  //描述编码器

    struct snd_soc_platform *platform; //Soc platform Interface
    struct delayed_work delayed_work;
    struct work_struct deferred_resume_work;
};
/*
 *在smdk 系列 bsp中(wm9713)是这样初始化上述soc card 结构的
 */
static struct snd_soc_card smdk = {
    .name = "SMDK",                        //声卡名字
    .platform = &s3c24xx_soc_platform,//Soc platform Interface
    .dai_link = &smdk_dai,    
    .num_links = ARRAY_SIZE(smdk_dai),
};

/*
 *音频子系统中用该结构体来描述SOC 平台接口
 *SoC platform interface
 */
struct snd_soc_platform {
    char *name;
    struct list_head list;

    int (*probe)(struct platform_device *pdev);
    int (*remove)(struct platform_device *pdev);
    int (*suspend)(struct snd_soc_dai_link *dai_link);
    int (*resume)(struct snd_soc_dai_link *dai_link);

    /* pcm creation and destruction */
    int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
        struct snd_pcm *);
    void (*pcm_free)(struct snd_pcm *);

    /*
     * For platform caused delay reporting.
     * Optional.
     */
    snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
        struct snd_soc_dai *);

    /* platform stream ops */
    struct snd_pcm_ops *pcm_ops;
};
/**
 *snd_soc_platform初始化定义在s3c-dma.c中
 */
struct snd_soc_platform s3c24xx_soc_platform = {
    .name        = "s3c24xx-audio",
    .pcm_ops    = &s3c_dma_ops,//pcm函数操作集
    .pcm_new    = s3c_dma_new, //实例化pcm设备
    .pcm_free    = s3c_dma_free_dma_buffers,
};
EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);

/* SoC machine DAI configuration,
 * glues a codec and cpu DAI together
 * 该结构负责将codec and cpu DAI 绑定在一起
 */
struct snd_soc_dai_link  {
    char *name;            /* Codec name */
    char *stream_name;        /* Stream name */

    /* DAI */
    struct snd_soc_dai *codec_dai;//编码器dai
    struct snd_soc_dai *cpu_dai;  //CPU端dai

    /* machine stream operations */
    struct snd_soc_ops *ops;//bsp流操作集

    /* codec/machine specific init - e.g. add machine controls */
    int (*init)(struct snd_soc_codec *codec);

    /* Keep DAI active over suspend */
    unsigned int ignore_suspend:1;

    /* Symmetry requirements */
    unsigned int symmetric_rates:1;

    /* Symmetry data - only valid if symmetry is being enforced */
    unsigned int rate;

    /* DAI pcm */
    struct snd_pcm *pcm;
};

/*
 *将codec驱动和CPU端的平台驱动进行绑定
 */
static struct snd_soc_dai_link smdk_dai[] = {
    {
    .name = "AC97 PCM RX",
    .stream_name = "AC97 PCM Playback",
    .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
    .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
    },
    {
    .name = "AC97 PCM TX",
    .stream_name = "AC97 PCM Capture",
    .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
    .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
    }
};

问:好了关与音频子系统中的bsp驱动就这些了,现在可以回过头来总结一下了,bsp驱动中究竟作了一些什么事情?
答:说白了就是将平台驱动和编码器驱动绑定起来.再仔细看看上面的代码至少我发现了他们好有面向对象的感觉
   你调用我,我调用你,在这里至少是在看bsp驱动的时候对于上面这些结构体的初始化我们没必要
   关心他的实现,我们只需要知道这个结构体中有这些成员.我们在这里为它赋一个初值就行了,如果说
   对于每一个结构体的初始化你一点一滴的要把他给贴出来,那么这个代码就没有办法再分析下去了
   对于上面提到的将codec驱动和CPU端的平台驱动进行绑定这个庞大的结构体,它究竟所怎样实现的呢
  不用多想肯定一部分所cpu平台驱动实现另一部分是在编码器驱动中实现,所谓编码器驱动不就是wm9713
  这块芯片的驱动嘛,只不过内核将它分成三份罢了
 
另外我会再做一副图来描述bsp驱动
阅读(1427) | 评论(0) | 转发(0) |
0

上一篇:MMU(理论)

下一篇:Porting WiFi drivers to Android

给主人留下些什么吧!~~