LCOV - code coverage report
Current view: top level - dev/usb - uoaklux.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 118 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: uoaklux.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: lux 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 UOAKLUX_DEBUG
      39             : int     uoakluxdebug = 0;
      40             : #define DPRINTFN(n, x)  do { if (uoakluxdebug > (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 UOAKLUX_SAMPLE_RATE     200     /* ms */
      48             : #define UOAKLUX_REFRESH_PERIOD  5       /* 5 sec : 0.2Hz */
      49             : 
      50             : struct uoaklux_sensor {
      51             :         struct uoak_sensor lux;
      52             :         /* lux sensor setting */
      53             :         uint8_t          gain;
      54             :         int              inttime;
      55             : 
      56             : };
      57             : 
      58             : struct uoaklux_softc {
      59             :         struct uhidev            sc_hdev;
      60             : 
      61             :         /* uoak common */
      62             :         struct uoak_softc        sc_uoak_softc;
      63             : 
      64             :         /* sensor framework */
      65             :         struct uoaklux_sensor    sc_sensor;
      66             :         struct ksensordev        sc_sensordev;
      67             :         struct sensor_task      *sc_sensortask;
      68             : };
      69             : 
      70             : const struct usb_devno uoaklux_devs[] = {
      71             :         { USB_VENDOR_TORADEX, USB_PRODUCT_TORADEX_LUX},
      72             : };
      73             : #define uoaklux_lookup(v, p) usb_lookup(uoaklux_devs, v, p)
      74             : 
      75             : int  uoaklux_match(struct device *, void *, void *);
      76             : void uoaklux_attach(struct device *, struct device *, void *);
      77             : int  uoaklux_detach(struct device *, int);
      78             : 
      79             : void uoaklux_intr(struct uhidev *, void *, u_int);
      80             : void uoaklux_refresh(void *);
      81             : 
      82             : int uoaklux_get_sensor_setting(struct uoaklux_softc *, enum uoak_target);
      83             : 
      84             : void uoaklux_dev_setting(void *, enum uoak_target);
      85             : void uoaklux_dev_print(void *, enum uoak_target);
      86             : 
      87             : 
      88             : struct cfdriver uoaklux_cd = {
      89             :         NULL, "uoaklux", DV_DULL
      90             : };
      91             : 
      92             : const struct cfattach uoaklux_ca = {
      93             :         sizeof(struct uoaklux_softc),
      94             :         uoaklux_match,
      95             :         uoaklux_attach,
      96             :         uoaklux_detach,
      97             : };
      98             : 
      99             : struct uoak_methods uoaklux_methods = {
     100             :         uoaklux_dev_print,
     101             :         uoaklux_dev_setting
     102             : };
     103             : 
     104             : 
     105             : int
     106           0 : uoaklux_match(struct device *parent, void *match, void *aux)
     107             : {
     108           0 :         struct uhidev_attach_arg *uha = aux;
     109             : 
     110           0 :         if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID)
     111           0 :                 return (UMATCH_NONE);
     112             : 
     113           0 :         if (uoaklux_lookup(uha->uaa->vendor, uha->uaa->product) == NULL)
     114           0 :                 return UMATCH_NONE;
     115             : 
     116           0 :         return (UMATCH_VENDOR_PRODUCT);
     117           0 : }
     118             : 
     119             : void
     120           0 : uoaklux_attach(struct device *parent, struct device *self, void *aux)
     121             : {
     122           0 :         struct uoaklux_softc *sc = (struct uoaklux_softc *)self;
     123           0 :         struct usb_attach_arg *uaa = aux;
     124           0 :         struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
     125           0 :         struct usbd_device *dev = uha->parent->sc_udev;
     126             : 
     127           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     128           0 :         int err, size, repid;
     129           0 :         void *desc;
     130             : 
     131           0 :         sc->sc_hdev.sc_intr = uoaklux_intr;
     132           0 :         sc->sc_hdev.sc_parent = uha->parent;
     133           0 :         sc->sc_hdev.sc_report_id = uha->reportid;
     134             : 
     135           0 :         scc->sc_parent = sc;
     136           0 :         scc->sc_udev = dev;
     137           0 :         scc->sc_hdev = &sc->sc_hdev;
     138           0 :         scc->sc_methods = &uoaklux_methods;
     139           0 :         scc->sc_sensordev = &sc->sc_sensordev;
     140             : 
     141           0 :         uhidev_get_report_desc(uha->parent, &desc, &size);
     142           0 :         repid = uha->reportid;
     143           0 :         scc->sc_ilen = hid_report_size(desc, size, hid_input, repid);
     144           0 :         scc->sc_olen = hid_report_size(desc, size, hid_output, repid);
     145           0 :         scc->sc_flen = hid_report_size(desc, size, hid_feature, repid);
     146             : 
     147             :         /*device initialize */
     148           0 :         (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON);
     149           0 :         err = uoak_set_sample_rate(scc, OAK_TARGET_RAM, UOAKLUX_SAMPLE_RATE);
     150           0 :         if (err) {
     151           0 :                 printf("%s: could not set sampling rate. exit\n",
     152           0 :                     sc->sc_hdev.sc_dev.dv_xname);
     153           0 :                 return;
     154             :         }
     155             : 
     156             :         /* query and print device setting */
     157           0 :         uoak_get_devinfo(scc);
     158           0 :         uoak_print_devinfo(scc);
     159             : 
     160             :         DPRINTF((" config in RAM\n"));
     161           0 :         uoak_get_setting(scc, OAK_TARGET_RAM);
     162           0 :         uoak_print_setting(scc, OAK_TARGET_RAM);
     163             : #ifdef UOAKLUX_DEBUG
     164             :         DPRINTF((" config in FLASh\n"));
     165             :         uoak_get_setting(scc, OAK_TARGET_FLASH);
     166             :         uoak_print_setting(scc, OAK_TARGET_FLASH);
     167             : #endif
     168             : 
     169             :         /* attach sensor */
     170           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname,
     171             :             sizeof(sc->sc_sensordev.xname));
     172           0 :         uoak_sensor_attach(scc, &sc->sc_sensor.lux, SENSOR_LUX);
     173             : 
     174             :         /* start sensor */
     175           0 :         sc->sc_sensortask = sensor_task_register(sc, uoaklux_refresh, 
     176             :             UOAKLUX_REFRESH_PERIOD);
     177           0 :         if (sc->sc_sensortask == NULL) {
     178           0 :                 printf(", unable to register update task\n");
     179           0 :                 return;
     180             :         }
     181           0 :         sensordev_install(&sc->sc_sensordev);
     182             : 
     183           0 :         err = uhidev_open(&sc->sc_hdev);
     184           0 :         if (err) {
     185           0 :                 printf("%s: could not open interrupt pipe, quit\n",
     186             :                     sc->sc_hdev.sc_dev.dv_xname);
     187           0 :                 return;
     188             :         }
     189           0 :         scc->sc_ibuf = malloc(scc->sc_ilen, M_USBDEV, M_WAITOK);
     190             : 
     191             :         DPRINTF(("uoaklux_attach: complete\n"));
     192           0 : }
     193             : 
     194             : 
     195             : int
     196           0 : uoaklux_detach(struct device *self, int flags)
     197             : {
     198           0 :         struct uoaklux_softc *sc = (struct uoaklux_softc *)self;
     199           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     200             :         int rv = 0;
     201             : 
     202           0 :         wakeup(&sc->sc_sensortask);
     203           0 :         sensordev_deinstall(&sc->sc_sensordev);
     204             : 
     205           0 :         uoak_sensor_detach(scc, &sc->sc_sensor.lux);
     206             : 
     207           0 :         if (sc->sc_sensortask != NULL)
     208           0 :                 sensor_task_unregister(sc->sc_sensortask);
     209             : 
     210           0 :         if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
     211           0 :                 uhidev_close(&sc->sc_hdev);
     212             : 
     213           0 :         if (scc->sc_ibuf != NULL) {
     214           0 :                 free(scc->sc_ibuf, M_USBDEV, scc->sc_ilen);
     215           0 :                 scc->sc_ibuf = NULL;
     216           0 :         }
     217             : 
     218           0 :         return (rv);
     219             : }
     220             : 
     221             : void
     222           0 : uoaklux_intr(struct uhidev *addr, void *ibuf, u_int len)
     223             : {
     224           0 :         struct uoaklux_softc *sc = (struct uoaklux_softc *)addr;
     225           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     226             :         int frame, val;
     227             : 
     228           0 :         if (scc->sc_ibuf == NULL)
     229           0 :                 return;
     230             : 
     231           0 :         memcpy(scc->sc_ibuf, ibuf, len);
     232           0 :         frame = (scc->sc_ibuf[1] << 8) + (scc->sc_ibuf[0]);
     233           0 :         val = (scc->sc_ibuf[3] << 8) + (scc->sc_ibuf[2]);
     234           0 :         uoak_sensor_update(&sc->sc_sensor.lux, val);
     235           0 : }
     236             : 
     237             : void
     238           0 : uoaklux_refresh(void *arg)
     239             : {
     240           0 :         struct uoaklux_softc *sc = arg;
     241           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     242           0 :         uint8_t led;
     243             : 
     244             :         /* blink LED for each cycle */
     245           0 :         if (uoak_led_status(scc, OAK_TARGET_RAM, &led) < 0)
     246             :                 DPRINTF(("status query error\n"));
     247           0 :         if (led == OAK_LED_OFF) 
     248           0 :                 (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_ON);
     249             :         else 
     250           0 :                 (void)uoak_led_ctrl(scc, OAK_TARGET_RAM, OAK_LED_OFF);
     251             : 
     252           0 :         uoak_sensor_refresh(&sc->sc_sensor.lux, 1000000, 0);
     253           0 : }
     254             : 
     255             : int
     256           0 : uoaklux_get_sensor_setting(struct uoaklux_softc *sc, enum uoak_target target)
     257             : {
     258           0 :         struct uoak_softc *scc = &sc->sc_uoak_softc;
     259             :         uint8_t result;
     260             : 
     261           0 :         memset(&scc->sc_rcmd, 0, sizeof(struct uoak_rcmd));
     262           0 :         scc->sc_rcmd.target = target;
     263           0 :         scc->sc_rcmd.datasize = 0x1;
     264           0 :         USETW(&scc->sc_rcmd.cmd, OAK_CMD_SENSORSETTING);
     265             : 
     266           0 :         if (uoak_get_cmd(scc) < 0)
     267           0 :                 return EIO;
     268             : 
     269           0 :         result =  scc->sc_buf[1];
     270             : 
     271           0 :         sc->sc_sensor.gain = ((result & OAK_LUX_SENSOR_GAIN_MASK) >> 3);
     272           0 :         sc->sc_sensor.inttime = (result & OAK_LUX_SENSOR_INTTIME_MASK);
     273             : 
     274           0 :         return 0;
     275           0 : }
     276             : 
     277             : /* device specific functions */
     278             : void
     279           0 : uoaklux_dev_setting(void *parent, enum uoak_target target)
     280             : {
     281           0 :         struct uoaklux_softc *sc = (struct uoaklux_softc *)parent;
     282             : 
     283             :         /* get device specific configuration */
     284           0 :         (void)uoaklux_get_sensor_setting(sc, target);
     285           0 : }
     286             : 
     287             : void
     288           0 : uoaklux_dev_print(void *parent, enum uoak_target target)
     289             : {
     290           0 :         struct uoaklux_softc *sc = (struct uoaklux_softc *)parent;
     291             : 
     292           0 :         printf(", %s gain", (sc->sc_sensor.gain ? "HIGH" : "LOW"));
     293           0 :         printf(", speed ");
     294           0 :         switch(sc->sc_sensor.inttime) {
     295             :         case OAK_LUX_SENSOR_INTTIME_13_7ms:
     296           0 :                 printf("13.7ms");
     297           0 :                 break;
     298             :         case OAK_LUX_SENSOR_INTTIME_101ms:
     299           0 :                 printf("101ms");
     300           0 :                 break;
     301             :         case OAK_LUX_SENSOR_INTTIME_402ms:
     302           0 :                 printf("402ms");
     303           0 :                 break;
     304             :         default:
     305           0 :                 printf("unknown");
     306           0 :                 break;
     307             :         }
     308           0 : }

Generated by: LCOV version 1.13