简介
Linux内核已经集成按键驱动。按键和键盘在Linux上都属于输入设备;Linux内核为此专门抽象了一个input输入子系统框架来管理该类事件;
按键驱动采用platform框架,因此我们只需要在设备树文件中添加相应节点即可;接下来我们学习如何在全志 a40i平台下使用Linux内核自带的按键驱动来驱动 board 上按键。
开发环境介绍
- 主机操作系统:Ubuntu14.04 64位
- 目标平台:A40I (ARM Cortex-A7)
- 交叉工具链:arm-linux-gnueabi,gcc5.3.1
- 内核版本:3.10
使能Linux内核自带的按键驱动
使用Linux内核自带的LED灯驱动首先需要配置Linux内核,使能自带的LED灯驱动;使能方法如下:
Step1. 打开Linux配置菜单
make ARCH=arm menuconfig
Step2. 打开按键驱动配置项
Device Drivers --->
Input device support --->
[*] Keyboards --->
<*> GPIO Buttons
选中“GPIO Buttons ”将其编译进内核中;
Linux内核自带的KEY驱动文件为:drivers/input/keyboard/gpio_keys.c
Step3. 添加设备树节点
根据内核提供的LED设备树节点添加参考说明文档:
Documentation/devicetree/bindings/input/gpio-keys.txt;
在设备树文件中添加KEY设备节点:
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
key_1 {
label = "reset";
gpios = <&pio PI 12 6 0 0 0>;
linux,code = <KEY_HANJA>; /*123*/
gpio-key,wakeup;
};
};
①、创建KEY节点名字gpio-keys,节点名字可根据情景取;
②、gpio-keys节点的compatible属性值必须为“gpio-keys”,由驱动文件决定;
③、所有的KEY都是gpio-keys的子节点,每个子节点可以用如下属性描述自己:
gpios: KEY所连接的GPIO信息,在a40i平台下,相信的GPIO dts描述可参考A40I Pinctrl(GPIO)接口使用说明书V1.0.pdf;
interrupts: KEY所使用的GPIO中断信息,不是必须的,可以不写;
label: KEY名字;
linux,code: KEY要模拟的按键
④、如果按键要连按的话加入:autorepeat;
应用测试
通过 cat /proc/bus/input/devices 来查看设备是否加载成功;
Func1.hexdump测试
hexdump: 查看文件的内容,比如二进制文件中包含的某些字符串,通常用来调试驱动用;
使用hexdump命令来查看/dev/input/event3文件,数据就是event结构
我们来看看event的结构体:input_event:
struct input_event {
struct timeval time; //事件发生的时间
__u16 type; // 哪类事件, 比如键盘事件
__u16 code; // 对应的事件里支持的哪个变量,比如按键K
__s32 value; // 对应的变量里的数值, 比如松开按键则是1,反之为0
};
把 time里的成员展开如下:
struct input_event {
long tv_sec; /* seconds */ //秒
long tv_usec; /* microseconds */ //微妙
__u16 type; // 哪类事件, 比如键盘事件
__u16 code; // 对应的事件里支持的哪个变量,比如按键K
__s32 value; // 对应的变量里的数值, 比如松开按键则是1,反之为0
};
以按开发板的按键 KEY_HANJA(123),为例(因为数据是从低到高打印的,所以数据是反的):
hexdump /dev/input/event3调试按键驱动:
/*按下时:*/
//hexdump序列号 秒 微妙 键盘事件 code=KEY_HANJA value=1(按下)
0000000 2a4b 5e6a c309 0001 0001 007b 0001 0000
//hexdump序列号 秒 微妙 同步事件 code value=0
0000010 2a4b 5e6a c309 0001 0000 0000 0000 0000
/*松开时:*/
//hexdump序列号 秒 微妙 键盘事件 code=KEY_HANJA value=1(松开)
0000020 2a4b 5e6a b829 0004 0001 007b 0000 0000
//hexdump序列号 秒 微妙 同步事件 code value=0
0000030 2a4b 5e6a b829 0004 0000 0000 0000 0000
也可以使用getevent 命令,用于获取 input 输入事件,比如获取按键上报信息、获取触摸屏上报信息等:
格式输出为event type、event code、event value;
event type(按键) event code(KEY_HANJA) event value(按下)
0001 007b 00000001
event type(同步事件) event code
0000 0000 00000000
event type(按键) event code(KEY_HANJA) event value(松开)
0001 007b 00000000
event type(同步事件) event code
0000 0000 00000000
Func2.系统调用测试
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <linux/input.h>
#include <errno.h>
void get_inputdev_node(char *name,char *identify);
int main(int argc,char *argv[])
{
int fd;
char devName[128];
struct input_event event;
get_inputdev_node(devName,"gpio-keys");
fd = open(devName, O_RDONLY/*|O_NONBLOCK*/);
if ( fd<=0 )
{
printf ("open key device error!\n");
return -1;
}else{
debug("Open key success! \n");
}
while(1)
{
if (read(g_FdKey, &event, sizeof(event)) == sizeof(event))
{
if (event.type == EV_KEY){
/*event.code该值看设备树节点linux,code*/
if( (KEY_HANJA==event.code)&&(1==event.value) ){
printf("INPUT_KEY_DOWN !");
}else if( (KEY_HANJA==event.code)&&(0==event.value) ){
ret=INPUT_KEY_UP;
printf("INPUT_KEY_UP !");
}
}
}else{
printf("read empty \n");
}
}
close(fd);
return 0;
}
/**
* @brief 字符串分割函数
* 将str字符以spl分割,存于dst中,并返回子字符串数量
*
* @param str[in] 待分割字符串
* @param spl[in] 分割符
* @param dst[out] 分割后的子字符串
* @return 返回子字符串数量
*
*/
int split(char dst[][SPLITELENGTH], char* str, const char* spl)
{
int n = 0;
char *result = NULL;
result = strtok(str, spl);
while( result != NULL )
{
strcpy(dst[n++], result);
result = strtok(NULL, spl);
}
return n;
}
/**
* @brief 输入设备节点解析
*
* @author Jalyn
* @date 2020-01-01
*
* @param [in] identify 根据该标识做解析
* @param [out] name 解析后的设备节点名称
* @return 无
*/
void get_inputdev_node(char *name,char *identify)
{
int ret=0;
FILE *fp;
char buf[256];
int findFlag=0;
char dst[10][SPLITELENGTH];
strcpy(name,"/dev/input/event1");
fp = fopen("/proc/bus/input/devices", "r");
if (fp != NULL) {
while (fgets(buf, sizeof(buf), fp) != NULL) {
if(strstr(buf,"Name")!=NULL)
{
findFlag=0;
if(strstr(buf,identify)!=NULL){
findFlag=1;
}
}
if(findFlag==1){
if(strstr(buf,"Handlers")!=NULL){
findFlag=0;
ret = split(dst, buf, " ");
}
}
}
if(ret!=0){
sprintf(name,"/dev/input/%s",dst[2]);
}
fclose(fp);
}else{
printf("open /proc/bus/input/devices error!\n");
}
}
网友评论