diff options
author | jkim <jkim@FreeBSD.org> | 2010-10-26 18:59:50 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2010-10-26 18:59:50 +0000 |
commit | ac1e1d40fd805786dc93f32dc3ed97de59aa0b3a (patch) | |
tree | c9bd777b0826009816d1ae91c68568372b172a88 /sys/dev/acpica | |
parent | c78cc2e91a450e158e4353438ade13bcb727fe9b (diff) | |
download | FreeBSD-src-ac1e1d40fd805786dc93f32dc3ed97de59aa0b3a.zip FreeBSD-src-ac1e1d40fd805786dc93f32dc3ed97de59aa0b3a.tar.gz |
Add two new loader tunables 'hw.acpi.install_interface' and
'hw.acpi.remove_interface'. hw.acpi.install_interface lets you install new
interfaces. Conversely, hw.acpi.remove_interface lets you remove OS
interfaces from the pre-defined list in ACPICA. For example,
hw.acpi.install_interface="FreeBSD"
lets _OSI("FreeBSD") method to return 0xffffffff (or success) and
hw.acpi.remove_interface="Windows 2009"
lets _OSI("Windows 2009") method to return zero (or failure). Both are
comma-separated lists and leading white spaces are ignored. For example,
the following examples are valid:
hw.acpi.install_interface="Linux, FreeBSD"
hw.acpi.remove_interface="Windows 2006, Windows 2006.1"
Diffstat (limited to 'sys/dev/acpica')
-rw-r--r-- | sys/dev/acpica/acpi.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 24982fe..c0f17f6 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -86,6 +86,11 @@ static struct cdevsw acpi_cdevsw = { .d_name = "acpi", }; +struct acpi_interface { + ACPI_STRING *data; + int num; +}; + /* Global mutex for locking access to the ACPI subsystem. */ struct mtx acpi_mutex; @@ -163,6 +168,7 @@ static void acpi_enable_pcie(void); #endif static void acpi_hint_device_unit(device_t acdev, device_t child, const char *name, int *unitp); +static void acpi_reset_interfaces(device_t dev); static device_method_t acpi_methods[] = { /* Device interface */ @@ -232,6 +238,16 @@ SYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD, acpi_ca_version, 0, "Version of Intel ACPI-CA"); /* + * Allow overriding _OSI methods. + */ +static char acpi_install_interface[256]; +TUNABLE_STR("hw.acpi.install_interface", acpi_install_interface, + sizeof(acpi_install_interface)); +static char acpi_remove_interface[256]; +TUNABLE_STR("hw.acpi.remove_interface", acpi_remove_interface, + sizeof(acpi_remove_interface)); + +/* * Allow override of whether methods execute in parallel or not. * Enable this for serial behavior, which fixes "AE_ALREADY_EXISTS" * errors for AML that really can't handle parallel method execution. @@ -467,6 +483,9 @@ acpi_attach(device_t dev) goto out; } + /* Override OS interfaces if the user requested. */ + acpi_reset_interfaces(dev); + /* Load ACPI name space. */ status = AcpiLoadTables(); if (ACPI_FAILURE(status)) { @@ -3473,6 +3492,93 @@ acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS) } static int +acpi_parse_interfaces(char *str, struct acpi_interface *iface) +{ + char *p; + size_t len; + int i, j; + + p = str; + while (isspace(*p) || *p == ',') + p++; + len = strlen(p); + if (len == 0) + return (0); + p = strdup(p, M_TEMP); + for (i = 0; i < len; i++) + if (p[i] == ',') + p[i] = '\0'; + i = j = 0; + while (i < len) + if (isspace(p[i]) || p[i] == '\0') + i++; + else { + i += strlen(p + i) + 1; + j++; + } + if (j == 0) { + free(p, M_TEMP); + return (0); + } + iface->data = malloc(sizeof(*iface->data) * j, M_TEMP, M_WAITOK); + iface->num = j; + i = j = 0; + while (i < len) + if (isspace(p[i]) || p[i] == '\0') + i++; + else { + iface->data[j] = p + i; + i += strlen(p + i) + 1; + j++; + } + + return (j); +} + +static void +acpi_free_interfaces(struct acpi_interface *iface) +{ + + free(iface->data[0], M_TEMP); + free(iface->data, M_TEMP); +} + +static void +acpi_reset_interfaces(device_t dev) +{ + struct acpi_interface list; + ACPI_STATUS status; + int i; + + if (acpi_parse_interfaces(acpi_install_interface, &list) > 0) { + for (i = 0; i < list.num; i++) { + status = AcpiInstallInterface(list.data[i]); + if (ACPI_FAILURE(status)) + device_printf(dev, + "failed to install _OSI(\"%s\"): %s\n", + list.data[i], AcpiFormatException(status)); + else if (bootverbose) + device_printf(dev, "installed _OSI(\"%s\")\n", + list.data[i]); + } + acpi_free_interfaces(&list); + } + if (acpi_parse_interfaces(acpi_remove_interface, &list) > 0) { + for (i = 0; i < list.num; i++) { + status = AcpiRemoveInterface(list.data[i]); + if (ACPI_FAILURE(status)) + device_printf(dev, + "failed to remove _OSI(\"%s\"): %s\n", + list.data[i], AcpiFormatException(status)); + else if (bootverbose) + device_printf(dev, "removed _OSI(\"%s\")\n", + list.data[i]); + } + acpi_free_interfaces(&list); + } +} + +static int acpi_pm_func(u_long cmd, void *arg, ...) { int state, acpi_state; |