基于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) |