摘要:我們用一種更為高級的方法去驅動所有的按鍵理論上按鍵最多可以驅動個,但是我的板子只有三個按鍵所以現在只能驅動三個,但是驅動三個和驅動個都是一樣的。
我們用一種更為高級的方法去驅動所有的按鍵————理論上按鍵最多可以驅動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 #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; //實例化一個輸入設備對象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 #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;}
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/121073.html
文章目錄 selenium 簡介selenium安裝安裝瀏覽器驅動確定瀏覽器版本下載驅動 定位頁面元素打開指定頁面id 定位name 定位class 定位tag 定位xpath 定位css 定位link 定位partial_link 定位 瀏覽器控制修改瀏覽器窗口大小瀏覽器前進&后退瀏覽器刷新瀏覽器窗口切換常見操作 鼠標控制單擊左鍵單擊右鍵雙擊拖動鼠標懸停 鍵盤控制 seleni...
摘要:鍵盤使用說明索引均為出廠默認值升級固件軟件支持一些常見問題解答電池開關電池插座轉接小板連接首次使用測試步驟藍牙和切換鍵盤默認層默認觸發層的鍵配置的功能默認功能層配置的功能默認的快捷鍵藍牙配對藍牙參數藍牙地址管理升級固件 ...
摘要:應用程序的模型是基于一個事件驅動的協作式多任務模型。兩個數據字段均不包含數據的事件有和。僅在短數據字段中包含數據的典型事件有,僅在長數據字段中包含數據的典型事件有和。 BREW應用程序的模型是基于一個事件驅動的協作式多任務模型。事件處理機制的核心問題是程序應該只處理需要的事件,對于不...
摘要:難在哪里根據上面的標簽需要定位最后一行標簽,以下列出了四種方式,定位的方式多樣并不唯一,使用時根據情況進行解析即可。加入每日一練我們使用并指明標簽內全部文本即可定位。 ...
閱讀 3075·2021-11-24 10:34
閱讀 3331·2021-11-22 13:53
閱讀 2637·2021-11-22 12:03
閱讀 3604·2021-09-26 09:47
閱讀 3013·2021-09-23 11:21
閱讀 4807·2021-09-22 15:08
閱讀 3301·2021-07-23 10:59
閱讀 1262·2019-08-29 18:31