Pull style into test branch
authorLen Brown <len.brown@intel.com>
Sat, 16 Dec 2006 06:04:27 +0000 (01:04 -0500)
committerLen Brown <len.brown@intel.com>
Sat, 16 Dec 2006 06:04:27 +0000 (01:04 -0500)
Conflicts:

drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/osl.c
drivers/acpi/sbs.c

13 files changed:
1  2 
drivers/acpi/acpi_memhotplug.c
drivers/acpi/asus_acpi.c
drivers/acpi/battery.c
drivers/acpi/dock.c
drivers/acpi/glue.c
drivers/acpi/ibm_acpi.c
drivers/acpi/osl.c
drivers/acpi/pci_link.c
drivers/acpi/power.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_perflib.c
drivers/acpi/sbs.c

index 6bcd9e8e7bcb2b081df4262a20489f9fd7ec0779,13687835c460bd602f8dfceea8c0c4a36e549bc9..150112ae48ed7e6bfdd4afefa7d17b7bd244845d
@@@ -85,8 -85,6 +85,8 @@@ struct acpi_memory_device 
        struct list_head res_list;
  };
  
 +static int acpi_hotmem_initialized;
 +
  static acpi_status
  acpi_memory_get_resource(struct acpi_resource *resource, void *context)
  {
@@@ -416,7 -414,7 +416,7 @@@ static int acpi_memory_device_add(struc
        /* Set the device state */
        mem_device->state = MEMORY_POWER_ON_STATE;
  
 -      printk(KERN_INFO "%s \n", acpi_device_name(device));
 +      printk(KERN_DEBUG "%s \n", acpi_device_name(device));
  
        return result;
  }
@@@ -429,7 -427,7 +429,7 @@@ static int acpi_memory_device_remove(st
        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;
@@@ -440,15 -438,6 +440,15 @@@ static int acpi_memory_device_start (st
        struct acpi_memory_device *mem_device;
        int result = 0;
  
 +      /*
 +       * Early boot code has recognized memory area by EFI/E820.
 +       * If DSDT shows these memory devices on boot, hotplug is not necessary
 +       * for them. So, it just returns until completion of this driver's
 +       * start up.
 +       */
 +      if (!acpi_hotmem_initialized)
 +              return 0;
 +
        mem_device = acpi_driver_data(device);
  
        if (!acpi_memory_check_device(mem_device)) {
@@@ -548,7 -537,6 +548,7 @@@ static int __init acpi_memory_device_in
                return -ENODEV;
        }
  
 +      acpi_hotmem_initialized = 1;
        return 0;
  }
  
diff --combined drivers/acpi/asus_acpi.c
index bf7bc25e680efa6e53d863b26a51608f122cd8ea,f7db8ea7ac0a6c023db1d2db74c8efcd13a86f75..bfae3ffff13c050017d28cf209e1718ce2cee8ab
@@@ -35,7 -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>
@@@ -139,7 -138,6 +139,7 @@@ struct asus_hotk 
                S2x,            //S200 (J1 reported), Victor MP-XP7210
                W1N,            //W1000N
                W5A,            //W5A
 +              W3V,            //W3030V
                xxN,            //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
                //(Centrino)
                END_MODEL
@@@ -378,17 -376,6 +378,17 @@@ static struct model_data model_conf[END
         .display_get = "\\ADVG"},
  
        {
 +       .name = "W3V",
 +       .mt_mled = "MLED",
 +       .mt_wled = "WLED",
 +       .mt_lcd_switch = xxN_PREFIX "_Q10",
 +       .lcd_status = "\\BKLT",
 +       .brightness_set = "SPLV",
 +       .brightness_get = "GPLV",
 +       .display_set = "SDSP",
 +       .display_get = "\\INFB"},
 +
 +       {
         .name = "xxN",
         .mt_mled = "MLED",
  /* WLED present, but not controlled by ACPI */
  /* 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
@@@ -570,11 -555,11 +570,11 @@@ static in
  write_led(const char __user * buffer, unsigned long count,
          char *ledname, int ledmask, int invert)
  {
 -      int value;
 +      int rv, value;
        int led_out = 0;
  
 -      count = parse_arg(buffer, count, &value);
 -      if (count > 0)
 +      rv = parse_arg(buffer, count, &value);
 +      if (rv > 0)
                led_out = value ? 1 : 0;
  
        hotk->status =
                printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
                       ledname);
  
 -      return count;
 +      return rv;
  }
  
  /*
@@@ -622,18 -607,20 +622,18 @@@ static in
  proc_write_ledd(struct file *file, const char __user * buffer,
                unsigned long count, void *data)
  {
 -      int value;
 +      int rv, value;
  
 -      count = parse_arg(buffer, count, &value);
 -      if (count > 0) {
 +      rv = parse_arg(buffer, count, &value);
 +      if (rv > 0) {
                if (!write_acpi_int
                    (hotk->handle, hotk->methods->mt_ledd, value, NULL))
                        printk(KERN_WARNING
                               "Asus ACPI: LED display write failed\n");
                else
                        hotk->ledd_status = (u32) value;
 -      } else if (count < 0)
 -              printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
 -
 -      return count;
 +      }
 +      return rv;
  }
  
  /*
@@@ -774,15 -761,15 +774,15 @@@ static in
  proc_write_lcd(struct file *file, const char __user * buffer,
               unsigned long count, void *data)
  {
 -      int value;
 +      int rv, value;
  
 -      count = parse_arg(buffer, count, &value);
 -      if (count > 0)
 +      rv = parse_arg(buffer, count, &value);
 +      if (rv > 0)
                set_lcd_state(value);
 -      return count;
 +      return rv;
  }
  
 -static int read_brightness(void)
 +static int read_brightness(struct backlight_device *bd)
  {
        int value;
  
  /*
   * 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) {
                                    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 :
                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
  proc_write_brn(struct file *file, const char __user * buffer,
               unsigned long count, void *data)
  {
 -      int value;
 +      int rv, value;
  
 -      count = parse_arg(buffer, count, &value);
 -      if (count > 0) {
 +      rv = parse_arg(buffer, count, &value);
 +      if (rv > 0) {
                value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
                /* 0 <= value <= 15 */
                set_brightness(value);
 -      } else if (count < 0) {
 -              printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
        }
 -
 -      return count;
 +      return rv;
  }
  
  static void set_display(int value)
@@@ -899,12 -880,15 +899,12 @@@ static in
  proc_write_disp(struct file *file, const char __user * buffer,
                unsigned long count, void *data)
  {
 -      int value;
 +      int rv, value;
  
 -      count = parse_arg(buffer, count, &value);
 -      if (count > 0)
 +      rv = parse_arg(buffer, count, &value);
 +      if (rv > 0)
                set_display(value);
 -      else if (count < 0)
 -              printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
 -
 -      return count;
 +      return rv;
  }
  
  typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
@@@ -1113,8 -1097,6 +1113,8 @@@ static int asus_model_match(char *model
                return A4G;
        else if (strncmp(model, "W1N", 3) == 0)
                return W1N;
 +      else if (strncmp(model, "W3V", 3) == 0)
 +              return W3V;
        else if (strncmp(model, "W5A", 3) == 0)
                return W5A;
        else
@@@ -1146,7 -1128,7 +1146,7 @@@ static int asus_hotk_get_info(void
        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)) {
         * 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;
                hotk->methods->mt_wled = NULL;
        /* L5D's WLED is not controlled by ACPI */
        else if (strncmp(string, "M2N", 3) == 0 ||
 +               strncmp(string, "W3V", 3) == 0 ||
                 strncmp(string, "S1N", 3) == 0)
                hotk->methods->mt_wled = "WLED";
 -      /* M2N and S1N have a usable WLED */
 +      /* M2N, S1N and W3V have a usable WLED */
        else if (asus_info) {
                if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
                        hotk->methods->mled_status = NULL;
@@@ -1264,8 -1245,7 +1264,7 @@@ static int asus_hotk_add(struct acpi_de
        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 = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
        if (!hotk)
                return -ENOMEM;
        memset(hotk, 0, sizeof(struct asus_hotk));
@@@ -1345,26 -1325,6 +1344,26 @@@ static int asus_hotk_remove(struct acpi
        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;
                return result;
        }
  
 -      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);
 +      asus_backlight_device = backlight_device_register("asus", 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;
 +      return 0;
  }
  
  module_init(asus_acpi_init);
diff --combined drivers/acpi/battery.c
index 026e40755cdd7b0780c4832aade6a9601fb9db83,adb0d2725731cf8ca4148bf4e56c3e4e070df0cb..f47c78a106561e23f3d179a3055fec3372c27734
@@@ -64,7 -64,6 +64,7 @@@ extern void *acpi_unlock_battery_dir(st
  
  static int acpi_battery_add(struct acpi_device *device);
  static int acpi_battery_remove(struct acpi_device *device, int type);
 +static int acpi_battery_resume(struct acpi_device *device, int status);
  
  static struct acpi_driver acpi_battery_driver = {
        .name = ACPI_BATTERY_DRIVER_NAME,
@@@ -72,7 -71,6 +72,7 @@@
        .ids = ACPI_BATTERY_HID,
        .ops = {
                .add = acpi_battery_add,
 +              .resume = acpi_battery_resume,
                .remove = acpi_battery_remove,
                },
  };
@@@ -149,7 -147,7 +149,7 @@@ acpi_battery_get_info(struct acpi_batte
                return -ENODEV;
        }
  
-       package = (union acpi_object *)buffer.pointer;
+       package = buffer.pointer;
  
        /* Extract Package Data */
  
        kfree(buffer.pointer);
  
        if (!result)
-               (*bif) = (struct acpi_battery_info *)data.pointer;
+               (*bif) = data.pointer;
  
        return result;
  }
@@@ -209,7 -207,7 +209,7 @@@ acpi_battery_get_status(struct acpi_bat
                return -ENODEV;
        }
  
-       package = (union acpi_object *)buffer.pointer;
+       package = buffer.pointer;
  
        /* Extract Package Data */
  
        kfree(buffer.pointer);
  
        if (!result)
-               (*bst) = (struct acpi_battery_status *)data.pointer;
+               (*bst) = data.pointer;
  
        return result;
  }
@@@ -334,7 -332,7 +334,7 @@@ static struct proc_dir_entry *acpi_batt
  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 +418,7 @@@ static int acpi_battery_info_open_fs(st
  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 +494,7 @@@ static int acpi_battery_state_open_fs(s
  
  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 +531,8 @@@ acpi_battery_write_alarm(struct file *f
  {
        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 +658,7 @@@ static int acpi_battery_remove_fs(struc
  
  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;
  
  
@@@ -742,7 -740,7 +742,7 @@@ static int acpi_battery_remove(struct a
        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,
        return 0;
  }
  
 +/* this is needed to learn about changes made in suspended state */
 +static int acpi_battery_resume(struct acpi_device *device, int state)
 +{
 +      struct acpi_battery *battery;
 +
 +      if (!device)
 +              return -EINVAL;
 +
 +      battery = device->driver_data;
 +      return acpi_battery_check(battery);
 +}
 +
  static int __init acpi_battery_init(void)
  {
        int result;
diff --combined drivers/acpi/dock.c
index 54ce12ab43d786680c275a3629de0227b1a13df1,3c3dee844dfc50f97db13048a6ae9563fbe9d292..90990a4b65264aa0522bf54017b433df357df4d2
@@@ -27,8 -27,6 +27,8 @@@
  #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>
  
@@@ -40,15 -38,13 +40,15 @@@ MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAM
  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;
  };
@@@ -118,9 -114,9 +118,9 @@@ static voi
  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);
  }
  
  /**
@@@ -134,9 -130,9 +134,9 @@@ static voi
  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);
  }
  
  /**
@@@ -299,7 -295,7 +299,7 @@@ static void hotplug_dock_devices(struc
  {
        struct dock_dependent_device *dd;
  
 -      spin_lock(&ds->hp_lock);
 +      mutex_lock(&ds->hp_lock);
  
        /*
         * First call driver specific hotplug functions
                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);
  }
  
  /**
@@@ -446,9 -440,6 +446,9 @@@ static int dock_in_progress(struct dock
   */
  int register_dock_notifier(struct notifier_block *nb)
  {
 +      if (!dock_station)
 +              return -ENODEV;
 +
        return atomic_notifier_chain_register(&dock_notifier_list, nb);
  }
  
@@@ -460,9 -451,6 +460,9 @@@ EXPORT_SYMBOL_GPL(register_dock_notifie
   */
  void unregister_dock_notifier(struct notifier_block *nb)
  {
 +      if (!dock_station)
 +              return;
 +
        atomic_notifier_chain_unregister(&dock_notifier_list, nb);
  }
  
@@@ -522,37 -510,6 +522,37 @@@ void unregister_hotplug_dock_device(acp
  
  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
   *
   * 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:
         * 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);
@@@ -616,7 -587,7 +616,7 @@@ find_dock_devices(acpi_handle handle, u
  {
        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);
        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
@@@ -681,33 -625,9 +681,33 @@@ static int dock_add(acpi_handle handle
        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,
        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);
  
        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;
  }
  
@@@ -770,11 -685,6 +770,11 @@@ static int dock_remove(void
        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;
  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)) {
@@@ -815,7 -725,7 +815,7 @@@ static int __init dock_init(void
                            ACPI_UINT32_MAX, find_dock, &num, NULL);
  
        if (!num)
 -              return -ENODEV;
 +              printk(KERN_INFO "No dock devices found.\n");
  
        return 0;
  }
diff --combined drivers/acpi/glue.c
index 4ac2f18e0da21a386f92f0681d372dc3b20d4ba3,ba5686fa47501c05e105db65cb2e0d68bbf49a3c..8a0324b43e53869adcf9f98a29c513a38b1c2d15
@@@ -96,7 -96,7 +96,7 @@@ struct acpi_find_pci_root 
  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,12 -189,8 +189,12 @@@ find_pci_rootbridge(acpi_handle handle
        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;
@@@ -221,7 -217,7 +221,7 @@@ do_acpi_find_child(acpi_handle handle, 
        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)) {
@@@ -271,9 -267,9 +271,9 @@@ static int acpi_bind_one(struct device 
  {
        acpi_status status;
  
 -      if (dev->firmware_data) {
 +      if (dev->archdata.acpi_handle) {
                printk(KERN_WARNING PREFIX
 -                     "Drivers changed 'firmware_data' for %s\n", dev->bus_id);
 +                     "Drivers changed 'acpi_handle' for %s\n", dev->bus_id);
                return -EINVAL;
        }
        get_device(dev);
                put_device(dev);
                return -EINVAL;
        }
 -      dev->firmware_data = handle;
 +      dev->archdata.acpi_handle = handle;
  
        return 0;
  }
  
  static int acpi_unbind_one(struct device *dev)
  {
 -      if (!dev->firmware_data)
 +      if (!dev->archdata.acpi_handle)
                return 0;
 -      if (dev == acpi_get_physical_device(dev->firmware_data)) {
 +      if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
                /* acpi_get_physical_device increase refcnt by one */
                put_device(dev);
 -              acpi_detach_data(dev->firmware_data, acpi_glue_data_handler);
 -              dev->firmware_data = NULL;
 +              acpi_detach_data(dev->archdata.acpi_handle,
 +                               acpi_glue_data_handler);
 +              dev->archdata.acpi_handle = NULL;
                /* acpi_bind_one increase refcnt by one */
                put_device(dev);
        } else {
                printk(KERN_ERR PREFIX
 -                     "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id);
 +                     "Oops, 'acpi_handle' corrupt for %s\n", dev->bus_id);
        }
        return 0;
  }
@@@ -333,8 -328,7 +333,8 @@@ static int acpi_platform_notify(struct 
        if (!ret) {
                struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
  
 -              acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer);
 +              acpi_get_name(dev->archdata.acpi_handle,
 +                            ACPI_FULL_PATHNAME, &buffer);
                DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer);
                kfree(buffer.pointer);
        } else
diff --combined drivers/acpi/ibm_acpi.c
index ab180073534638ec01b52d27441ac18597eb5005,6fbb42048890287cc1c00484fcad7b6adfae57c3..1e7abef404b0a44ef96d033f81c6ef4bb42f6a72
@@@ -3,7 -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
   *  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
  #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>
  
  #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");
@@@ -128,6 -116,28 +128,6 @@@ static acpi_handle root_handle = NULL
        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 */
@@@ -157,10 -167,8 +157,10 @@@ IBM_HANDLE(dock, root, "\\_SB.GDCK",     /
           "\\_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 */
  
@@@ -175,7 -183,6 +175,7 @@@ IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0
  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 */
@@@ -196,7 -203,7 +196,7 @@@ IBM_HANDLE(led, ec, "SLED",        /* 570 *
  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 */
@@@ -209,152 -216,6 +209,152 @@@ IBM_HANDLE(sfan, ec, "SFAN",   /* 570 *
  #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];
  
  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)))
@@@ -722,7 -581,8 +722,7 @@@ static int wan_status(void
  {
        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;
@@@ -770,15 -630,12 +770,15 @@@ static int wan_write(char *buf
        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)
  {
  
        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;
  }
@@@ -809,15 -666,15 +809,15 @@@ static int video_status(void
        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;
@@@ -836,10 -693,9 +836,10 @@@ static int video_autosw(void
  {
        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;
@@@ -859,12 -715,12 +859,12 @@@ static int video_read(char *p
        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");
@@@ -879,7 -735,7 +879,7 @@@ static int video_switch(void
  
        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);
  
  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");
@@@ -901,10 -757,10 +901,10 @@@ static int video_switch2(int status
  {
        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;
@@@ -940,10 -796,10 +940,10 @@@ static int video_write(char *buf
                        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) {
@@@ -1042,7 -898,6 +1042,7 @@@ static int light_write(char *buf
        return 0;
  }
  
 +#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
  static int _sta(acpi_handle handle)
  {
        int status;
  
        return status;
  }
 +#endif
  #ifdef CONFIG_ACPI_IBM_DOCK
  #define dock_docked() (_sta(dock_handle) & 1)
  
@@@ -1118,7 -972,6 +1118,7 @@@ static void dock_notify(struct ibm_stru
  }
  #endif
  
 +#ifdef CONFIG_ACPI_IBM_BAY
  static int bay_status_supported;
  static int bay_status2_supported;
  static int bay_eject_supported;
@@@ -1194,7 -1047,6 +1194,7 @@@ static void bay_notify(struct ibm_struc
  {
        acpi_bus_generate_event(ibm->device, event, 0);
  }
 +#endif
  
  static int cmos_read(char *p)
  {
@@@ -1242,28 -1094,26 +1242,28 @@@ static int cmos_write(char *buf
        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;
  }
@@@ -1280,7 -1130,7 +1280,7 @@@ static int led_read(char *p
        }
        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++) {
@@@ -1329,13 -1179,13 +1329,13 @@@ static int led_write(char *buf
                } 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);
@@@ -1422,142 -1272,50 +1422,142 @@@ static int acpi_ec_write(int i, u8 v
        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_read(char *p)
 +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
  {
 -      int len = 0;
 +      int i, t;
 +      s8 tmp;
 +      char tmpi[] = "TMPi";
  
 -      if (!thermal_tmp_supported)
 -              len += sprintf(p + len, "temperatures:\tnot supported\n");
 -      else {
 -              int i, t;
 -              char tmpi[] = "TMPi";
 -              s8 tmp[8];
 +      if (!s)
 +              return -EINVAL;
  
 -              if (thermal_updt_supported)
 -                      if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
 +      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;
 -                      if (thermal_updt_supported)
 -                              tmp[i] = (t - 2732 + 5) / 10;
 -                      else
 -                              tmp[i] = t;
 +                      s->temp[i] = (t - 2732) * 100;
                }
 +              return 8;
  
 -              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]);
 +      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;
 +
 +      n = thermal_get_sensors(&t);
 +      if (unlikely(n < 0))
 +              return n;
 +
 +      len += sprintf(p + len, "temperatures:\t");
 +
 +      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;
  }
@@@ -1623,23 -1381,12 +1623,23 @@@ static int ecdump_write(char *buf
  
  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);
  #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) {
                } 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,
 +                                                       &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)
@@@ -1818,482 -1522,86 +1818,482 @@@ static int volume_write(char *buf
        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_read(char *p)
 +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)
  {
 -      int len = 0;
 -      int s;
 -      u8 lo, hi, status;
 +      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 */
 -              if (!acpi_evalf(gfan_handle, &s, NULL, "d"))
 -                      return -EIO;
 +              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;
 +              }
 +      }
  
 -              len += sprintf(p + len, "level:\t\t%d\n", s);
 +      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 (!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 (unlikely(!acpi_ec_read(fan_status_offset, &s)))
 +                      return -EIO;
  
 -              if (!acpi_ec_read(fan_rpm_offset, &lo) ||
 -                  !acpi_ec_read(fan_rpm_offset + 1, &hi))
 -                      len += sprintf(p + len, "speed:\t\tunreadable\n");
 -              else
 -                      len += sprintf(p + len, "speed:\t\t%d\n",
 -                                     (hi << 8) + lo);
 +              if (likely(status))
 +                      *status = s;
 +
 +              break;
 +
 +      default:
 +              return -ENXIO;
        }
  
 -      if (sfan_handle)
 -              /* 570, 770x-JL */
 -              len += sprintf(p + len, "commands:\tlevel <level>"
 -                             " (<level> is 0-7)\n");
 -      if (!gfan_handle)
 +      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 */
 -              len += sprintf(p + len, "commands:\tenable, disable\n");
 -      if (fans_handle)
 -              /* X31, X40 */
 +              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 rc;
 +      u8 status;
 +      unsigned int speed = 0;
 +
 +      switch (fan_status_access_mode) {
 +      case IBMACPI_FAN_RD_ACPI_GFAN:
 +              /* 570, 600e/x, 770e, 770x */
 +              if ((rc = fan_get_status(&status)) < 0)
 +                      return rc;
 +
 +              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 ((rc = fan_get_status(&status)) < 0)
 +                      return rc;
 +
 +              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, "level:\t\t%d\n", status);
 +              break;
 +
 +      case IBMACPI_FAN_NONE:
 +      default:
 +              len += sprintf(p + len, "status:\t\tnot supported\n");
 +      }
 +
 +      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 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[] = {
        {
         .name = "driver",
         .type = ACPI_SYSTEM_NOTIFY,
         },
  #endif
 +#ifdef CONFIG_ACPI_IBM_BAY
        {
         .name = "bay",
         .init = bay_init,
         .handle = &bay_handle,
         .type = ACPI_SYSTEM_NOTIFY,
         },
 +#endif
        {
         .name = "cmos",
         .read = cmos_read,
         .name = "brightness",
         .read = brightness_read,
         .write = brightness_write,
 -       .experimental = 1,
 +       .init = brightness_init,
 +       .exit = brightness_exit,
         },
        {
         .name = "volume",
         .read = volume_read,
         .write = volume_write,
 -       .experimental = 1,
         },
        {
         .name = "fan",
         .read = fan_read,
         .write = fan_write,
 +       .init = fan_init,
 +       .exit = fan_exit,
         .experimental = 1,
         },
  };
  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)
  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;
  
  
  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;
@@@ -2523,7 -1827,7 +2523,7 @@@ static int __init register_driver(struc
        }
  
        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;
  
@@@ -2652,9 -1956,7 +2652,9 @@@ IBM_PARAM(light)
  #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);
@@@ -2671,33 -1973,6 +2671,33 @@@ static void acpi_ibm_exit(void
                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)
                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);
        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 --combined drivers/acpi/osl.c
index 02b30ae6a68edf4b8e433e6c0f3f19674d2e6159,2ed2d701f6e10e8f099fbd007da6144396d86d40..b7ca020a0565a772de31449b073a13b53cc48369
@@@ -50,7 -50,6 +50,7 @@@ ACPI_MODULE_NAME("osl"
  struct acpi_os_dpc {
        acpi_osd_exec_callback function;
        void *context;
 +      struct work_struct work;
  };
  
  #ifdef CONFIG_ACPI_CUSTOM_DSDT
@@@ -565,9 -564,12 +565,10 @@@ void acpi_os_derive_pci_id(acpi_handle 
        acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
  }
  
 -static void acpi_os_execute_deferred(void *context)
 +static void acpi_os_execute_deferred(struct work_struct *work)
  {
 -      struct acpi_os_dpc *dpc = NULL;
 +      struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
 -
 -      dpc = context;
        if (!dpc) {
                printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
                return;
@@@ -600,6 -602,7 +601,6 @@@ acpi_status acpi_os_execute(acpi_execut
  {
        acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
 -      struct work_struct *task;
  
        ACPI_FUNCTION_TRACE("os_queue_for_execution");
  
  
        /*
         * Allocate/initialize DPC structure.  Note that this memory will be
 -       * freed by the callee.  The kernel handles the tq_struct list  in a
 +       * freed by the callee.  The kernel handles the work_struct list  in a
         * way that allows us to also free its memory inside the callee.
         * Because we may want to schedule several tasks with different
         * parameters we can't use the approach some kernel code uses of
 -       * having a static tq_struct.
 -       * We can save time and code by allocating the DPC and tq_structs
 -       * from the same memory.
 +       * having a static work_struct.
         */
  
 -      dpc =
 -          kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
 -                  GFP_ATOMIC);
 +      dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
        if (!dpc)
                return_ACPI_STATUS(AE_NO_MEMORY);
  
        dpc->function = function;
        dpc->context = context;
  
 -      task = (void *)(dpc + 1);
 -      INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
 -
 -      if (!queue_work(kacpid_wq, task)) {
 +      INIT_WORK(&dpc->work, acpi_os_execute_deferred);
 +      if (!queue_work(kacpid_wq, &dpc->work)) {
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                  "Call to queue_work() failed.\n"));
                kfree(dpc);
@@@ -1051,7 -1060,7 +1052,7 @@@ acpi_os_create_cache(char *name, u16 si
  
  acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
  {
-       (void)kmem_cache_shrink(cache);
+       kmem_cache_shrink(cache);
        return (AE_OK);
  }
  
diff --combined drivers/acpi/pci_link.c
index d53bd9878ca2ccddcee6cde058d8781c74b698ba,6718198bfae76ccc17f3c3b4f3cd628d6b286659..812d733fe8167eeaf539f7a12094bf66c69dd2e1
@@@ -103,7 -103,7 +103,7 @@@ DEFINE_MUTEX(acpi_link_lock)
  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,7 -307,7 +307,7 @@@ static int acpi_pci_link_set(struct acp
        if (!link || !irq)
                return -EINVAL;
  
 -      resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC);
 +      resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
        if (!resource)
                return -ENOMEM;
  
@@@ -613,7 -613,7 +613,7 @@@ acpi_pci_link_allocate_irq(acpi_handle 
                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 -668,7 +668,7 @@@ int acpi_pci_link_free_irq(acpi_handle 
                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;
@@@ -808,7 -808,7 +808,7 @@@ static int acpi_pci_link_remove(struct 
        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 --combined drivers/acpi/power.c
index fe67a8af520ecdb715e020511b028c3b6d7f865c,e9dab54bd541ad499e453c8d2b9fc7a45045809b..23a8a9295578e9d408f0c238b56ff2f338b94f54
@@@ -108,7 -108,7 +108,7 @@@ acpi_power_get_context(acpi_handle hand
                return result;
        }
  
-       *resource = (struct acpi_power_resource *)acpi_driver_data(device);
+       *resource = acpi_driver_data(device);
        if (!resource)
                return -ENODEV;
  
@@@ -216,8 -216,10 +216,8 @@@ static int acpi_power_off_device(acpi_h
  {
        int result = 0;
        acpi_status status = AE_OK;
 -      struct acpi_device *device = NULL;
        struct acpi_power_resource *resource = NULL;
  
 -
        result = acpi_power_get_context(handle, &resource);
        if (result)
                return result;
        if (resource->references) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Resource [%s] is still in use, dereferencing\n",
 -                                device->pnp.bus_id));
 +                                resource->device->pnp.bus_id));
                return 0;
        }
  
        if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
 -                                device->pnp.bus_id));
 +                                resource->device->pnp.bus_id));
                return 0;
        }
  
                return -ENOEXEC;
  
        /* Update the power resource's _device_ power state */
 -      device = resource->device;
 -      device->power.state = ACPI_STATE_D3;
 +      resource->device->power.state = ACPI_STATE_D3;
  
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
                          resource->name));
@@@ -442,7 -445,7 +442,7 @@@ static int acpi_power_seq_show(struct s
        struct acpi_power_resource *resource = NULL;
  
  
-       resource = (struct acpi_power_resource *)seq->private;
+       resource = seq->private;
  
        if (!resource)
                goto end;
@@@ -590,7 -593,7 +590,7 @@@ static int acpi_power_remove(struct acp
        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);
  
index 1908e0d202226a47b0f839439a84f599d91649b1,44c624bd40cbdafbba877ec5831a0ae501e63d03..3e70a08e4a8b8cdbf09fb5eae66c920ae221a39e
@@@ -277,7 -277,7 +277,7 @@@ static struct proc_dir_entry *acpi_proc
  
  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)
@@@ -519,7 -519,7 +519,7 @@@ static int acpi_processor_get_info(stru
  
  static void *processor_device_array[NR_CPUS];
  
 -static int acpi_processor_start(struct acpi_device *device)
 +static int __cpuinit acpi_processor_start(struct acpi_device *device)
  {
        int result = 0;
        acpi_status status = AE_OK;
         * 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;
  
  
  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;
  
  
@@@ -637,7 -637,7 +637,7 @@@ static int acpi_processor_remove(struc
        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);
index 65b3f056ad895a7d0f524f7412ff861ce9298649,4504684671f6f664c86981a7693f911df9a807b8..4f2982cc54782c156dfddda43d0a7a4fd582a86a
@@@ -219,23 -219,6 +219,23 @@@ static void acpi_safe_halt(void
  
  static atomic_t c3_cpu_count;
  
 +/* Common C-state entry for C2, C3, .. */
 +static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
 +{
 +      if (cstate->space_id == ACPI_CSTATE_FFH) {
 +              /* Call into architectural FFH based C-state */
 +              acpi_processor_ffh_cstate_enter(cstate);
 +      } else {
 +              int unused;
 +              /* IO port based C-state */
 +              inb(cstate->address);
 +              /* Dummy wait op - must do something useless after P_LVL2 read
 +                 because chipsets cannot guarantee that STPCLK# signal
 +                 gets asserted in time to freeze execution properly. */
 +              unused = inl(acpi_fadt.xpm_tmr_blk.address);
 +      }
 +}
 +
  static void acpi_processor_idle(void)
  {
        struct acpi_processor *pr = NULL;
                /* Get start time (ticks) */
                t1 = inl(acpi_fadt.xpm_tmr_blk.address);
                /* Invoke C2 */
 -              inb(cx->address);
 -              /* Dummy wait op - must do something useless after P_LVL2 read
 -                 because chipsets cannot guarantee that STPCLK# signal
 -                 gets asserted in time to freeze execution properly. */
 -              t2 = inl(acpi_fadt.xpm_tmr_blk.address);
 +              acpi_cstate_enter(cx);
                /* Get end time (ticks) */
                t2 = inl(acpi_fadt.xpm_tmr_blk.address);
  
                /* Get start time (ticks) */
                t1 = inl(acpi_fadt.xpm_tmr_blk.address);
                /* Invoke C3 */
 -              inb(cx->address);
 -              /* Dummy wait op (see above) */
 -              t2 = inl(acpi_fadt.xpm_tmr_blk.address);
 +              acpi_cstate_enter(cx);
                /* Get end time (ticks) */
                t2 = inl(acpi_fadt.xpm_tmr_blk.address);
                if (pr->flags.bm_check) {
@@@ -639,16 -628,20 +639,16 @@@ static int acpi_processor_get_power_inf
        return 0;
  }
  
 -static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
 +static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
  {
 -
 -      /* Zero initialize all the C-states info. */
 -      memset(pr->power.states, 0, sizeof(pr->power.states));
 -
 -      /* set the first C-State to C1 */
 -      pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
 -
 -      /* the C0 state only exists as a filler in our array,
 -       * and all processors need to support C1 */
 +      if (!pr->power.states[ACPI_STATE_C1].valid) {
 +              /* set the first C-State to C1 */
 +              /* all processors need to support C1 */
 +              pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
 +              pr->power.states[ACPI_STATE_C1].valid = 1;
 +      }
 +      /* the C0 state only exists as a filler in our array */
        pr->power.states[ACPI_STATE_C0].valid = 1;
 -      pr->power.states[ACPI_STATE_C1].valid = 1;
 -
        return 0;
  }
  
@@@ -665,7 -658,12 +665,7 @@@ static int acpi_processor_get_power_inf
        if (nocst)
                return -ENODEV;
  
 -      current_count = 1;
 -
 -      /* Zero initialize C2 onwards and prepare for fresh CST lookup */
 -      for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
 -              memset(&(pr->power.states[i]), 0, 
 -                              sizeof(struct acpi_processor_cx));
 +      current_count = 0;
  
        status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
        if (ACPI_FAILURE(status)) {
                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) {
  
                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;
                    (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
                        continue;
  
 -              cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
 -                  0 : reg->address;
 -
                /* 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;
  
                cx.type = obj->integer.value;
 -
 -              if ((cx.type != ACPI_STATE_C1) &&
 -                  (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
 -                      continue;
 -
 -              if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
 -                      continue;
 +              /*
 +               * Some buggy BIOSes won't list C1 in _CST -
 +               * Let acpi_processor_get_power_info_default() handle them later
 +               */
 +              if (i == 1 && cx.type != ACPI_STATE_C1)
 +                      current_count++;
 +
 +              cx.address = reg->address;
 +              cx.index = current_count + 1;
 +
 +              cx.space_id = ACPI_CSTATE_SYSTEMIO;
 +              if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
 +                      if (acpi_processor_ffh_cstate_probe
 +                                      (pr->id, &cx, reg) == 0) {
 +                              cx.space_id = ACPI_CSTATE_FFH;
 +                      } else if (cx.type != ACPI_STATE_C1) {
 +                              /*
 +                               * C1 is a special case where FIXED_HARDWARE
 +                               * can be handled in non-MWAIT way as well.
 +                               * In that case, save this _CST entry info.
 +                               * That is, we retain space_id of SYSTEM_IO for
 +                               * halt based C1.
 +                               * Otherwise, ignore this info and continue.
 +                               */
 +                              continue;
 +                      }
 +              }
  
-               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;
  
@@@ -957,17 -938,11 +957,17 @@@ static int acpi_processor_get_power_inf
        /* NOTE: the idle thread may not be running while calling
         * this function */
  
 -      /* Adding C1 state */
 -      acpi_processor_get_power_info_default_c1(pr);
 +      /* Zero initialize all the C-states info. */
 +      memset(pr->power.states, 0, sizeof(pr->power.states));
 +
        result = acpi_processor_get_power_info_cst(pr);
        if (result == -ENODEV)
 -              acpi_processor_get_power_info_fadt(pr);
 +              result = acpi_processor_get_power_info_fadt(pr);
 +
 +      if (result)
 +              return result;
 +
 +      acpi_processor_get_power_info_default(pr);
  
        pr->power.count = acpi_processor_power_verify(pr);
  
@@@ -1029,7 -1004,7 +1029,7 @@@ int acpi_processor_cst_has_changed(stru
  
  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;
  
  
@@@ -1108,7 -1083,6 +1108,7 @@@ static const struct file_operations acp
        .release = single_release,
  };
  
 +#ifdef CONFIG_SMP
  static void smp_callback(void *v)
  {
        /* we already woke the CPU up, nothing more to do */
@@@ -1130,9 -1104,8 +1130,9 @@@ static int acpi_processor_latency_notif
  static struct notifier_block acpi_processor_latency_notifier = {
        .notifier_call = acpi_processor_latency_notify,
  };
 +#endif
  
 -int acpi_processor_power_init(struct acpi_processor *pr,
 +int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
                              struct acpi_device *device)
  {
        acpi_status status = 0;
                               "ACPI: processor limited to max C-state %d\n",
                               max_cstate);
                first_run++;
 +#ifdef CONFIG_SMP
                register_latency_notifier(&acpi_processor_latency_notifier);
 +#endif
        }
  
        if (!pr)
@@@ -1222,9 -1193,7 +1222,9 @@@ int acpi_processor_power_exit(struct ac
                 * copies of pm_idle before proceeding.
                 */
                cpu_idle_wait();
 +#ifdef CONFIG_SMP
                unregister_latency_notifier(&acpi_processor_latency_notifier);
 +#endif
        }
  
        return 0;
index 6fd174a3714958946be4f4b54377c434694824e2,39fdbcc37d438c71625fa13206e5568f8e740df8..0e60382714bbbacb6d63219b4ba51ff84c3612a0
@@@ -83,8 -83,10 +83,8 @@@ static int acpi_processor_ppc_notifier(
                goto out;
  
        ppc = (unsigned int)pr->performance_platform_limit;
 -      if (!ppc)
 -              goto out;
  
 -      if (ppc > pr->performance->state_count)
 +      if (ppc >= pr->performance->state_count)
                goto out;
  
        cpufreq_verify_within_limits(policy, 0,
@@@ -236,7 -238,7 +236,7 @@@ static int acpi_processor_get_performan
                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 -412,7 +410,7 @@@ static struct file_operations acpi_proc
  
  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 -453,8 +451,8 @@@ acpi_processor_write_performance(struc
                                 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 -553,7 +551,7 @@@ static int acpi_processor_get_psd(struc
                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 --combined drivers/acpi/sbs.c
index 8908a975e5753ca028179298e008502b774eb3f2,c6a819adcc9ecd59358aca961f22e4a3408afa13..2fb7533314cdfb57cc11b0ba89192766ddf06f7f
@@@ -98,11 -98,11 +98,11 @@@ static int update_info_mode = UPDATE_IN
  static int update_time = UPDATE_TIME;
  static int update_time2 = UPDATE_TIME2;
  
 -module_param(capacity_mode, int, CAPACITY_UNIT);
 -module_param(update_mode, int, UPDATE_MODE);
 -module_param(update_info_mode, int, UPDATE_INFO_MODE);
 -module_param(update_time, int, UPDATE_TIME);
 -module_param(update_time2, int, UPDATE_TIME2);
 +module_param(capacity_mode, int, 0);
 +module_param(update_mode, int, 0);
 +module_param(update_info_mode, int, 0);
 +module_param(update_time, int, 0);
 +module_param(update_time2, int, 0);
  
  static int acpi_sbs_add(struct acpi_device *device);
  static int acpi_sbs_remove(struct acpi_device *device, int type);
@@@ -923,7 -923,7 +923,7 @@@ static struct proc_dir_entry *acpi_batt
  
  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 +1076,7 @@@ static int acpi_battery_state_open_fs(s
  
  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 +1125,8 @@@ static ssize_
  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;
  
        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 +1217,7 @@@ static struct proc_dir_entry *acpi_ac_d
  
  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 +1302,7 @@@ static int acpi_battery_add(struct acpi
                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 +1485,7 @@@ static int acpi_sbs_update_run(struct a
                }
  
                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,
                        }
                }
                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,
@@@ -1659,7 -1659,7 +1659,7 @@@ static int acpi_sbs_add(struct acpi_dev
        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"));
  
  int acpi_sbs_remove(struct acpi_device *device, int type)
  {
-       struct acpi_sbs *sbs = NULL;
 -      struct acpi_sbs *sbs = acpi_driver_data(device);
++      struct acpi_sbs *sbs;
        int id;
  
 -      if (!device || !sbs) {
 +      if (!device) {
 +              return -EINVAL;
 +      }
 +
 +      sbs = (struct acpi_sbs *)acpi_driver_data(device);
 +
 +      if (!sbs) {
                return -EINVAL;
        }