xref: /netbsd-src/sys/compat/linux/common/linux_termios.c (revision 7c3f385475147b6e1c4753f2bee961630e2dfc40)
1 /*	$NetBSD: linux_termios.c,v 1.34 2008/03/21 21:54:58 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Frank van der Linden and Eric Haszlakiewicz.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: linux_termios.c,v 1.34 2008/03/21 21:54:58 ad Exp $");
41 
42 #if defined(_KERNEL_OPT)
43 #include "opt_ptm.h"
44 #endif
45 
46 #include <sys/param.h>
47 #include <sys/proc.h>
48 #include <sys/systm.h>
49 #include <sys/file.h>
50 #include <sys/filedesc.h>
51 #include <sys/ioctl.h>
52 #include <sys/mount.h>
53 #include <sys/termios.h>
54 
55 #include <sys/syscallargs.h>
56 
57 #include <compat/linux/common/linux_types.h>
58 #include <compat/linux/common/linux_ioctl.h>
59 #include <compat/linux/common/linux_signal.h>
60 #include <compat/linux/common/linux_util.h>
61 #include <compat/linux/common/linux_termios.h>
62 #include <compat/linux/common/linux_ipc.h>
63 #include <compat/linux/common/linux_sem.h>
64 
65 #include <compat/linux/linux_syscallargs.h>
66 
67 #ifdef DEBUG_LINUX
68 #define DPRINTF(a)	uprintf a
69 #else
70 #define DPRINTF(a)
71 #endif
72 
73 int
74 linux_ioctl_termios(struct lwp *l, const struct linux_sys_ioctl_args *uap, register_t *retval)
75 {
76 	/* {
77 		syscallarg(int) fd;
78 		syscallarg(u_long) com;
79 		syscallarg(void *) data;
80 	} */
81 	file_t *fp;
82 	u_long com;
83 	struct linux_termio tmplt;
84 	struct linux_termios tmplts;
85 	struct termios tmpbts;
86 	int idat;
87 	struct sys_ioctl_args ia;
88 	int error;
89 	char tioclinux;
90 	int (*bsdioctl)(file_t *, u_long, void *);
91 
92 	if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
93 		return (EBADF);
94 
95 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
96 		error = EBADF;
97 		goto out;
98 	}
99 
100 	bsdioctl = fp->f_ops->fo_ioctl;
101 	com = SCARG(uap, com);
102 	retval[0] = 0;
103 
104 	switch (com) {
105 	case LINUX_TCGETS:
106 		error = (*bsdioctl)(fp, TIOCGETA, &tmpbts);
107 		if (error)
108 			goto out;
109 		bsd_termios_to_linux_termios(&tmpbts, &tmplts);
110 		error = copyout(&tmplts, SCARG(uap, data), sizeof tmplts);
111 		goto out;
112 	case LINUX_TCSETS:
113 	case LINUX_TCSETSW:
114 	case LINUX_TCSETSF:
115 		/*
116 		 * First fill in all fields, so that we keep the current
117 		 * values for fields that Linux doesn't know about.
118 		 */
119 		error = (*bsdioctl)(fp, TIOCGETA, &tmpbts);
120 		if (error)
121 			goto out;
122 		error = copyin(SCARG(uap, data), &tmplts, sizeof tmplts);
123 		if (error)
124 			goto out;
125 		linux_termios_to_bsd_termios(&tmplts, &tmpbts);
126 		switch (com) {
127 		case LINUX_TCSETS:
128 			com = TIOCSETA;
129 			break;
130 		case LINUX_TCSETSW:
131 			com = TIOCSETAW;
132 			break;
133 		case LINUX_TCSETSF:
134 			com = TIOCSETAF;
135 			break;
136 		}
137 		error = (*bsdioctl)(fp, com, &tmpbts);
138 		goto out;
139 	case LINUX_TCGETA:
140 		error = (*bsdioctl)(fp, TIOCGETA, &tmpbts);
141 		if (error)
142 			goto out;
143 		bsd_termios_to_linux_termio(&tmpbts, &tmplt);
144 		error = copyout(&tmplt, SCARG(uap, data), sizeof tmplt);
145 		goto out;
146 	case LINUX_TCSETA:
147 	case LINUX_TCSETAW:
148 	case LINUX_TCSETAF:
149 		/*
150 		 * First fill in all fields, so that we keep the current
151 		 * values for fields that Linux doesn't know about.
152 		 */
153 		error = (*bsdioctl)(fp, TIOCGETA, &tmpbts);
154 		if (error)
155 			goto out;
156 		error = copyin(SCARG(uap, data), &tmplt, sizeof tmplt);
157 		if (error)
158 			goto out;
159 		linux_termio_to_bsd_termios(&tmplt, &tmpbts);
160 		switch (com) {
161 		case LINUX_TCSETA:
162 			com = TIOCSETA;
163 			break;
164 		case LINUX_TCSETAW:
165 			com = TIOCSETAW;
166 			break;
167 		case LINUX_TCSETAF:
168 			com = TIOCSETAF;
169 			break;
170 		}
171 		error = (*bsdioctl)(fp, com, &tmpbts);
172 		goto out;
173 	case LINUX_TCFLSH:
174 		switch((u_long)SCARG(uap, data)) {
175 		case 0:
176 			idat = FREAD;
177 			break;
178 		case 1:
179 			idat = FWRITE;
180 			break;
181 		case 2:
182 			idat = 0;
183 			break;
184 		default:
185 			error = EINVAL;
186 			goto out;
187 		}
188 		error = (*bsdioctl)(fp, TIOCFLUSH, &idat);
189 		goto out;
190 	case LINUX_TIOCGETD:
191 		error = (*bsdioctl)(fp, TIOCGETD, &idat);
192 		if (error)
193 			goto out;
194 		switch (idat) {
195 		case TTYDISC:
196 			idat = LINUX_N_TTY;
197 			break;
198 		case SLIPDISC:
199 			idat = LINUX_N_SLIP;
200 			break;
201 		case PPPDISC:
202 			idat = LINUX_N_PPP;
203 			break;
204 		case STRIPDISC:
205 			idat = LINUX_N_STRIP;
206 			break;
207 		/*
208 		 * Linux does not have the tablet line discipline.
209 		 */
210 		case TABLDISC:
211 		default:
212 			idat = -1;	/* XXX What should this be? */
213 			break;
214 		}
215 		error = copyout(&idat, SCARG(uap, data), sizeof idat);
216 		goto out;
217 	case LINUX_TIOCSETD:
218 		error = copyin(SCARG(uap, data), &idat, sizeof idat);
219 		if (error)
220 			goto out;
221 		switch (idat) {
222 		case LINUX_N_TTY:
223 			idat = TTYDISC;
224 			break;
225 		case LINUX_N_SLIP:
226 			idat = SLIPDISC;
227 			break;
228 		case LINUX_N_PPP:
229 			idat = PPPDISC;
230 			break;
231 		case LINUX_N_STRIP:
232 			idat = STRIPDISC;
233 			break;
234 		/*
235 		 * We can't handle the mouse line discipline Linux has.
236 		 */
237 		case LINUX_N_MOUSE:
238 		case LINUX_N_AX25:
239 		case LINUX_N_X25:
240 		case LINUX_N_6PACK:
241 		default:
242 			error = EINVAL;
243 			goto out;
244 		}
245 		error = (*bsdioctl)(fp, TIOCSETD, &idat);
246 		goto out;
247 	case LINUX_TIOCLINUX:
248 		error = copyin(SCARG(uap, data), &tioclinux, sizeof tioclinux);
249 		if (error != 0)
250 			goto out;
251 		switch (tioclinux) {
252 		case LINUX_TIOCLINUX_KERNMSG:
253 			/*
254 			 * XXX needed to not fail for some things. Could
255 			 * try to use TIOCCONS, but the char argument
256 			 * specifies the VT #, not an fd.
257 			 */
258 			error = 0;
259 			goto out;
260 		case LINUX_TIOCLINUX_COPY:
261 		case LINUX_TIOCLINUX_PASTE:
262 		case LINUX_TIOCLINUX_UNBLANK:
263 		case LINUX_TIOCLINUX_LOADLUT:
264 		case LINUX_TIOCLINUX_READSHIFT:
265 		case LINUX_TIOCLINUX_READMOUSE:
266 		case LINUX_TIOCLINUX_VESABLANK:
267 		case LINUX_TIOCLINUX_CURCONS:	/* could use VT_GETACTIVE */
268 			error = EINVAL;
269 			goto out;
270 		}
271 		break;
272 	case LINUX_TIOCGWINSZ:
273 		SCARG(&ia, com) = TIOCGWINSZ;
274 		break;
275 	case LINUX_TIOCSWINSZ:
276 		SCARG(&ia, com) = TIOCSWINSZ;
277 		break;
278 	case LINUX_TIOCGPGRP:
279 		SCARG(&ia, com) = TIOCGPGRP;
280 		break;
281 	case LINUX_TIOCSPGRP:
282 		SCARG(&ia, com) = TIOCSPGRP;
283 		break;
284 	case LINUX_FIONREAD:
285 		SCARG(&ia, com) = FIONREAD;
286 		break;
287 	case LINUX_FIONBIO:
288 		SCARG(&ia, com) = FIONBIO;
289 		break;
290 	case LINUX_FIOASYNC:
291 		SCARG(&ia, com) = FIOASYNC;
292 		break;
293 	case LINUX_TIOCEXCL:
294 		SCARG(&ia, com) = TIOCEXCL;
295 		break;
296 	case LINUX_TIOCNXCL:
297 		SCARG(&ia, com) = TIOCNXCL;
298 		break;
299 	case LINUX_TIOCCONS:
300 		SCARG(&ia, com) = TIOCCONS;
301 		break;
302 	case LINUX_TIOCNOTTY:
303 		SCARG(&ia, com) = TIOCNOTTY;
304 		break;
305 	case LINUX_TCSBRK:
306 		SCARG(&ia, com) = SCARG(uap, data) ? TIOCDRAIN : TIOCSBRK;
307 		break;
308 	case LINUX_TIOCMGET:
309 		SCARG(&ia, com) = TIOCMGET;
310 		break;
311 	case LINUX_TIOCMSET:
312 		SCARG(&ia, com) = TIOCMSET;
313 		break;
314 	case LINUX_TIOCMBIC:
315 		SCARG(&ia, com) = TIOCMBIC;
316 		break;
317 	case LINUX_TIOCMBIS:
318 		SCARG(&ia, com) = TIOCMBIS;
319 		break;
320 #ifdef LINUX_TIOCGPTN
321 	case LINUX_TIOCGPTN:
322 #ifndef NO_DEV_PTM
323 		{
324 			struct ptmget ptm;
325 
326 			error = (*bsdioctl)(fp, TIOCPTSNAME, &ptm);
327 			if (error != 0)
328 				goto out;
329 			error = copyout(&ptm.sfd, SCARG(uap, data),
330 			    sizeof(ptm.sfd));
331 			goto out;
332 		}
333 #endif /* NO_DEV_PTM */
334 #endif /* LINUX_TIOCGPTN */
335 #ifdef LINUX_TIOCSPTLCK
336 	case LINUX_TIOCSPTLCK:
337 			fd_putfile(SCARG(uap, fd));
338 			error = copyin(SCARG(uap, data), &idat, sizeof(idat));
339 			if (error)
340 				return error;
341 			DPRINTF(("TIOCSPTLCK %d\n", idat));
342 			return 0;
343 #endif
344 	default:
345 		error = EINVAL;
346 		goto out;
347 	}
348 
349 	SCARG(&ia, fd) = SCARG(uap, fd);
350 	SCARG(&ia, data) = SCARG(uap, data);
351 	error = sys_ioctl(curlwp, &ia, retval);
352 out:
353 	fd_putfile(SCARG(uap, fd));
354 	return error;
355 }
356