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