Skip to content

DeviceToDriverMapper

opencode-agent[bot] edited this page May 10, 2026 · 1 revision

DeviceToDriverMapper

Strategy pattern for mapping devices to appropriate drivers during discovery.

Overview

DeviceToDriverMapper is the core interface of JNode's driver discovery strategy pattern. When a device is discovered by a bus driver (PCI, USB, IDE, etc.), the DeviceManager iterates through all registered mappers in priority order and calls findDriver(device). The first mapper that returns a non-null Driver wins. This design enables JNode to support arbitrary device types and matching strategies without modifying the core device management logic — new hardware support is added simply by implementing a new mapper and registering it via the plugin extension point.

The mapper system is tightly integrated with the plugin system. Mappers are declared as extensions to the org.jnode.driver.mappers extension point in plugin descriptors. When a plugin is activated, its mappers are instantiated and sorted by match level. This means specific hardware matches (e.g., exact vendor/device ID) are always evaluated before generic class matches (e.g., "any PCI mass storage device").

Key Components

Class / File Role
core/src/driver/org/jnode/driver/DeviceToDriverMapper.java Core strategy interface: findDriver(Device), getMatchLevel()
core/src/driver/org/jnode/driver/AbstractDeviceManager.java Iterates mappers in priority order, first-match-wins
core/src/driver/org/jnode/driver/DefaultDeviceManager.java Loads mappers from plugin extensions, configureMapper() instantiation
core/src/driver/org/jnode/driver/bus/pci/PCIDeviceToDriverMapper.java PCI vendor/device ID matching
core/src/driver/org/jnode/driver/bus/pci/AbstractPCIDeviceToDriverMapper.java PCI ID parsing, driver instantiation, ID comparison with masks
core/src/driver/org/jnode/driver/bus/pci/PCIClassToDriverMapper.java PCI class (baseclass/subclass) matching
core/src/driver/org/jnode/driver/bus/usb/USBHubDeviceToDriverMapper.java USB hub matching
core/src/driver/org/jnode/driver/bus/isa/FloppyDeviceToDriverMapper.java Floppy device matching
fs/src/driver/org/jnode/driver/block/ide/IDEDiskDeviceToDriverMapper.java IDE disk matching
core/src/driver/org/jnode/driver/video/VESADeviceToDriverMapper.java VESA video predefined matching

How It Works

Interface Definition

The DeviceToDriverMapper interface is minimal by design:

public interface DeviceToDriverMapper {
    // Match levels — lower values are checked first
    public static final int MATCH_DEVICE_PREDEFINED = -1;  // Custom logic, highest priority
    public static final int MATCH_DEVICE_REVISION   =  0;  // Exact device + revision
    public static final int MATCH_DEVICE            =  1;  // Exact device ID match
    public static final int MATCH_DEVCLASS          =  2;  // Device class (generic), lowest priority

    Driver findDriver(Device device);
    int getMatchLevel();
}

Plugin Registration

Drivers declare mappers in plugin XML using the org.jnode.driver.mappers extension point:

<extension point="org.jnode.driver.mappers">
  <mapper id="10ec:8139"
          name="Realtek 8139"
          driver-class="org.jnode.driver.net.rtl8139.RTL8139Driver"
          class="org.jnode.driver.bus.pci.PCIDeviceToDriverMapper"
          vendor="0x10ec"
          device="0x8139"/>
</extension>

Mapper Loading

DefaultDeviceManager.configureMapper() instantiates mappers via reflection. Two constructor patterns are supported:

  1. Constructor with ConfigurationElement (preferred) — gives access to all plugin XML attributes:

    public PCIDeviceToDriverMapper(ConfigurationElement config) { ... }
  2. Default constructor (fallback) — used when no ConfigurationElement-aware constructor exists:

    public PCIDeviceToDriverMapper() { ... }

Match Level Sorting

AbstractDeviceManager sorts all loaded mappers by getMatchLevel() at startup:

Collections.sort(mappers, MapperComparator.INSTANCE);
// Lower match level = higher priority = checked first

This ensures that specific hardware matches always take precedence over generic class matches. The MapperComparator orders: MATCH_DEVICE_PREDEFINED (-1) → MATCH_DEVICE_REVISION (0) → MATCH_DEVICE (1) → MATCH_DEVCLASS (2).

Driver Binding Flow

When a device is registered with DeviceManager.register(device), AbstractDeviceManager.doRegister() calls findDriver(device) which iterates mappers:

private Driver findDriver(Device device) {
    for (DeviceToDriverMapper mapper : mappers) {
        Driver drv = mapper.findDriver(device);
        if (drv != null) {
            return drv;  // First match wins
        }
    }
    return null;
}

When a mapper matches, the driver's connect(device) method is called, binding the driver to the device. If no mapper matches, the device is registered without a driver — later plugin activations can add new mappers to find drivers via findDeviceDrivers().

PCI ID Matching

AbstractPCIDeviceToDriverMapper parses PCI IDs from plugin configuration (format: vendor:device[:revision]) with optional masks:

// Supports masks like 0xFFFF for wildcard matching
matches(vendorID, deviceID, revision)

PCIDeviceToDriverMapper.getMatchLevel() returns MATCH_DEVICE_REVISION if a revision is specified, otherwise MATCH_DEVICE, enabling fine-grained priority control for revision-specific drivers.

Gotchas & Non-Obvious Behavior

  • Counterintuitive match level ordering: Lower values = higher priority. MATCH_DEVICE_PREDEFINED (-1) is checked first; MATCH_DEVCLASS (2) is last. This ensures specific matches override generic ones, but the negative value for predefined is easy to misread.

  • First match wins — no best-match selection: The loop returns immediately on the first non-null result. A mapper that matches broadly before a more specific mapper will claim the device, even if a better match exists later. This is why getMatchLevel() sorting is critical.

  • Mapper must return null for non-applicable devices: Each mapper implementation must check device type (instanceof) and return null if it cannot handle the device. Returning null is the signal to "skip this mapper, try the next one."

  • Two constructor patterns: If a mapper has both a ConfigurationElement constructor and a default constructor, the ConfigurationElement version is used. If only a default constructor exists, it is called without configuration. Mixing approaches within a mapper hierarchy requires careful coordination (see AbstractPCIDeviceToDriverMapper).

  • Hot-plug device support: extensionAdded() in DefaultDeviceManager triggers findDeviceDrivers() for already-registered devices without drivers. This allows runtime driver discovery when new plugins are loaded, but requires that mappers be re-sorted if new extensions arrive after initial startup.

  • Mapper instances are reused: The same mapper instance is used for all matching operations. Mappers must be stateless with respect to findDriver() calls, or synchronize internal state if state is needed.

  • PCI ID masks: The PCI ID format supports bitmask wildcards (e.g., 0xFFFF means match any). The default mask is 0xFFFFFFFF for exact matching. Misconfigured masks can cause mappers to match devices they shouldn't, or fail to match devices they should.

Related Pages

  • DeviceManager — Central registry that iterates mappers and binds drivers to devices
  • Driver-Framework — Overview of the driver subsystem, including DeviceFinder and DeviceAPI
  • Bus-Drivers — Bus drivers (PCI, USB, etc.) that discover devices for mapper matching
  • Plugin-System — Extension point mechanism used to register mappers dynamically
  • Device-Discovery — How devices are found by DeviceFinder implementations before mappers run

Clone this wiki locally