Pull trivial into test branch
authorLen Brown <len.brown@intel.com>
Sat, 14 Oct 2006 06:28:07 +0000 (02:28 -0400)
committerLen Brown <len.brown@intel.com>
Sat, 14 Oct 2006 06:28:07 +0000 (02:28 -0400)
23 files changed:
Documentation/ibm-acpi.txt
MAINTAINERS
arch/i386/kernel/acpi/boot.c
arch/i386/kernel/acpi/cstate.c
arch/i386/kernel/process.c
arch/x86_64/kernel/process.c
drivers/acpi/asus_acpi.c
drivers/acpi/battery.c
drivers/acpi/ec.c
drivers/acpi/events/evmisc.c
drivers/acpi/events/evrgnini.c
drivers/acpi/ibm_acpi.c
drivers/acpi/osl.c
drivers/acpi/processor_idle.c
drivers/acpi/sbs.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/msi-laptop.c [new file with mode: 0644]
include/acpi/pdc_intel.h
include/acpi/processor.h
include/asm-i386/processor.h
include/asm-x86_64/processor.h
include/linux/acpi.h

index 71aa403..e50595b 100644 (file)
@@ -30,9 +30,10 @@ detailed description):
        - ACPI sounds
        - temperature sensors
        - Experimental: embedded controller register dump
-       - Experimental: LCD brightness control
-       - Experimental: volume control
+       - LCD brightness control
+       - Volume control
        - Experimental: fan speed, fan enable/disable
+       - Experimental: WAN enable and disable
 
 A compatibility table by model and feature is maintained on the web
 site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -52,40 +53,7 @@ Installation
 
 If you are compiling this driver as included in the Linux kernel
 sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
-ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes
-how to install this driver when downloaded from the web site.
-
-First, you need to get a kernel with ACPI support up and running.
-Please refer to http://acpi.sourceforge.net/ for help with this
-step. How successful you will be depends a lot on you ThinkPad model,
-the kernel you are using and any additional patches applied. The
-kernel provided with your distribution may not be good enough. I
-needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get
-ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not
-be supported at all.
-
-Assuming you have the basic ACPI support working (e.g. you can see the
-/proc/acpi directory), follow the following steps to install this
-driver:
-
-       - unpack the archive:
-
-               tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y
-
-       - compile the driver:
-
-               make
-
-       - install the module in your kernel modules directory:
-
-               make install
-
-       - load the module:
-
-               modprobe ibm_acpi
-
-After loading the module, check the "dmesg" output for any error messages.
-
+ACPI / IBM ThinkPad Laptop Extras).
 
 Features
 --------
@@ -523,13 +491,8 @@ registers contain the current battery capacity, etc. If you experiment
 with this, do send me your results (including some complete dumps with
 a description of the conditions when they were taken.)
 
-EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness
------------------------------------------------------------------
-
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+LCD brightness control -- /proc/acpi/ibm/brightness
+---------------------------------------------------
 
 This feature allows software control of the LCD brightness on ThinkPad
 models which don't have a hardware brightness slider. The available
@@ -542,13 +505,8 @@ commands are:
 The <level> number range is 0 to 7, although not all of them may be
 distinct. The current brightness level is shown in the file.
 
-EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume
------------------------------------------------------
-
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+Volume control -- /proc/acpi/ibm/volume
+---------------------------------------
 
 This feature allows volume control on ThinkPad models which don't have
 a hardware volume knob. The available commands are:
@@ -611,6 +569,23 @@ with the following command:
 
        echo 'level <level>' > /proc/acpi/ibm/thermal
 
+EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
+---------------------------------------
+
+This feature is marked EXPERIMENTAL because the implementation
+directly accesses hardware registers and may not work as expected. USE
+WITH CAUTION! To use this feature, you need to supply the
+experimental=1 parameter when loading the module.
+
+This feature shows the presence and current state of a WAN (Sierra
+Wireless EV-DO) device. If WAN is installed, the following commands can
+be used:
+
+       echo enable > /proc/acpi/ibm/wan
+       echo disable > /proc/acpi/ibm/wan
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
 
 Multiple Commands, Module Parameters
 ------------------------------------
index 1b5430a..a2b6d9f 100644 (file)
@@ -1998,6 +1998,13 @@ M:       rubini@ipvvis.unipv.it
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+MSI LAPTOP SUPPORT
+P:     Lennart Poettering
+M:     mzxreary@0pointer.de
+L:     https://tango.0pointer.de/mailman/listinfo/s270-linux
+W:     http://0pointer.de/lennart/tchibo.html
+S:     Maintained
+
 MTRR AND SIMILAR SUPPORT [i386]
 P:     Richard Gooch
 M:     rgooch@atnf.csiro.au
index 92f79cd..ab974ff 100644 (file)
@@ -332,7 +332,7 @@ acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
 /*
  * Parse Interrupt Source Override for the ACPI SCI
  */
-static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
+static void acpi_sci_ioapic_setup(u32 bus_irq, u32 gsi, u16 polarity, u16 trigger)
 {
        if (trigger == 0)       /* compatible SCI trigger is level */
                trigger = 3;
@@ -352,13 +352,13 @@ static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
         * If GSI is < 16, this will update its flags,
         * else it will create a new mp_irqs[] entry.
         */
-       mp_override_legacy_irq(gsi, polarity, trigger, gsi);
+       mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
 
        /*
         * stash over-ride to indicate we've been here
         * and for later update of acpi_fadt
         */
-       acpi_sci_override_gsi = gsi;
+       acpi_sci_override_gsi = bus_irq;
        return;
 }
 
@@ -376,7 +376,7 @@ acpi_parse_int_src_ovr(acpi_table_entry_header * header,
        acpi_table_print_madt_entry(header);
 
        if (intsrc->bus_irq == acpi_fadt.sci_int) {
-               acpi_sci_ioapic_setup(intsrc->global_irq,
+               acpi_sci_ioapic_setup(intsrc->bus_irq, intsrc->global_irq,
                                      intsrc->flags.polarity,
                                      intsrc->flags.trigger);
                return 0;
@@ -879,7 +879,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
         * pretend we got one so we can set the SCI flags.
         */
        if (!acpi_sci_override_gsi)
-               acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
+               acpi_sci_ioapic_setup(acpi_fadt.sci_int, acpi_fadt.sci_int, 0, 0);
 
        /* Fill in identity legacy mapings where no override */
        mp_config_acpi_legacy_irqs();
index 25db49e..20563e5 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
+#include <linux/cpu.h>
 
 #include <acpi/processor.h>
 #include <asm/acpi.h>
@@ -41,5 +42,124 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
                flags->bm_check = 1;
        }
 }
-
 EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
+
+/* The code below handles cstate entry with monitor-mwait pair on Intel*/
+
+struct cstate_entry_s {
+       struct {
+               unsigned int eax;
+               unsigned int ecx;
+       } states[ACPI_PROCESSOR_MAX_POWER];
+};
+static struct cstate_entry_s *cpu_cstate_entry;        /* per CPU ptr */
+
+static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
+
+#define MWAIT_SUBSTATE_MASK    (0xf)
+#define MWAIT_SUBSTATE_SIZE    (4)
+
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
+
+#define MWAIT_ECX_INTERRUPT_BREAK      (0x1)
+
+#define NATIVE_CSTATE_BEYOND_HALT      (2)
+
+int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+               struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+{
+       struct cstate_entry_s *percpu_entry;
+       struct cpuinfo_x86 *c = cpu_data + cpu;
+
+       cpumask_t saved_mask;
+       int retval;
+       unsigned int eax, ebx, ecx, edx;
+       unsigned int edx_part;
+       unsigned int cstate_type; /* C-state type and not ACPI C-state type */
+       unsigned int num_cstate_subtype;
+
+       if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF )
+               return -1;
+
+       if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT)
+               return -1;
+
+       percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+       percpu_entry->states[cx->index].eax = 0;
+       percpu_entry->states[cx->index].ecx = 0;
+
+       /* Make sure we are running on right CPU */
+       saved_mask = current->cpus_allowed;
+       retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
+       if (retval)
+               return -1;
+
+       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+       /* Check whether this particular cx_type (in CST) is supported or not */
+       cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1;
+       edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
+       num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
+
+       retval = 0;
+       if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
+               retval = -1;
+               goto out;
+       }
+
+       /* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+           !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
+               retval = -1;
+               goto out;
+       }
+       percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
+
+       /* Use the hint in CST */
+       percpu_entry->states[cx->index].eax = cx->address;
+
+       if (!mwait_supported[cstate_type]) {
+               mwait_supported[cstate_type] = 1;
+               printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d "
+                      "state\n", cx->type);
+       }
+
+out:
+       set_cpus_allowed(current, saved_mask);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
+
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
+{
+       unsigned int cpu = smp_processor_id();
+       struct cstate_entry_s *percpu_entry;
+
+       percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+       mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
+                             percpu_entry->states[cx->index].ecx);
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
+
+static int __init ffh_cstate_init(void)
+{
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+       if (c->x86_vendor != X86_VENDOR_INTEL)
+               return -1;
+
+       cpu_cstate_entry = alloc_percpu(struct cstate_entry_s);
+       return 0;
+}
+
+static void __exit ffh_cstate_exit(void)
+{
+       if (cpu_cstate_entry) {
+               free_percpu(cpu_cstate_entry);
+               cpu_cstate_entry = NULL;
+       }
+}
+
+arch_initcall(ffh_cstate_init);
+__exitcall(ffh_cstate_exit);
index b0a0780..57d3759 100644 (file)
@@ -236,20 +236,28 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
  * We execute MONITOR against need_resched and enter optimized wait state
  * through MWAIT. Whenever someone changes need_resched, we would be woken
  * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
  */
-static void mwait_idle(void)
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 {
-       local_irq_enable();
-
-       while (!need_resched()) {
+       if (!need_resched()) {
                __monitor((void *)&current_thread_info()->flags, 0, 0);
                smp_mb();
-               if (need_resched())
-                       break;
-               __mwait(0, 0);
+               if (!need_resched())
+                       __mwait(eax, ecx);
        }
 }
 
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+       local_irq_enable();
+       while (!need_resched())
+               mwait_idle_with_hints(0, 0);
+}
+
 void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
 {
        if (cpu_has(c, X86_FEATURE_MWAIT)) {
index 5e95b25..49f7fac 100644 (file)
@@ -238,20 +238,28 @@ void cpu_idle (void)
  * We execute MONITOR against need_resched and enter optimized wait state
  * through MWAIT. Whenever someone changes need_resched, we would be woken
  * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
  */
-static void mwait_idle(void)
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 {
-       local_irq_enable();
-
-       while (!need_resched()) {
+       if (!need_resched()) {
                __monitor((void *)&current_thread_info()->flags, 0, 0);
                smp_mb();
-               if (need_resched())
-                       break;
-               __mwait(0, 0);
+               if (!need_resched())
+                       __mwait(eax, ecx);
        }
 }
 
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+       local_irq_enable();
+       while (!need_resched())
+               mwait_idle_with_hints(0,0);
+}
+
 void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
 {
        static int printed;
index e9ee4c5..c7ac929 100644 (file)
@@ -138,6 +138,7 @@ struct asus_hotk {
                S2x,            //S200 (J1 reported), Victor MP-XP7210
                W1N,            //W1000N
                W5A,            //W5A
+               W3V,            //W3030V
                xxN,            //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
                //(Centrino)
                END_MODEL
@@ -376,6 +377,17 @@ static struct model_data model_conf[END_MODEL] = {
         .display_get = "\\ADVG"},
 
        {
+        .name = "W3V",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\BKLT",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
         .name = "xxN",
         .mt_mled = "MLED",
 /* WLED present, but not controlled by ACPI */
@@ -555,11 +567,11 @@ static int
 write_led(const char __user * buffer, unsigned long count,
          char *ledname, int ledmask, int invert)
 {
-       int value;
+       int rv, value;
        int led_out = 0;
 
-       count = parse_arg(buffer, count, &value);
-       if (count > 0)
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0)
                led_out = value ? 1 : 0;
 
        hotk->status =
@@ -572,7 +584,7 @@ write_led(const char __user * buffer, unsigned long count,
                printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
                       ledname);
 
-       return count;
+       return rv;
 }
 
 /*
@@ -607,20 +619,18 @@ static int
 proc_write_ledd(struct file *file, const char __user * buffer,
                unsigned long count, void *data)
 {
-       int value;
+       int rv, value;
 
-       count = parse_arg(buffer, count, &value);
-       if (count > 0) {
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0) {
                if (!write_acpi_int
                    (hotk->handle, hotk->methods->mt_ledd, value, NULL))
                        printk(KERN_WARNING
                               "Asus ACPI: LED display write failed\n");
                else
                        hotk->ledd_status = (u32) value;
-       } else if (count < 0)
-               printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
-       return count;
+       }
+       return rv;
 }
 
 /*
@@ -761,12 +771,12 @@ static int
 proc_write_lcd(struct file *file, const char __user * buffer,
               unsigned long count, void *data)
 {
-       int value;
+       int rv, value;
 
-       count = parse_arg(buffer, count, &value);
-       if (count > 0)
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0)
                set_lcd_state(value);
-       return count;
+       return rv;
 }
 
 static int read_brightness(void)
@@ -830,18 +840,15 @@ static int
 proc_write_brn(struct file *file, const char __user * buffer,
               unsigned long count, void *data)
 {
-       int value;
+       int rv, value;
 
-       count = parse_arg(buffer, count, &value);
-       if (count > 0) {
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0) {
                value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
                /* 0 <= value <= 15 */
                set_brightness(value);
-       } else if (count < 0) {
-               printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
        }
-
-       return count;
+       return rv;
 }
 
 static void set_display(int value)
@@ -880,15 +887,12 @@ static int
 proc_write_disp(struct file *file, const char __user * buffer,
                unsigned long count, void *data)
 {
-       int value;
+       int rv, value;
 
-       count = parse_arg(buffer, count, &value);
-       if (count > 0)
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0)
                set_display(value);
-       else if (count < 0)
-               printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
-       return count;
+       return rv;
 }
 
 typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
@@ -1097,6 +1101,8 @@ static int asus_model_match(char *model)
                return A4G;
        else if (strncmp(model, "W1N", 3) == 0)
                return W1N;
+       else if (strncmp(model, "W3V", 3) == 0)
+               return W3V;
        else if (strncmp(model, "W5A", 3) == 0)
                return W5A;
        else
@@ -1200,9 +1206,10 @@ static int asus_hotk_get_info(void)
                hotk->methods->mt_wled = NULL;
        /* L5D's WLED is not controlled by ACPI */
        else if (strncmp(string, "M2N", 3) == 0 ||
+                strncmp(string, "W3V", 3) == 0 ||
                 strncmp(string, "S1N", 3) == 0)
                hotk->methods->mt_wled = "WLED";
-       /* M2N and S1N have a usable WLED */
+       /* M2N, S1N and W3V have a usable WLED */
        else if (asus_info) {
                if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
                        hotk->methods->mled_status = NULL;
index 9810e2a..026e407 100644 (file)
@@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
 static int acpi_battery_add(struct acpi_device *device);
 static int acpi_battery_remove(struct acpi_device *device, int type);
+static int acpi_battery_resume(struct acpi_device *device, int status);
 
 static struct acpi_driver acpi_battery_driver = {
        .name = ACPI_BATTERY_DRIVER_NAME,
@@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_driver = {
        .ids = ACPI_BATTERY_HID,
        .ops = {
                .add = acpi_battery_add,
+               .resume = acpi_battery_resume,
                .remove = acpi_battery_remove,
                },
 };
@@ -753,6 +755,18 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+/* this is needed to learn about changes made in suspended state */
+static int acpi_battery_resume(struct acpi_device *device, int state)
+{
+       struct acpi_battery *battery;
+
+       if (!device)
+               return -EINVAL;
+
+       battery = device->driver_data;
+       return acpi_battery_check(battery);
+}
+
 static int __init acpi_battery_init(void)
 {
        int result;
index e5d7963..e6d4b08 100644 (file)
@@ -45,206 +45,143 @@ ACPI_MODULE_NAME("acpi_ec")
 #define ACPI_EC_DRIVER_NAME            "ACPI Embedded Controller Driver"
 #define ACPI_EC_DEVICE_NAME            "Embedded Controller"
 #define ACPI_EC_FILE_INFO              "info"
+
+/* EC status register */
 #define ACPI_EC_FLAG_OBF       0x01    /* Output buffer full */
 #define ACPI_EC_FLAG_IBF       0x02    /* Input buffer full */
 #define ACPI_EC_FLAG_BURST     0x10    /* burst mode */
 #define ACPI_EC_FLAG_SCI       0x20    /* EC-SCI occurred */
-#define ACPI_EC_EVENT_OBF      0x01    /* Output buffer full */
-#define ACPI_EC_EVENT_IBE      0x02    /* Input buffer empty */
-#define ACPI_EC_DELAY          50      /* Wait 50ms max. during EC ops */
-#define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
-#define ACPI_EC_UDELAY         100     /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT   1000    /* Wait 10ms max. during EC ops */
+
+/* EC commands */
 #define ACPI_EC_COMMAND_READ   0x80
 #define ACPI_EC_COMMAND_WRITE  0x81
 #define ACPI_EC_BURST_ENABLE   0x82
 #define ACPI_EC_BURST_DISABLE  0x83
 #define ACPI_EC_COMMAND_QUERY  0x84
-#define EC_POLL                        0xFF
-#define EC_INTR                        0x00
+
+/* EC events */
+enum {
+       ACPI_EC_EVENT_OBF_1 = 1,        /* Output buffer full */
+       ACPI_EC_EVENT_IBF_0,            /* Input buffer empty */
+};
+
+#define ACPI_EC_DELAY          50      /* Wait 50ms max. during EC ops */
+#define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY         100     /* Poll @ 100us increments */
+#define ACPI_EC_UDELAY_COUNT   1000    /* Wait 10ms max. during EC ops */
+
+enum {
+       EC_INTR = 1,    /* Output buffer full */
+       EC_POLL,        /* Input buffer empty */
+};
+
 static int acpi_ec_remove(struct acpi_device *device, int type);
 static int acpi_ec_start(struct acpi_device *device);
 static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_intr_add(struct acpi_device *device);
-static int acpi_ec_poll_add(struct acpi_device *device);
+static int acpi_ec_add(struct acpi_device *device);
 
 static struct acpi_driver acpi_ec_driver = {
        .name = ACPI_EC_DRIVER_NAME,
        .class = ACPI_EC_CLASS,
        .ids = ACPI_EC_HID,
        .ops = {
-               .add = acpi_ec_intr_add,
+               .add = acpi_ec_add,
                .remove = acpi_ec_remove,
                .start = acpi_ec_start,
                .stop = acpi_ec_stop,
                },
 };
-union acpi_ec {
-       struct {
-               u32 mode;
-               acpi_handle handle;
-               unsigned long uid;
-               unsigned long gpe_bit;
-               struct acpi_generic_address status_addr;
-               struct acpi_generic_address command_addr;
-               struct acpi_generic_address data_addr;
-               unsigned long global_lock;
-       } common;
-
-       struct {
-               u32 mode;
-               acpi_handle handle;
-               unsigned long uid;
-               unsigned long gpe_bit;
-               struct acpi_generic_address status_addr;
-               struct acpi_generic_address command_addr;
-               struct acpi_generic_address data_addr;
-               unsigned long global_lock;
-               unsigned int expect_event;
-               atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
-               atomic_t pending_gpe;
-               struct semaphore sem;
-               wait_queue_head_t wait;
-       } intr;
-
-       struct {
-               u32 mode;
-               acpi_handle handle;
-               unsigned long uid;
-               unsigned long gpe_bit;
-               struct acpi_generic_address status_addr;
-               struct acpi_generic_address command_addr;
-               struct acpi_generic_address data_addr;
-               unsigned long global_lock;
-               struct semaphore sem;
-       } poll;
-};
 
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data);
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data);
-static void acpi_ec_gpe_poll_query(void *ec_cxt);
-static void acpi_ec_gpe_intr_query(void *ec_cxt);
-static u32 acpi_ec_gpe_poll_handler(void *data);
-static u32 acpi_ec_gpe_intr_handler(void *data);
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
-                               u32 Level, void *context, void **retval);
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
-                             u32 Level, void *context, void **retval);
-
-static int __init acpi_ec_poll_get_real_ecdt(void);
-static int __init acpi_ec_intr_get_real_ecdt(void);
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
-static union acpi_ec *ec_ecdt;
+struct acpi_ec {
+       acpi_handle handle;
+       unsigned long uid;
+       unsigned long gpe_bit;
+       unsigned long command_addr;
+       unsigned long data_addr;
+       unsigned long global_lock;
+       struct semaphore sem;
+       unsigned int expect_event;
+       atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
+       wait_queue_head_t wait;
+} *ec_ecdt;
 
 /* External interfaces use first EC only, so remember */
 static struct acpi_device *first_ec;
-static int acpi_ec_poll_mode = EC_INTR;
+static int acpi_ec_mode = EC_INTR;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
 
-static u32 acpi_ec_read_status(union acpi_ec *ec)
+static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
 {
-       u32 status = 0;
-
-       acpi_hw_low_level_read(8, &status, &ec->common.status_addr);
-       return status;
+       return inb(ec->command_addr);
 }
 
-static int acpi_ec_wait(union acpi_ec *ec, u8 event)
+static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
 {
-       if (acpi_ec_poll_mode)
-               return acpi_ec_poll_wait(ec, event);
-       else
-               return acpi_ec_intr_wait(ec, event);
+       return inb(ec->data_addr);
 }
 
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event)
+static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
-       u32 acpi_ec_status = 0;
-       u32 i = ACPI_EC_UDELAY_COUNT;
+       outb(command, ec->command_addr);
+}
 
-       if (!ec)
-               return -EINVAL;
+static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
+{
+       outb(data, ec->data_addr);
+}
 
-       /* Poll the EC status register waiting for the event to occur. */
+static int acpi_ec_check_status(u8 status, u8 event)
+{
        switch (event) {
-       case ACPI_EC_EVENT_OBF:
-               do {
-                       acpi_hw_low_level_read(8, &acpi_ec_status,
-                                              &ec->common.status_addr);
-                       if (acpi_ec_status & ACPI_EC_FLAG_OBF)
-                               return 0;
-                       udelay(ACPI_EC_UDELAY);
-               } while (--i > 0);
+       case ACPI_EC_EVENT_OBF_1:
+               if (status & ACPI_EC_FLAG_OBF)
+                       return 1;
                break;
-       case ACPI_EC_EVENT_IBE:
-               do {
-                       acpi_hw_low_level_read(8, &acpi_ec_status,
-                                              &ec->common.status_addr);
-                       if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
-                               return 0;
-                       udelay(ACPI_EC_UDELAY);
-               } while (--i > 0);
+       case ACPI_EC_EVENT_IBF_0:
+               if (!(status & ACPI_EC_FLAG_IBF))
+                       return 1;
                break;
        default:
-               return -EINVAL;
+               break;
        }
 
-       return -ETIME;
+       return 0;
 }
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
-{
-       int result = 0;
-
 
-       ec->intr.expect_event = event;
-       smp_mb();
+static int acpi_ec_wait(struct acpi_ec *ec, u8 event)
+{
+       int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0;
+       long time_left;
 
-       switch (event) {
-       case ACPI_EC_EVENT_IBE:
-               if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) {
-                       ec->intr.expect_event = 0;
-                       return 0;
-               }
-               break;
-       default:
-               break;
+       ec->expect_event = event;
+       if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
+               ec->expect_event = 0;
+               return 0;
        }
 
-       result = wait_event_timeout(ec->intr.wait,
-                                   !ec->intr.expect_event,
+       do {
+               if (acpi_ec_mode == EC_POLL) {
+                       udelay(ACPI_EC_UDELAY);
+               } else {
+                       time_left = wait_event_timeout(ec->wait,
+                                   !ec->expect_event,
                                    msecs_to_jiffies(ACPI_EC_DELAY));
-
-       ec->intr.expect_event = 0;
-       smp_mb();
-
-       /*
-        * Verify that the event in question has actually happened by
-        * querying EC status. Do the check even if operation timed-out
-        * to make sure that we did not miss interrupt.
-        */
-       switch (event) {
-       case ACPI_EC_EVENT_OBF:
-               if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
+                       if (time_left > 0) {
+                               ec->expect_event = 0;
+                               return 0;
+                       }
+               }
+               if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
+                       ec->expect_event = 0;
                        return 0;
-               break;
+               }
+       } while (--i > 0);
 
-       case ACPI_EC_EVENT_IBE:
-               if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
-                       return 0;
-               break;
-       }
+       ec->expect_event = 0;
 
        return -ETIME;
 }
@@ -254,272 +191,150 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
  * Note: samsung nv5000 doesn't work with ec burst mode.
  * http://bugzilla.kernel.org/show_bug.cgi?id=4980
  */
-int acpi_ec_enter_burst_mode(union acpi_ec *ec)
+int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
 {
-       u32 tmp = 0;
-       int status = 0;
+       u8 tmp = 0;
+       u8 status = 0;
 
 
        status = acpi_ec_read_status(ec);
        if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
-               status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+               status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
                if (status)
                        goto end;
-               acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE,
-                                       &ec->common.command_addr);
-               status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-               acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
+               acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
+               status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+               tmp = acpi_ec_read_data(ec);
                if (tmp != 0x90) {      /* Burst ACK byte */
                        return -EINVAL;
                }
        }
 
-       atomic_set(&ec->intr.leaving_burst, 0);
+       atomic_set(&ec->leaving_burst, 0);
        return 0;
-      end:
-       ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
+  end:
+       ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
        return -1;
 }
 
-int acpi_ec_leave_burst_mode(union acpi_ec *ec)
+int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
 {
-       int status = 0;
+       u8 status = 0;
 
 
        status = acpi_ec_read_status(ec);
        if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
-               status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
+               status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
                if(status)
                        goto end;
-               acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
-               acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
-       } 
-       atomic_set(&ec->intr.leaving_burst, 1);
+               acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
+               acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+       }
+       atomic_set(&ec->leaving_burst, 1);
        return 0;
-end:
-       ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
+  end:
+       ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
        return -1;
 }
 #endif /* ACPI_FUTURE_USAGE */
 
-static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
-{
-       if (acpi_ec_poll_mode)
-               return acpi_ec_poll_read(ec, address, data);
-       else
-               return acpi_ec_intr_read(ec, address, data);
-}
-static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
-{
-       if (acpi_ec_poll_mode)
-               return acpi_ec_poll_write(ec, address, data);
-       else
-               return acpi_ec_intr_write(ec, address, data);
-}
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
+static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
+                                       const u8 *wdata, unsigned wdata_len,
+                                       u8 *rdata, unsigned rdata_len)
 {
-       acpi_status status = AE_OK;
-       int result = 0;
-       u32 glk = 0;
+       int result;
 
+       acpi_ec_write_cmd(ec, command);
 
-       if (!ec || !data)
-               return -EINVAL;
-
-       *data = 0;
-
-       if (ec->common.global_lock) {
-               status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-               if (ACPI_FAILURE(status))
-                       return -ENODEV;
+       for (; wdata_len > 0; wdata_len --) {
+               result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+               if (result)
+                       return result;
+               acpi_ec_write_data(ec, *(wdata++));
        }
 
-       if (down_interruptible(&ec->poll.sem)) {
-               result = -ERESTARTSYS;
-               goto end_nosem;
+       if (command == ACPI_EC_COMMAND_WRITE) {
+               result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+               if (result)
+                       return result;
        }
-       
-       acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
-                               &ec->common.command_addr);
-       result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (result)
-               goto end;
-
-       acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-       result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-       if (result)
-               goto end;
-
-       acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
-                         *data, address));
-
-      end:
-       up(&ec->poll.sem);
-end_nosem:
-       if (ec->common.global_lock)
-               acpi_release_global_lock(glk);
-
-       return result;
-}
-
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
-{
-       int result = 0;
-       acpi_status status = AE_OK;
-       u32 glk = 0;
 
+       for (; rdata_len > 0; rdata_len --) {
+               result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+               if (result)
+                       return result;
 
-       if (!ec)
-               return -EINVAL;
-
-       if (ec->common.global_lock) {
-               status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-               if (ACPI_FAILURE(status))
-                       return -ENODEV;
-       }
-
-       if (down_interruptible(&ec->poll.sem)) {
-               result = -ERESTARTSYS;
-               goto end_nosem;
+               *(rdata++) = acpi_ec_read_data(ec);
        }
-       
-       acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
-                               &ec->common.command_addr);
-       result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (result)
-               goto end;
-
-       acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-       result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (result)
-               goto end;
-
-       acpi_hw_low_level_write(8, data, &ec->common.data_addr);
-       result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (result)
-               goto end;
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
-                         data, address));
-
-      end:
-       up(&ec->poll.sem);
-end_nosem:
-       if (ec->common.global_lock)
-               acpi_release_global_lock(glk);
-
-       return result;
+       return 0;
 }
 
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
+static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
+                               const u8 *wdata, unsigned wdata_len,
+                               u8 *rdata, unsigned rdata_len)
 {
-       int status = 0;
+       int status;
        u32 glk;
 
-
-       if (!ec || !data)
+       if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
                return -EINVAL;
 
-       *data = 0;
+        if (rdata)
+                memset(rdata, 0, rdata_len);
 
-       if (ec->common.global_lock) {
+       if (ec->global_lock) {
                status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
                if (ACPI_FAILURE(status))
                        return -ENODEV;
        }
+       down(&ec->sem);
 
-       WARN_ON(in_interrupt());
-       down(&ec->intr.sem);
-
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
        if (status) {
                printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
                goto end;
        }
-       acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
-                               &ec->common.command_addr);
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
-       }
 
-       acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
-               goto end;
-       }
-       acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
-                         *data, address));
+        status = acpi_ec_transaction_unlocked(ec, command,
+                                              wdata, wdata_len,
+                                              rdata, rdata_len);
 
-      end:
-       up(&ec->intr.sem);
+end:
+       up(&ec->sem);
 
-       if (ec->common.global_lock)
+       if (ec->global_lock)
                acpi_release_global_lock(glk);
 
        return status;
 }
 
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
 {
-       int status = 0;
-       u32 glk;
-
-
-       if (!ec)
-               return -EINVAL;
-
-       if (ec->common.global_lock) {
-               status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-               if (ACPI_FAILURE(status))
-                       return -ENODEV;
-       }
-
-       WARN_ON(in_interrupt());
-       down(&ec->intr.sem);
-
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
-       }
-       acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
-                               &ec->common.command_addr);
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
-       }
-
-       acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
-       }
-
-       acpi_hw_low_level_write(8, data, &ec->common.data_addr);
+       int result;
+       u8 d;
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
-                         data, address));
-
-       up(&ec->intr.sem);
-
-       if (ec->common.global_lock)
-               acpi_release_global_lock(glk);
+       result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
+                                    &address, 1, &d, 1);
+       *data = d;
+       return result;
+}
 
-       return status;
+static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+{
+        u8 wdata[2] = { address, data };
+        return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
+                                  wdata, 2, NULL, 0);
 }
 
 /*
  * Externally callable EC access functions. For now, assume 1 EC only
  */
-int ec_read(u8 addr, u8 * val)
+int ec_read(u8 addr, u8 *val)
 {
-       union acpi_ec *ec;
+       struct acpi_ec *ec;
        int err;
-       u32 temp_data;
+       u8 temp_data;
 
        if (!first_ec)
                return -ENODEV;
@@ -539,7 +354,7 @@ EXPORT_SYMBOL(ec_read);
 
 int ec_write(u8 addr, u8 val)
 {
-       union acpi_ec *ec;
+       struct acpi_ec *ec;
        int err;
 
        if (!first_ec)
@@ -554,255 +369,106 @@ int ec_write(u8 addr, u8 val)
 
 EXPORT_SYMBOL(ec_write);
 
-static int acpi_ec_query(union acpi_ec *ec, u32 * data)
-{
-       if (acpi_ec_poll_mode)
-               return acpi_ec_poll_query(ec, data);
-       else
-               return acpi_ec_intr_query(ec, data);
-}
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
+extern int ec_transaction(u8 command,
+                          const u8 *wdata, unsigned wdata_len,
+                          u8 *rdata, unsigned rdata_len)
 {
-       int result = 0;
-       acpi_status status = AE_OK;
-       u32 glk = 0;
-
-
-       if (!ec || !data)
-               return -EINVAL;
-
-       *data = 0;
-
-       if (ec->common.global_lock) {
-               status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-               if (ACPI_FAILURE(status))
-                       return -ENODEV;
-       }
+       struct acpi_ec *ec;
 
-       /*
-        * Query the EC to find out which _Qxx method we need to evaluate.
-        * Note that successful completion of the query causes the ACPI_EC_SCI
-        * bit to be cleared (and thus clearing the interrupt source).
-        */
-       if (down_interruptible(&ec->poll.sem)) {
-               result = -ERESTARTSYS;
-               goto end_nosem;
-       }
-       
-       acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
-                               &ec->common.command_addr);
-       result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-       if (result)
-               goto end;
-
-       acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-       if (!*data)
-               result = -ENODATA;
+       if (!first_ec)
+               return -ENODEV;
 
-      end:
-       up(&ec->poll.sem);
-end_nosem:
-       if (ec->common.global_lock)
-               acpi_release_global_lock(glk);
+       ec = acpi_driver_data(first_ec);
 
-       return result;
+       return acpi_ec_transaction(ec, command, wdata,
+                                  wdata_len, rdata, rdata_len);
 }
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
-{
-       int status = 0;
-       u32 glk;
-
 
-       if (!ec || !data)
-               return -EINVAL;
-       *data = 0;
-
-       if (ec->common.global_lock) {
-               status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-               if (ACPI_FAILURE(status))
-                       return -ENODEV;
-       }
+EXPORT_SYMBOL(ec_transaction);
 
-       down(&ec->intr.sem);
+static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
+{
+       int result;
+        u8 d;
 
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "query EC, IB not empty\n");
-               goto end;
-       }
-       /*
-        * Query the EC to find out which _Qxx method we need to evaluate.
-        * Note that successful completion of the query causes the ACPI_EC_SCI
-        * bit to be cleared (and thus clearing the interrupt source).
-        */
-       acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
-                               &ec->common.command_addr);
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-       if (status) {
-               printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
-               goto end;
-       }
+        if (!ec || !data)
+                return -EINVAL;
 
-       acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-       if (!*data)
-               status = -ENODATA;
+        /*
+         * Query the EC to find out which _Qxx method we need to evaluate.
+         * Note that successful completion of the query causes the ACPI_EC_SCI
+         * bit to be cleared (and thus clearing the interrupt source).
+         */
 
-      end:
-       up(&ec->intr.sem);
+        result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+        if (result)
+                return result;
 
-       if (ec->common.global_lock)
-               acpi_release_global_lock(glk);
+        if (!d)
+                return -ENODATA;
 
-       return status;
+        *data = d;
+        return 0;
 }
 
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
 
-union acpi_ec_query_data {
+struct acpi_ec_query_data {
        acpi_handle handle;
        u8 data;
 };
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
-       if (acpi_ec_poll_mode)
-               acpi_ec_gpe_poll_query(ec_cxt);
-       else
-               acpi_ec_gpe_intr_query(ec_cxt);
-}
-
-static void acpi_ec_gpe_poll_query(void *ec_cxt)
-{
-       union acpi_ec *ec = (union acpi_ec *)ec_cxt;
-       u32 value = 0;
-       static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
-       const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
-               '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-       };
-
+       struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+       u8 value = 0;
+       static char object_name[8];
 
-       if (!ec_cxt)
+       if (!ec)
                goto end;
 
-       if (down_interruptible (&ec->poll.sem)) {
-               return;
-       }
-       acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
-       up(&ec->poll.sem);
-
-       /* TBD: Implement asynch events!
-        * NOTE: All we care about are EC-SCI's.  Other EC events are
-        * handled via polling (yuck!).  This is because some systems
-        * treat EC-SCIs as level (versus EDGE!) triggered, preventing
-        *  a purely interrupt-driven approach (grumble, grumble).
-        */
+       value = acpi_ec_read_status(ec);
+
        if (!(value & ACPI_EC_FLAG_SCI))
                goto end;
 
        if (acpi_ec_query(ec, &value))
                goto end;
 
-       object_name[2] = hex[((value >> 4) & 0x0F)];
-       object_name[3] = hex[(value & 0x0F)];
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
+       snprintf(object_name, 8, "_Q%2.2X", value);
 
-       acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
 
-      end:
-       acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
-}
-static void acpi_ec_gpe_intr_query(void *ec_cxt)
-{
-       union acpi_ec *ec = (union acpi_ec *)ec_cxt;
-       u32 value;
-       int result = -ENODATA;
-       static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
-       const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
-               '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-       };
+       acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
 
-
-       if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
-               result = acpi_ec_query(ec, &value);
-
-       if (result)
-               goto end;
-
-       object_name[2] = hex[((value >> 4) & 0x0F)];
-       object_name[3] = hex[(value & 0x0F)];
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
-
-       acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
       end:
-       atomic_dec(&ec->intr.pending_gpe);
-       return;
+       acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 }
 
 static u32 acpi_ec_gpe_handler(void *data)
-{
-       if (acpi_ec_poll_mode)
-               return acpi_ec_gpe_poll_handler(data);
-       else
-               return acpi_ec_gpe_intr_handler(data);
-}
-static u32 acpi_ec_gpe_poll_handler(void *data)
 {
        acpi_status status = AE_OK;
-       union acpi_ec *ec = (union acpi_ec *)data;
-
-       if (!ec)
-               return ACPI_INTERRUPT_NOT_HANDLED;
-
-       acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
-
-       status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
-
-       if (status == AE_OK)
-               return ACPI_INTERRUPT_HANDLED;
-       else
-               return ACPI_INTERRUPT_NOT_HANDLED;
-}
-static u32 acpi_ec_gpe_intr_handler(void *data)
-{
-       acpi_status status = AE_OK;
-       u32 value;
-       union acpi_ec *ec = (union acpi_ec *)data;
-
-       if (!ec)
-               return ACPI_INTERRUPT_NOT_HANDLED;
+       u8 value;
+       struct acpi_ec *ec = (struct acpi_ec *)data;
 
-       acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+       acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR);
        value = acpi_ec_read_status(ec);
 
-       switch (ec->intr.expect_event) {
-       case ACPI_EC_EVENT_OBF:
-               if (!(value & ACPI_EC_FLAG_OBF))
-                       break;
-               ec->intr.expect_event = 0;
-               wake_up(&ec->intr.wait);
-               break;
-       case ACPI_EC_EVENT_IBE:
-               if ((value & ACPI_EC_FLAG_IBF))
-                       break;
-               ec->intr.expect_event = 0;
-               wake_up(&ec->intr.wait);
-               break;
-       default:
-               break;
+       if (acpi_ec_mode == EC_INTR) {
+               if (acpi_ec_check_status(value, ec->expect_event)) {
+                       ec->expect_event = 0;
+                       wake_up(&ec->wait);
+               }
        }
 
        if (value & ACPI_EC_FLAG_SCI) {
-               atomic_add(1, &ec->intr.pending_gpe);
-               status = acpi_os_execute(OSL_EC_BURST_HANDLER,
-                                                    acpi_ec_gpe_query, ec);
+               status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
                return status == AE_OK ?
                    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
        }
-       acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+       acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
        return status == AE_OK ?
            ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 }
@@ -833,7 +499,7 @@ acpi_ec_space_handler(u32 function,
                      void *handler_context, void *region_context)
 {
        int result = 0;
-       union acpi_ec *ec = NULL;
+       struct acpi_ec *ec = NULL;
        u64 temp = *value;
        acpi_integer f_v = 0;
        int i = 0;
@@ -843,18 +509,16 @@ acpi_ec_space_handler(u32 function,
                return AE_BAD_PARAMETER;
 
        if (bit_width != 8 && acpi_strict) {
-               printk(KERN_WARNING PREFIX
-                      "acpi_ec_space_handler: bit_width should be 8\n");
                return AE_BAD_PARAMETER;
        }
 
-       ec = (union acpi_ec *)handler_context;
+       ec = (struct acpi_ec *)handler_context;
 
       next_byte:
        switch (function) {
        case ACPI_READ:
                temp = 0;
-               result = acpi_ec_read(ec, (u8) address, (u32 *) & temp);
+               result = acpi_ec_read(ec, (u8) address, (u8 *) &temp);
                break;
        case ACPI_WRITE:
                result = acpi_ec_write(ec, (u8) address, (u8) temp);
@@ -905,20 +569,20 @@ static struct proc_dir_entry *acpi_ec_dir;
 
 static int acpi_ec_read_info(struct seq_file *seq, void *offset)
 {
-       union acpi_ec *ec = (union acpi_ec *)seq->private;
+       struct acpi_ec *ec = (struct acpi_ec *)seq->private;
 
 
        if (!ec)
                goto end;
 
        seq_printf(seq, "gpe bit:                 0x%02x\n",
-                  (u32) ec->common.gpe_bit);
+                  (u32) ec->gpe_bit);
        seq_printf(seq, "ports:                   0x%02x, 0x%02x\n",
-                  (u32) ec->common.status_addr.address,
-                  (u32) ec->common.data_addr.address);
+                  (u32) ec->command_addr,
+                  (u32) ec->data_addr);
        seq_printf(seq, "use global lock:         %s\n",
-                  ec->common.global_lock ? "yes" : "no");
-       acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+                  ec->global_lock ? "yes" : "no");
+       acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 
       end:
        return 0;
@@ -929,7 +593,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
        return single_open(file, acpi_ec_read_info, PDE(inode)->data);
 }
 
-static const struct file_operations acpi_ec_info_ops = {
+static struct file_operations acpi_ec_info_ops = {
        .open = acpi_ec_info_open_fs,
        .read = seq_read,
        .llseek = seq_lseek,
@@ -978,101 +642,35 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
                                Driver Interface
    -------------------------------------------------------------------------- */
 
-static int acpi_ec_poll_add(struct acpi_device *device)
+static int acpi_ec_add(struct acpi_device *device)
 {
        int result = 0;
        acpi_status status = AE_OK;
-       union acpi_ec *ec = NULL;
+       struct acpi_ec *ec = NULL;
 
 
        if (!device)
                return -EINVAL;
 
-       ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+       ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
        if (!ec)
                return -ENOMEM;
-       memset(ec, 0, sizeof(union acpi_ec));
-
-       ec->common.handle = device->handle;
-       ec->common.uid = -1;
-       init_MUTEX(&ec->poll.sem);
-       strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
-       strcpy(acpi_device_class(device), ACPI_EC_CLASS);
-       acpi_driver_data(device) = ec;
-
-       /* Use the global lock for all EC transactions? */
-       acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
-                             &ec->common.global_lock);
-
-       /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
-          http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
-       if (ec_ecdt) {
-               acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
-                                                 ACPI_ADR_SPACE_EC,
-                                                 &acpi_ec_space_handler);
-
-               acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
-                                       &acpi_ec_gpe_handler);
-
-               kfree(ec_ecdt);
+       memset(ec, 0, sizeof(struct acpi_ec));
+
+       ec->handle = device->handle;
+       ec->uid = -1;
+       init_MUTEX(&ec->sem);
+       if (acpi_ec_mode == EC_INTR) {
+               atomic_set(&ec->leaving_burst, 1);
+               init_waitqueue_head(&ec->wait);
        }
-
-       /* Get GPE bit assignment (EC events). */
-       /* TODO: Add support for _GPE returning a package */
-       status =
-           acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
-                                 &ec->common.gpe_bit);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
-               result = -ENODEV;
-               goto end;
-       }
-
-       result = acpi_ec_add_fs(device);
-       if (result)
-               goto end;
-
-       printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n",
-              acpi_device_name(device), acpi_device_bid(device),
-              (u32) ec->common.gpe_bit);
-
-       if (!first_ec)
-               first_ec = device;
-
-      end:
-       if (result)
-               kfree(ec);
-
-       return result;
-}
-static int acpi_ec_intr_add(struct acpi_device *device)
-{
-       int result = 0;
-       acpi_status status = AE_OK;
-       union acpi_ec *ec = NULL;
-
-
-       if (!device)
-               return -EINVAL;
-
-       ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
-       if (!ec)
-               return -ENOMEM;
-       memset(ec, 0, sizeof(union acpi_ec));
-
-       ec->common.handle = device->handle;
-       ec->common.uid = -1;
-       atomic_set(&ec->intr.pending_gpe, 0);
-       atomic_set(&ec->intr.leaving_burst, 1);
-       init_MUTEX(&ec->intr.sem);
-       init_waitqueue_head(&ec->intr.wait);
        strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_EC_CLASS);
        acpi_driver_data(device) = ec;
 
        /* Use the global lock for all EC transactions? */
-       acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
-                             &ec->common.global_lock);
+       acpi_evaluate_integer(ec->handle, "_GLK", NULL,
+                             &ec->global_lock);
 
        /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
           http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
@@ -1081,7 +679,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
                                                  ACPI_ADR_SPACE_EC,
                                                  &acpi_ec_space_handler);
 
-               acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+               acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
                                        &acpi_ec_gpe_handler);
 
                kfree(ec_ecdt);
@@ -1090,10 +688,10 @@ static int acpi_ec_intr_add(struct acpi_device *device)
        /* Get GPE bit assignment (EC events). */
        /* TODO: Add support for _GPE returning a package */
        status =
-           acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
-                                 &ec->common.gpe_bit);
+           acpi_evaluate_integer(ec->handle, "_GPE", NULL,
+                                 &ec->gpe_bit);
        if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n");
+               ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment"));
                result = -ENODEV;
                goto end;
        }
@@ -1102,14 +700,14 @@ static int acpi_ec_intr_add(struct acpi_device *device)
        if (result)
                goto end;
 
-       printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n",
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
               acpi_device_name(device), acpi_device_bid(device),
-              (u32) ec->common.gpe_bit);
+              (u32) ec->gpe_bit));
 
        if (!first_ec)
                first_ec = device;
 
-      end:
+  end:
        if (result)
                kfree(ec);
 
@@ -1118,7 +716,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
-       union acpi_ec *ec = NULL;
+       struct acpi_ec *ec = NULL;
 
 
        if (!device)
@@ -1136,8 +734,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
 static acpi_status
 acpi_ec_io_ports(struct acpi_resource *resource, void *context)
 {
-       union acpi_ec *ec = (union acpi_ec *)context;
-       struct acpi_generic_address *addr;
+       struct acpi_ec *ec = (struct acpi_ec *)context;
 
        if (resource->type != ACPI_RESOURCE_TYPE_IO) {
                return AE_OK;
@@ -1148,26 +745,21 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
         * the second address region returned is the status/command
         * port.
         */
-       if (ec->common.data_addr.register_bit_width == 0) {
-               addr = &ec->common.data_addr;
-       } else if (ec->common.command_addr.register_bit_width == 0) {
-               addr = &ec->common.command_addr;
+       if (ec->data_addr == 0) {
+               ec->data_addr = resource->data.io.minimum;
+       } else if (ec->command_addr == 0) {
+               ec->command_addr = resource->data.io.minimum;
        } else {
                return AE_CTRL_TERMINATE;
        }
 
-       addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
-       addr->register_bit_width = 8;
-       addr->register_bit_offset = 0;
-       addr->address = resource->data.io.minimum;
-
        return AE_OK;
 }
 
 static int acpi_ec_start(struct acpi_device *device)
 {
        acpi_status status = AE_OK;
-       union acpi_ec *ec = NULL;
+       struct acpi_ec *ec = NULL;
 
 
        if (!device)
@@ -1181,39 +773,35 @@ static int acpi_ec_start(struct acpi_device *device)
        /*
         * Get I/O port addresses. Convert to GAS format.
         */
-       status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS,
+       status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
                                     acpi_ec_io_ports, ec);
-       if (ACPI_FAILURE(status)
-           || ec->common.command_addr.register_bit_width == 0) {
-               printk(KERN_ERR PREFIX "Error getting I/O port addresses\n");
+       if (ACPI_FAILURE(status) || ec->command_addr == 0) {
+               ACPI_EXCEPTION((AE_INFO, status,
+                               "Error getting I/O port addresses"));
                return -ENODEV;
        }
 
-       ec->common.status_addr = ec->common.command_addr;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
-                         (u32) ec->common.gpe_bit,
-                         (u32) ec->common.command_addr.address,
-                         (u32) ec->common.data_addr.address));
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+                         ec->gpe_bit, ec->command_addr, ec->data_addr));
 
        /*
         * Install GPE handler
         */
-       status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit,
+       status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
                                          ACPI_GPE_EDGE_TRIGGERED,
                                          &acpi_ec_gpe_handler, ec);
        if (ACPI_FAILURE(status)) {
                return -ENODEV;
        }
-       acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-       acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+       acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+       acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 
-       status = acpi_install_address_space_handler(ec->common.handle,
+       status = acpi_install_address_space_handler(ec->handle,
                                                    ACPI_ADR_SPACE_EC,
                                                    &acpi_ec_space_handler,
                                                    &acpi_ec_space_setup, ec);
        if (ACPI_FAILURE(status)) {
-               acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
+               acpi_remove_gpe_handler(NULL, ec->gpe_bit,
                                        &acpi_ec_gpe_handler);
                return -ENODEV;
        }
@@ -1224,7 +812,7 @@ static int acpi_ec_start(struct acpi_device *device)
 static int acpi_ec_stop(struct acpi_device *device, int type)
 {
        acpi_status status = AE_OK;
-       union acpi_ec *ec = NULL;
+       struct acpi_ec *ec = NULL;
 
 
        if (!device)
@@ -1232,14 +820,14 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
 
        ec = acpi_driver_data(device);
 
-       status = acpi_remove_address_space_handler(ec->common.handle,
+       status = acpi_remove_address_space_handler(ec->handle,
                                                   ACPI_ADR_SPACE_EC,
                                                   &acpi_ec_space_handler);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
        status =
-           acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
+           acpi_remove_gpe_handler(NULL, ec->gpe_bit,
                                    &acpi_ec_gpe_handler);
        if (ACPI_FAILURE(status))
                return -ENODEV;
@@ -1251,76 +839,30 @@ static acpi_status __init
 acpi_fake_ecdt_callback(acpi_handle handle,
                        u32 Level, void *context, void **retval)
 {
-
-       if (acpi_ec_poll_mode)
-               return acpi_fake_ecdt_poll_callback(handle,
-                                                      Level, context, retval);
-       else
-               return acpi_fake_ecdt_intr_callback(handle,
-                                                    Level, context, retval);
-}
-
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
-                               u32 Level, void *context, void **retval)
-{
-       acpi_status status;
-
-       status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-                                    acpi_ec_io_ports, ec_ecdt);
-       if (ACPI_FAILURE(status))
-               return status;
-       ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
-
-       ec_ecdt->common.uid = -1;
-       acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
-
-       status =
-           acpi_evaluate_integer(handle, "_GPE", NULL,
-                                 &ec_ecdt->common.gpe_bit);
-       if (ACPI_FAILURE(status))
-               return status;
-       init_MUTEX(&ec_ecdt->poll.sem);
-       ec_ecdt->common.global_lock = TRUE;
-       ec_ecdt->common.handle = handle;
-
-       printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
-              (u32) ec_ecdt->common.gpe_bit,
-              (u32) ec_ecdt->common.command_addr.address,
-              (u32) ec_ecdt->common.data_addr.address);
-
-       return AE_CTRL_TERMINATE;
-}
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
-                             u32 Level, void *context, void **retval)
-{
        acpi_status status;
 
-       init_MUTEX(&ec_ecdt->intr.sem);
-       init_waitqueue_head(&ec_ecdt->intr.wait);
+       init_MUTEX(&ec_ecdt->sem);
+       if (acpi_ec_mode == EC_INTR) {
+               init_waitqueue_head(&ec_ecdt->wait);
+       }
        status = acpi_walk_resources(handle, METHOD_NAME__CRS,
                                     acpi_ec_io_ports, ec_ecdt);
        if (ACPI_FAILURE(status))
                return status;
-       ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
 
-       ec_ecdt->common.uid = -1;
-       acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
+       ec_ecdt->uid = -1;
+       acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
 
        status =
            acpi_evaluate_integer(handle, "_GPE", NULL,
-                                 &ec_ecdt->common.gpe_bit);
+                                 &ec_ecdt->gpe_bit);
        if (ACPI_FAILURE(status))
                return status;
-       ec_ecdt->common.global_lock = TRUE;
-       ec_ecdt->common.handle = handle;
+       ec_ecdt->global_lock = TRUE;
+       ec_ecdt->handle = handle;
 
-       printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
-              (u32) ec_ecdt->common.gpe_bit,
-              (u32) ec_ecdt->common.command_addr.address,
-              (u32) ec_ecdt->common.data_addr.address);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+              ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr));
 
        return AE_CTRL_TERMINATE;
 }
@@ -1340,14 +882,14 @@ static int __init acpi_ec_fake_ecdt(void)
        acpi_status status;
        int ret = 0;
 
-       printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
 
-       ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+       ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
        if (!ec_ecdt) {
                ret = -ENOMEM;
                goto error;
        }
-       memset(ec_ecdt, 0, sizeof(union acpi_ec));
+       memset(ec_ecdt, 0, sizeof(struct acpi_ec));
 
        status = acpi_get_devices(ACPI_EC_HID,
                                  acpi_fake_ecdt_callback, NULL, NULL);
@@ -1355,23 +897,15 @@ static int __init acpi_ec_fake_ecdt(void)
                kfree(ec_ecdt);
                ec_ecdt = NULL;
                ret = -ENODEV;
+               ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
                goto error;
        }
        return 0;
-      error:
-       printk(KERN_ERR PREFIX "Can't make an fake ECDT\n");
+  error:
        return ret;
 }
 
 static int __init acpi_ec_get_real_ecdt(void)
-{
-       if (acpi_ec_poll_mode)
-               return acpi_ec_poll_get_real_ecdt();
-       else
-               return acpi_ec_intr_get_real_ecdt();
-}
-
-static int __init acpi_ec_poll_get_real_ecdt(void)
 {
        acpi_status status;
        struct acpi_table_ecdt *ecdt_ptr;
@@ -1382,80 +916,36 @@ static int __init acpi_ec_poll_get_real_ecdt(void)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       printk(KERN_INFO PREFIX "Found ECDT\n");
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
 
        /*
         * Generate a temporary ec context to use until the namespace is scanned
         */
-       ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+       ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
        if (!ec_ecdt)
                return -ENOMEM;
-       memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
-       ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
-       ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
-       ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
-       ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
-       init_MUTEX(&ec_ecdt->poll.sem);
-       /* use the GL just to be safe */
-       ec_ecdt->common.global_lock = TRUE;
-       ec_ecdt->common.uid = ecdt_ptr->uid;
+       memset(ec_ecdt, 0, sizeof(struct acpi_ec));
 
-       status =
-           acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
-       if (ACPI_FAILURE(status)) {
-               goto error;
+       init_MUTEX(&ec_ecdt->sem);
+       if (acpi_ec_mode == EC_INTR) {
+               init_waitqueue_head(&ec_ecdt->wait);
        }
-
-       return 0;
-      error:
-       printk(KERN_ERR PREFIX "Could not use ECDT\n");
-       kfree(ec_ecdt);
-       ec_ecdt = NULL;
-
-       return -ENODEV;
-}
-
-static int __init acpi_ec_intr_get_real_ecdt(void)
-{
-       acpi_status status;
-       struct acpi_table_ecdt *ecdt_ptr;
-
-       status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
-                                        (struct acpi_table_header **)
-                                        &ecdt_ptr);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       printk(KERN_INFO PREFIX "Found ECDT\n");
-
-       /*
-        * Generate a temporary ec context to use until the namespace is scanned
-        */
-       ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
-       if (!ec_ecdt)
-               return -ENOMEM;
-       memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
-       init_MUTEX(&ec_ecdt->intr.sem);
-       init_waitqueue_head(&ec_ecdt->intr.wait);
-       ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
-       ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
-       ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
-       ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
+       ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
+       ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
+       ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
        /* use the GL just to be safe */
-       ec_ecdt->common.global_lock = TRUE;
-       ec_ecdt->common.uid = ecdt_ptr->uid;
+       ec_ecdt->global_lock = TRUE;
+       ec_ecdt->uid = ecdt_ptr->uid;
 
        status =
-           acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
+           acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
        if (ACPI_FAILURE(status)) {
                goto error;
        }
 
        return 0;
-      error:
-       printk(KERN_ERR PREFIX "Could not use ECDT\n");
+  error:
+       ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
        kfree(ec_ecdt);
        ec_ecdt = NULL;
 
@@ -1480,14 +970,14 @@ int __init acpi_ec_ecdt_probe(void)
        /*
         * Install GPE handler
         */
-       status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+       status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
                                          ACPI_GPE_EDGE_TRIGGERED,
                                          &acpi_ec_gpe_handler, ec_ecdt);
        if (ACPI_FAILURE(status)) {
                goto error;
        }
-       acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-       acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR);
+       acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+       acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
 
        status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
                                                    ACPI_ADR_SPACE_EC,
@@ -1495,7 +985,7 @@ int __init acpi_ec_ecdt_probe(void)
                                                    &acpi_ec_space_setup,
                                                    ec_ecdt);
        if (ACPI_FAILURE(status)) {
-               acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+               acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
                                        &acpi_ec_gpe_handler);
                goto error;
        }
@@ -1503,7 +993,7 @@ int __init acpi_ec_ecdt_probe(void)
        return 0;
 
       error:
-       printk(KERN_ERR PREFIX "Could not use ECDT\n");
+       ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
        kfree(ec_ecdt);
        ec_ecdt = NULL;
 
@@ -1562,13 +1052,13 @@ static int __init acpi_ec_set_intr_mode(char *str)
                return 0;
 
        if (intr) {
-               acpi_ec_poll_mode = EC_INTR;
-               acpi_ec_driver.ops.add = acpi_ec_intr_add;
+               acpi_ec_mode = EC_INTR;
        } else {
-               acpi_ec_poll_mode = EC_POLL;
-               acpi_ec_driver.ops.add = acpi_ec_poll_add;
+               acpi_ec_mode = EC_POLL;
        }
-       printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling");
+       acpi_ec_driver.ops.add = acpi_ec_add;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));
+
        return 1;
 }
 
index 6eef4ef..ee2a10b 100644 (file)
@@ -342,20 +342,8 @@ static u32 acpi_ev_global_lock_handler(void *context)
        if (acquired) {
 
                /* Got the lock, now wake all threads waiting for it */
-
                acpi_gbl_global_lock_acquired = TRUE;
-
-               /* Run the Global Lock thread which will signal all waiting threads */
-
-               status =
-                   acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
-                                   acpi_ev_global_lock_thread, context);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_EXCEPTION((AE_INFO, status,
-                                       "Could not queue Global Lock thread"));
-
-                       return (ACPI_INTERRUPT_NOT_HANDLED);
-               }
+               acpi_ev_global_lock_thread(context);
        }
 
        return (ACPI_INTERRUPT_HANDLED);
index 5b3c7a8..203d135 100644 (file)
@@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
                                if (!
                                    (ACPI_STRNCMP
                                     (object_hID.value, PCI_ROOT_HID_STRING,
-                                     sizeof(PCI_ROOT_HID_STRING))
-                                    ||
-                                    !(ACPI_STRNCMP
-                                      (object_hID.value,
-                                       PCI_EXPRESS_ROOT_HID_STRING,
-                                       sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
-                               {
+                                     sizeof(PCI_ROOT_HID_STRING)))
+                                   ||
+                                   !(ACPI_STRNCMP
+                                     (object_hID.value,
+                                      PCI_EXPRESS_ROOT_HID_STRING,
+                                      sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
 
                                        /* Install a handler for this PCI root bridge */
 
index 15fc124..003a987 100644 (file)
@@ -1702,13 +1702,11 @@ static struct ibm_struct ibms[] = {
         .name = "brightness",
         .read = brightness_read,
         .write = brightness_write,
-        .experimental = 1,
         },
        {
         .name = "volume",
         .read = volume_read,
         .write = volume_write,
-        .experimental = 1,
         },
        {
         .name = "fan",
index 068fe4f..c84286c 100644 (file)
@@ -73,6 +73,7 @@ static unsigned int acpi_irq_irq;
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
+static struct workqueue_struct *kacpi_notify_wq;
 
 acpi_status acpi_os_initialize(void)
 {
@@ -91,8 +92,9 @@ acpi_status acpi_os_initialize1(void)
                return AE_NULL_ENTRY;
        }
        kacpid_wq = create_singlethread_workqueue("kacpid");
+       kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
        BUG_ON(!kacpid_wq);
-
+       BUG_ON(!kacpi_notify_wq);
        return AE_OK;
 }
 
@@ -104,6 +106,7 @@ acpi_status acpi_os_terminate(void)
        }
 
        destroy_workqueue(kacpid_wq);
+       destroy_workqueue(kacpi_notify_wq);
 
        return AE_OK;
 }
@@ -566,10 +569,7 @@ void acpi_os_derive_pci_id(acpi_handle rhandle,    /* upper bound  */
 
 static void acpi_os_execute_deferred(void *context)
 {
-       struct acpi_os_dpc *dpc = NULL;
-
-
-       dpc = (struct acpi_os_dpc *)context;
+       struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
        if (!dpc) {
                printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
                return;
@@ -604,14 +604,12 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        struct acpi_os_dpc *dpc;
        struct work_struct *task;
 
-       ACPI_FUNCTION_TRACE("os_queue_for_execution");
-
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
 
        if (!function)
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               return AE_BAD_PARAMETER;
 
        /*
         * Allocate/initialize DPC structure.  Note that this memory will be
@@ -624,26 +622,20 @@ acpi_status acpi_os_execute(acpi_execute_type type,
         * from the same memory.
         */
 
-       dpc =
-           kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
-                   GFP_ATOMIC);
+       dpc = kmalloc(sizeof(struct acpi_os_dpc) +
+                       sizeof(struct work_struct), GFP_ATOMIC);
        if (!dpc)
-               return_ACPI_STATUS(AE_NO_MEMORY);
-
+               return AE_NO_MEMORY;
        dpc->function = function;
        dpc->context = context;
-
        task = (void *)(dpc + 1);
        INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
-
-       if (!queue_work(kacpid_wq, task)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "Call to queue_work() failed.\n"));
-               kfree(dpc);
+       if (!queue_work((type == OSL_NOTIFY_HANDLER)?
+                       kacpi_notify_wq : kacpid_wq, task)) {
                status = AE_ERROR;
+               kfree(dpc);
        }
-
-       return_ACPI_STATUS(status);
+       return status;
 }
 
 EXPORT_SYMBOL(acpi_os_execute);
index 8537c42..526387d 100644 (file)
@@ -219,6 +219,23 @@ static void acpi_safe_halt(void)
 
 static atomic_t c3_cpu_count;
 
+/* Common C-state entry for C2, C3, .. */
+static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
+{
+       if (cstate->space_id == ACPI_CSTATE_FFH) {
+               /* Call into architectural FFH based C-state */
+               acpi_processor_ffh_cstate_enter(cstate);
+       } else {
+               int unused;
+               /* IO port based C-state */
+               inb(cstate->address);
+               /* Dummy wait op - must do something useless after P_LVL2 read
+                  because chipsets cannot guarantee that STPCLK# signal
+                  gets asserted in time to freeze execution properly. */
+               unused = inl(acpi_fadt.xpm_tmr_blk.address);
+       }
+}
+
 static void acpi_processor_idle(void)
 {
        struct acpi_processor *pr = NULL;
@@ -361,11 +378,7 @@ static void acpi_processor_idle(void)
                /* Get start time (ticks) */
                t1 = inl(acpi_fadt.xpm_tmr_blk.address);
                /* Invoke C2 */
-               inb(cx->address);
-               /* Dummy wait op - must do something useless after P_LVL2 read
-                  because chipsets cannot guarantee that STPCLK# signal
-                  gets asserted in time to freeze execution properly. */
-               t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+               acpi_cstate_enter(cx);
                /* Get end time (ticks) */
                t2 = inl(acpi_fadt.xpm_tmr_blk.address);
 
@@ -401,9 +414,7 @@ static void acpi_processor_idle(void)
                /* Get start time (ticks) */
                t1 = inl(acpi_fadt.xpm_tmr_blk.address);
                /* Invoke C3 */
-               inb(cx->address);
-               /* Dummy wait op (see above) */
-               t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+               acpi_cstate_enter(cx);
                /* Get end time (ticks) */
                t2 = inl(acpi_fadt.xpm_tmr_blk.address);
                if (pr->flags.bm_check) {
@@ -628,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
        return 0;
 }
 
-static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
+static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
 {
-
-       /* Zero initialize all the C-states info. */
-       memset(pr->power.states, 0, sizeof(pr->power.states));
-
-       /* set the first C-State to C1 */
-       pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
-
-       /* the C0 state only exists as a filler in our array,
-        * and all processors need to support C1 */
+       if (!pr->power.states[ACPI_STATE_C1].valid) {
+               /* set the first C-State to C1 */
+               /* all processors need to support C1 */
+               pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+               pr->power.states[ACPI_STATE_C1].valid = 1;
+       }
+       /* the C0 state only exists as a filler in our array */
        pr->power.states[ACPI_STATE_C0].valid = 1;
-       pr->power.states[ACPI_STATE_C1].valid = 1;
-
        return 0;
 }
 
@@ -658,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
        if (nocst)
                return -ENODEV;
 
-       current_count = 1;
-
-       /* Zero initialize C2 onwards and prepare for fresh CST lookup */
-       for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
-               memset(&(pr->power.states[i]), 0, 
-                               sizeof(struct acpi_processor_cx));
+       current_count = 0;
 
        status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
        if (ACPI_FAILURE(status)) {
@@ -718,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
                    (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
                        continue;
 
-               cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
-                   0 : reg->address;
-
                /* There should be an easy way to extract an integer... */
                obj = (union acpi_object *)&(element->package.elements[1]);
                if (obj->type != ACPI_TYPE_INTEGER)
                        continue;
 
                cx.type = obj->integer.value;
-
-               if ((cx.type != ACPI_STATE_C1) &&
-                   (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
-                       continue;
-
-               if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
-                       continue;
+               /*
+                * Some buggy BIOSes won't list C1 in _CST -
+                * Let acpi_processor_get_power_info_default() handle them later
+                */
+               if (i == 1 && cx.type != ACPI_STATE_C1)
+                       current_count++;
+
+               cx.address = reg->address;
+               cx.index = current_count + 1;
+
+               cx.space_id = ACPI_CSTATE_SYSTEMIO;
+               if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+                       if (acpi_processor_ffh_cstate_probe
+                                       (pr->id, &cx, reg) == 0) {
+                               cx.space_id = ACPI_CSTATE_FFH;
+                       } else if (cx.type != ACPI_STATE_C1) {
+                               /*
+                                * C1 is a special case where FIXED_HARDWARE
+                                * can be handled in non-MWAIT way as well.
+                                * In that case, save this _CST entry info.
+                                * That is, we retain space_id of SYSTEM_IO for
+                                * halt based C1.
+                                * Otherwise, ignore this info and continue.
+                                */
+                               continue;
+                       }
+               }
 
                obj = (union acpi_object *)&(element->package.elements[2]);
                if (obj->type != ACPI_TYPE_INTEGER)
@@ -938,12 +957,18 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
        /* NOTE: the idle thread may not be running while calling
         * this function */
 
-       /* Adding C1 state */
-       acpi_processor_get_power_info_default_c1(pr);
+       /* Zero initialize all the C-states info. */
+       memset(pr->power.states, 0, sizeof(pr->power.states));
+
        result = acpi_processor_get_power_info_cst(pr);
        if (result == -ENODEV)
                acpi_processor_get_power_info_fadt(pr);
 
+       if (result)
+               return result;
+
+       acpi_processor_get_power_info_default(pr);
+
        pr->power.count = acpi_processor_power_verify(pr);
 
        /*
index 62bef0b..8908a97 100644 (file)
@@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INFO_MODE;
 static int update_time = UPDATE_TIME;
 static int update_time2 = UPDATE_TIME2;
 
-module_param(capacity_mode, int, CAPACITY_UNIT);
-module_param(update_mode, int, UPDATE_MODE);
-module_param(update_info_mode, int, UPDATE_INFO_MODE);
-module_param(update_time, int, UPDATE_TIME);
-module_param(update_time2, int, UPDATE_TIME2);
+module_param(capacity_mode, int, 0);
+module_param(update_mode, int, 0);
+module_param(update_info_mode, int, 0);
+module_param(update_time, int, 0);
+module_param(update_time2, int, 0);
 
 static int acpi_sbs_add(struct acpi_device *device);
 static int acpi_sbs_remove(struct acpi_device *device, int type);
@@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_device *device)
 
 int acpi_sbs_remove(struct acpi_device *device, int type)
 {
-       struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
+       struct acpi_sbs *sbs = NULL;
        int id;
 
-       if (!device || !sbs) {
+       if (!device) {
+               return -EINVAL;
+       }
+
+       sbs = (struct acpi_sbs *)acpi_driver_data(device);
+
+       if (!sbs) {
                return -EINVAL;
        }
 
index 3df0e7a..fa7acc2 100644 (file)
@@ -57,4 +57,23 @@ config TIFM_7XX1
           To compile this driver as a module, choose M here: the module will
          be called tifm_7xx1.
 
+config MSI_LAPTOP
+        tristate "MSI Laptop Extras"
+        depends on X86
+        depends on ACPI_EC
+        depends on BACKLIGHT_CLASS_DEVICE
+        ---help---
+         This is a driver for laptops built by MSI (MICRO-STAR
+         INTERNATIONAL):
+
+         MSI MegaBook S270 (MS-1013)
+         Cytron/TCM/Medion/Tchibo MD96100/SAM2000
+
+         It adds support for Bluetooth, WLAN and LCD brightness control.
+
+         More information about this driver is available at
+         <http://0pointer.de/lennart/tchibo.html>.
+
+         If you have an MSI S270 laptop, say Y or M here.
+
 endmenu
index d65ece7..9a91c1e 100644 (file)
@@ -5,6 +5,7 @@ obj- := misc.o  # Dummy rule to force built-in.o to be made
 
 obj-$(CONFIG_IBM_ASM)          += ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)    += hdpuftrs/
+obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
 obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
new file mode 100644 (file)
index 0000000..fdb7153
--- /dev/null
@@ -0,0 +1,395 @@
+/*-*-linux-c-*-*/
+
+/*
+  Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301, USA.
+ */
+
+/*
+ * msi-laptop.c - MSI S270 laptop support. This laptop is sold under
+ * various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
+ *
+ * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
+ *
+ *   lcd_level - Screen brightness: contains a single integer in the
+ *   range 0..8. (rw)
+ *
+ *   auto_brightness - Enable automatic brightness control: contains
+ *   either 0 or 1. If set to 1 the hardware adjusts the screen
+ *   brightness automatically when the power cord is
+ *   plugged/unplugged. (rw)
+ *
+ *   wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
+ *
+ *   bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
+ *   Please note that this file is constantly 0 if no Bluetooth
+ *   hardware is available. (ro)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control subsystem and is
+ * available to userspace under /sys/class/backlight/msi-laptop-bl/.
+ *
+ * This driver might work on other laptops produced by MSI. If you
+ * want to try it you can pass force=1 as argument to the module which
+ * will force it to load even when the DMI data doesn't identify the
+ * laptop as MSI S270. YMMV.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/autoconf.h>
+
+#define MSI_DRIVER_VERSION "0.5"
+
+#define MSI_LCD_LEVEL_MAX 9
+
+#define MSI_EC_COMMAND_WIRELESS 0x10
+#define MSI_EC_COMMAND_LCD_LEVEL 0x11
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static int auto_brightness;
+module_param(auto_brightness, int, 0);
+MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
+
+/* Hardware access */
+
+static int set_lcd_level(int level)
+{
+       u8 buf[2];
+
+       if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
+               return -EINVAL;
+
+       buf[0] = 0x80;
+       buf[1] = (u8) (level*31);
+
+       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
+}
+
+static int get_lcd_level(void)
+{
+       u8 wdata = 0, rdata;
+       int result;
+
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+       if (result < 0)
+               return result;
+
+       return (int) rdata / 31;
+}
+
+static int get_auto_brightness(void)
+{
+       u8 wdata = 4, rdata;
+       int result;
+
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+       if (result < 0)
+               return result;
+
+       return !!(rdata & 8);
+}
+
+static int set_auto_brightness(int enable)
+{
+       u8 wdata[2], rdata;
+       int result;
+
+       wdata[0] = 4;
+
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1);
+       if (result < 0)
+               return result;
+
+       wdata[0] = 0x84;
+       wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
+
+       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0);
+}
+
+static int get_wireless_state(int *wlan, int *bluetooth)
+{
+       u8 wdata = 0, rdata;
+       int result;
+
+       result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
+       if (result < 0)
+               return -1;
+
+       if (wlan)
+               *wlan = !!(rdata & 8);
+
+       if (bluetooth)
+               *bluetooth = !!(rdata & 128);
+
+       return 0;
+}
+
+/* Backlight device stuff */
+
+static int bl_get_brightness(struct backlight_device *b)
+{
+       return get_lcd_level();
+}
+
+
+static int bl_update_status(struct backlight_device *b)
+{
+       return set_lcd_level(b->props->brightness);
+}
+
+static struct backlight_properties msibl_props = {
+       .owner          = THIS_MODULE,
+       .get_brightness = bl_get_brightness,
+       .update_status  = bl_update_status,
+       .max_brightness = MSI_LCD_LEVEL_MAX-1,
+};
+
+static struct backlight_device *msibl_device;
+
+/* Platform device */
+
+static ssize_t show_wlan(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+
+       int ret, enabled;
+
+       ret = get_wireless_state(&enabled, NULL);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_bluetooth(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+
+       int ret, enabled;
+
+       ret = get_wireless_state(NULL, &enabled);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_lcd_level(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+
+       int ret;
+
+       ret = get_lcd_level();
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_lcd_level(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+
+       int level, ret;
+
+       if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
+               return -EINVAL;
+
+       ret = set_lcd_level(level);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static ssize_t show_auto_brightness(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+
+       int ret;
+
+       ret = get_auto_brightness();
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_auto_brightness(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+
+       int enable, ret;
+
+       if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
+               return -EINVAL;
+
+       ret = set_auto_brightness(enable);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
+static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
+static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
+static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
+
+static struct attribute *msipf_attributes[] = {
+       &dev_attr_lcd_level.attr,
+       &dev_attr_auto_brightness.attr,
+       &dev_attr_bluetooth.attr,
+       &dev_attr_wlan.attr,
+       NULL
+};
+
+static struct attribute_group msipf_attribute_group = {
+       .attrs = msipf_attributes
+};
+
+static struct platform_driver msipf_driver = {
+       .driver = {
+               .name = "msi-laptop-pf",
+               .owner = THIS_MODULE,
+       }
+};
+
+static struct platform_device *msipf_device;
+
+/* Initialization */
+
+static struct dmi_system_id __initdata msi_dmi_table[] = {
+       {
+               .ident = "MSI S270",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
+               }
+       },
+       {
+               .ident = "Medion MD96100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
+               }
+       },
+       { }
+};
+
+
+static int __init msi_init(void)
+{
+       int ret;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (!force && !dmi_check_system(msi_dmi_table))
+               return -ENODEV;
+
+       if (auto_brightness < 0 || auto_brightness > 2)
+               return -EINVAL;
+
+       /* Register backlight stuff */
+
+       msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
+       if (IS_ERR(msibl_device))
+               return PTR_ERR(msibl_device);
+
+       ret = platform_driver_register(&msipf_driver);
+       if (ret)
+               goto fail_backlight;
+
+       /* Register platform stuff */
+
+       msipf_device = platform_device_alloc("msi-laptop-pf", -1);
+       if (!msipf_device) {
+               ret = -ENOMEM;
+               goto fail_platform_driver;
+       }
+
+       ret = platform_device_add(msipf_device);
+       if (ret)
+               goto fail_platform_device1;
+
+       ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+       if (ret)
+               goto fail_platform_device2;
+
+       /* Disable automatic brightness control by default because
+        * this module was probably loaded to do brightness control in
+        * software. */
+
+       if (auto_brightness != 2)
+               set_auto_brightness(auto_brightness);
+
+       printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
+
+       return 0;
+
+fail_platform_device2:
+
+       platform_device_del(msipf_device);
+
+fail_platform_device1:
+
+       platform_device_put(msipf_device);
+
+fail_platform_driver:
+
+       platform_driver_unregister(&msipf_driver);
+
+fail_backlight:
+
+       backlight_device_unregister(msibl_device);
+
+       return ret;
+}
+
+static void __exit msi_cleanup(void)
+{
+
+       sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+       platform_device_unregister(msipf_device);
+       platform_driver_unregister(&msipf_driver);
+       backlight_device_unregister(msibl_device);
+
+       /* Enable automatic brightness control again */
+       if (auto_brightness != 2)
+               set_auto_brightness(1);
+
+       printk(KERN_INFO "msi-laptop: driver unloaded.\n");
+}
+
+module_init(msi_init);
+module_exit(msi_cleanup);
+
+MODULE_AUTHOR("Lennart Poettering");
+MODULE_DESCRIPTION("MSI Laptop Support");
+MODULE_VERSION(MSI_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
index c5472be..e72bfdd 100644 (file)
@@ -13,6 +13,7 @@
 #define ACPI_PDC_SMP_C_SWCOORD         (0x0040)
 #define ACPI_PDC_SMP_T_SWCOORD         (0x0080)
 #define ACPI_PDC_C_C1_FFH              (0x0100)
+#define ACPI_PDC_C_C2C3_FFH            (0x0200)
 
 #define ACPI_PDC_EST_CAPABILITY_SMP    (ACPI_PDC_SMP_C1PT | \
                                         ACPI_PDC_C_C1_HALT | \
                                         ACPI_PDC_SMP_P_SWCOORD | \
                                         ACPI_PDC_P_FFH)
 
-#define ACPI_PDC_C_CAPABILITY_SMP      (ACPI_PDC_SMP_C2C3 | \
-                                        ACPI_PDC_SMP_C1PT | \
-                                        ACPI_PDC_C_C1_HALT)
+#define ACPI_PDC_C_CAPABILITY_SMP      (ACPI_PDC_SMP_C2C3  | \
+                                        ACPI_PDC_SMP_C1PT  | \
+                                        ACPI_PDC_C_C1_HALT | \
+                                        ACPI_PDC_C_C1_FFH  | \
+                                        ACPI_PDC_C_C2C3_FFH)
 
 #endif                         /* __PDC_INTEL_H__ */
index 9dd5b75..7798d2a 100644 (file)
@@ -29,6 +29,9 @@
 #define DOMAIN_COORD_TYPE_SW_ANY       0xfd
 #define DOMAIN_COORD_TYPE_HW_ALL       0xfe
 
+#define ACPI_CSTATE_SYSTEMIO   (0)
+#define ACPI_CSTATE_FFH                (1)
+
 /* Power Management */
 
 struct acpi_processor_cx;
@@ -58,6 +61,8 @@ struct acpi_processor_cx {
        u8 valid;
        u8 type;
        u32 address;
+       u8 space_id;
+       u8 index;
        u32 latency;
        u32 latency_ticks;
        u32 power;
@@ -206,6 +211,9 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
 #ifdef ARCH_HAS_POWER_INIT
 void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
                                        unsigned int cpu);
+int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+               struct acpi_processor_cx *cx, struct acpi_power_register *reg);
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
 #else
 static inline void acpi_processor_power_init_bm_check(struct
                                                      acpi_processor_flags
@@ -214,6 +222,16 @@ static inline void acpi_processor_power_init_bm_check(struct
        flags->bm_check = 1;
        return;
 }
+static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+               struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+{
+       return -1;
+}
+static inline void acpi_processor_ffh_cstate_enter(
+               struct acpi_processor_cx *cstate)
+{
+       return;
+}
 #endif
 
 /* in processor_perflib.c */
index 2277127..e0ddca9 100644 (file)
@@ -306,6 +306,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
                : :"a" (eax), "c" (ecx));
 }
 
+extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
+
 /* from system description table in BIOS.  Mostly for MCA use, but
 others may find it useful. */
 extern unsigned int machine_id;
index de9c314..cef17e0 100644 (file)
@@ -475,6 +475,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
                : :"a" (eax), "c" (ecx));
 }
 
+extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
+
 #define stack_current() \
 ({                                                             \
        struct thread_info *ti;                                 \
index 88b5dfd..2b0c955 100644 (file)
@@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
 
 extern int ec_read(u8 addr, u8 *val);
 extern int ec_write(u8 addr, u8 val);
+extern int ec_transaction(u8 command,
+                          const u8 *wdata, unsigned wdata_len,
+                          u8 *rdata, unsigned rdata_len);
 
 #endif /*CONFIG_ACPI_EC*/