Linux/Android——输入子系统input_event传递
Posted 请给我倒杯茶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux/Android——输入子系统input_event传递 相关的知识,希望对你有一定的参考价值。
本文转载自:http://blog.csdn.net/jscese/article/details/42099381
在前文 Linux/Android——usb触摸屏驱动 - usbtouchscreen (一) 中记录了如何在kernel中添加input device 类型为touchscreen的驱动,
这在整个输入体系中是最下层的设备驱动部分,往上一层就是linux内核的管理驱动input系统,kernel中的源码位置:/kernel/drivers/input/input.c
撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42099381
到目前已经完全调通,可以正常使用了,现在记录一下这段时间接触到的android 输入input 系统,先看一张网上的层次图,蛮不错的:
上一篇博客里面的 usbtouchscreen 就是对应上图的I2c module的位置,而在kernel中input的核心就是input.c .
input_dev:
这个结构体表述的是一个输入设备的相关信息,在usbtouchscreen 驱动中的 usbtouch_probe 会初始化input_dev,作为usbtouch设备的一部分.
会对 input_dev 做一系列的初始化,设置参数之类的,具体可参考之前博客
input_dev 结构原型如下,/kernel/include/linux/input.h中定义:
- /**
- * struct input_dev - represents an input device
- * @name: name of the device
- * @phys: physical path to the device in the system hierarchy
- * @uniq: unique identification code for the device (if device has it)
- * @id: id of the device (struct input_id)
- * @propbit: bitmap of device properties and quirks
- * @evbit: bitmap of types of events supported by the device (EV_KEY,
- * EV_REL, etc.)
- * @keybit: bitmap of keys/buttons this device has
- * @relbit: bitmap of relative axes for the device
- * @absbit: bitmap of absolute axes for the device
- * @mscbit: bitmap of miscellaneous events supported by the device
- * @ledbit: bitmap of leds present on the device
- * @sndbit: bitmap of sound effects supported by the device
- * @ffbit: bitmap of force feedback effects supported by the device
- * @swbit: bitmap of switches present on the device
- * @hint_events_per_packet: average number of events generated by the
- * device in a packet (between EV_SYN/SYN_REPORT events). Used by
- * event handlers to estimate size of the buffer needed to hold
- * events.
- * @keycodemax: size of keycode table
- * @keycodesize: size of elements in keycode table
- * @keycode: map of scancodes to keycodes for this device
- * @getkeycode: optional legacy method to retrieve current keymap.
- * @setkeycode: optional method to alter current keymap, used to implement
- * sparse keymaps. If not supplied default mechanism will be used.
- * The method is being called while holding event_lock and thus must
- * not sleep
- * @ff: force feedback structure associated with the device if device
- * supports force feedback effects
- * @repeat_key: stores key code of the last key pressed; used to implement
- * software autorepeat
- * @timer: timer for software autorepeat
- * @rep: current values for autorepeat parameters (delay, rate)
- * @mt: pointer to array of struct input_mt_slot holding current values
- * of tracked contacts
- * @mtsize: number of MT slots the device uses
- * @slot: MT slot currently being transmitted
- * @trkid: stores MT tracking ID for the current contact
- * @absinfo: array of &struct input_absinfo elements holding information
- * about absolute axes (current value, min, max, flat, fuzz,
- * resolution)
- * @key: reflects current state of device‘s keys/buttons
- * @led: reflects current state of device‘s LEDs
- * @snd: reflects current state of sound effects
- * @sw: reflects current state of device‘s switches
- * @open: this method is called when the very first user calls
- * input_open_device(). The driver must prepare the device
- * to start generating events (start polling thread,
- * request an IRQ, submit URB, etc.)
- * @close: this method is called when the very last user calls
- * input_close_device().
- * @flush: purges the device. Most commonly used to get rid of force
- * feedback effects loaded into the device when disconnecting
- * from it
- * @event: event handler for events sent _to_ the device, like EV_LED
- * or EV_SND. The device is expected to carry out the requested
- * action (turn on a LED, play sound, etc.) The call is protected
- * by @event_lock and must not sleep
- * @grab: input handle that currently has the device grabbed (via
- * EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
- * recipient for all input events coming from the device
- * @event_lock: this spinlock is is taken when input core receives
- * and processes a new event for the device (in input_event()).
- * Code that accesses and/or modifies parameters of a device
- * (such as keymap or absmin, absmax, absfuzz, etc.) after device
- * has been registered with input core must take this lock.
- * @mutex: serializes calls to open(), close() and flush() methods
- * @users: stores number of users (input handlers) that opened this
- * device. It is used by input_open_device() and input_close_device()
- * to make sure that dev->open() is only called when the first
- * user opens device and dev->close() is called when the very
- * last user closes the device
- * @going_away: marks devices that are in a middle of unregistering and
- * causes input_open_device*() fail with -ENODEV.
- * @sync: set to %true when there were no new events since last EV_SYN
- * @dev: driver model‘s view of this device
- * @h_list: list of input handles associated with the device. When
- * accessing the list dev->mutex must be held
- * @node: used to place the device onto input_dev_list
- */
- struct input_dev {
- const charchar *name;
- const charchar *phys;
- const charchar *uniq;
- struct input_id id;
- unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
- unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
- unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
- unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
- unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
- unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
- unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
- unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
- unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
- unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
- unsigned int hint_events_per_packet;
- unsigned int keycodemax;
- unsigned int keycodesize;
- voidvoid *keycode;
- int (*setkeycode)(struct input_dev *dev,
- const struct input_keymap_entry *ke,
- unsigned intint *old_keycode);
- int (*getkeycode)(struct input_dev *dev,
- struct input_keymap_entry *ke);
- struct ff_device *ff;
- unsigned int repeat_key;
- struct timer_list timer;
- int rep[REP_CNT];
- struct input_mt_slot *mt;
- int mtsize;
- int slot;
- int trkid;
- struct input_absinfo *absinfo;
- unsigned long key[BITS_TO_LONGS(KEY_CNT)];
- unsigned long led[BITS_TO_LONGS(LED_CNT)];
- unsigned long snd[BITS_TO_LONGS(SND_CNT)];
- unsigned long sw[BITS_TO_LONGS(SW_CNT)];
- int (*open)(struct input_dev *dev);
- void (*close)(struct input_dev *dev);
- int (*flush)(struct input_dev *dev, struct file *file);
- int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
- struct input_handle __rcu *grab;
- spinlock_t event_lock;
- struct mutex mutex;
- unsigned int users;
- bool going_away;
- bool sync;
- struct device dev;
- struct list_head h_list;
- struct list_head node;
- };
我解释可能还会误导,源码上面的注释是最好的解释,都是描述一个input 设备的相关信息.
每一个input设备,都需要初始化一个这样的input_dev结构来描述记录此设备的一些特性,然后通过input_register_device 注册到设备总线上以供后续使用
可以到系统运行目录的/proc/bus/input下 cat devices 查看总线上的已经注册上的input device
input_event:
设备驱动部分往上传递的就是触发的event事件了,还以usbtouchscreen的为例,回调函数为:
- /*****************************************************************************
- * Generic Part
- */
- static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
- unsigned charchar *pkt, int len)
- {
- struct usbtouch_device_info *type = usbtouch->type;
- if (!type->read_data(usbtouch, pkt))
- return;
- input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); // 上报触摸类型 。touch为按下
- if (swap_xy) {
- input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
- input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
- } else {
- input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
- input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); // 上报绝对坐标值
- }
- if (type->max_press)
- input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
- input_sync(usbtouch->input); // 同步操作
- }
可以看到通过 input_report_* 上报事件到input.c中,这也就是上面层次图中的箭头 9 ,初始在/kernel/include/linux/input.h:
- static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
- {
- input_event(dev, EV_KEY, code, !!value);
- }
- static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
- {
- input_event(dev, EV_REL, code, value);
- }
- static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
- {
- input_event(dev, EV_ABS, code, value);
- }
可以看到不同的report 都调用进了input_event,只是传参不同,接下来的事就全交由input.c 来做了!
- /**
- * input_event() - report new input event
- * @dev: device that generated the event
- * @type: type of the event
- * @code: event code
- * @value: value of the event
- *
- * This function should be used by drivers implementing various input
- * devices to report input events. See also input_inject_event().
- *
- * NOTE: input_event() may be safely used right after input device was
- * allocated with input_allocate_device(), even before it is registered
- * with input_register_device(), but the event will not reach any of the
- * input handlers. Such early invocation of input_event() may be used
- * to ‘seed‘ initial state of a switch or initial position of absolute
- * axis, etc.
- */
- void input_event(struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
- {
- unsigned long flags;
- if (is_event_supported(type, dev->evbit, EV_MAX)) { //判断是否是注册时的event类型,驱动probe时注册input_dev时设置了能响应的event类型
- spin_lock_irqsave(&dev->event_lock, flags); //自旋锁枷锁
- add_input_randomness(type, code, value);
- input_handle_event(dev, type, code, value); //进一步处理传上来的这个 event
- spin_unlock_irqrestore(&dev->event_lock, flags);//解锁
- }
- }
可以看到在这里首先就是过滤了事件类型,这个也是在usbtouchscreen中的probe中初始化过的!
类型有如下几种:
- /*
- * Event types
- */
- #define EV_SYN 0x00
- #define EV_KEY 0x01
- #define EV_REL 0x02
- #define EV_ABS 0x03
- #define EV_MSC 0x04
- #define EV_SW 0x05
- #define EV_LED 0x11
- #define EV_SND 0x12
- #define EV_REP 0x14
- #define EV_FF 0x15
- #define EV_PWR 0x16
- #define EV_FF_STATUS 0x17
- #define EV_MAX 0x1f
- #define EV_CNT (EV_MAX+1)
input_handle_event:
由上面的input_event 调入进这个handle处理。这里会根据type进行分类处理:
- static void input_handle_event(struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
- {
- int disposition = INPUT_IGNORE_EVENT; //初始为不做处理
- switch (type) {
- case EV_SYN:
- switch (code) {
- case SYN_CONFIG:
- disposition = INPUT_PASS_TO_ALL;
- break;
- case SYN_REPORT:
- if (!dev->sync) {
- dev->sync = true;
- disposition = INPUT_PASS_TO_HANDLERS;
- }
- break;
- ...
- case EV_KEY:
- if (is_event_supported(code, dev->keybit, KEY_MAX) && //按键code是否被keybit支持
- !!test_bit(code, dev->key) != value) { //key是键盘当前所有键状态,测试code对应键状态,value传来事件的按键状态。此句表示按键状态应有变化
- if (value != 2) {
- __change_bit(code, dev->key); //改变key的值以改变按键状态。
- if (value)
- input_start_autorepeat(dev, code); //如果按键值为按下,则开始重复按键操作。具体会不会重复,input_start_autorepeat还会根据evbit中有没有置位重复事件等判断。
- else
- input_stop_autorepeat(dev); //如果是松开按键则应停止重复按键相关操作。
- }
- disposition = INPUT_PASS_TO_HANDLERS;
- }
- break;
- ...
- case EV_ABS:
- if (is_event_supported(code, dev->absbit, ABS_MAX)) //同上面一样看是否支持
- disposition = input_handle_abs_event(dev, code, &value); //这个函数可以跟进去看,是做为筛选的,第一次是不会返回INPUT_IGNORE_EVENT ,后面如果有跟上次相同的ABS坐标就会被过滤掉,返回IGNORE
- // err("jscese display disposition vlue ==0x%x,code==0x%x, value== 0x%x\n",disposition,code,value);
- break;
- ...
- }
- if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
- dev->sync = false;
- if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
- dev->event(dev, type, code, value);
- if (disposition & INPUT_PASS_TO_HANDLERS)
- input_pass_event(dev, type, code, value); //更深一步调用 ,最终都是 调用到 event(**)方法
- }
这里先记录整个输入系统从设备驱动到上层的关系,以及从kernel中的驱动调用到input系统中的传递过程,虽然看到调用了input.c中的一些函数传递,但是对input核心还是没多少概念,
下篇解析记录一下input这个核心模块~
以上是关于Linux/Android——输入子系统input_event传递 的主要内容,如果未能解决你的问题,请参考以下文章
Linux/Android——input_handler之evdev
linux input输入子系统分析《四》:input子系统整体流程全面分析
Linux 输入设备调试详解(零基础开发)Rotary_Encoder旋转编码器模块(EC11)通用GPIO为例 挂载input输入子系统