linux输入子系统(3)

<!--[if !supportLists]-->1.4 <!--[endif]-->input_dev的注册

在输入设备驱动的初始化函数的最后一步就是调用input_register_device注册设备。这个函数如<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282018491 \h <span style='mso-element:field-separator'></span></span><![endif]-->程序清单 1.9<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000310038003400390031000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark:_Ref282018491'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282018491'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span><![endif]-->1<!--[if supportFields]><span style='mso-bookmark: _Ref282018491'></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282018491'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282018491'><span lang=EN-US> SEQ </span></span><span style='mso-bookmark:_Ref282018491'><span style='font-family:黑体;mso-ascii-font-family: Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element: field-separator'></span></span></span><![endif]-->9<!--[if supportFields]><span style='mso-bookmark:_Ref282018491'></span><span style='mso-element:field-end'></span><![endif]--> input_register_device

/* driver/input/input.c */

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 supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

init_timer(&dev->timer); <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 2 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

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) <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 3 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

dev->getkeycode = input_default_getkeycode;

if (!dev->setkeycode)

dev->setkeycode = input_default_setkeycode;

snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),

"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); <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 4 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

list_for_each_entry(handler, &input_handler_list, node) <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 5 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

input_attach_handler(dev, handler);

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

return 0;

}

下面就标记的几点进行说明:

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->注册同步事件为支持的类型,任何设备都默认支持同步事件。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 2 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->初始化设备连击计时器,如果驱动没有填写连击参数就使用默认值。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 3 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->如果驱动没有实现映射修改和查看的函数,填充默认函数。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 4 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->将本设备加入设备链表(这个链表是全局的)

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 5 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->将本设备和已经存在的handler进行比较,与id相匹配的handler建立连接。需要说明的是设备可能跟多个handler连接,这样此设备产生的事件会分发给所有连接的handler

可以看出上面第五步是最重要的一步,下面继续分析input_attach_handler这个函数。它的代码如<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282020091 \h <span style='mso-element:field-separator'></span></span><![endif]-->程序清单 1.10<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000320030003000390031000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark:_Ref282020091'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282020091'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span><![endif]-->1<!--[if supportFields]><span style='mso-bookmark: _Ref282020091'></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282020091'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282020091'><span lang=EN-US> SEQ </span></span><span style='mso-bookmark:_Ref282020091'><span style='font-family:黑体;mso-ascii-font-family: Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element: field-separator'></span></span></span><![endif]-->10<!--[if supportFields]><span style='mso-bookmark:_Ref282020091'></span><span style='mso-element:field-end'></span><![endif]--> input_attach_handler

/* driver/input/input.c */

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)) <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

return -ENODEV;

id = input_match_device(handler->id_table, dev); <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 2 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

if (!id)

return -ENODEV;

error = handler->connect(handler, dev, id); <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 3 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

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;

}

需要说明的地方有三点:

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]--> handler->blacklist中存储的是禁止连接的设备id,因此首先查看该设备是否允许连接。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 2 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]--> handler->id_table存储handler支持的设备id。如果能够找到匹配的id,则建立devhandler之间的连接。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 3 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->建立devhandler之间的连接。

connect函数的实现下章再讲,下面看看input_match_device的实现。代码如<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> REF _Ref282020868 \h <span style='mso-element:field-separator'></span></span><![endif]-->程序清单 1.11<!--[if gte mso 9]><xml> <w:data>08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F005200650066003200380032003000320030003800360038000000</w:data> </xml><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->所示。

程序清单 <!--[if supportFields]><span style='mso-bookmark:_Ref282020868'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282020868'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span>STYLEREF 1 \s <span style='mso-element:field-separator'></span></span></span><![endif]-->1<!--[if supportFields]><span style='mso-bookmark: _Ref282020868'></span><span style='mso-element:field-end'></span><![endif]-->.<!--[if supportFields]><span style='mso-bookmark:_Ref282020868'></span><span style='mso-element:field-begin'></span><span style='mso-bookmark:_Ref282020868'><span lang=EN-US> SEQ </span></span><span style='mso-bookmark:_Ref282020868'><span style='font-family:黑体;mso-ascii-font-family: Arial'>程序清单</span><span lang=EN-US> \* ARABIC \s 1 <span style='mso-element: field-separator'></span></span></span><![endif]-->11<!--[if supportFields]><span style='mso-bookmark:_Ref282020868'></span><span style='mso-element:field-end'></span><![endif]--> input_match_device

/* driver/input/input.c */

#define MATCH_BIT(bit, max) \

for (i = 0; i < BITS_TO_LONGS(max); i++) \

if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

break; \

if (i != BITS_TO_LONGS(max)) \

continue;

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) <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 2 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

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); <!--[if supportFields]><span lang=DE><span style='mso-element:field-begin'></span> = 3 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=DE><span style='mso-element:field-end'></span></span><![endif]-->

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;

}

匹配的过程主要做了两件事:

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 2 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->根据id->flag检查id是否匹配。id->flag记录需要匹配哪些域。

<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span><span style='mso-spacerun:yes'>&nbsp;</span>= 3 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->检查支持的事件种类是否一致。

第二种检查用到的宏MATCH_BIT定义在<!--[if supportFields]><span lang=EN-US><span style='mso-element:field-begin'></span> = 1 \* GB2 <span style='mso-element:field-separator'></span></span><![endif]--><!--[if supportFields]><span lang=EN-US><span style='mso-element:field-end'></span></span><![endif]-->处。其中最重要的一句是“if ((id->bit[i] & dev->bit[i]) != id->bit[i])”,这句话意味着id支持的事件种类是dev支持的事件的子集就算匹配了。如果某个handlerid除了id->driver_info之外的域都为0,那么此handler可以和任意dev匹配。实际上<内核>/driver/input/evdev.c中就是这么初始化id的。

现在总结一下input_dev注册的过程:一个input_dev注册的过程主要是在将自己加入input_dev_list,然后在input_handler_list中找到id和事件种类相匹配的handler并与之建立连接的过程。

input_dev产生的事件会分发给所有建立连接的handler。下面继续分析事件的传递。

你可能感兴趣的:(linux)