xref: /freebsd/sys/dev/atopcase/atopcase_acpi.c (revision 64fbda90da1b91d2412a5b970a3996f3cf1c8522)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021-2023 Val Packett <val@packett.cool>
5  * Copyright (c) 2023 Vladimir Kondratyev <wulf@FreeBSD.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "opt_acpi.h"
30 #include "opt_hid.h"
31 
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
37 #include <sys/module.h>
38 #include <sys/rman.h>
39 #include <sys/sx.h>
40 #include <sys/taskqueue.h>
41 
42 #include <contrib/dev/acpica/include/acpi.h>
43 #include <contrib/dev/acpica/include/accommon.h>
44 #include <contrib/dev/acpica/include/acevents.h>
45 #include <dev/acpica/acpivar.h>
46 #include <dev/acpica/acpiio.h>
47 
48 #include <dev/backlight/backlight.h>
49 
50 #include <dev/evdev/input.h>
51 
52 #define	HID_DEBUG_VAR atopcase_debug
53 #include <dev/hid/hid.h>
54 #include <dev/hid/hidquirk.h>
55 
56 #include <dev/spibus/spi.h>
57 #include <dev/spibus/spibusvar.h>
58 
59 #include "backlight_if.h"
60 #include "hid_if.h"
61 
62 #include "atopcase_reg.h"
63 #include "atopcase_var.h"
64 
65 /*
66  * XXX: The Linux driver only supports ACPI GPEs, but we only receive
67  * interrupts in this driver on a MacBookPro 12,1 and 14,1. This is because
68  * Linux responds to _OSI("Darwin") while we don't!
69  *
70  * ACPI GPE is enabled on FreeBSD by addition of following lines to
71  * /boot/loader.conf:
72  * hw.acpi.install_interface="Darwin"
73  * hw.acpi.remove_interface="Windows 2009, Windows 2012"
74  */
75 
76 static const char *atopcase_ids[] = { "APP000D", NULL };
77 
78 static device_probe_t	atopcase_acpi_probe;
79 static device_attach_t	atopcase_acpi_attach;
80 static device_detach_t	atopcase_acpi_detach;
81 static device_suspend_t	atopcase_acpi_suspend;
82 static device_resume_t	atopcase_acpi_resume;
83 
84 static bool
acpi_is_atopcase(ACPI_HANDLE handle)85 acpi_is_atopcase(ACPI_HANDLE handle)
86 {
87 	const char **ids;
88 	UINT32 sta;
89 
90 	for (ids = atopcase_ids; *ids != NULL; ids++) {
91 		if (acpi_MatchHid(handle, *ids))
92 			break;
93 	}
94 	if (*ids == NULL)
95 		return (false);
96 
97 	/*
98 	 * If no _STA method or if it failed, then assume that
99 	 * the device is present.
100 	 */
101 	if (ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) ||
102 	    ACPI_DEVICE_PRESENT(sta))
103 		return (true);
104 
105 	return (false);
106 }
107 
108 static int
atopcase_acpi_set_comm_enabled(struct atopcase_softc * sc,char * prop,const bool on)109 atopcase_acpi_set_comm_enabled(struct atopcase_softc *sc, char *prop,
110     const bool on)
111 {
112 	ACPI_OBJECT argobj;
113 	ACPI_OBJECT_LIST args;
114 
115 	argobj.Type = ACPI_TYPE_INTEGER;
116 	argobj.Integer.Value = on;
117 	args.Count = 1;
118 	args.Pointer = &argobj;
119 
120 	if (ACPI_FAILURE(
121 	    AcpiEvaluateObject(sc->sc_handle, prop, &args, NULL)))
122 		return (ENXIO);
123 
124 	DELAY(100);
125 
126 	return (0);
127 }
128 
129 static int
atopcase_acpi_test_comm_enabled(ACPI_HANDLE handle,char * prop,int * enabled)130 atopcase_acpi_test_comm_enabled(ACPI_HANDLE handle, char *prop, int *enabled)
131 {
132 	if (ACPI_FAILURE(acpi_GetInteger(handle, prop, enabled)))
133 		return (ENXIO);
134 
135 	return (0);
136 }
137 
138 static void
atopcase_acpi_task(void * ctx,int pending __unused)139 atopcase_acpi_task(void *ctx, int pending __unused)
140 {
141 	struct atopcase_softc *sc = ctx;
142 	int err = EAGAIN;
143 
144 	DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Timer event\n");
145 
146 	sx_xlock(&sc->sc_write_sx);
147 	err = atopcase_receive_packet(sc);
148 	sx_xunlock(&sc->sc_write_sx);
149 
150 	/* Rearm timer */
151 	taskqueue_enqueue_timeout(sc->sc_tq, &sc->sc_task,
152 	    hz / (err == EAGAIN ? 10 : 120));
153 }
154 
155 static void
atopcase_acpi_gpe_task(void * ctx)156 atopcase_acpi_gpe_task(void *ctx)
157 {
158 	struct atopcase_softc *sc = ctx;
159 
160 	DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "GPE event\n");
161 
162 	sx_xlock(&sc->sc_sx);
163 	(void)atopcase_intr(sc);
164 	sx_xunlock(&sc->sc_sx);
165 
166 	/* Rearm GPE */
167 	if (ACPI_FAILURE(AcpiFinishGpe(NULL, sc->sc_gpe_bit)))
168 		device_printf(sc->sc_dev, "GPE rearm failed\n");
169 }
170 
171 static UINT32
atopcase_acpi_notify(ACPI_HANDLE h __unused,UINT32 notify __unused,void * ctx)172 atopcase_acpi_notify(ACPI_HANDLE h __unused, UINT32 notify __unused, void *ctx)
173 {
174 	AcpiOsExecute(OSL_GPE_HANDLER, atopcase_acpi_gpe_task, ctx);
175 	return (0);
176 }
177 
178 static void
atopcase_acpi_intr(void * ctx)179 atopcase_acpi_intr(void *ctx)
180 {
181 	struct atopcase_softc *sc = ctx;
182 
183 	DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Interrupt event\n");
184 
185 	mtx_lock(&sc->sc_mtx);
186 	sc->sc_intr_cnt++;
187 	(void)atopcase_intr(sc);
188 	mtx_unlock(&sc->sc_mtx);
189 }
190 
191 static int
atopcase_acpi_probe(device_t dev)192 atopcase_acpi_probe(device_t dev)
193 {
194 	ACPI_HANDLE handle;
195 	int usb_enabled;
196 
197 	if (acpi_disabled("atopcase"))
198 		return (ENXIO);
199 
200 	handle = acpi_get_handle(dev);
201 	if (handle == NULL)
202 		return (ENXIO);
203 
204 	if (!acpi_is_atopcase(handle))
205 		return (ENXIO);
206 
207 	/* If USB interface exists and is enabled, use USB driver */
208 	if (atopcase_acpi_test_comm_enabled(handle, "UIST", &usb_enabled) == 0
209 	    && usb_enabled != 0)
210 		return (ENXIO);
211 
212 	device_set_desc(dev, "Apple MacBook SPI Topcase");
213 
214 	return (BUS_PROBE_DEFAULT);
215 }
216 
217 static int
atopcase_acpi_attach(device_t dev)218 atopcase_acpi_attach(device_t dev)
219 {
220 	struct atopcase_softc *sc = device_get_softc(dev);
221 	ACPI_DEVICE_INFO *device_info;
222 	uint32_t cs_delay;
223 	int spi_enabled, err;
224 
225 	sc->sc_dev = dev;
226 	sc->sc_handle = acpi_get_handle(dev);
227 
228 	if (atopcase_acpi_test_comm_enabled(sc->sc_handle, "SIST",
229 	    &spi_enabled) != 0) {
230 		device_printf(dev, "can't test SPI communication\n");
231 		return (ENXIO);
232 	}
233 
234 	/* Turn SPI off if enabled to force "booted" packet to appear */
235 	if (spi_enabled != 0 &&
236 	    atopcase_acpi_set_comm_enabled(sc, "SIEN", false) != 0) {
237 		device_printf(dev, "can't disable SPI communication\n");
238 		return (ENXIO);
239 	}
240 
241 	if (atopcase_acpi_set_comm_enabled(sc, "SIEN", true) != 0) {
242 		device_printf(dev, "can't enable SPI communication\n");
243 		return (ENXIO);
244 	}
245 
246 	/*
247 	 * Apple encodes a CS delay in ACPI properties, but
248 	 * - they're encoded in a non-standard way that predates _DSD, and
249 	 * - they're only exported if you respond to _OSI(Darwin) which we don't
250 	 *   - because that has more side effects than we're prepared to handle
251 	 * - Apple makes a Windows driver and Windows is not Darwin
252 	 *   - so presumably that one uses hardcoded values too
253 	 */
254 	spibus_get_cs_delay(sc->sc_dev, &cs_delay);
255 	if (cs_delay == 0)
256 		spibus_set_cs_delay(sc->sc_dev, 10);
257 
258 	/* Retrieve ACPI _HID */
259 	if (ACPI_FAILURE(AcpiGetObjectInfo(sc->sc_handle, &device_info)))
260 		return (ENXIO);
261 	if (device_info->Valid & ACPI_VALID_HID)
262 		strlcpy(sc->sc_hid, device_info->HardwareId.String,
263 		    sizeof(sc->sc_hid));
264 	AcpiOsFree(device_info);
265 
266 	sx_init(&sc->sc_write_sx, "atc_wr");
267 	sx_init(&sc->sc_sx, "atc_sx");
268 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
269 
270 	err = ENXIO;
271 	sc->sc_irq_res = bus_alloc_resource_any(sc->sc_dev,
272 	    SYS_RES_IRQ, &sc->sc_irq_rid, RF_ACTIVE);
273 	if (sc->sc_irq_res != NULL) {
274 		if (bus_setup_intr(dev, sc->sc_irq_res,
275 		      INTR_TYPE_MISC | INTR_MPSAFE, NULL,
276 		      atopcase_acpi_intr, sc, &sc->sc_irq_ih) != 0) {
277 			device_printf(dev, "can't setup interrupt handler\n");
278 			goto err;
279 		}
280 		device_printf(dev, "Using interrupts.\n");
281 		/*
282 		 * On some hardware interrupts are not acked by SPI read for
283 		 * unknown reasons that leads to interrupt storm due to level
284 		 * triggering. GPE does not suffer from this problem.
285 		 *
286 		 * TODO: Find out what Windows driver does to ack IRQ.
287 		 */
288 		pause("atopcase", hz / 5);
289 		DPRINTF("interrupts asserted: %u\n", sc->sc_intr_cnt);
290 		if (sc->sc_intr_cnt > 2 || sc->sc_intr_cnt == 0) {
291 			bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_ih);
292 			sc->sc_irq_ih = NULL;
293 			device_printf(dev, "Interrupt storm detected. "
294 			    "Falling back to polling\n");
295 			sc->sc_tq = taskqueue_create("atc_tq", M_WAITOK|M_ZERO,
296 			    taskqueue_thread_enqueue, &sc->sc_tq);
297 			TIMEOUT_TASK_INIT(sc->sc_tq, &sc->sc_task, 0,
298 			    atopcase_acpi_task, sc);
299 			taskqueue_start_threads(&sc->sc_tq, 1, PI_TTY,
300 			    "%s taskq", device_get_nameunit(dev));
301 		}
302 		/*
303 		 * Interrupts does not work at all. It may happen if kernel
304 		 * erroneously detected stray irq at bus_teardown_intr() and
305 		 * completelly disabled it after than.
306 		 * Fetch "booted" packet manually to pass communication check.
307 		 */
308 		if (sc->sc_intr_cnt == 0)
309 			atopcase_receive_packet(sc);
310 	} else {
311 		if (bootverbose)
312 			device_printf(dev, "can't allocate IRQ resource\n");
313 		if (ACPI_FAILURE(acpi_GetInteger(sc->sc_handle, "_GPE",
314 		    &sc->sc_gpe_bit))) {
315 			device_printf(dev, "can't allocate nor IRQ nor GPE\n");
316 			goto err;
317 		}
318 		if (ACPI_FAILURE(AcpiInstallGpeHandler(NULL, sc->sc_gpe_bit,
319 		    ACPI_GPE_LEVEL_TRIGGERED, atopcase_acpi_notify, sc))) {
320 			device_printf(dev, "can't install ACPI GPE handler\n");
321 			goto err;
322 		}
323 		if (ACPI_FAILURE(AcpiEnableGpe(NULL, sc->sc_gpe_bit))) {
324 			device_printf(dev, "can't enable ACPI notification\n");
325 			goto err;
326 		}
327 		device_printf(dev, "Using ACPI GPE.\n");
328 		if (bootverbose)
329 			device_printf(dev, "GPE int %d\n", sc->sc_gpe_bit);
330 	}
331 
332 	err = atopcase_init(sc);
333 
334 err:
335 	if (err != 0)
336 		atopcase_acpi_detach(dev);
337 	return (err);
338 }
339 
340 static int
atopcase_acpi_detach(device_t dev)341 atopcase_acpi_detach(device_t dev)
342 {
343 	struct atopcase_softc *sc = device_get_softc(dev);
344 	int err;
345 
346 	err = atopcase_destroy(sc);
347 	if (err != 0)
348 		return (err);
349 
350 	if (sc->sc_irq_ih)
351 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_ih);
352 	if (sc->sc_irq_res != NULL)
353 		bus_release_resource(dev, SYS_RES_IRQ,
354 		    sc->sc_irq_rid, sc->sc_irq_res);
355 
356 	if (sc->sc_tq != NULL) {
357 		while (taskqueue_cancel_timeout(sc->sc_tq, &sc->sc_task, NULL))
358 			taskqueue_drain_timeout(sc->sc_tq, &sc->sc_task);
359 		taskqueue_free(sc->sc_tq);
360 	}
361 
362 	if (sc->sc_gpe_bit != 0 && ACPI_FAILURE(AcpiRemoveGpeHandler(NULL,
363 	    sc->sc_gpe_bit, atopcase_acpi_notify)))
364 		device_printf(dev, "can't remove ACPI GPE handler\n");
365 
366 	if (atopcase_acpi_set_comm_enabled(sc, "SIEN", false) != 0)
367 		device_printf(dev, "can't disable SPI communication\n");
368 
369 	mtx_destroy(&sc->sc_mtx);
370 	sx_destroy(&sc->sc_sx);
371 	sx_destroy(&sc->sc_write_sx);
372 
373 	return (0);
374 }
375 
376 static int
atopcase_acpi_suspend(device_t dev)377 atopcase_acpi_suspend(device_t dev)
378 {
379 	struct atopcase_softc *sc = device_get_softc(dev);
380 	int err;
381 
382 	err = bus_generic_suspend(dev);
383 	if (err)
384 		return (err);
385 
386 	if (sc->sc_gpe_bit != 0)
387 		AcpiDisableGpe(NULL, sc->sc_gpe_bit);
388 
389 	if (sc->sc_tq != NULL)
390 		while (taskqueue_cancel_timeout(sc->sc_tq, &sc->sc_task, NULL))
391 			taskqueue_drain_timeout(sc->sc_tq, &sc->sc_task);
392 
393 	if (atopcase_acpi_set_comm_enabled(sc, "SIEN", false) != 0)
394 		device_printf(dev, "can't disable SPI communication\n");
395 
396 	return (0);
397 }
398 
399 static int
atopcase_acpi_resume(device_t dev)400 atopcase_acpi_resume(device_t dev)
401 {
402 	struct atopcase_softc *sc = device_get_softc(dev);
403 
404 	if (sc->sc_gpe_bit != 0)
405 		AcpiEnableGpe(NULL, sc->sc_gpe_bit);
406 
407 	if (sc->sc_tq != NULL)
408 		taskqueue_enqueue_timeout(sc->sc_tq, &sc->sc_task, hz / 120);
409 
410 	if (atopcase_acpi_set_comm_enabled(sc, "SIEN", true) != 0) {
411 		device_printf(dev, "can't enable SPI communication\n");
412 		return (ENXIO);
413 	}
414 
415 	return (bus_generic_resume(dev));
416 }
417 
418 static device_method_t atopcase_methods[] = {
419 	/* Device interface */
420 	DEVMETHOD(device_probe,		atopcase_acpi_probe),
421 	DEVMETHOD(device_attach,	atopcase_acpi_attach),
422 	DEVMETHOD(device_detach,	atopcase_acpi_detach),
423 	DEVMETHOD(device_suspend,	atopcase_acpi_suspend),
424 	DEVMETHOD(device_resume,	atopcase_acpi_resume),
425 
426 	/* HID interrupt interface */
427 	DEVMETHOD(hid_intr_setup,	atopcase_intr_setup),
428 	DEVMETHOD(hid_intr_unsetup,	atopcase_intr_unsetup),
429 	DEVMETHOD(hid_intr_start,	atopcase_intr_start),
430 	DEVMETHOD(hid_intr_stop,	atopcase_intr_stop),
431 	DEVMETHOD(hid_intr_poll,	atopcase_intr_poll),
432 
433 	/* HID interface */
434 	DEVMETHOD(hid_get_rdesc,	atopcase_get_rdesc),
435 	DEVMETHOD(hid_set_report,	atopcase_set_report),
436 
437 	/* Backlight interface */
438 	DEVMETHOD(backlight_update_status, atopcase_backlight_update_status),
439 	DEVMETHOD(backlight_get_status,	atopcase_backlight_get_status),
440 	DEVMETHOD(backlight_get_info,	atopcase_backlight_get_info),
441 
442 	DEVMETHOD_END
443 };
444 
445 static driver_t atopcase_driver = {
446 	"atopcase",
447 	atopcase_methods,
448 	sizeof(struct atopcase_softc),
449 };
450 
451 DRIVER_MODULE(atopcase, spibus, atopcase_driver, 0, 0);
452 MODULE_DEPEND(atopcase, acpi, 1, 1, 1);
453 MODULE_DEPEND(atopcase, backlight, 1, 1, 1);
454 MODULE_DEPEND(atopcase, hid, 1, 1, 1);
455 MODULE_DEPEND(atopcase, hidbus, 1, 1, 1);
456 MODULE_DEPEND(atopcase, spibus, 1, 1, 1);
457 MODULE_VERSION(atopcase, 1);
458 SPIBUS_ACPI_PNP_INFO(atopcase_ids);
459