xref: /netbsd-src/sys/compat/sunos32/sunos32_ioctl.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: sunos32_ioctl.c,v 1.14 2004/04/25 06:23:40 matt Exp $	*/
2 /* from: NetBSD: sunos_ioctl.c,v 1.35 2001/02/03 22:20:02 mrg Exp 	*/
3 
4 /*
5  * Copyright (c) 2001 Matthew R. Green
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. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1993 Markus Wild.
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. The name of the author may not be used to endorse or promote products
42  *    derived from this software without specific prior written permission
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
45  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
48  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
53  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  *
55  * loosely from: Header: sunos_ioctl.c,v 1.7 93/05/28 04:40:43 torek Exp
56  */
57 
58 #include <sys/cdefs.h>
59 __KERNEL_RCSID(0, "$NetBSD: sunos32_ioctl.c,v 1.14 2004/04/25 06:23:40 matt Exp $");
60 
61 #if defined(_KERNEL_OPT)
62 #include "opt_compat_netbsd32.h"
63 #include "opt_execfmt.h"
64 #endif
65 
66 #include <sys/param.h>
67 #include <sys/proc.h>
68 #include <sys/systm.h>
69 #include <sys/file.h>
70 #include <sys/filedesc.h>
71 #include <sys/ioctl.h>
72 #include <sys/termios.h>
73 #include <sys/tty.h>
74 #include <sys/socket.h>
75 #include <sys/audioio.h>
76 #include <sys/vnode.h>
77 #include <sys/mount.h>
78 #include <sys/disklabel.h>
79 #include <sys/sa.h>
80 #include <sys/syscallargs.h>
81 
82 #include <miscfs/specfs/specdev.h>
83 
84 #include <net/if.h>
85 
86 #include <dev/sun/disklabel.h>
87 
88 #include <compat/sunos/sunos.h>
89 #include <compat/sunos/sunos_syscallargs.h>
90 #include <compat/netbsd32/netbsd32.h>
91 #include <compat/netbsd32/netbsd32_syscallargs.h>
92 #include <compat/sunos32/sunos32.h>
93 #include <compat/sunos32/sunos32_syscallargs.h>
94 #include <compat/common/compat_util.h>
95 
96 /*
97  * SunOS ioctl calls.
98  * This file is something of a hodge-podge.
99  * Support gets added as things turn up....
100  */
101 
102 static const struct speedtab sptab[] = {
103 	{ 0, 0 },
104 	{ 50, 1 },
105 	{ 75, 2 },
106 	{ 110, 3 },
107 	{ 134, 4 },
108 	{ 135, 4 },
109 	{ 150, 5 },
110 	{ 200, 6 },
111 	{ 300, 7 },
112 	{ 600, 8 },
113 	{ 1200, 9 },
114 	{ 1800, 10 },
115 	{ 2400, 11 },
116 	{ 4800, 12 },
117 	{ 9600, 13 },
118 	{ 19200, 14 },
119 	{ 38400, 15 },
120 	{ -1, -1 }
121 };
122 
123 static const netbsd32_u_long s2btab[] = {
124 	0,
125 	50,
126 	75,
127 	110,
128 	134,
129 	150,
130 	200,
131 	300,
132 	600,
133 	1200,
134 	1800,
135 	2400,
136 	4800,
137 	9600,
138 	19200,
139 	38400,
140 };
141 
142 static void stios2btios __P((struct sunos_termios *, struct termios *));
143 static void btios2stios __P((struct termios *, struct sunos_termios *));
144 static void stios2stio __P((struct sunos_termios *, struct sunos_termio *));
145 static void stio2stios __P((struct sunos_termio *, struct sunos_termios *));
146 
147 /*
148  * These two conversion functions have mostly been done
149  * with some perl cut&paste, then hand-edited to comment
150  * out what doesn't exist under NetBSD.
151  * A note from Markus's code:
152  *	(l & BITMASK1) / BITMASK1 * BITMASK2  is translated
153  *	optimally by gcc m68k, much better than any ?: stuff.
154  *	Code may vary with different architectures of course.
155  *
156  * I don't know what optimizer you used, but seeing divu's and
157  * bfextu's in the m68k assembly output did not encourage me...
158  * as well, gcc on the sparc definitely generates much better
159  * code with `?:'.
160  */
161 
162 static void
163 stios2btios(st, bt)
164 	struct sunos_termios *st;
165 	struct termios *bt;
166 {
167 	netbsd32_u_long l, r;
168 
169 	l = st->c_iflag;
170 	r = 	((l & 0x00000001) ? IGNBRK	: 0);
171 	r |=	((l & 0x00000002) ? BRKINT	: 0);
172 	r |=	((l & 0x00000004) ? IGNPAR	: 0);
173 	r |=	((l & 0x00000008) ? PARMRK	: 0);
174 	r |=	((l & 0x00000010) ? INPCK	: 0);
175 	r |=	((l & 0x00000020) ? ISTRIP	: 0);
176 	r |= 	((l & 0x00000040) ? INLCR	: 0);
177 	r |=	((l & 0x00000080) ? IGNCR	: 0);
178 	r |=	((l & 0x00000100) ? ICRNL	: 0);
179 	/*	((l & 0x00000200) ? IUCLC	: 0) */
180 	r |=	((l & 0x00000400) ? IXON	: 0);
181 	r |=	((l & 0x00000800) ? IXANY	: 0);
182 	r |=	((l & 0x00001000) ? IXOFF	: 0);
183 	r |=	((l & 0x00002000) ? IMAXBEL	: 0);
184 	bt->c_iflag = r;
185 
186 	l = st->c_oflag;
187 	r = 	((l & 0x00000001) ? OPOST	: 0);
188 	/*	((l & 0x00000002) ? OLCUC	: 0) */
189 	r |=	((l & 0x00000004) ? ONLCR	: 0);
190 	/*	((l & 0x00000008) ? OCRNL	: 0) */
191 	/*	((l & 0x00000010) ? ONOCR	: 0) */
192 	/*	((l & 0x00000020) ? ONLRET	: 0) */
193 	/*	((l & 0x00000040) ? OFILL	: 0) */
194 	/*	((l & 0x00000080) ? OFDEL	: 0) */
195 	/*	((l & 0x00000100) ? NLDLY	: 0) */
196 	/*	((l & 0x00000100) ? NL1		: 0) */
197 	/*	((l & 0x00000600) ? CRDLY	: 0) */
198 	/*	((l & 0x00000200) ? CR1		: 0) */
199 	/*	((l & 0x00000400) ? CR2		: 0) */
200 	/*	((l & 0x00000600) ? CR3		: 0) */
201 	/*	((l & 0x00001800) ? TABDLY	: 0) */
202 	/*	((l & 0x00000800) ? TAB1	: 0) */
203 	/*	((l & 0x00001000) ? TAB2	: 0) */
204 	r |=	((l & 0x00001800) ? OXTABS	: 0);
205 	/*	((l & 0x00002000) ? BSDLY	: 0) */
206 	/*	((l & 0x00002000) ? BS1		: 0) */
207 	/*	((l & 0x00004000) ? VTDLY	: 0) */
208 	/*	((l & 0x00004000) ? VT1		: 0) */
209 	/*	((l & 0x00008000) ? FFDLY	: 0) */
210 	/*	((l & 0x00008000) ? FF1		: 0) */
211 	/*	((l & 0x00010000) ? PAGEOUT	: 0) */
212 	/*	((l & 0x00020000) ? WRAP	: 0) */
213 	bt->c_oflag = r;
214 
215 	l = st->c_cflag;
216 	switch (l & 0x00000030) {
217 	case 0:
218 		r = CS5;
219 		break;
220 	case 0x00000010:
221 		r = CS6;
222 		break;
223 	case 0x00000020:
224 		r = CS7;
225 		break;
226 	case 0x00000030:
227 		r = CS8;
228 		break;
229 	}
230 	r |=	((l & 0x00000040) ? CSTOPB	: 0);
231 	r |=	((l & 0x00000080) ? CREAD	: 0);
232 	r |= 	((l & 0x00000100) ? PARENB	: 0);
233 	r |=	((l & 0x00000200) ? PARODD	: 0);
234 	r |=	((l & 0x00000400) ? HUPCL	: 0);
235 	r |=	((l & 0x00000800) ? CLOCAL	: 0);
236 	/*	((l & 0x00001000) ? LOBLK	: 0) */
237 	r |=	((l & 0x80000000) ? (CRTS_IFLOW|CCTS_OFLOW) : 0);
238 	bt->c_cflag = r;
239 
240 	bt->c_ispeed = bt->c_ospeed = s2btab[l & 0x0000000f];
241 
242 	l = st->c_lflag;
243 	r = 	((l & 0x00000001) ? ISIG	: 0);
244 	r |=	((l & 0x00000002) ? ICANON	: 0);
245 	/*	((l & 0x00000004) ? XCASE	: 0) */
246 	r |=	((l & 0x00000008) ? ECHO	: 0);
247 	r |=	((l & 0x00000010) ? ECHOE	: 0);
248 	r |=	((l & 0x00000020) ? ECHOK	: 0);
249 	r |=	((l & 0x00000040) ? ECHONL	: 0);
250 	r |= 	((l & 0x00000080) ? NOFLSH	: 0);
251 	r |=	((l & 0x00000100) ? TOSTOP	: 0);
252 	r |=	((l & 0x00000200) ? ECHOCTL	: 0);
253 	r |=	((l & 0x00000400) ? ECHOPRT	: 0);
254 	r |=	((l & 0x00000800) ? ECHOKE	: 0);
255 	/*	((l & 0x00001000) ? DEFECHO	: 0) */
256 	r |=	((l & 0x00002000) ? FLUSHO	: 0);
257 	r |=	((l & 0x00004000) ? PENDIN	: 0);
258 	bt->c_lflag = r;
259 
260 	bt->c_cc[VINTR]    = st->c_cc[0]  ? st->c_cc[0]  : _POSIX_VDISABLE;
261 	bt->c_cc[VQUIT]    = st->c_cc[1]  ? st->c_cc[1]  : _POSIX_VDISABLE;
262 	bt->c_cc[VERASE]   = st->c_cc[2]  ? st->c_cc[2]  : _POSIX_VDISABLE;
263 	bt->c_cc[VKILL]    = st->c_cc[3]  ? st->c_cc[3]  : _POSIX_VDISABLE;
264 	bt->c_cc[VEOF]     = st->c_cc[4]  ? st->c_cc[4]  : _POSIX_VDISABLE;
265 	bt->c_cc[VEOL]     = st->c_cc[5]  ? st->c_cc[5]  : _POSIX_VDISABLE;
266 	bt->c_cc[VEOL2]    = st->c_cc[6]  ? st->c_cc[6]  : _POSIX_VDISABLE;
267     /*	bt->c_cc[VSWTCH]   = st->c_cc[7]  ? st->c_cc[7]  : _POSIX_VDISABLE; */
268 	bt->c_cc[VSTART]   = st->c_cc[8]  ? st->c_cc[8]  : _POSIX_VDISABLE;
269 	bt->c_cc[VSTOP]    = st->c_cc[9]  ? st->c_cc[9]  : _POSIX_VDISABLE;
270 	bt->c_cc[VSUSP]    = st->c_cc[10] ? st->c_cc[10] : _POSIX_VDISABLE;
271 	bt->c_cc[VDSUSP]   = st->c_cc[11] ? st->c_cc[11] : _POSIX_VDISABLE;
272 	bt->c_cc[VREPRINT] = st->c_cc[12] ? st->c_cc[12] : _POSIX_VDISABLE;
273 	bt->c_cc[VDISCARD] = st->c_cc[13] ? st->c_cc[13] : _POSIX_VDISABLE;
274 	bt->c_cc[VWERASE]  = st->c_cc[14] ? st->c_cc[14] : _POSIX_VDISABLE;
275 	bt->c_cc[VLNEXT]   = st->c_cc[15] ? st->c_cc[15] : _POSIX_VDISABLE;
276 	bt->c_cc[VSTATUS]  = st->c_cc[16] ? st->c_cc[16] : _POSIX_VDISABLE;
277 
278 	/* if `raw mode', create native VMIN/VTIME from SunOS VEOF/VEOL */
279 	bt->c_cc[VMIN]	   = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOF];
280 	bt->c_cc[VTIME]	   = (bt->c_lflag & ICANON) ? 1 : bt->c_cc[VEOL];
281 }
282 
283 
284 static void
285 btios2stios(bt, st)
286 	struct termios *bt;
287 	struct sunos_termios *st;
288 {
289 	netbsd32_u_long l, r;
290 	int s;
291 
292 	l = bt->c_iflag;
293 	r = 	((l &  IGNBRK) ? 0x00000001	: 0);
294 	r |=	((l &  BRKINT) ? 0x00000002	: 0);
295 	r |=	((l &  IGNPAR) ? 0x00000004	: 0);
296 	r |=	((l &  PARMRK) ? 0x00000008	: 0);
297 	r |=	((l &   INPCK) ? 0x00000010	: 0);
298 	r |=	((l &  ISTRIP) ? 0x00000020	: 0);
299 	r |=	((l &   INLCR) ? 0x00000040	: 0);
300 	r |=	((l &   IGNCR) ? 0x00000080	: 0);
301 	r |=	((l &   ICRNL) ? 0x00000100	: 0);
302 	/*	((l &   IUCLC) ? 0x00000200	: 0) */
303 	r |=	((l &    IXON) ? 0x00000400	: 0);
304 	r |=	((l &   IXANY) ? 0x00000800	: 0);
305 	r |=	((l &   IXOFF) ? 0x00001000	: 0);
306 	r |=	((l & IMAXBEL) ? 0x00002000	: 0);
307 	st->c_iflag = r;
308 
309 	l = bt->c_oflag;
310 	r =	((l &   OPOST) ? 0x00000001	: 0);
311 	/*	((l &   OLCUC) ? 0x00000002	: 0) */
312 	r |=	((l &   ONLCR) ? 0x00000004	: 0);
313 	/*	((l &   OCRNL) ? 0x00000008	: 0) */
314 	/*	((l &   ONOCR) ? 0x00000010	: 0) */
315 	/*	((l &  ONLRET) ? 0x00000020	: 0) */
316 	/*	((l &   OFILL) ? 0x00000040	: 0) */
317 	/*	((l &   OFDEL) ? 0x00000080	: 0) */
318 	/*	((l &   NLDLY) ? 0x00000100	: 0) */
319 	/*	((l &     NL1) ? 0x00000100	: 0) */
320 	/*	((l &   CRDLY) ? 0x00000600	: 0) */
321 	/*	((l &     CR1) ? 0x00000200	: 0) */
322 	/*	((l &     CR2) ? 0x00000400	: 0) */
323 	/*	((l &     CR3) ? 0x00000600	: 0) */
324 	/*	((l &  TABDLY) ? 0x00001800	: 0) */
325 	/*	((l &    TAB1) ? 0x00000800	: 0) */
326 	/*	((l &    TAB2) ? 0x00001000	: 0) */
327 	r |=	((l &  OXTABS) ? 0x00001800	: 0);
328 	/*	((l &   BSDLY) ? 0x00002000	: 0) */
329 	/*	((l &     BS1) ? 0x00002000	: 0) */
330 	/*	((l &   VTDLY) ? 0x00004000	: 0) */
331 	/*	((l &     VT1) ? 0x00004000	: 0) */
332 	/*	((l &   FFDLY) ? 0x00008000	: 0) */
333 	/*	((l &     FF1) ? 0x00008000	: 0) */
334 	/*	((l & PAGEOUT) ? 0x00010000	: 0) */
335 	/*	((l &    WRAP) ? 0x00020000	: 0) */
336 	st->c_oflag = r;
337 
338 	l = bt->c_cflag;
339 	switch (l & CSIZE) {
340 	case CS5:
341 		r = 0;
342 		break;
343 	case CS6:
344 		r = 0x00000010;
345 		break;
346 	case CS7:
347 		r = 0x00000020;
348 		break;
349 	case CS8:
350 		r = 0x00000030;
351 		break;
352 	}
353 	r |=	((l &  CSTOPB) ? 0x00000040	: 0);
354 	r |=	((l &   CREAD) ? 0x00000080	: 0);
355 	r |=	((l &  PARENB) ? 0x00000100	: 0);
356 	r |=	((l &  PARODD) ? 0x00000200	: 0);
357 	r |=	((l &   HUPCL) ? 0x00000400	: 0);
358 	r |=	((l &  CLOCAL) ? 0x00000800	: 0);
359 	/*	((l &   LOBLK) ? 0x00001000	: 0) */
360 	r |=	((l & (CRTS_IFLOW|CCTS_OFLOW)) ? 0x80000000 : 0);
361 	st->c_cflag = r;
362 
363 	l = bt->c_lflag;
364 	r =	((l &    ISIG) ? 0x00000001	: 0);
365 	r |=	((l &  ICANON) ? 0x00000002	: 0);
366 	/*	((l &   XCASE) ? 0x00000004	: 0) */
367 	r |=	((l &    ECHO) ? 0x00000008	: 0);
368 	r |=	((l &   ECHOE) ? 0x00000010	: 0);
369 	r |=	((l &   ECHOK) ? 0x00000020	: 0);
370 	r |=	((l &  ECHONL) ? 0x00000040	: 0);
371 	r |=	((l &  NOFLSH) ? 0x00000080	: 0);
372 	r |=	((l &  TOSTOP) ? 0x00000100	: 0);
373 	r |=	((l & ECHOCTL) ? 0x00000200	: 0);
374 	r |=	((l & ECHOPRT) ? 0x00000400	: 0);
375 	r |=	((l &  ECHOKE) ? 0x00000800	: 0);
376 	/*	((l & DEFECHO) ? 0x00001000	: 0) */
377 	r |=	((l &  FLUSHO) ? 0x00002000	: 0);
378 	r |=	((l &  PENDIN) ? 0x00004000	: 0);
379 	st->c_lflag = r;
380 
381 	s = ttspeedtab(bt->c_ospeed, sptab);
382 	if (s >= 0)
383 		st->c_cflag |= s;
384 
385 	st->c_cc[0] = bt->c_cc[VINTR]   != _POSIX_VDISABLE? bt->c_cc[VINTR]:0;
386 	st->c_cc[1] = bt->c_cc[VQUIT]   != _POSIX_VDISABLE? bt->c_cc[VQUIT]:0;
387 	st->c_cc[2] = bt->c_cc[VERASE]  != _POSIX_VDISABLE? bt->c_cc[VERASE]:0;
388 	st->c_cc[3] = bt->c_cc[VKILL]   != _POSIX_VDISABLE? bt->c_cc[VKILL]:0;
389 	st->c_cc[4] = bt->c_cc[VEOF]    != _POSIX_VDISABLE? bt->c_cc[VEOF]:0;
390 	st->c_cc[5] = bt->c_cc[VEOL]    != _POSIX_VDISABLE? bt->c_cc[VEOL]:0;
391 	st->c_cc[6] = bt->c_cc[VEOL2]   != _POSIX_VDISABLE? bt->c_cc[VEOL2]:0;
392 	st->c_cc[7] = 0;
393 		/*    bt->c_cc[VSWTCH]  != _POSIX_VDISABLE? bt->c_cc[VSWTCH]: */
394 	st->c_cc[8] = bt->c_cc[VSTART]  != _POSIX_VDISABLE? bt->c_cc[VSTART]:0;
395 	st->c_cc[9] = bt->c_cc[VSTOP]   != _POSIX_VDISABLE? bt->c_cc[VSTOP]:0;
396 	st->c_cc[10]= bt->c_cc[VSUSP]   != _POSIX_VDISABLE? bt->c_cc[VSUSP]:0;
397 	st->c_cc[11]= bt->c_cc[VDSUSP]  != _POSIX_VDISABLE? bt->c_cc[VDSUSP]:0;
398 	st->c_cc[12]= bt->c_cc[VREPRINT]!= _POSIX_VDISABLE? bt->c_cc[VREPRINT]:0;
399 	st->c_cc[13]= bt->c_cc[VDISCARD]!= _POSIX_VDISABLE? bt->c_cc[VDISCARD]:0;
400 	st->c_cc[14]= bt->c_cc[VWERASE] != _POSIX_VDISABLE? bt->c_cc[VWERASE]:0;
401 	st->c_cc[15]= bt->c_cc[VLNEXT]  != _POSIX_VDISABLE? bt->c_cc[VLNEXT]:0;
402 	st->c_cc[16]= bt->c_cc[VSTATUS] != _POSIX_VDISABLE? bt->c_cc[VSTATUS]:0;
403 
404 	if (!(bt->c_lflag & ICANON)) {
405 		/* SunOS stores VMIN/VTIME in VEOF/VEOL (if ICANON is off) */
406 		st->c_cc[4] = bt->c_cc[VMIN];
407 		st->c_cc[5] = bt->c_cc[VTIME];
408 	}
409 
410 	st->c_line = 0;
411 }
412 
413 static void
414 stios2stio(ts, t)
415 	struct sunos_termios *ts;
416 	struct sunos_termio *t;
417 {
418 	t->c_iflag = ts->c_iflag;
419 	t->c_oflag = ts->c_oflag;
420 	t->c_cflag = ts->c_cflag;
421 	t->c_lflag = ts->c_lflag;
422 	t->c_line  = ts->c_line;
423 	memcpy(t->c_cc, ts->c_cc, 8);
424 }
425 
426 static void
427 stio2stios(t, ts)
428 	struct sunos_termio *t;
429 	struct sunos_termios *ts;
430 {
431 	ts->c_iflag = t->c_iflag;
432 	ts->c_oflag = t->c_oflag;
433 	ts->c_cflag = t->c_cflag;
434 	ts->c_lflag = t->c_lflag;
435 	ts->c_line  = t->c_line;
436 	memcpy(ts->c_cc, t->c_cc, 8); /* don't touch the upper fields! */
437 }
438 
439 int
440 sunos32_sys_ioctl(l, v, retval)
441 	struct lwp *l;
442 	void *v;
443 	register_t *retval;
444 {
445 	struct sunos32_sys_ioctl_args /* {
446 		int	fd;
447 		netbsd32_u_long	com;
448 		netbsd32_caddr_t	data;
449 	} */ *uap = v;
450 	struct proc *p = l->l_proc;
451 	struct filedesc *fdp = p->p_fd;
452 	struct file *fp;
453 	int (*ctl)(struct file *, u_long, void *, struct proc *);
454 	int error;
455 
456 	if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
457 		return EBADF;
458 
459 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
460 		return EBADF;
461 
462 	ctl = fp->f_ops->fo_ioctl;
463 
464 	switch (SCARG(uap, com)) {
465 	case _IOR('t', 0, int):
466 		SCARG(uap, com) = TIOCGETD;
467 		break;
468 	case _IOW('t', 1, int):
469 	    {
470 		int disc;
471 
472 		if ((error = copyin((caddr_t)(u_long)SCARG(uap, data), &disc,
473 		    sizeof disc)) != 0)
474 			return error;
475 
476 		/* map SunOS NTTYDISC into our termios discipline */
477 		if (disc == 2)
478 			disc = 0;
479 		/* all other disciplines are not supported by NetBSD */
480 		if (disc)
481 			return ENXIO;
482 
483 		return (*ctl)(fp, TIOCSETD, &disc, p);
484 	    }
485 	case _IOW('t', 101, int):	/* sun SUNOS_TIOCSSOFTCAR */
486 	    {
487 		int x;	/* unused */
488 
489 		return copyin((caddr_t)(u_long)SCARG(uap, data), &x, sizeof x);
490 	    }
491 	case _IOR('t', 100, int):	/* sun SUNOS_TIOCSSOFTCAR */
492 	    {
493 		int x = 0;
494 
495 		return copyout(&x, (caddr_t)(u_long)SCARG(uap, data), sizeof x);
496 	    }
497 	case _IO('t', 36): 		/* sun TIOCCONS, no parameters */
498 	    {
499 		int on = 1;
500 		return (*ctl)(fp, TIOCCONS, &on, p);
501 	    }
502 	case _IOW('t', 37, struct sunos_ttysize):
503 	    {
504 		struct winsize ws;
505 		struct sunos_ttysize ss;
506 
507 		if ((error = (*ctl)(fp, TIOCGWINSZ, &ws, p)) != 0)
508 			return (error);
509 
510 		if ((error = copyin((caddr_t)(u_long)SCARG(uap, data), &ss, sizeof (ss))) != 0)
511 			return error;
512 
513 		ws.ws_row = ss.ts_row;
514 		ws.ws_col = ss.ts_col;
515 
516 		return ((*ctl)(fp, TIOCSWINSZ, &ws, p));
517 	    }
518 	case _IOW('t', 38, struct sunos_ttysize):
519 	    {
520 		struct winsize ws;
521 		struct sunos_ttysize ss;
522 
523 		if ((error = (*ctl)(fp, TIOCGWINSZ, &ws, p)) != 0)
524 			return (error);
525 
526 		ss.ts_row = ws.ws_row;
527 		ss.ts_col = ws.ws_col;
528 
529 		return copyout(&ss, (caddr_t)(u_long)SCARG(uap, data), sizeof (ss));
530 	    }
531 	case _IOW('t', 130, int):	/* TIOCSETPGRP: posix variant */
532 		SCARG(uap, com) = TIOCSPGRP;
533 		break;
534 	case _IOR('t', 131, int):	/* TIOCGETPGRP: posix variant */
535 	    {
536 		/*
537 		 * sigh, must do error translation on pty devices
538 		 * (see also kern/tty_pty.c)
539 		 */
540 		int pgrp;
541 		struct vnode *vp;
542 		error = (*ctl)(fp, TIOCGPGRP, &pgrp, p);
543 		if (error) {
544 			vp = (struct vnode *)fp->f_data;
545 			if (error == EIO && vp != NULL &&
546 			    vp->v_type == VCHR && major(vp->v_rdev) == 21)
547 				error = ENOTTY;
548 			return (error);
549 		}
550 		return copyout(&pgrp, (caddr_t)(u_long)SCARG(uap, data), sizeof(pgrp));
551 	    }
552 	case _IO('t', 132):
553 		SCARG(uap, com) = TIOCSCTTY;
554 		break;
555 	case SUNOS_TCGETA:
556 	case SUNOS_TCGETS:
557 	    {
558 		struct termios bts;
559 		struct sunos_termios sts;
560 		struct sunos_termio st;
561 
562 		if ((error = (*ctl)(fp, TIOCGETA, &bts, p)) != 0)
563 			return error;
564 
565 		btios2stios (&bts, &sts);
566 		if (SCARG(uap, com) == SUNOS_TCGETA) {
567 			stios2stio (&sts, &st);
568 			return copyout(&st, (caddr_t)(u_long)SCARG(uap, data),
569 			    sizeof (st));
570 		} else
571 			return copyout(&sts, (caddr_t)(u_long)SCARG(uap, data),
572 			    sizeof (sts));
573 		/*NOTREACHED*/
574 	    }
575 	case SUNOS_TCSETA:
576 	case SUNOS_TCSETAW:
577 	case SUNOS_TCSETAF:
578 	    {
579 		struct termios bts;
580 		struct sunos_termios sts;
581 		struct sunos_termio st;
582 
583 		if ((error = copyin((caddr_t)(u_long)SCARG(uap, data), &st,
584 		    sizeof (st))) != 0)
585 			return error;
586 
587 		/* get full BSD termios so we don't lose information */
588 		if ((error = (*ctl)(fp, TIOCGETA, &bts, p)) != 0)
589 			return error;
590 
591 		/*
592 		 * convert to sun termios, copy in information from
593 		 * termio, and convert back, then set new values.
594 		 */
595 		btios2stios(&bts, &sts);
596 		stio2stios(&st, &sts);
597 		stios2btios(&sts, &bts);
598 
599 		return (*ctl)(fp, SCARG(uap, com) - SUNOS_TCSETA + TIOCSETA,
600 		    &bts, p);
601 	    }
602 	case SUNOS_TCSETS:
603 	case SUNOS_TCSETSW:
604 	case SUNOS_TCSETSF:
605 	    {
606 		struct termios bts;
607 		struct sunos_termios sts;
608 
609 		if ((error = copyin((caddr_t)(u_long)SCARG(uap, data), &sts,
610 		    sizeof (sts))) != 0)
611 			return error;
612 		stios2btios (&sts, &bts);
613 		return (*ctl)(fp, SCARG(uap, com) - SUNOS_TCSETS + TIOCSETA,
614 		    &bts, p);
615 	    }
616 /*
617  * Pseudo-tty ioctl translations.
618  */
619 	case _IOW('t', 32, int): {	/* TIOCTCNTL */
620 		int error, on;
621 
622 		error = copyin((caddr_t)(u_long)SCARG(uap, data), &on, sizeof (on));
623 		if (error)
624 			return error;
625 		return (*ctl)(fp, TIOCUCNTL, &on, p);
626 	}
627 	case _IOW('t', 33, int): {	/* TIOCSIGNAL */
628 		int error, sig;
629 
630 		error = copyin((caddr_t)(u_long)SCARG(uap, data), &sig, sizeof (sig));
631 		if (error)
632 			return error;
633 		return (*ctl)(fp, TIOCSIG, &sig, p);
634 	}
635 
636 /*
637  * Socket ioctl translations.
638  */
639 #define IFREQ_IN(a) { \
640 	struct ifreq ifreq; \
641 	error = copyin((caddr_t)(u_long)SCARG(uap, data), &ifreq, sizeof (ifreq)); \
642 	if (error) \
643 		return error; \
644 	return (*ctl)(fp, a, &ifreq, p); \
645 }
646 #define IFREQ_INOUT(a) { \
647 	struct ifreq ifreq; \
648 	error = copyin((caddr_t)(u_long)SCARG(uap, data), &ifreq, sizeof (ifreq)); \
649 	if (error) \
650 		return error; \
651 	if ((error = (*ctl)(fp, a, &ifreq, p)) != 0) \
652 		return error; \
653 	return copyout(&ifreq, (caddr_t)(u_long)SCARG(uap, data), sizeof (ifreq)); \
654 }
655 
656 	case _IOW('i', 12, struct ifreq):
657 		/* SIOCSIFADDR */
658 		break;
659 
660 	case _IOWR('i', 13, struct ifreq):
661 		IFREQ_INOUT(OSIOCGIFADDR);
662 
663 	case _IOW('i', 14, struct ifreq):
664 		/* SIOCSIFDSTADDR */
665 		break;
666 
667 	case _IOWR('i', 15, struct ifreq):
668 		IFREQ_INOUT(OSIOCGIFDSTADDR);
669 
670 	case _IOW('i', 16, struct ifreq):
671 		/* SIOCSIFFLAGS */
672 		break;
673 
674 	case _IOWR('i', 17, struct ifreq):
675 		/* SIOCGIFFLAGS */
676 		break;
677 
678 	case _IOW('i', 21, struct ifreq):
679 		IFREQ_IN(SIOCSIFMTU);
680 
681 	case _IOWR('i', 22, struct ifreq):
682 		IFREQ_INOUT(SIOCGIFMTU);
683 
684 	case _IOWR('i', 23, struct ifreq):
685 		IFREQ_INOUT(SIOCGIFBRDADDR);
686 
687 	case _IOW('i', 24, struct ifreq):
688 		IFREQ_IN(SIOCSIFBRDADDR);
689 
690 	case _IOWR('i', 25, struct ifreq):
691 		IFREQ_INOUT(OSIOCGIFNETMASK);
692 
693 	case _IOW('i', 26, struct ifreq):
694 		IFREQ_IN(SIOCSIFNETMASK);
695 
696 	case _IOWR('i', 27, struct ifreq):
697 		IFREQ_INOUT(SIOCGIFMETRIC);
698 
699 	case _IOWR('i', 28, struct ifreq):
700 		IFREQ_IN(SIOCSIFMETRIC);
701 
702 	case _IOW('i', 30, struct arpreq):
703 		/* SIOCSARP */
704 		break;
705 
706 	case _IOWR('i', 31, struct arpreq):
707 		/* SIOCGARP */
708 		break;
709 
710 	case _IOW('i', 32, struct arpreq):
711 		/* SIOCDARP */
712 		break;
713 
714 	case _IOW('i', 18, struct ifreq):	/* SIOCSIFMEM */
715 	case _IOWR('i', 19, struct ifreq):	/* SIOCGIFMEM */
716 	case _IOW('i', 40, struct ifreq):	/* SIOCUPPER */
717 	case _IOW('i', 41, struct ifreq):	/* SIOCLOWER */
718 	case _IOW('i', 44, struct ifreq):	/* SIOCSETSYNC */
719 	case _IOWR('i', 45, struct ifreq):	/* SIOCGETSYNC */
720 	case _IOWR('i', 46, struct ifreq):	/* SIOCSDSTATS */
721 	case _IOWR('i', 47, struct ifreq):	/* SIOCSESTATS */
722 	case _IOW('i', 48, int):		/* SIOCSPROMISC */
723 	case _IOW('i', 49, struct ifreq):	/* SIOCADDMULTI */
724 	case _IOW('i', 50, struct ifreq):	/* SIOCDELMULTI */
725 		return EOPNOTSUPP;
726 
727 	case _IOWR('i', 20, struct ifconf):	/* SIOCGIFCONF */
728 	    {
729 		struct ifconf ifconf;
730 
731 		/*
732 		 * XXX: two more problems
733 		 * 1. our sockaddr's are variable length, not always sizeof(sockaddr)
734 		 * 2. this returns a name per protocol, ie. it returns two "lo0"'s
735 		 */
736 		error = copyin((caddr_t)(u_long)SCARG(uap, data), &ifconf,
737 		    sizeof (ifconf));
738 		if (error)
739 			return error;
740 		error = (*ctl)(fp, OSIOCGIFCONF, &ifconf, p);
741 		if (error)
742 			return error;
743 		return copyout(&ifconf, (caddr_t)(u_long)SCARG(uap, data),
744 		    sizeof (ifconf));
745 	    }
746 
747 /*
748  * Audio ioctl translations.
749  */
750 	case _IOR('A', 1, struct sunos_audio_info):	/* AUDIO_GETINFO */
751 	sunos_au_getinfo:
752 	    {
753 		struct audio_info aui;
754 		struct sunos_audio_info sunos_aui;
755 
756 		error = (*ctl)(fp, AUDIO_GETINFO, &aui, p);
757 		if (error)
758 			return error;
759 
760 		sunos_aui.play = *(struct sunos_audio_prinfo *)&aui.play;
761 		sunos_aui.record = *(struct sunos_audio_prinfo *)&aui.record;
762 
763 		/* `avail_ports' is `seek' in BSD */
764 		sunos_aui.play.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE;
765 		sunos_aui.record.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE;
766 
767 		sunos_aui.play.waiting = 0;
768 		sunos_aui.record.waiting = 0;
769 		sunos_aui.play.eof = 0;
770 		sunos_aui.record.eof = 0;
771 		sunos_aui.monitor_gain = 0; /* aui.__spare; XXX */
772 		/*XXXsunos_aui.output_muted = 0;*/
773 		/*XXX*/sunos_aui.reserved[0] = 0;
774 		/*XXX*/sunos_aui.reserved[1] = 0;
775 		/*XXX*/sunos_aui.reserved[2] = 0;
776 		/*XXX*/sunos_aui.reserved[3] = 0;
777 
778 		return copyout(&sunos_aui, (caddr_t)(u_long)SCARG(uap, data),
779 				sizeof (sunos_aui));
780 	    }
781 
782 	case _IOWR('A', 2, struct sunos_audio_info):	/* AUDIO_SETINFO */
783 	    {
784 		struct audio_info aui;
785 		struct sunos_audio_info sunos_aui;
786 
787 		error = copyin((caddr_t)(u_long)SCARG(uap, data), &sunos_aui,
788 		    sizeof (sunos_aui));
789 		if (error)
790 			return error;
791 
792 		aui.play = *(struct audio_prinfo *)&sunos_aui.play;
793 		aui.record = *(struct audio_prinfo *)&sunos_aui.record;
794 		/* aui.__spare = sunos_aui.monitor_gain; */
795 		aui.blocksize = ~0;
796 		aui.hiwat = ~0;
797 		aui.lowat = ~0;
798 		/* XXX somebody check this please. - is: aui.backlog = ~0; */
799 		aui.mode = ~0;
800 		/*
801 		 * The bsd driver does not distinguish between paused and
802 		 * active. (In the sun driver, not active means samples are
803 		 * not output at all, but paused means the last streams buffer
804 		 * is drained and then output stops.)  If either are 0, then
805 		 * when stop output. Otherwise, if either are non-zero,
806 		 * we resume.
807 		 */
808 		if (sunos_aui.play.pause == 0 || sunos_aui.play.active == 0)
809 			aui.play.pause = 0;
810 		else if (sunos_aui.play.pause != (u_char)~0 ||
811 			 sunos_aui.play.active != (u_char)~0)
812 			aui.play.pause = 1;
813 		if (sunos_aui.record.pause == 0 || sunos_aui.record.active == 0)
814 			aui.record.pause = 0;
815 		else if (sunos_aui.record.pause != (u_char)~0 ||
816 			 sunos_aui.record.active != (u_char)~0)
817 			aui.record.pause = 1;
818 
819 		error = (*ctl)(fp, AUDIO_SETINFO, &aui, p);
820 		if (error)
821 			return error;
822 		/* Return new state */
823 		goto sunos_au_getinfo;
824 	    }
825 	case _IO('A', 3):	/* AUDIO_DRAIN */
826 		return (*ctl)(fp, AUDIO_DRAIN, NULL, p);
827 	case _IOR('A', 4, int):	/* AUDIO_GETDEV */
828 	    {
829 		int devtype = SUNOS_AUDIO_DEV_AMD;
830 		return copyout(&devtype, (caddr_t)(u_long)SCARG(uap, data),
831 				sizeof (devtype));
832 	    }
833 
834 /*
835  * Selected streams ioctls.
836  */
837 #define SUNOS_S_FLUSHR		1
838 #define SUNOS_S_FLUSHW		2
839 #define SUNOS_S_FLUSHRW		3
840 
841 #define SUNOS_S_INPUT		1
842 #define SUNOS_S_HIPRI		2
843 #define SUNOS_S_OUTPUT		4
844 #define SUNOS_S_MSG		8
845 
846 	case _IO('S', 5):	/* I_FLUSH */
847 	    {
848 		int tmp = 0;
849 		switch ((int)(u_long)SCARG(uap, data)) {
850 		case SUNOS_S_FLUSHR:	tmp = FREAD;
851 		case SUNOS_S_FLUSHW:	tmp = FWRITE;
852 		case SUNOS_S_FLUSHRW:	tmp = FREAD|FWRITE;
853 		}
854                 return (*ctl)(fp, TIOCFLUSH, &tmp, p);
855 	    }
856 	case _IO('S', 9):	/* I_SETSIG */
857 	    {
858 		int on = 1;
859 		if (((int)(u_long)SCARG(uap, data) &
860 			(SUNOS_S_HIPRI|SUNOS_S_INPUT)) ==
861 		    SUNOS_S_HIPRI)
862 			return EOPNOTSUPP;
863                 return (*ctl)(fp, FIOASYNC, &on, p);
864 	    }
865 	/*
866 	 * SunOS disk ioctls, taken from arch/sparc/sparc/disksubr.c
867 	 * (which was from the old sparc/scsi/sun_disklabel.c), and
868 	 * modified to suite.
869 	 */
870 	case DKIOCGGEOM:
871             {
872 		struct disklabel dl;
873 
874 		error = (*ctl)(fp, DIOCGDINFO, &dl, p);
875 		if (error)
876 			return (error);
877 
878 #define datageom	((struct sun_dkgeom *)(u_long)SCARG(uap, data))
879 		/* XXX can't do memset() on a user address (dsl) */
880 		memset((caddr_t)(u_long)SCARG(uap, data), 0, sizeof(*datageom));
881 
882 		datageom->sdkc_ncylinders = dl.d_ncylinders;
883 		datageom->sdkc_acylinders = dl.d_acylinders;
884 		datageom->sdkc_ntracks = dl.d_ntracks;
885 		datageom->sdkc_nsectors = dl.d_nsectors;
886 		datageom->sdkc_interleave = dl.d_interleave;
887 		datageom->sdkc_sparespercyl = dl.d_sparespercyl;
888 		datageom->sdkc_rpm = dl.d_rpm;
889 		datageom->sdkc_pcylinders = dl.d_ncylinders + dl.d_acylinders;
890 #undef datageom
891 		break;
892 	    }
893 
894 	case DKIOCINFO:
895 		/* Homey don't do DKIOCINFO */
896 		/* XXX can't do memset() on a user address (dsl) */
897 		memset((caddr_t)(u_long)SCARG(uap, data), 0, sizeof(struct sun_dkctlr));
898 		break;
899 
900 	case DKIOCGPART:
901             {
902 		struct partinfo pi;
903 
904 		error = (*ctl)(fp, DIOCGPART, &pi, p);
905 		if (error)
906 			return (error);
907 
908 		if (pi.disklab->d_secpercyl == 0)
909 			return (ERANGE);	/* XXX */
910 		if (pi.part->p_offset % pi.disklab->d_secpercyl != 0)
911 			return (ERANGE);	/* XXX */
912 #define datapart	((struct sun_dkpart *)(u_long)SCARG(uap, data))
913 		datapart->sdkp_cyloffset = pi.part->p_offset / pi.disklab->d_secpercyl;
914 		datapart->sdkp_nsectors = pi.part->p_size;
915 #undef datapart
916 	    }
917 
918 	}
919 	return (netbsd32_ioctl(l, uap, retval));
920 }
921 
922 /* SunOS fcntl(2) cmds not implemented */
923 #define SUN_F_RGETLK	10
924 #define SUN_F_RSETLK	11
925 #define SUN_F_CNVT	12
926 #define SUN_F_RSETLKW	13
927 
928 /* SunOS flock translation */
929 struct sunos_flock {
930 	short	l_type;
931 	short	l_whence;
932 	netbsd32_long	l_start;
933 	netbsd32_long	l_len;
934 	short	l_pid;
935 	short	l_xxx;
936 };
937 
938 static void bsd_to_sunos_flock __P((struct flock *, struct sunos_flock *));
939 static void sunos_to_bsd_flock __P((struct sunos_flock *, struct flock *));
940 
941 #define SUNOS_F_RDLCK	1
942 #define	SUNOS_F_WRLCK	2
943 #define SUNOS_F_UNLCK	3
944 
945 static void
946 bsd_to_sunos_flock(iflp, oflp)
947 	struct flock		*iflp;
948 	struct sunos_flock	*oflp;
949 {
950 	switch (iflp->l_type) {
951 	case F_RDLCK:
952 		oflp->l_type = SUNOS_F_RDLCK;
953 		break;
954 	case F_WRLCK:
955 		oflp->l_type = SUNOS_F_WRLCK;
956 		break;
957 	case F_UNLCK:
958 		oflp->l_type = SUNOS_F_UNLCK;
959 		break;
960 	default:
961 		oflp->l_type = -1;
962 		break;
963 	}
964 
965 	oflp->l_whence = (short) iflp->l_whence;
966 	oflp->l_start = (netbsd32_long) iflp->l_start;
967 	oflp->l_len = (netbsd32_long) iflp->l_len;
968 	oflp->l_pid = (short) iflp->l_pid;
969 	oflp->l_xxx = 0;
970 }
971 
972 
973 static void
974 sunos_to_bsd_flock(iflp, oflp)
975 	struct sunos_flock	*iflp;
976 	struct flock		*oflp;
977 {
978 	switch (iflp->l_type) {
979 	case SUNOS_F_RDLCK:
980 		oflp->l_type = F_RDLCK;
981 		break;
982 	case SUNOS_F_WRLCK:
983 		oflp->l_type = F_WRLCK;
984 		break;
985 	case SUNOS_F_UNLCK:
986 		oflp->l_type = F_UNLCK;
987 		break;
988 	default:
989 		oflp->l_type = -1;
990 		break;
991 	}
992 
993 	oflp->l_whence = iflp->l_whence;
994 	oflp->l_start = (off_t) iflp->l_start;
995 	oflp->l_len = (off_t) iflp->l_len;
996 	oflp->l_pid = (pid_t) iflp->l_pid;
997 
998 }
999 static struct {
1000 	netbsd32_long	sun_flg;
1001 	netbsd32_long	bsd_flg;
1002 } sunfcntl_flgtab[] = {
1003 	/* F_[GS]ETFLags that differ: */
1004 #define SUN_FSETBLK	0x0010
1005 #define SUN_SHLOCK	0x0080
1006 #define SUN_EXLOCK	0x0100
1007 #define SUN_FNBIO	0x1000
1008 #define SUN_FSYNC	0x2000
1009 #define SUN_NONBLOCK	0x4000
1010 #define SUN_FNOCTTY	0x8000
1011 	{ SUN_NONBLOCK, O_NONBLOCK },
1012 	{ SUN_FNBIO, O_NONBLOCK },
1013 	{ SUN_SHLOCK, O_SHLOCK },
1014 	{ SUN_EXLOCK, O_EXLOCK },
1015 	{ SUN_FSYNC, O_FSYNC },
1016 	{ SUN_FSETBLK, 0 },
1017 	{ SUN_FNOCTTY, 0 }
1018 };
1019 
1020 int
1021 sunos32_sys_fcntl(l, v, retval)
1022 	struct lwp *l;
1023 	void *v;
1024 	register_t *retval;
1025 {
1026 	struct sunos32_sys_fcntl_args /* {
1027 		syscallarg(int) fd;
1028 		syscallarg(int) cmd;
1029 		syscallarg(netbsd32_voidp) arg;
1030 	} */ *uap = v;
1031 	struct proc *p = l->l_proc;
1032 	netbsd32_long flg;
1033 	int n, ret;
1034 
1035 	switch (SCARG(uap, cmd)) {
1036 	case F_SETFL:
1037 		flg = (netbsd32_long)SCARG(uap, arg);
1038 		n = sizeof(sunfcntl_flgtab) / sizeof(sunfcntl_flgtab[0]);
1039 		while (--n >= 0) {
1040 			if (flg & sunfcntl_flgtab[n].sun_flg) {
1041 				flg &= ~sunfcntl_flgtab[n].sun_flg;
1042 				flg |= sunfcntl_flgtab[n].bsd_flg;
1043 			}
1044 		}
1045 		SCARG(uap, arg) = (netbsd32_voidp)flg;
1046 		break;
1047 
1048 	case F_GETLK:
1049 	case F_SETLK:
1050 	case F_SETLKW:
1051 		{
1052 			int error;
1053 			struct sunos_flock	 ifl;
1054 			struct flock		*flp, fl;
1055 			caddr_t sg = stackgap_init(p, 0);
1056 			struct sys_fcntl_args		fa;
1057 
1058 			SCARG(&fa, fd) = SCARG(uap, fd);
1059 			SCARG(&fa, cmd) = SCARG(uap, cmd);
1060 
1061 			flp = stackgap_alloc(p, &sg, sizeof(struct flock));
1062 			SCARG(&fa, arg) = (void *) flp;
1063 
1064 			error = copyin((caddr_t)(u_long)SCARG(uap, arg), &ifl, sizeof ifl);
1065 			if (error)
1066 				return error;
1067 
1068 			sunos_to_bsd_flock(&ifl, &fl);
1069 
1070 			error = copyout(&fl, flp, sizeof fl);
1071 			if (error)
1072 				return error;
1073 
1074 			error = sys_fcntl(l, &fa, retval);
1075 			if (error || SCARG(&fa, cmd) != F_GETLK)
1076 				return error;
1077 
1078 			error = copyin(flp, &fl, sizeof fl);
1079 			if (error)
1080 				return error;
1081 
1082 			bsd_to_sunos_flock(&fl, &ifl);
1083 
1084 			return copyout(&ifl, (caddr_t)(u_long)SCARG(uap, arg), sizeof ifl);
1085 		}
1086 		break;
1087 	case SUN_F_RGETLK:
1088 	case SUN_F_RSETLK:
1089 	case SUN_F_CNVT:
1090 	case SUN_F_RSETLKW:
1091 		return (EOPNOTSUPP);
1092 	}
1093 
1094 	ret = netbsd32_fcntl(l, uap, retval);
1095 
1096 	switch (SCARG(uap, cmd)) {
1097 	case F_GETFL:
1098 		n = sizeof(sunfcntl_flgtab) / sizeof(sunfcntl_flgtab[0]);
1099 		while (--n >= 0) {
1100 			if (ret & sunfcntl_flgtab[n].bsd_flg) {
1101 				ret &= ~sunfcntl_flgtab[n].bsd_flg;
1102 				ret |= sunfcntl_flgtab[n].sun_flg;
1103 			}
1104 		}
1105 		break;
1106 	}
1107 
1108 	return (ret);
1109 }
1110