xref: /freebsd/sys/dev/asmc/asmc.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
1 /*-
2  * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 /*
29  * Driver for Apple's System Management Console (SMC).
30  * SMC can be found on the MacBook, MacBook Pro and Mac Mini.
31  *
32  * Inspired by the Linux applesmc driver.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/bus.h>
40 #include <sys/conf.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 #include "opt_intr_filter.h"
59 
60 /*
61  * Device interface.
62  */
63 static int 	asmc_probe(device_t dev);
64 static int 	asmc_attach(device_t dev);
65 static int 	asmc_detach(device_t dev);
66 static int 	asmc_resume(device_t dev);
67 
68 /*
69  * SMC functions.
70  */
71 static int 	asmc_init(device_t dev);
72 static int 	asmc_command(device_t dev, uint8_t command);
73 static int 	asmc_wait(device_t dev, uint8_t val);
74 static int 	asmc_wait_ack(device_t dev, uint8_t val, int amount);
75 static int 	asmc_key_write(device_t dev, const char *key, uint8_t *buf,
76     uint8_t len);
77 static int 	asmc_key_read(device_t dev, const char *key, uint8_t *buf,
78     uint8_t);
79 static int 	asmc_fan_count(device_t dev);
80 static int 	asmc_fan_getvalue(device_t dev, const char *key, int fan);
81 static int 	asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
82 static int 	asmc_temp_getvalue(device_t dev, const char *key);
83 static int 	asmc_sms_read(device_t, const char *key, int16_t *val);
84 static void 	asmc_sms_calibrate(device_t dev);
85 static int 	asmc_sms_intrfast(void *arg);
86 #ifdef INTR_FILTER
87 static void 	asmc_sms_handler(void *arg);
88 #endif
89 static void 	asmc_sms_printintr(device_t dev, uint8_t);
90 static void 	asmc_sms_task(void *arg, int pending);
91 #ifdef DEBUG
92 void		asmc_dumpall(device_t);
93 static int	asmc_key_dump(device_t, int);
94 #endif
95 
96 /*
97  * Model functions.
98  */
99 static int 	asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
100 static int 	asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
101 static int 	asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
102 static int 	asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
103 static int 	asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
104 static int 	asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
105 static int 	asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
106 static int 	asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
107 static int 	asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
108 static int 	asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
109 static int 	asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
110 static int 	asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
111 static int 	asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
112 
113 struct asmc_model {
114 	const char 	 *smc_model;	/* smbios.system.product env var. */
115 	const char 	 *smc_desc;	/* driver description */
116 
117 	/* Helper functions */
118 	int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
119 	int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
120 	int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
121 	int (*smc_fan_id)(SYSCTL_HANDLER_ARGS);
122 	int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
123 	int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
124 	int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
125 	int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
126 	int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
127 	int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
128 	int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
129 	int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
130 
131 	const char 	*smc_temps[ASMC_TEMP_MAX];
132 	const char 	*smc_tempnames[ASMC_TEMP_MAX];
133 	const char 	*smc_tempdescs[ASMC_TEMP_MAX];
134 };
135 
136 static struct asmc_model *asmc_match(device_t dev);
137 
138 #define ASMC_SMS_FUNCS	asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \
139 			asmc_mb_sysctl_sms_z
140 
141 #define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL
142 
143 #define ASMC_FAN_FUNCS	asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \
144 			asmc_mb_sysctl_fanminspeed, \
145 			asmc_mb_sysctl_fanmaxspeed, \
146 			asmc_mb_sysctl_fantargetspeed
147 
148 #define ASMC_FAN_FUNCS2	asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \
149 			asmc_mb_sysctl_fanminspeed, \
150 			asmc_mb_sysctl_fanmaxspeed, \
151 			asmc_mb_sysctl_fantargetspeed
152 
153 #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \
154 			 asmc_mbp_sysctl_light_right, \
155 			 asmc_mbp_sysctl_light_control
156 
157 struct asmc_model asmc_models[] = {
158 	{
159 	  "MacBook1,1", "Apple SMC MacBook Core Duo",
160 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
161 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
162 	},
163 
164 	{
165 	  "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
166 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
167 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
168 	},
169 
170 	{
171 	  "MacBook3,1", "Apple SMC MacBook Core 2 Duo",
172 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
173 	  ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS
174 	},
175 
176 	{
177 	  "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
178 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
179 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
180 	},
181 
182 	{
183 	  "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
184 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
185 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
186 	},
187 
188 	{
189 	  "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
190 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
191 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
192 	},
193 
194 	{
195 	  "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
196 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
197 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
198 	},
199 
200 	{
201 	  "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
202 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
203 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
204 	},
205 
206 	{
207 	  "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
208 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
209 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
210 	},
211 
212 	{
213 	  "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
214 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
215 	  ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
216 	},
217 
218 	{
219 	  "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)",
220 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
221 	  ASMC_MBP5_TEMPS, ASMC_MBP5_TEMPNAMES, ASMC_MBP5_TEMPDESCS
222 	},
223 
224 	{
225 	  "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)",
226 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
227 	  ASMC_MBP8_TEMPS, ASMC_MBP8_TEMPNAMES, ASMC_MBP8_TEMPDESCS
228 	},
229 
230 	{
231 	  "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
232 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
233 	  ASMC_MBP11_TEMPS, ASMC_MBP11_TEMPNAMES, ASMC_MBP11_TEMPDESCS
234 	},
235 
236 	/* The Mac Mini has no SMS */
237 	{
238 	  "Macmini1,1", "Apple SMC Mac Mini",
239 	  NULL, NULL, NULL,
240 	  ASMC_FAN_FUNCS,
241 	  NULL, NULL, NULL,
242 	  ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
243 	},
244 
245 	/* The Mac Mini 3,1 has no SMS */
246 	{
247 	  "Macmini3,1", "Apple SMC Mac Mini 3,1",
248 	  NULL, NULL, NULL,
249 	  ASMC_FAN_FUNCS,
250 	  NULL, NULL, NULL,
251 	  ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS
252 	},
253 
254 	/* Idem for the MacPro */
255 	{
256 	  "MacPro2", "Apple SMC Mac Pro (8-core)",
257 	  NULL, NULL, NULL,
258 	  ASMC_FAN_FUNCS,
259 	  NULL, NULL, NULL,
260 	  ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS
261 	},
262 
263 	/* Idem for the MacPro  2010*/
264 	{
265 	  "MacPro5,1", "Apple SMC MacPro (2010)",
266 	  NULL, NULL, NULL,
267 	  ASMC_FAN_FUNCS,
268 	  NULL, NULL, NULL,
269 	  ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS
270 	},
271 
272 	{
273 	  "MacBookAir1,1", "Apple SMC MacBook Air",
274 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
275 	  ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
276 	},
277 
278 	{
279 	  "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)",
280 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
281 	  ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS
282 	},
283 
284 	{
285 	  "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)",
286 	  ASMC_SMS_FUNCS_DISABLED,
287 	  ASMC_FAN_FUNCS2,
288 	  ASMC_LIGHT_FUNCS,
289 	  ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
290 	},
291 
292 	{
293 	  "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)",
294 	  ASMC_SMS_FUNCS_DISABLED,
295 	  ASMC_FAN_FUNCS2,
296 	  ASMC_LIGHT_FUNCS,
297 	  ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
298 	},
299 
300 
301 	{ NULL, NULL }
302 };
303 
304 #undef ASMC_SMS_FUNCS
305 #undef ASMC_SMS_FUNCS_DISABLED
306 #undef ASMC_FAN_FUNCS
307 #undef ASMC_FAN_FUNCS2
308 #undef ASMC_LIGHT_FUNCS
309 
310 /*
311  * Driver methods.
312  */
313 static device_method_t	asmc_methods[] = {
314 	DEVMETHOD(device_probe,		asmc_probe),
315 	DEVMETHOD(device_attach,	asmc_attach),
316 	DEVMETHOD(device_detach,	asmc_detach),
317 	DEVMETHOD(device_resume,	asmc_resume),
318 
319 	{ 0, 0 }
320 };
321 
322 static driver_t	asmc_driver = {
323 	"asmc",
324 	asmc_methods,
325 	sizeof(struct asmc_softc)
326 };
327 
328 /*
329  * Debugging
330  */
331 #define	_COMPONENT	ACPI_OEM
332 ACPI_MODULE_NAME("ASMC")
333 #ifdef DEBUG
334 #define ASMC_DPRINTF(str)	device_printf(dev, str)
335 #else
336 #define ASMC_DPRINTF(str)
337 #endif
338 
339 /* NB: can't be const */
340 static char *asmc_ids[] = { "APP0001", NULL };
341 
342 static devclass_t asmc_devclass;
343 
344 static unsigned int light_control = 0;
345 
346 DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL);
347 MODULE_DEPEND(asmc, acpi, 1, 1, 1);
348 
349 static struct asmc_model *
350 asmc_match(device_t dev)
351 {
352 	int i;
353 	char *model;
354 
355 	model = kern_getenv("smbios.system.product");
356 	if (model == NULL)
357 		return (NULL);
358 
359 	for (i = 0; asmc_models[i].smc_model; i++) {
360 		if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) {
361 			freeenv(model);
362 			return (&asmc_models[i]);
363 		}
364 	}
365 	freeenv(model);
366 
367 	return (NULL);
368 }
369 
370 static int
371 asmc_probe(device_t dev)
372 {
373 	struct asmc_model *model;
374 
375 	if (resource_disabled("asmc", 0))
376 		return (ENXIO);
377 	if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL)
378 		return (ENXIO);
379 
380 	model = asmc_match(dev);
381 	if (!model) {
382 		device_printf(dev, "model not recognized\n");
383 		return (ENXIO);
384 	}
385 	device_set_desc(dev, model->smc_desc);
386 
387 	return (BUS_PROBE_DEFAULT);
388 }
389 
390 static int
391 asmc_attach(device_t dev)
392 {
393 	int i, j;
394 	int ret;
395 	char name[2];
396 	struct asmc_softc *sc = device_get_softc(dev);
397 	struct sysctl_ctx_list *sysctlctx;
398 	struct sysctl_oid *sysctlnode;
399 	struct asmc_model *model;
400 
401 	sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
402 	    &sc->sc_rid_port, RF_ACTIVE);
403 	if (sc->sc_ioport == NULL) {
404 		device_printf(dev, "unable to allocate IO port\n");
405 		return (ENOMEM);
406 	}
407 
408 	sysctlctx  = device_get_sysctl_ctx(dev);
409 	sysctlnode = device_get_sysctl_tree(dev);
410 
411 	model = asmc_match(dev);
412 
413 	mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
414 
415 	sc->sc_model = model;
416 	asmc_init(dev);
417 
418 	/*
419 	 * dev.asmc.n.fan.* tree.
420 	 */
421 	sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
422 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
423 	    CTLFLAG_RD, 0, "Fan Root Tree");
424 
425 	for (i = 1; i <= sc->sc_nfan; i++) {
426 		j = i - 1;
427 		name[0] = '0' + j;
428 		name[1] = 0;
429 		sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
430 		    SYSCTL_CHILDREN(sc->sc_fan_tree[0]),
431 		    OID_AUTO, name, CTLFLAG_RD, 0,
432 		    "Fan Subtree");
433 
434 		SYSCTL_ADD_PROC(sysctlctx,
435 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
436 		    OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD,
437 		    dev, j, model->smc_fan_id, "I",
438 		    "Fan ID");
439 
440 		SYSCTL_ADD_PROC(sysctlctx,
441 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
442 		    OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD,
443 		    dev, j, model->smc_fan_speed, "I",
444 		    "Fan speed in RPM");
445 
446 		SYSCTL_ADD_PROC(sysctlctx,
447 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
448 		    OID_AUTO, "safespeed",
449 		    CTLTYPE_INT | CTLFLAG_RD,
450 		    dev, j, model->smc_fan_safespeed, "I",
451 		    "Fan safe speed in RPM");
452 
453 		SYSCTL_ADD_PROC(sysctlctx,
454 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
455 		    OID_AUTO, "minspeed",
456 		    CTLTYPE_INT | CTLFLAG_RW,
457 		    dev, j, model->smc_fan_minspeed, "I",
458 		    "Fan minimum speed in RPM");
459 
460 		SYSCTL_ADD_PROC(sysctlctx,
461 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
462 		    OID_AUTO, "maxspeed",
463 		    CTLTYPE_INT | CTLFLAG_RW,
464 		    dev, j, model->smc_fan_maxspeed, "I",
465 		    "Fan maximum speed in RPM");
466 
467 		SYSCTL_ADD_PROC(sysctlctx,
468 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
469 		    OID_AUTO, "targetspeed",
470 		    CTLTYPE_INT | CTLFLAG_RW,
471 		    dev, j, model->smc_fan_targetspeed, "I",
472 		    "Fan target speed in RPM");
473 	}
474 
475 	/*
476 	 * dev.asmc.n.temp tree.
477 	 */
478 	sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
479 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
480 	    CTLFLAG_RD, 0, "Temperature sensors");
481 
482 	for (i = 0; model->smc_temps[i]; i++) {
483 		SYSCTL_ADD_PROC(sysctlctx,
484 		    SYSCTL_CHILDREN(sc->sc_temp_tree),
485 		    OID_AUTO, model->smc_tempnames[i],
486 		    CTLTYPE_INT | CTLFLAG_RD,
487 		    dev, i, asmc_temp_sysctl, "I",
488 		    model->smc_tempdescs[i]);
489 	}
490 
491 	/*
492 	 * dev.asmc.n.light
493 	 */
494 	if (model->smc_light_left) {
495 		sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
496 		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
497 		    CTLFLAG_RD, 0, "Keyboard backlight sensors");
498 
499 		SYSCTL_ADD_PROC(sysctlctx,
500 		    SYSCTL_CHILDREN(sc->sc_light_tree),
501 		    OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD,
502 		    dev, 0, model->smc_light_left, "I",
503 		    "Keyboard backlight left sensor");
504 
505 		SYSCTL_ADD_PROC(sysctlctx,
506 		    SYSCTL_CHILDREN(sc->sc_light_tree),
507 		    OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD,
508 		    dev, 0, model->smc_light_right, "I",
509 		    "Keyboard backlight right sensor");
510 
511 		SYSCTL_ADD_PROC(sysctlctx,
512 		    SYSCTL_CHILDREN(sc->sc_light_tree),
513 		    OID_AUTO, "control",
514 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
515 		    dev, 0, model->smc_light_control, "I",
516 		    "Keyboard backlight brightness control");
517 	}
518 
519 	if (model->smc_sms_x == NULL)
520 		goto nosms;
521 
522 	/*
523 	 * dev.asmc.n.sms tree.
524 	 */
525 	sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
526 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
527 	    CTLFLAG_RD, 0, "Sudden Motion Sensor");
528 
529 	SYSCTL_ADD_PROC(sysctlctx,
530 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
531 	    OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD,
532 	    dev, 0, model->smc_sms_x, "I",
533 	    "Sudden Motion Sensor X value");
534 
535 	SYSCTL_ADD_PROC(sysctlctx,
536 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
537 	    OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD,
538 	    dev, 0, model->smc_sms_y, "I",
539 	    "Sudden Motion Sensor Y value");
540 
541 	SYSCTL_ADD_PROC(sysctlctx,
542 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
543 	    OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD,
544 	    dev, 0, model->smc_sms_z, "I",
545 	    "Sudden Motion Sensor Z value");
546 
547 	/*
548 	 * Need a taskqueue to send devctl_notify() events
549 	 * when the SMS interrupt us.
550 	 *
551 	 * PI_REALTIME is used due to the sensitivity of the
552 	 * interrupt. An interrupt from the SMS means that the
553 	 * disk heads should be turned off as quickly as possible.
554 	 *
555 	 * We only need to do this for the non INTR_FILTER case.
556 	 */
557 	sc->sc_sms_tq = NULL;
558 #ifndef INTR_FILTER
559 	TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
560 	sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
561 	    taskqueue_thread_enqueue, &sc->sc_sms_tq);
562 	taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
563 	    device_get_nameunit(dev));
564 #endif
565 	/*
566 	 * Allocate an IRQ for the SMS.
567 	 */
568 	sc->sc_rid_irq = 0;
569 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
570 	    &sc->sc_rid_irq, RF_ACTIVE);
571 	if (sc->sc_irq == NULL) {
572 		device_printf(dev, "unable to allocate IRQ resource\n");
573 		ret = ENXIO;
574 		goto err2;
575 	}
576 
577 	ret = bus_setup_intr(dev, sc->sc_irq,
578 	          INTR_TYPE_MISC | INTR_MPSAFE,
579 #ifdef INTR_FILTER
580 	    asmc_sms_intrfast, asmc_sms_handler,
581 #else
582 	    asmc_sms_intrfast, NULL,
583 #endif
584 	    dev, &sc->sc_cookie);
585 
586 	if (ret) {
587 		device_printf(dev, "unable to setup SMS IRQ\n");
588 		goto err1;
589 	}
590 nosms:
591 	return (0);
592 err1:
593 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq);
594 err2:
595 	bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
596 	    sc->sc_ioport);
597 	mtx_destroy(&sc->sc_mtx);
598 	if (sc->sc_sms_tq)
599 		taskqueue_free(sc->sc_sms_tq);
600 
601 	return (ret);
602 }
603 
604 static int
605 asmc_detach(device_t dev)
606 {
607 	struct asmc_softc *sc = device_get_softc(dev);
608 
609 	if (sc->sc_sms_tq) {
610 		taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
611 		taskqueue_free(sc->sc_sms_tq);
612 	}
613 	if (sc->sc_cookie)
614 		bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
615 	if (sc->sc_irq)
616 		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
617 		    sc->sc_irq);
618 	if (sc->sc_ioport)
619 		bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
620 		    sc->sc_ioport);
621 	mtx_destroy(&sc->sc_mtx);
622 
623 	return (0);
624 }
625 
626 static int
627 asmc_resume(device_t dev)
628 {
629     uint8_t buf[2];
630     buf[0] = light_control;
631     buf[1] = 0x00;
632     asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
633     return (0);
634 }
635 
636 
637 #ifdef DEBUG
638 void asmc_dumpall(device_t dev)
639 {
640 	int i;
641 
642 	/* XXX magic number */
643 	for (i=0; i < 0x100; i++)
644 		asmc_key_dump(dev, i);
645 }
646 #endif
647 
648 static int
649 asmc_init(device_t dev)
650 {
651 	struct asmc_softc *sc = device_get_softc(dev);
652 	int i, error = 1;
653 	uint8_t buf[4];
654 
655 	if (sc->sc_model->smc_sms_x == NULL)
656 		goto nosms;
657 
658 	/*
659 	 * We are ready to receive interrupts from the SMS.
660 	 */
661 	buf[0] = 0x01;
662 	ASMC_DPRINTF(("intok key\n"));
663 	asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
664 	DELAY(50);
665 
666 	/*
667 	 * Initiate the polling intervals.
668 	 */
669 	buf[0] = 20; /* msecs */
670 	ASMC_DPRINTF(("low int key\n"));
671 	asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
672 	DELAY(200);
673 
674 	buf[0] = 20; /* msecs */
675 	ASMC_DPRINTF(("high int key\n"));
676 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
677 	DELAY(200);
678 
679 	buf[0] = 0x00;
680 	buf[1] = 0x60;
681 	ASMC_DPRINTF(("sms low key\n"));
682 	asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
683 	DELAY(200);
684 
685 	buf[0] = 0x01;
686 	buf[1] = 0xc0;
687 	ASMC_DPRINTF(("sms high key\n"));
688 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
689 	DELAY(200);
690 
691 	/*
692 	 * I'm not sure what this key does, but it seems to be
693 	 * required.
694 	 */
695 	buf[0] = 0x01;
696 	ASMC_DPRINTF(("sms flag key\n"));
697 	asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
698 	DELAY(100);
699 
700 	sc->sc_sms_intr_works = 0;
701 
702 	/*
703 	 * Retry SMS initialization 1000 times
704 	 * (takes approx. 2 seconds in worst case)
705 	 */
706 	for (i = 0; i < 1000; i++) {
707 		if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
708 		    (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
709 			error = 0;
710 			sc->sc_sms_intr_works = 1;
711 			goto out;
712 		}
713 		buf[0] = ASMC_SMS_INIT1;
714 		buf[1] = ASMC_SMS_INIT2;
715 		ASMC_DPRINTF(("sms key\n"));
716 		asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
717 		DELAY(50);
718 	}
719 	device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
720 
721 out:
722 	asmc_sms_calibrate(dev);
723 nosms:
724 	sc->sc_nfan = asmc_fan_count(dev);
725 	if (sc->sc_nfan > ASMC_MAXFANS) {
726 		device_printf(dev, "more than %d fans were detected. Please "
727 		    "report this.\n", ASMC_MAXFANS);
728 		sc->sc_nfan = ASMC_MAXFANS;
729 	}
730 
731 	if (bootverbose) {
732 		/*
733 		 * The number of keys is a 32 bit buffer
734 		 */
735 		asmc_key_read(dev, ASMC_NKEYS, buf, 4);
736 		device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf));
737 	}
738 
739 #ifdef DEBUG
740 	asmc_dumpall(dev);
741 #endif
742 
743 	return (error);
744 }
745 
746 /*
747  * We need to make sure that the SMC acks the byte sent.
748  * Just wait up to (amount * 10)  ms.
749  */
750 static int
751 asmc_wait_ack(device_t dev, uint8_t val, int amount)
752 {
753 	struct asmc_softc *sc = device_get_softc(dev);
754 	u_int i;
755 
756 	val = val & ASMC_STATUS_MASK;
757 
758 	for (i = 0; i < amount; i++) {
759 		if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
760 			return (0);
761 		DELAY(10);
762 	}
763 
764 	return (1);
765 }
766 
767 /*
768  * We need to make sure that the SMC acks the byte sent.
769  * Just wait up to 100 ms.
770  */
771 static int
772 asmc_wait(device_t dev, uint8_t val)
773 {
774 	struct asmc_softc *sc;
775 
776 	if (asmc_wait_ack(dev, val, 1000) == 0)
777 		return (0);
778 
779 	sc = device_get_softc(dev);
780 	val = val & ASMC_STATUS_MASK;
781 
782 #ifdef DEBUG
783 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val,
784 	    ASMC_CMDPORT_READ(sc));
785 #endif
786 	return (1);
787 }
788 
789 /*
790  * Send the given command, retrying up to 10 times if
791  * the acknowledgement fails.
792  */
793 static int
794 asmc_command(device_t dev, uint8_t command) {
795 
796 	int i;
797 	struct asmc_softc *sc = device_get_softc(dev);
798 
799 	for (i=0; i < 10; i++) {
800 		ASMC_CMDPORT_WRITE(sc, command);
801 		if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
802 			return (0);
803 		}
804 	}
805 
806 #ifdef DEBUG
807 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
808 	    ASMC_CMDPORT_READ(sc));
809 #endif
810 	return (1);
811 }
812 
813 static int
814 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
815 {
816 	int i, error = 1, try = 0;
817 	struct asmc_softc *sc = device_get_softc(dev);
818 
819 	mtx_lock_spin(&sc->sc_mtx);
820 
821 begin:
822 	if (asmc_command(dev, ASMC_CMDREAD))
823 		goto out;
824 
825 	for (i = 0; i < 4; i++) {
826 		ASMC_DATAPORT_WRITE(sc, key[i]);
827 		if (asmc_wait(dev, 0x04))
828 			goto out;
829 	}
830 
831 	ASMC_DATAPORT_WRITE(sc, len);
832 
833 	for (i = 0; i < len; i++) {
834 		if (asmc_wait(dev, 0x05))
835 			goto out;
836 		buf[i] = ASMC_DATAPORT_READ(sc);
837 	}
838 
839 	error = 0;
840 out:
841 	if (error) {
842 		if (++try < 10) goto begin;
843 		device_printf(dev,"%s for key %s failed %d times, giving up\n",
844 			__func__, key, try);
845 	}
846 
847 	mtx_unlock_spin(&sc->sc_mtx);
848 
849 	return (error);
850 }
851 
852 #ifdef DEBUG
853 static int
854 asmc_key_dump(device_t dev, int number)
855 {
856 	struct asmc_softc *sc = device_get_softc(dev);
857 	char key[5] = { 0 };
858 	char type[7] = { 0 };
859 	uint8_t index[4];
860 	uint8_t v[32];
861 	uint8_t maxlen;
862 	int i, error = 1, try = 0;
863 
864 	mtx_lock_spin(&sc->sc_mtx);
865 
866 	index[0] = (number >> 24) & 0xff;
867 	index[1] = (number >> 16) & 0xff;
868 	index[2] = (number >> 8) & 0xff;
869 	index[3] = (number) & 0xff;
870 
871 begin:
872 	if (asmc_command(dev, 0x12))
873 		goto out;
874 
875 	for (i = 0; i < 4; i++) {
876 		ASMC_DATAPORT_WRITE(sc, index[i]);
877 		if (asmc_wait(dev, 0x04))
878 			goto out;
879 	}
880 
881 	ASMC_DATAPORT_WRITE(sc, 4);
882 
883 	for (i = 0; i < 4; i++) {
884 		if (asmc_wait(dev, 0x05))
885 			goto out;
886 		key[i] = ASMC_DATAPORT_READ(sc);
887 	}
888 
889 	/* get type */
890 	if (asmc_command(dev, 0x13))
891 		goto out;
892 
893 	for (i = 0; i < 4; i++) {
894 		ASMC_DATAPORT_WRITE(sc, key[i]);
895 		if (asmc_wait(dev, 0x04))
896 			goto out;
897 	}
898 
899 	ASMC_DATAPORT_WRITE(sc, 6);
900 
901 	for (i = 0; i < 6; i++) {
902 		if (asmc_wait(dev, 0x05))
903 			goto out;
904 		type[i] = ASMC_DATAPORT_READ(sc);
905 	}
906 
907 	error = 0;
908 out:
909 	if (error) {
910 		if (++try < 10) goto begin;
911 		device_printf(dev,"%s for key %s failed %d times, giving up\n",
912 			__func__, key, try);
913 		mtx_unlock_spin(&sc->sc_mtx);
914 	}
915 	else {
916 		char buf[1024];
917 		char buf2[8];
918 		mtx_unlock_spin(&sc->sc_mtx);
919 		maxlen = type[0];
920 		type[0] = ' ';
921 		type[5] = 0;
922 		if (maxlen > sizeof(v)) {
923 			device_printf(dev,
924 			    "WARNING: cropping maxlen from %d to %zu\n",
925 			    maxlen, sizeof(v));
926 			maxlen = sizeof(v);
927 		}
928 		for (i = 0; i < sizeof(v); i++) {
929 			v[i] = 0;
930 		}
931 		asmc_key_read(dev, key, v, maxlen);
932 		snprintf(buf, sizeof(buf), "key %d is: %s, type %s "
933 		    "(len %d), data", number, key, type, maxlen);
934 		for (i = 0; i < maxlen; i++) {
935 			snprintf(buf2, sizeof(buf2), " %02x", v[i]);
936 			strlcat(buf, buf2, sizeof(buf));
937 		}
938 		strlcat(buf, " \n", sizeof(buf));
939 		device_printf(dev, "%s", buf);
940 	}
941 
942 	return (error);
943 }
944 #endif
945 
946 static int
947 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
948 {
949 	int i, error = -1, try = 0;
950 	struct asmc_softc *sc = device_get_softc(dev);
951 
952 	mtx_lock_spin(&sc->sc_mtx);
953 
954 begin:
955 	ASMC_DPRINTF(("cmd port: cmd write\n"));
956 	if (asmc_command(dev, ASMC_CMDWRITE))
957 		goto out;
958 
959 	ASMC_DPRINTF(("data port: key\n"));
960 	for (i = 0; i < 4; i++) {
961 		ASMC_DATAPORT_WRITE(sc, key[i]);
962 		if (asmc_wait(dev, 0x04))
963 			goto out;
964 	}
965 	ASMC_DPRINTF(("data port: length\n"));
966 	ASMC_DATAPORT_WRITE(sc, len);
967 
968 	ASMC_DPRINTF(("data port: buffer\n"));
969 	for (i = 0; i < len; i++) {
970 		if (asmc_wait(dev, 0x04))
971 			goto out;
972 		ASMC_DATAPORT_WRITE(sc, buf[i]);
973 	}
974 
975 	error = 0;
976 out:
977 	if (error) {
978 		if (++try < 10) goto begin;
979 		device_printf(dev,"%s for key %s failed %d times, giving up\n",
980 			__func__, key, try);
981 	}
982 
983 	mtx_unlock_spin(&sc->sc_mtx);
984 
985 	return (error);
986 
987 }
988 
989 /*
990  * Fan control functions.
991  */
992 static int
993 asmc_fan_count(device_t dev)
994 {
995 	uint8_t buf[1];
996 
997 	if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) < 0)
998 		return (-1);
999 
1000 	return (buf[0]);
1001 }
1002 
1003 static int
1004 asmc_fan_getvalue(device_t dev, const char *key, int fan)
1005 {
1006 	int speed;
1007 	uint8_t buf[2];
1008 	char fankey[5];
1009 
1010 	snprintf(fankey, sizeof(fankey), key, fan);
1011 	if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0)
1012 		return (-1);
1013 	speed = (buf[0] << 6) | (buf[1] >> 2);
1014 
1015 	return (speed);
1016 }
1017 
1018 static char*
1019 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen)
1020 {
1021 	char fankey[5];
1022 	char* desc;
1023 
1024 	snprintf(fankey, sizeof(fankey), key, fan);
1025 	if (asmc_key_read(dev, fankey, buf, buflen) < 0)
1026 		return (NULL);
1027 	desc = buf+4;
1028 
1029 	return (desc);
1030 }
1031 
1032 static int
1033 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
1034 {
1035 	uint8_t buf[2];
1036 	char fankey[5];
1037 
1038 	speed *= 4;
1039 
1040 	buf[0] = speed>>8;
1041 	buf[1] = speed;
1042 
1043 	snprintf(fankey, sizeof(fankey), key, fan);
1044 	if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0)
1045 		return (-1);
1046 
1047 	return (0);
1048 }
1049 
1050 static int
1051 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
1052 {
1053 	device_t dev = (device_t) arg1;
1054 	int fan = arg2;
1055 	int error;
1056 	int32_t v;
1057 
1058 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
1059 	error = sysctl_handle_int(oidp, &v, 0, req);
1060 
1061 	return (error);
1062 }
1063 
1064 static int
1065 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
1066 {
1067 	uint8_t buf[16];
1068 	device_t dev = (device_t) arg1;
1069 	int fan = arg2;
1070 	int error = true;
1071 	char* desc;
1072 
1073 	desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
1074 
1075 	if (desc != NULL)
1076 		error = sysctl_handle_string(oidp, desc, 0, req);
1077 
1078 	return (error);
1079 }
1080 
1081 static int
1082 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
1083 {
1084 	device_t dev = (device_t) arg1;
1085 	int fan = arg2;
1086 	int error;
1087 	int32_t v;
1088 
1089 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
1090 	error = sysctl_handle_int(oidp, &v, 0, req);
1091 
1092 	return (error);
1093 }
1094 
1095 
1096 static int
1097 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
1098 {
1099 	device_t dev = (device_t) arg1;
1100 	int fan = arg2;
1101 	int error;
1102 	int32_t v;
1103 
1104 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
1105 	error = sysctl_handle_int(oidp, &v, 0, req);
1106 
1107 	if (error == 0 && req->newptr != NULL) {
1108 		unsigned int newspeed = v;
1109 		asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed);
1110 	}
1111 
1112 	return (error);
1113 }
1114 
1115 static int
1116 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
1117 {
1118 	device_t dev = (device_t) arg1;
1119 	int fan = arg2;
1120 	int error;
1121 	int32_t v;
1122 
1123 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
1124 	error = sysctl_handle_int(oidp, &v, 0, req);
1125 
1126 	if (error == 0 && req->newptr != NULL) {
1127 		unsigned int newspeed = v;
1128 		asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed);
1129 	}
1130 
1131 	return (error);
1132 }
1133 
1134 static int
1135 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
1136 {
1137 	device_t dev = (device_t) arg1;
1138 	int fan = arg2;
1139 	int error;
1140 	int32_t v;
1141 
1142 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
1143 	error = sysctl_handle_int(oidp, &v, 0, req);
1144 
1145 	if (error == 0 && req->newptr != NULL) {
1146 		unsigned int newspeed = v;
1147 		asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed);
1148 	}
1149 
1150 	return (error);
1151 }
1152 
1153 /*
1154  * Temperature functions.
1155  */
1156 static int
1157 asmc_temp_getvalue(device_t dev, const char *key)
1158 {
1159 	uint8_t buf[2];
1160 
1161 	/*
1162 	 * Check for invalid temperatures.
1163 	 */
1164 	if (asmc_key_read(dev, key, buf, sizeof buf) < 0)
1165 		return (-1);
1166 
1167 	return (buf[0]);
1168 }
1169 
1170 static int
1171 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
1172 {
1173 	device_t dev = (device_t) arg1;
1174 	struct asmc_softc *sc = device_get_softc(dev);
1175 	int error, val;
1176 
1177 	val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
1178 	error = sysctl_handle_int(oidp, &val, 0, req);
1179 
1180 	return (error);
1181 }
1182 
1183 /*
1184  * Sudden Motion Sensor functions.
1185  */
1186 static int
1187 asmc_sms_read(device_t dev, const char *key, int16_t *val)
1188 {
1189 	uint8_t buf[2];
1190 	int error;
1191 
1192 	/* no need to do locking here as asmc_key_read() already does it */
1193 	switch (key[3]) {
1194 	case 'X':
1195 	case 'Y':
1196 	case 'Z':
1197 		error =	asmc_key_read(dev, key, buf, sizeof buf);
1198 		break;
1199 	default:
1200 		device_printf(dev, "%s called with invalid argument %s\n",
1201 			      __func__, key);
1202 		error = 1;
1203 		goto out;
1204 	}
1205 	*val = ((int16_t)buf[0] << 8) | buf[1];
1206 out:
1207 	return (error);
1208 }
1209 
1210 static void
1211 asmc_sms_calibrate(device_t dev)
1212 {
1213 	struct asmc_softc *sc = device_get_softc(dev);
1214 
1215 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
1216 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
1217 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
1218 }
1219 
1220 static int
1221 asmc_sms_intrfast(void *arg)
1222 {
1223 	uint8_t type;
1224 	device_t dev = (device_t) arg;
1225 	struct asmc_softc *sc = device_get_softc(dev);
1226 	if (!sc->sc_sms_intr_works)
1227 		return (FILTER_HANDLED);
1228 
1229 	mtx_lock_spin(&sc->sc_mtx);
1230 	type = ASMC_INTPORT_READ(sc);
1231 	mtx_unlock_spin(&sc->sc_mtx);
1232 
1233 	sc->sc_sms_intrtype = type;
1234 	asmc_sms_printintr(dev, type);
1235 
1236 #ifdef INTR_FILTER
1237 	return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED);
1238 #else
1239 	taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
1240 #endif
1241 	return (FILTER_HANDLED);
1242 }
1243 
1244 #ifdef INTR_FILTER
1245 static void
1246 asmc_sms_handler(void *arg)
1247 {
1248 	struct asmc_softc *sc = device_get_softc(arg);
1249 
1250 	asmc_sms_task(sc, 0);
1251 }
1252 #endif
1253 
1254 
1255 static void
1256 asmc_sms_printintr(device_t dev, uint8_t type)
1257 {
1258 
1259 	switch (type) {
1260 	case ASMC_SMS_INTFF:
1261 		device_printf(dev, "WARNING: possible free fall!\n");
1262 		break;
1263 	case ASMC_SMS_INTHA:
1264 		device_printf(dev, "WARNING: high acceleration detected!\n");
1265 		break;
1266 	case ASMC_SMS_INTSH:
1267 		device_printf(dev, "WARNING: possible shock!\n");
1268 		break;
1269 	default:
1270 		device_printf(dev, "%s unknown interrupt\n", __func__);
1271 	}
1272 }
1273 
1274 static void
1275 asmc_sms_task(void *arg, int pending)
1276 {
1277 	struct asmc_softc *sc = (struct asmc_softc *)arg;
1278 	char notify[16];
1279 	int type;
1280 
1281 	switch (sc->sc_sms_intrtype) {
1282 	case ASMC_SMS_INTFF:
1283 		type = 2;
1284 		break;
1285 	case ASMC_SMS_INTHA:
1286 		type = 1;
1287 		break;
1288 	case ASMC_SMS_INTSH:
1289 		type = 0;
1290 		break;
1291 	default:
1292 		type = 255;
1293 	}
1294 
1295 	snprintf(notify, sizeof(notify), " notify=0x%x", type);
1296 	devctl_notify("ACPI", "asmc", "SMS", notify);
1297 }
1298 
1299 static int
1300 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
1301 {
1302 	device_t dev = (device_t) arg1;
1303 	int error;
1304 	int16_t val;
1305 	int32_t v;
1306 
1307 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
1308 	v = (int32_t) val;
1309 	error = sysctl_handle_int(oidp, &v, 0, req);
1310 
1311 	return (error);
1312 }
1313 
1314 static int
1315 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
1316 {
1317 	device_t dev = (device_t) arg1;
1318 	int error;
1319 	int16_t val;
1320 	int32_t v;
1321 
1322 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
1323 	v = (int32_t) val;
1324 	error = sysctl_handle_int(oidp, &v, 0, req);
1325 
1326 	return (error);
1327 }
1328 
1329 static int
1330 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
1331 {
1332 	device_t dev = (device_t) arg1;
1333 	int error;
1334 	int16_t val;
1335 	int32_t v;
1336 
1337 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
1338 	v = (int32_t) val;
1339 	error = sysctl_handle_int(oidp, &v, 0, req);
1340 
1341 	return (error);
1342 }
1343 
1344 static int
1345 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
1346 {
1347 	device_t dev = (device_t) arg1;
1348 	uint8_t buf[6];
1349 	int error;
1350 	int32_t v;
1351 
1352 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf);
1353 	v = buf[2];
1354 	error = sysctl_handle_int(oidp, &v, 0, req);
1355 
1356 	return (error);
1357 }
1358 
1359 static int
1360 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
1361 {
1362 	device_t dev = (device_t) arg1;
1363 	uint8_t buf[6];
1364 	int error;
1365 	int32_t v;
1366 
1367 	asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf);
1368 	v = buf[2];
1369 	error = sysctl_handle_int(oidp, &v, 0, req);
1370 
1371 	return (error);
1372 }
1373 
1374 static int
1375 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
1376 {
1377 	device_t dev = (device_t) arg1;
1378 	uint8_t buf[2];
1379 	int error;
1380 	int v;
1381 
1382 	v = light_control;
1383 	error = sysctl_handle_int(oidp, &v, 0, req);
1384 
1385 	if (error == 0 && req->newptr != NULL) {
1386 		if (v < 0 || v > 255)
1387 			return (EINVAL);
1388 		light_control = v;
1389 		buf[0] = light_control;
1390 		buf[1] = 0x00;
1391 		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
1392 	}
1393 	return (error);
1394 }
1395