回答

收藏

[评测分享] 【ALINX AXU2CGB试用】GPIO 按键视频 + linux 驱动源码分析

#板卡评测 #板卡评测 4809 人阅读 | 0 人回复 | 2021-05-26

本帖最后由 robe.zhang 于 2021-5-29 14:28 编辑

【ALINXAXU2CGB试用】GPIO 按键视频 + linux 驱动源码分析

以下是笔者最终的测试电路:包含了以往两篇文章提到的 EMIO GPIO 按键,AXI GPIO按键
key1,key2 用的是 EMIO GPIO 按键
key3,key4 用的是 AXI GPIO 按键

设备树也做了调整,包含了以往两篇文章提到的三种GPIO按键配置:
Key1 配置为中断方式 EMIO GPIO按键
Key2 配置为轮询方式 EMIO GPIO按键
Key3,key4 配置为轮询方式AXI GPIO 按键

重新编译后重启生效,运行视频:
https://v.youku.com/v_show/id_XNTE2MTM1NDc0MA==.html
按键1,对应键盘 r 键
按键2,对应键盘 o 键
按键3,对应键盘 t 键
按键4,对应键盘 enter 键
笔者按 1,2,2,3,4,输入ubuntu 用户名:root,并回车
再次按 1,2,2,3,4,输入ubuntu 密码:root,并回车
正常登录进系统了。
按键支持 repeat,按住按键不送,会重复输入键值

Linux 源码分析:
驱动代码位于内核 drivers\input 目录中:
核心代码位于一下文件中:
input.c                        #input 子系统核心代码
input-compat.c           # 32位兼容代码
input-mt.c                  #多点触控代码
input-poller.c              # 轮询代码
ff-core.c                       #力反馈代码

看 input.c 代码:

这个是 input 子系统核心层,在驱动初始化之前已经运行了。
2491行:注册 input class类


2497行:初始化 proc 文件系统

Input devices 对应的fops

Open 函数,使用了一个 seq_operations,使用序列文件的方法操作文件


Input handlers 对应的fops,也是用序列文件方法操作


以上是文件系统的内容,再具体点是 procfs 文件系统的内容,自己详细了解一下

2501行:注册字符设备,一个循环注册字符设备

注册时候找到 chrdevs 中的第 13项,就是input 系统的对应的字符设备,填充 structchar_device_struct 结构体,保存在 chrdevs 中


Chrdevs 是个机构体数组,第 13项用于 input 子系统,next 成员下保存每一个 input 字符设备指针

从这里能看出来,所有的字符设备,主设备号相同就全部存在于 Chrdevs 的第n项(n是主设备号),不同此设备号的字符设备结构体指针保存在 next 指针中,形成一个链表。
Input 设备注册之前,chrdevs[13]结构体要构建好,以便后续注册 input 设备。此处就是构建chrdev[13] 结构体,此代码先于设备驱动运行。

核心层还提供了一下 API
EXPORT_SYMBOL(input_free_minor);
EXPORT_SYMBOL(input_get_new_minor);        # 申请释放 minor 次设备号
EXPORT_SYMBOL(input_register_handle);
EXPORT_SYMBOL(input_unregister_handle);    # 注册,注销 handle

注册handle结尾,运行handler->start

EXPORT_SYMBOL(input_register_handler);
EXPORT_SYMBOL(input_unregister_handler);          # 注册,注销handler
EXPORT_SYMBOL(input_handler_for_each_handle);

EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device);            # 注册,注销input device


注册input device 函数
2180行,计算 packet 大小
2199,2202 行,设置获取键值,设置键值的函数
2207行,添加 dev 设备
2224行,attach handler
input device 注册函数就这么多内容

EXPORT_SYMBOL(input_enable_softrepeat);            # 使能重复输入

EXPORT_SYMBOL(input_set_capability);           # 设置位
EXPORT_SYMBOL(input_set_timestamp);
EXPORT_SYMBOL(input_set_capability);           # 设置,获取时间戳

EXPORT_SYMBOL(devm_input_allocate_device);
EXPORT_SYMBOL(input_free_device);              # 分配释放input_dev 结构体

devm_input_device_match 函数好简单,直接比较两个指针是不是相等

分配 input device,dev类是刚才的 input_class,类型是

EXPORT_SYMBOL(input_open_device);
EXPORT_SYMBOL(input_close_device);
EXPORT_SYMBOL(input_flush_device);             # 打开,关闭,冲刷input_device
有 open 运行 open函数,有 poller运行 poller并开启轮询工作队列


Close ,flush 更简单


EXPORT_SYMBOL(input_release_device);          # 释放 input_device
EXPORT_SYMBOL(input_grab_device);
EXPORT_SYMBOL(input_set_abs_params);
EXPORT_SYMBOL(input_alloc_absinfo);            # abs 设备的设置,比如触控板等

EXPORT_SYMBOL(input_inject_event);
EXPORT_SYMBOL(input_event);                # 发送事件
两个发送事件函数都调用了 input_handle_event


添加时间戳,调用 input_pass_values 发送

调用 input_to_handler

看 drivers\input\evdev.c 中的events 函数的实现



最终是传递事件,发送信号,唤醒进程去处理的。异步处理

核心层也实现了 autorepeat,使用时钟实现的

input_register_device 函数中 2196行,input_enable_softrepeat 初始化的


上报事件,设置定时器,过一会继续上报事件,实现 softrepeat

核心层就这么多,类似一个库,做了一些 input 基础的初始化,提供了一些接口给其他驱动调用

看gpio-keys驱动,这个是中断方式的gpio-keys驱动 :驱动代码位于 drivers\input\keyboard\gpio_keys.c文件中

774 行:如果 pdata 不存在就去解析设备树
780行,分配 ddata
787行,分配 keymap
793行,分配 input dev,下面是初始化input
825 行,是个循环,设置 gpio 按键,主要是分析子节点,设置gpio,中断,delay work
851行,注册 input dev
858行,休眠唤醒初始化






按键工作在中断模式,来了中断就上报事件,延迟一会就释放按键,释放也会上报

还有一个轮询模式的Gpio 按键驱动:代码位于drivers\input\keyboard\gpio_keys_polled.c 文件中




代码基本类似,360行,input_register_polled_device注册 polled_device 函数中 307 初始化 delay work 为 input_polled_device_work

input_polled_device_work 调用了 dev->poll后继续加入工作队列,继续轮询

dev->poll 在驱动 probe时候被初始化为 gpio_keys_polled_poll,

gpio_keys_polled_poll 的功能就是轮询所有按键,上报事件

轮询方式的 gpio 驱动工作方式就是轮训一编所有按键,加入工作队列,延迟一会,再次轮询再次延迟,不停循环

input_register_polled_device 函数第 314行,input_open_polled_device

一旦打开设备,就开始上报事件,加入工作队列,开始轮询了

关闭设备,就取消工作队列,不再轮询

按键驱动,核心是input子系统,也涉及到了gpio,中断,timer,work,文件系统等等,看驱动需要点内核基础,操作系统基础,需要一定的内核代码阅读量,内核各种api都要混个脸熟,需要一定的积累,需要分析大的框架和项目代码的能力,要求还是挺高的
有人总想投机,手把手教,包教包会,不存在的,没有速成法哈。驱动是内核级别的编程,在子系统框架下编程,学内核学框架就会了。Input 子系统看懂,是用好 gpio 按键驱动的基本功之一。


分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条