#include <sys/uuid.h>
#include "apple_fw.h"
#define APPLE_DTGP_UUID_STRING "a0b5b7c6-1318-441c-b0c9-fe695eaf949b"
static uint8_t apple_dtgp_uuid[ACPI_UUID_LENGTH];
static int apple_dtgp_uuid_ready;
static void
apple_fw_init_uuid(void)
{
struct uuid uuid;
if (apple_dtgp_uuid_ready)
return;
if (parse_uuid(APPLE_DTGP_UUID_STRING, &uuid) != 0)
return;
le_uuid_enc(apple_dtgp_uuid, &uuid);
apple_dtgp_uuid_ready = 1;
}
static ACPI_STATUS
apple_fw_eval_dsm(ACPI_HANDLE handle, int func, ACPI_BUFFER *result)
{
ACPI_OBJECT args[4];
ACPI_OBJECT_LIST arg_list;
args[0].Type = ACPI_TYPE_BUFFER;
args[0].Buffer.Length = ACPI_UUID_LENGTH;
args[0].Buffer.Pointer = apple_dtgp_uuid;
args[1].Type = ACPI_TYPE_INTEGER;
args[1].Integer.Value = 1;
args[2].Type = ACPI_TYPE_INTEGER;
args[2].Integer.Value = func;
args[3].Type = ACPI_TYPE_PACKAGE;
args[3].Package.Count = 0;
args[3].Package.Elements = NULL;
arg_list.Count = 4;
arg_list.Pointer = args;
result->Length = ACPI_ALLOCATE_BUFFER;
result->Pointer = NULL;
return (AcpiEvaluateObject(handle, "_DSM", &arg_list, result));
}
static void
apple_fw_parse_dsm_props(device_t dev, struct apple_fw_dsm_dev *ddev,
ACPI_OBJECT *pkg)
{
ACPI_OBJECT *elem;
uint32_t i;
int n;
if (pkg->Type != ACPI_TYPE_PACKAGE)
return;
for (i = 0; i + 1 < pkg->Package.Count; i += 2) {
if (ddev->prop_count >= APPLE_FW_MAX_PROPS)
break;
elem = &pkg->Package.Elements[i];
if (elem->Type != ACPI_TYPE_STRING)
continue;
n = ddev->prop_count;
strlcpy(ddev->props[n].key, elem->String.Pointer,
sizeof(ddev->props[n].key));
elem = &pkg->Package.Elements[i + 1];
switch (elem->Type) {
case ACPI_TYPE_INTEGER:
ddev->props[n].val_type = APPLE_FW_PROP_INT;
ddev->props[n].ival = (int64_t)elem->Integer.Value;
ddev->props[n].val_len = sizeof(int64_t);
break;
case ACPI_TYPE_STRING:
ddev->props[n].val_type = APPLE_FW_PROP_STRING;
strlcpy(ddev->props[n].sval, elem->String.Pointer,
sizeof(ddev->props[n].sval));
ddev->props[n].val_len = elem->String.Length;
break;
case ACPI_TYPE_BUFFER:
ddev->props[n].val_type = APPLE_FW_PROP_BUFFER;
ddev->props[n].val_len =
MIN(elem->Buffer.Length, APPLE_FW_MAX_PROPVAL);
memcpy(ddev->props[n].bval, elem->Buffer.Pointer,
ddev->props[n].val_len);
break;
default:
continue;
}
ddev->prop_count++;
}
}
static ACPI_STATUS
apple_fw_dsm_walk_cb(ACPI_HANDLE handle, UINT32 level, void *context,
void **retval)
{
device_t dev = (device_t)context;
struct apple_fw_softc *sc = device_get_softc(dev);
struct apple_fw_dsm_dev *ddev;
ACPI_HANDLE dsm_handle;
ACPI_STATUS status;
ACPI_BUFFER result;
ACPI_BUFFER pathbuf;
ACPI_OBJECT *obj;
ACPI_DEVICE_INFO *info;
char namebuf[256];
status = AcpiGetHandle(handle, "_DSM", &dsm_handle);
if (ACPI_FAILURE(status))
return (AE_OK);
status = apple_fw_eval_dsm(handle, 1, &result);
if (ACPI_FAILURE(status) || result.Pointer == NULL)
return (AE_OK);
obj = (ACPI_OBJECT *)result.Pointer;
if (!ACPI_PKG_VALID(obj, 2)) {
AcpiOsFree(result.Pointer);
return (AE_OK);
}
if (sc->sc_dsm_count >= APPLE_FW_MAX_DSM_DEVS) {
AcpiOsFree(result.Pointer);
return (AE_OK);
}
ddev = &sc->sc_dsm_devs[sc->sc_dsm_count];
memset(ddev, 0, sizeof(*ddev));
pathbuf.Length = sizeof(namebuf);
pathbuf.Pointer = namebuf;
status = AcpiGetName(handle, ACPI_FULL_PATHNAME, &pathbuf);
if (ACPI_SUCCESS(status))
strlcpy(ddev->path, namebuf, sizeof(ddev->path));
status = AcpiGetObjectInfo(handle, &info);
if (ACPI_SUCCESS(status)) {
if (info->Valid & ACPI_VALID_HID)
strlcpy(ddev->name, info->HardwareId.String,
sizeof(ddev->name));
AcpiOsFree(info);
}
if (ddev->name[0] == '\0') {
ACPI_BUFFER nbuf;
char snbuf[8];
nbuf.Length = sizeof(snbuf);
nbuf.Pointer = snbuf;
if (ACPI_SUCCESS(AcpiGetName(handle, ACPI_SINGLE_NAME, &nbuf)))
strlcpy(ddev->name, snbuf, sizeof(ddev->name));
}
apple_fw_parse_dsm_props(dev, ddev, obj);
AcpiOsFree(result.Pointer);
if (ddev->prop_count > 0)
sc->sc_dsm_count++;
return (AE_OK);
}
void
apple_fw_discover_dsm_devices(device_t dev)
{
struct apple_fw_softc *sc = device_get_softc(dev);
sc->sc_dsm_count = 0;
apple_fw_init_uuid();
AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 100,
apple_fw_dsm_walk_cb, NULL, dev, NULL);
}