vmmouse.c revision d075918c
1/* 2 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 3 * Copyright 1993 by David Dawes <dawes@xfree86.org> 4 * Copyright 2002 by SuSE Linux AG, Author: Egbert Eich 5 * Copyright 1994-2002 by The XFree86 Project, Inc. 6 * Copyright 2002 by Paul Elliott 7 * Copyright 2002-2006 by VMware, Inc. 8 * 9 * Permission to use, copy, modify, distribute, and sell this software and its 10 * documentation for any purpose is hereby granted without fee, provided that 11 * the above copyright notice appear in all copies and that both that 12 * copyright notice and this permission notice appear in supporting 13 * documentation, and that the names of copyright holders not be 14 * used in advertising or publicity pertaining to distribution of the 15 * software without specific, written prior permission. The copyright holders 16 * make no representations about the suitability of this 17 * software for any purpose. It is provided "as is" without express or 18 * implied warranty. 19 * 20 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 21 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 24 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 25 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 26 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 27 * 28 */ 29 30/* 31 * vmmouse.c -- 32 * 33 * This is a modified version of the mouse input driver 34 * provided in Xserver/hw/xfree86/input/mouse/mouse.c 35 * 36 * Although all data is read using the vmmouse protocol, notification 37 * is still done through the PS/2 port, so all the basic code for 38 * interacting with the port is retained. 39 * 40 */ 41 42 43/***************************************************************************** 44 * Standard Headers 45 ****************************************************************************/ 46#ifdef HAVE_CONFIG_H 47#include "config.h" 48#endif 49 50#include <stdio.h> 51#define NEED_EVENTS 52#include <X11/X.h> 53#include <X11/Xproto.h> 54 55#include "xf86.h" 56 57#ifdef XINPUT 58#include <X11/extensions/XI.h> 59#include <X11/extensions/XIproto.h> 60#include "extnsionst.h" 61#include "extinit.h" 62#else 63#include "inputstr.h" 64#endif 65 66#include "xf86Xinput.h" 67#include "xf86_OSproc.h" 68#include "xf86OSmouse.h" 69#include "compiler.h" 70 71#include "xisb.h" 72#include "mipointer.h" 73 74/***************************************************************************** 75 * Local Headers 76 ****************************************************************************/ 77#include "vmmouse_client.h" 78 79/* 80 * This is the only way I know to turn a #define of an integer constant into 81 * a constant string. 82 */ 83#define VMW_INNERSTRINGIFY(s) #s 84#define VMW_STRING(str) VMW_INNERSTRINGIFY(str) 85 86/* 87 * So that the file compiles unmodified when dropped into an xfree source tree. 88 */ 89#ifndef XORG_VERSION_CURRENT 90#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT 91#endif 92 93/* 94 * Version constants 95 */ 96#define VMMOUSE_MAJOR_VERSION 12 97#define VMMOUSE_MINOR_VERSION 6 98#define VMMOUSE_PATCHLEVEL 4 99#define VMMOUSE_DRIVER_VERSION \ 100 (VMMOUSE_MAJOR_VERSION * 65536 + VMMOUSE_MINOR_VERSION * 256 + VMMOUSE_PATCHLEVEL) 101#define VMMOUSE_DRIVER_VERSION_STRING \ 102 VMW_STRING(VMMOUSE_MAJOR_VERSION) "." VMW_STRING(VMMOUSE_MINOR_VERSION) \ 103 "." VMW_STRING(VMMOUSE_PATCHLEVEL) 104 105/* 106 * Standard four digit version string expected by VMware Tools installer. 107 * As the driver's version is only {major, minor, patchlevel}, simply append an 108 * extra zero for the fourth digit. 109 */ 110#ifdef __GNUC__ 111const char vm_mouse_version[] __attribute__((section(".modinfo"),unused)) = 112 "version=" VMMOUSE_DRIVER_VERSION_STRING ".0"; 113#endif 114 115 116/***************************************************************************** 117 * static function header 118 ****************************************************************************/ 119#ifdef XFree86LOADER 120static const OptionInfoRec *VMMouseAvailableOptions(void *unused); 121#endif 122static InputInfoPtr VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags); 123static void VMMouseUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags); 124static void MouseCommonOptions(InputInfoPtr pInfo); 125static void GetVMMouseMotionEvent(InputInfoPtr pInfo); 126static void VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw); 127static void VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy); 128static Bool VMMouseDeviceControl(DeviceIntPtr device, int mode); 129static void VMMouseCloseProc(LocalDevicePtr local); 130static int VMMouseControlProc(LocalDevicePtr local, xDeviceCtl * control); 131static void VMMouseReadInput(InputInfoPtr pInfo); 132static int VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode); 133static Bool VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2, 134 int v3, int v4, int v5, int *x, int *y); 135static void MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl); 136 137/****************************************************************************** 138 * Definitions 139 *****************************************************************************/ 140typedef struct { 141 int screenNum; 142 Bool vmmouseAvailable; 143 VMMOUSE_INPUT_DATA vmmousePrevInput; 144 Bool isCurrRelative; 145 Bool absoluteRequested; 146} VMMousePrivRec, *VMMousePrivPtr; 147 148static const char *reqSymbols[] = { 149 "InitPointerDeviceStruct", 150 "LoaderSymbol", 151 "LoadSubModule", 152 "miPointerGetMotionBufferSize", 153 "miPointerGetMotionEvents", 154 "screenInfo", 155 "Xcalloc", 156 "xf86AddEnabledDevice", 157 "xf86AddInputDriver", 158 "xf86AddModuleInfo", 159 "xf86AllocateInput", 160 "xf86BlockSIGIO", 161 "xf86CloseSerial", 162 "xf86CollectInputOptions", 163 "xf86ffs", 164 "xf86FlushInput", 165 "xf86GetAllowMouseOpenFail", 166 "xf86GetMotionEvents", 167 "xf86InitValuatorAxisStruct", 168 "xf86InitValuatorDefaults", 169 "xf86LoaderCheckSymbol", 170 "xf86MotionHistoryAllocate", 171 "xf86Msg", 172 "xf86NameCmp", 173 "xf86OpenSerial", 174 "xf86OSMouseInit", 175 "xf86PostButtonEvent", 176 "xf86PostMotionEvent", 177 "xf86ProcessCommonOptions", 178 "xf86RemoveEnabledDevice", 179 "xf86SetIntOption", 180 "xf86SetStrOption", 181 "xf86sprintf", 182 "xf86sscanf", 183 "xf86UnblockSIGIO", 184 "xf86usleep", 185 "xf86XInputSetScreen", 186 "Xfree", 187 "XisbBlockDuration", 188 "XisbFree", 189 "XisbNew", 190 "XisbRead", 191 "Xstrdup", 192 NULL 193}; 194 195InputDriverRec VMMOUSE = { 196 1, 197 "vmmouse", 198 NULL, 199 VMMousePreInit, 200 VMMouseUnInit, 201 NULL, 202 0 203}; 204 205typedef enum { 206 OPTION_ALWAYS_CORE, 207 OPTION_SEND_CORE_EVENTS, 208 OPTION_CORE_POINTER, 209 OPTION_SEND_DRAG_EVENTS, 210 OPTION_HISTORY_SIZE, 211 OPTION_DEVICE, 212 OPTION_PROTOCOL, 213 OPTION_BUTTONS, 214 OPTION_EMULATE_3_BUTTONS, 215 OPTION_EMULATE_3_TIMEOUT, 216 OPTION_CHORD_MIDDLE, 217 OPTION_FLIP_XY, 218 OPTION_INV_X, 219 OPTION_INV_Y, 220 OPTION_ANGLE_OFFSET, 221 OPTION_Z_AXIS_MAPPING, 222 OPTION_SAMPLE_RATE, 223 OPTION_RESOLUTION, 224 OPTION_EMULATE_WHEEL, 225 OPTION_EMU_WHEEL_BUTTON, 226 OPTION_EMU_WHEEL_INERTIA, 227 OPTION_X_AXIS_MAPPING, 228 OPTION_Y_AXIS_MAPPING, 229 OPTION_AUTO_SOFT, 230 OPTION_DRAGLOCKBUTTONS 231} MouseOpts; 232 233/* 234 * Define the acceptable mouse options 235 * Currently not all of those options are supported 236 * 237 */ 238static const OptionInfoRec mouseOptions[] = { 239 { OPTION_ALWAYS_CORE, "AlwaysCore", OPTV_BOOLEAN, {0}, FALSE }, 240 { OPTION_SEND_CORE_EVENTS, "SendCoreEvents", OPTV_BOOLEAN, {0}, FALSE }, 241 { OPTION_CORE_POINTER, "CorePointer", OPTV_BOOLEAN, {0}, FALSE }, 242 { OPTION_SEND_DRAG_EVENTS, "SendDragEvents", OPTV_BOOLEAN, {0}, FALSE }, 243 { OPTION_HISTORY_SIZE, "HistorySize", OPTV_INTEGER, {0}, FALSE }, 244 { OPTION_DEVICE, "Device", OPTV_STRING, {0}, FALSE }, 245 { OPTION_PROTOCOL, "Protocol", OPTV_STRING, {0}, FALSE }, 246 { OPTION_BUTTONS, "Buttons", OPTV_INTEGER, {0}, FALSE }, 247 { OPTION_EMULATE_3_BUTTONS, "Emulate3Buttons",OPTV_BOOLEAN, {0}, FALSE }, 248 { OPTION_EMULATE_3_TIMEOUT, "Emulate3Timeout",OPTV_INTEGER, {0}, FALSE }, 249 { OPTION_CHORD_MIDDLE, "ChordMiddle", OPTV_BOOLEAN, {0}, FALSE }, 250 { OPTION_FLIP_XY, "FlipXY", OPTV_BOOLEAN, {0}, FALSE }, 251 { OPTION_INV_X, "InvX", OPTV_BOOLEAN, {0}, FALSE }, 252 { OPTION_INV_Y, "InvY", OPTV_BOOLEAN, {0}, FALSE }, 253 { OPTION_ANGLE_OFFSET, "AngleOffset", OPTV_INTEGER, {0}, FALSE }, 254 { OPTION_Z_AXIS_MAPPING, "ZAxisMapping", OPTV_STRING, {0}, FALSE }, 255 { OPTION_SAMPLE_RATE, "SampleRate", OPTV_INTEGER, {0}, FALSE }, 256 { OPTION_RESOLUTION, "Resolution", OPTV_INTEGER, {0}, FALSE }, 257 { OPTION_EMULATE_WHEEL, "EmulateWheel", OPTV_BOOLEAN, {0}, FALSE }, 258 { OPTION_EMU_WHEEL_BUTTON, "EmulateWheelButton", OPTV_INTEGER, {0}, FALSE }, 259 { OPTION_EMU_WHEEL_INERTIA, "EmulateWheelInertia", OPTV_INTEGER, {0}, FALSE }, 260 { OPTION_X_AXIS_MAPPING, "XAxisMapping", OPTV_STRING, {0}, FALSE }, 261 { OPTION_Y_AXIS_MAPPING, "YAxisMapping", OPTV_STRING, {0}, FALSE }, 262 { OPTION_AUTO_SOFT, "AutoSoft", OPTV_BOOLEAN, {0}, FALSE }, 263 { OPTION_DRAGLOCKBUTTONS, "DragLockButtons",OPTV_STRING, {0}, FALSE }, 264 { -1, NULL, OPTV_NONE, {0}, FALSE } 265}; 266 267static char reverseMap[32] = { 0, 4, 2, 6, 1, 5, 3, 7, 268 8, 12, 10, 14, 9, 13, 11, 15, 269 16, 20, 18, 22, 17, 21, 19, 23, 270 24, 28, 26, 30, 25, 29, 27, 31}; 271 272#define reverseBits(map, b) (((b) & ~0x0f) | map[(b) & 0x0f]) 273 274 275/* 276 *---------------------------------------------------------------------- 277 * 278 * VMMousePreInit -- 279 * This function collect all the information that is necessary to 280 * determine the configuration of the hardware and to prepare the 281 * device for being used 282 * 283 * Results: 284 * An InputInfoPtr object which points to vmmouse's information, 285 * if the absolute pointing device available 286 * Otherwise, an InputInfoPtr of regular mouse 287 * 288 * Side effects: 289 * VMMouse was initialized with necessary information 290 * 291 *---------------------------------------------------------------------- 292 */ 293 294static InputInfoPtr 295VMMousePreInit(InputDriverPtr drv, IDevPtr dev, int flags) 296{ 297 InputInfoPtr pInfo; 298 MouseDevPtr pMse; 299 VMMousePrivPtr mPriv; 300 OSMouseInfoPtr osInfo = NULL; 301 302 /* 303 * let Xserver init the mouse first 304 */ 305 osInfo = xf86OSMouseInit(0); 306 if (!osInfo) 307 return FALSE; 308 309 mPriv = xcalloc (1, sizeof (VMMousePrivRec)); 310 311 312 if (!mPriv) { 313 return NULL; 314 } 315 316 mPriv->absoluteRequested = FALSE; 317 318 /* 319 * try to enable vmmouse here 320 */ 321 if (!VMMouseClient_Enable()) { 322 /* 323 * vmmouse failed 324 * Fall back to normal mouse module 325 */ 326 InputDriverRec *passthruMouse; 327 xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n"); 328 mPriv->vmmouseAvailable = FALSE; 329 passthruMouse = (InputDriverRec *)LoaderSymbol("MOUSE"); 330 xfree(mPriv); 331 if(passthruMouse != NULL){ 332 return (passthruMouse->PreInit)(drv, dev, flags); 333 } else { 334 return NULL; 335 } 336 337 } else { 338 /* 339 * vmmouse is available 340 */ 341 mPriv->vmmouseAvailable = TRUE; 342 xf86Msg(X_INFO, "VMWARE(0): vmmouse is available\n"); 343 /* 344 * Disable the absolute pointing device for now 345 * It will be enabled during DEVICE_ON phase 346 */ 347 VMMouseClient_Disable(); 348 } 349 350 if (!(pInfo = xf86AllocateInput(drv, 0))) { 351 xfree(mPriv); 352 return NULL; 353 } 354 355 /* Settup the pInfo */ 356 pInfo->name = dev->identifier; 357 pInfo->type_name = XI_MOUSE; 358 pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS; 359 pInfo->device_control = VMMouseDeviceControl; 360 pInfo->read_input = VMMouseReadInput; 361#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 362 pInfo->motion_history_proc = xf86GetMotionEvents; 363#endif 364 pInfo->control_proc = VMMouseControlProc; 365 pInfo->close_proc = VMMouseCloseProc; 366 pInfo->switch_mode = VMMouseSwitchMode; 367 pInfo->conversion_proc = VMMouseConvertProc; 368 pInfo->reverse_conversion_proc = NULL; 369 pInfo->fd = -1; 370 pInfo->dev = NULL; 371 pInfo->private_flags = 0; 372 pInfo->always_core_feedback = 0; 373 pInfo->conf_idev = dev; 374 375 /* Allocate the MouseDevRec and initialise it. */ 376 if (!(pMse = xcalloc(sizeof(MouseDevRec), 1))) { 377 xfree(mPriv); 378 return pInfo; 379 } 380 381 pInfo->private = pMse; 382 pMse->Ctrl = MouseCtrl; 383 pMse->PostEvent = VMMousePostEvent; 384 pMse->CommonOptions = MouseCommonOptions; 385 pMse->mousePriv = mPriv; 386 387 388 /* Collect the options, and process the common options. */ 389 xf86CollectInputOptions(pInfo, NULL, NULL); 390 xf86ProcessCommonOptions(pInfo, pInfo->options); 391 392 /* Check if the device can be opened. */ 393 pInfo->fd = xf86OpenSerial(pInfo->options); 394 if (pInfo->fd == -1) { 395 if (xf86GetAllowMouseOpenFail()) 396 xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name); 397 else { 398 xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name); 399 if (pMse->mousePriv) 400 xfree(pMse->mousePriv); 401 xfree(pMse); 402 pInfo->private = NULL; 403 return pInfo; 404 } 405 } 406 xf86CloseSerial(pInfo->fd); 407 pInfo->fd = -1; 408 409 /* Process the options */ 410 pMse->CommonOptions(pInfo); 411 412 /* set up the current screen num */ 413 mPriv->screenNum = xf86SetIntOption(pInfo->options, "ScreenNumber", 0); 414 415 pInfo->flags |= XI86_CONFIGURED; 416 return pInfo; 417} 418 419#ifdef XFree86LOADER 420static const OptionInfoRec * 421VMMouseAvailableOptions(void *unused) 422{ 423 return (mouseOptions); 424} 425#endif 426 427 428/* 429 *---------------------------------------------------------------------- 430 * 431 * MouseCtrl -- 432 * Alter the control paramters for the mouse. 433 * 434 * Results: 435 * None 436 * 437 * Side effects: 438 * None 439 * 440 *---------------------------------------------------------------------- 441 */ 442 443static void 444MouseCtrl(DeviceIntPtr device, PtrCtrl *ctrl) 445{ 446 InputInfoPtr pInfo; 447 MouseDevPtr pMse; 448 449 pInfo = device->public.devicePrivate; 450 pMse = pInfo->private; 451 452#ifdef EXTMOUSEDEBUG 453 xf86Msg(X_INFO, "VMMOUSE(0): MouseCtrl pMse=%p\n", pMse); 454#endif 455 456 pMse->num = ctrl->num; 457 pMse->den = ctrl->den; 458 pMse->threshold = ctrl->threshold; 459} 460 461 462/* 463 *---------------------------------------------------------------------- 464 * 465 * VMMouseDoPostEvent -- 466 * Post the mouse button event and mouse motion event to Xserver 467 * 468 * Results: 469 * None 470 * 471 * Side effects: 472 * Mouse location and button status was updated 473 * 474 *---------------------------------------------------------------------- 475 */ 476 477static void 478VMMouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy) 479{ 480 MouseDevPtr pMse; 481 VMMousePrivPtr mPriv; 482 int truebuttons; 483 int id, change; 484 Bool mouseMoved = FALSE; 485 486 pMse = pInfo->private; 487 mPriv = (VMMousePrivPtr)pMse->mousePriv; 488 489 /* 490 * The following truebuttons/reverseBits and lastButtons are 491 * used to compare the current buttons and the previous buttons 492 * to find the button changes during two mouse events 493 */ 494 truebuttons = buttons; 495 496 buttons = reverseBits(reverseMap, buttons); 497 498 if (mPriv->isCurrRelative) { 499 mouseMoved = dx || dy; 500 } else { 501 mouseMoved = (dx != mPriv->vmmousePrevInput.X) || 502 (dy != mPriv->vmmousePrevInput.Y) || 503 (mPriv->vmmousePrevInput.Flags & VMMOUSE_MOVE_RELATIVE); 504 } 505 if (mouseMoved) { 506 507#ifdef CALL_CONVERSION_PROC 508 /* 509 * Xservers between 1.3.99.0 - 1.4.0.90 do not call conversion_proc, so 510 * we need to do the conversion from device to screen space. 511 */ 512 VMMouseConvertProc(pInfo, 0, 2, dx, dy, 0, 0, 0, 0, &dx, &dy); 513#endif 514 xf86PostMotionEvent(pInfo->dev, !mPriv->isCurrRelative, 0, 2, dx, dy); 515 } 516 517 if (truebuttons != pMse->lastButtons) { 518 change = buttons ^ reverseBits(reverseMap, pMse->lastButtons); 519 while (change) { 520 id = ffs(change); 521 change &= ~(1 << (id - 1)); 522 xf86PostButtonEvent(pInfo->dev, 0, id, 523 (buttons & (1 << (id - 1))), 0, 0); 524 } 525 pMse->lastButtons = truebuttons; 526 } 527} 528 529 530/* 531 *---------------------------------------------------------------------- 532 * 533 * VMMousePostEvent -- 534 * Prepare the mouse status according to the Z axis mapping 535 * before we post the event to Xserver 536 * 537 * Results: 538 * None 539 * 540 * Side effects: 541 * Buttons was updated according to Z axis mapping 542 * 543 *---------------------------------------------------------------------- 544 */ 545 546static void 547VMMousePostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy, int dz, int dw) 548{ 549 MouseDevPtr pMse; 550 int zbutton = 0; 551 VMMousePrivPtr mPriv; 552 553 pMse = pInfo->private; 554 mPriv = (VMMousePrivPtr)pMse->mousePriv; 555 /* Map the Z axis movement. */ 556 /* XXX Could this go in the conversion_proc? */ 557 switch (pMse->negativeZ) { 558 case MSE_NOZMAP: /* do nothing */ 559 break; 560 case MSE_MAPTOX: 561 if (dz != 0) { 562 if(mPriv->isCurrRelative) 563 dx = dz; 564 else 565 dx += dz; 566 dz = 0; 567 } 568 break; 569 case MSE_MAPTOY: 570 if (dz != 0) { 571 if(mPriv->isCurrRelative) 572 dy = dz; 573 else 574 dy += dz; 575 dz = 0; 576 } 577 break; 578 default: /* buttons */ 579 buttons &= ~(pMse->negativeZ | pMse->positiveZ 580 | pMse->negativeW | pMse->positiveW); 581 if (dw < 0 || dz < -1) { 582 zbutton = pMse->negativeW; 583 } 584 else if (dz < 0) { 585 zbutton = pMse->negativeZ; 586 } 587 else if (dw > 0 || dz > 1) { 588 zbutton = pMse->positiveW; 589 } 590 else if (dz > 0) { 591 zbutton = pMse->positiveZ; 592 } 593 buttons |= zbutton; 594 dz = 0; 595 break; 596 } 597 598 VMMouseDoPostEvent(pInfo, buttons, dx, dy); 599 600 /* 601 * If dz has been mapped to a button `down' event, we need to cook up 602 * a corresponding button `up' event. 603 */ 604 if (zbutton) { 605 buttons &= ~zbutton; 606 if(mPriv->isCurrRelative) 607 VMMouseDoPostEvent(pInfo, buttons, 0, 0); 608 else 609 VMMouseDoPostEvent(pInfo, buttons, dx, dy); 610 } 611} 612 613 614/* 615 *---------------------------------------------------------------------- 616 * 617 * FlushButtons -- 618 * 619 * FlushButtons -- reset button states. 620 * 621 * Results: 622 * None 623 * 624 * Side effects: 625 * None 626 * 627 *---------------------------------------------------------------------- 628 */ 629 630static void 631FlushButtons(MouseDevPtr pMse) 632{ 633 pMse->lastButtons = 0; 634} 635 636 637/* 638 *---------------------------------------------------------------------- 639 * 640 * MouseCommonOptions -- 641 * Process acceptable mouse options. Currently we only process 642 * "Buttons" and "ZAxisMapping" options. 643 * More options can be added later on 644 * 645 * Results: 646 * None 647 * 648 * Side effects: 649 * The buttons was setup according to the options 650 * 651 *---------------------------------------------------------------------- 652 */ 653 654static void 655MouseCommonOptions(InputInfoPtr pInfo) 656{ 657 MouseDevPtr pMse; 658 MessageType from = X_DEFAULT; 659 char *s; 660 int origButtons; 661 662 pMse = pInfo->private; 663 664 pMse->buttons = xf86SetIntOption(pInfo->options, "Buttons", 0); 665 from = X_CONFIG; 666 if (!pMse->buttons) { 667 pMse->buttons = MSE_DFLTBUTTONS; 668 from = X_DEFAULT; 669 } 670 origButtons = pMse->buttons; 671 672 /* 673 * "emulate3Buttons" and "Drag Lock" is not supported 674 */ 675 676 /* 677 * Process option for ZAxisMapping 678 */ 679 s = xf86SetStrOption(pInfo->options, "ZAxisMapping", "4 5"); 680 if (s) { 681 int b1 = 0, b2 = 0, b3 = 0, b4 = 0; 682 char *msg = NULL; 683 684 if (!xf86NameCmp(s, "x")) { 685 pMse->negativeZ = pMse->positiveZ = MSE_MAPTOX; 686 pMse->negativeW = pMse->positiveW = MSE_MAPTOX; 687 msg = xstrdup("X axis"); 688 } else if (!xf86NameCmp(s, "y")) { 689 pMse->negativeZ = pMse->positiveZ = MSE_MAPTOY; 690 pMse->negativeW = pMse->positiveW = MSE_MAPTOY; 691 msg = xstrdup("Y axis"); 692 } else if (sscanf(s, "%d %d %d %d", &b1, &b2, &b3, &b4) >= 2 && 693 b1 > 0 && b1 <= MSE_MAXBUTTONS && 694 b2 > 0 && b2 <= MSE_MAXBUTTONS) { 695 msg = xstrdup("buttons XX and YY"); 696 if (msg) 697 sprintf(msg, "buttons %d and %d", b1, b2); 698 pMse->negativeZ = pMse->negativeW = 1 << (b1-1); 699 pMse->positiveZ = pMse->positiveW = 1 << (b2-1); 700 if (b1 > pMse->buttons) pMse->buttons = b1; 701 if (b2 > pMse->buttons) pMse->buttons = b2; 702 703 /* 704 * Option "ZAxisMapping" "N1 N2 N3 N4" not supported 705 */ 706 pMse->negativeW = pMse->positiveW = MSE_NOZMAP; 707 } else { 708 pMse->negativeZ = pMse->positiveZ = MSE_NOZMAP; 709 pMse->negativeW = pMse->positiveW = MSE_NOZMAP; 710 } 711 if (msg) { 712 xf86Msg(X_CONFIG, "%s: ZAxisMapping: %s\n", pInfo->name, msg); 713 xfree(msg); 714 } else { 715 xf86Msg(X_WARNING, "%s: Invalid ZAxisMapping value: \"%s\"\n", 716 pInfo->name, s); 717 } 718 } 719 720 /* 721 * Emulatewheel is not supported 722 */ 723 if (origButtons != pMse->buttons) 724 from = X_CONFIG; 725 726} 727 728 729/* 730 *---------------------------------------------------------------------- 731 * 732 * VMMouseUnInit -- 733 * This function was supposed to be called by Xserver to do Un-Init. 734 * But it was unused now 735 * 736 * Results: 737 * None 738 * 739 * Side effects: 740 * None 741 * 742 *---------------------------------------------------------------------- 743 */ 744 745static void 746VMMouseUnInit(InputDriverPtr drv, LocalDevicePtr local, int flags) 747{ 748 xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n"); 749} 750 751 752/* 753 *---------------------------------------------------------------------- 754 * 755 * VMMouseDeviceControl -- 756 * This function was called by Xserver during DEVICE_INIT, DEVICE_ON, 757 * DEVICE_OFF and DEVICE_CLOSE phase 758 * 759 * Results: 760 * TRUE, if sucessful 761 * FALSE, if failed 762 * 763 * Side effects: 764 * Absolute pointing device is enabled during DEVICE_ON 765 * Absolute pointing device is disabled during DEVICE_OFF 766 * and DEVICE_CLOSE 767 * 768 *---------------------------------------------------------------------- 769 */ 770 771static Bool 772VMMouseDeviceControl(DeviceIntPtr device, int mode) 773{ 774 InputInfoPtr pInfo; 775 MouseDevPtr pMse; 776 VMMousePrivPtr mPriv; 777 unsigned char map[MSE_MAXBUTTONS + 1]; 778 int i; 779 780 pInfo = device->public.devicePrivate; 781 pMse = pInfo->private; 782 pMse->device = device; 783 mPriv = (VMMousePrivPtr)pMse->mousePriv; 784 785 switch (mode){ 786 case DEVICE_INIT: 787 device->public.on = FALSE; 788 /* 789 * [KAZU-241097] We don't know exactly how many buttons the 790 * device has, so setup the map with the maximum number. 791 */ 792 for (i = 0; i < MSE_MAXBUTTONS; i++) 793 map[i + 1] = i + 1; 794 795 InitPointerDeviceStruct((DevicePtr)device, map, 796 min(pMse->buttons, MSE_MAXBUTTONS), 797#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 798 miPointerGetMotionEvents, 799#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3 800 GetMotionHistory, 801#endif 802 pMse->Ctrl, 803#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 804 miPointerGetMotionBufferSize() 805#else 806 GetMotionHistorySize(), 2 807#endif 808 ); 809 810 /* X valuator */ 811#ifdef ABS_VALUATOR_AXES 812 xf86InitValuatorAxisStruct(device, 0, 0, 65535, 10000, 0, 10000); 813#else 814 xf86InitValuatorAxisStruct(device, 0, 0, -1, 1, 0, 1); 815#endif 816 xf86InitValuatorDefaults(device, 0); 817 /* Y valuator */ 818#ifdef ABS_VALUATOR_AXES 819 xf86InitValuatorAxisStruct(device, 1, 0, 65535, 10000, 0, 10000); 820#else 821 xf86InitValuatorAxisStruct(device, 1, 0, -1, 1, 0, 1); 822#endif 823 xf86InitValuatorDefaults(device, 1); 824#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 825 xf86MotionHistoryAllocate(pInfo); 826#endif 827 828 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_INIT\n"); 829#ifdef EXTMOUSEDEBUG 830 xf86Msg(X_INFO, "assigning %p atom=%d name=%s\n", device, pInfo->atom, 831 pInfo->name); 832#endif 833 break; 834 835 case DEVICE_ON: 836 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_ON\n"); 837 pInfo->fd = xf86OpenSerial(pInfo->options); 838 if (pInfo->fd == -1) 839 xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name); 840 else { 841 pMse->buffer = XisbNew(pInfo->fd, 64); 842 if (!pMse->buffer) { 843 xf86CloseSerial(pInfo->fd); 844 pInfo->fd = -1; 845 } else { 846 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv; 847 if (mPriv != NULL) { 848 /* 849 * enable absolute pointing device here 850 */ 851 if (!VMMouseClient_Enable()) { 852 xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n"); 853 mPriv->vmmouseAvailable = FALSE; 854 device->public.on = FALSE; 855 return FALSE; 856 } else { 857 mPriv->vmmouseAvailable = TRUE; 858 xf86Msg(X_INFO, "VMWARE(0): vmmouse enabled\n"); 859 } 860 } 861 xf86FlushInput(pInfo->fd); 862 xf86AddEnabledDevice(pInfo); 863 } 864 } 865 pMse->lastButtons = 0; 866 device->public.on = TRUE; 867 FlushButtons(pMse); 868 break; 869 case DEVICE_OFF: 870 case DEVICE_CLOSE: 871 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_OFF/CLOSE\n"); 872 873 if (pInfo->fd != -1) { 874 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv; 875 if( mPriv->vmmouseAvailable ) { 876 VMMouseClient_Disable(); 877 mPriv->vmmouseAvailable = FALSE; 878 mPriv->absoluteRequested = FALSE; 879 } 880 881 xf86RemoveEnabledDevice(pInfo); 882 if (pMse->buffer) { 883 XisbFree(pMse->buffer); 884 pMse->buffer = NULL; 885 } 886 xf86CloseSerial(pInfo->fd); 887 pInfo->fd = -1; 888 } 889 device->public.on = FALSE; 890 usleep(300000); 891 break; 892 893 } 894 895 return Success; 896} 897 898 899/* 900 *---------------------------------------------------------------------- 901 * 902 * VMMouseReadInput -- 903 * This function was called by Xserver when there is data available 904 * in the input device 905 * 906 * Results: 907 * None 908 * 909 * Side effects: 910 * Input data in regular PS/2 fd was cleared 911 * Real mouse data was read from the absolute pointing device 912 * and posted to Xserver 913 * 914 *---------------------------------------------------------------------- 915 */ 916 917static void 918VMMouseReadInput(InputInfoPtr pInfo) 919{ 920 MouseDevPtr pMse; 921 VMMousePrivPtr mPriv; 922 int c; 923 int len = 0; 924 925 pMse = pInfo->private; 926 mPriv = pMse->mousePriv; 927 928 if (!mPriv->absoluteRequested) { 929 /* 930 * We can request for absolute mode, but it depends on 931 * host whether it will send us absolute or relative 932 * position. 933 */ 934 VMMouseClient_RequestAbsolute(); 935 mPriv->absoluteRequested = TRUE; 936 xf86Msg(X_INFO, "VMWARE(0): vmmouse enable absolute mode\n"); 937 } 938 939 /* 940 * First read the bytes in input device to clear the regular PS/2 fd so 941 * we don't get called again. 942 */ 943 /* 944 * Set blocking to -1 on the first call because we know there is data to 945 * read. Xisb automatically clears it after one successful read so that 946 * succeeding reads are preceeded by a select with a 0 timeout to prevent 947 * read from blocking indefinitely. 948 */ 949 XisbBlockDuration(pMse->buffer, -1); 950 while ((c = XisbRead(pMse->buffer)) >= 0) { 951 len++; 952 /* 953 * regular PS packet consists of 3 bytes 954 * We read 3 bytes to drain the PS/2 packet 955 */ 956 if(len < 3) continue; 957 len = 0; 958 /* 959 * Now get the real data from absolute pointing device 960 */ 961 GetVMMouseMotionEvent(pInfo); 962 } 963 /* 964 * There maybe still vmmouse data available 965 */ 966 GetVMMouseMotionEvent(pInfo); 967} 968 969 970/* 971 *---------------------------------------------------------------------- 972 * 973 * GetVMMouseMotionEvent -- 974 * Read all the mouse data available from the absolute 975 * pointing device and post it to the Xserver 976 * 977 * Results: 978 * None 979 * 980 * Side effects: 981 * Real mouse data was read from the absolute pointing 982 * device and posted to Xserver 983 * 984 *---------------------------------------------------------------------- 985 */ 986 987static void 988GetVMMouseMotionEvent(InputInfoPtr pInfo){ 989 MouseDevPtr pMse; 990 VMMousePrivPtr mPriv; 991 int buttons, dx, dy, dz, dw; 992 VMMOUSE_INPUT_DATA vmmouseInput; 993 int ps2Buttons = 0; 994 int numPackets; 995 996 pMse = pInfo->private; 997 mPriv = (VMMousePrivPtr)pMse->mousePriv; 998 while((numPackets = VMMouseClient_GetInput(&vmmouseInput))){ 999 if (numPackets == VMMOUSE_ERROR) { 1000 VMMouseClient_Disable(); 1001 VMMouseClient_Enable(); 1002 VMMouseClient_RequestAbsolute(); 1003 xf86Msg(X_INFO, "VMWARE(0): re-requesting absolute mode after reset\n"); 1004 break; 1005 } 1006 1007 if(vmmouseInput.Buttons & VMMOUSE_MIDDLE_BUTTON) 1008 ps2Buttons |= 0x04; /* Middle*/ 1009 if(vmmouseInput.Buttons & VMMOUSE_RIGHT_BUTTON) 1010 ps2Buttons |= 0x02; /* Right*/ 1011 if(vmmouseInput.Buttons & VMMOUSE_LEFT_BUTTON) 1012 ps2Buttons |= 0x01; /* Left*/ 1013 1014 buttons = (ps2Buttons & 0x04) >> 1 | /* Middle */ 1015 (ps2Buttons & 0x02) >> 1 | /* Right */ 1016 (ps2Buttons & 0x01) << 2; /* Left */ 1017 1018 dx = vmmouseInput.X; 1019 dy = vmmouseInput.Y; 1020 dz = (char)vmmouseInput.Z; 1021 dw = 0; 1022 /* 1023 * Get the per package relative or absolute information. 1024 */ 1025 mPriv->isCurrRelative = vmmouseInput.Flags & VMMOUSE_MOVE_RELATIVE; 1026 /* post an event */ 1027 pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw); 1028 mPriv->vmmousePrevInput = vmmouseInput; 1029 } 1030} 1031 1032 1033/* 1034 *---------------------------------------------------------------------- 1035 * 1036 * VMMouseControlProc -- 1037 * This function is unused 1038 * 1039 * Results: 1040 * None 1041 * 1042 * Side effects: 1043 * None 1044 * 1045 *---------------------------------------------------------------------- 1046 */ 1047 1048static int 1049VMMouseControlProc(LocalDevicePtr local, xDeviceCtl * control) 1050{ 1051 xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n"); 1052 return (Success); 1053} 1054 1055 1056/* 1057 *---------------------------------------------------------------------- 1058 * 1059 * VMMouseCloseProc -- 1060 * This function is unused 1061 * 1062 * Results: 1063 * None 1064 * 1065 * Side effects: 1066 * None 1067 * 1068 *---------------------------------------------------------------------- 1069 */ 1070 1071static void 1072VMMouseCloseProc(LocalDevicePtr local) 1073{ 1074 xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n"); 1075} 1076 1077 1078/* 1079 *---------------------------------------------------------------------- 1080 * 1081 * VMMouseSwitchProc -- 1082 * This function is unused 1083 * 1084 * Results: 1085 * None 1086 * 1087 * Side effects: 1088 * None 1089 * 1090 *---------------------------------------------------------------------- 1091 */ 1092 1093static int 1094VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) 1095{ 1096 xf86Msg(X_INFO, "VMWARE(0): VMMouseSwitchMode\n"); 1097 return (Success); 1098} 1099 1100 1101/* 1102 *---------------------------------------------------------------------- 1103 * 1104 * VMMouseConvertProc -- 1105 * This function was called by Xserver to convert valuators to X and Y 1106 * 1107 * Results: 1108 * TRUE 1109 * 1110 * Side effects: 1111 * X and Y was converted according to current Screen dimension 1112 * 1113 *---------------------------------------------------------------------- 1114 */ 1115 1116static Bool 1117VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2, 1118 int v3, int v4, int v5, int *x, int *y) 1119{ 1120 MouseDevPtr pMse; 1121 VMMousePrivPtr mPriv; 1122 double factorX, factorY; 1123 1124 pMse = pInfo->private; 1125 mPriv = pMse->mousePriv; 1126 1127 if (first != 0 || num != 2) 1128 return FALSE; 1129 1130 if(mPriv->isCurrRelative) { 1131 *x = v0; 1132 *y = v1; 1133 } else { 1134 factorX = ((double) screenInfo.screens[mPriv->screenNum]->width) / (double) 65535; 1135 factorY = ((double) screenInfo.screens[mPriv->screenNum]->height) / (double) 65535; 1136 1137 *x = v0 * factorX + 0.5; 1138 *y = v1 * factorY + 0.5; 1139 1140 if (mPriv->screenNum != -1) { 1141 xf86XInputSetScreen(pInfo, mPriv->screenNum, *x, *y); 1142 } 1143 } 1144 return TRUE; 1145} 1146 1147 1148#ifdef XFree86LOADER 1149ModuleInfoRec VMMouseInfo = { 1150 1, 1151 "VMMOUSE", 1152 NULL, 1153 0, 1154 VMMouseAvailableOptions, 1155}; 1156 1157 1158/* 1159 *---------------------------------------------------------------------- 1160 * 1161 * VMMouseUnplug -- 1162 * This function was called by Xserver when unplug 1163 * 1164 * Results: 1165 * None 1166 * 1167 * Side effects: 1168 * None 1169 * 1170 *---------------------------------------------------------------------- 1171 */ 1172 1173static void 1174VMMouseUnplug(pointer p) 1175{ 1176 xf86Msg(X_INFO, "VMWARE(0): VMMouseUnplug\n"); 1177} 1178 1179 1180/* 1181 *---------------------------------------------------------------------- 1182 * 1183 * VMMousePlug -- 1184 * This function was called when Xserver load vmmouse module. It will 1185 * integrate the module infto the XFree86 loader architecutre. 1186 * 1187 * Results: 1188 * TRUE 1189 * 1190 * Side effects: 1191 * Regular mouse module was loaded as a submodule. In case 1192 * absolute pointing device is not available, we can always fall back 1193 * to the regular mouse module 1194 * 1195 *---------------------------------------------------------------------- 1196 */ 1197 1198static pointer 1199VMMousePlug(pointer module, 1200 pointer options, 1201 int *errmaj, 1202 int *errmin) 1203{ 1204 static Bool Initialised = FALSE; 1205 char *name; 1206 1207 xf86LoaderReqSymLists(reqSymbols, NULL); 1208 1209 if (!Initialised) 1210 Initialised = TRUE; 1211 1212 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n"); 1213 xf86AddInputDriver(&VMMOUSE, module, 0); 1214 1215 /* 1216 * Load the normal mouse module as submodule 1217 * If we fail in PreInit later, this allows us to fall back to normal mouse module 1218 */ 1219#ifndef NORMALISE_MODULE_NAME 1220 name = xstrdup("mouse"); 1221#else 1222 /* Normalise the module name */ 1223 name = xf86NormalizeName("mouse"); 1224#endif 1225 1226 if (!LoadSubModule(module, name, NULL, NULL, NULL, NULL, errmaj, errmin)) { 1227 LoaderErrorMsg(NULL, name, *errmaj, *errmin); 1228 } 1229 xfree(name); 1230 1231 return module; 1232} 1233 1234static XF86ModuleVersionInfo VMMouseVersionRec = { 1235 "vmmouse", 1236 MODULEVENDORSTRING, 1237 MODINFOSTRING1, 1238 MODINFOSTRING2, 1239 XORG_VERSION_CURRENT, 1240 VMMOUSE_MAJOR_VERSION, VMMOUSE_MINOR_VERSION, VMMOUSE_PATCHLEVEL, 1241 ABI_CLASS_XINPUT, 1242 ABI_XINPUT_VERSION, 1243 MOD_CLASS_XINPUT, 1244 {0, 0, 0, 0} /* signature, to be patched into the file by a tool */ 1245}; 1246 1247/* 1248 * The variable contains the necessary information to load and initialize the module 1249 */ 1250XF86ModuleData vmmouseModuleData = { 1251 &VMMouseVersionRec, 1252 VMMousePlug, 1253 VMMouseUnplug 1254}; 1255#endif /* XFree86LOADER */ 1256