From 51cdb6b523be973e802cc940c6ac54cc8a50b802 Mon Sep 17 00:00:00 2001 From: Javier Date: Tue, 5 Apr 2022 22:24:47 +0200 Subject: add vmware support, debug logging to serial port, and fix ps2 routine clobbering registers --- dostsr.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 185 insertions(+), 35 deletions(-) (limited to 'dostsr.c') diff --git a/dostsr.c b/dostsr.c index 0bed693..3d9066e 100644 --- a/dostsr.c +++ b/dostsr.c @@ -26,6 +26,8 @@ #include "int10vga.h" #include "int2fwin.h" #include "int33.h" +#include "vbox.h" +#include "vmware.h" #include "dostsr.h" #define MSB_MASK 0x8000U @@ -303,7 +305,7 @@ static void refresh_cursor(void) bool should_show = data.visible_count >= 0; bool pos_changed, needs_refresh; -#if USE_INT2F +#if USE_WIN386 // Windows 386 is already rendering the cursor for us. // Hide our own. if (data.w386cursor) should_show = false; @@ -646,58 +648,180 @@ static void handle_mouse_event(uint16_t buttons, bool absolute, int x, int y, in } /** PS/2 BIOS calls this routine to notify mouse events. */ -static void __far ps2_mouse_callback(uint8_t status, uint8_t x, uint8_t y, uint8_t z) +static void __far ps2_mouse_handler(uint16_t word1, uint16_t word2, uint16_t word3, uint16_t word4) { -#pragma aux (PS2_CB) ps2_mouse_callback +#pragma aux ps2_mouse_handler "*" parm caller [ax] [bx] [cx] [dx] modify [ax bx cx dx si di es fs gs] - int sx = status & PS2M_STATUS_X_NEG ? 0xFF00 | x : x; - int sy = -(status & PS2M_STATUS_Y_NEG ? 0xFF00 | y : y); - int sz = z; + unsigned status; + int x, y, z; bool abs = false; #if TRACE_EVENTS - dlog_print("ps2 callback status="); - dlog_printx(status); - dlog_print(" sx="); - dlog_printd(sx); - dlog_print(" sy="); - dlog_printd(sy); - dlog_print(" sz="); - dlog_printd(z); + dlog_print("ps2 callback "); + dlog_printx(word1); + dlog_putc(' '); + dlog_printx(word2); + dlog_putc(' '); + dlog_printx(word3); + dlog_putc(' '); + dlog_printx(word4); dlog_endline(); -#endif +#endif /* TRACE_EVENTS */ + + // Decode the PS2 event args + // In a normal IBM PS/2 BIOS (incl. VirtualBox/Bochs/qemu/SeaBIOS): + // word1 low byte = status (following PS2M_STATUS_*) + // word2 low byte = x + // word3 low byte = y + // word4 = always zero + // In a PS/2 BIOS with wheel support (incl. VMware/DOSBox-X): + // taken from CuteMouse/KoKo: + // word1 high byte = x + // word1 low byte = status + // word2 low byte = y + // word3 low byte = z + // word4 = always zero + // VirtualBox/Bochs/qemu/SeaBIOS behave like a normal one, + // but they also store the raw contents of all mouse packets in the EBDA (starting 0x28 = packet 0). + // Other BIOSes don't do that so it is not a reliable option either. + // So, how to detect which BIOS we have? + // For now we are always assuming "normal" PS/2 BIOS. + // But with VirtualBox integration on we'll get the wheel packet from the EBDA, + // and with VMWare integration on we'll get it from the VMware protocol. + status = (uint8_t) word1; + x = (uint8_t) word2; + y = (uint8_t) word3; + z = 0; + (void) word4; + + // Sign-extend X, Y as per the status byte + x = status & PS2M_STATUS_X_NEG ? 0xFF00 | x : x; + y = -(status & PS2M_STATUS_Y_NEG ? 0xFF00 | y : y); #if USE_VIRTUALBOX if (data.vbavail) { uint16_t vbx, vby; if ((vbox_get_mouse(&data.vb, &abs, &vbx, &vby) == 0) && abs) { - sx = scaleu(vbx, 0xFFFFU, MAX(data.max.x, data.screen_max.x)); - sy = scaleu(vby, 0xFFFFU, MAX(data.max.y, data.screen_max.y)); + // VirtualBox gives unsigned coordinates from 0...0xFFFFU, + // scale to 0..screen_size (in pixels). + // If the user is using a window larger than the screen, use it. + x = scaleu(vbx, 0xFFFFU, MAX(data.max.x, data.screen_max.x)); + y = scaleu(vby, 0xFFFFU, MAX(data.max.y, data.screen_max.y)); data.vbhaveabs = true; } else { // VirtualBox does not support absolute coordinates, // or user has disabled them. data.vbhaveabs = false; + // Rely on PS/2 relative coordinates. + } + + // VirtualBox/Bochs BIOS does not pass wheel data to the callback, + // so we will fetch it directly from the BIOS data segment. + if (data.haswheel) { + int8_t __far * mouse_packet = MK_FP(bda_get_ebda_segment(), 0x28); + z = mouse_packet[3]; } } +#endif /* USE_VIRTUALBOX */ + +#if USE_VMWARE + if (data.vmwavail) { + uint32_t vmwstatus = vmware_abspointer_status(); + uint16_t data_avail = vmwstatus & VMWARE_ABSPOINTER_STATUS_MASK_DATA; + +#if TRACE_EVENTS + dlog_print("vmware status=0x"); + dlog_printx(vmwstatus >> 16); + dlog_print(" "); + dlog_printx(vmwstatus & 0xFFFF); + dlog_endline(); +#endif + + if (data_avail >= VMWARE_ABSPOINTER_DATA_PACKET_SIZE) { + struct vmware_abspointer_data vmw; + vmware_abspointer_data(VMWARE_ABSPOINTER_DATA_PACKET_SIZE, &vmw); + +#if TRACE_EVENTS + dlog_print("vmware pstatus=0x"); + dlog_printx(status); + dlog_print(" x=0x"); + dlog_printx(vmw.x); + dlog_print(" z="); + dlog_printd((int8_t) (uint8_t) vmw.z); + dlog_endline(); #endif - // VirtualBox/Bochs BIOS does not pass wheel data to the callback, - // so we will fetch it directly from the BIOS data segment. - if (data.haswheel && !sz) { - int8_t __far * mouse_packet = MK_FP(bda_get_ebda_segment(), 0x28); - sz = mouse_packet[3]; + if (vmw.status & VMWARE_ABSPOINTER_STATUS_RELATIVE) { + x = (int16_t) vmw.x; + y = (int16_t) vmw.y; + z = (int8_t) (uint8_t) vmw.z; + } else { + abs = true; + x = scaleu(vmw.x & 0xFFFFU, 0xFFFFU, + MAX(data.max.x, data.screen_max.x)); + y = scaleu(vmw.y & 0xFFFFU, 0xFFFFU, + MAX(data.max.y, data.screen_max.y)); + z = (int8_t) (uint8_t) vmw.z; + } + + if (vmw.status & VMWARE_ABSPOINTER_STATUS_BUTTON_LEFT) { + status |= PS2M_STATUS_BUTTON_1; + } + if (vmw.status & VMWARE_ABSPOINTER_STATUS_BUTTON_RIGHT) { + status |= PS2M_STATUS_BUTTON_2; + } + if (vmw.status & VMWARE_ABSPOINTER_STATUS_BUTTON_MIDDLE) { + status |= PS2M_STATUS_BUTTON_3; + } + } else { + return; // Ignore the PS/2 packet otherwise, it is likely garbage + } } +#endif /* USE_VMWARE */ handle_mouse_event(status & (PS2M_STATUS_BUTTON_1 | PS2M_STATUS_BUTTON_2 | PS2M_STATUS_BUTTON_3), - abs, sx, sy, sz); + abs, x, y, z); } -#if USE_VIRTUALBOX -static void enable_vbox_absolute(bool enable) +void __declspec(naked) __far ps2_mouse_callback() { - data.vbhaveabs = false; + __asm { + pusha + push ds + push es + push fs + push gs + ; 8 + 4 saved registers, 24 bytes + ; plus 4 bytes for retf address + ; = 28 bytes of stack before callback args + + mov bp, sp + push cs + pop ds + + mov ax,[bp+28+6] ; Status + mov bx,[bp+28+4] ; X + mov cx,[bp+28+2] ; Y + mov dx,[bp+28+0] ; Z + + call ps2_mouse_handler + + pop gs + pop fs + pop es + pop ds + popa + + retf + } +} + +#if USE_INTEGRATION +static void set_absolute(bool enable) +{ +#if USE_VIRTUALBOX + data.vbhaveabs = false; if (data.vbavail) { int err = vbox_set_mouse(&data.vb, enable, false); if (enable && !err) { @@ -707,19 +831,34 @@ static void enable_vbox_absolute(bool enable) dlog_puts("VBox absolute mouse disabled"); } } +#endif /* USE_VIRTUALBOX */ +#if USE_VMWARE + if (data.vmwavail) { + if (enable) { + uint16_t data_avail; + // It looks like a reset of the PS/2 mouse completely disables + // the vmware interface, so we have to reenable it from scratch. + vmware_abspointer_cmd(VMWARE_ABSPOINTER_CMD_ENABLE); + vmware_abspointer_data_clear(); + vmware_abspointer_cmd(VMWARE_ABSPOINTER_CMD_REQUEST_ABSOLUTE); + + dlog_puts("VMware absolute mouse enabled"); + } else { + vmware_abspointer_cmd(VMWARE_ABSPOINTER_CMD_REQUEST_RELATIVE); + vmware_abspointer_cmd(VMWARE_ABSPOINTER_CMD_DISABLE); + + dlog_puts("VMware absolute mouse disabled"); + } + } +#endif /* USE_VMWARE */ } -#endif +#endif /* USE_INTEGRATION */ static void reset_mouse_hardware() { ps2m_enable(false); -#if USE_VIRTUALBOX - // By default, enable the integration - enable_vbox_absolute(true); - load_cursor(); -#endif - +#if USE_WHEEL if (data.usewheel && ps2m_detect_wheel()) { // Detect wheel also reinitializes the mouse to the proper packet size data.haswheel = true; @@ -728,6 +867,10 @@ static void reset_mouse_hardware() data.haswheel = false; ps2m_init(PS2M_PACKET_SIZE_PLAIN); } +#else + data.haswheel = false; + ps2m_init(PS2M_PACKET_SIZE_PLAIN); +#endif ps2m_set_resolution(3); // 3 = 200 dpi, 8 counts per millimeter ps2m_set_sample_rate(4); // 4 = 80 reports per second @@ -735,6 +878,13 @@ static void reset_mouse_hardware() ps2m_set_callback(ps2_mouse_callback); +#if USE_INTEGRATION + // By default, enable absolute mouse + set_absolute(true); + // Reload hardware cursor + load_cursor(); +#endif + ps2m_enable(true); } @@ -813,7 +963,7 @@ static void return_clear_button_counter(union INTPACK __far *r, struct buttoncou /** Entry point for our int33 API. */ static void int33_handler(union INTPACK r) -#pragma aux int33_handler "*" parm caller [] modify [ax bx cx dx es] +#pragma aux int33_handler "*" parm caller [] modify [ax bx cx dx si di es fs gs] { switch (r.x.ax) { case INT33_RESET_MOUSE: @@ -1062,7 +1212,7 @@ void __declspec(naked) __far int33_isr(void) } } -#if USE_INT2F +#if USE_WIN386 /** Windows will call this function to notify events when we are inside a DOS box. */ static void windows_mouse_handler(int action, int x, int y, int buttons, int events) #pragma aux windows_mouse_handler "*" parm [ax] [bx] [cx] [dx] [si] modify [ax bx cx dx es] -- cgit v1.2.3