xref: /freebsd/sys/dev/asmc/asmc.c (revision d15f2551b25f79ddcbe289faa95e655100b952da)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org>
5  * All rights reserved.
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 ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 /*
31  * Driver for Apple's System Management Console (SMC).
32  * SMC can be found on the MacBook, MacBook Pro and Mac Mini.
33  *
34  * Inspired by the Linux applesmc driver.
35  */
36 
37 #include "opt_asmc.h"
38 
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/conf.h>
42 #include <sys/endian.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
48 #include <sys/sbuf.h>
49 #include <sys/sysctl.h>
50 #include <sys/systm.h>
51 #include <sys/taskqueue.h>
52 #include <sys/rman.h>
53 
54 #include <machine/resource.h>
55 #include <netinet/in.h>
56 
57 #include <contrib/dev/acpica/include/acpi.h>
58 
59 #include <dev/acpica/acpivar.h>
60 #include <dev/asmc/asmcvar.h>
61 #include <dev/asmc/asmcmmio.h>
62 
63 #include <dev/backlight/backlight.h>
64 #include "backlight_if.h"
65 
66 /*
67  * Device interface.
68  */
69 static int 	asmc_probe(device_t dev);
70 static int 	asmc_attach(device_t dev);
71 static int 	asmc_detach(device_t dev);
72 static int 	asmc_resume(device_t dev);
73 
74 /*
75  * Backlight interface.
76  */
77 static int	asmc_backlight_update_status(device_t dev,
78     struct backlight_props *props);
79 static int	asmc_backlight_get_status(device_t dev,
80     struct backlight_props *props);
81 static int	asmc_backlight_get_info(device_t dev, struct backlight_info *info);
82 
83 /*
84  * SMC functions.
85  */
86 static int 	asmc_init(device_t dev);
87 static int 	asmc_command(device_t dev, uint8_t command);
88 static int 	asmc_wait(device_t dev, uint8_t val);
89 static int 	asmc_wait_ack(device_t dev, uint8_t val, int amount);
90 static int 	asmc_key_write(device_t dev, const char *key, uint8_t *buf,
91     uint8_t len);
92 static int 	asmc_key_read(device_t dev, const char *key, uint8_t *buf,
93     uint8_t);
94 static int 	asmc_fan_count(device_t dev);
95 static int 	asmc_fan_getvalue(device_t dev, const char *key, int fan);
96 static int 	asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
97 static int 	asmc_temp_getvalue(device_t dev, const char *key);
98 static int 	asmc_sms_read(device_t, const char *key, int16_t *val);
99 static void 	asmc_sms_calibrate(device_t dev);
100 static int 	asmc_sms_intrfast(void *arg);
101 static void 	asmc_sms_printintr(device_t dev, uint8_t);
102 static void 	asmc_sms_task(void *arg, int pending);
103 static void	asmc_sms_init(device_t dev);
104 static void	asmc_detect_capabilities(device_t dev);
105 #ifdef ASMC_DEBUG
106 void		asmc_dumpall(device_t);
107 static int	asmc_key_dump(device_t, int);
108 #endif
109 
110 /*
111  * Sysctl handlers.
112  */
113 static int 	asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
114 static int 	asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
115 static int 	asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
116 static int 	asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
117 static int 	asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
118 static int 	asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
119 static int 	asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS);
120 static int 	asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
121 static int 	asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
122 static int 	asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
123 static int 	asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
124 static int 	asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
125 static int 	asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
126 static int 	asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
127 static int 	asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS);
128 static int	asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS);
129 
130 static int	asmc_key_getinfo(device_t, const char *, uint8_t *, char *);
131 
132 /* System state / board identity sysctls */
133 static int	asmc_cause_sysctl(SYSCTL_HANDLER_ARGS);
134 static int	asmc_msal_sysctl(SYSCTL_HANDLER_ARGS);
135 static int	asmc_clkt_sysctl(SYSCTL_HANDLER_ARGS);
136 static int	asmc_msps_sysctl(SYSCTL_HANDLER_ARGS);
137 static int	asmc_rplt_sysctl(SYSCTL_HANDLER_ARGS);
138 static int	asmc_rgen_sysctl(SYSCTL_HANDLER_ARGS);
139 
140 #ifdef ASMC_DEBUG
141 /* Raw key access */
142 static int	asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS);
143 static int	asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS);
144 static int	asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS);
145 static int	asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS);
146 #endif
147 
148 /* Voltage/Current/Power/Light sensor support */
149 static int	asmc_sensor_read(device_t, const char *, int *);
150 static int	asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS);
151 static int	asmc_detect_sensors(device_t);
152 static int	asmc_key_dump_by_index(device_t, int, char *, char *, uint8_t *);
153 static int	asmc_key_search(device_t, const char *, unsigned int *);
154 static const char *asmc_temp_desc(const char *key);
155 
156 /*
157  * SMC temperature key descriptions.
158  * These are universal across all Intel Apple hardware.
159  */
160 static const struct {
161 	const char	*key;
162 	const char	*desc;
163 } asmc_temp_descs[] = {
164 	/* Ambient / airflow */
165 	{ "TA0P", "Ambient" },
166 	{ "TA0S", "PCIe Slot 1 Ambient" },
167 	{ "TA0p", "Ambient Air" },
168 	{ "TA1P", "Ambient 2" },
169 	{ "TA1S", "PCIe Slot 1 PCB" },
170 	{ "TA1p", "Ambient Air 2" },
171 	{ "TA2P", "Ambient 3" },
172 	{ "TA2S", "PCIe Slot 2 Ambient" },
173 	{ "TA3S", "PCIe Slot 2 PCB" },
174 	{ "TA0V", "Ambient" },
175 	{ "TALP", "Ambient Light Proximity" },
176 	{ "TaLC", "Airflow Left" },
177 	{ "TaRC", "Airflow Right" },
178 	{ "Ta0P", "Airflow Proximity" },
179 	/* Battery / enclosure */
180 	{ "TB0T", "Enclosure Bottom" },
181 	{ "TB1T", "Battery 1" },
182 	{ "TB2T", "Battery 2" },
183 	{ "TB3T", "Battery 3" },
184 	{ "TBXT", "Battery" },
185 	{ "Tb0P", "BLC Proximity" },
186 	/* CPU */
187 	{ "TC0C", "CPU Core 1" },
188 	{ "TC0D", "CPU Die" },
189 	{ "TC0E", "CPU 1" },
190 	{ "TC0F", "CPU 2" },
191 	{ "TC0G", "CPU Package GPU" },
192 	{ "TC0H", "CPU Heatsink" },
193 	{ "TC0h", "CPU Heatsink" },
194 	{ "TC0J", "CPU" },
195 	{ "TC0P", "CPU Proximity" },
196 	{ "TC0c", "CPU Core 1 PECI" },
197 	{ "TC0d", "CPU Die PECI" },
198 	{ "TC0p", "CPU Proximity" },
199 	{ "TC1C", "CPU Core 2" },
200 	{ "TC1c", "CPU Core 2 PECI" },
201 	{ "TC1P", "CPU Proximity 2" },
202 	{ "TC2C", "CPU Core 3" },
203 	{ "TC2P", "CPU Proximity 3" },
204 	{ "TC2c", "CPU Core 3 PECI" },
205 	{ "TC3C", "CPU Core 4" },
206 	{ "TC3P", "CPU Proximity 4" },
207 	{ "TC3c", "CPU Core 4 PECI" },
208 	{ "TC4C", "CPU Core 5" },
209 	{ "TC5C", "CPU Core 6" },
210 	{ "TC6C", "CPU Core 7" },
211 	{ "TC7C", "CPU Core 8" },
212 	{ "TC8C", "CPU Core 9" },
213 	{ "TCGC", "PECI GPU" },
214 	{ "TCGc", "PECI GPU" },
215 	{ "TCHP", "Charger Proximity" },
216 	{ "TCSA", "PECI SA" },
217 	{ "TCSC", "PECI SA" },
218 	{ "TCSc", "PECI SA" },
219 	{ "TCTD", "CPU DTS" },
220 	{ "TCXC", "PECI CPU" },
221 	{ "TCXc", "PECI CPU" },
222 	{ "TCPG", "CPU Package GPU" },
223 	{ "TCXR", "CPU PECI DTS" },
224 	/* CPU dual-socket (Mac Pro) */
225 	{ "TCAG", "CPU A Package" },
226 	{ "TCAH", "CPU A Heatsink" },
227 	{ "TCBG", "CPU B Package" },
228 	{ "TCBH", "CPU B Heatsink" },
229 	/* GPU */
230 	{ "TG0C", "GPU Core" },
231 	{ "TG0D", "GPU Diode" },
232 	{ "TG0H", "GPU Heatsink" },
233 	{ "TG0M", "GPU Memory" },
234 	{ "TG0P", "GPU Proximity" },
235 	{ "TG0T", "GPU Diode" },
236 	{ "TG0V", "GPU" },
237 	{ "TG0d", "GPU Die" },
238 	{ "TG0h", "GPU Heatsink" },
239 	{ "TG0p", "GPU Proximity" },
240 	{ "TGTV", "GPU" },
241 	{ "TG1D", "GPU 2 Diode" },
242 	{ "TG1H", "GPU 2 Heatsink" },
243 	{ "TG1P", "GPU 2 Proximity" },
244 	{ "TG1d", "GPU 2 Die" },
245 	{ "TGVP", "GPU Memory Proximity" },
246 	/* Storage */
247 	{ "TH0A", "SSD A" },
248 	{ "TH0B", "SSD B" },
249 	{ "TH0C", "SSD C" },
250 	{ "TH0F", "SSD" },
251 	{ "TH0O", "HDD" },
252 	{ "TH0P", "HDD Proximity" },
253 	{ "TH0R", "SSD" },
254 	{ "TH0V", "SSD" },
255 	{ "TH0a", "SSD A" },
256 	{ "TH0b", "SSD B" },
257 	{ "TH0c", "SSD C" },
258 	{ "TH1O", "HDD 2" },
259 	{ "TH1P", "HDD Bay 2" },
260 	{ "TH2P", "HDD Bay 3" },
261 	{ "TH3P", "HDD Bay 4" },
262 	{ "Th0H", "Heatpipe 1" },
263 	{ "Th0N", "SSD" },
264 	{ "Th1H", "Heatpipe 2" },
265 	{ "Th2H", "Heatpipe 3" },
266 	/* Thunderbolt */
267 	{ "THSP", "Thunderbolt Proximity" },
268 	{ "TI0P", "Thunderbolt 1" },
269 	{ "TI0p", "Thunderbolt 1" },
270 	{ "TI1P", "Thunderbolt 2" },
271 	{ "TI1p", "Thunderbolt 2" },
272 	{ "TTLD", "Thunderbolt Left" },
273 	{ "TTRD", "Thunderbolt Right" },
274 	{ "Te0T", "Thunderbolt Diode" },
275 	{ "Te0t", "Thunderbolt Diode" },
276 	/* LCD */
277 	{ "TL0P", "LCD Proximity" },
278 	{ "TL0V", "LCD" },
279 	{ "TL0p", "LCD Proximity" },
280 	{ "TL1P", "LCD Panel 1" },
281 	{ "TL1V", "LCD 1" },
282 	{ "TL1p", "LCD Panel 1" },
283 	{ "TL1v", "LCD 1" },
284 	{ "TL2V", "LCD 2" },
285 	{ "TLAV", "LCD" },
286 	{ "TLBV", "LCD" },
287 	{ "TLCV", "LCD" },
288 	/* Memory */
289 	{ "TM0P", "Memory Proximity" },
290 	{ "TM0S", "Memory Slot 1" },
291 	{ "TM0p", "Memory Proximity" },
292 	{ "TM1P", "Memory Riser A 2" },
293 	{ "TM1S", "Memory Slot 2" },
294 	{ "Tm0P", "Memory Proximity" },
295 	{ "Tm0p", "Memory Proximity" },
296 	{ "Tm1P", "Memory Proximity 2" },
297 	{ "TMBS", "Memory Bank" },
298 	{ "TMCD", "Memory DIMM" },
299 	/* Northbridge / MCH */
300 	{ "TN0C", "Northbridge Core" },
301 	{ "TN0D", "Northbridge Diode" },
302 	{ "TN0H", "MCH Heatsink" },
303 	{ "TN0P", "Northbridge Proximity" },
304 	{ "TN1D", "MCH Die 2" },
305 	{ "TN1P", "Northbridge Proximity 2" },
306 	/* PCH */
307 	{ "TP0P", "PCH Proximity" },
308 	{ "TP0p", "PCH Proximity" },
309 	{ "TPCD", "PCH Die" },
310 	{ "TPCd", "PCH Die" },
311 	/* Optical drive */
312 	{ "TO0P", "Optical Drive" },
313 	{ "TO0p", "Optical Drive" },
314 	/* Power supply */
315 	{ "Tp0C", "Power Supply" },
316 	{ "Tp0P", "Power Supply Proximity" },
317 	{ "Tp1C", "Power Supply 2" },
318 	{ "Tp1P", "Power Supply Component" },
319 	{ "Tp1p", "Power Supply Component" },
320 	{ "Tp2P", "Power Supply 2" },
321 	{ "Tp2h", "Power Supply 2" },
322 	{ "Tp2H", "Power Supply 2" },
323 	{ "Tp3P", "Power Supply 3 Inlet" },
324 	{ "Tp3h", "Power Supply 3" },
325 	{ "Tp3H", "Power Supply 3" },
326 	{ "Tp4P", "Power Supply 4" },
327 	{ "Tp5P", "Power Supply 5" },
328 	/* Palm rest / trackpad */
329 	{ "Ts0P", "Palm Rest" },
330 	{ "Ts0S", "Memory Proximity" },
331 	{ "Ts1P", "Palm Rest 2" },
332 	{ "Ts1S", "Palm Rest 2" },
333 	/* Wireless */
334 	{ "TW0P", "Wireless Proximity" },
335 	{ "TW0p", "Wireless Proximity" },
336 	{ "TBLR", "Bluetooth" },
337 	/* Camera */
338 	{ "TS2P", "Camera Proximity" },
339 	{ "TS2V", "Camera" },
340 	{ "TS2p", "Camera Proximity" },
341 	/* Expansion */
342 	{ "TS0C", "Expansion Slots" },
343 	{ "TS0P", "Expansion Proximity" },
344 	{ "TS0V", "Expansion" },
345 	{ "TS0p", "Expansion Proximity" },
346 	/* Air vent */
347 	{ "TV0P", "Air Vent" },
348 	/* VRM */
349 	{ "Tv0S", "VRM 1" },
350 	{ "Tv1S", "VRM 2" },
351 	/* Misc */
352 	{ "TTF0", "Fan" },
353 	{ "TMLB", "Logic Board" },
354 };
355 
356 static const char *
357 asmc_temp_desc(const char *key)
358 {
359 	unsigned int i;
360 
361 	for (i = 0; i < nitems(asmc_temp_descs); i++) {
362 		if (strcmp(asmc_temp_descs[i].key, key) == 0)
363 			return (asmc_temp_descs[i].desc);
364 	}
365 	return ("Temperature");
366 }
367 
368 /*
369  * Driver methods.
370  */
371 static device_method_t	asmc_methods[] = {
372 	DEVMETHOD(device_probe,		asmc_probe),
373 	DEVMETHOD(device_attach,	asmc_attach),
374 	DEVMETHOD(device_detach,	asmc_detach),
375 	DEVMETHOD(device_resume,	asmc_resume),
376 
377 	/* Backlight interface */
378 	DEVMETHOD(backlight_update_status, asmc_backlight_update_status),
379 	DEVMETHOD(backlight_get_status, asmc_backlight_get_status),
380 	DEVMETHOD(backlight_get_info, asmc_backlight_get_info),
381 
382 	DEVMETHOD_END
383 };
384 
385 static driver_t	asmc_driver = {
386 	"asmc",
387 	asmc_methods,
388 	sizeof(struct asmc_softc)
389 };
390 
391 /*
392  * Debugging
393  */
394 #define	_COMPONENT	ACPI_OEM
395 ACPI_MODULE_NAME("ASMC")
396 #ifdef ASMC_DEBUG
397 #define ASMC_DPRINTF(str, ...)	device_printf(dev, str, ##__VA_ARGS__)
398 #else
399 #define ASMC_DPRINTF(str, ...)
400 #endif
401 
402 /* NB: can't be const */
403 static char *asmc_ids[] = { "APP0001", NULL };
404 
405 static unsigned int light_control = 0;
406 
407 ACPI_PNP_INFO(asmc_ids);
408 DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL);
409 MODULE_DEPEND(asmc, acpi, 1, 1, 1);
410 MODULE_DEPEND(asmc, backlight, 1, 1, 1);
411 
412 static int
413 asmc_probe(device_t dev)
414 {
415 	char *product;
416 	int rv;
417 
418 	if (resource_disabled("asmc", 0))
419 		return (ENXIO);
420 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL);
421 	if (rv > 0)
422 		return (rv);
423 	product = kern_getenv("smbios.system.product");
424 	device_set_descf(dev, "Apple %s", product ? product : "SMC");
425 	freeenv(product);
426 	return (rv);
427 }
428 
429 /*
430  * Try PIO first; fall back to MMIO for T2 Macs.
431  */
432 static int
433 asmc_try_probe(device_t dev)
434 {
435 	struct asmc_softc *sc = device_get_softc(dev);
436 
437 	sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
438 	    &sc->sc_rid_port, RF_ACTIVE);
439 	if (sc->sc_ioport != NULL)
440 		return (0);
441 
442 	sc->sc_rid_mem = 0;
443 	sc->sc_iomem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
444 	    &sc->sc_rid_mem, RF_ACTIVE);
445 	if (sc->sc_iomem != NULL) {
446 		if (asmc_mmio_probe(dev) == 0) {
447 			sc->sc_is_mmio = true;
448 			device_printf(dev, "using MMIO backend (T2)\n");
449 			return (0);
450 		}
451 		bus_release_resource(dev, SYS_RES_MEMORY,
452 		    sc->sc_rid_mem, sc->sc_iomem);
453 		sc->sc_iomem = NULL;
454 	}
455 
456 	device_printf(dev, "unable to allocate IO port\n");
457 	return (ENOMEM);
458 }
459 
460 static int
461 asmc_attach(device_t dev)
462 {
463 	int i, j;
464 	int ret;
465 	char name[2];
466 	struct asmc_softc *sc = device_get_softc(dev);
467 	struct sysctl_ctx_list *sysctlctx;
468 	struct sysctl_oid *sysctlnode;
469 
470 	ret = asmc_try_probe(dev);
471 	if (ret != 0)
472 		goto err;
473 
474 	sysctlctx = device_get_sysctl_ctx(dev);
475 	sysctlnode = device_get_sysctl_tree(dev);
476 
477 	/* Mutex may already be initialized by asmc_mmio_probe() */
478 	if (!mtx_initialized(&sc->sc_mtx))
479 		mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
480 
481 	/* Read SMC revision, key count, fan count */
482 	ret = asmc_init(dev);
483 	if (ret != 0) {
484 		device_printf(dev, "SMC not responding\n");
485 		goto err;
486 	}
487 
488 	/* Probe SMC keys to detect capabilities */
489 	asmc_detect_capabilities(dev);
490 
491 	/* Auto-detect and register voltage/current/power/ambient/temp sensors */
492 	asmc_detect_sensors(dev);
493 
494 	/*
495 	 * dev.asmc.n.fan.* tree.
496 	 */
497 	sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
498 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
499 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree");
500 
501 	for (i = 1; i <= sc->sc_nfan; i++) {
502 		j = i - 1;
503 		name[0] = '0' + j;
504 		name[1] = 0;
505 		sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
506 		    SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name,
507 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree");
508 
509 		SYSCTL_ADD_PROC(sysctlctx,
510 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
511 		    OID_AUTO, "id",
512 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
513 		    asmc_mb_sysctl_fanid, "I", "Fan ID");
514 
515 		SYSCTL_ADD_PROC(sysctlctx,
516 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
517 		    OID_AUTO, "speed",
518 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
519 		    asmc_mb_sysctl_fanspeed, "I", "Fan speed in RPM");
520 
521 		if (sc->sc_has_safespeed) {
522 			SYSCTL_ADD_PROC(sysctlctx,
523 			    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
524 			    OID_AUTO, "safespeed",
525 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
526 			    asmc_mb_sysctl_fansafespeed, "I",
527 			    "Fan safe speed in RPM");
528 		}
529 
530 		SYSCTL_ADD_PROC(sysctlctx,
531 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
532 		    OID_AUTO, "minspeed",
533 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
534 		    asmc_mb_sysctl_fanminspeed, "I",
535 		    "Fan minimum speed in RPM");
536 
537 		SYSCTL_ADD_PROC(sysctlctx,
538 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
539 		    OID_AUTO, "maxspeed",
540 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
541 		    asmc_mb_sysctl_fanmaxspeed, "I",
542 		    "Fan maximum speed in RPM");
543 
544 		SYSCTL_ADD_PROC(sysctlctx,
545 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
546 		    OID_AUTO, "targetspeed",
547 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
548 		    asmc_mb_sysctl_fantargetspeed, "I",
549 		    "Fan target speed in RPM");
550 
551 		SYSCTL_ADD_PROC(sysctlctx,
552 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
553 		    OID_AUTO, "manual",
554 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
555 		    asmc_mb_sysctl_fanmanual, "I",
556 		    "Fan manual mode (0=auto, 1=manual)");
557 	}
558 
559 	/*
560 	 * dev.asmc.n.temp tree.
561 	 */
562 	sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
563 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
564 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
565 
566 	for (i = 0; i < sc->sc_temp_count; i++) {
567 		SYSCTL_ADD_PROC(sysctlctx,
568 		    SYSCTL_CHILDREN(sc->sc_temp_tree),
569 		    OID_AUTO, sc->sc_temp_sensors[i],
570 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i,
571 		    asmc_temp_sysctl, "I",
572 		    asmc_temp_desc(sc->sc_temp_sensors[i]));
573 	}
574 
575 	/*
576 	 * dev.asmc.n.light
577 	 */
578 	if (sc->sc_has_light) {
579 		sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
580 		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
581 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
582 		    "Keyboard backlight sensors");
583 
584 		SYSCTL_ADD_PROC(sysctlctx,
585 		    SYSCTL_CHILDREN(sc->sc_light_tree),
586 		    OID_AUTO, "left",
587 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
588 		    dev, 0,
589 		    sc->sc_light_len == ASMC_LIGHT_LONGLEN ?
590 		        asmc_mbp_sysctl_light_left_10byte :
591 		        asmc_mbp_sysctl_light_left,
592 		    "I", "Keyboard backlight left sensor");
593 
594 		if (sc->sc_light_len != ASMC_LIGHT_LONGLEN &&
595 		    asmc_key_getinfo(dev, ASMC_KEY_LIGHTRIGHT,
596 		    NULL, NULL) == 0) {
597 			SYSCTL_ADD_PROC(sysctlctx,
598 			    SYSCTL_CHILDREN(sc->sc_light_tree),
599 			    OID_AUTO, "right",
600 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
601 			    dev, 0,
602 			    asmc_mbp_sysctl_light_right, "I",
603 			    "Keyboard backlight right sensor");
604 		}
605 
606 		SYSCTL_ADD_PROC(sysctlctx,
607 		    SYSCTL_CHILDREN(sc->sc_light_tree),
608 		    OID_AUTO, "control",
609 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
610 		    dev, 0, asmc_mbp_sysctl_light_control, "I",
611 		    "Keyboard backlight brightness control");
612 
613 		sc->sc_kbd_bkl = backlight_register("asmc", dev);
614 		if (sc->sc_kbd_bkl == NULL) {
615 			device_printf(dev, "Can not register backlight\n");
616 			ret = ENXIO;
617 			goto err;
618 		}
619 	}
620 
621 #ifdef ASMC_DEBUG
622 	/*
623 	 * Raw SMC key access for debugging.
624 	 */
625 	sc->sc_raw_tree = SYSCTL_ADD_NODE(sysctlctx,
626 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
627 	    "raw", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Raw SMC key access");
628 
629 	SYSCTL_ADD_PROC(sysctlctx,
630 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
631 	    OID_AUTO, "key",
632 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
633 	    dev, 0, asmc_raw_key_sysctl, "A",
634 	    "SMC key name (4 chars)");
635 
636 	SYSCTL_ADD_PROC(sysctlctx,
637 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
638 	    OID_AUTO, "value",
639 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
640 	    dev, 0, asmc_raw_value_sysctl, "A",
641 	    "SMC key value (hex string)");
642 
643 	SYSCTL_ADD_PROC(sysctlctx,
644 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
645 	    OID_AUTO, "len",
646 	    CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
647 	    dev, 0, asmc_raw_len_sysctl, "CU",
648 	    "SMC key value length");
649 
650 	SYSCTL_ADD_PROC(sysctlctx,
651 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
652 	    OID_AUTO, "type",
653 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
654 	    dev, 0, asmc_raw_type_sysctl, "A",
655 	    "SMC key type (4 chars)");
656 #endif
657 
658 	/*
659 	 * Battery charge limit (T2 Macs).
660 	 */
661 	if (sc->sc_is_t2 &&
662 	    asmc_key_getinfo(dev, ASMC_KEY_BCLM, NULL, NULL) == 0) {
663 		SYSCTL_ADD_PROC(sysctlctx,
664 		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "battery_charge_limit",
665 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
666 		    dev, 0, asmc_bclm_sysctl, "I",
667 		    "Battery charge limit (0-100)");
668 	}
669 
670 	/* System state / board identity subtree. */
671 	{
672 		struct sysctl_oid *sys_tree;
673 		uint8_t msps_len;
674 
675 		sys_tree = SYSCTL_ADD_NODE(sysctlctx,
676 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
677 		    "system", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
678 		    "System state and board identity");
679 		if (sys_tree == NULL) {
680 			device_printf(dev,
681 			    "failed to create system sysctl node\n");
682 			goto nosms;
683 		}
684 
685 		if (asmc_key_getinfo(dev, ASMC_KEY_MSSD, NULL, NULL) == 0)
686 			SYSCTL_ADD_PROC(sysctlctx,
687 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "shutdown_cause",
688 			    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
689 			    dev, 0, asmc_cause_sysctl, "A",
690 			    "Last shutdown cause (MSSD)");
691 
692 		if (asmc_key_getinfo(dev, ASMC_KEY_MSSP, NULL, NULL) == 0)
693 			SYSCTL_ADD_PROC(sysctlctx,
694 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "sleep_cause",
695 			    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
696 			    dev, 1, asmc_cause_sysctl, "A",
697 			    "Last sleep cause (MSSP)");
698 
699 		if (asmc_key_getinfo(dev, ASMC_KEY_MSAL, NULL, NULL) == 0)
700 			SYSCTL_ADD_PROC(sysctlctx,
701 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "thermal_status",
702 			    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
703 			    dev, 0, asmc_msal_sysctl, "A",
704 			    "Thermal subsystem status flags (MSAL)");
705 
706 		if (asmc_key_getinfo(dev, ASMC_KEY_CLKT, NULL, NULL) == 0)
707 			SYSCTL_ADD_PROC(sysctlctx,
708 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "time_of_day",
709 			    CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
710 			    dev, 0, asmc_clkt_sysctl, "IU",
711 			    "Seconds since midnight per SMC clock (CLKT)");
712 
713 		if (asmc_key_getinfo(dev, ASMC_KEY_MSPS, &msps_len, NULL) == 0 &&
714 		    (msps_len == 1 || msps_len == 2))
715 			SYSCTL_ADD_PROC(sysctlctx,
716 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "power_state",
717 			    CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
718 			    dev, 0, asmc_msps_sysctl, "IU",
719 			    "SMC power state index (MSPS)");
720 
721 		if (asmc_key_getinfo(dev, ASMC_KEY_RPLT, NULL, NULL) == 0)
722 			SYSCTL_ADD_PROC(sysctlctx,
723 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "board_id",
724 			    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
725 			    dev, 0, asmc_rplt_sysctl, "A",
726 			    "Apple internal board codename (RPlt)");
727 
728 		if (asmc_key_getinfo(dev, ASMC_KEY_RGEN, NULL, NULL) == 0)
729 			SYSCTL_ADD_PROC(sysctlctx,
730 			    SYSCTL_CHILDREN(sys_tree), OID_AUTO, "chip_gen",
731 			    CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE,
732 			    dev, 0, asmc_rgen_sysctl, "IU",
733 			    "Apple security chip generation (RGEN; 3=T2)");
734 	}
735 
736 	if (!sc->sc_has_sms)
737 		goto nosms;
738 
739 	/*
740 	 * Initialize SMS hardware.
741 	 */
742 	asmc_sms_init(dev);
743 
744 	/*
745 	 * dev.asmc.n.sms tree.
746 	 */
747 	sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
748 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
749 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor");
750 
751 	SYSCTL_ADD_PROC(sysctlctx,
752 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
753 	    OID_AUTO, "x",
754 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
755 	    dev, 0, asmc_mb_sysctl_sms_x, "I",
756 	    "Sudden Motion Sensor X value");
757 
758 	SYSCTL_ADD_PROC(sysctlctx,
759 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
760 	    OID_AUTO, "y",
761 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
762 	    dev, 0, asmc_mb_sysctl_sms_y, "I",
763 	    "Sudden Motion Sensor Y value");
764 
765 	SYSCTL_ADD_PROC(sysctlctx,
766 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
767 	    OID_AUTO, "z",
768 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
769 	    dev, 0, asmc_mb_sysctl_sms_z, "I",
770 	    "Sudden Motion Sensor Z value");
771 
772 	/*
773 	 * Need a taskqueue to send devctl_notify() events
774 	 * when the SMS interrupt us.
775 	 *
776 	 * PI_REALTIME is used due to the sensitivity of the
777 	 * interrupt. An interrupt from the SMS means that the
778 	 * disk heads should be turned off as quickly as possible.
779 	 *
780 	 * We only need to do this for the non INTR_FILTER case.
781 	 */
782 	sc->sc_sms_tq = NULL;
783 	TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
784 	sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
785 	    taskqueue_thread_enqueue, &sc->sc_sms_tq);
786 	taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
787 	    device_get_nameunit(dev));
788 	/*
789 	 * Allocate an IRQ for the SMS.
790 	 */
791 	sc->sc_rid_irq = 0;
792 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq,
793 	    RF_ACTIVE);
794 	if (sc->sc_irq == NULL) {
795 		device_printf(dev, "unable to allocate IRQ resource\n");
796 		ret = ENXIO;
797 		goto err;
798 	}
799 
800 	ret = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE,
801 	    asmc_sms_intrfast, NULL, dev, &sc->sc_cookie);
802 	if (ret) {
803 		device_printf(dev, "unable to setup SMS IRQ\n");
804 		goto err;
805 	}
806 
807 nosms:
808 	return (0);
809 
810 err:
811 	asmc_detach(dev);
812 
813 	return (ret);
814 }
815 
816 static int
817 asmc_detach(device_t dev)
818 {
819 	struct asmc_softc *sc = device_get_softc(dev);
820 
821 	if (sc->sc_kbd_bkl != NULL)
822 		backlight_destroy(sc->sc_kbd_bkl);
823 
824 	/* Free temperature sensor key arrays */
825 	for (int i = 0; i < sc->sc_temp_count; i++)
826 		free(sc->sc_temp_sensors[i], M_DEVBUF);
827 
828 	/* Free sensor key arrays */
829 	for (int i = 0; i < sc->sc_voltage_count; i++)
830 		free(sc->sc_voltage_sensors[i], M_DEVBUF);
831 	for (int i = 0; i < sc->sc_current_count; i++)
832 		free(sc->sc_current_sensors[i], M_DEVBUF);
833 	for (int i = 0; i < sc->sc_power_count; i++)
834 		free(sc->sc_power_sensors[i], M_DEVBUF);
835 	for (int i = 0; i < sc->sc_light_count; i++)
836 		free(sc->sc_light_sensors[i], M_DEVBUF);
837 
838 	if (sc->sc_sms_tq) {
839 		taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
840 		taskqueue_free(sc->sc_sms_tq);
841 		sc->sc_sms_tq = NULL;
842 	}
843 	if (sc->sc_cookie) {
844 		bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
845 		sc->sc_cookie = NULL;
846 	}
847 	if (sc->sc_irq) {
848 		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
849 		    sc->sc_irq);
850 		sc->sc_irq = NULL;
851 	}
852 	if (sc->sc_ioport) {
853 		bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
854 		    sc->sc_ioport);
855 		sc->sc_ioport = NULL;
856 	}
857 	asmc_mmio_detach(dev, sc);
858 	if (mtx_initialized(&sc->sc_mtx)) {
859 		mtx_destroy(&sc->sc_mtx);
860 	}
861 
862 	return (0);
863 }
864 
865 static int
866 asmc_resume(device_t dev)
867 {
868 	uint8_t buf[2];
869 
870 	buf[0] = light_control;
871 	buf[1] = 0x00;
872 	asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
873 
874 	return (0);
875 }
876 
877 #ifdef ASMC_DEBUG
878 void
879 asmc_dumpall(device_t dev)
880 {
881 	struct asmc_softc *sc = device_get_softc(dev);
882 	int i;
883 
884 	if (sc->sc_nkeys == 0) {
885 		device_printf(dev, "asmc_dumpall: key count not available\n");
886 		return;
887 	}
888 
889 	device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys);
890 	for (i = 0; i < sc->sc_nkeys; i++)
891 		asmc_key_dump(dev, i);
892 }
893 #endif
894 
895 /*
896  * Initialize SMC: read revision, key count, fan count.
897  * SMS initialization is handled separately in asmc_sms_init().
898  */
899 static int
900 asmc_init(device_t dev)
901 {
902 	struct asmc_softc *sc = device_get_softc(dev);
903 	struct sysctl_ctx_list *sysctlctx;
904 	uint8_t buf[6];
905 	int error;
906 
907 	sysctlctx = device_get_sysctl_ctx(dev);
908 
909 	error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6);
910 	if (error != 0) {
911 		/*
912 		 * Could not read REV key; T2 Macs may not have it.
913 		 * Use #KEY as a liveness check instead.
914 		 */
915 		if (sc->sc_is_t2) {
916 			error = asmc_key_read(dev, ASMC_NKEYS, buf, 4);
917 			if (error != 0)
918 				goto out;
919 			device_printf(dev, "T2 SMC: %d keys\n",
920 			    be32dec(buf));
921 		} else {
922 			goto out;
923 		}
924 	} else {
925 		device_printf(dev, "SMC revision: %x.%x%x%x\n",
926 		    buf[0], buf[1], buf[2],
927 		    ntohs(*(uint16_t *)buf + 4));
928 	}
929 
930 	/* Auto power-on after AC power loss (AUPO). */
931 	if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) {
932 		SYSCTL_ADD_PROC(sysctlctx,
933 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
934 		    OID_AUTO, "auto_poweron",
935 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
936 		    dev, 0, asmc_aupo_sysctl, "I",
937 		    "Auto power-on after AC power loss (0=off, 1=on)");
938 	}
939 
940 	sc->sc_nfan = asmc_fan_count(dev);
941 	if (sc->sc_nfan > ASMC_MAXFANS) {
942 		device_printf(dev,
943 		    "more than %d fans were detected. Please report this.\n",
944 		    ASMC_MAXFANS);
945 		sc->sc_nfan = ASMC_MAXFANS;
946 	}
947 
948 	/*
949 	 * Read and cache the number of SMC keys (32 bit buffer)
950 	 */
951 	if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) {
952 		sc->sc_nkeys = be32dec(buf);
953 		if (bootverbose)
954 			device_printf(dev, "number of keys: %d\n",
955 			    sc->sc_nkeys);
956 	} else {
957 		sc->sc_nkeys = 0;
958 	}
959 
960 out:
961 #ifdef ASMC_DEBUG
962 	asmc_dumpall(dev);
963 #endif
964 	return (error);
965 }
966 
967 /*
968  * Initialize the Sudden Motion Sensor hardware.
969  * Called from asmc_attach() after capabilities are detected.
970  */
971 static void
972 asmc_sms_init(device_t dev)
973 {
974 	struct asmc_softc *sc = device_get_softc(dev);
975 	uint8_t buf[2];
976 	int i;
977 
978 	/*
979 	 * We are ready to receive interrupts from the SMS.
980 	 */
981 	buf[0] = 0x01;
982 	ASMC_DPRINTF(("intok key\n"));
983 	asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
984 	DELAY(50);
985 
986 	/*
987 	 * Initiate the polling intervals.
988 	 */
989 	buf[0] = 20; /* msecs */
990 	ASMC_DPRINTF(("low int key\n"));
991 	asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
992 	DELAY(200);
993 
994 	buf[0] = 20; /* msecs */
995 	ASMC_DPRINTF(("high int key\n"));
996 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
997 	DELAY(200);
998 
999 	buf[0] = 0x00;
1000 	buf[1] = 0x60;
1001 	ASMC_DPRINTF(("sms low key\n"));
1002 	asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
1003 	DELAY(200);
1004 
1005 	buf[0] = 0x01;
1006 	buf[1] = 0xc0;
1007 	ASMC_DPRINTF(("sms high key\n"));
1008 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
1009 	DELAY(200);
1010 
1011 	/*
1012 	 * I'm not sure what this key does, but it seems to be
1013 	 * required.
1014 	 */
1015 	buf[0] = 0x01;
1016 	ASMC_DPRINTF(("sms flag key\n"));
1017 	asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
1018 	DELAY(100);
1019 
1020 	sc->sc_sms_intr_works = 0;
1021 
1022 	/*
1023 	 * Retry SMS initialization 1000 times
1024 	 * (takes approx. 2 seconds in worst case)
1025 	 */
1026 	for (i = 0; i < 1000; i++) {
1027 		if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
1028 		    (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
1029 			sc->sc_sms_intr_works = 1;
1030 			goto done;
1031 		}
1032 		buf[0] = ASMC_SMS_INIT1;
1033 		buf[1] = ASMC_SMS_INIT2;
1034 		ASMC_DPRINTF(("sms key\n"));
1035 		asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
1036 		DELAY(50);
1037 	}
1038 	device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
1039 
1040 done:
1041 	asmc_sms_calibrate(dev);
1042 }
1043 
1044 /*
1045  * Probe SMC keys to detect hardware capabilities.
1046  */
1047 static void
1048 asmc_detect_capabilities(device_t dev)
1049 {
1050 	struct asmc_softc *sc = device_get_softc(dev);
1051 	uint8_t len;
1052 	char type[ASMC_TYPELEN + 1];
1053 
1054 	/* SMS: require all keys used by asmc_sms_init() */
1055 	sc->sc_has_sms =
1056 	    (asmc_key_getinfo(dev, ASMC_KEY_SMS,
1057 	    &len, type) == 0 &&
1058 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_X,
1059 	    &len, type) == 0 &&
1060 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_Y,
1061 	    &len, type) == 0 &&
1062 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_Z,
1063 	    &len, type) == 0 &&
1064 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW,
1065 	    &len, type) == 0 &&
1066 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH,
1067 	    &len, type) == 0 &&
1068 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW_INT,
1069 	    &len, type) == 0 &&
1070 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH_INT,
1071 	    &len, type) == 0 &&
1072 	    asmc_key_getinfo(dev, ASMC_KEY_SMS_FLAG,
1073 	    &len, type) == 0 &&
1074 	    asmc_key_getinfo(dev, ASMC_KEY_INTOK,
1075 	    &len, type) == 0);
1076 
1077 	/* Light sensor: require ALV0 (len 6 or 10) and LKSB */
1078 	if (asmc_key_getinfo(dev, ASMC_KEY_LIGHTLEFT,
1079 	    &len, type) == 0 &&
1080 	    (len == ASMC_LIGHT_SHORTLEN || len == ASMC_LIGHT_LONGLEN) &&
1081 	    asmc_key_getinfo(dev, ASMC_KEY_LIGHTVALUE,
1082 	    NULL, NULL) == 0) {
1083 		sc->sc_has_light = 1;
1084 		sc->sc_light_len = len;
1085 	} else {
1086 		sc->sc_has_light = 0;
1087 		sc->sc_light_len = 0;
1088 	}
1089 
1090 	/* Fan safe speed */
1091 	sc->sc_has_safespeed =
1092 	    (asmc_key_getinfo(dev, ASMC_KEY_FANSAFESPEED0,
1093 	    &len, type) == 0);
1094 
1095 	/* Ambient light interrupt source */
1096 	sc->sc_has_alsl =
1097 	    (asmc_key_getinfo(dev, ASMC_KEY_LIGHTSRC,
1098 	    &len, type) == 0);
1099 
1100 	if (bootverbose)
1101 		device_printf(dev,
1102 		    "capabilities: sms=%d light=%d (len=%d) safespeed=%d alsl=%d\n",
1103 		    sc->sc_has_sms, sc->sc_has_light, sc->sc_light_len,
1104 		    sc->sc_has_safespeed, sc->sc_has_alsl);
1105 }
1106 
1107 /*
1108  * We need to make sure that the SMC acks the byte sent.
1109  * Just wait up to (amount * 10)  ms.
1110  */
1111 static int
1112 asmc_wait_ack(device_t dev, uint8_t val, int amount)
1113 {
1114 	struct asmc_softc *sc = device_get_softc(dev);
1115 	u_int i;
1116 
1117 	val = val & ASMC_STATUS_MASK;
1118 
1119 	for (i = 0; i < amount; i++) {
1120 		if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
1121 			return (0);
1122 		DELAY(10);
1123 	}
1124 
1125 	return (1);
1126 }
1127 
1128 /*
1129  * We need to make sure that the SMC acks the byte sent.
1130  * Just wait up to 100 ms.
1131  */
1132 static int
1133 asmc_wait(device_t dev, uint8_t val)
1134 {
1135 #ifdef ASMC_DEBUG
1136 	struct asmc_softc *sc;
1137 #endif
1138 
1139 	if (asmc_wait_ack(dev, val, 1000) == 0)
1140 		return (0);
1141 
1142 #ifdef ASMC_DEBUG
1143 	sc = device_get_softc(dev);
1144 
1145 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__,
1146 	    val & ASMC_STATUS_MASK, ASMC_CMDPORT_READ(sc));
1147 #endif
1148 	return (1);
1149 }
1150 
1151 /*
1152  * Send the given command, retrying up to 10 times if
1153  * the acknowledgement fails.
1154  */
1155 static int
1156 asmc_command(device_t dev, uint8_t command)
1157 {
1158 	int i;
1159 	struct asmc_softc *sc = device_get_softc(dev);
1160 
1161 	for (i = 0; i < 10; i++) {
1162 		ASMC_CMDPORT_WRITE(sc, command);
1163 		if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
1164 			return (0);
1165 		}
1166 	}
1167 
1168 #ifdef ASMC_DEBUG
1169 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
1170 	    ASMC_CMDPORT_READ(sc));
1171 #endif
1172 	return (1);
1173 }
1174 
1175 static int
1176 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1177 {
1178 	struct asmc_softc *sc = device_get_softc(dev);
1179 	int i, error = 1, try = 0;
1180 
1181 	if (sc->sc_is_mmio)
1182 		return (asmc_mmio_key_read(dev, key, buf, len));
1183 
1184 	mtx_lock_spin(&sc->sc_mtx);
1185 
1186 begin:
1187 	if (asmc_command(dev, ASMC_CMDREAD))
1188 		goto out;
1189 
1190 	for (i = 0; i < 4; i++) {
1191 		ASMC_DATAPORT_WRITE(sc, key[i]);
1192 		if (asmc_wait(dev, 0x04))
1193 			goto out;
1194 	}
1195 
1196 	ASMC_DATAPORT_WRITE(sc, len);
1197 
1198 	for (i = 0; i < len; i++) {
1199 		if (asmc_wait(dev, 0x05))
1200 			goto out;
1201 		buf[i] = ASMC_DATAPORT_READ(sc);
1202 	}
1203 
1204 	error = 0;
1205 out:
1206 	if (error) {
1207 		if (++try < 10)
1208 			goto begin;
1209 		device_printf(dev, "%s for key %s failed %d times, giving up\n",
1210 		    __func__, key, try);
1211 	}
1212 
1213 	mtx_unlock_spin(&sc->sc_mtx);
1214 
1215 	return (error);
1216 }
1217 
1218 #ifdef ASMC_DEBUG
1219 static int
1220 asmc_key_dump(device_t dev, int number)
1221 {
1222 	struct asmc_softc *sc = device_get_softc(dev);
1223 	char key[ASMC_KEYLEN + 1] = { 0 };
1224 	char type[ASMC_KEYINFO_RESPLEN + 1] = { 0 };
1225 	uint8_t index[4];
1226 	uint8_t v[ASMC_MAXVAL];
1227 	uint8_t maxlen;
1228 	int i, error = 1, try = 0;
1229 
1230 	if (sc->sc_is_mmio) {
1231 		uint8_t len = 0;
1232 		char mmio_type[ASMC_TYPELEN + 1] = { 0 };
1233 		if (asmc_key_dump_by_index(dev, number, key, mmio_type, &len))
1234 			return (1);
1235 		memset(v, 0, sizeof(v));
1236 		len = MIN(len, sizeof(v));
1237 		asmc_key_read(dev, key, v, len);
1238 		struct sbuf sb;
1239 		char buf[128];
1240 		sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
1241 		sbuf_printf(&sb, "key %d: %s, type %s (len %d), data",
1242 		    number, key, mmio_type, len);
1243 		for (i = 0; i < len; i++)
1244 			sbuf_printf(&sb, " %02x", v[i]);
1245 		sbuf_finish(&sb);
1246 		device_printf(dev, "%s\n", sbuf_data(&sb));
1247 		sbuf_delete(&sb);
1248 		return (0);
1249 	}
1250 
1251 	mtx_lock_spin(&sc->sc_mtx);
1252 
1253 	index[0] = (number >> 24) & 0xff;
1254 	index[1] = (number >> 16) & 0xff;
1255 	index[2] = (number >> 8) & 0xff;
1256 	index[3] = number & 0xff;
1257 
1258 begin:
1259 	if (asmc_command(dev, ASMC_CMDGETBYINDEX))
1260 		goto out;
1261 
1262 	for (i = 0; i < ASMC_KEYLEN; i++) {
1263 		ASMC_DATAPORT_WRITE(sc, index[i]);
1264 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1265 			goto out;
1266 	}
1267 
1268 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN);
1269 
1270 	for (i = 0; i < ASMC_KEYLEN; i++) {
1271 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1272 			goto out;
1273 		key[i] = ASMC_DATAPORT_READ(sc);
1274 	}
1275 
1276 	/* Get key info (length + type). */
1277 	if (asmc_command(dev, ASMC_CMDGETINFO))
1278 		goto out;
1279 
1280 	for (i = 0; i < ASMC_KEYLEN; i++) {
1281 		ASMC_DATAPORT_WRITE(sc, key[i]);
1282 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1283 			goto out;
1284 	}
1285 
1286 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
1287 
1288 	for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
1289 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1290 			goto out;
1291 		type[i] = ASMC_DATAPORT_READ(sc);
1292 	}
1293 
1294 	error = 0;
1295 out:
1296 	if (error) {
1297 		if (++try < ASMC_MAXRETRIES)
1298 			goto begin;
1299 		device_printf(dev,
1300 		    "%s for key %d failed %d times, giving up\n",
1301 		    __func__, number, try);
1302 	}
1303 	mtx_unlock_spin(&sc->sc_mtx);
1304 
1305 	if (error)
1306 		return (error);
1307 
1308 	maxlen = type[0];
1309 	type[0] = ' ';
1310 	type[5] = '\0';
1311 	maxlen = MIN(maxlen, sizeof(v));
1312 
1313 	memset(v, 0, sizeof(v));
1314 	error = asmc_key_read(dev, key, v, maxlen);
1315 	if (error)
1316 		return (error);
1317 
1318 	struct sbuf sb;
1319 	char buf[128];
1320 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
1321 	sbuf_printf(&sb, "key %d: %s, type%s (len %d), data",
1322 	    number, key, type, maxlen);
1323 	for (i = 0; i < maxlen; i++)
1324 		sbuf_printf(&sb, " %02x", v[i]);
1325 	sbuf_finish(&sb);
1326 	device_printf(dev, "%s\n", sbuf_data(&sb));
1327 	sbuf_delete(&sb);
1328 
1329 	return (0);
1330 }
1331 #endif /* ASMC_DEBUG */
1332 
1333 /*
1334  * Get key info (length and type) from SMC using command 0x13.
1335  * If len is non-NULL, stores the key's value length.
1336  * If type is non-NULL, stores the 4-char type string (must be at least 5 bytes).
1337  */
1338 static int
1339 asmc_key_getinfo(device_t dev, const char *key, uint8_t *len, char *type)
1340 {
1341 	struct asmc_softc *sc = device_get_softc(dev);
1342 	uint8_t info[ASMC_KEYINFO_RESPLEN];
1343 	int i, error = -1, try = 0;
1344 
1345 	if (sc->sc_is_mmio)
1346 		return (asmc_mmio_key_getinfo(dev, key, len, type));
1347 
1348 	mtx_lock_spin(&sc->sc_mtx);
1349 
1350 begin:
1351 	if (asmc_command(dev, ASMC_CMDGETINFO))
1352 		goto out;
1353 
1354 	for (i = 0; i < ASMC_KEYLEN; i++) {
1355 		ASMC_DATAPORT_WRITE(sc, key[i]);
1356 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1357 			goto out;
1358 	}
1359 
1360 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
1361 
1362 	for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
1363 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1364 			goto out;
1365 		info[i] = ASMC_DATAPORT_READ(sc);
1366 	}
1367 
1368 	error = 0;
1369 out:
1370 	if (error && ++try < ASMC_MAXRETRIES)
1371 		goto begin;
1372 	mtx_unlock_spin(&sc->sc_mtx);
1373 
1374 	if (error == 0) {
1375 		if (len != NULL)
1376 			*len = info[0];
1377 		if (type != NULL) {
1378 			for (i = 0; i < ASMC_TYPELEN; i++)
1379 				type[i] = info[i + 1];
1380 			type[ASMC_TYPELEN] = '\0';
1381 		}
1382 	}
1383 	return (error);
1384 }
1385 
1386 #ifdef ASMC_DEBUG
1387 /*
1388  * Raw SMC key access sysctls - enables reading/writing any SMC key by name
1389  * Usage:
1390  *   sysctl dev.asmc.0.raw.key=TC0P   # Set key, auto-detects length
1391  *   sysctl dev.asmc.0.raw.value      # Read current value (hex bytes)
1392  *   sysctl dev.asmc.0.raw.value=01   # Write new value
1393  */
1394 static int
1395 asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS)
1396 {
1397 	device_t dev = (device_t) arg1;
1398 	struct asmc_softc *sc = device_get_softc(dev);
1399 	char newkey[ASMC_KEYLEN + 1];
1400 	uint8_t keylen;
1401 	int error;
1402 
1403 	strlcpy(newkey, sc->sc_rawkey, sizeof(newkey));
1404 	error = sysctl_handle_string(oidp, newkey, sizeof(newkey), req);
1405 	if (error || req->newptr == NULL)
1406 		return (error);
1407 
1408 	if (strlen(newkey) != ASMC_KEYLEN)
1409 		return (EINVAL);
1410 
1411 	/* Get key info to auto-detect length and type */
1412 	if (asmc_key_getinfo(dev, newkey, &keylen, sc->sc_rawtype) != 0)
1413 		return (ENOENT);
1414 
1415 	if (keylen > ASMC_MAXVAL)
1416 		keylen = ASMC_MAXVAL;
1417 
1418 	strlcpy(sc->sc_rawkey, newkey, sizeof(sc->sc_rawkey));
1419 	sc->sc_rawlen = keylen;
1420 	memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval));
1421 
1422 	/* Read the key value */
1423 	asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen);
1424 
1425 	return (0);
1426 }
1427 
1428 static int
1429 asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS)
1430 {
1431 	device_t dev = (device_t) arg1;
1432 	struct asmc_softc *sc = device_get_softc(dev);
1433 	char hexbuf[ASMC_MAXVAL * 2 + 1];
1434 	int error, i;
1435 
1436 	/* Refresh from SMC if a key has been selected. */
1437 	if (sc->sc_rawkey[0] != '\0') {
1438 		asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval,
1439 		    sc->sc_rawlen > 0 ? sc->sc_rawlen : ASMC_MAXVAL);
1440 	}
1441 
1442 	/* Format as hex string */
1443 	for (i = 0; i < sc->sc_rawlen && i < ASMC_MAXVAL; i++)
1444 		snprintf(hexbuf + i * 2, 3, "%02x", sc->sc_rawval[i]);
1445 	hexbuf[i * 2] = '\0';
1446 
1447 	error = sysctl_handle_string(oidp, hexbuf, sizeof(hexbuf), req);
1448 	if (error || req->newptr == NULL)
1449 		return (error);
1450 
1451 	/* Reject writes until a key is selected via raw.key. */
1452 	if (sc->sc_rawkey[0] == '\0')
1453 		return (EINVAL);
1454 
1455 	memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval));
1456 	for (i = 0; i < sc->sc_rawlen && hexbuf[i*2] && hexbuf[i*2+1]; i++) {
1457 		unsigned int val;
1458 		char tmp[3] = { hexbuf[i*2], hexbuf[i*2+1], 0 };
1459 		if (sscanf(tmp, "%02x", &val) == 1)
1460 			sc->sc_rawval[i] = (uint8_t)val;
1461 	}
1462 
1463 	if (asmc_key_write(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen) != 0)
1464 		return (EIO);
1465 
1466 	return (0);
1467 }
1468 
1469 static int
1470 asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS)
1471 {
1472 	device_t dev = (device_t) arg1;
1473 	struct asmc_softc *sc = device_get_softc(dev);
1474 
1475 	return (sysctl_handle_8(oidp, &sc->sc_rawlen, 0, req));
1476 }
1477 
1478 static int
1479 asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS)
1480 {
1481 	device_t dev = (device_t) arg1;
1482 	struct asmc_softc *sc = device_get_softc(dev);
1483 
1484 	return (sysctl_handle_string(oidp, sc->sc_rawtype,
1485 	    sizeof(sc->sc_rawtype), req));
1486 }
1487 #endif
1488 
1489 /* SMC sensor type table: type string to fixed-point divisor. */
1490 static const struct {
1491 	const char	type[5];
1492 	int		divisor;
1493 } asmc_sensor_types[] = {
1494 	{ "sp78",  256 },
1495 	{ "sp87",  128 },
1496 	{ "sp4b", 2048 },
1497 	{ "sp5a", 1024 },
1498 	{ "sp69",  512 },
1499 	{ "sp96",   64 },
1500 	{ "sp2d", 8192 },
1501 	{ "ui16",    1 },
1502 	{ "",        0 },
1503 };
1504 
1505 /* Convert a 2-byte SMC value to milli-units. */
1506 static bool
1507 asmc_sensor_convert(const char *type, const uint8_t *buf, int *millivalue)
1508 {
1509 	int i;
1510 
1511 	for (i = 0; asmc_sensor_types[i].divisor != 0; i++) {
1512 		if (strncmp(type, asmc_sensor_types[i].type, 4) != 0)
1513 			continue;
1514 		if (asmc_sensor_types[i].divisor == 1)
1515 			*millivalue = be16dec(buf);
1516 		else
1517 			*millivalue = ((int)(int16_t)be16dec(buf) * 1000) /
1518 			    asmc_sensor_types[i].divisor;
1519 		return (true);
1520 	}
1521 	return (false);
1522 }
1523 
1524 static bool
1525 asmc_sensor_type_supported(const char *type)
1526 {
1527 	int i;
1528 
1529 	for (i = 0; asmc_sensor_types[i].divisor != 0; i++)
1530 		if (strncmp(type, asmc_sensor_types[i].type, 4) == 0)
1531 			return (true);
1532 	return (false);
1533 }
1534 
1535 /*
1536  * Generic sensor value reader with automatic type conversion.
1537  * Reads an SMC key, detects its type, and converts to millivalue.
1538  */
1539 static int
1540 asmc_sensor_read(device_t dev, const char *key, int *millivalue)
1541 {
1542 	uint8_t buf[2];
1543 	char type[ASMC_TYPELEN + 1];
1544 	uint8_t len;
1545 	int error;
1546 
1547 	error = asmc_key_getinfo(dev, key, &len, type);
1548 	if (error != 0)
1549 		return (error);
1550 
1551 	if (len != 2) {
1552 		if (bootverbose)
1553 			device_printf(dev,
1554 			    "%s: key %s unexpected length %d\n",
1555 			    __func__, key, len);
1556 		return (ENXIO);
1557 	}
1558 
1559 	error = asmc_key_read(dev, key, buf, sizeof(buf));
1560 	if (error != 0)
1561 		return (error);
1562 
1563 	if (!asmc_sensor_convert(type, buf, millivalue)) {
1564 		if (bootverbose)
1565 			device_printf(dev,
1566 			    "%s: unknown type '%s' for key %s\n",
1567 			    __func__, type, key);
1568 		return (ENXIO);
1569 	}
1570 
1571 	return (0);
1572 }
1573 
1574 /*
1575  * Generic sensor sysctl handler for voltage/current/power/light sensors.
1576  * arg2 encodes: sensor_type (high byte) | sensor_index (low byte)
1577  * Sensor types: 'V'=voltage, 'I'=current, 'P'=power, 'L'=light
1578  */
1579 static int
1580 asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS)
1581 {
1582 	device_t dev = (device_t) arg1;
1583 	struct asmc_softc *sc = device_get_softc(dev);
1584 	int error, val;
1585 	int sensor_type = (arg2 >> 8) & 0xFF;
1586 	int sensor_idx = arg2 & 0xFF;
1587 	const char *key = NULL;
1588 
1589 	/* Select sensor based on type and index */
1590 	switch (sensor_type) {
1591 	case 'V':  /* Voltage */
1592 		if (sensor_idx < sc->sc_voltage_count)
1593 			key = sc->sc_voltage_sensors[sensor_idx];
1594 		break;
1595 	case 'I':  /* Current */
1596 		if (sensor_idx < sc->sc_current_count)
1597 			key = sc->sc_current_sensors[sensor_idx];
1598 		break;
1599 	case 'P':  /* Power */
1600 		if (sensor_idx < sc->sc_power_count)
1601 			key = sc->sc_power_sensors[sensor_idx];
1602 		break;
1603 	case 'L':  /* Light */
1604 		if (sensor_idx < sc->sc_light_count)
1605 			key = sc->sc_light_sensors[sensor_idx];
1606 		break;
1607 	default:
1608 		return (EINVAL);
1609 	}
1610 
1611 	if (key == NULL)
1612 		return (ENOENT);
1613 
1614 	error = asmc_sensor_read(dev, key, &val);
1615 	if (error != 0)
1616 		return (error);
1617 
1618 	return (sysctl_handle_int(oidp, &val, 0, req));
1619 }
1620 
1621 /*
1622  * Scan a range of SMC key indices, adding matching sensors.
1623  * Only considers 2-byte keys with a supported type.
1624  */
1625 static void
1626 asmc_scan_sensor_range(device_t dev, unsigned int start,
1627     unsigned int end, char prefix, int *countp, char **sensors,
1628     int maxcount)
1629 {
1630 	char key[ASMC_KEYLEN + 1];
1631 	char type[ASMC_TYPELEN + 1];
1632 	uint8_t len;
1633 	unsigned int i;
1634 	char *sensor_key;
1635 
1636 	for (i = start; i < end; i++) {
1637 		if (asmc_key_dump_by_index(dev, i, key, type, &len))
1638 			continue;
1639 		if (key[0] != prefix || len != 2)
1640 			continue;
1641 		if (!asmc_sensor_type_supported(type))
1642 			continue;
1643 		if (*countp >= maxcount)
1644 			break;
1645 		sensor_key = malloc(ASMC_KEYLEN + 1,
1646 		    M_DEVBUF, M_WAITOK);
1647 		memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1648 		sensors[(*countp)++] = sensor_key;
1649 	}
1650 }
1651 
1652 static int
1653 asmc_detect_sensors(device_t dev)
1654 {
1655 	struct asmc_softc *sc = device_get_softc(dev);
1656 	struct sysctl_ctx_list *sysctlctx;
1657 	struct sysctl_oid *tree_node;
1658 	char key[ASMC_KEYLEN + 1];
1659 	char type[ASMC_TYPELEN + 1];
1660 	uint8_t len;
1661 	unsigned int start, end, i;
1662 	int error;
1663 	char *sensor_key;
1664 
1665 	sc->sc_voltage_count = 0;
1666 	sc->sc_current_count = 0;
1667 	sc->sc_power_count = 0;
1668 	sc->sc_light_count = 0;
1669 	sc->sc_temp_count = 0;
1670 
1671 	if (sc->sc_nkeys == 0)
1672 		return (0);
1673 
1674 	/*
1675 	 * Temperature sensors: binary search for T..U range,
1676 	 * then filter by type sp78.
1677 	 */
1678 	error = asmc_key_search(dev, "T\0\0\0", &start);
1679 	if (error == 0)
1680 		error = asmc_key_search(dev, "U\0\0\0", &end);
1681 	if (error == 0) {
1682 		for (i = start; i < end; i++) {
1683 			if (asmc_key_dump_by_index(dev, i,
1684 			    key, type, &len))
1685 				continue;
1686 			if (len != 2 ||
1687 			    strncmp(type, "sp78", 4) != 0)
1688 				continue;
1689 			if (sc->sc_temp_count >= ASMC_TEMP_MAX)
1690 				break;
1691 			sensor_key = malloc(ASMC_KEYLEN + 1,
1692 			    M_DEVBUF, M_WAITOK);
1693 			memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1694 			sc->sc_temp_sensors[sc->sc_temp_count++] =
1695 			    sensor_key;
1696 		}
1697 	}
1698 
1699 	/* Voltage/Current/Power sensors */
1700 	static const struct {
1701 		const char	*range_start;
1702 		const char	*range_end;
1703 		char		prefix;
1704 	} sensor_ranges[] = {
1705 		{ "V\0\0\0", "W\0\0\0", 'V' },	/* Voltage */
1706 		{ "I\0\0\0", "J\0\0\0", 'I' },	/* Current */
1707 		{ "P\0\0\0", "Q\0\0\0", 'P' },	/* Power */
1708 	};
1709 	static const size_t nsensor_ranges = nitems(sensor_ranges);
1710 
1711 	int *sensor_counts[] = {
1712 	    &sc->sc_voltage_count, &sc->sc_current_count,
1713 	    &sc->sc_power_count };
1714 	char **sensor_arrays[] = {
1715 	    sc->sc_voltage_sensors, sc->sc_current_sensors,
1716 	    sc->sc_power_sensors };
1717 
1718 	for (unsigned int r = 0; r < nsensor_ranges; r++) {
1719 		error = asmc_key_search(dev, sensor_ranges[r].range_start,
1720 		    &start);
1721 		if (error == 0)
1722 			error = asmc_key_search(dev,
1723 			    sensor_ranges[r].range_end, &end);
1724 		if (error == 0)
1725 			asmc_scan_sensor_range(dev, start, end,
1726 			    sensor_ranges[r].prefix, sensor_counts[r],
1727 			    sensor_arrays[r], ASMC_MAX_SENSORS);
1728 	}
1729 
1730 	/* Ambient light sensors: AL* in A..B range */
1731 	error = asmc_key_search(dev, "A\0\0\0", &start);
1732 	if (error == 0)
1733 		error = asmc_key_search(dev, "B\0\0\0", &end);
1734 	if (error == 0) {
1735 		for (i = start; i < end; i++) {
1736 			if (asmc_key_dump_by_index(dev, i,
1737 			    key, type, &len))
1738 				continue;
1739 			if (key[0] != 'A' || key[1] != 'L' ||
1740 			    (key[2] != 'V' && key[2] != 'S') ||
1741 			    len != 2)
1742 				continue;
1743 			if (!asmc_sensor_type_supported(type))
1744 				continue;
1745 			if (sc->sc_light_count >= ASMC_MAX_SENSORS)
1746 				break;
1747 			sensor_key = malloc(ASMC_KEYLEN + 1,
1748 			    M_DEVBUF, M_WAITOK);
1749 			memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1750 			sc->sc_light_sensors[sc->sc_light_count++] =
1751 			    sensor_key;
1752 		}
1753 	}
1754 
1755 	if (bootverbose)
1756 		device_printf(dev,
1757 		    "detected %d temp, %d voltage, %d current, "
1758 		    "%d power, %d light sensors\n",
1759 		    sc->sc_temp_count, sc->sc_voltage_count,
1760 		    sc->sc_current_count,
1761 		    sc->sc_power_count, sc->sc_light_count);
1762 
1763 	/* Register sysctls for detected sensors */
1764 	sysctlctx = device_get_sysctl_ctx(dev);
1765 
1766 	static const struct {
1767 		const char	*node_name;
1768 		const char	*node_desc;
1769 		char		tag;
1770 		const char	*leaf_desc;
1771 	} sensor_sysctl[] = {
1772 		{ "voltage", "Voltage sensors (millivolts)",  'V',
1773 		    "Voltage sensor (millivolts)" },
1774 		{ "current", "Current sensors (milliamps)",   'I',
1775 		    "Current sensor (milliamps)" },
1776 		{ "power",   "Power sensors (milliwatts)",    'P',
1777 		    "Power sensor (milliwatts)" },
1778 		{ "ambient", "Ambient light sensors",         'L',
1779 		    "Light sensor value" },
1780 	};
1781 
1782 	int *sysctl_counts[] = {
1783 	    &sc->sc_voltage_count, &sc->sc_current_count,
1784 	    &sc->sc_power_count, &sc->sc_light_count };
1785 	char **sysctl_arrays[] = {
1786 	    sc->sc_voltage_sensors, sc->sc_current_sensors,
1787 	    sc->sc_power_sensors, sc->sc_light_sensors };
1788 
1789 	for (unsigned int s = 0; s < nitems(sensor_sysctl); s++) {
1790 		int count = *sysctl_counts[s];
1791 		if (count <= 0)
1792 			continue;
1793 		tree_node = SYSCTL_ADD_NODE(sysctlctx,
1794 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1795 		    sensor_sysctl[s].node_name,
1796 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1797 		    sensor_sysctl[s].node_desc);
1798 		for (i = 0; i < count; i++) {
1799 			SYSCTL_ADD_PROC(sysctlctx,
1800 			    SYSCTL_CHILDREN(tree_node),
1801 			    OID_AUTO, sysctl_arrays[s][i],
1802 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1803 			    dev, (sensor_sysctl[s].tag << 8) | i,
1804 			    asmc_sensor_sysctl, "I",
1805 			    sensor_sysctl[s].leaf_desc);
1806 		}
1807 	}
1808 
1809 	return (0);
1810 }
1811 
1812 /*
1813  * Helper function to get key info by index (for sensor detection).
1814  */
1815 static int
1816 asmc_key_dump_by_index(device_t dev, int index, char *key_out,
1817     char *type_out, uint8_t *len_out)
1818 {
1819 	struct asmc_softc *sc = device_get_softc(dev);
1820 	uint8_t index_buf[ASMC_KEYLEN];
1821 	uint8_t key_buf[ASMC_KEYLEN];
1822 	uint8_t info_buf[ASMC_KEYINFO_RESPLEN];
1823 	int error = ENXIO, try = 0;
1824 	int i;
1825 
1826 	if (sc->sc_is_mmio) {
1827 		error = asmc_mmio_key_getbyindex(dev, index, key_out);
1828 		if (error != 0)
1829 			return (error);
1830 		return (asmc_mmio_key_getinfo(dev, key_out, len_out,
1831 		    type_out));
1832 	}
1833 
1834 	mtx_lock_spin(&sc->sc_mtx);
1835 
1836 	index_buf[0] = (index >> 24) & 0xff;
1837 	index_buf[1] = (index >> 16) & 0xff;
1838 	index_buf[2] = (index >> 8) & 0xff;
1839 	index_buf[3] = index & 0xff;
1840 
1841 begin:
1842 	if (asmc_command(dev, ASMC_CMDGETBYINDEX))
1843 		goto out;
1844 
1845 	for (i = 0; i < ASMC_KEYLEN; i++) {
1846 		ASMC_DATAPORT_WRITE(sc, index_buf[i]);
1847 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1848 			goto out;
1849 	}
1850 
1851 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN);
1852 
1853 	for (i = 0; i < ASMC_KEYLEN; i++) {
1854 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1855 			goto out;
1856 		key_buf[i] = ASMC_DATAPORT_READ(sc);
1857 	}
1858 
1859 	if (asmc_command(dev, ASMC_CMDGETINFO))
1860 		goto out;
1861 
1862 	for (i = 0; i < ASMC_KEYLEN; i++) {
1863 		ASMC_DATAPORT_WRITE(sc, key_buf[i]);
1864 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1865 			goto out;
1866 	}
1867 
1868 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
1869 
1870 	for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
1871 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1872 			goto out;
1873 		info_buf[i] = ASMC_DATAPORT_READ(sc);
1874 	}
1875 
1876 	memcpy(key_out, key_buf, ASMC_KEYLEN);
1877 	key_out[ASMC_KEYLEN] = '\0';
1878 	*len_out = info_buf[0];
1879 	memcpy(type_out, &info_buf[1], ASMC_TYPELEN);
1880 	type_out[ASMC_TYPELEN] = '\0';
1881 	error = 0;
1882 
1883 out:
1884 	if (error) {
1885 		if (++try < ASMC_MAXRETRIES)
1886 			goto begin;
1887 	}
1888 
1889 	mtx_unlock_spin(&sc->sc_mtx);
1890 	return (error);
1891 }
1892 
1893 /*
1894  * Binary search for the first key index >= prefix.
1895  * SMC keys are sorted, so this finds the lower bound efficiently.
1896  */
1897 static int
1898 asmc_key_search(device_t dev, const char *prefix, unsigned int *idx)
1899 {
1900 	struct asmc_softc *sc = device_get_softc(dev);
1901 	unsigned int lo, hi, mid;
1902 	char key[ASMC_KEYLEN + 1];
1903 	char type[ASMC_TYPELEN + 1];
1904 	uint8_t len;
1905 	int error;
1906 
1907 	lo = 0;
1908 	hi = sc->sc_nkeys;
1909 	while (lo < hi) {
1910 		mid = lo + (hi - lo) / 2;
1911 		error = asmc_key_dump_by_index(dev, mid,
1912 		    key, type, &len);
1913 		if (error != 0)
1914 			return (error);
1915 		if (strncmp(key, prefix, ASMC_KEYLEN) < 0)
1916 			lo = mid + 1;
1917 		else
1918 			hi = mid;
1919 	}
1920 	*idx = lo;
1921 	return (0);
1922 }
1923 
1924 static int
1925 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1926 {
1927 	struct asmc_softc *sc = device_get_softc(dev);
1928 	int i, error = -1, try = 0;
1929 
1930 	if (sc->sc_is_mmio)
1931 		return (asmc_mmio_key_write(dev, key, buf, len));
1932 
1933 	mtx_lock_spin(&sc->sc_mtx);
1934 
1935 begin:
1936 	ASMC_DPRINTF(("cmd port: cmd write\n"));
1937 	if (asmc_command(dev, ASMC_CMDWRITE))
1938 		goto out;
1939 
1940 	ASMC_DPRINTF(("data port: key\n"));
1941 	for (i = 0; i < 4; i++) {
1942 		ASMC_DATAPORT_WRITE(sc, key[i]);
1943 		if (asmc_wait(dev, 0x04))
1944 			goto out;
1945 	}
1946 	ASMC_DPRINTF(("data port: length\n"));
1947 	ASMC_DATAPORT_WRITE(sc, len);
1948 
1949 	ASMC_DPRINTF(("data port: buffer\n"));
1950 	for (i = 0; i < len; i++) {
1951 		if (asmc_wait(dev, 0x04))
1952 			goto out;
1953 		ASMC_DATAPORT_WRITE(sc, buf[i]);
1954 	}
1955 
1956 	error = 0;
1957 out:
1958 	if (error) {
1959 		if (++try < 10)
1960 			goto begin;
1961 		device_printf(dev, "%s for key %s failed %d times, giving up\n",
1962 		    __func__, key, try);
1963 	}
1964 
1965 	mtx_unlock_spin(&sc->sc_mtx);
1966 
1967 	return (error);
1968 }
1969 
1970 /*
1971  * Fan control functions.
1972  */
1973 static int
1974 asmc_fan_count(device_t dev)
1975 {
1976 	uint8_t buf[1];
1977 
1978 	if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0)
1979 		return (-1);
1980 
1981 	return (buf[0]);
1982 }
1983 
1984 static int
1985 asmc_fan_getvalue(device_t dev, const char *key, int fan)
1986 {
1987 	struct asmc_softc *sc = device_get_softc(dev);
1988 	int speed;
1989 	uint8_t buf[4];
1990 	char fankey[5];
1991 	char type[ASMC_TYPELEN + 1];
1992 
1993 	snprintf(fankey, sizeof(fankey), key, fan);
1994 
1995 	/*
1996 	 * T2 Macs use IEEE 754 float ("flt ") for fan speeds,
1997 	 * stored little-endian in the MMIO data register.
1998 	 * Standard Macs use s14.2 fixed-point ("fpe2", 2 bytes).
1999 	 */
2000 	if (sc->sc_is_t2 &&
2001 	    asmc_key_getinfo(dev, fankey, NULL, type) == 0 &&
2002 	    strncmp(type, "flt ", 4) == 0) {
2003 		if (asmc_key_read(dev, fankey, buf, 4) != 0)
2004 			return (-1);
2005 		speed = (int)asmc_float_to_u32(le32dec(buf));
2006 	} else {
2007 		if (asmc_key_read(dev, fankey, buf, 2) != 0)
2008 			return (-1);
2009 		speed = (buf[0] << 6) | (buf[1] >> 2);
2010 	}
2011 
2012 	return (speed);
2013 }
2014 
2015 static char *
2016 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf,
2017     uint8_t buflen)
2018 {
2019 	char fankey[5];
2020 	char *desc;
2021 
2022 	snprintf(fankey, sizeof(fankey), key, fan);
2023 	if (asmc_key_read(dev, fankey, buf, buflen) != 0)
2024 		return (NULL);
2025 	desc = buf + 4;
2026 
2027 	return (desc);
2028 }
2029 
2030 static int
2031 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
2032 {
2033 	struct asmc_softc *sc = device_get_softc(dev);
2034 	uint8_t buf[4];
2035 	char fankey[5];
2036 	char type[ASMC_TYPELEN + 1];
2037 
2038 	snprintf(fankey, sizeof(fankey), key, fan);
2039 
2040 	if (sc->sc_is_t2 &&
2041 	    asmc_key_getinfo(dev, fankey, NULL, type) == 0 &&
2042 	    strncmp(type, "flt ", 4) == 0) {
2043 		uint32_t fval;
2044 		speed = MAX(speed, 0);
2045 		speed = MIN(speed, 65535);
2046 		fval = asmc_u32_to_float((uint32_t)speed);
2047 		le32enc(buf, fval);
2048 		if (asmc_key_write(dev, fankey, buf, 4) != 0)
2049 			return (-1);
2050 	} else {
2051 		speed *= 4;
2052 		buf[0] = speed >> 8;
2053 		buf[1] = speed;
2054 		if (asmc_key_write(dev, fankey, buf, 2) != 0)
2055 			return (-1);
2056 	}
2057 
2058 	return (0);
2059 }
2060 
2061 static int
2062 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
2063 {
2064 	device_t dev = (device_t)arg1;
2065 	int fan = arg2;
2066 	int error;
2067 	int32_t v;
2068 
2069 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
2070 	error = sysctl_handle_int(oidp, &v, 0, req);
2071 
2072 	return (error);
2073 }
2074 
2075 static int
2076 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
2077 {
2078 	uint8_t buf[16];
2079 	device_t dev = (device_t)arg1;
2080 	int fan = arg2;
2081 	int error = true;
2082 	char *desc;
2083 
2084 	desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
2085 
2086 	if (desc != NULL)
2087 		error = sysctl_handle_string(oidp, desc, 0, req);
2088 
2089 	return (error);
2090 }
2091 
2092 static int
2093 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
2094 {
2095 	device_t dev = (device_t)arg1;
2096 	int fan = arg2;
2097 	int error;
2098 	int32_t v;
2099 
2100 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
2101 	error = sysctl_handle_int(oidp, &v, 0, req);
2102 
2103 	return (error);
2104 }
2105 
2106 static int
2107 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
2108 {
2109 	device_t dev = (device_t)arg1;
2110 	int fan = arg2;
2111 	int error;
2112 	int32_t v;
2113 
2114 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
2115 	error = sysctl_handle_int(oidp, &v, 0, req);
2116 
2117 	if (error == 0 && req->newptr != NULL) {
2118 		unsigned int newspeed = v;
2119 		asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed);
2120 	}
2121 
2122 	return (error);
2123 }
2124 
2125 static int
2126 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
2127 {
2128 	device_t dev = (device_t)arg1;
2129 	int fan = arg2;
2130 	int error;
2131 	int32_t v;
2132 
2133 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
2134 	error = sysctl_handle_int(oidp, &v, 0, req);
2135 
2136 	if (error == 0 && req->newptr != NULL) {
2137 		unsigned int newspeed = v;
2138 		asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed);
2139 	}
2140 
2141 	return (error);
2142 }
2143 
2144 static int
2145 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
2146 {
2147 	device_t dev = (device_t)arg1;
2148 	int fan = arg2;
2149 	int error;
2150 	int32_t v;
2151 
2152 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
2153 	error = sysctl_handle_int(oidp, &v, 0, req);
2154 
2155 	if (error == 0 && req->newptr != NULL) {
2156 		unsigned int newspeed = v;
2157 		asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed);
2158 	}
2159 
2160 	return (error);
2161 }
2162 
2163 static int
2164 asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS)
2165 {
2166 	device_t dev = (device_t)arg1;
2167 	struct asmc_softc *sc = device_get_softc(dev);
2168 	int fan = arg2;
2169 	int error;
2170 	int32_t v;
2171 	uint8_t buf[2];
2172 	uint16_t val;
2173 	char fmkey[5];
2174 
2175 	/*
2176 	 * T2 Macs use per-fan F%dMd keys (1 byte each).
2177 	 * Standard Macs use FS! bitmask (2 bytes).
2178 	 */
2179 	snprintf(fmkey, sizeof(fmkey), ASMC_KEY_FANMANUAL_T2, fan);
2180 	if (sc->sc_is_t2 &&
2181 	    asmc_key_getinfo(dev, fmkey, NULL, NULL) == 0) {
2182 		error = asmc_key_read(dev, fmkey, buf, 1);
2183 		if (error != 0)
2184 			return (error);
2185 		v = buf[0] ? 1 : 0;
2186 
2187 		error = sysctl_handle_int(oidp, &v, 0, req);
2188 		if (error == 0 && req->newptr != NULL) {
2189 			if (v != 0 && v != 1)
2190 				return (EINVAL);
2191 			buf[0] = (uint8_t)v;
2192 			error = asmc_key_write(dev, fmkey, buf, 1);
2193 		}
2194 		return (error);
2195 	}
2196 
2197 	/* Read current FS! bitmask (asmc_key_read locks internally) */
2198 	error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf));
2199 	if (error != 0)
2200 		return (error);
2201 
2202 	/* Extract manual bit for this fan (big-endian) */
2203 	val = (buf[0] << 8) | buf[1];
2204 	v = (val >> fan) & 0x01;
2205 
2206 	/* Let sysctl handle the value */
2207 	error = sysctl_handle_int(oidp, &v, 0, req);
2208 
2209 	if (error == 0 && req->newptr != NULL) {
2210 		/* Validate input (0 = auto, 1 = manual) */
2211 		if (v != 0 && v != 1)
2212 			return (EINVAL);
2213 		/* Read-modify-write of FS! bitmask */
2214 		error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf,
2215 		    sizeof(buf));
2216 		if (error == 0) {
2217 			val = (buf[0] << 8) | buf[1];
2218 
2219 			/* Modify single bit */
2220 			if (v)
2221 				val |= (1 << fan);   /* Set to manual */
2222 			else
2223 				val &= ~(1 << fan);  /* Set to auto */
2224 
2225 			/* Write back */
2226 			buf[0] = val >> 8;
2227 			buf[1] = val & 0xff;
2228 			error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf,
2229 			    sizeof(buf));
2230 		}
2231 	}
2232 
2233 	return (error);
2234 }
2235 
2236 /*
2237  * Temperature functions.
2238  */
2239 static int
2240 asmc_temp_getvalue(device_t dev, const char *key)
2241 {
2242 	uint8_t buf[2];
2243 
2244 	/*
2245 	 * Check for invalid temperatures.
2246 	 */
2247 	if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0)
2248 		return (-1);
2249 
2250 	return (buf[0]);
2251 }
2252 
2253 static int
2254 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
2255 {
2256 	device_t dev = (device_t)arg1;
2257 	struct asmc_softc *sc = device_get_softc(dev);
2258 	int error, val;
2259 
2260 	if (arg2 < 0 || arg2 >= sc->sc_temp_count)
2261 		return (EINVAL);
2262 
2263 	val = asmc_temp_getvalue(dev, sc->sc_temp_sensors[arg2]);
2264 	error = sysctl_handle_int(oidp, &val, 0, req);
2265 
2266 	return (error);
2267 }
2268 
2269 /*
2270  * Sudden Motion Sensor functions.
2271  */
2272 static int
2273 asmc_sms_read(device_t dev, const char *key, int16_t *val)
2274 {
2275 	uint8_t buf[2];
2276 	int error;
2277 
2278 	/* no need to do locking here as asmc_key_read() already does it */
2279 	switch (key[3]) {
2280 	case 'X':
2281 	case 'Y':
2282 	case 'Z':
2283 		error = asmc_key_read(dev, key, buf, sizeof(buf));
2284 		break;
2285 	default:
2286 		device_printf(dev, "%s called with invalid argument %s\n",
2287 		    __func__, key);
2288 		error = EINVAL;
2289 		goto out;
2290 	}
2291 	*val = ((int16_t)buf[0] << 8) | buf[1];
2292 out:
2293 	return (error);
2294 }
2295 
2296 static void
2297 asmc_sms_calibrate(device_t dev)
2298 {
2299 	struct asmc_softc *sc = device_get_softc(dev);
2300 
2301 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
2302 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
2303 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
2304 }
2305 
2306 static int
2307 asmc_sms_intrfast(void *arg)
2308 {
2309 	uint8_t type;
2310 	device_t dev = (device_t)arg;
2311 	struct asmc_softc *sc = device_get_softc(dev);
2312 	if (!sc->sc_sms_intr_works)
2313 		return (FILTER_HANDLED);
2314 
2315 	mtx_lock_spin(&sc->sc_mtx);
2316 	type = ASMC_INTPORT_READ(sc);
2317 	mtx_unlock_spin(&sc->sc_mtx);
2318 
2319 	sc->sc_sms_intrtype = type;
2320 	asmc_sms_printintr(dev, type);
2321 
2322 	/* Don't queue SMS task for ambient light interrupts */
2323 	if (type == ASMC_ALSL_INT2A && sc->sc_has_alsl)
2324 		return (FILTER_HANDLED);
2325 
2326 	taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
2327 	return (FILTER_HANDLED);
2328 }
2329 
2330 static void
2331 asmc_sms_printintr(device_t dev, uint8_t type)
2332 {
2333 	struct asmc_softc *sc = device_get_softc(dev);
2334 
2335 	switch (type) {
2336 	case ASMC_SMS_INTFF:
2337 		device_printf(dev, "WARNING: possible free fall!\n");
2338 		break;
2339 	case ASMC_SMS_INTHA:
2340 		device_printf(dev, "WARNING: high acceleration detected!\n");
2341 		break;
2342 	case ASMC_SMS_INTSH:
2343 		device_printf(dev, "WARNING: possible shock!\n");
2344 		break;
2345 	case ASMC_ALSL_INT2A:
2346 		/*
2347 		 * This suppresses console and log messages for the ambient
2348 		 * light sensor interrupt on models that have ALSL.
2349 		 */
2350 		if (sc->sc_has_alsl)
2351 			break;
2352 		/* FALLTHROUGH */
2353 	default:
2354 		device_printf(dev, "unknown interrupt: 0x%x\n", type);
2355 	}
2356 }
2357 
2358 static void
2359 asmc_sms_task(void *arg, int pending)
2360 {
2361 	struct asmc_softc *sc = (struct asmc_softc *)arg;
2362 	char notify[16];
2363 	int type;
2364 
2365 	switch (sc->sc_sms_intrtype) {
2366 	case ASMC_SMS_INTFF:
2367 		type = 2;
2368 		break;
2369 	case ASMC_SMS_INTHA:
2370 		type = 1;
2371 		break;
2372 	case ASMC_SMS_INTSH:
2373 		type = 0;
2374 		break;
2375 	default:
2376 		type = 255;
2377 	}
2378 
2379 	snprintf(notify, sizeof(notify), " notify=0x%x", type);
2380 	devctl_notify("ACPI", "asmc", "SMS", notify);
2381 }
2382 
2383 static int
2384 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
2385 {
2386 	device_t dev = (device_t)arg1;
2387 	int error;
2388 	int16_t val;
2389 	int32_t v;
2390 
2391 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
2392 	v = (int32_t)val;
2393 	error = sysctl_handle_int(oidp, &v, 0, req);
2394 
2395 	return (error);
2396 }
2397 
2398 static int
2399 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
2400 {
2401 	device_t dev = (device_t)arg1;
2402 	int error;
2403 	int16_t val;
2404 	int32_t v;
2405 
2406 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
2407 	v = (int32_t)val;
2408 	error = sysctl_handle_int(oidp, &v, 0, req);
2409 
2410 	return (error);
2411 }
2412 
2413 static int
2414 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
2415 {
2416 	device_t dev = (device_t)arg1;
2417 	int error;
2418 	int16_t val;
2419 	int32_t v;
2420 
2421 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
2422 	v = (int32_t)val;
2423 	error = sysctl_handle_int(oidp, &v, 0, req);
2424 
2425 	return (error);
2426 }
2427 
2428 static int
2429 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
2430 {
2431 	device_t dev = (device_t)arg1;
2432 	uint8_t buf[6];
2433 	int error;
2434 	int32_t v;
2435 
2436 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
2437 	v = buf[2];
2438 	error = sysctl_handle_int(oidp, &v, 0, req);
2439 
2440 	return (error);
2441 }
2442 
2443 static int
2444 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
2445 {
2446 	device_t dev = (device_t)arg1;
2447 	uint8_t buf[6];
2448 	int error;
2449 	int32_t v;
2450 
2451 	asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf));
2452 	v = buf[2];
2453 	error = sysctl_handle_int(oidp, &v, 0, req);
2454 
2455 	return (error);
2456 }
2457 
2458 static int
2459 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
2460 {
2461 	device_t dev = (device_t)arg1;
2462 	struct asmc_softc *sc = device_get_softc(dev);
2463 	uint8_t buf[2];
2464 	int error;
2465 	int v;
2466 
2467 	v = light_control;
2468 	error = sysctl_handle_int(oidp, &v, 0, req);
2469 
2470 	if (error == 0 && req->newptr != NULL) {
2471 		if (v < 0 || v > 255)
2472 			return (EINVAL);
2473 		light_control = v;
2474 		sc->sc_kbd_bkl_level = v * 100 / 255;
2475 		buf[0] = light_control;
2476 		buf[1] = 0x00;
2477 		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
2478 	}
2479 	return (error);
2480 }
2481 
2482 static int
2483 asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
2484 {
2485 	device_t dev = (device_t)arg1;
2486 	uint8_t buf[10];
2487 	int error;
2488 	uint32_t v;
2489 
2490 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
2491 
2492 	/*
2493 	 * This seems to be a 32 bit big endian value from buf[6] -> buf[9].
2494 	 *
2495 	 * Extract it out manually here, then shift/clamp it.
2496 	 */
2497 	v = be32dec(&buf[6]);
2498 
2499 	/*
2500 	 * Shift out, clamp at 255; that way it looks like the
2501 	 * earlier SMC firmware version responses.
2502 	 */
2503 	v = v >> 8;
2504 	if (v > 255)
2505 		v = 255;
2506 
2507 	error = sysctl_handle_int(oidp, &v, 0, req);
2508 
2509 	return (error);
2510 }
2511 
2512 /*
2513  * Auto power-on after AC power loss (AUPO key).
2514  * When non-zero the machine boots automatically when AC is restored
2515  * after an unclean power loss.  Useful for always-on servers / home labs.
2516  */
2517 static int
2518 asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS)
2519 {
2520 	device_t dev = (device_t)arg1;
2521 	uint8_t aupo;
2522 	int val, error;
2523 
2524 	if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
2525 		return (EIO);
2526 
2527 	val = (aupo != 0) ? 1 : 0;
2528 	error = sysctl_handle_int(oidp, &val, 0, req);
2529 	if (error != 0 || req->newptr == NULL)
2530 		return (error);
2531 
2532 	aupo = (val != 0) ? 1 : 0;
2533 	if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
2534 		return (EIO);
2535 
2536 	return (0);
2537 }
2538 
2539 static int
2540 asmc_backlight_update_status(device_t dev, struct backlight_props *props)
2541 {
2542 	struct asmc_softc *sc = device_get_softc(dev);
2543 	uint8_t buf[2];
2544 
2545 	sc->sc_kbd_bkl_level = props->brightness;
2546 	light_control = props->brightness * 255 / 100;
2547 	buf[0] = light_control;
2548 	buf[1] = 0x00;
2549 	asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
2550 
2551 	return (0);
2552 }
2553 
2554 static int
2555 asmc_backlight_get_status(device_t dev, struct backlight_props *props)
2556 {
2557 	struct asmc_softc *sc = device_get_softc(dev);
2558 
2559 	props->brightness = sc->sc_kbd_bkl_level;
2560 	props->nlevels = 0;
2561 
2562 	return (0);
2563 }
2564 
2565 static int
2566 asmc_backlight_get_info(device_t dev, struct backlight_info *info)
2567 {
2568 	info->type = BACKLIGHT_TYPE_KEYBOARD;
2569 	strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH);
2570 
2571 	return (0);
2572 }
2573 
2574 static const char *
2575 asmc_cause_str(int8_t cause, bool is_sleep)
2576 {
2577 	size_t i;
2578 
2579 	for (i = 0; i < nitems(asmc_cause_table); i++) {
2580 		if (asmc_cause_table[i].code != cause)
2581 			continue;
2582 		if (is_sleep && asmc_cause_table[i].sleep_desc != NULL)
2583 			return (asmc_cause_table[i].sleep_desc);
2584 		return (asmc_cause_table[i].desc);
2585 	}
2586 	return (NULL);
2587 }
2588 
2589 /* MSSD/MSSP: last shutdown/sleep cause.  arg2: 0=shutdown, 1=sleep. */
2590 static int
2591 asmc_cause_sysctl(SYSCTL_HANDLER_ARGS)
2592 {
2593 	device_t dev = (device_t)arg1;
2594 	bool is_sleep = (arg2 != 0);
2595 	const char *key = is_sleep ? ASMC_KEY_MSSP : ASMC_KEY_MSSD;
2596 	int8_t cause;
2597 	const char *desc;
2598 	char buf[ASMC_CAUSE_BUFLEN];
2599 
2600 	/* EIO: SMC I/O bus did not respond to key read. */
2601 	if (asmc_key_read(dev, key, (uint8_t *)&cause, 1) != 0)
2602 		return (EIO);
2603 
2604 	desc = asmc_cause_str(cause, is_sleep);
2605 	if (desc != NULL)
2606 		snprintf(buf, sizeof(buf), "%d (%s)", (int)cause, desc);
2607 	else
2608 		snprintf(buf, sizeof(buf), "%d", (int)cause);
2609 
2610 	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
2611 }
2612 
2613 static int
2614 asmc_msal_sysctl(SYSCTL_HANDLER_ARGS)
2615 {
2616 	device_t dev = (device_t)arg1;
2617 	uint8_t msal;
2618 	char buf[80];
2619 
2620 	/* EIO: SMC I/O bus did not respond to key read. */
2621 	if (asmc_key_read(dev, ASMC_KEY_MSAL, &msal, 1) != 0)
2622 		return (EIO);
2623 
2624 	snprintf(buf, sizeof(buf),
2625 	    "0x%02x (tss=%d therm_valid=%d calib_valid=%d prochot=%d plimits=%d)",
2626 	    msal,
2627 	    (msal & ASMC_MSAL_TSS) != 0,
2628 	    (msal & ASMC_MSAL_THERM_VALID) != 0,
2629 	    (msal & ASMC_MSAL_CALIB_VALID) != 0,
2630 	    (msal & ASMC_MSAL_PROCHOT) != 0,
2631 	    (msal & ASMC_MSAL_PLIMITS) != 0);
2632 
2633 	return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
2634 }
2635 
2636 static int
2637 asmc_clkt_sysctl(SYSCTL_HANDLER_ARGS)
2638 {
2639 	device_t dev = (device_t)arg1;
2640 	uint8_t buf[4];
2641 	uint32_t secs;
2642 
2643 	if (asmc_key_read(dev, ASMC_KEY_CLKT, buf, 4) != 0)
2644 		return (EIO);
2645 
2646 	secs = be32dec(buf);
2647 	return (sysctl_handle_32(oidp, &secs, 0, req));
2648 }
2649 
2650 static int
2651 asmc_msps_sysctl(SYSCTL_HANDLER_ARGS)
2652 {
2653 	device_t dev = (device_t)arg1;
2654 	uint8_t buf[2], len;
2655 	uint32_t state;
2656 
2657 	if (asmc_key_getinfo(dev, ASMC_KEY_MSPS, &len, NULL) != 0)
2658 		return (EIO);
2659 	if (len != 1 && len != 2)
2660 		return (EIO);
2661 
2662 	memset(buf, 0, sizeof(buf));
2663 	if (asmc_key_read(dev, ASMC_KEY_MSPS, buf, len) != 0)
2664 		return (EIO);
2665 
2666 	state = (len == 1) ? buf[0] : be16dec(buf);
2667 	return (sysctl_handle_32(oidp, &state, 0, req));
2668 }
2669 
2670 static int
2671 asmc_rplt_sysctl(SYSCTL_HANDLER_ARGS)
2672 {
2673 	device_t dev = (device_t)arg1;
2674 	uint8_t buf[ASMC_RPLT_MAXLEN + 1];
2675 	char name[ASMC_RPLT_MAXLEN + 1];
2676 
2677 	memset(buf, 0, sizeof(buf));
2678 	if (asmc_key_read(dev, ASMC_KEY_RPLT, buf, ASMC_RPLT_MAXLEN) != 0)
2679 		return (EIO);
2680 
2681 	memcpy(name, buf, ASMC_RPLT_MAXLEN);
2682 	name[ASMC_RPLT_MAXLEN] = '\0';
2683 
2684 	return (sysctl_handle_string(oidp, name, sizeof(name), req));
2685 }
2686 
2687 static int
2688 asmc_rgen_sysctl(SYSCTL_HANDLER_ARGS)
2689 {
2690 	device_t dev = (device_t)arg1;
2691 	uint8_t gen;
2692 	uint32_t val;
2693 
2694 	if (asmc_key_read(dev, ASMC_KEY_RGEN, &gen, 1) != 0)
2695 		return (EIO);
2696 
2697 	val = gen;
2698 	return (sysctl_handle_32(oidp, &val, 0, req));
2699 }
2700