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