Merge branch 'master' of ssh://swildner@crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / usr.sbin / moused / moused.c
blobce8f0c5181ccb5e2193bb3032e17aaa268dadd7a
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 $
49 * $DragonFly: src/usr.sbin/moused/moused.c,v 1.7 2008/11/12 21:44:59 swildner Exp $
51 #include <machine/console.h>
52 #include <machine/mouse.h>
53 #include <sys/cdefs.h>
54 #include <sys/param.h>
55 #include <sys/consio.h>
56 #include <sys/linker.h>
57 #include <sys/module.h>
58 #include <sys/socket.h>
59 #include <sys/stat.h>
60 #include <sys/time.h>
61 #include <sys/un.h>
63 #include <ctype.h>
64 #include <err.h>
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <limits.h>
68 #include <setjmp.h>
69 #include <signal.h>
70 #include <stdarg.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <syslog.h>
75 #include <termios.h>
76 #include <unistd.h>
78 #define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */
79 #define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */
80 #define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */
81 #define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */
82 #define DFLT_SCROLLTHRESHOLD 3 /* 3 pixels */
84 /* Abort 3-button emulation delay after this many movement events. */
85 #define BUTTON2_MAXMOVE 3
87 #define TRUE 1
88 #define FALSE 0
90 #define MOUSE_XAXIS (-1)
91 #define MOUSE_YAXIS (-2)
93 /* Logitech PS2++ protocol */
94 #define MOUSE_PS2PLUS_CHECKBITS(b) \
95 ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f))
96 #define MOUSE_PS2PLUS_PACKET_TYPE(b) \
97 (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
99 #define ChordMiddle 0x0001
100 #define Emulate3Button 0x0002
101 #define ClearDTR 0x0004
102 #define ClearRTS 0x0008
103 #define NoPnP 0x0010
104 #define VirtualScroll 0x0020
106 #define ID_NONE 0
107 #define ID_PORT 1
108 #define ID_IF 2
109 #define ID_TYPE 4
110 #define ID_MODEL 8
111 #define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
113 #define debug(fmt, args...) do { \
114 if (debug && nodaemon) \
115 warnx(fmt, ##args); \
116 } while (0)
118 #define logerr(e, fmt, args...) do { \
119 log_or_warn(LOG_DAEMON | LOG_ERR, errno, fmt, ##args); \
120 exit(e); \
121 } while (0)
123 #define logerrx(e, fmt, args...) do { \
124 log_or_warn(LOG_DAEMON | LOG_ERR, 0, fmt, ##args); \
125 exit(e); \
126 } while (0)
128 #define logwarn(fmt, args...) \
129 log_or_warn(LOG_DAEMON | LOG_WARNING, errno, fmt, ##args)
131 #define logwarnx(fmt, args...) \
132 log_or_warn(LOG_DAEMON | LOG_WARNING, 0, fmt, ##args)
134 /* structures */
136 /* symbol table entry */
137 typedef struct {
138 char *name;
139 int val;
140 int val2;
141 } symtab_t;
143 /* serial PnP ID string */
144 typedef struct {
145 int revision; /* PnP revision, 100 for 1.00 */
146 char *eisaid; /* EISA ID including mfr ID and product ID */
147 char *serial; /* serial No, optional */
148 char *class; /* device class, optional */
149 char *compat; /* list of compatible drivers, optional */
150 char *description; /* product description, optional */
151 int neisaid; /* length of the above fields... */
152 int nserial;
153 int nclass;
154 int ncompat;
155 int ndescription;
156 } pnpid_t;
158 /* global variables */
160 int debug = 0;
161 int nodaemon = FALSE;
162 int background = FALSE;
163 int identify = ID_NONE;
164 int extioctl = FALSE;
165 char *pidfile = "/var/run/moused.pid";
167 #define SCROLL_NOTSCROLLING 0
168 #define SCROLL_PREPARE 1
169 #define SCROLL_SCROLLING 2
171 static int scroll_state;
172 static int scroll_movement;
174 /* local variables */
176 /* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
177 static symtab_t rifs[] = {
178 { "serial", MOUSE_IF_SERIAL },
179 { "bus", MOUSE_IF_BUS },
180 { "inport", MOUSE_IF_INPORT },
181 { "ps/2", MOUSE_IF_PS2 },
182 { "sysmouse", MOUSE_IF_SYSMOUSE },
183 { "usb", MOUSE_IF_USB },
184 { NULL, MOUSE_IF_UNKNOWN },
187 /* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
188 static char *rnames[] = {
189 "microsoft",
190 "mousesystems",
191 "logitech",
192 "mmseries",
193 "mouseman",
194 "busmouse",
195 "inportmouse",
196 "ps/2",
197 "mmhitab",
198 "glidepoint",
199 "intellimouse",
200 "thinkingmouse",
201 "sysmouse",
202 "x10mouseremote",
203 "kidspad",
204 "versapad",
205 "jogdial",
206 #if notyet
207 "mariqua",
208 #endif
209 NULL
212 /* models */
213 static symtab_t rmodels[] = {
214 { "NetScroll", MOUSE_MODEL_NETSCROLL },
215 { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET },
216 { "GlidePoint", MOUSE_MODEL_GLIDEPOINT },
217 { "ThinkingMouse", MOUSE_MODEL_THINK },
218 { "IntelliMouse", MOUSE_MODEL_INTELLI },
219 { "EasyScroll/SmartScroll", MOUSE_MODEL_EASYSCROLL },
220 { "MouseMan+", MOUSE_MODEL_MOUSEMANPLUS },
221 { "Kidspad", MOUSE_MODEL_KIDSPAD },
222 { "VersaPad", MOUSE_MODEL_VERSAPAD },
223 { "IntelliMouse Explorer", MOUSE_MODEL_EXPLORER },
224 { "4D Mouse", MOUSE_MODEL_4D },
225 { "4D+ Mouse", MOUSE_MODEL_4DPLUS },
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_INPORT:
762 /* INPORT and BUS are the same... */
763 rodent.rtype = MOUSE_PROTO_BUS;
764 /* FALLTHROUGH */
765 case MOUSE_PROTO_BUS:
766 if (!rodent.portname)
767 rodent.portname = "/dev/mse0";
768 break;
770 case MOUSE_PROTO_PS2:
771 if (!rodent.portname)
772 rodent.portname = "/dev/psm0";
773 break;
775 default:
776 if (rodent.portname)
777 break;
778 warnx("no port name specified");
779 usage();
782 retry = 1;
783 if (strncmp(rodent.portname, "/dev/ums", 8) == 0) {
784 if (usbmodule() != 0)
785 retry = 5;
788 for (;;) {
789 if (setjmp(env) == 0) {
790 signal(SIGHUP, hup);
791 signal(SIGINT , cleanup);
792 signal(SIGQUIT, cleanup);
793 signal(SIGTERM, cleanup);
794 for (i = 0; i < retry; ++i) {
795 if (i > 0)
796 sleep(2);
797 rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK);
798 if (rodent.mfd != -1 || errno != ENOENT)
799 break;
801 if (rodent.mfd == -1)
802 logerr(1, "unable to open %s", rodent.portname);
803 if (r_identify() == MOUSE_PROTO_UNKNOWN) {
804 logwarnx("cannot determine mouse type on %s", rodent.portname);
805 close(rodent.mfd);
806 rodent.mfd = -1;
809 /* print some information */
810 if (identify != ID_NONE) {
811 if (identify == ID_ALL)
812 printf("%s %s %s %s\n",
813 rodent.portname, r_if(rodent.hw.iftype),
814 r_name(rodent.rtype), r_model(rodent.hw.model));
815 else if (identify & ID_PORT)
816 printf("%s\n", rodent.portname);
817 else if (identify & ID_IF)
818 printf("%s\n", r_if(rodent.hw.iftype));
819 else if (identify & ID_TYPE)
820 printf("%s\n", r_name(rodent.rtype));
821 else if (identify & ID_MODEL)
822 printf("%s\n", r_model(rodent.hw.model));
823 exit(0);
824 } else {
825 debug("port: %s interface: %s type: %s model: %s",
826 rodent.portname, r_if(rodent.hw.iftype),
827 r_name(rodent.rtype), r_model(rodent.hw.model));
830 if (rodent.mfd == -1) {
832 * We cannot continue because of error. Exit if the
833 * program has not become a daemon. Otherwise, block
834 * until the the user corrects the problem and issues SIGHUP.
836 if (!background)
837 exit(1);
838 sigpause(0);
841 r_init(); /* call init function */
842 moused();
845 if (rodent.mfd != -1)
846 close(rodent.mfd);
847 if (rodent.cfd != -1)
848 close(rodent.cfd);
849 rodent.mfd = rodent.cfd = -1;
851 /* NOT REACHED */
853 exit(0);
856 static int
857 usbmodule(void)
859 struct kld_file_stat fstat;
860 struct module_stat mstat;
861 int fileid, modid;
862 int loaded;
864 for (loaded = 0, fileid = kldnext(0); !loaded && fileid > 0;
865 fileid = kldnext(fileid)) {
866 fstat.version = sizeof(fstat);
867 if (kldstat(fileid, &fstat) < 0)
868 continue;
869 if (strncmp(fstat.name, "uhub/ums", 8) == 0) {
870 loaded = 1;
871 break;
873 for (modid = kldfirstmod(fileid); modid > 0;
874 modid = modfnext(modid)) {
875 mstat.version = sizeof(mstat);
876 if (modstat(modid, &mstat) < 0)
877 continue;
878 if (strncmp(mstat.name, "uhub/ums", 8) == 0) {
879 loaded = 1;
880 break;
884 if (!loaded) {
885 if (kldload("ums") != -1)
886 return 1;
887 if (errno != EEXIST)
888 logerr(1, "unable to load USB mouse driver");
890 return 0;
893 static void
894 moused(void)
896 struct mouse_info mouse;
897 mousestatus_t action0; /* original mouse action */
898 mousestatus_t action; /* interrim buffer */
899 mousestatus_t action2; /* mapped action */
900 struct timeval timeout;
901 fd_set fds;
902 u_char b;
903 FILE *fp;
904 int flags;
905 int c;
906 int i;
908 if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
909 logerr(1, "cannot open /dev/consolectl");
911 if (!nodaemon && !background) {
912 if (daemon(0, 0)) {
913 logerr(1, "failed to become a daemon");
914 } else {
915 background = TRUE;
916 fp = fopen(pidfile, "w");
917 if (fp != NULL) {
918 fprintf(fp, "%d\n", getpid());
919 fclose(fp);
924 /* clear mouse data */
925 bzero(&action0, sizeof(action0));
926 bzero(&action, sizeof(action));
927 bzero(&action2, sizeof(action2));
928 bzero(&mouse, sizeof(mouse));
929 mouse_button_state = S0;
930 gettimeofday(&mouse_button_state_tv, NULL);
931 mouse_move_delayed = 0;
932 for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
933 bstate[i].count = 0;
934 bstate[i].tv = mouse_button_state_tv;
936 for (i = 0; i < sizeof(zstate)/sizeof(zstate[0]); ++i) {
937 zstate[i].count = 0;
938 zstate[i].tv = mouse_button_state_tv;
941 /* choose which ioctl command to use */
942 mouse.operation = MOUSE_MOTION_EVENT;
943 extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
945 /* process mouse data */
946 timeout.tv_sec = 0;
947 timeout.tv_usec = 20000; /* 20 msec */
948 for (;;) {
950 FD_ZERO(&fds);
951 FD_SET(rodent.mfd, &fds);
952 if (rodent.mremsfd >= 0)
953 FD_SET(rodent.mremsfd, &fds);
954 if (rodent.mremcfd >= 0)
955 FD_SET(rodent.mremcfd, &fds);
957 c = select(FD_SETSIZE, &fds, NULL, NULL,
958 (rodent.flags & Emulate3Button) ? &timeout : NULL);
959 if (c < 0) { /* error */
960 logwarn("failed to read from mouse");
961 continue;
962 } else if (c == 0) { /* timeout */
963 /* assert(rodent.flags & Emulate3Button) */
964 action0.button = action0.obutton;
965 action0.dx = action0.dy = action0.dz = 0;
966 action0.flags = flags = 0;
967 if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) {
968 if (debug > 2)
969 debug("flags:%08x buttons:%08x obuttons:%08x",
970 action.flags, action.button, action.obutton);
971 } else {
972 action0.obutton = action0.button;
973 continue;
975 } else {
976 /* MouseRemote client connect/disconnect */
977 if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
978 mremote_clientchg(TRUE);
979 continue;
981 if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
982 mremote_clientchg(FALSE);
983 continue;
985 /* mouse movement */
986 if (read(rodent.mfd, &b, 1) == -1) {
987 if (errno == EWOULDBLOCK)
988 continue;
989 else
990 return;
992 if ((flags = r_protocol(b, &action0)) == 0)
993 continue;
995 if (rodent.flags & VirtualScroll) {
996 /* Allow middle button drags to scroll up and down */
997 if (action0.button == MOUSE_BUTTON2DOWN) {
998 if (scroll_state == SCROLL_NOTSCROLLING) {
999 scroll_state = SCROLL_PREPARE;
1000 debug("PREPARING TO SCROLL");
1002 debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1003 action.flags, action.button, action.obutton);
1004 } else {
1005 debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
1006 action.flags, action.button, action.obutton);
1008 /* This isn't a middle button down... move along... */
1009 if (scroll_state == SCROLL_SCROLLING) {
1011 * We were scrolling, someone let go of button 2.
1012 * Now turn autoscroll off.
1014 scroll_state = SCROLL_NOTSCROLLING;
1015 debug("DONE WITH SCROLLING / %d", scroll_state);
1016 } else if (scroll_state == SCROLL_PREPARE) {
1017 mousestatus_t newaction = action0;
1019 /* We were preparing to scroll, but we never moved... */
1020 r_timestamp(&action0);
1021 r_statetrans(&action0, &newaction,
1022 A(newaction.button & MOUSE_BUTTON1DOWN,
1023 action0.button & MOUSE_BUTTON3DOWN));
1025 /* Send middle down */
1026 newaction.button = MOUSE_BUTTON2DOWN;
1027 r_click(&newaction);
1029 /* Send middle up */
1030 r_timestamp(&newaction);
1031 newaction.obutton = newaction.button;
1032 newaction.button = action0.button;
1033 r_click(&newaction);
1038 r_timestamp(&action0);
1039 r_statetrans(&action0, &action,
1040 A(action0.button & MOUSE_BUTTON1DOWN,
1041 action0.button & MOUSE_BUTTON3DOWN));
1042 debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
1043 action.button, action.obutton);
1045 action0.obutton = action0.button;
1046 flags &= MOUSE_POSCHANGED;
1047 flags |= action.obutton ^ action.button;
1048 action.flags = flags;
1050 if (flags) { /* handler detected action */
1051 r_map(&action, &action2);
1052 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
1053 action2.button, action2.dx, action2.dy, action2.dz);
1055 if (rodent.flags & VirtualScroll) {
1057 * If *only* the middle button is pressed AND we are moving
1058 * the stick/trackpoint/nipple, scroll!
1060 if (scroll_state == SCROLL_PREPARE) {
1061 /* Ok, Set we're really scrolling now.... */
1062 if (action2.dy || action2.dx)
1063 scroll_state = SCROLL_SCROLLING;
1065 if (scroll_state == SCROLL_SCROLLING) {
1066 scroll_movement += action2.dy;
1067 debug("SCROLL: %d", scroll_movement);
1069 if (scroll_movement < -rodent.scrollthreshold) {
1070 /* Scroll down */
1071 action2.dz = -1;
1072 scroll_movement = 0;
1074 else if (scroll_movement > rodent.scrollthreshold) {
1075 /* Scroll up */
1076 action2.dz = 1;
1077 scroll_movement = 0;
1080 /* Don't move while scrolling */
1081 action2.dx = action2.dy = 0;
1085 if (extioctl) {
1086 /* Defer clicks until we aren't VirtualScroll'ing. */
1087 if (scroll_state == SCROLL_NOTSCROLLING)
1088 r_click(&action2);
1090 if (action2.flags & MOUSE_POSCHANGED) {
1091 mouse.operation = MOUSE_MOTION_EVENT;
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;
1096 if (debug < 2)
1097 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1099 } else {
1100 mouse.operation = MOUSE_ACTION;
1101 mouse.u.data.buttons = action2.button;
1102 mouse.u.data.x = action2.dx * rodent.accelx;
1103 mouse.u.data.y = action2.dy * rodent.accely;
1104 mouse.u.data.z = action2.dz;
1105 if (debug < 2)
1106 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1110 * If the Z axis movement is mapped to an imaginary physical
1111 * button, we need to cook up a corresponding button `up' event
1112 * after sending a button `down' event.
1114 if ((rodent.zmap[0] > 0) && (action.dz != 0)) {
1115 action.obutton = action.button;
1116 action.dx = action.dy = action.dz = 0;
1117 r_map(&action, &action2);
1118 debug("activity : buttons 0x%08x dx %d dy %d dz %d",
1119 action2.button, action2.dx, action2.dy, action2.dz);
1121 if (extioctl) {
1122 r_click(&action2);
1123 } else {
1124 mouse.operation = MOUSE_ACTION;
1125 mouse.u.data.buttons = action2.button;
1126 mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
1127 if (debug < 2)
1128 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
1133 /* NOT REACHED */
1136 static void
1137 hup(int sig)
1139 longjmp(env, 1);
1142 static void
1143 cleanup(int sig)
1145 if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM)
1146 unlink(_PATH_MOUSEREMOTE);
1147 exit(0);
1151 ** usage
1153 ** Complain, and free the CPU for more worthy tasks
1155 static void
1156 usage(void)
1158 fprintf(stderr, "%s\n%s\n%s\n%s\n",
1159 "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
1160 " [-V [-U threshold]] [-a X [,Y]] [-C threshold] [-m N=M] [-w N]",
1161 " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]] -p <port>",
1162 " moused [-d] -i <port|if|type|model|all> -p <port>");
1163 exit(1);
1167 * Output an error message to syslog or stderr as appropriate. If
1168 * `errnum' is non-zero, append its string form to the message.
1170 static void
1171 log_or_warn(int log_pri, int errnum, const char *fmt, ...)
1173 va_list ap;
1174 char buf[256];
1176 va_start(ap, fmt);
1177 vsnprintf(buf, sizeof(buf), fmt, ap);
1178 va_end(ap);
1179 if (errnum) {
1180 strlcat(buf, ": ", sizeof(buf));
1181 strlcat(buf, strerror(errnum), sizeof(buf));
1184 if (background)
1185 syslog(log_pri, "%s", buf);
1186 else
1187 warnx("%s", buf);
1191 ** Mouse interface code, courtesy of XFree86 3.1.2.
1193 ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm
1194 ** to clean, reformat and rationalise naming, it's quite possible that
1195 ** some things in here have been broken.
1197 ** I hope not 8)
1199 ** The following code is derived from a module marked :
1202 /* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */
1203 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28
1204 17:03:40 dawes Exp $ */
1207 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
1208 * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
1210 * Permission to use, copy, modify, distribute, and sell this software and its
1211 * documentation for any purpose is hereby granted without fee, provided that
1212 * the above copyright notice appear in all copies and that both that
1213 * copyright notice and this permission notice appear in supporting
1214 * documentation, and that the names of Thomas Roell and David Dawes not be
1215 * used in advertising or publicity pertaining to distribution of the
1216 * software without specific, written prior permission. Thomas Roell
1217 * and David Dawes makes no representations about the suitability of this
1218 * software for any purpose. It is provided "as is" without express or
1219 * implied warranty.
1221 * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
1222 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1223 * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY
1224 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
1225 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
1226 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1227 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1232 ** GlidePoint support from XFree86 3.2.
1233 ** Derived from the module:
1236 /* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
1237 /* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
1239 /* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
1240 static unsigned char proto[][7] = {
1241 /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */
1242 { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */
1243 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */
1244 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */
1245 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */
1246 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* MouseMan */
1247 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */
1248 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */
1249 { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */
1250 { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */
1251 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */
1252 { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */
1253 { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */
1254 { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */
1255 { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* X10 MouseRem */
1256 { 0x80, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* KIDSPAD */
1257 { 0xc3, 0xc0, 0x00, 0x00, 6, 0x00, 0xff }, /* VersaPad */
1258 { 0x00, 0x00, 0x00, 0x00, 1, 0x00, 0xff }, /* JogDial */
1259 #if notyet
1260 { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */
1261 #endif
1263 static unsigned char cur_proto[7];
1265 static int
1266 r_identify(void)
1268 char pnpbuf[256]; /* PnP identifier string may be up to 256 bytes long */
1269 pnpid_t pnpid;
1270 symtab_t *t;
1271 int level;
1272 int len;
1274 /* set the driver operation level, if applicable */
1275 if (rodent.level < 0)
1276 rodent.level = 1;
1277 ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level);
1278 rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0;
1281 * Interrogate the driver and get some intelligence on the device...
1282 * The following ioctl functions are not always supported by device
1283 * drivers. When the driver doesn't support them, we just trust the
1284 * user to supply valid information.
1286 rodent.hw.iftype = MOUSE_IF_UNKNOWN;
1287 rodent.hw.model = MOUSE_MODEL_GENERIC;
1288 ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw);
1290 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1291 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
1292 rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
1293 rodent.mode.rate = -1;
1294 rodent.mode.resolution = MOUSE_RES_UNKNOWN;
1295 rodent.mode.accelfactor = 0;
1296 rodent.mode.level = 0;
1297 if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) {
1298 if ((rodent.mode.protocol == MOUSE_PROTO_UNKNOWN)
1299 || (rodent.mode.protocol >= sizeof(proto)/sizeof(proto[0]))) {
1300 logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol);
1301 return MOUSE_PROTO_UNKNOWN;
1302 } else {
1303 /* INPORT and BUS are the same... */
1304 if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
1305 rodent.mode.protocol = MOUSE_PROTO_BUS;
1306 if (rodent.mode.protocol != rodent.rtype) {
1307 /* Hmm, the driver doesn't agree with the user... */
1308 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1309 logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1310 r_name(rodent.mode.protocol), r_name(rodent.rtype),
1311 r_name(rodent.mode.protocol));
1312 rodent.rtype = rodent.mode.protocol;
1313 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
1316 cur_proto[4] = rodent.mode.packetsize;
1317 cur_proto[0] = rodent.mode.syncmask[0]; /* header byte bit mask */
1318 cur_proto[1] = rodent.mode.syncmask[1]; /* header bit pattern */
1321 /* maybe this is a PnP mouse... */
1322 if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
1324 if (rodent.flags & NoPnP)
1325 return rodent.rtype;
1326 if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
1327 return rodent.rtype;
1329 debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
1330 pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
1331 pnpid.ncompat, pnpid.ncompat, pnpid.compat,
1332 pnpid.ndescription, pnpid.ndescription, pnpid.description);
1334 /* we have a valid PnP serial device ID */
1335 rodent.hw.iftype = MOUSE_IF_SERIAL;
1336 t = pnpproto(&pnpid);
1337 if (t != NULL) {
1338 rodent.mode.protocol = t->val;
1339 rodent.hw.model = t->val2;
1340 } else {
1341 rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
1343 if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
1344 rodent.mode.protocol = MOUSE_PROTO_BUS;
1346 /* make final adjustment */
1347 if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
1348 if (rodent.mode.protocol != rodent.rtype) {
1349 /* Hmm, the device doesn't agree with the user... */
1350 if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
1351 logwarnx("mouse type mismatch (%s != %s), %s is assumed",
1352 r_name(rodent.mode.protocol), r_name(rodent.rtype),
1353 r_name(rodent.mode.protocol));
1354 rodent.rtype = rodent.mode.protocol;
1355 bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
1360 debug("proto params: %02x %02x %02x %02x %d %02x %02x",
1361 cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
1362 cur_proto[4], cur_proto[5], cur_proto[6]);
1364 return rodent.rtype;
1367 static char *
1368 r_if(int iftype)
1370 char *s;
1372 s = gettokenname(rifs, iftype);
1373 return (s == NULL) ? "unknown" : s;
1376 static char *
1377 r_name(int type)
1379 return ((type == MOUSE_PROTO_UNKNOWN)
1380 || (type > sizeof(rnames)/sizeof(rnames[0]) - 1))
1381 ? "unknown" : rnames[type];
1384 static char *
1385 r_model(int model)
1387 char *s;
1389 s = gettokenname(rmodels, model);
1390 return (s == NULL) ? "unknown" : s;
1393 static void
1394 r_init(void)
1396 unsigned char buf[16]; /* scrach buffer */
1397 fd_set fds;
1398 char *s;
1399 char c;
1400 int i;
1403 ** This comment is a little out of context here, but it contains
1404 ** some useful information...
1405 ********************************************************************
1407 ** The following lines take care of the Logitech MouseMan protocols.
1409 ** NOTE: There are different versions of both MouseMan and TrackMan!
1410 ** Hence I add another protocol P_LOGIMAN, which the user can
1411 ** specify as MouseMan in his XF86Config file. This entry was
1412 ** formerly handled as a special case of P_MS. However, people
1413 ** who don't have the middle button problem, can still specify
1414 ** Microsoft and use P_MS.
1416 ** By default, these mice should use a 3 byte Microsoft protocol
1417 ** plus a 4th byte for the middle button. However, the mouse might
1418 ** have switched to a different protocol before we use it, so I send
1419 ** the proper sequence just in case.
1421 ** NOTE: - all commands to (at least the European) MouseMan have to
1422 ** be sent at 1200 Baud.
1423 ** - each command starts with a '*'.
1424 ** - whenever the MouseMan receives a '*', it will switch back
1425 ** to 1200 Baud. Hence I have to select the desired protocol
1426 ** first, then select the baud rate.
1428 ** The protocols supported by the (European) MouseMan are:
1429 ** - 5 byte packed binary protocol, as with the Mouse Systems
1430 ** mouse. Selected by sequence "*U".
1431 ** - 2 button 3 byte MicroSoft compatible protocol. Selected
1432 ** by sequence "*V".
1433 ** - 3 button 3+1 byte MicroSoft compatible protocol (default).
1434 ** Selected by sequence "*X".
1436 ** The following baud rates are supported:
1437 ** - 1200 Baud (default). Selected by sequence "*n".
1438 ** - 9600 Baud. Selected by sequence "*q".
1440 ** Selecting a sample rate is no longer supported with the MouseMan!
1441 ** Some additional lines in xf86Config.c take care of ill configured
1442 ** baud rates and sample rates. (The user will get an error.)
1445 switch (rodent.rtype) {
1447 case MOUSE_PROTO_LOGI:
1449 * The baud rate selection command must be sent at the current
1450 * baud rate; try all likely settings
1452 setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
1453 setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
1454 setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
1455 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1456 /* select MM series data format */
1457 write(rodent.mfd, "S", 1);
1458 setmousespeed(rodent.baudrate, rodent.baudrate,
1459 rodentcflags[MOUSE_PROTO_MM]);
1460 /* select report rate/frequency */
1461 if (rodent.rate <= 0) write(rodent.mfd, "O", 1);
1462 else if (rodent.rate <= 15) write(rodent.mfd, "J", 1);
1463 else if (rodent.rate <= 27) write(rodent.mfd, "K", 1);
1464 else if (rodent.rate <= 42) write(rodent.mfd, "L", 1);
1465 else if (rodent.rate <= 60) write(rodent.mfd, "R", 1);
1466 else if (rodent.rate <= 85) write(rodent.mfd, "M", 1);
1467 else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
1468 else write(rodent.mfd, "N", 1);
1469 break;
1471 case MOUSE_PROTO_LOGIMOUSEMAN:
1472 /* The command must always be sent at 1200 baud */
1473 setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
1474 write(rodent.mfd, "*X", 2);
1475 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1476 break;
1478 case MOUSE_PROTO_HITTAB:
1479 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1482 * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
1483 * The tablet must be configured to be in MM mode, NO parity,
1484 * Binary Format. xf86Info.sampleRate controls the sensativity
1485 * of the tablet. We only use this tablet for it's 4-button puck
1486 * so we don't run in "Absolute Mode"
1488 write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */
1489 usleep(50000);
1490 write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */
1491 usleep(50000);
1492 write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */
1493 usleep(50000);
1494 write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */
1495 usleep(50000);
1496 write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */
1497 usleep(50000);
1498 write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */
1499 usleep(50000);
1501 /* Resolution is in 'lines per inch' on the Hitachi tablet */
1502 if (rodent.resolution == MOUSE_RES_LOW) c = 'g';
1503 else if (rodent.resolution == MOUSE_RES_MEDIUMLOW) c = 'e';
1504 else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH) c = 'h';
1505 else if (rodent.resolution == MOUSE_RES_HIGH) c = 'd';
1506 else if (rodent.resolution <= 40) c = 'g';
1507 else if (rodent.resolution <= 100) c = 'd';
1508 else if (rodent.resolution <= 200) c = 'e';
1509 else if (rodent.resolution <= 500) c = 'h';
1510 else if (rodent.resolution <= 1000) c = 'j';
1511 else c = 'd';
1512 write(rodent.mfd, &c, 1);
1513 usleep(50000);
1515 write(rodent.mfd, "\021", 1); /* Resume DATA output */
1516 break;
1518 case MOUSE_PROTO_THINK:
1519 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1520 /* the PnP ID string may be sent again, discard it */
1521 usleep(200000);
1522 i = FREAD;
1523 ioctl(rodent.mfd, TIOCFLUSH, &i);
1524 /* send the command to initialize the beast */
1525 for (s = "E5E5"; *s; ++s) {
1526 write(rodent.mfd, s, 1);
1527 FD_ZERO(&fds);
1528 FD_SET(rodent.mfd, &fds);
1529 if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
1530 break;
1531 read(rodent.mfd, &c, 1);
1532 debug("%c", c);
1533 if (c != *s)
1534 break;
1536 break;
1538 case MOUSE_PROTO_JOGDIAL:
1539 break;
1540 case MOUSE_PROTO_MSC:
1541 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1542 if (rodent.flags & ClearDTR) {
1543 i = TIOCM_DTR;
1544 ioctl(rodent.mfd, TIOCMBIC, &i);
1546 if (rodent.flags & ClearRTS) {
1547 i = TIOCM_RTS;
1548 ioctl(rodent.mfd, TIOCMBIC, &i);
1550 break;
1552 case MOUSE_PROTO_SYSMOUSE:
1553 if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE)
1554 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1555 /* FALLTHROUGH */
1557 case MOUSE_PROTO_BUS:
1558 case MOUSE_PROTO_INPORT:
1559 case MOUSE_PROTO_PS2:
1560 if (rodent.rate >= 0)
1561 rodent.mode.rate = rodent.rate;
1562 if (rodent.resolution != MOUSE_RES_UNKNOWN)
1563 rodent.mode.resolution = rodent.resolution;
1564 ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
1565 break;
1567 case MOUSE_PROTO_X10MOUSEREM:
1568 mremote_serversetup();
1569 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1570 break;
1573 case MOUSE_PROTO_VERSAPAD:
1574 tcsendbreak(rodent.mfd, 0); /* send break for 400 msec */
1575 i = FREAD;
1576 ioctl(rodent.mfd, TIOCFLUSH, &i);
1577 for (i = 0; i < 7; ++i) {
1578 FD_ZERO(&fds);
1579 FD_SET(rodent.mfd, &fds);
1580 if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
1581 break;
1582 read(rodent.mfd, &c, 1);
1583 buf[i] = c;
1585 debug("%s\n", buf);
1586 if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r'))
1587 break;
1588 setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
1589 tcsendbreak(rodent.mfd, 0); /* send break for 400 msec again */
1590 for (i = 0; i < 7; ++i) {
1591 FD_ZERO(&fds);
1592 FD_SET(rodent.mfd, &fds);
1593 if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
1594 break;
1595 read(rodent.mfd, &c, 1);
1596 debug("%c", c);
1597 if (c != buf[i])
1598 break;
1600 i = FREAD;
1601 ioctl(rodent.mfd, TIOCFLUSH, &i);
1602 break;
1604 default:
1605 setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
1606 break;
1610 static int
1611 r_protocol(u_char rBuf, mousestatus_t *act)
1613 /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1614 static int butmapmss[4] = { /* Microsoft, MouseMan, GlidePoint,
1615 IntelliMouse, Thinking Mouse */
1617 MOUSE_BUTTON3DOWN,
1618 MOUSE_BUTTON1DOWN,
1619 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1621 static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
1622 Thinking Mouse */
1624 MOUSE_BUTTON4DOWN,
1625 MOUSE_BUTTON2DOWN,
1626 MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
1628 /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1629 static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
1630 MouseMan+ */
1632 MOUSE_BUTTON2DOWN,
1633 MOUSE_BUTTON4DOWN,
1634 MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
1636 /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
1637 static int butmapmsc[8] = { /* MouseSystems, MMSeries, Logitech,
1638 Bus, sysmouse */
1640 MOUSE_BUTTON3DOWN,
1641 MOUSE_BUTTON2DOWN,
1642 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1643 MOUSE_BUTTON1DOWN,
1644 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1645 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
1646 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
1648 /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
1649 static int butmapps2[8] = { /* PS/2 */
1651 MOUSE_BUTTON1DOWN,
1652 MOUSE_BUTTON3DOWN,
1653 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1654 MOUSE_BUTTON2DOWN,
1655 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
1656 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
1657 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
1659 /* for Hitachi tablet */
1660 static int butmaphit[8] = { /* MM HitTablet */
1662 MOUSE_BUTTON3DOWN,
1663 MOUSE_BUTTON2DOWN,
1664 MOUSE_BUTTON1DOWN,
1665 MOUSE_BUTTON4DOWN,
1666 MOUSE_BUTTON5DOWN,
1667 MOUSE_BUTTON6DOWN,
1668 MOUSE_BUTTON7DOWN,
1670 /* for serial VersaPad */
1671 static int butmapversa[8] = { /* VersaPad */
1674 MOUSE_BUTTON3DOWN,
1675 MOUSE_BUTTON3DOWN,
1676 MOUSE_BUTTON1DOWN,
1677 MOUSE_BUTTON1DOWN,
1678 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1679 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1681 /* for PS/2 VersaPad */
1682 static int butmapversaps2[8] = { /* VersaPad */
1684 MOUSE_BUTTON3DOWN,
1686 MOUSE_BUTTON3DOWN,
1687 MOUSE_BUTTON1DOWN,
1688 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1689 MOUSE_BUTTON1DOWN,
1690 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
1692 static int pBufP = 0;
1693 static unsigned char pBuf[8];
1694 static int prev_x, prev_y;
1695 static int on = FALSE;
1696 int x, y;
1698 debug("received char 0x%x",(int)rBuf);
1699 if (rodent.rtype == MOUSE_PROTO_KIDSPAD)
1700 return kidspad(rBuf, act) ;
1703 * Hack for resyncing: We check here for a package that is:
1704 * a) illegal (detected by wrong data-package header)
1705 * b) invalid (0x80 == -128 and that might be wrong for MouseSystems)
1706 * c) bad header-package
1708 * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of
1709 * -128 are allowed, but since they are very seldom we can easily
1710 * use them as package-header with no button pressed.
1711 * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore,
1712 * 0x80 is not valid as a header byte. For a PS/2 mouse we skip
1713 * checking data bytes.
1714 * For resyncing a PS/2 mouse we require the two most significant
1715 * bits in the header byte to be 0. These are the overflow bits,
1716 * and in case of an overflow we actually lose sync. Overflows
1717 * are very rare, however, and we quickly gain sync again after
1718 * an overflow condition. This is the best we can do. (Actually,
1719 * we could use bit 0x08 in the header byte for resyncing, since
1720 * that bit is supposed to be always on, but nobody told
1721 * Microsoft...)
1724 if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
1725 ((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
1727 pBufP = 0; /* skip package */
1730 if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
1731 return 0;
1733 /* is there an extra data byte? */
1734 if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
1737 * Hack for Logitech MouseMan Mouse - Middle button
1739 * Unfortunately this mouse has variable length packets: the standard
1740 * Microsoft 3 byte packet plus an optional 4th byte whenever the
1741 * middle button status changes.
1743 * We have already processed the standard packet with the movement
1744 * and button info. Now post an event message with the old status
1745 * of the left and right buttons and the updated middle button.
1749 * Even worse, different MouseMen and TrackMen differ in the 4th
1750 * byte: some will send 0x00/0x20, others 0x01/0x21, or even
1751 * 0x02/0x22, so I have to strip off the lower bits.
1753 * [JCH-96/01/21]
1754 * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
1755 * and it is activated by tapping the glidepad with the finger! 8^)
1756 * We map it to bit bit3, and the reverse map in xf86Events just has
1757 * to be extended so that it is identified as Button 4. The lower
1758 * half of the reverse-map may remain unchanged.
1762 * [KY-97/08/03]
1763 * Receive the fourth byte only when preceding three bytes have
1764 * been detected (pBufP >= cur_proto[4]). In the previous
1765 * versions, the test was pBufP == 0; thus, we may have mistakingly
1766 * received a byte even if we didn't see anything preceding
1767 * the byte.
1770 if ((rBuf & cur_proto[5]) != cur_proto[6]) {
1771 pBufP = 0;
1772 return 0;
1775 switch (rodent.rtype) {
1776 #if notyet
1777 case MOUSE_PROTO_MARIQUA:
1779 * This mouse has 16! buttons in addition to the standard
1780 * three of them. They return 0x10 though 0x1f in the
1781 * so-called `ten key' mode and 0x30 though 0x3f in the
1782 * `function key' mode. As there are only 31 bits for
1783 * button state (including the standard three), we ignore
1784 * the bit 0x20 and don't distinguish the two modes.
1786 act->dx = act->dy = act->dz = 0;
1787 act->obutton = act->button;
1788 rBuf &= 0x1f;
1789 act->button = (1 << (rBuf - 13))
1790 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1792 * FIXME: this is a button "down" event. There needs to be
1793 * a corresponding button "up" event... XXX
1795 break;
1796 #endif /* notyet */
1797 case MOUSE_PROTO_JOGDIAL:
1798 break;
1801 * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
1802 * always send the fourth byte, whereas the fourth byte is
1803 * optional for GlidePoint and ThinkingMouse. The fourth byte
1804 * is also optional for MouseMan+ and FirstMouse+ in their
1805 * native mode. It is always sent if they are in the IntelliMouse
1806 * compatible mode.
1808 case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse,
1809 MouseMan+ */
1810 act->dx = act->dy = 0;
1811 act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
1812 if ((act->dz >= 7) || (act->dz <= -7))
1813 act->dz = 0;
1814 act->obutton = act->button;
1815 act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
1816 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1817 break;
1819 default:
1820 act->dx = act->dy = act->dz = 0;
1821 act->obutton = act->button;
1822 act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
1823 | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
1824 break;
1827 act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
1828 | (act->obutton ^ act->button);
1829 pBufP = 0;
1830 return act->flags;
1833 if (pBufP >= cur_proto[4])
1834 pBufP = 0;
1835 pBuf[pBufP++] = rBuf;
1836 if (pBufP != cur_proto[4])
1837 return 0;
1840 * assembly full package
1843 debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
1844 cur_proto[4],
1845 pBuf[0], pBuf[1], pBuf[2], pBuf[3],
1846 pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
1848 act->dz = 0;
1849 act->obutton = act->button;
1850 switch (rodent.rtype)
1852 case MOUSE_PROTO_MS: /* Microsoft */
1853 case MOUSE_PROTO_LOGIMOUSEMAN: /* MouseMan/TrackMan */
1854 case MOUSE_PROTO_X10MOUSEREM: /* X10 MouseRemote */
1855 act->button = act->obutton & MOUSE_BUTTON4DOWN;
1856 if (rodent.flags & ChordMiddle)
1857 act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
1858 ? MOUSE_BUTTON2DOWN
1859 : butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1860 else
1861 act->button |= (act->obutton & MOUSE_BUTTON2DOWN)
1862 | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1864 /* Send X10 btn events to remote client (ensure -128-+127 range) */
1865 if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) &&
1866 ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) {
1867 if (rodent.mremcfd >= 0) {
1868 unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) |
1869 (pBuf[1] & 0x3F));
1870 write(rodent.mremcfd, &key, 1);
1872 return 0;
1875 act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
1876 act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
1877 break;
1879 case MOUSE_PROTO_GLIDEPOINT: /* GlidePoint */
1880 case MOUSE_PROTO_THINK: /* ThinkingMouse */
1881 case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse,
1882 MouseMan+ */
1883 act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
1884 | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
1885 act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
1886 act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
1887 break;
1889 case MOUSE_PROTO_MSC: /* MouseSystems Corp */
1890 #if notyet
1891 case MOUSE_PROTO_MARIQUA: /* Mariqua */
1892 #endif
1893 act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
1894 act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
1895 act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
1896 break;
1898 case MOUSE_PROTO_JOGDIAL: /* JogDial */
1899 if (rBuf == 0x6c)
1900 act->dz = -1;
1901 if (rBuf == 0x72)
1902 act->dz = 1;
1903 if (rBuf == 0x64)
1904 act->button = MOUSE_BUTTON1DOWN;
1905 if (rBuf == 0x75)
1906 act->button = 0;
1907 break;
1909 case MOUSE_PROTO_HITTAB: /* MM HitTablet */
1910 act->button = butmaphit[pBuf[0] & 0x07];
1911 act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1];
1912 act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2];
1913 break;
1915 case MOUSE_PROTO_MM: /* MM Series */
1916 case MOUSE_PROTO_LOGI: /* Logitech Mice */
1917 act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
1918 act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1];
1919 act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2];
1920 break;
1922 case MOUSE_PROTO_VERSAPAD: /* VersaPad */
1923 act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3];
1924 act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
1925 act->dx = act->dy = 0;
1926 if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) {
1927 on = FALSE;
1928 break;
1930 x = (pBuf[2] << 6) | pBuf[1];
1931 if (x & 0x800)
1932 x -= 0x1000;
1933 y = (pBuf[4] << 6) | pBuf[3];
1934 if (y & 0x800)
1935 y -= 0x1000;
1936 if (on) {
1937 act->dx = prev_x - x;
1938 act->dy = prev_y - y;
1939 } else {
1940 on = TRUE;
1942 prev_x = x;
1943 prev_y = y;
1944 break;
1946 case MOUSE_PROTO_BUS: /* Bus */
1947 case MOUSE_PROTO_INPORT: /* InPort */
1948 act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
1949 act->dx = (signed char)pBuf[1];
1950 act->dy = - (signed char)pBuf[2];
1951 break;
1953 case MOUSE_PROTO_PS2: /* PS/2 */
1954 act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
1955 act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ? pBuf[1] - 256 : pBuf[1];
1956 act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ? -(pBuf[2] - 256) : -pBuf[2];
1958 * Moused usually operates the psm driver at the operation level 1
1959 * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
1960 * The following code takes effect only when the user explicitly
1961 * requets the level 2 at which wheel movement and additional button
1962 * actions are encoded in model-dependent formats. At the level 0
1963 * the following code is no-op because the psm driver says the model
1964 * is MOUSE_MODEL_GENERIC.
1966 switch (rodent.hw.model) {
1967 case MOUSE_MODEL_EXPLORER:
1968 /* wheel and additional button data is in the fourth byte */
1969 act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG)
1970 ? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f);
1971 act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN)
1972 ? MOUSE_BUTTON4DOWN : 0;
1973 act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN)
1974 ? MOUSE_BUTTON5DOWN : 0;
1975 break;
1976 case MOUSE_MODEL_INTELLI:
1977 case MOUSE_MODEL_NET:
1978 /* wheel data is in the fourth byte */
1979 act->dz = (signed char)pBuf[3];
1980 if ((act->dz >= 7) || (act->dz <= -7))
1981 act->dz = 0;
1982 /* some compatible mice may have additional buttons */
1983 act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN)
1984 ? MOUSE_BUTTON4DOWN : 0;
1985 act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN)
1986 ? MOUSE_BUTTON5DOWN : 0;
1987 break;
1988 case MOUSE_MODEL_MOUSEMANPLUS:
1989 if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC)
1990 && (abs(act->dx) > 191)
1991 && MOUSE_PS2PLUS_CHECKBITS(pBuf)) {
1992 /* the extended data packet encodes button and wheel events */
1993 switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) {
1994 case 1:
1995 /* wheel data packet */
1996 act->dx = act->dy = 0;
1997 if (pBuf[2] & 0x80) {
1998 /* horizontal roller count - ignore it XXX*/
1999 } else {
2000 /* vertical roller count */
2001 act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG)
2002 ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
2004 act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
2005 ? MOUSE_BUTTON4DOWN : 0;
2006 act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN)
2007 ? MOUSE_BUTTON5DOWN : 0;
2008 break;
2009 case 2:
2010 /* this packet type is reserved by Logitech */
2012 * IBM ScrollPoint Mouse uses this packet type to
2013 * encode both vertical and horizontal scroll movement.
2015 act->dx = act->dy = 0;
2016 /* horizontal roller count */
2017 if (pBuf[2] & 0x0f)
2018 act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
2019 /* vertical roller count */
2020 if (pBuf[2] & 0xf0)
2021 act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
2022 #if 0
2023 /* vertical roller count */
2024 act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG)
2025 ? ((pBuf[2] >> 4) & 0x0f) - 16
2026 : ((pBuf[2] >> 4) & 0x0f);
2027 /* horizontal roller count */
2028 act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG)
2029 ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
2030 #endif
2031 break;
2032 case 0:
2033 /* device type packet - shouldn't happen */
2034 /* FALLTHROUGH */
2035 default:
2036 act->dx = act->dy = 0;
2037 act->button = act->obutton;
2038 debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n",
2039 MOUSE_PS2PLUS_PACKET_TYPE(pBuf),
2040 pBuf[0], pBuf[1], pBuf[2]);
2041 break;
2043 } else {
2044 /* preserve button states */
2045 act->button |= act->obutton & MOUSE_EXTBUTTONS;
2047 break;
2048 case MOUSE_MODEL_GLIDEPOINT:
2049 /* `tapping' action */
2050 act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
2051 break;
2052 case MOUSE_MODEL_NETSCROLL:
2053 /* three addtional bytes encode buttons and wheel events */
2054 act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
2055 ? MOUSE_BUTTON4DOWN : 0;
2056 act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN)
2057 ? MOUSE_BUTTON5DOWN : 0;
2058 act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
2059 break;
2060 case MOUSE_MODEL_THINK:
2061 /* the fourth button state in the first byte */
2062 act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
2063 break;
2064 case MOUSE_MODEL_VERSAPAD:
2065 act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS];
2066 act->button |=
2067 (pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
2068 act->dx = act->dy = 0;
2069 if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) {
2070 on = FALSE;
2071 break;
2073 x = ((pBuf[4] << 8) & 0xf00) | pBuf[1];
2074 if (x & 0x800)
2075 x -= 0x1000;
2076 y = ((pBuf[4] << 4) & 0xf00) | pBuf[2];
2077 if (y & 0x800)
2078 y -= 0x1000;
2079 if (on) {
2080 act->dx = prev_x - x;
2081 act->dy = prev_y - y;
2082 } else {
2083 on = TRUE;
2085 prev_x = x;
2086 prev_y = y;
2087 break;
2088 case MOUSE_MODEL_4D:
2089 act->dx = (pBuf[1] & 0x80) ? pBuf[1] - 256 : pBuf[1];
2090 act->dy = (pBuf[2] & 0x80) ? -(pBuf[2] - 256) : -pBuf[2];
2091 switch (pBuf[0] & MOUSE_4D_WHEELBITS) {
2092 case 0x10:
2093 act->dz = 1;
2094 break;
2095 case 0x30:
2096 act->dz = -1;
2097 break;
2098 case 0x40: /* 2nd wheel rolling right XXX */
2099 act->dz = 2;
2100 break;
2101 case 0xc0: /* 2nd wheel rolling left XXX */
2102 act->dz = -2;
2103 break;
2105 break;
2106 case MOUSE_MODEL_4DPLUS:
2107 if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) {
2108 act->dx = act->dy = 0;
2109 if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN)
2110 act->button |= MOUSE_BUTTON4DOWN;
2111 act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG)
2112 ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07);
2113 } else {
2114 /* preserve previous button states */
2115 act->button |= act->obutton & MOUSE_EXTBUTTONS;
2117 break;
2118 case MOUSE_MODEL_GENERIC:
2119 default:
2120 break;
2122 break;
2124 case MOUSE_PROTO_SYSMOUSE: /* sysmouse */
2125 act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
2126 act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
2127 act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
2128 if (rodent.level == 1) {
2129 act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1;
2130 act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
2132 break;
2134 default:
2135 return 0;
2138 * We don't reset pBufP here yet, as there may be an additional data
2139 * byte in some protocols. See above.
2142 /* has something changed? */
2143 act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
2144 | (act->obutton ^ act->button);
2146 return act->flags;
2149 static int
2150 r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans)
2152 int changed;
2153 int flags;
2155 a2->dx = a1->dx;
2156 a2->dy = a1->dy;
2157 a2->dz = a1->dz;
2158 a2->obutton = a2->button;
2159 a2->button = a1->button;
2160 a2->flags = a1->flags;
2161 changed = FALSE;
2163 if (rodent.flags & Emulate3Button) {
2164 if (debug > 2)
2165 debug("state:%d, trans:%d -> state:%d",
2166 mouse_button_state, trans,
2167 states[mouse_button_state].s[trans]);
2169 * Avoid re-ordering button and movement events. While a button
2170 * event is deferred, throw away up to BUTTON2_MAXMOVE movement
2171 * events to allow for mouse jitter. If more movement events
2172 * occur, then complete the deferred button events immediately.
2174 if ((a2->dx != 0 || a2->dy != 0) &&
2175 S_DELAYED(states[mouse_button_state].s[trans])) {
2176 if (++mouse_move_delayed > BUTTON2_MAXMOVE) {
2177 mouse_move_delayed = 0;
2178 mouse_button_state =
2179 states[mouse_button_state].s[A_TIMEOUT];
2180 changed = TRUE;
2181 } else
2182 a2->dx = a2->dy = 0;
2183 } else
2184 mouse_move_delayed = 0;
2185 if (mouse_button_state != states[mouse_button_state].s[trans])
2186 changed = TRUE;
2187 if (changed)
2188 gettimeofday(&mouse_button_state_tv, NULL);
2189 mouse_button_state = states[mouse_button_state].s[trans];
2190 a2->button &=
2191 ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN);
2192 a2->button &= states[mouse_button_state].mask;
2193 a2->button |= states[mouse_button_state].buttons;
2194 flags = a2->flags & MOUSE_POSCHANGED;
2195 flags |= a2->obutton ^ a2->button;
2196 if (flags & MOUSE_BUTTON2DOWN) {
2197 a2->flags = flags & MOUSE_BUTTON2DOWN;
2198 r_timestamp(a2);
2200 a2->flags = flags;
2202 return changed;
2205 /* phisical to logical button mapping */
2206 static int p2l[MOUSE_MAXBUTTON] = {
2207 MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
2208 MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
2209 0x00000100, 0x00000200, 0x00000400, 0x00000800,
2210 0x00001000, 0x00002000, 0x00004000, 0x00008000,
2211 0x00010000, 0x00020000, 0x00040000, 0x00080000,
2212 0x00100000, 0x00200000, 0x00400000, 0x00800000,
2213 0x01000000, 0x02000000, 0x04000000, 0x08000000,
2214 0x10000000, 0x20000000, 0x40000000,
2217 static char *
2218 skipspace(char *s)
2220 while(isspace(*s))
2221 ++s;
2222 return s;
2225 static int
2226 r_installmap(char *arg)
2228 int pbutton;
2229 int lbutton;
2230 char *s;
2232 while (*arg) {
2233 arg = skipspace(arg);
2234 s = arg;
2235 while (isdigit(*arg))
2236 ++arg;
2237 arg = skipspace(arg);
2238 if ((arg <= s) || (*arg != '='))
2239 return FALSE;
2240 lbutton = atoi(s);
2242 arg = skipspace(++arg);
2243 s = arg;
2244 while (isdigit(*arg))
2245 ++arg;
2246 if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
2247 return FALSE;
2248 pbutton = atoi(s);
2250 if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
2251 return FALSE;
2252 if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
2253 return FALSE;
2254 p2l[pbutton - 1] = 1 << (lbutton - 1);
2255 mstate[lbutton - 1] = &bstate[pbutton - 1];
2258 return TRUE;
2261 static void
2262 r_map(mousestatus_t *act1, mousestatus_t *act2)
2264 register int pb;
2265 register int pbuttons;
2266 int lbuttons;
2268 pbuttons = act1->button;
2269 lbuttons = 0;
2271 act2->obutton = act2->button;
2272 if (pbuttons & rodent.wmode) {
2273 pbuttons &= ~rodent.wmode;
2274 act1->dz = act1->dy;
2275 act1->dx = 0;
2276 act1->dy = 0;
2278 act2->dx = act1->dx;
2279 act2->dy = act1->dy;
2280 act2->dz = act1->dz;
2282 switch (rodent.zmap[0]) {
2283 case 0: /* do nothing */
2284 break;
2285 case MOUSE_XAXIS:
2286 if (act1->dz != 0) {
2287 act2->dx = act1->dz;
2288 act2->dz = 0;
2290 break;
2291 case MOUSE_YAXIS:
2292 if (act1->dz != 0) {
2293 act2->dy = act1->dz;
2294 act2->dz = 0;
2296 break;
2297 default: /* buttons */
2298 pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1]
2299 | rodent.zmap[2] | rodent.zmap[3]);
2300 if ((act1->dz < -1) && rodent.zmap[2]) {
2301 pbuttons |= rodent.zmap[2];
2302 zstate[2].count = 1;
2303 } else if (act1->dz < 0) {
2304 pbuttons |= rodent.zmap[0];
2305 zstate[0].count = 1;
2306 } else if ((act1->dz > 1) && rodent.zmap[3]) {
2307 pbuttons |= rodent.zmap[3];
2308 zstate[3].count = 1;
2309 } else if (act1->dz > 0) {
2310 pbuttons |= rodent.zmap[1];
2311 zstate[1].count = 1;
2313 act2->dz = 0;
2314 break;
2317 for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
2318 lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
2319 pbuttons >>= 1;
2321 act2->button = lbuttons;
2323 act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
2324 | (act2->obutton ^ act2->button);
2327 static void
2328 r_timestamp(mousestatus_t *act)
2330 struct timeval tv;
2331 struct timeval tv1;
2332 struct timeval tv2;
2333 struct timeval tv3;
2334 int button;
2335 int mask;
2336 int i;
2338 mask = act->flags & MOUSE_BUTTONS;
2339 #if 0
2340 if (mask == 0)
2341 return;
2342 #endif
2344 gettimeofday(&tv1, NULL);
2346 /* double click threshold */
2347 tv2.tv_sec = rodent.clickthreshold/1000;
2348 tv2.tv_usec = (rodent.clickthreshold%1000)*1000;
2349 timersub(&tv1, &tv2, &tv);
2350 debug("tv: %ld %ld", tv.tv_sec, tv.tv_usec);
2352 /* 3 button emulation timeout */
2353 tv2.tv_sec = rodent.button2timeout/1000;
2354 tv2.tv_usec = (rodent.button2timeout%1000)*1000;
2355 timersub(&tv1, &tv2, &tv3);
2357 button = MOUSE_BUTTON1DOWN;
2358 for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2359 if (mask & 1) {
2360 if (act->button & button) {
2361 /* the button is down */
2362 debug(" : %ld %ld",
2363 bstate[i].tv.tv_sec, bstate[i].tv.tv_usec);
2364 if (timercmp(&tv, &bstate[i].tv, >)) {
2365 bstate[i].count = 1;
2366 } else {
2367 ++bstate[i].count;
2369 bstate[i].tv = tv1;
2370 } else {
2371 /* the button is up */
2372 bstate[i].tv = tv1;
2374 } else {
2375 if (act->button & button) {
2376 /* the button has been down */
2377 if (timercmp(&tv3, &bstate[i].tv, >)) {
2378 bstate[i].count = 1;
2379 bstate[i].tv = tv1;
2380 act->flags |= button;
2381 debug("button %d timeout", i + 1);
2383 } else {
2384 /* the button has been up */
2387 button <<= 1;
2388 mask >>= 1;
2392 static int
2393 r_timeout(void)
2395 struct timeval tv;
2396 struct timeval tv1;
2397 struct timeval tv2;
2399 if (states[mouse_button_state].timeout)
2400 return TRUE;
2401 gettimeofday(&tv1, NULL);
2402 tv2.tv_sec = rodent.button2timeout/1000;
2403 tv2.tv_usec = (rodent.button2timeout%1000)*1000;
2404 timersub(&tv1, &tv2, &tv);
2405 return timercmp(&tv, &mouse_button_state_tv, >);
2408 static void
2409 r_click(mousestatus_t *act)
2411 struct mouse_info mouse;
2412 int button;
2413 int mask;
2414 int i;
2416 mask = act->flags & MOUSE_BUTTONS;
2417 if (mask == 0)
2418 return;
2420 button = MOUSE_BUTTON1DOWN;
2421 for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
2422 if (mask & 1) {
2423 debug("mstate[%d]->count:%d", i, mstate[i]->count);
2424 if (act->button & button) {
2425 /* the button is down */
2426 mouse.u.event.value = mstate[i]->count;
2427 } else {
2428 /* the button is up */
2429 mouse.u.event.value = 0;
2431 mouse.operation = MOUSE_BUTTON_EVENT;
2432 mouse.u.event.id = button;
2433 if (debug < 2)
2434 ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
2435 debug("button %d count %d", i + 1, mouse.u.event.value);
2437 button <<= 1;
2438 mask >>= 1;
2442 /* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
2443 /* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
2445 * Copyright 1993 by David Dawes <dawes@physics.su.oz.au>
2447 * Permission to use, copy, modify, distribute, and sell this software and its
2448 * documentation for any purpose is hereby granted without fee, provided that
2449 * the above copyright notice appear in all copies and that both that
2450 * copyright notice and this permission notice appear in supporting
2451 * documentation, and that the name of David Dawes
2452 * not be used in advertising or publicity pertaining to distribution of
2453 * the software without specific, written prior permission.
2454 * David Dawes makes no representations about the suitability of this
2455 * software for any purpose. It is provided "as is" without express or
2456 * implied warranty.
2458 * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO
2459 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
2460 * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR
2461 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
2462 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
2463 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2464 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2469 static void
2470 setmousespeed(int old, int new, unsigned cflag)
2472 struct termios tty;
2473 char *c;
2475 if (tcgetattr(rodent.mfd, &tty) < 0)
2477 logwarn("unable to get status of mouse fd");
2478 return;
2481 tty.c_iflag = IGNBRK | IGNPAR;
2482 tty.c_oflag = 0;
2483 tty.c_lflag = 0;
2484 tty.c_cflag = (tcflag_t)cflag;
2485 tty.c_cc[VTIME] = 0;
2486 tty.c_cc[VMIN] = 1;
2488 switch (old)
2490 case 9600:
2491 cfsetispeed(&tty, B9600);
2492 cfsetospeed(&tty, B9600);
2493 break;
2494 case 4800:
2495 cfsetispeed(&tty, B4800);
2496 cfsetospeed(&tty, B4800);
2497 break;
2498 case 2400:
2499 cfsetispeed(&tty, B2400);
2500 cfsetospeed(&tty, B2400);
2501 break;
2502 case 1200:
2503 default:
2504 cfsetispeed(&tty, B1200);
2505 cfsetospeed(&tty, B1200);
2508 if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
2510 logwarn("unable to set status of mouse fd");
2511 return;
2514 switch (new)
2516 case 9600:
2517 c = "*q";
2518 cfsetispeed(&tty, B9600);
2519 cfsetospeed(&tty, B9600);
2520 break;
2521 case 4800:
2522 c = "*p";
2523 cfsetispeed(&tty, B4800);
2524 cfsetospeed(&tty, B4800);
2525 break;
2526 case 2400:
2527 c = "*o";
2528 cfsetispeed(&tty, B2400);
2529 cfsetospeed(&tty, B2400);
2530 break;
2531 case 1200:
2532 default:
2533 c = "*n";
2534 cfsetispeed(&tty, B1200);
2535 cfsetospeed(&tty, B1200);
2538 if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
2539 || rodent.rtype == MOUSE_PROTO_LOGI)
2541 if (write(rodent.mfd, c, 2) != 2)
2543 logwarn("unable to write to mouse fd");
2544 return;
2547 usleep(100000);
2549 if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
2550 logwarn("unable to set status of mouse fd");
2554 * PnP COM device support
2556 * It's a simplistic implementation, but it works :-)
2557 * KY, 31/7/97.
2561 * Try to elicit a PnP ID as described in
2562 * Microsoft, Hayes: "Plug and Play External COM Device Specification,
2563 * rev 1.00", 1995.
2565 * The routine does not fully implement the COM Enumerator as par Section
2566 * 2.1 of the document. In particular, we don't have idle state in which
2567 * the driver software monitors the com port for dynamic connection or
2568 * removal of a device at the port, because `moused' simply quits if no
2569 * device is found.
2571 * In addition, as PnP COM device enumeration procedure slightly has
2572 * changed since its first publication, devices which follow earlier
2573 * revisions of the above spec. may fail to respond if the rev 1.0
2574 * procedure is used. XXX
2576 static int
2577 pnpwakeup1(void)
2579 struct timeval timeout;
2580 fd_set fds;
2581 int i;
2584 * This is the procedure described in rev 1.0 of PnP COM device spec.
2585 * Unfortunately, some devices which comform to earlier revisions of
2586 * the spec gets confused and do not return the ID string...
2588 debug("PnP COM device rev 1.0 probe...");
2590 /* port initialization (2.1.2) */
2591 ioctl(rodent.mfd, TIOCMGET, &i);
2592 i |= TIOCM_DTR; /* DTR = 1 */
2593 i &= ~TIOCM_RTS; /* RTS = 0 */
2594 ioctl(rodent.mfd, TIOCMSET, &i);
2595 usleep(240000);
2598 * The PnP COM device spec. dictates that the mouse must set DSR
2599 * in response to DTR (by hardware or by software) and that if DSR is
2600 * not asserted, the host computer should think that there is no device
2601 * at this serial port. But some mice just don't do that...
2603 ioctl(rodent.mfd, TIOCMGET, &i);
2604 debug("modem status 0%o", i);
2605 if ((i & TIOCM_DSR) == 0)
2606 return FALSE;
2608 /* port setup, 1st phase (2.1.3) */
2609 setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
2610 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
2611 ioctl(rodent.mfd, TIOCMBIC, &i);
2612 usleep(240000);
2613 i = TIOCM_DTR; /* DTR = 1, RTS = 0 */
2614 ioctl(rodent.mfd, TIOCMBIS, &i);
2615 usleep(240000);
2617 /* wait for response, 1st phase (2.1.4) */
2618 i = FREAD;
2619 ioctl(rodent.mfd, TIOCFLUSH, &i);
2620 i = TIOCM_RTS; /* DTR = 1, RTS = 1 */
2621 ioctl(rodent.mfd, TIOCMBIS, &i);
2623 /* try to read something */
2624 FD_ZERO(&fds);
2625 FD_SET(rodent.mfd, &fds);
2626 timeout.tv_sec = 0;
2627 timeout.tv_usec = 240000;
2628 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2629 debug("pnpwakeup1(): valid response in first phase.");
2630 return TRUE;
2633 /* port setup, 2nd phase (2.1.5) */
2634 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
2635 ioctl(rodent.mfd, TIOCMBIC, &i);
2636 usleep(240000);
2638 /* wait for respose, 2nd phase (2.1.6) */
2639 i = FREAD;
2640 ioctl(rodent.mfd, TIOCFLUSH, &i);
2641 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
2642 ioctl(rodent.mfd, TIOCMBIS, &i);
2644 /* try to read something */
2645 FD_ZERO(&fds);
2646 FD_SET(rodent.mfd, &fds);
2647 timeout.tv_sec = 0;
2648 timeout.tv_usec = 240000;
2649 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2650 debug("pnpwakeup1(): valid response in second phase.");
2651 return TRUE;
2654 return FALSE;
2657 static int
2658 pnpwakeup2(void)
2660 struct timeval timeout;
2661 fd_set fds;
2662 int i;
2665 * This is a simplified procedure; it simply toggles RTS.
2667 debug("alternate probe...");
2669 ioctl(rodent.mfd, TIOCMGET, &i);
2670 i |= TIOCM_DTR; /* DTR = 1 */
2671 i &= ~TIOCM_RTS; /* RTS = 0 */
2672 ioctl(rodent.mfd, TIOCMSET, &i);
2673 usleep(240000);
2675 setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
2677 /* wait for respose */
2678 i = FREAD;
2679 ioctl(rodent.mfd, TIOCFLUSH, &i);
2680 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
2681 ioctl(rodent.mfd, TIOCMBIS, &i);
2683 /* try to read something */
2684 FD_ZERO(&fds);
2685 FD_SET(rodent.mfd, &fds);
2686 timeout.tv_sec = 0;
2687 timeout.tv_usec = 240000;
2688 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
2689 debug("pnpwakeup2(): valid response.");
2690 return TRUE;
2693 return FALSE;
2696 static int
2697 pnpgets(char *buf)
2699 struct timeval timeout;
2700 fd_set fds;
2701 int begin;
2702 int i;
2703 char c;
2705 if (!pnpwakeup1() && !pnpwakeup2()) {
2707 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2708 * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
2709 * assuming there is something at the port even if it didn't
2710 * respond to the PnP enumeration procedure.
2712 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
2713 ioctl(rodent.mfd, TIOCMBIS, &i);
2714 return 0;
2717 /* collect PnP COM device ID (2.1.7) */
2718 begin = -1;
2719 i = 0;
2720 usleep(240000); /* the mouse must send `Begin ID' within 200msec */
2721 while (read(rodent.mfd, &c, 1) == 1) {
2722 /* we may see "M", or "M3..." before `Begin ID' */
2723 buf[i++] = c;
2724 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
2725 debug("begin-id %02x", c);
2726 begin = i - 1;
2727 break;
2729 debug("%c %02x", c, c);
2730 if (i >= 256)
2731 break;
2733 if (begin < 0) {
2734 /* we haven't seen `Begin ID' in time... */
2735 goto connect_idle;
2738 ++c; /* make it `End ID' */
2739 for (;;) {
2740 FD_ZERO(&fds);
2741 FD_SET(rodent.mfd, &fds);
2742 timeout.tv_sec = 0;
2743 timeout.tv_usec = 240000;
2744 if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
2745 break;
2747 read(rodent.mfd, &buf[i], 1);
2748 if (buf[i++] == c) /* End ID */
2749 break;
2750 if (i >= 256)
2751 break;
2753 if (begin > 0) {
2754 i -= begin;
2755 bcopy(&buf[begin], &buf[0], i);
2757 /* string may not be human readable... */
2758 debug("len:%d, '%-*.*s'", i, i, i, buf);
2760 if (buf[i - 1] == c)
2761 return i; /* a valid PnP string */
2764 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
2765 * in idle state. But, `moused' shall leave the modem control lines
2766 * as they are. See above.
2768 connect_idle:
2770 /* we may still have something in the buffer */
2771 return ((i > 0) ? i : 0);
2774 static int
2775 pnpparse(pnpid_t *id, char *buf, int len)
2777 char s[3];
2778 int offset;
2779 int sum = 0;
2780 int i, j;
2782 id->revision = 0;
2783 id->eisaid = NULL;
2784 id->serial = NULL;
2785 id->class = NULL;
2786 id->compat = NULL;
2787 id->description = NULL;
2788 id->neisaid = 0;
2789 id->nserial = 0;
2790 id->nclass = 0;
2791 id->ncompat = 0;
2792 id->ndescription = 0;
2794 if ((buf[0] != 0x28) && (buf[0] != 0x08)) {
2795 /* non-PnP mice */
2796 switch(buf[0]) {
2797 default:
2798 return FALSE;
2799 case 'M': /* Microsoft */
2800 id->eisaid = "PNP0F01";
2801 break;
2802 case 'H': /* MouseSystems */
2803 id->eisaid = "PNP0F04";
2804 break;
2806 id->neisaid = strlen(id->eisaid);
2807 id->class = "MOUSE";
2808 id->nclass = strlen(id->class);
2809 debug("non-PnP mouse '%c'", buf[0]);
2810 return TRUE;
2813 /* PnP mice */
2814 offset = 0x28 - buf[0];
2816 /* calculate checksum */
2817 for (i = 0; i < len - 3; ++i) {
2818 sum += buf[i];
2819 buf[i] += offset;
2821 sum += buf[len - 1];
2822 for (; i < len; ++i)
2823 buf[i] += offset;
2824 debug("PnP ID string: '%*.*s'", len, len, buf);
2826 /* revision */
2827 buf[1] -= offset;
2828 buf[2] -= offset;
2829 id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
2830 debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
2832 /* EISA vender and product ID */
2833 id->eisaid = &buf[3];
2834 id->neisaid = 7;
2836 /* option strings */
2837 i = 10;
2838 if (buf[i] == '\\') {
2839 /* device serial # */
2840 for (j = ++i; i < len; ++i) {
2841 if (buf[i] == '\\')
2842 break;
2844 if (i >= len)
2845 i -= 3;
2846 if (i - j == 8) {
2847 id->serial = &buf[j];
2848 id->nserial = 8;
2851 if (buf[i] == '\\') {
2852 /* PnP class */
2853 for (j = ++i; i < len; ++i) {
2854 if (buf[i] == '\\')
2855 break;
2857 if (i >= len)
2858 i -= 3;
2859 if (i > j + 1) {
2860 id->class = &buf[j];
2861 id->nclass = i - j;
2864 if (buf[i] == '\\') {
2865 /* compatible driver */
2866 for (j = ++i; i < len; ++i) {
2867 if (buf[i] == '\\')
2868 break;
2871 * PnP COM spec prior to v0.96 allowed '*' in this field,
2872 * it's not allowed now; just igore it.
2874 if (buf[j] == '*')
2875 ++j;
2876 if (i >= len)
2877 i -= 3;
2878 if (i > j + 1) {
2879 id->compat = &buf[j];
2880 id->ncompat = i - j;
2883 if (buf[i] == '\\') {
2884 /* product description */
2885 for (j = ++i; i < len; ++i) {
2886 if (buf[i] == ';')
2887 break;
2889 if (i >= len)
2890 i -= 3;
2891 if (i > j + 1) {
2892 id->description = &buf[j];
2893 id->ndescription = i - j;
2897 /* checksum exists if there are any optional fields */
2898 if ((id->nserial > 0) || (id->nclass > 0)
2899 || (id->ncompat > 0) || (id->ndescription > 0)) {
2900 debug("PnP checksum: 0x%X", sum);
2901 sprintf(s, "%02X", sum & 0x0ff);
2902 if (strncmp(s, &buf[len - 3], 2) != 0) {
2903 #if 0
2905 * I found some mice do not comply with the PnP COM device
2906 * spec regarding checksum... XXX
2908 logwarnx("PnP checksum error", 0);
2909 return FALSE;
2910 #endif
2914 return TRUE;
2917 static symtab_t *
2918 pnpproto(pnpid_t *id)
2920 symtab_t *t;
2921 int i, j;
2923 if (id->nclass > 0)
2924 if (strncmp(id->class, "MOUSE", id->nclass) != 0 &&
2925 strncmp(id->class, "TABLET", id->nclass) != 0)
2926 /* this is not a mouse! */
2927 return NULL;
2929 if (id->neisaid > 0) {
2930 t = gettoken(pnpprod, id->eisaid, id->neisaid);
2931 if (t->val != MOUSE_PROTO_UNKNOWN)
2932 return t;
2936 * The 'Compatible drivers' field may contain more than one
2937 * ID separated by ','.
2939 if (id->ncompat <= 0)
2940 return NULL;
2941 for (i = 0; i < id->ncompat; ++i) {
2942 for (j = i; id->compat[i] != ','; ++i)
2943 if (i >= id->ncompat)
2944 break;
2945 if (i > j) {
2946 t = gettoken(pnpprod, id->compat + j, i - j);
2947 if (t->val != MOUSE_PROTO_UNKNOWN)
2948 return t;
2952 return NULL;
2955 /* name/val mapping */
2957 static symtab_t *
2958 gettoken(symtab_t *tab, char *s, int len)
2960 int i;
2962 for (i = 0; tab[i].name != NULL; ++i) {
2963 if (strncmp(tab[i].name, s, len) == 0)
2964 break;
2966 return &tab[i];
2969 static char *
2970 gettokenname(symtab_t *tab, int val)
2972 int i;
2974 for (i = 0; tab[i].name != NULL; ++i) {
2975 if (tab[i].val == val)
2976 return tab[i].name;
2978 return NULL;
2983 * code to read from the Genius Kidspad tablet.
2985 The tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005,
2986 and to pre-pnp probes (RTS toggle) with 'T' (tablet ?)
2987 9600, 8 bit, parity odd.
2989 The tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains
2990 the proximity, tip and button info:
2991 (byte0 & 0x1) true = tip pressed
2992 (byte0 & 0x2) true = button pressed
2993 (byte0 & 0x40) false = pen in proximity of tablet.
2995 The next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid).
2997 Only absolute coordinates are returned, so we use the following approach:
2998 we store the last coordinates sent when the pen went out of the tablet,
3004 typedef enum {
3005 S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP
3006 } k_status ;
3008 static int
3009 kidspad(u_char rxc, mousestatus_t *act)
3011 static int buf[5];
3012 static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ;
3013 static k_status status = S_IDLE ;
3014 static struct timeval old, now ;
3016 int x, y ;
3018 if (buflen > 0 && (rxc & 0x80)) {
3019 fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc);
3020 buflen = 0 ;
3022 if (buflen == 0 && (rxc & 0xb8) != 0xb8) {
3023 fprintf(stderr, "invalid code 0 0x%x\n", rxc);
3024 return 0 ; /* invalid code, no action */
3026 buf[buflen++] = rxc ;
3027 if (buflen < 5)
3028 return 0 ;
3030 buflen = 0 ; /* for next time... */
3032 x = buf[1]+128*(buf[2] - 7) ;
3033 if (x < 0) x = 0 ;
3034 y = 28*128 - (buf[3] + 128* (buf[4] - 7)) ;
3035 if (y < 0) y = 0 ;
3037 x /= 8 ;
3038 y /= 8 ;
3040 act->flags = 0 ;
3041 act->obutton = act->button ;
3042 act->dx = act->dy = act->dz = 0 ;
3043 gettimeofday(&now, NULL);
3044 if (buf[0] & 0x40) /* pen went out of reach */
3045 status = S_IDLE ;
3046 else if (status == S_IDLE) { /* pen is newly near the tablet */
3047 act->flags |= MOUSE_POSCHANGED ; /* force update */
3048 status = S_PROXY ;
3049 x_prev = x ;
3050 y_prev = y ;
3052 old = now ;
3053 act->dx = x - x_prev ;
3054 act->dy = y - y_prev ;
3055 if (act->dx || act->dy)
3056 act->flags |= MOUSE_POSCHANGED ;
3057 x_prev = x ;
3058 y_prev = y ;
3059 if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */
3060 act->button = 0 ;
3061 if (buf[0] & 0x01) /* tip pressed */
3062 act->button |= MOUSE_BUTTON1DOWN ;
3063 if (buf[0] & 0x02) /* button pressed */
3064 act->button |= MOUSE_BUTTON2DOWN ;
3065 act->flags |= MOUSE_BUTTONSCHANGED ;
3067 b_prev = buf[0] ;
3068 return act->flags ;
3071 static void
3072 mremote_serversetup(void)
3074 struct sockaddr_un ad;
3076 /* Open a UNIX domain stream socket to listen for mouse remote clients */
3077 unlink(_PATH_MOUSEREMOTE);
3079 if ((rodent.mremsfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
3080 logerrx(1, "unable to create unix domain socket %s",_PATH_MOUSEREMOTE);
3082 umask(0111);
3084 bzero(&ad, sizeof(ad));
3085 ad.sun_family = AF_UNIX;
3086 strcpy(ad.sun_path, _PATH_MOUSEREMOTE);
3087 #ifndef SUN_LEN
3088 #define SUN_LEN(unp) (((char *)(unp)->sun_path - (char *)(unp)) + \
3089 strlen((unp)->path))
3090 #endif
3091 if (bind(rodent.mremsfd, (struct sockaddr *) &ad, SUN_LEN(&ad)) < 0)
3092 logerrx(1, "unable to bind unix domain socket %s", _PATH_MOUSEREMOTE);
3094 listen(rodent.mremsfd, 1);
3097 static void
3098 mremote_clientchg(int add)
3100 struct sockaddr_un ad;
3101 int ad_len, fd;
3103 if (rodent.rtype != MOUSE_PROTO_X10MOUSEREM)
3104 return;
3106 if (add) {
3107 /* Accept client connection, if we don't already have one */
3108 ad_len = sizeof(ad);
3109 fd = accept(rodent.mremsfd, (struct sockaddr *) &ad, &ad_len);
3110 if (fd < 0)
3111 logwarnx("failed accept on mouse remote socket");
3113 if (rodent.mremcfd < 0) {
3114 rodent.mremcfd = fd;
3115 debug("remote client connect...accepted");
3117 else {
3118 close(fd);
3119 debug("another remote client connect...disconnected");
3122 else {
3123 /* Client disconnected */
3124 debug("remote client disconnected");
3125 close(rodent.mremcfd);
3126 rodent.mremcfd = -1;