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