aboutsummaryrefslogtreecommitdiff
path: root/mousetsr.c
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 /mousetsr.c
parent3da9d4d5eff694e7e91116a693f328c289fc82f6 (diff)
downloadvbados-b9396bdeff4588762ab017cb3446910a2684b380.tar.gz
vbados-b9396bdeff4588762ab017cb3446910a2684b380.zip
switch mouse driver to always use 1-byte packets from BIOS
Diffstat (limited to 'mousetsr.c')
-rw-r--r--mousetsr.c166
1 files changed, 81 insertions, 85 deletions
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);