]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Jan 2009 20:40:37 +0000 (12:40 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Jan 2009 20:40:37 +0000 (12:40 -0800)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (23 commits)
  ACPI PCI hotplug: harden against panic regression
  ACPI: rename main.c to sleep.c
  dell-laptop: move to drivers/platform/x86/ from drivers/misc/
  eeepc-laptop: enable Bluetooth ACPI details
  ACPI: fix ACPI_FADT_S4_RTC_WAKE comment
  kprobes: check CONFIG_FREEZER instead of CONFIG_PM
  PM: Fix freezer compilation if PM_SLEEP is unset
  thermal fixup for broken BIOS which has invalid trip points.
  ACPI: EC: Don't trust ECDT tables from ASUS
  ACPI: EC: Limit workaround for ASUS notebooks even more
  ACPI: thinkpad-acpi: bump up version to 0.22
  ACPI: thinkpad-acpi: handle HKEY event 6030
  ACPI: thinkpad-acpi: clean-up fan subdriver quirk
  ACPI: thinkpad-acpi: start the event hunt season
  ACPI: thinkpad-acpi: handle HKEY thermal and battery alarms
  ACPI: thinkpad-acpi: clean up hotkey_notify()
  ACPI: thinkpad-acpi: use killable instead of interruptible mutexes
  ACPI: thinkpad-acpi: add UWB radio support
  ACPI: thinkpad-acpi: preserve radio state across shutdown
  ACPI: thinkpad-acpi: resume with radios disabled
  ...

17 files changed:
Documentation/laptops/thinkpad-acpi.txt
arch/ia64/kernel/kprobes.c
arch/x86/kernel/kprobes.c
drivers/acpi/Makefile
drivers/acpi/ec.c
drivers/acpi/sleep.c [moved from drivers/acpi/main.c with 100% similarity]
drivers/acpi/thermal.c
drivers/misc/Makefile
drivers/pci/hotplug/acpiphp_glue.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/dell-laptop.c [moved from drivers/misc/dell-laptop.c with 99% similarity]
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/thinkpad_acpi.c
include/acpi/actbl.h
kernel/kprobes.c
kernel/power/Makefile

index 898b4987bb802926545700e445aef5489f480f78..41bc99fa18844c64505591f6e561b6293049448c 100644 (file)
@@ -1,7 +1,7 @@
                     ThinkPad ACPI Extras Driver
 
-                            Version 0.21
-                           May 29th, 2008
+                            Version 0.22
+                        November 23rd,  2008
 
                Borislav Deianov <borislav@users.sf.net>
              Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -16,7 +16,8 @@ supported by the generic Linux ACPI drivers.
 This driver used to be named ibm-acpi until kernel 2.6.21 and release
 0.13-20070314.  It used to be in the drivers/acpi tree, but it was
 moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
-2.6.22, and release 0.14.
+2.6.22, and release 0.14.  It was moved to drivers/platform/x86 for
+kernel 2.6.29 and release 0.22.
 
 The driver is named "thinkpad-acpi".  In some places, like module
 names, "thinkpad_acpi" is used because of userspace issues.
@@ -1412,6 +1413,24 @@ Sysfs notes:
        rfkill controller switch "tpacpi_wwan_sw": refer to
        Documentation/rfkill.txt for details.
 
+EXPERIMENTAL: UWB
+-----------------
+
+This feature is marked EXPERIMENTAL because it has not been extensively
+tested and validated in various ThinkPad models yet.  The feature may not
+work as expected. USE WITH CAUTION! To use this feature, you need to supply
+the experimental=1 parameter when loading the module.
+
+sysfs rfkill class: switch "tpacpi_uwb_sw"
+
+This feature exports an rfkill controller for the UWB device, if one is
+present and enabled in the BIOS.
+
+Sysfs notes:
+
+       rfkill controller switch "tpacpi_uwb_sw": refer to
+       Documentation/rfkill.txt for details.
+
 Multiple Commands, Module Parameters
 ------------------------------------
 
index f90be51b1123fe12199da46e019c5c20f0b2b371..9adac441ac9bb1f4400a6620951d7e07bbdcdfbe 100644 (file)
@@ -870,7 +870,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
                return 1;
 
 ss_probe:
-#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER)
        if (p->ainsn.inst_flag == INST_FLAG_BOOSTABLE && !p->post_handler) {
                /* Boost up -- we can execute copied instructions directly */
                ia64_psr(regs)->ri = p->ainsn.slot;
index 884d985b8b8223a0df4c566b29ed0d47204e8453..e948b28a5a9ab47a1f0d91d78ec7039f315830bd 100644 (file)
@@ -446,7 +446,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
 static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs,
                                       struct kprobe_ctlblk *kcb)
 {
-#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER)
        if (p->ainsn.boostable == 1 && !p->post_handler) {
                /* Boost up -- we can execute copied instructions directly */
                reset_current_kprobe();
index d80f4cc2e0da31c9e3679320f473122c447b4aa2..65d90c720b5a63995179235af6683577e112cc44 100644 (file)
@@ -19,7 +19,7 @@ obj-y                         += osl.o utils.o reboot.o\
 
 # sleep related files
 obj-y                          += wakeup.o
-obj-y                          += main.o
+obj-y                          += sleep.o
 obj-$(CONFIG_ACPI_SLEEP)       += proc.o
 
 
index 8dfcbb8aff7398a5b75061b52eab15298726dd0e..a2b82c90a6838eaff23a83cd30e741e0c3422e2a 100644 (file)
@@ -120,31 +120,6 @@ static struct acpi_ec {
        spinlock_t curr_lock;
 } *boot_ec, *first_ec;
 
-/* 
- * Some Asus system have exchanged ECDT data/command IO addresses.
- */
-static int print_ecdt_error(const struct dmi_system_id *id)
-{
-       printk(KERN_NOTICE PREFIX "%s detected - "
-               "ECDT has exchanged control/data I/O address\n",
-               id->ident);
-       return 0;
-}
-
-static struct dmi_system_id __cpuinitdata ec_dmi_table[] = {
-       {
-       print_ecdt_error, "Asus L4R", {
-       DMI_MATCH(DMI_BIOS_VERSION, "1008.006"),
-       DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),
-       DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL},
-       {
-       print_ecdt_error, "Asus M6R", {
-       DMI_MATCH(DMI_BIOS_VERSION, "0207"),
-       DMI_MATCH(DMI_PRODUCT_NAME, "M6R"),
-       DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL},
-       {},
-};
-
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
@@ -983,8 +958,8 @@ static const struct acpi_device_id ec_device_ids[] = {
 int __init acpi_ec_ecdt_probe(void)
 {
        acpi_status status;
+       struct acpi_ec *saved_ec = NULL;
        struct acpi_table_ecdt *ecdt_ptr;
-       acpi_handle dummy;
 
        boot_ec = make_acpi_ec();
        if (!boot_ec)
@@ -998,21 +973,16 @@ int __init acpi_ec_ecdt_probe(void)
                pr_info(PREFIX "EC description table is found, configuring boot EC\n");
                boot_ec->command_addr = ecdt_ptr->control.address;
                boot_ec->data_addr = ecdt_ptr->data.address;
-               if (dmi_check_system(ec_dmi_table)) {
-                       /*
-                        * If the board falls into ec_dmi_table, it means
-                        * that ECDT table gives the incorrect command/status
-                        * & data I/O address. Just fix it.
-                        */
-                       boot_ec->data_addr = ecdt_ptr->control.address;
-                       boot_ec->command_addr = ecdt_ptr->data.address;
-               }
                boot_ec->gpe = ecdt_ptr->gpe;
                boot_ec->handle = ACPI_ROOT_OBJECT;
                acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
-               /* Add some basic check against completely broken table */
-               if (boot_ec->data_addr != boot_ec->command_addr)
+               /* Don't trust ECDT, which comes from ASUSTek */
+               if (!dmi_name_in_vendors("ASUS"))
                        goto install;
+               saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+               if (!saved_ec)
+                       return -ENOMEM;
+               memcpy(&saved_ec, boot_ec, sizeof(saved_ec));
        /* fall through */
        }
        /* This workaround is needed only on some broken machines,
@@ -1023,12 +993,29 @@ int __init acpi_ec_ecdt_probe(void)
        /* Check that acpi_get_devices actually find something */
        if (ACPI_FAILURE(status) || !boot_ec->handle)
                goto error;
-       /* We really need to limit this workaround, the only ASUS,
-        * which needs it, has fake EC._INI method, so use it as flag.
-        * Keep boot_ec struct as it will be needed soon.
-        */
-       if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy)))
-               return -ENODEV;
+       if (saved_ec) {
+               /* try to find good ECDT from ASUSTek */
+               if (saved_ec->command_addr != boot_ec->command_addr ||
+                   saved_ec->data_addr != boot_ec->data_addr ||
+                   saved_ec->gpe != boot_ec->gpe ||
+                   saved_ec->handle != boot_ec->handle)
+                       pr_info(PREFIX "ASUSTek keeps feeding us with broken "
+                       "ECDT tables, which are very hard to workaround. "
+                       "Trying to use DSDT EC info instead. Please send "
+                       "output of acpidump to linux-acpi@vger.kernel.org\n");
+               kfree(saved_ec);
+               saved_ec = NULL;
+       } else {
+               /* We really need to limit this workaround, the only ASUS,
+               * which needs it, has fake EC._INI method, so use it as flag.
+               * Keep boot_ec struct as it will be needed soon.
+               */
+               acpi_handle dummy;
+               if (!dmi_name_in_vendors("ASUS") ||
+                   ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
+                                                       &dummy)))
+                       return -ENODEV;
+       }
 install:
        if (!ec_install_handlers(boot_ec)) {
                first_ec = boot_ec;
similarity index 100%
rename from drivers/acpi/main.c
rename to drivers/acpi/sleep.c
index 073ff09218a9be62ac2acc25601080b4c87976e6..99e6f1f8ea457677e1b989c711e37e1b339e60c3 100644 (file)
@@ -416,7 +416,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
        }
 
        /* Passive (optional) */
-       if (flag & ACPI_TRIPS_PASSIVE) {
+       if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
+               (flag == ACPI_TRIPS_INIT)) {
                valid = tz->trips.passive.flags.valid;
                if (psv == -1) {
                        status = AE_SUPPORT;
@@ -462,8 +463,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                memset(&devices, 0, sizeof(struct acpi_handle_list));
                status = acpi_evaluate_reference(tz->device->handle, "_PSL",
                                                        NULL, &devices);
-               if (ACPI_FAILURE(status))
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_WARNING PREFIX
+                               "Invalid passive threshold\n");
                        tz->trips.passive.flags.valid = 0;
+               }
                else
                        tz->trips.passive.flags.valid = 1;
 
@@ -487,7 +491,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                if (act == -1)
                        break; /* disable all active trip points */
 
-               if (flag & ACPI_TRIPS_ACTIVE) {
+               if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
+                       tz->trips.active[i].flags.valid)) {
                        status = acpi_evaluate_integer(tz->device->handle,
                                                        name, NULL, &tmp);
                        if (ACPI_FAILURE(status)) {
@@ -521,8 +526,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                        memset(&devices, 0, sizeof(struct acpi_handle_list));
                        status = acpi_evaluate_reference(tz->device->handle,
                                                name, NULL, &devices);
-                       if (ACPI_FAILURE(status))
+                       if (ACPI_FAILURE(status)) {
+                               printk(KERN_WARNING PREFIX
+                                       "Invalid active%d threshold\n", i);
                                tz->trips.active[i].flags.valid = 0;
+                       }
                        else
                                tz->trips.active[i].flags.valid = 1;
 
index 9cf8ae6e4b39f53107cf46887ee4b70633ccd5db..d5749a7bc7775d1bddd58016e74c17f276087806 100644 (file)
@@ -10,7 +10,6 @@ obj-$(CONFIG_ATMEL_TCLIB)     += atmel_tclib.o
 obj-$(CONFIG_ICS932S401)       += ics932s401.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
 obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
-obj-$(CONFIG_DELL_LAPTOP)      += dell-laptop.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
 obj-$(CONFIG_PHANTOM)          += phantom.o
 obj-$(CONFIG_SGI_IOC4)         += ioc4.o
index f09b1010d477f64ce804d1c0a73d7e952192d34d..803d9ddd6e75f0fb2334c905c89c6f626657e656 100644 (file)
@@ -266,6 +266,8 @@ static int detect_ejectable_slots(struct pci_bus *pbus)
        int found = acpi_pci_detect_ejectable(pbus);
        if (!found) {
                acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus);
+               if (!bridge_handle)
+                       return 0;
                acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
                                    is_pci_dock_device, (void *)&found, NULL);
        }
index e65448e99b48b9f0f233d77b8f0bd1dd36532161..1a266d4ab5f18ec52d8451185adcf66a3cd892d6 100644 (file)
@@ -54,6 +54,18 @@ config ASUS_LAPTOP
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
 
+config DELL_LAPTOP
+       tristate "Dell Laptop Extras (EXPERIMENTAL)"
+       depends on X86
+       depends on DCDBAS
+       depends on EXPERIMENTAL
+       depends on BACKLIGHT_CLASS_DEVICE
+       depends on RFKILL
+       default n
+       ---help---
+       This driver adds support for rfkill and backlight control to Dell
+       laptops.
+
 config FUJITSU_LAPTOP
        tristate "Fujitsu Laptop Extras"
        depends on ACPI
@@ -192,6 +204,17 @@ config THINKPAD_ACPI
 
          If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
 
+config THINKPAD_ACPI_DEBUGFACILITIES
+       bool "Maintainer debug facilities"
+       depends on THINKPAD_ACPI
+       default n
+       ---help---
+         Enables extra stuff in the thinkpad-acpi which is completely useless
+         for normal use.  Read the driver source to find out what it does.
+
+         Say N here, unless you were told by a kernel maintainer to do
+         otherwise.
+
 config THINKPAD_ACPI_DEBUG
        bool "Verbose debug mode"
        depends on THINKPAD_ACPI
index 1e9de2ae0de56db8babfe46cc8724b0d22aa4505..e29065120be9f8b0250d7625936338c86377930f 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_ASUS_LAPTOP)       += asus-laptop.o
 obj-$(CONFIG_EEEPC_LAPTOP)     += eeepc-laptop.o
 obj-$(CONFIG_MSI_LAPTOP)       += msi-laptop.o
 obj-$(CONFIG_COMPAL_LAPTOP)    += compal-laptop.o
+obj-$(CONFIG_DELL_LAPTOP)      += dell-laptop.o
 obj-$(CONFIG_ACER_WMI)         += acer-wmi.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
similarity index 99%
rename from drivers/misc/dell-laptop.c
rename to drivers/platform/x86/dell-laptop.c
index 4d33a2068b7a76ec5738d0162a2816a92e4d1c88..16e11c2ee19a2a4dfb54f8c95e6639aa26bbfe70 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/rfkill.h>
 #include <linux/power_supply.h>
 #include <linux/acpi.h>
-#include "../firmware/dcdbas.h"
+#include "../../firmware/dcdbas.h"
 
 #define BRIGHTNESS_TOKEN 0x7d
 
index 02fe2b8b8939cd1f752e815c3c0e4e9310cedf77..9d93cb971e59a16df9ff014844d6a250983d6cd9 100644 (file)
@@ -90,7 +90,7 @@ enum {
 };
 
 static const char *cm_getv[] = {
-       "WLDG", NULL, NULL, NULL,
+       "WLDG", "BTHG", NULL, NULL,
        "CAMG", NULL, NULL, NULL,
        NULL, "PBLG", NULL, NULL,
        "CFVG", NULL, NULL, NULL,
@@ -99,7 +99,7 @@ static const char *cm_getv[] = {
 };
 
 static const char *cm_setv[] = {
-       "WLDS", NULL, NULL, NULL,
+       "WLDS", "BTHS", NULL, NULL,
        "CAMS", NULL, NULL, NULL,
        "SDSP", "PBLS", "HDPS", NULL,
        "CFVS", NULL, NULL, NULL,
index 3478453eba7a3e8e2997cc25fcdd807f377efb86..bcbc05107ba840b82a9d0414d3c0846c867b083f 100644 (file)
@@ -21,7 +21,7 @@
  *  02110-1301, USA.
  */
 
-#define TPACPI_VERSION "0.21"
+#define TPACPI_VERSION "0.22"
 #define TPACPI_SYSFS_VERSION 0x020200
 
 /*
@@ -122,6 +122,27 @@ enum {
 #define TPACPI_HKEY_INPUT_PRODUCT      0x5054 /* "TP" */
 #define TPACPI_HKEY_INPUT_VERSION      0x4101
 
+/* ACPI \WGSV commands */
+enum {
+       TP_ACPI_WGSV_GET_STATE          = 0x01, /* Get state information */
+       TP_ACPI_WGSV_PWR_ON_ON_RESUME   = 0x02, /* Resume WWAN powered on */
+       TP_ACPI_WGSV_PWR_OFF_ON_RESUME  = 0x03, /* Resume WWAN powered off */
+       TP_ACPI_WGSV_SAVE_STATE         = 0x04, /* Save state for S4/S5 */
+};
+
+/* TP_ACPI_WGSV_GET_STATE bits */
+enum {
+       TP_ACPI_WGSV_STATE_WWANEXIST    = 0x0001, /* WWAN hw available */
+       TP_ACPI_WGSV_STATE_WWANPWR      = 0x0002, /* WWAN radio enabled */
+       TP_ACPI_WGSV_STATE_WWANPWRRES   = 0x0004, /* WWAN state at resume */
+       TP_ACPI_WGSV_STATE_WWANBIOSOFF  = 0x0008, /* WWAN disabled in BIOS */
+       TP_ACPI_WGSV_STATE_BLTHEXIST    = 0x0001, /* BLTH hw available */
+       TP_ACPI_WGSV_STATE_BLTHPWR      = 0x0002, /* BLTH radio enabled */
+       TP_ACPI_WGSV_STATE_BLTHPWRRES   = 0x0004, /* BLTH state at resume */
+       TP_ACPI_WGSV_STATE_BLTHBIOSOFF  = 0x0008, /* BLTH disabled in BIOS */
+       TP_ACPI_WGSV_STATE_UWBEXIST     = 0x0010, /* UWB hw available */
+       TP_ACPI_WGSV_STATE_UWBPWR       = 0x0020, /* UWB radio enabled */
+};
 
 /****************************************************************************
  * Main driver
@@ -148,14 +169,17 @@ enum {
 enum {
        TPACPI_RFK_BLUETOOTH_SW_ID = 0,
        TPACPI_RFK_WWAN_SW_ID,
+       TPACPI_RFK_UWB_SW_ID,
 };
 
 /* Debugging */
 #define TPACPI_LOG TPACPI_FILE ": "
-#define TPACPI_ERR        KERN_ERR    TPACPI_LOG
-#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
-#define TPACPI_INFO   KERN_INFO   TPACPI_LOG
-#define TPACPI_DEBUG  KERN_DEBUG  TPACPI_LOG
+#define TPACPI_ALERT   KERN_ALERT  TPACPI_LOG
+#define TPACPI_CRIT    KERN_CRIT   TPACPI_LOG
+#define TPACPI_ERR     KERN_ERR    TPACPI_LOG
+#define TPACPI_NOTICE  KERN_NOTICE TPACPI_LOG
+#define TPACPI_INFO    KERN_INFO   TPACPI_LOG
+#define TPACPI_DEBUG   KERN_DEBUG  TPACPI_LOG
 
 #define TPACPI_DBG_ALL         0xffff
 #define TPACPI_DBG_INIT                0x0001
@@ -201,6 +225,7 @@ struct ibm_struct {
        void (*exit) (void);
        void (*resume) (void);
        void (*suspend) (pm_message_t state);
+       void (*shutdown) (void);
 
        struct list_head all_drivers;
 
@@ -239,6 +264,7 @@ static struct {
        u32 bright_16levels:1;
        u32 bright_acpimode:1;
        u32 wan:1;
+       u32 uwb:1;
        u32 fan_ctrl_status_undef:1;
        u32 input_device_registered:1;
        u32 platform_drv_registered:1;
@@ -288,6 +314,18 @@ struct tpacpi_led_classdev {
        unsigned int led;
 };
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+static int dbg_wlswemul;
+static int tpacpi_wlsw_emulstate;
+static int dbg_bluetoothemul;
+static int tpacpi_bluetooth_emulstate;
+static int dbg_wwanemul;
+static int tpacpi_wwan_emulstate;
+static int dbg_uwbemul;
+static int tpacpi_uwb_emulstate;
+#endif
+
+
 /****************************************************************************
  ****************************************************************************
  *
@@ -728,6 +766,18 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
        return 0;
 }
 
+static void tpacpi_shutdown_handler(struct platform_device *pdev)
+{
+       struct ibm_struct *ibm, *itmp;
+
+       list_for_each_entry_safe(ibm, itmp,
+                                &tpacpi_all_drivers,
+                                all_drivers) {
+               if (ibm->shutdown)
+                       (ibm->shutdown)();
+       }
+}
+
 static struct platform_driver tpacpi_pdriver = {
        .driver = {
                .name = TPACPI_DRVR_NAME,
@@ -735,6 +785,7 @@ static struct platform_driver tpacpi_pdriver = {
        },
        .suspend = tpacpi_suspend_handler,
        .resume = tpacpi_resume_handler,
+       .shutdown = tpacpi_shutdown_handler,
 };
 
 static struct platform_driver tpacpi_hwmon_pdriver = {
@@ -922,11 +973,27 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
                        struct rfkill **rfk,
                        const enum rfkill_type rfktype,
                        const char *name,
+                       const bool set_default,
                        int (*toggle_radio)(void *, enum rfkill_state),
                        int (*get_state)(void *, enum rfkill_state *))
 {
        int res;
-       enum rfkill_state initial_state;
+       enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED;
+
+       res = get_state(NULL, &initial_state);
+       if (res < 0) {
+               printk(TPACPI_ERR
+                       "failed to read initial state for %s, error %d; "
+                       "will turn radio off\n", name, res);
+       } else if (set_default) {
+               /* try to set the initial state as the default for the rfkill
+                * type, since we ask the firmware to preserve it across S5 in
+                * NVRAM */
+               rfkill_set_default(rfktype,
+                               (initial_state == RFKILL_STATE_UNBLOCKED) ?
+                                       RFKILL_STATE_UNBLOCKED :
+                                       RFKILL_STATE_SOFT_BLOCKED);
+       }
 
        *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype);
        if (!*rfk) {
@@ -938,9 +1005,7 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
        (*rfk)->name = name;
        (*rfk)->get_state = get_state;
        (*rfk)->toggle_radio = toggle_radio;
-
-       if (!get_state(NULL, &initial_state))
-               (*rfk)->state = initial_state;
+       (*rfk)->state = initial_state;
 
        res = rfkill_register(*rfk);
        if (res < 0) {
@@ -1006,6 +1071,119 @@ static DRIVER_ATTR(version, S_IRUGO,
 
 /* --------------------------------------------------------------------- */
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+
+static void tpacpi_send_radiosw_update(void);
+
+/* wlsw_emulstate ------------------------------------------------------ */
+static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv,
+                                               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wlsw_emulstate);
+}
+
+static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv,
+                                               const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       if (tpacpi_wlsw_emulstate != t) {
+               tpacpi_wlsw_emulstate = !!t;
+               tpacpi_send_radiosw_update();
+       } else
+               tpacpi_wlsw_emulstate = !!t;
+
+       return count;
+}
+
+static DRIVER_ATTR(wlsw_emulstate, S_IWUSR | S_IRUGO,
+               tpacpi_driver_wlsw_emulstate_show,
+               tpacpi_driver_wlsw_emulstate_store);
+
+/* bluetooth_emulstate ------------------------------------------------- */
+static ssize_t tpacpi_driver_bluetooth_emulstate_show(
+                                       struct device_driver *drv,
+                                       char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_bluetooth_emulstate);
+}
+
+static ssize_t tpacpi_driver_bluetooth_emulstate_store(
+                                       struct device_driver *drv,
+                                       const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       tpacpi_bluetooth_emulstate = !!t;
+
+       return count;
+}
+
+static DRIVER_ATTR(bluetooth_emulstate, S_IWUSR | S_IRUGO,
+               tpacpi_driver_bluetooth_emulstate_show,
+               tpacpi_driver_bluetooth_emulstate_store);
+
+/* wwan_emulstate ------------------------------------------------- */
+static ssize_t tpacpi_driver_wwan_emulstate_show(
+                                       struct device_driver *drv,
+                                       char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wwan_emulstate);
+}
+
+static ssize_t tpacpi_driver_wwan_emulstate_store(
+                                       struct device_driver *drv,
+                                       const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       tpacpi_wwan_emulstate = !!t;
+
+       return count;
+}
+
+static DRIVER_ATTR(wwan_emulstate, S_IWUSR | S_IRUGO,
+               tpacpi_driver_wwan_emulstate_show,
+               tpacpi_driver_wwan_emulstate_store);
+
+/* uwb_emulstate ------------------------------------------------- */
+static ssize_t tpacpi_driver_uwb_emulstate_show(
+                                       struct device_driver *drv,
+                                       char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_uwb_emulstate);
+}
+
+static ssize_t tpacpi_driver_uwb_emulstate_store(
+                                       struct device_driver *drv,
+                                       const char *buf, size_t count)
+{
+       unsigned long t;
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       tpacpi_uwb_emulstate = !!t;
+
+       return count;
+}
+
+static DRIVER_ATTR(uwb_emulstate, S_IWUSR | S_IRUGO,
+               tpacpi_driver_uwb_emulstate_show,
+               tpacpi_driver_uwb_emulstate_store);
+#endif
+
+/* --------------------------------------------------------------------- */
+
 static struct driver_attribute *tpacpi_driver_attributes[] = {
        &driver_attr_debug_level, &driver_attr_version,
        &driver_attr_interface_version,
@@ -1022,6 +1200,17 @@ static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
                i++;
        }
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (!res && dbg_wlswemul)
+               res = driver_create_file(drv, &driver_attr_wlsw_emulstate);
+       if (!res && dbg_bluetoothemul)
+               res = driver_create_file(drv, &driver_attr_bluetooth_emulstate);
+       if (!res && dbg_wwanemul)
+               res = driver_create_file(drv, &driver_attr_wwan_emulstate);
+       if (!res && dbg_uwbemul)
+               res = driver_create_file(drv, &driver_attr_uwb_emulstate);
+#endif
+
        return res;
 }
 
@@ -1031,6 +1220,13 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
 
        for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
                driver_remove_file(drv, tpacpi_driver_attributes[i]);
+
+#ifdef THINKPAD_ACPI_DEBUGFACILITIES
+       driver_remove_file(drv, &driver_attr_wlsw_emulstate);
+       driver_remove_file(drv, &driver_attr_bluetooth_emulstate);
+       driver_remove_file(drv, &driver_attr_wwan_emulstate);
+       driver_remove_file(drv, &driver_attr_uwb_emulstate);
+#endif
 }
 
 /****************************************************************************
@@ -1216,6 +1412,12 @@ static struct attribute_set *hotkey_dev_attributes;
 
 static int hotkey_get_wlsw(int *status)
 {
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_wlswemul) {
+               *status = !!tpacpi_wlsw_emulstate;
+               return 0;
+       }
+#endif
        if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
                return -EIO;
        return 0;
@@ -1678,7 +1880,7 @@ static ssize_t hotkey_mask_show(struct device *dev,
 {
        int res;
 
-       if (mutex_lock_interruptible(&hotkey_mutex))
+       if (mutex_lock_killable(&hotkey_mutex))
                return -ERESTARTSYS;
        res = hotkey_mask_get();
        mutex_unlock(&hotkey_mutex);
@@ -1697,7 +1899,7 @@ static ssize_t hotkey_mask_store(struct device *dev,
        if (parse_strtoul(buf, 0xffffffffUL, &t))
                return -EINVAL;
 
-       if (mutex_lock_interruptible(&hotkey_mutex))
+       if (mutex_lock_killable(&hotkey_mutex))
                return -ERESTARTSYS;
 
        res = hotkey_mask_set(t);
@@ -1783,7 +1985,7 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
                ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
                return -EINVAL;
 
-       if (mutex_lock_interruptible(&hotkey_mutex))
+       if (mutex_lock_killable(&hotkey_mutex))
                return -ERESTARTSYS;
 
        HOTKEY_CONFIG_CRITICAL_START
@@ -1818,7 +2020,7 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
        if (parse_strtoul(buf, 25, &t))
                return -EINVAL;
 
-       if (mutex_lock_interruptible(&hotkey_mutex))
+       if (mutex_lock_killable(&hotkey_mutex))
                return -ERESTARTSYS;
 
        hotkey_poll_freq = t;
@@ -1958,6 +2160,7 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
 
 static void bluetooth_update_rfk(void);
 static void wan_update_rfk(void);
+static void uwb_update_rfk(void);
 static void tpacpi_send_radiosw_update(void)
 {
        int wlsw;
@@ -1967,6 +2170,8 @@ static void tpacpi_send_radiosw_update(void)
                bluetooth_update_rfk();
        if (tp_features.wan)
                wan_update_rfk();
+       if (tp_features.uwb)
+               uwb_update_rfk();
 
        if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
                mutex_lock(&tpacpi_inputdev_send_mutex);
@@ -2222,6 +2427,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                    hotkey_source_mask, hotkey_poll_freq);
 #endif
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_wlswemul) {
+               tp_features.hotkey_wlsw = 1;
+               printk(TPACPI_INFO
+                       "radio switch emulation enabled\n");
+       } else
+#endif
        /* Not all thinkpads have a hardware radio switch */
        if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
                tp_features.hotkey_wlsw = 1;
@@ -2361,13 +2573,154 @@ err_exit:
        return (res < 0)? res : 1;
 }
 
+static bool hotkey_notify_hotkey(const u32 hkey,
+                                bool *send_acpi_ev,
+                                bool *ignore_acpi_ev)
+{
+       /* 0x1000-0x1FFF: key presses */
+       unsigned int scancode = hkey & 0xfff;
+       *send_acpi_ev = true;
+       *ignore_acpi_ev = false;
+
+       if (scancode > 0 && scancode < 0x21) {
+               scancode--;
+               if (!(hotkey_source_mask & (1 << scancode))) {
+                       tpacpi_input_send_key(scancode);
+                       *send_acpi_ev = false;
+               } else {
+                       *ignore_acpi_ev = true;
+               }
+               return true;
+       }
+       return false;
+}
+
+static bool hotkey_notify_wakeup(const u32 hkey,
+                                bool *send_acpi_ev,
+                                bool *ignore_acpi_ev)
+{
+       /* 0x2000-0x2FFF: Wakeup reason */
+       *send_acpi_ev = true;
+       *ignore_acpi_ev = false;
+
+       switch (hkey) {
+       case 0x2304: /* suspend, undock */
+       case 0x2404: /* hibernation, undock */
+               hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
+               *ignore_acpi_ev = true;
+               break;
+
+       case 0x2305: /* suspend, bay eject */
+       case 0x2405: /* hibernation, bay eject */
+               hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
+               *ignore_acpi_ev = true;
+               break;
+
+       case 0x2313: /* Battery on critical low level (S3) */
+       case 0x2413: /* Battery on critical low level (S4) */
+               printk(TPACPI_ALERT
+                       "EMERGENCY WAKEUP: battery almost empty\n");
+               /* how to auto-heal: */
+               /* 2313: woke up from S3, go to S4/S5 */
+               /* 2413: woke up from S4, go to S5 */
+               break;
+
+       default:
+               return false;
+       }
+
+       if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
+               printk(TPACPI_INFO
+                      "woke up due to a hot-unplug "
+                      "request...\n");
+               hotkey_wakeup_reason_notify_change();
+       }
+       return true;
+}
+
+static bool hotkey_notify_usrevent(const u32 hkey,
+                                bool *send_acpi_ev,
+                                bool *ignore_acpi_ev)
+{
+       /* 0x5000-0x5FFF: human interface helpers */
+       *send_acpi_ev = true;
+       *ignore_acpi_ev = false;
+
+       switch (hkey) {
+       case 0x5010: /* Lenovo new BIOS: brightness changed */
+       case 0x500b: /* X61t: tablet pen inserted into bay */
+       case 0x500c: /* X61t: tablet pen removed from bay */
+               return true;
+
+       case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
+       case 0x500a: /* X41t-X61t: swivel down (normal mode) */
+               tpacpi_input_send_tabletsw();
+               hotkey_tablet_mode_notify_change();
+               *send_acpi_ev = false;
+               return true;
+
+       case 0x5001:
+       case 0x5002:
+               /* LID switch events.  Do not propagate */
+               *ignore_acpi_ev = true;
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+static bool hotkey_notify_thermal(const u32 hkey,
+                                bool *send_acpi_ev,
+                                bool *ignore_acpi_ev)
+{
+       /* 0x6000-0x6FFF: thermal alarms */
+       *send_acpi_ev = true;
+       *ignore_acpi_ev = false;
+
+       switch (hkey) {
+       case 0x6011:
+               printk(TPACPI_CRIT
+                       "THERMAL ALARM: battery is too hot!\n");
+               /* recommended action: warn user through gui */
+               return true;
+       case 0x6012:
+               printk(TPACPI_ALERT
+                       "THERMAL EMERGENCY: battery is extremely hot!\n");
+               /* recommended action: immediate sleep/hibernate */
+               return true;
+       case 0x6021:
+               printk(TPACPI_CRIT
+                       "THERMAL ALARM: "
+                       "a sensor reports something is too hot!\n");
+               /* recommended action: warn user through gui, that */
+               /* some internal component is too hot */
+               return true;
+       case 0x6022:
+               printk(TPACPI_ALERT
+                       "THERMAL EMERGENCY: "
+                       "a sensor reports something is extremely hot!\n");
+               /* recommended action: immediate sleep/hibernate */
+               return true;
+       case 0x6030:
+               printk(TPACPI_INFO
+                       "EC reports that Thermal Table has changed\n");
+               /* recommended action: do nothing, we don't have
+                * Lenovo ATM information */
+               return true;
+       default:
+               printk(TPACPI_ALERT
+                        "THERMAL ALERT: unknown thermal alarm received\n");
+               return false;
+       }
+}
+
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 {
        u32 hkey;
-       unsigned int scancode;
-       int send_acpi_ev;
-       int ignore_acpi_ev;
-       int unk_ev;
+       bool send_acpi_ev;
+       bool ignore_acpi_ev;
+       bool known_ev;
 
        if (event != 0x80) {
                printk(TPACPI_ERR
@@ -2375,7 +2728,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                /* forward it to userspace, maybe it knows how to handle it */
                acpi_bus_generate_netlink_event(
                                        ibm->acpi->device->pnp.device_class,
-                                       ibm->acpi->device->dev.bus_id,
+                                       dev_name(&ibm->acpi->device->dev),
                                        event, 0);
                return;
        }
@@ -2391,107 +2744,72 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                        return;
                }
 
-               send_acpi_ev = 1;
-               ignore_acpi_ev = 0;
-               unk_ev = 0;
+               send_acpi_ev = true;
+               ignore_acpi_ev = false;
 
                switch (hkey >> 12) {
                case 1:
                        /* 0x1000-0x1FFF: key presses */
-                       scancode = hkey & 0xfff;
-                       if (scancode > 0 && scancode < 0x21) {
-                               scancode--;
-                               if (!(hotkey_source_mask & (1 << scancode))) {
-                                       tpacpi_input_send_key(scancode);
-                                       send_acpi_ev = 0;
-                               } else {
-                                       ignore_acpi_ev = 1;
-                               }
-                       } else {
-                               unk_ev = 1;
-                       }
+                       known_ev = hotkey_notify_hotkey(hkey, &send_acpi_ev,
+                                                &ignore_acpi_ev);
                        break;
                case 2:
-                       /* Wakeup reason */
-                       switch (hkey) {
-                       case 0x2304: /* suspend, undock */
-                       case 0x2404: /* hibernation, undock */
-                               hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
-                               ignore_acpi_ev = 1;
-                               break;
-                       case 0x2305: /* suspend, bay eject */
-                       case 0x2405: /* hibernation, bay eject */
-                               hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
-                               ignore_acpi_ev = 1;
-                               break;
-                       default:
-                               unk_ev = 1;
-                       }
-                       if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
-                               printk(TPACPI_INFO
-                                      "woke up due to a hot-unplug "
-                                      "request...\n");
-                               hotkey_wakeup_reason_notify_change();
-                       }
+                       /* 0x2000-0x2FFF: Wakeup reason */
+                       known_ev = hotkey_notify_wakeup(hkey, &send_acpi_ev,
+                                                &ignore_acpi_ev);
                        break;
                case 3:
-                       /* bay-related wakeups */
+                       /* 0x3000-0x3FFF: bay-related wakeups */
                        if (hkey == 0x3003) {
                                hotkey_autosleep_ack = 1;
                                printk(TPACPI_INFO
                                       "bay ejected\n");
                                hotkey_wakeup_hotunplug_complete_notify_change();
+                               known_ev = true;
                        } else {
-                               unk_ev = 1;
+                               known_ev = false;
                        }
                        break;
                case 4:
-                       /* dock-related wakeups */
+                       /* 0x4000-0x4FFF: dock-related wakeups */
                        if (hkey == 0x4003) {
                                hotkey_autosleep_ack = 1;
                                printk(TPACPI_INFO
                                       "undocked\n");
                                hotkey_wakeup_hotunplug_complete_notify_change();
+                               known_ev = true;
                        } else {
-                               unk_ev = 1;
+                               known_ev = false;
                        }
                        break;
                case 5:
                        /* 0x5000-0x5FFF: human interface helpers */
-                       switch (hkey) {
-                       case 0x5010: /* Lenovo new BIOS: brightness changed */
-                       case 0x500b: /* X61t: tablet pen inserted into bay */
-                       case 0x500c: /* X61t: tablet pen removed from bay */
-                               break;
-                       case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
-                       case 0x500a: /* X41t-X61t: swivel down (normal mode) */
-                               tpacpi_input_send_tabletsw();
-                               hotkey_tablet_mode_notify_change();
-                               send_acpi_ev = 0;
-                               break;
-                       case 0x5001:
-                       case 0x5002:
-                               /* LID switch events.  Do not propagate */
-                               ignore_acpi_ev = 1;
-                               break;
-                       default:
-                               unk_ev = 1;
-                       }
+                       known_ev = hotkey_notify_usrevent(hkey, &send_acpi_ev,
+                                                &ignore_acpi_ev);
+                       break;
+               case 6:
+                       /* 0x6000-0x6FFF: thermal alarms */
+                       known_ev = hotkey_notify_thermal(hkey, &send_acpi_ev,
+                                                &ignore_acpi_ev);
                        break;
                case 7:
                        /* 0x7000-0x7FFF: misc */
                        if (tp_features.hotkey_wlsw && hkey == 0x7000) {
                                tpacpi_send_radiosw_update();
                                send_acpi_ev = 0;
+                               known_ev = true;
                                break;
                        }
                        /* fallthrough to default */
                default:
-                       unk_ev = 1;
+                       known_ev = false;
                }
-               if (unk_ev) {
+               if (!known_ev) {
                        printk(TPACPI_NOTICE
                               "unhandled HKEY event 0x%04x\n", hkey);
+                       printk(TPACPI_NOTICE
+                              "please report the conditions when this "
+                              "event happened to %s\n", TPACPI_MAIL);
                }
 
                /* Legacy events */
@@ -2505,7 +2823,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                if (!ignore_acpi_ev && send_acpi_ev) {
                        acpi_bus_generate_netlink_event(
                                        ibm->acpi->device->pnp.device_class,
-                                       ibm->acpi->device->dev.bus_id,
+                                       dev_name(&ibm->acpi->device->dev),
                                        event, hkey);
                }
        }
@@ -2544,7 +2862,7 @@ static int hotkey_read(char *p)
                return len;
        }
 
-       if (mutex_lock_interruptible(&hotkey_mutex))
+       if (mutex_lock_killable(&hotkey_mutex))
                return -ERESTARTSYS;
        res = hotkey_status_get(&status);
        if (!res)
@@ -2575,7 +2893,7 @@ static int hotkey_write(char *buf)
        if (!tp_features.hotkey)
                return -ENODEV;
 
-       if (mutex_lock_interruptible(&hotkey_mutex))
+       if (mutex_lock_killable(&hotkey_mutex))
                return -ERESTARTSYS;
 
        status = -1;
@@ -2640,11 +2958,28 @@ enum {
        /* ACPI GBDC/SBDC bits */
        TP_ACPI_BLUETOOTH_HWPRESENT     = 0x01, /* Bluetooth hw available */
        TP_ACPI_BLUETOOTH_RADIOSSW      = 0x02, /* Bluetooth radio enabled */
-       TP_ACPI_BLUETOOTH_UNK           = 0x04, /* unknown function */
+       TP_ACPI_BLUETOOTH_RESUMECTRL    = 0x04, /* Bluetooth state at resume:
+                                                  off / last state */
+};
+
+enum {
+       /* ACPI \BLTH commands */
+       TP_ACPI_BLTH_GET_ULTRAPORT_ID   = 0x00, /* Get Ultraport BT ID */
+       TP_ACPI_BLTH_GET_PWR_ON_RESUME  = 0x01, /* Get power-on-resume state */
+       TP_ACPI_BLTH_PWR_ON_ON_RESUME   = 0x02, /* Resume powered on */
+       TP_ACPI_BLTH_PWR_OFF_ON_RESUME  = 0x03, /* Resume powered off */
+       TP_ACPI_BLTH_SAVE_STATE         = 0x05, /* Save state for S4/S5 */
 };
 
 static struct rfkill *tpacpi_bluetooth_rfkill;
 
+static void bluetooth_suspend(pm_message_t state)
+{
+       /* Try to make sure radio will resume powered off */
+       acpi_evalf(NULL, NULL, "\\BLTH", "vd",
+                  TP_ACPI_BLTH_PWR_OFF_ON_RESUME);
+}
+
 static int bluetooth_get_radiosw(void)
 {
        int status;
@@ -2656,6 +2991,12 @@ static int bluetooth_get_radiosw(void)
        if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
                return RFKILL_STATE_HARD_BLOCKED;
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_bluetoothemul)
+               return (tpacpi_bluetooth_emulstate) ?
+                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+#endif
+
        if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
                return -EIO;
 
@@ -2689,12 +3030,20 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk)
            && radio_on)
                return -EPERM;
 
-       if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
-               return -EIO;
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_bluetoothemul) {
+               tpacpi_bluetooth_emulstate = !!radio_on;
+               if (update_rfk)
+                       bluetooth_update_rfk();
+               return 0;
+       }
+#endif
+
+       /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
        if (radio_on)
-               status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+               status = TP_ACPI_BLUETOOTH_RADIOSSW;
        else
-               status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+               status = 0;
        if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
                return -EIO;
 
@@ -2765,8 +3114,19 @@ static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state)
        return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
 }
 
+static void bluetooth_shutdown(void)
+{
+       /* Order firmware to save current state to NVRAM */
+       if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd",
+                       TP_ACPI_BLTH_SAVE_STATE))
+               printk(TPACPI_NOTICE
+                       "failed to save bluetooth state to NVRAM\n");
+}
+
 static void bluetooth_exit(void)
 {
+       bluetooth_shutdown();
+
        if (tpacpi_bluetooth_rfkill)
                rfkill_unregister(tpacpi_bluetooth_rfkill);
 
@@ -2792,6 +3152,13 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
                str_supported(tp_features.bluetooth),
                status);
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_bluetoothemul) {
+               tp_features.bluetooth = 1;
+               printk(TPACPI_INFO
+                       "bluetooth switch emulation enabled\n");
+       } else
+#endif
        if (tp_features.bluetooth &&
            !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
                /* no bluetooth hardware present in system */
@@ -2812,6 +3179,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
                                &tpacpi_bluetooth_rfkill,
                                RFKILL_TYPE_BLUETOOTH,
                                "tpacpi_bluetooth_sw",
+                               true,
                                tpacpi_bluetooth_rfk_set,
                                tpacpi_bluetooth_rfk_get);
        if (res) {
@@ -2864,6 +3232,8 @@ static struct ibm_struct bluetooth_driver_data = {
        .read = bluetooth_read,
        .write = bluetooth_write,
        .exit = bluetooth_exit,
+       .suspend = bluetooth_suspend,
+       .shutdown = bluetooth_shutdown,
 };
 
 /*************************************************************************
@@ -2874,11 +3244,19 @@ enum {
        /* ACPI GWAN/SWAN bits */
        TP_ACPI_WANCARD_HWPRESENT       = 0x01, /* Wan hw available */
        TP_ACPI_WANCARD_RADIOSSW        = 0x02, /* Wan radio enabled */
-       TP_ACPI_WANCARD_UNK             = 0x04, /* unknown function */
+       TP_ACPI_WANCARD_RESUMECTRL      = 0x04, /* Wan state at resume:
+                                                  off / last state */
 };
 
 static struct rfkill *tpacpi_wan_rfkill;
 
+static void wan_suspend(pm_message_t state)
+{
+       /* Try to make sure radio will resume powered off */
+       acpi_evalf(NULL, NULL, "\\WGSV", "qvd",
+                  TP_ACPI_WGSV_PWR_OFF_ON_RESUME);
+}
+
 static int wan_get_radiosw(void)
 {
        int status;
@@ -2890,6 +3268,12 @@ static int wan_get_radiosw(void)
        if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
                return RFKILL_STATE_HARD_BLOCKED;
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_wwanemul)
+               return (tpacpi_wwan_emulstate) ?
+                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+#endif
+
        if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
                return -EIO;
 
@@ -2923,12 +3307,20 @@ static int wan_set_radiosw(int radio_on, int update_rfk)
            && radio_on)
                return -EPERM;
 
-       if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
-               return -EIO;
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_wwanemul) {
+               tpacpi_wwan_emulstate = !!radio_on;
+               if (update_rfk)
+                       wan_update_rfk();
+               return 0;
+       }
+#endif
+
+       /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */
        if (radio_on)
-               status |= TP_ACPI_WANCARD_RADIOSSW;
+               status = TP_ACPI_WANCARD_RADIOSSW;
        else
-               status &= ~TP_ACPI_WANCARD_RADIOSSW;
+               status = 0;
        if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
                return -EIO;
 
@@ -2999,8 +3391,19 @@ static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state)
        return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
 }
 
+static void wan_shutdown(void)
+{
+       /* Order firmware to save current state to NVRAM */
+       if (!acpi_evalf(NULL, NULL, "\\WGSV", "vd",
+                       TP_ACPI_WGSV_SAVE_STATE))
+               printk(TPACPI_NOTICE
+                       "failed to save WWAN state to NVRAM\n");
+}
+
 static void wan_exit(void)
 {
+       wan_shutdown();
+
        if (tpacpi_wan_rfkill)
                rfkill_unregister(tpacpi_wan_rfkill);
 
@@ -3024,6 +3427,13 @@ static int __init wan_init(struct ibm_init_struct *iibm)
                str_supported(tp_features.wan),
                status);
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_wwanemul) {
+               tp_features.wan = 1;
+               printk(TPACPI_INFO
+                       "wwan switch emulation enabled\n");
+       } else
+#endif
        if (tp_features.wan &&
            !(status & TP_ACPI_WANCARD_HWPRESENT)) {
                /* no wan hardware present in system */
@@ -3044,6 +3454,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
                                &tpacpi_wan_rfkill,
                                RFKILL_TYPE_WWAN,
                                "tpacpi_wwan_sw",
+                               true,
                                tpacpi_wan_rfk_set,
                                tpacpi_wan_rfk_get);
        if (res) {
@@ -3096,6 +3507,164 @@ static struct ibm_struct wan_driver_data = {
        .read = wan_read,
        .write = wan_write,
        .exit = wan_exit,
+       .suspend = wan_suspend,
+       .shutdown = wan_shutdown,
+};
+
+/*************************************************************************
+ * UWB subdriver
+ */
+
+enum {
+       /* ACPI GUWB/SUWB bits */
+       TP_ACPI_UWB_HWPRESENT   = 0x01, /* UWB hw available */
+       TP_ACPI_UWB_RADIOSSW    = 0x02, /* UWB radio enabled */
+};
+
+static struct rfkill *tpacpi_uwb_rfkill;
+
+static int uwb_get_radiosw(void)
+{
+       int status;
+
+       if (!tp_features.uwb)
+               return -ENODEV;
+
+       /* WLSW overrides UWB in firmware/hardware, reflect that */
+       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
+               return RFKILL_STATE_HARD_BLOCKED;
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_uwbemul)
+               return (tpacpi_uwb_emulstate) ?
+                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+#endif
+
+       if (!acpi_evalf(hkey_handle, &status, "GUWB", "d"))
+               return -EIO;
+
+       return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ?
+               RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+}
+
+static void uwb_update_rfk(void)
+{
+       int status;
+
+       if (!tpacpi_uwb_rfkill)
+               return;
+
+       status = uwb_get_radiosw();
+       if (status < 0)
+               return;
+       rfkill_force_state(tpacpi_uwb_rfkill, status);
+}
+
+static int uwb_set_radiosw(int radio_on, int update_rfk)
+{
+       int status;
+
+       if (!tp_features.uwb)
+               return -ENODEV;
+
+       /* WLSW overrides UWB in firmware/hardware, but there is no
+        * reason to risk weird behaviour. */
+       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
+           && radio_on)
+               return -EPERM;
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_uwbemul) {
+               tpacpi_uwb_emulstate = !!radio_on;
+               if (update_rfk)
+                       uwb_update_rfk();
+               return 0;
+       }
+#endif
+
+       status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0;
+       if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status))
+               return -EIO;
+
+       if (update_rfk)
+               uwb_update_rfk();
+
+       return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
+{
+       int uwbs = uwb_get_radiosw();
+
+       if (uwbs < 0)
+               return uwbs;
+
+       *state = uwbs;
+       return 0;
+}
+
+static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state)
+{
+       return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
+}
+
+static void uwb_exit(void)
+{
+       if (tpacpi_uwb_rfkill)
+               rfkill_unregister(tpacpi_uwb_rfkill);
+}
+
+static int __init uwb_init(struct ibm_init_struct *iibm)
+{
+       int res;
+       int status = 0;
+
+       vdbg_printk(TPACPI_DBG_INIT, "initializing uwb subdriver\n");
+
+       TPACPI_ACPIHANDLE_INIT(hkey);
+
+       tp_features.uwb = hkey_handle &&
+           acpi_evalf(hkey_handle, &status, "GUWB", "qd");
+
+       vdbg_printk(TPACPI_DBG_INIT, "uwb is %s, status 0x%02x\n",
+               str_supported(tp_features.uwb),
+               status);
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+       if (dbg_uwbemul) {
+               tp_features.uwb = 1;
+               printk(TPACPI_INFO
+                       "uwb switch emulation enabled\n");
+       } else
+#endif
+       if (tp_features.uwb &&
+           !(status & TP_ACPI_UWB_HWPRESENT)) {
+               /* no uwb hardware present in system */
+               tp_features.uwb = 0;
+               dbg_printk(TPACPI_DBG_INIT,
+                          "uwb hardware not installed\n");
+       }
+
+       if (!tp_features.uwb)
+               return 1;
+
+       res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID,
+                               &tpacpi_uwb_rfkill,
+                               RFKILL_TYPE_UWB,
+                               "tpacpi_uwb_sw",
+                               false,
+                               tpacpi_uwb_rfk_set,
+                               tpacpi_uwb_rfk_get);
+
+       return res;
+}
+
+static struct ibm_struct uwb_driver_data = {
+       .name = "uwb",
+       .exit = uwb_exit,
+       .flags.experimental = 1,
 };
 
 /*************************************************************************
@@ -3724,7 +4293,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
        }
        acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
        acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
-                                         ibm->acpi->device->dev.bus_id,
+                                         dev_name(&ibm->acpi->device->dev),
                                          event, data);
 }
 
@@ -3826,7 +4395,7 @@ static void bay_notify(struct ibm_struct *ibm, u32 event)
 {
        acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
        acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
-                                         ibm->acpi->device->dev.bus_id,
+                                         dev_name(&ibm->acpi->device->dev),
                                          event, 0);
 }
 
@@ -4850,7 +5419,7 @@ static int brightness_set(int value)
            value < 0)
                return -EINVAL;
 
-       res = mutex_lock_interruptible(&brightness_mutex);
+       res = mutex_lock_killable(&brightness_mutex);
        if (res < 0)
                return res;
 
@@ -5333,6 +5902,60 @@ TPACPI_HANDLE(sfan, ec, "SFAN",  /* 570 */
           "JFNS",              /* 770x-JL */
           );                   /* all others */
 
+/*
+ * Unitialized HFSP quirk: ACPI DSDT and EC fail to initialize the
+ * HFSP register at boot, so it contains 0x07 but the Thinkpad could
+ * be in auto mode (0x80).
+ *
+ * This is corrected by any write to HFSP either by the driver, or
+ * by the firmware.
+ *
+ * We assume 0x07 really means auto mode while this quirk is active,
+ * as this is far more likely than the ThinkPad being in level 7,
+ * which is only used by the firmware during thermal emergencies.
+ */
+
+static void fan_quirk1_detect(void)
+{
+       /* In some ThinkPads, neither the EC nor the ACPI
+        * DSDT initialize the HFSP register, and it ends up
+        * being initially 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) {
+               switch (thinkpad_id.ec_model) {
+               case 0x5931: /* TP-1Y */
+               case 0x3837: /* TP-78 */
+               case 0x3637: /* TP-76 */
+               case 0x3037: /* TP-70 */
+                       printk(TPACPI_NOTICE
+                              "fan_init: initial fan status is unknown, "
+                              "assuming it is in auto mode\n");
+                       tp_features.fan_ctrl_status_undef = 1;
+                       ;;
+               }
+       }
+}
+
+static void fan_quirk1_handle(u8 *fan_status)
+{
+       if (unlikely(tp_features.fan_ctrl_status_undef)) {
+               if (*fan_status != fan_control_initial_status) {
+                       /* something changed the HFSP regisnter since
+                        * driver init time, so it is not undefined
+                        * anymore */
+                       tp_features.fan_ctrl_status_undef = 0;
+               } else {
+                       /* Return most likely status. In fact, it
+                        * might be the only possible status */
+                       *fan_status = TP_EC_FAN_AUTO;
+               }
+       }
+}
+
 /*
  * Call with fan_mutex held
  */
@@ -5371,8 +5994,10 @@ static int fan_get_status(u8 *status)
                if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
                        return -EIO;
 
-               if (likely(status))
+               if (likely(status)) {
                        *status = s;
+                       fan_quirk1_handle(status);
+               }
 
                break;
 
@@ -5388,7 +6013,7 @@ static int fan_get_status_safe(u8 *status)
        int rc;
        u8 s;
 
-       if (mutex_lock_interruptible(&fan_mutex))
+       if (mutex_lock_killable(&fan_mutex))
                return -ERESTARTSYS;
        rc = fan_get_status(&s);
        if (!rc)
@@ -5471,7 +6096,7 @@ static int fan_set_level_safe(int level)
        if (!fan_control_allowed)
                return -EPERM;
 
-       if (mutex_lock_interruptible(&fan_mutex))
+       if (mutex_lock_killable(&fan_mutex))
                return -ERESTARTSYS;
 
        if (level == TPACPI_FAN_LAST_LEVEL)
@@ -5493,7 +6118,7 @@ static int fan_set_enable(void)
        if (!fan_control_allowed)
                return -EPERM;
 
-       if (mutex_lock_interruptible(&fan_mutex))
+       if (mutex_lock_killable(&fan_mutex))
                return -ERESTARTSYS;
 
        switch (fan_control_access_mode) {
@@ -5548,7 +6173,7 @@ static int fan_set_disable(void)
        if (!fan_control_allowed)
                return -EPERM;
 
-       if (mutex_lock_interruptible(&fan_mutex))
+       if (mutex_lock_killable(&fan_mutex))
                return -ERESTARTSYS;
 
        rc = 0;
@@ -5586,7 +6211,7 @@ static int fan_set_speed(int speed)
        if (!fan_control_allowed)
                return -EPERM;
 
-       if (mutex_lock_interruptible(&fan_mutex))
+       if (mutex_lock_killable(&fan_mutex))
                return -ERESTARTSYS;
 
        rc = 0;
@@ -5682,16 +6307,6 @@ static ssize_t fan_pwm1_enable_show(struct device *dev,
        if (res)
                return res;
 
-       if (unlikely(tp_features.fan_ctrl_status_undef)) {
-               if (status != fan_control_initial_status) {
-                       tp_features.fan_ctrl_status_undef = 0;
-               } else {
-                       /* Return most likely status. In fact, it
-                        * might be the only possible status */
-                       status = TP_EC_FAN_AUTO;
-               }
-       }
-
        if (status & TP_EC_FAN_FULLSPEED) {
                mode = 0;
        } else if (status & TP_EC_FAN_AUTO) {
@@ -5756,14 +6371,6 @@ static ssize_t fan_pwm1_show(struct device *dev,
        if (res)
                return res;
 
-       if (unlikely(tp_features.fan_ctrl_status_undef)) {
-               if (status != fan_control_initial_status) {
-                       tp_features.fan_ctrl_status_undef = 0;
-               } else {
-                       status = TP_EC_FAN_AUTO;
-               }
-       }
-
        if ((status &
             (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
                status = fan_control_desired_level;
@@ -5788,7 +6395,7 @@ static ssize_t fan_pwm1_store(struct device *dev,
        /* scale down from 0-255 to 0-7 */
        newlevel = (s >> 5) & 0x07;
 
-       if (mutex_lock_interruptible(&fan_mutex))
+       if (mutex_lock_killable(&fan_mutex))
                return -ERESTARTSYS;
 
        rc = fan_get_status(&status);
@@ -5895,29 +6502,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                if (likely(acpi_ec_read(fan_status_offset,
                                        &fan_control_initial_status))) {
                        fan_status_access_mode = TPACPI_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) {
-                               switch (thinkpad_id.ec_model) {
-                               case 0x5931: /* TP-1Y */
-                               case 0x3837: /* TP-78 */
-                               case 0x3637: /* TP-76 */
-                               case 0x3037: /* TP-70 */
-                                       printk(TPACPI_NOTICE
-                                              "fan_init: initial fan status "
-                                              "is unknown, assuming it is "
-                                              "in auto mode\n");
-                                       tp_features.fan_ctrl_status_undef = 1;
-                                       ;;
-                               }
-                       }
+                       fan_quirk1_detect();
                } else {
                        printk(TPACPI_ERR
                               "ThinkPad ACPI EC access misbehaving, "
@@ -6106,15 +6691,6 @@ static int fan_read(char *p)
                if (rc < 0)
                        return rc;
 
-               if (unlikely(tp_features.fan_ctrl_status_undef)) {
-                       if (status != fan_control_initial_status)
-                               tp_features.fan_ctrl_status_undef = 0;
-                       else
-                               /* Return most likely status. In fact, it
-                                * might be the only possible status */
-                               status = TP_EC_FAN_AUTO;
-               }
-
                len += sprintf(p + len, "status:\t\t%s\n",
                               (status != 0) ? "enabled" : "disabled");
 
@@ -6563,6 +7139,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
                .init = wan_init,
                .data = &wan_driver_data,
        },
+       {
+               .init = uwb_init,
+               .data = &uwb_driver_data,
+       },
 #ifdef CONFIG_THINKPAD_ACPI_VIDEO
        {
                .init = video_init,
@@ -6701,6 +7281,32 @@ TPACPI_PARAM(brightness);
 TPACPI_PARAM(volume);
 TPACPI_PARAM(fan);
 
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+module_param(dbg_wlswemul, uint, 0);
+MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation");
+module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0);
+MODULE_PARM_DESC(wlsw_state,
+                "Initial state of the emulated WLSW switch");
+
+module_param(dbg_bluetoothemul, uint, 0);
+MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation");
+module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0);
+MODULE_PARM_DESC(bluetooth_state,
+                "Initial state of the emulated bluetooth switch");
+
+module_param(dbg_wwanemul, uint, 0);
+MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation");
+module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0);
+MODULE_PARM_DESC(wwan_state,
+                "Initial state of the emulated WWAN switch");
+
+module_param(dbg_uwbemul, uint, 0);
+MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation");
+module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0);
+MODULE_PARM_DESC(uwb_state,
+                "Initial state of the emulated UWB switch");
+#endif
+
 static void thinkpad_acpi_module_exit(void)
 {
        struct ibm_struct *ibm, *itmp;
index 813e4b6c2c0d2f82aa3251e5b4a65d091c5f2daa..bf8d4cfd8cf57186a88664685761bd943054dbf3 100644 (file)
@@ -245,7 +245,7 @@ struct acpi_table_fadt {
 #define ACPI_FADT_POWER_BUTTON      (1<<4)     /* 04: Power button is handled as a generic feature */
 #define ACPI_FADT_SLEEP_BUTTON      (1<<5)     /* 05: Sleep button is handled as a generic feature, or  not present */
 #define ACPI_FADT_FIXED_RTC         (1<<6)     /* 06: RTC wakeup stat not in fixed register space */
-#define ACPI_FADT_S4_RTC_WAKE       (1<<7)     /* 07: RTC wakeup stat not possible from S4 */
+#define ACPI_FADT_S4_RTC_WAKE       (1<<7)     /* 07: RTC wakeup possible from S4 */
 #define ACPI_FADT_32BIT_TIMER       (1<<8)     /* 08: tmr_val is 32 bits 0=24-bits */
 #define ACPI_FADT_DOCKING_SUPPORTED (1<<9)     /* 09: Docking supported */
 #define ACPI_FADT_RESET_REGISTER    (1<<10)    /* 10: System reset via the FADT RESET_REG supported */
index 1b9cbdc0127ad5416aed125ad875badae744d8f8..7ba8cd9845cbe90aee7b1c54711633ad827e24ca 100644 (file)
@@ -123,7 +123,7 @@ static int collect_garbage_slots(void);
 static int __kprobes check_safety(void)
 {
        int ret = 0;
-#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_FREEZER)
        ret = freeze_processes();
        if (ret == 0) {
                struct task_struct *p, *q;
index 597823b5b7003992714a8f784ed4f278fb9dd0c4..d7a10167a25b37d787418bfbee02e68ba4e28c55 100644 (file)
@@ -4,7 +4,8 @@ EXTRA_CFLAGS    +=      -DDEBUG
 endif
 
 obj-y                          := main.o
-obj-$(CONFIG_PM_SLEEP)         += process.o console.o
+obj-$(CONFIG_PM_SLEEP)         += console.o
+obj-$(CONFIG_FREEZER)          += process.o
 obj-$(CONFIG_HIBERNATION)      += swsusp.o disk.o snapshot.o swap.o user.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)      += poweroff.o