The Toaru kernel supports loadable modules which provide most of the device driver support.
A simple module requires a load and unload method, which are exposed along with a module
name through the MODULE_DEF
macro available from <kernel/module.h>
.
#include <kernel/module.h>
static int load(void) {
/* Run on module installation */
return 0;
}
static int unload(void) {
/* Clean up for removal */
return 0;
}
MODULE_DEF(example_mod, load, unload);
If your module depends on another module being loaded, list each dependency using the MODULE_DEPENDS
macro:
MODULE_DEF(extension_mod, load, unload);
MODULE_DEPENDS(example_mod);
Currently, dependencies are tested at load time, but the kernel will not load dependencies for you.
Dependency lists can be parsed by external tools to ensure modules are properly linked.
All non-static kernel functions are available for use in modules. For example, the logging functions may be used:
#include <kernel/logging.h>
#include <kernel/module.h>
static int load(void) {
debug_print(WARNING, "Hello, world.");
return 0;
}
static int unload(void) {
return 0;
}
MODULE_DEF(printing_mod, load, unload);
Device drivers, such as those for network devices, may want to create a background process to manage tasks.
This can be done through the create_kernel_tasklet
interface at device startup.
#include <kernel/process.h>
#include <kernel/module.h>
static void tasklet_run(void * data, char * name) {
/* Perform tasklet activities */
while (1) {
do_thing();
}
}
static int load(void) {
create_kernel_tasklet(tasklet_run, "[demo-tasklet]", NULL);
return 0;
}
static int unload(void) {
/* Maybe clean up your tasklet here. */
return 0;
}
MODULE_DEF(tasklet_mod, load, unload);