Add support for Sony ACPI hotkeys via a new driver: acpisony(4).
authorpirofti <pirofti@openbsd.org>
Mon, 26 Jul 2010 11:29:23 +0000 (11:29 +0000)
committerpirofti <pirofti@openbsd.org>
Mon, 26 Jul 2010 11:29:23 +0000 (11:29 +0000)
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@.

share/man/man4/Makefile
share/man/man4/acpisony.4 [new file with mode: 0644]
sys/arch/amd64/conf/GENERIC
sys/arch/i386/conf/GENERIC
sys/dev/acpi/acpi.c
sys/dev/acpi/acpisony.c [new file with mode: 0644]
sys/dev/acpi/files.acpi

index feda76c..dfe736b 100644 (file)
@@ -1,9 +1,9 @@
-#      $OpenBSD: Makefile,v 1.511 2010/07/06 19:59:58 deraadt Exp $
+#      $OpenBSD: Makefile,v 1.512 2010/07/26 11:29:23 pirofti 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 acpipwrres.4 \
-       acpithinkpad.4 acpitimer.4 acpivideo.4 acpivout.4 \
+       acpisony.4 acpithinkpad.4 acpitimer.4 acpivideo.4 acpivout.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 age.4 alc.4 ale.4 agp.4 \
        aha.4 ahb.4 ahc.4 ahci.4 ahd.4 aibs.4 aic.4 \
diff --git a/share/man/man4/acpisony.4 b/share/man/man4/acpisony.4
new file mode 100644 (file)
index 0000000..b29dd31
--- /dev/null
@@ -0,0 +1,43 @@
+.\"    $OpenBSD: acpisony.4,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 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: July 26 2010 $
+.Dt ACPISONY 4
+.Os
+.Sh NAME
+.Nm acpisony
+.Nd ACPI video output
+.Sh SYNOPSIS
+.Cd "acpisony* at acpi?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the ACPI based hotkeys found in many Sony laptops.
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr intro 4 ,
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 4.8 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Paul Irofti Aq pirofti@openbsd.org .
index 23286e3..017a6bf 100644 (file)
@@ -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?
index 9b42015..3a5d646 100644 (file)
@@ -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?
index 2dca3e9..4ba59f3 100644 (file)
@@ -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);
@@ -2229,6 +2233,24 @@ acpi_foundvideo(struct aml_node *node, void *arg)
        return (0);
 }
 
+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)
 {
@@ -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 (file)
index 0000000..a1757b1
--- /dev/null
@@ -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);
+}
index 7a1c444..58885df 100644 (file)
@@ -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