4.5 codec驱动
hda_codec对象构建成功后,并没有直接为它构建pcm文件,而是放到codec的驱动中去完成。这样做的目的,可能是为了能方便的替换不同的驱动程序,就可以少一些在代码中的硬编码。
4.5.1 注册codec 驱动
从几个宏开始:
int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
struct module *owner);
#define hda_codec_driver_register(drv) \
__hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE)
void hda_codec_driver_unregister(struct hda_codec_driver *drv);
#define module_hda_codec_driver(drv) \
module_driver(drv, hda_codec_driver_register, \
hda_codec_driver_unregister)
以上定义在include/sound/hda_codec.h中。理解这段代码,再看一下module_driver的定义:
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
在 sound/pci/hda/hda_generic.c中有:
module_hda_codec_driver(generic_driver);
这个是为通用的codec准备的。另外在很多patch_*.c的文件中,也有类似的定义,用于指定的codec,比如:
module_hda_codec_driver(cirrus_driver);
我们就从generic_driver理解,宏展开后的形式如下:
static int __init generic_driver_init(void) {
return __hda_codec_driver_register(&(generic_driver),
KBUILD_MODNAME, THIS_MODULE);
}
module_init(generic_driver_init);
这是初始化的代码,退出的代码可以类似展开。这段宏的作用是生成一个generic_driver_init函数,然后在module_init的时候将会被调用。
再看一下hda_generic.c 中的代码:
static const struct hda_codec_ops generic_patch_ops = {
.build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = snd_hda_gen_init,
.free = snd_hda_gen_free,
.unsol_event = snd_hda_jack_unsol_event,
#ifdef CONFIG_PM
.check_power_status = snd_hda_gen_check_power_status,
#endif
};
/*
* snd_hda_parse_generic_codec - Generic codec parser
* @codec: the HDA codec
*/
static int snd_hda_parse_generic_codec(struct hda_codec *codec)
{
struct hda_gen_spec *spec;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
snd_hda_gen_spec_init(spec);
codec->spec = spec;
err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
if (err