Input之我见01——设备驱动初探

栏目: 数据库 · 发布时间: 6年前

内容简介:Input之我见01——设备驱动初探

在我们日常接触的计算机模型中,可以抽象成输入模块、输出模块和运算单元。随着技术不断发展革新,输入、输出设备都有着不同程度的发展。尤其是输入设备,让人机交互有了很大变化。在Android系统中,对于输出设备事件是处理是基本 linux 的输入子系统,同时也有了自己的特征。我试图通过自己整理资料、研究代码、调试跟踪来理清之间的脉络,同时也是Android系统一个从底层到上层的脉络。由于某些方面的局限,也许无法能解决你心中所有疑问,希望对你有所启发。如果文中有不错误疏漏的,也欢迎你提意见。

该小节先讲Linux Input子系统的内容

先看一下 Linux Input子系统架构图

Input之我见01——设备驱动初探

在Kernel里面主要分三层,设备驱动层、Input Core、事件驱动层。

相关数据结构

  • 静态数据结构

存储Input设备的信息,主要位于input.h

struct input_id {
 __u16 bustype;
 __u16 vendor;
 __u16 product;
 __u16 version;
};

input_event用于存储每一次传输的数据,这是个固定大小的结构体。

struct input_event {
 struct timeval time;
 __u16 type;
 __u16 code;
 __s32 value;
};

其中type定义 在Kernel(3.14)的Input子系统中,定义如下18种Input事件,常用的也就是前面5,6种

/* Events */

#define EV_SYN 0x00 //用于同步
#define EV_KEY 0x01 //用于按键,遥控器等,键值的输入设备
#define EV_REL 0x02 //相对事件,用于鼠标的输入
#define EV_ABS 0x03 //绝对事件,用于触摸屏
#define EV_MSC 0x04
#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

在Android7.0的EventHub中,对底层的事件类型,作了自己的分类,但有相应的对应关系

EventHub.h
/*
* Input device classes.
*/
enum {
 /* The input device is a keyboard or has buttons. */
INPUT_DEVICE_CLASS_KEYBOARD= 0x00000001,

 /* The input device is an alpha-numeric keyboard (not just a dial pad). */
INPUT_DEVICE_CLASS_ALPHAKEY= 0x00000002,

 /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
INPUT_DEVICE_CLASS_TOUCH= 0x00000004,

...
};
 
  • 动态数据结构

在Input事件驱动层, 以dvdev为例

input_handler:input管理者

struct input_handler{
 void *private;
 void (*event)(struct input_handle*handle, unsigned int type, unsigned int code, int value);
 bool (*filter)(struct input_handle*handle, unsigned int type, unsigned int code, int value);
 bool (*match)(struct input_handler*handler, struct input_dev*dev);
 int (*connect)(struct input_handler*handler, struct input_dev*dev, const struct input_device_id*id);
 void (*disconnect)(struct input_handle*handle);
 void (*start)(struct input_handle*handle);
......
 struct list_head h_list;
 struct list_head node;
};

input_handle:input设备的句柄

struct input_handle {

 void *private;

 int open;
 const char *name;

 struct input_dev *dev;
 struct input_handler *handler;

 struct list_head d_node;
 struct list_head h_node;
};

input_dev:input设备

struct input_dev {
 const char *name;
 const char *phys;
 const char *uniq;
 struct input_id id;

 unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
 unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
....
 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);

...

 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;
...
 struct device dev;

 struct list_head h_list;
 struct list_head node;
};

这三者 Input_dev,hander,与Hande的关系

Input之我见01——设备驱动初探

应该很清楚了吧,这里只以其中的一个input_dev和handler为例画出来的图,其他的以此类推。其中input_dev_list和input_handler_list是两条全局的链表,每当调用 input_register_device 函数时会将Input设备加入到input_dev_list链表的尾部;每当调用 input_register_handler 函数时会将handler加入到input_handler_list链表的尾部;每当调用 input_register_handle 函数时会将handle加入到其对应的Input设备的h_list链表的尾部,并且还会该handle加入到其对应的handler的h_list链表的尾部。

Input设备驱动

总共有三个核心的函数

input_register_handler(&evdev_handler);

input_register_handle(&evdev->handle);

input_register_device(remote->input);

前面两个是在事件驱动层的evdev.c的init函数和connect函数中调用;最后一个是在设备驱动中注册的。

我们从最底层的input_register_device分析起,以IR遥控器驱动为例

在probe函数中,进行input_register_device把该input设备注册进全局的input_dev_list链表

input_register_device(remote->input);

=》

int input_register_device(struct input_dev *dev)
{
...
//添加到全局设备
error = device_add(&dev->dev);
...
//添加到设备链表
list_add_tail(&dev->node, &input_dev_list);
//遍历input_handler_list链表,以node为关键字,把dev加入到handler_list中
list_for_each_entry(handler, &input_handler_list, node)
 input_attach_handler(dev, handler);

在input_attach_handler中,

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{

 id = input_match_device(handler, dev);
 if (!id)
 return -ENODEV;
...
 error = handler->connect(handler, dev, id);
...
 return error;
}

通过id进行匹配,第一次的话hander链表中没有dev对应的handler,就进行connect,其实是调用input_register_handle()。把input_dev,input_handler,input_handle关联起来。

注册完成之后,一般就调用这两个函数发送数据到input子系统中

input_event(dev,EV_KEY,scancode,type);
input_sync(dev);

主要看input_event

=》

input_handle_event(dev, type, code, value);

=》

input_pass_event(dev, type, code, value);

=》

handle->handler->event(handle, type, code, value);

在input_register_handler的时候,为dev分配了一个handler,并与handle进行关联了,此时就直接进入event函数了。

static void evdev_event(struct input_handle *handle,
 unsigned int type, unsigned int code, int value)
{
 struct evdev *evdev = handle->private;
 struct evdev_client *client;
 struct input_event event;

 event.type = type;
 event.code = code;
 event.value = value;
...
 client = rcu_dereference(evdev->grab);
 if (client)
 evdev_pass_event(client, &event);
 else
 list_for_each_entry_rcu(client, &evdev->client_list, node)
 evdev_pass_event(client, &event);

...
 if (type == EV_SYN && code == SYN_REPORT)
 wake_up_interruptible(&evdev->wait);
}

把事件通过evdev_pass_event传递给client,如果是同步事件的话,就调用wait,唤醒相应的监听进行。


以上所述就是小编给大家介绍的《Input之我见01——设备驱动初探》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术

计算机程序设计艺术

Donald E. Knuth / 李伯民、范明、蒋爱军 / 人民邮电出版社 / 2016-1-1 / 198

《计算机程序设计艺术》系列是公认的计算机科学领域经典之作,深入阐述了程序设计理论,对计算机领域的发展有着极为深远的影响。本书是该系列的第 1 卷,讲解基本算法,其中包含了其他各卷都需用到的基本内容。本卷从基本概念开始,然后讲述信息结构,并辅以大量的习题及答案。一起来看看 《计算机程序设计艺术》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具