The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/asmc/asmc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3e60e9e06c286550e856b20bde99a609


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.