项目中的dm365的按键驱动基于plamform总线和input子系统驱动架构,与一般的字符设备驱动很不一样,必须要对palmform总线和input子系统有所了解,因此像我这种初学菜鸟添加一个简单的gpio按键都会被弄得头晕目眩。
我的理解palmform总线事实上是内核的一种架构,这个架构能够使得驱动程序和具体的设备分离,两者通过匹配的方式找到对方,这样做的好处是使得核心代码(驱动)和具体的设备分离,添加设备时只需要修改具体设备的相关代码,而核心代码(驱动程序)则可以通用于所有同类型的设备,从而提高代码的重用能力,关于palmform总线更详细的介绍可以参考宋宝华的设备驱动12.1节,以下是针对dm365的按键驱动的一些分析:
1. 首先是设备部分,代码文件是dm365内核arch\arm\mach-davinci\board-dm365-evm.c, 这是板级(BSP)文件,里面存放的是与电路板相关的设备的描述与初始化代码,如gpio按键,外部nandflash 视频采集芯片tvp5146等设备。内核通过函数
static __init void dm365_evm_init(void)
来获取设备的描述及进行设备相关的的初始化(共性的初始化放在了核心层驱动程序里),gpio按键部分在函数
dm365_init_buttonkey(void)
中实现,里面最重要的一步是调用了函数
platform_device_register(struct platform_device &dm365_device_keys);
此函数是设备在platform总线的注册函数, 而结构体struct platform_device dm365_device_keys 正是 platform 总线提供的设备描述载体,我的代码为:
static struct platform_device dm365_device_keys = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &dm365_keyplatform,
},
};
其中.name 项是设备的名称,这一项在驱动程序的描述中也有而且名称必须一致,palmform总线正是通过此名称来匹配设备与驱动程序,platform_data 字段是设备描述,由用户自己定义,我的代码里其指向里结构体struct gpio_keys_platform_data dm365_keyplatform 而dm365_keyplatform 的buttons项又指向了dm365_key_button结构数组,其部分内容为:
static struct gpio_keys_button dm365_key_button[]={
{
.gpio = 22,//GPIO22
.code = KEY_ENTER,
.desc = "ButtonKey",
.type = EV_KEY,
.active_low = 1,
},
......
};
可以看到里面包含了描述一个gpio按键的所有有用信息,这些信息会被plamform总线传给驱动程序,至此gpio按键的设备这一块实现完毕,如果要添加一个gpio按键设备则只需在dm365_key_button数组中添加一组信息即可(有可能还要进行管脚复用的设置)。
2.如果只是想在系统里增加一个gpio按键那么上面介绍的已经实现了,驱动部分无需修改任何东西(当然前提是gpio 按键驱动已经实现并编译进内核)。gpio 按键驱动放在drivers\input\keyboard\dm365_gpiokey.c中,其基于input子系统架构,因此我们看不到普通字符设备驱动的cdev结构,也看不到申请释放设备号的函数register_chrdev_region() cdev_del(),因为他们被 结构 struct input_dev 以及其注册与注销函数 input_register_device()和input_unregister_device() 所取代,input子系统的这些接口自动为我们申请设备号和注册,上述的这些动作都在函数gpio_keys_probe()里完成,gpio_keys_probe() 又被plamform总线 驱动结构 struct platform_driver 所引用并通过函数platform_driver_register() 注册到总线上, gpio按键驱动的struct platform_driver 如下:
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &gpio_keys_pm_ops,
#endif
}
注意name字段为"gpio-keys"与前面的platform_device 结构体的name一样的 。 当Linux内核启动后plamform相关程序会自动匹配
name相同的设备和驱动,并把设备的信息如设备号等输出到sysfs上,然后udev或mdev程序通过读取sysfs的信息在/dev下建立设备文件。