diff -uNr linux-2.6.16.1/drivers/acpi/Kconfig linux-2.6.16.1-imac/drivers/acpi/Kconfig
--- linux-2.6.16.1/drivers/acpi/Kconfig	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/Kconfig	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/Makefile linux-2.6.16.1-imac/drivers/acpi/Makefile
--- linux-2.6.16.1/drivers/acpi/Makefile	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/Makefile	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/ac.c linux-2.6.16.1-imac/drivers/acpi/ac.c
--- linux-2.6.16.1/drivers/acpi/ac.c	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/ac.c	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/acpi_sbs.c linux-2.6.16.1-imac/drivers/acpi/acpi_sbs.c
--- linux-2.6.16.1/drivers/acpi/acpi_sbs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/acpi_sbs.c	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/battery.c linux-2.6.16.1-imac/drivers/acpi/battery.c
--- linux-2.6.16.1/drivers/acpi/battery.c	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/battery.c	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/ec.c linux-2.6.16.1-imac/drivers/acpi/ec.c
--- linux-2.6.16.1/drivers/acpi/ec.c	2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/ec.c	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/ec.h linux-2.6.16.1-imac/drivers/acpi/ec.h
--- linux-2.6.16.1/drivers/acpi/ec.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/ec.h	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/i2c_acpi_ec.c linux-2.6.16.1-imac/drivers/acpi/i2c_acpi_ec.c
--- linux-2.6.16.1/drivers/acpi/i2c_acpi_ec.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/i2c_acpi_ec.c	2006-04-01 23:51:38.000000000 +0000
@@ -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.1/drivers/acpi/i2c_acpi_ec.h linux-2.6.16.1-imac/drivers/acpi/i2c_acpi_ec.h
--- linux-2.6.16.1/drivers/acpi/i2c_acpi_ec.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16.1-imac/drivers/acpi/i2c_acpi_ec.h	2006-04-01 23:51:38.000000000 +0000
@@ -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);
