linux驱动开发扩展--输入核心层源码分析

 drivers/input/input.c

static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);

关于LIST_HEAD的定义可参考misc类设备驱动开发详解

定义了input_dev_list链表用来记录所有内核中注册了的input类设备。当我们向内核注册一个input类设备时,内核就会向input_dev_list链表中insert一个节点。 

定义了一个input_handler_list链表用来记录内核中注册了的handler。这些handler是在输入事件驱动层对应的源码中被注册进去的。可参考输入事件驱动层源码分析

 struct input_dev

包含了一个input设备的相关数据和操作方法 

成员:

  • unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; 设备所支持的事件类型
  • unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; EV_KEY事件类型所支持的code
  • unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; EV_REL事件类型所支持的code
  • 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)];

以上这些xxbit表示设备所支持的事件类型以及每种事件类型所支持的code值

数组结构的定义和划分方式,以evbit为例

EV_CNT表示内核中定义的支持的事件类型的种类,每一类放在一个bit位中表示,支持这个事件类型则在该位标记1,不支持则标记0。这里定义的是一个unsigned long类型的数组,对于32位系统每个unsigned long类型的变量中有32个bit,所以包含32种事件类型。那么EV_CNT种可以被多少个unsigned long所表示呢,答案就是BITS_TO_LONGS(EV_CNT)个

struct input_handler

包含了一个input handler的相关数据和操作方法 

输入事件驱动层源码分析

struct input_handle

struct input_handle {

	void *private;

	int open;
	const char *name;

	struct input_dev *dev;
	struct input_handler *handler;

	struct list_head	d_node;
	struct list_head	h_node;
};

当一个device和一个handler匹配上之后就会在这里做一个记录

struct list_head    d_node;和struct list_head    h_node;分别用来记录device和handler的链表节点

input_init

(1)class_register。input类的注册,对应/sys/class/input文件夹

(2)input_proc_init。该函数内部主要就是创建了/proc/bus/input文件件和它下面的属性文件以及绑定操作方法

(3)register_chrdev。注册设备

err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
#define INPUT_MAJOR		13
static const struct file_operations input_fops = {
	.owner = THIS_MODULE,
	.open = input_open_file,
};

input_open_file函数中并不直接操作硬件,而是使用函数指针的方式间接调用操作硬件的函数 

设备驱动层的接口函数
(1)input_allocate_device。struct input_dev类型变量的内存空间的申请和部分特定得泛型成员的初始化
(2)input_set_capability。为输入类设备上报的数据设置type和code
(3)input_register_device。向核心层注册设备

input_register_device

 (1)添加了EV_SYN同步事件

__set_bit(EV_SYN, dev->evbit);

(2)设置设备对应文件夹名字,可以在/sys/class/input下看到inputx的文件夹(注意这里只是符号链接文件,真正的文件在/sys/device/...下)

dev_set_name(&dev->dev, "input%ld",
		     (unsigned long) atomic_inc_return(&input_no) - 1);

(3)调用了device_add添加设备

error = device_add(&dev->dev);

(4)将设备添加到管理所有input设备的链表

list_add_tail(&dev->node, &input_dev_list);

(5)遍历input_handler_list进行handler和device的匹配和连接

list_for_each_entry(handler, &input_handler_list, node)
		input_attach_handler(dev, handler);

 

input_attach_handler

(1) 匹配device和handler

id = input_match_device(handler, dev);

(2)连接

error = handler->connect(handler, dev, id);

 

input_match_device

static const struct input_device_id *input_match_device(struct input_handler *handler,
							struct input_dev *dev)
{
	const struct input_device_id *id;
	int i;

	for (id = handler->id_table; id->flags || id->driver_info; id++) {

		if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
			if (id->bustype != dev->id.bustype)
				continue;

		if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
			if (id->vendor != dev->id.vendor)
				continue;

		if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
			if (id->product != dev->id.product)
				continue;

		if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
			if (id->version != dev->id.version)
				continue;

		MATCH_BIT(evbit,  EV_MAX);
		MATCH_BIT(keybit, KEY_MAX);
		MATCH_BIT(relbit, REL_MAX);
		MATCH_BIT(absbit, ABS_MAX);
		MATCH_BIT(mscbit, MSC_MAX);
		MATCH_BIT(ledbit, LED_MAX);
		MATCH_BIT(sndbit, SND_MAX);
		MATCH_BIT(ffbit,  FF_MAX);
		MATCH_BIT(swbit,  SW_MAX);

		if (!handler->match || handler->match(handler, dev))
			return id;
	}

	return NULL;
}

 遍历handler的id_table数组中的每个struct input_device_id类型的成员,首先根据flags进行判断,接着进行xxbit的匹配,最后当handler中的match函数指针不为NULL时去执行它,匹配上后返回id

handler中的id_table中包含了该handler与device匹配时相关的值,主要用于匹配时判断device和handler是否能够匹配上

事件驱动层的接口函数

(1)input_register_handler。注册一个新的handler

(2)input_register_handle。用来处理device和handler之间的一些东西

 input_table

static struct input_handler *input_table[8];

该数组中的每个元素都代表了一类input handler,最大可以有8个成员,所以内核中最大支持8类handler。

该数组中的每个成员实际上是一类handler的第一个handler

内核中可以有许多个handler,他们必须属于这8类中的一类。

每一类handler理论上最大能包含32个handler,每一类handler所对应的设备的次设备号范围分别是0-31,32-63,64-95,96-127,128-159,160-191,192-223,224-255。具体的原因见input_register_handler函数的内部实现

input_register_handler

int input_register_handler(struct input_handler *handler);

(1) 

INIT_LIST_HEAD(&handler->h_list);

初始化链表节点

(2)

if (handler->fops != NULL) {
		if (input_table[handler->minor >> 5]) {
			retval = -EBUSY;
			goto out;
		}
		input_table[handler->minor >> 5] = handler;
}

当handler的fops成员不是NULL时

当input_table[handler->minor >> 5]不为NULL时退出,否则设置input_table[handler->minor >> 5]为传入的handler

这里input_table数组下标中minor右移5位相当于除了一个32,所以每一类handler最大能包含32个handler,他们对应的设备次设备号范围也得到了

(3) 

list_add_tail(&handler->node, &input_handler_list);

将这个handler节点加入到input_handler_list链表中

(4)

list_for_each_entry(dev, &input_dev_list, node)
		input_attach_handler(dev, handler);

遍历input_dev_list进行handler和device的匹配和连接,这里和input_register_device函数中十分相似。可以看出,不论是device先注册还是handler先注册,都会在最新注册的时候去匹配和连接。

(5)

input_wakeup_procfs_readers();

proc文件系统相关的

input_register_handle

int input_register_handle(struct input_handle *handle);

 注册一个新的handle,应该是用来统筹管理device和handler的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值