LCOV - code coverage report
Current view: top level - dev/usb - utwitch.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 126 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: utwitch.c,v 1.17 2017/04/08 02:57:25 deraadt Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 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 Maywa-Denki & KAYAC YUREX BBU sensor */
      20             : /* this driver was previously known as uyurex(4). */
      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/usbdi_util.h>
      34             : #include <dev/usb/usbdevs.h>
      35             : #include <dev/usb/uhidev.h>
      36             : 
      37             : #define CMD_NONE        0xf0
      38             : #define CMD_EOF         0x0d
      39             : #define CMD_ACK         0x21
      40             : #define CMD_MODE        0x41 /* XXX */
      41             : #define CMD_VALUE       0x43
      42             : #define CMD_READ        0x52
      43             : #define CMD_WRITE       0x53
      44             : #define CMD_PADDING     0xff
      45             : 
      46             : #define UPDATE_TICK     5 /* sec */
      47             : 
      48             : #ifdef UYUREX_DEBUG
      49             : #define DPRINTF(x)      do { printf x; } while (0)
      50             : #else
      51             : #define DPRINTF(x)
      52             : #endif
      53             : 
      54             : struct utwitch_softc {
      55             :         struct uhidev            sc_hdev;
      56             :         struct usbd_device      *sc_udev;
      57             : 
      58             :         /* uhidev parameters */
      59             :         size_t                   sc_flen;       /* feature report length */
      60             :         size_t                   sc_ilen;       /* input report length */
      61             :         size_t                   sc_olen;       /* output report length */
      62             : 
      63             :         uint8_t                 *sc_ibuf;
      64             : 
      65             :         /* sensor framework */
      66             :         struct ksensor           sc_sensor_val;
      67             :         struct ksensor           sc_sensor_delta;
      68             :         struct ksensordev        sc_sensordev;
      69             :         struct sensor_task      *sc_sensortask;
      70             : 
      71             :         /* device private */
      72             :         int                      sc_initialized;
      73             :         uint8_t                  issueing_cmd;
      74             :         uint8_t                  accepted_cmd;
      75             : 
      76             :         uint32_t                 sc_curval;
      77             :         uint32_t                 sc_oldval;
      78             : };
      79             : 
      80             : const struct usb_devno utwitch_devs[] = {
      81             :         { USB_VENDOR_MICRODIA, USB_PRODUCT_MICRODIA_YUREX},
      82             : };
      83             : 
      84             : int utwitch_match(struct device *, void *, void *);
      85             : void utwitch_attach(struct device *, struct device *, void *);
      86             : int utwitch_detach(struct device *, int);
      87             : 
      88             : void utwitch_set_mode(struct utwitch_softc *, uint8_t);
      89             : void utwitch_read_value_request(struct utwitch_softc *);
      90             : void utwitch_write_value_request(struct utwitch_softc *, uint32_t);
      91             : 
      92             : void utwitch_intr(struct uhidev *, void *, u_int);
      93             : void utwitch_refresh(void *);
      94             : 
      95             : struct cfdriver utwitch_cd = {
      96             :         NULL, "utwitch", DV_DULL
      97             : };
      98             : 
      99             : const struct cfattach utwitch_ca = {
     100             :         sizeof(struct utwitch_softc),
     101             :         utwitch_match,
     102             :         utwitch_attach,
     103             :         utwitch_detach
     104             : };
     105             : 
     106             : int
     107           0 : utwitch_match(struct device *parent, void *match, void *aux)
     108             : {
     109           0 :         struct uhidev_attach_arg *uha = aux;
     110             : 
     111           0 :         if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID)
     112           0 :                 return (UMATCH_NONE);
     113             : 
     114           0 :         return (usb_lookup(utwitch_devs, uha->uaa->vendor, uha->uaa->product) != NULL ?
     115             :             UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
     116           0 : }
     117             : 
     118             : void
     119           0 : utwitch_attach(struct device *parent, struct device *self, void *aux)
     120             : {
     121           0 :         struct utwitch_softc *sc = (struct utwitch_softc *)self;
     122           0 :         struct usb_attach_arg *uaa = aux;
     123           0 :         struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
     124           0 :         struct usbd_device *dev = uha->parent->sc_udev;
     125           0 :         int size, repid, err;
     126           0 :         void *desc;
     127             : 
     128           0 :         sc->sc_udev = dev;
     129           0 :         sc->sc_hdev.sc_intr = utwitch_intr;
     130           0 :         sc->sc_hdev.sc_parent = uha->parent;
     131           0 :         sc->sc_hdev.sc_report_id = uha->reportid;
     132             : 
     133           0 :         uhidev_get_report_desc(uha->parent, &desc, &size);
     134           0 :         repid = uha->reportid;
     135           0 :         sc->sc_ilen = hid_report_size(desc, size, hid_input, repid);
     136           0 :         sc->sc_olen = hid_report_size(desc, size, hid_output, repid);
     137           0 :         sc->sc_flen = hid_report_size(desc, size, hid_feature, repid);
     138             : 
     139           0 :         err = uhidev_open(&sc->sc_hdev);
     140           0 :         if (err) {
     141           0 :                 printf("utwitch_open: uhidev_open %d\n", err);
     142           0 :                 return;
     143             :         }
     144           0 :         sc->sc_ibuf = malloc(sc->sc_ilen, M_USBDEV, M_WAITOK);
     145             : 
     146           0 :         printf("\n");
     147             : 
     148             : 
     149             :         /* attach sensor */
     150           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname,
     151             :             sizeof(sc->sc_sensordev.xname));
     152             : 
     153             :         /* add BBU sensor */
     154           0 :         sc->sc_sensor_val.type = SENSOR_INTEGER;
     155           0 :         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor_val);
     156           0 :         strlcpy(sc->sc_sensor_val.desc, "BBU",
     157             :                 sizeof(sc->sc_sensor_val.desc));
     158             : 
     159             :         /* add BBU delta sensor */
     160           0 :         sc->sc_sensor_delta.type = SENSOR_INTEGER;
     161           0 :         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor_delta);
     162           0 :         strlcpy(sc->sc_sensor_delta.desc, "mBBU/sec",
     163             :                 sizeof(sc->sc_sensor_delta.desc));
     164             : 
     165           0 :         sc->sc_sensortask = sensor_task_register(sc, utwitch_refresh, UPDATE_TICK);
     166           0 :         if (sc->sc_sensortask == NULL) {
     167           0 :                 printf(", unable to register update task\n");
     168           0 :                 return;
     169             :         }
     170           0 :         sensordev_install(&sc->sc_sensordev);
     171             : 
     172             :         DPRINTF(("utwitch_attach: complete\n"));
     173             : 
     174             :         /* init device */ /* XXX */
     175           0 :         utwitch_set_mode(sc, 0);
     176           0 : }
     177             : 
     178             : int
     179           0 : utwitch_detach(struct device *self, int flags)
     180             : {
     181           0 :         struct utwitch_softc *sc = (struct utwitch_softc *)self;
     182             :         int rv = 0;
     183             : 
     184           0 :         wakeup(&sc->sc_sensortask);
     185           0 :         sensordev_deinstall(&sc->sc_sensordev);
     186           0 :         sensor_detach(&sc->sc_sensordev, &sc->sc_sensor_val);
     187           0 :         sensor_detach(&sc->sc_sensordev, &sc->sc_sensor_delta);
     188           0 :         if (sc->sc_sensortask != NULL)
     189           0 :                 sensor_task_unregister(sc->sc_sensortask);
     190             : 
     191           0 :         if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
     192           0 :                 uhidev_close(&sc->sc_hdev);
     193             : 
     194           0 :         if (sc->sc_ibuf != NULL) {
     195           0 :                 free(sc->sc_ibuf, M_USBDEV, sc->sc_ilen);
     196           0 :                 sc->sc_ibuf = NULL;
     197           0 :         }
     198             : 
     199           0 :         return (rv);
     200             : }
     201             : 
     202             : void
     203           0 : utwitch_intr(struct uhidev *addr, void *ibuf, u_int len)
     204             : {
     205           0 :         struct utwitch_softc *sc = (struct utwitch_softc *)addr;
     206             :         uint8_t buf[8];
     207             :         uint32_t val;
     208             : 
     209           0 :         if (sc->sc_ibuf == NULL)
     210           0 :                 return;
     211             : 
     212             :         /* process requests */
     213           0 :         memcpy(buf, ibuf, 8);
     214             :         DPRINTF(("intr: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n",
     215             :                 buf[0], buf[1], buf[2], buf[3],
     216             :                 buf[4], buf[5], buf[6], buf[7]));
     217             : 
     218             : 
     219           0 :         switch (buf[0]) {
     220             :         case CMD_ACK:
     221           0 :                 if (buf[1] == sc->issueing_cmd) {
     222             :                         DPRINTF(("ack received for cmd 0x%.2x\n", buf[1]));
     223           0 :                         sc->accepted_cmd = buf[1];
     224           0 :                 } else {
     225             :                         DPRINTF(("cmd-ack mismatch: recved 0x%.2x, expect 0x%.2x\n",
     226             :                                 buf[1], sc->issueing_cmd));
     227             :                         /* discard previous command */
     228           0 :                         sc->accepted_cmd = CMD_NONE;
     229           0 :                         sc->issueing_cmd = CMD_NONE;
     230             :                 }
     231             :                 break;
     232             :         case CMD_READ:
     233             :         case CMD_VALUE:
     234           0 :                 val = (buf[2] << 24) + (buf[3] << 16) + (buf[4] << 8)  + buf[5];
     235           0 :                 if (!sc->sc_initialized) {
     236           0 :                         sc->sc_oldval = val;
     237           0 :                         sc->sc_initialized = 1;
     238           0 :                 }
     239           0 :                 sc->sc_sensor_val.value = val;
     240           0 :                 sc->sc_curval = val;
     241             :                 DPRINTF(("recv value update message: %d\n", val));
     242           0 :                 break;
     243             :         default:
     244             :                 DPRINTF(("unknown message: 0x%.2x\n", buf[0]));
     245             :         }
     246             : 
     247           0 :         return;
     248           0 : }
     249             : 
     250             : void
     251           0 : utwitch_refresh(void *arg)
     252             : {
     253           0 :         struct utwitch_softc *sc = arg;
     254             : 
     255           0 :         if (!sc->sc_initialized) {
     256           0 :                 utwitch_read_value_request(sc);
     257           0 :         } else {
     258             :                 /* calculate delta value */
     259           0 :                 sc->sc_sensor_delta.value =
     260           0 :                         (1000 * (sc->sc_curval - sc->sc_oldval)) / UPDATE_TICK;
     261           0 :                 sc->sc_oldval = sc->sc_curval;
     262             :         }
     263           0 : }
     264             : 
     265             : void
     266           0 : utwitch_set_mode(struct utwitch_softc *sc, uint8_t val)
     267             : {
     268           0 :         uint8_t req[8];
     269             : 
     270           0 :         memset(req, CMD_PADDING, sizeof(req));
     271           0 :         req[0] = CMD_MODE;
     272           0 :         req[1] = val;
     273           0 :         req[2] = CMD_EOF;
     274           0 :         if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
     275           0 :             sc->sc_hdev.sc_report_id, req, sc->sc_olen) != sc->sc_olen) {
     276           0 :                 printf("uhidev_set_report error:EIO\n");
     277           0 :                 return;
     278             :         }
     279             : 
     280             :         /* wait ack */
     281           0 :         tsleep(&sc->sc_sensortask, 0, "utwitch", (1000*hz+999)/1000 + 1);
     282           0 : }
     283             : 
     284             : void
     285           0 : utwitch_read_value_request(struct utwitch_softc *sc)
     286             : {
     287           0 :         uint8_t req[8];
     288             : 
     289           0 :         memset(req, CMD_PADDING, sizeof(req));
     290           0 :         req[0] = CMD_READ;
     291           0 :         req[1] = CMD_EOF;
     292           0 :         sc->issueing_cmd = CMD_READ;
     293           0 :         sc->accepted_cmd = CMD_NONE;
     294           0 :         if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
     295           0 :             sc->sc_hdev.sc_report_id, req, sc->sc_olen) != sc->sc_olen)
     296           0 :                 return;
     297             : 
     298             :         /* wait till sensor data are updated, 500ms will be enough */
     299           0 :         tsleep(&sc->sc_sensortask, 0, "utwitch", (500*hz+999)/1000 + 1);
     300           0 : }
     301             : 
     302             : void
     303           0 : utwitch_write_value_request(struct utwitch_softc *sc, uint32_t val)
     304             : {
     305             :         uint32_t v;
     306           0 :         uint8_t req[8];
     307             : 
     308           0 :         req[0] = CMD_WRITE;
     309           0 :         req[1] = 0;
     310           0 :         req[6] = CMD_EOF;
     311           0 :         req[7] = CMD_PADDING;
     312           0 :         v = htobe32(val);
     313           0 :         memcpy(req + 2, &v, sizeof(uint32_t));
     314             : 
     315           0 :         sc->issueing_cmd = CMD_WRITE;
     316           0 :         sc->accepted_cmd = CMD_NONE;
     317           0 :         if (uhidev_set_report(sc->sc_hdev.sc_parent, UHID_OUTPUT_REPORT,
     318           0 :             sc->sc_hdev.sc_report_id, req, sc->sc_olen) != sc->sc_olen)
     319           0 :                 return;
     320             : 
     321             :         /* wait till sensor data are updated, 250ms will be enough */
     322           0 :         tsleep(&sc->sc_sensortask, 0, "utwitch", (250*hz+999)/1000 + 1);
     323           0 : }

Generated by: LCOV version 1.13