diff -uNr linux-2.6.16/Makefile linux-2.6.16-iMac/Makefile
--- linux-2.6.16/Makefile	2006-03-21 23:01:17.000000000 +0100
+++ linux-2.6.16-iMac/Makefile	2006-03-20 08:12:47.000000000 +0100
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 16
-EXTRAVERSION =
+EXTRAVERSION = -iMac
 NAME=Sliding Snow Leopard
 
 # *DOCUMENTATION*
diff -uNr linux-2.6.16/arch/i386/kernel/dmi_scan.c linux-2.6.16-iMac/arch/i386/kernel/dmi_scan.c
--- linux-2.6.16/arch/i386/kernel/dmi_scan.c	2006-03-21 23:01:17.000000000 +0100
+++ linux-2.6.16-iMac/arch/i386/kernel/dmi_scan.c	2006-03-20 08:01:46.000000000 +0100
@@ -5,6 +5,7 @@
 #include <linux/dmi.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
+#include <linux/efi.h>
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
@@ -184,39 +185,66 @@
 	}
 }
 
-void __init dmi_scan_machine(void)
+static int __init dmi_present(char __iomem *p)
 {
 	u8 buf[15];
+	memcpy_fromio(buf, p, 15);
+	if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+		u16 num = (buf[13] << 8) | buf[12];
+		u16 len = (buf[7] << 8) | buf[6];
+		u32 base = (buf[11] << 24) | (buf[10] << 16) |
+			(buf[9] << 8) | buf[8];
+		
+		/*
+		 * DMI version 0.0 means that the real version is taken from
+		 * the SMBIOS version, which we don't know at this point.
+		 */
+		if (buf[14] != 0)
+			printk(KERN_INFO "DMI %d.%d present.\n",
+			       buf[14] >> 4, buf[14] & 0xF);
+		else
+			printk(KERN_INFO "DMI present.\n");
+		if (dmi_table(base,len, num, dmi_decode) == 0)
+			return 0;
+	}
+	
+	       return 1;
+}
+
+void __init dmi_scan_machine(void)
+{
 	char __iomem *p, *q;
+	int rc;
 
-	/*
-	 * no iounmap() for that ioremap(); it would be a no-op, but it's
-	 * so early in setup that sucker gets confused into doing what
-	 * it shouldn't if we actually call it.
-	 */
-	p = ioremap(0xF0000, 0x10000);
-	if (p == NULL)
-		goto out;
 
-	for (q = p; q < p + 0x10000; q += 16) {
-		memcpy_fromio(buf, q, 15);
-		if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
-			u16 num = (buf[13] << 8) | buf[12];
-			u16 len = (buf[7] << 8) | buf[6];
-			u32 base = (buf[11] << 24) | (buf[10] << 16) |
-				   (buf[9] << 8) | buf[8];
-
-			/*
-			 * DMI version 0.0 means that the real version is taken from
-			 * the SMBIOS version, which we don't know at this point.
-			 */
-			if (buf[14] != 0)
-				printk(KERN_INFO "DMI %d.%d present.\n",
-					buf[14] >> 4, buf[14] & 0xF);
-			else
-				printk(KERN_INFO "DMI present.\n");
+	if (efi_enabled) {
+		if (!efi.smbios)
+			goto out;
+
+		p = efi.smbios;
+
+		if (p == NULL)
+			goto out;
+
+		rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
 
-			if (dmi_table(base,len, num, dmi_decode) == 0)
+		if (!rc)
+			return;
+
+	} else {
+		
+		/*
+		 * no iounmap() for that ioremap(); it would be a no-op, but
+		 * it's so early in setup that sucker gets confused into doing
+		 * what it shouldn't if we actually call it.
+		 */
+		p = ioremap(0xF0000, 0x10000);
+		if (p == NULL)
+			goto out;
+		
+		for (q = p; q < p + 0x10000; q += 16) {
+			rc = dmi_present(q);
+			if (!rc)
 				return;
 		}
 	}
diff -uNr linux-2.6.16/arch/i386/kernel/efi.c linux-2.6.16-iMac/arch/i386/kernel/efi.c
--- linux-2.6.16/arch/i386/kernel/efi.c	2006-03-21 23:01:17.000000000 +0100
+++ linux-2.6.16-iMac/arch/i386/kernel/efi.c	2006-03-20 08:01:46.000000000 +0100
@@ -395,7 +395,7 @@
 			printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
-			efi.smbios = (void *) config_tables[i].table;
+			efi.smbios = __va(config_tables[i].table);
 			printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
 		} else
 		    if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
diff -uNr linux-2.6.16/drivers/Makefile linux-2.6.16-iMac/drivers/Makefile
--- linux-2.6.16/drivers/Makefile	2006-03-21 23:01:18.000000000 +0100
+++ linux-2.6.16-iMac/drivers/Makefile	2006-03-26 07:06:49.000000000 +0200
@@ -33,7 +33,7 @@
 obj-y				+= base/ block/ misc/ mfd/ net/ media/
 obj-$(CONFIG_NUBUS)		+= nubus/
 obj-$(CONFIG_ATM)		+= atm/
-obj-$(CONFIG_PPC_PMAC)		+= macintosh/
+obj-y				+= macintosh/
 obj-$(CONFIG_IDE)		+= ide/
 obj-$(CONFIG_FC4)		+= fc4/
 obj-$(CONFIG_SCSI)		+= scsi/
diff -uNr linux-2.6.16/drivers/acpi/Kconfig linux-2.6.16-iMac/drivers/acpi/Kconfig
--- linux-2.6.16/drivers/acpi/Kconfig	2006-03-21 23:01:18.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/Kconfig	2006-03-26 07:42:13.000000000 +0200
@@ -96,6 +96,13 @@
 	  /proc/acpi/battery. If you have a mobile system with a battery, 
 	  say Y.
 
+config ACPI_SBS
+       tristate "Smart Battery System"
+       depends on ACPI_AC && ACPI_BATTERY && I2C
+       default y
+       help
+         This driver adds support for the Smart Battery System
+
 config ACPI_BUTTON
 	tristate "Button"
 	default y
diff -uNr linux-2.6.16/drivers/acpi/Makefile linux-2.6.16-iMac/drivers/acpi/Makefile
--- linux-2.6.16/drivers/acpi/Makefile	2006-01-03 04:21:10.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/Makefile	2006-03-26 07:42:28.000000000 +0200
@@ -39,6 +39,7 @@
 obj-y				+= bus.o glue.o
 obj-$(CONFIG_ACPI_AC) 		+= ac.o
 obj-$(CONFIG_ACPI_BATTERY)	+= battery.o
+obj-$(CONFIG_ACPI_SBS)		+= i2c_acpi_ec.o acpi_sbs.o
 obj-$(CONFIG_ACPI_BUTTON)	+= button.o
 obj-$(CONFIG_ACPI_EC)		+= ec.o
 obj-$(CONFIG_ACPI_FAN)		+= fan.o
diff -uNr linux-2.6.16/drivers/acpi/ac.c linux-2.6.16-iMac/drivers/acpi/ac.c
--- linux-2.6.16/drivers/acpi/ac.c	2006-01-03 04:21:10.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/ac.c	2006-03-20 08:01:46.000000000 +0100
@@ -324,5 +324,12 @@
 	return_VOID;
 }
 
+struct proc_dir_entry *acpi_get_ac_dir(void)
+{
+	return (acpi_ac_dir);
+}
+
+EXPORT_SYMBOL(acpi_get_ac_dir);
+
 module_init(acpi_ac_init);
 module_exit(acpi_ac_exit);
diff -uNr linux-2.6.16/drivers/acpi/acpi_sbs.c linux-2.6.16-iMac/drivers/acpi/acpi_sbs.c
--- linux-2.6.16/drivers/acpi/acpi_sbs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/acpi_sbs.c	2006-03-21 23:04:03.000000000 +0100
@@ -0,0 +1,2268 @@
+/*
+ *  acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.2 $)
+ *
+ *  Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+
+#include "i2c_acpi_ec.h"
+
+extern struct proc_dir_entry *acpi_get_ac_dir(void);
+extern struct proc_dir_entry *acpi_get_battery_dir(void);
+
+#define ACPI_SBS_COMPONENT		0x00080000
+#define ACPI_SBS_CLASS			"sbs"
+#define ACPI_SBS_HID			"ACPI0002"
+#define ACPI_SBS_DRIVER_NAME		"ACPI Smart Battery System Driver"
+#define ACPI_SBS_DEVICE_NAME		"Smart Battery System"
+#define ACPI_SBS_FILE_INFO		"info"
+#define ACPI_SBS_FILE_STATE		"state"
+#define ACPI_SBS_FILE_ALARM		"alarm"
+#define ACPI_SB_DEVICE_NAME		"Smart Battery"
+#define ACPI_SBSM_DEVICE_NAME		"Smart Battery System Manager"
+#define ACPI_SBSEL_DEVICE_NAME		"Smart Battery Selector"
+#define ACPI_SBC_DEVICE_NAME		"Smart Battery Charger"
+#define ACPI_SB_DIR_NAME		"SB%d"
+#define ACPI_SBSM_DIR_NAME		"SBSM"
+#define ACPI_SBSEL_DIR_NAME		"SBSEL"
+#define ACPI_SBC_DIR_NAME		"SBC"
+#define ACPI_SBSM_CLASS			1
+#define ACPI_SBSEL_CLASS		2
+#define ACPI_LBATTERY_DIR_NAME		"BAT%d"
+#define ACPI_LADAPTER_DIR_NAME		"AC0"
+#define ACPI_SBH_SMBUS_ADDR		0x8
+#define ACPI_SBC_SMBUS_ADDR		0x9
+#define ACPI_SBSM_SMBUS_ADDR		0xa
+#define ACPI_SB_SMBUS_ADDR		0xb
+#define ACPI_SBS_TIMEOUT_DELAY		HZ/50
+
+#define _COMPONENT			ACPI_SBS_COMPONENT
+
+ACPI_MODULE_NAME("acpi_sbs")
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rich Townsend");
+MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
+
+static u16 capacity_mode = 2;
+module_param(capacity_mode, ushort, 2);
+
+static u16 mac_hack = 0;
+module_param(mac_hack, ushort, 0);
+
+static int acpi_sbs_add(struct acpi_device *device);
+static int acpi_sbs_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_sbs_driver = {
+	.name = ACPI_SBS_DRIVER_NAME,
+	.class = ACPI_SBS_CLASS,
+	.ids = ACPI_SBS_HID,
+	.ops = {
+		.add = acpi_sbs_add,
+		.remove = acpi_sbs_remove,
+		},
+};
+
+struct acpi_sb_info {
+	u8 capacity_mode;
+	u16 max_error;
+	u16 full_charge_capacity;
+	u16 charging_amperage;
+	u16 charging_voltage;
+	u16 cycle_count;
+	u16 design_capacity;
+	u16 design_voltage;
+	u8 specid;
+	u16 vscale;
+	u16 ipscale;
+	u16 manufacture_day;
+	u16 manufacture_month;
+	u16 manufacture_year;
+	u16 serial_number;
+	char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
+	char device_name[I2C_SMBUS_BLOCK_MAX + 3];
+	char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
+};
+
+struct acpi_sb_state {
+	u8 relearn_flag;
+	u16 temperature;
+	u16 voltage;
+	s16 amperage;
+	s16 average_amperage;
+	u16 relative_state_of_charge;
+	u16 absolute_state_of_charge;
+	u16 remaining_capacity;
+	u16 run_time_to_empty;
+	u16 average_time_to_empty;
+	u16 average_time_to_full;
+	u16 battery_status;
+};
+
+struct acpi_sb_alarm {
+	u16 remaining_capacity;
+	u16 remaining_time;
+};
+
+struct acpi_sb {
+	u8 id;
+	u8 init_state;
+	struct acpi_sbs *sbs;
+	struct acpi_sb_info info;
+	struct acpi_sb_state state;
+	struct acpi_sb_alarm alarm;
+	struct proc_dir_entry *sb_entry;
+	struct proc_dir_entry *lbattery_entry;
+};
+
+struct acpi_sbsm_info {
+	u8 batteries_supported;
+	u8 battery_system_revision;
+	u16 vscale;
+	u16 ipscale;
+	u8 charging_indicator;
+};
+
+struct acpi_sbsm_state {
+	u8 smb_x;
+	u8 power_by_x;
+	u8 charge_x;
+	u8 connected_x;
+	u8 present_x;
+	u8 ac_present;
+	u8 power_not_good;
+};
+
+struct acpi_sbsm {
+	u8 class;
+	struct acpi_sbs *sbs;
+	struct acpi_sbsm_info info;
+	struct acpi_sbsm_state state;
+	struct proc_dir_entry *sbsm_entry;
+};
+
+struct acpi_sbc_info {
+	u8 charger_spec;
+	u8 selector_support;
+};
+
+struct acpi_sbc_state {
+	u8 power_fail;
+	u8 battery_present;
+	u8 ac_present;
+};
+
+struct acpi_sbc {
+	struct acpi_sbs *sbs;
+	struct acpi_sbc_info info;
+	struct acpi_sbc_state state;
+	struct proc_dir_entry *sbc_entry;
+	struct proc_dir_entry *ladapter_entry;
+};
+
+struct acpi_sbs {
+	acpi_handle handle;
+	struct acpi_device *device;
+	struct acpi_ec_smbus *smbus;
+	struct acpi_sb *sb;
+	struct acpi_sbsm *sbsm;
+	struct acpi_sbc *sbc;
+	struct semaphore sem;
+};
+
+/* --------------------------------------------------------------------------
+                               SMBus Communication
+   -------------------------------------------------------------------------- */
+
+static s32
+acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, u16 addr, u8 func,
+			 u16 * word,
+			 void (*err_handler) (struct acpi_ec_smbus * smbus))
+{
+	union i2c_smbus_data data;
+	s32 result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_smbus_read_word");
+
+	result =
+	    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
+					    I2C_SMBUS_READ, func,
+					    I2C_SMBUS_WORD_DATA, &data);
+	if (result) {
+		if (err_handler)
+			err_handler(smbus);
+	} else {
+		*word = data.word;
+	}
+
+	return_VALUE(result);
+}
+
+static s32
+acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, u16 addr, u8 func,
+			char *str,
+			void (*err_handler) (struct acpi_ec_smbus * smbus))
+{
+	union i2c_smbus_data data;
+	s32 result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_smbus_read_str");
+
+	result = smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
+						 I2C_SMBUS_READ, func,
+						 I2C_SMBUS_BLOCK_DATA, &data);
+	if (result) {
+		if (err_handler)
+			err_handler(smbus);
+	} else {
+		strncpy(str, (const char *)data.block + 1, data.block[0]);
+		str[data.block[0]] = 0;
+	}
+
+	return_VALUE(result);
+}
+
+static void acpi_sb_smbus_err_handler(struct acpi_ec_smbus *smbus)
+{
+	union i2c_smbus_data data;
+	s32 result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_smbus_err_handler");
+
+	result =
+	    smbus->adapter.algo->smbus_xfer(&smbus->adapter, ACPI_SB_SMBUS_ADDR,
+					    0, I2C_SMBUS_READ, 0x16,
+					    I2C_SMBUS_BLOCK_DATA, &data);
+
+	switch (data.word & 0x000f) {
+	case 0x0000:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "unexpected bus error\n"));
+		break;
+	case 0x0001:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "busy\n"));
+		break;
+	case 0x0002:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "reserved command\n"));
+		break;
+	case 0x0003:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "unsupported command\n"));
+		break;
+	case 0x0004:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "access denied\n"));
+		break;
+	case 0x0005:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "overflow/underflow\n"));
+		break;
+	case 0x0006:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "bad size\n"));
+		break;
+	case 0x0007:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "unknown error\n"));
+		break;
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "unrecognized error\n"));
+	}
+}
+
+static s32
+acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, u16 addr, u8 func,
+			  u16 word,
+			  void (*err_handler) (struct acpi_ec_smbus * smbus))
+{
+	union i2c_smbus_data data;
+	s32 result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_smbus_write_word");
+
+	data.word = word;
+
+	result =
+	    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
+					    I2C_SMBUS_WRITE, func,
+					    I2C_SMBUS_WORD_DATA, &data);
+	if (result)
+		if (err_handler)
+			err_handler(smbus);
+
+	return_VALUE(result);
+}
+
+/* --------------------------------------------------------------------------
+                            Smart Battery System Management
+   -------------------------------------------------------------------------- */
+
+/* Smart Battery */
+
+static int acpi_sb_is_present(struct acpi_sb *sb)
+{
+	u16 battery_system_state;
+	int result;
+	int is_present;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_is_sb_present");
+
+	if (sb->sbs->sbsm) {
+		result = acpi_sbs_smbus_read_word(sb->sbs->smbus,
+						  ACPI_SBSM_SMBUS_ADDR, 0x01,
+						  &battery_system_state, NULL);
+		if (!result) {
+			is_present =
+			    (battery_system_state & 0x000f) & (1 << sb->id);
+		}
+		else
+			is_present = 0;
+	} else {
+		is_present = 0;
+	}
+
+	return_VALUE(is_present);
+}
+
+static int acpi_sb_select(struct acpi_sb *sb)
+{
+	struct acpi_ec_smbus *smbus = sb->sbs->smbus;
+	int result = 0;
+	u16 battery_system_state;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_select");
+
+	if (sb->sbs->sbsm) {
+
+		/* Take special care not to knobble other nibbles of
+		 * battery_system_state (aka selector_state), since
+		 * it causes charging to halt on SBSELs */
+
+		result =
+		    acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
+					     &battery_system_state, NULL);
+		if (result)
+			goto end;
+
+		result =
+		    acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
+					      (battery_system_state & 0x0fff) |
+					      (1 << (sb->id + 12)), NULL);
+	}
+
+      end:
+	if(mac_hack)
+		result = 0;
+	return_VALUE(result);
+}
+
+static int acpi_sb_get_info(struct acpi_sb *sb)
+{
+	struct acpi_ec_smbus *smbus = sb->sbs->smbus;
+	int result = 0;
+	u16 battery_mode;
+	u16 specification_info;
+	u16 manufacture_date;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_get_info");
+
+	if ((result = acpi_sb_select(sb)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
+					       &battery_mode,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+	sb->info.capacity_mode = (battery_mode & 0x8000) >> 15;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0c,
+					       &sb->info.max_error,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
+					       &sb->info.full_charge_capacity,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x14,
+					       &sb->info.charging_amperage,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x15,
+					       &sb->info.charging_voltage,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x17,
+					       &sb->info.cycle_count,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
+					       &sb->info.design_capacity,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
+					       &sb->info.design_voltage,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
+					       &specification_info,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	sb->info.specid = specification_info & 0x00ff;
+
+	switch ((specification_info & 0x0f00) >> 8) {
+	case 1:
+		sb->info.vscale = 10;
+		break;
+	case 2:
+		sb->info.vscale = 100;
+		break;
+	case 3:
+		sb->info.vscale = 1000;
+		break;
+	default:
+		sb->info.vscale = 1;
+	}
+
+	switch ((specification_info & 0xf000) >> 12) {
+	case 1:
+		sb->info.ipscale = 10;
+		break;
+	case 2:
+		sb->info.ipscale = 100;
+		break;
+	case 3:
+		sb->info.ipscale = 1000;
+		break;
+	default:
+		sb->info.ipscale = 1;
+	}
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1b,
+					       &manufacture_date,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	sb->info.manufacture_day = manufacture_date & 0x001f;
+	sb->info.manufacture_month = (manufacture_date & 0x01e0) >> 5;
+	sb->info.manufacture_year = ((manufacture_date & 0xfe00) >> 9) + 1980;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
+					       &sb->info.serial_number,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
+					      sb->info.manufacturer_name,
+					      &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
+					      sb->info.device_name,
+					      &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
+					      sb->info.device_chemistry,
+					      &acpi_sb_smbus_err_handler)))
+		goto end;
+
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sb_get_state(struct acpi_sb *sb)
+{
+	struct acpi_ec_smbus *smbus = sb->sbs->smbus;
+	int result = 0;
+	u16 battery_mode;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_get_state");
+
+	if ((result = acpi_sb_select(sb)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
+					       &battery_mode,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+	sb->state.relearn_flag = (battery_mode & 0x0080) >> 7;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x08,
+					       &sb->state.temperature,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
+					       &sb->state.voltage,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
+					       &sb->state.amperage,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0b,
+					       &sb->state.average_amperage,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0d,
+					       &sb->state.
+					       relative_state_of_charge,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0e,
+					       &sb->state.
+					       absolute_state_of_charge,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
+					       &sb->state.remaining_capacity,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x11,
+					       &sb->state.run_time_to_empty,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
+					       &sb->state.average_time_to_empty,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
+					       &sb->state.average_time_to_full,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
+					       &sb->state.battery_status,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sb_get_alarm(struct acpi_sb *sb)
+{
+	struct acpi_ec_smbus *smbus = sb->sbs->smbus;
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_get_alarm");
+
+	if ((result = acpi_sb_select(sb)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
+					       &sb->alarm.remaining_capacity,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x02,
+					       &sb->alarm.remaining_time,
+					       &acpi_sb_smbus_err_handler)))
+		goto end;
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sb_set_alarm(struct acpi_sb *sb)
+{
+	struct acpi_ec_smbus *smbus = sb->sbs->smbus;
+	int result = 0;
+	u16 battery_mode;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_set_alarm");
+
+	if ((result = acpi_sb_select(sb)))
+		goto end;
+
+	/* If necessary, enable the alarm */
+
+	if (sb->alarm.remaining_capacity > 0 || sb->alarm.remaining_time > 0) {
+		if ((result =
+		     acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
+					      &battery_mode,
+					      &acpi_sb_smbus_err_handler)))
+			goto end;
+		if ((result =
+		     acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
+					       battery_mode & 0xbfff,
+					       &acpi_sb_smbus_err_handler)))
+			goto end;
+	}
+
+	if ((result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
+						sb->alarm.remaining_capacity /
+						(sb->info.
+						 capacity_mode ? 10 : 1),
+						&acpi_sb_smbus_err_handler)))
+		goto end;
+
+	if ((result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x02,
+						sb->alarm.remaining_time,
+						&acpi_sb_smbus_err_handler)))
+		goto end;
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sb_init(struct acpi_sb *sb)
+{
+	int result = 0;
+	u16 battery_mode;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_init");
+
+	if (capacity_mode) {
+		result = acpi_sbs_smbus_read_word(sb->sbs->smbus,
+						  ACPI_SB_SMBUS_ADDR, 0x03,
+						  &battery_mode, NULL);
+		if (!result) {
+			if (capacity_mode == 1) {
+				battery_mode &= 0x7fff;
+			} else {
+				battery_mode |= 0x8000;
+			}
+			result =
+			    acpi_sbs_smbus_write_word(sb->sbs->smbus,
+						      ACPI_SB_SMBUS_ADDR,
+						      0x03, battery_mode, NULL);
+			if (result) {
+				printk(KERN_ALERT PREFIX
+				       "SBS: problem setting capacity_mode\n");
+				goto end;
+			}
+		} else {
+			printk(KERN_ALERT PREFIX
+			       "SBS: problem setting capacity_mode\n");
+			goto end;
+		}
+	}
+
+
+	result = acpi_sb_get_info(sb);
+	if (result) {
+		goto end;
+	}
+
+	result = acpi_sb_get_state(sb);
+	if (result) {
+		goto end;
+	}
+
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sb_check_init_state(struct acpi_sb *sb)
+{
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_check_init_state");
+
+	if (!sb->init_state) {
+		result = acpi_sb_init(sb);
+		if (result) {
+			goto end;
+		}
+		sb->init_state = 1;
+	}
+      end:
+	return_VALUE(result);
+}
+
+/* Smart Battery System Manager / Smart Battery Selector */
+
+static int acpi_sbsm_get_info(struct acpi_sbsm *sbsm)
+{
+	struct acpi_ec_smbus *smbus = sbsm->sbs->smbus;
+	int result = 0;
+	u16 battery_system_info;
+
+	ACPI_FUNCTION_TRACE("acpi_sbsm_get_info");
+
+	if ((result =
+	     acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
+				      &battery_system_info, NULL)))
+		goto end;
+
+	sbsm->info.batteries_supported = battery_system_info & 0x000f;
+	sbsm->info.battery_system_revision =
+	    (battery_system_info & 0x00f0) >> 4;
+
+	if (sbsm->class == ACPI_SBSM_CLASS) {
+		switch ((battery_system_info & 0x0f00) >> 8) {
+		case 1:
+			sbsm->info.vscale = 10;
+			break;
+		case 2:
+			sbsm->info.vscale = 100;
+			break;
+		case 3:
+			sbsm->info.vscale = 1000;
+			break;
+		default:
+			sbsm->info.vscale = 1;
+		}
+
+		switch ((battery_system_info & 0xf000) >> 12) {
+		case 1:
+			sbsm->info.ipscale = 10;
+			break;
+		case 2:
+			sbsm->info.ipscale = 100;
+			break;
+		case 3:
+			sbsm->info.ipscale = 1000;
+			break;
+		default:
+			sbsm->info.ipscale = 1;
+		}
+
+		sbsm->info.charging_indicator = 0;
+	} else {
+		sbsm->info.vscale = 1;
+		sbsm->info.ipscale = 1;
+
+		sbsm->info.charging_indicator =
+		    (battery_system_info & 0x0100) >> 8;
+	}
+
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sbsm_get_state(struct acpi_sbsm *sbsm)
+{
+	struct acpi_ec_smbus *smbus = sbsm->sbs->smbus;
+	int result = 0;
+	u16 battery_system_state;
+
+	ACPI_FUNCTION_TRACE("acpi_sbsm_get_state");
+
+	if ((result =
+	     acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
+				      &battery_system_state, NULL)))
+		goto end;
+
+	if (sbsm->class == ACPI_SBSM_CLASS) {
+		sbsm->state.smb_x = (battery_system_state & 0xf000) >> 12;
+		sbsm->state.power_by_x = (battery_system_state & 0x0f00) >> 8;
+		sbsm->state.charge_x = (battery_system_state & 0x00f0) >> 4;
+		sbsm->state.connected_x = sbsm->state.charge_x;
+		sbsm->state.present_x = battery_system_state & 0x000f;
+
+		if ((result =
+		     acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x02,
+					      &battery_system_state, NULL)))
+			goto end;
+
+		sbsm->state.ac_present = battery_system_state & 0x0001;
+		sbsm->state.power_not_good = battery_system_state & 0x0002;
+	} else {
+		sbsm->state.smb_x = (battery_system_state & 0xf000) >> 12;
+		sbsm->state.power_by_x = (battery_system_state & 0x0f00) >> 8;
+		sbsm->state.connected_x = (battery_system_state & 0x00f0) >> 4;
+		sbsm->state.present_x = battery_system_state & 0x000f;
+		if (sbsm->state.power_by_x == 0xf) {
+			sbsm->state.power_by_x = 0x0;
+			sbsm->state.connected_x = ~sbsm->state.connected_x;
+			sbsm->state.charge_x = sbsm->state.connected_x;
+			sbsm->state.ac_present = 1;
+		} else if (sbsm->state.power_by_x == 0x0) {
+			sbsm->state.charge_x = 0x0;
+			sbsm->state.ac_present = 1;
+		} else {
+			sbsm->state.charge_x = 0x0;
+			sbsm->state.ac_present = 0;
+		}
+		sbsm->state.power_not_good = 0;
+	}
+
+      end:
+	return_VALUE(result);
+}
+
+/* Smart Battery Charger */
+
+static int acpi_sbc_get_info(struct acpi_sbc *sbc)
+{
+	struct acpi_ec_smbus *smbus = sbc->sbs->smbus;
+	int result = 0;
+	u16 charger_spec_info;
+
+	ACPI_FUNCTION_TRACE("acpi_sbc_get_info");
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x11,
+					       &charger_spec_info, NULL)))
+		goto end;
+
+	sbc->info.charger_spec = charger_spec_info & 0x000f;
+	sbc->info.selector_support = (charger_spec_info & 0x0010) >> 4;
+
+      end:
+	return_VALUE(result);
+}
+
+static int acpi_sbc_get_state(struct acpi_sbc *sbc)
+{
+	struct acpi_ec_smbus *smbus = sbc->sbs->smbus;
+	int result = 0;
+	u16 charger_status;
+
+	ACPI_FUNCTION_TRACE("acpi_sbc_get_state");
+
+	if ((result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
+					       &charger_status, NULL)))
+		goto end;
+
+	sbc->state.power_fail = (charger_status & 0x2000) >> 13;
+	sbc->state.battery_present = (charger_status & 0x4000) >> 14;
+	sbc->state.ac_present = (charger_status & 0x8000) >> 15;
+
+      end:
+	return_VALUE(result);
+}
+
+/* --------------------------------------------------------------------------
+                              FS Interface (/proc)
+   -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_sbs_dir;
+
+/* Generic Routines */
+
+static int
+acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
+			struct proc_dir_entry *parent_dir,
+			char *dir_name,
+			struct file_operations *info_fops,
+			struct file_operations *state_fops,
+			struct file_operations *alarm_fops, void *data)
+{
+	struct proc_dir_entry *entry = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_generic_add_fs");
+
+	if (!*dir) {
+		*dir = proc_mkdir(dir_name, parent_dir);
+		if (!*dir)
+			return_VALUE(-ENODEV);
+		(*dir)->owner = THIS_MODULE;
+	}
+
+	/* 'info' [R] */
+	if (info_fops) {
+		entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
+		if (!entry)
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					  "Unable to create '%s' fs entry\n",
+					  ACPI_SBS_FILE_INFO));
+		else {
+			entry->proc_fops = info_fops;
+			entry->data = data;
+			entry->owner = THIS_MODULE;
+		}
+	}
+
+	/* 'state' [R] */
+	if (state_fops) {
+		entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
+		if (!entry)
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					  "Unable to create '%s' fs entry\n",
+					  ACPI_SBS_FILE_STATE));
+		else {
+			entry->proc_fops = state_fops;
+			entry->data = data;
+			entry->owner = THIS_MODULE;
+		}
+	}
+
+	/* 'alarm' [R/W] */
+	if (alarm_fops) {
+		entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IFREG | S_IRUGO | S_IWUSR, *dir);
+		if (!entry)
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+					  "Unable to create '%s' fs entry\n",
+					  ACPI_SBS_FILE_ALARM));
+		else {
+			entry->proc_fops = alarm_fops;
+			entry->data = data;
+			entry->owner = THIS_MODULE;
+		}
+	}
+
+	return_VALUE(0);
+}
+
+static void
+acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,
+			   struct proc_dir_entry *parent_dir)
+{
+	ACPI_FUNCTION_TRACE("acpi_sbs_generic_remove_fs");
+	
+	if (*dir) {
+		remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
+		remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
+		remove_proc_entry(ACPI_SBS_FILE_ALARM, *dir);
+		remove_proc_entry((*dir)->name, parent_dir);
+		*dir = NULL;
+	}
+
+}
+
+/* Smart Battery Interface */
+
+static int acpi_sb_read_info(struct seq_file *seq, void *offset)
+{
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	u32 cscale;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_read_info");
+
+	down(&sb->sbs->sem);
+
+	if (acpi_sb_is_present(sb)) {
+		seq_printf(seq, "present:                 yes\n");
+	} else {
+		seq_printf(seq, "present:                 no\n");
+		goto end;
+	}
+
+	if (sb->info.capacity_mode)
+		cscale = sb->info.vscale * sb->info.ipscale;
+	else
+		cscale = sb->info.ipscale;
+
+	seq_printf(seq, "design voltage:          %d mV\n",
+		   sb->info.design_voltage * sb->info.vscale);
+
+	seq_printf(seq, "design capacity:         %d%s",
+		   sb->info.design_capacity * cscale,
+		   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+	seq_printf(seq, "full charge capacity:    %d%s",
+		   sb->info.full_charge_capacity * cscale,
+		   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+	seq_printf(seq, "cycle count:             %d\n", sb->info.cycle_count);
+
+	seq_printf(seq, "charge reporting error:  %d%%\n", sb->info.max_error);
+
+	seq_printf(seq, "SB specification:        ");
+	switch (sb->info.specid) {
+	case 0x10:
+		seq_printf(seq, "v1.0\n");
+		break;
+	case 0x21:
+		seq_printf(seq, "v1.1 (without PEC)\n");
+		break;
+	case 0x31:
+		seq_printf(seq, "v1.1 (with PEC)\n");
+		break;
+	default:
+		seq_printf(seq, "unknown\n");
+	}
+
+	seq_printf(seq, "manufacturer name:       %s\n",
+		   sb->info.manufacturer_name);
+
+	seq_printf(seq, "manufacture date:        %4d-%2d-%2d\n",
+		   sb->info.manufacture_year,
+		   sb->info.manufacture_month, sb->info.manufacture_day);
+
+	seq_printf(seq, "serial number:           %d\n",
+		   sb->info.serial_number);
+
+	seq_printf(seq, "device name:             %s\n", sb->info.device_name);
+
+	seq_printf(seq, "device chemistry:        %s\n",
+		   sb->info.device_chemistry);
+
+      end:
+	up(&sb->sbs->sem);
+
+	return_VALUE(0);
+}
+
+static int acpi_sb_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sb_read_info, PDE(inode)->data);
+}
+
+static int acpi_sb_read_state(struct seq_file *seq, void *offset)
+{
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	int result = 0;
+	u32 cscale;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_read_state");
+
+	down(&sb->sbs->sem);
+
+	if (acpi_sb_is_present(sb)) {
+		seq_printf(seq, "present:                 yes\n");
+	} else {
+		seq_printf(seq, "present:                 no\n");
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+	result = acpi_sb_get_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery state\n");
+		goto end;
+	}
+
+	if (sb->info.capacity_mode)
+		cscale = sb->info.vscale * sb->info.ipscale;
+	else
+		cscale = sb->info.ipscale;
+
+	if (sb->state.amperage < 0) {
+		seq_printf(seq, "charging state:          discharging\n");
+		seq_printf(seq, "current:                 %d mA\n",
+			   -sb->state.amperage * sb->info.ipscale);
+	} else if (sb->state.amperage > 0) {
+		seq_printf(seq, "charging state:          charging\n");
+		seq_printf(seq, "current:                 %d mA\n",
+			   sb->state.amperage * sb->info.ipscale);
+	} else {
+		seq_printf(seq, "charging state:          charged\n");
+		seq_printf(seq, "current:                 0 mA\n");
+	}
+
+	seq_printf(seq, "average current          %d mA\n",
+		   abs(sb->state.average_amperage * sb->info.ipscale));
+
+	seq_printf(seq, "voltage:                 %d mV\n",
+		   sb->state.voltage * sb->info.vscale);
+
+	seq_printf(seq, "temperature:             %d.%d C\n",
+		   sb->state.temperature / 10 - 273,
+		   sb->state.temperature % 10 + 1);
+
+	seq_printf(seq, "relative charge:         %d%%\n",
+		   sb->state.relative_state_of_charge);
+
+	seq_printf(seq, "absolute charge:         %d%%\n",
+		   sb->state.absolute_state_of_charge);
+
+	seq_printf(seq, "remaining capacity:      %d%s",
+		   sb->state.remaining_capacity * cscale,
+		   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+	if (sb->state.run_time_to_empty == 65535)
+		seq_printf(seq, "run time to empty:       n/a\n");
+	else
+		seq_printf(seq, "run time to empty:       %dh %02dm\n",
+			   sb->state.run_time_to_empty / 60,
+			   sb->state.run_time_to_empty % 60);
+
+	if (sb->state.average_time_to_empty == 65535)
+		seq_printf(seq, "average time to empty:   n/a\n");
+	else
+		seq_printf(seq, "average time to empty:   %dh %02dm\n",
+			   sb->state.average_time_to_empty / 60,
+			   sb->state.average_time_to_empty % 60);
+
+	if (sb->state.average_time_to_full == 65535)
+		seq_printf(seq, "average time to full:    n/a\n");
+	else
+		seq_printf(seq, "average time to full:    %dh %02dm\n",
+			   sb->state.average_time_to_full / 60,
+			   sb->state.average_time_to_full % 60);
+
+      end:
+	up(&sb->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static int acpi_sb_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sb_read_state, PDE(inode)->data);
+}
+
+static int acpi_sb_read_alarm(struct seq_file *seq, void *offset)
+{
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	int result = 0;
+	u32 cscale;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_read_alarm");
+
+	down(&sb->sbs->sem);
+
+	if (acpi_sb_is_present(sb)) {
+		seq_printf(seq, "present:                 yes\n");
+	} else {
+		seq_printf(seq, "present:                 no\n");
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+
+	result = acpi_sb_get_alarm(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+		goto end;
+	}
+
+	if (sb->info.capacity_mode)
+		cscale = sb->info.vscale * sb->info.ipscale;
+	else
+		cscale = sb->info.ipscale;
+
+	seq_printf(seq, "remain capacity alarm:   ");
+	if (sb->alarm.remaining_capacity)
+		seq_printf(seq, "%d%s",
+			   sb->alarm.remaining_capacity * cscale,
+			   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+	else
+		seq_printf(seq, "disabled\n");
+
+	seq_printf(seq, "remain time alarm:       ");
+	if (sb->alarm.remaining_time)
+		seq_printf(seq, "%dh %02dm\n",
+			   sb->alarm.remaining_time / 60,
+			   sb->alarm.remaining_time % 60);
+	else
+		seq_printf(seq, "disabled\n");
+
+      end:
+	up(&sb->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static ssize_t
+acpi_sb_write_alarm(struct file *file, const char __user * buffer,
+		    size_t count, loff_t * ppos)
+{
+	struct seq_file *seq = (struct seq_file *)file->private_data;
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	char alarm_string[16] = { '\0' };
+	int alarm_values[3];
+	char *term;
+	int result;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_write_alarm");
+
+	down(&sb->sbs->sem);
+
+	if (!acpi_sb_is_present(sb)) {
+		result = -ENODEV;
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+
+	if (count > sizeof(alarm_string) - 1) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	if (copy_from_user(alarm_string, buffer, count)) {
+		result = -EFAULT;
+		goto end;
+	}
+
+	alarm_string[count] = 0;
+	term = get_options(alarm_string, 3, alarm_values);
+
+	if (alarm_values[0] > 0) {
+		if (alarm_values[1] >= 0 && alarm_values[1] <= 65535) {
+			sb->alarm.remaining_capacity = alarm_values[1];
+		} else {
+			result = -EINVAL;
+			goto end;
+		}
+	}
+
+	if (alarm_values[0] > 1) {
+		if (alarm_values[2] >= 0 && alarm_values[2] <= 65535) {
+			sb->alarm.remaining_time = alarm_values[2];
+		} else {
+			result = -EINVAL;
+			goto end;
+		}
+	}
+
+	result = acpi_sb_set_alarm(sb);
+
+      end:
+	up(&sb->sbs->sem);
+
+	if (result)
+		return_VALUE(result);
+	else
+		return_VALUE(count);
+}
+
+static int acpi_sb_alarm_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sb_read_alarm, PDE(inode)->data);
+}
+
+static struct file_operations acpi_sb_info_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sb_info_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct file_operations acpi_sb_state_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sb_state_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct file_operations acpi_sb_alarm_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sb_alarm_open_fs,
+	.read = seq_read,
+	.write = acpi_sb_write_alarm,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/* Smart Battery System Manager / Smart Battery Selector Interface */
+
+static int acpi_sbsm_read_info(struct seq_file *seq, void *offset)
+{
+	struct acpi_sbsm *sbsm = (struct acpi_sbsm *)seq->private;
+	u8 id;
+
+	ACPI_FUNCTION_TRACE("acpi_sbsm_read_info");
+
+	down(&sbsm->sbs->sem);
+
+	seq_printf(seq, "batteries supported:    ");
+	for (id = 0; id <= 3; id++) {
+		if (sbsm->info.batteries_supported & (1 << id))
+			seq_printf(seq, " " ACPI_SB_DIR_NAME, id);
+	}
+	seq_printf(seq, "\n");
+
+	if (sbsm->class == ACPI_SBSM_CLASS) {
+		seq_printf(seq, "SBSM specification:      ");
+
+		switch (sbsm->info.battery_system_revision) {
+		case 0x0008:
+			seq_printf(seq, "v1.0 (without PEC)\n");
+			break;
+		case 0x0009:
+			seq_printf(seq, "v1.0 (with PEC)\n");
+			break;
+		default:
+			seq_printf(seq, "unknown\n");
+		}
+	} else {
+		seq_printf(seq, "SBSEL specification:     ");
+
+		switch (sbsm->info.battery_system_revision) {
+		case 0x0001:
+			seq_printf(seq, "v1.0\n");
+			break;
+		case 0x0002:
+			seq_printf(seq, "v1.1 (without PEC)\n");
+			break;
+		case 0x0003:
+			seq_printf(seq, "v1.1 (with PEC)\n");
+			break;
+		default:
+			seq_printf(seq, "unknown\n");
+		}
+	}
+
+	up(&sbsm->sbs->sem);
+
+	return_VALUE(0);
+}
+
+static int acpi_sbsm_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sbsm_read_info, PDE(inode)->data);
+}
+
+static int acpi_sbsm_read_state(struct seq_file *seq, void *offset)
+{
+	struct acpi_sbsm *sbsm = (struct acpi_sbsm *)seq->private;
+	int result = 0;
+	u8 id;
+
+	ACPI_FUNCTION_TRACE("acpi_sbsm_read_state");
+
+	down(&sbsm->sbs->sem);
+
+	result = acpi_sbsm_get_state(sbsm);
+
+	if (result) {
+		seq_printf(seq,
+			   "ERROR: Unable to read battery system manager / selector state\n");
+		goto end;
+	}
+
+	if (sbsm->class == ACPI_SBSEL_CLASS) {
+		result = acpi_sbsm_get_state(sbsm);
+		if (result) {
+			seq_printf(seq,
+				   "ERROR: Unable to read charger state\n");
+			goto end;
+		}
+	}
+
+	seq_printf(seq, "batteries present:      ");
+	if (!sbsm->state.present_x) {
+		seq_printf(seq, " none");
+	} else {
+		for (id = 0; id <= 3; id++) {
+			if (sbsm->state.present_x & (1 << id))
+				seq_printf(seq, " " ACPI_SB_DIR_NAME, id);
+		}
+	}
+	seq_printf(seq, "\n");
+
+	seq_printf(seq, "batteries charging:     ");
+	if (sbsm->class == ACPI_SBSEL_CLASS && !sbsm->info.charging_indicator) {
+		if (sbsm->sbs->sbc->state.battery_present)
+			seq_printf(seq, " yes\n");
+		else
+			seq_printf(seq, " no\n");
+	} else {
+		if (!sbsm->state.charge_x) {
+			seq_printf(seq, " none");
+		} else {
+			for (id = 0; id <= 3; id++) {
+				if (sbsm->state.charge_x & (1 << id))
+					seq_printf(seq, " " ACPI_SB_DIR_NAME,
+						   id);
+			}
+		}
+		seq_printf(seq, "\n");
+	}
+
+	if (sbsm->state.ac_present) {
+		seq_printf(seq, "system powered by:       AC\n");
+	} else {
+		seq_printf(seq, "system powered by:      ");
+		for (id = 0; id <= 3; id++) {
+			if (sbsm->state.power_by_x & (1 << id))
+				seq_printf(seq, " " ACPI_SB_DIR_NAME, id);
+		}
+		seq_printf(seq, "\n");
+	}
+
+	if (sbsm->state.ac_present) {
+		if (sbsm->class == ACPI_SBSM_CLASS)
+			seq_printf(seq, "AC sufficient:           %s\n",
+				   sbsm->state.power_not_good ? "no" : "yes");
+		else
+			seq_printf(seq, "AC sufficient:           %s\n",
+				   sbsm->sbs->sbc->state.
+				   power_fail ? "no" : "yes");
+	} else {
+		seq_printf(seq, "AC sufficient:           n/a\n");
+	}
+
+      end:
+	up(&sbsm->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static int acpi_sbsm_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sbsm_read_state, PDE(inode)->data);
+}
+
+static struct file_operations acpi_sbsm_info_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sbsm_info_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct file_operations acpi_sbsm_state_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sbsm_state_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/* Smart Battery Charger Interface */
+
+static int acpi_sbc_read_info(struct seq_file *seq, void *offset)
+{
+	struct acpi_sbc *sbc = (struct acpi_sbc *)seq->private;
+
+	ACPI_FUNCTION_TRACE("acpi_sbc_read_info");
+
+	down(&sbc->sbs->sem);
+
+	seq_printf(seq, "SBC specification:       ");
+
+	switch (sbc->info.charger_spec) {
+	case 0x0001:
+		seq_printf(seq, "v1.0\n");
+		break;
+	case 0x0002:
+		seq_printf(seq, "v1.1 (without PEC)\n");
+		break;
+	case 0x0003:
+		seq_printf(seq, "v1.1 (with PEC)\n");
+		break;
+	default:
+		seq_printf(seq, "unknown\n");
+	}
+
+	seq_printf(seq, "Embedded SBSEL support:  %s\n",
+		   sbc->info.selector_support ? "yes" : "no");
+
+	up(&sbc->sbs->sem);
+
+	return_VALUE(0);
+}
+
+static int acpi_sbc_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sbc_read_info, PDE(inode)->data);
+}
+
+static int acpi_sbc_read_state(struct seq_file *seq, void *offset)
+{
+	struct acpi_sbc *sbc = (struct acpi_sbc *)seq->private;
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sbc_read_state");
+
+	down(&sbc->sbs->sem);
+
+	result = acpi_sbc_get_state(sbc);
+
+	if (result) {
+		seq_printf(seq,
+			   "ERROR: Unable to read battery charger state\n");
+		goto end;
+	}
+
+	seq_printf(seq, "battery charging:        %s\n",
+		   sbc->state.battery_present ? "yes" : "no");
+
+	seq_printf(seq, "system powered by:       %s\n",
+		   sbc->state.ac_present ? "AC" : "battery");
+
+	if (sbc->state.ac_present)
+		seq_printf(seq, "AC sufficient:           %s\n",
+			   sbc->state.power_fail ? "no" : "yes");
+	else
+		seq_printf(seq, "AC sufficient:           n/a\n");
+
+      end:
+	up(&sbc->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static int acpi_sbc_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_sbc_read_state, PDE(inode)->data);
+}
+
+static struct file_operations acpi_sbc_info_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sbc_info_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct file_operations acpi_sbc_state_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_sbc_state_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/* Legacy Battery Interface */
+
+static struct proc_dir_entry *acpi_lbattery_dir = NULL;
+
+static int acpi_lbattery_read_info(struct seq_file *seq, void *offset)
+{
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	u32 cscale;
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_lbattery_read_info");
+
+	down(&sb->sbs->sem);
+
+	if (acpi_sb_is_present(sb)) {
+		seq_printf(seq, "present:                 yes\n");
+	} else {
+		seq_printf(seq, "present:                 no\n");
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+
+	if (sb->info.capacity_mode)
+		cscale = sb->info.vscale * sb->info.ipscale;
+	else
+		cscale = sb->info.ipscale;
+
+	seq_printf(seq, "design capacity:         %d%s",
+		   sb->info.design_capacity * cscale,
+		   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+	seq_printf(seq, "last full capacity:      %d%s",
+		   sb->info.full_charge_capacity * cscale,
+		   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+	seq_printf(seq, "battery technology:      rechargeable\n");
+
+	seq_printf(seq, "design voltage:          %d mV\n",
+		   sb->info.design_voltage * sb->info.vscale);
+
+	seq_printf(seq, "design capacity warning: unknown\n");
+	seq_printf(seq, "design capacity low:     unknown\n");
+	seq_printf(seq, "capacity granularity 1:  unknown\n");
+	seq_printf(seq, "capacity granularity 2:  unknown\n");
+
+	seq_printf(seq, "model number:            %s\n", sb->info.device_name);
+
+	seq_printf(seq, "serial number:           %d\n",
+		   sb->info.serial_number);
+
+	seq_printf(seq, "battery type:            %s\n",
+		   sb->info.device_chemistry);
+
+	seq_printf(seq, "OEM info:                %s\n",
+		   sb->info.manufacturer_name);
+
+      end:
+	up(&sb->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static int acpi_lbattery_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_lbattery_read_info, PDE(inode)->data);
+}
+
+static int acpi_lbattery_read_state(struct seq_file *seq, void *offset)
+{
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	int result = 0;
+	u32 cscale;
+
+	ACPI_FUNCTION_TRACE("acpi_lbattery_read_state");
+
+	down(&sb->sbs->sem);
+
+	if (acpi_sb_is_present(sb)) {
+		seq_printf(seq, "present:                 yes\n");
+	} else {
+		seq_printf(seq, "present:                 no\n");
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+
+	result = acpi_sb_get_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery state\n");
+		goto end;
+	}
+
+	if (sb->info.capacity_mode)
+		cscale = sb->info.vscale * sb->info.ipscale;
+	else
+		cscale = sb->info.ipscale;
+
+	if (sb->state.battery_status & 0x0010)
+		seq_printf(seq, "capacity state:          critical\n");
+	else
+		seq_printf(seq, "capacity state:          ok\n");
+
+	if ((s16) sb->state.amperage < 0) {
+		seq_printf(seq, "charging state:          discharging\n");
+		if (sb->state.average_time_to_empty)
+			seq_printf(seq, "present rate:            %d%s\n",
+				   sb->state.remaining_capacity * cscale * 60 /
+				   sb->state.average_time_to_empty,
+				   sb->info.capacity_mode ? "0 mW" : " mA");
+		else
+			seq_printf(seq, "present rate:            n/a\n");
+	} else if ((s16) sb->state.amperage > 0) {
+		seq_printf(seq, "charging state:          charging\n");
+		if (sb->state.average_time_to_full)
+			seq_printf(seq, "present rate:            %d%s\n",
+				   (sb->info.full_charge_capacity -
+				    sb->state.remaining_capacity) * cscale * 60 /
+				   sb->state.average_time_to_full,
+				   sb->info.capacity_mode ? "0 mW" : " mA");
+		else
+			seq_printf(seq, "present rate:            n/a\n");
+	} else {
+		seq_printf(seq, "charging state:          charged\n");
+		seq_printf(seq, "present rate:            0 %s\n",
+			   sb->info.capacity_mode ? "mW" : "mA");
+	}
+
+	seq_printf(seq, "remaining capacity:      %d%s",
+		   sb->state.remaining_capacity * cscale,
+		   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+	seq_printf(seq, "present voltage:         %d mV\n",
+		   sb->state.voltage * sb->info.vscale);
+
+      end:
+	up(&sb->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static int acpi_lbattery_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_lbattery_read_state, PDE(inode)->data);
+}
+
+static int acpi_lbattery_read_alarm(struct seq_file *seq, void *offset)
+{
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	int result = 0;
+	u32 cscale;
+
+	ACPI_FUNCTION_TRACE("acpi_lbattery_read_alarm");
+
+	down(&sb->sbs->sem);
+
+	if (!acpi_sb_is_present(sb)) {
+		seq_printf(seq, "present:                 no\n");
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+
+	result = acpi_sb_get_alarm(sb);
+
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+		goto end;
+	}
+
+	if (sb->info.capacity_mode)
+		cscale = sb->info.vscale * sb->info.ipscale;
+	else
+		cscale = sb->info.ipscale;
+
+	seq_printf(seq, "alarm:                   ");
+	if (sb->alarm.remaining_capacity)
+		seq_printf(seq, "%d%s",
+			   sb->alarm.remaining_capacity * cscale,
+			   sb->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+	else
+		seq_printf(seq, "disabled\n");
+
+      end:
+	up(&sb->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static ssize_t
+acpi_lbattery_write_alarm(struct file *file, const char __user * buffer,
+			  size_t count, loff_t * ppos)
+{
+	struct seq_file *seq = (struct seq_file *)file->private_data;
+	struct acpi_sb *sb = (struct acpi_sb *)seq->private;
+	char alarm_string[6] = { '\0' };
+	int alarm_values[2];
+	char *term;
+	int result;
+
+	ACPI_FUNCTION_TRACE("acpi_lbattery_write_alarm");
+
+	down(&sb->sbs->sem);
+
+	if (!acpi_sb_is_present(sb)) {
+		result = -ENODEV;
+		goto end;
+	}
+
+	result = acpi_sb_check_init_state(sb);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery information\n");
+		goto end;
+	}
+
+	if (count > sizeof(alarm_string) - 1) {
+		result = -EINVAL;
+		goto end;
+	}
+
+	if (copy_from_user(alarm_string, buffer, count)) {
+		result = -EFAULT;
+		goto end;
+	}
+
+	alarm_string[count] = 0;
+	term = get_options(alarm_string, 2, alarm_values);
+
+	if (alarm_values[0] > 0) {
+		if (alarm_values[1] >= 0 && alarm_values[1] <= 65535) {
+			sb->alarm.remaining_capacity = alarm_values[1];
+		} else {
+			result = -EINVAL;
+			goto end;
+		}
+	}
+
+	result = acpi_sb_set_alarm(sb);
+
+      end:
+	up(&sb->sbs->sem);
+
+	if (result)
+		return_VALUE(result);
+	else
+		return_VALUE(count);
+}
+
+static int acpi_lbattery_alarm_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_lbattery_read_alarm, PDE(inode)->data);
+}
+
+static struct file_operations acpi_lbattery_info_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_lbattery_info_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct file_operations acpi_lbattery_state_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_lbattery_state_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct file_operations acpi_lbattery_alarm_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_lbattery_alarm_open_fs,
+	.read = seq_read,
+	.write = acpi_lbattery_write_alarm,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/* Legacy AC Adapter Interface */
+
+static struct proc_dir_entry *acpi_ladapter_dir = NULL;
+
+static int acpi_ladapter_read_state(struct seq_file *seq, void *offset)
+{
+	struct acpi_sbc *sbc = (struct acpi_sbc *)seq->private;
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_ladapter_read_state");
+
+	down(&sbc->sbs->sem);
+
+	result = acpi_sbc_get_state(sbc);
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read charger state\n");
+		goto end;
+	}
+
+	seq_printf(seq, "state:                   %s\n",
+		   sbc->state.ac_present ? "on-line" : "off-line");
+
+      end:
+	up(&sbc->sbs->sem);
+
+	return_VALUE(result);
+}
+
+static int acpi_ladapter_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_ladapter_read_state, PDE(inode)->data);
+}
+
+static struct file_operations acpi_ladapter_state_fops = {
+	.owner = THIS_MODULE,
+	.open = acpi_ladapter_state_open_fs,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+/* --------------------------------------------------------------------------
+                                 Driver Interface
+   -------------------------------------------------------------------------- */
+
+/* Smart Battery */
+
+static int acpi_sb_add(struct acpi_sbs *sbs, u8 id)
+{
+	int is_present;
+	int result;
+	char dir_name[5];
+	struct acpi_sb *sb;
+
+	ACPI_FUNCTION_TRACE("acpi_sb_add");
+
+	sb = &sbs->sb[id];
+
+	sb->init_state = 0;
+	sb->id = id;
+	sb->sbs = sbs;
+
+	is_present = acpi_sb_is_present(sb);
+
+	if (is_present) {
+		result = acpi_sb_init(sb);
+		if (result) {
+			goto end;
+		}
+		sb->init_state = 1;
+	}
+
+	result = sprintf(dir_name, ACPI_SB_DIR_NAME, id);
+	result = acpi_sbs_generic_add_fs(&sb->sb_entry,
+					 acpi_device_dir(sbs->device),
+					 dir_name,
+					 &acpi_sb_info_fops,
+					 &acpi_sb_state_fops,
+					 &acpi_sb_alarm_fops, sb);
+
+	if (result) {
+		goto end;
+	}
+	printk(KERN_INFO PREFIX "SBS: %s Slot [" ACPI_SB_DIR_NAME "] (battery %s)\n",
+	       ACPI_SB_DEVICE_NAME, id, is_present ? "present" : "absent");
+
+	result = sprintf(dir_name, ACPI_LBATTERY_DIR_NAME, id);
+	if (result < 0) {
+		goto end;
+	}
+	result = acpi_sbs_generic_add_fs(&sb->lbattery_entry,
+					 acpi_lbattery_dir,
+					 dir_name,
+					 &acpi_lbattery_info_fops,
+					 &acpi_lbattery_state_fops,
+					 &acpi_lbattery_alarm_fops, sb);
+	if (result) {
+		goto end;
+	}
+
+      end:
+	return_VALUE(result);
+}
+
+static void acpi_sb_remove(struct acpi_sbs *sbs, u8 id)
+{
+	ACPI_FUNCTION_TRACE("acpi_sb_remove");
+
+	acpi_sbs_generic_remove_fs(&(sbs->sb[id].sb_entry),
+				   acpi_device_dir(sbs->device));
+
+	acpi_sbs_generic_remove_fs(&(sbs->sb[id].lbattery_entry),
+				   acpi_lbattery_dir);
+}
+
+/* Smart Battery System Manager / Smart Battery Selector */
+
+static int acpi_sbsm_add(struct acpi_sbs *sbs)
+{
+	int result;
+	u16 battery_system_revision;
+
+	ACPI_FUNCTION_TRACE("acpi_sbsm_add");
+
+	sbs->sbsm->sbs = sbs;
+
+	/* Identify whether this is a System Manager or Selector */
+
+	result =
+	    acpi_sbs_smbus_read_word(sbs->smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
+				     &battery_system_revision, NULL);
+	if (result)
+		goto end;
+
+	if ((battery_system_revision & 0x00f0) == 0x0080 ||
+	    (battery_system_revision & 0x00f0) == 0x0090)
+		sbs->sbsm->class = ACPI_SBSM_CLASS;
+	else
+		sbs->sbsm->class = ACPI_SBSEL_CLASS;
+
+	result = acpi_sbsm_get_info(sbs->sbsm);
+	if (result)
+		goto end;
+
+	result = acpi_sbsm_get_state(sbs->sbsm);
+	if (result)
+		goto end;
+
+	if (sbs->sbsm->class == ACPI_SBSM_CLASS) {
+		result = acpi_sbs_generic_add_fs(&(sbs->sbsm->sbsm_entry),
+						 acpi_device_dir(sbs->device),
+						 ACPI_SBSM_DIR_NAME,
+						 &acpi_sbsm_info_fops,
+						 &acpi_sbsm_state_fops,
+						 NULL, sbs->sbsm);
+		if (result)
+			goto end;
+
+		printk(KERN_INFO PREFIX "SBS: %s [%s]\n", ACPI_SBSM_DEVICE_NAME,
+		       ACPI_SBSM_DIR_NAME);
+	} else {
+		result = acpi_sbs_generic_add_fs(&(sbs->sbsm->sbsm_entry),
+						 acpi_device_dir(sbs->device),
+						 ACPI_SBSEL_DIR_NAME,
+						 &acpi_sbsm_info_fops,
+						 &acpi_sbsm_state_fops,
+						 NULL, sbs->sbsm);
+		if (result)
+			goto end;
+
+		printk(KERN_INFO PREFIX "SBS: %s [%s]\n", ACPI_SBSEL_DEVICE_NAME,
+		       ACPI_SBSEL_DIR_NAME);
+	}
+
+      end:
+	return_VALUE(result);
+}
+
+static void acpi_sbsm_remove(struct acpi_sbs *sbs)
+{
+	ACPI_FUNCTION_TRACE("acpi_sbsm_remove");
+
+	acpi_sbs_generic_remove_fs(&sbs->sbsm->sbsm_entry,
+				   acpi_device_dir(sbs->device));
+}
+
+/* Smart Battery Charger */
+
+static int acpi_sbc_add(struct acpi_sbs *sbs)
+{
+	int result;
+
+	ACPI_FUNCTION_TRACE("acpi_sbc_add");
+
+	sbs->sbc->sbs = sbs;
+
+	result = acpi_sbc_get_info(sbs->sbc);
+	if (result)
+		goto end;
+
+	result = acpi_sbc_get_state(sbs->sbc);
+	if (result)
+		goto end;
+
+	result = acpi_sbs_generic_add_fs(&sbs->sbc->sbc_entry,
+					 acpi_device_dir(sbs->device),
+					 ACPI_SBC_DIR_NAME,
+					 &acpi_sbc_info_fops,
+					 &acpi_sbc_state_fops, NULL, sbs->sbc);
+	if (result)
+		goto end;
+
+	printk(KERN_INFO PREFIX "SBS: %s [%s]\n", ACPI_SBC_DEVICE_NAME,
+	       ACPI_SBC_DIR_NAME);
+
+	result = acpi_sbs_generic_add_fs(&sbs->sbc->ladapter_entry,
+					 acpi_ladapter_dir,
+					 ACPI_LADAPTER_DIR_NAME,
+					 NULL,
+					 &acpi_ladapter_state_fops,
+					 NULL, sbs->sbc);
+      end:
+	return_VALUE(result);
+}
+
+static void acpi_sbc_remove(struct acpi_sbs *sbs)
+{
+	ACPI_FUNCTION_TRACE("acpi_sbc_remove");
+
+	acpi_sbs_generic_remove_fs(&sbs->sbc->sbc_entry,
+				   acpi_device_dir(sbs->device));
+
+	acpi_sbs_generic_remove_fs(&sbs->sbc->ladapter_entry,
+				   acpi_ladapter_dir);
+}
+
+/* Smart Battery System */
+
+static int acpi_sbs_add(struct acpi_device *device)
+{
+	struct acpi_sbs *sbs = NULL;
+	struct acpi_ec_hc *ec_hc = NULL;
+	int result, remove_result = 0;
+	unsigned long sbs_obj;
+	u8 id;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_add");
+
+	sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
+	if (!sbs)
+		return_VALUE(-ENOMEM);
+
+	memset(sbs, 0, sizeof(struct acpi_sbs));
+
+	ec_hc = acpi_get_ec_hc(device);
+	if (!ec_hc) {
+		printk(KERN_ALERT PREFIX "SBS: no driver found for EC HC SMBus\n");
+		result = -ENODEV;
+		goto end;
+	}
+
+	sbs->device = device;
+	sbs->smbus = ec_hc->smbus;
+	sema_init(&sbs->sem, 1);
+
+	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
+	acpi_driver_data(device) = sbs;
+
+	result = acpi_sbs_generic_add_fs(&(acpi_device_dir(device)),
+					 acpi_sbs_dir,
+					 acpi_device_bid(device),
+					 NULL, NULL, NULL, sbs);
+	if (result)
+		goto end;
+
+	printk(KERN_INFO PREFIX "SBS: %s [%s]\n",
+	       acpi_device_name(device), acpi_device_bid(device));
+
+	/* Add the SBC */
+
+	sbs->sbc = kmalloc(sizeof(struct acpi_sbc), GFP_KERNEL);
+	if (!sbs->sbc) {
+		result = -ENOMEM;
+		goto end;
+	}
+	memset(sbs->sbc, 0, sizeof(struct acpi_sbc));
+
+	result = acpi_sbc_add(sbs);
+	if (result)
+		goto end;
+
+	/* Add the SBSM / SBSEL, if they are present */
+
+	result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
+	if (ACPI_FAILURE(result)) {
+		printk(KERN_ALERT PREFIX "Error obtaining _SBS object\n");
+		result = -EIO;
+		goto end;
+	}
+
+	sbs->sbsm = NULL;
+
+	if (sbs_obj > 0) {
+		sbs->sbsm = kmalloc(sizeof(struct acpi_sbsm), GFP_KERNEL);
+		if (!sbs->sbsm) {
+			result = -ENOMEM;
+			goto end;
+		}
+		memset(sbs->sbsm, 0, sizeof(struct acpi_sbsm));
+
+		result = acpi_sbsm_add(sbs);
+		if(result) {
+			kfree(sbs->sbsm);
+			sbs->sbsm = NULL;
+		}
+	}
+
+	/* Add the batteries */
+
+	sbs->sb = kmalloc(4 * sizeof(struct acpi_sb), GFP_KERNEL);
+	if (!sbs->sb) {
+		result = -ENOMEM;
+		goto end;
+	}
+	memset(sbs->sb, 0, 4 * sizeof(struct acpi_sb));
+
+	if (!sbs->sbsm) {
+		result = acpi_sb_add(sbs, 0);
+		if (result)
+			goto end;
+	} else {
+		for (id = 0; id <= 3; id++) {
+			if (sbs->sbsm->info.batteries_supported & (1 << id)) {
+				result = acpi_sb_add(sbs, id);
+				if (result)
+					goto end;
+			}
+		}
+	}
+
+	sbs->handle = device->handle;
+	printk(KERN_ALERT PREFIX "SBS: HANDLE %p\n", sbs->handle);
+
+	printk(KERN_INFO PREFIX "SBS: name %s, class %s, bid %s\n",
+	       acpi_device_name(device),
+	       acpi_device_class(device), acpi_device_bid(device));
+
+      end:
+	if (result) {
+		remove_result = acpi_sbs_remove(device, 0);
+	}
+	return_VALUE(result);
+}
+
+int acpi_sbs_remove(struct acpi_device *device, int type)
+{
+	struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
+	u8 id;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_remove");
+
+	if (!device || !sbs)
+		return_VALUE(-EINVAL);
+
+	if (sbs->sb) {
+		for (id = 0; id <= 3; id++) {
+			acpi_sb_remove(sbs, id);
+		}
+		kfree(sbs->sb);
+	}
+
+	if (sbs->sbsm) {
+		acpi_sbsm_remove(sbs);
+		kfree(sbs->sbsm);
+	}
+
+	if (sbs->sbc) {
+		acpi_sbc_remove(sbs);
+		kfree(sbs->sbc);
+	}
+
+	acpi_sbs_generic_remove_fs(&acpi_device_dir(device), acpi_sbs_dir);
+
+	kfree(sbs);
+
+	return_VALUE(0);
+}
+
+static int __init acpi_sbs_init(void)
+{
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_sbs_init");
+
+	if (capacity_mode > 2)
+		return_VALUE(-EINVAL);
+
+	acpi_sbs_dir = proc_mkdir(ACPI_SBS_CLASS, acpi_root_dir);
+	if (!acpi_sbs_dir)
+		return_VALUE(-ENODEV);
+	acpi_sbs_dir->owner = THIS_MODULE;
+
+	acpi_lbattery_dir = acpi_get_battery_dir();
+	if (!acpi_lbattery_dir) {
+		printk(KERN_ALERT PREFIX "SBS: cannot get acpi battery directory\n");
+		return_VALUE(-ENODEV);
+	}
+
+	acpi_ladapter_dir = acpi_get_ac_dir();
+	if (!acpi_ladapter_dir) {
+		printk(KERN_ALERT PREFIX "SBS: cannot get acpi ac directory\n");
+		return_VALUE(-ENODEV);
+	}
+
+	result = acpi_bus_register_driver(&acpi_sbs_driver);
+	if (result < 0) {
+		remove_proc_entry(ACPI_SBS_CLASS, acpi_root_dir);
+		return_VALUE(-ENODEV);
+	}
+
+	return_VALUE(0);
+}
+
+static void __exit acpi_sbs_exit(void)
+{
+	ACPI_FUNCTION_TRACE("acpi_sbs_exit");
+
+	acpi_bus_unregister_driver(&acpi_sbs_driver);
+
+	remove_proc_entry(ACPI_SBS_CLASS, acpi_root_dir);
+
+	return_VOID;
+}
+
+module_init(acpi_sbs_init);
+module_exit(acpi_sbs_exit);
diff -uNr linux-2.6.16/drivers/acpi/battery.c linux-2.6.16-iMac/drivers/acpi/battery.c
--- linux-2.6.16/drivers/acpi/battery.c	2006-01-03 04:21:10.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/battery.c	2006-03-20 08:01:46.000000000 +0100
@@ -808,5 +808,12 @@
 	return_VOID;
 }
 
+struct proc_dir_entry *acpi_get_battery_dir(void)
+{
+	return (acpi_battery_dir);
+}
+
+EXPORT_SYMBOL(acpi_get_battery_dir);
+
 module_init(acpi_battery_init);
 module_exit(acpi_battery_exit);
diff -uNr linux-2.6.16/drivers/acpi/blacklist.c linux-2.6.16-iMac/drivers/acpi/blacklist.c
--- linux-2.6.16/drivers/acpi/blacklist.c	2006-01-03 04:21:10.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/blacklist.c	2006-03-20 08:01:46.000000000 +0100
@@ -32,6 +32,7 @@
 #include <linux/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <linux/dmi.h>
+#include <linux/efi.h>
 
 enum acpi_blacklist_predicates {
 	all_versions,
@@ -80,6 +81,9 @@
 	int year;
 	char *s = dmi_get_system_info(DMI_BIOS_DATE);
 
+	if (efi_enabled)
+		return 0;
+
 	if (!s)
 		return 0;
 	if (!*s)
diff -uNr linux-2.6.16/drivers/acpi/ec.c linux-2.6.16-iMac/drivers/acpi/ec.c
--- linux-2.6.16/drivers/acpi/ec.c	2006-03-21 23:01:18.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/ec.c	2006-03-21 23:10:14.000000000 +0100
@@ -991,7 +991,6 @@
 	int result = 0;
 	acpi_status status = AE_OK;
 	union acpi_ec *ec = NULL;
-	unsigned long uid;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add");
 
@@ -1014,10 +1013,9 @@
 	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
 			      &ec->common.global_lock);
 
-	/* If our UID matches the UID for the ECDT-enumerated EC,
-	   we now have the *real* EC info, so kill the makeshift one. */
-	acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
-	if (ec_ecdt && ec_ecdt->common.uid == uid) {
+	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+	if (ec_ecdt) {
 		acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
 						  ACPI_ADR_SPACE_EC,
 						  &acpi_ec_space_handler);
@@ -1062,7 +1060,6 @@
 	int result = 0;
 	acpi_status status = AE_OK;
 	union acpi_ec *ec = NULL;
-	unsigned long uid;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add");
 
@@ -1088,10 +1085,9 @@
 	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
 			      &ec->common.global_lock);
 
-	/* If our UID matches the UID for the ECDT-enumerated EC,
-	   we now have the *real* EC info, so kill the makeshift one. */
-	acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
-	if (ec_ecdt && ec_ecdt->common.uid == uid) {
+	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
+	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
+	if (ec_ecdt) {
 		acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
 						  ACPI_ADR_SPACE_EC,
 						  &acpi_ec_space_handler);
diff -uNr linux-2.6.16/drivers/acpi/ec.h linux-2.6.16-iMac/drivers/acpi/ec.h
--- linux-2.6.16/drivers/acpi/ec.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/ec.h	2006-03-20 08:01:46.000000000 +0100
@@ -0,0 +1,70 @@
+/*
+ *  ec.h - ACPI Embedded Controller Driver ($Revision: 1.2 $)
+ *
+ *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
+ *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+union acpi_ec {
+	struct {
+		u32 mode;
+		acpi_handle handle;
+		unsigned long uid;
+		unsigned long gpe_bit;
+		struct acpi_generic_address status_addr;
+		struct acpi_generic_address command_addr;
+		struct acpi_generic_address data_addr;
+		unsigned long global_lock;
+	} common;
+
+	struct {
+		u32 mode;
+		acpi_handle handle;
+		unsigned long uid;
+		unsigned long gpe_bit;
+		struct acpi_generic_address status_addr;
+		struct acpi_generic_address command_addr;
+		struct acpi_generic_address data_addr;
+		unsigned long global_lock;
+		unsigned int expect_event;
+		atomic_t leaving_burst;	/* 0 : No, 1 : Yes, 2: abort */
+		atomic_t pending_gpe;
+		struct semaphore sem;
+		wait_queue_head_t wait;
+	} burst;
+
+	struct {
+		u32 mode;
+		acpi_handle handle;
+		unsigned long uid;
+		unsigned long gpe_bit;
+		struct acpi_generic_address status_addr;
+		struct acpi_generic_address command_addr;
+		struct acpi_generic_address data_addr;
+		unsigned long global_lock;
+		struct semaphore sem;
+		spinlock_t lock;
+	} polling;
+};
+
+extern int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data);
+extern int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data);
diff -uNr linux-2.6.16/drivers/acpi/i2c_acpi_ec.c linux-2.6.16-iMac/drivers/acpi/i2c_acpi_ec.c
--- linux-2.6.16/drivers/acpi/i2c_acpi_ec.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/i2c_acpi_ec.c	2006-03-21 16:51:20.000000000 +0100
@@ -0,0 +1,423 @@
+/*
+ * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
+ *
+ * Copyright (c) 2002, 2005 Ducrot Bruno
+ * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks) 
+ *
+ * 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 version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+
+#include "i2c_acpi_ec.h"
+
+//#define       xudelay(t)
+#define       xudelay(t)      udelay(t)
+
+//#define       xmsleep(t)
+#define	xmsleep(t)	msleep(t)
+
+#define ACPI_EC_HC_COMPONENT	0x00080000
+#define ACPI_EC_HC_CLASS	"ec_hc_smbus"
+#define ACPI_EC_HC_HID		"ACPI0001"
+#define ACPI_EC_HC_DRIVER_NAME	"ACPI EC HC smbus driver"
+#define ACPI_EC_HC_DEVICE_NAME	"EC HC smbus"
+
+#define _COMPONENT		ACPI_EC_HC_COMPONENT
+
+ACPI_MODULE_NAME("acpi_smbus")
+
+static int acpi_ec_hc_add(struct acpi_device *device);
+static int acpi_ec_hc_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_ec_hc_driver = {
+	.name = ACPI_EC_HC_DRIVER_NAME,
+	.class = ACPI_EC_HC_CLASS,
+	.ids = ACPI_EC_HC_HID,
+	.ops = {
+		.add = acpi_ec_hc_add,
+		.remove = acpi_ec_hc_remove,
+		},
+};
+
+/* Various bit mask for EC_SC (R) */
+#define OBF		0x01
+#define IBF		0x02
+#define CMD		0x08
+#define BURST		0x10
+#define SCI_EVT		0x20
+#define SMI_EVT		0x40
+
+/* Commands for EC_SC (W) */
+#define RD_EC		0x80
+#define WR_EC		0x81
+#define BE_EC		0x82
+#define BD_EC		0x83
+#define QR_EC		0x84
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+
+#define ACPI_EC_SMB_PRTCL	0x00	/* protocol, PEC */
+#define ACPI_EC_SMB_STS		0x01	/* status */
+#define ACPI_EC_SMB_ADDR	0x02	/* address */
+#define ACPI_EC_SMB_CMD		0x03	/* command */
+#define ACPI_EC_SMB_DATA	0x04	/* 32 data registers */
+#define ACPI_EC_SMB_BCNT	0x24	/* number of data bytes */
+#define ACPI_EC_SMB_ALRM_A	0x25	/* alarm address */
+#define ACPI_EC_SMB_ALRM_D	0x26	/* 2 bytes alarm data */
+
+#define ACPI_EC_SMB_STS_DONE	0x80
+#define ACPI_EC_SMB_STS_ALRM	0x40
+#define ACPI_EC_SMB_STS_RES	0x20
+#define ACPI_EC_SMB_STS_STATUS	0x1f
+
+#define ACPI_EC_SMB_STATUS_OK		0x00
+#define ACPI_EC_SMB_STATUS_FAIL		0x07
+#define ACPI_EC_SMB_STATUS_DNAK		0x10
+#define ACPI_EC_SMB_STATUS_DERR		0x11
+#define ACPI_EC_SMB_STATUS_CMD_DENY	0x12
+#define ACPI_EC_SMB_STATUS_UNKNOWN	0x13
+#define ACPI_EC_SMB_STATUS_ACC_DENY	0x17
+#define ACPI_EC_SMB_STATUS_TIMEOUT	0x18
+#define ACPI_EC_SMB_STATUS_NOTSUP	0x19
+#define ACPI_EC_SMB_STATUS_BUSY	0x1A
+#define ACPI_EC_SMB_STATUS_PEC	0x1F
+
+#define ACPI_EC_SMB_PRTCL_WRITE			0x00
+#define ACPI_EC_SMB_PRTCL_READ			0x01
+#define ACPI_EC_SMB_PRTCL_QUICK			0x02
+#define ACPI_EC_SMB_PRTCL_BYTE			0x04
+#define ACPI_EC_SMB_PRTCL_BYTE_DATA		0x06
+#define ACPI_EC_SMB_PRTCL_WORD_DATA		0x08
+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA		0x0a
+#define ACPI_EC_SMB_PRTCL_PROC_CALL		0x0c
+#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL	0x0d
+#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA	0x4a
+#define ACPI_EC_SMB_PRTCL_PEC			0x80
+
+/* Length of pre/post transaction sleep (msec) */
+#define ACPI_EC_SMB_TRANSACTION_SLEEP		1
+
+static int
+acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
+{
+	//u32 val;
+	int err;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_smb_read");
+
+	//err = acpi_ec_read(smbus->ec, smbus->base + address, &val);
+	/*
+	err = ec_read(smbus->base + address, &val);
+	if (!err)
+		*data = val;
+	*/
+	err = ec_read(smbus->base + address, data);
+
+	xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+
+	return err;
+}
+
+static int
+acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
+{
+	int err;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_smb_write");
+
+	//err = acpi_ec_write(smbus->ec, smbus->base + address, data);
+	err = ec_write(smbus->base + address, data);
+
+	xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+
+	return err;
+}
+
+static s32
+acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+		   char read_write, u8 command, int size,
+		   union i2c_smbus_data *data)
+{
+	struct acpi_ec_smbus *smbus = adap->algo_data;
+	unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
+	int i;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_smb_access");
+
+	if (read_write == I2C_SMBUS_READ) {
+		protocol = ACPI_EC_SMB_PRTCL_READ;
+	} else {
+		protocol = ACPI_EC_SMB_PRTCL_WRITE;
+	}
+	pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
+
+	switch (size) {
+
+	case I2C_SMBUS_QUICK:
+		protocol |= ACPI_EC_SMB_PRTCL_QUICK;
+		read_write = I2C_SMBUS_WRITE;
+		break;
+
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_WRITE)
+			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
+		protocol |= ACPI_EC_SMB_PRTCL_BYTE;
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE)
+			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
+		protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE) {
+			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
+			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
+					  data->word >> 8);
+		}
+		protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
+		break;
+
+	case I2C_SMBUS_BLOCK_DATA:
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = min_t(u8, data->block[0], 32);
+			acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
+			for (i = 0; i < len; i++)
+				acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
+						  data->block[i + 1]);
+		}
+		protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
+		break;
+
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		len = min_t(u8, data->block[0], 32);
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
+		if (read_write == I2C_SMBUS_WRITE)
+			for (i = 0; i < len; i++)
+				acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
+						  data->block[i + 1]);
+		protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
+		break;
+
+	case I2C_SMBUS_PROC_CALL:
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
+		protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
+		read_write = I2C_SMBUS_READ;
+		break;
+
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+		protocol |= pec;
+		len = min_t(u8, data->block[0], 31);
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+		acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
+		for (i = 0; i < len; i++)
+			acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
+					  data->block[i + 1]);
+		protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+		read_write = I2C_SMBUS_READ;
+		break;
+
+	default:
+		printk(KERN_WARNING PREFIX "EC SMBus adapter: "
+		       "Unsupported transaction %d\n", size);
+		return -1;
+	}
+
+	acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
+	acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
+
+	acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
+
+	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+		xudelay(500);
+		acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
+	}
+	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+		xmsleep(10);
+		acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
+	}
+	if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
+	    || (temp[0] & ACPI_EC_SMB_STS_STATUS))
+		return -1;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+
+	case I2C_SMBUS_BYTE:
+	case I2C_SMBUS_BYTE_DATA:
+		acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+	case I2C_SMBUS_PROC_CALL:
+		acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
+		acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
+		data->word = (temp[1] << 8) | temp[0];
+		break;
+
+	case I2C_SMBUS_BLOCK_DATA:
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+		len = 0;
+		acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
+		len = min_t(u8, len, 32);
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		for (i = 0; i < len; i++)
+			acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
+					 data->block + i + 1);
+		data->block[0] = len;
+		break;
+	}
+
+	return 0;
+}
+
+static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
+{
+	ACPI_FUNCTION_TRACE("acpi_ec_smb_func");
+
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA |
+	    I2C_FUNC_SMBUS_PROC_CALL |
+	    I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+	    I2C_FUNC_SMBUS_I2C_BLOCK |
+	    I2C_FUNC_SMBUS_HWPEC_CALC;
+}
+
+static struct i2c_algorithm acpi_ec_smbus_algorithm = {
+	.smbus_xfer = acpi_ec_smb_access,
+	.functionality = acpi_ec_smb_func,
+};
+
+static int acpi_ec_hc_add(struct acpi_device *device)
+{
+	int status;
+	unsigned long val;
+	struct acpi_ec_hc *ec_hc;
+	struct acpi_ec_smbus *smbus;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_hc_add");
+
+	if (!device)
+		return_VALUE(-EINVAL);
+
+	ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
+	if (!ec_hc)
+		return_VALUE(-ENOMEM);
+	memset(ec_hc, 0, sizeof(struct acpi_ec_hc));
+
+	smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
+	if (!smbus) {
+		kfree(ec_hc);
+		return_VALUE(-ENOMEM);
+	}
+	memset(smbus, 0, sizeof(struct acpi_ec_smbus));
+
+	ec_hc->handle = device->handle;
+	strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
+	acpi_driver_data(device) = ec_hc;
+
+	status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
+	if (ACPI_FAILURE(status)) {
+		printk(KERN_WARNING PREFIX "Error obtaining _EC\n");
+		kfree(ec_hc->smbus);
+		kfree(smbus);
+		return_VALUE(-EIO);
+	}
+
+	smbus->ec = acpi_driver_data(device->parent);
+	smbus->base = (val & 0xff00ull) >> 8;
+	smbus->alert = val & 0xffull;
+
+	printk(KERN_DEBUG "base: 0x%.x    alert: 0x%.2x\n", smbus->base, smbus->alert);
+
+	smbus->adapter.owner = THIS_MODULE;
+	smbus->adapter.algo = &acpi_ec_smbus_algorithm;
+	smbus->adapter.algo_data = smbus;
+
+	if (i2c_add_adapter(&smbus->adapter)) {
+		printk(KERN_WARNING PREFIX "EC SMBus adapter: "
+		       "Failed to register adapter\n");
+		kfree(smbus);
+		kfree(ec_hc);
+		return_VALUE(-EIO);
+	}
+
+	ec_hc->smbus = smbus;
+
+	printk(KERN_INFO PREFIX "EC SMBus adapter: name %s, class %s, bid %s\n",
+	       acpi_device_name(device),
+	       acpi_device_class(device), acpi_device_bid(device)
+	    );
+
+	return_VALUE(AE_OK);
+}
+
+static int acpi_ec_hc_remove(struct acpi_device *device, int type)
+{
+	struct acpi_ec_hc *ec_hc;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_hc_remove");
+
+	if (!device)
+		return_VALUE(-EINVAL);
+
+	ec_hc = acpi_driver_data(device);
+
+	i2c_del_adapter(&ec_hc->smbus->adapter);
+	kfree(ec_hc->smbus);
+	kfree(ec_hc);
+
+	return_VALUE(AE_OK);
+}
+
+static int __init acpi_ec_hc_init(void)
+{
+	ACPI_FUNCTION_TRACE("acpi_ec_hc_init");
+	return acpi_bus_register_driver(&acpi_ec_hc_driver);
+}
+
+static void __exit acpi_ec_hc_exit(void)
+{
+	ACPI_FUNCTION_TRACE("acpi_ec_hc_exit");
+	acpi_bus_unregister_driver(&acpi_ec_hc_driver);
+}
+
+struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
+{
+	ACPI_FUNCTION_TRACE("acpi_get_ec_hc");
+	return ((struct acpi_ec_hc *)acpi_driver_data(device->parent));
+}
+
+EXPORT_SYMBOL(acpi_get_ec_hc);
+
+module_init(acpi_ec_hc_init);
+module_exit(acpi_ec_hc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ducrot Bruno");
+MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff -uNr linux-2.6.16/drivers/acpi/i2c_acpi_ec.h linux-2.6.16-iMac/drivers/acpi/i2c_acpi_ec.h
--- linux-2.6.16/drivers/acpi/i2c_acpi_ec.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/i2c_acpi_ec.h	2006-03-20 08:01:46.000000000 +0100
@@ -0,0 +1,25 @@
+/*
+ * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
+ *
+ * Copyright (c) 2002, 2005 Ducrot Bruno
+ *
+ * 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 version 2.
+ */
+
+#include "ec.h"
+
+struct acpi_ec_smbus {
+	struct i2c_adapter adapter;
+	union acpi_ec *ec;
+	int base;
+	int alert;
+};
+
+struct acpi_ec_hc {
+	acpi_handle handle;
+	struct acpi_ec_smbus *smbus;
+};
+
+struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff -uNr linux-2.6.16/drivers/acpi/osl.c linux-2.6.16-iMac/drivers/acpi/osl.c
--- linux-2.6.16/drivers/acpi/osl.c	2006-03-21 23:01:18.000000000 +0100
+++ linux-2.6.16-iMac/drivers/acpi/osl.c	2006-03-20 08:01:46.000000000 +0100
@@ -208,6 +208,10 @@
 
 void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
 {
+	/* Don't unmap memory which was not mapped by acpi_os_map_memory */
+	if (efi_enabled &&
+		(efi_mem_attributes(virt_to_phys(virt)) & EFI_MEMORY_WB))
+			return;
 	iounmap(virt);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
diff -uNr linux-2.6.16/drivers/firmware/efivars.c linux-2.6.16-iMac/drivers/firmware/efivars.c
--- linux-2.6.16/drivers/firmware/efivars.c	2006-03-21 23:01:18.000000000 +0100
+++ linux-2.6.16-iMac/drivers/firmware/efivars.c	2006-03-20 10:37:27.000000000 +0100
@@ -110,7 +110,7 @@
 struct efi_variable {
 	efi_char16_t  VariableName[1024/sizeof(efi_char16_t)];
 	efi_guid_t    VendorGuid;
-	unsigned long DataSize;
+	u64         DataSize;
 	__u8          Data[1024];
 	efi_status_t  Status;
 	__u32         Attributes;
diff -uNr linux-2.6.16/drivers/macintosh/Kconfig linux-2.6.16-iMac/drivers/macintosh/Kconfig
--- linux-2.6.16/drivers/macintosh/Kconfig	2006-03-21 23:01:18.000000000 +0100
+++ linux-2.6.16-iMac/drivers/macintosh/Kconfig	2006-03-26 07:07:21.000000000 +0200
@@ -1,6 +1,6 @@
 
 menu "Macintosh device drivers"
-	depends on PPC || MAC
+	depends on PPC || MAC || X86
 
 config ADB
 	bool "Apple Desktop Bus (ADB) support"
@@ -135,7 +135,7 @@
 
 config MAC_EMUMOUSEBTN
 	bool "Support for mouse button 2+3 emulation"
-	depends on INPUT_ADBHID
+#	depends on INPUT_ADBHID
 	help
 	  This provides generic support for emulating the 2nd and 3rd mouse
 	  button with keypresses.  If you say Y here, the emulation is still
diff -uNr linux-2.6.16/drivers/pci/msi.c linux-2.6.16-iMac/drivers/pci/msi.c
--- linux-2.6.16/drivers/pci/msi.c	2006-03-21 23:01:19.000000000 +0100
+++ linux-2.6.16-iMac/drivers/pci/msi.c	2006-03-20 08:01:46.000000000 +0100
@@ -15,6 +15,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/dmi.h>
 
 #include <asm/errno.h>
 #include <asm/io.h>
@@ -40,6 +41,27 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+#ifdef CONFIG_X86
+
+static int __init apple_msi_disable(struct dmi_system_id *d)
+{
+	if (!pci_msi_quirk) {
+		printk(KERN_INFO "Apple machine detected. MSI disabled\n");
+		pci_msi_quirk = 1;
+	}
+	return 0;
+}
+
+static struct dmi_system_id __initdata msi_dmi_table[] = {
+	{
+		apple_msi_disable, "Apple",
+		{ DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), },
+	},
+	{ }
+};
+
+#endif		
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -362,6 +384,10 @@
 	if (!status)
 		return status;
 
+#ifdef CONFIG_X86
+	dmi_check_system(msi_dmi_table);
+#endif
+
 	if (pci_msi_quirk) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
diff -uNr linux-2.6.16/drivers/scsi/ata_piix.c linux-2.6.16-iMac/drivers/scsi/ata_piix.c
--- linux-2.6.16/drivers/scsi/ata_piix.c	2006-03-21 23:01:19.000000000 +0100
+++ linux-2.6.16-iMac/drivers/scsi/ata_piix.c	2006-03-20 08:01:46.000000000 +0100
@@ -95,6 +95,8 @@
 #define DRV_NAME	"ata_piix"
 #define DRV_VERSION	"1.05"
 
+#define ATA_ENABLE_PATA 1
+
 enum {
 	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
 	ICH5_PMR		= 0x90, /* port mapping register */
@@ -141,6 +143,7 @@
 	{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
 	{ 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
 	{ 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+	{ 0x8086, 0x27df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
 #endif
 
 	/* NOTE: The following PCI ids must be kept in sync with the
diff -uNr linux-2.6.16/drivers/usb/input/hid-core.c linux-2.6.16-iMac/drivers/usb/input/hid-core.c
--- linux-2.6.16/drivers/usb/input/hid-core.c	2006-03-21 23:01:19.000000000 +0100
+++ linux-2.6.16-iMac/drivers/usb/input/hid-core.c	2006-03-20 12:44:24.000000000 +0100
@@ -1602,6 +1602,8 @@
 	{ USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN },
 	{ USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN },
 	{ USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN },
 	{ USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN },
 	{ USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN },
 
diff -uNr linux-2.6.16/drivers/usb/storage/usb.c linux-2.6.16-iMac/drivers/usb/storage/usb.c
--- linux-2.6.16/drivers/usb/storage/usb.c	2006-03-21 23:01:19.000000000 +0100
+++ linux-2.6.16-iMac/drivers/usb/storage/usb.c	2006-03-20 08:01:46.000000000 +0100
@@ -103,7 +103,7 @@
 MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
 MODULE_LICENSE("GPL");
 
-static unsigned int delay_use = 5;
+static unsigned int delay_use = 0;
 module_param(delay_use, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
 
diff -uNr linux-2.6.16/drivers/video/Kconfig linux-2.6.16-iMac/drivers/video/Kconfig
--- linux-2.6.16/drivers/video/Kconfig	2006-03-21 23:01:19.000000000 +0100
+++ linux-2.6.16-iMac/drivers/video/Kconfig	2006-03-20 08:01:46.000000000 +0100
@@ -465,6 +465,15 @@
 	  You will get a boot time penguin logo at no additional cost. Please
 	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
 
+config FB_IMAC
+	bool "Intel Based Macs FB"
+	depends on (FB = y) && X86
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the frame buffer device driver for the Inel Based Mac's
+
 config VIDEO_SELECT
 	bool
 	depends on FB_VESA
diff -uNr linux-2.6.16/drivers/video/Makefile linux-2.6.16-iMac/drivers/video/Makefile
--- linux-2.6.16/drivers/video/Makefile	2006-01-03 04:21:10.000000000 +0100
+++ linux-2.6.16-iMac/drivers/video/Makefile	2006-03-20 08:01:46.000000000 +0100
@@ -97,6 +97,7 @@
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
+obj-$(CONFIG_FB_IMAC)             += imacfb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
 
diff -uNr linux-2.6.16/drivers/video/imacfb.c linux-2.6.16-iMac/drivers/video/imacfb.c
--- linux-2.6.16/drivers/video/imacfb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.16-iMac/drivers/video/imacfb.c	2006-03-20 08:01:46.000000000 +0100
@@ -0,0 +1,425 @@
+/*
+ * framebuffer driver for Intel Based Mac's
+ *
+ * (c) 2006 Edgar Hucek <gimli@dark-green.com>
+ * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <video/vga.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#define dac_reg	(0x3c8)
+#define dac_val	(0x3c9)
+
+typedef enum _MAC_TAPE {
+	M_I17,
+	M_I20,
+	M_MINI,
+	M_NEW
+} MAC_TAPE;
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo imacfb_defined __initdata = {
+      	.activate	= FB_ACTIVATE_NOW,
+	.height		= -1,
+	.width		= -1,
+	.right_margin	= 32,
+	.upper_margin	= 16,
+	.lower_margin	= 4,
+	.vsync_len	= 4,
+	.vmode		= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo imacfb_fix __initdata = {
+	.id	= "IMAC VGA",
+	.type	= FB_TYPE_PACKED_PIXELS,
+	.accel	= FB_ACCEL_NONE,
+};
+
+static int             inverse   = 0;
+static int             mtrr      = 0; /* disable mtrr */
+static int	       vram_remap __initdata = 0; /* Set amount of memory to be used */
+static int	       vram_total __initdata = 0; /* Set total amount of memory */
+static int             depth;
+static int             model = M_NEW;
+static int             manual_height = 0;
+static int             manual_width = 0;
+
+/* --------------------------------------------------------------------- */
+
+static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *info)
+{
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+	
+	if (regno >= info->cmap.len)
+		return 1;
+
+	if (regno < 16 && info->var.bits_per_pixel != 8) {
+		switch (info->var.bits_per_pixel) {
+		case 16:
+			if (info->var.red.offset == 10) {
+				/* 1:5:5:5 */
+				((u32*) (info->pseudo_palette))[regno] =
+					((red   & 0xf800) >>  1) |
+					((green & 0xf800) >>  6) |
+					((blue  & 0xf800) >> 11);
+			} else {
+				/* 0:5:6:5 */
+				((u32*) (info->pseudo_palette))[regno] =
+					((red   & 0xf800)      ) |
+					((green & 0xfc00) >>  5) |
+					((blue  & 0xf800) >> 11);
+			}
+			break;
+		case 24:
+		case 32:
+			red   >>= 8;
+			green >>= 8;
+			blue  >>= 8;
+			((u32 *)(info->pseudo_palette))[regno] =
+				(red   << info->var.red.offset)   |
+				(green << info->var.green.offset) |
+				(blue  << info->var.blue.offset);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static struct fb_ops imacfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= imacfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __init imacfb_setup(char *options)
+{
+	char *this_opt;
+	
+	if (!options || !*options)
+		return 0;
+	
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+		
+		if (! strcmp(this_opt, "inverse"))
+			inverse=1;
+		else if (! strncmp(this_opt, "mtrr:", 5))
+			mtrr = simple_strtoul(this_opt+5, NULL, 0);
+		else if (! strcmp(this_opt, "nomtrr"))
+			mtrr=0;
+		else if (! strncmp(this_opt, "vtotal:", 7))
+			vram_total = simple_strtoul(this_opt+7, NULL, 0);
+		else if (! strncmp(this_opt, "vremap:", 7))
+			vram_remap = simple_strtoul(this_opt+7, NULL, 0);
+		else if (! strcmp(this_opt, "i17"))
+			model = M_I17;
+		else if (! strcmp(this_opt, "i20"))
+			model = M_I20;
+		else if (! strcmp(this_opt, "mini"))
+			model = M_MINI;
+		else if (! strncmp(this_opt, "height:", 7))
+			manual_height = simple_strtoul(this_opt+7, NULL, 0);
+		else if (! strncmp(this_opt, "width:", 6))
+			manual_width = simple_strtoul(this_opt+6, NULL, 0);
+	}
+	return 0;
+}
+
+#define	DEFAULT_FB_MEM	1024*1024*16
+
+static int __init imacfb_probe(struct platform_device *dev)
+{
+	struct fb_info *info;
+	int err;
+	unsigned int size_vmode;
+	unsigned int size_remap;
+	unsigned int size_total;
+
+	screen_info.lfb_base = 0x80010000;
+	screen_info.lfb_depth = 32;
+	screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
+	screen_info.pages=1;
+	screen_info.blue_size = 8;
+	screen_info.blue_pos = 0;
+	screen_info.green_size = 8;
+	screen_info.green_pos = 8;
+	screen_info.red_size = 8;
+	screen_info.red_pos = 16;
+	screen_info.rsvd_size = 8;
+	screen_info.rsvd_pos = 24;
+
+	switch(model) {
+		case M_I17:
+			screen_info.lfb_width = 1440;
+			screen_info.lfb_height = 900;
+			screen_info.lfb_linelength = 1472 * 4;
+			break;
+		case M_NEW:
+		case M_I20:
+			screen_info.lfb_width = 1680;
+			screen_info.lfb_height = 1050;
+			screen_info.lfb_linelength = 1728 * 4;
+			break;
+		case M_MINI:
+			screen_info.lfb_width = 1024;
+			screen_info.lfb_height = 768;
+			screen_info.lfb_linelength = 2048 * 4;
+			break;
+ 	}
+
+	/* if the user wants to manually specify height/width,
+	   we will override the defaults */
+	/* TODO: eventually get auto-detection working */
+	if(manual_height > 0)
+		screen_info.lfb_height = manual_height;
+	if(manual_width > 0)
+		screen_info.lfb_width = manual_width;
+
+	/*
+	static void *videomemory;
+	static u_long videomemorysize = (64*1024*1024);
+	videomemory = ioremap(0x80000000,videomemorysize);
+	memset(videomemory, 0x99, videomemorysize);
+	*/
+
+	imacfb_fix.smem_start = screen_info.lfb_base;
+	imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
+	if (15 == imacfb_defined.bits_per_pixel)
+		imacfb_defined.bits_per_pixel = 16;
+	imacfb_defined.xres = screen_info.lfb_width;
+	imacfb_defined.yres = screen_info.lfb_height;
+	imacfb_fix.line_length = screen_info.lfb_linelength;
+	imacfb_fix.visual   = (imacfb_defined.bits_per_pixel == 8) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+	/*   size_vmode -- that is the amount of memory needed for the
+	 *                 used video mode, i.e. the minimum amount of
+	 *                 memory we need. */
+	size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
+
+	/*   size_total -- all video memory we have. Used for mtrr
+	 *                 entries, ressource allocation and bounds
+	 *                 checking. */
+	size_total = screen_info.lfb_size * 65536;
+	if (vram_total)
+		size_total = vram_total * 1024 * 1024;
+	if (size_total < size_vmode)
+		size_total = size_vmode;
+
+	/*   size_remap -- the amount of video memory we are going to
+	 *                 use for imacfb.  With modern cards it is no
+	 *                 option to simply use size_total as that
+	 *                 wastes plenty of kernel address space. */
+	size_remap  = size_vmode * 2;
+	if (vram_remap)
+		size_remap = vram_remap * 1024 * 1024;
+	if (size_remap < size_vmode)
+		size_remap = size_vmode;
+	if (size_remap > size_total)
+		size_remap = size_total;
+	imacfb_fix.smem_len = size_remap;
+
+#ifndef __i386__
+	screen_info.imacpm_seg = 0;
+#endif
+
+	if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
+		printk(KERN_WARNING
+		       "imacfb: cannot reserve video memory at 0x%lx\n",
+			imacfb_fix.smem_start);
+		/* We cannot make this fatal. Sometimes this comes from magic
+		   spaces our resource handlers simply don't know about */
+	}
+
+	info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
+	if (!info) {
+		release_mem_region(imacfb_fix.smem_start, size_total);
+		return -ENOMEM;
+	}
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+
+	info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR
+		       "imacfb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+			imacfb_fix.smem_len, imacfb_fix.smem_start);
+		err = -EIO;
+		goto err;
+	}
+
+	printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
+	       "using %dk, total %dk\n",
+	       imacfb_fix.smem_start, info->screen_base,
+	       size_remap/1024, size_total/1024);
+	printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+	       imacfb_defined.xres, imacfb_defined.yres, imacfb_defined.bits_per_pixel, imacfb_fix.line_length, screen_info.pages);
+
+	imacfb_defined.xres_virtual = imacfb_defined.xres;
+	imacfb_defined.yres_virtual = imacfb_fix.smem_len / imacfb_fix.line_length;
+	printk(KERN_INFO "imacfb: scrolling: redraw\n");
+	imacfb_defined.yres_virtual = imacfb_defined.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	imacfb_defined.pixclock     = 10000000 / imacfb_defined.xres * 1000 / imacfb_defined.yres;
+	imacfb_defined.left_margin  = (imacfb_defined.xres / 8) & 0xf8;
+	imacfb_defined.hsync_len    = (imacfb_defined.xres / 8) & 0xf8;
+	
+	imacfb_defined.red.offset    = screen_info.red_pos;
+	imacfb_defined.red.length    = screen_info.red_size;
+	imacfb_defined.green.offset  = screen_info.green_pos;
+	imacfb_defined.green.length  = screen_info.green_size;
+	imacfb_defined.blue.offset   = screen_info.blue_pos;
+	imacfb_defined.blue.length   = screen_info.blue_size;
+	imacfb_defined.transp.offset = screen_info.rsvd_pos;
+	imacfb_defined.transp.length = screen_info.rsvd_size;
+
+	if (imacfb_defined.bits_per_pixel <= 8) {
+		depth = imacfb_defined.green.length;
+		imacfb_defined.red.length =
+		imacfb_defined.green.length =
+		imacfb_defined.blue.length =
+		imacfb_defined.bits_per_pixel;
+	}
+
+	printk(KERN_INFO "imacfb: %s: "
+	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+	       (imacfb_defined.bits_per_pixel > 8) ?
+	       "Truecolor" : "Pseudocolor",
+	       screen_info.rsvd_size,
+	       screen_info.red_size,
+	       screen_info.green_size,
+	       screen_info.blue_size,
+	       screen_info.rsvd_pos,
+	       screen_info.red_pos,
+	       screen_info.green_pos,
+	       screen_info.blue_pos);
+
+	imacfb_fix.ypanstep  = 0;
+	imacfb_fix.ywrapstep = 0;
+
+	/* request failure does not faze us, as vgacon probably has this
+	 * region already (FIXME) */
+	request_region(0x3c0, 32, "imacfb");
+
+#ifdef CONFIG_MTRR
+	if (mtrr) {
+		unsigned int temp_size = size_total;
+		unsigned int type = 0;
+
+		switch (mtrr) {
+		case 1:
+			type = MTRR_TYPE_UNCACHABLE;
+			break;
+		case 2:
+			type = MTRR_TYPE_WRBACK;
+			break;
+		case 3:
+			type = MTRR_TYPE_WRCOMB;
+			break;
+		case 4:
+			type = MTRR_TYPE_WRTHROUGH;
+			break;
+		default:
+			type = 0;
+			break;
+		}
+
+		if (type) {
+			int rc;
+
+			/* Find the largest power-of-two */
+			while (temp_size & (temp_size - 1))
+				temp_size &= (temp_size - 1);
+
+			/* Try and find a power of two to add */
+			do {
+				rc = mtrr_add(imacfb_fix.smem_start, temp_size,
+					      type, 1);
+				temp_size >>= 1;
+			} while (temp_size >= PAGE_SIZE && rc == -EINVAL);
+		}
+	}
+#endif
+	
+	info->fbops = &imacfb_ops;
+	info->var = imacfb_defined;
+	info->fix = imacfb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		err = -ENOMEM;
+		goto err;
+	}
+	if (register_framebuffer(info)<0) {
+		err = -EINVAL;
+		fb_dealloc_cmap(&info->cmap);
+		goto err;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+	return 0;
+err:
+	framebuffer_release(info);
+	release_mem_region(imacfb_fix.smem_start, size_total);
+	return err;
+}
+
+static struct platform_driver imacfb_driver = {
+	.probe	= imacfb_probe,
+	.driver	= {
+		.name	= "imacfb",
+	},
+};
+
+static struct platform_device imacfb_device = {
+	.name	= "imacfb",
+};
+
+static int __init imacfb_init(void)
+{
+	int ret;
+	char *option = NULL;
+
+	/* ignore error return of fb_get_options */
+	fb_get_options("imacfb", &option);
+	imacfb_setup(option);
+	ret = platform_driver_register(&imacfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&imacfb_device);
+		if (ret)
+			platform_driver_unregister(&imacfb_driver);
+	}
+	return ret;
+}
+module_init(imacfb_init);
+
+MODULE_LICENSE("GPL");
diff -uNr linux-2.6.16/include/linux/efi.h linux-2.6.16-iMac/include/linux/efi.h
--- linux-2.6.16/include/linux/efi.h	2006-01-03 04:21:10.000000000 +0100
+++ linux-2.6.16-iMac/include/linux/efi.h	2006-03-20 10:38:02.000000000 +0100
@@ -163,7 +163,7 @@
 					    efi_time_t *tm);
 typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm);
 typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-					 unsigned long *data_size, void *data);
+					 u64 *data_size, void *data);
 typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name,
 					      efi_guid_t *vendor);
 typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, 
diff -uNr linux-2.6.16/sound/pci/hda/patch_sigmatel.c linux-2.6.16-iMac/sound/pci/hda/patch_sigmatel.c
--- linux-2.6.16/sound/pci/hda/patch_sigmatel.c	2006-03-21 23:01:21.000000000 +0100
+++ linux-2.6.16-iMac/sound/pci/hda/patch_sigmatel.c	2006-03-20 08:01:46.000000000 +0100
@@ -314,6 +314,9 @@
 	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
 	  .pci_subdevice = 0x0417,
 	  .config = STAC_D945GTP5 },	/* Intel D975XBK - 5 Stack */
+	{ .pci_subvendor = 0x8384,
+	  .pci_subdevice = 0x7680,
+	  .config = STAC_D945GTP5 },	/* Intel D975XBK - 5 Stack */
 	{} /* terminator */
 };
 
