1.4
input_dev
的註冊
在輸入裝置驅動的初始化函數的最後一步就是調用
input_register_device
註冊裝置。這個函數如
程式清單
1
.9
所示。
程式清單
1
.
9
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);
⑴
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;
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);
⑷
list_for_each_entry(handler,
&input_handler_list, node)
⑸
input_attach_handler(dev,
handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return
0;
}
下面就標記的幾點進行說明:
⑴
註冊同步事件為支援的類型,任何裝置都預設支援同步事件。
⑵
初始化裝置連擊計時器,如果驅動沒有填寫連擊參數就使用預設值。
⑶
如果驅動沒有實現映射修改和查看的函數,填充預設函數。
⑷
將本裝置加入裝置鏈表
(
這個鏈表是全域的
)
。
⑸
將本裝置和已經存在的
handler
進行比較,與
id
相匹配的
handler
建立串連。需要說明的是裝置可能跟多個
handler
串連,這樣此裝置產生的事件會分發給所有串連的
handler
。
可以看出上面第五步是最重要的一步,下面繼續分析
input_attach_handler
這個函數。它的代碼如
程式清單
1
.10
所示。
程式清單
1
.
10
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))
⑴
return
-ENODEV;
id =
input_match_device(handler->id_table, dev);
⑵
if (!id)
return
-ENODEV;
error =
handler->connect(handler, dev, id);
⑶
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;
}
需要說明的地方有三點:
⑴
handler->blacklist
中儲存的是禁止串連的裝置
id
,因此首先查看該裝置是否允許串連。
⑵
handler->id_table
儲存
handler
支援的裝置
id
。如果能夠找到匹配的
id
,則建立
dev
和
handler
之間的串連。
⑶
建立
dev
和
handler
之間的串連。
connect
函數的實現下章再講,下面看看
input_match_device
的實現。代碼如
程式清單
1
.11
所示。
程式清單
1
.
11
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]) /
⑴
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
(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->flag
檢查
id
是否匹配。
id->flag
記錄需要匹配哪些域。
⑶
檢查支援的事件種類是否一致。
第二種檢查用到的宏
MATCH_BIT
定義在
⑴
處。其中最重要的一句是“
if ((id->bit[i] &
dev->bit[i]) != id->bit[i])
”,這句話意味著
id
支援的事件種類是
dev
支援的事件的子集就算匹配了。如果某個
handler
的
id
除了
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
。下面繼續分析事件的傳遞。