【输入子系统02】输入子系统Input_event 传递
发布日期:2021-06-29 14:51:13 浏览次数:3 分类:技术文章

本文共 11591 字,大约阅读时间需要 38 分钟。

【输入子系统02】输入子系统Input_event 传递

在前文 《》中记录了如何在kernel中添加input device 类型为touchscreen的驱动,

这在整个输入体系中是最下层的设备驱动部分,往上一层就是linux内核的管理驱动input系统,kernel中的源码位置:/kernel/drivers/input/input.c

到目前已经完全调通,可以正常使用了,现在记录一下这段时间接触到的Android 输入input 系统,先看一张网上的层次图,蛮不错的:在这里插入图片描述

一、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 char *name; const char *phys; const char *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; void *keycode; int (*setkeycode)(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *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_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 char *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核心还是没多少概念,

————————————————
原文链接:https://blog.csdn.net/jscese/article/details/42099381

转载地址:https://ciellee.blog.csdn.net/article/details/104915817 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:【输入子系统03】输入子系统核心
下一篇:【输入子系统01】USB触摸屏驱动

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月16日 23时50分42秒