]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/asmc/asmc.c
Upgrade Unbound to 1.6.2. More to follow.
[FreeBSD/FreeBSD.git] / sys / dev / asmc / asmc.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29
30 /*
31  * Driver for Apple's System Management Console (SMC).
32  * SMC can be found on the MacBook, MacBook Pro and Mac Mini.
33  *
34  * Inspired by the Linux applesmc driver.
35  */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/conf.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/mutex.h>
48 #include <sys/sysctl.h>
49 #include <sys/systm.h>
50 #include <sys/taskqueue.h>
51 #include <sys/rman.h>
52
53 #include <machine/resource.h>
54
55 #include <contrib/dev/acpica/include/acpi.h>
56
57 #include <dev/acpica/acpivar.h>
58 #include <dev/asmc/asmcvar.h>
59
60 #include "opt_intr_filter.h"
61
62 /*
63  * Device interface.
64  */
65 static int      asmc_probe(device_t dev);
66 static int      asmc_attach(device_t dev);
67 static int      asmc_detach(device_t dev);
68 static int      asmc_resume(device_t dev);
69
70 /*
71  * SMC functions.
72  */
73 static int      asmc_init(device_t dev);
74 static int      asmc_command(device_t dev, uint8_t command);
75 static int      asmc_wait(device_t dev, uint8_t val);
76 static int      asmc_wait_ack(device_t dev, uint8_t val, int amount);
77 static int      asmc_key_write(device_t dev, const char *key, uint8_t *buf,
78     uint8_t len);
79 static int      asmc_key_read(device_t dev, const char *key, uint8_t *buf,
80     uint8_t);
81 static int      asmc_fan_count(device_t dev);
82 static int      asmc_fan_getvalue(device_t dev, const char *key, int fan);
83 static int      asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed);
84 static int      asmc_temp_getvalue(device_t dev, const char *key);
85 static int      asmc_sms_read(device_t, const char *key, int16_t *val);
86 static void     asmc_sms_calibrate(device_t dev);
87 static int      asmc_sms_intrfast(void *arg);
88 #ifdef INTR_FILTER
89 static void     asmc_sms_handler(void *arg);
90 #endif
91 static void     asmc_sms_printintr(device_t dev, uint8_t);
92 static void     asmc_sms_task(void *arg, int pending);
93 #ifdef DEBUG
94 void            asmc_dumpall(device_t);
95 static int      asmc_key_dump(device_t, int);
96 #endif
97
98 /*
99  * Model functions.
100  */
101 static int      asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS);
102 static int      asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS);
103 static int      asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS);
104 static int      asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS);
105 static int      asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS);
106 static int      asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS);
107 static int      asmc_temp_sysctl(SYSCTL_HANDLER_ARGS);
108 static int      asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS);
109 static int      asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS);
110 static int      asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
111 static int      asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
112 static int      asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
113 static int      asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
114
115 struct asmc_model {
116         const char       *smc_model;    /* smbios.system.product env var. */
117         const char       *smc_desc;     /* driver description */
118
119         /* Helper functions */
120         int (*smc_sms_x)(SYSCTL_HANDLER_ARGS);
121         int (*smc_sms_y)(SYSCTL_HANDLER_ARGS);
122         int (*smc_sms_z)(SYSCTL_HANDLER_ARGS);
123         int (*smc_fan_id)(SYSCTL_HANDLER_ARGS);
124         int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS);
125         int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS);
126         int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS);
127         int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS);
128         int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
129         int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
130         int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
131         int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
132
133         const char      *smc_temps[ASMC_TEMP_MAX];
134         const char      *smc_tempnames[ASMC_TEMP_MAX];
135         const char      *smc_tempdescs[ASMC_TEMP_MAX];
136 };
137
138 static struct asmc_model *asmc_match(device_t dev);
139
140 #define ASMC_SMS_FUNCS  asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \
141                         asmc_mb_sysctl_sms_z
142
143 #define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL
144
145 #define ASMC_FAN_FUNCS  asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \
146                         asmc_mb_sysctl_fanminspeed, \
147                         asmc_mb_sysctl_fanmaxspeed, \
148                         asmc_mb_sysctl_fantargetspeed
149
150 #define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \
151                         asmc_mb_sysctl_fanminspeed, \
152                         asmc_mb_sysctl_fanmaxspeed, \
153                         asmc_mb_sysctl_fantargetspeed
154
155 #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \
156                          asmc_mbp_sysctl_light_right, \
157                          asmc_mbp_sysctl_light_control
158
159 struct asmc_model asmc_models[] = {
160         {
161           "MacBook1,1", "Apple SMC MacBook Core Duo",
162           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
163           ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
164         },
165
166         {
167           "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
168           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
169           ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
170         },
171
172         {
173           "MacBook3,1", "Apple SMC MacBook Core 2 Duo",
174           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
175           ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS
176         },
177
178         {
179           "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)",
180           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
181           ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
182         },
183
184         {
185           "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)",
186           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
187           ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
188         },
189
190         {
191           "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
192           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
193           ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
194         },
195
196         {
197           "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
198           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
199           ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
200         },
201
202         {
203           "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
204           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
205           ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
206         },
207
208         {
209           "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
210           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
211           ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
212         },
213
214         {
215           "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
216           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
217           ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
218         },
219
220         {
221           "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)",
222           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
223           ASMC_MBP5_TEMPS, ASMC_MBP5_TEMPNAMES, ASMC_MBP5_TEMPDESCS
224         },
225
226         {
227           "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)",
228           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
229           ASMC_MBP8_TEMPS, ASMC_MBP8_TEMPNAMES, ASMC_MBP8_TEMPDESCS
230         },
231
232         {
233           "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
234           ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS,
235           ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS
236         },
237
238         {
239           "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)",
240           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
241           ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS
242         },
243
244         /* The Mac Mini has no SMS */
245         {
246           "Macmini1,1", "Apple SMC Mac Mini",
247           NULL, NULL, NULL,
248           ASMC_FAN_FUNCS,
249           NULL, NULL, NULL,
250           ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
251         },
252
253         /* The Mac Mini 3,1 has no SMS */
254         {
255           "Macmini3,1", "Apple SMC Mac Mini 3,1",
256           NULL, NULL, NULL,
257           ASMC_FAN_FUNCS,
258           NULL, NULL, NULL,
259           ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS
260         },
261
262         /* Idem for the MacPro */
263         {
264           "MacPro2", "Apple SMC Mac Pro (8-core)",
265           NULL, NULL, NULL,
266           ASMC_FAN_FUNCS,
267           NULL, NULL, NULL,
268           ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS
269         },
270
271         /* Idem for the MacPro  2010*/
272         {
273           "MacPro5,1", "Apple SMC MacPro (2010)",
274           NULL, NULL, NULL,
275           ASMC_FAN_FUNCS,
276           NULL, NULL, NULL,
277           ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS
278         },
279
280         {
281           "MacBookAir1,1", "Apple SMC MacBook Air",
282           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
283           ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
284         },
285
286         {
287           "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)",
288           ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
289           ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS
290         },
291
292         {
293           "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)",
294           ASMC_SMS_FUNCS_DISABLED,
295           ASMC_FAN_FUNCS2,
296           ASMC_LIGHT_FUNCS,
297           ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
298         },
299
300         {
301           "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)",
302           ASMC_SMS_FUNCS_DISABLED,
303           ASMC_FAN_FUNCS2,
304           ASMC_LIGHT_FUNCS,
305           ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS
306         },
307
308
309         { NULL, NULL }
310 };
311
312 #undef ASMC_SMS_FUNCS
313 #undef ASMC_SMS_FUNCS_DISABLED
314 #undef ASMC_FAN_FUNCS
315 #undef ASMC_FAN_FUNCS2
316 #undef ASMC_LIGHT_FUNCS
317
318 /*
319  * Driver methods.
320  */
321 static device_method_t  asmc_methods[] = {
322         DEVMETHOD(device_probe,         asmc_probe),
323         DEVMETHOD(device_attach,        asmc_attach),
324         DEVMETHOD(device_detach,        asmc_detach),
325         DEVMETHOD(device_resume,        asmc_resume),
326
327         { 0, 0 }
328 };
329
330 static driver_t asmc_driver = {
331         "asmc",
332         asmc_methods,
333         sizeof(struct asmc_softc)
334 };
335
336 /*
337  * Debugging
338  */
339 #define _COMPONENT      ACPI_OEM
340 ACPI_MODULE_NAME("ASMC")
341 #ifdef DEBUG
342 #define ASMC_DPRINTF(str)       device_printf(dev, str)
343 #else
344 #define ASMC_DPRINTF(str)
345 #endif
346
347 /* NB: can't be const */
348 static char *asmc_ids[] = { "APP0001", NULL };
349
350 static devclass_t asmc_devclass;
351
352 static unsigned int light_control = 0;
353
354 DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL);
355 MODULE_DEPEND(asmc, acpi, 1, 1, 1);
356
357 static struct asmc_model *
358 asmc_match(device_t dev)
359 {
360         int i;
361         char *model;
362
363         model = kern_getenv("smbios.system.product");
364         if (model == NULL)
365                 return (NULL);
366
367         for (i = 0; asmc_models[i].smc_model; i++) {
368                 if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) {
369                         freeenv(model);
370                         return (&asmc_models[i]);
371                 }
372         }
373         freeenv(model);
374
375         return (NULL);
376 }
377
378 static int
379 asmc_probe(device_t dev)
380 {
381         struct asmc_model *model;
382
383         if (resource_disabled("asmc", 0))
384                 return (ENXIO);
385         if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL)
386                 return (ENXIO);
387
388         model = asmc_match(dev);
389         if (!model) {
390                 device_printf(dev, "model not recognized\n");
391                 return (ENXIO);
392         }
393         device_set_desc(dev, model->smc_desc);
394
395         return (BUS_PROBE_DEFAULT);
396 }
397
398 static int
399 asmc_attach(device_t dev)
400 {
401         int i, j;
402         int ret;
403         char name[2];
404         struct asmc_softc *sc = device_get_softc(dev);
405         struct sysctl_ctx_list *sysctlctx;
406         struct sysctl_oid *sysctlnode;
407         struct asmc_model *model;
408
409         sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
410             &sc->sc_rid_port, RF_ACTIVE);
411         if (sc->sc_ioport == NULL) {
412                 device_printf(dev, "unable to allocate IO port\n");
413                 return (ENOMEM);
414         }
415
416         sysctlctx  = device_get_sysctl_ctx(dev);
417         sysctlnode = device_get_sysctl_tree(dev);
418
419         model = asmc_match(dev);
420
421         mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN);
422
423         sc->sc_model = model;
424         asmc_init(dev);
425
426         /*
427          * dev.asmc.n.fan.* tree.
428          */
429         sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx,
430             SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan",
431             CTLFLAG_RD, 0, "Fan Root Tree");
432
433         for (i = 1; i <= sc->sc_nfan; i++) {
434                 j = i - 1;
435                 name[0] = '0' + j;
436                 name[1] = 0;
437                 sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx,
438                     SYSCTL_CHILDREN(sc->sc_fan_tree[0]),
439                     OID_AUTO, name, CTLFLAG_RD, 0,
440                     "Fan Subtree");
441
442                 SYSCTL_ADD_PROC(sysctlctx,
443                     SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
444                     OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD,
445                     dev, j, model->smc_fan_id, "I",
446                     "Fan ID");
447
448                 SYSCTL_ADD_PROC(sysctlctx,
449                     SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
450                     OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD,
451                     dev, j, model->smc_fan_speed, "I",
452                     "Fan speed in RPM");
453
454                 SYSCTL_ADD_PROC(sysctlctx,
455                     SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
456                     OID_AUTO, "safespeed",
457                     CTLTYPE_INT | CTLFLAG_RD,
458                     dev, j, model->smc_fan_safespeed, "I",
459                     "Fan safe speed in RPM");
460
461                 SYSCTL_ADD_PROC(sysctlctx,
462                     SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
463                     OID_AUTO, "minspeed",
464                     CTLTYPE_INT | CTLFLAG_RW,
465                     dev, j, model->smc_fan_minspeed, "I",
466                     "Fan minimum speed in RPM");
467
468                 SYSCTL_ADD_PROC(sysctlctx,
469                     SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
470                     OID_AUTO, "maxspeed",
471                     CTLTYPE_INT | CTLFLAG_RW,
472                     dev, j, model->smc_fan_maxspeed, "I",
473                     "Fan maximum speed in RPM");
474
475                 SYSCTL_ADD_PROC(sysctlctx,
476                     SYSCTL_CHILDREN(sc->sc_fan_tree[i]),
477                     OID_AUTO, "targetspeed",
478                     CTLTYPE_INT | CTLFLAG_RW,
479                     dev, j, model->smc_fan_targetspeed, "I",
480                     "Fan target speed in RPM");
481         }
482
483         /*
484          * dev.asmc.n.temp tree.
485          */
486         sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx,
487             SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp",
488             CTLFLAG_RD, 0, "Temperature sensors");
489
490         for (i = 0; model->smc_temps[i]; i++) {
491                 SYSCTL_ADD_PROC(sysctlctx,
492                     SYSCTL_CHILDREN(sc->sc_temp_tree),
493                     OID_AUTO, model->smc_tempnames[i],
494                     CTLTYPE_INT | CTLFLAG_RD,
495                     dev, i, asmc_temp_sysctl, "I",
496                     model->smc_tempdescs[i]);
497         }
498
499         /*
500          * dev.asmc.n.light
501          */
502         if (model->smc_light_left) {
503                 sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
504                     SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
505                     CTLFLAG_RD, 0, "Keyboard backlight sensors");
506
507                 SYSCTL_ADD_PROC(sysctlctx,
508                     SYSCTL_CHILDREN(sc->sc_light_tree),
509                     OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD,
510                     dev, 0, model->smc_light_left, "I",
511                     "Keyboard backlight left sensor");
512
513                 SYSCTL_ADD_PROC(sysctlctx,
514                     SYSCTL_CHILDREN(sc->sc_light_tree),
515                     OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD,
516                     dev, 0, model->smc_light_right, "I",
517                     "Keyboard backlight right sensor");
518
519                 SYSCTL_ADD_PROC(sysctlctx,
520                     SYSCTL_CHILDREN(sc->sc_light_tree),
521                     OID_AUTO, "control",
522                     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
523                     dev, 0, model->smc_light_control, "I",
524                     "Keyboard backlight brightness control");
525         }
526
527         if (model->smc_sms_x == NULL)
528                 goto nosms;
529
530         /*
531          * dev.asmc.n.sms tree.
532          */
533         sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx,
534             SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms",
535             CTLFLAG_RD, 0, "Sudden Motion Sensor");
536
537         SYSCTL_ADD_PROC(sysctlctx,
538             SYSCTL_CHILDREN(sc->sc_sms_tree),
539             OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD,
540             dev, 0, model->smc_sms_x, "I",
541             "Sudden Motion Sensor X value");
542
543         SYSCTL_ADD_PROC(sysctlctx,
544             SYSCTL_CHILDREN(sc->sc_sms_tree),
545             OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD,
546             dev, 0, model->smc_sms_y, "I",
547             "Sudden Motion Sensor Y value");
548
549         SYSCTL_ADD_PROC(sysctlctx,
550             SYSCTL_CHILDREN(sc->sc_sms_tree),
551             OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD,
552             dev, 0, model->smc_sms_z, "I",
553             "Sudden Motion Sensor Z value");
554
555         /*
556          * Need a taskqueue to send devctl_notify() events
557          * when the SMS interrupt us.
558          *
559          * PI_REALTIME is used due to the sensitivity of the
560          * interrupt. An interrupt from the SMS means that the
561          * disk heads should be turned off as quickly as possible.
562          *
563          * We only need to do this for the non INTR_FILTER case.
564          */
565         sc->sc_sms_tq = NULL;
566 #ifndef INTR_FILTER
567         TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
568         sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
569             taskqueue_thread_enqueue, &sc->sc_sms_tq);
570         taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
571             device_get_nameunit(dev));
572 #endif
573         /*
574          * Allocate an IRQ for the SMS.
575          */
576         sc->sc_rid_irq = 0;
577         sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
578             &sc->sc_rid_irq, RF_ACTIVE);
579         if (sc->sc_irq == NULL) {
580                 device_printf(dev, "unable to allocate IRQ resource\n");
581                 ret = ENXIO;
582                 goto err2;
583         }
584
585         ret = bus_setup_intr(dev, sc->sc_irq,
586                   INTR_TYPE_MISC | INTR_MPSAFE,
587 #ifdef INTR_FILTER
588             asmc_sms_intrfast, asmc_sms_handler,
589 #else
590             asmc_sms_intrfast, NULL,
591 #endif
592             dev, &sc->sc_cookie);
593
594         if (ret) {
595                 device_printf(dev, "unable to setup SMS IRQ\n");
596                 goto err1;
597         }
598 nosms:
599         return (0);
600 err1:
601         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq);
602 err2:
603         bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
604             sc->sc_ioport);
605         mtx_destroy(&sc->sc_mtx);
606         if (sc->sc_sms_tq)
607                 taskqueue_free(sc->sc_sms_tq);
608
609         return (ret);
610 }
611
612 static int
613 asmc_detach(device_t dev)
614 {
615         struct asmc_softc *sc = device_get_softc(dev);
616
617         if (sc->sc_sms_tq) {
618                 taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task);
619                 taskqueue_free(sc->sc_sms_tq);
620         }
621         if (sc->sc_cookie)
622                 bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie);
623         if (sc->sc_irq)
624                 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq,
625                     sc->sc_irq);
626         if (sc->sc_ioport)
627                 bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port,
628                     sc->sc_ioport);
629         mtx_destroy(&sc->sc_mtx);
630
631         return (0);
632 }
633
634 static int
635 asmc_resume(device_t dev)
636 {
637     uint8_t buf[2];
638     buf[0] = light_control;
639     buf[1] = 0x00;
640     asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
641     return (0);
642 }
643
644
645 #ifdef DEBUG
646 void asmc_dumpall(device_t dev)
647 {
648         int i;
649
650         /* XXX magic number */
651         for (i=0; i < 0x100; i++)
652                 asmc_key_dump(dev, i);
653 }
654 #endif
655
656 static int
657 asmc_init(device_t dev)
658 {
659         struct asmc_softc *sc = device_get_softc(dev);
660         int i, error = 1;
661         uint8_t buf[4];
662
663         if (sc->sc_model->smc_sms_x == NULL)
664                 goto nosms;
665
666         /*
667          * We are ready to receive interrupts from the SMS.
668          */
669         buf[0] = 0x01;
670         ASMC_DPRINTF(("intok key\n"));
671         asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1);
672         DELAY(50);
673
674         /*
675          * Initiate the polling intervals.
676          */
677         buf[0] = 20; /* msecs */
678         ASMC_DPRINTF(("low int key\n"));
679         asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1);
680         DELAY(200);
681
682         buf[0] = 20; /* msecs */
683         ASMC_DPRINTF(("high int key\n"));
684         asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1);
685         DELAY(200);
686
687         buf[0] = 0x00;
688         buf[1] = 0x60;
689         ASMC_DPRINTF(("sms low key\n"));
690         asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2);
691         DELAY(200);
692
693         buf[0] = 0x01;
694         buf[1] = 0xc0;
695         ASMC_DPRINTF(("sms high key\n"));
696         asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2);
697         DELAY(200);
698
699         /*
700          * I'm not sure what this key does, but it seems to be
701          * required.
702          */
703         buf[0] = 0x01;
704         ASMC_DPRINTF(("sms flag key\n"));
705         asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1);
706         DELAY(100);
707
708         sc->sc_sms_intr_works = 0;
709
710         /*
711          * Retry SMS initialization 1000 times
712          * (takes approx. 2 seconds in worst case)
713          */
714         for (i = 0; i < 1000; i++) {
715                 if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 &&
716                     (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) {
717                         error = 0;
718                         sc->sc_sms_intr_works = 1;
719                         goto out;
720                 }
721                 buf[0] = ASMC_SMS_INIT1;
722                 buf[1] = ASMC_SMS_INIT2;
723                 ASMC_DPRINTF(("sms key\n"));
724                 asmc_key_write(dev, ASMC_KEY_SMS, buf, 2);
725                 DELAY(50);
726         }
727         device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n");
728
729 out:
730         asmc_sms_calibrate(dev);
731 nosms:
732         sc->sc_nfan = asmc_fan_count(dev);
733         if (sc->sc_nfan > ASMC_MAXFANS) {
734                 device_printf(dev, "more than %d fans were detected. Please "
735                     "report this.\n", ASMC_MAXFANS);
736                 sc->sc_nfan = ASMC_MAXFANS;
737         }
738
739         if (bootverbose) {
740                 /*
741                  * The number of keys is a 32 bit buffer
742                  */
743                 asmc_key_read(dev, ASMC_NKEYS, buf, 4);
744                 device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf));
745         }
746
747 #ifdef DEBUG
748         asmc_dumpall(dev);
749 #endif
750
751         return (error);
752 }
753
754 /*
755  * We need to make sure that the SMC acks the byte sent.
756  * Just wait up to (amount * 10)  ms.
757  */
758 static int
759 asmc_wait_ack(device_t dev, uint8_t val, int amount)
760 {
761         struct asmc_softc *sc = device_get_softc(dev);
762         u_int i;
763
764         val = val & ASMC_STATUS_MASK;
765
766         for (i = 0; i < amount; i++) {
767                 if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
768                         return (0);
769                 DELAY(10);
770         }
771
772         return (1);
773 }
774
775 /*
776  * We need to make sure that the SMC acks the byte sent.
777  * Just wait up to 100 ms.
778  */
779 static int
780 asmc_wait(device_t dev, uint8_t val)
781 {
782         struct asmc_softc *sc;
783
784         if (asmc_wait_ack(dev, val, 1000) == 0)
785                 return (0);
786
787         sc = device_get_softc(dev);
788         val = val & ASMC_STATUS_MASK;
789
790 #ifdef DEBUG
791         device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val,
792             ASMC_CMDPORT_READ(sc));
793 #endif
794         return (1);
795 }
796
797 /*
798  * Send the given command, retrying up to 10 times if
799  * the acknowledgement fails.
800  */
801 static int
802 asmc_command(device_t dev, uint8_t command) {
803
804         int i;
805         struct asmc_softc *sc = device_get_softc(dev);
806
807         for (i=0; i < 10; i++) {
808                 ASMC_CMDPORT_WRITE(sc, command);
809                 if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
810                         return (0);
811                 }
812         }
813
814 #ifdef DEBUG
815         device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
816             ASMC_CMDPORT_READ(sc));
817 #endif
818         return (1);
819 }
820
821 static int
822 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
823 {
824         int i, error = 1, try = 0;
825         struct asmc_softc *sc = device_get_softc(dev);
826
827         mtx_lock_spin(&sc->sc_mtx);
828
829 begin:
830         if (asmc_command(dev, ASMC_CMDREAD))
831                 goto out;
832
833         for (i = 0; i < 4; i++) {
834                 ASMC_DATAPORT_WRITE(sc, key[i]);
835                 if (asmc_wait(dev, 0x04))
836                         goto out;
837         }
838
839         ASMC_DATAPORT_WRITE(sc, len);
840
841         for (i = 0; i < len; i++) {
842                 if (asmc_wait(dev, 0x05))
843                         goto out;
844                 buf[i] = ASMC_DATAPORT_READ(sc);
845         }
846
847         error = 0;
848 out:
849         if (error) {
850                 if (++try < 10) goto begin;
851                 device_printf(dev,"%s for key %s failed %d times, giving up\n",
852                         __func__, key, try);
853         }
854
855         mtx_unlock_spin(&sc->sc_mtx);
856
857         return (error);
858 }
859
860 #ifdef DEBUG
861 static int
862 asmc_key_dump(device_t dev, int number)
863 {
864         struct asmc_softc *sc = device_get_softc(dev);
865         char key[5] = { 0 };
866         char type[7] = { 0 };
867         uint8_t index[4];
868         uint8_t v[32];
869         uint8_t maxlen;
870         int i, error = 1, try = 0;
871
872         mtx_lock_spin(&sc->sc_mtx);
873
874         index[0] = (number >> 24) & 0xff;
875         index[1] = (number >> 16) & 0xff;
876         index[2] = (number >> 8) & 0xff;
877         index[3] = (number) & 0xff;
878
879 begin:
880         if (asmc_command(dev, 0x12))
881                 goto out;
882
883         for (i = 0; i < 4; i++) {
884                 ASMC_DATAPORT_WRITE(sc, index[i]);
885                 if (asmc_wait(dev, 0x04))
886                         goto out;
887         }
888
889         ASMC_DATAPORT_WRITE(sc, 4);
890
891         for (i = 0; i < 4; i++) {
892                 if (asmc_wait(dev, 0x05))
893                         goto out;
894                 key[i] = ASMC_DATAPORT_READ(sc);
895         }
896
897         /* get type */
898         if (asmc_command(dev, 0x13))
899                 goto out;
900
901         for (i = 0; i < 4; i++) {
902                 ASMC_DATAPORT_WRITE(sc, key[i]);
903                 if (asmc_wait(dev, 0x04))
904                         goto out;
905         }
906
907         ASMC_DATAPORT_WRITE(sc, 6);
908
909         for (i = 0; i < 6; i++) {
910                 if (asmc_wait(dev, 0x05))
911                         goto out;
912                 type[i] = ASMC_DATAPORT_READ(sc);
913         }
914
915         error = 0;
916 out:
917         if (error) {
918                 if (++try < 10) goto begin;
919                 device_printf(dev,"%s for key %s failed %d times, giving up\n",
920                         __func__, key, try);
921                 mtx_unlock_spin(&sc->sc_mtx);
922         }
923         else {
924                 char buf[1024];
925                 char buf2[8];
926                 mtx_unlock_spin(&sc->sc_mtx);
927                 maxlen = type[0];
928                 type[0] = ' ';
929                 type[5] = 0;
930                 if (maxlen > sizeof(v)) {
931                         device_printf(dev,
932                             "WARNING: cropping maxlen from %d to %zu\n",
933                             maxlen, sizeof(v));
934                         maxlen = sizeof(v);
935                 }
936                 for (i = 0; i < sizeof(v); i++) {
937                         v[i] = 0;
938                 }
939                 asmc_key_read(dev, key, v, maxlen);
940                 snprintf(buf, sizeof(buf), "key %d is: %s, type %s "
941                     "(len %d), data", number, key, type, maxlen);
942                 for (i = 0; i < maxlen; i++) {
943                         snprintf(buf2, sizeof(buf2), " %02x", v[i]);
944                         strlcat(buf, buf2, sizeof(buf));
945                 }
946                 strlcat(buf, " \n", sizeof(buf));
947                 device_printf(dev, "%s", buf);
948         }
949
950         return (error);
951 }
952 #endif
953
954 static int
955 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
956 {
957         int i, error = -1, try = 0;
958         struct asmc_softc *sc = device_get_softc(dev);
959
960         mtx_lock_spin(&sc->sc_mtx);
961
962 begin:
963         ASMC_DPRINTF(("cmd port: cmd write\n"));
964         if (asmc_command(dev, ASMC_CMDWRITE))
965                 goto out;
966
967         ASMC_DPRINTF(("data port: key\n"));
968         for (i = 0; i < 4; i++) {
969                 ASMC_DATAPORT_WRITE(sc, key[i]);
970                 if (asmc_wait(dev, 0x04))
971                         goto out;
972         }
973         ASMC_DPRINTF(("data port: length\n"));
974         ASMC_DATAPORT_WRITE(sc, len);
975
976         ASMC_DPRINTF(("data port: buffer\n"));
977         for (i = 0; i < len; i++) {
978                 if (asmc_wait(dev, 0x04))
979                         goto out;
980                 ASMC_DATAPORT_WRITE(sc, buf[i]);
981         }
982
983         error = 0;
984 out:
985         if (error) {
986                 if (++try < 10) goto begin;
987                 device_printf(dev,"%s for key %s failed %d times, giving up\n",
988                         __func__, key, try);
989         }
990
991         mtx_unlock_spin(&sc->sc_mtx);
992
993         return (error);
994
995 }
996
997 /*
998  * Fan control functions.
999  */
1000 static int
1001 asmc_fan_count(device_t dev)
1002 {
1003         uint8_t buf[1];
1004
1005         if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) < 0)
1006                 return (-1);
1007
1008         return (buf[0]);
1009 }
1010
1011 static int
1012 asmc_fan_getvalue(device_t dev, const char *key, int fan)
1013 {
1014         int speed;
1015         uint8_t buf[2];
1016         char fankey[5];
1017
1018         snprintf(fankey, sizeof(fankey), key, fan);
1019         if (asmc_key_read(dev, fankey, buf, sizeof buf) < 0)
1020                 return (-1);
1021         speed = (buf[0] << 6) | (buf[1] >> 2);
1022
1023         return (speed);
1024 }
1025
1026 static char*
1027 asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen)
1028 {
1029         char fankey[5];
1030         char* desc;
1031
1032         snprintf(fankey, sizeof(fankey), key, fan);
1033         if (asmc_key_read(dev, fankey, buf, buflen) < 0)
1034                 return (NULL);
1035         desc = buf+4;
1036
1037         return (desc);
1038 }
1039
1040 static int
1041 asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed)
1042 {
1043         uint8_t buf[2];
1044         char fankey[5];
1045
1046         speed *= 4;
1047
1048         buf[0] = speed>>8;
1049         buf[1] = speed;
1050
1051         snprintf(fankey, sizeof(fankey), key, fan);
1052         if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0)
1053                 return (-1);
1054
1055         return (0);
1056 }
1057
1058 static int
1059 asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS)
1060 {
1061         device_t dev = (device_t) arg1;
1062         int fan = arg2;
1063         int error;
1064         int32_t v;
1065
1066         v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan);
1067         error = sysctl_handle_int(oidp, &v, 0, req);
1068
1069         return (error);
1070 }
1071
1072 static int
1073 asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS)
1074 {
1075         uint8_t buf[16];
1076         device_t dev = (device_t) arg1;
1077         int fan = arg2;
1078         int error = true;
1079         char* desc;
1080
1081         desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf));
1082
1083         if (desc != NULL)
1084                 error = sysctl_handle_string(oidp, desc, 0, req);
1085
1086         return (error);
1087 }
1088
1089 static int
1090 asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS)
1091 {
1092         device_t dev = (device_t) arg1;
1093         int fan = arg2;
1094         int error;
1095         int32_t v;
1096
1097         v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan);
1098         error = sysctl_handle_int(oidp, &v, 0, req);
1099
1100         return (error);
1101 }
1102
1103
1104 static int
1105 asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS)
1106 {
1107         device_t dev = (device_t) arg1;
1108         int fan = arg2;
1109         int error;
1110         int32_t v;
1111
1112         v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan);
1113         error = sysctl_handle_int(oidp, &v, 0, req);
1114
1115         if (error == 0 && req->newptr != NULL) {
1116                 unsigned int newspeed = v;
1117                 asmc_fan_setvalue(dev, ASMC_KEY_FANMINSPEED, fan, newspeed);
1118         }
1119
1120         return (error);
1121 }
1122
1123 static int
1124 asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS)
1125 {
1126         device_t dev = (device_t) arg1;
1127         int fan = arg2;
1128         int error;
1129         int32_t v;
1130
1131         v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan);
1132         error = sysctl_handle_int(oidp, &v, 0, req);
1133
1134         if (error == 0 && req->newptr != NULL) {
1135                 unsigned int newspeed = v;
1136                 asmc_fan_setvalue(dev, ASMC_KEY_FANMAXSPEED, fan, newspeed);
1137         }
1138
1139         return (error);
1140 }
1141
1142 static int
1143 asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS)
1144 {
1145         device_t dev = (device_t) arg1;
1146         int fan = arg2;
1147         int error;
1148         int32_t v;
1149
1150         v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan);
1151         error = sysctl_handle_int(oidp, &v, 0, req);
1152
1153         if (error == 0 && req->newptr != NULL) {
1154                 unsigned int newspeed = v;
1155                 asmc_fan_setvalue(dev, ASMC_KEY_FANTARGETSPEED, fan, newspeed);
1156         }
1157
1158         return (error);
1159 }
1160
1161 /*
1162  * Temperature functions.
1163  */
1164 static int
1165 asmc_temp_getvalue(device_t dev, const char *key)
1166 {
1167         uint8_t buf[2];
1168
1169         /*
1170          * Check for invalid temperatures.
1171          */
1172         if (asmc_key_read(dev, key, buf, sizeof buf) < 0)
1173                 return (-1);
1174
1175         return (buf[0]);
1176 }
1177
1178 static int
1179 asmc_temp_sysctl(SYSCTL_HANDLER_ARGS)
1180 {
1181         device_t dev = (device_t) arg1;
1182         struct asmc_softc *sc = device_get_softc(dev);
1183         int error, val;
1184
1185         val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]);
1186         error = sysctl_handle_int(oidp, &val, 0, req);
1187
1188         return (error);
1189 }
1190
1191 /*
1192  * Sudden Motion Sensor functions.
1193  */
1194 static int
1195 asmc_sms_read(device_t dev, const char *key, int16_t *val)
1196 {
1197         uint8_t buf[2];
1198         int error;
1199
1200         /* no need to do locking here as asmc_key_read() already does it */
1201         switch (key[3]) {
1202         case 'X':
1203         case 'Y':
1204         case 'Z':
1205                 error = asmc_key_read(dev, key, buf, sizeof buf);
1206                 break;
1207         default:
1208                 device_printf(dev, "%s called with invalid argument %s\n",
1209                               __func__, key);
1210                 error = 1;
1211                 goto out;
1212         }
1213         *val = ((int16_t)buf[0] << 8) | buf[1];
1214 out:
1215         return (error);
1216 }
1217
1218 static void
1219 asmc_sms_calibrate(device_t dev)
1220 {
1221         struct asmc_softc *sc = device_get_softc(dev);
1222
1223         asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x);
1224         asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y);
1225         asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z);
1226 }
1227
1228 static int
1229 asmc_sms_intrfast(void *arg)
1230 {
1231         uint8_t type;
1232         device_t dev = (device_t) arg;
1233         struct asmc_softc *sc = device_get_softc(dev);
1234         if (!sc->sc_sms_intr_works)
1235                 return (FILTER_HANDLED);
1236
1237         mtx_lock_spin(&sc->sc_mtx);
1238         type = ASMC_INTPORT_READ(sc);
1239         mtx_unlock_spin(&sc->sc_mtx);
1240
1241         sc->sc_sms_intrtype = type;
1242         asmc_sms_printintr(dev, type);
1243
1244 #ifdef INTR_FILTER
1245         return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED);
1246 #else
1247         taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
1248 #endif
1249         return (FILTER_HANDLED);
1250 }
1251
1252 #ifdef INTR_FILTER
1253 static void
1254 asmc_sms_handler(void *arg)
1255 {
1256         struct asmc_softc *sc = device_get_softc(arg);
1257
1258         asmc_sms_task(sc, 0);
1259 }
1260 #endif
1261
1262
1263 static void
1264 asmc_sms_printintr(device_t dev, uint8_t type)
1265 {
1266
1267         switch (type) {
1268         case ASMC_SMS_INTFF:
1269                 device_printf(dev, "WARNING: possible free fall!\n");
1270                 break;
1271         case ASMC_SMS_INTHA:
1272                 device_printf(dev, "WARNING: high acceleration detected!\n");
1273                 break;
1274         case ASMC_SMS_INTSH:
1275                 device_printf(dev, "WARNING: possible shock!\n");
1276                 break;
1277         default:
1278                 device_printf(dev, "%s unknown interrupt\n", __func__);
1279         }
1280 }
1281
1282 static void
1283 asmc_sms_task(void *arg, int pending)
1284 {
1285         struct asmc_softc *sc = (struct asmc_softc *)arg;
1286         char notify[16];
1287         int type;
1288
1289         switch (sc->sc_sms_intrtype) {
1290         case ASMC_SMS_INTFF:
1291                 type = 2;
1292                 break;
1293         case ASMC_SMS_INTHA:
1294                 type = 1;
1295                 break;
1296         case ASMC_SMS_INTSH:
1297                 type = 0;
1298                 break;
1299         default:
1300                 type = 255;
1301         }
1302
1303         snprintf(notify, sizeof(notify), " notify=0x%x", type);
1304         devctl_notify("ACPI", "asmc", "SMS", notify);
1305 }
1306
1307 static int
1308 asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS)
1309 {
1310         device_t dev = (device_t) arg1;
1311         int error;
1312         int16_t val;
1313         int32_t v;
1314
1315         asmc_sms_read(dev, ASMC_KEY_SMS_X, &val);
1316         v = (int32_t) val;
1317         error = sysctl_handle_int(oidp, &v, 0, req);
1318
1319         return (error);
1320 }
1321
1322 static int
1323 asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS)
1324 {
1325         device_t dev = (device_t) arg1;
1326         int error;
1327         int16_t val;
1328         int32_t v;
1329
1330         asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val);
1331         v = (int32_t) val;
1332         error = sysctl_handle_int(oidp, &v, 0, req);
1333
1334         return (error);
1335 }
1336
1337 static int
1338 asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS)
1339 {
1340         device_t dev = (device_t) arg1;
1341         int error;
1342         int16_t val;
1343         int32_t v;
1344
1345         asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val);
1346         v = (int32_t) val;
1347         error = sysctl_handle_int(oidp, &v, 0, req);
1348
1349         return (error);
1350 }
1351
1352 static int
1353 asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS)
1354 {
1355         device_t dev = (device_t) arg1;
1356         uint8_t buf[6];
1357         int error;
1358         int32_t v;
1359
1360         asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf);
1361         v = buf[2];
1362         error = sysctl_handle_int(oidp, &v, 0, req);
1363
1364         return (error);
1365 }
1366
1367 static int
1368 asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS)
1369 {
1370         device_t dev = (device_t) arg1;
1371         uint8_t buf[6];
1372         int error;
1373         int32_t v;
1374
1375         asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf);
1376         v = buf[2];
1377         error = sysctl_handle_int(oidp, &v, 0, req);
1378
1379         return (error);
1380 }
1381
1382 static int
1383 asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
1384 {
1385         device_t dev = (device_t) arg1;
1386         uint8_t buf[2];
1387         int error;
1388         int v;
1389
1390         v = light_control;
1391         error = sysctl_handle_int(oidp, &v, 0, req);
1392
1393         if (error == 0 && req->newptr != NULL) {
1394                 if (v < 0 || v > 255)
1395                         return (EINVAL);
1396                 light_control = v;
1397                 buf[0] = light_control;
1398                 buf[1] = 0x00;
1399                 asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf);
1400         }
1401         return (error);
1402 }