8、linux下输入子系统
input_sync(button_dev); /*通知接收者,一个报告发送完毕*/
参考:http://www.51hei.com/bbs/dpj-27652-1.html 很详细说明
input.c是输入子系统驱动程序顶层框架文件,是一个通用的文件
在connect函数中
for (minor = 0; minor < EVDEV_MINORS; minor++)
if (!evdev_table[minor])
break;
找一个空的evdev_table用来存放evdev,其中minor就是/dev/input/evnetx访问时的x
drivers/input/input.c:
class_register(&input_class)//创建一个类,作用和class_create等价,class_create内部就是调用class_register来实现的
//device_create是在input_handler的connect函数中通过device_add实现的,因为device_create实际上就是调用device_add
input_init > err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
问:怎么读按键?
input_open_file
struct input_handler *handler = input_table[iminor(inode) >> 5];
new_fops = fops_get(handler->fops) // =>&evdev_fops
file->f_op = new_fops;
err = new_fops->open(inode, file);
app: read > ... > file->f_op->read
input_table数组由谁构造?
input_register_handler //在内核中找该函数被谁调用,可以发现input分为左右两边,一遍调用input_register_handler ,一遍调用input_register_device
调用input_register_handler 的主要有evdev、键盘、鼠标、触摸屏等输入设备,这部分写好了纯软件代码,硬件相关的在input_register_device中,比如触摸屏驱动程序:s3c2410_ts.c
注册input_handler:
input_register_handler
// 放入数组
input_table[handler->minor >> 5] = handler;
// 放入链表
list_add_tail(&handler->node, &input_handler_list);
// 对于每个input_dev,调用input_attach_handler
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev
注册输入设备:
input_register_device
// 放入链表
list_add_tail(&dev->node, &input_dev_list);
// 对于每一个input_handler,都调用input_attach_handler
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev
input_attach_handler
id = input_match_device(handler->id_table, dev);
error = handler->connect(handler, dev, id);
注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,
根据input_handler的id_table判断这个input_handler能否支持这个input_dev,
如果能支持,则调用input_handler的connect函数建立"连接"
怎么建立连接?
1. 分配一个input_handle结构体
2.
input_handle.dev = input_dev; // 指向左边的input_dev
input_handle.handler = input_handler; // 指向右边的input_handler
3. 注册:
input_handler->h_list = &input_handle;
inpu_dev->h_list = &input_handle;
evdev_connect
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); // 分配一个input_handle
// 设置
evdev->handle.dev = dev; // 指向左边的input_dev
evdev->handle.name = evdev->name;
evdev->handle.handler = handler; // 指向右边的input_handler
evdev->handle.private = evdev;
// 注册
error = input_register_handle(&evdev->handle);
怎么读按键?
app: read
--------------------------
.......
evdev_read
// 无数据并且是非阻塞方式打开,则立刻返回
if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
// 否则休眠
retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist);
谁来唤醒?
evdev_event
input_handle_event(dev, type, code, value);
input_pass_event(dev, type, code, value);
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
handler->event(handle, type, code, value);
wake_up_interruptible(&evdev->wait);
evdev_event被谁调用?
猜:应该是硬件相关的代码,input_dev那层调用的
在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数
gpio_keys_isr
// 上报事件
input_event(input, type, button->code, !!state);(上报的时候是从input_handle链表取出handle,在调用handler的event,因此可能有多个支持的handle,在input_pass_event函数中)
input_sync(input);
input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
struct input_handle *handle;
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);//evdev_event
怎么写符合输入子系统框架的驱动程序?
1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如在中断服务程序里上报事件
struct input_dev {
void *private;
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[NBITS(EV_MAX)]; // 表示能产生哪类事件,可以看EV_MAX宏定义处,比如设置了可以参数按键类,然后才设置下面可以产生哪些按键
unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键
unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮
unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];
测试:
1.
hexdump /dev/event1 (open(/dev/event1), read(), )
秒 微秒 类 code value(四字节)
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000(在copy_to_user中拷贝input_event结构体数据)
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000(这是同步类事件,每个事件后都要发同步)
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000
2. 如果没有启动QT:
cat /dev/tty1 (原因是在tty下会包括keyboard.c,其也调用了input_register_handler,因此在注册驱动的时候除了和evdev关联起来,还和keyboard关联起来了,而keyboard.c的上层是tty)
按:s2,s3,s4
就可以得到ls
或者:
exec 0</dev/tty1(0表示标准输入,将标准输入文件改为tty1,即从tty1得到输入,以前0是从sh文件得到输入,sh是从串口得到输入)
然后可以使用按键来输入
(ps指令可以看到-sh程序的PID,在执行ls -l /proc/PID/fd可以看到-sh程序将标准输入、标准输出、标准错误都指向了窗口)
3. 如果已经启动了QT:
可以点开记事本
然后按:s2,s3,s4
如果可以参数重复类事件,input_event会启动定时器(通过input_start_autorepeat函数),调用定时器函数input_repeat_key继续上报时间,定时器在input_register_device中注册
8、linux下输入子系统的更多相关文章
- 12.Linux之输入子系统分析(详解)
版权声明:本文为博主原创文章,转载请标注出处: 在此节之前,我们学的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥/非阻塞.定时 ...
- linux input输入子系统应用分析
输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理是底层在按键.触摸等动作发送时产生一个中断(或驱动通过timer定时查询),然后CPU通过SPI.I2 C或外部存储器总线读取 ...
- linux input输入子系统分析《四》:input子系统整体流程全面分析
1 input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...
- linux内核输入子系统分析
1.为何引入input system? 以前我们写一些输入设备(键盘.鼠标等)的驱动都是采用字符设备.混杂设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可 ...
- Linux/Android——输入子系统input_event传递 (二)【转】
本文转载自:http://blog.csdn.net/jscese/article/details/42099381 在前文Linux/Android——usb触摸屏驱动 - usbtouchscre ...
- Linux下输入某些命令时会提示:bash:command not found
首先,查看$PATH中是否包含了这些命令. $PATH:决定了shell到哪些目录中去寻找命令或程序,PATH值是一系列的目录.当运行程序时,linux到这些目录下搜索进行编译链接. 格式: PATH ...
- Linux下 输入 env 而得到的环境变量解读
HOSTNAME=Master.Hadoop MAHOUT_HOME=/usr/hadoop/mahout-distribution-0.8 TERM=linux SHELL=/bin/bash HA ...
- Linux下clock子系统
常用API: 1.struct clk *clk_get(struct device *dev, const char *id):从一个时钟list链表中以dev或者字符id名称查找一个时钟clk结构 ...
- Linux下触摸屏驱动程序分析
[摘要: 本文以linux3.5--Exynos4412仄台,剖析触摸屏驱动焦点内容.Linux下触摸屏驱动(以ft5x06_ts为例)须要懂得以下学问: 1. I2C协定 2. Exynos4412 ...
随机推荐
- Codefroces Educational Round 26 837 D. Round Subset
D. Round Subset time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...
- userdel---删除用户及相关文件
userdel命令 userdel命令用于删除给定的用户,以及与用户相关的文件.若不加选项,则仅删除用户帐号,而不删除相关文件. 语法 userdel(选项)(参数) 选项 -f:强制删除用户,即 ...
- 洛谷 P1358 扑克牌
P1358 扑克牌 题目描述 组合数学是数学的重要组成部分,是一门研究离散对象的科学,它主要研究满足一定条件的组态(也称组合模型)的存在.计数以及构造等方面的问题.组合数学的主要内容有组合计数.组合设 ...
- 关于我遇到的“LNK 2019无法解析的外部符号”的链接错误
昨天在调试程序的时候出现了"LNK 2019无法解析的外部符号"的问题(VS2008),依照网上说的方法都没有解决这个问题,最后在项目文件里发现有两个同名的可是不在同一个目录下的c ...
- Android HttpLoggingInterceptor的用法简介
该拦截器用于记录应用中的网络请求的信息. 示例 OkHttpClient client = new OkHttpClient(); HttpLoggingInterceptor logging = n ...
- 在Sql中将 varchar 值 '1,2,3,4,5,6' 转换成数据类型 int
--问题:将aa转换为Int类型失败 string aa="3,5,11,56,88,45,23"; select * from ERPBuMen where ID in(aa) ...
- HDU 4607 Park Visit HDU暑期多校1
10W个点的一棵树,边权为1 求访问K个点要走过的最小路程 BFS求出一条最长路以后,我们可以YY出其他的边都要重复走两次 树上的最长路可以从任意一点开始BFS求出这点的最大距离,再把终点设置为起点再 ...
- Vue render: h => h(App) $mount
$mount()手动挂载 当Vue实例没有el属性时,则该实例尚没有挂载到某个dom中: 假如需要延迟挂载,可以在之后手动调用vm.$mount()方法来挂载.例如: new Vue({ //el: ...
- Linux经常使用命令(七) - cp
cp命令用来拷贝文件或者文件夹.是Linux系统中最经常使用的命令之中的一个.普通情况下.shell会设置一个别名.在命令行下拷贝文件时,假设目标文件已经存在.就会询问是否覆盖.无论你是否使用-i參数 ...
- HTML基础第九讲---表单
转自:https://i.cnblogs.com/posts?categoryid=1121494 最基本的留言版应该大家都用过吧!没错这就是一个表单运用很好的例子.表单提供了一个管道让读者发表心声, ...