精华内容
下载资源
问答
  • SPI协议数据传输具体的逻辑,详细介绍SPI总线架构! 知识回顾:Linux主机驱动和外设驱动分离思想
  • linux设备驱动程序注册过程详解

    千次阅读 2017-01-11 14:16:40
    Linux驱动程序注册过程,大致分为两个步骤: 模块初始化驱动程序注册 下面以内核提供的示例代码pci-skeleton.c,详细说明一个pci设备驱动程序的注册过程。其他设备的驱动代码注册过程基本相同,大家可自行查看...

    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 }
    可以看到,初始化函数很简单,只执行了一个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     <strong><span style="color:#ff0000;">int (*match)(struct device *dev, struct device_driver *drv);</span></strong>
     。。。
     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
    <strong><span style="color:#ff0000;">419     struct bus_type *bus;       /* type of bus device is on */
    420     struct device_driver *driver;   /* which driver has allocated this
    421                        device */</span></strong>
    。。。
    456
    457     void    (*release)(struct device *dev);
    458 };
    驱动:
    122 struct device_driver {
    123     const char      *name;
    <strong><span style="color:#ff0000;">124     struct bus_type     *bus;</span></strong>
    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
    <strong><span style="color:#ff0000;">135     int (*probe) (struct device *dev);</span></strong>
    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;
     <strong><span style="color:#ff0000;">554     struct device_driver    driver;</span></strong>
     555     struct pci_dynids dynids;
     556 };
    仔细看这个结构,发现其中一个成员是我们上面的总线设备模型中的driver的结构体。 其实在linux内核中,所有设备的驱动的定义,都是以struct device_driver为基类,进行继承与扩展的。 你没有看错,内核当中使用了很多OO的思想。再看看网卡I2C设备的的驱动描述:
    143 struct i2c_driver {
    144     unsigned int class;
    145
    。。。
    <strong><span style="color:#ff0000;">174     struct device_driver driver;</span></strong>
    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     <strong><span style="color:#ff0000;">error = driver_register(&drv->driver);</span></strong>
    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\n", 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...\n", drv->name);
    240         return -EBUSY;
    241     }
    242
    243     <strong><span style="color:#ff0000;">ret = bus_add_driver(drv);</span></strong>
    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         <strong><span style="color:#ff0000;">error = driver_attach(drv);</span></strong>
     653         if (error)
     654             goto out_unregister;
     655     }
     。。。。。。。。。。。。。。。
     690 }
    303 int driver_attach(struct device_driver *drv)
    304 {
    305     return <strong><span style="color:#ff0000;">bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);</span></strong>
    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     <strong>if (!driver_match_device(drv, dev))</strong>
    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         <strong><span style="color:#ff0000;">driver_probe_device(drv, dev);</span></strong>
    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\n",
    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\n",
    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\n",
    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函数的实现,需要根据驱动程序的功能来定,不属于本文的讨论范围。


    说明 :本文转自http: //www.tuicool.com/articles/J32i2m

    展开全文
  • linux设备驱动程序注册过程详解(一)

    千次阅读 多人点赞 2018-05-16 19:28:52
    原文地址:http://blog.csdn.net/tuzhutuzhu/article/details/34445847Linux驱动程序注册过程,大致分为两个步骤:模块初始化驱动程序注册下面以内核提供的示例代码pci-skeleton.c,详细说明一个pci设备驱动程序的...

     原文地址:http://blog.csdn.net/tuzhutuzhu/article/details/34445847

    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这个函数。---至于何时驱动模块加载,何时驱动模块卸载,有待后续追踪follow up

    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 }
    可以看到,模块初始化函数很简单,只执行了一个pci_register_driver函数就返回了。
    其实模块的初始化过程就是这么简单,这也是linux驱动程序的ISO标准流程:module_init-->xx_init_module-->xx_register_driver。在这里xxx_register_driver中是驱动注册到XX总线上

    International Standardization Operation
    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);
    };
    设备:
    406   struct  device {
    407       struct  device       *parent;
    408     struct  device_private   *p;
    410     struct  kobject kobj;
    412       const  char      *init_name;  /* initial name of the device */
    413       struct  device_type  * type ;
    414     struct  mutex        mutex;  /* mutex to synchronize calls to */
    419       struct  bus_type *bus;        /* type of bus device is on */
    420      struct device_driver *driver; /* which driver has allocated this 421 device */
    456       void (* release )( struct device *dev);
    458 };
    驱动:
    122  struct  device_driver {
    123      const  char      *name;
    124      struct bus_type *bus;
    125      struct module *owner;
    127      const  char *mod_name; /* used for built-in modules */
    128      bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
    130      #if defined(CONFIG_OF)
    132      const  struct of_device_id *of_match_table;
    133 #endif
    135      int (* probe) ( struct device *dev);</span></strong>
    136      int (* remove) ( struct device *dev); };

    上述三个结构体中,我将下文需要使用的成员进行了标识,后面会讨论到。

    对比上面的三个结构体,你会发现:总线中既定义了设备,也定义了驱动;设备中既有总线,也有驱动;驱动中既有总线也有设备相关的信息。那这三个的关系到底是什么呢?

    三者的关系是:
    内核要求每次出现一个设备,就要向总线汇报,会着说注册;每次出现一个驱动,也要向总线汇报,或者叫注册。比如系统初始化时,会扫描连接了哪些设备,并为每一个设备建立一个struct device变量,并为每一个驱动程序准备一个struct device_driver结构的变量。把这些量变量加入相应的链表,形成一条设备链表和一条驱动链表 。这样,就能通过总线找到注册挂载在该总线上的每一个设备和每一个驱动程序。

    当一个struct device诞生,总线就会去driver链表找设备对应的驱动程序。如果找到就执行设备的驱动程序,否则就等待。反之亦然。

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

    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 called */
      546       int   (*probe)  ( struct  pci_dev *dev,  const   struct  pci_device_id *id);    /* New device 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     struct device_driver driver;
    175      const  struct i2c_device_id *id_table;
    176      /* 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     /* 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     spin_lock_init(&drv->dynids.lock);
    1115      INIT_LIST_HEAD(&drv->dynids. list);
    1116     /* 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 ;
    227     BUG_ON(!drv->bus->p) ;
    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\n", drv->name) ;
    235     other = driver_find( drv->name, drv->bus) ;//根据driver_name 在bus链表上面查找到驱动driver(驱动链表& 设备链表)
    236     if ( other) {//驱动已经被注册了
    237         put_driver( other) ;
    238         printk( KERN_ERR  "Error: Driver '%s' is already registered, "
    239              "aborting...\n", drv->name) ;
    240         return -EBUSY ;
    241     }
    242     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,  NULLNULL);
      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         error = fn(dev, data);
    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))//在驱动driver注册到总线时调用match函数
    280          return  0;
    281     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);//当驱动注册到总线并match成功后,调用驱动probe()函数
    287     device_unlock(dev);
    288      if (dev->parent)
    289         device_unlock(dev->parent);
    290     return  0;
    292 }

    279行的driver_match_device函数就是用来为driver匹配device的。match函数和probe函数被调用的地方

     if (!driver_match_device(drv, dev))//在驱动driver注册到总线时调用match函数。

    286         driver_probe_device(drv, dev);//当驱动注册到总线并match成功后,调用驱动probe()函数


    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中注册BUS总线上的match函数来进行匹配了,匹配的具体过程就不看了。再回到上面的__driver_attach函数的driver_probe_device中。

    200  int  driver_probe_device( struct  device_driver *drv,  struct  device *dev)
    201 {
    202      int ret =  0;
    203     if (!device_is_registered(dev))
    205          return -ENODEV;
    206     pr_debug( "bus: '%s': %s: matched device %s with driver %s\n",
    208          drv->bus->name, __func__, dev_name(dev), drv->name);
    209     pm_runtime_get_noresume(dev);
    211     pm_runtime_barrier(dev);
    212     ret =  really_probe(dev, drv);
    213     pm_runtime_put_sync(dev);
    214     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\n",
    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\n",
    120             __func__, dev_name(dev));
    121         goto probe_failed;
    122     }
    123     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函数的实现,需要根据驱动程序的功能来定,不属于本文的讨论范围。


    展开全文
  • Linux内核驱动注册方式泛谈

    千次阅读 2014-07-09 22:15:50
    Linux驱动注册有多种方式,通常是以内核提供的表征数据结构封装后按照内核子系统提供的接口函数进行注册,还有一些是比较复杂的以链表方式进行维护。以下对几种驱动注册方式进行介绍: 一、子系统有专门的驱动注册...

     Linux驱动注册有多种方式,通常是以内核提供的表征数据结构封装后按照内核子系统提供的接口函数进行注册,还有一些是比较复杂的以链表方式进行维护。以下对几种驱动注册方式进行介绍:

    一、子系统有专门的驱动注册函数:

    例如RTC子系统,提供rtc_device_register注册接口函数。

    例如:

    rtc_device_register(client->name,&client->dev, &rx8025_rtc_ops, THIS_MODULE);

    static struct rtc_class_ops rx8025_rtc_ops= {

             .read_time= rx8025_get_time,

             .set_time= rx8025_set_time,

             .read_alarm= rx8025_read_alarm,

             .set_alarm= rx8025_set_alarm,

             .alarm_irq_enable= rx8025_alarm_irq_enable,

    };

    主要实现rtc_class_ops。使用RTC接口rtc_device_register,注册到RTC子系统中,受RTC子系统控制,包括设备创建,PROC和SYS文件系统属性创建。可以使用RTC子系统接口文件interface.c中的函数。

    另外网口类型驱动也是有专门的接口:

    register_netdev(ndev);

    注册网口后受内核管理。

     

    二、没有专门的驱动注册函数

    这类驱动注册比较直接,按照通用的字符驱动函数进行。例如看门狗类驱动。采用misc类型驱动进行注册。

    例如:

    misc_register(&rc32434_wdt_miscdev);

    static const struct file_operationsrc32434_wdt_fops = {

             .owner               = THIS_MODULE,

             .llseek                = no_llseek,

             .write                 = rc32434_wdt_write,

             .unlocked_ioctl         = rc32434_wdt_ioctl,

             .open                 = rc32434_wdt_open,

             .release   = rc32434_wdt_release,

    };

    实现看门狗自有的接口。

     

    三、复杂驱动

       该类驱动在内核配置中有专门的选项,一旦选中该选项,在内核启动后会执行相关系统模块初始化,维护一个链表,而具体驱动是往该链表中添加成员,系统模块会检测新成员加入并完成加入到子系统处理工作。

    例如PCI:

    PCI子系统在注册时启动BIOS:

    subsys_initcall(pcibios_init);

    其中subsys_initcall在内核初始化时进行调用。

    关于subsys_initcall定义:

    #define pure_initcall(fn)             __define_initcall("0",fn,0)

    #define core_initcall(fn)             __define_initcall("1",fn,1)

    #define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)

    #define postcore_initcall(fn)         __define_initcall("2",fn,2)

    #definepostcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)

    #define arch_initcall(fn)             __define_initcall("3",fn,3)

    #define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)

    #define subsys_initcall(fn)           __define_initcall("4",fn,4)

    #define subsys_initcall_sync(fn)      __define_initcall("4s",fn,4s)

    #define fs_initcall(fn)               __define_initcall("5",fn,5)

    #define fs_initcall_sync(fn)          __define_initcall("5s",fn,5s)

    #define rootfs_initcall(fn)    __define_initcall("rootfs",fn,rootfs)

    #define device_initcall(fn)           __define_initcall("6",fn,6)

    #define device_initcall_sync(fn)      __define_initcall("6s",fn,6s)

    #define late_initcall(fn)             __define_initcall("7",fn,7)

    #define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)

    在链接脚本vmlinux.lds中有这么一段:


    各段在内核文件中的位置:


    当内核在配置是选中PCI总线子系统时,内核启动后即会执行subsys_initcall(pcibios_init);

    该模块维护一个全局变量hose_list。并以链表管理的方式进行管理,一旦该链表有新成员添加即会使用PCI子系统对其进行处理,包括扫描,探测等。

       该方式主要工作是要往hose_list链表中添加成员然后即可使用PCI子系统。以Powerpc为例,PCI流程示意图如下所示:


    CPU在内核启动后初始化ARCH重要模块,其中添加一个PCI桥,桥对Powerpc 的PCI控制器资源解析并分配一个controller控制器,然后添加到hose_list链表中。完成注册工作。

    而pci_32.c文件中是对BOIS的管理,其中对hose_list链表的管理,管理添加进行的成员。发现有成员注册进来即会使用PCI子系统进行相关处理。

    类似的RapdiIO驱动:

    RapidIO系统也是采用类似PCI的方式,在内核配置时选中RapidIO后系统运行即会启动RapidIO子系统。

    在rio.c中:

    int __devinit rio_init_mports(void)

    {

             struct rio_mport *port;

             list_for_each_entry(port,&rio_mports, node) {

                       if(port->host_deviceid >= 0)

                                rio_enum_mport(port);

                       else

                                rio_disc_mport(port);

             }

             rio_init();

             return 0;

    }

    device_initcall_sync(rio_init_mports);

    其中device_initcall_sync就是上面讲到的初始化段。

    #define device_initcall_sync(fn)      __define_initcall("6s",fn,6s)

    执行这个初始化启动RapidIo子系统的条件是内核中有相关配置。

    再以Powerpc为例,以下是添加到RapidIO子系统的过程:


    其中,rio.c中维护rio-mports链表,检测是否有新成员注册进来,一旦有新成员注册进来即添加到rapidIO子系统中进行处理。

      而fsl_rio.c文件中有subsys_initcall初始化,完成RapdidIo驱动注册,这部分的工作也是内核配置之后即可完成。而注册完之后按照Powerpc上的资源进行解析并添加mport到rio-mports链表中。完成注册。

     RapidIo的注册过程与PCI的注册过程属于同一种类型的。都是内核在配置时选中相关支持启动子系统,子系统启动一个检测链表的工作。而具体的驱动需要往该链表中添加成员。


    展开全文
  • kernel版本3.10.14 driver_register顾名思义,是驱动程序的注册。但是很少是由我们写的驱动直接调用的,例如framebuffer中调用platform_driver_register,i2c中调用i2c_add_driver
     
     
     
     
     
     
     
    

    展开全文
  • Linux V4L2驱动详解

    2019-10-15 02:11:56
    嵌入式Linux中V4L2驱动详解 目录 一、API介绍 二、注册和open 三、基本ioctl处理 四、输入和输出 五、颜色与格式 六、格式协商 七、基本的帧IO 八、流IO 九、控制
  • 修改linux内核3.2.0 的 rtc 驱动 rtc-pcf8563.c (源码位置: drivers/rtc), 实现 i2c 驱动层平台设备的动态生成, 而无需在板级初始化中注册 i2c 设备 资源包含两个文件: rtc-pcf8563.c 和 rtc-pcf8563内核源码.c, ...
  • 本文简单的说明了一个实现API函数的全部过程。 总体上看分为: 1,用户API 2,用户中间层(与底层通信) 3,底层中间层(寻找对应的驱动函数) 4,驱动函数 5, CPU读写I/O端口。...我们主要的工作就是这个驱动部分
  • 主要介绍了详解Linux驱动中,probe函数何时被调用 ,具有一定的参考价值,有兴趣的同学可以了解一下。
  • 一、linux的设备驱动程序与外界的接口可以分为三个部分:  1.驱动程序与操作系统内核的接口。通过file_operations(include/linux/fs.h)数据结构来完成的。  2.驱动程序与系统引导的接口。这部分利用驱动程序对...
  • 嵌入式 Linux 按键驱动

    千次阅读 2021-12-21 22:54:59
    设备树与驱动如何匹配?
  • 详细讲解Linux驱动程序

    千次阅读 2021-05-08 23:40:04
    一 ?编写Linux驱动程序1.建立Linux驱动骨架? Linux内核在使用驱动时需要装载与卸载驱动?装载驱动:建立设备文件、分配内存地址空间等;...注册和注销设备文件任何一个Linux驱动都需要有一个设备文件,...
  • linux设备驱动框架

    万次阅读 多人点赞 2018-05-26 11:32:00
    一.Linux设备分类字符设备: 以字节为单位读写的设备。块设备 : 以块为单位(效率最高)读写的设备。网络设备 : 用于网络通讯设备。字符设备: 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,...
  • 从单片机到ARM Linux驱动——Linux驱动入门篇

    万次阅读 多人点赞 2020-10-24 10:58:43
    文章目录 字符设备驱动简介 字符设备驱动开发步骤 驱动模块的加载和卸载 字符设备注册与注销 实现设备的具体操作函数 添加LICENSE和作者信息 Linux设备号 设备号的组成 设备号的分配 字符设备驱动简介 字符设备是...
  • linux文件过滤驱动,编译成模块之后直接加载
  • linux 驱动开发之 中断注册

    千次阅读 2018-06-18 23:50:36
    之前一直学习的是Linux系统下面的字符驱动开发,但是那仅仅是Linux驱动下面的冰山一角,Linux驱动开发还包括什么网络设备开发、原子锁、块设备开发、网络设备开发等等部分,本篇文章将介绍linux架构下面中断注册。...
  • linux音频驱动详解--宋宝华

    热门讨论 2009-07-05 14:14:39
    主要介绍linux音频驱动,本文摘自宋宝华的《linux驱动详解》第十七章。不要积分的。
  • Linux字符设备驱动注册三种方法以及内核分析

    千次阅读 多人点赞 2018-10-07 15:59:38
    Linux驱动是用户访问底层硬件的桥梁,驱动有可以简单分成三类:字符设备、块设备、网络设备。其中最多的是字符设备,其中字符设备的注册方法主要有三种:杂项设备注册、早期字符设备注册、标准字符设备注册。以及...
  • linux驱动开发架构

    万次阅读 多人点赞 2019-05-30 14:38:37
    驱动模型 最近开始开发驱动,现总结通用驱动开发模型如下 驱动整体模型: 添加一个设备,多数需要用户空间下发指令等操作。那么有两个问题: kernel如何控制设备 用户空间如何和kernel中的驱动交互 问题1: ...
  • Linux 打印机驱动安装

    千次阅读 2021-05-17 18:22:53
    Linux打印机驱动安装(2010-11-05 16:16:55)标签:杂谈1、下载相应驱动,解压2、编译Compile:$ makeGet extra files from the web, such as .ICM profiles for color correction,and firmware. Select the model ...
  • 嵌入式Linux音频驱动开发

    千次阅读 多人点赞 2017-12-29 13:52:00
    1.嵌入式音频系统硬件连接 ...ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构 在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了al
  • Linux下的CDC-ACM驱动源码,USB虚拟串口驱动程序,欢迎下载学习!
  • linux总线驱动框架分析

    千次阅读 2018-08-08 15:30:31
    linux的总线驱动模型主要可以分为三个部分:总线、设备、驱动。  内核初始化会先调用platform_bus_init()初始化platform_bus总线,之后由_initcall的优先级顺序可知先初始化各种实际总线例如spi、i2c。之后注册...
  • linux驱动之字符设备驱动(一)

    千次阅读 2019-05-30 07:19:46
    关于linux操作系统,相信做过嵌入式开发的人或多或少都有所了解,都听说过它是一个优秀的,开源的os,在嵌入式设备行业、服务器行业,我们无处不见linux的身影,在这里想给大家纠正一个不太好的观念(可能是我自己...
  • linux设备驱动之PCIE驱动开发

    万次阅读 多人点赞 2017-11-13 13:47:00
    PCIE(PCI Express)是INTEL提出的新一代的总线接口,目前普及的PCIE 3.0的传输速率为8GT/s,下一代PCIE 4.0将翻番为16GT/S,因为传输速率快广泛应用于数据中心、云计算、人工智能...实现基本的PCIE驱动程序,实现以下模
  • Linux网卡驱动(1)-网卡驱动架构分析

    千次阅读 多人点赞 2019-06-16 15:33:09
    1.Linux网络子系统 我们这里研究内核空间即可,在内核空间分成5层,分别是: 1、系统调用接口,它面向的客户是应用层序,为应用程序提供访问网络子系统的统一方法,比如说socket,send等函数的系统调用 2、协议...
  • 【ARM】Linux驱动移植

    千次阅读 2017-06-06 21:59:09
    2Linux驱动原理 0从哪里切入 1什么是注册 2register_chrdev提交哪些数据 21设备号为什么是231 22设备名随便给 23文件操作结构体怎么设置 什么是THIS_MODULE Opencloseread这些都好理解 3register_chrdev...
  • linux以太网驱动总结

    万次阅读 2017-05-24 13:37:31
    linux以太网驱动总结工作中涉及linux以太网驱动,涉及代码:drivers/net/ethernet/stmicro/,drivers/net/phy/,进行一下总结。 概要: 1.以太网硬件 2.软件初始化probe, open 3.数据发送过程 4.数据接收过程 ...
  • 十九、Linux驱动之虚拟网卡驱动

    千次阅读 2018-12-11 17:22:46
    1. 基本概念  网络设备是完成用户数据包在网络媒介上发送和接收的设备,它将上层协议传递下来的数据包以特定的媒介访问控制方式进行发送,并将接收到的数据包... Linux系统对网络设备驱动定义了4个层次, 从上到...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 113,518
精华内容 45,407
关键字:

linux注册驱动

linux 订阅