blob: 7f1acf8a3ff278bd5ea2180d36c3768b91d618a3 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "acpi.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <launchpad/launchpad.h>
#include <acpisvc/simple.h>
#include <magenta/processargs.h>
#include <magenta/syscalls.h>
#include <mxio/io.h>
#include <mxio/util.h>
#include "devmgr.h"
#include "devhost.h"
static acpi_handle_t acpi_root;
mx_status_t devhost_launch_acpisvc(mx_handle_t job_handle) {
const char* binname = "/boot/bin/acpisvc";
mx_handle_t logger = MX_HANDLE_INVALID;
mx_handle_t root = MX_HANDLE_INVALID;
mx_handle_t rpc[2] = { MX_HANDLE_INVALID, MX_HANDLE_INVALID };
mx_log_create(0, &logger);
mx_handle_duplicate(get_root_resource(), MX_RIGHT_SAME_RIGHTS, &root);
mx_channel_create(0, &rpc[0], &rpc[1]);
launchpad_t* lp;
launchpad_create(job_handle, binname, &lp);
launchpad_load_from_file(lp, binname);
launchpad_set_args(lp, 1, &binname);
launchpad_clone(lp, LP_CLONE_ALL & (~LP_CLONE_MXIO_STDIO));
launchpad_add_handle(lp, logger, PA_HND(PA_MXIO_LOGGER, MXIO_FLAG_USE_FOR_STDIO | 1));
launchpad_add_handle(lp, root, PA_HND(PA_USER0, 0));
launchpad_add_handle(lp, rpc[1], PA_HND(PA_USER1, 0));
const char* errmsg;
mx_status_t status = launchpad_go(lp, NULL, &errmsg);
if (status < 0) {
mx_handle_close(rpc[0]);
printf("devmgr: acpisvc launch failed: %d: %s\n", status, errmsg);
return status;
}
acpi_handle_init(&acpi_root, rpc[0]);
return MX_OK;
}
// TODO(teisenbe): Instead of doing this as a single function, give the kpci
// driver a handle to the PCIe root complex ACPI node and let it ask for
// the initialization info.
mx_status_t devhost_init_pcie(void) {
char name[4] = {0};
{
acpi_rsp_list_children_t* rsp;
size_t len;
mx_status_t status = acpi_list_children(&acpi_root, &rsp, &len);
if (status != MX_OK) {
return status;
}
for (uint32_t i = 0; i < rsp->num_children; ++i) {
if (!memcmp(rsp->children[i].hid, "PNP0A08", 7)) {
memcpy(name, rsp->children[i].name, 4);
break;
}
}
free(rsp);
if (name[0] == 0) {
return MX_ERR_NOT_FOUND;
}
}
acpi_handle_t pcie_handle;
mx_status_t status = acpi_get_child_handle(&acpi_root, name, &pcie_handle);
if (status != MX_OK) {
return status;
}
acpi_rsp_get_pci_init_arg_t* rsp;
size_t len;
status = acpi_get_pci_init_arg(&pcie_handle, &rsp, &len);
if (status != MX_OK) {
acpi_handle_close(&pcie_handle);
return status;
}
acpi_handle_close(&pcie_handle);
len -= offsetof(acpi_rsp_get_pci_init_arg_t, arg);
status = mx_pci_init(get_root_resource(), &rsp->arg, len);
free(rsp);
return status;
}
void devhost_acpi_poweroff(void) {
acpi_s_state_transition(&acpi_root, ACPI_S_STATE_S5);
mx_debug_send_command(get_root_resource(), "poweroff", sizeof("poweroff"));
}
void devhost_acpi_reboot(void) {
acpi_s_state_transition(&acpi_root, ACPI_S_STATE_REBOOT);
mx_debug_send_command(get_root_resource(), "reboot", sizeof("reboot"));
}
void devhost_acpi_ps0(char* arg) {
acpi_ps0(&acpi_root, arg, strlen(arg));
}
mx_handle_t devhost_acpi_clone(void) {
return acpi_clone_handle(&acpi_root);
}