zoukankan      html  css  js  c++  java
  • input输入子系统

    在使用Open的时候,就自己能够使用。如果需要将驱动程序制作成通用的。就需要使用到输入子系统,就是在现成的驱动中修改成自己板子需要的驱动。

    input输入子系统

    自己写的时候

    1.确定主设备号major

    2.构造一个file_operetion结构体

        里面有Open

           write

           read

           close等函数

    3.使用register_chrdev告诉内核(注册这个驱动)

    4.由入口函数来调用register_chrdev来挂载驱动

    5.由出口函数来卸载掉驱动

    input子系统

    上面所述的1.2.3.4.5.都是有的,是系统已经做好了的。(现成的)

    输入子系统框架:

    input.c------->核心层

    drivers/input/input.c   >err = register_chrdev(INPUT_MAJOR, "input", &input_fops);

    使用了这样的一个结构体  input_fops 

    static const struct file_operations input_fops = {
    .owner = THIS_MODULE,
    .open = input_open_file,
    };

    通过上面的结构体上可以看出 只有一个open函数,那么到底是怎么实现读写的了?

    input_open_file  >struct input_handler *handler = input_table[iminor(inode) >> 5];
    
        new_fops = fops_get(handler->fops)
    
        file->f_op = new_fops;
    
        err = new_fops->open(inode, file);

    所以app,来read的时候最终就会调用到  read > ...... >file->f_op->read函数  

    input_table这个数组是由谁来构造的?

    在input_register_handler 这个函数中构造了一个input_table[handler->minor >> 5] = handler; 这个数组

    evdev.c keyboard.c  mousedev.c 向核心层注册 input_register_handler

    input_register_handler 纯软件概念

    注册input_handler:

      input_register_handler

      //放入数组

     

     input_table[handler->minor >> 5] = handler;

      //放入链表

      

    list_add_tail(&handler->node, &input_handler_list);  //同样的是将input_handler放入一个链表中去

      //对于每一个input_dev调用  input_attach_handler

     

     list_for_each_entry(dev, &input_dev_list, node)
      input_attach_handler(dev, handler);//根据input_handler的id_table判断能否能够支持这个input_dev 

    注册输入设备:

    input_register_device

      

    list_add_tail(&dev->node, &input_dev_list);//将输入设备放入一个链表中去
    
      list_for_each_entry(handler, &input_handler_list, node)  //对于每一个input_handler都调用input_attach_handler
      input_attach_handler(dev, handler);//根据input_handler的id_table判断能否能够支持这个input_dev 

    input_attach_handler:

     

     id = input_match_device(handler->id_table, dev);//判断handler->id_table 是否和dev匹配
    
      error = handler->connect(handler, dev, id);//若匹配则调用handler->connect()函数

    小结:在注册input_dev或者input_handler时,会两个相互比较 左边的input_dev和右边的input_handler,

    根据input_handler 的id_teble判断这个input_handler能否支持当前的input_dev,

    如果能够支持就调用input_handler的connect()函数建立连接。

    怎么建立连接了?

      比如说evdev.c的input_handler结构如图

      

      建立evdev的连接使用evdev_connect函数

      evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//分配了一个input_handle结构

      //设置input_handle  

     

     evdev->handle.dev = dev;       //指向input_dev结构体
      evdev->handle.name = evdev->name;
      evdev->handle.handler = handler;  //指向右边的input_handler结构体
      evdev->handle.private = evdev;
    
      
    
      error = input_register_handle(&evdev->handle);//注册这个input_handle

    从上可以看出在链接的时候就构造一个input_handle结构体

    evdev->handle.dev = dev;       //指向input_dev结构体
    
    evdev->handle.handler = handler;  //指向右边的input_handler结构体

    从下面的加入链表的动作中可以看出,两边都有一个h_lsit链表 ,这两个h_list都指向 input_handle,通过这个步骤就建立起了链接。

    可以通过input_handler中的h_list找到input_dev .。同样反过来也可以input_dev,通过自身的h_list找到input_handler。这样就建立起了链接了

    list_add_tail(&handle->d_node, &handle->dev->h_list);
    list_add_tail(&handle->h_node, &handler->h_list);

    小结:

    1.分配一个input_handle结构体

    2.设置这个input_handle

     

     input_handle->handle.dev = input_dev;       //指向input_dev结构体
    
      input_handle->handle.handler = intp_handler;  //指向右边的input_handler结构体

    3.注册这个input_handle  

     

     error = input_register_handle(&evdev->handle);//注册这个input_handle
    
      input_handler->h_list = &input_handle;
    
      input_dev->h_list       = &input_handle; 

    怎么读按键了?

      app  read

    ----------------------------------

      .......

        evdev_read

         

     //无数据并且是非阻塞方式打开的话   就直接返回 -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_read

    evdev_event 被谁调用?

      应该是硬件相关的代码来唤醒,也就是input_dev那层的东西来调用,evdev_event 

      在设备的中断服务程序里确定事件是什么,然后调用相应的input_handler的envet处理函数

      //向操作系统上报事件
      input_event(input, type, button->code, !!state);


      

    input_sync(input);
    
      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)   //查找列表中的handle
      if (handle->open)                 //如果这个handle打开了
        handle->handler->event(handle, type, code, value);//这一步就是调用右边的input_handler的event函数

    怎么写一个符合输入子系统框架的驱动程序?

    1.分配一个input_dev结构体

    2.设置

    3.注册

    4.硬件相关代码,如中断服务程序上报事件。

  • 相关阅读:
    【jquery仿dataList】应用之——模仿igoogle【定制化、拖动排序,最大化、分屏】
    【jquery版.net控件—dropdownlist】附源码,欢迎大家指点、指正、拍砖!!!
    求【javascript设计模式】【高性能网站建设指南】PDF!哪位有给下啊!!!
    只言碎语总结,今后发展web前端,并分享两个项目难点解决方案。
    【jquery模仿net控件】简单的datalist控件更新,及其简单应用
    一次上机面试题带来的感悟【学习的感觉、学习的方法】
    【jquery模仿net控件】初步GridView模型实现,及其简单应用
    【HTML5初探之Web Workers】网页也能多线程
    Fiddler真乃前端大杀器!!!
    【初探HTML5之使用新标签布局】用html5布局我的博客页!
  • 原文地址:https://www.cnblogs.com/hjxzjp/p/10549626.html
Copyright © 2011-2022 走看看