fl2440——内核自带按键驱动的移植与测试
来源:互联网 发布:海洋动态壁纸软件 编辑:程序博客网 时间:2024/05/29 10:19
陌上人如玉,公子世无双。雨虽大,但心境不能乱,是时候静下心来好好整理一篇博客了!
==========================================================================
主机操作系统:Centos 6.7
交叉编译器环境:arm-linux-gcc-4.5.4 (可通过命令/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc -v查询)
开发板平台: fl2440
Linux内核版本: linux-3.0 .54
==========================================================================
linux内核本身就带有按键驱动,只需要我们对其进行添加即可。那么linux是如何实现按键功能的。这里主要涉及到两方面的内容:linux的中断处理和输入子系统。Linux中断分为两个部分:前半部和后半部。前半部是实际响应中断的函数,需要用request_irq注册;后半部是由前半部调度,并在一个更安全的时间来执行的函数,该函数就是具体负责执行中断的内容。前半部不允许被其他中断干扰,因此它的内容短小,而执行后半部时可以响应其他中断。这种机制的好处是可以迅速的响应中断。
因为有了子系统的概念,所以在Linux内核自带驱动程序中,我们往往会发现一个驱动程序所定义的结构体以及函数被放在不同的文件夹下,子系统包括三个层次:事件处理层(Event Handler)、核心层(Input Core)和驱动层(Input Driver)。在led程序中已经对子系统做过简单介绍,在这就不加赘诉了。
该驱动程序gpio_keys.c在目录fl2440/kernel/linux-3.0.54/drivers/input/keyboard 中可以找到。
一、修改mach-smdk2440.c:
根据驱动程序的.name,我们可以找到相关的设备文件信息存放在哪里,然后将相关设备信息添加到我们的mach-smdk2440.c中去。
[yangni@yangni linux-3.0.54]$ grep gpio-keys -r * // gpio-keys 为匹配的name名
找到以后,将button的相关设备信息添加到我们的mach-smdk2440.c中去。
以下是修改后 mach-smdk2440.c文件的补丁文件:
我们开发板上只有4个按键,所以我们只需要四个成员,删除多余的。并且把4个gpio管脚设置分别为0 ,2 ,3,4,并且修改按键code的值。相关诸如KEY_1,KEY_2等在头文件linux-3.0.54/include/linux/input.h中定义
+++ mach-smdk2440.c2017-04-22 15:36:58.078925861 -0800@@ -52,6 +52,15 @@ #include <plat/common-smdk.h> #include <linux/dm9000.h> //添加DM9000网卡的头文件++//add for bubtton+#include <linux/input.h> //添加输入子系统头文件+ static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */@@ -231,13 +240,102 @@ .id= 0, }; +#if 1+//add for button++ static struct gpio_keys_button rx1950_gpio_keys_table[] = { + { + .code = KEY_1, + .gpio = S3C2410_GPF(0), + .active_low = 1, + .desc = "Button_1", + .wakeup = 1, + }, + { + .code = KEY_2, + .gpio = S3C2410_GPF(2), + .active_low = 1, + .desc = "Button_2", + }, + { + .code = KEY_3, + .gpio = S3C2410_GPF(3), + .active_low = 1, + .desc = "Button_3", + }, + { + .code = KEY_4, + .gpio = S3C2410_GPF(4), + .active_low = 1, + .desc = "Button_4", + },+}; + +static struct gpio_keys_platform_data rx1950_gpio_keys_data = { + .buttons = rx1950_gpio_keys_table, + .nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table),+};++static struct platform_device rx1950_device_gpiokeys = { + .name = "gpio-keys", + .dev.platform_data = &rx1950_gpio_keys_data,+}; +#endif static struct platform_device *smdk2440_devices[] __initdata = { &s3c_device_ohci,@@ -253,6 +351,16 @@ //add for beeper &s3c_device_timer, &smdk2440_beeper_device,+ //add for button+ &rx1950_device_gpiokeys,+ }; static void __init smdk2440_map_io(void)修改完后直接make,默认配置上选上支持按键的,所以无需修改配置,将生成的内核加载到开发板上。
二、开发板上测试:
(1)查看相关信息:
ls -l /proc/bus/input 可查看inptu下handler,它是用来事件的具体处理,它为输入设备的功能实现了一个接口
cat devices 查看设备信息,我们可以看到为按键事件分配了一个设备几点,用于处理按键事件。
(2)简单的测试:
我们可以用hexdump命令(查看”二进制“文件的十六进制编码)对按键进行有效测试:
第2~5列:输入事件时间戳,即结构体中的time。
第6列:输入事件类型,即结构体中的type。
第7列:按键的键值,即结构体中的code。
第8列:按键的状态,即结构体中的value,1表示按下,0表示松开。
上面是依次按下4个按键所得到的结果,每按一个键,会出现4行数据,这是因为每按一次键包括键的按下和键的抬起两个动作,而每个动作结束后还会有一个同步事件发生,因此会出现4行数据。
每行的倒数第四个数据到倒数第二数据分别对应input_event数据结构(同样定义在linux-3.0.54/include/linux/input.h)中的type ,code ,value
struct input_event {
struct timeval time;
__u16 type; //按键类型
__u16 code; //按键代码
__s32 value; //按键的值
};
倒数第三行是我们的按键代码,每个按键代码是唯一的,所以我们可以,经测试得到每个按键代码值为:
KEY_1: 2
KEY_2: 3
KEY_3: 4
KEY_4: 5
接下来我们就可以根据code的值来判断是哪个按键按下,分别用来控制led灯。
三、测试程序:
下面我们来写linux内核按键与led结合的测试程序:
/********************************************************************************* * Copyright: (C) 2017 qicheng * All rights reserved. * * Filename: led.c * Description: This file * * Version: 1.0.0(04/30/2017) * Author: yangni <497049229@qq.com> * ChangeLog: 1, Release initial version on "04/30/2017 11:44:03 AM" * ********************************************************************************/#include <stdio.h> #include<stdint.h> #include<string.h> #include<fcntl.h> #include<unistd.h> #include<linux/input.h> #include<unistd.h> #include <stdlib.h> #include <linux/input.h> #define EV_PRESS 1#define EV_RELEASE 0int main(void) { char buf[50]; int fd_button; int fd_led[4]; int i; struct input_event ev_key; fd_button= open("/dev/event0", 666); if(fd_button < 0) { perror("open device buttons"); exit(1); } for(i=1;i<=4;i++) { snprintf((char *)buf,sizeof(buf),"/sys/class/leds/led%d/brightness",i); fd_led[i] = open(buf, O_RDWR); if(fd_led[i]<0) { printf("can't open the file led%d",i); return -1; } } while(1) { read(fd_button,&ev_key,sizeof(struct input_event)); if(EV_KEY==ev_key.type && EV_PRESS==ev_key.value) //value=1 表示现在是按下 { switch(ev_key.code) //通过对code传值来确定是哪个按键 { static int count_key1 = 0; //定义一个静态变量count_key1 ,来计算按键按下次数 case KEY_1: if(count_key1%2==0) { write(fd_led[1],"1",1); count_key1++; } else { write(fd_led[1],"0",1); count_key1++; } break; case KEY_2: write(fd_led[2],"1",1); sleep(1); write(fd_led[2],"0",1); break; case KEY_3: write(fd_led[3],"1",1); sleep(1); write(fd_led[3],"0",1); break; case KEY_4: write(fd_led[4],"1",1); sleep(1); write(fd_led[4],"0",1); break; default: break; } } else if(EV_KEY==ev_key.type && EV_RELEASE==ev_key.value) //value=0表示现在按键释放 { printf("relase the key!\n"); } } for(i=1;i<=4;i++) { close(fd_led[i]); } close(fd_button); return 0; }
这里用for循环语句打开依次多个设备,用到了snprintf()函数。
int snprintf ( char *restrict buf , size_t n , const char * restrict format, ...);
函数说明:最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n 的话,将不会溢出。
以上面测试程序为例子:
循环打开led1,led2,led3,led4:
char buf[50];
int led[4];
for(i=1;i<=4;i++) { snprintf((char *)buf,sizeof(buf),"/sys/class/leds/led%d/brightness",i); fd_led[i] = open(buf, O_RDWR); if(fd_led[i]<0) { printf("can't open the file led%d",i); return -1; } }注意,因为我们要打开的是led1,led2,led3,led4,所以%d直接跟在led后面。
- fl2440——内核自带按键驱动的移植与测试
- fl2440——内核自带按键驱动 代码分析
- fl2440内核自带按键驱动移植及hexdump命令
- 内核自带按键驱动的添加与测试
- fl2440内核自带的LED驱动修改与使用
- fl2440——linux内核自带的led驱动添加
- fl2440使能linux-3.0内核自带的led驱动,并测试
- fl2440——内核自带LED的使用
- fl2440内核移植(五)——USB驱动移植
- 基于fl2440内核linux-3.0移植----添加按键驱动
- 内核自带LED驱动移植
- fl2440 platform 按键驱动的制作和测试
- fl2440的按键button驱动
- Linux-4.9.2内核在mini2440上的移植(十三)——按键驱动移植
- ARM9开发板FL2440移植Linux-3.0内核————添加USB驱动
- ARM9开发板FL2440移植Linux-3.0内核————MMC和LCD驱动
- fl2440——移植USB驱动、内核添加USB支持、U盘挂载
- fl2440的内核移植总结
- eclipse导出Jar包选项
- 谈android组件化之ARouter简单使用
- 蓝牙解析(part11):BLE SM(5):传统配对(Legacy Pairing):OOB
- linux编译boost
- Java中设计模式之生产者消费者模式-3
- fl2440——内核自带按键驱动的移植与测试
- Linux系统中安装和简易配置redis
- 【LeetCode】【Python】8. String to Integer (atoi)
- 表格如何去除边框以及分割线
- Qt中IEEE754格式转换为浮点数方法
- Android Annotation注解使用说明
- java中对象相等(equal)
- 调用微信js-sdk(‘分享给朋友‘为例)
- 面向对象与C++程序设计-向量和迭代器学习笔记