xref: /netbsd-src/sys/compat/linux/common/linux_ioctl.c (revision 1f2744e6e4915c9da2a3f980279398c4cf7d5e6d)
1 /*	$NetBSD: linux_ioctl.c,v 1.1 1995/02/28 23:24:58 fvdl 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/termios.h>
41 #include <sys/tty.h>
42 #include <sys/socket.h>
43 #include <sys/ioctl.h>
44 #include <sys/mount.h>
45 
46 #include <sys/syscallargs.h>
47 #include <compat/linux/linux_types.h>
48 #include <compat/linux/linux_ioctl.h>
49 #include <compat/linux/linux_util.h>
50 #include <compat/linux/linux_syscallargs.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
62 };
63 
64 /*
65  * Deal with termio ioctl cruft. This doesn't look very good..
66  * XXX too much code duplication, obviously..
67  *
68  * The conversion routines between Linux and BSD structures assume
69  * that the fields are already filled with the current values,
70  * so that fields present in BSD but not in Linux keep their current
71  * values.
72  */
73 
74 static int
75 linux_termio_to_bsd_termios(lt, bts)
76 	register struct linux_termio *lt;
77 	register struct termios *bts;
78 {
79 	int index;
80 
81 	bts->c_iflag = 0;
82 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNBRK, IGNBRK);
83 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_BRKINT, BRKINT);
84 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNPAR, IGNPAR);
85 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INPCK, INPCK);
86 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ISTRIP, ISTRIP);
87 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_INLCR, INLCR);
88 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IGNCR, IGNCR);
89 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_ICRNL, ICRNL);
90 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXON, IXON);
91 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXANY, IXANY);
92 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IXOFF, IXOFF);
93 	bts->c_iflag |= cvtto_bsd_mask(lt->c_iflag, LINUX_IMAXBEL, IMAXBEL);
94 
95 	bts->c_oflag = 0;
96 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_OPOST, OPOST);
97 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_ONLCR, ONLCR);
98 	bts->c_oflag |= cvtto_bsd_mask(lt->c_oflag, LINUX_XTABS, OXTABS);
99 
100 	/*
101 	 * This could have been:
102 	 * bts->c_cflag = (lt->c_flag & LINUX_CSIZE) << 4
103 	 * But who knows, those values might perhaps change one day.
104 	 */
105 	switch (lt->c_cflag & LINUX_CSIZE) {
106 	case LINUX_CS5:
107 		bts->c_cflag = CS5;
108 		break;
109 	case LINUX_CS6:
110 		bts->c_cflag = CS6;
111 		break;
112 	case LINUX_CS7:
113 		bts->c_cflag = CS7;
114 		break;
115 	case LINUX_CS8:
116 		bts->c_cflag = CS8;
117 		break;
118 	}
119 
120 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CSTOPB, CSTOPB);
121 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CREAD, CREAD);
122 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARENB, PARENB);
123 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_PARODD, PARODD);
124 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_HUPCL, HUPCL);
125 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CLOCAL, CLOCAL);
126 	bts->c_cflag |= cvtto_bsd_mask(lt->c_cflag, LINUX_CRTSCTS, CRTSCTS);
127 
128 	bts->c_lflag = 0;
129 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ISIG, ISIG);
130 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ICANON, ICANON);
131 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHO, ECHO);
132 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOE, ECHOE);
133 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOK, ECHOK);
134 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHONL, ECHONL);
135 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_NOFLSH, NOFLSH);
136 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_TOSTOP, TOSTOP);
137 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOCTL, ECHOCTL);
138 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOPRT, ECHOPRT);
139 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_ECHOKE, ECHOKE);
140 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_FLUSHO, FLUSHO);
141 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_PENDIN, PENDIN);
142 	bts->c_lflag |= cvtto_bsd_mask(lt->c_lflag, LINUX_IEXTEN, IEXTEN);
143 
144 	index = lt->c_cflag & LINUX_CBAUD;
145 	if (index & LINUX_CBAUDEX)
146 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
147 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
148 
149 	bts->c_cc[VINTR] = lt->c_cc[LINUX_VINTR];
150 	bts->c_cc[VQUIT] = lt->c_cc[LINUX_VQUIT];
151 	bts->c_cc[VERASE] = lt->c_cc[LINUX_VERASE];
152 	bts->c_cc[VKILL] = lt->c_cc[LINUX_VKILL];
153 	bts->c_cc[VEOF] = lt->c_cc[LINUX_VEOF];
154 	bts->c_cc[VTIME] = lt->c_cc[LINUX_VTIME];
155 	bts->c_cc[VMIN] = lt->c_cc[LINUX_VMIN];
156 }
157 
158 static int
159 bsd_termios_to_linux_termio(bts, lt)
160 	register struct termios *bts;
161 	register struct linux_termio *lt;
162 {
163 	int i, mask;
164 
165 	lt->c_iflag = 0;
166 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
167 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
168 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
169 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
170 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
171 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
172 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
173 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
174 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
175 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
176 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
177 	lt->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
178 
179 	lt->c_oflag = 0;
180 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
181 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
182 	lt->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
183 
184 	switch (bts->c_cflag & CSIZE) {
185 	case CS5:
186 		lt->c_cflag = LINUX_CS5;
187 		break;
188 	case CS6:
189 		lt->c_cflag = LINUX_CS6;
190 		break;
191 	case CS7:
192 		lt->c_cflag = LINUX_CS7;
193 		break;
194 	case CS8:
195 		lt->c_cflag = LINUX_CS8;
196 		break;
197 	}
198 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
199 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
200 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
201 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
202 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
203 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
204 	lt->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
205 
206 	lt->c_lflag = 0;
207 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
208 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
209 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
210 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
211 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
212 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
213 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
214 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
215 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
216 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
217 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
218 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
219 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
220 	lt->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
221 
222 	mask = LINUX_B9600;	/* XXX default value should this be 0? */
223 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
224 		if (bts->c_ospeed == linux_speeds[i]) {
225 			mask = linux_spmasks[i];
226 			break;
227 		}
228 	}
229 	lt->c_cflag |= mask;
230 
231 	lt->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
232 	lt->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
233 	lt->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
234 	lt->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
235 	lt->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
236 	lt->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
237 	lt->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
238 	lt->c_cc[LINUX_VSWTC] = 0;
239 
240 	/* XXX should be fixed someday */
241 	lt->c_line = 0;
242 }
243 
244 static int
245 linux_termios_to_bsd_termios(lts, bts)
246 	register struct linux_termios *lts;
247 	register struct termios *bts;
248 {
249 	int index;
250 
251 	bts->c_iflag = 0;
252 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNBRK, IGNBRK);
253 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_BRKINT, BRKINT);
254 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNPAR, IGNPAR);
255 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INPCK, INPCK);
256 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ISTRIP, ISTRIP);
257 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_INLCR, INLCR);
258 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IGNCR, IGNCR);
259 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_ICRNL, ICRNL);
260 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXON, IXON);
261 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXANY, IXANY);
262 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IXOFF, IXOFF);
263 	bts->c_iflag |= cvtto_bsd_mask(lts->c_iflag, LINUX_IMAXBEL, IMAXBEL);
264 
265 	bts->c_oflag = 0;
266 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_OPOST, OPOST);
267 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_ONLCR, ONLCR);
268 	bts->c_oflag |= cvtto_bsd_mask(lts->c_oflag, LINUX_XTABS, OXTABS);
269 
270 	bts->c_cflag = 0;
271 	switch (lts->c_cflag & LINUX_CSIZE) {
272 	case LINUX_CS5:
273 		bts->c_cflag = CS5;
274 		break;
275 	case LINUX_CS6:
276 		bts->c_cflag = CS6;
277 		break;
278 	case LINUX_CS7:
279 		bts->c_cflag = CS7;
280 		break;
281 	case LINUX_CS8:
282 		bts->c_cflag = CS8;
283 		break;
284 	}
285 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CSTOPB, CSTOPB);
286 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CREAD, CREAD);
287 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARENB, PARENB);
288 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_PARODD, PARODD);
289 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_HUPCL, HUPCL);
290 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CLOCAL, CLOCAL);
291 	bts->c_cflag |= cvtto_bsd_mask(lts->c_cflag, LINUX_CRTSCTS, CRTSCTS);
292 
293 	bts->c_lflag = 0;
294 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ISIG, ISIG);
295 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ICANON, ICANON);
296 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHO, ECHO);
297 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOE, ECHOE);
298 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOK, ECHOK);
299 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHONL, ECHONL);
300 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_NOFLSH, NOFLSH);
301 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_TOSTOP, TOSTOP);
302 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOCTL, ECHOCTL);
303 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOPRT, ECHOPRT);
304 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_ECHOKE, ECHOKE);
305 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_FLUSHO, FLUSHO);
306 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_PENDIN, PENDIN);
307 	bts->c_lflag |= cvtto_bsd_mask(lts->c_lflag, LINUX_IEXTEN, IEXTEN);
308 
309 	index = lts->c_cflag & LINUX_CBAUD;
310 	if (index & LINUX_CBAUDEX)
311 		index = (index & ~LINUX_CBAUDEX) + LINUX_NSPEEDS - 1;
312 	bts->c_ispeed = bts->c_ospeed = linux_speeds[index];
313 
314 	bts->c_cc[VINTR] = lts->c_cc[LINUX_VINTR];
315 	bts->c_cc[VQUIT] = lts->c_cc[LINUX_VQUIT];
316 	bts->c_cc[VERASE] = lts->c_cc[LINUX_VERASE];
317 	bts->c_cc[VKILL] = lts->c_cc[LINUX_VKILL];
318 	bts->c_cc[VEOF] = lts->c_cc[LINUX_VEOF];
319 	bts->c_cc[VTIME] = lts->c_cc[LINUX_VTIME];
320 	bts->c_cc[VMIN] = lts->c_cc[LINUX_VMIN];
321 	bts->c_cc[VEOL] = lts->c_cc[LINUX_VEOL];
322 	bts->c_cc[VEOL2] = lts->c_cc[LINUX_VEOL2];
323 	bts->c_cc[VWERASE] = lts->c_cc[LINUX_VWERASE];
324 	bts->c_cc[VSUSP] = lts->c_cc[LINUX_VSUSP];
325 	bts->c_cc[VSTART] = lts->c_cc[LINUX_VSTART];
326 	bts->c_cc[VSTOP] = lts->c_cc[LINUX_VSTOP];
327 	bts->c_cc[VLNEXT] = lts->c_cc[LINUX_VLNEXT];
328 	bts->c_cc[VDISCARD] = lts->c_cc[LINUX_VDISCARD];
329 	bts->c_cc[VREPRINT] = lts->c_cc[LINUX_VREPRINT];
330 }
331 
332 static int
333 bsd_termios_to_linux_termios(bts, lts)
334 	register struct termios *bts;
335 	register struct linux_termios *lts;
336 {
337 	int i, mask;
338 
339 	lts->c_iflag = 0;
340 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNBRK, LINUX_IGNBRK);
341 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, BRKINT, LINUX_BRKINT);
342 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNPAR, LINUX_IGNPAR);
343 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INPCK, LINUX_INPCK);
344 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ISTRIP, LINUX_ISTRIP);
345 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, INLCR, LINUX_INLCR);
346 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IGNCR, LINUX_IGNCR);
347 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, ICRNL, LINUX_ICRNL);
348 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXON, LINUX_IXON);
349 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXANY, LINUX_IXANY);
350 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IXOFF, LINUX_IXOFF);
351 	lts->c_iflag |= cvtto_linux_mask(bts->c_iflag, IMAXBEL, LINUX_IMAXBEL);
352 
353 	lts->c_oflag = 0;
354 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OPOST, LINUX_OPOST);
355 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, ONLCR, LINUX_ONLCR);
356 	lts->c_oflag |= cvtto_linux_mask(bts->c_oflag, OXTABS, LINUX_XTABS);
357 
358 	switch (bts->c_cflag & CSIZE) {
359 	case CS5:
360 		lts->c_cflag = LINUX_CS5;
361 		break;
362 	case CS6:
363 		lts->c_cflag = LINUX_CS6;
364 		break;
365 	case CS7:
366 		lts->c_cflag = LINUX_CS7;
367 		break;
368 	case CS8:
369 		lts->c_cflag = LINUX_CS8;
370 		break;
371 	}
372 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS5, LINUX_CS5);
373 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS6, LINUX_CS6);
374 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS7, LINUX_CS7);
375 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CS8, LINUX_CS8);
376 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CSTOPB, LINUX_CSTOPB);
377 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CREAD, LINUX_CREAD);
378 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARENB, LINUX_PARENB);
379 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, PARODD, LINUX_PARODD);
380 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, HUPCL, LINUX_HUPCL);
381 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CLOCAL, LINUX_CLOCAL);
382 	lts->c_cflag |= cvtto_linux_mask(bts->c_cflag, CRTSCTS, LINUX_CRTSCTS);
383 
384 	lts->c_lflag = 0;
385 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ISIG, LINUX_ISIG);
386 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ICANON, LINUX_ICANON);
387 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHO, LINUX_ECHO);
388 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOE, LINUX_ECHOE);
389 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOK, LINUX_ECHOK);
390 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHONL, LINUX_ECHONL);
391 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, NOFLSH, LINUX_NOFLSH);
392 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, TOSTOP, LINUX_TOSTOP);
393 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOCTL, LINUX_ECHOCTL);
394 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOPRT, LINUX_ECHOPRT);
395 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, ECHOKE, LINUX_ECHOKE);
396 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, FLUSHO, LINUX_FLUSHO);
397 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, PENDIN, LINUX_PENDIN);
398 	lts->c_lflag |= cvtto_linux_mask(bts->c_lflag, IEXTEN, LINUX_IEXTEN);
399 
400 	mask = LINUX_B9600;	/* XXX default value */
401 	for (i = 0; i < sizeof (linux_speeds) / sizeof (speed_t); i++) {
402 		if (bts->c_ospeed == linux_speeds[i]) {
403 			mask = linux_spmasks[i];
404 			break;
405 		}
406 	}
407 	lts->c_cflag |= mask;
408 
409 	lts->c_cc[LINUX_VINTR] = bts->c_cc[VINTR];
410 	lts->c_cc[LINUX_VQUIT] = bts->c_cc[VQUIT];
411 	lts->c_cc[LINUX_VERASE] = bts->c_cc[VERASE];
412 	lts->c_cc[LINUX_VKILL] = bts->c_cc[VKILL];
413 	lts->c_cc[LINUX_VEOF] = bts->c_cc[VEOF];
414 	lts->c_cc[LINUX_VTIME] = bts->c_cc[VTIME];
415 	lts->c_cc[LINUX_VMIN] = bts->c_cc[VMIN];
416 	lts->c_cc[LINUX_VEOL] = bts->c_cc[VEOL];
417 	lts->c_cc[LINUX_VEOL2] = bts->c_cc[VEOL2];
418 	lts->c_cc[LINUX_VWERASE] = bts->c_cc[VWERASE];
419 	lts->c_cc[LINUX_VSUSP] = bts->c_cc[VSUSP];
420 	lts->c_cc[LINUX_VSTART] = bts->c_cc[VSTART];
421 	lts->c_cc[LINUX_VSTOP] = bts->c_cc[VSTOP];
422 	lts->c_cc[LINUX_VLNEXT] = bts->c_cc[VLNEXT];
423 	lts->c_cc[LINUX_VDISCARD] = bts->c_cc[VDISCARD];
424 	lts->c_cc[LINUX_VREPRINT] = bts->c_cc[VREPRINT];
425 	lts->c_cc[LINUX_VSWTC] = 0;
426 
427 	/* XXX should be fixed someday */
428 	lts->c_line = 0;
429 }
430 
431 /*
432  * Most ioctl command are just converted to their NetBSD values,
433  * and passed on. The ones that take structure pointers and (flag)
434  * values need some massaging. This is done the usual way by
435  * allocating stackgap memory, letting the actual ioctl call do its
436  * work their and converting back the data afterwards.
437  */
438 int
439 linux_ioctl(p, uap, retval)
440 	register struct proc *p;
441 	register struct linux_ioctl_args /* {
442 		syscallarg(int) fd;
443 		syscallarg(u_long) com;
444 		syscallarg(caddr_t) data;
445 	} */ *uap;
446 	register_t *retval;
447 {
448 	int fd;
449 	unsigned long com;
450 	caddr_t data, sg;
451 	struct file *fp;
452 	struct filedesc *fdp;
453 	struct linux_termio tmplt, *alt;
454 	struct linux_termios tmplts, *alts;
455 	struct termios tmpbts, *abts;
456 	struct ioctl_args ia;
457 	int error, idat, *idatp;
458 
459 	fd = SCARG(&ia, fd) = SCARG(uap, fd);
460 	com = SCARG(uap, com);
461 	data = SCARG(&ia, data) = SCARG(uap, data);
462 	retval[0] = 0;
463 
464 	fdp = p->p_fd;
465 	if ((u_int)fd >= fdp->fd_nfiles ||
466 	    (fp = fdp->fd_ofiles[fd]) == NULL)
467 		return (EBADF);
468 
469 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
470 		return (EBADF);
471 
472 	sg = stackgap_init();
473 
474 	switch (com) {
475 	case LINUX_TCGETS:
476 		SCARG(&ia, com) = TIOCGETA;
477 		abts = stackgap_alloc(&sg, sizeof (*abts));
478 		SCARG(&ia, data) = (caddr_t) abts;
479 		if ((error = ioctl(p, &ia, retval)) != 0)
480 			return error;
481 		if ((error = copyin(abts, &tmpbts, sizeof tmpbts)))
482 			return error;
483 		bsd_termios_to_linux_termios(&tmpbts, &tmplts);
484 		return copyout(&tmplts, data, sizeof tmplts);
485 	case LINUX_TCSETS:
486 	case LINUX_TCSETSW:
487 	case LINUX_TCSETSF:
488 		switch (com) {
489 		case LINUX_TCSETS:
490 			SCARG(&ia, com) = TIOCSETA;
491 			break;
492 		case LINUX_TCSETSW:
493 			SCARG(&ia, com) = TIOCSETAW;
494 			break;
495 		case LINUX_TCSETSF:
496 			SCARG(&ia, com) = TIOCSETAF;
497 			break;
498 		}
499 		if ((error = copyin(data, &tmplts, sizeof tmplts)))
500 			return error;
501 		abts = stackgap_alloc(&sg, sizeof tmpbts);
502 		/*
503 		 * First fill in all fields, so that we keep the current
504 		 * values for fields that Linux doesn't know about.
505 		 */
506 		if ((error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
507 		    (caddr_t) &tmpbts, p)))
508 			return error;
509 		linux_termios_to_bsd_termios(&tmplts, &tmpbts);
510 		if ((error = copyout(&tmpbts, abts, sizeof tmpbts)))
511 			return error;
512 		SCARG(&ia, data) = (caddr_t) abts;
513 		return ioctl(p, &ia, retval);
514 	case LINUX_TCGETA:
515 		SCARG(&ia, com) = TIOCGETA;
516 		abts = stackgap_alloc(&sg, sizeof (*abts));
517 		SCARG(&ia, data) = (caddr_t) abts;
518 		if ((error = ioctl(p, &ia, retval)) != 0)
519 			return error;
520 		if ((error = copyin(abts, &tmpbts, sizeof tmpbts)))
521 			return error;
522 		bsd_termios_to_linux_termio(&tmpbts, &tmplt);
523 		return copyout(&tmplt, data, sizeof tmplt);
524 	case LINUX_TCSETA:
525 	case LINUX_TCSETAW:
526 	case LINUX_TCSETAF:
527 		switch (com) {
528 		case LINUX_TCSETA:
529 			SCARG(&ia, com) = TIOCSETA;
530 			break;
531 		case LINUX_TCSETAW:
532 			SCARG(&ia, com) = TIOCSETAW;
533 			break;
534 		case LINUX_TCSETAF:
535 			SCARG(&ia, com) = TIOCSETAF;
536 			break;
537 		}
538 		if ((error = copyin(&tmplt, data, sizeof tmplt)))
539 			return error;
540 		abts = stackgap_alloc(&sg, sizeof tmpbts);
541 		/*
542 		 * First fill in all fields, so that we keep the current
543 		 * values for fields that Linux doesn't know about.
544 		 */
545 		if ((error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA,
546 		    (caddr_t) &tmpbts, p)))
547 			return error;
548 		linux_termio_to_bsd_termios(&tmplt, &tmpbts);
549 		if ((error = copyout(&tmpbts, abts, sizeof tmpbts)))
550 			return error;
551 		SCARG(&ia, data) = (caddr_t) abts;
552 		return ioctl(p, &ia, retval);
553 	case LINUX_TIOCSETD:
554 		if ((error = copyin(data, (caddr_t) &idat, sizeof idat)))
555 			return error;
556 		switch (idat) {
557 		case LINUX_N_TTY:
558 			idat = TTYDISC;
559 			break;
560 		case LINUX_N_SLIP:
561 			idat = SLIPDISC;
562 			break;
563 		case LINUX_N_PPP:
564 			idat = PPPDISC;
565 			break;
566 		/*
567 		 * We can't handle the mouse line discipline Linux has.
568 		 */
569 		case LINUX_N_MOUSE:
570 		default:
571 			return EINVAL;
572 		}
573 
574 		idatp = (int *) stackgap_alloc(&sg, sizeof (int));
575 		if ((error = copyout(&idat, idatp, sizeof (int))))
576 			return error;
577 		SCARG(&ia, com) = TIOCSETD;
578 		SCARG(&ia, data) = (caddr_t) idatp;
579 		break;
580 	case LINUX_TIOCGETD:
581 		idatp = (int *) stackgap_alloc(&sg, sizeof (int));
582 		SCARG(&ia, com) = TIOCGETD;
583 		SCARG(&ia, data) = (caddr_t) idatp;
584 		if ((error = ioctl(p, &ia, retval)))
585 			return error;
586 		if ((error = copyin(idatp, (caddr_t) &idat, sizeof (int))))
587 			return error;
588 		switch (idat) {
589 		case TTYDISC:
590 			idat = LINUX_N_TTY;
591 			break;
592 		case SLIPDISC:
593 			idat = LINUX_N_SLIP;
594 			break;
595 		case PPPDISC:
596 			idat = LINUX_N_PPP;
597 			break;
598 		/*
599 		 * Linux does not have the tablet line discipline.
600 		 */
601 		case TABLDISC:
602 		default:
603 			idat = -1;	/* XXX What should this be? */
604 			break;
605 		}
606 		return copyout(&idat, data, sizeof (int));
607 	case LINUX_TIOCGWINSZ:
608 		SCARG(&ia, com) = TIOCGWINSZ;
609 		break;
610 	case LINUX_TIOCSWINSZ:
611 		SCARG(&ia, com) = TIOCSWINSZ;
612 		break;
613 	case LINUX_TIOCGPGRP:
614 		SCARG(&ia, com) = TIOCGPGRP;
615 		break;
616 	case LINUX_TIOCSPGRP:
617 		SCARG(&ia, com) = TIOCSPGRP;
618 		break;
619 	case LINUX_FIONREAD:
620 		SCARG(&ia, com) = FIONREAD;
621 		break;
622 	case LINUX_FIONBIO:
623 		SCARG(&ia, com) = FIONBIO;
624 		break;
625 	case LINUX_FIOASYNC:
626 		SCARG(&ia, com) = FIOASYNC;
627 		break;
628 	case LINUX_TIOCEXCL:
629 		SCARG(&ia, com) = TIOCEXCL;
630 		break;
631 	case LINUX_TIOCNXCL:
632 		SCARG(&ia, com) = TIOCNXCL;
633 		break;
634 	case LINUX_TIOCCONS:
635 		SCARG(&ia, com) = TIOCCONS;
636 		break;
637 	case LINUX_TIOCNOTTY:
638 		SCARG(&ia, com) = TIOCNOTTY;
639 		break;
640 	default:
641 		return EINVAL;
642 	}
643 
644 	return ioctl(p, &ia, retval);
645 }
646