zoukankan      html  css  js  c++  java
  • Pci设备驱动1:pci设备驱动实例(realtek8168)

    Realtek8168网卡时pci接口的网卡,其驱动程序就是一个PCI设备的驱动程序实例,我们一起看看其流程。

    1.  首先,初始化模块调用static inline int pci_register_driver(struct pci_driver *driver)函数来注册设备驱动,这个函数的参数是struct pci_driver *driver,对应于r8168,就是

    static struct pci_driver rtl8168_pci_driver = {

           .name             = MODULENAME,

           .id_table  = rtl8168_pci_tbl,

           .probe            = rtl8168_init_one,

           .remove          = __devexit_p(rtl8168_remove_one),

    #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11)

           .shutdown       = rtl8168_shutdown,

    #endif

    #ifdef CONFIG_PM

           .suspend  = rtl8168_suspend,

           .resume          = rtl8168_resume,

    #endif

    };

    这个结构体把这个设备驱动所支持的设备(rtl8168_pci_tbl),探测函数(rtl8168_init_one)等都定义好,后面我们将需要用到rtl8168_pci_tbl,rtl8168_init_one两部分内容来匹配,是否系统中的设备,看是否有设备可以跟这个驱动匹配

    2.  pci_register_driver 函数调用__pci_register_driver来完成任务,而__pci_register_driver则重新封装了要注册的驱动为PCI总线的,即

    int __pci_register_driver(struct pci_driver *drv, struct module *owner)

    {

           ……

           drv->driver.bus = &pci_bus_type;

        ……

           drv->driver.kobj.ktype = &pci_driver_kobj_type;

        ……

    }

    接下来就是调用设备驱动模型的函数,把我们要注册的驱动挂载到PCI总线的设备队列上,并扫描PCI总线的设备队列,查看是否有设备可以匹配这个驱动,这跟usb设备驱动的挂载是一致的,只是这里挂载的是PCI总线,usb挂载的是USB总线,大致的流程是

    driver_register()---àbus_add_driver()----àdriver_attach()--à__driver_attach()--àdriver_probe_device()---àdev->bus->probe(),即最后还是调用了2.中的pci_bus_type结构体中的probe成员函数,即static int pci_device_probe(struct device * dev)

    3.  static int pci_device_probe(struct device * dev)函数的参数dev就是遍历了PCI总线上的设备链表,一一进行匹配来完成的,因为我们调用__driver_attach()的方式是bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

    4.  static int pci_device_probe(struct device * dev)通过两个宏转换to_pci_driver,to_pci_dev,获得需要匹配的设备和驱动,调用static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)函数进行匹配

    5.  __pci_device_probe函数首先通过设备驱动中的rtl8168_pci_tbl表,跟从设备获得vendorID,productID进行比较,看是否一致,如果一致,就返回这个表的地址;如果没有一致的,就表明,这个设备跟这个驱动不匹配,就不需要继续进行下面的操作了,直接退出

    6.  如果第5步发现了一致的设备表,就表明有设备ID一致,需要进一步探测,接下来就要调用我们设备驱动程序中的探测函数,进行更具体的探测了,即pci_call_probe(drv, pci_dev, id)---à drv->probe(dev, id),到这里,就开始调用我们的设备驱动中的探测函数了。

    7.  static int __devinit rtl8168_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)函数是r8168的探测函数,其调用rtl8168_init_board(pdev, &dev, &ioaddr)来完成跟PCI设备驱动相关的探测。

    8.  static int __devinit rtl8168_init_board(struct pci_dev *pdev, struct net_device **dev_out, void __iomem **ioaddr_out)函数调用pci_enable_device函数来使能PCI设备,只有使能成功的PCI设备,才能正常使用。

    9.  调用pci_set_mwi函数判断设备是否支持memory-write-invalidate 功能

    10.              调用pci_find_capability函数来判断设备是否有电源管理功能.

    11.              调用pci_resource_flags函数来判断PCI是内存映射模式,还是IO模式

    12.              调用pci_resource_len函数来判断内存空间是否小于设备所需要的内存空间,如果小于,明显出错

    13.              调用pci_request_regions函数通知内核,当前PCI将使用这些内存地址,其他设备不能再使用了

    14.              调用pci_set_master(pdev)函数,设置设备具有获得总线的能力,即调用这个函数,使设备具备申请使用PCI总线的能力。

    15.              调用ioremap函数把刚刚申请的物理内存,映射成虚拟内存,因为进程使用的都是虚拟内存地址,而不是物理内存地址。

    16.              把ioremap映射的虚拟内存返回给调用函数。

    17.              到此,跟PCI相关的初始化都完成了,设备即可正常工作了

  • 相关阅读:
    JS防抖和节流
    移动端屏幕适配
    vue、react对比
    HTTP缓存
    程序员必备技术网站
    W3C标准、表现与数据分离、web语义化
    VUE的响应式原理
    react更新渲染及渲染原理
    ubuntu下mysql的环境搭建及使用
    apktool反编译工具
  • 原文地址:https://www.cnblogs.com/image-eye/p/2352912.html
Copyright © 2011-2022 走看看