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