IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Android系统 linux内核按键驱动开发 -> 正文阅读

[系统运维]Android系统 linux内核按键驱动开发

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);//为每个按键都初始化 GPIO
         ret = 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); // 为每个按键释放 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

// 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事件,我们的安卓设备就会 “返回”

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:38:53  更:2021-07-27 16:39:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 16:45:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码