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

          Line data    Source code
       1             : /* $OpenBSD: imt.c,v 1.4 2018/08/25 20:31:31 jcs Exp $ */
       2             : /*
       3             :  * HID-over-i2c multitouch trackpad driver for devices conforming to
       4             :  * Windows Precision Touchpad standard
       5             :  *
       6             :  * https://msdn.microsoft.com/en-us/library/windows/hardware/dn467314%28v=vs.85%29.aspx
       7             :  *
       8             :  * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
       9             :  *
      10             :  * Permission to use, copy, modify, and distribute this software for any
      11             :  * purpose with or without fee is hereby granted, provided that the above
      12             :  * copyright notice and this permission notice appear in all copies.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      15             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      16             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      17             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      18             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      19             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      20             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      21             :  */
      22             : 
      23             : #include <sys/param.h>
      24             : #include <sys/systm.h>
      25             : #include <sys/kernel.h>
      26             : #include <sys/device.h>
      27             : #include <sys/ioctl.h>
      28             : 
      29             : #include <dev/i2c/i2cvar.h>
      30             : #include <dev/i2c/ihidev.h>
      31             : 
      32             : #include <dev/wscons/wsconsio.h>
      33             : #include <dev/wscons/wsmousevar.h>
      34             : 
      35             : #include <dev/hid/hid.h>
      36             : #include <dev/hid/hidmtvar.h>
      37             : 
      38             : struct imt_softc {
      39             :         struct ihidev   sc_hdev;
      40             :         struct hidmt    sc_mt;
      41             : 
      42             :         int             sc_rep_input;
      43             :         int             sc_rep_config;
      44             :         int             sc_rep_cap;
      45             : };
      46             : 
      47             : int     imt_enable(void *);
      48             : int     imt_open(struct ihidev *);
      49             : void    imt_intr(struct ihidev *, void *, u_int);
      50             : void    imt_disable(void *);
      51             : int     imt_ioctl(void *, u_long, caddr_t, int, struct proc *);
      52             : 
      53             : const struct wsmouse_accessops imt_accessops = {
      54             :         imt_enable,
      55             :         imt_ioctl,
      56             :         imt_disable,
      57             : };
      58             : 
      59             : int     imt_match(struct device *, void *, void *);
      60             : int     imt_find_winptp_reports(struct ihidev_softc *, void *, int,
      61             :             struct imt_softc *);
      62             : void    imt_attach(struct device *, struct device *, void *);
      63             : int     imt_hidev_get_report(struct device *, int, int, void *, int);
      64             : int     imt_hidev_set_report(struct device *, int, int, void *, int);
      65             : int     imt_detach(struct device *, int);
      66             : 
      67             : struct cfdriver imt_cd = {
      68             :         NULL, "imt", DV_DULL
      69             : };
      70             : 
      71             : const struct cfattach imt_ca = {
      72             :         sizeof(struct imt_softc),
      73             :         imt_match,
      74             :         imt_attach,
      75             :         imt_detach
      76             : };
      77             : 
      78             : int
      79           0 : imt_match(struct device *parent, void *match, void *aux)
      80             : {
      81           0 :         struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
      82           0 :         int size;
      83           0 :         void *desc;
      84             : 
      85           0 :         if (iha->reportid == IHIDEV_CLAIM_ALLREPORTID) {
      86           0 :                 ihidev_get_report_desc(iha->parent, &desc, &size);
      87           0 :                 if (imt_find_winptp_reports(iha->parent, desc, size, NULL))
      88           0 :                         return (IMATCH_DEVCLASS_DEVSUBCLASS);
      89             :         }
      90             : 
      91           0 :         return (IMATCH_NONE);
      92           0 : }
      93             : 
      94             : int
      95           0 : imt_find_winptp_reports(struct ihidev_softc *parent, void *desc, int size,
      96             :     struct imt_softc *sc)
      97             : {
      98             :         int repid;
      99             :         int input = 0, conf = 0, cap = 0;
     100             : 
     101           0 :         if (sc != NULL) {
     102           0 :                 sc->sc_rep_input = -1;
     103           0 :                 sc->sc_rep_config = -1;
     104           0 :                 sc->sc_rep_cap = -1;
     105           0 :         }
     106             : 
     107           0 :         for (repid = 0; repid < parent->sc_nrepid; repid++) {
     108           0 :                 if (hid_report_size(desc, size, hid_input, repid) == 0 &&
     109           0 :                     hid_report_size(desc, size, hid_output, repid) == 0 &&
     110           0 :                     hid_report_size(desc, size, hid_feature, repid) == 0)
     111             :                         continue;
     112             : 
     113           0 :                 if (hid_is_collection(desc, size, repid,
     114             :                     HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD))) {
     115             :                         input = 1;
     116           0 :                         if (sc != NULL && sc->sc_rep_input == -1)
     117           0 :                                 sc->sc_rep_input = repid;
     118           0 :                 } else if (hid_is_collection(desc, size, repid,
     119             :                     HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIG))) {
     120             :                         conf = 1;
     121           0 :                         if (sc != NULL && sc->sc_rep_config == -1)
     122           0 :                                 sc->sc_rep_config = repid;
     123             :                 }
     124             : 
     125             :                 /* capabilities report could be anywhere */
     126           0 :                 if (hid_locate(desc, size, HID_USAGE2(HUP_DIGITIZERS,
     127             :                     HUD_CONTACT_MAX), repid, hid_feature, NULL, NULL)) {
     128             :                         cap = 1;
     129           0 :                         if (sc != NULL && sc->sc_rep_cap == -1)
     130           0 :                                 sc->sc_rep_cap = repid;
     131             :                 }
     132             :         }
     133             : 
     134           0 :         return (conf && input && cap);
     135             : }
     136             : 
     137             : void
     138           0 : imt_attach(struct device *parent, struct device *self, void *aux)
     139             : {
     140           0 :         struct imt_softc *sc = (struct imt_softc *)self;
     141           0 :         struct hidmt *mt = &sc->sc_mt;
     142           0 :         struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
     143           0 :         int size;
     144           0 :         void *desc;
     145             : 
     146           0 :         sc->sc_hdev.sc_intr = imt_intr;
     147           0 :         sc->sc_hdev.sc_parent = iha->parent;
     148             : 
     149           0 :         ihidev_get_report_desc(iha->parent, &desc, &size);
     150           0 :         imt_find_winptp_reports(iha->parent, desc, size, sc);
     151             : 
     152           0 :         memset(mt, 0, sizeof(sc->sc_mt));
     153             : 
     154             :         /* assume everything has "natural scrolling" where Y axis is reversed */
     155           0 :         mt->sc_flags = HIDMT_REVY;
     156             : 
     157           0 :         mt->hidev_report_type_conv = ihidev_report_type_conv;
     158           0 :         mt->hidev_get_report = imt_hidev_get_report;
     159           0 :         mt->hidev_set_report = imt_hidev_set_report;
     160           0 :         mt->sc_rep_input = sc->sc_rep_input;
     161           0 :         mt->sc_rep_config = sc->sc_rep_config;
     162           0 :         mt->sc_rep_cap = sc->sc_rep_cap;
     163             : 
     164           0 :         if (hidmt_setup(self, mt, desc, size) != 0)
     165           0 :                 return;
     166             : 
     167           0 :         hidmt_attach(mt, &imt_accessops);
     168           0 : }
     169             : 
     170             : int
     171           0 : imt_hidev_get_report(struct device *self, int type, int id, void *data, int len)
     172             : {
     173           0 :         struct imt_softc *sc = (struct imt_softc *)self;
     174             : 
     175           0 :         return ihidev_get_report((struct device *)sc->sc_hdev.sc_parent, type,
     176             :             id, data, len);
     177             : }
     178             : 
     179             : int
     180           0 : imt_hidev_set_report(struct device *self, int type, int id, void *data, int len)
     181             : {
     182           0 :         struct imt_softc *sc = (struct imt_softc *)self;
     183             : 
     184           0 :         return ihidev_set_report((struct device *)sc->sc_hdev.sc_parent, type,
     185             :             id, data, len);
     186             : }
     187             : 
     188             : int
     189           0 : imt_detach(struct device *self, int flags)
     190             : {
     191           0 :         struct imt_softc *sc = (struct imt_softc *)self;
     192           0 :         struct hidmt *mt = &sc->sc_mt;
     193             : 
     194           0 :         return hidmt_detach(mt, flags);
     195             : }
     196             : 
     197             : void
     198           0 : imt_intr(struct ihidev *dev, void *buf, u_int len)
     199             : {
     200           0 :         struct imt_softc *sc = (struct imt_softc *)dev;
     201           0 :         struct hidmt *mt = &sc->sc_mt;
     202             : 
     203           0 :         if (!mt->sc_enabled)
     204           0 :                 return;
     205             : 
     206           0 :         hidmt_input(mt, (uint8_t *)buf, len);
     207           0 : }
     208             : 
     209             : int
     210           0 : imt_enable(void *v)
     211             : {
     212           0 :         struct imt_softc *sc = v;
     213           0 :         struct hidmt *mt = &sc->sc_mt;
     214             :         int rv;
     215             : 
     216           0 :         if ((rv = hidmt_enable(mt)) != 0)
     217           0 :                 return rv;
     218             : 
     219           0 :         rv = ihidev_open(&sc->sc_hdev);
     220             : 
     221           0 :         hidmt_set_input_mode(mt, HIDMT_INPUT_MODE_MT_TOUCHPAD);
     222             : 
     223           0 :         return rv;
     224           0 : }
     225             : 
     226             : void
     227           0 : imt_disable(void *v)
     228             : {
     229           0 :         struct imt_softc *sc = v;
     230           0 :         struct hidmt *mt = &sc->sc_mt;
     231             : 
     232           0 :         hidmt_disable(mt);
     233           0 :         ihidev_close(&sc->sc_hdev);
     234           0 : }
     235             : 
     236             : int
     237           0 : imt_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
     238             : {
     239           0 :         struct imt_softc *sc = v;
     240           0 :         struct hidmt *mt = &sc->sc_mt;
     241             :         int rc;
     242             : 
     243           0 :         rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
     244           0 :         if (rc != -1)
     245           0 :                 return rc;
     246             : 
     247           0 :         return hidmt_ioctl(mt, cmd, data, flag, p);
     248           0 : }

Generated by: LCOV version 1.13