diff --git a/src/device/serial_passthrough.c b/src/device/serial_passthrough.c index 25db29096..426bfbc7b 100644 --- a/src/device/serial_passthrough.c +++ b/src/device/serial_passthrough.c @@ -13,7 +13,7 @@ * Jasmine Iwanek * * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #include @@ -222,10 +222,15 @@ serial_passthrough_dev_init(const device_t *info) } const char *serpt_mode_names[SERPT_MODES_MAX] = { - [SERPT_MODE_VCON] = "vcon", - [SERPT_MODE_TCPSRV] = "tcpsrv", - [SERPT_MODE_TCPCLNT] = "tcpclnt", - [SERPT_MODE_HOSTSER] = "hostser", +#ifdef _WIN32 + [SERPT_MODE_NPIPE_SRV] = "npipesrv", + [SERPT_MODE_NPIPE_CLNT] = "npipeclnt", +#else + [SERPT_MODE_VCON] = "vcon", +#endif + [SERPT_MODE_TCP_SRV] = "tcpsrv", + [SERPT_MODE_TCP_CLNT] = "tcpclnt", + [SERPT_MODE_HOSTSER] = "hostser", }; // clang-format off @@ -240,19 +245,17 @@ static const device_config_t serial_passthrough_config[] = { .spinner = { 0 }, .selection = { #ifdef _WIN32 - { .description = "Named Pipe (Server)", .value = SERPT_MODE_VCON }, -#if 0 /* TODO */ - { .description = "Named Pipe (Client)", .value = SERPT_MODE_VCON }, -#endif + { .description = "Named Pipe (Server)", .value = SERPT_MODE_NPIPE_SRV }, + { .description = "Named Pipe (Client)", .value = SERPT_MODE_NPIPE_CLNT }, #else /* _WIN32 */ - { .description = "Pseudo Terminal/Virtual Console", .value = SERPT_MODE_VCON }, + { .description = "Pseudo Terminal/Virtual Console", .value = SERPT_MODE_VCON }, #endif /* _WIN32 */ #if 0 /* TODO */ - { .description = "TCP Server", .value = SERPT_MODE_TCPSRV }, - { .description = "TCP Client", .value = SERPT_MODE_TCPCLNT }, + { .description = "TCP Server", .value = SERPT_MODE_TCP_SRV }, + { .description = "TCP Client", .value = SERPT_MODE_TCP_CLNT }, #endif - { .description = "Host Serial Passthrough", .value = SERPT_MODE_HOSTSER }, - { .description = "" } + { .description = "Host Serial Passthrough", .value = SERPT_MODE_HOSTSER }, + { .description = "" } }, .bios = { { 0 } } }, diff --git a/src/include/86box/serial_passthrough.h b/src/include/86box/serial_passthrough.h index c5454194a..a5fa0013a 100644 --- a/src/include/86box/serial_passthrough.h +++ b/src/include/86box/serial_passthrough.h @@ -13,7 +13,7 @@ * Jasmine Iwanek * * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #ifndef SERIAL_PASSTHROUGH_H @@ -28,10 +28,15 @@ #include <86box/serial.h> enum serial_passthrough_mode { - SERPT_MODE_VCON, /*Named Pipe (Server) / Pseudo Terminal/Virtual Console */ - SERPT_MODE_TCPSRV, /* TCP Server (TODO) */ - SERPT_MODE_TCPCLNT, /* TCP Client (TODO) */ - SERPT_MODE_HOSTSER, /* Host Serial Passthrough */ +#ifdef _WIN32 + SERPT_MODE_NPIPE_SRV, /* Named Pipe (Server) */ + SERPT_MODE_NPIPE_CLNT, /* Named Pipe (Client) */ +#else + SERPT_MODE_VCON, /* Pseudo Terminal/Virtual Console */ +#endif + SERPT_MODE_TCP_SRV, /* TCP Server (TODO) */ + SERPT_MODE_TCP_CLNT, /* TCP Client (TODO) */ + SERPT_MODE_HOSTSER, /* Host Serial Passthrough */ SERPT_MODES_MAX, }; diff --git a/src/qt/win_serial_passthrough.c b/src/qt/win_serial_passthrough.c index c1802ce73..725dc096f 100644 --- a/src/qt/win_serial_passthrough.c +++ b/src/qt/win_serial_passthrough.c @@ -13,7 +13,7 @@ * Jasmine Iwanek * * Copyright 2021 Andreas J. Reichel - * Copyright 2021-2023 Jasmine Iwanek + * Copyright 2021-2025 Jasmine Iwanek */ #define _XOPEN_SOURCE 500 @@ -46,9 +46,9 @@ plat_serpt_close(void *priv) fclose(dev->master_fd); #endif FlushFileBuffers((HANDLE) dev->master_fd); - if (dev->mode == SERPT_MODE_VCON) + if (dev->mode == SERPT_MODE_NPIPE_SRV) DisconnectNamedPipe((HANDLE) dev->master_fd); - if (dev->mode == SERPT_MODE_HOSTSER) { + else if (dev->mode == SERPT_MODE_HOSTSER) { SetCommState((HANDLE) dev->master_fd, (DCB *) dev->backend_priv); free(dev->backend_priv); } @@ -133,7 +133,8 @@ plat_serpt_write(void *priv, uint8_t data) serial_passthrough_t *dev = (serial_passthrough_t *) priv; switch (dev->mode) { - case SERPT_MODE_VCON: + case SERPT_MODE_NPIPE_SRV: + case SERPT_MODE_NPIPE_CLNT: case SERPT_MODE_HOSTSER: plat_serpt_write_vcon(dev, data); break; @@ -157,7 +158,8 @@ plat_serpt_read(void *priv, uint8_t *data) int res = 0; switch (dev->mode) { - case SERPT_MODE_VCON: + case SERPT_MODE_NPIPE_SRV: + case SERPT_MODE_NPIPE_CLNT: case SERPT_MODE_HOSTSER: res = plat_serpt_read_vcon(dev, data); break; @@ -187,6 +189,38 @@ open_pseudo_terminal(serial_passthrough_t *dev) return 1; } +static int +connect_named_pipe_client(serial_passthrough_t *dev) +{ + char ascii_pipe_name[1024] = { 0 }; + strncpy(ascii_pipe_name, dev->named_pipe, sizeof(ascii_pipe_name) - 1); + + HANDLE hPipe = CreateFileA( + ascii_pipe_name, // pipe name + GENERIC_READ | GENERIC_WRITE, + 0, // no sharing + NULL, // default security attributes + OPEN_EXISTING, // open existing pipe + 0, // default attributes + NULL); // no template file + + if (hPipe == INVALID_HANDLE_VALUE) { + DWORD error = GetLastError(); + wchar_t errorMsg[1024] = { 0 }; + wchar_t finalMsg[1024] = { 0 }; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errorMsg, 1024, NULL); + swprintf(finalMsg, 1024, L"Named Pipe (client, named_pipe=\"%hs\", port=COM%d): %ls\n", ascii_pipe_name, dev->port + 1, errorMsg); + ui_msgbox(MBX_ERROR | MBX_FATAL, finalMsg); + return 0; + } + + DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT; + SetNamedPipeHandleState(hPipe, &mode, NULL, NULL); + dev->master_fd = (intptr_t) hPipe; + pclog("Named Pipe client connected to %s\n", ascii_pipe_name); + return 1; +} + static int open_host_serial_port(serial_passthrough_t *dev) { @@ -222,15 +256,18 @@ plat_serpt_open_device(void *priv) serial_passthrough_t *dev = (serial_passthrough_t *) priv; switch (dev->mode) { - case SERPT_MODE_VCON: - if (open_pseudo_terminal(dev)) { + case SERPT_MODE_NPIPE_SRV: + if (open_pseudo_terminal(dev)) + return 0; + break; + case SERPT_MODE_NPIPE_CLNT: + if (connect_named_pipe_client(dev)) return 0; - } break; case SERPT_MODE_HOSTSER: - if (open_host_serial_port(dev)) { + if (open_host_serial_port(dev)) return 0; - } + break; default: break; } diff --git a/src/unix/unix_serial_passthrough.c b/src/unix/unix_serial_passthrough.c index 9929f3298..873c706b9 100644 --- a/src/unix/unix_serial_passthrough.c +++ b/src/unix/unix_serial_passthrough.c @@ -13,7 +13,7 @@ * Jasmine Iwanek * * Copyright 2021 Andreas J. Reichel. - * Copyright 2021-2022 Jasmine Iwanek. + * Copyright 2021-2025 Jasmine Iwanek. */ #ifndef __APPLE__ @@ -310,14 +310,12 @@ plat_serpt_open_device(void *priv) switch (dev->mode) { case SERPT_MODE_VCON: - if (!open_pseudo_terminal(dev)) { + if (!open_pseudo_terminal(dev)) return 1; - } break; case SERPT_MODE_HOSTSER: - if (!open_host_serial_port(dev)) { + if (!open_host_serial_port(dev)) return 1; - } break; default: break;