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