概述
我们先看下input的注册过程:
input_register_device(input_dev):
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;
__set_bit(EV_SYN, dev->evbit);//支持同步事件
/*
* 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;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);//按顺序地去定义input序号
error = device_add(&dev->dev);//将input dev添加到sys系统中,包括创建一些input的属性文件
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);//这里路径是上面device_add产生的
printk(KERN_INFO "input: %s as %sn",
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设备列表里面
list_for_each_entry(handler, &input_handler_list, node)//对input handler列表中的每个handler都进行匹配,这里input_handler_list怎么来的呢?我们在 input_register_handler找到它的形成过程
input_attach_handler(dev, handler);//匹配dev和handler
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
我们看下input_attach_handler(dev, handler):
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id;
int error;
if (handler->blacklist && input_match_device(handler->blacklist, dev))//如果在黑名单里面就返回
return -ENODEV;
id = input_match_device(handler->id_table, dev);//匹配handler->id_table和dev
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id);//调用handler的connect连接handler、 dev,这个函数很重要,起到了承上启下的作用。
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %dn",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
input_match_device(handler->id_table, dev):
static const struct input_device_id *input_match_device(const struct input_device_id *id,
struct input_dev *dev)
{
int i;
for (; id->flags || id->driver_info; id++) {//对handler中的每个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);
return id;
}
return NULL;
}
该函数会对handler中的每个id都进行查询,先根据id->flags设置去比较,然后比较具体的位,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;
可以看出来是id->bit[i]与dev->bit[i]比较。
从整体上看,匹配的过程还算比较简单。分析中有几个新的地方input_handler_list和handler->connect。
其实这些都是input子系统最顶层做的工作,最顶层可以有evdev,joydev,mousedev等,当然用户完全可以构建一个自己的dev。我们就挑选evdev做分析吧,也是最常用的一种。
static const struct input_device_id evdev_ids[] = {//还记得上面匹配函数里面用到的id吗?就是它哦
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,//看到了吧,匹配函数中的handler->connect
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
evdev初始化是注册了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]) {
retval = -EBUSY;
goto out;
}
input_table[handler->minor >> 5] = handler;//放到input_table
}
list_add_tail(&handler->node, &input_handler_list);//添加到handler列表中,这样就形成了input_handler_list
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);//这边也进行匹配了,所以无论是handler还是dev注册都会调用匹配函数
input_wakeup_procfs_readers();
out:
mutex_unlock(&input_mutex);
return retval;
}
我们下面分析一下evdev_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 error;
for (minor = 0; minor < EVDEV_MINORS; minor++)//找到一个空的minor
if (!evdev_table[minor])
break;
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devicesn");
return -ENFILE;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor);//evdev的名字,即event*
evdev->exist = 1;
evdev->minor = minor;
evdev->handle.dev = input_get_device(dev);//将dev赋值给handle
evdev->handle.name = dev_name(&evdev->dev);
evdev->handle.handler = handler;//将handler赋值给handle
evdev->handle.private = evdev;
//可以看出handle将dev和handler联系到一块了
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + 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);//注册handle,其实就是将handle再跟dev和handler分别联系起来,这样三者就真正地互相联系到一块了
if (error)
goto err_free_evdev;
error = evdev_install_chrdev(evdev);//把evdev添加到evdev_table中
if (error)
goto err_unregister_handle;
error = device_add(&evdev->dev);//将evdev添加到/sys/中
if (error)
goto err_cleanup_evdev;
return 0;
err_cleanup_evdev:
evdev_cleanup(evdev);
err_unregister_handle:
input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
return error;
}
我们先解释input_register_handle(&evdev->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;
list_add_tail_rcu(&handle->d_node, &dev->h_list);//将handle添加到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(&handle->h_node, &handler->h_list);//将handle添加到handler的h_list
if (handler->start)
handler->start(handle);
return 0;
}
将handle分别添加到dev和handler的h_list中,这样三者真正地联系起来了,可以互相访问。
我们可以看到evdev才是真正用户可以操作的设备,evdev中的handle把handler和dev联系到了一块,同时将evdev添加到了sys中。
最后
以上就是无奈柚子为你收集整理的我对linux理解之input一的全部内容,希望文章能够帮你解决我对linux理解之input一所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复