HAL
The Hardware Abstraction Layer is an important part of Ethereal's hardware API.
Interrupts
Handlers
Registering interrupts can be done with the HAL through the following function:
int hal_registerInterruptHandler(uintptr_t int_number, hal_interrupt_handler_t handler, void *context);
int_number
: The target interrupt number to usehandler
: The handler to usecontext
: The context to pass to the handler
The interrupt handler is declared as:
typedef int (*hal_interrupt_handler_t)(void *context);
danger
Returning nonzero from an interrupt handler will cause IRQ_HANDLER_FAILED
to be thrown.
You can unregister interrupt handlers using the following function:
void hal_unregisterInterruptHandler(uintptr_t int_no);
Putting it all together
Let's combine our knowledge of the PCI and HAL API to register an interrupt handler for our fake device.
/**
* @brief PCI example
*/
#include <kernel/loader/driver.h>
#include <kernel/debug.h>
#include <kernel/drivers/pci.h>
#include <kernel/mem/mem.h>
#include <kernel/hal.h>
#include <string.h>
int handler(void *context) {
dprintf(DEBUG, "IRQ handler!\n");
return 0;
}
int driver_scanCallback(pci_device_t *device, void *context) {
dprintf(INFO, "Found matching device at bus %d slot %d func %d\n", device->bus, device->slot, device->function);
// Get BAR0
pci_bar_t *b = pci_getBAR(device->bus, device->slot, device->function, 0);
assert(b);
// Map it as MMIO
uintptr_t m = mem_mapMMIO(b->address, b->size);
dprintf(DEBUG, "Mapped memory to 0x%016llX\n", m);
memset(m, 0, b->size);
mem_unmapMMIO(m, b->size);
// Enable an MSI interrupt
uint8_t irq = pci_enableMSI(device->bus, device->slot, device->function);
if (irq == 0xFF) return 1; // MSI not supported or error
// Register the handler
hal_registerInterruptHandler(irq, handler, (void*)0xDEADBEEF);
return 0;
}
int driver_init(int argc, char *argv[]) {
dprintf(DEBUG, "Scanning for example PCI device with VID 1234 and PID 1111...\n");
pci_id_mapping_t id_list[] = {
{ .vid = 0x1234, .pid = { 0x1111, PCI_NONE }},
PCI_ID_MAPPING_END
};
pci_scan_parameters_t params = {
.class_code = 0, // No class code
.subclass_code = 0, // No class code
.id_list = id_list
};
return pci_scan(driver_scanCallback, ¶ms, NULL);
}
int driver_deinit() { return DRIVER_STATUS_SUCCESS; }
struct driver_metadata driver_metadata = {
.name = "Example Driver",
.author = "Your Name Here",
.init = driver_init,
.deinit = driver_deinit
};