summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPaul Irofti <pirofti@cvs.openbsd.org>2010-07-26 11:29:24 +0000
committerPaul Irofti <pirofti@cvs.openbsd.org>2010-07-26 11:29:24 +0000
commit19771d70f42189726856be165e7d455b83509fcf (patch)
treeec1cf325d791f6db4fdabf037d3f3a03960e5c58 /sys
parenta310352f5c3ba3f7e0850afd0f57b6db100a6543 (diff)
Add support for Sony ACPI hotkeys via a new driver: acpisony(4).
Currently it only works for the suspend button and tries to do right for the brightness events, but I haven't found a Sony laptop that like to do right so far. In the future I want to make the brightness keys work on all Sony's and also add support for the zoom hotkeys and whatever other funky keys I can find on those things. Okay deraadt@.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/conf/GENERIC3
-rw-r--r--sys/arch/i386/conf/GENERIC3
-rw-r--r--sys/dev/acpi/acpi.c25
-rw-r--r--sys/dev/acpi/acpisony.c329
-rw-r--r--sys/dev/acpi/files.acpi7
5 files changed, 363 insertions, 4 deletions
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 23286e3d759..017a6bffa41 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.293 2010/07/21 20:10:17 miod Exp $
+# $OpenBSD: GENERIC,v 1.294 2010/07/26 11:29:23 pirofti Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -50,6 +50,7 @@ acpiec* at acpi?
acpiprt* at acpi?
acpitz* at acpi?
acpimadt0 at acpi?
+acpisony* at acpi?
acpithinkpad* at acpi?
acpivideo* at acpi?
acpivout* at acpivideo?
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 9b42015b7b4..3a5d646414a 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.689 2010/07/21 20:10:17 miod Exp $
+# $OpenBSD: GENERIC,v 1.690 2010/07/26 11:29:23 pirofti Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -60,6 +60,7 @@ acpimadt0 at acpi?
acpiprt* at acpi?
acpitz* at acpi?
acpiasus* at acpi?
+acpisony* at acpi?
acpithinkpad* at acpi?
acpivideo* at acpi?
acpivout* at acpivideo?
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index 2dca3e99148..4ba59f339a7 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.187 2010/07/22 14:19:47 deraadt Exp $ */
+/* $OpenBSD: acpi.c,v 1.188 2010/07/26 11:29:23 pirofti Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -108,6 +108,7 @@ int acpi_foundec(struct aml_node *, void *);
int acpi_foundtmp(struct aml_node *, void *);
int acpi_foundprw(struct aml_node *, void *);
int acpi_foundvideo(struct aml_node *, void *);
+int acpi_foundsony(struct aml_node *node, void *arg);
int acpi_foundide(struct aml_node *node, void *arg);
int acpiide_notify(struct aml_node *, int, void *);
@@ -762,6 +763,9 @@ acpi_attach(struct device *parent, struct device *self, void *aux)
/* attach docks */
aml_find_node(&aml_root, "_DCK", acpi_founddock, sc);
+ /* check if we're running on a sony */
+ aml_find_node(&aml_root, "GBRT", acpi_foundsony, sc);
+
/* attach video only if this is not a stinkpad */
if (!acpi_thinkpad_enabled)
aml_find_node(&aml_root, "_DOS", acpi_foundvideo, sc);
@@ -2230,6 +2234,24 @@ acpi_foundvideo(struct aml_node *node, void *arg)
}
int
+acpi_foundsony(struct aml_node *node, void *arg)
+{
+ struct acpi_softc *sc = (struct acpi_softc *)arg;
+ struct device *self = (struct device *)arg;
+ struct acpi_attach_args aaa;
+
+ memset(&aaa, 0, sizeof(aaa));
+ aaa.aaa_iot = sc->sc_iot;
+ aaa.aaa_memt = sc->sc_memt;
+ aaa.aaa_node = node->parent;
+ aaa.aaa_name = "acpisony";
+
+ config_found(self, &aaa, acpi_print);
+
+ return 0;
+}
+
+int
acpiopen(dev_t dev, int flag, int mode, struct proc *p)
{
int error = 0;
@@ -2484,4 +2506,5 @@ acpikqfilter(dev_t dev, struct knote *kn)
return (1);
}
+>>>>>>> 1.187
#endif /* SMALL_KERNEL */
diff --git a/sys/dev/acpi/acpisony.c b/sys/dev/acpi/acpisony.c
new file mode 100644
index 00000000000..a1757b18b10
--- /dev/null
+++ b/sys/dev/acpi/acpisony.c
@@ -0,0 +1,329 @@
+/* $OpenBSD: acpisony.c,v 1.1 2010/07/26 11:29:23 pirofti Exp $ */
+/*
+ * Copyright (c) 2010 Paul Irofti <pirofti@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or 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 <sys/proc.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>
+
+#include <machine/apmvar.h>
+
+int acpisony_match(struct device *, void *, void *);
+void acpisony_attach(struct device *, struct device *, void *);
+int acpisony_activate(struct device *, int);
+int acpisony_notify(struct aml_node *, int, void *);
+
+#ifdef ACPISONY_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+/* Notifications */
+#define SONY_NOTIFY_FN_KEY 0x90
+
+#define SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED 0x85
+#define SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED 0x05
+#define SONY_NOTIFY_BRIGHTNESS_UP_PRESSED 0x86
+#define SONY_NOTIFY_BRIGHTNESS_UP_RELEASED 0x06
+
+#define SONY_NOTIFY_DISPLAY_SWITCH_PRESSED 0x87
+#define SONY_NOTIFY_DISPLAY_SWITCH_RELEASED 0x07
+
+#define SONY_NOTIFY_ZOOM_OUT_PRESSED 0x89
+#define SONY_NOTIFY_ZOOM_OUT_RELEASED 0x09
+
+#define SONY_NOTIFY_ZOOM_IN_PRESSED 0x8a
+#define SONY_NOTIFY_ZOOM_IN_RELEASED 0x0a
+
+#define SONY_NOTIFY_SUSPEND_PRESSED 0x8c
+#define SONY_NOTIFY_SUSPEND_RELEASED 0x0c
+
+struct acpisony_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_devnode;
+};
+
+struct cfattach acpisony_ca = {
+ sizeof(struct acpisony_softc), acpisony_match, acpisony_attach,
+ NULL, acpisony_activate
+};
+
+struct cfdriver acpisony_cd = {
+ NULL, "acpisony", DV_DULL
+};
+
+void acpisony_notify_setup(struct acpisony_softc *);
+int acpisony_set_hotkey(struct acpisony_softc *, int, int);
+int acpisony_find_offset(struct acpisony_softc *, int);
+
+void acpisony_brightness_down(struct acpisony_softc *);
+int acpisony_get_brightness(struct acpisony_softc *);
+void acpisony_set_brightness(struct acpisony_softc *, int);
+
+int
+acpisony_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aa = aux;
+ struct cfdata *cf = match;
+
+ if (aa->aaa_name == NULL ||
+ strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
+ aa->aaa_table != NULL)
+ return (0);
+
+ return (1);
+}
+
+void
+acpisony_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct acpisony_softc *sc = (struct acpisony_softc *)self;
+ struct acpi_attach_args *aa = aux;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_devnode = aa->aaa_node;
+
+ printf(": %s\n", sc->sc_devnode->name);
+
+ /* Setup the notification masks */
+ acpisony_notify_setup(sc);
+
+ aml_register_notify(sc->sc_devnode, aa->aaa_dev,
+ acpisony_notify, sc, ACPIDEV_NOPOLL);
+}
+
+int
+acpisony_activate(struct device *self, int act)
+{
+ struct acpisony_softc *sc = (struct acpisony_softc *)self;
+
+ switch (act) {
+ case DVACT_RESUME:
+ acpisony_notify_setup(sc);
+ break;
+ }
+ return 0;
+}
+
+int
+acpisony_notify(struct aml_node *node, int notify, void *arg)
+{
+ struct acpisony_softc *sc = arg;
+ int val, key = 0;
+
+ if (notify == SONY_NOTIFY_FN_KEY) {
+ notify -= 0x90;
+ DPRINTF(("notify = %X", notify));
+
+ if (notify == acpisony_find_offset(sc, 0x100)) {
+ DPRINTF(("key = 0x100\n"));
+ key = 0x100;
+ }
+ if (notify == acpisony_find_offset(sc, 0x127)) {
+ DPRINTF(("key = 0x127\n"));
+ key = 0x127;
+ }
+
+ if (key) {
+ val = acpisony_set_hotkey(sc, key, 0x200);
+ if (val < 0) {
+ printf("returned val = %X", val);
+ return 1;
+ }
+ notify = val & 0xff;
+
+ DPRINTF(("Treat %X events, notify %X\n", key, notify));
+ } else
+ DPRINTF(("rfkill update, notify %X\n", notify));
+ }
+
+ switch (notify) {
+ case SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED:
+ DPRINTF(("br-down-pressed\n"));
+ acpisony_brightness_down(sc);
+ break;
+ case SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED:
+ DPRINTF(("br-down-released\n"));
+ break;
+ case SONY_NOTIFY_BRIGHTNESS_UP_PRESSED:
+ DPRINTF(("br-up-pressed\n"));
+ break;
+ case SONY_NOTIFY_BRIGHTNESS_UP_RELEASED:
+ DPRINTF(("br-up-released\n"));
+ break;
+ case SONY_NOTIFY_DISPLAY_SWITCH_PRESSED:
+ DPRINTF(("display-pressed\n"));
+ break;
+ case SONY_NOTIFY_DISPLAY_SWITCH_RELEASED:
+ DPRINTF(("display-released\n"));
+ break;
+ case SONY_NOTIFY_ZOOM_IN_PRESSED:
+ DPRINTF(("zoom-in-pressed\n"));
+ break;
+ case SONY_NOTIFY_ZOOM_IN_RELEASED:
+ DPRINTF(("zoom-in-released\n"));
+ break;
+ case SONY_NOTIFY_ZOOM_OUT_PRESSED:
+ DPRINTF(("zoom-out-pressed\n"));
+ break;
+ case SONY_NOTIFY_ZOOM_OUT_RELEASED:
+ DPRINTF(("zoom-out-released\n"));
+ break;
+ case SONY_NOTIFY_SUSPEND_PRESSED:
+ DPRINTF(("suspend-pressed\n"));
+#ifndef SMALL_KERNEL
+ if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) {
+ sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3;
+ acpi_wakeup(sc->sc_acpi);
+ }
+#endif
+ break;
+ case SONY_NOTIFY_SUSPEND_RELEASED:
+ DPRINTF(("suspend-released\n"));
+ break;
+ default:
+ printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
+ break;
+ }
+
+ return 0;
+}
+
+void
+acpisony_notify_setup(struct acpisony_softc *sc)
+{
+ struct aml_value arg;
+
+ bzero(&arg, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+
+ arg.v_integer = 1;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "ECON", 1, &arg, NULL);
+
+ /* Enable all events */
+ arg.v_integer = 0xffff;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
+
+ /* Enable hotkeys */
+ arg.v_integer = 0x04;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
+ arg.v_integer = 0x02;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
+ arg.v_integer = 0x10;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
+ arg.v_integer = 0x00;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
+ arg.v_integer = 0x02;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN03", 1, &arg, NULL);
+ arg.v_integer = 0x101;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
+}
+
+int
+acpisony_find_offset(struct acpisony_softc *sc, int key)
+{
+ struct aml_value arg, res;
+ int val;
+
+ bzero(&arg, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+
+ for (arg.v_integer = 0x20; arg.v_integer < 0x30; arg.v_integer++) {
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN00", 1, &arg, &res);
+ val = aml_val2int(&res);
+ aml_freevalue(&res);
+ if (val == key) {
+ DPRINTF(("Matched key %X\n", val));
+ return arg.v_integer - 0x20;
+ }
+ }
+
+ return -1;
+}
+
+int
+acpisony_set_hotkey(struct acpisony_softc *sc, int key, int val)
+{
+ int off, rc = -1;
+ struct aml_value res, arg;
+
+ bzero(&arg, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+
+ off = acpisony_find_offset(sc, key);
+ DPRINTF(("off = %X\n", off));
+ if (off < 0)
+ return rc;
+
+ arg.v_integer = off | val;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, &res);
+ rc = aml_val2int(&res);
+ aml_freevalue(&res);
+
+ return rc;
+}
+
+void
+acpisony_brightness_down(struct acpisony_softc *sc)
+{
+ int val;
+
+ val = acpisony_get_brightness(sc);
+ DPRINTF(("current value = %X", val));
+ if (val > 0)
+ val--;
+ else
+ val = 0;
+ DPRINTF(("next value = %X", val));
+ acpisony_set_brightness(sc, val);
+}
+
+int
+acpisony_get_brightness(struct acpisony_softc *sc)
+{
+ struct aml_value res;
+ int val;
+
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBRT", 0, NULL, &res);
+ val = aml_val2int(&res);
+ aml_freevalue(&res);
+
+ return val;
+}
+
+void
+acpisony_set_brightness(struct acpisony_softc *sc, int level)
+{
+ struct aml_value arg;
+
+ bzero(&arg, sizeof(arg));
+ arg.type = AML_OBJTYPE_INTEGER;
+ arg.v_integer = level;
+ aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBRT", 1, &arg, NULL);
+ aml_freevalue(&arg);
+}
diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi
index 7a1c444bbc5..58885dfc2f9 100644
--- a/sys/dev/acpi/files.acpi
+++ b/sys/dev/acpi/files.acpi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.acpi,v 1.23 2009/07/23 01:38:16 cnst Exp $
+# $OpenBSD: files.acpi,v 1.24 2010/07/26 11:29:23 pirofti Exp $
#
# Config file and device description for machine-independent ACPI code.
# Included by ports that need it.
@@ -76,6 +76,11 @@ device acpithinkpad
attach acpithinkpad at acpi
file dev/acpi/acpithinkpad.c acpithinkpad
+# Sony support
+device acpisony
+attach acpisony at acpi
+file dev/acpi/acpisony.c acpisony
+
# ACPI video
define acpivideo {}
device acpivideo