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