From 04aa141beb3f9e17ec7698f15c72ae17720370f7 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 26 Sep 2009 00:09:13 +0000 Subject: [PATCH] Adding a VMWare mouse input server filter add-on. It supports the same io port based protocol as the X vmmouse driver does. It yields proper absolute pointer positions under both the normal VMWare console and using the builtin VNC server. Therefore "fixes" the issue seen in #4630. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33298 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/input_server/filters/Jamfile | 1 + .../input_server/filters/vmware_mouse/Jamfile | 5 + .../filters/vmware_mouse/VMWareMouse.cpp | 223 ++++++++++++++++++ .../filters/vmware_mouse/VMWareMouse.h | 34 +++ .../filters/vmware_mouse/VMWareTypes.h | 63 +++++ 5 files changed, 326 insertions(+) create mode 100644 src/add-ons/input_server/filters/vmware_mouse/Jamfile create mode 100644 src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.cpp create mode 100644 src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.h create mode 100644 src/add-ons/input_server/filters/vmware_mouse/VMWareTypes.h diff --git a/src/add-ons/input_server/filters/Jamfile b/src/add-ons/input_server/filters/Jamfile index 02d1c33340..62949cc4bc 100644 --- a/src/add-ons/input_server/filters/Jamfile +++ b/src/add-ons/input_server/filters/Jamfile @@ -1,3 +1,4 @@ SubDir HAIKU_TOP src add-ons input_server filters ; SubInclude HAIKU_TOP src add-ons input_server filters screen_saver ; +SubInclude HAIKU_TOP src add-ons input_server filters vmware_mouse ; diff --git a/src/add-ons/input_server/filters/vmware_mouse/Jamfile b/src/add-ons/input_server/filters/vmware_mouse/Jamfile new file mode 100644 index 0000000000..3644d46ab4 --- /dev/null +++ b/src/add-ons/input_server/filters/vmware_mouse/Jamfile @@ -0,0 +1,5 @@ +SubDir HAIKU_TOP src add-ons input_server filters vmware_mouse ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +Addon vmware_mouse : VMWareMouse.cpp : be input_server $(TARGET_LIBSUPC++) ; diff --git a/src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.cpp b/src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.cpp new file mode 100644 index 0000000000..a6a2ff153f --- /dev/null +++ b/src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.cpp @@ -0,0 +1,223 @@ +/* + * Copyright 2009, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "VMWareMouse.h" +#include "VMWareTypes.h" + +#include +#include + +#include +#include + + +#define DEBUG_PREFIX "VMWareMouseFilter: " +#define TRACE(x...) /*syslog(DEBUG_PREFIX x)*/ +#define TRACE_ALWAYS(x...) syslog(LOG_INFO, DEBUG_PREFIX x) +#define TRACE_ERROR(x...) syslog(LOG_ERR, DEBUG_PREFIX x) + + +// #pragma mark - Public BInputServerFilter API + + +VMWareMouseFilter::VMWareMouseFilter() + : + BInputServerFilter() +{ + fIsEnabled = _Enable(); +} + + +VMWareMouseFilter::~VMWareMouseFilter() +{ + if (fIsEnabled) + _Disable(); +} + + +status_t +VMWareMouseFilter::InitCheck() +{ + if (fIsEnabled) + return B_OK; + return B_ERROR; +} + + +filter_result +VMWareMouseFilter::Filter(BMessage *message, BList *outList) +{ + if (!fIsEnabled) + return B_DISPATCH_MESSAGE; + + switch(message->what) { + case B_MOUSE_MOVED: + { + uint16 status, numWords; + _GetStatus(&status, &numWords); + if (status == VMWWARE_ERROR) { + TRACE_ERROR("error indicated when reading status, resetting\n"); + _Disable(); + fIsEnabled = _Enable(); + break; + } + + if (numWords == 0) { + // no actual data availabe, spurious event happens on fast move + return B_SKIP_MESSAGE; + } + + int32 x, y; + _GetPosition(x, y); + _ScalePosition(x, y); + + if (x < 0 || y < 0) { + TRACE_ERROR("got invalid coordinates %ld, %ld\n", x, y); + break; + } + + TRACE("setting position to %ld, %ld\n", x, y); + message->RemoveName("where"); + message->AddPoint("where", BPoint(x, y)); + break; + } + } + + return B_DISPATCH_MESSAGE; +} + + +// #pragma mark - VMWare Communication + + +void +VMWareMouseFilter::_ExecuteCommand(union packet_u &packet) +{ + packet.command.magic = VMWWARE_PORT_MAGIC; + packet.command.port = VMWWARE_PORT_NUMBER; + + int dummy; + asm volatile ( + "pushl %%ebx;" + "pushl %%eax;" + "movl 12(%%eax), %%edx;" + "movl 8(%%eax), %%ecx;" + "movl 4(%%eax), %%ebx;" + "movl (%%eax), %%eax;" + "inl %%dx, %%eax;" + "xchgl %%eax, (%%esp);" + "movl %%edx, 12(%%eax);" + "movl %%ecx, 8(%%eax);" + "movl %%ebx, 4(%%eax);" + "popl (%%eax);" + "popl %%ebx;" + : "=a"(dummy) + : "0"(&packet) + : "ecx", "edx", "memory"); +} + + +bool +VMWareMouseFilter::_Enable() +{ + union packet_u packet; + packet.command.command = VMWWARE_COMMAND_POINTER_COMMAND; + packet.command.value = VMWWARE_VALUE_READ_ID; + _ExecuteCommand(packet); + + uint16 numWords; + _GetStatus(NULL, &numWords); + if (numWords == 0) { + TRACE_ERROR("didn't get back data on reading version id\n"); + return false; + } + + packet.command.command = VMWWARE_COMMAND_POINTER_DATA; + packet.command.value = 1; // read size, 1 word + _ExecuteCommand(packet); + + if (packet.version.version != VMWWARE_VERSION_ID) { + TRACE_ERROR("got back unexpected version 0x%08lx\n", + packet.version.version); + return false; + } + + // request absolute data + packet.command.command = VMWWARE_COMMAND_POINTER_COMMAND; + packet.command.value = VMWWARE_VALUE_REQUEST_ABSOLUTE; + _ExecuteCommand(packet); + + TRACE_ALWAYS("successfully enabled\n"); + return true; +} + + +void +VMWareMouseFilter::_Disable() +{ + union packet_u packet; + packet.command.command = VMWWARE_COMMAND_POINTER_COMMAND; + packet.command.value = VMWWARE_VALUE_DISABLE; + _ExecuteCommand(packet); + + uint16 status; + _GetStatus(&status, NULL); + if (status != VMWWARE_ERROR) { + TRACE_ERROR("didn't get expected status value after disabling\n"); + return; + } + + TRACE_ALWAYS("successfully disabled\n"); +} + + +void +VMWareMouseFilter::_GetStatus(uint16 *status, uint16 *numWords) +{ + union packet_u packet; + packet.command.command = VMWWARE_COMMAND_POINTER_STATUS; + packet.command.value = 0; + _ExecuteCommand(packet); + + if (status != NULL) + *status = packet.status.status; + if (numWords != NULL) + *numWords = packet.status.num_words; +} + + +void +VMWareMouseFilter::_GetPosition(int32 &x, int32 &y) +{ + union packet_u packet; + packet.command.command = VMWWARE_COMMAND_POINTER_DATA; + packet.command.value = 4; // read size, 4 words + _ExecuteCommand(packet); + x = packet.data.x; + y = packet.data.y; +} + + +void +VMWareMouseFilter::_ScalePosition(int32 &x, int32 &y) +{ + static BScreen screen; + BRect frame = screen.Frame(); + x = (int32)(x * (frame.Width() / 65535) + 0.5); + y = (int32)(y * (frame.Height() / 65535) + 0.5); +} + + +// #pragma mark - Instatiation Entry Point + + +extern "C" +BInputServerFilter *instantiate_input_filter() +{ + return new (std::nothrow) VMWareMouseFilter(); +} diff --git a/src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.h b/src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.h new file mode 100644 index 0000000000..595ec7cb56 --- /dev/null +++ b/src/add-ons/input_server/filters/vmware_mouse/VMWareMouse.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef VMWARE_MOUSE_H +#define VMWARE_MOUSE_H + +#include + +class VMWareMouseFilter : public BInputServerFilter { +public: + VMWareMouseFilter(); +virtual ~VMWareMouseFilter(); + +virtual status_t InitCheck(); +virtual filter_result Filter(BMessage *msg, BList *outList); + +private: + void _ExecuteCommand(union packet_u &packet); + + bool _Enable(); + void _Disable(); + + void _GetStatus(uint16 *status, uint16 *numWords); + void _GetPosition(int32 &x, int32 &y); + void _ScalePosition(int32 &x, int32 &y); + + bool fIsEnabled; +}; + +#endif // VMWARE_MOUSE_H diff --git a/src/add-ons/input_server/filters/vmware_mouse/VMWareTypes.h b/src/add-ons/input_server/filters/vmware_mouse/VMWareTypes.h new file mode 100644 index 0000000000..a924793b72 --- /dev/null +++ b/src/add-ons/input_server/filters/vmware_mouse/VMWareTypes.h @@ -0,0 +1,63 @@ +/* + * Copyright 2009, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef VMWARE_TYPES_H +#define VMWARE_TYPES_H + +#define VMWWARE_PORT_MAGIC 0x564d5868 +#define VMWWARE_PORT_NUMBER 0x5658 + +#define VMWWARE_VERSION_ID 0x3442554a +#define VMWWARE_ERROR 0xffff + +#define VMWWARE_VALUE_DISABLE 0x000000f5 +#define VMWWARE_VALUE_READ_ID 0x45414552 +#define VMWWARE_VALUE_REQUEST_ABSOLUTE 0x53424152 + +#define VMWWARE_COMMAND_POINTER_DATA 39 +#define VMWWARE_COMMAND_POINTER_STATUS 40 +#define VMWWARE_COMMAND_POINTER_COMMAND 41 + + +struct command_s { + uint32 magic; + uint32 value; + uint32 command; + uint32 port; +} _PACKED; + + +struct data_s { + uint16 buttons; + uint16 flags; + int32 x; // signed when relative + int32 y; // signed when relative + int32 z; // always signed +} _PACKED; + + +struct status_s { + uint16 num_words; + uint16 status; + uint32 unused[2]; +} _PACKED; + + +struct version_s { + uint32 version; + uint32 unused[3]; +} _PACKED; + + +union packet_u { + struct command_s command; + struct data_s data; + struct status_s status; + struct version_s version; +}; + +#endif // VMWARE_TYPES_H