Android系统 linux内核按键驱动开发
前言
刚入门的小白,在csdn的帮助下完成了第一个按键驱动,特写此文记录学习并分享给有需要的人。
1.修改设备树.dts
我是用的开发板是rp-rk3288,Android8.1的源码。路径是rk3288-android8.1/kernel/arch/arm/boot/dts/rp-rk3288.dts。 在dts文件里面配置要使用的gpio。具体如何配置不同开发板是不一样的,可以参考同节点下其他gpio的配置,大多数都是大同小异的。 gpio_num = <&gpio5 15 GPIO_ACTIVE_LOW> : 代 表 设 置 gpio5_B7 为 低 电 平 ,. 将GPIO_ACTIVE_LOW 改成 GPIO_ACTIVE_HIGH 就是设置为高电平 gpio_function = <0>:0 代表设置为输出模式,1代表输入模式
2.创建驱动文件
在rk3288-android8.1/kernel/drivers/目录下创建目录hby,在hby下创建驱动文件hby.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include<linux/kdev_t.h>
struct input_dev *inputdev ;
struct rk3288_key_struct {
int key_gpio;
int key_code;
struct work_struct work;
};
struct rk3288_key_struct keys_list[] ={
{.key_code = KEY_BACK, .key_gpio = 167},
};
static irqreturn_t rk3288_key_intnerrupt(int irq, void *dev_id, struct pt_regs *regs){
int i= (int)dev_id;
int gpio = keys_list[i].key_gpio;
int code = keys_list[i].key_code;
udelay(20);
if (gpio_get_value(gpio)) {
return IRQ_HANDLED;
}
input_report_key(inputdev, code, 1);
input_sync(inputdev);
schedule_work(&(keys_list[i].work));
return IRQ_HANDLED;
}
static void rk3288_scankeypad(struct work_struct *_work){
struct rk3288_key_struct *key_tmp = container_of(_work, struct rk3288_key_struct, work);
int gpio = key_tmp -> key_gpio;
int code = key_tmp->key_code;
while(!gpio_get_value(gpio)){
mdelay(10);
}
input_report_key(inputdev, code, 0);
input_sync(inputdev);
}
static int __init hello_init(void){
int i = 0, ret = 0;
int irq_no = 0;
int code, gpio;
printk("!!!!!!!!!!HELLO 3288!!!!!!!!!!!!");
inputdev = input_allocate_device();;
if (!inputdev) {
return -ENOMEM;
}
inputdev->name = "hby_rk3288_key_ko";
set_bit(EV_KEY, inputdev->evbit);
for (i = 0; i < sizeof(keys_list)/sizeof(keys_list[0]); i++) {
code = keys_list[i].key_code;
gpio = keys_list[i].key_gpio;
INIT_WORK(&(keys_list[i].work), rk3288_scankeypad);
set_bit(code, inputdev->keybit);
gpio_free(gpio);
ret = gpio_request(gpio, "gpio5b7");
if (ret) {
printk("request gpio failed %d \n", gpio);
return -EBUSY;
}
gpio_direction_input(gpio);
int irq_no= gpio_to_irq(gpio);
int setirqret = irq_set_irq_type(irq_no, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING);
ret = request_irq(irq_no, rk3288_key_intnerrupt, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "hby_rk3288_key",(void *)i);
if (ret) {
printk("request irq faile%d!\n", irq_no);
return -EBUSY;
}
}
int registerdevice=input_register_device(inputdev);
printk("hby key driver up \n");
return 0;
}
static void __exit hello_exit(void)
{
int i = 0;
int irq_no;
for (i = 0; i < sizeof(keys_list)/sizeof(keys_list[0]); i++) {
irq_no = gpio_to_irq(keys_list[i].key_gpio);
free_irq(irq_no, (void *)i);
}
printk("!!!!!!!!!!!!!BYE!!!!!!!!!!!! \n");
input_unregister_device(inputdev);
}
subsys_initcall(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
驱动的代码就不解释了,注释写的很清楚了。
3.新建makefile和kconfig文件
这里需要在hby目录下新建makefile文件和kconfig文件 #makefile
obj-$(CONFIG_HBY) +=hby.o
#kconfig
config HBY
tristate "register driver hby"
default n
help
This is key driver for hby
至于makefile 和kconfig的具体语法这里就不详细介绍(因为我也不会【狗头】)想了解的可以参考这里
4.修改上级的makefile和kconfig文件
linux内核源码每一层都有一个makefile文件和kconfig文件,一个makefile只负责处理本目录中的编译关系,整个linux内核的makefile组成一个树状结构,对于上层makefile的子目录而言,只需要让kbuild知道它应该怎样进行递归地进入目录即可。所以要把我们新建的makefile和kconfig添加到这颗树上。也就是告诉上层我们这里还有一个makefile和config 具体做法 #1.修改hby目录的上层makefile,也就是rk3288-android8.1/kernel/drivers/makefile。添加 obj-$(CONFIG_HBY) += hby/ #2.修改hby目录的上层kconfig,也就是rk3288-android8.1/kernel/drivers/kconfig。 在menu "Device Drivers"和endmenu之间添加这一句。 source "drivers/hby/Kconfig
5.配置编译菜单
添加完之后进入内核根目录(/kernel),执行make menuconfig命令,menuconfig: 由scripts工具和Kconfig构成的图形配置界面, 通过它生成.config文件,在这个配置菜单中,将我们编写的驱动添加进去,则编译内核的时候我们的驱动就会编译。
进入Device Drivers —> 找到我们刚刚编写的驱动,把他设置为M。 在menuconfig中选择n、m和 y的区别: n:不编译 y: 模块驱动编译到内核中,启动时自动加载 m:模块会被编译,但是不会被编译到内核中,可以使用insmod命令动态加载驱动。
6.编译
有了上面的设置,编译内核的时候就会在hby目录下生成一个hby.ko文件
7.加载驱动
将这个.ko文件拷贝到设备里,使用insmod 命令加载驱动 dmesg -c命令查看printk方法打印的日志。 使用getevent 指令获取按键上报信息。其中event3就是我们新加入的驱动,设备名就是我们在驱动代码中设置的。当按下按键的时候,就能获取按键上报的信息。 在我们上述的这个例子里,我把该按键设置成back,也就是按下按键的时候上层就会收到一个back事件,我们的安卓设备就会 “返回”
|