打开/driver/input/input.c 这就是input代码的核心

找到

static int __init input_init(void)

{

err = class_register(&input_class);注册一个类,注册后会在sys/class出现input目录.

......

err = register_chrdev(INPUT_MAJOR, "input", &input_fops);注册一个主设备号为13的input设备,

}

打开input_fops

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

只有一个往内核中注册一个open函数,那么read,write,等函数也应该注册,则应该在input_open_file中注册,

分析static int input_open_file(struct inode *inode, struct file *file)

{

struct input_handler *handler = input_table[iminor(inode) >> 5];把input_table数组中的某一个成员赋值给handler,这个下面会具体分析

if (!handler || !(new_fops = fops_get(handler->fops)))获取handler中的file_operations结构体
        return -ENODEV;

old_fops = file->f_op;
    file->f_op = new_fops;

err = new_fops->open(inode, file);打开这个handler->fops->open函数

}

问1:input_table[iminor(inode) >> 5]这个数组是有谁来赋值的

int input_register_handler(struct input_handler *handler)

{

INIT_LIST_HEAD(&handler->h_list);

input_table[handler->minor >> 5] = handler;把handler赋值给input_table数组,位置以此设备号除以32

list_add_tail(&handler->node, &input_handler_list);把这个handler的节点加入input_handler_list链表中

list_for_each_entry(dev, &input_dev_list, node)一次遍历input_dev_list链表中的input_dev设备,然后对传进的handler进行匹配,寻找input_dev_list中有没有支持这个handler的设备
        input_attach_handler(dev, handler);具体的匹配方法接下来会详细分析

}

问2:那谁来调用input_register_handler,也就是handler从哪里来

搜索得到

Evbug.c (drivers\input):106:    return input_register_handler(&evbug_handler);
Evdev.c (drivers\input):745:    return input_register_handler(&evdev_handler);
Input.c (drivers\input):1193:int input_register_handler(struct input_handler *handler)
Input.c (drivers\input):1219:EXPORT_SYMBOL(input_register_handler);
Input.h (include\linux):1130:int input_register_handler(struct input_handler *);
Joydev.c (drivers\input):647:    return input_register_handler(&joydev_handler);
Keyboard.c (drivers\char):1367:    error = input_register_handler(&kbd_handler);
---- = input_register_handler(&kbd_handler); Matches (1 in 1 files) ----
Keyboard.c (drivers\char):1367:    error = input_register_handler(&kbd_handler);
那就打开keyboard.c以它为例详细分析这个是怎么注册的
static struct input_handler kbd_handler = {
    .event        = kbd_event,
    .connect    = kbd_connect,
    .disconnect    = kbd_disconnect,
    .start        = kbd_start,
    .name        = "kbd",
    .id_table    = kbd_ids,
};
int __init kbd_init(void)

{

error = input_register_handler(&kbd_handler);

}

其实就是吧kbd_handler这个结构体传递给input_table;

再总结一下:

int __init kbd_init(void)->error = input_register_handler(&kbd_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);

}

分析如何匹配的 input_attach_handler(dev, kbd_hander)

{

id = input_match_device(handler->id_table, dev);如果匹配成功返回一个id

error = handler->connect(handler, dev, id);然后会根据返回的id找到设备和kbd_handler进行连接,这个连接connect函数就是kbd_handler->kbd_connect

}

接下来详细分析input_match_device

{

for (; id->flags || id->driver_info; id++) {

if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
            if (id->bustype != dev->id.bustype)
                continue;

.......
             //针对handler->id->flags,比较不同的类型,如果比较成功
                    //进入下面的宏比较,否则进入下一个id

MATCH_BIT(evbit,  EV_MAX);
          .............
           //安位比较所支持事件的类型,只有所有未匹配成功才能成功返回,否则进入下一id
        return id;
    }

return NULL;

}

如果匹配成功就会进入连接,分析kbd_connect

static int kbd_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)

{

struct input_handle *handle;定义一个input_hanlde指针

handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);分配input_handle结构体空间

handle->dev = dev;使分配的handle中的dev指向和handler匹配的input_dev
    handle->handler = handler;使handle中的handler指向和input_dev匹配的input_handler
    handle->name = "kbd";

error = input_register_handle(handle);注册这个新分配的handle;

error = input_open_device(handle);

}

继续分析

int input_register_handle(struct input_handle *handle)
{
    struct input_handler *handler = handle->handler;

list_add_tail(&handle->d_node, &handle->dev->h_list); 把handle->d_node挂在input_dev->h_list上
    list_add_tail(&handle->h_node, &handler->h_list);吧handle->h_node挂载handler->h_list上
    这样就可以通过input_handler中的h_list找到handle,然后通过handle->dev找到匹配的input_dev

同样也可以通过input_dev中的h_list找到handl,然后通过handle->handler找到匹配的input_handler

这样input_handler,input
    if (handler->start)
        handler->start(handle);

return 0;
}继续分析

int input_open_device(struct input_handle *handle)
{
    struct input_dev *dev = handle->dev;
    int err;
    handle->open++;//handle的打开计数加1,注意和evdev的open的区别

if (!dev->users++ && dev->open)
        err = dev->open(dev);//如果此input-dev没有进程引用,并且定义了open
        //方法,就调用open方法,

if (err) //retval=1说明,没有成功打开,
        handle->open--;
}

总结connect的作用就是根据匹配成功的input_dev和input_handler,创建一个新的结构体input_handle,然后把结构体中的dev和handler分配指向input_dev和input_handler

这样的话,就可以通过input_handle这个结构体把input_dev和input_hanlder连接起来;

static int __init input_init(void)->err = register_chrdev(INPUT_MAJOR, "input", &input_fops)->input_fops-> input_open_file

{struct input_handler *handler = input_table[iminor(inode) >> 5];

if (!new_fops->open) {
        fops_put(new_fops);
        return -ENODEV;
    }

err = new_fops->open(inode, file);这个open函数就是kbd_handler中的fops中的open;这个keyboard中没有初始化fops;

}

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

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

和input_handler类似,大家自行分析

内核input子系统分析的更多相关文章

  1. Linux input子系统分析

    输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...

  2. linux kernel input 子系统分析

    Linux 内核为了处理各种不同类型的的输入设备 , 比如说鼠标 , 键盘 , 操纵杆 , 触摸屏 , 设计并实现了一个对上层应用统一的试图的抽象层 , 即是Linux 输入子系统 . 输入子系统的层 ...

  3. input子系统分析

    ------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ -------- ...

  4. linux内核input子系统解析【转】

    转自:http://emb.hqyj.com/Column/Column289.htm 时间:2017-01-04作者:华清远见 Android.X windows.qt等众多应用对于linux系统中 ...

  5. input子系统分析之三:驱动模块

    内核版本:3.9.5 本节将以even handler来分析设备的注册和打开的过程,分析之前不妨回顾一下上节介绍的数据结构. 结合前两节分析可知,input子系统分为3层,最上一层是event han ...

  6. input子系统分析之一:框架

    内核版本:3.9.5 输入设备总类繁杂,包括按键,键盘,触摸屏,鼠标,摇杆等等,它们本身都是字符设备,不过内核为了能将这些设备的共性抽象出来,简化驱动的开发,建立了一个Input子系统.Input子系 ...

  7. input子系统分析(转)

    转自:http://www.linuxidc.com/Linux/2011-09/43187.htm 作者:作者:YAOZHENGUO2006 Input子系统处理输入事务,任何输入设备的驱动程序都可 ...

  8. input子系统分析之二:数据结构

    内核版本:3.9.5 1. input_dev,用来标识输入设备 struct input_dev { const char *name; const char *phys; const char * ...

  9. linux内核输入子系统分析

    1.为何引入input system? 以前我们写一些输入设备(键盘.鼠标等)的驱动都是采用字符设备.混杂设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可 ...

随机推荐

  1. WPF界面布局——Canvas

    Canvas用于定义一个区域,称为画布,用于完全控制每个元素的精确位置.它是布局控件中最为简单的一种,直接将元素放在指定位置,使用Canvas时,必须指定一个子元素的位置(相对于Canvas),否则所 ...

  2. viewPager + fragment

    有两种实现方式,一种是 fragmentActivity + FragmentPagerAdapter (Fragment,FragmentManager需要导包:android.support.v4 ...

  3. java String 的+操作导致的问题

    不说别的先看代码截图: 结果如下: 很好奇为什么String对象的null加上了""就等于"null"字符串了,先给点资料看看: 这个是我找的一个人博客上的截图 ...

  4. Java类中中文问题

    一个奇怪问题 java类中要保存一个xml文件到数据库,2种传值方式其中1种不知何故会最终导致解析xml时报错. xml文件内容由StringBuffer定义,其中一段内容如下: sb.append( ...

  5. pm2.5检测统计

    SELECT AVG(pm25_h),AVG(pm10_h),AVG(temp_h),AVG(humi_h),AVG(co2_h),AVG(tvoc_h),perf_time FROM( SELECT ...

  6. WPF依赖属性DependencyProperty

    写在之前: 依赖属性算是WPF醉醉基础的一个组成了.平时写代码的时候,简单的绑定很轻松,但是遇到复杂的层次比较多的绑定,真的是要命.所以,我觉得深刻认识依赖属性是很有必要的.本篇只是个人学习的记录,学 ...

  7. vi编辑器 使用 命令

    vi编辑器 1)命令模式 打开文件后.默认处于命令模式,命令模式无法编辑文件 2)输入模式 在命令模式下 按 i 进入输入模式,便于编辑文件内容 3)末行模式 编辑内容后,按esc进入到命令模式,再按 ...

  8. synchronized和ReentrantLock

    一.什么是sychronized sychronized是java中最基本同步互斥的手段,可以修饰代码块,方法,类. 在修饰代码块的时候需要一个reference对象作为锁的对象. 在修饰方法的时候默 ...

  9. Java—Servlet技术

    1  Servlet 概述 Servlet简介——开发动态web资源的技术Sun公司在API提供了一个servlet接口,如开发一个java程序向浏览器输出数据:1)编写一个java类,实现servl ...

  10. 360浏览器兼容模式默认显示ie最高版本

    之前写完代码都会放在360浏览器里跑一边,基本没啥问题,因为设置的都是极速模式,极速模式内置的是webkit内核,后来测试人员测试了兼容模式,发现会出各种问题,打开控制台一看,“我的天呐”,默认的竟然 ...