Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 Oct 2010 18:59:50 +0000 (UTC)
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r214390 - head/sys/dev/acpica
Message-ID:  <201010261859.o9QIxoIS062547@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jkim
Date: Tue Oct 26 18:59:50 2010
New Revision: 214390
URL: http://svn.freebsd.org/changeset/base/214390

Log:
  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"

Modified:
  head/sys/dev/acpica/acpi.c

Modified: head/sys/dev/acpica/acpi.c
==============================================================================
--- head/sys/dev/acpica/acpi.c	Tue Oct 26 18:59:36 2010	(r214389)
+++ head/sys/dev/acpica/acpi.c	Tue Oct 26 18:59:50 2010	(r214390)
@@ -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, acp
 	      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
 }
 
 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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201010261859.o9QIxoIS062547>