xref: /freebsd/sys/dev/asmc/asmc.c (revision a3cefe7f2b4df0f70ff92d4570ce18e517af43ec)
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 #include <dev/backlight/backlight.h>
62 #include "backlight_if.h"
63 
64 /*
65  * Device interface.
66  */
67 static int 	asmc_probe(device_t dev);
68 static int 	asmc_attach(device_t dev);
69 static int 	asmc_detach(device_t dev);
70 static int 	asmc_resume(device_t dev);
71 
72 /*
73  * Backlight interface.
74  */
75 static int	asmc_backlight_update_status(device_t dev,
76     struct backlight_props *props);
77 static int	asmc_backlight_get_status(device_t dev,
78     struct backlight_props *props);
79 static int	asmc_backlight_get_info(device_t dev, struct backlight_info *info);
80 
81 /*
82  * SMC functions.
83  */
84 static int 	asmc_init(device_t dev);
85 static int 	asmc_command(device_t dev, uint8_t command);
86 static int 	asmc_wait(device_t dev, uint8_t val);
87 static int 	asmc_wait_ack(device_t dev, uint8_t val, int amount);
88 static int 	asmc_key_write(device_t dev, const char *key, uint8_t *buf,
89     uint8_t len);
90 static int 	asmc_key_read(device_t dev, const char *key, uint8_t *buf,
91     uint8_t);
92 static int 	asmc_fan_count(device_t dev);
93 static int 	asmc_fan_getvalue(device_t dev, const char *key, int fan);
94 static int 	asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
95 static int 	asmc_temp_getvalue(device_t dev, const char *key);
96 static int 	asmc_sms_read(device_t, const char *key, int16_t *val);
97 static void 	asmc_sms_calibrate(device_t dev);
98 static int 	asmc_sms_intrfast(void *arg);
99 static void 	asmc_sms_printintr(device_t dev, uint8_t);
100 static void 	asmc_sms_task(void *arg, int pending);
101 #ifdef ASMC_DEBUG
102 void		asmc_dumpall(device_t);
103 static int	asmc_key_dump(device_t, int);
104 #endif
105 
106 /*
107  * Model functions.
108  */
109 static int 	asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
110 static int 	asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
111 static int 	asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
112 static int 	asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
113 static int 	asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
114 static int 	asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
115 static int 	asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS);
116 static int 	asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
117 static int 	asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
118 static int 	asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
119 static int 	asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
120 static int 	asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
121 static int 	asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
122 static int 	asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
123 static int 	asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS);
124 static int	asmc_wol_sysctl(SYSCTL_HANDLER_ARGS);
125 
126 static int	asmc_key_getinfo(device_t, const char *, uint8_t *, char *);
127 
128 #ifdef ASMC_DEBUG
129 /* Raw key access */
130 static int	asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS);
131 static int	asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS);
132 static int	asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS);
133 static int	asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS);
134 #endif
135 
136 /* Voltage/Current/Power/Light sensor support */
137 static int	asmc_sensor_read(device_t, const char *, int *);
138 static int	asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS);
139 static int	asmc_detect_sensors(device_t);
140 static int	asmc_key_dump_by_index(device_t, int, char *, char *, uint8_t *);
141 
142 struct asmc_model {
143 	const char *smc_model; /* smbios.system.product env var. */
144 	const char *smc_desc;  /* driver description */
145 
146 	/* Helper functions */
147 	int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
148 	int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
149 	int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
150 	int (*smc_fan_id)(SYSCTL_HANDLER_ARGS);
151 	int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
152 	int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
153 	int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
154 	int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
155 	int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
156 	int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
157 	int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
158 	int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
159 
160 	const char 	*smc_temps[ASMC_TEMP_MAX];
161 	const char 	*smc_tempnames[ASMC_TEMP_MAX];
162 	const char 	*smc_tempdescs[ASMC_TEMP_MAX];
163 };
164 
165 static const struct asmc_model *asmc_match(device_t dev);
166 
167 #define ASMC_SMS_FUNCS						\
168 			.smc_sms_x = asmc_mb_sysctl_sms_x,	\
169 			.smc_sms_y = asmc_mb_sysctl_sms_y,	\
170 			.smc_sms_z = asmc_mb_sysctl_sms_z
171 
172 #define ASMC_SMS_FUNCS_DISABLED			\
173 			.smc_sms_x = NULL,	\
174 			.smc_sms_y = NULL,	\
175 			.smc_sms_z = NULL
176 
177 #define ASMC_FAN_FUNCS	\
178 			.smc_fan_id = asmc_mb_sysctl_fanid, \
179 			.smc_fan_speed = asmc_mb_sysctl_fanspeed, \
180 			.smc_fan_safespeed = asmc_mb_sysctl_fansafespeed, \
181 			.smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \
182 			.smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \
183 			.smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed
184 
185 #define ASMC_FAN_FUNCS2	\
186 			.smc_fan_id = asmc_mb_sysctl_fanid, \
187 			.smc_fan_speed = asmc_mb_sysctl_fanspeed, \
188 			.smc_fan_safespeed = NULL, \
189 			.smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \
190 			.smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \
191 			.smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed
192 
193 #define ASMC_LIGHT_FUNCS \
194 			 .smc_light_left = asmc_mbp_sysctl_light_left, \
195 			 .smc_light_right = asmc_mbp_sysctl_light_right, \
196 			 .smc_light_control = asmc_mbp_sysctl_light_control
197 
198 #define ASMC_LIGHT_FUNCS_10BYTE \
199 			 .smc_light_left = asmc_mbp_sysctl_light_left_10byte, \
200 			 .smc_light_right = NULL, \
201 			 .smc_light_control = asmc_mbp_sysctl_light_control
202 
203 #define ASMC_LIGHT_FUNCS_DISABLED \
204 			 .smc_light_left = NULL, \
205 			 .smc_light_right = NULL, \
206 			 .smc_light_control = NULL
207 
208 #define	ASMC_TEMPS_FUNCS_DISABLED \
209 			  .smc_temps = {},		\
210 			  .smc_tempnames = {},		\
211 			  .smc_tempdescs = {}		\
212 
213 static const struct asmc_model asmc_models[] = {
214 	{
215 	  "MacBook1,1", "Apple SMC MacBook Core Duo",
216 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
217 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
218 	},
219 
220 	{
221 	  "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
222 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
223 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
224 	},
225 
226 	{
227 	  "MacBook3,1", "Apple SMC MacBook Core 2 Duo",
228 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
229 	  ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS
230 	},
231 
232 	{
233 	  "MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)",
234 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED,
235 	  ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS
236 	},
237 
238 	{
239 	  "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
240 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
241 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
242 	},
243 
244 	{
245 	  "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
246 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
247 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
248 	},
249 
250 	{
251 	  "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
252 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
253 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
254 	},
255 
256 	{
257 	  "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
258 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
259 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
260 	},
261 
262 	{
263 	  "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
264 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
265 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
266 	},
267 
268 	{
269 	  "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
270 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
271 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
272 	},
273 
274 	{
275 	  "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
276 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
277 	  ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
278 	},
279 
280 	{
281 	  "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)",
282 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
283 	  ASMC_MBP51_TEMPS, ASMC_MBP51_TEMPNAMES, ASMC_MBP51_TEMPDESCS
284 	},
285 
286 	{
287 	  "MacBookPro5,5", "Apple SMC MacBook Pro Core 2 Duo (Mid 2009)",
288 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
289 	  ASMC_MBP55_TEMPS, ASMC_MBP55_TEMPNAMES, ASMC_MBP55_TEMPDESCS
290 	},
291 
292 	{
293 	  "MacBookPro6,2", "Apple SMC MacBook Pro (Mid 2010, 15-inch)",
294 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
295 	  ASMC_MBP62_TEMPS, ASMC_MBP62_TEMPNAMES, ASMC_MBP62_TEMPDESCS
296 	},
297 
298 	{
299 	  "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)",
300 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
301 	  ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS
302 	},
303 
304 	{
305 	  "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)",
306 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
307 	  ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS
308 	},
309 
310 	{
311 	  "MacBookPro8,3", "Apple SMC MacBook Pro (early 2011, 17-inch)",
312 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
313 	  ASMC_MBP83_TEMPS, ASMC_MBP83_TEMPNAMES, ASMC_MBP83_TEMPDESCS
314 	},
315 
316 	{
317 	  "MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)",
318 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
319 	  ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS
320 	},
321 
322 	{
323 	 "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012, 13-inch)",
324 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
325 	  ASMC_MBP92_TEMPS, ASMC_MBP92_TEMPNAMES, ASMC_MBP92_TEMPDESCS
326 	},
327 
328 	{
329 	  "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
330 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
331 	  ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS
332 	},
333 
334 	{
335 	  "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
336 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
337 	  ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS
338 	},
339 
340 	{
341 	  "MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)",
342 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
343 	  ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS
344 	},
345 
346 	{
347 	  "MacBookPro11,5",
348 	  "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch, AMD GPU)",
349 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
350 	  ASMC_MBP115_TEMPS, ASMC_MBP115_TEMPNAMES, ASMC_MBP115_TEMPDESCS
351 	},
352 
353 	{
354 	  "MacBookPro13,1", "Apple SMC MacBook Pro Retina Core i5 (late 2016, 13-inch)",
355 	  ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
356 	  ASMC_MBP131_TEMPS, ASMC_MBP131_TEMPNAMES, ASMC_MBP131_TEMPDESCS
357 	},
358 
359 	/* The Mac Mini has no SMS */
360 	{
361 	  "Macmini1,1", "Apple SMC Mac Mini",
362 	  ASMC_SMS_FUNCS_DISABLED,
363 	  ASMC_FAN_FUNCS,
364 	  ASMC_LIGHT_FUNCS_DISABLED,
365 	  ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
366 	},
367 
368 	/* The Mac Mini 2,1 has no SMS */
369 	{
370 	  "Macmini2,1", "Apple SMC Mac Mini 2,1",
371 	  ASMC_SMS_FUNCS_DISABLED,
372 	  ASMC_FAN_FUNCS,
373 	  ASMC_LIGHT_FUNCS_DISABLED,
374 	  ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS
375 	},
376 
377 	/* The Mac Mini 3,1 has no SMS */
378 	{
379 	  "Macmini3,1", "Apple SMC Mac Mini 3,1",
380 	  ASMC_SMS_FUNCS_DISABLED,
381 	  ASMC_FAN_FUNCS,
382 	  ASMC_LIGHT_FUNCS_DISABLED,
383 	  ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS
384 	},
385 
386 	/* The Mac Mini 4,1 (Mid-2010) has no SMS */
387 	{
388 	  "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)",
389 	  ASMC_SMS_FUNCS_DISABLED,
390 	  ASMC_FAN_FUNCS2,
391 	  ASMC_LIGHT_FUNCS_DISABLED,
392 	  ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS
393 	},
394 
395 	/* The Mac Mini 5,1 has no SMS */
396 	/* - same sensors as Mac Mini 5,2 */
397 	{
398 	  "Macmini5,1", "Apple SMC Mac Mini 5,1",
399 	  ASMC_SMS_FUNCS_DISABLED,
400 	  ASMC_FAN_FUNCS2,
401 	  ASMC_LIGHT_FUNCS_DISABLED,
402 	  ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
403 	},
404 
405 	/* The Mac Mini 5,2 has no SMS */
406 	{
407 	  "Macmini5,2", "Apple SMC Mac Mini 5,2",
408 	  ASMC_SMS_FUNCS_DISABLED,
409 	  ASMC_FAN_FUNCS2,
410 	  ASMC_LIGHT_FUNCS_DISABLED,
411 	  ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
412 	},
413 
414 	/* The Mac Mini 5,3 has no SMS */
415 	/* - same sensors as Mac Mini 5,2 */
416 	{
417 	  "Macmini5,3", "Apple SMC Mac Mini 5,3",
418 	  ASMC_SMS_FUNCS_DISABLED,
419 	  ASMC_FAN_FUNCS2,
420 	  ASMC_LIGHT_FUNCS_DISABLED,
421 	  ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS
422 	},
423 
424 	/* The Mac Mini 6,1 has no SMS */
425 	{
426 	  "Macmini6,1", "Apple SMC Mac Mini 6,1",
427 	  ASMC_SMS_FUNCS_DISABLED,
428 	  ASMC_FAN_FUNCS2,
429 	  ASMC_LIGHT_FUNCS_DISABLED,
430 	  ASMC_MM61_TEMPS, ASMC_MM61_TEMPNAMES, ASMC_MM61_TEMPDESCS
431 	},
432 
433 	/* The Mac Mini 6,2 has no SMS */
434 	{
435 	  "Macmini6,2", "Apple SMC Mac Mini 6,2",
436 	  ASMC_SMS_FUNCS_DISABLED,
437 	  ASMC_FAN_FUNCS2,
438 	  ASMC_LIGHT_FUNCS_DISABLED,
439 	  ASMC_MM62_TEMPS, ASMC_MM62_TEMPNAMES, ASMC_MM62_TEMPDESCS
440 	},
441 
442 	/* The Mac Mini 7,1 has no SMS */
443 	{
444 	  "Macmini7,1", "Apple SMC Mac Mini 7,1",
445 	  ASMC_SMS_FUNCS_DISABLED,
446 	  ASMC_FAN_FUNCS2,
447 	  ASMC_LIGHT_FUNCS_DISABLED,
448 	  ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS
449 	},
450 
451 	/* Idem for the Mac Pro "Quad Core" (original) */
452 	{
453 	  "MacPro1,1", "Apple SMC Mac Pro (Quad Core)",
454 	  ASMC_SMS_FUNCS_DISABLED,
455 	  ASMC_FAN_FUNCS,
456 	  ASMC_LIGHT_FUNCS_DISABLED,
457 	  ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS
458 	},
459 
460 	/* Idem for the Mac Pro (Early 2008) */
461 	{
462 	  "MacPro3,1", "Apple SMC Mac Pro (Early 2008)",
463 	  ASMC_SMS_FUNCS_DISABLED,
464 	  ASMC_FAN_FUNCS,
465 	  ASMC_LIGHT_FUNCS_DISABLED,
466 	  ASMC_MP31_TEMPS, ASMC_MP31_TEMPNAMES, ASMC_MP31_TEMPDESCS
467 	},
468 
469 	/* Idem for the Mac Pro (8-core) */
470 	{
471 	  "MacPro2", "Apple SMC Mac Pro (8-core)",
472 	  ASMC_SMS_FUNCS_DISABLED,
473 	  ASMC_FAN_FUNCS,
474 	  ASMC_LIGHT_FUNCS_DISABLED,
475 	  ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS
476 	},
477 
478 	/* Idem for the MacPro  2010*/
479 	{
480 	  "MacPro5,1", "Apple SMC MacPro (2010)",
481 	  ASMC_SMS_FUNCS_DISABLED,
482 	  ASMC_FAN_FUNCS,
483 	  ASMC_LIGHT_FUNCS_DISABLED,
484 	  ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS
485 	},
486 
487 	/* Idem for the Mac Pro 2013 (cylinder) */
488 	{
489 	  "MacPro6,1", "Apple SMC Mac Pro (2013)",
490 	  ASMC_SMS_FUNCS_DISABLED,
491 	  ASMC_FAN_FUNCS2,
492 	  ASMC_LIGHT_FUNCS_DISABLED,
493 	  ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS
494 	},
495 
496 	{
497 	  "MacBookAir1,1", "Apple SMC MacBook Air",
498 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
499 	  ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
500 	},
501 
502 	{
503 	  "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)",
504 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED,
505 	  ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS
506 	},
507 
508 	{
509 	  "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)",
510 	  ASMC_SMS_FUNCS_DISABLED,
511 	  ASMC_FAN_FUNCS2,
512 	  ASMC_LIGHT_FUNCS,
513 	  ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
514 	},
515 
516 	{
517 	  "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)",
518 	  ASMC_SMS_FUNCS_DISABLED,
519 	  ASMC_FAN_FUNCS2,
520 	  ASMC_LIGHT_FUNCS,
521 	  ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS
522 	},
523 
524 	{
525 	  "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)",
526 	  ASMC_SMS_FUNCS_DISABLED,
527 	  ASMC_FAN_FUNCS2,
528 	  ASMC_LIGHT_FUNCS,
529 	  ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
530 	},
531 
532 	{
533 	  "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)",
534 	  ASMC_SMS_FUNCS_DISABLED,
535 	  ASMC_FAN_FUNCS2,
536 	  ASMC_LIGHT_FUNCS,
537 	  ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
538 	},
539 	{
540 	  "MacBookAir6,1", "Apple SMC MacBook Air 11-inch (Early 2013)",
541 	  ASMC_SMS_FUNCS_DISABLED,
542 	  ASMC_FAN_FUNCS2,
543 	  ASMC_LIGHT_FUNCS_10BYTE,
544 	  ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
545 	},
546 	{
547 	  "MacBookAir6,2", "Apple SMC MacBook Air 13-inch (Early 2013)",
548 	  ASMC_SMS_FUNCS_DISABLED,
549 	  ASMC_FAN_FUNCS2,
550 	  ASMC_LIGHT_FUNCS_10BYTE,
551 	  ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS
552 	},
553 	{
554 	  "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)",
555 	  ASMC_SMS_FUNCS_DISABLED,
556 	  ASMC_FAN_FUNCS2,
557 	  ASMC_LIGHT_FUNCS,
558 	  ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
559 	},
560 	{
561 	  "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)",
562 	  ASMC_SMS_FUNCS_DISABLED,
563 	  ASMC_FAN_FUNCS2,
564 	  ASMC_LIGHT_FUNCS,
565 	  ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS
566 	}
567 };
568 
569 static const struct asmc_model asmc_generic_models[] = {
570 	{
571 	  .smc_model = "MacBookAir",
572 	  .smc_desc = NULL,
573 	  ASMC_SMS_FUNCS_DISABLED,
574 	  ASMC_FAN_FUNCS2,
575 	  ASMC_LIGHT_FUNCS,
576 	  ASMC_TEMPS_FUNCS_DISABLED
577 	},
578 	{
579 	  .smc_model = "MacBookPro",
580 	  .smc_desc = NULL,
581 	  ASMC_SMS_FUNCS_DISABLED,
582 	  ASMC_FAN_FUNCS2,
583 	  ASMC_LIGHT_FUNCS,
584 	  ASMC_TEMPS_FUNCS_DISABLED
585 	},
586 	{
587 	  .smc_model = "MacPro",
588 	  .smc_desc = NULL,
589 	  ASMC_SMS_FUNCS_DISABLED,
590 	  ASMC_FAN_FUNCS2,
591 	  ASMC_LIGHT_FUNCS_DISABLED,
592 	  ASMC_TEMPS_FUNCS_DISABLED
593 	},
594 	{
595 	  .smc_model = "Macmini",
596 	  .smc_desc = NULL,
597 	  ASMC_SMS_FUNCS_DISABLED,
598 	  ASMC_FAN_FUNCS2,
599 	  ASMC_LIGHT_FUNCS_DISABLED,
600 	  ASMC_TEMPS_FUNCS_DISABLED
601 	}
602 };
603 
604 #undef ASMC_SMS_FUNCS
605 #undef ASMC_SMS_FUNCS_DISABLED
606 #undef ASMC_FAN_FUNCS
607 #undef ASMC_FAN_FUNCS2
608 #undef ASMC_LIGHT_FUNCS
609 
610 /*
611  * Driver methods.
612  */
613 static device_method_t	asmc_methods[] = {
614 	DEVMETHOD(device_probe,		asmc_probe),
615 	DEVMETHOD(device_attach,	asmc_attach),
616 	DEVMETHOD(device_detach,	asmc_detach),
617 	DEVMETHOD(device_resume,	asmc_resume),
618 
619 	/* Backlight interface */
620 	DEVMETHOD(backlight_update_status, asmc_backlight_update_status),
621 	DEVMETHOD(backlight_get_status, asmc_backlight_get_status),
622 	DEVMETHOD(backlight_get_info, asmc_backlight_get_info),
623 
624 	DEVMETHOD_END
625 };
626 
627 static driver_t	asmc_driver = {
628 	"asmc",
629 	asmc_methods,
630 	sizeof(struct asmc_softc)
631 };
632 
633 /*
634  * Debugging
635  */
636 #define	_COMPONENT	ACPI_OEM
637 ACPI_MODULE_NAME("ASMC")
638 #ifdef ASMC_DEBUG
639 #define ASMC_DPRINTF(str, ...)	device_printf(dev, str, ##__VA_ARGS__)
640 #else
641 #define ASMC_DPRINTF(str, ...)
642 #endif
643 
644 /* NB: can't be const */
645 static char *asmc_ids[] = { "APP0001", NULL };
646 
647 static unsigned int light_control = 0;
648 
649 ACPI_PNP_INFO(asmc_ids);
650 DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL);
651 MODULE_DEPEND(asmc, acpi, 1, 1, 1);
652 MODULE_DEPEND(asmc, backlight, 1, 1, 1);
653 
654 static const struct asmc_model *
655 asmc_match(device_t dev)
656 {
657 	const struct asmc_model *model;
658 	char *model_name;
659 	int i;
660 
661 	model = NULL;
662 
663 	model_name = kern_getenv("smbios.system.product");
664 	if (model_name == NULL)
665 		goto out;
666 
667 	for (i = 0; i < nitems(asmc_models); i++) {
668 		if (strncmp(model_name, asmc_models[i].smc_model,
669 		    strlen(model_name)) == 0) {
670 			model = &asmc_models[i];
671 			goto out;
672 		}
673 	}
674 	for (i = 0; i < nitems(asmc_generic_models); i++) {
675 		if (strncmp(model_name, asmc_generic_models[i].smc_model,
676 		    strlen(asmc_generic_models[i].smc_model)) == 0) {
677 			model = &asmc_generic_models[i];
678 			goto out;
679 		}
680 	}
681 
682 out:
683 	freeenv(model_name);
684 	return (model);
685 }
686 
687 static int
688 asmc_probe(device_t dev)
689 {
690 	const struct asmc_model *model;
691 	const char *device_desc;
692 	int rv;
693 
694 	if (resource_disabled("asmc", 0))
695 		return (ENXIO);
696 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL);
697 	if (rv > 0)
698 		return (rv);
699 
700 	model = asmc_match(dev);
701 	if (model == NULL) {
702 		device_printf(dev, "model not recognized\n");
703 		return (ENXIO);
704 	}
705 	device_desc = model->smc_desc == NULL ?
706 	    model->smc_model : model->smc_desc;
707 	device_set_desc(dev, device_desc);
708 
709 	return (rv);
710 }
711 
712 static int
713 asmc_attach(device_t dev)
714 {
715 	int i, j;
716 	int ret;
717 	char name[2];
718 	struct asmc_softc *sc = device_get_softc(dev);
719 	struct sysctl_ctx_list *sysctlctx;
720 	struct sysctl_oid *sysctlnode;
721 	const struct asmc_model *model;
722 
723 	sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
724 	    &sc->sc_rid_port, RF_ACTIVE);
725 	if (sc->sc_ioport == NULL) {
726 		device_printf(dev, "unable to allocate IO port\n");
727 		return (ENOMEM);
728 	}
729 
730 	sysctlctx = device_get_sysctl_ctx(dev);
731 	sysctlnode = device_get_sysctl_tree(dev);
732 
733 	model = asmc_match(dev);
734 
735 	mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
736 
737 	sc->sc_model = model;
738 	asmc_init(dev);
739 
740 	/*
741 	 * dev.asmc.n.fan.* tree.
742 	 */
743 	sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
744 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
745 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Root Tree");
746 
747 	for (i = 1; i <= sc->sc_nfan; i++) {
748 		j = i - 1;
749 		name[0] = '0' + j;
750 		name[1] = 0;
751 		sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
752 		    SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name,
753 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree");
754 
755 		SYSCTL_ADD_PROC(sysctlctx,
756 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
757 		    OID_AUTO, "id",
758 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
759 		    model->smc_fan_id, "I", "Fan ID");
760 
761 		SYSCTL_ADD_PROC(sysctlctx,
762 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
763 		    OID_AUTO, "speed",
764 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
765 		    model->smc_fan_speed, "I", "Fan speed in RPM");
766 
767 		SYSCTL_ADD_PROC(sysctlctx,
768 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
769 		    OID_AUTO, "safespeed",
770 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j,
771 		    model->smc_fan_safespeed, "I", "Fan safe speed in RPM");
772 
773 		SYSCTL_ADD_PROC(sysctlctx,
774 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
775 		    OID_AUTO, "minspeed",
776 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
777 		    model->smc_fan_minspeed, "I", "Fan minimum speed in RPM");
778 
779 		SYSCTL_ADD_PROC(sysctlctx,
780 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
781 		    OID_AUTO, "maxspeed",
782 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
783 		    model->smc_fan_maxspeed, "I", "Fan maximum speed in RPM");
784 
785 		SYSCTL_ADD_PROC(sysctlctx,
786 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
787 		    OID_AUTO, "targetspeed",
788 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
789 		    model->smc_fan_targetspeed, "I", "Fan target speed in RPM");
790 
791 		SYSCTL_ADD_PROC(sysctlctx,
792 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
793 		    OID_AUTO, "manual",
794 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j,
795 		    asmc_mb_sysctl_fanmanual, "I",
796 		    "Fan manual mode (0=auto, 1=manual)");
797 	}
798 
799 	/*
800 	 * dev.asmc.n.temp tree.
801 	 */
802 	sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
803 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
804 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors");
805 
806 	for (i = 0; model->smc_temps[i]; i++) {
807 		SYSCTL_ADD_PROC(sysctlctx,
808 		    SYSCTL_CHILDREN(sc->sc_temp_tree),
809 		    OID_AUTO, model->smc_tempnames[i],
810 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i,
811 		    asmc_temp_sysctl, "I",
812 		    model->smc_tempdescs[i]);
813 	}
814 
815 	/*
816 	 * dev.asmc.n.light
817 	 */
818 	if (model->smc_light_left) {
819 		sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
820 		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
821 		    CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
822 		    "Keyboard backlight sensors");
823 
824 		SYSCTL_ADD_PROC(sysctlctx,
825 		    SYSCTL_CHILDREN(sc->sc_light_tree),
826 		    OID_AUTO, "left",
827 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
828 		    dev, 0, model->smc_light_left, "I",
829 		    "Keyboard backlight left sensor");
830 
831 		SYSCTL_ADD_PROC(sysctlctx,
832 		    SYSCTL_CHILDREN(sc->sc_light_tree),
833 		    OID_AUTO, "right",
834 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0,
835 		    model->smc_light_right, "I",
836 		    "Keyboard backlight right sensor");
837 
838 		SYSCTL_ADD_PROC(sysctlctx,
839 		    SYSCTL_CHILDREN(sc->sc_light_tree),
840 		    OID_AUTO, "control",
841 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
842 		    dev, 0, model->smc_light_control, "I",
843 		    "Keyboard backlight brightness control");
844 
845 		sc->sc_kbd_bkl = backlight_register("asmc", dev);
846 		if (sc->sc_kbd_bkl == NULL) {
847 			device_printf(dev, "Can not register backlight\n");
848 			ret = ENXIO;
849 			goto err;
850 		}
851 	}
852 
853 #ifdef ASMC_DEBUG
854 	/*
855 	 * Raw SMC key access for debugging.
856 	 */
857 	sc->sc_raw_tree = SYSCTL_ADD_NODE(sysctlctx,
858 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
859 	    "raw", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Raw SMC key access");
860 
861 	SYSCTL_ADD_PROC(sysctlctx,
862 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
863 	    OID_AUTO, "key",
864 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
865 	    dev, 0, asmc_raw_key_sysctl, "A",
866 	    "SMC key name (4 chars)");
867 
868 	SYSCTL_ADD_PROC(sysctlctx,
869 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
870 	    OID_AUTO, "value",
871 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
872 	    dev, 0, asmc_raw_value_sysctl, "A",
873 	    "SMC key value (hex string)");
874 
875 	SYSCTL_ADD_PROC(sysctlctx,
876 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
877 	    OID_AUTO, "len",
878 	    CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
879 	    dev, 0, asmc_raw_len_sysctl, "CU",
880 	    "SMC key value length");
881 
882 	SYSCTL_ADD_PROC(sysctlctx,
883 	    SYSCTL_CHILDREN(sc->sc_raw_tree),
884 	    OID_AUTO, "type",
885 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
886 	    dev, 0, asmc_raw_type_sysctl, "A",
887 	    "SMC key type (4 chars)");
888 #endif
889 
890 	if (model->smc_sms_x == NULL)
891 		goto nosms;
892 
893 	/*
894 	 * dev.asmc.n.sms tree.
895 	 */
896 	sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
897 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
898 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sudden Motion Sensor");
899 
900 	SYSCTL_ADD_PROC(sysctlctx,
901 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
902 	    OID_AUTO, "x",
903 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
904 	    dev, 0, model->smc_sms_x, "I",
905 	    "Sudden Motion Sensor X value");
906 
907 	SYSCTL_ADD_PROC(sysctlctx,
908 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
909 	    OID_AUTO, "y",
910 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
911 	    dev, 0, model->smc_sms_y, "I",
912 	    "Sudden Motion Sensor Y value");
913 
914 	SYSCTL_ADD_PROC(sysctlctx,
915 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
916 	    OID_AUTO, "z",
917 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
918 	    dev, 0, model->smc_sms_z, "I",
919 	    "Sudden Motion Sensor Z value");
920 
921 	/*
922 	 * Need a taskqueue to send devctl_notify() events
923 	 * when the SMS interrupt us.
924 	 *
925 	 * PI_REALTIME is used due to the sensitivity of the
926 	 * interrupt. An interrupt from the SMS means that the
927 	 * disk heads should be turned off as quickly as possible.
928 	 *
929 	 * We only need to do this for the non INTR_FILTER case.
930 	 */
931 	sc->sc_sms_tq = NULL;
932 	TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
933 	sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
934 	    taskqueue_thread_enqueue, &sc->sc_sms_tq);
935 	taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
936 	    device_get_nameunit(dev));
937 	/*
938 	 * Allocate an IRQ for the SMS.
939 	 */
940 	sc->sc_rid_irq = 0;
941 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq,
942 	    RF_ACTIVE);
943 	if (sc->sc_irq == NULL) {
944 		device_printf(dev, "unable to allocate IRQ resource\n");
945 		ret = ENXIO;
946 		goto err;
947 	}
948 
949 	ret = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE,
950 	    asmc_sms_intrfast, NULL, dev, &sc->sc_cookie);
951 	if (ret) {
952 		device_printf(dev, "unable to setup SMS IRQ\n");
953 		goto err;
954 	}
955 
956 nosms:
957 	return (0);
958 
959 err:
960 	asmc_detach(dev);
961 
962 	return (ret);
963 }
964 
965 static int
966 asmc_detach(device_t dev)
967 {
968 	struct asmc_softc *sc = device_get_softc(dev);
969 
970 	if (sc->sc_kbd_bkl != NULL)
971 		backlight_destroy(sc->sc_kbd_bkl);
972 
973 	/* Free sensor key arrays */
974 	for (int i = 0; i < sc->sc_voltage_count; i++)
975 		free(sc->sc_voltage_sensors[i], M_DEVBUF);
976 	for (int i = 0; i < sc->sc_current_count; i++)
977 		free(sc->sc_current_sensors[i], M_DEVBUF);
978 	for (int i = 0; i < sc->sc_power_count; i++)
979 		free(sc->sc_power_sensors[i], M_DEVBUF);
980 	for (int i = 0; i < sc->sc_light_count; i++)
981 		free(sc->sc_light_sensors[i], M_DEVBUF);
982 
983 	if (sc->sc_sms_tq) {
984 		taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
985 		taskqueue_free(sc->sc_sms_tq);
986 		sc->sc_sms_tq = NULL;
987 	}
988 	if (sc->sc_cookie) {
989 		bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
990 		sc->sc_cookie = NULL;
991 	}
992 	if (sc->sc_irq) {
993 		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
994 		    sc->sc_irq);
995 		sc->sc_irq = NULL;
996 	}
997 	if (sc->sc_ioport) {
998 		bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
999 		    sc->sc_ioport);
1000 		sc->sc_ioport = NULL;
1001 	}
1002 	if (mtx_initialized(&sc->sc_mtx)) {
1003 		mtx_destroy(&sc->sc_mtx);
1004 	}
1005 
1006 	return (0);
1007 }
1008 
1009 static int
1010 asmc_resume(device_t dev)
1011 {
1012 	uint8_t buf[2];
1013 
1014 	buf[0] = light_control;
1015 	buf[1] = 0x00;
1016 	asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
1017 
1018 	return (0);
1019 }
1020 
1021 #ifdef ASMC_DEBUG
1022 void
1023 asmc_dumpall(device_t dev)
1024 {
1025 	struct asmc_softc *sc = device_get_softc(dev);
1026 	int i;
1027 
1028 	if (sc->sc_nkeys == 0) {
1029 		device_printf(dev, "asmc_dumpall: key count not available\n");
1030 		return;
1031 	}
1032 
1033 	device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys);
1034 	for (i = 0; i < sc->sc_nkeys; i++)
1035 		asmc_key_dump(dev, i);
1036 }
1037 #endif
1038 
1039 static int
1040 asmc_init(device_t dev)
1041 {
1042 	struct asmc_softc *sc = device_get_softc(dev);
1043 	struct sysctl_ctx_list *sysctlctx;
1044 	uint8_t buf[6];
1045 	int i, error = 1;
1046 
1047 	sysctlctx = device_get_sysctl_ctx(dev);
1048 
1049 	error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6);
1050 	if (error != 0)
1051 		goto out_err;
1052 	device_printf(dev, "SMC revision: %x.%x%x%x\n", buf[0], buf[1], buf[2],
1053 	    ntohs(*(uint16_t *)buf + 4));
1054 
1055 	if (sc->sc_model->smc_sms_x == NULL)
1056 		goto nosms;
1057 
1058 	/*
1059 	 * We are ready to receive interrupts from the SMS.
1060 	 */
1061 	buf[0] = 0x01;
1062 	ASMC_DPRINTF(("intok key\n"));
1063 	asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
1064 	DELAY(50);
1065 
1066 	/*
1067 	 * Initiate the polling intervals.
1068 	 */
1069 	buf[0] = 20; /* msecs */
1070 	ASMC_DPRINTF(("low int key\n"));
1071 	asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
1072 	DELAY(200);
1073 
1074 	buf[0] = 20; /* msecs */
1075 	ASMC_DPRINTF(("high int key\n"));
1076 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
1077 	DELAY(200);
1078 
1079 	buf[0] = 0x00;
1080 	buf[1] = 0x60;
1081 	ASMC_DPRINTF(("sms low key\n"));
1082 	asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
1083 	DELAY(200);
1084 
1085 	buf[0] = 0x01;
1086 	buf[1] = 0xc0;
1087 	ASMC_DPRINTF(("sms high key\n"));
1088 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
1089 	DELAY(200);
1090 
1091 	/*
1092 	 * I'm not sure what this key does, but it seems to be
1093 	 * required.
1094 	 */
1095 	buf[0] = 0x01;
1096 	ASMC_DPRINTF(("sms flag key\n"));
1097 	asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
1098 	DELAY(100);
1099 
1100 	sc->sc_sms_intr_works = 0;
1101 
1102 	/*
1103 	 * Retry SMS initialization 1000 times
1104 	 * (takes approx. 2 seconds in worst case)
1105 	 */
1106 	for (i = 0; i < 1000; i++) {
1107 		if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
1108 		    (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
1109 			error = 0;
1110 			sc->sc_sms_intr_works = 1;
1111 			goto out;
1112 		}
1113 		buf[0] = ASMC_SMS_INIT1;
1114 		buf[1] = ASMC_SMS_INIT2;
1115 		ASMC_DPRINTF(("sms key\n"));
1116 		asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
1117 		DELAY(50);
1118 	}
1119 	device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
1120 
1121 out:
1122 	asmc_sms_calibrate(dev);
1123 nosms:
1124 	/* Wake-on-LAN convenience sysctl */
1125 	if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) {
1126 		SYSCTL_ADD_PROC(sysctlctx,
1127 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1128 		    OID_AUTO, "wol",
1129 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
1130 		    dev, 0, asmc_wol_sysctl, "I",
1131 		    "Wake-on-LAN enable (0=off, 1=on)");
1132 	}
1133 
1134 	sc->sc_nfan = asmc_fan_count(dev);
1135 	if (sc->sc_nfan > ASMC_MAXFANS) {
1136 		device_printf(dev,
1137 		    "more than %d fans were detected. Please report this.\n",
1138 		    ASMC_MAXFANS);
1139 		sc->sc_nfan = ASMC_MAXFANS;
1140 	}
1141 
1142 	/*
1143 	 * Read and cache the number of SMC keys (32 bit buffer)
1144 	 */
1145 	if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) {
1146 		sc->sc_nkeys = be32dec(buf);
1147 		if (bootverbose)
1148 			device_printf(dev, "number of keys: %d\n",
1149 			    sc->sc_nkeys);
1150 	} else {
1151 		sc->sc_nkeys = 0;
1152 	}
1153 
1154 	/*
1155 	 * Auto-detect and register voltage/current/power/ambient sensors.
1156 	 * Scans SMC keys and creates sysctls for detected sensors.
1157 	 */
1158 	asmc_detect_sensors(dev);
1159 
1160 out_err:
1161 #ifdef ASMC_DEBUG
1162 	asmc_dumpall(dev);
1163 #endif
1164 	return (error);
1165 }
1166 
1167 /*
1168  * We need to make sure that the SMC acks the byte sent.
1169  * Just wait up to (amount * 10)  ms.
1170  */
1171 static int
1172 asmc_wait_ack(device_t dev, uint8_t val, int amount)
1173 {
1174 	struct asmc_softc *sc = device_get_softc(dev);
1175 	u_int i;
1176 
1177 	val = val & ASMC_STATUS_MASK;
1178 
1179 	for (i = 0; i < amount; i++) {
1180 		if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
1181 			return (0);
1182 		DELAY(10);
1183 	}
1184 
1185 	return (1);
1186 }
1187 
1188 /*
1189  * We need to make sure that the SMC acks the byte sent.
1190  * Just wait up to 100 ms.
1191  */
1192 static int
1193 asmc_wait(device_t dev, uint8_t val)
1194 {
1195 #ifdef ASMC_DEBUG
1196 	struct asmc_softc *sc;
1197 #endif
1198 
1199 	if (asmc_wait_ack(dev, val, 1000) == 0)
1200 		return (0);
1201 
1202 #ifdef ASMC_DEBUG
1203 	sc = device_get_softc(dev);
1204 
1205 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__,
1206 	    val & ASMC_STATUS_MASK, ASMC_CMDPORT_READ(sc));
1207 #endif
1208 	return (1);
1209 }
1210 
1211 /*
1212  * Send the given command, retrying up to 10 times if
1213  * the acknowledgement fails.
1214  */
1215 static int
1216 asmc_command(device_t dev, uint8_t command)
1217 {
1218 	int i;
1219 	struct asmc_softc *sc = device_get_softc(dev);
1220 
1221 	for (i = 0; i < 10; i++) {
1222 		ASMC_CMDPORT_WRITE(sc, command);
1223 		if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
1224 			return (0);
1225 		}
1226 	}
1227 
1228 #ifdef ASMC_DEBUG
1229 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
1230 	    ASMC_CMDPORT_READ(sc));
1231 #endif
1232 	return (1);
1233 }
1234 
1235 static int
1236 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1237 {
1238 	int i, error = 1, try = 0;
1239 	struct asmc_softc *sc = device_get_softc(dev);
1240 
1241 	mtx_lock_spin(&sc->sc_mtx);
1242 
1243 begin:
1244 	if (asmc_command(dev, ASMC_CMDREAD))
1245 		goto out;
1246 
1247 	for (i = 0; i < 4; i++) {
1248 		ASMC_DATAPORT_WRITE(sc, key[i]);
1249 		if (asmc_wait(dev, 0x04))
1250 			goto out;
1251 	}
1252 
1253 	ASMC_DATAPORT_WRITE(sc, len);
1254 
1255 	for (i = 0; i < len; i++) {
1256 		if (asmc_wait(dev, 0x05))
1257 			goto out;
1258 		buf[i] = ASMC_DATAPORT_READ(sc);
1259 	}
1260 
1261 	error = 0;
1262 out:
1263 	if (error) {
1264 		if (++try < 10)
1265 			goto begin;
1266 		device_printf(dev, "%s for key %s failed %d times, giving up\n",
1267 		    __func__, key, try);
1268 	}
1269 
1270 	mtx_unlock_spin(&sc->sc_mtx);
1271 
1272 	return (error);
1273 }
1274 
1275 #ifdef ASMC_DEBUG
1276 static int
1277 asmc_key_dump(device_t dev, int number)
1278 {
1279 	struct asmc_softc *sc = device_get_softc(dev);
1280 	char key[ASMC_KEYLEN + 1] = { 0 };
1281 	char type[ASMC_KEYINFO_RESPLEN + 1] = { 0 };
1282 	uint8_t index[4];
1283 	uint8_t v[ASMC_MAXVAL];
1284 	uint8_t maxlen;
1285 	int i, error = 1, try = 0;
1286 
1287 	mtx_lock_spin(&sc->sc_mtx);
1288 
1289 	index[0] = (number >> 24) & 0xff;
1290 	index[1] = (number >> 16) & 0xff;
1291 	index[2] = (number >> 8) & 0xff;
1292 	index[3] = number & 0xff;
1293 
1294 begin:
1295 	if (asmc_command(dev, ASMC_CMDGETBYINDEX))
1296 		goto out;
1297 
1298 	for (i = 0; i < ASMC_KEYLEN; i++) {
1299 		ASMC_DATAPORT_WRITE(sc, index[i]);
1300 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1301 			goto out;
1302 	}
1303 
1304 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN);
1305 
1306 	for (i = 0; i < ASMC_KEYLEN; i++) {
1307 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1308 			goto out;
1309 		key[i] = ASMC_DATAPORT_READ(sc);
1310 	}
1311 
1312 	/* Get key info (length + type). */
1313 	if (asmc_command(dev, ASMC_CMDGETINFO))
1314 		goto out;
1315 
1316 	for (i = 0; i < ASMC_KEYLEN; i++) {
1317 		ASMC_DATAPORT_WRITE(sc, key[i]);
1318 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1319 			goto out;
1320 	}
1321 
1322 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
1323 
1324 	for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
1325 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1326 			goto out;
1327 		type[i] = ASMC_DATAPORT_READ(sc);
1328 	}
1329 
1330 	error = 0;
1331 out:
1332 	if (error) {
1333 		if (++try < ASMC_MAXRETRIES)
1334 			goto begin;
1335 		device_printf(dev,
1336 		    "%s for key %d failed %d times, giving up\n",
1337 		    __func__, number, try);
1338 	}
1339 	mtx_unlock_spin(&sc->sc_mtx);
1340 
1341 	if (error)
1342 		return (error);
1343 
1344 	maxlen = type[0];
1345 	type[0] = ' ';
1346 	type[5] = '\0';
1347 	if (maxlen > sizeof(v))
1348 		maxlen = sizeof(v);
1349 
1350 	memset(v, 0, sizeof(v));
1351 	error = asmc_key_read(dev, key, v, maxlen);
1352 	if (error)
1353 		return (error);
1354 
1355 	device_printf(dev, "key %d: %s, type%s (len %d), data",
1356 	    number, key, type, maxlen);
1357 	for (i = 0; i < maxlen; i++)
1358 		printf(" %02x", v[i]);
1359 	printf("\n");
1360 
1361 	return (0);
1362 }
1363 #endif /* ASMC_DEBUG */
1364 
1365 /*
1366  * Get key info (length and type) from SMC using command 0x13.
1367  * If len is non-NULL, stores the key's value length.
1368  * If type is non-NULL, stores the 4-char type string (must be at least 5 bytes).
1369  */
1370 static int
1371 asmc_key_getinfo(device_t dev, const char *key, uint8_t *len, char *type)
1372 {
1373 	struct asmc_softc *sc = device_get_softc(dev);
1374 	uint8_t info[ASMC_KEYINFO_RESPLEN];
1375 	int i, error = -1, try = 0;
1376 
1377 	mtx_lock_spin(&sc->sc_mtx);
1378 
1379 begin:
1380 	if (asmc_command(dev, ASMC_CMDGETINFO))
1381 		goto out;
1382 
1383 	for (i = 0; i < ASMC_KEYLEN; i++) {
1384 		ASMC_DATAPORT_WRITE(sc, key[i]);
1385 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1386 			goto out;
1387 	}
1388 
1389 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
1390 
1391 	for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
1392 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1393 			goto out;
1394 		info[i] = ASMC_DATAPORT_READ(sc);
1395 	}
1396 
1397 	error = 0;
1398 out:
1399 	if (error && ++try < ASMC_MAXRETRIES)
1400 		goto begin;
1401 	mtx_unlock_spin(&sc->sc_mtx);
1402 
1403 	if (error == 0) {
1404 		if (len != NULL)
1405 			*len = info[0];
1406 		if (type != NULL) {
1407 			for (i = 0; i < ASMC_TYPELEN; i++)
1408 				type[i] = info[i + 1];
1409 			type[ASMC_TYPELEN] = '\0';
1410 		}
1411 	}
1412 	return (error);
1413 }
1414 
1415 #ifdef ASMC_DEBUG
1416 /*
1417  * Raw SMC key access sysctls - enables reading/writing any SMC key by name
1418  * Usage:
1419  *   sysctl dev.asmc.0.raw.key=AUPO   # Set key, auto-detects length
1420  *   sysctl dev.asmc.0.raw.value      # Read current value (hex bytes)
1421  *   sysctl dev.asmc.0.raw.value=01   # Write new value
1422  */
1423 static int
1424 asmc_raw_key_sysctl(SYSCTL_HANDLER_ARGS)
1425 {
1426 	device_t dev = (device_t) arg1;
1427 	struct asmc_softc *sc = device_get_softc(dev);
1428 	char newkey[ASMC_KEYLEN + 1];
1429 	uint8_t keylen;
1430 	int error;
1431 
1432 	strlcpy(newkey, sc->sc_rawkey, sizeof(newkey));
1433 	error = sysctl_handle_string(oidp, newkey, sizeof(newkey), req);
1434 	if (error || req->newptr == NULL)
1435 		return (error);
1436 
1437 	if (strlen(newkey) != ASMC_KEYLEN)
1438 		return (EINVAL);
1439 
1440 	/* Get key info to auto-detect length and type */
1441 	if (asmc_key_getinfo(dev, newkey, &keylen, sc->sc_rawtype) != 0)
1442 		return (ENOENT);
1443 
1444 	if (keylen > ASMC_MAXVAL)
1445 		keylen = ASMC_MAXVAL;
1446 
1447 	strlcpy(sc->sc_rawkey, newkey, sizeof(sc->sc_rawkey));
1448 	sc->sc_rawlen = keylen;
1449 	memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval));
1450 
1451 	/* Read the key value */
1452 	asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen);
1453 
1454 	return (0);
1455 }
1456 
1457 static int
1458 asmc_raw_value_sysctl(SYSCTL_HANDLER_ARGS)
1459 {
1460 	device_t dev = (device_t) arg1;
1461 	struct asmc_softc *sc = device_get_softc(dev);
1462 	char hexbuf[ASMC_MAXVAL * 2 + 1];
1463 	int error, i;
1464 
1465 	/* Refresh from SMC if a key has been selected. */
1466 	if (sc->sc_rawkey[0] != '\0') {
1467 		asmc_key_read(dev, sc->sc_rawkey, sc->sc_rawval,
1468 		    sc->sc_rawlen > 0 ? sc->sc_rawlen : ASMC_MAXVAL);
1469 	}
1470 
1471 	/* Format as hex string */
1472 	for (i = 0; i < sc->sc_rawlen && i < ASMC_MAXVAL; i++)
1473 		snprintf(hexbuf + i * 2, 3, "%02x", sc->sc_rawval[i]);
1474 	hexbuf[i * 2] = '\0';
1475 
1476 	error = sysctl_handle_string(oidp, hexbuf, sizeof(hexbuf), req);
1477 	if (error || req->newptr == NULL)
1478 		return (error);
1479 
1480 	/* Reject writes until a key is selected via raw.key. */
1481 	if (sc->sc_rawkey[0] == '\0')
1482 		return (EINVAL);
1483 
1484 	memset(sc->sc_rawval, 0, sizeof(sc->sc_rawval));
1485 	for (i = 0; i < sc->sc_rawlen && hexbuf[i*2] && hexbuf[i*2+1]; i++) {
1486 		unsigned int val;
1487 		char tmp[3] = { hexbuf[i*2], hexbuf[i*2+1], 0 };
1488 		if (sscanf(tmp, "%02x", &val) == 1)
1489 			sc->sc_rawval[i] = (uint8_t)val;
1490 	}
1491 
1492 	if (asmc_key_write(dev, sc->sc_rawkey, sc->sc_rawval, sc->sc_rawlen) != 0)
1493 		return (EIO);
1494 
1495 	return (0);
1496 }
1497 
1498 static int
1499 asmc_raw_len_sysctl(SYSCTL_HANDLER_ARGS)
1500 {
1501 	device_t dev = (device_t) arg1;
1502 	struct asmc_softc *sc = device_get_softc(dev);
1503 
1504 	return (sysctl_handle_8(oidp, &sc->sc_rawlen, 0, req));
1505 }
1506 
1507 static int
1508 asmc_raw_type_sysctl(SYSCTL_HANDLER_ARGS)
1509 {
1510 	device_t dev = (device_t) arg1;
1511 	struct asmc_softc *sc = device_get_softc(dev);
1512 
1513 	return (sysctl_handle_string(oidp, sc->sc_rawtype,
1514 	    sizeof(sc->sc_rawtype), req));
1515 }
1516 #endif
1517 
1518 /*
1519  * Convert signed fixed-point SMC values to milli-units.
1520  * Format "spXY" means signed with X integer bits and Y fraction bits.
1521  */
1522 static int
1523 asmc_sp78_to_milli(const uint8_t *buf)
1524 {
1525 	int16_t val = (int16_t)be16dec(buf);
1526 
1527 	return ((int)val * 1000) / 256;
1528 }
1529 
1530 static int
1531 asmc_sp87_to_milli(const uint8_t *buf)
1532 {
1533 	int16_t val = (int16_t)be16dec(buf);
1534 
1535 	return ((int)val * 1000) / 128;
1536 }
1537 
1538 static int
1539 asmc_sp4b_to_milli(const uint8_t *buf)
1540 {
1541 	int16_t val = (int16_t)be16dec(buf);
1542 
1543 	return ((int)val * 1000) / 2048;
1544 }
1545 
1546 static int
1547 asmc_sp5a_to_milli(const uint8_t *buf)
1548 {
1549 	int16_t val = (int16_t)be16dec(buf);
1550 
1551 	return ((int)val * 1000) / 1024;
1552 }
1553 
1554 static int
1555 asmc_sp69_to_milli(const uint8_t *buf)
1556 {
1557 	int16_t val = (int16_t)be16dec(buf);
1558 
1559 	return ((int)val * 1000) / 512;
1560 }
1561 
1562 static int
1563 asmc_sp96_to_milli(const uint8_t *buf)
1564 {
1565 	int16_t val = (int16_t)be16dec(buf);
1566 
1567 	return ((int)val * 1000) / 64;
1568 }
1569 
1570 static int
1571 asmc_sp2d_to_milli(const uint8_t *buf)
1572 {
1573 	int16_t val = (int16_t)be16dec(buf);
1574 
1575 	return ((int)val * 1000) / 8192;
1576 }
1577 
1578 static bool
1579 asmc_sensor_type_supported(const char *type)
1580 {
1581 
1582 	return (strncmp(type, "sp78", 4) == 0 ||
1583 	    strncmp(type, "sp87", 4) == 0 ||
1584 	    strncmp(type, "sp4b", 4) == 0 ||
1585 	    strncmp(type, "sp5a", 4) == 0 ||
1586 	    strncmp(type, "sp69", 4) == 0 ||
1587 	    strncmp(type, "sp96", 4) == 0 ||
1588 	    strncmp(type, "sp2d", 4) == 0 ||
1589 	    strncmp(type, "ui16", 4) == 0);
1590 }
1591 
1592 /*
1593  * Generic sensor value reader with automatic type conversion.
1594  * Reads an SMC key, detects its type, and converts to millivalue.
1595  */
1596 static int
1597 asmc_sensor_read(device_t dev, const char *key, int *millivalue)
1598 {
1599 	uint8_t buf[2];
1600 	char type[ASMC_TYPELEN + 1];
1601 	uint8_t len;
1602 	int error;
1603 
1604 	error = asmc_key_getinfo(dev, key, &len, type);
1605 	if (error != 0)
1606 		return (error);
1607 
1608 	if (len != 2) {
1609 		if (bootverbose)
1610 			device_printf(dev,
1611 			    "%s: key %s unexpected length %d\n",
1612 			    __func__, key, len);
1613 		return (ENXIO);
1614 	}
1615 
1616 	error = asmc_key_read(dev, key, buf, sizeof(buf));
1617 	if (error != 0)
1618 		return (error);
1619 
1620 	if (strncmp(type, "sp78", 4) == 0) {
1621 		*millivalue = asmc_sp78_to_milli(buf);
1622 	} else if (strncmp(type, "sp87", 4) == 0) {
1623 		*millivalue = asmc_sp87_to_milli(buf);
1624 	} else if (strncmp(type, "sp4b", 4) == 0) {
1625 		*millivalue = asmc_sp4b_to_milli(buf);
1626 	} else if (strncmp(type, "sp5a", 4) == 0) {
1627 		*millivalue = asmc_sp5a_to_milli(buf);
1628 	} else if (strncmp(type, "sp69", 4) == 0) {
1629 		*millivalue = asmc_sp69_to_milli(buf);
1630 	} else if (strncmp(type, "sp96", 4) == 0) {
1631 		*millivalue = asmc_sp96_to_milli(buf);
1632 	} else if (strncmp(type, "sp2d", 4) == 0) {
1633 		*millivalue = asmc_sp2d_to_milli(buf);
1634 	} else if (strncmp(type, "ui16", 4) == 0) {
1635 		*millivalue = be16dec(buf);
1636 	} else {
1637 		if (bootverbose)
1638 			device_printf(dev,
1639 			    "%s: unknown type '%s' for key %s\n",
1640 			    __func__, type, key);
1641 		return (ENXIO);
1642 	}
1643 
1644 	return (0);
1645 }
1646 
1647 /*
1648  * Generic sensor sysctl handler for voltage/current/power/light sensors.
1649  * arg2 encodes: sensor_type (high byte) | sensor_index (low byte)
1650  * Sensor types: 'V'=voltage, 'I'=current, 'P'=power, 'L'=light
1651  */
1652 static int
1653 asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS)
1654 {
1655 	device_t dev = (device_t) arg1;
1656 	struct asmc_softc *sc = device_get_softc(dev);
1657 	int error, val;
1658 	int sensor_type = (arg2 >> 8) & 0xFF;
1659 	int sensor_idx = arg2 & 0xFF;
1660 	const char *key = NULL;
1661 
1662 	/* Select sensor based on type and index */
1663 	switch (sensor_type) {
1664 	case 'V':  /* Voltage */
1665 		if (sensor_idx < sc->sc_voltage_count)
1666 			key = sc->sc_voltage_sensors[sensor_idx];
1667 		break;
1668 	case 'I':  /* Current */
1669 		if (sensor_idx < sc->sc_current_count)
1670 			key = sc->sc_current_sensors[sensor_idx];
1671 		break;
1672 	case 'P':  /* Power */
1673 		if (sensor_idx < sc->sc_power_count)
1674 			key = sc->sc_power_sensors[sensor_idx];
1675 		break;
1676 	case 'L':  /* Light */
1677 		if (sensor_idx < sc->sc_light_count)
1678 			key = sc->sc_light_sensors[sensor_idx];
1679 		break;
1680 	default:
1681 		return (EINVAL);
1682 	}
1683 
1684 	if (key == NULL)
1685 		return (ENOENT);
1686 
1687 	error = asmc_sensor_read(dev, key, &val);
1688 	if (error != 0)
1689 		return (error);
1690 
1691 	return (sysctl_handle_int(oidp, &val, 0, req));
1692 }
1693 
1694 /*
1695  * Detect and register voltage/current/power/ambient sensors.
1696  * Scans all SMC keys and identifies sensor keys by prefix.
1697  * Returns 0 on success, -1 on error.
1698  */
1699 static int
1700 asmc_detect_sensors(device_t dev)
1701 {
1702 	struct asmc_softc *sc = device_get_softc(dev);
1703 	struct sysctl_ctx_list *sysctlctx;
1704 	struct sysctl_oid *tree_node;
1705 	char key[ASMC_KEYLEN + 1];
1706 	char type[ASMC_TYPELEN + 1];
1707 	uint8_t len;
1708 	unsigned int nkeys;
1709 	unsigned int i;
1710 	int error;
1711 	char *sensor_key;
1712 
1713 	/* Initialize counts */
1714 	sc->sc_voltage_count = 0;
1715 	sc->sc_current_count = 0;
1716 	sc->sc_power_count = 0;
1717 	sc->sc_light_count = 0;
1718 
1719 	if (sc->sc_nkeys == 0)
1720 		return (0);
1721 	nkeys = sc->sc_nkeys;
1722 
1723 	/* Scan all keys for voltage/current/power/ambient light sensors */
1724 	for (i = 0; i < nkeys; i++) {
1725 		/* Get key name by index */
1726 		error = asmc_key_dump_by_index(dev, i, key, type, &len);
1727 		if (error != 0)
1728 			continue;
1729 		if (!asmc_sensor_type_supported(type))
1730 			continue;
1731 
1732 		/* Voltage sensors (VC*, VD*, VG*, VP*, VI*) */
1733 		if (key[0] == 'V' && (key[1] == 'C' || key[1] == 'D' ||
1734 		    key[1] == 'G' || key[1] == 'P' || key[1] == 'I') &&
1735 		    len == 2) {
1736 			if (sc->sc_voltage_count >= ASMC_MAX_SENSORS)
1737 				continue;
1738 			sensor_key = malloc(ASMC_KEYLEN + 1,
1739 			    M_DEVBUF, M_WAITOK);
1740 			memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1741 			sc->sc_voltage_sensors[sc->sc_voltage_count++] =
1742 			    sensor_key;
1743 		} else if (key[0] == 'I' && (key[1] == 'C' ||
1744 		    key[1] == 'D' || key[1] == 'G' || key[1] == 'M' ||
1745 		    key[1] == 'N' || key[1] == 'O' || key[1] == 'H' ||
1746 		    key[1] == 'P' || key[1] == 'B' || key[1] == 'A' ||
1747 		    key[1] == 'L') && len == 2) {
1748 			/* Current sensors */
1749 			if (sc->sc_current_count >= ASMC_MAX_SENSORS)
1750 				continue;
1751 			sensor_key = malloc(ASMC_KEYLEN + 1,
1752 			    M_DEVBUF, M_WAITOK);
1753 			memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1754 			sc->sc_current_sensors[sc->sc_current_count++] =
1755 			    sensor_key;
1756 		} else if (key[0] == 'P' && (key[1] == 'C' ||
1757 		    key[1] == 'D' || key[1] == 'N' || key[1] == 'S' ||
1758 		    key[1] == 'T' || key[1] == 'H' || key[1] == 'F' ||
1759 		    key[1] == 'Z' || key[1] == 'z') && len == 2) {
1760 			/* Power sensors */
1761 			if (sc->sc_power_count >= ASMC_MAX_SENSORS)
1762 				continue;
1763 			sensor_key = malloc(ASMC_KEYLEN + 1,
1764 			    M_DEVBUF, M_WAITOK);
1765 			memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1766 			sc->sc_power_sensors[sc->sc_power_count++] =
1767 			    sensor_key;
1768 		} else if (key[0] == 'A' && key[1] == 'L' &&
1769 		    (key[2] == 'V' || key[2] == 'S') && len == 2) {
1770 			/* Ambient light sensors */
1771 			if (sc->sc_light_count >= ASMC_MAX_SENSORS)
1772 				continue;
1773 			sensor_key = malloc(ASMC_KEYLEN + 1,
1774 			    M_DEVBUF, M_WAITOK);
1775 			memcpy(sensor_key, key, ASMC_KEYLEN + 1);
1776 			sc->sc_light_sensors[sc->sc_light_count++] =
1777 			    sensor_key;
1778 		}
1779 	}
1780 
1781 	if (bootverbose)
1782 		device_printf(dev,
1783 		    "detected %d voltage, %d current, "
1784 		    "%d power, %d light sensors\n",
1785 		    sc->sc_voltage_count, sc->sc_current_count,
1786 		    sc->sc_power_count, sc->sc_light_count);
1787 
1788 	/* Register sysctls for detected sensors */
1789 	sysctlctx = device_get_sysctl_ctx(dev);
1790 
1791 	/* Voltage sensors */
1792 	if (sc->sc_voltage_count > 0) {
1793 		tree_node = SYSCTL_ADD_NODE(sysctlctx,
1794 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1795 		    "voltage", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Voltage sensors (millivolts)");
1796 
1797 		for (i = 0; i < sc->sc_voltage_count; i++) {
1798 			SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node),
1799 			    OID_AUTO, sc->sc_voltage_sensors[i],
1800 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1801 			    dev, ('V' << 8) | i, asmc_sensor_sysctl, "I",
1802 			    "Voltage sensor (millivolts)");
1803 		}
1804 	}
1805 
1806 	/* Current sensors */
1807 	if (sc->sc_current_count > 0) {
1808 		tree_node = SYSCTL_ADD_NODE(sysctlctx,
1809 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1810 		    "current", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Current sensors (milliamps)");
1811 
1812 		for (i = 0; i < sc->sc_current_count; i++) {
1813 			SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node),
1814 			    OID_AUTO, sc->sc_current_sensors[i],
1815 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1816 			    dev, ('I' << 8) | i, asmc_sensor_sysctl, "I",
1817 			    "Current sensor (milliamps)");
1818 		}
1819 	}
1820 
1821 	/* Power sensors */
1822 	if (sc->sc_power_count > 0) {
1823 		tree_node = SYSCTL_ADD_NODE(sysctlctx,
1824 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1825 		    "power", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Power sensors (milliwatts)");
1826 
1827 		for (i = 0; i < sc->sc_power_count; i++) {
1828 			SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node),
1829 			    OID_AUTO, sc->sc_power_sensors[i],
1830 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1831 			    dev, ('P' << 8) | i, asmc_sensor_sysctl, "I",
1832 			    "Power sensor (milliwatts)");
1833 		}
1834 	}
1835 
1836 	/* Ambient light sensors */
1837 	if (sc->sc_light_count > 0) {
1838 		tree_node = SYSCTL_ADD_NODE(sysctlctx,
1839 		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
1840 		    "ambient", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Ambient light sensors");
1841 
1842 		for (i = 0; i < sc->sc_light_count; i++) {
1843 			SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(tree_node),
1844 			    OID_AUTO, sc->sc_light_sensors[i],
1845 			    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
1846 			    dev, ('L' << 8) | i, asmc_sensor_sysctl, "I",
1847 			    "Light sensor value");
1848 		}
1849 	}
1850 
1851 	return (0);
1852 }
1853 
1854 /*
1855  * Helper function to get key info by index (for sensor detection).
1856  */
1857 static int
1858 asmc_key_dump_by_index(device_t dev, int index, char *key_out,
1859     char *type_out, uint8_t *len_out)
1860 {
1861 	struct asmc_softc *sc = device_get_softc(dev);
1862 	uint8_t index_buf[ASMC_KEYLEN];
1863 	uint8_t key_buf[ASMC_KEYLEN];
1864 	uint8_t info_buf[ASMC_KEYINFO_RESPLEN];
1865 	int error = ENXIO, try = 0;
1866 	int i;
1867 
1868 	mtx_lock_spin(&sc->sc_mtx);
1869 
1870 	index_buf[0] = (index >> 24) & 0xff;
1871 	index_buf[1] = (index >> 16) & 0xff;
1872 	index_buf[2] = (index >> 8) & 0xff;
1873 	index_buf[3] = index & 0xff;
1874 
1875 begin:
1876 	if (asmc_command(dev, ASMC_CMDGETBYINDEX))
1877 		goto out;
1878 
1879 	for (i = 0; i < ASMC_KEYLEN; i++) {
1880 		ASMC_DATAPORT_WRITE(sc, index_buf[i]);
1881 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1882 			goto out;
1883 	}
1884 
1885 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYLEN);
1886 
1887 	for (i = 0; i < ASMC_KEYLEN; i++) {
1888 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1889 			goto out;
1890 		key_buf[i] = ASMC_DATAPORT_READ(sc);
1891 	}
1892 
1893 	if (asmc_command(dev, ASMC_CMDGETINFO))
1894 		goto out;
1895 
1896 	for (i = 0; i < ASMC_KEYLEN; i++) {
1897 		ASMC_DATAPORT_WRITE(sc, key_buf[i]);
1898 		if (asmc_wait(dev, ASMC_STATUS_AWAIT_DATA))
1899 			goto out;
1900 	}
1901 
1902 	ASMC_DATAPORT_WRITE(sc, ASMC_KEYINFO_RESPLEN);
1903 
1904 	for (i = 0; i < ASMC_KEYINFO_RESPLEN; i++) {
1905 		if (asmc_wait(dev, ASMC_STATUS_DATA_READY))
1906 			goto out;
1907 		info_buf[i] = ASMC_DATAPORT_READ(sc);
1908 	}
1909 
1910 	memcpy(key_out, key_buf, ASMC_KEYLEN);
1911 	key_out[ASMC_KEYLEN] = '\0';
1912 	*len_out = info_buf[0];
1913 	memcpy(type_out, &info_buf[1], ASMC_TYPELEN);
1914 	type_out[ASMC_TYPELEN] = '\0';
1915 	error = 0;
1916 
1917 out:
1918 	if (error) {
1919 		if (++try < ASMC_MAXRETRIES)
1920 			goto begin;
1921 	}
1922 
1923 	mtx_unlock_spin(&sc->sc_mtx);
1924 	return (error);
1925 }
1926 
1927 static int
1928 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
1929 {
1930 	int i, error = -1, try = 0;
1931 	struct asmc_softc *sc = device_get_softc(dev);
1932 
1933 	mtx_lock_spin(&sc->sc_mtx);
1934 
1935 begin:
1936 	ASMC_DPRINTF(("cmd port: cmd write\n"));
1937 	if (asmc_command(dev, ASMC_CMDWRITE))
1938 		goto out;
1939 
1940 	ASMC_DPRINTF(("data port: key\n"));
1941 	for (i = 0; i < 4; i++) {
1942 		ASMC_DATAPORT_WRITE(sc, key[i]);
1943 		if (asmc_wait(dev, 0x04))
1944 			goto out;
1945 	}
1946 	ASMC_DPRINTF(("data port: length\n"));
1947 	ASMC_DATAPORT_WRITE(sc, len);
1948 
1949 	ASMC_DPRINTF(("data port: buffer\n"));
1950 	for (i = 0; i < len; i++) {
1951 		if (asmc_wait(dev, 0x04))
1952 			goto out;
1953 		ASMC_DATAPORT_WRITE(sc, buf[i]);
1954 	}
1955 
1956 	error = 0;
1957 out:
1958 	if (error) {
1959 		if (++try < 10)
1960 			goto begin;
1961 		device_printf(dev, "%s for key %s failed %d times, giving up\n",
1962 		    __func__, key, try);
1963 	}
1964 
1965 	mtx_unlock_spin(&sc->sc_mtx);
1966 
1967 	return (error);
1968 }
1969 
1970 /*
1971  * Fan control functions.
1972  */
1973 static int
1974 asmc_fan_count(device_t dev)
1975 {
1976 	uint8_t buf[1];
1977 
1978 	if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0)
1979 		return (-1);
1980 
1981 	return (buf[0]);
1982 }
1983 
1984 static int
1985 asmc_fan_getvalue(device_t dev, const char *key, int fan)
1986 {
1987 	int speed;
1988 	uint8_t buf[2];
1989 	char fankey[5];
1990 
1991 	snprintf(fankey, sizeof(fankey), key, fan);
1992 	if (asmc_key_read(dev, fankey, buf, sizeof(buf)) != 0)
1993 		return (-1);
1994 	speed = (buf[0] << 6) | (buf[1] >> 2);
1995 
1996 	return (speed);
1997 }
1998 
1999 static char *
2000 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf,
2001     uint8_t buflen)
2002 {
2003 	char fankey[5];
2004 	char *desc;
2005 
2006 	snprintf(fankey, sizeof(fankey), key, fan);
2007 	if (asmc_key_read(dev, fankey, buf, buflen) != 0)
2008 		return (NULL);
2009 	desc = buf + 4;
2010 
2011 	return (desc);
2012 }
2013 
2014 static int
2015 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
2016 {
2017 	uint8_t buf[2];
2018 	char fankey[5];
2019 
2020 	speed *= 4;
2021 
2022 	buf[0] = speed >> 8;
2023 	buf[1] = speed;
2024 
2025 	snprintf(fankey, sizeof(fankey), key, fan);
2026 	if (asmc_key_write(dev, fankey, buf, sizeof(buf)) < 0)
2027 		return (-1);
2028 
2029 	return (0);
2030 }
2031 
2032 static int
2033 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
2034 {
2035 	device_t dev = (device_t)arg1;
2036 	int fan = arg2;
2037 	int error;
2038 	int32_t v;
2039 
2040 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
2041 	error = sysctl_handle_int(oidp, &v, 0, req);
2042 
2043 	return (error);
2044 }
2045 
2046 static int
2047 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
2048 {
2049 	uint8_t buf[16];
2050 	device_t dev = (device_t)arg1;
2051 	int fan = arg2;
2052 	int error = true;
2053 	char *desc;
2054 
2055 	desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
2056 
2057 	if (desc != NULL)
2058 		error = sysctl_handle_string(oidp, desc, 0, req);
2059 
2060 	return (error);
2061 }
2062 
2063 static int
2064 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
2065 {
2066 	device_t dev = (device_t)arg1;
2067 	int fan = arg2;
2068 	int error;
2069 	int32_t v;
2070 
2071 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
2072 	error = sysctl_handle_int(oidp, &v, 0, req);
2073 
2074 	return (error);
2075 }
2076 
2077 static int
2078 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
2079 {
2080 	device_t dev = (device_t)arg1;
2081 	int fan = arg2;
2082 	int error;
2083 	int32_t v;
2084 
2085 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
2086 	error = sysctl_handle_int(oidp, &v, 0, req);
2087 
2088 	if (error == 0 && req->newptr != NULL) {
2089 		unsigned int newspeed = v;
2090 		asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed);
2091 	}
2092 
2093 	return (error);
2094 }
2095 
2096 static int
2097 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
2098 {
2099 	device_t dev = (device_t)arg1;
2100 	int fan = arg2;
2101 	int error;
2102 	int32_t v;
2103 
2104 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
2105 	error = sysctl_handle_int(oidp, &v, 0, req);
2106 
2107 	if (error == 0 && req->newptr != NULL) {
2108 		unsigned int newspeed = v;
2109 		asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed);
2110 	}
2111 
2112 	return (error);
2113 }
2114 
2115 static int
2116 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
2117 {
2118 	device_t dev = (device_t)arg1;
2119 	int fan = arg2;
2120 	int error;
2121 	int32_t v;
2122 
2123 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
2124 	error = sysctl_handle_int(oidp, &v, 0, req);
2125 
2126 	if (error == 0 && req->newptr != NULL) {
2127 		unsigned int newspeed = v;
2128 		asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed);
2129 	}
2130 
2131 	return (error);
2132 }
2133 
2134 static int
2135 asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS)
2136 {
2137 	device_t dev = (device_t)arg1;
2138 	int fan = arg2;
2139 	int error;
2140 	int32_t v;
2141 	uint8_t buf[2];
2142 	uint16_t val;
2143 
2144 	/* Read current FS! bitmask (asmc_key_read locks internally) */
2145 	error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf));
2146 	if (error != 0)
2147 		return (error);
2148 
2149 	/* Extract manual bit for this fan (big-endian) */
2150 	val = (buf[0] << 8) | buf[1];
2151 	v = (val >> fan) & 0x01;
2152 
2153 	/* Let sysctl handle the value */
2154 	error = sysctl_handle_int(oidp, &v, 0, req);
2155 
2156 	if (error == 0 && req->newptr != NULL) {
2157 		/* Validate input (0 = auto, 1 = manual) */
2158 		if (v != 0 && v != 1)
2159 			return (EINVAL);
2160 		/* Read-modify-write of FS! bitmask */
2161 		error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf,
2162 		    sizeof(buf));
2163 		if (error == 0) {
2164 			val = (buf[0] << 8) | buf[1];
2165 
2166 			/* Modify single bit */
2167 			if (v)
2168 				val |= (1 << fan);   /* Set to manual */
2169 			else
2170 				val &= ~(1 << fan);  /* Set to auto */
2171 
2172 			/* Write back */
2173 			buf[0] = val >> 8;
2174 			buf[1] = val & 0xff;
2175 			error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf,
2176 			    sizeof(buf));
2177 		}
2178 	}
2179 
2180 	return (error);
2181 }
2182 
2183 /*
2184  * Temperature functions.
2185  */
2186 static int
2187 asmc_temp_getvalue(device_t dev, const char *key)
2188 {
2189 	uint8_t buf[2];
2190 
2191 	/*
2192 	 * Check for invalid temperatures.
2193 	 */
2194 	if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0)
2195 		return (-1);
2196 
2197 	return (buf[0]);
2198 }
2199 
2200 static int
2201 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
2202 {
2203 	device_t dev = (device_t)arg1;
2204 	struct asmc_softc *sc = device_get_softc(dev);
2205 	int error, val;
2206 
2207 	val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
2208 	error = sysctl_handle_int(oidp, &val, 0, req);
2209 
2210 	return (error);
2211 }
2212 
2213 /*
2214  * Sudden Motion Sensor functions.
2215  */
2216 static int
2217 asmc_sms_read(device_t dev, const char *key, int16_t *val)
2218 {
2219 	uint8_t buf[2];
2220 	int error;
2221 
2222 	/* no need to do locking here as asmc_key_read() already does it */
2223 	switch (key[3]) {
2224 	case 'X':
2225 	case 'Y':
2226 	case 'Z':
2227 		error = asmc_key_read(dev, key, buf, sizeof(buf));
2228 		break;
2229 	default:
2230 		device_printf(dev, "%s called with invalid argument %s\n",
2231 		    __func__, key);
2232 		error = EINVAL;
2233 		goto out;
2234 	}
2235 	*val = ((int16_t)buf[0] << 8) | buf[1];
2236 out:
2237 	return (error);
2238 }
2239 
2240 static void
2241 asmc_sms_calibrate(device_t dev)
2242 {
2243 	struct asmc_softc *sc = device_get_softc(dev);
2244 
2245 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
2246 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
2247 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
2248 }
2249 
2250 static int
2251 asmc_sms_intrfast(void *arg)
2252 {
2253 	uint8_t type;
2254 	device_t dev = (device_t)arg;
2255 	struct asmc_softc *sc = device_get_softc(dev);
2256 	if (!sc->sc_sms_intr_works)
2257 		return (FILTER_HANDLED);
2258 
2259 	mtx_lock_spin(&sc->sc_mtx);
2260 	type = ASMC_INTPORT_READ(sc);
2261 	mtx_unlock_spin(&sc->sc_mtx);
2262 
2263 	sc->sc_sms_intrtype = type;
2264 	asmc_sms_printintr(dev, type);
2265 
2266 	taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
2267 	return (FILTER_HANDLED);
2268 }
2269 
2270 static void
2271 asmc_sms_printintr(device_t dev, uint8_t type)
2272 {
2273 	struct asmc_softc *sc = device_get_softc(dev);
2274 
2275 	switch (type) {
2276 	case ASMC_SMS_INTFF:
2277 		device_printf(dev, "WARNING: possible free fall!\n");
2278 		break;
2279 	case ASMC_SMS_INTHA:
2280 		device_printf(dev, "WARNING: high acceleration detected!\n");
2281 		break;
2282 	case ASMC_SMS_INTSH:
2283 		device_printf(dev, "WARNING: possible shock!\n");
2284 		break;
2285 	case ASMC_ALSL_INT2A:
2286 		/*
2287 		 * This suppresses console and log messages for the ambient
2288 		 * light sensor for models known to generate this interrupt.
2289 		 */
2290 		if (strcmp(sc->sc_model->smc_model, "MacBookPro5,5") == 0 ||
2291 		    strcmp(sc->sc_model->smc_model, "MacBookPro6,2") == 0)
2292 			break;
2293 		/* FALLTHROUGH */
2294 	default:
2295 		device_printf(dev, "unknown interrupt: 0x%x\n", type);
2296 	}
2297 }
2298 
2299 static void
2300 asmc_sms_task(void *arg, int pending)
2301 {
2302 	struct asmc_softc *sc = (struct asmc_softc *)arg;
2303 	char notify[16];
2304 	int type;
2305 
2306 	switch (sc->sc_sms_intrtype) {
2307 	case ASMC_SMS_INTFF:
2308 		type = 2;
2309 		break;
2310 	case ASMC_SMS_INTHA:
2311 		type = 1;
2312 		break;
2313 	case ASMC_SMS_INTSH:
2314 		type = 0;
2315 		break;
2316 	default:
2317 		type = 255;
2318 	}
2319 
2320 	snprintf(notify, sizeof(notify), " notify=0x%x", type);
2321 	devctl_notify("ACPI", "asmc", "SMS", notify);
2322 }
2323 
2324 static int
2325 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
2326 {
2327 	device_t dev = (device_t)arg1;
2328 	int error;
2329 	int16_t val;
2330 	int32_t v;
2331 
2332 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
2333 	v = (int32_t)val;
2334 	error = sysctl_handle_int(oidp, &v, 0, req);
2335 
2336 	return (error);
2337 }
2338 
2339 static int
2340 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
2341 {
2342 	device_t dev = (device_t)arg1;
2343 	int error;
2344 	int16_t val;
2345 	int32_t v;
2346 
2347 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
2348 	v = (int32_t)val;
2349 	error = sysctl_handle_int(oidp, &v, 0, req);
2350 
2351 	return (error);
2352 }
2353 
2354 static int
2355 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
2356 {
2357 	device_t dev = (device_t)arg1;
2358 	int error;
2359 	int16_t val;
2360 	int32_t v;
2361 
2362 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
2363 	v = (int32_t)val;
2364 	error = sysctl_handle_int(oidp, &v, 0, req);
2365 
2366 	return (error);
2367 }
2368 
2369 static int
2370 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
2371 {
2372 	device_t dev = (device_t)arg1;
2373 	uint8_t buf[6];
2374 	int error;
2375 	int32_t v;
2376 
2377 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
2378 	v = buf[2];
2379 	error = sysctl_handle_int(oidp, &v, 0, req);
2380 
2381 	return (error);
2382 }
2383 
2384 static int
2385 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
2386 {
2387 	device_t dev = (device_t)arg1;
2388 	uint8_t buf[6];
2389 	int error;
2390 	int32_t v;
2391 
2392 	asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf));
2393 	v = buf[2];
2394 	error = sysctl_handle_int(oidp, &v, 0, req);
2395 
2396 	return (error);
2397 }
2398 
2399 static int
2400 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
2401 {
2402 	device_t dev = (device_t)arg1;
2403 	struct asmc_softc *sc = device_get_softc(dev);
2404 	uint8_t buf[2];
2405 	int error;
2406 	int v;
2407 
2408 	v = light_control;
2409 	error = sysctl_handle_int(oidp, &v, 0, req);
2410 
2411 	if (error == 0 && req->newptr != NULL) {
2412 		if (v < 0 || v > 255)
2413 			return (EINVAL);
2414 		light_control = v;
2415 		sc->sc_kbd_bkl_level = v * 100 / 255;
2416 		buf[0] = light_control;
2417 		buf[1] = 0x00;
2418 		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
2419 	}
2420 	return (error);
2421 }
2422 
2423 static int
2424 asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS)
2425 {
2426 	device_t dev = (device_t)arg1;
2427 	uint8_t buf[10];
2428 	int error;
2429 	uint32_t v;
2430 
2431 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf));
2432 
2433 	/*
2434 	 * This seems to be a 32 bit big endian value from buf[6] -> buf[9].
2435 	 *
2436 	 * Extract it out manually here, then shift/clamp it.
2437 	 */
2438 	v = be32dec(&buf[6]);
2439 
2440 	/*
2441 	 * Shift out, clamp at 255; that way it looks like the
2442 	 * earlier SMC firmware version responses.
2443 	 */
2444 	v = v >> 8;
2445 	if (v > 255)
2446 		v = 255;
2447 
2448 	error = sysctl_handle_int(oidp, &v, 0, req);
2449 
2450 	return (error);
2451 }
2452 
2453 /*
2454  * Wake-on-LAN convenience sysctl.
2455  * Reading returns 1 if WoL is enabled, 0 if disabled.
2456  * Writing 1 enables WoL, 0 disables it.
2457  */
2458 static int
2459 asmc_wol_sysctl(SYSCTL_HANDLER_ARGS)
2460 {
2461 	device_t dev = (device_t)arg1;
2462 	uint8_t aupo;
2463 	int val, error;
2464 
2465 	/* Read current AUPO value */
2466 	if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
2467 		return (EIO);
2468 
2469 	val = (aupo != 0) ? 1 : 0;
2470 	error = sysctl_handle_int(oidp, &val, 0, req);
2471 	if (error != 0 || req->newptr == NULL)
2472 		return (error);
2473 
2474 	/* Clamp to 0 or 1 */
2475 	aupo = (val != 0) ? 1 : 0;
2476 
2477 	/* Write AUPO */
2478 	if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0)
2479 		return (EIO);
2480 
2481 	return (0);
2482 }
2483 
2484 static int
2485 asmc_backlight_update_status(device_t dev, struct backlight_props *props)
2486 {
2487 	struct asmc_softc *sc = device_get_softc(dev);
2488 	uint8_t buf[2];
2489 
2490 	sc->sc_kbd_bkl_level = props->brightness;
2491 	light_control = props->brightness * 255 / 100;
2492 	buf[0] = light_control;
2493 	buf[1] = 0x00;
2494 	asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf));
2495 
2496 	return (0);
2497 }
2498 
2499 static int
2500 asmc_backlight_get_status(device_t dev, struct backlight_props *props)
2501 {
2502 	struct asmc_softc *sc = device_get_softc(dev);
2503 
2504 	props->brightness = sc->sc_kbd_bkl_level;
2505 	props->nlevels = 0;
2506 
2507 	return (0);
2508 }
2509 
2510 static int
2511 asmc_backlight_get_info(device_t dev, struct backlight_info *info)
2512 {
2513 	info->type = BACKLIGHT_TYPE_KEYBOARD;
2514 	strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH);
2515 
2516 	return (0);
2517 }
2518