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