]>
Commit | Line | Data |
---|---|---|
93b55636 T |
1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
2 | /* | |
3 | * termios fuctions to support arbitrary baudrates (on Linux) | |
4 | * | |
5 | * Copyright (c) 2021 Pali Rohár <[email protected]> | |
6 | * Copyright (c) 2021 Marek Behún <[email protected]> | |
7 | */ | |
8 | ||
9 | #ifndef _TERMIOS_LINUX_H_ | |
10 | #define _TERMIOS_LINUX_H_ | |
11 | ||
12 | /* | |
13 | * We need to use raw TCGETS2/TCSETS2 or TCGETS/TCSETS ioctls with the BOTHER | |
14 | * flag in struct termios2/termios, defined in Linux headers <asm/ioctls.h> | |
15 | * (included by <sys/ioctl.h>) and <asm/termbits.h>. Since these headers | |
16 | * conflict with glibc's header file <termios.h>, it is not possible to use | |
17 | * libc's termios functions and we need to reimplement them via ioctl() calls. | |
18 | * | |
19 | * An arbitrary baudrate is supported when the macro BOTHER is defined. The | |
20 | * baudrate value itself is then stored into the c_ospeed and c_ispeed members. | |
21 | * If ioctls TCGETS2/TCSETS2 are defined and supported then these fields are | |
22 | * present in struct termios2, otherwise these fields are present in struct | |
23 | * termios. | |
24 | * | |
25 | * Note that the Bnnn constants from <termios.h> need not be compatible with Bnnn | |
26 | * constants from <asm/termbits.h>. | |
27 | */ | |
28 | ||
29 | #include <errno.h> | |
30 | #include <sys/ioctl.h> | |
31 | #include <sys/types.h> | |
32 | #include <asm/termbits.h> | |
33 | ||
34 | #if defined(BOTHER) && defined(TCGETS2) | |
35 | #define termios termios2 | |
36 | #endif | |
37 | ||
38 | static inline int tcgetattr(int fd, struct termios *t) | |
39 | { | |
40 | #if defined(BOTHER) && defined(TCGETS2) | |
41 | return ioctl(fd, TCGETS2, t); | |
42 | #else | |
43 | return ioctl(fd, TCGETS, t); | |
44 | #endif | |
45 | } | |
46 | ||
47 | static inline int tcsetattr(int fd, int a, const struct termios *t) | |
48 | { | |
49 | int cmd; | |
50 | ||
51 | switch (a) { | |
52 | #if defined(BOTHER) && defined(TCGETS2) | |
53 | case TCSANOW: | |
54 | cmd = TCSETS2; | |
55 | break; | |
56 | case TCSADRAIN: | |
57 | cmd = TCSETSW2; | |
58 | break; | |
59 | case TCSAFLUSH: | |
60 | cmd = TCSETSF2; | |
61 | break; | |
62 | #else | |
63 | case TCSANOW: | |
64 | cmd = TCSETS; | |
65 | break; | |
66 | case TCSADRAIN: | |
67 | cmd = TCSETSW; | |
68 | break; | |
69 | case TCSAFLUSH: | |
70 | cmd = TCSETSF; | |
71 | break; | |
72 | #endif | |
73 | default: | |
74 | errno = EINVAL; | |
75 | return -1; | |
76 | } | |
77 | ||
78 | return ioctl(fd, cmd, t); | |
79 | } | |
80 | ||
81 | static inline int tcdrain(int fd) | |
82 | { | |
83 | return ioctl(fd, TCSBRK, 1); | |
84 | } | |
85 | ||
86 | static inline int tcflush(int fd, int q) | |
87 | { | |
88 | return ioctl(fd, TCFLSH, q); | |
89 | } | |
90 | ||
91 | static inline int tcsendbreak(int fd, int d) | |
92 | { | |
a46877ee T |
93 | #ifdef TCSBRKP |
94 | return ioctl(fd, TCSBRKP, d); | |
95 | #else | |
96 | return ioctl(fd, TCSBRK, 0); | |
97 | #endif | |
93b55636 T |
98 | } |
99 | ||
100 | static inline int tcflow(int fd, int a) | |
101 | { | |
102 | return ioctl(fd, TCXONC, a); | |
103 | } | |
104 | ||
105 | static inline pid_t tcgetsid(int fd) | |
106 | { | |
107 | pid_t sid; | |
108 | ||
109 | if (ioctl(fd, TIOCGSID, &sid) < 0) | |
110 | return (pid_t)-1; | |
111 | ||
112 | return sid; | |
113 | } | |
114 | ||
115 | static inline speed_t cfgetospeed(const struct termios *t) | |
116 | { | |
117 | return t->c_cflag & CBAUD; | |
118 | } | |
119 | ||
120 | static inline int cfsetospeed(struct termios *t, speed_t s) | |
121 | { | |
122 | if (s & ~CBAUD) { | |
123 | errno = EINVAL; | |
124 | return -1; | |
125 | } | |
126 | ||
127 | t->c_cflag &= ~CBAUD; | |
128 | t->c_cflag |= s; | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
133 | #ifdef IBSHIFT | |
134 | static inline speed_t cfgetispeed(const struct termios *t) | |
135 | { | |
136 | speed_t s = (t->c_cflag >> IBSHIFT) & CBAUD; | |
137 | ||
138 | if (s == B0) | |
139 | return cfgetospeed(t); | |
140 | else | |
141 | return s; | |
142 | } | |
143 | ||
144 | static inline int cfsetispeed(struct termios *t, speed_t s) | |
145 | { | |
146 | if (s == 0) | |
147 | s = B0; | |
148 | ||
149 | if (s & ~CBAUD) { | |
150 | errno = EINVAL; | |
151 | return -1; | |
152 | } | |
153 | ||
154 | t->c_cflag &= ~(CBAUD << IBSHIFT); | |
155 | t->c_cflag |= s << IBSHIFT; | |
156 | ||
157 | return 0; | |
158 | } | |
159 | #else /* !IBSHIFT */ | |
160 | static inline speed_t cfgetispeed(const struct termios *t) | |
161 | { | |
162 | return cfgetospeed(t); | |
163 | } | |
164 | ||
165 | static inline int cfsetispeed(struct termios *t, speed_t s) | |
166 | { | |
167 | return cfsetospeed(t, s); | |
168 | } | |
169 | #endif /* !IBSHIFT */ | |
170 | ||
171 | static inline int cfsetspeed(struct termios *t, speed_t s) | |
172 | { | |
173 | if (cfsetospeed(t, s)) | |
174 | return -1; | |
175 | #ifdef IBSHIFT | |
176 | if (cfsetispeed(t, s)) | |
177 | return -1; | |
178 | #endif | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
183 | static void cfmakeraw(struct termios *t) | |
184 | { | |
185 | t->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | | |
186 | ICRNL | IXON); | |
187 | t->c_oflag &= ~OPOST; | |
188 | t->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); | |
189 | t->c_cflag &= ~(CSIZE | PARENB); | |
190 | t->c_cflag |= CS8; | |
191 | } | |
192 | ||
193 | #endif /* _TERMIOS_LINUX_H_ */ |