-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
merge(kernel: devices): add a device/driver API
We can now declare generic drivers! This API is heavily inspired by that of Linux, as it is the only one I know and am familiar with. Plus I like it :) Drivers are automatically loaded suring startup, and any detected device that matches a driver is automatically represented as a device, which will then be used to interact with the hardware. The actual implementation of how to interact with the hardware is not the responsibility of the driver, and depends on the type of device. This should generally be represented as a VTable inside a struct that contains a basic device struct. Signed-off-by: Léo DUBOIN <[email protected]>
- Loading branch information
Showing
16 changed files
with
404 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,81 @@ | ||
#pragma once | ||
|
||
/** | ||
* | ||
* @brief Kernel Device/Driver API | ||
* | ||
* @defgroup kernel_device Devices | ||
* @ingroup kernel | ||
* | ||
* # Devices | ||
* | ||
* ## Philsophy | ||
* | ||
* This device driver API is heavily inspired by Linux's one, as it is the only | ||
* one I'm familiar with currently, and I like it. | ||
* | ||
* Hardware interactions are split into two 3 parts: | ||
* * The physical hardware (not our responsibility) | ||
* * The driver | ||
* * The device | ||
* | ||
* **Every interaction with a hardware component is done by interacting with its | ||
* corresponding device.** | ||
* | ||
* | ||
* ## Design | ||
* | ||
* Devices come in many shapes (timers, buses, etc ...), and as such, the sets | ||
* of functions used to communicate with a given hardware varies a lot. | ||
* The different function groups (vtables) should be located inside the | ||
* \c device struct (whichever one, depending on the type of hardware), | ||
* and should stay hidden the driver. | ||
* | ||
* The driver's only responsibility is to create, initialize and register the | ||
* appropriate device \ref device for its hardware. Once the device has been | ||
* registered, it can be used to communicate with the underlying hardware. | ||
* | ||
* | ||
* ## Usage | ||
* | ||
* The kernel automatically detects and keeps track of all the connected | ||
* hardware devices. When a new device is detected, its corresponding driver is | ||
* looked for in the list of curenlty loaded drivers. If a matching one has been | ||
* found, it is requested to create the appropriate device. | ||
* | ||
* @see \ref kernel_device_driver | ||
* | ||
* @{ | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <kernel/error.h> | ||
#include <kernel/types.h> | ||
|
||
#include <libalgo/linked_list.h> | ||
|
||
#include <stddef.h> | ||
|
||
#include "kernel/error.h" | ||
typedef struct device_driver driver_t; | ||
|
||
/** @struct device | ||
* @brief Represents a device | ||
* | ||
* In the current implementation, as everything is stored in RAM, the device | ||
* struct is simply a wrapper arround what could be considered a contiguous | ||
* buffer in memory. | ||
* | ||
* In the future though, the device structure should become a common interface | ||
* between devices of different types (e.g. ram and hard disks should share this | ||
* API) | ||
* @brief Represents a device inside the kernel | ||
*/ | ||
typedef struct device { | ||
u32 start; ///< Start address of the device in memory | ||
size_t size; ///< Size of the memory area for this device | ||
|
||
/** @struct device_operations | ||
* @brief VTable of I/O operations for the device | ||
*/ | ||
struct device_operations { | ||
error_t (*read)(const struct device *, char *buffer, size_t offset, | ||
size_t size); | ||
error_t (*write)(const struct device *, size_t offset, | ||
const char *buffer, size_t size); | ||
} operations; | ||
} dev_t; | ||
|
||
/** Create a new device | ||
* | ||
* @warning This implementation only serves as a place holder for the actual | ||
* one in order to ease the migration once it is implemneted. This API | ||
* **WILL** change. | ||
* | ||
* @param start The starting address of the device's memory range | ||
* @param size The size of teh device's memory range | ||
|
||
node_t this; ///< Used to list devices, internal use only | ||
|
||
char *name; ///< The name of the device | ||
driver_t *driver; ///< The driver for this device | ||
|
||
} device_t; | ||
|
||
/** Register a new device. | ||
* | ||
* The device must have been allocated and initialized first by its | ||
* corresponding driver. | ||
*/ | ||
dev_t *device_new(u32 start, size_t size); | ||
error_t device_register(device_t *); | ||
|
||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/** | ||
* @brief Driver API | ||
* | ||
* @defgroup kernel_device_driver Drivers | ||
* @ingroup kernel_device | ||
* | ||
* # Drivers | ||
* | ||
* This file describes the **driver** part of the Device/Driver API. | ||
* | ||
* ## Creating a driver | ||
* | ||
* When creating a new driver, you MUST declare it using \ref DECLARE_DRIVER. | ||
* All drivers declared using this macro are automatically loaded when starting | ||
* up the kernel. | ||
* | ||
* The kernel automatically detects and keeps track of all the connected | ||
* hardware devices. When a new device is detected, its corresponding driver is | ||
* looked for inside this list of loaded drivers. If a match is found, the | ||
* matching driver's \c probe function is called to create the correct type of | ||
* device, and register it. | ||
* | ||
* @see kernel_device | ||
* | ||
* @{ | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <kernel/device.h> | ||
#include <kernel/error.h> | ||
|
||
#include <libalgo/linked_list.h> | ||
#include <utils/compiler.h> | ||
|
||
/** The different ways a device can be detected | ||
* @enum device_detection_method | ||
*/ | ||
typedef enum device_detection_method { | ||
DRIVER_TYPE_ACPI, ///< Devices detected through ACPI tables | ||
DRIVER_TYPE_TOTAL_COUNT, | ||
} device_detection_method; | ||
|
||
/** The basic device driver structure | ||
* @struct device_driver | ||
*/ | ||
typedef struct device_driver { | ||
|
||
node_t this; ///< Intrusive list node used to iterate through loaded drivers | ||
const char *name; ///< The name of the driver | ||
|
||
/** Information used by the driver API to match a device against a driver | ||
* @struct driver_match | ||
*/ | ||
struct driver_match { | ||
/// How matching devices are expected to be detected | ||
device_detection_method method; | ||
/// The matching data. | ||
/// This can be a name, a path or anything depending on the detection | ||
/// method. | ||
const char *const *compatible; | ||
} match; ///< Information used to match devices against this driver | ||
|
||
/** Vector table of the common operations used to control drivers | ||
* @struct driver_operations | ||
*/ | ||
struct driver_operations { | ||
/// Bind the driver to the device | ||
/// @param name The name of the matching physical device | ||
/// @param addr The physical address of the device | ||
error_t (*probe)(const char *, paddr_t addr); | ||
} operations; ///< Vector table of driver control operations | ||
|
||
} driver_t; | ||
|
||
/** Register a new driver | ||
* | ||
* After a driver has been registerd, any newly detected device that it matches | ||
* will automatically be bound to it using the \c probe function. | ||
* | ||
* @info This function is generally called automatically during startup on the | ||
* declared drivers, and should not need to be called manually elsewhere. | ||
*/ | ||
void driver_register(driver_t *driver); | ||
|
||
typedef void (*driver_init_t)(void); | ||
|
||
/** Declare a new driver. | ||
* | ||
* Drivers declared using this macro are automatically loaded at startup, and | ||
* are automatically associated with their corresponding devices. | ||
* | ||
* @param _name The name of the driver | ||
* @param _driver The driver's definition (\ref device_driver) | ||
*/ | ||
#define DECLARE_DRIVER(_name, _driver) \ | ||
static void init_driver_##_name(void) \ | ||
{ \ | ||
driver_register(_driver); \ | ||
} \ | ||
\ | ||
SECTION(".data.driver.init") \ | ||
MAYBE_UNUSED \ | ||
static driver_init_t __##_name##_driver_init = init_driver_##_name; | ||
|
||
/** Load all builtin drivers. | ||
* Builtin drivers are ones declared using \ref DECLARE_DRIVER | ||
*/ | ||
void driver_load_drivers(void); | ||
|
||
/** Retreive the driver that matches the given arguments. | ||
* @return A pointer to the driver, or one containing an eventual error code. | ||
*/ | ||
const driver_t *driver_find_match(device_detection_method, const char *); | ||
|
||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.