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