LCOV - code coverage report
Current view: top level - dev/usb - umt.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 94 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: umt.c,v 1.1 2018/08/25 20:31:31 jcs Exp $ */
       2             : /*
       3             :  * USB multitouch touchpad 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-2018 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/usb/usb.h>
      30             : #include <dev/usb/usbhid.h>
      31             : #include <dev/usb/usbdi.h>
      32             : #include <dev/usb/usbdevs.h>
      33             : #include <dev/usb/uhidev.h>
      34             : 
      35             : #include <dev/wscons/wsconsio.h>
      36             : #include <dev/wscons/wsmousevar.h>
      37             : 
      38             : #include <dev/hid/hid.h>
      39             : #include <dev/hid/hidmtvar.h>
      40             : 
      41             : struct umt_softc {
      42             :         struct uhidev   sc_hdev;
      43             :         struct hidmt    sc_mt;
      44             : 
      45             :         int             sc_rep_input;
      46             :         int             sc_rep_config;
      47             :         int             sc_rep_cap;
      48             : };
      49             : 
      50             : int     umt_enable(void *);
      51             : int     umt_open(struct uhidev *);
      52             : void    umt_intr(struct uhidev *, void *, u_int);
      53             : void    umt_disable(void *);
      54             : int     umt_ioctl(void *, u_long, caddr_t, int, struct proc *);
      55             : 
      56             : const struct wsmouse_accessops umt_accessops = {
      57             :         umt_enable,
      58             :         umt_ioctl,
      59             :         umt_disable,
      60             : };
      61             : 
      62             : int     umt_match(struct device *, void *, void *);
      63             : int     umt_find_winptp_reports(struct uhidev_softc *, void *, int,
      64             :             struct umt_softc *);
      65             : void    umt_attach(struct device *, struct device *, void *);
      66             : int     umt_hidev_get_report(struct device *, int, int, void *, int);
      67             : int     umt_hidev_set_report(struct device *, int, int, void *, int);
      68             : int     umt_detach(struct device *, int);
      69             : 
      70             : struct cfdriver umt_cd = {
      71             :         NULL, "umt", DV_DULL
      72             : };
      73             : 
      74             : const struct cfattach umt_ca = {
      75             :         sizeof(struct umt_softc),
      76             :         umt_match,
      77             :         umt_attach,
      78             :         umt_detach
      79             : };
      80             : 
      81             : int
      82           0 : umt_match(struct device *parent, void *match, void *aux)
      83             : {
      84           0 :         struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
      85           0 :         int size;
      86           0 :         void *desc;
      87             : 
      88           0 :         if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID) {
      89           0 :                 uhidev_get_report_desc(uha->parent, &desc, &size);
      90           0 :                 if (umt_find_winptp_reports(uha->parent, desc, size, NULL))
      91           0 :                         return (UMATCH_DEVCLASS_DEVSUBCLASS);
      92             :         }
      93             : 
      94           0 :         return (UMATCH_NONE);
      95           0 : }
      96             : 
      97             : int
      98           0 : umt_find_winptp_reports(struct uhidev_softc *parent, void *desc, int size,
      99             :     struct umt_softc *sc)
     100             : {
     101             :         int repid;
     102             :         int input = 0, conf = 0, cap = 0;
     103             : 
     104           0 :         if (sc != NULL) {
     105           0 :                 sc->sc_rep_input = -1;
     106           0 :                 sc->sc_rep_config = -1;
     107           0 :                 sc->sc_rep_cap = -1;
     108           0 :         }
     109             : 
     110           0 :         for (repid = 0; repid < parent->sc_nrepid; repid++) {
     111           0 :                 if (hid_report_size(desc, size, hid_input, repid) == 0 &&
     112           0 :                     hid_report_size(desc, size, hid_output, repid) == 0 &&
     113           0 :                     hid_report_size(desc, size, hid_feature, repid) == 0)
     114             :                         continue;
     115             : 
     116           0 :                 if (hid_is_collection(desc, size, repid,
     117             :                     HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD))) {
     118             :                         input = 1;
     119           0 :                         if (sc != NULL && sc->sc_rep_input == -1)
     120           0 :                                 sc->sc_rep_input = repid;
     121           0 :                 } else if (hid_is_collection(desc, size, repid,
     122             :                     HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIG))) {
     123             :                         conf = 1;
     124           0 :                         if (sc != NULL && sc->sc_rep_config == -1)
     125           0 :                                 sc->sc_rep_config = repid;
     126             :                 }
     127             : 
     128             :                 /* capabilities report could be anywhere */
     129           0 :                 if (hid_locate(desc, size, HID_USAGE2(HUP_DIGITIZERS,
     130             :                     HUD_CONTACT_MAX), repid, hid_feature, NULL, NULL)) {
     131             :                         cap = 1;
     132           0 :                         if (sc != NULL && sc->sc_rep_cap == -1)
     133           0 :                                 sc->sc_rep_cap = repid;
     134             :                 }
     135             :         }
     136             : 
     137           0 :         return (conf && input && cap);
     138             : }
     139             : 
     140             : void
     141           0 : umt_attach(struct device *parent, struct device *self, void *aux)
     142             : {
     143           0 :         struct umt_softc *sc = (struct umt_softc *)self;
     144           0 :         struct hidmt *mt = &sc->sc_mt;
     145           0 :         struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
     146           0 :         int size;
     147           0 :         void *desc;
     148             : 
     149           0 :         sc->sc_hdev.sc_intr = umt_intr;
     150           0 :         sc->sc_hdev.sc_parent = uha->parent;
     151             : 
     152           0 :         uhidev_get_report_desc(uha->parent, &desc, &size);
     153           0 :         umt_find_winptp_reports(uha->parent, desc, size, sc);
     154             : 
     155           0 :         memset(mt, 0, sizeof(sc->sc_mt));
     156             : 
     157             :         /* assume everything has "natural scrolling" where Y axis is reversed */
     158           0 :         mt->sc_flags = HIDMT_REVY;
     159             : 
     160           0 :         mt->hidev_report_type_conv = uhidev_report_type_conv;
     161           0 :         mt->hidev_get_report = umt_hidev_get_report;
     162           0 :         mt->hidev_set_report = umt_hidev_set_report;
     163           0 :         mt->sc_rep_input = sc->sc_rep_input;
     164           0 :         mt->sc_rep_config = sc->sc_rep_config;
     165           0 :         mt->sc_rep_cap = sc->sc_rep_cap;
     166             : 
     167           0 :         if (hidmt_setup(self, mt, desc, size) != 0)
     168           0 :                 return;
     169             : 
     170           0 :         hidmt_attach(mt, &umt_accessops);
     171           0 : }
     172             : 
     173             : int
     174           0 : umt_hidev_get_report(struct device *self, int type, int id, void *data, int len)
     175             : {
     176           0 :         struct umt_softc *sc = (struct umt_softc *)self;
     177             :         int ret;
     178             : 
     179           0 :         ret = uhidev_get_report(sc->sc_hdev.sc_parent, type, id, data, len);
     180           0 :         return (ret < len);
     181             : }
     182             : 
     183             : int
     184           0 : umt_hidev_set_report(struct device *self, int type, int id, void *data, int len)
     185             : {
     186           0 :         struct umt_softc *sc = (struct umt_softc *)self;
     187             :         int ret;
     188             : 
     189           0 :         ret = uhidev_set_report(sc->sc_hdev.sc_parent, type, id, data, len);
     190           0 :         return (ret < len);
     191             : }
     192             : 
     193             : int
     194           0 : umt_detach(struct device *self, int flags)
     195             : {
     196           0 :         struct umt_softc *sc = (struct umt_softc *)self;
     197           0 :         struct hidmt *mt = &sc->sc_mt;
     198             : 
     199           0 :         return hidmt_detach(mt, flags);
     200             : }
     201             : 
     202             : void
     203           0 : umt_intr(struct uhidev *dev, void *buf, u_int len)
     204             : {
     205           0 :         struct umt_softc *sc = (struct umt_softc *)dev;
     206           0 :         struct hidmt *mt = &sc->sc_mt;
     207             : 
     208           0 :         if (!mt->sc_enabled)
     209           0 :                 return;
     210             : 
     211           0 :         hidmt_input(mt, (uint8_t *)buf, len);
     212           0 : }
     213             : 
     214             : int
     215           0 : umt_enable(void *v)
     216             : {
     217           0 :         struct umt_softc *sc = v;
     218           0 :         struct hidmt *mt = &sc->sc_mt;
     219             :         int rv;
     220             : 
     221           0 :         if ((rv = hidmt_enable(mt)) != 0)
     222           0 :                 return rv;
     223             : 
     224           0 :         rv = uhidev_open(&sc->sc_hdev);
     225             : 
     226           0 :         hidmt_set_input_mode(mt, HIDMT_INPUT_MODE_MT_TOUCHPAD);
     227             : 
     228           0 :         return rv;
     229           0 : }
     230             : 
     231             : void
     232           0 : umt_disable(void *v)
     233             : {
     234           0 :         struct umt_softc *sc = v;
     235           0 :         struct hidmt *mt = &sc->sc_mt;
     236             : 
     237           0 :         hidmt_disable(mt);
     238           0 :         uhidev_close(&sc->sc_hdev);
     239           0 : }
     240             : 
     241             : int
     242           0 : umt_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
     243             : {
     244           0 :         struct umt_softc *sc = v;
     245           0 :         struct hidmt *mt = &sc->sc_mt;
     246             :         int rc;
     247             : 
     248           0 :         rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
     249           0 :         if (rc != -1)
     250           0 :                 return rc;
     251             : 
     252           0 :         return hidmt_ioctl(mt, cmd, data, flag, p);
     253           0 : }

Generated by: LCOV version 1.13