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