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