1*b7041c07Sderaadt /* $OpenBSD: wsmoused.c,v 1.38 2021/10/24 21:24:19 deraadt 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>
54f3afb3efSjbm #include <sys/stat.h>
55673a75b7Saaron #include <sys/types.h>
56673a75b7Saaron #include <sys/time.h>
57673a75b7Saaron #include <sys/tty.h>
58673a75b7Saaron #include <dev/wscons/wsconsio.h>
59673a75b7Saaron
60673a75b7Saaron #include <ctype.h>
61673a75b7Saaron #include <err.h>
62673a75b7Saaron #include <errno.h>
63673a75b7Saaron #include <fcntl.h>
64673a75b7Saaron #include <unistd.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
72673a75b7Saaron #include "mouse_protocols.h"
73673a75b7Saaron #include "wsmoused.h"
74673a75b7Saaron
75be45c8afSmiod #define DEFAULT_TTY "/dev/ttyCcfg"
76be45c8afSmiod
77673a75b7Saaron extern char *__progname;
78673a75b7Saaron extern char *mouse_names[];
79673a75b7Saaron
80673a75b7Saaron int debug = 0;
81673a75b7Saaron int background = FALSE;
82be45c8afSmiod int nodaemon = FALSE;
83673a75b7Saaron int identify = FALSE;
84673a75b7Saaron
85673a75b7Saaron mouse_t mouse = {
86b729828dSotto .flags = 0,
87b729828dSotto .portname = NULL,
88be45c8afSmiod .ttyname = NULL,
89b729828dSotto .proto = P_UNKNOWN,
90b729828dSotto .rate = MOUSE_RATE_UNKNOWN,
91b729828dSotto .resolution = MOUSE_RES_UNKNOWN,
92b729828dSotto .mfd = -1,
93b729828dSotto .clickthreshold = 500, /* 0.5 sec */
94673a75b7Saaron };
95673a75b7Saaron
96673a75b7Saaron /* identify the type of a wsmouse supported mouse */
97673a75b7Saaron void
wsmouse_identify(void)98673a75b7Saaron wsmouse_identify(void)
99673a75b7Saaron {
100673a75b7Saaron unsigned int type;
101673a75b7Saaron
102b47703b0Smiod if (mouse.mfd != -1) {
103b47703b0Smiod if (ioctl(mouse.mfd, WSMOUSEIO_GTYPE, &type) == -1)
104b47703b0Smiod err(1, "can't detect mouse type");
105be45c8afSmiod
106673a75b7Saaron printf("wsmouse supported mouse: ");
107673a75b7Saaron switch (type) {
108673a75b7Saaron case WSMOUSE_TYPE_VSXXX:
109673a75b7Saaron printf("DEC serial\n");
110673a75b7Saaron break;
111673a75b7Saaron case WSMOUSE_TYPE_PS2:
112673a75b7Saaron printf("PS/2 compatible\n");
113673a75b7Saaron break;
114673a75b7Saaron case WSMOUSE_TYPE_USB:
115673a75b7Saaron printf("USB\n");
116673a75b7Saaron break;
117673a75b7Saaron case WSMOUSE_TYPE_LMS:
118673a75b7Saaron printf("Logitech busmouse\n");
119673a75b7Saaron break;
120673a75b7Saaron case WSMOUSE_TYPE_MMS:
121673a75b7Saaron printf("Microsoft InPort mouse\n");
122673a75b7Saaron break;
123673a75b7Saaron case WSMOUSE_TYPE_TPANEL:
124673a75b7Saaron printf("Generic Touch Panel\n");
125673a75b7Saaron break;
126673a75b7Saaron case WSMOUSE_TYPE_NEXT:
127673a75b7Saaron printf("NeXT\n");
128673a75b7Saaron break;
129673a75b7Saaron case WSMOUSE_TYPE_ARCHIMEDES:
130673a75b7Saaron printf("Archimedes\n");
131673a75b7Saaron break;
132be45c8afSmiod case WSMOUSE_TYPE_ADB:
133be45c8afSmiod printf("ADB\n");
134be45c8afSmiod break;
135be45c8afSmiod case WSMOUSE_TYPE_HIL:
136be45c8afSmiod printf("HP-HIL\n");
137be45c8afSmiod break;
138be45c8afSmiod case WSMOUSE_TYPE_LUNA:
139be45c8afSmiod printf("Omron Luna\n");
140be45c8afSmiod break;
141be45c8afSmiod case WSMOUSE_TYPE_DOMAIN:
142be45c8afSmiod printf("Apollo Domain\n");
143be45c8afSmiod break;
144be45c8afSmiod case WSMOUSE_TYPE_SUN:
145be45c8afSmiod printf("Sun\n");
146be45c8afSmiod break;
147673a75b7Saaron default:
148673a75b7Saaron printf("Unknown\n");
149673a75b7Saaron break;
150673a75b7Saaron }
151b47703b0Smiod } else
15246347781Smpech warnx("unable to open %s", mouse.portname);
153673a75b7Saaron }
154673a75b7Saaron
155673a75b7Saaron /* wsmouse_init : init a wsmouse compatible mouse */
156673a75b7Saaron void
wsmouse_init(void)157673a75b7Saaron wsmouse_init(void)
158673a75b7Saaron {
159673a75b7Saaron unsigned int res = WSMOUSE_RES_MIN;
160673a75b7Saaron
161673a75b7Saaron ioctl(mouse.mfd, WSMOUSEIO_SRES, &res);
162673a75b7Saaron }
163673a75b7Saaron
164673a75b7Saaron /*
165673a75b7Saaron * Buttons remapping
166673a75b7Saaron */
167673a75b7Saaron
168673a75b7Saaron /* physical to logical button mapping */
169673a75b7Saaron static int p2l[MOUSE_MAXBUTTON] = {
170673a75b7Saaron MOUSE_BUTTON1, MOUSE_BUTTON2, MOUSE_BUTTON3, MOUSE_BUTTON4,
171673a75b7Saaron MOUSE_BUTTON5, MOUSE_BUTTON6, MOUSE_BUTTON7, MOUSE_BUTTON8,
172673a75b7Saaron };
173673a75b7Saaron
174673a75b7Saaron static char *
skipspace(char * s)175673a75b7Saaron skipspace(char *s)
176673a75b7Saaron {
1772bfe0399Sderaadt while (isspace((unsigned char)*s))
178673a75b7Saaron ++s;
179673a75b7Saaron return s;
180673a75b7Saaron }
181673a75b7Saaron
182673a75b7Saaron /* mouse_installmap : install a map between physical and logical buttons */
183673a75b7Saaron static int
mouse_installmap(char * arg)184673a75b7Saaron mouse_installmap(char *arg)
185673a75b7Saaron {
186673a75b7Saaron int pbutton;
187673a75b7Saaron int lbutton;
188673a75b7Saaron char *s;
189673a75b7Saaron
190673a75b7Saaron while (*arg) {
191673a75b7Saaron arg = skipspace(arg);
192673a75b7Saaron s = arg;
1932bfe0399Sderaadt while (isdigit((unsigned char)*arg))
194673a75b7Saaron ++arg;
195673a75b7Saaron arg = skipspace(arg);
196673a75b7Saaron if ((arg <= s) || (*arg != '='))
197673a75b7Saaron return FALSE;
198673a75b7Saaron lbutton = atoi(s);
199673a75b7Saaron
200673a75b7Saaron arg = skipspace(++arg);
201673a75b7Saaron s = arg;
2022bfe0399Sderaadt while (isdigit((unsigned char)*arg))
203673a75b7Saaron ++arg;
2042bfe0399Sderaadt if (arg <= s || (!isspace((unsigned char)*arg) && *arg != '\0'))
205673a75b7Saaron return FALSE;
206673a75b7Saaron pbutton = atoi(s);
207673a75b7Saaron
208b47703b0Smiod if (lbutton <= 0 || lbutton > MOUSE_MAXBUTTON)
209673a75b7Saaron return FALSE;
210b47703b0Smiod if (pbutton <= 0 || pbutton > MOUSE_MAXBUTTON)
211673a75b7Saaron return FALSE;
212673a75b7Saaron p2l[pbutton - 1] = lbutton - 1;
213673a75b7Saaron }
214673a75b7Saaron return TRUE;
215673a75b7Saaron }
216673a75b7Saaron
217673a75b7Saaron /* terminate signals handler */
218673a75b7Saaron static void
terminate(int sig)219673a75b7Saaron terminate(int sig)
220673a75b7Saaron {
221673a75b7Saaron struct wscons_event event;
222e02f5e47Sjbm unsigned int res;
223673a75b7Saaron
224673a75b7Saaron if (mouse.mfd != -1) {
225673a75b7Saaron event.type = WSCONS_EVENT_WSMOUSED_OFF;
226f3afb3efSjbm ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, &event);
227e02f5e47Sjbm res = WSMOUSE_RES_DEFAULT;
228e02f5e47Sjbm ioctl(mouse.mfd, WSMOUSEIO_SRES, &res);
229673a75b7Saaron close(mouse.mfd);
230673a75b7Saaron mouse.mfd = -1;
231673a75b7Saaron }
232ded45aa8Sderaadt _exit(0);
233673a75b7Saaron }
234673a75b7Saaron
235673a75b7Saaron /* buttons status (for multiple click detection) */
236673a75b7Saaron static struct {
237673a75b7Saaron int count; /* 0: up, 1: single click, 2: double click,... */
238673a75b7Saaron struct timeval tv; /* timestamp on the last `up' event */
239673a75b7Saaron } buttonstate[MOUSE_MAXBUTTON];
240673a75b7Saaron
241673a75b7Saaron /*
242673a75b7Saaron * handle button click
243673a75b7Saaron * Note that an ioctl is sent for each button
244673a75b7Saaron */
245673a75b7Saaron static void
mouse_click(struct wscons_event * event)246673a75b7Saaron mouse_click(struct wscons_event *event)
247673a75b7Saaron {
248673a75b7Saaron struct timeval max_date;
249673a75b7Saaron struct timeval now;
250673a75b7Saaron struct timeval delay;
2517c620f4aSshadchin int i; /* button number */
2527c620f4aSshadchin
2537c620f4aSshadchin i = event->value = p2l[event->value];
254673a75b7Saaron
255a9fa58fdSderaadt gettimeofday(&now, NULL);
256673a75b7Saaron delay.tv_sec = mouse.clickthreshold / 1000;
257673a75b7Saaron delay.tv_usec = (mouse.clickthreshold % 1000) * 1000;
258673a75b7Saaron timersub(&now, &delay, &max_date);
259673a75b7Saaron
260673a75b7Saaron if (event->type == WSCONS_EVENT_MOUSE_DOWN) {
261673a75b7Saaron if (timercmp(&max_date, &buttonstate[i].tv, >)) {
2626c2da34cSokan timerclear(&buttonstate[i].tv);
263673a75b7Saaron buttonstate[i].count = 1;
264b47703b0Smiod } else {
265673a75b7Saaron buttonstate[i].count++;
266673a75b7Saaron }
267673a75b7Saaron } else {
268673a75b7Saaron /* button is up */
269673a75b7Saaron buttonstate[i].tv.tv_sec = now.tv_sec;
270673a75b7Saaron buttonstate[i].tv.tv_usec = now.tv_usec;
271673a75b7Saaron }
272673a75b7Saaron
273673a75b7Saaron /*
274673a75b7Saaron * we use the time field of wscons_event structure to put the number
275673a75b7Saaron * of multiple clicks
276673a75b7Saaron */
277673a75b7Saaron if (event->type == WSCONS_EVENT_MOUSE_DOWN) {
278673a75b7Saaron event->time.tv_sec = buttonstate[i].count;
279673a75b7Saaron event->time.tv_nsec = 0;
280b47703b0Smiod } else {
281673a75b7Saaron /* button is up */
282673a75b7Saaron event->time.tv_sec = 0;
283673a75b7Saaron event->time.tv_nsec = 0;
284673a75b7Saaron }
285673a75b7Saaron ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
286673a75b7Saaron }
287673a75b7Saaron
288673a75b7Saaron /* workaround for cursor speed on serial mice */
289673a75b7Saaron static void
normalize_event(struct wscons_event * event)290673a75b7Saaron normalize_event(struct wscons_event *event)
291673a75b7Saaron {
292673a75b7Saaron int dx, dy;
293673a75b7Saaron int two_power = 1;
294673a75b7Saaron
295673a75b7Saaron /* 2: normal speed, 3: slower cursor, 1: faster cursor */
296673a75b7Saaron #define NORMALIZE_DIVISOR 3
297673a75b7Saaron
298b47703b0Smiod switch (event->type) {
299b47703b0Smiod case WSCONS_EVENT_MOUSE_DELTA_X:
300673a75b7Saaron dx = abs(event->value);
301673a75b7Saaron while (dx > 2) {
302673a75b7Saaron two_power++;
303673a75b7Saaron dx = dx / 2;
304673a75b7Saaron }
305673a75b7Saaron event->value = event->value / (NORMALIZE_DIVISOR * two_power);
306b47703b0Smiod break;
307b47703b0Smiod case WSCONS_EVENT_MOUSE_DELTA_Y:
308673a75b7Saaron two_power = 1;
309673a75b7Saaron dy = abs(event->value);
310673a75b7Saaron while (dy > 2) {
311673a75b7Saaron two_power++;
312673a75b7Saaron dy = dy / 2;
313673a75b7Saaron }
314673a75b7Saaron event->value = event->value / (NORMALIZE_DIVISOR * two_power);
315b47703b0Smiod break;
316673a75b7Saaron }
317673a75b7Saaron }
318673a75b7Saaron
319673a75b7Saaron /* send a wscons_event to the kernel */
320bd203825Sshadchin static void
treat_event(struct wscons_event * event)321673a75b7Saaron treat_event(struct wscons_event *event)
322673a75b7Saaron {
323673a75b7Saaron if (IS_MOTION_EVENT(event->type)) {
324673a75b7Saaron ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
3255015c596Sjacekm } else if (IS_BUTTON_EVENT(event->type) &&
3265015c596Sjacekm (uint)event->value < MOUSE_MAXBUTTON) {
3277c620f4aSshadchin mouse_click(event);
328673a75b7Saaron }
329673a75b7Saaron }
330673a75b7Saaron
331673a75b7Saaron /* split a full mouse event into multiples wscons events */
332673a75b7Saaron static void
split_event(mousestatus_t * act)333673a75b7Saaron split_event(mousestatus_t *act)
334673a75b7Saaron {
335673a75b7Saaron struct wscons_event event;
336673a75b7Saaron int button, i, mask;
337673a75b7Saaron
338673a75b7Saaron if (act->dx != 0) {
339673a75b7Saaron event.type = WSCONS_EVENT_MOUSE_DELTA_X;
340673a75b7Saaron event.value = act->dx;
341673a75b7Saaron normalize_event(&event);
342673a75b7Saaron treat_event(&event);
343673a75b7Saaron }
344673a75b7Saaron if (act->dy != 0) {
345673a75b7Saaron event.type = WSCONS_EVENT_MOUSE_DELTA_Y;
346673a75b7Saaron event.value = 0 - act->dy;
347673a75b7Saaron normalize_event(&event);
348673a75b7Saaron treat_event(&event);
349673a75b7Saaron }
350673a75b7Saaron if (act->dz != 0) {
351673a75b7Saaron event.type = WSCONS_EVENT_MOUSE_DELTA_Z;
352673a75b7Saaron event.value = act->dz;
353673a75b7Saaron treat_event(&event);
354673a75b7Saaron }
3552fc38322Smiod if (act->dw != 0) {
3562fc38322Smiod event.type = WSCONS_EVENT_MOUSE_DELTA_W;
3572fc38322Smiod event.value = act->dw;
3582fc38322Smiod treat_event(&event);
3592fc38322Smiod }
360673a75b7Saaron
361673a75b7Saaron /* buttons state */
362673a75b7Saaron mask = act->flags & MOUSE_BUTTONS;
363673a75b7Saaron if (mask == 0)
364673a75b7Saaron /* no button modified */
365673a75b7Saaron return;
366673a75b7Saaron
367673a75b7Saaron button = MOUSE_BUTTON1DOWN;
368673a75b7Saaron for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); i++) {
369673a75b7Saaron if (mask & 1) {
370b47703b0Smiod event.type = (act->button & button) ?
371b47703b0Smiod WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
372673a75b7Saaron event.value = i;
373673a75b7Saaron treat_event(&event);
374673a75b7Saaron }
375673a75b7Saaron button <<= 1;
376673a75b7Saaron mask >>= 1;
377673a75b7Saaron }
378673a75b7Saaron }
379673a75b7Saaron
380673a75b7Saaron /* main function */
381673a75b7Saaron static void
wsmoused(void)382673a75b7Saaron wsmoused(void)
383673a75b7Saaron {
384673a75b7Saaron mousestatus_t action;
385673a75b7Saaron struct wscons_event event; /* original wscons_event */
386673a75b7Saaron struct pollfd pfd[1];
387673a75b7Saaron int res;
388673a75b7Saaron u_char b;
389f3afb3efSjbm
390be45c8afSmiod /* notify kernel the start of wsmoused */
3918923421aSshadchin event.type = WSCONS_EVENT_WSMOUSED_ON;
392673a75b7Saaron res = ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, &event);
393673a75b7Saaron if (res != 0) {
394673a75b7Saaron /* the display driver has no getchar() method */
395f3afb3efSjbm logerr(1, "this display driver has no support for wsmoused(8)");
396673a75b7Saaron }
397673a75b7Saaron
398673a75b7Saaron bzero(&action, sizeof(action));
399673a75b7Saaron bzero(&event, sizeof(event));
400673a75b7Saaron bzero(&buttonstate, sizeof(buttonstate));
401673a75b7Saaron
402673a75b7Saaron pfd[0].fd = mouse.mfd;
403673a75b7Saaron pfd[0].events = POLLIN;
404673a75b7Saaron
405673a75b7Saaron /* process mouse data */
406673a75b7Saaron for (;;) {
40729f11fc7Sfgsch if (poll(pfd, 1, INFTIM) <= 0)
408673a75b7Saaron logwarn("failed to read from mouse");
409be45c8afSmiod
410be45c8afSmiod if (mouse.proto == P_WSCONS) {
411673a75b7Saaron /* wsmouse supported mouse */
412673a75b7Saaron read(mouse.mfd, &event, sizeof(event));
413bd203825Sshadchin treat_event(&event);
414b47703b0Smiod } else {
415f3afb3efSjbm /* serial mouse (not supported by wsmouse) */
416673a75b7Saaron res = read(mouse.mfd, &b, 1);
417673a75b7Saaron
418673a75b7Saaron /* if we have a full mouse event */
419673a75b7Saaron if (mouse_protocol(b, &action))
420673a75b7Saaron /* split it as multiple wscons_event */
421673a75b7Saaron split_event(&action);
422673a75b7Saaron }
423673a75b7Saaron }
424673a75b7Saaron }
425673a75b7Saaron
426673a75b7Saaron
427673a75b7Saaron static void
usage(void)428673a75b7Saaron usage(void)
429673a75b7Saaron {
430ceaf4be1Sderaadt fprintf(stderr, "usage: %s [-2dfi] [-C thresh] [-D device]"
431be45c8afSmiod " [-M N=M]\n\t[-p device] [-t type]\n", __progname);
432673a75b7Saaron exit(1);
433673a75b7Saaron }
434673a75b7Saaron
435673a75b7Saaron int
main(int argc,char ** argv)436673a75b7Saaron main(int argc, char **argv)
437673a75b7Saaron {
438be45c8afSmiod unsigned int type;
439673a75b7Saaron int opt;
440673a75b7Saaron int i;
441673a75b7Saaron
442ceaf4be1Sderaadt #define GETOPT_STRING "2dfhip:t:C:D:M:"
443673a75b7Saaron while ((opt = (getopt(argc, argv, GETOPT_STRING))) != -1) {
444673a75b7Saaron switch (opt) {
445673a75b7Saaron case '2':
446673a75b7Saaron /* on two button mice, right button pastes */
447673a75b7Saaron p2l[MOUSE_BUTTON3] = MOUSE_BUTTON2;
448673a75b7Saaron break;
449673a75b7Saaron case 'd':
450673a75b7Saaron ++debug;
451673a75b7Saaron break;
452673a75b7Saaron case 'f':
453673a75b7Saaron nodaemon = TRUE;
454673a75b7Saaron break;
455673a75b7Saaron case 'h':
456673a75b7Saaron usage();
457673a75b7Saaron break;
458673a75b7Saaron case 'i':
459673a75b7Saaron identify = TRUE;
460be45c8afSmiod nodaemon = TRUE;
461673a75b7Saaron break;
462673a75b7Saaron case 'p':
463ca198d9fSderaadt if ((mouse.portname = strdup(optarg)) == NULL)
464ca198d9fSderaadt logerr(1, "out of memory");
465673a75b7Saaron break;
466673a75b7Saaron case 't':
467673a75b7Saaron if (strcmp(optarg, "auto") == 0) {
468673a75b7Saaron mouse.proto = P_UNKNOWN;
469673a75b7Saaron mouse.flags &= ~NoPnP;
470673a75b7Saaron break;
471673a75b7Saaron }
472b47703b0Smiod for (i = 0; mouse_names[i] != NULL; i++)
473673a75b7Saaron if (strcmp(optarg,mouse_names[i]) == 0) {
474673a75b7Saaron mouse.proto = i;
475673a75b7Saaron mouse.flags |= NoPnP;
476673a75b7Saaron break;
477673a75b7Saaron }
478b47703b0Smiod if (mouse_names[i] != NULL)
479673a75b7Saaron break;
48046347781Smpech warnx("no such mouse protocol `%s'", optarg);
481673a75b7Saaron usage();
482673a75b7Saaron break;
483673a75b7Saaron case 'C':
484673a75b7Saaron #define MAX_CLICKTHRESHOLD 2000 /* max delay for double click */
485673a75b7Saaron mouse.clickthreshold = atoi(optarg);
486b47703b0Smiod if (mouse.clickthreshold < 0 ||
487b47703b0Smiod mouse.clickthreshold > MAX_CLICKTHRESHOLD) {
48846347781Smpech warnx("invalid threshold `%s': max value is %d",
489b47703b0Smiod optarg, MAX_CLICKTHRESHOLD);
490673a75b7Saaron usage();
491673a75b7Saaron }
492673a75b7Saaron break;
493be45c8afSmiod case 'D':
494be45c8afSmiod if ((mouse.ttyname = strdup(optarg)) == NULL)
495be45c8afSmiod logerr(1, "out of memory");
496be45c8afSmiod break;
497673a75b7Saaron case 'M':
498673a75b7Saaron if (!mouse_installmap(optarg)) {
49946347781Smpech warnx("invalid mapping `%s'", optarg);
500673a75b7Saaron usage();
501673a75b7Saaron }
502673a75b7Saaron break;
503673a75b7Saaron default:
504673a75b7Saaron usage();
505673a75b7Saaron }
506673a75b7Saaron }
507be45c8afSmiod
508be45c8afSmiod /*
509be45c8afSmiod * Use defaults if unspecified
510be45c8afSmiod */
511b47703b0Smiod if (mouse.portname == NULL)
512b47703b0Smiod mouse.portname = WSMOUSE_DEV;
513be45c8afSmiod if (mouse.ttyname == NULL)
514be45c8afSmiod mouse.ttyname = DEFAULT_TTY;
515673a75b7Saaron
516be45c8afSmiod if (identify == FALSE) {
517*b7041c07Sderaadt if ((mouse.cfd = open(mouse.ttyname, O_RDWR)) == -1)
518be45c8afSmiod logerr(1, "cannot open %s", mouse.ttyname);
519be45c8afSmiod }
520be45c8afSmiod
521673a75b7Saaron if ((mouse.mfd = open(mouse.portname,
522*b7041c07Sderaadt O_RDONLY | O_NONBLOCK)) == -1)
523673a75b7Saaron logerr(1, "unable to open %s", mouse.portname);
524be45c8afSmiod
525be45c8afSmiod /*
526be45c8afSmiod * Find out whether the mouse device is a wsmouse device
527be45c8afSmiod * or a serial device.
528be45c8afSmiod */
529be45c8afSmiod if (ioctl(mouse.mfd, WSMOUSEIO_GTYPE, &type) != -1)
530be45c8afSmiod mouse.proto = P_WSCONS;
531be45c8afSmiod else {
532673a75b7Saaron if (mouse_identify() == P_UNKNOWN) {
533673a75b7Saaron close(mouse.mfd);
534b47703b0Smiod logerr(1, "cannot determine mouse type on %s",
535b47703b0Smiod mouse.portname);
536673a75b7Saaron }
537673a75b7Saaron }
538673a75b7Saaron
539673a75b7Saaron if (identify == TRUE) {
540be45c8afSmiod if (mouse.proto == P_WSCONS)
541673a75b7Saaron wsmouse_identify();
542673a75b7Saaron else
543673a75b7Saaron printf("serial mouse: %s type\n",
544be45c8afSmiod mouse_name(mouse.proto));
545b47703b0Smiod exit(0);
546673a75b7Saaron }
547673a75b7Saaron
548be45c8afSmiod signal(SIGINT, terminate);
549be45c8afSmiod signal(SIGQUIT, terminate);
550be45c8afSmiod signal(SIGTERM, terminate);
551be45c8afSmiod
552be45c8afSmiod if (mouse.proto == P_WSCONS)
553be45c8afSmiod wsmouse_init();
554be45c8afSmiod else
555673a75b7Saaron mouse_init();
556be45c8afSmiod
557fca39c33Sdjm if (!nodaemon) {
558fca39c33Sdjm openlog(__progname, LOG_PID, LOG_DAEMON);
559fca39c33Sdjm if (daemon(0, 0)) {
560fca39c33Sdjm logerr(1, "failed to become a daemon");
561fca39c33Sdjm } else {
562fca39c33Sdjm background = TRUE;
563fca39c33Sdjm }
564fca39c33Sdjm }
565fca39c33Sdjm
566673a75b7Saaron wsmoused();
567be45c8afSmiod exit(0);
568673a75b7Saaron }
569