input子系统分析Jason一、概述在linux下,按键、触摸屏、鼠标等都可以利用input接口函数来实现设备驱动。1,linux输入子系统主要分三层:驱动,输入CORE,事件处理层。驱动根据CORE提供的接口,向上报告发生的按键动作。然后CORE根据驱动的类型,分派这个报告给对应的事件处理层进行处事。事件处理层把数据变化反应到设备模型的文件中(事件缓冲区)。并通知在这些设备模型文件上等待的进程。2,输入子系统在KERNEL初始化时被初始化。会创建所有类型输入输出设备的逻辑设备(及sysfs结点)。当硬件注册时,就会调用所有类型的inputhandler的connect函数,根据硬件注册的结构来判断是否与自己相关,然后再创建一个具体的设备结点。3,驱动只负责的把输入设备注册到输入子系统中,然后输入子系统来创建对应的具体设备结点。而事件处理层,在初始化时,需要注册所一类设备的输入事件处理函数及相关接口4,一类inputhandler可以和多个硬件设备相关联,创建多个设备节点。而一个设备也可能与多个inputhandler相关联,创建多个设备节点。二、输入设备结构体1.input_dev这是input设备基本的设备结构,每个input驱动程序中都必须分配初始化这样一个结构,成员比较多代码路径kernel/include/linux/input.h1.structinput_dev{2.constchar*name;//设备名3.constchar*phys;//设备系统层的物理路径4.constchar*uniq;//5.structinput_idid;//输入设备id总线类型;厂商编号,产品id,产品版本6.7.unsignedlongevbit[BITS_TO_LONGS(EV_CNT)];//事件类型标志位8.unsignedlongkeybit[BITS_TO_LONGS(KEY_CNT)];//键盘事件标志位9.unsignedlongrelbit[BITS_TO_LONGS(REL_CNT)];//相对位移事件标志位10.unsignedlongabsbit[BITS_TO_LONGS(ABS_CNT)];//绝对位移事件标志位11.unsignedlongmscbit[BITS_TO_LONGS(MSC_CNT)];//杂项事件标志位12.unsignedlongledbit[BITS_TO_LONGS(LED_CNT)];//led指示灯标志位13.unsignedlongsndbit[BITS_TO_LONGS(SND_CNT)];//声音事件14.unsignedlongffbit[BITS_TO_LONGS(FF_CNT)];//强制反馈事件15.unsignedlongswbit[BITS_TO_LONGS(SW_CNT)];//开关事件标志位16.17.unsignedinthint_events_per_packet;18.unsignedintkeycodemax;//键盘码表大小19.unsignedintkeycodesize;//键盘码大小20.void*keycode;//键盘码表指针21.22.int(*setkeycode)(structinput_dev*dev,unsignedintscancode,unsignedintkeycode);//设置键盘码23.int(*getkeycode)(structinput_dev*dev,unsignedintscancode,unsignedint*keycode);//获取键盘码24.int(*setkeycode_new)(structinput_dev*dev,conststructinput_keymap_entry*ke,unsignedint*old_keycode);25.int(*getkeycode_new)(structinput_dev*dev,structinput_keymap_entry*ke);26.27.structff_device*ff;//强制反馈设备28.unsignedintrepeat_key;//重复按键标志位29.structtimer_listtimer;//定时器30.intrep[REP_CNT];//重复次数31.structinput_mt_slot*mt;32.intmtsize;33.intslot;34.structinput_absinfo*absinfo;35.unsignedlongkey[BITS_TO_LONGS(KEY_CNT)];//36.unsignedlongled[BITS_TO_LONGS(LED_CNT)];//37.unsignedlongsnd[BITS_TO_LONGS(SND_CNT)];//38.unsignedlongsw[BITS_TO_LONGS(SW_CNT)];//39.40.int(*open)(structinput_dev*dev);//open方法41.void(*close)(structinput_dev*dev);//close方法42.int(*flush)(structinput_dev*dev,structfile*file);43.int(*event)(structinput_dev*dev,unsignedinttype,unsignedintcode,intvalue);44.45.structinput_handle__rcu*grab;46.spinlock_tevent_lock;47.structmutexmutex;48.unsignedintusers;49.boolgoing_away;50.boolsync;51.structdevicedev;//设备文件52.structlist_headh_list;//input_handler处理器链表头53.structlist_headnode;//input_device设备链表头54.};三、input_handler输入处理器这是事件处理器的数据结构,代表一个事件处理器代码路径kernel/include/linux/input.h1.structinput_handler{2.void*private;//私有数据3.void(*event)(structinput_handle*handle,unsignedinttype,unsignedintcode,intvalue);//事件处理4.bool(*filter)(structinput_handle*handle,unsignedinttype,unsignedintcode,intvalue);//过滤器5.bool(*match)(structinput_handler*handler,structinput_dev*dev);//设备匹配6.int(*connect)(structinput_handler*handler,structinput_dev*dev,conststructinput_device_id*id);//设备连接7.void(*disconnect)(structinput_handle*handle);//设备断开连接8.void(*start)(structinput_handle*handle);9.conststructfile_operations*fops;//输入操作函数集10.intminor;//次设备号11.constchar*name;//设备名12.conststructinput_device_id*id_table;//输入设备id表13.structlist_headh_list;//input_handler处理器链表头14.structlist_headnode;//input_device设备链表头15.};四、input_handleinput_handle结构体代表一个成功配对的input_dev和input_handler代码路径kernel/include/linux/input.hstructinput_handle{1.void*private;//每个配对的事件处理器都会分配一个对应的设备结构,如evdev事件处理器的evdev结构,注意这个结构与设备驱动层的input_dev不同,初始化handle时,保存到这里。2.intopen;//打开标志,每个input_handle打开后才能操作,这个一般通过事件处理器的open方法间接设置3.constchar*name;4.structinput_dev*dev;//关联的input_dev结构5.structinput_handler*handler;//关联的input_handler结构6.structlist_headd_node;//input_handle通过d_node连接到了input_dev上的h_list链表上7.structlist_headh_node;//input_handle通过h_node连接到了input_handler的h_list链表上8.};五、三个数据结构之间的关系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,比如说一个鼠标,它可以对应evenhandler,也可以对应mousehandler,因此当其注册时与系统中的handler进行匹配,就有可能产生两个实例,一个是evdev,另一个是mousedev,而任何一个实例中都只有一个handle。至于以何种方式来传递事件,就由用户程序打开哪个实例来决定。后面一个情况很容易理解,一个事件驱动不能只为一个甚至一种设备服务,系统中可能有多种设备都能使用这类handler,比如eventhandler就可以匹配所有的设备。在input子系统中,有8种事件驱动,每种事件驱动最多可以对应32个设备,因此dev实例总数最多可以达到256个。六、输入系统初始化代码路径kernel/drivers/input/input.c9.staticint__initinput_init(void)10.{11.interr;12.13.err=class_register(&input_class);//注册类创建/sys/input14.if(err){15.printk(KERN_ERRinput:unabl