input子系统中重要结构体分析

来源:互联网 发布:任务管理器修复软件 编辑:程序博客网 时间:2024/05/22 06:17
在input.h中定义了input_dev描述一个具体的input设备struct input_dev {const char *name;const char *phys;const char *uniq;struct input_id id;unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//设备所支持的事件unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//KEY事件支持的编码unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//REL事件支持的编码unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];unsigned long swbit[BITS_TO_LONGS(SW_CNT)];unsigned int hint_events_per_packet;unsigned int keycodemax;unsigned int keycodesize;void *keycode;int (*setkeycode)(struct input_dev *dev,  const struct input_keymap_entry *ke,  unsigned int *old_keycode);int (*getkeycode)(struct input_dev *dev,  struct input_keymap_entry *ke);struct ff_device *ff;unsigned int repeat_key;struct timer_list timer;int rep[REP_CNT];struct input_mt_slot *mt;int mtsize;int slot;int trkid;struct input_absinfo *absinfo;unsigned long key[BITS_TO_LONGS(KEY_CNT)];unsigned long led[BITS_TO_LONGS(LED_CNT)];unsigned long snd[BITS_TO_LONGS(SND_CNT)];unsigned long sw[BITS_TO_LONGS(SW_CNT)];int (*open)(struct input_dev *dev);void (*close)(struct input_dev *dev);int (*flush)(struct input_dev *dev, struct file *file);int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);struct input_handle __rcu *grab;spinlock_t event_lock;struct mutex mutex;unsigned int users;bool going_away;bool sync;struct device dev;struct list_headh_list;//handle的链表struct list_headnode;};input_handler为input设置提供接口struct input_handler {void *private;void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//当有事件的时候被input core调用bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//分离出常规事件bool (*match)(struct input_handler *handler, struct input_dev *dev);//当匹配handler和设备的时候调用int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);//当handler和设备匹配的后调用void (*disconnect)(struct input_handle *handle);void (*start)(struct input_handle *handle);//在connect之后调用startconst struct file_operations *fops;int minor;const char *name;const struct input_device_id *id_table;struct list_headh_list;//handle的链表struct list_headnode;};input_handle是关联设备和handler的桥梁struct input_handle {void *private;int open;//打开标志const char *name;struct input_dev *dev;struct input_handler *handler;struct list_headd_node;//input_dev的链表struct list_headh_node;//handler的链表};在知道这3个结构体以后,我们开始分析input.c的代码先看input的入口和出口static int __init input_init(void){int err;err = class_register(&input_class);//向内核注册一个类,用于linux设备模型,注册后会在/sys/class/下面出现input目录if (err) {pr_err("unable to register input_dev class\n");return err;}err = input_proc_init();//与proc文件系统有关if (err)goto fail1;/*注册字符设备,主设备号为13表示input设备,可以在/proc/devices下看到*/err = register_chrdev(INPUT_MAJOR, "input", &input_fops);if (err) {pr_err("unable to register char major %d", INPUT_MAJOR);goto fail2;}return 0; fail2:input_proc_exit(); fail1:class_unregister(&input_class);return err;}static void __exit input_exit(void){input_proc_exit();unregister_chrdev(INPUT_MAJOR, "input");class_unregister(&input_class);}subsys_initcall(input_init);module_exit(input_exit);在注册input的时候绑定的操作函数集static const struct file_operations input_fops = {.owner = THIS_MODULE,.open = input_open_file,.llseek = noop_llseek,};这里主要看 input_open_filestatic int input_open_file(struct inode *inode, struct file *file){struct input_handler *handler;const struct file_operations *old_fops, *new_fops = NULL;int err;err = mutex_lock_interruptible(&input_mutex);if (err)return err;/* No load-on-demand here? */handler = input_table[iminor(inode) >> 5];//获得handler,因为每个注册的handler都会把自己注册到input_table这个数组里,下标右移5位表示除以32,因为每个handler最大可以处理32个设备,所以是以32为倍数对齐if (handler)new_fops = fops_get(handler->fops);//获得handler的操作函数集mutex_unlock(&input_mutex);/* * That's _really_ odd. Usually NULL ->open means "nothing special", * not "no device". Oh, well... */if (!new_fops || !new_fops->open) {fops_put(new_fops);err = -ENODEV;goto out;}old_fops = file->f_op;file->f_op = new_fops;err = new_fops->open(inode, file);if (err) {fops_put(file->f_op);file->f_op = fops_get(old_fops);}fops_put(old_fops);out:return err;}这个函数只要是得到handler的操作函数集,如果获得成功,使用新的操作函数集代替旧的,并调用新函数集的open函数。接下来看input子系统中3个重要结构体的注册和注销(input_dev,input_handle,input_handlerint input_register_device(struct input_dev *dev){static atomic_t input_no = ATOMIC_INIT(0);//原子变量,代表总共注册的input设备,每注册一个加1,由于是静态变量,每次调用都不会清零struct input_handler *handler;const char *path;int error;/* Every input device generates EV_SYN/SYN_REPORT events. */__set_bit(EV_SYN, dev->evbit);//EV_SYN这个是所有设备要支持的事件类型,所以要设置/* KEY_RESERVED is not supposed to be transmitted to userspace. */__clear_bit(KEY_RESERVED, dev->keybit);//KEY_RESERVED(版权)不应该传到用户空间/* Make sure that bitmasks not mentioned in dev->evbit are clean. */input_cleanse_bitmasks(dev);//确保dev->evbit被清零是不介意的if (!dev->hint_events_per_packet)dev->hint_events_per_packet =input_estimate_events_per_packet(dev);/* * 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;}/*如果没有dev->getkeycode和dev->setkeycode使用由input提供的默认函数*/if (!dev->getkeycode)dev->getkeycode = input_default_getkeycode;if (!dev->setkeycode)dev->setkeycode = input_default_setkeycode;/*设置input_dev中device的名字,名字将在/class/input/中出现*/dev_set_name(&dev->dev, "input%ld",     (unsigned long) atomic_inc_return(&input_no) - 1);error = device_add(&dev->dev);//将device加到linux设备模型中if (error)return error;/*得到device的路径*/path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);pr_info("%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);//将device的节点加到input_dev_list链表上/*遍历input_handler_list链表,配对input_dev和input_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;}EXPORT_SYMBOL(input_register_device);在注册input_dev主要完成嘞一些初始化设置,然后调用 input_attach_handler来匹配input_devinput_handler.static int input_attach_handler(struct input_dev *dev, struct input_handler *handler){const struct input_device_id *id;int error;/*主要的配对函数,主要比较ID中的各项*/id = input_match_device(handler, dev);if (!id)return -ENODEV;/*配对成功调用 handler->connect函数,在事件处理器中定义,主要生成input_handle结构,并初始化,还生成一个事件处理器相关的结构*/error = 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;}匹配首先调用了 input_match_device,在匹配成功以后调用了handlerconnect函数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;/*遍历传入的handler->id_table,寻找合适的ID进行配对*/for (id = handler->id_table; id->flags || id->driver_info; id++) {/*根据flags来,来筛选出同种类型的ID,否者进入下一个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);if (!handler->match || handler->match(handler, dev))return id;}return NULL;}这个函数主要从handler->id_table中找出和input_dev同种类型的input_handler,然后比较支持的事件,最后看handler是否提供了match函数,提供了就调用handlermatch进行匹配,没有提供直接返回同类型的id.#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;这个可以看出这里是按位比较,比较成功,进入下一个MATCH_BIT比较下一个事件类型,否则进行下一个ID的比较。对于触摸屏来说对应的事件处理器为evdev,在evdev事件处理器中没有提供match函数,所以只要flag和事件类型都匹配成功,就会返回这个handlerid。当然evdev提供了connect函数evdev_connectstatic int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id){struct evdev *evdev;int minor;int error;/*由于EVDEV_MINORS等于32,说明evdev可以同时有32个设备和它配对,evdev_table的下标minor并不是次设备号*/for (minor = 0; minor < EVDEV_MINORS; minor++)if (!evdev_table[minor])break;/*说明32个设备全部被占用了,链接失败*/if (minor == EVDEV_MINORS) {pr_err("no more free evdev devices\n");return -ENFILE;}evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);if (!evdev)return -ENOMEM;INIT_LIST_HEAD(&evdev->client_list);spin_lock_init(&evdev->client_lock);mutex_init(&evdev->mutex);init_waitqueue_head(&evdev->wait);/* 设置evdev中device的名字,它也将出现在/class/input/下,但是他和input_dev下面的device是有区别的, * evdev配对以后的虚拟设备结构,没有对应的硬件,但是可以通过它找到相应的硬件*/dev_set_name(&evdev->dev, "event%d", minor);evdev->exist = true;evdev->minor = minor;evdev->handle.dev = input_get_device(dev);evdev->handle.name = dev_name(&evdev->dev);evdev->handle.handler = handler;evdev->handle.private = evdev;evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);//minor不是真正的次设备号,还要加上EVDEV_MINOR_BASEevdev->dev.class = &input_class;evdev->dev.parent = &dev->dev;//配对生成新的device,父设备是与他相关联的input_devevdev->dev.release = evdev_free;device_initialize(&evdev->dev);error = input_register_handle(&evdev->handle);//注册handle结构体if (error)goto err_free_evdev;error = evdev_install_chrdev(evdev);//把evdev结构保存到evdev_table中,这个数组以minor为索引if (error)goto err_unregister_handle;error = device_add(&evdev->dev);//将evdev下面的device注册到linux设备模型中if (error)goto err_cleanup_evdev;return 0; err_cleanup_evdev:evdev_cleanup(evdev); err_unregister_handle:input_unregister_handle(&evdev->handle); err_free_evdev:put_device(&evdev->dev);return error;}connect函数evdev的分配和初始化,保存到evdev_table数组中,并注册一个handleint input_register_handle(struct input_handle *handle){struct input_handler *handler = handle->handler;struct input_dev *dev = handle->dev;int error;/* * We take dev->mutex here to prevent race with * input_release_device(). */error = mutex_lock_interruptible(&dev->mutex);if (error)return error;/* * Filters go to the head of the list, normal handlers * to the tail. */if (handler->filter)list_add_rcu(&handle->d_node, &dev->h_list);//将handle的d_node链接到相关input_dev的h_list链表中elselist_add_tail_rcu(&handle->d_node, &dev->h_list);mutex_unlock(&dev->mutex);/* * Since we are supposed to be called from ->connect() * which is mutually exclusive with ->disconnect() * we can't be racing with input_unregister_handle() * and so separate lock is not needed here. */list_add_tail_rcu(&handle->h_node, &handler->h_list);//将handle的h_node链接到其相关的input_handler的h_list链表中if (handler->start)handler->start(handle);return 0;}EXPORT_SYMBOL(input_register_handle);从上面可以看出,connect调用input_register_handle主要就是通过handle充当桥梁,建立input_devinput_handler的关联。input_handler的注册,一般事件处理层入口处注册input_handler,比如evdev事件处理器static int __init evdev_init(void){/*将evdev_handler注册到系统中*/return input_register_handler(&evdev_handler);}static void __exit evdev_exit(void){input_unregister_handler(&evdev_handler);}module_init(evdev_init);module_exit(evdev_exit);input_handler的注册有什么作用呢?int input_register_handler(struct input_handler *handler){struct input_dev *dev;int retval;retval = mutex_lock_interruptible(&input_mutex);if (retval)return retval;INIT_LIST_HEAD(&handler->h_list);/*每次注册一个handler都会将其保存到input_table,这里索引值等于handler->minor左移5位,也就是除以32 * 因为每个handler最多可以处理32个input_dev设备,所以要以32为对齐minor是传进来的handler的MINOR_BASE*/if (handler->fops != NULL) {if (input_table[handler->minor >> 5]) {retval = -EBUSY;goto out;}input_table[handler->minor >> 5] = handler;}list_add_tail(&handler->node, &input_handler_list);//将handler连接到input_handler_list链表中/*遍历input_dev链表,开始匹配*/list_for_each_entry(dev, &input_dev_list, node)input_attach_handler(dev, handler);input_wakeup_procfs_readers(); out:mutex_unlock(&input_mutex);return retval;}EXPORT_SYMBOL(input_register_handler);从上面的代码可以看出注册handler主要完成两件事,首先将handler链接到input_handler_list链表,然后匹配input_dev和input_handler.在注册input_dev的时候需要匹配input_dev和input_handler,是遍历的handler的链表,表示从device来找handler。在注册input_handler的时候也需要匹配input_dev和input_handler,但是是遍历的dev的链表,表示是从handler来找device。

原创粉丝点击