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