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

          Line data    Source code
       1             : /*      $OpenBSD: uoakv.c,v 1.13 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: 8channel +/-10V ADC 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 UOAKV_DEBUG
      39             : int     uoakvdebug = 0;
      40             : #define DPRINTFN(n, x)  do { if (uoakvdebug > (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 UOAKV_SAMPLE_RATE       100     /* ms */
      48             : #define UOAKV_REFRESH_PERIOD    1       /* 1 sec : 1Hz */
      49             : 
      50             : struct uoakv_sensor {
      51             :         struct uoak_sensor v;
      52             :         /* ADC setting */
      53             :         unsigned int offset[OAK_V_TARGET_MAX];  /* absolute offset (mV) */
      54             : };
      55             : 
      56             : struct uoakv_softc {
      57             :         struct uhidev            sc_hdev;
      58             : 
      59             :         /* uoak common */
      60             :         struct uoak_softc        sc_uoak_softc;
      61             : 
      62             :         /* sensor framework */
      63             :         struct uoakv_sensor      sc_sensor[OAK_V_MAXSENSORS];
      64             :         struct ksensordev        sc_sensordev;
      65             :         struct sensor_task      *sc_sensortask;
      66             : 
      67             :         /* sensor setting */
      68             :         int                      sc_inputmode[OAK_V_TARGET_MAX];
      69             : 
      70             : };
      71             : 
      72             : const struct usb_devno uoakv_devs[] = {
      73             :         { USB_VENDOR_TORADEX, USB_PRODUCT_TORADEX_10V},
      74             : };
      75             : #define uoakv_lookup(v, p) usb_lookup(uoakv_devs, v, p)
      76             : 
      77             : int  uoakv_match(struct device *, void *, void *);
      78             : void uoakv_attach(struct device *, struct device *, void *);
      79             : int  uoakv_detach(struct device *, int);
      80             : 
      81             : void uoakv_intr(struct uhidev *, void *, u_int);
      82             : void uoakv_refresh(void *);
      83             : 
      84             : int uoakv_get_channel_setting(struct uoakv_softc *, enum uoak_target, int);
      85             : int uoakv_get_sensor_setting(struct uoakv_softc *, enum uoak_target);
      86             : 
      87             : void uoakv_dev_setting(void *, enum uoak_target);
      88             : void uoakv_dev_print(void *, enum uoak_target);
      89             : 
      90             : 
      91             : struct cfdriver uoakv_cd = {
      92             :         NULL, "uoakv", DV_DULL
      93             : };
      94             : 
      95             : const struct cfattach uoakv_ca = {
      96             :         sizeof(struct uoakv_softc),
      97             :         uoakv_match,
      98             :         uoakv_attach,
      99             :         uoakv_detach,
     100             : 
     101             : };
     102             : 
     103             : struct uoak_methods uoakv_methods = {
     104             :         uoakv_dev_print,
     105             :         uoakv_dev_setting
     106             : };
     107             : 
     108             : int
     109           0 : uoakv_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 (uoakv_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 : uoakv_attach(struct device *parent, struct device *self, void *aux)
     124             : {
     125           0 :         struct uoakv_softc *sc = (struct uoakv_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 i, err, size, repid;
     132           0 :         void *desc;
     133             : 
     134           0 :         sc->sc_hdev.sc_intr = uoakv_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 = &uoakv_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, UOAKV_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 FRASH\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 :         for (i = 0; i < OAK_V_MAXSENSORS; i++)
     176           0 :                 uoak_sensor_attach(scc, &sc->sc_sensor[i].v, SENSOR_VOLTS_DC);
     177             : 
     178             :         /* start sensor */
     179           0 :         sc->sc_sensortask = sensor_task_register(sc, uoakv_refresh,
     180             :             UOAKV_REFRESH_PERIOD);
     181           0 :         if (sc->sc_sensortask == NULL) {
     182           0 :                 printf(", unable to register update task\n");
     183           0 :                 return;
     184             :         }
     185           0 :         sensordev_install(&sc->sc_sensordev);
     186             : 
     187           0 :         err = uhidev_open(&sc->sc_hdev);
     188           0 :         if (err) {
     189           0 :                 printf("%s: could not open interrupt pipe, quit\n",
     190             :                     sc->sc_hdev.sc_dev.dv_xname);
     191           0 :                 return;
     192             :         }
     193           0 :         scc->sc_ibuf = malloc(scc->sc_ilen, M_USBDEV, M_WAITOK);
     194             : 
     195             :         DPRINTF(("uoakv_attach: complete\n"));
     196           0 : }
     197             : 
     198             : int
     199           0 : uoakv_detach(struct device *self, int flags)
     200             : {
     201           0 :         struct uoakv_softc *sc = (struct uoakv_softc *)self;
     202           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     203             :         int i, rv = 0;
     204             : 
     205           0 :         wakeup(&sc->sc_sensortask);
     206           0 :         sensordev_deinstall(&sc->sc_sensordev);
     207             : 
     208           0 :         for (i = 0; i < OAK_V_MAXSENSORS; i++)
     209           0 :                 uoak_sensor_detach(scc, &sc->sc_sensor[i].v);
     210             : 
     211           0 :         if (sc->sc_sensortask != NULL)
     212           0 :                 sensor_task_unregister(sc->sc_sensortask);
     213             : 
     214           0 :         if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
     215           0 :                 uhidev_close(&sc->sc_hdev);
     216             : 
     217           0 :         if (scc->sc_ibuf != NULL) {
     218           0 :                 free(scc->sc_ibuf, M_USBDEV, scc->sc_ilen);
     219           0 :                 scc->sc_ibuf = NULL;
     220           0 :         }
     221             : 
     222           0 :         return (rv);
     223             : }
     224             : 
     225             : void
     226           0 : uoakv_intr(struct uhidev *addr, void *ibuf, u_int len)
     227             : {
     228           0 :         struct uoakv_softc *sc = (struct uoakv_softc *)addr;
     229           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     230             :         int i, idx, frame;
     231             :         int16_t val;
     232             : 
     233           0 :         if (scc->sc_ibuf == NULL)
     234           0 :                 return;
     235             : 
     236           0 :         memcpy(scc->sc_ibuf, ibuf, len);
     237           0 :         frame = (scc->sc_ibuf[1] << 8) + scc->sc_ibuf[0];
     238             : 
     239           0 :         for (i = 0; i < OAK_V_MAXSENSORS; i++) {
     240           0 :                 idx = (i + 1) * 2;
     241           0 :                 val = (int16_t)((scc->sc_ibuf[idx+1] << 8) | scc->sc_ibuf[idx]);
     242           0 :                 uoak_sensor_update(&sc->sc_sensor[i].v, val);
     243             :         }
     244           0 : }
     245             : 
     246             : void
     247           0 : uoakv_refresh(void *arg)
     248             : {
     249           0 :         struct uoakv_softc *sc = arg;
     250           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     251           0 :         uint8_t led;
     252             :         int i;
     253             : 
     254             :         /* blink LED for each cycle */
     255           0 :         if (uoak_led_status(scc, OAK_TARGET_RAM, &led) < 0)
     256             :                 DPRINTF(("status query error\n"));
     257           0 :         if (led == OAK_LED_OFF)
     258           0 :                 (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON);
     259             :         else
     260           0 :                 (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_OFF);
     261             : 
     262           0 :         for (i = 0; i < OAK_V_MAXSENSORS; i++)
     263           0 :                 uoak_sensor_refresh(&sc->sc_sensor[i].v, 1000, 0);
     264           0 : }
     265             : 
     266             : int
     267           0 : uoakv_get_channel_setting(struct uoakv_softc *sc, enum uoak_target target,
     268             :   int ch)
     269             : {
     270           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     271             :         uint16_t cmd, result;
     272             : 
     273           0 :         memset(&scc->sc_rcmd, 0, sizeof(struct uoak_rcmd));
     274           0 :         scc->sc_rcmd.target = target;
     275           0 :         scc->sc_rcmd.datasize = 0x2;
     276             : 
     277             : #define OAK_V_CHANNEL_IDX_OFFSET 3
     278           0 :         cmd = (ch + OAK_V_CHANNEL_IDX_OFFSET);
     279           0 :         USETW(&scc->sc_rcmd.cmd, cmd);
     280             : 
     281           0 :         if (uoak_get_cmd(scc) < 0)
     282           0 :                 return EIO;
     283             : 
     284           0 :         result = (scc->sc_buf[2] << 8) + scc->sc_buf[1];
     285           0 :         sc->sc_sensor[ch].offset[target] = result;
     286             : 
     287           0 :         return 0;
     288           0 : }
     289             : 
     290             : int
     291           0 : uoakv_get_sensor_setting(struct uoakv_softc *sc, enum uoak_target target)
     292             : {
     293           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     294             :         uint8_t result;
     295             : 
     296           0 :         memset(&scc->sc_rcmd, 0, sizeof(struct uoak_rcmd));
     297           0 :         scc->sc_rcmd.target = target;
     298           0 :         scc->sc_rcmd.datasize = 0x1;
     299           0 :         USETW(&scc->sc_rcmd.cmd, OAK_CMD_SENSORSETTING);
     300             : 
     301           0 :         if (uoak_get_cmd(scc) < 0)
     302           0 :                 return EIO;
     303             : 
     304           0 :         result =  scc->sc_buf[1];
     305           0 :         sc->sc_inputmode[target] = (result & OAK_V_SENSOR_INPUTMODEMASK);
     306             : 
     307           0 :         return 0;
     308           0 : }
     309             : 
     310             : /* device specific functions */
     311             : void
     312           0 : uoakv_dev_setting(void *parent, enum uoak_target target)
     313             : {
     314           0 :         struct uoakv_softc *sc = (struct uoakv_softc *)parent;
     315             :         int i;
     316             : 
     317             :         /* get device specific configuration */
     318           0 :         (void)uoakv_get_sensor_setting(sc, target);
     319           0 :         for (i = 0; i < OAK_V_MAXSENSORS; i++)
     320           0 :                 (void)uoakv_get_channel_setting(sc, target, i);
     321           0 : }
     322             : 
     323             : void
     324           0 : uoakv_dev_print(void *parent, enum uoak_target target)
     325             : {
     326           0 :         struct uoakv_softc *sc = (struct uoakv_softc *)parent;
     327             :         int i;
     328             : 
     329           0 :         printf(", %s",
     330           0 :             (sc->sc_inputmode[target] ? "Psuedo-Diffential" : "Single-Ended"));
     331             : 
     332           0 :         printf(", ADC channel offsets:\n");
     333           0 :         printf("%s: ", sc->sc_hdev.sc_dev.dv_xname);
     334           0 :         for (i = 0; i < OAK_V_MAXSENSORS; i++)
     335           0 :                 printf("ch%02d %2d.%02d, ", i,
     336           0 :                     sc->sc_sensor[i].offset[target] / 100,
     337           0 :                     sc->sc_sensor[i].offset[target] % 100);
     338           0 : }

Generated by: LCOV version 1.13