]> 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@woody.linux-foundation.org>
Fri, 19 Oct 2007 20:12:46 +0000 (13:12 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 19 Oct 2007 20:12:46 +0000 (13:12 -0700)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (41 commits)
  ACPICA: hw: Don't carry spinlock over suspend
  ACPICA: hw: remove use_lock flag from acpi_hw_register_{read, write}
  ACPI: cpuidle: port idle timer suspend/resume workaround to cpuidle
  ACPI: clean up acpi_enter_sleep_state_prep
  Hibernation: Make sure that ACPI is enabled in acpi_hibernation_finish
  ACPI: suppress uninitialized var warning
  cpuidle: consolidate 2.6.22 cpuidle branch into one patch
  ACPI: thinkpad-acpi: skip blanks before the data when parsing sysfs
  ACPI: AC: Add sysfs interface
  ACPI: SBS: Add sysfs alarm
  ACPI: SBS: Add ACPI_PROCFS around procfs handling code.
  ACPI: SBS: Add support for power_supply class (and sysfs)
  ACPI: SBS: Make SBS reads table-driven.
  ACPI: SBS: Simplify data structures in SBS
  ACPI: SBS: Split host controller (ACPI0001) from SBS driver (ACPI0002)
  ACPI: EC: Add new query handler to list head.
  ACPI: Add acpi_bus_generate_event4() function
  ACPI: Battery: add sysfs alarm
  ACPI: Battery: Add sysfs support
  ACPI: Battery: Misc clean-ups, no functional changes
  ...

Fix up conflicts in drivers/misc/thinkpad_acpi.[ch] manually

16 files changed:
1  2 
arch/i386/Kconfig
arch/x86_64/Kconfig
drivers/Makefile
drivers/acpi/bus.c
drivers/acpi/osl.c
drivers/acpi/processor_idle.c
drivers/acpi/sleep/main.c
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/sony-laptop.c
drivers/misc/thinkpad_acpi.c
drivers/misc/thinkpad_acpi.h
drivers/net/wireless/ipw2100.c
kernel/time/tick-sched.c

diff --combined arch/i386/Kconfig
index 04be7a7d090fc5306371481d92f1908e8312ee6d,3328e0ab54281198ab1e54e62bbf0ff98fe38a7c..d0a4ea1ba14d166d83c60fd269b1595d101bb742
@@@ -146,7 -146,6 +146,7 @@@ config X86_ELA
  
  config X86_VOYAGER
        bool "Voyager (NCR)"
 +      select SMP if !BROKEN
        help
          Voyager is an MCA-based 32-way capable SMP architecture proprietary
          to NCR Corp.  Machine classes 345x/35xx/4100/51xx are Voyager-based.
@@@ -215,17 -214,6 +215,17 @@@ config X86_ES700
  
  endchoice
  
 +config SCHED_NO_NO_OMIT_FRAME_POINTER
 +      bool "Single-depth WCHAN output"
 +      default y
 +      help
 +        Calculate simpler /proc/<PID>/wchan values. If this option
 +        is disabled then wchan values will recurse back to the
 +        caller function. This provides more accurate wchan values,
 +        at the expense of slightly more scheduling overhead.
 +
 +        If in doubt, say "Y".
 +
  config PARAVIRT
        bool "Paravirtualization support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
          However, when run without a hypervisor the kernel is
          theoretically slower.  If in doubt, say N.
  
 -source "arch/i386/xen/Kconfig"
 +source "arch/x86/xen/Kconfig"
  
  config VMI
        bool "VMI Paravirt-ops support"
@@@ -719,7 -707,7 +719,7 @@@ config MATH_EMULATIO
          intend to use this kernel on different machines.
  
          More information about the internals of the Linux math coprocessor
 -        emulation can be found in <file:arch/i386/math-emu/README>.
 +        emulation can be found in <file:arch/x86/math-emu/README>.
  
          If you are not sure, say Y; apart from resulting in a 66 KB bigger
          kernel, it won't hurt.
@@@ -832,13 -820,12 +832,13 @@@ config CRASH_DUM
        depends on HIGHMEM
        help
          Generate crash dump after being started by kexec.
 -          This should be normally only set in special crash dump kernels
 +        This should be normally only set in special crash dump kernels
          which are loaded in the main kernel with kexec-tools into
          a specially reserved region and then later executed after
          a crash by kdump/kexec. The crash dump kernel must be compiled
 -          to a memory address not used by the main kernel or BIOS using
 -          PHYSICAL_START.
 +        to a memory address not used by the main kernel or BIOS using
 +        PHYSICAL_START, or it must be built as a relocatable image
 +        (CONFIG_RELOCATABLE=y).
          For more details see Documentation/kdump/kdump.txt
  
  config PHYSICAL_START
          Don't change this unless you know what you are doing.
  
  config RELOCATABLE
 -      bool "Build a relocatable kernel(EXPERIMENTAL)"
 +      bool "Build a relocatable kernel (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        help
          This builds a kernel image that retains relocation information
 -          so it can be loaded someplace besides the default 1MB.
 +        so it can be loaded someplace besides the default 1MB.
          The relocations tend to make the kernel binary about 10% larger,
 -          but are discarded at runtime.
 +        but are discarded at runtime.
  
          One use is for the kexec on panic case where the recovery kernel
 -          must live at a different physical address than the primary
 -          kernel.
 +        must live at a different physical address than the primary
 +        kernel.
  
  config PHYSICAL_ALIGN
        hex "Alignment value to which kernel should be aligned"
@@@ -1080,8 -1067,10 +1080,10 @@@ config APM_REAL_MODE_POWER_OF
  
  endif # APM
  
 -source "arch/i386/kernel/cpu/cpufreq/Kconfig"
 +source "arch/x86/kernel/cpu/cpufreq/Kconfig"
  
+ source "drivers/cpuidle/Kconfig"
  endmenu
  
  menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
@@@ -1150,11 -1139,6 +1152,11 @@@ config PCI_MMCONFI
        depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
        default y
  
 +config PCI_DOMAINS
 +      bool
 +      depends on PCI
 +      default y
 +
  source "drivers/pci/pcie/Kconfig"
  
  source "drivers/pci/Kconfig"
@@@ -1224,16 -1208,6 +1226,16 @@@ config SCx200HR_TIME
          processor goes idle (as is done by the scheduler).  The
          other workaround is idle=poll boot option.
  
 +config GEODE_MFGPT_TIMER
 +      bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
 +      depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
 +      default y
 +      help
 +        This driver provides a clock event source based on the MFGPT
 +        timer(s) in the CS5535 and CS5536 companion chip for the geode.
 +        MFGPTs have a better resolution and max interval than the
 +        generic PIT, and are suitable for use as high-res timers.
 +
  config K8_NB
        def_bool y
        depends on AGP_AMD64
@@@ -1256,6 -1230,32 +1258,6 @@@ source "drivers/Kconfig
  
  source "fs/Kconfig"
  
 -menuconfig INSTRUMENTATION
 -      bool "Instrumentation Support"
 -      depends on EXPERIMENTAL
 -      default y
 -      ---help---
 -        Say Y here to get to see options related to performance measurement,
 -        debugging, and testing. This option alone does not add any kernel code.
 -
 -        If you say N, all options in this submenu will be skipped and disabled.
 -
 -if INSTRUMENTATION
 -
 -source "arch/i386/oprofile/Kconfig"
 -
 -config KPROBES
 -      bool "Kprobes"
 -      depends on KALLSYMS && MODULES
 -      help
 -        Kprobes allows you to trap at almost any kernel address and
 -        execute a callback function.  register_kprobe() establishes
 -        a probepoint and specifies the callback.  Kprobes is useful
 -        for kernel debugging, non-intrusive instrumentation and testing.
 -        If in doubt, say "N".
 -
 -endif # INSTRUMENTATION
 -
  source "arch/i386/Kconfig.debug"
  
  source "security/Kconfig"
diff --combined arch/x86_64/Kconfig
index d2521942e5bdca4213f2978319a0bf009f585469,e8dbb37a29cf368152c5c9996cbd9cd5446a03d9..25785b23df87fabe74ff640459dc5ecc04d68f6a
@@@ -36,18 -36,6 +36,18 @@@ config GENERIC_CMOS_UPDAT
        bool
        default y
  
 +config CLOCKSOURCE_WATCHDOG
 +      bool
 +      default y
 +
 +config GENERIC_CLOCKEVENTS
 +      bool
 +      default y
 +
 +config GENERIC_CLOCKEVENTS_BROADCAST
 +      bool
 +      default y
 +
  config ZONE_DMA32
        bool
        default y
@@@ -142,8 -130,6 +142,8 @@@ source "init/Kconfig
  
  menu "Processor type and features"
  
 +source "kernel/time/Kconfig"
 +
  choice
        prompt "Subarchitecture Type"
        default X86_PC
@@@ -175,12 -161,14 +175,12 @@@ config MK
  config MPSC
         bool "Intel P4 / older Netburst based Xeon"
         help
 -        Optimize for Intel Pentium 4 and older Nocona/Dempsey Xeon CPUs
 -        with Intel Extended Memory 64 Technology(EM64T). For details see
 -        <http://www.intel.com/technology/64bitextensions/>.
 +        Optimize for Intel Pentium 4, Pentium D and older Nocona/Dempsey
 +        Xeon CPUs with Intel 64bit which is compatible with x86-64.
          Note that the latest Xeons (Xeon 51xx and 53xx) are not based on the
            Netburst core and shouldn't use this option. You can distinguish them
          using the cpu family field
 -        in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one
 -        (this rule only applies to systems that support EM64T)
 +        in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one.
  
  config MCORE2
        bool "Intel Core2 / newer Xeon"
          Optimize for Intel Core2 and newer Xeons (51xx)
          You can distinguish the newer Xeons from the older ones using
          the cpu family field in /proc/cpuinfo. 15 is an older Xeon
 -        (use CONFIG_MPSC then), 6 is a newer one. This rule only
 -        applies to CPUs that support EM64T.
 +        (use CONFIG_MPSC then), 6 is a newer one.
  
  config GENERIC_CPU
        bool "Generic-x86-64"
@@@ -406,7 -395,6 +406,7 @@@ config ARCH_DISCONTIGMEM_DEFAUL
  config ARCH_SPARSEMEM_ENABLE
        def_bool y
        depends on (NUMA || EXPERIMENTAL)
 +      select SPARSEMEM_VMEMMAP_ENABLE
  
  config ARCH_MEMORY_PROBE
        def_bool y
@@@ -473,9 -461,8 +473,9 @@@ config HPET_TIME
          <http://www.intel.com/hardwaredesign/hpetspec.htm>.
  
  config HPET_EMULATE_RTC
 -      bool "Provide RTC interrupt"
 +      bool
        depends on HPET_TIMER && RTC=y
 +      default y
  
  # Mark as embedded because too many people got it wrong.
  # The code disables itself when not needed.
@@@ -580,18 -567,17 +580,18 @@@ config CRASH_DUM
        bool "kernel crash dumps (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        help
 -          Generate crash dump after being started by kexec.
 -          This should be normally only set in special crash dump kernels
 -          which are loaded in the main kernel with kexec-tools into
 -          a specially reserved region and then later executed after
 -          a crash by kdump/kexec. The crash dump kernel must be compiled
 +        Generate crash dump after being started by kexec.
 +        This should be normally only set in special crash dump kernels
 +        which are loaded in the main kernel with kexec-tools into
 +        a specially reserved region and then later executed after
 +        a crash by kdump/kexec. The crash dump kernel must be compiled
          to a memory address not used by the main kernel or BIOS using
 -        PHYSICAL_START.
 -          For more details see Documentation/kdump/kdump.txt
 +        PHYSICAL_START, or it must be built as a relocatable image
 +        (CONFIG_RELOCATABLE=y).
 +        For more details see Documentation/kdump/kdump.txt
  
  config RELOCATABLE
 -      bool "Build a relocatable kernel(EXPERIMENTAL)"
 +      bool "Build a relocatable kernel (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        help
          Builds a relocatable kernel. This enables loading and running
          must live at a different physical address than the primary
          kernel.
  
 -        Note: If CONFIG_RELOCATABLE=y, then kernel run from the address
 -        it has been loaded at and compile time physical address
 +        Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
 +        it has been loaded at and the compile time physical address
          (CONFIG_PHYSICAL_START) is ignored.
  
  config PHYSICAL_START
@@@ -716,15 -702,12 +716,17 @@@ menu "Power management options
  
  source kernel/power/Kconfig
  
 +config ARCH_HIBERNATION_HEADER
 +      bool
 +      depends on HIBERNATION
 +      default y
 +
  source "drivers/acpi/Kconfig"
  
 -source "arch/x86_64/kernel/cpufreq/Kconfig"
 +source "arch/x86/kernel/cpufreq/Kconfig"
  
+ source "drivers/cpuidle/Kconfig"
  endmenu
  
  menu "Bus options (PCI etc.)"
@@@ -743,11 -726,6 +745,11 @@@ config PCI_MMCONFI
        bool "Support mmconfig PCI config space access"
        depends on PCI && ACPI
  
 +config PCI_DOMAINS
 +      bool
 +      depends on PCI
 +      default y
 +
  source "drivers/pci/pcie/Kconfig"
  
  source "drivers/pci/Kconfig"
@@@ -799,6 -777,22 +801,6 @@@ source "drivers/firmware/Kconfig
  
  source fs/Kconfig
  
 -menu "Instrumentation Support"
 -        depends on EXPERIMENTAL
 -
 -source "arch/x86_64/oprofile/Kconfig"
 -
 -config KPROBES
 -      bool "Kprobes"
 -      depends on KALLSYMS && MODULES
 -      help
 -        Kprobes allows you to trap at almost any kernel address and
 -        execute a callback function.  register_kprobe() establishes
 -        a probepoint and specifies the callback.  Kprobes is useful
 -        for kernel debugging, non-intrusive instrumentation and testing.
 -        If in doubt, say "N".
 -endmenu
 -
  source "arch/x86_64/Kconfig.debug"
  
  source "security/Kconfig"
diff --combined drivers/Makefile
index d2dc01cc73e7cd98c511003e66274c2299650e76,10a9c52c910060a06579cb56496ea8ae56c09221..cfe38ffff28a3024ab36ed254975a0e16f5819c5
@@@ -66,7 -66,7 +66,7 @@@ obj-y                         += i2c
  obj-$(CONFIG_W1)              += w1/
  obj-$(CONFIG_POWER_SUPPLY)    += power/
  obj-$(CONFIG_HWMON)           += hwmon/
 -obj-$(CONFIG_WATCHDOG)                += char/watchdog/
 +obj-$(CONFIG_WATCHDOG)                += watchdog/
  obj-$(CONFIG_PHONE)           += telephony/
  obj-$(CONFIG_MD)              += md/
  obj-$(CONFIG_BT)              += bluetooth/
@@@ -76,6 -76,7 +76,7 @@@ obj-$(CONFIG_MCA)             += mca
  obj-$(CONFIG_EISA)            += eisa/
  obj-$(CONFIG_LGUEST_GUEST)    += lguest/
  obj-$(CONFIG_CPU_FREQ)                += cpufreq/
+ obj-$(CONFIG_CPU_IDLE)                += cpuidle/
  obj-$(CONFIG_MMC)             += mmc/
  obj-$(CONFIG_NEW_LEDS)                += leds/
  obj-$(CONFIG_INFINIBAND)      += infiniband/
@@@ -85,8 -86,6 +86,8 @@@ obj-$(CONFIG_CRYPTO)          += crypto
  obj-$(CONFIG_SUPERH)          += sh/
  obj-$(CONFIG_GENERIC_TIME)    += clocksource/
  obj-$(CONFIG_DMA_ENGINE)      += dma/
 +obj-$(CONFIG_DCA)             += dca/
  obj-$(CONFIG_HID)             += hid/
  obj-$(CONFIG_PPC_PS3)         += ps3/
  obj-$(CONFIG_OF)              += of/
 +obj-$(CONFIG_SSB)             += ssb/
diff --combined drivers/acpi/bus.c
index cbfc81579c9af5ddf5760e6ac410174cff203e38,a54234d3aac12d7f3c59af3f027cf80196d73e0a..fb2cff9a2d24679cf99e9c82b9f04a4e32ea4bb0
@@@ -194,7 -194,7 +194,7 @@@ int acpi_bus_set_power(acpi_handle hand
  
        if (!device->flags.power_manageable) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
 -                              device->dev.kobj.name));
 +                              kobject_name(&device->dev.kobj)));
                return -ENODEV;
        }
        /*
                printk(KERN_WARNING PREFIX
                              "Transitioning device [%s] to D%d\n",
                              device->pnp.bus_id, state);
 -      else
 +      else {
 +              device->power.state = state;
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Device [%s] transitioned to D%d\n",
                                  device->pnp.bus_id, state));
 +      }
  
        return result;
  }
@@@ -286,15 -284,11 +286,11 @@@ DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_
  
  extern int event_is_open;
  
- int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+ int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
  {
-       struct acpi_bus_event *event = NULL;
+       struct acpi_bus_event *event;
        unsigned long flags = 0;
  
-       if (!device)
-               return -EINVAL;
        /* drop event on the floor if no one's listening */
        if (!event_is_open)
                return 0;
        if (!event)
                return -ENOMEM;
  
-       strcpy(event->device_class, device->pnp.device_class);
-       strcpy(event->bus_id, device->pnp.bus_id);
+       strcpy(event->device_class, device_class);
+       strcpy(event->bus_id, bus_id);
        event->type = type;
        event->data = data;
  
        wake_up_interruptible(&acpi_bus_event_queue);
  
        return 0;
+ }
+ EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
+ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+ {
+       if (!device)
+               return -EINVAL;
+       return acpi_bus_generate_proc_event4(device->pnp.device_class,
+                                            device->pnp.bus_id, type, data);
  }
  
  EXPORT_SYMBOL(acpi_bus_generate_proc_event);
diff --combined drivers/acpi/osl.c
index 352cf81af5818de3569848038714052cbfd0353d,5d14d4f10b1240743a74efafb3a94d8ff9cf142c..aabc6ca4a81c72463529c3e711b012f8b6e909a7
@@@ -1042,14 -1042,6 +1042,6 @@@ static int __init acpi_wake_gpes_always
  
  __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
  
- /*
-  * max_cstate is defined in the base kernel so modules can
-  * change it w/o depending on the state of the processor module.
-  */
- unsigned int max_cstate = ACPI_PROCESSOR_MAX_POWER;
- EXPORT_SYMBOL(max_cstate);
  /*
   * Acquire a spinlock.
   *
@@@ -1214,7 -1206,7 +1206,7 @@@ acpi_os_validate_address 
  }
  
  #ifdef CONFIG_DMI
 -static int dmi_osi_linux(struct dmi_system_id *d)
 +static int dmi_osi_linux(const struct dmi_system_id *d)
  {
        printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
        enable_osi_linux(1);
index 1f6fb38de017fc2c16dcd067b96efec802b1e155,0cad56ca342bdb0f0e556c53edc41cb752ef38a9..f996d0e37689c402642a0c884b0126ad15a505bc
@@@ -40,6 -40,7 +40,7 @@@
  #include <linux/sched.h>      /* need_resched() */
  #include <linux/latency.h>
  #include <linux/clockchips.h>
+ #include <linux/cpuidle.h>
  
  /*
   * Include the apic definitions for x86 to have the APIC timer related defines
@@@ -64,14 -65,22 +65,22 @@@ ACPI_MODULE_NAME("processor_idle")
  #define ACPI_PROCESSOR_FILE_POWER     "power"
  #define US_TO_PM_TIMER_TICKS(t)               ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
  #define PM_TIMER_TICK_NS              (1000000000ULL/PM_TIMER_FREQUENCY)
+ #ifndef CONFIG_CPU_IDLE
  #define C2_OVERHEAD                   4       /* 1us (3.579 ticks per us) */
  #define C3_OVERHEAD                   4       /* 1us (3.579 ticks per us) */
  static void (*pm_idle_save) (void) __read_mostly;
- module_param(max_cstate, uint, 0644);
+ #else
+ #define C2_OVERHEAD                   1       /* 1us */
+ #define C3_OVERHEAD                   1       /* 1us */
+ #endif
+ #define PM_TIMER_TICKS_TO_US(p)               (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
  
+ static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
+ module_param(max_cstate, uint, 0000);
  static unsigned int nocst __read_mostly;
  module_param(nocst, uint, 0000);
  
+ #ifndef CONFIG_CPU_IDLE
  /*
   * bm_history -- bit-mask with a bit per jiffy of bus-master activity
   * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms
  static unsigned int bm_history __read_mostly =
      (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
  module_param(bm_history, uint, 0644);
- /* --------------------------------------------------------------------------
-                                 Power Management
-    -------------------------------------------------------------------------- */
+ static int acpi_processor_set_power_policy(struct acpi_processor *pr);
+ #endif
  
  /*
   * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
   *
   * To skip this limit, boot/load with a large max_cstate limit.
   */
 -static int set_max_cstate(struct dmi_system_id *id)
 +static int set_max_cstate(const struct dmi_system_id *id)
  {
        if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
                return 0;
@@@ -177,6 -187,18 +187,18 @@@ static inline u32 ticks_elapsed(u32 t1
                return ((0xFFFFFFFF - t1) + t2);
  }
  
+ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
+ {
+       if (t2 >= t1)
+               return PM_TIMER_TICKS_TO_US(t2 - t1);
+       else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
+               return PM_TIMER_TICKS_TO_US(((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
+       else
+               return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
+ }
+ #ifndef CONFIG_CPU_IDLE
  static void
  acpi_processor_power_activate(struct acpi_processor *pr,
                              struct acpi_processor_cx *new)
@@@ -248,6 -270,7 +270,7 @@@ static void acpi_cstate_enter(struct ac
                unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
        }
  }
+ #endif /* !CONFIG_CPU_IDLE */
  
  #ifdef ARCH_APICTIMER_STOPS_ON_C3
  
@@@ -276,12 -299,21 +299,12 @@@ static void acpi_timer_check_state(int 
  
  static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
  {
 -#ifdef CONFIG_GENERIC_CLOCKEVENTS
        unsigned long reason;
  
        reason = pr->power.timer_broadcast_on_state < INT_MAX ?
                CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
  
        clockevents_notify(reason, &pr->id);
 -#else
 -      cpumask_t mask = cpumask_of_cpu(pr->id);
 -
 -      if (pr->power.timer_broadcast_on_state < INT_MAX)
 -              on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
 -      else
 -              on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
 -#endif
  }
  
  /* Power(C) State timer broadcast control */
@@@ -289,6 -321,8 +312,6 @@@ static void acpi_state_timer_broadcast(
                                       struct acpi_processor_cx *cx,
                                       int broadcast)
  {
 -#ifdef CONFIG_GENERIC_CLOCKEVENTS
 -
        int state = cx - pr->power.states;
  
        if (state >= pr->power.timer_broadcast_on_state) {
                        CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
                clockevents_notify(reason, &pr->id);
        }
 -#endif
  }
  
  #else
@@@ -330,6 -365,7 +353,7 @@@ int acpi_processor_resume(struct acpi_d
        return 0;
  }
  
+ #ifndef CONFIG_CPU_IDLE
  static void acpi_processor_idle(void)
  {
        struct acpi_processor *pr = NULL;
         * an SMP system. We do it here instead of doing it at _CST/P_LVL
         * detection phase, to work cleanly with logical CPU hotplug.
         */
-       if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && 
+       if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
            !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
                cx = &pr->power.states[ACPI_STATE_C1];
  #endif
@@@ -727,6 -763,7 +751,7 @@@ static int acpi_processor_set_power_pol
  
        return 0;
  }
+ #endif /* !CONFIG_CPU_IDLE */
  
  static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
  {
  #ifndef CONFIG_HOTPLUG_CPU
        /*
         * Check for P_LVL2_UP flag before entering C2 and above on
-        * an SMP system. 
+        * an SMP system.
         */
        if ((num_online_cpus() > 1) &&
            !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
@@@ -945,7 -982,12 +970,12 @@@ static void acpi_processor_power_verify
         * Normalize the C2 latency to expidite policy
         */
        cx->valid = 1;
+ #ifndef CONFIG_CPU_IDLE
        cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ #else
+       cx->latency_ticks = cx->latency;
+ #endif
  
        return;
  }
@@@ -1025,7 -1067,12 +1055,12 @@@ static void acpi_processor_power_verify
         * use this in our C3 policy
         */
        cx->valid = 1;
+ #ifndef CONFIG_CPU_IDLE
        cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ #else
+       cx->latency_ticks = cx->latency;
+ #endif
  
        return;
  }
@@@ -1090,6 -1137,7 +1125,7 @@@ static int acpi_processor_get_power_inf
  
        pr->power.count = acpi_processor_power_verify(pr);
  
+ #ifndef CONFIG_CPU_IDLE
        /*
         * Set Default Policy
         * ------------------
        result = acpi_processor_set_power_policy(pr);
        if (result)
                return result;
+ #endif
  
        /*
         * if one state of type C2 or C3 is available, mark this
        return 0;
  }
  
- int acpi_processor_cst_has_changed(struct acpi_processor *pr)
- {
-       int result = 0;
-       if (!pr)
-               return -EINVAL;
-       if (nocst) {
-               return -ENODEV;
-       }
-       if (!pr->flags.power_setup_done)
-               return -ENODEV;
-       /* Fall back to the default idle loop */
-       pm_idle = pm_idle_save;
-       synchronize_sched();    /* Relies on interrupts forcing exit from idle. */
-       pr->flags.power = 0;
-       result = acpi_processor_get_power_info(pr);
-       if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
-               pm_idle = acpi_processor_idle;
-       return result;
- }
- /* proc interface */
  static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
  {
        struct acpi_processor *pr = seq->private;
@@@ -1227,6 -1247,35 +1235,35 @@@ static const struct file_operations acp
        .release = single_release,
  };
  
+ #ifndef CONFIG_CPU_IDLE
+ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+ {
+       int result = 0;
+       if (!pr)
+               return -EINVAL;
+       if (nocst) {
+               return -ENODEV;
+       }
+       if (!pr->flags.power_setup_done)
+               return -ENODEV;
+       /* Fall back to the default idle loop */
+       pm_idle = pm_idle_save;
+       synchronize_sched();    /* Relies on interrupts forcing exit from idle. */
+       pr->flags.power = 0;
+       result = acpi_processor_get_power_info(pr);
+       if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
+               pm_idle = acpi_processor_idle;
+       return result;
+ }
  #ifdef CONFIG_SMP
  static void smp_callback(void *v)
  {
@@@ -1249,7 -1298,366 +1286,366 @@@ static int acpi_processor_latency_notif
  static struct notifier_block acpi_processor_latency_notifier = {
        .notifier_call = acpi_processor_latency_notify,
  };
+ #endif
+ #else /* CONFIG_CPU_IDLE */
+ /**
+  * acpi_idle_bm_check - checks if bus master activity was detected
+  */
+ static int acpi_idle_bm_check(void)
+ {
+       u32 bm_status = 0;
+       acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
+       if (bm_status)
+               acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
+       /*
+        * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
+        * the true state of bus mastering activity; forcing us to
+        * manually check the BMIDEA bit of each IDE channel.
+        */
+       else if (errata.piix4.bmisx) {
+               if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
+                   || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
+                       bm_status = 1;
+       }
+       return bm_status;
+ }
+ /**
+  * acpi_idle_update_bm_rld - updates the BM_RLD bit depending on target state
+  * @pr: the processor
+  * @target: the new target state
+  */
+ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
+                                          struct acpi_processor_cx *target)
+ {
+       if (pr->flags.bm_rld_set && target->type != ACPI_STATE_C3) {
+               acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
+               pr->flags.bm_rld_set = 0;
+       }
+       if (!pr->flags.bm_rld_set && target->type == ACPI_STATE_C3) {
+               acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
+               pr->flags.bm_rld_set = 1;
+       }
+ }
+ /**
+  * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
+  * @cx: cstate data
+  */
+ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+ {
+       if (cx->space_id == ACPI_CSTATE_FFH) {
+               /* Call into architectural FFH based C-state */
+               acpi_processor_ffh_cstate_enter(cx);
+       } else {
+               int unused;
+               /* IO port based C-state */
+               inb(cx->address);
+               /* Dummy wait op - must do something useless after P_LVL2 read
+                  because chipsets cannot guarantee that STPCLK# signal
+                  gets asserted in time to freeze execution properly. */
+               unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       }
+ }
+ /**
+  * acpi_idle_enter_c1 - enters an ACPI C1 state-type
+  * @dev: the target CPU
+  * @state: the state data
+  *
+  * This is equivalent to the HALT instruction.
+  */
+ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
+                             struct cpuidle_state *state)
+ {
+       struct acpi_processor *pr;
+       struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+       pr = processors[smp_processor_id()];
+       if (unlikely(!pr))
+               return 0;
+       if (pr->flags.bm_check)
+               acpi_idle_update_bm_rld(pr, cx);
+       current_thread_info()->status &= ~TS_POLLING;
+       /*
+        * TS_POLLING-cleared state must be visible before we test
+        * NEED_RESCHED:
+        */
+       smp_mb();
+       if (!need_resched())
+               safe_halt();
+       current_thread_info()->status |= TS_POLLING;
+       cx->usage++;
+       return 0;
+ }
+ /**
+  * acpi_idle_enter_simple - enters an ACPI state without BM handling
+  * @dev: the target CPU
+  * @state: the state data
+  */
+ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
+                                 struct cpuidle_state *state)
+ {
+       struct acpi_processor *pr;
+       struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+       u32 t1, t2;
+       pr = processors[smp_processor_id()];
+       if (unlikely(!pr))
+               return 0;
+       if (acpi_idle_suspend)
+               return(acpi_idle_enter_c1(dev, state));
+       if (pr->flags.bm_check)
+               acpi_idle_update_bm_rld(pr, cx);
+       local_irq_disable();
+       current_thread_info()->status &= ~TS_POLLING;
+       /*
+        * TS_POLLING-cleared state must be visible before we test
+        * NEED_RESCHED:
+        */
+       smp_mb();
+       if (unlikely(need_resched())) {
+               current_thread_info()->status |= TS_POLLING;
+               local_irq_enable();
+               return 0;
+       }
+       if (cx->type == ACPI_STATE_C3)
+               ACPI_FLUSH_CPU_CACHE();
+       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       acpi_state_timer_broadcast(pr, cx, 1);
+       acpi_idle_do_entry(cx);
+       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+ #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+       /* TSC could halt in idle, so notify users */
+       mark_tsc_unstable("TSC halts in idle");;
+ #endif
+       local_irq_enable();
+       current_thread_info()->status |= TS_POLLING;
+       cx->usage++;
+       acpi_state_timer_broadcast(pr, cx, 0);
+       cx->time += ticks_elapsed(t1, t2);
+       return ticks_elapsed_in_us(t1, t2);
+ }
+ static int c3_cpu_count;
+ static DEFINE_SPINLOCK(c3_lock);
+ /**
+  * acpi_idle_enter_bm - enters C3 with proper BM handling
+  * @dev: the target CPU
+  * @state: the state data
+  *
+  * If BM is detected, the deepest non-C3 idle state is entered instead.
+  */
+ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
+                             struct cpuidle_state *state)
+ {
+       struct acpi_processor *pr;
+       struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+       u32 t1, t2;
+       pr = processors[smp_processor_id()];
+       if (unlikely(!pr))
+               return 0;
+       if (acpi_idle_suspend)
+               return(acpi_idle_enter_c1(dev, state));
+       local_irq_disable();
+       current_thread_info()->status &= ~TS_POLLING;
+       /*
+        * TS_POLLING-cleared state must be visible before we test
+        * NEED_RESCHED:
+        */
+       smp_mb();
+       if (unlikely(need_resched())) {
+               current_thread_info()->status |= TS_POLLING;
+               local_irq_enable();
+               return 0;
+       }
+       /*
+        * Must be done before busmaster disable as we might need to
+        * access HPET !
+        */
+       acpi_state_timer_broadcast(pr, cx, 1);
+       if (acpi_idle_bm_check()) {
+               cx = pr->power.bm_state;
+               acpi_idle_update_bm_rld(pr, cx);
+               t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+               acpi_idle_do_entry(cx);
+               t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       } else {
+               acpi_idle_update_bm_rld(pr, cx);
+               spin_lock(&c3_lock);
+               c3_cpu_count++;
+               /* Disable bus master arbitration when all CPUs are in C3 */
+               if (c3_cpu_count == num_online_cpus())
+                       acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
+               spin_unlock(&c3_lock);
+               t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+               acpi_idle_do_entry(cx);
+               t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+               spin_lock(&c3_lock);
+               /* Re-enable bus master arbitration */
+               if (c3_cpu_count == num_online_cpus())
+                       acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
+               c3_cpu_count--;
+               spin_unlock(&c3_lock);
+       }
+ #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+       /* TSC could halt in idle, so notify users */
+       mark_tsc_unstable("TSC halts in idle");
+ #endif
+       local_irq_enable();
+       current_thread_info()->status |= TS_POLLING;
+       cx->usage++;
+       acpi_state_timer_broadcast(pr, cx, 0);
+       cx->time += ticks_elapsed(t1, t2);
+       return ticks_elapsed_in_us(t1, t2);
+ }
+ struct cpuidle_driver acpi_idle_driver = {
+       .name =         "acpi_idle",
+       .owner =        THIS_MODULE,
+ };
+ /**
+  * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE
+  * @pr: the ACPI processor
+  */
+ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
+ {
+       int i, count = 0;
+       struct acpi_processor_cx *cx;
+       struct cpuidle_state *state;
+       struct cpuidle_device *dev = &pr->power.dev;
+       if (!pr->flags.power_setup_done)
+               return -EINVAL;
+       if (pr->flags.power == 0) {
+               return -EINVAL;
+       }
+       for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+               cx = &pr->power.states[i];
+               state = &dev->states[count];
+               if (!cx->valid)
+                       continue;
+ #ifdef CONFIG_HOTPLUG_CPU
+               if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+                   !pr->flags.has_cst &&
+                   !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
+                       continue;
  #endif
+               cpuidle_set_statedata(state, cx);
+               snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
+               state->exit_latency = cx->latency;
+               state->target_residency = cx->latency * 6;
+               state->power_usage = cx->power;
+               state->flags = 0;
+               switch (cx->type) {
+                       case ACPI_STATE_C1:
+                       state->flags |= CPUIDLE_FLAG_SHALLOW;
+                       state->enter = acpi_idle_enter_c1;
+                       break;
+                       case ACPI_STATE_C2:
+                       state->flags |= CPUIDLE_FLAG_BALANCED;
+                       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+                       state->enter = acpi_idle_enter_simple;
+                       break;
+                       case ACPI_STATE_C3:
+                       state->flags |= CPUIDLE_FLAG_DEEP;
+                       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+                       state->flags |= CPUIDLE_FLAG_CHECK_BM;
+                       state->enter = pr->flags.bm_check ?
+                                       acpi_idle_enter_bm :
+                                       acpi_idle_enter_simple;
+                       break;
+               }
+               count++;
+       }
+       dev->state_count = count;
+       if (!count)
+               return -EINVAL;
+       /* find the deepest state that can handle active BM */
+       if (pr->flags.bm_check) {
+               for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++)
+                       if (pr->power.states[i].type == ACPI_STATE_C3)
+                               break;
+               pr->power.bm_state = &pr->power.states[i-1];
+       }
+       return 0;
+ }
+ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+ {
+       int ret;
+       if (!pr)
+               return -EINVAL;
+       if (nocst) {
+               return -ENODEV;
+       }
+       if (!pr->flags.power_setup_done)
+               return -ENODEV;
+       cpuidle_pause_and_lock();
+       cpuidle_disable_device(&pr->power.dev);
+       acpi_processor_get_power_info(pr);
+       acpi_processor_setup_cpuidle(pr);
+       ret = cpuidle_enable_device(&pr->power.dev);
+       cpuidle_resume_and_unlock();
+       return ret;
+ }
+ #endif /* CONFIG_CPU_IDLE */
  
  int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
                              struct acpi_device *device)
                               "ACPI: processor limited to max C-state %d\n",
                               max_cstate);
                first_run++;
- #ifdef CONFIG_SMP
+ #if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP)
                register_latency_notifier(&acpi_processor_latency_notifier);
  #endif
        }
        }
  
        acpi_processor_get_power_info(pr);
+       pr->flags.power_setup_done = 1;
  
        /*
         * Install the idle handler if processor power management is supported.
         * platforms that only support C1.
         */
        if ((pr->flags.power) && (!boot_option_idle_override)) {
+ #ifdef CONFIG_CPU_IDLE
+               acpi_processor_setup_cpuidle(pr);
+               pr->power.dev.cpu = pr->id;
+               if (cpuidle_register_device(&pr->power.dev))
+                       return -EIO;
+ #endif
                printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id);
                for (i = 1; i <= pr->power.count; i++)
                        if (pr->power.states[i].valid)
                                       pr->power.states[i].type);
                printk(")\n");
  
+ #ifndef CONFIG_CPU_IDLE
                if (pr->id == 0) {
                        pm_idle_save = pm_idle;
                        pm_idle = acpi_processor_idle;
                }
+ #endif
        }
  
        /* 'power' [R] */
                entry->owner = THIS_MODULE;
        }
  
-       pr->flags.power_setup_done = 1;
        return 0;
  }
  
  int acpi_processor_power_exit(struct acpi_processor *pr,
                              struct acpi_device *device)
  {
+ #ifdef CONFIG_CPU_IDLE
+       if ((pr->flags.power) && (!boot_option_idle_override))
+               cpuidle_unregister_device(&pr->power.dev);
+ #endif
        pr->flags.power_setup_done = 0;
  
        if (acpi_device_dir(device))
                remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,
                                  acpi_device_dir(device));
  
+ #ifndef CONFIG_CPU_IDLE
        /* Unregister the idle handler when processor #0 is removed. */
        if (pr->id == 0) {
                pm_idle = pm_idle_save;
                unregister_latency_notifier(&acpi_processor_latency_notifier);
  #endif
        }
+ #endif
  
        return 0;
  }
index 048295ec370786aae9b04b900402103e29c72df8,be616317fe53ea786d689fd380a1aa5d8c5abf2f..f3d3867303ec61602958f135494cc1ccbe86309b
@@@ -44,13 -44,12 +44,12 @@@ int acpi_sleep_prepare(u32 acpi_state
        ACPI_FLUSH_CPU_CACHE();
        acpi_enable_wakeup_device_prep(acpi_state);
  #endif
-       acpi_gpe_sleep_prepare(acpi_state);
        acpi_enter_sleep_state_prep(acpi_state);
        return 0;
  }
  
  #ifdef CONFIG_SUSPEND
 -static struct pm_ops acpi_pm_ops;
 +static struct platform_suspend_ops acpi_pm_ops;
  
  extern void do_suspend_lowlevel(void);
  
@@@ -85,12 -84,13 +84,12 @@@ static int acpi_pm_set_target(suspend_s
  
  /**
   *    acpi_pm_prepare - Do preliminary suspend work.
 - *    @pm_state: ignored
   *
   *    If necessary, set the firmware waking vector and do arch-specific
   *    nastiness to get the wakeup code to the waking vector.
   */
  
 -static int acpi_pm_prepare(suspend_state_t pm_state)
 +static int acpi_pm_prepare(void)
  {
        int error = acpi_sleep_prepare(acpi_target_sleep_state);
  
@@@ -159,12 -159,13 +158,12 @@@ static int acpi_pm_enter(suspend_state_
  
  /**
   *    acpi_pm_finish - Finish up suspend sequence.
 - *    @pm_state: ignored
   *
   *    This is called after we wake back up (or if entering the sleep state
   *    failed). 
   */
  
 -static int acpi_pm_finish(suspend_state_t pm_state)
 +static void acpi_pm_finish(void)
  {
        u32 acpi_state = acpi_target_sleep_state;
  
                init_8259A(0);
        }
  #endif
 -      return 0;
  }
  
  static int acpi_pm_state_valid(suspend_state_t pm_state)
        }
  }
  
 -static struct pm_ops acpi_pm_ops = {
 +static struct platform_suspend_ops acpi_pm_ops = {
        .valid = acpi_pm_state_valid,
        .set_target = acpi_pm_set_target,
        .prepare = acpi_pm_prepare,
   * Toshiba fails to preserve interrupts over S1, reinitialization
   * of 8259 is needed after S1 resume.
   */
 -static int __init init_ints_after_s1(struct dmi_system_id *d)
 +static int __init init_ints_after_s1(const struct dmi_system_id *d)
  {
        printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
        init_8259A_after_S1 = 1;
@@@ -230,12 -232,6 +229,12 @@@ static struct dmi_system_id __initdata 
  #endif /* CONFIG_SUSPEND */
  
  #ifdef CONFIG_HIBERNATION
 +static int acpi_hibernation_start(void)
 +{
 +      acpi_target_sleep_state = ACPI_STATE_S4;
 +      return 0;
 +}
 +
  static int acpi_hibernation_prepare(void)
  {
        return acpi_sleep_prepare(ACPI_STATE_S4);
@@@ -257,24 -253,18 +256,29 @@@ static int acpi_hibernation_enter(void
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
  }
  
 +static void acpi_hibernation_leave(void)
 +{
 +      /*
 +       * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 +       * enable it here.
 +       */
 +      acpi_enable();
 +}
 +
  static void acpi_hibernation_finish(void)
  {
+       /*
+        * If ACPI is not enabled by the BIOS and the boot kernel, we need to
+        * enable it here.
+        */
+       acpi_enable();
        acpi_leave_sleep_state(ACPI_STATE_S4);
        acpi_disable_wakeup_device(ACPI_STATE_S4);
  
        /* reset firmware waking vector */
        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
 +
 +      acpi_target_sleep_state = ACPI_STATE_S0;
  }
  
  static int acpi_hibernation_pre_restore(void)
@@@ -291,13 -281,10 +295,13 @@@ static void acpi_hibernation_restore_cl
        acpi_hw_enable_all_runtime_gpes();
  }
  
 -static struct hibernation_ops acpi_hibernation_ops = {
 +static struct platform_hibernation_ops acpi_hibernation_ops = {
 +      .start = acpi_hibernation_start,
 +      .pre_snapshot = acpi_hibernation_prepare,
 +      .finish = acpi_hibernation_finish,
        .prepare = acpi_hibernation_prepare,
        .enter = acpi_hibernation_enter,
 -      .finish = acpi_hibernation_finish,
 +      .leave = acpi_hibernation_leave,
        .pre_restore = acpi_hibernation_pre_restore,
        .restore_cleanup = acpi_hibernation_restore_cleanup,
  };
@@@ -434,7 -421,7 +438,7 @@@ int __init acpi_sleep_init(void
                }
        }
  
 -      pm_set_ops(&acpi_pm_ops);
 +      suspend_set_ops(&acpi_pm_ops);
  #endif
  
  #ifdef CONFIG_HIBERNATION
diff --combined drivers/acpi/thermal.c
index ad898e10c1a91162b42a18827678de93744a7a09,69ec73b0239d18712f6c2af66905bf8d1701390e..5f79b44512120e489950f65a22d912aa88ed66ec
@@@ -195,6 -195,7 +195,7 @@@ struct acpi_thermal 
        struct acpi_thermal_trips trips;
        struct acpi_handle_list devices;
        struct timer_list timer;
+       struct mutex lock;
  };
  
  static const struct file_operations acpi_thermal_state_fops = {
@@@ -711,6 -712,7 +712,7 @@@ static void acpi_thermal_check(void *da
        int result = 0;
        struct acpi_thermal *tz = data;
        unsigned long sleep_time = 0;
+       unsigned long timeout_jiffies = 0;
        int i = 0;
        struct acpi_thermal_state state;
  
                return;
        }
  
+       /* Check if someone else is already running */
+       if (!mutex_trylock(&tz->lock))
+               return;
        state = tz->state;
  
        result = acpi_thermal_get_temperature(tz);
        if (result)
-               return;
+               goto unlock;
  
        memset(&tz->state, 0, sizeof(tz->state));
  
         * a thermal event occurs).  Note that _TSP and _TZD values are
         * given in 1/10th seconds (we must covert to milliseconds).
         */
-       if (tz->state.passive)
+       if (tz->state.passive) {
                sleep_time = tz->trips.passive.tsp * 100;
-       else if (tz->polling_frequency > 0)
+               timeout_jiffies =  jiffies + (HZ * sleep_time) / 1000;
+       } else if (tz->polling_frequency > 0) {
                sleep_time = tz->polling_frequency * 100;
+               timeout_jiffies =  round_jiffies(jiffies + (HZ * sleep_time) / 1000);
+       }
  
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
                          tz->name, tz->temperature, sleep_time));
                        del_timer(&(tz->timer));
        } else {
                if (timer_pending(&(tz->timer)))
-                       mod_timer(&(tz->timer),
-                                       jiffies + (HZ * sleep_time) / 1000);
+                       mod_timer(&(tz->timer), timeout_jiffies);
                else {
                        tz->timer.data = (unsigned long)tz;
                        tz->timer.function = acpi_thermal_run;
-                       tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+                       tz->timer.expires = timeout_jiffies;
                        add_timer(&(tz->timer));
                }
        }
-       return;
+       unlock:
+       mutex_unlock(&tz->lock);
  }
  
  /* --------------------------------------------------------------------------
@@@ -1251,7 -1259,7 +1259,7 @@@ static int acpi_thermal_add(struct acpi
        strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
        acpi_driver_data(device) = tz;
+       mutex_init(&tz->lock);
        result = acpi_thermal_get_info(tz);
        if (result)
                goto end;
@@@ -1321,7 -1329,7 +1329,7 @@@ static int acpi_thermal_remove(struct a
        }
  
        acpi_thermal_remove_fs(device);
+       mutex_destroy(&tz->lock);
        kfree(tz);
        return 0;
  }
@@@ -1360,7 -1368,7 +1368,7 @@@ static int acpi_thermal_resume(struct a
  }
  
  #ifdef CONFIG_DMI
 -static int thermal_act(struct dmi_system_id *d) {
 +static int thermal_act(const struct dmi_system_id *d) {
  
        if (act == 0) {
                printk(KERN_NOTICE "ACPI: %s detected: "
        }
        return 0;
  }
 -static int thermal_nocrt(struct dmi_system_id *d) {
 +static int thermal_nocrt(const struct dmi_system_id *d) {
  
        printk(KERN_NOTICE "ACPI: %s detected: "
                "disabling all critical thermal trip point actions.\n", d->ident);
        nocrt = 1;
        return 0;
  }
 -static int thermal_tzp(struct dmi_system_id *d) {
 +static int thermal_tzp(const struct dmi_system_id *d) {
  
        if (tzp == 0) {
                printk(KERN_NOTICE "ACPI: %s detected: "
        }
        return 0;
  }
 -static int thermal_psv(struct dmi_system_id *d) {
 +static int thermal_psv(const struct dmi_system_id *d) {
  
        if (psv == 0) {
                printk(KERN_NOTICE "ACPI: %s detected: "
diff --combined drivers/acpi/video.c
index b8a2095cb5ee44f3ceea40ccdf7d11c9c9c58ca0,f31e3c8749e0ae48f805489538346882eaf79ee8..bac956b30c57b94fafe71c951331723122bbd926
@@@ -316,7 -316,7 +316,7 @@@ static int acpi_video_output_get(struc
  {
        unsigned long state;
        struct acpi_video_device *vd =
 -              (struct acpi_video_device *)class_get_devdata(&od->class_dev);
 +              (struct acpi_video_device *)dev_get_drvdata(&od->dev);
        acpi_video_device_get_state(vd, &state);
        return (int)state;
  }
@@@ -325,7 -325,7 +325,7 @@@ static int acpi_video_output_set(struc
  {
        unsigned long state = od->request_state;
        struct acpi_video_device *vd=
 -              (struct acpi_video_device *)class_get_devdata(&od->class_dev);
 +              (struct acpi_video_device *)dev_get_drvdata(&od->dev);
        return acpi_video_device_set_state(vd, state);
  }
  
@@@ -409,14 -409,17 +409,17 @@@ acpi_video_device_lcd_query_levels(stru
  static int
  acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
  {
-       int status;
+       int status = AE_OK;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
        struct acpi_object_list args = { 1, &arg0 };
  
  
        arg0.integer.value = level;
-       status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
  
+       if (device->cap._BCM)
+               status = acpi_evaluate_object(device->dev->handle, "_BCM",
+                                             &args, NULL);
+       device->brightness->curr = level;
        return status;
  }
  
@@@ -424,11 -427,11 +427,11 @@@ static in
  acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
                                        unsigned long *level)
  {
-       int status;
-       status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level);
-       return status;
+       if (device->cap._BQC)
+               return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL,
+                                            level);
+       *level = device->brightness->curr;
+       return AE_OK;
  }
  
  static int
@@@ -1633,9 -1636,20 +1636,20 @@@ static in
  acpi_video_get_next_level(struct acpi_video_device *device,
                          u32 level_current, u32 event)
  {
-       int min, max, min_above, max_below, i, l;
+       int min, max, min_above, max_below, i, l, delta = 255;
        max = max_below = 0;
        min = min_above = 255;
+       /* Find closest level to level_current */
+       for (i = 0; i < device->brightness->count; i++) {
+               l = device->brightness->levels[i];
+               if (abs(l - level_current) < abs(delta)) {
+                       delta = l - level_current;
+                       if (!delta)
+                               break;
+               }
+       }
+       /* Ajust level_current to closest available level */
+       level_current += delta;
        for (i = 0; i < device->brightness->count; i++) {
                l = device->brightness->levels[i];
                if (l < min)
diff --combined drivers/misc/Kconfig
index 346c44eff95eb91370fc832664c2632956473d4d,e0a1ff927a5bc45057e5e5cd0bab7ae0f7704e08..cf02ddc3436fce25dde5ad87b190ad21776480e8
@@@ -111,6 -111,21 +111,21 @@@ config ASUS_LAPTO
  
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
  
+ config FUJITSU_LAPTOP
+         tristate "Fujitsu Laptop Extras"
+         depends on X86
+         depends on ACPI
+         depends on BACKLIGHT_CLASS_DEVICE
+         ---help---
+         This is a driver for laptops built by Fujitsu:
+           * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
+           * Possibly other Fujitsu laptop models
+         It adds support for LCD brightness control.
+         If you have a Fujitsu laptop, say Y or M here.
  config MSI_LAPTOP
          tristate "MSI Laptop Extras"
          depends on X86
@@@ -134,6 -149,7 +149,7 @@@ config SONY_LAPTO
        tristate "Sony Laptop Extras"
        depends on X86 && ACPI
        select BACKLIGHT_CLASS_DEVICE
+       depends on INPUT
          ---help---
          This mini-driver drives the SNC and SPIC devices present in the ACPI
          BIOS of the Sony Vaio laptops.
@@@ -156,6 -172,7 +172,7 @@@ config THINKPAD_ACP
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
        select NVRAM
+       depends on INPUT
        ---help---
          This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
          support for Fn-Fx key combinations, Bluetooth control, video
@@@ -203,16 -220,4 +220,16 @@@ config THINKPAD_ACPI_BA
          If you are not sure, say Y here.
  
  
 +config ATMEL_SSC
 +      tristate "Device driver for Atmel SSC peripheral"
 +      depends on AVR32 || ARCH_AT91
 +      ---help---
 +        This option enables device driver support for Atmel Syncronized
 +        Serial Communication peripheral (SSC).
 +
 +        The SSC peripheral supports a wide variety of serial frame based
 +        communications, i.e. I2S, SPI, etc.
 +
 +        If unsure, say N.
 +
  endif # MISC_DEVICES
diff --combined drivers/misc/Makefile
index a24c61475c2f8afcd3490a89055bab3587e9b39d,be90d483d2f9fa10c2153c83a55db1cf7f8ff8e4..87f2685d728fed038472818507a48741f873e177
@@@ -7,7 -7,6 +7,7 @@@ obj-$(CONFIG_IBM_ASM)            += ibmasm
  obj-$(CONFIG_HDPU_FEATURES)   += hdpuftrs/
  obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
  obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
 +obj-$(CONFIG_ATMEL_SSC)               += atmel-ssc.o
  obj-$(CONFIG_LKDTM)           += lkdtm.o
  obj-$(CONFIG_TIFM_CORE)               += tifm_core.o
  obj-$(CONFIG_TIFM_7XX1)               += tifm_7xx1.o
@@@ -15,4 -14,5 +15,5 @@@ obj-$(CONFIG_PHANTOM)         += phantom.
  obj-$(CONFIG_SGI_IOC4)                += ioc4.o
  obj-$(CONFIG_SONY_LAPTOP)     += sony-laptop.o
  obj-$(CONFIG_THINKPAD_ACPI)   += thinkpad_acpi.o
+ obj-$(CONFIG_FUJITSU_LAPTOP)  += fujitsu-laptop.o
  obj-$(CONFIG_EEPROM_93CX6)    += eeprom_93cx6.o
index 86da96becd28101118d619d56cbe93b290005b8c,f248080828f295023c53eac391502b6153c55261..1bfbb87e5793a7585271c580bc0abc2f0db06bb7
@@@ -411,9 -411,9 +411,9 @@@ static int sony_laptop_setup_input(void
        jog_dev->id.bustype = BUS_ISA;
        jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
  
 -      jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 -      jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
 -      jog_dev->relbit[0] = BIT(REL_WHEEL);
 +      jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
 +      jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
 +      jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
  
        error = input_register_device(jog_dev);
        if (error)
@@@ -807,7 -807,7 +807,7 @@@ static struct sony_nc_event *sony_nc_ev
  /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
   * for Fn keys
   */
 -static int sony_nc_C_enable(struct dmi_system_id *id)
 +static int sony_nc_C_enable(const struct dmi_system_id *id)
  {
        int result = 0;
  
@@@ -845,7 -845,7 +845,7 @@@ static struct sony_nc_event sony_C_even
  };
  
  /* SNC-only model map */
 -static struct dmi_system_id sony_nc_ids[] = {
 +static const struct dmi_system_id sony_nc_ids[] = {
                {
                        .ident = "Sony Vaio FE Series",
                        .callback = sony_nc_C_enable,
@@@ -1173,7 -1173,8 +1173,8 @@@ static struct acpi_driver sony_nc_drive
  #define SONYPI_TYPE3_OFFSET   0x12
  
  struct sony_pic_ioport {
-       struct acpi_resource_io io;
+       struct acpi_resource_io io1;
+       struct acpi_resource_io io2;
        struct list_head        list;
  };
  
@@@ -1443,11 -1444,11 +1444,11 @@@ static u8 sony_pic_call1(u8 dev
  {
        u8 v1, v2;
  
-       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+       wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
                        ITERATIONS_LONG);
-       outb(dev, spic_dev.cur_ioport->io.minimum + 4);
-       v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
-       v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+       outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+       v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
+       v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
        dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
        return v2;
  }
@@@ -1456,13 -1457,13 +1457,13 @@@ static u8 sony_pic_call2(u8 dev, u8 fn
  {
        u8 v1;
  
-       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+       wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
                        ITERATIONS_LONG);
-       outb(dev, spic_dev.cur_ioport->io.minimum + 4);
-       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+       outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
                        ITERATIONS_LONG);
-       outb(fn, spic_dev.cur_ioport->io.minimum);
-       v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+       outb(fn, spic_dev.cur_ioport->io1.minimum);
+       v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
        dprintk("sony_pic_call2: 0x%.4x\n", v1);
        return v1;
  }
@@@ -1471,13 -1472,13 +1472,13 @@@ static u8 sony_pic_call3(u8 dev, u8 fn
  {
        u8 v1;
  
-       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
-       outb(dev, spic_dev.cur_ioport->io.minimum + 4);
-       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
-       outb(fn, spic_dev.cur_ioport->io.minimum);
-       wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
-       outb(v, spic_dev.cur_ioport->io.minimum);
-       v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+       outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+       outb(fn, spic_dev.cur_ioport->io1.minimum);
+       wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+       outb(v, spic_dev.cur_ioport->io1.minimum);
+       v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
        dprintk("sony_pic_call3: 0x%.4x\n", v1);
        return v1;
  }
@@@ -2074,7 -2075,18 +2075,18 @@@ sony_pic_read_possible_resource(struct 
  
        switch (resource->type) {
        case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+               {
+                       /* start IO enumeration */
+                       struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+                       if (!ioport)
+                               return AE_ERROR;
+                       list_add(&ioport->list, &dev->ioports);
+                       return AE_OK;
+               }
        case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+               /* end IO enumeration */
                return AE_OK;
  
        case ACPI_RESOURCE_TYPE_IRQ:
                                if (!interrupt)
                                        return AE_ERROR;
  
-                               list_add_tail(&interrupt->list, &dev->interrupts);
+                               list_add(&interrupt->list, &dev->interrupts);
                                interrupt->irq.triggering = p->triggering;
                                interrupt->irq.polarity = p->polarity;
                                interrupt->irq.sharable = p->sharable;
        case ACPI_RESOURCE_TYPE_IO:
                {
                        struct acpi_resource_io *io = &resource->data.io;
-                       struct sony_pic_ioport *ioport = NULL;
+                       struct sony_pic_ioport *ioport =
+                               list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
                        if (!io) {
                                dprintk("Blank IO resource\n");
                                return AE_OK;
                        }
  
-                       ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
-                       if (!ioport)
+                       if (!ioport->io1.minimum) {
+                               memcpy(&ioport->io1, io, sizeof(*io));
+                               dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
+                                               ioport->io1.address_length);
+                       }
+                       else if (!ioport->io2.minimum) {
+                               memcpy(&ioport->io2, io, sizeof(*io));
+                               dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
+                                               ioport->io2.address_length);
+                       }
+                       else {
+                               printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
                                return AE_ERROR;
-                       list_add_tail(&ioport->list, &dev->ioports);
-                       memcpy(&ioport->io, io, sizeof(*io));
+                       }
                        return AE_OK;
                }
        default:
@@@ -2199,10 -2220,22 +2220,22 @@@ static int sony_pic_enable(struct acpi_
  {
        acpi_status status;
        int result = 0;
+       /* Type 1 resource layout is:
+        *    IO
+        *    IO
+        *    IRQNoFlags
+        *    End
+        *
+        * Type 2 and 3 resource layout is:
+        *    IO
+        *    IRQNoFlags
+        *    End
+        */
        struct {
-               struct acpi_resource io_res;
-               struct acpi_resource irq_res;
-               struct acpi_resource end;
+               struct acpi_resource res1;
+               struct acpi_resource res2;
+               struct acpi_resource res3;
+               struct acpi_resource res4;
        } *resource;
        struct acpi_buffer buffer = { 0, NULL };
  
        buffer.length = sizeof(*resource) + 1;
        buffer.pointer = resource;
  
-       /* setup io resource */
-       resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
-       resource->io_res.length = sizeof(struct acpi_resource);
-       memcpy(&resource->io_res.data.io, &ioport->io,
-                       sizeof(struct acpi_resource_io));
+       /* setup Type 1 resources */
+       if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
  
-       /* setup irq resource */
-       resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
-       resource->irq_res.length = sizeof(struct acpi_resource);
-       memcpy(&resource->irq_res.data.irq, &irq->irq,
-                       sizeof(struct acpi_resource_irq));
-       /* we requested a shared irq */
-       resource->irq_res.data.irq.sharable = ACPI_SHARED;
+               /* setup io resources */
+               resource->res1.type = ACPI_RESOURCE_TYPE_IO;
+               resource->res1.length = sizeof(struct acpi_resource);
+               memcpy(&resource->res1.data.io, &ioport->io1,
+                               sizeof(struct acpi_resource_io));
  
-       resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+               resource->res2.type = ACPI_RESOURCE_TYPE_IO;
+               resource->res2.length = sizeof(struct acpi_resource);
+               memcpy(&resource->res2.data.io, &ioport->io2,
+                               sizeof(struct acpi_resource_io));
+               /* setup irq resource */
+               resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
+               resource->res3.length = sizeof(struct acpi_resource);
+               memcpy(&resource->res3.data.irq, &irq->irq,
+                               sizeof(struct acpi_resource_irq));
+               /* we requested a shared irq */
+               resource->res3.data.irq.sharable = ACPI_SHARED;
+               resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
+       }
+       /* setup Type 2/3 resources */
+       else {
+               /* setup io resource */
+               resource->res1.type = ACPI_RESOURCE_TYPE_IO;
+               resource->res1.length = sizeof(struct acpi_resource);
+               memcpy(&resource->res1.data.io, &ioport->io1,
+                               sizeof(struct acpi_resource_io));
+               /* setup irq resource */
+               resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
+               resource->res2.length = sizeof(struct acpi_resource);
+               memcpy(&resource->res2.data.irq, &irq->irq,
+                               sizeof(struct acpi_resource_irq));
+               /* we requested a shared irq */
+               resource->res2.data.irq.sharable = ACPI_SHARED;
+               resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
+       }
  
        /* Attempt to set the resource */
        dprintk("Evaluating _SRS\n");
  
        /* check for total failure */
        if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+               printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
                result = -ENODEV;
                goto end;
        }
@@@ -2268,11 -2329,14 +2329,14 @@@ static irqreturn_t sony_pic_irq(int irq
  
        struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
  
-       ev = inb_p(dev->cur_ioport->io.minimum);
-       data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
+       ev = inb_p(dev->cur_ioport->io1.minimum);
+       if (dev->cur_ioport->io2.minimum)
+               data_mask = inb_p(dev->cur_ioport->io2.minimum);
+       else
+               data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);
  
        dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
-                       ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
+                       ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);
  
        if (ev == 0x00 || ev == 0xff)
                return IRQ_HANDLED;
@@@ -2323,8 -2387,11 +2387,11 @@@ static int sony_pic_remove(struct acpi_
        }
  
        free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
-       release_region(spic_dev.cur_ioport->io.minimum,
-                       spic_dev.cur_ioport->io.address_length);
+       release_region(spic_dev.cur_ioport->io1.minimum,
+                       spic_dev.cur_ioport->io1.address_length);
+       if (spic_dev.cur_ioport->io2.minimum)
+               release_region(spic_dev.cur_ioport->io2.minimum,
+                               spic_dev.cur_ioport->io2.address_length);
  
        sonypi_compat_exit();
  
@@@ -2397,14 -2464,36 +2464,36 @@@ static int sony_pic_add(struct acpi_dev
                goto err_remove_input;
  
        /* request io port */
-       list_for_each_entry(io, &spic_dev.ioports, list) {
-               if (request_region(io->io.minimum, io->io.address_length,
+       list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
+               if (request_region(io->io1.minimum, io->io1.address_length,
                                        "Sony Programable I/O Device")) {
-                       dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
-                                       io->io.minimum, io->io.maximum,
-                                       io->io.address_length);
-                       spic_dev.cur_ioport = io;
-                       break;
+                       dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
+                                       io->io1.minimum, io->io1.maximum,
+                                       io->io1.address_length);
+                       /* Type 1 have 2 ioports */
+                       if (io->io2.minimum) {
+                               if (request_region(io->io2.minimum,
+                                               io->io2.address_length,
+                                               "Sony Programable I/O Device")) {
+                                       dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
+                                                       io->io2.minimum, io->io2.maximum,
+                                                       io->io2.address_length);
+                                       spic_dev.cur_ioport = io;
+                                       break;
+                               }
+                               else {
+                                       dprintk("Unable to get I/O port2: "
+                                                       "0x%.4x (0x%.4x) + 0x%.2x\n",
+                                                       io->io2.minimum, io->io2.maximum,
+                                                       io->io2.address_length);
+                                       release_region(io->io1.minimum,
+                                                       io->io1.address_length);
+                               }
+                       }
+                       else {
+                               spic_dev.cur_ioport = io;
+                               break;
+                       }
                }
        }
        if (!spic_dev.cur_ioport) {
        }
  
        /* request IRQ */
-       list_for_each_entry(irq, &spic_dev.interrupts, list) {
+       list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
                if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
                                        IRQF_SHARED, "sony-laptop", &spic_dev)) {
                        dprintk("IRQ: %d - triggering: %d - "
@@@ -2462,8 -2551,11 +2551,11 @@@ err_free_irq
        free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
  
  err_release_region:
-       release_region(spic_dev.cur_ioport->io.minimum,
-                       spic_dev.cur_ioport->io.address_length);
+       release_region(spic_dev.cur_ioport->io1.minimum,
+                       spic_dev.cur_ioport->io1.address_length);
+       if (spic_dev.cur_ioport->io2.minimum)
+               release_region(spic_dev.cur_ioport->io2.minimum,
+                               spic_dev.cur_ioport->io2.address_length);
  
  err_remove_compat:
        sonypi_compat_exit();
index 81e068fa7ac5f33c6466b28e66770dc72ff7a920,37891a8c030a229cb18deba84038f4c55af966d7..e953276664a0f77aef6a0a997452488d75a294c3
@@@ -22,7 -22,7 +22,7 @@@
   */
  
  #define IBM_VERSION "0.16"
- #define TPACPI_SYSFS_VERSION 0x010000
+ #define TPACPI_SYSFS_VERSION 0x020000
  
  /*
   *  Changelog:
@@@ -117,6 -117,12 +117,12 @@@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]")
  
  #define __unused __attribute__ ((unused))
  
+ static enum {
+       TPACPI_LIFE_INIT = 0,
+       TPACPI_LIFE_RUNNING,
+       TPACPI_LIFE_EXITING,
+ } tpacpi_lifecycle;
  /****************************************************************************
   ****************************************************************************
   *
@@@ -342,6 -348,9 +348,9 @@@ static void dispatch_acpi_notify(acpi_h
  {
        struct ibm_struct *ibm = data;
  
+       if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+               return;
        if (!ibm || !ibm->acpi || !ibm->acpi->notify)
                return;
  
@@@ -517,8 -526,10 +526,10 @@@ static char *next_cmd(char **cmds
   ****************************************************************************/
  
  static struct platform_device *tpacpi_pdev;
 -static struct class_device *tpacpi_hwmon;
+ static struct platform_device *tpacpi_sensors_pdev;
 +static struct device *tpacpi_hwmon;
  static struct input_dev *tpacpi_inputdev;
+ static struct mutex tpacpi_inputdev_send_mutex;
  
  
  static int tpacpi_resume_handler(struct platform_device *pdev)
@@@ -543,6 -554,12 +554,12 @@@ static struct platform_driver tpacpi_pd
        .resume = tpacpi_resume_handler,
  };
  
+ static struct platform_driver tpacpi_hwmon_pdriver = {
+       .driver = {
+               .name = IBM_HWMON_DRVR_NAME,
+               .owner = THIS_MODULE,
+       },
+ };
  
  /*************************************************************************
   * thinkpad-acpi driver attributes
@@@ -692,6 -709,8 +709,8 @@@ static int parse_strtoul(const char *bu
  {
        char *endp;
  
+       while (*buf && isspace(*buf))
+               buf++;
        *value = simple_strtoul(buf, &endp, 0);
        while (*endp && isspace(*endp))
                endp++;
@@@ -945,15 -964,15 +964,15 @@@ static int __init hotkey_init(struct ib
                KEY_UNKNOWN,    /* 0x0C: FN+BACKSPACE */
                KEY_UNKNOWN,    /* 0x0D: FN+INSERT */
                KEY_UNKNOWN,    /* 0x0E: FN+DELETE */
 -              KEY_RESERVED,   /* 0x0F: FN+HOME (brightness up) */
 +              KEY_BRIGHTNESSUP,       /* 0x0F: FN+HOME (brightness up) */
                /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
 -              KEY_RESERVED,   /* 0x10: FN+END (brightness down) */
 +              KEY_BRIGHTNESSDOWN,     /* 0x10: FN+END (brightness down) */
                KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
                KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
                KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
 -              KEY_RESERVED,   /* 0x14: VOLUME UP */
 -              KEY_RESERVED,   /* 0x15: VOLUME DOWN */
 -              KEY_RESERVED,   /* 0x16: MUTE */
 +              KEY_VOLUMEUP,   /* 0x14: VOLUME UP */
 +              KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
 +              KEY_MUTE,       /* 0x16: MUTE */
                KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_RESERVED,   /* 0x11: FN+PGUP (thinklight toggle) */
                KEY_UNKNOWN,    /* 0x12: FN+PGDOWN */
                KEY_ZOOM,       /* 0x13: FN+SPACE (zoom) */
 -              KEY_RESERVED,   /* 0x14: VOLUME UP */
 -              KEY_RESERVED,   /* 0x15: VOLUME DOWN */
 -              KEY_RESERVED,   /* 0x16: MUTE */
 +              KEY_VOLUMEUP,   /* 0x14: VOLUME UP */
 +              KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
 +              KEY_MUTE,       /* 0x16: MUTE */
                KEY_VENDOR,     /* 0x17: Thinkpad/AccessIBM/Lenovo */
                /* (assignments unknown, please report if found) */
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
  
        int res, i;
        int status;
+       int hkeyv;
  
        vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
  
                        return res;
  
                /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
-                  A30, R30, R31, T20-22, X20-21, X22-24 */
-               tp_features.hotkey_mask =
-                       acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+                  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(IBM_ERR "unknown version of the "
+                                      "HKEY interface: 0x%x\n", hkeyv);
+                               printk(IBM_ERR "please report this to %s\n",
+                                      IBM_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));
  
                if (tp_features.hotkey_mask) {
-                       /* MHKA available in A31, R40, R40e, T4x, X31, and later */
                        if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
-                                       "MHKA", "qd"))
+                                       "MHKA", "qd")) {
+                               printk(IBM_ERR
+                                      "missing MHKA handler, "
+                                      "please report this to %s\n",
+                                      IBM_MAIL);
                                hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+                       }
                }
  
                res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
@@@ -1131,6 -1168,8 +1168,8 @@@ static void tpacpi_input_send_key(unsig
                                  unsigned int keycode)
  {
        if (keycode != KEY_RESERVED) {
+               mutex_lock(&tpacpi_inputdev_send_mutex);
                input_report_key(tpacpi_inputdev, keycode, 1);
                if (keycode == KEY_UNKNOWN)
                        input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
                        input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
                                    scancode);
                input_sync(tpacpi_inputdev);
+               mutex_unlock(&tpacpi_inputdev_send_mutex);
        }
  }
  
@@@ -1149,18 -1190,47 +1190,47 @@@ static void tpacpi_input_send_radiosw(v
  {
        int wlsw;
  
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+       mutex_lock(&tpacpi_inputdev_send_mutex);
+       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
                input_report_switch(tpacpi_inputdev,
                                    SW_RADIO, !!wlsw);
+               input_sync(tpacpi_inputdev);
+       }
+       mutex_unlock(&tpacpi_inputdev_send_mutex);
  }
  
  static void hotkey_notify(struct ibm_struct *ibm, u32 event)
  {
        u32 hkey;
        unsigned int keycode, scancode;
-       int send_acpi_ev = 0;
+       int send_acpi_ev;
+       int ignore_acpi_ev;
+       if (event != 0x80) {
+               printk(IBM_ERR "unknown HKEY notification event %d\n", 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,
+                                               event, 0);
+               return;
+       }
+       while (1) {
+               if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+                       printk(IBM_ERR "failed to retrieve HKEY event\n");
+                       return;
+               }
+               if (hkey == 0) {
+                       /* queue empty */
+                       return;
+               }
+               send_acpi_ev = 0;
+               ignore_acpi_ev = 0;
  
-       if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
                switch (hkey >> 12) {
                case 1:
                        /* 0x1000-0x1FFF: key presses */
                         * eat up known LID events */
                        if (hkey != 0x5001 && hkey != 0x5002) {
                                printk(IBM_ERR
-                                       "unknown LID-related hotkey event: 0x%04x\n",
-                                       hkey);
+                                      "unknown LID-related HKEY event: 0x%04x\n",
+                                      hkey);
                                send_acpi_ev = 1;
+                       } else {
+                               ignore_acpi_ev = 1;
                        }
                        break;
                case 7:
                        printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
                        send_acpi_ev = 1;
                }
-       } else {
-               printk(IBM_ERR "unknown hotkey notification event %d\n", event);
-               hkey = 0;
-               send_acpi_ev = 1;
-       }
  
-       /* Legacy events */
-       if (send_acpi_ev || hotkey_report_mode < 2)
-               acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+               /* Legacy events */
+               if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) {
+                       acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+               }
  
-       /* netlink events */
-       if (send_acpi_ev) {
-               acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
-                                               ibm->acpi->device->dev.bus_id,
-                                               event, hkey);
+               /* netlink events */
+               if (!ignore_acpi_ev && send_acpi_ev) {
+                       acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+                                                       ibm->acpi->device->dev.bus_id,
+                                                       event, hkey);
+               }
        }
  }
  
@@@ -2812,7 -2881,7 +2881,7 @@@ static int __init thermal_init(struct i
  
        switch(thermal_read_mode) {
        case TPACPI_THERMAL_TPEC_16:
-               res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+               res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
                                &thermal_temp_input16_group);
                if (res)
                        return res;
        case TPACPI_THERMAL_TPEC_8:
        case TPACPI_THERMAL_ACPI_TMP07:
        case TPACPI_THERMAL_ACPI_UPDT:
-               res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+               res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
                                &thermal_temp_input8_group);
                if (res)
                        return res;
@@@ -2837,13 -2906,13 +2906,13 @@@ static void thermal_exit(void
  {
        switch(thermal_read_mode) {
        case TPACPI_THERMAL_TPEC_16:
-               sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+               sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
                                   &thermal_temp_input16_group);
                break;
        case TPACPI_THERMAL_TPEC_8:
        case TPACPI_THERMAL_ACPI_TMP07:
        case TPACPI_THERMAL_ACPI_UPDT:
-               sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+               sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
                                   &thermal_temp_input16_group);
                break;
        case TPACPI_THERMAL_NONE:
@@@ -3626,7 -3695,7 +3695,7 @@@ static struct device_attribute dev_attr
        __ATTR(fan1_input, S_IRUGO,
                fan_fan1_input_show, NULL);
  
- /* sysfs fan fan_watchdog (driver) ------------------------------------- */
+ /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
  static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
                                     char *buf)
  {
@@@ -3768,10 -3837,10 +3837,10 @@@ static int __init fan_init(struct ibm_i
  
        if (fan_status_access_mode != TPACPI_FAN_NONE ||
            fan_control_access_mode != TPACPI_FAN_WR_NONE) {
-               rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+               rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
                                         &fan_attr_group);
                if (!(rc < 0))
-                       rc = driver_create_file(&tpacpi_pdriver.driver,
+                       rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
                                        &driver_attr_fan_watchdog);
                if (rc < 0)
                        return rc;
@@@ -3854,8 -3923,8 +3923,8 @@@ static void fan_exit(void
        vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
  
        /* FIXME: can we really do this unconditionally? */
-       sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
-       driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+       sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
+       driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog);
  
        cancel_delayed_work(&fan_watchdog_task);
        flush_scheduled_work();
@@@ -3888,6 -3957,9 +3957,9 @@@ static void fan_watchdog_fire(struct wo
  {
        int rc;
  
+       if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+               return;
        printk(IBM_NOTICE "fan watchdog: enabling fan\n");
        rc = fan_set_enable();
        if (rc < 0) {
@@@ -3908,7 -3980,8 +3980,8 @@@ static void fan_watchdog_reset(void
        if (fan_watchdog_active)
                cancel_delayed_work(&fan_watchdog_task);
  
-       if (fan_watchdog_maxinterval > 0) {
+       if (fan_watchdog_maxinterval > 0 &&
+           tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
                fan_watchdog_active = 1;
                if (!schedule_delayed_work(&fan_watchdog_task,
                                msecs_to_jiffies(fan_watchdog_maxinterval
@@@ -4302,6 -4375,19 +4375,19 @@@ static struct ibm_struct fan_driver_dat
   ****************************************************************************
   ****************************************************************************/
  
+ /* sysfs name ---------------------------------------------------------- */
+ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
+                          struct device_attribute *attr,
+                          char *buf)
+ {
+       return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME);
+ }
+ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
+       __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL);
+ /* --------------------------------------------------------------------- */
  /* /proc support */
  static struct proc_dir_entry *proc_dir;
  
@@@ -4448,7 -4534,7 +4534,7 @@@ static void ibm_exit(struct ibm_struct 
  
  static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
  {
 -      struct dmi_device *dev = NULL;
 +      const struct dmi_device *dev = NULL;
        char ec_fw_string[18];
  
        if (!tp)
@@@ -4674,6 -4760,8 +4760,8 @@@ static int __init thinkpad_acpi_module_
  {
        int ret, i;
  
+       tpacpi_lifecycle = TPACPI_LIFE_INIT;
        /* Parameter checking */
        if (hotkey_report_mode > 2)
                return -EINVAL;
  
        ret = platform_driver_register(&tpacpi_pdriver);
        if (ret) {
-               printk(IBM_ERR "unable to register platform driver\n");
+               printk(IBM_ERR "unable to register main platform driver\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
        tp_features.platform_drv_registered = 1;
  
+       ret = platform_driver_register(&tpacpi_hwmon_pdriver);
+       if (ret) {
+               printk(IBM_ERR "unable to register hwmon platform driver\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+       tp_features.sensors_pdrv_registered = 1;
        ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+       if (!ret) {
+               tp_features.platform_drv_attrs_registered = 1;
+               ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver);
+       }
        if (ret) {
                printk(IBM_ERR "unable to create sysfs driver attributes\n");
                thinkpad_acpi_module_exit();
                return ret;
        }
-       tp_features.platform_drv_attrs_registered = 1;
+       tp_features.sensors_pdrv_attrs_registered = 1;
  
  
        /* Device initialization */
                thinkpad_acpi_module_exit();
                return ret;
        }
-       tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+       tpacpi_sensors_pdev = platform_device_register_simple(
+                                                       IBM_HWMON_DRVR_NAME,
+                                                       -1, NULL, 0);
+       if (IS_ERR(tpacpi_sensors_pdev)) {
+               ret = PTR_ERR(tpacpi_sensors_pdev);
+               tpacpi_sensors_pdev = NULL;
+               printk(IBM_ERR "unable to register hwmon platform device\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+       ret = device_create_file(&tpacpi_sensors_pdev->dev,
+                                &dev_attr_thinkpad_acpi_pdev_name);
+       if (ret) {
+               printk(IBM_ERR
+                       "unable to create sysfs hwmon device attributes\n");
+               thinkpad_acpi_module_exit();
+               return ret;
+       }
+       tp_features.sensors_pdev_attrs_registered = 1;
+       tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev);
        if (IS_ERR(tpacpi_hwmon)) {
                ret = PTR_ERR(tpacpi_hwmon);
                tpacpi_hwmon = NULL;
                thinkpad_acpi_module_exit();
                return ret;
        }
+       mutex_init(&tpacpi_inputdev_send_mutex);
        tpacpi_inputdev = input_allocate_device();
        if (!tpacpi_inputdev) {
                printk(IBM_ERR "unable to allocate input device\n");
                tp_features.input_device_registered = 1;
        }
  
+       tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
        return 0;
  }
  
@@@ -4776,6 -4897,8 +4897,8 @@@ static void thinkpad_acpi_module_exit(v
  {
        struct ibm_struct *ibm, *itmp;
  
+       tpacpi_lifecycle = TPACPI_LIFE_EXITING;
        list_for_each_entry_safe_reverse(ibm, itmp,
                                         &tpacpi_all_drivers,
                                         all_drivers) {
        if (tpacpi_hwmon)
                hwmon_device_unregister(tpacpi_hwmon);
  
+       if (tp_features.sensors_pdev_attrs_registered)
+               device_remove_file(&tpacpi_sensors_pdev->dev,
+                                  &dev_attr_thinkpad_acpi_pdev_name);
+       if (tpacpi_sensors_pdev)
+               platform_device_unregister(tpacpi_sensors_pdev);
        if (tpacpi_pdev)
                platform_device_unregister(tpacpi_pdev);
  
+       if (tp_features.sensors_pdrv_attrs_registered)
+               tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
        if (tp_features.platform_drv_attrs_registered)
                tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
  
+       if (tp_features.sensors_pdrv_registered)
+               platform_driver_unregister(&tpacpi_hwmon_pdriver);
        if (tp_features.platform_drv_registered)
                platform_driver_unregister(&tpacpi_pdriver);
  
index acd5835ec889b2181011a28a60206421a4f55e7e,c5fdd688cc990c3752e451df5de403797c4f4103..3abcc812063433e664a23df7d5275918d6906351
  
  #define IBM_NAME "thinkpad"
  #define IBM_DESC "ThinkPad ACPI Extras"
- #define IBM_FILE "thinkpad_acpi"
+ #define IBM_FILE IBM_NAME "_acpi"
  #define IBM_URL "http://ibm-acpi.sf.net/"
  #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
  
  #define IBM_PROC_DIR "ibm"
  #define IBM_ACPI_EVENT_PREFIX "ibm"
  #define IBM_DRVR_NAME IBM_FILE
+ #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
  
  #define IBM_LOG IBM_FILE ": "
  #define IBM_ERR          KERN_ERR    IBM_LOG
@@@ -171,7 -172,8 +172,8 @@@ static int parse_strtoul(const char *bu
  
  /* Device model */
  static struct platform_device *tpacpi_pdev;
 -static struct class_device *tpacpi_hwmon;
+ static struct platform_device *tpacpi_sensors_pdev;
 +static struct device *tpacpi_hwmon;
  static struct platform_driver tpacpi_pdriver;
  static struct input_dev *tpacpi_inputdev;
  static int tpacpi_create_driver_attributes(struct device_driver *drv);
@@@ -233,22 -235,25 +235,25 @@@ struct ibm_init_struct 
  
  static struct {
  #ifdef CONFIG_THINKPAD_ACPI_BAY
-       u16 bay_status:1;
-       u16 bay_eject:1;
-       u16 bay_status2:1;
-       u16 bay_eject2:1;
+       u32 bay_status:1;
+       u32 bay_eject:1;
+       u32 bay_status2:1;
+       u32 bay_eject2:1;
  #endif
-       u16 bluetooth:1;
-       u16 hotkey:1;
-       u16 hotkey_mask:1;
-       u16 hotkey_wlsw:1;
-       u16 light:1;
-       u16 light_status:1;
-       u16 wan:1;
-       u16 fan_ctrl_status_undef:1;
-       u16 input_device_registered:1;
-       u16 platform_drv_registered:1;
-       u16 platform_drv_attrs_registered:1;
+       u32 bluetooth:1;
+       u32 hotkey:1;
+       u32 hotkey_mask:1;
+       u32 hotkey_wlsw:1;
+       u32 light:1;
+       u32 light_status:1;
+       u32 wan:1;
+       u32 fan_ctrl_status_undef:1;
+       u32 input_device_registered:1;
+       u32 platform_drv_registered:1;
+       u32 platform_drv_attrs_registered:1;
+       u32 sensors_pdrv_registered:1;
+       u32 sensors_pdrv_attrs_registered:1;
+       u32 sensors_pdev_attrs_registered:1;
  } tp_features;
  
  struct thinkpad_id_data {
index 2d46a16c09450c73d3ea5121af6f17391eca2fee,e8a94b7462950307180459fe23c971199f45bad4..c144e3cdb890f9ef9d7210d93b1dce3064aa48ed
@@@ -1858,14 -1858,6 +1858,6 @@@ static void ipw2100_down(struct ipw2100
  
        modify_acceptable_latency("ipw2100", INFINITE_LATENCY);
  
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
-       if (priv->config & CFG_C3_DISABLED) {
-               IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
-               acpi_set_cstate_limit(priv->cstate_limit);
-               priv->config &= ~CFG_C3_DISABLED;
-       }
- #endif
        /* We have to signal any supplicant if we are disassociating */
        if (associated)
                wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
@@@ -1922,7 -1914,6 +1914,7 @@@ static void isr_indicate_associated(str
        u32 chan;
        char *txratename;
        u8 bssid[ETH_ALEN];
 +      DECLARE_MAC_BUF(mac);
  
        /*
         * TBD: BSSID is usually 00:00:00:00:00:00 here and not
        }
  
        IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
 -                     MAC_FMT ")\n",
 +                     "%s)\n",
                       priv->net_dev->name, escape_essid(essid, essid_len),
 -                     txratename, chan, MAC_ARG(bssid));
 +                     txratename, chan, print_mac(mac, bssid));
  
        /* now we copy read ssid into dev */
        if (!(priv->config & CFG_STATIC_ESSID)) {
@@@ -2054,12 -2045,10 +2046,12 @@@ static int ipw2100_set_essid(struct ipw
  
  static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
  {
 +      DECLARE_MAC_BUF(mac);
 +
        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
 -                "disassociated: '%s' " MAC_FMT " \n",
 +                "disassociated: '%s' %s \n",
                  escape_essid(priv->essid, priv->essid_len),
 -                MAC_ARG(priv->bssid));
 +                print_mac(mac, priv->bssid));
  
        priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
  
@@@ -2091,14 -2080,6 +2083,6 @@@ static void isr_indicate_rf_kill(struc
        /* RF_KILL is now enabled (else we wouldn't be here) */
        priv->status |= STATUS_RF_KILL_HW;
  
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
-       if (priv->config & CFG_C3_DISABLED) {
-               IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
-               acpi_set_cstate_limit(priv->cstate_limit);
-               priv->config &= ~CFG_C3_DISABLED;
-       }
- #endif
        /* Make sure the RF Kill check timer is running */
        priv->stop_rf_kill = 0;
        cancel_delayed_work(&priv->rf_kill);
@@@ -2329,23 -2310,10 +2313,10 @@@ static void ipw2100_corruption_detected
        u32 match, reg;
        int j;
  #endif
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
-       int limit;
- #endif
  
        IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
                       i * sizeof(struct ipw2100_status));
  
- #ifdef ACPI_CSTATE_LIMIT_DEFINED
-       IPW_DEBUG_INFO(": Disabling C3 transitions.\n");
-       limit = acpi_get_cstate_limit();
-       if (limit > 2) {
-               priv->cstate_limit = limit;
-               acpi_set_cstate_limit(2);
-               priv->config |= CFG_C3_DISABLED;
-       }
- #endif
  #ifdef IPW2100_DEBUG_C3
        /* Halt the fimrware so we can get a good image */
        write_register(priv->net_dev, IPW_REG_RESET_REG,
@@@ -4052,7 -4020,6 +4023,7 @@@ static ssize_t show_bssinfo(struct devi
        char *out = buf;
        int length;
        int ret;
 +      DECLARE_MAC_BUF(mac);
  
        if (priv->status & STATUS_RF_KILL_MASK)
                return 0;
                               __LINE__);
  
        out += sprintf(out, "ESSID: %s\n", essid);
 -      out += sprintf(out, "BSSID:   %02x:%02x:%02x:%02x:%02x:%02x\n",
 -                     bssid[0], bssid[1], bssid[2],
 -                     bssid[3], bssid[4], bssid[5]);
 +      out += sprintf(out, "BSSID:   %s\n", print_mac(mac, bssid));
        out += sprintf(out, "Channel: %d\n", chan);
  
        return out - buf;
@@@ -4654,20 -4623,19 +4625,20 @@@ static void ipw2100_rx_free(struct ipw2
  static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
  {
        u32 length = ETH_ALEN;
 -      u8 mac[ETH_ALEN];
 +      u8 addr[ETH_ALEN];
 +      DECLARE_MAC_BUF(mac);
  
        int err;
  
 -      err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
 +      err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
        if (err) {
                IPW_DEBUG_INFO("MAC address read failed\n");
                return -EIO;
        }
 -      IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
 -                     mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  
 -      memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
 +      memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
 +      IPW_DEBUG_INFO("card MAC is %s\n",
 +                     print_mac(mac, priv->net_dev->dev_addr));
  
        return 0;
  }
@@@ -5046,10 -5014,10 +5017,10 @@@ static int ipw2100_set_mandatory_bssid(
        int err;
  
  #ifdef CONFIG_IPW2100_DEBUG
 +      DECLARE_MAC_BUF(mac);
        if (bssid != NULL)
 -              IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
 -                           bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
 -                           bssid[5]);
 +              IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
 +                           print_mac(mac, bssid));
        else
                IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
  #endif
@@@ -6242,6 -6210,8 +6213,6 @@@ static int ipw2100_pci_init_one(struct 
  
        IPW_DEBUG_INFO("Attempting to register device...\n");
  
 -      SET_MODULE_OWNER(dev);
 -
        printk(KERN_INFO DRV_NAME
               ": Detected Intel PRO/Wireless 2100 Network Connection\n");
  
@@@ -6895,7 -6865,6 +6866,7 @@@ static int ipw2100_wx_set_wap(struct ne
        static const unsigned char off[] = {
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        };
 +      DECLARE_MAC_BUF(mac);
  
        // sanity checks
        if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
  
        err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
  
 -      IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
 -                   wrqu->ap_addr.sa_data[0] & 0xff,
 -                   wrqu->ap_addr.sa_data[1] & 0xff,
 -                   wrqu->ap_addr.sa_data[2] & 0xff,
 -                   wrqu->ap_addr.sa_data[3] & 0xff,
 -                   wrqu->ap_addr.sa_data[4] & 0xff,
 -                   wrqu->ap_addr.sa_data[5] & 0xff);
 +      IPW_DEBUG_WX("SET BSSID -> %s\n",
 +                   print_mac(mac, wrqu->ap_addr.sa_data));
  
        done:
        mutex_unlock(&priv->action_mutex);
@@@ -6938,7 -6912,6 +6909,7 @@@ static int ipw2100_wx_get_wap(struct ne
         */
  
        struct ipw2100_priv *priv = ieee80211_priv(dev);
 +      DECLARE_MAC_BUF(mac);
  
        /* If we are associated, trying to associate, or have a statically
         * configured BSSID then return that; otherwise return ANY */
        } else
                memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
  
 -      IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
 -                   MAC_ARG(wrqu->ap_addr.sa_data));
 +      IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
 +                   print_mac(mac, wrqu->ap_addr.sa_data));
        return 0;
  }
  
@@@ -8277,9 -8250,10 +8248,9 @@@ static struct iw_statistics *ipw2100_wx
  
  static struct iw_handler_def ipw2100_wx_handler_def = {
        .standard = ipw2100_wx_handlers,
 -      .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
 -      .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
 -      .num_private_args = sizeof(ipw2100_private_args) /
 -          sizeof(struct iw_priv_args),
 +      .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
 +      .num_private = ARRAY_SIZE(ipw2100_private_handler),
 +      .num_private_args = ARRAY_SIZE(ipw2100_private_args),
        .private = (iw_handler *) ipw2100_private_handler,
        .private_args = (struct iw_priv_args *)ipw2100_private_args,
        .get_wireless_stats = ipw2100_wx_wireless_stats,
diff --combined kernel/time/tick-sched.c
index ce89ffb474d0cbeba8b2d84af5c3a6c9ae5f7389,637519af61510bdc6e8b07c2657a6d5ffe5d43e0..10a1347597fd394fec309d1ae74663ae2d9ae05c
@@@ -153,6 -153,7 +153,7 @@@ void tick_nohz_stop_sched_tick(void
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags;
        struct tick_sched *ts;
        ktime_t last_update, expires, now, delta;
+       struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
        int cpu;
  
        local_irq_save(flags);
  out:
        ts->next_jiffies = next_jiffies;
        ts->last_jiffies = last_jiffies;
+       ts->sleep_length = ktime_sub(dev->next_event, now);
  end:
        local_irq_restore(flags);
  }
  
+ /**
+  * tick_nohz_get_sleep_length - return the length of the current sleep
+  *
+  * Called from power state control code with interrupts disabled
+  */
+ ktime_t tick_nohz_get_sleep_length(void)
+ {
+       struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
+       return ts->sleep_length;
+ }
+ EXPORT_SYMBOL_GPL(tick_nohz_get_sleep_length);
  /**
   * nohz_restart_sched_tick - restart the idle tick from the idle task
   *
@@@ -570,7 -586,7 +586,7 @@@ void tick_setup_sched_timer(void
        /* Get the next period (per cpu) */
        ts->sched_timer.expires = tick_init_jiffy_update();
        offset = ktime_to_ns(tick_period) >> 1;
 -      do_div(offset, NR_CPUS);
 +      do_div(offset, num_possible_cpus());
        offset *= smp_processor_id();
        ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);