dxd - dynax driver framework 3.0.2
cross platform open source driver development framework
Loading...
Searching...
No Matches
PCI devices

dxd::pci::device is the OS half of a PCI device, one per platform under one name and one interface - kernel/driverkit/dxd_pci_device.h, kernel/wdm/dxd_pci_device.h, KMDF's dxd::kmdf::pci::device in kernel/wdm/kmdf/dxd_kmdf_pci_device.h -, which a product's link composes as its super_device_t (template<typename super_device_t= dxd::pci::device> class device: public super_device_t). There is no platform-free class: what is common is the interface; the two Windows halves share kernel/wdm/dxd_pci_platform.h.

  • Memory: read32(bar, offset)/write32(bar, offset, value) reach a BAR by its index in the configuration space - DriverKit through the nub's memory index, Windows through the BAR's mapping, the start's raw resource matched to the BAR's bus address (pci::bars). Bus mastering and memory space are enabled at the launch. A BAR not reached reads all ones and takes no write, so conclude() takes any launch.
  • Removal: a register of a device gone from the bus reads all ones, removed(value); the link decides what a register reading all ones means where a queue answers it empty too.
  • Interrupts: irq(vector, timestamp) claims an interrupt and quiets its source, isr(vector) serves it - DriverKit runs both on the device's serial queue, Windows irq() at the interrupt's level and isr() in the vector's DPC. MSI where the platform grants it (Windows: the inf's MSISupported), the legacy line as vector 0 otherwise. irq_enable(bool) enables or disables the sources - WDM connects and disconnects them, KMDF's framework connects them in D0 and the device's own switch lets irq() claim -; the launch leaves them off, a sleep turns them off and its wake back to where they were. KMDF's interrupt objects are the framework device object's, made once: a rebalance's successor finds them bound to the new resources.
  • What every platform keeps: irq_enable(), scatter_gather::initialize() and free() run at passive level - from launch(), conclude(), sleep(), wake() or a client's call; isr() may run beside the next irq(), so a link serializes the two through its device's own interrupt mask.
  • DMA: a buffer<scope, limit> is whole pages below 1<< limit on every platform, none of them shared with another allocation and none of their runs contiguous by need. scatter_gather<limit> hands such a buffer's device addresses as runs (segment[idx], segments) from initialize(device, buffer) to free(), which device and driver both read and write for the buffer's lifetime - DriverKit an IODMACommand per instance (32 runs at most, the IOMMU maps a buffer as one), IOKit through the nub's mapper, Windows a common buffer of the buffer's pages (CreateCommonBufferFromMdl) on an adapter of the limit's width per instance: one run where DMA remapping maps them, a run per physically contiguous range otherwise. The generic inf opts every device into DMA remapping.
  • Teardown: conclude() disables the interrupts, flushes what is in flight (the queue drained, the DPCs flushed), Windows unmaps the BARs, before anything of the device goes; a product concludes its own part first, a failed launch included (dxd::device). A surprise removal (WDM's unplugged()) disconnects the interrupts at once, the BARs read all ones until then.
  • Windows resources: a memory requirement of length 0 the bus states is dropped ahead of the start; a device's BARs stand from its start to its conclude() - a rebalance retires it and its successor maps the new ones (plain WDM, KMDF).