1*471aeecfSnaddy /* $OpenBSD: acpicbkbd.c,v 1.3 2022/04/06 18:59:27 naddy Exp $ */
26caabb8eSjcs /*
36caabb8eSjcs * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
46caabb8eSjcs *
56caabb8eSjcs * Permission to use, copy, modify, and/or distribute this software for any
66caabb8eSjcs * purpose with or without fee is hereby granted, provided that the above
76caabb8eSjcs * copyright notice and this permission notice appear in all copies.
86caabb8eSjcs *
96caabb8eSjcs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106caabb8eSjcs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116caabb8eSjcs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126caabb8eSjcs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136caabb8eSjcs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146caabb8eSjcs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156caabb8eSjcs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166caabb8eSjcs */
176caabb8eSjcs
186caabb8eSjcs #include <sys/param.h>
196caabb8eSjcs #include <sys/systm.h>
206caabb8eSjcs
216caabb8eSjcs #include <dev/acpi/acpivar.h>
226caabb8eSjcs #include <dev/acpi/amltypes.h>
236caabb8eSjcs #include <dev/acpi/dsdt.h>
246caabb8eSjcs
256caabb8eSjcs #include <dev/wscons/wsconsio.h>
266caabb8eSjcs
276800a44dSjcs /* #define ACPICBKBD_DEBUG */
286800a44dSjcs
296caabb8eSjcs #ifdef ACPICBKBD_DEBUG
306caabb8eSjcs #define DPRINTF(x) printf x
316caabb8eSjcs #else
326caabb8eSjcs #define DPRINTF(x)
336caabb8eSjcs #endif
346caabb8eSjcs
356caabb8eSjcs #define ACPICBKBD_MAX_BACKLIGHT 100
366caabb8eSjcs
376caabb8eSjcs struct acpicbkbd_softc {
386caabb8eSjcs struct device sc_dev;
396caabb8eSjcs struct acpi_softc *sc_acpi;
406caabb8eSjcs struct aml_node *sc_devnode;
416caabb8eSjcs
426caabb8eSjcs uint64_t sc_backlight;
436caabb8eSjcs };
446caabb8eSjcs
456caabb8eSjcs int acpicbkbd_match(struct device *, void *, void *);
466caabb8eSjcs void acpicbkbd_attach(struct device *, struct device *, void *);
476800a44dSjcs int acpicbkbd_activate(struct device *, int);
486caabb8eSjcs
496caabb8eSjcs int acpicbkbd_get_backlight(struct wskbd_backlight *);
506caabb8eSjcs int acpicbkbd_set_backlight(struct wskbd_backlight *);
516caabb8eSjcs void acpicbkbd_write_backlight(void *, int);
526caabb8eSjcs extern int (*wskbd_get_backlight)(struct wskbd_backlight *);
536caabb8eSjcs extern int (*wskbd_set_backlight)(struct wskbd_backlight *);
546caabb8eSjcs
55*471aeecfSnaddy const struct cfattach acpicbkbd_ca = {
566800a44dSjcs sizeof(struct acpicbkbd_softc),
576800a44dSjcs acpicbkbd_match,
586800a44dSjcs acpicbkbd_attach,
596800a44dSjcs NULL,
606800a44dSjcs acpicbkbd_activate,
616caabb8eSjcs };
626caabb8eSjcs
636caabb8eSjcs struct cfdriver acpicbkbd_cd = {
646caabb8eSjcs NULL, "acpicbkbd", DV_DULL
656caabb8eSjcs };
666caabb8eSjcs
676caabb8eSjcs const char *acpicbkbd_hids[] = {
686caabb8eSjcs "GOOG0002",
696caabb8eSjcs NULL
706caabb8eSjcs };
716caabb8eSjcs
726caabb8eSjcs int
acpicbkbd_match(struct device * parent,void * match,void * aux)736caabb8eSjcs acpicbkbd_match(struct device *parent, void *match, void *aux)
746caabb8eSjcs {
756caabb8eSjcs struct acpi_attach_args *aaa = aux;
766caabb8eSjcs struct cfdata *cf = match;
776caabb8eSjcs
786caabb8eSjcs return acpi_matchhids(aaa, acpicbkbd_hids, cf->cf_driver->cd_name);
796caabb8eSjcs }
806caabb8eSjcs
816caabb8eSjcs void
acpicbkbd_attach(struct device * parent,struct device * self,void * aux)826caabb8eSjcs acpicbkbd_attach(struct device *parent, struct device *self, void *aux)
836caabb8eSjcs {
846caabb8eSjcs struct acpicbkbd_softc *sc = (struct acpicbkbd_softc *)self;
856caabb8eSjcs struct acpi_attach_args *aa = aux;
866caabb8eSjcs
876caabb8eSjcs sc->sc_acpi = (struct acpi_softc *)parent;
886caabb8eSjcs sc->sc_devnode = aa->aaa_node;
896caabb8eSjcs
906caabb8eSjcs printf(": %s", sc->sc_devnode->name);
916caabb8eSjcs
926caabb8eSjcs if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "KBQC",
936caabb8eSjcs 0, NULL, &sc->sc_backlight) == 0) {
946caabb8eSjcs wskbd_get_backlight = acpicbkbd_get_backlight;
956caabb8eSjcs wskbd_set_backlight = acpicbkbd_set_backlight;
966caabb8eSjcs } else
976caabb8eSjcs printf(", no backlight control");
986caabb8eSjcs
996caabb8eSjcs printf("\n");
1006caabb8eSjcs }
1016caabb8eSjcs
1026caabb8eSjcs int
acpicbkbd_activate(struct device * self,int act)1036800a44dSjcs acpicbkbd_activate(struct device *self, int act)
1046800a44dSjcs {
1056800a44dSjcs struct acpicbkbd_softc *sc = (struct acpicbkbd_softc *)self;
1066800a44dSjcs
1076800a44dSjcs switch (act) {
1086800a44dSjcs case DVACT_WAKEUP:
1096800a44dSjcs /* restore backlight to pre-suspend value */
1106800a44dSjcs acpi_addtask(sc->sc_acpi, acpicbkbd_write_backlight, sc, 0);
1116800a44dSjcs
1126800a44dSjcs break;
1136800a44dSjcs }
1146800a44dSjcs return (0);
1156800a44dSjcs }
1166800a44dSjcs
1176800a44dSjcs int
acpicbkbd_get_backlight(struct wskbd_backlight * kbl)1186caabb8eSjcs acpicbkbd_get_backlight(struct wskbd_backlight *kbl)
1196caabb8eSjcs {
1206caabb8eSjcs struct acpicbkbd_softc *sc = acpicbkbd_cd.cd_devs[0];
1216caabb8eSjcs
1226caabb8eSjcs KASSERT(sc != NULL);
1236caabb8eSjcs
1246caabb8eSjcs kbl->min = 0;
1256caabb8eSjcs kbl->max = ACPICBKBD_MAX_BACKLIGHT;
1266caabb8eSjcs kbl->curval = sc->sc_backlight;
1276caabb8eSjcs
1286caabb8eSjcs return 0;
1296caabb8eSjcs }
1306caabb8eSjcs
1316caabb8eSjcs int
acpicbkbd_set_backlight(struct wskbd_backlight * kbl)1326caabb8eSjcs acpicbkbd_set_backlight(struct wskbd_backlight *kbl)
1336caabb8eSjcs {
1346caabb8eSjcs struct acpicbkbd_softc *sc = acpicbkbd_cd.cd_devs[0];
1356caabb8eSjcs
1366caabb8eSjcs KASSERT(sc != NULL);
1376caabb8eSjcs
1386caabb8eSjcs if (kbl->curval > ACPICBKBD_MAX_BACKLIGHT)
1396caabb8eSjcs return EINVAL;
1406caabb8eSjcs
1416caabb8eSjcs sc->sc_backlight = kbl->curval;
1426caabb8eSjcs
1436caabb8eSjcs acpi_addtask(sc->sc_acpi, acpicbkbd_write_backlight, sc, 0);
1446caabb8eSjcs acpi_wakeup(sc->sc_acpi);
1456caabb8eSjcs
1466caabb8eSjcs return 0;
1476caabb8eSjcs }
1486caabb8eSjcs
1496caabb8eSjcs void
acpicbkbd_write_backlight(void * arg0,int arg1)1506caabb8eSjcs acpicbkbd_write_backlight(void *arg0, int arg1)
1516caabb8eSjcs {
1526caabb8eSjcs struct acpicbkbd_softc *sc = arg0;
1536caabb8eSjcs struct aml_value arg;
1546caabb8eSjcs
1556800a44dSjcs DPRINTF(("%s: writing backlight of %lld\n", sc->sc_dev.dv_xname,
1566caabb8eSjcs sc->sc_backlight));
1576caabb8eSjcs
1586caabb8eSjcs memset(&arg, 0, sizeof(arg));
1596caabb8eSjcs arg.type = AML_OBJTYPE_INTEGER;
1606caabb8eSjcs arg.v_integer = sc->sc_backlight;
1616caabb8eSjcs aml_evalname(sc->sc_acpi, sc->sc_devnode, "KBCM", 1, &arg, NULL);
1626caabb8eSjcs }
163