1 /*	$OpenBSD: linux_termios.c,v 1.15 2003/04/05 20:30:18 millert Exp $	*/
2 /*	$NetBSD: linux_termios.c,v 1.3 1996/04/05 00:01:54 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1995 Frank van der Linden
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed for the NetBSD Project
19  *      by Frank van der Linden
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/proc.h>
37 #include <sys/systm.h>
38 #include <sys/file.h>
39 #include <sys/filedesc.h>
40 #include <sys/ioctl.h>
41 #include <sys/mount.h>
42 #include <sys/termios.h>
43 
44 #include <sys/syscallargs.h>
45 
46 #include <compat/linux/linux_types.h>
47 #include <compat/linux/linux_ioctl.h>
48 #include <compat/linux/linux_signal.h>
49 #include <compat/linux/linux_syscallargs.h>
50 #include <compat/linux/linux_util.h>
51 #include <compat/linux/linux_termios.h>
52 
53 static speed_t linux_speeds[] = {
54 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
55 	9600, 19200, 38400, 57600, 115200, 230400
56 };
57 
58 static const int linux_spmasks[] = {
59 	LINUX_B0, LINUX_B50, LINUX_B75, LINUX_B110, LINUX_B134, LINUX_B150,
60 	LINUX_B200, LINUX_B300, LINUX_B600, LINUX_B1200, LINUX_B1800,
61 	LINUX_B2400, LINUX_B4800, LINUX_B9600, LINUX_B19200, LINUX_B38400,
62 	LINUX_B57600, LINUX_B115200, LINUX_B230400
63 };
64 
65 static void linux_termio_to_bsd_termios(struct linux_termio *,
66     struct termios *);
67 static void bsd_termios_to_linux_termio(struct termios *,
68     struct linux_termio *);
69 static void linux_termios_to_bsd_termios(struct linux_termios *,
70     struct termios *);
71 static void bsd_termios_to_linux_termios(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
linux_termio_to_bsd_termios(lt,bts)85 linux_termio_to_bsd_termios(lt, bts)
86 	struct linux_termio *lt;
87 	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
bsd_termios_to_linux_termio(bts,lt)168 bsd_termios_to_linux_termio(bts, lt)
169 	struct termios *bts;
170 	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
linux_termios_to_bsd_termios(lts,bts)254 linux_termios_to_bsd_termios(lts, bts)
255 	struct linux_termios *lts;
256 	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
bsd_termios_to_linux_termios(bts,lts)342 bsd_termios_to_linux_termios(bts, lts)
343 	struct termios *bts;
344 	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
linux_ioctl_termios(p,v,retval)441 linux_ioctl_termios(p, v, retval)
442 	struct proc *p;
443 	void *v;
444 	register_t *retval;
445 {
446 	struct linux_sys_ioctl_args /* {
447 		syscallarg(int) fd;
448 		syscallarg(u_long) com;
449 		syscallarg(caddr_t) data;
450 	} */ *uap = v;
451 	struct file *fp;
452 	struct filedesc *fdp;
453 	u_long com;
454 	struct linux_termio tmplt;
455 	struct linux_termios tmplts;
456 	struct termios tmpbts;
457 	caddr_t sg;
458 	int idat;
459 	struct sys_ioctl_args ia;
460 	char tioclinux;
461 	int error = 0;
462 
463 	fdp = p->p_fd;
464 	if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
465 		return (EBADF);
466 	FREF(fp);
467 
468 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
469 		error = EBADF;
470 		goto out;
471 	}
472 
473 	com = SCARG(uap, com);
474 	retval[0] = 0;
475 
476 	switch (com) {
477 	case LINUX_TCGETS:
478 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts,
479 		    p);
480 		if (error)
481 			goto out;
482 		bsd_termios_to_linux_termios(&tmpbts, &tmplts);
483 		error = copyout(&tmplts, SCARG(uap, data), sizeof tmplts);
484 		goto out;
485 	case LINUX_TCSETS:
486 	case LINUX_TCSETSW:
487 	case LINUX_TCSETSF:
488 		/*
489 		 * First fill in all fields, so that we keep the current
490 		 * values for fields that Linux doesn't know about.
491 		 */
492 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts,
493 		    p);
494 		if (error)
495 			goto out;
496 		error = copyin(SCARG(uap, data), &tmplts, sizeof tmplts);
497 		if (error)
498 			goto out;
499 		linux_termios_to_bsd_termios(&tmplts, &tmpbts);
500 		switch (com) {
501 		case LINUX_TCSETS:
502 			com = TIOCSETA;
503 			break;
504 		case LINUX_TCSETSW:
505 			com = TIOCSETAW;
506 			break;
507 		case LINUX_TCSETSF:
508 			com = TIOCSETAF;
509 			break;
510 		}
511 		error = (*fp->f_ops->fo_ioctl)(fp, com, (caddr_t)&tmpbts, p);
512 		goto out;
513 	case LINUX_TCGETA:
514 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts,
515 		    p);
516 		if (error)
517 			goto out;
518 		bsd_termios_to_linux_termio(&tmpbts, &tmplt);
519 		error = copyout(&tmplt, SCARG(uap, data), sizeof tmplt);
520 		goto out;
521 	case LINUX_TCSETA:
522 	case LINUX_TCSETAW:
523 	case LINUX_TCSETAF:
524 		/*
525 		 * First fill in all fields, so that we keep the current
526 		 * values for fields that Linux doesn't know about.
527 		 */
528 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts,
529 		    p);
530 		if (error)
531 			goto out;
532 		error = copyin(SCARG(uap, data), &tmplt, sizeof tmplt);
533 		if (error)
534 			goto out;
535 		linux_termio_to_bsd_termios(&tmplt, &tmpbts);
536 		switch (com) {
537 		case LINUX_TCSETA:
538 			com = TIOCSETA;
539 			break;
540 		case LINUX_TCSETAW:
541 			com = TIOCSETAW;
542 			break;
543 		case LINUX_TCSETAF:
544 			com = TIOCSETAF;
545 			break;
546 		}
547 		error = (*fp->f_ops->fo_ioctl)(fp, com, (caddr_t)&tmpbts, p);
548 		goto out;
549 	case LINUX_TIOCGETD:
550 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETD, (caddr_t)&idat, p);
551 		if (error)
552 			goto out;
553 		switch (idat) {
554 		case TTYDISC:
555 			idat = LINUX_N_TTY;
556 			break;
557 		case SLIPDISC:
558 			idat = LINUX_N_SLIP;
559 			break;
560 		case PPPDISC:
561 			idat = LINUX_N_PPP;
562 			break;
563 		/*
564 		 * Linux does not have the tablet line discipline.
565 		 */
566 		case TABLDISC:
567 		default:
568 			idat = -1;	/* XXX What should this be? */
569 			break;
570 		}
571 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
572 		goto out;
573 	case LINUX_TIOCSETD:
574 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
575 		if (error)
576 			goto out;
577 		switch (idat) {
578 		case LINUX_N_TTY:
579 			idat = TTYDISC;
580 			break;
581 		case LINUX_N_SLIP:
582 			idat = SLIPDISC;
583 			break;
584 		case LINUX_N_PPP:
585 			idat = PPPDISC;
586 			break;
587 		/*
588 		 * We can't handle the mouse line discipline Linux has.
589 		 */
590 		case LINUX_N_MOUSE:
591 		default:
592 			error = EINVAL;
593 			goto out;
594 		}
595 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCSETD, (caddr_t)&idat, p);
596 		goto out;
597 	case LINUX_TIOCLINUX:
598 		error = copyin(SCARG(uap, data), &tioclinux, sizeof tioclinux);
599 		if (error != 0)
600 			goto out;
601 		switch (tioclinux) {
602 		case LINUX_TIOCLINUX_KERNMSG:
603 			/*
604 			 * XXX needed to not fail for some things. Could
605 			 * try to use TIOCCONS, but the char argument
606 			 * specifies the VT #, not an fd.
607 			 */
608 			goto out;
609 		case LINUX_TIOCLINUX_COPY:
610 		case LINUX_TIOCLINUX_PASTE:
611 		case LINUX_TIOCLINUX_UNBLANK:
612 		case LINUX_TIOCLINUX_LOADLUT:
613 		case LINUX_TIOCLINUX_READSHIFT:
614 		case LINUX_TIOCLINUX_READMOUSE:
615 		case LINUX_TIOCLINUX_VESABLANK:
616 		case LINUX_TIOCLINUX_CURCONS:	/* could use VT_GETACTIVE */
617 			error = EINVAL;
618 			goto out;
619 		}
620 		break;
621 	case LINUX_TIOCGWINSZ:
622 		SCARG(&ia, com) = TIOCGWINSZ;
623 		break;
624 	case LINUX_TIOCSWINSZ:
625 		SCARG(&ia, com) = TIOCSWINSZ;
626 		break;
627 	case LINUX_TIOCMGET:
628 		SCARG(&ia, com) = TIOCMGET;
629 		break;
630 	case LINUX_TIOCMBIS:
631 		SCARG(&ia, com) = TIOCMBIS;
632 		break;
633 	case LINUX_TIOCMBIC:
634 		SCARG(&ia, com) = TIOCMBIC;
635 		break;
636 	case LINUX_TIOCMSET:
637 		SCARG(&ia, com) = TIOCMSET;
638 		break;
639 	case LINUX_TIOCGPGRP:
640 		SCARG(&ia, com) = TIOCGPGRP;
641 		break;
642 	case LINUX_TIOCSPGRP:
643 		SCARG(&ia, com) = TIOCSPGRP;
644 		break;
645 	case LINUX_FIONREAD:
646 		SCARG(&ia, com) = FIONREAD;
647 		break;
648 	case LINUX_FIONBIO:
649 		SCARG(&ia, com) = FIONBIO;
650 		break;
651 	case LINUX_FIOASYNC:
652 		SCARG(&ia, com) = FIOASYNC;
653 		break;
654 	case LINUX_TIOCEXCL:
655 		SCARG(&ia, com) = TIOCEXCL;
656 		break;
657 	case LINUX_TIOCNXCL:
658 		SCARG(&ia, com) = TIOCNXCL;
659 		break;
660 	case LINUX_TIOCSCTTY:
661 		SCARG(&ia, com) = TIOCSCTTY;
662 		break;
663 	case LINUX_TIOCCONS:
664 		SCARG(&ia, com) = TIOCCONS;
665 		break;
666 	case LINUX_TIOCNOTTY:
667 		SCARG(&ia, com) = TIOCNOTTY;
668 		break;
669 	case LINUX_TCSBRK:
670 		SCARG(&ia, com) = SCARG(uap, data) ? TIOCDRAIN : TIOCSBRK;
671 		break;
672 	case LINUX_TCXONC:
673 		switch ((int)SCARG(uap, data)) {
674 		case LINUX_TCOOFF:
675 			SCARG(&ia, com) = TIOCSTOP;
676 			break;
677 		case LINUX_TCOON:
678 			SCARG(&ia, com) = TIOCSTART;
679 			break;
680 		case LINUX_TCIOFF:
681 		case LINUX_TCION: {
682 			u_char c, *cp;
683 			struct sys_write_args wa;
684 
685 			error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
686 			    (caddr_t)&tmpbts, p);
687 			if (error)
688 				goto out;
689 			if ((int)SCARG(uap, data) == LINUX_TCIOFF)
690 				c = tmpbts.c_cc[VSTOP];
691 			else
692 				c = tmpbts.c_cc[VSTART];
693 			if (c == _POSIX_VDISABLE)
694 				goto out;
695 
696 			sg = stackgap_init(p->p_emul);
697 			cp = (char *) stackgap_alloc(&sg, 1);
698 			if ((error = copyout(&c, cp, 1)))
699 				goto out;
700 
701 			SCARG(&wa, fd) = SCARG(uap, fd);
702 			SCARG(&wa, buf) = cp;
703 			SCARG(&wa, nbyte) = 1;
704 			error = sys_write(p, &wa, retval);
705 			goto out;
706 		    }
707 		default:
708 			error = EINVAL;
709 			goto out;
710 		}
711 		SCARG(uap, data) = 0;
712 		break;
713 	default:
714 		error = EINVAL;
715 		goto out;
716 	}
717 
718 	SCARG(&ia, fd) = SCARG(uap, fd);
719 	SCARG(&ia, data) = SCARG(uap, data);
720 	error = sys_ioctl(p, &ia, retval);
721 
722 out:
723 	FRELE(fp);
724 	return (error);
725 }
726