dmesg.8: Improve markup a bit and fix a typo (dumnr -> dumpnr).
[dragonfly.git] / usr.sbin / moused / moused.c
blobf78ced2c99f781139b65f0fe2eb5e9709a0751f0
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.
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.
32 **/
34 /**
35 ** MOUSED.C
37 ** Mouse daemon : listens to a serial port, the bus mouse interface, or
38 ** the PS/2 mouse port for mouse data stream, interprets data and passes
39 ** ioctls off to the console driver.
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!
45 **/
48 * $FreeBSD: src/usr.sbin/moused/moused.c,v 1.69 2005/01/06 08:38:29 philip Exp $
51 #include <machine/console.h>
52 #include <sys/mouse.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>
62 #include <ctype.h>
63 #include <err.h>
64 #include <errno.h>
65 #include <fcntl.h>
66 #include <limits.h>
67 #include <setjmp.h>
68 #include <signal.h>
69 #include <stdarg.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <syslog.h>
74 #include <termios.h>
75 #include <unistd.h>
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 */
81 #define DFLT_SCROLLTHRESHOLD 3 /* 3 pixels */
83 /* Abort 3-button emulation delay after this many movement events. */
84 #define BUTTON2_MAXMOVE 3
86 #define TRUE 1
87 #define FALSE 0
89 #define MOUSE_XAXIS (-1)
90 #define MOUSE_YAXIS (-2)
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))
98 #define ChordMiddle 0x0001
99 #define Emulate3Button 0x0002
100 #define ClearDTR 0x0004
101 #define ClearRTS 0x0008
102 #define NoPnP 0x0010
103 #define VirtualScroll 0x0020
105 #define ID_NONE 0
106 #define ID_PORT 1
107 #define ID_IF 2
108 #define ID_TYPE 4
109 #define ID_MODEL 8
110 #define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
112 #define debug(fmt, args...) do { \
113 if (debug && nodaemon) \
114 warnx(fmt, ##args); \
115 } while (0)
117 #define logerr(e, fmt, args...) do { \
118 log_or_warn(LOG_DAEMON | LOG_ERR, errno, fmt, ##args); \
119 exit(e); \
120 } while (0)
122 #define logerrx(e, fmt, args...) do { \
123 log_or_warn(LOG_DAEMON | LOG_ERR, 0, fmt, ##args); \
124 exit(e); \
125 } while (0)
127 #define logwarn(fmt, args...) \
128 log_or_warn(LOG_DAEMON | LOG_WARNING, errno, fmt, ##args)
130 #define logwarnx(fmt, args...) \
131 log_or_warn(LOG_DAEMON | LOG_WARNING, 0, fmt, ##args)
133 /* structures */
135 /* symbol table entry */
136 typedef struct {
137 char *name;
138 int val;
139 int val2;
140 } symtab_t;
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;
157 /* global variables */
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";
166 #define SCROLL_NOTSCROLLING 0
167 #define SCROLL_PREPARE 1
168 #define SCROLL_SCROLLING 2
170 static int scroll_state;
171 static int scroll_movement;
173 /* local variables */
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 },
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
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 },
225 { "Synaptics Touchpad", MOUSE_MODEL_SYNAPTICS },
226 { "generic", MOUSE_MODEL_GENERIC },
227 { NULL, MOUSE_MODEL_UNKNOWN },
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 */
249 { "KYEEZ00", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL },
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 },
267 /* MS bus */
268 { "PNP0F00", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
269 /* MS serial */
270 { "PNP0F01", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
271 /* MS InPort */
272 { "PNP0F02", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC },
273 /* MS PS/2 */
274 { "PNP0F03", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
276 * EzScroll returns PNP0F04 in the compatible device field; but it
277 * doesn't look compatible... XXX
279 /* MouseSystems */
280 { "PNP0F04", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC },
281 /* MouseSystems */
282 { "PNP0F05", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC },
283 #if notyet
284 /* Genius Mouse */
285 { "PNP0F06", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
286 /* Genius Mouse */
287 { "PNP0F07", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
288 #endif
289 /* Logitech serial */
290 { "PNP0F08", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
291 /* MS BallPoint serial */
292 { "PNP0F09", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
293 /* MS PnP serial */
294 { "PNP0F0A", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
295 /* MS PnP BallPoint serial */
296 { "PNP0F0B", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
297 /* MS serial comatible */
298 { "PNP0F0C", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
299 /* MS InPort comatible */
300 { "PNP0F0D", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC },
301 /* MS PS/2 comatible */
302 { "PNP0F0E", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
303 /* MS BallPoint comatible */
304 { "PNP0F0F", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
305 #if notyet
306 /* TI QuickPort */
307 { "PNP0F10", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
308 #endif
309 /* MS bus comatible */
310 { "PNP0F11", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
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 */
317 { "PNP0F14", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
318 #endif
319 /* Logitech bus */
320 { "PNP0F15", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
321 #if notyet
322 /* Logitech SWIFT */
323 { "PNP0F16", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
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 */
333 { "PNP0F1A", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
334 /* HP Omnibook */
335 { "PNP0F1B", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
336 /* Compaq LTE TrackBall PS/2 */
337 { "PNP0F1C", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
338 /* Compaq LTE TrackBall serial */
339 { "PNP0F1D", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
340 /* MS Kidts Trackball */
341 { "PNP0F1E", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC },
342 #endif
343 /* Interlink VersaPad */
344 { "LNK0001", MOUSE_PROTO_VERSAPAD, MOUSE_MODEL_VERSAPAD },
346 { NULL, MOUSE_PROTO_UNKNOWN, MOUSE_MODEL_GENERIC },
349 /* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
350 static unsigned short rodentcflags[] =
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 */
357 0, /* Bus */
358 0, /* InPort */
359 0, /* PS/2 */
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 */
368 0, /* JogDial */
369 #if notyet
370 (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* Mariqua */
371 #endif
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 */
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,
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 */
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 */
425 /* state machine for 3 button emulation */
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 */
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))
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 },
469 static int mouse_button_state;
470 static struct timeval mouse_button_state_tv;
471 static int mouse_move_delayed;
473 static jmp_buf env;
475 /* function prototypes */
477 static void moused(void);
478 static void hup(int sig);
479 static void cleanup(int sig);
480 static void usage(void);
481 static void log_or_warn(int log_pri, int errnum, const char *fmt, ...)
482 __printflike(3, 4);
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);
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);
504 static symtab_t *gettoken(symtab_t *tab, char *s, int len);
505 static char *gettokenname(symtab_t *tab, int val);
507 static void mremote_serversetup();
508 static void mremote_clientchg(int add);
510 static int kidspad(u_char rxc, mousestatus_t *act);
512 static int usbmodule(void);
515 main(int argc, char *argv[])
517 int c;
518 int i;
519 int j;
520 int retry;
522 for (i = 0; i < MOUSE_MAXBUTTON; ++i)
523 mstate[i] = &bstate[i];
525 while ((c = getopt(argc, argv, "3C:DE:F:I:PRS:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
526 switch(c) {
528 case '3':
529 rodent.flags |= Emulate3Button;
530 break;
532 case 'E':
533 rodent.button2timeout = atoi(optarg);
534 if ((rodent.button2timeout < 0) ||
535 (rodent.button2timeout > MAX_BUTTON2TIMEOUT)) {
536 warnx("invalid argument `%s'", optarg);
537 usage();
539 break;
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();
548 if (i == 1)
549 rodent.accely = rodent.accelx;
551 break;
553 case 'c':
554 rodent.flags |= ChordMiddle;
555 break;
557 case 'd':
558 ++debug;
559 break;
561 case 'f':
562 nodaemon = TRUE;
563 break;
565 case 'i':
566 if (strcmp(optarg, "all") == 0)
567 identify = ID_ALL;
568 else if (strcmp(optarg, "port") == 0)
569 identify = ID_PORT;
570 else if (strcmp(optarg, "if") == 0)
571 identify = ID_IF;
572 else if (strcmp(optarg, "type") == 0)
573 identify = ID_TYPE;
574 else if (strcmp(optarg, "model") == 0)
575 identify = ID_MODEL;
576 else {
577 warnx("invalid argument `%s'", optarg);
578 usage();
580 nodaemon = TRUE;
581 break;
583 case 'l':
584 rodent.level = atoi(optarg);
585 if ((rodent.level < 0) || (rodent.level > 4)) {
586 warnx("invalid argument `%s'", optarg);
587 usage();
589 break;
591 case 'm':
592 if (!r_installmap(optarg)) {
593 warnx("invalid argument `%s'", optarg);
594 usage();
596 break;
598 case 'p':
599 rodent.portname = optarg;
600 break;
602 case 'r':
603 if (strcmp(optarg, "high") == 0)
604 rodent.resolution = MOUSE_RES_HIGH;
605 else if (strcmp(optarg, "medium-high") == 0)
606 rodent.resolution = MOUSE_RES_HIGH;
607 else if (strcmp(optarg, "medium-low") == 0)
608 rodent.resolution = MOUSE_RES_MEDIUMLOW;
609 else if (strcmp(optarg, "low") == 0)
610 rodent.resolution = MOUSE_RES_LOW;
611 else if (strcmp(optarg, "default") == 0)
612 rodent.resolution = MOUSE_RES_DEFAULT;
613 else {
614 rodent.resolution = atoi(optarg);
615 if (rodent.resolution <= 0) {
616 warnx("invalid argument `%s'", optarg);
617 usage();
620 break;
622 case 's':
623 rodent.baudrate = 9600;
624 break;
626 case 'w':
627 i = atoi(optarg);
628 if ((i <= 0) || (i > MOUSE_MAXBUTTON)) {
629 warnx("invalid argument `%s'", optarg);
630 usage();
632 rodent.wmode = 1 << (i - 1);
633 break;
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;
640 else {
641 i = atoi(optarg);
643 * Use button i for negative Z axis movement and
644 * button (i + 1) for positive Z axis movement.
646 if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
647 warnx("invalid argument `%s'", optarg);
648 usage();
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();
661 rodent.zmap[j] = i;
662 ++optind;
664 if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0))
665 rodent.zmap[3] = rodent.zmap[2] + 1;
667 break;
669 case 'C':
670 rodent.clickthreshold = atoi(optarg);
671 if ((rodent.clickthreshold < 0) ||
672 (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
673 warnx("invalid argument `%s'", optarg);
674 usage();
676 break;
678 case 'D':
679 rodent.flags |= ClearDTR;
680 break;
682 case 'F':
683 rodent.rate = atoi(optarg);
684 if (rodent.rate <= 0) {
685 warnx("invalid argument `%s'", optarg);
686 usage();
688 break;
690 case 'I':
691 pidfile = optarg;
692 break;
694 case 'P':
695 rodent.flags |= NoPnP;
696 break;
698 case 'R':
699 rodent.flags |= ClearRTS;
700 break;
702 case 'S':
703 rodent.baudrate = atoi(optarg);
704 if (rodent.baudrate <= 0) {
705 warnx("invalid argument `%s'", optarg);
706 usage();
708 debug("rodent baudrate %d", rodent.baudrate);
709 break;
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;
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;
725 if (rnames[i])
726 break;
727 warnx("no such mouse type `%s'", optarg);
728 usage();
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();
739 break;
741 case 'h':
742 case '?':
743 default:
744 usage();
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];
754 rodent.zmap[i] = 1 << (rodent.zmap[i] - 1);
758 /* the default port name */
759 switch(rodent.rtype) {
761 case MOUSE_PROTO_PS2:
762 if (!rodent.portname)
763 rodent.portname = "/dev/psm0";
764 break;
766 default:
767 if (rodent.portname)
768 break;
769 warnx("no port name specified");
770 usage();
773 retry = 1;
774 if (strncmp(rodent.portname, "/dev/ums", 8) == 0) {
775 if (usbmodule() != 0)
776 retry = 5;
779 for (;;) {
780 if (setjmp(env) == 0) {
781 signal(SIGHUP, hup);
782 signal(SIGINT , cleanup);
783 signal(SIGQUIT, cleanup);
784 signal(SIGTERM, cleanup);
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;
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;
800 /* print some information */
801 if (identify != ID_NONE) {
802 if (identify == ID_ALL)
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));
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 {
816 debug("port: %s interface: %s type: %s model: %s",
817 rodent.portname, r_if(rodent.hw.iftype),
818 r_name(rodent.rtype), r_model(rodent.hw.model));
821 if (rodent.mfd == -1) {
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.
827 if (!background)
828 exit(1);
829 sigpause(0);
832 r_init(); /* call init function */
833 moused();
836 if (rodent.mfd != -1)
837 close(rodent.mfd);
838 if (rodent.cfd != -1)
839 close(rodent.cfd);
840 rodent.mfd = rodent.cfd = -1;
842 /* NOT REACHED */
844 exit(0);
847 static int
848 usbmodule(void)
850 struct kld_file_stat fstat;
851 struct module_stat mstat;
852 int fileid, modid;
853 int loaded;
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;
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;
875 if (!loaded) {
876 if (kldload("ums") != -1)
877 return 1;
878 if (errno != EEXIST)
879 logerr(1, "unable to load USB mouse driver");
881 return 0;
884 static void
885 moused(void)
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 buf[16];
894 FILE *fp;
895 int fill = 0;
896 int pos = 0;
897 int flags;
898 int c;
899 int i;
901 if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
902 logerr(1, "cannot open /dev/consolectl");
904 if (!nodaemon && !background) {
905 if (daemon(0, 0)) {
906 logerr(1, "failed to become a daemon");
907 } else {
908 background = TRUE;
909 fp = fopen(pidfile, "w");
910 if (fp != NULL) {
911 fprintf(fp, "%d\n", getpid());
912 fclose(fp);
917 /* clear mouse data */
918 bzero(&action0, sizeof(action0));
919 bzero(&action, sizeof(action));
920 bzero(&action2, sizeof(action2));
921 bzero(&mouse, sizeof(mouse));
922 mouse_button_state = S0;
923 gettimeofday(&mouse_button_state_tv, NULL);
924 mouse_move_delayed = 0;
925 for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
926 bstate[i].count = 0;
927 bstate[i].tv = mouse_button_state_tv;
929 for (i = 0; i < sizeof(zstate)/sizeof(zstate[0]); ++i) {
930 zstate[i].count = 0;
931 zstate[i].tv = mouse_button_state_tv;
934 /* choose which ioctl command to use */
935 mouse.operation = MOUSE_MOTION_EVENT;
936 extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
938 /* process mouse data */
939 timeout.tv_sec = 0;
940 timeout.tv_usec = 20000; /* 20 msec */
941 for (;;) {
942 if (fill > pos)
943 goto more;
944 fill = 0;
946 FD_ZERO(&fds);
947 FD_SET(rodent.mfd, &fds);
948 if (rodent.mremsfd >= 0)
949 FD_SET(rodent.mremsfd, &fds);
950 if (rodent.mremcfd >= 0)
951 FD_SET(rodent.mremcfd, &fds);
953 c = select(FD_SETSIZE, &fds, NULL, NULL,
954 (rodent.flags & Emulate3Button) ? &timeout : NULL);
955 if (c < 0) { /* error */
956 logwarn("failed to read from mouse");
957 continue;
958 } else if (c == 0) { /* timeout */
959 /* assert(rodent.flags & Emulate3Button) */
960 action0.button = action0.obutton;
961 action0.dx = action0.dy = action0.dz = 0;
962 action0.flags = flags = 0;
963 if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) {
964 if (debug > 2)
965 debug("flags:%08x buttons:%08x obuttons:%08x",
966 action.flags, action.button, action.obutton);
967 } else {
968 action0.obutton = action0.button;
969 continue;
971 } else {
972 /* MouseRemote client connect/disconnect */
973 if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
974 mremote_clientchg(TRUE);
975 continue;
977 if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
978 mremote_clientchg(FALSE);
979 continue;
981 /* mouse movement */
982 if ((fill = read(rodent.mfd, buf, sizeof(buf))) == -1) {
983 if (errno == EWOULDBLOCK)
984 continue;
985 else
986 return;
988 pos = 0;
989 more:
990 if ((flags = r_protocol(buf[pos++], &action0)) == 0)
991 continue;
993 if (rodent.flags & VirtualScroll) {
994 /* Allow middle button drags to scroll up and down */
995 if (action0.button == MOUSE_BUTTON2DOWN) {
996 if (scroll_state == SCROLL_NOTSCROLLING) {
997 scroll_state = SCROLL_PREPARE;
998 debug("PREPARING TO SCROLL");
1000 debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1001 action.flags, action.button, action.obutton);
1002 } else {
1003 debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1004 action.flags, action.button, action.obutton);
1006 /* This isn't a middle button down... move along... */
1007 if (scroll_state == SCROLL_SCROLLING) {
1009 * We were scrolling, someone let go of button 2.
1010 * Now turn autoscroll off.
1012 scroll_state = SCROLL_NOTSCROLLING;
1013 debug("DONE WITH SCROLLING / %d", scroll_state);
1014 } else if (scroll_state == SCROLL_PREPARE) {
1015 mousestatus_t newaction = action0;
1017 /* We were preparing to scroll, but we never moved... */
1018 r_timestamp(&action0);
1019 r_statetrans(&action0, &newaction,
1020 A(newaction.button & MOUSE_BUTTON1DOWN,
1021 action0.button & MOUSE_BUTTON3DOWN));
1023 /* Send middle down */
1024 newaction.button = MOUSE_BUTTON2DOWN;
1025 r_click(&newaction);
1027 /* Send middle up */
1028 r_timestamp(&newaction);
1029 newaction.obutton = newaction.button;
1030 newaction.button = action0.button;
1031 r_click(&newaction);
1036 r_timestamp(&action0);
1037 r_statetrans(&action0, &action,
1038 A(action0.button & MOUSE_BUTTON1DOWN,
1039 action0.button & MOUSE_BUTTON3DOWN));
1040 debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
1041 action.button, action.obutton);
1043 action0.obutton = action0.button;
1044 flags &= MOUSE_POSCHANGED;
1045 flags |= action.obutton ^ action.button;
1046 action.flags = flags;
1048 if (flags) { /* handler detected action */
1049 r_map(&action, &action2);
1050 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
1051 action2.button, action2.dx, action2.dy, action2.dz);
1053 if (rodent.flags & VirtualScroll) {
1055 * If *only* the middle button is pressed AND we are moving
1056 * the stick/trackpoint/nipple, scroll!
1058 if (scroll_state == SCROLL_PREPARE) {
1059 /* Ok, Set we're really scrolling now.... */
1060 if (action2.dy || action2.dx)
1061 scroll_state = SCROLL_SCROLLING;
1063 if (scroll_state == SCROLL_SCROLLING) {
1064 scroll_movement += action2.dy;
1065 debug("SCROLL: %d", scroll_movement);
1067 if (scroll_movement < -rodent.scrollthreshold) {
1068 /* Scroll down */
1069 action2.dz = -1;
1070 scroll_movement = 0;
1072 else if (scroll_movement > rodent.scrollthreshold) {
1073 /* Scroll up */
1074 action2.dz = 1;
1075 scroll_movement = 0;
1078 /* Don't move while scrolling */
1079 action2.dx = action2.dy = 0;
1083 if (extioctl) {
1084 /* Defer clicks until we aren't VirtualScroll'ing. */
1085 if (scroll_state == SCROLL_NOTSCROLLING)
1086 r_click(&action2);
1088 if (action2.flags & MOUSE_POSCHANGED) {
1089 mouse.operation = MOUSE_MOTION_EVENT;
1090 mouse.u.data.buttons = action2.button;
1091 mouse.u.data.x = action2.dx * rodent.accelx;
1092 mouse.u.data.y = action2.dy * rodent.accely;
1093 mouse.u.data.z = action2.dz;
1094 if (debug < 2)
1095 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1097 } else {
1098 mouse.operation = MOUSE_ACTION;
1099 mouse.u.data.buttons = action2.button;
1100 mouse.u.data.x = action2.dx * rodent.accelx;
1101 mouse.u.data.y = action2.dy * rodent.accely;
1102 mouse.u.data.z = action2.dz;
1103 if (debug < 2)
1104 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1108 * If the Z axis movement is mapped to an imaginary physical
1109 * button, we need to cook up a corresponding button `up' event
1110 * after sending a button `down' event.
1112 if ((rodent.zmap[0] > 0) && (action.dz != 0)) {
1113 action.obutton = action.button;
1114 action.dx = action.dy = action.dz = 0;
1115 r_map(&action, &action2);
1116 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
1117 action2.button, action2.dx, action2.dy, action2.dz);
1119 if (extioctl) {
1120 r_click(&action2);
1121 } else {
1122 mouse.operation = MOUSE_ACTION;
1123 mouse.u.data.buttons = action2.button;
1124 mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
1125 if (debug < 2)
1126 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1131 /* NOT REACHED */
1134 static void
1135 hup(int sig)
1137 longjmp(env, 1);
1140 static void
1141 cleanup(int sig)
1143 if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM)
1144 unlink(_PATH_MOUSEREMOTE);
1145 exit(0);
1149 ** usage
1151 ** Complain, and free the CPU for more worthy tasks
1153 static void
1154 usage(void)
1156 fprintf(stderr, "%s\n%s\n%s\n%s\n",
1157 "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
1158 " [-V [-U threshold]] [-a X [,Y]] [-C threshold] [-m N=M] [-w N]",
1159 " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]] -p <port>",
1160 " moused [-d] -i <port|if|type|model|all> -p <port>");
1161 exit(1);
1165 * Output an error message to syslog or stderr as appropriate. If
1166 * `errnum' is non-zero, append its string form to the message.
1168 static void
1169 log_or_warn(int log_pri, int errnum, const char *fmt, ...)
1171 va_list ap;
1172 char buf[256];
1174 va_start(ap, fmt);
1175 vsnprintf(buf, sizeof(buf), fmt, ap);
1176 va_end(ap);
1177 if (errnum) {
1178 strlcat(buf, ": ", sizeof(buf));
1179 strlcat(buf, strerror(errnum), sizeof(buf));
1182 if (background)
1183 syslog(log_pri, "%s", buf);
1184 else
1185 warnx("%s", buf);
1189 ** Mouse interface code, courtesy of XFree86 3.1.2.
1191 ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
1192 ** to clean, reformat and rationalise naming, it's quite possible that
1193 ** some things in here have been broken.
1195 ** I hope not 8)
1197 ** The following code is derived from a module marked :
1200 /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
1201 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
1202 17:03:40 dawes Exp $ */
1205 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
1206 * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
1208 * Permission to use, copy, modify, distribute, and sell this software and its
1209 * documentation for any purpose is hereby granted without fee, provided that
1210 * the above copyright notice appear in all copies and that both that
1211 * copyright notice and this permission notice appear in supporting
1212 * documentation, and that the names of Thomas Roell and David Dawes not be
1213 * used in advertising or publicity pertaining to distribution of the
1214 * software without specific, written prior permission. Thomas Roell
1215 * and David Dawes makes no representations about the suitability of this
1216 * software for any purpose. It is provided "as is" without express or
1217 * implied warranty.
1219 * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
1220 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1221 * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
1222 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
1223 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
1224 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1225 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1230 ** GlidePoint support from XFree86 3.2.
1231 ** Derived from the module:
1234 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
1235 /* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
1237 /* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
1238 static unsigned char proto[][7] = {
1239 /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */
1240 { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */
1241 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */
1242 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */
1243 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */
1244 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* MouseMan */
1245 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */
1246 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */
1247 { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */
1248 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */
1249 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */
1250 { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */
1251 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */
1252 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */
1253 { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* X10 MouseRem */
1254 { 0x80, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* KIDSPAD */
1255 { 0xc3, 0xc0, 0x00, 0x00, 6, 0x00, 0xff }, /* VersaPad */
1256 { 0x00, 0x00, 0x00, 0x00, 1, 0x00, 0xff }, /* JogDial */
1257 #if notyet
1258 { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */
1259 #endif
1261 static unsigned char cur_proto[7];
1263 static int
1264 r_identify(void)
1266 char pnpbuf[256]; /* PnP identifier string may be up to 256 bytes long */
1267 pnpid_t pnpid;
1268 symtab_t *t;
1269 int level;
1270 int len;
1272 /* set the driver operation level, if applicable */
1273 if (rodent.level < 0)
1274 rodent.level = 1;
1275 ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level);
1276 rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0;
1279 * Interrogate the driver and get some intelligence on the device...
1280 * The following ioctl functions are not always supported by device
1281 * drivers. When the driver doesn't support them, we just trust the
1282 * user to supply valid information.
1284 rodent.hw.iftype = MOUSE_IF_UNKNOWN;
1285 rodent.hw.model = MOUSE_MODEL_GENERIC;
1286 ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw);
1288 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1289 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
1290 rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
1291 rodent.mode.rate = -1;
1292 rodent.mode.resolution = MOUSE_RES_UNKNOWN;
1293 rodent.mode.accelfactor = 0;
1294 rodent.mode.level = 0;
1295 if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) {
1296 if ((rodent.mode.protocol == MOUSE_PROTO_UNKNOWN)
1297 || (rodent.mode.protocol >= sizeof(proto)/sizeof(proto[0]))) {
1298 logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol);
1299 return MOUSE_PROTO_UNKNOWN;
1300 } else {
1301 /* INPORT and BUS are the same... */
1302 if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
1303 rodent.mode.protocol = MOUSE_PROTO_BUS;
1304 if (rodent.mode.protocol != rodent.rtype) {
1305 /* Hmm, the driver doesn't agree with the user... */
1306 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1307 logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1308 r_name(rodent.mode.protocol), r_name(rodent.rtype),
1309 r_name(rodent.mode.protocol));
1310 rodent.rtype = rodent.mode.protocol;
1311 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
1314 cur_proto[4] = rodent.mode.packetsize;
1315 cur_proto[0] = rodent.mode.syncmask[0]; /* header byte bit mask */
1316 cur_proto[1] = rodent.mode.syncmask[1]; /* header bit pattern */
1319 /* maybe this is a PnP mouse... */
1320 if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
1322 if (rodent.flags & NoPnP)
1323 return rodent.rtype;
1324 if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
1325 return rodent.rtype;
1327 debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
1328 pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
1329 pnpid.ncompat, pnpid.ncompat, pnpid.compat,
1330 pnpid.ndescription, pnpid.ndescription, pnpid.description);
1332 /* we have a valid PnP serial device ID */
1333 rodent.hw.iftype = MOUSE_IF_SERIAL;
1334 t = pnpproto(&pnpid);
1335 if (t != NULL) {
1336 rodent.mode.protocol = t->val;
1337 rodent.hw.model = t->val2;
1338 } else {
1339 rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
1341 if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
1342 rodent.mode.protocol = MOUSE_PROTO_BUS;
1344 /* make final adjustment */
1345 if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
1346 if (rodent.mode.protocol != rodent.rtype) {
1347 /* Hmm, the device doesn't agree with the user... */
1348 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1349 logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1350 r_name(rodent.mode.protocol), r_name(rodent.rtype),
1351 r_name(rodent.mode.protocol));
1352 rodent.rtype = rodent.mode.protocol;
1353 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
1358 debug("proto params: %02x %02x %02x %02x %d %02x %02x",
1359 cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
1360 cur_proto[4], cur_proto[5], cur_proto[6]);
1362 return rodent.rtype;
1365 static char *
1366 r_if(int iftype)
1368 char *s;
1370 s = gettokenname(rifs, iftype);
1371 return (s == NULL) ? "unknown" : s;
1374 static char *
1375 r_name(int type)
1377 return ((type == MOUSE_PROTO_UNKNOWN)
1378 || (type > sizeof(rnames)/sizeof(rnames[0]) - 1))
1379 ? "unknown" : rnames[type];
1382 static char *
1383 r_model(int model)
1385 char *s;
1387 s = gettokenname(rmodels, model);
1388 return (s == NULL) ? "unknown" : s;
1391 static void
1392 r_init(void)
1394 unsigned char buf[16]; /* scrach buffer */
1395 fd_set fds;
1396 char *s;
1397 char c;
1398 int i;
1401 ** This comment is a little out of context here, but it contains
1402 ** some useful information...
1403 ********************************************************************
1405 ** The following lines take care of the Logitech MouseMan protocols.
1407 ** NOTE: There are different versions of both MouseMan and TrackMan!
1408 ** Hence I add another protocol P_LOGIMAN, which the user can
1409 ** specify as MouseMan in his XF86Config file. This entry was
1410 ** formerly handled as a special case of P_MS. However, people
1411 ** who don't have the middle button problem, can still specify
1412 ** Microsoft and use P_MS.
1414 ** By default, these mice should use a 3 byte Microsoft protocol
1415 ** plus a 4th byte for the middle button. However, the mouse might
1416 ** have switched to a different protocol before we use it, so I send
1417 ** the proper sequence just in case.
1419 ** NOTE: - all commands to (at least the European) MouseMan have to
1420 ** be sent at 1200 Baud.
1421 ** - each command starts with a '*'.
1422 ** - whenever the MouseMan receives a '*', it will switch back
1423 ** to 1200 Baud. Hence I have to select the desired protocol
1424 ** first, then select the baud rate.
1426 ** The protocols supported by the (European) MouseMan are:
1427 ** - 5 byte packed binary protocol, as with the Mouse Systems
1428 ** mouse. Selected by sequence "*U".
1429 ** - 2 button 3 byte MicroSoft compatible protocol. Selected
1430 ** by sequence "*V".
1431 ** - 3 button 3+1 byte MicroSoft compatible protocol (default).
1432 ** Selected by sequence "*X".
1434 ** The following baud rates are supported:
1435 ** - 1200 Baud (default). Selected by sequence "*n".
1436 ** - 9600 Baud. Selected by sequence "*q".
1438 ** Selecting a sample rate is no longer supported with the MouseMan!
1439 ** Some additional lines in xf86Config.c take care of ill configured
1440 ** baud rates and sample rates. (The user will get an error.)
1443 switch (rodent.rtype) {
1445 case MOUSE_PROTO_LOGI:
1447 * The baud rate selection command must be sent at the current
1448 * baud rate; try all likely settings
1450 setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
1451 setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
1452 setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
1453 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1454 /* select MM series data format */
1455 write(rodent.mfd, "S", 1);
1456 setmousespeed(rodent.baudrate, rodent.baudrate,
1457 rodentcflags[MOUSE_PROTO_MM]);
1458 /* select report rate/frequency */
1459 if (rodent.rate <= 0) write(rodent.mfd, "O", 1);
1460 else if (rodent.rate <= 15) write(rodent.mfd, "J", 1);
1461 else if (rodent.rate <= 27) write(rodent.mfd, "K", 1);
1462 else if (rodent.rate <= 42) write(rodent.mfd, "L", 1);
1463 else if (rodent.rate <= 60) write(rodent.mfd, "R", 1);
1464 else if (rodent.rate <= 85) write(rodent.mfd, "M", 1);
1465 else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
1466 else write(rodent.mfd, "N", 1);
1467 break;
1469 case MOUSE_PROTO_LOGIMOUSEMAN:
1470 /* The command must always be sent at 1200 baud */
1471 setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
1472 write(rodent.mfd, "*X", 2);
1473 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1474 break;
1476 case MOUSE_PROTO_HITTAB:
1477 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1480 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
1481 * The tablet must be configured to be in MM mode, NO parity,
1482 * Binary Format. xf86Info.sampleRate controls the sensativity
1483 * of the tablet. We only use this tablet for it's 4-button puck
1484 * so we don't run in "Absolute Mode"
1486 write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */
1487 usleep(50000);
1488 write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */
1489 usleep(50000);
1490 write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */
1491 usleep(50000);
1492 write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */
1493 usleep(50000);
1494 write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */
1495 usleep(50000);
1496 write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */
1497 usleep(50000);
1499 /* Resolution is in 'lines per inch' on the Hitachi tablet */
1500 if (rodent.resolution == MOUSE_RES_LOW) c = 'g';
1501 else if (rodent.resolution == MOUSE_RES_MEDIUMLOW) c = 'e';
1502 else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH) c = 'h';
1503 else if (rodent.resolution == MOUSE_RES_HIGH) c = 'd';
1504 else if (rodent.resolution <= 40) c = 'g';
1505 else if (rodent.resolution <= 100) c = 'd';
1506 else if (rodent.resolution <= 200) c = 'e';
1507 else if (rodent.resolution <= 500) c = 'h';
1508 else if (rodent.resolution <= 1000) c = 'j';
1509 else c = 'd';
1510 write(rodent.mfd, &c, 1);
1511 usleep(50000);
1513 write(rodent.mfd, "\021", 1); /* Resume DATA output */
1514 break;
1516 case MOUSE_PROTO_THINK:
1517 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1518 /* the PnP ID string may be sent again, discard it */
1519 usleep(200000);
1520 i = FREAD;
1521 ioctl(rodent.mfd, TIOCFLUSH, &i);
1522 /* send the command to initialize the beast */
1523 for (s = "E5E5"; *s; ++s) {
1524 write(rodent.mfd, s, 1);
1525 FD_ZERO(&fds);
1526 FD_SET(rodent.mfd, &fds);
1527 if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
1528 break;
1529 read(rodent.mfd, &c, 1);
1530 debug("%c", c);
1531 if (c != *s)
1532 break;
1534 break;
1536 case MOUSE_PROTO_JOGDIAL:
1537 break;
1538 case MOUSE_PROTO_MSC:
1539 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1540 if (rodent.flags & ClearDTR) {
1541 i = TIOCM_DTR;
1542 ioctl(rodent.mfd, TIOCMBIC, &i);
1544 if (rodent.flags & ClearRTS) {
1545 i = TIOCM_RTS;
1546 ioctl(rodent.mfd, TIOCMBIC, &i);
1548 break;
1550 case MOUSE_PROTO_SYSMOUSE:
1551 if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE)
1552 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1553 /* FALLTHROUGH */
1555 case MOUSE_PROTO_BUS:
1556 case MOUSE_PROTO_INPORT:
1557 case MOUSE_PROTO_PS2:
1558 if (rodent.rate >= 0)
1559 rodent.mode.rate = rodent.rate;
1560 if (rodent.resolution != MOUSE_RES_UNKNOWN)
1561 rodent.mode.resolution = rodent.resolution;
1562 ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
1563 break;
1565 case MOUSE_PROTO_X10MOUSEREM:
1566 mremote_serversetup();
1567 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1568 break;
1571 case MOUSE_PROTO_VERSAPAD:
1572 tcsendbreak(rodent.mfd, 0); /* send break for 400 msec */
1573 i = FREAD;
1574 ioctl(rodent.mfd, TIOCFLUSH, &i);
1575 for (i = 0; i < 7; ++i) {
1576 FD_ZERO(&fds);
1577 FD_SET(rodent.mfd, &fds);
1578 if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
1579 break;
1580 read(rodent.mfd, &c, 1);
1581 buf[i] = c;
1583 debug("%s\n", buf);
1584 if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r'))
1585 break;
1586 setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
1587 tcsendbreak(rodent.mfd, 0); /* send break for 400 msec again */
1588 for (i = 0; i < 7; ++i) {
1589 FD_ZERO(&fds);
1590 FD_SET(rodent.mfd, &fds);
1591 if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
1592 break;
1593 read(rodent.mfd, &c, 1);
1594 debug("%c", c);
1595 if (c != buf[i])
1596 break;
1598 i = FREAD;
1599 ioctl(rodent.mfd, TIOCFLUSH, &i);
1600 break;
1602 default:
1603 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1604 break;
1608 static int
1609 r_protocol(u_char rBuf, mousestatus_t *act)
1611 /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1612 static int butmapmss[4] = { /* Microsoft, MouseMan, GlidePoint,
1613 IntelliMouse, Thinking Mouse */
1615 MOUSE_BUTTON3DOWN,
1616 MOUSE_BUTTON1DOWN,
1617 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1619 static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
1620 Thinking Mouse */
1622 MOUSE_BUTTON4DOWN,
1623 MOUSE_BUTTON2DOWN,
1624 MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
1626 /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1627 static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
1628 MouseMan+ */
1630 MOUSE_BUTTON2DOWN,
1631 MOUSE_BUTTON4DOWN,
1632 MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
1634 /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
1635 static int butmapmsc[8] = { /* MouseSystems, MMSeries, Logitech,
1636 Bus, sysmouse */
1638 MOUSE_BUTTON3DOWN,
1639 MOUSE_BUTTON2DOWN,
1640 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1641 MOUSE_BUTTON1DOWN,
1642 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1643 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
1644 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
1646 /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1647 static int butmapps2[8] = { /* PS/2 */
1649 MOUSE_BUTTON1DOWN,
1650 MOUSE_BUTTON3DOWN,
1651 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1652 MOUSE_BUTTON2DOWN,
1653 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
1654 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1655 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
1657 /* for Hitachi tablet */
1658 static int butmaphit[8] = { /* MM HitTablet */
1660 MOUSE_BUTTON3DOWN,
1661 MOUSE_BUTTON2DOWN,
1662 MOUSE_BUTTON1DOWN,
1663 MOUSE_BUTTON4DOWN,
1664 MOUSE_BUTTON5DOWN,
1665 MOUSE_BUTTON6DOWN,
1666 MOUSE_BUTTON7DOWN,
1668 /* for serial VersaPad */
1669 static int butmapversa[8] = { /* VersaPad */
1672 MOUSE_BUTTON3DOWN,
1673 MOUSE_BUTTON3DOWN,
1674 MOUSE_BUTTON1DOWN,
1675 MOUSE_BUTTON1DOWN,
1676 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1677 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1679 /* for PS/2 VersaPad */
1680 static int butmapversaps2[8] = { /* VersaPad */
1682 MOUSE_BUTTON3DOWN,
1684 MOUSE_BUTTON3DOWN,
1685 MOUSE_BUTTON1DOWN,
1686 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1687 MOUSE_BUTTON1DOWN,
1688 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1690 static int pBufP = 0;
1691 static unsigned char pBuf[8];
1692 static int prev_x, prev_y;
1693 static int on = FALSE;
1694 int x, y;
1696 debug("received char 0x%x",(int)rBuf);
1697 if (rodent.rtype == MOUSE_PROTO_KIDSPAD)
1698 return kidspad(rBuf, act) ;
1701 * Hack for resyncing: We check here for a package that is:
1702 * a) illegal (detected by wrong data-package header)
1703 * b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
1704 * c) bad header-package
1706 * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
1707 * -128 are allowed, but since they are very seldom we can easily
1708 * use them as package-header with no button pressed.
1709 * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
1710 * 0x80 is not valid as a header byte. For a PS/2 mouse we skip
1711 * checking data bytes.
1712 * For resyncing a PS/2 mouse we require the two most significant
1713 * bits in the header byte to be 0. These are the overflow bits,
1714 * and in case of an overflow we actually lose sync. Overflows
1715 * are very rare, however, and we quickly gain sync again after
1716 * an overflow condition. This is the best we can do. (Actually,
1717 * we could use bit 0x08 in the header byte for resyncing, since
1718 * that bit is supposed to be always on, but nobody told
1719 * Microsoft...)
1722 if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
1723 ((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
1725 pBufP = 0; /* skip package */
1728 if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
1729 return 0;
1731 /* is there an extra data byte? */
1732 if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
1735 * Hack for Logitech MouseMan Mouse - Middle button
1737 * Unfortunately this mouse has variable length packets: the standard
1738 * Microsoft 3 byte packet plus an optional 4th byte whenever the
1739 * middle button status changes.
1741 * We have already processed the standard packet with the movement
1742 * and button info. Now post an event message with the old status
1743 * of the left and right buttons and the updated middle button.
1747 * Even worse, different MouseMen and TrackMen differ in the 4th
1748 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
1749 * 0x02/0x22, so I have to strip off the lower bits.
1751 * [JCH-96/01/21]
1752 * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
1753 * and it is activated by tapping the glidepad with the finger! 8^)
1754 * We map it to bit bit3, and the reverse map in xf86Events just has
1755 * to be extended so that it is identified as Button 4. The lower
1756 * half of the reverse-map may remain unchanged.
1760 * [KY-97/08/03]
1761 * Receive the fourth byte only when preceding three bytes have
1762 * been detected (pBufP >= cur_proto[4]). In the previous
1763 * versions, the test was pBufP == 0; thus, we may have mistakingly
1764 * received a byte even if we didn't see anything preceding
1765 * the byte.
1768 if ((rBuf & cur_proto[5]) != cur_proto[6]) {
1769 pBufP = 0;
1770 return 0;
1773 switch (rodent.rtype) {
1774 #if notyet
1775 case MOUSE_PROTO_MARIQUA:
1777 * This mouse has 16! buttons in addition to the standard
1778 * three of them. They return 0x10 though 0x1f in the
1779 * so-called `ten key' mode and 0x30 though 0x3f in the
1780 * `function key' mode. As there are only 31 bits for
1781 * button state (including the standard three), we ignore
1782 * the bit 0x20 and don't distinguish the two modes.
1784 act->dx = act->dy = act->dz = 0;
1785 act->obutton = act->button;
1786 rBuf &= 0x1f;
1787 act->button = (1 << (rBuf - 13))
1788 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1790 * FIXME: this is a button "down" event. There needs to be
1791 * a corresponding button "up" event... XXX
1793 break;
1794 #endif /* notyet */
1795 case MOUSE_PROTO_JOGDIAL:
1796 break;
1799 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
1800 * always send the fourth byte, whereas the fourth byte is
1801 * optional for GlidePoint and ThinkingMouse. The fourth byte
1802 * is also optional for MouseMan+ and FirstMouse+ in their
1803 * native mode. It is always sent if they are in the IntelliMouse
1804 * compatible mode.
1806 case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse,
1807 MouseMan+ */
1808 act->dx = act->dy = 0;
1809 act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
1810 if ((act->dz >= 7) || (act->dz <= -7))
1811 act->dz = 0;
1812 act->obutton = act->button;
1813 act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
1814 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1815 break;
1817 default:
1818 act->dx = act->dy = act->dz = 0;
1819 act->obutton = act->button;
1820 act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
1821 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1822 break;
1825 act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
1826 | (act->obutton ^ act->button);
1827 pBufP = 0;
1828 return act->flags;
1831 if (pBufP >= cur_proto[4])
1832 pBufP = 0;
1833 pBuf[pBufP++] = rBuf;
1834 if (pBufP != cur_proto[4])
1835 return 0;
1838 * assembly full package
1841 debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
1842 cur_proto[4],
1843 pBuf[0], pBuf[1], pBuf[2], pBuf[3],
1844 pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
1846 act->dz = 0;
1847 act->obutton = act->button;
1848 switch (rodent.rtype)
1850 case MOUSE_PROTO_MS: /* Microsoft */
1851 case MOUSE_PROTO_LOGIMOUSEMAN: /* MouseMan/TrackMan */
1852 case MOUSE_PROTO_X10MOUSEREM: /* X10 MouseRemote */
1853 act->button = act->obutton & MOUSE_BUTTON4DOWN;
1854 if (rodent.flags & ChordMiddle)
1855 act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
1856 ? MOUSE_BUTTON2DOWN
1857 : butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1858 else
1859 act->button |= (act->obutton & MOUSE_BUTTON2DOWN)
1860 | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1862 /* Send X10 btn events to remote client (ensure -128-+127 range) */
1863 if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) &&
1864 ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) {
1865 if (rodent.mremcfd >= 0) {
1866 unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) |
1867 (pBuf[1] & 0x3F));
1868 write(rodent.mremcfd, &key, 1);
1870 return 0;
1873 act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
1874 act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
1875 break;
1877 case MOUSE_PROTO_GLIDEPOINT: /* GlidePoint */
1878 case MOUSE_PROTO_THINK: /* ThinkingMouse */
1879 case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse,
1880 MouseMan+ */
1881 act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
1882 | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1883 act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
1884 act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
1885 break;
1887 case MOUSE_PROTO_MSC: /* MouseSystems Corp */
1888 #if notyet
1889 case MOUSE_PROTO_MARIQUA: /* Mariqua */
1890 #endif
1891 act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
1892 act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
1893 act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
1894 break;
1896 case MOUSE_PROTO_JOGDIAL: /* JogDial */
1897 if (rBuf == 0x6c)
1898 act->dz = -1;
1899 if (rBuf == 0x72)
1900 act->dz = 1;
1901 if (rBuf == 0x64)
1902 act->button = MOUSE_BUTTON1DOWN;
1903 if (rBuf == 0x75)
1904 act->button = 0;
1905 break;
1907 case MOUSE_PROTO_HITTAB: /* MM HitTablet */
1908 act->button = butmaphit[pBuf[0] & 0x07];
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;
1913 case MOUSE_PROTO_MM: /* MM Series */
1914 case MOUSE_PROTO_LOGI: /* Logitech Mice */
1915 act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
1916 act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1];
1917 act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2];
1918 break;
1920 case MOUSE_PROTO_VERSAPAD: /* VersaPad */
1921 act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3];
1922 act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
1923 act->dx = act->dy = 0;
1924 if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) {
1925 on = FALSE;
1926 break;
1928 x = (pBuf[2] << 6) | pBuf[1];
1929 if (x & 0x800)
1930 x -= 0x1000;
1931 y = (pBuf[4] << 6) | pBuf[3];
1932 if (y & 0x800)
1933 y -= 0x1000;
1934 if (on) {
1935 act->dx = prev_x - x;
1936 act->dy = prev_y - y;
1937 } else {
1938 on = TRUE;
1940 prev_x = x;
1941 prev_y = y;
1942 break;
1944 case MOUSE_PROTO_BUS: /* Bus */
1945 case MOUSE_PROTO_INPORT: /* InPort */
1946 act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
1947 act->dx = (signed char)pBuf[1];
1948 act->dy = - (signed char)pBuf[2];
1949 break;
1951 case MOUSE_PROTO_PS2: /* PS/2 */
1952 act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
1953 act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ? pBuf[1] - 256 : pBuf[1];
1954 act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ? -(pBuf[2] - 256) : -pBuf[2];
1956 * Moused usually operates the psm driver at the operation level 1
1957 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
1958 * The following code takes effect only when the user explicitly
1959 * requets the level 2 at which wheel movement and additional button
1960 * actions are encoded in model-dependent formats. At the level 0
1961 * the following code is no-op because the psm driver says the model
1962 * is MOUSE_MODEL_GENERIC.
1964 switch (rodent.hw.model) {
1965 case MOUSE_MODEL_EXPLORER:
1966 /* wheel and additional button data is in the fourth byte */
1967 act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG)
1968 ? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f);
1969 act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN)
1970 ? MOUSE_BUTTON4DOWN : 0;
1971 act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN)
1972 ? MOUSE_BUTTON5DOWN : 0;
1973 break;
1974 case MOUSE_MODEL_INTELLI:
1975 case MOUSE_MODEL_NET:
1976 /* wheel data is in the fourth byte */
1977 act->dz = (signed char)pBuf[3];
1978 if ((act->dz >= 7) || (act->dz <= -7))
1979 act->dz = 0;
1980 /* some compatible mice may have additional buttons */
1981 act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN)
1982 ? MOUSE_BUTTON4DOWN : 0;
1983 act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN)
1984 ? MOUSE_BUTTON5DOWN : 0;
1985 break;
1986 case MOUSE_MODEL_MOUSEMANPLUS:
1987 if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
1988 && (abs(act->dx) > 191)
1989 && MOUSE_PS2PLUS_CHECKBITS(pBuf)) {
1990 /* the extended data packet encodes button and wheel events */
1991 switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) {
1992 case 1:
1993 /* wheel data packet */
1994 act->dx = act->dy = 0;
1995 if (pBuf[2] & 0x80) {
1996 /* horizontal roller count - ignore it XXX*/
1997 } else {
1998 /* vertical roller count */
1999 act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG)
2000 ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
2002 act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
2003 ? MOUSE_BUTTON4DOWN : 0;
2004 act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
2005 ? MOUSE_BUTTON5DOWN : 0;
2006 break;
2007 case 2:
2008 /* this packet type is reserved by Logitech */
2010 * IBM ScrollPoint Mouse uses this packet type to
2011 * encode both vertical and horizontal scroll movement.
2013 act->dx = act->dy = 0;
2014 /* horizontal roller count */
2015 if (pBuf[2] & 0x0f)
2016 act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
2017 /* vertical roller count */
2018 if (pBuf[2] & 0xf0)
2019 act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
2020 #if 0
2021 /* vertical roller count */
2022 act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG)
2023 ? ((pBuf[2] >> 4) & 0x0f) - 16
2024 : ((pBuf[2] >> 4) & 0x0f);
2025 /* horizontal roller count */
2026 act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG)
2027 ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
2028 #endif
2029 break;
2030 case 0:
2031 /* device type packet - shouldn't happen */
2032 /* FALLTHROUGH */
2033 default:
2034 act->dx = act->dy = 0;
2035 act->button = act->obutton;
2036 debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n",
2037 MOUSE_PS2PLUS_PACKET_TYPE(pBuf),
2038 pBuf[0], pBuf[1], pBuf[2]);
2039 break;
2041 } else {
2042 /* preserve button states */
2043 act->button |= act->obutton & MOUSE_EXTBUTTONS;
2045 break;
2046 case MOUSE_MODEL_GLIDEPOINT:
2047 /* `tapping' action */
2048 act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
2049 break;
2050 case MOUSE_MODEL_NETSCROLL:
2051 /* three addtional bytes encode buttons and wheel events */
2052 act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
2053 ? MOUSE_BUTTON4DOWN : 0;
2054 act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN)
2055 ? MOUSE_BUTTON5DOWN : 0;
2056 act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
2057 break;
2058 case MOUSE_MODEL_THINK:
2059 /* the fourth button state in the first byte */
2060 act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
2061 break;
2062 case MOUSE_MODEL_VERSAPAD:
2063 act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS];
2064 act->button |=
2065 (pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
2066 act->dx = act->dy = 0;
2067 if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) {
2068 on = FALSE;
2069 break;
2071 x = ((pBuf[4] << 8) & 0xf00) | pBuf[1];
2072 if (x & 0x800)
2073 x -= 0x1000;
2074 y = ((pBuf[4] << 4) & 0xf00) | pBuf[2];
2075 if (y & 0x800)
2076 y -= 0x1000;
2077 if (on) {
2078 act->dx = prev_x - x;
2079 act->dy = prev_y - y;
2080 } else {
2081 on = TRUE;
2083 prev_x = x;
2084 prev_y = y;
2085 break;
2086 case MOUSE_MODEL_4D:
2087 act->dx = (pBuf[1] & 0x80) ? pBuf[1] - 256 : pBuf[1];
2088 act->dy = (pBuf[2] & 0x80) ? -(pBuf[2] - 256) : -pBuf[2];
2089 switch (pBuf[0] & MOUSE_4D_WHEELBITS) {
2090 case 0x10:
2091 act->dz = 1;
2092 break;
2093 case 0x30:
2094 act->dz = -1;
2095 break;
2096 case 0x40: /* 2nd wheel rolling right XXX */
2097 act->dz = 2;
2098 break;
2099 case 0xc0: /* 2nd wheel rolling left XXX */
2100 act->dz = -2;
2101 break;
2103 break;
2104 case MOUSE_MODEL_4DPLUS:
2105 if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) {
2106 act->dx = act->dy = 0;
2107 if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN)
2108 act->button |= MOUSE_BUTTON4DOWN;
2109 act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG)
2110 ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07);
2111 } else {
2112 /* preserve previous button states */
2113 act->button |= act->obutton & MOUSE_EXTBUTTONS;
2115 break;
2116 case MOUSE_MODEL_GENERIC:
2117 default:
2118 break;
2120 break;
2122 case MOUSE_PROTO_SYSMOUSE: /* sysmouse */
2123 act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
2124 act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
2125 act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
2126 if (rodent.level == 1) {
2127 act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1;
2128 act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
2130 break;
2132 default:
2133 return 0;
2136 * We don't reset pBufP here yet, as there may be an additional data
2137 * byte in some protocols. See above.
2140 /* has something changed? */
2141 act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
2142 | (act->obutton ^ act->button);
2144 return act->flags;
2147 static int
2148 r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans)
2150 int changed;
2151 int flags;
2153 a2->dx = a1->dx;
2154 a2->dy = a1->dy;
2155 a2->dz = a1->dz;
2156 a2->obutton = a2->button;
2157 a2->button = a1->button;
2158 a2->flags = a1->flags;
2159 changed = FALSE;
2161 if (rodent.flags & Emulate3Button) {
2162 if (debug > 2)
2163 debug("state:%d, trans:%d -> state:%d",
2164 mouse_button_state, trans,
2165 states[mouse_button_state].s[trans]);
2167 * Avoid re-ordering button and movement events. While a button
2168 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
2169 * events to allow for mouse jitter. If more movement events
2170 * occur, then complete the deferred button events immediately.
2172 if ((a2->dx != 0 || a2->dy != 0) &&
2173 S_DELAYED(states[mouse_button_state].s[trans])) {
2174 if (++mouse_move_delayed > BUTTON2_MAXMOVE) {
2175 mouse_move_delayed = 0;
2176 mouse_button_state =
2177 states[mouse_button_state].s[A_TIMEOUT];
2178 changed = TRUE;
2179 } else
2180 a2->dx = a2->dy = 0;
2181 } else
2182 mouse_move_delayed = 0;
2183 if (mouse_button_state != states[mouse_button_state].s[trans])
2184 changed = TRUE;
2185 if (changed)
2186 gettimeofday(&mouse_button_state_tv, NULL);
2187 mouse_button_state = states[mouse_button_state].s[trans];
2188 a2->button &=
2189 ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN);
2190 a2->button &= states[mouse_button_state].mask;
2191 a2->button |= states[mouse_button_state].buttons;
2192 flags = a2->flags & MOUSE_POSCHANGED;
2193 flags |= a2->obutton ^ a2->button;
2194 if (flags & MOUSE_BUTTON2DOWN) {
2195 a2->flags = flags & MOUSE_BUTTON2DOWN;
2196 r_timestamp(a2);
2198 a2->flags = flags;
2200 return changed;
2203 /* phisical to logical button mapping */
2204 static int p2l[MOUSE_MAXBUTTON] = {
2205 MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
2206 MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
2207 0x00000100, 0x00000200, 0x00000400, 0x00000800,
2208 0x00001000, 0x00002000, 0x00004000, 0x00008000,
2209 0x00010000, 0x00020000, 0x00040000, 0x00080000,
2210 0x00100000, 0x00200000, 0x00400000, 0x00800000,
2211 0x01000000, 0x02000000, 0x04000000, 0x08000000,
2212 0x10000000, 0x20000000, 0x40000000,
2215 static char *
2216 skipspace(char *s)
2218 while(isspace(*s))
2219 ++s;
2220 return s;
2223 static int
2224 r_installmap(char *arg)
2226 int pbutton;
2227 int lbutton;
2228 char *s;
2230 while (*arg) {
2231 arg = skipspace(arg);
2232 s = arg;
2233 while (isdigit(*arg))
2234 ++arg;
2235 arg = skipspace(arg);
2236 if ((arg <= s) || (*arg != '='))
2237 return FALSE;
2238 lbutton = atoi(s);
2240 arg = skipspace(++arg);
2241 s = arg;
2242 while (isdigit(*arg))
2243 ++arg;
2244 if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
2245 return FALSE;
2246 pbutton = atoi(s);
2248 if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
2249 return FALSE;
2250 if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
2251 return FALSE;
2252 p2l[pbutton - 1] = 1 << (lbutton - 1);
2253 mstate[lbutton - 1] = &bstate[pbutton - 1];
2256 return TRUE;
2259 static void
2260 r_map(mousestatus_t *act1, mousestatus_t *act2)
2262 register int pb;
2263 register int pbuttons;
2264 int lbuttons;
2266 pbuttons = act1->button;
2267 lbuttons = 0;
2269 act2->obutton = act2->button;
2270 if (pbuttons & rodent.wmode) {
2271 pbuttons &= ~rodent.wmode;
2272 act1->dz = act1->dy;
2273 act1->dx = 0;
2274 act1->dy = 0;
2276 act2->dx = act1->dx;
2277 act2->dy = act1->dy;
2278 act2->dz = act1->dz;
2280 switch (rodent.zmap[0]) {
2281 case 0: /* do nothing */
2282 break;
2283 case MOUSE_XAXIS:
2284 if (act1->dz != 0) {
2285 act2->dx = act1->dz;
2286 act2->dz = 0;
2288 break;
2289 case MOUSE_YAXIS:
2290 if (act1->dz != 0) {
2291 act2->dy = act1->dz;
2292 act2->dz = 0;
2294 break;
2295 default: /* buttons */
2296 pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1]
2297 | rodent.zmap[2] | rodent.zmap[3]);
2298 if ((act1->dz < -1) && rodent.zmap[2]) {
2299 pbuttons |= rodent.zmap[2];
2300 zstate[2].count = 1;
2301 } else if (act1->dz < 0) {
2302 pbuttons |= rodent.zmap[0];
2303 zstate[0].count = 1;
2304 } else if ((act1->dz > 1) && rodent.zmap[3]) {
2305 pbuttons |= rodent.zmap[3];
2306 zstate[3].count = 1;
2307 } else if (act1->dz > 0) {
2308 pbuttons |= rodent.zmap[1];
2309 zstate[1].count = 1;
2311 act2->dz = 0;
2312 break;
2315 for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
2316 lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
2317 pbuttons >>= 1;
2319 act2->button = lbuttons;
2321 act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
2322 | (act2->obutton ^ act2->button);
2325 static void
2326 r_timestamp(mousestatus_t *act)
2328 struct timeval tv;
2329 struct timeval tv1;
2330 struct timeval tv2;
2331 struct timeval tv3;
2332 int button;
2333 int mask;
2334 int i;
2336 mask = act->flags & MOUSE_BUTTONS;
2337 if (mask == 0)
2338 return;
2340 gettimeofday(&tv1, NULL);
2342 /* double click threshold */
2343 tv2.tv_sec = rodent.clickthreshold/1000;
2344 tv2.tv_usec = (rodent.clickthreshold%1000)*1000;
2345 timersub(&tv1, &tv2, &tv);
2346 debug("tv: %ld %ld", tv.tv_sec, tv.tv_usec);
2348 /* 3 button emulation timeout */
2349 tv2.tv_sec = rodent.button2timeout/1000;
2350 tv2.tv_usec = (rodent.button2timeout%1000)*1000;
2351 timersub(&tv1, &tv2, &tv3);
2353 button = MOUSE_BUTTON1DOWN;
2354 for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2355 if (mask & 1) {
2356 if (act->button & button) {
2357 /* the button is down */
2358 debug(" : %ld %ld",
2359 bstate[i].tv.tv_sec, bstate[i].tv.tv_usec);
2360 if (timercmp(&tv, &bstate[i].tv, >)) {
2361 bstate[i].count = 1;
2362 } else {
2363 ++bstate[i].count;
2365 bstate[i].tv = tv1;
2366 } else {
2367 /* the button is up */
2368 bstate[i].tv = tv1;
2370 } else {
2371 if (act->button & button) {
2372 /* the button has been down */
2373 if (timercmp(&tv3, &bstate[i].tv, >)) {
2374 bstate[i].count = 1;
2375 bstate[i].tv = tv1;
2376 act->flags |= button;
2377 debug("button %d timeout", i + 1);
2379 } else {
2380 /* the button has been up */
2383 button <<= 1;
2384 mask >>= 1;
2388 static int
2389 r_timeout(void)
2391 struct timeval tv;
2392 struct timeval tv1;
2393 struct timeval tv2;
2395 if (states[mouse_button_state].timeout)
2396 return TRUE;
2397 gettimeofday(&tv1, NULL);
2398 tv2.tv_sec = rodent.button2timeout/1000;
2399 tv2.tv_usec = (rodent.button2timeout%1000)*1000;
2400 timersub(&tv1, &tv2, &tv);
2401 return timercmp(&tv, &mouse_button_state_tv, >);
2404 static void
2405 r_click(mousestatus_t *act)
2407 struct mouse_info mouse;
2408 int button;
2409 int mask;
2410 int i;
2412 mask = act->flags & MOUSE_BUTTONS;
2413 if (mask == 0)
2414 return;
2416 button = MOUSE_BUTTON1DOWN;
2417 for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2418 if (mask & 1) {
2419 debug("mstate[%d]->count:%d", i, mstate[i]->count);
2420 if (act->button & button) {
2421 /* the button is down */
2422 mouse.u.event.value = mstate[i]->count;
2423 } else {
2424 /* the button is up */
2425 mouse.u.event.value = 0;
2427 mouse.operation = MOUSE_BUTTON_EVENT;
2428 mouse.u.event.id = button;
2429 if (debug < 2)
2430 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
2431 debug("button %d count %d", i + 1, mouse.u.event.value);
2433 button <<= 1;
2434 mask >>= 1;
2438 /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
2439 /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
2441 * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
2443 * Permission to use, copy, modify, distribute, and sell this software and its
2444 * documentation for any purpose is hereby granted without fee, provided that
2445 * the above copyright notice appear in all copies and that both that
2446 * copyright notice and this permission notice appear in supporting
2447 * documentation, and that the name of David Dawes
2448 * not be used in advertising or publicity pertaining to distribution of
2449 * the software without specific, written prior permission.
2450 * David Dawes makes no representations about the suitability of this
2451 * software for any purpose. It is provided "as is" without express or
2452 * implied warranty.
2454 * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
2455 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
2456 * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
2457 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
2458 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
2459 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2460 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2465 static void
2466 setmousespeed(int old, int new, unsigned cflag)
2468 struct termios tty;
2469 char *c;
2471 if (tcgetattr(rodent.mfd, &tty) < 0)
2473 logwarn("unable to get status of mouse fd");
2474 return;
2477 tty.c_iflag = IGNBRK | IGNPAR;
2478 tty.c_oflag = 0;
2479 tty.c_lflag = 0;
2480 tty.c_cflag = (tcflag_t)cflag;
2481 tty.c_cc[VTIME] = 0;
2482 tty.c_cc[VMIN] = 1;
2484 switch (old)
2486 case 9600:
2487 cfsetispeed(&tty, B9600);
2488 cfsetospeed(&tty, B9600);
2489 break;
2490 case 4800:
2491 cfsetispeed(&tty, B4800);
2492 cfsetospeed(&tty, B4800);
2493 break;
2494 case 2400:
2495 cfsetispeed(&tty, B2400);
2496 cfsetospeed(&tty, B2400);
2497 break;
2498 case 1200:
2499 default:
2500 cfsetispeed(&tty, B1200);
2501 cfsetospeed(&tty, B1200);
2504 if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
2506 logwarn("unable to set status of mouse fd");
2507 return;
2510 switch (new)
2512 case 9600:
2513 c = "*q";
2514 cfsetispeed(&tty, B9600);
2515 cfsetospeed(&tty, B9600);
2516 break;
2517 case 4800:
2518 c = "*p";
2519 cfsetispeed(&tty, B4800);
2520 cfsetospeed(&tty, B4800);
2521 break;
2522 case 2400:
2523 c = "*o";
2524 cfsetispeed(&tty, B2400);
2525 cfsetospeed(&tty, B2400);
2526 break;
2527 case 1200:
2528 default:
2529 c = "*n";
2530 cfsetispeed(&tty, B1200);
2531 cfsetospeed(&tty, B1200);
2534 if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
2535 || rodent.rtype == MOUSE_PROTO_LOGI)
2537 if (write(rodent.mfd, c, 2) != 2)
2539 logwarn("unable to write to mouse fd");
2540 return;
2543 usleep(100000);
2545 if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
2546 logwarn("unable to set status of mouse fd");
2550 * PnP COM device support
2552 * It's a simplistic implementation, but it works :-)
2553 * KY, 31/7/97.
2557 * Try to elicit a PnP ID as described in
2558 * Microsoft, Hayes: "Plug and Play External COM Device Specification,
2559 * rev 1.00", 1995.
2561 * The routine does not fully implement the COM Enumerator as par Section
2562 * 2.1 of the document. In particular, we don't have idle state in which
2563 * the driver software monitors the com port for dynamic connection or
2564 * removal of a device at the port, because `moused' simply quits if no
2565 * device is found.
2567 * In addition, as PnP COM device enumeration procedure slightly has
2568 * changed since its first publication, devices which follow earlier
2569 * revisions of the above spec. may fail to respond if the rev 1.0
2570 * procedure is used. XXX
2572 static int
2573 pnpwakeup1(void)
2575 struct timeval timeout;
2576 fd_set fds;
2577 int i;
2580 * This is the procedure described in rev 1.0 of PnP COM device spec.
2581 * Unfortunately, some devices which comform to earlier revisions of
2582 * the spec gets confused and do not return the ID string...
2584 debug("PnP COM device rev 1.0 probe...");
2586 /* port initialization (2.1.2) */
2587 ioctl(rodent.mfd, TIOCMGET, &i);
2588 i |= TIOCM_DTR; /* DTR = 1 */
2589 i &= ~TIOCM_RTS; /* RTS = 0 */
2590 ioctl(rodent.mfd, TIOCMSET, &i);
2591 usleep(240000);
2594 * The PnP COM device spec. dictates that the mouse must set DSR
2595 * in response to DTR (by hardware or by software) and that if DSR is
2596 * not asserted, the host computer should think that there is no device
2597 * at this serial port. But some mice just don't do that...
2599 ioctl(rodent.mfd, TIOCMGET, &i);
2600 debug("modem status 0%o", i);
2601 if ((i & TIOCM_DSR) == 0)
2602 return FALSE;
2604 /* port setup, 1st phase (2.1.3) */
2605 setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
2606 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
2607 ioctl(rodent.mfd, TIOCMBIC, &i);
2608 usleep(240000);
2609 i = TIOCM_DTR; /* DTR = 1, RTS = 0 */
2610 ioctl(rodent.mfd, TIOCMBIS, &i);
2611 usleep(240000);
2613 /* wait for response, 1st phase (2.1.4) */
2614 i = FREAD;
2615 ioctl(rodent.mfd, TIOCFLUSH, &i);
2616 i = TIOCM_RTS; /* DTR = 1, RTS = 1 */
2617 ioctl(rodent.mfd, TIOCMBIS, &i);
2619 /* try to read something */
2620 FD_ZERO(&fds);
2621 FD_SET(rodent.mfd, &fds);
2622 timeout.tv_sec = 0;
2623 timeout.tv_usec = 240000;
2624 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2625 debug("pnpwakeup1(): valid response in first phase.");
2626 return TRUE;
2629 /* port setup, 2nd phase (2.1.5) */
2630 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
2631 ioctl(rodent.mfd, TIOCMBIC, &i);
2632 usleep(240000);
2634 /* wait for respose, 2nd phase (2.1.6) */
2635 i = FREAD;
2636 ioctl(rodent.mfd, TIOCFLUSH, &i);
2637 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
2638 ioctl(rodent.mfd, TIOCMBIS, &i);
2640 /* try to read something */
2641 FD_ZERO(&fds);
2642 FD_SET(rodent.mfd, &fds);
2643 timeout.tv_sec = 0;
2644 timeout.tv_usec = 240000;
2645 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2646 debug("pnpwakeup1(): valid response in second phase.");
2647 return TRUE;
2650 return FALSE;
2653 static int
2654 pnpwakeup2(void)
2656 struct timeval timeout;
2657 fd_set fds;
2658 int i;
2661 * This is a simplified procedure; it simply toggles RTS.
2663 debug("alternate probe...");
2665 ioctl(rodent.mfd, TIOCMGET, &i);
2666 i |= TIOCM_DTR; /* DTR = 1 */
2667 i &= ~TIOCM_RTS; /* RTS = 0 */
2668 ioctl(rodent.mfd, TIOCMSET, &i);
2669 usleep(240000);
2671 setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
2673 /* wait for respose */
2674 i = FREAD;
2675 ioctl(rodent.mfd, TIOCFLUSH, &i);
2676 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
2677 ioctl(rodent.mfd, TIOCMBIS, &i);
2679 /* try to read something */
2680 FD_ZERO(&fds);
2681 FD_SET(rodent.mfd, &fds);
2682 timeout.tv_sec = 0;
2683 timeout.tv_usec = 240000;
2684 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2685 debug("pnpwakeup2(): valid response.");
2686 return TRUE;
2689 return FALSE;
2692 static int
2693 pnpgets(char *buf)
2695 struct timeval timeout;
2696 fd_set fds;
2697 int begin;
2698 int i;
2699 char c;
2701 if (!pnpwakeup1() && !pnpwakeup2()) {
2703 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2704 * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
2705 * assuming there is something at the port even if it didn't
2706 * respond to the PnP enumeration procedure.
2708 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
2709 ioctl(rodent.mfd, TIOCMBIS, &i);
2710 return 0;
2713 /* collect PnP COM device ID (2.1.7) */
2714 begin = -1;
2715 i = 0;
2716 usleep(240000); /* the mouse must send `Begin ID' within 200msec */
2717 while (read(rodent.mfd, &c, 1) == 1) {
2718 /* we may see "M", or "M3..." before `Begin ID' */
2719 buf[i++] = c;
2720 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
2721 debug("begin-id %02x", c);
2722 begin = i - 1;
2723 break;
2725 debug("%c %02x", c, c);
2726 if (i >= 256)
2727 break;
2729 if (begin < 0) {
2730 /* we haven't seen `Begin ID' in time... */
2731 goto connect_idle;
2734 ++c; /* make it `End ID' */
2735 for (;;) {
2736 FD_ZERO(&fds);
2737 FD_SET(rodent.mfd, &fds);
2738 timeout.tv_sec = 0;
2739 timeout.tv_usec = 240000;
2740 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
2741 break;
2743 read(rodent.mfd, &buf[i], 1);
2744 if (buf[i++] == c) /* End ID */
2745 break;
2746 if (i >= 256)
2747 break;
2749 if (begin > 0) {
2750 i -= begin;
2751 bcopy(&buf[begin], &buf[0], i);
2753 /* string may not be human readable... */
2754 debug("len:%d, '%-*.*s'", i, i, i, buf);
2756 if (buf[i - 1] == c)
2757 return i; /* a valid PnP string */
2760 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2761 * in idle state. But, `moused' shall leave the modem control lines
2762 * as they are. See above.
2764 connect_idle:
2766 /* we may still have something in the buffer */
2767 return ((i > 0) ? i : 0);
2770 static int
2771 pnpparse(pnpid_t *id, char *buf, int len)
2773 char s[3];
2774 int offset;
2775 int sum = 0;
2776 int i, j;
2778 id->revision = 0;
2779 id->eisaid = NULL;
2780 id->serial = NULL;
2781 id->class = NULL;
2782 id->compat = NULL;
2783 id->description = NULL;
2784 id->neisaid = 0;
2785 id->nserial = 0;
2786 id->nclass = 0;
2787 id->ncompat = 0;
2788 id->ndescription = 0;
2790 if ((buf[0] != 0x28) && (buf[0] != 0x08)) {
2791 /* non-PnP mice */
2792 switch(buf[0]) {
2793 default:
2794 return FALSE;
2795 case 'M': /* Microsoft */
2796 id->eisaid = "PNP0F01";
2797 break;
2798 case 'H': /* MouseSystems */
2799 id->eisaid = "PNP0F04";
2800 break;
2802 id->neisaid = strlen(id->eisaid);
2803 id->class = "MOUSE";
2804 id->nclass = strlen(id->class);
2805 debug("non-PnP mouse '%c'", buf[0]);
2806 return TRUE;
2809 /* PnP mice */
2810 offset = 0x28 - buf[0];
2812 /* calculate checksum */
2813 for (i = 0; i < len - 3; ++i) {
2814 sum += buf[i];
2815 buf[i] += offset;
2817 sum += buf[len - 1];
2818 for (; i < len; ++i)
2819 buf[i] += offset;
2820 debug("PnP ID string: '%*.*s'", len, len, buf);
2822 /* revision */
2823 buf[1] -= offset;
2824 buf[2] -= offset;
2825 id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
2826 debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
2828 /* EISA vender and product ID */
2829 id->eisaid = &buf[3];
2830 id->neisaid = 7;
2832 /* option strings */
2833 i = 10;
2834 if (buf[i] == '\\') {
2835 /* device serial # */
2836 for (j = ++i; i < len; ++i) {
2837 if (buf[i] == '\\')
2838 break;
2840 if (i >= len)
2841 i -= 3;
2842 if (i - j == 8) {
2843 id->serial = &buf[j];
2844 id->nserial = 8;
2847 if (buf[i] == '\\') {
2848 /* PnP class */
2849 for (j = ++i; i < len; ++i) {
2850 if (buf[i] == '\\')
2851 break;
2853 if (i >= len)
2854 i -= 3;
2855 if (i > j + 1) {
2856 id->class = &buf[j];
2857 id->nclass = i - j;
2860 if (buf[i] == '\\') {
2861 /* compatible driver */
2862 for (j = ++i; i < len; ++i) {
2863 if (buf[i] == '\\')
2864 break;
2867 * PnP COM spec prior to v0.96 allowed '*' in this field,
2868 * it's not allowed now; just igore it.
2870 if (buf[j] == '*')
2871 ++j;
2872 if (i >= len)
2873 i -= 3;
2874 if (i > j + 1) {
2875 id->compat = &buf[j];
2876 id->ncompat = i - j;
2879 if (buf[i] == '\\') {
2880 /* product description */
2881 for (j = ++i; i < len; ++i) {
2882 if (buf[i] == ';')
2883 break;
2885 if (i >= len)
2886 i -= 3;
2887 if (i > j + 1) {
2888 id->description = &buf[j];
2889 id->ndescription = i - j;
2893 /* checksum exists if there are any optional fields */
2894 if ((id->nserial > 0) || (id->nclass > 0)
2895 || (id->ncompat > 0) || (id->ndescription > 0)) {
2896 debug("PnP checksum: 0x%X", sum);
2897 sprintf(s, "%02X", sum & 0x0ff);
2898 if (strncmp(s, &buf[len - 3], 2) != 0) {
2899 #if 0
2901 * I found some mice do not comply with the PnP COM device
2902 * spec regarding checksum... XXX
2904 logwarnx("PnP checksum error", 0);
2905 return FALSE;
2906 #endif
2910 return TRUE;
2913 static symtab_t *
2914 pnpproto(pnpid_t *id)
2916 symtab_t *t;
2917 int i, j;
2919 if (id->nclass > 0)
2920 if (strncmp(id->class, "MOUSE", id->nclass) != 0 &&
2921 strncmp(id->class, "TABLET", id->nclass) != 0)
2922 /* this is not a mouse! */
2923 return NULL;
2925 if (id->neisaid > 0) {
2926 t = gettoken(pnpprod, id->eisaid, id->neisaid);
2927 if (t->val != MOUSE_PROTO_UNKNOWN)
2928 return t;
2932 * The 'Compatible drivers' field may contain more than one
2933 * ID separated by ','.
2935 if (id->ncompat <= 0)
2936 return NULL;
2937 for (i = 0; i < id->ncompat; ++i) {
2938 for (j = i; id->compat[i] != ','; ++i)
2939 if (i >= id->ncompat)
2940 break;
2941 if (i > j) {
2942 t = gettoken(pnpprod, id->compat + j, i - j);
2943 if (t->val != MOUSE_PROTO_UNKNOWN)
2944 return t;
2948 return NULL;
2951 /* name/val mapping */
2953 static symtab_t *
2954 gettoken(symtab_t *tab, char *s, int len)
2956 int i;
2958 for (i = 0; tab[i].name != NULL; ++i) {
2959 if (strncmp(tab[i].name, s, len) == 0)
2960 break;
2962 return &tab[i];
2965 static char *
2966 gettokenname(symtab_t *tab, int val)
2968 int i;
2970 for (i = 0; tab[i].name != NULL; ++i) {
2971 if (tab[i].val == val)
2972 return tab[i].name;
2974 return NULL;
2979 * code to read from the Genius Kidspad tablet.
2981 The tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005,
2982 and to pre-pnp probes (RTS toggle) with 'T' (tablet ?)
2983 9600, 8 bit, parity odd.
2985 The tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains
2986 the proximity, tip and button info:
2987 (byte0 & 0x1) true = tip pressed
2988 (byte0 & 0x2) true = button pressed
2989 (byte0 & 0x40) false = pen in proximity of tablet.
2991 The next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid).
2993 Only absolute coordinates are returned, so we use the following approach:
2994 we store the last coordinates sent when the pen went out of the tablet,
3000 typedef enum {
3001 S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP
3002 } k_status ;
3004 static int
3005 kidspad(u_char rxc, mousestatus_t *act)
3007 static int buf[5];
3008 static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ;
3009 static k_status status = S_IDLE ;
3010 static struct timeval now ;
3012 int x, y ;
3014 if (buflen > 0 && (rxc & 0x80)) {
3015 fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
3016 buflen = 0 ;
3018 if (buflen == 0 && (rxc & 0xb8) != 0xb8) {
3019 fprintf(stderr, "invalid code 0 0x%x\n", rxc);
3020 return 0 ; /* invalid code, no action */
3022 buf[buflen++] = rxc ;
3023 if (buflen < 5)
3024 return 0 ;
3026 buflen = 0 ; /* for next time... */
3028 x = buf[1]+128*(buf[2] - 7) ;
3029 if (x < 0) x = 0 ;
3030 y = 28*128 - (buf[3] + 128* (buf[4] - 7)) ;
3031 if (y < 0) y = 0 ;
3033 x /= 8 ;
3034 y /= 8 ;
3036 act->flags = 0 ;
3037 act->obutton = act->button ;
3038 act->dx = act->dy = act->dz = 0 ;
3039 gettimeofday(&now, NULL);
3040 if (buf[0] & 0x40) /* pen went out of reach */
3041 status = S_IDLE ;
3042 else if (status == S_IDLE) { /* pen is newly near the tablet */
3043 act->flags |= MOUSE_POSCHANGED ; /* force update */
3044 status = S_PROXY ;
3045 x_prev = x ;
3046 y_prev = y ;
3048 act->dx = x - x_prev ;
3049 act->dy = y - y_prev ;
3050 if (act->dx || act->dy)
3051 act->flags |= MOUSE_POSCHANGED ;
3052 x_prev = x ;
3053 y_prev = y ;
3054 if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */
3055 act->button = 0 ;
3056 if (buf[0] & 0x01) /* tip pressed */
3057 act->button |= MOUSE_BUTTON1DOWN ;
3058 if (buf[0] & 0x02) /* button pressed */
3059 act->button |= MOUSE_BUTTON2DOWN ;
3060 act->flags |= MOUSE_BUTTONSCHANGED ;
3062 b_prev = buf[0] ;
3063 return act->flags ;
3066 static void
3067 mremote_serversetup(void)
3069 struct sockaddr_un ad;
3071 /* Open a UNIX domain stream socket to listen for mouse remote clients */
3072 unlink(_PATH_MOUSEREMOTE);
3074 if ((rodent.mremsfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
3075 logerrx(1, "unable to create unix domain socket %s",_PATH_MOUSEREMOTE);
3077 umask(0111);
3079 bzero(&ad, sizeof(ad));
3080 ad.sun_family = AF_UNIX;
3081 strcpy(ad.sun_path, _PATH_MOUSEREMOTE);
3082 #ifndef SUN_LEN
3083 #define SUN_LEN(unp) (((char *)(unp)->sun_path - (char *)(unp)) + \
3084 strlen((unp)->path))
3085 #endif
3086 if (bind(rodent.mremsfd, (struct sockaddr *) &ad, SUN_LEN(&ad)) < 0)
3087 logerrx(1, "unable to bind unix domain socket %s", _PATH_MOUSEREMOTE);
3089 listen(rodent.mremsfd, 1);
3092 static void
3093 mremote_clientchg(int add)
3095 struct sockaddr_un ad;
3096 int ad_len, fd;
3098 if (rodent.rtype != MOUSE_PROTO_X10MOUSEREM)
3099 return;
3101 if (add) {
3102 /* Accept client connection, if we don't already have one */
3103 ad_len = sizeof(ad);
3104 fd = accept(rodent.mremsfd, (struct sockaddr *) &ad, &ad_len);
3105 if (fd < 0)
3106 logwarnx("failed accept on mouse remote socket");
3108 if (rodent.mremcfd < 0) {
3109 rodent.mremcfd = fd;
3110 debug("remote client connect...accepted");
3112 else {
3113 close(fd);
3114 debug("another remote client connect...disconnected");
3117 else {
3118 /* Client disconnected */
3119 debug("remote client disconnected");
3120 close(rodent.mremcfd);
3121 rodent.mremcfd = -1;