aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-10-15 11:02:52 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-15 11:02:52 -0700
commit0b269d8462a9f0058afb46eaee56e0732acf16c4 (patch)
treef6f5d801b0f991b34b7a71394370fc31746883bb
parented75ded7dd3fdb647df4efefc5d11158e3d182be (diff)
parent9aaed2b42d00d4abb2748d72d599a8033600e2bf (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (28 commits) ACPI: check battery status on resume for un/plug events during sleep ACPICA: Fix incorrect handling of PCI Express Root Bridge _HID ACPI: asus_acpi: don't printk on writing garbage to proc files ACPI: asus_acpi: fix proc files parsing ACPI: SCI interrupt source override ACPI: fix printk format warnings ACPI: fix section for CPU init functions ACPI: update comments in motherboard.c ACPI: acpi_pci_link_set() can allocate with either GFP_ATOMIC or GFP_KERNEL ACPI: fix potential OOPS in power driver with CONFIG_ACPI_DEBUG ACPI: ibm_acpi: delete obsolete documentation ACPI: created a dedicated workqueue for notify() execution ACPI: Remove deferred execution from global lock acquire wakeup path MSI S270 Laptop support: backlight, wlan, bluetooth states ACPI: EC: export ec_transaction() for msi-laptop driver ACPI: EC: Simplify acpi_hw_low_level*() with inb()/outb(). ACPI: EC: Unify poll and interrupt gpe handlers ACPI: EC: Unify poll and interrupt mode transaction functions ACPI: EC: Remove unused variables and duplicated code ACPI: EC: Remove unnecessary delay added by previous transation patch. ...
-rw-r--r--Documentation/ibm-acpi.txt75
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/i386/kernel/acpi/boot.c10
-rw-r--r--arch/i386/kernel/acpi/cstate.c122
-rw-r--r--arch/i386/kernel/process.c22
-rw-r--r--arch/x86_64/kernel/process.c22
-rw-r--r--drivers/acpi/asus_acpi.c67
-rw-r--r--drivers/acpi/battery.c14
-rw-r--r--drivers/acpi/ec.c1096
-rw-r--r--drivers/acpi/events/evmisc.c14
-rw-r--r--drivers/acpi/events/evrgnini.c13
-rw-r--r--drivers/acpi/ibm_acpi.c2
-rw-r--r--drivers/acpi/motherboard.c6
-rw-r--r--drivers/acpi/osl.c34
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/power.c9
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_idle.c103
-rw-r--r--drivers/acpi/sbs.c20
-rw-r--r--drivers/acpi/tables/tbget.c2
-rw-r--r--drivers/acpi/tables/tbrsdt.c2
-rw-r--r--drivers/misc/Kconfig19
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/msi-laptop.c395
-rw-r--r--include/acpi/pdc_intel.h9
-rw-r--r--include/acpi/processor.h18
-rw-r--r--include/asm-i386/processor.h2
-rw-r--r--include/asm-x86_64/processor.h2
-rw-r--r--include/linux/acpi.h3
29 files changed, 1088 insertions, 1005 deletions
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
index 71aa4034527..e50595bfd8e 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/ibm-acpi.txt
@@ -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
------------------------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index 1b5430a49fd..a2b6d9fa350 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 92f79cdd9a4..ab974ff9707 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -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();
diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c
index 25db49ef177..20563e52c62 100644
--- a/arch/i386/kernel/acpi/cstate.c
+++ b/arch/i386/kernel/acpi/cstate.c
@@ -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);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index b0a07801d9d..57d375900af 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -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)) {
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 5e95b257ee2..49f7fac6229 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -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;
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index e9ee4c52a5f..c7ac9297a20 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -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;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 9810e2a55d0..026e40755cd 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -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;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e5d79636285..e6d4b084dca 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -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 (