zoukankan      html  css  js  c++  java
  • 输入子系统(一)字符设备驱动框架分析

    很多分析输入子系统的文章已经讲得很清楚了,这里主要是记录自己的学习过程。参考的几篇文章:

    输入子系统学习笔记之按键实例编程

    输入子系统学习笔记之源码分析1_框架性分析

    输入子系统学习笔记之源码分析2_数据结构分析

    输入子系统学习笔记之源码分析3_流程分析

    输入子系统也是字符设备驱动,也遵循字符设备驱动的流程:

    a. 分配主设备号

    b. 构建file_operations结构体中的open,write,read...等函数

    c. 调用register_chrdev()函数注册字符设备

    d. 调用class_register()注册类

    e. 调用device_create()创建设备,linux会在sysfs目录下自动创建字符设备。

    以上的步骤同样适用于分析输入子系统,只不过上面的各个步骤可能分散在不同的文件与函数中完成。

    1. input.c中的函数input_init()完成上述a,b,c,d四步。

     1 /*
     2 *b. 构建file_operations结构体,只实现了open函数
     3 */
     4 static const struct file_operations input_fops = {
     5     .owner = THIS_MODULE,
     6     .open = input_open_file,
     7     .llseek = noop_llseek,
     8 };
     9 
    10 static int __init input_init(void)
    11 {
    12     int err;
    13 
    14     err = class_register(&input_class);/*d. 调用class_register()注册类*/
    15     if (err) {
    16         pr_err("unable to register input_dev class
    ");
    17         return err;
    18     }
    19 
    20     err = input_proc_init();
    21     if (err)
    22         goto fail1;
    23     /*
    24     *a. 分配主设备号INPUT_MAJOR=13
    25     *c. 调用register_chrdev()函数注册字符设备
    26     */
    27     err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
    28     if (err) {
    29         pr_err("unable to register char major %d", INPUT_MAJOR);
    30         goto fail2;
    31     }
    32 
    33     return 0;
    34 
    35  fail2:    input_proc_exit();
    36  fail1:    class_unregister(&input_class);
    37     return err;
    38 }

    2. 那么谁来调用device_create()创建设备?这里直接给出结论,后面再分析过程。

    handler->connect函数中会完成设备的创建工作。这里已 evdev_connect()函数为例来分析。

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

      -->for (minor = 0; minor < EVDEV_MINORS; minor++)  确定次设备号

        if (!evdev_table[minor]) break;

      -->evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);确定设备号

      -->evdev->dev.class = &input_class;

      -->dev_set_name(&evdev->dev, "event%d", minor);  设置设备名字

        -->kobject_set_name_vargs(&dev->kobj, fmt, vargs);

      -->device_initialize(&evdev->dev);

      -->device_add(&evdev->dev);

     1 static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
     2              const struct input_device_id *id)
     3 {
     4     struct evdev *evdev;
     5     int minor;
     6     int error;
     7 
     8     for (minor = 0; minor < EVDEV_MINORS; minor++)
     9         if (!evdev_table[minor])
    10             break;
    11 
    12     if (minor == EVDEV_MINORS) {
    13         pr_err("no more free evdev devices
    ");
    14         return -ENFILE;
    15     }
    16 
    17     evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
    18     if (!evdev)
    19         return -ENOMEM;
    20 
    21     INIT_LIST_HEAD(&evdev->client_list);
    22     spin_lock_init(&evdev->client_lock);
    23     mutex_init(&evdev->mutex);
    24     init_waitqueue_head(&evdev->wait);
    25 
    26     dev_set_name(&evdev->dev, "event%d", minor);
    27     evdev->exist = true;
    28     evdev->minor = minor;
    29 
    30     evdev->handle.dev = input_get_device(dev);
    31     evdev->handle.name = dev_name(&evdev->dev);
    32     evdev->handle.handler = handler;
    33     evdev->handle.private = evdev;
    34 
    35     evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
    36     evdev->dev.class = &input_class;
    37     evdev->dev.parent = &dev->dev;
    38     evdev->dev.release = evdev_free;
    39     device_initialize(&evdev->dev);
    40 
    41     error = input_register_handle(&evdev->handle);
    42     if (error)
    43         goto err_free_evdev;
    44 
    45     error = evdev_install_chrdev(evdev);
    46     if (error)
    47         goto err_unregister_handle;
    48 
    49     error = device_add(&evdev->dev);
    50     if (error)
    51         goto err_cleanup_evdev;
    52 
    53     return 0;
    54 
    55  err_cleanup_evdev:
    56     evdev_cleanup(evdev);
    57  err_unregister_handle:
    58     input_unregister_handle(&evdev->handle);
    59  err_free_evdev:
    60     put_device(&evdev->dev);
    61     return error;
    62 }
    evdev_connect()
     1 int dev_set_name(struct device *dev, const char *fmt, ...)
     2 {
     3     va_list vargs;
     4     int err;
     5 
     6     va_start(vargs, fmt);
     7     err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
     8     va_end(vargs);
     9     return err;
    10 }
    dev_set_name()

    上面的分析没有看到调用device_create()函数,但分析device_create()函数可知起始上面的步骤和device_create()内执行的一致。

    struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)

      -->device_create_vargs(class, parent, devt, drvdata, fmt, vargs);

        -->dev->class = class;

        -->dev->devt = devt;

        -->kobject_set_name_vargs(&dev->kobj, fmt, args);

        -->device_register(dev);

          -->device_initialize(dev);

          -->device_add(dev);

     1 struct device *device_create(struct class *class, struct device *parent,
     2                  dev_t devt, void *drvdata, const char *fmt, ...)
     3 {
     4     va_list vargs;
     5     struct device *dev;
     6 
     7     va_start(vargs, fmt);
     8     dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
     9     va_end(vargs);
    10     return dev;
    11 }
    device_create()
     1 struct device *device_create_vargs(struct class *class, struct device *parent,
     2                    dev_t devt, void *drvdata, const char *fmt,
     3                    va_list args)
     4 {
     5     struct device *dev = NULL;
     6     int retval = -ENODEV;
     7 
     8     if (class == NULL || IS_ERR(class))
     9         goto error;
    10 
    11     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    12     if (!dev) {
    13         retval = -ENOMEM;
    14         goto error;
    15     }
    16 
    17     dev->devt = devt;
    18     dev->class = class;
    19     dev->parent = parent;
    20     dev->release = device_create_release;
    21     dev_set_drvdata(dev, drvdata);
    22 
    23     retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
    24     if (retval)
    25         goto error;
    26 
    27     retval = device_register(dev);
    28     if (retval)
    29         goto error;
    30 
    31     return dev;
    32 
    33 error:
    34     put_device(dev);
    35     return ERR_PTR(retval);
    36 }
    device_create_vargs()
    1 int device_register(struct device *dev)
    2 {
    3     device_initialize(dev);
    4     return device_add(dev);
    5 }
    device_register()
  • 相关阅读:
    CentOS7.5右键创建空白文档
    CentOS7.5安装配置conky(极简)
    CentOS7.5安装nodejs
    CentOS7.5安装网易云音乐
    CentOS7.5删除旧的内核
    CentOS7.5安装notepadqq
    CentOS7英文环境下使用中文输入法
    CentOS7安装Pycharm后无法使用日常的快捷键
    tomcat的work目录作用
    ORACLE获取某个时间段之间的月份列表
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/6041500.html
Copyright © 2011-2022 走看看