1 /* $OpenBSD: hilms.c,v 1.5 2007/04/10 22:37:17 miod Exp $ */ 2 /* 3 * Copyright (c) 2003, Miodrag Vallat. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 #include <sys/ioctl.h> 33 34 #include <machine/autoconf.h> 35 #include <machine/bus.h> 36 #include <machine/cpu.h> 37 38 #include <dev/hil/hilreg.h> 39 #include <dev/hil/hilvar.h> 40 #include <dev/hil/hildevs.h> 41 42 #include <dev/wscons/wsconsio.h> 43 #include <dev/wscons/wsmousevar.h> 44 45 struct hilms_softc { 46 struct hildev_softc sc_hildev; 47 48 int sc_features; 49 u_int sc_buttons; 50 u_int sc_axes; 51 int sc_enabled; 52 int sc_buttonstate; 53 54 struct device *sc_wsmousedev; 55 }; 56 57 int hilmsprobe(struct device *, void *, void *); 58 void hilmsattach(struct device *, struct device *, void *); 59 int hilmsdetach(struct device *, int); 60 61 struct cfdriver hilms_cd = { 62 NULL, "hilms", DV_DULL 63 }; 64 65 struct cfattach hilms_ca = { 66 sizeof(struct hilms_softc), hilmsprobe, hilmsattach, hilmsdetach, 67 }; 68 69 int hilms_enable(void *); 70 int hilms_ioctl(void *, u_long, caddr_t, int, struct proc *); 71 void hilms_disable(void *); 72 73 const struct wsmouse_accessops hilms_accessops = { 74 hilms_enable, 75 hilms_ioctl, 76 hilms_disable, 77 }; 78 79 void hilms_callback(struct hildev_softc *, u_int, u_int8_t *); 80 81 int 82 hilmsprobe(struct device *parent, void *match, void *aux) 83 { 84 struct hil_attach_args *ha = aux; 85 86 if (ha->ha_type != HIL_DEVICE_MOUSE) 87 return (0); 88 89 /* 90 * Reject anything that has only buttons - they are handled as 91 * keyboards, really. 92 */ 93 if (ha->ha_infolen > 1 && (ha->ha_info[1] & HIL_AXMASK) == 0) 94 return (0); 95 96 return (1); 97 } 98 99 void 100 hilmsattach(struct device *parent, struct device *self, void *aux) 101 { 102 struct hilms_softc *sc = (void *)self; 103 struct hil_attach_args *ha = aux; 104 struct wsmousedev_attach_args a; 105 int iob, rx, ry; 106 107 sc->hd_code = ha->ha_code; 108 sc->hd_type = ha->ha_type; 109 sc->hd_infolen = ha->ha_infolen; 110 bcopy(ha->ha_info, sc->hd_info, ha->ha_infolen); 111 sc->hd_fn = hilms_callback; 112 113 /* 114 * Interpret the identification bytes, if any 115 */ 116 rx = ry = 0; 117 if (ha->ha_infolen > 1) { 118 sc->sc_features = ha->ha_info[1]; 119 sc->sc_axes = sc->sc_features & HIL_AXMASK; 120 121 if (sc->sc_features & HIL_IOB) { 122 /* skip resolution bytes */ 123 iob = 4; 124 if (sc->sc_features & HIL_ABSOLUTE) { 125 /* skip ranges */ 126 rx = ha->ha_info[4] | (ha->ha_info[5] << 8); 127 if (sc->sc_axes > 1) 128 ry = ha->ha_info[6] | 129 (ha->ha_info[7] << 8); 130 iob += 2 * sc->sc_axes; 131 } 132 133 if (iob >= ha->ha_infolen) { 134 sc->sc_features &= ~(HIL_IOB | HILIOB_PIO); 135 } else { 136 iob = ha->ha_info[iob]; 137 sc->sc_buttons = iob & HILIOB_BMASK; 138 sc->sc_features |= (iob & HILIOB_PIO); 139 } 140 } 141 } 142 143 printf(", %d axes", sc->sc_axes); 144 if (sc->sc_buttons == 1) 145 printf(", 1 button"); 146 else if (sc->sc_buttons > 1) 147 printf(", %d buttons", sc->sc_buttons); 148 if (sc->sc_features & HILIOB_PIO) 149 printf(", pressure sensor"); 150 if (sc->sc_features & HIL_ABSOLUTE) { 151 printf ("\n%s: %d", self->dv_xname, rx); 152 if (ry != 0) 153 printf("x%d", ry); 154 else 155 printf(" linear"); 156 printf(" fixed area"); 157 } 158 159 printf("\n"); 160 161 sc->sc_enabled = 0; 162 163 a.accessops = &hilms_accessops; 164 a.accesscookie = sc; 165 166 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 167 } 168 169 int 170 hilmsdetach(struct device *self, int flags) 171 { 172 struct hilms_softc *sc = (void *)self; 173 174 if (sc->sc_wsmousedev != NULL) 175 return config_detach(sc->sc_wsmousedev, flags); 176 177 return (0); 178 } 179 180 int 181 hilms_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 194 void 195 hilms_disable(void *v) 196 { 197 struct hilms_softc *sc = v; 198 199 sc->sc_enabled = 0; 200 } 201 202 int 203 hilms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 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 -1; 216 } 217 218 void 219 hilms_callback(struct hildev_softc *dev, u_int buflen, u_int8_t *buf) 220 { 221 struct hilms_softc *sc = (struct hilms_softc *)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