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