From: Kirill Zhumarin kirill.zhumarin@gmail.com
--- configure.ac | 1 + dlls/ntdll/Makefile.in | 1 + dlls/ntdll/unix/serial.c | 12 ++++ dlls/ntdll/unix/serial_termios2.c | 109 ++++++++++++++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 4 ++ include/config.h.in | 3 + 6 files changed, 130 insertions(+) create mode 100644 dlls/ntdll/unix/serial_termios2.c
diff --git a/configure.ac b/configure.ac index 64083de89c4..1a7361763a5 100644 --- a/configure.ac +++ b/configure.ac @@ -388,6 +388,7 @@ AC_CHECK_HEADERS(\ OpenCL/opencl.h \ arpa/inet.h \ arpa/nameser.h \ + asm/termbits.h \ asm/types.h \ asm/user.h \ elf.h \ 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/unix/serial.c b/dlls/ntdll/unix/serial.c index 372103b4df8..73c1e176c4a 100644 --- a/dlls/ntdll/unix/serial.c +++ b/dlls/ntdll/unix/serial.c @@ -121,6 +121,12 @@ static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr) { struct termios port; int speed; + int status; + + /* If termios2 is supported, first try to use it. Otherwise, use termios as a fallback. */ + status = serial_get_baud_rate_termios2(fd, &sbr->BaudRate); + if (status != STATUS_NOT_SUPPORTED) + return status;
if (tcgetattr(fd, &port) == -1) { @@ -454,6 +460,12 @@ static NTSTATUS purge(int fd, DWORD flags) static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr) { struct termios port; + int status; + + /* If termios2 is supported, first try to use it. Otherwise, use termios as a fallback. */ + status = serial_set_baud_rate_termios2(fd, sbr->BaudRate); + if (status != STATUS_NOT_SUPPORTED) + return status;
if (tcgetattr(fd, &port) == -1) { diff --git a/dlls/ntdll/unix/serial_termios2.c b/dlls/ntdll/unix/serial_termios2.c new file mode 100644 index 00000000000..45f48bc4f2f --- /dev/null +++ b/dlls/ntdll/unix/serial_termios2.c @@ -0,0 +1,109 @@ +/* + * 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" + +#if defined(HAVE_ASM_TERMBITS_H) && defined(TCGETS2) + +WINE_DEFAULT_DEBUG_CHANNEL(comm); + +NTSTATUS serial_set_baud_rate_termios2(int fd, ULONG baudrate) +{ + struct termios2 port; + + if (ioctl(fd, TCGETS2, &port) == -1) + { + /* This is an old kernel, TCGETS2 is not present. */ + if (errno == EINVAL) + return STATUS_NOT_SUPPORTED; + + 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, ULONG* baudrate) +{ + struct termios2 port; + + if (ioctl(fd, TCGETS2, &port) == -1) + { + /* This is an old kernel, TCGETS2 is not present. */ + if (errno == EINVAL) + return STATUS_NOT_SUPPORTED; + + 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_ospeed; + + return STATUS_SUCCESS; +} +#else +NTSTATUS serial_set_baud_rate_termios2(int fd, ULONG baudrate) +{ + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS serial_get_baud_rate_termios2(int fd, ULONG* baudrate) +{ + return STATUS_NOT_SUPPORTED; +} +#endif diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index b249570d421..1823299b8b9 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -308,6 +308,10 @@ 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 ); + +extern NTSTATUS serial_set_baud_rate_termios2( int fd, ULONG baudrate ); +extern NTSTATUS serial_get_baud_rate_termios2( int fd, ULONG *baudrate ); + 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..ee92b4a5024 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -12,6 +12,9 @@ /* Define to 1 if you have the <arpa/nameser.h> header file. */ #undef HAVE_ARPA_NAMESER_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 <asm/types.h> header file. */ #undef HAVE_ASM_TYPES_H