From 63bb0d8a92481392922910703d27cf3464def09f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 30 Aug 2025 01:18:20 +0600 Subject: [PATCH] Pass through serial lines between serial port and emulator --- src/device/serial_passthrough.c | 2 + src/include/86box/plat_serial_passthrough.h | 1 + src/qt/win_serial_passthrough.c | 44 ++++++++++++++++++++- src/unix/unix_serial_passthrough.c | 31 +++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 426bfbc7b..249380b4f 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -75,6 +75,8 @@ host_to_serial_cb(void *priv) uint8_t byte; + plat_serpt_set_line_state(priv); + /* write_fifo has no failure indication, but if we write to fast, the host * can never fetch the bytes in time, so check if the fifo is full if in * fifo mode or if lsr has bit 0 set if not in fifo mode */ diff --git a/src/include/86box/plat_serial_passthrough.h b/src/include/86box/plat_serial_passthrough.h index 60674ea58..ec9a96545 100644 --- a/src/include/86box/plat_serial_passthrough.h +++ b/src/include/86box/plat_serial_passthrough.h @@ -30,6 +30,7 @@ extern int plat_serpt_read(void *priv, uint8_t *data); extern int plat_serpt_open_device(void *priv); extern void plat_serpt_close(void *priv); extern void plat_serpt_set_params(void *priv); +extern void plat_serpt_set_line_state(void *priv); #ifdef __cplusplus } diff --git a/src/qt/win_serial_passthrough.c b/src/qt/win_serial_passthrough.c index 4ea6a1875..d00cf0dd2 100644 --- a/src/qt/win_serial_passthrough.c +++ b/src/qt/win_serial_passthrough.c @@ -82,10 +82,31 @@ plat_serpt_write_vcon(serial_passthrough_t *dev, uint8_t data) WriteFile((HANDLE) dev->master_fd, &data, 1, &bytesWritten, NULL); } +void +plat_serpt_set_line_state(void *priv) +{ + const serial_passthrough_t *dev = (serial_passthrough_t *) priv; + + if (dev->mode == SERPT_MODE_HOSTSER) { + DWORD msrstate; + EscapeCommFunction((HANDLE) dev->master_fd, (dev->serial->mctrl & 1) ? SETDTR : CLRDTR); + EscapeCommFunction((HANDLE) dev->master_fd, (dev->serial->mctrl & 2) ? SETRTS : CLRRTS); + EscapeCommFunction((HANDLE) dev->master_fd, (dev->serial->lcr & (1 << 6) ? SETBREAK : CLRBREAK)); + + if (GetCommModemStatus((HANDLE) dev->master_fd, &msrstate)) { + serial_set_dcd(dev->serial, !!(msrstate & MS_RLSD_ON)); + serial_set_dsr(dev->serial, !!(msrstate & MS_DSR_ON)); + serial_set_cts(dev->serial, !!(msrstate & MS_CTS_ON)); + serial_set_ri(dev->serial, !!(msrstate & MS_RING_ON)); + } + } +} + void plat_serpt_set_params(void *priv) { const serial_passthrough_t *dev = (serial_passthrough_t *) priv; + WINBOOL result; if (dev->mode == SERPT_MODE_HOSTSER) { DCB serialattr = { 0 }; @@ -108,6 +129,13 @@ plat_serpt_set_params(void *priv) BAUDRATE_RANGE(dev->baudrate, 57600, 115200); BAUDRATE_RANGE(dev->baudrate, 115200, 0xFFFFFFFF); + serialattr.fRtsControl = RTS_CONTROL_ENABLE; + serialattr.fDtrControl = DTR_CONTROL_ENABLE; + serialattr.fDsrSensitivity = FALSE; + serialattr.fAbortOnError = FALSE; + + serialattr.fInX = FALSE; + serialattr.fOutX = FALSE; serialattr.ByteSize = dev->data_bits; serialattr.StopBits = (dev->serial->lcr & 0x04) ? TWOSTOPBITS : ONESTOPBIT; if (!(dev->serial->lcr & 0x08)) { @@ -122,7 +150,21 @@ plat_serpt_set_params(void *priv) } } - SetCommState((HANDLE) dev->master_fd, &serialattr); + result = SetCommState((HANDLE) dev->master_fd, &serialattr); + + { + DWORD msrstate; + EscapeCommFunction((HANDLE) dev->master_fd, (dev->serial->mctrl & 1) ? SETDTR : CLRDTR); + EscapeCommFunction((HANDLE) dev->master_fd, (dev->serial->mctrl & 2) ? SETRTS : CLRRTS); + EscapeCommFunction((HANDLE) dev->master_fd, (dev->serial->lcr & (1 << 6) ? SETBREAK : CLRBREAK)); + + if (GetCommModemStatus((HANDLE) dev->master_fd, &msrstate)) { + serial_set_dcd(dev->serial, !!(msrstate & MS_RLSD_ON)); + serial_set_dsr(dev->serial, !!(msrstate & MS_DSR_ON)); + serial_set_cts(dev->serial, !!(msrstate & MS_CTS_ON)); + serial_set_ri(dev->serial, !!(msrstate & MS_RING_ON)); + } + } #undef BAUDRATE_RANGE } } diff --git a/src/unix/unix_serial_passthrough.c b/src/unix/unix_serial_passthrough.c index f6f953eee..fb74f67b3 100644 --- a/src/unix/unix_serial_passthrough.c +++ b/src/unix/unix_serial_passthrough.c @@ -36,6 +36,7 @@ #include #include #include +#include #include <86box/86box.h> #include <86box/log.h> @@ -48,6 +49,35 @@ #define LOG_PREFIX "serial_passthrough: " +void +plat_serpt_set_line_state(void *priv) +{ + serial_passthrough_t *dev = (serial_passthrough_t *) priv; + int setstate = 0, clrstate = 0, curstate = 0; + if (dev->mode != SERPT_MODE_HOSTSER) + return; + + if (dev->serial->lcr & (1 << 6)) { + tcsendbreak(dev->master_fd, 0); + } + + ioctl(dev->master_fd, TIOCMGET, &curstate); + + clrstate |= !(dev->serial->mctrl & 1) ? TIOCM_DTR : 0; + clrstate |= !(dev->serial->mctrl & 2) ? TIOCM_RTS : 0; + + setstate |= (dev->serial->mctrl & 1) ? TIOCM_DTR : 0; + setstate |= (dev->serial->mctrl & 2) ? TIOCM_RTS : 0; + + ioctl(dev->master_fd, TIOCMBIS, &setstate); + ioctl(dev->master_fd, TIOCMBIC, &clrstate); + + serial_set_cts(dev->serial, !!(curstate & TIOCM_CTS)); + serial_set_dcd(dev->serial, !!(curstate & TIOCM_CAR)); + serial_set_dsr(dev->serial, !!(curstate & TIOCM_DSR)); + serial_set_ri(dev->serial, !!(curstate & TIOCM_RI)); +} + int plat_serpt_read(void *priv, uint8_t *data) { @@ -194,6 +224,7 @@ plat_serpt_set_params(void *priv) term_attr.c_cflag |= CMSPAR; #endif } + term_attr.c_iflag &= ~(IXON | IXOFF); tcsetattr(dev->master_fd, TCSANOW, &term_attr); #undef BAUDRATE_RANGE }