summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-01-16 12:56:15 +1100
committerStephen Rothwell <sfr@canb.auug.org.au>2009-01-16 12:56:15 +1100
commit1aa0144b7b0efa0fc1ba45171a07647793e69984 (patch)
tree0b8c1225cd3d886e902949fe3f33606381ba0e61
parent7ecd661e06385157141a0e8edaa2839637e5f72d (diff)
parent073ce4be3d0550c93664f18845831a86388b9f55 (diff)
Merge commit 'acpi/test'
-rw-r--r--MAINTAINERS5
-rw-r--r--arch/ia64/kernel/kprobes.c2
-rw-r--r--arch/x86/kernel/kprobes.c2
-rw-r--r--drivers/acpi/pci_link.c39
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/platform/x86/Kconfig25
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/dell-laptop.c (renamed from drivers/misc/dell-laptop.c)2
-rw-r--r--drivers/platform/x86/eeepc-laptop.c4
-rw-r--r--drivers/platform/x86/oqo-wmi.c941
-rw-r--r--include/acpi/actbl.h2
-rw-r--r--kernel/kprobes.c2
-rw-r--r--kernel/power/Makefile3
13 files changed, 1000 insertions, 30 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c9eb6b5a6c7b..a5975c5f52d9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3245,6 +3245,11 @@ M: robert.richter@amd.com
L: oprofile-list@lists.sf.net
S: Maintained
+OQO WMI EXTRAS DRIVER
+P: Matthew Garrett
+M: mjg59@srcf.ucam.org
+S: Maintained
+
ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
P: Mark Fasheh
M: mfasheh@suse.com
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index f90be51b1123..9adac441ac9b 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -870,7 +870,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
return 1;
ss_probe:
-#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER)
if (p->ainsn.inst_flag == INST_FLAG_BOOSTABLE && !p->post_handler) {
/* Boost up -- we can execute copied instructions directly */
ia64_psr(regs)->ri = p->ainsn.slot;
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 884d985b8b82..e948b28a5a9a 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -446,7 +446,7 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
-#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER)
if (p->ainsn.boostable == 1 && !p->post_handler) {
/* Boost up -- we can execute copied instructions directly */
reset_current_kprobe();
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 1c6e73c7865e..4b084d8dc85b 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -414,7 +414,8 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
link->irq.active = irq;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link %s set to IRQ %d\n",
+ acpi_device_bid(link->device), link->irq.active));
end:
kfree(resource);
@@ -649,6 +650,9 @@ acpi_pci_link_allocate_irq(acpi_handle handle,
return -1;
}
link->refcnt++;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Link %s is referenced %d\n",
+ acpi_device_bid(link->device), link->refcnt));
mutex_unlock(&acpi_link_lock);
if (triggering)
@@ -657,9 +661,6 @@ acpi_pci_link_allocate_irq(acpi_handle handle,
*polarity = link->irq.polarity;
if (name)
*name = acpi_device_bid(link->device);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Link %s is referenced\n",
- acpi_device_bid(link->device)));
return (link->irq.active);
}
@@ -692,23 +693,15 @@ int acpi_pci_link_free_irq(acpi_handle handle)
printk(KERN_ERR PREFIX "Link isn't initialized\n");
return -1;
}
-#ifdef FUTURE_USE
- /*
- * The Link reference count allows us to _DISable an unused link
- * and suspend time, and set it again on resume.
- * However, 2.6.12 still has irq_router.resume
- * which blindly restores the link state.
- * So we disable the reference count method
- * to prevent duplicate acpi_pci_link_set()
- * which would harm some systems
- */
link->refcnt--;
-#endif
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Link %s is dereferenced\n",
- acpi_device_bid(link->device)));
+ "Link %s is dereferenced %d\n",
+ acpi_device_bid(link->device), link->refcnt));
if (link->refcnt == 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Link %s is disabled\n",
+ acpi_device_bid(link->device)));
acpi_evaluate_object(link->device->handle, "_DIS", NULL, NULL);
}
mutex_unlock(&acpi_link_lock);
@@ -782,13 +775,17 @@ static int acpi_pci_link_add(struct acpi_device *device)
return result;
}
-static int acpi_pci_link_resume(struct acpi_pci_link *link)
+static void acpi_pci_link_resume(struct acpi_pci_link *link)
{
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link %s resume ref %d act %d ini %d\n",
+ acpi_device_bid(link->device), link->refcnt,
+ link->irq.active, link->irq.initialized));
+
if (link->refcnt && link->irq.active && link->irq.initialized)
- return (acpi_pci_link_set(link, link->irq.active));
- else
- return 0;
+ acpi_pci_link_set(link, link->irq.active);
+
+ return;
}
static int irqrouter_resume(struct sys_device *dev)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 9cf8ae6e4b39..d5749a7bc777 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
-obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index e65448e99b48..017fb8173425 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -54,6 +54,18 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
+config DELL_LAPTOP
+ tristate "Dell Laptop Extras (EXPERIMENTAL)"
+ depends on X86
+ depends on DCDBAS
+ depends on EXPERIMENTAL
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL
+ default n
+ ---help---
+ This driver adds support for rfkill and backlight control to Dell
+ laptops.
+
config FUJITSU_LAPTOP
tristate "Fujitsu Laptop Extras"
depends on ACPI
@@ -120,6 +132,19 @@ config MSI_LAPTOP
If you have an MSI S270 laptop, say Y or M here.
+config OQO_WMI
+ tristate "OQO WMI extras"
+ depends on ACPI_WMI
+ depends on INPUT
+ depends on RFKILL
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to support rfkill and backlight control on
+ series 2 OQO handheld devices.
+
+ To compile this driver as a module, choose M here: the module will
+ be called oqo-wmi.
+
config PANASONIC_LAPTOP
tristate "Panasonic Laptop Extras"
depends on INPUT && ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 1e9de2ae0de5..37ac07f2362d 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -6,12 +6,14 @@ obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
+obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
+obj-$(CONFIG_OQO_WMI) += oqo-wmi.o
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
diff --git a/drivers/misc/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 4d33a2068b7a..16e11c2ee19a 100644
--- a/drivers/misc/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -22,7 +22,7 @@
#include <linux/rfkill.h>
#include <linux/power_supply.h>
#include <linux/acpi.h>
-#include "../firmware/dcdbas.h"
+#include "../../firmware/dcdbas.h"
#define BRIGHTNESS_TOKEN 0x7d
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 02fe2b8b8939..9d93cb971e59 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -90,7 +90,7 @@ enum {
};
static const char *cm_getv[] = {
- "WLDG", NULL, NULL, NULL,
+ "WLDG", "BTHG", NULL, NULL,
"CAMG", NULL, NULL, NULL,
NULL, "PBLG", NULL, NULL,
"CFVG", NULL, NULL, NULL,
@@ -99,7 +99,7 @@ static const char *cm_getv[] = {
};
static const char *cm_setv[] = {
- "WLDS", NULL, NULL, NULL,
+ "WLDS", "BTHS", NULL, NULL,
"CAMS", NULL, NULL, NULL,
"SDSP", "PBLS", "HDPS", NULL,
"CFVS", NULL, NULL, NULL,
diff --git a/drivers/platform/x86/oqo-wmi.c b/drivers/platform/x86/oqo-wmi.c
new file mode 100644
index 000000000000..940e605cb460
--- /dev/null
+++ b/drivers/platform/x86/oqo-wmi.c
@@ -0,0 +1,941 @@
+/*
+ * OQO WMI UPMC Extras
+ *
+ * Copyright (C) 2008 Brian S. Julin <bri@abrij.org>
+ *
+ * Based on acer-wmi:
+ * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * NOTE: You need to turn SMI on in BIOS (if dmidecode works, you already have)
+ * NOTE: acpi-wmi support mandatory
+ * NOTE: backlight and inputdev support a must, ifdefs will come later
+ */
+
+/*
+ *
+ * 0.3: added WLAN enable switch, restore settings on unload,
+ * resume/suspend handling
+ * 0.2: Still not production-ready, but added ambient light sensor,
+ * backlight, and it prints the unit serial number to dmesg (do
+ * not know where to make that available to userspace yet.)
+ * 0.1: This is a first cut. Plan to reboot after playing with this.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <linux/i8042.h>
+#include <linux/input-polldev.h>
+#include <linux/rfkill.h>
+
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Brian Julin");
+MODULE_DESCRIPTION("OQO UPMC WMI Extras Driver");
+MODULE_LICENSE("GPL");
+
+#define OQO_LOGPREFIX "oqo-wmi: "
+#define OQO_ERR KERN_ERR OQO_LOGPREFIX
+#define OQO_NOTICE KERN_NOTICE OQO_LOGPREFIX
+#define OQO_INFO KERN_INFO OQO_LOGPREFIX
+
+#define OQO_KINE_MAXTRY 3
+
+/* Store defined devices globally since we only have one instance. */
+static struct platform_device *oqo_platform_device;
+static struct backlight_device *oqo_backlight_device;
+static struct rfkill *oqo_rfkill;
+static struct input_dev *oqo_kine;
+static struct input_polled_dev *oqo_kine_polled;
+
+/* Likewise store current and original settings globally. */
+struct oqo_settings {
+ int lid_wakes; /* not sure if ACPI handles/needs help here */
+ int kine_itvl;
+ int bl_bright;
+};
+
+static struct oqo_settings orig, curr;
+
+/* Some of this code is left like in acer-wmi so we can add the older
+ Model 01 and any future models more easily, but we should not expect
+ it to be as complicated as Acer given each model is a leap rather than
+ a subtle variant on the last, so we aren't using "quirks" perse. Not
+ sure if there is any real difference for our purposes between the o2
+ and e2.
+*/
+struct oqo_model {
+ const char *model;
+ u16 model_subs;
+};
+#define MODEL_SUB_OQO_O2_SMB0 3
+
+static struct oqo_model oqo_models[] = {
+ {
+ .model = "Model 2",
+ .model_subs = MODEL_SUB_OQO_O2_SMB0,
+ },
+ {}
+};
+
+static struct oqo_model *model;
+
+static int force;
+module_param(force, bool, 0644);
+MODULE_PARM_DESC(force, "Force WMI detection even if DMI detection failed");
+
+/*
+ * OQO Model 2 SMBUS registers
+ * We are just using WMI to read the Cx700 smbus, to share the
+ * ACPI mutex (what may also eventually work in VMs/win32)
+ * Using i2c-viapro directly could interfere with PM.
+ */
+
+#define OQO_O2_SMB0_WWAN_DSBL_ADDR 0x19
+#define OQO_O2_SMB0_WWAN_DSBL_MASK 0x02
+#define OQO_O2_SMB0_LUMIN_LO 0x20
+#define OQO_O2_SMB0_LUMIN_HI 0x21
+#define OQO_O2_SMB0_BL_LO 0x26
+#define OQO_O2_SMB0_BL_HI 0x27
+#define OQO_O2_SMB0_ACCEL_POLL_ITVL 0x45
+#define OQO_O2_SMB0_ACCEL_XLO 0x50
+#define OQO_O2_SMB0_ACCEL_XHI 0x51
+#define OQO_O2_SMB0_ACCEL_YLO 0x52
+#define OQO_O2_SMB0_ACCEL_YHI 0x53
+#define OQO_O2_SMB0_ACCEL_ZLO 0x54
+#define OQO_O2_SMB0_ACCEL_ZHI 0x55
+/* These may be handled by ACPI not sure yet. */
+#define OQO_O2_SMB0_LID_WAKES_ADDR 0x58
+#define OQO_O2_SMB0_LID_WAKES_MASK 0x08
+
+#define OQO_O2_SMB0_SERIAL_START 0x70
+#define OQO_O2_SMB0_SERIAL_LEN 11
+
+static char oqo_sn[OQO_O2_SMB0_SERIAL_LEN + 1];
+
+/* Other addresses I have noticed used on the 02 SMBUS (from DSDT and whatnot)
+ *
+ * These are not used because the linux ACPI drivers work fine on them
+ *
+ * 0x0A -- processor sleep mode?
+ * 0x0C -- ACPI events, probably clears when read.
+ * 0x30 -- thermal zone
+ * There is something going on at 0x31 through 0x34 which is likely
+ * also thermal. The values change over time. Have not figured that
+ * out yet.
+ * 0x41 -- AC detect
+ * 0x42 -- LID button ACTUALLY THIS DOES NOT WORK AND NEEDS TO BE FIXED
+ * 0xa0 and 0xa1 -- battery something (presence? state?)
+ * 0xa4 to 0xcf -- battery info (0xc8-0xca contains "OQO")
+ * 0xd4 to 0xef -- other battery stats
+ */
+
+/*
+ * OQO method GUIDs
+ */
+#define OQO_O2_AMW0_GUID "ABBC0F6D-8EA1-11D1-00A0-C90629100000"
+MODULE_ALIAS("wmi:ABBC0F6D-8EA1-11D1-00A0-C90629100000");
+
+/*
+ * Interface type flags
+ */
+enum interface_type {
+ OQO_O2_AMW0,
+};
+
+/* Each low-level interface must define at least some of the following */
+struct wmi_interface {
+ /* The WMI device type */
+ u32 type;
+};
+
+static struct wmi_interface AMW0_interface = {
+ .type = OQO_O2_AMW0,
+};
+
+/* The detected/chosen interface */
+static struct wmi_interface *interface;
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+ model = dmi->driver_data;
+ /*
+ * Detect which ACPI-WMI interface we're using.
+ */
+ if (wmi_has_guid(OQO_O2_AMW0_GUID))
+ interface = &AMW0_interface;
+
+ return 0;
+}
+
+static struct dmi_system_id oqo_dmis[] = {
+ {
+ .callback = dmi_matched,
+ .ident = "OQO 02",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "OQO Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OQO Model 2"),
+ },
+ .driver_data = oqo_models + 0,
+ },
+ {}
+};
+
+/*
+ * AMW0 (V1) interface on OQO Model 2
+ *
+ * wmba: has four functions selected by int arg 1. arg2 is 3 byte buffer.
+ * 1: performs GETB method on the SMBUS using bytes 0, 1 of Arg2
+ * returns a buffer object containing a single byte
+ * 2: performs SETB on SMBUS using bytes 0, 1, 2 of Arg2
+ * returns 0 as int.
+ * 3: dumps 256 values into a given SMBUS register (not used here)
+ * returns 0 as int.
+ * 4: puts byte 0 of arg2 into some sort of busy flag. Some ACPI
+ * funcs check this (==0) to decide if SMBUS operations are safe.
+ * returns 0 as int.
+ * wmbb: simply returns the busy flag set by wmba #4
+ */
+static acpi_status oqo_smbus_getb(u8 addr, u8 *result)
+{
+ struct acpi_buffer input, res;
+ acpi_status status;
+ union acpi_object *obj;
+ u32 arg2;
+
+ input.length = 4;
+ input.pointer = &arg2;
+ res.length = ACPI_ALLOCATE_BUFFER;
+ res.pointer = NULL;
+
+ arg2 = addr;
+ arg2 <<= 8;
+ arg2 |= 0x12; /* HOSTCMD */
+
+ status = wmi_evaluate_method(OQO_O2_AMW0_GUID, 1, 1, &input, &res);
+
+ if (status != AE_OK)
+ return status;
+
+ obj = (union acpi_object *)res.pointer;
+ if (!obj)
+ return AE_NULL_OBJECT;
+
+ if (obj->type != ACPI_TYPE_BUFFER
+ || obj->buffer.length != 1 || obj->buffer.pointer == NULL) {
+ kfree(obj);
+ return AE_TYPE;
+ }
+ *result = ((u8 *) (obj->buffer.pointer))[0];
+ kfree(obj);
+ return status;
+}
+
+static acpi_status oqo_smbus_setb(u8 addr, u8 val)
+{
+ struct acpi_buffer input, res;
+ acpi_status status;
+ union acpi_object *obj;
+ u32 arg2;
+
+ input.length = 4;
+ input.pointer = &arg2;
+ res.length = ACPI_ALLOCATE_BUFFER;
+ res.pointer = NULL;
+
+ arg2 = val;
+ arg2 <<= 8;
+ arg2 |= addr;
+ arg2 <<= 8;
+ arg2 |= 0x12; /* HOSTCMD */
+
+ status = wmi_evaluate_method(OQO_O2_AMW0_GUID, 1, 2, &input, &res);
+
+ if (status != AE_OK)
+ return status;
+
+ obj = (union acpi_object *)res.pointer;
+ if (!obj)
+ return AE_NULL_OBJECT;
+
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ kfree(obj);
+ return AE_TYPE;
+ }
+ kfree(obj);
+ return status;
+}
+
+/*
+ * We assume we are the only one using this ...ahem... "lock" on
+ * the SMBUS because it would be pathetically noneffective otherwise.
+ *
+ * Nonzero silly_lock will keep certain ACPI routines away from the
+ * SMBUS (if they aren't already on it when you call it.) Zero
+ * silly_lock will let them back on
+ *
+ * This is probably useful before sleeping the system, and one
+ * waits until any ACPI funcs would have long finished before
+ * proceeding. It seems harmless enough and will work to wrap
+ * more accesses with it.
+ */
+static acpi_status oqo_lock_smbus(int silly_lock)
+{
+ struct acpi_buffer input, res;
+ acpi_status status;
+ union acpi_object *obj;
+ u32 arg2;
+
+ input.length = 4;
+ input.pointer = &arg2;
+ res.length = ACPI_ALLOCATE_BUFFER;
+ res.pointer = NULL;
+
+ arg2 = !!silly_lock;
+
+ status = wmi_evaluate_method(OQO_O2_AMW0_GUID, 1, 4, &input, &res);
+
+ if (status != AE_OK)
+ return status;
+
+ obj = (union acpi_object *)res.pointer;
+ if (!obj)
+ return AE_NULL_OBJECT;
+
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ kfree(obj);
+ return AE_TYPE;
+ }
+ kfree(obj);
+ return status;
+}
+
+static int smread_s16(u8 hi_addr, u8 lo_addr)
+{
+ s16 ret = -1;
+ acpi_status status;
+ u8 r;
+
+ /* Keep some ACPI routines off the SMBUS */
+ status = oqo_lock_smbus(1);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ status = oqo_smbus_getb(hi_addr, &r);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ ret = r;
+ ret <<= 8;
+
+ status = oqo_smbus_getb(lo_addr, &r);
+ if (ACPI_FAILURE(status)) {
+ ret = -1;
+ goto skip;
+ }
+
+ ret |= r;
+ ret &= 0x7fff;
+skip:
+ /* Let ACPI routines back on the SMBUS */
+ status = oqo_lock_smbus(0);
+ if (ACPI_FAILURE(status))
+ return -1;
+ return (int)ret;
+}
+
+static int smwrite_s16(u8 hi_addr, u8 lo_addr, s16 val)
+{
+ acpi_status status;
+ u8 r;
+ int ret = -1;
+
+ status = oqo_lock_smbus(1);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ r = (val >> 8) & 0x7f;
+ status = oqo_smbus_setb(hi_addr, r);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ r = val & 0xff;
+ status = oqo_smbus_setb(lo_addr, r);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ ret = 0;
+skip:
+ status = oqo_lock_smbus(0);
+ if (ACPI_FAILURE(status))
+ return -1;
+ return ret;
+}
+
+static int smread_u8(u8 addr)
+{
+ int ret = -1;
+ acpi_status status;
+ u8 r;
+
+ status = oqo_lock_smbus(1);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ status = oqo_smbus_getb(addr, &r);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ ret = r;
+skip:
+ status = oqo_lock_smbus(0);
+ if (ACPI_FAILURE(status))
+ return -1;
+ return (int)ret;
+}
+
+static int smwrite_u8(u8 addr, u8 val)
+{
+ acpi_status status;
+ int ret = -1;
+
+ status = oqo_lock_smbus(1);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ status = oqo_smbus_setb(addr, val);
+ if (ACPI_FAILURE(status))
+ goto skip;
+
+ ret = 0;
+skip:
+ status = oqo_lock_smbus(0);
+ if (ACPI_FAILURE(status))
+ return -1;
+ return ret;
+}
+
+/*
+ * Accelerometer inputdev
+ */
+
+/*
+ * Get a reading of the accelerometer from the firwmware and push
+ * it to an inputdev.
+ *
+ * Also the ambient light detector hitch-hikes on the inputdev, since
+ * it could be useful in some of the same applications for accelerometers.
+ *
+ * Available information and a bit of poking have not found a
+ * way to freeze a snapshot of the accelerometer data, so we have
+ * to do consistency checks to reduce the odds that we mix low
+ * and high bytes from different updates.
+ *
+ * Unfortunately SMBUS access is very slow (11ms) and the firmware API
+ * does not provide 2-byte transfers, so mixed readings happen and
+ * have to be corrected a lot. (Do not know why; it should be a
+ * multi-kHz.. bus and the reads take only a hundred-ish cycles/byte.
+ * It is not the ACPI function -- it is slow on i2c-viapro as well.)
+ *
+ * Since there is such a big time lag between readings, the axis
+ * are decoupled and reported separately on different timelines as
+ * different events rather than as a set.
+ */
+static acpi_status oqo_read_kine(int *good, s16 *x, s16 *y, s16 *z,
+ u16 *lumin)
+{
+ u8 hiregs[4] = { OQO_O2_SMB0_ACCEL_XHI,
+ OQO_O2_SMB0_ACCEL_YHI,
+ OQO_O2_SMB0_ACCEL_ZHI,
+ OQO_O2_SMB0_LUMIN_HI
+ };
+ u8 loregs[4] = { OQO_O2_SMB0_ACCEL_XLO,
+ OQO_O2_SMB0_ACCEL_YLO,
+ OQO_O2_SMB0_ACCEL_ZLO,
+ OQO_O2_SMB0_LUMIN_LO
+ };
+
+ short ax[4] = { ABS_X, ABS_Y, ABS_Z, ABS_MISC };
+ u8 realgood = 0;
+ u16 res[4];
+ acpi_status status;
+ int i;
+
+ *good = 0;
+
+ /* Routine: Starting with the lo byte, read lo/hi bytes
+ alternately until two lo byte readings, match. Then
+ take that reading and combine it with the hi reading
+ sandwiched between. Errors can still happen when
+ jittering at wrap boundaries, but should be rare.
+
+ Don't use this for missile guidance.
+
+ Userspace post-processing error detection encouraged.
+ */
+ for (i = 0; i < 4; i++) {
+ int maxtry;
+ u32 log;
+ u8 r, lo, hi;
+
+ lo = loregs[i];
+ hi = hiregs[i];
+ log = 0;
+
+#define LOGRES(reg) do { \
+ status = oqo_smbus_getb(reg, &r); \
+ log <<= 8; log |= r; log &= 0xffffff; \
+ if (ACPI_FAILURE(status)) \
+ goto leave; \
+ } while (0)
+
+ maxtry = OQO_KINE_MAXTRY + 1;
+ while (maxtry) {
+ LOGRES(lo);
+ if (maxtry <= OQO_KINE_MAXTRY &&
+ (log >> 16) == (log & 0xff)) {
+ *(res + i) = log & 0xffff;
+ break;
+ }
+ LOGRES(hi);
+ maxtry--;
+ }
+
+ if (maxtry == OQO_KINE_MAXTRY)
+ realgood |= 1 << i;
+
+ if (maxtry) {
+ *good |= 1 << i;
+ /* JIC CYA: this bit may be reserved */
+ res[3] &= 0x7fff;
+ input_report_abs(oqo_kine, ax[i], (s16) res[i]);
+ }
+ /* else we had trouble getting the reading to lock
+ and we skip reporting this axis.
+ */
+ }
+
+ *x = (u16) res[0];
+ *y = (u16) res[1];
+ *z = (u16) res[2];
+ *lumin = (u16) res[3];
+ return status;
+leave:
+ return status;
+}
+
+/*
+ * Generic Device (interface-independent)
+ */
+
+static void oqo_kine_poll(struct input_polled_dev *dev)
+{
+ s16 x, y, z;
+ u16 lumin;
+ int good;
+ /* struct timeval tv1, tv2; */
+
+ if (dev != oqo_kine_polled)
+ return;
+ if (orig.kine_itvl < 0)
+ return;
+
+ x = y = z = 0;
+ oqo_read_kine(&good, &x, &y, &z, &lumin);
+}
+
+static int __devinit oqo_kine_init(void)
+{
+ int err;
+
+ oqo_kine = input_allocate_device();
+ if (!oqo_kine)
+ return -ENOMEM;
+
+ oqo_kine->name = "OQO embedded accelerometer";
+ oqo_kine->phys = "platform:oqo-wmi:kine";
+ oqo_kine->id.bustype = 0;
+ oqo_kine->id.vendor = 0;
+ oqo_kine->id.product = 2;
+ oqo_kine->id.version = 0;
+ oqo_kine->evbit[0] = BIT_MASK(EV_ABS);
+ set_bit(ABS_X, oqo_kine->absbit);
+ set_bit(ABS_Y, oqo_kine->absbit);
+ set_bit(ABS_Z, oqo_kine->absbit);
+ set_bit(ABS_MISC, oqo_kine->absbit);
+ oqo_kine->absmin[ABS_X] =
+ oqo_kine->absmin[ABS_Y] =
+ oqo_kine->absmin[ABS_Z] = oqo_kine->absmin[ABS_MISC] = -32768;
+ oqo_kine->absmax[ABS_X] =
+ oqo_kine->absmax[ABS_Y] =
+ oqo_kine->absmax[ABS_Z] = oqo_kine->absmax[ABS_MISC] = 32767;
+
+ memcpy(oqo_kine->dev.bus_id, "kine", 4);
+
+ oqo_kine_polled = input_allocate_polled_device();
+ if (!oqo_kine_polled) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ oqo_kine_polled->poll = oqo_kine_poll;
+ oqo_kine_polled->poll_interval = 250;
+ oqo_kine_polled->input = oqo_kine;
+
+ orig.kine_itvl = -1; /* prevent callback from running */
+ err = input_register_polled_device(oqo_kine_polled);
+ if (err) {
+ printk(OQO_ERR "Failed to register OQO kine input\n");
+ goto bail1;
+ }
+
+ /* This will allow the callback to run now if successful. */
+ orig.kine_itvl = smread_u8(OQO_O2_SMB0_ACCEL_POLL_ITVL);
+ smwrite_u8(OQO_O2_SMB0_ACCEL_POLL_ITVL, 250);
+ curr.kine_itvl = smread_u8(OQO_O2_SMB0_ACCEL_POLL_ITVL);
+ if (orig.kine_itvl < 0 || curr.kine_itvl != 250) {
+ printk(OQO_ERR "Test communication with kine sensor failed\n");
+ err = -ENODEV;
+ goto bail2;
+ }
+
+ printk(OQO_INFO "Created OQO kine input.\n");
+ printk(OQO_INFO "Firmware interval %ims, driver interval %ims\n",
+ curr.kine_itvl, oqo_kine_polled->poll_interval);
+ return 0;
+bail2:
+ input_unregister_polled_device(oqo_kine_polled);
+bail1:
+ input_free_polled_device(oqo_kine_polled); /* frees oqo_kine */
+ return err;
+bail0:
+ input_free_device(oqo_kine);
+ return err;
+}
+
+static void __devexit oqo_kine_fini(void)
+{
+ smwrite_u8(OQO_O2_SMB0_ACCEL_POLL_ITVL, orig.kine_itvl);
+ input_unregister_polled_device(oqo_kine_polled);
+ input_free_polled_device(oqo_kine_polled);
+}
+
+/*
+ * Backlight device
+ */
+static int read_brightness(struct backlight_device *bd)
+{
+ return (int)smread_s16(OQO_O2_SMB0_BL_HI, OQO_O2_SMB0_BL_LO);
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ return smwrite_s16(OQO_O2_SMB0_BL_HI,
+ OQO_O2_SMB0_BL_LO, (s16) bd->props.brightness);
+}
+
+static struct backlight_ops oqo_bl_ops = {
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+};
+
+static int __devinit oqo_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ /*
+ * It would be nice if someone would figure out how backlights
+ * like these, which are not driven through the video hardware,
+ * are supposed to find their associated fb and bind to it (and
+ * rebind when fb drivers change.
+ *
+ * Most extras backlights just shove a junk name in like we do here,
+ * and don't end up integrated with fbcon sysfs as a result.
+ */
+ bd = backlight_device_register("oqo-bl", dev, NULL, &oqo_bl_ops);
+
+ if (IS_ERR(bd)) {
+ printk(OQO_ERR "Could not register OQO backlight device\n");
+ oqo_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+
+ oqo_backlight_device = bd;
+ bd->props.max_brightness = 0x7fff;
+ curr.bl_bright = orig.bl_bright = bd->props.brightness =
+ read_brightness(NULL);
+
+ if (bd->props.brightness < 0)
+ goto fail;
+
+ backlight_update_status(bd);
+ printk(OQO_INFO "Found backlight set at %i\n", bd->props.brightness);
+ return 0;
+
+fail:
+ backlight_device_unregister(oqo_backlight_device);
+ oqo_backlight_device = NULL;
+ return -ENODEV;
+}
+
+static void __devexit oqo_backlight_fini(void)
+{
+ if (!oqo_backlight_device)
+ return;
+ oqo_backlight_device->props.brightness = orig.bl_bright;
+ backlight_update_status(oqo_backlight_device);
+ backlight_device_unregister(oqo_backlight_device);
+}
+
+/*
+ * RFKill device
+ */
+
+static int oqo_rfkill_get(void *data, enum rfkill_state *state)
+{
+ int res;
+
+ res = smread_u8(OQO_O2_SMB0_WWAN_DSBL_ADDR);
+ if (res < 0)
+ return res;
+
+ res &= OQO_O2_SMB0_WWAN_DSBL_MASK;
+
+ if (res)
+ *state = RFKILL_STATE_SOFT_BLOCKED;
+ else
+ *state = RFKILL_STATE_UNBLOCKED;
+
+ return 0;
+}
+
+static int oqo_rfkill_toggle(void *data, enum rfkill_state state)
+{
+ int res;
+
+ res = smread_u8(OQO_O2_SMB0_WWAN_DSBL_ADDR);
+
+ if (state == RFKILL_STATE_UNBLOCKED)
+ res &= ~OQO_O2_SMB0_WWAN_DSBL_MASK;
+ else
+ res |= OQO_O2_SMB0_WWAN_DSBL_MASK;
+
+ return smwrite_u8(OQO_O2_SMB0_WWAN_DSBL_ADDR, res);
+}
+
+static int __devinit oqo_rfkill_init(struct device *dev)
+{
+ int res;
+
+ oqo_rfkill = rfkill_allocate(dev, RFKILL_TYPE_WWAN);
+ if (!oqo_rfkill)
+ return -ENODEV;
+
+ res = smread_u8(OQO_O2_SMB0_WWAN_DSBL_ADDR);
+ res &= OQO_O2_SMB0_WWAN_DSBL_MASK;
+
+ oqo_rfkill->name = "oqo-wwan";
+ if (res)
+ oqo_rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
+ else
+ oqo_rfkill->state = RFKILL_STATE_UNBLOCKED;
+
+ oqo_rfkill->get_state = oqo_rfkill_get;
+ oqo_rfkill->toggle_radio = oqo_rfkill_toggle;
+ oqo_rfkill->user_claim_unsupported = 1;
+
+ res = rfkill_register(oqo_rfkill);
+
+ if (res)
+ rfkill_free(oqo_rfkill);
+
+ return res;
+}
+
+static void __devexit oqo_rfkill_fini(void)
+{
+ if (!oqo_rfkill)
+ return;
+ rfkill_unregister(oqo_rfkill);
+}
+
+/*
+ * Platform device
+ */
+
+static int __devinit oqo_platform_probe(struct platform_device *device)
+{
+ int err;
+ int i;
+ char *troubleok = "trouble, but continuing.\n";
+
+ memset(oqo_sn, 0, OQO_O2_SMB0_SERIAL_LEN + 1);
+ for (i = 0; i < OQO_O2_SMB0_SERIAL_LEN; i++) {
+ err = oqo_smbus_getb(OQO_O2_SMB0_SERIAL_START + i, oqo_sn + i);
+ if (err) {
+ printk(OQO_ERR "Serial number check failed.\n");
+ return err;
+ }
+ }
+ printk(OQO_INFO "Found OQO with serial number %s.\n", oqo_sn);
+
+ err = oqo_backlight_init(&device->dev);
+ if (err)
+ printk(OQO_ERR "Backlight init %s", troubleok);
+
+ err = oqo_rfkill_init(&device->dev);
+ if (err)
+ printk(OQO_ERR "RFKill init %s", troubleok);
+
+ /* LID does not work at all yet, and this may be taken
+ care of by ACPI.
+ */
+ orig.lid_wakes = smread_u8(OQO_O2_SMB0_LID_WAKES_ADDR);
+ orig.lid_wakes &= OQO_O2_SMB0_LID_WAKES_MASK;
+ orig.lid_wakes = curr.lid_wakes = !!orig.lid_wakes;
+ if (orig.lid_wakes < 0) {
+ printk(OQO_ERR "Wake on LID event %s", troubleok);
+ } else {
+ printk(OQO_INFO "Wake on LID is %s.\n",
+ (orig.lid_wakes ? "on" : "off"));
+ }
+
+ err = oqo_kine_init();
+ return err;
+}
+
+static int oqo_platform_remove(struct platform_device *device)
+{
+ oqo_backlight_fini();
+ oqo_rfkill_fini();
+ oqo_kine_fini();
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int oqo_platform_suspend(struct platform_device *dev, pm_message_t state)
+{
+ if (!interface)
+ return -ENOMEM;
+
+ /* This sticks during boot so do not turn it entirely off */
+ if (oqo_backlight_device) {
+ curr.bl_bright = read_brightness(oqo_backlight_device);
+ smwrite_s16(OQO_O2_SMB0_BL_HI, OQO_O2_SMB0_BL_LO, 256);
+ }
+ return 0;
+}
+
+static int oqo_platform_resume(struct platform_device *device)
+{
+ if (!interface)
+ return -ENOMEM;
+
+ if (oqo_backlight_device) {
+ smwrite_s16(OQO_O2_SMB0_BL_HI,
+ OQO_O2_SMB0_BL_LO, curr.bl_bright);
+ }
+
+ return 0;
+}
+
+#else
+#define oqo_platform_suspend NULL
+#define oqo_platform_resume NULL
+#endif
+
+static struct platform_driver oqo_platform_driver = {
+ .driver = {
+ .name = "oqo-wmi",
+ .owner = THIS_MODULE,
+ },
+ .probe = oqo_platform_probe,
+ .remove = oqo_platform_remove,
+ .suspend = oqo_platform_suspend,
+ .resume = oqo_platform_resume,
+};
+
+static int __init oqo_wmi_init(void)
+{
+ int err;
+
+ dmi_check_system(oqo_dmis);
+
+ if (!interface && force) {
+ model = oqo_models;
+ if (wmi_has_guid(OQO_O2_AMW0_GUID))
+ interface = &AMW0_interface;
+ }
+
+ if (!interface) {
+ printk(OQO_ERR "No or unsupported WMI interface. Aborting.\n");
+ printk(OQO_ERR "Hint: Get dmidecode working and try again.\n");
+ printk(OQO_ERR "(Check \"System Management BIOS\" in BIOS)\n");
+ if (!force)
+ printk(OQO_ERR "Use the force option to skip DMI"
+ " checking\n");
+ return -ENODEV;
+ }
+
+ err = platform_driver_register(&oqo_platform_driver);
+ if (err) {
+ printk(OQO_ERR "platform_driver_register gave %d.\n", err);
+ goto bail0;
+ }
+
+ oqo_platform_device = platform_device_alloc("oqo-wmi", -1);
+ if (!oqo_platform_device) {
+ printk(OQO_ERR "Could not allocate platform device.\n");
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ err = platform_device_add(oqo_platform_device);
+ if (err) {
+ printk(OQO_ERR "platform_device_add gave %d.\n", err);
+ platform_device_put(oqo_platform_device);
+ goto bail1;
+ }
+
+ return 0;
+
+bail1:
+ platform_driver_unregister(&oqo_platform_driver);
+bail0:
+ return err;
+}
+
+static void __exit oqo_wmi_fini(void)
+{
+ platform_device_del(oqo_platform_device);
+ platform_driver_unregister(&oqo_platform_driver);
+
+ return;
+}
+
+module_init(oqo_wmi_init);
+module_exit(oqo_wmi_fini);
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 813e4b6c2c0d..bf8d4cfd8cf5 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -245,7 +245,7 @@ struct acpi_table_fadt {
#define ACPI_FADT_POWER_BUTTON (1<<4) /* 04: Power button is handled as a generic feature */
#define ACPI_FADT_SLEEP_BUTTON (1<<5) /* 05: Sleep button is handled as a generic feature, or not present */
#define ACPI_FADT_FIXED_RTC (1<<6) /* 06: RTC wakeup stat not in fixed register space */
-#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: RTC wakeup stat not possible from S4 */
+#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: RTC wakeup possible from S4 */
#define ACPI_FADT_32BIT_TIMER (1<<8) /* 08: tmr_val is 32 bits 0=24-bits */
#define ACPI_FADT_DOCKING_SUPPORTED (1<<9) /* 09: Docking supported */
#define ACPI_FADT_RESET_REGISTER (1<<10) /* 10: System reset via the FADT RESET_REG supported */
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 1b9cbdc0127a..7ba8cd9845cb 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -123,7 +123,7 @@ static int collect_garbage_slots(void);
static int __kprobes check_safety(void)
{
int ret = 0;
-#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_FREEZER)
ret = freeze_processes();
if (ret == 0) {
struct task_struct *p, *q;
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 597823b5b700..d7a10167a25b 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -4,7 +4,8 @@ EXTRA_CFLAGS += -DDEBUG
endif
obj-y := main.o
-obj-$(CONFIG_PM_SLEEP) += process.o console.o
+obj-$(CONFIG_PM_SLEEP) += console.o
+obj-$(CONFIG_FREEZER) += process.o
obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o