xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision 7573cb47cf4b1f33b6794f82a8a5e0bcbdcc1ada)
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.8 1996/03/04 11:15:19 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 struct linux_serial_struct {
86         int     type;
87         int     line;
88         int     port;
89         int     irq;
90         int     flags;
91         int     xmit_fifo_size;
92         int     custom_divisor;
93         int     baud_base;
94         unsigned short  close_delay;
95         char    reserved_char[2];
96         int     hub6;
97         unsigned short  closing_wait;
98         unsigned short  closing_wait2;
99         int     reserved[4];
100 };
101 
102 
103 static int
104 linux_to_bsd_speed(int code, struct speedtab *table)
105 {
106     for ( ; table->sp_code != -1; table++)
107 	if (table->sp_code == code)
108 	    return (table->sp_speed);
109     return -1;
110 }
111 
112 static int
113 bsd_to_linux_speed(int speed, struct speedtab *table)
114 {
115     for ( ; table->sp_speed != -1; table++)
116 	if (table->sp_speed == speed)
117 	    return (table->sp_code);
118     return -1;
119 }
120 
121 static void
122 bsd_to_linux_termios(struct termios *bsd_termios,
123 		struct linux_termios *linux_termios)
124 {
125     int i, speed;
126 
127 #ifdef DEBUG
128     printf("LINUX: BSD termios structure (input):\n");
129     printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
130 	   bsd_termios->c_iflag, bsd_termios->c_oflag,
131 	   bsd_termios->c_cflag, bsd_termios->c_lflag,
132 	   bsd_termios->c_ispeed, bsd_termios->c_ospeed);
133     printf("c_cc ");
134     for (i=0; i<NCCS; i++)
135 	printf("%02x ", bsd_termios->c_cc[i]);
136     printf("\n");
137 #endif
138     linux_termios->c_iflag = 0;
139     if (bsd_termios->c_iflag & IGNBRK)
140 	linux_termios->c_iflag |= LINUX_IGNBRK;
141     if (bsd_termios->c_iflag & BRKINT)
142 	linux_termios->c_iflag |= LINUX_BRKINT;
143     if (bsd_termios->c_iflag & IGNPAR)
144 	linux_termios->c_iflag |= LINUX_IGNPAR;
145     if (bsd_termios->c_iflag & PARMRK)
146 	linux_termios->c_iflag |= LINUX_PARMRK;
147     if (bsd_termios->c_iflag & INPCK)
148 	linux_termios->c_iflag |= LINUX_INPCK;
149     if (bsd_termios->c_iflag & ISTRIP)
150 	linux_termios->c_iflag |= LINUX_ISTRIP;
151     if (bsd_termios->c_iflag & INLCR)
152 	linux_termios->c_iflag |= LINUX_INLCR;
153     if (bsd_termios->c_iflag & IGNCR)
154 	linux_termios->c_iflag |= LINUX_IGNCR;
155     if (bsd_termios->c_iflag & ICRNL)
156 	linux_termios->c_iflag |= LINUX_ICRNL;
157     if (bsd_termios->c_iflag & IXON)
158 	linux_termios->c_iflag |= LINUX_IXANY;
159     if (bsd_termios->c_iflag & IXON)
160 	linux_termios->c_iflag |= LINUX_IXON;
161     if (bsd_termios->c_iflag & IXOFF)
162 	linux_termios->c_iflag |= LINUX_IXOFF;
163     if (bsd_termios->c_iflag & IMAXBEL)
164 	linux_termios->c_iflag |= LINUX_IMAXBEL;
165 
166     linux_termios->c_oflag = 0;
167     if (bsd_termios->c_oflag & OPOST)
168 	linux_termios->c_oflag |= LINUX_OPOST;
169     if (bsd_termios->c_oflag & ONLCR)
170 	linux_termios->c_oflag |= LINUX_ONLCR;
171     if (bsd_termios->c_oflag & OXTABS)
172 	linux_termios->c_oflag |= LINUX_XTABS;
173 
174     linux_termios->c_cflag =
175 	bsd_to_linux_speed(bsd_termios->c_ispeed, sptab);
176     linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4;
177     if (bsd_termios->c_cflag & CSTOPB)
178 	linux_termios->c_cflag |= LINUX_CSTOPB;
179     if (bsd_termios->c_cflag & CREAD)
180 	linux_termios->c_cflag |= LINUX_CREAD;
181     if (bsd_termios->c_cflag & PARENB)
182 	linux_termios->c_cflag |= LINUX_PARENB;
183     if (bsd_termios->c_cflag & PARODD)
184 	linux_termios->c_cflag |= LINUX_PARODD;
185     if (bsd_termios->c_cflag & HUPCL)
186 	linux_termios->c_cflag |= LINUX_HUPCL;
187     if (bsd_termios->c_cflag & CLOCAL)
188 	linux_termios->c_cflag |= LINUX_CLOCAL;
189     if (bsd_termios->c_cflag & CRTSCTS)
190 	linux_termios->c_cflag |= LINUX_CRTSCTS;
191 
192     linux_termios->c_lflag = 0;
193     if (bsd_termios->c_lflag & ISIG)
194 	linux_termios->c_lflag |= LINUX_ISIG;
195     if (bsd_termios->c_lflag & ICANON)
196 	linux_termios->c_lflag |= LINUX_ICANON;
197     if (bsd_termios->c_lflag & ECHO)
198 	linux_termios->c_lflag |= LINUX_ECHO;
199     if (bsd_termios->c_lflag & ECHOE)
200 	linux_termios->c_lflag |= LINUX_ECHOE;
201     if (bsd_termios->c_lflag & ECHOK)
202 	linux_termios->c_lflag |= LINUX_ECHOK;
203     if (bsd_termios->c_lflag & ECHONL)
204 	linux_termios->c_lflag |= LINUX_ECHONL;
205     if (bsd_termios->c_lflag & NOFLSH)
206 	linux_termios->c_lflag |= LINUX_NOFLSH;
207     if (bsd_termios->c_lflag & TOSTOP)
208 	linux_termios->c_lflag |= LINUX_TOSTOP;
209     if (bsd_termios->c_lflag & ECHOCTL)
210 	linux_termios->c_lflag |= LINUX_ECHOCTL;
211     if (bsd_termios->c_lflag & ECHOPRT)
212 	linux_termios->c_lflag |= LINUX_ECHOPRT;
213     if (bsd_termios->c_lflag & ECHOKE)
214 	linux_termios->c_lflag |= LINUX_ECHOKE;
215     if (bsd_termios->c_lflag & FLUSHO)
216 	linux_termios->c_lflag |= LINUX_FLUSHO;
217     if (bsd_termios->c_lflag & PENDIN)
218 	linux_termios->c_lflag |= LINUX_PENDIN;
219     if (bsd_termios->c_lflag & IEXTEN)
220 	linux_termios->c_lflag |= LINUX_IEXTEN;
221 
222     for (i=0; i<LINUX_NCCS; i++)
223 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
224     linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR];
225     linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT];
226     linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE];
227     linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL];
228     linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF];
229     linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL];
230     linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN];
231     linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME];
232     linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2];
233     linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE;
234     linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP];
235     linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART];
236     linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP];
237     linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT];
238     linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD];
239     linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE];
240     linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT];
241 
242     for (i=0; i<LINUX_NCCS; i++) {
243       if (linux_termios->c_cc[i] == _POSIX_VDISABLE)
244 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
245     }
246 
247     linux_termios->c_line = 0;
248 #ifdef DEBUG
249     printf("LINUX: LINUX termios structure (output):\n");
250     printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
251 	   linux_termios->c_iflag, linux_termios->c_oflag,
252 	   linux_termios->c_cflag, linux_termios->c_lflag,
253 	   linux_termios->c_line);
254     printf("c_cc ");
255     for (i=0; i<LINUX_NCCS; i++)
256 	printf("%02x ", linux_termios->c_cc[i]);
257     printf("\n");
258 #endif
259 }
260 
261 
262 static void
263 linux_to_bsd_termios(struct linux_termios *linux_termios,
264 		struct termios *bsd_termios)
265 {
266     int i, speed;
267 #ifdef DEBUG
268     printf("LINUX: LINUX termios structure (input):\n");
269     printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
270 	   linux_termios->c_iflag, linux_termios->c_oflag,
271 	   linux_termios->c_cflag, linux_termios->c_lflag,
272 	   linux_termios->c_line);
273     printf("c_cc ");
274     for (i=0; i<LINUX_NCCS; i++)
275 	printf("%02x ", linux_termios->c_cc[i]);
276     printf("\n");
277 #endif
278     bsd_termios->c_iflag = 0;
279     if (linux_termios->c_iflag & LINUX_IGNBRK)
280 	bsd_termios->c_iflag |= IGNBRK;
281     if (linux_termios->c_iflag & LINUX_BRKINT)
282 	bsd_termios->c_iflag |= BRKINT;
283     if (linux_termios->c_iflag & LINUX_IGNPAR)
284 	bsd_termios->c_iflag |= IGNPAR;
285     if (linux_termios->c_iflag & LINUX_PARMRK)
286 	bsd_termios->c_iflag |= PARMRK;
287     if (linux_termios->c_iflag & LINUX_INPCK)
288 	bsd_termios->c_iflag |= INPCK;
289     if (linux_termios->c_iflag & LINUX_ISTRIP)
290 	bsd_termios->c_iflag |= ISTRIP;
291     if (linux_termios->c_iflag & LINUX_INLCR)
292 	bsd_termios->c_iflag |= INLCR;
293     if (linux_termios->c_iflag & LINUX_IGNCR)
294 	bsd_termios->c_iflag |= IGNCR;
295     if (linux_termios->c_iflag & LINUX_ICRNL)
296 	bsd_termios->c_iflag |= ICRNL;
297     if (linux_termios->c_iflag & LINUX_IXON)
298 	bsd_termios->c_iflag |= IXANY;
299     if (linux_termios->c_iflag & LINUX_IXON)
300 	bsd_termios->c_iflag |= IXON;
301     if (linux_termios->c_iflag & LINUX_IXOFF)
302 	bsd_termios->c_iflag |= IXOFF;
303     if (linux_termios->c_iflag & LINUX_IMAXBEL)
304 	bsd_termios->c_iflag |= IMAXBEL;
305 
306     bsd_termios->c_oflag = 0;
307     if (linux_termios->c_oflag & LINUX_OPOST)
308 	bsd_termios->c_oflag |= OPOST;
309     if (linux_termios->c_oflag & LINUX_ONLCR)
310 	bsd_termios->c_oflag |= ONLCR;
311     if (linux_termios->c_oflag & LINUX_XTABS)
312 	bsd_termios->c_oflag |= OXTABS;
313 
314     bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4;
315     if (linux_termios->c_cflag & LINUX_CSTOPB)
316 	bsd_termios->c_cflag |= CSTOPB;
317     if (linux_termios->c_cflag & LINUX_PARENB)
318 	bsd_termios->c_cflag |= PARENB;
319     if (linux_termios->c_cflag & LINUX_PARODD)
320 	bsd_termios->c_cflag |= PARODD;
321     if (linux_termios->c_cflag & LINUX_HUPCL)
322 	bsd_termios->c_cflag |= HUPCL;
323     if (linux_termios->c_cflag & LINUX_CLOCAL)
324 	bsd_termios->c_cflag |= CLOCAL;
325     if (linux_termios->c_cflag & LINUX_CRTSCTS)
326 	bsd_termios->c_cflag |= CRTSCTS;
327 
328     bsd_termios->c_lflag = 0;
329     if (linux_termios->c_lflag & LINUX_ISIG)
330 	bsd_termios->c_lflag |= ISIG;
331     if (linux_termios->c_lflag & LINUX_ICANON)
332 	bsd_termios->c_lflag |= ICANON;
333     if (linux_termios->c_lflag & LINUX_ECHO)
334 	bsd_termios->c_lflag |= ECHO;
335     if (linux_termios->c_lflag & LINUX_ECHOE)
336 	bsd_termios->c_lflag |= ECHOE;
337     if (linux_termios->c_lflag & LINUX_ECHOK)
338 	bsd_termios->c_lflag |= ECHOK;
339     if (linux_termios->c_lflag & LINUX_ECHONL)
340 	bsd_termios->c_lflag |= ECHONL;
341     if (linux_termios->c_lflag & LINUX_NOFLSH)
342 	bsd_termios->c_lflag |= NOFLSH;
343     if (linux_termios->c_lflag & LINUX_TOSTOP)
344 	bsd_termios->c_lflag |= TOSTOP;
345     if (linux_termios->c_lflag & LINUX_ECHOCTL)
346 	bsd_termios->c_lflag |= ECHOCTL;
347     if (linux_termios->c_lflag & LINUX_ECHOPRT)
348 	bsd_termios->c_lflag |= ECHOPRT;
349     if (linux_termios->c_lflag & LINUX_ECHOKE)
350 	bsd_termios->c_lflag |= ECHOKE;
351     if (linux_termios->c_lflag & LINUX_FLUSHO)
352 	bsd_termios->c_lflag |= FLUSHO;
353     if (linux_termios->c_lflag & LINUX_PENDIN)
354 	bsd_termios->c_lflag |= PENDIN;
355     if (linux_termios->c_lflag & IEXTEN)
356 	bsd_termios->c_lflag |= IEXTEN;
357 
358     for (i=0; i<NCCS; i++)
359 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
360     bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR];
361     bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT];
362     bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE];
363     bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL];
364     bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF];
365     bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL];
366     bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN];
367     bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME];
368     bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2];
369     bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP];
370     bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART];
371     bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP];
372     bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT];
373     bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD];
374     bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE];
375     bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT];
376 
377     for (i=0; i<NCCS; i++) {
378       if (bsd_termios->c_cc[i] == LINUX_POSIX_VDISABLE)
379 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
380     }
381 
382     bsd_termios->c_ispeed = bsd_termios->c_ospeed =
383 	linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab);
384 #ifdef DEBUG
385 	printf("LINUX: BSD termios structure (output):\n");
386 	printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
387 	       bsd_termios->c_iflag, bsd_termios->c_oflag,
388 	       bsd_termios->c_cflag, bsd_termios->c_lflag,
389 	       bsd_termios->c_ispeed, bsd_termios->c_ospeed);
390 	printf("c_cc ");
391 	for (i=0; i<NCCS; i++)
392 	    printf("%02x ", bsd_termios->c_cc[i]);
393 	printf("\n");
394 #endif
395 }
396 
397 
398 static void
399 bsd_to_linux_termio(struct termios *bsd_termios,
400 		struct linux_termio *linux_termio)
401 {
402   struct linux_termios tmios;
403 
404   bsd_to_linux_termios(bsd_termios, &tmios);
405   linux_termio->c_iflag = tmios.c_iflag;
406   linux_termio->c_oflag = tmios.c_oflag;
407   linux_termio->c_cflag = tmios.c_cflag;
408   linux_termio->c_lflag = tmios.c_lflag;
409   linux_termio->c_line  = tmios.c_line;
410   memcpy(linux_termio->c_cc, tmios.c_cc, LINUX_NCC);
411 }
412 
413 static void
414 linux_to_bsd_termio(struct linux_termio *linux_termio,
415 		struct termios *bsd_termios)
416 {
417   struct linux_termios tmios;
418   int i;
419 
420   tmios.c_iflag = linux_termio->c_iflag;
421   tmios.c_oflag = linux_termio->c_oflag;
422   tmios.c_cflag = linux_termio->c_cflag;
423   tmios.c_lflag = linux_termio->c_lflag;
424 
425   for (i=0; i<LINUX_NCCS; i++)
426     tmios.c_cc[i] = LINUX_POSIX_VDISABLE;
427   memcpy(tmios.c_cc, linux_termio->c_cc, LINUX_NCC);
428 
429   linux_to_bsd_termios(&tmios, bsd_termios);
430 }
431 
432 static void
433 linux_tiocgserial(struct file *fp, struct linux_serial_struct *lss)
434 {
435   if (!fp || !lss)
436     return;
437 
438   lss->type = LINUX_PORT_16550A;
439   lss->flags = 0;
440   lss->close_delay = 0;
441 }
442 
443 static void
444 linux_tiocsserial(struct file *fp, struct linux_serial_struct *lss)
445 {
446   if (!fp || !lss)
447     return;
448 }
449 
450 int
451 linux_ioctl(struct proc *p, struct linux_ioctl_args *args, int *retval)
452 {
453     struct termios bsd_termios;
454     struct winsize bsd_winsize;
455     struct linux_termios linux_termios;
456     struct linux_termio linux_termio;
457     struct linux_winsize linux_winsize;
458     struct filedesc *fdp = p->p_fd;
459     struct file *fp;
460     int (*func)(struct file *fp, int com, caddr_t data, struct proc *p);
461     int bsd_line, linux_line;
462     int error;
463 
464 #ifdef DEBUG
465     printf("Linux-emul(%d): ioctl(%d, %04x, *)\n",
466 	   p->p_pid, args->fd, args->cmd);
467 #endif
468     if ((unsigned)args->fd >= fdp->fd_nfiles
469 	|| (fp = fdp->fd_ofiles[args->fd]) == 0)
470 	return EBADF;
471 
472     if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) {
473 	return EBADF;
474     }
475 
476     func = fp->f_ops->fo_ioctl;
477     switch (args->cmd & 0xffff) {
478 
479     case LINUX_TCGETA:
480 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
481 	    return error;
482 	bsd_to_linux_termio(&bsd_termios, &linux_termio);
483 	return copyout((caddr_t)&linux_termio, (caddr_t)args->arg,
484 		       sizeof(linux_termio));
485 
486     case LINUX_TCSETA:
487 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
488 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
489 
490     case LINUX_TCSETAW:
491 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
492 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
493 
494     case LINUX_TCSETAF:
495 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
496 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
497 
498     case LINUX_TCGETS:
499 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
500 	    return error;
501 	bsd_to_linux_termios(&bsd_termios, &linux_termios);
502 	return copyout((caddr_t)&linux_termios, (caddr_t)args->arg,
503 		       sizeof(linux_termios));
504 
505     case LINUX_TCSETS:
506 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
507 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
508 
509     case LINUX_TCSETSW:
510 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
511 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
512 
513     case LINUX_TCSETSF:
514 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
515 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
516 
517     case LINUX_TIOCGPGRP:
518 	args->cmd = TIOCGPGRP;
519 	return ioctl(p, (struct ioctl_args *)args, retval);
520 
521     case LINUX_TIOCSPGRP:
522 	args->cmd = TIOCSPGRP;
523 	return ioctl(p, (struct ioctl_args *)args, retval);
524 
525     case LINUX_TIOCGWINSZ:
526 	args->cmd = TIOCGWINSZ;
527 	return ioctl(p, (struct ioctl_args *)args, retval);
528 
529     case LINUX_TIOCSWINSZ:
530 	args->cmd = TIOCSWINSZ;
531 	return ioctl(p, (struct ioctl_args *)args, retval);
532 
533     case LINUX_FIONREAD:
534 	args->cmd = FIONREAD;
535 	return ioctl(p, (struct ioctl_args *)args, retval);
536 
537     case LINUX_FIONBIO:
538 	args->cmd = FIONBIO;
539 	return ioctl(p, (struct ioctl_args *)args, retval);
540 
541     case LINUX_FIOASYNC:
542 	args->cmd = FIOASYNC;
543 	return ioctl(p, (struct ioctl_args *)args, retval);
544 
545     case LINUX_FIONCLEX:
546 	args->cmd = FIONCLEX;
547 	return ioctl(p, (struct ioctl_args *)args, retval);
548 
549     case LINUX_FIOCLEX:
550 	args->cmd = FIOCLEX;
551 	return ioctl(p, (struct ioctl_args *)args, retval);
552 
553     case LINUX_TIOCEXCL:
554 	args->cmd = TIOCEXCL;
555 	return ioctl(p, (struct ioctl_args *)args, retval);
556 
557     case LINUX_TIOCNXCL:
558 	args->cmd = TIOCNXCL;
559 	return ioctl(p, (struct ioctl_args *)args, retval);
560 
561     case LINUX_TIOCCONS:
562 	args->cmd = TIOCCONS;
563 	return ioctl(p, (struct ioctl_args *)args, retval);
564 
565     case LINUX_TIOCNOTTY:
566 	args->cmd = TIOCNOTTY;
567 	return ioctl(p, (struct ioctl_args *)args, retval);
568 
569     case LINUX_SIOCGIFCONF:
570 	args->cmd = OSIOCGIFCONF;
571 	return ioctl(p, (struct ioctl_args *)args, retval);
572 
573     case LINUX_SIOCGIFFLAGS:
574 	args->cmd = SIOCGIFFLAGS;
575 	return ioctl(p, (struct ioctl_args *)args, retval);
576 
577     case LINUX_SIOCGIFADDR:
578 	args->cmd = OSIOCGIFADDR;
579 	return ioctl(p, (struct ioctl_args *)args, retval);
580 
581     case LINUX_SIOCGIFDSTADDR:
582 	args->cmd = OSIOCGIFDSTADDR;
583 	return ioctl(p, (struct ioctl_args *)args, retval);
584 
585     case LINUX_SIOCGIFBRDADDR:
586 	args->cmd = OSIOCGIFBRDADDR;
587 	return ioctl(p, (struct ioctl_args *)args, retval);
588 
589     case LINUX_SIOCGIFNETMASK:
590 	args->cmd = OSIOCGIFNETMASK;
591 	return ioctl(p, (struct ioctl_args *)args, retval);
592 
593     case LINUX_SIOCADDMULTI:
594 	args->cmd = SIOCADDMULTI;
595 	return ioctl(p, (struct ioctl_args *)args, retval);
596 
597     case LINUX_SIOCDELMULTI:
598 	args->cmd = SIOCDELMULTI;
599 	return ioctl(p, (struct ioctl_args *)args, retval);
600 
601     case LINUX_TIOCSETD:
602 	switch (args->arg) {
603 	case LINUX_N_TTY:
604 	    bsd_line = TTYDISC;
605 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
606 	case LINUX_N_SLIP:
607 	    bsd_line = SLIPDISC;
608 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
609 	case LINUX_N_PPP:
610 	    bsd_line = PPPDISC;
611 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
612 	default:
613 	    return EINVAL;
614 	}
615 
616     case LINUX_TIOCGETD:
617 	bsd_line = TTYDISC;
618 	if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p))
619 	    return error;
620 	switch (bsd_line) {
621 	case TTYDISC:
622 	    linux_line = LINUX_N_TTY;
623 	    break;
624 	case SLIPDISC:
625 	    linux_line = LINUX_N_SLIP;
626 	    break;
627 	case PPPDISC:
628 	    linux_line = LINUX_N_PPP;
629 	    break;
630 	default:
631 	    return EINVAL;
632 	}
633 	return copyout(&linux_line, (caddr_t)args->arg,
634 		       sizeof(int));
635 
636     case LINUX_SNDCTL_DSP_RESET:
637 	args->cmd = SNDCTL_DSP_RESET;
638 	return ioctl(p, (struct ioctl_args *)args, retval);
639 
640     case LINUX_SNDCTL_DSP_SYNC:
641 	args->cmd = SNDCTL_DSP_SYNC;
642 	return ioctl(p, (struct ioctl_args *)args, retval);
643 
644     case LINUX_SNDCTL_DSP_SPEED:
645 	args->cmd = SNDCTL_DSP_SPEED;
646 	return ioctl(p, (struct ioctl_args *)args, retval);
647 
648     case LINUX_SNDCTL_DSP_STEREO:
649 	args->cmd = SNDCTL_DSP_STEREO;
650 	return ioctl(p, (struct ioctl_args *)args, retval);
651 
652     case LINUX_SNDCTL_DSP_GETBLKSIZE:
653       /* LINUX_SNDCTL_DSP_SETBLKSIZE */
654 	args->cmd = SNDCTL_DSP_GETBLKSIZE;
655 	return ioctl(p, (struct ioctl_args *)args, retval);
656 
657     case LINUX_SNDCTL_DSP_SETFMT:
658 	args->cmd = SNDCTL_DSP_SETFMT;
659 	return ioctl(p, (struct ioctl_args *)args, retval);
660 
661     case LINUX_SOUND_PCM_WRITE_CHANNELS:
662 	args->cmd = SOUND_PCM_WRITE_CHANNELS;
663 	return ioctl(p, (struct ioctl_args *)args, retval);
664 
665     case LINUX_SOUND_PCM_WRITE_FILTER:
666 	args->cmd = SOUND_PCM_WRITE_FILTER;
667 	return ioctl(p, (struct ioctl_args *)args, retval);
668 
669     case LINUX_SNDCTL_DSP_POST:
670 	args->cmd = SNDCTL_DSP_POST;
671 	return ioctl(p, (struct ioctl_args *)args, retval);
672 
673     case LINUX_SNDCTL_DSP_SUBDIVIDE:
674 	args->cmd = SNDCTL_DSP_SUBDIVIDE;
675 	return ioctl(p, (struct ioctl_args *)args, retval);
676 
677     case LINUX_SNDCTL_DSP_SETFRAGMENT:
678 	args->cmd = SNDCTL_DSP_SETFRAGMENT;
679 	return ioctl(p, (struct ioctl_args *)args, retval);
680 
681     case LINUX_SNDCTL_DSP_GETFMTS:
682 	args->cmd = SNDCTL_DSP_GETFMTS;
683 	return ioctl(p, (struct ioctl_args *)args, retval);
684 
685     case LINUX_SNDCTL_DSP_GETOSPACE:
686 	args->cmd = SNDCTL_DSP_GETOSPACE;
687 	return ioctl(p, (struct ioctl_args *)args, retval);
688 
689     case LINUX_SNDCTL_DSP_GETISPACE:
690 	args->cmd = SNDCTL_DSP_GETISPACE;
691 	return ioctl(p, (struct ioctl_args *)args, retval);
692 
693     case LINUX_SNDCTL_DSP_NONBLOCK:
694 	args->cmd = SNDCTL_DSP_NONBLOCK;
695 	return ioctl(p, (struct ioctl_args *)args, retval);
696 
697     case LINUX_TIOCGSERIAL:
698         linux_tiocgserial(fp, (struct linux_serial_struct *)args->arg);
699         return 0;
700 
701     case LINUX_TIOCSSERIAL:
702         linux_tiocsserial(fp, (struct linux_serial_struct *)args->arg);
703 	return 0;
704 
705     case LINUX_TCFLSH:
706       args->cmd = TIOCFLUSH;
707       switch (args->arg) {
708         case LINUX_TCIFLUSH:
709                 args->arg = FREAD;
710                 break;
711         case LINUX_TCOFLUSH:
712                 args->arg = FWRITE;
713                 break;
714         case LINUX_TCIOFLUSH:
715                 args->arg = FREAD | FWRITE;
716                 break;
717         default:
718 	        return EINVAL;
719       }
720       return ioctl(p, (struct ioctl_args *)args, retval);
721 
722     }
723     uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n",
724 	    args->fd, (args->cmd&0xffff00)>>8,
725 	    (args->cmd&0xffff00)>>8, args->cmd&0xff);
726     return EINVAL;
727 }
728