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