主頁 >  其他 > 高級驅動——(驅動所有按鍵)

高級驅動——(驅動所有按鍵)

2021-09-25 19:13:34 其他

我們用一種更為高級的方法去驅動所有的按鍵————理論上按鍵最多可以驅動768個,但是我的板子只有三個按鍵
所以現在只能驅動三個,但是驅動三個和驅動768個都是一樣的,
首先我們要利用起設備樹檔案了,如果不用設備樹的話,你就得一個一個的去驅動,雖然你可以在一個模塊上完成所有的按鍵驅動,但是要是真的驅動768個按鍵,那么你估計能寫上萬行代碼,你要跟以前的方法一樣,每一個按鍵都要去實體化設備,然后獲取中斷,地址,…這些資訊,然后再處理這些資訊,
但是如果你用了設備樹,我直接在設備樹上寫好這些資訊,到時候你拿的去用就可以了,
并且你直接整一個for回圈,它就自動把768個設備資訊給你全部拿過來了,豈不爽哉!!
那就讓我們來領略一下設備樹的魅力:
————————————————————————————————————————————————
驅動所有按鍵第一步:
撰寫設備樹:
我們之前也撰寫過,這里我們詳細的講一下:(設備樹就是用來存盤設備資訊的)
首先是在根節點下創建了一個屬于我們的設備叫:key_int_node.
我們要驅動三個按鍵,所以在這個我們的設備下面創建了三個子設備,代表我這設備由這三個設備共同組成,
要是你有一千個設備那么你也可以吧一千個設備寫里面組成你的設備,
好讓我們看一下每一個子設備下存盤了上面資訊

```c
在設備樹檔案中設定這幾個元素:
  key_int_node{
            compatible = "test_key";
            #address-cells = <1>;
            #size-cells = <1>;

            key_int@0 {
                    key_name = "key2_power_eint";     //表示我這個子設備名字叫....自定義
                    key_code = <116>;	              //設定這個子設備的鍵值,就是代表這個鍵是用來干嘛的,
                    									//你可以隨便設你想讓它有上面功能都可以
                    gpio = <&gpx1 1 0>;				//代表這個引腳在電路圖上是屬于gpx1_1引腳,后面可以讀這個引腳的值來獲
                    								//取按鍵有沒有按下,就很方便
                    reg = <0x11000C20 0x18>;			//物理地址
                    interrupt-parent = <&gpx1>;			//表示中斷繼承了gpx1
                    interrupts = <1 0>;					//代表是gpx1_1的中斷,后面根據節點獲取中斷號就是
            };

            key_int@1 {
                    key_name = "key3_vup_eint";
                    key_code = <115>;
                    gpio = <&gpx1 2 0>;
                    reg = <0x11000C20 0x18>;
                    interrupt-parent = <&gpx1>;
                    interrupts = <2 0>;
            };

            key_int@2 {
                    key_name = "key4_vdown_eint";
                    key_code = <114>;
                    gpio = <&gpx3 2 0>;
                    reg = <0x11000C60 0x18>;
                    interrupt-parent = <&gpx3>;
                    interrupts = <2 0>;
            };
	};	
	好了第一步完成,你可以根據芯片手冊,把所有的按鍵資訊寫進去

——————————————————————————————————————
驅動所有按鍵第二步:
接下來我們就要撰寫設備模塊代碼了
1)首先就是日常搭框架
2)然后就是想辦法從設備樹上把這些我們寫的檔案資訊拿過來,

我們采用了我通用的設備資訊結構體,
然后我用一個陣列去實體化它,那么我只要一個陣列的名字我就可以存盤并且找到所有的設備資訊了,

struct  key_desc{
	char *name;
	int key_code;
	int irqno;
	int gpio_num;
	void *regbase;
	struct device_node *cnp;	
};

struct key_desc *all_dev[KEY_NOM];

那我們有這樣一個結構體陣列了,那我還是沒有從設備樹上獲取到資訊啊,
別急——我們寫一個函式,直接對著設備樹就是 —拿來吧你
我們需要一個中介去連接我們的設備樹,和用來存盤資訊的結構體:這個中介就是: struct device_node *cnp; 這是一個設備節點在結構體中已經定義了
首先我們像獲取中斷號一樣,從設備樹上獲取到節點,但是這個節點,不是我們要的兒子節點,所有我們得獲取到子節點點,并且,
要一個設備結構體陣列對應一個子節點資訊:

void get_allirqno(void){
	//從設備樹上獲取設備節點
	struct device_node *np = of_find_node_by_path("/key_int_node");
	if(np == NULL){
		printk("find_node error\n");
		return 0;
	}
	struct  device_node*lcnp;   //用來記錄節點的,到時候再賦給每一個的all_dev的cnp
	
	//要獲取的節點的上一個節點,這樣就可以通過上一個節點的位置獲取到我要獲取的節點的位置
	 struct device_node *prev = NULL;
	int i=0;
	
	do{
		
			if(lcnp != NULL){
				all_dev[i++].cnp = lcnp;//將當前的節點記錄下來
			}

			prev = lcnp; //把當前的設定位prev

		}while(of_get_next_child(np, prev) != NULL);
							
	
}

這樣我們就可以通過設備結構體陣列中的子節點與設備樹建立了連接,

——————————————————————————————————————————————————
接下來是驅動第三步:
完成模塊裝載入口
我們之前在模塊裝載路口做了三件事:
1,分配一個input device物件
2, 初始化input device物件
3,注冊input device物件
我們現在也是做這三件事;
1)實體化一個輸入設備物件,并發分配空間,和部分初始化
struct input_dev *inputdev; //實體化一個輸入設備物件
inputdev = input_allocate_device(void);
2)可以添加設備資訊
3)呼叫我們的獲取資訊的函式————因為我們接下來要用到這些在設備樹上的資訊

4)初始化input device物件
這里需要初始化倆個:
一個是按鍵型別
//初始化inputdevice物件—設為按鍵型別資訊
_set_bit(EV_KEY, inputdev->evbit);
還有就是按鍵的具體資訊:
但是不要忘了,我們有很多很多的按鍵,所以我們要利用我們之前的設備結構體陣列中的子節點
然后利用for回圈,把設備樹上的其它對應資訊讀到對應的設備結構體陣列中去
我們還要
1)設定鍵值具體資訊:所以要拿到對應的鍵值
of_property_read_u32(cnp,“key_code”, &code
2)申請對應中斷:所以要拿到中斷號
irqno = irq_of_parse_and_map(cnp, 0)
3)我們還可以列印設備名字用來區分設備
of_property_read_string(cnp, “key_name”, &key_name);

這樣我們就完成了,設備的初始化以及中斷申請
4)注冊設備:
我們申請了設備(由很多子設備組成的大設備)就要注冊進去,讓內核幫我們匹配
input_register_device(inputdev);
——————————————————————————————
接下來是驅動第三步:
那我們拿到資料了,怎么把按鍵的值傳出去呢?
,我們寫在中斷處理函式里面,但是我有幾百個設備,我只用了一個中斷處理函式我怎么區分你按的是什么中斷?
首先我們在申請中斷的時候就會把,設備資訊結構體指標傳個中斷處理函式,
我們直接可以區分不同的鍵值,
并且我們還可以直接根據設備樹上的gpionum直接去讀引腳的資料判斷,是否被按下————nice
int gpionum = of_get_named_gpio(pdesc->cnp, “gpio”, 0);
//直接通過gpio獲取按鍵狀態
int value = gpio_get_value(gpionum);
——————————————————總的代碼————————————————————

#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>

#include <asm/io.h>


#define KEY_NUMS 3

#define KEY_NOM 3
#define IRQFLAGS IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING


struct input_dev *inputdev;  //實體化一個輸入設備物件

struct  key_desc{
	char *name;
	int key_code;
	int irqno;
	int gpio_num;
	void *regbase;
	struct device_node *cnp;	
};

struct key_desc all_dev[KEY_NOM];


irqreturn_t  input_key_irq_handler(int irqno, void *devid){
	
	//區分不同的按鍵
	struct key_desc *pdesc = (struct key_desc *)devid;

	int gpionum = of_get_named_gpio(pdesc->cnp, "gpio", 0);


	//直接通過gpio獲取按鍵狀態
	int value = gpio_get_value(gpionum);

	if(value){//抬起
		
		input_report_key(inputdev, pdesc->key_code, 0);
		input_sync(inputdev);//上報資料結束
			
	}else{
		input_report_key(inputdev, pdesc->key_code, 1);
		input_sync(inputdev);//上報資料結束
}


return IRQ_HANDLED;

}




void get_allirqno(void){
	//從設備樹上獲取設備節點
	struct device_node *np = of_find_node_by_path("/key_int_node");
	if(np == NULL){
		printk("find_node error\n");
		return 0;
	}
	struct  device_node*lcnp;   //用來記錄節點的,到時候再賦給每一個的all_dev的cnp
	
	//要獲取的節點的上一個節點,這樣就可以通過上一個節點的位置獲取到我要獲取的節點的位置
	 struct device_node *prev = NULL;
	int i=0;
	
	do{
		
			if(lcnp != NULL){
				all_dev[i++].cnp = lcnp;//將當前的節點記錄下來
			}

			prev = lcnp; //把當前的設定位prev

		}while(of_get_next_child(np, prev) != NULL);
							
	
}


static int __init akey_dev_init(void){
	//撰寫輸入子系統代碼
	/*
		1,分配一個input device物件
		2, 初始化input  device物件
		3,注冊input device物件
	*/
	//1、給實體化的輸入設備物件分配空間并部分初始化
	inputdev = input_allocate_device(void)if(inputdev == NULL)
	{
		printk(KERN_ERR "input_allocate_device error\n");
		return -ENOMEM;
	}
	//添加設備資訊/sys/class/input/eventx/device/
	//自定義
	inputdev->name = "input key";
	inputdev->phys = "key/input/input0";
	inputdev->uniq = "simple key0 for 4412";
	inputdev->id.bustype = BUS_HOST;
	inputdev->id.vendor =0x1234 ;
	inputdev->id.product = 0x8888;
	inputdev->id.version = 0x0001;

	get_allirqno();
	
	//初始化inputdevice物件---設為按鍵型別資訊
	_set_bit(EV_KEY, inputdev->evbit);

	//利用設備樹多個獲取資訊
	int i;
	for(i=0;i<KEY_NOM;++i){
		
	struct device_node *cnp = all_dev[i].cnp;   //這個cnp記錄了每個設備的節點

	//獲取鍵值
	int code;
	of_property_read_u32(cnp,"key_code", &code);
	_set_bit(code, inputdev->keybit); //將從設備樹上獲取的鍵值設定位鍵值資料code
	 all_dev[i].key_code = code; //把code資訊記錄到每個子設備的結構體中


	//獲取中斷號
	int irqno;
	irqno = irq_of_parse_and_map(cnp, 0);
	all_dev->irqno = irqno;

	//獲取按鍵name
	char *key_name ;
	of_property_read_string(cnp, "key_name",  &key_name);
	all_dev[i].name = key_name;


	//申請中斷
		ret = request_irq(irqno, input_key_irq_handler, irqflags, 
					key_name, &all_dev[i]);
		if(ret != 0)
		{
			printk("request_irq error\n");
			goto err_1;
			}
	
	}


	//注冊設備
	ret = input_register_device(inputdev);
	if(ret != 0)
	{
		printk(KERN_ERR "input_register_device error\n");
		goto err_0;
	}

	return 0;

err_1:
	input_unregister_device(inputdev);
err_0:
	input_free_device(inputdev);

}



static int __exit akey_dev_exit(void){

	int i;
	for(i=0; i<KEY_NOM; i++)
		free_irq(all_dev[i].irqno, &all_dev[i]);
		
	input_unregister_device(inputdev);
	input_free_device(inputdev);

}


module_init(akey_dev_init);
module_exit(akey_dev_exit);
MODULE_LICENSE("GPL");

—————————————————————應用程式代碼———————————————————————

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

int main(void)
{
	int fd;
	int ret;
	struct input_event event;
	
	fd = open("/dev/input/event1", O_RDWR);
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}


	while(1)
	{
		ret = read(fd, &event, sizeof(struct input_event));
		if(ret < 0)
		{
			perror("read");
			exit(1);
		}

		if(event.type == EV_KEY){

		
			switch(event.code){
				case KEY_POWER:
					if(event.value){ //按下
						printf("__APP_USER__ :  power pressed\n");

					}else{
						printf("__APP_USER__ :  power up\n");
					}
					break;
				case KEY_VOLUMEDOWN:
					if(event.value){ //按下
						printf("__APP_USER__ :  vollum dowm  pressed\n");

					}else{
						printf("__APP_USER__ :  vollum dowm up\n");
					}
					break;
				case KEY_VOLUMEUP:
					if(event.value){ //按下
						printf("__APP_USER__ :  vollum up  pressed\n");

					}else{
						printf("__APP_USER__ :  vollum up up\n");
					}
					break;
				default:

					printf("error");
			}

		}
		
	}


	close(fd);

	return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302864.html

標籤:其他

上一篇:python-mqtt自動化測驗

下一篇:ESP8266用EspTouch一鍵配網,斷網自動恢復連接

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more