Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6

* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (68 commits)
  ACPI: replace kmalloc+memset with kzalloc
  ACPI: Add support for acpi_load_table/acpi_unload_table_id
  fbdev: update after backlight argument change
  ACPI: video: Add dev argument for backlight_device_register
  ACPI: Implement acpi_video_get_next_level()
  ACPI: Kconfig - depend on PM rather than selecting it
  ACPI: fix NULL check in drivers/acpi/osl.c
  ACPI: make drivers/acpi/ec.c:ec_ecdt static
  ACPI: prevent processor module from loading on failures
  ACPI: fix single linked list manipulation
  ACPI: ibm_acpi: allow clean removal
  ACPI: fix git automerge failure
  ACPI: ibm_acpi: respond to workqueue update
  ACPI: dock: add uevent to indicate change in device status
  ACPI: ec: Lindent once again
  ACPI: ec: Change #define to enums there possible.
  ACPI: ec: Style changes.
  ACPI: ec: Acquire Global Lock under EC mutex.
  ACPI: ec: Drop udelay() from poll mode. Loop by reading status field instead.
  ACPI: ec: Rename gpe_bit to gpe
  ...
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
index e50595b..0132d36 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/ibm-acpi.txt
@@ -398,26 +398,68 @@
 
 Most ThinkPads include six or more separate temperature sensors but
 only expose the CPU temperature through the standard ACPI methods.
-This feature shows readings from up to eight different sensors. Some
-readings may not be valid, e.g. may show large negative values. For
-example, on the X40, a typical output may be:
-
-temperatures:   42 42 45 41 36 -128 33 -128
-
-Thomas Gruber took his R51 apart and traced all six active sensors in
-his laptop (the location of sensors may vary on other models):
-
-1:  CPU
-2:  Mini PCI Module
-3:  HDD
-4:  GPU
-5:  Battery
-6:  N/A
-7:  Battery
-8:  N/A
+This feature shows readings from up to eight different sensors on older
+ThinkPads, and it has experimental support for up to sixteen different
+sensors on newer ThinkPads.  Readings from sensors that are not available
+return -128.
 
 No commands can be written to this file.
 
+EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
+implementation directly accesses hardware registers and may not work as
+expected. USE WITH CAUTION! To use this feature, you need to supply the
+experimental=1 parameter when loading the module.  When EXPERIMENTAL
+mode is enabled, reading the first 8 sensors on newer ThinkPads will
+also use an new experimental thermal sensor access mode.
+
+For example, on the X40, a typical output may be:
+temperatures:   42 42 45 41 36 -128 33 -128
+
+EXPERIMENTAL: On the T43/p, a typical output may be:
+temperatures:   48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
+
+The mapping of thermal sensors to physical locations varies depending on
+system-board model (and thus, on ThinkPad model).
+
+http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that
+tries to track down these locations for various models.
+
+Most (newer?) models seem to follow this pattern:
+
+1:  CPU
+2:  (depends on model)
+3:  (depends on model)
+4:  GPU
+5:  Main battery: main sensor
+6:  Bay battery: main sensor
+7:  Main battery: secondary sensor
+8:  Bay battery: secondary sensor
+9-15: (depends on model)
+
+For the R51 (source: Thomas Gruber):
+2:  Mini-PCI
+3:  Internal HDD
+
+For the T43, T43/p (source: Shmidoax/Thinkwiki.org)
+http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
+2:  System board, left side (near PCMCIA slot), reported as HDAPS temp
+3:  PCMCIA slot
+9:  MCH (northbridge) to DRAM Bus
+10: ICH (southbridge), under Mini-PCI card, under touchpad
+11: Power regulator, underside of system board, below F2 key
+
+The A31 has a very atypical layout for the thermal sensors
+(source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31)
+1:  CPU
+2:  Main Battery: main sensor
+3:  Power Converter
+4:  Bay Battery: main sensor
+5:  MCH (northbridge)
+6:  PCMCIA/ambient
+7:  Main Battery: secondary sensor
+8:  Bay Battery: secondary sensor
+
+
 EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
 ------------------------------------------------------------------------
 
@@ -529,27 +571,57 @@
 WITH CAUTION! To use this feature, you need to supply the
 experimental=1 parameter when loading the module.
 
-This feature attempts to show the current fan speed. The speed is read
-directly from the hardware registers of the embedded controller. This
-is known to work on later R, T and X series ThinkPads but may show a
-bogus value on other models.
+This feature attempts to show the current fan speed, control mode and
+other fan data that might be available.  The speed is read directly
+from the hardware registers of the embedded controller.  This is known
+to work on later R, T and X series ThinkPads but may show a bogus
+value on other models.
+
+Most ThinkPad fans work in "levels".  Level 0 stops the fan.  The higher
+the level, the higher the fan speed, although adjacent levels often map
+to the same fan speed.  7 is the highest level, where the fan reaches
+the maximum recommended speed.  Level "auto" means the EC changes the
+fan level according to some internal algorithm, usually based on
+readings from the thermal sensors.  Level "disengaged" means the EC
+disables the speed-locked closed-loop fan control, and drives the fan as
+fast as it can go, which might exceed hardware limits, so use this level
+with caution.
+
+The fan usually ramps up or down slowly from one speed to another,
+and it is normal for the EC to take several seconds to react to fan
+commands.
 
 The fan may be enabled or disabled with the following commands:
 
 	echo enable  >/proc/acpi/ibm/fan
 	echo disable >/proc/acpi/ibm/fan
 
-WARNING WARNING WARNING: do not leave the fan disabled unless you are
-monitoring the temperature sensor readings and you are ready to enable
-it if necessary to avoid overheating.
+Placing a fan on level 0 is the same as disabling it.  Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
 
-The fan only runs if it's enabled *and* the various temperature
-sensors which control it read high enough. On the X40, this seems to
-depend on the CPU and HDD temperatures. Specifically, the fan is
-turned on when either the CPU temperature climbs to 56 degrees or the
-HDD temperature climbs to 46 degrees. The fan is turned off when the
-CPU temperature drops to 49 degrees and the HDD temperature drops to
-41 degrees. These thresholds cannot currently be controlled.
+WARNING WARNING WARNING: do not leave the fan disabled unless you are
+monitoring all of the temperature sensor readings and you are ready to
+enable it if necessary to avoid overheating.
+
+An enabled fan in level "auto" may stop spinning if the EC decides the
+ThinkPad is cool enough and doesn't need the extra airflow.  This is
+normal, and the EC will spin the fan up if the varios thermal readings
+rise too much.
+
+On the X40, this seems to depend on the CPU and HDD temperatures.
+Specifically, the fan is turned on when either the CPU temperature
+climbs to 56 degrees or the HDD temperature climbs to 46 degrees.  The
+fan is turned off when the CPU temperature drops to 49 degrees and the
+HDD temperature drops to 41 degrees.  These thresholds cannot
+currently be controlled.
+
+The fan level can be controlled with the command:
+
+	echo 'level <level>' > /proc/acpi/ibm/thermal
+
+Where <level> is an integer from 0 to 7, or one of the words "auto"
+or "disengaged" (without the quotes).  Not all ThinkPads support the
+"auto" and "disengaged" levels.
 
 On the X31 and X40 (and ONLY on those models), the fan speed can be
 controlled to a certain degree. Once the fan is running, it can be
@@ -562,12 +634,9 @@
 any effect or the fan speed eventually settles somewhere in that
 range. The fan cannot be stopped or started with this command.
 
-On the 570, temperature readings are not available through this
-feature and the fan control works a little differently. The fan speed
-is reported in levels from 0 (off) to 7 (max) and can be controlled
-with the following command:
-
-	echo 'level <level>' > /proc/acpi/ibm/thermal
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met.  It will override any fan programming done
+through ibm-acpi.
 
 EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
 ---------------------------------------
@@ -601,6 +670,26 @@
 
 	modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
 
+The ibm-acpi kernel driver can be programmed to revert the fan level
+to a safe setting if userspace does not issue one of the fan commands:
+"enable", "disable", "level" or "watchdog" within a configurable
+ammount of time.  To do this, use the "watchdog" command.
+
+	echo 'watchdog <interval>' > /proc/acpi/ibm/fan
+
+Interval is the ammount of time in seconds to wait for one of the
+above mentioned fan commands before reseting the fan level to a safe
+one.  If set to zero, the watchdog is disabled (default).  When the
+watchdog timer runs out, it does the exact equivalent of the "enable"
+fan command.
+
+Note that the watchdog timer stops after it enables the fan.  It will
+be rearmed again automatically (using the same interval) when one of
+the above mentioned fan commands is received.  The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made
+through means other than the "enable", "disable", and "level" fan
+commands.
+
 
 Example Configuration
 ---------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index 366465d..db09036 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1400,6 +1400,15 @@
 T:	git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 S:	Maintained
 
+IBM ACPI EXTRAS DRIVER
+P:	Henrique de Moraes Holschuh
+M:	ibm-acpi@hmh.eng.br
+L:	ibm-acpi-devel@lists.sourceforge.net
+W:	http://ibm-acpi.sourceforge.net
+W:	http://thinkwiki.org/wiki/Ibm-acpi
+T:	git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
+S:	Maintained
+
 SN-IA64 (Itanium) SUB-PLATFORM
 P:	Jes Sorensen
 M:	jes@sgi.com
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index c8f96cf..094300b 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -1327,3 +1327,25 @@
 	return 0;
 }
 early_param("acpi_sci", setup_acpi_sci);
+
+int __acpi_acquire_global_lock(unsigned int *lock)
+{
+	unsigned int old, new, val;
+	do {
+		old = *lock;
+		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
+		val = cmpxchg(lock, old, new);
+	} while (unlikely (val != old));
+	return (new < 3) ? -1 : 0;
+}
+
+int __acpi_release_global_lock(unsigned int *lock)
+{
+	unsigned int old, new, val;
+	do {
+		old = *lock;
+		new = old & ~0x3;
+		val = cmpxchg(lock, old, new);
+	} while (unlikely (val != old));
+	return old & 0x1;
+}
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
index 088f130..15c08d5 100644
--- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -276,12 +276,10 @@
 
 	dprintk("acpi_cpufreq_cpu_init\n");
 
-	data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+	data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
 	if (!data)
 		return (-ENOMEM);
 
-	memset(data, 0, sizeof(struct cpufreq_acpi_io));
-
 	acpi_io_data[cpu] = data;
 
 	result = acpi_processor_register_performance(&data->acpi_data, cpu);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 0f9d4be..1639998 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -11,7 +11,7 @@
 	bool "ACPI Support"
 	depends on IA64 || X86
 	depends on PCI
-	select PM
+	depends on PM
 	default y
 	---help---
 	  Advanced Configuration and Power Interface (ACPI) support for 
@@ -97,6 +97,7 @@
 
 config ACPI_BUTTON
 	tristate "Button"
+	depends on INPUT
 	default y
 	help
 	  This driver handles events on the power, sleep and lid buttons.
@@ -172,6 +173,7 @@
 config ACPI_ASUS
         tristate "ASUS/Medion Laptop Extras"
 	depends on X86
+	select BACKLIGHT_CLASS_DEVICE
         ---help---
           This driver provides support for extra features of ACPI-compatible
           ASUS laptops. As some of Medion laptops are made by ASUS, it may also
@@ -200,6 +202,7 @@
 config ACPI_IBM
 	tristate "IBM ThinkPad Laptop Extras"
 	depends on X86
+	select BACKLIGHT_CLASS_DEVICE
 	---help---
 	  This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
 	  support for Fn-Fx key combinations, Bluetooth control, video
@@ -222,9 +225,21 @@
 
 	  If you are not sure, say N here.
 
+config ACPI_IBM_BAY
+	bool "Legacy Removable Bay Support"
+	depends on ACPI_IBM
+	depends on ACPI_BAY=n
+	default n
+	---help---
+	  Allows the ibm_acpi driver to handle removable bays.
+	  This support is obsoleted by CONFIG_ACPI_BAY.
+
+	  If you are not sure, say N here.
+
 config ACPI_TOSHIBA
 	tristate "Toshiba Laptop Extras"
 	depends on X86
+	select BACKLIGHT_CLASS_DEVICE
 	---help---
 	  This driver adds support for access to certain system settings
 	  on "legacy free" Toshiba laptops.  These laptops can be recognized by
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 11abc7b..6daeace 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -109,7 +109,7 @@
 
 static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_ac *ac = (struct acpi_ac *)seq->private;
+	struct acpi_ac *ac = seq->private;
 
 
 	if (!ac)
@@ -187,7 +187,7 @@
 
 static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_ac *ac = (struct acpi_ac *)data;
+	struct acpi_ac *ac = data;
 	struct acpi_device *device = NULL;
 
 
@@ -221,10 +221,9 @@
 	if (!device)
 		return -EINVAL;
 
-	ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
+	ac = kzalloc(sizeof(struct acpi_ac), GFP_KERNEL);
 	if (!ac)
 		return -ENOMEM;
-	memset(ac, 0, sizeof(struct acpi_ac));
 
 	ac->device = device;
 	strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
@@ -269,7 +268,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	ac = (struct acpi_ac *)acpi_driver_data(device);
+	ac = acpi_driver_data(device);
 
 	status = acpi_remove_notify_handler(device->handle,
 					    ACPI_ALL_NOTIFY, acpi_ac_notify);
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 6bcd9e8..cd946ed 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -395,10 +395,9 @@
 	if (!device)
 		return -EINVAL;
 
-	mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
+	mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
 	if (!mem_device)
 		return -ENOMEM;
-	memset(mem_device, 0, sizeof(struct acpi_memory_device));
 
 	INIT_LIST_HEAD(&mem_device->res_list);
 	mem_device->device = device;
@@ -429,7 +428,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	mem_device = (struct acpi_memory_device *)acpi_driver_data(device);
+	mem_device = acpi_driver_data(device);
 	kfree(mem_device);
 
 	return 0;
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index c7ac929..396140b 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <linux/backlight.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
@@ -402,6 +403,8 @@
 /* procdir we use */
 static struct proc_dir_entry *asus_proc_dir;
 
+static struct backlight_device *asus_backlight_device;
+
 /*
  * This header is made available to allow proper configuration given model,
  * revision number , ... this info cannot go in struct asus_hotk because it is
@@ -779,7 +782,7 @@
 	return rv;
 }
 
-static int read_brightness(void)
+static int read_brightness(struct backlight_device *bd)
 {
 	int value;
 
@@ -801,9 +804,10 @@
 /*
  * Change the brightness level
  */
-static void set_brightness(int value)
+static int set_brightness(int value)
 {
 	acpi_status status = 0;
+	int ret = 0;
 
 	/* SPLV laptop */
 	if (hotk->methods->brightness_set) {
@@ -811,11 +815,12 @@
 				    value, NULL))
 			printk(KERN_WARNING
 			       "Asus ACPI: Error changing brightness\n");
-		return;
+			ret = -EIO;
+		goto out;
 	}
 
 	/* No SPLV method if we are here, act as appropriate */
-	value -= read_brightness();
+	value -= read_brightness(NULL);
 	while (value != 0) {
 		status = acpi_evaluate_object(NULL, (value > 0) ?
 					      hotk->methods->brightness_up :
@@ -825,15 +830,22 @@
 		if (ACPI_FAILURE(status))
 			printk(KERN_WARNING
 			       "Asus ACPI: Error changing brightness\n");
+			ret = -EIO;
 	}
-	return;
+out:
+	return ret;
+}
+
+static int set_brightness_status(struct backlight_device *bd)
+{
+	return set_brightness(bd->props->brightness);
 }
 
 static int
 proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
 	      void *data)
 {
-	return sprintf(page, "%d\n", read_brightness());
+	return sprintf(page, "%d\n", read_brightness(NULL));
 }
 
 static int
@@ -1134,7 +1146,7 @@
 	if (ACPI_FAILURE(status))
 		printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
 	else
-		asus_info = (struct acpi_table_header *)dsdt.pointer;
+		asus_info = dsdt.pointer;
 
 	/* We have to write 0 on init this far for all ASUS models */
 	if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
@@ -1156,7 +1168,7 @@
 	 * asus_model_match() and try something completely different.
 	 */
 	if (buffer.pointer) {
-		model = (union acpi_object *)buffer.pointer;
+		model = buffer.pointer;
 		switch (model->type) {
 		case ACPI_TYPE_STRING:
 			string = model->string.pointer;
@@ -1252,11 +1264,9 @@
 	printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
 	       ASUS_ACPI_VERSION);
 
-	hotk =
-	    (struct asus_hotk *)kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+	hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
 	if (!hotk)
 		return -ENOMEM;
-	memset(hotk, 0, sizeof(struct asus_hotk));
 
 	hotk->handle = device->handle;
 	strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
@@ -1333,6 +1343,26 @@
 	return 0;
 }
 
+static struct backlight_properties asus_backlight_data = {
+        .owner          = THIS_MODULE,
+        .get_brightness = read_brightness,
+        .update_status  = set_brightness_status,
+        .max_brightness = 15,
+};
+
+static void __exit asus_acpi_exit(void)
+{
+	if (asus_backlight_device)
+		backlight_device_unregister(asus_backlight_device);
+
+	acpi_bus_unregister_driver(&asus_hotk_driver);
+	remove_proc_entry(PROC_ASUS, acpi_root_dir);
+
+	kfree(asus_info);
+
+	return;
+}
+
 static int __init asus_acpi_init(void)
 {
 	int result;
@@ -1370,18 +1400,16 @@
 		return result;
 	}
 
+	asus_backlight_device = backlight_device_register("asus",NULL,NULL,
+							  &asus_backlight_data);
+        if (IS_ERR(asus_backlight_device)) {
+		printk(KERN_ERR "Could not register asus backlight device\n");
+		asus_backlight_device = NULL;
+		asus_acpi_exit();
+	}
+
 	return 0;
 }
 
-static void __exit asus_acpi_exit(void)
-{
-	acpi_bus_unregister_driver(&asus_hotk_driver);
-	remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
-	kfree(asus_info);
-
-	return;
-}
-
 module_init(asus_acpi_init);
 module_exit(asus_acpi_exit);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 026e4075..5f43e0d 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -149,7 +149,7 @@
 		return -ENODEV;
 	}
 
-	package = (union acpi_object *)buffer.pointer;
+	package = buffer.pointer;
 
 	/* Extract Package Data */
 
@@ -160,12 +160,11 @@
 		goto end;
 	}
 
-	data.pointer = kmalloc(data.length, GFP_KERNEL);
+	data.pointer = kzalloc(data.length, GFP_KERNEL);
 	if (!data.pointer) {
 		result = -ENOMEM;
 		goto end;
 	}
-	memset(data.pointer, 0, data.length);
 
 	status = acpi_extract_package(package, &format, &data);
 	if (ACPI_FAILURE(status)) {
@@ -179,7 +178,7 @@
 	kfree(buffer.pointer);
 
 	if (!result)
-		(*bif) = (struct acpi_battery_info *)data.pointer;
+		(*bif) = data.pointer;
 
 	return result;
 }
@@ -209,7 +208,7 @@
 		return -ENODEV;
 	}
 
-	package = (union acpi_object *)buffer.pointer;
+	package = buffer.pointer;
 
 	/* Extract Package Data */
 
@@ -220,12 +219,11 @@
 		goto end;
 	}
 
-	data.pointer = kmalloc(data.length, GFP_KERNEL);
+	data.pointer = kzalloc(data.length, GFP_KERNEL);
 	if (!data.pointer) {
 		result = -ENOMEM;
 		goto end;
 	}
-	memset(data.pointer, 0, data.length);
 
 	status = acpi_extract_package(package, &format, &data);
 	if (ACPI_FAILURE(status)) {
@@ -239,7 +237,7 @@
 	kfree(buffer.pointer);
 
 	if (!result)
-		(*bst) = (struct acpi_battery_status *)data.pointer;
+		(*bst) = data.pointer;
 
 	return result;
 }
@@ -334,7 +332,7 @@
 static int acpi_battery_read_info(struct seq_file *seq, void *offset)
 {
 	int result = 0;
-	struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+	struct acpi_battery *battery = seq->private;
 	struct acpi_battery_info *bif = NULL;
 	char *units = "?";
 
@@ -418,7 +416,7 @@
 static int acpi_battery_read_state(struct seq_file *seq, void *offset)
 {
 	int result = 0;
-	struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+	struct acpi_battery *battery = seq->private;
 	struct acpi_battery_status *bst = NULL;
 	char *units = "?";
 
@@ -494,7 +492,7 @@
 
 static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
 {
-	struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+	struct acpi_battery *battery = seq->private;
 	char *units = "?";
 
 
@@ -531,8 +529,8 @@
 {
 	int result = 0;
 	char alarm_string[12] = { '\0' };
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_battery *battery = (struct acpi_battery *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_battery *battery = m->private;
 
 
 	if (!battery || (count > sizeof(alarm_string) - 1))
@@ -658,7 +656,7 @@
 
 static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_battery *battery = (struct acpi_battery *)data;
+	struct acpi_battery *battery = data;
 	struct acpi_device *device = NULL;
 
 
@@ -694,10 +692,9 @@
 	if (!device)
 		return -EINVAL;
 
-	battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL);
+	battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
 	if (!battery)
 		return -ENOMEM;
-	memset(battery, 0, sizeof(struct acpi_battery));
 
 	battery->device = device;
 	strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
@@ -742,7 +739,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	battery = (struct acpi_battery *)acpi_driver_data(device);
+	battery = acpi_driver_data(device);
 
 	status = acpi_remove_notify_handler(device->handle,
 					    ACPI_ALL_NOTIFY,
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 5ef885e..ac86058 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -29,6 +29,7 @@
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/input.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -62,7 +63,7 @@
 #define _COMPONENT		ACPI_BUTTON_COMPONENT
 ACPI_MODULE_NAME("acpi_button")
 
-    MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
@@ -78,12 +79,14 @@
 	.ops = {
 		.add = acpi_button_add,
 		.remove = acpi_button_remove,
-		},
+	},
 };
 
 struct acpi_button {
 	struct acpi_device *device;	/* Fixed button kludge */
-	u8 type;
+	unsigned int type;
+	struct input_dev *input;
+	char phys[32];			/* for input device */
 	unsigned long pushed;
 };
 
@@ -109,8 +112,7 @@
 
 static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_button *button = (struct acpi_button *)seq->private;
-
+	struct acpi_button *button = seq->private;
 
 	if (!button || !button->device)
 		return 0;
@@ -128,22 +130,17 @@
 
 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_button *button = (struct acpi_button *)seq->private;
+	struct acpi_button *button = seq->private;
 	acpi_status status;
 	unsigned long state;
 
-
 	if (!button || !button->device)
 		return 0;
 
 	status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
-	if (ACPI_FAILURE(status)) {
-		seq_printf(seq, "state:      unsupported\n");
-	} else {
-		seq_printf(seq, "state:      %s\n",
-			   (state ? "open" : "closed"));
-	}
-
+	seq_printf(seq, "state:      %s\n",
+		   ACPI_FAILURE(status) ? "unsupported" :
+			(state ? "open" : "closed"));
 	return 0;
 }
 
@@ -159,8 +156,7 @@
 static int acpi_button_add_fs(struct acpi_device *device)
 {
 	struct proc_dir_entry *entry = NULL;
-	struct acpi_button *button = NULL;
-
+	struct acpi_button *button;
 
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
@@ -228,10 +224,8 @@
 
 static int acpi_button_remove_fs(struct acpi_device *device)
 {
-	struct acpi_button *button = NULL;
+	struct acpi_button *button = acpi_driver_data(device);
 
-
-	button = acpi_driver_data(device);
 	if (acpi_device_dir(device)) {
 		if (button->type == ACPI_BUTTON_TYPE_LID)
 			remove_proc_entry(ACPI_BUTTON_FILE_STATE,
@@ -253,14 +247,34 @@
 
 static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_button *button = (struct acpi_button *)data;
-
+	struct acpi_button *button = data;
+	struct input_dev *input;
 
 	if (!button || !button->device)
 		return;
 
 	switch (event) {
 	case ACPI_BUTTON_NOTIFY_STATUS:
+		input = button->input;
+
+		if (button->type == ACPI_BUTTON_TYPE_LID) {
+			struct acpi_handle *handle = button->device->handle;
+			unsigned long state;
+
+			if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
+								NULL, &state)))
+				input_report_switch(input, SW_LID, !state);
+
+		} else {
+			int keycode = test_bit(KEY_SLEEP, input->keybit) ?
+						KEY_SLEEP : KEY_POWER;
+
+			input_report_key(input, keycode, 1);
+			input_sync(input);
+			input_report_key(input, keycode, 0);
+		}
+		input_sync(input);
+
 		acpi_bus_generate_event(button->device, event,
 					++button->pushed);
 		break;
@@ -275,8 +289,7 @@
 
 static acpi_status acpi_button_notify_fixed(void *data)
 {
-	struct acpi_button *button = (struct acpi_button *)data;
-
+	struct acpi_button *button = data;
 
 	if (!button)
 		return AE_BAD_PARAMETER;
@@ -286,24 +299,75 @@
 	return AE_OK;
 }
 
+static int acpi_button_install_notify_handlers(struct acpi_button *button)
+{
+	acpi_status status;
+
+	switch (button->type) {
+	case ACPI_BUTTON_TYPE_POWERF:
+		status =
+		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+						     acpi_button_notify_fixed,
+						     button);
+		break;
+	case ACPI_BUTTON_TYPE_SLEEPF:
+		status =
+		    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+						     acpi_button_notify_fixed,
+						     button);
+		break;
+	default:
+		status = acpi_install_notify_handler(button->device->handle,
+						     ACPI_DEVICE_NOTIFY,
+						     acpi_button_notify,
+						     button);
+		break;
+	}
+
+	return ACPI_FAILURE(status) ? -ENODEV : 0;
+}
+
+static void acpi_button_remove_notify_handlers(struct acpi_button *button)
+{
+	switch (button->type) {
+	case ACPI_BUTTON_TYPE_POWERF:
+		acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+						acpi_button_notify_fixed);
+		break;
+	case ACPI_BUTTON_TYPE_SLEEPF:
+		acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+						acpi_button_notify_fixed);
+		break;
+	default:
+		acpi_remove_notify_handler(button->device->handle,
+					   ACPI_DEVICE_NOTIFY,
+					   acpi_button_notify);
+		break;
+	}
+}
+
 static int acpi_button_add(struct acpi_device *device)
 {
-	int result = 0;
-	acpi_status status = AE_OK;
-	struct acpi_button *button = NULL;
-
+	int error;
+	struct acpi_button *button;
+	struct input_dev *input;
 
 	if (!device)
 		return -EINVAL;
 
-	button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
+	button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
 	if (!button)
 		return -ENOMEM;
-	memset(button, 0, sizeof(struct acpi_button));
 
 	button->device = device;
 	acpi_driver_data(device) = button;
 
+	button->input = input = input_allocate_device();
+	if (!input) {
+		error = -ENOMEM;
+		goto err_free_button;
+	}
+
 	/*
 	 * Determine the button type (via hid), as fixed-feature buttons
 	 * need to be handled a bit differently than generic-space.
@@ -338,39 +402,48 @@
 	} else {
 		printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
 			    acpi_device_hid(device));
-		result = -ENODEV;
-		goto end;
+		error = -ENODEV;
+		goto err_free_input;
 	}
 
-	result = acpi_button_add_fs(device);
-	if (result)
-		goto end;
+	error = acpi_button_add_fs(device);
+	if (error)
+		goto err_free_input;
+
+	error = acpi_button_install_notify_handlers(button);
+	if (error)
+		goto err_remove_fs;
+
+	snprintf(button->phys, sizeof(button->phys),
+		 "%s/button/input0", acpi_device_hid(device));
+
+	input->name = acpi_device_name(device);
+	input->phys = button->phys;
+	input->id.bustype = BUS_HOST;
+	input->id.product = button->type;
 
 	switch (button->type) {
+	case ACPI_BUTTON_TYPE_POWER:
 	case ACPI_BUTTON_TYPE_POWERF:
-		status =
-		    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-						     acpi_button_notify_fixed,
-						     button);
+		input->evbit[0] = BIT(EV_KEY);
+		set_bit(KEY_POWER, input->keybit);
 		break;
+
+	case ACPI_BUTTON_TYPE_SLEEP:
 	case ACPI_BUTTON_TYPE_SLEEPF:
-		status =
-		    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-						     acpi_button_notify_fixed,
-						     button);
+		input->evbit[0] = BIT(EV_KEY);
+		set_bit(KEY_SLEEP, input->keybit);
 		break;
-	default:
-		status = acpi_install_notify_handler(device->handle,
-						     ACPI_DEVICE_NOTIFY,
-						     acpi_button_notify,
-						     button);
+
+	case ACPI_BUTTON_TYPE_LID:
+		input->evbit[0] = BIT(EV_SW);
+		set_bit(SW_LID, input->swbit);
 		break;
 	}
 
-	if (ACPI_FAILURE(status)) {
-		result = -ENODEV;
-		goto end;
-	}
+	error = input_register_device(input);
+	if (error)
+		goto err_remove_handlers;
 
 	if (device->wakeup.flags.valid) {
 		/* Button's GPE is run-wake GPE */
@@ -385,47 +458,31 @@
 	printk(KERN_INFO PREFIX "%s [%s]\n",
 	       acpi_device_name(device), acpi_device_bid(device));
 
-      end:
-	if (result) {
-		acpi_button_remove_fs(device);
-		kfree(button);
-	}
+	return 0;
 
-	return result;
+ err_remove_handlers:
+	acpi_button_remove_notify_handlers(button);
+ err_remove_fs:
+	acpi_button_remove_fs(device);
+ err_free_input:
+	input_free_device(input);
+ err_free_button:
+	kfree(button);
+	return error;
 }
 
 static int acpi_button_remove(struct acpi_device *device, int type)
 {
-	acpi_status status = 0;
-	struct acpi_button *button = NULL;
-
+	struct acpi_button *button;
 
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
 	button = acpi_driver_data(device);
 
-	/* Unregister for device notifications. */
-	switch (button->type) {
-	case ACPI_BUTTON_TYPE_POWERF:
-		status =
-		    acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-						    acpi_button_notify_fixed);
-		break;
-	case ACPI_BUTTON_TYPE_SLEEPF:
-		status =
-		    acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-						    acpi_button_notify_fixed);
-		break;
-	default:
-		status = acpi_remove_notify_handler(device->handle,
-						    ACPI_DEVICE_NOTIFY,
-						    acpi_button_notify);
-		break;
-	}
-
+	acpi_button_remove_notify_handlers(button);
 	acpi_button_remove_fs(device);
-
+	input_unregister_device(button->input);
 	kfree(button);
 
 	return 0;
@@ -433,8 +490,7 @@
 
 static int __init acpi_button_init(void)
 {
-	int result = 0;
-
+	int result;
 
 	acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
 	if (!acpi_button_dir)
@@ -451,7 +507,6 @@
 
 static void __exit acpi_button_exit(void)
 {
-
 	acpi_bus_unregister_driver(&acpi_button_driver);
 
 	if (acpi_power_dir)
@@ -461,8 +516,6 @@
 	if (acpi_lid_dir)
 		remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
 	remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
-
-	return;
 }
 
 module_init(acpi_button_init);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 871aa52..0a1863e 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -96,11 +96,10 @@
 		return -EINVAL;
 	}
 
-	container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
+	container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
 	if (!container)
 		return -ENOMEM;
 
-	memset(container, 0, sizeof(struct acpi_container));
 	container->handle = device->handle;
 	strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
@@ -117,7 +116,7 @@
 	acpi_status status = AE_OK;
 	struct acpi_container *pc = NULL;
 
-	pc = (struct acpi_container *)acpi_driver_data(device);
+	pc = acpi_driver_data(device);
 	kfree(pc);
 	return status;
 }
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index bf5b79e..90990a4 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/notifier.h>
+#include <linux/platform_device.h>
 #include <linux/jiffies.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
@@ -39,13 +40,15 @@
 MODULE_LICENSE("GPL");
 
 static struct atomic_notifier_head dock_notifier_list;
+static struct platform_device dock_device;
+static char dock_device_name[] = "dock";
 
 struct dock_station {
 	acpi_handle handle;
 	unsigned long last_dock_time;
 	u32 flags;
 	spinlock_t dd_lock;
-	spinlock_t hp_lock;
+	struct mutex hp_lock;
 	struct list_head dependent_devices;
 	struct list_head hotplug_devices;
 };
@@ -115,9 +118,9 @@
 dock_add_hotplug_device(struct dock_station *ds,
 			struct dock_dependent_device *dd)
 {
-	spin_lock(&ds->hp_lock);
+	mutex_lock(&ds->hp_lock);
 	list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
-	spin_unlock(&ds->hp_lock);
+	mutex_unlock(&ds->hp_lock);
 }
 
 /**
@@ -131,9 +134,9 @@
 dock_del_hotplug_device(struct dock_station *ds,
 			struct dock_dependent_device *dd)
 {
-	spin_lock(&ds->hp_lock);
+	mutex_lock(&ds->hp_lock);
 	list_del(&dd->hotplug_list);
-	spin_unlock(&ds->hp_lock);
+	mutex_unlock(&ds->hp_lock);
 }
 
 /**
@@ -296,7 +299,7 @@
 {
 	struct dock_dependent_device *dd;
 
-	spin_lock(&ds->hp_lock);
+	mutex_lock(&ds->hp_lock);
 
 	/*
 	 * First call driver specific hotplug functions
@@ -318,15 +321,17 @@
 		else
 			dock_create_acpi_device(dd->handle);
 	}
-	spin_unlock(&ds->hp_lock);
+	mutex_unlock(&ds->hp_lock);
 }
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
 {
+	struct device *dev = &dock_device.dev;
 	/*
-	 * we don't do events until someone tells me that
-	 * they would like to have them.
+	 * Indicate that the status of the dock station has
+	 * changed.
 	 */
+	kobject_uevent(&dev->kobj, KOBJ_CHANGE);
 }
 
 /**
@@ -441,6 +446,9 @@
  */
 int register_dock_notifier(struct notifier_block *nb)
 {
+	if (!dock_station)
+		return -ENODEV;
+
 	return atomic_notifier_chain_register(&dock_notifier_list, nb);
 }
 
@@ -452,6 +460,9 @@
  */
 void unregister_dock_notifier(struct notifier_block *nb)
 {
+	if (!dock_station)
+		return;
+
 	atomic_notifier_chain_unregister(&dock_notifier_list, nb);
 }
 
@@ -512,6 +523,37 @@
 EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
 
 /**
+ * handle_eject_request - handle an undock request checking for error conditions
+ *
+ * Check to make sure the dock device is still present, then undock and
+ * hotremove all the devices that may need removing.
+ */
+static int handle_eject_request(struct dock_station *ds, u32 event)
+{
+	if (!dock_present(ds))
+		return -ENODEV;
+
+	if (dock_in_progress(ds))
+		return -EBUSY;
+
+	/*
+	 * here we need to generate the undock
+	 * event prior to actually doing the undock
+	 * so that the device struct still exists.
+	 */
+	dock_event(ds, event, UNDOCK_EVENT);
+	hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+	undock(ds);
+	eject_dock(ds);
+	if (dock_present(ds)) {
+		printk(KERN_ERR PREFIX "Unable to undock!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/**
  * dock_notify - act upon an acpi dock notification
  * @handle: the dock station handle
  * @event: the acpi event
@@ -519,13 +561,11 @@
  *
  * If we are notified to dock, then check to see if the dock is
  * present and then dock.  Notify all drivers of the dock event,
- * and then hotplug and devices that may need hotplugging.  For undock
- * check to make sure the dock device is still present, then undock
- * and hotremove all the devices that may need removing.
+ * and then hotplug and devices that may need hotplugging.
  */
 static void dock_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct dock_station *ds = (struct dock_station *)data;
+	struct dock_station *ds = data;
 
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
@@ -553,19 +593,7 @@
 	 * to the driver who wish to hotplug.
          */
 	case ACPI_NOTIFY_EJECT_REQUEST:
-		if (!dock_in_progress(ds) && dock_present(ds)) {
-			/*
-			 * here we need to generate the undock
-			 * event prior to actually doing the undock
-			 * so that the device struct still exists.
-			 */
-			dock_event(ds, event, UNDOCK_EVENT);
-			hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
-			undock(ds);
-			eject_dock(ds);
-			if (dock_present(ds))
-				printk(KERN_ERR PREFIX "Unable to undock!\n");
-		}
+		handle_eject_request(ds, event);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -588,7 +616,7 @@
 {
 	acpi_status status;
 	acpi_handle tmp;
-	struct dock_station *ds = (struct dock_station *)context;
+	struct dock_station *ds = context;
 	struct dock_dependent_device *dd;
 
 	status = acpi_bus_get_ejd(handle, &tmp);
@@ -604,6 +632,33 @@
 	return AE_OK;
 }
 
+/*
+ * show_docked - read method for "docked" file in sysfs
+ */
+static ssize_t show_docked(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
+
+}
+DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
+
+/*
+ * write_undock - write method for "undock" file in sysfs
+ */
+static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	int ret;
+
+	if (!count)
+		return -EINVAL;
+
+	ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
+	return ret ? ret: count;
+}
+DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+
 /**
  * dock_add - add a new dock station
  * @handle: the dock station handle
@@ -626,9 +681,33 @@
 	INIT_LIST_HEAD(&dock_station->dependent_devices);
 	INIT_LIST_HEAD(&dock_station->hotplug_devices);
 	spin_lock_init(&dock_station->dd_lock);
-	spin_lock_init(&dock_station->hp_lock);
+	mutex_init(&dock_station->hp_lock);
 	ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 
+	/* initialize platform device stuff */
+	dock_device.name = dock_device_name;
+	ret = platform_device_register(&dock_device);
+	if (ret) {
+		printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+		kfree(dock_station);
+		return ret;
+	}
+	ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+	if (ret) {
+		printk("Error %d adding sysfs file\n", ret);
+		platform_device_unregister(&dock_device);
+		kfree(dock_station);
+		return ret;
+	}
+	ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+	if (ret) {
+		printk("Error %d adding sysfs file\n", ret);
+		device_remove_file(&dock_device.dev, &dev_attr_docked);
+		platform_device_unregister(&dock_device);
+		kfree(dock_station);
+		return ret;
+	}
+
 	/* Find dependent devices */
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 			    ACPI_UINT32_MAX, find_dock_devices, dock_station,
@@ -638,7 +717,8 @@
 	dd = alloc_dock_dependent_device(handle);
 	if (!dd) {
 		kfree(dock_station);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto dock_add_err_unregister;
 	}
 	add_dock_dependent_device(dock_station, dd);
 
@@ -658,8 +738,12 @@
 	return 0;
 
 dock_add_err:
-	kfree(dock_station);
 	kfree(dd);
+dock_add_err_unregister:
+	device_remove_file(&dock_device.dev, &dev_attr_docked);
+	device_remove_file(&dock_device.dev, &dev_attr_undock);
+	platform_device_unregister(&dock_device);
+	kfree(dock_station);
 	return ret;
 }
 
@@ -686,6 +770,11 @@
 	if (ACPI_FAILURE(status))
 		printk(KERN_ERR "Error removing notify handler\n");
 
+	/* cleanup sysfs */
+	device_remove_file(&dock_device.dev, &dev_attr_docked);
+	device_remove_file(&dock_device.dev, &dev_attr_undock);
+	platform_device_unregister(&dock_device);
+
 	/* free dock station memory */
 	kfree(dock_station);
 	return 0;
@@ -703,7 +792,7 @@
 static acpi_status
 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
-	int *count = (int *)context;
+	int *count = context;
 	acpi_status status = AE_OK;
 
 	if (is_dock(handle)) {
@@ -726,7 +815,7 @@
 			    ACPI_UINT32_MAX, find_dock, &num, NULL);
 
 	if (!num)
-		return -ENODEV;
+		printk(KERN_INFO "No dock devices found.\n");
 
 	return 0;
 }
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e6d4b08..9c52d87 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -45,35 +45,34 @@
 #define ACPI_EC_DRIVER_NAME		"ACPI Embedded Controller Driver"
 #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
 #define ACPI_EC_FILE_INFO		"info"
-
+#undef PREFIX
+#define PREFIX				"ACPI: EC: "
 /* EC status register */
 #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
 #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
 #define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
 #define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
-
 /* EC commands */
-#define ACPI_EC_COMMAND_READ	0x80
-#define ACPI_EC_COMMAND_WRITE	0x81
-#define ACPI_EC_BURST_ENABLE	0x82
-#define ACPI_EC_BURST_DISABLE	0x83
-#define ACPI_EC_COMMAND_QUERY	0x84
-
+enum ec_command {
+	ACPI_EC_COMMAND_READ = 0x80,
+	ACPI_EC_COMMAND_WRITE = 0x81,
+	ACPI_EC_BURST_ENABLE = 0x82,
+	ACPI_EC_BURST_DISABLE = 0x83,
+	ACPI_EC_COMMAND_QUERY = 0x84,
+};
 /* EC events */
-enum {
+enum ec_event {
 	ACPI_EC_EVENT_OBF_1 = 1,	/* Output buffer full */
-	ACPI_EC_EVENT_IBF_0,		/* Input buffer empty */
+	ACPI_EC_EVENT_IBF_0,	/* Input buffer empty */
 };
 
-#define ACPI_EC_DELAY		50	/* Wait 50ms max. during EC ops */
+#define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
-#define ACPI_EC_UDELAY         100	/* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT   1000	/* Wait 10ms max. during EC ops */
 
-enum {
-	EC_INTR = 1,	/* Output buffer full */
-	EC_POLL,	/* Input buffer empty */
-};
+static enum ec_mode {
+	EC_INTR = 1,		/* Output buffer full */
+	EC_POLL,		/* Input buffer empty */
+} acpi_ec_mode = EC_INTR;
 
 static int acpi_ec_remove(struct acpi_device *device, int type);
 static int acpi_ec_start(struct acpi_device *device);
@@ -93,22 +92,21 @@
 };
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
-struct acpi_ec {
+static struct acpi_ec {
 	acpi_handle handle;
 	unsigned long uid;
-	unsigned long gpe_bit;
+	unsigned long gpe;
 	unsigned long command_addr;
 	unsigned long data_addr;
 	unsigned long global_lock;
-	struct semaphore sem;
-	unsigned int expect_event;
+	struct mutex lock;
+	atomic_t query_pending;
 	atomic_t leaving_burst;	/* 0 : No, 1 : Yes, 2: abort */
 	wait_queue_head_t wait;
 } *ec_ecdt;
 
 /* External interfaces use first EC only, so remember */
 static struct acpi_device *first_ec;
-static int acpi_ec_mode = EC_INTR;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -134,54 +132,41 @@
 	outb(data, ec->data_addr);
 }
 
-static int acpi_ec_check_status(u8 status, u8 event)
+static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
 {
-	switch (event) {
-	case ACPI_EC_EVENT_OBF_1:
+	u8 status = acpi_ec_read_status(ec);
+
+	if (event == ACPI_EC_EVENT_OBF_1) {
 		if (status & ACPI_EC_FLAG_OBF)
 			return 1;
-		break;
-	case ACPI_EC_EVENT_IBF_0:
+	} else if (event == ACPI_EC_EVENT_IBF_0) {
 		if (!(status & ACPI_EC_FLAG_IBF))
 			return 1;
-		break;
-	default:
-		break;
 	}
 
 	return 0;
 }
 
-static int acpi_ec_wait(struct acpi_ec *ec, u8 event)
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event)
 {
-	int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0;
-	long time_left;
-
-	ec->expect_event = event;
-	if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
-		ec->expect_event = 0;
-		return 0;
-	}
-
-	do {
-		if (acpi_ec_mode == EC_POLL) {
-			udelay(ACPI_EC_UDELAY);
-		} else {
-			time_left = wait_event_timeout(ec->wait,
-				    !ec->expect_event,
-				    msecs_to_jiffies(ACPI_EC_DELAY));
-			if (time_left > 0) {
-				ec->expect_event = 0;
+	if (acpi_ec_mode == EC_POLL) {
+		unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+		while (time_before(jiffies, delay)) {
+			if (acpi_ec_check_status(ec, event))
 				return 0;
-			}
 		}
-		if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
-			ec->expect_event = 0;
+	} else {
+		if (wait_event_timeout(ec->wait,
+				       acpi_ec_check_status(ec, event),
+				       msecs_to_jiffies(ACPI_EC_DELAY)) ||
+		    acpi_ec_check_status(ec, event)) {
 			return 0;
+		} else {
+			printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
+			       " status = %d, expect_event = %d\n",
+			       acpi_ec_read_status(ec), event);
 		}
-	} while (--i > 0);
-
-	ec->expect_event = 0;
+	}
 
 	return -ETIME;
 }
@@ -196,7 +181,6 @@
 	u8 tmp = 0;
 	u8 status = 0;
 
-
 	status = acpi_ec_read_status(ec);
 	if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
 		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
@@ -212,7 +196,7 @@
 
 	atomic_set(&ec->leaving_burst, 0);
 	return 0;
-  end:
+      end:
 	ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
 	return -1;
 }
@@ -221,58 +205,68 @@
 {
 	u8 status = 0;
 
-
 	status = acpi_ec_read_status(ec);
-	if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
+	if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
 		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
-		if(status)
+		if (status)
 			goto end;
 		acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
 		acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
 	}
 	atomic_set(&ec->leaving_burst, 1);
 	return 0;
-  end:
+      end:
 	ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
 	return -1;
 }
-#endif /* ACPI_FUTURE_USAGE */
+#endif				/* ACPI_FUTURE_USAGE */
 
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
-					const u8 *wdata, unsigned wdata_len,
-					u8 *rdata, unsigned rdata_len)
+					const u8 * wdata, unsigned wdata_len,
+					u8 * rdata, unsigned rdata_len)
 {
-	int result;
+	int result = 0;
 
 	acpi_ec_write_cmd(ec, command);
 
-	for (; wdata_len > 0; wdata_len --) {
+	for (; wdata_len > 0; --wdata_len) {
 		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
-		if (result)
-			return result;
+		if (result) {
+			printk(KERN_ERR PREFIX
+			       "write_cmd timeout, command = %d\n", command);
+			goto end;
+		}
 		acpi_ec_write_data(ec, *(wdata++));
 	}
 
-	if (command == ACPI_EC_COMMAND_WRITE) {
+	if (!rdata_len) {
 		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
-		if (result)
-			return result;
+		if (result) {
+			printk(KERN_ERR PREFIX
+			       "finish-write timeout, command = %d\n", command);
+			goto end;
+		}
+	} else if (command == ACPI_EC_COMMAND_QUERY) {
+		atomic_set(&ec->query_pending, 0);
 	}
 
-	for (; rdata_len > 0; rdata_len --) {
+	for (; rdata_len > 0; --rdata_len) {
 		result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
-		if (result)
-			return result;
+		if (result) {
+			printk(KERN_ERR PREFIX "read timeout, command = %d\n",
+			       command);
+			goto end;
+		}
 
 		*(rdata++) = acpi_ec_read_data(ec);
 	}
-
-	return 0;
+      end:
+	return result;
 }
 
 static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
-				const u8 *wdata, unsigned wdata_len,
-				u8 *rdata, unsigned rdata_len)
+			       const u8 * wdata, unsigned wdata_len,
+			       u8 * rdata, unsigned rdata_len)
 {
 	int status;
 	u32 glk;
@@ -280,36 +274,40 @@
 	if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
 		return -EINVAL;
 
-        if (rdata)
-                memset(rdata, 0, rdata_len);
+	if (rdata)
+		memset(rdata, 0, rdata_len);
 
+	mutex_lock(&ec->lock);
 	if (ec->global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status))
 			return -ENODEV;
 	}
-	down(&ec->sem);
+
+	/* Make sure GPE is enabled before doing transaction */
+	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
 	if (status) {
-		printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
+		printk(KERN_DEBUG PREFIX
+		       "input buffer is not empty, aborting transaction\n");
 		goto end;
 	}
 
-        status = acpi_ec_transaction_unlocked(ec, command,
-                                              wdata, wdata_len,
-                                              rdata, rdata_len);
+	status = acpi_ec_transaction_unlocked(ec, command,
+					      wdata, wdata_len,
+					      rdata, rdata_len);
 
-end:
-	up(&ec->sem);
+      end:
 
 	if (ec->global_lock)
 		acpi_release_global_lock(glk);
+	mutex_unlock(&ec->lock);
 
 	return status;
 }
 
-static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
 {
 	int result;
 	u8 d;
@@ -322,15 +320,15 @@
 
 static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
 {
-        u8 wdata[2] = { address, data };
-        return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
+	u8 wdata[2] = { address, data };
+	return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
 				   wdata, 2, NULL, 0);
 }
 
 /*
  * Externally callable EC access functions. For now, assume 1 EC only
  */
-int ec_read(u8 addr, u8 *val)
+int ec_read(u8 addr, u8 * val)
 {
 	struct acpi_ec *ec;
 	int err;
@@ -369,9 +367,9 @@
 
 EXPORT_SYMBOL(ec_write);
 
-extern int ec_transaction(u8 command,
-                          const u8 *wdata, unsigned wdata_len,
-                          u8 *rdata, unsigned rdata_len)
+int ec_transaction(u8 command,
+			  const u8 * wdata, unsigned wdata_len,
+			  u8 * rdata, unsigned rdata_len)
 {
 	struct acpi_ec *ec;
 
@@ -386,65 +384,49 @@
 
 EXPORT_SYMBOL(ec_transaction);
 
-static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
+static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
 {
 	int result;
-        u8 d;
+	u8 d;
 
-        if (!ec || !data)
-                return -EINVAL;
+	if (!ec || !data)
+		return -EINVAL;
 
-        /*
-         * Query the EC to find out which _Qxx method we need to evaluate.
-         * Note that successful completion of the query causes the ACPI_EC_SCI
-         * bit to be cleared (and thus clearing the interrupt source).
-         */
+	/*
+	 * Query the EC to find out which _Qxx method we need to evaluate.
+	 * Note that successful completion of the query causes the ACPI_EC_SCI
+	 * bit to be cleared (and thus clearing the interrupt source).
+	 */
 
-        result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
-        if (result)
-                return result;
+	result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+	if (result)
+		return result;
 
-        if (!d)
-                return -ENODATA;
+	if (!d)
+		return -ENODATA;
 
-        *data = d;
-        return 0;
+	*data = d;
+	return 0;
 }
 
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
 
-struct acpi_ec_query_data {
-	acpi_handle handle;
-	u8 data;
-};
-
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
 	struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
 	u8 value = 0;
-	static char object_name[8];
+	char object_name[8];
 
-	if (!ec)
-		goto end;
-
-	value = acpi_ec_read_status(ec);
-
-	if (!(value & ACPI_EC_FLAG_SCI))
-		goto end;
-
-	if (acpi_ec_query(ec, &value))
-		goto end;
+	if (!ec || acpi_ec_query(ec, &value))
+		return;
 
 	snprintf(object_name, 8, "_Q%2.2X", value);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
+	printk(KERN_INFO PREFIX "evaluating %s\n", object_name);
 
 	acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
-
-      end:
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 }
 
 static u32 acpi_ec_gpe_handler(void *data)
@@ -453,22 +435,18 @@
 	u8 value;
 	struct acpi_ec *ec = (struct acpi_ec *)data;
 
-	acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR);
-	value = acpi_ec_read_status(ec);
-
 	if (acpi_ec_mode == EC_INTR) {
-		if (acpi_ec_check_status(value, ec->expect_event)) {
-			ec->expect_event = 0;
-			wake_up(&ec->wait);
-		}
+		wake_up(&ec->wait);
 	}
 
-	if (value & ACPI_EC_FLAG_SCI) {
-		status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
-		return status == AE_OK ?
-		    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
+	value = acpi_ec_read_status(ec);
+	if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
+		atomic_set(&ec->query_pending, 1);
+		status =
+		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
+				    ec);
 	}
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+
 	return status == AE_OK ?
 	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 }
@@ -504,7 +482,6 @@
 	acpi_integer f_v = 0;
 	int i = 0;
 
-
 	if ((address > 0xFF) || !value || !handler_context)
 		return AE_BAD_PARAMETER;
 
@@ -518,7 +495,7 @@
 	switch (function) {
 	case ACPI_READ:
 		temp = 0;
-		result = acpi_ec_read(ec, (u8) address, (u8 *) &temp);
+		result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
 		break;
 	case ACPI_WRITE:
 		result = acpi_ec_write(ec, (u8) address, (u8) temp);
@@ -571,18 +548,15 @@
 {
 	struct acpi_ec *ec = (struct acpi_ec *)seq->private;
 
-
 	if (!ec)
 		goto end;
 
-	seq_printf(seq, "gpe bit:                 0x%02x\n",
-		   (u32) ec->gpe_bit);
+	seq_printf(seq, "gpe:                 0x%02x\n", (u32) ec->gpe);
 	seq_printf(seq, "ports:                   0x%02x, 0x%02x\n",
-		   (u32) ec->command_addr,
-		   (u32) ec->data_addr);
+		   (u32) ec->command_addr, (u32) ec->data_addr);
 	seq_printf(seq, "use global lock:         %s\n",
 		   ec->global_lock ? "yes" : "no");
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 
       end:
 	return 0;
@@ -605,7 +579,6 @@
 {
 	struct proc_dir_entry *entry = NULL;
 
-
 	if (!acpi_device_dir(device)) {
 		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
 						     acpi_ec_dir);
@@ -648,18 +621,17 @@
 	acpi_status status = AE_OK;
 	struct acpi_ec *ec = NULL;
 
-
 	if (!device)
 		return -EINVAL;
 
-	ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec)
 		return -ENOMEM;
-	memset(ec, 0, sizeof(struct acpi_ec));
 
 	ec->handle = device->handle;
 	ec->uid = -1;
-	init_MUTEX(&ec->sem);
+	mutex_init(&ec->lock);
+	atomic_set(&ec->query_pending, 0);
 	if (acpi_ec_mode == EC_INTR) {
 		atomic_set(&ec->leaving_burst, 1);
 		init_waitqueue_head(&ec->wait);
@@ -669,8 +641,7 @@
 	acpi_driver_data(device) = ec;
 
 	/* Use the global lock for all EC transactions? */
-	acpi_evaluate_integer(ec->handle, "_GLK", NULL,
-			      &ec->global_lock);
+	acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
 
 	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
 	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
@@ -679,7 +650,7 @@
 						  ACPI_ADR_SPACE_EC,
 						  &acpi_ec_space_handler);
 
-		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
 					&acpi_ec_gpe_handler);
 
 		kfree(ec_ecdt);
@@ -687,11 +658,10 @@
 
 	/* Get GPE bit assignment (EC events). */
 	/* TODO: Add support for _GPE returning a package */
-	status =
-	    acpi_evaluate_integer(ec->handle, "_GPE", NULL,
-				  &ec->gpe_bit);
+	status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
 	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment"));
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Obtaining GPE bit assignment"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -701,13 +671,13 @@
 		goto end;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
-	       acpi_device_name(device), acpi_device_bid(device),
-	       (u32) ec->gpe_bit));
+			  acpi_device_name(device), acpi_device_bid(device),
+			  (u32) ec->gpe));
 
 	if (!first_ec)
 		first_ec = device;
 
-  end:
+      end:
 	if (result)
 		kfree(ec);
 
@@ -718,7 +688,6 @@
 {
 	struct acpi_ec *ec = NULL;
 
-
 	if (!device)
 		return -EINVAL;
 
@@ -761,7 +730,6 @@
 	acpi_status status = AE_OK;
 	struct acpi_ec *ec = NULL;
 
-
 	if (!device)
 		return -EINVAL;
 
@@ -782,27 +750,26 @@
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
-			  ec->gpe_bit, ec->command_addr, ec->data_addr));
+			  ec->gpe, ec->command_addr, ec->data_addr));
 
 	/*
 	 * Install GPE handler
 	 */
-	status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
+	status = acpi_install_gpe_handler(NULL, ec->gpe,
 					  ACPI_GPE_EDGE_TRIGGERED,
 					  &acpi_ec_gpe_handler, ec);
 	if (ACPI_FAILURE(status)) {
 		return -ENODEV;
 	}
-	acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
+	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 
 	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
 						    &acpi_ec_space_setup, ec);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec->gpe_bit,
-					&acpi_ec_gpe_handler);
+		acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
 		return -ENODEV;
 	}
 
@@ -814,7 +781,6 @@
 	acpi_status status = AE_OK;
 	struct acpi_ec *ec = NULL;
 
-
 	if (!device)
 		return -EINVAL;
 
@@ -826,9 +792,7 @@
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	status =
-	    acpi_remove_gpe_handler(NULL, ec->gpe_bit,
-				    &acpi_ec_gpe_handler);
+	status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
@@ -841,7 +805,7 @@
 {
 	acpi_status status;
 
-	init_MUTEX(&ec_ecdt->sem);
+	mutex_init(&ec_ecdt->lock);
 	if (acpi_ec_mode == EC_INTR) {
 		init_waitqueue_head(&ec_ecdt->wait);
 	}
@@ -853,16 +817,15 @@
 	ec_ecdt->uid = -1;
 	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
 
-	status =
-	    acpi_evaluate_integer(handle, "_GPE", NULL,
-				  &ec_ecdt->gpe_bit);
+	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
 	if (ACPI_FAILURE(status))
 		return status;
 	ec_ecdt->global_lock = TRUE;
 	ec_ecdt->handle = handle;
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
-	       ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr));
+			  ec_ecdt->gpe, ec_ecdt->command_addr,
+			  ec_ecdt->data_addr));
 
 	return AE_CTRL_TERMINATE;
 }
@@ -884,12 +847,11 @@
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
 
-	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec_ecdt) {
 		ret = -ENOMEM;
 		goto error;
 	}
-	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
 
 	status = acpi_get_devices(ACPI_EC_HID,
 				  acpi_fake_ecdt_callback, NULL, NULL);
@@ -901,7 +863,7 @@
 		goto error;
 	}
 	return 0;
-  error:
+      error:
 	return ret;
 }
 
@@ -921,30 +883,28 @@
 	/*
 	 * Generate a temporary ec context to use until the namespace is scanned
 	 */
-	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec_ecdt)
 		return -ENOMEM;
-	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
 
-	init_MUTEX(&ec_ecdt->sem);
+	mutex_init(&ec_ecdt->lock);
 	if (acpi_ec_mode == EC_INTR) {
 		init_waitqueue_head(&ec_ecdt->wait);
 	}
 	ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
 	ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
-	ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
+	ec_ecdt->gpe = ecdt_ptr->gpe_bit;
 	/* use the GL just to be safe */
 	ec_ecdt->global_lock = TRUE;
 	ec_ecdt->uid = ecdt_ptr->uid;
 
-	status =
-	    acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+	status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
 	if (ACPI_FAILURE(status)) {
 		goto error;
 	}
 
 	return 0;
-  error:
+      error:
 	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
 	kfree(ec_ecdt);
 	ec_ecdt = NULL;
@@ -970,14 +930,14 @@
 	/*
 	 * Install GPE handler
 	 */
-	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
+	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
 					  ACPI_GPE_EDGE_TRIGGERED,
 					  &acpi_ec_gpe_handler, ec_ecdt);
 	if (ACPI_FAILURE(status)) {
 		goto error;
 	}
-	acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
+	acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
+	acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
 
 	status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
 						    ACPI_ADR_SPACE_EC,
@@ -985,7 +945,7 @@
 						    &acpi_ec_space_setup,
 						    ec_ecdt);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
 					&acpi_ec_gpe_handler);
 		goto error;
 	}
@@ -1004,7 +964,6 @@
 {
 	int result = 0;
 
-
 	if (acpi_disabled)
 		return 0;
 
@@ -1057,7 +1016,8 @@
 		acpi_ec_mode = EC_POLL;
 	}
 	acpi_ec_driver.ops.add = acpi_ec_add;
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n",
+			  intr ? "interrupt" : "polling"));
 
 	return 1;
 }
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index ee2a10b..bf63edc 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -331,7 +331,6 @@
 static u32 acpi_ev_global_lock_handler(void *context)
 {
 	u8 acquired = FALSE;
-	acpi_status status;
 
 	/*
 	 * Attempt to get the lock
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 3a39c2e..bf90f04 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -266,10 +266,10 @@
 	     walk_state->thread->thread_id)
 	    && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
 		ACPI_ERROR((AE_INFO,
-			    "Thread %X cannot release Mutex [%4.4s] acquired by thread %X",
-			    (u32) walk_state->thread->thread_id,
+			    "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
+			    (unsigned long)walk_state->thread->thread_id,
 			    acpi_ut_get_node_name(obj_desc->mutex.node),
-			    (u32) obj_desc->mutex.owner_thread->thread_id));
+			    (unsigned long)obj_desc->mutex.owner_thread->thread_id));
 		return_ACPI_STATUS(AE_AML_NOT_OWNER);
 	}
 
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 045c894..f305a82 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -99,8 +99,8 @@
 		     size_t count, loff_t * ppos)
 {
 	int result = 0;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_fan *fan = (struct acpi_fan *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_fan *fan = m->private;
 	char state_string[12] = { '\0' };
 
 
@@ -186,10 +186,9 @@
 	if (!device)
 		return -EINVAL;
 
-	fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL);
+	fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL);
 	if (!fan)
 		return -ENOMEM;
-	memset(fan, 0, sizeof(struct acpi_fan));
 
 	fan->device = device;
 	strcpy(acpi_device_name(device), "Fan");
@@ -229,7 +228,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	fan = (struct acpi_fan *)acpi_driver_data(device);
+	fan = acpi_driver_data(device);
 
 	acpi_fan_remove_fs(device);
 
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index a2f46d5..8a0324b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -96,7 +96,7 @@
 static acpi_status
 do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
-	unsigned long *busnr = (unsigned long *)data;
+	unsigned long *busnr = data;
 	struct acpi_resource_address64 address;
 
 	if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
@@ -189,8 +189,12 @@
 	bus = tmp;
 
 	if (seg == find->seg && bus == find->bus)
+	{
 		find->handle = handle;
-	status = AE_OK;
+		status = AE_CTRL_TERMINATE;
+	}
+	else
+		status = AE_OK;
       exit:
 	kfree(buffer.pointer);
 	return status;
@@ -217,7 +221,7 @@
 	acpi_status status;
 	struct acpi_device_info *info;
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	struct acpi_find_child *find = (struct acpi_find_child *)context;
+	struct acpi_find_child *find = context;
 
 	status = acpi_get_object_info(handle, &buffer);
 	if (ACPI_SUCCESS(status)) {
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
index 1ba2db6..8edfb92 100644
--- a/drivers/acpi/hotkey.c
+++ b/drivers/acpi/hotkey.c
@@ -265,8 +265,7 @@
 
 static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_polling_hotkey *poll_hotkey =
-	    (struct acpi_polling_hotkey *)seq->private;
+	struct acpi_polling_hotkey *poll_hotkey = seq->private;
 	char *buf;
 
 
@@ -577,7 +576,7 @@
 	if (ACPI_FAILURE(status))
 		goto do_fail_zero;
 	key->poll_hotkey.poll_result =
-	    (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+	    kmalloc(sizeof(union acpi_object), GFP_KERNEL);
 	if (!key->poll_hotkey.poll_result)
 		goto do_fail_zero;
 	return AE_OK;
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
index 6342e61..8338be0 100644
--- a/drivers/acpi/i2c_ec.c
+++ b/drivers/acpi/i2c_ec.c
@@ -309,18 +309,16 @@
 		return -EINVAL;
 	}
 
-	ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
+	ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
 	if (!ec_hc) {
 		return -ENOMEM;
 	}
-	memset(ec_hc, 0, sizeof(struct acpi_ec_hc));
 
-	smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
+	smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
 	if (!smbus) {
 		kfree(ec_hc);
 		return -ENOMEM;
 	}
-	memset(smbus, 0, sizeof(struct acpi_ec_smbus));
 
 	ec_hc->handle = device->handle;
 	strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
@@ -393,7 +391,7 @@
 
 struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
 {
-	return ((struct acpi_ec_hc *)acpi_driver_data(device->parent));
+	return acpi_driver_data(device->parent);
 }
 
 EXPORT_SYMBOL(acpi_get_ec_hc);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 5a84459..b72d13d 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -3,6 +3,7 @@
  *
  *
  *  Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ *  Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
  *
  *  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
@@ -19,10 +20,14 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define IBM_VERSION "0.12a"
+#define IBM_VERSION "0.13"
 
 /*
  *  Changelog:
+ *
+ *  2006-11-22	0.13	new maintainer
+ *  			changelog now lives in git commit history, and will
+ *  			not be updated further in-file.
  *  
  *  2005-08-17  0.12	fix compilation on 2.6.13-rc kernels
  *  2005-03-17	0.11	support for 600e, 770x
@@ -77,9 +82,16 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/string.h>
+
 #include <linux/proc_fs.h>
+#include <linux/backlight.h>
 #include <asm/uaccess.h>
 
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
 #include <acpi/acpi_drivers.h>
 #include <acpi/acnamesp.h>
 
@@ -88,7 +100,7 @@
 #define IBM_FILE "ibm_acpi"
 #define IBM_URL "http://ibm-acpi.sf.net/"
 
-MODULE_AUTHOR("Borislav Deianov");
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
 MODULE_DESCRIPTION(IBM_DESC);
 MODULE_VERSION(IBM_VERSION);
 MODULE_LICENSE("GPL");
@@ -116,28 +128,6 @@
 	static char        *object##_path;			\
 	static char        *object##_paths[] = { paths }
 
-/*
- * The following models are supported to various degrees:
- *
- * 570, 600e, 600x, 770e, 770x
- * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
- * G40, G41
- * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
- * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
- * X20, X21, X22, X23, X24, X30, X31, X40
- *
- * The following models have no supported features:
- *
- * 240, 240x, i1400
- *
- * Still missing DSDTs for the following models:
- *
- * A20p, A22e, A22m
- * R52
- * S31
- * T43p
- */
-
 IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0",	/* 240, 240x */
 	   "\\_SB.PCI.ISA.EC",	/* 570 */
 	   "\\_SB.PCI0.ISA0.EC0",	/* 600e/x, 770e, 770x */
@@ -167,8 +157,10 @@
 	   "\\_SB.PCI.ISA.SLCE",	/* 570 */
     );				/* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
 #endif
+#ifdef CONFIG_ACPI_IBM_BAY
 IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST",	/* 570 */
 	   "\\_SB.PCI0.IDE0.IDES.IDSM",	/* 600e/x, 770e, 770x */
+	   "\\_SB.PCI0.SATA.SCND.MSTR",	/* T60, X60, Z60 */ 
 	   "\\_SB.PCI0.IDE0.SCND.MSTR",	/* all others */
     );				/* A21e, R30, R31 */
 
@@ -183,6 +175,7 @@
 IBM_HANDLE(bay2_ej, bay2, "_EJ3",	/* 600e/x, 770e, A3x */
 	   "_EJ0",		/* 770x */
     );				/* all others */
+#endif
 
 /* don't list other alternatives as we install a notify handler on the 570 */
 IBM_HANDLE(pci, root, "\\_SB.PCI");	/* 570 */
@@ -203,7 +196,7 @@
 IBM_HANDLE(beep, ec, "BEEP");	/* all except R30, R31 */
 IBM_HANDLE(ecrd, ec, "ECRD");	/* 570 */
 IBM_HANDLE(ecwr, ec, "ECWR");	/* 570 */
-IBM_HANDLE(fans, ec, "FANS");	/* X31, X40 */
+IBM_HANDLE(fans, ec, "FANS");	/* X31, X40, X41 */
 
 IBM_HANDLE(gfan, ec, "GFAN",	/* 570 */
 	   "\\FSPD",		/* 600e/x, 770e, 770x */
@@ -216,6 +209,152 @@
 #define IBM_HKEY_HID	"IBM0068"
 #define IBM_PCI_HID	"PNP0A03"
 
+enum thermal_access_mode {
+	IBMACPI_THERMAL_NONE = 0,	/* No thermal support */
+	IBMACPI_THERMAL_ACPI_TMP07,	/* Use ACPI TMP0-7 */
+	IBMACPI_THERMAL_ACPI_UPDT,	/* Use ACPI TMP0-7 with UPDT */
+	IBMACPI_THERMAL_TPEC_8,		/* Use ACPI EC regs, 8 sensors */
+	IBMACPI_THERMAL_TPEC_16,	/* Use ACPI EC regs, 16 sensors */
+};
+
+#define IBMACPI_MAX_THERMAL_SENSORS 16	/* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+	s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
+};
+
+/*
+ * FAN ACCESS MODES
+ *
+ * IBMACPI_FAN_RD_ACPI_GFAN:
+ * 	ACPI GFAN method: returns fan level
+ *
+ * 	see IBMACPI_FAN_WR_ACPI_SFAN
+ * 	EC 0x2f not available if GFAN exists
+ *
+ * IBMACPI_FAN_WR_ACPI_SFAN:
+ * 	ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ * 	EC 0x2f might be available *for reading*, but never for writing.
+ *
+ * IBMACPI_FAN_WR_TPEC:
+ * 	ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
+ * 	on almost all ThinkPads
+ *
+ * 	Fan speed changes of any sort (including those caused by the
+ * 	disengaged mode) are usually done slowly by the firmware as the
+ * 	maximum ammount of fan duty cycle change per second seems to be
+ * 	limited.
+ *
+ * 	Reading is not available if GFAN exists.
+ * 	Writing is not available if SFAN exists.
+ *
+ * 	Bits
+ *	 7	automatic mode engaged;
+ *  		(default operation mode of the ThinkPad)
+ * 		fan level is ignored in this mode.
+ *	 6	disengage mode (takes precedence over bit 7);
+ *		not available on all thinkpads.  May disable
+ *		the tachometer, and speeds up fan to 100% duty-cycle,
+ *		which speeds it up far above the standard RPM
+ *		levels.  It is not impossible that it could cause
+ *		hardware damage.
+ *	5-3	unused in some models.  Extra bits for fan level
+ *		in others, but still useless as all values above
+ *		7 map to the same speed as level 7 in these models.
+ *	2-0	fan level (0..7 usually)
+ *			0x00 = stop
+ * 			0x07 = max (set when temperatures critical)
+ * 		Some ThinkPads may have other levels, see
+ * 		IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ *	FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ *	boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ *	does so, its initial value is meaningless (0x07).
+ *
+ *	For firmware bugs, refer to:
+ *	http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * 	----
+ *
+ *	ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ *	Main fan tachometer reading (in RPM)
+ *
+ *	This register is present on all ThinkPads with a new-style EC, and
+ *	it is known not to be present on the A21m/e, and T22, as there is
+ *	something else in offset 0x84 according to the ACPI DSDT.  Other
+ *	ThinkPads from this same time period (and earlier) probably lack the
+ *	tachometer as well.
+ *
+ *	Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ *	was never fixed by IBM to report the EC firmware version string
+ *	probably support the tachometer (like the early X models), so
+ *	detecting it is quite hard.  We need more data to know for sure.
+ *
+ *	FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ *	might result.
+ *
+ *	FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
+ *	register is not invalidated in ThinkPads that disable tachometer
+ *	readings.  Thus, the tachometer readings go stale.
+ *
+ *	For firmware bugs, refer to:
+ *	http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * IBMACPI_FAN_WR_ACPI_FANS:
+ *	ThinkPad X31, X40, X41.  Not available in the X60.
+ *
+ *	FANS ACPI handle: takes three arguments: low speed, medium speed,
+ *	high speed.  ACPI DSDT seems to map these three speeds to levels
+ *	as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ *	(this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ * 	The speeds are stored on handles
+ * 	(FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ * 	There are three default speed sets, acessible as handles:
+ * 	FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ * 	ACPI DSDT switches which set is in use depending on various
+ * 	factors.
+ *
+ * 	IBMACPI_FAN_WR_TPEC is also available and should be used to
+ * 	command the fan.  The X31/X40/X41 seems to have 8 fan levels,
+ * 	but the ACPI tables just mention level 7.
+ */
+
+enum fan_status_access_mode {
+	IBMACPI_FAN_NONE = 0,		/* No fan status or control */
+	IBMACPI_FAN_RD_ACPI_GFAN,	/* Use ACPI GFAN */
+	IBMACPI_FAN_RD_TPEC,		/* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+	IBMACPI_FAN_WR_NONE = 0,	/* No fan control */
+	IBMACPI_FAN_WR_ACPI_SFAN,	/* Use ACPI SFAN */
+	IBMACPI_FAN_WR_TPEC,		/* Use ACPI EC reg 0x2f */
+	IBMACPI_FAN_WR_ACPI_FANS,	/* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+	IBMACPI_FAN_CMD_SPEED 	= 0x0001,	/* speed command */
+	IBMACPI_FAN_CMD_LEVEL 	= 0x0002,	/* level command  */
+	IBMACPI_FAN_CMD_ENABLE	= 0x0004,	/* enable/disable cmd,
+						 * and also watchdog cmd */
+};
+
+enum {					/* Fan control constants */
+	fan_status_offset = 0x2f,	/* EC register 0x2f */
+	fan_rpm_offset = 0x84,		/* EC register 0x84: LSB, 0x85 MSB (RPM)
+					 * 0x84 must be read before 0x85 */
+
+	IBMACPI_FAN_EC_DISENGAGED 	= 0x40,	/* EC mode: tachometer
+						 * disengaged */
+	IBMACPI_FAN_EC_AUTO		= 0x80, /* EC mode: auto fan
+						 * control */
+};
+
+static char *ibm_thinkpad_ec_found = NULL;
+
 struct ibm_struct {
 	char *name;
 	char param[32];
@@ -243,6 +382,8 @@
 
 static struct proc_dir_entry *proc_dir = NULL;
 
+static struct backlight_device *ibm_backlight_device = NULL;
+
 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
 #define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -581,8 +722,7 @@
 {
 	int status;
 
-	if (!wan_supported ||
-	    !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+	if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
 		status = 0;
 
 	return status;
@@ -630,12 +770,15 @@
 	return 0;
 }
 
-static int video_supported;
-static int video_orig_autosw;
+enum video_access_mode {
+	IBMACPI_VIDEO_NONE = 0,
+	IBMACPI_VIDEO_570,	/* 570 */
+	IBMACPI_VIDEO_770,	/* 600e/x, 770e, 770x */
+	IBMACPI_VIDEO_NEW,	/* all others */
+};
 
-#define VIDEO_570 1
-#define VIDEO_770 2
-#define VIDEO_NEW 3
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
 
 static int video_init(void)
 {
@@ -647,16 +790,16 @@
 
 	if (!vid_handle)
 		/* video switching not supported on R30, R31 */
-		video_supported = 0;
+		video_supported = IBMACPI_VIDEO_NONE;
 	else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
 		/* 570 */
-		video_supported = VIDEO_570;
+		video_supported = IBMACPI_VIDEO_570;
 	else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
 		/* 600e/x, 770e, 770x */
-		video_supported = VIDEO_770;
+		video_supported = IBMACPI_VIDEO_770;
 	else
 		/* all others */
-		video_supported = VIDEO_NEW;
+		video_supported = IBMACPI_VIDEO_NEW;
 
 	return 0;
 }
@@ -666,15 +809,15 @@
 	int status = 0;
 	int i;
 
-	if (video_supported == VIDEO_570) {
+	if (video_supported == IBMACPI_VIDEO_570) {
 		if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
 			status = i & 3;
-	} else if (video_supported == VIDEO_770) {
+	} else if (video_supported == IBMACPI_VIDEO_770) {
 		if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
 			status |= 0x01 * i;
 		if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
 			status |= 0x02 * i;
-	} else if (video_supported == VIDEO_NEW) {
+	} else if (video_supported == IBMACPI_VIDEO_NEW) {
 		acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
 		if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
 			status |= 0x02 * i;
@@ -693,9 +836,10 @@
 {
 	int autosw = 0;
 
-	if (video_supported == VIDEO_570)
+	if (video_supported == IBMACPI_VIDEO_570)
 		acpi_evalf(vid_handle, &autosw, "SWIT", "d");
-	else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW)
+	else if (video_supported == IBMACPI_VIDEO_770 ||
+		 video_supported == IBMACPI_VIDEO_NEW)
 		acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
 
 	return autosw & 1;
@@ -715,12 +859,12 @@
 	len += sprintf(p + len, "status:\t\tsupported\n");
 	len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
 	len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
-	if (video_supported == VIDEO_NEW)
+	if (video_supported == IBMACPI_VIDEO_NEW)
 		len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
 	len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
 	len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
 	len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
-	if (video_supported == VIDEO_NEW)
+	if (video_supported == IBMACPI_VIDEO_NEW)
 		len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
 	len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
 	len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
@@ -735,7 +879,7 @@
 
 	if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
 		return -EIO;
-	ret = video_supported == VIDEO_570 ?
+	ret = video_supported == IBMACPI_VIDEO_570 ?
 	    acpi_evalf(ec_handle, NULL, "_Q16", "v") :
 	    acpi_evalf(vid_handle, NULL, "VSWT", "v");
 	acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
@@ -745,9 +889,9 @@
 
 static int video_expand(void)
 {
-	if (video_supported == VIDEO_570)
+	if (video_supported == IBMACPI_VIDEO_570)
 		return acpi_evalf(ec_handle, NULL, "_Q17", "v");
-	else if (video_supported == VIDEO_770)
+	else if (video_supported == IBMACPI_VIDEO_770)
 		return acpi_evalf(vid_handle, NULL, "VEXP", "v");
 	else
 		return acpi_evalf(NULL, NULL, "\\VEXP", "v");
@@ -757,10 +901,10 @@
 {
 	int ret;
 
-	if (video_supported == VIDEO_570) {
+	if (video_supported == IBMACPI_VIDEO_570) {
 		ret = acpi_evalf(NULL, NULL,
 				 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
-	} else if (video_supported == VIDEO_770) {
+	} else if (video_supported == IBMACPI_VIDEO_770) {
 		int autosw = video_autosw();
 		if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
 			return -EIO;
@@ -796,10 +940,10 @@
 			enable |= 0x02;
 		} else if (strlencmp(cmd, "crt_disable") == 0) {
 			disable |= 0x02;
-		} else if (video_supported == VIDEO_NEW &&
+		} else if (video_supported == IBMACPI_VIDEO_NEW &&
 			   strlencmp(cmd, "dvi_enable") == 0) {
 			enable |= 0x08;
-		} else if (video_supported == VIDEO_NEW &&
+		} else if (video_supported == IBMACPI_VIDEO_NEW &&
 			   strlencmp(cmd, "dvi_disable") == 0) {
 			disable |= 0x08;
 		} else if (strlencmp(cmd, "auto_enable") == 0) {
@@ -898,6 +1042,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
 static int _sta(acpi_handle handle)
 {
 	int status;
@@ -907,6 +1052,7 @@
 
 	return status;
 }
+#endif
 #ifdef CONFIG_ACPI_IBM_DOCK
 #define dock_docked() (_sta(dock_handle) & 1)
 
@@ -972,6 +1118,7 @@
 }
 #endif
 
+#ifdef CONFIG_ACPI_IBM_BAY
 static int bay_status_supported;
 static int bay_status2_supported;
 static int bay_eject_supported;
@@ -1047,6 +1194,7 @@
 {
 	acpi_bus_generate_event(ibm->device, event, 0);
 }
+#endif
 
 static int cmos_read(char *p)
 {
@@ -1094,26 +1242,28 @@
 	return 0;
 }
 
-static int led_supported;
-
-#define LED_570 1
-#define LED_OLD 2
-#define LED_NEW 3
+enum led_access_mode {
+	IBMACPI_LED_NONE = 0,
+	IBMACPI_LED_570,	/* 570 */
+	IBMACPI_LED_OLD,	/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+	IBMACPI_LED_NEW,	/* all others */
+};
+static enum led_access_mode led_supported;
 
 static int led_init(void)
 {
 	if (!led_handle)
 		/* led not supported on R30, R31 */
-		led_supported = 0;
+		led_supported = IBMACPI_LED_NONE;
 	else if (strlencmp(led_path, "SLED") == 0)
 		/* 570 */
-		led_supported = LED_570;
+		led_supported = IBMACPI_LED_570;
 	else if (strlencmp(led_path, "SYSL") == 0)
 		/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
-		led_supported = LED_OLD;
+		led_supported = IBMACPI_LED_OLD;
 	else
 		/* all others */
-		led_supported = LED_NEW;
+		led_supported = IBMACPI_LED_NEW;
 
 	return 0;
 }
@@ -1130,7 +1280,7 @@
 	}
 	len += sprintf(p + len, "status:\t\tsupported\n");
 
-	if (led_supported == LED_570) {
+	if (led_supported == IBMACPI_LED_570) {
 		/* 570 */
 		int i, status;
 		for (i = 0; i < 8; i++) {
@@ -1179,13 +1329,13 @@
 		} else
 			return -EINVAL;
 
-		if (led_supported == LED_570) {
+		if (led_supported == IBMACPI_LED_570) {
 			/* 570 */
 			led = 1 << led;
 			if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
 					led, led_sled_arg1[ind]))
 				return -EIO;
-		} else if (led_supported == LED_OLD) {
+		} else if (led_supported == IBMACPI_LED_OLD) {
 			/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
 			led = 1 << led;
 			ret = ec_write(EC_HLMS, led);
@@ -1272,50 +1422,142 @@
 	return 1;
 }
 
-static int thermal_tmp_supported;
-static int thermal_updt_supported;
+static enum thermal_access_mode thermal_read_mode;
 
 static int thermal_init(void)
 {
-	/* temperatures not supported on 570, G4x, R30, R31, R32 */
-	thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+	u8 t, ta1, ta2;
+	int i;
+	int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
 
-	/* 600e/x, 770e, 770x */
-	thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv");
+	if (ibm_thinkpad_ec_found && experimental) {
+		/*
+		 * Direct EC access mode: sensors at registers
+		 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
+		 * non-implemented, thermal sensors return 0x80 when
+		 * not available
+		 */
+
+		ta1 = ta2 = 0;
+		for (i = 0; i < 8; i++) {
+			if (likely(acpi_ec_read(0x78 + i, &t))) {
+				ta1 |= t;
+			} else {
+				ta1 = 0;
+				break;
+			}
+			if (likely(acpi_ec_read(0xC0 + i, &t))) {
+				ta2 |= t;
+			} else {
+				ta1 = 0;
+				break;
+			}
+		}
+		if (ta1 == 0) {
+			/* This is sheer paranoia, but we handle it anyway */
+			if (acpi_tmp7) {
+				printk(IBM_ERR
+				       "ThinkPad ACPI EC access misbehaving, "
+				       "falling back to ACPI TMPx access mode\n");
+				thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
+			} else {
+				printk(IBM_ERR
+				       "ThinkPad ACPI EC access misbehaving, "
+				       "disabling thermal sensors access\n");
+				thermal_read_mode = IBMACPI_THERMAL_NONE;
+			}
+		} else {
+			thermal_read_mode =
+			    (ta2 != 0) ?
+			    IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
+		}
+	} else if (acpi_tmp7) {
+		if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+			/* 600e/x, 770e, 770x */
+			thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
+		} else {
+			/* Standard ACPI TMPx access, max 8 sensors */
+			thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
+		}
+	} else {
+		/* temperatures not supported on 570, G4x, R30, R31, R32 */
+		thermal_read_mode = IBMACPI_THERMAL_NONE;
+	}
 
 	return 0;
 }
 
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+	int i, t;
+	s8 tmp;
+	char tmpi[] = "TMPi";
+
+	if (!s)
+		return -EINVAL;
+
+	switch (thermal_read_mode) {
+#if IBMACPI_MAX_THERMAL_SENSORS >= 16
+	case IBMACPI_THERMAL_TPEC_16:
+		for (i = 0; i < 8; i++) {
+			if (!acpi_ec_read(0xC0 + i, &tmp))
+				return -EIO;
+			s->temp[i + 8] = tmp * 1000;
+		}
+		/* fallthrough */
+#endif
+	case IBMACPI_THERMAL_TPEC_8:
+		for (i = 0; i < 8; i++) {
+			if (!acpi_ec_read(0x78 + i, &tmp))
+				return -EIO;
+			s->temp[i] = tmp * 1000;
+		}
+		return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
+
+	case IBMACPI_THERMAL_ACPI_UPDT:
+		if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+			return -EIO;
+		for (i = 0; i < 8; i++) {
+			tmpi[3] = '0' + i;
+			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+				return -EIO;
+			s->temp[i] = (t - 2732) * 100;
+		}
+		return 8;
+
+	case IBMACPI_THERMAL_ACPI_TMP07:
+		for (i = 0; i < 8; i++) {
+			tmpi[3] = '0' + i;
+			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+				return -EIO;
+			s->temp[i] = t * 1000;
+		}
+		return 8;
+
+	case IBMACPI_THERMAL_NONE:
+	default:
+		return 0;
+	}
+}
+
 static int thermal_read(char *p)
 {
 	int len = 0;
+	int n, i;
+	struct ibm_thermal_sensors_struct t;
 
-	if (!thermal_tmp_supported)
-		len += sprintf(p + len, "temperatures:\tnot supported\n");
-	else {
-		int i, t;
-		char tmpi[] = "TMPi";
-		s8 tmp[8];
+	n = thermal_get_sensors(&t);
+	if (unlikely(n < 0))
+		return n;
 
-		if (thermal_updt_supported)
-			if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
-				return -EIO;
+	len += sprintf(p + len, "temperatures:\t");
 
-		for (i = 0; i < 8; i++) {
-			tmpi[3] = '0' + i;
-			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
-				return -EIO;
-			if (thermal_updt_supported)
-				tmp[i] = (t - 2732 + 5) / 10;
-			else
-				tmp[i] = t;
-		}
-
-		len += sprintf(p + len,
-			       "temperatures:\t%d %d %d %d %d %d %d %d\n",
-			       tmp[0], tmp[1], tmp[2], tmp[3],
-			       tmp[4], tmp[5], tmp[6], tmp[7]);
-	}
+	if (n > 0) {
+		for (i = 0; i < (n - 1); i++)
+			len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+		len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+	} else
+		len += sprintf(p + len, "not supported\n");
 
 	return len;
 }
@@ -1381,12 +1623,23 @@
 
 static int brightness_offset = 0x31;
 
+static int brightness_get(struct backlight_device *bd)
+{
+	u8 level;
+	if (!acpi_ec_read(brightness_offset, &level))
+		return -EIO;
+
+	level &= 0x7;
+
+	return level;
+}
+
 static int brightness_read(char *p)
 {
 	int len = 0;
-	u8 level;
+	int level;
 
-	if (!acpi_ec_read(brightness_offset, &level)) {
+	if ((level = brightness_get(NULL)) < 0) {
 		len += sprintf(p + len, "level:\t\tunreadable\n");
 	} else {
 		len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
@@ -1401,16 +1654,34 @@
 #define BRIGHTNESS_UP	4
 #define BRIGHTNESS_DOWN	5
 
-static int brightness_write(char *buf)
+static int brightness_set(int value)
 {
 	int cmos_cmd, inc, i;
-	u8 level;
+	int current_value = brightness_get(NULL);
+
+	value &= 7;
+
+	cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
+	inc = value > current_value ? 1 : -1;
+	for (i = current_value; i != value; i += inc) {
+		if (!cmos_eval(cmos_cmd))
+			return -EIO;
+		if (!acpi_ec_write(brightness_offset, i + inc))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int brightness_write(char *buf)
+{
+	int level;
 	int new_level;
 	char *cmd;
 
 	while ((cmd = next_cmd(&buf))) {
-		if (!acpi_ec_read(brightness_offset, &level))
-			return -EIO;
+		if ((level = brightness_get(NULL)) < 0)
+			return level;
 		level &= 7;
 
 		if (strlencmp(cmd, "up") == 0) {
@@ -1423,19 +1694,44 @@
 		} else
 			return -EINVAL;
 
-		cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
-		inc = new_level > level ? 1 : -1;
-		for (i = level; i != new_level; i += inc) {
-			if (!cmos_eval(cmos_cmd))
-				return -EIO;
-			if (!acpi_ec_write(brightness_offset, i + inc))
-				return -EIO;
-		}
+		brightness_set(new_level);
 	}
 
 	return 0;
 }
 
+static int brightness_update_status(struct backlight_device *bd)
+{
+	return brightness_set(bd->props->brightness);
+}
+
+static struct backlight_properties ibm_backlight_data = {
+        .owner          = THIS_MODULE,
+        .get_brightness = brightness_get,
+        .update_status  = brightness_update_status,
+        .max_brightness = 7,
+};
+
+static int brightness_init(void)
+{
+	ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
+							 &ibm_backlight_data);
+	if (IS_ERR(ibm_backlight_device)) {
+		printk(IBM_ERR "Could not register backlight device\n");
+		return PTR_ERR(ibm_backlight_device);
+	}
+
+	return 0;
+}
+
+static void brightness_exit(void)
+{
+	if (ibm_backlight_device) {
+		backlight_device_unregister(ibm_backlight_device);
+		ibm_backlight_device = NULL;
+	}
+}
+
 static int volume_offset = 0x30;
 
 static int volume_read(char *p)
@@ -1522,84 +1818,480 @@
 	return 0;
 }
 
-static int fan_status_offset = 0x2f;
-static int fan_rpm_offset = 0x84;
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+
+static int fan_control_status_known;
+static u8 fan_control_initial_status;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+static int fan_init(void)
+{
+	fan_status_access_mode = IBMACPI_FAN_NONE;
+	fan_control_access_mode = IBMACPI_FAN_WR_NONE;
+	fan_control_commands = 0;
+	fan_control_status_known = 1;
+	fan_watchdog_maxinterval = 0;
+
+	if (gfan_handle) {
+		/* 570, 600e/x, 770e, 770x */
+		fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
+	} else {
+		/* all other ThinkPads: note that even old-style
+		 * ThinkPad ECs supports the fan control register */
+		if (likely(acpi_ec_read(fan_status_offset,
+					&fan_control_initial_status))) {
+			fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
+
+			/* In some ThinkPads, neither the EC nor the ACPI
+			 * DSDT initialize the fan status, and it ends up
+			 * being set to 0x07 when it *could* be either
+			 * 0x07 or 0x80.
+			 *
+			 * Enable for TP-1Y (T43), TP-78 (R51e),
+			 * TP-76 (R52), TP-70 (T43, R52), which are known
+			 * to be buggy. */
+			if (fan_control_initial_status == 0x07 &&
+			    ibm_thinkpad_ec_found &&
+			    ((ibm_thinkpad_ec_found[0] == '1' &&
+			      ibm_thinkpad_ec_found[1] == 'Y') ||
+			     (ibm_thinkpad_ec_found[0] == '7' &&
+			      (ibm_thinkpad_ec_found[1] == '6' ||
+			       ibm_thinkpad_ec_found[1] == '8' ||
+			       ibm_thinkpad_ec_found[1] == '0'))
+			    )) {
+				printk(IBM_NOTICE
+				       "fan_init: initial fan status is "
+				       "unknown, assuming it is in auto "
+				       "mode\n");
+				fan_control_status_known = 0;
+			}
+		} else {
+			printk(IBM_ERR
+			       "ThinkPad ACPI EC access misbehaving, "
+			       "fan status and control unavailable\n");
+			return 0;
+		}
+	}
+
+	if (sfan_handle) {
+		/* 570, 770x-JL */
+		fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
+		fan_control_commands |=
+		    IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
+	} else {
+		if (!gfan_handle) {
+			/* gfan without sfan means no fan control */
+			/* all other models implement TP EC 0x2f control */
+
+			if (fans_handle) {
+				/* X31, X40, X41 */
+				fan_control_access_mode =
+				    IBMACPI_FAN_WR_ACPI_FANS;
+				fan_control_commands |=
+				    IBMACPI_FAN_CMD_SPEED |
+				    IBMACPI_FAN_CMD_LEVEL |
+				    IBMACPI_FAN_CMD_ENABLE;
+			} else {
+				fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
+				fan_control_commands |=
+				    IBMACPI_FAN_CMD_LEVEL |
+				    IBMACPI_FAN_CMD_ENABLE;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int fan_get_status(u8 *status)
+{
+	u8 s;
+
+	/* TODO:
+	 * Add IBMACPI_FAN_RD_ACPI_FANS ? */
+
+	switch (fan_status_access_mode) {
+	case IBMACPI_FAN_RD_ACPI_GFAN:
+		/* 570, 600e/x, 770e, 770x */
+
+		if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+			return -EIO;
+
+		if (likely(status))
+			*status = s & 0x07;
+
+		break;
+
+	case IBMACPI_FAN_RD_TPEC:
+		/* all except 570, 600e/x, 770e, 770x */
+		if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+			return -EIO;
+
+		if (likely(status))
+			*status = s;
+
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+	u8 hi, lo;
+
+	switch (fan_status_access_mode) {
+	case IBMACPI_FAN_RD_TPEC:
+		/* all except 570, 600e/x, 770e, 770x */
+		if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+			     !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+			return -EIO;
+
+		if (likely(speed))
+			*speed = (hi << 8) | lo;
+
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void fan_exit(void)
+{
+	cancel_delayed_work(&fan_watchdog_task);
+	flush_scheduled_work();
+}
+
+static void fan_watchdog_reset(void)
+{
+	static int fan_watchdog_active = 0;
+
+	if (fan_watchdog_active)
+		cancel_delayed_work(&fan_watchdog_task);
+
+	if (fan_watchdog_maxinterval > 0) {
+		fan_watchdog_active = 1;
+		if (!schedule_delayed_work(&fan_watchdog_task,
+				msecs_to_jiffies(fan_watchdog_maxinterval
+						 * 1000))) {
+			printk(IBM_ERR "failed to schedule the fan watchdog, "
+			       "watchdog will not trigger\n");
+		}
+	} else
+		fan_watchdog_active = 0;
+}
 
 static int fan_read(char *p)
 {
 	int len = 0;
-	int s;
-	u8 lo, hi, status;
+	int rc;
+	u8 status;
+	unsigned int speed = 0;
 
-	if (gfan_handle) {
+	switch (fan_status_access_mode) {
+	case IBMACPI_FAN_RD_ACPI_GFAN:
 		/* 570, 600e/x, 770e, 770x */
-		if (!acpi_evalf(gfan_handle, &s, NULL, "d"))
-			return -EIO;
+		if ((rc = fan_get_status(&status)) < 0)
+			return rc;
 
-		len += sprintf(p + len, "level:\t\t%d\n", s);
-	} else {
+		len += sprintf(p + len, "status:\t\t%s\n"
+			       "level:\t\t%d\n",
+			       (status != 0) ? "enabled" : "disabled", status);
+		break;
+
+	case IBMACPI_FAN_RD_TPEC:
 		/* all except 570, 600e/x, 770e, 770x */
-		if (!acpi_ec_read(fan_status_offset, &status))
-			len += sprintf(p + len, "status:\t\tunreadable\n");
-		else
-			len += sprintf(p + len, "status:\t\t%s\n",
-				       enabled(status, 7));
+		if ((rc = fan_get_status(&status)) < 0)
+			return rc;
 
-		if (!acpi_ec_read(fan_rpm_offset, &lo) ||
-		    !acpi_ec_read(fan_rpm_offset + 1, &hi))
-			len += sprintf(p + len, "speed:\t\tunreadable\n");
+		if (unlikely(!fan_control_status_known)) {
+			if (status != fan_control_initial_status)
+				fan_control_status_known = 1;
+			else
+				/* Return most likely status. In fact, it
+				 * might be the only possible status */
+				status = IBMACPI_FAN_EC_AUTO;
+		}
+
+		len += sprintf(p + len, "status:\t\t%s\n",
+			       (status != 0) ? "enabled" : "disabled");
+
+		/* No ThinkPad boots on disengaged mode, we can safely
+		 * assume the tachometer is online if fan control status
+		 * was unknown */
+		if ((rc = fan_get_speed(&speed)) < 0)
+			return rc;
+
+		len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+		if (status & IBMACPI_FAN_EC_DISENGAGED)
+			/* Disengaged mode takes precedence */
+			len += sprintf(p + len, "level:\t\tdisengaged\n");
+		else if (status & IBMACPI_FAN_EC_AUTO)
+			len += sprintf(p + len, "level:\t\tauto\n");
 		else
-			len += sprintf(p + len, "speed:\t\t%d\n",
-				       (hi << 8) + lo);
+			len += sprintf(p + len, "level:\t\t%d\n", status);
+		break;
+
+	case IBMACPI_FAN_NONE:
+	default:
+		len += sprintf(p + len, "status:\t\tnot supported\n");
 	}
 
-	if (sfan_handle)
-		/* 570, 770x-JL */
-		len += sprintf(p + len, "commands:\tlevel <level>"
-			       " (<level> is 0-7)\n");
-	if (!gfan_handle)
-		/* all except 570, 600e/x, 770e, 770x */
-		len += sprintf(p + len, "commands:\tenable, disable\n");
-	if (fans_handle)
-		/* X31, X40 */
+	if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
+		len += sprintf(p + len, "commands:\tlevel <level>");
+
+		switch (fan_control_access_mode) {
+		case IBMACPI_FAN_WR_ACPI_SFAN:
+			len += sprintf(p + len, " (<level> is 0-7)\n");
+			break;
+
+		default:
+			len += sprintf(p + len, " (<level> is 0-7, "
+				       "auto, disengaged)\n");
+			break;
+		}
+	}
+
+	if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
+		len += sprintf(p + len, "commands:\tenable, disable\n"
+			       "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+			       "1-120 (seconds))\n");
+
+	if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
 		len += sprintf(p + len, "commands:\tspeed <speed>"
 			       " (<speed> is 0-65535)\n");
 
 	return len;
 }
 
-static int fan_write(char *buf)
+static int fan_set_level(int level)
 {
-	char *cmd;
-	int level, speed;
-
-	while ((cmd = next_cmd(&buf))) {
-		if (sfan_handle &&
-		    sscanf(cmd, "level %d", &level) == 1 &&
-		    level >= 0 && level <= 7) {
-			/* 570, 770x-JL */
+	switch (fan_control_access_mode) {
+	case IBMACPI_FAN_WR_ACPI_SFAN:
+		if (level >= 0 && level <= 7) {
 			if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
 				return -EIO;
-		} else if (!gfan_handle && strlencmp(cmd, "enable") == 0) {
-			/* all except 570, 600e/x, 770e, 770x */
-			if (!acpi_ec_write(fan_status_offset, 0x80))
-				return -EIO;
-		} else if (!gfan_handle && strlencmp(cmd, "disable") == 0) {
-			/* all except 570, 600e/x, 770e, 770x */
-			if (!acpi_ec_write(fan_status_offset, 0x00))
-				return -EIO;
-		} else if (fans_handle &&
-			   sscanf(cmd, "speed %d", &speed) == 1 &&
-			   speed >= 0 && speed <= 65535) {
-			/* X31, X40 */
+		} else
+			return -EINVAL;
+		break;
+
+	case IBMACPI_FAN_WR_ACPI_FANS:
+	case IBMACPI_FAN_WR_TPEC:
+		if ((level != IBMACPI_FAN_EC_AUTO) &&
+		    (level != IBMACPI_FAN_EC_DISENGAGED) &&
+		    ((level < 0) || (level > 7)))
+			return -EINVAL;
+
+		if (!acpi_ec_write(fan_status_offset, level))
+			return -EIO;
+		else
+			fan_control_status_known = 1;
+		break;
+
+	default:
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int fan_set_enable(void)
+{
+	u8 s;
+	int rc;
+
+	switch (fan_control_access_mode) {
+	case IBMACPI_FAN_WR_ACPI_FANS:
+	case IBMACPI_FAN_WR_TPEC:
+		if ((rc = fan_get_status(&s)) < 0)
+			return rc;
+
+		/* Don't go out of emergency fan mode */
+		if (s != 7)
+			s = IBMACPI_FAN_EC_AUTO;
+
+		if (!acpi_ec_write(fan_status_offset, s))
+			return -EIO;
+		else
+			fan_control_status_known = 1;
+		break;
+
+	case IBMACPI_FAN_WR_ACPI_SFAN:
+		if ((rc = fan_get_status(&s)) < 0)
+			return rc;
+
+		s &= 0x07;
+
+		/* Set fan to at least level 4 */
+		if (s < 4)
+			s = 4;
+
+		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+			return -EIO;
+		break;
+
+	default:
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int fan_set_disable(void)
+{
+	switch (fan_control_access_mode) {
+	case IBMACPI_FAN_WR_ACPI_FANS:
+	case IBMACPI_FAN_WR_TPEC:
+		if (!acpi_ec_write(fan_status_offset, 0x00))
+			return -EIO;
+		else
+			fan_control_status_known = 1;
+		break;
+
+	case IBMACPI_FAN_WR_ACPI_SFAN:
+		if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+			return -EIO;
+		break;
+
+	default:
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int fan_set_speed(int speed)
+{
+	switch (fan_control_access_mode) {
+	case IBMACPI_FAN_WR_ACPI_FANS:
+		if (speed >= 0 && speed <= 65535) {
 			if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
 					speed, speed, speed))
 				return -EIO;
 		} else
 			return -EINVAL;
+		break;
+
+	default:
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+	int level;
+
+	if (strlencmp(cmd, "level auto") == 0)
+		level = IBMACPI_FAN_EC_AUTO;
+	else if (strlencmp(cmd, "level disengaged") == 0)
+		level = IBMACPI_FAN_EC_DISENGAGED;
+	else if (sscanf(cmd, "level %d", &level) != 1)
+		return 0;
+
+	if ((*rc = fan_set_level(level)) == -ENXIO)
+		printk(IBM_ERR "level command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+	if (strlencmp(cmd, "enable") != 0)
+		return 0;
+
+	if ((*rc = fan_set_enable()) == -ENXIO)
+		printk(IBM_ERR "enable command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+	if (strlencmp(cmd, "disable") != 0)
+		return 0;
+
+	if ((*rc = fan_set_disable()) == -ENXIO)
+		printk(IBM_ERR "disable command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+	int speed;
+
+	/* TODO:
+	 * Support speed <low> <medium> <high> ? */
+
+	if (sscanf(cmd, "speed %d", &speed) != 1)
+		return 0;
+
+	if ((*rc = fan_set_speed(speed)) == -ENXIO)
+		printk(IBM_ERR "speed command accepted for unsupported "
+		       "access mode %d", fan_control_access_mode);
+
+	return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+	int interval;
+
+	if (sscanf(cmd, "watchdog %d", &interval) != 1)
+		return 0;
+
+	if (interval < 0 || interval > 120)
+		*rc = -EINVAL;
+	else
+		fan_watchdog_maxinterval = interval;
+
+	return 1;
+}
+
+static int fan_write(char *buf)
+{
+	char *cmd;
+	int rc = 0;
+
+	while (!rc && (cmd = next_cmd(&buf))) {
+		if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
+		      fan_write_cmd_level(cmd, &rc)) &&
+		    !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
+		      (fan_write_cmd_enable(cmd, &rc) ||
+		       fan_write_cmd_disable(cmd, &rc) ||
+		       fan_write_cmd_watchdog(cmd, &rc))) &&
+		    !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
+		      fan_write_cmd_speed(cmd, &rc))
+		    )
+			rc = -EINVAL;
+		else if (!rc)
+			fan_watchdog_reset();
 	}
 
-	return 0;
+	return rc;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+	printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+	if (fan_set_enable()) {
+		printk(IBM_ERR "fan watchdog: error while enabling fan\n");
+		/* reschedule for later */
+		fan_watchdog_reset();
+	}
 }
 
 static struct ibm_struct ibms[] = {
@@ -1662,6 +2354,7 @@
 	 .type = ACPI_SYSTEM_NOTIFY,
 	 },
 #endif
+#ifdef CONFIG_ACPI_IBM_BAY
 	{
 	 .name = "bay",
 	 .init = bay_init,
@@ -1671,6 +2364,7 @@
 	 .handle = &bay_handle,
 	 .type = ACPI_SYSTEM_NOTIFY,
 	 },
+#endif
 	{
 	 .name = "cmos",
 	 .read = cmos_read,
@@ -1702,6 +2396,8 @@
 	 .name = "brightness",
 	 .read = brightness_read,
 	 .write = brightness_write,
+	 .init = brightness_init,
+	 .exit = brightness_exit,
 	 },
 	{
 	 .name = "volume",
@@ -1712,6 +2408,8 @@
 	 .name = "fan",
 	 .read = fan_read,
 	 .write = fan_write,
+	 .init = fan_init,
+	 .exit = fan_exit,
 	 .experimental = 1,
 	 },
 };
@@ -1719,7 +2417,7 @@
 static int dispatch_read(char *page, char **start, off_t off, int count,
 			 int *eof, void *data)
 {
-	struct ibm_struct *ibm = (struct ibm_struct *)data;
+	struct ibm_struct *ibm = data;
 	int len;
 
 	if (!ibm || !ibm->read)
@@ -1744,7 +2442,7 @@
 static int dispatch_write(struct file *file, const char __user * userbuf,
 			  unsigned long count, void *data)
 {
-	struct ibm_struct *ibm = (struct ibm_struct *)data;
+	struct ibm_struct *ibm = data;
 	char *kernbuf;
 	int ret;
 
@@ -1773,7 +2471,7 @@
 
 static void dispatch_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct ibm_struct *ibm = (struct ibm_struct *)data;
+	struct ibm_struct *ibm = data;
 
 	if (!ibm || !ibm->notify)
 		return;
@@ -1805,7 +2503,7 @@
 		       ibm->name, status);
 		return -ENODEV;
 	}
-
+	ibm->notify_installed = 1;
 	return 0;
 }
 
@@ -1818,14 +2516,13 @@
 {
 	int ret;
 
-	ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+	ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
 	if (!ibm->driver) {
 		printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
 		return -1;
 	}
 
-	memset(ibm->driver, 0, sizeof(struct acpi_driver));
-	sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
+	sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
 	ibm->driver->ids = ibm->hid;
 	ibm->driver->ops.add = &ibm_device_add;
 
@@ -1882,7 +2579,6 @@
 		ret = setup_notify(ibm);
 		if (ret < 0)
 			return ret;
-		ibm->notify_installed = 1;
 	}
 
 	return 0;
@@ -1954,7 +2650,9 @@
 #ifdef CONFIG_ACPI_IBM_DOCK
 IBM_PARAM(dock);
 #endif
+#ifdef CONFIG_ACPI_IBM_BAY
 IBM_PARAM(bay);
+#endif
 IBM_PARAM(cmos);
 IBM_PARAM(led);
 IBM_PARAM(beep);
@@ -1971,6 +2669,33 @@
 		ibm_exit(&ibms[i]);
 
 	remove_proc_entry(IBM_DIR, acpi_root_dir);
+
+	if (ibm_thinkpad_ec_found)
+		kfree(ibm_thinkpad_ec_found);
+}
+
+static char* __init check_dmi_for_ec(void)
+{
+	struct dmi_device *dev = NULL;
+	char ec_fw_string[18];
+
+	/*
+	 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+	 * X32 or newer, all Z series;  Some models must have an
+	 * up-to-date BIOS or they will not be detected.
+	 *
+	 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+	 */
+	while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+		if (sscanf(dev->name,
+			   "IBM ThinkPad Embedded Controller -[%17c",
+			   ec_fw_string) == 1) {
+			ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+			ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+			return kstrdup(ec_fw_string, GFP_KERNEL);
+		}
+	}
+	return NULL;
 }
 
 static int __init acpi_ibm_init(void)
@@ -1992,6 +2717,12 @@
 		return -ENODEV;
 	}
 
+	/* Models with newer firmware report the EC in DMI */
+	ibm_thinkpad_ec_found = check_dmi_for_ec();
+	if (ibm_thinkpad_ec_found)
+		printk(IBM_INFO "ThinkPad EC firmware %s\n",
+		       ibm_thinkpad_ec_found);
+
 	/* these handles are not required */
 	IBM_HANDLE_INIT(vid);
 	IBM_HANDLE_INIT(vid2);
@@ -2004,12 +2735,14 @@
 	IBM_HANDLE_INIT(dock);
 #endif
 	IBM_HANDLE_INIT(pci);
+#ifdef CONFIG_ACPI_IBM_BAY
 	IBM_HANDLE_INIT(bay);
 	if (bay_handle)
 		IBM_HANDLE_INIT(bay_ej);
 	IBM_HANDLE_INIT(bay2);
 	if (bay2_handle)
 		IBM_HANDLE_INIT(bay2_ej);
+#endif
 	IBM_HANDLE_INIT(beep);
 	IBM_HANDLE_INIT(ecrd);
 	IBM_HANDLE_INIT(ecwr);
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index a163e1d..a18b1c2 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -50,6 +50,50 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_get_id
+ *
+ * PARAMETERS:  Handle          - Handle of object whose id is desired
+ *              ret_id          - Where the id will be placed
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This routine returns the owner id associated with a handle
+ *
+ ******************************************************************************/
+acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id)
+{
+	struct acpi_namespace_node *node;
+	acpi_status status;
+
+	/* Parameter Validation */
+
+	if (!ret_id) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* Convert and validate the handle */
+
+	node = acpi_ns_map_handle_to_node(handle);
+	if (!node) {
+		(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+		return (AE_BAD_PARAMETER);
+	}
+
+	*ret_id = node->owner_id;
+
+	status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+	return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_id)
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_get_type
  *
  * PARAMETERS:  Handle          - Handle of object whose type is desired
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index e5e448e..bd96a70 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -248,7 +248,7 @@
 		handle = phandle;
 		status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
 		if (ACPI_SUCCESS(status))
-			return (int)pxm;
+			return pxm;
 		status = acpi_get_parent(handle, &phandle);
 	} while (ACPI_SUCCESS(status));
 	return -1;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 02b30ae..57ae1e5 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -568,6 +568,7 @@
 static void acpi_os_execute_deferred(struct work_struct *work)
 {
 	struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
+
 	if (!dpc) {
 		printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
 		return;
@@ -1031,7 +1032,7 @@
 acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
 {
 	*cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
-	if (cache == NULL)
+	if (*cache == NULL)
 		return AE_ERROR;
 	else
 		return AE_OK;
@@ -1051,7 +1052,7 @@
 
 acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
 {
-	(void)kmem_cache_shrink(cache);
+	kmem_cache_shrink(cache);
 	return (AE_OK);
 }
 
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 1e2ae6e..55f57a6 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -122,19 +122,17 @@
 	if (!device || !device->parent)
 		return -EINVAL;
 
-	pathname = kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+	pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
 	if (!pathname)
 		return -ENOMEM;
-	memset(pathname, 0, ACPI_PATHNAME_MAX);
 	buffer.length = ACPI_PATHNAME_MAX;
 	buffer.pointer = pathname;
 
-	data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+	data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
 	if (!data) {
 		kfree(pathname);
 		return -ENOMEM;
 	}
-	memset(data, 0, sizeof(struct acpi_pci_data));
 
 	acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
@@ -281,10 +279,9 @@
 	if (!device || !device->parent)
 		return -EINVAL;
 
-	pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+	pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
 	if (!pathname)
 		return -ENOMEM;
-	memset(pathname, 0, ACPI_PATHNAME_MAX);
 
 	buffer.length = ACPI_PATHNAME_MAX;
 	buffer.pointer = pathname;
@@ -331,11 +328,9 @@
 	char *pathname = NULL;
 	struct acpi_buffer buffer = { 0, NULL };
 
-
-	pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+	pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
 	if (!pathname)
 		return -ENOMEM;
-	memset(pathname, 0, ACPI_PATHNAME_MAX);
 
 	buffer.length = ACPI_PATHNAME_MAX;
 	buffer.pointer = pathname;
@@ -345,12 +340,11 @@
 		return -EINVAL;
 	}
 
-	data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+	data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
 	if (!data) {
 		kfree(pathname);
 		return -ENOMEM;
 	}
-	memset(data, 0, sizeof(struct acpi_pci_data));
 
 	data->id = *id;
 	data->bus = bus;
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index feda034..fe7d007 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -89,10 +89,9 @@
 	if (!prt)
 		return -EINVAL;
 
-	entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
+	entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
 	if (!entry)
 		return -ENOMEM;
-	memset(entry, 0, sizeof(struct acpi_prt_entry));
 
 	entry->id.segment = segment;
 	entry->id.bus = bus;
@@ -161,10 +160,9 @@
 	static int first_time = 1;
 
 
-	pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+	pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
 	if (!pathname)
 		return -ENOMEM;
-	memset(pathname, 0, ACPI_PATHNAME_MAX);
 
 	if (first_time) {
 		acpi_prt.count = 0;
@@ -198,11 +196,10 @@
 		return -ENODEV;
 	}
 
-	prt = kmalloc(buffer.length, GFP_KERNEL);
+	prt = kzalloc(buffer.length, GFP_KERNEL);
 	if (!prt) {
 		return -ENOMEM;
 	}
-	memset(prt, 0, buffer.length);
 	buffer.pointer = prt;
 
 	status = acpi_get_irq_routing_table(handle, &buffer);
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index d53bd98..481e633 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -103,7 +103,7 @@
 static acpi_status
 acpi_pci_link_check_possible(struct acpi_resource *resource, void *context)
 {
-	struct acpi_pci_link *link = (struct acpi_pci_link *)context;
+	struct acpi_pci_link *link = context;
 	u32 i = 0;
 
 
@@ -307,11 +307,10 @@
 	if (!link || !irq)
 		return -EINVAL;
 
-	resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
+	resource = kzalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
 	if (!resource)
 		return -ENOMEM;
 
-	memset(resource, 0, sizeof(*resource) + 1);
 	buffer.length = sizeof(*resource) + 1;
 	buffer.pointer = resource;
 
@@ -613,7 +612,7 @@
 		return -1;
 	}
 
-	link = (struct acpi_pci_link *)acpi_driver_data(device);
+	link = acpi_driver_data(device);
 	if (!link) {
 		printk(KERN_ERR PREFIX "Invalid link context\n");
 		return -1;
@@ -668,7 +667,7 @@
 		return -1;
 	}
 
-	link = (struct acpi_pci_link *)acpi_driver_data(device);
+	link = acpi_driver_data(device);
 	if (!link) {
 		printk(KERN_ERR PREFIX "Invalid link context\n");
 		return -1;
@@ -718,10 +717,9 @@
 	if (!device)
 		return -EINVAL;
 
-	link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
+	link = kzalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
 	if (!link)
 		return -ENOMEM;
-	memset(link, 0, sizeof(struct acpi_pci_link));
 
 	link->device = device;
 	strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
@@ -808,7 +806,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	link = (struct acpi_pci_link *)acpi_driver_data(device);
+	link = acpi_driver_data(device);
 
 	mutex_lock(&acpi_link_lock);
 	list_del(&link->node);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 0984a1e..a860efa 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -98,11 +98,12 @@
 
 	struct acpi_pci_driver **pptr = &sub_driver;
 	while (*pptr) {
-		if (*pptr != driver)
-			continue;
-		*pptr = (*pptr)->next;
-		break;
+		if (*pptr == driver)
+			break;
+		pptr = &(*pptr)->next;
 	}
+	BUG_ON(!*pptr);
+	*pptr = (*pptr)->next;
 
 	if (!driver->remove)
 		return;
@@ -119,7 +120,7 @@
 static acpi_status
 get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
-	int *busnr = (int *)data;
+	int *busnr = data;
 	struct acpi_resource_address64 address;
 
 	if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
@@ -164,10 +165,9 @@
 	if (!device)
 		return -EINVAL;
 
-	root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
+	root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
 	if (!root)
 		return -ENOMEM;
-	memset(root, 0, sizeof(struct acpi_pci_root));
 	INIT_LIST_HEAD(&root->node);
 
 	root->device = device;
@@ -331,7 +331,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	root = (struct acpi_pci_root *)acpi_driver_data(device);
+	root = acpi_driver_data(device);
 
 	kfree(root);
 
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fe67a8a..0ba7dfb 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -108,7 +108,7 @@
 		return result;
 	}
 
-	*resource = (struct acpi_power_resource *)acpi_driver_data(device);
+	*resource = acpi_driver_data(device);
 	if (!resource)
 		return -ENODEV;
 
@@ -442,7 +442,7 @@
 	struct acpi_power_resource *resource = NULL;
 
 
-	resource = (struct acpi_power_resource *)seq->private;
+	resource = seq->private;
 
 	if (!resource)
 		goto end;
@@ -532,10 +532,9 @@
 	if (!device)
 		return -EINVAL;
 
-	resource = kmalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
+	resource = kzalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
 	if (!resource)
 		return -ENOMEM;
-	memset(resource, 0, sizeof(struct acpi_power_resource));
 
 	resource->device = device;
 	strcpy(resource->name, device->pnp.bus_id);
@@ -590,7 +589,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	resource = (struct acpi_power_resource *)acpi_driver_data(device);
+	resource = acpi_driver_data(device);
 
 	acpi_power_remove_fs(device);
 
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 1908e0d2..25718fe 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -277,7 +277,7 @@
 
 static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+	struct acpi_processor *pr = seq->private;
 
 
 	if (!pr)
@@ -542,12 +542,12 @@
 	 * Don't trust it blindly
 	 */
 	if (processor_device_array[pr->id] != NULL &&
-	    processor_device_array[pr->id] != (void *)device) {
+	    processor_device_array[pr->id] != device) {
 		printk(KERN_WARNING "BIOS reported wrong ACPI id"
 			"for the processor\n");
 		return -ENODEV;
 	}
-	processor_device_array[pr->id] = (void *)device;
+	processor_device_array[pr->id] = device;
 
 	processors[pr->id] = pr;
 
@@ -578,7 +578,7 @@
 
 static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_processor *pr = (struct acpi_processor *)data;
+	struct acpi_processor *pr = data;
 	struct acpi_device *device = NULL;
 
 
@@ -615,10 +615,9 @@
 	if (!device)
 		return -EINVAL;
 
-	pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+	pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
 	if (!pr)
 		return -ENOMEM;
-	memset(pr, 0, sizeof(struct acpi_processor));
 
 	pr->handle = device->handle;
 	strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
@@ -637,7 +636,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	pr = (struct acpi_processor *)acpi_driver_data(device);
+	pr = acpi_driver_data(device);
 
 	if (pr->id >= NR_CPUS) {
 		kfree(pr);
@@ -901,13 +900,13 @@
 
 	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
 	if (!acpi_processor_dir)
-		return 0;
+		return -ENOMEM;
 	acpi_processor_dir->owner = THIS_MODULE;
 
 	result = acpi_bus_register_driver(&acpi_processor_driver);
 	if (result < 0) {
 		remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-		return 0;
+		return result;
 	}
 
 	acpi_processor_install_hotplug_notify();
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 6dac605..3f30af2 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -681,7 +681,7 @@
 		return -ENODEV;
 	}
 
-	cst = (union acpi_object *)buffer.pointer;
+	cst = buffer.pointer;
 
 	/* There must be at least 2 elements */
 	if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
@@ -710,14 +710,14 @@
 
 		memset(&cx, 0, sizeof(cx));
 
-		element = (union acpi_object *)&(cst->package.elements[i]);
+		element = &(cst->package.elements[i]);
 		if (element->type != ACPI_TYPE_PACKAGE)
 			continue;
 
 		if (element->package.count != 4)
 			continue;
 
-		obj = (union acpi_object *)&(element->package.elements[0]);
+		obj = &(element->package.elements[0]);
 
 		if (obj->type != ACPI_TYPE_BUFFER)
 			continue;
@@ -729,7 +729,7 @@
 			continue;
 
 		/* There should be an easy way to extract an integer... */
-		obj = (union acpi_object *)&(element->package.elements[1]);
+		obj = &(element->package.elements[1]);
 		if (obj->type != ACPI_TYPE_INTEGER)
 			continue;
 
@@ -762,13 +762,13 @@
 			}
 		}
 
-		obj = (union acpi_object *)&(element->package.elements[2]);
+		obj = &(element->package.elements[2]);
 		if (obj->type != ACPI_TYPE_INTEGER)
 			continue;
 
 		cx.latency = obj->integer.value;
 
-		obj = (union acpi_object *)&(element->package.elements[3]);
+		obj = &(element->package.elements[3]);
 		if (obj->type != ACPI_TYPE_INTEGER)
 			continue;
 
@@ -1037,7 +1037,7 @@
 
 static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+	struct acpi_processor *pr = seq->private;
 	unsigned int i;
 
 
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 6fd174a..0e60382 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -236,7 +236,7 @@
 		return -ENODEV;
 	}
 
-	pss = (union acpi_object *)buffer.pointer;
+	pss = buffer.pointer;
 	if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
 		printk(KERN_ERR PREFIX "Invalid _PSS data\n");
 		result = -EFAULT;
@@ -410,7 +410,7 @@
 
 static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+	struct acpi_processor *pr = seq->private;
 	int i;
 
 
@@ -451,8 +451,8 @@
 				 size_t count, loff_t * data)
 {
 	int result = 0;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_processor *pr = (struct acpi_processor *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_processor *pr = m->private;
 	struct acpi_processor_performance *perf;
 	char state_string[12] = { '\0' };
 	unsigned int new_state = 0;
@@ -551,7 +551,7 @@
 		return -ENODEV;
 	}
 
-	psd = (union acpi_object *) buffer.pointer;
+	psd = buffer.pointer;
 	if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
 		result = -EFAULT;
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index ef5e0f6..40fecd6 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -208,7 +208,7 @@
 	if (result)
 		return result;
 
-	pr = (struct acpi_processor *)acpi_driver_data(device);
+	pr = acpi_driver_data(device);
 	if (!pr)
 		return -ENODEV;
 
@@ -348,8 +348,8 @@
 					  size_t count, loff_t * data)
 {
 	int result = 0;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_processor *pr = (struct acpi_processor *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_processor *pr = m->private;
 	char limit_string[25] = { '\0' };
 	int px = 0;
 	int tx = 0;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index d044ec5..0ec7dcd 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -259,7 +259,7 @@
 static int acpi_processor_throttling_seq_show(struct seq_file *seq,
 					      void *offset)
 {
-	struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+	struct acpi_processor *pr = seq->private;
 	int i = 0;
 	int result = 0;
 
@@ -307,8 +307,8 @@
 					       size_t count, loff_t * data)
 {
 	int result = 0;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_processor *pr = (struct acpi_processor *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_processor *pr = m->private;
 	char state_string[12] = { '\0' };
 
 
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 8908a97..f58fc74 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -923,7 +923,7 @@
 
 static int acpi_battery_read_info(struct seq_file *seq, void *offset)
 {
-	struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+	struct acpi_battery *battery = seq->private;
 	int cscale;
 	int result = 0;
 
@@ -1076,7 +1076,7 @@
 
 static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
 {
-	struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+	struct acpi_battery *battery = seq->private;
 	int result = 0;
 	int cscale;
 
@@ -1125,8 +1125,8 @@
 acpi_battery_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_battery *battery = (struct acpi_battery *)seq->private;
+	struct seq_file *seq = file->private_data;
+	struct acpi_battery *battery = seq->private;
 	char alarm_string[12] = { '\0' };
 	int result, old_alarm, new_alarm;
 
@@ -1160,14 +1160,14 @@
 	if (result) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "acpi_battery_set_alarm() failed\n"));
-		(void)acpi_battery_set_alarm(battery, old_alarm);
+		acpi_battery_set_alarm(battery, old_alarm);
 		goto end;
 	}
 	result = acpi_battery_get_alarm(battery);
 	if (result) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "acpi_battery_get_alarm() failed\n"));
-		(void)acpi_battery_set_alarm(battery, old_alarm);
+		acpi_battery_set_alarm(battery, old_alarm);
 		goto end;
 	}
 
@@ -1217,7 +1217,7 @@
 
 static int acpi_ac_read_state(struct seq_file *seq, void *offset)
 {
-	struct acpi_sbs *sbs = (struct acpi_sbs *)seq->private;
+	struct acpi_sbs *sbs = seq->private;
 	int result;
 
 	if (sbs->zombie) {
@@ -1302,7 +1302,7 @@
 		battery->init_state = 1;
 	}
 
-	(void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+	sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
 
 	result = acpi_sbs_generic_add_fs(&battery->battery_entry,
 					 acpi_battery_dir,
@@ -1485,7 +1485,7 @@
 		}
 
 		if (old_battery_present != new_battery_present) {
-			(void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+			sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
 			result = acpi_sbs_generate_event(sbs->device,
 							 ACPI_SBS_BATTERY_NOTIFY_STATUS,
 							 new_battery_present,
@@ -1498,7 +1498,7 @@
 			}
 		}
 		if (old_remaining_capacity != battery->state.remaining_capacity) {
-			(void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+			sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
 			result = acpi_sbs_generate_event(sbs->device,
 							 ACPI_SBS_BATTERY_NOTIFY_STATUS,
 							 new_battery_present,
@@ -1576,12 +1576,11 @@
 	int id, cnt;
 	acpi_status status = AE_OK;
 
-	sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
+	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
 	if (!sbs) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
 		return -ENOMEM;
 	}
-	memset(sbs, 0, sizeof(struct acpi_sbs));
 
 	cnt = 0;
 	while (cnt < 10) {
@@ -1659,7 +1658,7 @@
 	init_timer(&sbs->update_timer);
 	if (update_mode == QUEUE_UPDATE_MODE) {
 		status = acpi_os_execute(OSL_GPE_HANDLER,
-					 acpi_sbs_update_queue, (void *)sbs);
+					 acpi_sbs_update_queue, sbs);
 		if (status != AE_OK) {
 			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 					  "acpi_os_execute() failed\n"));
@@ -1685,7 +1684,7 @@
 
 int acpi_sbs_remove(struct acpi_device *device, int type)
 {
-	struct acpi_sbs *sbs = NULL;
+	struct acpi_sbs *sbs;
 	int id;
 
 	if (!device) {
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 698a154..283d875 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -984,12 +984,11 @@
 	if (!child)
 		return -EINVAL;
 
-	device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
+	device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL);
 	if (!device) {
 		printk(KERN_ERR PREFIX "Memory allocation error\n");
 		return -ENOMEM;
 	}
-	memset(device, 0, sizeof(struct acpi_device));
 
 	device->handle = handle;
 	device->parent = parent;
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index af1dbab..fab8f26 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -183,11 +183,11 @@
 #endif
 
 /*
- * Disable all wakeup GPEs before power off.
- * 
+ * Disable all wakeup GPEs before entering requested sleep state.
+ *	@sleep_state:	ACPI state
  * Since acpi_enter_sleep_state() will disable all
  * RUNTIME GPEs, we simply mark all GPES that
- * are not enabled for wakeup from S5 as RUNTIME.
+ * are not enabled for wakeup from requested state as RUNTIME.
  */
 void acpi_gpe_sleep_prepare(u32 sleep_state)
 {
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index bfb3bfc..ffa30c9 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -228,7 +228,7 @@
 static int
 acpi_table_compute_checksum(void *table_pointer, unsigned long length)
 {
-	u8 *p = (u8 *) table_pointer;
+	u8 *p = table_pointer;
 	unsigned long remains = length;
 	unsigned long sum = 0;
 
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 7767987..5ba9303 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -123,7 +123,6 @@
 
 ACPI_EXPORT_SYMBOL(acpi_load_tables)
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_table
@@ -221,6 +220,59 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_unload_table_id
+ *
+ * PARAMETERS:  table_type    - Type of table to be unloaded
+ *              id            - Owner ID of the table to be removed.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This routine is used to force the unload of a table (by id)
+ *
+ ******************************************************************************/
+acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id)
+{
+	struct acpi_table_desc *table_desc;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_unload_table);
+
+	/* Parameter validation */
+	if (table_type > ACPI_TABLE_ID_MAX)
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+	/* Find table from the requested type list */
+	table_desc = acpi_gbl_table_lists[table_type].next;
+	while (table_desc && table_desc->owner_id != id)
+		table_desc = table_desc->next;
+
+	if (!table_desc)
+		return_ACPI_STATUS(AE_NOT_EXIST);
+
+	/*
+	 * Delete all namespace objects owned by this table. Note that these
+	 * objects can appear anywhere in the namespace by virtue of the AML
+	 * "Scope" operator. Thus, we need to track ownership by an ID, not
+	 * simply a position within the hierarchy
+	 */
+	acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(status);
+
+	(void)acpi_tb_uninstall_table(table_desc);
+
+	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
+
+#ifdef ACPI_FUTURE_USAGE
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_unload_table
  *
  * PARAMETERS:  table_type    - Type of table to be unloaded
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5753d06..40ddb4d 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -663,7 +663,7 @@
 static void acpi_thermal_check(void *data)
 {
 	int result = 0;
-	struct acpi_thermal *tz = (struct acpi_thermal *)data;
+	struct acpi_thermal *tz = data;
 	unsigned long sleep_time = 0;
 	int i = 0;
 	struct acpi_thermal_state state;
@@ -778,7 +778,7 @@
 
 static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+	struct acpi_thermal *tz = seq->private;
 
 
 	if (!tz)
@@ -813,7 +813,7 @@
 static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
 {
 	int result = 0;
-	struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+	struct acpi_thermal *tz = seq->private;
 
 
 	if (!tz)
@@ -837,7 +837,7 @@
 
 static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+	struct acpi_thermal *tz = seq->private;
 	int i = 0;
 	int j = 0;
 
@@ -893,8 +893,8 @@
 			       const char __user * buffer,
 			       size_t count, loff_t * ppos)
 {
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_thermal *tz = m->private;
 
 	char *limit_string;
 	int num, critical, hot, passive;
@@ -902,12 +902,10 @@
 	int i = 0;
 
 
-	limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
+	limit_string = kzalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
 	if (!limit_string)
 		return -ENOMEM;
 
-	memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
-
 	active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
 	if (!active) {
 		kfree(limit_string);
@@ -953,7 +951,7 @@
 
 static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+	struct acpi_thermal *tz = seq->private;
 
 
 	if (!tz)
@@ -984,8 +982,8 @@
 				const char __user * buffer,
 				size_t count, loff_t * ppos)
 {
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_thermal *tz = m->private;
 	int result = 0;
 	char mode_string[12] = { '\0' };
 
@@ -1014,7 +1012,7 @@
 
 static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+	struct acpi_thermal *tz = seq->private;
 
 
 	if (!tz)
@@ -1043,8 +1041,8 @@
 			   const char __user * buffer,
 			   size_t count, loff_t * ppos)
 {
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_thermal *tz = m->private;
 	int result = 0;
 	char polling_string[12] = { '\0' };
 	int seconds = 0;
@@ -1170,7 +1168,7 @@
 
 static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_thermal *tz = (struct acpi_thermal *)data;
+	struct acpi_thermal *tz = data;
 	struct acpi_device *device = NULL;
 
 
@@ -1271,10 +1269,9 @@
 	if (!device)
 		return -EINVAL;
 
-	tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
+	tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
 	if (!tz)
 		return -ENOMEM;
-	memset(tz, 0, sizeof(struct acpi_thermal));
 
 	tz->device = device;
 	strcpy(tz->name, device->pnp.bus_id);
@@ -1324,7 +1321,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	tz = (struct acpi_thermal *)acpi_driver_data(device);
+	tz = acpi_driver_data(device);
 
 	/* avoid timer adding new defer task */
 	tz->zombie = 1;
@@ -1364,7 +1361,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	tz = (struct acpi_thermal *)acpi_driver_data(device);
+	tz = acpi_driver_data(device);
 
 	acpi_thermal_get_temperature(tz);
 
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 7fe0b7a..88aeccb 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -41,6 +41,8 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <linux/backlight.h>
+
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_drivers.h>
@@ -210,6 +212,7 @@
 }
 
 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
+static struct backlight_device *toshiba_backlight_device;
 static int force_fan;
 static int last_key_event;
 static int key_event_valid;
@@ -271,14 +274,23 @@
 	return result;
 }
 
-static char *read_lcd(char *p)
+static int get_lcd(struct backlight_device *bd)
 {
 	u32 hci_result;
 	u32 value;
 
 	hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
 	if (hci_result == HCI_SUCCESS) {
-		value = value >> HCI_LCD_BRIGHTNESS_SHIFT;
+		return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
+	} else
+		return -EFAULT;
+}
+
+static char *read_lcd(char *p)
+{
+	int value = get_lcd(NULL);
+
+	if (value >= 0) {
 		p += sprintf(p, "brightness:              %d\n", value);
 		p += sprintf(p, "brightness_levels:       %d\n",
 			     HCI_LCD_BRIGHTNESS_LEVELS);
@@ -289,22 +301,34 @@
 	return p;
 }
 
+static int set_lcd(int value)
+{
+	u32 hci_result;
+
+	value = value << HCI_LCD_BRIGHTNESS_SHIFT;
+	hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
+	if (hci_result != HCI_SUCCESS)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int set_lcd_status(struct backlight_device *bd)
+{
+	return set_lcd(bd->props->brightness);
+}
+
 static unsigned long write_lcd(const char *buffer, unsigned long count)
 {
 	int value;
-	u32 hci_result;
+	int ret = count;
 
 	if (sscanf(buffer, " brightness : %i", &value) == 1 &&
-	    value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
-		value = value << HCI_LCD_BRIGHTNESS_SHIFT;
-		hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
-		if (hci_result != HCI_SUCCESS)
-			return -EFAULT;
-	} else {
-		return -EINVAL;
-	}
-
-	return count;
+	    value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS)
+		ret = set_lcd(value);
+	else
+		ret = -EINVAL;
+	return ret;
 }
 
 static char *read_video(char *p)
@@ -506,6 +530,26 @@
 	return AE_OK;
 }
 
+static struct backlight_properties toshiba_backlight_data = {
+        .owner          = THIS_MODULE,
+        .get_brightness = get_lcd,
+        .update_status  = set_lcd_status,
+        .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1,
+};
+
+static void __exit toshiba_acpi_exit(void)
+{
+	if (toshiba_backlight_device)
+		backlight_device_unregister(toshiba_backlight_device);
+
+	remove_device();
+
+	if (toshiba_proc_dir)
+		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+
+	return;
+}
+
 static int __init toshiba_acpi_init(void)
 {
 	acpi_status status = AE_OK;
@@ -546,18 +590,17 @@
 			remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
 	}
 
+	toshiba_backlight_device = backlight_device_register("toshiba",NULL,
+						NULL,
+						&toshiba_backlight_data);
+        if (IS_ERR(toshiba_backlight_device)) {
+		printk(KERN_ERR "Could not register toshiba backlight device\n");
+		toshiba_backlight_device = NULL;
+		toshiba_acpi_exit();
+	}
+
 	return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
 }
 
-static void __exit toshiba_acpi_exit(void)
-{
-	remove_device();
-
-	if (toshiba_proc_dir)
-		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
-
-	return;
-}
-
 module_init(toshiba_acpi_init);
 module_exit(toshiba_acpi_exit);
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index bb1eaf9..9e9054e 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -180,8 +180,9 @@
 	if (thread_id != acpi_gbl_prev_thread_id) {
 		if (ACPI_LV_THREADS & acpi_dbg_level) {
 			acpi_os_printf
-			    ("\n**** Context Switch from TID %X to TID %X ****\n\n",
-			     (u32) acpi_gbl_prev_thread_id, (u32) thread_id);
+			    ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
+			     (unsigned long) acpi_gbl_prev_thread_id,
+			     (unsigned long) thread_id);
 		}
 
 		acpi_gbl_prev_thread_id = thread_id;
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index c39062a..180e73c 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -243,23 +243,24 @@
 #endif
 
 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-			  "Thread %X attempting to acquire Mutex [%s]\n",
-			  (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
+			  "Thread %lX attempting to acquire Mutex [%s]\n",
+			  (unsigned long) this_thread_id,
+			  acpi_ut_get_mutex_name(mutex_id)));
 
 	status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
 				       ACPI_WAIT_FOREVER);
 	if (ACPI_SUCCESS(status)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-				  "Thread %X acquired Mutex [%s]\n",
-				  (u32) this_thread_id,
+				  "Thread %lX acquired Mutex [%s]\n",
+				  (unsigned long) this_thread_id,
 				  acpi_ut_get_mutex_name(mutex_id)));
 
 		acpi_gbl_mutex_info[mutex_id].use_count++;
 		acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
 	} else {
 		ACPI_EXCEPTION((AE_INFO, status,
-				"Thread %X could not acquire Mutex [%X]",
-				(u32) this_thread_id, mutex_id));
+				"Thread %lX could not acquire Mutex [%X]",
+				(unsigned long) this_thread_id, mutex_id));
 	}
 
 	return (status);
@@ -285,7 +286,8 @@
 
 	this_thread_id = acpi_os_get_thread_id();
 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-			  "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id,
+			  "Thread %lX releasing Mutex [%s]\n",
+			  (unsigned long) this_thread_id,
 			  acpi_ut_get_mutex_name(mutex_id)));
 
 	if (mutex_id > ACPI_MAX_MUTEX) {
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index d0d84c4..68a809f 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -83,7 +83,7 @@
 		return AE_BAD_DATA;
 	}
 
-	format_string = (char *)format->pointer;
+	format_string = format->pointer;
 
 	/*
 	 * Calculate size_required.
@@ -262,11 +262,10 @@
 	if (!data)
 		return AE_BAD_PARAMETER;
 
-	element = kmalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
+	element = kzalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
 	if (!element)
 		return AE_NO_MEMORY;
 
-	memset(element, 0, sizeof(union acpi_object));
 	buffer.length = sizeof(union acpi_object);
 	buffer.pointer = element;
 	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
@@ -321,12 +320,11 @@
 		return AE_BAD_DATA;
 	}
 
-	*data = kmalloc(element->string.length + 1, GFP_KERNEL);
+	*data = kzalloc(element->string.length + 1, GFP_KERNEL);
 	if (!data) {
 		printk(KERN_ERR PREFIX "Memory allocation\n");
 		return -ENOMEM;
 	}
-	memset(*data, 0, element->string.length + 1);
 
 	memcpy(*data, element->string.pointer, element->string.length);
 
@@ -361,7 +359,7 @@
 	if (ACPI_FAILURE(status))
 		goto end;
 
-	package = (union acpi_object *)buffer.pointer;
+	package = buffer.pointer;
 
 	if ((buffer.length == 0) || !package) {
 		printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 56666a9..36b37d7 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
  *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ *  Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -47,11 +48,11 @@
 #define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT	0x83
 #define ACPI_VIDEO_NOTIFY_PREV_OUTPUT	0x84
 
-#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS	0x82
-#define	ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS	0x83
-#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS	0x84
-#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS	0x85
-#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF		0x86
+#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS	0x85
+#define	ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS	0x86
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS	0x87
+#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS	0x88
+#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF		0x89
 
 #define ACPI_VIDEO_HEAD_INVALID		(~0u - 1)
 #define ACPI_VIDEO_HEAD_END		(~0u)
@@ -386,7 +387,7 @@
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	obj = (union acpi_object *)buffer.pointer;
+	obj = buffer.pointer;
 
 	if (obj && obj->type == ACPI_TYPE_BUFFER)
 		*edid = obj;
@@ -532,11 +533,10 @@
 		int count = 0;
 		union acpi_object *o;
 
-		br = kmalloc(sizeof(*br), GFP_KERNEL);
+		br = kzalloc(sizeof(*br), GFP_KERNEL);
 		if (!br) {
 			printk(KERN_ERR "can't allocate memory\n");
 		} else {
-			memset(br, 0, sizeof(*br));
 			br->levels = kmalloc(obj->package.count *
 					     sizeof *(br->levels), GFP_KERNEL);
 			if (!br->levels)
@@ -654,8 +654,7 @@
 
 static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_device *dev =
-	    (struct acpi_video_device *)seq->private;
+	struct acpi_video_device *dev = seq->private;
 
 
 	if (!dev)
@@ -688,8 +687,7 @@
 static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
 {
 	int status;
-	struct acpi_video_device *dev =
-	    (struct acpi_video_device *)seq->private;
+	struct acpi_video_device *dev = seq->private;
 	unsigned long state;
 
 
@@ -727,8 +725,8 @@
 			      size_t count, loff_t * data)
 {
 	int status;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_video_device *dev = m->private;
 	char str[12] = { 0 };
 	u32 state = 0;
 
@@ -754,8 +752,7 @@
 static int
 acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_device *dev =
-	    (struct acpi_video_device *)seq->private;
+	struct acpi_video_device *dev = seq->private;
 	int i;
 
 
@@ -784,8 +781,8 @@
 				   const char __user * buffer,
 				   size_t count, loff_t * data)
 {
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_video_device *dev = m->private;
 	char str[4] = { 0 };
 	unsigned int level = 0;
 	int i;
@@ -817,8 +814,7 @@
 
 static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_device *dev =
-	    (struct acpi_video_device *)seq->private;
+	struct acpi_video_device *dev = seq->private;
 	int status;
 	int i;
 	union acpi_object *edid = NULL;
@@ -866,7 +862,7 @@
 	if (!device)
 		return -ENODEV;
 
-	vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
+	vid_dev = acpi_driver_data(device);
 	if (!vid_dev)
 		return -ENODEV;
 
@@ -931,7 +927,7 @@
 {
 	struct acpi_video_device *vid_dev;
 
-	vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
+	vid_dev = acpi_driver_data(device);
 	if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
 		return -ENODEV;
 
@@ -950,7 +946,7 @@
 /* video bus */
 static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+	struct acpi_video_bus *video = seq->private;
 
 
 	if (!video)
@@ -975,7 +971,7 @@
 
 static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+	struct acpi_video_bus *video = seq->private;
 
 
 	if (!video)
@@ -995,7 +991,7 @@
 
 static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+	struct acpi_video_bus *video = seq->private;
 	unsigned long options;
 	int status;
 
@@ -1033,7 +1029,7 @@
 
 static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+	struct acpi_video_bus *video = seq->private;
 	int status;
 	unsigned long id;
 
@@ -1054,7 +1050,7 @@
 
 static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
 {
-	struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
+	struct acpi_video_bus *video = seq->private;
 
 
 	seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
@@ -1079,8 +1075,8 @@
 			  size_t count, loff_t * data)
 {
 	int status;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_video_bus *video = m->private;
 	char str[12] = { 0 };
 	unsigned long opt, options;
 
@@ -1119,8 +1115,8 @@
 			 size_t count, loff_t * data)
 {
 	int status;
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
+	struct seq_file *m = file->private_data;
+	struct acpi_video_bus *video = m->private;
 	char str[12] = { 0 };
 	unsigned long opt;
 
@@ -1150,7 +1146,7 @@
 	struct acpi_video_bus *video;
 
 
-	video = (struct acpi_video_bus *)acpi_driver_data(device);
+	video = acpi_driver_data(device);
 
 	if (!acpi_device_dir(device)) {
 		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -1226,7 +1222,7 @@
 	struct acpi_video_bus *video;
 
 
-	video = (struct acpi_video_bus *)acpi_driver_data(device);
+	video = acpi_driver_data(device);
 
 	if (acpi_device_dir(device)) {
 		remove_proc_entry("info", acpi_device_dir(device));
@@ -1263,12 +1259,10 @@
 	    acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
 	if (ACPI_SUCCESS(status)) {
 
-		data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+		data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
 		if (!data)
 			return -ENOMEM;
 
-		memset(data, 0, sizeof(struct acpi_video_device));
-
 		strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
 		strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
 		acpi_driver_data(device) = data;
@@ -1403,7 +1397,7 @@
 		return status;
 	}
 
-	dod = (union acpi_object *)buffer.pointer;
+	dod = buffer.pointer;
 	if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
 		status = -EFAULT;
@@ -1426,7 +1420,7 @@
 
 	count = 0;
 	for (i = 0; i < dod->package.count; i++) {
-		obj = (union acpi_object *)&dod->package.elements[i];
+		obj = &dod->package.elements[i];
 
 		if (obj->type != ACPI_TYPE_INTEGER) {
 			printk(KERN_ERR PREFIX "Invalid _DOD data\n");
@@ -1509,8 +1503,34 @@
 acpi_video_get_next_level(struct acpi_video_device *device,
 			  u32 level_current, u32 event)
 {
-	/*Fix me */
-	return level_current;
+	int min, max, min_above, max_below, i, l;
+	max = max_below = 0;
+	min = min_above = 255;
+	for (i = 0; i < device->brightness->count; i++) {
+		l = device->brightness->levels[i];
+		if (l < min)
+			min = l;
+		if (l > max)
+			max = l;
+		if (l < min_above && l > level_current)
+			min_above = l;
+		if (l > max_below && l < level_current)
+			max_below = l;
+	}
+
+	switch (event) {
+	case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
+		return (level_current < max) ? min_above : min;
+	case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
+		return (level_current < max) ? min_above : max;
+	case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
+		return (level_current > min) ? max_below : min;
+	case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
+	case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
+		return 0;
+	default:
+		return level_current;
+	}
 }
 
 static void
@@ -1612,7 +1632,7 @@
 
 static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_video_bus *video = (struct acpi_video_bus *)data;
+	struct acpi_video_bus *video = data;
 	struct acpi_device *device = NULL;
 
 	printk("video bus notify\n");
@@ -1654,8 +1674,7 @@
 
 static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct acpi_video_device *video_device =
-	    (struct acpi_video_device *)data;
+	struct acpi_video_device *video_device = data;
 	struct acpi_device *device = NULL;
 
 
@@ -1696,10 +1715,9 @@
 	if (!device)
 		return -EINVAL;
 
-	video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
+	video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
 	if (!video)
 		return -ENOMEM;
-	memset(video, 0, sizeof(struct acpi_video_bus));
 
 	video->device = device;
 	strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
@@ -1757,7 +1775,7 @@
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
-	video = (struct acpi_video_bus *)acpi_driver_data(device);
+	video = acpi_driver_data(device);
 
 	acpi_video_bus_stop_devices(video);
 
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index fdb7153..8e5e07e 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -317,7 +317,8 @@
 
 	/* Register backlight stuff */
 
-	msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
+	msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL,
+						&msibl_props);
 	if (IS_ERR(msibl_device))
 		return PTR_ERR(msibl_device);
 
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index bd40aee..7f03881 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -319,13 +319,12 @@
 	if (bufp == NULL)
 		goto read_table_done;
 
-	lbuf = kmalloc(size, GFP_KERNEL);
+	lbuf = kzalloc(size, GFP_KERNEL);
 	dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
 			__FUNCTION__, package->package.count, size, lbuf);
 
 	if (lbuf) {
 		*bufp = lbuf;
-		memset(lbuf, 0, size);
 	} else {
 		size = -ENOMEM;
 		goto read_table_done;
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 02cbb7f..a7932a7 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -281,7 +281,7 @@
 	/* Register backlight device */
 	snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
 		atomic_inc_return(&count_displays) - 1);
-	pdata->bd = backlight_device_register(bl_name, pdata,
+	pdata->bd = backlight_device_register(bl_name, NULL, NULL,
 						&appledisplay_bl_data);
 	if (IS_ERR(pdata->bd)) {
 		err("appledisplay: Backlight registration failed");
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 3feddf8..2e976ff 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1834,7 +1834,7 @@
 
 	snprintf(name, sizeof(name), "aty128bl%d", info->node);
 
-	bd = backlight_device_register(name, par, &aty128_bl_data);
+	bd = backlight_device_register(name, info->dev, par, &aty128_bl_data);
 	if (IS_ERR(bd)) {
 		info->bl_dev = NULL;
 		printk(KERN_WARNING "aty128: Backlight registration failed\n");
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 09684d7..f2ebdd8 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2211,7 +2211,7 @@
 
 	snprintf(name, sizeof(name), "atybl%d", info->node);
 
-	bd = backlight_device_register(name, par, &aty_bl_data);
+	bd = backlight_device_register(name, info->dev, par, &aty_bl_data);
 	if (IS_ERR(bd)) {
 		info->bl_dev = NULL;
 		printk(KERN_WARNING "aty: Backlight registration failed\n");
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 585eb7b..3abfd4a 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -163,7 +163,7 @@
 
 	snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
 
-	bd = backlight_device_register(name, pdata, &radeon_bl_data);
+	bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data);
 	if (IS_ERR(bd)) {
 		rinfo->info->bl_dev = NULL;
 		printk("radeonfb: Backlight registration failed\n");
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index db8c191..9601bfe 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -216,8 +216,10 @@
  * Creates and registers new backlight class_device. Returns either an
  * ERR_PTR() or a pointer to the newly allocated device.
  */
-struct backlight_device *backlight_device_register(const char *name, void *devdata,
-						   struct backlight_properties *bp)
+struct backlight_device *backlight_device_register(const char *name,
+	struct device *dev,
+	void *devdata,
+	struct backlight_properties *bp)
 {
 	int i, rc;
 	struct backlight_device *new_bd;
@@ -232,6 +234,7 @@
 	new_bd->props = bp;
 	memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
 	new_bd->class_dev.class = &backlight_class;
+	new_bd->class_dev.dev = dev;
 	strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
 	class_set_devdata(&new_bd->class_dev, devdata);
 
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 5b75ae4..df934bd 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -141,7 +141,7 @@
 
 	snprintf(name, sizeof(name), "nvidiabl%d", info->node);
 
-	bd = backlight_device_register(name, par, &nvidia_bl_data);
+	bd = backlight_device_register(name, info->dev, par, &nvidia_bl_data);
 	if (IS_ERR(bd)) {
 		info->bl_dev = NULL;
 		printk(KERN_WARNING "nvidia: Backlight registration failed\n");
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 345e8b1..1a13966 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -384,7 +384,7 @@
 
 	snprintf(name, sizeof(name), "rivabl%d", info->node);
 
-	bd = backlight_device_register(name, par, &riva_bl_data);
+	bd = backlight_device_register(name, info->dev, par, &riva_bl_data);
 	if (IS_ERR(bd)) {
 		info->bl_dev = NULL;
 		printk(KERN_WARNING "riva: Backlight registration failed\n");
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 049e9aa..8145876 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -97,11 +97,12 @@
 
 acpi_status acpi_load_tables(void);
 
-#ifdef ACPI_FUTURE_USAGE
 acpi_status acpi_load_table(struct acpi_table_header *table_ptr);
 
-acpi_status acpi_unload_table(acpi_table_type table_type);
+acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id);
 
+#ifdef ACPI_FUTURE_USAGE
+acpi_status acpi_unload_table(acpi_table_type table_type);
 acpi_status
 acpi_get_table_header(acpi_table_type table_type,
 		      u32 instance, struct acpi_table_header *out_table_header);
@@ -180,6 +181,8 @@
 
 acpi_status acpi_get_type(acpi_handle object, acpi_object_type * out_type);
 
+acpi_status acpi_get_id(acpi_handle object, acpi_owner_id * out_type);
+
 acpi_status acpi_get_parent(acpi_handle object, acpi_handle * out_handle);
 
 /*
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
index c80b3a9..7cfad93 100644
--- a/include/asm-i386/acpi.h
+++ b/include/asm-i386/acpi.h
@@ -56,30 +56,8 @@
 #define ACPI_ENABLE_IRQS()  local_irq_enable()
 #define ACPI_FLUSH_CPU_CACHE()	wbinvd()
 
-
-static inline int
-__acpi_acquire_global_lock (unsigned int *lock)
-{
-	unsigned int old, new, val;
-	do {
-		old = *lock;
-		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
-		val = cmpxchg(lock, old, new);
-	} while (unlikely (val != old));
-	return (new < 3) ? -1 : 0;
-}
-
-static inline int
-__acpi_release_global_lock (unsigned int *lock)
-{
-	unsigned int old, new, val;
-	do {
-		old = *lock;
-		new = old & ~0x3;
-		val = cmpxchg(lock, old, new);
-	} while (unlikely (val != old));
-	return old & 0x1;
-}
+int __acpi_acquire_global_lock(unsigned int *lock);
+int __acpi_release_global_lock(unsigned int *lock);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
 	((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index 9d1916e..6b6fc6f 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -54,30 +54,8 @@
 #define ACPI_ENABLE_IRQS()  local_irq_enable()
 #define ACPI_FLUSH_CPU_CACHE()	wbinvd()
 
-
-static inline int
-__acpi_acquire_global_lock (unsigned int *lock)
-{
-	unsigned int old, new, val;
-	do {
-		old = *lock;
-		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
-		val = cmpxchg(lock, old, new);
-	} while (unlikely (val != old));
-	return (new < 3) ? -1 : 0;
-}
-
-static inline int
-__acpi_release_global_lock (unsigned int *lock)
-{
-	unsigned int old, new, val;
-	do {
-		old = *lock;
-		new = old & ~0x3;
-		val = cmpxchg(lock, old, new);
-	} while (unlikely (val != old));
-	return old & 0x1;
-}
+int __acpi_acquire_global_lock(unsigned int *lock);
+int __acpi_release_global_lock(unsigned int *lock);
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
 	((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 75e91f5..a5cf1be 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -54,7 +54,7 @@
 };
 
 extern struct backlight_device *backlight_device_register(const char *name,
-	void *devdata, struct backlight_properties *bp);
+	struct device *dev,void *devdata,struct backlight_properties *bp);
 extern void backlight_device_unregister(struct backlight_device *bd);
 
 #define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev)
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 0b00f56..88fc5d7 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -60,9 +60,11 @@
 {
 	switch(mode) {
 	case PM_DISK_PLATFORM:
-		kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-		pm_ops->enter(PM_SUSPEND_DISK);
-		break;
+		if (pm_ops && pm_ops->enter) {
+			kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+			pm_ops->enter(PM_SUSPEND_DISK);
+			break;
+		}
 	case PM_DISK_SHUTDOWN:
 		kernel_power_off();
 		break;
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 500eb87..ff3a618 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -29,7 +29,7 @@
 DEFINE_MUTEX(pm_mutex);
 
 struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
+suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
 
 /**
  *	pm_set_ops - Set the global power method table.