LINUX输入子系统详解

来源:互联网 发布:西门子plc tcp端口号 编辑:程序博客网 时间:2024/06/03 19:04
输入子系统:为何引入:以前我们写一些输入设备(键盘鼠标等)的驱动都是采用字符设备、混杂设备处理的。为了实现对分散的、不同类别的输入设备进行统一驱动,出现了输入子系统自己写驱动程序时需要:  1 major2 file_operation3 register_chrdev4 入口函数5 出口函数输入子系统:  别人已经帮你做好上述    我们需要弄清楚把自己代码融合进去输入子系统框架总体框架://用户编程的接口(设备节点),并处理驱动层提交的数据输入子系统事件处理层 *evdev.c  //输入事件驱动//为设备驱动层提供了规范和接口。设备驱动层只要关心如何驱动硬件并获得硬件数据,然后调用核心层提供的接口,核心层会自动把数据提交给事件处理层//它的存在屏蔽了用户到设备驱动的交互细节,为设备驱动层和事件处理层提供了相互通信的统一界面输入子系统核心层  input.c//主要完成对硬件设备的读写访问,中断设置,并把硬件产生的事件转换成核心层定义的规范交给事件处理层输入子系统设备驱动层         // 输入设备驱动 input_table[] 全局 input_handler类型的数组input.c 核心层:    中转作用入口函数:input_init:   //创建设备类并注册设备,对照自己写的驱动,为了可以自动挂接,还没有class_device_create, //应该是在我们input_register_device之后,调用handler的connect函数建立连接时在类下创建设备err = class_register(&input_class);err = register_chrdev(INPUT_MAJOR, "input", &input_fops);static const struct file_operations input_fops = {.owner = THIS_MODULE,.open = input_open_file,};struct input_handler {void *private;void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);void (*disconnect)(struct input_handle *handle);void (*start)(struct input_handle *handle);const struct file_operations *fops;int minor;const char *name;const struct input_device_id *id_table;const struct input_device_id *blacklist;struct list_headh_list;struct list_headnode;};问:只有一个open函数如何读input_open_file:struct input_handler *handler = input_table[iminor(inode) >> 5];new_fops = fops_get(handler->fops)file->f_op = new_fops;   // ->&evdev_fopserr = new_fops->open(inode, file);app: read>...>file->f_op->readinput_table数组由谁构造: input_register_handler:input_table[handler->minor >> 5] = handler;  纯软件构造 evdev.c keyboard.c mousedev.c   -> input_register_handler向核心层注册,设备子系统已经向核心层注册,我们不用管 设备: input_register_device->input.c硬件 建立handler与device联系: input_device结构 与input_handler结构中的.id_table比较 可以的话调用input_handler.connect函数建立连接   input_register_device: //设备驱动注册为设备委托内核做的事情     list_add_tail(&dev->node, &input_dev_list);    //将输入设备挂接到输入设备链表input_dev_list中  //查找并匹配输入设备对应的事件处理层,通过input_handler_list链表    list_for_each_entry(handler, &input_handler_list, node)input_attach_handler(dev, handler);//根据input_handler的id_table判断能否支持这个input_deviceinput_attach_handler:id = input_match_device(handler->id_table, dev);input_device结构 与input_handler结构中的.id_table比较 可以的话调用input_handler.connect函数建立连接error = handler->connect(handler, dev, id);handler->connect(handler, dev, id);:如何具体的连接:通过evdev->handle,handle结构有两个变量分别是dev,input_handler输入设备驱动最终的目的就是能够与事件处理层的事件驱动相互匹配,但是在drivers/input目录下有evdev.c事件驱动、mousedev.c事件驱动、joydev.c事件驱动等等,我们的输入设备产生的事件应该最终上报给谁,然后让事件驱动再去处理呢?其实evdev.c mousedev.c等genuine硬件输入设备的处理方式的不同抽象除了不同的事件处理接口帮助上层去调用而我们写的设备驱动程序只不过是完成了硬件寄存器中数据的读写,但提交给用户的事件必须是经过事件处理层的封装和同步才能够完成的,事件处理层提供给用户一个统一的界面来操作。整个关联过程:input_register_device->input_attach_handler->input_match_device->handler->connect->input_register_handle(evdev.c)->input_dev,handler->input_dev_list,input_handler_list核心层与事件处理层建立联系:                  err = class_register(&input_class);   //创建类err = register_chrdev(INPUT_MAJOR, "input", &input_fops);  //注册input设备input_register_handler://放入数组input_table[handler->minor >> 5] = handler;//放入链表list_add_tail(&handler->node, &input_handler_list);list_for_each_entry(dev, &input_dev_list, node)input_attach_handler(dev, handler);怎么建立连接:1.分配一个input_handle结构体evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);  //分配一个input_handle结构2.设置input_handle结构体input_handle.dev = input_dev;input_handle_handler = input_handler3.注册input_handler->dev = &input_handleinput_dev->h_list = &input_handle//设置evdev->handle.dev = dev;evdev->handle.name = evdev->name;evdev->handle.handler = handler;evdev->handle.private = evdev;sprintf(evdev->name, "event%d", minor);//注册error = input_register_handle(&evdev->handle);input_device 与 input_handler中均有.h_list ,两者通过.h_list找到input_handle,然后分别通过input_handle的.handler与.dev找到相应的handler与.dev怎么读按键?app:read ---------------.....evdev_read//无数据并且是非阻塞方式打开,则立刻返回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_dev调用 在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数gpio_keys_isr//上报事件input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value):       struct input_handle *handle;       list_for_each_entry(handle, &dev->h_list, d_node)        if (handle->open)       handle->handler->event(handle, type, code, value);怎么写符合输入子系统框架的驱动:1.分配一个input_dev结构体2.设置3.注册4.硬件相关的代码,比如在中断服务程序里上报事件 


0 0