aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2022-02-27 17:40:45 +0100
committerJavier <dev.git@javispedro.com>2022-02-27 18:28:02 +0100
commitdee9ca901fd3f2edec7af8f82300257b285067b0 (patch)
tree04907d71f81b80de8e8ccff4373fba13fa3a93b4
downloadvbmouse-dee9ca901fd3f2edec7af8f82300257b285067b0.tar.gz
vbmouse-dee9ca901fd3f2edec7af8f82300257b285067b0.zip
initial import
-rw-r--r--.gitignore5
-rw-r--r--README.md56
-rw-r--r--makefile26
-rw-r--r--mousew16.c215
-rw-r--r--mousew16.h53
-rw-r--r--oemsetup.inf8
-rw-r--r--pci.h122
-rw-r--r--ps2.h124
-rw-r--r--vbmouse.lnk9
-rw-r--r--vbox.c239
-rw-r--r--vbox.h73
-rw-r--r--vboxdev.h495
12 files changed, 1425 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0fd4460
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+vbmouse.drv
+vbmouse.map
+vbmouse.flp
+*.o
+runvm.sh
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d26c58f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,56 @@
+This is a mouse driver for Windows 3.x with VirtualBox mouse integration support.
+
+I have tested it with Windows 3.0 in real and 386 enhanced modes, as well as Windows 3.11 in 386 enhanced mode.
+
+# Install
+
+Just copy vbmouse.drv to your WINDOWS\SYSTEM directory and edit WINDOWS\SYSTEM.INI 's mouse.drv line to point to it, e.g.
+
+ [boot]
+ mouse.drv = vbmouse.drv
+
+For a "proper" installation, you may create a floppy image containing oemsetup.inf and vbmouse.drv
+and point the Windows Setup program to it when it asks for a 3rd party mouse driver disk.
+
+# Building
+
+This requires [http://open-watcom.github.io/](OpenWatcom 2.0), albeit it may work with an older version,
+and was only tested on a Linux host.
+
+The included makefile is a wmake makefile. To build it just enter the OpenWatcom environment and run `wmake vbmouse.drv`.
+`wmake flp` may be used to build a floppy image containg oemsetup.inf and vbmouse.drv for easier installation.
+
+# Design
+
+This is at its core a driver for a plain PS/2 mouse driver, using the PS/2 BIOS.
+If running outside VirtualBox, in fact it will behave like a PS/2 mouse driver.
+However, it removes a lot of checks for older platforms and is mostly written in C rather than assembly,
+so hopefully it is easier to understand than the Windows sample drivers.
+
+The VirtualBox guest integrations present itself as a PCI device to the guest.
+Thanks to the BIOS, the device is already pre-configured.
+The driver uses the real-mode PCI BIOS to request the current configuration of this PCI device.
+To communicate with the host, the guest must send the PCI device the (physical) address
+of a buffer containing commands to be sent to the host.
+The host will write back the response in the same buffer.
+Further details are available in [https://wiki.osdev.org/VirtualBox_Guest_Additions](OSDev).
+The only challenge here is getting the physical address from inside 386 protected mode Windows,
+but turns out this can be done with the `GetSelectorBase()` WINAPI.
+
+When VirtualBox is told that the guest wants absolute mouse information, VirtualBox will stop sending
+relative mouse information via the PS/2 mouse. However, the PS/2 controller will still send interrupts
+whenever mouse motion happens, and it will still report mouse button presses. In fact, the only way
+to obtain mouse button presses is still through the PS/2 controller.
+Thus, the only difference between this driver and a standard PS/2 mouse driver is that,
+when an interrupt from the mouse comes in, we won't report the relative mouse motion to Windows.
+Rather, we call into VirtualBox (right from the PS/2 BIOS interrupt handler)
+to obtain the absolution mouse position, and report that to Windows.
+
+### Known issues
+
+Unfortunately, when a MS-DOS old application is foregrounded full-screen, this mouse driver will remain active,
+and therefore VirtualBox will not send relative motion data via the PS/2 protocol.
+This means full-screen MS-DOS programs will see a PS/2 mouse and will receive button presses from it, but will not
+receive mouse motion. The driver would need to deactivative itself in response to a full-screen MS-DOS VM, perhaps
+by hooking interrupt 2Fh function 4002h (Notify Foreground Switch) or the like.
+
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..1366864
--- /dev/null
+++ b/makefile
@@ -0,0 +1,26 @@
+# This is an Open Watcom wmake makefile, not GNU make.
+# Assuming you have sourced `owsetenv` beforehand.
+
+.BEFORE:
+ # We need DOS and Windows headers, not host platform's
+ set include=$(%watcom)/h/win;$(%watcom)/h
+
+# The main driver file
+vbmouse.drv: mousew16.c mousew16.h vbox.c vbox.h vboxdev.h ps2.h pci.h
+ # -bd to build DLL
+ # -mc to use compact memory model (far data pointers, since ss != ds)
+ # -zu for DLL calling convention (ss != ds)
+ # -zc put constants on the code segment (cs)
+ # -s to disable stack checks, since the runtime uses MessageBox() to abort (which we can't call from mouse.drv)
+ wcl -6 -mc -bd -zu -zc -s -bt=windows -l=windows_dll @vbmouse.lnk -fe=$^@ mousew16.c vbox.c
+
+clean: .SYMBOLIC
+ rm -f vbmouse.drv vbmouse.flp *.o
+
+vbmouse.flp:
+ mformat -C -f 1440 -v VBMOUSE -i $^@ ::
+
+# Build a floppy image containing the driver
+flp: vbmouse.flp vbmouse.drv oemsetup.inf .SYMBOLIC
+ mcopy -i vbmouse.flp -o oemsetup.inf vbmouse.drv ::
+
diff --git a/mousew16.c b/mousew16.c
new file mode 100644
index 0000000..94bd309
--- /dev/null
+++ b/mousew16.c
@@ -0,0 +1,215 @@
+/*
+ * VBMouse - win16 mouse driver entry points
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <windows.h>
+
+#include "vbox.h"
+#include "vboxdev.h"
+#include "ps2.h"
+#include "mousew16.h"
+
+/** If this is 0, this should behave like a plain PS/2 mouse driver. */
+#define ENABLE_VBOX 1
+
+/** Logging through the virtualbox backdoor. */
+#define log(...) vbox_logs(__VA_ARGS__)
+
+#define MOUSE_NUM_BUTTONS 2
+
+/** The routine Windows gave us which we should use to report events. */
+static LPFN_MOUSEEVENT eventproc;
+/** Current status of the mouse driver (see MOUSEFLAGS_*). */
+static unsigned char mouseflags;
+enum {
+ MOUSEFLAGS_ENABLED = 1 << 0,
+ MOUSEFLAGS_HAS_VBOX = 1 << 1,
+ MOUSEFLAGS_VBOX_ENABLED = 1 << 2,
+};
+/** Last received pressed button status (to compare and see which buttons have been pressed). */
+static unsigned char mousebtnstatus;
+
+/* This is how events are delivered to Windows */
+
+static void send_event(unsigned short Status, short deltaX, short deltaY, short ButtonCount, short extra1, short extra2);
+#pragma aux (MOUSEEVENTPROC) send_event = \
+ "call dword ptr [eventproc]"
+
+/* PS/2 BIOS mouse callback. */
+
+#pragma code_seg ( "CALLBACKS" )
+static void FAR ps2_mouse_callback(uint8_t status, uint8_t x, uint8_t y, uint8_t z)
+{
+#pragma aux (PS2_CB) ps2_mouse_callback
+
+ int sstatus = 0;
+ int sx = status & PS2M_STATUS_X_NEG ? 0xFF00 | x : x;
+ int sy = -(status & PS2M_STATUS_Y_NEG ? 0xFF00 | y : y);
+
+ if (!(mouseflags & MOUSEFLAGS_ENABLED)) {
+ // Likely eventproc is invalid
+ return;
+ }
+
+ if (sx || sy) {
+ sstatus |= SF_MOVEMENT;
+ }
+
+#if ENABLE_VBOX
+ if ((sstatus & SF_MOVEMENT) && (mouseflags & MOUSEFLAGS_VBOX_ENABLED)) {
+ bool abs;
+ uint16_t vbx, vby;
+ // Even if we are connected to VBox, the user may have selected to disable abs positioning
+ // So only report abs coordinates if it is still enabled.
+ if (vbox_get_mouse_locked(&abs, &vbx, &vby) == 0 && abs) {
+ sx = vbx;
+ sy = vby;
+ sstatus |= SF_ABSOLUTE;
+ }
+ }
+#endif
+
+ // Now proceed to see which buttons have been pressed down and/or released
+ if ((mousebtnstatus & PS2M_STATUS_BUTTON_1) && !(status & PS2M_STATUS_BUTTON_1)) {
+ sstatus |= SF_B1_UP;
+ } else if (!(mousebtnstatus & PS2M_STATUS_BUTTON_1) && (status & PS2M_STATUS_BUTTON_1)) {
+ sstatus |= SF_B1_DOWN;
+ }
+
+ if ((mousebtnstatus & PS2M_STATUS_BUTTON_2) && !(status & PS2M_STATUS_BUTTON_2)) {
+ sstatus |= SF_B2_UP;
+ } else if (!(mousebtnstatus & PS2M_STATUS_BUTTON_2) && (status & PS2M_STATUS_BUTTON_2)) {
+ sstatus |= SF_B2_DOWN;
+ }
+
+ mousebtnstatus = status & (PS2M_STATUS_BUTTON_1 | PS2M_STATUS_BUTTON_2);
+
+ if (sstatus) {
+ send_event(sstatus, sx, sy, MOUSE_NUM_BUTTONS, 0, 0);
+ }
+}
+
+#pragma code_seg ()
+
+/* Driver exported functions. */
+
+/** DLL entry point (or driver initialization routine).
+ * The initialization routine should check whether a mouse exists.
+ * @return nonzero value indicates a mouse exists.
+ */
+#pragma off (unreferenced);
+BOOL FAR PASCAL LibMain(HINSTANCE hInstance, WORD wDataSegment,
+ WORD wHeapSize, LPSTR lpszCmdLine)
+#pragma pop (unreferenced);
+{
+ // We are not going to bother checking whether a PS2 mouse exists and just assume it does
+
+#if ENABLE_VBOX
+ // However we will check whether VirtualBox exists:
+ if (vbox_init() == 0) {
+ vbox_logs("VirtualBox found\n");
+ vbox_report_guest_info(VBOXOSTYPE_Win31);
+
+ // VirtualBox connection was succesful, remember that
+ mouseflags |= MOUSEFLAGS_HAS_VBOX;
+ }
+#endif
+
+ return 1;
+}
+
+/** Called by Windows to retrieve information about the mouse hardware. */
+WORD FAR PASCAL Inquire(LPMOUSEINFO lpMouseInfo)
+{
+ lpMouseInfo->msExist = 1;
+ lpMouseInfo->msRelative = mouseflags & MOUSEFLAGS_HAS_VBOX ? 0 : 1;
+ lpMouseInfo->msNumButtons = MOUSE_NUM_BUTTONS;
+ lpMouseInfo->msRate = 40;
+ return sizeof(MOUSEINFO);
+}
+
+/** Called by Windows to enable the mouse driver.
+ * @param lpEventProc Callback function to call when a mouse event happens. */
+VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc)
+{
+ cli(); // Write to far pointer may not be atomic, and we could be interrupted mid-write
+ eventproc = lpEventProc;
+ sti();
+
+ if (!(mouseflags & MOUSEFLAGS_ENABLED)) {
+ int err;
+ if ((err = ps2_init())) {
+ vbox_logs("PS2 init failure\n");
+ return;
+ }
+ if ((err = ps2_set_callback(ps2_mouse_callback))) {
+ vbox_logs("PS2 set handler failure\n");
+ return;
+ }
+ if ((err = ps2_enable(true))) {
+ vbox_logs("PS2 enable failure\n");
+ return;
+ }
+
+ vbox_logs("PS/2 Enabled!\n");
+ mouseflags |= MOUSEFLAGS_ENABLED;
+
+#if ENABLE_VBOX
+ if (mouseflags & MOUSEFLAGS_HAS_VBOX) {
+ vbox_init_callbacks();
+
+ if ((err = vbox_set_mouse(true))) {
+ vbox_logs("VBox enable failure\n");
+ vbox_deinit_callbacks();
+ return;
+ }
+
+ vbox_logs("VBOX Enabled!\n");
+ mouseflags |= MOUSEFLAGS_VBOX_ENABLED;
+ }
+#endif
+ }
+}
+
+/** Called by Windows to disable the mouse driver. */
+VOID FAR PASCAL Disable(VOID)
+{
+ if (mouseflags & MOUSEFLAGS_ENABLED) {
+ ps2_enable(false);
+ ps2_set_callback(NULL);
+ vbox_logs("PS2 Disabled!\n");
+
+ mouseflags &= ~MOUSEFLAGS_ENABLED;
+
+#if ENABLE_VBOX
+ if (mouseflags & MOUSEFLAGS_VBOX_ENABLED) {
+ vbox_set_mouse(false);
+ vbox_deinit_callbacks();
+ vbox_logs("VBOX Disabled!\n");
+ mouseflags &= ~MOUSEFLAGS_VBOX_ENABLED;
+ }
+#endif
+ }
+}
+
+/** Called by Window to retrieve the interrupt vector number used by this driver, or -1. */
+int FAR PASCAL MouseGetIntVect(VOID)
+{
+ return -1;
+}
+
diff --git a/mousew16.h b/mousew16.h
new file mode 100644
index 0000000..54b262f
--- /dev/null
+++ b/mousew16.h
@@ -0,0 +1,53 @@
+#ifndef MOUSEW16_H
+#define MOUSEW16_H
+
+/* Win16's mouse driver interface. */
+
+/** Contains information about the mouse, used by Inquire(). */
+typedef _Packed struct MOUSEINFO
+{
+ /** Whether a mouse exists. */
+ char msExist;
+ /** Whether the mouse returns absolute or relative coordinates. */
+ char msRelative;
+ /** Number of buttons. */
+ short msNumButtons;
+ /** Maximum number of events per second. */
+ short msRate;
+ // Reserved:
+ short msXThreshold;
+ short msYThreshold;
+ short msXRes;
+ short msYRes;
+ // The following are available in Windows >= 3.1 only:
+ #if 0
+ /** Specifies the COM port used, or 0 for none. */
+ short msMouseCommPort;
+ #endif
+} MOUSEINFO;
+typedef MOUSEINFO __far *LPMOUSEINFO;
+
+/** Movement occurred. */
+#define SF_MOVEMENT 0x0001
+/** Button 1 changed to down. */
+#define SF_B1_DOWN 0x0002
+/** Button 1 changed to up. */
+#define SF_B1_UP 0x0004
+/** Button 2 changed to down. */
+#define SF_B2_DOWN 0x0008
+/** Button 2 changed to up. */
+#define SF_B2_UP 0x0010
+/** Event coordinates are absolute instead of relative. */
+#define SF_ABSOLUTE 0x8000
+
+/** Driver should call this callback when there are new mouse events to report.
+ * @param Status What happened. Combination of SF_MOVEMENT, SF_ABSOLUTE, etc.
+ * @param deltaX either number of mickeys moved or absolute coordinate if SB_ABSOLUTE.
+ * @param deltaY either number of mickeys moved or absolute coordinate if SB_ABSOLUTE.
+ * @param ButtonCount number of buttons
+ * @param extra1,extra2 leave as zero
+ */
+typedef void (__far *LPFN_MOUSEEVENT)(unsigned short Status, short deltaX, short deltaY, short ButtonCount, short extra1, short extra2);
+#pragma aux MOUSEEVENTPROC parm [ax] [bx] [cx] [dx] [di] [si]
+
+#endif
diff --git a/oemsetup.inf b/oemsetup.inf
new file mode 100644
index 0000000..d78d067
--- /dev/null
+++ b/oemsetup.inf
@@ -0,0 +1,8 @@
+[data]
+ Version = "3.0"
+
+[disks]
+ 1 =., "VBMouse driver disk", disk1
+
+[pointing.device]
+ vbmouse = 1:vbmouse.drv, "VirtualBox PS/2 Mouse", x:*vmd, vbmouse
diff --git a/pci.h b/pci.h
new file mode 100644
index 0000000..265c38a
--- /dev/null
+++ b/pci.h
@@ -0,0 +1,122 @@
+/*
+ * VBMouse - PCI BIOS communication routines
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PCI_H
+#define PCI_H
+
+typedef unsigned char pcierr;
+enum {
+ PCI_SUCCESSFUL = 0,
+ PCI_GENERIC_ERROR = 1,
+ PCI_FUNC_NOT_SUPPORTED = 0x81,
+ PCI_BAD_VENDOR_ID = 0x83,
+ PCI_DEVICE_NOT_FOUND = 0x86,
+ PCI_BAD_REGISTER_NUMBER = 0x87,
+ PCI_SET_FAILED = 0x88,
+ PCI_BUFFER_TOO_SMALL = 0x89
+};
+
+typedef unsigned short pcisel;
+
+static pcierr pci_init_bios(void);
+#pragma aux pci_init_bios = \
+ "mov ax, 0xB101" \
+ "int 0x1A" \
+ "jc not_found" \
+ "cmp ah, 0" \
+ "jne not_found" \
+ "cmp edx, ' ICP'" \
+ "jne not_found" \
+ "mov ah, 0" \
+ "jmp end" \
+ "not_found: mov ah, 1" \
+ "end:" \
+ __value [ah] \
+ __modify [ax bx cx dx]
+
+static pcierr pci_find_device(pcisel *sel, unsigned short vendor_id, unsigned short dev_id, unsigned short index);
+#pragma aux pci_find_device = \
+ "mov ax, 0xB102" \
+ "int 0x1A" \
+ "jnc success" \
+ "mov ah, 1" \
+ "success: mov [es:di], bx" \
+ __parm [es di] [dx] [cx] [si] \
+ __value [ah] \
+ __modify [ax bx]
+
+/* Reading from configuration space */
+
+static pcierr pci_read_config_byte(pcisel sel, unsigned char reg, unsigned char *data);
+#pragma aux pci_read_config_byte = \
+ "mov ax, 0xB108" \
+ "int 0x1A" \
+ "mov [es:si], cl" \
+ __parm [bx] [di] [es si] \
+ __value [ah] \
+ __modify [ax cx]
+
+static pcierr pci_read_config_word(pcisel sel, unsigned char reg, unsigned short *data);
+#pragma aux pci_read_config_word = \
+ "mov ax, 0xB109" \
+ "int 0x1A" \
+ "mov [es:si], cx" \
+ __parm [bx] [di] [es si] \
+ __value [ah] \
+ __modify [ax cx]
+
+static pcierr pci_read_config_dword(pcisel sel, unsigned char reg, unsigned long *data);
+#pragma aux pci_read_config_dword = \
+ "mov ax, 0xB10A" \
+ "int 0x1A" \
+ "mov [es:si], ecx" \
+ __parm [bx] [di] [es si] \
+ __value [ah] \
+ __modify [ax cx]
+
+/* Writing to configuration space */
+
+static pcierr pci_write_config_byte(pcisel sel, unsigned char reg, unsigned char data);
+#pragma aux pci_write_config_byte = \
+ "mov ax, 0xB10B" \
+ "int 0x1A" \
+ __parm [bx] [di] [cl] \
+ __value [ah] \
+ __modify [ax]
+
+static pcierr pci_write_config_word(pcisel sel, unsigned char reg, unsigned short data);
+#pragma aux pci_write_config_word = \
+ "mov ax, 0xB10C" \
+ "int 0x1A" \
+ __parm [bx] [di] [cx] \
+ __value [ah] \
+ __modify [ax cx]
+
+static pcierr pci_write_config_dword(pcisel sel, unsigned char reg, unsigned long data);
+#pragma aux pci_write_config_dword = \
+ "mov ax, 0xB10D" \
+ "shl esi, 16" \
+ "and ecx, 0xFFFF" \
+ "or ecx, esi" \
+ "int 0x1A" \
+ __parm [bx] [di] [si cx] \
+ __value [ah] \
+ __modify [ax cx]
+
+#endif
diff --git a/ps2.h b/ps2.h
new file mode 100644
index 0000000..0ff154b
--- /dev/null
+++ b/ps2.h
@@ -0,0 +1,124 @@
+/*
+ * VBMouse - Routines to access the PS2 BIOS services
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PS2_H
+#define PS2_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+enum {
+ PS2M_STATUS_BUTTON_1 = 1 << 0,
+ PS2M_STATUS_BUTTON_2 = 1 << 1,
+ PS2M_STATUS_BUTTON_3 = 1 << 2,
+ PS2M_STATUS_X_NEG = 1 << 4,
+ PS2M_STATUS_Y_NEG = 1 << 5,
+ PS2M_STATUS_X_OVF = 1 << 6,
+ PS2M_STATUS_Y_OVF = 1 << 7,
+};
+
+#pragma aux PS2_CB far loadds parm reverse caller []
+// TODO: ax and es look not be preserved with this. VBox BIOS already preserves them though.
+
+/** Invoked by the BIOS when there is a mouse event.
+ * @param status combination of PS2M_STATUS_* flags */
+typedef void (__far * LPFN_PS2CALLBACK)(uint8_t status, uint8_t x, uint8_t y, uint8_t z);
+
+static inline void cli(void);
+#pragma aux cli = "cli"
+
+static inline void sti(void);
+#pragma aux sti = "sti"
+
+static uint8_t ps2_init(void);
+#pragma aux ps2_init = \
+ "stc" /* If nothing happens, assume failure */ \
+ "mov ax, 0xC205" /* Pointing device: initialization */ \
+ "mov bh, 3" /* Use 3 byte packets */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ax, 0xC201" /* Pointing device: reset */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ax, 0xC203" /* Pointing device: set resolution */ \
+ "mov bh, 3" /* 3 count per mm = ~ 200 ppi */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ax, 0xC202" /* Pointing device: set sample rate*/ \
+ "mov bh, 5" /* 2: 40 samples per second */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ax, 0xC206" /* Pointing device: extended commands */ \
+ "mov bh, 1" /* Set 1:1 scaling */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ah, 0" /* Success */ \
+ "jmp end" \
+ \
+ "fail: test ah, ah" /* Ensure we have some error code back, set ah to ff if we don't */ \
+ "jnz end" \
+ "mov ah, 0xFF" \
+ "end:" \
+ __value [ah] \
+ __modify [ax]
+
+static uint8_t ps2_set_callback(LPFN_PS2CALLBACK callback);
+#pragma aux ps2_set_callback = \
+ "stc" /* If nothing happens, assume failure */ \
+ "mov ax, 0xC207" /* Pointing device: set interrupt callback (in es:bx) */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ah, 0" /* Success */ \
+ "jmp end" \
+ \
+ "fail: test ah, ah" /* Ensure we have some error code back */ \
+ "jnz end" \
+ "mov ah, 0xFF" \
+ "end:" \
+ __parm [es bx] \
+ __value [ah] \
+ __modify [ax]
+
+static uint8_t ps2_enable(bool enable);
+#pragma aux ps2_enable = \
+ "test bh, bh" /* Ensure enable is either 1 or 0 */ \
+ "setnz bh" \
+ "stc" /* If nothing happens, assume failure */ \
+ "mov ax, 0xC200" /* Pointing device enable/disable (in bh) */ \
+ "int 0x15" \
+ "jc fail" \
+ \
+ "mov ah, 0" /* Success */ \
+ "jmp end" \
+ \
+ "fail: test ah, ah" /* Ensure we have some error code back */ \
+ "jnz end" \
+ "mov ah, 0xFF" \
+ "end:" \
+ __parm [bh] \
+ __value [ah] \
+ __modify [ax]
+
+#endif
diff --git a/vbmouse.lnk b/vbmouse.lnk
new file mode 100644
index 0000000..1f260ee
--- /dev/null
+++ b/vbmouse.lnk
@@ -0,0 +1,9 @@
+OPTION MODNAME=MOUSE # This is necessary; USER.EXE imports mouse functions using this module name
+OPTION DESCRIPTION 'VirtualBox Mouse driver'
+
+SEGMENT CALLBACKS FIXED SHARED # We need a non-moveable segment to store our PS/2 BIOS callbacks
+
+EXPORT Inquire.1
+EXPORT Enable.2
+EXPORT Disable.3
+EXPORT MouseGetIntVect.4
diff --git a/vbox.c b/vbox.c
new file mode 100644
index 0000000..042a470
--- /dev/null
+++ b/vbox.c
@@ -0,0 +1,239 @@
+/*
+ * VBMouse - VirtualBox communication routines
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <windows.h>
+#include <i86.h>
+
+#include "pci.h"
+#include "vboxdev.h"
+#include "vbox.h"
+
+/** VBox's PCI bus, device number, etc. */
+static pcisel vbpci;
+/** IO base of VBox's PCI device. */
+static uint16_t vbiobase;
+/** IRQ number of VBox's PCI device. Unused. */
+static uint8_t vbirq;
+
+/** Keep a pre-allocated VBox VMMDevRequest struct for the benefit of the callbacks,
+ which may be called in a IRQ handler where I'd prefer to avoid making API calls. */
+static VMMDevReqMouseStatus __far * reqMouse;
+static HANDLE reqMouseH;
+static uint32_t reqMouseAddr;
+
+/** Actually send a request to the VirtualBox VMM device.
+ * @param addr 32-bit linear address containing the VMMDevRequest struct.
+ */
+static void vbox_send_request(uint32_t addr);
+#pragma aux vbox_send_request = \
+ "movzx eax, ax" /* Need to make a single 32-bit write so combine both regs. */ \
+ "movzx ebx, bx" \
+ "shl ebx, 16" \
+ "or eax, ebx" \
+ "mov dx, vbiobase" \
+ "out dx, eax" \
+ "shr ebx, 16" \
+ __parm [bx ax] \
+ __modify [dx]
+
+/** Acknowledge an interrupt from the VirtualBox VMM device at iobase.
+ * @return bitmask with all pending events (e.g. VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED). */
+static uint32_t vbox_irq_ack();
+#pragma aux vbox_irq_ack = \
+ "mov dx, vbiobase" \
+ "add dx, 8" \
+ "in eax, dx" \
+ "mov edx, eax" \
+ "shr edx, 16" \
+ __value [dx ax] \
+
+// Classic PCI defines
+#define VBOX_PCI_VEND_ID 0x80ee
+#define VBOX_PCI_PROD_ID 0xcafe
+enum {
+ CFG_COMMAND = 0x04, /* Word */
+ CFG_INTERRUPT = 0x3C, /* Byte */
+ CFG_BAR0 = 0x10, /* DWord */
+ CFG_BAR1 = 0x14, /* DWord */
+};
+
+/** Gets the 32-bit linear address of a 16:16 far pointer.
+ Uses GetSelectorBase() since we are supposed to work under protected mode. */
+static inline uint32_t get_physical_addr(void far *obj)
+{
+ return GetSelectorBase(FP_SEG(obj)) + FP_OFF(obj);
+}
+
+/** Send a request to the VirtualBox VMM device at vbiobase.
+ * @param request must be a VMMDevRequest (e.g. VMMDevReqMouseStatus). */
+static inline void vbox_request(void far *request)
+{
+ uint32_t addr = get_physical_addr(request);
+ vbox_send_request(addr);
+}
+
+/** Finds the VirtualBox PCI device and reads the current IO base.
+ * @returns 0 if the device was found. */
+int vbox_init(void)
+{
+ int err;
+ uint16_t command;
+ uint32_t bar;
+
+ if ((err = pci_init_bios())) {
+ return -1;
+ }
+
+ if ((err = pci_find_device(&vbpci, VBOX_PCI_VEND_ID, VBOX_PCI_PROD_ID, 0))) {
+ return -1;
+ }
+
+ if ((err = pci_read_config_word(vbpci, CFG_COMMAND, &command))
+ || !(command & 1)) {
+ return -2;
+ }
+
+ if ((err = pci_read_config_byte(vbpci, CFG_INTERRUPT, &vbirq))) {
+ return -2;
+ }
+
+ if ((err = pci_read_config_dword(vbpci, CFG_BAR0, &bar))) {
+ return -2;
+ }
+
+ if (!(bar & 1)) {
+ return -2;
+ }
+
+ vbiobase = bar & 0xFFFC;
+
+ return 0;
+}
+
+/** Lets VirtualBox know that there are VirtualBox Guest Additions on this guest.
+ * @param osType os installed on this guest. */
+int vbox_report_guest_info(uint32_t osType)
+{
+ VMMDevReportGuestInfo req = {0};
+
+ req.header.size = sizeof(req);
+ req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req.header.requestType = VMMDevReq_ReportGuestInfo;
+ req.header.rc = -1;
+ req.guestInfo.interfaceVersion = VMMDEV_VERSION;
+ req.guestInfo.osType = osType;
+
+ vbox_request(&req);
+
+ return req.header.rc;
+}
+
+/** Tells VirtualBox about the events we are interested in receiving.
+ These events are notified via the PCI IRQ which we are not using, so this is not used either. */
+int vbox_set_filter_mask(uint32_t add, uint32_t remove)
+{
+ VMMDevCtlGuestFilterMask req = {0};
+
+ req.header.size = sizeof(req);
+ req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req.header.requestType = VMMDevReq_CtlGuestFilterMask;
+ req.header.rc = -1;
+ req.u32OrMask = add;
+ req.u32NotMask = remove;
+
+ vbox_request(&req);
+
+ return req.header.rc;
+}
+
+/** Tells VirtualBox whether we want absolute mouse information or not. */
+int vbox_set_mouse(bool enable)
+{
+ VMMDevReqMouseStatus req = {0};
+
+ req.header.size = sizeof(req);
+ req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req.header.requestType = VMMDevReq_SetMouseStatus;
+ req.header.rc = -1;
+ req.mouseFeatures = enable ? VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE : 0;
+
+ vbox_request(&req);
+
+ return req.header.rc;
+}
+
+/** Gets the current absolute mouse position from VirtualBox.
+ * @param abs false if user has disabled mouse integration in VirtualBox,
+ * in which case we should fallback to PS/2 relative events. */
+int vbox_get_mouse(bool *abs, uint16_t *xpos, uint16_t *ypos)
+{
+ VMMDevReqMouseStatus req = {0};
+
+ req.header.size = sizeof(req);
+ req.header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ req.header.requestType = VMMDevReq_GetMouseStatus;
+ req.header.rc = -1;
+
+ vbox_request(&req);
+
+ *abs = req.mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE;
+ *xpos = req.pointerXPos;
+ *ypos = req.pointerYPos;
+
+ return req.header.rc;
+}
+
+/** Just allocates the memory used by vbox_get_mouse_locked below. */
+void vbox_init_callbacks(void)
+{
+ reqMouseH = GlobalAlloc(GMEM_FIXED|GMEM_SHARE, sizeof(VMMDevReqMouseStatus));
+ reqMouse = (LPVOID) GlobalLock(reqMouseH);
+ reqMouseAddr = get_physical_addr(reqMouse);
+}
+
+void vbox_deinit_callbacks(void)
+{
+ GlobalFree(reqMouseH);
+ reqMouse = NULL;
+ reqMouseAddr = 0;
+}
+
+#pragma code_seg ( "CALLBACKS" )
+
+/** This is a version of vbox_get_mouse() that does not call any other functions. */
+int vbox_get_mouse_locked(bool *abs, uint16_t *xpos, uint16_t *ypos)
+{
+ // Note that this may be called with interrupts disabled
+ reqMouse->header.size = sizeof(VMMDevReqMouseStatus);
+ reqMouse->header.version = VMMDEV_REQUEST_HEADER_VERSION;
+ reqMouse->header.requestType = VMMDevReq_GetMouseStatus;
+ reqMouse->header.rc = -1;
+ reqMouse->mouseFeatures = 0;
+ reqMouse->pointerXPos = 0;
+ reqMouse->pointerYPos = 0;
+
+ vbox_send_request(reqMouseAddr);
+
+ *abs = reqMouse->mouseFeatures & VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE;
+ *xpos = reqMouse->pointerXPos;
+ *ypos = reqMouse->pointerYPos;
+
+ return reqMouse->header.rc;
+}
+
diff --git a/vbox.h b/vbox.h
new file mode 100644
index 0000000..c711dd1
--- /dev/null
+++ b/vbox.h
@@ -0,0 +1,73 @@
+/*
+ * VBMouse - VirtualBox communication routines
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef VBOX_H
+#define VBOX_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/** Logs a single character to the VBox debug message port. */
+static void vbox_logc(char c);
+#pragma aux vbox_logc = \
+ "mov dx, 0x504" \
+ "out dx, al" \
+ __parm [al] \
+ __modify [dx]
+
+/** Logs a string to the VBox debug message port. */
+static void vbox_logs(const char __far *str);
+#pragma aux vbox_logs = \
+ "mov di, si" \
+ "xor cx, cx" \
+ "not cx" /* First we have to strlen(str), prepare -1 as max length */ \
+ "xor al, al" /* The '\0' that we're searching for */ \
+ "cld" \
+ "repne scas byte ptr es:[di]" /* afterwards, cx = -(len+2) */ \
+ "not cx" /* cx = (len+1) */ \
+ "dec cx" /* cx = len */ \
+ "mov dx, 0x504" /* And now we can write the string */ \
+ "rep outs dx, byte ptr es:[si]" \
+ __parm [es si] \
+ __modify [ax cx dx si di]
+
+/** Logs a single character followed by '\n' to force log flush.
+ * A life-saver when there is no data segment available. */
+#define vbox_putc(c) do { \
+ vbox_logc(c); vbox_logc('\n'); \
+ } while (0);
+
+extern int vbox_init(void);
+
+extern int vbox_report_guest_info(uint32_t osType);
+
+extern int vbox_set_filter_mask(uint32_t add, uint32_t remove);
+
+extern int vbox_set_mouse(bool enable);
+
+extern int vbox_get_mouse(bool *abs, uint16_t *xpos, uint16_t *ypos);
+
+extern void vbox_init_callbacks();
+extern void vbox_deinit_callbacks();
+
+// In CALLBACKS segment:
+
+extern int vbox_get_mouse_locked(bool *abs, uint16_t *xpos, uint16_t *ypos);
+
+#endif
diff --git a/vboxdev.h b/vboxdev.h
new file mode 100644
index 0000000..627486f
--- /dev/null
+++ b/vboxdev.h
@@ -0,0 +1,495 @@
+/*
+ * Definitions in this file come from VirtualBox.
+ * Copyright (C) 2006-2020 Oracle Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef VBOXDEV_H
+#define VBOXDEV_H
+
+#include <stdint.h>
+
+/* Basic defines required for interoperability with VirtualBox's VMM device */
+
+#define AssertCompileSize(type, size) /**/
+#define RT_BIT(bit) ( 1U << (bit) )
+
+#define VMMDEV_VERSION 0x00010004UL
+
+/** Version of VMMDevRequestHeader structure. */
+#define VMMDEV_REQUEST_HEADER_VERSION (0x10001)
+
+/** PC port for debug output */
+#define RTLOG_DEBUG_PORT 0x504
+
+/** Port for generic request interface (relative offset). */
+#define VMMDEV_PORT_OFF_REQUEST 0
+/** Port for requests that can be handled w/o going to ring-3 (relative offset).
+ * This works like VMMDevReq_AcknowledgeEvents when read. */
+#define VMMDEV_PORT_OFF_REQUEST_FAST 8
+
+/** Version of VMMDevMemory structure (VMMDevMemory::u32Version). */
+# define VMMDEV_MEMORY_VERSION (1)
+
+/** @name VMMDev events.
+ *
+ * Used mainly by VMMDevReq_AcknowledgeEvents/VMMDevEvents and version 1.3 of
+ * VMMDevMemory.
+ *
+ * @{
+ */
+/** Host mouse capabilities has been changed. */
+#define VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED RT_BIT(0)
+/** HGCM event. */
+#define VMMDEV_EVENT_HGCM RT_BIT(1)
+/** A display change request has been issued. */
+#define VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST RT_BIT(2)
+/** Credentials are available for judgement. */
+#define VMMDEV_EVENT_JUDGE_CREDENTIALS RT_BIT(3)
+/** The guest has been restored. */
+#define VMMDEV_EVENT_RESTORED RT_BIT(4)
+/** Seamless mode state changed. */
+#define VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST RT_BIT(5)
+/** Memory balloon size changed. */
+#define VMMDEV_EVENT_BALLOON_CHANGE_REQUEST RT_BIT(6)
+/** Statistics interval changed. */
+#define VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST RT_BIT(7)
+/** VRDP status changed. */
+#define VMMDEV_EVENT_VRDP RT_BIT(8)
+/** New mouse position data available. */
+#define VMMDEV_EVENT_MOUSE_POSITION_CHANGED RT_BIT(9)
+/** CPU hotplug event occurred. */
+#define VMMDEV_EVENT_CPU_HOTPLUG RT_BIT(10)
+/** The mask of valid events, for sanity checking. */
+#define VMMDEV_EVENT_VALID_EVENT_MASK UINT32_C(0x000007ff)
+/** @} */
+
+
+/**
+ * The layout of VMMDEV RAM region that contains information for guest.
+ */
+typedef struct VMMDevMemory
+{
+ /** The size of this structure. */
+ uint32_t u32Size;
+ /** The structure version. (VMMDEV_MEMORY_VERSION) */
+ uint32_t u32Version;
+
+ union
+ {
+ struct
+ {
+ /** Flag telling that VMMDev set the IRQ and acknowlegment is required */
+ uint32_t fHaveEvents;
+ } V1_04;
+
+ struct
+ {
+ /** Pending events flags, set by host. */
+ uint32_t u32HostEvents;
+ /** Mask of events the guest wants to see, set by guest. */
+ uint32_t u32GuestEventMask;
+ } V1_03;
+ } V;
+
+ //VBVAMEMORY vbvaMemory;
+
+} VMMDevMemory;
+
+typedef enum VBOXOSTYPE
+{
+ VBOXOSTYPE_Unknown = 0,
+ VBOXOSTYPE_Unknown_x64 = 0x00100,
+ /** @name DOS and it's descendants
+ * @{ */
+ VBOXOSTYPE_DOS = 0x10000,
+ VBOXOSTYPE_Win31 = 0x15000,
+ VBOXOSTYPE_Win9x = 0x20000,
+ VBOXOSTYPE_Win95 = 0x21000,
+ VBOXOSTYPE_Win98 = 0x22000,
+ VBOXOSTYPE_WinMe = 0x23000,
+ VBOXOSTYPE_WinNT = 0x30000,
+ VBOXOSTYPE_WinNT_x64 = 0x30100,
+ VBOXOSTYPE_WinNT3x = 0x30800,
+ VBOXOSTYPE_WinNT4 = 0x31000,
+ VBOXOSTYPE_Win2k = 0x32000,
+ VBOXOSTYPE_WinXP = 0x33000,
+ VBOXOSTYPE_WinXP_x64 = 0x33100,
+ VBOXOSTYPE_Win2k3 = 0x34000,
+ VBOXOSTYPE_Win2k3_x64 = 0x34100,
+ VBOXOSTYPE_WinVista = 0x35000,
+ VBOXOSTYPE_WinVista_x64 = 0x35100,
+ VBOXOSTYPE_Win2k8 = 0x36000,
+ VBOXOSTYPE_Win2k8_x64 = 0x36100,
+ VBOXOSTYPE_Win7 = 0x37000,
+ VBOXOSTYPE_Win7_x64 = 0x37100,
+ VBOXOSTYPE_Win8 = 0x38000,
+ VBOXOSTYPE_Win8_x64 = 0x38100,
+ VBOXOSTYPE_Win2k12_x64 = 0x39100,
+ VBOXOSTYPE_Win81 = 0x3A000,
+ VBOXOSTYPE_Win81_x64 = 0x3A100,
+ VBOXOSTYPE_Win10 = 0x3B000,
+ VBOXOSTYPE_Win10_x64 = 0x3B100,
+ VBOXOSTYPE_Win2k16_x64 = 0x3C100,
+ VBOXOSTYPE_Win2k19_x64 = 0x3D100,
+ VBOXOSTYPE_Win11_x64 = 0x3E100,
+ VBOXOSTYPE_OS2 = 0x40000,
+ VBOXOSTYPE_OS2Warp3 = 0x41000,
+ VBOXOSTYPE_OS2Warp4 = 0x42000,
+ VBOXOSTYPE_OS2Warp45 = 0x43000,
+ VBOXOSTYPE_ECS = 0x44000,
+ VBOXOSTYPE_ArcaOS = 0x45000,
+ VBOXOSTYPE_OS21x = 0x48000,
+ /** @} */
+ /** @name Unixy related OSes
+ * @{ */
+ VBOXOSTYPE_Linux = 0x50000,
+ VBOXOSTYPE_Linux_x64 = 0x50100,
+ VBOXOSTYPE_Linux22 = 0x51000,
+ VBOXOSTYPE_Linux24 = 0x52000,
+ VBOXOSTYPE_Linux24_x64 = 0x52100,
+ VBOXOSTYPE_Linux26 = 0x53000,
+ VBOXOSTYPE_Linux26_x64 = 0x53100,
+ VBOXOSTYPE_ArchLinux = 0x54000,
+ VBOXOSTYPE_ArchLinux_x64 = 0x54100,
+ VBOXOSTYPE_Debian = 0x55000,
+ VBOXOSTYPE_Debian_x64 = 0x55100,
+ VBOXOSTYPE_OpenSUSE = 0x56000,
+ VBOXOSTYPE_OpenSUSE_x64 = 0x56100,
+ VBOXOSTYPE_FedoraCore = 0x57000,
+ VBOXOSTYPE_FedoraCore_x64 = 0x57100,
+ VBOXOSTYPE_Gentoo = 0x58000,
+ VBOXOSTYPE_Gentoo_x64 = 0x58100,
+ VBOXOSTYPE_Mandriva = 0x59000,
+ VBOXOSTYPE_Mandriva_x64 = 0x59100,
+ VBOXOSTYPE_RedHat = 0x5A000,
+ VBOXOSTYPE_RedHat_x64 = 0x5A100,
+ VBOXOSTYPE_Turbolinux = 0x5B000,
+ VBOXOSTYPE_Turbolinux_x64 = 0x5B100,
+ VBOXOSTYPE_Ubuntu = 0x5C000,
+ VBOXOSTYPE_Ubuntu_x64 = 0x5C100,
+ VBOXOSTYPE_Xandros = 0x5D000,
+ VBOXOSTYPE_Xandros_x64 = 0x5D100,
+ VBOXOSTYPE_Oracle = 0x5E000,
+ VBOXOSTYPE_Oracle_x64 = 0x5E100,
+ VBOXOSTYPE_FreeBSD = 0x60000,
+ VBOXOSTYPE_FreeBSD_x64 = 0x60100,
+ VBOXOSTYPE_OpenBSD = 0x61000,
+ VBOXOSTYPE_OpenBSD_x64 = 0x61100,
+ VBOXOSTYPE_NetBSD = 0x62000,
+ VBOXOSTYPE_NetBSD_x64 = 0x62100,
+ VBOXOSTYPE_Netware = 0x70000,
+ VBOXOSTYPE_Solaris = 0x80000,
+ VBOXOSTYPE_Solaris_x64 = 0x80100,
+ VBOXOSTYPE_OpenSolaris = 0x81000,
+ VBOXOSTYPE_OpenSolaris_x64 = 0x81100,
+ VBOXOSTYPE_Solaris11_x64 = 0x82100,
+ VBOXOSTYPE_L4 = 0x90000,
+ VBOXOSTYPE_QNX = 0xA0000,
+ VBOXOSTYPE_MacOS = 0xB0000,
+ VBOXOSTYPE_MacOS_x64 = 0xB0100,
+ VBOXOSTYPE_MacOS106 = 0xB2000,
+ VBOXOSTYPE_MacOS106_x64 = 0xB2100,
+ VBOXOSTYPE_MacOS107_x64 = 0xB3100,
+ VBOXOSTYPE_MacOS108_x64 = 0xB4100,
+ VBOXOSTYPE_MacOS109_x64 = 0xB5100,
+ VBOXOSTYPE_MacOS1010_x64 = 0xB6100,
+ VBOXOSTYPE_MacOS1011_x64 = 0xB7100,
+ VBOXOSTYPE_MacOS1012_x64 = 0xB8100,
+ VBOXOSTYPE_MacOS1013_x64 = 0xB9100,
+ /** @} */
+ /** @name Other OSes and stuff
+ * @{ */
+ VBOXOSTYPE_JRockitVE = 0xC0000,
+ VBOXOSTYPE_Haiku = 0xD0000,
+ VBOXOSTYPE_Haiku_x64 = 0xD0100,
+ VBOXOSTYPE_VBoxBS_x64 = 0xE0100,
+ /** @} */
+
+/** The bit number which indicates 64-bit or 32-bit. */
+#define VBOXOSTYPE_x64_BIT 8
+ /** The mask which indicates 64-bit. */
+ VBOXOSTYPE_x64 = 1 << VBOXOSTYPE_x64_BIT,
+
+ /** The usual 32-bit hack. */
+ VBOXOSTYPE_32BIT_HACK = 0x7fffffff
+} VBOXOSTYPE;
+
+typedef enum VMMDevRequestType
+{
+ VMMDevReq_InvalidRequest = 0,
+ VMMDevReq_GetMouseStatus = 1,
+ VMMDevReq_SetMouseStatus = 2,
+ VMMDevReq_SetPointerShape = 3,
+ VMMDevReq_GetHostVersion = 4,
+ VMMDevReq_Idle = 5,
+ VMMDevReq_GetHostTime = 10,
+ VMMDevReq_GetHypervisorInfo = 20,
+ VMMDevReq_SetHypervisorInfo = 21,
+ VMMDevReq_RegisterPatchMemory = 22, /**< @since version 3.0.6 */
+ VMMDevReq_DeregisterPatchMemory = 23, /**< @since version 3.0.6 */
+ VMMDevReq_SetPowerStatus = 30,
+ VMMDevReq_AcknowledgeEvents = 41,
+ VMMDevReq_CtlGuestFilterMask = 42,
+ VMMDevReq_ReportGuestInfo = 50,
+ VMMDevReq_ReportGuestInfo2 = 58, /**< @since version 3.2.0 */
+ VMMDevReq_ReportGuestStatus = 59, /**< @since version 3.2.8 */
+ VMMDevReq_ReportGuestUserState = 74, /**< @since version 4.3 */
+ VMMDevReq_SizeHack = 0x7fffffff
+} VMMDevRequestType;
+
+typedef struct VMMDevRequestHeader
+{
+ /** IN: Size of the structure in bytes (including body).
+ * (VBGLREQHDR uses this for input size and output if reserved1 is zero). */
+ uint32_t size;
+ /** IN: Version of the structure. */
+ uint32_t version;
+ /** IN: Type of the request.
+ * @note VBGLREQHDR uses this for optional output size. */
+ VMMDevRequestType requestType;
+ /** OUT: VBox status code. */
+ int32_t rc;
+ /** Reserved field no.1. MBZ.
+ * @note VBGLREQHDR uses this for optional output size, however never for a
+ * real VMMDev request, only in the I/O control interface. */
+ uint32_t reserved1;
+ /** IN: Requestor information (VMMDEV_REQUESTOR_XXX) when
+ * VBOXGSTINFO2_F_REQUESTOR_INFO is set, otherwise ignored by the host. */
+ uint32_t fRequestor;
+} VMMDevRequestHeader;
+
+/**
+ * Mouse status request structure.
+ *
+ * Used by VMMDevReq_GetMouseStatus and VMMDevReq_SetMouseStatus.
+ */
+typedef struct
+{
+ /** header */
+ VMMDevRequestHeader header;
+ /** Mouse feature mask. See VMMDEV_MOUSE_*. */
+ uint32_t mouseFeatures;
+ /** Mouse x position. */
+ int32_t pointerXPos;
+ /** Mouse y position. */
+ int32_t pointerYPos;
+} VMMDevReqMouseStatus;
+AssertCompileSize(VMMDevReqMouseStatus, 24+12);
+
+/** @name Mouse capability bits (VMMDevReqMouseStatus::mouseFeatures).
+ * @{ */
+/** The guest can (== wants to) handle absolute coordinates. */
+#define VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE RT_BIT(0)
+/** The host can (== wants to) send absolute coordinates.
+ * (Input not captured.) */
+#define VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE RT_BIT(1)
+/** The guest can *NOT* switch to software cursor and therefore depends on the
+ * host cursor.
+ *
+ * When guest additions are installed and the host has promised to display the
+ * cursor itself, the guest installs a hardware mouse driver. Don't ask the
+ * guest to switch to a software cursor then. */
+#define VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR RT_BIT(2)
+/** The host does NOT provide support for drawing the cursor itself. */
+#define VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER RT_BIT(3)
+/** The guest can read VMMDev events to find out about pointer movement */
+#define VMMDEV_MOUSE_NEW_PROTOCOL RT_BIT(4)
+/** If the guest changes the status of the
+ * VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR bit, the host will honour this */
+#define VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR RT_BIT(5)
+/** The host supplies an absolute pointing device. The Guest Additions may
+ * wish to use this to decide whether to install their own driver */
+#define VMMDEV_MOUSE_HOST_HAS_ABS_DEV RT_BIT(6)
+/** The mask of all VMMDEV_MOUSE_* flags */
+#define VMMDEV_MOUSE_MASK UINT32_C(0x0000007f)
+/** The mask of guest capability changes for which notification events should
+ * be sent */
+#define VMMDEV_MOUSE_NOTIFY_HOST_MASK \
+ (VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR)
+/** The mask of all capabilities which the guest can legitimately change */
+#define VMMDEV_MOUSE_GUEST_MASK \
+ (VMMDEV_MOUSE_NOTIFY_HOST_MASK | VMMDEV_MOUSE_NEW_PROTOCOL)
+/** The mask of host capability changes for which notification events should
+ * be sent */
+#define VMMDEV_MOUSE_NOTIFY_GUEST_MASK \
+ VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE
+/** The mask of all capabilities which the host can legitimately change */
+#define VMMDEV_MOUSE_HOST_MASK \
+ ( VMMDEV_MOUSE_NOTIFY_GUEST_MASK \
+ | VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER \
+ | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR \
+ | VMMDEV_MOUSE_HOST_HAS_ABS_DEV)
+/** @} */
+
+/** @name Absolute mouse reporting range
+ * @{ */
+/** @todo Should these be here? They are needed by both host and guest. */
+/** The minumum value our pointing device can return. */
+#define VMMDEV_MOUSE_RANGE_MIN 0
+/** The maximum value our pointing device can return. */
+#define VMMDEV_MOUSE_RANGE_MAX 0xFFFF
+/** The full range our pointing device can return. */
+#define VMMDEV_MOUSE_RANGE (VMMDEV_MOUSE_RANGE_MAX - VMMDEV_MOUSE_RANGE_MIN)
+/** @} */
+
+
+/**
+ * Mouse pointer shape/visibility change request.
+ *
+ * Used by VMMDevReq_SetPointerShape. The size is variable.
+ */
+typedef struct VMMDevReqMousePointer
+{
+ /** Header. */
+ VMMDevRequestHeader header;
+ /** VBOX_MOUSE_POINTER_* bit flags from VBox/Graphics/VBoxVideo.h. */
+ uint32_t fFlags;
+ /** x coordinate of hot spot. */
+ uint32_t xHot;
+ /** y coordinate of hot spot. */
+ uint32_t yHot;
+ /** Width of the pointer in pixels. */
+ uint32_t width;
+ /** Height of the pointer in scanlines. */
+ uint32_t height;
+ /** Pointer data.
+ *
+ ****
+ * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color) mask.
+ *
+ * For pointers without alpha channel the XOR mask pixels are 32 bit values: (lsb)BGR0(msb).
+ * For pointers with alpha channel the XOR mask consists of (lsb)BGRA(msb) 32 bit values.
+ *
+ * Guest driver must create the AND mask for pointers with alpha channel, so if host does not
+ * support alpha, the pointer could be displayed as a normal color pointer. The AND mask can
+ * be constructed from alpha values. For example alpha value >= 0xf0 means bit 0 in the AND mask.
+ *
+ * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND mask,
+ * therefore, is cbAnd = (width + 7) / 8 * height. The padding bits at the
+ * end of any scanline are undefined.
+ *
+ * The XOR mask follows the AND mask on the next 4 bytes aligned offset:
+ * uint8_t *pXor = pAnd + (cbAnd + 3) & ~3
+ * Bytes in the gap between the AND and the XOR mask are undefined.
+ * XOR mask scanlines have no gap between them and size of XOR mask is:
+ * cXor = width * 4 * height.
+ ****
+ *
+ * Preallocate 4 bytes for accessing actual data as p->pointerData.
+ */
+ char pointerData[4];
+} VMMDevReqMousePointer;
+
+/**
+ * Pending events structure.
+ *
+ * Used by VMMDevReq_AcknowledgeEvents.
+ */
+typedef struct
+{
+ /** Header. */
+ VMMDevRequestHeader header;
+ /** OUT: Pending event mask. */
+ uint32_t events;
+} VMMDevEvents;
+AssertCompileSize(VMMDevEvents, 24+4);
+
+
+/**
+ * Guest event filter mask control.
+ *
+ * Used by VMMDevReq_CtlGuestFilterMask.
+ */
+typedef struct
+{
+ /** Header. */
+ VMMDevRequestHeader header;
+ /** Mask of events to be added to the filter. */
+ uint32_t u32OrMask;
+ /** Mask of events to be removed from the filter. */
+ uint32_t u32NotMask;
+} VMMDevCtlGuestFilterMask;
+AssertCompileSize(VMMDevCtlGuestFilterMask, 24+8);
+
+/**
+ * Guest information structure.
+ *
+ * Used by VMMDevReportGuestInfo and PDMIVMMDEVCONNECTOR::pfnUpdateGuestVersion.
+ */
+typedef struct VBoxGuestInfo
+{
+ /** The VMMDev interface version expected by additions.
+ * *Deprecated*, do not use anymore! Will be removed. */
+ uint32_t interfaceVersion;
+ /** Guest OS type. */
+ VBOXOSTYPE osType;
+} VBoxGuestInfo;
+AssertCompileSize(VBoxGuestInfo, 8);
+
+/**
+ * Guest information report.
+ *
+ * Used by VMMDevReq_ReportGuestInfo.
+ */
+typedef struct
+{
+ /** Header. */
+ VMMDevRequestHeader header;
+ /** Guest information. */
+ VBoxGuestInfo guestInfo;
+} VMMDevReportGuestInfo;
+AssertCompileSize(VMMDevReportGuestInfo, 24+8);
+
+
+/**
+ * Guest information structure, version 2.
+ *
+ * Used by VMMDevReportGuestInfo2 and PDMIVMMDEVCONNECTOR::pfnUpdateGuestVersion2.
+ */
+typedef struct VBoxGuestInfo2
+{
+ /** Major version. */
+ uint16_t additionsMajor;
+ /** Minor version. */
+ uint16_t additionsMinor;
+ /** Build number. */
+ uint32_t additionsBuild;
+ /** SVN revision. */
+ uint32_t additionsRevision;
+ /** Feature mask, VBOXGSTINFO2_F_XXX. */
+ uint32_t additionsFeatures;
+ /** The intentional meaning of this field was:
+ * Some additional information, for example 'Beta 1' or something like that.
+ *
+ * The way it was implemented was implemented: VBOX_VERSION_STRING.
+ *
+ * This means the first three members are duplicated in this field (if the guest
+ * build config is sane). So, the user must check this and chop it off before
+ * usage. There is, because of the Main code's blind trust in the field's
+ * content, no way back. */
+ char szName[128];
+} VBoxGuestInfo2;
+AssertCompileSize(VBoxGuestInfo2, 144);
+
+#endif