1 /* $OpenBSD: ims.c,v 1.2 2018/09/01 20:50:16 jcs Exp $ */ 2 /* 3 * HID-over-i2c mouse/trackpad driver 4 * 5 * Copyright (c) 2015, 2016 joshua stein <jcs@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/kernel.h> 23 #include <sys/device.h> 24 #include <sys/ioctl.h> 25 26 #include <dev/i2c/i2cvar.h> 27 #include <dev/i2c/ihidev.h> 28 29 #include <dev/wscons/wsconsio.h> 30 #include <dev/wscons/wsmousevar.h> 31 32 #include <dev/hid/hid.h> 33 #include <dev/hid/hidmsvar.h> 34 35 struct ims_softc { 36 struct ihidev sc_hdev; 37 struct hidms sc_ms; 38 }; 39 40 void ims_intr(struct ihidev *addr, void *ibuf, u_int len); 41 42 int ims_enable(void *); 43 void ims_disable(void *); 44 int ims_ioctl(void *, u_long, caddr_t, int, struct proc *); 45 46 const struct wsmouse_accessops ims_accessops = { 47 ims_enable, 48 ims_ioctl, 49 ims_disable, 50 }; 51 52 int ims_match(struct device *, void *, void *); 53 void ims_attach(struct device *, struct device *, void *); 54 int ims_detach(struct device *, int); 55 56 struct cfdriver ims_cd = { 57 NULL, "ims", DV_DULL 58 }; 59 60 const struct cfattach ims_ca = { 61 sizeof(struct ims_softc), 62 ims_match, 63 ims_attach, 64 ims_detach 65 }; 66 67 int 68 ims_match(struct device *parent, void *match, void *aux) 69 { 70 struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 71 int size; 72 void *desc; 73 74 ihidev_get_report_desc(iha->parent, &desc, &size); 75 76 if (hid_is_collection(desc, size, iha->reportid, 77 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_POINTER))) 78 return (IMATCH_IFACECLASS); 79 80 if (hid_is_collection(desc, size, iha->reportid, 81 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) 82 return (IMATCH_IFACECLASS); 83 84 if (hid_is_collection(desc, size, iha->reportid, 85 HID_USAGE2(HUP_DIGITIZERS, HUD_PEN))) 86 return (IMATCH_IFACECLASS); 87 88 if (hid_is_collection(desc, size, iha->reportid, 89 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)) && 90 hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), 91 iha->reportid, hid_input, NULL, NULL)) 92 return (IMATCH_IFACECLASS); 93 94 return (IMATCH_NONE); 95 } 96 97 void 98 ims_attach(struct device *parent, struct device *self, void *aux) 99 { 100 struct ims_softc *sc = (struct ims_softc *)self; 101 struct hidms *ms = &sc->sc_ms; 102 struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux; 103 int size, repid; 104 void *desc; 105 106 sc->sc_hdev.sc_intr = ims_intr; 107 sc->sc_hdev.sc_parent = iha->parent; 108 sc->sc_hdev.sc_report_id = iha->reportid; 109 110 ihidev_get_report_desc(iha->parent, &desc, &size); 111 repid = iha->reportid; 112 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 113 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 114 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 115 116 if (hidms_setup(self, ms, 0, iha->reportid, desc, size) != 0) 117 return; 118 119 hidms_attach(ms, &ims_accessops); 120 } 121 122 int 123 ims_detach(struct device *self, int flags) 124 { 125 struct ims_softc *sc = (struct ims_softc *)self; 126 struct hidms *ms = &sc->sc_ms; 127 128 return hidms_detach(ms, flags); 129 } 130 131 void 132 ims_intr(struct ihidev *addr, void *buf, u_int len) 133 { 134 struct ims_softc *sc = (struct ims_softc *)addr; 135 struct hidms *ms = &sc->sc_ms; 136 137 if (ms->sc_enabled != 0) 138 hidms_input(ms, (uint8_t *)buf, len); 139 } 140 141 int 142 ims_enable(void *v) 143 { 144 struct ims_softc *sc = v; 145 struct hidms *ms = &sc->sc_ms; 146 int rv; 147 148 if ((rv = hidms_enable(ms)) != 0) 149 return rv; 150 151 return ihidev_open(&sc->sc_hdev); 152 } 153 154 void 155 ims_disable(void *v) 156 { 157 struct ims_softc *sc = v; 158 struct hidms *ms = &sc->sc_ms; 159 160 hidms_disable(ms); 161 ihidev_close(&sc->sc_hdev); 162 } 163 164 int 165 ims_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 166 { 167 struct ims_softc *sc = v; 168 struct hidms *ms = &sc->sc_ms; 169 int rc; 170 171 #if 0 172 rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p); 173 if (rc != -1) 174 return rc; 175 #endif 176 177 rc = hidms_ioctl(ms, cmd, data, flag, p); 178 if (rc != -1) 179 return rc; 180 181 switch (cmd) { 182 case WSMOUSEIO_GTYPE: 183 /* XXX: should we set something else? */ 184 *(u_int *)data = WSMOUSE_TYPE_USB; 185 return 0; 186 default: 187 return -1; 188 } 189 } 190