linux_termios.c revision 1.22.4.7 1 /* $NetBSD: linux_termios.c,v 1.22.4.7 2008/03/24 09:38:41 yamt 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.22.4.7 2008/03/24 09:38:41 yamt 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