1 /* $OpenBSD: acpicbkbd.c,v 1.3 2022/04/06 18:59:27 naddy Exp $ */
2 /*
3 * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20
21 #include <dev/acpi/acpivar.h>
22 #include <dev/acpi/amltypes.h>
23 #include <dev/acpi/dsdt.h>
24
25 #include <dev/wscons/wsconsio.h>
26
27 /* #define ACPICBKBD_DEBUG */
28
29 #ifdef ACPICBKBD_DEBUG
30 #define DPRINTF(x) printf x
31 #else
32 #define DPRINTF(x)
33 #endif
34
35 #define ACPICBKBD_MAX_BACKLIGHT 100
36
37 struct acpicbkbd_softc {
38 struct device sc_dev;
39 struct acpi_softc *sc_acpi;
40 struct aml_node *sc_devnode;
41
42 uint64_t sc_backlight;
43 };
44
45 int acpicbkbd_match(struct device *, void *, void *);
46 void acpicbkbd_attach(struct device *, struct device *, void *);
47 int acpicbkbd_activate(struct device *, int);
48
49 int acpicbkbd_get_backlight(struct wskbd_backlight *);
50 int acpicbkbd_set_backlight(struct wskbd_backlight *);
51 void acpicbkbd_write_backlight(void *, int);
52 extern int (*wskbd_get_backlight)(struct wskbd_backlight *);
53 extern int (*wskbd_set_backlight)(struct wskbd_backlight *);
54
55 const struct cfattach acpicbkbd_ca = {
56 sizeof(struct acpicbkbd_softc),
57 acpicbkbd_match,
58 acpicbkbd_attach,
59 NULL,
60 acpicbkbd_activate,
61 };
62
63 struct cfdriver acpicbkbd_cd = {
64 NULL, "acpicbkbd", DV_DULL
65 };
66
67 const char *acpicbkbd_hids[] = {
68 "GOOG0002",
69 NULL
70 };
71
72 int
acpicbkbd_match(struct device * parent,void * match,void * aux)73 acpicbkbd_match(struct device *parent, void *match, void *aux)
74 {
75 struct acpi_attach_args *aaa = aux;
76 struct cfdata *cf = match;
77
78 return acpi_matchhids(aaa, acpicbkbd_hids, cf->cf_driver->cd_name);
79 }
80
81 void
acpicbkbd_attach(struct device * parent,struct device * self,void * aux)82 acpicbkbd_attach(struct device *parent, struct device *self, void *aux)
83 {
84 struct acpicbkbd_softc *sc = (struct acpicbkbd_softc *)self;
85 struct acpi_attach_args *aa = aux;
86
87 sc->sc_acpi = (struct acpi_softc *)parent;
88 sc->sc_devnode = aa->aaa_node;
89
90 printf(": %s", sc->sc_devnode->name);
91
92 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "KBQC",
93 0, NULL, &sc->sc_backlight) == 0) {
94 wskbd_get_backlight = acpicbkbd_get_backlight;
95 wskbd_set_backlight = acpicbkbd_set_backlight;
96 } else
97 printf(", no backlight control");
98
99 printf("\n");
100 }
101
102 int
acpicbkbd_activate(struct device * self,int act)103 acpicbkbd_activate(struct device *self, int act)
104 {
105 struct acpicbkbd_softc *sc = (struct acpicbkbd_softc *)self;
106
107 switch (act) {
108 case DVACT_WAKEUP:
109 /* restore backlight to pre-suspend value */
110 acpi_addtask(sc->sc_acpi, acpicbkbd_write_backlight, sc, 0);
111
112 break;
113 }
114 return (0);
115 }
116
117 int
acpicbkbd_get_backlight(struct wskbd_backlight * kbl)118 acpicbkbd_get_backlight(struct wskbd_backlight *kbl)
119 {
120 struct acpicbkbd_softc *sc = acpicbkbd_cd.cd_devs[0];
121
122 KASSERT(sc != NULL);
123
124 kbl->min = 0;
125 kbl->max = ACPICBKBD_MAX_BACKLIGHT;
126 kbl->curval = sc->sc_backlight;
127
128 return 0;
129 }
130
131 int
acpicbkbd_set_backlight(struct wskbd_backlight * kbl)132 acpicbkbd_set_backlight(struct wskbd_backlight *kbl)
133 {
134 struct acpicbkbd_softc *sc = acpicbkbd_cd.cd_devs[0];
135
136 KASSERT(sc != NULL);
137
138 if (kbl->curval > ACPICBKBD_MAX_BACKLIGHT)
139 return EINVAL;
140
141 sc->sc_backlight = kbl->curval;
142
143 acpi_addtask(sc->sc_acpi, acpicbkbd_write_backlight, sc, 0);
144 acpi_wakeup(sc->sc_acpi);
145
146 return 0;
147 }
148
149 void
acpicbkbd_write_backlight(void * arg0,int arg1)150 acpicbkbd_write_backlight(void *arg0, int arg1)
151 {
152 struct acpicbkbd_softc *sc = arg0;
153 struct aml_value arg;
154
155 DPRINTF(("%s: writing backlight of %lld\n", sc->sc_dev.dv_xname,
156 sc->sc_backlight));
157
158 memset(&arg, 0, sizeof(arg));
159 arg.type = AML_OBJTYPE_INTEGER;
160 arg.v_integer = sc->sc_backlight;
161 aml_evalname(sc->sc_acpi, sc->sc_devnode, "KBCM", 1, &arg, NULL);
162 }
163