At initialization, the fi bus driver's drv_init() method is called for each device node tested. The fi bus driver will then get the opportunity to:
Launch an instance of itself, on that node.
Launch an instance of the tested device driver referenced in the PROP_FI_DRIVER property, giving its own bus operations instead of the original bus driver operations.
Optionally register itself in the device registry, to export a bus FI DDI, if it is intended to have a client.
Code Example 14-2 illustrates the initialization of a generic PCI Fault Injection bus driver (pciFi(9DRV)). In this example, the PciFiDev structure contains the fault injection driver instance specific data. This data is allocated and initialized in drv_init(). Fields of interest for the examples are:
node, which contains the bus FI driver's device node.
dev.node, which contains the tested child driver's device node.
entry, which contains data to be registered in the device registry.
devRegId, which contains the identifier of allocated device registry entry.
/* * Try to start (initialize) tested child driver */ static KnError childInit(PciFiDev* pciFi) { char* drv_name; DrvRegId drv_curr; DrvRegId drv_prev; DrvRegEntry* entry; DevProperty prop; DevNode node; /* * Check if not already started */ if (pciFi->dev.node) { return K_EBUSY; } node = pciFi->node; /* * Check for PROP_FI_DRIVER property */ prop = dtreePropFind(node, PROP_FI_DRIVER); if (prop == NULL) { DKI_ERR(("%s: error -- %s required property not found\n", pciFi->path, PROP_FI_DRIVER)); return K_EFAIL; } /* * Try to start PROP_FI_DRIVER driver */ drv_name = (char*)dtreePropValue(prop); drv_curr = svDriverLookupFirst(); while (drv_curr) { entry = svDriverEntry(drv_curr); if (entry->drv_init && !strcmp(pciFiDrv.bus_class, entry->bus_class) && (pciFiDrv.bus_version >= entry->bus_version) && !strcmp(drv_name, entry->drv_name)) { entry->drv_init(node, &pciFiPciBusOps, pciFi); if (pciFi->dev.node) { svDriverRelease(drv_curr); break; } } drv_prev = drv_curr; drv_curr = svDriverLookupNext(drv_curr); svDriverRelease(drv_prev); } return (pciFi->dev.node ? K_OK : K_EFAIL); } /* * Driver initialization method */ static void drv_init (DevNode node, void* busOps, void* busId) { PciFiDev* pciFi; int pathSz; char* path; KnError res; DevProperty prop; PciPropBusNum bus; PciPropDevNum dev; PciPropFuncNum func; /* * Get my path name in the device tree (for errors) */ pathSz = dtreePathLeng(node); path = (char*)svMemAlloc(pathSz); if (!path) { DKI_ERR(("%s: error -- not enough memory\n", pciFiDrv.drv_name)); return; } dtreePathGet(node, path); /* * Get mandatory properties */ [...] /* * Allocate driver instance data */ pciFi = (PciFiDev*)svMemAlloc(sizeof(PciFiDev)); if (! pciFi) { DKI_ERR(("%s: error -- not enough memory\n", path)); svMemFree(path, pathSz); return; } /* * Initialize driver instance data */ [...] /* * Allocate objects associated to allocated resources */ [...] /* * Open parent PCI bus connection */ res = pciFi->pciOps->open(busId, node, eventHandler, /* my event handler */ loadHandler, /* my load handler */ pciFi, /* my handlers cookie */ &pciFi->pciDevId); if (res != K_OK) { DKI_ERR(("%s: error -- open() failed (%d)\n", path, res)); svMemFree(path, pathSz); svMemFree(pciFi, sizeof(PciFiDev)); return; } /* * Allocate PCI_FI instance driver descriptor in the device registry */ pciFi->entry.dev_class = PCIFI_CLASS; pciFi->entry.dev_id = pciFi; pciFi->entry.dev_node = node; pciFi->entry.dev_ops = &pciFiOps; pciFi->devRegId = svDeviceAlloc(&pciFi->entry, PCIFI_VERSION_INITIAL, FALSE, /* pciFi cannot be * shared */ relHandler); if (! pciFi->devRegId) { DKI_ERR(("%s: error -- not enough memory\n", path)); pciFi->pciOps->close(pciFi->pciDevId); svMemFree(pciFi, sizeof(PciFiDev)); svMemFree(path, pathSz); return; } /* * Chain driver instance in list */ pciFi->next = pciFiDevs; pciFiDevs = pciFi; /* * Finally, register the new device driver instance * in the device registry. In case a shut down event * has been signaled during the initialization, the device entry * remains invalid and the relHandler() handler is invoked * to shut down the device driver instance. Otherwise, the device * entry becames valid and therefore visible for driver clients. */ svDeviceRegister(pciFi->devRegId); DKI_MSG(("%s: %s driver started\n", path, pciFiDrv.drv_name)); /* * Try to start a tested driver. If this fails, a tested driver * may be started later by the loadHandler() handler. */ (void)childInit(pciFi); }