aboutsummaryrefslogtreecommitdiff
path: root/mousew16.c
diff options
context:
space:
mode:
Diffstat (limited to 'mousew16.c')
-rw-r--r--mousew16.c215
1 files changed, 215 insertions, 0 deletions
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;
+}
+