Linux Input子系统(1)--概述

水平有限,描述不当之处还请指出,转载请注明出处http://blog.csdn.net/vanbreaker/article/details/7714188

      输入设备总类繁杂,包括按键,键盘,触摸屏,鼠标,摇杆等等,它们本身都是字符设备,不过内核为了能将这些设备的共性抽象出来,简化驱动的开发,建立了一个Input子系统。Input子系统分为三层,从下至上分别是输入设备驱动层,输入核心层以及输入事件驱动层。这三层中的输入核心层和输入事件驱动层都是内核已经完成了的,因此需要我们完成的只有输入设备驱动层。考虑输入设备主要的工作过程都是 动作产生(按键,触屏……)-->产生中断-->读取数值(键值,坐标……)-->将数值传递给应用程序。最后一个步骤就属于事件的处理,对于同一类设备,他们的处理方式都是相同的,因此内核已在事件驱动层为我们做好了,不需我们操心,而产生中断-->读取数值是因设备而异的,需要我们根据具体的设备来编写驱动。一个大致的工作流程就是,input device向上层报告-->input core接收报告,并根据在注册input device时建立好的连接选择哪一类handler来处理事件-->通过handler将数据存放在相应的dev(evdev,mousedev…)实例的缓冲区中,等待应用程序来读取。当然,有时候也需要从应用层向设备层逆向传递,比如控制一些和设备相关的LED,蜂鸣器等。设备驱动层,输入核心层和事件处理层之间的关系可以用下图来阐释:

      下面来看看Input子系统的关键数据结构

  1. struct input_dev { 
  2.     const char *name; 
  3.     const char *phys; 
  4.     const char *uniq; 
  5.     struct input_id id;//与input_handler匹配用的id,包括 
  6.  
  7.     unsigned long evbit[BITS_TO_LONGS(EV_CNT)];    //设备支持的事件类型 
  8.     unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  //按键事件支持的子事件类型 
  9.     unsigned long relbit[BITS_TO_LONGS(REL_CNT)];  //相对坐标事件支持的子事件类型 
  10.     unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  //绝对坐标事件支持的子事件类型 
  11.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];   
  12.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];   
  13.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];   
  14.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];      
  15.     unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; 
  16.  
  17.     unsigned int keycodemax; 
  18.     unsigned int keycodesize; 
  19.     void *keycode; 
  20.     int (*setkeycode)(struct input_dev *dev, int scancode, int keycode); 
  21.     int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode); 
  22.  
  23.     struct ff_device *ff; 
  24.  
  25.     unsigned int repeat_key; //最近一次的按键值 
  26.     struct timer_list timer; 
  27.  
  28.     int sync; 
  29.  
  30.     int abs[ABS_MAX + 1]; 
  31.     int rep[REP_MAX + 1]; 
  32.  
  33.     unsigned long key[BITS_TO_LONGS(KEY_CNT)];//反应设备当前的按键状态 
  34.     unsigned long led[BITS_TO_LONGS(LED_CNT)];//反应设备当前的led状态 
  35.     unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反应设备当前的声音输入状态 
  36.     unsigned long sw[BITS_TO_LONGS(SW_CNT)];  //反应设备当前的开关状态 
  37.  
  38.     int absmax[ABS_MAX + 1];//来自绝对坐标事件的最大键值 
  39.     int absmin[ABS_MAX + 1];//来自绝对坐标事件的最小键值 
  40.     int absfuzz[ABS_MAX + 1]; 
  41.     int absflat[ABS_MAX + 1]; 
  42.  
  43.     int (*open)(struct input_dev *dev);  //第一次打开设备时调用,初始化设备用 
  44.     void (*close)(struct input_dev *dev);//最后一个应用程序释放设备时用,关闭设备 
  45.     int (*flush)(struct input_dev *dev, struct file *file); 
  46.     /*用于处理传递给设备的事件,如LED事件和声音事件*/ 
  47.     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); 
  48.  
  49.     struct input_handle *grab;//当前占有该设备的input_handle 
  50.  
  51.     spinlock_t event_lock; 
  52.     struct mutex mutex; 
  53.  
  54.     unsigned int users;//打开该设备的用户数量(input handlers) 
  55.     int going_away; 
  56.  
  57.     struct device dev; 
  58.  
  59.     struct list_head    h_list;//该链表头用于链接此设备所关联的input_handle 
  60.     struct list_head    node;  //用于将此设备链接到input_dev_list 
  61. }; 
struct input_dev {
	const char *name;
	const char *phys;
	const char *uniq;
	struct input_id id;//与input_handler匹配用的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)];  //相对坐标事件支持的子事件类型
	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
};


  1. struct input_handler { 
  2.  
  3.     void *private
  4.  
  5.     /*event用于处理事件*/ 
  6.     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); 
  7.     /*connect用于建立handler和device的联系*/ 
  8.     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); 
  9.     /*disconnect用于解除handler和device的联系*/ 
  10.     void (*disconnect)(struct input_handle *handle); 
  11.     void (*start)(struct input_handle *handle); 
  12.  
  13.     const struct file_operations *fops;//handler的一些处理函数 
  14.     int minor;//次设备号 
  15.     const char *name; 
  16.  
  17.     const struct input_device_id *id_table;//用于和device匹配 
  18.     const struct input_device_id *blacklist;//匹配黑名单 
  19.  
  20.     struct list_head    h_list;//用于链接和此handler相关的handle 
  21.     struct list_head    node;  //用于将该handler链入input_handler_list 
  22. }; 
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匹配
	const struct input_device_id *blacklist;//匹配黑名单

	struct list_head	h_list;//用于链接和此handler相关的handle
	struct list_head	node;  //用于将该handler链入input_handler_list
};

  1. struct input_handle { 
  2.  
  3.     void *private
  4.  
  5.     int open;//记录设备的打开次数(有多少个应用程序访问设备) 
  6.     const char *name; 
  7.  
  8.     struct input_dev *dev;//指向所属的device 
  9.     struct input_handler *handler;//指向所属的handler 
  10.  
  11.     struct list_head    d_node;//用于链入所属device的handle链表 
  12.     struct list_head    h_node;//用于链入所属handler的handle链表 
  13. }; 
struct input_handle {

	void *private;

	int open;//记录设备的打开次数(有多少个应用程序访问设备)
	const char *name;

	struct input_dev *dev;//指向所属的device
	struct input_handler *handler;//指向所属的handler

	struct list_head	d_node;//用于链入所属device的handle链表
	struct list_head	h_node;//用于链入所属handler的handle链表
};


我们可以看到,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个。下一节将以even handler为例介绍设备注册以及打开的过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值