diff options
-rw-r--r-- | int15ps2.h | 13 | ||||
-rw-r--r-- | int33.h | 2 | ||||
-rw-r--r-- | mousetsr.c | 166 | ||||
-rw-r--r-- | mousetsr.h | 29 | ||||
-rw-r--r-- | mousew16.c | 2 | ||||
-rw-r--r-- | mousmain.c | 4 | ||||
-rw-r--r-- | sfmain.c | 1 | ||||
-rw-r--r-- | sftsr.h | 3 | ||||
-rw-r--r-- | version.h | 7 |
9 files changed, 118 insertions, 109 deletions
@@ -63,6 +63,7 @@ enum ps2m_device_ids { PS2M_DEVICE_ID_IMEX_HORZ = 5 }; +/** Valid PS/2 mouse resolutions in DPI. */ enum ps2m_resolution { PS2M_RESOLUTION_25 = 0, PS2M_RESOLUTION_50 = 1, @@ -70,6 +71,7 @@ enum ps2m_resolution { PS2M_RESOLUTION_200 = 3 }; +/** Valid PS/2 mouse sampling rates in Hz. */ enum ps2m_sample_rate { PS2M_SAMPLE_RATE_10 = 0, PS2M_SAMPLE_RATE_20 = 1, @@ -197,6 +199,7 @@ static ps2m_err ps2m_enable(bool enable); __value [ah] \ __modify [ax] +/** Sends the magic sequence to switch the mouse to the IMPS2 protocol. */ static void ps2m_send_imps2_sequence(void) { ps2m_set_sample_rate(PS2M_SAMPLE_RATE_200); @@ -204,21 +207,15 @@ static void ps2m_send_imps2_sequence(void) ps2m_set_sample_rate(PS2M_SAMPLE_RATE_80); } +/** Detects whether we have a IMPS2 mouse with wheel support. */ static bool ps2m_detect_wheel(void) { int err; uint8_t device_id; - // Switch to the 4-byte packet and reset the mouse. - // We are not supposed to receive messages at this time anyway. - err = ps2m_init(PS2M_PACKET_SIZE_EXT); - if (err) { - return false; - } - // Get the initial mouse device id err = ps2m_get_device_id(&device_id); - if (err || device_id != 0) { + if (err || device_id != PS2M_DEVICE_ID_PLAIN) { // TODO : Likely have to accept more device_ids here. return false; } @@ -246,7 +246,7 @@ static uint16_t int33_get_driver_version(void); __value [bx] \ __modify [ax bx cx dx] -static int int33_get_max_coordinates(int16_t *x, int16_t *y); +static int int33_get_max_coordinates(uint16_t *x, uint16_t *y); #pragma aux int33_get_max_coordinates = \ "mov ax, 0x26" \ "mov bx, -1" \ @@ -644,9 +644,9 @@ static void handle_mouse_event(uint16_t buttons, bool absolute, int x, int y, in events |= INT33_EVENT_MASK_MOVEMENT; // Check if around one second has passed - if ((ticks - data.last_ticks) >= 18) { + if ((ticks - data.last_motion_ticks) >= 18) { data.total_motion = 0; - data.last_ticks = ticks; + data.last_motion_ticks = ticks; } // If more than the double speed threshold has been moved in the last second, @@ -729,81 +729,40 @@ 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 ps2_mouse_handler(uint16_t word1, uint16_t word2, uint16_t word3, uint16_t word4) +static void handle_ps2_packet(void) { -#pragma aux ps2_mouse_handler "*" parm caller [ax] [bx] [cx] [dx] modify [ax bx cx dx si di es fs gs] - unsigned status; - int x, y, z; + int x, y, z = 0; bool abs = false; -#if TRACE_EVENTS - 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 /* TRACE_EVENTS */ - - // Decode the PS2 event args + // Decode the PS2 packet... + status = data.ps2_packet[0]; + x = data.ps2_packet[1]; + y = data.ps2_packet[2]; #if USE_WHEEL - // 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 - // Real hardware seems to be of either type. - // VirtualBox/Bochs/qemu/SeaBIOS also store the raw contents of all mouse - // packets in the EBDA reserved area (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? - - // First, we'll only read the EBDA if we have confirmed VirtualBox (see USE_VIRTUALBOX below) - // For VirtualBox VMs this is mandatory since we have no other way of getting wheel data - // For qemu VMs, we can still get to wheel data via the vmmouse interface (and we'll do that). - // Second, the moment we see that the high byte of word1 is not 0, - // we'll assume the BIOS is of the second type, and remember that. - // (since when there is no movement, x would be 0 anyway!) - - if (word1 & 0xFF00) data.bios_x_on_status = true; - - if (data.haswheel && data.bios_x_on_status) { - status = (uint8_t) word1; - x = (uint8_t) (word1 >> 8); - y = (uint8_t) word2; - z = (int8_t) word3; // Sign-extend z packet - } else { - status = (uint8_t) word1; - x = (uint8_t) word2; - y = (uint8_t) word3; - z = 0; + if (data.haswheel) { + // Sign-extend Z + z = (int8_t) data.ps2_packet[3]; } -#else - status = (uint8_t) word1; - x = (uint8_t) word2; - y = (uint8_t) word3; - z = 0; #endif - (void) word4; // This appears to be never used on either type of BIOS - // 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 TRACE_EVENTS + dlog_print("ps2 packet "); + dlog_printx(status); + dlog_putc(' '); + dlog_printd(x); + dlog_putc(' '); + dlog_printd(y); + dlog_putc(' '); + dlog_printd(z); + dlog_endline(); +#endif /* TRACE_EVENTS */ + #if USE_VIRTUALBOX if (data.vbavail) { uint16_t vbx, vby; @@ -821,15 +780,6 @@ static void ps2_mouse_handler(uint16_t word1, uint16_t word2, uint16_t word3, ui data.vbhaveabs = false; // Rely on PS/2 relative coordinates. } - -#if USE_WHEEL - // 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 } #endif /* USE_VIRTUALBOX */ @@ -894,6 +844,47 @@ static void ps2_mouse_handler(uint16_t word1, uint16_t word2, uint16_t word3, ui abs, x, y, z); } +/** PS/2 BIOS calls this routine to notify mouse events. + * In our case, each time we receive a byte from the mouse. */ +static void ps2_mouse_handler(unsigned byte) +{ +#pragma aux ps2_mouse_handler "*" parm caller [ax] modify [ax bx cx dx si di es fs gs] + + uint16_t ticks = bda_get_tick_count_lo(); + +#if TRACE_EVENTS + dlog_print("ps2 callback byte "); + dlog_printd(1 + data.cur_packet_bytes); + dlog_putc('/'); + dlog_printd(data.packet_size); + dlog_putc('='); + dlog_printx(byte & 0xFF); + dlog_endline(); +#endif /* TRACE_EVENTS */ + + if (data.cur_packet_bytes && + ticks >= data.cur_packet_ticks + MAX_PS2_PACKET_DELAY) { + // Assume the start of a new packet + dlog_print("dropping packet! prev ticks="); + dlog_printu(data.cur_packet_ticks); + dlog_print(" new_ticks="); + dlog_printu(ticks); + dlog_endline(); + data.cur_packet_bytes = 0; + } + if (data.cur_packet_bytes == 0) { + data.cur_packet_ticks = ticks; + } + + data.ps2_packet[data.cur_packet_bytes] = byte; + data.cur_packet_bytes++; + + if (data.cur_packet_bytes == data.packet_size) { + handle_ps2_packet(); + data.cur_packet_bytes = 0; + } +} + void __declspec(naked) __far ps2_mouse_callback() { __asm { @@ -906,15 +897,16 @@ void __declspec(naked) __far ps2_mouse_callback() ; 8 + 4 saved registers, 24 bytes ; plus 4 bytes for retf address ; = 28 bytes of stack before callback args + ; The BIOS always pushes 4 words, so first BIOS parameter is at bp + 28 + 6 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 + 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 @@ -967,26 +959,30 @@ static void set_absolute(bool enable) static void reset_mouse_hardware() { + // Stop receiving bytes... ps2m_enable(false); + // Let the BIOS know we want every packet separately + // This also resets the mouse + ps2m_init(1); + + data.packet_size = PS2M_PACKET_SIZE_PLAIN; + data.cur_packet_bytes = 0; + data.cur_packet_ticks = 0; + #if USE_WHEEL - data.bios_x_on_status = false; if (data.usewheel && ps2m_detect_wheel()) { dlog_puts("PS/2 wheel detected"); data.haswheel = true; - // Detect wheel also reinitializes the mouse to the proper packet size + data.packet_size = PS2M_PACKET_SIZE_EXT; } else { dlog_puts("PS/2 wheel NOT detected"); data.haswheel = false; - // Otherwise do an extra reset to return back to initial state, just in case - ps2m_init(PS2M_PACKET_SIZE_PLAIN); } -#else - 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 + ps2m_set_resolution(PS2M_RESOLUTION_200); + ps2m_set_sample_rate(PS2M_SAMPLE_RATE_80); ps2m_set_scaling_factor(1); // 1 = 1:1 scaling ps2m_set_callback(get_cs():>ps2_mouse_callback); @@ -39,9 +39,6 @@ /** Trace events verbosily */ #define TRACE_EVENTS 0 -#define VERSION_MAJOR 0 -#define VERSION_MINOR 5 - /** The report MS MOUSE compatible version to programs who ask for it. */ #define REPORTED_VERSION_MAJOR 6 #define REPORTED_VERSION_MINOR 0x30 @@ -50,8 +47,16 @@ #define USE_INTEGRATION (USE_VIRTUALBOX || USE_VMWARE) +/** Max size of PS/2 packet that we support. */ +#define MAX_PS2_PACKET_SIZE 4 + +/** Maximum number of 55ms ticks that may pass between two bytes of the same PS/2 packet */ +#define MAX_PS2_PACKET_DELAY 2 + +/** Number of buttons reported back to user programs. */ #define NUM_BUTTONS 3 +/** Size of int33 graphic cursor shape definitions. */ #define GRAPHIC_CURSOR_WIDTH 16 #define GRAPHIC_CURSOR_HEIGHT 16 #define GRAPHIC_CURSOR_SCANLINE_LEN 2 @@ -77,6 +82,7 @@ typedef struct tsrdata { #if USE_WIN386 void (__interrupt __far *prev_int2f_handler)(); #endif + // Settings configured via the command line #if USE_WHEEL /** Whether to enable & use wheel mouse. */ bool usewheel; @@ -99,14 +105,19 @@ typedef struct tsrdata { * This stores the desired grid granularity. */ struct point screen_granularity; - // Detected mouse hardware + // Detected mouse hardware & status #if USE_WHEEL /** Whether the current mouse has a wheel (and support is enabled). */ - bool haswheel : 1; - /** Whether the current PS/2 BIOS seems to be putting the first packet - * on the high byte of the first word when we use wheel mouse. */ - bool bios_x_on_status : 1; + bool haswheel; #endif + /** Packet size that we are currently using. */ + uint8_t packet_size; + /** Number of bytes received so far (< packet_size). */ + uint8_t cur_packet_bytes; + /** Stores the bytes received so far (cur_bytes). */ + uint8_t ps2_packet[MAX_PS2_PACKET_SIZE]; + /** Number of ticks at the point when we started to receive this packet. */ + uint16_t cur_packet_ticks; // Current mouse settings /** Mouse sensitivity/speed. */ @@ -149,7 +160,7 @@ typedef struct tsrdata { /** Total mickeys moved in the last second. */ uint16_t total_motion; /** Ticks when the above value was last reset. */ - uint16_t last_ticks; + uint16_t last_motion_ticks; /** Current status of buttons (as bitfield). */ uint16_t buttons; struct { @@ -171,7 +171,7 @@ static void FAR int33_mouse_callback(uint16_t events, uint16_t buttons, int16_t dlog_endline(); #endif - if (events & INT33_EVENT_MASK_LEFT_BUTTON_PRESSED) status |= SF_B1_DOWN; + if (events & INT33_EVENT_MASK_LEFT_BUTTON_PRESSED) status |= SF_B1_DOWN; if (events & INT33_EVENT_MASK_LEFT_BUTTON_RELEASED) status |= SF_B1_UP; if (events & INT33_EVENT_MASK_RIGHT_BUTTON_PRESSED) status |= SF_B2_DOWN; if (events & INT33_EVENT_MASK_RIGHT_BUTTON_RELEASED) status |= SF_B2_UP; @@ -21,8 +21,8 @@ #include <stdlib.h> #include <string.h> #include <dos.h> -#include <i86.h> +#include "version.h" #include "dlog.h" #include "int33.h" #include "int21dos.h" @@ -246,7 +246,7 @@ static int configure_driver(LPTSRDATA data) dlog_init(); // Check for PS/2 mouse BIOS availability - if ((err = ps2m_init(PS2M_PACKET_SIZE_PLAIN))) { + if ((err = ps2m_init(1))) { fprintf(stderr, "Cannot init PS/2 mouse BIOS, err=%d\n", err); // Can't do anything without PS/2 return err; @@ -23,6 +23,7 @@ #include <time.h> #include <dos.h> +#include "version.h" #include "dlog.h" #include "vboxshfl.h" #include "dostsr.h" @@ -26,9 +26,6 @@ #include "vbox.h" #include "int21dos.h" -#define VERSION_MAJOR 0 -#define VERSION_MINOR 2 - #define TRACE_CALLS 0 #define LASTDRIVE 'Z' diff --git a/version.h b/version.h new file mode 100644 index 0000000..1f6fb40 --- /dev/null +++ b/version.h @@ -0,0 +1,7 @@ +#ifndef VERSION_H +#define VERSION_H + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 0x51 + +#endif // VERSION_H |