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