132a8088fSRui Paulo /*- 24470f0f3SRui Paulo * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org> 332a8088fSRui Paulo * All rights reserved. 432a8088fSRui Paulo * 532a8088fSRui Paulo * Redistribution and use in source and binary forms, with or without 632a8088fSRui Paulo * modification, are permitted provided that the following conditions 732a8088fSRui Paulo * are met: 832a8088fSRui Paulo * 1. Redistributions of source code must retain the above copyright 932a8088fSRui Paulo * notice, this list of conditions and the following disclaimer. 1032a8088fSRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 1132a8088fSRui Paulo * notice, this list of conditions and the following disclaimer in the 1232a8088fSRui Paulo * documentation and/or other materials provided with the distribution. 1332a8088fSRui Paulo * 1432a8088fSRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1532a8088fSRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1632a8088fSRui Paulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1732a8088fSRui Paulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 1832a8088fSRui Paulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 1932a8088fSRui Paulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2032a8088fSRui Paulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2132a8088fSRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2232a8088fSRui Paulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2332a8088fSRui Paulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2432a8088fSRui Paulo * POSSIBILITY OF SUCH DAMAGE. 2532a8088fSRui Paulo * 2632a8088fSRui Paulo */ 2732a8088fSRui Paulo 2832a8088fSRui Paulo /* 2932a8088fSRui Paulo * Driver for Apple's System Management Console (SMC). 3032a8088fSRui Paulo * SMC can be found on the MacBook, MacBook Pro and Mac Mini. 3132a8088fSRui Paulo * 3232a8088fSRui Paulo * Inspired by the Linux applesmc driver. 3332a8088fSRui Paulo */ 3432a8088fSRui Paulo 3532a8088fSRui Paulo #include <sys/cdefs.h> 3632a8088fSRui Paulo __FBSDID("$FreeBSD$"); 3732a8088fSRui Paulo 3832a8088fSRui Paulo #include <sys/param.h> 3932a8088fSRui Paulo #include <sys/bus.h> 4032a8088fSRui Paulo #include <sys/conf.h> 4132a8088fSRui Paulo #include <sys/kernel.h> 4232a8088fSRui Paulo #include <sys/lock.h> 4332a8088fSRui Paulo #include <sys/malloc.h> 4432a8088fSRui Paulo #include <sys/module.h> 4532a8088fSRui Paulo #include <sys/mutex.h> 4632a8088fSRui Paulo #include <sys/sysctl.h> 4732a8088fSRui Paulo #include <sys/systm.h> 4832a8088fSRui Paulo #include <sys/taskqueue.h> 4932a8088fSRui Paulo #include <sys/rman.h> 504c061448SRui Paulo 5132a8088fSRui Paulo #include <machine/resource.h> 52129d3046SJung-uk Kim 53129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h> 54129d3046SJung-uk Kim 554470f0f3SRui Paulo #include <dev/acpica/acpivar.h> 5632a8088fSRui Paulo #include <dev/asmc/asmcvar.h> 5732a8088fSRui Paulo 584c061448SRui Paulo #include "opt_intr_filter.h" 594c061448SRui Paulo 6032a8088fSRui Paulo /* 6132a8088fSRui Paulo * Device interface. 6232a8088fSRui Paulo */ 6332a8088fSRui Paulo static int asmc_probe(device_t dev); 6432a8088fSRui Paulo static int asmc_attach(device_t dev); 6532a8088fSRui Paulo static int asmc_detach(device_t dev); 6632a8088fSRui Paulo 6732a8088fSRui Paulo /* 6832a8088fSRui Paulo * SMC functions. 6932a8088fSRui Paulo */ 7032a8088fSRui Paulo static int asmc_init(device_t dev); 71be80e49aSRui Paulo static int asmc_command(device_t dev, uint8_t command); 7232a8088fSRui Paulo static int asmc_wait(device_t dev, uint8_t val); 73be80e49aSRui Paulo static int asmc_wait_ack(device_t dev, uint8_t val, int amount); 7432a8088fSRui Paulo static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, 7532a8088fSRui Paulo uint8_t len); 7632a8088fSRui Paulo static int asmc_key_read(device_t dev, const char *key, uint8_t *buf, 7732a8088fSRui Paulo uint8_t); 7832a8088fSRui Paulo static int asmc_fan_count(device_t dev); 7932a8088fSRui Paulo static int asmc_fan_getvalue(device_t dev, const char *key, int fan); 8032a8088fSRui Paulo static int asmc_temp_getvalue(device_t dev, const char *key); 8132a8088fSRui Paulo static int asmc_sms_read(device_t, const char *key, int16_t *val); 8232a8088fSRui Paulo static void asmc_sms_calibrate(device_t dev); 8332a8088fSRui Paulo static int asmc_sms_intrfast(void *arg); 8432a8088fSRui Paulo #ifdef INTR_FILTER 8532a8088fSRui Paulo static void asmc_sms_handler(void *arg); 8632a8088fSRui Paulo #endif 8732a8088fSRui Paulo static void asmc_sms_printintr(device_t dev, uint8_t); 8832a8088fSRui Paulo static void asmc_sms_task(void *arg, int pending); 891269f4d4SRui Paulo #ifdef DEBUG 901269f4d4SRui Paulo void asmc_dumpall(device_t); 911269f4d4SRui Paulo static int asmc_key_dump(device_t, int); 921269f4d4SRui Paulo #endif 9332a8088fSRui Paulo 9432a8088fSRui Paulo /* 9532a8088fSRui Paulo * Model functions. 9632a8088fSRui Paulo */ 9732a8088fSRui Paulo static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); 9832a8088fSRui Paulo static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); 9932a8088fSRui Paulo static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); 10032a8088fSRui Paulo static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); 10132a8088fSRui Paulo static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); 10232a8088fSRui Paulo static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); 10332a8088fSRui Paulo static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); 10432a8088fSRui Paulo static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); 10532a8088fSRui Paulo static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS); 10632a8088fSRui Paulo static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); 10732a8088fSRui Paulo static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); 108be80e49aSRui Paulo static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); 10932a8088fSRui Paulo 11032a8088fSRui Paulo struct asmc_model { 11132a8088fSRui Paulo const char *smc_model; /* smbios.system.product env var. */ 11232a8088fSRui Paulo const char *smc_desc; /* driver description */ 11332a8088fSRui Paulo 11432a8088fSRui Paulo /* Helper functions */ 11532a8088fSRui Paulo int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); 11632a8088fSRui Paulo int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); 11732a8088fSRui Paulo int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); 11832a8088fSRui Paulo int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); 11932a8088fSRui Paulo int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); 12032a8088fSRui Paulo int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); 12132a8088fSRui Paulo int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); 12232a8088fSRui Paulo int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); 12332a8088fSRui Paulo int (*smc_light_left)(SYSCTL_HANDLER_ARGS); 12432a8088fSRui Paulo int (*smc_light_right)(SYSCTL_HANDLER_ARGS); 125be80e49aSRui Paulo int (*smc_light_control)(SYSCTL_HANDLER_ARGS); 12632a8088fSRui Paulo 127d8246db0SRui Paulo const char *smc_temps[ASMC_TEMP_MAX]; 128d8246db0SRui Paulo const char *smc_tempnames[ASMC_TEMP_MAX]; 129d8246db0SRui Paulo const char *smc_tempdescs[ASMC_TEMP_MAX]; 13032a8088fSRui Paulo }; 13132a8088fSRui Paulo 13232a8088fSRui Paulo static struct asmc_model *asmc_match(device_t dev); 13332a8088fSRui Paulo 13432a8088fSRui Paulo #define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ 13532a8088fSRui Paulo asmc_mb_sysctl_sms_z 13632a8088fSRui Paulo 13732a8088fSRui Paulo #define ASMC_FAN_FUNCS asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ 13832a8088fSRui Paulo asmc_mb_sysctl_fanminspeed, \ 13932a8088fSRui Paulo asmc_mb_sysctl_fanmaxspeed, \ 14032a8088fSRui Paulo asmc_mb_sysctl_fantargetspeed 14132a8088fSRui Paulo #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ 142be80e49aSRui Paulo asmc_mbp_sysctl_light_right, \ 143be80e49aSRui Paulo asmc_mbp_sysctl_light_control 14432a8088fSRui Paulo 14532a8088fSRui Paulo struct asmc_model asmc_models[] = { 14632a8088fSRui Paulo { 14732a8088fSRui Paulo "MacBook1,1", "Apple SMC MacBook Core Duo", 148be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 14932a8088fSRui Paulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 15032a8088fSRui Paulo }, 15132a8088fSRui Paulo 15232a8088fSRui Paulo { 15332a8088fSRui Paulo "MacBook2,1", "Apple SMC MacBook Core 2 Duo", 154be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 15532a8088fSRui Paulo ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS 15632a8088fSRui Paulo }, 15732a8088fSRui Paulo 15832a8088fSRui Paulo { 15932a8088fSRui Paulo "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", 16032a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 16132a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 16232a8088fSRui Paulo }, 16332a8088fSRui Paulo 16432a8088fSRui Paulo { 16532a8088fSRui Paulo "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", 16632a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 16732a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 16832a8088fSRui Paulo }, 16932a8088fSRui Paulo 17032a8088fSRui Paulo { 17132a8088fSRui Paulo "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", 17232a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 17332a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 17432a8088fSRui Paulo }, 17532a8088fSRui Paulo 17632a8088fSRui Paulo { 17732a8088fSRui Paulo "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", 17832a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 17932a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 18032a8088fSRui Paulo }, 18132a8088fSRui Paulo 18232a8088fSRui Paulo { 18332a8088fSRui Paulo "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", 18432a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 18532a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 18632a8088fSRui Paulo }, 18732a8088fSRui Paulo 18832a8088fSRui Paulo { 18932a8088fSRui Paulo "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", 19032a8088fSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 19132a8088fSRui Paulo ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS 19232a8088fSRui Paulo }, 19332a8088fSRui Paulo 194be80e49aSRui Paulo { 195be80e49aSRui Paulo "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", 196be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, 197be80e49aSRui Paulo ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS 198be80e49aSRui Paulo }, 199be80e49aSRui Paulo 20032a8088fSRui Paulo /* The Mac Mini has no SMS */ 20132a8088fSRui Paulo { 20232a8088fSRui Paulo "Macmini1,1", "Apple SMC Mac Mini", 20332a8088fSRui Paulo NULL, NULL, NULL, 20432a8088fSRui Paulo ASMC_FAN_FUNCS, 205be80e49aSRui Paulo NULL, NULL, NULL, 20632a8088fSRui Paulo ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS 20732a8088fSRui Paulo }, 20832a8088fSRui Paulo 209d8246db0SRui Paulo /* Idem for the MacPro */ 210d8246db0SRui Paulo { 211d8246db0SRui Paulo "MacPro2", "Apple SMC Mac Pro (8-core)", 212d8246db0SRui Paulo NULL, NULL, NULL, 213d8246db0SRui Paulo ASMC_FAN_FUNCS, 214be80e49aSRui Paulo NULL, NULL, NULL, 215d8246db0SRui Paulo ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS 216d8246db0SRui Paulo }, 217941f9f10SRui Paulo 218941f9f10SRui Paulo { 219941f9f10SRui Paulo "MacBookAir1,1", "Apple SMC MacBook Air", 220be80e49aSRui Paulo ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, 221941f9f10SRui Paulo ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS 222941f9f10SRui Paulo }, 223941f9f10SRui Paulo 224d8246db0SRui Paulo 22532a8088fSRui Paulo { NULL, NULL } 22632a8088fSRui Paulo }; 22732a8088fSRui Paulo 22832a8088fSRui Paulo #undef ASMC_SMS_FUNCS 22932a8088fSRui Paulo #undef ASMC_FAN_FUNCS 23032a8088fSRui Paulo #undef ASMC_LIGHT_FUNCS 23132a8088fSRui Paulo 23232a8088fSRui Paulo /* 23332a8088fSRui Paulo * Driver methods. 23432a8088fSRui Paulo */ 23532a8088fSRui Paulo static device_method_t asmc_methods[] = { 23632a8088fSRui Paulo DEVMETHOD(device_probe, asmc_probe), 23732a8088fSRui Paulo DEVMETHOD(device_attach, asmc_attach), 23832a8088fSRui Paulo DEVMETHOD(device_detach, asmc_detach), 23932a8088fSRui Paulo 24032a8088fSRui Paulo { 0, 0 } 24132a8088fSRui Paulo }; 24232a8088fSRui Paulo 24332a8088fSRui Paulo static driver_t asmc_driver = { 24432a8088fSRui Paulo "asmc", 24532a8088fSRui Paulo asmc_methods, 24632a8088fSRui Paulo sizeof(struct asmc_softc) 24732a8088fSRui Paulo }; 24832a8088fSRui Paulo 2494470f0f3SRui Paulo /* 2504470f0f3SRui Paulo * Debugging 2514470f0f3SRui Paulo */ 2524470f0f3SRui Paulo #define _COMPONENT ACPI_OEM 2534470f0f3SRui Paulo ACPI_MODULE_NAME("ASMC") 2544470f0f3SRui Paulo #ifdef DEBUG 2554470f0f3SRui Paulo #define ASMC_DPRINTF(str) device_printf(dev, str) 2564fb9bf66SRui Paulo #else 2574fb9bf66SRui Paulo #define ASMC_DPRINTF(str) 2584470f0f3SRui Paulo #endif 2594470f0f3SRui Paulo 260be80e49aSRui Paulo /* NB: can't be const */ 2614470f0f3SRui Paulo static char *asmc_ids[] = { "APP0001", NULL }; 2624470f0f3SRui Paulo 26332a8088fSRui Paulo static devclass_t asmc_devclass; 26432a8088fSRui Paulo 2654470f0f3SRui Paulo DRIVER_MODULE(asmc, acpi, asmc_driver, asmc_devclass, NULL, NULL); 2664470f0f3SRui Paulo MODULE_DEPEND(asmc, acpi, 1, 1, 1); 26732a8088fSRui Paulo 26832a8088fSRui Paulo static struct asmc_model * 26932a8088fSRui Paulo asmc_match(device_t dev) 27032a8088fSRui Paulo { 27132a8088fSRui Paulo int i; 27232a8088fSRui Paulo char *model; 27332a8088fSRui Paulo 27432a8088fSRui Paulo model = getenv("smbios.system.product"); 27547105877SRui Paulo if (model == NULL) 27647105877SRui Paulo return (NULL); 27747105877SRui Paulo 27832a8088fSRui Paulo for (i = 0; asmc_models[i].smc_model; i++) { 27932a8088fSRui Paulo if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { 28032a8088fSRui Paulo freeenv(model); 28132a8088fSRui Paulo return (&asmc_models[i]); 28232a8088fSRui Paulo } 28332a8088fSRui Paulo } 28432a8088fSRui Paulo freeenv(model); 28532a8088fSRui Paulo 28632a8088fSRui Paulo return (NULL); 28732a8088fSRui Paulo } 28832a8088fSRui Paulo 28932a8088fSRui Paulo static int 29032a8088fSRui Paulo asmc_probe(device_t dev) 29132a8088fSRui Paulo { 29232a8088fSRui Paulo struct asmc_model *model; 29332a8088fSRui Paulo 2949cb3ef6eSRui Paulo if (resource_disabled("asmc", 0)) 29532a8088fSRui Paulo return (ENXIO); 2964470f0f3SRui Paulo if (ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids) == NULL) 2974470f0f3SRui Paulo return (ENXIO); 2984470f0f3SRui Paulo 29932a8088fSRui Paulo model = asmc_match(dev); 3004470f0f3SRui Paulo if (!model) { 3014470f0f3SRui Paulo device_printf(dev, "model not recognized\n"); 30232a8088fSRui Paulo return (ENXIO); 3034470f0f3SRui Paulo } 30432a8088fSRui Paulo device_set_desc(dev, model->smc_desc); 30532a8088fSRui Paulo 30632a8088fSRui Paulo return (BUS_PROBE_DEFAULT); 30732a8088fSRui Paulo } 30832a8088fSRui Paulo 30932a8088fSRui Paulo static int 31032a8088fSRui Paulo asmc_attach(device_t dev) 31132a8088fSRui Paulo { 31232a8088fSRui Paulo int i, j; 31332a8088fSRui Paulo int ret; 31432a8088fSRui Paulo char name[2]; 31532a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 31632a8088fSRui Paulo struct sysctl_ctx_list *sysctlctx; 31732a8088fSRui Paulo struct sysctl_oid *sysctlnode; 31832a8088fSRui Paulo struct asmc_model *model; 31932a8088fSRui Paulo 3204470f0f3SRui Paulo sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 3214470f0f3SRui Paulo &sc->sc_rid_port, RF_ACTIVE); 3224470f0f3SRui Paulo if (sc->sc_ioport == NULL) { 3234470f0f3SRui Paulo device_printf(dev, "unable to allocate IO port\n"); 3244470f0f3SRui Paulo return (ENOMEM); 3254470f0f3SRui Paulo } 3264470f0f3SRui Paulo 32732a8088fSRui Paulo sysctlctx = device_get_sysctl_ctx(dev); 32832a8088fSRui Paulo sysctlnode = device_get_sysctl_tree(dev); 32932a8088fSRui Paulo 33032a8088fSRui Paulo model = asmc_match(dev); 33132a8088fSRui Paulo 33232a8088fSRui Paulo mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); 33332a8088fSRui Paulo 33432a8088fSRui Paulo sc->sc_model = model; 33532a8088fSRui Paulo asmc_init(dev); 33632a8088fSRui Paulo 33732a8088fSRui Paulo /* 33832a8088fSRui Paulo * dev.asmc.n.fan.* tree. 33932a8088fSRui Paulo */ 34032a8088fSRui Paulo sc->sc_fan_tree[0] = SYSCTL_ADD_NODE(sysctlctx, 34132a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "fan", 34232a8088fSRui Paulo CTLFLAG_RD, 0, "Fan Root Tree"); 34332a8088fSRui Paulo 34432a8088fSRui Paulo for (i = 1; i <= sc->sc_nfan; i++) { 34532a8088fSRui Paulo j = i - 1; 34632a8088fSRui Paulo name[0] = '0' + j; 34732a8088fSRui Paulo name[1] = 0; 34832a8088fSRui Paulo sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, 34932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[0]), 35032a8088fSRui Paulo OID_AUTO, name, CTLFLAG_RD, 0, 35132a8088fSRui Paulo "Fan Subtree"); 35232a8088fSRui Paulo 35332a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 35432a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 35532a8088fSRui Paulo OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD, 35632a8088fSRui Paulo dev, j, model->smc_fan_speed, "I", 35732a8088fSRui Paulo "Fan speed in RPM"); 35832a8088fSRui Paulo 35932a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 36032a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 36132a8088fSRui Paulo OID_AUTO, "safespeed", 36232a8088fSRui Paulo CTLTYPE_INT | CTLFLAG_RD, 36332a8088fSRui Paulo dev, j, model->smc_fan_safespeed, "I", 36432a8088fSRui Paulo "Fan safe speed in RPM"); 36532a8088fSRui Paulo 36632a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 36732a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 36832a8088fSRui Paulo OID_AUTO, "minspeed", 36932a8088fSRui Paulo CTLTYPE_INT | CTLFLAG_RD, 37032a8088fSRui Paulo dev, j, model->smc_fan_minspeed, "I", 37132a8088fSRui Paulo "Fan minimum speed in RPM"); 37232a8088fSRui Paulo 37332a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 37432a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 37532a8088fSRui Paulo OID_AUTO, "maxspeed", 37632a8088fSRui Paulo CTLTYPE_INT | CTLFLAG_RD, 37732a8088fSRui Paulo dev, j, model->smc_fan_maxspeed, "I", 37832a8088fSRui Paulo "Fan maximum speed in RPM"); 37932a8088fSRui Paulo 38032a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 38132a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_fan_tree[i]), 38232a8088fSRui Paulo OID_AUTO, "targetspeed", 38332a8088fSRui Paulo CTLTYPE_INT | CTLFLAG_RD, 38432a8088fSRui Paulo dev, j, model->smc_fan_targetspeed, "I", 38532a8088fSRui Paulo "Fan target speed in RPM"); 38632a8088fSRui Paulo } 38732a8088fSRui Paulo 38832a8088fSRui Paulo /* 38932a8088fSRui Paulo * dev.asmc.n.temp tree. 39032a8088fSRui Paulo */ 39132a8088fSRui Paulo sc->sc_temp_tree = SYSCTL_ADD_NODE(sysctlctx, 39232a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", 39332a8088fSRui Paulo CTLFLAG_RD, 0, "Temperature sensors"); 39432a8088fSRui Paulo 39532a8088fSRui Paulo for (i = 0; model->smc_temps[i]; i++) { 39632a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 39732a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_temp_tree), 39832a8088fSRui Paulo OID_AUTO, model->smc_tempnames[i], 39932a8088fSRui Paulo CTLTYPE_INT | CTLFLAG_RD, 40032a8088fSRui Paulo dev, i, asmc_temp_sysctl, "I", 40132a8088fSRui Paulo model->smc_tempdescs[i]); 40232a8088fSRui Paulo } 40332a8088fSRui Paulo 404be80e49aSRui Paulo /* 405be80e49aSRui Paulo * dev.asmc.n.light 406be80e49aSRui Paulo */ 407be80e49aSRui Paulo if (model->smc_light_left) { 408be80e49aSRui Paulo sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, 409be80e49aSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", 410be80e49aSRui Paulo CTLFLAG_RD, 0, "Keyboard backlight sensors"); 411be80e49aSRui Paulo 412be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 413be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 414be80e49aSRui Paulo OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD, 415be80e49aSRui Paulo dev, 0, model->smc_light_left, "I", 416be80e49aSRui Paulo "Keyboard backlight left sensor"); 417be80e49aSRui Paulo 418be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 419be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 420be80e49aSRui Paulo OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD, 421be80e49aSRui Paulo dev, 0, model->smc_light_right, "I", 422be80e49aSRui Paulo "Keyboard backlight right sensor"); 423be80e49aSRui Paulo 424be80e49aSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 425be80e49aSRui Paulo SYSCTL_CHILDREN(sc->sc_light_tree), 4263471c35dSRui Paulo OID_AUTO, "control", 4273471c35dSRui Paulo CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 428be80e49aSRui Paulo dev, 0, model->smc_light_control, "I", 429be80e49aSRui Paulo "Keyboard backlight brightness control"); 430be80e49aSRui Paulo } 431be80e49aSRui Paulo 43232a8088fSRui Paulo if (model->smc_sms_x == NULL) 43332a8088fSRui Paulo goto nosms; 43432a8088fSRui Paulo 43532a8088fSRui Paulo /* 43632a8088fSRui Paulo * dev.asmc.n.sms tree. 43732a8088fSRui Paulo */ 43832a8088fSRui Paulo sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, 43932a8088fSRui Paulo SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "sms", 44032a8088fSRui Paulo CTLFLAG_RD, 0, "Sudden Motion Sensor"); 44132a8088fSRui Paulo 44232a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 44332a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 44432a8088fSRui Paulo OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD, 44532a8088fSRui Paulo dev, 0, model->smc_sms_x, "I", 44632a8088fSRui Paulo "Sudden Motion Sensor X value"); 44732a8088fSRui Paulo 44832a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 44932a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 45032a8088fSRui Paulo OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD, 45132a8088fSRui Paulo dev, 0, model->smc_sms_y, "I", 45232a8088fSRui Paulo "Sudden Motion Sensor Y value"); 45332a8088fSRui Paulo 45432a8088fSRui Paulo SYSCTL_ADD_PROC(sysctlctx, 45532a8088fSRui Paulo SYSCTL_CHILDREN(sc->sc_sms_tree), 45632a8088fSRui Paulo OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD, 45732a8088fSRui Paulo dev, 0, model->smc_sms_z, "I", 45832a8088fSRui Paulo "Sudden Motion Sensor Z value"); 45932a8088fSRui Paulo 46032a8088fSRui Paulo /* 46132a8088fSRui Paulo * Need a taskqueue to send devctl_notify() events 46232a8088fSRui Paulo * when the SMS interrupt us. 46332a8088fSRui Paulo * 46432a8088fSRui Paulo * PI_REALTIME is used due to the sensitivity of the 46532a8088fSRui Paulo * interrupt. An interrupt from the SMS means that the 46632a8088fSRui Paulo * disk heads should be turned off as quickly as possible. 46732a8088fSRui Paulo * 46832a8088fSRui Paulo * We only need to do this for the non INTR_FILTER case. 46932a8088fSRui Paulo */ 47032a8088fSRui Paulo sc->sc_sms_tq = NULL; 47132a8088fSRui Paulo #ifndef INTR_FILTER 47232a8088fSRui Paulo TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc); 47332a8088fSRui Paulo sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK, 47432a8088fSRui Paulo taskqueue_thread_enqueue, &sc->sc_sms_tq); 47532a8088fSRui Paulo taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq", 47632a8088fSRui Paulo device_get_nameunit(dev)); 47732a8088fSRui Paulo #endif 47832a8088fSRui Paulo /* 47932a8088fSRui Paulo * Allocate an IRQ for the SMS. 48032a8088fSRui Paulo */ 4814470f0f3SRui Paulo sc->sc_rid_irq = 0; 4824470f0f3SRui Paulo sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 4834470f0f3SRui Paulo &sc->sc_rid_irq, RF_ACTIVE); 4844470f0f3SRui Paulo if (sc->sc_irq == NULL) { 48532a8088fSRui Paulo device_printf(dev, "unable to allocate IRQ resource\n"); 48632a8088fSRui Paulo ret = ENXIO; 48732a8088fSRui Paulo goto err2; 48832a8088fSRui Paulo } 48932a8088fSRui Paulo 4904470f0f3SRui Paulo ret = bus_setup_intr(dev, sc->sc_irq, 49132a8088fSRui Paulo INTR_TYPE_MISC | INTR_MPSAFE, 49232a8088fSRui Paulo #ifdef INTR_FILTER 49332a8088fSRui Paulo asmc_sms_intrfast, asmc_sms_handler, 49432a8088fSRui Paulo #else 49532a8088fSRui Paulo asmc_sms_intrfast, NULL, 49632a8088fSRui Paulo #endif 49732a8088fSRui Paulo dev, &sc->sc_cookie); 49832a8088fSRui Paulo 49932a8088fSRui Paulo if (ret) { 50032a8088fSRui Paulo device_printf(dev, "unable to setup SMS IRQ\n"); 50132a8088fSRui Paulo goto err1; 50232a8088fSRui Paulo } 50332a8088fSRui Paulo nosms: 50432a8088fSRui Paulo return (0); 50532a8088fSRui Paulo err1: 5064470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); 50732a8088fSRui Paulo err2: 5084470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 5094470f0f3SRui Paulo sc->sc_ioport); 51032a8088fSRui Paulo mtx_destroy(&sc->sc_mtx); 51132a8088fSRui Paulo if (sc->sc_sms_tq) 51232a8088fSRui Paulo taskqueue_free(sc->sc_sms_tq); 51332a8088fSRui Paulo 51432a8088fSRui Paulo return (ret); 51532a8088fSRui Paulo } 51632a8088fSRui Paulo 51732a8088fSRui Paulo static int 51832a8088fSRui Paulo asmc_detach(device_t dev) 51932a8088fSRui Paulo { 52032a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 52132a8088fSRui Paulo 52232a8088fSRui Paulo if (sc->sc_sms_tq) { 52332a8088fSRui Paulo taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); 52432a8088fSRui Paulo taskqueue_free(sc->sc_sms_tq); 52532a8088fSRui Paulo } 52632a8088fSRui Paulo if (sc->sc_cookie) 5274470f0f3SRui Paulo bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); 5284470f0f3SRui Paulo if (sc->sc_irq) 5294470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, 5304470f0f3SRui Paulo sc->sc_irq); 5314470f0f3SRui Paulo if (sc->sc_ioport) 5324470f0f3SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, 5334470f0f3SRui Paulo sc->sc_ioport); 53432a8088fSRui Paulo mtx_destroy(&sc->sc_mtx); 53532a8088fSRui Paulo 53632a8088fSRui Paulo return (0); 53732a8088fSRui Paulo } 53832a8088fSRui Paulo 5391269f4d4SRui Paulo #ifdef DEBUG 5401269f4d4SRui Paulo void asmc_dumpall(device_t dev) 5411269f4d4SRui Paulo { 5421269f4d4SRui Paulo int i; 5431269f4d4SRui Paulo 5441269f4d4SRui Paulo /* XXX magic number */ 5451269f4d4SRui Paulo for (i=0; i < 0x100; i++) 5461269f4d4SRui Paulo asmc_key_dump(dev, i); 5471269f4d4SRui Paulo } 5481269f4d4SRui Paulo #endif 5491269f4d4SRui Paulo 55032a8088fSRui Paulo static int 55132a8088fSRui Paulo asmc_init(device_t dev) 55232a8088fSRui Paulo { 55332a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 55432a8088fSRui Paulo int i, error = 1; 55532a8088fSRui Paulo uint8_t buf[4]; 55632a8088fSRui Paulo 55732a8088fSRui Paulo if (sc->sc_model->smc_sms_x == NULL) 55832a8088fSRui Paulo goto nosms; 55932a8088fSRui Paulo 56032a8088fSRui Paulo /* 56132a8088fSRui Paulo * We are ready to recieve interrupts from the SMS. 56232a8088fSRui Paulo */ 56332a8088fSRui Paulo buf[0] = 0x01; 5644470f0f3SRui Paulo ASMC_DPRINTF(("intok key\n")); 56532a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_INTOK, buf, 1); 56632a8088fSRui Paulo DELAY(50); 56732a8088fSRui Paulo 56832a8088fSRui Paulo /* 56932a8088fSRui Paulo * Initiate the polling intervals. 57032a8088fSRui Paulo */ 57132a8088fSRui Paulo buf[0] = 20; /* msecs */ 5724470f0f3SRui Paulo ASMC_DPRINTF(("low int key\n")); 57332a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_LOW_INT, buf, 1); 57432a8088fSRui Paulo DELAY(200); 57532a8088fSRui Paulo 57632a8088fSRui Paulo buf[0] = 20; /* msecs */ 5774470f0f3SRui Paulo ASMC_DPRINTF(("high int key\n")); 57832a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH_INT, buf, 1); 57932a8088fSRui Paulo DELAY(200); 58032a8088fSRui Paulo 58132a8088fSRui Paulo buf[0] = 0x00; 58232a8088fSRui Paulo buf[1] = 0x60; 5834470f0f3SRui Paulo ASMC_DPRINTF(("sms low key\n")); 58432a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_LOW, buf, 2); 58532a8088fSRui Paulo DELAY(200); 58632a8088fSRui Paulo 58732a8088fSRui Paulo buf[0] = 0x01; 58832a8088fSRui Paulo buf[1] = 0xc0; 5894470f0f3SRui Paulo ASMC_DPRINTF(("sms high key\n")); 59032a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_HIGH, buf, 2); 59132a8088fSRui Paulo DELAY(200); 59232a8088fSRui Paulo 59332a8088fSRui Paulo /* 59432a8088fSRui Paulo * I'm not sure what this key does, but it seems to be 59532a8088fSRui Paulo * required. 59632a8088fSRui Paulo */ 59732a8088fSRui Paulo buf[0] = 0x01; 5984470f0f3SRui Paulo ASMC_DPRINTF(("sms flag key\n")); 59932a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS_FLAG, buf, 1); 600b75dfbe8SRui Paulo DELAY(100); 60132a8088fSRui Paulo 6021269f4d4SRui Paulo sc->sc_sms_intr_works = 0; 6031269f4d4SRui Paulo 60432a8088fSRui Paulo /* 6051269f4d4SRui Paulo * Retry SMS initialization 1000 times 6061269f4d4SRui Paulo * (takes approx. 2 seconds in worst case) 60732a8088fSRui Paulo */ 6081269f4d4SRui Paulo for (i = 0; i < 1000; i++) { 60932a8088fSRui Paulo if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && 6101269f4d4SRui Paulo (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { 61132a8088fSRui Paulo error = 0; 6121269f4d4SRui Paulo sc->sc_sms_intr_works = 1; 6134fb9bf66SRui Paulo goto out; 61432a8088fSRui Paulo } 61532a8088fSRui Paulo buf[0] = ASMC_SMS_INIT1; 61632a8088fSRui Paulo buf[1] = ASMC_SMS_INIT2; 6174470f0f3SRui Paulo ASMC_DPRINTF(("sms key\n")); 61832a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_SMS, buf, 2); 61932a8088fSRui Paulo DELAY(50); 62032a8088fSRui Paulo } 6214fb9bf66SRui Paulo device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); 62232a8088fSRui Paulo 6234fb9bf66SRui Paulo out: 62432a8088fSRui Paulo asmc_sms_calibrate(dev); 62532a8088fSRui Paulo nosms: 62632a8088fSRui Paulo sc->sc_nfan = asmc_fan_count(dev); 62732a8088fSRui Paulo if (sc->sc_nfan > ASMC_MAXFANS) { 62832a8088fSRui Paulo device_printf(dev, "more than %d fans were detected. Please " 62932a8088fSRui Paulo "report this.\n", ASMC_MAXFANS); 63032a8088fSRui Paulo sc->sc_nfan = ASMC_MAXFANS; 63132a8088fSRui Paulo } 63232a8088fSRui Paulo 63332a8088fSRui Paulo if (bootverbose) { 63432a8088fSRui Paulo /* 63532a8088fSRui Paulo * XXX: The number of keys is a 32 bit buffer, but 63632a8088fSRui Paulo * right now Apple only uses the last 8 bit. 63732a8088fSRui Paulo */ 63832a8088fSRui Paulo asmc_key_read(dev, ASMC_NKEYS, buf, 4); 63932a8088fSRui Paulo device_printf(dev, "number of keys: %d\n", buf[3]); 64032a8088fSRui Paulo } 64132a8088fSRui Paulo 6421269f4d4SRui Paulo #ifdef DEBUG 6431269f4d4SRui Paulo asmc_dumpall(dev); 6441269f4d4SRui Paulo #endif 6451269f4d4SRui Paulo 64632a8088fSRui Paulo return (error); 64732a8088fSRui Paulo } 64832a8088fSRui Paulo 64932a8088fSRui Paulo /* 65032a8088fSRui Paulo * We need to make sure that the SMC acks the byte sent. 651be80e49aSRui Paulo * Just wait up to (amount * 10) ms. 65232a8088fSRui Paulo */ 65332a8088fSRui Paulo static int 654be80e49aSRui Paulo asmc_wait_ack(device_t dev, uint8_t val, int amount) 65532a8088fSRui Paulo { 6564470f0f3SRui Paulo struct asmc_softc *sc = device_get_softc(dev); 65732a8088fSRui Paulo u_int i; 65832a8088fSRui Paulo 65932a8088fSRui Paulo val = val & ASMC_STATUS_MASK; 66032a8088fSRui Paulo 661be80e49aSRui Paulo for (i = 0; i < amount; i++) { 6624470f0f3SRui Paulo if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val) 66332a8088fSRui Paulo return (0); 66432a8088fSRui Paulo DELAY(10); 66532a8088fSRui Paulo } 66632a8088fSRui Paulo 667be80e49aSRui Paulo return (1); 668be80e49aSRui Paulo } 669be80e49aSRui Paulo 670be80e49aSRui Paulo /* 671be80e49aSRui Paulo * We need to make sure that the SMC acks the byte sent. 672be80e49aSRui Paulo * Just wait up to 100 ms. 673be80e49aSRui Paulo */ 674be80e49aSRui Paulo static int 675be80e49aSRui Paulo asmc_wait(device_t dev, uint8_t val) 676be80e49aSRui Paulo { 677be80e49aSRui Paulo struct asmc_softc *sc; 678be80e49aSRui Paulo 679be80e49aSRui Paulo if (asmc_wait_ack(dev, val, 1000) == 0) 680be80e49aSRui Paulo return (0); 681be80e49aSRui Paulo 682be80e49aSRui Paulo sc = device_get_softc(dev); 683be80e49aSRui Paulo val = val & ASMC_STATUS_MASK; 684be80e49aSRui Paulo 685be80e49aSRui Paulo #ifdef DEBUG 68632a8088fSRui Paulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, 6874470f0f3SRui Paulo ASMC_CMDPORT_READ(sc)); 688be80e49aSRui Paulo #endif 689be80e49aSRui Paulo return (1); 690be80e49aSRui Paulo } 69132a8088fSRui Paulo 692be80e49aSRui Paulo /* 693be80e49aSRui Paulo * Send the given command, retrying up to 10 times if 694be80e49aSRui Paulo * the acknowledgement fails. 695be80e49aSRui Paulo */ 696be80e49aSRui Paulo static int 697be80e49aSRui Paulo asmc_command(device_t dev, uint8_t command) { 698be80e49aSRui Paulo 699be80e49aSRui Paulo int i; 700be80e49aSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 701be80e49aSRui Paulo 702be80e49aSRui Paulo for (i=0; i < 10; i++) { 703be80e49aSRui Paulo ASMC_CMDPORT_WRITE(sc, command); 704be80e49aSRui Paulo if (asmc_wait_ack(dev, 0x0c, 100) == 0) { 705be80e49aSRui Paulo return (0); 706be80e49aSRui Paulo } 707be80e49aSRui Paulo } 708be80e49aSRui Paulo 709be80e49aSRui Paulo #ifdef DEBUG 710be80e49aSRui Paulo device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, 711be80e49aSRui Paulo ASMC_CMDPORT_READ(sc)); 712be80e49aSRui Paulo #endif 71332a8088fSRui Paulo return (1); 71432a8088fSRui Paulo } 71532a8088fSRui Paulo 71632a8088fSRui Paulo static int 71732a8088fSRui Paulo asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len) 71832a8088fSRui Paulo { 719be80e49aSRui Paulo int i, error = 1, try = 0; 72032a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 72132a8088fSRui Paulo 72232a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 72332a8088fSRui Paulo 724be80e49aSRui Paulo begin: 725be80e49aSRui Paulo if (asmc_command(dev, ASMC_CMDREAD)) 72632a8088fSRui Paulo goto out; 72732a8088fSRui Paulo 72832a8088fSRui Paulo for (i = 0; i < 4; i++) { 7294470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 73032a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 73132a8088fSRui Paulo goto out; 73232a8088fSRui Paulo } 73332a8088fSRui Paulo 7344470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, len); 73532a8088fSRui Paulo 73632a8088fSRui Paulo for (i = 0; i < len; i++) { 73732a8088fSRui Paulo if (asmc_wait(dev, 0x05)) 73832a8088fSRui Paulo goto out; 7394470f0f3SRui Paulo buf[i] = ASMC_DATAPORT_READ(sc); 74032a8088fSRui Paulo } 74132a8088fSRui Paulo 74232a8088fSRui Paulo error = 0; 74332a8088fSRui Paulo out: 744be80e49aSRui Paulo if (error) { 745be80e49aSRui Paulo if (++try < 10) goto begin; 746be80e49aSRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 747be80e49aSRui Paulo __func__, key, try); 748be80e49aSRui Paulo } 749be80e49aSRui Paulo 75032a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 75132a8088fSRui Paulo 75232a8088fSRui Paulo return (error); 75332a8088fSRui Paulo } 75432a8088fSRui Paulo 7551269f4d4SRui Paulo #ifdef DEBUG 7561269f4d4SRui Paulo static int 7571269f4d4SRui Paulo asmc_key_dump(device_t dev, int number) 7581269f4d4SRui Paulo { 7591269f4d4SRui Paulo struct asmc_softc *sc = device_get_softc(dev); 7601269f4d4SRui Paulo char key[5] = { 0 }; 7611269f4d4SRui Paulo char type[7] = { 0 }; 7621269f4d4SRui Paulo uint8_t index[4]; 7631269f4d4SRui Paulo uint8_t v[32]; 7641269f4d4SRui Paulo uint8_t maxlen; 7651269f4d4SRui Paulo int i, error = 1, try = 0; 7661269f4d4SRui Paulo 7671269f4d4SRui Paulo mtx_lock_spin(&sc->sc_mtx); 7681269f4d4SRui Paulo 7691269f4d4SRui Paulo index[0] = (number >> 24) & 0xff; 7701269f4d4SRui Paulo index[1] = (number >> 16) & 0xff; 7711269f4d4SRui Paulo index[2] = (number >> 8) & 0xff; 7721269f4d4SRui Paulo index[3] = (number) & 0xff; 7731269f4d4SRui Paulo 7741269f4d4SRui Paulo begin: 7751269f4d4SRui Paulo if (asmc_command(dev, 0x12)) 7761269f4d4SRui Paulo goto out; 7771269f4d4SRui Paulo 7781269f4d4SRui Paulo for (i = 0; i < 4; i++) { 7791269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, index[i]); 7801269f4d4SRui Paulo if (asmc_wait(dev, 0x04)) 7811269f4d4SRui Paulo goto out; 7821269f4d4SRui Paulo } 7831269f4d4SRui Paulo 7841269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, 4); 7851269f4d4SRui Paulo 7861269f4d4SRui Paulo for (i = 0; i < 4; i++) { 7871269f4d4SRui Paulo if (asmc_wait(dev, 0x05)) 7881269f4d4SRui Paulo goto out; 7891269f4d4SRui Paulo key[i] = ASMC_DATAPORT_READ(sc); 7901269f4d4SRui Paulo } 7911269f4d4SRui Paulo 7921269f4d4SRui Paulo /* get type */ 7931269f4d4SRui Paulo if (asmc_command(dev, 0x13)) 7941269f4d4SRui Paulo goto out; 7951269f4d4SRui Paulo 7961269f4d4SRui Paulo for (i = 0; i < 4; i++) { 7971269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 7981269f4d4SRui Paulo if (asmc_wait(dev, 0x04)) 7991269f4d4SRui Paulo goto out; 8001269f4d4SRui Paulo } 8011269f4d4SRui Paulo 8021269f4d4SRui Paulo ASMC_DATAPORT_WRITE(sc, 6); 8031269f4d4SRui Paulo 8041269f4d4SRui Paulo for (i = 0; i < 6; i++) { 8051269f4d4SRui Paulo if (asmc_wait(dev, 0x05)) 8061269f4d4SRui Paulo goto out; 8071269f4d4SRui Paulo type[i] = ASMC_DATAPORT_READ(sc); 8081269f4d4SRui Paulo } 8091269f4d4SRui Paulo 8101269f4d4SRui Paulo error = 0; 8111269f4d4SRui Paulo out: 8121269f4d4SRui Paulo if (error) { 8131269f4d4SRui Paulo if (++try < 10) goto begin; 8141269f4d4SRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 8151269f4d4SRui Paulo __func__, key, try); 8161269f4d4SRui Paulo mtx_unlock_spin(&sc->sc_mtx); 8171269f4d4SRui Paulo } 8181269f4d4SRui Paulo else { 8191269f4d4SRui Paulo char buf[1024]; 8201269f4d4SRui Paulo char buf2[8]; 8211269f4d4SRui Paulo mtx_unlock_spin(&sc->sc_mtx); 8221269f4d4SRui Paulo maxlen = type[0]; 8231269f4d4SRui Paulo type[0] = ' '; 8241269f4d4SRui Paulo type[5] = 0; 8251269f4d4SRui Paulo if (maxlen > sizeof(v)) { 8261269f4d4SRui Paulo device_printf(dev, "WARNING: cropping maxlen " 8271269f4d4SRui Paulo "from %d to %lud\n", maxlen, sizeof(v)); 8281269f4d4SRui Paulo maxlen = sizeof(v); 8291269f4d4SRui Paulo } 8301269f4d4SRui Paulo for (i = 0; i < sizeof(v); i++) { 8311269f4d4SRui Paulo v[i] = 0; 8321269f4d4SRui Paulo } 8331269f4d4SRui Paulo asmc_key_read(dev, key, v, maxlen); 8341269f4d4SRui Paulo snprintf(buf, sizeof(buf), "key %d is: %s, type %s " 8351269f4d4SRui Paulo "(len %d), data", number, key, type, maxlen); 8361269f4d4SRui Paulo for (i = 0; i < maxlen; i++) { 8371269f4d4SRui Paulo snprintf(buf2, sizeof(buf), " %02x", v[i]); 8381269f4d4SRui Paulo strlcat(buf, buf2, sizeof(buf)); 8391269f4d4SRui Paulo } 8401269f4d4SRui Paulo strlcat(buf, " \n", sizeof(buf)); 8411269f4d4SRui Paulo device_printf(dev, buf); 8421269f4d4SRui Paulo } 8431269f4d4SRui Paulo 8441269f4d4SRui Paulo return (error); 8451269f4d4SRui Paulo } 8461269f4d4SRui Paulo #endif 8471269f4d4SRui Paulo 84832a8088fSRui Paulo static int 84932a8088fSRui Paulo asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) 85032a8088fSRui Paulo { 851be80e49aSRui Paulo int i, error = -1, try = 0; 85232a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 85332a8088fSRui Paulo 85432a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 85532a8088fSRui Paulo 856be80e49aSRui Paulo begin: 8574470f0f3SRui Paulo ASMC_DPRINTF(("cmd port: cmd write\n")); 858be80e49aSRui Paulo if (asmc_command(dev, ASMC_CMDWRITE)) 85932a8088fSRui Paulo goto out; 86032a8088fSRui Paulo 8614470f0f3SRui Paulo ASMC_DPRINTF(("data port: key\n")); 86232a8088fSRui Paulo for (i = 0; i < 4; i++) { 8634470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, key[i]); 86432a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 86532a8088fSRui Paulo goto out; 86632a8088fSRui Paulo } 8674470f0f3SRui Paulo ASMC_DPRINTF(("data port: length\n")); 8684470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, len); 86932a8088fSRui Paulo 8704470f0f3SRui Paulo ASMC_DPRINTF(("data port: buffer\n")); 87132a8088fSRui Paulo for (i = 0; i < len; i++) { 87232a8088fSRui Paulo if (asmc_wait(dev, 0x04)) 87332a8088fSRui Paulo goto out; 8744470f0f3SRui Paulo ASMC_DATAPORT_WRITE(sc, buf[i]); 87532a8088fSRui Paulo } 87632a8088fSRui Paulo 87732a8088fSRui Paulo error = 0; 87832a8088fSRui Paulo out: 879be80e49aSRui Paulo if (error) { 880be80e49aSRui Paulo if (++try < 10) goto begin; 881be80e49aSRui Paulo device_printf(dev,"%s for key %s failed %d times, giving up\n", 882be80e49aSRui Paulo __func__, key, try); 883be80e49aSRui Paulo } 884be80e49aSRui Paulo 88532a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 88632a8088fSRui Paulo 88732a8088fSRui Paulo return (error); 88832a8088fSRui Paulo 88932a8088fSRui Paulo } 89032a8088fSRui Paulo 89132a8088fSRui Paulo /* 89232a8088fSRui Paulo * Fan control functions. 89332a8088fSRui Paulo */ 89432a8088fSRui Paulo static int 89532a8088fSRui Paulo asmc_fan_count(device_t dev) 89632a8088fSRui Paulo { 89732a8088fSRui Paulo uint8_t buf[1]; 89832a8088fSRui Paulo 89932a8088fSRui Paulo if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, 1) < 0) 90032a8088fSRui Paulo return (-1); 90132a8088fSRui Paulo 90232a8088fSRui Paulo return (buf[0]); 90332a8088fSRui Paulo } 90432a8088fSRui Paulo 90532a8088fSRui Paulo static int 90632a8088fSRui Paulo asmc_fan_getvalue(device_t dev, const char *key, int fan) 90732a8088fSRui Paulo { 90832a8088fSRui Paulo int speed; 90932a8088fSRui Paulo uint8_t buf[2]; 91032a8088fSRui Paulo char fankey[5]; 91132a8088fSRui Paulo 91232a8088fSRui Paulo snprintf(fankey, sizeof(fankey), key, fan); 91332a8088fSRui Paulo if (asmc_key_read(dev, fankey, buf, 2) < 0) 91432a8088fSRui Paulo return (-1); 91532a8088fSRui Paulo speed = (buf[0] << 6) | (buf[1] >> 2); 91632a8088fSRui Paulo 91732a8088fSRui Paulo return (speed); 91832a8088fSRui Paulo } 91932a8088fSRui Paulo 92032a8088fSRui Paulo static int 92132a8088fSRui Paulo asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) 92232a8088fSRui Paulo { 92332a8088fSRui Paulo device_t dev = (device_t) arg1; 92432a8088fSRui Paulo int fan = arg2; 92532a8088fSRui Paulo int error; 92632a8088fSRui Paulo int32_t v; 92732a8088fSRui Paulo 92832a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSPEED, fan); 92932a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 93032a8088fSRui Paulo 93132a8088fSRui Paulo return (error); 93232a8088fSRui Paulo } 93332a8088fSRui Paulo 93432a8088fSRui Paulo static int 93532a8088fSRui Paulo asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) 93632a8088fSRui Paulo { 93732a8088fSRui Paulo device_t dev = (device_t) arg1; 93832a8088fSRui Paulo int fan = arg2; 93932a8088fSRui Paulo int error; 94032a8088fSRui Paulo int32_t v; 94132a8088fSRui Paulo 94232a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANSAFESPEED, fan); 94332a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 94432a8088fSRui Paulo 94532a8088fSRui Paulo return (error); 94632a8088fSRui Paulo } 94732a8088fSRui Paulo 94832a8088fSRui Paulo 94932a8088fSRui Paulo static int 95032a8088fSRui Paulo asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) 95132a8088fSRui Paulo { 95232a8088fSRui Paulo device_t dev = (device_t) arg1; 95332a8088fSRui Paulo int fan = arg2; 95432a8088fSRui Paulo int error; 95532a8088fSRui Paulo int32_t v; 95632a8088fSRui Paulo 95732a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMINSPEED, fan); 95832a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 95932a8088fSRui Paulo 96032a8088fSRui Paulo return (error); 96132a8088fSRui Paulo } 96232a8088fSRui Paulo 96332a8088fSRui Paulo static int 96432a8088fSRui Paulo asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) 96532a8088fSRui Paulo { 96632a8088fSRui Paulo device_t dev = (device_t) arg1; 96732a8088fSRui Paulo int fan = arg2; 96832a8088fSRui Paulo int error; 96932a8088fSRui Paulo int32_t v; 97032a8088fSRui Paulo 97132a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANMAXSPEED, fan); 97232a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 97332a8088fSRui Paulo 97432a8088fSRui Paulo return (error); 97532a8088fSRui Paulo } 97632a8088fSRui Paulo 97732a8088fSRui Paulo static int 97832a8088fSRui Paulo asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) 97932a8088fSRui Paulo { 98032a8088fSRui Paulo device_t dev = (device_t) arg1; 98132a8088fSRui Paulo int fan = arg2; 98232a8088fSRui Paulo int error; 98332a8088fSRui Paulo int32_t v; 98432a8088fSRui Paulo 98532a8088fSRui Paulo v = asmc_fan_getvalue(dev, ASMC_KEY_FANTARGETSPEED, fan); 98632a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 98732a8088fSRui Paulo 98832a8088fSRui Paulo return (error); 98932a8088fSRui Paulo } 99032a8088fSRui Paulo 99132a8088fSRui Paulo /* 99232a8088fSRui Paulo * Temperature functions. 99332a8088fSRui Paulo */ 99432a8088fSRui Paulo static int 99532a8088fSRui Paulo asmc_temp_getvalue(device_t dev, const char *key) 99632a8088fSRui Paulo { 99732a8088fSRui Paulo uint8_t buf[2]; 99832a8088fSRui Paulo 99932a8088fSRui Paulo /* 100032a8088fSRui Paulo * Check for invalid temperatures. 100132a8088fSRui Paulo */ 100232a8088fSRui Paulo if (asmc_key_read(dev, key, buf, 2) < 0) 100332a8088fSRui Paulo return (-1); 100432a8088fSRui Paulo 100532a8088fSRui Paulo return (buf[0]); 100632a8088fSRui Paulo } 100732a8088fSRui Paulo 100832a8088fSRui Paulo static int 100932a8088fSRui Paulo asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) 101032a8088fSRui Paulo { 101132a8088fSRui Paulo device_t dev = (device_t) arg1; 101232a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 101332a8088fSRui Paulo int error, val; 101432a8088fSRui Paulo 101532a8088fSRui Paulo val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); 101632a8088fSRui Paulo error = sysctl_handle_int(oidp, &val, 0, req); 101732a8088fSRui Paulo 101832a8088fSRui Paulo return (error); 101932a8088fSRui Paulo } 102032a8088fSRui Paulo 102132a8088fSRui Paulo /* 102232a8088fSRui Paulo * Sudden Motion Sensor functions. 102332a8088fSRui Paulo */ 102432a8088fSRui Paulo static int 102532a8088fSRui Paulo asmc_sms_read(device_t dev, const char *key, int16_t *val) 102632a8088fSRui Paulo { 102732a8088fSRui Paulo uint8_t buf[2]; 102832a8088fSRui Paulo int error; 102932a8088fSRui Paulo 103032a8088fSRui Paulo /* no need to do locking here as asmc_key_read() already does it */ 103132a8088fSRui Paulo switch (key[3]) { 103232a8088fSRui Paulo case 'X': 103332a8088fSRui Paulo case 'Y': 103432a8088fSRui Paulo case 'Z': 103532a8088fSRui Paulo error = asmc_key_read(dev, key, buf, 2); 103632a8088fSRui Paulo break; 103732a8088fSRui Paulo default: 103832a8088fSRui Paulo device_printf(dev, "%s called with invalid argument %s\n", 103932a8088fSRui Paulo __func__, key); 104032a8088fSRui Paulo error = 1; 104132a8088fSRui Paulo goto out; 104232a8088fSRui Paulo } 104332a8088fSRui Paulo *val = ((int16_t)buf[0] << 8) | buf[1]; 104432a8088fSRui Paulo out: 104532a8088fSRui Paulo return (error); 104632a8088fSRui Paulo } 104732a8088fSRui Paulo 104832a8088fSRui Paulo static void 104932a8088fSRui Paulo asmc_sms_calibrate(device_t dev) 105032a8088fSRui Paulo { 105132a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 105232a8088fSRui Paulo 105332a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &sc->sms_rest_x); 105432a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &sc->sms_rest_y); 105532a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &sc->sms_rest_z); 105632a8088fSRui Paulo } 105732a8088fSRui Paulo 105832a8088fSRui Paulo static int 105932a8088fSRui Paulo asmc_sms_intrfast(void *arg) 106032a8088fSRui Paulo { 106132a8088fSRui Paulo uint8_t type; 106232a8088fSRui Paulo device_t dev = (device_t) arg; 106332a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(dev); 10641269f4d4SRui Paulo if (!sc->sc_sms_intr_works) 10651269f4d4SRui Paulo return (FILTER_HANDLED); 106632a8088fSRui Paulo 106732a8088fSRui Paulo mtx_lock_spin(&sc->sc_mtx); 10684470f0f3SRui Paulo type = ASMC_INTPORT_READ(sc); 106932a8088fSRui Paulo mtx_unlock_spin(&sc->sc_mtx); 107032a8088fSRui Paulo 107132a8088fSRui Paulo sc->sc_sms_intrtype = type; 107232a8088fSRui Paulo asmc_sms_printintr(dev, type); 107332a8088fSRui Paulo 107432a8088fSRui Paulo #ifdef INTR_FILTER 107532a8088fSRui Paulo return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED); 107632a8088fSRui Paulo #else 107732a8088fSRui Paulo taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); 107832a8088fSRui Paulo #endif 107932a8088fSRui Paulo return (FILTER_HANDLED); 108032a8088fSRui Paulo } 108132a8088fSRui Paulo 108232a8088fSRui Paulo #ifdef INTR_FILTER 108332a8088fSRui Paulo static void 108432a8088fSRui Paulo asmc_sms_handler(void *arg) 108532a8088fSRui Paulo { 108632a8088fSRui Paulo struct asmc_softc *sc = device_get_softc(arg); 108732a8088fSRui Paulo 108832a8088fSRui Paulo asmc_sms_task(sc, 0); 108932a8088fSRui Paulo } 109032a8088fSRui Paulo #endif 109132a8088fSRui Paulo 109232a8088fSRui Paulo 109332a8088fSRui Paulo static void 109432a8088fSRui Paulo asmc_sms_printintr(device_t dev, uint8_t type) 109532a8088fSRui Paulo { 109632a8088fSRui Paulo 109732a8088fSRui Paulo switch (type) { 109832a8088fSRui Paulo case ASMC_SMS_INTFF: 109932a8088fSRui Paulo device_printf(dev, "WARNING: possible free fall!\n"); 110032a8088fSRui Paulo break; 110132a8088fSRui Paulo case ASMC_SMS_INTHA: 110232a8088fSRui Paulo device_printf(dev, "WARNING: high acceleration detected!\n"); 110332a8088fSRui Paulo break; 110432a8088fSRui Paulo case ASMC_SMS_INTSH: 110532a8088fSRui Paulo device_printf(dev, "WARNING: possible shock!\n"); 110632a8088fSRui Paulo break; 110732a8088fSRui Paulo default: 110832a8088fSRui Paulo device_printf(dev, "%s unknown interrupt\n", __func__); 110932a8088fSRui Paulo } 111032a8088fSRui Paulo } 111132a8088fSRui Paulo 111232a8088fSRui Paulo static void 111332a8088fSRui Paulo asmc_sms_task(void *arg, int pending) 111432a8088fSRui Paulo { 111532a8088fSRui Paulo struct asmc_softc *sc = (struct asmc_softc *)arg; 111632a8088fSRui Paulo char notify[16]; 111732a8088fSRui Paulo int type; 111832a8088fSRui Paulo 111932a8088fSRui Paulo switch (sc->sc_sms_intrtype) { 112032a8088fSRui Paulo case ASMC_SMS_INTFF: 112132a8088fSRui Paulo type = 2; 112232a8088fSRui Paulo break; 112332a8088fSRui Paulo case ASMC_SMS_INTHA: 112432a8088fSRui Paulo type = 1; 112532a8088fSRui Paulo break; 112632a8088fSRui Paulo case ASMC_SMS_INTSH: 112732a8088fSRui Paulo type = 0; 112832a8088fSRui Paulo break; 112932a8088fSRui Paulo default: 113032a8088fSRui Paulo type = 255; 113132a8088fSRui Paulo } 113232a8088fSRui Paulo 113332a8088fSRui Paulo snprintf(notify, sizeof(notify), " notify=0x%x", type); 11344470f0f3SRui Paulo devctl_notify("ACPI", "asmc", "SMS", notify); 113532a8088fSRui Paulo } 113632a8088fSRui Paulo 113732a8088fSRui Paulo static int 113832a8088fSRui Paulo asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) 113932a8088fSRui Paulo { 114032a8088fSRui Paulo device_t dev = (device_t) arg1; 114132a8088fSRui Paulo int error; 114232a8088fSRui Paulo int16_t val; 114332a8088fSRui Paulo int32_t v; 114432a8088fSRui Paulo 114532a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); 114632a8088fSRui Paulo v = (int32_t) val; 114732a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 114832a8088fSRui Paulo 114932a8088fSRui Paulo return (error); 115032a8088fSRui Paulo } 115132a8088fSRui Paulo 115232a8088fSRui Paulo static int 115332a8088fSRui Paulo asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) 115432a8088fSRui Paulo { 115532a8088fSRui Paulo device_t dev = (device_t) arg1; 115632a8088fSRui Paulo int error; 115732a8088fSRui Paulo int16_t val; 115832a8088fSRui Paulo int32_t v; 115932a8088fSRui Paulo 116032a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); 116132a8088fSRui Paulo v = (int32_t) val; 116232a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, 0, req); 116332a8088fSRui Paulo 116432a8088fSRui Paulo return (error); 116532a8088fSRui Paulo } 116632a8088fSRui Paulo 116732a8088fSRui Paulo static int 116832a8088fSRui Paulo asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) 116932a8088fSRui Paulo { 117032a8088fSRui Paulo device_t dev = (device_t) arg1; 117132a8088fSRui Paulo int error; 117232a8088fSRui Paulo int16_t val; 117332a8088fSRui Paulo int32_t v; 117432a8088fSRui Paulo 117532a8088fSRui Paulo asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); 117632a8088fSRui Paulo v = (int32_t) val; 117732a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 117832a8088fSRui Paulo 117932a8088fSRui Paulo return (error); 118032a8088fSRui Paulo } 118132a8088fSRui Paulo 118232a8088fSRui Paulo static int 118332a8088fSRui Paulo asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) 118432a8088fSRui Paulo { 118532a8088fSRui Paulo device_t dev = (device_t) arg1; 118632a8088fSRui Paulo uint8_t buf[6]; 118732a8088fSRui Paulo int error; 118832a8088fSRui Paulo int32_t v; 118932a8088fSRui Paulo 119032a8088fSRui Paulo asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, 6); 119132a8088fSRui Paulo v = buf[2]; 119232a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 119332a8088fSRui Paulo 119432a8088fSRui Paulo return (error); 119532a8088fSRui Paulo } 119632a8088fSRui Paulo 119732a8088fSRui Paulo static int 119832a8088fSRui Paulo asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) 119932a8088fSRui Paulo { 120032a8088fSRui Paulo device_t dev = (device_t) arg1; 120132a8088fSRui Paulo uint8_t buf[6]; 120232a8088fSRui Paulo int error; 120332a8088fSRui Paulo int32_t v; 120432a8088fSRui Paulo 120532a8088fSRui Paulo asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, 6); 120632a8088fSRui Paulo v = buf[2]; 120732a8088fSRui Paulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 1208be80e49aSRui Paulo 1209be80e49aSRui Paulo return (error); 1210be80e49aSRui Paulo } 1211be80e49aSRui Paulo 1212be80e49aSRui Paulo static int 1213be80e49aSRui Paulo asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) 1214be80e49aSRui Paulo { 1215be80e49aSRui Paulo device_t dev = (device_t) arg1; 1216be80e49aSRui Paulo uint8_t buf[2]; 1217be80e49aSRui Paulo int error; 1218be80e49aSRui Paulo unsigned int level; 1219be80e49aSRui Paulo static int32_t v; 1220be80e49aSRui Paulo 1221be80e49aSRui Paulo error = sysctl_handle_int(oidp, &v, sizeof(v), req); 122232a8088fSRui Paulo if (error == 0 && req->newptr != NULL) { 122332a8088fSRui Paulo level = *(unsigned int *)req->newptr; 122432a8088fSRui Paulo if (level > 255) 122532a8088fSRui Paulo return (EINVAL); 1226be80e49aSRui Paulo v = level; 122732a8088fSRui Paulo buf[0] = level; 122832a8088fSRui Paulo buf[1] = 0x00; 122932a8088fSRui Paulo asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2); 123032a8088fSRui Paulo } 123132a8088fSRui Paulo 123232a8088fSRui Paulo return (error); 123332a8088fSRui Paulo } 1234