aboutsummaryrefslogtreecommitdiff
path: root/mousmain.c
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2026-08-30 02:21:09 +0200
committerJavier <dev.git@javispedro.com>2026-08-30 02:21:09 +0200
commit1b0344660de2832b472b0a413c50ff7f111a9293 (patch)
tree5ae7303643d6c9187da6366cf30a4f6a4c73d54b /mousmain.c
parent003a26a76982f512e2f3a1108e46b88aa29ab306 (diff)
downloadvbados-1b0344660de2832b472b0a413c50ff7f111a9293.tar.gz
vbados-1b0344660de2832b472b0a413c50ff7f111a9293.zip
first steps towards (optional) serial mouse support
Diffstat (limited to 'mousmain.c')
-rw-r--r--mousmain.c306
1 files changed, 275 insertions, 31 deletions
diff --git a/mousmain.c b/mousmain.c
index 07ba05a..a7298a5 100644
--- a/mousmain.c
+++ b/mousmain.c
@@ -28,6 +28,7 @@
#include "int33.h"
#include "int21dos.h"
#include "int15ps2.h"
+#include "serial.h"
#include "vbox.h"
#include "vmware.h"
#include "dostsr.h"
@@ -43,13 +44,15 @@ static bool detect_wheel(LPTSRDATA data)
if (ps2m_detect_imps2()) {
if (ps2m_detect_imex()) {
data->num_wheels = 2;
+ data->num_buttons = 5;
} else {
data->num_wheels = 1;
+ data->num_buttons = 3;
}
- printf(_(1, 0, "Wheel mouse found and enabled\n"));
return true;
} else {
data->num_wheels = 0;
+ data->num_buttons = 3;
return false;
}
}
@@ -124,7 +127,7 @@ static int set_hwheel_key(LPTSRDATA data, const char *keyname)
#endif /* USE_WHEEL */
#if USE_VIRTUALBOX
-static int set_virtualbox_integration(LPTSRDATA data, bool enable)
+static int set_virtualbox_integration(LPTSRDATA data, bool enable, bool verbose)
{
if (enable) {
int err;
@@ -133,19 +136,19 @@ static int set_virtualbox_integration(LPTSRDATA data, bool enable)
err = vbox_init_device(&data->vb);
if (err) {
- fprintf(stderr, _(3, 3, "Cannot find VirtualBox PCI device, err=%d\n"), err);
+ if (verbose) fprintf(stderr, _(3, 3, "Cannot find VirtualBox PCI device, err=%d\n"), err);
return err;
}
err = vbox_init_buffer(&data->vb, VBOX_BUFFER_SIZE);
if (err) {
- fprintf(stderr, _(3, 4, "Cannot lock buffer used for VirtualBox communication, err=%d\n"), err);
+ if (verbose) fprintf(stderr, _(3, 4, "Cannot lock buffer used for VirtualBox communication, err=%d\n"), err);
return err;
}
err = vbox_report_guest_info(&data->vb, VBOXOSTYPE_DOS);
if (err) {
- fprintf(stderr, _(3, 5, "VirtualBox communication is not working, err=%d\n"), err);
+ if (verbose) fprintf(stderr, _(3, 5, "VirtualBox communication is not working, err=%d\n"), err);
return err;
}
@@ -162,7 +165,7 @@ static int set_virtualbox_integration(LPTSRDATA data, bool enable)
data->vbavail = false;
data->vbhaveabs = false;
} else {
- printf(_(1, 9, "VirtualBox integration already disabled or not available\n"));
+ if (verbose) printf(_(1, 9, "VirtualBox integration already disabled or not available\n"));
}
}
@@ -179,7 +182,7 @@ static int set_virtualbox_host_cursor(LPTSRDATA data, bool enable)
#endif
#if USE_VMWARE
-static int set_vmware_integration(LPTSRDATA data, bool enable)
+static int set_vmware_integration(LPTSRDATA data, bool enable, bool verbose)
{
if (enable) {
int32_t version;
@@ -190,11 +193,11 @@ static int set_vmware_integration(LPTSRDATA data, bool enable)
version = vmware_get_version();
if (version < 0) {
- fprintf(stderr, _(3, 6, "Could not detect VMware, err=%ld\n"), version);
+ if (verbose) fprintf(stderr, _(3, 6, "Could not detect VMware, err=%ld\n"), version);
return -1;
}
- printf(_(1, 11, "Found VMware protocol version %ld\n"), version);
+ if (verbose) printf(_(1, 11, "Found VMware protocol version %ld\n"), version);
vmware_abspointer_cmd(VMWARE_ABSPOINTER_CMD_ENABLE);
@@ -220,7 +223,7 @@ static int set_vmware_integration(LPTSRDATA data, bool enable)
data->vmwavail = false;
printf(_(1, 13, "Disabled VMware integration\n"));
} else {
- printf(_(1, 14, "VMware integration already disabled or not available\n"));
+ if (verbose) printf(_(1, 14, "VMware integration already disabled or not available\n"));
}
}
@@ -228,7 +231,7 @@ static int set_vmware_integration(LPTSRDATA data, bool enable)
}
#endif
-static int set_integration(LPTSRDATA data, bool enable)
+static int set_integration(LPTSRDATA data, bool enable, bool verbose)
{
if (enable) {
int err = -1;
@@ -236,13 +239,13 @@ static int set_integration(LPTSRDATA data, bool enable)
#if USE_VIRTUALBOX
// First check if we can enable the VirtualBox integration,
// since it's a PCI device it's easier to check if it's not present
- err = set_virtualbox_integration(data, true);
+ err = set_virtualbox_integration(data, true, verbose);
if (!err) return 0;
#endif
#if USE_VMWARE
// Afterwards try VMWare integration
- err = set_vmware_integration(data, true);
+ err = set_vmware_integration(data, true, verbose);
if (!err) return 0;
#endif
@@ -251,12 +254,12 @@ static int set_integration(LPTSRDATA data, bool enable)
} else {
#if USE_VIRTUALBOX
if (data->vbavail) {
- set_virtualbox_integration(data, false);
+ set_virtualbox_integration(data, false, verbose);
}
#endif
#if USE_VMWARE
if (data->vmwavail) {
- set_vmware_integration(data, false);
+ set_vmware_integration(data, false, verbose);
}
#endif
return 0;
@@ -274,29 +277,33 @@ static int set_host_cursor(LPTSRDATA data, bool enable)
return -1;
}
-static int configure_driver(LPTSRDATA data)
+static int configure_driver_ps2(LPTSRDATA data)
{
int err;
- // Configure the debug logging port
- dlog_init();
-
// Check for PS/2 mouse BIOS availability
if ((err = ps2m_init(PS2M_PACKET_SIZE_STD))) {
- fprintf(stderr, _(3, 8, "Cannot init PS/2 mouse BIOS, err=%d\n"), err);
- // Can't do anything without PS/2
return err;
}
+ // OK, if BIOS gives no error, assume PS/2 mouse is present and use it
+ data->port = 0;
+ data->port_io = 0;
+ data->port_irq = 0;
+
#if USE_WHEEL
// Let's utilize the wheel by default
data->usewheel = true;
- detect_wheel(data); // Prints message if wheel found
+ detect_wheel(data);
+#else
+ // Without ImEX/wheel detection, hardcode number of buttons
+ data->num_buttons = 3;
+ data->num_wheels = 0;
#endif
#if USE_INTEGRATION
// Enable integration by default
- set_integration(data, true);
+ set_integration(data, true, false);
#endif
#if USE_VIRTUALBOX
@@ -307,6 +314,168 @@ static int configure_driver(LPTSRDATA data)
return 0;
}
+#if USE_SERIAL
+static int configure_driver_serial(LPTSRDATA data, int port, unsigned iobase)
+{
+ struct serial_config serconfig;
+ unsigned delay;
+ char sig1 = 0, sig2 = 0;
+
+ if (!iobase) {
+ dprintf("Skip search on COM%u because no IO base found\n", port);
+ return -1;
+ }
+
+#if ENABLE_DLOG && DLOG_TARGET == DLOG_TARGET_SERIAL
+ if (iobase == DLOG_TARGET_PORT) {
+ dprintf("Skip search on COM%u because it would overlap with dlog %x\n", port, iobase);
+ }
+#endif
+
+ dprintf("Detecting mouse on COM%d, iobase %xh\n", port, iobase);
+ serial_save_config(iobase, &serconfig);
+ serial_configure_interrupts(iobase, SERIAL_IER_NONE); // disable interrupts for now
+ // 1200 bps, word length = 7, parity = none
+ serial_configure_line(iobase, SERIAL_DIVISOR_1200, SERIAL_LCR_WL_7|SERIAL_LCR_PAR_NONE);
+ serial_set_fifo_control(iobase, SERIAL_FCR_FIFO_RESET|SERIAL_FCR_FIFO_ENABLE);
+ // Enables DRT, but clears RTS, so that mouse enters reset state
+ serial_set_modem_control(iobase, SERIAL_MCR_DTR);
+ dputs("DTR ON, RTS OFF");
+
+ // Wait for 3 ticks (100-150ms) for mouse to power off
+ bda_wait_ticks(3);
+
+ // Now turn on the mouse by enabling RTS
+ serial_set_modem_control(iobase, SERIAL_MCR_DTR | SERIAL_MCR_RTS);
+ dputs("DTR ON, RTS ON");
+
+ // Wait up to 10 ticks (550ms) for the mouse to send something we understand
+ for (delay = 10; delay > 0; delay--) {
+ while (serial_data_ready(iobase)) {
+ uint8_t car = serial_read_data(iobase);
+
+ // Is this something we recognize ?
+ dprintf("received serial data after reset: 0x%hx '%c'\n", car, car);
+ if (car == 'M') {
+ // Ok, got the MS signature, break out of this wait
+ sig1 = car;
+ break;
+ }
+ }
+
+ if (sig1) break;
+ bda_wait_tick();
+ dprintf("remaining ticks %u\n", delay);
+ }
+
+
+ if (sig1 == 'M') {
+ // We have a valid MS-style serial mouse
+ data->port = port;
+ data->device_id = 'M';
+ data->port_io = iobase;
+ data->port_irq = serial_get_irq(port);
+ data->num_buttons = 2;
+#if USE_WHEEL
+ data->num_wheels = 0;
+#endif
+ data->packet_size = 3;
+
+ // Should we wait for an extended signature? Let's do it
+ for (delay = 2; delay > 0; delay--) {
+ while (serial_data_ready(iobase)) {
+ uint8_t car = serial_read_data(iobase);
+
+ dprintf("received serial data after '%c': 0x%hx '%c'\n", sig1, car, car);
+ if (car == '3') {
+ // Ok, got the MS signature, break out of this wait
+ sig2 = car;
+ break;
+ }
+ }
+
+ if (sig2) break;
+ bda_wait_tick();
+ dprintf("2nd loop remaining ticks %u\n", delay);
+ }
+
+ if (sig2 == '3') {
+ data->device_id = '3';
+ data->num_buttons = 3;
+ }
+
+ // In any case, we got ourselves a mouse.
+ return 0;
+ }
+
+ // No mouse found on this port.
+ serial_restore_config(iobase, &serconfig);
+ return -2;
+}
+#endif
+
+/// Auto-configure the TSR. Try to detect which mouse we have connected and enable all possible integrations.
+static int configure_driver(LPTSRDATA data, unsigned num_ports, int ports[])
+{
+ int errs[MAX_PORTS+1] = {0};
+ unsigned portidx;
+
+ // Configure the debug logging port
+ dlog_init();
+
+ for (portidx = 0; portidx < num_ports; portidx++) {
+ int port = ports[portidx];
+ if (port == 0) {
+ // PS/2
+ int err = configure_driver_ps2(data);
+ if (!err) {
+ unsigned num_wheels = 0;
+#if USE_WHEEL
+ num_wheels = data->num_wheels;
+#endif
+ printf(_(1, 0, "Found PS/2 mouse with %u buttons, %u wheels\n"), data->num_buttons, num_wheels);
+ return 0;
+ } else {
+ // Remember error to print out later only if no mouse was found
+ errs[portidx] = err;
+ }
+ } else {
+#if USE_SERIAL
+ int err = configure_driver_serial(data, port, serial_get_iobase(port));
+ if (!err) {
+ unsigned num_wheels = 0;
+#if USE_WHEEL
+ num_wheels = data->num_wheels;
+#endif
+ printf(_(1, 22, "Found serial mouse on COM%u with %u buttons, %u wheels\n"), port, data->num_buttons, num_wheels);
+ return 0;
+ } else {
+ errs[portidx] = err;
+ }
+#endif
+ }
+ }
+
+ // If we are here, we have neither serial nor PS/2.
+ // Print all error messages now.
+ for (portidx = 0; portidx < num_ports; portidx++) {
+ int port = ports[portidx];
+ int err = errs[portidx];
+
+ if (err) {
+ if (port == 0) {
+ fprintf(stderr, _(3, 8, "Cannot init PS/2 mouse BIOS, err=%d\n"), err);
+ } else {
+ fprintf(stderr, _(3, 15, "Cannot find mouse in COM%u, err=%d\n"), port, err);
+ }
+ }
+ }
+
+ fprintf(stderr, _(3, 14, "No mouse found\n"));
+
+ return -1;
+}
+
static int move_driver_to_umb(LPTSRDATA __far * data)
{
segment_t cur_seg = FP_SEG(*data);
@@ -332,6 +501,16 @@ static __declspec(aborts) int install_driver(LPTSRDATA data, bool high)
data->prev_int33_handler = _dos_getvect(0x33);
_dos_setvect(0x33, data:>int33_isr);
+ data->prev_irq3_4_handler = 0;
+#if USE_SERIAL
+ if (data->port_irq) {
+ dprintf("Hooking irq%hu (int%x) for serial\n", data->port_irq, 0x8 + data->port_irq);
+ data->prev_irq3_4_handler = _dos_getvect(0x8 + data->port_irq);
+ _dos_setvect(0x8 + data->port_irq, data:>irq3_4_isr);
+ }
+#endif
+
+ data->prev_int2f_handler = 0;
#if USE_WIN386
data->prev_int2f_handler = _dos_getvect(0x2f);
_dos_setvect(0x2f, data:>int2f_isr);
@@ -359,16 +538,27 @@ static bool check_if_driver_uninstallable(LPTSRDATA data)
// Compare the segment of the installed handler to see if its ours
// or someone else's
if (FP_SEG(cur_int33_handler) != FP_SEG(data)) {
- fprintf(stderr, _(3, 9, "INT33 has been hooked by someone else, cannot safely remove\n"));
+ fprintf(stderr, _(3, 9, "INT%X has been hooked by someone else, cannot safely remove\n"), 0x33);
return false;
}
+#if USE_SERIAL
+ if (data->port_irq) {
+ void (__interrupt __far *cur_irq3_4_handler)() = _dos_getvect(0x8 + data->port_irq);
+
+ if (FP_SEG(cur_irq3_4_handler) != FP_SEG(data)) {
+ fprintf(stderr, _(3, 9, "INT%X has been hooked by someone else, cannot safely remove\n"), 0x8 + data->port_irq);
+ return false;
+ }
+ }
+#endif
+
#if USE_WIN386
{
void (__interrupt __far *cur_int2f_handler)() = _dos_getvect(0x2f);
if (FP_SEG(cur_int2f_handler) != FP_SEG(data)) {
- fprintf(stderr, _(3, 10, "INT2F has been hooked by someone else, cannot safely remove\n"));
+ fprintf(stderr, _(3, 9, "INT%X has been hooked by someone else, cannot safely remove\n"), 0x2F);
return false;
}
}
@@ -379,12 +569,28 @@ static bool check_if_driver_uninstallable(LPTSRDATA data)
static int unconfigure_driver(LPTSRDATA data)
{
+ if (data->port == 0) {
+ // PS/2 mode
+
+ // Turn off PS2 BIOS, and remove callback
+ ps2m_enable(false);
+ ps2m_set_callback(0);
+
#if USE_INTEGRATION
- set_integration(data, false);
+ set_integration(data, false, false);
#endif
+ } else {
+#if USE_SERIAL
+ // Serial mode
+ uint16_t iobase = data->port_io;
- ps2m_enable(false);
- ps2m_set_callback(0);
+ // Disable interrupts, and clear RTS/DTS, which should completely power down mouse
+ serial_configure_interrupts(iobase, 0);
+ serial_set_modem_control(iobase, 0);
+
+ // TODO Should I mask the serial IRQ on the PIC too?
+#endif
+ }
return 0;
}
@@ -393,6 +599,12 @@ static int uninstall_driver(LPTSRDATA data)
{
_dos_setvect(0x33, data->prev_int33_handler);
+#if USE_SERIAL
+ if (data->port_irq) {
+ _dos_setvect(0x8 + data->port_irq, data->prev_irq3_4_handler);
+ }
+#endif
+
#if USE_WIN386
_dos_setvect(0x2f, data->prev_int2f_handler);
#endif
@@ -409,7 +621,7 @@ static int uninstall_driver(LPTSRDATA data)
static int driver_reset(void)
{
printf(_(1, 19, "Reset mouse driver\n"));
- return int33_reset() == 0xFFFF;
+ return int33_reset() == INT33_MOUSE_FOUND;
}
static int driver_not_found(void)
@@ -476,6 +688,21 @@ static bool is_false(const char *s)
|| stricmp(s, "0") == 0;
}
+static int parse_port(const char *s)
+{
+ if (stricmp(s, "ps2") == 0) {
+ return 0;
+#if USE_SERIAL
+ } else if (strnicmp(s, "com", 3) == 0 && s[4] == '\0'
+ && s[3] >= '0' && s[3] <= '9') {
+ // "COMn" string
+ return s[3] - '0';
+#endif
+ } else {
+ return -1;
+ }
+}
+
int main(int argc, const char *argv[])
{
LPTSRDATA data = get_tsr_data(true);
@@ -487,6 +714,9 @@ int main(int argc, const char *argv[])
if (argi >= argc || stricmp(argv[argi], "install") == 0) {
bool high = true;
+ int portidx = 0, port;
+ // Default search order (PS2, COM1, COM2, COM3...)
+ int ports[1+MAX_PORTS] = {-1};
argi++;
for (; argi < argc; argi++) {
@@ -494,11 +724,25 @@ int main(int argc, const char *argv[])
high = false;
} else if (stricmp(argv[argi], "high") == 0) {
high = true;
+ } else if ((port = parse_port(argv[argi])) >= 0) {
+ if (portidx > MAX_PORTS) return invalid_arg(argv[argi]);
+ if (port < 0 || port > MAX_PORTS) return invalid_arg(argv[argi]);
+ ports[portidx++] = port;
} else {
return invalid_arg(argv[argi]);
}
}
+ if (!portidx) {
+ // User has not specified custom search order, so init with default
+ const unsigned num_com_ports = MIN(serial_num_ports(), MAX_PORTS);
+ if (ps2m_installed()) ports[portidx++] = 0; // 1st. PS2
+ // 2nd. COMn in order
+ for (port = 1; port <= num_com_ports; port++) {
+ ports[portidx++] = port;
+ }
+ }
+
if (data) {
printf(_(1, 21, "VBMouse already installed\n"));
print_help();
@@ -512,7 +756,7 @@ int main(int argc, const char *argv[])
} else {
deallocate_environment(_psp);
}
- err = configure_driver(data);
+ err = configure_driver(data, portidx, ports);
if (err) {
if (high) cancel_reallocation(FP_SEG(data));
return EXIT_FAILURE;
@@ -588,7 +832,7 @@ int main(int argc, const char *argv[])
if (is_false(argv[argi])) enable = false;
}
- return set_integration(data, enable);
+ return set_integration(data, enable, true);
} else if (stricmp(argv[argi], "hostcur") == 0) {
bool enable = true;