LCOV - code coverage report
Current view: top level - dev/usb - uthum.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 337 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: uthum.c,v 1.32 2017/01/09 14:44:28 mpi Exp $   */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2009, 2010 Yojiro UO <yuo@nui.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /* Driver for HID base TEMPer seriese Temperature(/Humidity) sensors */
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/kernel.h>
      24             : #include <sys/device.h>
      25             : #include <sys/conf.h>
      26             : #include <sys/sensors.h>
      27             : 
      28             : #include <dev/usb/usb.h>
      29             : #include <dev/usb/usbhid.h>
      30             : #include <dev/usb/usbdi.h>
      31             : #include <dev/usb/usbdi_util.h>
      32             : #include <dev/usb/usbdevs.h>
      33             : #include <dev/usb/uhidev.h>
      34             : 
      35             : #ifdef UTHUM_DEBUG
      36             : #define DPRINTF(x)      do { printf x; } while (0)
      37             : #else
      38             : #define DPRINTF(x)
      39             : #endif
      40             : 
      41             : /* Device types */
      42             : #define UTHUM_TYPE_TEMPERHUM    0x535a
      43             : #define UTHUM_TYPE_TEMPERHUM_2  0x575a /* alternative TEMPerHUM */
      44             : #define UTHUM_TYPE_TEMPER1      0x5758 /* TEMPer1 and HID TEMPer */
      45             : #define UTHUM_TYPE_TEMPER2      0x5759
      46             : #define UTHUM_TYPE_TEMPERNTC    0x575b
      47             : #define UTHUM_TYPE_UNKNOWN      0xffff
      48             : 
      49             : /* Common */
      50             : #define UTHUM_CAL_OFFSET        0x14
      51             : #define UTHUM_MAX_SENSORS       2
      52             : #define CMD_DEVTYPE             0x52
      53             : #define DEVTYPE_EOF             0x53
      54             : 
      55             : /* query commands */
      56             : #define CMD_GETDATA_NTC         0x41 /* TEMPerNTC NTC part */
      57             : #define CMD_RESET0              0x43 /* TEMPer, TEMPer[12], TEMPerNTC */
      58             : #define CMD_RESET1              0x44 /* TEMPer, TEMPer[12] */
      59             : #define CMD_GETDATA             0x48 /* TEMPerHUM */
      60             : #define CMD_GETDATA_OUTER       0x53 /* TEMPer, TEMPer[12], TEMPerNTC */
      61             : #define CMD_GETDATA_INNER       0x54 /* TEMPer, TEMPer[12], TEMPerNTC */
      62             : #define CMD_GETDATA_EOF         0x31
      63             : #define CMD_GETDATA_EOF2        0xaa
      64             : 
      65             : /* temperntc mode */
      66             : #define TEMPERNTC_MODE_BASE     0x61 /* 0x61 - 0x68 */
      67             : #define TEMPERNTC_MODE_MAX      0x68
      68             : #define CMD_TEMPERNTC_MODE_DONE 0x69
      69             : #define UTHUM_NTC_MIN_THRESHOLD 0xb300
      70             : #define UTHUM_NTC_MAX_THRESHOLD 0xf200
      71             : 
      72             : /* sensor name */
      73             : #define UTHUM_TEMPER_INNER      0
      74             : #define UTHUM_TEMPER_OUTER      1
      75             : #define UTHUM_TEMPER_NTC        1
      76             : #define UTHUM_TEMPERHUM_TEMP    0
      77             : #define UTHUM_TEMPERHUM_HUM     1
      78             : 
      79             : enum uthum_sensor_type {
      80             :         UTHUM_SENSOR_UNKNOWN,
      81             :         UTHUM_SENSOR_SHT1X,
      82             :         UTHUM_SENSOR_DS75,
      83             :         UTHUM_SENSOR_NTC,
      84             :         UTHUM_SENSOR_MAXTYPES,
      85             : };
      86             : 
      87             : static const char * const uthum_sensor_type_s[UTHUM_SENSOR_MAXTYPES] = {
      88             :         "unknown",
      89             :         "sht1x",
      90             :         "ds75/12bit",
      91             :         "NTC"
      92             : };
      93             : 
      94             : static uint8_t cmd_issue[8] =
      95             :         { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x02, 0x00 };
      96             : static uint8_t cmd_query[8] =
      97             :         { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x01, 0x00 };
      98             : 
      99             : struct uthum_sensor {
     100             :         struct ksensor sensor;
     101             :         int cal_offset; /* mC or m%RH */
     102             :         int attached;
     103             :         enum uthum_sensor_type dev_type;
     104             :         int cur_state;  /* for TEMPerNTC */
     105             : };
     106             : 
     107             : struct uthum_softc {
     108             :         struct uhidev            sc_hdev;
     109             :         struct usbd_device      *sc_udev;
     110             :         int                      sc_device_type;
     111             :         int                      sc_num_sensors;
     112             : 
     113             :         /* uhidev parameters */
     114             :         size_t                   sc_flen;       /* feature report length */
     115             :         size_t                   sc_ilen;       /* input report length */
     116             :         size_t                   sc_olen;       /* output report length */
     117             : 
     118             :         /* sensor framework */
     119             :         struct uthum_sensor      sc_sensor[UTHUM_MAX_SENSORS];
     120             :         struct ksensordev        sc_sensordev;
     121             :         struct sensor_task      *sc_sensortask;
     122             : };
     123             : 
     124             : const struct usb_devno uthum_devs[] = {
     125             :         /* XXX: various TEMPer variants are using same VID/PID */
     126             :         { USB_VENDOR_TENX, USB_PRODUCT_TENX_TEMPER},
     127             : };
     128             : #define uthum_lookup(v, p) usb_lookup(uthum_devs, v, p)
     129             : 
     130             : int  uthum_match(struct device *, void *, void *);
     131             : void uthum_attach(struct device *, struct device *, void *);
     132             : int  uthum_detach(struct device *, int);
     133             : 
     134             : int  uthum_issue_cmd(struct uthum_softc *, uint8_t, int);
     135             : int  uthum_read_data(struct uthum_softc *, uint8_t, uint8_t *, size_t, int);
     136             : int  uthum_check_device_info(struct uthum_softc *);
     137             : void uthum_reset_device(struct uthum_softc *);
     138             : void uthum_setup_sensors(struct uthum_softc *);
     139             : 
     140             : void uthum_intr(struct uhidev *, void *, u_int);
     141             : void uthum_refresh(void *);
     142             : void uthum_refresh_temper(struct uthum_softc *, int);
     143             : void uthum_refresh_temperhum(struct uthum_softc *);
     144             : void uthum_refresh_temperntc(struct uthum_softc *, int);
     145             : 
     146             : int  uthum_ntc_getdata(struct uthum_softc *, int *);
     147             : int  uthum_ntc_tuning(struct uthum_softc *, int, int *);
     148             : int64_t uthum_ntc_temp(int64_t, int);
     149             : int  uthum_sht1x_temp(uint8_t, uint8_t);
     150             : int  uthum_sht1x_rh(uint8_t, uint8_t, int);
     151             : int  uthum_ds75_temp(uint8_t, uint8_t);
     152             : void uthum_print_sensorinfo(struct uthum_softc *, int);
     153             : 
     154             : struct cfdriver uthum_cd = {
     155             :         NULL, "uthum", DV_DULL
     156             : };
     157             : 
     158             : const struct cfattach uthum_ca = {
     159             :         sizeof(struct uthum_softc),
     160             :         uthum_match,
     161             :         uthum_attach,
     162             :         uthum_detach
     163             : };
     164             : 
     165             : int
     166           0 : uthum_match(struct device *parent, void *match, void *aux)
     167             : {
     168           0 :         struct uhidev_attach_arg *uha = aux;
     169             : 
     170           0 :         if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID)
     171           0 :                 return (UMATCH_NONE);
     172             : 
     173           0 :         if (uthum_lookup(uha->uaa->vendor, uha->uaa->product) == NULL)
     174           0 :                 return UMATCH_NONE;
     175             : 
     176             : #if 0 /* attach only sensor part of HID as uthum* */
     177             : #define HUG_UNKNOWN_3   0x0003
     178             :         void *desc;
     179             :         int size;
     180             :         uhidev_get_report_desc(uha->parent, &desc, &size);
     181             :         if (!hid_is_collection(desc, size, uha->reportid,
     182             :             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_UNKNOWN_3)))
     183             :                 return (UMATCH_NONE);
     184             : #undef HUG_UNKNOWN_3
     185             : #endif
     186             : 
     187           0 :         return (UMATCH_VENDOR_PRODUCT);
     188           0 : }
     189             : 
     190             : void
     191           0 : uthum_attach(struct device *parent, struct device *self, void *aux)
     192             : {
     193           0 :         struct uthum_softc *sc = (struct uthum_softc *)self;
     194           0 :         struct usb_attach_arg *uaa = aux;
     195           0 :         struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
     196           0 :         struct usbd_device *dev = uha->parent->sc_udev;
     197           0 :         int i, size, repid;
     198           0 :         void *desc;
     199             : 
     200           0 :         sc->sc_udev = dev;
     201           0 :         sc->sc_hdev.sc_intr = uthum_intr;
     202           0 :         sc->sc_hdev.sc_parent = uha->parent;
     203           0 :         sc->sc_hdev.sc_report_id = uha->reportid;
     204           0 :         sc->sc_num_sensors = 0;
     205             : 
     206           0 :         uhidev_get_report_desc(uha->parent, &desc, &size);
     207           0 :         repid = uha->reportid;
     208           0 :         sc->sc_ilen = hid_report_size(desc, size, hid_input, repid);
     209           0 :         sc->sc_olen = hid_report_size(desc, size, hid_output, repid);
     210           0 :         sc->sc_flen = hid_report_size(desc, size, hid_feature, repid);
     211             : 
     212           0 :         printf("\n");
     213             : 
     214           0 :         if (sc->sc_flen < 32) {
     215             :                 /* not sensor interface, just attach */
     216           0 :                 return;
     217             :         }
     218             : 
     219             :         /* maybe unsupported device */
     220           0 :         if (uthum_check_device_info(sc) < 0) {
     221             :                 DPRINTF(("uthum: unknown device\n"));
     222           0 :                 return;
     223             :         };
     224             : 
     225             :         /* attach sensor */
     226           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname,
     227             :             sizeof(sc->sc_sensordev.xname));
     228           0 :         uthum_setup_sensors(sc);
     229             : 
     230             :         /* attach sensors */
     231           0 :         for (i = 0; i < UTHUM_MAX_SENSORS; i++) {
     232           0 :                 if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_UNKNOWN)
     233             :                         continue;
     234           0 :                 uthum_print_sensorinfo(sc, i);
     235           0 :                 sc->sc_sensor[i].sensor.flags |= SENSOR_FINVALID;
     236           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i].sensor);
     237           0 :                 sc->sc_sensor[i].attached = 1;
     238           0 :                 sc->sc_num_sensors++;
     239           0 :         }
     240             : 
     241           0 :         if (sc->sc_num_sensors > 0) {
     242             :                 /* 0.1Hz */
     243           0 :                 sc->sc_sensortask = sensor_task_register(sc, uthum_refresh, 6);
     244           0 :                 if (sc->sc_sensortask == NULL) {
     245           0 :                         printf(", unable to register update task\n");
     246           0 :                         return;
     247             :                 }
     248           0 :                 sensordev_install(&sc->sc_sensordev);
     249           0 :         }
     250             : 
     251             :         DPRINTF(("uthum_attach: complete\n"));
     252           0 : }
     253             : 
     254             : int
     255           0 : uthum_detach(struct device *self, int flags)
     256             : {
     257           0 :         struct uthum_softc *sc = (struct uthum_softc *)self;
     258             :         int i, rv = 0;
     259             : 
     260           0 :         if (sc->sc_num_sensors > 0) {
     261           0 :                 wakeup(&sc->sc_sensortask);
     262           0 :                 sensordev_deinstall(&sc->sc_sensordev);
     263           0 :                 for (i = 0; i < UTHUM_MAX_SENSORS; i++) {
     264           0 :                         if (sc->sc_sensor[i].attached)
     265           0 :                                 sensor_detach(&sc->sc_sensordev,
     266           0 :                                         &sc->sc_sensor[i].sensor);
     267             :                 }
     268           0 :                 if (sc->sc_sensortask != NULL)
     269           0 :                         sensor_task_unregister(sc->sc_sensortask);
     270             :         }
     271             : 
     272           0 :         uthum_reset_device(sc);
     273             : 
     274           0 :         return (rv);
     275             : }
     276             : 
     277             : void
     278           0 : uthum_intr(struct uhidev *addr, void *ibuf, u_int len)
     279             : {
     280             :         /* do nothing */
     281           0 : }
     282             : 
     283             : int
     284           0 : uthum_issue_cmd(struct uthum_softc *sc, uint8_t target_cmd, int delay)
     285             : {
     286           0 :         uint8_t cmdbuf[32];
     287             :         int i, actlen;
     288             : 
     289           0 :         bzero(cmdbuf, sizeof(cmdbuf));
     290           0 :         memcpy(cmdbuf, cmd_issue, sizeof(cmd_issue));
     291           0 :         actlen = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
     292           0 :             sc->sc_hdev.sc_report_id, cmdbuf, sc->sc_olen);
     293           0 :         if (actlen != sc->sc_olen)
     294           0 :                 return EIO;
     295             : 
     296           0 :         bzero(cmdbuf, sizeof(cmdbuf));
     297           0 :         cmdbuf[0] = target_cmd;
     298           0 :         actlen = uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
     299           0 :             sc->sc_hdev.sc_report_id, cmdbuf, sc->sc_olen);
     300           0 :         if (actlen != sc->sc_olen)
     301           0 :                 return EIO;
     302             : 
     303           0 :         bzero(cmdbuf, sizeof(cmdbuf));
     304           0 :         for (i = 0; i < 7; i++) {
     305           0 :                 actlen = uhidev_set_report(sc->sc_hdev.sc_parent,
     306           0 :                     UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, cmdbuf,
     307           0 :                     sc->sc_olen);
     308           0 :                 if (actlen != sc->sc_olen)
     309           0 :                         return EIO;
     310             :         }
     311             : 
     312             :         /* wait if required */
     313           0 :         if (delay > 0)
     314           0 :                 tsleep(&sc->sc_sensortask, 0, "uthum", (delay*hz+999)/1000 + 1);
     315             : 
     316           0 :         return 0;
     317           0 : }
     318             : 
     319             : int
     320           0 : uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf,
     321             :         size_t len, int delay)
     322             : {
     323           0 :         uint8_t cmdbuf[32], report[256];
     324             : 
     325             :         /* if return buffer is null, do nothing */
     326           0 :         if ((buf == NULL) || len == 0)
     327           0 :                 return 0;
     328             : 
     329           0 :         if (uthum_issue_cmd(sc, target_cmd, 50))
     330           0 :                 return 0;
     331             : 
     332           0 :         bzero(cmdbuf, sizeof(cmdbuf));
     333           0 :         memcpy(cmdbuf, cmd_query, sizeof(cmd_query));
     334           0 :         if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
     335           0 :             sc->sc_hdev.sc_report_id, cmdbuf, sc->sc_olen) != sc->sc_olen)
     336           0 :                 return EIO;
     337             : 
     338             :         /* wait if required */
     339           0 :         if (delay > 0)
     340           0 :                 tsleep(&sc->sc_sensortask, 0, "uthum", (delay*hz+999)/1000 + 1);
     341             : 
     342             :         /* get answer */
     343           0 :         if (uhidev_get_report(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT,
     344           0 :             sc->sc_hdev.sc_report_id, report, sc->sc_flen) != sc->sc_flen)
     345           0 :                 return EIO;
     346           0 :         memcpy(buf, report, len);
     347           0 :         return 0;
     348           0 : }
     349             : 
     350             : int
     351           0 : uthum_check_device_info(struct uthum_softc *sc)
     352             : {
     353           0 :         struct uthum_dev_info {
     354             :                 uint16_t dev_type;
     355             :                 uint8_t  cal[2][2];  /* calibration offsets */
     356             :                 uint8_t  footer;
     357             :                 uint8_t  padding[25];
     358             :         } dinfo;
     359             :         int val, dev_type;
     360             :         int retry = 3;
     361             : 
     362             :         /* issue query to device */
     363           0 :         while (retry) {
     364           0 :                 if (uthum_read_data(sc, CMD_DEVTYPE, (void *)&dinfo,
     365           0 :                     sizeof(struct uthum_dev_info), 0) != 0) {
     366             :                         DPRINTF(("uthum: device information query fail.\n"));
     367           0 :                         retry--;
     368           0 :                         continue;
     369             :                 }
     370           0 :                 if (dinfo.footer !=  DEVTYPE_EOF) {
     371             :                         /* it will be a bogus entry, retry. */
     372           0 :                         retry--;
     373             :                 } else
     374             :                         break;
     375             :         }
     376             : 
     377           0 :         if (retry <= 0)
     378           0 :                 return EIO;
     379             : 
     380           0 :         dev_type = betoh16(dinfo.dev_type);
     381             :         /* TEMPerHUM has 2 different device identifiers, unify them */
     382           0 :         if (dev_type == UTHUM_TYPE_TEMPERHUM_2)
     383             :                 dev_type = UTHUM_TYPE_TEMPERHUM;
     384             : 
     385             :         /* check device type and calibration offset*/
     386           0 :         switch (dev_type) {
     387             :         case UTHUM_TYPE_TEMPER2:
     388             :         case UTHUM_TYPE_TEMPERHUM:
     389             :         case UTHUM_TYPE_TEMPERNTC:
     390           0 :                 val = (dinfo.cal[1][0] - UTHUM_CAL_OFFSET) * 100;
     391           0 :                 val += dinfo.cal[1][1] * 10;
     392           0 :                 sc->sc_sensor[1].cal_offset = val;
     393             :                 /* fall down, don't break */
     394             :         case UTHUM_TYPE_TEMPER1:
     395           0 :                 val = (dinfo.cal[0][0] - UTHUM_CAL_OFFSET) * 100;
     396           0 :                 val += dinfo.cal[0][1] * 10;
     397           0 :                 sc->sc_sensor[0].cal_offset = val;
     398           0 :                 sc->sc_device_type = dev_type;
     399             :                 break;
     400             :         default:
     401           0 :                 sc->sc_device_type = UTHUM_TYPE_UNKNOWN;
     402           0 :                 printf("uthum: unknown device (devtype = 0x%.2x)\n",
     403             :                     dev_type);
     404           0 :                 return EIO;
     405             :         }
     406             : 
     407             :         /* device specific init process */
     408           0 :         switch (dev_type) {
     409             :         case UTHUM_TYPE_TEMPERHUM:
     410           0 :                 sc->sc_sensor[UTHUM_TEMPER_NTC].cur_state = 0;
     411           0 :                 break;
     412             :         };
     413             : 
     414           0 :         uthum_reset_device(sc);
     415             : 
     416           0 :         return 0;
     417           0 : };
     418             : 
     419             : void
     420           0 : uthum_reset_device(struct uthum_softc *sc)
     421             : {
     422           0 :         switch (sc->sc_device_type) {
     423             :         case UTHUM_TYPE_TEMPER1:
     424             :         case UTHUM_TYPE_TEMPERNTC:
     425           0 :                 uthum_issue_cmd(sc, CMD_RESET0, 200);
     426           0 :                 break;
     427             :         case UTHUM_TYPE_TEMPER2:
     428           0 :                 uthum_issue_cmd(sc, CMD_RESET0, 200);
     429           0 :                 uthum_issue_cmd(sc, CMD_RESET1, 200);
     430           0 :                 break;
     431             :         }
     432           0 : }
     433             : 
     434             : void
     435           0 : uthum_setup_sensors(struct uthum_softc *sc)
     436             : {
     437             :         int i;
     438             : 
     439           0 :         for (i = 0; i < UTHUM_MAX_SENSORS; i++)
     440           0 :                 sc->sc_sensor[i].dev_type = UTHUM_SENSOR_UNKNOWN;
     441             : 
     442           0 :         switch (sc->sc_device_type) {
     443             :         case UTHUM_TYPE_TEMPER2:        /* 2 temperature sensors */
     444           0 :                 sc->sc_sensor[UTHUM_TEMPER_OUTER].dev_type =
     445             :                     UTHUM_SENSOR_DS75;
     446           0 :                 sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.type =
     447             :                     SENSOR_TEMP;
     448           0 :                 strlcpy(sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.desc,
     449             :                     "outer",
     450             :                     sizeof(sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.desc));
     451             :                 /* fall down */
     452             :         case UTHUM_TYPE_TEMPER1:        /* 1 temperature sensor */
     453           0 :                 sc->sc_sensor[UTHUM_TEMPER_INNER].dev_type =
     454             :                     UTHUM_SENSOR_DS75;
     455           0 :                 sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.type =
     456             :                     SENSOR_TEMP;
     457           0 :                 strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc,
     458             :                     "inner",
     459             :                     sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc));
     460           0 :                 break;
     461             :         case UTHUM_TYPE_TEMPERHUM:
     462             :                 /* 1 temperature sensor and 1 humidity sensor */
     463           0 :                 for (i = 0; i < 2; i++)
     464           0 :                         sc->sc_sensor[i].dev_type = UTHUM_SENSOR_SHT1X;
     465           0 :                 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.type = SENSOR_TEMP;
     466           0 :                 sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.type =
     467             :                     SENSOR_HUMIDITY;
     468           0 :                 strlcpy(sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.desc,
     469             :                     "RH",
     470             :                     sizeof(sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.desc));
     471           0 :                 break;
     472             :         case UTHUM_TYPE_TEMPERNTC:
     473             :                 /* 2 temperature sensors */
     474           0 :                 for (i = 0; i < 2; i++)
     475           0 :                         sc->sc_sensor[i].sensor.type = SENSOR_TEMP;
     476           0 :                 sc->sc_sensor[UTHUM_TEMPER_INNER].dev_type =
     477             :                     UTHUM_SENSOR_DS75;
     478           0 :                 sc->sc_sensor[UTHUM_TEMPER_NTC].dev_type =
     479             :                     UTHUM_SENSOR_NTC;
     480           0 :                 strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc,
     481             :                     "inner",
     482             :                     sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc));
     483           0 :                 strlcpy(sc->sc_sensor[UTHUM_TEMPER_NTC].sensor.desc,
     484             :                     "outer/ntc",
     485             :                     sizeof(sc->sc_sensor[UTHUM_TEMPER_NTC].sensor.desc));
     486             : 
     487             :                 /* sensor state tuning */
     488           0 :                 for (i = 0; i < 4; i++)
     489           0 :                         uthum_issue_cmd(sc, TEMPERNTC_MODE_BASE, 50);
     490           0 :                 sc->sc_sensor[UTHUM_TEMPER_NTC].cur_state = TEMPERNTC_MODE_BASE;
     491           0 :                 if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC, NULL))
     492             :                         DPRINTF(("uthum: NTC sensor tuning failed\n"));
     493           0 :                 uthum_issue_cmd(sc, CMD_TEMPERNTC_MODE_DONE, 100);
     494           0 :                 break;
     495             :         default:
     496             :                 /* do nothing */
     497             :                 break;
     498             :         }
     499           0 : }
     500             : 
     501             : int
     502           0 : uthum_ntc_getdata(struct uthum_softc *sc, int *val)
     503             : {
     504           0 :         uint8_t buf[8];
     505             : 
     506           0 :         if (val == NULL)
     507           0 :                 return EIO;
     508             : 
     509             :         /* get sensor value */
     510           0 :         if (uthum_read_data(sc, CMD_GETDATA_NTC, buf, sizeof(buf), 10) != 0) {
     511             :                 DPRINTF(("uthum: data read fail\n"));
     512           0 :                 return EIO;
     513             :         }
     514             : 
     515             :         /* check data integrity */
     516           0 :         if (buf[2] !=  CMD_GETDATA_EOF2) {
     517             :                 DPRINTF(("uthum: broken ntc data 0x%.2x 0x%.2x 0x%.2x\n",
     518             :                     buf[0], buf[1], buf[2]));
     519           0 :                 return EIO;
     520             :         }
     521             : 
     522           0 :         *val = (buf[0] << 8) + buf[1];
     523           0 :         return 0;
     524           0 : }
     525             : 
     526             : int
     527           0 : uthum_ntc_tuning(struct uthum_softc *sc, int sensor, int *val)
     528             : {
     529             :         struct uthum_sensor *s;
     530           0 :         int done, state, ostate, curval;
     531             :         int retry = 3;
     532             : 
     533           0 :         s = &sc->sc_sensor[sensor];
     534           0 :         state = s->cur_state;
     535             : 
     536             :         /* get current sensor value */
     537           0 :         if (val == NULL) {
     538           0 :                 while (retry) {
     539           0 :                         if (uthum_ntc_getdata(sc, &curval)) {
     540           0 :                                 retry--;
     541           0 :                                 continue;
     542             :                         } else
     543             :                                 break;
     544             :                 }
     545           0 :                 if (retry <= 0)
     546           0 :                         return EIO;
     547             :         } else {
     548           0 :                 curval = *val;
     549             :         }
     550             : 
     551             :         /* no state change is required */
     552           0 :         if ((curval >= UTHUM_NTC_MIN_THRESHOLD) &&
     553           0 :             (curval <= UTHUM_NTC_MAX_THRESHOLD)) {
     554           0 :                 return 0;
     555             :         }
     556             : 
     557           0 :         if (((curval < UTHUM_NTC_MIN_THRESHOLD) &&
     558           0 :              (state == TEMPERNTC_MODE_MAX)) ||
     559           0 :             ((curval > UTHUM_NTC_MAX_THRESHOLD) &&
     560           0 :              (state == TEMPERNTC_MODE_BASE)))
     561           0 :                 return 0;
     562             : 
     563             :         DPRINTF(("uthum: ntc tuning start. cur state = 0x%.2x, val = 0x%.4x\n",
     564             :             state, curval));
     565             : 
     566             :         /* tuning loop */
     567             :         ostate = state;
     568             :         done = 0;
     569           0 :         while (!done) {
     570           0 :                 if (curval < UTHUM_NTC_MIN_THRESHOLD) {
     571           0 :                         if (state == TEMPERNTC_MODE_MAX)
     572           0 :                                 done++;
     573             :                         else
     574           0 :                                 state++;
     575           0 :                 } else if (curval > UTHUM_NTC_MAX_THRESHOLD) {
     576           0 :                         if (state == TEMPERNTC_MODE_BASE)
     577           0 :                                 done++;
     578             :                         else
     579           0 :                                 state--;
     580             :                 } else {
     581           0 :                         uthum_ntc_getdata(sc, &curval);
     582           0 :                         if ((curval >= UTHUM_NTC_MIN_THRESHOLD) &&
     583           0 :                             (curval <= UTHUM_NTC_MAX_THRESHOLD))
     584           0 :                                 done++;
     585             :                 }
     586             : 
     587             :                 /* update state */
     588           0 :                 if (state != ostate) {
     589           0 :                         uthum_issue_cmd(sc, state, 50);
     590           0 :                         uthum_issue_cmd(sc, state, 50);
     591           0 :                         uthum_ntc_getdata(sc, &curval);
     592           0 :                 }
     593             :                 ostate = state;
     594             :         }
     595             : 
     596             :         DPRINTF(("uthum: ntc tuning done. state change: 0x%.2x->0x%.2x\n",
     597             :             s->cur_state, state));
     598           0 :         s->cur_state = state;
     599           0 :         if (val != NULL)
     600           0 :                 *val = curval;
     601             : 
     602           0 :         return 0;
     603           0 : }
     604             : 
     605             : void
     606           0 : uthum_refresh(void *arg)
     607             : {
     608           0 :         struct uthum_softc *sc = arg;
     609             :         int i;
     610             : 
     611           0 :         switch (sc->sc_device_type) {
     612             :         case UTHUM_TYPE_TEMPER1:
     613             :         case UTHUM_TYPE_TEMPER2:
     614             :         case UTHUM_TYPE_TEMPERNTC:
     615           0 :                 for (i = 0; i < sc->sc_num_sensors; i++) {
     616           0 :                         if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_DS75)
     617           0 :                                 uthum_refresh_temper(sc, i);
     618           0 :                         else if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_NTC)
     619           0 :                                 uthum_refresh_temperntc(sc, i);
     620             :                 }
     621             :                 break;
     622             :         case UTHUM_TYPE_TEMPERHUM:
     623           0 :                 uthum_refresh_temperhum(sc);
     624           0 :                 break;
     625             :         default:
     626             :                 break;
     627             :                 /* never reach */
     628             :         }
     629           0 : }
     630             : 
     631             : void
     632           0 : uthum_refresh_temperhum(struct uthum_softc *sc)
     633             : {
     634           0 :         uint8_t buf[8];
     635             :         int temp, rh;
     636             : 
     637           0 :         if (uthum_read_data(sc, CMD_GETDATA, buf, sizeof(buf), 1000) != 0) {
     638             :                 DPRINTF(("uthum: data read fail\n"));
     639           0 :                 sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.flags
     640           0 :                     |= SENSOR_FINVALID;
     641           0 :                 sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.flags
     642           0 :                     |= SENSOR_FINVALID;
     643           0 :                 return;
     644             :         }
     645             : 
     646           0 :         temp = uthum_sht1x_temp(buf[0], buf[1]);
     647           0 :         rh = uthum_sht1x_rh(buf[2], buf[3], temp);
     648             : 
     649             :         /* apply calibration offsets */
     650           0 :         temp += sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].cal_offset;
     651           0 :         rh += sc->sc_sensor[UTHUM_TEMPERHUM_HUM].cal_offset;
     652             : 
     653           0 :         sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.value =
     654           0 :             (temp * 10000) + 273150000;
     655           0 :         sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.flags &= ~SENSOR_FINVALID;
     656           0 :         sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.value = rh;
     657           0 :         sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.flags &= ~SENSOR_FINVALID;
     658           0 : }
     659             : 
     660             : void
     661           0 : uthum_refresh_temper(struct uthum_softc *sc, int sensor)
     662             : {
     663           0 :         uint8_t buf[8];
     664             :         uint8_t cmd;
     665             :         int temp;
     666             : 
     667           0 :         if (sensor == UTHUM_TEMPER_INNER)
     668           0 :                 cmd = CMD_GETDATA_INNER;
     669           0 :         else if (sensor == UTHUM_TEMPER_OUTER)
     670             :                 cmd = CMD_GETDATA_OUTER;
     671             :         else
     672           0 :                 return;
     673             : 
     674             :         /* get sensor value */
     675           0 :         if (uthum_read_data(sc, cmd, buf, sizeof(buf), 1000) != 0) {
     676             :                 DPRINTF(("uthum: data read fail\n"));
     677           0 :                 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
     678           0 :                 return;
     679             :         }
     680             : 
     681             :         /* check integrity */
     682           0 :         if (buf[2] !=  CMD_GETDATA_EOF) {
     683             :                 DPRINTF(("uthum: broken ds75 data: 0x%.2x 0x%.2x 0x%.2x\n",
     684             :                     buf[0], buf[1], buf[2]));
     685           0 :                 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
     686           0 :                 return;
     687             :         }
     688           0 :         temp = uthum_ds75_temp(buf[0], buf[1]);
     689             : 
     690             :         /* apply calibration offset */
     691           0 :         temp += sc->sc_sensor[sensor].cal_offset;
     692             : 
     693           0 :         sc->sc_sensor[sensor].sensor.value = (temp * 10000) + 273150000;
     694           0 :         sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID;
     695           0 : }
     696             : 
     697             : void
     698           0 : uthum_refresh_temperntc(struct uthum_softc *sc, int sensor)
     699             : {
     700           0 :         int val;
     701             :         int64_t temp;
     702             : 
     703             :         /* get sensor data */
     704           0 :         if (uthum_ntc_getdata(sc, &val)) {
     705             :                 DPRINTF(("uthum: ntc data read fail\n"));
     706           0 :                 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
     707           0 :                 return;
     708             :         }
     709             : 
     710             :         /* adjust sensor state */
     711           0 :         if ((val < UTHUM_NTC_MIN_THRESHOLD) ||
     712           0 :             (val > UTHUM_NTC_MAX_THRESHOLD)) {
     713           0 :                 if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC, &val)) {
     714             :                         DPRINTF(("uthum: NTC sensor tuning failed\n"));
     715           0 :                         sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
     716           0 :                         return;
     717             :                 }
     718             :         }
     719             : 
     720           0 :         temp = uthum_ntc_temp(val, sc->sc_sensor[sensor].cur_state);
     721           0 :         if (temp == 0) {
     722             :                 /* XXX: work around. */
     723           0 :                 sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
     724           0 :         } else {
     725             :                 /* apply calibration offset */
     726           0 :                 temp += sc->sc_sensor[sensor].cal_offset * 10000;
     727           0 :                 sc->sc_sensor[sensor].sensor.value = temp;
     728           0 :                 sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID;
     729             :         }
     730           0 : }
     731             : 
     732             : /* return C-degree * 100 value */
     733             : int
     734           0 : uthum_ds75_temp(uint8_t msb, uint8_t lsb)
     735             : {
     736             :         /* DS75: 12bit precision mode : 0.0625 degrees Celsius ticks */
     737           0 :         return (msb * 100) + ((lsb >> 4) * 25 / 4);
     738             : }
     739             : 
     740             : /* return C-degree * 100 value */
     741             : int
     742           0 : uthum_sht1x_temp(uint8_t msb, uint8_t lsb)
     743             : {
     744             :         int nticks;
     745             : 
     746             :         /* sensor device VDD-bias value table
     747             :          * ----------------------------------------------
     748             :          * VDD  2.5V    3.0V    3.5V    4.0V    5.0V
     749             :          * bias -3940   -3960   -3970   -3980   -4010
     750             :          * ----------------------------------------------
     751             :          *
     752             :          * as the VDD of the SHT10 on my TEMPerHUM is 3.43V +/- 0.05V,
     753             :          * bias -3970 will be best for that device.
     754             :          */
     755             : 
     756           0 :         nticks = (msb * 256 + lsb) & 0x3fff;
     757           0 :         return (nticks - 3970);
     758             : }
     759             : 
     760             : /* return %RH * 1000 */
     761             : int
     762           0 : uthum_sht1x_rh(uint8_t msb, uint8_t lsb, int temp)
     763             : {
     764             :         int nticks, rh_l;
     765             : 
     766           0 :         nticks = (msb * 256 + lsb) & 0x0fff;
     767           0 :         rh_l = (-40000 + 405 * nticks) - ((7 * nticks * nticks) / 250);
     768             : 
     769           0 :         return ((temp - 2500) * (1 + (nticks >> 7)) + rh_l) / 10;
     770             : }
     771             : 
     772             : /* return muK */
     773             : int64_t
     774           0 : uthum_ntc_temp(int64_t val, int state)
     775             : {
     776             :         int64_t temp = 0;
     777             : 
     778           0 :         switch (state) {
     779             :         case TEMPERNTC_MODE_BASE:       /* 0x61 */
     780             :         case TEMPERNTC_MODE_BASE+1:     /* 0x62 */
     781             :         case TEMPERNTC_MODE_BASE+2:     /* 0x63 */
     782             :         case TEMPERNTC_MODE_BASE+3:     /* 0x64 */
     783             :                 /* XXX, no data */
     784             :                 temp = -273150000;
     785           0 :                 break;
     786             :         case TEMPERNTC_MODE_BASE+4:     /* 0x65 */
     787           0 :                 temp = ((val * val * 2977) / 100000) - (val * 4300) + 152450000;
     788           0 :                 break;
     789             :         case TEMPERNTC_MODE_BASE+5:     /* 0x66 */
     790           0 :                 temp = ((val * val * 3887) / 100000) - (val * 5300) + 197590000;
     791           0 :                 break;
     792             :         case TEMPERNTC_MODE_BASE+6:     /* 0x67 */
     793           0 :                 temp = ((val * val * 3495) / 100000) - (val * 5000) + 210590000;
     794           0 :                 break;
     795             :         case TEMPERNTC_MODE_BASE+7:     /* 0x68 */
     796           0 :                 if (val < UTHUM_NTC_MIN_THRESHOLD)
     797           0 :                         temp = (val * -1700) + 149630000;
     798             :                 else
     799           0 :                         temp = ((val * val * 3257) / 100000) - (val * 4900) +
     800             :                             230470000;
     801             :                 break;
     802             :         default:
     803             :                 DPRINTF(("NTC state error, unknown state 0x%.2x\n", state));
     804             :                 break;
     805             :         }
     806             : 
     807             :         /* convert muC->muK value */
     808           0 :         return temp + 273150000;
     809             : }
     810             : 
     811             : void
     812           0 : uthum_print_sensorinfo(struct uthum_softc *sc, int num)
     813             : {
     814             :         struct uthum_sensor *s;
     815           0 :         s = &sc->sc_sensor[num];
     816             : 
     817           0 :         printf("%s: ", sc->sc_hdev.sc_dev.dv_xname);
     818           0 :         switch (s->sensor.type) {
     819             :         case SENSOR_TEMP:
     820           0 :                 printf("type %s (temperature)",
     821           0 :                     uthum_sensor_type_s[s->dev_type]);
     822           0 :                 if (s->cal_offset)
     823           0 :                         printf(", calibration offset %c%d.%d degC",
     824           0 :                             (s->cal_offset < 0) ? '-' : '+',
     825           0 :                             abs(s->cal_offset / 100),
     826           0 :                             abs(s->cal_offset % 100));
     827             :                 break;
     828             :         case SENSOR_HUMIDITY:
     829           0 :                 printf("type %s (humidity)",
     830           0 :                     uthum_sensor_type_s[s->dev_type]);
     831           0 :                 if (s->cal_offset)
     832           0 :                         printf("calibration offset %c%d.%d %%RH",
     833           0 :                             (s->cal_offset < 0) ? '-' : '+',
     834           0 :                             abs(s->cal_offset / 100),
     835           0 :                             abs(s->cal_offset % 100));
     836             :                 break;
     837             :         default:
     838           0 :                 printf("unknown");
     839           0 :         }
     840           0 :         printf("\n");
     841           0 : }

Generated by: LCOV version 1.13