jcs's openbsd hax
openbsd
at jcs 210 lines 5.3 kB view raw
1/* $OpenBSD: imt.c,v 1.7 2025/07/21 21:46:40 bru Exp $ */ 2/* 3 * HID-over-i2c multitouch trackpad driver for devices conforming to 4 * Windows Precision Touchpad standard 5 * 6 * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-precision-touchpad-required-hid-top-level-collections 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 38struct 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 47int imt_enable(void *); 48void imt_intr(struct ihidev *, void *, u_int); 49void imt_disable(void *); 50int imt_ioctl(void *, u_long, caddr_t, int, struct proc *); 51 52const struct wsmouse_accessops imt_accessops = { 53 imt_enable, 54 imt_ioctl, 55 imt_disable, 56}; 57 58int imt_match(struct device *, void *, void *); 59void imt_attach(struct device *, struct device *, void *); 60int imt_hidev_get_report(struct device *, int, int, void *, int); 61int imt_hidev_set_report(struct device *, int, int, void *, int); 62int imt_detach(struct device *, int); 63 64struct cfdriver imt_cd = { 65 NULL, "imt", DV_DULL 66}; 67 68const struct cfattach imt_ca = { 69 sizeof(struct imt_softc), 70 imt_match, 71 imt_attach, 72 imt_detach 73}; 74 75int 76imt_match(struct device *parent, void *match, void *aux) 77{ 78 struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 79 int input_rid, conf_rid, cap_rid; 80 int size; 81 void *desc; 82 83 if (iha->reportid == IHIDEV_CLAIM_MULTIPLEID) { 84 ihidev_get_report_desc(iha->parent, &desc, &size); 85 if (hidmt_find_winptp_reports(desc, size, 86 &input_rid, &conf_rid, &cap_rid)) { 87 iha->claims[0] = input_rid; 88 iha->claims[1] = conf_rid; 89 iha->claims[2] = cap_rid; 90 iha->nclaims = 3; 91 return (IMATCH_DEVCLASS_DEVSUBCLASS); 92 } 93 } 94 95 return (IMATCH_NONE); 96} 97 98void 99imt_attach(struct device *parent, struct device *self, void *aux) 100{ 101 struct imt_softc *sc = (struct imt_softc *)self; 102 struct hidmt *mt = &sc->sc_mt; 103 struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 104 int size; 105 void *desc; 106 107 sc->sc_hdev.sc_intr = imt_intr; 108 sc->sc_hdev.sc_parent = iha->parent; 109 110 ihidev_get_report_desc(iha->parent, &desc, &size); 111 hidmt_find_winptp_reports(desc, size, &sc->sc_rep_input, 112 &sc->sc_rep_config, &sc->sc_rep_cap); 113 114 memset(mt, 0, sizeof(sc->sc_mt)); 115 116 /* assume everything has "natural scrolling" where Y axis is reversed */ 117 mt->sc_flags = HIDMT_REVY; 118 119 mt->hidev_report_type_conv = ihidev_report_type_conv; 120 mt->hidev_get_report = imt_hidev_get_report; 121 mt->hidev_set_report = imt_hidev_set_report; 122 mt->sc_rep_input = sc->sc_rep_input; 123 mt->sc_rep_config = sc->sc_rep_config; 124 mt->sc_rep_cap = sc->sc_rep_cap; 125 126 if (hidmt_setup(self, mt, desc, size) != 0) 127 return; 128 129 hidmt_attach(mt, &imt_accessops); 130} 131 132int 133imt_hidev_get_report(struct device *self, int type, int id, void *data, int len) 134{ 135 struct imt_softc *sc = (struct imt_softc *)self; 136 137 return ihidev_get_report((struct device *)sc->sc_hdev.sc_parent, type, 138 id, data, len); 139} 140 141int 142imt_hidev_set_report(struct device *self, int type, int id, void *data, int len) 143{ 144 struct imt_softc *sc = (struct imt_softc *)self; 145 146 return ihidev_set_report((struct device *)sc->sc_hdev.sc_parent, type, 147 id, data, len); 148} 149 150int 151imt_detach(struct device *self, int flags) 152{ 153 struct imt_softc *sc = (struct imt_softc *)self; 154 struct hidmt *mt = &sc->sc_mt; 155 156 return hidmt_detach(mt, flags); 157} 158 159void 160imt_intr(struct ihidev *dev, void *buf, u_int len) 161{ 162 struct imt_softc *sc = (struct imt_softc *)dev; 163 struct hidmt *mt = &sc->sc_mt; 164 165 if (!mt->sc_enabled) 166 return; 167 168 hidmt_input(mt, (uint8_t *)buf, len); 169} 170 171int 172imt_enable(void *v) 173{ 174 struct imt_softc *sc = v; 175 struct hidmt *mt = &sc->sc_mt; 176 int rv; 177 178 if ((rv = hidmt_enable(mt)) != 0) 179 return rv; 180 181 rv = ihidev_open(&sc->sc_hdev); 182 183 hidmt_set_input_mode(mt, HIDMT_INPUT_MODE_MT_TOUCHPAD); 184 185 return rv; 186} 187 188void 189imt_disable(void *v) 190{ 191 struct imt_softc *sc = v; 192 struct hidmt *mt = &sc->sc_mt; 193 194 hidmt_disable(mt); 195 ihidev_close(&sc->sc_hdev); 196} 197 198int 199imt_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 200{ 201 struct imt_softc *sc = v; 202 struct hidmt *mt = &sc->sc_mt; 203 int rc; 204 205 rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p); 206 if (rc != -1) 207 return rc; 208 209 return hidmt_ioctl(mt, cmd, data, flag, p); 210}