Linux下被遗忘的gpio_keys按键驱动

系统 Linux
我们新项目硬件设计上使用gpio口做按键,所以我就需要搞定这个驱动,本来想自己写一个gpio口的按键驱动,然后看了下内核下面的代码,已经有现成的了。

 [[406543]]

我们新项目硬件设计上使用gpio口做按键,所以我就需要搞定这个驱动,本来想自己写一个gpio口的按键驱动,然后看了下内核下面的代码,已经有现成的了。Linux内核下游很多很多的现成驱动,只要你想得到的,基本都是有现成的,当然了,不包括一些非正常的需求性问题,学会在Linux下找驱动,看驱动和内核代码,我觉得是一件享受和快乐的事情。

不过我还是在使用这个驱动上遇到了问题。

1. 先说ADC 按键

之前的文章有写过adc按键的实现,无非就是为了省点GPIO口。

RK 利用SARADC 来做多个按键

2. GPIO 按键硬件原理图

3. 驱动代码

  1. kernel-4.4/drivers/input/keyboard/gpio_keys.c 

完整代码可查看 

  1. https://gitee.com/weiqifa/gpio_key/blob/master/gpio_keys.c 

驱动代码流程,从probe处开始

刚开始的时候,我连dts文件都不会写,因为之前没有接触过这个驱动。然后看了gpio_keys_get_devtree_pdata函数,之后又看了内核代码下其他项目其他平台的dts文件,才知道怎么写这个驱动的dts文件。

实话说,这个驱动完成了很多我们需要的功能,比如防抖,比如中断,比如按键label等等。

3.1 gpio_keys_get_devtree_pdata 函数解析dts文件

这个文件解析的dts 有两种方式,一种是直接传入irq的,一种是只传入gpio口的。

我们的这个项目,就只传入了gpio口。

3.2 gpio_keys_setup_key 函数

这个函数用来设置gpio口的中断的,直接看代码会比较清楚。

下面这个函数,我还没有想清楚它的作用,看了回调函数里面的实现,是为了把开启的工作队列停止掉。但是我加了打印并没有打印,我猜测是为了防止误触发,就是按键按下的时间非常短的时候,才会调用这个。 

  1. /**  
  2.  * devm_add_action() - add a custom action to list of managed resources  
  3.  * @dev: Device that owns the action  
  4.  * @action: Function that should be called  
  5.  * @data: Pointer to data passed to @action implementation  
  6.  *  
  7.  * This adds a custom action to the list of managed resources so that  
  8.  * it gets executed as part of standard resource unwinding.  
  9.  */  
  10. int devm_add_action(struct device *dev, void (*action)(void *), void *data)  
  11.  
  12.  struct action_devres *devres;  
  13.  devres = devres_alloc(devm_action_release,  
  14.          sizeof(struct action_devres), GFP_KERNEL);  
  15.  if (!devres)  
  16.   return -ENOMEM; 
  17.  devres->datadata = data;  
  18.  devres->actionaction = action;  
  19.  devres_add(dev, devres);  
  20.  return 0;  

3.3 驱动修改

驱动修改的代码如下 

  1. --- a/kernel-4.4/drivers/input/keyboard/gpio_keys.c  
  2. +++ b/kernel-4.4/drivers/input/keyboard/gpio_keys.c  
  3. @@ -32,6 +32,11 @@  
  4.  #include <linux/of_irq.h>  
  5.  #include <linux/spinlock.h>  
  6.  
  7. +#define LOG_TAG "[BUTTON]: %s() line: %d "  
  8. +#define PRINTK_T(fmt, args...)  printk(KERN_INFO LOG_TAG fmt, __FUNCTION__, __LINE__,  ##args)  
  9.  
  10.  
  11.  struct gpio_button_data {  
  12.         const struct gpio_keys_button *button;  
  13.         struct input_dev *input;  
  14. @@ -462,9 +467,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  
  15.         spin_lock_init(&bdata->lock);  
  16.         if (gpio_is_valid(button->gpio)) {  
  17.  
  18. -               error = devm_gpio_request_one(&pdev->dev, button->gpio,  
  19. -                                             GPIOF_IN, desc);  
  20. +               PRINTK_T("gpio:%d\n",button->gpio);  
  21. +               error = devm_gpio_request(&pdev->dev, button->gpio,desc);  
  22.                 if (error < 0) {  
  23.                         dev_err(dev, "Failed to request GPIO %d, error %d\n",  
  24.                                 button->gpio, error);  
  25. @@ -483,7 +487,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  
  26.                 if (button->irq) {  
  27.                         bdata->irq = button->irq;  
  28.                 } else {  
  29. +                       gpio_direction_input(button->gpio);  
  30.                         irq = gpio_to_irq(button->gpio);  
  31. +                       PRINTK_T("===weiqifa=== irq :%d\n",irq);  
  32.                         if (irq < 0) {  
  33.                                 error = irq 
  34.                                 dev_err(dev,  
  35. @@ -540,8 +546,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,  
  36.         if (!button->can_disable)  
  37.                 irqflags |= IRQF_SHARED;  
  38. -       error = devm_request_any_context_irq(&pdev->dev, bdata->irq,  
  39. -                                            isr, irqflags, desc, bdata);  
  40. +       PRINTK_T("===weiqifa=== devm_request_threaded_irq()\n");  
  41. +       error = devm_request_threaded_irq(&pdev->dev, bdata->irq,NULL,  
  42. +                                            isr, irqflags| IRQF_ONESHOT, desc, bdata);  
  43.         if (error < 0) {  
  44.                 dev_err(dev, "Unable to claim irq %d; error %d\n",  
  45.                         bdata->irq, error);  
  46. @@ -709,6 +717,8 @@ static int gpio_keys_probe(struct platform_device *pdev)  
  47.         int i, error;  
  48.         int wakeup = 0  
  49. +       PRINTK_T("start.\n"); 
  50.  
  51.         if (!pdata) {  
  52.                 pdata = gpio_keys_get_devtree_pdata(dev);  
  53.                 if (IS_ERR(pdata))  
  54. @@ -779,6 +789,8 @@ static int gpio_keys_probe(struct platform_device *pdev)  
  55.         device_init_wakeup(&pdev->dev, wakeup);  
  56. +       PRINTK_T("end.\n"); 
  57.  
  58.         return 0;  
  59.  err_remove_group: 

可以确定的是,如果不修改的话,肯定是会出错的。

你要知道,这个驱动是在2005年就完成编写了,中间经过了多少次的系统升级,而且很多厂商主推的还是ADC按键驱动,GPIO口驱动默认情况下是会被抛弃的,厂商释放的SDK根本就不会记得修改这个驱动代码,所以别以为你的手机运行正常里面就没有bug,bug无处不在,只是我们有了重启大法而已。

4. dts 代码 

  1. gpio-keys {  
  2.    compatible = "gpio-keys" 
  3.    #address-cells = <1> 
  4.    #size-cells = <0> 
  5.    autorepeat; 
  6.     //pinctrl-names = "default" 
  7.    //pinctrl-0 = <&pwrbtn> 
  8.    button@0 {  
  9.      gpios = <&pio 49 IRQ_TYPE_EDGE_BOTH> 
  10.      linux,code = <KEY_F13> 
  11.      label = "GPIO F13 Power" 
  12.      linux,input-type = <1> 
  13.      gpio-key,wakeup = <1> 
  14.      debounce-interval = <100> 
  15.    };  
  16.    button@1 {  
  17.      gpios = <&pio 48 IRQ_TYPE_EDGE_BOTH> 
  18.      linux,code = <KEY_F14> 
  19.      label = "GPIO F14 Power" 
  20.      linux,input-type = <1> 
  21.      gpio-key,wakeup = <1> 
  22.      debounce-interval = <100> 
  23.    };  
  24.    button@2 {  
  25.      gpios = <&pio 51 IRQ_TYPE_EDGE_BOTH> 
  26.      linux,code = <KEY_F15> 
  27.      label = "GPIO F15 Power" 
  28.      linux,input-type = <1> 
  29.      gpio-key,wakeup = <1> 
  30.      debounce-interval = <100> 
  31.    };  
  32.  }; 

5. 测试驱动

烧录后按下按键,可以看到键值上报.

 

 

责任编辑:庞桂玉 来源: 良许Linux
相关推荐

2021-11-29 07:55:45

Linux GPIO Linux 系统

2022-04-22 11:16:35

Linux工具命令

2024-03-27 13:03:27

AI技术论坛

2009-08-12 09:02:52

Linux未来LinuxWindows

2009-09-03 09:08:08

Linuxroot密码遗忘

2020-07-20 11:23:24

信息安全个人信息数据安全

2014-10-28 10:53:39

UNIX

2020-10-14 09:41:02

Hi3861GPIO点灯

2022-05-17 14:17:50

物理安全网络攻击网络安全

2017-11-21 09:10:54

Linux命令行技巧

2022-08-22 07:08:12

敏捷开发软件

2020-11-02 12:07:11

鸿蒙 GPIO

2011-01-05 13:00:19

2011-01-06 16:29:08

linuxtasklet机制

2021-03-05 11:52:50

LinuxSPI驱动详解

2009-04-24 10:57:25

2012-06-27 09:43:59

Win RTWin NT

2023-07-10 09:52:51

机器谷歌

2020-10-28 10:03:43

Hi3861 GPIO点灯按键

2020-04-09 11:03:29

ClouderaHadoopCDP
点赞
收藏

51CTO技术栈公众号