1 1.33 andvar /* $NetBSD: moused.c,v 1.33 2025/07/11 22:19:54 andvar Exp $ */ 2 1.1 augustss /** 3 1.1 augustss ** Copyright (c) 1995 Michael Smith, All rights reserved. 4 1.1 augustss ** 5 1.1 augustss ** Redistribution and use in source and binary forms, with or without 6 1.1 augustss ** modification, are permitted provided that the following conditions 7 1.1 augustss ** are met: 8 1.1 augustss ** 1. Redistributions of source code must retain the above copyright 9 1.1 augustss ** notice, this list of conditions and the following disclaimer as 10 1.1 augustss ** the first lines of this file unmodified. 11 1.1 augustss ** 2. Redistributions in binary form must reproduce the above copyright 12 1.1 augustss ** notice, this list of conditions and the following disclaimer in the 13 1.1 augustss ** documentation and/or other materials provided with the distribution. 14 1.1 augustss ** 3. All advertising materials mentioning features or use of this software 15 1.1 augustss ** must display the following acknowledgment: 16 1.1 augustss ** This product includes software developed by Michael Smith. 17 1.1 augustss ** 4. The name of the author may not be used to endorse or promote products 18 1.1 augustss ** derived from this software without specific prior written permission. 19 1.1 augustss ** 20 1.1 augustss ** 21 1.1 augustss ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY 22 1.1 augustss ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 augustss ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 augustss ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR 25 1.1 augustss ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 augustss ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 augustss ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 1.1 augustss ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 1.1 augustss ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 1.1 augustss ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 1.1 augustss ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 1.1 augustss ** 33 1.1 augustss **/ 34 1.1 augustss 35 1.1 augustss /** 36 1.1 augustss ** MOUSED.C 37 1.1 augustss ** 38 1.1 augustss ** Mouse daemon : listens to a serial port, the bus mouse interface, or 39 1.1 augustss ** the PS/2 mouse port for mouse data stream, interprets data and passes 40 1.1 augustss ** ioctls off to the console driver. 41 1.1 augustss ** 42 1.1 augustss ** The mouse interface functions are derived closely from the mouse 43 1.1 augustss ** handler in the XFree86 X server. Many thanks to the XFree86 people 44 1.1 augustss ** for their great work! 45 1.1 augustss ** 46 1.1 augustss **/ 47 1.1 augustss 48 1.3 gmcgarry #include <sys/cdefs.h> 49 1.3 gmcgarry 50 1.1 augustss #ifndef lint 51 1.33 andvar __RCSID("$NetBSD: moused.c,v 1.33 2025/07/11 22:19:54 andvar Exp $"); 52 1.1 augustss #endif /* not lint */ 53 1.1 augustss 54 1.1 augustss #include <ctype.h> 55 1.1 augustss #include <err.h> 56 1.1 augustss #include <errno.h> 57 1.1 augustss #include <fcntl.h> 58 1.1 augustss #include <limits.h> 59 1.1 augustss #include <stdio.h> 60 1.1 augustss #include <stdlib.h> 61 1.1 augustss #include <stdarg.h> 62 1.1 augustss #include <string.h> 63 1.1 augustss #include <signal.h> 64 1.1 augustss #include <setjmp.h> 65 1.1 augustss #include <termios.h> 66 1.1 augustss #include <syslog.h> 67 1.1 augustss #include "mouse.h" 68 1.1 augustss #include <sys/ioctl.h> 69 1.1 augustss #include <dev/wscons/wsconsio.h> 70 1.1 augustss #include <sys/types.h> 71 1.1 augustss #include <sys/time.h> 72 1.1 augustss #include <sys/socket.h> 73 1.22 christos #include <stdint.h> 74 1.1 augustss #include <sys/un.h> 75 1.10 itojun #include <poll.h> 76 1.1 augustss #include <unistd.h> 77 1.1 augustss 78 1.1 augustss #define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */ 79 1.1 augustss #define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */ 80 1.1 augustss #define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */ 81 1.1 augustss #define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */ 82 1.1 augustss 83 1.1 augustss /* Abort 3-button emulation delay after this many movement events. */ 84 1.1 augustss #define BUTTON2_MAXMOVE 3 85 1.1 augustss 86 1.1 augustss #define TRUE 1 87 1.1 augustss #define FALSE 0 88 1.1 augustss 89 1.1 augustss #define MOUSE_XAXIS (-1) 90 1.1 augustss #define MOUSE_YAXIS (-2) 91 1.1 augustss 92 1.1 augustss /* Logitech PS2++ protocol */ 93 1.1 augustss #define MOUSE_PS2PLUS_CHECKBITS(b) \ 94 1.1 augustss ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f)) 95 1.1 augustss #define MOUSE_PS2PLUS_PACKET_TYPE(b) \ 96 1.1 augustss (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) 97 1.1 augustss 98 1.1 augustss #define ChordMiddle 0x0001 99 1.1 augustss #define Emulate3Button 0x0002 100 1.1 augustss #define ClearDTR 0x0004 101 1.1 augustss #define ClearRTS 0x0008 102 1.1 augustss #define NoPnP 0x0010 103 1.1 augustss 104 1.1 augustss #define ID_NONE 0 105 1.1 augustss #define ID_PORT 1 106 1.1 augustss #define ID_IF 2 107 1.1 augustss #define ID_TYPE 4 108 1.1 augustss #define ID_MODEL 8 109 1.1 augustss #define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL) 110 1.1 augustss 111 1.1 augustss /* structures */ 112 1.1 augustss 113 1.1 augustss /* symbol table entry */ 114 1.1 augustss typedef struct { 115 1.18 lukem const char *name; 116 1.1 augustss int val; 117 1.1 augustss int val2; 118 1.1 augustss } symtab_t; 119 1.1 augustss 120 1.1 augustss /* serial PnP ID string */ 121 1.1 augustss typedef struct { 122 1.1 augustss int revision; /* PnP revision, 100 for 1.00 */ 123 1.18 lukem const char *eisaid; /* EISA ID including mfr ID and product ID */ 124 1.18 lukem const char *serial; /* serial No, optional */ 125 1.18 lukem const char *class; /* device class, optional */ 126 1.18 lukem const char *compat; /* list of compatible drivers, optional */ 127 1.18 lukem const char *description; /* product description, optional */ 128 1.1 augustss int neisaid; /* length of the above fields... */ 129 1.1 augustss int nserial; 130 1.1 augustss int nclass; 131 1.1 augustss int ncompat; 132 1.1 augustss int ndescription; 133 1.1 augustss } pnpid_t; 134 1.1 augustss 135 1.1 augustss /* global variables */ 136 1.1 augustss 137 1.19 joerg static int dbg = 0; 138 1.19 joerg static int nodaemon = FALSE; 139 1.19 joerg static int background = FALSE; 140 1.19 joerg static int identify = ID_NONE; 141 1.19 joerg static const char *pidfile = "/var/run/moused.pid"; 142 1.1 augustss 143 1.1 augustss /* local variables */ 144 1.1 augustss 145 1.1 augustss /* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */ 146 1.1 augustss static symtab_t rifs[] = { 147 1.18 lukem { "serial", MOUSE_IF_SERIAL, 0 }, 148 1.18 lukem { "bus", MOUSE_IF_BUS, 0 }, 149 1.18 lukem { "inport", MOUSE_IF_INPORT, 0 }, 150 1.18 lukem { "ps/2", MOUSE_IF_PS2, 0 }, 151 1.18 lukem { "sysmouse", MOUSE_IF_SYSMOUSE, 0 }, 152 1.18 lukem { "usb", MOUSE_IF_USB, 0 }, 153 1.18 lukem { NULL, MOUSE_IF_UNKNOWN, 0 }, 154 1.1 augustss }; 155 1.1 augustss 156 1.1 augustss /* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */ 157 1.18 lukem static const char *rnames[] = { 158 1.1 augustss "microsoft", 159 1.1 augustss "mousesystems", 160 1.1 augustss "logitech", 161 1.1 augustss "mmseries", 162 1.1 augustss "mouseman", 163 1.1 augustss "busmouse", 164 1.1 augustss "inportmouse", 165 1.1 augustss "ps/2", 166 1.1 augustss "mmhitab", 167 1.1 augustss "glidepoint", 168 1.1 augustss "intellimouse", 169 1.1 augustss "thinkingmouse", 170 1.1 augustss "sysmouse", 171 1.1 augustss "x10mouseremote", 172 1.1 augustss "kidspad", 173 1.1 augustss #if notyet 174 1.1 augustss "mariqua", 175 1.1 augustss #endif 176 1.1 augustss NULL 177 1.1 augustss }; 178 1.1 augustss 179 1.1 augustss /* models */ 180 1.1 augustss static symtab_t rmodels[] = { 181 1.18 lukem { "NetScroll", MOUSE_MODEL_NETSCROLL, 0 }, 182 1.18 lukem { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET, 0 }, 183 1.18 lukem { "GlidePoint", MOUSE_MODEL_GLIDEPOINT, 0 }, 184 1.18 lukem { "ThinkingMouse", MOUSE_MODEL_THINK, 0 }, 185 1.18 lukem { "IntelliMouse", MOUSE_MODEL_INTELLI, 0 }, 186 1.18 lukem { "EasyScroll/SmartScroll", MOUSE_MODEL_EASYSCROLL, 0 }, 187 1.18 lukem { "MouseMan+", MOUSE_MODEL_MOUSEMANPLUS, 0 }, 188 1.18 lukem { "Kidspad", MOUSE_MODEL_KIDSPAD, 0 }, 189 1.18 lukem { "VersaPad", MOUSE_MODEL_VERSAPAD, 0 }, 190 1.18 lukem { "IntelliMouse Explorer", MOUSE_MODEL_EXPLORER, 0 }, 191 1.18 lukem { "4D Mouse", MOUSE_MODEL_4D, 0 }, 192 1.18 lukem { "4D+ Mouse", MOUSE_MODEL_4DPLUS, 0 }, 193 1.18 lukem { "generic", MOUSE_MODEL_GENERIC, 0 }, 194 1.18 lukem { NULL, MOUSE_MODEL_UNKNOWN, 0 }, 195 1.1 augustss }; 196 1.1 augustss 197 1.1 augustss /* PnP EISA/product IDs */ 198 1.1 augustss static symtab_t pnpprod[] = { 199 1.1 augustss /* Kensignton ThinkingMouse */ 200 1.1 augustss { "KML0001", MOUSE_PROTO_THINK, MOUSE_MODEL_THINK }, 201 1.1 augustss /* MS IntelliMouse */ 202 1.1 augustss { "MSH0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 203 1.1 augustss /* MS IntelliMouse TrackBall */ 204 1.1 augustss { "MSH0004", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 205 1.1 augustss /* Tremon Wheel Mouse MUSD */ 206 1.1 augustss { "HTK0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 207 1.1 augustss /* Genius PnP Mouse */ 208 1.1 augustss { "KYE0001", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 209 1.1 augustss /* MouseSystems SmartScroll Mouse (OEM from Genius?) */ 210 1.1 augustss { "KYE0002", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL }, 211 1.1 augustss /* Genius NetMouse */ 212 1.1 augustss { "KYE0003", MOUSE_PROTO_INTELLI, MOUSE_MODEL_NET }, 213 1.1 augustss /* Genius Kidspad, Easypad and other tablets */ 214 1.1 augustss { "KYE0005", MOUSE_PROTO_KIDSPAD, MOUSE_MODEL_KIDSPAD }, 215 1.1 augustss /* Genius EZScroll */ 216 1.1 augustss { "KYEEZ00", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL }, 217 1.1 augustss /* Logitech Cordless MouseMan Wheel */ 218 1.1 augustss { "LGI8033", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 219 1.1 augustss /* Logitech MouseMan (new 4 button model) */ 220 1.1 augustss { "LGI800C", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 221 1.1 augustss /* Logitech MouseMan+ */ 222 1.1 augustss { "LGI8050", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 223 1.1 augustss /* Logitech FirstMouse+ */ 224 1.1 augustss { "LGI8051", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 225 1.1 augustss /* Logitech serial */ 226 1.1 augustss { "LGI8001", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 227 1.1 augustss /* A4 Tech 4D/4D+ Mouse */ 228 1.1 augustss { "A4W0005", MOUSE_PROTO_INTELLI, MOUSE_MODEL_4D }, 229 1.1 augustss /* 8D Scroll Mouse */ 230 1.1 augustss { "PEC9802", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 231 1.1 augustss /* Mitsumi Wireless Scroll Mouse */ 232 1.1 augustss { "MTM6401", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 233 1.1 augustss 234 1.1 augustss /* MS bus */ 235 1.1 augustss { "PNP0F00", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 236 1.1 augustss /* MS serial */ 237 1.1 augustss { "PNP0F01", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 238 1.1 augustss /* MS InPort */ 239 1.1 augustss { "PNP0F02", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC }, 240 1.1 augustss /* MS PS/2 */ 241 1.1 augustss { "PNP0F03", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 242 1.1 augustss /* 243 1.1 augustss * EzScroll returns PNP0F04 in the compatible device field; but it 244 1.1 augustss * doesn't look compatible... XXX 245 1.1 augustss */ 246 1.1 augustss /* MouseSystems */ 247 1.1 augustss { "PNP0F04", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC }, 248 1.1 augustss /* MouseSystems */ 249 1.1 augustss { "PNP0F05", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC }, 250 1.1 augustss #if notyet 251 1.1 augustss /* Genius Mouse */ 252 1.1 augustss { "PNP0F06", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 253 1.1 augustss /* Genius Mouse */ 254 1.1 augustss { "PNP0F07", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 255 1.1 augustss #endif 256 1.1 augustss /* Logitech serial */ 257 1.1 augustss { "PNP0F08", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 258 1.1 augustss /* MS BallPoint serial */ 259 1.1 augustss { "PNP0F09", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 260 1.1 augustss /* MS PnP serial */ 261 1.1 augustss { "PNP0F0A", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 262 1.1 augustss /* MS PnP BallPoint serial */ 263 1.1 augustss { "PNP0F0B", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 264 1.28 andvar /* MS serial compatible */ 265 1.1 augustss { "PNP0F0C", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 266 1.28 andvar /* MS InPort compatible */ 267 1.1 augustss { "PNP0F0D", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC }, 268 1.28 andvar /* MS PS/2 compatible */ 269 1.1 augustss { "PNP0F0E", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 270 1.28 andvar /* MS BallPoint compatible */ 271 1.1 augustss { "PNP0F0F", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 272 1.1 augustss #if notyet 273 1.1 augustss /* TI QuickPort */ 274 1.1 augustss { "PNP0F10", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 275 1.1 augustss #endif 276 1.28 andvar /* MS bus compatible */ 277 1.1 augustss { "PNP0F11", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 278 1.1 augustss /* Logitech PS/2 */ 279 1.1 augustss { "PNP0F12", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 280 1.1 augustss /* PS/2 */ 281 1.1 augustss { "PNP0F13", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 282 1.1 augustss #if notyet 283 1.1 augustss /* MS Kids Mouse */ 284 1.1 augustss { "PNP0F14", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 285 1.1 augustss #endif 286 1.1 augustss /* Logitech bus */ 287 1.1 augustss { "PNP0F15", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 288 1.1 augustss #if notyet 289 1.1 augustss /* Logitech SWIFT */ 290 1.1 augustss { "PNP0F16", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 291 1.1 augustss #endif 292 1.1 augustss /* Logitech serial compat */ 293 1.1 augustss { "PNP0F17", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 294 1.1 augustss /* Logitech bus compatible */ 295 1.1 augustss { "PNP0F18", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 296 1.1 augustss /* Logitech PS/2 compatible */ 297 1.1 augustss { "PNP0F19", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 298 1.1 augustss #if notyet 299 1.1 augustss /* Logitech SWIFT compatible */ 300 1.1 augustss { "PNP0F1A", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 301 1.1 augustss /* HP Omnibook */ 302 1.1 augustss { "PNP0F1B", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 303 1.1 augustss /* Compaq LTE TrackBall PS/2 */ 304 1.1 augustss { "PNP0F1C", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 305 1.1 augustss /* Compaq LTE TrackBall serial */ 306 1.1 augustss { "PNP0F1D", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 307 1.1 augustss /* MS Kidts Trackball */ 308 1.1 augustss { "PNP0F1E", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC }, 309 1.1 augustss #endif 310 1.1 augustss /* Interlink VersaPad */ 311 1.1 augustss { "LNK0001", MOUSE_PROTO_VERSAPAD, MOUSE_MODEL_VERSAPAD }, 312 1.1 augustss 313 1.1 augustss { NULL, MOUSE_PROTO_UNKNOWN, MOUSE_MODEL_GENERIC }, 314 1.1 augustss }; 315 1.1 augustss 316 1.1 augustss /* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */ 317 1.1 augustss static unsigned short rodentcflags[] = 318 1.1 augustss { 319 1.1 augustss (CS7 | CREAD | CLOCAL | HUPCL ), /* MicroSoft */ 320 1.1 augustss (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* MouseSystems */ 321 1.1 augustss (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* Logitech */ 322 1.1 augustss (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ), /* MMSeries */ 323 1.1 augustss (CS7 | CREAD | CLOCAL | HUPCL ), /* MouseMan */ 324 1.1 augustss 0, /* Bus */ 325 1.1 augustss 0, /* InPort */ 326 1.1 augustss 0, /* PS/2 */ 327 1.1 augustss (CS8 | CREAD | CLOCAL | HUPCL ), /* MM HitTablet */ 328 1.1 augustss (CS7 | CREAD | CLOCAL | HUPCL ), /* GlidePoint */ 329 1.1 augustss (CS7 | CREAD | CLOCAL | HUPCL ), /* IntelliMouse */ 330 1.1 augustss (CS7 | CREAD | CLOCAL | HUPCL ), /* Thinking Mouse */ 331 1.1 augustss (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* sysmouse */ 332 1.1 augustss (CS7 | CREAD | CLOCAL | HUPCL ), /* X10 MouseRemote */ 333 1.1 augustss (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ), /* kidspad etc. */ 334 1.1 augustss (CS8 | CREAD | CLOCAL | HUPCL ), /* VersaPad */ 335 1.1 augustss #if notyet 336 1.1 augustss (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* Mariqua */ 337 1.1 augustss #endif 338 1.1 augustss }; 339 1.1 augustss 340 1.1 augustss static struct rodentparam { 341 1.1 augustss int flags; 342 1.1 augustss char *portname; /* /dev/XXX */ 343 1.1 augustss int rtype; /* MOUSE_PROTO_XXX */ 344 1.1 augustss int level; /* operation level: 0 or greater */ 345 1.1 augustss int baudrate; 346 1.1 augustss int rate; /* report rate */ 347 1.1 augustss int resolution; /* MOUSE_RES_XXX or a positive number */ 348 1.1 augustss int zmap[4]; /* MOUSE_{X|Y}AXIS or a button number */ 349 1.1 augustss int wmode; /* wheel mode button number */ 350 1.1 augustss int mfd; /* mouse file descriptor */ 351 1.1 augustss int cfd; /* /dev/wsmousectl file descriptor */ 352 1.1 augustss int mremsfd; /* mouse remote server file descriptor */ 353 1.1 augustss int mremcfd; /* mouse remote client file descriptor */ 354 1.1 augustss long clickthreshold; /* double click speed in msec */ 355 1.1 augustss long button2timeout; /* 3 button emulation timeout */ 356 1.1 augustss mousehw_t hw; /* mouse device hardware information */ 357 1.1 augustss mousemode_t mode; /* protocol information */ 358 1.1 augustss float accelx; /* Acceleration in the X axis */ 359 1.1 augustss float accely; /* Acceleration in the Y axis */ 360 1.1 augustss } rodent = { 361 1.17 gmcgarry .flags = 0, 362 1.17 gmcgarry .portname = NULL, 363 1.17 gmcgarry .rtype = MOUSE_PROTO_UNKNOWN, 364 1.17 gmcgarry .level = -1, 365 1.17 gmcgarry .baudrate = 1200, 366 1.17 gmcgarry .rate = 0, 367 1.17 gmcgarry .resolution = MOUSE_RES_UNKNOWN, 368 1.17 gmcgarry .zmap = { 0, 0, 0, 0 }, 369 1.17 gmcgarry .wmode = 0, 370 1.17 gmcgarry .mfd = -1, 371 1.17 gmcgarry .cfd = -1, 372 1.17 gmcgarry .mremsfd = -1, 373 1.17 gmcgarry .mremcfd = -1, 374 1.17 gmcgarry .clickthreshold = DFLT_CLICKTHRESHOLD, 375 1.17 gmcgarry .button2timeout = DFLT_BUTTON2TIMEOUT, 376 1.17 gmcgarry .accelx = 1.0, 377 1.17 gmcgarry .accely = 1.0, 378 1.1 augustss }; 379 1.1 augustss 380 1.1 augustss /* button status */ 381 1.1 augustss struct button_state { 382 1.1 augustss int count; /* 0: up, 1: single click, 2: double click,... */ 383 1.1 augustss struct timeval tv; /* timestamp on the last button event */ 384 1.1 augustss }; 385 1.1 augustss static struct button_state bstate[MOUSE_MAXBUTTON]; /* button state */ 386 1.1 augustss static struct button_state *mstate[MOUSE_MAXBUTTON];/* mapped button st.*/ 387 1.1 augustss static struct button_state zstate[4]; /* Z/W axis state */ 388 1.1 augustss 389 1.1 augustss /* state machine for 3 button emulation */ 390 1.1 augustss 391 1.1 augustss #define S0 0 /* start */ 392 1.1 augustss #define S1 1 /* button 1 delayed down */ 393 1.1 augustss #define S2 2 /* button 3 delayed down */ 394 1.1 augustss #define S3 3 /* both buttons down -> button 2 down */ 395 1.1 augustss #define S4 4 /* button 1 delayed up */ 396 1.1 augustss #define S5 5 /* button 1 down */ 397 1.1 augustss #define S6 6 /* button 3 down */ 398 1.1 augustss #define S7 7 /* both buttons down */ 399 1.1 augustss #define S8 8 /* button 3 delayed up */ 400 1.1 augustss #define S9 9 /* button 1 or 3 up after S3 */ 401 1.1 augustss 402 1.1 augustss #define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0)) 403 1.1 augustss #define A_TIMEOUT 4 404 1.1 augustss #define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st)) 405 1.1 augustss 406 1.1 augustss static struct { 407 1.1 augustss int s[A_TIMEOUT + 1]; 408 1.1 augustss int buttons; 409 1.1 augustss int mask; 410 1.1 augustss int timeout; 411 1.1 augustss } states[10] = { 412 1.1 augustss /* S0 */ 413 1.1 augustss { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE }, 414 1.1 augustss /* S1 */ 415 1.1 augustss { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE }, 416 1.1 augustss /* S2 */ 417 1.1 augustss { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE }, 418 1.1 augustss /* S3 */ 419 1.1 augustss { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE }, 420 1.1 augustss /* S4 */ 421 1.1 augustss { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE }, 422 1.1 augustss /* S5 */ 423 1.1 augustss { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE }, 424 1.1 augustss /* S6 */ 425 1.1 augustss { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE }, 426 1.1 augustss /* S7 */ 427 1.1 augustss { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE }, 428 1.1 augustss /* S8 */ 429 1.1 augustss { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE }, 430 1.1 augustss /* S9 */ 431 1.1 augustss { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE }, 432 1.1 augustss }; 433 1.1 augustss static int mouse_button_state; 434 1.1 augustss static struct timeval mouse_button_state_tv; 435 1.1 augustss static int mouse_move_delayed; 436 1.1 augustss 437 1.1 augustss static jmp_buf env; 438 1.1 augustss 439 1.1 augustss /* function prototypes */ 440 1.1 augustss 441 1.18 lukem static void moused(const char *); 442 1.19 joerg __dead static void hup(int sig); 443 1.19 joerg __dead static void cleanup(int sig); 444 1.19 joerg __dead static void usage(void); 445 1.1 augustss 446 1.1 augustss static int r_identify(void); 447 1.18 lukem static const char *r_if(int type); 448 1.18 lukem static const char *r_name(int type); 449 1.18 lukem static const char *r_model(int model); 450 1.1 augustss static void r_init(void); 451 1.1 augustss static int r_protocol(u_char b, mousestatus_t *act); 452 1.1 augustss static int r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans); 453 1.1 augustss static int r_installmap(char *arg); 454 1.1 augustss static void r_map(mousestatus_t *act1, mousestatus_t *act2); 455 1.1 augustss static void r_timestamp(mousestatus_t *act); 456 1.1 augustss static int r_timeout(void); 457 1.1 augustss static void setmousespeed(int old, int new, unsigned cflag); 458 1.1 augustss 459 1.1 augustss static int pnpwakeup1(void); 460 1.1 augustss static int pnpwakeup2(void); 461 1.1 augustss static int pnpgets(char *buf); 462 1.1 augustss static int pnpparse(pnpid_t *id, char *buf, int len); 463 1.1 augustss static symtab_t *pnpproto(pnpid_t *id); 464 1.1 augustss 465 1.18 lukem static symtab_t *gettoken(symtab_t *tab, const char *s, int len); 466 1.18 lukem static const char *gettokenname(symtab_t *tab, int val); 467 1.1 augustss 468 1.1 augustss static void wsev(int ty, int val); 469 1.1 augustss 470 1.1 augustss static int kidspad(u_char rxc, mousestatus_t *act); 471 1.1 augustss 472 1.19 joerg __printflike(1, 2) static void 473 1.5 thorpej debug(const char *fmt, ...) 474 1.5 thorpej { 475 1.5 thorpej va_list ap; 476 1.5 thorpej 477 1.5 thorpej va_start(ap, fmt); 478 1.5 thorpej if (dbg && nodaemon) 479 1.5 thorpej vwarnx(fmt, ap); 480 1.5 thorpej va_end(ap); 481 1.5 thorpej } 482 1.5 thorpej 483 1.19 joerg __dead __printflike(2, 3) static void 484 1.5 thorpej logerr(int e, const char *fmt, ...) 485 1.5 thorpej { 486 1.5 thorpej va_list ap; 487 1.5 thorpej 488 1.5 thorpej va_start(ap, fmt); 489 1.5 thorpej if (background) { 490 1.5 thorpej int saveerrno = errno; 491 1.5 thorpej vsyslog(LOG_DAEMON | LOG_ERR, fmt, ap); 492 1.5 thorpej errno = saveerrno; 493 1.5 thorpej syslog(LOG_DAEMON | LOG_ERR, "%m"); 494 1.5 thorpej exit(e); 495 1.5 thorpej } else 496 1.5 thorpej verr(e, fmt, ap); 497 1.5 thorpej va_end(ap); 498 1.5 thorpej } 499 1.5 thorpej 500 1.19 joerg __printflike(1, 2) static void 501 1.5 thorpej logwarn(const char *fmt, ...) 502 1.5 thorpej { 503 1.5 thorpej va_list ap; 504 1.5 thorpej 505 1.5 thorpej va_start(ap, fmt); 506 1.5 thorpej if (background) { 507 1.5 thorpej int saveerrno = errno; 508 1.5 thorpej vsyslog(LOG_DAEMON | LOG_WARNING, fmt, ap); 509 1.5 thorpej errno = saveerrno; 510 1.5 thorpej syslog(LOG_DAEMON | LOG_WARNING, "%m"); 511 1.5 thorpej } else 512 1.5 thorpej vwarn(fmt, ap); 513 1.5 thorpej va_end(ap); 514 1.5 thorpej } 515 1.5 thorpej 516 1.19 joerg __printflike(1, 2) static void 517 1.5 thorpej logwarnx(const char *fmt, ...) 518 1.5 thorpej { 519 1.5 thorpej va_list ap; 520 1.5 thorpej 521 1.5 thorpej va_start(ap, fmt); 522 1.5 thorpej if (background) 523 1.5 thorpej vsyslog(LOG_DAEMON | LOG_WARNING, fmt, ap); 524 1.5 thorpej else 525 1.5 thorpej vwarnx(fmt, ap); 526 1.5 thorpej va_end(ap); 527 1.5 thorpej } 528 1.5 thorpej 529 1.1 augustss int 530 1.1 augustss main(int argc, char *argv[]) 531 1.1 augustss { 532 1.1 augustss int c; 533 1.1 augustss int i; 534 1.1 augustss int j; 535 1.18 lukem const char * volatile ctldev = "/dev/wsmuxctl0"; 536 1.1 augustss 537 1.1 augustss for (i = 0; i < MOUSE_MAXBUTTON; ++i) 538 1.1 augustss mstate[i] = &bstate[i]; 539 1.1 augustss 540 1.1 augustss while((c = getopt(argc,argv,"3DE:F:I:PRS:W:a:cdfhi:l:m:p:r:st:w:z:")) != -1) 541 1.1 augustss switch(c) { 542 1.1 augustss 543 1.1 augustss case 'W': 544 1.1 augustss ctldev = optarg; 545 1.1 augustss break; 546 1.1 augustss 547 1.1 augustss case '3': 548 1.1 augustss rodent.flags |= Emulate3Button; 549 1.1 augustss break; 550 1.1 augustss 551 1.1 augustss case 'E': 552 1.1 augustss rodent.button2timeout = atoi(optarg); 553 1.1 augustss if ((rodent.button2timeout < 0) || 554 1.1 augustss (rodent.button2timeout > MAX_BUTTON2TIMEOUT)) { 555 1.1 augustss warnx("invalid argument `%s'", optarg); 556 1.1 augustss usage(); 557 1.1 augustss } 558 1.1 augustss break; 559 1.1 augustss 560 1.1 augustss case 'a': 561 1.1 augustss i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely); 562 1.1 augustss if (i == 0) { 563 1.1 augustss warnx("invalid acceleration argument '%s'", optarg); 564 1.1 augustss usage(); 565 1.1 augustss } 566 1.1 augustss 567 1.1 augustss if (i == 1) 568 1.1 augustss rodent.accely = rodent.accelx; 569 1.1 augustss 570 1.1 augustss break; 571 1.1 augustss 572 1.1 augustss case 'c': 573 1.1 augustss rodent.flags |= ChordMiddle; 574 1.1 augustss break; 575 1.1 augustss 576 1.1 augustss case 'd': 577 1.5 thorpej ++dbg; 578 1.1 augustss break; 579 1.1 augustss 580 1.1 augustss case 'f': 581 1.1 augustss nodaemon = TRUE; 582 1.1 augustss break; 583 1.1 augustss 584 1.1 augustss case 'i': 585 1.1 augustss if (strcmp(optarg, "all") == 0) 586 1.1 augustss identify = ID_ALL; 587 1.1 augustss else if (strcmp(optarg, "port") == 0) 588 1.1 augustss identify = ID_PORT; 589 1.1 augustss else if (strcmp(optarg, "if") == 0) 590 1.1 augustss identify = ID_IF; 591 1.1 augustss else if (strcmp(optarg, "type") == 0) 592 1.1 augustss identify = ID_TYPE; 593 1.1 augustss else if (strcmp(optarg, "model") == 0) 594 1.1 augustss identify = ID_MODEL; 595 1.1 augustss else { 596 1.1 augustss warnx("invalid argument `%s'", optarg); 597 1.1 augustss usage(); 598 1.1 augustss } 599 1.1 augustss nodaemon = TRUE; 600 1.1 augustss break; 601 1.1 augustss 602 1.1 augustss case 'l': 603 1.1 augustss rodent.level = atoi(optarg); 604 1.1 augustss if ((rodent.level < 0) || (rodent.level > 4)) { 605 1.1 augustss warnx("invalid argument `%s'", optarg); 606 1.1 augustss usage(); 607 1.1 augustss } 608 1.1 augustss break; 609 1.1 augustss 610 1.1 augustss case 'm': 611 1.1 augustss if (!r_installmap(optarg)) { 612 1.1 augustss warnx("invalid argument `%s'", optarg); 613 1.1 augustss usage(); 614 1.1 augustss } 615 1.1 augustss break; 616 1.1 augustss 617 1.1 augustss case 'p': 618 1.1 augustss rodent.portname = optarg; 619 1.1 augustss break; 620 1.1 augustss 621 1.1 augustss case 'r': 622 1.1 augustss if (strcmp(optarg, "high") == 0) 623 1.1 augustss rodent.resolution = MOUSE_RES_HIGH; 624 1.1 augustss else if (strcmp(optarg, "medium-high") == 0) 625 1.1 augustss rodent.resolution = MOUSE_RES_HIGH; 626 1.1 augustss else if (strcmp(optarg, "medium-low") == 0) 627 1.1 augustss rodent.resolution = MOUSE_RES_MEDIUMLOW; 628 1.1 augustss else if (strcmp(optarg, "low") == 0) 629 1.1 augustss rodent.resolution = MOUSE_RES_LOW; 630 1.1 augustss else if (strcmp(optarg, "default") == 0) 631 1.1 augustss rodent.resolution = MOUSE_RES_DEFAULT; 632 1.1 augustss else { 633 1.1 augustss rodent.resolution = atoi(optarg); 634 1.1 augustss if (rodent.resolution <= 0) { 635 1.1 augustss warnx("invalid argument `%s'", optarg); 636 1.1 augustss usage(); 637 1.1 augustss } 638 1.1 augustss } 639 1.1 augustss break; 640 1.1 augustss 641 1.1 augustss case 's': 642 1.1 augustss rodent.baudrate = 9600; 643 1.1 augustss break; 644 1.1 augustss 645 1.1 augustss case 'w': 646 1.1 augustss i = atoi(optarg); 647 1.1 augustss if ((i <= 0) || (i > MOUSE_MAXBUTTON)) { 648 1.1 augustss warnx("invalid argument `%s'", optarg); 649 1.1 augustss usage(); 650 1.1 augustss } 651 1.1 augustss rodent.wmode = 1 << (i - 1); 652 1.1 augustss break; 653 1.1 augustss 654 1.1 augustss case 'z': 655 1.1 augustss if (strcmp(optarg, "x") == 0) 656 1.1 augustss rodent.zmap[0] = MOUSE_XAXIS; 657 1.1 augustss else if (strcmp(optarg, "y") == 0) 658 1.1 augustss rodent.zmap[0] = MOUSE_YAXIS; 659 1.1 augustss else { 660 1.1 augustss i = atoi(optarg); 661 1.1 augustss /* 662 1.1 augustss * Use button i for negative Z axis movement and 663 1.1 augustss * button (i + 1) for positive Z axis movement. 664 1.1 augustss */ 665 1.1 augustss if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) { 666 1.1 augustss warnx("invalid argument `%s'", optarg); 667 1.1 augustss usage(); 668 1.1 augustss } 669 1.1 augustss rodent.zmap[0] = i; 670 1.1 augustss rodent.zmap[1] = i + 1; 671 1.1 augustss debug("optind: %d, optarg: '%s'", optind, optarg); 672 1.1 augustss for (j = 1; j < 4; ++j) { 673 1.14 dsl if ((optind >= argc) || !isdigit((unsigned char)*argv[optind])) 674 1.1 augustss break; 675 1.1 augustss i = atoi(argv[optind]); 676 1.1 augustss if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) { 677 1.1 augustss warnx("invalid argument `%s'", argv[optind]); 678 1.1 augustss usage(); 679 1.1 augustss } 680 1.1 augustss rodent.zmap[j] = i; 681 1.1 augustss ++optind; 682 1.1 augustss } 683 1.1 augustss if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0)) 684 1.1 augustss rodent.zmap[3] = rodent.zmap[2] + 1; 685 1.1 augustss } 686 1.1 augustss break; 687 1.1 augustss 688 1.1 augustss case 'D': 689 1.1 augustss rodent.flags |= ClearDTR; 690 1.1 augustss break; 691 1.1 augustss 692 1.1 augustss case 'F': 693 1.1 augustss rodent.rate = atoi(optarg); 694 1.1 augustss if (rodent.rate <= 0) { 695 1.1 augustss warnx("invalid argument `%s'", optarg); 696 1.1 augustss usage(); 697 1.1 augustss } 698 1.1 augustss break; 699 1.1 augustss 700 1.1 augustss case 'I': 701 1.1 augustss pidfile = optarg; 702 1.1 augustss break; 703 1.1 augustss 704 1.1 augustss case 'P': 705 1.1 augustss rodent.flags |= NoPnP; 706 1.1 augustss break; 707 1.1 augustss 708 1.1 augustss case 'R': 709 1.1 augustss rodent.flags |= ClearRTS; 710 1.1 augustss break; 711 1.1 augustss 712 1.1 augustss case 'S': 713 1.1 augustss rodent.baudrate = atoi(optarg); 714 1.1 augustss if (rodent.baudrate <= 0) { 715 1.1 augustss warnx("invalid argument `%s'", optarg); 716 1.1 augustss usage(); 717 1.1 augustss } 718 1.1 augustss debug("rodent baudrate %d", rodent.baudrate); 719 1.1 augustss break; 720 1.1 augustss 721 1.1 augustss case 't': 722 1.1 augustss if (strcmp(optarg, "auto") == 0) { 723 1.1 augustss rodent.rtype = MOUSE_PROTO_UNKNOWN; 724 1.1 augustss rodent.flags &= ~NoPnP; 725 1.1 augustss rodent.level = -1; 726 1.1 augustss break; 727 1.1 augustss } 728 1.1 augustss for (i = 0; rnames[i]; i++) 729 1.1 augustss if (strcmp(optarg, rnames[i]) == 0) { 730 1.1 augustss rodent.rtype = i; 731 1.1 augustss rodent.flags |= NoPnP; 732 1.1 augustss rodent.level = (i == MOUSE_PROTO_SYSMOUSE) ? 1 : 0; 733 1.1 augustss break; 734 1.1 augustss } 735 1.1 augustss if (rnames[i]) 736 1.1 augustss break; 737 1.1 augustss warnx("no such mouse type `%s'", optarg); 738 1.1 augustss usage(); 739 1.1 augustss 740 1.1 augustss case 'h': 741 1.1 augustss case '?': 742 1.1 augustss default: 743 1.1 augustss usage(); 744 1.1 augustss } 745 1.1 augustss 746 1.1 augustss /* fix Z axis mapping */ 747 1.1 augustss for (i = 0; i < 4; ++i) { 748 1.1 augustss if (rodent.zmap[i] > 0) { 749 1.1 augustss for (j = 0; j < MOUSE_MAXBUTTON; ++j) { 750 1.1 augustss if (mstate[j] == &bstate[rodent.zmap[i] - 1]) 751 1.1 augustss mstate[j] = &zstate[i]; 752 1.1 augustss } 753 1.1 augustss rodent.zmap[i] = 1 << (rodent.zmap[i] - 1); 754 1.1 augustss } 755 1.1 augustss } 756 1.1 augustss 757 1.1 augustss /* the default port name */ 758 1.1 augustss switch(rodent.rtype) { 759 1.1 augustss case MOUSE_PROTO_INPORT: 760 1.1 augustss /* INPORT and BUS are the same... */ 761 1.1 augustss rodent.rtype = MOUSE_PROTO_BUS; 762 1.1 augustss /* FALL THROUGH */ 763 1.1 augustss default: 764 1.1 augustss if (rodent.portname) 765 1.1 augustss break; 766 1.1 augustss warnx("no port name specified"); 767 1.1 augustss usage(); 768 1.1 augustss } 769 1.1 augustss 770 1.1 augustss for (;;) { 771 1.1 augustss if (setjmp(env) == 0) { 772 1.1 augustss signal(SIGHUP, hup); 773 1.1 augustss signal(SIGINT , cleanup); 774 1.1 augustss signal(SIGQUIT, cleanup); 775 1.1 augustss signal(SIGTERM, cleanup); 776 1.1 augustss if ((rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK, 0)) 777 1.1 augustss == -1) 778 1.1 augustss logerr(1, "unable to open %s", rodent.portname); 779 1.1 augustss if (r_identify() == MOUSE_PROTO_UNKNOWN) { 780 1.1 augustss logwarnx("cannot determine mouse type on %s", rodent.portname); 781 1.1 augustss close(rodent.mfd); 782 1.1 augustss rodent.mfd = -1; 783 1.1 augustss } 784 1.1 augustss 785 1.1 augustss /* print some information */ 786 1.1 augustss if (identify != ID_NONE) { 787 1.1 augustss if (identify == ID_ALL) 788 1.1 augustss printf("%s %s %s %s\n", 789 1.1 augustss rodent.portname, r_if(rodent.hw.iftype), 790 1.1 augustss r_name(rodent.rtype), r_model(rodent.hw.model)); 791 1.1 augustss else if (identify & ID_PORT) 792 1.1 augustss printf("%s\n", rodent.portname); 793 1.1 augustss else if (identify & ID_IF) 794 1.1 augustss printf("%s\n", r_if(rodent.hw.iftype)); 795 1.1 augustss else if (identify & ID_TYPE) 796 1.1 augustss printf("%s\n", r_name(rodent.rtype)); 797 1.1 augustss else if (identify & ID_MODEL) 798 1.1 augustss printf("%s\n", r_model(rodent.hw.model)); 799 1.1 augustss exit(0); 800 1.1 augustss } else { 801 1.1 augustss debug("port: %s interface: %s type: %s model: %s", 802 1.1 augustss rodent.portname, r_if(rodent.hw.iftype), 803 1.1 augustss r_name(rodent.rtype), r_model(rodent.hw.model)); 804 1.1 augustss } 805 1.1 augustss 806 1.1 augustss if (rodent.mfd == -1) { 807 1.1 augustss /* 808 1.1 augustss * We cannot continue because of error. Exit if the 809 1.1 augustss * program has not become a daemon. Otherwise, block 810 1.13 simonb * until the user corrects the problem and issues SIGHUP. 811 1.1 augustss */ 812 1.1 augustss if (!background) 813 1.1 augustss exit(1); 814 1.1 augustss sigpause(0); 815 1.1 augustss } 816 1.1 augustss 817 1.1 augustss r_init(); /* call init function */ 818 1.1 augustss moused(ctldev); 819 1.1 augustss } 820 1.1 augustss 821 1.1 augustss if (rodent.mfd != -1) 822 1.1 augustss close(rodent.mfd); 823 1.1 augustss if (rodent.cfd != -1) 824 1.1 augustss close(rodent.cfd); 825 1.1 augustss rodent.mfd = rodent.cfd = -1; 826 1.1 augustss } 827 1.1 augustss /* NOT REACHED */ 828 1.1 augustss 829 1.1 augustss exit(0); 830 1.1 augustss } 831 1.1 augustss 832 1.1 augustss static void 833 1.1 augustss wsev(int ty, int val) 834 1.1 augustss { 835 1.1 augustss struct wscons_event ev; 836 1.1 augustss 837 1.1 augustss ev.type = ty; 838 1.1 augustss ev.value = val; 839 1.5 thorpej if (dbg) 840 1.1 augustss printf("wsev: type=%d value=%d\n", ty, val); 841 1.1 augustss if (ioctl(rodent.cfd, WSMUXIO_INJECTEVENT, &ev) < 0) 842 1.5 thorpej logwarn("muxio inject event"); 843 1.1 augustss } 844 1.1 augustss 845 1.1 augustss static void 846 1.18 lukem moused(const char *wsm) 847 1.1 augustss { 848 1.1 augustss mousestatus_t action0; /* original mouse action */ 849 1.1 augustss mousestatus_t action; /* interrim buffer */ 850 1.1 augustss mousestatus_t action2; /* mapped action */ 851 1.1 augustss int lastbutton = 0; 852 1.1 augustss int button; 853 1.8 mycroft struct pollfd set[3]; 854 1.1 augustss u_char b; 855 1.1 augustss FILE *fp; 856 1.1 augustss int flags; 857 1.1 augustss int c; 858 1.1 augustss int i; 859 1.1 augustss 860 1.1 augustss if ((rodent.cfd = open(wsm, O_WRONLY, 0)) == -1) 861 1.1 augustss logerr(1, "cannot open %s", wsm); 862 1.1 augustss 863 1.1 augustss if (!nodaemon && !background) { 864 1.1 augustss if (daemon(0, 0)) { 865 1.4 thorpej logerr(1, "failed to become a daemon"); 866 1.1 augustss } else { 867 1.1 augustss background = TRUE; 868 1.1 augustss fp = fopen(pidfile, "w"); 869 1.1 augustss if (fp != NULL) { 870 1.1 augustss fprintf(fp, "%d\n", getpid()); 871 1.1 augustss fclose(fp); 872 1.1 augustss } 873 1.1 augustss } 874 1.1 augustss } 875 1.1 augustss 876 1.1 augustss /* clear mouse data */ 877 1.1 augustss bzero(&action0, sizeof(action0)); 878 1.1 augustss bzero(&action, sizeof(action)); 879 1.1 augustss bzero(&action2, sizeof(action2)); 880 1.1 augustss mouse_button_state = S0; 881 1.1 augustss gettimeofday(&mouse_button_state_tv, NULL); 882 1.1 augustss mouse_move_delayed = 0; 883 1.1 augustss for (i = 0; i < MOUSE_MAXBUTTON; ++i) { 884 1.1 augustss bstate[i].count = 0; 885 1.1 augustss bstate[i].tv = mouse_button_state_tv; 886 1.1 augustss } 887 1.18 lukem for (i = 0; i < (int)(sizeof(zstate)/sizeof(zstate[0])); ++i) { 888 1.1 augustss zstate[i].count = 0; 889 1.1 augustss zstate[i].tv = mouse_button_state_tv; 890 1.1 augustss } 891 1.15 lukem flags = 0; 892 1.1 augustss 893 1.1 augustss /* process mouse data */ 894 1.1 augustss for (;;) { 895 1.1 augustss 896 1.8 mycroft set[0].fd = rodent.mfd; 897 1.8 mycroft set[0].events = POLLIN; 898 1.8 mycroft set[1].fd = rodent.mremsfd; 899 1.9 mycroft set[1].events = POLLIN; 900 1.8 mycroft set[2].fd = rodent.mremcfd; 901 1.9 mycroft set[2].events = POLLIN; 902 1.1 augustss 903 1.8 mycroft c = poll(set, 3, (rodent.flags & Emulate3Button) ? 20 : INFTIM); 904 1.1 augustss if (c < 0) { /* error */ 905 1.4 thorpej logwarn("failed to read from mouse"); 906 1.1 augustss continue; 907 1.1 augustss } else if (c == 0) { /* timeout */ 908 1.1 augustss /* assert(rodent.flags & Emulate3Button) */ 909 1.1 augustss action0.button = action0.obutton; 910 1.1 augustss action0.dx = action0.dy = action0.dz = 0; 911 1.1 augustss action0.flags = flags = 0; 912 1.1 augustss if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) { 913 1.5 thorpej if (dbg > 2) 914 1.1 augustss debug("flags:%08x buttons:%08x obuttons:%08x", 915 1.1 augustss action.flags, action.button, action.obutton); 916 1.1 augustss } else { 917 1.1 augustss action0.obutton = action0.button; 918 1.1 augustss continue; 919 1.1 augustss } 920 1.1 augustss } else { 921 1.2 augustss #if 0 922 1.1 augustss /* MouseRemote client connect/disconnect */ 923 1.8 mycroft if (set[1].revents & POLLIN) { 924 1.1 augustss mremote_clientchg(TRUE); 925 1.1 augustss continue; 926 1.1 augustss } 927 1.8 mycroft if (set[2].revents & POLLIN) { 928 1.1 augustss mremote_clientchg(FALSE); 929 1.1 augustss continue; 930 1.1 augustss } 931 1.2 augustss #endif 932 1.1 augustss /* mouse movement */ 933 1.8 mycroft if (set[0].revents & POLLIN) { 934 1.8 mycroft if (read(rodent.mfd, &b, 1) == -1) 935 1.8 mycroft return; 936 1.8 mycroft if ((flags = r_protocol(b, &action0)) == 0) 937 1.1 augustss continue; 938 1.8 mycroft r_timestamp(&action0); 939 1.8 mycroft r_statetrans(&action0, &action, 940 1.8 mycroft A(action0.button & MOUSE_BUTTON1DOWN, 941 1.8 mycroft action0.button & MOUSE_BUTTON3DOWN)); 942 1.8 mycroft debug("flags:%08x buttons:%08x obuttons:%08x", action.flags, 943 1.8 mycroft action.button, action.obutton); 944 1.1 augustss } 945 1.1 augustss } 946 1.1 augustss action0.obutton = action0.button; 947 1.1 augustss flags &= MOUSE_POSCHANGED; 948 1.1 augustss flags |= action.obutton ^ action.button; 949 1.1 augustss action.flags = flags; 950 1.1 augustss 951 1.1 augustss if (flags) { /* handler detected action */ 952 1.1 augustss r_map(&action, &action2); 953 1.1 augustss debug("activity : buttons 0x%08x dx %d dy %d dz %d", 954 1.1 augustss action2.button, action2.dx, action2.dy, action2.dz); 955 1.1 augustss 956 1.5 thorpej if (dbg > 1) 957 1.1 augustss printf("buttons=%x x=%d y=%d z=%d\n", action2.button, 958 1.1 augustss (int)(action2.dx * rodent.accelx), 959 1.1 augustss (int)(action2.dy * rodent.accely), 960 1.1 augustss (int)action2.dz); 961 1.5 thorpej if (action2.dx != 0 && dbg < 2) 962 1.1 augustss wsev(WSCONS_EVENT_MOUSE_DELTA_X, action2.dx * rodent.accelx); 963 1.5 thorpej if (action2.dy != 0 && dbg < 2) 964 1.1 augustss wsev(WSCONS_EVENT_MOUSE_DELTA_Y, -action2.dy * rodent.accely); 965 1.5 thorpej if (action2.dz != 0 && dbg < 2) 966 1.1 augustss wsev(WSCONS_EVENT_MOUSE_DELTA_Z, action2.dz); 967 1.1 augustss button = lastbutton ^ action2.button; 968 1.1 augustss lastbutton = action2.button; 969 1.1 augustss printf("diff=%x buts=%x\n", button, lastbutton); 970 1.1 augustss for (i = 0; i < 3; i ++) { 971 1.5 thorpej if ((button & (1<<i)) && dbg < 2) { 972 1.1 augustss wsev(lastbutton & (1<<i) ? WSCONS_EVENT_MOUSE_DOWN : 973 1.1 augustss WSCONS_EVENT_MOUSE_UP, i); 974 1.1 augustss } 975 1.1 augustss } 976 1.1 augustss 977 1.1 augustss /* 978 1.1 augustss * If the Z axis movement is mapped to a imaginary physical 979 1.1 augustss * button, we need to cook up a corresponding button `up' event 980 1.1 augustss * after sending a button `down' event. 981 1.1 augustss */ 982 1.1 augustss if ((rodent.zmap[0] > 0) && (action.dz != 0)) { 983 1.1 augustss action.obutton = action.button; 984 1.1 augustss action.dx = action.dy = action.dz = 0; 985 1.1 augustss r_map(&action, &action2); 986 1.1 augustss debug("activity : buttons 0x%08x dx %d dy %d dz %d", 987 1.1 augustss action2.button, action2.dx, action2.dy, action2.dz); 988 1.1 augustss 989 1.1 augustss /* XXX emplement this */ 990 1.1 augustss #if 0 991 1.1 augustss if (extioctl) { 992 1.1 augustss r_click(&action2); 993 1.1 augustss } else { 994 1.1 augustss mouse.operation = MOUSE_ACTION; 995 1.1 augustss mouse.u.data.buttons = action2.button; 996 1.1 augustss mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0; 997 1.5 thorpej if (dbg < 2) 998 1.1 augustss ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 999 1.1 augustss } 1000 1.1 augustss #endif 1001 1.1 augustss } 1002 1.1 augustss } 1003 1.1 augustss } 1004 1.1 augustss /* NOT REACHED */ 1005 1.1 augustss } 1006 1.1 augustss 1007 1.1 augustss static void 1008 1.1 augustss hup(int sig) 1009 1.1 augustss { 1010 1.1 augustss longjmp(env, 1); 1011 1.1 augustss } 1012 1.1 augustss 1013 1.1 augustss static void 1014 1.1 augustss cleanup(int sig) 1015 1.1 augustss { 1016 1.1 augustss if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM) 1017 1.1 augustss unlink(_PATH_MOUSEREMOTE); 1018 1.1 augustss exit(0); 1019 1.1 augustss } 1020 1.1 augustss 1021 1.1 augustss /** 1022 1.1 augustss ** usage 1023 1.1 augustss ** 1024 1.1 augustss ** Complain, and free the CPU for more worthy tasks 1025 1.1 augustss **/ 1026 1.1 augustss static void 1027 1.1 augustss usage(void) 1028 1.1 augustss { 1029 1.1 augustss fprintf(stderr, "%s\n%s\n%s\n%s\n", 1030 1.1 augustss "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]", 1031 1.1 augustss " [-a X[,Y]] [-m N=M] [-w N] [-z N]", 1032 1.1 augustss " [-t <mousetype>] [-3 [-E timeout]] -p <port>", 1033 1.1 augustss " moused [-d] -i <port|if|type|model|all> -p <port>"); 1034 1.1 augustss exit(1); 1035 1.1 augustss } 1036 1.1 augustss 1037 1.1 augustss /** 1038 1.1 augustss ** Mouse interface code, courtesy of XFree86 3.1.2. 1039 1.1 augustss ** 1040 1.1 augustss ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm 1041 1.1 augustss ** to clean, reformat and rationalise naming, it's quite possible that 1042 1.1 augustss ** some things in here have been broken. 1043 1.1 augustss ** 1044 1.1 augustss ** I hope not 8) 1045 1.1 augustss ** 1046 1.1 augustss ** The following code is derived from a module marked : 1047 1.1 augustss **/ 1048 1.1 augustss 1049 1.1 augustss /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */ 1050 1.1 augustss /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28 1051 1.1 augustss 17:03:40 dawes Exp $ */ 1052 1.1 augustss /* 1053 1.1 augustss * 1054 1.1 augustss * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 1055 1.1 augustss * Copyright 1993 by David Dawes <dawes (at) physics.su.oz.au> 1056 1.1 augustss * 1057 1.1 augustss * Permission to use, copy, modify, distribute, and sell this software and its 1058 1.1 augustss * documentation for any purpose is hereby granted without fee, provided that 1059 1.1 augustss * the above copyright notice appear in all copies and that both that 1060 1.1 augustss * copyright notice and this permission notice appear in supporting 1061 1.1 augustss * documentation, and that the names of Thomas Roell and David Dawes not be 1062 1.1 augustss * used in advertising or publicity pertaining to distribution of the 1063 1.1 augustss * software without specific, written prior permission. Thomas Roell 1064 1.1 augustss * and David Dawes makes no representations about the suitability of this 1065 1.1 augustss * software for any purpose. It is provided "as is" without express or 1066 1.1 augustss * implied warranty. 1067 1.1 augustss * 1068 1.1 augustss * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 1069 1.1 augustss * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 1070 1.1 augustss * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY 1071 1.1 augustss * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 1072 1.1 augustss * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 1073 1.1 augustss * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 1074 1.1 augustss * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1075 1.1 augustss * 1076 1.1 augustss */ 1077 1.1 augustss 1078 1.1 augustss /** 1079 1.1 augustss ** GlidePoint support from XFree86 3.2. 1080 1.1 augustss ** Derived from the module: 1081 1.1 augustss **/ 1082 1.1 augustss 1083 1.1 augustss /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */ 1084 1.1 augustss /* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */ 1085 1.1 augustss 1086 1.1 augustss /* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */ 1087 1.1 augustss static unsigned char proto[][7] = { 1088 1.1 augustss /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */ 1089 1.1 augustss { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */ 1090 1.1 augustss { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */ 1091 1.1 augustss { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */ 1092 1.1 augustss { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */ 1093 1.1 augustss { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* MouseMan */ 1094 1.1 augustss { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */ 1095 1.1 augustss { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */ 1096 1.1 augustss { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */ 1097 1.1 augustss { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */ 1098 1.1 augustss { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */ 1099 1.1 augustss { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */ 1100 1.1 augustss { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */ 1101 1.1 augustss { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */ 1102 1.1 augustss { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* X10 MouseRem */ 1103 1.1 augustss { 0x80, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* KIDSPAD */ 1104 1.1 augustss { 0xc3, 0xc0, 0x00, 0x00, 6, 0x00, 0xff }, /* VersaPad */ 1105 1.1 augustss #if notyet 1106 1.1 augustss { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */ 1107 1.1 augustss #endif 1108 1.1 augustss }; 1109 1.1 augustss static unsigned char cur_proto[7]; 1110 1.1 augustss 1111 1.1 augustss static int 1112 1.1 augustss r_identify(void) 1113 1.1 augustss { 1114 1.1 augustss char pnpbuf[256]; /* PnP identifier string may be up to 256 bytes long */ 1115 1.1 augustss pnpid_t pnpid; 1116 1.1 augustss symtab_t *t; 1117 1.1 augustss int len; 1118 1.1 augustss 1119 1.1 augustss rodent.level = 0; 1120 1.1 augustss 1121 1.1 augustss if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1122 1.1 augustss bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 1123 1.1 augustss rodent.mode.protocol = MOUSE_PROTO_UNKNOWN; 1124 1.1 augustss rodent.mode.rate = -1; 1125 1.1 augustss rodent.mode.resolution = MOUSE_RES_UNKNOWN; 1126 1.1 augustss rodent.mode.accelfactor = 0; 1127 1.1 augustss rodent.mode.level = 0; 1128 1.1 augustss 1129 1.1 augustss /* maybe this is an PnP mouse... */ 1130 1.1 augustss if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) { 1131 1.1 augustss 1132 1.1 augustss if (rodent.flags & NoPnP) 1133 1.1 augustss return rodent.rtype; 1134 1.1 augustss if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len)) 1135 1.1 augustss return rodent.rtype; 1136 1.1 augustss 1137 1.1 augustss debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'", 1138 1.1 augustss pnpid.neisaid, pnpid.neisaid, pnpid.eisaid, 1139 1.1 augustss pnpid.ncompat, pnpid.ncompat, pnpid.compat, 1140 1.1 augustss pnpid.ndescription, pnpid.ndescription, pnpid.description); 1141 1.1 augustss 1142 1.1 augustss /* we have a valid PnP serial device ID */ 1143 1.1 augustss rodent.hw.iftype = MOUSE_IF_SERIAL; 1144 1.1 augustss t = pnpproto(&pnpid); 1145 1.1 augustss if (t != NULL) { 1146 1.1 augustss rodent.mode.protocol = t->val; 1147 1.1 augustss rodent.hw.model = t->val2; 1148 1.1 augustss } else { 1149 1.1 augustss rodent.mode.protocol = MOUSE_PROTO_UNKNOWN; 1150 1.1 augustss } 1151 1.1 augustss if (rodent.mode.protocol == MOUSE_PROTO_INPORT) 1152 1.1 augustss rodent.mode.protocol = MOUSE_PROTO_BUS; 1153 1.1 augustss 1154 1.1 augustss /* make final adjustment */ 1155 1.1 augustss if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) { 1156 1.1 augustss if (rodent.mode.protocol != rodent.rtype) { 1157 1.1 augustss /* Hmm, the device doesn't agree with the user... */ 1158 1.1 augustss if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1159 1.1 augustss logwarnx("mouse type mismatch (%s != %s), %s is assumed", 1160 1.1 augustss r_name(rodent.mode.protocol), r_name(rodent.rtype), 1161 1.1 augustss r_name(rodent.mode.protocol)); 1162 1.1 augustss rodent.rtype = rodent.mode.protocol; 1163 1.1 augustss bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 1164 1.1 augustss } 1165 1.1 augustss } 1166 1.1 augustss } 1167 1.1 augustss 1168 1.1 augustss debug("proto params: %02x %02x %02x %02x %d %02x %02x", 1169 1.1 augustss cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3], 1170 1.1 augustss cur_proto[4], cur_proto[5], cur_proto[6]); 1171 1.1 augustss 1172 1.1 augustss return rodent.rtype; 1173 1.1 augustss } 1174 1.1 augustss 1175 1.18 lukem static const char * 1176 1.1 augustss r_if(int iftype) 1177 1.1 augustss { 1178 1.18 lukem const char *s; 1179 1.1 augustss 1180 1.1 augustss s = gettokenname(rifs, iftype); 1181 1.1 augustss return (s == NULL) ? "unknown" : s; 1182 1.1 augustss } 1183 1.1 augustss 1184 1.18 lukem static const char * 1185 1.1 augustss r_name(int type) 1186 1.1 augustss { 1187 1.1 augustss return ((type == MOUSE_PROTO_UNKNOWN) 1188 1.18 lukem || (type > (int)(sizeof(rnames)/sizeof(rnames[0]) - 1))) 1189 1.1 augustss ? "unknown" : rnames[type]; 1190 1.1 augustss } 1191 1.1 augustss 1192 1.18 lukem static const char * 1193 1.1 augustss r_model(int model) 1194 1.1 augustss { 1195 1.18 lukem const char *s; 1196 1.1 augustss 1197 1.1 augustss s = gettokenname(rmodels, model); 1198 1.1 augustss return (s == NULL) ? "unknown" : s; 1199 1.1 augustss } 1200 1.1 augustss 1201 1.1 augustss static void 1202 1.1 augustss r_init(void) 1203 1.1 augustss { 1204 1.1 augustss unsigned char buf[16]; /* scrach buffer */ 1205 1.8 mycroft struct pollfd set[1]; 1206 1.18 lukem const char *s; 1207 1.1 augustss char c; 1208 1.1 augustss int i; 1209 1.1 augustss 1210 1.1 augustss /** 1211 1.1 augustss ** This comment is a little out of context here, but it contains 1212 1.1 augustss ** some useful information... 1213 1.1 augustss ******************************************************************** 1214 1.1 augustss ** 1215 1.1 augustss ** The following lines take care of the Logitech MouseMan protocols. 1216 1.1 augustss ** 1217 1.1 augustss ** NOTE: There are different versions of both MouseMan and TrackMan! 1218 1.1 augustss ** Hence I add another protocol P_LOGIMAN, which the user can 1219 1.1 augustss ** specify as MouseMan in his XF86Config file. This entry was 1220 1.1 augustss ** formerly handled as a special case of P_MS. However, people 1221 1.1 augustss ** who don't have the middle button problem, can still specify 1222 1.1 augustss ** Microsoft and use P_MS. 1223 1.1 augustss ** 1224 1.1 augustss ** By default, these mice should use a 3 byte Microsoft protocol 1225 1.1 augustss ** plus a 4th byte for the middle button. However, the mouse might 1226 1.1 augustss ** have switched to a different protocol before we use it, so I send 1227 1.1 augustss ** the proper sequence just in case. 1228 1.1 augustss ** 1229 1.1 augustss ** NOTE: - all commands to (at least the European) MouseMan have to 1230 1.1 augustss ** be sent at 1200 Baud. 1231 1.1 augustss ** - each command starts with a '*'. 1232 1.1 augustss ** - whenever the MouseMan receives a '*', it will switch back 1233 1.1 augustss ** to 1200 Baud. Hence I have to select the desired protocol 1234 1.1 augustss ** first, then select the baud rate. 1235 1.1 augustss ** 1236 1.1 augustss ** The protocols supported by the (European) MouseMan are: 1237 1.1 augustss ** - 5 byte packed binary protocol, as with the Mouse Systems 1238 1.1 augustss ** mouse. Selected by sequence "*U". 1239 1.1 augustss ** - 2 button 3 byte MicroSoft compatible protocol. Selected 1240 1.1 augustss ** by sequence "*V". 1241 1.1 augustss ** - 3 button 3+1 byte MicroSoft compatible protocol (default). 1242 1.1 augustss ** Selected by sequence "*X". 1243 1.1 augustss ** 1244 1.1 augustss ** The following baud rates are supported: 1245 1.1 augustss ** - 1200 Baud (default). Selected by sequence "*n". 1246 1.1 augustss ** - 9600 Baud. Selected by sequence "*q". 1247 1.1 augustss ** 1248 1.1 augustss ** Selecting a sample rate is no longer supported with the MouseMan! 1249 1.1 augustss ** Some additional lines in xf86Config.c take care of ill configured 1250 1.1 augustss ** baud rates and sample rates. (The user will get an error.) 1251 1.1 augustss */ 1252 1.1 augustss 1253 1.1 augustss switch (rodent.rtype) { 1254 1.1 augustss 1255 1.1 augustss case MOUSE_PROTO_LOGI: 1256 1.1 augustss /* 1257 1.1 augustss * The baud rate selection command must be sent at the current 1258 1.1 augustss * baud rate; try all likely settings 1259 1.1 augustss */ 1260 1.1 augustss setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]); 1261 1.1 augustss setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]); 1262 1.1 augustss setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]); 1263 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1264 1.1 augustss /* select MM series data format */ 1265 1.1 augustss write(rodent.mfd, "S", 1); 1266 1.1 augustss setmousespeed(rodent.baudrate, rodent.baudrate, 1267 1.1 augustss rodentcflags[MOUSE_PROTO_MM]); 1268 1.1 augustss /* select report rate/frequency */ 1269 1.1 augustss if (rodent.rate <= 0) write(rodent.mfd, "O", 1); 1270 1.1 augustss else if (rodent.rate <= 15) write(rodent.mfd, "J", 1); 1271 1.1 augustss else if (rodent.rate <= 27) write(rodent.mfd, "K", 1); 1272 1.1 augustss else if (rodent.rate <= 42) write(rodent.mfd, "L", 1); 1273 1.1 augustss else if (rodent.rate <= 60) write(rodent.mfd, "R", 1); 1274 1.1 augustss else if (rodent.rate <= 85) write(rodent.mfd, "M", 1); 1275 1.1 augustss else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1); 1276 1.1 augustss else write(rodent.mfd, "N", 1); 1277 1.1 augustss break; 1278 1.1 augustss 1279 1.1 augustss case MOUSE_PROTO_LOGIMOUSEMAN: 1280 1.1 augustss /* The command must always be sent at 1200 baud */ 1281 1.1 augustss setmousespeed(1200, 1200, rodentcflags[rodent.rtype]); 1282 1.1 augustss write(rodent.mfd, "*X", 2); 1283 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1284 1.1 augustss break; 1285 1.1 augustss 1286 1.1 augustss case MOUSE_PROTO_HITTAB: 1287 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1288 1.1 augustss 1289 1.1 augustss /* 1290 1.1 augustss * Initialize Hitachi PUMA Plus - Model 1212E to desired settings. 1291 1.1 augustss * The tablet must be configured to be in MM mode, NO parity, 1292 1.1 augustss * Binary Format. xf86Info.sampleRate controls the sensativity 1293 1.25 snj * of the tablet. We only use this tablet for its 4-button puck 1294 1.1 augustss * so we don't run in "Absolute Mode" 1295 1.1 augustss */ 1296 1.1 augustss write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */ 1297 1.1 augustss usleep(50000); 1298 1.1 augustss write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */ 1299 1.1 augustss usleep(50000); 1300 1.1 augustss write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */ 1301 1.1 augustss usleep(50000); 1302 1.1 augustss write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */ 1303 1.1 augustss usleep(50000); 1304 1.1 augustss write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */ 1305 1.1 augustss usleep(50000); 1306 1.1 augustss write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */ 1307 1.1 augustss usleep(50000); 1308 1.1 augustss 1309 1.1 augustss /* Resolution is in 'lines per inch' on the Hitachi tablet */ 1310 1.1 augustss if (rodent.resolution == MOUSE_RES_LOW) c = 'g'; 1311 1.1 augustss else if (rodent.resolution == MOUSE_RES_MEDIUMLOW) c = 'e'; 1312 1.1 augustss else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH) c = 'h'; 1313 1.1 augustss else if (rodent.resolution == MOUSE_RES_HIGH) c = 'd'; 1314 1.1 augustss else if (rodent.resolution <= 40) c = 'g'; 1315 1.1 augustss else if (rodent.resolution <= 100) c = 'd'; 1316 1.1 augustss else if (rodent.resolution <= 200) c = 'e'; 1317 1.1 augustss else if (rodent.resolution <= 500) c = 'h'; 1318 1.1 augustss else if (rodent.resolution <= 1000) c = 'j'; 1319 1.1 augustss else c = 'd'; 1320 1.1 augustss write(rodent.mfd, &c, 1); 1321 1.1 augustss usleep(50000); 1322 1.1 augustss 1323 1.1 augustss write(rodent.mfd, "\021", 1); /* Resume DATA output */ 1324 1.1 augustss break; 1325 1.1 augustss 1326 1.1 augustss case MOUSE_PROTO_THINK: 1327 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1328 1.1 augustss /* the PnP ID string may be sent again, discard it */ 1329 1.1 augustss usleep(200000); 1330 1.1 augustss i = FREAD; 1331 1.1 augustss ioctl(rodent.mfd, TIOCFLUSH, &i); 1332 1.1 augustss /* send the command to initialize the beast */ 1333 1.8 mycroft set[0].fd = rodent.mfd; 1334 1.8 mycroft set[0].events = POLLIN; 1335 1.1 augustss for (s = "E5E5"; *s; ++s) { 1336 1.1 augustss write(rodent.mfd, s, 1); 1337 1.8 mycroft if (poll(set, 1, INFTIM) <= 0) 1338 1.1 augustss break; 1339 1.1 augustss read(rodent.mfd, &c, 1); 1340 1.1 augustss debug("%c", c); 1341 1.1 augustss if (c != *s) 1342 1.1 augustss break; 1343 1.1 augustss } 1344 1.1 augustss break; 1345 1.1 augustss 1346 1.1 augustss case MOUSE_PROTO_MSC: 1347 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1348 1.1 augustss if (rodent.flags & ClearDTR) { 1349 1.1 augustss i = TIOCM_DTR; 1350 1.1 augustss ioctl(rodent.mfd, TIOCMBIC, &i); 1351 1.1 augustss } 1352 1.1 augustss if (rodent.flags & ClearRTS) { 1353 1.1 augustss i = TIOCM_RTS; 1354 1.1 augustss ioctl(rodent.mfd, TIOCMBIC, &i); 1355 1.1 augustss } 1356 1.1 augustss break; 1357 1.1 augustss 1358 1.1 augustss case MOUSE_PROTO_SYSMOUSE: 1359 1.1 augustss if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE) 1360 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1361 1.1 augustss /* fall through */ 1362 1.1 augustss 1363 1.1 augustss case MOUSE_PROTO_BUS: 1364 1.1 augustss case MOUSE_PROTO_INPORT: 1365 1.1 augustss case MOUSE_PROTO_PS2: 1366 1.1 augustss if (rodent.rate >= 0) 1367 1.1 augustss rodent.mode.rate = rodent.rate; 1368 1.1 augustss if (rodent.resolution != MOUSE_RES_UNKNOWN) 1369 1.1 augustss rodent.mode.resolution = rodent.resolution; 1370 1.1 augustss #if 0 1371 1.1 augustss ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode); 1372 1.1 augustss #endif 1373 1.1 augustss break; 1374 1.1 augustss 1375 1.1 augustss case MOUSE_PROTO_X10MOUSEREM: 1376 1.1 augustss #if 0 1377 1.1 augustss mremote_serversetup(); 1378 1.1 augustss #endif 1379 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1380 1.1 augustss break; 1381 1.1 augustss 1382 1.1 augustss 1383 1.1 augustss case MOUSE_PROTO_VERSAPAD: 1384 1.1 augustss tcsendbreak(rodent.mfd, 0); /* send break for 400 msec */ 1385 1.1 augustss i = FREAD; 1386 1.1 augustss ioctl(rodent.mfd, TIOCFLUSH, &i); 1387 1.8 mycroft set[0].fd = rodent.mfd; 1388 1.8 mycroft set[0].events = POLLIN; 1389 1.1 augustss for (i = 0; i < 7; ++i) { 1390 1.8 mycroft if (poll(set, 1, INFTIM) <= 0) 1391 1.1 augustss break; 1392 1.1 augustss read(rodent.mfd, &c, 1); 1393 1.1 augustss buf[i] = c; 1394 1.1 augustss } 1395 1.1 augustss debug("%s\n", buf); 1396 1.1 augustss if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r')) 1397 1.1 augustss break; 1398 1.1 augustss setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]); 1399 1.1 augustss tcsendbreak(rodent.mfd, 0); /* send break for 400 msec again */ 1400 1.1 augustss for (i = 0; i < 7; ++i) { 1401 1.8 mycroft if (poll(set, 1, INFTIM) <= 0) 1402 1.1 augustss break; 1403 1.1 augustss read(rodent.mfd, &c, 1); 1404 1.1 augustss debug("%c", c); 1405 1.1 augustss if (c != buf[i]) 1406 1.1 augustss break; 1407 1.1 augustss } 1408 1.1 augustss i = FREAD; 1409 1.1 augustss ioctl(rodent.mfd, TIOCFLUSH, &i); 1410 1.1 augustss break; 1411 1.1 augustss 1412 1.1 augustss default: 1413 1.1 augustss setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1414 1.1 augustss break; 1415 1.1 augustss } 1416 1.1 augustss } 1417 1.1 augustss 1418 1.1 augustss static int 1419 1.1 augustss r_protocol(u_char rBuf, mousestatus_t *act) 1420 1.1 augustss { 1421 1.1 augustss /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 1422 1.1 augustss static int butmapmss[4] = { /* Microsoft, MouseMan, GlidePoint, 1423 1.1 augustss IntelliMouse, Thinking Mouse */ 1424 1.1 augustss 0, 1425 1.1 augustss MOUSE_BUTTON3DOWN, 1426 1.1 augustss MOUSE_BUTTON1DOWN, 1427 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1428 1.1 augustss }; 1429 1.1 augustss static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint, 1430 1.1 augustss Thinking Mouse */ 1431 1.1 augustss 0, 1432 1.1 augustss MOUSE_BUTTON4DOWN, 1433 1.1 augustss MOUSE_BUTTON2DOWN, 1434 1.1 augustss MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN, 1435 1.1 augustss }; 1436 1.1 augustss /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 1437 1.1 augustss static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse, 1438 1.1 augustss MouseMan+ */ 1439 1.1 augustss 0, 1440 1.1 augustss MOUSE_BUTTON2DOWN, 1441 1.1 augustss MOUSE_BUTTON4DOWN, 1442 1.1 augustss MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN, 1443 1.1 augustss }; 1444 1.1 augustss /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */ 1445 1.1 augustss static int butmapmsc[8] = { /* MouseSystems, MMSeries, Logitech, 1446 1.1 augustss Bus, sysmouse */ 1447 1.1 augustss 0, 1448 1.1 augustss MOUSE_BUTTON3DOWN, 1449 1.1 augustss MOUSE_BUTTON2DOWN, 1450 1.1 augustss MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 1451 1.1 augustss MOUSE_BUTTON1DOWN, 1452 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1453 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 1454 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 1455 1.1 augustss }; 1456 1.1 augustss /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 1457 1.1 augustss static int butmapps2[8] = { /* PS/2 */ 1458 1.1 augustss 0, 1459 1.1 augustss MOUSE_BUTTON1DOWN, 1460 1.1 augustss MOUSE_BUTTON3DOWN, 1461 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1462 1.1 augustss MOUSE_BUTTON2DOWN, 1463 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 1464 1.1 augustss MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 1465 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 1466 1.1 augustss }; 1467 1.1 augustss /* for Hitachi tablet */ 1468 1.1 augustss static int butmaphit[8] = { /* MM HitTablet */ 1469 1.1 augustss 0, 1470 1.1 augustss MOUSE_BUTTON3DOWN, 1471 1.1 augustss MOUSE_BUTTON2DOWN, 1472 1.1 augustss MOUSE_BUTTON1DOWN, 1473 1.1 augustss MOUSE_BUTTON4DOWN, 1474 1.1 augustss MOUSE_BUTTON5DOWN, 1475 1.1 augustss MOUSE_BUTTON6DOWN, 1476 1.1 augustss MOUSE_BUTTON7DOWN, 1477 1.1 augustss }; 1478 1.1 augustss /* for serial VersaPad */ 1479 1.1 augustss static int butmapversa[8] = { /* VersaPad */ 1480 1.1 augustss 0, 1481 1.1 augustss 0, 1482 1.1 augustss MOUSE_BUTTON3DOWN, 1483 1.1 augustss MOUSE_BUTTON3DOWN, 1484 1.1 augustss MOUSE_BUTTON1DOWN, 1485 1.1 augustss MOUSE_BUTTON1DOWN, 1486 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1487 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1488 1.1 augustss }; 1489 1.1 augustss /* for PS/2 VersaPad */ 1490 1.1 augustss static int butmapversaps2[8] = { /* VersaPad */ 1491 1.1 augustss 0, 1492 1.1 augustss MOUSE_BUTTON3DOWN, 1493 1.1 augustss 0, 1494 1.1 augustss MOUSE_BUTTON3DOWN, 1495 1.1 augustss MOUSE_BUTTON1DOWN, 1496 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1497 1.1 augustss MOUSE_BUTTON1DOWN, 1498 1.1 augustss MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1499 1.1 augustss }; 1500 1.1 augustss static int pBufP = 0; 1501 1.1 augustss static unsigned char pBuf[8]; 1502 1.1 augustss static int prev_x, prev_y; 1503 1.1 augustss static int on = FALSE; 1504 1.1 augustss int x, y; 1505 1.1 augustss 1506 1.1 augustss debug("received char 0x%x",(int)rBuf); 1507 1.1 augustss if (rodent.rtype == MOUSE_PROTO_KIDSPAD) 1508 1.24 christos return kidspad(rBuf, act); 1509 1.1 augustss 1510 1.1 augustss /* 1511 1.1 augustss * Hack for resyncing: We check here for a package that is: 1512 1.1 augustss * a) illegal (detected by wrong data-package header) 1513 1.1 augustss * b) invalid (0x80 == -128 and that might be wrong for MouseSystems) 1514 1.1 augustss * c) bad header-package 1515 1.1 augustss * 1516 1.29 andvar * NOTE: b) is a violation of the MouseSystems-Protocol, since values of 1517 1.1 augustss * -128 are allowed, but since they are very seldom we can easily 1518 1.1 augustss * use them as package-header with no button pressed. 1519 1.1 augustss * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore, 1520 1.1 augustss * 0x80 is not valid as a header byte. For a PS/2 mouse we skip 1521 1.1 augustss * checking data bytes. 1522 1.1 augustss * For resyncing a PS/2 mouse we require the two most significant 1523 1.1 augustss * bits in the header byte to be 0. These are the overflow bits, 1524 1.1 augustss * and in case of an overflow we actually lose sync. Overflows 1525 1.1 augustss * are very rare, however, and we quickly gain sync again after 1526 1.1 augustss * an overflow condition. This is the best we can do. (Actually, 1527 1.1 augustss * we could use bit 0x08 in the header byte for resyncing, since 1528 1.1 augustss * that bit is supposed to be always on, but nobody told 1529 1.1 augustss * Microsoft...) 1530 1.1 augustss */ 1531 1.1 augustss 1532 1.1 augustss if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 && 1533 1.1 augustss ((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80)) 1534 1.1 augustss { 1535 1.1 augustss pBufP = 0; /* skip package */ 1536 1.1 augustss } 1537 1.1 augustss 1538 1.1 augustss if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1]) 1539 1.1 augustss return 0; 1540 1.1 augustss 1541 1.1 augustss /* is there an extra data byte? */ 1542 1.1 augustss if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1]) 1543 1.1 augustss { 1544 1.1 augustss /* 1545 1.1 augustss * Hack for Logitech MouseMan Mouse - Middle button 1546 1.1 augustss * 1547 1.1 augustss * Unfortunately this mouse has variable length packets: the standard 1548 1.1 augustss * Microsoft 3 byte packet plus an optional 4th byte whenever the 1549 1.1 augustss * middle button status changes. 1550 1.1 augustss * 1551 1.1 augustss * We have already processed the standard packet with the movement 1552 1.1 augustss * and button info. Now post an event message with the old status 1553 1.1 augustss * of the left and right buttons and the updated middle button. 1554 1.1 augustss */ 1555 1.1 augustss 1556 1.1 augustss /* 1557 1.1 augustss * Even worse, different MouseMen and TrackMen differ in the 4th 1558 1.1 augustss * byte: some will send 0x00/0x20, others 0x01/0x21, or even 1559 1.1 augustss * 0x02/0x22, so I have to strip off the lower bits. 1560 1.1 augustss * 1561 1.1 augustss * [JCH-96/01/21] 1562 1.1 augustss * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte" 1563 1.1 augustss * and it is activated by tapping the glidepad with the finger! 8^) 1564 1.1 augustss * We map it to bit bit3, and the reverse map in xf86Events just has 1565 1.1 augustss * to be extended so that it is identified as Button 4. The lower 1566 1.1 augustss * half of the reverse-map may remain unchanged. 1567 1.1 augustss */ 1568 1.1 augustss 1569 1.1 augustss /* 1570 1.1 augustss * [KY-97/08/03] 1571 1.1 augustss * Receive the fourth byte only when preceding three bytes have 1572 1.1 augustss * been detected (pBufP >= cur_proto[4]). In the previous 1573 1.1 augustss * versions, the test was pBufP == 0; thus, we may have mistakingly 1574 1.1 augustss * received a byte even if we didn't see anything preceding 1575 1.1 augustss * the byte. 1576 1.1 augustss */ 1577 1.1 augustss 1578 1.1 augustss if ((rBuf & cur_proto[5]) != cur_proto[6]) { 1579 1.1 augustss pBufP = 0; 1580 1.1 augustss return 0; 1581 1.1 augustss } 1582 1.1 augustss 1583 1.1 augustss switch (rodent.rtype) { 1584 1.1 augustss #if notyet 1585 1.1 augustss case MOUSE_PROTO_MARIQUA: 1586 1.1 augustss /* 1587 1.1 augustss * This mouse has 16! buttons in addition to the standard 1588 1.1 augustss * three of them. They return 0x10 though 0x1f in the 1589 1.1 augustss * so-called `ten key' mode and 0x30 though 0x3f in the 1590 1.1 augustss * `function key' mode. As there are only 31 bits for 1591 1.1 augustss * button state (including the standard three), we ignore 1592 1.1 augustss * the bit 0x20 and don't distinguish the two modes. 1593 1.1 augustss */ 1594 1.1 augustss act->dx = act->dy = act->dz = 0; 1595 1.1 augustss act->obutton = act->button; 1596 1.1 augustss rBuf &= 0x1f; 1597 1.1 augustss act->button = (1 << (rBuf - 13)) 1598 1.1 augustss | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 1599 1.1 augustss /* 1600 1.1 augustss * FIXME: this is a button "down" event. There needs to be 1601 1.1 augustss * a corresponding button "up" event... XXX 1602 1.1 augustss */ 1603 1.1 augustss break; 1604 1.1 augustss #endif /* notyet */ 1605 1.1 augustss 1606 1.1 augustss /* 1607 1.1 augustss * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse 1608 1.1 augustss * always send the fourth byte, whereas the fourth byte is 1609 1.1 augustss * optional for GlidePoint and ThinkingMouse. The fourth byte 1610 1.1 augustss * is also optional for MouseMan+ and FirstMouse+ in their 1611 1.1 augustss * native mode. It is always sent if they are in the IntelliMouse 1612 1.1 augustss * compatible mode. 1613 1.1 augustss */ 1614 1.1 augustss case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse, 1615 1.1 augustss MouseMan+ */ 1616 1.1 augustss act->dx = act->dy = 0; 1617 1.1 augustss act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f); 1618 1.1 augustss if ((act->dz >= 7) || (act->dz <= -7)) 1619 1.1 augustss act->dz = 0; 1620 1.1 augustss act->obutton = act->button; 1621 1.1 augustss act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4] 1622 1.1 augustss | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 1623 1.1 augustss break; 1624 1.1 augustss 1625 1.1 augustss default: 1626 1.1 augustss act->dx = act->dy = act->dz = 0; 1627 1.1 augustss act->obutton = act->button; 1628 1.1 augustss act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4] 1629 1.1 augustss | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 1630 1.1 augustss break; 1631 1.1 augustss } 1632 1.1 augustss 1633 1.1 augustss act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0) 1634 1.1 augustss | (act->obutton ^ act->button); 1635 1.1 augustss pBufP = 0; 1636 1.1 augustss return act->flags; 1637 1.1 augustss } 1638 1.1 augustss 1639 1.1 augustss if (pBufP >= cur_proto[4]) 1640 1.1 augustss pBufP = 0; 1641 1.1 augustss pBuf[pBufP++] = rBuf; 1642 1.1 augustss if (pBufP != cur_proto[4]) 1643 1.1 augustss return 0; 1644 1.1 augustss 1645 1.1 augustss /* 1646 1.1 augustss * assembly full package 1647 1.1 augustss */ 1648 1.1 augustss 1649 1.1 augustss debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x", 1650 1.1 augustss cur_proto[4], 1651 1.1 augustss pBuf[0], pBuf[1], pBuf[2], pBuf[3], 1652 1.1 augustss pBuf[4], pBuf[5], pBuf[6], pBuf[7]); 1653 1.1 augustss 1654 1.1 augustss act->dz = 0; 1655 1.1 augustss act->obutton = act->button; 1656 1.1 augustss switch (rodent.rtype) 1657 1.1 augustss { 1658 1.1 augustss case MOUSE_PROTO_MS: /* Microsoft */ 1659 1.1 augustss case MOUSE_PROTO_LOGIMOUSEMAN: /* MouseMan/TrackMan */ 1660 1.1 augustss case MOUSE_PROTO_X10MOUSEREM: /* X10 MouseRemote */ 1661 1.1 augustss act->button = act->obutton & MOUSE_BUTTON4DOWN; 1662 1.1 augustss if (rodent.flags & ChordMiddle) 1663 1.1 augustss act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS) 1664 1.1 augustss ? MOUSE_BUTTON2DOWN 1665 1.1 augustss : butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 1666 1.1 augustss else 1667 1.1 augustss act->button |= (act->obutton & MOUSE_BUTTON2DOWN) 1668 1.1 augustss | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 1669 1.1 augustss 1670 1.2 augustss #if 0 1671 1.1 augustss /* Send X10 btn events to remote client (ensure -128-+127 range) */ 1672 1.1 augustss if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) && 1673 1.1 augustss ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) { 1674 1.1 augustss if (rodent.mremcfd >= 0) { 1675 1.1 augustss unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) | 1676 1.1 augustss (pBuf[1] & 0x3F)); 1677 1.1 augustss write( rodent.mremcfd, &key, 1 ); 1678 1.1 augustss } 1679 1.1 augustss return 0; 1680 1.1 augustss } 1681 1.2 augustss #endif 1682 1.1 augustss 1683 1.1 augustss act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); 1684 1.1 augustss act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); 1685 1.1 augustss break; 1686 1.1 augustss 1687 1.1 augustss case MOUSE_PROTO_GLIDEPOINT: /* GlidePoint */ 1688 1.1 augustss case MOUSE_PROTO_THINK: /* ThinkingMouse */ 1689 1.1 augustss case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse, 1690 1.1 augustss MouseMan+ */ 1691 1.1 augustss act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN)) 1692 1.1 augustss | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 1693 1.1 augustss act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); 1694 1.1 augustss act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); 1695 1.1 augustss break; 1696 1.1 augustss 1697 1.1 augustss case MOUSE_PROTO_MSC: /* MouseSystems Corp */ 1698 1.1 augustss #if notyet 1699 1.1 augustss case MOUSE_PROTO_MARIQUA: /* Mariqua */ 1700 1.1 augustss #endif 1701 1.1 augustss act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS]; 1702 1.1 augustss act->dx = (char)(pBuf[1]) + (char)(pBuf[3]); 1703 1.1 augustss act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4])); 1704 1.1 augustss break; 1705 1.1 augustss 1706 1.1 augustss case MOUSE_PROTO_HITTAB: /* MM HitTablet */ 1707 1.1 augustss act->button = butmaphit[pBuf[0] & 0x07]; 1708 1.1 augustss act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1]; 1709 1.1 augustss act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2]; 1710 1.1 augustss break; 1711 1.1 augustss 1712 1.1 augustss case MOUSE_PROTO_MM: /* MM Series */ 1713 1.1 augustss case MOUSE_PROTO_LOGI: /* Logitech Mice */ 1714 1.1 augustss act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS]; 1715 1.1 augustss act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1]; 1716 1.1 augustss act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2]; 1717 1.1 augustss break; 1718 1.1 augustss 1719 1.1 augustss case MOUSE_PROTO_VERSAPAD: /* VersaPad */ 1720 1.1 augustss act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3]; 1721 1.1 augustss act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 1722 1.1 augustss act->dx = act->dy = 0; 1723 1.1 augustss if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) { 1724 1.1 augustss on = FALSE; 1725 1.1 augustss break; 1726 1.1 augustss } 1727 1.1 augustss x = (pBuf[2] << 6) | pBuf[1]; 1728 1.1 augustss if (x & 0x800) 1729 1.1 augustss x -= 0x1000; 1730 1.1 augustss y = (pBuf[4] << 6) | pBuf[3]; 1731 1.1 augustss if (y & 0x800) 1732 1.1 augustss y -= 0x1000; 1733 1.1 augustss if (on) { 1734 1.1 augustss act->dx = prev_x - x; 1735 1.1 augustss act->dy = prev_y - y; 1736 1.1 augustss } else { 1737 1.1 augustss on = TRUE; 1738 1.1 augustss } 1739 1.1 augustss prev_x = x; 1740 1.1 augustss prev_y = y; 1741 1.1 augustss break; 1742 1.1 augustss 1743 1.1 augustss case MOUSE_PROTO_BUS: /* Bus */ 1744 1.1 augustss case MOUSE_PROTO_INPORT: /* InPort */ 1745 1.1 augustss act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS]; 1746 1.1 augustss act->dx = (char)pBuf[1]; 1747 1.1 augustss act->dy = - (char)pBuf[2]; 1748 1.1 augustss break; 1749 1.1 augustss 1750 1.1 augustss case MOUSE_PROTO_PS2: /* PS/2 */ 1751 1.1 augustss act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS]; 1752 1.1 augustss act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ? pBuf[1] - 256 : pBuf[1]; 1753 1.1 augustss act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ? -(pBuf[2] - 256) : -pBuf[2]; 1754 1.1 augustss /* 1755 1.1 augustss * Moused usually operates the psm driver at the operation level 1 1756 1.1 augustss * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol. 1757 1.1 augustss * The following code takes effect only when the user explicitly 1758 1.27 andvar * requests the level 2 at which wheel movement and additional button 1759 1.1 augustss * actions are encoded in model-dependent formats. At the level 0 1760 1.1 augustss * the following code is no-op because the psm driver says the model 1761 1.1 augustss * is MOUSE_MODEL_GENERIC. 1762 1.1 augustss */ 1763 1.1 augustss switch (rodent.hw.model) { 1764 1.1 augustss case MOUSE_MODEL_EXPLORER: 1765 1.1 augustss /* wheel and additional button data is in the fourth byte */ 1766 1.1 augustss act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG) 1767 1.1 augustss ? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f); 1768 1.1 augustss act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN) 1769 1.1 augustss ? MOUSE_BUTTON4DOWN : 0; 1770 1.1 augustss act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN) 1771 1.1 augustss ? MOUSE_BUTTON5DOWN : 0; 1772 1.1 augustss break; 1773 1.1 augustss case MOUSE_MODEL_INTELLI: 1774 1.1 augustss case MOUSE_MODEL_NET: 1775 1.1 augustss /* wheel data is in the fourth byte */ 1776 1.1 augustss act->dz = (char)pBuf[3]; 1777 1.1 augustss if ((act->dz >= 7) || (act->dz <= -7)) 1778 1.1 augustss act->dz = 0; 1779 1.1 augustss /* some compatible mice may have additional buttons */ 1780 1.1 augustss act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN) 1781 1.1 augustss ? MOUSE_BUTTON4DOWN : 0; 1782 1.1 augustss act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN) 1783 1.1 augustss ? MOUSE_BUTTON5DOWN : 0; 1784 1.1 augustss break; 1785 1.1 augustss case MOUSE_MODEL_MOUSEMANPLUS: 1786 1.1 augustss if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) 1787 1.1 augustss && (abs(act->dx) > 191) 1788 1.1 augustss && MOUSE_PS2PLUS_CHECKBITS(pBuf)) { 1789 1.1 augustss /* the extended data packet encodes button and wheel events */ 1790 1.1 augustss switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) { 1791 1.1 augustss case 1: 1792 1.1 augustss /* wheel data packet */ 1793 1.1 augustss act->dx = act->dy = 0; 1794 1.1 augustss if (pBuf[2] & 0x80) { 1795 1.1 augustss /* horizontal roller count - ignore it XXX*/ 1796 1.1 augustss } else { 1797 1.1 augustss /* vertical roller count */ 1798 1.1 augustss act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG) 1799 1.1 augustss ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); 1800 1.1 augustss } 1801 1.1 augustss act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN) 1802 1.1 augustss ? MOUSE_BUTTON4DOWN : 0; 1803 1.1 augustss act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN) 1804 1.1 augustss ? MOUSE_BUTTON5DOWN : 0; 1805 1.1 augustss break; 1806 1.1 augustss case 2: 1807 1.1 augustss /* this packet type is reserved by Logitech */ 1808 1.1 augustss /* 1809 1.1 augustss * IBM ScrollPoint Mouse uses this packet type to 1810 1.1 augustss * encode both vertical and horizontal scroll movement. 1811 1.1 augustss */ 1812 1.1 augustss act->dx = act->dy = 0; 1813 1.1 augustss /* horizontal roller count */ 1814 1.1 augustss if (pBuf[2] & 0x0f) 1815 1.1 augustss act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2; 1816 1.1 augustss /* vertical roller count */ 1817 1.1 augustss if (pBuf[2] & 0xf0) 1818 1.1 augustss act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1; 1819 1.1 augustss #if 0 1820 1.1 augustss /* vertical roller count */ 1821 1.1 augustss act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) 1822 1.1 augustss ? ((pBuf[2] >> 4) & 0x0f) - 16 1823 1.1 augustss : ((pBuf[2] >> 4) & 0x0f); 1824 1.1 augustss /* horizontal roller count */ 1825 1.1 augustss act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG) 1826 1.1 augustss ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); 1827 1.1 augustss #endif 1828 1.1 augustss break; 1829 1.1 augustss case 0: 1830 1.1 augustss /* device type packet - shouldn't happen */ 1831 1.1 augustss /* FALL THROUGH */ 1832 1.1 augustss default: 1833 1.1 augustss act->dx = act->dy = 0; 1834 1.1 augustss act->button = act->obutton; 1835 1.1 augustss debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n", 1836 1.1 augustss MOUSE_PS2PLUS_PACKET_TYPE(pBuf), 1837 1.1 augustss pBuf[0], pBuf[1], pBuf[2]); 1838 1.1 augustss break; 1839 1.1 augustss } 1840 1.1 augustss } else { 1841 1.1 augustss /* preserve button states */ 1842 1.1 augustss act->button |= act->obutton & MOUSE_EXTBUTTONS; 1843 1.1 augustss } 1844 1.1 augustss break; 1845 1.1 augustss case MOUSE_MODEL_GLIDEPOINT: 1846 1.1 augustss /* `tapping' action */ 1847 1.1 augustss act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN; 1848 1.1 augustss break; 1849 1.1 augustss case MOUSE_MODEL_NETSCROLL: 1850 1.1 augustss /* three addtional bytes encode buttons and wheel events */ 1851 1.1 augustss act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN) 1852 1.1 augustss ? MOUSE_BUTTON4DOWN : 0; 1853 1.1 augustss act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN) 1854 1.1 augustss ? MOUSE_BUTTON5DOWN : 0; 1855 1.1 augustss act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4]; 1856 1.1 augustss break; 1857 1.1 augustss case MOUSE_MODEL_THINK: 1858 1.1 augustss /* the fourth button state in the first byte */ 1859 1.1 augustss act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0; 1860 1.1 augustss break; 1861 1.1 augustss case MOUSE_MODEL_VERSAPAD: 1862 1.1 augustss act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS]; 1863 1.1 augustss act->button |= 1864 1.1 augustss (pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 1865 1.1 augustss act->dx = act->dy = 0; 1866 1.1 augustss if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) { 1867 1.1 augustss on = FALSE; 1868 1.1 augustss break; 1869 1.1 augustss } 1870 1.1 augustss x = ((pBuf[4] << 8) & 0xf00) | pBuf[1]; 1871 1.1 augustss if (x & 0x800) 1872 1.1 augustss x -= 0x1000; 1873 1.1 augustss y = ((pBuf[4] << 4) & 0xf00) | pBuf[2]; 1874 1.1 augustss if (y & 0x800) 1875 1.1 augustss y -= 0x1000; 1876 1.1 augustss if (on) { 1877 1.1 augustss act->dx = prev_x - x; 1878 1.1 augustss act->dy = prev_y - y; 1879 1.1 augustss } else { 1880 1.1 augustss on = TRUE; 1881 1.1 augustss } 1882 1.1 augustss prev_x = x; 1883 1.1 augustss prev_y = y; 1884 1.1 augustss break; 1885 1.1 augustss case MOUSE_MODEL_4D: 1886 1.1 augustss act->dx = (pBuf[1] & 0x80) ? pBuf[1] - 256 : pBuf[1]; 1887 1.1 augustss act->dy = (pBuf[2] & 0x80) ? -(pBuf[2] - 256) : -pBuf[2]; 1888 1.1 augustss switch (pBuf[0] & MOUSE_4D_WHEELBITS) { 1889 1.1 augustss case 0x10: 1890 1.1 augustss act->dz = 1; 1891 1.1 augustss break; 1892 1.1 augustss case 0x30: 1893 1.1 augustss act->dz = -1; 1894 1.1 augustss break; 1895 1.1 augustss case 0x40: /* 2nd wheel rolling right XXX */ 1896 1.1 augustss act->dz = 2; 1897 1.1 augustss break; 1898 1.1 augustss case 0xc0: /* 2nd wheel rolling left XXX */ 1899 1.1 augustss act->dz = -2; 1900 1.1 augustss break; 1901 1.1 augustss } 1902 1.1 augustss break; 1903 1.1 augustss case MOUSE_MODEL_4DPLUS: 1904 1.1 augustss if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) { 1905 1.1 augustss act->dx = act->dy = 0; 1906 1.1 augustss if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN) 1907 1.1 augustss act->button |= MOUSE_BUTTON4DOWN; 1908 1.1 augustss act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG) 1909 1.1 augustss ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07); 1910 1.1 augustss } else { 1911 1.1 augustss /* preserve previous button states */ 1912 1.1 augustss act->button |= act->obutton & MOUSE_EXTBUTTONS; 1913 1.1 augustss } 1914 1.1 augustss break; 1915 1.1 augustss case MOUSE_MODEL_GENERIC: 1916 1.1 augustss default: 1917 1.1 augustss break; 1918 1.1 augustss } 1919 1.1 augustss break; 1920 1.1 augustss 1921 1.1 augustss case MOUSE_PROTO_SYSMOUSE: /* sysmouse */ 1922 1.1 augustss act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS]; 1923 1.1 augustss act->dx = (char)(pBuf[1]) + (char)(pBuf[3]); 1924 1.1 augustss act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4])); 1925 1.1 augustss if (rodent.level == 1) { 1926 1.1 augustss act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1))/2; 1927 1.1 augustss act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3); 1928 1.1 augustss } 1929 1.1 augustss break; 1930 1.1 augustss 1931 1.1 augustss default: 1932 1.1 augustss return 0; 1933 1.1 augustss } 1934 1.1 augustss /* 1935 1.1 augustss * We don't reset pBufP here yet, as there may be an additional data 1936 1.1 augustss * byte in some protocols. See above. 1937 1.1 augustss */ 1938 1.1 augustss 1939 1.1 augustss /* has something changed? */ 1940 1.1 augustss act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0) 1941 1.1 augustss | (act->obutton ^ act->button); 1942 1.1 augustss 1943 1.1 augustss return act->flags; 1944 1.1 augustss } 1945 1.1 augustss 1946 1.1 augustss static int 1947 1.1 augustss r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans) 1948 1.1 augustss { 1949 1.1 augustss int changed; 1950 1.1 augustss int flags; 1951 1.1 augustss 1952 1.1 augustss a2->dx = a1->dx; 1953 1.1 augustss a2->dy = a1->dy; 1954 1.1 augustss a2->dz = a1->dz; 1955 1.1 augustss a2->obutton = a2->button; 1956 1.1 augustss a2->button = a1->button; 1957 1.1 augustss a2->flags = a1->flags; 1958 1.1 augustss changed = FALSE; 1959 1.1 augustss 1960 1.1 augustss if (rodent.flags & Emulate3Button) { 1961 1.5 thorpej if (dbg > 2) 1962 1.1 augustss debug("state:%d, trans:%d -> state:%d", 1963 1.1 augustss mouse_button_state, trans, 1964 1.1 augustss states[mouse_button_state].s[trans]); 1965 1.1 augustss /* 1966 1.1 augustss * Avoid re-ordering button and movement events. While a button 1967 1.1 augustss * event is deferred, throw away up to BUTTON2_MAXMOVE movement 1968 1.1 augustss * events to allow for mouse jitter. If more movement events 1969 1.1 augustss * occur, then complete the deferred button events immediately. 1970 1.1 augustss */ 1971 1.1 augustss if ((a2->dx != 0 || a2->dy != 0) && 1972 1.1 augustss S_DELAYED(states[mouse_button_state].s[trans])) { 1973 1.1 augustss if (++mouse_move_delayed > BUTTON2_MAXMOVE) { 1974 1.1 augustss mouse_move_delayed = 0; 1975 1.1 augustss mouse_button_state = 1976 1.1 augustss states[mouse_button_state].s[A_TIMEOUT]; 1977 1.1 augustss changed = TRUE; 1978 1.1 augustss } else 1979 1.1 augustss a2->dx = a2->dy = 0; 1980 1.1 augustss } else 1981 1.1 augustss mouse_move_delayed = 0; 1982 1.1 augustss if (mouse_button_state != states[mouse_button_state].s[trans]) 1983 1.1 augustss changed = TRUE; 1984 1.1 augustss if (changed) 1985 1.1 augustss gettimeofday(&mouse_button_state_tv, NULL); 1986 1.1 augustss mouse_button_state = states[mouse_button_state].s[trans]; 1987 1.1 augustss a2->button &= 1988 1.1 augustss ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN); 1989 1.1 augustss a2->button &= states[mouse_button_state].mask; 1990 1.1 augustss a2->button |= states[mouse_button_state].buttons; 1991 1.1 augustss flags = a2->flags & MOUSE_POSCHANGED; 1992 1.1 augustss flags |= a2->obutton ^ a2->button; 1993 1.1 augustss if (flags & MOUSE_BUTTON2DOWN) { 1994 1.1 augustss a2->flags = flags & MOUSE_BUTTON2DOWN; 1995 1.1 augustss r_timestamp(a2); 1996 1.1 augustss } 1997 1.1 augustss a2->flags = flags; 1998 1.1 augustss } 1999 1.1 augustss return changed; 2000 1.1 augustss } 2001 1.1 augustss 2002 1.1 augustss /* phisical to logical button mapping */ 2003 1.1 augustss static int p2l[MOUSE_MAXBUTTON] = { 2004 1.1 augustss MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN, 2005 1.1 augustss MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN, 2006 1.1 augustss 0x00000100, 0x00000200, 0x00000400, 0x00000800, 2007 1.1 augustss 0x00001000, 0x00002000, 0x00004000, 0x00008000, 2008 1.1 augustss 0x00010000, 0x00020000, 0x00040000, 0x00080000, 2009 1.1 augustss 0x00100000, 0x00200000, 0x00400000, 0x00800000, 2010 1.1 augustss 0x01000000, 0x02000000, 0x04000000, 0x08000000, 2011 1.1 augustss 0x10000000, 0x20000000, 0x40000000, 2012 1.1 augustss }; 2013 1.1 augustss 2014 1.1 augustss static char * 2015 1.1 augustss skipspace(char *s) 2016 1.1 augustss { 2017 1.14 dsl while(isspace((unsigned char)*s)) 2018 1.1 augustss ++s; 2019 1.1 augustss return s; 2020 1.1 augustss } 2021 1.1 augustss 2022 1.1 augustss static int 2023 1.1 augustss r_installmap(char *arg) 2024 1.1 augustss { 2025 1.1 augustss int pbutton; 2026 1.1 augustss int lbutton; 2027 1.1 augustss char *s; 2028 1.1 augustss 2029 1.1 augustss while (*arg) { 2030 1.1 augustss arg = skipspace(arg); 2031 1.1 augustss s = arg; 2032 1.14 dsl while (isdigit((unsigned char)*arg)) 2033 1.1 augustss ++arg; 2034 1.1 augustss arg = skipspace(arg); 2035 1.1 augustss if ((arg <= s) || (*arg != '=')) 2036 1.1 augustss return FALSE; 2037 1.1 augustss lbutton = atoi(s); 2038 1.1 augustss 2039 1.23 joerg arg = skipspace(arg + 1); 2040 1.1 augustss s = arg; 2041 1.14 dsl while (isdigit((unsigned char)*arg)) 2042 1.1 augustss ++arg; 2043 1.14 dsl if ((arg <= s) || (!isspace((unsigned char)*arg) && (*arg != '\0'))) 2044 1.1 augustss return FALSE; 2045 1.1 augustss pbutton = atoi(s); 2046 1.1 augustss 2047 1.1 augustss if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON)) 2048 1.1 augustss return FALSE; 2049 1.1 augustss if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON)) 2050 1.1 augustss return FALSE; 2051 1.1 augustss p2l[pbutton - 1] = 1 << (lbutton - 1); 2052 1.1 augustss mstate[lbutton - 1] = &bstate[pbutton - 1]; 2053 1.1 augustss } 2054 1.1 augustss 2055 1.1 augustss return TRUE; 2056 1.1 augustss } 2057 1.1 augustss 2058 1.1 augustss static void 2059 1.1 augustss r_map(mousestatus_t *act1, mousestatus_t *act2) 2060 1.1 augustss { 2061 1.1 augustss register int pb; 2062 1.1 augustss register int pbuttons; 2063 1.1 augustss int lbuttons; 2064 1.1 augustss 2065 1.1 augustss pbuttons = act1->button; 2066 1.1 augustss lbuttons = 0; 2067 1.1 augustss 2068 1.1 augustss act2->obutton = act2->button; 2069 1.1 augustss if (pbuttons & rodent.wmode) { 2070 1.1 augustss pbuttons &= ~rodent.wmode; 2071 1.1 augustss act1->dz = act1->dy; 2072 1.1 augustss act1->dx = 0; 2073 1.1 augustss act1->dy = 0; 2074 1.1 augustss } 2075 1.1 augustss act2->dx = act1->dx; 2076 1.1 augustss act2->dy = act1->dy; 2077 1.1 augustss act2->dz = act1->dz; 2078 1.1 augustss 2079 1.1 augustss switch (rodent.zmap[0]) { 2080 1.1 augustss case 0: /* do nothing */ 2081 1.1 augustss break; 2082 1.1 augustss case MOUSE_XAXIS: 2083 1.1 augustss if (act1->dz != 0) { 2084 1.1 augustss act2->dx = act1->dz; 2085 1.1 augustss act2->dz = 0; 2086 1.1 augustss } 2087 1.1 augustss break; 2088 1.1 augustss case MOUSE_YAXIS: 2089 1.1 augustss if (act1->dz != 0) { 2090 1.1 augustss act2->dy = act1->dz; 2091 1.1 augustss act2->dz = 0; 2092 1.1 augustss } 2093 1.1 augustss break; 2094 1.1 augustss default: /* buttons */ 2095 1.1 augustss pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1] 2096 1.1 augustss | rodent.zmap[2] | rodent.zmap[3]); 2097 1.1 augustss if ((act1->dz < -1) && rodent.zmap[2]) { 2098 1.1 augustss pbuttons |= rodent.zmap[2]; 2099 1.1 augustss zstate[2].count = 1; 2100 1.1 augustss } else if (act1->dz < 0) { 2101 1.1 augustss pbuttons |= rodent.zmap[0]; 2102 1.1 augustss zstate[0].count = 1; 2103 1.1 augustss } else if ((act1->dz > 1) && rodent.zmap[3]) { 2104 1.1 augustss pbuttons |= rodent.zmap[3]; 2105 1.1 augustss zstate[3].count = 1; 2106 1.1 augustss } else if (act1->dz > 0) { 2107 1.1 augustss pbuttons |= rodent.zmap[1]; 2108 1.1 augustss zstate[1].count = 1; 2109 1.1 augustss } 2110 1.1 augustss act2->dz = 0; 2111 1.1 augustss break; 2112 1.1 augustss } 2113 1.1 augustss 2114 1.1 augustss for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) { 2115 1.1 augustss lbuttons |= (pbuttons & 1) ? p2l[pb] : 0; 2116 1.1 augustss pbuttons >>= 1; 2117 1.1 augustss } 2118 1.1 augustss act2->button = lbuttons; 2119 1.1 augustss 2120 1.1 augustss act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0) 2121 1.1 augustss | (act2->obutton ^ act2->button); 2122 1.1 augustss } 2123 1.1 augustss 2124 1.1 augustss static void 2125 1.1 augustss r_timestamp(mousestatus_t *act) 2126 1.1 augustss { 2127 1.1 augustss struct timeval tv; 2128 1.1 augustss struct timeval tv1; 2129 1.1 augustss struct timeval tv2; 2130 1.1 augustss struct timeval tv3; 2131 1.1 augustss int button; 2132 1.1 augustss int mask; 2133 1.1 augustss int i; 2134 1.1 augustss 2135 1.1 augustss mask = act->flags & MOUSE_BUTTONS; 2136 1.1 augustss #if 0 2137 1.1 augustss if (mask == 0) 2138 1.1 augustss return; 2139 1.1 augustss #endif 2140 1.1 augustss 2141 1.1 augustss gettimeofday(&tv1, NULL); 2142 1.1 augustss 2143 1.1 augustss /* double click threshold */ 2144 1.1 augustss tv2.tv_sec = rodent.clickthreshold/1000; 2145 1.1 augustss tv2.tv_usec = (rodent.clickthreshold%1000)*1000; 2146 1.1 augustss timersub(&tv1, &tv2, &tv); 2147 1.22 christos debug("tv: %jd %jd", (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec); 2148 1.1 augustss 2149 1.1 augustss /* 3 button emulation timeout */ 2150 1.1 augustss tv2.tv_sec = rodent.button2timeout/1000; 2151 1.1 augustss tv2.tv_usec = (rodent.button2timeout%1000)*1000; 2152 1.1 augustss timersub(&tv1, &tv2, &tv3); 2153 1.1 augustss 2154 1.1 augustss button = MOUSE_BUTTON1DOWN; 2155 1.1 augustss for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) { 2156 1.1 augustss if (mask & 1) { 2157 1.1 augustss if (act->button & button) { 2158 1.1 augustss /* the button is down */ 2159 1.22 christos debug(" : %jd %jd", 2160 1.22 christos (intmax_t)bstate[i].tv.tv_sec, 2161 1.22 christos (intmax_t)bstate[i].tv.tv_usec); 2162 1.1 augustss if (timercmp(&tv, &bstate[i].tv, >)) { 2163 1.1 augustss bstate[i].count = 1; 2164 1.1 augustss } else { 2165 1.1 augustss ++bstate[i].count; 2166 1.1 augustss } 2167 1.1 augustss bstate[i].tv = tv1; 2168 1.1 augustss } else { 2169 1.1 augustss /* the button is up */ 2170 1.1 augustss bstate[i].tv = tv1; 2171 1.1 augustss } 2172 1.1 augustss } else { 2173 1.1 augustss if (act->button & button) { 2174 1.1 augustss /* the button has been down */ 2175 1.1 augustss if (timercmp(&tv3, &bstate[i].tv, >)) { 2176 1.1 augustss bstate[i].count = 1; 2177 1.1 augustss bstate[i].tv = tv1; 2178 1.1 augustss act->flags |= button; 2179 1.1 augustss debug("button %d timeout", i + 1); 2180 1.1 augustss } 2181 1.1 augustss } else { 2182 1.1 augustss /* the button has been up */ 2183 1.1 augustss } 2184 1.1 augustss } 2185 1.1 augustss button <<= 1; 2186 1.1 augustss mask >>= 1; 2187 1.1 augustss } 2188 1.1 augustss } 2189 1.1 augustss 2190 1.1 augustss static int 2191 1.1 augustss r_timeout(void) 2192 1.1 augustss { 2193 1.1 augustss struct timeval tv; 2194 1.1 augustss struct timeval tv1; 2195 1.1 augustss struct timeval tv2; 2196 1.1 augustss 2197 1.1 augustss if (states[mouse_button_state].timeout) 2198 1.1 augustss return TRUE; 2199 1.1 augustss gettimeofday(&tv1, NULL); 2200 1.1 augustss tv2.tv_sec = rodent.button2timeout/1000; 2201 1.1 augustss tv2.tv_usec = (rodent.button2timeout%1000)*1000; 2202 1.1 augustss timersub(&tv1, &tv2, &tv); 2203 1.1 augustss return timercmp(&tv, &mouse_button_state_tv, >); 2204 1.1 augustss } 2205 1.1 augustss 2206 1.1 augustss /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */ 2207 1.1 augustss /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */ 2208 1.1 augustss /* 2209 1.1 augustss * Copyright 1993 by David Dawes <dawes (at) physics.su.oz.au> 2210 1.1 augustss * 2211 1.1 augustss * Permission to use, copy, modify, distribute, and sell this software and its 2212 1.1 augustss * documentation for any purpose is hereby granted without fee, provided that 2213 1.1 augustss * the above copyright notice appear in all copies and that both that 2214 1.1 augustss * copyright notice and this permission notice appear in supporting 2215 1.1 augustss * documentation, and that the name of David Dawes 2216 1.1 augustss * not be used in advertising or publicity pertaining to distribution of 2217 1.1 augustss * the software without specific, written prior permission. 2218 1.1 augustss * David Dawes makes no representations about the suitability of this 2219 1.1 augustss * software for any purpose. It is provided "as is" without express or 2220 1.1 augustss * implied warranty. 2221 1.1 augustss * 2222 1.1 augustss * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO 2223 1.1 augustss * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 2224 1.1 augustss * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR 2225 1.1 augustss * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 2226 1.1 augustss * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 2227 1.1 augustss * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 2228 1.1 augustss * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2229 1.1 augustss * 2230 1.1 augustss */ 2231 1.1 augustss 2232 1.1 augustss 2233 1.1 augustss static void 2234 1.1 augustss setmousespeed(int old, int new, unsigned cflag) 2235 1.1 augustss { 2236 1.1 augustss struct termios tty; 2237 1.18 lukem const char *c; 2238 1.1 augustss 2239 1.1 augustss if (tcgetattr(rodent.mfd, &tty) < 0) 2240 1.1 augustss { 2241 1.4 thorpej logwarn("unable to get status of mouse fd"); 2242 1.1 augustss return; 2243 1.1 augustss } 2244 1.1 augustss 2245 1.1 augustss tty.c_iflag = IGNBRK | IGNPAR; 2246 1.1 augustss tty.c_oflag = 0; 2247 1.1 augustss tty.c_lflag = 0; 2248 1.1 augustss tty.c_cflag = (tcflag_t)cflag; 2249 1.1 augustss tty.c_cc[VTIME] = 0; 2250 1.1 augustss tty.c_cc[VMIN] = 1; 2251 1.1 augustss 2252 1.1 augustss switch (old) 2253 1.1 augustss { 2254 1.1 augustss case 9600: 2255 1.1 augustss cfsetispeed(&tty, B9600); 2256 1.1 augustss cfsetospeed(&tty, B9600); 2257 1.1 augustss break; 2258 1.1 augustss case 4800: 2259 1.1 augustss cfsetispeed(&tty, B4800); 2260 1.1 augustss cfsetospeed(&tty, B4800); 2261 1.1 augustss break; 2262 1.1 augustss case 2400: 2263 1.1 augustss cfsetispeed(&tty, B2400); 2264 1.1 augustss cfsetospeed(&tty, B2400); 2265 1.1 augustss break; 2266 1.1 augustss case 1200: 2267 1.1 augustss default: 2268 1.1 augustss cfsetispeed(&tty, B1200); 2269 1.1 augustss cfsetospeed(&tty, B1200); 2270 1.1 augustss } 2271 1.1 augustss 2272 1.1 augustss if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0) 2273 1.1 augustss { 2274 1.4 thorpej logwarn("unable to set status of mouse fd"); 2275 1.1 augustss return; 2276 1.1 augustss } 2277 1.1 augustss 2278 1.1 augustss switch (new) 2279 1.1 augustss { 2280 1.1 augustss case 9600: 2281 1.1 augustss c = "*q"; 2282 1.1 augustss cfsetispeed(&tty, B9600); 2283 1.1 augustss cfsetospeed(&tty, B9600); 2284 1.1 augustss break; 2285 1.1 augustss case 4800: 2286 1.1 augustss c = "*p"; 2287 1.1 augustss cfsetispeed(&tty, B4800); 2288 1.1 augustss cfsetospeed(&tty, B4800); 2289 1.1 augustss break; 2290 1.1 augustss case 2400: 2291 1.1 augustss c = "*o"; 2292 1.1 augustss cfsetispeed(&tty, B2400); 2293 1.1 augustss cfsetospeed(&tty, B2400); 2294 1.1 augustss break; 2295 1.1 augustss case 1200: 2296 1.1 augustss default: 2297 1.1 augustss c = "*n"; 2298 1.1 augustss cfsetispeed(&tty, B1200); 2299 1.1 augustss cfsetospeed(&tty, B1200); 2300 1.1 augustss } 2301 1.1 augustss 2302 1.1 augustss if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN 2303 1.1 augustss || rodent.rtype == MOUSE_PROTO_LOGI) 2304 1.1 augustss { 2305 1.1 augustss if (write(rodent.mfd, c, 2) != 2) 2306 1.1 augustss { 2307 1.4 thorpej logwarn("unable to write to mouse fd"); 2308 1.1 augustss return; 2309 1.1 augustss } 2310 1.1 augustss } 2311 1.1 augustss usleep(100000); 2312 1.1 augustss 2313 1.1 augustss if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0) 2314 1.4 thorpej logwarn("unable to set status of mouse fd"); 2315 1.1 augustss } 2316 1.1 augustss 2317 1.1 augustss /* 2318 1.1 augustss * PnP COM device support 2319 1.1 augustss * 2320 1.1 augustss * It's a simplistic implementation, but it works :-) 2321 1.1 augustss * KY, 31/7/97. 2322 1.1 augustss */ 2323 1.1 augustss 2324 1.1 augustss /* 2325 1.1 augustss * Try to elicit a PnP ID as described in 2326 1.1 augustss * Microsoft, Hayes: "Plug and Play External COM Device Specification, 2327 1.1 augustss * rev 1.00", 1995. 2328 1.1 augustss * 2329 1.1 augustss * The routine does not fully implement the COM Enumerator as par Section 2330 1.1 augustss * 2.1 of the document. In particular, we don't have idle state in which 2331 1.1 augustss * the driver software monitors the com port for dynamic connection or 2332 1.1 augustss * removal of a device at the port, because `moused' simply quits if no 2333 1.1 augustss * device is found. 2334 1.1 augustss * 2335 1.1 augustss * In addition, as PnP COM device enumeration procedure slightly has 2336 1.1 augustss * changed since its first publication, devices which follow earlier 2337 1.1 augustss * revisions of the above spec. may fail to respond if the rev 1.0 2338 1.1 augustss * procedure is used. XXX 2339 1.1 augustss */ 2340 1.1 augustss static int 2341 1.1 augustss pnpwakeup1(void) 2342 1.1 augustss { 2343 1.8 mycroft struct pollfd set[1]; 2344 1.1 augustss int i; 2345 1.1 augustss 2346 1.1 augustss /* 2347 1.1 augustss * This is the procedure described in rev 1.0 of PnP COM device spec. 2348 1.1 augustss * Unfortunately, some devices which comform to earlier revisions of 2349 1.1 augustss * the spec gets confused and do not return the ID string... 2350 1.1 augustss */ 2351 1.1 augustss debug("PnP COM device rev 1.0 probe..."); 2352 1.1 augustss 2353 1.1 augustss /* port initialization (2.1.2) */ 2354 1.1 augustss ioctl(rodent.mfd, TIOCMGET, &i); 2355 1.1 augustss i |= TIOCM_DTR; /* DTR = 1 */ 2356 1.1 augustss i &= ~TIOCM_RTS; /* RTS = 0 */ 2357 1.1 augustss ioctl(rodent.mfd, TIOCMSET, &i); 2358 1.1 augustss usleep(240000); 2359 1.1 augustss 2360 1.1 augustss /* 2361 1.1 augustss * The PnP COM device spec. dictates that the mouse must set DSR 2362 1.1 augustss * in response to DTR (by hardware or by software) and that if DSR is 2363 1.1 augustss * not asserted, the host computer should think that there is no device 2364 1.1 augustss * at this serial port. But some mice just don't do that... 2365 1.1 augustss */ 2366 1.1 augustss ioctl(rodent.mfd, TIOCMGET, &i); 2367 1.1 augustss debug("modem status 0%o", i); 2368 1.1 augustss if ((i & TIOCM_DSR) == 0) 2369 1.1 augustss return FALSE; 2370 1.1 augustss 2371 1.1 augustss /* port setup, 1st phase (2.1.3) */ 2372 1.1 augustss setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL)); 2373 1.1 augustss i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 2374 1.1 augustss ioctl(rodent.mfd, TIOCMBIC, &i); 2375 1.1 augustss usleep(240000); 2376 1.1 augustss i = TIOCM_DTR; /* DTR = 1, RTS = 0 */ 2377 1.1 augustss ioctl(rodent.mfd, TIOCMBIS, &i); 2378 1.1 augustss usleep(240000); 2379 1.1 augustss 2380 1.1 augustss /* wait for response, 1st phase (2.1.4) */ 2381 1.1 augustss i = FREAD; 2382 1.1 augustss ioctl(rodent.mfd, TIOCFLUSH, &i); 2383 1.1 augustss i = TIOCM_RTS; /* DTR = 1, RTS = 1 */ 2384 1.1 augustss ioctl(rodent.mfd, TIOCMBIS, &i); 2385 1.1 augustss 2386 1.1 augustss /* try to read something */ 2387 1.8 mycroft set[0].fd = rodent.mfd; 2388 1.8 mycroft set[0].events = POLLIN; 2389 1.8 mycroft if (poll(set, 1, 240) > 0) { 2390 1.1 augustss debug("pnpwakeup1(): valid response in first phase."); 2391 1.1 augustss return TRUE; 2392 1.1 augustss } 2393 1.1 augustss 2394 1.1 augustss /* port setup, 2nd phase (2.1.5) */ 2395 1.1 augustss i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 2396 1.1 augustss ioctl(rodent.mfd, TIOCMBIC, &i); 2397 1.1 augustss usleep(240000); 2398 1.1 augustss 2399 1.33 andvar /* wait for response, 2nd phase (2.1.6) */ 2400 1.1 augustss i = FREAD; 2401 1.1 augustss ioctl(rodent.mfd, TIOCFLUSH, &i); 2402 1.1 augustss i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 2403 1.1 augustss ioctl(rodent.mfd, TIOCMBIS, &i); 2404 1.1 augustss 2405 1.1 augustss /* try to read something */ 2406 1.8 mycroft if (poll(set, 1, 240) > 0) { 2407 1.1 augustss debug("pnpwakeup1(): valid response in second phase."); 2408 1.1 augustss return TRUE; 2409 1.1 augustss } 2410 1.1 augustss 2411 1.1 augustss return FALSE; 2412 1.1 augustss } 2413 1.1 augustss 2414 1.1 augustss static int 2415 1.1 augustss pnpwakeup2(void) 2416 1.1 augustss { 2417 1.8 mycroft struct pollfd set[1]; 2418 1.1 augustss int i; 2419 1.1 augustss 2420 1.1 augustss /* 2421 1.1 augustss * This is a simplified procedure; it simply toggles RTS. 2422 1.1 augustss */ 2423 1.1 augustss debug("alternate probe..."); 2424 1.1 augustss 2425 1.1 augustss ioctl(rodent.mfd, TIOCMGET, &i); 2426 1.1 augustss i |= TIOCM_DTR; /* DTR = 1 */ 2427 1.1 augustss i &= ~TIOCM_RTS; /* RTS = 0 */ 2428 1.1 augustss ioctl(rodent.mfd, TIOCMSET, &i); 2429 1.1 augustss usleep(240000); 2430 1.1 augustss 2431 1.1 augustss setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL)); 2432 1.1 augustss 2433 1.33 andvar /* wait for response */ 2434 1.1 augustss i = FREAD; 2435 1.1 augustss ioctl(rodent.mfd, TIOCFLUSH, &i); 2436 1.1 augustss i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 2437 1.1 augustss ioctl(rodent.mfd, TIOCMBIS, &i); 2438 1.1 augustss 2439 1.1 augustss /* try to read something */ 2440 1.8 mycroft set[0].fd = rodent.mfd; 2441 1.8 mycroft set[0].events = POLLIN; 2442 1.8 mycroft if (poll(set, 1, 240) > 0) { 2443 1.1 augustss debug("pnpwakeup2(): valid response."); 2444 1.1 augustss return TRUE; 2445 1.1 augustss } 2446 1.1 augustss 2447 1.1 augustss return FALSE; 2448 1.1 augustss } 2449 1.1 augustss 2450 1.1 augustss static int 2451 1.1 augustss pnpgets(char *buf) 2452 1.1 augustss { 2453 1.8 mycroft struct pollfd set[1]; 2454 1.1 augustss int begin; 2455 1.1 augustss int i; 2456 1.1 augustss char c; 2457 1.1 augustss 2458 1.1 augustss if (!pnpwakeup1() && !pnpwakeup2()) { 2459 1.1 augustss /* 2460 1.1 augustss * According to PnP spec, we should set DTR = 1 and RTS = 0 while 2461 1.1 augustss * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed, 2462 1.1 augustss * assuming there is something at the port even if it didn't 2463 1.1 augustss * respond to the PnP enumeration procedure. 2464 1.1 augustss */ 2465 1.1 augustss i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 2466 1.1 augustss ioctl(rodent.mfd, TIOCMBIS, &i); 2467 1.1 augustss return 0; 2468 1.1 augustss } 2469 1.1 augustss 2470 1.1 augustss /* collect PnP COM device ID (2.1.7) */ 2471 1.1 augustss begin = -1; 2472 1.1 augustss i = 0; 2473 1.1 augustss usleep(240000); /* the mouse must send `Begin ID' within 200msec */ 2474 1.1 augustss while (read(rodent.mfd, &c, 1) == 1) { 2475 1.1 augustss /* we may see "M", or "M3..." before `Begin ID' */ 2476 1.1 augustss buf[i++] = c; 2477 1.1 augustss if ((c == 0x08) || (c == 0x28)) { /* Begin ID */ 2478 1.1 augustss debug("begin-id %02x", c); 2479 1.1 augustss begin = i - 1; 2480 1.1 augustss break; 2481 1.1 augustss } 2482 1.1 augustss debug("%c %02x", c, c); 2483 1.1 augustss if (i >= 256) 2484 1.1 augustss break; 2485 1.1 augustss } 2486 1.1 augustss if (begin < 0) { 2487 1.1 augustss /* we haven't seen `Begin ID' in time... */ 2488 1.1 augustss goto connect_idle; 2489 1.1 augustss } 2490 1.1 augustss 2491 1.1 augustss ++c; /* make it `End ID' */ 2492 1.8 mycroft set[0].fd = rodent.mfd; 2493 1.8 mycroft set[0].events = POLLIN; 2494 1.1 augustss for (;;) { 2495 1.8 mycroft if (poll(set, 1, 240) <= 0) 2496 1.1 augustss break; 2497 1.1 augustss 2498 1.1 augustss read(rodent.mfd, &buf[i], 1); 2499 1.1 augustss if (buf[i++] == c) /* End ID */ 2500 1.1 augustss break; 2501 1.1 augustss if (i >= 256) 2502 1.1 augustss break; 2503 1.1 augustss } 2504 1.1 augustss if (begin > 0) { 2505 1.1 augustss i -= begin; 2506 1.1 augustss bcopy(&buf[begin], &buf[0], i); 2507 1.1 augustss } 2508 1.1 augustss /* string may not be human readable... */ 2509 1.1 augustss debug("len:%d, '%-*.*s'", i, i, i, buf); 2510 1.1 augustss 2511 1.1 augustss if (buf[i - 1] == c) 2512 1.1 augustss return i; /* a valid PnP string */ 2513 1.1 augustss 2514 1.1 augustss /* 2515 1.1 augustss * According to PnP spec, we should set DTR = 1 and RTS = 0 while 2516 1.1 augustss * in idle state. But, `moused' shall leave the modem control lines 2517 1.1 augustss * as they are. See above. 2518 1.1 augustss */ 2519 1.1 augustss connect_idle: 2520 1.1 augustss 2521 1.1 augustss /* we may still have something in the buffer */ 2522 1.1 augustss return ((i > 0) ? i : 0); 2523 1.1 augustss } 2524 1.1 augustss 2525 1.1 augustss static int 2526 1.1 augustss pnpparse(pnpid_t *id, char *buf, int len) 2527 1.1 augustss { 2528 1.1 augustss char s[3]; 2529 1.1 augustss int offset; 2530 1.1 augustss int sum = 0; 2531 1.1 augustss int i, j; 2532 1.1 augustss 2533 1.1 augustss id->revision = 0; 2534 1.26 mrg id->eisaid = ""; 2535 1.1 augustss id->serial = NULL; 2536 1.1 augustss id->class = NULL; 2537 1.26 mrg id->compat = ""; 2538 1.26 mrg id->description = ""; 2539 1.1 augustss id->neisaid = 0; 2540 1.1 augustss id->nserial = 0; 2541 1.1 augustss id->nclass = 0; 2542 1.1 augustss id->ncompat = 0; 2543 1.1 augustss id->ndescription = 0; 2544 1.1 augustss 2545 1.1 augustss if ((buf[0] != 0x28) && (buf[0] != 0x08)) { 2546 1.1 augustss /* non-PnP mice */ 2547 1.1 augustss switch(buf[0]) { 2548 1.1 augustss default: 2549 1.1 augustss return FALSE; 2550 1.1 augustss case 'M': /* Microsoft */ 2551 1.1 augustss id->eisaid = "PNP0F01"; 2552 1.1 augustss break; 2553 1.1 augustss case 'H': /* MouseSystems */ 2554 1.1 augustss id->eisaid = "PNP0F04"; 2555 1.1 augustss break; 2556 1.1 augustss } 2557 1.1 augustss id->neisaid = strlen(id->eisaid); 2558 1.1 augustss id->class = "MOUSE"; 2559 1.1 augustss id->nclass = strlen(id->class); 2560 1.1 augustss debug("non-PnP mouse '%c'", buf[0]); 2561 1.1 augustss return TRUE; 2562 1.1 augustss } 2563 1.1 augustss 2564 1.1 augustss /* PnP mice */ 2565 1.1 augustss offset = 0x28 - buf[0]; 2566 1.1 augustss 2567 1.1 augustss /* calculate checksum */ 2568 1.1 augustss for (i = 0; i < len - 3; ++i) { 2569 1.1 augustss sum += buf[i]; 2570 1.1 augustss buf[i] += offset; 2571 1.1 augustss } 2572 1.1 augustss sum += buf[len - 1]; 2573 1.1 augustss for (; i < len; ++i) 2574 1.1 augustss buf[i] += offset; 2575 1.1 augustss debug("PnP ID string: '%*.*s'", len, len, buf); 2576 1.1 augustss 2577 1.1 augustss /* revision */ 2578 1.1 augustss buf[1] -= offset; 2579 1.1 augustss buf[2] -= offset; 2580 1.1 augustss id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f); 2581 1.1 augustss debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100); 2582 1.1 augustss 2583 1.32 andvar /* EISA vendor and product ID */ 2584 1.1 augustss id->eisaid = &buf[3]; 2585 1.1 augustss id->neisaid = 7; 2586 1.1 augustss 2587 1.1 augustss /* option strings */ 2588 1.1 augustss i = 10; 2589 1.1 augustss if (buf[i] == '\\') { 2590 1.1 augustss /* device serial # */ 2591 1.1 augustss for (j = ++i; i < len; ++i) { 2592 1.1 augustss if (buf[i] == '\\') 2593 1.1 augustss break; 2594 1.1 augustss } 2595 1.1 augustss if (i >= len) 2596 1.1 augustss i -= 3; 2597 1.1 augustss if (i - j == 8) { 2598 1.1 augustss id->serial = &buf[j]; 2599 1.1 augustss id->nserial = 8; 2600 1.1 augustss } 2601 1.1 augustss } 2602 1.1 augustss if (buf[i] == '\\') { 2603 1.1 augustss /* PnP class */ 2604 1.1 augustss for (j = ++i; i < len; ++i) { 2605 1.1 augustss if (buf[i] == '\\') 2606 1.1 augustss break; 2607 1.1 augustss } 2608 1.1 augustss if (i >= len) 2609 1.1 augustss i -= 3; 2610 1.1 augustss if (i > j + 1) { 2611 1.1 augustss id->class = &buf[j]; 2612 1.1 augustss id->nclass = i - j; 2613 1.1 augustss } 2614 1.1 augustss } 2615 1.1 augustss if (buf[i] == '\\') { 2616 1.1 augustss /* compatible driver */ 2617 1.1 augustss for (j = ++i; i < len; ++i) { 2618 1.1 augustss if (buf[i] == '\\') 2619 1.1 augustss break; 2620 1.1 augustss } 2621 1.1 augustss /* 2622 1.1 augustss * PnP COM spec prior to v0.96 allowed '*' in this field, 2623 1.30 msaitoh * it's not allowed now; just ignore it. 2624 1.1 augustss */ 2625 1.1 augustss if (buf[j] == '*') 2626 1.1 augustss ++j; 2627 1.1 augustss if (i >= len) 2628 1.1 augustss i -= 3; 2629 1.1 augustss if (i > j + 1) { 2630 1.1 augustss id->compat = &buf[j]; 2631 1.1 augustss id->ncompat = i - j; 2632 1.1 augustss } 2633 1.1 augustss } 2634 1.1 augustss if (buf[i] == '\\') { 2635 1.1 augustss /* product description */ 2636 1.1 augustss for (j = ++i; i < len; ++i) { 2637 1.1 augustss if (buf[i] == ';') 2638 1.1 augustss break; 2639 1.1 augustss } 2640 1.1 augustss if (i >= len) 2641 1.1 augustss i -= 3; 2642 1.1 augustss if (i > j + 1) { 2643 1.1 augustss id->description = &buf[j]; 2644 1.1 augustss id->ndescription = i - j; 2645 1.1 augustss } 2646 1.1 augustss } 2647 1.1 augustss 2648 1.1 augustss /* checksum exists if there are any optional fields */ 2649 1.1 augustss if ((id->nserial > 0) || (id->nclass > 0) 2650 1.1 augustss || (id->ncompat > 0) || (id->ndescription > 0)) { 2651 1.1 augustss debug("PnP checksum: 0x%X", sum); 2652 1.12 itojun snprintf(s, sizeof(s), "%02X", sum & 0x0ff); 2653 1.1 augustss if (strncmp(s, &buf[len - 3], 2) != 0) { 2654 1.1 augustss #if 0 2655 1.1 augustss /* 2656 1.1 augustss * I found some mice do not comply with the PnP COM device 2657 1.1 augustss * spec regarding checksum... XXX 2658 1.1 augustss */ 2659 1.1 augustss logwarnx("PnP checksum error", 0); 2660 1.1 augustss return FALSE; 2661 1.1 augustss #endif 2662 1.1 augustss } 2663 1.1 augustss } 2664 1.1 augustss 2665 1.1 augustss return TRUE; 2666 1.1 augustss } 2667 1.1 augustss 2668 1.1 augustss static symtab_t * 2669 1.1 augustss pnpproto(pnpid_t *id) 2670 1.1 augustss { 2671 1.1 augustss symtab_t *t; 2672 1.1 augustss int i, j; 2673 1.1 augustss 2674 1.1 augustss if (id->nclass > 0) 2675 1.1 augustss if ( strncmp(id->class, "MOUSE", id->nclass) != 0 && 2676 1.1 augustss strncmp(id->class, "TABLET", id->nclass) != 0) 2677 1.1 augustss /* this is not a mouse! */ 2678 1.1 augustss return NULL; 2679 1.1 augustss 2680 1.1 augustss if (id->neisaid > 0) { 2681 1.1 augustss t = gettoken(pnpprod, id->eisaid, id->neisaid); 2682 1.1 augustss if (t->val != MOUSE_PROTO_UNKNOWN) 2683 1.1 augustss return t; 2684 1.1 augustss } 2685 1.1 augustss 2686 1.1 augustss /* 2687 1.1 augustss * The 'Compatible drivers' field may contain more than one 2688 1.1 augustss * ID separated by ','. 2689 1.1 augustss */ 2690 1.1 augustss if (id->ncompat <= 0) 2691 1.1 augustss return NULL; 2692 1.1 augustss for (i = 0; i < id->ncompat; ++i) { 2693 1.1 augustss for (j = i; id->compat[i] != ','; ++i) 2694 1.1 augustss if (i >= id->ncompat) 2695 1.1 augustss break; 2696 1.1 augustss if (i > j) { 2697 1.1 augustss t = gettoken(pnpprod, id->compat + j, i - j); 2698 1.1 augustss if (t->val != MOUSE_PROTO_UNKNOWN) 2699 1.1 augustss return t; 2700 1.1 augustss } 2701 1.1 augustss } 2702 1.1 augustss 2703 1.1 augustss return NULL; 2704 1.1 augustss } 2705 1.1 augustss 2706 1.1 augustss /* name/val mapping */ 2707 1.1 augustss 2708 1.1 augustss static symtab_t * 2709 1.18 lukem gettoken(symtab_t *tab, const char *s, int len) 2710 1.1 augustss { 2711 1.1 augustss int i; 2712 1.1 augustss 2713 1.1 augustss for (i = 0; tab[i].name != NULL; ++i) { 2714 1.1 augustss if (strncmp(tab[i].name, s, len) == 0) 2715 1.1 augustss break; 2716 1.1 augustss } 2717 1.1 augustss return &tab[i]; 2718 1.1 augustss } 2719 1.1 augustss 2720 1.18 lukem static const char * 2721 1.1 augustss gettokenname(symtab_t *tab, int val) 2722 1.1 augustss { 2723 1.1 augustss int i; 2724 1.1 augustss 2725 1.1 augustss for (i = 0; tab[i].name != NULL; ++i) { 2726 1.1 augustss if (tab[i].val == val) 2727 1.1 augustss return tab[i].name; 2728 1.1 augustss } 2729 1.1 augustss return NULL; 2730 1.1 augustss } 2731 1.1 augustss 2732 1.1 augustss 2733 1.1 augustss /* 2734 1.1 augustss * code to read from the Genius Kidspad tablet. 2735 1.1 augustss 2736 1.1 augustss The tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005, 2737 1.1 augustss and to pre-pnp probes (RTS toggle) with 'T' (tablet ?) 2738 1.1 augustss 9600, 8 bit, parity odd. 2739 1.1 augustss 2740 1.1 augustss The tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains 2741 1.1 augustss the proximity, tip and button info: 2742 1.1 augustss (byte0 & 0x1) true = tip pressed 2743 1.1 augustss (byte0 & 0x2) true = button pressed 2744 1.1 augustss (byte0 & 0x40) false = pen in proximity of tablet. 2745 1.1 augustss 2746 1.1 augustss The next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid). 2747 1.1 augustss 2748 1.1 augustss Only absolute coordinates are returned, so we use the following approach: 2749 1.1 augustss we store the last coordinates sent when the pen went out of the tablet, 2750 1.1 augustss 2751 1.1 augustss 2752 1.1 augustss * 2753 1.1 augustss */ 2754 1.1 augustss 2755 1.1 augustss typedef enum { 2756 1.1 augustss S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP 2757 1.24 christos } k_status; 2758 1.1 augustss 2759 1.1 augustss static int 2760 1.1 augustss kidspad(u_char rxc, mousestatus_t *act) 2761 1.1 augustss { 2762 1.1 augustss static int buf[5]; 2763 1.24 christos static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1; 2764 1.24 christos static k_status status = S_IDLE; 2765 1.24 christos static struct timeval now; 2766 1.1 augustss 2767 1.24 christos int x, y; 2768 1.1 augustss 2769 1.1 augustss if (buflen > 0 && (rxc & 0x80) ) { 2770 1.1 augustss fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc); 2771 1.24 christos buflen = 0; 2772 1.1 augustss } 2773 1.1 augustss if (buflen == 0 && (rxc & 0xb8) != 0xb8 ) { 2774 1.1 augustss fprintf(stderr, "invalid code 0 0x%x\n", rxc); 2775 1.24 christos return 0; /* invalid code, no action */ 2776 1.1 augustss } 2777 1.24 christos buf[buflen++] = rxc; 2778 1.1 augustss if (buflen < 5) 2779 1.24 christos return 0; 2780 1.1 augustss 2781 1.24 christos buflen = 0; /* for next time... */ 2782 1.1 augustss 2783 1.24 christos x = buf[1]+128*(buf[2] - 7); 2784 1.24 christos if (x < 0) x = 0; 2785 1.24 christos y = 28*128 - (buf[3] + 128* (buf[4] - 7)); 2786 1.24 christos if (y < 0) y = 0; 2787 1.1 augustss 2788 1.24 christos x /= 8; 2789 1.24 christos y /= 8; 2790 1.1 augustss 2791 1.24 christos act->flags = 0; 2792 1.24 christos act->obutton = act->button; 2793 1.24 christos act->dx = act->dy = act->dz = 0; 2794 1.1 augustss gettimeofday(&now, NULL); 2795 1.1 augustss if ( buf[0] & 0x40 ) /* pen went out of reach */ 2796 1.24 christos status = S_IDLE; 2797 1.1 augustss else if (status == S_IDLE) { /* pen is newly near the tablet */ 2798 1.24 christos act->flags |= MOUSE_POSCHANGED; /* force update */ 2799 1.24 christos status = S_PROXY; 2800 1.24 christos x_prev = x; 2801 1.24 christos y_prev = y; 2802 1.24 christos } 2803 1.24 christos act->dx = x - x_prev; 2804 1.24 christos act->dy = y - y_prev; 2805 1.1 augustss if (act->dx || act->dy) 2806 1.24 christos act->flags |= MOUSE_POSCHANGED; 2807 1.24 christos x_prev = x; 2808 1.24 christos y_prev = y; 2809 1.1 augustss if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */ 2810 1.24 christos act->button = 0; 2811 1.1 augustss if ( buf[0] & 0x01 ) /* tip pressed */ 2812 1.24 christos act->button |= MOUSE_BUTTON1DOWN; 2813 1.1 augustss if ( buf[0] & 0x02 ) /* button pressed */ 2814 1.24 christos act->button |= MOUSE_BUTTON2DOWN; 2815 1.24 christos act->flags |= MOUSE_BUTTONSCHANGED; 2816 1.1 augustss } 2817 1.24 christos b_prev = buf[0]; 2818 1.24 christos return act->flags; 2819 1.1 augustss } 2820