1/*	$NetBSD: ultrix_ioctl.c,v 1.35 2008/03/21 21:54:59 ad Exp $ */
2/*	from : NetBSD: sunos_ioctl.c,v 1.21 1995/10/07 06:27:31 mycroft Exp */
3
4/*
5 * Copyright (c) 1993 Markus Wild.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * loosely from: Header: sunos_ioctl.c,v 1.7 93/05/28 04:40:43 torek Exp
28 */
29
30#include <sys/cdefs.h>
31__KERNEL_RCSID(0, "$NetBSD: ultrix_ioctl.c,v 1.35 2008/03/21 21:54:59 ad Exp $");
32
33#if defined(_KERNEL_OPT)
34#include "opt_compat_ultrix.h"
35#include "opt_compat_sunos.h"
36#endif
37
38#include <sys/param.h>
39#include <sys/proc.h>
40#include <sys/systm.h>
41#include <sys/file.h>
42#include <sys/filedesc.h>
43#include <sys/ioctl.h>
44#include <sys/termios.h>
45#include <sys/tty.h>
46#include <sys/socket.h>
47#include <sys/audioio.h>
48#include <net/if.h>
49
50#include <sys/mount.h>
51
52#include <compat/sys/sockio.h>
53#include <compat/ultrix/ultrix_syscallargs.h>
54#include <sys/syscallargs.h>
55
56#include <compat/sunos/sunos.h>
57
58#include <compat/ultrix/ultrix_tty.h>
59
60#define emul_termio	ultrix_termio
61#define emul_termios	ultrix_termios
62
63/*
64 * SunOS ioctl calls.
65 * This file is something of a hodge-podge.
66 * Support gets added as things turn up....
67 */
68
69static const struct speedtab sptab[] = {
70	{ 0, 0 },
71	{ 50, 1 },
72	{ 75, 2 },
73	{ 110, 3 },
74	{ 134, 4 },
75	{ 135, 4 },
76	{ 150, 5 },
77	{ 200, 6 },
78	{ 300, 7 },
79	{ 600, 8 },
80	{ 1200, 9 },
81	{ 1800, 10 },
82	{ 2400, 11 },
83	{ 4800, 12 },
84	{ 9600, 13 },
85	{ 19200, 14 },
86	{ 38400, 15 },
87	{ -1, -1 }
88};
89
90static const uint16_t s2btab[] = {
91	0,
92	50,
93	75,
94	110,
95	134,
96	150,
97	200,
98	300,
99	600,
100	1200,
101	1800,
102	2400,
103	4800,
104	9600,
105	19200,
106	38400,
107};
108
109
110/*
111 * Translate a single tty control char from the emulation value
112 * to native termios, and vice-versa. Special-case
113 * the value of POSIX_VDISABLE, mapping it to and from 0.
114 */
115#define NATIVE_TO_EMUL_CC(bsd_cc) \
116 (((bsd_cc)   != _POSIX_VDISABLE) ? (bsd_cc) : 0)
117
118#define EMUL_TO_NATIVE_CC(emul_cc) \
119 (emul_cc) ? (emul_cc) : _POSIX_VDISABLE;
120
121
122static void stios2btios(struct emul_termios *, struct termios *);
123static void btios2stios(struct termios *, struct emul_termios *);
124static void stios2stio(struct emul_termios *, struct emul_termio *);
125static void stio2stios(struct emul_termio *, struct emul_termios *);
126
127/*
128 * these two conversion functions have mostly been done
129 * with some perl cut&paste, then handedited to comment
130 * out what doesn't exist under NetBSD.
131 * A note from Markus's code:
132 *	(l & BITMASK1) / BITMASK1 * BITMASK2  is translated
133 *	optimally by gcc m68k, much better than any ?: stuff.
134 *	Code may vary with different architectures of course.
135 *
136 * I don't know what optimizer you used, but seeing divu's and
137 * bfextu's in the m68k assembly output did not encourage me...
138 * as well, gcc on the sparc definately generates much better
139 * code with ?:.
140 */
141
142
143static void
144stios2btios(struct emul_termios *st, struct termios *bt)
145{
146	uint32_t l, r;
147
148	l = st->c_iflag;
149	r = 	((l & 0x00000001) ? IGNBRK	: 0);
150	r |=	((l & 0x00000002) ? BRKINT	: 0);
151	r |=	((l & 0x00000004) ? IGNPAR	: 0);
152	r |=	((l & 0x00000008) ? PARMRK	: 0);
153	r |=	((l & 0x00000010) ? INPCK	: 0);
154	r |=	((l & 0x00000020) ? ISTRIP	: 0);
155	r |= 	((l & 0x00000040) ? INLCR	: 0);
156	r |=	((l & 0x00000080) ? IGNCR	: 0);
157	r |=	((l & 0x00000100) ? ICRNL	: 0);
158	/*	((l & 0x00000200) ? IUCLC	: 0) */
159	r |=	((l & 0x00000400) ? IXON	: 0);
160	r |=	((l & 0x00000800) ? IXANY	: 0);
161	r |=	((l & 0x00001000) ? IXOFF	: 0);
162	r |=	((l & 0x00002000) ? IMAXBEL	: 0);
163	bt->c_iflag = r;
164
165	l = st->c_oflag;
166	r = 	((l & 0x00000001) ? OPOST	: 0);
167	/*	((l & 0x00000002) ? OLCUC	: 0) */
168	r |=	((l & 0x00000004) ? ONLCR	: 0);
169	/*	((l & 0x00000008) ? OCRNL	: 0) */
170	/*	((l & 0x00000010) ? ONOCR	: 0) */
171	/*	((l & 0x00000020) ? ONLRET	: 0) */
172	/*	((l & 0x00000040) ? OFILL	: 0) */
173	/*	((l & 0x00000080) ? OFDEL	: 0) */
174	/*	((l & 0x00000100) ? NLDLY	: 0) */
175	/*	((l & 0x00000100) ? NL1		: 0) */
176	/*	((l & 0x00000600) ? CRDLY	: 0) */
177	/*	((l & 0x00000200) ? CR1		: 0) */
178	/*	((l & 0x00000400) ? CR2		: 0) */
179	/*	((l & 0x00000600) ? CR3		: 0) */
180	/*	((l & 0x00001800) ? TABDLY	: 0) */
181	/*	((l & 0x00000800) ? TAB1	: 0) */
182	/*	((l & 0x00001000) ? TAB2	: 0) */
183	r |=	((l & 0x00001800) ? OXTABS	: 0);
184	/*	((l & 0x00002000) ? BSDLY	: 0) */
185	/*	((l & 0x00002000) ? BS1		: 0) */
186	/*	((l & 0x00004000) ? VTDLY	: 0) */
187	/*	((l & 0x00004000) ? VT1		: 0) */
188	/*	((l & 0x00008000) ? FFDLY	: 0) */
189	/*	((l & 0x00008000) ? FF1		: 0) */
190	/*	((l & 0x00010000) ? PAGEOUT	: 0) */
191	/*	((l & 0x00020000) ? WRAP	: 0) */
192	bt->c_oflag = r;
193
194	l = st->c_cflag;
195	switch (l & 0x00000030) {
196	case 0:
197		r = CS5;
198		break;
199	case 0x00000010:
200		r = CS6;
201		break;
202	case 0x00000020:
203		r = CS7;
204		break;
205	case 0x00000030:
206		r = CS8;
207		break;
208	}
209	r |=	((l & 0x00000040) ? CSTOPB	: 0);
210	r |=	((l & 0x00000080) ? CREAD	: 0);
211	r |= 	((l & 0x00000100) ? PARENB	: 0);
212	r |=	((l & 0x00000200) ? PARODD	: 0);
213	r |=	((l & 0x00000400) ? HUPCL	: 0);
214	r |=	((l & 0x00000800) ? CLOCAL	: 0);
215	/*	((l & 0x00001000) ? LOBLK	: 0) */
216	r |=	((l & 0x80000000) ? (CRTS_IFLOW|CCTS_OFLOW) : 0);
217	bt->c_cflag = r;
218
219	bt->c_ispeed = bt->c_ospeed = s2btab[l & 0x0000000f];
220
221	l = st->c_lflag;
222	r = 	((l & 0x00000001) ? ISIG	: 0);
223	r |=	((l & 0x00000002) ? ICANON	: 0);
224	/*	((l & 0x00000004) ? XCASE	: 0) */
225	r |=	((l & 0x00000008) ? ECHO	: 0);
226	r |=	((l & 0x00000010) ? ECHOE	: 0);
227	r |=	((l & 0x00000020) ? ECHOK	: 0);
228	r |=	((l & 0x00000040) ? ECHONL	: 0);
229	r |= 	((l & 0x00000080) ? NOFLSH	: 0);
230	r |=	((l & 0x00000100) ? TOSTOP	: 0);
231	r |=	((l & 0x00000200) ? ECHOCTL	: 0);
232	r |=	((l & 0x00000400) ? ECHOPRT	: 0);
233	r |=	((l & 0x00000800) ? ECHOKE	: 0);
234	/*	((l & 0x00001000) ? DEFECHO	: 0) */
235	r |=	((l & 0x00002000) ? FLUSHO	: 0);
236	r |=	((l & 0x00004000) ? PENDIN	: 0);
237	bt->c_lflag = r;
238
239	bt->c_cc[VINTR]    = EMUL_TO_NATIVE_CC(st->c_cc[0]);
240	bt->c_cc[VQUIT]    = EMUL_TO_NATIVE_CC(st->c_cc[1]);
241	bt->c_cc[VERASE]   = EMUL_TO_NATIVE_CC(st->c_cc[2]);
242	bt->c_cc[VKILL]    = EMUL_TO_NATIVE_CC(st->c_cc[3]);
243	bt->c_cc[VEOF]     = EMUL_TO_NATIVE_CC(st->c_cc[4]);
244	bt->c_cc[VEOL]     = EMUL_TO_NATIVE_CC(st->c_cc[5]);
245	bt->c_cc[VEOL2]    = EMUL_TO_NATIVE_CC(st->c_cc[6]);
246	/* not present on NetBSD */
247	/* bt->c_cc[VSWTCH]   = EMUL_TO_NATIVE_CC(st->c_cc[7]); */
248	bt->c_cc[VSTART]   = EMUL_TO_NATIVE_CC(st->c_cc[10]);
249	bt->c_cc[VSTOP]    = EMUL_TO_NATIVE_CC(st->c_cc[11]);
250	bt->c_cc[VSUSP]    = EMUL_TO_NATIVE_CC(st->c_cc[12]);
251	bt->c_cc[VDSUSP]   = EMUL_TO_NATIVE_CC(st->c_cc[13]);
252	bt->c_cc[VREPRINT] = EMUL_TO_NATIVE_CC(st->c_cc[14]);
253	bt->c_cc[VDISCARD] = EMUL_TO_NATIVE_CC(st->c_cc[15]);
254	bt->c_cc[VWERASE]  = EMUL_TO_NATIVE_CC(st->c_cc[16]);
255	bt->c_cc[VLNEXT]   = EMUL_TO_NATIVE_CC(st->c_cc[17]);
256	bt->c_cc[VSTATUS]  = EMUL_TO_NATIVE_CC(st->c_cc[18]);
257
258#ifdef COMPAT_ULTRIX
259	/* Ultrix termio/termios has real vmin/vtime */
260	bt->c_cc[VMIN]	   = EMUL_TO_NATIVE_CC(st->c_cc[8]);
261	bt->c_cc[VTIME]	   = EMUL_TO_NATIVE_CC(st->c_cc[9]);
262#else
263	/* if `raw mode', create native VMIN/VTIME from SunOS VEOF/VEOL */
264	bt->c_cc[VMIN]	   = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOF];
265	bt->c_cc[VTIME]	   = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOL];
266#endif
267
268}
269
270/*
271 * Convert bsd termios to "sunos" emulated termios
272 */
273static void
274btios2stios(struct termios *bt, struct emul_termios *st)
275{
276	uint32_t l, r;
277	int speed;
278
279	l = bt->c_iflag;
280	r = 	((l &  IGNBRK) ? 0x00000001	: 0);
281	r |=	((l &  BRKINT) ? 0x00000002	: 0);
282	r |=	((l &  IGNPAR) ? 0x00000004	: 0);
283	r |=	((l &  PARMRK) ? 0x00000008	: 0);
284	r |=	((l &   INPCK) ? 0x00000010	: 0);
285	r |=	((l &  ISTRIP) ? 0x00000020	: 0);
286	r |=	((l &   INLCR) ? 0x00000040	: 0);
287	r |=	((l &   IGNCR) ? 0x00000080	: 0);
288	r |=	((l &   ICRNL) ? 0x00000100	: 0);
289	/*	((l &   IUCLC) ? 0x00000200	: 0) */
290	r |=	((l &    IXON) ? 0x00000400	: 0);
291	r |=	((l &   IXANY) ? 0x00000800	: 0);
292	r |=	((l &   IXOFF) ? 0x00001000	: 0);
293	r |=	((l & IMAXBEL) ? 0x00002000	: 0);
294	st->c_iflag = r;
295
296	l = bt->c_oflag;
297	r =	((l &   OPOST) ? 0x00000001	: 0);
298	/*	((l &   OLCUC) ? 0x00000002	: 0) */
299	r |=	((l &   ONLCR) ? 0x00000004	: 0);
300	/*	((l &   OCRNL) ? 0x00000008	: 0) */
301	/*	((l &   ONOCR) ? 0x00000010	: 0) */
302	/*	((l &  ONLRET) ? 0x00000020	: 0) */
303	/*	((l &   OFILL) ? 0x00000040	: 0) */
304	/*	((l &   OFDEL) ? 0x00000080	: 0) */
305	/*	((l &   NLDLY) ? 0x00000100	: 0) */
306	/*	((l &     NL1) ? 0x00000100	: 0) */
307	/*	((l &   CRDLY) ? 0x00000600	: 0) */
308	/*	((l &     CR1) ? 0x00000200	: 0) */
309	/*	((l &     CR2) ? 0x00000400	: 0) */
310	/*	((l &     CR3) ? 0x00000600	: 0) */
311	/*	((l &  TABDLY) ? 0x00001800	: 0) */
312	/*	((l &    TAB1) ? 0x00000800	: 0) */
313	/*	((l &    TAB2) ? 0x00001000	: 0) */
314	r |=	((l &  OXTABS) ? 0x00001800	: 0);
315	/*	((l &   BSDLY) ? 0x00002000	: 0) */
316	/*	((l &     BS1) ? 0x00002000	: 0) */
317	/*	((l &   VTDLY) ? 0x00004000	: 0) */
318	/*	((l &     VT1) ? 0x00004000	: 0) */
319	/*	((l &   FFDLY) ? 0x00008000	: 0) */
320	/*	((l &     FF1) ? 0x00008000	: 0) */
321	/*	((l & PAGEOUT) ? 0x00010000	: 0) */
322	/*	((l &    WRAP) ? 0x00020000	: 0) */
323	st->c_oflag = r;
324
325	l = bt->c_cflag;
326	switch (l & CSIZE) {
327	case CS5:
328		r = 0;
329		break;
330	case CS6:
331		r = 0x00000010;
332		break;
333	case CS7:
334		r = 0x00000020;
335		break;
336	case CS8:
337		r = 0x00000030;
338		break;
339	}
340	r |=	((l &  CSTOPB) ? 0x00000040	: 0);
341	r |=	((l &   CREAD) ? 0x00000080	: 0);
342	r |=	((l &  PARENB) ? 0x00000100	: 0);
343	r |=	((l &  PARODD) ? 0x00000200	: 0);
344	r |=	((l &   HUPCL) ? 0x00000400	: 0);
345	r |=	((l &  CLOCAL) ? 0x00000800	: 0);
346	/*	((l &   LOBLK) ? 0x00001000	: 0) */
347	r |=	((l & (CRTS_IFLOW|CCTS_OFLOW)) ? 0x80000000 : 0);
348	st->c_cflag = r;
349
350	l = bt->c_lflag;
351	r =	((l &    ISIG) ? 0x00000001	: 0);
352	r |=	((l &  ICANON) ? 0x00000002	: 0);
353	/*	((l &   XCASE) ? 0x00000004	: 0) */
354	r |=	((l &    ECHO) ? 0x00000008	: 0);
355	r |=	((l &   ECHOE) ? 0x00000010	: 0);
356	r |=	((l &   ECHOK) ? 0x00000020	: 0);
357	r |=	((l &  ECHONL) ? 0x00000040	: 0);
358	r |=	((l &  NOFLSH) ? 0x00000080	: 0);
359	r |=	((l &  TOSTOP) ? 0x00000100	: 0);
360	r |=	((l & ECHOCTL) ? 0x00000200	: 0);
361	r |=	((l & ECHOPRT) ? 0x00000400	: 0);
362	r |=	((l &  ECHOKE) ? 0x00000800	: 0);
363	/*	((l & DEFECHO) ? 0x00001000	: 0) */
364	r |=	((l &  FLUSHO) ? 0x00002000	: 0);
365	r |=	((l &  PENDIN) ? 0x00004000	: 0);
366	st->c_lflag = r;
367
368	speed = ttspeedtab(bt->c_ospeed, sptab);
369	if (speed != -1)
370	    st->c_cflag |= speed;
371
372	st->c_cc[0] = NATIVE_TO_EMUL_CC(bt->c_cc[VINTR]);
373	st->c_cc[1] = NATIVE_TO_EMUL_CC(bt->c_cc[VQUIT]);
374	st->c_cc[2] = NATIVE_TO_EMUL_CC(bt->c_cc[VERASE]);
375	st->c_cc[3] = NATIVE_TO_EMUL_CC(bt->c_cc[VKILL]);
376	st->c_cc[4] = NATIVE_TO_EMUL_CC(bt->c_cc[VEOF]);
377	st->c_cc[5] = NATIVE_TO_EMUL_CC(bt->c_cc[VEOL]);
378	st->c_cc[6] = NATIVE_TO_EMUL_CC(bt->c_cc[VEOL2]);
379
380	/* XXX ultrix has a VSWTCH.  NetBSD does not. */
381#ifdef notdef
382	st->c_cc[7] = NATIVE_TO_EMUL_CC(bt->c_cc[VSWTCH]);
383#else
384	st->c_cc[7] = 0;
385#endif
386	st->c_cc[10] = NATIVE_TO_EMUL_CC(bt->c_cc[VSTART]);
387	st->c_cc[11] = NATIVE_TO_EMUL_CC(bt->c_cc[VSTOP]);
388	st->c_cc[12]= NATIVE_TO_EMUL_CC(bt->c_cc[VSUSP]);
389	st->c_cc[13]= NATIVE_TO_EMUL_CC(bt->c_cc[VDSUSP]);
390	st->c_cc[14]= NATIVE_TO_EMUL_CC(bt->c_cc[VREPRINT]);
391	st->c_cc[15]= NATIVE_TO_EMUL_CC(bt->c_cc[VDISCARD]);
392	st->c_cc[16]= NATIVE_TO_EMUL_CC(bt->c_cc[VWERASE]);
393	st->c_cc[17]= NATIVE_TO_EMUL_CC(bt->c_cc[VLNEXT]);
394	st->c_cc[18]= NATIVE_TO_EMUL_CC(bt->c_cc[VSTATUS]);
395
396#ifdef COMPAT_ULTRIX
397	st->c_cc[8]= NATIVE_TO_EMUL_CC(bt->c_cc[VMIN]);
398	st->c_cc[9]= NATIVE_TO_EMUL_CC(bt->c_cc[VTIME]);
399#else
400	if (!(bt->c_lflag & ICANON)) {
401		/* SunOS stores VMIN/VTIME in VEOF/VEOL (if ICANON is off) */
402		st->c_cc[4] = bt->c_cc[VMIN];
403		st->c_cc[5] = bt->c_cc[VTIME];
404	}
405#endif
406
407#ifdef COMPAT_SUNOS
408	st->c_line = 0;	/* 4.3bsd "old" line discipline */
409#else
410	st->c_line = 2;	/* 4.3bsd "new" line discipline, Ultrix default. */
411#endif
412}
413
414#define TERMIO_NCC 10	/* ultrix termio NCC is 10 */
415
416/*
417 * Convert emulated struct termios to termio(?)
418 */
419static void
420stios2stio(struct emul_termios *ts, struct emul_termio *t)
421{
422	t->c_iflag = ts->c_iflag;
423	t->c_oflag = ts->c_oflag;
424	t->c_cflag = ts->c_cflag;
425	t->c_lflag = ts->c_lflag;
426	t->c_line  = ts->c_line;
427	memcpy(t->c_cc, ts->c_cc, TERMIO_NCC);
428}
429
430/*
431 * Convert the other way
432 */
433static void
434stio2stios(struct emul_termio *t, struct emul_termios *ts)
435{
436	ts->c_iflag = t->c_iflag;
437	ts->c_oflag = t->c_oflag;
438	ts->c_cflag = t->c_cflag;
439	ts->c_lflag = t->c_lflag;
440	ts->c_line  = t->c_line;
441	memcpy(ts->c_cc, t->c_cc, TERMIO_NCC); /* don't touch the upper fields! */
442}
443
444static int
445ultrix_do_ioctl(int fd, int cmd, void *arg, struct lwp *l)
446{
447	file_t *fp;
448	int error;
449
450	if ((fp = fd_getfile(fd)) == NULL)
451		return EBADF;
452
453	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
454		error = EBADF;
455	else
456		error = fp->f_ops->fo_ioctl(fp, cmd, arg);
457	fd_putfile(fd);
458	return error;
459}
460
461int
462ultrix_sys_ioctl(struct lwp *l, const struct ultrix_sys_ioctl_args *uap, register_t *retval)
463{
464	struct sys_ioctl_args ap;
465	int error;
466
467	SCARG(&ap, fd) = SCARG(uap, fd);
468	SCARG(&ap, data) = SCARG(uap, data);
469	SCARG(&ap, com) = SCARG(uap, com);
470	switch (SCARG(&ap, com)) {
471	case _IOR('t', 0, int):
472		SCARG(&ap, com) = TIOCGETD;
473		break;
474	case _IOW('t', 1, int):
475	    {
476		int disc;
477
478		if ((error = copyin(SCARG(&ap, data), &disc, sizeof disc)) != 0)
479			return error;
480
481		/* map SunOS NTTYDISC into our termios discipline */
482		if (disc == 2)
483			disc = 0;
484		/* all other disciplines are not supported by NetBSD */
485		if (disc)
486			return ENXIO;
487
488		return ultrix_do_ioctl(SCARG(&ap, fd), TIOCSETD, &disc, l);
489	    }
490	case _IOW('t', 101, int):	/* sun SUNOS_TIOCSSOFTCAR */
491	    {
492		int x;	/* unused */
493
494		return copyin(&x, SCARG(&ap, data), sizeof x);
495	    }
496	case _IOR('t', 100, int):	/* sun SUNOS_TIOCSSOFTCAR */
497	    {
498		int x = 0;
499
500		return copyout(&x, SCARG(&ap, data), sizeof x);
501	    }
502	case _IO('t', 36): 		/* sun TIOCCONS, no parameters */
503	    {
504		int on = 1;
505		return ultrix_do_ioctl(SCARG(&ap, fd), TIOCCONS, &on, l);
506	    }
507	case _IOW('t', 37, struct sunos_ttysize):
508	    {
509		struct winsize ws;
510		struct sunos_ttysize ss;
511
512		if ((error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGWINSZ, &ws, l)) != 0)
513			return error;
514
515		if ((error = copyin(SCARG(&ap, data), &ss, sizeof (ss))) != 0)
516			return error;
517
518		ws.ws_row = ss.ts_row;
519		ws.ws_col = ss.ts_col;
520
521		return ultrix_do_ioctl(SCARG(&ap, fd), TIOCSWINSZ, &ws, l);
522	    }
523	case _IOW('t', 38, struct sunos_ttysize):
524	    {
525		struct winsize ws;
526		struct sunos_ttysize ss;
527
528		if ((error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGWINSZ, &ws, l)) != 0)
529			return error;
530
531		ss.ts_row = ws.ws_row;
532		ss.ts_col = ws.ws_col;
533
534		return copyout (&ss, SCARG(&ap, data), sizeof (ss));
535	    }
536	case _IOW('t', 118, int):
537		SCARG(&ap, com) = TIOCSPGRP;
538		break;
539	case _IOR('t', 119, int):
540		SCARG(&ap, com) = TIOCGPGRP;
541		break;
542
543	/* Emulate termio or termios tcget() */
544	case ULTRIX_TCGETA:
545	case ULTRIX_TCGETS:
546	    {
547		struct termios bts;
548		struct ultrix_termios sts;
549		struct ultrix_termio st;
550
551		if ((error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGETA, &bts, l)) != 0)
552			return error;
553
554		btios2stios (&bts, &sts);
555		if (SCARG(&ap, com) == ULTRIX_TCGETA) {
556			stios2stio (&sts, &st);
557			return copyout(&st, SCARG(&ap, data), sizeof (st));
558		} else
559			return copyout(&sts, SCARG(&ap, data), sizeof (sts));
560		/*NOTREACHED*/
561	    }
562	/* Emulate termio tcset() */
563	case ULTRIX_TCSETA:
564	case ULTRIX_TCSETAW:
565	case ULTRIX_TCSETAF:
566	    {
567		struct termios bts;
568		struct ultrix_termios sts;
569		struct ultrix_termio st;
570		int result;
571
572		if ((error = copyin(SCARG(&ap, data), &st, sizeof (st))) != 0)
573			return error;
574
575		/* get full BSD termios so we don't lose information */
576		if ((error = ultrix_do_ioctl(SCARG(&ap, fd), TIOCGETA, &bts, l)) != 0)
577			return error;
578
579		/*
580		 * convert to sun termios, copy in information from
581		 * termio, and convert back, then set new values.
582		 */
583		btios2stios(&bts, &sts);
584		stio2stios(&st, &sts);
585		stios2btios(&sts, &bts);
586
587		/*
588		 * map ioctl code: ultrix tcsets are numbered in reverse order
589		 */
590#ifdef notyet
591		return ultrix_do_ioctl(SCARG(&ap, fd), ULTRIX_TCSETA - SCARG(&ap, com) + TIOCSETA,
592		    &bts, l);
593#else
594		result= ultrix_do_ioctl(SCARG(&ap, fd), ULTRIX_TCSETA -  SCARG(&ap, com) + TIOCSETA,
595		    &bts, l);
596		printf("ultrix TCSETA %lx returns %d\n",
597		    ULTRIX_TCSETA - SCARG(&ap, com), result);
598		return result;
599#endif
600
601	    }
602	/* Emulate termios tcset() */
603	case ULTRIX_TCSETS:
604	case ULTRIX_TCSETSW:
605	case ULTRIX_TCSETSF:
606	    {
607		struct termios bts;
608		struct ultrix_termios sts;
609
610		if ((error = copyin(SCARG(&ap, data), &sts, sizeof (sts))) != 0)
611			return error;
612		stios2btios (&sts, &bts);
613		return ultrix_do_ioctl(SCARG(&ap, fd), ULTRIX_TCSETS - SCARG(&ap, com) + TIOCSETA,
614		    &bts, l);
615	    }
616/*
617 * Pseudo-tty ioctl translations.
618 */
619	case _IOW('t', 32, int): {	/* TIOCTCNTL */
620		int on;
621
622		error = copyin(SCARG(&ap, data), &on, sizeof (on));
623		if (error != 0)
624			return error;
625		return ultrix_do_ioctl(SCARG(&ap, fd), TIOCUCNTL, &on, l);
626	}
627	case _IOW('t', 33, int): {	/* TIOCSIGNAL */
628		int sig;
629
630		error = copyin(SCARG(&ap, data), &sig, sizeof (sig));
631		if (error != 0)
632			return error;
633		return ultrix_do_ioctl(SCARG(&ap, fd), TIOCSIG, &sig, l);
634	}
635
636/*
637 * Socket ioctl translations.
638 */
639#define IN_TYPE(a, type_t) { \
640	type_t localbuf; \
641	if ((error = copyin(SCARG(&ap, data), \
642				&localbuf, sizeof (type_t))) != 0) \
643		return error; \
644	return ultrix_do_ioctl(SCARG(&ap, fd), a, &localbuf, l); \
645}
646
647#define INOUT_TYPE(a, type_t) { \
648	type_t localbuf; \
649	if ((error = copyin(SCARG(&ap, data), &localbuf,	\
650			     sizeof (type_t))) != 0) \
651		return error; \
652	if ((error = ultrix_do_ioctl(SCARG(&ap, fd), a, &localbuf, l)) != 0) \
653		return error; \
654	return copyout(&localbuf, SCARG(&ap, data), sizeof (type_t)); \
655}
656
657
658#define IFREQ_IN(a) { \
659	struct oifreq ifreq; \
660	if ((error = copyin(SCARG(&ap, data), &ifreq, sizeof (ifreq))) != 0) \
661		return error; \
662	return ultrix_do_ioctl(SCARG(&ap, fd), a, &ifreq, l); \
663}
664
665#define IFREQ_INOUT(a) { \
666	struct oifreq ifreq; \
667	if ((error = copyin(SCARG(&ap, data), &ifreq, sizeof (ifreq))) != 0) \
668		return error; \
669	if ((error = ultrix_do_ioctl(SCARG(&ap, fd), a, &ifreq, l)) != 0) \
670		return error; \
671	return copyout(&ifreq, SCARG(&ap, data), sizeof (ifreq)); \
672}
673
674	case _IOW('i', 12, struct oifreq):
675		/* SIOCSIFADDR */
676		break;
677
678	case _IOWR('i', 13, struct oifreq):
679		IFREQ_INOUT(OOSIOCGIFADDR);
680
681	case _IOW('i', 14, struct oifreq):
682		/* SIOCSIFDSTADDR */
683		break;
684
685	case _IOWR('i', 15, struct oifreq):
686		IFREQ_INOUT(OOSIOCGIFDSTADDR);
687
688	case _IOW('i', 16, struct oifreq):
689		/* SIOCSIFFLAGS */
690		break;
691
692	case _IOWR('i', 17, struct oifreq):
693		/* SIOCGIFFLAGS */
694		break;
695
696	case _IOWR('i', 18, struct oifreq):
697		IFREQ_INOUT(SIOCGIFBRDADDR);
698
699	case _IOWR('i', 19, struct oifreq):
700		IFREQ_INOUT(SIOCSIFBRDADDR);
701
702	case _IOWR('i', 20, struct ifconf):	/* SIOCGIFCONF */
703	    {
704		struct ifconf ifconfarg;
705
706		/*
707		 * XXX: two more problems
708		 * 1. our sockaddr's are variable length, not always sizeof(sockaddr)
709		 * 2. this returns a name per protocol, ie. it returns two "lo0"'s
710		 */
711		error = copyin(SCARG(&ap, data), &ifconfarg, sizeof (ifconfarg));
712		if (error)
713			return error;
714		error = ultrix_do_ioctl(SCARG(&ap, fd), OSIOCGIFCONF, &ifconfarg, l);
715		if (error)
716			return error;
717		return copyout(&ifconfarg, SCARG(&ap, data), sizeof (ifconfarg));
718	    }
719
720
721	case _IOWR('i', 21, struct oifreq):
722		IFREQ_INOUT(OOSIOCGIFNETMASK);
723
724	case _IOW('i', 22, struct oifreq):
725		IFREQ_IN(SIOCSIFNETMASK);
726
727	/* 23: _IOWR('i', 23, struct oifreq):  Ultrix SIOCSPHYADDR */
728	/* 24: _IOWR('i', 24, struct oifreq):  Ultrix SIOCSADDMULTI */
729	/* 25: _IOWR('i', 25, struct oifreq):  Ultrix SIOCSDELMULTI */
730
731	case _IOW('i',  26, struct oifreq):	/* SIOCSIFRDCTRS? */
732	case _IOWR('i', 27, struct oifreq):	/* SIOCGIFZCTRS? */
733	case _IOWR('i', 28, struct oifreq):	/* read physaddr ? */
734		return EOPNOTSUPP;
735
736
737	case _IOW('i', 30, struct arpreq):
738		/* SIOCSARP */
739		break;
740
741	case _IOWR('i', 31, struct arpreq):
742		/* SIOCGARP */
743		break;
744
745	case _IOW('i', 32, struct arpreq):
746		/* SIOCDARP */
747		break;
748
749	case _IOW('i', 40, struct oifreq):	/* SIOCARPREQ */
750		return EOPNOTSUPP;
751
752	case _IOWR('i', 41, struct oifreq):
753		IFREQ_INOUT(SIOCGIFMETRIC);
754
755	case _IOWR('i', 42, struct oifreq):
756		IFREQ_IN(SIOCSIFMETRIC);
757
758	case _IOW('i', 44, struct oifreq):	/* SIOCSETSYNC */
759	case _IOWR('i', 45, struct oifreq):	/* SIOCGETSYNC */
760	case _IOWR('i', 46, struct oifreq):	/* SIOCSDSTATS */
761	case _IOWR('i', 47, struct oifreq):	/* SIOCSESTATS */
762	case _IOW('i', 48, int):		/* SIOCSPROMISC */
763		return EOPNOTSUPP;
764
765	/* emulate for vat, vic tools */
766	case _IOW('i', 49, struct oifreq):	/* SIOCADDMULTI */
767	case _IOW('i', 50, struct oifreq):	/* SIOCDELMULTI */
768		return EOPNOTSUPP;
769
770	}
771	return sys_ioctl(l, &ap, retval);
772}
773