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