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>//获取一个设备的设备编号,应当使用<linux/kdev_t.h>中定义的宏
//定义输入设备指针
struct input_dev *inputdev ;struct rk3288_key_struct { int key_gpio;// GPIO编号int key_code; // 按键能产生的键值struct work_struct work; // 按键的工作队列  };struct rk3288_key_struct keys_list[] ={//按键列表,有多个按键就可以在这里加上{.key_code = KEY_BACK, .key_gpio = 167},//{.key_code = KEY_VOLUMEUP, .key_gpio = 166},//{.key_code = KEY_VOLUMEDOWN, .key_gpio = 223}
};
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; //获取按键的 GPIO int code = keys_list[i].key_code; // 获取按键的键值// 延迟 20uS,看按键是不是按下,如果不是,就是抖动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){//中断处理下班部分// 通过工作队列指针而获得它所属的 rk3288_key_struct类型的对象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;// 每隔 10mS 检查按键是否已经提起,如果没有提起就一直等待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();;// 1. 分配一个input_dev结构体 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);//为每个按键都初始化 GPIOret = gpio_request(gpio, "gpio5b7");if (ret) {printk("request gpio failed %d \n", gpio);return -EBUSY;}gpio_direction_input(gpio); //当 GPIO 被设置为输入工作状态后,就可以检测中断信号int irq_no= gpio_to_irq(gpio);//获取中断号int setirqret = irq_set_irq_type(irq_no, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING);// 把每个 GPIO 中断响应方式都设置为下降沿响应//为每个按键的中断都安装中断处理函数,其私有数据为按键信息在 keys_list 数组下的索引 ret = request_irq(irq_no, rk3288_key_intnerrupt, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, "hby_rk3288_key",(void *)i);///(void *)i  &keys_list[i]if (ret) {printk("request irq faile%d!\n", irq_no);return -EBUSY;}} //3. 注册 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); // 为每个按键释放 GPIOfree_irq(irq_no, (void *)i); // 为每个按键卸载中断处理函数}printk("!!!!!!!!!!!!!BYE!!!!!!!!!!!! \n");input_unregister_device(inputdev);// 注销输入设备驱动
}
subsys_initcall(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

module_initmodule_exit
这两个函数分别在加载和卸载驱动时被调用,即调用insmod和rmmod命令的时候我们编写的hello_init函数和hello_exit函数会执行
这部分代码需要注意的是,我们的按键gpio常态时电平是1,按下的时候为0,写驱动的时候一定要结合硬件的特性。
其他代码的具体含义见注释,注释写的很详细,这里不赘述。

3.新建makefile和kconfig文件

这里需要在hby目录下新建makefile文件和kconfig文件
#makefile

// makefile文件只有一行代码
obj-$(CONFIG_HBY) +=hby.o

#kconfig

config HBYtristate "register driver hby"default nhelpThis 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事件,我们的安卓设备就会 “返回”

Android系统 linux内核按键驱动开发相关推荐

  1. linux内核led驱动开发,从Linux内核LED驱动来理解字符设备驱动开发流程

    目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设 ...

  2. android系统移植之按键驱动篇

    平台:MX53_QSB开发板 MX53_QSB开发板上一起有四个按键,分别为RESET,POWER,USER1,USER2.其中RESET为纯硬件复位按键,无须软件控制.POWER,USER1,USE ...

  3. linux内核按键驱动,嵌入式Linux按键驱动框架

    前言 本文将通过轮询.中断.poll机制.异步通知和同步互斥阻塞等方式编写按键驱动程序.本节的驱动框架是在<嵌入式Linux驱动框架的搭建>的基础上进行改进的,所以本文只讲解修改的部分. ...

  4. Android深度探索--HAL与驱动开发----第三章读书笔记

    Git--源代码管理软件,Git功能十分复杂,我们需要完成的功能有:创建版本库,提交源代码,创建分支,向远程服务器提交源代码,从远程服务器获取源代码等.而本章的学习内容就是掌握如何使用Git从源代码托 ...

  5. Android 系统(4)---Android HAL层与Linux Kernel层驱动开发简介

    Android HAL层与Linux Kernel层驱动开发简介 近日稍微对Android中的驱动开发做了一些简要的了解,稍稍理清了一下Android驱动开发的套路,总结一下笔记. HAL:Hardw ...

  6. Android HAL层与Linux Kernel层驱动开发简介

    Android HAL层与Linux Kernel层驱动开发简介 阅读数:5070 近日稍微对Android中的驱动开发做了一些简要的了解,稍稍理清了一下Android驱动开发的套路,总结一下笔记. ...

  7. 嵌入式系统Linux内核开发工程师必须掌握的三十道题

    嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...

  8. 嵌入式系统Linux内核开发实战指南(ARM平台) 书评

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! < ...

  9. 基于Linux2.6下的按键驱动开发步骤

    实验平台:友善之臂s3c2410 编译环境:ubuntu > arm-linux-gcc3.4.5 内核版本:Linux2.6 实验目的:在Linux下完成arm板上的8*8按键驱动开发,最终实 ...

最新文章

  1. String拼接字符串效率低,你知道原因吗?
  2. Windows下oracle RMAN备份脚本
  3. java web 导出word_JavaWeb Project使用FreeMaker导出Word文件
  4. linux 机器格式化_为什么机器人应该为我们格式化代码
  5. 你没干什么坏事,你怕什么?
  6. 信息学奥赛一本通(2042:【例5.10】稀疏矩阵)
  7. ubuntu安装cuda(转精华)
  8. Palo Alto Networks下一代安全平台五大创新功能:云安全为重中之重
  9. Wave Arts Tube Saturator for Mac(电子管模拟效果器插件)
  10. 海康VisionMaster算法平台介绍
  11. 近世代数课后习题作业 1
  12. springboot配置文件为yml格式详解
  13. unity打开excel表格_unity创建编辑读取EXCEL文件表格数据游戏插件工具Uni-Excel 1.0
  14. 关于网络存储技术和存储的协议
  15. web前端期末大作业 html+css学生心理 7页主题网页设计
  16. JavaWeb学习-动态代理-2-invoke()方法和动态代理Waiter类练习
  17. TCP协议拥塞控制算法(Reno、HSTCP、BIC、Vegas、Westwood)
  18. 大家一起学数据结构之单链表
  19. @PersistenceContext 注解在spring中代理
  20. 冯 . 诺依曼体系结构对计算机发展的限制

热门文章

  1. docker 设备共享
  2. 2019年厦门国际银行“数创金融杯”数据建模大赛总结
  3. zotero本地常见插件配置,新电脑配置zotero,新手入门
  4. 重装系统服务器2012r2,SCCM2012R2网络部署重装系统
  5. 异构网络互联;路由与转发;SDN基本概念;拥塞控制
  6. html涟漪动画效果,CSS+JS实现水滴涟漪动画按钮效果的示例代码
  7. Linux中tar和scp
  8. 面试姊妹篇4:常见的Java多线程面试题
  9. 红米5a android 版本,#MIUI#关于红米手机4高配版 Android版本适配的说明【miui9吧】_百度贴吧...
  10. Win11电脑速度慢、延迟高怎么办?