From fe67e068f200d93aa1e36691783c0fe77c8c23da Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sun, 14 Sep 2014 05:18:52 +0200
Subject: [PATCH] WIP ACPI power meter

---
 sys/dev/acpica/Makefile      |   2 +-
 sys/dev/acpica/acpi_pmeter.c | 183 +++++++++++++++++++++++++++++++++++++++++++
 sys/dev/acpica/acpivar.h     |   1 +
 3 files changed, 185 insertions(+), 1 deletion(-)
 create mode 100644 sys/dev/acpica/acpi_pmeter.c

diff --git a/sys/dev/acpica/Makefile b/sys/dev/acpica/Makefile
index b2c1a3e..fea639b 100644
--- a/sys/dev/acpica/Makefile
+++ b/sys/dev/acpica/Makefile
@@ -69,7 +69,7 @@ SRCS+=	utxferror.c utxfinit.c
 #
 SRCS+=  acpi.c acpi_acad.c acpi_battery.c acpi_button.c acpi_cmbat.c
 SRCS+=	acpi_cpu.c acpi_cpu_cstate.c acpi_cpu_pstate.c acpi_smbat.c
-SRCS+=  acpi_ec.c acpi_isab.c acpi_lid.c
+SRCS+=  acpi_ec.c acpi_isab.c acpi_lid.c acpi_pmeter.c
 SRCS+=  acpi_package.c
 # The PCI part of ACPI5 doesn't work with the current infrastructure
 SRCS+=	acpi_pci.c acpi_pcib.c acpi_pcib_acpi.c acpi_pcib_pci.c
diff --git a/sys/dev/acpica/acpi_pmeter.c b/sys/dev/acpica/acpi_pmeter.c
new file mode 100644
index 0000000..c22874a
--- /dev/null
+++ b/sys/dev/acpica/acpi_pmeter.c
@@ -0,0 +1,183 @@
+/*-
+ * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_acpi.h"
+#include <sys/bus.h>
+#include <sys/module.h>
+
+#include "acpi.h"
+
+#include <dev/acpica/acpivar.h>
+
+/* Hooks for the ACPICA debugging infrastructure */
+#define _COMPONENT	ACPI_POWER_METER
+ACPI_MODULE_NAME("POWER_METER")
+
+struct	acpi_pmeter_softc {
+	int			pmeter_consumption;
+	int			pmeter_avg_interval;
+};
+
+static int	acpi_pmeter_probe(device_t);
+static int	acpi_pmeter_attach(device_t);
+
+static device_method_t acpi_pmeter_methods[] = {
+    /* Device interface */
+    DEVMETHOD(device_probe,	acpi_pmeter_probe),
+    DEVMETHOD(device_attach,	acpi_pmeter_attach),
+
+    DEVMETHOD_END
+};
+
+static driver_t acpi_pmeter_driver = {
+    "acpi_pmeter",
+    acpi_pmeter_methods,
+    sizeof(struct acpi_pmeter_softc),
+};
+
+static devclass_t acpi_pmeter_devclass;
+DRIVER_MODULE(acpi_pmeter, acpi, acpi_pmeter_driver, acpi_pmeter_devclass,
+    NULL, NULL);
+MODULE_DEPEND(acpi_pmeter, acpi, 1, 1, 1);
+
+static int
+acpi_pmeter_probe(device_t dev)
+{
+    static char *pmeter_ids[] = { "ACPI000D", NULL };
+
+    if (acpi_disabled("powermeter") ||
+	ACPI_ID_PROBE(device_get_parent(dev), dev, pmeter_ids) == NULL)
+	return (ENXIO);
+
+    device_set_desc(dev, "Power Meter");
+    return (0);
+}
+
+static int
+acpi_pmeter_attach(device_t dev)
+{
+	ACPI_BUFFER buf;
+	ACPI_HANDLE handle;
+	ACPI_STATUS status;
+	ACPI_OBJECT *obj;
+
+	handle = acpi_get_handle(dev);
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_PMC", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _PMC package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_PTP", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _PTP package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_PMM", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _PMM package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_PAI", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _PAI package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_GAI", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _GAI package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_SHL", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _SHL package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_GHL", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _GHL package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	buf.Pointer = NULL;
+	buf.Length = ACPI_ALLOCATE_BUFFER;
+	status = AcpiEvaluateObject(handle, "_PMD", NULL, &buf);
+	if (ACPI_FAILURE(status)) {
+		device_printf(dev, "can't get _PMD package - %s\n",
+		    AcpiFormatException(status));
+	} else {
+		obj = (ACPI_OBJECT *)buf.Pointer;
+		AcpiOsFree(obj);
+	}
+
+	return (0);
+}
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 5ac55bc..8a15b74 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -183,6 +183,7 @@ extern struct lock acpi_lock;
 #define	ACPI_THERMAL		0x01000000
 #define	ACPI_TIMER		0x02000000
 #define	ACPI_OEM		0x04000000
+#define	ACPI_POWER_METER	0x08000000
 
 /*
  * Constants for different interrupt models used with acpi_SetIntrModel().
-- 
1.9.3

