xref: /openbsd/usr.sbin/wsmoused/wsmoused.c (revision 29f11fc7)
1*29f11fc7Sfgsch /* $OpenBSD: wsmoused.c,v 1.2 2001/08/12 17:53:16 fgsch Exp $ */
2673a75b7Saaron 
3673a75b7Saaron /*
4673a75b7Saaron  * Copyright (c) 2001 Jean-Baptiste Marchand, Julien Montagne and Jerome Verdon
5673a75b7Saaron  *
6673a75b7Saaron  * Copyright (c) 1998 by Kazutaka Yokota
7673a75b7Saaron  *
8673a75b7Saaron  * Copyright (c) 1995 Michael Smith
9673a75b7Saaron  *
10673a75b7Saaron  * Copyright (c) 1993 by David Dawes <dawes@xfree86.org>
11673a75b7Saaron  *
12673a75b7Saaron  * Copyright (c) 1990,91 by Thomas Roell, Dinkelscherben, Germany.
13673a75b7Saaron  *
14673a75b7Saaron  * All rights reserved.
15673a75b7Saaron  *
16673a75b7Saaron  * Most of this code was taken from the FreeBSD moused daemon, written by
17673a75b7Saaron  * Michael Smith. The FreeBSD moused daemon already contained code from the
18673a75b7Saaron  * Xfree Project, written by David Dawes and Thomas Roell and Kazutaka Yokota.
19673a75b7Saaron  *
20673a75b7Saaron  * Adaptation to OpenBSD was done by Jean-Baptiste Marchand, Julien Montagne
21673a75b7Saaron  * and Jerome Verdon.
22673a75b7Saaron  *
23673a75b7Saaron  * Redistribution and use in source and binary forms, with or without
24673a75b7Saaron  * modification, are permitted provided that the following conditions
25673a75b7Saaron  * are met:
26673a75b7Saaron  * 1. Redistributions of source code must retain the above copyright
27673a75b7Saaron  *    notice, this list of conditions and the following disclaimer.
28673a75b7Saaron  * 2. Redistributions in binary form must reproduce the above copyright
29673a75b7Saaron  *    notice, this list of conditions and the following disclaimer in the
30673a75b7Saaron  *    documentation and/or other materials provided with the distribution.
31673a75b7Saaron  * 3. All advertising materials mentioning features or use of this software
32673a75b7Saaron  *    must display the following acknowledgement:
33673a75b7Saaron  *	This product includes software developed by
34673a75b7Saaron  *      David Dawes, Jean-Baptiste Marchand, Julien Montagne, Thomas Roell,
35673a75b7Saaron  *      Michael Smith, Jerome Verdon and Kazutaka Yokota.
36673a75b7Saaron  * 4. The name authors may not be used to endorse or promote products
37673a75b7Saaron  *    derived from this software without specific prior written permission.
38673a75b7Saaron  *
39673a75b7Saaron  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
40673a75b7Saaron  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41673a75b7Saaron  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
42673a75b7Saaron  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
43673a75b7Saaron  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44673a75b7Saaron  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45673a75b7Saaron  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46673a75b7Saaron  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47673a75b7Saaron  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
48673a75b7Saaron  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49673a75b7Saaron  *
50673a75b7Saaron  *
51673a75b7Saaron  */
52673a75b7Saaron 
53673a75b7Saaron #include <sys/ioctl.h>
54673a75b7Saaron #include <sys/types.h>
55673a75b7Saaron #include <sys/time.h>
56673a75b7Saaron #include <sys/tty.h>
57673a75b7Saaron #include <dev/wscons/wsconsio.h>
58673a75b7Saaron 
59673a75b7Saaron #include <ctype.h>
60673a75b7Saaron #include <err.h>
61673a75b7Saaron #include <errno.h>
62673a75b7Saaron #include <fcntl.h>
63673a75b7Saaron #include <unistd.h>
64673a75b7Saaron #include <setjmp.h>
65673a75b7Saaron #include <signal.h>
66673a75b7Saaron #include <poll.h>
67673a75b7Saaron #include <stdio.h>
68673a75b7Saaron #include <string.h>
69673a75b7Saaron #include <stdlib.h>
70673a75b7Saaron #include <syslog.h>
71673a75b7Saaron #include <varargs.h>
72673a75b7Saaron 
73673a75b7Saaron #include "mouse_protocols.h"
74673a75b7Saaron #include "wsmoused.h"
75673a75b7Saaron 
76673a75b7Saaron extern char *optarg;
77673a75b7Saaron extern int optind;
78673a75b7Saaron extern char *__progname;
79673a75b7Saaron extern char *mouse_names[];
80673a75b7Saaron 
81673a75b7Saaron int debug = 0;
82673a75b7Saaron int nodaemon = FALSE;
83673a75b7Saaron int background = FALSE;
84673a75b7Saaron int identify = FALSE;
85673a75b7Saaron char *pidfile = "/var/run/wsmoused.pid";
86673a75b7Saaron static sigjmp_buf env;
87673a75b7Saaron 
88673a75b7Saaron mouse_t mouse = {
89673a75b7Saaron     flags : 0,
90673a75b7Saaron     portname : NULL,
91673a75b7Saaron     proto : P_UNKNOWN,
92673a75b7Saaron     baudrate : 1200,
93673a75b7Saaron     old_baudrate : 1200,
94673a75b7Saaron     rate : MOUSE_RATE_UNKNOWN,
95673a75b7Saaron     resolution : MOUSE_RES_UNKNOWN,
96673a75b7Saaron     zmap: 0,
97673a75b7Saaron     wmode: 0,
98673a75b7Saaron     mfd : -1,
99673a75b7Saaron     clickthreshold : 500,	/* 0.5 sec */
100673a75b7Saaron };
101673a75b7Saaron 
102673a75b7Saaron /* identify the type of a wsmouse supported mouse */
103673a75b7Saaron void
104673a75b7Saaron wsmouse_identify(void)
105673a75b7Saaron {
106673a75b7Saaron 	unsigned int type;
107673a75b7Saaron 
108673a75b7Saaron 	if (mouse.mfd) {
109673a75b7Saaron 		ioctl(mouse.mfd, WSMOUSEIO_GTYPE, &type);
110673a75b7Saaron 	       	printf("wsmouse supported mouse: ");
111673a75b7Saaron 		switch (type) {
112673a75b7Saaron 			case WSMOUSE_TYPE_VSXXX:
113673a75b7Saaron 				printf("DEC serial\n");
114673a75b7Saaron 				break;
115673a75b7Saaron 			case WSMOUSE_TYPE_PS2:
116673a75b7Saaron 				printf("PS/2 compatible\n");
117673a75b7Saaron 				break;
118673a75b7Saaron 			case WSMOUSE_TYPE_USB:
119673a75b7Saaron 				printf("USB \n");
120673a75b7Saaron 				break;
121673a75b7Saaron 			case WSMOUSE_TYPE_LMS:
122673a75b7Saaron 				printf("Logitech busmouse\n");
123673a75b7Saaron 				break;
124673a75b7Saaron 			case WSMOUSE_TYPE_MMS:
125673a75b7Saaron 				printf("Microsoft InPort mouse\n");
126673a75b7Saaron 				break;
127673a75b7Saaron 			case WSMOUSE_TYPE_TPANEL:
128673a75b7Saaron 				printf("Generic Touch Panel\n");
129673a75b7Saaron 				break;
130673a75b7Saaron 			case WSMOUSE_TYPE_NEXT:
131673a75b7Saaron 				printf("NeXT\n");
132673a75b7Saaron 				break;
133673a75b7Saaron 			case WSMOUSE_TYPE_ARCHIMEDES:
134673a75b7Saaron 				printf("Archimedes\n");
135673a75b7Saaron 				break;
136673a75b7Saaron 			default:
137673a75b7Saaron 				printf("Unknown\n");
138673a75b7Saaron 				break;
139673a75b7Saaron 		}
140673a75b7Saaron 	}
141673a75b7Saaron 	else
142673a75b7Saaron 		printf("Unable to open %s \n", mouse.portname);
143673a75b7Saaron }
144673a75b7Saaron 
145673a75b7Saaron 
146673a75b7Saaron 
147673a75b7Saaron 
148673a75b7Saaron /* wsmouse_init : init a wsmouse compatible mouse */
149673a75b7Saaron void
150673a75b7Saaron wsmouse_init(void)
151673a75b7Saaron {
152673a75b7Saaron 	unsigned int res = WSMOUSE_RES_MIN;
153673a75b7Saaron 	unsigned int rate = WSMOUSE_RATE_DEFAULT;
154673a75b7Saaron 
155673a75b7Saaron 	ioctl(mouse.mfd, WSMOUSEIO_SRES, &res);
156673a75b7Saaron 	ioctl(mouse.mfd, WSMOUSEIO_SRATE, &rate);
157673a75b7Saaron }
158673a75b7Saaron 
159673a75b7Saaron 
160673a75b7Saaron /*
161673a75b7Saaron  * Buttons remapping
162673a75b7Saaron  */
163673a75b7Saaron 
164673a75b7Saaron /* physical to logical button mapping */
165673a75b7Saaron static int p2l[MOUSE_MAXBUTTON] = {
166673a75b7Saaron     MOUSE_BUTTON1, MOUSE_BUTTON2, MOUSE_BUTTON3, MOUSE_BUTTON4,
167673a75b7Saaron     MOUSE_BUTTON5, MOUSE_BUTTON6, MOUSE_BUTTON7, MOUSE_BUTTON8,
168673a75b7Saaron };
169673a75b7Saaron 
170673a75b7Saaron static char *
171673a75b7Saaron skipspace(char *s)
172673a75b7Saaron {
173673a75b7Saaron     while(isspace(*s))
174673a75b7Saaron 	++s;
175673a75b7Saaron     return s;
176673a75b7Saaron }
177673a75b7Saaron 
178673a75b7Saaron /* mouse_installmap : install a map between physical and logical buttons */
179673a75b7Saaron static int
180673a75b7Saaron mouse_installmap(char *arg)
181673a75b7Saaron {
182673a75b7Saaron     int pbutton;
183673a75b7Saaron     int lbutton;
184673a75b7Saaron     char *s;
185673a75b7Saaron 
186673a75b7Saaron     while (*arg) {
187673a75b7Saaron 	arg = skipspace(arg);
188673a75b7Saaron 	s = arg;
189673a75b7Saaron 	while (isdigit(*arg))
190673a75b7Saaron 	    ++arg;
191673a75b7Saaron 	arg = skipspace(arg);
192673a75b7Saaron 	if ((arg <= s) || (*arg != '='))
193673a75b7Saaron 	    return FALSE;
194673a75b7Saaron 	lbutton = atoi(s);
195673a75b7Saaron 
196673a75b7Saaron 	arg = skipspace(++arg);
197673a75b7Saaron 	s = arg;
198673a75b7Saaron 	while (isdigit(*arg))
199673a75b7Saaron 	    ++arg;
200673a75b7Saaron 	if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
201673a75b7Saaron 	    return FALSE;
202673a75b7Saaron 	pbutton = atoi(s);
203673a75b7Saaron 
204673a75b7Saaron 	if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
205673a75b7Saaron 	    return FALSE;
206673a75b7Saaron 	if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
207673a75b7Saaron 	    return FALSE;
208673a75b7Saaron 	p2l[pbutton - 1] = lbutton - 1;
209673a75b7Saaron     }
210673a75b7Saaron 
211673a75b7Saaron     return TRUE;
212673a75b7Saaron }
213673a75b7Saaron 
214673a75b7Saaron /* mouse_map : converts physical buttons to logical buttons */
215673a75b7Saaron static void
216673a75b7Saaron mouse_map(struct wscons_event *orig, struct wscons_event *mapped)
217673a75b7Saaron {
218673a75b7Saaron 	mapped->type = orig->type;
219673a75b7Saaron 	mapped->value = p2l[orig->value];
220673a75b7Saaron }
221673a75b7Saaron 
222673a75b7Saaron /* terminate signals handler */
223673a75b7Saaron static void
224673a75b7Saaron terminate(int sig)
225673a75b7Saaron {
226673a75b7Saaron 	struct wscons_event event;
227673a75b7Saaron 
228673a75b7Saaron 	if (mouse.mfd != -1) {
229673a75b7Saaron 		event.type = WSCONS_EVENT_WSMOUSED_OFF;
230673a75b7Saaron 		ioctl(mouse.mfd, WSDISPLAYIO_WSMOUSED, &event);
231673a75b7Saaron 		close(mouse.mfd);
232673a75b7Saaron 		mouse.mfd = -1;
233673a75b7Saaron 	}
234673a75b7Saaron 	unlink(pidfile);
235673a75b7Saaron 	exit(0);
236673a75b7Saaron }
237673a75b7Saaron 
238673a75b7Saaron /* buttons status (for multiple click detection) */
239673a75b7Saaron static struct {
240673a75b7Saaron     int count;		/* 0: up, 1: single click, 2: double click,... */
241673a75b7Saaron     struct timeval tv;	/* timestamp on the last `up' event */
242673a75b7Saaron } buttonstate[MOUSE_MAXBUTTON];
243673a75b7Saaron 
244673a75b7Saaron /*
245673a75b7Saaron  * handle button click
246673a75b7Saaron  * Note that an ioctl is sent for each button
247673a75b7Saaron  */
248673a75b7Saaron static void
249673a75b7Saaron mouse_click(struct wscons_event *event)
250673a75b7Saaron {
251673a75b7Saaron     struct timeval max_date;
252673a75b7Saaron     struct timeval now;
253673a75b7Saaron     struct timeval delay;
254673a75b7Saaron     struct timezone tz;
255673a75b7Saaron     int i = event->value; /* button number */
256673a75b7Saaron 
257673a75b7Saaron     gettimeofday(&now, &tz);
258673a75b7Saaron     delay.tv_sec = mouse.clickthreshold / 1000;
259673a75b7Saaron     delay.tv_usec = (mouse.clickthreshold % 1000) * 1000;
260673a75b7Saaron     timersub(&now, &delay, &max_date);
261673a75b7Saaron 
262673a75b7Saaron     if (event->type == WSCONS_EVENT_MOUSE_DOWN) {
263673a75b7Saaron 	    if (timercmp(&max_date, &buttonstate[i].tv, >)) {
264673a75b7Saaron 		    buttonstate[i].tv.tv_sec = 0;
265673a75b7Saaron 		    buttonstate[i].tv.tv_usec = 0;
266673a75b7Saaron 		    buttonstate[i].count = 1;
267673a75b7Saaron 	    }
268673a75b7Saaron 	    else {
269673a75b7Saaron 		    buttonstate[i].count++;
270673a75b7Saaron 	    }
271673a75b7Saaron     } else {
272673a75b7Saaron 	    /* button is up */
273673a75b7Saaron 	    buttonstate[i].tv.tv_sec = now.tv_sec;
274673a75b7Saaron 	    buttonstate[i].tv.tv_usec = now.tv_usec;
275673a75b7Saaron     }
276673a75b7Saaron 
277673a75b7Saaron     /*
278673a75b7Saaron      * we use the time field of wscons_event structure to put the number
279673a75b7Saaron      * of multiple clicks
280673a75b7Saaron      */
281673a75b7Saaron     if (event->type == WSCONS_EVENT_MOUSE_DOWN) {
282673a75b7Saaron 	    event->time.tv_sec = buttonstate[i].count;
283673a75b7Saaron 	    event->time.tv_nsec = 0;
284673a75b7Saaron     }
285673a75b7Saaron     else {
286673a75b7Saaron 	   /* button is up */
287673a75b7Saaron 	   event->time.tv_sec = 0;
288673a75b7Saaron 	   event->time.tv_nsec = 0;
289673a75b7Saaron     }
290673a75b7Saaron     ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
291673a75b7Saaron }
292673a75b7Saaron 
293673a75b7Saaron 
294673a75b7Saaron /* workaround for cursor speed on serial mice */
295673a75b7Saaron static void
296673a75b7Saaron normalize_event(struct wscons_event *event)
297673a75b7Saaron {
298673a75b7Saaron 	int dx, dy;
299673a75b7Saaron 	int two_power = 1;
300673a75b7Saaron 
301673a75b7Saaron /* 2: normal speed, 3: slower cursor, 1: faster cursor */
302673a75b7Saaron #define NORMALIZE_DIVISOR 3
303673a75b7Saaron 
304673a75b7Saaron 	if (event->type == WSCONS_EVENT_MOUSE_DELTA_X) {
305673a75b7Saaron 		dx = abs(event->value);
306673a75b7Saaron 		while (dx > 2) {
307673a75b7Saaron 			two_power++;
308673a75b7Saaron 			dx = dx / 2;
309673a75b7Saaron 		}
310673a75b7Saaron 		event->value = event->value / (NORMALIZE_DIVISOR * two_power);
311673a75b7Saaron 		return ;
312673a75b7Saaron 	}
313673a75b7Saaron 
314673a75b7Saaron 	if (event->type == WSCONS_EVENT_MOUSE_DELTA_Y) {
315673a75b7Saaron 		two_power = 1;
316673a75b7Saaron 		dy = abs(event->value);
317673a75b7Saaron 		while (dy > 2) {
318673a75b7Saaron 			two_power++;
319673a75b7Saaron 			dy = dy / 2;
320673a75b7Saaron 		}
321673a75b7Saaron 		event->value = event->value / (NORMALIZE_DIVISOR * two_power);
322673a75b7Saaron 	}
323673a75b7Saaron 	return ;
324673a75b7Saaron }
325673a75b7Saaron 
326673a75b7Saaron /* send a wscons_event to the kernel */
327673a75b7Saaron static void
328673a75b7Saaron treat_event(struct wscons_event *event)
329673a75b7Saaron {
330673a75b7Saaron 	struct wscons_event mapped_event;
331673a75b7Saaron 
332673a75b7Saaron 	if (IS_MOTION_EVENT(event->type)) {
333673a75b7Saaron 		ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
334673a75b7Saaron 		return ;
335673a75b7Saaron 	}
336673a75b7Saaron 	if (IS_BUTTON_EVENT(event->type)) {
337673a75b7Saaron 		mouse_map(event, &mapped_event);
338673a75b7Saaron 		mouse_click(&mapped_event);
339673a75b7Saaron 		return ;
340673a75b7Saaron 	}
341673a75b7Saaron 	return ;
342673a75b7Saaron }
343673a75b7Saaron 
344673a75b7Saaron 
345673a75b7Saaron /* split a full mouse event into multiples wscons events */
346673a75b7Saaron static void
347673a75b7Saaron split_event(mousestatus_t *act)
348673a75b7Saaron {
349673a75b7Saaron 	struct wscons_event event;
350673a75b7Saaron 	int button, i, mask;
351673a75b7Saaron 
352673a75b7Saaron 	if (act->dx != 0) {
353673a75b7Saaron 		event.type = WSCONS_EVENT_MOUSE_DELTA_X;
354673a75b7Saaron 		event.value = act->dx;
355673a75b7Saaron 		normalize_event(&event);
356673a75b7Saaron 		treat_event(&event);
357673a75b7Saaron 	}
358673a75b7Saaron 	if (act->dy != 0) {
359673a75b7Saaron 		event.type = WSCONS_EVENT_MOUSE_DELTA_Y;
360673a75b7Saaron 		event.value = 0 - act->dy;
361673a75b7Saaron 		normalize_event(&event);
362673a75b7Saaron 		treat_event(&event);
363673a75b7Saaron 	}
364673a75b7Saaron 	if (act->dz != 0) {
365673a75b7Saaron 		event.type = WSCONS_EVENT_MOUSE_DELTA_Z;
366673a75b7Saaron 		event.value = act->dz;
367673a75b7Saaron 		treat_event(&event);
368673a75b7Saaron 	}
369673a75b7Saaron 
370673a75b7Saaron 	/* buttons state */
371673a75b7Saaron 	mask = act->flags & MOUSE_BUTTONS;
372673a75b7Saaron 	if (mask == 0)
373673a75b7Saaron 		/* no button modified */
374673a75b7Saaron 		return;
375673a75b7Saaron 
376673a75b7Saaron 	button = MOUSE_BUTTON1DOWN;
377673a75b7Saaron 	for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); i++) {
378673a75b7Saaron 		if (mask & 1) {
379673a75b7Saaron 			if (act->button & button) {
380673a75b7Saaron 				/* button is down */
381673a75b7Saaron 				event.type = WSCONS_EVENT_MOUSE_DOWN;
382673a75b7Saaron 				event.value = i;
383673a75b7Saaron 				treat_event(&event);
384673a75b7Saaron 			}
385673a75b7Saaron 			else {
386673a75b7Saaron 				/* button is up */
387673a75b7Saaron 				event.type = WSCONS_EVENT_MOUSE_UP;
388673a75b7Saaron 				event.value = i;
389673a75b7Saaron 				treat_event(&event);
390673a75b7Saaron 			}
391673a75b7Saaron 		}
392673a75b7Saaron 		button <<= 1;
393673a75b7Saaron 		mask >>= 1;
394673a75b7Saaron 	}
395673a75b7Saaron 
396673a75b7Saaron }
397673a75b7Saaron 
398673a75b7Saaron /* main function */
399673a75b7Saaron static void
400673a75b7Saaron wsmoused(void)
401673a75b7Saaron {
402673a75b7Saaron     mousestatus_t action;
403673a75b7Saaron     struct wscons_event event; /* original wscons_event */
404673a75b7Saaron     struct pollfd pfd[1];
405673a75b7Saaron     int res;
406673a75b7Saaron     u_char b;
407673a75b7Saaron     FILE *fp;
408673a75b7Saaron 
409673a75b7Saaron     if ((mouse.cfd = open("/dev/ttyCcfg", O_RDWR, 0)) == -1)
410673a75b7Saaron 	logerr(1, "cannot open /dev/ttyCcfg");
411673a75b7Saaron 
412673a75b7Saaron     if (!nodaemon && !background) {
413673a75b7Saaron 	if (daemon(0, 0)) {
414673a75b7Saaron 	    logerr(1, "failed to become a daemon");
415673a75b7Saaron 	} else {
416673a75b7Saaron 	  background = TRUE;
417673a75b7Saaron 	    fp = fopen(pidfile, "w");
418673a75b7Saaron 	    if (fp != NULL) {
419673a75b7Saaron 		fprintf(fp, "%d\n", getpid());
420673a75b7Saaron 		fclose(fp);
421673a75b7Saaron 	    }
422673a75b7Saaron 	}
423673a75b7Saaron     }
424673a75b7Saaron 
425673a75b7Saaron     /* initialization */
426673a75b7Saaron 
427673a75b7Saaron     event.type = WSCONS_EVENT_WSMOUSED_ON;
428673a75b7Saaron     res = ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, &event);
429673a75b7Saaron     if (res != 0) {
430673a75b7Saaron 	/* the display driver has no getchar() method */
431673a75b7Saaron 	fprintf(stderr,
432673a75b7Saaron 		"Error: this display driver has no support for wsmoused\n");
433673a75b7Saaron 	exit(1);
434673a75b7Saaron     }
435673a75b7Saaron 
436673a75b7Saaron     bzero(&action, sizeof(action));
437673a75b7Saaron     bzero(&event, sizeof(event));
438673a75b7Saaron     bzero(&buttonstate, sizeof(buttonstate));
439673a75b7Saaron 
440673a75b7Saaron     pfd[0].fd = mouse.mfd;
441673a75b7Saaron     pfd[0].events = POLLIN;
442673a75b7Saaron 
443673a75b7Saaron     /* process mouse data */
444673a75b7Saaron     for (;;) {
445673a75b7Saaron 
446*29f11fc7Sfgsch 	if (poll(pfd, 1, INFTIM) <= 0)
447673a75b7Saaron 		logwarn("failed to read from mouse");
448673a75b7Saaron 	if (IS_WSMOUSE_DEV(mouse.portname))  {
449673a75b7Saaron 		/* wsmouse supported mouse */
450673a75b7Saaron 		read(mouse.mfd, &event, sizeof(event));
451673a75b7Saaron 		treat_event(&event);
452673a75b7Saaron 	}
453673a75b7Saaron 	else {
454673a75b7Saaron 		/* serial mouse (not wsmouse supported) */
455673a75b7Saaron 		res = read(mouse.mfd, &b, 1);
456673a75b7Saaron 
457673a75b7Saaron 		/* if we have a full mouse event */
458673a75b7Saaron 		if (mouse_protocol(b, &action))
459673a75b7Saaron 			/* split it as multiple wscons_event */
460673a75b7Saaron 			split_event(&action);
461673a75b7Saaron 	}
462673a75b7Saaron     }
463673a75b7Saaron }
464673a75b7Saaron 
465673a75b7Saaron 
466673a75b7Saaron static void
467673a75b7Saaron usage(void)
468673a75b7Saaron {
469673a75b7Saaron 	printf("usage: %s [-2df] [-t protocol] [-C threshold] [-I file] \
470673a75b7Saaron [-M N=M] [-p port]",__progname);
471673a75b7Saaron 	printf("       %s -i [-p port] \n",__progname);
472673a75b7Saaron 	exit(1);
473673a75b7Saaron }
474673a75b7Saaron 
475673a75b7Saaron int
476673a75b7Saaron main(int argc, char **argv)
477673a75b7Saaron {
478673a75b7Saaron 	int opt;
479673a75b7Saaron 	int i;
480673a75b7Saaron 
481673a75b7Saaron #define GETOPT_STRING "2dfhip:t:C:I:M:"
482673a75b7Saaron 	while ((opt = (getopt(argc, argv, GETOPT_STRING))) != -1) {
483673a75b7Saaron 		switch (opt) {
484673a75b7Saaron 			case '2':
485673a75b7Saaron 				/* on two button mice, right button pastes */
486673a75b7Saaron 				p2l[MOUSE_BUTTON3] = MOUSE_BUTTON2;
487673a75b7Saaron 				break;
488673a75b7Saaron 			case 'd':
489673a75b7Saaron 				++debug;
490673a75b7Saaron 				break;
491673a75b7Saaron 			case 'f':
492673a75b7Saaron 				nodaemon = TRUE;
493673a75b7Saaron 				break;
494673a75b7Saaron 			case 'h':
495673a75b7Saaron 				usage();
496673a75b7Saaron 				return 1;
497673a75b7Saaron 				break;
498673a75b7Saaron 			case 'i':
499673a75b7Saaron 				identify = TRUE;
500673a75b7Saaron 				break;
501673a75b7Saaron 			case 'p':
502673a75b7Saaron 				mouse.portname = strdup(optarg);
503673a75b7Saaron 				break;
504673a75b7Saaron 			case 't':
505673a75b7Saaron 				if (strcmp(optarg, "auto") == 0) {
506673a75b7Saaron 					mouse.proto = P_UNKNOWN;
507673a75b7Saaron 					mouse.flags &= ~NoPnP;
508673a75b7Saaron 					break;
509673a75b7Saaron 				}
510673a75b7Saaron 				for (i = 0; mouse_names[i]; i++)
511673a75b7Saaron 					if (strcmp(optarg,mouse_names[i]) == 0){
512673a75b7Saaron 						mouse.proto = i;
513673a75b7Saaron 						mouse.flags |= NoPnP;
514673a75b7Saaron 						break;
515673a75b7Saaron 					}
516673a75b7Saaron 				if (mouse_names[i])
517673a75b7Saaron 					break;
518673a75b7Saaron 				printf("no such mouse protocol `%s'\n", optarg);
519673a75b7Saaron 				usage();
520673a75b7Saaron 				break;
521673a75b7Saaron 			case 'C':
522673a75b7Saaron #define MAX_CLICKTHRESHOLD 2000 /* max delay for double click */
523673a75b7Saaron 
524673a75b7Saaron 				mouse.clickthreshold = atoi(optarg);
525673a75b7Saaron 				if ((mouse.clickthreshold < 0) ||
526673a75b7Saaron 				(mouse.clickthreshold > MAX_CLICKTHRESHOLD)) {
527673a75b7Saaron 					printf("invalid threshold `%s': max value is %d\n"
528673a75b7Saaron 						, optarg,MAX_CLICKTHRESHOLD);
529673a75b7Saaron 					usage();
530673a75b7Saaron 				}
531673a75b7Saaron 				break;
532673a75b7Saaron 			case 'I':
533673a75b7Saaron 				pidfile = optarg;
534673a75b7Saaron 				break;
535673a75b7Saaron 			case 'M':
536673a75b7Saaron 				if (!mouse_installmap(optarg)) {
537673a75b7Saaron 					warnx("invalid mapping `%s'\n", optarg);
538673a75b7Saaron 					usage();
539673a75b7Saaron 				}
540673a75b7Saaron 				break;
541673a75b7Saaron 			default:
542673a75b7Saaron 				usage();
543673a75b7Saaron 		}
544673a75b7Saaron 	}
545673a75b7Saaron 	if (!mouse.portname)
546673a75b7Saaron 		/* default is /dev/wsmouse */
547673a75b7Saaron 		mouse.portname = "/dev/wsmouse";
548673a75b7Saaron 
549673a75b7Saaron 	for (;;) {
550673a75b7Saaron 		signal(SIGINT , terminate);
551673a75b7Saaron 		signal(SIGQUIT, terminate);
552673a75b7Saaron 		signal(SIGTERM, terminate);
553673a75b7Saaron 		signal(SIGKILL, terminate);
554673a75b7Saaron 		if ((mouse.mfd = open(mouse.portname,
555673a75b7Saaron 					O_RDONLY | O_NONBLOCK, 0)) == -1)
556673a75b7Saaron 			logerr(1, "unable to open %s", mouse.portname);
557673a75b7Saaron 		if (IS_SERIAL_DEV(mouse.portname)) {
558673a75b7Saaron 			if (mouse_identify() == P_UNKNOWN) {
559673a75b7Saaron 				logwarn("cannot determine mouse type on %s", mouse.portname);
560673a75b7Saaron 				close(mouse.mfd);
561673a75b7Saaron 				mouse.mfd = -1;
562673a75b7Saaron 			}
563673a75b7Saaron 		}
564673a75b7Saaron 
565673a75b7Saaron 		if (identify == TRUE) {
566673a75b7Saaron 			if (IS_WSMOUSE_DEV(mouse.portname))
567673a75b7Saaron 				wsmouse_identify();
568673a75b7Saaron 			else
569673a75b7Saaron 				printf("serial mouse: %s type\n",
570673a75b7Saaron 						mouse_name(mouse.proto));
571673a75b7Saaron 			return (0);
572673a75b7Saaron 		}
573673a75b7Saaron 
574673a75b7Saaron 		if (mouse.mfd == -1) {
575673a75b7Saaron 			exit(1);
576673a75b7Saaron 		}
577673a75b7Saaron 
578673a75b7Saaron 		mouse_init();
579673a75b7Saaron 		wsmoused();
580673a75b7Saaron 
581673a75b7Saaron 	}
582673a75b7Saaron }
583673a75b7Saaron 
584