在input系统中,先是下面这张图片
之后是这样图片,呵呵先熟悉一下环境,再介绍。
在input中有三个结构体要注意,如下
- 1.input_dev 这是input设备基本的设备结构,每个input驱动程序中都必须分配初始化这样一个结构,成员比较多
- struct input_dev {
- const char *name;
- const char *phys;
- const char *uniq;
- struct input_id id;//与input_handler匹配用的id,包括
- /*struct input_id {
- __u16 bustype; //总线类型
- __u16 vendor; //生产厂商
- __u16 product; //产品类型
- __u16 version; //版本
- }; */
- /*
- #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 //LED或其它指示设备
- #define EV_SND 0x12 //声音输出,如蜂鸣器
- #define EV_REP 0x14 //允许按键自重复
- #define EV_FF 0x15 //力反馈
- #define EV_PWR 0x16 //电源管理事件
- */
- 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 keycodemax;
- unsigned int keycodesize;
- void *keycode;
- int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
- int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
- struct ff_device *ff;
- unsigned int repeat_key; //最近一次的按键值
- struct timer_list timer;
- int sync;
- int abs[ABS_MAX + 1];
- int rep[REP_MAX + 1];
- unsigned long key[BITS_TO_LONGS(KEY_CNT)];//反应设备当前的按键状态
- unsigned long led[BITS_TO_LONGS(LED_CNT)];//反应设备当前的led状态
- unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反应设备当前的声音输入状态
- unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //反应设备当前的开关状态
- int absmax[ABS_MAX + 1];//来自绝对坐标事件的最大键值
- int absmin[ABS_MAX + 1];//来自绝对坐标事件的最小键值
- int absfuzz[ABS_MAX + 1];
- int absflat[ABS_MAX + 1];
- int (*open)(struct input_dev *dev); //第一次打开设备时调用,初始化设备用
- void (*close)(struct input_dev *dev);//最后一个应用程序释放设备时用,关闭设备
- int (*flush)(struct input_dev *dev, struct file *file);
- /*用于处理传递给设备的事件,如LED事件和声音事件*/
- int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
- struct input_handle *grab;//当前占有该设备的input_handle
- spinlock_t event_lock;
- struct mutex mutex;
- unsigned int users;//打开该设备的用户数量(input handlers)
- int going_away;
- struct device dev;
- struct list_head h_list;//该链表头用于链接此设备所关联的input_handle
- struct list_head node; //用于将此设备链接到input_dev_list
- }
- 2. input_handler 这是事件处理器的数据结构,代表一个事件处理器
- struct input_handler {
- void *private;
- /*event用于处理事件*/
- void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
- /*connect用于建立handler和device的联系*/
- int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
- /*disconnect用于解除handler和device的联系*/
- void (*disconnect)(struct input_handle *handle);
- void (*start)(struct input_handle *handle);
- const struct file_operations *fops;//handler的一些处理函数
- int minor;//次设备号
- const char *name;
- const struct input_device_id *id_table;//用于和device匹配 ,这个是事件处理器所支持的input设备
- const struct input_device_id *blacklist;//匹配黑名单,这个是事件处理器应该忽略的input设备
- struct list_head h_list;//这个链表用来链接他所支持的input_handle结构,input_dev与input_handler配对之后就会生成一个input_handle结构
- struct list_head node; //链接到input_handler_list,这个链表链接了所有注册到内核的事件处理器
- };
- 3.input_handle 结构体代表一个成功配对的input_dev和input_handler
- struct input_handle {
- void *private; //每个配对的事件处理器都会分配一个对应的设备结构,如evdev事件处理器的evdev结构,注意这个结构与设备驱动层的input_dev不同,初始化handle时,保存到这里。
- int open; //打开标志,每个input_handle 打开后才能操作,这个一般通过事件处理器的open方法间接设置
- const char *name;
- struct input_dev *dev; //关联的input_dev结构
- struct input_handler *handler; //关联的input_handler结构
- struct list_head d_node; //input_handle通过d_node连接到了input_dev上的h_list链表上
- struct list_head h_node; //input_handle通过h_node连接到了input_handler的h_list链表上
- };
-
- 三个数据结构之间的关系
- input_dev 是硬件驱动层,代表一个input设备
- input_handler 是事件处理层,代表一个事件处理器
- input_handle 个人认为属于核心层,代表一个配对的input设备与input事件处理器
- input_dev 通过全局的input_dev_list链接在一起。设备注册的时候实现这个操作。
- input_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现这个操作(事件处理器一般内核自带,一般不需要我们来写)
- input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_dev 和 input_handler 的h_list上了。通过input_dev 和input_handler就可以找到input_handle在设备注册和事件处理器,注册的时候都要进行配对工作,配对后就会实现链接。通过input_handle也可以找到input_dev和input_handler。
- 我们可以看到,input_device和input_handler中都有一个h_list,而input_handle拥有指向input_dev和input_handler的指针,也就是说input_handle是用来关联input_dev和input_handler的。
-
那么为什么一个input_device和input_handler中拥有的是h_list而不是一个handle呢?因为一个device可能对应多个handler,而一个handler也不能只处理一个device,比如说一个鼠标,它可以对应even handler,也可以对应mouse handler,因此当其注册时与系统中的handler进行匹配,就有可能产生两个实例,一个是evdev,另一个是mousedev,而任何一个实例中都只有一个handle。至于以何种方式来传递事件,就由用户程序打开哪个实例来决定。后面一个情况很容易理解,一个事件驱动不能只为一个甚至一种设备服务,系统中可能有多种设备都能使用这类handler,比如event handler就可以匹配所有的设备。在input子系统中,有8种事件驱动,每种事件驱动最多可以对应32个设备,因此dev实例总数最多可以达到256个。
注意: input_handle,才是使用的时候的核心
之后 继续介绍用户层使用的时候,在core里面的结构体
- 主要数据结构
- (1) evdev设备结构
- struct evdev {
- int exist;
- int open; //打开标志
- int minor; //次设备号
- struct input_handle handle; //关联的input_handle
- wait_queue_head_t wait; //等待队列,当进程读取设备,而没有事件产生的时候,进程就会睡在其上面
- struct evdev_client *grab; //强制绑定的evdev_client结构,这个结构后面再分析
- struct list_head client_list; //evdev_client 链表,这说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问evdev设备
- spinlock_t client_lock; /* protects client_list */
- struct mutex mutex;
- struct device dev; //device结构,说明这是一个设备结构
- };
- //evdev结构体在配对成功的时候生成,由handler->connect生成,对应设备文件为/class/input/event(n),如触摸屏驱动的event0,这个设备是用户空间要访问的设备,可以理解它是一个虚拟设备,因为没有对应的硬件,但是通过handle->dev 就可以找到input_dev结构,而它对应着触摸屏,设备文件为/class/input/input0。这个设备结构生成之后保存在evdev_table中,索引值是minor。
- (2)evdev用户端结构
- struct evdev_client {
- struct input_event buffer[EVDEV_BUFFER_SIZE];//这个是一个input_event数据结构的数组,input_event代表一个事件,基本成员:类型(type),编码(code),值(value)
- int head; //针对buffer数组的索引
- int tail; //针对buffer数组的索引,当head与tail相等的时候,说明没有事件
- spinlock_t buffer_lock; /* protects access to buffer, head and tail */
- struct fasync_struct *fasync; //异步通知函数
- struct evdev *evdev; //evdev设备
- struct list_head node; // evdev_client 链表项
- };
- //这个结构在进程打开event0设备的时候调用evdev的open方法,在open中创建这个结构,并初始化。在关闭设备文件的时候释放这个结构。
- (3)input_event结构
- struct input_event {
- struct timeval time; //事件发生的时间
- __u16 type; //事件类型
- __u16 code; //子事件
- __s32 value; //事件的value
- };
这个三个结构体的关系也和特殊:
evdev是在驱动创建的时候生成的,关键要看里面的struct input_handle handle;,在这里指定了这个结构体关联的驱动。也可以这样理解,有了它就有了驱动的数据和操作
evdev_client
这个结构体是在用户层调用和input核心里面的open函数的时候申请成功的,在close的时候会被释放。要注意里面的struct evdev *evdev;,
哈哈,明白了吧
这个结构体是在用户层调用和input核心里面的open函数的时候申请成功的,在close的时候会被释放。要注意里面的struct evdev *evdev;,
哈哈,明白了吧
input_event
这个结构体在evdev_client 里面,具体标示一个具体的事件
这个结构体在evdev_client 里面,具体标示一个具体的事件
之后呢再介绍一个结构体,它是input核心跟用户层的ops,用户使用下面完成对input设备的读取
- static const struct file_operations evdev_fops = {
- .owner = THIS_MODULE,
- .read = evdev_read,
- .write = evdev_write,
- .poll = evdev_poll,
- .open = evdev_open,
- .release = evdev_release,
- .unlocked_ioctl = evdev_ioctl,
- #ifdef CONFIG_COMPAT
- .compat_ioctl = evdev_ioctl_compat,
- #endif
- .fasync = evdev_fasync,
- .flush = evdev_flush,
- .llseek = no_llseek,
- };
分析open:
evdev_open(struct inode *inode, struct file *file)
——>static int evdev_open_device(struct evdev *evdev)
——>static int evdev_open_device(struct evdev *evdev)
——>int input_open_device(struct input_handle *handle)
——>dev->open(dev);
——>dev->open(dev);
分析read:
ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos)
——>wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist);
//等待数据
//等待数据
当中断发生并有数据的时候,会调用事件处理,唤醒这个等待的
最后呢
看一下上面结构体evdev_client
和evdev 里面的list_head
项,这里表示了一个驱动可以对应多个用户
和evdev 里面的list_head
项,这里表示了一个驱动可以对应多个用户