xref: /freebsd-src/sys/compat/linux/linux_ioctl.c (revision daf818451bf2be70f8bdd1a2ee5a265cd6a44ced)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: linux_ioctl.c,v 1.7 1996/03/03 19:07:50 peter Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/proc.h>
35 #include <sys/ioctl.h>
36 #include <sys/ioctl_compat.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/tty.h>
40 #include <sys/termios.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <net/if.h>
44 #include <sys/sockio.h>
45 
46 #include <machine/console.h>
47 #include <machine/soundcard.h>
48 
49 #include <i386/linux/linux.h>
50 #include <i386/linux/linux_proto.h>
51 
52 struct linux_termio {
53     unsigned short c_iflag;
54     unsigned short c_oflag;
55     unsigned short c_cflag;
56     unsigned short c_lflag;
57     unsigned char c_line;
58     unsigned char c_cc[LINUX_NCC];
59 };
60 
61 
62 struct linux_termios {
63     unsigned long   c_iflag;
64     unsigned long   c_oflag;
65     unsigned long   c_cflag;
66     unsigned long   c_lflag;
67     unsigned char   c_line;
68     unsigned char   c_cc[LINUX_NCCS];
69 };
70 
71 struct linux_winsize {
72     unsigned short ws_row, ws_col;
73     unsigned short ws_xpixel, ws_ypixel;
74 };
75 
76 static struct speedtab sptab[] = {
77     { 0, 0 }, { 50, 1 }, { 75, 2 }, { 110, 3 },
78     { 134, 4 }, { 135, 4 }, { 150, 5 }, { 200, 6 },
79     { 300, 7 }, { 600, 8 }, { 1200, 9 }, { 1800, 10 },
80     { 2400, 11 }, { 4800, 12 }, { 9600, 13 },
81     { 19200, 14 }, { 38400, 15 },
82     { 57600, 4097 }, { 115200, 4098 }, {-1, -1 }
83 };
84 
85 static int
86 linux_to_bsd_speed(int code, struct speedtab *table)
87 {
88     for ( ; table->sp_code != -1; table++)
89 	if (table->sp_code == code)
90 	    return (table->sp_speed);
91     return -1;
92 }
93 
94 static int
95 bsd_to_linux_speed(int speed, struct speedtab *table)
96 {
97     for ( ; table->sp_speed != -1; table++)
98 	if (table->sp_speed == speed)
99 	    return (table->sp_code);
100     return -1;
101 }
102 
103 static void
104 bsd_to_linux_termios(struct termios *bsd_termios,
105 		struct linux_termios *linux_termios)
106 {
107     int i, speed;
108 
109 #ifdef DEBUG
110     printf("LINUX: BSD termios structure (input):\n");
111     printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
112 	   bsd_termios->c_iflag, bsd_termios->c_oflag,
113 	   bsd_termios->c_cflag, bsd_termios->c_lflag,
114 	   bsd_termios->c_ispeed, bsd_termios->c_ospeed);
115     printf("c_cc ");
116     for (i=0; i<NCCS; i++)
117 	printf("%02x ", bsd_termios->c_cc[i]);
118     printf("\n");
119 #endif
120     linux_termios->c_iflag = 0;
121     if (bsd_termios->c_iflag & IGNBRK)
122 	linux_termios->c_iflag |= LINUX_IGNBRK;
123     if (bsd_termios->c_iflag & BRKINT)
124 	linux_termios->c_iflag |= LINUX_BRKINT;
125     if (bsd_termios->c_iflag & IGNPAR)
126 	linux_termios->c_iflag |= LINUX_IGNPAR;
127     if (bsd_termios->c_iflag & PARMRK)
128 	linux_termios->c_iflag |= LINUX_PARMRK;
129     if (bsd_termios->c_iflag & INPCK)
130 	linux_termios->c_iflag |= LINUX_INPCK;
131     if (bsd_termios->c_iflag & ISTRIP)
132 	linux_termios->c_iflag |= LINUX_ISTRIP;
133     if (bsd_termios->c_iflag & INLCR)
134 	linux_termios->c_iflag |= LINUX_INLCR;
135     if (bsd_termios->c_iflag & IGNCR)
136 	linux_termios->c_iflag |= LINUX_IGNCR;
137     if (bsd_termios->c_iflag & ICRNL)
138 	linux_termios->c_iflag |= LINUX_ICRNL;
139     if (bsd_termios->c_iflag & IXON)
140 	linux_termios->c_iflag |= LINUX_IXANY;
141     if (bsd_termios->c_iflag & IXON)
142 	linux_termios->c_iflag |= LINUX_IXON;
143     if (bsd_termios->c_iflag & IXOFF)
144 	linux_termios->c_iflag |= LINUX_IXOFF;
145     if (bsd_termios->c_iflag & IMAXBEL)
146 	linux_termios->c_iflag |= LINUX_IMAXBEL;
147 
148     linux_termios->c_oflag = 0;
149     if (bsd_termios->c_oflag & OPOST)
150 	linux_termios->c_oflag |= LINUX_OPOST;
151     if (bsd_termios->c_oflag & ONLCR)
152 	linux_termios->c_oflag |= LINUX_ONLCR;
153     if (bsd_termios->c_oflag & OXTABS)
154 	linux_termios->c_oflag |= LINUX_XTABS;
155 
156     linux_termios->c_cflag =
157 	bsd_to_linux_speed(bsd_termios->c_ispeed, sptab);
158     linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4;
159     if (bsd_termios->c_cflag & CSTOPB)
160 	linux_termios->c_cflag |= LINUX_CSTOPB;
161     if (bsd_termios->c_cflag & CREAD)
162 	linux_termios->c_cflag |= LINUX_CREAD;
163     if (bsd_termios->c_cflag & PARENB)
164 	linux_termios->c_cflag |= LINUX_PARENB;
165     if (bsd_termios->c_cflag & PARODD)
166 	linux_termios->c_cflag |= LINUX_PARODD;
167     if (bsd_termios->c_cflag & HUPCL)
168 	linux_termios->c_cflag |= LINUX_HUPCL;
169     if (bsd_termios->c_cflag & CLOCAL)
170 	linux_termios->c_cflag |= LINUX_CLOCAL;
171     if (bsd_termios->c_cflag & CRTSCTS)
172 	linux_termios->c_cflag |= LINUX_CRTSCTS;
173 
174     linux_termios->c_lflag = 0;
175     if (bsd_termios->c_lflag & ISIG)
176 	linux_termios->c_lflag |= LINUX_ISIG;
177     if (bsd_termios->c_lflag & ICANON)
178 	linux_termios->c_lflag |= LINUX_ICANON;
179     if (bsd_termios->c_lflag & ECHO)
180 	linux_termios->c_lflag |= LINUX_ECHO;
181     if (bsd_termios->c_lflag & ECHOE)
182 	linux_termios->c_lflag |= LINUX_ECHOE;
183     if (bsd_termios->c_lflag & ECHOK)
184 	linux_termios->c_lflag |= LINUX_ECHOK;
185     if (bsd_termios->c_lflag & ECHONL)
186 	linux_termios->c_lflag |= LINUX_ECHONL;
187     if (bsd_termios->c_lflag & NOFLSH)
188 	linux_termios->c_lflag |= LINUX_NOFLSH;
189     if (bsd_termios->c_lflag & TOSTOP)
190 	linux_termios->c_lflag |= LINUX_TOSTOP;
191     if (bsd_termios->c_lflag & ECHOCTL)
192 	linux_termios->c_lflag |= LINUX_ECHOCTL;
193     if (bsd_termios->c_lflag & ECHOPRT)
194 	linux_termios->c_lflag |= LINUX_ECHOPRT;
195     if (bsd_termios->c_lflag & ECHOKE)
196 	linux_termios->c_lflag |= LINUX_ECHOKE;
197     if (bsd_termios->c_lflag & FLUSHO)
198 	linux_termios->c_lflag |= LINUX_FLUSHO;
199     if (bsd_termios->c_lflag & PENDIN)
200 	linux_termios->c_lflag |= LINUX_PENDIN;
201     if (bsd_termios->c_lflag & IEXTEN)
202 	linux_termios->c_lflag |= LINUX_IEXTEN;
203 
204     for (i=0; i<LINUX_NCCS; i++)
205 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
206     linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR];
207     linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT];
208     linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE];
209     linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL];
210     linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF];
211     linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL];
212     linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN];
213     linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME];
214     linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2];
215     linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE;
216     linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP];
217     linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART];
218     linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP];
219     linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT];
220     linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD];
221     linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE];
222     linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT];
223 
224     for (i=0; i<LINUX_NCCS; i++) {
225       if (linux_termios->c_cc[i] == _POSIX_VDISABLE)
226 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
227     }
228 
229     linux_termios->c_line = 0;
230 #ifdef DEBUG
231     printf("LINUX: LINUX termios structure (output):\n");
232     printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
233 	   linux_termios->c_iflag, linux_termios->c_oflag,
234 	   linux_termios->c_cflag, linux_termios->c_lflag,
235 	   linux_termios->c_line);
236     printf("c_cc ");
237     for (i=0; i<LINUX_NCCS; i++)
238 	printf("%02x ", linux_termios->c_cc[i]);
239     printf("\n");
240 #endif
241 }
242 
243 
244 static void
245 linux_to_bsd_termios(struct linux_termios *linux_termios,
246 		struct termios *bsd_termios)
247 {
248     int i, speed;
249 #ifdef DEBUG
250     printf("LINUX: LINUX termios structure (input):\n");
251     printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
252 	   linux_termios->c_iflag, linux_termios->c_oflag,
253 	   linux_termios->c_cflag, linux_termios->c_lflag,
254 	   linux_termios->c_line);
255     printf("c_cc ");
256     for (i=0; i<LINUX_NCCS; i++)
257 	printf("%02x ", linux_termios->c_cc[i]);
258     printf("\n");
259 #endif
260     bsd_termios->c_iflag = 0;
261     if (linux_termios->c_iflag & LINUX_IGNBRK)
262 	bsd_termios->c_iflag |= IGNBRK;
263     if (linux_termios->c_iflag & LINUX_BRKINT)
264 	bsd_termios->c_iflag |= BRKINT;
265     if (linux_termios->c_iflag & LINUX_IGNPAR)
266 	bsd_termios->c_iflag |= IGNPAR;
267     if (linux_termios->c_iflag & LINUX_PARMRK)
268 	bsd_termios->c_iflag |= PARMRK;
269     if (linux_termios->c_iflag & LINUX_INPCK)
270 	bsd_termios->c_iflag |= INPCK;
271     if (linux_termios->c_iflag & LINUX_ISTRIP)
272 	bsd_termios->c_iflag |= ISTRIP;
273     if (linux_termios->c_iflag & LINUX_INLCR)
274 	bsd_termios->c_iflag |= INLCR;
275     if (linux_termios->c_iflag & LINUX_IGNCR)
276 	bsd_termios->c_iflag |= IGNCR;
277     if (linux_termios->c_iflag & LINUX_ICRNL)
278 	bsd_termios->c_iflag |= ICRNL;
279     if (linux_termios->c_iflag & LINUX_IXON)
280 	bsd_termios->c_iflag |= IXANY;
281     if (linux_termios->c_iflag & LINUX_IXON)
282 	bsd_termios->c_iflag |= IXON;
283     if (linux_termios->c_iflag & LINUX_IXOFF)
284 	bsd_termios->c_iflag |= IXOFF;
285     if (linux_termios->c_iflag & LINUX_IMAXBEL)
286 	bsd_termios->c_iflag |= IMAXBEL;
287 
288     bsd_termios->c_oflag = 0;
289     if (linux_termios->c_oflag & LINUX_OPOST)
290 	bsd_termios->c_oflag |= OPOST;
291     if (linux_termios->c_oflag & LINUX_ONLCR)
292 	bsd_termios->c_oflag |= ONLCR;
293     if (linux_termios->c_oflag & LINUX_XTABS)
294 	bsd_termios->c_oflag |= OXTABS;
295 
296     bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4;
297     if (linux_termios->c_cflag & LINUX_CSTOPB)
298 	bsd_termios->c_cflag |= CSTOPB;
299     if (linux_termios->c_cflag & LINUX_PARENB)
300 	bsd_termios->c_cflag |= PARENB;
301     if (linux_termios->c_cflag & LINUX_PARODD)
302 	bsd_termios->c_cflag |= PARODD;
303     if (linux_termios->c_cflag & LINUX_HUPCL)
304 	bsd_termios->c_cflag |= HUPCL;
305     if (linux_termios->c_cflag & LINUX_CLOCAL)
306 	bsd_termios->c_cflag |= CLOCAL;
307     if (linux_termios->c_cflag & LINUX_CRTSCTS)
308 	bsd_termios->c_cflag |= CRTSCTS;
309 
310     bsd_termios->c_lflag = 0;
311     if (linux_termios->c_lflag & LINUX_ISIG)
312 	bsd_termios->c_lflag |= ISIG;
313     if (linux_termios->c_lflag & LINUX_ICANON)
314 	bsd_termios->c_lflag |= ICANON;
315     if (linux_termios->c_lflag & LINUX_ECHO)
316 	bsd_termios->c_lflag |= ECHO;
317     if (linux_termios->c_lflag & LINUX_ECHOE)
318 	bsd_termios->c_lflag |= ECHOE;
319     if (linux_termios->c_lflag & LINUX_ECHOK)
320 	bsd_termios->c_lflag |= ECHOK;
321     if (linux_termios->c_lflag & LINUX_ECHONL)
322 	bsd_termios->c_lflag |= ECHONL;
323     if (linux_termios->c_lflag & LINUX_NOFLSH)
324 	bsd_termios->c_lflag |= NOFLSH;
325     if (linux_termios->c_lflag & LINUX_TOSTOP)
326 	bsd_termios->c_lflag |= TOSTOP;
327     if (linux_termios->c_lflag & LINUX_ECHOCTL)
328 	bsd_termios->c_lflag |= ECHOCTL;
329     if (linux_termios->c_lflag & LINUX_ECHOPRT)
330 	bsd_termios->c_lflag |= ECHOPRT;
331     if (linux_termios->c_lflag & LINUX_ECHOKE)
332 	bsd_termios->c_lflag |= ECHOKE;
333     if (linux_termios->c_lflag & LINUX_FLUSHO)
334 	bsd_termios->c_lflag |= FLUSHO;
335     if (linux_termios->c_lflag & LINUX_PENDIN)
336 	bsd_termios->c_lflag |= PENDIN;
337     if (linux_termios->c_lflag & IEXTEN)
338 	bsd_termios->c_lflag |= IEXTEN;
339 
340     for (i=0; i<NCCS; i++)
341 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
342     bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR];
343     bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT];
344     bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE];
345     bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL];
346     bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF];
347     bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL];
348     bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN];
349     bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME];
350     bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2];
351     bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP];
352     bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART];
353     bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP];
354     bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT];
355     bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD];
356     bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE];
357     bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT];
358 
359     for (i=0; i<NCCS; i++) {
360       if (bsd_termios->c_cc[i] == LINUX_POSIX_VDISABLE)
361 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
362     }
363 
364     bsd_termios->c_ispeed = bsd_termios->c_ospeed =
365 	linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab);
366 #ifdef DEBUG
367 	printf("LINUX: BSD termios structure (output):\n");
368 	printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
369 	       bsd_termios->c_iflag, bsd_termios->c_oflag,
370 	       bsd_termios->c_cflag, bsd_termios->c_lflag,
371 	       bsd_termios->c_ispeed, bsd_termios->c_ospeed);
372 	printf("c_cc ");
373 	for (i=0; i<NCCS; i++)
374 	    printf("%02x ", bsd_termios->c_cc[i]);
375 	printf("\n");
376 #endif
377 }
378 
379 
380 static void
381 bsd_to_linux_termio(struct termios *bsd_termios,
382 		struct linux_termio *linux_termio)
383 {
384   struct linux_termios tmios;
385 
386   bsd_to_linux_termios(bsd_termios, &tmios);
387   linux_termio->c_iflag = tmios.c_iflag;
388   linux_termio->c_oflag = tmios.c_oflag;
389   linux_termio->c_cflag = tmios.c_cflag;
390   linux_termio->c_lflag = tmios.c_lflag;
391   linux_termio->c_line  = tmios.c_line;
392   memcpy(linux_termio->c_cc, tmios.c_cc, LINUX_NCC);
393 }
394 
395 static void
396 linux_to_bsd_termio(struct linux_termio *linux_termio,
397 		struct termios *bsd_termios)
398 {
399   struct linux_termios tmios;
400   int i;
401 
402   tmios.c_iflag = linux_termio->c_iflag;
403   tmios.c_oflag = linux_termio->c_oflag;
404   tmios.c_cflag = linux_termio->c_cflag;
405   tmios.c_lflag = linux_termio->c_lflag;
406 
407   for (i=0; i<LINUX_NCCS; i++)
408     tmios.c_cc[i] = LINUX_POSIX_VDISABLE;
409   memcpy(tmios.c_cc, linux_termio->c_cc, LINUX_NCC);
410 
411   linux_to_bsd_termios(&tmios, bsd_termios);
412 }
413 
414 
415 int
416 linux_ioctl(struct proc *p, struct linux_ioctl_args *args, int *retval)
417 {
418     struct termios bsd_termios;
419     struct winsize bsd_winsize;
420     struct linux_termios linux_termios;
421     struct linux_termio linux_termio;
422     struct linux_winsize linux_winsize;
423     struct filedesc *fdp = p->p_fd;
424     struct file *fp;
425     int (*func)(struct file *fp, int com, caddr_t data, struct proc *p);
426     int bsd_line, linux_line;
427     int error;
428 
429 #ifdef DEBUG
430     printf("Linux-emul(%d): ioctl(%d, %04x, *)\n",
431 	   p->p_pid, args->fd, args->cmd);
432 #endif
433     if ((unsigned)args->fd >= fdp->fd_nfiles
434 	|| (fp = fdp->fd_ofiles[args->fd]) == 0)
435 	return EBADF;
436 
437     if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) {
438 	return EBADF;
439     }
440 
441     func = fp->f_ops->fo_ioctl;
442     switch (args->cmd & 0xffff) {
443 
444     case LINUX_TCGETA:
445 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
446 	    return error;
447 	bsd_to_linux_termio(&bsd_termios, &linux_termio);
448 	return copyout((caddr_t)&linux_termio, (caddr_t)args->arg,
449 		       sizeof(linux_termio));
450 
451     case LINUX_TCSETA:
452 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
453 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
454 
455     case LINUX_TCSETAW:
456 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
457 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
458 
459     case LINUX_TCSETAF:
460 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
461 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
462 
463     case LINUX_TCGETS:
464 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
465 	    return error;
466 	bsd_to_linux_termios(&bsd_termios, &linux_termios);
467 	return copyout((caddr_t)&linux_termios, (caddr_t)args->arg,
468 		       sizeof(linux_termios));
469 
470     case LINUX_TCSETS:
471 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
472 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
473 
474     case LINUX_TCSETSW:
475 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
476 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
477 
478     case LINUX_TCSETSF:
479 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
480 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
481 
482     case LINUX_TIOCGPGRP:
483 	args->cmd = TIOCGPGRP;
484 	return ioctl(p, (struct ioctl_args *)args, retval);
485 
486     case LINUX_TIOCSPGRP:
487 	args->cmd = TIOCSPGRP;
488 	return ioctl(p, (struct ioctl_args *)args, retval);
489 
490     case LINUX_TIOCGWINSZ:
491 	args->cmd = TIOCGWINSZ;
492 	return ioctl(p, (struct ioctl_args *)args, retval);
493 
494     case LINUX_TIOCSWINSZ:
495 	args->cmd = TIOCSWINSZ;
496 	return ioctl(p, (struct ioctl_args *)args, retval);
497 
498     case LINUX_FIONREAD:
499 	args->cmd = FIONREAD;
500 	return ioctl(p, (struct ioctl_args *)args, retval);
501 
502     case LINUX_FIONBIO:
503 	args->cmd = FIONBIO;
504 	return ioctl(p, (struct ioctl_args *)args, retval);
505 
506     case LINUX_FIOASYNC:
507 	args->cmd = FIOASYNC;
508 	return ioctl(p, (struct ioctl_args *)args, retval);
509 
510     case LINUX_FIONCLEX:
511 	args->cmd = FIONCLEX;
512 	return ioctl(p, (struct ioctl_args *)args, retval);
513 
514     case LINUX_FIOCLEX:
515 	args->cmd = FIOCLEX;
516 	return ioctl(p, (struct ioctl_args *)args, retval);
517 
518     case LINUX_TIOCEXCL:
519 	args->cmd = TIOCEXCL;
520 	return ioctl(p, (struct ioctl_args *)args, retval);
521 
522     case LINUX_TIOCNXCL:
523 	args->cmd = TIOCNXCL;
524 	return ioctl(p, (struct ioctl_args *)args, retval);
525 
526     case LINUX_TIOCCONS:
527 	args->cmd = TIOCCONS;
528 	return ioctl(p, (struct ioctl_args *)args, retval);
529 
530     case LINUX_TIOCNOTTY:
531 	args->cmd = TIOCNOTTY;
532 	return ioctl(p, (struct ioctl_args *)args, retval);
533 
534     case LINUX_SIOCGIFCONF:
535 	args->cmd = OSIOCGIFCONF;
536 	return ioctl(p, (struct ioctl_args *)args, retval);
537 
538     case LINUX_SIOCGIFFLAGS:
539 	args->cmd = SIOCGIFFLAGS;
540 	return ioctl(p, (struct ioctl_args *)args, retval);
541 
542     case LINUX_SIOCGIFADDR:
543 	args->cmd = OSIOCGIFADDR;
544 	return ioctl(p, (struct ioctl_args *)args, retval);
545 
546     case LINUX_SIOCGIFDSTADDR:
547 	args->cmd = OSIOCGIFDSTADDR;
548 	return ioctl(p, (struct ioctl_args *)args, retval);
549 
550     case LINUX_SIOCGIFBRDADDR:
551 	args->cmd = OSIOCGIFBRDADDR;
552 	return ioctl(p, (struct ioctl_args *)args, retval);
553 
554     case LINUX_SIOCGIFNETMASK:
555 	args->cmd = OSIOCGIFNETMASK;
556 	return ioctl(p, (struct ioctl_args *)args, retval);
557 
558     case LINUX_SIOCADDMULTI:
559 	args->cmd = SIOCADDMULTI;
560 	return ioctl(p, (struct ioctl_args *)args, retval);
561 
562     case LINUX_SIOCDELMULTI:
563 	args->cmd = SIOCDELMULTI;
564 	return ioctl(p, (struct ioctl_args *)args, retval);
565 
566     case LINUX_TIOCSETD:
567 	switch (args->arg) {
568 	case LINUX_N_TTY:
569 	    bsd_line = TTYDISC;
570 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
571 	case LINUX_N_SLIP:
572 	    bsd_line = SLIPDISC;
573 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
574 	case LINUX_N_PPP:
575 	    bsd_line = PPPDISC;
576 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
577 	default:
578 	    return EINVAL;
579 	}
580 
581     case LINUX_TIOCGETD:
582 	bsd_line = TTYDISC;
583 	if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p))
584 	    return error;
585 	switch (bsd_line) {
586 	case TTYDISC:
587 	    linux_line = LINUX_N_TTY;
588 	    break;
589 	case SLIPDISC:
590 	    linux_line = LINUX_N_SLIP;
591 	    break;
592 	case PPPDISC:
593 	    linux_line = LINUX_N_PPP;
594 	    break;
595 	default:
596 	    return EINVAL;
597 	}
598 	return copyout(&linux_line, (caddr_t)args->arg,
599 		       sizeof(int));
600 
601     case LINUX_SNDCTL_DSP_RESET:
602 	args->cmd = SNDCTL_DSP_RESET;
603 	return ioctl(p, (struct ioctl_args *)args, retval);
604 
605     case LINUX_SNDCTL_DSP_SYNC:
606 	args->cmd = SNDCTL_DSP_SYNC;
607 	return ioctl(p, (struct ioctl_args *)args, retval);
608 
609     case LINUX_SNDCTL_DSP_SPEED:
610 	args->cmd = SNDCTL_DSP_SPEED;
611 	return ioctl(p, (struct ioctl_args *)args, retval);
612 
613     case LINUX_SNDCTL_DSP_STEREO:
614 	args->cmd = SNDCTL_DSP_STEREO;
615 	return ioctl(p, (struct ioctl_args *)args, retval);
616 
617     case LINUX_SNDCTL_DSP_GETBLKSIZE:
618       /* LINUX_SNDCTL_DSP_SETBLKSIZE */
619 	args->cmd = SNDCTL_DSP_GETBLKSIZE;
620 	return ioctl(p, (struct ioctl_args *)args, retval);
621 
622     case LINUX_SNDCTL_DSP_SETFMT:
623 	args->cmd = SNDCTL_DSP_SETFMT;
624 	return ioctl(p, (struct ioctl_args *)args, retval);
625 
626     case LINUX_SOUND_PCM_WRITE_CHANNELS:
627 	args->cmd = SOUND_PCM_WRITE_CHANNELS;
628 	return ioctl(p, (struct ioctl_args *)args, retval);
629 
630     case LINUX_SOUND_PCM_WRITE_FILTER:
631 	args->cmd = SOUND_PCM_WRITE_FILTER;
632 	return ioctl(p, (struct ioctl_args *)args, retval);
633 
634     case LINUX_SNDCTL_DSP_POST:
635 	args->cmd = SNDCTL_DSP_POST;
636 	return ioctl(p, (struct ioctl_args *)args, retval);
637 
638     case LINUX_SNDCTL_DSP_SUBDIVIDE:
639 	args->cmd = SNDCTL_DSP_SUBDIVIDE;
640 	return ioctl(p, (struct ioctl_args *)args, retval);
641 
642     case LINUX_SNDCTL_DSP_SETFRAGMENT:
643 	args->cmd = SNDCTL_DSP_SETFRAGMENT;
644 	return ioctl(p, (struct ioctl_args *)args, retval);
645 
646     case LINUX_SNDCTL_DSP_GETFMTS:
647 	args->cmd = SNDCTL_DSP_GETFMTS;
648 	return ioctl(p, (struct ioctl_args *)args, retval);
649 
650     case LINUX_SNDCTL_DSP_GETOSPACE:
651 	args->cmd = SNDCTL_DSP_GETOSPACE;
652 	return ioctl(p, (struct ioctl_args *)args, retval);
653 
654     case LINUX_SNDCTL_DSP_GETISPACE:
655 	args->cmd = SNDCTL_DSP_GETISPACE;
656 	return ioctl(p, (struct ioctl_args *)args, retval);
657 
658     case LINUX_SNDCTL_DSP_NONBLOCK:
659 	args->cmd = SNDCTL_DSP_NONBLOCK;
660 	return ioctl(p, (struct ioctl_args *)args, retval);
661     }
662     uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n",
663 	    args->fd, (args->cmd&0xffff00)>>8,
664 	    (args->cmd&0xffff00)>>8, args->cmd&0xff);
665     return EINVAL;
666 }
667