device-manager: data-driven driver matching via /etc/devices.csv
Replace the three hardcoded switch tables (pciDriverForIdentity, hidDriverFor, usbDriverForIdentity) with an authoritative, human-readable device registry the manager reads at boot. Matching is most-specific-wins across base/subclass/prog_if/vendor/device/subsystem/hid, so a precise vendor:device rule and a generic class rule coexist; an unmatched device is logged, never guessed. This resolves docs' "matching stays code until the third bus". - ABI: child_added and DeviceDescriptor gain vendor/device/subsystem; child_added gains a bus discriminator (BusKind) so PCI and USB class triples match against the right namespace. - pci-bus reads vendor/device (config 0x00) and subsystem (0x2C, type-0) and reports them. - library/device/registry: freestanding CSV parser + matchDriver() with specificity scoring; 5 unit tests wired into `zig build test`. - etc/devices.csv bundled into the initrd; the kernel serves /etc directly, so the manager reads it before any filesystem service is up (fat starts later). - virtio-gpu: drop the now-redundant post-spawn 1AF4:1050 re-confirm, since the registry binds this driver by exact identity. - Remove the orphaned system/drivers/display driver (unreferenced by build or registry). - docs: new devices-csv.md; device-manager.md "matching stays code" resolved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KJqSiLLchDUUCoXn5jsiwd
This commit is contained in:
@@ -153,6 +153,12 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
|
||||
var descriptor = std.mem.zeroes(device.DeviceDescriptor);
|
||||
descriptor.class = @intFromEnum(device.DeviceClass.pci_device);
|
||||
descriptor.pci_class = class_triple;
|
||||
// Vendor/device from the first config dword (0x00): low half vendor, high half
|
||||
// device. These carry to the manager's /etc/devices.csv matcher so a function
|
||||
// can bind on its exact 1AF4:1050 identity, not just its class triple.
|
||||
const vendor_device = configRead(bus, dev, function, 0x00);
|
||||
descriptor.vendor = @truncate(vendor_device);
|
||||
descriptor.device = @truncate(vendor_device >> 16);
|
||||
descriptor.resources[0] = .{
|
||||
.kind = @intFromEnum(device.ResourceKind.memory),
|
||||
.start = ecam_physical + (((bus - start_bus) << 20) | (dev << 15) | (function << 12)),
|
||||
@@ -164,6 +170,11 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
|
||||
// write all-ones, read the writable mask back, restore. Header type 0 only.
|
||||
const header_type = (configRead(bus, dev, function, 0x0C) >> 16) & 0x7F;
|
||||
if (header_type == 0) {
|
||||
// Subsystem id lives at 0x2C only on type-0 (device) headers, not on
|
||||
// bridges: dword low half is subsystem-vendor, high half subsystem-device.
|
||||
// Repack vendor-first so it reads like the CSV's `ssvid:ssid`.
|
||||
const subsystem_dword = configRead(bus, dev, function, 0x2C);
|
||||
descriptor.subsystem = (@as(u32, @truncate(subsystem_dword)) << 16) | @as(u32, @truncate(subsystem_dword >> 16));
|
||||
const command = configRead16(bus, dev, function, 0x04);
|
||||
configWrite16(bus, dev, function, 0x04, command & ~@as(u16, 0b11));
|
||||
var i: u64 = 0;
|
||||
@@ -215,10 +226,14 @@ fn registerAndReport(bus: u64, dev: u64, function: u64, class_triple: u32) void
|
||||
return;
|
||||
};
|
||||
const report = device_manager_protocol.ChildAdded{
|
||||
.bus = @intFromEnum(device_manager_protocol.BusKind.pci),
|
||||
.parent = bridge_id,
|
||||
.bus_address = (bus << 8) | (dev << 3) | function,
|
||||
.identity = class_triple,
|
||||
.device_id = registered,
|
||||
.vendor = descriptor.vendor,
|
||||
.device = descriptor.device,
|
||||
.subsystem = descriptor.subsystem,
|
||||
};
|
||||
var reply: [device_manager_protocol.message_maximum]u8 = undefined;
|
||||
_ = ipc.call(manager_handle, std.mem.asBytes(&report), &reply) catch {
|
||||
|
||||
Reference in New Issue
Block a user