/* 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; }