xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision 2ad872c5794e4c26fdf6ed219ad3f09ca0d5304a)
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.29 1998/09/30 01:42:53 jfieber 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/fcntl.h>
36 #include <sys/file.h>
37 #include <sys/filedesc.h>
38 #include <sys/filio.h>
39 #include <sys/tty.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <net/if_dl.h>
43 #include <net/if_types.h>
44 #include <sys/sockio.h>
45 
46 #include <machine/soundcard.h>
47 #include <machine/console.h>
48 
49 #include <i386/linux/linux.h>
50 #include <i386/linux/linux_proto.h>
51 
52 #define ISSIGVALID(sig)		((sig) > 0 && (sig) < NSIG)
53 
54 struct linux_termio {
55     unsigned short c_iflag;
56     unsigned short c_oflag;
57     unsigned short c_cflag;
58     unsigned short c_lflag;
59     unsigned char c_line;
60     unsigned char c_cc[LINUX_NCC];
61 };
62 
63 
64 struct linux_termios {
65     unsigned long   c_iflag;
66     unsigned long   c_oflag;
67     unsigned long   c_cflag;
68     unsigned long   c_lflag;
69     unsigned char   c_line;
70     unsigned char   c_cc[LINUX_NCCS];
71 };
72 
73 struct linux_winsize {
74     unsigned short ws_row, ws_col;
75     unsigned short ws_xpixel, ws_ypixel;
76 };
77 
78 static struct speedtab sptab[] = {
79     { 0, 0 }, { 50, 1 }, { 75, 2 }, { 110, 3 },
80     { 134, 4 }, { 135, 4 }, { 150, 5 }, { 200, 6 },
81     { 300, 7 }, { 600, 8 }, { 1200, 9 }, { 1800, 10 },
82     { 2400, 11 }, { 4800, 12 }, { 9600, 13 },
83     { 19200, 14 }, { 38400, 15 },
84     { 57600, 4097 }, { 115200, 4098 }, {-1, -1 }
85 };
86 
87 struct linux_serial_struct {
88         int     type;
89         int     line;
90         int     port;
91         int     irq;
92         int     flags;
93         int     xmit_fifo_size;
94         int     custom_divisor;
95         int     baud_base;
96         unsigned short  close_delay;
97         char    reserved_char[2];
98         int     hub6;
99         unsigned short  closing_wait;
100         unsigned short  closing_wait2;
101         int     reserved[4];
102 };
103 
104 
105 static int
106 linux_to_bsd_speed(int code, struct speedtab *table)
107 {
108     for ( ; table->sp_code != -1; table++)
109 	if (table->sp_code == code)
110 	    return (table->sp_speed);
111     return -1;
112 }
113 
114 static int
115 bsd_to_linux_speed(int speed, struct speedtab *table)
116 {
117     for ( ; table->sp_speed != -1; table++)
118 	if (table->sp_speed == speed)
119 	    return (table->sp_code);
120     return -1;
121 }
122 
123 static void
124 bsd_to_linux_termios(struct termios *bsd_termios,
125 		struct linux_termios *linux_termios)
126 {
127     int i;
128 
129 #ifdef DEBUG
130     printf("LINUX: BSD termios structure (input):\n");
131     printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
132 	   bsd_termios->c_iflag, bsd_termios->c_oflag,
133 	   bsd_termios->c_cflag, bsd_termios->c_lflag,
134 	   bsd_termios->c_ispeed, bsd_termios->c_ospeed);
135     printf("c_cc ");
136     for (i=0; i<NCCS; i++)
137 	printf("%02x ", bsd_termios->c_cc[i]);
138     printf("\n");
139 #endif
140     linux_termios->c_iflag = 0;
141     if (bsd_termios->c_iflag & IGNBRK)
142 	linux_termios->c_iflag |= LINUX_IGNBRK;
143     if (bsd_termios->c_iflag & BRKINT)
144 	linux_termios->c_iflag |= LINUX_BRKINT;
145     if (bsd_termios->c_iflag & IGNPAR)
146 	linux_termios->c_iflag |= LINUX_IGNPAR;
147     if (bsd_termios->c_iflag & PARMRK)
148 	linux_termios->c_iflag |= LINUX_PARMRK;
149     if (bsd_termios->c_iflag & INPCK)
150 	linux_termios->c_iflag |= LINUX_INPCK;
151     if (bsd_termios->c_iflag & ISTRIP)
152 	linux_termios->c_iflag |= LINUX_ISTRIP;
153     if (bsd_termios->c_iflag & INLCR)
154 	linux_termios->c_iflag |= LINUX_INLCR;
155     if (bsd_termios->c_iflag & IGNCR)
156 	linux_termios->c_iflag |= LINUX_IGNCR;
157     if (bsd_termios->c_iflag & ICRNL)
158 	linux_termios->c_iflag |= LINUX_ICRNL;
159     if (bsd_termios->c_iflag & IXON)
160 	linux_termios->c_iflag |= LINUX_IXANY;
161     if (bsd_termios->c_iflag & IXON)
162 	linux_termios->c_iflag |= LINUX_IXON;
163     if (bsd_termios->c_iflag & IXOFF)
164 	linux_termios->c_iflag |= LINUX_IXOFF;
165     if (bsd_termios->c_iflag & IMAXBEL)
166 	linux_termios->c_iflag |= LINUX_IMAXBEL;
167 
168     linux_termios->c_oflag = 0;
169     if (bsd_termios->c_oflag & OPOST)
170 	linux_termios->c_oflag |= LINUX_OPOST;
171     if (bsd_termios->c_oflag & ONLCR)
172 	linux_termios->c_oflag |= LINUX_ONLCR;
173     if (bsd_termios->c_oflag & OXTABS)
174 	linux_termios->c_oflag |= LINUX_XTABS;
175 
176     linux_termios->c_cflag =
177 	bsd_to_linux_speed(bsd_termios->c_ispeed, sptab);
178     linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4;
179     if (bsd_termios->c_cflag & CSTOPB)
180 	linux_termios->c_cflag |= LINUX_CSTOPB;
181     if (bsd_termios->c_cflag & CREAD)
182 	linux_termios->c_cflag |= LINUX_CREAD;
183     if (bsd_termios->c_cflag & PARENB)
184 	linux_termios->c_cflag |= LINUX_PARENB;
185     if (bsd_termios->c_cflag & PARODD)
186 	linux_termios->c_cflag |= LINUX_PARODD;
187     if (bsd_termios->c_cflag & HUPCL)
188 	linux_termios->c_cflag |= LINUX_HUPCL;
189     if (bsd_termios->c_cflag & CLOCAL)
190 	linux_termios->c_cflag |= LINUX_CLOCAL;
191     if (bsd_termios->c_cflag & CRTSCTS)
192 	linux_termios->c_cflag |= LINUX_CRTSCTS;
193 
194     linux_termios->c_lflag = 0;
195     if (bsd_termios->c_lflag & ISIG)
196 	linux_termios->c_lflag |= LINUX_ISIG;
197     if (bsd_termios->c_lflag & ICANON)
198 	linux_termios->c_lflag |= LINUX_ICANON;
199     if (bsd_termios->c_lflag & ECHO)
200 	linux_termios->c_lflag |= LINUX_ECHO;
201     if (bsd_termios->c_lflag & ECHOE)
202 	linux_termios->c_lflag |= LINUX_ECHOE;
203     if (bsd_termios->c_lflag & ECHOK)
204 	linux_termios->c_lflag |= LINUX_ECHOK;
205     if (bsd_termios->c_lflag & ECHONL)
206 	linux_termios->c_lflag |= LINUX_ECHONL;
207     if (bsd_termios->c_lflag & NOFLSH)
208 	linux_termios->c_lflag |= LINUX_NOFLSH;
209     if (bsd_termios->c_lflag & TOSTOP)
210 	linux_termios->c_lflag |= LINUX_TOSTOP;
211     if (bsd_termios->c_lflag & ECHOCTL)
212 	linux_termios->c_lflag |= LINUX_ECHOCTL;
213     if (bsd_termios->c_lflag & ECHOPRT)
214 	linux_termios->c_lflag |= LINUX_ECHOPRT;
215     if (bsd_termios->c_lflag & ECHOKE)
216 	linux_termios->c_lflag |= LINUX_ECHOKE;
217     if (bsd_termios->c_lflag & FLUSHO)
218 	linux_termios->c_lflag |= LINUX_FLUSHO;
219     if (bsd_termios->c_lflag & PENDIN)
220 	linux_termios->c_lflag |= LINUX_PENDIN;
221     if (bsd_termios->c_lflag & IEXTEN)
222 	linux_termios->c_lflag |= LINUX_IEXTEN;
223 
224     for (i=0; i<LINUX_NCCS; i++)
225 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
226     linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR];
227     linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT];
228     linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE];
229     linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL];
230     linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF];
231     linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL];
232     linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN];
233     linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME];
234     linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2];
235     linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE;
236     linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP];
237     linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART];
238     linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP];
239     linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT];
240     linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD];
241     linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE];
242     linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT];
243 
244     for (i=0; i<LINUX_NCCS; i++) {
245       if (linux_termios->c_cc[i] == _POSIX_VDISABLE)
246 	linux_termios->c_cc[i] = LINUX_POSIX_VDISABLE;
247     }
248 
249     linux_termios->c_line = 0;
250 #ifdef DEBUG
251     printf("LINUX: LINUX termios structure (output):\n");
252     printf("i=%08lx o=%08lx c=%08lx l=%08lx line=%d\n",
253 	linux_termios->c_iflag, linux_termios->c_oflag, linux_termios->c_cflag,
254 	linux_termios->c_lflag, 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 }
261 
262 
263 static void
264 linux_to_bsd_termios(struct linux_termios *linux_termios,
265 		struct termios *bsd_termios)
266 {
267     int i;
268 #ifdef DEBUG
269     printf("LINUX: LINUX termios structure (input):\n");
270     printf("i=%08lx o=%08lx c=%08lx l=%08lx line=%d\n",
271 	linux_termios->c_iflag, linux_termios->c_oflag, linux_termios->c_cflag,
272 	linux_termios->c_lflag, 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)
452 {
453     struct termios bsd_termios;
454     struct linux_termios linux_termios;
455     struct linux_termio linux_termio;
456     struct filedesc *fdp = p->p_fd;
457     struct file *fp;
458     int (*func)(struct file *fp, u_long com, caddr_t data, struct proc *p);
459     int bsd_line, linux_line;
460     int error;
461 
462 #ifdef DEBUG
463     printf("Linux-emul(%ld): ioctl(%d, %04lx, *)\n",
464 	(long)p->p_pid, args->fd, args->cmd);
465 #endif
466     if ((unsigned)args->fd >= fdp->fd_nfiles
467 	|| (fp = fdp->fd_ofiles[args->fd]) == 0)
468 	return EBADF;
469 
470     if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) {
471 	return EBADF;
472     }
473 
474     func = fp->f_ops->fo_ioctl;
475     switch (args->cmd & 0xffff) {
476 
477     case LINUX_TCGETA:
478 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
479 	    return error;
480 	bsd_to_linux_termio(&bsd_termios, &linux_termio);
481 	return copyout((caddr_t)&linux_termio, (caddr_t)args->arg,
482 		       sizeof(linux_termio));
483 
484     case LINUX_TCSETA:
485 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
486 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
487 
488     case LINUX_TCSETAW:
489 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
490 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
491 
492     case LINUX_TCSETAF:
493 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
494 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
495 
496     case LINUX_TCGETS:
497 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
498 	    return error;
499 	bsd_to_linux_termios(&bsd_termios, &linux_termios);
500 	return copyout((caddr_t)&linux_termios, (caddr_t)args->arg,
501 		       sizeof(linux_termios));
502 
503     case LINUX_TCSETS:
504 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
505 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
506 
507     case LINUX_TCSETSW:
508 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
509 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
510 
511     case LINUX_TCSETSF:
512 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
513 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
514 
515     case LINUX_TIOCGPGRP:
516 	args->cmd = TIOCGPGRP;
517 	return ioctl(p, (struct ioctl_args *)args);
518 
519     case LINUX_TIOCSPGRP:
520 	args->cmd = TIOCSPGRP;
521 	return ioctl(p, (struct ioctl_args *)args);
522 
523     case LINUX_TIOCGWINSZ:
524 	args->cmd = TIOCGWINSZ;
525 	return ioctl(p, (struct ioctl_args *)args);
526 
527     case LINUX_TIOCSWINSZ:
528 	args->cmd = TIOCSWINSZ;
529 	return ioctl(p, (struct ioctl_args *)args);
530 
531     case LINUX_FIONREAD:
532 	args->cmd = FIONREAD;
533 	return ioctl(p, (struct ioctl_args *)args);
534 
535     case LINUX_FIONBIO:
536 	args->cmd = FIONBIO;
537 	return ioctl(p, (struct ioctl_args *)args);
538 
539     case LINUX_FIOASYNC:
540 	args->cmd = FIOASYNC;
541 	return ioctl(p, (struct ioctl_args *)args);
542 
543     case LINUX_FIONCLEX:
544 	args->cmd = FIONCLEX;
545 	return ioctl(p, (struct ioctl_args *)args);
546 
547     case LINUX_FIOCLEX:
548 	args->cmd = FIOCLEX;
549 	return ioctl(p, (struct ioctl_args *)args);
550 
551     case LINUX_TIOCEXCL:
552 	args->cmd = TIOCEXCL;
553 	return ioctl(p, (struct ioctl_args *)args);
554 
555     case LINUX_TIOCNXCL:
556 	args->cmd = TIOCNXCL;
557 	return ioctl(p, (struct ioctl_args *)args);
558 
559     case LINUX_TIOCCONS:
560 	args->cmd = TIOCCONS;
561 	return ioctl(p, (struct ioctl_args *)args);
562 
563     case LINUX_TIOCNOTTY:
564 	args->cmd = TIOCNOTTY;
565 	return ioctl(p, (struct ioctl_args *)args);
566 
567     case LINUX_SIOCGIFCONF:
568 	args->cmd = OSIOCGIFCONF;
569 	return ioctl(p, (struct ioctl_args *)args);
570 
571     case LINUX_SIOCGIFFLAGS:
572 	args->cmd = SIOCGIFFLAGS;
573 	return ioctl(p, (struct ioctl_args *)args);
574 
575     case LINUX_SIOCGIFADDR:
576 	args->cmd = OSIOCGIFADDR;
577 	return ioctl(p, (struct ioctl_args *)args);
578 
579     case LINUX_SIOCGIFDSTADDR:
580 	args->cmd = OSIOCGIFDSTADDR;
581 	return ioctl(p, (struct ioctl_args *)args);
582 
583     case LINUX_SIOCGIFBRDADDR:
584 	args->cmd = OSIOCGIFBRDADDR;
585 	return ioctl(p, (struct ioctl_args *)args);
586 
587     case LINUX_SIOCGIFNETMASK:
588 	args->cmd = OSIOCGIFNETMASK;
589 	return ioctl(p, (struct ioctl_args *)args);
590 
591 	/* get hardware address */
592     case LINUX_SIOCGIFHWADDR:
593     {
594 	int			ifn;
595 	struct ifnet		*ifp;
596 	struct ifaddr		*ifa;
597 	struct sockaddr_dl	*sdl;
598 	struct linux_ifreq	*ifr = (struct linux_ifreq *)args->arg;
599 
600 	/*
601 	 * Note that we don't actually respect the name in the ifreq structure, as
602 	 * Linux interface names are all different
603 	 */
604 
605 	for (ifn = 0; ifn < if_index; ifn++) {
606 
607 	    ifp = ifnet_addrs[ifn]->ifa_ifp;	/* pointer to interface */
608 	    if (ifp->if_type == IFT_ETHER) {	/* looks good */
609 		/* walk the address list */
610 		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = TAILQ_NEXT(ifa, ifa_link)) {
611 		    if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&	/* we have an address structure */
612 			(sdl->sdl_family == AF_LINK) &&			/* it's a link address */
613 			(sdl->sdl_type == IFT_ETHER)) {			/* for an ethernet link */
614 
615 			return(copyout(LLADDR(sdl), (caddr_t)&ifr->ifr_hwaddr.sa_data, LINUX_IFHWADDRLEN));
616 		    }
617 		}
618 	    }
619 	}
620 	return(ENOENT);		/* ??? */
621     }
622 
623     case LINUX_SIOCADDMULTI:
624 	args->cmd = SIOCADDMULTI;
625 	return ioctl(p, (struct ioctl_args *)args);
626 
627     case LINUX_SIOCDELMULTI:
628 	args->cmd = SIOCDELMULTI;
629 	return ioctl(p, (struct ioctl_args *)args);
630 
631     case LINUX_FIOSETOWN:
632 	args->cmd = FIOSETOWN;
633 	return ioctl(p, (struct ioctl_args *)args);
634 
635     case LINUX_SIOCSPGRP:
636 	args->cmd = SIOCSPGRP;
637 	return ioctl(p, (struct ioctl_args *)args);
638 
639     case LINUX_FIOGETOWN:
640 	args->cmd = FIOGETOWN;
641 	return ioctl(p, (struct ioctl_args *)args);
642 
643     case LINUX_SIOCGPGRP:
644 	args->cmd = SIOCGPGRP;
645 	return ioctl(p, (struct ioctl_args *)args);
646 
647     case LINUX_SIOCATMARK:
648 	args->cmd = SIOCATMARK;
649 	return ioctl(p, (struct ioctl_args *)args);
650 
651     case LINUX_TIOCSETD:
652 	switch (args->arg) {
653 	case LINUX_N_TTY:
654 	    bsd_line = TTYDISC;
655 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
656 	case LINUX_N_SLIP:
657 	    bsd_line = SLIPDISC;
658 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
659 	case LINUX_N_PPP:
660 	    bsd_line = PPPDISC;
661 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
662 	default:
663 	    return EINVAL;
664 	}
665 
666     case LINUX_TIOCGETD:
667 	bsd_line = TTYDISC;
668 	if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p))
669 	    return error;
670 	switch (bsd_line) {
671 	case TTYDISC:
672 	    linux_line = LINUX_N_TTY;
673 	    break;
674 	case SLIPDISC:
675 	    linux_line = LINUX_N_SLIP;
676 	    break;
677 	case PPPDISC:
678 	    linux_line = LINUX_N_PPP;
679 	    break;
680 	default:
681 	    return EINVAL;
682 	}
683 	return copyout(&linux_line, (caddr_t)args->arg,
684 		       sizeof(int));
685 
686     case LINUX_SNDCTL_SEQ_RESET:
687 	args->cmd = SNDCTL_SEQ_RESET;
688 	return ioctl(p, (struct ioctl_args *)args);
689 
690     case LINUX_SNDCTL_SEQ_SYNC:
691 	args->cmd = SNDCTL_SEQ_SYNC;
692 	return ioctl(p, (struct ioctl_args *)args);
693 
694     case LINUX_SNDCTL_SYNTH_INFO:
695 	args->cmd = SNDCTL_SYNTH_INFO;
696 	return ioctl(p, (struct ioctl_args *)args);
697 
698     case LINUX_SNDCTL_SEQ_CTRLRATE:
699 	args->cmd = SNDCTL_SEQ_CTRLRATE;
700 	return ioctl(p, (struct ioctl_args *)args);
701 
702     case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
703 	args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
704 	return ioctl(p, (struct ioctl_args *)args);
705 
706     case LINUX_SNDCTL_SEQ_GETINCOUNT:
707 	args->cmd = SNDCTL_SEQ_GETINCOUNT;
708 	return ioctl(p, (struct ioctl_args *)args);
709 
710     case LINUX_SNDCTL_SEQ_PERCMODE:
711 	args->cmd = SNDCTL_SEQ_PERCMODE;
712 	return ioctl(p, (struct ioctl_args *)args);
713 
714     case LINUX_SNDCTL_FM_LOAD_INSTR:
715 	args->cmd = SNDCTL_FM_LOAD_INSTR;
716 	return ioctl(p, (struct ioctl_args *)args);
717 
718     case LINUX_SNDCTL_SEQ_TESTMIDI:
719 	args->cmd = SNDCTL_SEQ_TESTMIDI;
720 	return ioctl(p, (struct ioctl_args *)args);
721 
722     case LINUX_SNDCTL_SEQ_RESETSAMPLES:
723 	args->cmd = SNDCTL_SEQ_RESETSAMPLES;
724 	return ioctl(p, (struct ioctl_args *)args);
725 
726     case LINUX_SNDCTL_SEQ_NRSYNTHS:
727 	args->cmd = SNDCTL_SEQ_NRSYNTHS;
728 	return ioctl(p, (struct ioctl_args *)args);
729 
730     case LINUX_SNDCTL_SEQ_NRMIDIS:
731 	args->cmd = SNDCTL_SEQ_NRMIDIS;
732 	return ioctl(p, (struct ioctl_args *)args);
733 
734     case LINUX_SNDCTL_MIDI_INFO:
735 	args->cmd = SNDCTL_MIDI_INFO;
736 	return ioctl(p, (struct ioctl_args *)args);
737 
738     case LINUX_SNDCTL_SEQ_TRESHOLD:
739 	args->cmd = SNDCTL_SEQ_TRESHOLD;
740 	return ioctl(p, (struct ioctl_args *)args);
741 
742     case LINUX_SNDCTL_SYNTH_MEMAVL:
743 	args->cmd = SNDCTL_SYNTH_MEMAVL;
744 	return ioctl(p, (struct ioctl_args *)args);
745 
746     case LINUX_SNDCTL_DSP_GETOPTR :
747 	args->cmd = SNDCTL_DSP_GETOPTR;
748 	return ioctl(p, (struct ioctl_args *)args);
749 
750     case LINUX_SNDCTL_DSP_GETIPTR :
751 	args->cmd = SNDCTL_DSP_GETIPTR;
752 	return ioctl(p, (struct ioctl_args *)args);
753 
754     case LINUX_SNDCTL_DSP_SETTRIGGER:
755 	args->cmd = SNDCTL_DSP_SETTRIGGER;
756 	return ioctl(p, (struct ioctl_args *)args);
757 
758     case LINUX_SNDCTL_DSP_GETCAPS:
759 	args->cmd = SNDCTL_DSP_GETCAPS;
760 	return ioctl(p, (struct ioctl_args *)args);
761 
762     case LINUX_SNDCTL_DSP_RESET:
763 	args->cmd = SNDCTL_DSP_RESET;
764 	return ioctl(p, (struct ioctl_args *)args);
765 
766     case LINUX_SNDCTL_DSP_SYNC:
767 	args->cmd = SNDCTL_DSP_SYNC;
768 	return ioctl(p, (struct ioctl_args *)args);
769 
770     case LINUX_SNDCTL_DSP_SPEED:
771 	args->cmd = SNDCTL_DSP_SPEED;
772 	return ioctl(p, (struct ioctl_args *)args);
773 
774     case LINUX_SNDCTL_DSP_STEREO:
775 	args->cmd = SNDCTL_DSP_STEREO;
776 	return ioctl(p, (struct ioctl_args *)args);
777 
778     case LINUX_SNDCTL_DSP_GETBLKSIZE:
779       /* LINUX_SNDCTL_DSP_SETBLKSIZE */
780 	args->cmd = SNDCTL_DSP_GETBLKSIZE;
781 	return ioctl(p, (struct ioctl_args *)args);
782 
783     case LINUX_SNDCTL_DSP_SETFMT:
784 	args->cmd = SNDCTL_DSP_SETFMT;
785 	return ioctl(p, (struct ioctl_args *)args);
786 
787     case LINUX_SOUND_PCM_WRITE_CHANNELS:
788 	args->cmd = SOUND_PCM_WRITE_CHANNELS;
789 	return ioctl(p, (struct ioctl_args *)args);
790 
791     case LINUX_SOUND_PCM_WRITE_FILTER:
792 	args->cmd = SOUND_PCM_WRITE_FILTER;
793 	return ioctl(p, (struct ioctl_args *)args);
794 
795     case LINUX_SNDCTL_DSP_POST:
796 	args->cmd = SNDCTL_DSP_POST;
797 	return ioctl(p, (struct ioctl_args *)args);
798 
799     case LINUX_SNDCTL_DSP_SUBDIVIDE:
800 	args->cmd = SNDCTL_DSP_SUBDIVIDE;
801 	return ioctl(p, (struct ioctl_args *)args);
802 
803     case LINUX_SNDCTL_DSP_SETFRAGMENT:
804 	args->cmd = SNDCTL_DSP_SETFRAGMENT;
805 	return ioctl(p, (struct ioctl_args *)args);
806 
807     case LINUX_SNDCTL_DSP_GETFMTS:
808 	args->cmd = SNDCTL_DSP_GETFMTS;
809 	return ioctl(p, (struct ioctl_args *)args);
810 
811     case LINUX_SNDCTL_DSP_GETOSPACE:
812 	args->cmd = SNDCTL_DSP_GETOSPACE;
813 	return ioctl(p, (struct ioctl_args *)args);
814 
815     case LINUX_SNDCTL_DSP_GETISPACE:
816 	args->cmd = SNDCTL_DSP_GETISPACE;
817 	return ioctl(p, (struct ioctl_args *)args);
818 
819     case LINUX_SNDCTL_DSP_NONBLOCK:
820 	args->cmd = SNDCTL_DSP_NONBLOCK;
821 	return ioctl(p, (struct ioctl_args *)args);
822 
823     case LINUX_SOUND_MIXER_WRITE_VOLUME:
824 	args->cmd = SOUND_MIXER_WRITE_VOLUME;
825 	return ioctl(p, (struct ioctl_args *)args);
826 
827     case LINUX_SOUND_MIXER_WRITE_BASS:
828 	args->cmd = SOUND_MIXER_WRITE_BASS;
829 	return ioctl(p, (struct ioctl_args *)args);
830 
831     case LINUX_SOUND_MIXER_WRITE_TREBLE:
832 	args->cmd = SOUND_MIXER_WRITE_TREBLE;
833 	return ioctl(p, (struct ioctl_args *)args);
834 
835     case LINUX_SOUND_MIXER_WRITE_SYNTH:
836 	args->cmd = SOUND_MIXER_WRITE_SYNTH;
837 	return ioctl(p, (struct ioctl_args *)args);
838 
839     case LINUX_SOUND_MIXER_WRITE_PCM:
840 	args->cmd = SOUND_MIXER_WRITE_PCM;
841 	return ioctl(p, (struct ioctl_args *)args);
842 
843     case LINUX_SOUND_MIXER_WRITE_SPEAKER:
844 	args->cmd = SOUND_MIXER_WRITE_SPEAKER;
845 	return ioctl(p, (struct ioctl_args *)args);
846 
847     case LINUX_SOUND_MIXER_WRITE_LINE:
848 	args->cmd = SOUND_MIXER_WRITE_LINE;
849 	return ioctl(p, (struct ioctl_args *)args);
850 
851     case LINUX_SOUND_MIXER_WRITE_MIC:
852 	args->cmd = SOUND_MIXER_WRITE_MIC;
853 	return ioctl(p, (struct ioctl_args *)args);
854 
855     case LINUX_SOUND_MIXER_WRITE_CD:
856 	args->cmd = SOUND_MIXER_WRITE_CD;
857 	return ioctl(p, (struct ioctl_args *)args);
858 
859     case LINUX_SOUND_MIXER_WRITE_IMIX:
860 	args->cmd = SOUND_MIXER_WRITE_IMIX;
861 	return ioctl(p, (struct ioctl_args *)args);
862 
863     case LINUX_SOUND_MIXER_WRITE_ALTPCM:
864 	args->cmd = SOUND_MIXER_WRITE_ALTPCM;
865 	return ioctl(p, (struct ioctl_args *)args);
866 
867     case LINUX_SOUND_MIXER_WRITE_RECLEV:
868 	args->cmd = SOUND_MIXER_WRITE_RECLEV;
869 	return ioctl(p, (struct ioctl_args *)args);
870 
871     case LINUX_SOUND_MIXER_WRITE_IGAIN:
872 	args->cmd = SOUND_MIXER_WRITE_IGAIN;
873 	return ioctl(p, (struct ioctl_args *)args);
874 
875     case LINUX_SOUND_MIXER_WRITE_OGAIN:
876 	args->cmd = SOUND_MIXER_WRITE_OGAIN;
877 	return ioctl(p, (struct ioctl_args *)args);
878 
879     case LINUX_SOUND_MIXER_WRITE_LINE1:
880 	args->cmd = SOUND_MIXER_WRITE_LINE1;
881 	return ioctl(p, (struct ioctl_args *)args);
882 
883     case LINUX_SOUND_MIXER_WRITE_LINE2:
884 	args->cmd = SOUND_MIXER_WRITE_LINE2;
885 	return ioctl(p, (struct ioctl_args *)args);
886 
887     case LINUX_SOUND_MIXER_WRITE_LINE3:
888 	args->cmd = SOUND_MIXER_WRITE_LINE3;
889 	return ioctl(p, (struct ioctl_args *)args);
890 
891     case LINUX_SOUND_MIXER_READ_DEVMASK:
892 	args->cmd = SOUND_MIXER_READ_DEVMASK;
893 	return ioctl(p, (struct ioctl_args *)args);
894 
895     case LINUX_TIOCGSERIAL:
896         linux_tiocgserial(fp, (struct linux_serial_struct *)args->arg);
897         return 0;
898 
899     case LINUX_TIOCSSERIAL:
900         linux_tiocsserial(fp, (struct linux_serial_struct *)args->arg);
901 	return 0;
902 
903     case LINUX_TCFLSH:
904       args->cmd = TIOCFLUSH;
905       switch (args->arg) {
906         case LINUX_TCIFLUSH:
907                 args->arg = FREAD;
908                 break;
909         case LINUX_TCOFLUSH:
910                 args->arg = FWRITE;
911                 break;
912         case LINUX_TCIOFLUSH:
913                 args->arg = FREAD | FWRITE;
914                 break;
915         default:
916 	        return EINVAL;
917       }
918       return ioctl(p, (struct ioctl_args *)args);
919 
920    case LINUX_VT_OPENQRY:
921 
922 	args->cmd = VT_OPENQRY;
923 	return  ioctl(p, (struct ioctl_args *)args);
924 
925     case LINUX_VT_GETMODE:
926 
927 	args->cmd = VT_GETMODE;
928 	return  ioctl(p, (struct ioctl_args *)args);
929 
930     case LINUX_VT_SETMODE:
931       {
932 	struct vt_mode *mode;
933 	args->cmd = VT_SETMODE;
934 	mode = (struct vt_mode *)args->arg;
935 	if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
936 	    mode->frsig = mode->acqsig;
937 	return ioctl(p, (struct ioctl_args *)args);
938       }
939 
940     case LINUX_VT_GETSTATE:
941 
942 	args->cmd = VT_GETACTIVE;
943 	return  ioctl(p, (struct ioctl_args *)args);
944 
945     case LINUX_VT_ACTIVATE:
946 
947 	args->cmd = VT_ACTIVATE;
948 	return  ioctl(p, (struct ioctl_args *)args);
949 
950     case LINUX_VT_WAITACTIVE:
951 
952 	args->cmd = VT_WAITACTIVE;
953 	return  ioctl(p, (struct ioctl_args *)args);
954 
955     case LINUX_KDGKBMODE:
956 
957 	args->cmd = KDGKBMODE;
958 	return ioctl(p, (struct ioctl_args *)args);
959 
960     case LINUX_KDSKBMODE:
961       {
962         int kbdmode;
963 	switch (args->arg) {
964 	case LINUX_KBD_RAW:
965 	    kbdmode = K_RAW;
966 	    return (*func)(fp, KDSKBMODE, (caddr_t)&kbdmode, p);
967 	case LINUX_KBD_XLATE:
968 	    kbdmode = K_XLATE;
969 	    return (*func)(fp, KDSKBMODE , (caddr_t)&kbdmode, p);
970 	case LINUX_KBD_MEDIUMRAW:
971 	    kbdmode = K_RAW;
972 	    return (*func)(fp, KDSKBMODE , (caddr_t)&kbdmode, p);
973 	default:
974 	    return EINVAL;
975 	}
976       }
977 
978     case LINUX_KDGETMODE:
979 	args->cmd = KDGETMODE;
980 	return	ioctl(p, (struct ioctl_args *)args);
981 
982     case LINUX_KDSETMODE:
983 	args->cmd = KDSETMODE;
984 	return	ioctl(p, (struct ioctl_args *)args);
985 
986     case LINUX_KDSETLED:
987 	args->cmd = KDSETLED;
988 	return  ioctl(p, (struct ioctl_args *)args);
989 
990     case LINUX_KDGETLED:
991 	args->cmd = KDGETLED;
992 	return  ioctl(p, (struct ioctl_args *)args);
993 
994     case LINUX_KIOCSOUND:
995 	args->cmd = KIOCSOUND;
996 	return  ioctl(p, (struct ioctl_args *)args);
997 
998     case LINUX_KDMKTONE:
999 	args->cmd = KDMKTONE;
1000 	return  ioctl(p, (struct ioctl_args *)args);
1001     }
1002 
1003     uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n",
1004 	args->fd, (u_int)((args->cmd & 0xffff00) >> 8),
1005 	(int)((args->cmd & 0xffff00) >> 8), (u_int)(args->cmd & 0xff));
1006     return EINVAL;
1007 }
1008