linux驱动input子系统学习二(框架)

input输入子系统如何工作?

例如以一次鼠标按下事件为例子来说明我们的input输入子系统的工作过程:

设备驱动层:当我们按下鼠标左键的时候就会触发中断(中断是早就注册好的),就会去执行中断所绑定的处理函数,在函数中就会去读取硬件寄存器来判断按下的是哪个按键和状态 ---->

将按键信息上报给input core层  ---> input core层处理好了之后就会上报给input event层,input event层会将我们的输入事件封装成一个input_event结构体放入一个缓冲区中 --->  

应用层read就会将缓冲区中的数据读取出去。

此外,还存在一个返回路径 (return path)。返回路径允许给一个键盘设置 LED,给一个 force feedback joystick提供 motion commands。路径的两个方向(指从内核到用户的方向和从用户到内核的方向)使用相同的 event定义和不同的 type identifier。

 

更进一步理解Input 子系统,需要理解以下4个对象:

Input_device , handler,  handle , client

Input_device:  代表着具体的输入设备,它直接从硬件中读取数据,并以事件的形式转发


/**
 * struct input_dev - represents an input device
 * @name: name of the device
 * @phys: physical path to the device in the system hierarchy
 * @uniq: unique identification code for the device (if device has it)
 * @id: id of the device (struct input_id)
 * @evbit: bitmap of types of events supported by the device (EV_KEY,
 *	EV_REL, etc.)
 * @keybit: bitmap of keys/buttons this device has
 * @relbit: bitmap of relative axes for the device
 * @absbit: bitmap of absolute axes for the device
 * @mscbit: bitmap of miscellaneous events supported by the device
 * @ledbit: bitmap of leds present on the device
 * @sndbit: bitmap of sound effects supported by the device
 * @ffbit: bitmap of force feedback effects supported by the device
 * @swbit: bitmap of switches present on the device
 * @keycodemax: size of keycode table
 * @keycodesize: size of elements in keycode table
 * @keycode: map of scancodes to keycodes for this device
 * @setkeycode: optional method to alter current keymap, used to implement
 *	sparse keymaps. If not supplied default mechanism will be used.
 *	The method is being called while holding event_lock and thus must
 *	not sleep
 * @getkeycode: optional method to retrieve current keymap. If not supplied
 *	default mechanism will be used. The method is being called while
 *	holding event_lock and thus must not sleep
 * @ff: force feedback structure associated with the device if device
 *	supports force feedback effects
 * @repeat_key: stores key code of the last key pressed; used to implement
 *	software autorepeat
 * @timer: timer for software autorepeat
 * @sync: set to 1 when there were no new events since last EV_SYNC
 * @abs: current values for reports from absolute axes
 * @rep: current values for autorepeat parameters (delay, rate)
 * @key: reflects current state of device's keys/buttons
 * @led: reflects current state of device's LEDs
 * @snd: reflects current state of sound effects
 * @sw: reflects current state of device's switches
 * @absmax: maximum values for events coming from absolute axes
 * @absmin: minimum values for events coming from absolute axes
 * @absfuzz: describes noisiness for axes
 * @absflat: size of the center flat position (used by joydev)
 * @absres: resolution used for events coming form absolute axes
 * @open: this method is called when the very first user calls
 *	input_open_device(). The driver must prepare the device
 *	to start generating events (start polling thread,
 *	request an IRQ, submit URB, etc.)
 * @close: this method is called when the very last user calls
 *	input_close_device().
 * @flush: purges the device. Most commonly used to get rid of force
 *	feedback effects loaded into the device when disconnecting
 *	from it
 * @event: event handler for events sent _to_ the device, like EV_LED
 *	or EV_SND. The device is expected to carry out the requested
 *	action (turn on a LED, play sound, etc.) The call is protected
 *	by @event_lock and must not sleep
 * @grab: input handle that currently has the device grabbed (via
 *	EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
 *	recipient for all input events coming from the device
 * @event_lock: this spinlock is is taken when input core receives
 *	and processes a new event for the device (in input_event()).
 *	Code that accesses and/or modifies parameters of a device
 *	(such as keymap or absmin, absmax, absfuzz, etc.) after device
 *	has been registered with input core must take this lock.
 * @mutex: serializes calls to open(), close() and flush() methods
 * @users: stores number of users (input handlers) that opened this
 *	device. It is used by input_open_device() and input_close_device()
 *	to make sure that dev->open() is only called when the first
 *	user opens device and dev->close() is called when the very
 *	last user closes the device
 * @going_away: marks devices that are in a middle of unregistering and
 *	causes input_open_device*() fail with -ENODEV.
 * @dev: driver model's view of this device
 * @h_list: list of input handles associated with the device. When
 *	accessing the list dev->mutex must be held
 * @node: used to place the device onto input_dev_list
 */
struct input_dev {
	const char *name;        /* 设备名称 */
	const char *phys;        /* z设备在分层系统的路径 */
	const char *uniq;
	struct input_id 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,
			  unsigned int scancode, unsigned int keycode);
	int (*getkeycode)(struct input_dev *dev,
			  unsigned int scancode, unsigned int *keycode);

	struct ff_device *ff;

	unsigned int repeat_key;      /* 重复上报键值,比如:键盘一直按着A不松手 */
	struct timer_list timer;      /* 重复上报的时间 */

	int sync;

	int abs[ABS_CNT];
	int rep[REP_MAX + 1];

	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 absmax[ABS_CNT];
	int absmin[ABS_CNT];
	int absfuzz[ABS_CNT];
	int absflat[ABS_CNT];
	int absres[ABS_CNT];

	int (*open)(struct input_dev *dev);    /* 设备具体的open函数 */
	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 *grab;

	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	struct device dev;

	struct list_head	h_list;        /* 用来挂接这个struct input_dev和所有struct handler的链表头 */
	struct list_head	node;   /* 作为链表节点挂接到  input_dev_list 链表上  (input_dev_list链表是input核心层维护的一个用来挂接所有input设备的一个链表头) */
};

Hanler:  代表接收某一类事件的上层接口,对应于一类事件设备文件


/**
 * struct input_handler - implements one of interfaces for input devices
 * @private: driver-specific data
 * @event: event handler. This method is being called by input core with
 *	interrupts disabled and dev->event_lock spinlock held and so
 *	it may not sleep
 * @filter: similar to @event; separates normal event handlers from
 *	"filters".
 * @match: called after comparing device's id with handler's id_table
 *	to perform fine-grained matching between device and handler
 * @connect: called when attaching a handler to an input device
 * @disconnect: disconnects a handler from input device
 * @start: starts handler for given handle. This function is called by
 *	input core right after connect() method and also when a process
 *	that "grabbed" a device releases it
 * @fops: file operations this driver implements
 * @minor: beginning of range of 32 minors for devices this driver
 *	can provide
 * @name: name of the handler, to be shown in /proc/bus/input/handlers
 * @id_table: pointer to a table of input_device_ids this driver can
 *	handle
 * @h_list: list of input handles associated with the handler
 * @node: for placing the driver onto input_handler_list
 *
 * Input handlers attach to input devices and create input handles. There
 * are likely several handlers attached to any given input device at the
 * same time. All of them will get their copy of input event generated by
 * the device.
 *
 * The very same structure is used to implement input filters. Input core
 * allows filters to run first and will not pass event to regular handlers
 * if any of the filters indicate that the event should be filtered (by
 * returning %true from their filter() method).
 *
 * Note that input core serializes calls to connect() and disconnect()
 * methods.
 */
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);    /*  函数用来匹配handler 与 input_dev 设备 */
	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);        /* 当handler 与 input_dev 匹配成功之后用来连接 */
	void (*disconnect)(struct input_handle *handle);    /* 断开handler 与 input_dev 之间的连接 */
	void (*start)(struct input_handle *handle);

	const struct file_operations *fops;
	int minor;            /* 该handler 的编号 (在input_table 数组中用来计算数组下标) input_table数组就是input子系统用来管理注册的handler的一个数据结构 */
	const char *name;

	const struct input_device_id *id_table;         /* 里面放置着dev和本handler能匹配在一起的信息 */

	struct list_head	h_list;    /* 用来挂接handler 上连接的所有handle 的一个链表头 */
	struct list_head	node;    /* 作为一个链表节点挂接到 input_handler_list 链表上(input_handler_list 链表是一个由上层handler参维护的一个用来挂接所有注册的handler的链表头) */
};

Handle : 用于将input_device 和  handler 连接起来,对应于某1个具体的设备文件。


/**
 * struct input_handle - links input device with an input handler
 * @private: handler-specific data
 * @open: counter showing whether the handle is 'open', i.e. should deliver
 *	events from its device
 * @name: name given to the handle by handler that created it
 * @dev: input device the handle is attached to
 * @handler: handler that works with the device through this handle
 * @d_node: used to put the handle on device's list of attached handles
 * @h_node: used to put the handle on handler's list of handles from which
 *	it gets events
 */
struct input_handle {

	void *private;            /* handle  的私有数据 */

	int open;                 /* 这个也是用来做打开计数的 */
	const char *name;

	struct input_dev *dev;    /*  用来指向该handle 绑定的input_dev 结构体 */
	struct input_handler *handler;    /* 用来指向该handle 绑定的 handler 结构体 */

	struct list_head	d_node;    /* 把它对应的dev里面的hlist与该handle绑定上 */
	struct list_head	h_node;    /* 把它对应的handler里面的hlist与该handle绑定 */
};

Client:  对应于用户程序对文件的访问接口,每open一次事件驱动,就创建一个client.

struct evdev_client {
	struct input_event buffer[EVDEV_BUFFER_SIZE];    /* 缓冲数据 */
	int head;                    /* 为buffer做环形队列做标记 */
	int tail;                    /* 当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链表项 */
	struct wake_lock wake_lock;
	char name[28];
};

 

input子系统的核心层维护着两条中要的链表

static LIST_HEAD(input_dev_list);        /* 记录所有的输入设备 */
static LIST_HEAD(input_handler_list);    /* 记录所有的事件驱动 */

每当一个新的设备或者一个新的事件驱动被系统加载(调用input_register_device()或 input_register_driver()),都会扫描整个链表,并调用函数input_match_device(struct input_handler *handler, struct input_dev *dev)  尝试配对工作。Input_handler-->id_table   记录了需要匹配的特征。

 

下面我放一张图来表明上面几个的关系,图参考自下面这篇博客,里面也讲的很清晰

https://www.cnblogs.com/deng-tao/p/6094049.html

这个图对层次结构已经讲的很清晰了,后面的具体代码分析也可以对照这张图来分析。我主要把注意点说一下。

1.一个dev可以对应不只一个handler,比如一个mouse设备既可以匹配到mousedev里面的handler又可以匹配到evdev里面的handler,对应于上图的dev1,一个dev对应两个handler就必须有两个handle来连接它们。

2.一个dev设备也可以只对应一个handler,比如我们自行定义的输入设备就只让匹配evdev里面的handler

 

 

input的核心层还一个8个数据的数组,里面放着已经注册的某一类的处理接口(如:mouse,event等)

static struct input_handler *input_table[8];

为什么是8?

这是因为目前常用的handler只有三种,evdev,mousedev,joydev,这么三个,而且evdev可以通用,所以定义8个肯定够用了。

定义了8个后,因为次设备号只有256个。所以平均每个设备类的次设备号最多就32个。

 

下面是系统目前为设备定义的次设备号信息。

#define JOYDEV_MINOR_BASE	0        /* 游戏手柄类次设备号开始位置 */
#define JOYDEV_MINORS		16       /* 游戏手柄类次设备号个数 */

#define MOUSEDEV_MINOR_BASE	32       /*鼠标类次设备号开始位置 */
#define MOUSEDEV_MINORS		32       /* 鼠标类次设备号个数 */

#define EVDEV_MINOR_BASE	64       /*通用事件类次设备号开始位置 */
#define EVDEV_MINORS		32       /*通用事件类次设备号个数 */

 

可以看到每个设备类的次涉笔号的基址都是32的倍数,后面我们会用到这个32为倍数的基址。

 

你可能感兴趣的:(linux驱动,input子系统)