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