Android输入子系统浅析(一)

Linux输入子系统框架

1:Input输入子系统总体框架

    Linux内核的输入子系统是对分散的,多种不同类别的输入设备(如键盘,鼠标,触摸屏)等字符设备进行统一处理的一层抽象,就是在字符设备驱动上抽象出的一层。但是这些输入设备都各有不同,那么输入子系统也就只能实现他们的共性,差异性则由设备驱动来实现,而差异性最直观的表现在这些设备功能上的不同。但是,为了更好的理解Linux的输入子系统,我们有必要仔细研究下它的框架。

    Linux输入子系统将输入驱动抽象为三层:设备驱动层、核心层、事件处理层,其内在联系如下图所示:


下面先对这三个部分做一个简要的概括,后面的分析也是基于这三个部分:

        设备驱动层:主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层

        核心层:为设备驱动层提供了规范和接口。设备驱动层只关心如何驱动硬件并获得硬件数据,然后调用核心层提供的接口,核心层自动把数据提交给事件处理层

        事件处理层:是用户编程的接口(设备节点),并处理驱动层提交的数据处理

本篇博文所述均是基于linux 3.4.5内核,android 4.2.2版本,硬件平台基于MT6589平台.


2:Input子系统分层分析

        2.1:在分析这三部分之前,首先我们先看看input.h这个头文件,因为输入子系统的很多重要结构体都是在里面定义的。

        路径:kernel/include/linux/input.h

       重要结构体之input_dev:

struct input_dev {
	const char *name;    //设备名称
	const char *phys;       //设备在系统的物理路径
	const char *uniq;      //设备唯一识别符
	struct input_id id;     //设备ID,包含总线ID(PCI,USB)、厂商ID,与input_handler匹配时用到

	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];     //bitmap of device properties and quirks

	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;   //keycode表的大小
	unsigned int keycodesize;  //keycode表中的元素个数
	void *keycode;	//设备的键盘表										

	//配置keycode表
	int (*setkeycode)(struct input_dev *dev,											
			  const struct input_keymap_entry *ke,
			  unsigned int *old_keycode);

	//获取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)];

	//操作接口
	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_head	h_list; //h_list是一个链表头,用来把handle挂载在这个上
	struct list_head	node; //这个node是用来连到input_dev_list上的
};

     重要结构体之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;      //次设备号
	const char *name;

	const struct input_device_id *id_table;

	struct list_head	h_list;    //h_list是一个链表头,用来把handle挂载在这个上
	struct list_head	node;    //这个node是用来连到input_handler_list上的 
};


重要结构体之input_handle

struct input_handle {  
  
    void *private;    //私有数据  
  
    int open;  
    const char *name;  
  
    struct input_dev *dev;  //指向input_dev  
    struct input_handler *handler;  //指向input_handler  
  
    struct list_head    d_node;  //连到input_dev的h_list  
    struct list_head    h_node; //连到input_handler的h_list  
};  

重要结构体之evdev_client:

/*在进程打开event设备的时候调用evdev的open方法,在open中创建和初始化*/
struct evdev_client {  
    unsigned int head;  //针对buffer数组的索引  
    unsigned int tail;   //针对buffer数组的索引,当head和tail相等的时候,说明没事件  
    unsigned int packet_head; /* [future] position of the first element of next packet */  
    spinlock_t buffer_lock; /* protects access to buffer, head and tail */  
    struct wake_lock wake_lock;  
    bool use_wake_lock;  
    char name[28];  
    struct fasync_struct *fasync;   //异步通知函数  
    struct evdev *evdev;    //evdev设备  
    struct list_head node;   //evdev_client链表项  
    int clkid;  
    unsigned int bufsize;  
    struct input_event buffer[]; //一个input_event数据结构的数组,input_event代表一个事件  
};  

重要结构体之evdev:

<pre name="code" class="cpp">/*evdev结构体在配对成功的时候生成,由handler_connect生成*/ 
struct evdev {  
    int open;   //打开引用计数  
    int minor;  //次设备号  
    struct input_handle handle;  //关联的input_handle  
    wait_queue_head_t wait;    //等待队列  
    struct evdev_client __rcu *grab;  
    struct list_head client_list;  //evdev_client链表,说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问  
    spinlock_t client_lock; /* protects client_list */  
    struct mutex mutex;  
    struct device dev;  
    bool exist;  
};  

 

 
 
另外,input.h中还定义了可以支持哪些事件类型,这些只是大类事件,每个事件下还有具体区分: 

/*
 * Event types
 */

#define EV_SYN			0x00               //同步时间
#define EV_KEY			0x01              //绝对二进制值,如键盘或者按钮  
#define EV_REL			0x02             //绝对结果,如鼠标设备
#define EV_ABS			0x03            //绝对整数值,如TP,操纵杆
#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          //电源管理
#define EV_FF_STATUS		0x17       
#define EV_MAX			0x1f
#define EV_CNT			(EV_MAX&#
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值