linux input子系统 -- 03 找到正确的handler

handler都有什么?搜索源码 

drivers/macintosh/mac_hid.c:   err = input_register_handler(&mac_hid_emumouse_handler);
net/rfkill/input.c:    return input_register_handler(&rfkill_handler);
drivers/tty/sysrq.c:   error = input_register_handler(&sysrq_handler);
drivers/input/input-leds.c:    return input_register_handler(&input_leds_handler);
drivers/input/evdev.c: return input_register_handler(&evdev_handler);
drivers/input/evbug.c: return input_register_handler(&evbug_handler);
drivers/input/apm-power.c:     return input_register_handler(&apmpower_handler);
drivers/input/joydev.c:        return input_register_handler(&joydev_handler);
drivers/input/mousedev.c:      error = input_register_handler(&mousedev_handler);

对于一个input设备我们要为其找一个合适的事件处理者(handler)

我们这里选择evdev_handler,因为它无条件匹配所有的input设备

static struct input_handler evdev_handler = {
        .event          = evdev_event,
        .events         = evdev_events,
        .connect        = evdev_connect,
        .disconnect     = evdev_disconnect,
        .legacy_minors  = true,
        .minor          = EVDEV_MINOR_BASE,
        .name           = "evdev",
        .id_table       = evdev_ids,
};

分析handler的注册 

input_register_handler()

int input_register_handler(struct input_handler *handler)
{
        struct input_dev *dev;
        int error;

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

        INIT_LIST_HEAD(&handler->h_list);

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

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

        input_wakeup_procfs_readers();

        mutex_unlock(&input_mutex);
        return 0;
}

首先将handler挂载到input_handler_list上,然后遍历input_dev_list,与已经注册的input设备进行匹配,匹配函数input_attach_handler

input_register_handler() -> input_attach_handler()

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);
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);
	if (error && error != -ENODEV)
		pr_err("failed to attach handler %s to device %s, error: %d\n",
		       handler->name, kobject_name(&dev->dev.kobj), error);

	return error;
}

这里先分析input_match_device

input_register_handler() -> input_attach_handler() -> 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;

	for (id = handler->id_table; id->flags || id->driver_info; id++) {
		if (input_match_device_id(dev, id) &&
		    (!handler->match || handler->match(handler, dev))) {
			return id;
		}
	}

	return NULL;
}

对于id_table,这里分析的evdev_handler对应的是 evdev_ids,其原型如下

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

可以看到只有个driver_info,没有flags,接着跟进分析 input_match_device_id,这里的id表示的是id_table

bool input_match_device_id(const struct input_dev *dev,
			   const struct input_device_id *id)
{
	if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
		if (id->bustype != dev->id.bustype)
			return false;

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

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

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

	if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX) ||
	    !bitmap_subset(id->keybit, dev->keybit, KEY_MAX) ||
	    !bitmap_subset(id->relbit, dev->relbit, REL_MAX) ||
	    !bitmap_subset(id->absbit, dev->absbit, ABS_MAX) ||
	    !bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX) ||
	    !bitmap_subset(id->ledbit, dev->ledbit, LED_MAX) ||
	    !bitmap_subset(id->sndbit, dev->sndbit, SND_MAX) ||
	    !bitmap_subset(id->ffbit, dev->ffbit, FF_MAX) ||
	    !bitmap_subset(id->swbit, dev->swbit, SW_MAX) ||
	    !bitmap_subset(id->propbit, dev->propbit, INPUT_PROP_MAX)) {
		return false;
	}

	return true;
}

可以看到flags中会有这些标志,之前input设备注册的时候,还讨论过vendor,product,version作用是什么,这里随便没有去匹配,但是可以知道通过这些变量可以匹配到特殊的handler

对于其中的bitmap_subset来说,以bitmap_subset(id->evbit, dev->evbit, EV_MAX)为例,

主要判断就是id->evbit中标记的事件必须等同或者是dev->evbit中标记事件的子集,下面对应的具体事件也是如此。

对于id_table中都为空的情况,空集是任何集合的子集,是任何非空集合的真子集,所以一样满足。

input_match_device_id满足,接着分析handler的match函数,如果有match的话,这里没有。

此时可以认为input_match_device 函数满足,返回input_attach_handler()

input_register_handler() -> input_attach_handler()

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);
	if (!id)
		return -ENODEV;

	error = handler->connect(handler, dev, id);
	if (error && error != -ENODEV)
		pr_err("failed to attach handler %s to device %s, error: %d\n",
		       handler->name, kobject_name(&dev->dev.kobj), error);

	return error;
}

继续分析connect函数

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
			 const struct input_device_id *id)
{
	struct evdev *evdev;
	int minor;
	int dev_no;
	int error;

	minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);
	if (minor < 0) {
		error = minor;
		pr_err("failed to reserve new minor: %d\n", error);
		return error;
	}

	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
	if (!evdev) {
		error = -ENOMEM;
		goto err_free_minor;
	}

	INIT_LIST_HEAD(&evdev->client_list);
	spin_lock_init(&evdev->client_lock);
	mutex_init(&evdev->mutex);
	init_waitqueue_head(&evdev->wait);
	evdev->exist = true;

	dev_no = minor;
	/* Normalize device number if it falls into legacy range */
	if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
		dev_no -= EVDEV_MINOR_BASE;
	dev_set_name(&evdev->dev, "event%d", dev_no);

	evdev->handle.dev = input_get_device(dev);
	evdev->handle.name = dev_name(&evdev->dev);
	evdev->handle.handler = handler;
	evdev->handle.private = evdev;

	evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);
	evdev->dev.class = &input_class;
	evdev->dev.parent = &dev->dev;
	evdev->dev.release = evdev_free;
	device_initialize(&evdev->dev);

	error = input_register_handle(&evdev->handle);
	if (error)
		goto err_free_evdev;

	cdev_init(&evdev->cdev, &evdev_fops);

	error = cdev_device_add(&evdev->cdev, &evdev->dev);
	if (error)
		goto err_cleanup_evdev;

	return 0;
}

这个connect函数主要做了3件事情

  1. 申请副设备号,并将副设备号作为event的编号
  2. 初始化handle,通过handle关连input设备和handler,同时注册handle
  3. 注册eventX,其对应的fops是evdev_fops

这里分析一下handle的注册

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);

	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);

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

	return 0;
}

对应handler->filter,filter是过滤器的意思,如果有filter则将handle挂载到dev->h_list的头部,没有的话则挂载到尾部,有种优先的感觉,具体的作用遇到再分析,这里还不知道。

同时将handle挂载到handler->h_list,具体作用?

最后如果handler有start方法,则调用start方法,当前的handler没有。

以上就完成了handler的注册,进而引发了input设备和handler的匹配过程,最终注册了eventX节点。

该篇文章中只是分析了一个handler,对于一个input设备匹配多个handler的情况,后面单独再分析。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值