vmmouse.c revision 0da4cdcc
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 xf86Msg(X_INFO, "VMWARE(0): VMMouseUnInit\n"); 811} 812 813 814/* 815 *---------------------------------------------------------------------- 816 * 817 * VMMouseDeviceControl -- 818 * This function was called by Xserver during DEVICE_INIT, DEVICE_ON, 819 * DEVICE_OFF and DEVICE_CLOSE phase 820 * 821 * Results: 822 * TRUE, if sucessful 823 * FALSE, if failed 824 * 825 * Side effects: 826 * Absolute pointing device is enabled during DEVICE_ON 827 * Absolute pointing device is disabled during DEVICE_OFF 828 * and DEVICE_CLOSE 829 * 830 *---------------------------------------------------------------------- 831 */ 832 833static Bool 834VMMouseDeviceControl(DeviceIntPtr device, int mode) 835{ 836 InputInfoPtr pInfo; 837 MouseDevPtr pMse; 838 unsigned char map[MSE_MAXBUTTONS + 1]; 839 int i; 840#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 841 Atom btn_labels[MSE_MAXBUTTONS] = {0}; 842 Atom axes_labels[2] = { 0, 0 }; 843#endif 844 845 pInfo = device->public.devicePrivate; 846 pMse = pInfo->private; 847 pMse->device = device; 848 849 switch (mode){ 850 case DEVICE_INIT: 851 device->public.on = FALSE; 852 /* 853 * [KAZU-241097] We don't know exactly how many buttons the 854 * device has, so setup the map with the maximum number. 855 */ 856 for (i = 0; i < MSE_MAXBUTTONS; i++) 857 map[i + 1] = i + 1; 858#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 859 btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); 860 btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); 861 btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); 862 btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); 863 btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); 864 btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); 865 btn_labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); 866 /* other buttons are unknown */ 867 868#ifdef ABS_VALUATOR_AXES 869 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); 870 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); 871#else 872 axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); 873 axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); 874#endif /* ABS_VALUATOR_AXES */ 875#endif 876 877 InitPointerDeviceStruct((DevicePtr)device, map, 878 min(pMse->buttons, MSE_MAXBUTTONS), 879#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 880 btn_labels, 881#endif 882#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 883 miPointerGetMotionEvents, 884#elif GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3 885 GetMotionHistory, 886#endif 887 pMse->Ctrl, 888#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 889 miPointerGetMotionBufferSize() 890#else 891 GetMotionHistorySize(), 2 892#endif 893#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 894 , axes_labels 895#endif 896 ); 897 898 /* X valuator */ 899#ifdef ABS_VALUATOR_AXES 900 xf86InitValuatorAxisStruct(device, 0, 901#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 902 axes_labels[0], 903#endif 904 0, 65535, 10000, 0, 10000 905#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12 906 , Absolute 907#endif 908 ); 909#else 910 xf86InitValuatorAxisStruct(device, 0, 911#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 912 axes_labels[0], 913#endif 914 0, -1, 1, 0, 1 915#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12 916 , Relative 917#endif 918 ); 919#endif 920 xf86InitValuatorDefaults(device, 0); 921 /* Y valuator */ 922#ifdef ABS_VALUATOR_AXES 923 xf86InitValuatorAxisStruct(device, 1, 924#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 925 axes_labels[1], 926#endif 927 0, 65535, 10000, 0, 10000 928#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12 929 , Absolute 930#endif 931 ); 932#else 933 xf86InitValuatorAxisStruct(device, 1, 934#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 935 axes_labels[1], 936#endif 937 0, -1, 1, 0, 1 938#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12 939 , Relative 940#endif 941 ); 942#endif 943 xf86InitValuatorDefaults(device, 1); 944#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) == 0 945 xf86MotionHistoryAllocate(pInfo); 946#endif 947 948 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_INIT\n"); 949#ifdef EXTMOUSEDEBUG 950 xf86Msg(X_INFO, "assigning %p atom=%d name=%s\n", device, pInfo->atom, 951 pInfo->name); 952#endif 953 break; 954 955 case DEVICE_ON: 956 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_ON\n"); 957 pInfo->fd = xf86OpenSerial(pInfo->options); 958 if (pInfo->fd == -1) 959 xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name); 960 else { 961 pMse->buffer = XisbNew(pInfo->fd, 64); 962 if (!pMse->buffer) { 963 xf86CloseSerial(pInfo->fd); 964 pInfo->fd = -1; 965 } else { 966 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv; 967 if (mPriv != NULL) { 968 /* 969 * enable absolute pointing device here 970 */ 971 if (!VMMouseClient_Enable()) { 972 xf86Msg(X_ERROR, "VMWARE(0): vmmouse enable failed\n"); 973 mPriv->vmmouseAvailable = FALSE; 974 device->public.on = FALSE; 975 return FALSE; 976 } else { 977 mPriv->vmmouseAvailable = TRUE; 978 xf86Msg(X_INFO, "VMWARE(0): vmmouse enabled\n"); 979 } 980 } 981 xf86FlushInput(pInfo->fd); 982 xf86AddEnabledDevice(pInfo); 983 } 984 } 985 pMse->lastButtons = 0; 986 device->public.on = TRUE; 987 FlushButtons(pMse); 988 break; 989 case DEVICE_OFF: 990 case DEVICE_CLOSE: 991 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE DEVICE_OFF/CLOSE\n"); 992 993 if (pInfo->fd != -1) { 994 VMMousePrivPtr mPriv = (VMMousePrivPtr)pMse->mousePriv; 995 if( mPriv->vmmouseAvailable ) { 996 VMMouseClient_Disable(); 997 mPriv->vmmouseAvailable = FALSE; 998 mPriv->absoluteRequested = FALSE; 999 } 1000 1001 xf86RemoveEnabledDevice(pInfo); 1002 if (pMse->buffer) { 1003 XisbFree(pMse->buffer); 1004 pMse->buffer = NULL; 1005 } 1006 xf86CloseSerial(pInfo->fd); 1007 pInfo->fd = -1; 1008 } 1009 device->public.on = FALSE; 1010 usleep(300000); 1011 break; 1012 1013 } 1014 1015 return Success; 1016} 1017 1018 1019/* 1020 *---------------------------------------------------------------------- 1021 * 1022 * VMMouseReadInput -- 1023 * This function was called by Xserver when there is data available 1024 * in the input device 1025 * 1026 * Results: 1027 * None 1028 * 1029 * Side effects: 1030 * Input data in regular PS/2 fd was cleared 1031 * Real mouse data was read from the absolute pointing device 1032 * and posted to Xserver 1033 * 1034 *---------------------------------------------------------------------- 1035 */ 1036 1037static void 1038VMMouseReadInput(InputInfoPtr pInfo) 1039{ 1040 MouseDevPtr pMse; 1041 VMMousePrivPtr mPriv; 1042 int c; 1043 int len = 0; 1044 1045 pMse = pInfo->private; 1046 mPriv = pMse->mousePriv; 1047 1048 if (!mPriv->absoluteRequested) { 1049 /* 1050 * We can request for absolute mode, but it depends on 1051 * host whether it will send us absolute or relative 1052 * position. 1053 */ 1054 VMMouseClient_RequestAbsolute(); 1055 mPriv->absoluteRequested = TRUE; 1056 LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): vmmouse enable absolute mode\n"); 1057 } 1058 1059 /* 1060 * First read the bytes in input device to clear the regular PS/2 fd so 1061 * we don't get called again. 1062 */ 1063 /* 1064 * Set blocking to -1 on the first call because we know there is data to 1065 * read. Xisb automatically clears it after one successful read so that 1066 * succeeding reads are preceeded by a select with a 0 timeout to prevent 1067 * read from blocking indefinitely. 1068 */ 1069 XisbBlockDuration(pMse->buffer, -1); 1070 while ((c = XisbRead(pMse->buffer)) >= 0) { 1071 len++; 1072 /* 1073 * regular PS packet consists of 3 bytes 1074 * We read 3 bytes to drain the PS/2 packet 1075 */ 1076 if(len < 3) continue; 1077 len = 0; 1078 /* 1079 * Now get the real data from absolute pointing device 1080 */ 1081 GetVMMouseMotionEvent(pInfo); 1082 } 1083 /* 1084 * There maybe still vmmouse data available 1085 */ 1086 GetVMMouseMotionEvent(pInfo); 1087} 1088 1089 1090/* 1091 *---------------------------------------------------------------------- 1092 * 1093 * GetVMMouseMotionEvent -- 1094 * Read all the mouse data available from the absolute 1095 * pointing device and post it to the Xserver 1096 * 1097 * Results: 1098 * None 1099 * 1100 * Side effects: 1101 * Real mouse data was read from the absolute pointing 1102 * device and posted to Xserver 1103 * 1104 *---------------------------------------------------------------------- 1105 */ 1106 1107static void 1108GetVMMouseMotionEvent(InputInfoPtr pInfo){ 1109 MouseDevPtr pMse; 1110 VMMousePrivPtr mPriv; 1111 int buttons, dx, dy, dz, dw; 1112 VMMOUSE_INPUT_DATA vmmouseInput; 1113 int numPackets; 1114 1115 pMse = pInfo->private; 1116 mPriv = (VMMousePrivPtr)pMse->mousePriv; 1117 while((numPackets = VMMouseClient_GetInput(&vmmouseInput))){ 1118 int ps2Buttons = 0; 1119 if (numPackets == VMMOUSE_ERROR) { 1120 VMMouseClient_Disable(); 1121 VMMouseClient_Enable(); 1122 VMMouseClient_RequestAbsolute(); 1123 LogMessageVerbSigSafe(X_INFO, -1, "VMWARE(0): re-requesting absolute mode after reset\n"); 1124 break; 1125 } 1126 1127 if(vmmouseInput.Buttons & VMMOUSE_MIDDLE_BUTTON) 1128 ps2Buttons |= 0x04; /* Middle*/ 1129 if(vmmouseInput.Buttons & VMMOUSE_RIGHT_BUTTON) 1130 ps2Buttons |= 0x02; /* Right*/ 1131 if(vmmouseInput.Buttons & VMMOUSE_LEFT_BUTTON) 1132 ps2Buttons |= 0x01; /* Left*/ 1133 1134 buttons = (ps2Buttons & 0x04) >> 1 | /* Middle */ 1135 (ps2Buttons & 0x02) >> 1 | /* Right */ 1136 (ps2Buttons & 0x01) << 2; /* Left */ 1137 1138 dx = vmmouseInput.X; 1139 dy = vmmouseInput.Y; 1140 dz = (char)vmmouseInput.Z; 1141 dw = 0; 1142 /* 1143 * Get the per package relative or absolute information. 1144 */ 1145 mPriv->isCurrRelative = vmmouseInput.Flags & VMMOUSE_MOVE_RELATIVE; 1146 /* post an event */ 1147 pMse->PostEvent(pInfo, buttons, dx, dy, dz, dw); 1148 mPriv->vmmousePrevInput = vmmouseInput; 1149 } 1150} 1151 1152 1153/* 1154 *---------------------------------------------------------------------- 1155 * 1156 * VMMouseControlProc -- 1157 * This function is unused 1158 * 1159 * Results: 1160 * None 1161 * 1162 * Side effects: 1163 * None 1164 * 1165 *---------------------------------------------------------------------- 1166 */ 1167 1168static int 1169VMMouseControlProc(InputInfoPtr pInfo, xDeviceCtl * control) 1170{ 1171 xf86Msg(X_INFO, "VMWARE(0): VMMouseControlProc\n"); 1172 return (Success); 1173} 1174 1175 1176/* 1177 *---------------------------------------------------------------------- 1178 * 1179 * VMMouseCloseProc -- 1180 * This function is unused 1181 * 1182 * Results: 1183 * None 1184 * 1185 * Side effects: 1186 * None 1187 * 1188 *---------------------------------------------------------------------- 1189 */ 1190 1191#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 1192static void 1193VMMouseCloseProc(InputInfoPtr pInfo) 1194{ 1195 xf86Msg(X_INFO, "VMWARE(0): VMMouseCloseProc\n"); 1196} 1197#endif 1198 1199 1200/* 1201 *---------------------------------------------------------------------- 1202 * 1203 * VMMouseSwitchProc -- 1204 * This function is unused 1205 * 1206 * Results: 1207 * None 1208 * 1209 * Side effects: 1210 * None 1211 * 1212 *---------------------------------------------------------------------- 1213 */ 1214 1215static int 1216VMMouseSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) 1217{ 1218 xf86Msg(X_INFO, "VMWARE(0): VMMouseSwitchMode\n"); 1219 return (Success); 1220} 1221 1222 1223/* 1224 *---------------------------------------------------------------------- 1225 * 1226 * VMMouseConvertProc -- 1227 * This function was called by Xserver to convert valuators to X and Y 1228 * 1229 * Results: 1230 * TRUE 1231 * 1232 * Side effects: 1233 * X and Y was converted according to current Screen dimension 1234 * 1235 *---------------------------------------------------------------------- 1236 */ 1237 1238#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 12 1239static Bool 1240VMMouseConvertProc(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2, 1241 int v3, int v4, int v5, int *x, int *y) 1242{ 1243 MouseDevPtr pMse; 1244 VMMousePrivPtr mPriv; 1245 double factorX, factorY; 1246 1247 pMse = pInfo->private; 1248 mPriv = pMse->mousePriv; 1249 1250 if (first != 0 || num != 2) 1251 return FALSE; 1252 1253 if(mPriv->isCurrRelative) { 1254 *x = v0; 1255 *y = v1; 1256 } else { 1257 factorX = ((double) screenInfo.screens[mPriv->screenNum]->width) / (double) 65535; 1258 factorY = ((double) screenInfo.screens[mPriv->screenNum]->height) / (double) 65535; 1259 1260 *x = v0 * factorX + 0.5; 1261 *y = v1 * factorY + 0.5; 1262 1263 if (mPriv->screenNum != -1) { 1264 xf86XInputSetScreen(pInfo, mPriv->screenNum, *x, *y); 1265 } 1266 } 1267 return TRUE; 1268} 1269#endif 1270 1271 1272#ifdef XFree86LOADER 1273 1274/* 1275 *---------------------------------------------------------------------- 1276 * 1277 * VMMouseUnplug -- 1278 * This function was called by Xserver when unplug 1279 * 1280 * Results: 1281 * None 1282 * 1283 * Side effects: 1284 * None 1285 * 1286 *---------------------------------------------------------------------- 1287 */ 1288 1289static void 1290VMMouseUnplug(pointer p) 1291{ 1292 xf86Msg(X_INFO, "VMWARE(0): VMMouseUnplug\n"); 1293} 1294 1295 1296/* 1297 *---------------------------------------------------------------------- 1298 * 1299 * VMMousePlug -- 1300 * This function was called when Xserver load vmmouse module. It will 1301 * integrate the module infto the XFree86 loader architecutre. 1302 * 1303 * Results: 1304 * TRUE 1305 * 1306 * Side effects: 1307 * Regular mouse module was loaded as a submodule. In case 1308 * absolute pointing device is not available, we can always fall back 1309 * to the regular mouse module 1310 * 1311 *---------------------------------------------------------------------- 1312 */ 1313 1314static pointer 1315VMMousePlug(pointer module, 1316 pointer options, 1317 int *errmaj, 1318 int *errmin) 1319{ 1320 static Bool Initialised = FALSE; 1321 1322#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 7 1323 xf86LoaderReqSymLists(reqSymbols, NULL); 1324#endif 1325 1326 if (!Initialised) 1327 Initialised = TRUE; 1328 1329 xf86Msg(X_INFO, "VMWARE(0): VMMOUSE module was loaded\n"); 1330 xf86AddInputDriver(&VMMOUSE, module, 0); 1331 1332#ifndef NO_MOUSE_MODULE 1333{ 1334 char *name; 1335 /* 1336 * Load the normal mouse module as submodule 1337 * If we fail in PreInit later, this allows us to fall back to normal mouse module 1338 */ 1339#ifndef NORMALISE_MODULE_NAME 1340 name = xstrdup("mouse"); 1341#else 1342 /* Normalise the module name */ 1343 name = xf86NormalizeName("mouse"); 1344#endif 1345 1346 if (!LoadSubModule(module, name, NULL, NULL, NULL, NULL, errmaj, errmin)) { 1347 LoaderErrorMsg(NULL, name, *errmaj, *errmin); 1348 } 1349 free(name); 1350} 1351#endif 1352 1353 return module; 1354} 1355 1356static XF86ModuleVersionInfo VMMouseVersionRec = { 1357 "vmmouse", 1358 MODULEVENDORSTRING, 1359 MODINFOSTRING1, 1360 MODINFOSTRING2, 1361 XORG_VERSION_CURRENT, 1362 PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, 1363 ABI_CLASS_XINPUT, 1364 ABI_XINPUT_VERSION, 1365 MOD_CLASS_XINPUT, 1366 {0, 0, 0, 0} /* signature, to be patched into the file by a tool */ 1367}; 1368 1369/* 1370 * The variable contains the necessary information to load and initialize the module 1371 */ 1372_X_EXPORT XF86ModuleData vmmouseModuleData = { 1373 &VMMouseVersionRec, 1374 VMMousePlug, 1375 VMMouseUnplug 1376}; 1377#endif /* XFree86LOADER */ 1378