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