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事件,我們的安卓設備就會 “回傳”
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/290474.html
標籤:其他
下一篇:IOS-Tom貓小游戲實作
