* Copyright 2022, JΓ©rΓ΄me Duval, jerome.duval@gmail.com.
* Distributed under the terms of the MIT License.
*/
#include <new>
#include <stdio.h>
#include <string.h>
#include <ACPI.h>
#include <ByteOrder.h>
#include <condition_variable.h>
extern "C" {
# include "acpi.h"
}
#define DRIVER_NAME "ccp_rng_acpi"
#include "ccp.h"
typedef struct {
ccp_device_info info;
acpi_device_module_info* acpi;
acpi_device device;
} ccp_acpi_sim_info;
struct ccp_crs {
uint32 addr_bas;
uint32 addr_len;
};
static acpi_status
ccp_scan_parse_callback(ACPI_RESOURCE *res, void *context)
{
struct ccp_crs* crs = (struct ccp_crs*)context;
if (res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
crs->addr_bas = res->Data.FixedMemory32.Address;
crs->addr_len = res->Data.FixedMemory32.AddressLength;
}
return B_OK;
}
static status_t
init_device(device_node* node, void** device_cookie)
{
CALLED();
status_t status = B_OK;
ccp_acpi_sim_info* bus = (ccp_acpi_sim_info*)calloc(1,
sizeof(ccp_acpi_sim_info));
if (bus == NULL)
return B_NO_MEMORY;
acpi_device_module_info* acpi;
acpi_device device;
{
device_node* acpiParent = gDeviceManager->get_parent_node(node);
gDeviceManager->get_driver(acpiParent, (driver_module_info**)&acpi,
(void**)&device);
gDeviceManager->put_node(acpiParent);
}
bus->acpi = acpi;
bus->device = device;
struct ccp_crs crs;
status = acpi->walk_resources(device, (ACPI_STRING)"_CRS",
ccp_scan_parse_callback, &crs);
if (status != B_OK) {
ERROR("Error while getting resouces\n");
free(bus);
return status;
}
if (crs.addr_bas == 0 || crs.addr_len == 0) {
TRACE("skipping non configured CCP devices\n");
free(bus);
return B_BAD_VALUE;
}
bus->info.base_addr = crs.addr_bas;
bus->info.map_size = crs.addr_len;
*device_cookie = bus;
return B_OK;
}
static void
uninit_device(void* device_cookie)
{
ccp_acpi_sim_info* bus = (ccp_acpi_sim_info*)device_cookie;
free(bus);
}
static status_t
register_device(device_node* parent)
{
device_attr attrs[] = {
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "CCP ACPI"}},
{B_DEVICE_BUS, B_STRING_TYPE, {.string = "CCP"}},
{B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = CCP_DEVICE_MODULE_NAME}},
{}
};
return gDeviceManager->register_node(parent,
CCP_ACPI_DEVICE_MODULE_NAME, attrs, NULL, NULL);
}
static float
supports_device(device_node* parent)
{
const char* bus;
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
< B_OK) {
return -1;
}
if (strcmp(bus, "acpi") != 0)
return 0.0f;
uint32 device_type;
if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
&device_type, false) != B_OK
|| device_type != ACPI_TYPE_DEVICE) {
return 0.0;
}
const char *name;
if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
false) != B_OK) {
return 0.0;
}
if (strcmp(name, "AMDI0C00") == 0) {
TRACE("CCP device found! name %s\n", name);
return 0.6f;
}
return 0.0f;
}
driver_module_info gCcpAcpiDevice = {
{
CCP_ACPI_DEVICE_MODULE_NAME,
0,
NULL
},
supports_device,
register_device,
init_device,
uninit_device,
NULL,
NULL,
NULL,
};