xref: /openbsd-src/sys/dev/acpi/acpisony.c (revision 471aeecfc619bc9b69519928152daf993376c2a1)
1*471aeecfSnaddy /* $OpenBSD: acpisony.c,v 1.10 2022/04/06 18:59:27 naddy Exp $ */
28a193ee5Spirofti /*
38855e28cSpirofti  * Copyright (c) 2010 Paul Irofti <paul@irofti.net>
48a193ee5Spirofti  *
58a193ee5Spirofti  * Permission to use, copy, modify, and/or distribute this software for any
68a193ee5Spirofti  * purpose with or without fee is hereby granted, provided that the above
78a193ee5Spirofti  * copyright notice and this permission notice appear in all copies.
88a193ee5Spirofti  *
98a193ee5Spirofti  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108a193ee5Spirofti  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118a193ee5Spirofti  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128a193ee5Spirofti  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138a193ee5Spirofti  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148a193ee5Spirofti  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158a193ee5Spirofti  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168a193ee5Spirofti  */
178a193ee5Spirofti 
188a193ee5Spirofti #include <sys/param.h>
198a193ee5Spirofti #include <sys/systm.h>
208a193ee5Spirofti 
218a193ee5Spirofti #include <dev/acpi/acpireg.h>
228a193ee5Spirofti #include <dev/acpi/acpivar.h>
238a193ee5Spirofti #include <dev/acpi/acpidev.h>
248a193ee5Spirofti #include <dev/acpi/amltypes.h>
258a193ee5Spirofti #include <dev/acpi/dsdt.h>
268a193ee5Spirofti 
278a193ee5Spirofti #include <machine/apmvar.h>
288a193ee5Spirofti 
298a193ee5Spirofti int	acpisony_match(struct device *, void *, void *);
308a193ee5Spirofti void	acpisony_attach(struct device *, struct device *, void *);
318a193ee5Spirofti int	acpisony_activate(struct device *, int);
328a193ee5Spirofti int	acpisony_notify(struct aml_node *, int, void *);
338a193ee5Spirofti 
348a193ee5Spirofti #ifdef ACPISONY_DEBUG
358a193ee5Spirofti #define DPRINTF(x)	printf x
368a193ee5Spirofti #else
378a193ee5Spirofti #define DPRINTF(x)
388a193ee5Spirofti #endif
398a193ee5Spirofti 
408a193ee5Spirofti /* Notifications */
418a193ee5Spirofti #define	SONY_NOTIFY_FN_KEY			0x90
428a193ee5Spirofti 
438a193ee5Spirofti #define	SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED	0x85
448a193ee5Spirofti #define	SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED	0x05
458a193ee5Spirofti #define	SONY_NOTIFY_BRIGHTNESS_UP_PRESSED	0x86
468a193ee5Spirofti #define	SONY_NOTIFY_BRIGHTNESS_UP_RELEASED	0x06
478a193ee5Spirofti 
488a193ee5Spirofti #define	SONY_NOTIFY_DISPLAY_SWITCH_PRESSED	0x87
498a193ee5Spirofti #define	SONY_NOTIFY_DISPLAY_SWITCH_RELEASED	0x07
508a193ee5Spirofti 
518a193ee5Spirofti #define	SONY_NOTIFY_ZOOM_OUT_PRESSED		0x89
528a193ee5Spirofti #define	SONY_NOTIFY_ZOOM_OUT_RELEASED		0x09
538a193ee5Spirofti 
548a193ee5Spirofti #define	SONY_NOTIFY_ZOOM_IN_PRESSED		0x8a
558a193ee5Spirofti #define	SONY_NOTIFY_ZOOM_IN_RELEASED		0x0a
568a193ee5Spirofti 
578a193ee5Spirofti #define	SONY_NOTIFY_SUSPEND_PRESSED		0x8c
588a193ee5Spirofti #define	SONY_NOTIFY_SUSPEND_RELEASED		0x0c
598a193ee5Spirofti 
608a193ee5Spirofti struct acpisony_softc {
618a193ee5Spirofti 	struct device		sc_dev;
628a193ee5Spirofti 
638a193ee5Spirofti 	bus_space_tag_t		sc_iot;
648a193ee5Spirofti 	bus_space_handle_t	sc_ioh;
658a193ee5Spirofti 
668a193ee5Spirofti 	struct acpi_softc	*sc_acpi;
678a193ee5Spirofti 	struct aml_node		*sc_devnode;
688a193ee5Spirofti };
698a193ee5Spirofti 
70*471aeecfSnaddy const struct cfattach acpisony_ca = {
718a193ee5Spirofti 	sizeof(struct acpisony_softc), acpisony_match, acpisony_attach,
728a193ee5Spirofti 	NULL, acpisony_activate
738a193ee5Spirofti };
748a193ee5Spirofti 
758a193ee5Spirofti struct cfdriver acpisony_cd = {
768a193ee5Spirofti 	NULL, "acpisony", DV_DULL
778a193ee5Spirofti };
788a193ee5Spirofti 
798a193ee5Spirofti void acpisony_notify_setup(struct acpisony_softc *);
808a193ee5Spirofti int acpisony_set_hotkey(struct acpisony_softc *, int, int);
818a193ee5Spirofti int acpisony_find_offset(struct acpisony_softc *, int);
828a193ee5Spirofti 
838a193ee5Spirofti void acpisony_brightness_down(struct acpisony_softc *);
848a193ee5Spirofti int acpisony_get_brightness(struct acpisony_softc *);
858a193ee5Spirofti void acpisony_set_brightness(struct acpisony_softc *, int);
868a193ee5Spirofti 
878a193ee5Spirofti int
acpisony_match(struct device * parent,void * match,void * aux)888a193ee5Spirofti acpisony_match(struct device *parent, void *match, void *aux)
898a193ee5Spirofti {
908a193ee5Spirofti 	struct acpi_attach_args *aa = aux;
918a193ee5Spirofti 	struct cfdata		*cf = match;
928a193ee5Spirofti 
938a193ee5Spirofti 	if (aa->aaa_name == NULL ||
948a193ee5Spirofti 	    strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
958a193ee5Spirofti 	    aa->aaa_table != NULL)
968a193ee5Spirofti 		return (0);
978a193ee5Spirofti 
988a193ee5Spirofti 	return (1);
998a193ee5Spirofti }
1008a193ee5Spirofti 
1018a193ee5Spirofti void
acpisony_attach(struct device * parent,struct device * self,void * aux)1028a193ee5Spirofti acpisony_attach(struct device *parent, struct device *self, void *aux)
1038a193ee5Spirofti {
1048a193ee5Spirofti 	struct acpisony_softc	*sc = (struct acpisony_softc *)self;
1058a193ee5Spirofti 	struct acpi_attach_args *aa = aux;
1068a193ee5Spirofti 
1078a193ee5Spirofti 	sc->sc_acpi = (struct acpi_softc *)parent;
1088a193ee5Spirofti 	sc->sc_devnode = aa->aaa_node;
1098a193ee5Spirofti 
1108a193ee5Spirofti 	printf(": %s\n", sc->sc_devnode->name);
1118a193ee5Spirofti 
1128a193ee5Spirofti 	/* Setup the notification masks */
1138a193ee5Spirofti 	acpisony_notify_setup(sc);
1148a193ee5Spirofti 
1158a193ee5Spirofti 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
1168a193ee5Spirofti 	    acpisony_notify, sc, ACPIDEV_NOPOLL);
1178a193ee5Spirofti }
1188a193ee5Spirofti 
1198a193ee5Spirofti int
acpisony_activate(struct device * self,int act)1208a193ee5Spirofti acpisony_activate(struct device *self, int act)
1218a193ee5Spirofti {
1228a193ee5Spirofti 	struct acpisony_softc *sc = (struct acpisony_softc *)self;
1238a193ee5Spirofti 
1248a193ee5Spirofti 	switch (act) {
125b4b59f5cSderaadt 	case DVACT_WAKEUP:
1268a193ee5Spirofti 		acpisony_notify_setup(sc);
1278a193ee5Spirofti 		break;
1288a193ee5Spirofti 	}
1298a193ee5Spirofti 	return 0;
1308a193ee5Spirofti }
1318a193ee5Spirofti 
1328a193ee5Spirofti int
acpisony_notify(struct aml_node * node,int notify,void * arg)1338a193ee5Spirofti acpisony_notify(struct aml_node *node, int notify, void *arg)
1348a193ee5Spirofti {
1358a193ee5Spirofti 	struct acpisony_softc *sc = arg;
1368a193ee5Spirofti 	int val, key = 0;
1378a193ee5Spirofti 
1388a193ee5Spirofti 	if (notify == SONY_NOTIFY_FN_KEY) {
1398a193ee5Spirofti 		notify -= 0x90;
1408a193ee5Spirofti 		DPRINTF(("notify = %X", notify));
1418a193ee5Spirofti 
1428a193ee5Spirofti 		if (notify == acpisony_find_offset(sc, 0x100)) {
1438a193ee5Spirofti 			DPRINTF(("key = 0x100\n"));
1448a193ee5Spirofti 			key = 0x100;
1458a193ee5Spirofti 		}
1468a193ee5Spirofti 		if (notify == acpisony_find_offset(sc, 0x127)) {
1478a193ee5Spirofti 			DPRINTF(("key = 0x127\n"));
1488a193ee5Spirofti 			key = 0x127;
1498a193ee5Spirofti 		}
1508a193ee5Spirofti 
1518a193ee5Spirofti 		if (key) {
1528a193ee5Spirofti 			val = acpisony_set_hotkey(sc, key, 0x200);
1538a193ee5Spirofti 			if (val < 0) {
1548a193ee5Spirofti 				printf("returned val = %X", val);
1558a193ee5Spirofti 				return 1;
1568a193ee5Spirofti 			}
1578a193ee5Spirofti 			notify = val & 0xff;
1588a193ee5Spirofti 
1598a193ee5Spirofti 			DPRINTF(("Treat %X events, notify %X\n", key, notify));
1608a193ee5Spirofti 		} else
1618a193ee5Spirofti 			DPRINTF(("rfkill update, notify %X\n", notify));
1628a193ee5Spirofti 	}
1638a193ee5Spirofti 
1648a193ee5Spirofti 	switch (notify) {
1658a193ee5Spirofti 	case SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED:
1668a193ee5Spirofti 		DPRINTF(("br-down-pressed\n"));
1678a193ee5Spirofti 		acpisony_brightness_down(sc);
1688a193ee5Spirofti 		break;
1698a193ee5Spirofti 	case SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED:
1708a193ee5Spirofti 		DPRINTF(("br-down-released\n"));
1718a193ee5Spirofti 		break;
1728a193ee5Spirofti 	case SONY_NOTIFY_BRIGHTNESS_UP_PRESSED:
1738a193ee5Spirofti 		DPRINTF(("br-up-pressed\n"));
1748a193ee5Spirofti 		break;
1758a193ee5Spirofti 	case SONY_NOTIFY_BRIGHTNESS_UP_RELEASED:
1768a193ee5Spirofti 		DPRINTF(("br-up-released\n"));
1778a193ee5Spirofti 		break;
1788a193ee5Spirofti 	case SONY_NOTIFY_DISPLAY_SWITCH_PRESSED:
1798a193ee5Spirofti 		DPRINTF(("display-pressed\n"));
1808a193ee5Spirofti 		break;
1818a193ee5Spirofti 	case SONY_NOTIFY_DISPLAY_SWITCH_RELEASED:
1828a193ee5Spirofti 		DPRINTF(("display-released\n"));
1838a193ee5Spirofti 		break;
1848a193ee5Spirofti 	case SONY_NOTIFY_ZOOM_IN_PRESSED:
1858a193ee5Spirofti 		DPRINTF(("zoom-in-pressed\n"));
1868a193ee5Spirofti 		break;
1878a193ee5Spirofti 	case SONY_NOTIFY_ZOOM_IN_RELEASED:
1888a193ee5Spirofti 		DPRINTF(("zoom-in-released\n"));
1898a193ee5Spirofti 		break;
1908a193ee5Spirofti 	case SONY_NOTIFY_ZOOM_OUT_PRESSED:
1918a193ee5Spirofti 		DPRINTF(("zoom-out-pressed\n"));
1928a193ee5Spirofti 		break;
1938a193ee5Spirofti 	case SONY_NOTIFY_ZOOM_OUT_RELEASED:
1948a193ee5Spirofti 		DPRINTF(("zoom-out-released\n"));
1958a193ee5Spirofti 		break;
1968a193ee5Spirofti 	case SONY_NOTIFY_SUSPEND_PRESSED:
1978a193ee5Spirofti 		DPRINTF(("suspend-pressed\n"));
1988a193ee5Spirofti #ifndef SMALL_KERNEL
1997a94bfdfSderaadt 		if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
20090680e5dSjordan 			acpi_addtask(sc->sc_acpi, acpi_sleep_task,
201ad814436Sderaadt 			    sc->sc_acpi, SLEEP_SUSPEND);
2028a193ee5Spirofti #endif
2038a193ee5Spirofti 		break;
2048a193ee5Spirofti 	case SONY_NOTIFY_SUSPEND_RELEASED:
2058a193ee5Spirofti 		DPRINTF(("suspend-released\n"));
2068a193ee5Spirofti 		break;
2078a193ee5Spirofti 	default:
2088a193ee5Spirofti 		printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
2098a193ee5Spirofti 		break;
2108a193ee5Spirofti 	}
2118a193ee5Spirofti 
2128a193ee5Spirofti 	return 0;
2138a193ee5Spirofti }
2148a193ee5Spirofti 
2158a193ee5Spirofti void
acpisony_notify_setup(struct acpisony_softc * sc)2168a193ee5Spirofti acpisony_notify_setup(struct acpisony_softc *sc)
2178a193ee5Spirofti {
2188a193ee5Spirofti 	struct aml_value arg;
2198a193ee5Spirofti 
2208a193ee5Spirofti 	bzero(&arg, sizeof(arg));
2218a193ee5Spirofti 	arg.type = AML_OBJTYPE_INTEGER;
2228a193ee5Spirofti 
2238a193ee5Spirofti 	arg.v_integer = 1;
2248a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "ECON", 1, &arg, NULL);
2258a193ee5Spirofti 
2268a193ee5Spirofti 	/* Enable all events */
2278a193ee5Spirofti 	arg.v_integer = 0xffff;
2288a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
2298a193ee5Spirofti 
2308a193ee5Spirofti 	/* Enable hotkeys */
2318a193ee5Spirofti 	arg.v_integer = 0x04;
2328a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
2338a193ee5Spirofti 	arg.v_integer = 0x02;
2348a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
2358a193ee5Spirofti 	arg.v_integer = 0x10;
2368a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
2378a193ee5Spirofti 	arg.v_integer = 0x00;
2388a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
2398a193ee5Spirofti 	arg.v_integer = 0x02;
2408a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN03", 1, &arg, NULL);
2418a193ee5Spirofti 	arg.v_integer = 0x101;
2428a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
2438a193ee5Spirofti }
2448a193ee5Spirofti 
2458a193ee5Spirofti int
acpisony_find_offset(struct acpisony_softc * sc,int key)2468a193ee5Spirofti acpisony_find_offset(struct acpisony_softc *sc, int key)
2478a193ee5Spirofti {
2488a193ee5Spirofti 	struct aml_value arg, res;
2498a193ee5Spirofti 	int val;
2508a193ee5Spirofti 
2518a193ee5Spirofti 	bzero(&arg, sizeof(arg));
2528a193ee5Spirofti 	arg.type = AML_OBJTYPE_INTEGER;
2538a193ee5Spirofti 
2548a193ee5Spirofti 	for (arg.v_integer = 0x20; arg.v_integer < 0x30; arg.v_integer++) {
2558a193ee5Spirofti 		aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN00", 1, &arg, &res);
2568a193ee5Spirofti 		val = aml_val2int(&res);
2578a193ee5Spirofti 		aml_freevalue(&res);
2588a193ee5Spirofti 		if (val == key) {
2598a193ee5Spirofti 			DPRINTF(("Matched key %X\n", val));
2608a193ee5Spirofti 			return arg.v_integer - 0x20;
2618a193ee5Spirofti 		}
2628a193ee5Spirofti 	}
2638a193ee5Spirofti 
2648a193ee5Spirofti 	return -1;
2658a193ee5Spirofti }
2668a193ee5Spirofti 
2678a193ee5Spirofti int
acpisony_set_hotkey(struct acpisony_softc * sc,int key,int val)2688a193ee5Spirofti acpisony_set_hotkey(struct acpisony_softc *sc, int key, int val)
2698a193ee5Spirofti {
2708a193ee5Spirofti 	int off, rc = -1;
2718a193ee5Spirofti 	struct aml_value res, arg;
2728a193ee5Spirofti 
2738a193ee5Spirofti 	bzero(&arg, sizeof(arg));
2748a193ee5Spirofti 	arg.type = AML_OBJTYPE_INTEGER;
2758a193ee5Spirofti 
2768a193ee5Spirofti 	off = acpisony_find_offset(sc, key);
2778a193ee5Spirofti 	DPRINTF(("off = %X\n", off));
2788a193ee5Spirofti 	if (off < 0)
2798a193ee5Spirofti 		return rc;
2808a193ee5Spirofti 
2818a193ee5Spirofti 	arg.v_integer = off | val;
2828a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, &res);
2838a193ee5Spirofti 	rc = aml_val2int(&res);
2848a193ee5Spirofti 	aml_freevalue(&res);
2858a193ee5Spirofti 
2868a193ee5Spirofti 	return rc;
2878a193ee5Spirofti }
2888a193ee5Spirofti 
2898a193ee5Spirofti void
acpisony_brightness_down(struct acpisony_softc * sc)2908a193ee5Spirofti acpisony_brightness_down(struct acpisony_softc *sc)
2918a193ee5Spirofti {
2928a193ee5Spirofti 	int val;
2938a193ee5Spirofti 
2948a193ee5Spirofti 	val = acpisony_get_brightness(sc);
2958a193ee5Spirofti 	DPRINTF(("current value = %X", val));
2968a193ee5Spirofti 	if (val > 0)
2978a193ee5Spirofti 		val--;
2988a193ee5Spirofti 	else
2998a193ee5Spirofti 		val = 0;
3008a193ee5Spirofti 	DPRINTF(("next value = %X", val));
3018a193ee5Spirofti 	acpisony_set_brightness(sc, val);
3028a193ee5Spirofti }
3038a193ee5Spirofti 
3048a193ee5Spirofti int
acpisony_get_brightness(struct acpisony_softc * sc)3058a193ee5Spirofti acpisony_get_brightness(struct acpisony_softc *sc)
3068a193ee5Spirofti {
3078a193ee5Spirofti 	struct aml_value res;
3088a193ee5Spirofti 	int val;
3098a193ee5Spirofti 
3108a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBRT", 0, NULL, &res);
3118a193ee5Spirofti 	val = aml_val2int(&res);
3128a193ee5Spirofti 	aml_freevalue(&res);
3138a193ee5Spirofti 
3148a193ee5Spirofti 	return val;
3158a193ee5Spirofti }
3168a193ee5Spirofti 
3178a193ee5Spirofti void
acpisony_set_brightness(struct acpisony_softc * sc,int level)3188a193ee5Spirofti acpisony_set_brightness(struct acpisony_softc *sc, int level)
3198a193ee5Spirofti {
3208a193ee5Spirofti 	struct aml_value arg;
3218a193ee5Spirofti 
3228a193ee5Spirofti 	bzero(&arg, sizeof(arg));
3238a193ee5Spirofti 	arg.type = AML_OBJTYPE_INTEGER;
3248a193ee5Spirofti 	arg.v_integer = level;
3258a193ee5Spirofti 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBRT", 1, &arg, NULL);
3268a193ee5Spirofti 	aml_freevalue(&arg);
3278a193ee5Spirofti }
328