commit 5d0d9803f8310f302382621ab25c3ef9b711cb64 Author: Makoto Fujiwara (CF-S9) Date: Sun Jan 8 17:45:13 2017 +0900 (panasonic, toughbook) Add new files based upon gnats.netbsd.org/46870 diff --git a/share/man/man4/panasonic.4 b/share/man/man4/panasonic.4 new file mode 100644 index 00000000000..0f97b915b71 --- /dev/null +++ b/share/man/man4/panasonic.4 @@ -0,0 +1,74 @@ +.\" +.\" Copyright (c) 2012 Nathanial Sloss +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 29, 2012 +.Dt PANASONIC 4 +.Os +.Sh NAME +.Nm panasonic +.Nd Panasonic TOUGHBOOK laptop features support +.Sh SYNOPSIS +.Cd "panasonic* at acpi?" +.Sh DESCRIPTION +The +.Nm +driver provides support for hotkey handling and screen brightness found on +Panasonic TOUGHBOOK laptop computers. +.Pp +The +.Nm +driver provides support for modifying the screen brightness via the +.Xr sysctl 8 +interface. +.Pp +The following +.Xr sysctl 8 +variables are available: +.Pp +.Bl -tag -width "hw.panasonic.brightness [R/W]" -compact +.It Em hw.panasonic.brightness Bq R/W +Controls current LCD brightness. +Range [0-100]. +.El +.Sh SEE ALSO +.Xr acpi 4 , +.Xr acpivga 4 , +.Xr pmf 9 , +.Xr sysmon_envsys 9 , +.Xr toughbook_hbtn 4 +.Sh HISTORY +The +.Nm +device driver appeared in FreeBSD and was extended and ported to +.Nx 3.0.1 by Nathanial Sloss. +.Sh AUTHORS +.An OGAWA Takaya Aq t-ogawa@triaez.kaisei.org +.An Yoshihiro TAKAHASHI Aq nyan@FreeBSD.org +.An Nathanial Sloss +.Sh BUGS +If the computer is fully supported by +.Xr acpivga 4 then a different method +for controlling the screen brightness is used and the above mentioned +.Xr sysctl 8 variable may not work. diff --git a/share/man/man4/toughbook_hbtn.4 b/share/man/man4/toughbook_hbtn.4 new file mode 100644 index 00000000000..c86489046cd --- /dev/null +++ b/share/man/man4/toughbook_hbtn.4 @@ -0,0 +1,63 @@ +.\" +.\" Copyright (c) 2012 Nathanial Sloss +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd July 2, 2012 +.Dt TOUGHBOOK_HBTN 4 +.Os +.Sh NAME +.Nm toughbook_hbtn +.Nd Panasonic Toughbook CF-18/19 Tablet Buttons +.Sh SYNOPSIS +.Cd "toughbook_hbtn* at acpi?" +.Sh DESCRIPTION +The +.Nm +driver supports the tablet buttons found on CF-18/19 Toughbook computers: +.Bl -column -offset indent "Button " "/etc/powerd/actions/button" +.It Sy Button Ta Sy Script +.It Li Input (Keyboard) Ta Pa /etc/powerd/actions/input_panel-button +.It Li Enter (Target) Ta Pa /etc/powerd/actions/enter-button +.It Li Rotation Ta Pa /etc/powerd/actions/rotation-button +.It Li Security (Key) Ta Pa /etc/powerd/actions/security +.El +.Pp +When a button is pressed, the +.Xr powerd 8 +daemon, if running, +will execute the corresponding script. +.Sh SEE ALSO +.Xr acpi 4 , +.Xr panasonic 4 , +.Xr powerd 8 +.Sh AUTHORS +Software and manual page written by Nathanial Sloss +.Sh HISTORY +The +.Nm +driver +was an addition to +.Xr panasonic 4 +which was ported to +.Nx 3.0.1 but was never released . diff --git a/sys/dev/acpi/panasonic_acpi.c b/sys/dev/acpi/panasonic_acpi.c new file mode 100644 index 00000000000..94e9cfed908 --- /dev/null +++ b/sys/dev/acpi/panasonic_acpi.c @@ -0,0 +1,626 @@ +/*- + * Copyright (c) 2006-2012 Nathanial Sloss + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2003 OGAWA Takaya + * Copyright (c) 2004 Yoshihiro TAKAHASHI + * All rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +typedef struct panasonic_softc { + device_t sc_dev; + struct acpi_devnode *sc_node; + + int sc_brightness; + int sc_brightness_min; + int sc_brightness_max; + +#define PANASONIC_PSW_SLEEP 0 +#define PANASONIC_PSW_HIBERNATE 1 +#define PANASONIC_PSW_DISPLAY_CYCLE 2 +#define PANASONIC_PSW_BATTERY_INFO 3 +#define PANASONIC_PSW_LAST 4 + + struct sysmon_pswitch sc_smpsw[PANASONIC_PSW_LAST]; + bool sc_smpsw_valid; + + struct sysctllog *sc_log; + int sc_brightness_mib; + +} panasonic_softc_t; + +/* Hotkey buttons (HKEY) */ +#define PANASONIC_NOTIFY_BrightnessDownPRESSED 0x81 +#define PANASONIC_NOTIFY_BrightnessDownRELEASED 0x01 + +#define PANASONIC_NOTIFY_BrightnessUpPRESSED 0x82 +#define PANASONIC_NOTIFY_BrightnessUpRELEASED 0x02 + +#define PANASONIC_NOTIFY_DisplayCyclePRESSED 0x83 +#define PANASONIC_NOTIFY_DisplayCycleRELEASED 0x03 + +#define PANASONIC_NOTIFY_VolumeMutePRESSED 0x84 +#define PANASONIC_NOTIFY_VolumeMuteRELEASED 0x04 + +#define PANASONIC_NOTIFY_VolumeDownPRESSED 0x85 +#define PANASONIC_NOTIFY_VolumeDownRELEASED 0x05 + +#define PANASONIC_NOTIFY_VolumeUpPRESSED 0x86 +#define PANASONIC_NOTIFY_VolumeUpRELEASED 0x06 + +#define PANASONIC_NOTIFY_SuspendToRamPRESSED 0x07 + +#define PANASONIC_NOTIFY_BatteryInfoPRESSED 0x89 +#define PANASONIC_NOTIFY_BatteryInfoRELEASED 0x09 + +#define PANASONIC_NOTIFY_SuspendToHddPRESSED 0x0A + +#define ACPI_SERIAL_BEGIN(x) +#define ACPI_SERIAL_END(x) +#define ACPI_SERIAL_ASSERT(x) + +#define HKEY_SET 0 +#define HKEY_GET 1 + +/* Registers */ +#define HKEY_REG_LCD_BRIGHTNESS_MAX_AC 0x02 +#define HKEY_REG_LCD_BRIGHTNESS_MIN_AC 0x03 +#define HKEY_REG_LCD_BRIGHTNESS_AC 0x04 +#define HKEY_REG_LCD_BRIGHTNESS_MAX_DC 0x05 +#define HKEY_REG_LCD_BRIGHTNESS_MIN_DC 0x06 +#define HKEY_REG_LCD_BRIGHTNESS_DC 0x07 +#define HKEY_REG_SOUND_MUTE 0x08 + +/* Field definitions */ +#define HKEY_LCD_BRIGHTNESS_BITS 4 +#define HKEY_LCD_BRIGHTNESS_DIV ((1 << HKEY_LCD_BRIGHTNESS_BITS) - 1) + +#define LCD_BRIGHTNESS_DOWN 0 +#define LCD_BRIGHTNESS_UP 1 + +#define LCD_BRIGHTNESS_MIN 0 +#define LCD_BRIGHTNESS_MAX 1 + +#define HARDWARE_UNMUTE 0 +#define HARDWARE_MUTE 1 + +static int panasonic_match(device_t, cfdata_t, void *); +static void panasonic_attach(device_t, device_t, void *); +static int panasonic_detach(device_t, int); + +static void panasonic_notify_handler(ACPI_HANDLE, UINT32, void *); + +static void panasonic_init(struct panasonic_softc *); +static void panasonic_sysctl_setup(struct panasonic_softc *); + +static int +acpi_panasonic_hkey_event(device_t, ACPI_INTEGER *); + +static void +acpi_panasonic_hkey_action(device_t, ACPI_INTEGER); + +static void panasonic_acpi_brightness_up(device_t); + +static void panasonic_acpi_brightness_down(device_t); + +static void hkey_lcd_brightness_action(struct panasonic_softc *, int); + +static int +hkey_lcd_brightness(struct panasonic_softc *, int, ACPI_INTEGER *); + +static ACPI_INTEGER +acpi_panasonic_sinf(ACPI_HANDLE, ACPI_INTEGER); + +static void +acpi_panasonic_sset(ACPI_HANDLE, ACPI_INTEGER, ACPI_INTEGER); + +static int +hkey_sound_mute(ACPI_HANDLE, int, ACPI_INTEGER *); + +CFATTACH_DECL_NEW(panasonic, sizeof(panasonic_softc_t), + panasonic_match, panasonic_attach, panasonic_detach, NULL); + +static const char * const panasonic_ids[] = { + "MAT0019", + NULL +}; + +static int +panasonic_match(device_t parent, cfdata_t match, void *opaque) +{ + struct acpi_attach_args *aa = opaque; + + if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) + return 0; + + return acpi_match_hid(aa->aa_node->ad_devinfo, panasonic_ids); +} + +static void +panasonic_attach(device_t parent, device_t self, void *opaque) +{ + panasonic_softc_t *sc = device_private(self); + struct acpi_attach_args *aa = opaque; + struct sysmon_pswitch *psw; + ACPI_STATUS rv; + + sc->sc_node = aa->aa_node; + sc->sc_dev = self; + + aprint_naive(": Panasonic Hotkeys\n"); + aprint_normal(": Panasonic Hotkeys\n"); + + rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, ACPI_ALL_NOTIFY, + panasonic_notify_handler, sc); + if (ACPI_FAILURE(rv)) + aprint_error_dev(self, "couldn't install notify handler: %s\n", + AcpiFormatException(rv)); + + /* Register power switches with sysmon */ + psw = sc->sc_smpsw; + sc->sc_smpsw_valid = true; + + psw[PANASONIC_PSW_SLEEP].smpsw_name = device_xname(self); + psw[PANASONIC_PSW_SLEEP].smpsw_type = PSWITCH_TYPE_SLEEP; +#if notyet + psw[PANASONIC_PSW_HIBERNATE].smpsw_name = device_xname(self); + mpsw[PANASONIC_PSW_HIBERNATE].smpsw_type = PSWITCH_TYPE_HIBERNATE; +#endif + int i; + for (i = PANASONIC_PSW_DISPLAY_CYCLE; i < PANASONIC_PSW_LAST; i++) + psw[i].smpsw_type = PSWITCH_TYPE_HOTKEY; + psw[PANASONIC_PSW_DISPLAY_CYCLE].smpsw_name = PSWITCH_HK_DISPLAY_CYCLE; + psw[PANASONIC_PSW_BATTERY_INFO].smpsw_name = PSWITCH_HK_BATTERY_INFO; + + for (i = 0; i < PANASONIC_PSW_LAST; i++) { + if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) { + aprint_error_dev(self, + "couldn't register with sysmon\n"); + sc->sc_smpsw_valid = false; + break; + } + } + if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP, + panasonic_acpi_brightness_up, true)) + aprint_error_dev(self, + "couldn't register BRIGHTNESS UP handler\n"); + + if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN, + panasonic_acpi_brightness_down, true)) + aprint_error_dev(self, + "couldn't register BRIGHTNESS DOWN handler\n"); + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + + panasonic_init(sc); + panasonic_sysctl_setup(sc); +} + +static int +panasonic_detach(device_t self, int flags) +{ + struct panasonic_softc *sc = device_private(self); + int i; + + if (sc->sc_smpsw_valid) + for (i = 0; i < PANASONIC_PSW_LAST; i++) + sysmon_pswitch_unregister(&sc->sc_smpsw[i]); + + if (sc->sc_log) + sysctl_teardown(&sc->sc_log); + pmf_device_deregister(self); + + return 0; +} + +static void +panasonic_notify_handler(ACPI_HANDLE hdl, UINT32 notify, void *opaque) +{ + panasonic_softc_t *sc = opaque; + + ACPI_INTEGER key; + key = 0; + + switch (notify) { + case 0x80: + ACPI_SERIAL_BEGIN(panasonic); + if (acpi_panasonic_hkey_event(sc->sc_dev, &key) == 0) { + acpi_panasonic_hkey_action(sc->sc_dev, key); + } + + ACPI_SERIAL_END(panasonic); + break; + default: + aprint_debug_dev(sc->sc_dev, "unknown notify: %#x\n", notify); + break; + } +} + +static void +panasonic_init(struct panasonic_softc *sc) +{ + ACPI_INTEGER val; + ACPI_HANDLE hdl; + + hdl = sc->sc_node->ad_handle; + val = HARDWARE_UNMUTE; + + /* Unmute the speaker - Hardware */ + hkey_sound_mute(hdl, HKEY_SET, &val); + + /* Initialise variables */ + sc->sc_brightness_min = acpi_panasonic_sinf(hdl, + HKEY_REG_LCD_BRIGHTNESS_MIN_AC); + sc->sc_brightness_max = acpi_panasonic_sinf(hdl, + HKEY_REG_LCD_BRIGHTNESS_MAX_AC); + if (sc->sc_brightness_max <= 0) + sc->sc_brightness_max = 100; + sc->sc_brightness = (acpi_panasonic_sinf(hdl, + HKEY_REG_LCD_BRIGHTNESS_AC) * 100) / sc->sc_brightness_max; +} + +static int +panasonic_sysctl_verify(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct panasonic_softc *sc; + ACPI_INTEGER val; + int err, tmp; + + node = *rnode; + sc = rnode->sysctl_data; + + if (node.sysctl_num == sc->sc_brightness_mib) { + err = hkey_lcd_brightness(sc, HKEY_GET, &val); + if (err) + val = sc->sc_brightness_min; + tmp = (val * 100) / sc->sc_brightness_max; + node.sysctl_data = &tmp; + err = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (err || newp == NULL) + return err; + + if (tmp < 0 || tmp > 100) + return EINVAL; + val = (tmp * sc->sc_brightness_max) / 100; + if (val == 0) + val = sc->sc_brightness_min; + err = hkey_lcd_brightness(sc, HKEY_SET, &val); + if (err) + return err; + tmp = (val * 100) / sc->sc_brightness_max; + sc->sc_brightness = tmp; + } + + return 0; +} + +static void +panasonic_sysctl_setup(struct panasonic_softc *sc) +{ + const struct sysctlnode *node, *node_brightness; + int err; + + err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0, + CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL); + if (err) + goto sysctl_err; + + err = sysctl_createv(&sc->sc_log, 0, NULL, &node, 0, + CTLTYPE_NODE, "panasonic", + SYSCTL_DESCR("Toughbook controls"), NULL, 0, + NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); + if (err) + goto sysctl_err; + + err = sysctl_createv(&sc->sc_log, 0, &node, &node_brightness, + CTLFLAG_READWRITE | CTLFLAG_ANYWRITE, CTLTYPE_INT, "brightness", + SYSCTL_DESCR("Screen brightness (Percent)"), + panasonic_sysctl_verify, 0, sc, 0, + CTL_CREATE, CTL_EOL); + if (err) + goto sysctl_err; + sc->sc_brightness_mib = node_brightness->sysctl_num; + + return; +sysctl_err: + aprint_error_dev(sc->sc_dev, "failed to add sysctl nodes. (%d)\n", err); +} + +static int +acpi_panasonic_hkey_event(device_t self, ACPI_INTEGER *arg) { + + struct panasonic_softc *sc = device_private(self); + + ACPI_BUFFER buf; + ACPI_OBJECT *res; + ACPI_INTEGER val; + int status; + + ACPI_SERIAL_ASSERT(panasonic); + status = ENXIO; + + buf.Length = ACPI_ALLOCATE_BUFFER; + buf.Pointer = NULL; + AcpiEvaluateObject(sc->sc_node->ad_handle, "HINF", NULL, &buf); + res = (ACPI_OBJECT *)buf.Pointer; + if (res->Type != ACPI_TYPE_INTEGER) { + aprint_error_dev(self, "HINF returned non-integer\n"); + goto end; + } + val = res->Integer.Value; + + *arg = val; + status = 0; +end: + if (buf.Pointer) + AcpiOsFree(buf.Pointer); + + return (status); +} + +static void +acpi_panasonic_hkey_action(device_t self, ACPI_INTEGER key) +{ + + struct panasonic_softc *sc = device_private(self); + + ACPI_SERIAL_ASSERT(panasonic); + + switch (key) { + case PANASONIC_NOTIFY_BrightnessDownPRESSED: + pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN); + break; + case PANASONIC_NOTIFY_BrightnessDownRELEASED: + break; + case PANASONIC_NOTIFY_BrightnessUpPRESSED: + pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP); + break; + case PANASONIC_NOTIFY_BrightnessUpRELEASED: + break; + case PANASONIC_NOTIFY_DisplayCyclePRESSED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_DISPLAY_CYCLE], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_DisplayCycleRELEASED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_DISPLAY_CYCLE], + PSWITCH_EVENT_RELEASED); + break; + case PANASONIC_NOTIFY_VolumeMutePRESSED: + pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE); + break; + case PANASONIC_NOTIFY_VolumeMuteRELEASED: + break; + case PANASONIC_NOTIFY_VolumeDownPRESSED: + pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN); + break; + case PANASONIC_NOTIFY_VolumeDownRELEASED: + break; + case PANASONIC_NOTIFY_VolumeUpPRESSED: + pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP); + break; + case PANASONIC_NOTIFY_VolumeUpRELEASED: + break; + case PANASONIC_NOTIFY_SuspendToRamPRESSED: + /* Suspend. */ + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_SLEEP], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_BatteryInfoPRESSED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_BATTERY_INFO], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_BatteryInfoRELEASED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_BATTERY_INFO], + PSWITCH_EVENT_RELEASED); + break; + case PANASONIC_NOTIFY_SuspendToHddPRESSED: +#if notyet + /* Hibernate. */ + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_HIBERNATE], + PSWITCH_EVENT_PRESSED); +#endif + break; + default: + aprint_error_dev(sc->sc_dev, "Unknown Key 0x%X\n", (int)key); + break; + } +} + +static void +panasonic_acpi_brightness_up(device_t self){ + + struct panasonic_softc *sc = device_private(self); + + hkey_lcd_brightness_action(sc, LCD_BRIGHTNESS_UP); + +} + +static void +panasonic_acpi_brightness_down(device_t self){ + + struct panasonic_softc *sc = device_private(self); + + hkey_lcd_brightness_action(sc, LCD_BRIGHTNESS_DOWN); + +} + +static void +hkey_lcd_brightness_action(struct panasonic_softc *sc, int direction){ + + ACPI_INTEGER arg; + + hkey_lcd_brightness(sc, HKEY_GET, &arg); + + if (direction == LCD_BRIGHTNESS_UP) + arg += sc->sc_brightness_max / HKEY_LCD_BRIGHTNESS_DIV; + else + arg -= sc->sc_brightness_max / HKEY_LCD_BRIGHTNESS_DIV; + + if (arg < sc->sc_brightness_min) + arg = sc->sc_brightness_min; + else if (arg > sc->sc_brightness_max) + arg = sc->sc_brightness_max; + + hkey_lcd_brightness(sc, HKEY_SET, &arg); + +} + +static int +hkey_lcd_brightness(struct panasonic_softc *sc, int op, ACPI_INTEGER *val) +{ + ACPI_HANDLE hdl; + ACPI_INTEGER reg; + + hdl = sc->sc_node->ad_handle; + + reg = HKEY_REG_LCD_BRIGHTNESS_AC; + + ACPI_SERIAL_ASSERT(panasonic); + switch (op) { + case HKEY_SET: + if (*val < sc->sc_brightness_min || + *val > sc->sc_brightness_max) + return (EINVAL); + acpi_panasonic_sset(hdl, reg, *val); + break; + case HKEY_GET: + *val = acpi_panasonic_sinf(hdl, reg); + break; + } + + return (0); +} + +static ACPI_INTEGER +acpi_panasonic_sinf(ACPI_HANDLE hdl, ACPI_INTEGER index) +{ + ACPI_BUFFER buf; + ACPI_OBJECT *res; + ACPI_INTEGER ret; + + ACPI_SERIAL_ASSERT(panasonic); + ret = -1; + buf.Length = ACPI_ALLOCATE_BUFFER; + buf.Pointer = NULL; + AcpiEvaluateObject(hdl, "SINF", NULL, &buf); + res = (ACPI_OBJECT *)buf.Pointer; + if (res->Type == ACPI_TYPE_PACKAGE) + ret = res->Package.Elements[index].Integer.Value; + AcpiOsFree(buf.Pointer); + + return (ret); +} + +static void +acpi_panasonic_sset(ACPI_HANDLE hdl, ACPI_INTEGER index, ACPI_INTEGER val) +{ + ACPI_OBJECT_LIST args; + ACPI_OBJECT obj[2]; + + ACPI_SERIAL_ASSERT(panasonic); + obj[0].Type = ACPI_TYPE_INTEGER; + obj[0].Integer.Value = index; + obj[1].Type = ACPI_TYPE_INTEGER; + obj[1].Integer.Value = val; + args.Count = 2; + args.Pointer = obj; + AcpiEvaluateObject(hdl, "SSET", &args, NULL); +} + +static int +hkey_sound_mute(ACPI_HANDLE hdl, int op, ACPI_INTEGER *val) +{ + + ACPI_SERIAL_ASSERT(panasonic); + switch (op) { + case HKEY_SET: + if (*val != 0 && *val != 1) + return (EINVAL); + acpi_panasonic_sset(hdl, HKEY_REG_SOUND_MUTE, *val); + break; + case HKEY_GET: + *val = acpi_panasonic_sinf(hdl, HKEY_REG_SOUND_MUTE); + break; + } + + return (0); +} + diff --git a/sys/dev/acpi/toughbook_hbtn_acpi.c b/sys/dev/acpi/toughbook_hbtn_acpi.c new file mode 100644 index 00000000000..bbe23ab4ffb --- /dev/null +++ b/sys/dev/acpi/toughbook_hbtn_acpi.c @@ -0,0 +1,287 @@ +/*- + * Copyright (c)2008 - 2012 Nathanial Sloss + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Panasonic Toughbook CF-18/19 (and possibly others) tablet button driver. */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +typedef struct toughbook_hbtn_softc { + device_t sc_dev; + struct acpi_devnode *sc_node; + +#define PANASONIC_PSW_SECURITY 0 +#define PANASONIC_PSW_ROTATION 1 +#define PANASONIC_PSW_ENTER 2 +#define PANASONIC_PSW_INPUT_PANEL 3 +#define PANASONIC_PSW_LAST 4 + + struct sysmon_pswitch sc_smpsw[PANASONIC_PSW_LAST]; + bool sc_smpsw_valid; + +} toughbook_hbtn_softc_t; + +/* Tablet buttons (HBTN) */ +#define PANASONIC_NOTIFY_SecurityPRESSED 0x34 +#define PANASONIC_NOTIFY_SecurityRELEASED 0x35 + +#define PANASONIC_NOTIFY_RotationPRESSED 0x36 +#define PANASONIC_NOTIFY_RotationRELEASED 0x37 + +#define PANASONIC_NOTIFY_EnterPRESSED 0x38 +#define PANASONIC_NOTIFY_EnterRELEASED 0x39 + +#define PANASONIC_NOTIFY_InputPanelPRESSED 0x3A +#define PANASONIC_NOTIFY_InputPanelRELEASED 0x3B + +#define ACPI_SERIAL_BEGIN(x) +#define ACPI_SERIAL_END(x) +#define ACPI_SERIAL_ASSERT(x) + +#define HKEY_SET 0 +#define HKEY_GET 1 + +static int hbtn_match(device_t, cfdata_t, void *); +static void hbtn_attach(device_t, device_t, void *); +static int hbtn_detach(device_t, int); + +static void hbtn_notify_handler(ACPI_HANDLE, UINT32, void *); + +static int +acpi_hbtn_event(device_t, ACPI_INTEGER *); + +static void +acpi_hbtn_action(device_t, ACPI_INTEGER); + +CFATTACH_DECL_NEW(toughbook_hbtn, sizeof(toughbook_hbtn_softc_t), + hbtn_match, hbtn_attach, hbtn_detach, NULL); + +static const char * const toughbook_hbtn_ids[] = { + "MAT001F", + "MAT0020", + NULL +}; + +static int +hbtn_match(device_t parent, cfdata_t match, void *opaque) +{ + struct acpi_attach_args *aa = opaque; + + if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) + return 0; + + return acpi_match_hid(aa->aa_node->ad_devinfo, toughbook_hbtn_ids); +} + +static void +hbtn_attach(device_t parent, device_t self, void *opaque) +{ + toughbook_hbtn_softc_t *sc = device_private(self); + struct acpi_attach_args *aa = opaque; + struct sysmon_pswitch *psw; + ACPI_STATUS rv; + + sc->sc_node = aa->aa_node; + sc->sc_dev = self; + + aprint_naive(": Toughbook tablet buttons\n"); + aprint_normal(": Toughbook tablet buttons\n"); + + rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, ACPI_ALL_NOTIFY, + hbtn_notify_handler, sc); + if (ACPI_FAILURE(rv)) + aprint_error_dev(self, "couldn't install notify handler: %s\n", + AcpiFormatException(rv)); + + /* Register power switches with sysmon */ + psw = sc->sc_smpsw; + sc->sc_smpsw_valid = true; + + int i; + for (i = PANASONIC_PSW_SECURITY; i < PANASONIC_PSW_LAST; i++) + psw[i].smpsw_type = PSWITCH_TYPE_HOTKEY; + psw[PANASONIC_PSW_SECURITY].smpsw_name = "security"; + psw[PANASONIC_PSW_ROTATION].smpsw_name = "rotation-button"; + psw[PANASONIC_PSW_ENTER].smpsw_name = "enter-button"; + psw[PANASONIC_PSW_INPUT_PANEL].smpsw_name = "input_panel-button"; + + for (i = 0; i < PANASONIC_PSW_LAST; i++) { + if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) { + aprint_error_dev(self, + "couldn't register with sysmon\n"); + sc->sc_smpsw_valid = false; + break; + } + } + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + +} + +static int +hbtn_detach(device_t self, int flags) +{ + toughbook_hbtn_softc_t *sc = device_private(self); + int i; + + if (sc->sc_smpsw_valid) + for (i = 0; i < PANASONIC_PSW_LAST; i++) + sysmon_pswitch_unregister(&sc->sc_smpsw[i]); + + pmf_device_deregister(self); + + return 0; +} + +static void +hbtn_notify_handler(ACPI_HANDLE hdl, UINT32 notify, void *opaque) +{ + toughbook_hbtn_softc_t *sc = opaque; + + ACPI_INTEGER key; + key = 0; + + switch (notify) { + case 0x80: + ACPI_SERIAL_BEGIN(panasonic); + if (acpi_hbtn_event(sc->sc_dev, &key) == 0) { + acpi_hbtn_action(sc->sc_dev, key); + } + + ACPI_SERIAL_END(panasonic); + break; + default: + aprint_debug_dev(sc->sc_dev, "unknown notify: %#x\n", notify); + break; + } + +} + +static int +acpi_hbtn_event(device_t self, ACPI_INTEGER *arg) { + + toughbook_hbtn_softc_t *sc = device_private(self); + + ACPI_BUFFER buf; + ACPI_OBJECT *res; + ACPI_INTEGER val; + int status; + + ACPI_SERIAL_ASSERT(panasonic); + status = ENXIO; + + buf.Length = ACPI_ALLOCATE_BUFFER; + buf.Pointer = NULL; + AcpiEvaluateObject(sc->sc_node->ad_handle, "HINF", NULL, &buf); + res = (ACPI_OBJECT *)buf.Pointer; + if (res->Type != ACPI_TYPE_INTEGER) { + aprint_error_dev(self, "HINF returned non-integer\n"); + goto end; + } + val = res->Integer.Value; + + *arg = val; + status = 0; +end: + if (buf.Pointer) + AcpiOsFree(buf.Pointer); + + return status; +} + +static void +acpi_hbtn_action(device_t self, ACPI_INTEGER key) +{ + + toughbook_hbtn_softc_t *sc = device_private(self); + + ACPI_SERIAL_ASSERT(panasonic); + + switch (key) { + case PANASONIC_NOTIFY_SecurityPRESSED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_SECURITY], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_SecurityRELEASED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_SECURITY], + PSWITCH_EVENT_RELEASED); + break; + case PANASONIC_NOTIFY_RotationPRESSED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ROTATION], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_RotationRELEASED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ROTATION], + PSWITCH_EVENT_RELEASED); + break; + case PANASONIC_NOTIFY_EnterPRESSED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ENTER], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_EnterRELEASED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ENTER], + PSWITCH_EVENT_RELEASED); + break; + case PANASONIC_NOTIFY_InputPanelPRESSED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_INPUT_PANEL], + PSWITCH_EVENT_PRESSED); + break; + case PANASONIC_NOTIFY_InputPanelRELEASED: + if (sc->sc_smpsw_valid == false) + break; + sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_INPUT_PANEL], + PSWITCH_EVENT_RELEASED); + break; + default: + aprint_error_dev(sc->sc_dev, "Unknown Key 0x%X\n", (int)key); + } +} +