1.概述

Gpio-keys 是基于input子系统实现的一个通用按键驱动,该驱动也符合linux驱动实现模型,即driver和device分离模型.一般按键驱动,都是基于gpio-keys进行开发的.

2. gpio-keys 代码分析(基于 linux 4.14.40)

(1)整体来说分为以下四步

static int gpio_keys_probe(struct platform_device *pdev)

{

...........

...........

/*第一,从设备树获取button,即gpio相关控制方式和属性*/

pdata = gpio_keys_get_devtree_pdata(dev);

...........

...........

/*第二,分配一个input 设备*/

input = devm_input_allocate_device(dev);

...........

...........

/*第三,注册gpio相关信息和分配资源*/

for (i = 0; i < pdata->nbuttons; i++) {

error = gpio_keys_setup_key(pdev, input, ddata,

button, i, child);

...........

...........

/*第四,注册input 设备到kernel*/

error = input_register_device(input);

...........

...........

return 0;

}

(2)从注册一个input设备来看,二,四步是一个通用的步骤,第三步和第一步是关键,先看第三步.

static int gpio_keys_setup_key(struct platform_device *pdev,

struct input_dev *input,

struct gpio_keys_drvdata *ddata,

const struct gpio_keys_button *button,

int idx,

struct fwnode_handle *child)

{

.............

.............

/*第一,请求gpio并获取irq 资源*/

error = devm_gpio_request_one(dev, button->gpio, flags, desc);

irq = gpiod_to_irq(bdata->gpiod);

.............

.............

/*第二,注册一个delayed work任务,这个任务的目的,当中断发生时,需要向

通过input子系统发消息,这个过程有可能会sleep或者schedule,所以必须通一个

delay work去完成这件事.

*/

INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);

isr = gpio_keys_gpio_isr;

irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;}

.............

.............

/*第三,注册中断*/

error = devm_request_any_context_irq(dev, bdata->irq, isr, irqflags,

desc, bdata);

return 0;

}

(3)下面来看中断和delay work做了什么事

static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)

{

struct gpio_button_data *bdata = dev_id;

...............

...............

/*中断中,唯一做的事,就是把delay work加入到了system_wq队列中去.还做了一个延迟

这个延迟目的是为了去抖动.*/

mod_delayed_work(system_wq,

&bdata->work,

msecs_to_jiffies(bdata->software_debounce));

return IRQ_HANDLED;

}

static void gpio_keys_gpio_work_func(struct work_struct *work)

{

/*调用上报消息,接着向下看*/

...........

gpio_keys_gpio_report_event(bdata);

...........

}

static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)

{

............

/*第一步,获取gpio 状态.*/

state = gpiod_get_value_cansleep(bdata->gpiod);

............

/*发送消息到input*/

input_event(input, type, *bdata->code, state);

input_sync(input);

............

}

(4)下面请看第一步工作,以及设备树的配置

(红色为必要部分)

label : 一个key 的别名

linux,code :  键值,作为按键的唯一识别号

linux,input-type: input类型(EV_KEY(按键), EV_ABS(相对坐标), EV_REL(绝对坐标)...) 默认为EV_KEY

wakeup-source: 与pm相关,默认为disable

linux,can-disable:是否共享中断line ((默认)0:shared, 1: not shared)

debounce-interval : 去抖延时

gpios :  gpio 的相关信息

/*用于gpio资源的申请及初始化,可列举很多*/

gpio_keys_pins_default: gpio_keys_pins_default {

pinctrl-single,pins = <

AM4372_IOPAD(0x9a0, PIN_INPUT | MUX_MODE9) /* (L23) mcasp0_aclkr.gpio0[18] */

>;

};

/*创建gpio-keys 设备描述*/

gpio_keys: gpio_keys {

compatible = "gpio-keys";

pinctrl-names = "default";

pinctrl-0 = ;

#address-cells = <1>;

#size-cells = <0>;

/*添加一个button, 用于做系统reset*/

button0 {

label = "reset";

linux,code = <0x198>; /*KEY_RESTART*/

gpios = ;

};

};

3. 内核模块选择配置

| with configuration data saying which GPIOs are used. |

| |

| To compile this driver as a module, choose M here: the |

| module will be called gpio_keys. |

| |

| Symbol: KEYBOARD_GPIO [=y] |

| Type : tristate |

| Prompt: GPIO Buttons |

| Location: |

| -> Device Drivers |

| -> Input device support |

| -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y]) |

| -> Keyboards (INPUT_KEYBOARD [=y]) |

| Defined at drivers/input/keyboard/Kconfig:214 |

| Depends on: !UML && INPUT [=y] && INPUT_KEYBOARD [=y] && (GPIOLIB [=y] || COMPILE_TEST [=n])

4. cat /proc/bus/input/devices

通过这个可以看到接到input事件的handler是哪一个

$: cat /proc/bus/input/devices

I: Bus=0019 Vendor=0001 Product=0001 Version=0100

N: Name="gpio_keys"

P: Phys=gpio-keys/input0

S: Sysfs=/devices/platform/gpio_keys/input/input0

U: Uniq=

H: Handlers=event0

B: PROP=0

B: EV=3

B: KEY=1000000 0 0 0 0 0 0 0 0 0 0 0 0

/下面的信息有助于你编写udev rules

$:udevadm info -a -p /sys//devices/platform/gpio_keys/input/input0

looking at device '/devices/platform/gpio_keys/input/input0':

KERNEL=="input0"

SUBSYSTEM=="input"

DRIVER==""

ATTR{name}=="gpio_keys"

ATTR{phys}=="gpio-keys/input0"

ATTR{properties}=="0"

ATTR{uniq}==""

looking at parent device '/devices/platform/gpio_keys':

KERNELS=="gpio_keys"

SUBSYSTEMS=="platform"

DRIVERS=="gpio-keys"

ATTRS{disabled_keys}==""

ATTRS{disabled_switches}==""

ATTRS{driver_override}=="(null)"

ATTRS{keys}=="408"

ATTRS{switches}==""

looking at parent device '/devices/platform':

KERNELS=="platform"

SUBSYSTEMS==""

DRIVERS==""

4.如何接收按键消息,以下例程供参考

#include #include #include #include #include #include #include #include #include #define KEY_DEVICE_FILE "/dev/input/event0"

struct input_event {

struct timeval time;

unsigned short type;

unsigned short code;

int value;

};

int main()

{

int fd_key = -1;

struct input_event key_evt;

int ret = 0;

fd_key= open(KEY_DEVICE_FILE, O_RDONLY);

if(fd_key< 0) {

return fd_key;

}

monitor_key:

ret = read(fd_key, (char*)&key_evt, sizeof(struct input_event));

if(ret < 0)

{

printf("read key event failed:%d\n", ret);

}else{

if(key_evt.code == 408 && key_evt.value == 1)

{

printf("The press of reset button is detected\n");

return 0;

}

#if 0

printf("%lld seconds %ld microseconds", key_evt.time.tv_sec,

key_evt.time.tv_usec);

printf("type:%d code:%d value:%d\n", key_evt.type, key_evt.code, key_evt.value);

#endif

}

goto monitor_key;

return 0;

}

linux按键驱动中的结构体,linux 驱动之input子系统(gpio-keys)实现相关推荐

  1. 获取另一个驱动的设备结构体_Linux 驱动开发 / 设备模型快速入门

    背 景 Read the fucking source code!  --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版 ...

  2. linux 中 timeval结构体 - Neddy11 - 博客园

    linux 中 timeval结构体 - Neddy11 - 博客园 linux 中 timeval结构体 网上很多人写到,timeval结构解释错误 ************************ ...

  3. Linux结构体变量报错,C语言中的结构体

    用户自己建立自己的结构体类型 1.  定义和使用结构体变量 (1).结构体的定义 C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体. (2).声明一个结构体类型的一般形式为: ...

  4. Linux进程中task_struct结构体

    一.进程的定义: ①正在执行的程序: ②正在计算机上执行的实例: ③能分配给处理器并由处理器可以执行的实体. ④具有以下特征的活动单元: 一组指令序列的执行.一个当前状态和相关的系统资源. 进程的两个 ...

  5. linux windows 结构体,Linux下C语言——结构体对齐

    结构体对齐的步骤: 1.结构体各成员对齐 2.整个结构体圆整 结构体对齐的特定对齐值: 1.自身对齐值: 自身对齐值就是结构体变量里每个成员的自身大小; 2.指定对齐值: 指定对齐值是由宏#pragm ...

  6. Linux学习-文件IOA1——用结构体和文件操作函数实现文件的拷贝

    Linux学习-文件IOA1--用结构体和文件操作函数实现文件的拷贝 其实我们不必选用结构体去实现模仿拷贝功能的,但是为了锻炼我们的思维以及对结构体.文件操作函数的使用,所以我们就这样来折腾自己. 学 ...

  7. 获取另一个驱动的设备结构体_《rt-thread驱动框架分析》-i2c驱动

    驱动分析 I2C设备驱动框架图: 我们先RT-Thread的I2C框架图(这是我自己理解的框架图,如果不对的地方,请指出): 上图是我分析的RTT的I2C框架图.主要分为三层,驱动层-核心层-设备层. ...

  8. step2 . day5 C语言中的结构体和枚举

    最近几天交叉的学习C和Linux,知识梳理的不是很仔细,有很多还没有搞明白的问题,所有耽误了几天更新笔记,也是在细嚼慢咽中,做了一个规划表,现阶段先把C后面的知识学好,然后再梳理Linux系统相关知识 ...

  9. C语言中的结构体,结构体中数组初始化与赋值

    最近写c语言中的结构体遇到了些问题,从网上找了些资料如下: 结构体是连续存储的,但由于结构体中成员类型各异,所以会存在内存对齐问题,也就是内存里面会有空档,具体的对齐方式这里 暂不讨论: 1.结构体的 ...

最新文章

  1. leetcode--对称二叉树--python
  2. python爬虫的应用-python网络爬虫应用实战
  3. 中文手机评论情感分类系列(一)
  4. 信息学奥赛一本通(1203:扩号匹配问题)
  5. php加密 java rsa_PHP的DES加密和RSA签名(兼容java)
  6. tp5中php正则怎么写,详解tp5中phpmailer的使用
  7. 语句 if else
  8. 从现实抽象出类的步骤
  9. getprop setprop初步探索
  10. zabbix server is not running解决办法
  11. html5数字在线处理,Qunee for HTML5 - 中文 : 事件处理
  12. 发家致富:爬取双色球信息并统计
  13. 谈谈百度竞价的一些思路
  14. 游戏c#脚本语言,C#作为脚本语言执行解密
  15. Android手机app启动的时候第一个Activity必须是MainActivity吗
  16. Git版本控制器(涵盖GitHub\Gitee码云\GitLab),全网最详细教程
  17. 二叉树的深度和平衡二叉树的深度
  18. 夜遇歹人来不及报警怎么办?让求救app帮助你
  19. 干货分享!杭州知名SEO公司清法网络告诉你如何玩转小红书
  20. 高ROE高息选股策略

热门文章

  1. python for CFD(前两步问题总结)
  2. Linux下安装FTP
  3. 负载均衡器上实现客户端IP限制
  4. 5个IO口扫描25个按键的解决方法(转帖)
  5. ad 卡尔曼_对Kalman(卡尔曼)滤波器的理解
  6. 【PM模块】维护业务处理流程—内部维护(通知单)
  7. YaaS,we can!
  8. Sap权限相关设置、控制及传输
  9. IDOC实例,消息方式的IDOC
  10. 望城——民营经济的“旺城”