xref: /freebsd/sys/dev/asmc/asmc.c (revision bc531a96c9b28b1cabcd5deb0c9f8f6d815cfebc)
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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