/*
Copyright (C) 2021 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
The GNU Hurd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with the GNU Hurd. If not, see .
*/
/* Implementation of ACPI operations */
#include
#include
#include
#include
#include
#include "libacpica/acpi_init.h"
#include "acpifs.h"
static error_t
check_permissions (struct protid *master, int flags)
{
struct node *node;
struct acpifs_dirent *e;
node = master->po->np;
e = node->nn->ln;
/* Check whether the user has permissions to access this node */
return entry_check_perms (master->user, e, flags);
}
static void
acpi_enable(struct acpi_table *facp)
{
int i;
uint8_t *ptr = (uint8_t *)&facp->data;
/* Grab value to write to SMI_CMD to enable ACPI */
uint8_t acpi_en = ptr[SMI_EN_OFFSET];
uint16_t smi_cmd = (uint16_t)ptr[SMI_CMD_OFFSET] | ((uint16_t)ptr[SMI_CMD_OFFSET+1] << 8);
uint16_t pm1a_ctl = (uint16_t)ptr[PM1A_CTL_OFFSET] | ((uint16_t)ptr[PM1A_CTL_OFFSET+1] << 8);
/* Get I/O permissions */
if (ioperm(smi_cmd, 2, 1))
{
fprintf(stderr, "EPERM on ioperm(smi_cmd)\n");
return;
}
if (ioperm(pm1a_ctl, 2, 1))
{
fprintf(stderr, "EPERM on ioperm(pm1a_ctl)\n");
return;
}
/* Enable ACPI */
outb(acpi_en, smi_cmd);
for (i = 0; i < 300; i++)
{
if ((inw(pm1a_ctl) & SCI_EN) == SCI_EN)
break;
}
/* Drop I/O permissions */
ioperm(smi_cmd, 2, 0);
ioperm(pm1a_ctl, 2, 0);
}
error_t
S_acpi_sleep (struct protid *master, int sleep_state)
{
error_t err;
struct acpifs_dirent *e;
if (!master)
return EOPNOTSUPP;
e = master->po->np->nn->ln;
if (strncmp (e->name, "FACP", 4))
/* This operation may only be addressed to the FADT table */
return EINVAL;
err = check_permissions (master, O_READ);
if (err)
return err;
/* Enable ACPI */
acpi_enable(e->acpitable);
/* Perform sleep */
acpi_enter_sleep(sleep_state);
/* Never reached */
return err;
}
error_t
S_acpi_enable (struct protid *master)
{
error_t err;
struct acpifs_dirent *e;
if (!master)
return EOPNOTSUPP;
e = master->po->np->nn->ln;
if (strncmp (e->name, "FACP", 4))
/* This operation may only be addressed to the FADT table */
return EINVAL;
err = check_permissions (master, O_READ);
if (err)
return err;
acpi_enable(e->acpitable);
return err;
}
error_t
S_acpi_get_irq (struct protid *master, int bus, int dev, int func, int *irq)
{
error_t err;
if (!master)
return EOPNOTSUPP;
err = check_permissions (master, O_READ);
if (err)
return err;
*irq = acpi_get_irq_number(bus, dev, func);
return err;
}