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

          Line data    Source code
       1             : /*      $OpenBSD: uoakrh.c,v 1.15 2017/04/08 02:57:25 deraadt Exp $   */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2012 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             : /* TORADEX OAK seriese sensors: Temperature/Humidity sensor driver */
      20             : /* http://developer.toradex.com/files/toradex-dev/uploads/media/Oak/Oak_ProgrammingGuide.pdf */
      21             : 
      22             : #include <sys/param.h>
      23             : #include <sys/systm.h>
      24             : #include <sys/kernel.h>
      25             : #include <sys/malloc.h>
      26             : #include <sys/device.h>
      27             : #include <sys/conf.h>
      28             : #include <sys/sensors.h>
      29             : 
      30             : #include <dev/usb/usb.h>
      31             : #include <dev/usb/usbhid.h>
      32             : #include <dev/usb/usbdi.h>
      33             : #include <dev/usb/usbdevs.h>
      34             : #include <dev/usb/uhidev.h>
      35             : 
      36             : #include "uoak.h"
      37             : 
      38             : #ifdef OARKRH_DEBUG
      39             : int     uoakrhdebug = 0;
      40             : #define DPRINTFN(n, x)  do { if (uoakrhdebug > (n)) printf x; } while (0)
      41             : #else
      42             : #define DPRINTFN(n, x)
      43             : #endif
      44             : 
      45             : #define DPRINTF(x) DPRINTFN(0, x)
      46             : 
      47             : #define UOAKRH_SAMPLE_RATE      200     /* ms */
      48             : #define UOAKRH_REFRESH_PERIOD   10      /* 10 sec : 0.1Hz */
      49             : 
      50             : struct uoakrh_sensor {
      51             :         struct ksensor   temp;
      52             :         struct ksensor   humi;
      53             :         int count;
      54             :         int tempval, humival;
      55             :         int resolution;
      56             : };
      57             : 
      58             : struct uoakrh_softc {
      59             :         struct uhidev            sc_hdev;
      60             : 
      61             :         /* uoak common */
      62             :         struct uoak_softc        sc_uoak_softc;
      63             : 
      64             :         /* sensor framework */
      65             :         struct uoakrh_sensor     sc_sensor;
      66             :         struct ksensordev        sc_sensordev;
      67             :         struct sensor_task      *sc_sensortask;
      68             : 
      69             :         /* sensor setting */
      70             :         int                      sc_rh_heater;
      71             : };
      72             : 
      73             : const struct usb_devno uoakrh_devs[] = {
      74             :         { USB_VENDOR_TORADEX, USB_PRODUCT_TORADEX_RH},
      75             : };
      76             : #define uoakrh_lookup(v, p) usb_lookup(uoakrh_devs, v, p)
      77             : 
      78             : int  uoakrh_match(struct device *, void *, void *);
      79             : void uoakrh_attach(struct device *, struct device *, void *);
      80             : int  uoakrh_detach(struct device *, int);
      81             : 
      82             : void uoakrh_intr(struct uhidev *, void *, u_int);
      83             : void uoakrh_refresh(void *);
      84             : 
      85             : int uoakrh_get_sensor_setting(struct uoakrh_softc *, enum uoak_target);
      86             : 
      87             : void uoakrh_dev_setting(void *, enum uoak_target);
      88             : void uoakrh_dev_print(void *, enum uoak_target);
      89             : 
      90             : 
      91             : struct cfdriver uoakrh_cd = {
      92             :         NULL, "uoakrh", DV_DULL
      93             : };
      94             : 
      95             : const struct cfattach uoakrh_ca = {
      96             :         sizeof(struct uoakrh_softc),
      97             :         uoakrh_match,
      98             :         uoakrh_attach,
      99             :         uoakrh_detach,
     100             : };
     101             : 
     102             : struct uoak_methods uoakrh_methods = {
     103             :         uoakrh_dev_print,
     104             :         uoakrh_dev_setting
     105             : };
     106             : 
     107             : 
     108             : int
     109           0 : uoakrh_match(struct device *parent, void *match, void *aux)
     110             : {
     111           0 :         struct uhidev_attach_arg *uha = aux;
     112             : 
     113           0 :         if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID)
     114           0 :                 return (UMATCH_NONE);
     115             : 
     116           0 :         if (uoakrh_lookup(uha->uaa->vendor, uha->uaa->product) == NULL)
     117           0 :                 return UMATCH_NONE;
     118             : 
     119           0 :         return (UMATCH_VENDOR_PRODUCT);
     120           0 : }
     121             : 
     122             : void
     123           0 : uoakrh_attach(struct device *parent, struct device *self, void *aux)
     124             : {
     125           0 :         struct uoakrh_softc *sc = (struct uoakrh_softc *)self;
     126           0 :         struct usb_attach_arg *uaa = aux;
     127           0 :         struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
     128           0 :         struct usbd_device *dev = uha->parent->sc_udev;
     129             : 
     130           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     131           0 :         int err, size, repid;
     132           0 :         void *desc;
     133             : 
     134           0 :         sc->sc_hdev.sc_intr = uoakrh_intr;
     135           0 :         sc->sc_hdev.sc_parent = uha->parent;
     136           0 :         sc->sc_hdev.sc_report_id = uha->reportid;
     137             : 
     138           0 :         scc->sc_parent = sc;
     139           0 :         scc->sc_udev = dev;
     140           0 :         scc->sc_hdev = &sc->sc_hdev;
     141           0 :         scc->sc_methods = &uoakrh_methods;
     142           0 :         scc->sc_sensordev = &sc->sc_sensordev;
     143             : 
     144           0 :         uhidev_get_report_desc(uha->parent, &desc, &size);
     145           0 :         repid = uha->reportid;
     146           0 :         scc->sc_ilen = hid_report_size(desc, size, hid_input, repid);
     147           0 :         scc->sc_olen = hid_report_size(desc, size, hid_output, repid);
     148           0 :         scc->sc_flen = hid_report_size(desc, size, hid_feature, repid);
     149             : 
     150             :         /* device initialize */
     151           0 :         (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON);
     152           0 :         err = uoak_set_sample_rate(scc, OAK_TARGET_RAM, UOAKRH_SAMPLE_RATE);
     153           0 :         if (err) {
     154           0 :                 printf("%s: could not set sampling rate. exit\n",
     155           0 :                     sc->sc_hdev.sc_dev.dv_xname);
     156           0 :                 return;
     157             :         }
     158             : 
     159             :         /* query and print device setting */
     160           0 :         uoak_get_devinfo(scc);
     161           0 :         uoak_print_devinfo(scc);
     162             : 
     163             :         DPRINTF((" config in RAM\n"));
     164           0 :         uoak_get_setting(scc, OAK_TARGET_RAM);
     165           0 :         uoak_print_setting(scc, OAK_TARGET_RAM);
     166             : #ifdef UOAKV_DEBUG
     167             :         DPRINTF((" config in FLASH\n"));
     168             :         uoak_get_setting(scc, OAK_TARGET_FLASH);
     169             :         uoak_print_setting(scc, OAK_TARGET_FLASH);
     170             : #endif
     171             : 
     172             :         /* attach sensor */
     173           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname,
     174             :             sizeof(sc->sc_sensordev.xname));
     175           0 :         sc->sc_sensor.temp.type = SENSOR_TEMP;
     176           0 :         sc->sc_sensor.humi.type = SENSOR_HUMIDITY;
     177           0 :         sc->sc_sensor.temp.flags |= SENSOR_FINVALID;
     178           0 :         sc->sc_sensor.humi.flags |= SENSOR_FINVALID;
     179             : 
     180             :         /* add label with sensor serial# */
     181           0 :         (void)snprintf(sc->sc_sensor.temp.desc, sizeof(sc->sc_sensor.temp.desc),
     182           0 :             "Temp.(#%s)", scc->sc_udi.udi_serial);
     183           0 :         (void)snprintf(sc->sc_sensor.humi.desc, sizeof(sc->sc_sensor.humi.desc),
     184             :             "%%RH(#%s)", scc->sc_udi.udi_serial);
     185           0 :         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor.temp);
     186           0 :         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor.humi);
     187             : 
     188             :         /* start sensor */
     189           0 :         sc->sc_sensortask = sensor_task_register(sc, uoakrh_refresh, 
     190             :             UOAKRH_REFRESH_PERIOD);
     191           0 :         if (sc->sc_sensortask == NULL) {
     192           0 :                 printf(", unable to register update task\n");
     193           0 :                 return;
     194             :         }
     195           0 :         sensordev_install(&sc->sc_sensordev);
     196             : 
     197           0 :         err = uhidev_open(&sc->sc_hdev);
     198           0 :         if (err) {
     199           0 :                 printf("%s: could not open interrupt pipe, quit\n",
     200             :                     sc->sc_hdev.sc_dev.dv_xname);
     201           0 :                 return;
     202             :         }
     203           0 :         scc->sc_ibuf = malloc(scc->sc_ilen, M_USBDEV, M_WAITOK);
     204             : 
     205             :         DPRINTF(("uoakrh_attach: complete\n"));
     206           0 : }
     207             : 
     208             : int
     209           0 : uoakrh_detach(struct device *self, int flags)
     210             : {
     211           0 :         struct uoakrh_softc *sc = (struct uoakrh_softc *)self;
     212           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     213             :         int rv = 0;
     214             : 
     215           0 :         wakeup(&sc->sc_sensortask);
     216           0 :         sensordev_deinstall(&sc->sc_sensordev);
     217             : 
     218           0 :         sensor_detach(&sc->sc_sensordev, &sc->sc_sensor.temp);
     219           0 :         sensor_detach(&sc->sc_sensordev, &sc->sc_sensor.humi);
     220             : 
     221           0 :         if (sc->sc_sensortask != NULL)
     222           0 :                 sensor_task_unregister(sc->sc_sensortask);
     223             : 
     224           0 :         if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
     225           0 :                 uhidev_close(&sc->sc_hdev);
     226             : 
     227           0 :         if (scc->sc_ibuf != NULL) {
     228           0 :                 free(scc->sc_ibuf, M_USBDEV, scc->sc_ilen);
     229           0 :                 scc->sc_ibuf = NULL;
     230           0 :         }
     231             : 
     232           0 :         return (rv);
     233             : }
     234             : 
     235             : void
     236           0 : uoakrh_intr(struct uhidev *addr, void *ibuf, u_int len)
     237             : {
     238           0 :         struct uoakrh_softc *sc = (struct uoakrh_softc *)addr;
     239           0 :         struct uoakrh_sensor *s = &sc->sc_sensor;
     240           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     241             :         int frame, temp, humi;
     242             : 
     243           0 :         if (scc->sc_ibuf == NULL)
     244           0 :                 return;
     245             : 
     246           0 :         memcpy(scc->sc_ibuf, ibuf, len);
     247           0 :         frame = (scc->sc_ibuf[1] << 8) + (scc->sc_ibuf[0]);
     248           0 :         humi  = (scc->sc_ibuf[3] << 8) + (scc->sc_ibuf[2]);
     249           0 :         temp  = (scc->sc_ibuf[5] << 8) + (scc->sc_ibuf[4]);
     250             : 
     251           0 :         if (s->count == 0) { 
     252           0 :                 s->tempval = temp;
     253           0 :                 s->humival = humi;
     254           0 :         }
     255             : 
     256             :         /* calculate average value */
     257           0 :         s->tempval = (s->tempval * s->count + temp) / (s->count + 1);
     258           0 :         s->humival = (s->humival * s->count + humi) / (s->count + 1);
     259             : 
     260           0 :         s->count++;
     261           0 : }
     262             : 
     263             : void
     264           0 : uoakrh_refresh(void *arg)
     265             : {
     266           0 :         struct uoakrh_softc *sc = arg;
     267           0 :         struct uoakrh_sensor *s = &sc->sc_sensor;
     268           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     269           0 :         uint8_t led;
     270             : 
     271             :         /* blink LED for each cycle */
     272           0 :         if (uoak_led_status(scc, OAK_TARGET_RAM, &led) < 0)
     273             :                 DPRINTF(("status query error\n"));
     274           0 :         if (led == OAK_LED_OFF) 
     275           0 :                 (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON);
     276             :         else 
     277           0 :                 (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_OFF);
     278             : 
     279             :         /* update sensor value */
     280           0 :         s->temp.value = (uint64_t)(s->tempval) * 10000;
     281           0 :         s->humi.value = (uint64_t)(s->humival) * 10;
     282           0 :         s->temp.flags &= ~SENSOR_FINVALID;
     283           0 :         s->humi.flags &= ~SENSOR_FINVALID;
     284           0 :         s->count = 0;
     285           0 : }
     286             : 
     287             : 
     288             : int
     289           0 : uoakrh_get_sensor_setting(struct uoakrh_softc *sc, enum uoak_target target)
     290             : {
     291             :         uint8_t result;
     292           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     293             : 
     294           0 :         memset(&scc->sc_rcmd, 0, sizeof(struct uoak_rcmd));
     295           0 :         scc->sc_rcmd.target = target;
     296           0 :         scc->sc_rcmd.datasize = 0x1;
     297           0 :         USETW(&scc->sc_rcmd.cmd, OAK_CMD_SENSORSETTING);
     298             : 
     299           0 :         if (uoak_get_cmd(scc) < 0)
     300           0 :                 return EIO;
     301             : 
     302           0 :         result =  scc->sc_buf[1];
     303           0 :         sc->sc_sensor.resolution = (result & OAK_RH_SENSOR_RES_MASK);
     304           0 :         sc->sc_rh_heater = (result & OAK_RH_SENSOR_HEATER_MASK) >> 2;
     305             : 
     306           0 :         return 0;
     307           0 : }
     308             : 
     309             : /* device specific functions */
     310             : void
     311           0 : uoakrh_dev_setting(void *parent, enum uoak_target target)
     312             : {
     313           0 :         struct uoakrh_softc *sc = (struct uoakrh_softc *)parent;
     314             : 
     315             :         /* get device specific configuration */
     316           0 :         (void)uoakrh_get_sensor_setting(sc, target);
     317           0 : }
     318             : 
     319             : void
     320           0 : uoakrh_dev_print(void *parent, enum uoak_target target)
     321             : {
     322           0 :         struct uoakrh_softc *sc = (struct uoakrh_softc *)parent;
     323             : 
     324           0 :         printf(", %s",
     325           0 :             (sc->sc_sensor.resolution ? "8bit RH/12 bit" : "12bit RH/14bit"));
     326           0 :         printf(", heater %s", (sc->sc_rh_heater ? "ON" : "OFF"));
     327           0 : }

Generated by: LCOV version 1.13