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
61 /*
62 * Device interface.
63 */
64 static int asmc_probe(device_t dev);
65 static int asmc_attach(device_t dev);
66 static int asmc_detach(device_t dev);
67 static int asmc_resume(device_t dev);
68
69 /*
70 * SMC functions.
71 */
72 static int asmc_init(device_t dev);
73 static int asmc_command(device_t dev, uint8_t command);
74 static int asmc_wait(device_t dev, uint8_t val);
75 static int asmc_wait_ack(device_t dev, uint8_t val, int amount);
76 static int asmc_key_write(device_t dev, const char *key, uint8_t *buf,
77 uint8_t len);
78 static int asmc_key_read(device_t dev, const char *key, uint8_t *buf,
79 uint8_t);
80 static int asmc_fan_count(device_t dev);
81 static int asmc_fan_getvalue(device_t dev, const char *key, int fan);
82 static int asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
83 static int asmc_temp_getvalue(device_t dev, const char *key);
84 static int asmc_sms_read(device_t, const char *key, int16_t *val);
85 static void asmc_sms_calibrate(device_t dev);
86 static int asmc_sms_intrfast(void *arg);
87 static void asmc_sms_printintr(device_t dev, uint8_t);
88 static void asmc_sms_task(void *arg, int pending);
89 #ifdef ASMC_DEBUG
90 void asmc_dumpall(device_t);
91 static int asmc_key_dump(device_t, int);
92 #endif
93
94 /*
95 * Model functions.
96 */
97 static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
98 static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
99 static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
100 static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
101 static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
102 static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
103 static int asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS);
104 static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
105 static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
106 static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
107 static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
108 static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
109 static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
110 static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
111 static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS);
112 static int asmc_wol_sysctl(SYSCTL_HANDLER_ARGS);
113
114 struct asmc_model {
115 const char *smc_model; /* smbios.system.product env var. */
116 const char *smc_desc; /* driver description */
117
118 /* Helper functions */
119 int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
120 int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
121 int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
122 int (*smc_fan_id)(SYSCTL_HANDLER_ARGS);
123 int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
124 int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
125 int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
126 int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
127 int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
128 int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
129 int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
130 int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
131
132 const char *smc_temps[ASMC_TEMP_MAX];
133 const char *smc_tempnames[ASMC_TEMP_MAX];
134 const char *smc_tempdescs[ASMC_TEMP_MAX];
135 };
136
137 static const struct asmc_model *asmc_match(device_t dev);
138
139 #define ASMC_SMS_FUNCS \
140 .smc_sms_x = asmc_mb_sysctl_sms_x, \
141 .smc_sms_y = asmc_mb_sysctl_sms_y, \
142 .smc_sms_z = asmc_mb_sysctl_sms_z
143
144 #define ASMC_SMS_FUNCS_DISABLED \
145 .smc_sms_x = NULL, \
146 .smc_sms_y = NULL, \
147 .smc_sms_z = NULL
148
149 #define ASMC_FAN_FUNCS \
150 .smc_fan_id = asmc_mb_sysctl_fanid, \
151 .smc_fan_speed = asmc_mb_sysctl_fanspeed, \
152 .smc_fan_safespeed = asmc_mb_sysctl_fansafespeed, \
153 .smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \
154 .smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \
155 .smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed
156
157 #define ASMC_FAN_FUNCS2 \
158 .smc_fan_id = asmc_mb_sysctl_fanid, \
159 .smc_fan_speed = asmc_mb_sysctl_fanspeed, \
160 .smc_fan_safespeed = NULL, \
161 .smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \
162 .smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \
163 .smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed
164
165 #define ASMC_LIGHT_FUNCS \
166 .smc_light_left = asmc_mbp_sysctl_light_left, \
167 .smc_light_right = asmc_mbp_sysctl_light_right, \
168 .smc_light_control = asmc_mbp_sysctl_light_control
169
170 #define ASMC_LIGHT_FUNCS_10BYTE \
171 .smc_light_left = asmc_mbp_sysctl_light_left_10byte, \
172 .smc_light_right = NULL, \
173 .smc_light_control = asmc_mbp_sysctl_light_control
174
175 #define ASMC_LIGHT_FUNCS_DISABLED \
176 .smc_light_left = NULL, \
177 .smc_light_right = NULL, \
178 .smc_light_control = NULL
179
180 #define ASMC_TEMPS_FUNCS_DISABLED \
181 .smc_temps = {}, \
182 .smc_tempnames = {}, \
183 .smc_tempdescs = {} \
184
185 static const struct asmc_model asmc_models[] = {
186 {
187 "MacBook1,1", "Apple SMC MacBook Core Duo",
188 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
189 ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
190 },
191
192 {
193 "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
194 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
195 ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
196 },
197
198 {
199 "MacBook3,1", "Apple SMC MacBook Core 2 Duo",
200 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
201 ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS
202 },
203
204 {
205 "MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)",
206 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED,
207 ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS
208 },
209
210 {
211 "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
212 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
213 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
214 },
215
216 {
217 "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
218 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
219 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
220 },
221
222 {
223 "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
224 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
225 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
226 },
227
228 {
229 "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
230 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
231 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
232 },
233
234 {
235 "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
236 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
237 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
238 },
239
240 {
241 "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
242 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
243 ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
244 },
245
246 {
247 "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
248 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
249 ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
250 },
251
252 {
253 "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)",
254 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
255 ASMC_MBP51_TEMPS, ASMC_MBP51_TEMPNAMES, ASMC_MBP51_TEMPDESCS
256 },
257
258 {
259 "MacBookPro5,5", "Apple SMC MacBook Pro Core 2 Duo (Mid 2009)",
260 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
261 ASMC_MBP55_TEMPS, ASMC_MBP55_TEMPNAMES, ASMC_MBP55_TEMPDESCS
262 },
263
264 {
265 "MacBookPro6,2", "Apple SMC MacBook Pro (Mid 2010, 15-inch)",
266 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
267 ASMC_MBP62_TEMPS, ASMC_MBP62_TEMPNAMES, ASMC_MBP62_TEMPDESCS
268 },
269
270 {
271 "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)",
272 ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
273 ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS
274 },
275
276 {
277 "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)",
278 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
279 ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS
280 },
281
282 {
283 "MacBookPro8,3", "Apple SMC MacBook Pro (early 2011, 17-inch)",
284 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
285 ASMC_MBP83_TEMPS, ASMC_MBP83_TEMPNAMES, ASMC_MBP83_TEMPDESCS
286 },
287
288 {
289 "MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)",
290 ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
291 ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS
292 },
293
294 {
295 "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012, 13-inch)",
296 ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
297 ASMC_MBP92_TEMPS, ASMC_MBP92_TEMPNAMES, ASMC_MBP92_TEMPDESCS
298 },
299
300 {
301 "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
302 ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
303 ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS
304 },
305
306 {
307 "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
308 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
309 ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS
310 },
311
312 {
313 "MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)",
314 ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
315 ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS
316 },
317
318 {
319 "MacBookPro11,5",
320 "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch, AMD GPU)",
321 ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
322 ASMC_MBP115_TEMPS, ASMC_MBP115_TEMPNAMES, ASMC_MBP115_TEMPDESCS
323 },
324
325 /* The Mac Mini has no SMS */
326 {
327 "Macmini1,1", "Apple SMC Mac Mini",
328 ASMC_SMS_FUNCS_DISABLED,
329 ASMC_FAN_FUNCS,
330 ASMC_LIGHT_FUNCS_DISABLED,
331 ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
332 },
333
334 /* The Mac Mini 2,1 has no SMS */
335 {
336 "Macmini2,1", "Apple SMC Mac Mini 2,1",
337 ASMC_SMS_FUNCS_DISABLED,
338 ASMC_FAN_FUNCS,
339 ASMC_LIGHT_FUNCS_DISABLED,
340 ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS
341 },
342
343 /* The Mac Mini 3,1 has no SMS */
344 {
345 "Macmini3,1", "Apple SMC Mac Mini 3,1",
346 ASMC_SMS_FUNCS_DISABLED,
347 ASMC_FAN_FUNCS,
348 ASMC_LIGHT_FUNCS_DISABLED,
349 ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS
350 },
351
352 /* The Mac Mini 4,1 (Mid-2010) has no SMS */
353 {
354 "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)",
355 ASMC_SMS_FUNCS_DISABLED,
356 ASMC_FAN_FUNCS2,
357 ASMC_LIGHT_FUNCS_DISABLED,
358 ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS
359 },
360
361 /* The Mac Mini 5,1 has no SMS */
362 /* - same sensors as Mac Mini 5,2 */
363 {
364 "Macmini5,1", "Apple SMC Mac Mini 5,1",
365 ASMC_SMS_FUNCS_DISABLED,
366 ASMC_FAN_FUNCS2,
367 ASMC_LIGHT_FUNCS_DISABLED,
368 ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
369 },
370
371 /* The Mac Mini 5,2 has no SMS */
372 {
373 "Macmini5,2", "Apple SMC Mac Mini 5,2",
374 ASMC_SMS_FUNCS_DISABLED,
375 ASMC_FAN_FUNCS2,
376 ASMC_LIGHT_FUNCS_DISABLED,
377 ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
378 },
379
380 /* The Mac Mini 5,3 has no SMS */
381 /* - same sensors as Mac Mini 5,2 */
382 {
383 "Macmini5,3", "Apple SMC Mac Mini 5,3",
384 ASMC_SMS_FUNCS_DISABLED,
385 ASMC_FAN_FUNCS2,
386 ASMC_LIGHT_FUNCS_DISABLED,
387 ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
388 },
389
390 /* The Mac Mini 6,1 has no SMS */
391 {
392 "Macmini6,1", "Apple SMC Mac Mini 6,1",
393 ASMC_SMS_FUNCS_DISABLED,
394 ASMC_FAN_FUNCS2,
395 ASMC_LIGHT_FUNCS_DISABLED,
396 ASMC_MM61_TEMPS, ASMC_MM61_TEMPNAMES, ASMC_MM61_TEMPDESCS
397 },
398
399 /* The Mac Mini 6,2 has no SMS */
400 {
401 "Macmini6,2", "Apple SMC Mac Mini 6,2",
402 ASMC_SMS_FUNCS_DISABLED,
403 ASMC_FAN_FUNCS2,
404 ASMC_LIGHT_FUNCS_DISABLED,
405 ASMC_MM62_TEMPS, ASMC_MM62_TEMPNAMES, ASMC_MM62_TEMPDESCS
406 },
407
408 /* The Mac Mini 7,1 has no SMS */
409 {
410 "Macmini7,1", "Apple SMC Mac Mini 7,1",
411 ASMC_SMS_FUNCS_DISABLED,
412 ASMC_FAN_FUNCS2,
413 ASMC_LIGHT_FUNCS_DISABLED,
414 ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS
415 },
416
417 /* Idem for the Mac Pro "Quad Core" (original) */
418 {
419 "MacPro1,1", "Apple SMC Mac Pro (Quad Core)",
420 ASMC_SMS_FUNCS_DISABLED,
421 ASMC_FAN_FUNCS,
422 ASMC_LIGHT_FUNCS_DISABLED,
423 ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS
424 },
425
426 /* Idem for the Mac Pro (Early 2008) */
427 {
428 "MacPro3,1", "Apple SMC Mac Pro (Early 2008)",
429 ASMC_SMS_FUNCS_DISABLED,
430 ASMC_FAN_FUNCS,
431 ASMC_LIGHT_FUNCS_DISABLED,
432 ASMC_MP31_TEMPS, ASMC_MP31_TEMPNAMES, ASMC_MP31_TEMPDESCS
433 },
434
435 /* Idem for the Mac Pro (8-core) */
436 {
437 "MacPro2", "Apple SMC Mac Pro (8-core)",
438 ASMC_SMS_FUNCS_DISABLED,
439 ASMC_FAN_FUNCS,
440 ASMC_LIGHT_FUNCS_DISABLED,
441 ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS
442 },
443
444 /* Idem for the MacPro 2010*/
445 {
446 "MacPro5,1", "Apple SMC MacPro (2010)",
447 ASMC_SMS_FUNCS_DISABLED,
448 ASMC_FAN_FUNCS,
449 ASMC_LIGHT_FUNCS_DISABLED,
450 ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS
451 },
452
453 /* Idem for the Mac Pro 2013 (cylinder) */
454 {
455 "MacPro6,1", "Apple SMC Mac Pro (2013)",
456 ASMC_SMS_FUNCS_DISABLED,
457 ASMC_FAN_FUNCS2,
458 ASMC_LIGHT_FUNCS_DISABLED,
459 ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS
460 },
461
462 {
463 "MacBookAir1,1", "Apple SMC MacBook Air",
464 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
465 ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
466 },
467
468 {
469 "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)",
470 ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
471 ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS
472 },
473
474 {
475 "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)",
476 ASMC_SMS_FUNCS_DISABLED,
477 ASMC_FAN_FUNCS2,
478 ASMC_LIGHT_FUNCS,
479 ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
480 },
481
482 {
483 "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)",
484 ASMC_SMS_FUNCS_DISABLED,
485 ASMC_FAN_FUNCS2,
486 ASMC_LIGHT_FUNCS,
487 ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
488 },
489
490 {
491 "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)",
492 ASMC_SMS_FUNCS_DISABLED,
493 ASMC_FAN_FUNCS2,
494 ASMC_LIGHT_FUNCS,
495 ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
496 },
497
498 {
499 "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)",
500 ASMC_SMS_FUNCS_DISABLED,
501 ASMC_FAN_FUNCS2,
502 ASMC_LIGHT_FUNCS,
503 ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
504 },
505 {
506 "MacBookAir6,1", "Apple SMC MacBook Air 11-inch (Early 2013)",
507 ASMC_SMS_FUNCS_DISABLED,
508 ASMC_FAN_FUNCS2,
509 ASMC_LIGHT_FUNCS_10BYTE,
510 ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
511 },
512 {
513 "MacBookAir6,2", "Apple SMC MacBook Air 13-inch (Early 2013)",
514 ASMC_SMS_FUNCS_DISABLED,
515 ASMC_FAN_FUNCS2,
516 ASMC_LIGHT_FUNCS_10BYTE,
517 ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
518 },
519 {
520 "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)",
521 ASMC_SMS_FUNCS_DISABLED,
522 ASMC_FAN_FUNCS2,
523 ASMC_LIGHT_FUNCS,
524 ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
525 },
526 {
527 "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)",
528 ASMC_SMS_FUNCS_DISABLED,
529 ASMC_FAN_FUNCS2,
530 ASMC_LIGHT_FUNCS,
531 ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
532 }
533 };
534
535 static const struct asmc_model asmc_generic_models[] = {
536 {
537 .smc_model = "MacBookAir",
538 .smc_desc = NULL,
539 ASMC_SMS_FUNCS_DISABLED,
540 ASMC_FAN_FUNCS2,
541 ASMC_LIGHT_FUNCS,
542 ASMC_TEMPS_FUNCS_DISABLED
543 },
544 {
545 .smc_model = "MacBookPro",
546 .smc_desc = NULL,
547 ASMC_SMS_FUNCS_DISABLED,
548 ASMC_FAN_FUNCS2,
549 ASMC_LIGHT_FUNCS,
550 ASMC_TEMPS_FUNCS_DISABLED
551 },
552 {
553 .smc_model = "MacPro",
554 .smc_desc = NULL,
555 ASMC_SMS_FUNCS_DISABLED,
556 ASMC_FAN_FUNCS2,
557 ASMC_LIGHT_FUNCS_DISABLED,
558 ASMC_TEMPS_FUNCS_DISABLED
559 },
560 {
561 .smc_model = "Macmini",
562 .smc_desc = NULL,
563 ASMC_SMS_FUNCS_DISABLED,
564 ASMC_FAN_FUNCS2,
565 ASMC_LIGHT_FUNCS_DISABLED,
566 ASMC_TEMPS_FUNCS_DISABLED
567 }
568 };
569
570 #undef ASMC_SMS_FUNCS
571 #undef ASMC_SMS_FUNCS_DISABLED
572 #undef ASMC_FAN_FUNCS
573 #undef ASMC_FAN_FUNCS2
574 #undef ASMC_LIGHT_FUNCS
575
576 /*
577 * Driver methods.
578 */
579 static device_method_t asmc_methods[] = {
580 DEVMETHOD(device_probe, asmc_probe),
581 DEVMETHOD(device_attach, asmc_attach),
582 DEVMETHOD(device_detach, asmc_detach),
583 DEVMETHOD(device_resume, asmc_resume),
584 DEVMETHOD_END
585 };
586
587 static driver_t asmc_driver = {
588 "asmc",
589 asmc_methods,
590 sizeof(struct asmc_softc)
591 };
592
593 /*
594 * Debugging
595 */
596 #define _COMPONENT ACPI_OEM
597 ACPI_MODULE_NAME("ASMC")
598 #ifdef ASMC_DEBUG
599 #define ASMC_DPRINTF(str, ...) device_printf(dev, str, ##__VA_ARGS__)
600 #else
601 #define ASMC_DPRINTF(str, ...)
602 #endif
603
604 /* NB: can't be const */
605 static char *asmc_ids[] = { "APP0001", NULL };
606
607 static unsigned int light_control = 0;
608
609 DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL);
610 MODULE_DEPEND(asmc, acpi, 1, 1, 1);
611
612 static const struct asmc_model *
asmc_match(device_t dev)613 asmc_match(device_t dev)
614 {
615 const struct asmc_model *model;
616 char *model_name;
617 int i;
618
619 model = NULL;
620
621 model_name = kern_getenv("smbios.system.product");
622 if (model_name == NULL)
623 goto out;
624
625 for (i = 0; i < nitems(asmc_models); i++) {
626 if (strncmp(model_name, asmc_models[i].smc_model,
627 strlen(model_name)) == 0) {
628 model = &asmc_models[i];
629 goto out;
630 }
631 }
632 for (i = 0; i < nitems(asmc_generic_models); i++) {
633 if (strncmp(model_name, asmc_generic_models[i].smc_model,
634 strlen(asmc_generic_models[i].smc_model)) == 0) {
635 model = &asmc_generic_models[i];
636 goto out;
637 }
638 }
639
640 out:
641 freeenv(model_name);
642 return (model);
643 }
644
645 static int
asmc_probe(device_t dev)646 asmc_probe(device_t dev)
647 {
648 const struct asmc_model *model;
649 const char *device_desc;
650 int rv;
651
652 if (resource_disabled("asmc", 0))
653 return (ENXIO);
654 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL);
655 if (rv > 0)
656 return (rv);
657
658 model = asmc_match(dev);
659 if (model == NULL) {
660 device_printf(dev, "model not recognized\n");
661 return (ENXIO);
662 }
663 device_desc = model->smc_desc == NULL ?
664 model->smc_model : model->smc_desc;
665 device_set_desc(dev, device_desc);
666
667 return (rv);
668 }
669
670 static int
asmc_attach(device_t dev)671 asmc_attach(device_t dev)
672 {
673 int i, j;
674 int ret;
675 char name[2];
676 struct asmc_softc *sc = device_get_softc(dev);
677 struct sysctl_ctx_list *sysctlctx;
678 struct sysctl_oid *sysctlnode;
679 const struct asmc_model *model;
680
681 sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
682 &sc->sc_rid_port, RF_ACTIVE);
683 if (sc->sc_ioport == NULL) {
684 device_printf(dev, "unable to allocate IO port\n");
685 return (ENOMEM);
686 }
687
688 sysctlctx = device_get_sysctl_ctx(dev);
689 sysctlnode = device_get_sysctl_tree(dev);
690
691 model = asmc_match(dev);
692
693 mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
694
695 sc->sc_model = model;
696 asmc_init(dev);
697
698 /*
699 * dev.asmc.n.fan.* tree.
700 */
701 sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
702 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
703 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree");
704
705 for (i = 1; i <= sc->sc_nfan; i++) {
706 j = i - 1;
707 name[0] = '0' + j;
708 name[1] = 0;
709 sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
710 SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name,
711 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree");
712
713 SYSCTL_ADD_PROC(sysctlctx,
714 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
715 OID_AUTO, "id",
716 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
717 model->smc_fan_id, "I", "Fan ID");
718
719 SYSCTL_ADD_PROC(sysctlctx,
720 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
721 OID_AUTO, "speed",
722 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
723 model->smc_fan_speed, "I", "Fan speed in RPM");
724
725 SYSCTL_ADD_PROC(sysctlctx,
726 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
727 OID_AUTO, "safespeed",
728 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
729 model->smc_fan_safespeed, "I", "Fan safe speed in RPM");
730
731 SYSCTL_ADD_PROC(sysctlctx,
732 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
733 OID_AUTO, "minspeed",
734 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
735 model->smc_fan_minspeed, "I", "Fan minimum speed in RPM");
736
737 SYSCTL_ADD_PROC(sysctlctx,
738 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
739 OID_AUTO, "maxspeed",
740 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
741 model->smc_fan_maxspeed, "I", "Fan maximum speed in RPM");
742
743 SYSCTL_ADD_PROC(sysctlctx,
744 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
745 OID_AUTO, "targetspeed",
746 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
747 model->smc_fan_targetspeed, "I", "Fan target speed in RPM");
748
749 SYSCTL_ADD_PROC(sysctlctx,
750 SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
751 OID_AUTO, "manual",
752 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
753 asmc_mb_sysctl_fanmanual, "I",
754 "Fan manual mode (0=auto, 1=manual)");
755 }
756
757 /*
758 * dev.asmc.n.temp tree.
759 */
760 sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
761 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
762 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
763
764 for (i = 0; model->smc_temps[i]; i++) {
765 SYSCTL_ADD_PROC(sysctlctx,
766 SYSCTL_CHILDREN(sc->sc_temp_tree),
767 OID_AUTO, model->smc_tempnames[i],
768 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i,
769 asmc_temp_sysctl, "I",
770 model->smc_tempdescs[i]);
771 }
772
773 /*
774 * dev.asmc.n.light
775 */
776 if (model->smc_light_left) {
777 sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
778 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
779 CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
780 "Keyboard backlight sensors");
781
782 SYSCTL_ADD_PROC(sysctlctx,
783 SYSCTL_CHILDREN(sc->sc_light_tree),
784 OID_AUTO, "left",
785 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
786 dev, 0, model->smc_light_left, "I",
787 "Keyboard backlight left sensor");
788
789 SYSCTL_ADD_PROC(sysctlctx,
790 SYSCTL_CHILDREN(sc->sc_light_tree),
791 OID_AUTO, "right",
792 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0,
793 model->smc_light_right, "I",
794 "Keyboard backlight right sensor");
795
796 SYSCTL_ADD_PROC(sysctlctx,
797 SYSCTL_CHILDREN(sc->sc_light_tree),
798 OID_AUTO, "control",
799 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
800 dev, 0, model->smc_light_control, "I",
801 "Keyboard backlight brightness control");
802 }
803
804 if (model->smc_sms_x == NULL)
805 goto nosms;
806
807 /*
808 * dev.asmc.n.sms tree.
809 */
810 sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
811 SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
812 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor");
813
814 SYSCTL_ADD_PROC(sysctlctx,
815 SYSCTL_CHILDREN(sc->sc_sms_tree),
816 OID_AUTO, "x",
817 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
818 dev, 0, model->smc_sms_x, "I",
819 "Sudden Motion Sensor X value");
820
821 SYSCTL_ADD_PROC(sysctlctx,
822 SYSCTL_CHILDREN(sc->sc_sms_tree),
823 OID_AUTO, "y",
824 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
825 dev, 0, model->smc_sms_y, "I",
826 "Sudden Motion Sensor Y value");
827
828 SYSCTL_ADD_PROC(sysctlctx,
829 SYSCTL_CHILDREN(sc->sc_sms_tree),
830 OID_AUTO, "z",
831 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
832 dev, 0, model->smc_sms_z, "I",
833 "Sudden Motion Sensor Z value");
834
835 /*
836 * Need a taskqueue to send devctl_notify() events
837 * when the SMS interrupt us.
838 *
839 * PI_REALTIME is used due to the sensitivity of the
840 * interrupt. An interrupt from the SMS means that the
841 * disk heads should be turned off as quickly as possible.
842 *
843 * We only need to do this for the non INTR_FILTER case.
844 */
845 sc->sc_sms_tq = NULL;
846 TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
847 sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
848 taskqueue_thread_enqueue, &sc->sc_sms_tq);
849 taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
850 device_get_nameunit(dev));
851 /*
852 * Allocate an IRQ for the SMS.
853 */
854 sc->sc_rid_irq = 0;
855 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq,
856 RF_ACTIVE);
857 if (sc->sc_irq == NULL) {
858 device_printf(dev, "unable to allocate IRQ resource\n");
859 ret = ENXIO;
860 goto err;
861 }
862
863 ret = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE,
864 asmc_sms_intrfast, NULL, dev, &sc->sc_cookie);
865 if (ret) {
866 device_printf(dev, "unable to setup SMS IRQ\n");
867 goto err;
868 }
869
870 nosms:
871 return (0);
872
873 err:
874 asmc_detach(dev);
875
876 return (ret);
877 }
878
879 static int
asmc_detach(device_t dev)880 asmc_detach(device_t dev)
881 {
882 struct asmc_softc *sc = device_get_softc(dev);
883
884 if (sc->sc_sms_tq) {
885 taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
886 taskqueue_free(sc->sc_sms_tq);
887 sc->sc_sms_tq = NULL;
888 }
889 if (sc->sc_cookie) {
890 bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
891 sc->sc_cookie = NULL;
892 }
893 if (sc->sc_irq) {
894 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
895 sc->sc_irq);
896 sc->sc_irq = NULL;
897 }
898 if (sc->sc_ioport) {
899 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
900 sc->sc_ioport);
901 sc->sc_ioport = NULL;
902 }
903 if (mtx_initialized(&sc->sc_mtx)) {
904 mtx_destroy(&sc->sc_mtx);
905 }
906
907 return (0);
908 }
909
910 static int
asmc_resume(device_t dev)911 asmc_resume(device_t dev)
912 {
913 uint8_t buf[2];
914
915 buf[0] = light_control;
916 buf[1] = 0x00;
917 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
918
919 return (0);
920 }
921
922 #ifdef ASMC_DEBUG
923 void
asmc_dumpall(device_t dev)924 asmc_dumpall(device_t dev)
925 {
926 struct asmc_softc *sc = device_get_softc(dev);
927 int i;
928
929 if (sc->sc_nkeys == 0) {
930 device_printf(dev, "asmc_dumpall: key count not available\n");
931 return;
932 }
933
934 device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys);
935 for (i = 0; i < sc->sc_nkeys; i++)
936 asmc_key_dump(dev, i);
937 }
938 #endif
939
940 static int
asmc_init(device_t dev)941 asmc_init(device_t dev)
942 {
943 struct asmc_softc *sc = device_get_softc(dev);
944 struct sysctl_ctx_list *sysctlctx;
945 uint8_t buf[6];
946 int i, error = 1;
947
948 sysctlctx = device_get_sysctl_ctx(dev);
949
950 error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6);
951 if (error != 0)
952 goto out_err;
953 device_printf(dev, "SMC revision: %x.%x%x%x\n", buf[0], buf[1], buf[2],
954 ntohs(*(uint16_t *)buf + 4));
955
956 if (sc->sc_model->smc_sms_x == NULL)
957 goto nosms;
958
959 /*
960 * We are ready to receive interrupts from the SMS.
961 */
962 buf[0] = 0x01;
963 ASMC_DPRINTF(("intok key\n"));
964 asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
965 DELAY(50);
966
967 /*
968 * Initiate the polling intervals.
969 */
970 buf[0] = 20; /* msecs */
971 ASMC_DPRINTF(("low int key\n"));
972 asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
973 DELAY(200);
974
975 buf[0] = 20; /* msecs */
976 ASMC_DPRINTF(("high int key\n"));
977 asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
978 DELAY(200);
979
980 buf[0] = 0x00;
981 buf[1] = 0x60;
982 ASMC_DPRINTF(("sms low key\n"));
983 asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
984 DELAY(200);
985
986 buf[0] = 0x01;
987 buf[1] = 0xc0;
988 ASMC_DPRINTF(("sms high key\n"));
989 asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
990 DELAY(200);
991
992 /*
993 * I'm not sure what this key does, but it seems to be
994 * required.
995 */
996 buf[0] = 0x01;
997 ASMC_DPRINTF(("sms flag key\n"));
998 asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
999 DELAY(100);
1000
1001 sc->sc_sms_intr_works = 0;
1002
1003 /*
1004 * Retry SMS initialization 1000 times
1005 * (takes approx. 2 seconds in worst case)
1006 */
1007 for (i = 0; i < 1000; i++) {
1008 if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
1009 (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
1010 error = 0;
1011 sc->sc_sms_intr_works = 1;
1012 goto out;
1013 }
1014 buf[0] = ASMC_SMS_INIT1;
1015 buf[1] = ASMC_SMS_INIT2;
1016 ASMC_DPRINTF(("sms key\n"));
1017 asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
1018 DELAY(50);
1019 }
1020 device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
1021
1022 out:
1023 asmc_sms_calibrate(dev);
1024 nosms:
1025 /* Wake-on-LAN convenience sysctl */
1026 if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) {
1027 SYSCTL_ADD_PROC(sysctlctx,
1028 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1029 OID_AUTO, "wol",
1030 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
1031 dev, 0, asmc_wol_sysctl, "I",
1032 "Wake-on-LAN enable (0=off, 1=on)");
1033 }
1034
1035 sc->sc_nfan = asmc_fan_count(dev);
1036 if (sc->sc_nfan > ASMC_MAXFANS) {
1037 device_printf(dev,
1038 "more than %d fans were detected. Please report this.\n",
1039 ASMC_MAXFANS);
1040 sc->sc_nfan = ASMC_MAXFANS;
1041 }
1042
1043 /*
1044 * Read and cache the number of SMC keys (32 bit buffer)
1045 */
1046 if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) {
1047 sc->sc_nkeys = be32dec(buf);
1048 if (bootverbose)
1049 device_printf(dev, "number of keys: %d\n",
1050 sc->sc_nkeys);
1051 } else {
1052 sc->sc_nkeys = 0;
1053 }
1054
1055 out_err:
1056 #ifdef ASMC_DEBUG
1057 asmc_dumpall(dev);
1058 #endif
1059 return (error);
1060 }
1061
1062 /*
1063 * We need to make sure that the SMC acks the byte sent.
1064 * Just wait up to (amount * 10) ms.
1065 */
1066 static int
asmc_wait_ack(device_t dev,uint8_t val,int amount)1067 asmc_wait_ack(device_t dev, uint8_t val, int amount)
1068 {
1069 struct asmc_softc *sc = device_get_softc(dev);
1070 u_int i;
1071
1072 val = val & ASMC_STATUS_MASK;
1073
1074 for (i = 0; i < amount; i++) {
1075 if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
1076 return (0);
1077 DELAY(10);
1078 }
1079
1080 return (1);
1081 }
1082
1083 /*
1084 * We need to make sure that the SMC acks the byte sent.
1085 * Just wait up to 100 ms.
1086 */
1087 static int
asmc_wait(device_t dev,uint8_t val)1088 asmc_wait(device_t dev, uint8_t val)
1089 {
1090 #ifdef ASMC_DEBUG
1091 struct asmc_softc *sc;
1092 #endif
1093
1094 if (asmc_wait_ack(dev, val, 1000) == 0)
1095 return (0);
1096
1097 #ifdef ASMC_DEBUG
1098 sc = device_get_softc(dev);
1099
1100 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__,
1101 val & ASMC_STATUS_MASK, ASMC_CMDPORT_READ(sc));
1102 #endif
1103 return (1);
1104 }
1105
1106 /*
1107 * Send the given command, retrying up to 10 times if
1108 * the acknowledgement fails.
1109 */
1110 static int
asmc_command(device_t dev,uint8_t command)1111 asmc_command(device_t dev, uint8_t command)
1112 {
1113 int i;
1114 struct asmc_softc *sc = device_get_softc(dev);
1115
1116 for (i = 0; i < 10; i++) {
1117 ASMC_CMDPORT_WRITE(sc, command);
1118 if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
1119 return (0);
1120 }
1121 }
1122
1123 #ifdef ASMC_DEBUG
1124 device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
1125 ASMC_CMDPORT_READ(sc));
1126 #endif
1127 return (1);
1128 }
1129
1130 static int
asmc_key_read(device_t dev,const char * key,uint8_t * buf,uint8_t len)1131 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1132 {
1133 int i, error = 1, try = 0;
1134 struct asmc_softc *sc = device_get_softc(dev);
1135
1136 mtx_lock_spin(&sc->sc_mtx);
1137
1138 begin:
1139 if (asmc_command(dev, ASMC_CMDREAD))
1140 goto out;
1141
1142 for (i = 0; i < 4; i++) {
1143 ASMC_DATAPORT_WRITE(sc, key[i]);
1144 if (asmc_wait(dev, 0x04))
1145 goto out;
1146 }
1147
1148 ASMC_DATAPORT_WRITE(sc, len);
1149
1150 for (i = 0; i < len; i++) {
1151 if (asmc_wait(dev, 0x05))
1152 goto out;
1153 buf[i] = ASMC_DATAPORT_READ(sc);
1154 }
1155
1156 error = 0;
1157 out:
1158 if (error) {
1159 if (++try < 10)
1160 goto begin;
1161 device_printf(dev, "%s for key %s failed %d times, giving up\n",
1162 __func__, key, try);
1163 }
1164
1165 mtx_unlock_spin(&sc->sc_mtx);
1166
1167 return (error);
1168 }
1169
1170 #ifdef ASMC_DEBUG
1171 static int
asmc_key_dump(device_t dev,int number)1172 asmc_key_dump(device_t dev, int number)
1173 {
1174 struct asmc_softc *sc = device_get_softc(dev);
1175 char key[5] = { 0 };
1176 char type[7] = { 0 };
1177 uint8_t index[4];
1178 uint8_t v[32];
1179 uint8_t maxlen;
1180 int i, error = 1, try = 0;
1181
1182 mtx_lock_spin(&sc->sc_mtx);
1183
1184 index[0] = (number >> 24) & 0xff;
1185 index[1] = (number >> 16) & 0xff;
1186 index[2] = (number >> 8) & 0xff;
1187 index[3] = (number) & 0xff;
1188
1189 begin:
1190 if (asmc_command(dev, 0x12))
1191 goto out;
1192
1193 for (i = 0; i < 4; i++) {
1194 ASMC_DATAPORT_WRITE(sc, index[i]);
1195 if (asmc_wait(dev, 0x04))
1196 goto out;
1197 }
1198
1199 ASMC_DATAPORT_WRITE(sc, 4);
1200
1201 for (i = 0; i < 4; i++) {
1202 if (asmc_wait(dev, 0x05))
1203 goto out;
1204 key[i] = ASMC_DATAPORT_READ(sc);
1205 }
1206
1207 /* get type */
1208 if (asmc_command(dev, 0x13))
1209 goto out;
1210
1211 for (i = 0; i < 4; i++) {
1212 ASMC_DATAPORT_WRITE(sc, key[i]);
1213 if (asmc_wait(dev, 0x04))
1214 goto out;
1215 }
1216
1217 ASMC_DATAPORT_WRITE(sc, 6);
1218
1219 for (i = 0; i < 6; i++) {
1220 if (asmc_wait(dev, 0x05))
1221 goto out;
1222 type[i] = ASMC_DATAPORT_READ(sc);
1223 }
1224
1225 error = 0;
1226 out:
1227 if (error) {
1228 if (++try < 10)
1229 goto begin;
1230 device_printf(dev, "%s for key %s failed %d times, giving up\n",
1231 __func__, key, try);
1232 mtx_unlock_spin(&sc->sc_mtx);
1233 } else {
1234 char buf[1024];
1235 char buf2[8];
1236 mtx_unlock_spin(&sc->sc_mtx);
1237 maxlen = type[0];
1238 type[0] = ' ';
1239 type[5] = 0;
1240 if (maxlen > sizeof(v)) {
1241 device_printf(dev,
1242 "WARNING: cropping maxlen from %d to %zu\n", maxlen,
1243 sizeof(v));
1244 maxlen = sizeof(v);
1245 }
1246 for (i = 0; i < sizeof(v); i++) {
1247 v[i] = 0;
1248 }
1249 asmc_key_read(dev, key, v, maxlen);
1250 snprintf(buf, sizeof(buf),
1251 "key %d is: %s, type %s (len %d), data",
1252 number, key, type, maxlen);
1253 for (i = 0; i < maxlen; i++) {
1254 snprintf(buf2, sizeof(buf2), " %02x", v[i]);
1255 strlcat(buf, buf2, sizeof(buf));
1256 }
1257 strlcat(buf, " \n", sizeof(buf));
1258 device_printf(dev, "%s", buf);
1259 }
1260
1261 return (error);
1262 }
1263 #endif
1264
1265 static int
asmc_key_write(device_t dev,const char * key,uint8_t * buf,uint8_t len)1266 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1267 {
1268 int i, error = -1, try = 0;
1269 struct asmc_softc *sc = device_get_softc(dev);
1270
1271 mtx_lock_spin(&sc->sc_mtx);
1272
1273 begin:
1274 ASMC_DPRINTF(("cmd port: cmd write\n"));
1275 if (asmc_command(dev, ASMC_CMDWRITE))
1276 goto out;
1277
1278 ASMC_DPRINTF(("data port: key\n"));
1279 for (i = 0; i < 4; i++) {
1280 ASMC_DATAPORT_WRITE(sc, key[i]);
1281 if (asmc_wait(dev, 0x04))
1282 goto out;
1283 }
1284 ASMC_DPRINTF(("data port: length\n"));
1285 ASMC_DATAPORT_WRITE(sc, len);
1286
1287 ASMC_DPRINTF(("data port: buffer\n"));
1288 for (i = 0; i < len; i++) {
1289 if (asmc_wait(dev, 0x04))
1290 goto out;
1291 ASMC_DATAPORT_WRITE(sc, buf[i]);
1292 }
1293
1294 error = 0;
1295 out:
1296 if (error) {
1297 if (++try < 10)
1298 goto begin;
1299 device_printf(dev, "%s for key %s failed %d times, giving up\n",
1300 __func__, key, try);
1301 }
1302
1303 mtx_unlock_spin(&sc->sc_mtx);
1304
1305 return (error);
1306 }
1307
1308 /*
1309 * Fan control functions.
1310 */
1311 static int
asmc_fan_count(device_t dev)1312 asmc_fan_count(device_t dev)
1313 {
1314 uint8_t buf[1];
1315
1316 if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0)
1317 return (-1);
1318
1319 return (buf[0]);
1320 }
1321
1322 static int
asmc_fan_getvalue(device_t dev,const char * key,int fan)1323 asmc_fan_getvalue(device_t dev, const char *key, int fan)
1324 {
1325 int speed;
1326 uint8_t buf[2];
1327 char fankey[5];
1328
1329 snprintf(fankey, sizeof(fankey), key, fan);
1330 if (asmc_key_read(dev, fankey, buf, sizeof(buf)) != 0)
1331 return (-1);
1332 speed = (buf[0] << 6) | (buf[1] >> 2);
1333
1334 return (speed);
1335 }
1336
1337 static char *
asmc_fan_getstring(device_t dev,const char * key,int fan,uint8_t * buf,uint8_t buflen)1338 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf,
1339 uint8_t buflen)
1340 {
1341 char fankey[5];
1342 char *desc;
1343
1344 snprintf(fankey, sizeof(fankey), key, fan);
1345 if (asmc_key_read(dev, fankey, buf, buflen) != 0)
1346 return (NULL);
1347 desc = buf + 4;
1348
1349 return (desc);
1350 }
1351
1352 static int
asmc_fan_setvalue(device_t dev,const char * key,int fan,int speed)1353 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
1354 {
1355 uint8_t buf[2];
1356 char fankey[5];
1357
1358 speed *= 4;
1359
1360 buf[0] = speed >> 8;
1361 buf[1] = speed;
1362
1363 snprintf(fankey, sizeof(fankey), key, fan);
1364 if (asmc_key_write(dev, fankey, buf, sizeof(buf)) < 0)
1365 return (-1);
1366
1367 return (0);
1368 }
1369
1370 static int
asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)1371 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
1372 {
1373 device_t dev = (device_t)arg1;
1374 int fan = arg2;
1375 int error;
1376 int32_t v;
1377
1378 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
1379 error = sysctl_handle_int(oidp, &v, 0, req);
1380
1381 return (error);
1382 }
1383
1384 static int
asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)1385 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
1386 {
1387 uint8_t buf[16];
1388 device_t dev = (device_t)arg1;
1389 int fan = arg2;
1390 int error = true;
1391 char *desc;
1392
1393 desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
1394
1395 if (desc != NULL)
1396 error = sysctl_handle_string(oidp, desc, 0, req);
1397
1398 return (error);
1399 }
1400
1401 static int
asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)1402 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
1403 {
1404 device_t dev = (device_t)arg1;
1405 int fan = arg2;
1406 int error;
1407 int32_t v;
1408
1409 v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
1410 error = sysctl_handle_int(oidp, &v, 0, req);
1411
1412 return (error);
1413 }
1414
1415 static int
asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)1416 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
1417 {
1418 device_t dev = (device_t)arg1;
1419 int fan = arg2;
1420 int error;
1421 int32_t v;
1422
1423 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
1424 error = sysctl_handle_int(oidp, &v, 0, req);
1425
1426 if (error == 0 && req->newptr != NULL) {
1427 unsigned int newspeed = v;
1428 asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed);
1429 }
1430
1431 return (error);
1432 }
1433
1434 static int
asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)1435 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
1436 {
1437 device_t dev = (device_t)arg1;
1438 int fan = arg2;
1439 int error;
1440 int32_t v;
1441
1442 v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
1443 error = sysctl_handle_int(oidp, &v, 0, req);
1444
1445 if (error == 0 && req->newptr != NULL) {
1446 unsigned int newspeed = v;
1447 asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed);
1448 }
1449
1450 return (error);
1451 }
1452
1453 static int
asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)1454 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
1455 {
1456 device_t dev = (device_t)arg1;
1457 int fan = arg2;
1458 int error;
1459 int32_t v;
1460
1461 v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
1462 error = sysctl_handle_int(oidp, &v, 0, req);
1463
1464 if (error == 0 && req->newptr != NULL) {
1465 unsigned int newspeed = v;
1466 asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed);
1467 }
1468
1469 return (error);
1470 }
1471
1472 static int
asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS)1473 asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS)
1474 {
1475 device_t dev = (device_t)arg1;
1476 int fan = arg2;
1477 int error;
1478 int32_t v;
1479 uint8_t buf[2];
1480 uint16_t val;
1481
1482 /* Read current FS! bitmask (asmc_key_read locks internally) */
1483 error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf));
1484 if (error != 0)
1485 return (error);
1486
1487 /* Extract manual bit for this fan (big-endian) */
1488 val = (buf[0] << 8) | buf[1];
1489 v = (val >> fan) & 0x01;
1490
1491 /* Let sysctl handle the value */
1492 error = sysctl_handle_int(oidp, &v, 0, req);
1493
1494 if (error == 0 && req->newptr != NULL) {
1495 /* Validate input (0 = auto, 1 = manual) */
1496 if (v != 0 && v != 1)
1497 return (EINVAL);
1498 /* Read-modify-write of FS! bitmask */
1499 error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf,
1500 sizeof(buf));
1501 if (error == 0) {
1502 val = (buf[0] << 8) | buf[1];
1503
1504 /* Modify single bit */
1505 if (v)
1506 val |= (1 << fan); /* Set to manual */
1507 else
1508 val &= ~(1 << fan); /* Set to auto */
1509
1510 /* Write back */
1511 buf[0] = val >> 8;
1512 buf[1] = val & 0xff;
1513 error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf,
1514 sizeof(buf));
1515 }
1516 }
1517
1518 return (error);
1519 }
1520
1521 /*
1522 * Temperature functions.
1523 */
1524 static int
asmc_temp_getvalue(device_t dev,const char * key)1525 asmc_temp_getvalue(device_t dev, const char *key)
1526 {
1527 uint8_t buf[2];
1528
1529 /*
1530 * Check for invalid temperatures.
1531 */
1532 if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0)
1533 return (-1);
1534
1535 return (buf[0]);
1536 }
1537
1538 static int
asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)1539 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
1540 {
1541 device_t dev = (device_t)arg1;
1542 struct asmc_softc *sc = device_get_softc(dev);
1543 int error, val;
1544
1545 val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
1546 error = sysctl_handle_int(oidp, &val, 0, req);
1547
1548 return (error);
1549 }
1550
1551 /*
1552 * Sudden Motion Sensor functions.
1553 */
1554 static int
asmc_sms_read(device_t dev,const char * key,int16_t * val)1555 asmc_sms_read(device_t dev, const char *key, int16_t *val)
1556 {
1557 uint8_t buf[2];
1558 int error;
1559
1560 /* no need to do locking here as asmc_key_read() already does it */
1561 switch (key[3]) {
1562 case 'X':
1563 case 'Y':
1564 case 'Z':
1565 error = asmc_key_read(dev, key, buf, sizeof(buf));
1566 break;
1567 default:
1568 device_printf(dev, "%s called with invalid argument %s\n",
1569 __func__, key);
1570 error = EINVAL;
1571 goto out;
1572 }
1573 *val = ((int16_t)buf[0] << 8) | buf[1];
1574 out:
1575 return (error);
1576 }
1577
1578 static void
asmc_sms_calibrate(device_t dev)1579 asmc_sms_calibrate(device_t dev)
1580 {
1581 struct asmc_softc *sc = device_get_softc(dev);
1582
1583 asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
1584 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
1585 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
1586 }
1587
1588 static int
asmc_sms_intrfast(void * arg)1589 asmc_sms_intrfast(void *arg)
1590 {
1591 uint8_t type;
1592 device_t dev = (device_t)arg;
1593 struct asmc_softc *sc = device_get_softc(dev);
1594 if (!sc->sc_sms_intr_works)
1595 return (FILTER_HANDLED);
1596
1597 mtx_lock_spin(&sc->sc_mtx);
1598 type = ASMC_INTPORT_READ(sc);
1599 mtx_unlock_spin(&sc->sc_mtx);
1600
1601 sc->sc_sms_intrtype = type;
1602 asmc_sms_printintr(dev, type);
1603
1604 taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
1605 return (FILTER_HANDLED);
1606 }
1607
1608 static void
asmc_sms_printintr(device_t dev,uint8_t type)1609 asmc_sms_printintr(device_t dev, uint8_t type)
1610 {
1611 struct asmc_softc *sc = device_get_softc(dev);
1612
1613 switch (type) {
1614 case ASMC_SMS_INTFF:
1615 device_printf(dev, "WARNING: possible free fall!\n");
1616 break;
1617 case ASMC_SMS_INTHA:
1618 device_printf(dev, "WARNING: high acceleration detected!\n");
1619 break;
1620 case ASMC_SMS_INTSH:
1621 device_printf(dev, "WARNING: possible shock!\n");
1622 break;
1623 case ASMC_ALSL_INT2A:
1624 /*
1625 * This suppresses console and log messages for the ambient
1626 * light sensor for models known to generate this interrupt.
1627 */
1628 if (strcmp(sc->sc_model->smc_model, "MacBookPro5,5") == 0 ||
1629 strcmp(sc->sc_model->smc_model, "MacBookPro6,2") == 0)
1630 break;
1631 /* FALLTHROUGH */
1632 default:
1633 device_printf(dev, "unknown interrupt: 0x%x\n", type);
1634 }
1635 }
1636
1637 static void
asmc_sms_task(void * arg,int pending)1638 asmc_sms_task(void *arg, int pending)
1639 {
1640 struct asmc_softc *sc = (struct asmc_softc *)arg;
1641 char notify[16];
1642 int type;
1643
1644 switch (sc->sc_sms_intrtype) {
1645 case ASMC_SMS_INTFF:
1646 type = 2;
1647 break;
1648 case ASMC_SMS_INTHA:
1649 type = 1;
1650 break;
1651 case ASMC_SMS_INTSH:
1652 type = 0;
1653 break;
1654 default:
1655 type = 255;
1656 }
1657
1658 snprintf(notify, sizeof(notify), " notify=0x%x", type);
1659 devctl_notify("ACPI", "asmc", "SMS", notify);
1660 }
1661
1662 static int
asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)1663 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
1664 {
1665 device_t dev = (device_t)arg1;
1666 int error;
1667 int16_t val;
1668 int32_t v;
1669
1670 asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
1671 v = (int32_t)val;
1672 error = sysctl_handle_int(oidp, &v, 0, req);
1673
1674 return (error);
1675 }
1676
1677 static int
asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)1678 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
1679 {
1680 device_t dev = (device_t)arg1;
1681 int error;
1682 int16_t val;
1683 int32_t v;
1684
1685 asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
1686 v = (int32_t)val;
1687 error = sysctl_handle_int(oidp, &v, 0, req);
1688
1689 return (error);
1690 }
1691
1692 static int
asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)1693 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
1694 {
1695 device_t dev = (device_t)arg1;
1696 int error;
1697 int16_t val;
1698 int32_t v;
1699
1700 asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
1701 v = (int32_t)val;
1702 error = sysctl_handle_int(oidp, &v, 0, req);
1703
1704 return (error);
1705 }
1706
1707 static int
asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)1708 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
1709 {
1710 device_t dev = (device_t)arg1;
1711 uint8_t buf[6];
1712 int error;
1713 int32_t v;
1714
1715 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
1716 v = buf[2];
1717 error = sysctl_handle_int(oidp, &v, 0, req);
1718
1719 return (error);
1720 }
1721
1722 static int
asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)1723 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
1724 {
1725 device_t dev = (device_t)arg1;
1726 uint8_t buf[6];
1727 int error;
1728 int32_t v;
1729
1730 asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf));
1731 v = buf[2];
1732 error = sysctl_handle_int(oidp, &v, 0, req);
1733
1734 return (error);
1735 }
1736
1737 static int
asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)1738 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
1739 {
1740 device_t dev = (device_t)arg1;
1741 uint8_t buf[2];
1742 int error;
1743 int v;
1744
1745 v = light_control;
1746 error = sysctl_handle_int(oidp, &v, 0, req);
1747
1748 if (error == 0 && req->newptr != NULL) {
1749 if (v < 0 || v > 255)
1750 return (EINVAL);
1751 light_control = v;
1752 buf[0] = light_control;
1753 buf[1] = 0x00;
1754 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
1755 }
1756 return (error);
1757 }
1758
1759 static int
asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)1760 asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
1761 {
1762 device_t dev = (device_t)arg1;
1763 uint8_t buf[10];
1764 int error;
1765 uint32_t v;
1766
1767 asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
1768
1769 /*
1770 * This seems to be a 32 bit big endian value from buf[6] -> buf[9].
1771 *
1772 * Extract it out manually here, then shift/clamp it.
1773 */
1774 v = be32dec(&buf[6]);
1775
1776 /*
1777 * Shift out, clamp at 255; that way it looks like the
1778 * earlier SMC firmware version responses.
1779 */
1780 v = v >> 8;
1781 if (v > 255)
1782 v = 255;
1783
1784 error = sysctl_handle_int(oidp, &v, 0, req);
1785
1786 return (error);
1787 }
1788
1789 /*
1790 * Wake-on-LAN convenience sysctl.
1791 * Reading returns 1 if WoL is enabled, 0 if disabled.
1792 * Writing 1 enables WoL, 0 disables it.
1793 */
1794 static int
asmc_wol_sysctl(SYSCTL_HANDLER_ARGS)1795 asmc_wol_sysctl(SYSCTL_HANDLER_ARGS)
1796 {
1797 device_t dev = (device_t)arg1;
1798 uint8_t aupo;
1799 int val, error;
1800
1801 /* Read current AUPO value */
1802 if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
1803 return (EIO);
1804
1805 val = (aupo != 0) ? 1 : 0;
1806 error = sysctl_handle_int(oidp, &val, 0, req);
1807 if (error != 0 || req->newptr == NULL)
1808 return (error);
1809
1810 /* Clamp to 0 or 1 */
1811 aupo = (val != 0) ? 1 : 0;
1812
1813 /* Write AUPO */
1814 if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
1815 return (EIO);
1816
1817 return (0);
1818 }
1819