#pragma once /** * The lcrash system bus is a root device which manages all other associated devices, and handles bookkeeping for other subsystems (e.g. classifying devices) * The system bus supports device names to aid debuggers, however these names are otherwise meaningless and pointers to structures should be used instead * * Example device tree: * /SYSBUS * /PCI * /PCI0000:00:00.0 * $ETHERNET * /PCI0000:00:00.1 * $FRAMEBUF * $TEXTBUF * /ACPI:0 * $BATTERY * /ACPI:1 * $SERIAL * /COM:0 * $SERIAL * /COM:1 * $SERIAL * * Device capabilities provide a way for devices to expose functionality without writing device specific code, a capability is defined by the following structure * struct SysbusDeviceCapability { * // Name of the device capability * const char* CapabilityName; * }; * * Devices types are defined by the following structure: * struct SysbusDeviceDescription { * // Name of the device type * const char* DeviceName; * * // == Instance Management == * // List of device instances * struct SysbusDevice** Instances; * * // Device initialization code, returns 0 if ok * int (*CreateDevice)(struct SysbusDevice* Device, void* Data); * * // Cleanup code for before a device is deleted, returns 0 if ok * int (*DeleteDevice)(struct SysbusDevice* Device); * * // == Capablities == * // Returns a capability specific structure if a capability is present, otherwise returns NULL * void* (*GetCapability)(struct SysbusDevice* Device, struct SysbusDeviceCapability* Capability); * }; * * Devices are stored in the following structure: * struct SysbusDevice { * // Pointer to the device type structure * const struct SysbusDeviceDescription* DeviceDescription; * * // Name of the device * const char* DeviceName; * * // Device specific data * void* DeviceData; * * // Child devices * struct SysbusDevice** Children; * }; * * Drivers can define a new device type by calling `struct SysbusDeviceDescription* SysbusCreateDeviceDescription()` which * Allocates and returns a device description structure * * Drivers must free device types with `void SysbusDeleteDeviceDescription(struct SysbusDeviceDescription* DESCRIPTION)` which * Deletes a DESCRIPTION's instances * Deallocates a device DESCRIPTION structure * * Drivers can create a new device by calling `struct SysbusDevice* SysbusCreateDevice(struct SysbusDeviceDescription* DESCRIPTION, void* DATA)` which * DEVICE = Allocate a device structure * Initializes it by calling DESCRIPTION::CreateDevice(DEVICE, DATA) * if ok then * Adds the DEVICE to the DESCRIPTION's instance list * Returns the DEVICE * otherwise returns NULL * * Drivers must free devices with `void SysbusDeleteDevice(struct SysbusDevice* DEVICE)` which * Uninitializes the DEVICE by calling DEVICE::DeviceDescription::DeleteDevice(DEVICE) * Removes the DEVICE from the DEVICE::DeviceDescription's instance list * Deallocates the DEVICE */ #include /** * Structure that describes a specific device capablility */ struct SysbusDeviceCapability { // Name of the device capability const char* CapabilityName; }; /** * Structure that describes a device and allows them to hook the sysbus subsystem */ struct SysbusDeviceDescription { /// Device name, this is only used for debugging const c8* DeviceName; /// List of device instances /// Do not hold pointers to this list /// Managed by the sysbus subsystem. DRIVERS, DO NOT MODIFY THIS LIST. struct SysbusDevice** Instances; /// Number of instances /// Managed by the sysbus subsystem. DO NOT MODIFY THIS. u32 InstanceCount; /// Instance array length /// Managed by the sysbus subsysyem. DO NOT MODIFY THIS. /// \internal u32 InstanceSlots; /// Called by the sysbus subsystem when a device is created, use this to initialize a device /// \returns 0 on success s32 (*CreateDevice)(struct SysbusDevice*, void*); /// Called by the sysbus subsystem when a device is deleted, use this to deinitialize a device /// \returns 0 on success s32 (*DeleteDevice)(struct SysbusDevice* Device); /// Returns a capability specific structure if a capability is present, otherwise returns NULL void* (*GetCapability)(struct SysbusDevice* Device, struct SysbusDeviceCapability* Capability); }; /** * Structure that describes an instace of a specific device */ struct SysbusDevice { /// Pointer to the device type structure const struct SysbusDeviceDescription* DeviceDescription; /// Name of the device const c8* DeviceName; /// Device specific data void* DeviceData; /// Parent device /// Managed by the sysbus subsystem. DO NOT MODIFY THIS. struct SysbusDevice* Parent; /// Child devices /// Managed by the sysbus subsystem. DRIVERS, DO NOT MODIFY THIS LIST /// Do not hold pointers to this list, it may be moved or resized as needed struct SysbusDevice** Children; /// Number of children /// Managed by the sysbus subsystem. DO NOT MODIFY THIS. u32 ChildCount; /// Child array length /// Managed by the sysbus subsysyem. DO NOT MODIFY THIS. /// \internal u32 ChildSlots; }; /// Initialize the sysbus subsystem void SysbusInitialize(); /** * Create and return a sysbus device description */ struct SysbusDeviceDescription* SysbusCreateDeviceDescription(); /** * Delete a sysbus device description */ void SysbusDeleteDeviceDescription(struct SysbusDeviceDescription* Description); /** * Create a new device */ struct SysbusDevice* SysbusCreateDevice( struct SysbusDeviceDescription* Description, struct SysbusDevice* Parent, void* Data ); /** * Delete a device */ void SysbusDeleteDevice(struct SysbusDevice* Device);