linux: implement arbitrary and split speeds in termios
Linux has supported arbitrary speeds and split speeds in the kernel
since 2008 on all platforms except Alpha (fixed in 2020), but glibc
was never updated to match. This is further complicated by POSIX uses
of macros for the cf[gs]et[io]speed interfaces, rather than plain
numbers, as it really ought to have.
On most platforms, the glibc ABI includes the c_[io]speed fields in
struct termios, but they are incorrectly used. On MIPS and SPARC, they
are entirely missing.
For backwards compatibility, the kernel will still use the legacy
speed fields unless they are set to BOTHER, and will use the legacy
output speed as the input speed if the latter is 0 (== B0). However,
the specific encoding used is visible to user space applications,
including ones other than the one running.
- SPARC and MIPS get a new struct termios, and tc[gs]etattr() is
versioned accordingly. However, the new struct termios is set to be
a strict extension of the old one, which means that cf* interfaces
other than the speed-related ones do not need versioning.
- The Bxxx constants are redefined as equivalent to their integer
values and the legacy Bxxx constants are renamed __Bxxx.
- cf[gs]et[io]speed() and cfsetspeed() are versioned accordingly.
- tcgetattr() and cfset[io]speed() are adjusted to always keep the
c_[io]speed fields correct (unlike earlier versions), but to
canonicalize the representation to ALSO configure the legacy fields
if a valid legacy representation exists.
- tcsetattr(), too, canonicalizes the representation in this way
before passing it to the kernel, to maximize compatibility with
older applications/tools.
- The old IBAUD0 hack is removed; it is no longer necessary since
even the legacy c_cflag baud rate fields have had separate input
values for a long time.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2025-06-12 01:35:36 +00:00
|
|
|
/* termios functions internal implementation header for Linux
|
|
|
|
|
|
|
|
Copyright (C) 1991-2025 Free Software Foundation, Inc.
|
|
|
|
This file is part of the GNU C Library.
|
|
|
|
|
|
|
|
The GNU C 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.
|
|
|
|
|
|
|
|
The GNU C 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 the GNU C Library; if not, see
|
|
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#ifndef TERMIOS_INTERNALS_H
|
|
|
|
#define TERMIOS_INTERNALS_H 1
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <termios.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sysdep.h>
|
|
|
|
#include <shlib-compat.h>
|
|
|
|
|
2025-07-11 14:04:07 +00:00
|
|
|
#include <termios-kernel-consts.h>
|
|
|
|
|
|
|
|
/* Alpha got termios2 late, but TCGETS has exactly the same structure
|
|
|
|
format and function as TCGETS2. On all other platforms, the termios2
|
|
|
|
interface exists as far back as this version of glibc supports.
|
|
|
|
|
|
|
|
For TCSETS* it is more complicated; this is handled in tcsetattr.c. */
|
|
|
|
#ifdef __ASSUME_TERMIOS2
|
|
|
|
# define ARCH_TCGETS KERNEL_TCGETS2
|
|
|
|
#else
|
|
|
|
# define ARCH_TCGETS KERNEL_TCGETS
|
|
|
|
#endif
|
linux: implement arbitrary and split speeds in termios
Linux has supported arbitrary speeds and split speeds in the kernel
since 2008 on all platforms except Alpha (fixed in 2020), but glibc
was never updated to match. This is further complicated by POSIX uses
of macros for the cf[gs]et[io]speed interfaces, rather than plain
numbers, as it really ought to have.
On most platforms, the glibc ABI includes the c_[io]speed fields in
struct termios, but they are incorrectly used. On MIPS and SPARC, they
are entirely missing.
For backwards compatibility, the kernel will still use the legacy
speed fields unless they are set to BOTHER, and will use the legacy
output speed as the input speed if the latter is 0 (== B0). However,
the specific encoding used is visible to user space applications,
including ones other than the one running.
- SPARC and MIPS get a new struct termios, and tc[gs]etattr() is
versioned accordingly. However, the new struct termios is set to be
a strict extension of the old one, which means that cf* interfaces
other than the speed-related ones do not need versioning.
- The Bxxx constants are redefined as equivalent to their integer
values and the legacy Bxxx constants are renamed __Bxxx.
- cf[gs]et[io]speed() and cfsetspeed() are versioned accordingly.
- tcgetattr() and cfset[io]speed() are adjusted to always keep the
c_[io]speed fields correct (unlike earlier versions), but to
canonicalize the representation to ALSO configure the legacy fields
if a valid legacy representation exists.
- tcsetattr(), too, canonicalizes the representation in this way
before passing it to the kernel, to maximize compatibility with
older applications/tools.
- The old IBAUD0 hack is removed; it is no longer necessary since
even the legacy c_cflag baud rate fields have had separate input
values for a long time.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2025-06-12 01:35:36 +00:00
|
|
|
|
|
|
|
/* ---- Kernel interface definitions ---- */
|
|
|
|
|
|
|
|
/* The the termios2 structure used in the kernel interfaces is not the
|
|
|
|
same as the termios structure we use in the libc. Therefore we
|
|
|
|
must translate it here. */
|
|
|
|
|
|
|
|
struct termios2
|
|
|
|
{
|
|
|
|
tcflag_t c_iflag; /* input mode flags */
|
|
|
|
tcflag_t c_oflag; /* output mode flags */
|
|
|
|
tcflag_t c_cflag; /* control mode flags */
|
|
|
|
tcflag_t c_lflag; /* local mode flags */
|
2025-07-11 14:04:07 +00:00
|
|
|
#if KERNEL_TERMIOS2_CC_OFFSET < KERNEL_TERMIOS2_LINE_OFFSET
|
linux: implement arbitrary and split speeds in termios
Linux has supported arbitrary speeds and split speeds in the kernel
since 2008 on all platforms except Alpha (fixed in 2020), but glibc
was never updated to match. This is further complicated by POSIX uses
of macros for the cf[gs]et[io]speed interfaces, rather than plain
numbers, as it really ought to have.
On most platforms, the glibc ABI includes the c_[io]speed fields in
struct termios, but they are incorrectly used. On MIPS and SPARC, they
are entirely missing.
For backwards compatibility, the kernel will still use the legacy
speed fields unless they are set to BOTHER, and will use the legacy
output speed as the input speed if the latter is 0 (== B0). However,
the specific encoding used is visible to user space applications,
including ones other than the one running.
- SPARC and MIPS get a new struct termios, and tc[gs]etattr() is
versioned accordingly. However, the new struct termios is set to be
a strict extension of the old one, which means that cf* interfaces
other than the speed-related ones do not need versioning.
- The Bxxx constants are redefined as equivalent to their integer
values and the legacy Bxxx constants are renamed __Bxxx.
- cf[gs]et[io]speed() and cfsetspeed() are versioned accordingly.
- tcgetattr() and cfset[io]speed() are adjusted to always keep the
c_[io]speed fields correct (unlike earlier versions), but to
canonicalize the representation to ALSO configure the legacy fields
if a valid legacy representation exists.
- tcsetattr(), too, canonicalizes the representation in this way
before passing it to the kernel, to maximize compatibility with
older applications/tools.
- The old IBAUD0 hack is removed; it is no longer necessary since
even the legacy c_cflag baud rate fields have had separate input
values for a long time.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2025-06-12 01:35:36 +00:00
|
|
|
cc_t c_cc[_TERMIOS2_NCCS]; /* control characters */
|
|
|
|
cc_t c_line; /* line discipline */
|
|
|
|
#else
|
|
|
|
cc_t c_line; /* line discipline */
|
|
|
|
cc_t c_cc[_TERMIOS2_NCCS]; /* control characters */
|
|
|
|
#endif
|
|
|
|
speed_t c_ispeed; /* input speed */
|
|
|
|
speed_t c_ospeed; /* output speed */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ---- Application interface definitions ---- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Should old speed_t and struct termios (if applicable) compatibility
|
|
|
|
* functions be included?
|
|
|
|
*/
|
|
|
|
#define _TERMIOS_OLD_COMPAT SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_42)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Old struct termios (without c_ispeed and c_ospeed fields) if
|
|
|
|
* applicable. The new struct termios *must* be binary identical up to
|
|
|
|
* the sizeof the old structure.
|
|
|
|
*
|
|
|
|
* This only applies to SPARC and MIPS; for other architectures the
|
|
|
|
* new and old speed_t interfaces both use the same struct termios.
|
|
|
|
*/
|
2025-07-11 14:04:07 +00:00
|
|
|
#include <old_termios.h>
|
linux: implement arbitrary and split speeds in termios
Linux has supported arbitrary speeds and split speeds in the kernel
since 2008 on all platforms except Alpha (fixed in 2020), but glibc
was never updated to match. This is further complicated by POSIX uses
of macros for the cf[gs]et[io]speed interfaces, rather than plain
numbers, as it really ought to have.
On most platforms, the glibc ABI includes the c_[io]speed fields in
struct termios, but they are incorrectly used. On MIPS and SPARC, they
are entirely missing.
For backwards compatibility, the kernel will still use the legacy
speed fields unless they are set to BOTHER, and will use the legacy
output speed as the input speed if the latter is 0 (== B0). However,
the specific encoding used is visible to user space applications,
including ones other than the one running.
- SPARC and MIPS get a new struct termios, and tc[gs]etattr() is
versioned accordingly. However, the new struct termios is set to be
a strict extension of the old one, which means that cf* interfaces
other than the speed-related ones do not need versioning.
- The Bxxx constants are redefined as equivalent to their integer
values and the legacy Bxxx constants are renamed __Bxxx.
- cf[gs]et[io]speed() and cfsetspeed() are versioned accordingly.
- tcgetattr() and cfset[io]speed() are adjusted to always keep the
c_[io]speed fields correct (unlike earlier versions), but to
canonicalize the representation to ALSO configure the legacy fields
if a valid legacy representation exists.
- tcsetattr(), too, canonicalizes the representation in this way
before passing it to the kernel, to maximize compatibility with
older applications/tools.
- The old IBAUD0 hack is removed; it is no longer necessary since
even the legacy c_cflag baud rate fields have had separate input
values for a long time.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
2025-06-12 01:35:36 +00:00
|
|
|
|
|
|
|
/* ---- Internal function definitions ---- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy a set of c_cc fields of possibly different width. If the target
|
|
|
|
* field is longer, then fill with _POSIX_VDISABLE == -1.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
copy_c_cc (cc_t *to, size_t nto, const cc_t *from, size_t nfrom)
|
|
|
|
{
|
|
|
|
if (nto < nfrom)
|
|
|
|
nfrom = nto;
|
|
|
|
|
|
|
|
to = __mempcpy (to, from, nfrom * sizeof(cc_t));
|
|
|
|
if (nto > nfrom)
|
|
|
|
memset (to, _POSIX_VDISABLE, (nto - nfrom) * sizeof(cc_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract the output and input legacy speed fields from c_cflag. */
|
|
|
|
static inline tcflag_t
|
|
|
|
cbaud (tcflag_t c_cflag)
|
|
|
|
{
|
|
|
|
return c_cflag & CBAUD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline tcflag_t
|
|
|
|
cibaud (tcflag_t c_cflag)
|
|
|
|
{
|
|
|
|
return cbaud (c_cflag >> IBSHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern speed_t
|
|
|
|
___cbaud_to_speed (tcflag_t c_cflag, speed_t other)
|
|
|
|
__attribute_const__ attribute_hidden;
|
|
|
|
|
|
|
|
extern tcflag_t
|
|
|
|
___speed_to_cbaud (speed_t speed)
|
|
|
|
__attribute_const__ attribute_hidden;
|
|
|
|
|
|
|
|
extern void
|
|
|
|
___termios2_canonicalize_speeds (struct termios2 *k_termios_p)
|
|
|
|
attribute_hidden;
|
|
|
|
|
|
|
|
#endif /* TERMIOS_INTERNALS_H */
|