【Linux设备驱动】Linux输入子系统之底层驱动

★什么是Linux输入子系统?为什么引入Linux输入子系统?html

Linux输入子系统是为多种不一样的输入设备提供一种统一的机制,将它们归属到统一架构下面。在输入子系统之前,输入设备(鼠标、键盘)都是采用字符设备或者混杂设备进行处理。所以就会产生一个问题,如何将硬件不一样、类型不一样的输入设备进行统一的处理,才有了后面的Linux输入子系统。node

★Linux输入子系统的层次结构编程

Linux输入子系统分为三个层次:设备驱动层、核心层、事件处理层。一个输入事件(鼠标产生的事件)会经过设备驱动层、核心层、事件处理层、到达用户空间最终到达应用程序。数组


(注:图片来源http://www.cnblogs.com/cute/archive/2011/08/30/2159305.html)数据结构

★Linux输入子系统的分层架构


(注:图片来源http://www.cnblogs.com/cute/archive/2011/08/30/2159305.html)函数

★Linux输入子系统之设备驱动层ui

◇做用google

驱动层主要负责与硬件打交道。对硬件设备的访问,中断设置,将硬件产生的事件转换为核心层定义的规范提交给事件处理层。编码

◇重要的数据结构

输入设备数据结构:input_dev

struct input_dev {
			const char *name;//提供给用户的输入设备的名称
			const char *phys;//提供给编程者的设备节点的名称
			const char *uniq;//指定惟一的ID号
			struct input_id id;//输入设备标识ID,用于和事件处理层进行匹配
			
			/**BITS_TO_LONGS的做用:求一个数是几个long的长度**/
			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 *mt;

			struct input_absinfo *absinfo;

			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 (*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; //用于open、close函数的连续访问互斥

			unsigned int users; //设备使用计数器
			bool going_away;

			struct device dev;

			struct list_head	h_list; //handle列表
			struct list_head	node; //input_dev链表

			unsigned int num_vals;
			unsigned int max_vals;
			struct input_value *vals;

			bool devres_managed;
};
◇重要的函数

分配与注册一个输入设备

分配:

Struct input_dev *input_allocate_device*(void);//分配一个输入设备结构体的指针。 

注册:

int input_register_device(struct input_dev *dev);

这个函数把dev输入设备挂在输入设备链表中,而且通知事件处理层调用connect函数完成设备和事件处理的绑定,

当用户打开设备时,便可以调用到相应的事件处理接口得到硬件上报的数据了。

◇事件的支持

对于一个设备驱动,要使用set_bit()函数来告诉输入子系统它支持哪些事件,例如:

set_bit(nuc970_keycode[i], input_kp_dev->keybit);设置按键的类型。在input_dev结构体下有两个数组
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//支持的事件类型
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//支持的按键类型
事件类型:

#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 core)来报告EV_KEY,EV_REL,EV_ABS等事件,报告函数为:
Void input_report_key(struct input_dev *dev,unsigned int code, int value) //报告键值
Void input_report_rel(struct input_dev *dev,unsigned int code, int value) //报告相对坐标
Void input_report_abs(struct input_dev *dev,unsigned int code, int value) //报告绝对坐标
Void input_sync(struct input_dev *dev);//报告同步事件
◇释放与注销设备
Void input_free_device(struct input_dev *dev); 
Void input_unregister_device(struct input_dev *);
参考资料:

http://7071976.blog.51cto.com/7061976/1398175

http://blog.csdn.net/voice_shen/article/details/7005681

http://blog.csdn.net/ielife/article/details/7798952

http://www.chengxuyuans.com/Linux/66974.html

https://sites.google.com/site/rgbbones2/inputsubsystem

http://blog.chinaunix.net/uid/23770712/list/2.html

http://www.cnblogs.com/cute/archive/2011/08/30/2159305.html