summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/Makefile6
-rw-r--r--share/man/man4/acpi.46
-rw-r--r--share/man/man4/acpithinkpad.438
-rw-r--r--sys/arch/amd64/conf/GENERIC3
-rw-r--r--sys/arch/i386/conf/GENERIC3
-rw-r--r--sys/dev/acpi/acpi.c5
-rw-r--r--sys/dev/acpi/acpireg.h3
-rw-r--r--sys/dev/acpi/acpithinkpad.c346
-rw-r--r--sys/dev/acpi/files.acpi7
9 files changed, 407 insertions, 10 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 0a674c3d293..b4e65735f90 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.450 2008/04/24 13:57:49 jsing Exp $
+# $OpenBSD: Makefile,v 1.451 2008/04/27 16:23:16 jcs Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
- acpiec.4 acpihpet.4 acpimadt.4 acpiprt.4 acpitimer.4 acpitz.4 \
- acx.4 adc.4 addcom.4 adl.4 admcts.4 admlc.4 admtemp.4 \
+ acpiec.4 acpihpet.4 acpimadt.4 acpiprt.4 acpithinkpad.4 acpitimer.4 \
+ acpitz.4 acx.4 adc.4 addcom.4 adl.4 admcts.4 admlc.4 admtemp.4 \
admtm.4 admtmp.4 admtt.4 adt.4 adtfsm.4 adv.4 agp.4 \
aha.4 ahb.4 ahc.4 ahci.4 \
ahd.4 aic.4 akbd.4 alipm.4 amdiic.4 amdpm.4 ami.4 amphy.4 ams.4 \
diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4
index 1b1dac7d8c7..a528c870709 100644
--- a/share/man/man4/acpi.4
+++ b/share/man/man4/acpi.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: acpi.4,v 1.29 2008/04/24 13:57:49 jsing Exp $
+.\" $OpenBSD: acpi.4,v 1.30 2008/04/27 16:23:16 jcs Exp $
.\"
.\" Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: April 24 2008 $
+.Dd $Mdocdate: April 27 2008 $
.Dt ACPI 4
.Os
.Sh NAME
@@ -65,6 +65,8 @@ ACPI high precision event timer
ACPI APIC configuration
.It Xr acpiprt 4
ACPI PCI routing table configuration
+.It Xr acpithinkpad 4
+IBM/Lenovo Thinkpad support
.It Xr acpitimer 4
ACPI power management timer
.It Xr acpitz 4
diff --git a/share/man/man4/acpithinkpad.4 b/share/man/man4/acpithinkpad.4
new file mode 100644
index 00000000000..a7c86e42955
--- /dev/null
+++ b/share/man/man4/acpithinkpad.4
@@ -0,0 +1,38 @@
+.\" $OpenBSD: acpithinkpad.4,v 1.1 2008/04/27 16:23:16 jcs Exp $
+.\"
+.\" Copyright (c) 2008 joshua stein <jcs@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: April 27 2008 $
+.Dt ACPITHINKPAD 4
+.Os
+.Sh NAME
+.Nm acpithinkpad
+.Nd IBM/Lenovo Thinkpad ACPI support
+.Sh SYNOPSIS
+.Cd "acpithinkpad* at acpi?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides ACPI support for IBM/Lenovo Thinkpad laptops.
+It responds to various hotkey button presses such as the brightness adjustment
+and wireless toggle keys.
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr intro 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 4.4 .
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 81bbfd0c23b..6e884942911 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.225 2008/04/19 01:18:39 djm Exp $
+# $OpenBSD: GENERIC,v 1.226 2008/04/27 16:23:16 jcs Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -51,6 +51,7 @@ acpicpu* at acpi?
acpiec* at acpi?
acpiprt* at acpi?
acpitz* at acpi?
+acpithinkpad* at acpi?
ipmi0 at mainbus? disable # IPMI
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 80d1858e681..91fa8b7ef19 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.613 2008/04/24 13:57:49 jsing Exp $
+# $OpenBSD: GENERIC,v 1.614 2008/04/27 16:23:16 jcs Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -58,6 +58,7 @@ acpiec* at acpi?
acpiprt* at acpi?
acpitz* at acpi?
acpiasus* at acpi?
+acpithinkpad* at acpi?
option PCIVERBOSE
option EISAVERBOSE
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index cb7827566df..604a06f3016 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.115 2008/04/24 13:57:49 jsing Exp $ */
+/* $OpenBSD: acpi.c,v 1.116 2008/04/27 16:23:16 jcs Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -1855,9 +1855,12 @@ acpi_foundhid(struct aml_node *node, void *arg)
aaa.aaa_name = "acpibtn";
else if (!strcmp(dev, ACPI_DEV_ASUS))
aaa.aaa_name = "acpiasus";
+ else if (!strcmp(dev, ACPI_DEV_THINKPAD))
+ aaa.aaa_name = "acpithinkpad";
if (aaa.aaa_name)
config_found(self, &aaa, acpi_print);
+
aml_freevalue(&res);
return 0;
diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h
index e2e42e311df..8f2289c76a0 100644
--- a/sys/dev/acpi/acpireg.h
+++ b/sys/dev/acpi/acpireg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpireg.h,v 1.13 2008/04/24 13:57:49 jsing Exp $ */
+/* $OpenBSD: acpireg.h,v 1.14 2008/04/27 16:23:16 jcs Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
@@ -485,5 +485,6 @@ struct acpi_facs {
#define ACPI_DEV_THZ "THERMALZONE" /* Thermal Zone */
#define ACPI_DEV_FFB "FIXEDBUTTON" /* Fixed Feature Button */
#define ACPI_DEV_ASUS "ASUS010" /* ASUS Hotkeys */
+#define ACPI_DEV_THINKPAD "IBM0068" /* Thinkpad support */
#endif /* !_DEV_ACPI_ACPIREG_H_ */
diff --git a/sys/dev/acpi/acpithinkpad.c b/sys/dev/acpi/acpithinkpad.c
new file mode 100644
index 00000000000..47066f53579
--- /dev/null
+++ b/sys/dev/acpi/acpithinkpad.c
@@ -0,0 +1,346 @@
+/* $OpenBSD: acpithinkpad.c,v 1.1 2008/04/27 16:23:16 jcs Exp $ */
+
+/*
+ * Copyright (c) 2008 joshua stein <jcs@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#define THINKPAD_HKEY_VERSION 0x0100
+
+#define THINKPAD_CMOS_BRIGHTNESS_UP 0x04
+#define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05
+
+#define THINKPAD_BLUETOOTH_PRESENT 0x01
+#define THINKPAD_BLUETOOTH_ENABLED 0x02
+
+/* wan (not wifi) card */
+#define THINKPAD_WAN_PRESENT 0x01
+#define THINKPAD_WAN_ENABLED 0x02
+
+/* type 1 events */
+#define THINKPAD_BUTTON_FN_F1 0x001
+#define THINKPAD_BUTTON_LOCK_SCREEN 0x002
+#define THINKPAD_BUTTON_BATTERY_INFO 0x003
+#define THINKPAD_BUTTON_SUSPEND 0x004
+#define THINKPAD_BUTTON_WIRELESS 0x005
+#define THINKPAD_BUTTON_FN_F6 0x006
+#define THINKPAD_BUTTON_EXTERNAL_SCREEN 0x007
+#define THINKPAD_BUTTON_POINTER_SWITCH 0x008
+#define THINKPAD_BUTTON_EJECT 0x009
+#define THINKPAD_BUTTON_BRIGHTNESS_UP 0x010
+#define THINKPAD_BUTTON_BRIGHTNESS_DOWN 0x011
+#define THINKPAD_BUTTON_THINKLIGHT 0x012
+#define THINKPAD_BUTTON_FN_SPACE 0x014
+#define THINKPAD_BUTTON_THINKVANTAGE 0x018
+#define THINKPAD_BUTTON_FN_F11 0x00b
+#define THINKPAD_BUTTON_HIBERNATE 0x00c
+
+/* type 5 events */
+#define THINKPAD_LID_OPEN 0x001
+#define THINKPAD_LID_CLOSED 0x002
+#define THINKPAD_TABLET_SCREEN_NORMAL 0x00a
+#define THINKPAD_TABLET_SCREEN_ROTATED 0x009
+#define THINKPAD_TABLET_PEN_INSERTED 0x00b
+#define THINKPAD_TABLET_PEN_REMOVED 0x00c
+
+struct acpithinkpad_softc {
+ struct device sc_dev;
+
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_devnode;
+};
+
+int thinkpad_match(struct device *, void *, void *);
+void thinkpad_attach(struct device *, struct device *, void *);
+int thinkpad_hotkey(struct aml_node *, int, void *);
+int thinkpad_enable_events(struct acpithinkpad_softc *);
+int thinkpad_toggle_bluetooth(struct acpithinkpad_softc *);
+int thinkpad_toggle_wan(struct acpithinkpad_softc *);
+int thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t);
+int thinkpad_brightness_up(struct acpithinkpad_softc *);
+int thinkpad_brightness_down(struct acpithinkpad_softc *);
+
+struct cfattach acpithinkpad_ca = {
+ sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach
+};
+
+struct cfdriver acpithinkpad_cd = {
+ NULL, "acpithinkpad", DV_DULL
+};
+
+int
+thinkpad_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aa = aux;
+ struct cfdata *cf = match;
+ struct aml_value res;
+
+ if (aa->aaa_name == NULL ||
+ strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
+ aa->aaa_table != NULL)
+ return (0);
+
+ if (aml_evalname((struct acpi_softc *)parent, aa->aaa_node->child,
+ "MHKV", 0, NULL, &res))
+ goto fail;
+
+ if (aml_val2int(&res) != THINKPAD_HKEY_VERSION)
+ goto fail;
+
+ return (1);
+
+fail:
+ aml_freevalue(&res);
+ return (0);
+}
+
+void
+thinkpad_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
+ struct acpi_attach_args *aa = aux;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_devnode = aa->aaa_node->child;
+
+ printf("\n");
+
+ /* set event mask to receive everything */
+ thinkpad_enable_events(sc);
+
+ /* run thinkpad_hotkey on button presses */
+ aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev,
+ thinkpad_hotkey, sc, ACPIDEV_NOPOLL);
+
+ return;
+}
+
+int
+thinkpad_enable_events(struct acpithinkpad_softc *sc)
+{
+ struct aml_value res, arg, args[2];
+ int64_t mask;
+ int i;
+
+ /* get the supported event mask */
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKA", 0, NULL, &res)) {
+ printf("%s: no MHKA\n", DEVNAME(sc));
+ aml_freevalue(&res);
+ return (1);
+ }
+ mask = aml_val2int(&res);
+
+ /* update hotkey mask */
+ memset(&args, 0, sizeof(args));
+ args[0].type = args[1].type = AML_OBJTYPE_INTEGER;
+ for (i = 0; i < 32; i++) {
+ args[0].v_integer = i + 1;
+ args[1].v_integer = (((1 << i) & mask) != 0);
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKM", 2, args,
+ NULL)) {
+ printf("%s: couldn't toggle MHKM\n", DEVNAME(sc));
+ return (1);
+ }
+ }
+
+ /* enable hotkeys */
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = 1;
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKC", 1, &arg, NULL)) {
+ printf("%s: couldn't enable hotkeys\n", DEVNAME(sc));
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg)
+{
+ struct acpithinkpad_softc *sc = arg;
+ struct aml_value res;
+ int val, type, event, handled;
+
+ for (;;) {
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKP", 0, NULL,
+ &res)) {
+ aml_freevalue(&res);
+ return (1);
+ }
+
+ val = aml_val2int(&res);
+ if (val == 0)
+ return (1);
+
+ type = (val & 0xf000) >> 12;
+ event = val & 0x0fff;
+ handled = 0;
+
+ switch (type) {
+ case 1:
+ switch (event) {
+ case THINKPAD_BUTTON_BRIGHTNESS_UP:
+ thinkpad_brightness_up(sc);
+ handled = 1;
+ break;
+ case THINKPAD_BUTTON_BRIGHTNESS_DOWN:
+ thinkpad_brightness_down(sc);
+ handled = 1;
+ break;
+ case THINKPAD_BUTTON_WIRELESS:
+ thinkpad_toggle_bluetooth(sc);
+ handled = 1;
+ break;
+ case THINKPAD_BUTTON_SUSPEND:
+ handled = 1;
+ /*
+ acpi_enter_sleep_state(sc->sc_acpi,
+ ACPI_STATE_S3);
+ */
+ break;
+ case THINKPAD_BUTTON_HIBERNATE:
+ case THINKPAD_BUTTON_FN_F1:
+ case THINKPAD_BUTTON_LOCK_SCREEN:
+ case THINKPAD_BUTTON_BATTERY_INFO:
+ case THINKPAD_BUTTON_FN_F6:
+ case THINKPAD_BUTTON_EXTERNAL_SCREEN:
+ case THINKPAD_BUTTON_POINTER_SWITCH:
+ case THINKPAD_BUTTON_EJECT:
+ case THINKPAD_BUTTON_THINKLIGHT:
+ case THINKPAD_BUTTON_FN_SPACE:
+ case THINKPAD_BUTTON_THINKVANTAGE:
+ case THINKPAD_BUTTON_FN_F11:
+ /* TODO: notify userland */
+ handled = 1;
+ break;
+ }
+
+ break;
+ case 5:
+ switch (event) {
+ case THINKPAD_TABLET_SCREEN_NORMAL:
+ case THINKPAD_TABLET_SCREEN_ROTATED:
+ case THINKPAD_LID_OPEN:
+ case THINKPAD_LID_CLOSED:
+ case THINKPAD_TABLET_PEN_INSERTED:
+ case THINKPAD_TABLET_PEN_REMOVED:
+ /* TODO: notify userland */
+ handled = 1;
+
+ break;
+ }
+ break;
+ }
+
+ if (!handled)
+ printf("%s: unknown type %d event 0x%03x\n",
+ DEVNAME(sc), type, event);
+ }
+}
+
+int
+thinkpad_toggle_bluetooth(struct acpithinkpad_softc *sc)
+{
+ struct aml_value res, arg;
+ int bluetooth;
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBDC", 0, NULL, &res)) {
+ /* no bluetooth, oh well */
+ aml_freevalue(&res);
+ return (1);
+ }
+
+ bluetooth = aml_val2int(&res);
+ aml_freevalue(&res);
+ if (!(bluetooth & THINKPAD_BLUETOOTH_PRESENT))
+ return (1);
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = bluetooth ^= THINKPAD_BLUETOOTH_ENABLED;
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBDC", 1, &arg, NULL)) {
+ printf("%s: couldn't toggle bluetooth\n", DEVNAME(sc));
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+thinkpad_toggle_wan(struct acpithinkpad_softc *sc)
+{
+ struct aml_value res, arg;
+ int wan;
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "GWAN", 0, NULL, &res)) {
+ aml_freevalue(&res);
+ return (1);
+ }
+
+ wan = aml_val2int(&res);
+ aml_freevalue(&res);
+ if (!(wan & THINKPAD_WAN_PRESENT))
+ return (1);
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = wan ^= THINKPAD_WAN_ENABLED;
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SWAN", 1, &arg, NULL)) {
+ printf("%s: couldn't toggle wan\n", DEVNAME(sc));
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t cmd)
+{
+ struct aml_value arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = cmd;
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "\\UCMS", 1, &arg,
+ NULL)) {
+ printf("%s: cmos command 0x%x failed\n", DEVNAME(sc), cmd);
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+thinkpad_brightness_up(struct acpithinkpad_softc *sc)
+{
+ return thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP);
+}
+
+int
+thinkpad_brightness_down(struct acpithinkpad_softc *sc)
+{
+ return thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN);
+}
diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi
index 62f2ff27020..bbac54f8c9f 100644
--- a/sys/dev/acpi/files.acpi
+++ b/sys/dev/acpi/files.acpi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.acpi,v 1.17 2008/04/24 13:57:49 jsing Exp $
+# $OpenBSD: files.acpi,v 1.18 2008/04/27 16:23:16 jcs Exp $
#
# Config file and device description for machine-independent ACPI code.
# Included by ports that need it.
@@ -70,3 +70,8 @@ file dev/acpi/acpidock.c acpidock
device acpiasus
attach acpiasus at acpi
file dev/acpi/acpiasus.c acpiasus
+
+# IBM/Lenovo Thinkpad support
+device acpithinkpad
+attach acpithinkpad at acpi
+file dev/acpi/acpithinkpad.c acpithinkpad