hilms.c revision 1.6
1/* $NetBSD: hilms.c,v 1.6 2023/05/10 00:09:47 riastradh 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 struct hilms_softc *sc = device_private(self); 171 int error; 172 173 error = config_detach_children(self, flags); 174 if (error) 175 return error; 176 177 return 0; 178} 179 180int 181hilms_enable(void *v) 182{ 183 struct hilms_softc *sc = v; 184 185 if (sc->sc_enabled) 186 return EBUSY; 187 188 sc->sc_enabled = 1; 189 sc->sc_buttonstate = 0; 190 191 return 0; 192} 193 194void 195hilms_disable(void *v) 196{ 197 struct hilms_softc *sc = v; 198 199 sc->sc_enabled = 0; 200} 201 202int 203hilms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 204{ 205#if 0 206 struct hilms_softc *sc = v; 207#endif 208 209 switch (cmd) { 210 case WSMOUSEIO_GTYPE: 211 *(int *)data = WSMOUSE_TYPE_HIL; 212 return 0; 213 } 214 215 return EPASSTHROUGH; 216} 217 218void 219hilms_callback(struct hildev_softc *hdsc, u_int buflen, uint8_t *buf) 220{ 221 struct hilms_softc *sc = device_private(hdsc->sc_dev); 222 int type, flags; 223 int dx, dy, dz, button; 224#ifdef DIAGNOSTIC 225 int minlen; 226#endif 227 228 /* 229 * Ignore packet if we don't need it 230 */ 231 if (sc->sc_enabled == 0) 232 return; 233 234 type = *buf++; 235 236#ifdef DIAGNOSTIC 237 /* 238 * Check that the packet contains all the expected data, 239 * ignore it if too short. 240 */ 241 minlen = 1; 242 if (type & HIL_MOUSEMOTION) { 243 minlen += sc->sc_axes << 244 (sc->sc_features & HIL_16_BITS) ? 1 : 0; 245 } 246 if (type & HIL_MOUSEBUTTON) 247 minlen++; 248 249 if (minlen > buflen) 250 return; 251#endif 252 253 /* 254 * The packet can contain both a mouse motion and a button event. 255 * In this case, the motion data comes first. 256 */ 257 258 if (type & HIL_MOUSEMOTION) { 259 flags = sc->sc_features & HIL_ABSOLUTE ? 260 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 261 WSMOUSE_INPUT_ABSOLUTE_Z : WSMOUSE_INPUT_DELTA; 262 if (sc->sc_features & HIL_16_BITS) { 263 dx = *buf++; 264 dx |= (*buf++) << 8; 265 if (!(sc->sc_features & HIL_ABSOLUTE)) 266 dx = (int16_t)dx; 267 } else { 268 dx = *buf++; 269 if (!(sc->sc_features & HIL_ABSOLUTE)) 270 dx = (int8_t)dx; 271 } 272 if (sc->sc_axes > 1) { 273 if (sc->sc_features & HIL_16_BITS) { 274 dy = *buf++; 275 dy |= (*buf++) << 8; 276 if (!(sc->sc_features & HIL_ABSOLUTE)) 277 dy = (int16_t)dy; 278 } else { 279 dy = *buf++; 280 if (!(sc->sc_features & HIL_ABSOLUTE)) 281 dy = (int8_t)dy; 282 } 283 if (sc->sc_axes > 2) { 284 if (sc->sc_features & HIL_16_BITS) { 285 dz = *buf++; 286 dz |= (*buf++) << 8; 287 if (!(sc->sc_features & HIL_ABSOLUTE)) 288 dz = (int16_t)dz; 289 } else { 290 dz = *buf++; 291 if (!(sc->sc_features & HIL_ABSOLUTE)) 292 dz = (int8_t)dz; 293 } 294 } else 295 dz = 0; 296 } else 297 dy = dz = 0; 298 299 /* 300 * Correct Y direction for button boxes. 301 */ 302 if ((sc->sc_features & HIL_ABSOLUTE) == 0 && 303 sc->sc_buttons == 0) 304 dy = -dy; 305 } else 306 dx = dy = dz = flags = 0; 307 308 if (type & HIL_MOUSEBUTTON) { 309 button = *buf; 310 /* 311 * The pressure sensor is very primitive and only has 312 * a boolean behaviour, as an extra mouse button, which is 313 * down if there is pressure or the pen is near the tablet, 314 * and up if there is no pressure or the pen is far from the 315 * tablet - at least for Tablet id 0x94, P/N 46088B 316 * 317 * The corresponding codes are 0x8f and 0x8e. Convert them 318 * to a pseudo fourth button - even if the tablet never 319 * has three buttons. 320 */ 321 button = (button - 0x80) >> 1; 322 if (button > 4) 323 button = 4; 324 325 if (*buf & 1) { 326 /* Button released, or no pressure */ 327 sc->sc_buttonstate &= ~(1 << button); 328 } else { 329 /* Button pressed, or pressure */ 330 sc->sc_buttonstate |= (1 << button); 331 } 332 /* buf++; */ 333 } 334 335 if (sc->sc_wsmousedev != NULL) 336 wsmouse_input(sc->sc_wsmousedev, 337 sc->sc_buttonstate, dx, dy, dz, 0, flags); 338} 339