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