摘要:我們用一種更為高級(jí)的方法去驅(qū)動(dòng)所有的按鍵理論上按鍵最多可以驅(qū)動(dòng)個(gè),但是我的板子只有三個(gè)按鍵所以現(xiàn)在只能驅(qū)動(dòng)三個(gè),但是驅(qū)動(dòng)三個(gè)和驅(qū)動(dòng)個(gè)都是一樣的。
我們用一種更為高級(jí)的方法去驅(qū)動(dòng)所有的按鍵————理論上按鍵最多可以驅(qū)動(dòng)768個(gè),但是我的板子只有三個(gè)按鍵
所以現(xiàn)在只能驅(qū)動(dòng)三個(gè),但是驅(qū)動(dòng)三個(gè)和驅(qū)動(dòng)768個(gè)都是一樣的。
首先我們要利用起設(shè)備樹文件了,如果不用設(shè)備樹的話,你就得一個(gè)一個(gè)的去驅(qū)動(dòng),雖然你可以在一個(gè)模塊上完成所有的按鍵驅(qū)動(dòng),但是要是真的驅(qū)動(dòng)768個(gè)按鍵,那么你估計(jì)能寫上萬行代碼。你要跟以前的方法一樣,每一個(gè)按鍵都要去實(shí)例化設(shè)備,然后獲取中斷,地址,…這些信息,然后再處理這些信息。
但是如果你用了設(shè)備樹,我直接在設(shè)備樹上寫好這些信息,到時(shí)候你拿的去用就可以了。
并且你直接整一個(gè)for循環(huán),它就自動(dòng)把768個(gè)設(shè)備信息給你全部拿過來了,豈不爽哉!!
那就讓我們來領(lǐng)略一下設(shè)備樹的魅力:
————————————————————————————————————————————————
驅(qū)動(dòng)所有按鍵第一步:
編寫設(shè)備樹:
我們之前也編寫過,這里我們?cè)敿?xì)的講一下:(設(shè)備樹就是用來存儲(chǔ)設(shè)備信息的)
首先是在根節(jié)點(diǎn)下創(chuàng)建了一個(gè)屬于我們的設(shè)備叫:key_int_node.
我們要驅(qū)動(dòng)三個(gè)按鍵,所以在這個(gè)我們的設(shè)備下面創(chuàng)建了三個(gè)子設(shè)備,代表我這設(shè)備由這三個(gè)設(shè)備共同組成。
要是你有一千個(gè)設(shè)備那么你也可以吧一千個(gè)設(shè)備寫里面組成你的設(shè)備。
好讓我們看一下每一個(gè)子設(shè)備下存儲(chǔ)了上面信息
```c在設(shè)備樹文件中設(shè)置這幾個(gè)元素: key_int_node{ compatible = "test_key"; #address-cells = <1>; #size-cells = <1>; key_int@0 { key_name = "key2_power_eint"; //表示我這個(gè)子設(shè)備名字叫....自定義 key_code = <116>; //設(shè)置這個(gè)子設(shè)備的鍵值,就是代表這個(gè)鍵是用來干嘛的, //你可以隨便設(shè)你想讓它有上面功能都可以 gpio = <&gpx1 1 0>; //代表這個(gè)引腳在電路圖上是屬于gpx1_1引腳,后面可以讀這個(gè)引腳的值來獲 //取按鍵有沒有按下,就很方便 reg = <0x11000C20 0x18>; //物理地址 interrupt-parent = <&gpx1>; //表示中斷繼承了gpx1 interrupts = <1 0>; //代表是gpx1_1的中斷,后面根據(jù)節(jié)點(diǎn)獲取中斷號(hào)就是 }; 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>; }; }; 好了第一步完成,你可以根據(jù)芯片手冊(cè),把所有的按鍵信息寫進(jìn)去
——————————————————————————————————————
驅(qū)動(dòng)所有按鍵第二步:
接下來我們就要編寫設(shè)備模塊代碼了
1)首先就是日常搭框架
2)然后就是想辦法從設(shè)備樹上把這些我們寫的文件信息拿過來。
我們采用了我通用的設(shè)備信息結(jié)構(gòu)體,
然后我用一個(gè)數(shù)組去實(shí)例化它,那么我只要一個(gè)數(shù)組的名字我就可以存儲(chǔ)并且找到所有的設(shè)備信息了。
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];
那我們有這樣一個(gè)結(jié)構(gòu)體數(shù)組了,那我還是沒有從設(shè)備樹上獲取到信息啊。
別急——我們寫一個(gè)函數(shù),直接對(duì)著設(shè)備樹就是 —拿來吧你
我們需要一個(gè)中介去連接我們的設(shè)備樹,和用來存儲(chǔ)信息的結(jié)構(gòu)體:這個(gè)中介就是: struct device_node *cnp; 這是一個(gè)設(shè)備節(jié)點(diǎn)在結(jié)構(gòu)體中已經(jīng)定義了
首先我們像獲取中斷號(hào)一樣,從設(shè)備樹上獲取到節(jié)點(diǎn),但是這個(gè)節(jié)點(diǎn),不是我們要的兒子節(jié)點(diǎn)。所有我們得獲取到子節(jié)點(diǎn)點(diǎn),并且,
要一個(gè)設(shè)備結(jié)構(gòu)體數(shù)組對(duì)應(yīng)一個(gè)子節(jié)點(diǎn)信息:
void get_allirqno(void){ //從設(shè)備樹上獲取設(shè)備節(jié)點(diǎn) 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; //用來記錄節(jié)點(diǎn)的,到時(shí)候再賦給每一個(gè)的all_dev的cnp //要獲取的節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn),這樣就可以通過上一個(gè)節(jié)點(diǎn)的位置獲取到我要獲取的節(jié)點(diǎn)的位置 struct device_node *prev = NULL; int i=0; do{ if(lcnp != NULL){ all_dev[i++].cnp = lcnp;//將當(dāng)前的節(jié)點(diǎn)記錄下來 } prev = lcnp; //把當(dāng)前的設(shè)置位prev }while(of_get_next_child(np, prev) != NULL); }
這樣我們就可以通過設(shè)備結(jié)構(gòu)體數(shù)組中的子節(jié)點(diǎn)與設(shè)備樹建立了連接。
——————————————————————————————————————————————————
接下來是驅(qū)動(dòng)第三步:
完成模塊裝載入口
我們之前在模塊裝載路口做了三件事:
1,分配一個(gè)input device對(duì)象
2, 初始化input device對(duì)象
3,注冊(cè)input device對(duì)象
我們現(xiàn)在也是做這三件事;
1)實(shí)例化一個(gè)輸入設(shè)備對(duì)象,并發(fā)分配空間,和部分初始化
struct input_dev *inputdev; //實(shí)例化一個(gè)輸入設(shè)備對(duì)象
inputdev = input_allocate_device(void);
2)可以添加設(shè)備信息
3)調(diào)用我們的獲取信息的函數(shù)————因?yàn)槲覀兘酉聛硪玫竭@些在設(shè)備樹上的信息
4)初始化input device對(duì)象
這里需要初始化倆個(gè):
一個(gè)是按鍵類型
//初始化inputdevice對(duì)象—設(shè)為按鍵類型信息
_set_bit(EV_KEY, inputdev->evbit);
還有就是按鍵的具體信息:
但是不要忘了,我們有很多很多的按鍵,所以我們要利用我們之前的設(shè)備結(jié)構(gòu)體數(shù)組中的子節(jié)點(diǎn)
然后利用for循環(huán),把設(shè)備樹上的其它對(duì)應(yīng)信息讀到對(duì)應(yīng)的設(shè)備結(jié)構(gòu)體數(shù)組中去
我們還要
1)設(shè)置鍵值具體信息:所以要拿到對(duì)應(yīng)的鍵值
of_property_read_u32(cnp,“key_code”, &code
2)申請(qǐng)對(duì)應(yīng)中斷:所以要拿到中斷號(hào)
irqno = irq_of_parse_and_map(cnp, 0)
3)我們還可以打印設(shè)備名字用來區(qū)分設(shè)備
of_property_read_string(cnp, “key_name”, &key_name);
這樣我們就完成了,設(shè)備的初始化以及中斷申請(qǐng)
4)注冊(cè)設(shè)備:
我們申請(qǐng)了設(shè)備(由很多子設(shè)備組成的大設(shè)備)就要注冊(cè)進(jìn)去,讓內(nèi)核幫我們匹配
input_register_device(inputdev);
——————————————————————————————
接下來是驅(qū)動(dòng)第三步:
那我們拿到數(shù)據(jù)了,怎么把按鍵的值傳出去呢?
,我們寫在中斷處理函數(shù)里面,但是我有幾百個(gè)設(shè)備,我只用了一個(gè)中斷處理函數(shù)我怎么區(qū)分你按的是什么中斷?
首先我們?cè)谏暾?qǐng)中斷的時(shí)候就會(huì)把,設(shè)備信息結(jié)構(gòu)體指針傳個(gè)中斷處理函數(shù)。
我們直接可以區(qū)分不同的鍵值。
并且我們還可以直接根據(jù)設(shè)備樹上的gpionum直接去讀引腳的數(shù)據(jù)判斷,是否被按下————nice
int gpionum = of_get_named_gpio(pdesc->cnp, “gpio”, 0);
//直接通過gpio獲取按鍵狀態(tài)
int value = gpio_get_value(gpionum);
——————————————————總的代碼————————————————————
#include #include #include #include #include #include #include #include #define KEY_NUMS 3#define KEY_NOM 3#define IRQFLAGS IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISINGstruct input_dev *inputdev; //實(shí)例化一個(gè)輸入設(shè)備對(duì)象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){ //區(qū)分不同的按鍵 struct key_desc *pdesc = (struct key_desc *)devid; int gpionum = of_get_named_gpio(pdesc->cnp, "gpio", 0); //直接通過gpio獲取按鍵狀態(tài) int value = gpio_get_value(gpionum); if(value){//抬起 input_report_key(inputdev, pdesc->key_code, 0); input_sync(inputdev);//上報(bào)數(shù)據(jù)結(jié)束 }else{ input_report_key(inputdev, pdesc->key_code, 1); input_sync(inputdev);//上報(bào)數(shù)據(jù)結(jié)束}return IRQ_HANDLED;}void get_allirqno(void){ //從設(shè)備樹上獲取設(shè)備節(jié)點(diǎn) 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; //用來記錄節(jié)點(diǎn)的,到時(shí)候再賦給每一個(gè)的all_dev的cnp //要獲取的節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn),這樣就可以通過上一個(gè)節(jié)點(diǎn)的位置獲取到我要獲取的節(jié)點(diǎn)的位置 struct device_node *prev = NULL; int i=0; do{ if(lcnp != NULL){ all_dev[i++].cnp = lcnp;//將當(dāng)前的節(jié)點(diǎn)記錄下來 } prev = lcnp; //把當(dāng)前的設(shè)置位prev }while(of_get_next_child(np, prev) != NULL); }static int __init akey_dev_init(void){ //編寫輸入子系統(tǒng)代碼 /* 1,分配一個(gè)input device對(duì)象 2, 初始化input device對(duì)象 3,注冊(cè)input device對(duì)象 */ //1、給實(shí)例化的輸入設(shè)備對(duì)象分配空間并部分初始化 inputdev = input_allocate_device(void); if(inputdev == NULL) { printk(KERN_ERR "input_allocate_device error/n"); return -ENOMEM; } //添加設(shè)備信息/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對(duì)象---設(shè)為按鍵類型信息 _set_bit(EV_KEY, inputdev->evbit); //利用設(shè)備樹多個(gè)獲取信息 int i; for(i=0;i<KEY_NOM;++i){ struct device_node *cnp = all_dev[i].cnp; //這個(gè)cnp記錄了每個(gè)設(shè)備的節(jié)點(diǎn) //獲取鍵值 int code; of_property_read_u32(cnp,"key_code", &code); _set_bit(code, inputdev->keybit); //將從設(shè)備樹上獲取的鍵值設(shè)置位鍵值數(shù)據(jù)code all_dev[i].key_code = code; //把code信息記錄到每個(gè)子設(shè)備的結(jié)構(gòu)體中 //獲取中斷號(hào) 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; //申請(qǐng)中斷 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; } } //注冊(cè)設(shè)備 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");
—————————————————————應(yīng)用程序代碼———————————————————————
#include #include #include #include #include #include #include #include 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;}
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/121073.html
文章目錄 selenium 簡(jiǎn)介selenium安裝安裝瀏覽器驅(qū)動(dòng)確定瀏覽器版本下載驅(qū)動(dòng) 定位頁面元素打開指定頁面id 定位name 定位class 定位tag 定位xpath 定位css 定位link 定位partial_link 定位 瀏覽器控制修改瀏覽器窗口大小瀏覽器前進(jìn)&后退瀏覽器刷新瀏覽器窗口切換常見操作 鼠標(biāo)控制單擊左鍵單擊右鍵雙擊拖動(dòng)鼠標(biāo)懸停 鍵盤控制 seleni...
摘要:鍵盤使用說明索引均為出廠默認(rèn)值升級(jí)固件軟件支持一些常見問題解答電池開關(guān)電池插座轉(zhuǎn)接小板連接首次使用測(cè)試步驟藍(lán)牙和切換鍵盤默認(rèn)層默認(rèn)觸發(fā)層的鍵配置的功能默認(rèn)功能層配置的功能默認(rèn)的快捷鍵藍(lán)牙配對(duì)藍(lán)牙參數(shù)藍(lán)牙地址管理升級(jí)固件 ...
摘要:應(yīng)用程序的模型是基于一個(gè)事件驅(qū)動(dòng)的協(xié)作式多任務(wù)模型。兩個(gè)數(shù)據(jù)字段均不包含數(shù)據(jù)的事件有和。僅在短數(shù)據(jù)字段中包含數(shù)據(jù)的典型事件有,僅在長(zhǎng)數(shù)據(jù)字段中包含數(shù)據(jù)的典型事件有和。 BREW應(yīng)用程序的模型是基于一個(gè)事件驅(qū)動(dòng)的協(xié)作式多任務(wù)模型。事件處理機(jī)制的核心問題是程序應(yīng)該只處理需要的事件,對(duì)于不...
摘要:難在哪里根據(jù)上面的標(biāo)簽需要定位最后一行標(biāo)簽,以下列出了四種方式,定位的方式多樣并不唯一,使用時(shí)根據(jù)情況進(jìn)行解析即可。加入每日一練我們使用并指明標(biāo)簽內(nèi)全部文本即可定位。 ...
閱讀 3062·2021-11-24 10:34
閱讀 3322·2021-11-22 13:53
閱讀 2629·2021-11-22 12:03
閱讀 3598·2021-09-26 09:47
閱讀 3005·2021-09-23 11:21
閱讀 4772·2021-09-22 15:08
閱讀 3289·2021-07-23 10:59
閱讀 1258·2019-08-29 18:31