這節結合even handler來分析設備的注冊和打開的過程,在設備注冊之前,必須先初始化INPUT子系統,由input_init()函數來完成
相關閱讀:Linux Input子系統(上)--概述 http://www.linuxidc.com/Linux/2012-07/64419.htm
- static int __init input_init(void)
- {
- int err;
-
- input_init_abs_bypass();
-
- err = class_register(&input_class);//注冊input類
- if (err) {
- printk(KERN_ERR "input: unable to register input_dev class\n");
- return err;
- }
-
- err = input_proc_init();//創建/proc中的項
- if (err)
- goto fail1;
-
- /*注冊設備,設備號為INPUT_MAJOR(13),後面注冊的輸入設備都使用該主設備號*/
- err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
- if (err) {
- printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
- goto fail2;
- }
-
- return 0;
-
- fail2: input_proc_exit();
- fail1: class_unregister(&input_class);
- return err;
- }
input_fops中只定義了open函數。
- static const struct file_operations input_fops = {
- .owner = THIS_MODULE,
- .open = input_open_file,
- };
我們需要在設備驅動層中完成輸入設備的注冊,通過調用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;
- }
-
- /*沒有定義設備的getkeycode函數,則使用默認的獲取鍵值函數*/
- if (!dev->getkeycode)
- dev->getkeycode = input_default_getkeycode;
-
- /*沒有定義設備的setkeycode函數,則使用默認的設定鍵值函數*/
- if (!dev->setkeycode)
- dev->setkeycode = input_default_setkeycode;
-
- /*設定dev的名字*/
- 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;
- }
-
- /*將設備添加到input_dev_list設備鏈表*/
- list_add_tail(&dev->node, &input_dev_list);
-
- /*遍歷input_handler_list,試圖與每一個handler進行匹配*/
- list_for_each_entry(handler, &input_handler_list, node)
- input_attach_handler(dev, handler);
-
- input_wakeup_procfs_readers();
-
- mutex_unlock(&input_mutex);
-
- return 0;
- }
- static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
- {
- const struct input_device_id *id;
- int error;
-
- /*如果定義了handler的黑名單,並且設備和黑名單中的id匹配了,則該設備不能和handler匹配*/
- if (handler->blacklist && input_match_device(handler->blacklist, dev))
- return -ENODEV;
-
- id = input_match_device(handler->id_table, dev);
- if (!id)
- return -ENODEV;
-
- /*執行handler的connect,建立handler與設備之間的聯系*/
- 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;
- }