• linux设备驱动程序注冊过程具体解释


    Linux的驱动程序注冊过程,大致分为两个步骤:
    • 模块初始化
    • 驱动程序注冊
    以下以内核提供的演示样例代码pci-skeleton.c,具体说明一个pci设备驱动程序的注冊过程。其它设备的驱动代码注冊过程基本同样,大家可自行查看。使用的内核代码版本号是2.6.38。

    1. 模块初始化

    1.1 驱动程序入口

    全部的设备驱动程序都会有例如以下两行代码:
    1922 module_init(netdrv_init_module);
    1923 module_exit(netdrv_cleanup_module);
    
    module_init/module_exit是两个宏。module_init是该驱动程序的入口,载入驱动模块时,驱动程序就从netdrv_init_module函数開始运行。而当该驱动程序相应的设备被删除了,则会运行netdrv_cleanup_module这个函数。

    1.2 模块初始化

    当驱动程序開始运行时,首先会运行该驱动程序的初始化函数netdrv_init_module,代码例如以下:
    1906 static int __init netdrv_init_module(void)
    1907 {
    1908 /* when a module, this is printed whether or not devices are found in probe */
    1909 #ifdef MODULE
    1910     printk(version);
    1911 #endif
    1912     return pci_register_driver(&netdrv_pci_driver);
    1913 }
    能够看到,初始化函数非常easy,仅仅运行了一个pci_register_driver函数就返回了。
    事实上模块的初始化过程就是这么简单,这也是linux驱动程序的ISO标准流程:module_init-->xx_init_module-->xx_register_driver。相信你看着这里时,还是一头雾水。别着急,我们慢慢来。

    2. 驱动程序注冊

    什么是驱动模块的注冊?上面讲到的初始化函数中调用的pci_register_driver函数就是注冊驱动程序啦。在介绍注冊函数之前,必需要具体说明下linux的总线设备驱动模型,否则以下的内容非常难描写叙述清楚。

    2.1 linux总线设备驱动模型

    关于总线设备驱动模型,非常多书上都有具体的解说,可是都非常抽象,非常难理解(至少我是这样觉得的)。以下我尽量用最简单的方法来说明相关内容。
    linux内核中分别用struct bus_type,struct device和struct device_driver来描写叙述总线、设备和驱动。
    总线:
     50 struct bus_type {
     51     const char      *name;
     52     struct bus_attribute    *bus_attrs;
     53     struct device_attribute *dev_attrs;
     54     struct driver_attribute *drv_attrs;
     55
     56     int (*match)(struct device *dev, struct device_driver *drv);
     。。。
     68 };
    设备:
    406 struct device {
    407     struct device       *parent;
    408
    409     struct device_private   *p;
    410
    411     struct kobject kobj;
    412     const char      *init_name; /* initial name of the device */
    413     struct device_type  *type;
    414
    415     struct mutex        mutex;  /* mutex to synchronize calls to
    416                      * its driver.
    417                      */
    418
    419     struct bus_type *bus;       /* type of bus device is on */
    420     struct device_driver *driver;   /* which driver has allocated this
    421                        device */
    。。。
    456
    457     void    (*release)(struct device *dev);
    458 };
    驱动:
    122 struct device_driver {
    123     const char      *name;
    124     struct bus_type     *bus;
    125
    126     struct module       *owner;
    127     const char      *mod_name;  /* used for built-in modules */
    128
    129     bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */
    130
    131 #if defined(CONFIG_OF)
    132     const struct of_device_id   *of_match_table;
    133 #endif
    134
    135     int (*probe) (struct device *dev);
    136     int (*remove) (struct device *dev);
    。。。
    145 };
    上述三个结构体中,我将下文须要使用的成员进行了标识,后面会讨论到。
    对照上面的三个结构体,你会发现:总线中既定义了设备,也定义了驱动;设备中既有总线,也有驱动;驱动中既有总线也有设备相关的信息。那这三个的关系究竟是什么呢?
    三者的关系是:
    内核要求每次出现一个设备,就要向总线汇报,会着说注冊;每次出现一个驱动,也要向总线汇报,或者叫注冊。比方系统初始化时,会扫描连接了哪些设备,并为每个设备建立一个struct device变量,并为每个驱动程序准备一个struct device_driver结构的变量。把这些量变量添�对应的链表,形成一条设备链表和一条驱动量表。这样,总线就能通过总线找到每个设备和每个驱动程序。
    当一个struct device诞生,总线就会去driver链表找设备相应的驱动程序。假设找到就运行设备的驱动程序,否则就等待。反之亦然。

    另一个须要注意的地方:
    usb_type结构体的match函数,它的两个參数一个是驱动,还有一个则是设备。这个函数就是用来进行推断,总线上的驱动程序能不能处理设备的。至于这个函数什么时候调用,怎么调用,后面会有说。

    2.2 注冊函数具体解释

    以下我们来详解驱动的注冊函数。

    2.2.1 驱动的描写叙述

    首先从register函数的函数原型看起:
    896 #define pci_register_driver(driver)     
    897     __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
    
    1103 int __pci_register_driver(struct pci_driver *drv, struct module *owner,
    1104               const char *mod_name)
    真正的注冊函数式__pci_register_driver(),它的第一个參数是struct pci_driver类型的,再看看这个结构的定义:
     542 struct pci_driver {
     543     struct list_head node;
     544     const char *name;
     545     const struct pci_device_id *id_table;   /* must be non-NULL for probe to be calle     d */
     546     int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);   /* New de     vice inserted */
     547     void (*remove) (struct pci_dev *dev);   /* Device removed (NULL if not a hot-plug      capable driver) */
     548     int  (*suspend) (struct pci_dev *dev, pm_message_t state);  /* Device suspended *     /
     549     int  (*suspend_late) (struct pci_dev *dev, pm_message_t state);
     550     int  (*resume_early) (struct pci_dev *dev);
     551     int  (*resume) (struct pci_dev *dev);                   /* Device woken up */
     552     void (*shutdown) (struct pci_dev *dev);
     553     struct pci_error_handlers *err_handler;
     554     struct device_driver    driver;
     555     struct pci_dynids dynids;
     556 };
    细致看这个结构,发现其中一个成员是我们上面的总线设备模型中的driver的结构体。事实上在linux内核中,全部设备的驱动的定义,都是以struct device_driver为基类,进行继承与扩展的。你没有看错,内核其中使用了非常多OO的思想。再看看网卡I2C设备的的驱动描写叙述:
    143 struct i2c_driver {
    144     unsigned int class;
    145
    。。。
    174     struct device_driver driver;
    175     const struct i2c_device_id *id_table;
    176
    177     /* Device detection callback for automatic device creation */
    178     int (*detect)(struct i2c_client *, struct i2c_board_info *);
    179     const unsigned short *address_list;
    180     struct list_head clients;
    181 };
    如今我们知道了pci设备的驱动程序的描写叙述方法。可是问题又来了:这么复杂的一个结构体,我们怎么用呢?
    首先看下实例代码中是怎么玩的:
    1894 static struct pci_driver netdrv_pci_driver = {
    1895     .name       = MODNAME,
    1896     .id_table   = netdrv_pci_tbl,
    1897     .probe      = netdrv_init_one,
    1898     .remove     = __devexit_p(netdrv_remove_one),
    1899 #ifdef CONFIG_PM
    1900     .suspend    = netdrv_suspend,
    1901     .resume     = netdrv_resume,
    1902 #endif /* CONFIG_PM */
    1903 };
    我们能够看出来,并非这个结构体的全部成员我们都要操作,我们仅仅管当中最关键的几个即可了。
    那上面的几个分别什么作用呢?
    name:驱动模块的名字,这个能够忽略。
    id_table:这个id的表非常重要,它的作用是匹配驱动所支持的设备。相同看看代码中的使用方法:
     221 static DEFINE_PCI_DEVICE_TABLE(netdrv_pci_tbl) = {
     222     {0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
     223     {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NETDRV_CB },
     224     {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX },
     225 /*  {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
     226     {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
     227     {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
     228     {0,}
     229 };
     230 MODULE_DEVICE_TABLE(pci, netdrv_pci_tbl);
    这里表示的就是本驱动程序支持的设备类型。
    probe:这个函数指针相同非常重要。当驱动匹配到了相应的设备之后,就会调用该函数来驱动设备。所以能够说这个函数才是驱动程序真正的入口。
    remove:当驱动程序相应的设备被删除之后,使用这个函数来删除驱动程序。
    综合看来,上面的id_table和probe函数好像是最重要的,那我们就看看它们是怎么使用的。

    2.2.2 驱动-设备的匹配

    上面在说明probe函数的时候说到:当驱动匹配到了相应的设备之后,就会调用该函数来驱动设备。这个匹配是什么意思?怎样进行匹配?跟bus结构体中的match函数有没有关系?
    带着这几个问题,我们来看看register函数。这里我将仅仅说明驱动-设备匹配相关的内容,过程中看到的其它内容不在讨论范围内。我们将调用过程加粗和标红。
    1103 int __pci_register_driver(struct pci_driver *drv, struct module *owner,
    1104               const char *mod_name)
    1105 {
    1106     int error;
    1107
    1108     /* initialize common driver fields */
    1109     drv->driver.name = drv->name;
    1110     drv->driver.bus = &pci_bus_type;
    1111     drv->driver.owner = owner;
    1112     drv->driver.mod_name = mod_name;
    1113
    1114     spin_lock_init(&drv->dynids.lock);
    1115     INIT_LIST_HEAD(&drv->dynids.list);
    1116
    1117     /* register with core */
    1118     error = driver_register(&drv->driver);
    1119     if (error)
    1120         goto out;
    1121
             。。。。。。。。
    1137 }
    __pci_register_driver函数中,调用driver_register,在总线上注冊驱动。
    222 int driver_register(struct device_driver *drv)
    223 {
    224     int ret;
    225     struct device_driver *other;
    226
    227     BUG_ON(!drv->bus->p);
    228
    229     if ((drv->bus->probe && drv->probe) ||
    230         (drv->bus->remove && drv->remove) ||
    231         (drv->bus->shutdown && drv->shutdown))
    232         printk(KERN_WARNING "Driver '%s' needs updating - please use "
    233             "bus_type methods
    ", drv->name);
    234
    235     other = driver_find(drv->name, drv->bus);
    236     if (other) {
    237         put_driver(other);
    238         printk(KERN_ERR "Error: Driver '%s' is already registered, "
    239             "aborting...
    ", drv->name);
    240         return -EBUSY;
    241     }
    242
    243     ret = bus_add_driver(drv);
    244     if (ret)
    245         return ret;
    246     ret = driver_add_groups(drv, drv->groups);
    247     if (ret)
    248         bus_remove_driver(drv);
    249     return ret;
    250 }
    driver_register中调用bus_add_driver,将设备驱动加入�到总线上。
     625 int bus_add_driver(struct device_driver *drv)
     626 {
      。。。。。。。。。。。。。
     642     klist_init(&priv->klist_devices, NULL, NULL);
     643     priv->driver = drv;
     644     drv->p = priv;
     645     priv->kobj.kset = bus->p->drivers_kset;
     646     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
     647                      "%s", drv->name);
     648     if (error)
     649         goto out_unregister;
     650
     651     if (drv->bus->p->drivers_autoprobe) {
     652         error = driver_attach(drv);
     653         if (error)
     654             goto out_unregister;
     655     }
     。。。。。。。。。。。。。。。
     690 }
    303 int driver_attach(struct device_driver *drv)
    304 {
    305     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
    306 }
    能够看出来,上面讲驱动程序追加到总线上之后,如今開始将设备与驱动进行匹配了。
     285 int bus_for_each_dev(struct bus_type *bus, struct device *start,
     286              void *data, int (*fn)(struct device *, void *))
     287 {
      。。。。。。。。。。。。
     295     klist_iter_init_node(&bus->p->klist_devices, &i,
     296                  (start ? &start->p->knode_bus : NULL));
     297     while ((dev = next_device(&i)) && !error)
     298         <span style="color:#ff0000;">error = fn(dev, data);</span>
     299     klist_iter_exit(&i);
     300     return error;
     301 }
    这里的fn就是__driver_attach函数,我们来看一下它干了什么:
    265 static int __driver_attach(struct device *dev, void *data)
    266 {
    267     struct device_driver *drv = data;
    。。。。。。。。。。。。。。。
    279     if (!driver_match_device(drv, dev))
    280         return 0;
    281
    282     if (dev->parent)    /* Needed for USB */
    283         device_lock(dev->parent);
    284     device_lock(dev);
    285     if (!dev->driver)
    286         driver_probe_device(drv, dev);
    287     device_unlock(dev);
    288     if (dev->parent)
    289         device_unlock(dev->parent);
    290
    291     return 0;
    292 }

    279行的driver_match_device函数就是用来为driver匹配device的

    108 static inline int driver_match_device(struct device_driver *drv,
    109                       struct device *dev)
    110 {
    111     return drv->bus->match ? drv->bus->match(dev, drv) : 1;
    112 }
    这里開始调用device_driver中注冊的match函数来进行匹配了,匹配的详细过程就不看了。再回到上面的__driver_attach函数的driver_probe_device中。

    200 int driver_probe_device(struct device_driver *drv, struct device *dev)
    201 {
    202     int ret = 0;
    203
    204     if (!device_is_registered(dev))
    205         return -ENODEV;
    206
    207     pr_debug("bus: '%s': %s: matched device %s with driver %s
    ",
    208          drv->bus->name, __func__, dev_name(dev), drv->name);
    209
    210     pm_runtime_get_noresume(dev);
    211     pm_runtime_barrier(dev);
    212     ret = really_probe(dev, drv);
    213     pm_runtime_put_sync(dev);
    214
    215     return ret;
    216 }
    108 static int really_probe(struct device *dev, struct device_driver *drv)
    109 {
    110     int ret = 0;
    111
    112     atomic_inc(&probe_count);
    113     pr_debug("bus: '%s': %s: probing driver %s with device %s
    ",
    114          drv->bus->name, __func__, drv->name, dev_name(dev));
    115     WARN_ON(!list_empty(&dev->devres_head));
    116
    117     dev->driver = drv;
    118     if (driver_sysfs_add(dev)) {
    119         printk(KERN_ERR "%s: driver_sysfs_add(%s) failed
    ",
    120             __func__, dev_name(dev));
    121         goto probe_failed;
    122     }
    123
    124     if (dev->bus->probe) {
    125         ret = dev->bus->probe(dev);
    126         if (ret)
    127             goto probe_failed;
    128     } else if (drv->probe) {
    129         ret = drv->probe(dev);
    130         if (ret)
    131             goto probe_failed;
    132     }
    133
       。。。。。。。。。。。。。。
    160 }
    到这里,最终看到drv->probe函数了。驱动程序的probe函数開始运行了,驱动程序的注冊工作也就大功告成了。

    3. 总结

    我们来总结一下设备驱动程序初始化的几个步骤:
    1. 依据设备类型,构造所需描写叙述驱动的结构体。该结构体须要继承struct device_driver结构,并给几个重要的成员初始化。
    2. 通过module_init宏调用驱动程序的初始化函数xx_init_module,在初始化函数中注冊驱动程序。
    3.驱动程序会遍历总线上的struct device和struct device_driver两条链表,调用总线的match函数,对设备与驱动程序进行匹配。
    4.假设设备与驱动程序匹配成功,则调用驱动程序的probe函数。probe函数的实现,须要依据驱动程序的功能来定,不属于本文的讨论范围。
  • 相关阅读:
    C#实体类对象修改日志记录
    C#中关于增强类功能的几种方式
    Elasticsearch入坑指南之RESTful API
    React入门实例
    .Net Core+Vue.js+ElementUI 实现前后端分离
    ElasticSearch入坑指南之概述及安装
    MySQL优化技巧
    RabbitMQ入门教程——路由(Routing)
    RabbitMQ入门教程——发布/订阅
    RabbitMQ入门教程——工作队列
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4024178.html
Copyright © 2020-2023  润新知