xref: /openbsd/sys/dev/acpi/acpicbkbd.c (revision 471aeecf)
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