标签:
input子系统的搭建要点:
核心层为事件驱动层和设备驱动层的注册提供API的实现、核心层为设备驱动层上报事件提供API的实现 、事件驱动层为应用层提供API的实现 。int input_register_handler(struct input_handler *handler);②为设备驱动层提供的:
void input_unregister_handler(struct input_handler *handler);
struct input_dev *input_allocate_device(void);设备驱动要用到的上报输入事件函数API:
void input_free_device(struct input_dev *dev);
int input_register_device(struct input_dev *dev);
void input_unregister_device(struct input_dev *dev);
void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value);//下面是这个函数的特殊定义##上面这些接口函数的实现过程几乎就是input子系统的框架搭建过程:##
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value);
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value);
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value);
input_register_handler(struct input_handler *handler) { ...... // ①放入数组:根据次设备号就可以查找到,方便应用层快速调用 input_table[handler->minor >> 5] = handler;//把传进来的handler结构体根据他自身的minor次设备号放到input_table[]数组对应的位置 // ②链入链表:方便遍历 list_add_tail(&handler->node, &input_handler_list); // ③在input_dev_list链表中主动找匹配的input_dev: list_for_each_entry(dev, &input_dev_list, node) //for循环的宏定义 input_attach_handler(dev, handler); id = input_match_device(handler->id_table, dev); // 根据input_handler的id_table判断能否支持这个input_dev error = handler->connect(handler, dev, id); //match成功的话调用 ...... }完全可以想象只要有调用input_register_handler()就会根据minor来填充input_table[]对应的项,这点必须值得肯定!
input_register_device(struct input_dev *dev) { ...... // 链入链表 list_add_tail(&dev->node, &input_dev_list); // 在input_handler_list链表中主动找匹配的input_handler: list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); id = input_match_device(handler->id_table, dev);// 根据input_handler的id_table判断能否支持这个input_dev error = handler->connect(handler, dev, id); //如果能支持,则调用input_handler的connect函数建立"连接" ...... }也在内核源码里边来搜一搜input_register_device函数在哪些地方被调用:
evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id) { ...... //1. 分配一个input_handle结构体 evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //2.设置这个结构体 evdev->minor = minor; evdev->handle.dev = input_get_device(dev); // 指向input_dev evdev->handle.name = evdev->name; evdev->handle.handler = handler; //指向input_handler evdev->handle.private = evdev; //3.把这个结构体注册到input_handler和input_dev结构体 error = input_register_handle(&evdev->handle);//下面进一步分析这个函数就知道究竟是怎样让handler和dev建立联系的! ...... }input_register_handle函数实现:
input_register_handle(); { ...... list_add_tail_rcu(&handle->d_node, &dev->h_list); list_add_tail(&handle->h_node, &handler->h_list); ...... }小结一下这一点的内容:
input_handle.dev = input_dev; // 指向input_dev3. 注册:
input_handle.handler = input_handler; // 指向input_handler
input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value) { input_handle_event(dev, type, code, value); switch (type) { case EV_SYN: ... case EV_KEY: ... case EV_SW: ... case EV_ABS: ... case EV_REL: ... } ... //分析到这里要小心了,一开始以为是这个if条件成立,因为第一感觉就是input_device结构体的这个成员会在哪里被初始化, //然后就去直奔input_register_device函数里找啊找,半毛钱都没找到,原来本来就没有进行定义,所以dev->event为空,条件不成立! if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); if (disposition & INPUT_PASS_TO_HANDLERS)//擦!从sourceInsi也可以发现INPUT_PASS_TO_HANDLERS这个宏是有定义的 input_pass_event(dev, type, code, value);//这个就是设备驱动层上报事件的关键工作! }
input_pass_event(struct input_dev *dev,unsigned int type, unsigned int code, int value) { struct input_handle *handle; ... list_for_each_entry_rcu(handle, &dev->h_list, d_node) if (handle->open) handle->handler->event(handle,type, code, value);//最终调用的是匹配的input_handler结构体的event成员 //这就好办了,handler是事件驱动层,我们就拿event.c文件里的例子来继续分析 } void evdev_event(struct input_handle *handle,unsigned int type, unsigned int code, int value) { ...... wake_up_interruptible(&evdev->wait);//唤醒工作 }小结:
static struct input_handler evdev_handler = { .event = evdev_event, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, };
static const struct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, //以这个接口函数的实现进行分析 ...... };
evdev_read() { ....... // 无数据并且是非阻塞方式打开,则立刻返回 if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN; // 否则进入休眠,上面刚刚提到:这里的休眠就是设备驱动层通过调用input_event()函数最终重定向到事件驱动层的evdev_event()函数来唤醒的 retval = wait_event_interruptible(evdev->wait, client->head != client->tail || !evdev->exist); ....... }小结:
事件驱动层和核心层都是通用的,我们需要实现的是设备驱动层。输入设备驱动会把硬件产生的事件信息用统一的格式(struct input_event)上报给核心层,然后核心层进行分类后,再上报给相应的事件处理驱动程序,最后通过事件层传递到用户空间,应用程序可以通过设备节点来获取事件信息。比如底层报上来的是一个按键事件,核心层会报给evdev来处理;如果报的是一个鼠标事件,核心层会报给mousedev来处理。最后附上一张经典的输入子系统的框架图。
标签:
原文地址:http://blog.csdn.net/clb1609158506/article/details/45166491