input_register_device()浅析

/** input系统中,分为: 设备驱动层 核心层 事件处理层将 input_dev结构体(表示一个输入设备) 注册到 核心层. 注意: 1: 这个input_dev必需由input_allocate_device()函数来分配 2:input_register_device()如果注册失败,必需调用input_free_device()来释放分配的空间 3:如果注册成功,在卸载函数中应该调用input_unregister_device()来注销input_devinput_dev = input_allocate_device(); if (!input_dev) { ret = -ENOMEM; return ret; } ..... ..... ret = input_register_device(input_dev); if (ret) { printk("ts-if: Could not register input device(touchscreen)!\n"); input_free_device(input_dev); return ret; }成功 : 返回 0 失败 : 返回非0值 */ int input_register_device(struct input_dev * dev) { /** 为生成设备节点序号做准备。 下面的代码会调用dev_set_name()来设置设备节点的名字 会在sysfs系统中以input0、input1、input2.....出现 */ static atomic_t input_no = ATOMIC_INIT(0); struct input_handler * handler; const char *path; /** struct input_dev { ... 设备支持的事件类型 每一个事件的类型都用一个位来表示 如果某一位被置 1 ,表示该设备支持这类事件 被值 0 ,表示该设备不支持这类事件 unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; } */ /* 将evbit的第0位置1 表示支持所有的事件 */ __set_bit(EV_SYN,dev->evbit); /** 如果驱动预先设置了延时,自动重复被驱动处理, 核心层就不做这件事了 */ init_timer(&dev->timer); if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { dev->timer.data = https://www.it610.com/article/(long) dev; dev->timer.function = input_repeat_key; dev->rep[REP_DELAY] = 250; dev->rep[REP_PERIOD] = 33; }/** 检查getkeycode函数有没有被定义。 如果没有定义,则使用默认的input_default_getkeycode. */ if (!dev->getkeycode) dev->getkeycode = input_default_getkeycode; //得到指定的键值/** 检查setkeycode函数有没有被定义。 如果没有定义,则使用默认的input_default_setkeycode. */ if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode; //设置键值//设置input_dev中的device的名字 dev_set_name(&dev->dev, "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); /** 任何一个设备的注册都会经过这个函数,设备驱动模型中的核心函数 */ error = device_add(&dev->dev); if (error) { return error; } /** 生成并返回设备的路径,调用者必需使用kfree()来释放结果 因为它的代码中有path = kzalloc(len, gfp_mask); */ 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); /** 获取锁---访问临界区---释放锁获取互斥锁且可以被信号打断,当正在等待锁的时信号到来了会返回EINTR */ error = mutex_lock_interruptible(&input_mutex); if (error) { device_del(&dev->dev); return error; } /** input_dev维护了两条链表 1 : input_dev_list链表,该链表包含了系统中所有的input_dev。 2 : input_handle_list链表 将input_dev添加到input_dev_list链表 */ list_add_tail(&dev->node, &input_dev_list); /** 遍历input_handler链表上,对链表中的每一个input_handler执行 input_attach_handler函数 */ list_for_each_entry(handler, &input_handler_list, node) { /** 匹配input_dev和input_handler。下面讲解。 */ input_attach_handler(dev, handler); }/** 当用户层调用poll()系统调用的时候,input_proc_devices_poll函数会被调用 static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) { poll_wait(file, &input_devices_poll_wait, wait); ... return 0; }唤醒读等待队列input_devices_poll_wait */ input_wakeup_procfs_readers(); //释放互斥锁 mutex_unlock(&input_mutex); return 0; }/** 用于匹配input_dev和input_handler 匹配成功的关键是 : handler中的blacklist、id_table 如果匹配成功,会调用handler的connect函数 */ static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) { /** //设备的标识,存储了设备的信息 struct input_device_id { kernel_ulong_t flags; //要匹配的项设备中的这些信息将要和input_handler中的id_table中定义的进行匹配 __u16 bustype; //总线类型 __u16 vendor; //制造商ID __u16 product; //产品ID __u16 version; //版本号 .... ... } */ const struct input_device_id * id; int error; id = input_match_device(handler,dev); if(!id) { return -ENODEV; } /** 一下是匹配成功后要执行的。调用handler的connect函数 */ err = handler->connect(handler,dev,id); if(error && error != -ENODEV) { pr_err("failed to attach handler %s to device %s, error: %d\n", handler->name, kobject_name(&dev->dev.kobj), error); } return error; }static const struct input_device_id *input_match_device(struct input_handler *handler, struct input_dev *dev) { const struct input_device_id *id; int i; /** id_table 表示驱动支持的设备列表id_table的出现,让一个handler支持多个input_dev变成了可能。evdev支持所有的设备 static const struct input_device_id evdev_ids[] = { { .driver_info = 1 },//匹配所有的设备 { }, }; keyboard支持的设备 static const struct input_device_id kbd_ids[] = { {//比较evbit .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT_MASK(EV_KEY) },//只要能产生按键类事件,就支持 },{ .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT_MASK(EV_SND) },//主要能产生声音就支持 },{ }, }; */ for (id = handler->id_table; id->flags || id->driver_info; id++) { //匹配总线类型 if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) //如果id_table[i]中支持的总线类型 与设备的标识中的总线类型不相符 //就比较id_table[i+1]项 if (id->bustype != dev->id.bustype) continue; //匹配制造商id if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) if (id->vendor != dev->id.vendor) continue; //匹配产品id 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); //下面有分析 if (!handler->match || handler->match(handler, dev)) return id; }return NULL; }static bool joydev_match(struct input_handler *handler, struct input_dev *dev) { /** evbit:设备支持哪些事件 EV_KEY : 0x01 evbit 是long类型 第0位被置1,表示支持所有事件。 某一位置1表示支持该事件 某一位为0标识不支持该事件test_bit(EV_KEY, dev->evbit) : 测试是否支持按键类事件 test_bit(BTN_TOUCH, dev->keybit)测试是否支持按键类事件中是否支持触摸 */ if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit)) return false; ..... return true; }

    推荐阅读