//! The device-manager protocol (docs/device-manager.md): what drivers and //! applications say to the device manager over its well-known endpoint. The //! vfs-protocol pattern — extern-struct messages, a version in the handshake, //! reserved fields — so both sides depend on the contract by name. Deliberately //! contains nothing lifecycle-shaped: stopping, liveness (the zero-length ping), //! and exit reasons are the universal vocabulary of //! docs/process-lifecycle.md, not this protocol. /// The protocol version a driver states in its hello. A manager that cannot /// serve a driver's version refuses the hello, and the mismatch is loud at /// startup instead of quiet corruption later. pub const version: u16 = 1; /// Which bus a `child_added` came from — stated by the reporting bus driver so /// the manager's /system/configuration/devices.csv matcher knows how to read the report's identity /// (a PCI class triple vs a USB class triple are the same 24 bits but different /// namespaces) and which `bus` column a rule must name to bind it. `unknown` is /// the zero default, so an un-upgraded reporter fails to match rather than /// binding to the wrong bus's rule. pub const BusKind = enum(u8) { unknown = 0, pci = 1, usb = 2, acpi = 3, }; /// What kind of driver is talking (docs/driver-model.md's shapes). pub const Role = enum(u8) { /// Owns a controller and reports the devices behind it (`child_added`). bus = 1, /// Serves one device, reached through a bus's transfer protocol. device = 2, }; /// The message kinds. pub const Operation = enum(u8) { hello = 1, child_added = 2, child_removed = 3, enumerate = 4, subscribe = 5, }; /// `Hello.device_id` for a driver that serves no enumerated device (a test /// fixture, a synthetic source). pub const no_device: u64 = ~@as(u64, 0); /// The handshake, sent once by every driver the manager spawns — the manager's /// one self-enforced deadline: spawned and silent past it means wrong binary, /// wrong version, or wedged before main, and the stop sequence follows. pub const Hello = extern struct { operation: u8 = @intFromEnum(Operation.hello), /// A Role value. role: u8, /// The protocol version this driver was built against (`version`). version: u16 = version, reserved: u32 = 0, /// The device this driver was assigned (its argv[1]), or `no_device`. device_id: u64, }; pub const hello_size = @sizeOf(Hello); /// The manager's answer to a hello. Nonzero status = refused (version mismatch, /// unknown sender); a refused driver should exit cleanly. pub const HelloReply = extern struct { status: i32, reserved: u32 = 0, }; pub const reply_size = @sizeOf(HelloReply); /// A bus driver reporting one device it discovered behind its controller /// (docs/device-manager.md "the tree"). Identity is the bus's native language — /// for USB a port-speed class; the (class, subclass, protocol) triple joins it /// once control transfers exist (the USB track). The manager mirrors the child /// into its tree; when the reporting driver dies, the manager prunes everything /// it reported (the children describe protocol state that died with it) and the /// restarted instance rediscovers and re-reports. pub const ChildAdded = extern struct { operation: u8 = @intFromEnum(Operation.child_added), /// A `BusKind` value: which bus reported this child, so the manager reads the /// identity in the right namespace and matches against the right `bus` column. bus: u8 = @intFromEnum(BusKind.unknown), reserved1: u16 = 0, reserved2: u32 = 0, /// The reporting driver's own device (the controller) — the child's parent. parent: u64, /// Where on the bus (for USB: the root port number, 1-based). bus_address: u64, /// Bus-specific identity (for USB: the PORTSC port-speed class; for PCI: /// the class triple; for ACPI devices, 0 — identity is the hid below). identity: u64, /// The kernel device id this child was `device_register`ed as — what the /// manager hands a matched driver as its argv assignment — or `no_device` /// for an unregistered leaf (a USB port before the descriptor track). device_id: u64 = no_device, /// The vendor id (PCI vendor / USB idVendor), or 0 when the bus has no such /// concept (ACPI). Carried so the manager's /system/configuration/devices.csv matcher can bind /// on vendor — a level the bus-native `identity` (a class triple) cannot express. vendor: u16 = 0, /// The device id (PCI device / USB idProduct), or 0. The most specific numeric /// level: this is what lets one virtio-gpu (1AF4:1050) be told from any other /// virtio display function without the driver re-confirming after it is spawned. device: u16 = 0, /// The PCI subsystem id, packed `(subsystem_vendor << 16) | subsystem_device` /// (so it reads vendor-first, matching the CSV's `ssvid:ssid`), or 0 when the /// device has no subsystem id (a bridge, or a non-PCI bus). subsystem: u32 = 0, /// The ACPI hardware id (`_HID`), EISA-decoded (e.g. "PNP0303"), for devices /// discovered by firmware string rather than a numeric bus identity. Empty /// (all zero) otherwise. Widens for FDT `compatible` strings later. hid: [8]u8 = .{0} ** 8, }; pub const child_added_size = @sizeOf(ChildAdded); /// A bus driver reporting a device gone (hot-unplug). Not yet sent by any /// driver — the port scan has no unplug interrupt — but the manager handles it; /// death-pruning covers removal until hotplug lands. pub const ChildRemoved = extern struct { operation: u8 = @intFromEnum(Operation.child_removed), reserved0: u8 = 0, reserved1: u16 = 0, reserved2: u32 = 0, parent: u64, bus_address: u64, }; pub const child_removed_size = @sizeOf(ChildRemoved); /// The manager's answer to a tree report. pub const ReportReply = extern struct { status: i32, reserved: u32 = 0, }; /// An application asking for the tree (M18.3): the reply is an EnumerateReply /// header followed by `count` ChildEntry records. pub const Enumerate = extern struct { operation: u8 = @intFromEnum(Operation.enumerate), reserved0: u8 = 0, reserved1: u16 = 0, reserved2: u32 = 0, }; pub const EnumerateReply = extern struct { status: i32, /// ChildEntry records following this header. count: u32, }; pub const ChildEntry = extern struct { parent: u64, bus_address: u64, identity: u64, }; /// An application subscribing to published add/remove events (the input-service /// pattern): the subscriber's endpoint rides as the call's **capability**, and /// events arrive on it as buffered messages whose payload is the same /// ChildAdded / ChildRemoved struct the bus drivers send — one encoding, both /// directions. pub const Subscribe = extern struct { operation: u8 = @intFromEnum(Operation.subscribe), reserved0: u8 = 0, reserved1: u16 = 0, reserved2: u32 = 0, }; /// Upper bound on any message in this protocol — sizes the endpoint buffers. /// Capped by the kernel's IPC MESSAGE_MAXIMUM (256): an EnumerateReply carries /// up to ten ChildEntry records per call, plenty for the mirror's current /// bounds; paging joins the protocol if a tree ever outgrows one message. pub const message_maximum = 256;