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