hilms.c revision 1.1
1/* $NetBSD: hilms.c,v 1.1 2011/02/06 18:26:54 tsutsui 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 58int hilmsprobe(device_t, cfdata_t, void *); 59void hilmsattach(device_t, device_t, void *); 60int hilmsdetach(device_t, int); 61 62CFATTACH_DECL_NEW(hilms, sizeof(struct hilms_softc), 63 hilmsprobe, hilmsattach, hilmsdetach, NULL); 64 65int hilms_enable(void *); 66int hilms_ioctl(void *, u_long, void *, int, struct lwp *); 67void hilms_disable(void *); 68 69const struct wsmouse_accessops hilms_accessops = { 70 hilms_enable, 71 hilms_ioctl, 72 hilms_disable, 73}; 74 75void hilms_callback(struct hildev_softc *, u_int, u_int8_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 printf(", %d axes", sc->sc_axes); 141 if (sc->sc_buttons == 1) 142 printf(", 1 button"); 143 else if (sc->sc_buttons > 1) 144 printf(", %d buttons", sc->sc_buttons); 145 if (sc->sc_features & HILIOB_PIO) 146 printf(", pressure sensor"); 147 if (sc->sc_features & HIL_ABSOLUTE) { 148 printf ("\n%s: %d", device_xname(self), rx); 149 if (ry != 0) 150 printf("x%d", ry); 151 else 152 printf(" linear"); 153 printf(" fixed area"); 154 } 155 156 printf("\n"); 157 158 sc->sc_enabled = 0; 159 160 a.accessops = &hilms_accessops; 161 a.accesscookie = sc; 162 163 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 164} 165 166int 167hilmsdetach(device_t self, int flags) 168{ 169 struct hilms_softc *sc = device_private(self); 170 171 if (sc->sc_wsmousedev != NULL) 172 return config_detach(sc->sc_wsmousedev, flags); 173 174 return (0); 175} 176 177int 178hilms_enable(void *v) 179{ 180 struct hilms_softc *sc = v; 181 182 if (sc->sc_enabled) 183 return EBUSY; 184 185 sc->sc_enabled = 1; 186 sc->sc_buttonstate = 0; 187 188 return (0); 189} 190 191void 192hilms_disable(void *v) 193{ 194 struct hilms_softc *sc = v; 195 196 sc->sc_enabled = 0; 197} 198 199int 200hilms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 201{ 202#if 0 203 struct hilms_softc *sc = v; 204#endif 205 206 switch (cmd) { 207 case WSMOUSEIO_GTYPE: 208 *(int *)data = WSMOUSE_TYPE_HIL; 209 return 0; 210 } 211 212 return EPASSTHROUGH; 213} 214 215void 216hilms_callback(struct hildev_softc *hdsc, u_int buflen, u_int8_t *buf) 217{ 218 struct hilms_softc *sc = device_private(hdsc->sc_dev); 219 int type, flags; 220 int dx, dy, dz, button; 221#ifdef DIAGNOSTIC 222 int minlen; 223#endif 224 225 /* 226 * Ignore packet if we don't need it 227 */ 228 if (sc->sc_enabled == 0) 229 return; 230 231 type = *buf++; 232 233#ifdef DIAGNOSTIC 234 /* 235 * Check that the packet contains all the expected data, 236 * ignore it if too short. 237 */ 238 minlen = 1; 239 if (type & HIL_MOUSEMOTION) { 240 minlen += sc->sc_axes << 241 (sc->sc_features & HIL_16_BITS) ? 1 : 0; 242 } 243 if (type & HIL_MOUSEBUTTON) 244 minlen++; 245 246 if (minlen > buflen) 247 return; 248#endif 249 250 /* 251 * The packet can contain both a mouse motion and a button event. 252 * In this case, the motion data comes first. 253 */ 254 255 if (type & HIL_MOUSEMOTION) { 256 flags = sc->sc_features & HIL_ABSOLUTE ? 257 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | 258 WSMOUSE_INPUT_ABSOLUTE_Z : WSMOUSE_INPUT_DELTA; 259 if (sc->sc_features & HIL_16_BITS) { 260 dx = *buf++; 261 dx |= (*buf++) << 8; 262 if (!(sc->sc_features & HIL_ABSOLUTE)) 263 dx = (int16_t)dx; 264 } else { 265 dx = *buf++; 266 if (!(sc->sc_features & HIL_ABSOLUTE)) 267 dx = (int8_t)dx; 268 } 269 if (sc->sc_axes > 1) { 270 if (sc->sc_features & HIL_16_BITS) { 271 dy = *buf++; 272 dy |= (*buf++) << 8; 273 if (!(sc->sc_features & HIL_ABSOLUTE)) 274 dy = (int16_t)dy; 275 } else { 276 dy = *buf++; 277 if (!(sc->sc_features & HIL_ABSOLUTE)) 278 dy = (int8_t)dy; 279 } 280 if (sc->sc_axes > 2) { 281 if (sc->sc_features & HIL_16_BITS) { 282 dz = *buf++; 283 dz |= (*buf++) << 8; 284 if (!(sc->sc_features & HIL_ABSOLUTE)) 285 dz = (int16_t)dz; 286 } else { 287 dz = *buf++; 288 if (!(sc->sc_features & HIL_ABSOLUTE)) 289 dz = (int8_t)dz; 290 } 291 } else 292 dz = 0; 293 } else 294 dy = dz = 0; 295 296 /* 297 * Correct Y direction for button boxes. 298 */ 299 if ((sc->sc_features & HIL_ABSOLUTE) == 0 && 300 sc->sc_buttons == 0) 301 dy = -dy; 302 } else 303 dx = dy = dz = flags = 0; 304 305 if (type & HIL_MOUSEBUTTON) { 306 button = *buf; 307 /* 308 * The pressure sensor is very primitive and only has 309 * a boolean behaviour, as an extra mouse button, which is 310 * down if there is pressure or the pen is near the tablet, 311 * and up if there is no pressure or the pen is far from the 312 * tablet - at least for Tablet id 0x94, P/N 46088B 313 * 314 * The corresponding codes are 0x8f and 0x8e. Convert them 315 * to a pseudo fourth button - even if the tablet never 316 * has three buttons. 317 */ 318 button = (button - 0x80) >> 1; 319 if (button > 4) 320 button = 4; 321 322 if (*buf & 1) { 323 /* Button released, or no pressure */ 324 sc->sc_buttonstate &= ~(1 << button); 325 } else { 326 /* Button pressed, or pressure */ 327 sc->sc_buttonstate |= (1 << button); 328 } 329 /* buf++; */ 330 } 331 332 if (sc->sc_wsmousedev != NULL) 333 wsmouse_input(sc->sc_wsmousedev, 334 sc->sc_buttonstate, dx, dy, dz, 0, flags); 335} 336