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