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

Cache object: b8310395a47ad188f2ca40422689763a


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