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