* Copyright 2009, Clemens Zeidler. All rights reserved.
* Copyright 2006, Jérôme Duval. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
#include <stdlib.h>
#include <string.h>
#include "ACPIPrivate.h"
extern "C" {
#include "acpi.h"
}
#include <dpc.h>
#include <PCI.h>
#ifdef TRACE_ACPI_MODULE
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
device_manager_info* gDeviceManager = NULL;
pci_module_info* gPCIManager = NULL;
dpc_module_info* gDPC = NULL;
module_dependency module_dependencies[] = {
{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager},
{B_PCI_MODULE_NAME, (module_info**)&gPCIManager},
{B_DPC_MODULE_NAME, (module_info**)&gDPC},
{}
};
static float
acpi_module_supports_device(device_node* parent)
{
const char* bus;
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
return B_ERROR;
if (strcmp(bus, "root"))
return 0.0;
return 1.0;
}
static status_t
acpi_module_register_device(device_node* parent)
{
device_attr attrs[] = {
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI" }},
{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_KEEP_DRIVER_LOADED }},
{}
};
return gDeviceManager->register_node(parent, ACPI_ROOT_MODULE_NAME, attrs,
NULL, NULL);
}
static status_t
acpi_enumerate_child_devices(device_node* node, const char* root)
{
char result[255];
void* counter = NULL;
TRACE(("acpi_enumerate_child_devices: recursing from %s\n", root));
while (get_next_entry(ACPI_TYPE_ANY, root, result,
sizeof(result), &counter) == B_OK) {
uint32 type = get_object_type(result);
device_node* deviceNode;
switch (type) {
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_DEVICE: {
device_attr attrs[16] = {
{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
{ ACPI_DEVICE_PATH_ITEM, B_STRING_TYPE, { .string = result }},
{ ACPI_DEVICE_TYPE_ITEM, B_UINT32_TYPE, { .ui32 = type }},
{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
{ NULL }
};
uint32 attrCount = 4;
char* hid = NULL;
char* cidList[11] = { NULL };
char* uid = NULL;
char* cls = NULL;
if (type == ACPI_TYPE_DEVICE) {
if (get_device_info(result, &hid, (char**)&cidList, 8,
&uid, &cls) == B_OK) {
if (hid != NULL) {
attrs[attrCount].name = ACPI_DEVICE_HID_ITEM;
attrs[attrCount].type = B_STRING_TYPE;
attrs[attrCount].value.string = hid;
attrCount++;
}
for (int i = 0; cidList[i] != NULL; i++) {
attrs[attrCount].name = ACPI_DEVICE_CID_ITEM;
attrs[attrCount].type = B_STRING_TYPE;
attrs[attrCount].value.string = cidList[i];
attrCount++;
}
if (uid != NULL) {
attrs[attrCount].name = ACPI_DEVICE_UID_ITEM;
attrs[attrCount].type = B_STRING_TYPE;
attrs[attrCount].value.string = uid;
attrCount++;
}
if (cls != NULL) {
uint32 clsClass = strtoul(cls, NULL, 16);
attrs[attrCount].name = B_DEVICE_TYPE;
attrs[attrCount].type = B_UINT16_TYPE;
attrs[attrCount].value.ui16 = (clsClass >> 16) & 0xff ;
attrCount++;
attrs[attrCount].name = B_DEVICE_SUB_TYPE;
attrs[attrCount].type = B_UINT16_TYPE;
attrs[attrCount].value.ui16 = (clsClass >> 8) & 0xff ;
attrCount++;
attrs[attrCount].name = B_DEVICE_INTERFACE;
attrs[attrCount].type = B_UINT16_TYPE;
attrs[attrCount].value.ui16 = (clsClass >> 0) & 0xff ;
attrCount++;
}
}
uint32 addr;
if (get_device_addr(result, &addr) == B_OK) {
attrs[attrCount].name = ACPI_DEVICE_ADDR_ITEM;
attrs[attrCount].type = B_UINT32_TYPE;
attrs[attrCount].value.ui32 = addr;
attrCount++;
}
}
status_t status = gDeviceManager->register_node(node,
ACPI_DEVICE_MODULE_NAME, attrs, NULL, &deviceNode);
free(hid);
free(uid);
free(cls);
for (int i = 0; cidList[i] != NULL; i++)
free(cidList[i]);
if (status != B_OK)
break;
acpi_enumerate_child_devices(deviceNode, result);
break;
}
default:
acpi_enumerate_child_devices(node, result);
break;
}
}
return B_OK;
}
static status_t
acpi_module_register_child_devices(void* cookie)
{
device_node* node = (device_node*)cookie;
status_t status = gDeviceManager->publish_device(node, "acpi/namespace",
ACPI_NS_DUMP_DEVICE_MODULE_NAME);
if (status != B_OK)
return status;
status = gDeviceManager->publish_device(node, "acpi/call",
ACPI_CALL_DEVICE_MODULE_NAME);
if (status != B_OK)
return status;
if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) == 0) {
dprintf("registering power button\n");
device_attr attrs[] = {
{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = "ACPI_FPB" }},
{ ACPI_DEVICE_TYPE_ITEM, B_UINT32_TYPE, { .ui32 = ACPI_TYPE_DEVICE }},
{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
{ NULL }
};
device_node* deviceNode;
gDeviceManager->register_node(node, ACPI_DEVICE_MODULE_NAME, attrs,
NULL, &deviceNode);
}
if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
dprintf("registering sleep button\n");
device_attr attrs[] = {
{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }},
{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = "ACPI_FSB" }},
{ ACPI_DEVICE_TYPE_ITEM, B_UINT32_TYPE, { .ui32 = ACPI_TYPE_DEVICE }},
{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},
{ NULL }
};
device_node* deviceNode;
gDeviceManager->register_node(node, ACPI_DEVICE_MODULE_NAME, attrs,
NULL, &deviceNode);
}
return acpi_enumerate_child_devices(node, "\\");
}
static status_t
acpi_module_init(device_node* node, void** _cookie)
{
*_cookie = node;
return B_OK;
}
static void
acpi_module_uninit(void* cookie)
{
}
static int32
acpi_module_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
{
module_info* module;
return get_module(B_ACPI_MODULE_NAME, &module);
}
case B_MODULE_UNINIT:
return put_module(B_ACPI_MODULE_NAME);
}
return B_BAD_VALUE;
}
static struct acpi_root_info sACPIRootModule = {
{
{
ACPI_ROOT_MODULE_NAME,
0,
acpi_module_std_ops
},
acpi_module_supports_device,
acpi_module_register_device,
acpi_module_init,
acpi_module_uninit,
acpi_module_register_child_devices,
NULL,
NULL,
},
get_handle,
get_name,
acquire_global_lock,
release_global_lock,
install_notify_handler,
remove_notify_handler,
update_all_gpes,
enable_gpe,
disable_gpe,
clear_gpe,
set_gpe,
finish_gpe,
install_gpe_handler,
remove_gpe_handler,
install_address_space_handler,
remove_address_space_handler,
enable_fixed_event,
disable_fixed_event,
fixed_event_status,
reset_fixed_event,
install_fixed_event_handler,
remove_fixed_event_handler,
get_next_entry,
get_next_object,
get_device,
get_device_info,
get_object_type,
get_object,
get_object_typed,
ns_handle_to_pathname,
evaluate_object,
evaluate_method,
get_irq_routing_table,
get_current_resources,
get_possible_resources,
set_current_resources,
walk_resources,
prepare_sleep_state,
enter_sleep_state,
reboot,
get_table
};
module_info* modules[] = {
(module_info*)&gACPIModule,
(module_info*)&sACPIRootModule,
(module_info*)&acpi_ns_dump_module,
(module_info*)&gACPIDeviceModule,
(module_info*)&embedded_controller_driver_module,
(module_info*)&embedded_controller_device_module,
(module_info*)&gAcpiCallDeviceModule,
NULL
};