From 8a193ee5f35905027e31287f1d89c8049c32524a Mon Sep 17 00:00:00 2001 From: pirofti Date: Mon, 26 Jul 2010 11:29:23 +0000 Subject: [PATCH] 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@. --- share/man/man4/Makefile | 4 +- share/man/man4/acpisony.4 | 43 +++++ sys/arch/amd64/conf/GENERIC | 3 +- sys/arch/i386/conf/GENERIC | 3 +- sys/dev/acpi/acpi.c | 25 ++- sys/dev/acpi/acpisony.c | 329 ++++++++++++++++++++++++++++++++++++ sys/dev/acpi/files.acpi | 7 +- 7 files changed, 408 insertions(+), 6 deletions(-) create mode 100644 share/man/man4/acpisony.4 create mode 100644 sys/dev/acpi/acpisony.c diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index feda76c49d9..dfe736bba9b 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -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 index 00000000000..b29dd31cc5e --- /dev/null +++ b/share/man/man4/acpisony.4 @@ -0,0 +1,43 @@ +.\" $OpenBSD: acpisony.4,v 1.1 2010/07/26 11:29:23 pirofti Exp $ +.\" +.\" Copyright (c) 2010 Paul Irofti +.\" +.\" 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 . 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 * Copyright (c) 2005 Jordan Hargrave @@ -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 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 + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include + +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 -- 2.20.1