输入子系统(1):数据结构总结

来源:互联网 发布:java哈希表 编辑:程序博客网 时间:2024/05/20 23:34

1:概述

输入子系统在linux内核中使用广泛,按键,鼠标,sensor类,touch等驱动都会用到输入子系统。输入子系统的结构分为以下三层:

1.1:设备驱动层

这一层需要用户在设备驱动中去实现,调用核心层的函数接口,完成输入设备的注册和并将发生的事件上报给子系统核心层;

1.2:输入子系统核心层

为驱动层和事件处理层提供函数接口,并且注册input字符设备,主设备号是13,次设备号为0~255,接受来自驱动层的上报事件,并最终通过事件处理层的接口,上报给用户,为设备驱动层和事件处理层架起一座桥梁;

1.3:事件处理层

实现了和用户层的接口,所有用户的操作都是通过事件处理层提供的接口进行;


2:输入子系统中重要的数据结构

2.1:input类数据结构:input_handle  input_handler  input_dev 

input_dev:代表一个输入设备,需要用户去填充并注册进内核,一个input_dev只能代表一个输入设备;

struct input_dev {const char *name;     //输入设备名字const char *phys;     //设备在系统中的物理路径const char *uniq;     //设备唯一标识符struct input_id id;   //设备ID,与input_handler匹配时会用到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)];   //支持的led灯事件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)];//操作接口,比如打开/sys/input/event0的时候会调用open函数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;  //当前使用的handle spinlock_t event_lock;struct mutex mutex;unsigned int users;bool going_away;bool sync;struct device dev;struct list_headh_list;  //链表头节点,用来将input_handle挂在这个头节点上struct list_headnode;    //链表节点,用来挂在input_dev_list上};
input_handler:代表某一类输入设备对应的事件处理逻辑,也就是一个input_handler可以对于那个很多个输入设备和输入设备节点;

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);const struct file_operations *fops;int minor;                           //input_handler对应的最小次设备号const char *name;const struct input_device_id *id_table;  //用于和input_dev进行匹配struct list_headh_list;     //链表头节点,用于将input_handle挂在这个上面struct list_headnode;       //链表节点,用于挂在input_handler_list上};
input_handle:使input_dev和input_handler建立起对应关系;

struct input_handle {void *private;int open;const char *name;struct input_dev *dev;          //指向input_devstruct input_handler *handler;  //指向input_handlerstruct list_headd_node; //挂在input_dev的h_list上struct list_headh_node; //挂在input_handler的h_list上};
2.2:evdev类数据结构:evdev  evdev_client

evdev:代表一个具体的事件设备event,和input_dev对应,当注册input_dev时,如果匹配成功,内核会建立一个与之对应的evdev结构,一个evdev就是一个字符节点,比如:/dev/input/event0;

evdev_client:当open一个event节点的时候,会创建evdev_client结构体,用于保存设备驱动上报的事件;

2.3:table类数据结构:evdev_table input_table

evdev_table:存放evdev的数组,table大小为32,也就是说最大有32个event节点;

input_table:存放input_handler结构的数组,大小为8,内核总共支持256个输入字符设备,主设备号为13,次设备为0~255,内核按照输入字符设备次设备号的不同,将这些设备号对应到8个input_handler,即一个input_handler对应32个输入字符设备节点,比如:evdev_handler对应的字符设备次设备号是从64开始的,比如有一个输入字符设备节点的次设备号是64,所以input_table[64>>5]中的input_handler就是此输入设备对应的input_handler;

3:上述数据结构直接的关系

3.1:输入子系统会维护evdev_table和input_table两个表,用来存放event和input_handler;

3.2:input_dev和input_handler会互相匹配,匹配成功后调用input_handler中的connect进行连接,连接的时候创建evdev结构并创建文件节点;

3.3:当用户空间open一个输入设备节点(/dev/input/event0)的时候,会依据设备节点的次设备号找到对应的input_handler,调用input_handler中的文件操作open函数,并创建evdev_client结构;

3.4:下面用一张图表现这些关系,图片来自网络:


3.5:先通过对数据结构的认识,大概有个感性了解,随后的章节参考内核代码,去认识这些数据结构,肯定会更加清晰;



0 0
原创粉丝点击