moused.c revision 153070
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: head/usr.sbin/moused/moused.c 153070 2005-12-04 00:28:40Z philip $"); 4929849Scharnier 50122853Sdes#include <sys/param.h> 51122853Sdes#include <sys/consio.h> 52122853Sdes#include <sys/linker.h> 53122853Sdes#include <sys/module.h> 54122853Sdes#include <sys/mouse.h> 55122853Sdes#include <sys/socket.h> 56122853Sdes#include <sys/stat.h> 57122853Sdes#include <sys/time.h> 58122853Sdes#include <sys/un.h> 59122853Sdes 6058231Syokota#include <ctype.h> 6129849Scharnier#include <err.h> 6229849Scharnier#include <errno.h> 6329849Scharnier#include <fcntl.h> 64149426Spjd#include <libutil.h> 6529849Scharnier#include <limits.h> 66122853Sdes#include <setjmp.h> 67122853Sdes#include <signal.h> 68122853Sdes#include <stdarg.h> 6916566Ssos#include <stdio.h> 7016566Ssos#include <stdlib.h> 7116566Ssos#include <string.h> 72122853Sdes#include <syslog.h> 7316566Ssos#include <termios.h> 7421885Ssos#include <unistd.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 */ 8131604Syokota 8279430Siedowse/* Abort 3-button emulation delay after this many movement events. */ 8379430Siedowse#define BUTTON2_MAXMOVE 3 8479430Siedowse 8531604Syokota#define TRUE 1 8631604Syokota#define FALSE 0 8731604Syokota 8831604Syokota#define MOUSE_XAXIS (-1) 8931604Syokota#define MOUSE_YAXIS (-2) 9031604Syokota 9148778Syokota/* Logitech PS2++ protocol */ 9248778Syokota#define MOUSE_PS2PLUS_CHECKBITS(b) \ 9348778Syokota ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f)) 9448778Syokota#define MOUSE_PS2PLUS_PACKET_TYPE(b) \ 9548778Syokota (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) 9648778Syokota 9731604Syokota#define ChordMiddle 0x0001 9831604Syokota#define Emulate3Button 0x0002 9931604Syokota#define ClearDTR 0x0004 10031604Syokota#define ClearRTS 0x0008 10131604Syokota#define NoPnP 0x0010 102136372Sphilip#define VirtualScroll 0x0020 103148161Sphilip#define HVirtualScroll 0x0040 104122605Sdes 10531604Syokota#define ID_NONE 0 10631604Syokota#define ID_PORT 1 10731604Syokota#define ID_IF 2 108136372Sphilip#define ID_TYPE 4 10931604Syokota#define ID_MODEL 8 11031604Syokota#define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL) 11131604Syokota 11295629Siedowse#define debug(fmt, args...) do { \ 11395629Siedowse if (debug && nodaemon) \ 11495629Siedowse warnx(fmt, ##args); \ 11595629Siedowse} while (0) 11616566Ssos 11795629Siedowse#define logerr(e, fmt, args...) do { \ 11895629Siedowse log_or_warn(LOG_DAEMON | LOG_ERR, errno, fmt, ##args); \ 11995629Siedowse exit(e); \ 12095629Siedowse} while (0) 12131604Syokota 12295629Siedowse#define logerrx(e, fmt, args...) do { \ 12395629Siedowse log_or_warn(LOG_DAEMON | LOG_ERR, 0, fmt, ##args); \ 12495629Siedowse exit(e); \ 12595629Siedowse} while (0) 12631604Syokota 12795629Siedowse#define logwarn(fmt, args...) \ 12895629Siedowse log_or_warn(LOG_DAEMON | LOG_WARNING, errno, fmt, ##args) 12931604Syokota 13095629Siedowse#define logwarnx(fmt, args...) \ 13195629Siedowse log_or_warn(LOG_DAEMON | LOG_WARNING, 0, fmt, ##args) 13231604Syokota 13331604Syokota/* structures */ 13431604Syokota 13531604Syokota/* symbol table entry */ 13631604Syokotatypedef struct { 13731604Syokota char *name; 13831604Syokota int val; 13931604Syokota int val2; 14031604Syokota} symtab_t; 14131604Syokota 14231604Syokota/* serial PnP ID string */ 14331604Syokotatypedef struct { 14431604Syokota int revision; /* PnP revision, 100 for 1.00 */ 14531604Syokota char *eisaid; /* EISA ID including mfr ID and product ID */ 14631604Syokota char *serial; /* serial No, optional */ 14731604Syokota char *class; /* device class, optional */ 14831604Syokota char *compat; /* list of compatible drivers, optional */ 14931604Syokota char *description; /* product description, optional */ 15031604Syokota int neisaid; /* length of the above fields... */ 15131604Syokota int nserial; 15231604Syokota int nclass; 15331604Syokota int ncompat; 15431604Syokota int ndescription; 15531604Syokota} pnpid_t; 15631604Syokota 15731604Syokota/* global variables */ 15831604Syokota 15916566Ssosint debug = 0; 16031604Syokotaint nodaemon = FALSE; 16131604Syokotaint background = FALSE; 162153070Sphilipint paused = FALSE; 16331604Syokotaint identify = ID_NONE; 16431604Syokotaint extioctl = FALSE; 16534152Sjkhchar *pidfile = "/var/run/moused.pid"; 166149426Spjdstruct pidfh *pfh; 16716566Ssos 168136372Sphilip#define SCROLL_NOTSCROLLING 0 169136372Sphilip#define SCROLL_PREPARE 1 170136372Sphilip#define SCROLL_SCROLLING 2 171136372Sphilip 172136372Sphilipstatic int scroll_state; 173136372Sphilipstatic int scroll_movement; 174148161Sphilipstatic int hscroll_movement; 175136372Sphilip 17631604Syokota/* local variables */ 17716566Ssos 17831604Syokota/* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */ 17931604Syokotastatic symtab_t rifs[] = { 18031604Syokota { "serial", MOUSE_IF_SERIAL }, 18131604Syokota { "bus", MOUSE_IF_BUS }, 18231604Syokota { "inport", MOUSE_IF_INPORT }, 18331604Syokota { "ps/2", MOUSE_IF_PS2 }, 18431604Syokota { "sysmouse", MOUSE_IF_SYSMOUSE }, 18544326Syokota { "usb", MOUSE_IF_USB }, 18631604Syokota { NULL, MOUSE_IF_UNKNOWN }, 18731604Syokota}; 18816566Ssos 18931604Syokota/* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */ 19031604Syokotastatic char *rnames[] = { 19116566Ssos "microsoft", 19216566Ssos "mousesystems", 19331604Syokota "logitech", 19416566Ssos "mmseries", 19531604Syokota "mouseman", 19616566Ssos "busmouse", 19731604Syokota "inportmouse", 19816566Ssos "ps/2", 19918222Speter "mmhitab", 20031604Syokota "glidepoint", 20131604Syokota "intellimouse", 20231604Syokota "thinkingmouse", 20331604Syokota "sysmouse", 20436991Sahasty "x10mouseremote", 20541271Syokota "kidspad", 20693071Swill "versapad", 20793071Swill "jogdial", 20831604Syokota#if notyet 20931604Syokota "mariqua", 21031604Syokota#endif 211145001Smdodd "gtco_digipad", 21216566Ssos NULL 21316566Ssos}; 21416566Ssos 21531604Syokota/* models */ 21631604Syokotastatic symtab_t rmodels[] = { 21758231Syokota { "NetScroll", MOUSE_MODEL_NETSCROLL }, 21858231Syokota { "NetMouse/NetScroll Optical", MOUSE_MODEL_NET }, 21958231Syokota { "GlidePoint", MOUSE_MODEL_GLIDEPOINT }, 22058231Syokota { "ThinkingMouse", MOUSE_MODEL_THINK }, 22158231Syokota { "IntelliMouse", MOUSE_MODEL_INTELLI }, 22258231Syokota { "EasyScroll/SmartScroll", MOUSE_MODEL_EASYSCROLL }, 22358231Syokota { "MouseMan+", MOUSE_MODEL_MOUSEMANPLUS }, 22458231Syokota { "Kidspad", MOUSE_MODEL_KIDSPAD }, 22558231Syokota { "VersaPad", MOUSE_MODEL_VERSAPAD }, 22658231Syokota { "IntelliMouse Explorer", MOUSE_MODEL_EXPLORER }, 22758231Syokota { "4D Mouse", MOUSE_MODEL_4D }, 22858231Syokota { "4D+ Mouse", MOUSE_MODEL_4DPLUS }, 229133083Sphilip { "Synaptics Touchpad", MOUSE_MODEL_SYNAPTICS }, 23058231Syokota { "generic", MOUSE_MODEL_GENERIC }, 231122605Sdes { NULL, MOUSE_MODEL_UNKNOWN }, 23231604Syokota}; 23331604Syokota 23431604Syokota/* PnP EISA/product IDs */ 23531604Syokotastatic symtab_t pnpprod[] = { 23631604Syokota /* Kensignton ThinkingMouse */ 23731604Syokota { "KML0001", MOUSE_PROTO_THINK, MOUSE_MODEL_THINK }, 23831604Syokota /* MS IntelliMouse */ 23931604Syokota { "MSH0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 24031604Syokota /* MS IntelliMouse TrackBall */ 24131604Syokota { "MSH0004", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 24258099Sache /* Tremon Wheel Mouse MUSD */ 24358099Sache { "HTK0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 24433074Sache /* Genius PnP Mouse */ 24533074Sache { "KYE0001", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 24656524Syokota /* MouseSystems SmartScroll Mouse (OEM from Genius?) */ 24756524Syokota { "KYE0002", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL }, 24833074Sache /* Genius NetMouse */ 24933074Sache { "KYE0003", MOUSE_PROTO_INTELLI, MOUSE_MODEL_NET }, 25041271Syokota /* Genius Kidspad, Easypad and other tablets */ 25141271Syokota { "KYE0005", MOUSE_PROTO_KIDSPAD, MOUSE_MODEL_KIDSPAD }, 25231604Syokota /* Genius EZScroll */ 253122605Sdes { "KYEEZ00", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL }, 25456335Syokota /* Logitech Cordless MouseMan Wheel */ 25556335Syokota { "LGI8033", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 25631949Syokota /* Logitech MouseMan (new 4 button model) */ 25731949Syokota { "LGI800C", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 25831604Syokota /* Logitech MouseMan+ */ 25931604Syokota { "LGI8050", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 26031604Syokota /* Logitech FirstMouse+ */ 26131604Syokota { "LGI8051", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS }, 26232634Syokota /* Logitech serial */ 26332634Syokota { "LGI8001", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 26458231Syokota /* A4 Tech 4D/4D+ Mouse */ 26558231Syokota { "A4W0005", MOUSE_PROTO_INTELLI, MOUSE_MODEL_4D }, 26658231Syokota /* 8D Scroll Mouse */ 26758231Syokota { "PEC9802", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 26858328Syokota /* Mitsumi Wireless Scroll Mouse */ 26958328Syokota { "MTM6401", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI }, 27031604Syokota 27131604Syokota /* MS bus */ 27231604Syokota { "PNP0F00", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 27331604Syokota /* MS serial */ 274122605Sdes { "PNP0F01", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 27531604Syokota /* MS InPort */ 276122605Sdes { "PNP0F02", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC }, 27731604Syokota /* MS PS/2 */ 278122605Sdes { "PNP0F03", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 27931604Syokota /* 28031604Syokota * EzScroll returns PNP0F04 in the compatible device field; but it 28131604Syokota * doesn't look compatible... XXX 28231604Syokota */ 283122605Sdes /* MouseSystems */ 284122605Sdes { "PNP0F04", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC }, 285122605Sdes /* MouseSystems */ 286122605Sdes { "PNP0F05", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC }, 28731604Syokota#if notyet 288122605Sdes /* Genius Mouse */ 289122854Sdes { "PNP0F06", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 290122605Sdes /* Genius Mouse */ 291122854Sdes { "PNP0F07", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 29231604Syokota#endif 29331604Syokota /* Logitech serial */ 29431604Syokota { "PNP0F08", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 29531604Syokota /* MS BallPoint serial */ 296122605Sdes { "PNP0F09", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 29731604Syokota /* MS PnP serial */ 298122605Sdes { "PNP0F0A", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 29931604Syokota /* MS PnP BallPoint serial */ 300122605Sdes { "PNP0F0B", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 30131604Syokota /* MS serial comatible */ 302122605Sdes { "PNP0F0C", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 30331604Syokota /* MS InPort comatible */ 304122605Sdes { "PNP0F0D", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC }, 30531604Syokota /* MS PS/2 comatible */ 306122605Sdes { "PNP0F0E", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 30731604Syokota /* MS BallPoint comatible */ 308122605Sdes { "PNP0F0F", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC }, 30931604Syokota#if notyet 31031604Syokota /* TI QuickPort */ 311122854Sdes { "PNP0F10", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 31231604Syokota#endif 31331604Syokota /* MS bus comatible */ 314122605Sdes { "PNP0F11", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 31531604Syokota /* Logitech PS/2 */ 31631604Syokota { "PNP0F12", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 31731604Syokota /* PS/2 */ 31831604Syokota { "PNP0F13", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 31931604Syokota#if notyet 32031604Syokota /* MS Kids Mouse */ 321122854Sdes { "PNP0F14", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 32231604Syokota#endif 323122605Sdes /* Logitech bus */ 32431604Syokota { "PNP0F15", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 32531604Syokota#if notyet 32631604Syokota /* Logitech SWIFT */ 327122854Sdes { "PNP0F16", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 32831604Syokota#endif 32931604Syokota /* Logitech serial compat */ 33031604Syokota { "PNP0F17", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC }, 33131604Syokota /* Logitech bus compatible */ 33231604Syokota { "PNP0F18", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC }, 33331604Syokota /* Logitech PS/2 compatible */ 33431604Syokota { "PNP0F19", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC }, 33531604Syokota#if notyet 33631604Syokota /* Logitech SWIFT compatible */ 337122854Sdes { "PNP0F1A", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 33831604Syokota /* HP Omnibook */ 339122854Sdes { "PNP0F1B", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 34031604Syokota /* Compaq LTE TrackBall PS/2 */ 341122854Sdes { "PNP0F1C", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 34231604Syokota /* Compaq LTE TrackBall serial */ 343122854Sdes { "PNP0F1D", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 34431604Syokota /* MS Kidts Trackball */ 345122854Sdes { "PNP0F1E", MOUSE_PROTO_XXX, MOUSE_MODEL_GENERIC }, 34631604Syokota#endif 34749967Syokota /* Interlink VersaPad */ 34849967Syokota { "LNK0001", MOUSE_PROTO_VERSAPAD, MOUSE_MODEL_VERSAPAD }, 34931604Syokota 35031604Syokota { NULL, MOUSE_PROTO_UNKNOWN, MOUSE_MODEL_GENERIC }, 35131604Syokota}; 35231604Syokota 35331604Syokota/* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */ 35431604Syokotastatic unsigned short rodentcflags[] = 35516566Ssos{ 356122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* MicroSoft */ 357122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* MouseSystems */ 358122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* Logitech */ 359122854Sdes (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL), /* MMSeries */ 360122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* MouseMan */ 36131604Syokota 0, /* Bus */ 36231604Syokota 0, /* InPort */ 36318222Speter 0, /* PS/2 */ 364122854Sdes (CS8 | CREAD | CLOCAL | HUPCL), /* MM HitTablet */ 365122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* GlidePoint */ 366122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* IntelliMouse */ 367122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* Thinking Mouse */ 368122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* sysmouse */ 369122854Sdes (CS7 | CREAD | CLOCAL | HUPCL), /* X10 MouseRemote */ 370122854Sdes (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL), /* kidspad etc. */ 371122854Sdes (CS8 | CREAD | CLOCAL | HUPCL), /* VersaPad */ 37293071Swill 0, /* JogDial */ 37331604Syokota#if notyet 374122854Sdes (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL), /* Mariqua */ 37531604Syokota#endif 376145001Smdodd (CS8 | CREAD | HUPCL ), /* GTCO Digi-Pad */ 37716566Ssos}; 37816566Ssos 37931604Syokotastatic struct rodentparam { 38031604Syokota int flags; 38131604Syokota char *portname; /* /dev/XXX */ 38231604Syokota int rtype; /* MOUSE_PROTO_XXX */ 38331604Syokota int level; /* operation level: 0 or greater */ 38431604Syokota int baudrate; 38531604Syokota int rate; /* report rate */ 38631604Syokota int resolution; /* MOUSE_RES_XXX or a positive number */ 38758231Syokota int zmap[4]; /* MOUSE_{X|Y}AXIS or a button number */ 38841270Syokota int wmode; /* wheel mode button number */ 38931604Syokota int mfd; /* mouse file descriptor */ 39031604Syokota int cfd; /* /dev/consolectl file descriptor */ 39136991Sahasty int mremsfd; /* mouse remote server file descriptor */ 39236991Sahasty int mremcfd; /* mouse remote client file descriptor */ 39331604Syokota long clickthreshold; /* double click speed in msec */ 39458344Syokota long button2timeout; /* 3 button emulation timeout */ 39531604Syokota mousehw_t hw; /* mouse device hardware information */ 39631604Syokota mousemode_t mode; /* protocol information */ 39778770Sgreid float accelx; /* Acceleration in the X axis */ 39878770Sgreid float accely; /* Acceleration in the Y axis */ 399136372Sphilip int scrollthreshold; /* Movement distance before virtual scrolling */ 400122605Sdes} rodent = { 401131525Sstefanf .flags = 0, 402131525Sstefanf .portname = NULL, 403131525Sstefanf .rtype = MOUSE_PROTO_UNKNOWN, 404131525Sstefanf .level = -1, 405131525Sstefanf .baudrate = 1200, 406131525Sstefanf .rate = 0, 407131525Sstefanf .resolution = MOUSE_RES_UNKNOWN, 408131525Sstefanf .zmap = { 0, 0, 0, 0 }, 409131525Sstefanf .wmode = 0, 410131525Sstefanf .mfd = -1, 411131525Sstefanf .cfd = -1, 412131525Sstefanf .mremsfd = -1, 413131525Sstefanf .mremcfd = -1, 414131525Sstefanf .clickthreshold = DFLT_CLICKTHRESHOLD, 415131525Sstefanf .button2timeout = DFLT_BUTTON2TIMEOUT, 416131525Sstefanf .accelx = 1.0, 417131525Sstefanf .accely = 1.0, 418136372Sphilip .scrollthreshold = DFLT_SCROLLTHRESHOLD, 41931604Syokota}; 42016566Ssos 42131604Syokota/* button status */ 42258344Syokotastruct button_state { 42331604Syokota int count; /* 0: up, 1: single click, 2: double click,... */ 42458344Syokota struct timeval tv; /* timestamp on the last button event */ 42558344Syokota}; 42658344Syokotastatic struct button_state bstate[MOUSE_MAXBUTTON]; /* button state */ 42758344Syokotastatic struct button_state *mstate[MOUSE_MAXBUTTON];/* mapped button st.*/ 42858344Syokotastatic struct button_state zstate[4]; /* Z/W axis state */ 42916566Ssos 43058344Syokota/* state machine for 3 button emulation */ 43158344Syokota 43258344Syokota#define S0 0 /* start */ 43358344Syokota#define S1 1 /* button 1 delayed down */ 43458344Syokota#define S2 2 /* button 3 delayed down */ 43558344Syokota#define S3 3 /* both buttons down -> button 2 down */ 43658344Syokota#define S4 4 /* button 1 delayed up */ 43758344Syokota#define S5 5 /* button 1 down */ 43858344Syokota#define S6 6 /* button 3 down */ 43958344Syokota#define S7 7 /* both buttons down */ 44058344Syokota#define S8 8 /* button 3 delayed up */ 44158344Syokota#define S9 9 /* button 1 or 3 up after S3 */ 44258344Syokota 44358344Syokota#define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0)) 44458344Syokota#define A_TIMEOUT 4 44579430Siedowse#define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st)) 44658344Syokota 44758344Syokotastatic struct { 44858344Syokota int s[A_TIMEOUT + 1]; 44958344Syokota int buttons; 45058344Syokota int mask; 45159090Syokota int timeout; 45258344Syokota} states[10] = { 45358344Syokota /* S0 */ 45459090Syokota { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE }, 45558344Syokota /* S1 */ 45659090Syokota { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE }, 45758344Syokota /* S2 */ 45859090Syokota { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE }, 45958344Syokota /* S3 */ 46059090Syokota { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE }, 46158344Syokota /* S4 */ 46259090Syokota { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE }, 46358344Syokota /* S5 */ 46459090Syokota { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE }, 46558344Syokota /* S6 */ 46659090Syokota { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE }, 46758344Syokota /* S7 */ 46859090Syokota { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE }, 46958344Syokota /* S8 */ 47059090Syokota { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE }, 47158344Syokota /* S9 */ 47259090Syokota { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE }, 47358344Syokota}; 47458344Syokotastatic int mouse_button_state; 47558344Syokotastatic struct timeval mouse_button_state_tv; 47679430Siedowsestatic int mouse_move_delayed; 47758344Syokota 47831604Syokotastatic jmp_buf env; 47916566Ssos 480150310Sphilipstatic int drift_distance = 4; /* max steps X+Y */ 481150310Sphilipstatic int drift_time = 500; /* in 0.5 sec */ 482150310Sphilipstatic struct timeval drift_time_tv; 483150310Sphilipstatic struct timeval drift_2time_tv; /* 2*drift_time */ 484150310Sphilipstatic int drift_after = 4000; /* 4 sec */ 485150310Sphilipstatic struct timeval drift_after_tv; 486150310Sphilipstatic int drift_terminate = FALSE; 487150310Sphilipstatic struct timeval drift_current_tv; 488150310Sphilipstatic struct timeval drift_tmp; 489150310Sphilipstatic struct timeval drift_last_activity = {0,0}; 490150310Sphilipstatic struct drift_xy { 491150310Sphilip int x; int y; } drift_last = {0,0}; /* steps in last drift_time */ 492150310Sphilipstatic struct timeval drift_since = {0,0}; 493150310Sphilipstatic struct drift_xy drift_previous={0,0}; /* steps in previous drift_time */ 494150310Sphilip 49531604Syokota/* function prototypes */ 49616566Ssos 49731604Syokotastatic void moused(void); 49831604Syokotastatic void hup(int sig); 49936991Sahastystatic void cleanup(int sig); 500153070Sphilipstatic void pause_mouse(int sig); 50131604Syokotastatic void usage(void); 50295629Siedowsestatic void log_or_warn(int log_pri, int errnum, const char *fmt, ...) 50395629Siedowse __printflike(3, 4); 50431604Syokota 50531604Syokotastatic int r_identify(void); 50631604Syokotastatic char *r_if(int type); 50731604Syokotastatic char *r_name(int type); 50831604Syokotastatic char *r_model(int model); 50931604Syokotastatic void r_init(void); 51031604Syokotastatic int r_protocol(u_char b, mousestatus_t *act); 51158344Syokotastatic int r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans); 51231604Syokotastatic int r_installmap(char *arg); 51331604Syokotastatic void r_map(mousestatus_t *act1, mousestatus_t *act2); 51458344Syokotastatic void r_timestamp(mousestatus_t *act); 51558344Syokotastatic int r_timeout(void); 51631604Syokotastatic void r_click(mousestatus_t *act); 51731604Syokotastatic void setmousespeed(int old, int new, unsigned cflag); 51831604Syokota 51940255Syokotastatic int pnpwakeup1(void); 52040255Syokotastatic int pnpwakeup2(void); 52131604Syokotastatic int pnpgets(char *buf); 52231604Syokotastatic int pnpparse(pnpid_t *id, char *buf, int len); 52331604Syokotastatic symtab_t *pnpproto(pnpid_t *id); 52431604Syokota 52531604Syokotastatic symtab_t *gettoken(symtab_t *tab, char *s, int len); 52631604Syokotastatic char *gettokenname(symtab_t *tab, int val); 52731604Syokota 52836991Sahastystatic void mremote_serversetup(); 52936991Sahastystatic void mremote_clientchg(int add); 53036991Sahasty 531122854Sdesstatic int kidspad(u_char rxc, mousestatus_t *act); 532145001Smdoddstatic int gtco_digipad(u_char, mousestatus_t *); 53341271Syokota 534122854Sdesstatic int usbmodule(void); 535122852Sdes 53651287Speterint 53716566Ssosmain(int argc, char *argv[]) 53816566Ssos{ 53931604Syokota int c; 54031604Syokota int i; 54158231Syokota int j; 542122630Sdes int retry; 54316566Ssos 54458344Syokota for (i = 0; i < MOUSE_MAXBUTTON; ++i) 54558344Syokota mstate[i] = &bstate[i]; 54658344Syokota 547150310Sphilip while ((c = getopt(argc, argv, "3C:DE:F:HI:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1) 54831604Syokota switch(c) { 54931604Syokota 55031604Syokota case '3': 55131604Syokota rodent.flags |= Emulate3Button; 55231604Syokota break; 55331604Syokota 55458344Syokota case 'E': 55558344Syokota rodent.button2timeout = atoi(optarg); 556122605Sdes if ((rodent.button2timeout < 0) || 557122605Sdes (rodent.button2timeout > MAX_BUTTON2TIMEOUT)) { 558122605Sdes warnx("invalid argument `%s'", optarg); 559122605Sdes usage(); 56058344Syokota } 56158344Syokota break; 56258344Syokota 56378770Sgreid case 'a': 56478770Sgreid i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely); 56578770Sgreid if (i == 0) { 56678770Sgreid warnx("invalid acceleration argument '%s'", optarg); 56778770Sgreid usage(); 56878770Sgreid } 569122605Sdes 57078770Sgreid if (i == 1) 57178770Sgreid rodent.accely = rodent.accelx; 572122605Sdes 57378770Sgreid break; 574122605Sdes 57516566Ssos case 'c': 57616566Ssos rodent.flags |= ChordMiddle; 57716566Ssos break; 57816566Ssos 57916566Ssos case 'd': 58031604Syokota ++debug; 58116566Ssos break; 58216566Ssos 58316566Ssos case 'f': 58431604Syokota nodaemon = TRUE; 58516566Ssos break; 58616566Ssos 58731604Syokota case 'i': 58831604Syokota if (strcmp(optarg, "all") == 0) 589122605Sdes identify = ID_ALL; 59031604Syokota else if (strcmp(optarg, "port") == 0) 591122605Sdes identify = ID_PORT; 59231604Syokota else if (strcmp(optarg, "if") == 0) 593122605Sdes identify = ID_IF; 59431604Syokota else if (strcmp(optarg, "type") == 0) 595122605Sdes identify = ID_TYPE; 59631604Syokota else if (strcmp(optarg, "model") == 0) 597122605Sdes identify = ID_MODEL; 59831604Syokota else { 599122605Sdes warnx("invalid argument `%s'", optarg); 600122605Sdes usage(); 60131604Syokota } 60231604Syokota nodaemon = TRUE; 60331604Syokota break; 60431604Syokota 60531604Syokota case 'l': 60631604Syokota rodent.level = atoi(optarg); 60731604Syokota if ((rodent.level < 0) || (rodent.level > 4)) { 608122605Sdes warnx("invalid argument `%s'", optarg); 609122605Sdes usage(); 61031604Syokota } 61131604Syokota break; 61231604Syokota 61331604Syokota case 'm': 61431604Syokota if (!r_installmap(optarg)) { 615122605Sdes warnx("invalid argument `%s'", optarg); 616122605Sdes usage(); 61731604Syokota } 61831604Syokota break; 61931604Syokota 62016566Ssos case 'p': 62116566Ssos rodent.portname = optarg; 62216566Ssos break; 62316566Ssos 62424377Speter case 'r': 62531604Syokota if (strcmp(optarg, "high") == 0) 626122605Sdes rodent.resolution = MOUSE_RES_HIGH; 62731604Syokota else if (strcmp(optarg, "medium-high") == 0) 628122605Sdes rodent.resolution = MOUSE_RES_HIGH; 62931604Syokota else if (strcmp(optarg, "medium-low") == 0) 630122605Sdes rodent.resolution = MOUSE_RES_MEDIUMLOW; 63131604Syokota else if (strcmp(optarg, "low") == 0) 632122605Sdes rodent.resolution = MOUSE_RES_LOW; 63331604Syokota else if (strcmp(optarg, "default") == 0) 634122605Sdes rodent.resolution = MOUSE_RES_DEFAULT; 63531604Syokota else { 636122605Sdes rodent.resolution = atoi(optarg); 637122605Sdes if (rodent.resolution <= 0) { 638122605Sdes warnx("invalid argument `%s'", optarg); 639122605Sdes usage(); 640122605Sdes } 64131604Syokota } 64224377Speter break; 64324377Speter 64416566Ssos case 's': 64516566Ssos rodent.baudrate = 9600; 64618222Speter break; 64716566Ssos 64841270Syokota case 'w': 64941270Syokota i = atoi(optarg); 65041270Syokota if ((i <= 0) || (i > MOUSE_MAXBUTTON)) { 65141270Syokota warnx("invalid argument `%s'", optarg); 65241270Syokota usage(); 65341270Syokota } 65441270Syokota rodent.wmode = 1 << (i - 1); 65541270Syokota break; 65641270Syokota 65731604Syokota case 'z': 65831604Syokota if (strcmp(optarg, "x") == 0) 65958231Syokota rodent.zmap[0] = MOUSE_XAXIS; 66031604Syokota else if (strcmp(optarg, "y") == 0) 66158231Syokota rodent.zmap[0] = MOUSE_YAXIS; 662122605Sdes else { 66331604Syokota i = atoi(optarg); 664122605Sdes /* 665122605Sdes * Use button i for negative Z axis movement and 66631604Syokota * button (i + 1) for positive Z axis movement. 66731604Syokota */ 66831604Syokota if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) { 669122605Sdes warnx("invalid argument `%s'", optarg); 670122605Sdes usage(); 67131604Syokota } 67258344Syokota rodent.zmap[0] = i; 67358344Syokota rodent.zmap[1] = i + 1; 67458861Syokota debug("optind: %d, optarg: '%s'", optind, optarg); 67558231Syokota for (j = 1; j < 4; ++j) { 67658231Syokota if ((optind >= argc) || !isdigit(*argv[optind])) 67758231Syokota break; 67858231Syokota i = atoi(argv[optind]); 67958231Syokota if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) { 68058231Syokota warnx("invalid argument `%s'", argv[optind]); 68158231Syokota usage(); 68258231Syokota } 68358344Syokota rodent.zmap[j] = i; 68458231Syokota ++optind; 68558231Syokota } 68659090Syokota if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0)) 68758344Syokota rodent.zmap[3] = rodent.zmap[2] + 1; 68831604Syokota } 68918222Speter break; 69018222Speter 69131604Syokota case 'C': 69231604Syokota rodent.clickthreshold = atoi(optarg); 693122605Sdes if ((rodent.clickthreshold < 0) || 694122605Sdes (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) { 695122605Sdes warnx("invalid argument `%s'", optarg); 696122605Sdes usage(); 69731604Syokota } 69831604Syokota break; 69931604Syokota 70018222Speter case 'D': 70131604Syokota rodent.flags |= ClearDTR; 70218222Speter break; 70318222Speter 70431604Syokota case 'F': 70531604Syokota rodent.rate = atoi(optarg); 70631604Syokota if (rodent.rate <= 0) { 707122605Sdes warnx("invalid argument `%s'", optarg); 708122605Sdes usage(); 70931604Syokota } 71031604Syokota break; 71131604Syokota 712148161Sphilip case 'H': 713148161Sphilip rodent.flags |= HVirtualScroll; 714148161Sphilip break; 715148161Sphilip 71634152Sjkh case 'I': 71734152Sjkh pidfile = optarg; 71834152Sjkh break; 71934152Sjkh 72031604Syokota case 'P': 72131604Syokota rodent.flags |= NoPnP; 72231604Syokota break; 72331604Syokota 72431604Syokota case 'R': 72531604Syokota rodent.flags |= ClearRTS; 72631604Syokota break; 72731604Syokota 72818222Speter case 'S': 72918222Speter rodent.baudrate = atoi(optarg); 73031604Syokota if (rodent.baudrate <= 0) { 731122605Sdes warnx("invalid argument `%s'", optarg); 732122605Sdes usage(); 73331604Syokota } 73418222Speter debug("rodent baudrate %d", rodent.baudrate); 73518222Speter break; 73618222Speter 737150310Sphilip case 'T': 738150310Sphilip drift_terminate = TRUE; 739150310Sphilip sscanf(optarg, "%d,%d,%d", &drift_distance, &drift_time, 740150310Sphilip &drift_after); 741150310Sphilip if (drift_distance <= 0 || drift_time <= 0 || drift_after <= 0) { 742150310Sphilip warnx("invalid argument `%s'", optarg); 743150310Sphilip usage(); 744150310Sphilip } 745150310Sphilip debug("terminate drift: distance %d, time %d, after %d", 746150310Sphilip drift_distance, drift_time, drift_after); 747150310Sphilip drift_time_tv.tv_sec = drift_time/1000; 748150310Sphilip drift_time_tv.tv_usec = (drift_time%1000)*1000; 749150310Sphilip drift_2time_tv.tv_sec = (drift_time*=2)/1000; 750150310Sphilip drift_2time_tv.tv_usec = (drift_time%1000)*1000; 751150310Sphilip drift_after_tv.tv_sec = drift_after/1000; 752150310Sphilip drift_after_tv.tv_usec = (drift_after%1000)*1000; 753150310Sphilip break; 754150310Sphilip 75516566Ssos case 't': 75631949Syokota if (strcmp(optarg, "auto") == 0) { 75731949Syokota rodent.rtype = MOUSE_PROTO_UNKNOWN; 75831949Syokota rodent.flags &= ~NoPnP; 75931949Syokota rodent.level = -1; 76031949Syokota break; 76131949Syokota } 76216566Ssos for (i = 0; rnames[i]; i++) 76331949Syokota if (strcmp(optarg, rnames[i]) == 0) { 76416566Ssos rodent.rtype = i; 76531949Syokota rodent.flags |= NoPnP; 76631949Syokota rodent.level = (i == MOUSE_PROTO_SYSMOUSE) ? 1 : 0; 76716566Ssos break; 76816566Ssos } 76916566Ssos if (rnames[i]) 77016566Ssos break; 77131604Syokota warnx("no such mouse type `%s'", optarg); 77216566Ssos usage(); 77316566Ssos 774136372Sphilip case 'V': 775136372Sphilip rodent.flags |= VirtualScroll; 776136372Sphilip break; 777136372Sphilip case 'U': 778136372Sphilip rodent.scrollthreshold = atoi(optarg); 779136372Sphilip if (rodent.scrollthreshold < 0) { 780136372Sphilip warnx("invalid argument `%s'", optarg); 781136372Sphilip usage(); 782136372Sphilip } 783136372Sphilip break; 784136372Sphilip 78516566Ssos case 'h': 78616566Ssos case '?': 78716566Ssos default: 78816566Ssos usage(); 78916566Ssos } 79016566Ssos 79159090Syokota /* fix Z axis mapping */ 79259090Syokota for (i = 0; i < 4; ++i) { 79359090Syokota if (rodent.zmap[i] > 0) { 79459090Syokota for (j = 0; j < MOUSE_MAXBUTTON; ++j) { 79559090Syokota if (mstate[j] == &bstate[rodent.zmap[i] - 1]) 79659090Syokota mstate[j] = &zstate[i]; 79759090Syokota } 79859090Syokota rodent.zmap[i] = 1 << (rodent.zmap[i] - 1); 79959090Syokota } 80059090Syokota } 80159090Syokota 80231604Syokota /* the default port name */ 80331604Syokota switch(rodent.rtype) { 80431604Syokota 80531604Syokota case MOUSE_PROTO_INPORT: 806122605Sdes /* INPORT and BUS are the same... */ 80731604Syokota rodent.rtype = MOUSE_PROTO_BUS; 808102413Scharnier /* FALLTHROUGH */ 80931604Syokota case MOUSE_PROTO_BUS: 81016566Ssos if (!rodent.portname) 81116566Ssos rodent.portname = "/dev/mse0"; 81216566Ssos break; 81331604Syokota 81431604Syokota case MOUSE_PROTO_PS2: 81516566Ssos if (!rodent.portname) 81616566Ssos rodent.portname = "/dev/psm0"; 81716566Ssos break; 81831604Syokota 81916566Ssos default: 82016566Ssos if (rodent.portname) 82116566Ssos break; 82229849Scharnier warnx("no port name specified"); 82316566Ssos usage(); 82416566Ssos } 82516566Ssos 826122630Sdes retry = 1; 827122630Sdes if (strncmp(rodent.portname, "/dev/ums", 8) == 0) { 828124339Ssobomax if (usbmodule() != 0) 829124339Ssobomax retry = 5; 830122630Sdes } 831122630Sdes 83231604Syokota for (;;) { 83331604Syokota if (setjmp(env) == 0) { 83431604Syokota signal(SIGHUP, hup); 83536991Sahasty signal(SIGINT , cleanup); 83636991Sahasty signal(SIGQUIT, cleanup); 83736991Sahasty signal(SIGTERM, cleanup); 838153070Sphilip signal(SIGUSR1, pause_mouse); 839122630Sdes for (i = 0; i < retry; ++i) { 840124339Ssobomax if (i > 0) 841124339Ssobomax sleep(2); 842122630Sdes rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK); 843122630Sdes if (rodent.mfd != -1 || errno != ENOENT) 844122630Sdes break; 845122630Sdes } 846122630Sdes if (rodent.mfd == -1) 847122605Sdes logerr(1, "unable to open %s", rodent.portname); 848122605Sdes if (r_identify() == MOUSE_PROTO_UNKNOWN) { 849122605Sdes logwarnx("cannot determine mouse type on %s", rodent.portname); 850122605Sdes close(rodent.mfd); 851122605Sdes rodent.mfd = -1; 852122605Sdes } 85331604Syokota 85431604Syokota /* print some information */ 855122605Sdes if (identify != ID_NONE) { 85631604Syokota if (identify == ID_ALL) 857122605Sdes printf("%s %s %s %s\n", 858122605Sdes rodent.portname, r_if(rodent.hw.iftype), 859122605Sdes r_name(rodent.rtype), r_model(rodent.hw.model)); 86031604Syokota else if (identify & ID_PORT) 86131604Syokota printf("%s\n", rodent.portname); 86231604Syokota else if (identify & ID_IF) 86331604Syokota printf("%s\n", r_if(rodent.hw.iftype)); 86431604Syokota else if (identify & ID_TYPE) 86531604Syokota printf("%s\n", r_name(rodent.rtype)); 86631604Syokota else if (identify & ID_MODEL) 86731604Syokota printf("%s\n", r_model(rodent.hw.model)); 86831604Syokota exit(0); 86931604Syokota } else { 870122605Sdes debug("port: %s interface: %s type: %s model: %s", 87131604Syokota rodent.portname, r_if(rodent.hw.iftype), 87231604Syokota r_name(rodent.rtype), r_model(rodent.hw.model)); 87331604Syokota } 87431604Syokota 87531604Syokota if (rodent.mfd == -1) { 876122605Sdes /* 877122605Sdes * We cannot continue because of error. Exit if the 878122605Sdes * program has not become a daemon. Otherwise, block 879122605Sdes * until the the user corrects the problem and issues SIGHUP. 880122605Sdes */ 881122605Sdes if (!background) 88231604Syokota exit(1); 883122605Sdes sigpause(0); 88431604Syokota } 88531604Syokota 886122605Sdes r_init(); /* call init function */ 88731604Syokota moused(); 88831604Syokota } 88931604Syokota 89031604Syokota if (rodent.mfd != -1) 89131604Syokota close(rodent.mfd); 89231604Syokota if (rodent.cfd != -1) 89331604Syokota close(rodent.cfd); 89431604Syokota rodent.mfd = rodent.cfd = -1; 89516566Ssos } 89631604Syokota /* NOT REACHED */ 89716566Ssos 89831604Syokota exit(0); 89931604Syokota} 90016566Ssos 901122852Sdesstatic int 902122852Sdesusbmodule(void) 903122852Sdes{ 904122852Sdes struct kld_file_stat fstat; 905122852Sdes struct module_stat mstat; 906122852Sdes int fileid, modid; 907122852Sdes int loaded; 908122852Sdes 909122852Sdes for (loaded = 0, fileid = kldnext(0); !loaded && fileid > 0; 910122852Sdes fileid = kldnext(fileid)) { 911122852Sdes fstat.version = sizeof(fstat); 912122852Sdes if (kldstat(fileid, &fstat) < 0) 913122852Sdes continue; 914122852Sdes if (strncmp(fstat.name, "uhub/ums", 8) == 0) { 915122852Sdes loaded = 1; 916122852Sdes break; 917122852Sdes } 918122852Sdes for (modid = kldfirstmod(fileid); modid > 0; 919122852Sdes modid = modfnext(modid)) { 920122852Sdes mstat.version = sizeof(mstat); 921122852Sdes if (modstat(modid, &mstat) < 0) 922122852Sdes continue; 923122852Sdes if (strncmp(mstat.name, "uhub/ums", 8) == 0) { 924122852Sdes loaded = 1; 925122852Sdes break; 926122852Sdes } 927122852Sdes } 928122852Sdes } 929124339Ssobomax if (!loaded) { 930124339Ssobomax if (kldload("ums") != -1) 931124339Ssobomax return 1; 932124339Ssobomax if (errno != EEXIST) 933124339Ssobomax logerr(1, "unable to load USB mouse driver"); 934124339Ssobomax } 935124339Ssobomax return 0; 936122852Sdes} 937122852Sdes 93831604Syokotastatic void 93931604Syokotamoused(void) 94031604Syokota{ 94131604Syokota struct mouse_info mouse; 94258344Syokota mousestatus_t action0; /* original mouse action */ 94358344Syokota mousestatus_t action; /* interrim buffer */ 94431604Syokota mousestatus_t action2; /* mapped action */ 94558344Syokota struct timeval timeout; 94631604Syokota fd_set fds; 94731604Syokota u_char b; 948149426Spjd pid_t mpid; 94958344Syokota int flags; 95058344Syokota int c; 95158344Syokota int i; 95231604Syokota 95331604Syokota if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1) 95495629Siedowse logerr(1, "cannot open /dev/consolectl"); 95531604Syokota 95695629Siedowse if (!nodaemon && !background) { 957150214Spjd pfh = pidfile_open(pidfile, 0600, &mpid); 958149426Spjd if (pfh == NULL) { 959149426Spjd if (errno == EEXIST) 960149426Spjd logerrx(1, "moused already running, pid: %d", mpid); 961149426Spjd logwarn("cannot open pid file"); 962149426Spjd } 96331604Syokota if (daemon(0, 0)) { 964149426Spjd int saved_errno = errno; 965149426Spjd pidfile_remove(pfh); 966149426Spjd errno = saved_errno; 96795629Siedowse logerr(1, "failed to become a daemon"); 96831604Syokota } else { 96931604Syokota background = TRUE; 970149426Spjd pidfile_write(pfh); 97116566Ssos } 97295629Siedowse } 97316566Ssos 97431604Syokota /* clear mouse data */ 97558344Syokota bzero(&action0, sizeof(action0)); 97631604Syokota bzero(&action, sizeof(action)); 97731604Syokota bzero(&action2, sizeof(action2)); 97831604Syokota bzero(&mouse, sizeof(mouse)); 97958344Syokota mouse_button_state = S0; 98058344Syokota gettimeofday(&mouse_button_state_tv, NULL); 98179430Siedowse mouse_move_delayed = 0; 98258344Syokota for (i = 0; i < MOUSE_MAXBUTTON; ++i) { 98358344Syokota bstate[i].count = 0; 98458344Syokota bstate[i].tv = mouse_button_state_tv; 98558344Syokota } 98658344Syokota for (i = 0; i < sizeof(zstate)/sizeof(zstate[0]); ++i) { 98758344Syokota zstate[i].count = 0; 98858344Syokota zstate[i].tv = mouse_button_state_tv; 98958344Syokota } 99031604Syokota 99131604Syokota /* choose which ioctl command to use */ 99231604Syokota mouse.operation = MOUSE_MOTION_EVENT; 99331604Syokota extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0); 99431604Syokota 99531604Syokota /* process mouse data */ 99658344Syokota timeout.tv_sec = 0; 99758344Syokota timeout.tv_usec = 20000; /* 20 msec */ 99831604Syokota for (;;) { 99931604Syokota 100021885Ssos FD_ZERO(&fds); 100131604Syokota FD_SET(rodent.mfd, &fds); 100258344Syokota if (rodent.mremsfd >= 0) 100358344Syokota FD_SET(rodent.mremsfd, &fds); 100458344Syokota if (rodent.mremcfd >= 0) 100558344Syokota FD_SET(rodent.mremcfd, &fds); 100636991Sahasty 100758344Syokota c = select(FD_SETSIZE, &fds, NULL, NULL, 100858344Syokota (rodent.flags & Emulate3Button) ? &timeout : NULL); 100958344Syokota if (c < 0) { /* error */ 101095629Siedowse logwarn("failed to read from mouse"); 101136991Sahasty continue; 101258344Syokota } else if (c == 0) { /* timeout */ 101358344Syokota /* assert(rodent.flags & Emulate3Button) */ 101458344Syokota action0.button = action0.obutton; 101558344Syokota action0.dx = action0.dy = action0.dz = 0; 101658344Syokota action0.flags = flags = 0; 101758344Syokota if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) { 101858344Syokota if (debug > 2) 101958344Syokota debug("flags:%08x buttons:%08x obuttons:%08x", 102058344Syokota action.flags, action.button, action.obutton); 102158344Syokota } else { 102258344Syokota action0.obutton = action0.button; 102358344Syokota continue; 102458344Syokota } 102558344Syokota } else { 102658344Syokota /* MouseRemote client connect/disconnect */ 102758344Syokota if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) { 102858344Syokota mremote_clientchg(TRUE); 102958344Syokota continue; 103058344Syokota } 103158344Syokota if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) { 103258344Syokota mremote_clientchg(FALSE); 103358344Syokota continue; 103458344Syokota } 103558344Syokota /* mouse movement */ 103658344Syokota if (read(rodent.mfd, &b, 1) == -1) { 103758344Syokota if (errno == EWOULDBLOCK) 103858344Syokota continue; 103958344Syokota else 104058344Syokota return; 104158344Syokota } 104258344Syokota if ((flags = r_protocol(b, &action0)) == 0) 104358344Syokota continue; 1044136372Sphilip 1045148161Sphilip if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) { 1046136372Sphilip /* Allow middle button drags to scroll up and down */ 1047136372Sphilip if (action0.button == MOUSE_BUTTON2DOWN) { 1048136372Sphilip if (scroll_state == SCROLL_NOTSCROLLING) { 1049136372Sphilip scroll_state = SCROLL_PREPARE; 1050136372Sphilip debug("PREPARING TO SCROLL"); 1051136372Sphilip } 1052136372Sphilip debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x", 1053136372Sphilip action.flags, action.button, action.obutton); 1054136372Sphilip } else { 1055136372Sphilip debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x", 1056136372Sphilip action.flags, action.button, action.obutton); 1057136372Sphilip 1058136372Sphilip /* This isn't a middle button down... move along... */ 1059136372Sphilip if (scroll_state == SCROLL_SCROLLING) { 1060136372Sphilip /* 1061136372Sphilip * We were scrolling, someone let go of button 2. 1062136372Sphilip * Now turn autoscroll off. 1063136372Sphilip */ 1064136372Sphilip scroll_state = SCROLL_NOTSCROLLING; 1065136372Sphilip debug("DONE WITH SCROLLING / %d", scroll_state); 1066136372Sphilip } else if (scroll_state == SCROLL_PREPARE) { 1067136372Sphilip mousestatus_t newaction = action0; 1068136372Sphilip 1069136372Sphilip /* We were preparing to scroll, but we never moved... */ 1070136372Sphilip r_timestamp(&action0); 1071136372Sphilip r_statetrans(&action0, &newaction, 1072136372Sphilip A(newaction.button & MOUSE_BUTTON1DOWN, 1073136372Sphilip action0.button & MOUSE_BUTTON3DOWN)); 1074136372Sphilip 1075136372Sphilip /* Send middle down */ 1076136372Sphilip newaction.button = MOUSE_BUTTON2DOWN; 1077136372Sphilip r_click(&newaction); 1078136372Sphilip 1079136372Sphilip /* Send middle up */ 1080136372Sphilip r_timestamp(&newaction); 1081136372Sphilip newaction.obutton = newaction.button; 1082136372Sphilip newaction.button = action0.button; 1083136372Sphilip r_click(&newaction); 1084136372Sphilip } 1085136372Sphilip } 1086136372Sphilip } 1087136372Sphilip 108858344Syokota r_timestamp(&action0); 1089122605Sdes r_statetrans(&action0, &action, 1090122605Sdes A(action0.button & MOUSE_BUTTON1DOWN, 1091122605Sdes action0.button & MOUSE_BUTTON3DOWN)); 109258344Syokota debug("flags:%08x buttons:%08x obuttons:%08x", action.flags, 109358344Syokota action.button, action.obutton); 109436991Sahasty } 109558344Syokota action0.obutton = action0.button; 109658344Syokota flags &= MOUSE_POSCHANGED; 109758344Syokota flags |= action.obutton ^ action.button; 109858344Syokota action.flags = flags; 109936991Sahasty 110058344Syokota if (flags) { /* handler detected action */ 110131604Syokota r_map(&action, &action2); 110231604Syokota debug("activity : buttons 0x%08x dx %d dy %d dz %d", 110331604Syokota action2.button, action2.dx, action2.dy, action2.dz); 110431604Syokota 1105148161Sphilip if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) { 1106136372Sphilip /* 1107136372Sphilip * If *only* the middle button is pressed AND we are moving 1108136372Sphilip * the stick/trackpoint/nipple, scroll! 1109136372Sphilip */ 1110136372Sphilip if (scroll_state == SCROLL_PREPARE) { 1111136372Sphilip /* Ok, Set we're really scrolling now.... */ 1112136372Sphilip if (action2.dy || action2.dx) 1113136372Sphilip scroll_state = SCROLL_SCROLLING; 1114136372Sphilip } 1115136372Sphilip if (scroll_state == SCROLL_SCROLLING) { 1116148161Sphilip if (rodent.flags & VirtualScroll) { 1117148161Sphilip scroll_movement += action2.dy; 1118148161Sphilip debug("SCROLL: %d", scroll_movement); 1119136372Sphilip 1120148161Sphilip if (scroll_movement < -rodent.scrollthreshold) { 1121148161Sphilip /* Scroll down */ 1122148161Sphilip action2.dz = -1; 1123148161Sphilip scroll_movement = 0; 1124148161Sphilip } 1125148161Sphilip else if (scroll_movement > rodent.scrollthreshold) { 1126148161Sphilip /* Scroll up */ 1127148161Sphilip action2.dz = 1; 1128148161Sphilip scroll_movement = 0; 1129148161Sphilip } 1130148161Sphilip } 1131148161Sphilip if (rodent.flags & HVirtualScroll) { 1132148161Sphilip hscroll_movement += action2.dx; 1133148161Sphilip debug("HORIZONTAL SCROLL: %d", hscroll_movement); 1134136372Sphilip 1135148161Sphilip if (hscroll_movement < -rodent.scrollthreshold) { 1136148161Sphilip action2.dz = -2; 1137148161Sphilip hscroll_movement = 0; 1138148161Sphilip } 1139148161Sphilip else if (hscroll_movement > rodent.scrollthreshold) { 1140148161Sphilip action2.dz = 2; 1141148161Sphilip hscroll_movement = 0; 1142148161Sphilip } 1143148161Sphilip } 1144148161Sphilip 1145136372Sphilip /* Don't move while scrolling */ 1146136372Sphilip action2.dx = action2.dy = 0; 1147136372Sphilip } 1148136372Sphilip } 1149136372Sphilip 1150150310Sphilip if (drift_terminate) { 1151150310Sphilip if (flags != MOUSE_POSCHANGED || action.dz || action2.dz) 1152150310Sphilip drift_last_activity = drift_current_tv; 1153150310Sphilip else { 1154150310Sphilip /* X or/and Y movement only - possibly drift */ 1155150310Sphilip timersub(&drift_current_tv,&drift_last_activity,&drift_tmp); 1156150310Sphilip if (timercmp(&drift_tmp, &drift_after_tv, >)) { 1157150310Sphilip timersub(&drift_current_tv, &drift_since, &drift_tmp); 1158150310Sphilip if (timercmp(&drift_tmp, &drift_time_tv, <)) { 1159150310Sphilip drift_last.x += action2.dx; 1160150310Sphilip drift_last.y += action2.dy; 1161150310Sphilip } else { 1162150310Sphilip /* discard old accumulated steps (drift) */ 1163150310Sphilip if (timercmp(&drift_tmp, &drift_2time_tv, >)) 1164150310Sphilip drift_previous.x = drift_previous.y = 0; 1165150310Sphilip else 1166150310Sphilip drift_previous = drift_last; 1167150310Sphilip drift_last.x = action2.dx; 1168150310Sphilip drift_last.y = action2.dy; 1169150310Sphilip drift_since = drift_current_tv; 1170150310Sphilip } 1171150310Sphilip if (abs(drift_last.x) + abs(drift_last.y) 1172150310Sphilip > drift_distance) { 1173150310Sphilip /* real movement, pass all accumulated steps */ 1174150310Sphilip action2.dx = drift_previous.x + drift_last.x; 1175150310Sphilip action2.dy = drift_previous.y + drift_last.y; 1176150310Sphilip /* and reset accumulators */ 1177150310Sphilip timerclear(&drift_since); 1178150310Sphilip drift_last.x = drift_last.y = 0; 1179150310Sphilip /* drift_previous will be cleared at next movement*/ 1180150310Sphilip drift_last_activity = drift_current_tv; 1181150310Sphilip } else { 1182150310Sphilip continue; /* don't pass current movement to 1183150310Sphilip * console driver */ 1184150310Sphilip } 1185150310Sphilip } 1186150310Sphilip } 1187150310Sphilip } 1188150310Sphilip 118931604Syokota if (extioctl) { 1190136372Sphilip /* Defer clicks until we aren't VirtualScroll'ing. */ 1191136372Sphilip if (scroll_state == SCROLL_NOTSCROLLING) 1192136372Sphilip r_click(&action2); 1193136372Sphilip 1194122605Sdes if (action2.flags & MOUSE_POSCHANGED) { 1195122605Sdes mouse.operation = MOUSE_MOTION_EVENT; 1196122605Sdes mouse.u.data.buttons = action2.button; 1197122605Sdes mouse.u.data.x = action2.dx * rodent.accelx; 1198122605Sdes mouse.u.data.y = action2.dy * rodent.accely; 1199122605Sdes mouse.u.data.z = action2.dz; 120031604Syokota if (debug < 2) 1201153070Sphilip if (!paused) 1202153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 1203122605Sdes } 120431604Syokota } else { 1205122605Sdes mouse.operation = MOUSE_ACTION; 1206122605Sdes mouse.u.data.buttons = action2.button; 1207122605Sdes mouse.u.data.x = action2.dx * rodent.accelx; 1208122605Sdes mouse.u.data.y = action2.dy * rodent.accely; 1209122605Sdes mouse.u.data.z = action2.dz; 121031604Syokota if (debug < 2) 1211153070Sphilip if (!paused) 1212153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 121331604Syokota } 121431604Syokota 1215108533Sschweikh /* 1216108533Sschweikh * If the Z axis movement is mapped to an imaginary physical 121731604Syokota * button, we need to cook up a corresponding button `up' event 121831604Syokota * after sending a button `down' event. 121931604Syokota */ 1220122605Sdes if ((rodent.zmap[0] > 0) && (action.dz != 0)) { 122131604Syokota action.obutton = action.button; 122231604Syokota action.dx = action.dy = action.dz = 0; 1223122605Sdes r_map(&action, &action2); 1224122605Sdes debug("activity : buttons 0x%08x dx %d dy %d dz %d", 122531604Syokota action2.button, action2.dx, action2.dy, action2.dz); 122631604Syokota 1227122605Sdes if (extioctl) { 1228122605Sdes r_click(&action2); 1229122605Sdes } else { 1230122605Sdes mouse.operation = MOUSE_ACTION; 1231122605Sdes mouse.u.data.buttons = action2.button; 123231604Syokota mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0; 123331604Syokota if (debug < 2) 1234153070Sphilip if (!paused) 1235153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 1236122605Sdes } 123731604Syokota } 123816566Ssos } 123916566Ssos } 124031604Syokota /* NOT REACHED */ 1241122605Sdes} 124216566Ssos 124331604Syokotastatic void 124431604Syokotahup(int sig) 124531604Syokota{ 124631604Syokota longjmp(env, 1); 124731604Syokota} 124816566Ssos 1249122605Sdesstatic void 125036991Sahastycleanup(int sig) 125136991Sahasty{ 125236991Sahasty if (rodent.rtype == MOUSE_PROTO_X10MOUSEREM) 125336991Sahasty unlink(_PATH_MOUSEREMOTE); 125436991Sahasty exit(0); 125536991Sahasty} 125636991Sahasty 1257153070Sphilipstatic void 1258153070Sphilippause_mouse(int sig) 1259153070Sphilip{ 1260153070Sphilip paused = !paused; 1261153070Sphilip} 1262153070Sphilip 126316566Ssos/** 126416566Ssos ** usage 126516566Ssos ** 126616566Ssos ** Complain, and free the CPU for more worthy tasks 126716566Ssos **/ 126831604Syokotastatic void 126916566Ssosusage(void) 127016566Ssos{ 1271150310Sphilip fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 127258344Syokota "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]", 1273150310Sphilip " [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]", 1274150310Sphilip " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]", 1275150310Sphilip " [-T distance[,time[,after]]] -p <port>", 127681364Sdougb " moused [-d] -i <port|if|type|model|all> -p <port>"); 127716566Ssos exit(1); 127816566Ssos} 127916566Ssos 128095629Siedowse/* 128195629Siedowse * Output an error message to syslog or stderr as appropriate. If 128295629Siedowse * `errnum' is non-zero, append its string form to the message. 128395629Siedowse */ 128495629Siedowsestatic void 128595629Siedowselog_or_warn(int log_pri, int errnum, const char *fmt, ...) 128695629Siedowse{ 128795629Siedowse va_list ap; 128895629Siedowse char buf[256]; 128995629Siedowse 129095629Siedowse va_start(ap, fmt); 129195629Siedowse vsnprintf(buf, sizeof(buf), fmt, ap); 129295629Siedowse va_end(ap); 129395629Siedowse if (errnum) { 129495629Siedowse strlcat(buf, ": ", sizeof(buf)); 129595629Siedowse strlcat(buf, strerror(errnum), sizeof(buf)); 129695629Siedowse } 129795629Siedowse 129895629Siedowse if (background) 129995629Siedowse syslog(log_pri, "%s", buf); 130095629Siedowse else 130195629Siedowse warnx("%s", buf); 130295629Siedowse} 130395629Siedowse 130416566Ssos/** 130516566Ssos ** Mouse interface code, courtesy of XFree86 3.1.2. 130616566Ssos ** 130716566Ssos ** Note: Various bits have been trimmed, and in my shortsighted enthusiasm 130816566Ssos ** to clean, reformat and rationalise naming, it's quite possible that 130916566Ssos ** some things in here have been broken. 131016566Ssos ** 131116566Ssos ** I hope not 8) 131216566Ssos ** 131316566Ssos ** The following code is derived from a module marked : 131416566Ssos **/ 131516566Ssos 131616566Ssos/* $XConsortium: xf86_Mouse.c,v 1.2 94/10/12 20:33:21 kaleb Exp $ */ 131716566Ssos/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.2 1995/01/28 131816566Ssos 17:03:40 dawes Exp $ */ 131916566Ssos/* 132016566Ssos * 132116566Ssos * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 132216566Ssos * Copyright 1993 by David Dawes <dawes@physics.su.oz.au> 132316566Ssos * 132416566Ssos * Permission to use, copy, modify, distribute, and sell this software and its 132516566Ssos * documentation for any purpose is hereby granted without fee, provided that 132616566Ssos * the above copyright notice appear in all copies and that both that 132716566Ssos * copyright notice and this permission notice appear in supporting 132816566Ssos * documentation, and that the names of Thomas Roell and David Dawes not be 132916566Ssos * used in advertising or publicity pertaining to distribution of the 133016566Ssos * software without specific, written prior permission. Thomas Roell 133116566Ssos * and David Dawes makes no representations about the suitability of this 133216566Ssos * software for any purpose. It is provided "as is" without express or 133316566Ssos * implied warranty. 133416566Ssos * 133516566Ssos * THOMAS ROELL AND DAVID DAWES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 133616566Ssos * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 133716566Ssos * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR DAVID DAWES BE LIABLE FOR ANY 133816566Ssos * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 133916566Ssos * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 134016566Ssos * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 134116566Ssos * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 134216566Ssos * 134316566Ssos */ 134416566Ssos 134531604Syokota/** 134631604Syokota ** GlidePoint support from XFree86 3.2. 134731604Syokota ** Derived from the module: 134831604Syokota **/ 134916566Ssos 135031604Syokota/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */ 135131604Syokota/* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */ 135231604Syokota 135331604Syokota/* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */ 135431604Syokotastatic unsigned char proto[][7] = { 135531604Syokota /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */ 1356122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */ 135731604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */ 135831604Syokota { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */ 135931604Syokota { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */ 1360122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* MouseMan */ 136131604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */ 136231604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */ 136331604Syokota { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */ 136431604Syokota { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */ 1365122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */ 1366122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */ 1367122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */ 136831604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */ 1369122605Sdes { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* X10 MouseRem */ 137041271Syokota { 0x80, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* KIDSPAD */ 137149967Syokota { 0xc3, 0xc0, 0x00, 0x00, 6, 0x00, 0xff }, /* VersaPad */ 137293071Swill { 0x00, 0x00, 0x00, 0x00, 1, 0x00, 0xff }, /* JogDial */ 137331604Syokota#if notyet 137431604Syokota { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */ 137531604Syokota#endif 137631604Syokota}; 137731604Syokotastatic unsigned char cur_proto[7]; 137831604Syokota 137931604Syokotastatic int 138031604Syokotar_identify(void) 138131604Syokota{ 138231604Syokota char pnpbuf[256]; /* PnP identifier string may be up to 256 bytes long */ 138331604Syokota pnpid_t pnpid; 138431604Syokota symtab_t *t; 138531604Syokota int level; 138631604Syokota int len; 138731604Syokota 138831604Syokota /* set the driver operation level, if applicable */ 138931604Syokota if (rodent.level < 0) 139031604Syokota rodent.level = 1; 139131604Syokota ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level); 139231604Syokota rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0; 139331604Syokota 139431604Syokota /* 1395122605Sdes * Interrogate the driver and get some intelligence on the device... 139631604Syokota * The following ioctl functions are not always supported by device 139731604Syokota * drivers. When the driver doesn't support them, we just trust the 139831604Syokota * user to supply valid information. 139931604Syokota */ 140031604Syokota rodent.hw.iftype = MOUSE_IF_UNKNOWN; 140131604Syokota rodent.hw.model = MOUSE_MODEL_GENERIC; 140231604Syokota ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw); 140331604Syokota 140431604Syokota if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1405122605Sdes bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 140631604Syokota rodent.mode.protocol = MOUSE_PROTO_UNKNOWN; 140731604Syokota rodent.mode.rate = -1; 140831604Syokota rodent.mode.resolution = MOUSE_RES_UNKNOWN; 140931604Syokota rodent.mode.accelfactor = 0; 141031604Syokota rodent.mode.level = 0; 141131604Syokota if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) { 1412122605Sdes if ((rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) 141331604Syokota || (rodent.mode.protocol >= sizeof(proto)/sizeof(proto[0]))) { 141431604Syokota logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol); 141531604Syokota return MOUSE_PROTO_UNKNOWN; 1416122605Sdes } else { 141731604Syokota /* INPORT and BUS are the same... */ 141831604Syokota if (rodent.mode.protocol == MOUSE_PROTO_INPORT) 1419122605Sdes rodent.mode.protocol = MOUSE_PROTO_BUS; 142031604Syokota if (rodent.mode.protocol != rodent.rtype) { 142131604Syokota /* Hmm, the driver doesn't agree with the user... */ 1422122605Sdes if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1423122605Sdes logwarnx("mouse type mismatch (%s != %s), %s is assumed", 1424122605Sdes r_name(rodent.mode.protocol), r_name(rodent.rtype), 1425122605Sdes r_name(rodent.mode.protocol)); 1426122605Sdes rodent.rtype = rodent.mode.protocol; 1427122605Sdes bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 142831604Syokota } 1429122605Sdes } 1430122605Sdes cur_proto[4] = rodent.mode.packetsize; 1431122605Sdes cur_proto[0] = rodent.mode.syncmask[0]; /* header byte bit mask */ 1432122605Sdes cur_proto[1] = rodent.mode.syncmask[1]; /* header bit pattern */ 143331604Syokota } 143431604Syokota 1435108470Sschweikh /* maybe this is a PnP mouse... */ 143631604Syokota if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) { 143731604Syokota 1438122605Sdes if (rodent.flags & NoPnP) 1439122605Sdes return rodent.rtype; 144031604Syokota if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len)) 1441122605Sdes return rodent.rtype; 144231604Syokota 1443122605Sdes debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'", 1444122605Sdes pnpid.neisaid, pnpid.neisaid, pnpid.eisaid, 1445122605Sdes pnpid.ncompat, pnpid.ncompat, pnpid.compat, 144631604Syokota pnpid.ndescription, pnpid.ndescription, pnpid.description); 144731604Syokota 144831604Syokota /* we have a valid PnP serial device ID */ 1449122605Sdes rodent.hw.iftype = MOUSE_IF_SERIAL; 145031604Syokota t = pnpproto(&pnpid); 145131604Syokota if (t != NULL) { 1452122605Sdes rodent.mode.protocol = t->val; 1453122605Sdes rodent.hw.model = t->val2; 145431604Syokota } else { 1455122605Sdes rodent.mode.protocol = MOUSE_PROTO_UNKNOWN; 145631604Syokota } 145731604Syokota if (rodent.mode.protocol == MOUSE_PROTO_INPORT) 145831604Syokota rodent.mode.protocol = MOUSE_PROTO_BUS; 145931604Syokota 1460122605Sdes /* make final adjustment */ 146131604Syokota if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) { 146231604Syokota if (rodent.mode.protocol != rodent.rtype) { 146331604Syokota /* Hmm, the device doesn't agree with the user... */ 1464122605Sdes if (rodent.rtype != MOUSE_PROTO_UNKNOWN) 1465122605Sdes logwarnx("mouse type mismatch (%s != %s), %s is assumed", 1466122605Sdes r_name(rodent.mode.protocol), r_name(rodent.rtype), 1467122605Sdes r_name(rodent.mode.protocol)); 1468122605Sdes rodent.rtype = rodent.mode.protocol; 1469122605Sdes bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto)); 147031604Syokota } 147131604Syokota } 147231604Syokota } 147331604Syokota 147431604Syokota debug("proto params: %02x %02x %02x %02x %d %02x %02x", 1475122605Sdes cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3], 147631604Syokota cur_proto[4], cur_proto[5], cur_proto[6]); 147731604Syokota 147831604Syokota return rodent.rtype; 147931604Syokota} 148031604Syokota 148131604Syokotastatic char * 148231604Syokotar_if(int iftype) 148331604Syokota{ 148431604Syokota char *s; 148531604Syokota 148631604Syokota s = gettokenname(rifs, iftype); 148731604Syokota return (s == NULL) ? "unknown" : s; 148831604Syokota} 148931604Syokota 149031604Syokotastatic char * 149131604Syokotar_name(int type) 149231604Syokota{ 1493122605Sdes return ((type == MOUSE_PROTO_UNKNOWN) 149431604Syokota || (type > sizeof(rnames)/sizeof(rnames[0]) - 1)) 149531604Syokota ? "unknown" : rnames[type]; 149631604Syokota} 149731604Syokota 149831604Syokotastatic char * 149931604Syokotar_model(int model) 150031604Syokota{ 150131604Syokota char *s; 150231604Syokota 150331604Syokota s = gettokenname(rmodels, model); 150431604Syokota return (s == NULL) ? "unknown" : s; 150531604Syokota} 150631604Syokota 150731604Syokotastatic void 150816566Ssosr_init(void) 150916566Ssos{ 151049967Syokota unsigned char buf[16]; /* scrach buffer */ 151131604Syokota fd_set fds; 151231604Syokota char *s; 151331604Syokota char c; 151431604Syokota int i; 151531604Syokota 151616566Ssos /** 1517122605Sdes ** This comment is a little out of context here, but it contains 151816566Ssos ** some useful information... 151916566Ssos ******************************************************************** 152016566Ssos ** 152116566Ssos ** The following lines take care of the Logitech MouseMan protocols. 152216566Ssos ** 152316566Ssos ** NOTE: There are different versions of both MouseMan and TrackMan! 152416566Ssos ** Hence I add another protocol P_LOGIMAN, which the user can 152516566Ssos ** specify as MouseMan in his XF86Config file. This entry was 152616566Ssos ** formerly handled as a special case of P_MS. However, people 152716566Ssos ** who don't have the middle button problem, can still specify 152816566Ssos ** Microsoft and use P_MS. 152916566Ssos ** 153016566Ssos ** By default, these mice should use a 3 byte Microsoft protocol 153116566Ssos ** plus a 4th byte for the middle button. However, the mouse might 153216566Ssos ** have switched to a different protocol before we use it, so I send 153316566Ssos ** the proper sequence just in case. 153416566Ssos ** 153516566Ssos ** NOTE: - all commands to (at least the European) MouseMan have to 153616566Ssos ** be sent at 1200 Baud. 153716566Ssos ** - each command starts with a '*'. 153816566Ssos ** - whenever the MouseMan receives a '*', it will switch back 153916566Ssos ** to 1200 Baud. Hence I have to select the desired protocol 154016566Ssos ** first, then select the baud rate. 154116566Ssos ** 154216566Ssos ** The protocols supported by the (European) MouseMan are: 154316566Ssos ** - 5 byte packed binary protocol, as with the Mouse Systems 154416566Ssos ** mouse. Selected by sequence "*U". 154516566Ssos ** - 2 button 3 byte MicroSoft compatible protocol. Selected 154616566Ssos ** by sequence "*V". 154716566Ssos ** - 3 button 3+1 byte MicroSoft compatible protocol (default). 154816566Ssos ** Selected by sequence "*X". 154916566Ssos ** 155016566Ssos ** The following baud rates are supported: 155116566Ssos ** - 1200 Baud (default). Selected by sequence "*n". 155216566Ssos ** - 9600 Baud. Selected by sequence "*q". 155316566Ssos ** 155416566Ssos ** Selecting a sample rate is no longer supported with the MouseMan! 155516566Ssos ** Some additional lines in xf86Config.c take care of ill configured 155616566Ssos ** baud rates and sample rates. (The user will get an error.) 155716566Ssos */ 155816566Ssos 155931604Syokota switch (rodent.rtype) { 156031604Syokota 156131604Syokota case MOUSE_PROTO_LOGI: 1562122605Sdes /* 156331604Syokota * The baud rate selection command must be sent at the current 1564122605Sdes * baud rate; try all likely settings 156531604Syokota */ 156631604Syokota setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]); 156731604Syokota setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]); 156831604Syokota setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]); 156931604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 157031604Syokota /* select MM series data format */ 157131604Syokota write(rodent.mfd, "S", 1); 157231604Syokota setmousespeed(rodent.baudrate, rodent.baudrate, 157331604Syokota rodentcflags[MOUSE_PROTO_MM]); 157431604Syokota /* select report rate/frequency */ 157531604Syokota if (rodent.rate <= 0) write(rodent.mfd, "O", 1); 157631604Syokota else if (rodent.rate <= 15) write(rodent.mfd, "J", 1); 157731604Syokota else if (rodent.rate <= 27) write(rodent.mfd, "K", 1); 157831604Syokota else if (rodent.rate <= 42) write(rodent.mfd, "L", 1); 157931604Syokota else if (rodent.rate <= 60) write(rodent.mfd, "R", 1); 158031604Syokota else if (rodent.rate <= 85) write(rodent.mfd, "M", 1); 158131604Syokota else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1); 158231604Syokota else write(rodent.mfd, "N", 1); 158331604Syokota break; 158431604Syokota 158531604Syokota case MOUSE_PROTO_LOGIMOUSEMAN: 158631604Syokota /* The command must always be sent at 1200 baud */ 158731604Syokota setmousespeed(1200, 1200, rodentcflags[rodent.rtype]); 158816566Ssos write(rodent.mfd, "*X", 2); 158931604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 159031604Syokota break; 159118222Speter 159231604Syokota case MOUSE_PROTO_HITTAB: 159331604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 159418222Speter 159531604Syokota /* 159631604Syokota * Initialize Hitachi PUMA Plus - Model 1212E to desired settings. 159731604Syokota * The tablet must be configured to be in MM mode, NO parity, 159831604Syokota * Binary Format. xf86Info.sampleRate controls the sensativity 159931604Syokota * of the tablet. We only use this tablet for it's 4-button puck 160031604Syokota * so we don't run in "Absolute Mode" 160131604Syokota */ 160231604Syokota write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */ 160331604Syokota usleep(50000); 160431604Syokota write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */ 160531604Syokota usleep(50000); 160631604Syokota write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */ 160731604Syokota usleep(50000); 160831604Syokota write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */ 160931604Syokota usleep(50000); 161031604Syokota write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */ 161131604Syokota usleep(50000); 161231604Syokota write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */ 161331604Syokota usleep(50000); 161418222Speter 161531604Syokota /* Resolution is in 'lines per inch' on the Hitachi tablet */ 1616122605Sdes if (rodent.resolution == MOUSE_RES_LOW) c = 'g'; 161731604Syokota else if (rodent.resolution == MOUSE_RES_MEDIUMLOW) c = 'e'; 161831604Syokota else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH) c = 'h'; 161931604Syokota else if (rodent.resolution == MOUSE_RES_HIGH) c = 'd'; 1620122605Sdes else if (rodent.resolution <= 40) c = 'g'; 1621122605Sdes else if (rodent.resolution <= 100) c = 'd'; 1622122605Sdes else if (rodent.resolution <= 200) c = 'e'; 1623122605Sdes else if (rodent.resolution <= 500) c = 'h'; 1624122605Sdes else if (rodent.resolution <= 1000) c = 'j'; 1625122605Sdes else c = 'd'; 162631604Syokota write(rodent.mfd, &c, 1); 162731604Syokota usleep(50000); 162818222Speter 162931604Syokota write(rodent.mfd, "\021", 1); /* Resume DATA output */ 163031604Syokota break; 163131604Syokota 163231604Syokota case MOUSE_PROTO_THINK: 163331604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 163431604Syokota /* the PnP ID string may be sent again, discard it */ 163531604Syokota usleep(200000); 163631604Syokota i = FREAD; 163731604Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 163831604Syokota /* send the command to initialize the beast */ 163931604Syokota for (s = "E5E5"; *s; ++s) { 164031604Syokota write(rodent.mfd, s, 1); 164131604Syokota FD_ZERO(&fds); 164231604Syokota FD_SET(rodent.mfd, &fds); 164331604Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0) 164431604Syokota break; 164531604Syokota read(rodent.mfd, &c, 1); 164631604Syokota debug("%c", c); 164731604Syokota if (c != *s) 1648122605Sdes break; 164918222Speter } 165031604Syokota break; 165131604Syokota 165293071Swill case MOUSE_PROTO_JOGDIAL: 165393071Swill break; 165431604Syokota case MOUSE_PROTO_MSC: 165531604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 165631604Syokota if (rodent.flags & ClearDTR) { 165731604Syokota i = TIOCM_DTR; 165831604Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 1659122605Sdes } 1660122605Sdes if (rodent.flags & ClearRTS) { 166131604Syokota i = TIOCM_RTS; 166231604Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 1663122605Sdes } 166431604Syokota break; 166531604Syokota 166631726Syokota case MOUSE_PROTO_SYSMOUSE: 166731726Syokota if (rodent.hw.iftype == MOUSE_IF_SYSMOUSE) 166831726Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 1669102413Scharnier /* FALLTHROUGH */ 167031726Syokota 167131604Syokota case MOUSE_PROTO_BUS: 167231604Syokota case MOUSE_PROTO_INPORT: 167331604Syokota case MOUSE_PROTO_PS2: 167431604Syokota if (rodent.rate >= 0) 167531604Syokota rodent.mode.rate = rodent.rate; 167631604Syokota if (rodent.resolution != MOUSE_RES_UNKNOWN) 167731604Syokota rodent.mode.resolution = rodent.resolution; 167831604Syokota ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode); 167931604Syokota break; 168031604Syokota 168136991Sahasty case MOUSE_PROTO_X10MOUSEREM: 168236991Sahasty mremote_serversetup(); 168336991Sahasty setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 168436991Sahasty break; 168536991Sahasty 168636991Sahasty 168749967Syokota case MOUSE_PROTO_VERSAPAD: 168849967Syokota tcsendbreak(rodent.mfd, 0); /* send break for 400 msec */ 168949967Syokota i = FREAD; 169049967Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 169149967Syokota for (i = 0; i < 7; ++i) { 169249967Syokota FD_ZERO(&fds); 169349967Syokota FD_SET(rodent.mfd, &fds); 169449967Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0) 169549967Syokota break; 169649967Syokota read(rodent.mfd, &c, 1); 169749967Syokota buf[i] = c; 169849967Syokota } 169949967Syokota debug("%s\n", buf); 170049967Syokota if ((buf[0] != 'V') || (buf[1] != 'P')|| (buf[7] != '\r')) 170149967Syokota break; 170249967Syokota setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]); 170349967Syokota tcsendbreak(rodent.mfd, 0); /* send break for 400 msec again */ 170449967Syokota for (i = 0; i < 7; ++i) { 170549967Syokota FD_ZERO(&fds); 170649967Syokota FD_SET(rodent.mfd, &fds); 170749967Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0) 170849967Syokota break; 170949967Syokota read(rodent.mfd, &c, 1); 171049967Syokota debug("%c", c); 171149967Syokota if (c != buf[i]) 171249967Syokota break; 171349967Syokota } 171449967Syokota i = FREAD; 171549967Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 171649967Syokota break; 171749967Syokota 171831604Syokota default: 171931604Syokota setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]); 172031604Syokota break; 172116566Ssos } 172216566Ssos} 172316566Ssos 172431604Syokotastatic int 172531604Syokotar_protocol(u_char rBuf, mousestatus_t *act) 172616566Ssos{ 172731604Syokota /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 1728122605Sdes static int butmapmss[4] = { /* Microsoft, MouseMan, GlidePoint, 172931604Syokota IntelliMouse, Thinking Mouse */ 1730122605Sdes 0, 1731122605Sdes MOUSE_BUTTON3DOWN, 1732122605Sdes MOUSE_BUTTON1DOWN, 1733122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 173431604Syokota }; 1735122605Sdes static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint, 173631604Syokota Thinking Mouse */ 1737122605Sdes 0, 1738122605Sdes MOUSE_BUTTON4DOWN, 1739122605Sdes MOUSE_BUTTON2DOWN, 1740122605Sdes MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN, 174131604Syokota }; 174231604Syokota /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 174331604Syokota static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse, 174431604Syokota MouseMan+ */ 1745122605Sdes 0, 1746122605Sdes MOUSE_BUTTON2DOWN, 1747122605Sdes MOUSE_BUTTON4DOWN, 1748122605Sdes MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN, 174931604Syokota }; 175031604Syokota /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */ 1751122605Sdes static int butmapmsc[8] = { /* MouseSystems, MMSeries, Logitech, 175231604Syokota Bus, sysmouse */ 1753122605Sdes 0, 1754122605Sdes MOUSE_BUTTON3DOWN, 1755122605Sdes MOUSE_BUTTON2DOWN, 1756122605Sdes MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 1757122605Sdes MOUSE_BUTTON1DOWN, 1758122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 175931604Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 176031604Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 176131604Syokota }; 176231604Syokota /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */ 176331604Syokota static int butmapps2[8] = { /* PS/2 */ 1764122605Sdes 0, 1765122605Sdes MOUSE_BUTTON1DOWN, 1766122605Sdes MOUSE_BUTTON3DOWN, 1767122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1768122605Sdes MOUSE_BUTTON2DOWN, 1769122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 177031604Syokota MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 177131604Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 177231604Syokota }; 177331604Syokota /* for Hitachi tablet */ 177431604Syokota static int butmaphit[8] = { /* MM HitTablet */ 1775122605Sdes 0, 1776122605Sdes MOUSE_BUTTON3DOWN, 1777122605Sdes MOUSE_BUTTON2DOWN, 1778122605Sdes MOUSE_BUTTON1DOWN, 1779122605Sdes MOUSE_BUTTON4DOWN, 1780122605Sdes MOUSE_BUTTON5DOWN, 1781122605Sdes MOUSE_BUTTON6DOWN, 1782122605Sdes MOUSE_BUTTON7DOWN, 178331604Syokota }; 178449967Syokota /* for serial VersaPad */ 178549967Syokota static int butmapversa[8] = { /* VersaPad */ 1786122605Sdes 0, 1787122605Sdes 0, 1788122605Sdes MOUSE_BUTTON3DOWN, 1789122605Sdes MOUSE_BUTTON3DOWN, 1790122605Sdes MOUSE_BUTTON1DOWN, 1791122605Sdes MOUSE_BUTTON1DOWN, 1792122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1793122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 179449967Syokota }; 179549967Syokota /* for PS/2 VersaPad */ 179649967Syokota static int butmapversaps2[8] = { /* VersaPad */ 1797122605Sdes 0, 1798122605Sdes MOUSE_BUTTON3DOWN, 1799122605Sdes 0, 1800122605Sdes MOUSE_BUTTON3DOWN, 1801122605Sdes MOUSE_BUTTON1DOWN, 1802122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 1803122605Sdes MOUSE_BUTTON1DOWN, 1804122605Sdes MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 180549967Syokota }; 180616566Ssos static int pBufP = 0; 180716566Ssos static unsigned char pBuf[8]; 180849967Syokota static int prev_x, prev_y; 180949967Syokota static int on = FALSE; 181049967Syokota int x, y; 181116566Ssos 181216566Ssos debug("received char 0x%x",(int)rBuf); 181341271Syokota if (rodent.rtype == MOUSE_PROTO_KIDSPAD) 181441271Syokota return kidspad(rBuf, act) ; 1815145001Smdodd if (rodent.rtype == MOUSE_PROTO_GTCO_DIGIPAD) 1816145001Smdodd return gtco_digipad(rBuf, act); 181716566Ssos 181816566Ssos /* 181916566Ssos * Hack for resyncing: We check here for a package that is: 182016566Ssos * a) illegal (detected by wrong data-package header) 182116566Ssos * b) invalid (0x80 == -128 and that might be wrong for MouseSystems) 182216566Ssos * c) bad header-package 182316566Ssos * 182416566Ssos * NOTE: b) is a voilation of the MouseSystems-Protocol, since values of 182516566Ssos * -128 are allowed, but since they are very seldom we can easily 182616566Ssos * use them as package-header with no button pressed. 182716566Ssos * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. Furthermore, 182816566Ssos * 0x80 is not valid as a header byte. For a PS/2 mouse we skip 182916566Ssos * checking data bytes. 183016566Ssos * For resyncing a PS/2 mouse we require the two most significant 183116566Ssos * bits in the header byte to be 0. These are the overflow bits, 183216566Ssos * and in case of an overflow we actually lose sync. Overflows 183316566Ssos * are very rare, however, and we quickly gain sync again after 183416566Ssos * an overflow condition. This is the best we can do. (Actually, 183516566Ssos * we could use bit 0x08 in the header byte for resyncing, since 183616566Ssos * that bit is supposed to be always on, but nobody told 183716566Ssos * Microsoft...) 183816566Ssos */ 183916566Ssos 184031604Syokota if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 && 184131604Syokota ((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80)) 184216566Ssos { 184316566Ssos pBufP = 0; /* skip package */ 184416566Ssos } 1845122605Sdes 184631604Syokota if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1]) 184731604Syokota return 0; 184831604Syokota 184931604Syokota /* is there an extra data byte? */ 185031604Syokota if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1]) 185116566Ssos { 185216566Ssos /* 185316566Ssos * Hack for Logitech MouseMan Mouse - Middle button 185416566Ssos * 185516566Ssos * Unfortunately this mouse has variable length packets: the standard 185616566Ssos * Microsoft 3 byte packet plus an optional 4th byte whenever the 185716566Ssos * middle button status changes. 185816566Ssos * 185916566Ssos * We have already processed the standard packet with the movement 186016566Ssos * and button info. Now post an event message with the old status 186116566Ssos * of the left and right buttons and the updated middle button. 186216566Ssos */ 186316566Ssos 186416566Ssos /* 186516566Ssos * Even worse, different MouseMen and TrackMen differ in the 4th 186616566Ssos * byte: some will send 0x00/0x20, others 0x01/0x21, or even 186716566Ssos * 0x02/0x22, so I have to strip off the lower bits. 1868122605Sdes * 1869122605Sdes * [JCH-96/01/21] 1870122605Sdes * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte" 1871122605Sdes * and it is activated by tapping the glidepad with the finger! 8^) 1872122605Sdes * We map it to bit bit3, and the reverse map in xf86Events just has 1873122605Sdes * to be extended so that it is identified as Button 4. The lower 1874122605Sdes * half of the reverse-map may remain unchanged. 187516566Ssos */ 187631604Syokota 1877122605Sdes /* 187831604Syokota * [KY-97/08/03] 187972645Sasmodai * Receive the fourth byte only when preceding three bytes have 188031604Syokota * been detected (pBufP >= cur_proto[4]). In the previous 188131604Syokota * versions, the test was pBufP == 0; thus, we may have mistakingly 1882122605Sdes * received a byte even if we didn't see anything preceding 188331604Syokota * the byte. 188431604Syokota */ 188531604Syokota 188631604Syokota if ((rBuf & cur_proto[5]) != cur_proto[6]) { 1887122605Sdes pBufP = 0; 188831604Syokota return 0; 188916566Ssos } 189016566Ssos 189131604Syokota switch (rodent.rtype) { 189231604Syokota#if notyet 189331604Syokota case MOUSE_PROTO_MARIQUA: 1894122605Sdes /* 189531604Syokota * This mouse has 16! buttons in addition to the standard 189631604Syokota * three of them. They return 0x10 though 0x1f in the 189731604Syokota * so-called `ten key' mode and 0x30 though 0x3f in the 1898122605Sdes * `function key' mode. As there are only 31 bits for 189931604Syokota * button state (including the standard three), we ignore 190031604Syokota * the bit 0x20 and don't distinguish the two modes. 190131604Syokota */ 190231604Syokota act->dx = act->dy = act->dz = 0; 190331604Syokota act->obutton = act->button; 190431604Syokota rBuf &= 0x1f; 190531604Syokota act->button = (1 << (rBuf - 13)) 1906122605Sdes | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 1907122605Sdes /* 1908122605Sdes * FIXME: this is a button "down" event. There needs to be 190931604Syokota * a corresponding button "up" event... XXX 191031604Syokota */ 191131604Syokota break; 191231604Syokota#endif /* notyet */ 191393071Swill case MOUSE_PROTO_JOGDIAL: 191493071Swill break; 191531604Syokota 191631604Syokota /* 191731604Syokota * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse 191831604Syokota * always send the fourth byte, whereas the fourth byte is 1919122605Sdes * optional for GlidePoint and ThinkingMouse. The fourth byte 1920122605Sdes * is also optional for MouseMan+ and FirstMouse+ in their 1921122605Sdes * native mode. It is always sent if they are in the IntelliMouse 192231604Syokota * compatible mode. 1923122605Sdes */ 192431604Syokota case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse, 192531604Syokota MouseMan+ */ 192631604Syokota act->dx = act->dy = 0; 192731604Syokota act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f); 192858231Syokota if ((act->dz >= 7) || (act->dz <= -7)) 192958231Syokota act->dz = 0; 193031604Syokota act->obutton = act->button; 193131604Syokota act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4] 193231604Syokota | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 193331604Syokota break; 193431604Syokota 193531604Syokota default: 193631604Syokota act->dx = act->dy = act->dz = 0; 193731604Syokota act->obutton = act->button; 193831604Syokota act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4] 193931604Syokota | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN)); 194031604Syokota break; 194131604Syokota } 194231604Syokota 194331604Syokota act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0) 194431604Syokota | (act->obutton ^ act->button); 1945122605Sdes pBufP = 0; 194631604Syokota return act->flags; 194716566Ssos } 1948122605Sdes 194931604Syokota if (pBufP >= cur_proto[4]) 195031604Syokota pBufP = 0; 195116566Ssos pBuf[pBufP++] = rBuf; 195231604Syokota if (pBufP != cur_proto[4]) 195331604Syokota return 0; 1954122605Sdes 195516566Ssos /* 195616566Ssos * assembly full package 195716566Ssos */ 195816566Ssos 195931604Syokota debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x", 1960122605Sdes cur_proto[4], 1961122605Sdes pBuf[0], pBuf[1], pBuf[2], pBuf[3], 196231604Syokota pBuf[4], pBuf[5], pBuf[6], pBuf[7]); 196316566Ssos 196431604Syokota act->dz = 0; 196531604Syokota act->obutton = act->button; 1966122605Sdes switch (rodent.rtype) 196716566Ssos { 196831604Syokota case MOUSE_PROTO_MS: /* Microsoft */ 196931604Syokota case MOUSE_PROTO_LOGIMOUSEMAN: /* MouseMan/TrackMan */ 197036991Sahasty case MOUSE_PROTO_X10MOUSEREM: /* X10 MouseRemote */ 197134074Syokota act->button = act->obutton & MOUSE_BUTTON4DOWN; 197216566Ssos if (rodent.flags & ChordMiddle) 197334074Syokota act->button |= ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS) 1974122605Sdes ? MOUSE_BUTTON2DOWN 197531604Syokota : butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 197616566Ssos else 197734074Syokota act->button |= (act->obutton & MOUSE_BUTTON2DOWN) 197831604Syokota | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 1979122605Sdes 198036991Sahasty /* Send X10 btn events to remote client (ensure -128-+127 range) */ 1981122605Sdes if ((rodent.rtype == MOUSE_PROTO_X10MOUSEREM) && 198236991Sahasty ((pBuf[0] & 0xFC) == 0x44) && (pBuf[2] == 0x3F)) { 198336991Sahasty if (rodent.mremcfd >= 0) { 1984122605Sdes unsigned char key = (signed char)(((pBuf[0] & 0x03) << 6) | 198536991Sahasty (pBuf[1] & 0x3F)); 1986122854Sdes write(rodent.mremcfd, &key, 1); 198736991Sahasty } 198836991Sahasty return 0; 198936991Sahasty } 199036991Sahasty 199196930Sknu act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); 199296930Sknu act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); 199316566Ssos break; 199431604Syokota 199531604Syokota case MOUSE_PROTO_GLIDEPOINT: /* GlidePoint */ 199631604Syokota case MOUSE_PROTO_THINK: /* ThinkingMouse */ 199731604Syokota case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse, 199831604Syokota MouseMan+ */ 199931604Syokota act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN)) 2000122605Sdes | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4]; 200196930Sknu act->dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); 200296930Sknu act->dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); 200331604Syokota break; 2004122605Sdes 200531604Syokota case MOUSE_PROTO_MSC: /* MouseSystems Corp */ 200631604Syokota#if notyet 200731604Syokota case MOUSE_PROTO_MARIQUA: /* Mariqua */ 200831604Syokota#endif 200931604Syokota act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS]; 201096930Sknu act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]); 201196930Sknu act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4])); 201216566Ssos break; 201393071Swill 201493071Swill case MOUSE_PROTO_JOGDIAL: /* JogDial */ 201593071Swill if (rBuf == 0x6c) 201696930Sknu act->dz = -1; 201793071Swill if (rBuf == 0x72) 201896930Sknu act->dz = 1; 201993071Swill if (rBuf == 0x64) 202093071Swill act->button = MOUSE_BUTTON1DOWN; 202193071Swill if (rBuf == 0x75) 202293071Swill act->button = 0; 202393071Swill break; 202493071Swill 202531604Syokota case MOUSE_PROTO_HITTAB: /* MM HitTablet */ 202631604Syokota act->button = butmaphit[pBuf[0] & 0x07]; 202731604Syokota act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1]; 202831604Syokota act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2]; 202918222Speter break; 203018222Speter 203131604Syokota case MOUSE_PROTO_MM: /* MM Series */ 203231604Syokota case MOUSE_PROTO_LOGI: /* Logitech Mice */ 203331604Syokota act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS]; 203431604Syokota act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1]; 203531604Syokota act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2]; 203616566Ssos break; 2037122605Sdes 203849967Syokota case MOUSE_PROTO_VERSAPAD: /* VersaPad */ 203949967Syokota act->button = butmapversa[(pBuf[0] & MOUSE_VERSA_BUTTONS) >> 3]; 204049967Syokota act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 204149967Syokota act->dx = act->dy = 0; 204249967Syokota if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) { 204349967Syokota on = FALSE; 204449967Syokota break; 204549967Syokota } 204649967Syokota x = (pBuf[2] << 6) | pBuf[1]; 204749967Syokota if (x & 0x800) 204849967Syokota x -= 0x1000; 204949967Syokota y = (pBuf[4] << 6) | pBuf[3]; 205049967Syokota if (y & 0x800) 205149967Syokota y -= 0x1000; 205249967Syokota if (on) { 205349967Syokota act->dx = prev_x - x; 205449967Syokota act->dy = prev_y - y; 205549967Syokota } else { 205649967Syokota on = TRUE; 205749967Syokota } 205849967Syokota prev_x = x; 205949967Syokota prev_y = y; 206049967Syokota break; 206149967Syokota 206231604Syokota case MOUSE_PROTO_BUS: /* Bus */ 206331604Syokota case MOUSE_PROTO_INPORT: /* InPort */ 206431604Syokota act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS]; 206596930Sknu act->dx = (signed char)pBuf[1]; 206696930Sknu act->dy = - (signed char)pBuf[2]; 206716566Ssos break; 206816566Ssos 206931604Syokota case MOUSE_PROTO_PS2: /* PS/2 */ 207031604Syokota act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS]; 207131604Syokota act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ? pBuf[1] - 256 : pBuf[1]; 207231604Syokota act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ? -(pBuf[2] - 256) : -pBuf[2]; 207331604Syokota /* 207431604Syokota * Moused usually operates the psm driver at the operation level 1 207531604Syokota * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol. 2076122605Sdes * The following code takes effect only when the user explicitly 2077122605Sdes * requets the level 2 at which wheel movement and additional button 207831604Syokota * actions are encoded in model-dependent formats. At the level 0 207931604Syokota * the following code is no-op because the psm driver says the model 208031604Syokota * is MOUSE_MODEL_GENERIC. 208131604Syokota */ 208231604Syokota switch (rodent.hw.model) { 208358231Syokota case MOUSE_MODEL_EXPLORER: 208458231Syokota /* wheel and additional button data is in the fourth byte */ 208558231Syokota act->dz = (pBuf[3] & MOUSE_EXPLORER_ZNEG) 208658231Syokota ? (pBuf[3] & 0x0f) - 16 : (pBuf[3] & 0x0f); 208758231Syokota act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON4DOWN) 208858231Syokota ? MOUSE_BUTTON4DOWN : 0; 208958231Syokota act->button |= (pBuf[3] & MOUSE_EXPLORER_BUTTON5DOWN) 209058231Syokota ? MOUSE_BUTTON5DOWN : 0; 209158231Syokota break; 209231604Syokota case MOUSE_MODEL_INTELLI: 209331604Syokota case MOUSE_MODEL_NET: 209431604Syokota /* wheel data is in the fourth byte */ 209596930Sknu act->dz = (signed char)pBuf[3]; 209658231Syokota if ((act->dz >= 7) || (act->dz <= -7)) 209758231Syokota act->dz = 0; 209858231Syokota /* some compatible mice may have additional buttons */ 209958231Syokota act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON4DOWN) 210058231Syokota ? MOUSE_BUTTON4DOWN : 0; 210158231Syokota act->button |= (pBuf[0] & MOUSE_PS2INTELLI_BUTTON5DOWN) 210258231Syokota ? MOUSE_BUTTON5DOWN : 0; 210331604Syokota break; 210431604Syokota case MOUSE_MODEL_MOUSEMANPLUS: 210548778Syokota if (((pBuf[0] & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) 210648778Syokota && (abs(act->dx) > 191) 210748778Syokota && MOUSE_PS2PLUS_CHECKBITS(pBuf)) { 210831604Syokota /* the extended data packet encodes button and wheel events */ 210948778Syokota switch (MOUSE_PS2PLUS_PACKET_TYPE(pBuf)) { 211048778Syokota case 1: 211148778Syokota /* wheel data packet */ 211248778Syokota act->dx = act->dy = 0; 211348778Syokota if (pBuf[2] & 0x80) { 211448778Syokota /* horizontal roller count - ignore it XXX*/ 211548778Syokota } else { 211648778Syokota /* vertical roller count */ 211748778Syokota act->dz = (pBuf[2] & MOUSE_PS2PLUS_ZNEG) 211848778Syokota ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); 211948778Syokota } 212048778Syokota act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN) 212148778Syokota ? MOUSE_BUTTON4DOWN : 0; 212248778Syokota act->button |= (pBuf[2] & MOUSE_PS2PLUS_BUTTON5DOWN) 212348778Syokota ? MOUSE_BUTTON5DOWN : 0; 212448778Syokota break; 212548778Syokota case 2: 212658231Syokota /* this packet type is reserved by Logitech */ 212758231Syokota /* 212858231Syokota * IBM ScrollPoint Mouse uses this packet type to 212958231Syokota * encode both vertical and horizontal scroll movement. 213058231Syokota */ 213158231Syokota act->dx = act->dy = 0; 213258231Syokota /* horizontal roller count */ 213358231Syokota if (pBuf[2] & 0x0f) 213458231Syokota act->dz = (pBuf[2] & MOUSE_SPOINT_WNEG) ? -2 : 2; 213558231Syokota /* vertical roller count */ 213658231Syokota if (pBuf[2] & 0xf0) 213758231Syokota act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1; 213858231Syokota#if 0 213958231Syokota /* vertical roller count */ 214058231Syokota act->dz = (pBuf[2] & MOUSE_SPOINT_ZNEG) 214158231Syokota ? ((pBuf[2] >> 4) & 0x0f) - 16 214258231Syokota : ((pBuf[2] >> 4) & 0x0f); 214358231Syokota /* horizontal roller count */ 214458231Syokota act->dw = (pBuf[2] & MOUSE_SPOINT_WNEG) 214558231Syokota ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); 214658231Syokota#endif 214758231Syokota break; 214848778Syokota case 0: 214948778Syokota /* device type packet - shouldn't happen */ 2150102413Scharnier /* FALLTHROUGH */ 215148778Syokota default: 215248778Syokota act->dx = act->dy = 0; 215348778Syokota act->button = act->obutton; 2154122605Sdes debug("unknown PS2++ packet type %d: 0x%02x 0x%02x 0x%02x\n", 215548778Syokota MOUSE_PS2PLUS_PACKET_TYPE(pBuf), 215648778Syokota pBuf[0], pBuf[1], pBuf[2]); 215748778Syokota break; 215848778Syokota } 215931604Syokota } else { 216031604Syokota /* preserve button states */ 216131604Syokota act->button |= act->obutton & MOUSE_EXTBUTTONS; 216231604Syokota } 216331604Syokota break; 216431604Syokota case MOUSE_MODEL_GLIDEPOINT: 216531604Syokota /* `tapping' action */ 216631604Syokota act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN; 216731604Syokota break; 216831604Syokota case MOUSE_MODEL_NETSCROLL: 216958231Syokota /* three addtional bytes encode buttons and wheel events */ 217058231Syokota act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN) 217131604Syokota ? MOUSE_BUTTON4DOWN : 0; 217258231Syokota act->button |= (pBuf[3] & MOUSE_PS2_BUTTON1DOWN) 217358231Syokota ? MOUSE_BUTTON5DOWN : 0; 217431604Syokota act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4]; 217531604Syokota break; 217631604Syokota case MOUSE_MODEL_THINK: 217731604Syokota /* the fourth button state in the first byte */ 217831604Syokota act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0; 217931604Syokota break; 218049967Syokota case MOUSE_MODEL_VERSAPAD: 218149967Syokota act->button = butmapversaps2[pBuf[0] & MOUSE_PS2VERSA_BUTTONS]; 218249967Syokota act->button |= 218349967Syokota (pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 218449967Syokota act->dx = act->dy = 0; 218549967Syokota if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) { 218649967Syokota on = FALSE; 218749967Syokota break; 218849967Syokota } 218949967Syokota x = ((pBuf[4] << 8) & 0xf00) | pBuf[1]; 219049967Syokota if (x & 0x800) 219149967Syokota x -= 0x1000; 219249967Syokota y = ((pBuf[4] << 4) & 0xf00) | pBuf[2]; 219349967Syokota if (y & 0x800) 219449967Syokota y -= 0x1000; 219549967Syokota if (on) { 219649967Syokota act->dx = prev_x - x; 219749967Syokota act->dy = prev_y - y; 219849967Syokota } else { 219949967Syokota on = TRUE; 220049967Syokota } 220149967Syokota prev_x = x; 220249967Syokota prev_y = y; 220349967Syokota break; 220458231Syokota case MOUSE_MODEL_4D: 220558231Syokota act->dx = (pBuf[1] & 0x80) ? pBuf[1] - 256 : pBuf[1]; 220658231Syokota act->dy = (pBuf[2] & 0x80) ? -(pBuf[2] - 256) : -pBuf[2]; 220758231Syokota switch (pBuf[0] & MOUSE_4D_WHEELBITS) { 220858231Syokota case 0x10: 220958231Syokota act->dz = 1; 221058231Syokota break; 221158231Syokota case 0x30: 221258231Syokota act->dz = -1; 221358231Syokota break; 221458231Syokota case 0x40: /* 2nd wheel rolling right XXX */ 221558231Syokota act->dz = 2; 221658231Syokota break; 221758231Syokota case 0xc0: /* 2nd wheel rolling left XXX */ 221858231Syokota act->dz = -2; 221958231Syokota break; 222058231Syokota } 222158231Syokota break; 222258231Syokota case MOUSE_MODEL_4DPLUS: 222358231Syokota if ((act->dx < 16 - 256) && (act->dy > 256 - 16)) { 222458231Syokota act->dx = act->dy = 0; 222558231Syokota if (pBuf[2] & MOUSE_4DPLUS_BUTTON4DOWN) 222658231Syokota act->button |= MOUSE_BUTTON4DOWN; 222758231Syokota act->dz = (pBuf[2] & MOUSE_4DPLUS_ZNEG) 222858231Syokota ? ((pBuf[2] & 0x07) - 8) : (pBuf[2] & 0x07); 222958231Syokota } else { 223058231Syokota /* preserve previous button states */ 223158231Syokota act->button |= act->obutton & MOUSE_EXTBUTTONS; 223258231Syokota } 223358231Syokota break; 223431604Syokota case MOUSE_MODEL_GENERIC: 223531604Syokota default: 223631604Syokota break; 223731604Syokota } 223816566Ssos break; 223931604Syokota 224031604Syokota case MOUSE_PROTO_SYSMOUSE: /* sysmouse */ 224131604Syokota act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS]; 224296930Sknu act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]); 224396930Sknu act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4])); 224431604Syokota if (rodent.level == 1) { 224596930Sknu act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1; 224631604Syokota act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3); 224731604Syokota } 224831604Syokota break; 224931604Syokota 225031604Syokota default: 225131604Syokota return 0; 225216566Ssos } 2253122605Sdes /* 225431604Syokota * We don't reset pBufP here yet, as there may be an additional data 225531604Syokota * byte in some protocols. See above. 225631604Syokota */ 225731604Syokota 225831604Syokota /* has something changed? */ 225931604Syokota act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0) 226031604Syokota | (act->obutton ^ act->button); 226131604Syokota 226258344Syokota return act->flags; 226358344Syokota} 226458344Syokota 226558344Syokotastatic int 226658344Syokotar_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans) 226758344Syokota{ 226858344Syokota int changed; 226958344Syokota int flags; 227058344Syokota 227158344Syokota a2->dx = a1->dx; 227258344Syokota a2->dy = a1->dy; 227358344Syokota a2->dz = a1->dz; 227458344Syokota a2->obutton = a2->button; 227558344Syokota a2->button = a1->button; 227658344Syokota a2->flags = a1->flags; 227758344Syokota changed = FALSE; 227858344Syokota 227931604Syokota if (rodent.flags & Emulate3Button) { 228058344Syokota if (debug > 2) 2281122605Sdes debug("state:%d, trans:%d -> state:%d", 228258344Syokota mouse_button_state, trans, 228358344Syokota states[mouse_button_state].s[trans]); 228479430Siedowse /* 228579430Siedowse * Avoid re-ordering button and movement events. While a button 228679430Siedowse * event is deferred, throw away up to BUTTON2_MAXMOVE movement 228779430Siedowse * events to allow for mouse jitter. If more movement events 228879430Siedowse * occur, then complete the deferred button events immediately. 228979430Siedowse */ 229079430Siedowse if ((a2->dx != 0 || a2->dy != 0) && 229179430Siedowse S_DELAYED(states[mouse_button_state].s[trans])) { 229279430Siedowse if (++mouse_move_delayed > BUTTON2_MAXMOVE) { 229379430Siedowse mouse_move_delayed = 0; 229479430Siedowse mouse_button_state = 229579430Siedowse states[mouse_button_state].s[A_TIMEOUT]; 229679430Siedowse changed = TRUE; 229779432Siedowse } else 229879430Siedowse a2->dx = a2->dy = 0; 229979430Siedowse } else 230079430Siedowse mouse_move_delayed = 0; 230179430Siedowse if (mouse_button_state != states[mouse_button_state].s[trans]) 230279430Siedowse changed = TRUE; 230379430Siedowse if (changed) 230479430Siedowse gettimeofday(&mouse_button_state_tv, NULL); 230558344Syokota mouse_button_state = states[mouse_button_state].s[trans]; 230658344Syokota a2->button &= 230758344Syokota ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN); 230858344Syokota a2->button &= states[mouse_button_state].mask; 230958344Syokota a2->button |= states[mouse_button_state].buttons; 231058344Syokota flags = a2->flags & MOUSE_POSCHANGED; 231158344Syokota flags |= a2->obutton ^ a2->button; 231258344Syokota if (flags & MOUSE_BUTTON2DOWN) { 231358344Syokota a2->flags = flags & MOUSE_BUTTON2DOWN; 231458344Syokota r_timestamp(a2); 231558344Syokota } 231658344Syokota a2->flags = flags; 231731604Syokota } 231858344Syokota return changed; 231916566Ssos} 232018222Speter 232131604Syokota/* phisical to logical button mapping */ 232231604Syokotastatic int p2l[MOUSE_MAXBUTTON] = { 2323122605Sdes MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN, 2324122605Sdes MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN, 232531604Syokota 0x00000100, 0x00000200, 0x00000400, 0x00000800, 232631604Syokota 0x00001000, 0x00002000, 0x00004000, 0x00008000, 232731604Syokota 0x00010000, 0x00020000, 0x00040000, 0x00080000, 232831604Syokota 0x00100000, 0x00200000, 0x00400000, 0x00800000, 232931604Syokota 0x01000000, 0x02000000, 0x04000000, 0x08000000, 233031604Syokota 0x10000000, 0x20000000, 0x40000000, 233131604Syokota}; 233231604Syokota 233331604Syokotastatic char * 233431604Syokotaskipspace(char *s) 233531604Syokota{ 233631604Syokota while(isspace(*s)) 233731604Syokota ++s; 233831604Syokota return s; 233931604Syokota} 234031604Syokota 234131604Syokotastatic int 234231604Syokotar_installmap(char *arg) 234331604Syokota{ 234431604Syokota int pbutton; 234531604Syokota int lbutton; 234631604Syokota char *s; 234731604Syokota 234831604Syokota while (*arg) { 234931604Syokota arg = skipspace(arg); 235031604Syokota s = arg; 235131604Syokota while (isdigit(*arg)) 235231604Syokota ++arg; 235331604Syokota arg = skipspace(arg); 235431604Syokota if ((arg <= s) || (*arg != '=')) 235531604Syokota return FALSE; 235631604Syokota lbutton = atoi(s); 235731604Syokota 235831604Syokota arg = skipspace(++arg); 235931604Syokota s = arg; 236031604Syokota while (isdigit(*arg)) 236131604Syokota ++arg; 236231604Syokota if ((arg <= s) || (!isspace(*arg) && (*arg != '\0'))) 236331604Syokota return FALSE; 236431604Syokota pbutton = atoi(s); 236531604Syokota 236631604Syokota if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON)) 236731604Syokota return FALSE; 236831604Syokota if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON)) 236931604Syokota return FALSE; 237031604Syokota p2l[pbutton - 1] = 1 << (lbutton - 1); 237158344Syokota mstate[lbutton - 1] = &bstate[pbutton - 1]; 237231604Syokota } 237331604Syokota 237431604Syokota return TRUE; 237531604Syokota} 237631604Syokota 237731604Syokotastatic void 237831604Syokotar_map(mousestatus_t *act1, mousestatus_t *act2) 237931604Syokota{ 238031604Syokota register int pb; 238131604Syokota register int pbuttons; 238231604Syokota int lbuttons; 238331604Syokota 238431604Syokota pbuttons = act1->button; 238531604Syokota lbuttons = 0; 238631604Syokota 238731604Syokota act2->obutton = act2->button; 238841270Syokota if (pbuttons & rodent.wmode) { 238941270Syokota pbuttons &= ~rodent.wmode; 239041270Syokota act1->dz = act1->dy; 239141270Syokota act1->dx = 0; 239241270Syokota act1->dy = 0; 239341270Syokota } 239431604Syokota act2->dx = act1->dx; 239531604Syokota act2->dy = act1->dy; 239631604Syokota act2->dz = act1->dz; 239731604Syokota 239858231Syokota switch (rodent.zmap[0]) { 239931604Syokota case 0: /* do nothing */ 240031604Syokota break; 240131604Syokota case MOUSE_XAXIS: 240231604Syokota if (act1->dz != 0) { 240331604Syokota act2->dx = act1->dz; 240431604Syokota act2->dz = 0; 240531604Syokota } 240631604Syokota break; 240731604Syokota case MOUSE_YAXIS: 240831604Syokota if (act1->dz != 0) { 240931604Syokota act2->dy = act1->dz; 241031604Syokota act2->dz = 0; 241131604Syokota } 241231604Syokota break; 241331604Syokota default: /* buttons */ 241458231Syokota pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1] 241558231Syokota | rodent.zmap[2] | rodent.zmap[3]); 241658344Syokota if ((act1->dz < -1) && rodent.zmap[2]) { 241758231Syokota pbuttons |= rodent.zmap[2]; 241858344Syokota zstate[2].count = 1; 241958344Syokota } else if (act1->dz < 0) { 242058231Syokota pbuttons |= rodent.zmap[0]; 242158344Syokota zstate[0].count = 1; 242258344Syokota } else if ((act1->dz > 1) && rodent.zmap[3]) { 242358231Syokota pbuttons |= rodent.zmap[3]; 242458344Syokota zstate[3].count = 1; 242558344Syokota } else if (act1->dz > 0) { 242658231Syokota pbuttons |= rodent.zmap[1]; 242758344Syokota zstate[1].count = 1; 242858344Syokota } 242931604Syokota act2->dz = 0; 243031604Syokota break; 243131604Syokota } 243231604Syokota 243331604Syokota for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) { 243431604Syokota lbuttons |= (pbuttons & 1) ? p2l[pb] : 0; 243531604Syokota pbuttons >>= 1; 243631604Syokota } 243731604Syokota act2->button = lbuttons; 243831604Syokota 243931604Syokota act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0) 244031604Syokota | (act2->obutton ^ act2->button); 244131604Syokota} 244231604Syokota 244331604Syokotastatic void 244458344Syokotar_timestamp(mousestatus_t *act) 244531604Syokota{ 244631604Syokota struct timeval tv; 244731604Syokota struct timeval tv1; 244831604Syokota struct timeval tv2; 244958344Syokota struct timeval tv3; 245031604Syokota int button; 245131604Syokota int mask; 245231604Syokota int i; 245331604Syokota 245431604Syokota mask = act->flags & MOUSE_BUTTONS; 245558344Syokota#if 0 245631604Syokota if (mask == 0) 245731604Syokota return; 245858344Syokota#endif 245931604Syokota 246058344Syokota gettimeofday(&tv1, NULL); 2461150310Sphilip drift_current_tv = tv1; 246258344Syokota 246358344Syokota /* double click threshold */ 246431604Syokota tv2.tv_sec = rodent.clickthreshold/1000; 246531604Syokota tv2.tv_usec = (rodent.clickthreshold%1000)*1000; 2466122605Sdes timersub(&tv1, &tv2, &tv); 246731604Syokota debug("tv: %ld %ld", tv.tv_sec, tv.tv_usec); 246858344Syokota 246958344Syokota /* 3 button emulation timeout */ 247058344Syokota tv2.tv_sec = rodent.button2timeout/1000; 247158344Syokota tv2.tv_usec = (rodent.button2timeout%1000)*1000; 2472122605Sdes timersub(&tv1, &tv2, &tv3); 247358344Syokota 247431604Syokota button = MOUSE_BUTTON1DOWN; 247531604Syokota for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) { 2476122605Sdes if (mask & 1) { 2477122605Sdes if (act->button & button) { 2478122605Sdes /* the button is down */ 2479122605Sdes debug(" : %ld %ld", 248058344Syokota bstate[i].tv.tv_sec, bstate[i].tv.tv_usec); 248158344Syokota if (timercmp(&tv, &bstate[i].tv, >)) { 2482122605Sdes bstate[i].count = 1; 2483122605Sdes } else { 2484122605Sdes ++bstate[i].count; 2485122605Sdes } 248658344Syokota bstate[i].tv = tv1; 2487122605Sdes } else { 2488122605Sdes /* the button is up */ 2489122605Sdes bstate[i].tv = tv1; 2490122605Sdes } 2491122605Sdes } else { 249258344Syokota if (act->button & button) { 249358344Syokota /* the button has been down */ 249458344Syokota if (timercmp(&tv3, &bstate[i].tv, >)) { 249558344Syokota bstate[i].count = 1; 249658344Syokota bstate[i].tv = tv1; 249758344Syokota act->flags |= button; 249858344Syokota debug("button %d timeout", i + 1); 249958344Syokota } 250058344Syokota } else { 250158344Syokota /* the button has been up */ 250258344Syokota } 250358344Syokota } 250458344Syokota button <<= 1; 250558344Syokota mask >>= 1; 250658344Syokota } 250758344Syokota} 250858344Syokota 250958344Syokotastatic int 251058344Syokotar_timeout(void) 251158344Syokota{ 251258344Syokota struct timeval tv; 251358344Syokota struct timeval tv1; 251458344Syokota struct timeval tv2; 251558344Syokota 251659090Syokota if (states[mouse_button_state].timeout) 251759090Syokota return TRUE; 251858344Syokota gettimeofday(&tv1, NULL); 251958344Syokota tv2.tv_sec = rodent.button2timeout/1000; 252058344Syokota tv2.tv_usec = (rodent.button2timeout%1000)*1000; 2521122605Sdes timersub(&tv1, &tv2, &tv); 252258344Syokota return timercmp(&tv, &mouse_button_state_tv, >); 252358344Syokota} 252458344Syokota 252558344Syokotastatic void 252658344Syokotar_click(mousestatus_t *act) 252758344Syokota{ 252858344Syokota struct mouse_info mouse; 252958344Syokota int button; 253058344Syokota int mask; 253158344Syokota int i; 253258344Syokota 253358344Syokota mask = act->flags & MOUSE_BUTTONS; 253458344Syokota if (mask == 0) 253558344Syokota return; 253658344Syokota 253758344Syokota button = MOUSE_BUTTON1DOWN; 253858344Syokota for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) { 2539122605Sdes if (mask & 1) { 254058344Syokota debug("mstate[%d]->count:%d", i, mstate[i]->count); 2541122605Sdes if (act->button & button) { 2542122605Sdes /* the button is down */ 2543122605Sdes mouse.u.event.value = mstate[i]->count; 2544122605Sdes } else { 2545122605Sdes /* the button is up */ 2546122605Sdes mouse.u.event.value = 0; 2547122605Sdes } 254831604Syokota mouse.operation = MOUSE_BUTTON_EVENT; 254931604Syokota mouse.u.event.id = button; 255031604Syokota if (debug < 2) 2551153070Sphilip if (!paused) 2552153070Sphilip ioctl(rodent.cfd, CONS_MOUSECTL, &mouse); 255331604Syokota debug("button %d count %d", i + 1, mouse.u.event.value); 2554122605Sdes } 255531604Syokota button <<= 1; 255631604Syokota mask >>= 1; 255731604Syokota } 255831604Syokota} 255931604Syokota 256018222Speter/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */ 256118222Speter/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */ 256218222Speter/* 256318222Speter * Copyright 1993 by David Dawes <dawes@physics.su.oz.au> 256418222Speter * 256518222Speter * Permission to use, copy, modify, distribute, and sell this software and its 256618222Speter * documentation for any purpose is hereby granted without fee, provided that 256718222Speter * the above copyright notice appear in all copies and that both that 256818222Speter * copyright notice and this permission notice appear in supporting 2569122605Sdes * documentation, and that the name of David Dawes 2570122605Sdes * not be used in advertising or publicity pertaining to distribution of 257118222Speter * the software without specific, written prior permission. 2572122605Sdes * David Dawes makes no representations about the suitability of this 2573122605Sdes * software for any purpose. It is provided "as is" without express or 257418222Speter * implied warranty. 257518222Speter * 2576122605Sdes * DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD TO 2577122605Sdes * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 2578122605Sdes * FITNESS, IN NO EVENT SHALL DAVID DAWES BE LIABLE FOR 2579122605Sdes * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 2580122605Sdes * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 2581122605Sdes * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 258218222Speter * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 258318222Speter * 258418222Speter */ 258518222Speter 258618222Speter 258731604Syokotastatic void 258831604Syokotasetmousespeed(int old, int new, unsigned cflag) 258918222Speter{ 259018222Speter struct termios tty; 259118222Speter char *c; 259218222Speter 259318222Speter if (tcgetattr(rodent.mfd, &tty) < 0) 259418222Speter { 259595629Siedowse logwarn("unable to get status of mouse fd"); 259631604Syokota return; 259718222Speter } 259818222Speter 259918222Speter tty.c_iflag = IGNBRK | IGNPAR; 260018222Speter tty.c_oflag = 0; 260118222Speter tty.c_lflag = 0; 260218222Speter tty.c_cflag = (tcflag_t)cflag; 260318222Speter tty.c_cc[VTIME] = 0; 260418222Speter tty.c_cc[VMIN] = 1; 260518222Speter 260618222Speter switch (old) 260718222Speter { 260818222Speter case 9600: 260918222Speter cfsetispeed(&tty, B9600); 261018222Speter cfsetospeed(&tty, B9600); 261118222Speter break; 261218222Speter case 4800: 261318222Speter cfsetispeed(&tty, B4800); 261418222Speter cfsetospeed(&tty, B4800); 261518222Speter break; 261618222Speter case 2400: 261718222Speter cfsetispeed(&tty, B2400); 261818222Speter cfsetospeed(&tty, B2400); 261918222Speter break; 262018222Speter case 1200: 262118222Speter default: 262218222Speter cfsetispeed(&tty, B1200); 262318222Speter cfsetospeed(&tty, B1200); 262418222Speter } 262518222Speter 262618222Speter if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0) 262718222Speter { 262895629Siedowse logwarn("unable to set status of mouse fd"); 262931604Syokota return; 263018222Speter } 263118222Speter 263218222Speter switch (new) 263318222Speter { 263418222Speter case 9600: 263518222Speter c = "*q"; 263618222Speter cfsetispeed(&tty, B9600); 263718222Speter cfsetospeed(&tty, B9600); 263818222Speter break; 263918222Speter case 4800: 264018222Speter c = "*p"; 264118222Speter cfsetispeed(&tty, B4800); 264218222Speter cfsetospeed(&tty, B4800); 264318222Speter break; 264418222Speter case 2400: 264518222Speter c = "*o"; 264618222Speter cfsetispeed(&tty, B2400); 264718222Speter cfsetospeed(&tty, B2400); 264818222Speter break; 264918222Speter case 1200: 265018222Speter default: 265118222Speter c = "*n"; 265218222Speter cfsetispeed(&tty, B1200); 265318222Speter cfsetospeed(&tty, B1200); 265418222Speter } 265518222Speter 2656122605Sdes if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN 265731604Syokota || rodent.rtype == MOUSE_PROTO_LOGI) 265818222Speter { 265918222Speter if (write(rodent.mfd, c, 2) != 2) 266018222Speter { 266195629Siedowse logwarn("unable to write to mouse fd"); 266231604Syokota return; 266318222Speter } 266418222Speter } 266518222Speter usleep(100000); 266618222Speter 266718222Speter if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0) 266895629Siedowse logwarn("unable to set status of mouse fd"); 266931604Syokota} 267031604Syokota 2671122605Sdes/* 2672122605Sdes * PnP COM device support 2673122605Sdes * 267431604Syokota * It's a simplistic implementation, but it works :-) 267531604Syokota * KY, 31/7/97. 267631604Syokota */ 267731604Syokota 267831604Syokota/* 2679122605Sdes * Try to elicit a PnP ID as described in 2680122605Sdes * Microsoft, Hayes: "Plug and Play External COM Device Specification, 268131604Syokota * rev 1.00", 1995. 268231604Syokota * 268331604Syokota * The routine does not fully implement the COM Enumerator as par Section 268431604Syokota * 2.1 of the document. In particular, we don't have idle state in which 2685122605Sdes * the driver software monitors the com port for dynamic connection or 2686122605Sdes * removal of a device at the port, because `moused' simply quits if no 268731604Syokota * device is found. 268831604Syokota * 2689122605Sdes * In addition, as PnP COM device enumeration procedure slightly has 269031604Syokota * changed since its first publication, devices which follow earlier 2691122605Sdes * revisions of the above spec. may fail to respond if the rev 1.0 269231604Syokota * procedure is used. XXX 269331604Syokota */ 269431604Syokotastatic int 269540255Syokotapnpwakeup1(void) 269631604Syokota{ 269731604Syokota struct timeval timeout; 269831604Syokota fd_set fds; 269931604Syokota int i; 270031604Syokota 2701122605Sdes /* 270231604Syokota * This is the procedure described in rev 1.0 of PnP COM device spec. 270331604Syokota * Unfortunately, some devices which comform to earlier revisions of 270431604Syokota * the spec gets confused and do not return the ID string... 270531604Syokota */ 270640255Syokota debug("PnP COM device rev 1.0 probe..."); 270731604Syokota 270831604Syokota /* port initialization (2.1.2) */ 270931604Syokota ioctl(rodent.mfd, TIOCMGET, &i); 271031604Syokota i |= TIOCM_DTR; /* DTR = 1 */ 271131604Syokota i &= ~TIOCM_RTS; /* RTS = 0 */ 271231604Syokota ioctl(rodent.mfd, TIOCMSET, &i); 271340255Syokota usleep(240000); 271431604Syokota 271540255Syokota /* 2716122605Sdes * The PnP COM device spec. dictates that the mouse must set DSR 2717122605Sdes * in response to DTR (by hardware or by software) and that if DSR is 271840255Syokota * not asserted, the host computer should think that there is no device 271941269Syokota * at this serial port. But some mice just don't do that... 272040255Syokota */ 272140255Syokota ioctl(rodent.mfd, TIOCMGET, &i); 272240255Syokota debug("modem status 0%o", i); 272340255Syokota if ((i & TIOCM_DSR) == 0) 272440255Syokota return FALSE; 272540255Syokota 272631604Syokota /* port setup, 1st phase (2.1.3) */ 272731604Syokota setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL)); 272831604Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 272931604Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 273040255Syokota usleep(240000); 273131604Syokota i = TIOCM_DTR; /* DTR = 1, RTS = 0 */ 273231604Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 273340255Syokota usleep(240000); 273431604Syokota 273531604Syokota /* wait for response, 1st phase (2.1.4) */ 273631604Syokota i = FREAD; 273731604Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 273831604Syokota i = TIOCM_RTS; /* DTR = 1, RTS = 1 */ 273931604Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 274031604Syokota 274131604Syokota /* try to read something */ 274231604Syokota FD_ZERO(&fds); 274331604Syokota FD_SET(rodent.mfd, &fds); 274431604Syokota timeout.tv_sec = 0; 274540255Syokota timeout.tv_usec = 240000; 274640255Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 274740255Syokota debug("pnpwakeup1(): valid response in first phase."); 274840255Syokota return TRUE; 274941269Syokota } 275031604Syokota 275141269Syokota /* port setup, 2nd phase (2.1.5) */ 275241269Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */ 275341269Syokota ioctl(rodent.mfd, TIOCMBIC, &i); 275441269Syokota usleep(240000); 275531604Syokota 275641269Syokota /* wait for respose, 2nd phase (2.1.6) */ 275741269Syokota i = FREAD; 275841269Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 275941269Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 276041269Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 276131604Syokota 276241269Syokota /* try to read something */ 276341269Syokota FD_ZERO(&fds); 276441269Syokota FD_SET(rodent.mfd, &fds); 276541269Syokota timeout.tv_sec = 0; 276641269Syokota timeout.tv_usec = 240000; 276741269Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 276841269Syokota debug("pnpwakeup1(): valid response in second phase."); 276941269Syokota return TRUE; 277031604Syokota } 277141269Syokota 277240255Syokota return FALSE; 277340255Syokota} 277440255Syokota 277540255Syokotastatic int 277640255Syokotapnpwakeup2(void) 277740255Syokota{ 277840255Syokota struct timeval timeout; 277940255Syokota fd_set fds; 278040255Syokota int i; 278140255Syokota 278231604Syokota /* 278331604Syokota * This is a simplified procedure; it simply toggles RTS. 278431604Syokota */ 278541269Syokota debug("alternate probe..."); 278631604Syokota 278731604Syokota ioctl(rodent.mfd, TIOCMGET, &i); 278831604Syokota i |= TIOCM_DTR; /* DTR = 1 */ 278931604Syokota i &= ~TIOCM_RTS; /* RTS = 0 */ 279031604Syokota ioctl(rodent.mfd, TIOCMSET, &i); 279140255Syokota usleep(240000); 279231604Syokota 279331604Syokota setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL)); 279431604Syokota 279531604Syokota /* wait for respose */ 279631604Syokota i = FREAD; 279731604Syokota ioctl(rodent.mfd, TIOCFLUSH, &i); 279831604Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 279931604Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 280031604Syokota 280131604Syokota /* try to read something */ 280231604Syokota FD_ZERO(&fds); 280331604Syokota FD_SET(rodent.mfd, &fds); 280431604Syokota timeout.tv_sec = 0; 280540255Syokota timeout.tv_usec = 240000; 280640255Syokota if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 280740255Syokota debug("pnpwakeup2(): valid response."); 280840255Syokota return TRUE; 280940255Syokota } 281041269Syokota 281140255Syokota return FALSE; 281240255Syokota} 281331604Syokota 281440255Syokotastatic int 281540255Syokotapnpgets(char *buf) 281640255Syokota{ 281740255Syokota struct timeval timeout; 281840255Syokota fd_set fds; 281940255Syokota int begin; 282040255Syokota int i; 282140255Syokota char c; 282240255Syokota 282340255Syokota if (!pnpwakeup1() && !pnpwakeup2()) { 282440255Syokota /* 2825122605Sdes * According to PnP spec, we should set DTR = 1 and RTS = 0 while 2826122605Sdes * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed, 2827122605Sdes * assuming there is something at the port even if it didn't 282840255Syokota * respond to the PnP enumeration procedure. 282940255Syokota */ 283040255Syokota i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */ 283140255Syokota ioctl(rodent.mfd, TIOCMBIS, &i); 283240255Syokota return 0; 283340255Syokota } 283440255Syokota 283531604Syokota /* collect PnP COM device ID (2.1.7) */ 283640255Syokota begin = -1; 283731604Syokota i = 0; 283840255Syokota usleep(240000); /* the mouse must send `Begin ID' within 200msec */ 283931604Syokota while (read(rodent.mfd, &c, 1) == 1) { 284031604Syokota /* we may see "M", or "M3..." before `Begin ID' */ 284140255Syokota buf[i++] = c; 2842122605Sdes if ((c == 0x08) || (c == 0x28)) { /* Begin ID */ 284340255Syokota debug("begin-id %02x", c); 284440255Syokota begin = i - 1; 284531604Syokota break; 2846122605Sdes } 2847122605Sdes debug("%c %02x", c, c); 284840255Syokota if (i >= 256) 284940255Syokota break; 285031604Syokota } 285140255Syokota if (begin < 0) { 285231604Syokota /* we haven't seen `Begin ID' in time... */ 285331604Syokota goto connect_idle; 285431604Syokota } 285531604Syokota 285631604Syokota ++c; /* make it `End ID' */ 285731604Syokota for (;;) { 2858122605Sdes FD_ZERO(&fds); 2859122605Sdes FD_SET(rodent.mfd, &fds); 2860122605Sdes timeout.tv_sec = 0; 2861122605Sdes timeout.tv_usec = 240000; 2862122605Sdes if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0) 286331604Syokota break; 286431604Syokota 286531604Syokota read(rodent.mfd, &buf[i], 1); 2866122605Sdes if (buf[i++] == c) /* End ID */ 286731604Syokota break; 286831604Syokota if (i >= 256) 286931604Syokota break; 287031604Syokota } 287140255Syokota if (begin > 0) { 287240255Syokota i -= begin; 287340255Syokota bcopy(&buf[begin], &buf[0], i); 287440255Syokota } 287531604Syokota /* string may not be human readable... */ 287640255Syokota debug("len:%d, '%-*.*s'", i, i, i, buf); 287731604Syokota 287840255Syokota if (buf[i - 1] == c) 287940255Syokota return i; /* a valid PnP string */ 288040255Syokota 288131604Syokota /* 2882122605Sdes * According to PnP spec, we should set DTR = 1 and RTS = 0 while 288340255Syokota * in idle state. But, `moused' shall leave the modem control lines 288440255Syokota * as they are. See above. 288531604Syokota */ 288631604Syokotaconnect_idle: 288740255Syokota 288840255Syokota /* we may still have something in the buffer */ 288940255Syokota return ((i > 0) ? i : 0); 289031604Syokota} 289131604Syokota 289231604Syokotastatic int 289331604Syokotapnpparse(pnpid_t *id, char *buf, int len) 289431604Syokota{ 289531604Syokota char s[3]; 289631604Syokota int offset; 289731604Syokota int sum = 0; 289831604Syokota int i, j; 289931604Syokota 290031604Syokota id->revision = 0; 290131604Syokota id->eisaid = NULL; 290231604Syokota id->serial = NULL; 290331604Syokota id->class = NULL; 290431604Syokota id->compat = NULL; 290531604Syokota id->description = NULL; 290631604Syokota id->neisaid = 0; 290731604Syokota id->nserial = 0; 290831604Syokota id->nclass = 0; 290931604Syokota id->ncompat = 0; 291031604Syokota id->ndescription = 0; 291131604Syokota 291240255Syokota if ((buf[0] != 0x28) && (buf[0] != 0x08)) { 291340255Syokota /* non-PnP mice */ 291440255Syokota switch(buf[0]) { 291540255Syokota default: 291640255Syokota return FALSE; 291740255Syokota case 'M': /* Microsoft */ 291840255Syokota id->eisaid = "PNP0F01"; 291940255Syokota break; 292040255Syokota case 'H': /* MouseSystems */ 292140255Syokota id->eisaid = "PNP0F04"; 292240255Syokota break; 292340255Syokota } 292440255Syokota id->neisaid = strlen(id->eisaid); 292540255Syokota id->class = "MOUSE"; 292640255Syokota id->nclass = strlen(id->class); 292740255Syokota debug("non-PnP mouse '%c'", buf[0]); 292840255Syokota return TRUE; 292940255Syokota } 293040255Syokota 293140255Syokota /* PnP mice */ 293231604Syokota offset = 0x28 - buf[0]; 293331604Syokota 293431604Syokota /* calculate checksum */ 293531604Syokota for (i = 0; i < len - 3; ++i) { 293631604Syokota sum += buf[i]; 293731604Syokota buf[i] += offset; 293831604Syokota } 293931604Syokota sum += buf[len - 1]; 294031604Syokota for (; i < len; ++i) 294131604Syokota buf[i] += offset; 294231604Syokota debug("PnP ID string: '%*.*s'", len, len, buf); 294331604Syokota 294431604Syokota /* revision */ 294531604Syokota buf[1] -= offset; 294631604Syokota buf[2] -= offset; 294731604Syokota id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f); 294831604Syokota debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100); 294931604Syokota 295031604Syokota /* EISA vender and product ID */ 295131604Syokota id->eisaid = &buf[3]; 295231604Syokota id->neisaid = 7; 295331604Syokota 295431604Syokota /* option strings */ 295531604Syokota i = 10; 295631604Syokota if (buf[i] == '\\') { 2957122605Sdes /* device serial # */ 2958122605Sdes for (j = ++i; i < len; ++i) { 2959122605Sdes if (buf[i] == '\\') 296031604Syokota break; 2961122605Sdes } 296231604Syokota if (i >= len) 296331604Syokota i -= 3; 296431604Syokota if (i - j == 8) { 2965122605Sdes id->serial = &buf[j]; 2966122605Sdes id->nserial = 8; 296718222Speter } 296831604Syokota } 296931604Syokota if (buf[i] == '\\') { 2970122605Sdes /* PnP class */ 2971122605Sdes for (j = ++i; i < len; ++i) { 2972122605Sdes if (buf[i] == '\\') 297331604Syokota break; 2974122605Sdes } 297531604Syokota if (i >= len) 297631604Syokota i -= 3; 297731604Syokota if (i > j + 1) { 2978122605Sdes id->class = &buf[j]; 2979122605Sdes id->nclass = i - j; 2980122605Sdes } 298131604Syokota } 298231604Syokota if (buf[i] == '\\') { 298331604Syokota /* compatible driver */ 2984122605Sdes for (j = ++i; i < len; ++i) { 2985122605Sdes if (buf[i] == '\\') 298631604Syokota break; 2987122605Sdes } 298831604Syokota /* 2989122605Sdes * PnP COM spec prior to v0.96 allowed '*' in this field, 299031604Syokota * it's not allowed now; just igore it. 299131604Syokota */ 299231604Syokota if (buf[j] == '*') 299331604Syokota ++j; 299431604Syokota if (i >= len) 299531604Syokota i -= 3; 299631604Syokota if (i > j + 1) { 2997122605Sdes id->compat = &buf[j]; 2998122605Sdes id->ncompat = i - j; 2999122605Sdes } 300031604Syokota } 300131604Syokota if (buf[i] == '\\') { 300231604Syokota /* product description */ 3003122605Sdes for (j = ++i; i < len; ++i) { 3004122605Sdes if (buf[i] == ';') 300531604Syokota break; 3006122605Sdes } 300731604Syokota if (i >= len) 300831604Syokota i -= 3; 300931604Syokota if (i > j + 1) { 3010122605Sdes id->description = &buf[j]; 3011122605Sdes id->ndescription = i - j; 3012122605Sdes } 301331604Syokota } 301431604Syokota 301531604Syokota /* checksum exists if there are any optional fields */ 301631604Syokota if ((id->nserial > 0) || (id->nclass > 0) 301731604Syokota || (id->ncompat > 0) || (id->ndescription > 0)) { 3018122605Sdes debug("PnP checksum: 0x%X", sum); 3019122605Sdes sprintf(s, "%02X", sum & 0x0ff); 3020122605Sdes if (strncmp(s, &buf[len - 3], 2) != 0) { 302131604Syokota#if 0 3022122605Sdes /* 3023122605Sdes * I found some mice do not comply with the PnP COM device 302431604Syokota * spec regarding checksum... XXX 302531604Syokota */ 3026122605Sdes logwarnx("PnP checksum error", 0); 302731604Syokota return FALSE; 302831604Syokota#endif 3029122605Sdes } 303031604Syokota } 303131604Syokota 303231604Syokota return TRUE; 303318222Speter} 303431604Syokota 303531604Syokotastatic symtab_t * 303631604Syokotapnpproto(pnpid_t *id) 303731604Syokota{ 303831604Syokota symtab_t *t; 303931604Syokota int i, j; 304031604Syokota 304131604Syokota if (id->nclass > 0) 3042122854Sdes if (strncmp(id->class, "MOUSE", id->nclass) != 0 && 3043122854Sdes strncmp(id->class, "TABLET", id->nclass) != 0) 304431604Syokota /* this is not a mouse! */ 304531604Syokota return NULL; 304631604Syokota 304731604Syokota if (id->neisaid > 0) { 3048122605Sdes t = gettoken(pnpprod, id->eisaid, id->neisaid); 304931604Syokota if (t->val != MOUSE_PROTO_UNKNOWN) 3050122605Sdes return t; 305131604Syokota } 305231604Syokota 305331604Syokota /* 305431604Syokota * The 'Compatible drivers' field may contain more than one 305531604Syokota * ID separated by ','. 305631604Syokota */ 305731604Syokota if (id->ncompat <= 0) 305831604Syokota return NULL; 305931604Syokota for (i = 0; i < id->ncompat; ++i) { 3060122605Sdes for (j = i; id->compat[i] != ','; ++i) 3061122605Sdes if (i >= id->ncompat) 306231604Syokota break; 3063122605Sdes if (i > j) { 3064122605Sdes t = gettoken(pnpprod, id->compat + j, i - j); 306531604Syokota if (t->val != MOUSE_PROTO_UNKNOWN) 3066122605Sdes return t; 306731604Syokota } 306831604Syokota } 306931604Syokota 307031604Syokota return NULL; 307131604Syokota} 307231604Syokota 307331604Syokota/* name/val mapping */ 307431604Syokota 307531604Syokotastatic symtab_t * 307631604Syokotagettoken(symtab_t *tab, char *s, int len) 307731604Syokota{ 307831604Syokota int i; 307931604Syokota 308031604Syokota for (i = 0; tab[i].name != NULL; ++i) { 308131604Syokota if (strncmp(tab[i].name, s, len) == 0) 308231604Syokota break; 308331604Syokota } 308431604Syokota return &tab[i]; 308531604Syokota} 308631604Syokota 308731604Syokotastatic char * 308831604Syokotagettokenname(symtab_t *tab, int val) 308931604Syokota{ 309031604Syokota int i; 309131604Syokota 309231604Syokota for (i = 0; tab[i].name != NULL; ++i) { 309331604Syokota if (tab[i].val == val) 309431604Syokota return tab[i].name; 309531604Syokota } 309631604Syokota return NULL; 309731604Syokota} 309836991Sahasty 309941271Syokota 310041271Syokota/* 310141271Syokota * code to read from the Genius Kidspad tablet. 310241271Syokota 310341271SyokotaThe tablet responds to the COM PnP protocol 1.0 with EISA-ID KYE0005, 310441271Syokotaand to pre-pnp probes (RTS toggle) with 'T' (tablet ?) 310541271Syokota9600, 8 bit, parity odd. 310641271Syokota 310741271SyokotaThe tablet puts out 5 bytes. b0 (mask 0xb8, value 0xb8) contains 310841271Syokotathe proximity, tip and button info: 310941271Syokota (byte0 & 0x1) true = tip pressed 311041271Syokota (byte0 & 0x2) true = button pressed 311141271Syokota (byte0 & 0x40) false = pen in proximity of tablet. 311241271Syokota 311341271SyokotaThe next 4 bytes are used for coordinates xl, xh, yl, yh (7 bits valid). 311441271Syokota 311541271SyokotaOnly absolute coordinates are returned, so we use the following approach: 311641271Syokotawe store the last coordinates sent when the pen went out of the tablet, 311741271Syokota 311841271Syokota 311941271Syokota * 312041271Syokota */ 312141271Syokota 312241271Syokotatypedef enum { 312341271Syokota S_IDLE, S_PROXY, S_FIRST, S_DOWN, S_UP 312441271Syokota} k_status ; 312541271Syokota 312641271Syokotastatic int 312741271Syokotakidspad(u_char rxc, mousestatus_t *act) 312841271Syokota{ 312995629Siedowse static int buf[5]; 313041271Syokota static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ; 313141271Syokota static k_status status = S_IDLE ; 313241271Syokota static struct timeval old, now ; 313341271Syokota 313478737Sdd int x, y ; 313541271Syokota 3136122854Sdes if (buflen > 0 && (rxc & 0x80)) { 313741271Syokota fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc); 313841271Syokota buflen = 0 ; 313941271Syokota } 3140122854Sdes if (buflen == 0 && (rxc & 0xb8) != 0xb8) { 314141271Syokota fprintf(stderr, "invalid code 0 0x%x\n", rxc); 314241271Syokota return 0 ; /* invalid code, no action */ 314341271Syokota } 314441271Syokota buf[buflen++] = rxc ; 314541271Syokota if (buflen < 5) 314641271Syokota return 0 ; 314741271Syokota 314841271Syokota buflen = 0 ; /* for next time... */ 314941271Syokota 315041271Syokota x = buf[1]+128*(buf[2] - 7) ; 315141271Syokota if (x < 0) x = 0 ; 315241271Syokota y = 28*128 - (buf[3] + 128* (buf[4] - 7)) ; 315341271Syokota if (y < 0) y = 0 ; 315441271Syokota 315541271Syokota x /= 8 ; 315641271Syokota y /= 8 ; 315741271Syokota 315841271Syokota act->flags = 0 ; 315941271Syokota act->obutton = act->button ; 316041271Syokota act->dx = act->dy = act->dz = 0 ; 316141271Syokota gettimeofday(&now, NULL); 3162122854Sdes if (buf[0] & 0x40) /* pen went out of reach */ 316341271Syokota status = S_IDLE ; 316441271Syokota else if (status == S_IDLE) { /* pen is newly near the tablet */ 316541271Syokota act->flags |= MOUSE_POSCHANGED ; /* force update */ 316641271Syokota status = S_PROXY ; 316741271Syokota x_prev = x ; 316841271Syokota y_prev = y ; 316941271Syokota } 317041271Syokota old = now ; 317141271Syokota act->dx = x - x_prev ; 317241271Syokota act->dy = y - y_prev ; 317341271Syokota if (act->dx || act->dy) 317441271Syokota act->flags |= MOUSE_POSCHANGED ; 317541271Syokota x_prev = x ; 317641271Syokota y_prev = y ; 317741271Syokota if (b_prev != 0 && b_prev != buf[0]) { /* possibly record button change */ 317841271Syokota act->button = 0 ; 3179122854Sdes if (buf[0] & 0x01) /* tip pressed */ 318041271Syokota act->button |= MOUSE_BUTTON1DOWN ; 3181122854Sdes if (buf[0] & 0x02) /* button pressed */ 318241271Syokota act->button |= MOUSE_BUTTON2DOWN ; 318341271Syokota act->flags |= MOUSE_BUTTONSCHANGED ; 318441271Syokota } 318541271Syokota b_prev = buf[0] ; 318641271Syokota return act->flags ; 318741271Syokota} 318841271Syokota 3189145001Smdoddstatic int 3190145001Smdoddgtco_digipad (u_char rxc, mousestatus_t *act) 3191145001Smdodd{ 3192145001Smdodd static u_char buf[5]; 3193145001Smdodd static int buflen = 0, b_prev = 0 , x_prev = -1, y_prev = -1 ; 3194145001Smdodd static k_status status = S_IDLE ; 3195145001Smdodd int x, y; 3196145001Smdodd 3197145001Smdodd#define GTCO_HEADER 0x80 3198145001Smdodd#define GTCO_PROXIMITY 0x40 3199145001Smdodd#define GTCO_START (GTCO_HEADER|GTCO_PROXIMITY) 3200145001Smdodd#define GTCO_BUTTONMASK 0x3c 3201145001Smdodd 3202145001Smdodd 3203145001Smdodd if (buflen > 0 && ((rxc & GTCO_HEADER) != GTCO_HEADER)) { 3204145001Smdodd fprintf(stderr, "invalid code %d 0x%x\n", buflen, rxc); 3205145001Smdodd buflen = 0 ; 3206145001Smdodd } 3207145001Smdodd if (buflen == 0 && (rxc & GTCO_START) != GTCO_START) { 3208145001Smdodd fprintf(stderr, "invalid code 0 0x%x\n", rxc); 3209145001Smdodd return 0 ; /* invalid code, no action */ 3210145001Smdodd } 3211145001Smdodd 3212145001Smdodd buf[buflen++] = rxc ; 3213145001Smdodd if (buflen < 5) 3214145001Smdodd return 0 ; 3215145001Smdodd 3216145001Smdodd buflen = 0 ; /* for next time... */ 3217145001Smdodd 3218145001Smdodd x = ((buf[2] & ~GTCO_START) << 6 | (buf[1] & ~GTCO_START)); 3219145001Smdodd y = 4768 - ((buf[4] & ~GTCO_START) << 6 | (buf[3] & ~GTCO_START)); 3220145001Smdodd 3221145001Smdodd x /= 2.5; 3222145001Smdodd y /= 2.5; 3223145001Smdodd 3224145001Smdodd act->flags = 0 ; 3225145001Smdodd act->obutton = act->button ; 3226145001Smdodd act->dx = act->dy = act->dz = 0 ; 3227145001Smdodd 3228145001Smdodd if ((buf[0] & 0x40) == 0) /* pen went out of reach */ 3229145001Smdodd status = S_IDLE ; 3230145001Smdodd else if (status == S_IDLE) { /* pen is newly near the tablet */ 3231145001Smdodd act->flags |= MOUSE_POSCHANGED ; /* force update */ 3232145001Smdodd status = S_PROXY ; 3233145001Smdodd x_prev = x ; 3234145001Smdodd y_prev = y ; 3235145001Smdodd } 3236145001Smdodd 3237145001Smdodd act->dx = x - x_prev ; 3238145001Smdodd act->dy = y - y_prev ; 3239145001Smdodd if (act->dx || act->dy) 3240145001Smdodd act->flags |= MOUSE_POSCHANGED ; 3241145001Smdodd x_prev = x ; 3242145001Smdodd y_prev = y ; 3243145001Smdodd 3244145001Smdodd /* possibly record button change */ 3245145001Smdodd if (b_prev != 0 && b_prev != buf[0]) { 3246145001Smdodd act->button = 0 ; 3247145001Smdodd if (buf[0] & 0x04) /* tip pressed/yellow */ 3248145001Smdodd act->button |= MOUSE_BUTTON1DOWN ; 3249145001Smdodd if (buf[0] & 0x08) /* grey/white */ 3250145001Smdodd act->button |= MOUSE_BUTTON2DOWN ; 3251145001Smdodd if (buf[0] & 0x10) /* black/green */ 3252145001Smdodd act->button |= MOUSE_BUTTON3DOWN ; 3253145001Smdodd if (buf[0] & 0x20) /* tip+grey/blue */ 3254145001Smdodd act->button |= MOUSE_BUTTON4DOWN ; 3255145001Smdodd act->flags |= MOUSE_BUTTONSCHANGED ; 3256145001Smdodd } 3257145001Smdodd b_prev = buf[0] ; 3258145001Smdodd return act->flags ; 3259145001Smdodd} 3260145001Smdodd 3261122605Sdesstatic void 326236991Sahastymremote_serversetup() 326336991Sahasty{ 326436991Sahasty struct sockaddr_un ad; 326536991Sahasty 326636991Sahasty /* Open a UNIX domain stream socket to listen for mouse remote clients */ 3267122605Sdes unlink(_PATH_MOUSEREMOTE); 326836991Sahasty 3269122854Sdes if ((rodent.mremsfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 327036991Sahasty logerrx(1, "unable to create unix domain socket %s",_PATH_MOUSEREMOTE); 327136991Sahasty 327236991Sahasty umask(0111); 3273122605Sdes 327436991Sahasty bzero(&ad, sizeof(ad)); 327536991Sahasty ad.sun_family = AF_UNIX; 327636991Sahasty strcpy(ad.sun_path, _PATH_MOUSEREMOTE); 327736991Sahasty#ifndef SUN_LEN 3278122854Sdes#define SUN_LEN(unp) (((char *)(unp)->sun_path - (char *)(unp)) + \ 3279122854Sdes strlen((unp)->path)) 328036991Sahasty#endif 3281122605Sdes if (bind(rodent.mremsfd, (struct sockaddr *) &ad, SUN_LEN(&ad)) < 0) 328236991Sahasty logerrx(1, "unable to bind unix domain socket %s", _PATH_MOUSEREMOTE); 328336991Sahasty 328436991Sahasty listen(rodent.mremsfd, 1); 328536991Sahasty} 328636991Sahasty 3287122605Sdesstatic void 328836991Sahastymremote_clientchg(int add) 328936991Sahasty{ 329036991Sahasty struct sockaddr_un ad; 329136991Sahasty int ad_len, fd; 329236991Sahasty 329336991Sahasty if (rodent.rtype != MOUSE_PROTO_X10MOUSEREM) 329436991Sahasty return; 329536991Sahasty 3296122854Sdes if (add) { 329736991Sahasty /* Accept client connection, if we don't already have one */ 329836991Sahasty ad_len = sizeof(ad); 329936991Sahasty fd = accept(rodent.mremsfd, (struct sockaddr *) &ad, &ad_len); 330036991Sahasty if (fd < 0) 330136991Sahasty logwarnx("failed accept on mouse remote socket"); 330236991Sahasty 3303122854Sdes if (rodent.mremcfd < 0) { 330436991Sahasty rodent.mremcfd = fd; 330536991Sahasty debug("remote client connect...accepted"); 330636991Sahasty } 330736991Sahasty else { 330836991Sahasty close(fd); 330936991Sahasty debug("another remote client connect...disconnected"); 331036991Sahasty } 331136991Sahasty } 331236991Sahasty else { 331336991Sahasty /* Client disconnected */ 331436991Sahasty debug("remote client disconnected"); 3315122854Sdes close(rodent.mremcfd); 331636991Sahasty rodent.mremcfd = -1; 331736991Sahasty } 331836991Sahasty} 3319