/* * * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. * Copyright 1993 by David Dawes * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich * Copyright 1994-2002 by The XFree86 Project, Inc. * Copyright 2002 by Paul Elliott * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the names of copyright holders not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. The copyright holders * make no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* Patch for PS/2 Intellimouse - Tim Goodwin 1997-11-06. */ /* * [JCH-96/01/21] Added fourth button support for PROT_GLIDEPOINT mouse * protocol. */ /* * [TVO-97/03/05] Added microsoft IntelliMouse support */ /* * [PME-02/08/11] Added suport for drag lock buttons * for use with 4 button trackballs for convenience * and to help limited dexterity persons */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #define NEED_EVENTS #include #include #include "xf86.h" #ifdef XINPUT #include #include #include "extnsionst.h" #include "extinit.h" #else #include "inputstr.h" #endif #include "xf86Xinput.h" #include "xf86_OSproc.h" #include "xf86OSmouse.h" #ifndef NEED_XF86_TYPES #define NEED_XF86_TYPES /* for xisb.h when !XFree86LOADER */ #endif #include "compiler.h" #include "xisb.h" #include "mouse.h" #include "mousePriv.h" #include "mipointer.h" enum { /* number of bits in mapped nibble */ NIB_BITS=4, /* size of map of nibbles to bitmask */ NIB_SIZE= (1 << NIB_BITS), /* mask for map */ NIB_MASK= (NIB_SIZE -1), /* number of maps to map all the buttons */ NIB_COUNT = ((MSE_MAXBUTTONS+NIB_BITS-1)/NIB_BITS) }; /*data to be used in implementing trackball drag locks.*/ typedef struct _DragLockRec { /* Fields used to implement trackball drag locks. */ /* mask for those buttons that are ordinary drag lock buttons */ int lockButtonsM; /* mask for the master drag lock button if any */ int masterLockM; /* button state up/down from last time adjusted for drag locks */ int lockLastButtons; /* * true if master lock state i.e. master drag lock * button has just been pressed */ int masterTS; /* simulate these buttons being down although they are not */ int simulatedDown; /* * data to map bits for drag lock buttons to corresponding * bits for the target buttons */ int nib_table[NIB_COUNT][NIB_SIZE]; } DragLockRec, *DragLockPtr; static InputInfoPtr MousePreInit(InputDriverPtr drv, IDevPtr dev, int flags); #if 0 static void MouseUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags); #endif static int MouseProc(DeviceIntPtr device, int what); static Bool MouseConvert(LocalDevicePtr local, int first, int num, int v0, int v1, int v2, int v3, int v4, int v5, int *x, int *y); static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl); static void MousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw); static void MouseReadInput(InputInfoPtr pInfo); static void MouseBlockHandler(pointer data, struct timeval **waitTime, pointer LastSelectMask); static void MouseWakeupHandler(pointer data, int i, pointer LastSelectMask); static void FlushButtons(MouseDevPtr pMse); static Bool SetupMouse(InputInfoPtr pInfo); static Bool initMouseHW(InputInfoPtr pInfo); #ifdef SUPPORT_MOUSE_RESET static Bool mouseReset(InputInfoPtr pInfo, unsigned char val); static void ps2WakeupHandler(pointer data, int i, pointer LastSelectMask); static void ps2BlockHandler(pointer data, struct timeval **waitTime, pointer LastSelectMask); #endif /* mouse autoprobe stuff */ static const char *autoOSProtocol(InputInfoPtr pInfo, int *protoPara); static void autoProbeMouse(InputInfoPtr pInfo, Bool inSync, Bool lostSync); static void checkForErraticMovements(InputInfoPtr pInfo, int dx, int dy); static Bool collectData(MouseDevPtr pMse, unsigned char u); static void SetMouseProto(MouseDevPtr pMse, MouseProtocolID protocolID); static Bool autoGood(MouseDevPtr pMse); #undef MOUSE _X_EXPORT InputDriverRec MOUSE = { 1, "mouse", NULL, MousePreInit, /*MouseUnInit,*/NULL, NULL, 0 }; #define RETRY_COUNT 4 /* * Microsoft (all serial models), Logitech MouseMan, First Mouse, etc, * ALPS GlidePoint, Thinking Mouse. */ static const char *msDefaults[] = { "BaudRate", "1200", "DataBits", "7", "StopBits", "1", "Parity", "None", "FlowControl", "None", "VTime", "0", "VMin", "1", NULL }; /* MouseSystems */ static const char *mlDefaults[] = { "BaudRate", "1200", "DataBits", "8", "StopBits", "2", "Parity", "None", "FlowControl", "None", "VTime", "0", "VMin", "1", NULL }; /* MMSeries */ static const char *mmDefaults[] = { "BaudRate", "1200", "DataBits", "8", "StopBits", "1", "Parity", "Odd", "FlowControl", "None", "VTime", "0", "VMin", "1", NULL }; #if 0 /* Logitech series 9 *//* same as msc: now mlDefaults */ static const char *logiDefaults[] = { "BaudRate", "1200", "DataBits", "8", "StopBits", "2", "Parity", "None", "FlowControl", "None", "VTime", "0", "VMin", "1", NULL }; #endif /* Hitachi Tablet */ static const char *mmhitDefaults[] = { "BaudRate", "1200", "DataBits", "8", "StopBits", "1", "Parity", "None", "FlowControl", "None", "VTime", "0", "VMin", "1", NULL }; /* AceCad Tablet */ static const char *acecadDefaults[] = { "BaudRate", "9600", "DataBits", "8", "StopBits", "1", "Parity", "Odd", "FlowControl", "None", "VTime", "0", "VMin", "1", NULL }; static MouseProtocolRec mouseProtocols[] = { /* Serial protocols */ { "Microsoft", MSE_SERIAL, msDefaults, PROT_MS }, { "MouseSystems", MSE_SERIAL, mlDefaults, PROT_MSC }, { "MMSeries", MSE_SERIAL, mmDefaults, PROT_MM }, { "Logitech", MSE_SERIAL, mlDefaults, PROT_LOGI }, { "MouseMan", MSE_SERIAL, msDefaults, PROT_LOGIMAN }, { "MMHitTab", MSE_SERIAL, mmhitDefaults, PROT_MMHIT }, { "GlidePoint", MSE_SERIAL, msDefaults, PROT_GLIDE }, { "IntelliMouse", MSE_SERIAL, msDefaults, PROT_IMSERIAL }, { "ThinkingMouse", MSE_SERIAL, msDefaults, PROT_THINKING }, { "AceCad", MSE_SERIAL, acecadDefaults, PROT_ACECAD }, { "ValuMouseScroll", MSE_SERIAL, msDefaults, PROT_VALUMOUSESCROLL }, /* Standard PS/2 */ { "PS/2", MSE_PS2, NULL, PROT_PS2 }, { "GenericPS/2", MSE_PS2, NULL, PROT_GENPS2 }, /* Extended PS/2 */ { "ImPS/2", MSE_XPS2, NULL, PROT_IMPS2 }, { "ExplorerPS/2", MSE_XPS2, NULL, PROT_EXPPS2 }, { "ThinkingMousePS/2", MSE_XPS2, NULL, PROT_THINKPS2 }, { "MouseManPlusPS/2", MSE_XPS2, NULL, PROT_MMPS2 }, { "GlidePointPS/2", MSE_XPS2, NULL, PROT_GLIDEPS2 }, { "NetMousePS/2", MSE_XPS2, NULL, PROT_NETPS2 }, { "NetScrollPS/2", MSE_XPS2, NULL, PROT_NETSCPS2 }, /* Bus Mouse */ { "BusMouse", MSE_BUS, NULL, PROT_BM }, /* Auto-detect (PnP) */ { "Auto", MSE_AUTO, NULL, PROT_AUTO }, /* Misc (usually OS-specific) */ { "SysMouse", MSE_MISC, mlDefaults, PROT_SYSMOUSE }, /* end of list */ { NULL, MSE_NONE, NULL, PROT_UNKNOWN } }; /* Process options common to all mouse types. */ static void MouseCommonOptions(InputInfoPtr pInfo) { MouseDevPtr pMse; MessageType buttons_from = X_CONFIG; char *s; int origButtons; int i; pMse = pInfo->private; pMse->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0); if (!pMse->buttons) { pMse->buttons = MSE_DFLTBUTTONS; buttons_from = X_DEFAULT; } origButtons = pMse->buttons; pMse->emulate3Buttons = xf86SetBoolOption(pInfo->options, "Emulate3Buttons", FALSE); if (!xf86FindOptionValue(pInfo->options,"Emulate3Buttons")) { pMse->emulate3ButtonsSoft = TRUE; pMse->emulate3Buttons = TRUE; } pMse->emulate3Timeout = xf86SetIntOption(pInfo->options, "Emulate3Timeout", 50); if (pMse->emulate3Buttons || pMse->emulate3ButtonsSoft) { MessageType from = X_CONFIG; if (pMse->emulate3ButtonsSoft) from = X_DEFAULT; xf86Msg(from, "%s: Emulate3Buttons, Emulate3Timeout: %d\n", pInfo->name, pMse->emulate3Timeout); } pMse->chordMiddle = xf86SetBoolOption(pInfo->options, "ChordMiddle", FALSE); if (pMse->chordMiddle) xf86Msg(X_CONFIG, "%s: ChordMiddle\n", pInfo->name); pMse->flipXY = xf86SetBoolOption(pInfo->options, "FlipXY", FALSE); if (pMse->flipXY) xf86Msg(X_CONFIG, "%s: FlipXY\n", pInfo->name); if (xf86SetBoolOption(pInfo->options, "InvX", FALSE)) { pMse->invX = -1; xf86Msg(X_CONFIG, "%s: InvX\n", pInfo->name); } else pMse->invX = 1; if (xf86SetBoolOption(pInfo->options, "InvY", FALSE)) { pMse->invY = -1; xf86Msg(X_CONFIG, "%s: InvY\n", pInfo->name); } else pMse->invY = 1; pMse->angleOffset = xf86SetIntOption(pInfo->options, "AngleOffset", 0); if (pMse->pDragLock) xfree(pMse->pDragLock); pMse->pDragLock = NULL; s = xf86SetStrOption(pInfo->options, "DragLockButtons", NULL); if (s) { int lock; /* lock button */ int target; /* target button */ int lockM,targetM; /* bitmasks for drag lock, target */ int i, j; /* indexes */ char *s1; /* parse input string */ DragLockPtr pLock; pLock = pMse->pDragLock = xcalloc(1, sizeof(DragLockRec)); /* init code */ /* initial string to be taken apart */ s1 = s; /* keep getting numbers which are buttons */ while ((s1 != NULL) && (lock = strtol(s1, &s1, 10)) != 0) { /* check sanity for a button */ if ((lock < 0) || (lock > MSE_MAXBUTTONS)) { xf86Msg(X_WARNING, "DragLock: Invalid button number = %d\n", lock); break; }; /* turn into a button mask */ lockM = 1 << (lock - 1); /* try to get drag lock button */ if ((s1 == NULL) || ((target=strtol(s1, &s1, 10)) == 0)) { /*if no target, must be a master drag lock button */ /* save master drag lock mask */ pLock->masterLockM = lockM; xf86Msg(X_CONFIG, "DragLock button %d is master drag lock", lock); } else { /* have target button number*/ /* check target button number for sanity */ if ((target < 0) || (target > MSE_MAXBUTTONS)) { xf86Msg(X_WARNING, "DragLock: Invalid button number for target=%d\n", target); break; } /* target button mask */ targetM = 1 << (target - 1); xf86Msg(X_CONFIG, "DragLock: button %d is drag lock for button %d\n", lock,target); lock--; /* initialize table that maps drag lock mask to target mask */ pLock->nib_table[lock / NIB_BITS][1 << (lock % NIB_BITS)] = targetM; /* add new drag lock to mask of drag locks */ pLock->lockButtonsM |= lockM; } } /* * fill out rest of map that maps sets of drag lock buttons * to sets of target buttons, in the form of masks */ /* for each nibble */ for (i = 0; i < NIB_COUNT; i++) { /* for each possible set of bits for that nibble */ for (j = 0; j < NIB_SIZE; j++) { int ff, fM, otherbits; /* get first bit set in j*/ ff = ffs(j) - 1; /* if 0 bits set nothing to do */ if (ff >= 0) { /* form mask for fist bit set */ fM = 1 << ff; /* mask off first bit set to get remaining bits set*/ otherbits = j & ~fM; /* * if otherbits =0 then only 1 bit set * so j=fM * nib_table[i][fM] already calculated if fM has * only 1 bit set. * nib_table[i][j] has already been filled in * by previous loop. otherwise * otherbits < j so nibtable[i][otherbits] * has already been calculated. */ if (otherbits) pLock->nib_table[i][j] = pLock->nib_table[i][fM] | pLock->nib_table[i][otherbits]; } } } xfree(s); } s = xf86SetStrOption(pInfo->options, "ZAxisMapping", "4 5"); if (s) { int b1 = 0, b2 = 0, b3 = 0, b4 = 0; char *msg = NULL; pMse->negativeZ = pMse->positiveZ = MSE_NOAXISMAP; pMse->negativeW = pMse->positiveW = MSE_NOAXISMAP; if (!xf86NameCmp(s, "x")) { pMse->negativeZ = pMse->positiveZ = MSE_MAPTOX; msg = xstrdup("X axis"); } else if (!xf86NameCmp(s, "y")) { pMse->negativeZ = pMse->positiveZ = MSE_MAPTOY; msg = xstrdup("Y axis"); } else if (sscanf(s, "%d %d %d %d", &b1, &b2, &b3, &b4) >= 2 && b1 > 0 && b1 <= MSE_MAXBUTTONS && b2 > 0 && b2 <= MSE_MAXBUTTONS) { msg = xstrdup("buttons XX and YY"); if (msg) sprintf(msg, "buttons %d and %d", b1, b2); pMse->negativeZ = 1 << (b1-1); pMse->positiveZ = 1 << (b2-1); if (b3 > 0 && b3 <= MSE_MAXBUTTONS && b4 > 0 && b4 <= MSE_MAXBUTTONS) { if (msg) xfree(msg); msg = xstrdup("buttons XX, YY, ZZ and WW"); if (msg) sprintf(msg, "buttons %d, %d, %d and %d", b1, b2, b3, b4); pMse->negativeW = 1 << (b3-1); pMse->positiveW = 1 << (b4-1); } if (b1 > pMse->buttons) pMse->buttons = b1; if (b2 > pMse->buttons) pMse->buttons = b2; if (b3 > pMse->buttons) pMse->buttons = b3; if (b4 > pMse->buttons) pMse->buttons = b4; } if (msg) { xf86Msg(X_CONFIG, "%s: ZAxisMapping: %s\n", pInfo->name, msg); xfree(msg); } else { xf86Msg(X_WARNING, "%s: Invalid ZAxisMapping value: \"%s\"\n", pInfo->name, s); } xfree(s); } if (xf86SetBoolOption(pInfo->options, "EmulateWheel", FALSE)) { Bool yFromConfig = FALSE; int wheelButton; pMse->emulateWheel = TRUE; wheelButton = xf86SetIntOption(pInfo->options, "EmulateWheelButton", 4); if (wheelButton < 0 || wheelButton > MSE_MAXBUTTONS) { xf86Msg(X_WARNING, "%s: Invalid EmulateWheelButton value: %d\n", pInfo->name, wheelButton); wheelButton = 4; } pMse->wheelButton = wheelButton; pMse->wheelInertia = xf86SetIntOption(pInfo->options, "EmulateWheelInertia", 10); if (pMse->wheelInertia <= 0) { xf86Msg(X_WARNING, "%s: Invalid EmulateWheelInertia value: %d\n", pInfo->name, pMse->wheelInertia); pMse->wheelInertia = 10; } pMse->wheelButtonTimeout = xf86SetIntOption(pInfo->options, "EmulateWheelTimeout", 200); if (pMse->wheelButtonTimeout <= 0) { xf86Msg(X_WARNING, "%s: Invalid EmulateWheelTimeout value: %d\n", pInfo->name, pMse->wheelButtonTimeout); pMse->wheelButtonTimeout = 200; } pMse->negativeX = MSE_NOAXISMAP; pMse->positiveX = MSE_NOAXISMAP; s = xf86SetStrOption(pInfo->options, "XAxisMapping", NULL); if (s) { int b1 = 0, b2 = 0; char *msg = NULL; if ((sscanf(s, "%d %d", &b1, &b2) == 2) && b1 > 0 && b1 <= MSE_MAXBUTTONS && b2 > 0 && b2 <= MSE_MAXBUTTONS) { msg = xstrdup("buttons XX and YY"); if (msg) sprintf(msg, "buttons %d and %d", b1, b2); pMse->negativeX = b1; pMse->positiveX = b2; if (b1 > pMse->buttons) pMse->buttons = b1; if (b2 > pMse->buttons) pMse->buttons = b2; } else { xf86Msg(X_WARNING, "%s: Invalid XAxisMapping value: \"%s\"\n", pInfo->name, s); } if (msg) { xf86Msg(X_CONFIG, "%s: XAxisMapping: %s\n", pInfo->name, msg); xfree(msg); } xfree(s); } s = xf86SetStrOption(pInfo->options, "YAxisMapping", NULL); if (s) { int b1 = 0, b2 = 0; char *msg = NULL; if ((sscanf(s, "%d %d", &b1, &b2) == 2) && b1 > 0 && b1 <= MSE_MAXBUTTONS && b2 > 0 && b2 <= MSE_MAXBUTTONS) { msg = xstrdup("buttons XX and YY"); if (msg) sprintf(msg, "buttons %d and %d", b1, b2); pMse->negativeY = b1; pMse->positiveY = b2; if (b1 > pMse->buttons) pMse->buttons = b1; if (b2 > pMse->buttons) pMse->buttons = b2; yFromConfig = TRUE; } else { xf86Msg(X_WARNING, "%s: Invalid YAxisMapping value: \"%s\"\n", pInfo->name, s); } if (msg) { xf86Msg(X_CONFIG, "%s: YAxisMapping: %s\n", pInfo->name, msg); xfree(msg); } xfree(s); } if (!yFromConfig) { pMse->negativeY = 4; pMse->positiveY = 5; if (pMse->negativeY > pMse->buttons) pMse->buttons = pMse->negativeY; if (pMse->positiveY > pMse->buttons) pMse->buttons = pMse->positiveY; xf86Msg(X_DEFAULT, "%s: YAxisMapping: buttons %d and %d\n", pInfo->name, pMse->negativeY, pMse->positiveY); } xf86Msg(X_CONFIG, "%s: EmulateWheel, EmulateWheelButton: %d, " "EmulateWheelInertia: %d, " "EmulateWheelTimeout: %d\n", pInfo->name, wheelButton, pMse->wheelInertia, pMse->wheelButtonTimeout); } s = xf86SetStrOption(pInfo->options, "ButtonMapping", NULL); if (s) { int b, n = 0; char *s1 = s; /* keep getting numbers which are buttons */ while (s1 && n < MSE_MAXBUTTONS && (b = strtol(s1, &s1, 10)) != 0) { /* check sanity for a button */ if (b < 0 || b > MSE_MAXBUTTONS) { xf86Msg(X_WARNING, "ButtonMapping: Invalid button number = %d\n", b); break; }; pMse->buttonMap[n++] = 1 << (b-1); if (b > pMse->buttons) pMse->buttons = b; } xfree(s); } /* get maximum of mapped buttons */ for (i = pMse->buttons-1; i >= 0; i--) { int f = ffs (pMse->buttonMap[i]); if (f > pMse->buttons) pMse->buttons = f; } if (origButtons != pMse->buttons) buttons_from = X_CONFIG; xf86Msg(buttons_from, "%s: Buttons: %d\n", pInfo->name, pMse->buttons); pMse->doubleClickSourceButtonMask = 0; pMse->doubleClickTargetButtonMask = 0; pMse->doubleClickTargetButton = 0; s = xf86SetStrOption(pInfo->options, "DoubleClickButtons", NULL); if (s) { int b1 = 0, b2 = 0; char *msg = NULL; if ((sscanf(s, "%d %d", &b1, &b2) == 2) && (b1 > 0) && (b1 <= MSE_MAXBUTTONS) && (b2 > 0) && (b2 <= MSE_MAXBUTTONS)) { msg = xstrdup("buttons XX and YY"); if (msg) sprintf(msg, "buttons %d and %d", b1, b2); pMse->doubleClickTargetButton = b1; pMse->doubleClickTargetButtonMask = 1 << (b1 - 1); pMse->doubleClickSourceButtonMask = 1 << (b2 - 1); if (b1 > pMse->buttons) pMse->buttons = b1; if (b2 > pMse->buttons) pMse->buttons = b2; } else { xf86Msg(X_WARNING, "%s: Invalid DoubleClickButtons value: \"%s\"\n", pInfo->name, s); } if (msg) { xf86Msg(X_CONFIG, "%s: DoubleClickButtons: %s\n", pInfo->name, msg); xfree(msg); } xfree(s); } } /* * map bits corresponding to lock buttons. * for each bit for a lock button, * turn on bit corresponding to button button that the lock * button services. */ static int lock2targetMap(DragLockPtr pLock, int lockMask) { int result,i; result = 0; /* * for each nibble group of bits, use * map for that group to get corresponding * bits, turn them on. * if 4 or less buttons only first map will * need to be used. */ for (i = 0; (i < NIB_COUNT) && lockMask; i++) { result |= pLock->nib_table[i][lockMask& NIB_MASK]; lockMask &= ~NIB_MASK; lockMask >>= NIB_BITS; } return result; } static void MouseHWOptions(InputInfoPtr pInfo) { MouseDevPtr pMse = pInfo->private; mousePrivPtr mPriv = (mousePrivPtr)pMse->mousePriv; if (mPriv == NULL) return; if ((mPriv->soft = xf86SetBoolOption(pInfo->options, "AutoSoft", FALSE))) { xf86Msg(X_CONFIG, "Don't initialize mouse when auto-probing\n"); } pMse->sampleRate = xf86SetIntOption(pInfo->options, "SampleRate", 0); if (pMse->sampleRate) { xf86Msg(X_CONFIG, "%s: SampleRate: %d\n", pInfo->name, pMse->sampleRate); } pMse->resolution = xf86SetIntOption(pInfo->options, "Resolution", 0); if (pMse->resolution) { xf86Msg(X_CONFIG, "%s: Resolution: %d\n", pInfo->name, pMse->resolution); } if ((mPriv->sensitivity = xf86SetRealOption(pInfo->options, "Sensitivity", 1.0))) { xf86Msg(X_CONFIG, "%s: Sensitivity: %g\n", pInfo->name, mPriv->sensitivity); } } static void MouseSerialOptions(InputInfoPtr pInfo) { MouseDevPtr pMse = pInfo->private; Bool clearDTR, clearRTS; pMse->baudRate = xf86SetIntOption(pInfo->options, "BaudRate", 0); if (pMse->baudRate) { xf86Msg(X_CONFIG, "%s: BaudRate: %d\n", pInfo->name, pMse->baudRate); } if ((clearDTR = xf86SetBoolOption(pInfo->options, "ClearDTR",FALSE))) pMse->mouseFlags |= MF_CLEAR_DTR; if ((clearRTS = xf86SetBoolOption(pInfo->options, "ClearRTS",FALSE))) pMse->mouseFlags |= MF_CLEAR_RTS; if (clearDTR || clearRTS) { xf86Msg(X_CONFIG, "%s: ", pInfo->name); if (clearDTR) { xf86ErrorF("ClearDTR"); if (clearRTS) xf86ErrorF(", "); } if (clearRTS) { xf86ErrorF("ClearRTS"); } xf86ErrorF("\n"); } } static MouseProtocolID ProtocolNameToID(const char *name) { int i; for (i = 0; mouseProtocols[i].name; i++) if (xf86NameCmp(name, mouseProtocols[i].name) == 0) return mouseProtocols[i].id; return PROT_UNKNOWN; } static const char * ProtocolIDToName(MouseProtocolID id) { int i; switch (id) { case PROT_UNKNOWN: return "Unknown"; break; case PROT_UNSUP: return "Unsupported"; break; default: for (i = 0; mouseProtocols[i].name; i++) if (id == mouseProtocols[i].id) return mouseProtocols[i].name; return "Invalid"; } } static int ProtocolIDToClass(MouseProtocolID id) { int i; switch (id) { case PROT_UNKNOWN: case PROT_UNSUP: return MSE_NONE; break; default: for (i = 0; mouseProtocols[i].name; i++) if (id == mouseProtocols[i].id) return mouseProtocols[i].class; return MSE_NONE; } } static MouseProtocolPtr GetProtocol(MouseProtocolID id) { int i; switch (id) { case PROT_UNKNOWN: case PROT_UNSUP: return NULL; break; default: for (i = 0; mouseProtocols[i].name; i++) if (id == mouseProtocols[i].id) { return &mouseProtocols[i]; } return NULL; } } static OSMouseInfoPtr osInfo = NULL; static Bool InitProtocols(void) { int classes; int i; const char *osname = NULL; if (osInfo) return TRUE; osInfo = xf86OSMouseInit(0); if (!osInfo) return FALSE; if (!osInfo->SupportedInterfaces) return FALSE; classes = osInfo->SupportedInterfaces(); if (!classes) return FALSE; /* Mark unsupported interface classes. */ for (i = 0; mouseProtocols[i].name; i++) if (!(mouseProtocols[i].class & classes)) mouseProtocols[i].id = PROT_UNSUP; for (i = 0; mouseProtocols[i].name; i++) if (mouseProtocols[i].class & MSE_MISC) if (!osInfo->CheckProtocol || !osInfo->CheckProtocol(mouseProtocols[i].name)) mouseProtocols[i].id = PROT_UNSUP; /* NetBSD uses PROT_BM for "PS/2". */ xf86GetOS(&osname, NULL, NULL, NULL); if (osname && xf86NameCmp(osname, "netbsd") == 0) for (i = 0; mouseProtocols[i].name; i++) if (mouseProtocols[i].id == PROT_PS2) mouseProtocols[i].id = PROT_BM; return TRUE; } static InputInfoPtr MousePreInit(InputDriverPtr drv, IDevPtr dev, int flags) { InputInfoPtr pInfo; MouseDevPtr pMse; mousePrivPtr mPriv; MessageType protocolFrom = X_DEFAULT, deviceFrom = X_CONFIG; const char *protocol, *osProt = NULL; const char *device; MouseProtocolID protocolID; MouseProtocolPtr pProto; Bool detected; int i; if (!InitProtocols()) return NULL; if (!(pInfo = xf86AllocateInput(drv, 0))) return NULL; /* Initialise the InputInfoRec. */ pInfo->name = dev->identifier; pInfo->type_name = XI_MOUSE; pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; pInfo->device_control = MouseProc; pInfo->read_input = MouseReadInput; #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 pInfo->motion_history_proc = xf86GetMotionEvents; pInfo->history_size = 0; #endif pInfo->control_proc = NULL; pInfo->close_proc = NULL; pInfo->switch_mode = NULL; pInfo->conversion_proc = MouseConvert; pInfo->reverse_conversion_proc = NULL; pInfo->fd = -1; pInfo->dev = NULL; pInfo->private_flags = 0; pInfo->always_core_feedback = NULL; pInfo->conf_idev = dev; /* Check if SendDragEvents has been disabled. */ if (!xf86SetBoolOption(dev->commonOptions, "SendDragEvents", TRUE)) { pInfo->flags &= ~XI86_SEND_DRAG_EVENTS; } /* Allocate the MouseDevRec and initialise it. */ /* * XXX This should be done by a function in the core server since the * MouseDevRec is defined in the os-support layer. */ if (!(pMse = xcalloc(sizeof(MouseDevRec), 1))) return pInfo; pInfo->private = pMse; pMse->Ctrl = MouseCtrl; pMse->PostEvent = MousePostEvent; pMse->CommonOptions = MouseCommonOptions; /* Find the protocol type. */ protocol = xf86SetStrOption(dev->commonOptions, "Protocol", NULL); if (protocol) { protocolFrom = X_CONFIG; } else if (osInfo->DefaultProtocol) { protocol = osInfo->DefaultProtocol(); protocolFrom = X_DEFAULT; } if (!protocol) { xf86Msg(X_ERROR, "%s: No Protocol specified\n", pInfo->name); return pInfo; } /* Default Mapping: 1 2 3 8 9 10 11 ... */ for (i = 0; i < MSE_MAXBUTTONS; i++) pMse->buttonMap[i] = 1 << (i > 2 && i < MSE_MAXBUTTONS-4 ? i+4 : i); protocolID = ProtocolNameToID(protocol); do { detected = TRUE; switch (protocolID) { case PROT_AUTO: if (osInfo->SetupAuto) { if ((osProt = osInfo->SetupAuto(pInfo,NULL))) { MouseProtocolID id = ProtocolNameToID(osProt); if (id == PROT_UNKNOWN || id == PROT_UNSUP) { protocolID = id; protocol = osProt; detected = FALSE; } } } break; case PROT_UNKNOWN: /* Check for a builtin OS-specific protocol, * and call its PreInit. */ if (osInfo->CheckProtocol && osInfo->CheckProtocol(protocol)) { if (!xf86CheckStrOption(dev->commonOptions, "Device", NULL) && osInfo->FindDevice) { xf86Msg(X_WARNING, "%s: No Device specified, " "looking for one...\n", pInfo->name); if (!osInfo->FindDevice(pInfo, protocol, 0)) { xf86Msg(X_ERROR, "%s: Cannot find which device " "to use.\n", pInfo->name); } else deviceFrom = X_PROBED; } if (osInfo->PreInit) { osInfo->PreInit(pInfo, protocol, 0); } return pInfo; } xf86Msg(X_ERROR, "%s: Unknown protocol \"%s\"\n", pInfo->name, protocol); return pInfo; break; case PROT_UNSUP: xf86Msg(X_ERROR, "%s: Protocol \"%s\" is not supported on this " "platform\n", pInfo->name, protocol); return pInfo; break; default: break; } } while (!detected); if (!xf86CheckStrOption(dev->commonOptions, "Device", NULL) && osInfo->FindDevice) { xf86Msg(X_WARNING, "%s: No Device specified, looking for one...\n", pInfo->name); if (!osInfo->FindDevice(pInfo, protocol, 0)) { xf86Msg(X_ERROR, "%s: Cannot find which device to use.\n", pInfo->name); } else { deviceFrom = X_PROBED; xf86MarkOptionUsedByName(dev->commonOptions, "Device"); } } device = xf86CheckStrOption(dev->commonOptions, "Device", NULL); if (device) xf86Msg(deviceFrom, "%s: Device: \"%s\"\n", pInfo->name, device); xf86Msg(protocolFrom, "%s: Protocol: \"%s\"\n", pInfo->name, protocol); if (!(pProto = GetProtocol(protocolID))) return pInfo; pMse->protocolID = protocolID; pMse->oldProtocolID = protocolID; /* hack */ pMse->autoProbe = FALSE; /* Collect the options, and process the common options. */ xf86CollectInputOptions(pInfo, pProto->defaults, NULL); xf86ProcessCommonOptions(pInfo, pInfo->options); /* Check if the device can be opened. */ pInfo->fd = xf86OpenSerial(pInfo->options); if (pInfo->fd == -1) { if (xf86GetAllowMouseOpenFail()) xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name); else { xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name); if (pMse->mousePriv) xfree(pMse->mousePriv); xfree(pMse); pInfo->private = NULL; return pInfo; } } xf86CloseSerial(pInfo->fd); pInfo->fd = -1; if (!(mPriv = (pointer) xcalloc(sizeof(mousePrivRec), 1))) return pInfo; pMse->mousePriv = mPriv; pMse->CommonOptions(pInfo); pMse->checkMovements = checkForErraticMovements; pMse->autoProbeMouse = autoProbeMouse; pMse->collectData = collectData; pMse->dataGood = autoGood; MouseHWOptions(pInfo); MouseSerialOptions(pInfo); pInfo->flags |= XI86_CONFIGURED; return pInfo; } static void MouseReadInput(InputInfoPtr pInfo) { MouseDevPtr pMse; int j, buttons, dx, dy, dz, dw, baddata; int pBufP; int c; unsigned char *pBuf, u; pMse = pInfo->private; pBufP = pMse->protoBufTail; pBuf = pMse->protoBuf; if (pInfo->fd == -1) return; /* * Set blocking to -1 on the first call because we know there is data to * read. Xisb automatically clears it after one successful read so that * succeeding reads are preceeded by a select with a 0 timeout to prevent * read from blocking indefinitely. */ XisbBlockDuration(pMse->buffer, -1); while ((c = XisbRead(pMse->buffer)) >= 0) { u = (unsigned char)c; #if defined (EXTMOUSEDEBUG) || defined (MOUSEDATADEBUG) ErrorF("mouse byte: %2.2x\n",u); #endif /* if we do autoprobing collect the data */ if (pMse->collectData && pMse->autoProbe) if (pMse->collectData(pMse,u)) continue; #ifdef SUPPORT_MOUSE_RESET if (mouseReset(pInfo,u)) { pBufP = 0; continue; } #endif if (pBufP >= pMse->protoPara[4]) { /* * Buffer contains a full packet, which has already been processed: * Empty the buffer and check for optional 4th byte, which will be * processed directly, without being put into the buffer first. */ pBufP = 0; if ((u & pMse->protoPara[0]) != pMse->protoPara[1] && (u & pMse->protoPara[5]) == pMse->protoPara[6]) { /* * Hack for Logitech MouseMan Mouse - Middle button * * Unfortunately this mouse has variable length packets: the * standard Microsoft 3 byte packet plus an optional 4th byte * whenever the middle button status changes. * * We have already processed the standard packet with the * movement and button info. Now post an event message with * the old status of the left and right buttons and the * updated middle button. */ /* * Even worse, different MouseMen and TrackMen differ in the * 4th byte: some will send 0x00/0x20, others 0x01/0x21, or * even 0x02/0x22, so I have to strip off the lower bits. * [CHRIS-211092] * * [JCH-96/01/21] * HACK for ALPS "fourth button". (It's bit 0x10 of the * "fourth byte" and it is activated by tapping the glidepad * with the finger! 8^) We map it to bit bit3, and the * reverse map in xf86Events just has to be extended so that * it is identified as Button 4. The lower half of the * reverse-map may remain unchanged. */ /* * [KAZU-030897] * Receive the fourth byte only when preceeding three bytes * have been detected (pBufP >= pMse->protoPara[4]). In the * previous versions, the test was pBufP == 0; we may have * mistakingly received a byte even if we didn't see anything * preceeding the byte. */ #ifdef EXTMOUSEDEBUG ErrorF("mouse 4th byte %02x\n",u); #endif dx = dy = dz = dw = 0; buttons = 0; switch (pMse->protocolID) { /* * [KAZU-221197] * IntelliMouse, NetMouse (including NetMouse Pro) and Mie * Mouse always send the fourth byte, whereas the fourth byte * is optional for GlidePoint and ThinkingMouse. The fourth * byte is also optional for MouseMan+ and FirstMouse+ in * their native mode. It is always sent if they are in the * IntelliMouse compatible mode. */ case PROT_IMSERIAL: /* IntelliMouse, NetMouse, Mie Mouse, MouseMan+ */ dz = (u & 0x08) ? (u & 0x0f) - 16 : (u & 0x0f); if ((dz >= 7) || (dz <= -7)) dz = 0; buttons |= ((int)(u & 0x10) >> 3) | ((int)(u & 0x20) >> 2) | (pMse->lastButtons & 0x05); break; case PROT_GLIDE: case PROT_THINKING: buttons |= ((int)(u & 0x10) >> 1); /* fall through */ default: buttons |= ((int)(u & 0x20) >> 4) | (pMse->lastButtons & 0x05); break; } goto post_event; } } /* End of packet buffer flush and 4th byte hack. */ /* * Append next byte to buffer (which is empty or contains an * incomplete packet); iterate if packet (still) not complete. */ pBuf[pBufP++] = u; if (pBufP != pMse->protoPara[4]) continue; #ifdef EXTMOUSEDEBUG2 { int i; ErrorF("received %d bytes",pBufP); for ( i=0; i < pBufP; i++) ErrorF(" %02x",pBuf[i]); ErrorF("\n"); } #endif /* * Hack for resyncing: We check here for a package that is: * a) illegal (detected by wrong data-package header) * b) invalid (0x80 == -128 and that might be wrong for MouseSystems) * c) bad header-package * * NOTE: b) is a violation of the MouseSystems-Protocol, since values * of -128 are allowed, but since they are very seldom we can * easily use them as package-header with no button pressed. * NOTE/2: On a PS/2 mouse any byte is valid as a data byte. * Furthermore, 0x80 is not valid as a header byte. For a PS/2 * mouse we skip checking data bytes. For resyncing a PS/2 * mouse we require the two most significant bits in the header * byte to be 0. These are the overflow bits, and in case of * an overflow we actually lose sync. Overflows are very rare, * however, and we quickly gain sync again after an overflow * condition. This is the best we can do. (Actually, we could * use bit 0x08 in the header byte for resyncing, since that * bit is supposed to be always on, but nobody told Microsoft...) */ /* * [KAZU,OYVIND-120398] * The above hack is wrong! Because of b) above, we shall see * erroneous mouse events so often when the MouseSystem mouse is * moved quickly. As for the PS/2 and its variants, we don't need * to treat them as special cases, because protoPara[2] and * protoPara[3] are both 0x00 for them, thus, any data bytes will * never be discarded. 0x80 is rejected for MMSeries, Logitech * and MMHittab protocols, because protoPara[2] and protoPara[3] * are 0x80 and 0x00 respectively. The other protocols are 7-bit * protocols; there is no use checking 0x80. * * All in all we should check the condition a) only. */ /* * [OYVIND-120498] * Check packet for valid data: * If driver is in sync with datastream, the packet is considered * bad if any byte (header and/or data) contains an invalid value. * * If packet is bad, we discard the first byte and shift the buffer. * Next iteration will then check the new situation for validity. * * If flag MF_SAFE is set in proto[7] and the driver * is out of sync, the packet is also considered bad if * any of the data bytes contains a valid header byte value. * This situation could occur if the buffer contains * the tail of one packet and the header of the next. * * Note: The driver starts in out-of-sync mode (pMse->inSync = 0). */ baddata = 0; /* All databytes must be valid. */ for (j = 1; j < pBufP; j++ ) if ((pBuf[j] & pMse->protoPara[2]) != pMse->protoPara[3]) baddata = 1; /* If out of sync, don't mistake a header byte for data. */ if ((pMse->protoPara[7] & MPF_SAFE) && !pMse->inSync) for (j = 1; j < pBufP; j++ ) if ((pBuf[j] & pMse->protoPara[0]) == pMse->protoPara[1]) baddata = 1; /* Accept or reject the packet ? */ if ((pBuf[0] & pMse->protoPara[0]) != pMse->protoPara[1] || baddata) { if (pMse->inSync) { #ifdef EXTMOUSEDEBUG ErrorF("mouse driver lost sync\n"); #endif } #ifdef EXTMOUSEDEBUG ErrorF("skipping byte %02x\n",*pBuf); #endif /* Tell auto probe that we are out of sync */ if (pMse->autoProbeMouse && pMse->autoProbe) pMse->autoProbeMouse(pInfo, FALSE, pMse->inSync); pMse->protoBufTail = --pBufP; for (j = 0; j < pBufP; j++) pBuf[j] = pBuf[j+1]; pMse->inSync = 0; continue; } /* Tell auto probe that we were successful */ if (pMse->autoProbeMouse && pMse->autoProbe) pMse->autoProbeMouse(pInfo, TRUE, FALSE); if (!pMse->inSync) { #ifdef EXTMOUSEDEBUG ErrorF("mouse driver back in sync\n"); #endif pMse->inSync = 1; } if (!pMse->dataGood(pMse)) continue; /* * Packet complete and verified, now process it ... */ REDO_INTERPRET: dz = dw = 0; switch (pMse->protocolID) { case PROT_LOGIMAN: /* MouseMan / TrackMan [CHRIS-211092] */ case PROT_MS: /* Microsoft */ if (pMse->chordMiddle) buttons = (((int) pBuf[0] & 0x30) == 0x30) ? 2 : ((int)(pBuf[0] & 0x20) >> 3) | ((int)(pBuf[0] & 0x10) >> 4); else buttons = (pMse->lastButtons & 2) | ((int)(pBuf[0] & 0x20) >> 3) | ((int)(pBuf[0] & 0x10) >> 4); dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); break; case PROT_GLIDE: /* ALPS GlidePoint */ case PROT_THINKING: /* ThinkingMouse */ case PROT_IMSERIAL: /* IntelliMouse, NetMouse, Mie Mouse, MouseMan+ */ buttons = (pMse->lastButtons & (8 + 2)) | ((int)(pBuf[0] & 0x20) >> 3) | ((int)(pBuf[0] & 0x10) >> 4); dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); break; case PROT_MSC: /* Mouse Systems Corp */ buttons = (~pBuf[0]) & 0x07; dx = (signed char)(pBuf[1]) + (char)(pBuf[3]); dy = - ((signed char)(pBuf[2]) + (char)(pBuf[4])); break; case PROT_MMHIT: /* MM_HitTablet */ buttons = pBuf[0] & 0x07; if (buttons != 0) buttons = 1 << (buttons - 1); dx = (pBuf[0] & 0x10) ? pBuf[1] : - pBuf[1]; dy = (pBuf[0] & 0x08) ? - pBuf[2] : pBuf[2]; break; case PROT_ACECAD: /* ACECAD */ /* ACECAD is almost exactly like MM but the buttons are different */ buttons = (pBuf[0] & 0x02) | ((pBuf[0] & 0x04) >> 2) | ((pBuf[0] & 1) << 2); dx = (pBuf[0] & 0x10) ? pBuf[1] : - pBuf[1]; dy = (pBuf[0] & 0x08) ? - pBuf[2] : pBuf[2]; break; case PROT_MM: /* MM Series */ case PROT_LOGI: /* Logitech Mice */ buttons = pBuf[0] & 0x07; dx = (pBuf[0] & 0x10) ? pBuf[1] : - pBuf[1]; dy = (pBuf[0] & 0x08) ? - pBuf[2] : pBuf[2]; break; case PROT_BM: /* BusMouse */ buttons = (~pBuf[0]) & 0x07; dx = (signed char)pBuf[1]; dy = - (signed char)pBuf[2]; break; case PROT_PS2: /* PS/2 mouse */ case PROT_GENPS2: /* generic PS/2 mouse */ buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2; /* Left */ dx = (pBuf[0] & 0x10) ? (int)pBuf[1]-256 : (int)pBuf[1]; dy = (pBuf[0] & 0x20) ? -((int)pBuf[2]-256) : -(int)pBuf[2]; break; /* PS/2 mouse variants */ case PROT_IMPS2: /* IntelliMouse PS/2 */ case PROT_NETPS2: /* NetMouse PS/2 */ buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2 | /* Left */ (pBuf[0] & 0x40) >> 3 | /* button 4 */ (pBuf[0] & 0x80) >> 3; /* button 5 */ dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1]; dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2]; /* * The next cast must be 'signed char' for platforms (like PPC) * where char defaults to unsigned. */ dz = (signed char)(pBuf[3] | ((pBuf[3] & 0x08) ? 0xf8 : 0)); if ((pBuf[3] & 0xf8) && ((pBuf[3] & 0xf8) != 0xf8)) { if (pMse->autoProbe) { SetMouseProto(pMse, PROT_EXPPS2); xf86Msg(X_INFO, "Mouse autoprobe: Changing protocol to %s\n", pMse->protocol); goto REDO_INTERPRET; } else dz = 0; } break; case PROT_EXPPS2: /* IntelliMouse Explorer PS/2 */ if (pMse->autoProbe && (pBuf[3] & 0xC0)) { SetMouseProto(pMse, PROT_IMPS2); xf86Msg(X_INFO,"Mouse autoprobe: Changing protocol to %s\n", pMse->protocol); goto REDO_INTERPRET; } buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2 | /* Left */ (pBuf[3] & 0x10) >> 1 | /* button 4 */ (pBuf[3] & 0x20) >> 1; /* button 5 */ dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1]; dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2]; if (pMse->negativeW != MSE_NOAXISMAP) { switch (pBuf[3] & 0x0f) { case 0x00: break; case 0x01: dz = 1; break; case 0x02: dw = 1; break; case 0x0e: dw = -1; break; case 0x0f: dz = -1; break; default: xf86Msg(X_INFO, "Mouse autoprobe: Disabling secondary wheel\n"); pMse->negativeW = pMse->positiveW = MSE_NOAXISMAP; } } if (pMse->negativeW == MSE_NOAXISMAP) dz = (pBuf[3]&0x08) ? (pBuf[3]&0x0f) - 16 : (pBuf[3]&0x0f); break; case PROT_MMPS2: /* MouseMan+ PS/2 */ buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2; /* Left */ dx = (pBuf[0] & 0x10) ? pBuf[1] - 256 : pBuf[1]; if (((pBuf[0] & 0x48) == 0x48) && (abs(dx) > 191) && ((((pBuf[2] & 0x03) << 2) | 0x02) == (pBuf[1] & 0x0f))) { /* extended data packet */ switch ((((pBuf[0] & 0x30) >> 2) | ((pBuf[1] & 0x30) >> 4))) { case 1: /* wheel data packet */ buttons |= ((pBuf[2] & 0x10) ? 0x08 : 0) | /* 4th button */ ((pBuf[2] & 0x20) ? 0x10 : 0); /* 5th button */ dx = dy = 0; dz = (pBuf[2] & 0x08) ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); break; case 2: /* Logitech reserves this packet type */ /* * IBM ScrollPoint uses this packet to encode its * stick movement. */ buttons |= (pMse->lastButtons & ~0x07); dx = dy = 0; dz = (pBuf[2] & 0x80) ? ((pBuf[2] >> 4) & 0x0f) - 16 : ((pBuf[2] >> 4) & 0x0f); dw = (pBuf[2] & 0x08) ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f); break; case 0: /* device type packet - shouldn't happen */ default: buttons |= (pMse->lastButtons & ~0x07); dx = dy = 0; dz = 0; break; } } else { buttons |= (pMse->lastButtons & ~0x07); dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1]; dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2]; } break; case PROT_GLIDEPS2: /* GlidePoint PS/2 */ buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2 | /* Left */ ((pBuf[0] & 0x08) ? 0 : 0x08);/* fourth button */ dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1]; dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2]; break; case PROT_NETSCPS2: /* NetScroll PS/2 */ buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2 | /* Left */ ((pBuf[3] & 0x02) ? 0x08 : 0) | /* button 4 */ ((pBuf[3] & 0x01) ? 0x10 : 0); /* button 5 */ dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1]; dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2]; dz = (pBuf[3] & 0x10) ? pBuf[4] - 256 : pBuf[4]; break; case PROT_THINKPS2: /* ThinkingMouse PS/2 */ buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */ (pBuf[0] & 0x02) >> 1 | /* Right */ (pBuf[0] & 0x01) << 2 | /* Left */ ((pBuf[0] & 0x08) ? 0x08 : 0);/* fourth button */ pBuf[1] |= (pBuf[0] & 0x40) ? 0x80 : 0x00; dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1]; dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2]; break; case PROT_SYSMOUSE: /* sysmouse */ buttons = (~pBuf[0]) & 0x07; dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]); dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4])); /* FreeBSD sysmouse sends additional data bytes */ if (pMse->protoPara[4] >= 8) { /* * These casts must be 'signed char' for platforms (like PPC) * where char defaults to unsigned. */ dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1; buttons |= (int)(~pBuf[7] & 0x7f) << 3; } break; case PROT_VALUMOUSESCROLL: /* Kensington ValuMouseScroll */ buttons = ((int)(pBuf[0] & 0x20) >> 3) | ((int)(pBuf[0] & 0x10) >> 4) | ((int)(pBuf[3] & 0x10) >> 3); dx = (signed char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F)); dy = (signed char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F)); dz = (pBuf[3] & 0x08) ? ((int)(pBuf[3] & 0x0F) - 0x10) : ((int)(pBuf[3] & 0x0F)); break; default: /* There's a table error */ #ifdef EXTMOUSEDEBUG ErrorF("mouse table error\n"); #endif continue; } #ifdef EXTMOUSEDEBUG ErrorF("packet"); for ( j=0; j < pBufP; j++) ErrorF(" %02x",pBuf[j]); ErrorF("\n"); #endif post_event: #ifdef EXTMOUSEDEBUG ErrorF("dx=%i dy=%i dz=%i dw=%i buttons=%x\n",dx,dy,dz,dw,buttons); #endif /* When auto-probing check if data makes sense */ if (pMse->checkMovements && pMse->autoProbe) pMse->checkMovements(pInfo,dx,dy); /* post an event */ pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw); /* * We don't reset pBufP here yet, as there may be an additional data * byte in some protocols. See above. */ } pMse->protoBufTail = pBufP; } /* * MouseCtrl -- * Alter the control parameters for the mouse. Note that all special * protocol values are handled by dix. */ static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl) { InputInfoPtr pInfo; MouseDevPtr pMse; pInfo = device->public.devicePrivate; pMse = pInfo->private; #ifdef EXTMOUSEDEBUG ErrorF("MouseCtrl pMse=%p\n", pMse); #endif pMse->num = ctrl->num; pMse->den = ctrl->den; pMse->threshold = ctrl->threshold; } /* *************************************************************************** * * MouseProc -- * *************************************************************************** */ static int MouseProc(DeviceIntPtr device, int what) { InputInfoPtr pInfo; MouseDevPtr pMse; mousePrivPtr mPriv; unsigned char map[MSE_MAXBUTTONS + 1]; int i; #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 Atom btn_labels[MSE_MAXBUTTONS] = {0}; Atom axes_labels[2] = { 0, 0 }; #endif pInfo = device->public.devicePrivate; pMse = pInfo->private; pMse->device = device; switch (what) { case DEVICE_INIT: device->public.on = FALSE; /* * [KAZU-241097] We don't know exactly how many buttons the * device has, so setup the map with the maximum number. */ for (i = 0; i < MSE_MAXBUTTONS; i++) map[i + 1] = i + 1; /* FIXME: we should probably set the labels here */ InitPointerDeviceStruct((DevicePtr)device, map, min(pMse->buttons, MSE_MAXBUTTONS), #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 btn_labels, #endif #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 miPointerGetMotionEvents, #elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3 GetMotionHistory, #endif pMse->Ctrl, #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 miPointerGetMotionBufferSize() #else GetMotionHistorySize(), 2 #endif #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 , axes_labels #endif ); /* X valuator */ xf86InitValuatorAxisStruct(device, 0, #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 axes_labels[0], #endif -1, -1, 1, 0, 1); xf86InitValuatorDefaults(device, 0); /* Y valuator */ xf86InitValuatorAxisStruct(device, 1, #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 axes_labels[1], #endif -1, -1, 1, 0, 1); xf86InitValuatorDefaults(device, 1); #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 xf86MotionHistoryAllocate(pInfo); #endif #ifdef EXTMOUSEDEBUG ErrorF("assigning %p atom=%d name=%s\n", device, pInfo->atom, pInfo->name); #endif break; case DEVICE_ON: pInfo->fd = xf86OpenSerial(pInfo->options); if (pInfo->fd == -1) xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name); else { if (pMse->xisbscale) pMse->buffer = XisbNew(pInfo->fd, pMse->xisbscale * 4); else pMse->buffer = XisbNew(pInfo->fd, 64); if (!pMse->buffer) { xf86CloseSerial(pInfo->fd); pInfo->fd = -1; } else { if (!SetupMouse(pInfo)) { xf86CloseSerial(pInfo->fd); pInfo->fd = -1; XisbFree(pMse->buffer); pMse->buffer = NULL; } else { mPriv = (mousePrivPtr)pMse->mousePriv; if (mPriv != NULL) { if ( pMse->protocolID != PROT_AUTO) { pMse->inSync = TRUE; /* @@@ */ if (mPriv->soft) mPriv->autoState = AUTOPROBE_GOOD; else mPriv->autoState = AUTOPROBE_H_GOOD; } else { if (mPriv->soft) mPriv->autoState = AUTOPROBE_NOPROTO; else mPriv->autoState = AUTOPROBE_H_NOPROTO; } } xf86FlushInput(pInfo->fd); xf86AddEnabledDevice(pInfo); if (pMse->emulate3Buttons || pMse->emulate3ButtonsSoft) { RegisterBlockAndWakeupHandlers (MouseBlockHandler, MouseWakeupHandler, (pointer) pInfo); } } } } pMse->lastButtons = 0; pMse->lastMappedButtons = 0; pMse->emulateState = 0; pMse->emulate3Pending = FALSE; pMse->wheelButtonExpires = GetTimeInMillis (); device->public.on = TRUE; FlushButtons(pMse); break; case DEVICE_OFF: case DEVICE_CLOSE: if (pInfo->fd != -1) { xf86RemoveEnabledDevice(pInfo); if (pMse->buffer) { XisbFree(pMse->buffer); pMse->buffer = NULL; } xf86CloseSerial(pInfo->fd); pInfo->fd = -1; if (pMse->emulate3Buttons || pMse->emulate3ButtonsSoft) { RemoveBlockAndWakeupHandlers (MouseBlockHandler, MouseWakeupHandler, (pointer) pInfo); } } device->public.on = FALSE; break; } return Success; } /* *************************************************************************** * * MouseConvert -- * Convert valuators to X and Y. * *************************************************************************** */ static Bool MouseConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2, int v3, int v4, int v5, int *x, int *y) { if (first != 0 || num != 2) return FALSE; *x = v0; *y = v1; return TRUE; } /********************************************************************** * * FlushButtons -- reset button states. * **********************************************************************/ static void FlushButtons(MouseDevPtr pMse) { pMse->lastButtons = 0; pMse->lastMappedButtons = 0; } /********************************************************************** * * Emulate3Button support code * **********************************************************************/ /* * Lets create a simple finite-state machine for 3 button emulation: * * We track buttons 1 and 3 (left and right). There are 11 states: * 0 ground - initial state * 1 delayed left - left pressed, waiting for right * 2 delayed right - right pressed, waiting for left * 3 pressed middle - right and left pressed, emulated middle sent * 4 pressed left - left pressed and sent * 5 pressed right - right pressed and sent * 6 released left - left released after emulated middle * 7 released right - right released after emulated middle * 8 repressed left - left pressed after released left * 9 repressed right - right pressed after released right * 10 pressed both - both pressed, not emulating middle * * At each state, we need handlers for the following events * 0: no buttons down * 1: left button down * 2: right button down * 3: both buttons down * 4: emulate3Timeout passed without a button change * Note that button events are not deltas, they are the set of buttons being * pressed now. It's possible (ie, mouse hardware does it) to go from (eg) * left down to right down without anything in between, so all cases must be * handled. * * a handler consists of three values: * 0: action1 * 1: action2 * 2: new emulation state * * action > 0: ButtonPress * action = 0: nothing * action < 0: ButtonRelease * * The comment preceeding each section is the current emulation state. * The comments to the right are of the form *