From: Kirill Zhumarin kirill.zhumarin@gmail.com
--- configure | 6 ++ dlls/ntdll/Makefile.in | 1 + .../ntdll/i386-windows/unix/serial_termios2.o | 0 dlls/ntdll/unix/serial.c | 14 +++ dlls/ntdll/unix/serial_termios2.c | 87 +++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 6 ++ include/config.h.in | 3 + 7 files changed, 117 insertions(+) create mode 100644 dlls/ntdll/i386-windows/unix/serial_termios2.o create mode 100644 dlls/ntdll/unix/serial_termios2.c
diff --git a/configure b/configure index 83a641ff542..bc8141dfe67 100755 --- a/configure +++ b/configure @@ -7989,6 +7989,12 @@ if test "x$ac_cv_header_linux_serial_h" = xyes then : printf "%s\n" "#define HAVE_LINUX_SERIAL_H 1" >>confdefs.h
+fi +ac_fn_c_check_header_compile "$LINENO" "asm/termbits.h" "ac_cv_header_asm_termbits_h" "$ac_includes_default" +if test "x$ac_cv_header_asm_termbits_h" = xyes +then : + printf "%s\n" "#define HAVE_ASM_TERMBITS_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" if test "x$ac_cv_header_linux_types_h" = xyes diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index b519bcd655f..d6fa26ea1d3 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -55,6 +55,7 @@ SOURCES = \ unix/registry.c \ unix/security.c \ unix/serial.c \ + unix/serial_termios2.c \ unix/server.c \ unix/signal_arm.c \ unix/signal_arm64.c \ diff --git a/dlls/ntdll/i386-windows/unix/serial_termios2.o b/dlls/ntdll/i386-windows/unix/serial_termios2.o new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dlls/ntdll/unix/serial.c b/dlls/ntdll/unix/serial.c index 372103b4df8..b4601bfeb3c 100644 --- a/dlls/ntdll/unix/serial.c +++ b/dlls/ntdll/unix/serial.c @@ -122,6 +122,14 @@ static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr) struct termios port; int speed;
+#ifdef HAVE_ASM_TERMBITS_H + /* If termios2 is supported, first try to use it. Otherwise, use termios as a fallback. */ + if (serial_get_baud_rate_termios2(fd, &speed) == STATUS_SUCCESS) { + sbr->BaudRate = speed; + return STATUS_SUCCESS; + } +#endif + if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); @@ -455,6 +463,12 @@ static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr) { struct termios port;
+#ifdef HAVE_ASM_TERMBITS_H + /* If termios2 is supported, first try to use it. Otherwise, use termios as a fallback. */ + if (serial_set_baud_rate_termios2(fd, sbr->BaudRate) == STATUS_SUCCESS) + return STATUS_SUCCESS; +#endif + if (tcgetattr(fd, &port) == -1) { ERR("tcgetattr error '%s'\n", strerror(errno)); diff --git a/dlls/ntdll/unix/serial_termios2.c b/dlls/ntdll/unix/serial_termios2.c new file mode 100644 index 00000000000..84be6ac6b5f --- /dev/null +++ b/dlls/ntdll/unix/serial_termios2.c @@ -0,0 +1,87 @@ +/* + * Linux termios2 support + * + * Copyright 2024 Kirill Zhumarin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include <errno.h> +#include <sys/ioctl.h> +#ifdef HAVE_ASM_TERMBITS_H +#include <asm/termbits.h> +#endif + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "winioctl.h" +#include "ddk/ntddser.h" +#include "wine/server.h" +#include "unix_private.h" +#include "wine/debug.h" +#include "unix_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(comm); + +#ifdef HAVE_ASM_TERMBITS_H +NTSTATUS serial_set_baud_rate_termios2( int fd, int baudrate ) { + struct termios2 port; + + if (ioctl(fd, TCGETS2, &port) == -1) + { + ERR("ioctl TCGETS2 error '%s'\n", strerror(errno)); + return errno_to_status( errno ); + } + + port.c_cflag &= ~CBAUD; + port.c_cflag |= BOTHER; + port.c_ospeed = baudrate; + + port.c_cflag &= ~(CBAUD << IBSHIFT); + port.c_cflag |= BOTHER << IBSHIFT; + port.c_ispeed = baudrate; + + if (ioctl(fd, TCSETS2, &port) == -1) + { + ERR("ioctl TCSETS2 error '%s'\n", strerror(errno)); + return errno_to_status( errno ); + } + + return STATUS_SUCCESS; +} + +NTSTATUS serial_get_baud_rate_termios2( int fd, int* baudrate ) { + struct termios2 port; + + if (ioctl(fd, TCGETS2, &port) == -1) + { + ERR("ioctl TCGETS2 error '%s'\n", strerror(errno)); + return errno_to_status( errno ); + } + + /* TERMIOS2 supports separate input and output baudrate, but wine supports only the common baudrate. */ + *baudrate = port.c_ispeed; + + return STATUS_SUCCESS; +} +#endif diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index b249570d421..1fc8a65ef4e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -308,6 +308,12 @@ extern NTSTATUS serial_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROU IO_STATUS_BLOCK *io, UINT code, void *in_buffer, UINT in_size, void *out_buffer, UINT out_size ); extern NTSTATUS serial_FlushBuffersFile( int fd ); + +#ifdef HAVE_ASM_TERMBITS_H +extern NTSTATUS serial_set_baud_rate_termios2( int fd, int baudrate ); +extern NTSTATUS serial_get_baud_rate_termios2( int fd, int *baudrate ); +#endif + extern NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, UINT code, void *in_buffer, UINT in_size, void *out_buffer, UINT out_size ); extern NTSTATUS sock_read( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, diff --git a/include/config.h.in b/include/config.h.in index a910b2c85f1..68b8c932bf7 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -183,6 +183,9 @@ /* Define to 1 if you have the <linux/serial.h> header file. */ #undef HAVE_LINUX_SERIAL_H
+/* Define to 1 if you have the <asm/termbits.h> header file. */ +#undef HAVE_ASM_TERMBITS_H + /* Define to 1 if you have the <linux/types.h> header file. */ #undef HAVE_LINUX_TYPES_H