1/* $NetBSD: hilms.c,v 1.7 2023/05/11 09:35:57 martin Exp $ */ 2/* $OpenBSD: hilms.c,v 1.5 2007/04/10 22:37:17 miod Exp $ */ 3/* 4 * Copyright (c) 2003, Miodrag Vallat. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/device.h> 33#include <sys/ioctl.h> 34#include <sys/bus.h> 35#include <sys/cpu.h> 36 37#include <machine/autoconf.h> 38 39#include <dev/hil/hilreg.h> 40#include <dev/hil/hilvar.h> 41#include <dev/hil/hildevs.h> 42 43#include <dev/wscons/wsconsio.h> 44#include <dev/wscons/wsmousevar.h> 45 46struct hilms_softc { 47 struct hildev_softc sc_hildev; 48 49 int sc_features; 50 u_int sc_buttons; 51 u_int sc_axes; 52 int sc_enabled; 53 int sc_buttonstate; 54 55 device_t sc_wsmousedev; 56}; 57 58static int hilmsprobe(device_t, cfdata_t, void *); 59static void hilmsattach(device_t, device_t, void *); 60static int hilmsdetach(device_t, int); 61 62CFATTACH_DECL_NEW(hilms, sizeof(struct hilms_softc), 63 hilmsprobe, hilmsattach, hilmsdetach, NULL); 64 65static int hilms_enable(void *); 66static int hilms_ioctl(void *, u_long, void *, int, struct lwp *); 67static void hilms_disable(void *); 68 69static const struct wsmouse_accessops hilms_accessops = { 70 .enable = hilms_enable, 71 .ioctl = hilms_ioctl, 72 .disable = hilms_disable, 73}; 74 75static void hilms_callback(struct hildev_softc *, u_int, uint8_t *); 76 77int 78hilmsprobe(device_t parent, cfdata_t cf, void *aux) 79{ 80 struct hil_attach_args *ha = aux; 81 82 if (ha->ha_type != HIL_DEVICE_MOUSE) 83 return 0; 84 85 /* 86 * Reject anything that has only buttons - they are handled as 87 * keyboards, really. 88 */ 89 if (ha->ha_infolen > 1 && (ha->ha_info[1] & HIL_AXMASK) == 0) 90 return 0; 91 92 return 1; 93} 94 95void 96hilmsattach(device_t parent, device_t self, void *aux) 97{ 98 struct hilms_softc *sc = device_private(self); 99 struct hil_attach_args *ha = aux; 100 struct wsmousedev_attach_args a; 101 int iob, rx, ry; 102 103 sc->sc_hildev.sc_dev = self; 104 sc->hd_code = ha->ha_code; 105 sc->hd_type = ha->ha_type; 106 sc->hd_infolen = ha->ha_infolen; 107 memcpy(sc->hd_info, ha->ha_info, ha->ha_infolen); 108 sc->hd_fn = hilms_callback; 109 110 /* 111 * Interpret the identification bytes, if any 112 */ 113 rx = ry = 0; 114 if (ha->ha_infolen > 1) { 115 sc->sc_features = ha->ha_info[1]; 116 sc->sc_axes = sc->sc_features & HIL_AXMASK; 117 118 if (sc->sc_features & HIL_IOB) { 119 /* skip resolution bytes */ 120 iob = 4; 121 if (sc->sc_features & HIL_ABSOLUTE) { 122 /* skip ranges */ 123 rx = ha->ha_info[4] | (ha->ha_info[5] << 8); 124 if (sc->sc_axes > 1) 125 ry = ha->ha_info[6] | 126 (ha->ha_info[7] << 8); 127 iob += 2 * sc->sc_axes; 128 } 129 130 if (iob >= ha->ha_infolen) { 131 sc->sc_features &= ~(HIL_IOB | HILIOB_PIO); 132 } else { 133 iob = ha->ha_info[iob]; 134 sc->sc_buttons = iob & HILIOB_BMASK; 135 sc->sc_features |= (iob & HILIOB_PIO); 136 } 137 } 138 } 139 140 aprint_normal(", %d axes", sc->sc_axes); 141 if (sc->sc_buttons == 1) 142 aprint_normal(", 1 button"); 143 else if (sc->sc_buttons > 1) 144 aprint_normal(", %d buttons", sc->sc_buttons); 145 if (sc->sc_features & HILIOB_PIO) 146 aprint_normal(", pressure sensor"); 147 if (sc->sc_features & HIL_ABSOLUTE) { 148 aprint_normal("\n"); 149 aprint_normal_dev(self, "%d", rx); 150 if (ry != 0) 151 aprint_normal("x%d", ry); 152 else 153 aprint_normal(" linear"); 154 aprint_normal(" fixed area"); 155 } 156 157 aprint_normal("\n"); 158 159 sc->sc_enabled = 0; 160 161 a.accessops = &hilms_accessops; 162 a.accesscookie = sc; 163 164 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE); 165} 166 167int 168hilmsdetach(device_t self, int flags) 169{ 170 int error; 171 172 error = config_detach_children(self, flags); 173 if (error) 174 return error; 175 176 return 0; 177} 178 179int 180hilms_enable(void *v) 181{ 182 struct hilms_softc *sc = v; 183 184 if (sc->sc_enabled) 185 return EBUSY; 186 187 sc->sc_enabled = 1; 188 sc->sc_buttonstate = 0; 189 190 return 0; 191} 192 193void 194hilms_disable(void *v) 195{ 196 struct hilms_softc *sc = v; 197 198 sc->sc_enabled = 0; 199} 200 201int 202hilms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 203{ 204#if 0 205 struct hilms_softc *sc = v; 206#endif 207 208 switch (cmd) { 209 case WSMOUSEIO_GTYPE: 210 *(int *)data = WSMOUSE_TYPE_HIL; 211 return 0; 212 } 213 214 return EPASSTHROUGH; 215} 216 217void 218hilms_callback(struct hildev_softc *hdsc, u_int buflen, uint8_t *buf) 219{ 220 struct hilms_softc *sc = device_private(hdsc->sc_dev); 221 int type, flags; 222 int dx, dy, dz, button; 223#ifdef DIAGNOSTIC 224 int minlen; 225#endif 226 227 /* 228 * Ignore packet if we don't need it 229 */ 230 if (sc->sc_enabled == 0) 231 return; 232 233 type = *buf++; 234 235#ifdef DIAGNOSTIC 236 /* 237 * Check that the packet contains all the expected data, 238 * ignore it if too short. 239 */ 240 minlen = 1; 241 if (type & HIL_MOUSEMOTION) { 242 minlen += sc->sc_axes << 243 (sc->sc_features & HIL_16_BITS) ? 1 : 0; 244 } 245 if (type & HIL_MOUSEBUTTON) 246 minlen++; 247 248 if (minlen > buflen) 249 return; 250#endif 251 252 /* 253 * The packet can contain both a mouse motion and a button event. 254 * In this case, the motion data comes first. 255 */ 256 257 if (type & HIL_MOUSEMOTION) { 258 flags = sc->sc_features & HIL_ABSOLUTE ? 259 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 260 WSMOUSE_INPUT_ABSOLUTE_Z : WSMOUSE_INPUT_DELTA; 261 if (sc->sc_features & HIL_16_BITS) { 262 dx = *buf++; 263 dx |= (*buf++) << 8; 264 if (!(sc->sc_features & HIL_ABSOLUTE)) 265 dx = (int16_t)dx; 266 } else { 267 dx = *buf++; 268 if (!(sc->sc_features & HIL_ABSOLUTE)) 269 dx = (int8_t)dx; 270 } 271 if (sc->sc_axes > 1) { 272 if (sc->sc_features & HIL_16_BITS) { 273 dy = *buf++; 274 dy |= (*buf++) << 8; 275 if (!(sc->sc_features & HIL_ABSOLUTE)) 276 dy = (int16_t)dy; 277 } else { 278 dy = *buf++; 279 if (!(sc->sc_features & HIL_ABSOLUTE)) 280 dy = (int8_t)dy; 281 } 282 if (sc->sc_axes > 2) { 283 if (sc->sc_features & HIL_16_BITS) { 284 dz = *buf++; 285 dz |= (*buf++) << 8; 286 if (!(sc->sc_features & HIL_ABSOLUTE)) 287 dz = (int16_t)dz; 288 } else { 289 dz = *buf++; 290 if (!(sc->sc_features & HIL_ABSOLUTE)) 291 dz = (int8_t)dz; 292 } 293 } else 294 dz = 0; 295 } else 296 dy = dz = 0; 297 298 /* 299 * Correct Y direction for button boxes. 300 */ 301 if ((sc->sc_features & HIL_ABSOLUTE) == 0 && 302 sc->sc_buttons == 0) 303 dy = -dy; 304 } else 305 dx = dy = dz = flags = 0; 306 307 if (type & HIL_MOUSEBUTTON) { 308 button = *buf; 309 /* 310 * The pressure sensor is very primitive and only has 311 * a boolean behaviour, as an extra mouse button, which is 312 * down if there is pressure or the pen is near the tablet, 313 * and up if there is no pressure or the pen is far from the 314 * tablet - at least for Tablet id 0x94, P/N 46088B 315 * 316 * The corresponding codes are 0x8f and 0x8e. Convert them 317 * to a pseudo fourth button - even if the tablet never 318 * has three buttons. 319 */ 320 button = (button - 0x80) >> 1; 321 if (button > 4) 322 button = 4; 323 324 if (*buf & 1) { 325 /* Button released, or no pressure */ 326 sc->sc_buttonstate &= ~(1 << button); 327 } else { 328 /* Button pressed, or pressure */ 329 sc->sc_buttonstate |= (1 << button); 330 } 331 /* buf++; */ 332 } 333 334 if (sc->sc_wsmousedev != NULL) 335 wsmouse_input(sc->sc_wsmousedev, 336 sc->sc_buttonstate, dx, dy, dz, 0, flags); 337} 338