aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2022-04-18 22:13:00 +0200
committerJavier <dev.git@javispedro.com>2022-04-18 22:13:00 +0200
commitb9396bdeff4588762ab017cb3446910a2684b380 (patch)
treea43e4647125e52e02507127043b62bcb3f59c3c3
parent3da9d4d5eff694e7e91116a693f328c289fc82f6 (diff)
downloadvbados-b9396bdeff4588762ab017cb3446910a2684b380.tar.gz
vbados-b9396bdeff4588762ab017cb3446910a2684b380.zip
switch mouse driver to always use 1-byte packets from BIOS
-rw-r--r--int15ps2.h13
-rw-r--r--int33.h2
-rw-r--r--mousetsr.c166
-rw-r--r--mousetsr.h29
-rw-r--r--mousew16.c2
-rw-r--r--mousmain.c4
-rw-r--r--sfmain.c1
-rw-r--r--sftsr.h3
-rw-r--r--version.h7
9 files changed, 118 insertions, 109 deletions
diff --git a/int15ps2.h b/int15ps2.h
index 6b6c415..cce254d 100644
--- a/int15ps2.h
+++ b/int15ps2.h
@@ -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;
}
diff --git a/int33.h b/int33.h
index 69ef7ed..10816f0 100644
--- a/int33.h
+++ b/int33.h
@@ -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" \
diff --git a/mousetsr.c b/mousetsr.c
index 5d820cf..406727b 100644
--- a/mousetsr.c
+++ b/mousetsr.c
@@ -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);
diff --git a/mousetsr.h b/mousetsr.h
index 00646db..5e10afa 100644
--- a/mousetsr.h
+++ b/mousetsr.h
@@ -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 {
diff --git a/mousew16.c b/mousew16.c
index bebafc3..dc16833 100644
--- a/mousew16.c
+++ b/mousew16.c
@@ -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;
diff --git a/mousmain.c b/mousmain.c
index 56b8efe..72b5b09 100644
--- a/mousmain.c
+++ b/mousmain.c
@@ -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;
diff --git a/sfmain.c b/sfmain.c
index e2f0b58..9f4fe38 100644
--- a/sfmain.c
+++ b/sfmain.c
@@ -23,6 +23,7 @@
#include <time.h>
#include <dos.h>
+#include "version.h"
#include "dlog.h"
#include "vboxshfl.h"
#include "dostsr.h"
diff --git a/sftsr.h b/sftsr.h
index f9a7b61..6161757 100644
--- a/sftsr.h
+++ b/sftsr.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