patch-2.4.0-test4 linux/drivers/acpi/ec.c

Next file: linux/drivers/acpi/os.c
Previous file: linux/drivers/acpi/driver.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test3/linux/drivers/acpi/ec.c linux/drivers/acpi/ec.c
@@ -0,0 +1,191 @@
+/*
+ *  ec.c - Embedded controller support
+ *
+ *  Copyright (C) 2000 Andrew Henroid
+ *
+ *  This program 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include "acpi.h"
+#include "driver.h"
+
+enum
+{
+	ACPI_EC_HID = 0x090cd041,
+};
+
+enum
+{
+        ACPI_EC_SMI = 0x40,
+        ACPI_EC_SCI = 0x20,
+        ACPI_EC_BURST = 0x10,
+        ACPI_EC_CMD = 0x08,
+        ACPI_EC_IBF = 0x02,
+        ACPI_EC_OBF = 0x01
+};
+
+enum
+{
+        ACPI_EC_READ = 0x80,
+        ACPI_EC_WRITE = 0x81,
+        ACPI_EC_BURST_ENABLE = 0x82,
+        ACPI_EC_BURST_DISABLE = 0x83,
+        ACPI_EC_QUERY = 0x84,
+};
+
+
+static int acpi_ec_data = 0;
+static int acpi_ec_status = 0;
+static DECLARE_WAIT_QUEUE_HEAD(acpi_ec_wait);
+
+/*
+ * handle GPE
+ */
+static void
+acpi_ec_gpe(void *context)
+{
+	printk(KERN_INFO "ACPI: EC GPE\n");
+	if (waitqueue_active(&acpi_ec_wait))
+		wake_up_interruptible(&acpi_ec_wait);
+}
+
+/*
+ * wait for read/write status to clear
+ */
+static void
+acpi_ec_wait_control(void)
+{
+        udelay(1);
+        while(inb(acpi_ec_status) & ACPI_EC_IBF)
+                udelay(10);
+}
+
+/*
+ * read a byte from the EC
+ */
+int
+acpi_ec_read(int addr, int *value)
+{
+	if (!acpi_ec_data || !acpi_ec_status)
+		return -1;
+
+        outb(ACPI_EC_READ, acpi_ec_status);
+        acpi_ec_wait_control();
+        outb(addr, acpi_ec_data);
+        acpi_ec_wait_control();
+        interruptible_sleep_on(&acpi_ec_wait);
+        *value = inb(acpi_ec_data);
+
+	return 0;
+}
+
+/*
+ * write a byte to the EC
+ */
+int
+acpi_ec_write(int addr, int value)
+{
+	if (!acpi_ec_data || !acpi_ec_status)
+		return -1;
+
+        outb(ACPI_EC_WRITE, acpi_ec_status);
+        acpi_ec_wait_control();
+        outb(addr, acpi_ec_data);
+        acpi_ec_wait_control();
+        outb(value, acpi_ec_data);
+        acpi_ec_wait_control();
+        interruptible_sleep_on(&acpi_ec_wait);
+
+	return 0;
+}
+
+/*
+ * Get processor information
+ */
+static ACPI_STATUS
+acpi_find_ec(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
+{
+	ACPI_BUFFER buf;
+	ACPI_OBJECT obj;
+	RESOURCE *res;
+	int gpe;
+
+	buf.length = sizeof(obj);
+	buf.pointer = &obj;
+	if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_HID", NULL, &buf))
+	    || obj.type != ACPI_TYPE_NUMBER
+	    || obj.number.value != ACPI_EC_HID)
+		return AE_OK;
+
+	buf.length = 0;
+	buf.pointer = NULL;
+	if (acpi_get_current_resources(handle, &buf) != AE_BUFFER_OVERFLOW)
+		return AE_OK;
+
+	buf.pointer = kmalloc(buf.length, GFP_KERNEL);
+	if (!buf.pointer)
+		return AE_OK;
+
+	if (!ACPI_SUCCESS(acpi_get_current_resources(handle, &buf))) {
+		kfree(buf.pointer);
+		return AE_OK;
+	}
+
+	res = (RESOURCE*) buf.pointer;
+	acpi_ec_data = (int) res->data.io.min_base_address;
+	res = (RESOURCE*)((u8*) buf.pointer + res->length);
+	acpi_ec_status = (int) res->data.io.min_base_address;
+
+	kfree(buf.pointer);
+
+	buf.length = sizeof(obj);
+	buf.pointer = &obj;
+	if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf))
+	    || obj.type != ACPI_TYPE_NUMBER)
+		return AE_OK;
+	gpe = (int) obj.number.value;
+
+	printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,%d)\n",
+	       acpi_ec_data, acpi_ec_status, gpe);
+
+	if (!ACPI_SUCCESS(acpi_install_gpe_handler(
+		gpe,
+		(ACPI_EVENT_LEVEL_TRIGGERED
+		 | ACPI_EVENT_EDGE_TRIGGERED),
+		acpi_ec_gpe,
+		NULL)))
+		return AE_OK;
+	
+	return AE_OK;
+}
+
+int
+acpi_ec_init(void)
+{
+	acpi_walk_namespace(ACPI_TYPE_DEVICE,
+			    ACPI_ROOT_OBJECT,
+			    ACPI_INT32_MAX,
+			    acpi_find_ec,
+			    NULL,
+			    NULL);
+	return 0;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)