Initial commit
This commit is contained in:
commit
cbc51f523e
125 changed files with 34817 additions and 0 deletions
353
src/uacpi/default_handlers.c
Normal file
353
src/uacpi/default_handlers.c
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
#include <uacpi/internal/opregion.h>
|
||||
#include <uacpi/internal/namespace.h>
|
||||
#include <uacpi/internal/utilities.h>
|
||||
#include <uacpi/internal/helpers.h>
|
||||
#include <uacpi/internal/log.h>
|
||||
#include <uacpi/internal/io.h>
|
||||
#include <uacpi/kernel_api.h>
|
||||
#include <uacpi/uacpi.h>
|
||||
|
||||
#define PCI_ROOT_PNP_ID "PNP0A03"
|
||||
#define PCI_EXPRESS_ROOT_PNP_ID "PNP0A08"
|
||||
|
||||
static uacpi_namespace_node *find_pci_root(uacpi_namespace_node *node)
|
||||
{
|
||||
static const uacpi_char *pci_root_ids[] = {
|
||||
PCI_ROOT_PNP_ID,
|
||||
PCI_EXPRESS_ROOT_PNP_ID,
|
||||
UACPI_NULL
|
||||
};
|
||||
uacpi_namespace_node *parent = node->parent;
|
||||
|
||||
while (parent != uacpi_namespace_root()) {
|
||||
if (uacpi_device_matches_pnp_id(parent, pci_root_ids)) {
|
||||
uacpi_trace(
|
||||
"found a PCI root node %.4s controlling region %.4s\n",
|
||||
parent->name.text, node->name.text
|
||||
);
|
||||
return parent;
|
||||
}
|
||||
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
uacpi_trace_region_error(
|
||||
node, "unable to find PCI root controlling",
|
||||
UACPI_STATUS_NOT_FOUND
|
||||
);
|
||||
return node;
|
||||
}
|
||||
|
||||
static uacpi_status pci_region_attach(uacpi_region_attach_data *data)
|
||||
{
|
||||
uacpi_namespace_node *node, *pci_root, *device;
|
||||
uacpi_pci_address address = { 0 };
|
||||
uacpi_u64 value;
|
||||
uacpi_status ret;
|
||||
|
||||
node = data->region_node;
|
||||
pci_root = find_pci_root(node);
|
||||
|
||||
/*
|
||||
* Find the actual device object that is supposed to be controlling
|
||||
* this operation region.
|
||||
*/
|
||||
device = node;
|
||||
while (device) {
|
||||
uacpi_object_type type;
|
||||
|
||||
ret = uacpi_namespace_node_type(device, &type);
|
||||
if (uacpi_unlikely_error(ret))
|
||||
return ret;
|
||||
|
||||
if (type == UACPI_OBJECT_DEVICE)
|
||||
break;
|
||||
|
||||
device = device->parent;
|
||||
}
|
||||
|
||||
if (uacpi_unlikely(device == UACPI_NULL)) {
|
||||
ret = UACPI_STATUS_NOT_FOUND;
|
||||
uacpi_trace_region_error(
|
||||
node, "unable to find device responsible for", ret
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = uacpi_eval_simple_integer(device, "_ADR", &value);
|
||||
if (ret == UACPI_STATUS_OK) {
|
||||
address.function = (value >> 0) & 0xFF;
|
||||
address.device = (value >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
ret = uacpi_eval_simple_integer(pci_root, "_SEG", &value);
|
||||
if (ret == UACPI_STATUS_OK)
|
||||
address.segment = value;
|
||||
|
||||
ret = uacpi_eval_simple_integer(pci_root, "_BBN", &value);
|
||||
if (ret == UACPI_STATUS_OK)
|
||||
address.bus = value;
|
||||
|
||||
uacpi_trace(
|
||||
"detected PCI device %.4s@%04X:%02X:%02X:%01X\n",
|
||||
device->name.text, address.segment, address.bus,
|
||||
address.device, address.function
|
||||
);
|
||||
|
||||
return uacpi_kernel_pci_device_open(address, &data->out_region_context);
|
||||
}
|
||||
|
||||
static uacpi_status pci_region_detach(uacpi_region_detach_data *data)
|
||||
{
|
||||
uacpi_kernel_pci_device_close(data->region_context);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status pci_region_do_rw(
|
||||
uacpi_region_op op, uacpi_region_rw_data *data
|
||||
)
|
||||
{
|
||||
uacpi_handle dev = data->region_context;
|
||||
uacpi_u8 width;
|
||||
uacpi_size offset;
|
||||
|
||||
offset = data->offset;
|
||||
width = data->byte_width;
|
||||
|
||||
return op == UACPI_REGION_OP_READ ?
|
||||
uacpi_kernel_pci_read(dev, offset, width, &data->value) :
|
||||
uacpi_kernel_pci_write(dev, offset, width, data->value);
|
||||
}
|
||||
|
||||
static uacpi_status handle_pci_region(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
switch (op) {
|
||||
case UACPI_REGION_OP_ATTACH:
|
||||
return pci_region_attach(op_data);
|
||||
case UACPI_REGION_OP_DETACH:
|
||||
return pci_region_detach(op_data);
|
||||
case UACPI_REGION_OP_READ:
|
||||
case UACPI_REGION_OP_WRITE:
|
||||
return pci_region_do_rw(op, op_data);
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
struct memory_region_ctx {
|
||||
uacpi_phys_addr phys;
|
||||
uacpi_u8 *virt;
|
||||
uacpi_size size;
|
||||
};
|
||||
|
||||
static uacpi_status memory_region_attach(uacpi_region_attach_data *data)
|
||||
{
|
||||
struct memory_region_ctx *ctx;
|
||||
uacpi_object *region_obj;
|
||||
uacpi_operation_region *op_region;
|
||||
uacpi_status ret;
|
||||
|
||||
ctx = uacpi_kernel_alloc(sizeof(*ctx));
|
||||
if (ctx == UACPI_NULL)
|
||||
return UACPI_STATUS_OUT_OF_MEMORY;
|
||||
|
||||
ret = uacpi_namespace_node_acquire_object_typed(
|
||||
data->region_node, UACPI_OBJECT_OPERATION_REGION_BIT, ®ion_obj
|
||||
);
|
||||
if (uacpi_unlikely_error(ret))
|
||||
return ret;
|
||||
|
||||
op_region = region_obj->op_region;
|
||||
ctx->size = op_region->length;
|
||||
|
||||
// FIXME: this really shouldn't try to map everything at once
|
||||
ctx->phys = op_region->offset;
|
||||
ctx->virt = uacpi_kernel_map(ctx->phys, ctx->size);
|
||||
|
||||
if (uacpi_unlikely(ctx->virt == UACPI_NULL)) {
|
||||
ret = UACPI_STATUS_MAPPING_FAILED;
|
||||
uacpi_trace_region_error(data->region_node, "unable to map", ret);
|
||||
uacpi_free(ctx, sizeof(*ctx));
|
||||
goto out;
|
||||
}
|
||||
|
||||
data->out_region_context = ctx;
|
||||
out:
|
||||
uacpi_namespace_node_release_object(region_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uacpi_status memory_region_detach(uacpi_region_detach_data *data)
|
||||
{
|
||||
struct memory_region_ctx *ctx = data->region_context;
|
||||
|
||||
uacpi_kernel_unmap(ctx->virt, ctx->size);
|
||||
uacpi_free(ctx, sizeof(*ctx));
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
struct io_region_ctx {
|
||||
uacpi_io_addr base;
|
||||
uacpi_handle handle;
|
||||
};
|
||||
|
||||
static uacpi_status io_region_attach(uacpi_region_attach_data *data)
|
||||
{
|
||||
struct io_region_ctx *ctx;
|
||||
uacpi_object *region_obj;
|
||||
uacpi_operation_region *op_region;
|
||||
uacpi_status ret;
|
||||
|
||||
ctx = uacpi_kernel_alloc(sizeof(*ctx));
|
||||
if (ctx == UACPI_NULL)
|
||||
return UACPI_STATUS_OUT_OF_MEMORY;
|
||||
|
||||
ret = uacpi_namespace_node_acquire_object_typed(
|
||||
data->region_node, UACPI_OBJECT_OPERATION_REGION_BIT, ®ion_obj
|
||||
);
|
||||
if (uacpi_unlikely_error(ret))
|
||||
return ret;
|
||||
|
||||
op_region = region_obj->op_region;
|
||||
ctx->base = op_region->offset;
|
||||
|
||||
ret = uacpi_kernel_io_map(ctx->base, op_region->length, &ctx->handle);
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
uacpi_trace_region_error(
|
||||
data->region_node, "unable to map an IO", ret
|
||||
);
|
||||
uacpi_free(ctx, sizeof(*ctx));
|
||||
goto out;
|
||||
}
|
||||
|
||||
data->out_region_context = ctx;
|
||||
|
||||
out:
|
||||
uacpi_object_unref(region_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uacpi_status io_region_detach(uacpi_region_detach_data *data)
|
||||
{
|
||||
struct io_region_ctx *ctx = data->region_context;
|
||||
|
||||
uacpi_kernel_io_unmap(ctx->handle);
|
||||
uacpi_free(ctx, sizeof(*ctx));
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status memory_region_do_rw(
|
||||
uacpi_region_op op, uacpi_region_rw_data *data
|
||||
)
|
||||
{
|
||||
struct memory_region_ctx *ctx = data->region_context;
|
||||
uacpi_u8 *ptr;
|
||||
|
||||
ptr = ctx->virt + (data->address - ctx->phys);
|
||||
|
||||
return op == UACPI_REGION_OP_READ ?
|
||||
uacpi_system_memory_read(ptr, data->byte_width, &data->value) :
|
||||
uacpi_system_memory_write(ptr, data->byte_width, data->value);
|
||||
}
|
||||
|
||||
static uacpi_status handle_memory_region(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
switch (op) {
|
||||
case UACPI_REGION_OP_ATTACH:
|
||||
return memory_region_attach(op_data);
|
||||
case UACPI_REGION_OP_DETACH:
|
||||
return memory_region_detach(op_data);
|
||||
case UACPI_REGION_OP_READ:
|
||||
case UACPI_REGION_OP_WRITE:
|
||||
return memory_region_do_rw(op, op_data);
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
static uacpi_status table_data_region_do_rw(
|
||||
uacpi_region_op op, uacpi_region_rw_data *data
|
||||
)
|
||||
{
|
||||
void *addr = UACPI_VIRT_ADDR_TO_PTR((uacpi_virt_addr)data->offset);
|
||||
|
||||
return op == UACPI_REGION_OP_READ ?
|
||||
uacpi_system_memory_read(addr, data->byte_width, &data->value) :
|
||||
uacpi_system_memory_write(addr, data->byte_width, data->value);
|
||||
}
|
||||
|
||||
static uacpi_status handle_table_data_region(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
switch (op) {
|
||||
case UACPI_REGION_OP_ATTACH:
|
||||
case UACPI_REGION_OP_DETACH:
|
||||
return UACPI_STATUS_OK;
|
||||
case UACPI_REGION_OP_READ:
|
||||
case UACPI_REGION_OP_WRITE:
|
||||
return table_data_region_do_rw(op, op_data);
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
static uacpi_status io_region_do_rw(
|
||||
uacpi_region_op op, uacpi_region_rw_data *data
|
||||
)
|
||||
{
|
||||
struct io_region_ctx *ctx = data->region_context;
|
||||
uacpi_u8 width;
|
||||
uacpi_size offset;
|
||||
|
||||
offset = data->offset - ctx->base;
|
||||
width = data->byte_width;
|
||||
|
||||
return op == UACPI_REGION_OP_READ ?
|
||||
uacpi_kernel_io_read(ctx->handle, offset, width, &data->value) :
|
||||
uacpi_kernel_io_write(ctx->handle, offset, width, data->value);
|
||||
}
|
||||
|
||||
static uacpi_status handle_io_region(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
switch (op) {
|
||||
case UACPI_REGION_OP_ATTACH:
|
||||
return io_region_attach(op_data);
|
||||
case UACPI_REGION_OP_DETACH:
|
||||
return io_region_detach(op_data);
|
||||
case UACPI_REGION_OP_READ:
|
||||
case UACPI_REGION_OP_WRITE:
|
||||
return io_region_do_rw(op, op_data);
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
void uacpi_install_default_address_space_handlers(void)
|
||||
{
|
||||
uacpi_namespace_node *root;
|
||||
|
||||
root = uacpi_namespace_root();
|
||||
|
||||
uacpi_install_address_space_handler_with_flags(
|
||||
root, UACPI_ADDRESS_SPACE_SYSTEM_MEMORY,
|
||||
handle_memory_region, UACPI_NULL,
|
||||
UACPI_ADDRESS_SPACE_HANDLER_DEFAULT
|
||||
);
|
||||
|
||||
uacpi_install_address_space_handler_with_flags(
|
||||
root, UACPI_ADDRESS_SPACE_SYSTEM_IO,
|
||||
handle_io_region, UACPI_NULL,
|
||||
UACPI_ADDRESS_SPACE_HANDLER_DEFAULT
|
||||
);
|
||||
|
||||
uacpi_install_address_space_handler_with_flags(
|
||||
root, UACPI_ADDRESS_SPACE_PCI_CONFIG,
|
||||
handle_pci_region, UACPI_NULL,
|
||||
UACPI_ADDRESS_SPACE_HANDLER_DEFAULT
|
||||
);
|
||||
|
||||
uacpi_install_address_space_handler_with_flags(
|
||||
root, UACPI_ADDRESS_SPACE_TABLE_DATA,
|
||||
handle_table_data_region, UACPI_NULL,
|
||||
UACPI_ADDRESS_SPACE_HANDLER_DEFAULT
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue