Skip to content

DeviceManager

opencode-agent[bot] edited this page May 11, 2026 · 2 revisions

DeviceManager

Central registry for devices, drivers, and their bindings.

Overview

The DeviceManager (core/src/driver/org/jnode/driver/DeviceManager.java) is the central registry of JNode's device framework. It manages the complete lifecycle of hardware devices — from discovery through registration, driver binding, and startup — while providing a query API for applications to locate and interact with devices.

The DeviceManager interface defines the contract, and AbstractDeviceManager provides the core implementation with the device map (Map<String, Device>), system bus tree, listener dispatch, and device lifecycle logic. DefaultDeviceManager extends this with plugin-based loading of DeviceFinder and DeviceToDriverMapper extensions from the org.jnode.driver.finders and org.jnode.driver.mappers extension points.

At boot, DefaultDeviceManager binds itself to the InitialNaming service registry under DeviceManager.NAME so that any code can look it up:

DeviceManager dm = InitialNaming.lookup(DeviceManager.NAME);
Collection<Device> allDevices = dm.getDevices();

Key Components

Class / File Role
core/src/driver/org/jnode/driver/DeviceManager.java Public interface: registration, startup, shutdown, device lookup, listener management
core/src/driver/org/jnode/driver/AbstractDeviceManager.java Core implementation: device map, bus tree, lifecycle methods, event dispatch
core/src/driver/org/jnode/driver/DefaultDeviceManager.java Plugin integration: loads finders and mappers from extension points
core/src/driver/org/jnode/driver/DeviceManagerListener.java DeviceManagerListener — Listener interface for deviceRegistered / deviceUnregister events
core/src/driver/org/jnode/driver/DeviceToDriverMapper.java Interface for matching a device to a suitable driver
core/src/driver/org/jnode/driver/DeviceFinder.java Interface for discovering devices on a bus

How It Works

Device Registration and Driver Binding

DeviceManager.register(Device) performs three steps atomically (within doRegister()):

  1. Check uniqueness — throws DeviceAlreadyRegisteredException if the device ID is already in the map.
  2. Find a driver — calls findDriver(device) which iterates registered DeviceToDriverMappers (sorted by match level) until one returns a non-null Driver. If a driver is found, device.setDriver(driver) is called.
  3. Add to the mapdevices.put(device.getId(), device).

After registration, start(device) is called unless the command line contains no<deviceId>:

// AbstractDeviceManager.register()
shouldStart = doRegister(device);
if (cmdLine.indexOf("no" + device.getId()) >= 0) {
    shouldStart = false;
}
fireRegisteredEvent(device);
if (shouldStart) {
    start(device);
}

findDriver iterates mappers in priority order:

// AbstractDeviceManager.findDriver()
protected final Driver findDriver(Device device) {
    synchronized (mappers) {
        for (DeviceToDriverMapper mapper : mappers) {
            final Driver drv = mapper.findDriver(device);
            if (drv != null) {
                return drv;
            }
        }
    }
    return null;
}

The MapperComparator sorts mappers ascending by getMatchLevel():

  • MATCH_DEVICE_PREDEFINED = -1 — custom/predefined mapping logic
  • MATCH_DEVICE_REVISION = 0 — exact device + revision (best match)
  • MATCH_DEVICE = 1 — exact device ID
  • MATCH_DEVCLASS = 2 — device class only

findDeviceDrivers() is called whenever a new mapper extension is added, re-evaluating all devices that currently have no driver.

Plugin Extension Loading

DefaultDeviceManager implements ExtensionPointListener and listens to two extension points. When an extension is added, it reloads all extensions and re-runs device driver discovery:

// DefaultDeviceManager.extensionAdded()
public final void extensionAdded(ExtensionPoint point, Extension extension) {
    loadExtensions();   // refreshFinders() + refreshMappers()
    findDeviceDrivers();
}

Finders and mappers are configured via XML in plugin descriptors:

<extension point="org.jnode.driver.finders">
  <finder class="org.jnode.driver.bus.pci.PCIFinder"/>
</extension>
<extension point="org.jnode.driver.mappers">
  <mapper class="org.jnode.driver.bus.pci.PCIDriverMapper"/>
</extension>

Event System

Two listener interfaces:

  • DeviceManagerListenerDeviceManagerListenerdeviceRegistered(Device) and deviceUnregister(Device) for all manager events
  • DeviceListenerDeviceListenerdeviceStarted(Device) and deviceStop(Device) for device lifecycle events

Listeners that take longer than 100ms to respond trigger an error log:

// AbstractDeviceManager.fireRegisteredEvent()
StopWatch sw = new StopWatch();
for (DeviceManagerListener l : list) {
    sw.start();
    l.deviceRegistered(device);
    if (sw.isElapsedLongerThen(100)) {
        BootLogInstance.get().error("DeviceManagerListener took " + sw + " in deviceRegistered");
    }
}

Device API Pattern

The DeviceManager.getDevicesByAPI(Class<? extends DeviceAPI>) method enables service discovery by API type:

public final Collection<Device> getDevicesByAPI(Class<? extends DeviceAPI> apiClass) {
    final ArrayList<Device> result = new ArrayList<Device>();
    for (Device dev : devices.values()) {
        if (dev.implementsAPI(apiClass)) {
            result.add(dev);
        }
    }
    return result;
}

Devices register their APIs via device.registerAPI(DeviceAPI.class, implementation). Common hierarchies: BlockDeviceAPIFSBlockDeviceAPI, CharacterDeviceAPISerialPortAPI, NetDeviceAPI, FrameBufferAPI.

System Bus

The system bus (AbstractDeviceManager.getSystemBus()) is the root of the hardware topology. Created as a package-private SystemBus inner class:

this.systemBus = new SystemBus();

Bus drivers attach child buses (PCI, USB, ISA) to it, and DeviceFinder implementations probe these buses for hardware.

Gotchas

  • doRegister is synchronized but start is not — registration is atomic but device startup happens outside the synchronized block, meaning a device can be in the map but not yet started if another thread races.
  • Mapper ordering is by match level, not specificity — a MATCH_DEVCLASS mapper with level 2 runs after a MATCH_DEVICE_REVISION mapper with level 0. Broad-match mappers must have higher level values.
  • Delayed driver binding — if no mapper finds a driver, the device stays registered but unstarted. findDeviceDrivers() is called whenever a new mapper extension is added, allowing late-binding to reconnect these devices.
  • 100ms listener warning threshold — both DeviceManagerListener and DeviceListener callbacks are checked for timing. Slow listeners can affect the timing of other device registrations.
  • Command-line device blockingno<deviceId> in jnode.cmdline only blocks startup, not registration. The device still appears in getDevices().
  • Immutable lookup collectiongetDevices() and getDevicesByAPI() return Collections.unmodifiableCollection. Iteration over the live map is safe against concurrent modification but the map values themselves can change.

Related Pages

  • Driver-Framework — Broader driver subsystem: bus drivers, resource management, API hierarchies.
  • Plugin-System — How DeviceFinder and DeviceToDriverMapper are registered via extension points.
  • Resource-Management — Hardware resource allocation (IRQ, I/O ports, DMA, memory) used by device drivers.
  • Interrupt-Handling — How hardware IRQs are routed to device driver handlers.
  • Device-Manager — Alias for the same page (existing hyphenated name).

Clone this wiki locally