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