linux驱动input子系统学习三(输入核心层)

输入核心层,是input子系统实现的核心。

对下(设备驱动层),提供设备注册接口,输入信息反馈接口。

对上(事件驱动层),提供事件注册接口,等。

一.先学习input子系统自己的实现。

注册input子系统本身很简单只需要在sysfs中注册号相应的设备类和主设备号即可。

下面有难度的是初始化input子系统的proc文件系统,但这不是我们这次分析的核心,也不是必须的,所以proc文件系统相关的我们就先不分析来。

static char *input_devnode(struct device *dev, mode_t *mode)
{
	return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
}

struct class input_class = {
	.name		= "input",
	.devnode	= input_devnode,
};

static int __init input_init(void)
{
	int err;

	input_init_abs_bypass();    /* 触摸屏类设备比较特殊,要先初始化一些数据 */

	err = class_register(&input_class);    /* 在sysfs中的class类下注册一个input的类 */
	if (err) {
		printk(KERN_ERR "input: unable to register input_dev class\n");
		return err;
	}

	err = input_proc_init();    /* 初始化proc文件系统 */
	if (err)
		goto fail1;

	err = register_chrdev(INPUT_MAJOR, "input", &input_fops);    /* 注册字符设备驱动 */
	if (err) {
		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
		goto fail2;
	}

	return 0;

 fail2:	input_proc_exit();
 fail1:	class_unregister(&input_class);
	return err;
}

取消注册就更简单来,和注册相反即可。

static void __exit input_exit(void)
{
	input_proc_exit();                        /* 卸载input的proc文件系统内的信息 */
	unregister_chrdev(INPUT_MAJOR, "input");  /* 注销该字符设备驱动 */
	class_unregister(&input_class);           /* 注销类 */
}

二.设备驱动层提供的接口函数学习。

1.设备描述结构体变量,同时初始化一些通用性数据。(不同设备特有的数据需要自己填充)


/**
 * input_allocate_device - allocate memory for new input device
 *
 * Returns prepared struct input_dev or NULL.
 *
 * NOTE: Use input_free_device() to free devices that have not been
 * registered; input_unregister_device() should be used for already
 * registered devices.
 */
struct input_dev *input_allocate_device(void)
{
	struct input_dev *dev;

	dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);    /* 申请内存 */
	if (dev) {        
		dev->dev.type = &input_dev_type;       /* 绑定设备信息 */
		dev->dev.class = &input_class;         /* 绑定在sysfs所属的类,后面的register里面的add_device后才能出现在sysfs下的input文件夹下 */
		device_initialize(&dev->dev);          /* 设备初始化 */
		mutex_init(&dev->mutex);
		spin_lock_init(&dev->event_lock);
		INIT_LIST_HEAD(&dev->h_list);         /* 初始化链表 */
		INIT_LIST_HEAD(&dev->node);

		__module_get(THIS_MODULE);
	}

	return dev;
}

2.设置dev设备的能力,只有注册前设置来它拥有的能力,将来该设备注册后,发送的信息才能被上报。

注意:该函数每次只能设置一个能力。

/* 根据type类型,设置code到相应的typebit */
/**
 * input_set_capability - mark device as capable of a certain event
 * @dev: device that is capable of emitting or accepting event
 * @type: type of the event (EV_KEY, EV_REL, etc...)
 * @code: event code
 *
 * In addition to setting up corresponding bit in appropriate capability
 * bitmap the function also adjusts dev->evbit.
 */
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
	switch (type) {
	case EV_KEY:
		__set_bit(code, dev->keybit);
		break;

	case EV_REL:
		__set_bit(code, dev->relbit);
		break;

	case EV_ABS:
		__set_bit(code, dev->absbit);
		break;

	case EV_MSC:
		__set_bit(code, dev->mscbit);
		break;

	case EV_SW:
		__set_bit(code, dev->swbit);
		break;

	case EV_LED:
		__set_bit(code, dev->ledbit);
		break;

	case EV_SND:
		__set_bit(code, dev->sndbit);
		break;

	case EV_FF:
		__set_bit(code, dev->ffbit);
		break;

	case EV_PWR:
		/* do nothing */
		break;

	default:
		printk(KERN_ERR
			"input_set_capability: unknown type %u (code %u)\n",
			type, code);
		dump_stack();
		return;
	}

	__set_bit(type, dev->evbit);
}

3.具体设备注册(需要前两步申请空间和填充能力后才能注册)


/**
 * input_register_device - register device with input core
 * @dev: device to be registered
 *
 * This function registers device with input core. The device must be
 * allocated with input_allocate_device() and all it's capabilities
 * set up before registering.
 * If function fails the device must be freed with input_free_device().
 * Once device has been successfully registered it can be unregistered
 * with input_unregister_device(); input_free_device() should not be
 * called in this case.
 */
int input_register_device(struct input_dev *dev)
{
	static atomic_t input_no = ATOMIC_INIT(0);
	struct input_handler *handler;
	const char *path;
	int error;

	/* Every input device generates EV_SYN/SYN_REPORT events. */
	__set_bit(EV_SYN, dev->evbit);    /* 通用的同步包 */

	/* KEY_RESERVED is not supposed to be transmitted to userspace. */
	__clear_bit(KEY_RESERVED, dev->keybit);

	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
	input_cleanse_bitmasks(dev);

	/*
	 * If delay and period are pre-set by the driver, then autorepeating
	 * is handled by the driver itself and we don't do it in input.c.
	 */
	init_timer(&dev->timer);    /* 重复上报功能数据填充 */
	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
		dev->timer.data = (long) dev;
		dev->timer.function = input_repeat_key;
		dev->rep[REP_DELAY] = 250;
		dev->rep[REP_PERIOD] = 33;
	}
    /* 下面继续填充结构体 */
	if (!dev->getkeycode)
		dev->getkeycode = input_default_getkeycode;

	if (!dev->setkeycode)
		dev->setkeycode = input_default_setkeycode;
    /* 设置设备名字,从input0开始,依次增大1 */
	dev_set_name(&dev->dev, "input%ld",
		     (unsigned long) atomic_inc_return(&input_no) - 1);

    /* 把该inputx设备加入到设备链表中,同时在sysfs的input文件夹系出现inputx以及我们初始化的name,phy等参数 */
	error = device_add(&dev->dev);
	if (error)
		return error;
    /* 打印调试信息,安装设备会出现 */
	path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
	printk(KERN_INFO "input: %s as %s\n",
		dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
	kfree(path);

	error = mutex_lock_interruptible(&input_mutex);
	if (error) {
		device_del(&dev->dev);
		return error;
	}
    /* 把该设备加入到核心层维护的两个重要链表之一的设备链表中去 */
	list_add_tail(&dev->node, &input_dev_list);
    /* 依次遍历另一条重要链表input_handler_list,看该设备能不能匹配到那个handler */
	list_for_each_entry(handler, &input_handler_list, node)
		input_attach_handler(dev, handler);    /*匹配,和链接两者  */

	input_wakeup_procfs_readers();            /* 匹配到了,则更新peoc文件系统 */

	mutex_unlock(&input_mutex);

	return 0;
}

4.handler和dev做匹配,如果匹配上,则把两者绑定。


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

	id = input_match_device(handler, dev);    /* 匹配handler和dev */
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);    /* 做具体的绑定handler和dev工作,由具体的事驱动层实现 */
	if (error && error != -ENODEV)
		printk(KERN_ERR
			"input: failed to attach handler %s to device %s, "
			"error: %d\n",
			handler->name, kobject_name(&dev->dev.kobj), error);

	return error;
}

5.匹配handler和dev

每一个事件驱动层在实现的时候都要实现一个struct input_device_id的表(数组),用来表明该事件驱动可以支持的设备。

struct input_device_id {

	kernel_ulong_t flags;    /* flags表明下面的四个要不要匹配,已经用相关宏定义好 */

	__u16 bustype;
	__u16 vendor;
	__u16 product;
	__u16 version;

	kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
	kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

	kernel_ulong_t driver_info;
};

如果填充时在handler里面的在flags标志里面置位了下面的某一个,则匹配时就会检查响应的(总线类型,厂商,设备号,设备版本)。如果没有置位相应位,则表明匹配时不检查响应的标志位。

#define INPUT_DEVICE_ID_MATCH_BUS	1
#define INPUT_DEVICE_ID_MATCH_VENDOR	2
#define INPUT_DEVICE_ID_MATCH_PRODUCT	4
#define INPUT_DEVICE_ID_MATCH_VERSION	8

同时也可以置位需要匹配类型,

#define INPUT_DEVICE_ID_MATCH_EVBIT	0x0010
#define INPUT_DEVICE_ID_MATCH_KEYBIT	0x0020
#define INPUT_DEVICE_ID_MATCH_RELBIT	0x0040
#define INPUT_DEVICE_ID_MATCH_ABSBIT	0x0080
#define INPUT_DEVICE_ID_MATCH_MSCIT	0x0100
#define INPUT_DEVICE_ID_MATCH_LEDBIT	0x0200
#define INPUT_DEVICE_ID_MATCH_SNDBIT	0x0400
#define INPUT_DEVICE_ID_MATCH_FFBIT	0x0800
#define INPUT_DEVICE_ID_MATCH_SWBIT	0x1000

下面就是真正的通过input_device_id来匹配


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;

    /* input_device_id是一个数组,从前向后依次遍历id_table中和dev里面的id和xxbit中完全匹配的 */
	for (id = handler->id_table; id->flags || id->driver_info; id++) {

		if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)   /* 正如前面描述的handler中id_table置位了相应标志位才做匹配检查 */
			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;
        /* 同一id_table里面的flags匹配成功,才能MATCH_BIT匹配 */
		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);
        /* 看handler层有没有再定义macth匹配函数,如果没有,那到这里就是已经找到id了,否则,还要通过handler里面的match才能确定就是该id */
		if (!handler->match || handler->match(handler, dev))    
			return id;
	}

	return NULL;
}

我们以某一个来分析MATCH_BIT宏。

#define MATCH_BIT(bit, max) \
		for (i = 0; i < BITS_TO_LONGS(max); i++) \
			if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
				break; \
		if (i != BITS_TO_LONGS(max)) \
			continue;

假设以keybit为例,宏替换后如下。可以发现,就是匹配handler里面的keybit值的dev里面keybit值。即每一项都要满足id_table中,该项(keybit的值)。即dev的key值可以有 1 2 3 4 5 6,handler中id_table可以只有1,2,3。这样也能匹配成功。

for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++) 
	if ((id->keybit[i] & dev->keybit[i]) != id->keybit[i]) 
		break; 
if (i != BITS_TO_LONGS(KEY_MAX)) 
	continue;

下面我们以evdev的id_table分别举例,方便上面的理解。

首先看evdev的id_table:可以发现,它里面除了driver_info其他都是空的。即evdev的handler可以匹配所有的device

即空的flags:不用匹配flags

空的xxbit,不用匹配xxbit

static const struct input_device_id evdev_ids[] = {
	{ .driver_info = 1 },	/* Matches all devices */
	{ },			/* Terminating zero entry */
};

6.input_register_device分析完毕,那就剩下一个unregister了。

它和register的顺序刚好相反,就不详细分析了。


/**
 * input_unregister_device - unregister previously registered device
 * @dev: device to be unregistered
 *
 * This function unregisters an input device. Once device is unregistered
 * the caller should not try to access it as it may get freed at any moment.
 */
void input_unregister_device(struct input_dev *dev)
{
	struct input_handle *handle, *next;

	input_disconnect_device(dev);

	mutex_lock(&input_mutex);

	list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
		handle->handler->disconnect(handle);
	WARN_ON(!list_empty(&dev->h_list));

	del_timer_sync(&dev->timer);
	list_del_init(&dev->node);

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);

	device_unregister(&dev->dev);
}

至此,和核心层中input子系统和device相关的已经分析完毕。

三.事件驱动层提供的接口函数学习

接下来我们分析handler部分

1.首先肯定还是handler的注册了


/**
 * input_register_handler - register a new input handler
 * @handler: handler to be registered
 *
 * This function registers a new input handler (interface) for input
 * devices in the system and attaches it to all input devices that
 * are compatible with the handler.
 */
int input_register_handler(struct input_handler *handler)
{
	struct input_dev *dev;
	int retval;

	retval = mutex_lock_interruptible(&input_mutex);
	if (retval)
		return retval;

	INIT_LIST_HEAD(&handler->h_list);    /* 初始化自身链表 */

	if (handler->fops != NULL) {
		if (input_table[handler->minor >> 5]) {    /* 每种handler的minor以32的倍数为base ,这里是检查当前handler类是不是已经注册过了,比如evdev的base是64,那么他就在input_table[2]中*/
			retval = -EBUSY;
			goto out;
		}
		input_table[handler->minor >> 5] = handler;    /* 上面检查没被注册过,测在这里注册进input_table中 */
	}

	list_add_tail(&handler->node, &input_handler_list); /* 把当前handler加入到input核心增维护的两条重要链表之一的handler链表中去 */
         /* 用当前的handler遍历核心层维护的两条重要链表之一的dev链表,并尝试匹配 */
	list_for_each_entry(dev, &input_dev_list, node)
		input_attach_handler(dev, handler);   

	input_wakeup_procfs_readers();        /* 更新proce文件系统 */

 out:
	mutex_unlock(&input_mutex);
	return retval;
}

匹配算法和device那边的完全一样(调用的同一个函数都)。

这里要说明的是为什么即在注册handler的时候匹配一遍,又要在注册device的时候匹配一次。

这是因为,通常系统不能确定是handler先注册,还是dev先注册。

假设只在注册dev的时候匹配handler(注册handler去掉匹配那几句代码  ),结果,devi先执行的,因为handler还没被注册,所以dev匹配失败。当注册handler的时候,因为没有了再次匹配,所以两者无法再接续到一块了。所以要在handler和dev注册都匹配一次,当然肯定是后面注册的才能匹配成。

2.还有一个就是卸载handler函数了,这个我们就不分析了和注册方向相反分析即可。


/**
 * input_unregister_handler - unregisters an input handler
 * @handler: handler to be unregistered
 *
 * This function disconnects a handler from its input devices and
 * removes it from lists of known handlers.
 */
void input_unregister_handler(struct input_handler *handler)
{
	struct input_handle *handle, *next;

	mutex_lock(&input_mutex);

	list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
		handler->disconnect(handle);    
	WARN_ON(!list_empty(&handler->h_list));

	list_del_init(&handler->node);

	if (handler->fops != NULL)
		input_table[handler->minor >> 5] = NULL;

	input_wakeup_procfs_readers();

	mutex_unlock(&input_mutex);
}

3.还有一个注册函数就是handle的注册(与其说注册,其实就是把handler和dev的链表加入到handle的数据中)


/**
 * input_register_handle - register a new input handle
 * @handle: handle to register
 *
 * This function puts a new input handle onto device's
 * and handler's lists so that events can flow through
 * it once it is opened using input_open_device().
 *
 * This function is supposed to be called from handler's
 * connect() method.
 */
int input_register_handle(struct input_handle *handle)
{
	struct input_handler *handler = handle->handler;
	struct input_dev *dev = handle->dev;
	int error;

	/*
	 * We take dev->mutex here to prevent race with
	 * input_release_device().
	 */
	error = mutex_lock_interruptible(&dev->mutex);
	if (error)
		return error;

	/*
	 * Filters go to the head of the list, normal handlers
	 * to the tail.
	 */
	if (handler->filter)
		list_add_rcu(&handle->d_node, &dev->h_list);
	else
		list_add_tail_rcu(&handle->d_node, &dev->h_list);   /* 把dev加入到handle */

	mutex_unlock(&dev->mutex);

	/*
	 * Since we are supposed to be called from ->connect()
	 * which is mutually exclusive with ->disconnect()
	 * we can't be racing with input_unregister_handle()
	 * and so separate lock is not needed here.
	 */
	list_add_tail_rcu(&handle->h_node, &handler->h_list);    /* 把handler加入到handle */

	if (handler->start)
		handler->start(handle);

	return 0;
}

4.既然有handle的注册,那当然有handle的卸载了。

/**
 * input_unregister_handle - unregister an input handle
 * @handle: handle to unregister
 *
 * This function removes input handle from device's
 * and handler's lists.
 *
 * This function is supposed to be called from handler's
 * disconnect() method.
 */
void input_unregister_handle(struct input_handle *handle)
{
	struct input_dev *dev = handle->dev;

	list_del_rcu(&handle->h_node);

	/*
	 * Take dev->mutex to prevent race with input_release_device().
	 */
	mutex_lock(&dev->mutex);
	list_del_rcu(&handle->d_node);
	mutex_unlock(&dev->mutex);

	synchronize_rcu();
}

RCU形式的锁机制,它允许多个执行单元对它同时对它进行读,但是多个执行单元对它进行写操作时,并不会让你随随便便就碰她,它会要求你先复制一个副本,要改要删随你便,反正你改的不是她本身。当所有的写单元都一一改完后,再统一写回,是不是比一般的自旋锁高级多了。不过不要轻易用它,系统开销较大。

猜你喜欢

转载自blog.csdn.net/qq_16777851/article/details/81229209