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下输入子系统的更多相关文章

  1. 12.Linux之输入子系统分析(详解)

    版权声明:本文为博主原创文章,转载请标注出处:   在此节之前,我们学的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥/非阻塞.定时 ...

  2. linux input输入子系统应用分析

    输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理是底层在按键.触摸等动作发送时产生一个中断(或驱动通过timer定时查询),然后CPU通过SPI.I2 C或外部存储器总线读取 ...

  3. linux input输入子系统分析《四》:input子系统整体流程全面分析

    1      input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...

  4. linux内核输入子系统分析

    1.为何引入input system? 以前我们写一些输入设备(键盘.鼠标等)的驱动都是采用字符设备.混杂设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可 ...

  5. Linux/Android——输入子系统input_event传递 (二)【转】

    本文转载自:http://blog.csdn.net/jscese/article/details/42099381 在前文Linux/Android——usb触摸屏驱动 - usbtouchscre ...

  6. Linux下输入某些命令时会提示:bash:command not found

    首先,查看$PATH中是否包含了这些命令. $PATH:决定了shell到哪些目录中去寻找命令或程序,PATH值是一系列的目录.当运行程序时,linux到这些目录下搜索进行编译链接. 格式: PATH ...

  7. Linux下 输入 env 而得到的环境变量解读

    HOSTNAME=Master.Hadoop MAHOUT_HOME=/usr/hadoop/mahout-distribution-0.8 TERM=linux SHELL=/bin/bash HA ...

  8. Linux下clock子系统

    常用API: 1.struct clk *clk_get(struct device *dev, const char *id):从一个时钟list链表中以dev或者字符id名称查找一个时钟clk结构 ...

  9. Linux下触摸屏驱动程序分析

    [摘要: 本文以linux3.5--Exynos4412仄台,剖析触摸屏驱动焦点内容.Linux下触摸屏驱动(以ft5x06_ts为例)须要懂得以下学问: 1. I2C协定 2. Exynos4412 ...

随机推荐

  1. java(数组及常用简单算法 )

    数组 数组:数组是存储同一种数据类型数据的集合容器. 数组的定义格式: 数据类型[]  变量名  =  new  数据类型[长度]; 数组的好处:对分配到数组对象中每一个数据都分配一个编号(索引值.角 ...

  2. css3--根据数据加载显示的一个动画

    css: .circle { width: 200px; height: 200px; position: absolute; border-radius: 50%; background: #0cc ...

  3. 如何优雅的写UI——(3)添加MFC选项卡

    窗体创建完成,接下来我们讲讲控件的使用 首先在CFormView窗体下选项卡的成员变量,这里我选择MFC下的选项卡类库:CMFCTabCtrl class CtabView : public CFor ...

  4. [Python] Python's namedtuples can be a great alternative to defining a class manually

    # Why Python is Great: Namedtuples # Using namedtuple is way shorter than # defining a class manuall ...

  5. 【JEECG技术博文】JEECG 简单实例解说权限控制

    JEECG简单实例解说权限控制 请大家点击这里为我们投票.2015博客之星.很多其他分享敬请期待 博文地址:http://blog.itpub.net/30066956/viewspace-18687 ...

  6. Echarts Y轴min显示奇葩问题(做此记录)

    项目需求是根据不同情况显示最大值最小值   有9-35  12-50 9-50 三种情况 前面两种可以显示出来  但是9-50的话  最小值9显示不出来  8,7等就可以显示出来 后面想到强制从最小值 ...

  7. vue中v-for的用法以及参数的作用

    <template> <div> <div class="content clearfix" v-on:click="goorderingD ...

  8. 蚂蚁金服入股36Kr给我的一点警示:应该相信自己的理性分析,不能盲目迷信权威

    最近3年,关注互联网和创业投资比较多,每周都会关注下本周发生的创业投融资大事件. 我注意到,一些自媒体作者经常会发布一些有"前瞻性"的文章,比如"美团大众要合并了&quo ...

  9. CList 点击表头排序 (2)两种排序方法中其中一种

    上一篇讲解SortItem()方法如何使用,虽然都是抄别人的但是就是想让大家有个大概的了解 CList 点击表头排序 (1)SortItems函数 点击表头排序基本思路都是 1.首先响应HDN_ITE ...

  10. redirect_uri 参数错误

    http://www.cnblogs.com/zitjubiz/p/5935712.html http://blog.csdn.net/u014033756/article/details/52038 ...