linux下被遗忘的gpio_keys按键驱动

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

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

1. 先说ADC 按键

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

RK 利用SARADC 来做多个按键

2. GPIO 按键硬件原理图

3. 驱动代码

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

完整代码可查看

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口的中断的,直接看代码会比较清楚。

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

/*** 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 驱动修改

驱动修改的代码如下

--- 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:

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

你要知道,这个驱动是在2005年就完成编写了,中间经过了多少次的系统升级,而且很多厂商主推的还是ADC按键驱动,GPIO口驱动默认情况下是会被抛弃的,厂商释放的SDK根本就不会记得修改这个驱动代码,所以别以为你的手机运行正常里面就没有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. 测试驱动

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


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

嵌入式Linux

微信扫描二维码,关注我的公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465854.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何通过审计安全事件日志检测密码喷洒(Password Spraying)攻击

许多渗透测试人员和攻击者通常都会使用一种被称为“密码喷洒&#xff08;Password Spraying&#xff09;”的技术来进行测试和攻击。对密码进行喷洒式的攻击&#xff0c;这个叫法很形象&#xff0c;因为它属于自动化密码猜测的一种。这种针对所有用户的自动密码猜测通常是为了避…

每日一题(39)—— sizeof

以下代码中的两个sizeof用法有问题吗&#xff1f; void UpperCase(char str[]) {for(size_t i 0; i < sizeof(str)/sizeof(str[0]); i){str[i] - (a - A);} }char str[] "aBcDe"; cout << "str字符长度为: " << sizeof(str)/sizeof(str[…

IT综合管理 新时期的运维管理思路

IT运维管理给企业带来效益已经有十余载的历史&#xff0c;IT部门也逐步成为为企业的重要支撑部门&#xff0c;通过IT部门管理好企业的网络、桌面、业务、机房环境以及其他IT资源。虽然IT运维管理已经给企业带来了节能增效的实际效益&#xff0c;但这些效益正增着IT规模的与日俱…

单片机编程技巧—状态机编程

摘要&#xff1a;不知道大家有没有这样一种感觉&#xff0c;就是感觉自己玩单片机还可以&#xff0c;各个功能模块也都会驱动&#xff0c;但是如果让你完整的写一套代码&#xff0c;却无逻辑与框架可言&#xff0c;上来就是开始写&#xff01;东抄抄写抄抄。说明编程还处于比较…

啥叫旁路电容?啥叫去耦?可以不再争论了吗

1. 旁路和去耦先谈两个比较重要的概念&#xff1a;旁路电容(Bypass Capacitor)&#xff0c;去耦电容(Decoupling Capacitor)。只要是设计过硬件电路的同学肯定对这两个词不陌生&#xff0c;但真正理解这两个概念的可能并不多。我刚毕业时就问过我的师傅&#xff0c;为什么总是在…

H5活动产品设计指南基础版

本文来自 网易云社区 。 H5一般页面不会很多&#xff0c;看似简单&#xff0c;实际上会有很多细节需要注意&#xff0c;我自己在做过了几个H5之后&#xff0c;发现了一些常犯的问题&#xff0c;做了小结&#xff0c;希望给新开始做H5的产品相关的同学提供一些帮助。 首先说说一…

每日一题(40)—— 字符串常量

下列代码有什么问题&#xff1f; char* s"AAA"; printf("%s",s); s[0]B; printf("%s",s);"AAA"是字符串常量。s是指针&#xff0c;指向这个字符串常量&#xff0c;所以声明s的时候就有问题。 cosntchar* s"AAA"; 然后又因…

下一个天亮

下一个天亮&#xff0c;我们依然是最好的搭档。最初的梦想&#xff0c;永远也从来不曾放弃。谢谢你教会我成长&#xff0c;谢谢你给我的一切。我们要永远这么好下去。加油哦。原来有些话真的只适合烂在心底。我能选择的&#xff0c;从始至终的唯一选择&#xff0c;只有坚强&…

图解丨在嵌入式设备上实现HTTP服务器

您好呀&#xff0c;我是小二。本期为大家带来一个 WiFi 应用的实际场景&#xff0c;其实在之前「我对 WiFi 驱动移植过程&#xff0c;做了一次总结复盘」这篇文章中有简单提过&#xff0c;但由于内容较多&#xff0c;就单独摘出来了。来自读者的催更????????????&a…

maven详解之仓库

在Maven中&#xff0c;任何一个依赖、插件或者项目构建的输出&#xff0c;都可以称之为构件。 Maven在某个统一的位置存储所有项目的共享的构件&#xff0c;这个统一的位置&#xff0c;我们就称之为仓库。&#xff08;仓库就是存放依赖和插件的地方&#xff09; 任何的构件都有…

Linux内核代码,第一次看到这样使用的宏

晚上看内核代码&#xff0c;看到一个有意思的宏&#xff0c;我之前没有见到过&#xff0c;当然&#xff0c;肯定有人见到过&#xff0c;我写出来是给那些没有看到过的人看的。我说是深夜&#xff0c;那就肯定是深夜代码是从内核里面看到的我们正常使用宏是这样的C语言、嵌入式中…

学习笔记三

三、信息安全风险管理的风险评估<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />1、风险评估概述A、风险评估的概念风险评估是信息安全风险管理的第二步&#xff0c;针对确立的风险管理对象所面临的风险进行识别、分析和评价。请…

每日一题(41)—— 数组和链表的区别

数组和链表的区别&#xff1a; 数组&#xff1a;数据顺序存储&#xff0c;固定大小 连表&#xff1a;数据可以随机存储&#xff0c;大小可动态改变

flex柱状图和折线图的混合图使用

<?xml version"1.0"?> <mx:Application xmlns:mx"http://www.adobe.com/2006/mxml"> <mx:Script> <!--[CDATA[ import mx.collections.ArrayCollection; [Bindable] public var data1:ArrayCollectionnew ArrayCollection([{date:&…

给高通提个问题解决为啥那么久?

我第一次接触高通芯片是在中兴那&#xff0c;我们用的是一款很老的芯片&#xff0c;高通的文档非常多&#xff0c;资料非常丰富&#xff0c;如果有问题的话我一般都会从文档里面找答案。但是&#xff0c;但是&#xff0c;并不是所有的问题都是能自己搞定&#xff0c;比如遇到一…

BZOJ4503 两个串 【fft】

题目链接 BZOJ4503 题解 水水题。 和残缺的字符串那题几乎是一样的 同样转化为多项式 同样TLE 同样要手写一下复数才A #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<complex> #include<cmath> #i…

每日一题(42)—— 已知一个数组table,用一个宏定义,求出数据的元素个数

已知一个数组table&#xff0c;用一个宏定义&#xff0c;求出数据的元素个数。 // 总大小除以第一个元素的大小 #define TNTBL (sizeof(table)/sizeof(table[0]))

新公司上班第一天

大家好&#xff0c;文章转自我的朋友helloworld&#xff0c;文中的我并不是我&#xff0c;感谢大家阅读&#xff0c;转载&#xff0c;在看。Hello 各位小伙伴&#xff0c;周一愉快~今天是我到新公司上班的第一天&#xff0c;入职新公司&#xff0c;就好像刚刚谈恋爱一样&#x…

[CTO札记]从Cloud Computing看战略决策:想做、能做与可做 -

1&#xff09;想做--未来方向很多人已经意识到&#xff0c;Cloud Computing未来将是基础设施&#xff0c;扮演水、电、气的角色。可以说&#xff0c;Cloud Computing是很多互联网、电信大公司想做的事。因为&#xff1a;》不仅重要&#xff08;大公司都不想自己的命运掌握在别人…

JAVA基础学习之路(三)类定义及构造方法

类的定义及使用 一&#xff0c;类的定义 class Book {//定义一个类int price;//定义一个属性int num;public static int getMonney(int price, int num) {//定义一个方法return price*num;} }public class test2 {public static void main(String args[]) {Book monney new B…