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