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