Add patches accepted for 2.6.26-rc6
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Fri, 13 Jun 2008 01:01:32 +0000 (12 22:01 -0300)
committerHenrique de Moraes Holschuh <hmh@hmh.eng.br>
Fri, 13 Jun 2008 01:49:22 +0000 (12 22:49 -0300)
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
releases/upstream/2.6.26-rc6/0001-thinkpad-acpi-SW_RADIO-to-SW_RFKILL_ALL-rename.patch [new file with mode: 0644]
releases/upstream/2.6.26-rc6/0002-thinkpad-acpi-fix-initialization-error-paths.patch [new file with mode: 0644]
releases/upstream/2.6.26-rc6/0003-thinkpad-acpi-fix-LED-handling-on-older-ThinkPads.patch [new file with mode: 0644]

diff --git a/releases/upstream/2.6.26-rc6/0001-thinkpad-acpi-SW_RADIO-to-SW_RFKILL_ALL-rename.patch b/releases/upstream/2.6.26-rc6/0001-thinkpad-acpi-SW_RADIO-to-SW_RFKILL_ALL-rename.patch
new file mode 100644 (file)
index 0000000..1081be7
--- /dev/null
@@ -0,0 +1,54 @@
+From 197a2cd907e3a5278a1cfd48c86402133f38a9ba Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Tue, 3 Jun 2008 23:36:09 -0300
+Subject: thinkpad-acpi: SW_RADIO to SW_RFKILL_ALL rename
+
+Rename SW_RADIO to SW_RFKILL_ALL in thinkpad-acpi code and docs, following
+5adad0133907790c50283bf03271d920d6897043 "Input: rename SW_RADIO to
+SW_RFKILL_ALL".
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+---
+ Documentation/laptops/thinkpad-acpi.txt |    2 +-
+ drivers/misc/thinkpad_acpi.c            |    4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
+index 01c6c3d..64b3f14 100644
+--- a/Documentation/laptops/thinkpad-acpi.txt
++++ b/Documentation/laptops/thinkpad-acpi.txt
+@@ -503,7 +503,7 @@ generate input device EV_KEY events.
+ In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW
+ events for switches:
+-SW_RADIO      T60 and later hardare rfkill rocker switch
++SW_RFKILL_ALL T60 and later hardare rfkill rocker switch
+ SW_TABLET_MODE        Tablet ThinkPads HKEY events 0x5009 and 0x500A
+ Non hot-key ACPI HKEY event map:
+diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
+index a0ce0b2..f81e048 100644
+--- a/drivers/misc/thinkpad_acpi.c
++++ b/drivers/misc/thinkpad_acpi.c
+@@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void)
+               mutex_lock(&tpacpi_inputdev_send_mutex);
+               input_report_switch(tpacpi_inputdev,
+-                                  SW_RADIO, !!wlsw);
++                                  SW_RFKILL_ALL, !!wlsw);
+               input_sync(tpacpi_inputdev);
+               mutex_unlock(&tpacpi_inputdev_send_mutex);
+@@ -2199,7 +2199,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
+               if (tp_features.hotkey_wlsw) {
+                       set_bit(EV_SW, tpacpi_inputdev->evbit);
+-                      set_bit(SW_RADIO, tpacpi_inputdev->swbit);
++                      set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit);
+               }
+               if (tp_features.hotkey_tablet) {
+                       set_bit(EV_SW, tpacpi_inputdev->evbit);
+-- 
+1.5.5.3
+
diff --git a/releases/upstream/2.6.26-rc6/0002-thinkpad-acpi-fix-initialization-error-paths.patch b/releases/upstream/2.6.26-rc6/0002-thinkpad-acpi-fix-initialization-error-paths.patch
new file mode 100644 (file)
index 0000000..491cd59
--- /dev/null
@@ -0,0 +1,546 @@
+From 9c0a76e16ee6648f4bd19563e9fe12a4f4fabba1 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Tue, 3 Jun 2008 23:36:10 -0300
+Subject: thinkpad-acpi: fix initialization error paths
+
+Rework some subdriver init and exit handlers, in order to fix some
+initialization error paths that were missing, or broken.
+
+Hitting those bugs should be extremely rare in the real world, but should
+that happen, thinkpad-acpi would fail to dealocate some resources and a
+reboot might well be needed to be able to load the driver again.
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Signed-off-by: Len Brown <len.brown@intel.com>
+---
+ drivers/misc/thinkpad_acpi.c |  435 ++++++++++++++++++++++--------------------
+ 1 files changed, 229 insertions(+), 206 deletions(-)
+
+diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
+index f81e048..58973da 100644
+--- a/drivers/misc/thinkpad_acpi.c
++++ b/drivers/misc/thinkpad_acpi.c
+@@ -1921,6 +1921,29 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
+       &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
+ };
++static void hotkey_exit(void)
++{
++#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
++      hotkey_poll_stop_sync();
++#endif
++
++      if (hotkey_dev_attributes)
++              delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
++
++      kfree(hotkey_keycode_map);
++
++      if (tp_features.hotkey) {
++              dbg_printk(TPACPI_DBG_EXIT,
++                         "restoring original hot key mask\n");
++              /* no short-circuit boolean operator below! */
++              if ((hotkey_mask_set(hotkey_orig_mask) |
++                   hotkey_status_set(hotkey_orig_status)) != 0)
++                      printk(TPACPI_ERR
++                             "failed to restore hot key mask "
++                             "to BIOS defaults\n");
++      }
++}
++
+ static int __init hotkey_init(struct ibm_init_struct *iibm)
+ {
+       /* Requirements for changing the default keymaps:
+@@ -2060,226 +2083,220 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
+       vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
+               str_supported(tp_features.hotkey));
+-      if (tp_features.hotkey) {
+-              hotkey_dev_attributes = create_attr_set(13, NULL);
+-              if (!hotkey_dev_attributes)
+-                      return -ENOMEM;
+-              res = add_many_to_attr_set(hotkey_dev_attributes,
+-                              hotkey_attributes,
+-                              ARRAY_SIZE(hotkey_attributes));
+-              if (res)
+-                      return res;
++      if (!tp_features.hotkey)
++              return 1;
+-              /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+-                 A30, R30, R31, T20-22, X20-21, X22-24.  Detected by checking
+-                 for HKEY interface version 0x100 */
+-              if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
+-                      if ((hkeyv >> 8) != 1) {
+-                              printk(TPACPI_ERR "unknown version of the "
+-                                     "HKEY interface: 0x%x\n", hkeyv);
+-                              printk(TPACPI_ERR "please report this to %s\n",
+-                                     TPACPI_MAIL);
+-                      } else {
+-                              /*
+-                               * MHKV 0x100 in A31, R40, R40e,
+-                               * T4x, X31, and later
+-                               */
+-                              tp_features.hotkey_mask = 1;
+-                      }
++      hotkey_dev_attributes = create_attr_set(13, NULL);
++      if (!hotkey_dev_attributes)
++              return -ENOMEM;
++      res = add_many_to_attr_set(hotkey_dev_attributes,
++                      hotkey_attributes,
++                      ARRAY_SIZE(hotkey_attributes));
++      if (res)
++              goto err_exit;
++
++      /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
++         A30, R30, R31, T20-22, X20-21, X22-24.  Detected by checking
++         for HKEY interface version 0x100 */
++      if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
++              if ((hkeyv >> 8) != 1) {
++                      printk(TPACPI_ERR "unknown version of the "
++                             "HKEY interface: 0x%x\n", hkeyv);
++                      printk(TPACPI_ERR "please report this to %s\n",
++                             TPACPI_MAIL);
++              } else {
++                      /*
++                       * MHKV 0x100 in A31, R40, R40e,
++                       * T4x, X31, and later
++                       */
++                      tp_features.hotkey_mask = 1;
+               }
++      }
+-              vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
+-                      str_supported(tp_features.hotkey_mask));
++      vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
++              str_supported(tp_features.hotkey_mask));
+-              if (tp_features.hotkey_mask) {
+-                      if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+-                                      "MHKA", "qd")) {
+-                              printk(TPACPI_ERR
+-                                     "missing MHKA handler, "
+-                                     "please report this to %s\n",
+-                                     TPACPI_MAIL);
+-                              /* FN+F12, FN+F4, FN+F3 */
+-                              hotkey_all_mask = 0x080cU;
+-                      }
++      if (tp_features.hotkey_mask) {
++              if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
++                              "MHKA", "qd")) {
++                      printk(TPACPI_ERR
++                             "missing MHKA handler, "
++                             "please report this to %s\n",
++                             TPACPI_MAIL);
++                      /* FN+F12, FN+F4, FN+F3 */
++                      hotkey_all_mask = 0x080cU;
+               }
++      }
+-              /* hotkey_source_mask *must* be zero for
+-               * the first hotkey_mask_get */
+-              res = hotkey_status_get(&hotkey_orig_status);
+-              if (!res && tp_features.hotkey_mask) {
+-                      res = hotkey_mask_get();
+-                      hotkey_orig_mask = hotkey_mask;
+-                      if (!res) {
+-                              res = add_many_to_attr_set(
+-                                      hotkey_dev_attributes,
+-                                      hotkey_mask_attributes,
+-                                      ARRAY_SIZE(hotkey_mask_attributes));
+-                      }
+-              }
++      /* hotkey_source_mask *must* be zero for
++       * the first hotkey_mask_get */
++      res = hotkey_status_get(&hotkey_orig_status);
++      if (res)
++              goto err_exit;
++
++      if (tp_features.hotkey_mask) {
++              res = hotkey_mask_get();
++              if (res)
++                      goto err_exit;
++
++              hotkey_orig_mask = hotkey_mask;
++              res = add_many_to_attr_set(
++                              hotkey_dev_attributes,
++                              hotkey_mask_attributes,
++                              ARRAY_SIZE(hotkey_mask_attributes));
++              if (res)
++                      goto err_exit;
++      }
+ #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+-              if (tp_features.hotkey_mask) {
+-                      hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
+-                                              & ~hotkey_all_mask;
+-              } else {
+-                      hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
+-              }
++      if (tp_features.hotkey_mask) {
++              hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
++                                      & ~hotkey_all_mask;
++      } else {
++              hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
++      }
+-              vdbg_printk(TPACPI_DBG_INIT,
+-                          "hotkey source mask 0x%08x, polling freq %d\n",
+-                          hotkey_source_mask, hotkey_poll_freq);
++      vdbg_printk(TPACPI_DBG_INIT,
++                  "hotkey source mask 0x%08x, polling freq %d\n",
++                  hotkey_source_mask, hotkey_poll_freq);
+ #endif
+-              /* Not all thinkpads have a hardware radio switch */
+-              if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+-                      tp_features.hotkey_wlsw = 1;
+-                      printk(TPACPI_INFO
+-                              "radio switch found; radios are %s\n",
+-                              enabled(status, 0));
+-                      res = add_to_attr_set(hotkey_dev_attributes,
+-                                      &dev_attr_hotkey_radio_sw.attr);
+-              }
++      /* Not all thinkpads have a hardware radio switch */
++      if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
++              tp_features.hotkey_wlsw = 1;
++              printk(TPACPI_INFO
++                      "radio switch found; radios are %s\n",
++                      enabled(status, 0));
++              res = add_to_attr_set(hotkey_dev_attributes,
++                              &dev_attr_hotkey_radio_sw.attr);
++      }
+-              /* For X41t, X60t, X61t Tablets... */
+-              if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
+-                      tp_features.hotkey_tablet = 1;
+-                      printk(TPACPI_INFO
+-                              "possible tablet mode switch found; "
+-                              "ThinkPad in %s mode\n",
+-                              (status & TP_HOTKEY_TABLET_MASK)?
+-                                      "tablet" : "laptop");
+-                      res = add_to_attr_set(hotkey_dev_attributes,
+-                                      &dev_attr_hotkey_tablet_mode.attr);
+-              }
++      /* For X41t, X60t, X61t Tablets... */
++      if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
++              tp_features.hotkey_tablet = 1;
++              printk(TPACPI_INFO
++                      "possible tablet mode switch found; "
++                      "ThinkPad in %s mode\n",
++                      (status & TP_HOTKEY_TABLET_MASK)?
++                              "tablet" : "laptop");
++              res = add_to_attr_set(hotkey_dev_attributes,
++                              &dev_attr_hotkey_tablet_mode.attr);
++      }
+-              if (!res)
+-                      res = register_attr_set_with_sysfs(
+-                                      hotkey_dev_attributes,
+-                                      &tpacpi_pdev->dev.kobj);
+-              if (res)
+-                      return res;
++      if (!res)
++              res = register_attr_set_with_sysfs(
++                              hotkey_dev_attributes,
++                              &tpacpi_pdev->dev.kobj);
++      if (res)
++              goto err_exit;
+-              /* Set up key map */
++      /* Set up key map */
+-              hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+-                                              GFP_KERNEL);
+-              if (!hotkey_keycode_map) {
+-                      printk(TPACPI_ERR
+-                              "failed to allocate memory for key map\n");
+-                      return -ENOMEM;
+-              }
++      hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
++                                      GFP_KERNEL);
++      if (!hotkey_keycode_map) {
++              printk(TPACPI_ERR
++                      "failed to allocate memory for key map\n");
++              res = -ENOMEM;
++              goto err_exit;
++      }
+-              if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+-                      dbg_printk(TPACPI_DBG_INIT,
+-                                 "using Lenovo default hot key map\n");
+-                      memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+-                              TPACPI_HOTKEY_MAP_SIZE);
++      if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
++              dbg_printk(TPACPI_DBG_INIT,
++                         "using Lenovo default hot key map\n");
++              memcpy(hotkey_keycode_map, &lenovo_keycode_map,
++                      TPACPI_HOTKEY_MAP_SIZE);
++      } else {
++              dbg_printk(TPACPI_DBG_INIT,
++                         "using IBM default hot key map\n");
++              memcpy(hotkey_keycode_map, &ibm_keycode_map,
++                      TPACPI_HOTKEY_MAP_SIZE);
++      }
++
++      set_bit(EV_KEY, tpacpi_inputdev->evbit);
++      set_bit(EV_MSC, tpacpi_inputdev->evbit);
++      set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
++      tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
++      tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
++      tpacpi_inputdev->keycode = hotkey_keycode_map;
++      for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
++              if (hotkey_keycode_map[i] != KEY_RESERVED) {
++                      set_bit(hotkey_keycode_map[i],
++                              tpacpi_inputdev->keybit);
+               } else {
+-                      dbg_printk(TPACPI_DBG_INIT,
+-                                 "using IBM default hot key map\n");
+-                      memcpy(hotkey_keycode_map, &ibm_keycode_map,
+-                              TPACPI_HOTKEY_MAP_SIZE);
+-              }
+-
+-              set_bit(EV_KEY, tpacpi_inputdev->evbit);
+-              set_bit(EV_MSC, tpacpi_inputdev->evbit);
+-              set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+-              tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+-              tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+-              tpacpi_inputdev->keycode = hotkey_keycode_map;
+-              for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+-                      if (hotkey_keycode_map[i] != KEY_RESERVED) {
+-                              set_bit(hotkey_keycode_map[i],
+-                                      tpacpi_inputdev->keybit);
+-                      } else {
+-                              if (i < sizeof(hotkey_reserved_mask)*8)
+-                                      hotkey_reserved_mask |= 1 << i;
+-                      }
+-              }
+-
+-              if (tp_features.hotkey_wlsw) {
+-                      set_bit(EV_SW, tpacpi_inputdev->evbit);
+-                      set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit);
+-              }
+-              if (tp_features.hotkey_tablet) {
+-                      set_bit(EV_SW, tpacpi_inputdev->evbit);
+-                      set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
++                      if (i < sizeof(hotkey_reserved_mask)*8)
++                              hotkey_reserved_mask |= 1 << i;
+               }
++      }
+-              /* Do not issue duplicate brightness change events to
+-               * userspace */
+-              if (!tp_features.bright_acpimode)
+-                      /* update bright_acpimode... */
+-                      tpacpi_check_std_acpi_brightness_support();
+-
+-              if (tp_features.bright_acpimode) {
+-                      printk(TPACPI_INFO
+-                             "This ThinkPad has standard ACPI backlight "
+-                             "brightness control, supported by the ACPI "
+-                             "video driver\n");
+-                      printk(TPACPI_NOTICE
+-                             "Disabling thinkpad-acpi brightness events "
+-                             "by default...\n");
+-
+-                      /* The hotkey_reserved_mask change below is not
+-                       * necessary while the keys are at KEY_RESERVED in the
+-                       * default map, but better safe than sorry, leave it
+-                       * here as a marker of what we have to do, especially
+-                       * when we finally become able to set this at runtime
+-                       * on response to X.org requests */
+-                      hotkey_reserved_mask |=
+-                              (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
+-                              | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
+-              }
++      if (tp_features.hotkey_wlsw) {
++              set_bit(EV_SW, tpacpi_inputdev->evbit);
++              set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit);
++      }
++      if (tp_features.hotkey_tablet) {
++              set_bit(EV_SW, tpacpi_inputdev->evbit);
++              set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
++      }
+-              dbg_printk(TPACPI_DBG_INIT,
+-                              "enabling hot key handling\n");
+-              res = hotkey_status_set(1);
+-              if (res)
+-                      return res;
+-              res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
+-                                      & ~hotkey_reserved_mask)
+-                                      | hotkey_orig_mask);
+-              if (res < 0 && res != -ENXIO)
+-                      return res;
++      /* Do not issue duplicate brightness change events to
++       * userspace */
++      if (!tp_features.bright_acpimode)
++              /* update bright_acpimode... */
++              tpacpi_check_std_acpi_brightness_support();
+-              dbg_printk(TPACPI_DBG_INIT,
+-                              "legacy hot key reporting over procfs %s\n",
+-                              (hotkey_report_mode < 2) ?
+-                                      "enabled" : "disabled");
++      if (tp_features.bright_acpimode) {
++              printk(TPACPI_INFO
++                     "This ThinkPad has standard ACPI backlight "
++                     "brightness control, supported by the ACPI "
++                     "video driver\n");
++              printk(TPACPI_NOTICE
++                     "Disabling thinkpad-acpi brightness events "
++                     "by default...\n");
++
++              /* The hotkey_reserved_mask change below is not
++               * necessary while the keys are at KEY_RESERVED in the
++               * default map, but better safe than sorry, leave it
++               * here as a marker of what we have to do, especially
++               * when we finally become able to set this at runtime
++               * on response to X.org requests */
++              hotkey_reserved_mask |=
++                      (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
++                      | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
++      }
++
++      dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n");
++      res = hotkey_status_set(1);
++      if (res) {
++              hotkey_exit();
++              return res;
++      }
++      res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
++                              & ~hotkey_reserved_mask)
++                              | hotkey_orig_mask);
++      if (res < 0 && res != -ENXIO) {
++              hotkey_exit();
++              return res;
++      }
+-              tpacpi_inputdev->open = &hotkey_inputdev_open;
+-              tpacpi_inputdev->close = &hotkey_inputdev_close;
++      dbg_printk(TPACPI_DBG_INIT,
++                      "legacy hot key reporting over procfs %s\n",
++                      (hotkey_report_mode < 2) ?
++                              "enabled" : "disabled");
+-              hotkey_poll_setup_safe(1);
+-              tpacpi_input_send_radiosw();
+-              tpacpi_input_send_tabletsw();
+-      }
++      tpacpi_inputdev->open = &hotkey_inputdev_open;
++      tpacpi_inputdev->close = &hotkey_inputdev_close;
+-      return (tp_features.hotkey)? 0 : 1;
+-}
++      hotkey_poll_setup_safe(1);
++      tpacpi_input_send_radiosw();
++      tpacpi_input_send_tabletsw();
+-static void hotkey_exit(void)
+-{
+-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+-      hotkey_poll_stop_sync();
+-#endif
++      return 0;
+-      if (tp_features.hotkey) {
+-              dbg_printk(TPACPI_DBG_EXIT,
+-                         "restoring original hot key mask\n");
+-              /* no short-circuit boolean operator below! */
+-              if ((hotkey_mask_set(hotkey_orig_mask) |
+-                   hotkey_status_set(hotkey_orig_status)) != 0)
+-                      printk(TPACPI_ERR
+-                             "failed to restore hot key mask "
+-                             "to BIOS defaults\n");
+-      }
++err_exit:
++      delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
++      hotkey_dev_attributes = NULL;
+-      if (hotkey_dev_attributes) {
+-              delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+-              hotkey_dev_attributes = NULL;
+-      }
++      return (res < 0)? res : 1;
+ }
+ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+@@ -3319,7 +3336,7 @@ static struct tpacpi_led_classdev tpacpi_led_thinklight = {
+ static int __init light_init(struct ibm_init_struct *iibm)
+ {
+-      int rc = 0;
++      int rc;
+       vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
+@@ -3337,20 +3354,23 @@ static int __init light_init(struct ibm_init_struct *iibm)
+               tp_features.light_status =
+                       acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+-      vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
+-              str_supported(tp_features.light));
++      vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n",
++              str_supported(tp_features.light),
++              str_supported(tp_features.light_status));
+-      if (tp_features.light) {
+-              rc = led_classdev_register(&tpacpi_pdev->dev,
+-                                         &tpacpi_led_thinklight.led_classdev);
+-      }
++      if (!tp_features.light)
++              return 1;
++
++      rc = led_classdev_register(&tpacpi_pdev->dev,
++                                 &tpacpi_led_thinklight.led_classdev);
+       if (rc < 0) {
+               tp_features.light = 0;
+               tp_features.light_status = 0;
+-      } else {
+-              rc = (tp_features.light)? 0 : 1;
++      } else  {
++              rc = 0;
+       }
++
+       return rc;
+ }
+@@ -3978,7 +3998,6 @@ static void led_exit(void)
+       }
+       kfree(tpacpi_leds);
+-      tpacpi_leds = NULL;
+ }
+ static int __init led_init(struct ibm_init_struct *iibm)
+@@ -4802,7 +4821,6 @@ static void brightness_exit(void)
+               vdbg_printk(TPACPI_DBG_EXIT,
+                           "calling backlight_device_unregister()\n");
+               backlight_device_unregister(ibm_backlight_device);
+-              ibm_backlight_device = NULL;
+       }
+ }
+@@ -5764,11 +5782,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
+           fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+               rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
+                                        &fan_attr_group);
+-              if (!(rc < 0))
+-                      rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
+-                                      &driver_attr_fan_watchdog);
+               if (rc < 0)
+                       return rc;
++
++              rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
++                                      &driver_attr_fan_watchdog);
++              if (rc < 0) {
++                      sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
++                                      &fan_attr_group);
++                      return rc;
++              }
+               return 0;
+       } else
+               return 1;
+-- 
+1.5.5.3
+
diff --git a/releases/upstream/2.6.26-rc6/0003-thinkpad-acpi-fix-LED-handling-on-older-ThinkPads.patch b/releases/upstream/2.6.26-rc6/0003-thinkpad-acpi-fix-LED-handling-on-older-ThinkPads.patch
new file mode 100644 (file)
index 0000000..e379328
--- /dev/null
@@ -0,0 +1,115 @@
+From 24e45bbe695719dca8c20e03d386eb6ea86526b5 Mon Sep 17 00:00:00 2001
+From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Date: Tue, 3 Jun 2008 23:36:11 -0300
+Subject: thinkpad-acpi: fix LED handling on older ThinkPads
+
+The less tested codepaths for LED handling, used on ThinkPads 570, 600e/x,
+770e, 770x, A21e, A2xm/p, T20-22, X20 and maybe a few others, would write
+data to kernel memory it had no business touching, for leds number 3 and
+above.  If one is lucky, that illegal write would cause an OOPS, but
+chances are it would silently corrupt a byte.
+
+The problem was introduced in commit af116101, "ACPI: thinkpad-acpi: add
+sysfs led class support to thinkpad leds (v3.2)".
+
+Fix the bug by refactoring the entire code to be far more obvious on what
+it wants to do.  Also do some defensive "constification".
+
+Issue reported by Karol Lewandowski <lmctlx@gmail.com> (he's an lucky guy
+and got an OOPS instead of silent corruption :-) ).
+
+Root cause of the OOPS identified by Adrian Bunk <bunk@kernel.org>.
+Thanks, Adrian!
+
+Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+Tested-by: Karol Lewandowski <lmctlx@gmail.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+---
+ drivers/misc/thinkpad_acpi.c |   55 +++++++++++++++++++++--------------------
+ 1 files changed, 28 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
+index 58973da..b596929 100644
+--- a/drivers/misc/thinkpad_acpi.c
++++ b/drivers/misc/thinkpad_acpi.c
+@@ -3853,7 +3853,7 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
+       "tpacpi::standby",
+ };
+-static int led_get_status(unsigned int led)
++static int led_get_status(const unsigned int led)
+ {
+       int status;
+       enum led_status_t led_s;
+@@ -3877,41 +3877,42 @@ static int led_get_status(unsigned int led)
+       /* not reached */
+ }
+-static int led_set_status(unsigned int led, enum led_status_t ledstatus)
++static int led_set_status(const unsigned int led,
++                        const enum led_status_t ledstatus)
+ {
+       /* off, on, blink. Index is led_status_t */
+-      static const int led_sled_arg1[] = { 0, 1, 3 };
+-      static const int led_exp_hlbl[] = { 0, 0, 1 };  /* led# * */
+-      static const int led_exp_hlcl[] = { 0, 1, 1 };  /* led# * */
+-      static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
++      static const unsigned int led_sled_arg1[] = { 0, 1, 3 };
++      static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 };
+       int rc = 0;
+       switch (led_supported) {
+       case TPACPI_LED_570:
+-                      /* 570 */
+-                      led = 1 << led;
+-                      if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+-                                      led, led_sled_arg1[ledstatus]))
+-                              rc = -EIO;
+-                      break;
++              /* 570 */
++              if (led > 7)
++                      return -EINVAL;
++              if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
++                              (1 << led), led_sled_arg1[ledstatus]))
++                      rc = -EIO;
++              break;
+       case TPACPI_LED_OLD:
+-                      /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+-                      led = 1 << led;
+-                      rc = ec_write(TPACPI_LED_EC_HLMS, led);
+-                      if (rc >= 0)
+-                              rc = ec_write(TPACPI_LED_EC_HLBL,
+-                                            led * led_exp_hlbl[ledstatus]);
+-                      if (rc >= 0)
+-                              rc = ec_write(TPACPI_LED_EC_HLCL,
+-                                            led * led_exp_hlcl[ledstatus]);
+-                      break;
++              /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
++              if (led > 7)
++                      return -EINVAL;
++              rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led));
++              if (rc >= 0)
++                      rc = ec_write(TPACPI_LED_EC_HLBL,
++                                    (ledstatus == TPACPI_LED_BLINK) << led);
++              if (rc >= 0)
++                      rc = ec_write(TPACPI_LED_EC_HLCL,
++                                    (ledstatus != TPACPI_LED_OFF) << led);
++              break;
+       case TPACPI_LED_NEW:
+-                      /* all others */
+-                      if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+-                                      led, led_led_arg1[ledstatus]))
+-                              rc = -EIO;
+-                      break;
++              /* all others */
++              if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
++                              led, led_led_arg1[ledstatus]))
++                      rc = -EIO;
++              break;
+       default:
+               rc = -ENXIO;
+       }
+-- 
+1.5.5.3
+