xref: /freebsd/sys/dev/asmc/asmc.c (revision 39beb93c)
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 #include <contrib/dev/acpica/acpi.h>
53 #include <dev/acpica/acpivar.h>
54 #include <dev/asmc/asmcvar.h>
55 
56 #include "opt_intr_filter.h"
57 
58 /*
59  * Device interface.
60  */
61 static int 	asmc_probe(device_t dev);
62 static int 	asmc_attach(device_t dev);
63 static int 	asmc_detach(device_t dev);
64 
65 /*
66  * SMC functions.
67  */
68 static int 	asmc_init(device_t dev);
69 static int 	asmc_wait(device_t dev, uint8_t val);
70 static int 	asmc_key_write(device_t dev, const char *key, uint8_t *buf,
71     uint8_t len);
72 static int 	asmc_key_read(device_t dev, const char *key, uint8_t *buf,
73     uint8_t);
74 static int 	asmc_fan_count(device_t dev);
75 static int 	asmc_fan_getvalue(device_t dev, const char *key, int fan);
76 static int 	asmc_temp_getvalue(device_t dev, const char *key);
77 static int 	asmc_sms_read(device_t, const char *key, int16_t *val);
78 static void 	asmc_sms_calibrate(device_t dev);
79 static int 	asmc_sms_intrfast(void *arg);
80 #ifdef INTR_FILTER
81 static void 	asmc_sms_handler(void *arg);
82 #endif
83 static void 	asmc_sms_printintr(device_t dev, uint8_t);
84 static void 	asmc_sms_task(void *arg, int pending);
85 
86 /*
87  * Model functions.
88  */
89 static int 	asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
90 static int 	asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
91 static int 	asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
92 static int 	asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
93 static int 	asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
94 static int 	asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
95 static int 	asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
96 static int 	asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
97 static int 	asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
98 static int 	asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
99 static int 	asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
100 
101 struct asmc_model {
102 	const char 	 *smc_model;	/* smbios.system.product env var. */
103 	const char 	 *smc_desc;	/* driver description */
104 
105 	/* Helper functions */
106 	int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
107 	int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
108 	int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
109 	int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
110 	int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
111 	int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
112 	int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
113 	int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
114 	int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
115 	int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
116 
117 	const char 	*smc_temps[ASMC_TEMP_MAX];
118 	const char 	*smc_tempnames[ASMC_TEMP_MAX];
119 	const char 	*smc_tempdescs[ASMC_TEMP_MAX];
120 };
121 
122 static struct asmc_model *asmc_match(device_t dev);
123 
124 #define ASMC_SMS_FUNCS	asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \
125 			asmc_mb_sysctl_sms_z
126 
127 #define ASMC_FAN_FUNCS	asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \
128 			asmc_mb_sysctl_fanminspeed, \
129 			asmc_mb_sysctl_fanmaxspeed, \
130 			asmc_mb_sysctl_fantargetspeed
131 #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \
132 			 asmc_mbp_sysctl_light_right
133 
134 struct asmc_model asmc_models[] = {
135 	{
136 	  "MacBook1,1", "Apple SMC MacBook Core Duo",
137 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL,
138 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
139 	},
140 
141 	{
142 	  "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
143 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL,
144 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
145 	},
146 
147 	{
148 	  "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
149 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
150 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
151 	},
152 
153 	{
154 	  "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
155 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
156 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
157 	},
158 
159 	{
160 	  "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
161 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
162 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
163 	},
164 
165 	{
166 	  "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
167 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
168 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
169 	},
170 
171 	{
172 	  "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
173 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
174 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
175 	},
176 
177 	{
178 	  "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
179 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
180 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
181 	},
182 
183 	/* The Mac Mini has no SMS */
184 	{
185 	  "Macmini1,1", "Apple SMC Mac Mini",
186 	  NULL, NULL, NULL,
187 	  ASMC_FAN_FUNCS,
188 	  NULL, NULL,
189 	  ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
190 	},
191 
192 	/* Idem for the MacPro */
193 	{
194 	  "MacPro2", "Apple SMC Mac Pro (8-core)",
195 	  NULL, NULL, NULL,
196 	  ASMC_FAN_FUNCS,
197 	  NULL, NULL,
198 	  ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS
199 	},
200 
201 	{
202 	  "MacBookAir1,1", "Apple SMC MacBook Air",
203 	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL,
204 	  ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
205 	},
206 
207 
208 	{ NULL, NULL }
209 };
210 
211 #undef ASMC_SMS_FUNCS
212 #undef ASMC_FAN_FUNCS
213 #undef ASMC_LIGHT_FUNCS
214 
215 /*
216  * Driver methods.
217  */
218 static device_method_t	asmc_methods[] = {
219 	DEVMETHOD(device_probe,		asmc_probe),
220 	DEVMETHOD(device_attach,	asmc_attach),
221 	DEVMETHOD(device_detach,	asmc_detach),
222 
223 	{ 0, 0 }
224 };
225 
226 static driver_t	asmc_driver = {
227 	"asmc",
228 	asmc_methods,
229 	sizeof(struct asmc_softc)
230 };
231 
232 /*
233  * Debugging
234  */
235 #define	_COMPONENT	ACPI_OEM
236 ACPI_MODULE_NAME("ASMC")
237 #ifdef DEBUG
238 #define ASMC_DPRINTF(str)	device_printf(dev, str)
239 #else
240 #define ASMC_DPRINTF(str)
241 #endif
242 
243 static char *asmc_ids[] = { "APP0001", NULL };
244 
245 static devclass_t asmc_devclass;
246 
247 DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL);
248 MODULE_DEPEND(asmc, acpi, 1, 1, 1);
249 
250 static struct asmc_model *
251 asmc_match(device_t dev)
252 {
253 	int i;
254 	char *model;
255 
256 	model = getenv("smbios.system.product");
257 	if (model == NULL)
258 		return (NULL);
259 
260 	for (i = 0; asmc_models[i].smc_model; i++) {
261 		if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) {
262 			freeenv(model);
263 			return (&asmc_models[i]);
264 		}
265 	}
266 	freeenv(model);
267 
268 	return (NULL);
269 }
270 
271 static int
272 asmc_probe(device_t dev)
273 {
274 	struct asmc_model *model;
275 
276 	if (resource_disabled("asmc", 0))
277 		return (ENXIO);
278 	if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL)
279 		return (ENXIO);
280 
281 	model = asmc_match(dev);
282 	if (!model) {
283 		device_printf(dev, "model not recognized\n");
284 		return (ENXIO);
285 	}
286 	device_set_desc(dev, model->smc_desc);
287 
288 	return (BUS_PROBE_DEFAULT);
289 }
290 
291 static int
292 asmc_attach(device_t dev)
293 {
294 	int i, j;
295 	int ret;
296 	char name[2];
297 	struct asmc_softc *sc = device_get_softc(dev);
298 	struct sysctl_ctx_list *sysctlctx;
299 	struct sysctl_oid *sysctlnode;
300 	struct asmc_model *model;
301 
302 	sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
303 	    &sc->sc_rid_port, RF_ACTIVE);
304 	if (sc->sc_ioport == NULL) {
305 		device_printf(dev, "unable to allocate IO port\n");
306 		return (ENOMEM);
307 	}
308 
309 	sysctlctx  = device_get_sysctl_ctx(dev);
310 	sysctlnode = device_get_sysctl_tree(dev);
311 
312 	model = asmc_match(dev);
313 
314 	mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
315 
316 	sc->sc_model = model;
317 	asmc_init(dev);
318 
319 	/*
320 	 * dev.asmc.n.fan.* tree.
321 	 */
322 	sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
323 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
324 	    CTLFLAG_RD, 0, "Fan Root Tree");
325 
326 	for (i = 1; i <= sc->sc_nfan; i++) {
327 		j = i - 1;
328 		name[0] = '0' + j;
329 		name[1] = 0;
330 		sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
331 		    SYSCTL_CHILDREN(sc->sc_fan_tree[0]),
332 		    OID_AUTO, name, CTLFLAG_RD, 0,
333 		    "Fan Subtree");
334 
335 		SYSCTL_ADD_PROC(sysctlctx,
336 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
337 		    OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD,
338 		    dev, j, model->smc_fan_speed, "I",
339 		    "Fan speed in RPM");
340 
341 		SYSCTL_ADD_PROC(sysctlctx,
342 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
343 		    OID_AUTO, "safespeed",
344 		    CTLTYPE_INT | CTLFLAG_RD,
345 		    dev, j, model->smc_fan_safespeed, "I",
346 		    "Fan safe speed in RPM");
347 
348 		SYSCTL_ADD_PROC(sysctlctx,
349 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
350 		    OID_AUTO, "minspeed",
351 		    CTLTYPE_INT | CTLFLAG_RD,
352 		    dev, j, model->smc_fan_minspeed, "I",
353 		    "Fan minimum speed in RPM");
354 
355 		SYSCTL_ADD_PROC(sysctlctx,
356 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
357 		    OID_AUTO, "maxspeed",
358 		    CTLTYPE_INT | CTLFLAG_RD,
359 		    dev, j, model->smc_fan_maxspeed, "I",
360 		    "Fan maximum speed in RPM");
361 
362 		SYSCTL_ADD_PROC(sysctlctx,
363 		    SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
364 		    OID_AUTO, "targetspeed",
365 		    CTLTYPE_INT | CTLFLAG_RD,
366 		    dev, j, model->smc_fan_targetspeed, "I",
367 		    "Fan target speed in RPM");
368 	}
369 
370 	/*
371 	 * dev.asmc.n.temp tree.
372 	 */
373 	sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
374 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
375 	    CTLFLAG_RD, 0, "Temperature sensors");
376 
377 	for (i = 0; model->smc_temps[i]; i++) {
378 		SYSCTL_ADD_PROC(sysctlctx,
379 		    SYSCTL_CHILDREN(sc->sc_temp_tree),
380 		    OID_AUTO, model->smc_tempnames[i],
381 		    CTLTYPE_INT | CTLFLAG_RD,
382 		    dev, i, asmc_temp_sysctl, "I",
383 		    model->smc_tempdescs[i]);
384 	}
385 
386 	if (model->smc_sms_x == NULL)
387 		goto nosms;
388 
389 	/*
390 	 * dev.asmc.n.sms tree.
391 	 */
392 	sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
393 	    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
394 	    CTLFLAG_RD, 0, "Sudden Motion Sensor");
395 
396 	SYSCTL_ADD_PROC(sysctlctx,
397 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
398 	    OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD,
399 	    dev, 0, model->smc_sms_x, "I",
400 	    "Sudden Motion Sensor X value");
401 
402 	SYSCTL_ADD_PROC(sysctlctx,
403 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
404 	    OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD,
405 	    dev, 0, model->smc_sms_y, "I",
406 	    "Sudden Motion Sensor Y value");
407 
408 	SYSCTL_ADD_PROC(sysctlctx,
409 	    SYSCTL_CHILDREN(sc->sc_sms_tree),
410 	    OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD,
411 	    dev, 0, model->smc_sms_z, "I",
412 	    "Sudden Motion Sensor Z value");
413 
414 	/*
415 	 * dev.asmc.n.light
416 	 */
417 	if (model->smc_light_left) {
418 		sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
419 		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
420 		    CTLFLAG_RD, 0, "Keyboard backlight sensors");
421 
422 		SYSCTL_ADD_PROC(sysctlctx,
423 		    SYSCTL_CHILDREN(sc->sc_light_tree),
424 		    OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RW,
425 		    dev, 0, model->smc_light_left, "I",
426 		    "Keyboard backlight left sensor");
427 
428 		SYSCTL_ADD_PROC(sysctlctx,
429 		    SYSCTL_CHILDREN(sc->sc_light_tree),
430 		    OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RW,
431 		    dev, 0, model->smc_light_right, "I",
432 		    "Keyboard backlight right sensor");
433 	}
434 
435 	/*
436 	 * Need a taskqueue to send devctl_notify() events
437 	 * when the SMS interrupt us.
438 	 *
439 	 * PI_REALTIME is used due to the sensitivity of the
440 	 * interrupt. An interrupt from the SMS means that the
441 	 * disk heads should be turned off as quickly as possible.
442 	 *
443 	 * We only need to do this for the non INTR_FILTER case.
444 	 */
445 	sc->sc_sms_tq = NULL;
446 #ifndef INTR_FILTER
447 	TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
448 	sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
449 	    taskqueue_thread_enqueue, &sc->sc_sms_tq);
450 	taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
451 	    device_get_nameunit(dev));
452 #endif
453 	/*
454 	 * Allocate an IRQ for the SMS.
455 	 */
456 	sc->sc_rid_irq = 0;
457 	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
458 	    &sc->sc_rid_irq, RF_ACTIVE);
459 	if (sc->sc_irq == NULL) {
460 		device_printf(dev, "unable to allocate IRQ resource\n");
461 		ret = ENXIO;
462 		goto err2;
463 	}
464 
465 	ret = bus_setup_intr(dev, sc->sc_irq,
466 	          INTR_TYPE_MISC | INTR_MPSAFE,
467 #ifdef INTR_FILTER
468 	    asmc_sms_intrfast, asmc_sms_handler,
469 #else
470 	    asmc_sms_intrfast, NULL,
471 #endif
472 	    dev, &sc->sc_cookie);
473 
474 	if (ret) {
475 		device_printf(dev, "unable to setup SMS IRQ\n");
476 		goto err1;
477 	}
478 nosms:
479 	return (0);
480 err1:
481 	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq);
482 err2:
483 	bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
484 	    sc->sc_ioport);
485 	mtx_destroy(&sc->sc_mtx);
486 	if (sc->sc_sms_tq)
487 		taskqueue_free(sc->sc_sms_tq);
488 
489 	return (ret);
490 }
491 
492 static int
493 asmc_detach(device_t dev)
494 {
495 	struct asmc_softc *sc = device_get_softc(dev);
496 
497 	if (sc->sc_sms_tq) {
498 		taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
499 		taskqueue_free(sc->sc_sms_tq);
500 	}
501 	if (sc->sc_cookie)
502 		bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
503 	if (sc->sc_irq)
504 		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
505 		    sc->sc_irq);
506 	if (sc->sc_ioport)
507 		bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
508 		    sc->sc_ioport);
509 	mtx_destroy(&sc->sc_mtx);
510 
511 	return (0);
512 }
513 
514 static int
515 asmc_init(device_t dev)
516 {
517 	struct asmc_softc *sc = device_get_softc(dev);
518 	int i, error = 1;
519 	uint8_t buf[4];
520 
521 	if (sc->sc_model->smc_sms_x == NULL)
522 		goto nosms;
523 
524 	/*
525 	 * We are ready to recieve interrupts from the SMS.
526 	 */
527 	buf[0] = 0x01;
528 	ASMC_DPRINTF(("intok key\n"));
529 	asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
530 	DELAY(50);
531 
532 	/*
533 	 * Initiate the polling intervals.
534 	 */
535 	buf[0] = 20; /* msecs */
536 	ASMC_DPRINTF(("low int key\n"));
537 	asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
538 	DELAY(200);
539 
540 	buf[0] = 20; /* msecs */
541 	ASMC_DPRINTF(("high int key\n"));
542 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
543 	DELAY(200);
544 
545 	buf[0] = 0x00;
546 	buf[1] = 0x60;
547 	ASMC_DPRINTF(("sms low key\n"));
548 	asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
549 	DELAY(200);
550 
551 	buf[0] = 0x01;
552 	buf[1] = 0xc0;
553 	ASMC_DPRINTF(("sms high key\n"));
554 	asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
555 	DELAY(200);
556 
557 	/*
558 	 * I'm not sure what this key does, but it seems to be
559 	 * required.
560 	 */
561 	buf[0] = 0x01;
562 	ASMC_DPRINTF(("sms flag key\n"));
563 	asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
564 	DELAY(100);
565 
566 	/*
567 	 * Wait up to 5 seconds for SMS initialization.
568 	 */
569 	for (i = 0; i < 10000; i++) {
570 		if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
571 		    (buf[0] != 0x00 || buf[1] != 0x00)) {
572 			error = 0;
573 			goto out;
574 		}
575 		buf[0] = ASMC_SMS_INIT1;
576 		buf[1] = ASMC_SMS_INIT2;
577 		ASMC_DPRINTF(("sms key\n"));
578 		asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
579 		DELAY(50);
580 	}
581 	device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
582 
583 out:
584 	asmc_sms_calibrate(dev);
585 nosms:
586 	sc->sc_nfan = asmc_fan_count(dev);
587 	if (sc->sc_nfan > ASMC_MAXFANS) {
588 		device_printf(dev, "more than %d fans were detected. Please "
589 		    "report this.\n", ASMC_MAXFANS);
590 		sc->sc_nfan = ASMC_MAXFANS;
591 	}
592 
593 	if (bootverbose) {
594 		/*
595 		 * XXX: The number of keys is a 32 bit buffer, but
596 		 * right now Apple only uses the last 8 bit.
597 		 */
598 		asmc_key_read(dev, ASMC_NKEYS, buf, 4);
599 		device_printf(dev, "number of keys: %d\n", buf[3]);
600 	}
601 
602 	return (error);
603 }
604 
605 /*
606  * We need to make sure that the SMC acks the byte sent.
607  * Just wait up to 100 ms.
608  */
609 static int
610 asmc_wait(device_t dev, uint8_t val)
611 {
612 	struct asmc_softc *sc = device_get_softc(dev);
613 	u_int i;
614 
615 	val = val & ASMC_STATUS_MASK;
616 
617 	for (i = 0; i < 1000; i++) {
618 		if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
619 			return (0);
620 		DELAY(10);
621 	}
622 
623 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val,
624 	    ASMC_CMDPORT_READ(sc));
625 
626 	return (1);
627 }
628 
629 static int
630 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
631 {
632 	int i, error = 1;
633 	struct asmc_softc *sc = device_get_softc(dev);
634 
635 	mtx_lock_spin(&sc->sc_mtx);
636 
637 	ASMC_CMDPORT_WRITE(sc, ASMC_CMDREAD);
638 	if (asmc_wait(dev, 0x0c))
639 		goto out;
640 
641 	for (i = 0; i < 4; i++) {
642 		ASMC_DATAPORT_WRITE(sc, key[i]);
643 		if (asmc_wait(dev, 0x04))
644 			goto out;
645 	}
646 
647 	ASMC_DATAPORT_WRITE(sc, len);
648 
649 	for (i = 0; i < len; i++) {
650 		if (asmc_wait(dev, 0x05))
651 			goto out;
652 		buf[i] = ASMC_DATAPORT_READ(sc);
653 	}
654 
655 	error = 0;
656 out:
657 	mtx_unlock_spin(&sc->sc_mtx);
658 
659 	return (error);
660 }
661 
662 static int
663 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
664 {
665 	int i, error = -1;
666 	struct asmc_softc *sc = device_get_softc(dev);
667 
668 	mtx_lock_spin(&sc->sc_mtx);
669 
670 	ASMC_DPRINTF(("cmd port: cmd write\n"));
671 	ASMC_CMDPORT_WRITE(sc, ASMC_CMDWRITE);
672 	if (asmc_wait(dev, 0x0c))
673 		goto out;
674 
675 	ASMC_DPRINTF(("data port: key\n"));
676 	for (i = 0; i < 4; i++) {
677 		ASMC_DATAPORT_WRITE(sc, key[i]);
678 		if (asmc_wait(dev, 0x04))
679 			goto out;
680 	}
681 	ASMC_DPRINTF(("data port: length\n"));
682 	ASMC_DATAPORT_WRITE(sc, len);
683 
684 	ASMC_DPRINTF(("data port: buffer\n"));
685 	for (i = 0; i < len; i++) {
686 		if (asmc_wait(dev, 0x04))
687 			goto out;
688 		ASMC_DATAPORT_WRITE(sc, buf[i]);
689 	}
690 
691 	error = 0;
692 out:
693 	mtx_unlock_spin(&sc->sc_mtx);
694 
695 	return (error);
696 
697 }
698 
699 /*
700  * Fan control functions.
701  */
702 static int
703 asmc_fan_count(device_t dev)
704 {
705 	uint8_t buf[1];
706 
707 	if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, 1) < 0)
708 		return (-1);
709 
710 	return (buf[0]);
711 }
712 
713 static int
714 asmc_fan_getvalue(device_t dev, const char *key, int fan)
715 {
716 	int speed;
717 	uint8_t buf[2];
718 	char fankey[5];
719 
720 	snprintf(fankey, sizeof(fankey), key, fan);
721 	if (asmc_key_read(dev, fankey, buf, 2) < 0)
722 		return (-1);
723 	speed = (buf[0] << 6) | (buf[1] >> 2);
724 
725 	return (speed);
726 }
727 
728 static int
729 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
730 {
731 	device_t dev = (device_t) arg1;
732 	int fan = arg2;
733 	int error;
734 	int32_t v;
735 
736 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
737 	error = sysctl_handle_int(oidp, &v, 0, req);
738 
739 	return (error);
740 }
741 
742 static int
743 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
744 {
745 	device_t dev = (device_t) arg1;
746 	int fan = arg2;
747 	int error;
748 	int32_t v;
749 
750 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
751 	error = sysctl_handle_int(oidp, &v, 0, req);
752 
753 	return (error);
754 }
755 
756 
757 static int
758 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
759 {
760 	device_t dev = (device_t) arg1;
761 	int fan = arg2;
762 	int error;
763 	int32_t v;
764 
765 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
766 	error = sysctl_handle_int(oidp, &v, 0, req);
767 
768 	return (error);
769 }
770 
771 static int
772 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
773 {
774 	device_t dev = (device_t) arg1;
775 	int fan = arg2;
776 	int error;
777 	int32_t v;
778 
779 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
780 	error = sysctl_handle_int(oidp, &v, 0, req);
781 
782 	return (error);
783 }
784 
785 static int
786 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
787 {
788 	device_t dev = (device_t) arg1;
789 	int fan = arg2;
790 	int error;
791 	int32_t v;
792 
793 	v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
794 	error = sysctl_handle_int(oidp, &v, 0, req);
795 
796 	return (error);
797 }
798 
799 /*
800  * Temperature functions.
801  */
802 static int
803 asmc_temp_getvalue(device_t dev, const char *key)
804 {
805 	uint8_t buf[2];
806 
807 	/*
808 	 * Check for invalid temperatures.
809 	 */
810 	if (asmc_key_read(dev, key, buf, 2) < 0)
811 		return (-1);
812 
813 	return (buf[0]);
814 }
815 
816 static int
817 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
818 {
819 	device_t dev = (device_t) arg1;
820 	struct asmc_softc *sc = device_get_softc(dev);
821 	int error, val;
822 
823 	val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
824 	error = sysctl_handle_int(oidp, &val, 0, req);
825 
826 	return (error);
827 }
828 
829 /*
830  * Sudden Motion Sensor functions.
831  */
832 static int
833 asmc_sms_read(device_t dev, const char *key, int16_t *val)
834 {
835 	uint8_t buf[2];
836 	int error;
837 
838 	/* no need to do locking here as asmc_key_read() already does it */
839 	switch (key[3]) {
840 	case 'X':
841 	case 'Y':
842 	case 'Z':
843 		error =	asmc_key_read(dev, key, buf, 2);
844 		break;
845 	default:
846 		device_printf(dev, "%s called with invalid argument %s\n",
847 			      __func__, key);
848 		error = 1;
849 		goto out;
850 	}
851 	*val = ((int16_t)buf[0] << 8) | buf[1];
852 out:
853 	return (error);
854 }
855 
856 static void
857 asmc_sms_calibrate(device_t dev)
858 {
859 	struct asmc_softc *sc = device_get_softc(dev);
860 
861 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
862 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
863 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
864 }
865 
866 static int
867 asmc_sms_intrfast(void *arg)
868 {
869 	uint8_t type;
870 	device_t dev = (device_t) arg;
871 	struct asmc_softc *sc = device_get_softc(dev);
872 
873 	mtx_lock_spin(&sc->sc_mtx);
874 	type = ASMC_INTPORT_READ(sc);
875 	mtx_unlock_spin(&sc->sc_mtx);
876 
877 	sc->sc_sms_intrtype = type;
878 	asmc_sms_printintr(dev, type);
879 
880 #ifdef INTR_FILTER
881 	return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED);
882 #else
883 	taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
884 #endif
885 	return (FILTER_HANDLED);
886 }
887 
888 #ifdef INTR_FILTER
889 static void
890 asmc_sms_handler(void *arg)
891 {
892 	struct asmc_softc *sc = device_get_softc(arg);
893 
894 	asmc_sms_task(sc, 0);
895 }
896 #endif
897 
898 
899 static void
900 asmc_sms_printintr(device_t dev, uint8_t type)
901 {
902 
903 	switch (type) {
904 	case ASMC_SMS_INTFF:
905 		device_printf(dev, "WARNING: possible free fall!\n");
906 		break;
907 	case ASMC_SMS_INTHA:
908 		device_printf(dev, "WARNING: high acceleration detected!\n");
909 		break;
910 	case ASMC_SMS_INTSH:
911 		device_printf(dev, "WARNING: possible shock!\n");
912 		break;
913 	default:
914 		device_printf(dev, "%s unknown interrupt\n", __func__);
915 	}
916 }
917 
918 static void
919 asmc_sms_task(void *arg, int pending)
920 {
921 	struct asmc_softc *sc = (struct asmc_softc *)arg;
922 	char notify[16];
923 	int type;
924 
925 	switch (sc->sc_sms_intrtype) {
926 	case ASMC_SMS_INTFF:
927 		type = 2;
928 		break;
929 	case ASMC_SMS_INTHA:
930 		type = 1;
931 		break;
932 	case ASMC_SMS_INTSH:
933 		type = 0;
934 		break;
935 	default:
936 		type = 255;
937 	}
938 
939 	snprintf(notify, sizeof(notify), " notify=0x%x", type);
940 	devctl_notify("ACPI", "asmc", "SMS", notify);
941 }
942 
943 static int
944 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
945 {
946 	device_t dev = (device_t) arg1;
947 	int error;
948 	int16_t val;
949 	int32_t v;
950 
951 	asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
952 	v = (int32_t) val;
953 	error = sysctl_handle_int(oidp, &v, 0, req);
954 
955 	return (error);
956 }
957 
958 static int
959 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
960 {
961 	device_t dev = (device_t) arg1;
962 	int error;
963 	int16_t val;
964 	int32_t v;
965 
966 	asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
967 	v = (int32_t) val;
968 	error = sysctl_handle_int(oidp, &v, 0, req);
969 
970 	return (error);
971 }
972 
973 static int
974 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
975 {
976 	device_t dev = (device_t) arg1;
977 	int error;
978 	int16_t val;
979 	int32_t v;
980 
981 	asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
982 	v = (int32_t) val;
983 	error = sysctl_handle_int(oidp, &v, sizeof(v), req);
984 
985 	return (error);
986 }
987 
988 static int
989 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
990 {
991 	device_t dev = (device_t) arg1;
992 	uint8_t buf[6];
993 	int error;
994 	unsigned int level;
995 	int32_t v;
996 
997 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, 6);
998 	v = buf[2];
999 	error = sysctl_handle_int(oidp, &v, sizeof(v), req);
1000 	if (error == 0 && req->newptr != NULL) {
1001 		level = *(unsigned int *)req->newptr;
1002 		if (level > 255)
1003 			return (EINVAL);
1004 		buf[0] = level;
1005 		buf[1] = 0x00;
1006 		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2);
1007 	}
1008 
1009 	return (error);
1010 }
1011 
1012 static int
1013 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
1014 {
1015 	device_t dev = (device_t) arg1;
1016 	uint8_t buf[6];
1017 	int error;
1018 	unsigned int level;
1019 	int32_t v;
1020 
1021 	asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, 6);
1022 	v = buf[2];
1023 	error = sysctl_handle_int(oidp, &v, sizeof(v), req);
1024 	if (error == 0 && req->newptr != NULL) {
1025 		level = *(unsigned int *)req->newptr;
1026 		if (level > 255)
1027 			return (EINVAL);
1028 		buf[0] = level;
1029 		buf[1] = 0x00;
1030 		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2);
1031 	}
1032 
1033 	return (error);
1034 }
1035