Hi all running OpenBSD on Apple hardware: 
I
 was working on the asmc kernel driver for the Macbooks. I have a 
MBPro8.2 (mid 2011), and came to get the driver installed, reading all 
sensors and temperatures into the "hw.sensors" framework. 
See
 attached diffs. Beginning line 30 I describe the ideas for the driver. 
Further information available,  also a "todo list". Thx to Joshua@, who 
helped me to create the diffs below, and provided input for the "todo 
list". Looking forward to get some feedback, especially on other Apple 
hardware.
rgds,
Volker
Index: dev/isa/asmc.c
===================================================================
RCS file: dev/isa/asmc.c
diff -N dev/isa/asmc.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/isa/asmc.c      24 Jan 2014 20:24:38 -0000
@@ -0,0 +1,1317 @@
+/* $OpenBSD: asmc.c,v 0.1 2014/01/14 15:47:16 volker $ */
+/*
+ * Copyright (c) 2013, 2014 Volker Nowarra 
+ * Complete rewrite of code in Nov/Dec 2013 from following sources:
+ *
+ * MACOSX:
+ * SmcFanControl.m by Hendrik Holtmann 
+ * SmcCommand.c (no reference)
+ * FREEBSD driver by Rui Paulo <rpa...@freebsd.org>
+ * LINUX driver by Nicolas Boichat <nico...@boichat.ch> and 
+ *                Henrik Rydberg <rydb...@euromail.se>
+ * and the OpenBSD aps.c driver by Jonathan Gray <j...@openbsd.org> and 
+ *                                Can Erkin Acar <cana...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+ 
+/*
+ * Driver for Apple's System Management Console (SMC). SMC can be found
+ * on the MacBook, MacBook Pro and Mac Mini, and possibly others ...
+ * 
+ * Idea is to match / attach into the kernel, as defined in "man 8 config", 
+ * section "EXAMPLES (kernel building)". The function asmc_match() would 
+ * read the BIOS, compare it to a defined model in "*asmc_models[]", and 
+ * if match, returns success. The asmc_attach() function would do the 
+ * "man 9 bus_space" handling, and call on success asmc_init(). 
+ * asmc_init() tries to talk to the SMC chip, and if success prepares 
+ * the sensors framework ("sysctl hw"), and sets up the the calls to 
+ * the SMC chip to readsensor values. The Apple SMC has read and write 
+ * areas, usually 10 read only values for FANs, 2 values for reading 
+ * backlit, and 3 for motion sensors (SMS). 
+ * Values can be written to change the FAN speeds. The different Apple 
+ * Macs provide up to 36 temperatur sensors !
+ * 
+ * Main driver for this development was reduction of code size into kernel,  
+ * two binary integers are used for the sensors and temps. This way code 
+ * size was reduced from 50KB down to 25KB, and to 15KB on i386. 
+ * Details see "struct asmc_model".
+ */
+
+/* 
+ * man style says, either param.h or types.h, but not both !
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/sensors.h>
+#include <sys/timeout.h>
+#include <sys/types.h>
+#include <sys/event.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+
+#include <machine/apmvar.h>
+#include <machine/biosvar.h>
+#include <machine/bus.h>
+#include <machine/smbiosvar.h>
+
+
+#define ASMCDEBUG
+#if defined(ASMCDEBUG)
+#define DPRINTF(x)             do { printf x; } while (0)
+#else
+#define DPRINTF(x)
+#endif
+
+/* ASMC DETAILED DEBUG :-) */
+#define XSMCDDEBUG
+#if defined(ASMCDDEBUG)
+#define DDPRINTF(x)            do { printf x; } while (0)
+#else
+#define DDPRINTF(x)
+#endif
+
+
+/*
+ * Observed values, partially from Linux and FreeBSD driver 
+ * data and command/status port used by Apple SMC 
+ */
+
+#define ASMC_DATAPORT_OFFSET   0x00
+#define ASMC_CMDPORT_OFFSET    0x04
+#define ASMC_ADDR_SIZE         0x1f
+#define ASMC_MAX_DATA_LENGTH   32 /* 0x300-0x31f */
+
+/* 
+ * Interrupt port
+ */
+#define ASMC_INTPORT_READ()    bus_space_read_1(0x300, 0x00, ASMC_ADDR_SIZE)
+
+/*
+ * SMC command modes
+ */
+#define ASMC_READ_CMD          0x10
+#define ASMC_WRITE_CMD         0x11
+#define ASMC_GETKEYBYINDEX_CMD 0x12
+#define ASMC_GETKEYBYTYPE_CMD  0x13
+
+/* 
+ * Timings
+ */
+#define ASMC_MIN_WAIT          0x0010
+#define ASMC_MAX_WAIT          0x8000
+#define ASMC_RETRY_WAIT                0x0400
+#define ASMC_REFRESH_RATE      7               /* in seconds   */
+
+/* 
+ * status from SMC chip 
+ */
+#define ASMC_STATUS_02         0x02
+#define ASMC_STATUS_04         0x04
+#define ASMC_STATUS_05         0x05
+#define ASMC_STATUS_08         0x08
+#define ASMC_STATUS_0C         0x0c
+#define ASMC_STATUS_0e         0x0e
+#define ASMC_STATUS_MASK       0x0f
+
+/*
+ * Number of keys 
+ */
+#define ASMC_NKEYS             "#KEY"  /* RO; 4 bytes */ 
+
+/*
+ * Clamshell
+ */
+#define ASMC_KEY_CLAMSHELL     "MSLD"  /* RO; 1 byte */
+
+/* 
+ * Interrupt keys
+ */
+#define ASMC_KEY_INTOK         "NTOK"  /* WO; 1 byte */
+
+/* 
+ * Fan control via SMC. 
+ */
+#define ASMC_MAXFANS           2
+#define ASMC_FANCOUNT          "FNum"  /* RO; 1 byte */
+#define ASMC_FANMANUAL         "FS! "  /* RW; 2 bytes */
+
+/* 
+ * Sudden Motion Sensor (SMS). 
+ */
+#define ASMC_SMS_INIT1         0xe0
+#define ASMC_SMS_INIT2         0xf8
+#define ASMC_KEY_SMS           "MOCN"  /* RW; 2 bytes */
+#define ASMC_KEY_SMS_LOW       "MOLT"  /* RW; 2 bytes */
+#define ASMC_KEY_SMS_HIGH      "MOHT"  /* RW; 2 bytes */
+#define ASMC_KEY_SMS_LOW_INT   "MOLD"  /* RW; 1 byte */
+#define ASMC_KEY_SMS_HIGH_INT  "MOHD"  /* RW; 1 byte */
+#define ASMC_KEY_SMS_FLAG      "MSDW"  /* RW; 1 byte */
+#define ASMC_SMS_INTFF         0x60    /* Free fall Interrupt */
+#define ASMC_SMS_INTHA         0x6f    /* High Acceleration Interrupt */
+#define ASMC_SMS_INTSH         0x80    /* Shock Interrupt */
+
+/* 
+ * Keyboard backlight 
+ */
+#define ASMC_KEY_LIGHTVALUE    "LKSB"  /* WO; 2 bytes */
+
+/* 
+ * max no of read ony sensors into sensors framework (sysctl hw): 
+ * 3 SMS, 10 Fans, 2 Lights, + max 36 Temps, to be verified ...
+ */
+#define ASMC_TOTAL_SENSORS     50
+
+
+/*
+ * OpenBSD Device driver interface.
+ */
+int     asmc_match(struct device *, void *, void *);
+void    asmc_attach(struct device *, struct device *, void *);
+
+struct asmc_softc {
+       struct device           sc_dev;         /* unclear ...          */
+        bus_space_tag_t        asmc_iot;       /* bus io tag           */
+        bus_space_handle_t     asmc_ioh;       /* io handler           */
+       struct mutex            sc_mutex;       /* mutex                */
+       int                     sc_nfan;        /* number of fans       */
+       struct ksensor          sensors[ASMC_TOTAL_SENSORS];
+       struct ksensordev       sensordev;      /* kernel sensor device */
+};
+
+struct cfattach asmc_ca = {
+       sizeof(struct asmc_softc), asmc_match, asmc_attach 
+};
+
+struct cfdriver asmc_cd = {
+       NULL, "asmc", DV_DULL
+};
+
+/* 
+ * To integrate for automatic updates every x seconds, 
+ * uncomment the next line ... 
+ * 
+ * struct timeout asmc_timeout; 
+ */
+
+/* 
+ * to convert numbers into binary values, only for debug purposes
+ */
+const char bit_rep[16][5] = { 
+[ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011", 
+[ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111", 
+[ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011", 
+[12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111" 
+}; 
+
+/* 
+ * descriptions of the Macs 
+ */
+const char *asmc_descs[] = { "unknown",
+/* 1  */ "Apple SMC MacBook Core Duo",
+/* 2  */ "Apple SMC MacBook",
+/* 3  */ "Apple SMC MacBook Air",
+/* 4  */ "Apple SMC MacBook Pro Core Duo (15-inch)",
+/* 5  */ "Apple SMC MacBook Pro Core Duo (17-inch)",
+/* 6  */ "Apple SMC MacBook Pro Core 2 Duo (17-inch)",
+/* 7  */ "Apple SMC MacBook Pro Core 2 Duo (15-inch)",
+/* 8  */ "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)",
+/* 9  */ "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)",
+/* 10 */ "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
+/* 11 */ "Apple SMC MacBook Pro",
+/* 12 */ "Apple SMC Mac Mini",
+/* 13 */ "Apple SMC Mac Pro (8-core)" 
+};
+
+/* 
+ * descriptions of the SMC Versions
+ */
+const char *asmc_versions[] = { "unknown", 
+"1.13f3",  "1.15f3",  "1.16f11", "1.18f5",  "1.19f2", 
+"1.1f5 ",  "1.20f4",  "1.23f20", "1.24f3",  "1.25f4", 
+"1.26f3",  "1.27f2",  "1.29f1",  "1.2f10",  "1.30f3", 
+"1.31f1",  "1.32f8",  "1.33f8",  "1.34f8",  "1.35f1", 
+"1.38f5",  "1.39f5",  "1.39f11", "1.3f4",   "1.42f4", 
+"1.47f2",  "1.48f2",  "1.49f2",  "1.4f12",  "1.51f53", 
+"1.53f13", "1.54f36", "1.58f16", "1.5f10",  "1.60f58", 
+"1.62f6",  "1.64f5",  "1.66f54", "1.68f96", "1.69f1", 
+"1.7f10",  "1.8f2" 
+};
+
+/* 
+ * descriptions of the SMC types
+ */
+const char *asmc_types[] = { "unknown", 
+"smc-napa", "smc-santarosa", "smc-mcp", 
+"smc-piketon", "smc-huronriver", "smc-thurley" 
+};
+
+/* 
+ * all possible temp codes, names and descriptions 
+ * temps are updated regularly, each ASMC_REFRESH_RATE
+ */
+const char *asmc_temp_field[] = {
+/* 1  */ "TA0P", "TA0P", "TA0P",
+/* 2  */ "TB0T", "enclosure", "Enclosure Bottom",
+/* 3  */ "TC0C", "TC0C", "TC0C",
+/* 4  */ "TC0D", "cpu", "CPU Temperature Diode",
+/* 5  */ "TC0P", "cpu2", "CPU Point 2",
+/* 6  */ "TC1C", "TC1C", "TC1C",
+/* 7  */ "TC1D", "TC1D", "TC1D",
+/* 8  */ "TC2C", "TC2C", "TC2C",
+/* 9  */ "TC2D", "TC2D", "TC2D",
+/* 10 */ "TC3C", "TC3C", "TC3C",
+/* 11 */ "TC3D", "TC3D", "TC3D",
+/* 12 */ "TCAG", "TCAG", "TCAG",
+/* 13 */ "TCAH", "TCAH", "TCAH",
+/* 14 */ "TCBG", "TCBG", "TCBG",
+/* 15 */ "TCBH", "TCBH", "TCBH",
+/* 16 */ "TG0D", "graphics", "Graphics Chip Diode",
+/* 17 */ "TG0H", "graphicssink", "Graphics Chip Heatsink",
+/* 18 */ "TG0P", "graphicssink", "Graphics Heatsink",
+/* 19 */ "TG0T", "unknown", "Unknown" ,
+/* 20 */ "Th0H", "heatsink1", "Main Heatsink 1",
+/* 21 */ "TH0P", "TH0P", "TH0P",
+/* 22 */ "Th1H", "heatsink2", "Main Heatsink 2",
+/* 23 */ "TH1P", "TH1P", "TH1P",
+/* 24 */ "Th2H", "heatsink3", "Main Heatsink 3",
+/* 25 */ "TH2P", "TH2P", "TH2P",
+/* 26 */ "TH3P", "TH3P", "TH3P",
+/* 27 */ "THTG", "THTG", "THTG",
+/* 28 */ "TM0P", "memory", "Memory Bank A",
+/* 29 */ "Tm0P", "memory", "Memory Controller",
+/* 30 */ "TM0P", "TM0P", "TM0P",
+/* 31 */ "TM0S", "TM0S", "TM0S",
+/* 32 */ "TM1P", "TM1P", "TM1P",
+/* 33 */ "TM1S", "TM1S", "TM1S",
+/* 34 */ "TM2P", "TM2P", "TM2P",
+/* 35 */ "TM2S", "TM2S", "TM2S",
+/* 36 */ "TM3S", "TM3S", "TM3S",
+/* 37 */ "TM8P", "TM8P", "TM8P",
+/* 38 */ "TM8S", "TM8S", "TM8S",
+/* 39 */ "TM9P", "TM9P", "TM9P",
+/* 40 */ "TM9S", "TM9S", "TM9S",
+/* 41 */ "TMAP", "TMAP", "TMAP",
+/* 42 */ "TMAS", "TMAS", "TMAS",
+/* 43 */ "TMBS", "TMBS", "TMBS",
+/* 44 */ "TN0H", "TN0H", "TN0H",
+/* 45 */ "TN0P", "northbridge1", "Northbridge Point 1",
+/* 46 */ "TN1P", "northbridge2", "Northbridge Point 2",
+/* 47 */ "TS0C", "TS0C", "TS0C",
+/* 48 */ "Ts0P", "unknown1", "Unknown",
+/* 49 */ "TTF0", "unknown2", "Unknown",
+/* 50 */ "TW0P", "wireless", "Wireless Module",
+
+/* 63 */ NULL, NULL, NULL
+};
+
+/* 
+ * these sensors are updated regularly, each ASMC_REFRESH_RATE
+ */
+const char *asmc_sensors_reg[] = { 
+/* 1  RO; 2 bytes */   "MO_X", "sms_x", "sms_x",
+/* 2  RO; 2 bytes */   "MO_Y", "sms_y", "sms_y",
+/* 3  RO; 2 bytes */   "MO_Z", "sms_z", "sms_z",
+/* 4  RO; 2 bytes */   "F0Ac", "fan0",  "fan0_speed",
+/* 5  RO; 2 bytes */   "F1Ac", "fan1",  "fan1_speed",
+/* 6  RW; 2 bytes */   "F0Tg", "fan0",  "fan0_targetspeed",
+/* 7  RW; 2 bytes */   "F1Tg", "fan1",  "fan1_targetspeed",
+/* 8  RO; 2 bytes */   "ALV0", "lightright", "lightright",
+/* 9  RO; 2 bytes */   "ALV1", "lightleft", "lightleft",
+/* 10            */    
+/* 16 */ NULL, NULL, NULL
+};
+
+/* 
+ * sensor codes, names and descriptions, used in reading 
+ * the SMC and updating the sensors framework ("sysctl hw")
+ * init sensors are only update once on init procedure
+ */
+const char *asmc_sensors_irreg[] = { 
+/* 1 RO; 2 bytes */    "F0Sf", "fan0", "fan0_safespeed",
+/* 2 RO; 2 bytes */    "F1Sf", "fan1", "fan1_safespeed",
+/* 3 RO; 2 bytes */    "F0Mn", "fan0", "fan0_minspeed",
+/* 4 RO; 2 bytes */    "F1Mn", "fan1", "fan1_minspeed",
+/* 5 RO; 2 bytes */    "F0Mx", "fan0", "fan0_maxspeed",
+/* 6 RO; 2 bytes */    "F1Mx", "fan1", "fan1_maxspeed",
+/* 7             */    
+/* 8             */    NULL, NULL, NULL
+};
+
+
+/******************* DRIVER RELATED FUNCTIONS ******************************
+ *
+ * OpenBSD I/O functions.
+ */
+static int asmc_wait_status(struct asmc_softc *sc, uint8_t val);
+static int asmc_bus_write(struct asmc_softc *sc, int offset, int cmd);
+static int asmc_read_key(struct asmc_softc *sc, const char *key, int *buffer, 
int len);
+/*
+ * AppleSMC related functions.
+ */
+static int asmc_update_sensors(struct asmc_softc *sc, bool status);
+static int asmc_get_sensors(struct asmc_softc *sc);
+void asmc_refresh(void *arg);
+static int asmc_init(struct asmc_softc *sc);
+
+/******************* SMC ATTRIBUTES PER COMPUTER ***************************
+ *
+ * This section prepares all options (SMS, fans, temperatures, ...)
+ */
+
+struct asmc_model {
+       const char      *asmc_model;    /* smbios unique name   */
+       const uint8_t   asmc_desc;      /* system description   */
+       const uint8_t   asmc_version;   /* SMC driver version   */
+       const uint8_t   asmc_type;      /* SMC type             */
+       const uint8_t   asmc_sensors_irreg; /* sensor (init)    */
+       const uint16_t  asmc_sensors_reg; /* sensor (regularly) */
+       const uint64_t  asmc_temps;     /* temperatures         */
+       
+       /* Not every model has the same sensors (temps, fans,   */
+       /* or SMS). Thus capabilities are reflected in          */
+       /* binaries. The binary can be easily extended ...      */
+       /* Each bit reflects the following capability:          */
+       /*                                                      */
+       /* for temperatures:                                    */
+       /* there are roughly 50 sensors defined ...             */
+       /* asmc_temps[1] = "TA0P", "TA0P"                       */
+       /* asmc_temps[2] = "enclosure", "Enclosure Bottom"      */
+       /* asmc_temps[3] = "TC0C", "TC0C"                       */
+       /* asmc_temps[4] = "cpu", "CPU Temperature Diode"       */
+       /* asmc_temps[5] = "cpu2", "CPU Point 2"                */
+       /* ...                                                  */
+       /* asmc_temps[45] = "northbridge1", "Northbridge 1"     */
+       /* asmc_temps[46] = "northbridge2", "Northbridge 2"     */
+       /* asmc_temps[47] = "TS0C", "TS0C"                      */
+       /* asmc_temps[48] = "unknown1", "Unknown"               */
+       /* asmc_temps[49] = "unknown2", "Unknown"               */
+       /* asmc_temps[50] = "wireless", "Wireless Module"       */
+       /* asmc_temps[51] = "unknown", "Unknown"                */
+       /* asmc_temps[52-63] = free for future usage            */
+       /*                                                      */
+       /* the regularly updated sensors                        */
+       /* asmc_sensors_reg[0] = sms_x  x shock motion sensor   */
+       /* asmc_sensors_reg[1] = sms_y  y shock motion sensor   */
+       /* asmc_sensors_reg[2] = sms_z  z shock motion sensor   */
+       /* asmc_sensors_reg[3] = fan0_speed                     */
+       /* asmc_sensors_reg[4] = fan1_speed                     */
+       /* asmc_sensors_reg[5] = fan0_targetspeed               */
+       /* asmc_sensors_reg[6] = fan1_targetspeed               */
+       /* asmc_sensors_reg[7] = lightright                     */
+       /* asmc_sensors_reg[8] = lightleft                      */
+       /* asmc_sensors_reg[9-15] = free for future usage       */
+       /*                                                      */
+       /* the "one time" updated sensors (at driver init)      */
+       /* asmc_sensors_irreg[0] = fan0_safespeed               */
+       /* asmc_sensors_irreg[1] = fan1_safespeed               */
+       /* asmc_sensors_irreg[2] = fan0_minspeed                */
+       /* asmc_sensors_irreg[3] = fan1_minspeed                */
+       /* asmc_sensors_irreg[4] = fan0_maxspeed                */
+       /* asmc_sensors_irreg[5] = fan1_maxspeed                */
+       /* asmc_sensors_irreg[6-7] = free for future usage      */
+       /*                                                      */
+};
+
+uint8_t asmc_model_index;      /* index into asmc_model structure */ 
+struct asmc_model asmc_models[] = {
+       /********************************************************
+        * to convert binary and decimal values, use bc:
+        *   $ echo "obase=2;63" | bc 
+        *   111111
+        *   $ echo "ibase=2;111111" | bc
+        *   63
+        ********************************************************/
+
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 63 = 00111111         )
+        * asmc_sensors_reg[0-15],      (127 = 00000000 01111111)
+        * asmc_temps[0-63]             ( 10 = 000...00 00001010)
+        * MAC BOOK (no backlights!):
+        ********************************************************/
+       { "MacBook1,1", 1, 29, 1, 63, 127, 10 },
+       { "MacBook2,1", 1, 1,  1, 63, 127, 10 },
+       { "MacBook3,1", 1, 9,  1, 63, 127, 10 },
+       { "MacBook4,1", 2, 16, 2, 63, 127, 10 },
+       { "MacBook5,1", 2, 17, 3, 63, 127, 10 },
+       { "MacBook5,2", 2, 21, 3, 63, 127, 10 },
+       { "MacBook6,1", 2, 30, 3, 63, 127, 10 },
+       { "MacBook7,1", 2, 30, 3, 63, 127, 10 },
+       
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 63 = 00111111         )
+        * asmc_sensors_reg[0-15],      (511 = 00000001 11111111)
+        * asmc_temps[0-63],            ( 10 = 000...00 00001010)
+        * MacBook Air (yes, they do have backlit !):
+        ********************************************************/
+       { "MacBookAir1,1", 3, 8,  2, 63, 511, 10 },
+       { "MacBookAir2,1", 3, 19, 3, 63, 511, 10 },
+       { "MacBookAir3,1", 3, 35, 3, 63, 511, 10 },
+       { "MacBookAir3,2", 3, 38, 3, 63, 511, 10 },
+       { "MacBookAir4,1", 3, 0,  0, 63, 511, 10 },     
+       { "MacBookAir5,1", 3, 0,  0, 63, 511, 10 },     
+       { "MacBookAir5,2", 3, 0,  0, 63, 511, 10 },     
+
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 60 = 00111100         )
+        * asmc_sensors_reg[0-15],      (511 = 00000001 11111111)
+        * asmc_temps[0-63],    985162698031130 =
+        * 11 10000000 00000000 00010000 10101001 10000000 00011010
+        * MacBook Pro:
+        ********************************************************/
+       { "MacBookPro1,1", 4,  14, 1, 63, 511, 268402687 },
+       { "MacBookPro1,2", 5,  34, 1, 63, 511, 268402687 },
+       { "MacBookPro2,1", 6,   4, 1, 63, 511, 268402687 },
+       { "MacBookPro2,2", 7,   4, 2, 63, 511, 268402687 },
+       { "MacBookPro3,1", 8,   3, 0, 63, 511, 268402687 },
+       { "MacBookPro3,2", 9,   0, 0, 63, 511, 268402687 },
+       { "MacBookPro4,1", 10, 10, 2, 63, 511, 268402687 },
+       { "MacBookPro5,1", 11, 26, 3, 63, 511, 268402687 },     
+       { "MacBookPro5,2", 11, 25, 3, 63, 511, 268402687 },     
+       { "MacBookPro5,3", 11, 27, 3, 63, 511, 268402687 },     
+       { "MacBookPro5,4", 11, 28, 3, 63, 511, 268402687 },     
+       { "MacBookPro5,5", 11, 33, 3, 63, 511, 268402687 },
+       { "MacBookPro6,1", 11, 36, 4, 63, 511, 268402687 },     
+       { "MacBookPro6,2", 11, 33, 4, 63, 511, 268402687 },     
+       { "MacBookPro7,1", 11, 40, 3, 63, 511, 268402687 },     
+       { "MacBookPro8,1", 10, 39, 5, 60, 511, 703687720730650LL },
+       { "MacBookPro8,2", 10, 39, 5, 60, 511, 703687720730650LL },
+       { "MacBookPro8,3", 11, 39, 5, 60, 511, 703687720730650LL },
+       { "MacBookPro9,1", 11,  0, 0, 60, 511, 703687720730650LL },
+       { "MacBookPro9,2", 11,  0, 0, 60, 511, 703687720730650LL },
+       
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 63 = 00111111         )
+        * asmc_sensors_reg[0-15],      (120 = 00000000 01111000)
+        * asmc_temps[0-63],            ( 10 = 000...00 00001010)
+        * Mac Mini (has no SMS and no Backlight)
+        ********************************************************/
+       { "MacMini1,1", 13, 24, 1, 63, 120, 10 },
+       { "MacMini2,1", 13,  5, 1, 63, 120, 10 },
+       { "MacMini3,1", 13, 20, 3, 63, 120, 10 },
+       { "Macmini4,1", 13,  0, 0, 63, 120, 10 },
+       { "Macmini5,1", 13,  0, 0, 63, 120, 10 },
+       { "Macmini5,2", 13,  0, 0, 63, 120, 10 },
+       { "Macmini5,3", 13,  0, 0, 63, 120, 10 },
+       
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 63 = 00111111         )
+        * asmc_sensors_reg[0-15],      (120 = 00000000 01111000)
+        * asmc_temps[0-63],       10 = 000...00 00001010
+        * MacPro (has no SMS and no Backlight):
+        *******************************************************/
+       { "MacPro1,1", 14, 41, 1, 63, 120, 10 },
+       { "MacPro2,1", 14,  2, 1, 63, 120, 10 },
+       { "MacPro3,1", 14, 10, 1, 63, 120, 10 },
+       { "MacPro4,1", 14, 22, 6, 63, 120, 10 },        
+       { "MacPro5,1", 14, 23, 6, 63, 120, 10 },
+ 
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 63 = 00111111         )
+        * asmc_sensors_reg[0-15],      (120 = 00000000 01111000)
+        * asmc_temps[0-63]
+        * iMac 9.1: version "IM91.88Z.008D.B08.0904271717"
+        *******************************************************/
+       { "iMac4,1",  0, 6,  1, 63, 120, 10 },
+       { "iMac4,2",  0, 6,  1, 63, 120, 10 },
+       { "iMac5,1",  0, 42, 1, 63, 120, 10 },
+       { "iMac5,2",  0, 42, 1, 63, 120, 10 },
+       { "iMac6,1",  0, 42, 2, 63, 120, 10 },
+       { "iMac7,1",  0, 7,  2, 63, 120, 10 },
+       { "iMac8,1",  0, 13, 2, 63, 120, 10 },
+       { "iMac9,1",  0, 15, 1, 63, 120, 10 },
+       { "iMac10,1", 0, 31, 3, 63, 120, 10 },
+       { "iMac11,1", 0, 32, 4, 63, 120, 10 },
+       { "iMac11,2", 0, 37, 4, 63, 120, 10 },
+       { "iMac12,1", 0, 18, 5, 63, 120, 10 },
+       { "iMac12,2", 0, 18, 5, 63, 120, 10 },
+
+       /********************************************************
+        * MODEL, DESC, SMC_Version, SMC_Type, 
+        * asmc_sensors_irreg[0-7],     ( 63 = 00111111         )
+        * asmc_sensors_reg[0-15],      (120 = 00000000 01111000)
+        * asmc_temps[0-63]
+        * XServers ... 
+        *******************************************************/
+       { "Xserve1,1", 0, 11, 1, 63, 120, 10 },
+       { "Xserve2,1", 0, 11, 1, 63, 120, 10 },
+
+       { "UNKNOWN" },
+       { NULL }
+};
+
+/******************* DRIVER SUPPORT FUNCTIONS BEGIN HERE *********************
+ *
+ * asmc_update_sensors - update the sensors framework by (re-) reading
+ * current sensor values.
+ * status=0 if called from init function 
+ *     (also update "one time sensors", as defined in *asmc_sensors_irreg[])
+ * status=1 if called asmc_refresh function 
+ *     (update only regular sensors, as defined in *asmc_sensors_reg[])
+ */
+static int 
+asmc_update_sensors(struct asmc_softc *sc, bool status)
+{
+       int buffer[6], val;
+       uint8_t i, k, sensor_number;
+       uint64_t j;
+
+       struct asmc_model *model;
+
+       DPRINTF(("ASMC_UPDATE_SENSORS\n"));
+
+       model = &asmc_models[asmc_model_index];
+
+       /************************************************* 
+        * Read the possible TEMPERATURES 
+        *************************************************/
+       DPRINTF((" ** TEMPERATURES \n"));
+       /* 
+        * run through all temp types and update the values in sysctl
+        * framework "sysctl hw". The asmc_temps bitfield is sizeof(uint64_t) 
+        * variable, so asmc_temps is 8 bytes, multiply it by 8 (bits)
+        * to loop through all the 64 bits. For each match call asmc_read_key.
+        */
+       sensor_number=1;
+       j=1;
+       for (i=0; i<8*sizeof(model->asmc_temps); i++) { 
+           k=i*3;
+           if (model->asmc_temps & j) {
+               if (strlen(asmc_temp_field[k])) {
+                   DPRINTF((" ** %s, %s, %s \n", asmc_temp_field[k], 
+                       asmc_temp_field[k+1], 
+                       asmc_temp_field[k+2]));
+                   if(asmc_read_key(sc, asmc_temp_field[k], buffer, 2)) {
+                       DPRINTF((" ** Error updating sensor %s. \n", 
+                           asmc_temp_field[k]));
+                       sc->sensors[sensor_number].flags &= ~SENSOR_FUNKNOWN;
+                       sc->sensors[sensor_number].status = SENSOR_S_UNKNOWN;
+                       val = 0;
+                   } else 
+                       val = buffer[0];
+                   DPRINTF(("  * %s = %d, sensor_number=%d \n", 
+                       asmc_temp_field[k], val, sensor_number));
+                   sc->sensors[sensor_number++].value = val;
+               }
+           }
+           j = j << 1;
+       } /* end for loop */
+
+       /* 
+        * run through all regularly updatable sensors and update the values
+        * in sysctl framework "sysctl hw". The sensors bitfield is 
+        * sizeof(uint16_t) variable, so "asmc_sensors_reg" is two bytes, 
+        * multiply it by 8 (bits) to loop through each of the 16 bits.
+        * Call for each match asmc_read_key.
+        */ 
+       DPRINTF((" ** REG-SENSORS \n"));
+       j=1;
+       for (i=0; i<8*sizeof(model->asmc_sensors_reg); i++) { 
+           buffer[0] = 0;
+           buffer[1] = 0;
+           buffer[2] = 0;
+           buffer[3] = 0;
+           k=i*3;
+           if (model->asmc_sensors_reg & j) {
+               if (strlen(asmc_sensors_reg[k])) {
+                   DPRINTF((" ** %s, %s, %s \n", asmc_sensors_reg[k], 
+                       asmc_sensors_reg[k+1],
+                       asmc_sensors_reg[k+2]));
+                   /******************************************** 
+                   * Read X/Y/Z motion sensors. tbd! 
+                   * if (i<3) type=SENSOR_ACCEL;
+                   *********************************************/
+                   if (i<3) { 
+                       if(asmc_read_key(sc, asmc_sensors_reg[k], buffer, 2)) {
+                          DPRINTF((" ** Error updating SMS sensor %s. \n",
+                                asmc_sensors_reg[k]));
+                          sc->sensors[sensor_number].flags &= ~SENSOR_FUNKNOWN;
+                          sc->sensors[sensor_number].status = SENSOR_S_UNKNOWN;
+                          val = 0;
+                       } else {
+                          val = ((int16_t)buffer[0] << 8);
+                       }
+                   }
+
+                   /******************************************** 
+                   * Read FANs
+                   *********************************************/
+                   if (i>=3 && i<=6) { 
+                       if(asmc_read_key(sc, asmc_sensors_reg[k], buffer, 2)) {
+                          DPRINTF((" ** Error updating FAN sensor %s. \n",
+                                asmc_sensors_reg[k]));
+                          sc->sensors[sensor_number].flags &= ~SENSOR_FUNKNOWN;
+                          sc->sensors[sensor_number].status = SENSOR_S_UNKNOWN;
+                          val = 0;
+                       } else {
+                          val = (buffer[0] << 6) | (buffer[1] >> 2);
+                       }
+                   }
+
+                   /******************************************** 
+                   * Read lights
+                   *********************************************/
+                   if (i>=7 && i<=8) {
+                       if(asmc_read_key(sc, asmc_sensors_reg[k], buffer, 6)) {
+                          DPRINTF((" ** Error updating light sensor %s. \n",
+                               asmc_sensors_reg[k]));
+                          sc->sensors[sensor_number].flags &= ~SENSOR_FUNKNOWN;
+                          sc->sensors[sensor_number].status = SENSOR_S_UNKNOWN;
+                          val = 0;
+                       } else {
+                          val = buffer[2];
+                       }
+                   }
+                   DPRINTF(("  * %s = %d, sensor_number=%d \n", 
+                       asmc_sensors_reg[k], val, sensor_number));
+                   sc->sensors[sensor_number++].value = val;
+               }
+           } 
+           j = j << 1;
+       } /* end sensors for() loop */
+
+       /* 
+        * run through all "only on init updated" sensors and put the values
+        * in the sysctl framework "sysctl hw". The sensors bitfield is 
+        * sizeof(uint8_t) variable, so "asmc_sensors_irreg" is one byte, 
+        * multiply it by 8 (bits) to loop through each of the 8 bits.
+        * Call for each match asmc_read_key.
+        * update only, if function parameter "status" = 0
+        */ 
+       DPRINTF((" ** IRREG-SENSORS, Status = %d\n", status));
+       if ( status ) {
+           j=1;
+           for (i=0; i<8*sizeof(model->asmc_sensors_irreg); i++) { 
+               buffer[0] = 0;
+               buffer[1] = 0;
+               buffer[2] = 0;
+               buffer[3] = 0;
+               k=i*3;
+               if (model->asmc_sensors_irreg & j) {
+                   if (strlen(asmc_sensors_irreg[k])) {
+                       DPRINTF((" ** %s, %s, %s \n", asmc_sensors_irreg[k], 
+                          asmc_sensors_irreg[k+1],
+                          asmc_sensors_irreg[k+2]));
+                       if(asmc_read_key(sc, asmc_sensors_irreg[k], buffer, 2)) 
{
+                          DPRINTF((" ** Error updating sensor %s. \n",
+                          asmc_sensors_irreg[k]));
+                          sc->sensors[sensor_number].flags &= ~SENSOR_FUNKNOWN;
+                          sc->sensors[sensor_number].status = SENSOR_S_UNKNOWN;
+                          val = 0;
+                       } else 
+                          val = (buffer[0] << 6) | (buffer[1] >> 2);
+                       DPRINTF(("  * %s = %d, sensor_number=%d \n", 
+                       asmc_sensors_irreg[k], val, sensor_number));
+                       sc->sensors[sensor_number++].value = val;
+                   }   /* end if strlen ...                    */
+               }       /* end if model... & j                  */ 
+           j = j << 1;
+           }           /* end "one time" sensors for() loop    */
+       } else {
+           DPRINTF(("*** not in IRREG-SENSORS, Status = %d\n", status));
+       }               /* end if status = ...                  */
+       return 0;
+}
+
+
+/*
+ * asmc_get_sensors - get the possible sensors from the asmc structure.
+ * The sensors are defined in several fields, every bit indicates an 
+ * existing sensor. Not all models have the same amount or 
+ * types of sensors. So need to get the binary 
+ * (asmc_models[asmc_model_index].asmc_sensors) and run through it bit 
+ * by bit. The variable "j" points for all temperatures and sensors into 
+ * the corresponding arrays, to get the names or descriptions of the 
+ * sensors and temps (from the asmcvar.h file).
+ */
+static int 
+asmc_get_sensors(struct asmc_softc *sc)
+{
+       uint64_t j=1;
+       uint32_t i, k=0; 
+       uint8_t bitval, sensor_number;
+
+       struct asmc_model *model;
+       
+       DPRINTF(("ASMC_GET_SENSORS\n"));
+
+       bitval=0;
+       model = &asmc_models[asmc_model_index];
+
+       DDPRINTF((" asmc_model=%s\n", model->asmc_model));
+       DDPRINTF((" asmc_temp=%llu\n ", model->asmc_temps));
+       bitval = (model->asmc_temps >> 56) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps >> 48) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps >> 40) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps >> 32) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps >> 24) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps >> 16) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps >> 8) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_temps) & 0xff;
+       DDPRINTF(("%s%s\n", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+
+       DDPRINTF((" asmc_sensors_reg=%d, ", model->asmc_sensors_reg));
+       bitval = (model->asmc_sensors_reg >> 8) & 0xff;
+       DDPRINTF(("%s%s ", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+       bitval = (model->asmc_sensors_reg) & 0xff;
+       DDPRINTF(("%s%s\n", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+
+       DDPRINTF((" asmc_sensors_irreg=%d, ", model->asmc_sensors_irreg));
+       bitval = (model->asmc_sensors_reg) & 0xff;
+       DDPRINTF(("%s%s\n", bit_rep[bitval >> 4], bit_rep[bitval & 0x0F])); 
+
+       /* 
+        * find a temperature by running through the asmc_temps bitfield. 
+        * "model->asmc_temps" is a sizeof(uint64_t) variable, multiply by
+        * 8 (bits) to loop through each of the 64 bits. If bit is set, 
+        * assign "aspplesmc" to the sensordev.xname. Add to the current
+        * sensor (sc->sensor) the type and attach it to sc->sensordev. 
+        */ 
+       sensor_number=1;
+       i=0;
+       j=1;
+       k=0;
+       for (i=0; i<8*sizeof(model->asmc_temps); i++) { 
+           k=i*3;
+           if (model->asmc_temps & j) {
+               DDPRINTF((" Temps: bit[%d], j=%llu, ", i, j));
+               DDPRINTF(("k=%d ", k)); 
+               strlcpy(sc->sensordev.xname, "applesmc", 
sizeof(sc->sensordev.xname));
+               DDPRINTF(("--> "));
+               if (strlen(asmc_temp_field[k])) {
+                   DDPRINTF(("%s, %s", 
+                       asmc_temp_field[k+1], 
+                       asmc_temp_field[k+2]));
+                   /* sc->sensors[sensor_number].type=SENSOR_TEMP; */
+                   sc->sensors[sensor_number].type=SENSOR_INTEGER;
+                   strlcpy(sc->sensors[sensor_number].desc, 
asmc_temp_field[k+2], sizeof(sc->sensors[sensor_number].desc));
+               }
+               DDPRINTF(("\n"));
+               /* All possible temps have been read, we attach to the 
+                * sensors framework, and set all values to "invalid".  */
+               sensor_attach(&sc->sensordev, &sc->sensors[sensor_number]);
+               sc->sensors[sensor_number].flags &= ~SENSOR_FINVALID;
+               sensor_number++;
+           }
+           j = j << 1;
+       }
+
+       /* 
+        * find a "to be regularly updated" sensor by running through the 
+        * "asmc_sensors_reg" bitfield. "model->asmc_temps" is a 
+        * sizeof(uint16_t) variable, multiply by 8 (bits) to loop through 
+        * each of the 16 bits. If bit is set, assign "aspplesmc" to the 
+        * sensordev.xname. Add to the current sensor (sc->sensor) the type 
+        * and attach it to sc->sensordev. 
+        */ 
+       i=0;
+       j=1;
+       k=0;
+       for (i=0; i<8*sizeof(model->asmc_sensors_reg); i++) { 
+           k=i*3;
+           if (model->asmc_sensors_reg & j) {
+               DDPRINTF((" Sensors: bit[%d], j=%llu, k=%d ", i, j, k));
+               strlcpy(sc->sensordev.xname, "applesmc", 
+                   sizeof(sc->sensordev.xname));
+               DDPRINTF(("--> "));
+               if (strlen(asmc_sensors_reg[k])) {
+                   if (i<3) 
+                       sc->sensors[sensor_number].type=SENSOR_ACCEL;
+                   if (i>=3 && i<=6) 
+                       sc->sensors[sensor_number].type=SENSOR_FANRPM;
+                   if (i>=7 && i<=8) 
+                       sc->sensors[sensor_number].type=SENSOR_LUX;
+                   DDPRINTF(("%s, %s\n",
+                       asmc_sensors_reg[k+1], 
+                       asmc_sensors_reg[k+2]));
+                   strlcpy(sc->sensors[sensor_number].desc, 
+                       asmc_sensors_reg[k+2], 
+                       sizeof(sc->sensors[sensor_number].desc));
+               }
+               /*
+                * All regularly updatable sensors have been read, we attach 
+                * to the sensors framework, and set all values to "invalid".
+                */
+               sensor_attach(&sc->sensordev, &sc->sensors[sensor_number]);
+               sc->sensors[sensor_number].flags &= ~SENSOR_FINVALID;
+               sensor_number++;
+           } 
+           j = j << 1;
+       } /* end for() loop */
+
+       /* 
+        * find all irregularly updated sensors by running through the 
+        * "asmc_sensors_irreg" bitfield. "model->asmc_sensors_irreg" is a 
+        * sizeof(uint8_t) variable, multiply by 8 (bits) to loop through 
+        * each of the 8 bits. If bit is set, assign "aspplesmc" to the 
+        * sensordev.xname. Add to the current sensor (sc->sensor) the type 
+        * and attach it to sc->sensordev. 
+        */ 
+       i=0;
+       j=1;
+       k=0;
+       for (i=0; i<8*sizeof(model->asmc_sensors_irreg); i++) { 
+           k=i*3;
+           if (model->asmc_sensors_irreg & j) {
+               DDPRINTF((" Sensors: bit[%d], j=%llu, k=%d ", i, j, k));
+               strlcpy(sc->sensordev.xname, "applesmc", 
+                   sizeof(sc->sensordev.xname));
+               DDPRINTF(("--> "));
+               if (strlen(asmc_sensors_irreg[k])) {
+                   sc->sensors[sensor_number].type=SENSOR_FANRPM;
+                   DDPRINTF(("%s, %s\n",
+                       asmc_sensors_irreg[k+1], 
+                       asmc_sensors_irreg[k+2]));
+                   strlcpy(sc->sensors[sensor_number].desc, 
+                       asmc_sensors_irreg[k+2], 
+                       sizeof(sc->sensors[sensor_number].desc));
+               }
+               /* All "one time" sensors have been read, we attach to the 
+                * sensors framework, and set all values to "invalid". */
+               sensor_attach(&sc->sensordev, &sc->sensors[sensor_number]);
+               sc->sensors[sensor_number].flags &= ~SENSOR_FINVALID;
+               sensor_number++;
+           } 
+           j = j << 1;
+       } /* end for() loop */
+
+       DDPRINTF(("\n"));
+       DDPRINTF(("sensordev_install(&sc->sensordev);\n"));
+       sensordev_install(&sc->sensordev); 
+       return 0;
+}
+
+
+/*
+ * asmc_refresh - update the sensors regularly. 
+ * The timeout_set() function reuires the refresh
+ * routine to be a void() function. 
+ */
+void
+asmc_refresh(void *arg)
+{
+       struct asmc_softc *sc = (struct asmc_softc *)arg;
+
+       if (asmc_update_sensors(sc,NULL)) 
+           DPRINTF(("*** ERROR in update_sensors section ... \n"));
+
+       /* timeout_add_sec(&asmc_timeout, ASMC_REFRESH_RATE); */
+}
+
+/***************************************************************************
+ *
+ * asmc commands - to initialize, read and write values to the SMC 
+ * 
+ ***************************************************************************/
+
+
+/*
+ * asmc_wait_status - Wait for the status port to come back with a certain 
+ * value (masked with 0x0f), returning zero if the value is obtained. 
+ */
+static int 
+asmc_wait_status(struct asmc_softc *sc, uint8_t val)
+{
+       int i, status;
+
+       DDPRINTF(("   WAIT_STATUS, expected val=0x%02x,", val)); 
+       val = val & ASMC_STATUS_MASK;
+       DDPRINTF((" mask with 0x%02x: 0x%02x,", ASMC_STATUS_MASK, val)); 
+
+       for (i = ASMC_MIN_WAIT; i < ASMC_MAX_WAIT; i <<= 1) {
+           delay(ASMC_RETRY_WAIT);     /* wait & resend          */
+           mtx_enter(&sc->sc_mutex);
+           status=bus_space_read_1(sc->asmc_iot, sc->asmc_ioh, 
ASMC_CMDPORT_OFFSET);
+           mtx_leave(&sc->sc_mutex);
+           if (status & ASMC_STATUS_02)        /* wait for smc to settle */
+               continue;
+           if (status & ASMC_STATUS_04) {      /* cmd accepted, good !   */
+               DDPRINTF((" status=%s%s, *ok*\n", bit_rep[val >> 4], 
bit_rep[val & 0x0F])); 
+               return(0);
+           }
+           if (status & ASMC_STATUS_08)        /* wait for smc to settle */
+               continue;
+           if (status & ASMC_STATUS_0e)        /* wait for smc to settle */
+               continue;
+           if (i >= ASMC_MAX_WAIT) {           /* timeout: give up      */
+               DPRINTF(("\n ** failed, status=%s%s \n", bit_rep[val >> 4], 
bit_rep[val & 0x0F])); 
+               break;
+           }
+           DDPRINTF(("i=%d, status=0x%02x; ", i, status)); 
+       }
+       if ( i >= ASMC_MAX_WAIT ) DDPRINTF((" \n")); 
+       DPRINTF(("*** wait status failed: status 0x%02x != expected value 
0x%02x\n", status, val));
+       return -EIO;
+}
+
+
+/*
+ * asmc_bus_write - send command to write to a port
+ */
+static int 
+asmc_bus_write(struct asmc_softc *sc, int offset, int val)
+{
+       DDPRINTF(("   bus_space_write(iot0x%02x, ioh0x%02x, offset0x%02x, 
val=0x%02x) \n", sc->asmc_iot, sc->asmc_ioh, offset, val));
+       mtx_enter(&sc->sc_mutex);
+       bus_space_write_1(sc->asmc_iot, sc->asmc_ioh, offset, val);
+       mtx_leave(&sc->sc_mutex);
+       if (asmc_wait_status(sc, ASMC_STATUS_0C)) {
+           DPRINTF(("*** Error getting result for 0x%02x\n", val));
+           return -EIO;
+       }
+       return 0;
+}
+
+
+/*
+ * asmc_read_key - reads len bytes from ASMC_DATAPORT_OFFSET
+ * This is "the" major function of the APPLE SMC driver. 
+ * To read sensors or temps, a four letter code must be sent to
+ * the SMC chip's I/O address. Procedure is like this:
+ *  1: write to the CMD port (0x304), that we want to read something
+ *  2: write to the data port (0x300) the four letter code
+ *  3: write the length ("int len") to the data port (0x300)
+ *  4: read the result from the data port (0x300)
+ * The SMC will reply with status codes for each activity, which are
+ * captured in the asmc_wait_status() routine.
+ * The result goes into our buffer. 
+ */
+static int 
+asmc_read_key(struct asmc_softc *sc, const char *key, int *buffer, int len)
+{
+       int i,y;
+       uint8_t status, data;
+
+       DDPRINTF((" ASMC_READ_KEY\n"));
+
+       status=data=0;
+
+       if (len > ASMC_ADDR_SIZE) {
+           DPRINTF(("*** Error: len is too big: %db \n", ASMC_ADDR_SIZE));
+           return -EINVAL;
+       }
+
+       DDPRINTF(("  STEP1: asmc_bus_write, to send ASMC_READ_CMD\n"));
+       if(asmc_bus_write(sc, ASMC_CMDPORT_OFFSET, ASMC_READ_CMD))
+           return -EIO;
+
+       DDPRINTF(("  STEP2: asmc_bus_write to send 4 letter code\n"));
+       for (i=0; i<4; i++) {
+           y=key[i];
+           DDPRINTF(("   key[%d]=%s,",i,&y)); 
+           if(asmc_bus_write(sc, ASMC_DATAPORT_OFFSET, y))
+               return -EIO;
+           if (asmc_wait_status(sc, ASMC_STATUS_04))
+               return -EIO;
+       }
+       DDPRINTF(("  STEP3: asmc_bus_write for length result, length=%d\n", 
len));
+       if(asmc_bus_write(sc, ASMC_DATAPORT_OFFSET, len))
+           return -EIO;
+       DDPRINTF(("  STEP4: wait with 0x05, and read result to buffer\n"));
+       for (i=0; i<len; i++) {
+           if (asmc_wait_status(sc, ASMC_STATUS_05)) 
+               return -EIO;
+           DDPRINTF(("   bus_space_read:")); 
+           mtx_enter(&sc->sc_mutex);
+           buffer[i] = bus_space_read_1(sc->asmc_iot, 
+               sc->asmc_ioh, ASMC_DATAPORT_OFFSET);
+           mtx_leave(&sc->sc_mutex);
+           DDPRINTF((" len=%d, buffer[%d]=%d\n", len, i, buffer[i]));
+       }
+       DDPRINTF(("  buf[0]=%d, buf[1]=%d, buf[2]=%d, buf[3]=%d, buf[4]=%d, 
buf[5]=%d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], 
buffer[5]));
+
+       /* read data port until bit 0 is cleared */
+       DDPRINTF(("  read data port until bit 0 is cleared, "));
+       for (i=0; i<16; i++) {
+           delay(ASMC_RETRY_WAIT);
+           mtx_enter(&sc->sc_mutex);
+           status=bus_space_read_1(sc->asmc_iot, sc->asmc_ioh, 
ASMC_CMDPORT_OFFSET);
+           mtx_leave(&sc->sc_mutex);
+           if (!(status & 0x01))
+               break;
+           mtx_enter(&sc->sc_mutex);
+           data=bus_space_read_1(sc->asmc_iot, sc->asmc_ioh, 
ASMC_DATAPORT_OFFSET);
+           mtx_leave(&sc->sc_mutex);
+       }
+       if (i)
+           DDPRINTF(("  flushed %d bytes, last value is: %d", i, data));
+       DDPRINTF(("\n"));
+       return 0;
+}
+
+
+static int 
+asmc_init(struct asmc_softc *sc)
+{
+       uint8_t index[4];
+       uint8_t i;
+       int buffer[6], val;
+
+       char key[5] = { 0 };
+       char type[7] = { 0 };
+
+       struct asmc_model *model;
+
+       DPRINTF(("ASMC_INIT \n"));
+       model = &asmc_models[asmc_model_index];
+
+       /************************************************* 
+        * Read the number of keys (32 ?)  
+        *
+        * XXX: The number of keys is a 32 bit buffer, but
+        * right now Apple only uses the last 8 bit.
+        *************************************************/
+       DPRINTF((" ** ASMC_NKEYS\n"));
+       if (asmc_read_key(sc, ASMC_NKEYS, buffer, 4)) { 
+           DPRINTF((" ** no value for ASMC_NKEYS, trying again ... \n"));
+           delay(ASMC_RETRY_WAIT);
+           if (asmc_read_key(sc, ASMC_NKEYS, buffer, 4))  
+               DPRINTF(("*** Error in ASMC_NKEYS. \n"));
+       } else 
+           DPRINTF(("  * number of keys = %d\n", buffer[3]));
+
+       /************************************************* 
+        * ok, generally we can speak to the SMC. Before 
+        * preparing the sensors framework, need to be 
+        * sure if we have fans in the system. All MACs
+        * have FANs, haven't they ?
+        * If so, we can continue reading all other sensors. 
+        * 
+        * Read the Number of FANs
+        *************************************************/
+       DPRINTF((" ** ASMC_FANCOUNT\n"));
+       if (asmc_read_key(sc, ASMC_FANCOUNT, buffer, 1)) {
+           DPRINTF((" ** no value for FANCOUNT, retrying ... \n"));
+           delay(ASMC_RETRY_WAIT);
+           if (asmc_read_key(sc, ASMC_FANCOUNT, buffer, 1)) {
+               DPRINTF(("*** Error in FANCOUNT. \n"));
+               return -EIO;
+           }
+       }
+       sc->sc_nfan = buffer[0];
+       DPRINTF(("  * FANCOUNT=%d\n", sc->sc_nfan));
+
+       if ( sc->sc_nfan > ASMC_MAXFANS ) {
+           DPRINTF(("  * FANCOUNT: %d exceeds MAX_FANCOUNT %d, setting FAN 
count to 1\n", sc->sc_nfan, ASMC_MAXFANS));
+           sc->sc_nfan = 1;
+       } 
+
+       /************************************************* 
+        * ok, SMC replies to our requests in an expected 
+        * manner, let's prepare the sensors framework, 
+        * before reading all other sensors
+        *************************************************/
+       if(asmc_get_sensors(sc)) {
+           DPRINTF(("*** Error getting sensors ... \n"));
+           return -EIO;
+       }
+
+       /************************************************* 
+        * and read the sensors values at the same time    
+        *************************************************/
+       if (asmc_update_sensors(sc,1)) {
+           DPRINTF(("*** ERROR in update_sensors section ... \n"));
+           return 0;
+       }
+/* 
+       timeout_set(&asmc_timeout, asmc_refresh, sc);
+       timeout_add_sec(&asmc_timeout, ASMC_REFRESH_RATE);
+*/
+       return 0;
+
+/************************************************* 
+ * these functions exist in the FREEBSD driver, 
+ * usage/return values currently unclear ... 
+ ************************************************* 
+ * The function "GetKeybyIndex" is called in the 
+ * FREEBSD driver with val=1;val<=100;val++ ...
+ * that should be 1 to keycount ?
+ *************************************************/
+       /************************************************* 
+        * Get Key by Index
+        *************************************************/
+       val = 1;
+       index[0] = (val >> 24) & 0xff;
+       index[1] = (val >> 16) & 0xff;
+       index[2] = (val >> 8) & 0xff;
+       index[3] = (val) & 0xff;
+       DPRINTF(("*** GET KEY BY INDEX ***\n"));
+
+       if(asmc_bus_write(sc, ASMC_CMDPORT_OFFSET, ASMC_GETKEYBYINDEX_CMD))
+           DPRINTF((" ** Could not GET KEY BY INDEX ... \n"));
+       for (i = 0; i < 4; i++) {
+           val=index[i];
+           DDPRINTF(("FOR LOOP, index[%d]=%s%s \n", i, bit_rep[val >> 4], 
bit_rep[val & 0x0F])); 
+           if(asmc_bus_write(sc, ASMC_DATAPORT_OFFSET, index[i])) {
+               return -EIO;
+           }
+           if (asmc_wait_status(sc, ASMC_STATUS_04)) {
+               return -EIO;
+           }
+       }
+       DDPRINTF((" After for loop...\n"));
+       if(asmc_bus_write(sc, ASMC_DATAPORT_OFFSET, 4)) {
+           DPRINTF((" ** Could not GET KEY BY INDEX ... \n"));
+       }
+       for (i = 0; i < 4; i++) {
+           if (asmc_wait_status(sc, ASMC_STATUS_05)) {
+               return -EIO;
+           }
+           mtx_enter(&sc->sc_mutex);
+           key[i]=bus_space_read_1(sc->asmc_iot, sc->asmc_ioh, 
ASMC_DATAPORT_OFFSET);
+           mtx_leave(&sc->sc_mutex);
+           DPRINTF((" key[%d]=0x%02x\n", i, key[i]));
+       }
+       DPRINTF(("\n"));
+
+       /************************************************* 
+        * Get Key by Type 
+        *************************************************/
+       DPRINTF(("*** GET KEY BY TYPE ***\n"));
+       if(asmc_bus_write(sc, ASMC_CMDPORT_OFFSET, ASMC_GETKEYBYTYPE_CMD))
+           DPRINTF((" ** Could not GET KEY BY TYPE ... \n"));
+       for (i = 0; i < 4; i++) {
+           val=key[i];
+           DDPRINTF((" FOR LOOP, key[%d]=0x%02x, %s%s \n", i, key[i], 
bit_rep[val >> 4], bit_rep[val & 0x0F])); 
+           if(asmc_bus_write(sc, ASMC_DATAPORT_OFFSET, key[i])) 
+               return -EIO;
+           if (asmc_wait_status(sc, ASMC_STATUS_04)) 
+               return -EIO;
+       }
+       if(asmc_bus_write(sc, ASMC_DATAPORT_OFFSET, 6))
+           DPRINTF((" ** Could not GET KEY BY TYPE ... \n"));
+       for (i = 0; i < 6; i++) {
+           if (asmc_wait_status(sc, ASMC_STATUS_05)) {
+               return -EIO;
+           }
+           mtx_enter(&sc->sc_mutex);
+           type[i]=bus_space_read_1(sc->asmc_iot, sc->asmc_ioh, 
ASMC_DATAPORT_OFFSET);
+           mtx_leave(&sc->sc_mutex);
+           DPRINTF((" type[%d]=0x%02x\n", i, type[i]));
+       }
+       DPRINTF(("\n"));
+       return 0;
+}
+
+
+/******************* OpenBSD DRIVER HOOKS BEGIN HERE ************************
+ *
+ * This section implements asmc driver hooks into the kernel 
+ ****************************************************************************/
+int
+asmc_match(struct device *parent, void *match, void *aux)
+{
+       /*
+        * We read the BIOS tables for our system, and get the 
+        * vendor / product. Then we run through our asmc_models[] 
+        * structure, and try to find a matching product.
+        */
+       unsigned i;
+       char bios_string[64];           /* the BIOS model       */
+       struct smbios_sys *sbsys;
+       struct smbtable bios;
+       struct asmc_model *model;
+
+       DPRINTF(("ASMC_MATCH \n"));
+
+       if (smbios_find_table(SMBIOS_TYPE_SYSTEM, &bios)) {
+           sbsys = bios.tblhdr;
+           if ((smbios_get_string(&bios, sbsys->vendor, bios_string, 
+               sizeof(bios_string))) != NULL) 
+                       DPRINTF((" BIOS: vendor %s,", bios_string));
+           if ((smbios_get_string(&bios, sbsys->product, bios_string, 
+               sizeof(bios_string))) != NULL) 
+                       DPRINTF((" product %s\n", bios_string));
+       } else {
+           DPRINTF((" ASMC: could not find BIOS\n"));
+           return -EIO;
+       } /* end BIOS request */
+
+       /* 
+        * now run through all models and see 
+        * if there is something matching... 
+        */
+       for (i=0; asmc_models[i].asmc_model; i++) {
+           asmc_model_index = i;
+           model = &asmc_models[i];
+           if (strncmp("UNKNOWN", model->asmc_model, strlen("UNKNOWN"))) {
+               if (!strncmp(bios_string, model->asmc_model, 
strlen(bios_string))) {
+                   DPRINTF((" asmc_models[%d]=%s;", 
+                     i, model->asmc_model));
+                   DDPRINTF((" %d; %d; %d\n", 
+                     model->asmc_desc, 
+                     model->asmc_version, 
+                     model->asmc_type)); 
+                   return (1);
+               }
+           } else {
+               DPRINTF((" ** ERROR: no model found for %s\n", bios_string));
+               return -EIO;
+           }
+       } /* end for loop */
+       DPRINTF((" ** ERROR: ASMC_MATCH: shouldn't reach here ..."));
+       return -EIO;
+}
+
+
+void 
+asmc_attach(struct device *parent, struct device *self, void *aux)
+{
+       int iobase;
+
+       struct isa_attach_args *ia = aux;
+       struct asmc_softc *sc = (void *)self;
+
+       DPRINTF(("\nASMC_ATTACH\n"));
+
+       bus_space_handle_t ioh;
+       bus_space_tag_t iot = ia->ia_iot;
+       iobase = ia->ipa_io[0].base;
+       iot = sc->asmc_iot = ia->ia_iot;
+
+       DDPRINTF((" bus_space_map: iot:0x%02x, iobase:0x%02x, ASMC_ADDR_SIZE: 
0x%02x \n", iot, iobase, ASMC_ADDR_SIZE));
+       if (bus_space_map(iot, iobase, ASMC_ADDR_SIZE, 0, &sc->asmc_ioh)) {
+           DPRINTF(("asmc attach: can't map i/o space\n"));
+           return;
+       }
+       ioh = sc->asmc_ioh;
+       mtx_init(&sc->sc_mutex, IPL_BIO);
+
+       /* see if we get an answer from the chip        */
+       if (asmc_init(sc))
+           DPRINTF(("could not asmc_init correctly\n"));
+
+       bus_space_unmap(sc->asmc_iot, iobase, ASMC_ADDR_SIZE);
+       /* not sure, why this is required, but if not, the next line
+        * is collated to the asmc status line ... */
+       printf("\n");
+}
+
+
Index: dev/isa/files.isa
===================================================================
RCS file: /cvs/src/sys/dev/isa/files.isa,v
retrieving revision 1.112
diff -u -p -u -r1.112 files.isa
--- dev/isa/files.isa   5 Apr 2013 07:25:26 -0000       1.112
+++ dev/isa/files.isa   24 Jan 2014 20:24:38 -0000
@@ -350,6 +350,11 @@ device     aps
 attach aps at isa
 file   dev/isa/aps.c                   aps
 
+# Apple Macintosh SMC (System Management Controller)
+device asmc
+attach asmc at isa
+file   dev/isa/asmc.c                  asmc
+
 # ISA I/O mapped as GPIO
 device isagpio: gpiobus
 attach isagpio at isa
Index: arch/i386/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/i386/conf/GENERIC,v
retrieving revision 1.747
diff -u -p -u -r1.747 GENERIC
--- arch/i386/conf/GENERIC      1 Jun 2013 01:13:34 -0000       1.747
+++ arch/i386/conf/GENERIC      24 Jan 2014 20:24:38 -0000
@@ -152,6 +152,7 @@ uguru0      at isa? disable port 0xe0       # ABIT 
 fins0  at isa? port 0x4e               # Fintek F71805 Super I/O
 
 aps0   at isa? port 0x1600             # ThinkPad Active Protection System
+asmc0  at isa? port 0x300 irq 6        # Apple System Mgmt Controller
 
 itherm*        at pci?                         # Intel 3400 Thermal Sensor
 adc*   at iic?                         # Analog Devices AD7416/AD7417/7418
Index: arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.342
diff -u -p -u -r1.342 GENERIC
--- arch/amd64/conf/GENERIC     1 Jun 2013 01:13:33 -0000       1.342
+++ arch/amd64/conf/GENERIC     24 Jan 2014 20:24:38 -0000
@@ -103,6 +103,7 @@ lm* at wbsio?
 uguru0 at isa? disable port 0xe0       # ABIT uGuru
 
 aps0   at isa? port 0x1600             # ThinkPad Active Protection System
+asmc0  at isa? port 0x300 irq 6        # Apple System Mgmt Controller
 
 piixpm*        at pci?                 # Intel PIIX PM
 iic*   at piixpm?
       

Reply via email to