From 45aeeabc0613326b8597659b17f975a0ec4b1209 Mon Sep 17 00:00:00 2001
From: Javier <dev.git@javispedro.com>
Date: Sun, 13 Mar 2022 18:40:01 +0100
Subject: split ps/2 initialization into more functions

---
 mousew16.c |  21 ++++++--
 ps2.h      | 160 ++++++++++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 127 insertions(+), 54 deletions(-)

diff --git a/mousew16.c b/mousew16.c
index 45c0266..4d54175 100644
--- a/mousew16.c
+++ b/mousew16.c
@@ -238,21 +238,32 @@ WORD FAR PASCAL Inquire(LPMOUSEINFO lpMouseInfo)
   * @param lpEventProc Callback function to call when a mouse event happens. */
 VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc)
 {
+	// Store the windows-given callback
 	cli(); // Write to far pointer may not be atomic, and we could be interrupted mid-write
 	eventproc = lpEventProc;
 	sti();
 
 	if (!(mouseflags & MOUSEFLAGS_ENABLED)) {
+		// Configure the PS/2 bios and reset the mouse
 		int err;
-		if ((err = ps2_init())) {
+		if ((err = ps2m_init(PS2_MOUSE_PLAIN_PACKET_SIZE))) {
 			vbox_logs("PS2 init failure\n");
 			return;
 		}
-		if ((err = ps2_set_callback(ps2_mouse_callback))) {
+
+		// Configure mouse settings; just use the same defaults as Windows.
+		// Note that protected mode Windows just ignores all of these anyway.
+		ps2m_set_resolution(3);     // 3 = 200 dpi, 8 counts per millimeter
+		ps2m_set_sample_rate(2);    // 2 = 40 reports per second
+		ps2m_set_scaling_factor(1); // 1 = 1:1 scaling
+		// Don't check errors for these, we don't care much
+
+		if ((err = ps2m_set_callback(ps2_mouse_callback))) {
 			vbox_logs("PS2 set handler failure\n");
 			return;
 		}
-		if ((err = ps2_enable(true))) {
+
+		if ((err = ps2m_enable(true))) {
 			vbox_logs("PS2 enable failure\n");
 			return;
 		}
@@ -306,8 +317,8 @@ VOID FAR PASCAL Disable(VOID)
 		}
 #endif
 
-		ps2_enable(false);
-		ps2_set_callback(NULL);
+		ps2m_enable(false);
+		ps2m_set_callback(NULL);
 		vbox_logs("PS2 Disabled!\n");
 
 		mouseflags &= ~MOUSEFLAGS_ENABLED;
diff --git a/ps2.h b/ps2.h
index 6fcb1ec..586ba52 100644
--- a/ps2.h
+++ b/ps2.h
@@ -28,7 +28,19 @@
 /** The corresponding interrupt vector for IRQ 12. */
 #define PS2_MOUSE_INT_VECTOR 0x74
 
-enum {
+/** Packet size for plain PS/2 in default protocol. */
+#define PS2_MOUSE_PLAIN_PACKET_SIZE 3
+
+typedef uint8_t ps2m_err;
+enum ps2m_errors {
+	PS2M_ERR_INVALID_FUNCTION = 1,
+	PSM2_ERR_INVALID_INPUT    = 2,
+	PSM2_ERR_INTERFACE_ERROR  = 3,
+	PSM2_ERR_RESEND           = 4,
+	PSM2_ERR_NO_CALLBACK      = 5,
+};
+
+enum ps2m_status {
 	PS2M_STATUS_BUTTON_1 = 1 << 0,
 	PS2M_STATUS_BUTTON_2 = 1 << 1,
 	PS2M_STATUS_BUTTON_3 = 1 << 2,
@@ -38,8 +50,19 @@ enum {
 	PS2M_STATUS_Y_OVF    = 1 << 7,
 };
 
+enum ps2m_device_ids {
+	/** Standard PS/2 mouse, 2 buttons. */
+	PS2M_DEVICE_ID_PLAIN = 0,
+	/** IntelliMouse PS/2, with wheel. */
+	PS2M_DEVICE_ID_IMPS2 = 3,
+	/** IntelliMouse Explorer, wheel and 5 buttons. */
+	PS2M_DEVICE_ID_IMEX = 4,
+	/** IntelliMouse Explorer, wheel, 5 buttons, and horizontal scrolling. */
+	PS2M_DEVICE_ID_IMEX_HORZ = 5
+};
+
 #pragma aux PS2_CB far loadds parm reverse caller []
-// TODO: ax and es look not be preserved with this. VBox BIOS already preserves them though.
+// TODO: ax and es look not be preserved with this. VBox BIOS already preserves them though, as well as 32-bit registers
 
 /** Invoked by the BIOS when there is a mouse event.
  *  @param status combination of PS2M_STATUS_* flags */
@@ -51,76 +74,115 @@ static inline void cli(void);
 static inline void sti(void);
 #pragma aux sti = "sti"
 
-static uint8_t ps2_init(void);
-#pragma aux ps2_init = \
-	"stc"              /* If nothing happens, assume failure */ \
-	"mov ax, 0xC205"   /* Pointing device: initialization */ \
-	"mov bh, 3"        /* Use 3 byte packets */ \
+static ps2m_err ps2m_init(uint8_t packet_size);
+#pragma aux ps2m_init = \
+	"stc"               /* If nothing happens, assume failure */ \
+	"mov ax, 0xC205"    /* Pointing device: initialization (packet size in bh) */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ax, 0xC201"   /* Pointing device: reset */ \
+	"jnc end"           /* Success */ \
+	"fail: test ah, ah" /* Ensure we have some error code back, set ah to -1 if we don't */ \
+	"jnz end" \
+	"dec ah" \
+	"end:" \
+	__parm [bh] \
+	__value [ah] \
+	__modify [ax]
+
+static ps2m_err ps2m_reset(void);
+#pragma aux ps2m_reset = \
+	"stc" \
+	"mov ax, 0xC201"    /* Pointing device: reset */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ax, 0xC203"   /* Pointing device: set resolution */ \
-	"mov bh, 3"        /* 3 count per mm = ~ 200 ppi */ \
+	"jnc end" \
+	"fail: test ah, ah" \
+	"jnz end" \
+	"dec ah" \
+	"end:" \
+	__value [ah] \
+	__modify [ax]
+
+static ps2m_err ps2m_get_device_id(uint8_t *device_id);
+#pragma aux ps2m_get_device_id = \
+	"stc" \
+	"mov ax, 0xC201"    /* Pointing device: reset */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ax, 0xC202"   /* Pointing device: set sample rate*/ \
-	"mov bh, 5"        /* 2: 40 samples per second */ \
+	"mov es:[di], bh"   /* Save returned value */ \
+	"jnc end" \
+	"fail: test ah, ah" \
+	"jnz end" \
+	"dec ah" \
+	"end:" \
+	__parm [es di] \
+	__value [ah] \
+	__modify [ax]
+
+static ps2m_err ps2m_set_resolution(uint8_t resolution);
+#pragma aux ps2m_set_resolution = \
+	"stc" \
+	"mov ax, 0xC203"    /* Pointing device: set resolution (in bh) */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ax, 0xC206"   /* Pointing device: extended commands */ \
-	"mov bh, 1"        /* Set 1:1 scaling */ \
+	"jnc end" \
+	"fail: test ah, ah" \
+	"jnz end" \
+	"dec ah" \
+	"end:" \
+	__parm [bh] \
+	__value [ah] \
+	__modify [ax]
+
+static ps2m_err ps2m_set_sample_rate(uint8_t sample_rate);
+#pragma aux ps2m_set_sample_rate = \
+	"stc" \
+	"mov ax, 0xC202"    /* Pointing device: set sample rate (in bh) */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ah, 0"        /* Success */ \
-	"jmp end" \
-	\
-	"fail: test ah, ah" /* Ensure we have some error code back, set ah to ff if we don't */ \
+	"jnc end" \
+	"fail: test ah, ah" \
 	"jnz end" \
-	"mov ah, 0xFF" \
+	"dec ah" \
 	"end:" \
+	__parm [bh] \
+	__value [ah] \
+	__modify [ax]
+
+static ps2m_err ps2m_set_scaling_factor(uint8_t scaling_factor);
+#pragma aux ps2m_set_scaling_factor = \
+	"stc" \
+	"mov ax, 0xC206"    /* Pointing device: extended commands (with bh > 0, set scaling factor) */ \
+	"int 0x15" \
+	"jnc end" \
+	"fail: test ah, ah" \
+	"jnz end" \
+	"dec ah" \
+	"end:" \
+	__parm [bh] \
 	__value [ah] \
 	__modify [ax]
 
-static uint8_t ps2_set_callback(LPFN_PS2CALLBACK callback);
-#pragma aux ps2_set_callback = \
-	"stc"              /* If nothing happens, assume failure */ \
+static ps2m_err ps2m_set_callback(LPFN_PS2CALLBACK callback);
+#pragma aux ps2m_set_callback = \
+	"stc" \
 	"mov ax, 0xC207"   /* Pointing device: set interrupt callback (in es:bx) */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ah, 0"        /* Success */ \
-	"jmp end" \
-	\
-	"fail: test ah, ah" /* Ensure we have some error code back */ \
+	"jnc end" \
+	"fail: test ah, ah" \
 	"jnz end" \
-	"mov ah, 0xFF" \
+	"dec ah" \
 	"end:" \
 	__parm [es bx] \
 	__value [ah] \
 	__modify [ax]
 
-static uint8_t ps2_enable(bool enable);
-#pragma aux ps2_enable = \
+static ps2m_err ps2m_enable(bool enable);
+#pragma aux ps2m_enable = \
 	"test bh, bh"      /* Ensure enable is either 1 or 0 */ \
 	"setnz bh" \
-	"stc"              /* If nothing happens, assume failure */ \
+	"stc" \
 	"mov ax, 0xC200"   /* Pointing device enable/disable (in bh) */ \
 	"int 0x15" \
-	"jc fail" \
-	\
-	"mov ah, 0"        /* Success */ \
-	"jmp end" \
-	\
-	"fail: test ah, ah" /* Ensure we have some error code back */ \
+	"jnc end" \
+	"fail: test ah, ah" \
 	"jnz end" \
-	"mov ah, 0xFF" \
+	"dec ah" \
 	"end:" \
 	__parm [bh] \
 	__value [ah] \
-- 
cgit v1.2.3