1/*	$NetBSD: svr4_termios.c,v 1.26 2008/03/21 21:54:59 ad Exp $	 */
2
3/*-
4 * Copyright (c) 1994, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: svr4_termios.c,v 1.26 2008/03/21 21:54:59 ad Exp $");
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/termios.h>
42#include <sys/tty.h>
43#include <sys/socket.h>
44#include <sys/mount.h>
45#include <net/if.h>
46#include <sys/malloc.h>
47
48#include <sys/syscallargs.h>
49
50#include <compat/svr4/svr4_types.h>
51#include <compat/svr4/svr4_util.h>
52#include <compat/svr4/svr4_signal.h>
53#include <compat/svr4/svr4_ioctl.h>
54#include <compat/svr4/svr4_lwp.h>
55#include <compat/svr4/svr4_ucontext.h>
56#include <compat/svr4/svr4_syscallargs.h>
57#include <compat/svr4/svr4_stropts.h>
58#include <compat/svr4/svr4_termios.h>
59
60
61#ifndef __CONCAT3
62# if __STDC__
63#  define __CONCAT3(a,b,c)	a ## b ## c
64# else
65#  define __CONCAT3(a,b,c)	a/**/b/**/c
66# endif
67#endif
68
69static u_long bsd_to_svr4_speed(u_long, u_long);
70static u_long svr4_to_bsd_speed(u_long, u_long);
71static void svr4_to_bsd_termios(const struct svr4_termios *,
72				     struct termios *, int);
73static void bsd_to_svr4_termios(const struct termios *,
74				     struct svr4_termios *);
75static void svr4_termio_to_termios(const struct svr4_termio *,
76					struct svr4_termios *);
77static void svr4_termios_to_termio(const struct svr4_termios *,
78					struct svr4_termio *);
79#ifdef DEBUG_SVR4
80static void print_svr4_termios(const struct svr4_termios *);
81static void print_bsd_termios(const struct termios *);
82#endif /* DEBUG_SVR4 */
83
84#define undefined_char(a,b)				/**/
85#define undefined_flag1(f,a,b)				/**/
86#define undefined_flag2(f,a,b,c1,t1,c2,t2)		/**/
87#define undefined_flag4(f,a,b,c1,t1,c2,t2,c3,t3,c4,t4)	/**/
88
89#define svr4_to_bsd_char(a,b) \
90	if (new || __CONCAT3(SVR4_,a,b) < SVR4_NCC) { \
91		if (st->c_cc[__CONCAT3(SVR4_,a,b)] == SVR4_POSIX_VDISABLE) \
92			bt->c_cc[__CONCAT(a,b)] = _POSIX_VDISABLE; \
93		else \
94			bt->c_cc[__CONCAT(a,b)] = st->c_cc[__CONCAT3(SVR4_,a,b)]; \
95	}
96
97#define svr4_to_bsd_flag1(f,a,b) \
98	if (new || __CONCAT3(SVR4_,a,b) < 0200000) { \
99		if (st->f & __CONCAT3(SVR4_,a,b)) \
100			bt->f |= __CONCAT(a,b); \
101		else \
102			bt->f &= ~__CONCAT(a,b); \
103	}
104
105#define svr4_to_bsd_flag2(f,a,b,c1,t1,c2,t2) \
106	if (new || __CONCAT3(SVR4_,a,b) < 0200000) { \
107		bt->f &= ~__CONCAT(a,b); \
108		switch (st->f & __CONCAT3(SVR4_,a,b)) { \
109		case __CONCAT3(SVR4_,c1,t1): bt->f |= __CONCAT(c1,t1); break; \
110		case __CONCAT3(SVR4_,c2,t2): bt->f |= __CONCAT(c2,t2); break; \
111		} \
112	}
113
114#define svr4_to_bsd_flag4(f,a,b,c1,t1,c2,t2,c3,t3,c4,t4) \
115	if (new || __CONCAT3(SVR4_,a,b) < 0200000) { \
116		bt->f &= ~__CONCAT(a,b); \
117		switch (st->f & __CONCAT3(SVR4_,a,b)) { \
118		case __CONCAT3(SVR4_,c1,t1): bt->f |= __CONCAT(c1,t1); break; \
119		case __CONCAT3(SVR4_,c2,t2): bt->f |= __CONCAT(c2,t2); break; \
120		case __CONCAT3(SVR4_,c3,t3): bt->f |= __CONCAT(c3,t3); break; \
121		case __CONCAT3(SVR4_,c4,t4): bt->f |= __CONCAT(c4,t4); break; \
122		} \
123	}
124
125
126#define bsd_to_svr4_char(a,b) \
127	if (bt->c_cc[__CONCAT(a,b)] == _POSIX_VDISABLE) \
128		st->c_cc[__CONCAT3(SVR4_,a,b)] = SVR4_POSIX_VDISABLE; \
129	else \
130		st->c_cc[__CONCAT3(SVR4_,a,b)] = bt->c_cc[__CONCAT(a,b)]
131
132#define bsd_to_svr4_flag1(f,a,b) \
133	if (bt->f & __CONCAT(a,b)) \
134		st->f |= __CONCAT3(SVR4_,a,b); \
135	else \
136		st->f &= ~__CONCAT3(SVR4_,a,b)
137
138#define bsd_to_svr4_flag2(f,a,b,c1,t1,c2,t2) \
139	st->f &= ~__CONCAT(a,b); \
140	switch (bt->f & __CONCAT(a,b)) { \
141	case __CONCAT(c1,t1): st->f |= __CONCAT3(SVR4_,c1,t1); break; \
142	case __CONCAT(c2,t2): st->f |= __CONCAT3(SVR4_,c2,t2); break; \
143	}
144
145#define bsd_to_svr4_flag4(f,a,b,c1,t1,c2,t2,c3,t3,c4,t4) \
146	st->f &= ~__CONCAT(a,b); \
147	switch (bt->f & __CONCAT(a,b)) { \
148	case __CONCAT(c1,t1): st->f |= __CONCAT3(SVR4_,c1,t1); break; \
149	case __CONCAT(c2,t2): st->f |= __CONCAT3(SVR4_,c2,t2); break; \
150	case __CONCAT(c3,t3): st->f |= __CONCAT3(SVR4_,c3,t3); break; \
151	case __CONCAT(c4,t4): st->f |= __CONCAT3(SVR4_,c4,t4); break; \
152	}
153
154#ifdef DEBUG_SVR4
155static void
156print_svr4_termios(const struct svr4_termios *st)
157{
158	int i;
159	uprintf("SVR4\niflag=%lo oflag=%lo cflag=%lo lflag=%lo\n",
160	    st->c_iflag, st->c_oflag, st->c_cflag, st->c_lflag);
161	uprintf("cc: ");
162	for (i = 0; i < SVR4_NCCS; i++)
163		uprintf("%o ", st->c_cc[i]);
164	uprintf("\n");
165}
166
167
168static void
169print_bsd_termios(const struct termios *bt)
170{
171	int i;
172	uprintf("BSD\niflag=%o oflag=%o cflag=%o lflag=%o\n",
173	    bt->c_iflag, bt->c_oflag, bt->c_cflag, bt->c_lflag);
174	uprintf("cc: ");
175	for (i = 0; i < NCCS; i++)
176		uprintf("%o ", bt->c_cc[i]);
177	uprintf("\n");
178}
179#endif /* DEBUG_SVR4 */
180
181static u_long
182bsd_to_svr4_speed(u_long sp, u_long mask)
183{
184	switch (sp) {
185#undef getval
186#define getval(a,b)	case __CONCAT(a,b):	sp = __CONCAT3(SVR4_,a,b)
187	getval(B,0);
188	getval(B,50);
189	getval(B,75);
190	getval(B,110);
191	getval(B,134);
192	getval(B,150);
193	getval(B,200);
194	getval(B,300);
195	getval(B,600);
196	getval(B,1200);
197	getval(B,1800);
198	getval(B,2400);
199	getval(B,4800);
200	getval(B,9600);
201	getval(B,19200);
202	getval(B,38400);
203	getval(B,57600);
204	getval(B,115200);
205	default: sp = SVR4_B9600;	/* XXX */
206	}
207
208	while ((mask & 1) == 0) {
209		mask >>= 1;
210		sp <<= 1;
211	}
212
213	return sp;
214}
215
216
217static u_long
218svr4_to_bsd_speed(u_long sp, u_long mask)
219{
220	while ((mask & 1) == 0) {
221		mask >>= 1;
222		sp >>= 1;
223	}
224
225	switch (sp & mask) {
226#undef getval
227#define getval(a,b)	case __CONCAT3(SVR4_,a,b):	return __CONCAT(a,b)
228	getval(B,0);
229	getval(B,50);
230	getval(B,75);
231	getval(B,110);
232	getval(B,134);
233	getval(B,150);
234	getval(B,200);
235	getval(B,300);
236	getval(B,600);
237	getval(B,1200);
238	getval(B,1800);
239	getval(B,2400);
240	getval(B,4800);
241	getval(B,9600);
242	getval(B,19200);
243	getval(B,38400);
244	getval(B,57600);
245	getval(B,115200);
246	default: return B9600;	/* XXX */
247	}
248}
249
250
251static void
252svr4_to_bsd_termios(const struct svr4_termios *st, struct termios *bt, int new)
253{
254	/* control characters */
255	/*
256	 * We process VMIN and VTIME first,
257	 * because they are shared with VEOF and VEOL
258	 */
259	svr4_to_bsd_char(V,MIN);
260	svr4_to_bsd_char(V,TIME);
261
262	svr4_to_bsd_char(V,INTR);
263	svr4_to_bsd_char(V,QUIT);
264	svr4_to_bsd_char(V,ERASE);
265	svr4_to_bsd_char(V,KILL);
266	svr4_to_bsd_char(V,EOF);
267	svr4_to_bsd_char(V,EOL);
268	svr4_to_bsd_char(V,EOL2);
269	undefined_char(V,SWTCH);
270	svr4_to_bsd_char(V,START);
271	svr4_to_bsd_char(V,STOP);
272	svr4_to_bsd_char(V,SUSP);
273	svr4_to_bsd_char(V,DSUSP);
274	svr4_to_bsd_char(V,REPRINT);
275	svr4_to_bsd_char(V,DISCARD);
276	svr4_to_bsd_char(V,WERASE);
277	svr4_to_bsd_char(V,LNEXT);
278
279	/* Input modes */
280	svr4_to_bsd_flag1(c_iflag,I,GNBRK);
281	svr4_to_bsd_flag1(c_iflag,B,RKINT);
282	svr4_to_bsd_flag1(c_iflag,I,GNPAR);
283	svr4_to_bsd_flag1(c_iflag,P,ARMRK);
284	svr4_to_bsd_flag1(c_iflag,I,NPCK);
285	svr4_to_bsd_flag1(c_iflag,I,STRIP);
286	svr4_to_bsd_flag1(c_iflag,I,NLCR);
287	svr4_to_bsd_flag1(c_iflag,I,GNCR);
288	svr4_to_bsd_flag1(c_iflag,I,CRNL);
289	undefined_flag1(c_iflag,I,UCLC);
290	svr4_to_bsd_flag1(c_iflag,I,XON);
291	svr4_to_bsd_flag1(c_iflag,I,XANY);
292	svr4_to_bsd_flag1(c_iflag,I,XOFF);
293	svr4_to_bsd_flag1(c_iflag,I,MAXBEL);
294	undefined_flag1(c_iflag,D,OSMODE);
295
296	/* Output modes */
297	svr4_to_bsd_flag1(c_oflag,O,POST);
298	undefined_flag1(c_oflag,O,LCUC);
299	svr4_to_bsd_flag1(c_oflag,O,NLCR);
300	undefined_flag1(c_oflag,O,CRNL);
301	undefined_flag1(c_oflag,O,NOCR);
302	undefined_flag1(c_oflag,O,NLRET);
303	undefined_flag1(c_oflag,O,FILL);
304	undefined_flag1(c_oflag,O,FDEL);
305	undefined_flag2(c_oflag,N,LDLY,N,L0,N,L1);
306	undefined_flag4(c_oflag,C,RDLY,C,R0,C,R1,C,R2,C,R3);
307	undefined_flag4(c_oflag,T,ABDLY,T,AB0,T,AB1,T,AB2,T,AB3);
308	undefined_flag2(c_oflag,B,SDLY,B,S0,B,S1);
309	undefined_flag2(c_oflag,V,TDLY,V,T0,V,T1);
310	undefined_flag2(c_oflag,F,FDLY,F,F0,F,F1);
311	undefined_flag1(c_oflag,P,AGEOUT);
312	undefined_flag1(c_oflag,W,RAP);
313
314	/* Control modes */
315	bt->c_ospeed = svr4_to_bsd_speed(st->c_cflag, SVR4_CBAUD);
316	svr4_to_bsd_flag4(c_cflag,C,SIZE,C,S5,C,S6,C,S7,C,S8)
317	svr4_to_bsd_flag1(c_cflag,C,STOPB);
318	svr4_to_bsd_flag1(c_cflag,C,READ);
319	svr4_to_bsd_flag1(c_cflag,P,ARENB);
320	svr4_to_bsd_flag1(c_cflag,P,ARODD);
321	svr4_to_bsd_flag1(c_cflag,H,UPCL);
322	svr4_to_bsd_flag1(c_cflag,C,LOCAL);
323	undefined_flag1(c_cflag,R,CV1EN);
324	undefined_flag1(c_cflag,X,MT1EN);
325	undefined_flag1(c_cflag,L,OBLK);
326	undefined_flag1(c_cflag,X,CLUDE);
327	bt->c_ispeed = svr4_to_bsd_speed(st->c_cflag, SVR4_CIBAUD);
328	undefined_flag1(c_cflag,P,AREXT);
329
330	/* line discipline modes */
331	svr4_to_bsd_flag1(c_lflag,I,SIG);
332	svr4_to_bsd_flag1(c_lflag,I,CANON);
333	undefined_flag1(c_lflag,X,CASE);
334	svr4_to_bsd_flag1(c_lflag,E,CHO);
335	svr4_to_bsd_flag1(c_lflag,E,CHOE);
336	svr4_to_bsd_flag1(c_lflag,E,CHOK);
337	svr4_to_bsd_flag1(c_lflag,E,CHONL);
338	svr4_to_bsd_flag1(c_lflag,N,OFLSH);
339	svr4_to_bsd_flag1(c_lflag,T,OSTOP);
340	svr4_to_bsd_flag1(c_lflag,E,CHOCTL);
341	svr4_to_bsd_flag1(c_lflag,E,CHOPRT);
342	svr4_to_bsd_flag1(c_lflag,E,CHOKE);
343	undefined_flag1(c_lflag,D,EFECHO);
344	svr4_to_bsd_flag1(c_lflag,F,LUSHO);
345	svr4_to_bsd_flag1(c_lflag,P,ENDIN);
346	svr4_to_bsd_flag1(c_lflag,I,EXTEN);
347}
348
349
350static void
351bsd_to_svr4_termios(const struct termios *bt, struct svr4_termios *st)
352{
353	/* control characters */
354	/*
355	 * We process VMIN and VTIME first,
356	 * because they are shared with VEOF and VEOL
357	 */
358	bsd_to_svr4_char(V,MIN);
359	bsd_to_svr4_char(V,TIME);
360	bsd_to_svr4_char(V,INTR);
361	bsd_to_svr4_char(V,QUIT);
362	bsd_to_svr4_char(V,ERASE);
363	bsd_to_svr4_char(V,KILL);
364	bsd_to_svr4_char(V,EOF);
365	bsd_to_svr4_char(V,EOL);
366	bsd_to_svr4_char(V,EOL2);
367	undefined_char(V,SWTCH);
368	bsd_to_svr4_char(V,START);
369	bsd_to_svr4_char(V,STOP);
370	bsd_to_svr4_char(V,SUSP);
371	bsd_to_svr4_char(V,DSUSP);
372	bsd_to_svr4_char(V,REPRINT);
373	bsd_to_svr4_char(V,DISCARD);
374	bsd_to_svr4_char(V,WERASE);
375	bsd_to_svr4_char(V,LNEXT);
376
377	/* Input modes */
378	bsd_to_svr4_flag1(c_iflag,I,GNBRK);
379	bsd_to_svr4_flag1(c_iflag,B,RKINT);
380	bsd_to_svr4_flag1(c_iflag,I,GNPAR);
381	bsd_to_svr4_flag1(c_iflag,P,ARMRK);
382	bsd_to_svr4_flag1(c_iflag,I,NPCK);
383	bsd_to_svr4_flag1(c_iflag,I,STRIP);
384	bsd_to_svr4_flag1(c_iflag,I,NLCR);
385	bsd_to_svr4_flag1(c_iflag,I,GNCR);
386	bsd_to_svr4_flag1(c_iflag,I,CRNL);
387	undefined_flag1(c_iflag,I,UCLC);
388	bsd_to_svr4_flag1(c_iflag,I,XON);
389	bsd_to_svr4_flag1(c_iflag,I,XANY);
390	bsd_to_svr4_flag1(c_iflag,I,XOFF);
391	bsd_to_svr4_flag1(c_iflag,I,MAXBEL);
392	undefined_flag1(c_iflag,D,OSMODE);
393
394	/* Output modes */
395	bsd_to_svr4_flag1(c_oflag,O,POST);
396	undefined_flag1(c_oflag,O,LCUC);
397	bsd_to_svr4_flag1(c_oflag,O,NLCR);
398	undefined_flag1(c_oflag,O,CRNL);
399	undefined_flag1(c_oflag,O,NOCR);
400	undefined_flag1(c_oflag,O,NLRET);
401	undefined_flag1(c_oflag,O,FILL);
402	undefined_flag1(c_oflag,O,FDEL);
403	undefined_flag2(c_oflag,N,LDLY,N,L0,N,L1);
404	undefined_flag4(c_oflag,C,RDLY,C,R0,C,R1,C,R2,C,R3);
405	undefined_flag4(c_oflag,T,ABDLY,T,AB0,T,AB1,T,AB2,T,AB3);
406	undefined_flag2(c_oflag,B,SDLY,B,S0,B,S1);
407	undefined_flag2(c_oflag,V,TDLY,V,T0,V,T1);
408	undefined_flag2(c_oflag,F,FDLY,F,F0,F,F1);
409	undefined_flag1(c_oflag,P,AGEOUT);
410	undefined_flag1(c_oflag,W,RAP);
411
412	/* Control modes */
413	st->c_cflag &= ~SVR4_CBAUD;
414	st->c_cflag |= bsd_to_svr4_speed(bt->c_ospeed, SVR4_CBAUD);
415	bsd_to_svr4_flag4(c_cflag,C,SIZE,C,S5,C,S6,C,S7,C,S8)
416	bsd_to_svr4_flag1(c_cflag,C,STOPB);
417	bsd_to_svr4_flag1(c_cflag,C,READ);
418	bsd_to_svr4_flag1(c_cflag,P,ARENB);
419	bsd_to_svr4_flag1(c_cflag,P,ARODD);
420	bsd_to_svr4_flag1(c_cflag,H,UPCL);
421	bsd_to_svr4_flag1(c_cflag,C,LOCAL);
422	undefined_flag1(c_cflag,R,CV1EN);
423	undefined_flag1(c_cflag,X,MT1EN);
424	undefined_flag1(c_cflag,L,OBLK);
425	undefined_flag1(c_cflag,X,CLUDE);
426	st->c_cflag &= ~SVR4_CIBAUD;
427	st->c_cflag |= bsd_to_svr4_speed(bt->c_ispeed, SVR4_CIBAUD);
428
429	undefined_flag1(c_oflag,P,AREXT);
430
431	/* line discipline modes */
432	bsd_to_svr4_flag1(c_lflag,I,SIG);
433	bsd_to_svr4_flag1(c_lflag,I,CANON);
434	undefined_flag1(c_lflag,X,CASE);
435	bsd_to_svr4_flag1(c_lflag,E,CHO);
436	bsd_to_svr4_flag1(c_lflag,E,CHOE);
437	bsd_to_svr4_flag1(c_lflag,E,CHOK);
438	bsd_to_svr4_flag1(c_lflag,E,CHONL);
439	bsd_to_svr4_flag1(c_lflag,N,OFLSH);
440	bsd_to_svr4_flag1(c_lflag,T,OSTOP);
441	bsd_to_svr4_flag1(c_lflag,E,CHOCTL);
442	bsd_to_svr4_flag1(c_lflag,E,CHOPRT);
443	bsd_to_svr4_flag1(c_lflag,E,CHOKE);
444	undefined_flag1(c_lflag,D,EFECHO);
445	bsd_to_svr4_flag1(c_lflag,F,LUSHO);
446	bsd_to_svr4_flag1(c_lflag,P,ENDIN);
447	bsd_to_svr4_flag1(c_lflag,I,EXTEN);
448}
449
450
451static void
452svr4_termio_to_termios(const struct svr4_termio *t, struct svr4_termios *ts)
453{
454	int i;
455
456	ts->c_iflag = (svr4_tcflag_t) t->c_iflag;
457	ts->c_oflag = (svr4_tcflag_t) t->c_oflag;
458	ts->c_cflag = (svr4_tcflag_t) t->c_cflag;
459	ts->c_lflag = (svr4_tcflag_t) t->c_lflag;
460
461	for (i = 0; i < SVR4_NCC; i++)
462		ts->c_cc[i] = (svr4_cc_t) t->c_cc[i];
463}
464
465
466static void
467svr4_termios_to_termio(const struct svr4_termios *ts, struct svr4_termio *t)
468{
469	int i;
470
471	t->c_iflag = (u_short) ts->c_iflag;
472	t->c_oflag = (u_short) ts->c_oflag;
473	t->c_cflag = (u_short) ts->c_cflag;
474	t->c_lflag = (u_short) ts->c_lflag;
475	t->c_line = 0;	/* XXX */
476
477	for (i = 0; i < SVR4_NCC; i++)
478		t->c_cc[i] = (u_char) ts->c_cc[i];
479}
480
481int
482svr4_term_ioctl(file_t *fp, struct lwp *l, register_t *retval, int fd, u_long cmd, void *data)
483{
484	struct termios 		bt;
485	struct svr4_termios	st;
486	struct svr4_termio	t;
487	int			error, new;
488	int (*ctl)(file_t *, u_long,  void *) = fp->f_ops->fo_ioctl;
489
490	*retval = 0;
491
492	switch (cmd) {
493	case SVR4_TCGETA:
494	case SVR4_TCGETS:
495		if ((error = (*ctl)(fp, TIOCGETA, &bt)) != 0)
496			return error;
497
498		memset(&st, 0, sizeof(st));
499		bsd_to_svr4_termios(&bt, &st);
500
501		DPRINTF(("ioctl(TCGET%c);\n", cmd == SVR4_TCGETA ? 'A' : 'S'));
502#ifdef DEBUG_SVR4
503		print_bsd_termios(&bt);
504		print_svr4_termios(&st);
505#endif /* DEBUG_SVR4 */
506
507		if (cmd == SVR4_TCGETA) {
508		    svr4_termios_to_termio(&st, &t);
509		    return copyout(&t, data, sizeof(t));
510		}
511		else  {
512		    return copyout(&st, data, sizeof(st));
513		}
514
515	case SVR4_TCSETA:
516	case SVR4_TCSETS:
517	case SVR4_TCSETAW:
518	case SVR4_TCSETSW:
519	case SVR4_TCSETAF:
520	case SVR4_TCSETSF:
521		/* get full BSD termios so we don't lose information */
522		if ((error = (*ctl)(fp, TIOCGETA, &bt)) != 0)
523			return error;
524
525		switch (cmd) {
526		case SVR4_TCSETS:
527		case SVR4_TCSETSW:
528		case SVR4_TCSETSF:
529			if ((error = copyin(data, &st, sizeof(st))) != 0)
530				return error;
531			new = 1;
532			break;
533
534		case SVR4_TCSETA:
535		case SVR4_TCSETAW:
536		case SVR4_TCSETAF:
537			if ((error = copyin(data, &t, sizeof(t))) != 0)
538				return error;
539
540			svr4_termio_to_termios(&t, &st);
541			new = 0;
542			break;
543
544		default:
545			return EINVAL;
546		}
547
548		svr4_to_bsd_termios(&st, &bt, new);
549
550		switch (cmd) {
551		case SVR4_TCSETA:
552		case SVR4_TCSETS:
553			DPRINTF(("ioctl(TCSET[A|S]);\n"));
554			cmd = TIOCSETA;
555			break;
556		case SVR4_TCSETAW:
557		case SVR4_TCSETSW:
558			DPRINTF(("ioctl(TCSET[A|S]W);\n"));
559			cmd = TIOCSETAW;
560			break;
561		case SVR4_TCSETAF:
562		case SVR4_TCSETSF:
563			DPRINTF(("ioctl(TCSET[A|S]F);\n"));
564			cmd = TIOCSETAF;
565			break;
566		}
567
568#ifdef DEBUG_SVR4
569		print_bsd_termios(&bt);
570		print_svr4_termios(&st);
571#endif /* DEBUG_SVR4 */
572
573		return (*ctl)(fp, cmd, &bt);
574
575	case SVR4_TIOCGWINSZ:
576		{
577			struct svr4_winsize ws;
578
579			error = (*ctl)(fp, TIOCGWINSZ, &ws);
580			if (error)
581				return error;
582			return copyout(&ws, data, sizeof(ws));
583		}
584
585	case SVR4_TIOCSWINSZ:
586		{
587			struct svr4_winsize ws;
588
589			if ((error = copyin(data, &ws, sizeof(ws))) != 0)
590				return error;
591			return (*ctl)(fp, TIOCSWINSZ, &ws);
592		}
593
594	default:
595		return svr4_stream_ti_ioctl(fp, l, retval, fd, cmd, data);
596	}
597}
598