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

Cache object: 711b3c8f3ae8bff7a876afc07a9c0a66


[ 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.