对输入子系统分析总结
2013-04-23 09:04
141 查看
原文链接 http://100ask.net/forum/showtopic-3567.aspx 在drivers/input/input.c中: 进入模块入口函数input_init : err= register_chrdev(INPUT_MAJOR, "input",&input_fops); 复制代码 而input_fops只有open和llseek函数: static const struct file_operations input_fops ={ .owner= THIS_MODULE, .open= input_open_file, .llseek= noop_llseek, }; 复制代码 那么没有read函数的话该怎么读数据呢? 进入 input_open_file函数: struct input_handler*handler;//定义一个input_handler指针 handler= input_table[iminor(inode) >>5];//根据传入文件的次设备号从 //input_table中提取出一个input_handler if(handler) new_fops=fops_get(handler->fops);//从input_handler中提取出new_fops file->f_op= new_fops;//将new_fops赋值给当前文件的file_operations err= new_fops->open(inode, file); 复制代码 经过这些操作后,当app再来调用read,write,open等函数时,最终都会调用到file->f_op 中的read,write,open等函数。 那么input_open_file函数中的input_table 又是从何而来的呢? 搜索代码可知, 在input.c的input_register_handler函数中构造了input_table: if(handler->fops != NULL) { if(input_table[handler->minor>> 5]) { retval= -EBUSY; gotoout; } //给input_table中的第handler->minor >>5项赋值 input_table[handler->minor>> 5] = handler; } 复制代码 又是谁在调用input_register_handler呢? 搜索内核可知: evdev.c,tsdev.c,joydev.c, keyboard.c,mousedev.c等文件调用了 input_register_handler,我们以evdev.c为例 在drivers/input/evdev.c中: 进入模块入口函数evdev_init: returninput_register_handler(&evdev_handler); evdev_handler的定义如下: staticstruct input_handler evdev_handler = { .event =evdev_event, .connect =evdev_connect, .disconnect =evdev_disconnect, .fops =&evdev_fops,//前面所用到的 new_fops指的就是这里定义的的fops .minor =EVDEV_MINOR_BASE, .name ="evdev", .id_table =evdev_ids, }; 复制代码 这里需要插入的讲解一下输入子系统的架构!如图: 当通过input_register_device注册一个 input_dev设备或者通过 input_register_handler注册一个input_handler时,input_dev与 input_handler 会进行匹配,如何匹配? 在input_handler中有一个id_table,里面包含的就是这个input_handler能处理的input_dev, 当input_handler与input_dev匹配成功的话,则会调用 input_handler里 的connect函数。 下面我们来看下input_register_device和input_register_handler分别做了什么: input_register_device: //将刚注册的input_dev放入input_dev_list链表(1) list_add_tail(&dev->node,&input_dev_list); list_for_each_entry(handler,&input_handler_list,node) input_attach_handler(dev,handler); input_register_handler: //将刚注册的input_handler放入input_table中(1) input_table[handler->minor>> 5] = handler; //将刚注册的input_handler放入input_handler_list链表中 (2) list_add_tail(&handler->node,&input_handler_list); list_for_each_entry(dev,&input_dev_list,node) input_attach_handler(dev,handler); 复制代码 由此可以看出,无论是先注册input_handler还是先注册input_dev最终都会调用来 input_attach_handler(dev,handler); 来进行两两匹配。现在我们来看看input_attach_handler是如何将input_handler和input_dev进行 匹配的。 在input_attach_handler函数中: id = input_match_device(handler, dev); error = handler->connect(handler,dev, id); 我们以evdev.c中的 input_handler结构中的connect函数为例,分析connect函数做了些什么。 在evdev_connect函数中: evdev= kzalloc(sizeof(struct evdev), GFP_KERNEL); evdev->handle.dev= input_get_device(dev); evdev->handle.name= dev_name(&evdev->dev); evdev->handle.handler= handler; evdev->handle.private= evdev; error=input_register_handle(&evdev->handle); 复制代码 下面我们来看注册input_handle做了些什么: list_add_tail_rcu(&handle->d_node,&dev->h_list); list_add_tail_rcu(&handle->h_node,&handler->h_list); 复制代码 对于输入设备,我们知道一般需要读取其数据,那么经过上述的一些列动作后又是如何读取到数据的呢? 我们来看下evdev.c中的input_handler中的fops中的read函数: 在evdev_read函数中: //如果没有数据且nonblock的话,则EAGAIN if( client->head == client->tail&& evdev->exist&& (file->f_flags & O_NONBLOCK)) return-EAGAIN; //否则,睡眠 retval=wait_event_interruptible(evdev->wait,client->head!= client->tail ||! evdev->exist); 复制代码 既然有睡眠,那么何时被唤醒,搜索代码。 在evdev_event函数中: //唤醒 wake_up_interruptible(&evdev->wait); evdev_event是input_handler中的成员,当有数据可读 (如触摸屏被按下,按键 被按下)时,event函数会被调用。 而event函数是怎么被调用到的?这就得看设备层了, 设备层的驱动做了如下工作: <1>在中断函数中确定判断发生了什么事件,并且相应的值是多少 <2>通过input_event()函数上报事件 //input.c input_report_key会调用 input_event <3>通过input_sync()函数表明上报结束 分析input_event函数我们就可以知道input_handler中的event函数是如何被调用到的了。 在input_event中,调用了input_handle_event函数,在input_handle_event函数中调用了 input_pass_event函数; 在input_pass_event函数中: input_report_key ——> input_event——> input_handle_event ——> input_pass_event ——> handler->event structinput_handler *handler; list_for_each_entry_rcu(handle,&dev->h_list, d_node) { if (!handle->open) continue; //如果该input_handle被打开,则该input_handle->input_handler即为可 //处理该input_dev的handler handler= handle->handler; if(!handler->filter) { if(filtered) break; handler->event(handle,type, code, value); }else if (handler->filter(handle, type, code,value)) filtered= true; } 复制代码 最后,回归到如何写符合输入子系统框架的驱动程序,四个步骤: <1> 分配一个input_dev结构体 <2> 设置input_dev <3> 注册input_dev <4> 在中断函数中上报事件 |
相关文章推荐
- 输入服务子系统实例分析(韦东山的视频总结及针对linux-2.6.30.4)
- 对输入子系统分析总结
- 对输入子系统分析总结
- 【分享】对输入子系统分析总结
- 输入服务子系统框架代码分析(韦东山的视频总结及针对linux-2.6.30.4)
- Linux 输入(input)子系统架构分析
- Linux输入子系统分析二
- input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析
- [转]2.6内核输入子系统分析
- linux input输入子系统分析《四》:input子系统整体流程全面分析
- linux input输入子系统分析《四》:input子系统整体流程全面分析
- 42 linux内核里的输入子系统分析
- ads7846驱动及android系统input输入子系统分析
- linux input输入子系统分析《一》:初识input输入子系统
- Linux视频驱动 学习总结之第13课(输入子系统)
- input子系统基础之按键4——输入核心层源码分析
- linux input输入子系统分析《一》:初识input输入子系统
- Linux input子系统分析 输入子系统核心分析
- linux 输入子系统(2)----简单实例分析系统结构(input_dev层)
- linux input输入子系统分析《一》:初识input输入子系统