xref: /netbsd-src/sys/compat/linux/common/linux_termios.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: linux_termios.c,v 1.3 1996/04/05 00:01:54 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Frank van der Linden
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *      by Frank van der Linden
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/proc.h>
36 #include <sys/systm.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/ioctl.h>
40 #include <sys/mount.h>
41 #include <sys/termios.h>
42 
43 #include <sys/syscallargs.h>
44 
45 #include <compat/linux/linux_types.h>
46 #include <compat/linux/linux_ioctl.h>
47 #include <compat/linux/linux_signal.h>
48 #include <compat/linux/linux_syscallargs.h>
49 #include <compat/linux/linux_util.h>
50 #include <compat/linux/linux_termios.h>
51 
52 static speed_t linux_speeds[] = {
53 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
54 	9600, 19200, 38400, 57600, 115200
55 };
56 
57 static int linux_spmasks[] = {
58 	LINUX_B0, LINUX_B50, LINUX_B75, LINUX_B110, LINUX_B134, LINUX_B150,
59 	LINUX_B200, LINUX_B300, LINUX_B600, LINUX_B1200, LINUX_B1800,
60 	LINUX_B2400, LINUX_B4800, LINUX_B9600, LINUX_B19200, LINUX_B38400,
61 	LINUX_B57600, LINUX_B115200, LINUX_B230400
62 };
63 
64 
65 static void linux_termio_to_bsd_termios __P((struct linux_termio *,
66 					     struct termios *));
67 static void bsd_termios_to_linux_termio __P((struct termios *,
68 					     struct linux_termio *));
69 static void linux_termios_to_bsd_termios __P((struct linux_termios *,
70 					      struct termios *));
71 static void bsd_termios_to_linux_termios __P((struct termios *,
72 					      struct linux_termios *));
73 
74 /*
75  * Deal with termio ioctl cruft. This doesn't look very good..
76  * XXX too much code duplication, obviously..
77  *
78  * The conversion routines between Linux and BSD structures assume
79  * that the fields are already filled with the current values,
80  * so that fields present in BSD but not in Linux keep their current
81  * values.
82  */
83 
84 static void
85 linux_termio_to_bsd_termios(lt, bts)
86 	register struct linux_termio *lt;
87 	register struct termios *bts;
88 {
89 	int index;
90 
91 	bts->c_iflag = 0;
92 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNBRK, IGNBRK);
93 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_BRKINT, BRKINT);
94 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNPAR, IGNPAR);
95 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INPCK, INPCK);
96 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ISTRIP, ISTRIP);
97 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INLCR, INLCR);
98 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNCR, IGNCR);
99 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ICRNL, ICRNL);
100 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXON, IXON);
101 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXANY, IXANY);
102 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXOFF, IXOFF);
103 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IMAXBEL, IMAXBEL);
104 
105 	bts->c_oflag = 0;
106 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_OPOST, OPOST);
107 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_ONLCR, ONLCR);
108 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_XTABS, OXTABS);
109 
110 	/*
111 	 * This could have been:
112 	 * bts->c_cflag = (lt->c_flag & LINUX_CSIZE) << 4
113 	 * But who knows, those values might perhaps change one day.
114 	 */
115 	switch (lt->c_cflag & LINUX_CSIZE) {
116 	case LINUX_CS5:
117 		bts->c_cflag = CS5;
118 		break;
119 	case LINUX_CS6:
120 		bts->c_cflag = CS6;
121 		break;
122 	case LINUX_CS7:
123 		bts->c_cflag = CS7;
124 		break;
125 	case LINUX_CS8:
126 		bts->c_cflag = CS8;
127 		break;
128 	}
129 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CSTOPB, CSTOPB);
130 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CREAD, CREAD);
131 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARENB, PARENB);
132 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARODD, PARODD);
133 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_HUPCL, HUPCL);
134 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CLOCAL, CLOCAL);
135 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CRTSCTS, CRTSCTS);
136 
137 	bts->c_lflag = 0;
138 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ISIG, ISIG);
139 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ICANON, ICANON);
140 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHO, ECHO);
141 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOE, ECHOE);
142 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOK, ECHOK);
143 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHONL, ECHONL);
144 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_NOFLSH, NOFLSH);
145 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_TOSTOP, TOSTOP);
146 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOCTL, ECHOCTL);
147 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOPRT, ECHOPRT);
148 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOKE, ECHOKE);
149 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_FLUSHO, FLUSHO);
150 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_PENDIN, PENDIN);
151 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_IEXTEN, IEXTEN);
152 
153 	index = lt->c_cflag & LINUX_CBAUD;
154 	if (index & LINUX_CBAUDEX)
155 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
156 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
157 
158 	bts->c_cc[VINTR] = lt->c_cc[LINUX_VINTR];
159 	bts->c_cc[VQUIT] = lt->c_cc[LINUX_VQUIT];
160 	bts->c_cc[VERASE] = lt->c_cc[LINUX_VERASE];
161 	bts->c_cc[VKILL] = lt->c_cc[LINUX_VKILL];
162 	bts->c_cc[VEOF] = lt->c_cc[LINUX_VEOF];
163 	bts->c_cc[VTIME] = lt->c_cc[LINUX_VTIME];
164 	bts->c_cc[VMIN] = lt->c_cc[LINUX_VMIN];
165 }
166 
167 static void
168 bsd_termios_to_linux_termio(bts, lt)
169 	register struct termios *bts;
170 	register struct linux_termio *lt;
171 {
172 	int i, mask;
173 
174 	lt->c_iflag = 0;
175 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
176 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
177 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
178 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
179 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
180 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
181 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
182 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
183 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
184 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
185 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
186 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
187 
188 	lt->c_oflag = 0;
189 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
190 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
191 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
192 
193 	switch (bts->c_cflag & CSIZE) {
194 	case CS5:
195 		lt->c_cflag = LINUX_CS5;
196 		break;
197 	case CS6:
198 		lt->c_cflag = LINUX_CS6;
199 		break;
200 	case CS7:
201 		lt->c_cflag = LINUX_CS7;
202 		break;
203 	case CS8:
204 		lt->c_cflag = LINUX_CS8;
205 		break;
206 	}
207 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
208 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
209 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
210 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
211 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
212 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
213 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
214 
215 	lt->c_lflag = 0;
216 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
217 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
218 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
219 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
220 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
221 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
222 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
223 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
224 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
225 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
226 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
227 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
228 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
229 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
230 
231 	mask = LINUX_B9600;	/* XXX default value should this be 0? */
232 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
233 		if (bts->c_ospeed == linux_speeds[i]) {
234 			mask = linux_spmasks[i];
235 			break;
236 		}
237 	}
238 	lt->c_cflag |= mask;
239 
240 	lt->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
241 	lt->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
242 	lt->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
243 	lt->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
244 	lt->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
245 	lt->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
246 	lt->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
247 	lt->c_cc[LINUX_VSWTC] = 0;
248 
249 	/* XXX should be fixed someday */
250 	lt->c_line = 0;
251 }
252 
253 static void
254 linux_termios_to_bsd_termios(lts, bts)
255 	register struct linux_termios *lts;
256 	register struct termios *bts;
257 {
258 	int index;
259 
260 	bts->c_iflag = 0;
261 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNBRK, IGNBRK);
262 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_BRKINT, BRKINT);
263 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNPAR, IGNPAR);
264 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INPCK, INPCK);
265 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ISTRIP, ISTRIP);
266 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INLCR, INLCR);
267 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNCR, IGNCR);
268 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ICRNL, ICRNL);
269 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXON, IXON);
270 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXANY, IXANY);
271 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXOFF, IXOFF);
272 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IMAXBEL, IMAXBEL);
273 
274 	bts->c_oflag = 0;
275 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_OPOST, OPOST);
276 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_ONLCR, ONLCR);
277 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_XTABS, OXTABS);
278 
279 	bts->c_cflag = 0;
280 	switch (lts->c_cflag & LINUX_CSIZE) {
281 	case LINUX_CS5:
282 		bts->c_cflag = CS5;
283 		break;
284 	case LINUX_CS6:
285 		bts->c_cflag = CS6;
286 		break;
287 	case LINUX_CS7:
288 		bts->c_cflag = CS7;
289 		break;
290 	case LINUX_CS8:
291 		bts->c_cflag = CS8;
292 		break;
293 	}
294 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CSTOPB, CSTOPB);
295 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CREAD, CREAD);
296 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARENB, PARENB);
297 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARODD, PARODD);
298 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_HUPCL, HUPCL);
299 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CLOCAL, CLOCAL);
300 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CRTSCTS, CRTSCTS);
301 
302 	bts->c_lflag = 0;
303 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ISIG, ISIG);
304 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ICANON, ICANON);
305 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHO, ECHO);
306 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOE, ECHOE);
307 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOK, ECHOK);
308 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHONL, ECHONL);
309 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_NOFLSH, NOFLSH);
310 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_TOSTOP, TOSTOP);
311 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOCTL, ECHOCTL);
312 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOPRT, ECHOPRT);
313 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOKE, ECHOKE);
314 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_FLUSHO, FLUSHO);
315 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_PENDIN, PENDIN);
316 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_IEXTEN, IEXTEN);
317 
318 	index = lts->c_cflag & LINUX_CBAUD;
319 	if (index & LINUX_CBAUDEX)
320 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
321 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
322 
323 	bts->c_cc[VINTR] = lts->c_cc[LINUX_VINTR];
324 	bts->c_cc[VQUIT] = lts->c_cc[LINUX_VQUIT];
325 	bts->c_cc[VERASE] = lts->c_cc[LINUX_VERASE];
326 	bts->c_cc[VKILL] = lts->c_cc[LINUX_VKILL];
327 	bts->c_cc[VEOF] = lts->c_cc[LINUX_VEOF];
328 	bts->c_cc[VTIME] = lts->c_cc[LINUX_VTIME];
329 	bts->c_cc[VMIN] = lts->c_cc[LINUX_VMIN];
330 	bts->c_cc[VEOL] = lts->c_cc[LINUX_VEOL];
331 	bts->c_cc[VEOL2] = lts->c_cc[LINUX_VEOL2];
332 	bts->c_cc[VWERASE] = lts->c_cc[LINUX_VWERASE];
333 	bts->c_cc[VSUSP] = lts->c_cc[LINUX_VSUSP];
334 	bts->c_cc[VSTART] = lts->c_cc[LINUX_VSTART];
335 	bts->c_cc[VSTOP] = lts->c_cc[LINUX_VSTOP];
336 	bts->c_cc[VLNEXT] = lts->c_cc[LINUX_VLNEXT];
337 	bts->c_cc[VDISCARD] = lts->c_cc[LINUX_VDISCARD];
338 	bts->c_cc[VREPRINT] = lts->c_cc[LINUX_VREPRINT];
339 }
340 
341 static void
342 bsd_termios_to_linux_termios(bts, lts)
343 	register struct termios *bts;
344 	register struct linux_termios *lts;
345 {
346 	int i, mask;
347 
348 	lts->c_iflag = 0;
349 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
350 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
351 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
352 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
353 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
354 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
355 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
356 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
357 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
358 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
359 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
360 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
361 
362 	lts->c_oflag = 0;
363 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
364 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
365 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
366 
367 	switch (bts->c_cflag & CSIZE) {
368 	case CS5:
369 		lts->c_cflag = LINUX_CS5;
370 		break;
371 	case CS6:
372 		lts->c_cflag = LINUX_CS6;
373 		break;
374 	case CS7:
375 		lts->c_cflag = LINUX_CS7;
376 		break;
377 	case CS8:
378 		lts->c_cflag = LINUX_CS8;
379 		break;
380 	}
381 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS5, LINUX_CS5);
382 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS6, LINUX_CS6);
383 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS7, LINUX_CS7);
384 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS8, LINUX_CS8);
385 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
386 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
387 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
388 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
389 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
390 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
391 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
392 
393 	lts->c_lflag = 0;
394 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
395 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
396 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
397 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
398 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
399 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
400 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
401 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
402 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
403 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
404 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
405 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
406 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
407 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
408 
409 	mask = LINUX_B9600;	/* XXX default value */
410 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
411 		if (bts->c_ospeed == linux_speeds[i]) {
412 			mask = linux_spmasks[i];
413 			break;
414 		}
415 	}
416 	lts->c_cflag |= mask;
417 
418 	lts->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
419 	lts->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
420 	lts->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
421 	lts->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
422 	lts->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
423 	lts->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
424 	lts->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
425 	lts->c_cc[LINUX_VEOL] = bts->c_cc[VEOL];
426 	lts->c_cc[LINUX_VEOL2] = bts->c_cc[VEOL2];
427 	lts->c_cc[LINUX_VWERASE] = bts->c_cc[VWERASE];
428 	lts->c_cc[LINUX_VSUSP] = bts->c_cc[VSUSP];
429 	lts->c_cc[LINUX_VSTART] = bts->c_cc[VSTART];
430 	lts->c_cc[LINUX_VSTOP] = bts->c_cc[VSTOP];
431 	lts->c_cc[LINUX_VLNEXT] = bts->c_cc[VLNEXT];
432 	lts->c_cc[LINUX_VDISCARD] = bts->c_cc[VDISCARD];
433 	lts->c_cc[LINUX_VREPRINT] = bts->c_cc[VREPRINT];
434 	lts->c_cc[LINUX_VSWTC] = 0;
435 
436 	/* XXX should be fixed someday */
437 	lts->c_line = 0;
438 }
439 
440 int
441 linux_ioctl_termios(p, uap, retval)
442 	register struct proc *p;
443 	register struct linux_sys_ioctl_args /* {
444 		syscallarg(int) fd;
445 		syscallarg(u_long) com;
446 		syscallarg(caddr_t) data;
447 	} */ *uap;
448 	register_t *retval;
449 {
450 	register struct file *fp;
451 	register struct filedesc *fdp;
452 	u_long com;
453 	struct linux_termio tmplt;
454 	struct linux_termios tmplts;
455 	struct termios tmpbts;
456 	int idat;
457 	struct sys_ioctl_args ia;
458 	int error;
459 
460 	fdp = p->p_fd;
461 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
462 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
463 		return (EBADF);
464 
465 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
466 		return (EBADF);
467 
468 	com = SCARG(uap, com);
469 	retval[0] = 0;
470 
471 	switch (com) {
472 	case LINUX_TCGETS:
473 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, p);
474 		if (error)
475 			return error;
476 		bsd_termios_to_linux_termios(&tmpbts, &tmplts);
477 		error = copyout(&tmplts, SCARG(uap, data), sizeof tmplts);
478 		if (error)
479 			return error;
480 		return 0;
481 	case LINUX_TCSETS:
482 	case LINUX_TCSETSW:
483 	case LINUX_TCSETSF:
484 		/*
485 		 * First fill in all fields, so that we keep the current
486 		 * values for fields that Linux doesn't know about.
487 		 */
488 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, p);
489 		if (error)
490 			return error;
491 		error = copyin(SCARG(uap, data), &tmplts, sizeof tmplts);
492 		if (error)
493 			return error;
494 		linux_termios_to_bsd_termios(&tmplts, &tmpbts);
495 		switch (com) {
496 		case LINUX_TCSETS:
497 			com = TIOCSETA;
498 			break;
499 		case LINUX_TCSETSW:
500 			com = TIOCSETAW;
501 			break;
502 		case LINUX_TCSETSF:
503 			com = TIOCSETAF;
504 			break;
505 		}
506 		error = (*fp->f_ops->fo_ioctl)(fp, com, (caddr_t)&tmpbts, p);
507 		if (error)
508 			return error;
509 		return 0;
510 	case LINUX_TCGETA:
511 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, p);
512 		if (error)
513 			return error;
514 		bsd_termios_to_linux_termio(&tmpbts, &tmplt);
515 		error = copyout(&tmplt, SCARG(uap, data), sizeof tmplt);
516 		if (error)
517 			return error;
518 		return 0;
519 	case LINUX_TCSETA:
520 	case LINUX_TCSETAW:
521 	case LINUX_TCSETAF:
522 		/*
523 		 * First fill in all fields, so that we keep the current
524 		 * values for fields that Linux doesn't know about.
525 		 */
526 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts, p);
527 		if (error)
528 			return error;
529 		error = copyin(SCARG(uap, data), &tmplt, sizeof tmplt);
530 		if (error)
531 			return error;
532 		linux_termio_to_bsd_termios(&tmplt, &tmpbts);
533 		switch (com) {
534 		case LINUX_TCSETA:
535 			com = TIOCSETA;
536 			break;
537 		case LINUX_TCSETAW:
538 			com = TIOCSETAW;
539 			break;
540 		case LINUX_TCSETAF:
541 			com = TIOCSETAF;
542 			break;
543 		}
544 		error = (*fp->f_ops->fo_ioctl)(fp, com, (caddr_t)&tmpbts, p);
545 		if (error)
546 			return error;
547 		return 0;
548 	case LINUX_TIOCGETD:
549 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETD, (caddr_t)&idat, p);
550 		if (error)
551 			return error;
552 		switch (idat) {
553 		case TTYDISC:
554 			idat = LINUX_N_TTY;
555 			break;
556 		case SLIPDISC:
557 			idat = LINUX_N_SLIP;
558 			break;
559 		case PPPDISC:
560 			idat = LINUX_N_PPP;
561 			break;
562 		/*
563 		 * Linux does not have the tablet line discipline.
564 		 */
565 		case TABLDISC:
566 		default:
567 			idat = -1;	/* XXX What should this be? */
568 			break;
569 		}
570 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
571 		if (error)
572 			return error;
573 		return 0;
574 	case LINUX_TIOCSETD:
575 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
576 		if (error)
577 			return error;
578 		switch (idat) {
579 		case LINUX_N_TTY:
580 			idat = TTYDISC;
581 			break;
582 		case LINUX_N_SLIP:
583 			idat = SLIPDISC;
584 			break;
585 		case LINUX_N_PPP:
586 			idat = PPPDISC;
587 			break;
588 		/*
589 		 * We can't handle the mouse line discipline Linux has.
590 		 */
591 		case LINUX_N_MOUSE:
592 		default:
593 			return EINVAL;
594 		}
595 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCSETD, (caddr_t)&idat, p);
596 		if (error)
597 			return error;
598 		return 0;
599 	case LINUX_TIOCGWINSZ:
600 		SCARG(&ia, com) = TIOCGWINSZ;
601 		break;
602 	case LINUX_TIOCSWINSZ:
603 		SCARG(&ia, com) = TIOCSWINSZ;
604 		break;
605 	case LINUX_TIOCGPGRP:
606 		SCARG(&ia, com) = TIOCGPGRP;
607 		break;
608 	case LINUX_TIOCSPGRP:
609 		SCARG(&ia, com) = TIOCSPGRP;
610 		break;
611 	case LINUX_FIONREAD:
612 		SCARG(&ia, com) = FIONREAD;
613 		break;
614 	case LINUX_FIONBIO:
615 		SCARG(&ia, com) = FIONBIO;
616 		break;
617 	case LINUX_FIOASYNC:
618 		SCARG(&ia, com) = FIOASYNC;
619 		break;
620 	case LINUX_TIOCEXCL:
621 		SCARG(&ia, com) = TIOCEXCL;
622 		break;
623 	case LINUX_TIOCNXCL:
624 		SCARG(&ia, com) = TIOCNXCL;
625 		break;
626 	case LINUX_TIOCCONS:
627 		SCARG(&ia, com) = TIOCCONS;
628 		break;
629 	case LINUX_TIOCNOTTY:
630 		SCARG(&ia, com) = TIOCNOTTY;
631 		break;
632 	default:
633 		return EINVAL;
634 	}
635 
636 	SCARG(&ia, fd) = SCARG(uap, fd);
637 	SCARG(&ia, data) = SCARG(uap, data);
638 	return sys_ioctl(p, &ia, retval);
639 }
640