valz_acpi.c revision 1.6
11.6Schristos/*	$NetBSD: valz_acpi.c,v 1.6 2015/09/26 13:04:10 christos Exp $	*/
21.5Snonaka
31.5Snonaka/*-
41.5Snonaka * Copyright (c) 2002 The NetBSD Foundation, Inc.
51.5Snonaka * All rights reserved.
61.5Snonaka *
71.5Snonaka * This code is derived from software contributed to The NetBSD Foundation
81.5Snonaka * by Masanori Kanaoka.
91.5Snonaka *
101.5Snonaka * Redistribution and use in source and binary forms, with or without
111.5Snonaka * modification, are permitted provided that the following conditions
121.5Snonaka * are met:
131.5Snonaka * 1. Redistributions of source code must retain the above copyright
141.5Snonaka *    notice, this list of conditions and the following disclaimer.
151.5Snonaka * 2. Redistributions in binary form must reproduce the above copyright
161.5Snonaka *    notice, this list of conditions and the following disclaimer in the
171.5Snonaka *    documentation and/or other materials provided with the distribution.
181.5Snonaka *
191.5Snonaka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
201.5Snonaka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
211.5Snonaka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
221.5Snonaka * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
231.5Snonaka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
241.5Snonaka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
251.5Snonaka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
261.5Snonaka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
271.5Snonaka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
281.5Snonaka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
291.5Snonaka * POSSIBILITY OF SUCH DAMAGE.
301.5Snonaka */
311.1Sjakllsch
321.1Sjakllsch/*
331.5Snonaka * Copyright 2001 Bill Sommerfeld.
341.1Sjakllsch * All rights reserved.
351.1Sjakllsch *
361.1Sjakllsch * Redistribution and use in source and binary forms, with or without
371.1Sjakllsch * modification, are permitted provided that the following conditions
381.1Sjakllsch * are met:
391.1Sjakllsch * 1. Redistributions of source code must retain the above copyright
401.1Sjakllsch *    notice, this list of conditions and the following disclaimer.
411.1Sjakllsch * 2. Redistributions in binary form must reproduce the above copyright
421.1Sjakllsch *    notice, this list of conditions and the following disclaimer in the
431.1Sjakllsch *    documentation and/or other materials provided with the distribution.
441.5Snonaka * 3. All advertising materials mentioning features or use of this software
451.5Snonaka *    must display the following acknowledgement:
461.5Snonaka *	This product includes software developed for the NetBSD Project by
471.5Snonaka *	Wasabi Systems, Inc.
481.5Snonaka * 4. The name of Wasabi Systems, Inc. may not be used to endorse
491.5Snonaka *    or promote products derived from this software without specific prior
501.5Snonaka *    written permission.
511.1Sjakllsch *
521.5Snonaka * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
531.5Snonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
541.1Sjakllsch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
551.5Snonaka * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
561.5Snonaka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
571.5Snonaka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
581.5Snonaka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
591.5Snonaka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
601.5Snonaka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
611.5Snonaka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
621.5Snonaka * POSSIBILITY OF SUCH DAMAGE.
631.5Snonaka */
641.5Snonaka
651.5Snonaka/*
661.5Snonaka * ACPI VALZ Driver for Toshiba dynabook R63/PS
671.5Snonaka *	This driver is based on vald_acpi.c
681.5Snonaka */
691.5Snonaka
701.5Snonaka/*
711.5Snonaka * Obtain information of Toshiba "GHCI" Method from next URL.
721.5Snonaka *           http://www.buzzard.me.uk/toshiba/docs.html
731.5Snonaka *           http://memebeam.org/toys/ToshibaAcpiDriver
741.1Sjakllsch */
751.1Sjakllsch
761.1Sjakllsch#include <sys/cdefs.h>
771.6Schristos__KERNEL_RCSID(0, "$NetBSD: valz_acpi.c,v 1.6 2015/09/26 13:04:10 christos Exp $");
781.1Sjakllsch
791.1Sjakllsch#include <sys/param.h>
801.1Sjakllsch#include <sys/systm.h>
811.5Snonaka#include <sys/device.h>
821.1Sjakllsch
831.5Snonaka#include <dev/acpi/acpica.h>
841.1Sjakllsch#include <dev/acpi/acpireg.h>
851.1Sjakllsch#include <dev/acpi/acpivar.h>
861.1Sjakllsch
871.5Snonaka#define _COMPONENT		ACPI_RESOURCE_COMPONENT
881.5SnonakaACPI_MODULE_NAME		("valz_acpi")
891.5Snonaka
901.5Snonaka#define METHOD_HCI		"GHCI"
911.5Snonaka#define METHOD_HCI_ENABLE	"ENAB"
921.1Sjakllsch
931.5Snonaka/* Operations */
941.5Snonaka/* Get */
951.5Snonaka#define HCI_GET			0xfe00
961.5Snonaka#define SCI_CHECK		0xf000
971.5Snonaka#define SCI_GET			0xf300
981.5Snonaka
991.5Snonaka/* Set */
1001.5Snonaka#define HCI_SET			0xff00
1011.5Snonaka#define SCI_OPEN		0xf100
1021.5Snonaka#define SCI_CLOSE		0xf200
1031.5Snonaka#define SCI_SET			0xf400
1041.5Snonaka
1051.5Snonaka/* Return codes */
1061.5Snonaka#define HCI_SUCCESS		0x0000
1071.5Snonaka#define HCI_FAILURE		0x1000
1081.5Snonaka#define HCI_NOT_SUPPORTED	0x8000
1091.5Snonaka#define HCI_INPUT_ERROR		0x8300
1101.5Snonaka#define HCI_FIFO_EMPTY		0x8c00
1111.5Snonaka
1121.5Snonaka#define SCI_OPENCLOSE_OK	0x0044
1131.5Snonaka#define SCI_NOT_SUPPORTED	0x8000
1141.5Snonaka#define SCI_ALREADY_OPEN	0x8100
1151.5Snonaka#define SCI_NOT_OPEN		0x8200
1161.5Snonaka#define SCI_NOT_PRESENT		0x8600
1171.5Snonaka
1181.5Snonaka/* Functions */
1191.5Snonaka#define HCI_LCD_BACKLIGHT	0x0002
1201.5Snonaka#define HCI_ACADAPTOR		0x0003
1211.5Snonaka#define HCI_SYSTEM_EVENT_FIFO	0x0016
1221.5Snonaka#define HCI_KBD_BACKLIGHT	0x0017
1231.5Snonaka#define HCI_DISPLAY_DEV		0x001c
1241.5Snonaka#define HCI_HOTKEY_EVENT	0x001e
1251.5Snonaka#define HCI_LCD_BRIGHTNESS	0x002a
1261.5Snonaka#define HCI_CPU_SPEED		0x0032
1271.5Snonaka
1281.5Snonaka#define SCI_USB_OFF_CHARGE	0x0150
1291.5Snonaka#define SCI_TOUCHPAD		0x050e
1301.5Snonaka#define SCI_KBD_BACKLIGHT_STS	0x015c
1311.5Snonaka#define SCI_KBD_BACKLIGHT	0x0095
1321.5Snonaka
1331.5Snonaka#define SCI_KBD_BL_TIME_SHIFT	0x10
1341.5Snonaka
1351.5Snonaka/* Field definitions */
1361.5Snonaka#define HCI_LCD_BRIGHTNESS_BITS	3
1371.5Snonaka#define HCI_LCD_BRIGHTNESS_SFT	(16 - HCI_LCD_BRIGHTNESS_BITS)
1381.5Snonaka#define HCI_LCD_BRIGHTNESS_MIN	0
1391.5Snonaka#define HCI_LCD_BRIGHTNESS_MAX	7
1401.5Snonaka#define HCI_VIDEO_DEVICE_FLG	0x0100
1411.5Snonaka#define HCI_CPU_SPEED_BITS	3
1421.5Snonaka#define HCI_CPU_SPEED_SFT	(16 - HCI_CPU_SPEED_BITS)
1431.5Snonaka#define HCI_CPU_SPEED_MAX	((1 << HCI_CPU_SPEED_BITS) - 1)
1441.5Snonaka
1451.5Snonaka/* Key press/release events */
1461.5Snonaka
1471.5Snonaka/* Key press/release events */
1481.5Snonaka#define FN_RELEASE_OFFSET	0x80
1491.5Snonaka#  if 0
1501.5Snonaka/* Not used */
1511.5Snonaka#define FN_PRESS		0x01ff
1521.5Snonaka#define FN_RELEASE		0x0100
1531.5Snonaka#  endif
1541.5Snonaka#define FN_ESC_PRESS		0x0101
1551.5Snonaka#define FN_ESC_RELEASE		(FN_ESC_PRESS + FN_RELEASE_OFFSET)
1561.5Snonaka#define FN_F1_PRESS		0x013b
1571.5Snonaka#define FN_F1_RELEASE		(FN_F1_PRESS + FN_RELEASE_OFFSET)
1581.5Snonaka#define FN_F2_PRESS		0x013c
1591.5Snonaka#define FN_F2_RELEASE		(FN_F2_PRESS + FN_RELEASE_OFFSET)
1601.5Snonaka#define FN_F3_PRESS		0x013d
1611.5Snonaka#define FN_F3_RELEASE		(FN_F3_PRESS + FN_RELEASE_OFFSET)
1621.5Snonaka#define FN_F4_PRESS		0x013e
1631.5Snonaka#define FN_F4_RELEASE		(FN_F4_PRESS + FN_RELEASE_OFFSET)
1641.5Snonaka#define FN_F5_PRESS		0x013f
1651.5Snonaka#define FN_F5_RELEASE		(FN_F5_PRESS + FN_RELEASE_OFFSET)
1661.5Snonaka#define FN_F6_PRESS		0x0140
1671.5Snonaka#define FN_F6_RELEASE		(FN_F6_PRESS + FN_RELEASE_OFFSET)
1681.5Snonaka#define FN_F7_PRESS		0x0141
1691.5Snonaka#define FN_F7_RELEASE		(FN_F7_PRESS + FN_RELEASE_OFFSET)
1701.5Snonaka#define FN_F8_PRESS		0x0142
1711.5Snonaka#define FN_F8_RELEASE		(FN_F8_PRESS + FN_RELEASE_OFFSET)
1721.5Snonaka#define FN_F9_PRESS		0x0143
1731.5Snonaka#define FN_F9_RELEASE		(FN_F9_PRESS + FN_RELEASE_OFFSET)
1741.5Snonaka/* Toggle, they are controlled by hardware */
1751.5Snonaka#define FN_F10_ON		0x1bb0
1761.5Snonaka#define FN_F10_OFF		0x1bb1
1771.5Snonaka#define FN_F11_ON		0x1bb2
1781.5Snonaka#define FN_F11_OFF		0x1bb3
1791.5Snonaka/* Fn+F12 does not emit keycode */
1801.5Snonaka/* dynabook R63/PS does not have KANJI keytop print */
1811.5Snonaka#define FN_KNJ_PRESS		0x0129
1821.5Snonaka#define FN_KNJ_RELEASE		(FN_KNJ_PRESS + FN_RELEASE_OFFSET)
1831.5Snonaka#define FN_1_PRESS		0x0102
1841.5Snonaka#define FN_1_RELEASE		(FN_1_PRESS + FN_RELEASE_OFFSET)
1851.5Snonaka#define FN_2_PRESS		0x0103
1861.5Snonaka#define FN_2_RELEASE		(FN_2_PRESS + FN_RELEASE_OFFSET)
1871.5Snonaka/* Fn+3 and Fn+4 do not emit keybode */
1881.5Snonaka#define FN_Z_PRESS		0x012c
1891.5Snonaka#define FN_Z_RELEASE		(FN_1_PRESS + FN_RELEASE_OFFSET)
1901.5Snonaka#define FN_SPACE_PRESS		0x0139
1911.5Snonaka#define FN_SPACE_RELEASE	(FN_1_PRESS + FN_RELEASE_OFFSET)
1921.5Snonaka#define FN_TAB_PRESS		0x010f
1931.5Snonaka#define FN_TAB_RELEASE		(FN_TAB_PRESS + FN_RELEASE_OFFSET)
1941.5Snonaka#define FN_CAPS_PRESS		0x013a
1951.5Snonaka#define FN_CAPS_RELEASE		(FN_CAPS_PRESS + FN_RELEASE_OFFSET)
1961.5Snonaka#define FN_BACKSPACE_PRESS	0x010e
1971.5Snonaka#define FN_BACKSPACE_RELEASE	(FN_BACKSPACE_PRESS + FN_RELEASE_OFFSET)
1981.5Snonaka#define FN_INS_PRESS		0x0152
1991.5Snonaka#define FN_INS_RELEASE		(FN_INS_PRESS + FN_RELEASE_OFFSET)
2001.5Snonaka#define FN_DEL_PRESS		0x0153
2011.5Snonaka#define FN_DEL_RELEASE		(FN_DEL_PRESS + FN_RELEASE_OFFSET)
2021.5Snonaka#define FN_PRTSC_PRESS		0x0137
2031.5Snonaka#define FN_PRTSC_RELEASE	(FN_PRTSC_PRESS + FN_RELEASE_OFFSET)
2041.5Snonaka
2051.5Snonaka/* HCI register definitions */
2061.5Snonaka#define HCI_WORDS		6 /* number of registers */
2071.5Snonaka#define HCI_REG_AX		0 /* Operation -> return value */
2081.5Snonaka#define HCI_REG_BX		1 /* Function */
2091.5Snonaka#define HCI_REG_CX		2 /* Argument (in or out) */
2101.5Snonaka#define HCI_REG_DX		3 /* unused */
2111.5Snonaka#define HCI_REG_SI		4 /* unused */
2121.5Snonaka#define HCI_REG_DI		5 /* unused */
2131.5Snonaka
2141.5Snonaka#define HCI_ON			0x0001
2151.5Snonaka#define HCI_OFF			0x0000
2161.5Snonaka#define HCI_ENABLE		0x0001
2171.5Snonaka#define HCI_DISABLE		0x0000
2181.5Snonaka
2191.5Snonaka#define HCI_LCD			0x1
2201.5Snonaka#define HCI_CRT			0x2
2211.5Snonaka#define HCI_TV			0x4
2221.5Snonaka
2231.5Snonaka#define SCI_KBD_BL_MODE_MASK	0x1f
2241.5Snonaka#define SCI_KBD_BL_TIMO_SFT	0x10
2251.5Snonaka#define SCI_KBD_BL_MODE_AUTO	0x2
2261.5Snonaka#define SCI_KBD_BL_MODE_ON	0x8
2271.5Snonaka#define SCI_KBD_BL_MODE_OFF	0x10
2281.5Snonaka
2291.5Snonakastruct valz_acpi_softc {
2301.5Snonaka	device_t sc_dev;		/* base device glue */
2311.5Snonaka	struct acpi_devnode *sc_node;	/* our ACPI devnode */
2321.1Sjakllsch};
2331.1Sjakllsch
2341.5Snonakastatic const char * const valz_acpi_hids[] = {
2351.5Snonaka	"TOS6208",
2361.1Sjakllsch	NULL
2371.1Sjakllsch};
2381.1Sjakllsch
2391.5Snonakastatic int	valz_acpi_match(device_t, cfdata_t, void *);
2401.5Snonakastatic void	valz_acpi_attach(device_t, device_t, void *);
2411.1Sjakllsch
2421.5Snonakastatic void	valz_acpi_event(void *);
2431.5Snonakastatic void	valz_acpi_notify_handler(ACPI_HANDLE, uint32_t, void *);
2441.1Sjakllsch
2451.5Snonaka#define ACPI_NOTIFY_ValzHotkeyPressed	0x80
2461.5Snonaka#define ACPI_NOTIFY_ValzLidClosed	0x8f
2471.5Snonaka#define ACPI_NOTIFY_ValzKbdBLChanges	0x92
2481.5Snonaka
2491.5Snonaka/* HCI manipulation */
2501.5Snonakastatic ACPI_STATUS	hci_op(struct valz_acpi_softc *,
2511.5Snonaka				uint32_t *, uint32_t *);
2521.5Snonakastatic ACPI_STATUS	valz_acpi_hci_get(struct valz_acpi_softc *, uint32_t,
2531.5Snonaka					uint32_t, uint32_t *, uint32_t *);
2541.5Snonakastatic ACPI_STATUS	valz_acpi_hci_set(struct valz_acpi_softc *, uint32_t,
2551.5Snonaka					uint32_t, uint32_t, uint32_t *);
2561.5Snonaka
2571.5Snonakastatic ACPI_STATUS	sci_open(struct valz_acpi_softc *);
2581.5Snonakastatic ACPI_STATUS	sci_close(struct valz_acpi_softc *);
2591.5Snonaka
2601.5Snonakastatic ACPI_STATUS	valz_acpi_touchpad_toggle(struct valz_acpi_softc *);
2611.5Snonakastatic ACPI_STATUS	valz_acpi_lcd_backlight_toggle(
2621.5Snonaka					struct valz_acpi_softc *sc);
2631.5Snonaka
2641.5SnonakaCFATTACH_DECL_NEW(valz_acpi, sizeof(struct valz_acpi_softc),
2651.5Snonaka    valz_acpi_match, valz_acpi_attach, NULL, NULL);
2661.5Snonaka
2671.5Snonaka/*
2681.5Snonaka * valz_acpi_match:
2691.5Snonaka *
2701.5Snonaka *	Autoconfiguration `match' routine.
2711.5Snonaka */
2721.1Sjakllschstatic int
2731.5Snonakavalz_acpi_match(device_t parent, cfdata_t match, void *aux)
2741.1Sjakllsch{
2751.1Sjakllsch	struct acpi_attach_args *aa = aux;
2761.1Sjakllsch
2771.1Sjakllsch	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
2781.5Snonaka		return (0);
2791.1Sjakllsch
2801.5Snonaka	return (acpi_match_hid(aa->aa_node->ad_devinfo, valz_acpi_hids));
2811.1Sjakllsch}
2821.1Sjakllsch
2831.5Snonaka/*
2841.5Snonaka * valz_acpi_attach:
2851.5Snonaka *
2861.5Snonaka *	Autoconfiguration `attach' routine.
2871.5Snonaka */
2881.1Sjakllschstatic void
2891.5Snonakavalz_acpi_attach(device_t parent, device_t self, void *aux)
2901.1Sjakllsch{
2911.5Snonaka	struct valz_acpi_softc *sc = device_private(self);
2921.5Snonaka	struct acpi_attach_args *aa = aux;
2931.1Sjakllsch	ACPI_STATUS rv;
2941.1Sjakllsch
2951.5Snonaka	aprint_naive(": Toshiba VALZ\n");
2961.5Snonaka	aprint_normal(": Toshiba VALZ\n");
2971.1Sjakllsch
2981.5Snonaka	sc->sc_node = aa->aa_node;
2991.1Sjakllsch	sc->sc_dev = self;
3001.1Sjakllsch
3011.5Snonaka	/* enable valz notify */
3021.5Snonaka	rv = AcpiEvaluateObject(sc->sc_node->ad_handle, METHOD_HCI_ENABLE,
3031.5Snonaka				NULL, NULL);
3041.5Snonaka	if (ACPI_FAILURE(rv)) {
3051.5Snonaka		aprint_error("Cannot enable VALZ.\n");
3061.5Snonaka	} else {
3071.5Snonaka		(void)acpi_register_notify(sc->sc_node,
3081.5Snonaka		    valz_acpi_notify_handler);
3091.5Snonaka	}
3101.1Sjakllsch}
3111.1Sjakllsch
3121.5Snonaka/*
3131.5Snonaka * valz_acpi_notify_handler:
3141.5Snonaka *
3151.5Snonaka *	Notify handler.
3161.5Snonaka */
3171.1Sjakllschstatic void
3181.5Snonakavalz_acpi_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context)
3191.1Sjakllsch{
3201.5Snonaka	struct valz_acpi_softc *sc;
3211.5Snonaka	device_t self = context;
3221.5Snonaka
3231.5Snonaka	sc = device_private(self);
3241.1Sjakllsch
3251.1Sjakllsch	switch (notify) {
3261.5Snonaka	case ACPI_NOTIFY_ValzHotkeyPressed:
3271.5Snonaka		(void)AcpiOsExecute(OSL_NOTIFY_HANDLER, valz_acpi_event, sc);
3281.1Sjakllsch		break;
3291.5Snonaka
3301.5Snonaka	case ACPI_NOTIFY_ValzLidClosed:
3311.5Snonaka		/* Lid closed */
3321.1Sjakllsch		break;
3331.5Snonaka
3341.5Snonaka	case ACPI_NOTIFY_ValzKbdBLChanges:
3351.5Snonaka		/* Keyboard backlight mode changed */
3361.5Snonaka		break;
3371.5Snonaka
3381.1Sjakllsch	default:
3391.5Snonaka		aprint_error_dev(sc->sc_dev,
3401.5Snonaka		    "unknown notify 0x%02X\n", notify);
3411.1Sjakllsch		break;
3421.1Sjakllsch	}
3431.1Sjakllsch}
3441.1Sjakllsch
3451.5Snonaka/*
3461.5Snonaka * valz_acpi_event:
3471.5Snonaka *
3481.5Snonaka *	Check hotkey event and do it, if event occur.
3491.5Snonaka */
3501.1Sjakllschstatic void
3511.5Snonakavalz_acpi_event(void *arg)
3521.1Sjakllsch{
3531.5Snonaka	struct valz_acpi_softc *sc = arg;
3541.1Sjakllsch	ACPI_STATUS rv;
3551.5Snonaka	uint32_t value, result;
3561.1Sjakllsch
3571.5Snonaka	for (;;) {
3581.5Snonaka		rv = valz_acpi_hci_get(sc, HCI_GET, HCI_SYSTEM_EVENT_FIFO,
3591.5Snonaka			&value, &result);
3601.5Snonaka		if (ACPI_SUCCESS(rv) && result == 0) {
3611.5Snonaka			switch (value) {
3621.5Snonaka			case FN_F9_PRESS:
3631.5Snonaka				valz_acpi_touchpad_toggle(sc);
3641.5Snonaka				break;
3651.5Snonaka			case FN_TAB_PRESS:
3661.5Snonaka				valz_acpi_lcd_backlight_toggle(sc);
3671.5Snonaka				break;
3681.5Snonaka
3691.5Snonaka			default:
3701.5Snonaka				/* Many unused buttons */
3711.5Snonaka				aprint_debug("Pressed: 0x%x\n", value);
3721.5Snonaka				break;
3731.5Snonaka			}
3741.5Snonaka		}
3751.5Snonaka		if (ACPI_FAILURE(rv) || result == HCI_NOT_SUPPORTED ||
3761.5Snonaka			result == HCI_FIFO_EMPTY)
3771.5Snonaka			break;
3781.5Snonaka	}
3791.1Sjakllsch}
3801.1Sjakllsch
3811.5Snonaka/*
3821.5Snonaka * HCI/SCI operation
3831.5Snonaka */
3841.1Sjakllschstatic ACPI_STATUS
3851.5Snonakahci_op(struct valz_acpi_softc *sc, uint32_t *input, uint32_t *output)
3861.1Sjakllsch{
3871.1Sjakllsch	ACPI_STATUS rv;
3881.5Snonaka	ACPI_OBJECT Arg[HCI_WORDS];
3891.5Snonaka	ACPI_OBJECT_LIST ArgList;
3901.5Snonaka	ACPI_OBJECT *param, *PrtElement;
3911.1Sjakllsch	ACPI_BUFFER buf;
3921.5Snonaka	int		i;
3931.1Sjakllsch
3941.5Snonaka	for (i = 0; i < HCI_WORDS; i++) {
3951.5Snonaka		Arg[i].Type = ACPI_TYPE_INTEGER;
3961.5Snonaka		Arg[i].Integer.Value = 0;
3971.5Snonaka	}
3981.5Snonaka
3991.5Snonaka	for (i = 0; i < HCI_WORDS; i++) {
4001.5Snonaka		Arg[i].Integer.Value = input[i];
4011.5Snonaka	}
4021.5Snonaka
4031.5Snonaka	ArgList.Count = HCI_WORDS;
4041.5Snonaka	ArgList.Pointer = Arg;
4051.5Snonaka
4061.5Snonaka	buf.Pointer = NULL;
4071.5Snonaka	buf.Length = ACPI_ALLOCATE_BUFFER;
4081.5Snonaka
4091.5Snonaka	rv = AcpiEvaluateObjectTyped(sc->sc_node->ad_handle,
4101.5Snonaka	    METHOD_HCI, &ArgList, &buf, ACPI_TYPE_PACKAGE);
4111.5Snonaka	if (ACPI_FAILURE(rv)) {
4121.5Snonaka		aprint_error_dev(sc->sc_dev, "failed to evaluate GHCI: %s\n",
4131.5Snonaka		    AcpiFormatException(rv));
4141.5Snonaka		return rv;
4151.5Snonaka	}
4161.1Sjakllsch
4171.5Snonaka	for (i = 0; i < HCI_WORDS; i++) {
4181.5Snonaka		output[i] = 0;
4191.5Snonaka	}
4201.5Snonaka	param = (ACPI_OBJECT *)buf.Pointer;
4211.5Snonaka	PrtElement = param->Package.Elements;
4221.5Snonaka	for (i = 0; i < HCI_WORDS; i++) {
4231.6Schristos		if (PrtElement->Type == ACPI_TYPE_INTEGER) {
4241.5Snonaka			output[i] = PrtElement->Integer.Value;
4251.5Snonaka			PrtElement++;
4261.6Schristos		}
4271.5Snonaka	}
4281.1Sjakllsch
4291.6Schristos	ACPI_FREE(buf.Pointer);
4301.1Sjakllsch
4311.5Snonaka	return rv;
4321.1Sjakllsch}
4331.1Sjakllsch
4341.5Snonaka/*
4351.5Snonaka * valz_acpi_hci_get:
4361.5Snonaka *
4371.5Snonaka *	Get value via "GHCI" Method.
4381.5Snonaka */
4391.5Snonakastatic ACPI_STATUS
4401.5Snonakavalz_acpi_hci_get(struct valz_acpi_softc *sc, uint32_t function,
4411.5Snonaka    uint32_t reg, uint32_t *value, uint32_t *result)
4421.5Snonaka{
4431.5Snonaka	ACPI_STATUS rv;
4441.5Snonaka
4451.5Snonaka	uint32_t input[HCI_WORDS];
4461.5Snonaka	uint32_t output[HCI_WORDS];
4471.5Snonaka
4481.5Snonaka	input[HCI_REG_AX] = function;
4491.5Snonaka	input[HCI_REG_BX] = reg;
4501.5Snonaka	input[HCI_REG_CX] = 0;
4511.5Snonaka	input[HCI_REG_DX] = 0;
4521.5Snonaka	input[HCI_REG_SI] = 0;
4531.5Snonaka	input[HCI_REG_DI] = 0;
4541.5Snonaka
4551.5Snonaka	rv = hci_op(sc, input, output);
4561.5Snonaka
4571.5Snonaka	*result = output[HCI_REG_AX];
4581.5Snonaka	*value = output[HCI_REG_CX];
4591.5Snonaka
4601.5Snonaka	return rv;
4611.5Snonaka}
4621.5Snonaka
4631.5Snonaka/*
4641.5Snonaka * valz_acpi_hci_set:
4651.5Snonaka *
4661.5Snonaka *	Set value via "GHCI" Method.
4671.5Snonaka */
4681.5Snonakastatic ACPI_STATUS
4691.5Snonakavalz_acpi_hci_set(struct valz_acpi_softc *sc, uint32_t function,
4701.5Snonaka    uint32_t reg, uint32_t value, uint32_t *result)
4711.5Snonaka{
4721.5Snonaka	ACPI_STATUS rv;
4731.5Snonaka
4741.5Snonaka	uint32_t input[HCI_WORDS];
4751.5Snonaka	uint32_t output[HCI_WORDS];
4761.5Snonaka
4771.5Snonaka	input[HCI_REG_AX] = function;
4781.5Snonaka	input[HCI_REG_BX] = reg;
4791.5Snonaka	input[HCI_REG_CX] = value;
4801.5Snonaka	input[HCI_REG_DX] = 0;
4811.5Snonaka	input[HCI_REG_SI] = 0;
4821.5Snonaka	input[HCI_REG_DI] = 0;
4831.5Snonaka
4841.5Snonaka	rv = hci_op(sc, input, output);
4851.5Snonaka
4861.5Snonaka	*result = output[HCI_REG_AX];
4871.5Snonaka
4881.5Snonaka	return rv;
4891.5Snonaka}
4901.5Snonaka
4911.5Snonaka/*
4921.5Snonaka * Open SCI
4931.5Snonaka */
4941.5Snonakastatic ACPI_STATUS
4951.5Snonakasci_open(struct valz_acpi_softc *sc)
4961.1Sjakllsch{
4971.1Sjakllsch	ACPI_STATUS rv;
4981.5Snonaka	uint32_t result;
4991.1Sjakllsch
5001.5Snonaka	rv = valz_acpi_hci_set(sc, SCI_OPEN, 0, 0, &result);
5011.5Snonaka	if (ACPI_FAILURE(rv)) {
5021.5Snonaka		aprint_error("SCI: ACPI set error\n");
5031.5Snonaka	} else {
5041.5Snonaka		switch (result) {
5051.5Snonaka		case SCI_OPENCLOSE_OK:
5061.5Snonaka			aprint_debug("Opening SCI\n");
5071.5Snonaka			break;
5081.5Snonaka		case SCI_ALREADY_OPEN:
5091.5Snonaka			aprint_error("SCI already open\n");
5101.5Snonaka			break;
5111.5Snonaka		case SCI_NOT_SUPPORTED:
5121.5Snonaka			aprint_error("SCI is not supported\n");
5131.5Snonaka			break;
5141.5Snonaka		case SCI_NOT_PRESENT:
5151.5Snonaka			aprint_error("SCI is not present\n");
5161.5Snonaka			break;
5171.5Snonaka		default:
5181.5Snonaka			aprint_error("SCI: undefined behavior\n");
5191.5Snonaka			break;
5201.5Snonaka		}
5211.5Snonaka	}
5221.5Snonaka
5231.5Snonaka	return rv;
5241.5Snonaka}
5251.5Snonaka
5261.5Snonaka/*
5271.5Snonaka * Close SCI
5281.5Snonaka */
5291.5Snonakastatic ACPI_STATUS
5301.5Snonakasci_close(struct valz_acpi_softc *sc)
5311.5Snonaka{
5321.5Snonaka	ACPI_STATUS rv;
5331.5Snonaka	uint32_t result;
5341.1Sjakllsch
5351.5Snonaka	rv = valz_acpi_hci_set(sc, SCI_CLOSE, 0, 0, &result);
5361.1Sjakllsch	if (ACPI_FAILURE(rv)) {
5371.5Snonaka		aprint_error("SCI: ACPI set error\n");
5381.5Snonaka	} else {
5391.5Snonaka		switch (result) {
5401.5Snonaka		case SCI_OPENCLOSE_OK:
5411.5Snonaka			aprint_debug("Closing SCI\n");
5421.5Snonaka			break;
5431.5Snonaka		case SCI_NOT_OPEN:
5441.5Snonaka			aprint_error("SCI is not opened\n");
5451.5Snonaka			break;
5461.5Snonaka		case SCI_NOT_SUPPORTED:
5471.5Snonaka			aprint_error("SCI is not supported\n");
5481.5Snonaka			break;
5491.5Snonaka		case SCI_NOT_PRESENT:
5501.5Snonaka			aprint_error("SCI is not present\n");
5511.5Snonaka			break;
5521.5Snonaka		default:
5531.5Snonaka			aprint_error("SCI: undefined behavior\n");
5541.5Snonaka			break;
5551.5Snonaka		}
5561.1Sjakllsch	}
5571.1Sjakllsch
5581.5Snonaka	return rv;
5591.5Snonaka}
5601.5Snonaka
5611.5Snonaka/*
5621.5Snonaka * Enable/disable touchpad and trackpoint with HCI_ENABLE/HCI_DISABLE
5631.5Snonaka */
5641.5Snonakastatic ACPI_STATUS
5651.5Snonakavalz_acpi_touchpad_toggle(struct valz_acpi_softc *sc)
5661.5Snonaka{
5671.5Snonaka	ACPI_STATUS rv;
5681.5Snonaka	uint32_t result, status, value;
5691.1Sjakllsch
5701.5Snonaka	rv = sci_open(sc);
5711.5Snonaka	if (ACPI_FAILURE(rv))
5721.5Snonaka		aprint_error_dev(sc->sc_dev,
5731.5Snonaka				"Cannot open SCI: %s\n",
5741.5Snonaka				AcpiFormatException(rv));
5751.5Snonaka
5761.5Snonaka	rv = valz_acpi_hci_get(sc, SCI_GET, SCI_TOUCHPAD, &value, &result);
5771.5Snonaka	if (ACPI_FAILURE(rv))
5781.5Snonaka		aprint_error_dev(sc->sc_dev,
5791.5Snonaka				"Cannot get SCI touchpad status: %s\n",
5801.5Snonaka				AcpiFormatException(rv));
5811.5Snonaka
5821.5Snonaka	switch (value) {
5831.5Snonaka	case HCI_ENABLE:
5841.5Snonaka		status = HCI_DISABLE;
5851.1Sjakllsch		break;
5861.5Snonaka	case HCI_DISABLE:
5871.5Snonaka		status = HCI_ENABLE;
5881.1Sjakllsch		break;
5891.1Sjakllsch	default:
5901.5Snonaka		status = HCI_ENABLE;
5911.5Snonaka		break;
5921.1Sjakllsch	}
5931.1Sjakllsch
5941.5Snonaka	rv = valz_acpi_hci_set(sc, SCI_SET, SCI_TOUCHPAD, status, &result);
5951.5Snonaka	if (ACPI_FAILURE(rv))
5961.5Snonaka		aprint_error_dev(sc->sc_dev,
5971.5Snonaka				"Cannot set SCI touchpad status: %s\n",
5981.5Snonaka				AcpiFormatException(rv));
5991.1Sjakllsch
6001.5Snonaka	rv = sci_close(sc);
6011.1Sjakllsch	if (ACPI_FAILURE(rv))
6021.5Snonaka		aprint_error_dev(sc->sc_dev,
6031.5Snonaka				"Cannot close SCI: %s\n",
6041.5Snonaka				AcpiFormatException(rv));
6051.5Snonaka
6061.5Snonaka	return rv;
6071.1Sjakllsch}
6081.1Sjakllsch
6091.5Snonaka/*
6101.5Snonaka * Enable/disable LCD backlight with HCI_ENABLE/HCI_DISABLE
6111.5Snonaka */
6121.5Snonakastatic ACPI_STATUS
6131.5Snonakavalz_acpi_lcd_backlight_toggle(struct valz_acpi_softc *sc)
6141.1Sjakllsch{
6151.5Snonaka	ACPI_STATUS rv;
6161.5Snonaka	uint32_t result, status, value;
6171.5Snonaka
6181.5Snonaka	rv = valz_acpi_hci_get(sc, HCI_GET, HCI_LCD_BACKLIGHT, &value, &result);
6191.5Snonaka	if (ACPI_FAILURE(rv))
6201.5Snonaka		aprint_error_dev(sc->sc_dev,
6211.5Snonaka				"Cannot get HCI LCD backlight status: %s\n",
6221.5Snonaka				AcpiFormatException(rv));
6231.5Snonaka
6241.5Snonaka	switch (value) {
6251.5Snonaka	case HCI_ON:
6261.5Snonaka		status = HCI_OFF;
6271.5Snonaka		break;
6281.5Snonaka	case HCI_OFF:
6291.5Snonaka		status = HCI_ON;
6301.5Snonaka		break;
6311.5Snonaka	default:
6321.5Snonaka		status = HCI_ON;
6331.5Snonaka		break;
6341.5Snonaka	}
6351.5Snonaka
6361.5Snonaka	rv = valz_acpi_hci_set(sc, HCI_SET, HCI_LCD_BACKLIGHT, status, &result);
6371.5Snonaka	if (ACPI_FAILURE(rv))
6381.5Snonaka		aprint_error_dev(sc->sc_dev,
6391.5Snonaka				"Cannot set HCI LCD backlight status: %s\n",
6401.5Snonaka				AcpiFormatException(rv));
6411.1Sjakllsch
6421.5Snonaka	return rv;
6431.1Sjakllsch}
644