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