input 设备是通过input_register_device接口注册:
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);
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);//将本设备加入设备链表(这个链表是全局的)
list_for_each_entry(handler, &input_handler_list, node)//将本设备和已经存在的handler进行比较,与id相匹配的handler建立连接。
//需要说明的是设备可能跟多个handler连接,这样此设备产生的事件会分发给所有连接的handler
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
Input_device 的evbit 表示该设备所支持的事件。在这里将其EV_SYN 置位,即所有设备都支持这个事件.如果dev->rep[REP_DELAY]和dev->rep[REP_PERIOD]没有设值,则将其赋默认值。这主要是处理重复按键的.如果input device 没有定义getkeycode 和setkeycode.则将其赋默认值。这两个操作函数就可以用来取键的扫描码和设置键的扫描码。然后调用device_add()将input_dev 中封装的device 注册到sysfs
将input device 挂到input_dev_list 链表上.然后,对每一个挂在input_handler_list 的handler 调用input_attach_handler().在这里的情况有好比设备模型中的device 和driver 的匹配。所有的input device 都挂在input_dev_list 链上。所有的handle 都挂在input_handler_list 上。
看一下这个匹配的详细过程。匹配是在input_attach_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))//handler->blacklist中存储的是禁止连接的设备id,因此首先查看该设备是否允许连接
return -ENODEV;
id = input_match_device(handler->id_table, dev);//handler->id_table存储handler支持的设备id。如果能够找到匹配的id,则建立dev和handler之间的连接
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id);//建立dev和handler之间的连接
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;
}
如果handle 的blacklist 被赋值。要先匹配blacklist 中的数据跟dev->id 的数据是否匹配。匹配成功过后再来匹配handle->id
和dev->id 中的数据。如果匹配成功,则调用handler->connect().
来看一下具体的数据匹配过程,这是在input_match_device()中完成的。代码如下:
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++) {
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)//根据id->flag检查id是否匹配。id->flag记录需要匹配哪些域
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;
}
由此看到。在id->flags 中定义了要匹配的项。定义INPUT_DEVICE_ID_MATCH_BUS。则是要比较input device 和input handler 的总线类型。INPUT_DEVICE_ID_MATCH_VENDOR , INPUT_DEVICE_ID_MATCH_PRODUCT ,INPUT_DEVICE_ID_MATCH_VERSION 分别要求设备厂商。设备号和设备版本.如果id->flags 定义的类型匹配成功。或者是id->flags 没有定义,就会进入到MATCH_BIT 的匹配项了.从MATCH_BIT宏的定义可以看出。只有当iput device 和input handler 的id 成员在evbit, keybit,… swbit 项相同才会匹配成功。而且匹配的顺序是从evbit, keybit 到swbit.只要有一项不同,就会循环到id 中的下一项进行比较.简而言之,注册input device 的过程就是为input device 设置默认值,并将其挂以input_dev_list.与挂载在input_handler_list中的handler 相匹配。如果匹配成功,就会调用handler 的connect 函数.