一个简单的按键驱动,涉及到的知识点有:GPIO配置,input输入子系统,platform平台总线,中断,kobject(sysfs)。
由于内核中已经有了gpio_keys.c函数,简单的实现独立式按键驱动功能,应该还是挺简单,按键所接端口为中断引脚。如果是矩阵按键呢?相应代码的改动应该较大,未研究。
按键驱动属于input输入子系统,同时按键驱动也是挂在platform平台总线上。
编写platform驱动要完成三方面的工作:
1.platform_device的编写
2.platform_driver的编写
3.设备资源和数据的定义
对于platform_device的编写又有两方法:
1.在BSP板文件中实现定义,在板文件中将platform_device被归纳为一个数组,最终通过platform_add_devices()函数统一注册。
这个函数内部其实调用了platform_device_register()单个注册平台设备。
2.第二种是为platform_device单独编写内核模块然后加载到内核中。
同理其中对于resource的定义也有两种方法:
1.在板文件中定义
2.在platform_device所处的内核模块代码中编写
我这边采用第一种方法。
Linux 内核下的 drivers/input/keyboard/gpio_keys.c实现了一个体系结构无关的GPIO按键驱动,如下:
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,
.pm = &gpio_keys_pm_ops,
.of_match_table = gpio_keys_of_match,
}
};
使用此按键驱动,只需在arch/arm/板级文件中定义相关的数据即可。
找到对应的板级文件,如Board-xxxx-gpiomux.c ,只需要做两件事。
1、增加GPIO的配置
msm_gpiomux_install(function_key_configs,ARRAY_SIZE(function_key_configs)); //完成GPIO的配置
static struct msm_gpiomux_config function_key_configs[] __initdata = {
{
.gpio = 10,
.settings = {
[GPIOMUX_SUSPENDED] = &function_buttons_cfg,
},
},
};
static struct gpiomux_setting function_buttons_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_UP,
};
其中ARRAY_SIZE这个宏,是求设备结构体中设备的个数。
2、按键的platform_device的编写
platform_add_devices(function_devices,ARRAY_SIZE(function_devices));//注册平台设备
static struct platform_device *function_devices[] __initdata = {
&function_buttons_device,
};
static struct platform_device function_buttons_device = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &function_buttons_data,
},
};
static struct gpio_keys_platform_data function_buttons_data = {
.buttons = function_buttons,//设备名
.nbuttons = ARRAY_SIZE(function_buttons),
};
static struct gpio_keys_button function_buttons [ ] =
{
{
.gpio = GPIO_NUM_WPS_BUTTON,
.code = KEY_WPS_BUTTON,
.desc = "WPS Button" ,
.active_low = 1,
},
};
这样就可以了,在终端里就发现有这两个节点:
/sys/bus/platform/devices/gpio-keys
/sys/devices/platform/gpio-keys
同时在文件系统dev目录下有event设备节点,对gpio-keys按键的访问可以通过event来完成。
应用层程序:
fd = open("/dev/input/event0", O_RDONLY);//打开按键文件节点
repeat_param[0]=500;//ms重复按键第一次间隔
repeat_param[1]=66;//ms重复按键后续间隔
ret = ioctl(fd,EVIOCSREP,(int *)repeat_param);//设置重复按键参数,当然这些参数也可以在驱动里设置
while(1) {ret = read(fd,&buf,sizeof(struct input_event));}//数据保存在buf
code = buf.code;
key_state = buf.value;
switch(code)
{
case KEY_DOWN:
code = '1';
break;
case KEY_ENTER:
code = '2';
break;
case KEY_HOME:
code = '3';
break;
case KEY_POWER:
code = '4';
break;
default:
code = 0;
break;
}
close(fd);
printf("Key test finished.\n");
return 0;
基本完成了,应用层程序可以按照应用层要求增加相应代码,如进程通信等。
另外关于平台文件说明:
arch目录下的文件就是与CPU级相关的文件,而board、drivers、include等文件夹下的文件都是与板级相关的文件。
我们在移植的过程中,需要修改的文件也就是这些与平台相关的文件。对于开发板,如2440,多修改板级文件,对于公司开发的新产品,多修改arch目录下的文件就是与CPU级相关的文件。有时CPU级相关的文件和与板级相关的文件都称混称为板级文件。
另active_low = 1,还是active_low =0,要根据硬件的连接,如果按下按键为高电平那么active_low =0,如果按下按键为低电平那么active_low =1.