diff options
| author | Javier <dev.git@javispedro.com> | 2026-08-30 02:21:09 +0200 |
|---|---|---|
| committer | Javier <dev.git@javispedro.com> | 2026-08-30 02:21:09 +0200 |
| commit | 1b0344660de2832b472b0a413c50ff7f111a9293 (patch) | |
| tree | 5ae7303643d6c9187da6366cf30a4f6a4c73d54b /mousmain.c | |
| parent | 003a26a76982f512e2f3a1108e46b88aa29ab306 (diff) | |
| download | vbados-1b0344660de2832b472b0a413c50ff7f111a9293.tar.gz vbados-1b0344660de2832b472b0a413c50ff7f111a9293.zip | |
first steps towards (optional) serial mouse support
Diffstat (limited to 'mousmain.c')
| -rw-r--r-- | mousmain.c | 306 |
1 files changed, 275 insertions, 31 deletions
@@ -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; |
