zoukankan      html  css  js  c++  java
  • Linux input子系统学习总结(二)----Input事件驱动

    Input 事件驱动:  (主要文件 :drivers/input/evdev.c  、  drivers/input/input.h)基于kernel 4.0 

    一、 关键函数调用顺序:

    1、input_register_handler(&evdev_handler); ///注册 evdev_handler 这个input事件驱evdev.c   

     

    2、input_attach_handler(dev, handler);////input 设备和 input 事件进行匹配   input.h

     

    3、handler->connect(handler, dev, id);///调用evdev_handler 的 connect 函数(.connect = evdev_connect

     

    4、evdev_connect(struct input_handler *handler, struct input_dev *dev,

    const struct input_device_id *id)

     

    5、cdev_init(&evdev->cdev, &evdev_fops);//// 初始化一个 cdev

     

    6、device_add(&evdev->dev);///把初始化好的 evdev 添加到内核

                  

      在系统启动时系统会注册input事件驱动 evdev_handler,通过遍历系统中已经存在input设备,并与之进行匹配,匹配成功即条用connect函数

    创建evdev设备,即input设备节点,初始化完成之后,上层应用程序通过evdev_fops对输入设备节点进行open/write/read/ioctrl等一系列操作,

    从而完成input输入子系统的整个功能实现;

     

    二、关键代码段

     1 static struct input_handler evdev_handler = { 
     2     .event        = evdev_event,
     3     .events        = evdev_events,
     4     .connect    = evdev_connect,
     5     .disconnect    = evdev_disconnect,
     6     .legacy_minors    = true,
     7     .minor        = EVDEV_MINOR_BASE,///次设备号从64开始
     8     .name        = "evdev",
     9     .id_table    = evdev_ids,
    10 };
    11 
    12 static int __init evdev_init(void)
    13 {
    14     return input_register_handler(&evdev_handler); ///注册 evdev_handler 这个input事件驱动
    15 }
     1 int input_register_handler(struct input_handler *handler)///把input 事件驱动注册到内核
     2 {
     3     struct input_dev *dev;
     4     int error;
     5 
     6     error = mutex_lock_interruptible(&input_mutex);
     7     if (error)
     8         return error;
     9 
    10     INIT_LIST_HEAD(&handler->h_list);///初始化链表头,把链表的前和后都指向它自己
    11 
    12     list_add_tail(&handler->node, &input_handler_list);///把 handler的 node 加到 input_handler_list这个双向链表,之后就可以通过这个链表访问所有的input_handler
    13 
    14     list_for_each_entry(dev, &input_dev_list, node)  
    15         input_attach_handler(dev, handler);////inout 设备和 input 事件进行匹配
    16 
    17     input_wakeup_procfs_readers();
    18 
    19     mutex_unlock(&input_mutex);
    20     return 0;
    21 }
     1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
     2 {
     3     const struct input_device_id *id;
     4     int error;
     5 
     6     id = input_match_device(handler, dev);///input_dev 和 input_handler 通过id_table进行匹配
     7     if (!id)
     8         return -ENODEV;
     9 
    10     error = handler->connect(handler, dev, id);///如果返回id不为空就执行handler 的 connect  ---> 调用 evdev.c 的 connect 函数
    11     if (error && error != -ENODEV)
    12         pr_err("failed to attach handler %s to device %s, error: %d
    ",
    13                handler->name, kobject_name(&dev->dev.kobj), error);
    14 
    15     return error;
    16 }
     1 /*
     2  * Create new evdev device. Note that input core serializes calls
     3  * to connect and disconnect.
     4  */
     5 static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
     6              const struct input_device_id *id)
     7 {
     8     struct evdev *evdev;
     9     int minor;
    10     int dev_no;
    11     int error;
    12 
    13     minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);//动态分配一个新的设备号minor
    14     if (minor < 0) {
    15         error = minor;
    16         pr_err("failed to reserve new minor: %d
    ", error);
    17         return error;
    18     }
    19 
    20     evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);///初始化evdev ,为evdev分配空间
    21     if (!evdev) {
    22         error = -ENOMEM;
    23         goto err_free_minor;
    24     }
    25 
    26     INIT_LIST_HEAD(&evdev->client_list);///初始化队列
    27     spin_lock_init(&evdev->client_lock);
    28     mutex_init(&evdev->mutex);
    29     init_waitqueue_head(&evdev->wait);///初始化等待队列
    30     evdev->exist = true;
    31 
    32     dev_no = minor;
    33     /* Normalize device number if it falls into legacy range */
    34     if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
    35         dev_no -= EVDEV_MINOR_BASE;
    36     dev_set_name(&evdev->dev, "event%d", dev_no);///给设备设置名字(event0、event1、...)
    37 
    38     evdev->handle.dev = input_get_device(dev);
    39     evdev->handle.name = dev_name(&evdev->dev);
    40     evdev->handle.handler = handler;
    41     evdev->handle.private = evdev;
    42 
    43     evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);////根据主设备号(主设备号都是13)和次设备号生成一个设备号(次设备号从64开始)
    44     evdev->dev.class = &input_class;
    45     evdev->dev.parent = &dev->dev;
    46     evdev->dev.release = evdev_free;
    47     device_initialize(&evdev->dev);///对设备进行初始化
    48 
    49     error = input_register_handle(&evdev->handle);///注册 handle,handle 用来关联 input_dev 和 input_handler
    50     if (error)
    51         goto err_free_evdev;
    52 
    53     cdev_init(&evdev->cdev, &evdev_fops);//// 初始化一个 cdev
    54     evdev->cdev.kobj.parent = &evdev->dev.kobj;
    55     error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
    56     if (error)
    57         goto err_unregister_handle;
    58 
    59     error = device_add(&evdev->dev);///把初始化好的 evdev 添加到内核
    60     if (error)
    61         goto err_cleanup_evdev;
    62 
    63     return 0;
    64 
    65  err_cleanup_evdev:
    66     evdev_cleanup(evdev);
    67  err_unregister_handle:
    68     input_unregister_handle(&evdev->handle);
    69  err_free_evdev:
    70     put_device(&evdev->dev);
    71  err_free_minor:
    72     input_free_minor(minor);
    73     return error;
    74 }

    如下图 ,在linux 系统上 /dev/input这个路径下可以看到已经注册好的input设备节点,input设备的主设备号都是13,其中 

    按键设备的次设备号从64~95,鼠标设备的次设备号从32~63。

     

  • 相关阅读:
    为什么Java的main方法必须是public static void?
    2. 直接插入、折半插入、希尔排序及其比较(插入类排序)
    1. 冒泡与选择排序及其比较
    0.排序介绍与性能度量
    (十)更快的排序算法(归并、快排、基数)
    (九)排序(选择、插入、希尔)
    (八)递归
    (七)栈的三种实现
    (六)栈的规则及应用
    (五)如何写测试类
  • 原文地址:https://www.cnblogs.com/EaIE099/p/5054925.html
Copyright © 2011-2022 走看看