input subsystem简要分析

2014-11-19  本文已影响129人  季风落地窗

Input Subsystem 系统主要由 drivers/input/input.c input_register_device() 和 input_register_handler() 两个函数实现。
Handler 组件通过 input_register_handler 函数将逻辑设备操作结构体注册到 input_handler_list 链表中;
device 组件通过 input_register_device 组件将直接对具体硬件的操作结构体注册到 input_dev_list 链表中

struct input_dev {
    ...
    struct device dev;
    ...
    struct list_head    h_list; //与 input_dev关联的 input_headle 的链表头
    struct list_head    node;   //用于将本设备连接到 input_dev_list
};

struct input_handler {
    ...
    const struct file_operations *fops;
    ...
    const struct input_device_id *id_table;//用户和设备匹配, 这个是事件处理器所支持的input设备
    ...
    struct list_head    h_list; //所支持的 input_headle 结构的链表的表头
    struct list_head    node;   //链入全局链表input_handler_list, 它连接了所有注册到内核的handler 
};

struct input_handle {
    ...
    struct input_dev *dev;              //关联的input_dev结构
    struct input_handler *handler;      //关联的input_headler结构

    struct list_head    d_node;         //input_headle通过d_node连接到了input_dev的h_list上
    struct list_head    h_node;         //input_headle通过h_node连接到了input_headler的h_list上
};

input_dev / input_headler / input_headle 关系:
input_dev 是硬件驱动层,代表一个input设备
input_headler 是事件处理层,代表一个事件处理器
input_headle 个人认为属于核心层, 代表一个配对的设备与事件处理器
那么input_dev 和input_handler是如何跟input子系统总线联系起来的呢?

(linux)/drivers/input/input.c

input_init()
    class_register(&input_class);                       //创建类
    register_chrdev(INPUT_MAJOR, "input", &input_fops); //创建类下的设备, 并由此可知   file_operations结构体变量为input_fops

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

//该结构体只填充了 .open 方法, read / write / poll 等方法没有填充, 那么肯定是由open做了些"工作"来间接实现了其他的功能, 那么就让我们来看看 input_open_file的内部

static int input_open_file(struct inode *inode, struct file *file)
{
    struct input_handler *handler;
    ...
    //以次设备号为下标,拿到一个 input_handler, 在input_handler内部有个file_operations成员
    handler = input_table[iminor(inode) >> 5];
    ...
    //将input_handler的file_operations成员拿出
    new_fops = fops_get(handler->fops);
    ...
    //将原来的fops保存起来, 将新的fops给 file->f_op
    old_fops = file->f_op;
    file->f_op = new_fops;
    //从此file->f_op都是 新的fops
    err = new_fops->open(inode, file);
    ...
    return err;
}

以上程序的关键是 input_table[], 那么input_table是怎么来的呢?

insmod时候调用

//注册input_handler

input_register_handler()
    input_table[handler->minor >> 5] = handler;     //那么是谁调用了input_register_handler 了呢?
    //将handler加入 input_handler_list链表
    list_add_tail(&handler->node, &input_handler_list);
    //每个 input_handler 都调用 input_attach_handler, 遍历headler 查看是否支持dev
    list_for_each_entry(handler, &input_handler_list, node)
       //根据input_handler 的id_table 判断能否支持该input_device
       input_attach_handler(dev, handler);          

插入设备调用

//注册输入设备

input_register_device()
    //将每个 input_device 都放入链表
    list_add_tail(&dev->node, &input_dev_list);
    //每个 input_handler 都调用input_attach_handler, 遍历handler, 查看能否支持dev
    list_for_each_entry(handler, &input_handler_list, node)
       //根据input_handler 的id_table 判断能够支持该input_device
       input_attach_handler(dev, handler);          

以上两个函数非常对称, 不管先调用哪个函数都最后调用了 input_attach_handler, 那么input_attach_handler 做了什么工作呢?

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
    id = input_match_device(handler->id_table, dev);//遍历id_table, 看找有没有与dev匹配的
    if (!id)
        return -ENODEV;

    error = handler->connect(handler, dev, id);

它先比较了handler层的 input_handler的id_table和device层的input_dev, 如果handler能够支持input_dev 则调用handler的connect将device和handler"连接"起来

//那么他们是怎么建立"连接"的呢? 主要看 handler 里的 connect 函数 (这里以evdev为例来说明)

evdev_connect
1. 申请一个  handle 结构体
2. 设置
    handle.dev = input_dev;
    handle.handler = input_handler;
3. input_dev->h_list = &handle;
    input_hanlder->h_list = &handle;

这样一来
device层可以通过 input_dev的h_list先找到handle 然后再通过handle的handler找到 input_handler
handler层可以通过input_handler的h_list先找到handle然后再通过handle的dev找到 input_dev
两者就靠 handle连接了起来

从编写代码的过程再捋一遍思绪:
1. 申请input_dev结构体 input_allocate_device

2. 设置 input_dev 
   1) 可以产生哪类事件
   2) 产生该类事件中的哪些事件

3. 将input_dev注册到内核

4. 实现业务逻辑代码
    申请中断等...

问题:

  1. input_table 是什么?
  2. 应用层如何获取input_event上报的事件?
上一篇 下一篇

猜你喜欢

热点阅读