116566Ssos/** 216566Ssos ** Copyright (c) 1995 Michael Smith, All rights reserved. 316566Ssos ** 416566Ssos ** Redistribution and use in source and binary forms, with or without 516566Ssos ** modification, are permitted provided that the following conditions 616566Ssos ** are met: 716566Ssos ** 1. Redistributions of source code must retain the above copyright 816566Ssos ** notice, this list of conditions and the following disclaimer as 916566Ssos ** the first lines of this file unmodified. 1016566Ssos ** 2. Redistributions in binary form must reproduce the above copyright 1116566Ssos ** notice, this list of conditions and the following disclaimer in the 1216566Ssos ** documentation and/or other materials provided with the distribution. 1316566Ssos ** 3. All advertising materials mentioning features or use of this software 1416566Ssos ** must display the following acknowledgment: 1516566Ssos ** This product includes software developed by Michael Smith. 1616566Ssos ** 4. The name of the author may not be used to endorse or promote products 1716566Ssos ** derived from this software without specific prior written permission. 1816566Ssos ** 1916566Ssos ** 2016566Ssos ** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND ANY 2116566Ssos ** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2216566Ssos ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2316566Ssos ** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE FOR 2416566Ssos ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2516566Ssos ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2616566Ssos ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 2716566Ssos ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2816566Ssos ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 2916566Ssos ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 3016566Ssos ** EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3116566Ssos ** 3216566Ssos **/ 3316566Ssos 3416566Ssos/** 3516566Ssos ** MOUSED.C 3616566Ssos ** 3731604Syokota ** Mouse daemon : listens to a serial port, the bus mouse interface, or 38122605Sdes ** the PS/2 mouse port for mouse data stream, interprets data and passes 3931604Syokota ** ioctls off to the console driver. 4016566Ssos ** 4116566Ssos ** The mouse interface functions are derived closely from the mouse 4216566Ssos ** handler in the XFree86 X server. Many thanks to the XFree86 people 4316566Ssos ** for their great work! 44122605Sdes ** 4516566Ssos **/ 4616566Ssos 47122854Sdes#include <sys/cdefs.h> 48122854Sdes__FBSDID("$FreeBSD$"); 4929849Scharnier 50122853Sdes#include <sys/param.h> 51122853Sdes#include <sys/consio.h> 52122853Sdes#include <sys/mouse.h> 53122853Sdes#include <sys/socket.h> 54122853Sdes#include <sys/stat.h> 55122853Sdes#include <sys/time.h> 56122853Sdes#include <sys/un.h> 57122853Sdes 5858231Syokota#include <ctype.h> 5929849Scharnier#include <err.h> 6029849Scharnier#include <errno.h> 6129849Scharnier#include <fcntl.h> 62149426Spjd#include <libutil.h> 6329849Scharnier#include <limits.h> 64122853Sdes#include <setjmp.h> 65122853Sdes#include <signal.h> 66122853Sdes#include <stdarg.h> 67176889Sjkim#include <stdint.h> 6816566Ssos#include <stdio.h> 6916566Ssos#include <stdlib.h> 7016566Ssos#include <string.h> 71122853Sdes#include <syslog.h> 7216566Ssos#include <termios.h> 7321885Ssos#include <unistd.h> 74167461Sphilip#include <math.h> 7516566Ssos 7631604Syokota#define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */ 7758344Syokota#define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */ 7858344Syokota#define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */ 7959465Syokota#define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */ 80136372Sphilip#define DFLT_SCROLLTHRESHOLD 3 /* 3 pixels */ 81179015Sphilip#define DFLT_SCROLLSPEED 2 /* 2 pixels */ 8231604Syokota 8379430Siedowse/* Abort 3-button emulation delay after this many movement events. */ 8479430Siedowse#define BUTTON2_MAXMOVE 3 8579430Siedowse 8631604Syokota#define TRUE 1 8731604Syokota#define FALSE 0 8831604Syokota 8931604Syokota#define MOUSE_XAXIS (-1) 9031604Syokota#define MOUSE_YAXIS (-2) 9131604Syokota 9248778Syokota/* Logitech PS2++ protocol */ 9348778Syokota#define MOUSE_PS2PLUS_CHECKBITS(b) \ 9448778Syokota ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f)) 9548778Syokota#define MOUSE_PS2PLUS_PACKET_TYPE(b) \ 9648778Syokota (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) 9748778Syokota 9831604Syokota#define ChordMiddle 0x0001 9931604Syokota#define Emulate3Button 0x0002 10031604Syokota#define ClearDTR 0x0004 10131604Syokota#define ClearRTS 0x0008 10231604Syokota#define NoPnP 0x0010 103136372Sphilip#define VirtualScroll 0x0020 104148161Sphilip#define HVirtualScroll 0x0040 105167461Sphilip#define ExponentialAcc 0x0080 106122605Sdes 10731604Syokota#define ID_NONE 0 10831604Syokota#define ID_PORT 1 10931604Syokota#define ID_IF 2 110136372Sphilip#define ID_TYPE 4 11131604Syokota#define ID_MODEL 8 11231604Syokota#define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL) 11331604Syokota 114176854Sjkim/* Operations on timespecs */ 115176854Sjkim#define tsclr(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0) 116176854Sjkim#define tscmp(tvp, uvp, cmp) \ 117176854Sjkim (((tvp)->tv_sec == (uvp)->tv_sec) ? \ 118176854Sjkim ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \ 119176854Sjkim ((tvp)->tv_sec cmp (uvp)->tv_sec)) 120176854Sjkim#define tssub(tvp, uvp, vvp) \ 121176854Sjkim do { \ 122176854Sjkim (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ 123176854Sjkim (vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \ 124176854Sjkim if ((vvp)->tv_nsec < 0) { \ 125176854Sjkim (vvp)->tv_sec--; \ 126176854Sjkim (vvp)->tv_nsec += 1000000000; \ 127176854Sjkim } \ 128176854Sjkim } while (0) 129176854Sjkim 130160523Sstefanf#define debug(...) do { \ 13195629Siedowse if (debug && nodaemon) \ 132160523Sstefanf warnx(__VA_ARGS__); \ 13395629Siedowse} while (0) 13416566Ssos 135160523Sstefanf#define logerr(e, ...) do { \ 136160523Sstefanf log_or_warn(LOG_DAEMON | LOG_ERR, errno, __VA_ARGS__); \ 13795629Siedowse exit(e); \ 13895629Siedowse} while (0) 13931604Syokota 140160523Sstefanf#define logerrx(e, ...) do { \ 141160523Sstefanf log_or_warn(LOG_DAEMON | LOG_ERR, 0, __VA_ARGS__); \ 14295629Siedowse exit(e); \ 14395629Siedowse} while (0) 14431604Syokota 145160523Sstefanf#define logwarn(...) \ 146160523Sstefanf log_or_warn(LOG_DAEMON | LOG_WARNING, errno, __VA_ARGS__) 14731604Syokota 148160523Sstefanf#define logwarnx(...) \ 149160523Sstefanf log_or_warn(LOG_DAEMON | LOG_WARNING, 0, __VA_ARGS__) 15031604Syokota 15131604Syokota/* structures */ 15231604Syokota 15331604Syokota/* symbol table entry */ 15431604Syokotatypedef struct { 155176855Sjkim const char *name; 15631604Syokota int val; 15731604Syokota int val2; 15831604Syokota} symtab_t; 15931604Syokota 16031604Syokota/* serial PnP ID string */ 16131604Syokotatypedef struct { 16231604Syokota int revision; /* PnP revision, 100 for 1.00 */ 163176855Sjkim const char *eisaid; /* EISA ID including mfr ID and product ID */ 16431604Syokota char *serial; /* serial No, optional */ 165176855Sjkim const char *class; /* device class, optional */ 16631604Syokota char *compat; /* list of compatible drivers, optional */ 16731604Syokota char *description; /* product description, optional */ 16831604Syokota int neisaid; /* length of the above fields... */ 16931604Syokota int nserial; 17031604Syokota int nclass; 17131604Syokota int ncompat; 17231604Syokota int ndescription; 17331604Syokota} pnpid_t; 17431604Syokota 17531604Syokota/* global variables */ 17631604Syokota 177227256Sedstatic int debug = 0; 178227256Sedstatic int nodaemon = FALSE; 179227256Sedstatic int background = FALSE; 180227256Sedstatic int paused = FALSE; 181227256Sedstatic int identify = ID_NONE; 182227256Sedstatic int extioctl = FALSE; 183227256Sedstatic const char *pidfile = "/var/run/moused.pid"; 184227256Sedstatic struct pidfh *pfh; 18516566Ssos 186136372Sphilip#define SCROLL_NOTSCROLLING 0 187136372Sphilip#define SCROLL_PREPARE 1 188136372Sphilip#define SCROLL_SCROLLING 2 189136372Sphilip 190136372Sphilipstatic int scroll_state; 191136372Sphilipstatic int scroll_movement; 192148161Sphilipstatic int hscroll_movement; 193136372Sphilip 19431604Syokota/* local variables */ 19516566Ssos 19631604Syokota/* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */ 19731604Syokotastatic symtab_t rifs[] = { 198176855Sjkim { "serial", MOUSE_IF_SERIAL, 0 }, 199176855Sjkim { "bus", MOUSE_IF_BUS, 0 }, 200176855Sjkim { "inport", MOUSE_IF_INPORT, 0 }, 201176855Sjkim { "ps/2", MOUSE_IF_PS2, 0 }, 202176855Sjkim { "sysmouse", MOUSE_IF_SYSMOUSE, 0 }, 203176855Sjkim { "usb", MOUSE_IF_USB, 0 }, 204176855Sjkim { NULL, MOUSE_IF_UNKNOWN, 0 }, 20531604Syokota}; 20616566Ssos 20731604Syokota/* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */ 208176855Sjkimstatic const char *rnames[] = { 20916566Ssos "microsoft", 21016566Ssos "mousesystems", 21131604Syokota "logitech", 21216566Ssos "mmseries", 21331604Syokota "mouseman", 21416566Ssos "busmouse", 21531604Syokota "inportmouse", 21616566Ssos "ps/2", 21718222Speter "mmhitab", 21831604Syokota "glidepoint", 21931604Syokota "intellimouse", 22031604Syokota "thinkingmouse", 22131604Syokota "sysmouse", 22236991Sahasty "x10mouseremote", 22341271Syokota "kidspad", 22493071Swill "versapad", 22593071Swill "jogdial", 22631604Syokota#if notyet 22731604Syokota "mariqua", 22831604Syokota#endif 229145001Smdodd "gtco_digipad", 23016566Ssos NULL 23116566Ssos}; 23216566Ssos 23331604Syokota/* models */ 23431604Syokotastatic symtab_t rmodels[] = { 235176855Sjkim { "NetScroll", MOUSE_MODEL_NETSCROLL, 0 }, 236176855Sjkim { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET, 0 }, 237176855Sjkim { "GlidePoint", MOUSE_MODEL_GLIDEPOINT, 0 }, 238176855Sjkim { "ThinkingMouse", MOUSE_MODEL_THINK, 0 }, 239176855Sjkim { "IntelliMouse", MOUSE_MODEL_INTELLI, 0 }, 240176855Sjkim { "EasyScroll/SmartScroll", MOUSE_MODEL_EASYSCROLL, 0 }, 241176855Sjkim { "MouseMan+", MOUSE_MODEL_MOUSEMANPLUS, 0 }, 242176855Sjkim { "Kidspad", MOUSE_MODEL_KIDSPAD, 0 }, 243176855Sjkim { "VersaPad", MOUSE_MODEL_VERSAPAD, 0 }, 244176855Sjkim { "IntelliMouse Explorer", MOUSE_MODEL_EXPLORER, 0 }, 245176855Sjkim { "4D Mouse", MOUSE_MODEL_4D, 0 }, 246176855Sjkim { "4D+ Mouse", MOUSE_MODEL_4DPLUS, 0 }, 247176855Sjkim { "Synaptics Touchpad", MOUSE_MODEL_SYNAPTICS, 0 }, 248248478Sjkim { "TrackPoint", MOUSE_MODEL_TRACKPOINT, 0 }, 249176855Sjkim { "generic", MOUSE_MODEL_GENERIC, 0 }, 250176855Sjkim { NULL, MOUSE_MODEL_UNKNOWN, 0 }, 25131604Syokota}; 25231604Syokota 25331604Syokota/* PnP EISA/product IDs */ 25431604Syokotastatic symtab_t pnpprod[] = { 25531604Syokota /* Kensignton ThinkingMouse */ 25631604Syokota { "KML0001", MOUSE_PROTO_THINK, MOUSE_MODEL_THINK }, 25731604Syokota /* MS IntelliMouse */ 25831604Syokota { "MSH0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 25931604Syokota /* MS IntelliMouse TrackBall */ 26031604Syokota { "MSH0004", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 26158099Sache /* Tremon Wheel Mouse MUSD */ 26258099Sache { "HTK0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 26333074Sache /* Genius PnP Mouse */ 26433074Sache { "KYE0001", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 26556524Syokota /* MouseSystems SmartScroll Mouse (OEM from Genius?) */ 26656524Syokota { "KYE0002", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL }, 26733074Sache /* Genius NetMouse */ 26833074Sache { "KYE0003", MOUSE_PROTO_INTELLI, MOUSE_MODEL_NET }, 26941271Syokota /* Genius Kidspad, Easypad and other tablets */ 27041271Syokota { "KYE0005", MOUSE_PROTO_KIDSPAD, MOUSE_MODEL_KIDSPAD }, 27131604Syokota /* Genius EZScroll */ 272122605Sdes { "KYEEZ00", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL }, 27356335Syokota /* Logitech Cordless MouseMan Wheel */ 27456335Syokota { "LGI8033", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 27531949Syokota /* Logitech MouseMan (new 4 button model) */ 27631949Syokota { "LGI800C", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 27731604Syokota /* Logitech MouseMan+ */ 27831604Syokota { "LGI8050", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 27931604Syokota /* Logitech FirstMouse+ */ 28031604Syokota { "LGI8051", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 28132634Syokota /* Logitech serial */ 28232634Syokota { "LGI8001", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 28358231Syokota /* A4 Tech 4D/4D+ Mouse */ 28458231Syokota { "A4W0005", MOUSE_PROTO_INTELLI, MOUSE_MODEL_4D }, 28558231Syokota /* 8D Scroll Mouse */ 28658231Syokota { "PEC9802", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 28758328Syokota /* Mitsumi Wireless Scroll Mouse */ 28858328Syokota { "MTM6401", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 28931604Syokota 29031604Syokota /* MS bus */ 29131604Syokota { "PNP0F00", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 29231604Syokota /* MS serial */ 293122605Sdes { "PNP0F01", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 29431604Syokota /* MS InPort */ 295122605Sdes { "PNP0F02", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC }, 29631604Syokota /* MS PS/2 */ 297122605Sdes { "PNP0F03", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 29831604Syokota /* 29931604Syokota * EzScroll returns PNP0F04 in the compatible device field; but it 30031604Syokota * doesn't look compatible... XXX 30131604Syokota */ 302122605Sdes /* MouseSystems */ 303122605Sdes { "PNP0F04", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC }, 304122605Sdes /* MouseSystems */ 305122605Sdes { "PNP0F05", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC }, 30631604Syokota#if notyet 307122605Sdes /* Genius Mouse */ 308122854Sdes { "PNP0F06", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 309122605Sdes /* Genius Mouse */ 310122854Sdes { "PNP0F07", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 31131604Syokota#endif 31231604Syokota /* Logitech serial */ 31331604Syokota { "PNP0F08", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 31431604Syokota /* MS BallPoint serial */ 315122605Sdes { "PNP0F09", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 31631604Syokota /* MS PnP serial */ 317122605Sdes { "PNP0F0A", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 31831604Syokota /* MS PnP BallPoint serial */ 319122605Sdes { "PNP0F0B", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 32031604Syokota /* MS serial comatible */ 321122605Sdes { "PNP0F0C", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 32231604Syokota /* MS InPort comatible */ 323122605Sdes { "PNP0F0D", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC }, 32431604Syokota /* MS PS/2 comatible */ 325122605Sdes { "PNP0F0E", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 32631604Syokota /* MS BallPoint comatible */ 327122605Sdes { "PNP0F0F", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 32831604Syokota#if notyet 32931604Syokota /* TI QuickPort */ 330122854Sdes { "PNP0F10", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 33131604Syokota#endif 33231604Syokota /* MS bus comatible */ 333122605Sdes { "PNP0F11", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 33431604Syokota /* Logitech PS/2 */ 33531604Syokota { "PNP0F12", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 33631604Syokota /* PS/2 */ 33731604Syokota { "PNP0F13", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 33831604Syokota#if notyet 33931604Syokota /* MS Kids Mouse */ 340122854Sdes { "PNP0F14", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 34131604Syokota#endif 342122605Sdes /* Logitech bus */ 34331604Syokota { "PNP0F15", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 34431604Syokota#if notyet 34531604Syokota /* Logitech SWIFT */ 346122854Sdes { "PNP0F16", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 34731604Syokota#endif 34831604Syokota /* Logitech serial compat */ 34931604Syokota { "PNP0F17", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 35031604Syokota /* Logitech bus compatible */ 35131604Syokota { "PNP0F18", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 35231604Syokota /* Logitech PS/2 compatible */ 35331604Syokota { "PNP0F19", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 35431604Syokota#if notyet 35531604Syokota /* Logitech SWIFT compatible */ 356122854Sdes { "PNP0F1A", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 35731604Syokota /* HP Omnibook */ 358122854Sdes { "PNP0F1B", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 35931604Syokota /* Compaq LTE TrackBall PS/2 */ 360122854Sdes { "PNP0F1C", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 36131604Syokota /* Compaq LTE TrackBall serial */ 362122854Sdes { "PNP0F1D", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 36331604Syokota /* MS Kidts Trackball */ 364122854Sdes { "PNP0F1E", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 36531604Syokota#endif 36649967Syokota /* Interlink VersaPad */ 36749967Syokota { "LNK0001", MOUSE_PROTO_VERSAPAD, MOUSE_MODEL_VERSAPAD }, 36831604Syokota 36931604Syokota { NULL, MOUSE_PROTO_UNKNOWN, MOUSE_MODEL_GENERIC }, 37031604Syokota}; 37131604Syokota 37231604Syokota/* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */ 37331604Syokotastatic unsigned short rodentcflags[] = 37416566Ssos{ 375122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* MicroSoft */ 376122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* MouseSystems */ 377122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* Logitech */ 378122854Sdes (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL), /* MMSeries */ 379122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* MouseMan */ 38031604Syokota 0, /* Bus */ 38131604Syokota 0, /* InPort */ 38218222Speter 0, /* PS/2 */ 383122854Sdes (CS8 | CREAD | CLOCAL | HUPCL), /* MM HitTablet */ 384122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* GlidePoint */ 385122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* IntelliMouse */ 386122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* Thinking Mouse */ 387122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* sysmouse */ 388122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* X10 MouseRemote */ 389122854Sdes (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL), /* kidspad etc. */ 390122854Sdes (CS8 | CREAD | CLOCAL | HUPCL), /* VersaPad */ 39193071Swill 0, /* JogDial */ 39231604Syokota#if notyet 393122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* Mariqua */ 39431604Syokota#endif 395145001Smdodd (CS8 | CREAD | HUPCL ), /* GTCO Digi-Pad */ 39616566Ssos}; 39716566Ssos 39831604Syokotastatic struct rodentparam { 39931604Syokota int flags; 400176855Sjkim const char *portname; /* /dev/XXX */ 40131604Syokota int rtype; /* MOUSE_PROTO_XXX */ 40231604Syokota int level; /* operation level: 0 or greater */ 40331604Syokota int baudrate; 40431604Syokota int rate; /* report rate */ 40531604Syokota int resolution; /* MOUSE_RES_XXX or a positive number */ 40658231Syokota int zmap[4]; /* MOUSE_{X|Y}AXIS or a button number */ 40741270Syokota int wmode; /* wheel mode button number */ 40831604Syokota int mfd; /* mouse file descriptor */ 40931604Syokota int cfd; /* /dev/consolectl file descriptor */ 41036991Sahasty int mremsfd; /* mouse remote server file descriptor */ 41136991Sahasty int mremcfd; /* mouse remote client file descriptor */ 412240891Shselasky int is_removable; /* set if device is removable, like USB */ 41331604Syokota long clickthreshold; /* double click speed in msec */ 41458344Syokota long button2timeout; /* 3 button emulation timeout */ 41531604Syokota mousehw_t hw; /* mouse device hardware information */ 41631604Syokota mousemode_t mode; /* protocol information */ 41778770Sgreid float accelx; /* Acceleration in the X axis */ 41878770Sgreid float accely; /* Acceleration in the Y axis */ 419167461Sphilip float expoaccel; /* Exponential acceleration */ 420167461Sphilip float expoffset; /* Movement offset for exponential accel. */ 421170895Sphilip float remainx; /* Remainder on X and Y axis, respectively... */ 422170895Sphilip float remainy; /* ... to compensate for rounding errors. */ 423136372Sphilip int scrollthreshold; /* Movement distance before virtual scrolling */ 424179015Sphilip int scrollspeed; /* Movement distance to rate of scrolling */ 425122605Sdes} rodent = { 426131525Sstefanf .flags = 0, 427131525Sstefanf .portname = NULL, 428131525Sstefanf .rtype = MOUSE_PROTO_UNKNOWN, 429131525Sstefanf .level = -1, 430131525Sstefanf .baudrate = 1200, 431131525Sstefanf .rate = 0, 432131525Sstefanf .resolution = MOUSE_RES_UNKNOWN, 433131525Sstefanf .zmap = { 0, 0, 0, 0 }, 434131525Sstefanf .wmode = 0, 435131525Sstefanf .mfd = -1, 436131525Sstefanf .cfd = -1, 437131525Sstefanf .mremsfd = -1, 438131525Sstefanf .mremcfd = -1, 439240891Shselasky .is_removable = 0, 440131525Sstefanf .clickthreshold = DFLT_CLICKTHRESHOLD, 441131525Sstefanf .button2timeout = DFLT_BUTTON2TIMEOUT, 442131525Sstefanf .accelx = 1.0, 443131525Sstefanf .accely = 1.0, 444167461Sphilip .expoaccel = 1.0, 445167461Sphilip .expoffset = 1.0, 446170895Sphilip .remainx = 0.0, 447170895Sphilip .remainy = 0.0, 448136372Sphilip .scrollthreshold = DFLT_SCROLLTHRESHOLD, 449179015Sphilip .scrollspeed = DFLT_SCROLLSPEED, 45031604Syokota}; 45116566Ssos 45231604Syokota/* button status */ 45358344Syokotastruct button_state { 45431604Syokota int count; /* 0: up, 1: single click, 2: double click,... */ 455176854Sjkim struct timespec ts; /* timestamp on the last button event */ 45658344Syokota}; 457176855Sjkimstatic struct button_state bstate[MOUSE_MAXBUTTON]; /* button state */ 45858344Syokotastatic struct button_state *mstate[MOUSE_MAXBUTTON];/* mapped button st.*/ 45958344Syokotastatic struct button_state zstate[4]; /* Z/W axis state */ 46016566Ssos 46158344Syokota/* state machine for 3 button emulation */ 46258344Syokota 46358344Syokota#define S0 0 /* start */ 46458344Syokota#define S1 1 /* button 1 delayed down */ 46558344Syokota#define S2 2 /* button 3 delayed down */ 46658344Syokota#define S3 3 /* both buttons down -> button 2 down */ 46758344Syokota#define S4 4 /* button 1 delayed up */ 46858344Syokota#define S5 5 /* button 1 down */ 46958344Syokota#define S6 6 /* button 3 down */ 47058344Syokota#define S7 7 /* both buttons down */ 47158344Syokota#define S8 8 /* button 3 delayed up */ 47258344Syokota#define S9 9 /* button 1 or 3 up after S3 */ 47358344Syokota 47458344Syokota#define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0)) 47558344Syokota#define A_TIMEOUT 4 47679430Siedowse#define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st)) 47758344Syokota 47858344Syokotastatic struct { 47958344Syokota int s[A_TIMEOUT + 1]; 48058344Syokota int buttons; 48158344Syokota int mask; 48259090Syokota int timeout; 48358344Syokota} states[10] = { 48458344Syokota /* S0 */ 48559090Syokota { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE }, 48658344Syokota /* S1 */ 48759090Syokota { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE }, 48858344Syokota /* S2 */ 48959090Syokota { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE }, 49058344Syokota /* S3 */ 49159090Syokota { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE }, 49258344Syokota /* S4 */ 49359090Syokota { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE }, 49458344Syokota /* S5 */ 49559090Syokota { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE }, 49658344Syokota /* S6 */ 49759090Syokota { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE }, 49858344Syokota /* S7 */ 49959090Syokota { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE }, 50058344Syokota /* S8 */ 50159090Syokota { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE }, 50258344Syokota /* S9 */ 50359090Syokota { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE }, 50458344Syokota}; 50558344Syokotastatic int mouse_button_state; 506176854Sjkimstatic struct timespec mouse_button_state_ts; 50779430Siedowsestatic int mouse_move_delayed; 50858344Syokota 50931604Syokotastatic jmp_buf env; 51016566Ssos 511176854Sjkimstruct drift_xy { 512176854Sjkim int x; 513176854Sjkim int y; 514176854Sjkim}; 515176854Sjkimstatic int drift_distance = 4; /* max steps X+Y */ 516176854Sjkimstatic int drift_time = 500; /* in 0.5 sec */ 517176854Sjkimstatic struct timespec drift_time_ts; 518176854Sjkimstatic struct timespec drift_2time_ts; /* 2*drift_time */ 519176854Sjkimstatic int drift_after = 4000; /* 4 sec */ 520176854Sjkimstatic struct timespec drift_after_ts; 521150310Sphilipstatic int drift_terminate = FALSE; 522176854Sjkimstatic struct timespec drift_current_ts; 523176854Sjkimstatic struct timespec drift_tmp; 524176854Sjkimstatic struct timespec drift_last_activity = {0, 0}; 525176854Sjkimstatic struct timespec drift_since = {0, 0}; 526176855Sjkimstatic struct drift_xy drift_last = {0, 0}; /* steps in last drift_time */ 527176855Sjkimstatic struct drift_xy drift_previous = {0, 0}; /* steps in prev. drift_time */ 528150310Sphilip 52931604Syokota/* function prototypes */ 53016566Ssos 531170895Sphilipstatic void linacc(int, int, int*, int*); 532167461Sphilipstatic void expoacc(int, int, int*, int*); 53331604Syokotastatic void moused(void); 53431604Syokotastatic void hup(int sig); 53536991Sahastystatic void cleanup(int sig); 536153070Sphilipstatic void pause_mouse(int sig); 53731604Syokotastatic void usage(void); 53895629Siedowsestatic void log_or_warn(int log_pri, int errnum, const char *fmt, ...) 53995629Siedowse __printflike(3, 4); 54031604Syokota 54131604Syokotastatic int r_identify(void); 542176855Sjkimstatic const char *r_if(int type); 543176855Sjkimstatic const char *r_name(int type); 544176855Sjkimstatic const char *r_model(int model); 54531604Syokotastatic void r_init(void); 54631604Syokotastatic int r_protocol(u_char b, mousestatus_t *act); 54758344Syokotastatic int r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans); 54831604Syokotastatic int r_installmap(char *arg); 54931604Syokotastatic void r_map(mousestatus_t *act1, mousestatus_t *act2); 55058344Syokotastatic void r_timestamp(mousestatus_t *act); 55158344Syokotastatic int r_timeout(void); 55231604Syokotastatic void r_click(mousestatus_t *act); 55331604Syokotastatic void setmousespeed(int old, int new, unsigned cflag); 55431604Syokota 55540255Syokotastatic int pnpwakeup1(void); 55640255Syokotastatic int pnpwakeup2(void); 55731604Syokotastatic int pnpgets(char *buf); 55831604Syokotastatic int pnpparse(pnpid_t *id, char *buf, int len); 55931604Syokotastatic symtab_t *pnpproto(pnpid_t *id); 56031604Syokota 561176855Sjkimstatic symtab_t *gettoken(symtab_t *tab, const char *s, int len); 562176855Sjkimstatic const char *gettokenname(symtab_t *tab, int val); 56331604Syokota 564176855Sjkimstatic void mremote_serversetup(void); 56536991Sahastystatic void mremote_clientchg(int add); 56636991Sahasty 567122854Sdesstatic int kidspad(u_char rxc, mousestatus_t *act); 568145001Smdoddstatic int gtco_digipad(u_char, mousestatus_t *); 56941271Syokota 57051287Speterint 57116566Ssosmain(int argc, char *argv[]) 57216566Ssos{ 57331604Syokota int c; 57431604Syokota int i; 57558231Syokota int j; 57616566Ssos 57758344Syokota for (i = 0; i < MOUSE_MAXBUTTON; ++i) 57858344Syokota mstate[i] = &bstate[i]; 57958344Syokota 580179015Sphilip while ((c = getopt(argc, argv, "3A:C:DE:F:HI:L:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1) 58131604Syokota switch(c) { 58231604Syokota 58331604Syokota case '3': 58431604Syokota rodent.flags |= Emulate3Button; 58531604Syokota break; 58631604Syokota 58758344Syokota case 'E': 58858344Syokota rodent.button2timeout = atoi(optarg); 589122605Sdes if ((rodent.button2timeout < 0) || 590122605Sdes (rodent.button2timeout > MAX_BUTTON2TIMEOUT)) { 591122605Sdes warnx("invalid argument `%s'", optarg); 592122605Sdes usage(); 59358344Syokota } 59458344Syokota break; 59558344Syokota 59678770Sgreid case 'a': 59778770Sgreid i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely); 59878770Sgreid if (i == 0) { 599167461Sphilip warnx("invalid linear acceleration argument '%s'", optarg); 60078770Sgreid usage(); 60178770Sgreid } 602122605Sdes 60378770Sgreid if (i == 1) 60478770Sgreid rodent.accely = rodent.accelx; 605122605Sdes 60678770Sgreid break; 607122605Sdes 608167461Sphilip case 'A': 609167461Sphilip rodent.flags |= ExponentialAcc; 610167461Sphilip i = sscanf(optarg, "%f,%f", &rodent.expoaccel, &rodent.expoffset); 611167461Sphilip if (i == 0) { 612167461Sphilip warnx("invalid exponential acceleration argument '%s'", optarg); 613167461Sphilip usage(); 614167461Sphilip } 615167461Sphilip 616167461Sphilip if (i == 1) 617167461Sphilip rodent.expoffset = 1.0; 618167461Sphilip 619167461Sphilip break; 620167461Sphilip 62116566Ssos case 'c': 62216566Ssos rodent.flags |= ChordMiddle; 62316566Ssos break; 62416566Ssos 62516566Ssos case 'd': 62631604Syokota ++debug; 62716566Ssos break; 62816566Ssos 62916566Ssos case 'f': 63031604Syokota nodaemon = TRUE; 63116566Ssos break; 63216566Ssos 63331604Syokota case 'i': 63431604Syokota if (strcmp(optarg, "all") == 0) 635122605Sdes identify = ID_ALL; 63631604Syokota else if (strcmp(optarg, "port") == 0) 637122605Sdes identify = ID_PORT; 63831604Syokota else if (strcmp(optarg, "if") == 0) 639122605Sdes identify = ID_IF; 64031604Syokota else if (strcmp(optarg, "type") == 0) 641122605Sdes identify = ID_TYPE; 64231604Syokota else if (strcmp(optarg, "model") == 0) 643122605Sdes identify = ID_MODEL; 64431604Syokota else { 645122605Sdes warnx("invalid argument `%s'", optarg); 646122605Sdes usage(); 64731604Syokota } 64831604Syokota nodaemon = TRUE; 64931604Syokota break; 65031604Syokota 65131604Syokota case 'l': 65231604Syokota rodent.level = atoi(optarg); 65331604Syokota if ((rodent.level < 0) || (rodent.level > 4)) { 654122605Sdes warnx("invalid argument `%s'", optarg); 655122605Sdes usage(); 65631604Syokota } 65731604Syokota break; 65831604Syokota 65931604Syokota case 'm': 66031604Syokota if (!r_installmap(optarg)) { 661122605Sdes warnx("invalid argument `%s'", optarg); 662122605Sdes usage(); 66331604Syokota } 66431604Syokota break; 66531604Syokota 66616566Ssos case 'p': 66716566Ssos rodent.portname = optarg; 66816566Ssos break; 66916566Ssos 67024377Speter case 'r': 67131604Syokota if (strcmp(optarg, "high") == 0) 672122605Sdes rodent.resolution = MOUSE_RES_HIGH; 67331604Syokota else if (strcmp(optarg, "medium-high") == 0) 674122605Sdes rodent.resolution = MOUSE_RES_HIGH; 67531604Syokota else if (strcmp(optarg, "medium-low") == 0) 676122605Sdes rodent.resolution = MOUSE_RES_MEDIUMLOW; 67731604Syokota else if (strcmp(optarg, "low") == 0) 678122605Sdes rodent.resolution = MOUSE_RES_LOW; 67931604Syokota else if (strcmp(optarg, "default") == 0) 680122605Sdes rodent.resolution = MOUSE_RES_DEFAULT; 68131604Syokota else { 682122605Sdes rodent.resolution = atoi(optarg); 683122605Sdes if (rodent.resolution <= 0) { 684122605Sdes warnx("invalid argument `%s'", optarg); 685122605Sdes usage(); 686122605Sdes } 68731604Syokota } 68824377Speter break; 68924377Speter 69016566Ssos case 's': 69116566Ssos rodent.baudrate = 9600; 69218222Speter break; 69316566Ssos 69441270Syokota case 'w': 69541270Syokota i = atoi(optarg); 69641270Syokota if ((i <= 0) || (i > MOUSE_MAXBUTTON)) { 69741270Syokota warnx("invalid argument `%s'", optarg); 69841270Syokota usage(); 69941270Syokota } 70041270Syokota rodent.wmode = 1 << (i - 1); 70141270Syokota break; 70241270Syokota 70331604Syokota case 'z': 70431604Syokota if (strcmp(optarg, "x") == 0) 70558231Syokota rodent.zmap[0] = MOUSE_XAXIS; 70631604Syokota else if (strcmp(optarg, "y") == 0) 70758231Syokota rodent.zmap[0] = MOUSE_YAXIS; 708122605Sdes else { 70931604Syokota i = atoi(optarg); 710122605Sdes /* 711122605Sdes * Use button i for negative Z axis movement and 71231604Syokota * button (i + 1) for positive Z axis movement. 71331604Syokota */ 71431604Syokota if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) { 715122605Sdes warnx("invalid argument `%s'", optarg); 716122605Sdes usage(); 71731604Syokota } 71858344Syokota rodent.zmap[0] = i; 71958344Syokota rodent.zmap[1] = i + 1; 72058861Syokota debug("optind: %d, optarg: '%s'", optind, optarg); 72158231Syokota for (j = 1; j < 4; ++j) { 72258231Syokota if ((optind >= argc) || !isdigit(*argv[optind])) 72358231Syokota break; 72458231Syokota i = atoi(argv[optind]); 72558231Syokota if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) { 72658231Syokota warnx("invalid argument `%s'", argv[optind]); 72758231Syokota usage(); 72858231Syokota } 72958344Syokota rodent.zmap[j] = i; 73058231Syokota ++optind; 73158231Syokota } 73259090Syokota if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0)) 73358344Syokota rodent.zmap[3] = rodent.zmap[2] + 1; 73431604Syokota } 73518222Speter break; 73618222Speter 73731604Syokota case 'C': 73831604Syokota rodent.clickthreshold = atoi(optarg); 739122605Sdes if ((rodent.clickthreshold < 0) || 740122605Sdes (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) { 741122605Sdes warnx("invalid argument `%s'", optarg); 742122605Sdes usage(); 74331604Syokota } 74431604Syokota break; 74531604Syokota 74618222Speter case 'D': 74731604Syokota rodent.flags |= ClearDTR; 74818222Speter break; 74918222Speter 75031604Syokota case 'F': 75131604Syokota rodent.rate = atoi(optarg); 75231604Syokota if (rodent.rate <= 0) { 753122605Sdes warnx("invalid argument `%s'", optarg); 754122605Sdes usage(); 75531604Syokota } 75631604Syokota break; 75731604Syokota 758148161Sphilip case 'H': 759148161Sphilip rodent.flags |= HVirtualScroll; 760148161Sphilip break; 761176855Sjkim 76234152Sjkh case 'I': 76334152Sjkh pidfile = optarg; 76434152Sjkh break; 76534152Sjkh 766179015Sphilip case 'L': 767179015Sphilip rodent.scrollspeed = atoi(optarg); 768179015Sphilip if (rodent.scrollspeed < 0) { 769179015Sphilip warnx("invalid argument `%s'", optarg); 770179015Sphilip usage(); 771179015Sphilip } 772179015Sphilip break; 773179015Sphilip 77431604Syokota case 'P': 77531604Syokota rodent.flags |= NoPnP; 77631604Syokota break; 77731604Syokota 77831604Syokota case 'R': 77931604Syokota rodent.flags |= ClearRTS; 78031604Syokota break; 78131604Syokota 78218222Speter case 'S': 78318222Speter rodent.baudrate = atoi(optarg); 78431604Syokota if (rodent.baudrate <= 0) { 785122605Sdes warnx("invalid argument `%s'", optarg); 786122605Sdes usage(); 78731604Syokota } 78818222Speter debug("rodent baudrate %d", rodent.baudrate); 78918222Speter break; 79018222Speter 791150310Sphilip case 'T': 792150310Sphilip drift_terminate = TRUE; 793150310Sphilip sscanf(optarg, "%d,%d,%d", &drift_distance, &drift_time, 794150310Sphilip &drift_after); 795150310Sphilip if (drift_distance <= 0 || drift_time <= 0 || drift_after <= 0) { 796150310Sphilip warnx("invalid argument `%s'", optarg); 797150310Sphilip usage(); 798150310Sphilip } 799150310Sphilip debug("terminate drift: distance %d, time %d, after %d", 800150310Sphilip drift_distance, drift_time, drift_after); 801176854Sjkim drift_time_ts.tv_sec = drift_time / 1000; 802176854Sjkim drift_time_ts.tv_nsec = (drift_time % 1000) * 1000000; 803176854Sjkim drift_2time_ts.tv_sec = (drift_time *= 2) / 1000; 804176854Sjkim drift_2time_ts.tv_nsec = (drift_time % 1000) * 1000000; 805176854Sjkim drift_after_ts.tv_sec = drift_after / 1000; 806176854Sjkim drift_after_ts.tv_nsec = (drift_after % 1000) * 1000000; 807150310Sphilip break; 808150310Sphilip 80916566Ssos case 't': 81031949Syokota if (strcmp(optarg, "auto") == 0) { 81131949Syokota rodent.rtype = MOUSE_PROTO_UNKNOWN; 81231949Syokota rodent.flags &= ~NoPnP; 81331949Syokota rodent.level = -1; 81431949Syokota break; 81531949Syokota } 816176855Sjkim for (i = 0; rnames[i] != NULL; i++) 81731949Syokota if (strcmp(optarg, rnames[i]) == 0) { 81816566Ssos rodent.rtype = i; 81931949Syokota rodent.flags |= NoPnP; 82031949Syokota rodent.level = (i == MOUSE_PROTO_SYSMOUSE) ? 1 : 0; 82116566Ssos break; 82216566Ssos } 823176855Sjkim if (rnames[i] == NULL) { 824176855Sjkim warnx("no such mouse type `%s'", optarg); 825176855Sjkim usage(); 826176855Sjkim } 827176855Sjkim break; 82816566Ssos 829136372Sphilip case 'V': 830136372Sphilip rodent.flags |= VirtualScroll; 831136372Sphilip break; 832136372Sphilip case 'U': 833136372Sphilip rodent.scrollthreshold = atoi(optarg); 834136372Sphilip if (rodent.scrollthreshold < 0) { 835136372Sphilip warnx("invalid argument `%s'", optarg); 836136372Sphilip usage(); 837136372Sphilip } 838136372Sphilip break; 839136372Sphilip 84016566Ssos case 'h': 84116566Ssos case '?': 84216566Ssos default: 84316566Ssos usage(); 84416566Ssos } 84516566Ssos 84659090Syokota /* fix Z axis mapping */ 84759090Syokota for (i = 0; i < 4; ++i) { 84859090Syokota if (rodent.zmap[i] > 0) { 84959090Syokota for (j = 0; j < MOUSE_MAXBUTTON; ++j) { 85059090Syokota if (mstate[j] == &bstate[rodent.zmap[i] - 1]) 85159090Syokota mstate[j] = &zstate[i]; 85259090Syokota } 85359090Syokota rodent.zmap[i] = 1 << (rodent.zmap[i] - 1); 85459090Syokota } 85559090Syokota } 85659090Syokota 85731604Syokota /* the default port name */ 85831604Syokota switch(rodent.rtype) { 85931604Syokota 86031604Syokota case MOUSE_PROTO_INPORT: 861122605Sdes /* INPORT and BUS are the same... */ 86231604Syokota rodent.rtype = MOUSE_PROTO_BUS; 863102413Scharnier /* FALLTHROUGH */ 86431604Syokota case MOUSE_PROTO_BUS: 86516566Ssos if (!rodent.portname) 86616566Ssos rodent.portname = "/dev/mse0"; 86716566Ssos break; 86831604Syokota 86931604Syokota case MOUSE_PROTO_PS2: 87016566Ssos if (!rodent.portname) 87116566Ssos rodent.portname = "/dev/psm0"; 87216566Ssos break; 87331604Syokota 87416566Ssos default: 87516566Ssos if (rodent.portname) 87616566Ssos break; 87729849Scharnier warnx("no port name specified"); 87816566Ssos usage(); 87916566Ssos } 88016566Ssos 881240891Shselasky if (strncmp(rodent.portname, "/dev/ums", 8) == 0) 882240891Shselasky rodent.is_removable = 1; 883122630Sdes 88431604Syokota for (;;) { 88531604Syokota if (setjmp(env) == 0) { 88631604Syokota signal(SIGHUP, hup); 88736991Sahasty signal(SIGINT , cleanup); 88836991Sahasty signal(SIGQUIT, cleanup); 88936991Sahasty signal(SIGTERM, cleanup); 890153070Sphilip signal(SIGUSR1, pause_mouse); 891240891Shselasky 892240891Shselasky rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK); 893122630Sdes if (rodent.mfd == -1) 894122605Sdes logerr(1, "unable to open %s", rodent.portname); 895122605Sdes if (r_identify() == MOUSE_PROTO_UNKNOWN) { 896122605Sdes logwarnx("cannot determine mouse type on %s", rodent.portname); 897122605Sdes close(rodent.mfd); 898122605Sdes rodent.mfd = -1; 899122605Sdes } 90031604Syokota 90131604Syokota /* print some information */ 902122605Sdes if (identify != ID_NONE) { 90331604Syokota if (identify == ID_ALL) 904122605Sdes printf("%s %s %s %s\n", 905122605Sdes rodent.portname, r_if(rodent.hw.iftype), 906122605Sdes r_name(rodent.rtype), r_model(rodent.hw.model)); 90731604Syokota else if (identify & ID_PORT) 90831604Syokota printf("%s\n", rodent.portname); 90931604Syokota else if (identify & ID_IF) 91031604Syokota printf("%s\n", r_if(rodent.hw.iftype)); 91131604Syokota else if (identify & ID_TYPE) 91231604Syokota printf("%s\n", r_name(rodent.rtype)); 91331604Syokota else if (identify & ID_MODEL) 91431604Syokota printf("%s\n", r_model(rodent.hw.model)); 91531604Syokota exit(0); 91631604Syokota } else { 917122605Sdes debug("port: %s interface: %s type: %s model: %s", 91831604Syokota rodent.portname, r_if(rodent.hw.iftype), 91931604Syokota r_name(rodent.rtype), r_model(rodent.hw.model)); 92031604Syokota } 92131604Syokota 92231604Syokota if (rodent.mfd == -1) { 923122605Sdes /* 924122605Sdes * We cannot continue because of error. Exit if the 925122605Sdes * program has not become a daemon. Otherwise, block 926218909Sbrucec * until the user corrects the problem and issues SIGHUP. 927122605Sdes */ 928122605Sdes if (!background) 92931604Syokota exit(1); 930122605Sdes sigpause(0); 93131604Syokota } 93231604Syokota 933122605Sdes r_init(); /* call init function */ 93431604Syokota moused(); 93531604Syokota } 93631604Syokota 93731604Syokota if (rodent.mfd != -1) 93831604Syokota close(rodent.mfd); 93931604Syokota if (rodent.cfd != -1) 94031604Syokota close(rodent.cfd); 94131604Syokota rodent.mfd = rodent.cfd = -1; 942240891Shselasky if (rodent.is_removable) 943240891Shselasky exit(0); 94416566Ssos } 94531604Syokota /* NOT REACHED */ 94616566Ssos 94731604Syokota exit(0); 94831604Syokota} 94916566Ssos 950167461Sphilip/* 951170895Sphilip * Function to calculate linear acceleration. 952170895Sphilip * 953170895Sphilip * If there are any rounding errors, the remainder 954170895Sphilip * is stored in the remainx and remainy variables 955170895Sphilip * and taken into account upon the next movement. 956170895Sphilip */ 957170895Sphilip 958170895Sphilipstatic void 959170895Sphiliplinacc(int dx, int dy, int *movex, int *movey) 960170895Sphilip{ 961170895Sphilip float fdx, fdy; 962170895Sphilip 963170895Sphilip if (dx == 0 && dy == 0) { 964170895Sphilip *movex = *movey = 0; 965170895Sphilip return; 966170895Sphilip } 967170895Sphilip fdx = dx * rodent.accelx + rodent.remainx; 968170895Sphilip fdy = dy * rodent.accely + rodent.remainy; 969170895Sphilip *movex = lround(fdx); 970170895Sphilip *movey = lround(fdy); 971170895Sphilip rodent.remainx = fdx - *movex; 972170895Sphilip rodent.remainy = fdy - *movey; 973170895Sphilip} 974170895Sphilip 975170895Sphilip/* 976167461Sphilip * Function to calculate exponential acceleration. 977170895Sphilip * (Also includes linear acceleration if enabled.) 978167461Sphilip * 979167461Sphilip * In order to give a smoother behaviour, we record the four 980167461Sphilip * most recent non-zero movements and use their average value 981167461Sphilip * to calculate the acceleration. 982167461Sphilip */ 983167461Sphilip 98431604Syokotastatic void 985167461Sphilipexpoacc(int dx, int dy, int *movex, int *movey) 986167461Sphilip{ 987167461Sphilip static float lastlength[3] = {0.0, 0.0, 0.0}; 988167461Sphilip float fdx, fdy, length, lbase, accel; 989167461Sphilip 990167461Sphilip if (dx == 0 && dy == 0) { 991167461Sphilip *movex = *movey = 0; 992167461Sphilip return; 993167461Sphilip } 994167461Sphilip fdx = dx * rodent.accelx; 995167461Sphilip fdy = dy * rodent.accely; 996167461Sphilip length = sqrtf((fdx * fdx) + (fdy * fdy)); /* Pythagoras */ 997167461Sphilip length = (length + lastlength[0] + lastlength[1] + lastlength[2]) / 4; 998167461Sphilip lbase = length / rodent.expoffset; 999167461Sphilip accel = powf(lbase, rodent.expoaccel) / lbase; 1000170895Sphilip fdx = fdx * accel + rodent.remainx; 1001170895Sphilip fdy = fdy * accel + rodent.remainy; 1002170895Sphilip *movex = lroundf(fdx); 1003170895Sphilip *movey = lroundf(fdy); 1004170895Sphilip rodent.remainx = fdx - *movex; 1005170895Sphilip rodent.remainy = fdy - *movey; 1006167461Sphilip lastlength[2] = lastlength[1]; 1007167461Sphilip lastlength[1] = lastlength[0]; 1008167461Sphilip lastlength[0] = length; /* Insert new average, not original length! */ 1009167461Sphilip} 1010167461Sphilip 1011167461Sphilipstatic void 101231604Syokotamoused(void) 101331604Syokota{ 101431604Syokota struct mouse_info mouse; 101558344Syokota mousestatus_t action0; /* original mouse action */ 1016228990Suqs mousestatus_t action; /* interim buffer */ 101731604Syokota mousestatus_t action2; /* mapped action */ 101858344Syokota struct timeval timeout; 101931604Syokota fd_set fds; 102031604Syokota u_char b; 1021149426Spjd pid_t mpid; 102258344Syokota int flags; 102358344Syokota int c; 102458344Syokota int i; 102531604Syokota 102631604Syokota if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1) 102795629Siedowse logerr(1, "cannot open /dev/consolectl"); 102831604Syokota 102995629Siedowse if (!nodaemon && !background) { 1030150214Spjd pfh = pidfile_open(pidfile, 0600, &mpid); 1031149426Spjd if (pfh == NULL) { 1032149426Spjd if (errno == EEXIST) 1033149426Spjd logerrx(1, "moused already running, pid: %d", mpid); 1034149426Spjd logwarn("cannot open pid file"); 1035149426Spjd } 103631604Syokota if (daemon(0, 0)) { 1037149426Spjd int saved_errno = errno; 1038149426Spjd pidfile_remove(pfh); 1039149426Spjd errno = saved_errno; 104095629Siedowse logerr(1, "failed to become a daemon"); 104131604Syokota } else { 104231604Syokota background = TRUE; 1043149426Spjd pidfile_write(pfh); 104416566Ssos } 104595629Siedowse } 104616566Ssos 104731604Syokota /* clear mouse data */ 104858344Syokota bzero(&action0, sizeof(action0)); 104931604Syokota bzero(&action, sizeof(action)); 105031604Syokota bzero(&action2, sizeof(action2)); 105131604Syokota bzero(&mouse, sizeof(mouse)); 105258344Syokota mouse_button_state = S0; 1053176854Sjkim clock_gettime(CLOCK_MONOTONIC_FAST, &mouse_button_state_ts); 105479430Siedowse mouse_move_delayed = 0; 105558344Syokota for (i = 0; i < MOUSE_MAXBUTTON; ++i) { 105658344Syokota bstate[i].count = 0; 1057176854Sjkim bstate[i].ts = mouse_button_state_ts; 105858344Syokota } 1059176855Sjkim for (i = 0; i < (int)(sizeof(zstate) / sizeof(zstate[0])); ++i) { 106058344Syokota zstate[i].count = 0; 1061176854Sjkim zstate[i].ts = mouse_button_state_ts; 106258344Syokota } 106331604Syokota 106431604Syokota /* choose which ioctl command to use */ 106531604Syokota mouse.operation = MOUSE_MOTION_EVENT; 106631604Syokota extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0); 106731604Syokota 106831604Syokota /* process mouse data */ 106958344Syokota timeout.tv_sec = 0; 107058344Syokota timeout.tv_usec = 20000; /* 20 msec */ 107131604Syokota for (;;) { 107231604Syokota 107321885Ssos FD_ZERO(&fds); 107431604Syokota FD_SET(rodent.mfd, &fds); 107558344Syokota if (rodent.mremsfd >= 0) 107658344Syokota FD_SET(rodent.mremsfd, &fds); 107758344Syokota if (rodent.mremcfd >= 0) 107858344Syokota FD_SET(rodent.mremcfd, &fds); 107936991Sahasty 108058344Syokota c = select(FD_SETSIZE, &fds, NULL, NULL, 1081209214Smav ((rodent.flags & Emulate3Button) && 1082209214Smav S_DELAYED(mouse_button_state)) ? &timeout : NULL); 108358344Syokota if (c < 0) { /* error */ 108495629Siedowse logwarn("failed to read from mouse"); 108536991Sahasty continue; 108658344Syokota } else if (c == 0) { /* timeout */ 108758344Syokota /* assert(rodent.flags & Emulate3Button) */ 108858344Syokota action0.button = action0.obutton; 108958344Syokota action0.dx = action0.dy = action0.dz = 0; 109058344Syokota action0.flags = flags = 0; 109158344Syokota if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) { 109258344Syokota if (debug > 2) 109358344Syokota debug("flags:%08x buttons:%08x obuttons:%08x", 109458344Syokota action.flags, action.button, action.obutton); 109558344Syokota } else { 109658344Syokota action0.obutton = action0.button; 109758344Syokota continue; 109858344Syokota } 109958344Syokota } else { 110058344Syokota /* MouseRemote client connect/disconnect */ 110158344Syokota if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) { 110258344Syokota mremote_clientchg(TRUE); 110358344Syokota continue; 110458344Syokota } 110558344Syokota if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) { 110658344Syokota mremote_clientchg(FALSE); 110758344Syokota continue; 110858344Syokota } 110958344Syokota /* mouse movement */ 111058344Syokota if (read(rodent.mfd, &b, 1) == -1) { 111158344Syokota if (errno == EWOULDBLOCK) 111258344Syokota continue; 111358344Syokota else 111458344Syokota return; 111558344Syokota } 111658344Syokota if ((flags = r_protocol(b, &action0)) == 0) 111758344Syokota continue; 1118136372Sphilip 1119148161Sphilip if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) { 1120136372Sphilip /* Allow middle button drags to scroll up and down */ 1121136372Sphilip if (action0.button == MOUSE_BUTTON2DOWN) { 1122136372Sphilip if (scroll_state == SCROLL_NOTSCROLLING) { 1123136372Sphilip scroll_state = SCROLL_PREPARE; 1124179015Sphilip scroll_movement = hscroll_movement = 0; 1125136372Sphilip debug("PREPARING TO SCROLL"); 1126136372Sphilip } 1127136372Sphilip debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x", 1128136372Sphilip action.flags, action.button, action.obutton); 1129136372Sphilip } else { 1130136372Sphilip debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x", 1131136372Sphilip action.flags, action.button, action.obutton); 1132136372Sphilip 1133136372Sphilip /* This isn't a middle button down... move along... */ 1134176855Sjkim if (scroll_state == SCROLL_SCROLLING) { 1135176855Sjkim /* 1136136372Sphilip * We were scrolling, someone let go of button 2. 1137136372Sphilip * Now turn autoscroll off. 1138136372Sphilip */ 1139136372Sphilip scroll_state = SCROLL_NOTSCROLLING; 1140136372Sphilip debug("DONE WITH SCROLLING / %d", scroll_state); 1141136372Sphilip } else if (scroll_state == SCROLL_PREPARE) { 1142136372Sphilip mousestatus_t newaction = action0; 1143136372Sphilip 1144136372Sphilip /* We were preparing to scroll, but we never moved... */ 1145136372Sphilip r_timestamp(&action0); 1146136372Sphilip r_statetrans(&action0, &newaction, 1147136372Sphilip A(newaction.button & MOUSE_BUTTON1DOWN, 1148136372Sphilip action0.button & MOUSE_BUTTON3DOWN)); 1149136372Sphilip 1150136372Sphilip /* Send middle down */ 1151136372Sphilip newaction.button = MOUSE_BUTTON2DOWN; 1152136372Sphilip r_click(&newaction); 1153136372Sphilip 1154136372Sphilip /* Send middle up */ 1155136372Sphilip r_timestamp(&newaction); 1156136372Sphilip newaction.obutton = newaction.button; 1157136372Sphilip newaction.button = action0.button; 1158136372Sphilip r_click(&newaction); 1159176855Sjkim } 1160136372Sphilip } 1161136372Sphilip } 1162136372Sphilip 116358344Syokota r_timestamp(&action0); 1164122605Sdes r_statetrans(&action0, &action, 1165122605Sdes A(action0.button & MOUSE_BUTTON1DOWN, 1166122605Sdes action0.button & MOUSE_BUTTON3DOWN)); 116758344Syokota debug("flags:%08x buttons:%08x obuttons:%08x", action.flags, 116858344Syokota action.button, action.obutton); 116936991Sahasty } 117058344Syokota action0.obutton = action0.button; 117158344Syokota flags &= MOUSE_POSCHANGED; 117258344Syokota flags |= action.obutton ^ action.button; 117358344Syokota action.flags = flags; 117436991Sahasty 117558344Syokota if (flags) { /* handler detected action */ 117631604Syokota r_map(&action, &action2); 117731604Syokota debug("activity : buttons 0x%08x dx %d dy %d dz %d", 117831604Syokota action2.button, action2.dx, action2.dy, action2.dz); 117931604Syokota 1180148161Sphilip if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) { 1181176855Sjkim /* 1182136372Sphilip * If *only* the middle button is pressed AND we are moving 1183136372Sphilip * the stick/trackpoint/nipple, scroll! 1184136372Sphilip */ 1185136372Sphilip if (scroll_state == SCROLL_PREPARE) { 1186179015Sphilip /* Middle button down, waiting for movement threshold */ 1187179015Sphilip if (action2.dy || action2.dx) { 1188179015Sphilip if (rodent.flags & VirtualScroll) { 1189179015Sphilip scroll_movement += action2.dy; 1190179015Sphilip if (scroll_movement < -rodent.scrollthreshold) { 1191179015Sphilip scroll_state = SCROLL_SCROLLING; 1192179015Sphilip } else if (scroll_movement > rodent.scrollthreshold) { 1193179015Sphilip scroll_state = SCROLL_SCROLLING; 1194179015Sphilip } 1195179015Sphilip } 1196179015Sphilip if (rodent.flags & HVirtualScroll) { 1197179015Sphilip hscroll_movement += action2.dx; 1198179015Sphilip if (hscroll_movement < -rodent.scrollthreshold) { 1199179015Sphilip scroll_state = SCROLL_SCROLLING; 1200179015Sphilip } else if (hscroll_movement > rodent.scrollthreshold) { 1201179015Sphilip scroll_state = SCROLL_SCROLLING; 1202179015Sphilip } 1203179015Sphilip } 1204179015Sphilip if (scroll_state == SCROLL_SCROLLING) scroll_movement = hscroll_movement = 0; 1205179015Sphilip } 1206179015Sphilip } else if (scroll_state == SCROLL_SCROLLING) { 1207148161Sphilip if (rodent.flags & VirtualScroll) { 1208148161Sphilip scroll_movement += action2.dy; 1209148161Sphilip debug("SCROLL: %d", scroll_movement); 1210179015Sphilip if (scroll_movement < -rodent.scrollspeed) { 1211148161Sphilip /* Scroll down */ 1212148161Sphilip action2.dz = -1; 1213148161Sphilip scroll_movement = 0; 1214148161Sphilip } 1215179015Sphilip else if (scroll_movement > rodent.scrollspeed) { 1216148161Sphilip /* Scroll up */ 1217148161Sphilip action2.dz = 1; 1218148161Sphilip scroll_movement = 0; 1219148161Sphilip } 1220148161Sphilip } 1221148161Sphilip if (rodent.flags & HVirtualScroll) { 1222148161Sphilip hscroll_movement += action2.dx; 1223148161Sphilip debug("HORIZONTAL SCROLL: %d", hscroll_movement); 1224136372Sphilip 1225179015Sphilip if (hscroll_movement < -rodent.scrollspeed) { 1226148161Sphilip action2.dz = -2; 1227148161Sphilip hscroll_movement = 0; 1228148161Sphilip } 1229179015Sphilip else if (hscroll_movement > rodent.scrollspeed) { 1230148161Sphilip action2.dz = 2; 1231148161Sphilip hscroll_movement = 0; 1232148161Sphilip } 1233148161Sphilip } 1234148161Sphilip 1235136372Sphilip /* Don't move while scrolling */ 1236136372Sphilip action2.dx = action2.dy = 0; 1237136372Sphilip } 1238136372Sphilip } 1239136372Sphilip 1240150310Sphilip if (drift_terminate) { 1241176855Sjkim if ((flags & MOUSE_POSCHANGED) == 0 || action.dz || action2.dz) 1242176854Sjkim drift_last_activity = drift_current_ts; 1243150310Sphilip else { 1244150310Sphilip /* X or/and Y movement only - possibly drift */ 1245176854Sjkim tssub(&drift_current_ts, &drift_last_activity, &drift_tmp); 1246176854Sjkim if (tscmp(&drift_tmp, &drift_after_ts, >)) { 1247176854Sjkim tssub(&drift_current_ts, &drift_since, &drift_tmp); 1248176854Sjkim if (tscmp(&drift_tmp, &drift_time_ts, <)) { 1249150310Sphilip drift_last.x += action2.dx; 1250150310Sphilip drift_last.y += action2.dy; 1251150310Sphilip } else { 1252150310Sphilip /* discard old accumulated steps (drift) */ 1253176854Sjkim if (tscmp(&drift_tmp, &drift_2time_ts, >)) 1254150310Sphilip drift_previous.x = drift_previous.y = 0; 1255150310Sphilip else 1256150310Sphilip drift_previous = drift_last; 1257150310Sphilip drift_last.x = action2.dx; 1258150310Sphilip drift_last.y = action2.dy; 1259176854Sjkim drift_since = drift_current_ts; 1260150310Sphilip } 1261150310Sphilip if (abs(drift_last.x) + abs(drift_last.y) 1262150310Sphilip > drift_distance) { 1263150310Sphilip /* real movement, pass all accumulated steps */ 1264150310Sphilip action2.dx = drift_previous.x + drift_last.x; 1265150310Sphilip action2.dy = drift_previous.y + drift_last.y; 1266150310Sphilip /* and reset accumulators */ 1267176854Sjkim tsclr(&drift_since); 1268150310Sphilip drift_last.x = drift_last.y = 0; 1269150310Sphilip /* drift_previous will be cleared at next movement*/ 1270176854Sjkim drift_last_activity = drift_current_ts; 1271150310Sphilip } else { 1272150310Sphilip continue; /* don't pass current movement to 1273150310Sphilip * console driver */ 1274150310Sphilip } 1275150310Sphilip } 1276150310Sphilip } 1277150310Sphilip } 1278150310Sphilip 127931604Syokota if (extioctl) { 1280136372Sphilip /* Defer clicks until we aren't VirtualScroll'ing. */ 1281176855Sjkim if (scroll_state == SCROLL_NOTSCROLLING) 1282136372Sphilip r_click(&action2); 1283136372Sphilip 1284122605Sdes if (action2.flags & MOUSE_POSCHANGED) { 1285122605Sdes mouse.operation = MOUSE_MOTION_EVENT; 1286122605Sdes mouse.u.data.buttons = action2.button; 1287167461Sphilip if (rodent.flags & ExponentialAcc) { 1288167461Sphilip expoacc(action2.dx, action2.dy, 1289167461Sphilip &mouse.u.data.x, &mouse.u.data.y); 1290167461Sphilip } 1291167461Sphilip else { 1292170895Sphilip linacc(action2.dx, action2.dy, 1293170895Sphilip &mouse.u.data.x, &mouse.u.data.y); 1294167461Sphilip } 1295122605Sdes mouse.u.data.z = action2.dz; 129631604Syokota if (debug < 2) 1297153070Sphilip if (!paused) 1298153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 1299122605Sdes } 130031604Syokota } else { 1301122605Sdes mouse.operation = MOUSE_ACTION; 1302122605Sdes mouse.u.data.buttons = action2.button; 1303167461Sphilip if (rodent.flags & ExponentialAcc) { 1304167461Sphilip expoacc(action2.dx, action2.dy, 1305167461Sphilip &mouse.u.data.x, &mouse.u.data.y); 1306167461Sphilip } 1307167461Sphilip else { 1308170895Sphilip linacc(action2.dx, action2.dy, 1309170895Sphilip &mouse.u.data.x, &mouse.u.data.y); 1310167461Sphilip } 1311122605Sdes mouse.u.data.z = action2.dz; 131231604Syokota if (debug < 2) 1313153070Sphilip if (!paused) 1314153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 131531604Syokota } 131631604Syokota 1317108533Sschweikh /* 1318108533Sschweikh * If the Z axis movement is mapped to an imaginary physical 131931604Syokota * button, we need to cook up a corresponding button `up' event 132031604Syokota * after sending a button `down' event. 132131604Syokota */ 1322122605Sdes if ((rodent.zmap[0] > 0) && (action.dz != 0)) { 132331604Syokota action.obutton = action.button; 132431604Syokota action.dx = action.dy = action.dz = 0; 1325122605Sdes r_map(&action, &action2); 1326122605Sdes debug("activity : buttons 0x%08x dx %d dy %d dz %d", 132731604Syokota action2.button, action2.dx, action2.dy, action2.dz); 132831604Syokota 1329122605Sdes if (extioctl) { 1330122605Sdes r_click(&action2); 1331122605Sdes } else { 1332122605Sdes mouse.operation = MOUSE_ACTION; 1333122605Sdes mouse.u.data.buttons = action2.button; 133431604Syokota mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0; 133531604Syokota if (debug < 2) 1336153070Sphilip if (!paused) 1337153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 1338122605Sdes } 133931604Syokota } 134016566Ssos } 134116566Ssos } 134231604Syokota /* NOT REACHED */ 1343122605Sdes} 134416566Ssos 134531604Syokotastatic void 1346176855Sjkimhup(__unused int sig) 134731604Syokota{ 134831604Syokota longjmp(env, 1); 134931604Syokota} 135016566Ssos 1351122605Sdesstatic void 1352176855Sjkimcleanup(__unused int sig) 135336991Sahasty{ 135436991Sahasty if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM) 135536991Sahasty unlink(_PATH_MOUSEREMOTE); 135636991Sahasty exit(0); 135736991Sahasty} 135836991Sahasty 1359153070Sphilipstatic void 1360176855Sjkimpause_mouse(__unused int sig) 1361153070Sphilip{ 1362153070Sphilip paused = !paused; 1363153070Sphilip} 1364153070Sphilip 136516566Ssos/** 136616566Ssos ** usage 136716566Ssos ** 136816566Ssos ** Complain, and free the CPU for more worthy tasks 136916566Ssos **/ 137031604Syokotastatic void 137116566Ssosusage(void) 137216566Ssos{ 1373150310Sphilip fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 137458344Syokota "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]", 1375150310Sphilip " [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]", 1376150310Sphilip " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]", 1377150310Sphilip " [-T distance[,time[,after]]] -p <port>", 137881364Sdougb " moused [-d] -i <port|if|type|model|all> -p <port>"); 137916566Ssos exit(1); 138016566Ssos} 138116566Ssos 138295629Siedowse/* 138395629Siedowse * Output an error message to syslog or stderr as appropriate. If 138495629Siedowse * `errnum' is non-zero, append its string form to the message. 138595629Siedowse */ 138695629Siedowsestatic void 138795629Siedowselog_or_warn(int log_pri, int errnum, const char *fmt, ...) 138895629Siedowse{ 138995629Siedowse va_list ap; 139095629Siedowse char buf[256]; 139195629Siedowse 139295629Siedowse va_start(ap, fmt); 139395629Siedowse vsnprintf(buf, sizeof(buf), fmt, ap); 139495629Siedowse va_end(ap); 139595629Siedowse if (errnum) { 139695629Siedowse strlcat(buf, ": ", sizeof(buf)); 139795629Siedowse strlcat(buf, strerror(errnum), sizeof(buf)); 139895629Siedowse } 139995629Siedowse 140095629Siedowse if (background) 140195629Siedowse syslog(log_pri, "%s", buf); 140295629Siedowse else 140395629Siedowse warnx("%s", buf); 140495629Siedowse} 140595629Siedowse 140616566Ssos/** 140716566Ssos ** Mouse interface code, courtesy of XFree86 3.1.2. 140816566Ssos ** 140916566Ssos ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm 141016566Ssos ** to clean, reformat and rationalise naming, it's quite possible that 141116566Ssos ** some things in here have been broken. 141216566Ssos ** 141316566Ssos ** I hope not 8) 141416566Ssos ** 141516566Ssos ** The following code is derived from a module marked : 141616566Ssos **/ 141716566Ssos 141816566Ssos/* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */ 141916566Ssos/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28 142016566Ssos 17:03:40 dawes Exp $ */ 142116566Ssos/* 142216566Ssos * 142316566Ssos * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 142416566Ssos * Copyright 1993 by David Dawes <dawes@physics.su.oz.au> 142516566Ssos * 142616566Ssos * Permission to use, copy, modify, distribute, and sell this software and its 142716566Ssos * documentation for any purpose is hereby granted without fee, provided that 142816566Ssos * the above copyright notice appear in all copies and that both that 142916566Ssos * copyright notice and this permission notice appear in supporting 143016566Ssos * documentation, and that the names of Thomas Roell and David Dawes not be 143116566Ssos * used in advertising or publicity pertaining to distribution of the 143216566Ssos * software without specific, written prior permission. Thomas Roell 143316566Ssos * and David Dawes makes no representations about the suitability of this 143416566Ssos * software for any purpose. It is provided "as is" without express or 143516566Ssos * implied warranty. 143616566Ssos * 143716566Ssos * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 143816566Ssos * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 143916566Ssos * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY 144016566Ssos * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 144116566Ssos * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 144216566Ssos * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 144316566Ssos * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 144416566Ssos * 144516566Ssos */ 144616566Ssos 144731604Syokota/** 144831604Syokota ** GlidePoint support from XFree86 3.2. 144931604Syokota ** Derived from the module: 145031604Syokota **/ 145116566Ssos 145231604Syokota/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */ 145331604Syokota/* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */ 145431604Syokota 145531604Syokota/* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */ 145631604Syokotastatic unsigned char proto[][7] = { 145731604Syokota /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */ 1458122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */ 145931604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */ 146031604Syokota { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */ 146131604Syokota { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */ 1462122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* MouseMan */ 146331604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */ 146431604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */ 146531604Syokota { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */ 146631604Syokota { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */ 1467122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */ 1468122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */ 1469122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */ 147031604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */ 1471122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* X10 MouseRem */ 147241271Syokota { 0x80, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* KIDSPAD */ 147349967Syokota { 0xc3, 0xc0, 0x00, 0x00, 6, 0x00, 0xff }, /* VersaPad */ 147493071Swill { 0x00, 0x00, 0x00, 0x00, 1, 0x00, 0xff }, /* JogDial */ 147531604Syokota#if notyet 147631604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */ 147731604Syokota#endif 147831604Syokota}; 147931604Syokotastatic unsigned char cur_proto[7]; 148031604Syokota 148131604Syokotastatic int 148231604Syokotar_identify(void) 148331604Syokota{ 148431604Syokota char pnpbuf[256]; /* PnP identifier string may be up to 256 bytes long */ 148531604Syokota pnpid_t pnpid; 148631604Syokota symtab_t *t; 148731604Syokota int level; 148831604Syokota int len; 148931604Syokota 149031604Syokota /* set the driver operation level, if applicable */ 149131604Syokota if (rodent.level < 0) 149231604Syokota rodent.level = 1; 149331604Syokota ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level); 149431604Syokota rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0; 149531604Syokota 149631604Syokota /* 1497122605Sdes * Interrogate the driver and get some intelligence on the device... 149831604Syokota * The following ioctl functions are not always supported by device 149931604Syokota * drivers. When the driver doesn't support them, we just trust the 150031604Syokota * user to supply valid information. 150131604Syokota */ 150231604Syokota rodent.hw.iftype = MOUSE_IF_UNKNOWN; 150331604Syokota rodent.hw.model = MOUSE_MODEL_GENERIC; 150431604Syokota ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw); 150531604Syokota 150631604Syokota if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1507122605Sdes bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 150831604Syokota rodent.mode.protocol = MOUSE_PROTO_UNKNOWN; 150931604Syokota rodent.mode.rate = -1; 151031604Syokota rodent.mode.resolution = MOUSE_RES_UNKNOWN; 151131604Syokota rodent.mode.accelfactor = 0; 151231604Syokota rodent.mode.level = 0; 151331604Syokota if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) { 1514176855Sjkim if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN || 1515176855Sjkim rodent.mode.protocol >= (int)(sizeof(proto) / sizeof(proto[0]))) { 151631604Syokota logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol); 1517176855Sjkim return (MOUSE_PROTO_UNKNOWN); 1518122605Sdes } else { 151931604Syokota /* INPORT and BUS are the same... */ 152031604Syokota if (rodent.mode.protocol == MOUSE_PROTO_INPORT) 1521122605Sdes rodent.mode.protocol = MOUSE_PROTO_BUS; 152231604Syokota if (rodent.mode.protocol != rodent.rtype) { 152331604Syokota /* Hmm, the driver doesn't agree with the user... */ 1524122605Sdes if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1525122605Sdes logwarnx("mouse type mismatch (%s != %s), %s is assumed", 1526122605Sdes r_name(rodent.mode.protocol), r_name(rodent.rtype), 1527122605Sdes r_name(rodent.mode.protocol)); 1528122605Sdes rodent.rtype = rodent.mode.protocol; 1529122605Sdes bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 153031604Syokota } 1531122605Sdes } 1532122605Sdes cur_proto[4] = rodent.mode.packetsize; 1533122605Sdes cur_proto[0] = rodent.mode.syncmask[0]; /* header byte bit mask */ 1534122605Sdes cur_proto[1] = rodent.mode.syncmask[1]; /* header bit pattern */ 153531604Syokota } 153631604Syokota 1537108470Sschweikh /* maybe this is a PnP mouse... */ 153831604Syokota if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) { 153931604Syokota 1540122605Sdes if (rodent.flags & NoPnP) 1541176855Sjkim return (rodent.rtype); 154231604Syokota if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len)) 1543176855Sjkim return (rodent.rtype); 154431604Syokota 1545122605Sdes debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'", 1546122605Sdes pnpid.neisaid, pnpid.neisaid, pnpid.eisaid, 1547122605Sdes pnpid.ncompat, pnpid.ncompat, pnpid.compat, 154831604Syokota pnpid.ndescription, pnpid.ndescription, pnpid.description); 154931604Syokota 155031604Syokota /* we have a valid PnP serial device ID */ 1551122605Sdes rodent.hw.iftype = MOUSE_IF_SERIAL; 155231604Syokota t = pnpproto(&pnpid); 155331604Syokota if (t != NULL) { 1554122605Sdes rodent.mode.protocol = t->val; 1555122605Sdes rodent.hw.model = t->val2; 155631604Syokota } else { 1557122605Sdes rodent.mode.protocol = MOUSE_PROTO_UNKNOWN; 155831604Syokota } 155931604Syokota if (rodent.mode.protocol == MOUSE_PROTO_INPORT) 156031604Syokota rodent.mode.protocol = MOUSE_PROTO_BUS; 156131604Syokota 1562122605Sdes /* make final adjustment */ 156331604Syokota if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) { 156431604Syokota if (rodent.mode.protocol != rodent.rtype) { 156531604Syokota /* Hmm, the device doesn't agree with the user... */ 1566122605Sdes if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1567122605Sdes logwarnx("mouse type mismatch (%s != %s), %s is assumed", 1568122605Sdes r_name(rodent.mode.protocol), r_name(rodent.rtype), 1569122605Sdes r_name(rodent.mode.protocol)); 1570122605Sdes rodent.rtype = rodent.mode.protocol; 1571122605Sdes bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 157231604Syokota } 157331604Syokota } 157431604Syokota } 157531604Syokota 157631604Syokota debug("proto params: %02x %02x %02x %02x %d %02x %02x", 1577122605Sdes cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3], 157831604Syokota cur_proto[4], cur_proto[5], cur_proto[6]); 157931604Syokota 1580176855Sjkim return (rodent.rtype); 158131604Syokota} 158231604Syokota 1583176855Sjkimstatic const char * 158431604Syokotar_if(int iftype) 158531604Syokota{ 158631604Syokota 1587176855Sjkim return (gettokenname(rifs, iftype)); 158831604Syokota} 158931604Syokota 1590176855Sjkimstatic const char * 159131604Syokotar_name(int type) 159231604Syokota{ 1593176855Sjkim const char *unknown = "unknown"; 1594176855Sjkim 1595176855Sjkim return (type == MOUSE_PROTO_UNKNOWN || 1596176855Sjkim type >= (int)(sizeof(rnames) / sizeof(rnames[0])) ? 1597176855Sjkim unknown : rnames[type]); 159831604Syokota} 159931604Syokota 1600176855Sjkimstatic const char * 160131604Syokotar_model(int model) 160231604Syokota{ 160331604Syokota 1604176855Sjkim return (gettokenname(rmodels, model)); 160531604Syokota} 160631604Syokota 160731604Syokotastatic void 160816566Ssosr_init(void) 160916566Ssos{ 161049967Syokota unsigned char buf[16]; /* scrach buffer */ 161131604Syokota fd_set fds; 1612176855Sjkim const char *s; 161331604Syokota char c; 161431604Syokota int i; 161531604Syokota 161616566Ssos /** 1617122605Sdes ** This comment is a little out of context here, but it contains 161816566Ssos ** some useful information... 161916566Ssos ******************************************************************** 162016566Ssos ** 162116566Ssos ** The following lines take care of the Logitech MouseMan protocols. 162216566Ssos ** 162316566Ssos ** NOTE: There are different versions of both MouseMan and TrackMan! 162416566Ssos ** Hence I add another protocol P_LOGIMAN, which the user can 162516566Ssos ** specify as MouseMan in his XF86Config file. This entry was 162616566Ssos ** formerly handled as a special case of P_MS. However, people 162716566Ssos ** who don't have the middle button problem, can still specify 162816566Ssos ** Microsoft and use P_MS. 162916566Ssos ** 163016566Ssos ** By default, these mice should use a 3 byte Microsoft protocol 163116566Ssos ** plus a 4th byte for the middle button. However, the mouse might 163216566Ssos ** have switched to a different protocol before we use it, so I send 163316566Ssos ** the proper sequence just in case. 163416566Ssos ** 163516566Ssos ** NOTE: - all commands to (at least the European) MouseMan have to 163616566Ssos ** be sent at 1200 Baud. 163716566Ssos ** - each command starts with a '*'. 163816566Ssos ** - whenever the MouseMan receives a '*', it will switch back 163916566Ssos ** to 1200 Baud. Hence I have to select the desired protocol 164016566Ssos ** first, then select the baud rate. 164116566Ssos ** 164216566Ssos ** The protocols supported by the (European) MouseMan are: 164316566Ssos ** - 5 byte packed binary protocol, as with the Mouse Systems 164416566Ssos ** mouse. Selected by sequence "*U". 164516566Ssos ** - 2 button 3 byte MicroSoft compatible protocol. Selected 164616566Ssos ** by sequence "*V". 164716566Ssos ** - 3 button 3+1 byte MicroSoft compatible protocol (default). 164816566Ssos ** Selected by sequence "*X". 164916566Ssos ** 165016566Ssos ** The following baud rates are supported: 165116566Ssos ** - 1200 Baud (default). Selected by sequence "*n". 165216566Ssos ** - 9600 Baud. Selected by sequence "*q". 165316566Ssos ** 165416566Ssos ** Selecting a sample rate is no longer supported with the MouseMan! 165516566Ssos ** Some additional lines in xf86Config.c take care of ill configured 165616566Ssos ** baud rates and sample rates. (The user will get an error.) 165716566Ssos */ 165816566Ssos 165931604Syokota switch (rodent.rtype) { 166031604Syokota 166131604Syokota case MOUSE_PROTO_LOGI: 1662122605Sdes /* 166331604Syokota * The baud rate selection command must be sent at the current 1664122605Sdes * baud rate; try all likely settings 166531604Syokota */ 166631604Syokota setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]); 166731604Syokota setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]); 166831604Syokota setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]); 166931604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 167031604Syokota /* select MM series data format */ 167131604Syokota write(rodent.mfd, "S", 1); 167231604Syokota setmousespeed(rodent.baudrate, rodent.baudrate, 167331604Syokota rodentcflags[MOUSE_PROTO_MM]); 167431604Syokota /* select report rate/frequency */ 167531604Syokota if (rodent.rate <= 0) write(rodent.mfd, "O", 1); 167631604Syokota else if (rodent.rate <= 15) write(rodent.mfd, "J", 1); 167731604Syokota else if (rodent.rate <= 27) write(rodent.mfd, "K", 1); 167831604Syokota else if (rodent.rate <= 42) write(rodent.mfd, "L", 1); 167931604Syokota else if (rodent.rate <= 60) write(rodent.mfd, "R", 1); 168031604Syokota else if (rodent.rate <= 85) write(rodent.mfd, "M", 1); 168131604Syokota else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1); 168231604Syokota else write(rodent.mfd, "N", 1); 168331604Syokota break; 168431604Syokota 168531604Syokota case MOUSE_PROTO_LOGIMOUSEMAN: 168631604Syokota /* The command must always be sent at 1200 baud */ 168731604Syokota setmousespeed(1200, 1200, rodentcflags[rodent.rtype]); 168816566Ssos write(rodent.mfd, "*X", 2); 168931604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 169031604Syokota break; 169118222Speter 169231604Syokota case MOUSE_PROTO_HITTAB: 169331604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 169418222Speter 169531604Syokota /* 169631604Syokota * Initialize Hitachi PUMA Plus - Model 1212E to desired settings. 169731604Syokota * The tablet must be configured to be in MM mode, NO parity, 169831604Syokota * Binary Format. xf86Info.sampleRate controls the sensativity 169931604Syokota * of the tablet. We only use this tablet for it's 4-button puck 170031604Syokota * so we don't run in "Absolute Mode" 170131604Syokota */ 170231604Syokota write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */ 170331604Syokota usleep(50000); 170431604Syokota write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */ 170531604Syokota usleep(50000); 170631604Syokota write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */ 170731604Syokota usleep(50000); 170831604Syokota write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */ 170931604Syokota usleep(50000); 171031604Syokota write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */ 171131604Syokota usleep(50000); 171231604Syokota write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */ 171331604Syokota usleep(50000); 171418222Speter 171531604Syokota /* Resolution is in 'lines per inch' on the Hitachi tablet */ 1716122605Sdes if (rodent.resolution == MOUSE_RES_LOW) c = 'g'; 171731604Syokota else if (rodent.resolution == MOUSE_RES_MEDIUMLOW) c = 'e'; 171831604Syokota else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH) c = 'h'; 171931604Syokota else if (rodent.resolution == MOUSE_RES_HIGH) c = 'd'; 1720122605Sdes else if (rodent.resolution <= 40) c = 'g'; 1721122605Sdes else if (rodent.resolution <= 100) c = 'd'; 1722122605Sdes else if (rodent.resolution <= 200) c = 'e'; 1723122605Sdes else if (rodent.resolution <= 500) c = 'h'; 1724122605Sdes else if (rodent.resolution <= 1000) c = 'j'; 1725122605Sdes else c = 'd'; 172631604Syokota write(rodent.mfd, &c, 1); 172731604Syokota usleep(50000); 172818222Speter 172931604Syokota write(rodent.mfd, "\021", 1); /* Resume DATA output */ 173031604Syokota break; 173131604Syokota 173231604Syokota case MOUSE_PROTO_THINK: 173331604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 173431604Syokota /* the PnP ID string may be sent again, discard it */ 173531604Syokota usleep(200000); 173631604Syokota i = FREAD; 173731604Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 173831604Syokota /* send the command to initialize the beast */ 173931604Syokota for (s = "E5E5"; *s; ++s) { 174031604Syokota write(rodent.mfd, s, 1); 174131604Syokota FD_ZERO(&fds); 174231604Syokota FD_SET(rodent.mfd, &fds); 174331604Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0) 174431604Syokota break; 174531604Syokota read(rodent.mfd, &c, 1); 174631604Syokota debug("%c", c); 174731604Syokota if (c != *s) 1748122605Sdes break; 174918222Speter } 175031604Syokota break; 175131604Syokota 175293071Swill case MOUSE_PROTO_JOGDIAL: 175393071Swill break; 175431604Syokota case MOUSE_PROTO_MSC: 175531604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 175631604Syokota if (rodent.flags & ClearDTR) { 175731604Syokota i = TIOCM_DTR; 175831604Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 1759122605Sdes } 1760122605Sdes if (rodent.flags & ClearRTS) { 176131604Syokota i = TIOCM_RTS; 176231604Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 1763122605Sdes } 176431604Syokota break; 176531604Syokota 176631726Syokota case MOUSE_PROTO_SYSMOUSE: 176731726Syokota if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE) 176831726Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1769102413Scharnier /* FALLTHROUGH */ 177031726Syokota 177131604Syokota case MOUSE_PROTO_BUS: 177231604Syokota case MOUSE_PROTO_INPORT: 177331604Syokota case MOUSE_PROTO_PS2: 177431604Syokota if (rodent.rate >= 0) 177531604Syokota rodent.mode.rate = rodent.rate; 177631604Syokota if (rodent.resolution != MOUSE_RES_UNKNOWN) 177731604Syokota rodent.mode.resolution = rodent.resolution; 177831604Syokota ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode); 177931604Syokota break; 178031604Syokota 178136991Sahasty case MOUSE_PROTO_X10MOUSEREM: 178236991Sahasty mremote_serversetup(); 178336991Sahasty setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 178436991Sahasty break; 178536991Sahasty 178636991Sahasty 178749967Syokota case MOUSE_PROTO_VERSAPAD: 178849967Syokota tcsendbreak(rodent.mfd, 0); /* send break for 400 msec */ 178949967Syokota i = FREAD; 179049967Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 179149967Syokota for (i = 0; i < 7; ++i) { 179249967Syokota FD_ZERO(&fds); 179349967Syokota FD_SET(rodent.mfd, &fds); 179449967Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0) 179549967Syokota break; 179649967Syokota read(rodent.mfd, &c, 1); 179749967Syokota buf[i] = c; 179849967Syokota } 179949967Syokota debug("%s\n", buf); 180049967Syokota if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r')) 180149967Syokota break; 180249967Syokota setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]); 180349967Syokota tcsendbreak(rodent.mfd, 0); /* send break for 400 msec again */ 180449967Syokota for (i = 0; i < 7; ++i) { 180549967Syokota FD_ZERO(&fds); 180649967Syokota FD_SET(rodent.mfd, &fds); 180749967Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0) 180849967Syokota break; 180949967Syokota read(rodent.mfd, &c, 1); 181049967Syokota debug("%c", c); 181149967Syokota if (c != buf[i]) 181249967Syokota break; 181349967Syokota } 181449967Syokota i = FREAD; 181549967Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 181649967Syokota break; 181749967Syokota 181831604Syokota default: 181931604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 182031604Syokota break; 182116566Ssos } 182216566Ssos} 182316566Ssos 182431604Syokotastatic int 182531604Syokotar_protocol(u_char rBuf, mousestatus_t *act) 182616566Ssos{ 182731604Syokota /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 1828122605Sdes static int butmapmss[4] = { /* Microsoft, MouseMan, GlidePoint, 182931604Syokota IntelliMouse, Thinking Mouse */ 1830122605Sdes 0, 1831122605Sdes MOUSE_BUTTON3DOWN, 1832122605Sdes MOUSE_BUTTON1DOWN, 1833122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 183431604Syokota }; 1835122605Sdes static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint, 183631604Syokota Thinking Mouse */ 1837122605Sdes 0, 1838122605Sdes MOUSE_BUTTON4DOWN, 1839122605Sdes MOUSE_BUTTON2DOWN, 1840122605Sdes MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN, 184131604Syokota }; 184231604Syokota /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 184331604Syokota static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse, 184431604Syokota MouseMan+ */ 1845122605Sdes 0, 1846122605Sdes MOUSE_BUTTON2DOWN, 1847122605Sdes MOUSE_BUTTON4DOWN, 1848122605Sdes MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN, 184931604Syokota }; 185031604Syokota /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */ 1851122605Sdes static int butmapmsc[8] = { /* MouseSystems, MMSeries, Logitech, 185231604Syokota Bus, sysmouse */ 1853122605Sdes 0, 1854122605Sdes MOUSE_BUTTON3DOWN, 1855122605Sdes MOUSE_BUTTON2DOWN, 1856122605Sdes MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 1857122605Sdes MOUSE_BUTTON1DOWN, 1858122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 185931604Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 186031604Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 186131604Syokota }; 186231604Syokota /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 186331604Syokota static int butmapps2[8] = { /* PS/2 */ 1864122605Sdes 0, 1865122605Sdes MOUSE_BUTTON1DOWN, 1866122605Sdes MOUSE_BUTTON3DOWN, 1867122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1868122605Sdes MOUSE_BUTTON2DOWN, 1869122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 187031604Syokota MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 187131604Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 187231604Syokota }; 187331604Syokota /* for Hitachi tablet */ 187431604Syokota static int butmaphit[8] = { /* MM HitTablet */ 1875122605Sdes 0, 1876122605Sdes MOUSE_BUTTON3DOWN, 1877122605Sdes MOUSE_BUTTON2DOWN, 1878122605Sdes MOUSE_BUTTON1DOWN, 1879122605Sdes MOUSE_BUTTON4DOWN, 1880122605Sdes MOUSE_BUTTON5DOWN, 1881122605Sdes MOUSE_BUTTON6DOWN, 1882122605Sdes MOUSE_BUTTON7DOWN, 188331604Syokota }; 188449967Syokota /* for serial VersaPad */ 188549967Syokota static int butmapversa[8] = { /* VersaPad */ 1886122605Sdes 0, 1887122605Sdes 0, 1888122605Sdes MOUSE_BUTTON3DOWN, 1889122605Sdes MOUSE_BUTTON3DOWN, 1890122605Sdes MOUSE_BUTTON1DOWN, 1891122605Sdes MOUSE_BUTTON1DOWN, 1892122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1893122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 189449967Syokota }; 189549967Syokota /* for PS/2 VersaPad */ 189649967Syokota static int butmapversaps2[8] = { /* VersaPad */ 1897122605Sdes 0, 1898122605Sdes MOUSE_BUTTON3DOWN, 1899122605Sdes 0, 1900122605Sdes MOUSE_BUTTON3DOWN, 1901122605Sdes MOUSE_BUTTON1DOWN, 1902122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1903122605Sdes MOUSE_BUTTON1DOWN, 1904122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 190549967Syokota }; 190616566Ssos static int pBufP = 0; 190716566Ssos static unsigned char pBuf[8]; 190849967Syokota static int prev_x, prev_y; 190949967Syokota static int on = FALSE; 191049967Syokota int x, y; 191116566Ssos 191216566Ssos debug("received char 0x%x",(int)rBuf); 191341271Syokota if (rodent.rtype == MOUSE_PROTO_KIDSPAD) 1914176855Sjkim return (kidspad(rBuf, act)); 1915145001Smdodd if (rodent.rtype == MOUSE_PROTO_GTCO_DIGIPAD) 1916176855Sjkim return (gtco_digipad(rBuf, act)); 191716566Ssos 191816566Ssos /* 191916566Ssos * Hack for resyncing: We check here for a package that is: 192016566Ssos * a) illegal (detected by wrong data-package header) 192116566Ssos * b) invalid (0x80 == -128 and that might be wrong for MouseSystems) 192216566Ssos * c) bad header-package 192316566Ssos * 192416566Ssos * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of 192516566Ssos * -128 are allowed, but since they are very seldom we can easily 192616566Ssos * use them as package-header with no button pressed. 192716566Ssos * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore, 192816566Ssos * 0x80 is not valid as a header byte. For a PS/2 mouse we skip 192916566Ssos * checking data bytes. 193016566Ssos * For resyncing a PS/2 mouse we require the two most significant 193116566Ssos * bits in the header byte to be 0. These are the overflow bits, 193216566Ssos * and in case of an overflow we actually lose sync. Overflows 193316566Ssos * are very rare, however, and we quickly gain sync again after 193416566Ssos * an overflow condition. This is the best we can do. (Actually, 193516566Ssos * we could use bit 0x08 in the header byte for resyncing, since 193616566Ssos * that bit is supposed to be always on, but nobody told 193716566Ssos * Microsoft...) 193816566Ssos */ 193916566Ssos 194031604Syokota if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 && 194131604Syokota ((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80)) 194216566Ssos { 194316566Ssos pBufP = 0; /* skip package */ 194416566Ssos } 1945122605Sdes 194631604Syokota if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1]) 1947176855Sjkim return (0); 194831604Syokota 194931604Syokota /* is there an extra data byte? */ 195031604Syokota if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1]) 195116566Ssos { 195216566Ssos /* 195316566Ssos * Hack for Logitech MouseMan Mouse - Middle button 195416566Ssos * 195516566Ssos * Unfortunately this mouse has variable length packets: the standard 195616566Ssos * Microsoft 3 byte packet plus an optional 4th byte whenever the 195716566Ssos * middle button status changes. 195816566Ssos * 195916566Ssos * We have already processed the standard packet with the movement 196016566Ssos * and button info. Now post an event message with the old status 196116566Ssos * of the left and right buttons and the updated middle button. 196216566Ssos */ 196316566Ssos 196416566Ssos /* 196516566Ssos * Even worse, different MouseMen and TrackMen differ in the 4th 196616566Ssos * byte: some will send 0x00/0x20, others 0x01/0x21, or even 196716566Ssos * 0x02/0x22, so I have to strip off the lower bits. 1968122605Sdes * 1969122605Sdes * [JCH-96/01/21] 1970122605Sdes * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte" 1971122605Sdes * and it is activated by tapping the glidepad with the finger! 8^) 1972122605Sdes * We map it to bit bit3, and the reverse map in xf86Events just has 1973122605Sdes * to be extended so that it is identified as Button 4. The lower 1974122605Sdes * half of the reverse-map may remain unchanged. 197516566Ssos */ 197631604Syokota 1977122605Sdes /* 197831604Syokota * [KY-97/08/03] 197972645Sasmodai * Receive the fourth byte only when preceding three bytes have 198031604Syokota * been detected (pBufP >= cur_proto[4]). In the previous 198131604Syokota * versions, the test was pBufP == 0; thus, we may have mistakingly 1982122605Sdes * received a byte even if we didn't see anything preceding 198331604Syokota * the byte. 198431604Syokota */ 198531604Syokota 198631604Syokota if ((rBuf & cur_proto[5]) != cur_proto[6]) { 1987122605Sdes pBufP = 0; 1988176855Sjkim return (0); 198916566Ssos } 199016566Ssos 199131604Syokota switch (rodent.rtype) { 199231604Syokota#if notyet 199331604Syokota case MOUSE_PROTO_MARIQUA: 1994122605Sdes /* 199531604Syokota * This mouse has 16! buttons in addition to the standard 199631604Syokota * three of them. They return 0x10 though 0x1f in the 199731604Syokota * so-called `ten key' mode and 0x30 though 0x3f in the 1998122605Sdes * `function key' mode. As there are only 31 bits for 199931604Syokota * button state (including the standard three), we ignore 200031604Syokota * the bit 0x20 and don't distinguish the two modes. 200131604Syokota */ 200231604Syokota act->dx = act->dy = act->dz = 0; 200331604Syokota act->obutton = act->button; 200431604Syokota rBuf &= 0x1f; 200531604Syokota act->button = (1 << (rBuf - 13)) 2006122605Sdes | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 2007122605Sdes /* 2008122605Sdes * FIXME: this is a button "down" event. There needs to be 200931604Syokota * a corresponding button "up" event... XXX 201031604Syokota */ 201131604Syokota break; 201231604Syokota#endif /* notyet */ 201393071Swill case MOUSE_PROTO_JOGDIAL: 201493071Swill break; 201531604Syokota 201631604Syokota /* 201731604Syokota * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse 201831604Syokota * always send the fourth byte, whereas the fourth byte is 2019122605Sdes * optional for GlidePoint and ThinkingMouse. The fourth byte 2020122605Sdes * is also optional for MouseMan+ and FirstMouse+ in their 2021122605Sdes * native mode. It is always sent if they are in the IntelliMouse 202231604Syokota * compatible mode. 2023122605Sdes */ 202431604Syokota case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse, 202531604Syokota MouseMan+ */ 202631604Syokota act->dx = act->dy = 0; 202731604Syokota act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f); 202858231Syokota if ((act->dz >= 7) || (act->dz <= -7)) 202958231Syokota act->dz = 0; 203031604Syokota act->obutton = act->button; 203131604Syokota act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4] 203231604Syokota | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 203331604Syokota break; 203431604Syokota 203531604Syokota default: 203631604Syokota act->dx = act->dy = act->dz = 0; 203731604Syokota act->obutton = act->button; 203831604Syokota act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4] 203931604Syokota | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 204031604Syokota break; 204131604Syokota } 204231604Syokota 204331604Syokota act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0) 204431604Syokota | (act->obutton ^ act->button); 2045122605Sdes pBufP = 0; 2046176855Sjkim return (act->flags); 204716566Ssos } 2048122605Sdes 204931604Syokota if (pBufP >= cur_proto[4]) 205031604Syokota pBufP = 0; 205116566Ssos pBuf[pBufP++] = rBuf; 205231604Syokota if (pBufP != cur_proto[4]) 2053176855Sjkim return (0); 2054122605Sdes 205516566Ssos /* 205616566Ssos * assembly full package 205716566Ssos */ 205816566Ssos 205931604Syokota debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x", 2060122605Sdes cur_proto[4], 2061122605Sdes pBuf[0], pBuf[1], pBuf[2], pBuf[3], 206231604Syokota pBuf[4], pBuf[5], pBuf[6], pBuf[7]); 206316566Ssos 206431604Syokota act->dz = 0; 206531604Syokota act->obutton = act->button; 2066122605Sdes switch (rodent.rtype) 206716566Ssos { 206831604Syokota case MOUSE_PROTO_MS: /* Microsoft */ 206931604Syokota case MOUSE_PROTO_LOGIMOUSEMAN: /* MouseMan/TrackMan */ 207036991Sahasty case MOUSE_PROTO_X10MOUSEREM: /* X10 MouseRemote */ 207134074Syokota act->button = act->obutton & MOUSE_BUTTON4DOWN; 207216566Ssos if (rodent.flags & ChordMiddle) 207334074Syokota act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS) 2074122605Sdes ? MOUSE_BUTTON2DOWN 207531604Syokota : butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 207616566Ssos else 207734074Syokota act->button |= (act->obutton & MOUSE_BUTTON2DOWN) 207831604Syokota | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 2079122605Sdes 208036991Sahasty /* Send X10 btn events to remote client (ensure -128-+127 range) */ 2081122605Sdes if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) && 208236991Sahasty ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) { 208336991Sahasty if (rodent.mremcfd >= 0) { 2084122605Sdes unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) | 208536991Sahasty (pBuf[1] & 0x3F)); 2086122854Sdes write(rodent.mremcfd, &key, 1); 208736991Sahasty } 2088176855Sjkim return (0); 208936991Sahasty } 209036991Sahasty 209196930Sknu act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); 209296930Sknu act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); 209316566Ssos break; 209431604Syokota 209531604Syokota case MOUSE_PROTO_GLIDEPOINT: /* GlidePoint */ 209631604Syokota case MOUSE_PROTO_THINK: /* ThinkingMouse */ 209731604Syokota case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse, 209831604Syokota MouseMan+ */ 209931604Syokota act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN)) 2100122605Sdes | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 210196930Sknu act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); 210296930Sknu act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); 210331604Syokota break; 2104122605Sdes 210531604Syokota case MOUSE_PROTO_MSC: /* MouseSystems Corp */ 210631604Syokota#if notyet 210731604Syokota case MOUSE_PROTO_MARIQUA: /* Mariqua */ 210831604Syokota#endif 210931604Syokota act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS]; 211096930Sknu act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]); 211196930Sknu act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4])); 211216566Ssos break; 211393071Swill 211493071Swill case MOUSE_PROTO_JOGDIAL: /* JogDial */ 211593071Swill if (rBuf == 0x6c) 211696930Sknu act->dz = -1; 211793071Swill if (rBuf == 0x72) 211896930Sknu act->dz = 1; 211993071Swill if (rBuf == 0x64) 212093071Swill act->button = MOUSE_BUTTON1DOWN; 212193071Swill if (rBuf == 0x75) 212293071Swill act->button = 0; 212393071Swill break; 212493071Swill 212531604Syokota case MOUSE_PROTO_HITTAB: /* MM HitTablet */ 212631604Syokota act->button = butmaphit[pBuf[0] & 0x07]; 212731604Syokota act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1]; 212831604Syokota act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2]; 212918222Speter break; 213018222Speter 213131604Syokota case MOUSE_PROTO_MM: /* MM Series */ 213231604Syokota case MOUSE_PROTO_LOGI: /* Logitech Mice */ 213331604Syokota act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS]; 213431604Syokota act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1]; 213531604Syokota act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2]; 213616566Ssos break; 2137122605Sdes 213849967Syokota case MOUSE_PROTO_VERSAPAD: /* VersaPad */ 213949967Syokota act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3]; 214049967Syokota act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 214149967Syokota act->dx = act->dy = 0; 214249967Syokota if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) { 214349967Syokota on = FALSE; 214449967Syokota break; 214549967Syokota } 214649967Syokota x = (pBuf[2] << 6) | pBuf[1]; 214749967Syokota if (x & 0x800) 214849967Syokota x -= 0x1000; 214949967Syokota y = (pBuf[4] << 6) | pBuf[3]; 215049967Syokota if (y & 0x800) 215149967Syokota y -= 0x1000; 215249967Syokota if (on) { 215349967Syokota act->dx = prev_x - x; 215449967Syokota act->dy = prev_y - y; 215549967Syokota } else { 215649967Syokota on = TRUE; 215749967Syokota } 215849967Syokota prev_x = x; 215949967Syokota prev_y = y; 216049967Syokota break; 216149967Syokota 216231604Syokota case MOUSE_PROTO_BUS: /* Bus */ 216331604Syokota case MOUSE_PROTO_INPORT: /* InPort */ 216431604Syokota act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS]; 216596930Sknu act->dx = (signed char)pBuf[1]; 216696930Sknu act->dy = - (signed char)pBuf[2]; 216716566Ssos break; 216816566Ssos 216931604Syokota case MOUSE_PROTO_PS2: /* PS/2 */ 217031604Syokota act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS]; 217131604Syokota act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ? pBuf[1] - 256 : pBuf[1]; 217231604Syokota act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ? -(pBuf[2] - 256) : -pBuf[2]; 217331604Syokota /* 217431604Syokota * Moused usually operates the psm driver at the operation level 1 217531604Syokota * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol. 2176122605Sdes * The following code takes effect only when the user explicitly 2177122605Sdes * requets the level 2 at which wheel movement and additional button 217831604Syokota * actions are encoded in model-dependent formats. At the level 0 217931604Syokota * the following code is no-op because the psm driver says the model 218031604Syokota * is MOUSE_MODEL_GENERIC. 218131604Syokota */ 218231604Syokota switch (rodent.hw.model) { 218358231Syokota case MOUSE_MODEL_EXPLORER: 218458231Syokota /* wheel and additional button data is in the fourth byte */ 218558231Syokota act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG) 218658231Syokota ? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f); 218758231Syokota act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN) 218858231Syokota ? MOUSE_BUTTON4DOWN : 0; 218958231Syokota act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN) 219058231Syokota ? MOUSE_BUTTON5DOWN : 0; 219158231Syokota break; 219231604Syokota case MOUSE_MODEL_INTELLI: 219331604Syokota case MOUSE_MODEL_NET: 219431604Syokota /* wheel data is in the fourth byte */ 219596930Sknu act->dz = (signed char)pBuf[3]; 219658231Syokota if ((act->dz >= 7) || (act->dz <= -7)) 219758231Syokota act->dz = 0; 219858231Syokota /* some compatible mice may have additional buttons */ 219958231Syokota act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN) 220058231Syokota ? MOUSE_BUTTON4DOWN : 0; 220158231Syokota act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN) 220258231Syokota ? MOUSE_BUTTON5DOWN : 0; 220331604Syokota break; 220431604Syokota case MOUSE_MODEL_MOUSEMANPLUS: 220548778Syokota if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) 220648778Syokota && (abs(act->dx) > 191) 220748778Syokota && MOUSE_PS2PLUS_CHECKBITS(pBuf)) { 220831604Syokota /* the extended data packet encodes button and wheel events */ 220948778Syokota switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) { 221048778Syokota case 1: 221148778Syokota /* wheel data packet */ 221248778Syokota act->dx = act->dy = 0; 221348778Syokota if (pBuf[2] & 0x80) { 221448778Syokota /* horizontal roller count - ignore it XXX*/ 221548778Syokota } else { 221648778Syokota /* vertical roller count */ 221748778Syokota act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG) 221848778Syokota ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); 221948778Syokota } 222048778Syokota act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN) 222148778Syokota ? MOUSE_BUTTON4DOWN : 0; 222248778Syokota act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN) 222348778Syokota ? MOUSE_BUTTON5DOWN : 0; 222448778Syokota break; 222548778Syokota case 2: 222658231Syokota /* this packet type is reserved by Logitech */ 222758231Syokota /* 222858231Syokota * IBM ScrollPoint Mouse uses this packet type to 222958231Syokota * encode both vertical and horizontal scroll movement. 223058231Syokota */ 223158231Syokota act->dx = act->dy = 0; 223258231Syokota /* horizontal roller count */ 223358231Syokota if (pBuf[2] & 0x0f) 223458231Syokota act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2; 223558231Syokota /* vertical roller count */ 223658231Syokota if (pBuf[2] & 0xf0) 223758231Syokota act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1; 223858231Syokota#if 0 223958231Syokota /* vertical roller count */ 224058231Syokota act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) 224158231Syokota ? ((pBuf[2] >> 4) & 0x0f) - 16 224258231Syokota : ((pBuf[2] >> 4) & 0x0f); 224358231Syokota /* horizontal roller count */ 224458231Syokota act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG) 224558231Syokota ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); 224658231Syokota#endif 224758231Syokota break; 224848778Syokota case 0: 224948778Syokota /* device type packet - shouldn't happen */ 2250102413Scharnier /* FALLTHROUGH */ 225148778Syokota default: 225248778Syokota act->dx = act->dy = 0; 225348778Syokota act->button = act->obutton; 2254122605Sdes debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n", 225548778Syokota MOUSE_PS2PLUS_PACKET_TYPE(pBuf), 225648778Syokota pBuf[0], pBuf[1], pBuf[2]); 225748778Syokota break; 225848778Syokota } 225931604Syokota } else { 226031604Syokota /* preserve button states */ 226131604Syokota act->button |= act->obutton & MOUSE_EXTBUTTONS; 226231604Syokota } 226331604Syokota break; 226431604Syokota case MOUSE_MODEL_GLIDEPOINT: 226531604Syokota /* `tapping' action */ 226631604Syokota act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN; 226731604Syokota break; 226831604Syokota case MOUSE_MODEL_NETSCROLL: 2269228990Suqs /* three additional bytes encode buttons and wheel events */ 227058231Syokota act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN) 227131604Syokota ? MOUSE_BUTTON4DOWN : 0; 227258231Syokota act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN) 227358231Syokota ? MOUSE_BUTTON5DOWN : 0; 227431604Syokota act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4]; 227531604Syokota break; 227631604Syokota case MOUSE_MODEL_THINK: 227731604Syokota /* the fourth button state in the first byte */ 227831604Syokota act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0; 227931604Syokota break; 228049967Syokota case MOUSE_MODEL_VERSAPAD: 228149967Syokota act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS]; 228249967Syokota act->button |= 228349967Syokota (pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 228449967Syokota act->dx = act->dy = 0; 228549967Syokota if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) { 228649967Syokota on = FALSE; 228749967Syokota break; 228849967Syokota } 228949967Syokota x = ((pBuf[4] << 8) & 0xf00) | pBuf[1]; 229049967Syokota if (x & 0x800) 229149967Syokota x -= 0x1000; 229249967Syokota y = ((pBuf[4] << 4) & 0xf00) | pBuf[2]; 229349967Syokota if (y & 0x800) 229449967Syokota y -= 0x1000; 229549967Syokota if (on) { 229649967Syokota act->dx = prev_x - x; 229749967Syokota act->dy = prev_y - y; 229849967Syokota } else { 229949967Syokota on = TRUE; 230049967Syokota } 230149967Syokota prev_x = x; 230249967Syokota prev_y = y; 230349967Syokota break; 230458231Syokota case MOUSE_MODEL_4D: 230558231Syokota act->dx = (pBuf[1] & 0x80) ? pBuf[1] - 256 : pBuf[1]; 230658231Syokota act->dy = (pBuf[2] & 0x80) ? -(pBuf[2] - 256) : -pBuf[2]; 230758231Syokota switch (pBuf[0] & MOUSE_4D_WHEELBITS) { 230858231Syokota case 0x10: 230958231Syokota act->dz = 1; 231058231Syokota break; 231158231Syokota case 0x30: 231258231Syokota act->dz = -1; 231358231Syokota break; 231458231Syokota case 0x40: /* 2nd wheel rolling right XXX */ 231558231Syokota act->dz = 2; 231658231Syokota break; 231758231Syokota case 0xc0: /* 2nd wheel rolling left XXX */ 231858231Syokota act->dz = -2; 231958231Syokota break; 232058231Syokota } 232158231Syokota break; 232258231Syokota case MOUSE_MODEL_4DPLUS: 232358231Syokota if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) { 232458231Syokota act->dx = act->dy = 0; 232558231Syokota if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN) 232658231Syokota act->button |= MOUSE_BUTTON4DOWN; 232758231Syokota act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG) 232858231Syokota ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07); 232958231Syokota } else { 233058231Syokota /* preserve previous button states */ 233158231Syokota act->button |= act->obutton & MOUSE_EXTBUTTONS; 233258231Syokota } 233358231Syokota break; 233431604Syokota case MOUSE_MODEL_GENERIC: 233531604Syokota default: 233631604Syokota break; 233731604Syokota } 233816566Ssos break; 233931604Syokota 234031604Syokota case MOUSE_PROTO_SYSMOUSE: /* sysmouse */ 234131604Syokota act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS]; 234296930Sknu act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]); 234396930Sknu act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4])); 234431604Syokota if (rodent.level == 1) { 234596930Sknu act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1; 234631604Syokota act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3); 234731604Syokota } 234831604Syokota break; 234931604Syokota 235031604Syokota default: 2351176855Sjkim return (0); 235216566Ssos } 2353122605Sdes /* 235431604Syokota * We don't reset pBufP here yet, as there may be an additional data 235531604Syokota * byte in some protocols. See above. 235631604Syokota */ 235731604Syokota 235831604Syokota /* has something changed? */ 235931604Syokota act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0) 236031604Syokota | (act->obutton ^ act->button); 236131604Syokota 2362176855Sjkim return (act->flags); 236358344Syokota} 236458344Syokota 236558344Syokotastatic int 236658344Syokotar_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans) 236758344Syokota{ 236858344Syokota int changed; 236958344Syokota int flags; 237058344Syokota 237158344Syokota a2->dx = a1->dx; 237258344Syokota a2->dy = a1->dy; 237358344Syokota a2->dz = a1->dz; 237458344Syokota a2->obutton = a2->button; 237558344Syokota a2->button = a1->button; 237658344Syokota a2->flags = a1->flags; 237758344Syokota changed = FALSE; 237858344Syokota 237931604Syokota if (rodent.flags & Emulate3Button) { 238058344Syokota if (debug > 2) 2381122605Sdes debug("state:%d, trans:%d -> state:%d", 238258344Syokota mouse_button_state, trans, 238358344Syokota states[mouse_button_state].s[trans]); 238479430Siedowse /* 238579430Siedowse * Avoid re-ordering button and movement events. While a button 238679430Siedowse * event is deferred, throw away up to BUTTON2_MAXMOVE movement 238779430Siedowse * events to allow for mouse jitter. If more movement events 238879430Siedowse * occur, then complete the deferred button events immediately. 238979430Siedowse */ 239079430Siedowse if ((a2->dx != 0 || a2->dy != 0) && 239179430Siedowse S_DELAYED(states[mouse_button_state].s[trans])) { 239279430Siedowse if (++mouse_move_delayed > BUTTON2_MAXMOVE) { 239379430Siedowse mouse_move_delayed = 0; 239479430Siedowse mouse_button_state = 239579430Siedowse states[mouse_button_state].s[A_TIMEOUT]; 239679430Siedowse changed = TRUE; 239779432Siedowse } else 239879430Siedowse a2->dx = a2->dy = 0; 239979430Siedowse } else 240079430Siedowse mouse_move_delayed = 0; 240179430Siedowse if (mouse_button_state != states[mouse_button_state].s[trans]) 240279430Siedowse changed = TRUE; 240379430Siedowse if (changed) 2404176854Sjkim clock_gettime(CLOCK_MONOTONIC_FAST, &mouse_button_state_ts); 240558344Syokota mouse_button_state = states[mouse_button_state].s[trans]; 240658344Syokota a2->button &= 240758344Syokota ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN); 240858344Syokota a2->button &= states[mouse_button_state].mask; 240958344Syokota a2->button |= states[mouse_button_state].buttons; 241058344Syokota flags = a2->flags & MOUSE_POSCHANGED; 241158344Syokota flags |= a2->obutton ^ a2->button; 241258344Syokota if (flags & MOUSE_BUTTON2DOWN) { 241358344Syokota a2->flags = flags & MOUSE_BUTTON2DOWN; 241458344Syokota r_timestamp(a2); 241558344Syokota } 241658344Syokota a2->flags = flags; 241731604Syokota } 2418176855Sjkim return (changed); 241916566Ssos} 242018222Speter 242131604Syokota/* phisical to logical button mapping */ 242231604Syokotastatic int p2l[MOUSE_MAXBUTTON] = { 2423122605Sdes MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN, 2424122605Sdes MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN, 242531604Syokota 0x00000100, 0x00000200, 0x00000400, 0x00000800, 242631604Syokota 0x00001000, 0x00002000, 0x00004000, 0x00008000, 242731604Syokota 0x00010000, 0x00020000, 0x00040000, 0x00080000, 242831604Syokota 0x00100000, 0x00200000, 0x00400000, 0x00800000, 242931604Syokota 0x01000000, 0x02000000, 0x04000000, 0x08000000, 243031604Syokota 0x10000000, 0x20000000, 0x40000000, 243131604Syokota}; 243231604Syokota 243331604Syokotastatic char * 243431604Syokotaskipspace(char *s) 243531604Syokota{ 243631604Syokota while(isspace(*s)) 243731604Syokota ++s; 2438176855Sjkim return (s); 243931604Syokota} 244031604Syokota 244131604Syokotastatic int 244231604Syokotar_installmap(char *arg) 244331604Syokota{ 244431604Syokota int pbutton; 244531604Syokota int lbutton; 244631604Syokota char *s; 244731604Syokota 244831604Syokota while (*arg) { 244931604Syokota arg = skipspace(arg); 245031604Syokota s = arg; 245131604Syokota while (isdigit(*arg)) 245231604Syokota ++arg; 245331604Syokota arg = skipspace(arg); 245431604Syokota if ((arg <= s) || (*arg != '=')) 2455176855Sjkim return (FALSE); 245631604Syokota lbutton = atoi(s); 245731604Syokota 245831604Syokota arg = skipspace(++arg); 245931604Syokota s = arg; 246031604Syokota while (isdigit(*arg)) 246131604Syokota ++arg; 246231604Syokota if ((arg <= s) || (!isspace(*arg) && (*arg != '\0'))) 2463176855Sjkim return (FALSE); 246431604Syokota pbutton = atoi(s); 246531604Syokota 246631604Syokota if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON)) 2467176855Sjkim return (FALSE); 246831604Syokota if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON)) 2469176855Sjkim return (FALSE); 247031604Syokota p2l[pbutton - 1] = 1 << (lbutton - 1); 247158344Syokota mstate[lbutton - 1] = &bstate[pbutton - 1]; 247231604Syokota } 247331604Syokota 2474176855Sjkim return (TRUE); 247531604Syokota} 247631604Syokota 247731604Syokotastatic void 247831604Syokotar_map(mousestatus_t *act1, mousestatus_t *act2) 247931604Syokota{ 248031604Syokota register int pb; 248131604Syokota register int pbuttons; 248231604Syokota int lbuttons; 248331604Syokota 248431604Syokota pbuttons = act1->button; 248531604Syokota lbuttons = 0; 248631604Syokota 248731604Syokota act2->obutton = act2->button; 248841270Syokota if (pbuttons & rodent.wmode) { 248941270Syokota pbuttons &= ~rodent.wmode; 249041270Syokota act1->dz = act1->dy; 249141270Syokota act1->dx = 0; 249241270Syokota act1->dy = 0; 249341270Syokota } 249431604Syokota act2->dx = act1->dx; 249531604Syokota act2->dy = act1->dy; 249631604Syokota act2->dz = act1->dz; 249731604Syokota 249858231Syokota switch (rodent.zmap[0]) { 249931604Syokota case 0: /* do nothing */ 250031604Syokota break; 250131604Syokota case MOUSE_XAXIS: 250231604Syokota if (act1->dz != 0) { 250331604Syokota act2->dx = act1->dz; 250431604Syokota act2->dz = 0; 250531604Syokota } 250631604Syokota break; 250731604Syokota case MOUSE_YAXIS: 250831604Syokota if (act1->dz != 0) { 250931604Syokota act2->dy = act1->dz; 251031604Syokota act2->dz = 0; 251131604Syokota } 251231604Syokota break; 251331604Syokota default: /* buttons */ 251458231Syokota pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1] 251558231Syokota | rodent.zmap[2] | rodent.zmap[3]); 251658344Syokota if ((act1->dz < -1) && rodent.zmap[2]) { 251758231Syokota pbuttons |= rodent.zmap[2]; 251858344Syokota zstate[2].count = 1; 251958344Syokota } else if (act1->dz < 0) { 252058231Syokota pbuttons |= rodent.zmap[0]; 252158344Syokota zstate[0].count = 1; 252258344Syokota } else if ((act1->dz > 1) && rodent.zmap[3]) { 252358231Syokota pbuttons |= rodent.zmap[3]; 252458344Syokota zstate[3].count = 1; 252558344Syokota } else if (act1->dz > 0) { 252658231Syokota pbuttons |= rodent.zmap[1]; 252758344Syokota zstate[1].count = 1; 252858344Syokota } 252931604Syokota act2->dz = 0; 253031604Syokota break; 253131604Syokota } 253231604Syokota 253331604Syokota for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) { 253431604Syokota lbuttons |= (pbuttons & 1) ? p2l[pb] : 0; 253531604Syokota pbuttons >>= 1; 253631604Syokota } 253731604Syokota act2->button = lbuttons; 253831604Syokota 253931604Syokota act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0) 254031604Syokota | (act2->obutton ^ act2->button); 254131604Syokota} 254231604Syokota 254331604Syokotastatic void 254458344Syokotar_timestamp(mousestatus_t *act) 254531604Syokota{ 2546176854Sjkim struct timespec ts; 2547176854Sjkim struct timespec ts1; 2548176854Sjkim struct timespec ts2; 2549176854Sjkim struct timespec ts3; 255031604Syokota int button; 255131604Syokota int mask; 255231604Syokota int i; 255331604Syokota 255431604Syokota mask = act->flags & MOUSE_BUTTONS; 255558344Syokota#if 0 255631604Syokota if (mask == 0) 255731604Syokota return; 255858344Syokota#endif 255931604Syokota 2560176854Sjkim clock_gettime(CLOCK_MONOTONIC_FAST, &ts1); 2561176854Sjkim drift_current_ts = ts1; 256258344Syokota 256358344Syokota /* double click threshold */ 2564176854Sjkim ts2.tv_sec = rodent.clickthreshold / 1000; 2565176854Sjkim ts2.tv_nsec = (rodent.clickthreshold % 1000) * 1000000; 2566176854Sjkim tssub(&ts1, &ts2, &ts); 2567176889Sjkim debug("ts: %jd %ld", (intmax_t)ts.tv_sec, ts.tv_nsec); 256858344Syokota 256958344Syokota /* 3 button emulation timeout */ 2570176854Sjkim ts2.tv_sec = rodent.button2timeout / 1000; 2571176854Sjkim ts2.tv_nsec = (rodent.button2timeout % 1000) * 1000000; 2572176854Sjkim tssub(&ts1, &ts2, &ts3); 257358344Syokota 257431604Syokota button = MOUSE_BUTTON1DOWN; 257531604Syokota for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) { 2576122605Sdes if (mask & 1) { 2577122605Sdes if (act->button & button) { 2578122605Sdes /* the button is down */ 2579176889Sjkim debug(" : %jd %ld", 2580176889Sjkim (intmax_t)bstate[i].ts.tv_sec, bstate[i].ts.tv_nsec); 2581176854Sjkim if (tscmp(&ts, &bstate[i].ts, >)) { 2582122605Sdes bstate[i].count = 1; 2583122605Sdes } else { 2584122605Sdes ++bstate[i].count; 2585122605Sdes } 2586176854Sjkim bstate[i].ts = ts1; 2587122605Sdes } else { 2588122605Sdes /* the button is up */ 2589176854Sjkim bstate[i].ts = ts1; 2590122605Sdes } 2591122605Sdes } else { 259258344Syokota if (act->button & button) { 259358344Syokota /* the button has been down */ 2594176854Sjkim if (tscmp(&ts3, &bstate[i].ts, >)) { 259558344Syokota bstate[i].count = 1; 2596176854Sjkim bstate[i].ts = ts1; 259758344Syokota act->flags |= button; 259858344Syokota debug("button %d timeout", i + 1); 259958344Syokota } 260058344Syokota } else { 260158344Syokota /* the button has been up */ 260258344Syokota } 260358344Syokota } 260458344Syokota button <<= 1; 260558344Syokota mask >>= 1; 260658344Syokota } 260758344Syokota} 260858344Syokota 260958344Syokotastatic int 261058344Syokotar_timeout(void) 261158344Syokota{ 2612176854Sjkim struct timespec ts; 2613176854Sjkim struct timespec ts1; 2614176854Sjkim struct timespec ts2; 261558344Syokota 261659090Syokota if (states[mouse_button_state].timeout) 2617176855Sjkim return (TRUE); 2618176854Sjkim clock_gettime(CLOCK_MONOTONIC_FAST, &ts1); 2619176854Sjkim ts2.tv_sec = rodent.button2timeout / 1000; 2620176854Sjkim ts2.tv_nsec = (rodent.button2timeout % 1000) * 1000000; 2621176854Sjkim tssub(&ts1, &ts2, &ts); 2622176855Sjkim return (tscmp(&ts, &mouse_button_state_ts, >)); 262358344Syokota} 262458344Syokota 262558344Syokotastatic void 262658344Syokotar_click(mousestatus_t *act) 262758344Syokota{ 262858344Syokota struct mouse_info mouse; 262958344Syokota int button; 263058344Syokota int mask; 263158344Syokota int i; 263258344Syokota 263358344Syokota mask = act->flags & MOUSE_BUTTONS; 263458344Syokota if (mask == 0) 263558344Syokota return; 263658344Syokota 263758344Syokota button = MOUSE_BUTTON1DOWN; 263858344Syokota for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) { 2639122605Sdes if (mask & 1) { 264058344Syokota debug("mstate[%d]->count:%d", i, mstate[i]->count); 2641122605Sdes if (act->button & button) { 2642122605Sdes /* the button is down */ 2643122605Sdes mouse.u.event.value = mstate[i]->count; 2644122605Sdes } else { 2645122605Sdes /* the button is up */ 2646122605Sdes mouse.u.event.value = 0; 2647122605Sdes } 264831604Syokota mouse.operation = MOUSE_BUTTON_EVENT; 264931604Syokota mouse.u.event.id = button; 265031604Syokota if (debug < 2) 2651153070Sphilip if (!paused) 2652153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 265331604Syokota debug("button %d count %d", i + 1, mouse.u.event.value); 2654122605Sdes } 265531604Syokota button <<= 1; 265631604Syokota mask >>= 1; 265731604Syokota } 265831604Syokota} 265931604Syokota 266018222Speter/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */ 266118222Speter/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */ 266218222Speter/* 266318222Speter * Copyright 1993 by David Dawes <dawes@physics.su.oz.au> 266418222Speter * 266518222Speter * Permission to use, copy, modify, distribute, and sell this software and its 266618222Speter * documentation for any purpose is hereby granted without fee, provided that 266718222Speter * the above copyright notice appear in all copies and that both that 266818222Speter * copyright notice and this permission notice appear in supporting 2669122605Sdes * documentation, and that the name of David Dawes 2670122605Sdes * not be used in advertising or publicity pertaining to distribution of 267118222Speter * the software without specific, written prior permission. 2672122605Sdes * David Dawes makes no representations about the suitability of this 2673122605Sdes * software for any purpose. It is provided "as is" without express or 267418222Speter * implied warranty. 267518222Speter * 2676122605Sdes * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO 2677122605Sdes * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 2678122605Sdes * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR 2679122605Sdes * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 2680122605Sdes * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 2681122605Sdes * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 268218222Speter * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 268318222Speter * 268418222Speter */ 268518222Speter 268618222Speter 268731604Syokotastatic void 268831604Syokotasetmousespeed(int old, int new, unsigned cflag) 268918222Speter{ 269018222Speter struct termios tty; 2691176855Sjkim const char *c; 269218222Speter 269318222Speter if (tcgetattr(rodent.mfd, &tty) < 0) 269418222Speter { 269595629Siedowse logwarn("unable to get status of mouse fd"); 269631604Syokota return; 269718222Speter } 269818222Speter 269918222Speter tty.c_iflag = IGNBRK | IGNPAR; 270018222Speter tty.c_oflag = 0; 270118222Speter tty.c_lflag = 0; 270218222Speter tty.c_cflag = (tcflag_t)cflag; 270318222Speter tty.c_cc[VTIME] = 0; 270418222Speter tty.c_cc[VMIN] = 1; 270518222Speter 270618222Speter switch (old) 270718222Speter { 270818222Speter case 9600: 270918222Speter cfsetispeed(&tty, B9600); 271018222Speter cfsetospeed(&tty, B9600); 271118222Speter break; 271218222Speter case 4800: 271318222Speter cfsetispeed(&tty, B4800); 271418222Speter cfsetospeed(&tty, B4800); 271518222Speter break; 271618222Speter case 2400: 271718222Speter cfsetispeed(&tty, B2400); 271818222Speter cfsetospeed(&tty, B2400); 271918222Speter break; 272018222Speter case 1200: 272118222Speter default: 272218222Speter cfsetispeed(&tty, B1200); 272318222Speter cfsetospeed(&tty, B1200); 272418222Speter } 272518222Speter 272618222Speter if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0) 272718222Speter { 272895629Siedowse logwarn("unable to set status of mouse fd"); 272931604Syokota return; 273018222Speter } 273118222Speter 273218222Speter switch (new) 273318222Speter { 273418222Speter case 9600: 273518222Speter c = "*q"; 273618222Speter cfsetispeed(&tty, B9600); 273718222Speter cfsetospeed(&tty, B9600); 273818222Speter break; 273918222Speter case 4800: 274018222Speter c = "*p"; 274118222Speter cfsetispeed(&tty, B4800); 274218222Speter cfsetospeed(&tty, B4800); 274318222Speter break; 274418222Speter case 2400: 274518222Speter c = "*o"; 274618222Speter cfsetispeed(&tty, B2400); 274718222Speter cfsetospeed(&tty, B2400); 274818222Speter break; 274918222Speter case 1200: 275018222Speter default: 275118222Speter c = "*n"; 275218222Speter cfsetispeed(&tty, B1200); 275318222Speter cfsetospeed(&tty, B1200); 275418222Speter } 275518222Speter 2756122605Sdes if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN 275731604Syokota || rodent.rtype == MOUSE_PROTO_LOGI) 275818222Speter { 275918222Speter if (write(rodent.mfd, c, 2) != 2) 276018222Speter { 276195629Siedowse logwarn("unable to write to mouse fd"); 276231604Syokota return; 276318222Speter } 276418222Speter } 276518222Speter usleep(100000); 276618222Speter 276718222Speter if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0) 276895629Siedowse logwarn("unable to set status of mouse fd"); 276931604Syokota} 277031604Syokota 2771122605Sdes/* 2772122605Sdes * PnP COM device support 2773122605Sdes * 277431604Syokota * It's a simplistic implementation, but it works :-) 277531604Syokota * KY, 31/7/97. 277631604Syokota */ 277731604Syokota 277831604Syokota/* 2779122605Sdes * Try to elicit a PnP ID as described in 2780122605Sdes * Microsoft, Hayes: "Plug and Play External COM Device Specification, 278131604Syokota * rev 1.00", 1995. 278231604Syokota * 278331604Syokota * The routine does not fully implement the COM Enumerator as par Section 278431604Syokota * 2.1 of the document. In particular, we don't have idle state in which 2785122605Sdes * the driver software monitors the com port for dynamic connection or 2786122605Sdes * removal of a device at the port, because `moused' simply quits if no 278731604Syokota * device is found. 278831604Syokota * 2789122605Sdes * In addition, as PnP COM device enumeration procedure slightly has 279031604Syokota * changed since its first publication, devices which follow earlier 2791122605Sdes * revisions of the above spec. may fail to respond if the rev 1.0 279231604Syokota * procedure is used. XXX 279331604Syokota */ 279431604Syokotastatic int 279540255Syokotapnpwakeup1(void) 279631604Syokota{ 279731604Syokota struct timeval timeout; 279831604Syokota fd_set fds; 279931604Syokota int i; 280031604Syokota 2801122605Sdes /* 280231604Syokota * This is the procedure described in rev 1.0 of PnP COM device spec. 280331604Syokota * Unfortunately, some devices which comform to earlier revisions of 280431604Syokota * the spec gets confused and do not return the ID string... 280531604Syokota */ 280640255Syokota debug("PnP COM device rev 1.0 probe..."); 280731604Syokota 280831604Syokota /* port initialization (2.1.2) */ 280931604Syokota ioctl(rodent.mfd, TIOCMGET, &i); 281031604Syokota i |= TIOCM_DTR; /* DTR = 1 */ 281131604Syokota i &= ~TIOCM_RTS; /* RTS = 0 */ 281231604Syokota ioctl(rodent.mfd, TIOCMSET, &i); 281340255Syokota usleep(240000); 281431604Syokota 281540255Syokota /* 2816122605Sdes * The PnP COM device spec. dictates that the mouse must set DSR 2817122605Sdes * in response to DTR (by hardware or by software) and that if DSR is 281840255Syokota * not asserted, the host computer should think that there is no device 281941269Syokota * at this serial port. But some mice just don't do that... 282040255Syokota */ 282140255Syokota ioctl(rodent.mfd, TIOCMGET, &i); 282240255Syokota debug("modem status 0%o", i); 282340255Syokota if ((i & TIOCM_DSR) == 0) 2824176855Sjkim return (FALSE); 282540255Syokota 282631604Syokota /* port setup, 1st phase (2.1.3) */ 282731604Syokota setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL)); 282831604Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 282931604Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 283040255Syokota usleep(240000); 283131604Syokota i = TIOCM_DTR; /* DTR = 1, RTS = 0 */ 283231604Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 283340255Syokota usleep(240000); 283431604Syokota 283531604Syokota /* wait for response, 1st phase (2.1.4) */ 283631604Syokota i = FREAD; 283731604Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 283831604Syokota i = TIOCM_RTS; /* DTR = 1, RTS = 1 */ 283931604Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 284031604Syokota 284131604Syokota /* try to read something */ 284231604Syokota FD_ZERO(&fds); 284331604Syokota FD_SET(rodent.mfd, &fds); 284431604Syokota timeout.tv_sec = 0; 284540255Syokota timeout.tv_usec = 240000; 284640255Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 284740255Syokota debug("pnpwakeup1(): valid response in first phase."); 2848176855Sjkim return (TRUE); 284941269Syokota } 285031604Syokota 285141269Syokota /* port setup, 2nd phase (2.1.5) */ 285241269Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 285341269Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 285441269Syokota usleep(240000); 285531604Syokota 285641269Syokota /* wait for respose, 2nd phase (2.1.6) */ 285741269Syokota i = FREAD; 285841269Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 285941269Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 286041269Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 286131604Syokota 286241269Syokota /* try to read something */ 286341269Syokota FD_ZERO(&fds); 286441269Syokota FD_SET(rodent.mfd, &fds); 286541269Syokota timeout.tv_sec = 0; 286641269Syokota timeout.tv_usec = 240000; 286741269Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 286841269Syokota debug("pnpwakeup1(): valid response in second phase."); 2869176855Sjkim return (TRUE); 287031604Syokota } 287141269Syokota 2872176855Sjkim return (FALSE); 287340255Syokota} 287440255Syokota 287540255Syokotastatic int 287640255Syokotapnpwakeup2(void) 287740255Syokota{ 287840255Syokota struct timeval timeout; 287940255Syokota fd_set fds; 288040255Syokota int i; 288140255Syokota 288231604Syokota /* 288331604Syokota * This is a simplified procedure; it simply toggles RTS. 288431604Syokota */ 288541269Syokota debug("alternate probe..."); 288631604Syokota 288731604Syokota ioctl(rodent.mfd, TIOCMGET, &i); 288831604Syokota i |= TIOCM_DTR; /* DTR = 1 */ 288931604Syokota i &= ~TIOCM_RTS; /* RTS = 0 */ 289031604Syokota ioctl(rodent.mfd, TIOCMSET, &i); 289140255Syokota usleep(240000); 289231604Syokota 289331604Syokota setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL)); 289431604Syokota 289531604Syokota /* wait for respose */ 289631604Syokota i = FREAD; 289731604Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 289831604Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 289931604Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 290031604Syokota 290131604Syokota /* try to read something */ 290231604Syokota FD_ZERO(&fds); 290331604Syokota FD_SET(rodent.mfd, &fds); 290431604Syokota timeout.tv_sec = 0; 290540255Syokota timeout.tv_usec = 240000; 290640255Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 290740255Syokota debug("pnpwakeup2(): valid response."); 2908176855Sjkim return (TRUE); 290940255Syokota } 291041269Syokota 2911176855Sjkim return (FALSE); 291240255Syokota} 291331604Syokota 291440255Syokotastatic int 291540255Syokotapnpgets(char *buf) 291640255Syokota{ 291740255Syokota struct timeval timeout; 291840255Syokota fd_set fds; 291940255Syokota int begin; 292040255Syokota int i; 292140255Syokota char c; 292240255Syokota 292340255Syokota if (!pnpwakeup1() && !pnpwakeup2()) { 292440255Syokota /* 2925122605Sdes * According to PnP spec, we should set DTR = 1 and RTS = 0 while 2926122605Sdes * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed, 2927122605Sdes * assuming there is something at the port even if it didn't 292840255Syokota * respond to the PnP enumeration procedure. 292940255Syokota */ 293040255Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 293140255Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 2932176855Sjkim return (0); 293340255Syokota } 293440255Syokota 293531604Syokota /* collect PnP COM device ID (2.1.7) */ 293640255Syokota begin = -1; 293731604Syokota i = 0; 293840255Syokota usleep(240000); /* the mouse must send `Begin ID' within 200msec */ 293931604Syokota while (read(rodent.mfd, &c, 1) == 1) { 294031604Syokota /* we may see "M", or "M3..." before `Begin ID' */ 294140255Syokota buf[i++] = c; 2942122605Sdes if ((c == 0x08) || (c == 0x28)) { /* Begin ID */ 294340255Syokota debug("begin-id %02x", c); 294440255Syokota begin = i - 1; 294531604Syokota break; 2946122605Sdes } 2947122605Sdes debug("%c %02x", c, c); 294840255Syokota if (i >= 256) 294940255Syokota break; 295031604Syokota } 295140255Syokota if (begin < 0) { 295231604Syokota /* we haven't seen `Begin ID' in time... */ 295331604Syokota goto connect_idle; 295431604Syokota } 295531604Syokota 295631604Syokota ++c; /* make it `End ID' */ 295731604Syokota for (;;) { 2958122605Sdes FD_ZERO(&fds); 2959122605Sdes FD_SET(rodent.mfd, &fds); 2960122605Sdes timeout.tv_sec = 0; 2961122605Sdes timeout.tv_usec = 240000; 2962122605Sdes if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0) 296331604Syokota break; 296431604Syokota 296531604Syokota read(rodent.mfd, &buf[i], 1); 2966122605Sdes if (buf[i++] == c) /* End ID */ 296731604Syokota break; 296831604Syokota if (i >= 256) 296931604Syokota break; 297031604Syokota } 297140255Syokota if (begin > 0) { 297240255Syokota i -= begin; 297340255Syokota bcopy(&buf[begin], &buf[0], i); 297440255Syokota } 297531604Syokota /* string may not be human readable... */ 297640255Syokota debug("len:%d, '%-*.*s'", i, i, i, buf); 297731604Syokota 297840255Syokota if (buf[i - 1] == c) 2979176855Sjkim return (i); /* a valid PnP string */ 298040255Syokota 298131604Syokota /* 2982122605Sdes * According to PnP spec, we should set DTR = 1 and RTS = 0 while 298340255Syokota * in idle state. But, `moused' shall leave the modem control lines 298440255Syokota * as they are. See above. 298531604Syokota */ 298631604Syokotaconnect_idle: 298740255Syokota 298840255Syokota /* we may still have something in the buffer */ 298940255Syokota return ((i > 0) ? i : 0); 299031604Syokota} 299131604Syokota 299231604Syokotastatic int 299331604Syokotapnpparse(pnpid_t *id, char *buf, int len) 299431604Syokota{ 299531604Syokota char s[3]; 299631604Syokota int offset; 299731604Syokota int sum = 0; 299831604Syokota int i, j; 299931604Syokota 300031604Syokota id->revision = 0; 300131604Syokota id->eisaid = NULL; 300231604Syokota id->serial = NULL; 300331604Syokota id->class = NULL; 300431604Syokota id->compat = NULL; 300531604Syokota id->description = NULL; 300631604Syokota id->neisaid = 0; 300731604Syokota id->nserial = 0; 300831604Syokota id->nclass = 0; 300931604Syokota id->ncompat = 0; 301031604Syokota id->ndescription = 0; 301131604Syokota 301240255Syokota if ((buf[0] != 0x28) && (buf[0] != 0x08)) { 301340255Syokota /* non-PnP mice */ 301440255Syokota switch(buf[0]) { 301540255Syokota default: 3016176855Sjkim return (FALSE); 301740255Syokota case 'M': /* Microsoft */ 301840255Syokota id->eisaid = "PNP0F01"; 301940255Syokota break; 302040255Syokota case 'H': /* MouseSystems */ 302140255Syokota id->eisaid = "PNP0F04"; 302240255Syokota break; 302340255Syokota } 302440255Syokota id->neisaid = strlen(id->eisaid); 302540255Syokota id->class = "MOUSE"; 302640255Syokota id->nclass = strlen(id->class); 302740255Syokota debug("non-PnP mouse '%c'", buf[0]); 3028176855Sjkim return (TRUE); 302940255Syokota } 303040255Syokota 303140255Syokota /* PnP mice */ 303231604Syokota offset = 0x28 - buf[0]; 303331604Syokota 303431604Syokota /* calculate checksum */ 303531604Syokota for (i = 0; i < len - 3; ++i) { 303631604Syokota sum += buf[i]; 303731604Syokota buf[i] += offset; 303831604Syokota } 303931604Syokota sum += buf[len - 1]; 304031604Syokota for (; i < len; ++i) 304131604Syokota buf[i] += offset; 304231604Syokota debug("PnP ID string: '%*.*s'", len, len, buf); 304331604Syokota 304431604Syokota /* revision */ 304531604Syokota buf[1] -= offset; 304631604Syokota buf[2] -= offset; 304731604Syokota id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f); 304831604Syokota debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100); 304931604Syokota 305031604Syokota /* EISA vender and product ID */ 305131604Syokota id->eisaid = &buf[3]; 305231604Syokota id->neisaid = 7; 305331604Syokota 305431604Syokota /* option strings */ 305531604Syokota i = 10; 305631604Syokota if (buf[i] == '\\') { 3057122605Sdes /* device serial # */ 3058122605Sdes for (j = ++i; i < len; ++i) { 3059122605Sdes if (buf[i] == '\\') 306031604Syokota break; 3061122605Sdes } 306231604Syokota if (i >= len) 306331604Syokota i -= 3; 306431604Syokota if (i - j == 8) { 3065122605Sdes id->serial = &buf[j]; 3066122605Sdes id->nserial = 8; 306718222Speter } 306831604Syokota } 306931604Syokota if (buf[i] == '\\') { 3070122605Sdes /* PnP class */ 3071122605Sdes for (j = ++i; i < len; ++i) { 3072122605Sdes if (buf[i] == '\\') 307331604Syokota break; 3074122605Sdes } 307531604Syokota if (i >= len) 307631604Syokota i -= 3; 307731604Syokota if (i > j + 1) { 3078122605Sdes id->class = &buf[j]; 3079122605Sdes id->nclass = i - j; 3080122605Sdes } 308131604Syokota } 308231604Syokota if (buf[i] == '\\') { 308331604Syokota /* compatible driver */ 3084122605Sdes for (j = ++i; i < len; ++i) { 3085122605Sdes if (buf[i] == '\\') 308631604Syokota break; 3087122605Sdes } 308831604Syokota /* 3089122605Sdes * PnP COM spec prior to v0.96 allowed '*' in this field, 309031604Syokota * it's not allowed now; just igore it. 309131604Syokota */ 309231604Syokota if (buf[j] == '*') 309331604Syokota ++j; 309431604Syokota if (i >= len) 309531604Syokota i -= 3; 309631604Syokota if (i > j + 1) { 3097122605Sdes id->compat = &buf[j]; 3098122605Sdes id->ncompat = i - j; 3099122605Sdes } 310031604Syokota } 310131604Syokota if (buf[i] == '\\') { 310231604Syokota /* product description */ 3103122605Sdes for (j = ++i; i < len; ++i) { 3104122605Sdes if (buf[i] == ';') 310531604Syokota break; 3106122605Sdes } 310731604Syokota if (i >= len) 310831604Syokota i -= 3; 310931604Syokota if (i > j + 1) { 3110122605Sdes id->description = &buf[j]; 3111122605Sdes id->ndescription = i - j; 3112122605Sdes } 311331604Syokota } 311431604Syokota 311531604Syokota /* checksum exists if there are any optional fields */ 311631604Syokota if ((id->nserial > 0) || (id->nclass > 0) 311731604Syokota || (id->ncompat > 0) || (id->ndescription > 0)) { 3118122605Sdes debug("PnP checksum: 0x%X", sum); 3119122605Sdes sprintf(s, "%02X", sum & 0x0ff); 3120122605Sdes if (strncmp(s, &buf[len - 3], 2) != 0) { 312131604Syokota#if 0 3122122605Sdes /* 3123122605Sdes * I found some mice do not comply with the PnP COM device 312431604Syokota * spec regarding checksum... XXX 312531604Syokota */ 3126122605Sdes logwarnx("PnP checksum error", 0); 3127176855Sjkim return (FALSE); 312831604Syokota#endif 3129122605Sdes } 313031604Syokota } 313131604Syokota 3132176855Sjkim return (TRUE); 313318222Speter} 313431604Syokota 313531604Syokotastatic symtab_t * 313631604Syokotapnpproto(pnpid_t *id) 313731604Syokota{ 313831604Syokota symtab_t *t; 313931604Syokota int i, j; 314031604Syokota 314131604Syokota if (id->nclass > 0) 3142122854Sdes if (strncmp(id->class, "MOUSE", id->nclass) != 0 && 3143122854Sdes strncmp(id->class, "TABLET", id->nclass) != 0) 314431604Syokota /* this is not a mouse! */ 3145176855Sjkim return (NULL); 314631604Syokota 314731604Syokota if (id->neisaid > 0) { 3148122605Sdes t = gettoken(pnpprod, id->eisaid, id->neisaid); 314931604Syokota if (t->val != MOUSE_PROTO_UNKNOWN) 3150176855Sjkim return (t); 315131604Syokota } 315231604Syokota 315331604Syokota /* 315431604Syokota * The 'Compatible drivers' field may contain more than one 315531604Syokota * ID separated by ','. 315631604Syokota */ 315731604Syokota if (id->ncompat <= 0) 3158176855Sjkim return (NULL); 315931604Syokota for (i = 0; i < id->ncompat; ++i) { 3160122605Sdes for (j = i; id->compat[i] != ','; ++i) 3161122605Sdes if (i >= id->ncompat) 316231604Syokota break; 3163122605Sdes if (i > j) { 3164122605Sdes t = gettoken(pnpprod, id->compat + j, i - j); 316531604Syokota if (t->val != MOUSE_PROTO_UNKNOWN) 3166176855Sjkim return (t); 316731604Syokota } 316831604Syokota } 316931604Syokota 3170176855Sjkim return (NULL); 317131604Syokota} 317231604Syokota 317331604Syokota/* name/val mapping */ 317431604Syokota 317531604Syokotastatic symtab_t * 3176176855Sjkimgettoken(symtab_t *tab, const char *s, int len) 317731604Syokota{ 317831604Syokota int i; 317931604Syokota 318031604Syokota for (i = 0; tab[i].name != NULL; ++i) { 318131604Syokota if (strncmp(tab[i].name, s, len) == 0) 318231604Syokota break; 318331604Syokota } 3184176855Sjkim return (&tab[i]); 318531604Syokota} 318631604Syokota 3187176855Sjkimstatic const char * 318831604Syokotagettokenname(symtab_t *tab, int val) 318931604Syokota{ 3190176855Sjkim static const char unknown[] = "unknown"; 319131604Syokota int i; 319231604Syokota 319331604Syokota for (i = 0; tab[i].name != NULL; ++i) { 319431604Syokota if (tab[i].val == val) 3195176855Sjkim return (tab[i].name); 319631604Syokota } 3197176855Sjkim return (unknown); 319831604Syokota} 319936991Sahasty 320041271Syokota 320141271Syokota/* 320241271Syokota * code to read from the Genius Kidspad tablet. 320341271Syokota 320441271SyokotaThe tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005, 320541271Syokotaand to pre-pnp probes (RTS toggle) with 'T' (tablet ?) 320641271Syokota9600, 8 bit, parity odd. 320741271Syokota 320841271SyokotaThe tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains 320941271Syokotathe proximity, tip and button info: 321041271Syokota (byte0 & 0x1) true = tip pressed 321141271Syokota (byte0 & 0x2) true = button pressed 321241271Syokota (byte0 & 0x40) false = pen in proximity of tablet. 321341271Syokota 321441271SyokotaThe next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid). 321541271Syokota 321641271SyokotaOnly absolute coordinates are returned, so we use the following approach: 321741271Syokotawe store the last coordinates sent when the pen went out of the tablet, 321841271Syokota 321941271Syokota 322041271Syokota * 322141271Syokota */ 322241271Syokota 322341271Syokotatypedef enum { 322441271Syokota S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP 3225176855Sjkim} k_status; 322641271Syokota 322741271Syokotastatic int 322841271Syokotakidspad(u_char rxc, mousestatus_t *act) 322941271Syokota{ 323095629Siedowse static int buf[5]; 3231176855Sjkim static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1; 3232176855Sjkim static k_status status = S_IDLE; 3233230351Seadler static struct timespec now; 323441271Syokota 3235176855Sjkim int x, y; 323641271Syokota 3237122854Sdes if (buflen > 0 && (rxc & 0x80)) { 323841271Syokota fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc); 3239176855Sjkim buflen = 0; 324041271Syokota } 3241122854Sdes if (buflen == 0 && (rxc & 0xb8) != 0xb8) { 324241271Syokota fprintf(stderr, "invalid code 0 0x%x\n", rxc); 3243176855Sjkim return (0); /* invalid code, no action */ 324441271Syokota } 3245176855Sjkim buf[buflen++] = rxc; 324641271Syokota if (buflen < 5) 3247176855Sjkim return (0); 324841271Syokota 3249176855Sjkim buflen = 0; /* for next time... */ 325041271Syokota 3251176855Sjkim x = buf[1]+128*(buf[2] - 7); 3252176855Sjkim if (x < 0) x = 0; 3253176855Sjkim y = 28*128 - (buf[3] + 128* (buf[4] - 7)); 3254176855Sjkim if (y < 0) y = 0; 325541271Syokota 3256176855Sjkim x /= 8; 3257176855Sjkim y /= 8; 325841271Syokota 3259176855Sjkim act->flags = 0; 3260176855Sjkim act->obutton = act->button; 3261176855Sjkim act->dx = act->dy = act->dz = 0; 3262176854Sjkim clock_gettime(CLOCK_MONOTONIC_FAST, &now); 3263122854Sdes if (buf[0] & 0x40) /* pen went out of reach */ 3264176855Sjkim status = S_IDLE; 326541271Syokota else if (status == S_IDLE) { /* pen is newly near the tablet */ 3266176855Sjkim act->flags |= MOUSE_POSCHANGED; /* force update */ 3267176855Sjkim status = S_PROXY; 3268176855Sjkim x_prev = x; 3269176855Sjkim y_prev = y; 327041271Syokota } 3271176855Sjkim act->dx = x - x_prev; 3272176855Sjkim act->dy = y - y_prev; 327341271Syokota if (act->dx || act->dy) 3274176855Sjkim act->flags |= MOUSE_POSCHANGED; 3275176855Sjkim x_prev = x; 3276176855Sjkim y_prev = y; 327741271Syokota if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */ 3278176855Sjkim act->button = 0; 3279122854Sdes if (buf[0] & 0x01) /* tip pressed */ 3280176855Sjkim act->button |= MOUSE_BUTTON1DOWN; 3281122854Sdes if (buf[0] & 0x02) /* button pressed */ 3282176855Sjkim act->button |= MOUSE_BUTTON2DOWN; 3283176855Sjkim act->flags |= MOUSE_BUTTONSCHANGED; 328441271Syokota } 3285176855Sjkim b_prev = buf[0]; 3286176855Sjkim return (act->flags); 328741271Syokota} 328841271Syokota 3289145001Smdoddstatic int 3290145001Smdoddgtco_digipad (u_char rxc, mousestatus_t *act) 3291145001Smdodd{ 3292145001Smdodd static u_char buf[5]; 3293176855Sjkim static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1; 3294176855Sjkim static k_status status = S_IDLE; 3295176855Sjkim int x, y; 3296145001Smdodd 3297145001Smdodd#define GTCO_HEADER 0x80 3298145001Smdodd#define GTCO_PROXIMITY 0x40 3299145001Smdodd#define GTCO_START (GTCO_HEADER|GTCO_PROXIMITY) 3300145001Smdodd#define GTCO_BUTTONMASK 0x3c 3301145001Smdodd 3302176855Sjkim 3303145001Smdodd if (buflen > 0 && ((rxc & GTCO_HEADER) != GTCO_HEADER)) { 3304145001Smdodd fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc); 3305176855Sjkim buflen = 0; 3306145001Smdodd } 3307145001Smdodd if (buflen == 0 && (rxc & GTCO_START) != GTCO_START) { 3308145001Smdodd fprintf(stderr, "invalid code 0 0x%x\n", rxc); 3309176855Sjkim return (0); /* invalid code, no action */ 3310145001Smdodd } 3311145001Smdodd 3312176855Sjkim buf[buflen++] = rxc; 3313145001Smdodd if (buflen < 5) 3314176855Sjkim return (0); 3315145001Smdodd 3316176855Sjkim buflen = 0; /* for next time... */ 3317145001Smdodd 3318145001Smdodd x = ((buf[2] & ~GTCO_START) << 6 | (buf[1] & ~GTCO_START)); 3319145001Smdodd y = 4768 - ((buf[4] & ~GTCO_START) << 6 | (buf[3] & ~GTCO_START)); 3320145001Smdodd 3321145001Smdodd x /= 2.5; 3322145001Smdodd y /= 2.5; 3323176855Sjkim 3324176855Sjkim act->flags = 0; 3325176855Sjkim act->obutton = act->button; 3326176855Sjkim act->dx = act->dy = act->dz = 0; 3327176855Sjkim 3328145001Smdodd if ((buf[0] & 0x40) == 0) /* pen went out of reach */ 3329176855Sjkim status = S_IDLE; 3330145001Smdodd else if (status == S_IDLE) { /* pen is newly near the tablet */ 3331176855Sjkim act->flags |= MOUSE_POSCHANGED; /* force update */ 3332176855Sjkim status = S_PROXY; 3333176855Sjkim x_prev = x; 3334176855Sjkim y_prev = y; 3335145001Smdodd } 3336145001Smdodd 3337176855Sjkim act->dx = x - x_prev; 3338176855Sjkim act->dy = y - y_prev; 3339145001Smdodd if (act->dx || act->dy) 3340176855Sjkim act->flags |= MOUSE_POSCHANGED; 3341176855Sjkim x_prev = x; 3342176855Sjkim y_prev = y; 3343176855Sjkim 3344145001Smdodd /* possibly record button change */ 3345176855Sjkim if (b_prev != 0 && b_prev != buf[0]) { 3346176855Sjkim act->button = 0; 3347176855Sjkim if (buf[0] & 0x04) { 3348176855Sjkim /* tip pressed/yellow */ 3349176855Sjkim act->button |= MOUSE_BUTTON1DOWN; 3350176855Sjkim } 3351176855Sjkim if (buf[0] & 0x08) { 3352176855Sjkim /* grey/white */ 3353176855Sjkim act->button |= MOUSE_BUTTON2DOWN; 3354176855Sjkim } 3355176855Sjkim if (buf[0] & 0x10) { 3356176855Sjkim /* black/green */ 3357176855Sjkim act->button |= MOUSE_BUTTON3DOWN; 3358176855Sjkim } 3359176855Sjkim if (buf[0] & 0x20) { 3360176855Sjkim /* tip+grey/blue */ 3361176855Sjkim act->button |= MOUSE_BUTTON4DOWN; 3362176855Sjkim } 3363176855Sjkim act->flags |= MOUSE_BUTTONSCHANGED; 3364145001Smdodd } 3365176855Sjkim b_prev = buf[0]; 3366176855Sjkim return (act->flags); 3367145001Smdodd} 3368145001Smdodd 3369122605Sdesstatic void 3370176855Sjkimmremote_serversetup(void) 337136991Sahasty{ 337236991Sahasty struct sockaddr_un ad; 337336991Sahasty 337436991Sahasty /* Open a UNIX domain stream socket to listen for mouse remote clients */ 3375122605Sdes unlink(_PATH_MOUSEREMOTE); 337636991Sahasty 3377122854Sdes if ((rodent.mremsfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 337836991Sahasty logerrx(1, "unable to create unix domain socket %s",_PATH_MOUSEREMOTE); 337936991Sahasty 338036991Sahasty umask(0111); 3381122605Sdes 338236991Sahasty bzero(&ad, sizeof(ad)); 338336991Sahasty ad.sun_family = AF_UNIX; 338436991Sahasty strcpy(ad.sun_path, _PATH_MOUSEREMOTE); 338536991Sahasty#ifndef SUN_LEN 3386122854Sdes#define SUN_LEN(unp) (((char *)(unp)->sun_path - (char *)(unp)) + \ 3387122854Sdes strlen((unp)->path)) 338836991Sahasty#endif 3389122605Sdes if (bind(rodent.mremsfd, (struct sockaddr *) &ad, SUN_LEN(&ad)) < 0) 339036991Sahasty logerrx(1, "unable to bind unix domain socket %s", _PATH_MOUSEREMOTE); 339136991Sahasty 339236991Sahasty listen(rodent.mremsfd, 1); 339336991Sahasty} 339436991Sahasty 3395122605Sdesstatic void 339636991Sahastymremote_clientchg(int add) 339736991Sahasty{ 339836991Sahasty struct sockaddr_un ad; 3399176855Sjkim socklen_t ad_len; 3400176855Sjkim int fd; 340136991Sahasty 340236991Sahasty if (rodent.rtype != MOUSE_PROTO_X10MOUSEREM) 340336991Sahasty return; 340436991Sahasty 3405122854Sdes if (add) { 340636991Sahasty /* Accept client connection, if we don't already have one */ 340736991Sahasty ad_len = sizeof(ad); 340836991Sahasty fd = accept(rodent.mremsfd, (struct sockaddr *) &ad, &ad_len); 340936991Sahasty if (fd < 0) 341036991Sahasty logwarnx("failed accept on mouse remote socket"); 341136991Sahasty 3412122854Sdes if (rodent.mremcfd < 0) { 341336991Sahasty rodent.mremcfd = fd; 341436991Sahasty debug("remote client connect...accepted"); 341536991Sahasty } 341636991Sahasty else { 341736991Sahasty close(fd); 341836991Sahasty debug("another remote client connect...disconnected"); 341936991Sahasty } 342036991Sahasty } 342136991Sahasty else { 342236991Sahasty /* Client disconnected */ 342336991Sahasty debug("remote client disconnected"); 3424122854Sdes close(rodent.mremcfd); 342536991Sahasty rodent.mremcfd = -1; 342636991Sahasty } 342736991Sahasty} 3428