pci匯流排驅動及pci裝置驅動註冊

picaso77發表於2020-12-22

一、PCI匯流排註冊

1、pci匯流排註冊對應建構函式

static int __init pci_driver_init(void)
{
    return bus_register(&pci_bus_type);
}

postcore_initcall(pci_driver_init);

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

#define __define_initcall(level,fn) \
    static initcall_t __initcall_##fn __attribute_used__ \
    __attribute__((__section__(".initcall" level ".init"))) = fn

start_kernel  -->rest_init() -->kernel_init()  --> do_basic_setup()  -->do_initcalls()----》遍歷.initcall" level ".init,執行.initcall" level ".init對應的fn,最終pci_driver_init被執行

2、執行註冊

pci匯流排的ops結構體:

struct bus_type pci_bus_type = {
    .name        = "pci",
    .match        = pci_bus_match,
    .hotplug    = pci_hotplug,
    .suspend    = pci_device_suspend,
    .resume        = pci_device_resume,
    .dev_attrs    = pci_dev_attrs,
};

註冊pci驅動
int bus_register(struct bus_type * bus)
{
    int retval;

    retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);       //設定pci_bus_type->subsys.kset.kobj->k_name為pci

    subsys_set_kset(bus, bus_subsys);           //pci_bus_type->subsys.kset.kobj.kset = &bus_subsys.kset (bus_subsys由buses_init調subsystem_register進行初始化)
    retval = subsystem_register(&bus->subsys);       //初始化X.kobj.entry、X.list連結串列頭部、將X.kobj->entry新增到X.kobj->kset->list,建立sys/bus目錄下pci目錄(X為pci_bus_type->subsys.kset)

    kobject_set_name(&bus->devices.kobj, "devices");   
    bus->devices.subsys = &bus->subsys;
    retval = kset_register(&bus->devices);    //初始化X.kobj.entry、X.list連結串列頭部,X->kobj.parent為pci_bus_type->subsys.kset.kobj,建立sys/bus/pci目錄下devices目錄(X為pci_bus_type->devices)

    kobject_set_name(&bus->drivers.kobj, "drivers");
    bus->drivers.subsys = &bus->subsys;
    bus->drivers.ktype = &ktype_driver;
    retval = kset_register(&bus->drivers);    //初始化X.kobj.entry、X.list連結串列頭部,X->kobj.parent為pci_bus_type->subsys.kset.kobj,建立sys/bus/pci目錄下drivers目錄(X為pci_bus_type->drivers)
      .......

二、註冊pci裝置驅動

int pci_register_driver(struct pci_driver *drv)
{
    int error;

    /* initialize common driver fields */
    drv->driver.name = drv->name;
    drv->driver.bus = &pci_bus_type;
    drv->driver.probe = pci_device_probe;
    drv->driver.remove = pci_device_remove;
    drv->driver.owner = drv->owner;
    drv->driver.kobj.ktype = &pci_driver_kobj_type;
    pci_init_dynids(&drv->dynids);

    /* register with core */
    error = driver_register(&drv->driver);
}

int driver_register(struct device_driver * drv)
{
    INIT_LIST_HEAD(&drv->devices);     //初始化pci裝置驅動的devices連結串列
    init_MUTEX_LOCKED(&drv->unload_sem);
    return bus_add_driver(drv);
}

int bus_add_driver(struct device_driver * drv)
{
    struct bus_type * bus = get_bus(drv->bus);
    int error = 0;

    if (bus) {
        pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
        error = kobject_set_name(&drv->kobj, "%s", drv->name);   //設定drv->driver.kobj.name為pci裝置驅動名字
        drv->kobj.kset = &bus->drivers;          //drv->kobj.kset為pci_bus_type->drivers
       error = kobject_register(&drv->kobj));      //初始化drv->kobj->entry連結串列、drv->kobj.parent為pci_bus_type->drivers->list,將drv->kobj->entry新增到pci_bus_type->drivers->list,以sys/bus/pci/drivers為目錄建立pci裝置驅動名的目錄

        down_write(&bus->subsys.rwsem);
        driver_attach(drv);               //1、遍歷pci_bus_type->devices->list上的device調driver_probe_device,該函式調drv->driver.bus.match = &pci_bus_type.match =pci_bus_match將device的pci id與driver註冊的pci id進行匹配, 若匹配成功,調driver的probe函式

                                                      2、調device_bind_driver:dev->driver_list新增到dev->driver->devices,將sys/bus/pci/drivers/驅動名/pci_id與sys/bus/pci/devices/pci_id建立軟連結

                                                       注:subsys_initcall(pcibios_init)註冊pci初始化回撥,subsys_initcall也是__define_initcall的巨集定義,在系統初始化時回撥被呼叫,??該回撥執行pci_scan_bus進行pci裝置的bar空間讀取並新增裝置到pci_bus_type->devices->list??
        up_write(&bus->subsys.rwsem);
        module_add_driver(drv->owner, drv);      //建立driver與module的軟連結

        driver_add_attrs(bus, drv);                 //根據pci_dev_attrs建立軟連結
}

相關文章