linux下被遗忘的gpio_keys按键驱动
我們新項(xiàng)目硬件設(shè)計(jì)上使用gpio口做按鍵,所以我就需要搞定這個(gè)驅(qū)動(dòng),本來想自己寫一個(gè)gpio口的按鍵驅(qū)動(dòng),然后看了下內(nèi)核下面的代碼,已經(jīng)有現(xiàn)成的了。Linux內(nèi)核下游很多很多的現(xiàn)成驅(qū)動(dòng),只要你想得到的,基本都是有現(xiàn)成的,當(dāng)然了,不包括一些非正常的需求性問題,學(xué)會(huì)在Linux下找驅(qū)動(dòng),看驅(qū)動(dòng)和內(nèi)核代碼,我覺得是一件享受和快樂的事情。
不過我還是在使用這個(gè)驅(qū)動(dòng)上遇到了問題。
1. 先說ADC 按鍵
之前的文章有寫過adc按鍵的實(shí)現(xiàn),無非就是為了省點(diǎn)GPIO口。
RK 利用SARADC 來做多個(gè)按鍵
2. GPIO?按鍵硬件原理圖
3. 驅(qū)動(dòng)代碼
kernel-4.4/drivers/input/keyboard/gpio_keys.c完整代碼可查看
https://gitee.com/weiqifa/gpio_key/blob/master/gpio_keys.c驅(qū)動(dòng)代碼流程,從probe處開始
剛開始的時(shí)候,我連dts文件都不會(huì)寫,因?yàn)橹皼]有接觸過這個(gè)驅(qū)動(dòng)。然后看了gpio_keys_get_devtree_pdata函數(shù),之后又看了內(nèi)核代碼下其他項(xiàng)目其他平臺(tái)的dts文件,才知道怎么寫這個(gè)驅(qū)動(dòng)的dts文件。
實(shí)話說,這個(gè)驅(qū)動(dòng)完成了很多我們需要的功能,比如防抖,比如中斷,比如按鍵label等等。
3.1 gpio_keys_get_devtree_pdata 函數(shù)解析dts文件
這個(gè)文件解析的dts 有兩種方式,一種是直接傳入irq的,一種是只傳入gpio口的。
我們的這個(gè)項(xiàng)目,就只傳入了gpio口。
3.2 gpio_keys_setup_key 函數(shù)
這個(gè)函數(shù)用來設(shè)置gpio口的中斷的,直接看代碼會(huì)比較清楚。
下面這個(gè)函數(shù),我還沒有想清楚它的作用,看了回調(diào)函數(shù)里面的實(shí)現(xiàn),是為了把開啟的工作隊(duì)列停止掉。但是我加了打印并沒有打印,我猜測(cè)是為了防止誤觸發(fā),就是按鍵按下的時(shí)間非常短的時(shí)候,才會(huì)調(diào)用這個(gè)。
/***?devm_add_action()?-?add?a?custom?action?to?list?of?managed?resources*?@dev:?Device?that?owns?the?action*?@action:?Function?that?should?be?called*?@data:?Pointer?to?data?passed?to?@action?implementation**?This?adds?a?custom?action?to?the?list?of?managed?resources?so?that*?it?gets?executed?as?part?of?standard?resource?unwinding.*/ int?devm_add_action(struct?device?*dev,?void?(*action)(void?*),?void?*data) {struct?action_devres?*devres;devres?=?devres_alloc(devm_action_release,sizeof(struct?action_devres),?GFP_KERNEL);if?(!devres)return?-ENOMEM;devres->data?=?data;devres->action?=?action;devres_add(dev,?devres);return?0; }3.3 驅(qū)動(dòng)修改
驅(qū)動(dòng)修改的代碼如下
---?a/kernel-4.4/drivers/input/keyboard/gpio_keys.c +++?b/kernel-4.4/drivers/input/keyboard/gpio_keys.c @@?-32,6?+32,11?@@#include?<linux/of_irq.h>#include?<linux/spinlock.h>+ +#define?LOG_TAG?"[BUTTON]:?%s()?line:?%d?" +#define?PRINTK_T(fmt,?args...)??printk(KERN_INFO?LOG_TAG?fmt,?__FUNCTION__,?__LINE__,??##args) + +struct?gpio_button_data?{const?struct?gpio_keys_button?*button;struct?input_dev?*input; @@?-462,9?+467,8?@@?static?int?gpio_keys_setup_key(struct?platform_device?*pdev,spin_lock_init(&bdata->lock);if?(gpio_is_valid(button->gpio))?{ - -???????????????error?=?devm_gpio_request_one(&pdev->dev,?button->gpio, -?????????????????????????????????????????????GPIOF_IN,?desc); +???????????????PRINTK_T("gpio:%d\n",button->gpio); +???????????????error?=?devm_gpio_request(&pdev->dev,?button->gpio,desc);if?(error?<?0)?{dev_err(dev,?"Failed?to?request?GPIO?%d,?error?%d\n",button->gpio,?error); @@?-483,7?+487,9?@@?static?int?gpio_keys_setup_key(struct?platform_device?*pdev,if?(button->irq)?{bdata->irq?=?button->irq;}?else?{ +???????????????????????gpio_direction_input(button->gpio);irq?=?gpio_to_irq(button->gpio); +???????????????????????PRINTK_T("===weiqifa===?irq?:%d\n",irq);if?(irq?<?0)?{error?=?irq;dev_err(dev, @@?-540,8?+546,10?@@?static?int?gpio_keys_setup_key(struct?platform_device?*pdev,if?(!button->can_disable)irqflags?|=?IRQF_SHARED;-???????error?=?devm_request_any_context_irq(&pdev->dev,?bdata->irq, -????????????????????????????????????????????isr,?irqflags,?desc,?bdata); +???????PRINTK_T("===weiqifa===?devm_request_threaded_irq()\n"); + +???????error?=?devm_request_threaded_irq(&pdev->dev,?bdata->irq,NULL, +????????????????????????????????????????????isr,?irqflags|?IRQF_ONESHOT,?desc,?bdata);if?(error?<?0)?{dev_err(dev,?"Unable?to?claim?irq?%d;?error?%d\n",bdata->irq,?error); @@?-709,6?+717,8?@@?static?int?gpio_keys_probe(struct?platform_device?*pdev)int?i,?error;int?wakeup?=?0;+???????PRINTK_T("start.\n"); +if?(!pdata)?{pdata?=?gpio_keys_get_devtree_pdata(dev);if?(IS_ERR(pdata)) @@?-779,6?+789,8?@@?static?int?gpio_keys_probe(struct?platform_device?*pdev)device_init_wakeup(&pdev->dev,?wakeup);+???????PRINTK_T("end.\n"); +return?0;err_remove_group:可以確定的是,如果不修改的話,肯定是會(huì)出錯(cuò)的。
你要知道,這個(gè)驅(qū)動(dòng)是在2005年就完成編寫了,中間經(jīng)過了多少次的系統(tǒng)升級(jí),而且很多廠商主推的還是ADC按鍵驅(qū)動(dòng),GPIO口驅(qū)動(dòng)默認(rèn)情況下是會(huì)被拋棄的,廠商釋放的SDK根本就不會(huì)記得修改這個(gè)驅(qū)動(dòng)代碼,所以別以為你的手機(jī)運(yùn)行正常里面就沒有bug,bug無處不在,只是我們有了重啟大法而已。
4. dts 代碼
gpio-keys?{compatible?=?"gpio-keys";#address-cells?=?<1>;#size-cells?=?<0>;autorepeat;//pinctrl-names?=?"default";//pinctrl-0?=?<&pwrbtn>;button@0?{gpios?=?<&pio?49?IRQ_TYPE_EDGE_BOTH>;linux,code?=?<KEY_F13>;label?=?"GPIO?F13?Power";linux,input-type?=?<1>;gpio-key,wakeup?=?<1>;debounce-interval?=?<100>;};button@1?{gpios?=?<&pio?48?IRQ_TYPE_EDGE_BOTH>;linux,code?=?<KEY_F14>;label?=?"GPIO?F14?Power";linux,input-type?=?<1>;gpio-key,wakeup?=?<1>;debounce-interval?=?<100>;};button@2?{gpios?=?<&pio?51?IRQ_TYPE_EDGE_BOTH>;linux,code?=?<KEY_F15>;label?=?"GPIO?F15?Power";linux,input-type?=?<1>;gpio-key,wakeup?=?<1>;debounce-interval?=?<100>;};};5. 測(cè)試驅(qū)動(dòng)
燒錄后按下按鍵,可以看到鍵值上報(bào).
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識(shí)小密圈
關(guān)注公眾號(hào),后臺(tái)回復(fù)「1024」獲取學(xué)習(xí)資料網(wǎng)盤鏈接。
歡迎點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā),在看,您的每一次鼓勵(lì),我都將銘記于心~
嵌入式Linux
微信掃描二維碼,關(guān)注我的公眾號(hào)
總結(jié)
以上是生活随笔為你收集整理的linux下被遗忘的gpio_keys按键驱动的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL2005数据库可疑的解决方法
- 下一篇: 雷神笔记本关闭跳出垃圾游戏广告