在使用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.硬件相关代码,如中断服务程序上报事件。

版权声明:本文为hjxzjp原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/hjxzjp/p/10549626.html