xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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.24 1998/06/07 17:11:26 dfr 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 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;
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=%08lx o=%08lx c=%08lx l=%08lx line=%d\n",
251 	linux_termios->c_iflag, linux_termios->c_oflag, linux_termios->c_cflag,
252 	linux_termios->c_lflag, linux_termios->c_line);
253     printf("c_cc ");
254     for (i=0; i<LINUX_NCCS; i++)
255 	printf("%02x ", linux_termios->c_cc[i]);
256     printf("\n");
257 #endif
258 }
259 
260 
261 static void
262 linux_to_bsd_termios(struct linux_termios *linux_termios,
263 		struct termios *bsd_termios)
264 {
265     int i;
266 #ifdef DEBUG
267     printf("LINUX: LINUX termios structure (input):\n");
268     printf("i=%08lx o=%08lx c=%08lx l=%08lx line=%d\n",
269 	linux_termios->c_iflag, linux_termios->c_oflag, linux_termios->c_cflag,
270 	linux_termios->c_lflag, linux_termios->c_line);
271     printf("c_cc ");
272     for (i=0; i<LINUX_NCCS; i++)
273 	printf("%02x ", linux_termios->c_cc[i]);
274     printf("\n");
275 #endif
276     bsd_termios->c_iflag = 0;
277     if (linux_termios->c_iflag & LINUX_IGNBRK)
278 	bsd_termios->c_iflag |= IGNBRK;
279     if (linux_termios->c_iflag & LINUX_BRKINT)
280 	bsd_termios->c_iflag |= BRKINT;
281     if (linux_termios->c_iflag & LINUX_IGNPAR)
282 	bsd_termios->c_iflag |= IGNPAR;
283     if (linux_termios->c_iflag & LINUX_PARMRK)
284 	bsd_termios->c_iflag |= PARMRK;
285     if (linux_termios->c_iflag & LINUX_INPCK)
286 	bsd_termios->c_iflag |= INPCK;
287     if (linux_termios->c_iflag & LINUX_ISTRIP)
288 	bsd_termios->c_iflag |= ISTRIP;
289     if (linux_termios->c_iflag & LINUX_INLCR)
290 	bsd_termios->c_iflag |= INLCR;
291     if (linux_termios->c_iflag & LINUX_IGNCR)
292 	bsd_termios->c_iflag |= IGNCR;
293     if (linux_termios->c_iflag & LINUX_ICRNL)
294 	bsd_termios->c_iflag |= ICRNL;
295     if (linux_termios->c_iflag & LINUX_IXON)
296 	bsd_termios->c_iflag |= IXANY;
297     if (linux_termios->c_iflag & LINUX_IXON)
298 	bsd_termios->c_iflag |= IXON;
299     if (linux_termios->c_iflag & LINUX_IXOFF)
300 	bsd_termios->c_iflag |= IXOFF;
301     if (linux_termios->c_iflag & LINUX_IMAXBEL)
302 	bsd_termios->c_iflag |= IMAXBEL;
303 
304     bsd_termios->c_oflag = 0;
305     if (linux_termios->c_oflag & LINUX_OPOST)
306 	bsd_termios->c_oflag |= OPOST;
307     if (linux_termios->c_oflag & LINUX_ONLCR)
308 	bsd_termios->c_oflag |= ONLCR;
309     if (linux_termios->c_oflag & LINUX_XTABS)
310 	bsd_termios->c_oflag |= OXTABS;
311 
312     bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4;
313     if (linux_termios->c_cflag & LINUX_CSTOPB)
314 	bsd_termios->c_cflag |= CSTOPB;
315     if (linux_termios->c_cflag & LINUX_PARENB)
316 	bsd_termios->c_cflag |= PARENB;
317     if (linux_termios->c_cflag & LINUX_PARODD)
318 	bsd_termios->c_cflag |= PARODD;
319     if (linux_termios->c_cflag & LINUX_HUPCL)
320 	bsd_termios->c_cflag |= HUPCL;
321     if (linux_termios->c_cflag & LINUX_CLOCAL)
322 	bsd_termios->c_cflag |= CLOCAL;
323     if (linux_termios->c_cflag & LINUX_CRTSCTS)
324 	bsd_termios->c_cflag |= CRTSCTS;
325 
326     bsd_termios->c_lflag = 0;
327     if (linux_termios->c_lflag & LINUX_ISIG)
328 	bsd_termios->c_lflag |= ISIG;
329     if (linux_termios->c_lflag & LINUX_ICANON)
330 	bsd_termios->c_lflag |= ICANON;
331     if (linux_termios->c_lflag & LINUX_ECHO)
332 	bsd_termios->c_lflag |= ECHO;
333     if (linux_termios->c_lflag & LINUX_ECHOE)
334 	bsd_termios->c_lflag |= ECHOE;
335     if (linux_termios->c_lflag & LINUX_ECHOK)
336 	bsd_termios->c_lflag |= ECHOK;
337     if (linux_termios->c_lflag & LINUX_ECHONL)
338 	bsd_termios->c_lflag |= ECHONL;
339     if (linux_termios->c_lflag & LINUX_NOFLSH)
340 	bsd_termios->c_lflag |= NOFLSH;
341     if (linux_termios->c_lflag & LINUX_TOSTOP)
342 	bsd_termios->c_lflag |= TOSTOP;
343     if (linux_termios->c_lflag & LINUX_ECHOCTL)
344 	bsd_termios->c_lflag |= ECHOCTL;
345     if (linux_termios->c_lflag & LINUX_ECHOPRT)
346 	bsd_termios->c_lflag |= ECHOPRT;
347     if (linux_termios->c_lflag & LINUX_ECHOKE)
348 	bsd_termios->c_lflag |= ECHOKE;
349     if (linux_termios->c_lflag & LINUX_FLUSHO)
350 	bsd_termios->c_lflag |= FLUSHO;
351     if (linux_termios->c_lflag & LINUX_PENDIN)
352 	bsd_termios->c_lflag |= PENDIN;
353     if (linux_termios->c_lflag & IEXTEN)
354 	bsd_termios->c_lflag |= IEXTEN;
355 
356     for (i=0; i<NCCS; i++)
357 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
358     bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR];
359     bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT];
360     bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE];
361     bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL];
362     bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF];
363     bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL];
364     bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN];
365     bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME];
366     bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2];
367     bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP];
368     bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART];
369     bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP];
370     bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT];
371     bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD];
372     bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE];
373     bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT];
374 
375     for (i=0; i<NCCS; i++) {
376       if (bsd_termios->c_cc[i] == LINUX_POSIX_VDISABLE)
377 	bsd_termios->c_cc[i] = _POSIX_VDISABLE;
378     }
379 
380     bsd_termios->c_ispeed = bsd_termios->c_ospeed =
381 	linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab);
382 #ifdef DEBUG
383 	printf("LINUX: BSD termios structure (output):\n");
384 	printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
385 	       bsd_termios->c_iflag, bsd_termios->c_oflag,
386 	       bsd_termios->c_cflag, bsd_termios->c_lflag,
387 	       bsd_termios->c_ispeed, bsd_termios->c_ospeed);
388 	printf("c_cc ");
389 	for (i=0; i<NCCS; i++)
390 	    printf("%02x ", bsd_termios->c_cc[i]);
391 	printf("\n");
392 #endif
393 }
394 
395 
396 static void
397 bsd_to_linux_termio(struct termios *bsd_termios,
398 		struct linux_termio *linux_termio)
399 {
400   struct linux_termios tmios;
401 
402   bsd_to_linux_termios(bsd_termios, &tmios);
403   linux_termio->c_iflag = tmios.c_iflag;
404   linux_termio->c_oflag = tmios.c_oflag;
405   linux_termio->c_cflag = tmios.c_cflag;
406   linux_termio->c_lflag = tmios.c_lflag;
407   linux_termio->c_line  = tmios.c_line;
408   memcpy(linux_termio->c_cc, tmios.c_cc, LINUX_NCC);
409 }
410 
411 static void
412 linux_to_bsd_termio(struct linux_termio *linux_termio,
413 		struct termios *bsd_termios)
414 {
415   struct linux_termios tmios;
416   int i;
417 
418   tmios.c_iflag = linux_termio->c_iflag;
419   tmios.c_oflag = linux_termio->c_oflag;
420   tmios.c_cflag = linux_termio->c_cflag;
421   tmios.c_lflag = linux_termio->c_lflag;
422 
423   for (i=0; i<LINUX_NCCS; i++)
424     tmios.c_cc[i] = LINUX_POSIX_VDISABLE;
425   memcpy(tmios.c_cc, linux_termio->c_cc, LINUX_NCC);
426 
427   linux_to_bsd_termios(&tmios, bsd_termios);
428 }
429 
430 static void
431 linux_tiocgserial(struct file *fp, struct linux_serial_struct *lss)
432 {
433   if (!fp || !lss)
434     return;
435 
436   lss->type = LINUX_PORT_16550A;
437   lss->flags = 0;
438   lss->close_delay = 0;
439 }
440 
441 static void
442 linux_tiocsserial(struct file *fp, struct linux_serial_struct *lss)
443 {
444   if (!fp || !lss)
445     return;
446 }
447 
448 int
449 linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
450 {
451     struct termios bsd_termios;
452     struct linux_termios linux_termios;
453     struct linux_termio linux_termio;
454     struct filedesc *fdp = p->p_fd;
455     struct file *fp;
456     int (*func)(struct file *fp, u_long com, caddr_t data, struct proc *p);
457     int bsd_line, linux_line;
458     int error;
459 
460 #ifdef DEBUG
461     printf("Linux-emul(%ld): ioctl(%d, %04lx, *)\n",
462 	(long)p->p_pid, args->fd, args->cmd);
463 #endif
464     if ((unsigned)args->fd >= fdp->fd_nfiles
465 	|| (fp = fdp->fd_ofiles[args->fd]) == 0)
466 	return EBADF;
467 
468     if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) {
469 	return EBADF;
470     }
471 
472     func = fp->f_ops->fo_ioctl;
473     switch (args->cmd & 0xffff) {
474 
475     case LINUX_TCGETA:
476 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
477 	    return error;
478 	bsd_to_linux_termio(&bsd_termios, &linux_termio);
479 	return copyout((caddr_t)&linux_termio, (caddr_t)args->arg,
480 		       sizeof(linux_termio));
481 
482     case LINUX_TCSETA:
483 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
484 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
485 
486     case LINUX_TCSETAW:
487 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
488 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
489 
490     case LINUX_TCSETAF:
491 	linux_to_bsd_termio((struct linux_termio *)args->arg, &bsd_termios);
492 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
493 
494     case LINUX_TCGETS:
495 	if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0)
496 	    return error;
497 	bsd_to_linux_termios(&bsd_termios, &linux_termios);
498 	return copyout((caddr_t)&linux_termios, (caddr_t)args->arg,
499 		       sizeof(linux_termios));
500 
501     case LINUX_TCSETS:
502 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
503 	return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p);
504 
505     case LINUX_TCSETSW:
506 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
507 	return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p);
508 
509     case LINUX_TCSETSF:
510 	linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios);
511 	return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p);
512 
513     case LINUX_TIOCGPGRP:
514 	args->cmd = TIOCGPGRP;
515 	return ioctl(p, (struct ioctl_args *)args);
516 
517     case LINUX_TIOCSPGRP:
518 	args->cmd = TIOCSPGRP;
519 	return ioctl(p, (struct ioctl_args *)args);
520 
521     case LINUX_TIOCGWINSZ:
522 	args->cmd = TIOCGWINSZ;
523 	return ioctl(p, (struct ioctl_args *)args);
524 
525     case LINUX_TIOCSWINSZ:
526 	args->cmd = TIOCSWINSZ;
527 	return ioctl(p, (struct ioctl_args *)args);
528 
529     case LINUX_FIONREAD:
530 	args->cmd = FIONREAD;
531 	return ioctl(p, (struct ioctl_args *)args);
532 
533     case LINUX_FIONBIO:
534 	args->cmd = FIONBIO;
535 	return ioctl(p, (struct ioctl_args *)args);
536 
537     case LINUX_FIOASYNC:
538 	args->cmd = FIOASYNC;
539 	return ioctl(p, (struct ioctl_args *)args);
540 
541     case LINUX_FIONCLEX:
542 	args->cmd = FIONCLEX;
543 	return ioctl(p, (struct ioctl_args *)args);
544 
545     case LINUX_FIOCLEX:
546 	args->cmd = FIOCLEX;
547 	return ioctl(p, (struct ioctl_args *)args);
548 
549     case LINUX_TIOCEXCL:
550 	args->cmd = TIOCEXCL;
551 	return ioctl(p, (struct ioctl_args *)args);
552 
553     case LINUX_TIOCNXCL:
554 	args->cmd = TIOCNXCL;
555 	return ioctl(p, (struct ioctl_args *)args);
556 
557     case LINUX_TIOCCONS:
558 	args->cmd = TIOCCONS;
559 	return ioctl(p, (struct ioctl_args *)args);
560 
561     case LINUX_TIOCNOTTY:
562 	args->cmd = TIOCNOTTY;
563 	return ioctl(p, (struct ioctl_args *)args);
564 
565     case LINUX_SIOCGIFCONF:
566 	args->cmd = OSIOCGIFCONF;
567 	return ioctl(p, (struct ioctl_args *)args);
568 
569     case LINUX_SIOCGIFFLAGS:
570 	args->cmd = SIOCGIFFLAGS;
571 	return ioctl(p, (struct ioctl_args *)args);
572 
573     case LINUX_SIOCGIFADDR:
574 	args->cmd = OSIOCGIFADDR;
575 	return ioctl(p, (struct ioctl_args *)args);
576 
577     case LINUX_SIOCGIFDSTADDR:
578 	args->cmd = OSIOCGIFDSTADDR;
579 	return ioctl(p, (struct ioctl_args *)args);
580 
581     case LINUX_SIOCGIFBRDADDR:
582 	args->cmd = OSIOCGIFBRDADDR;
583 	return ioctl(p, (struct ioctl_args *)args);
584 
585     case LINUX_SIOCGIFNETMASK:
586 	args->cmd = OSIOCGIFNETMASK;
587 	return ioctl(p, (struct ioctl_args *)args);
588 
589 	/* get hardware address */
590     case LINUX_SIOCGIFHWADDR:
591     {
592 	int			ifn;
593 	struct ifnet		*ifp;
594 	struct ifaddr		*ifa;
595 	struct sockaddr_dl	*sdl;
596 	struct linux_ifreq	*ifr = (struct linux_ifreq *)args->arg;
597 
598 	/*
599 	 * Note that we don't actually respect the name in the ifreq structure, as
600 	 * Linux interface names are all different
601 	 */
602 
603 	for (ifn = 0; ifn < if_index; ifn++) {
604 
605 	    ifp = ifnet_addrs[ifn]->ifa_ifp;	/* pointer to interface */
606 	    if (ifp->if_type == IFT_ETHER) {	/* looks good */
607 		/* walk the address list */
608 		for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = TAILQ_NEXT(ifa, ifa_link)) {
609 		    if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&	/* we have an address structure */
610 			(sdl->sdl_family == AF_LINK) &&			/* it's a link address */
611 			(sdl->sdl_type == IFT_ETHER)) {			/* for an ethernet link */
612 
613 			return(copyout(LLADDR(sdl), (caddr_t)&ifr->ifr_hwaddr.sa_data, LINUX_IFHWADDRLEN));
614 		    }
615 		}
616 	    }
617 	}
618 	return(ENOENT);		/* ??? */
619     }
620 
621     case LINUX_SIOCADDMULTI:
622 	args->cmd = SIOCADDMULTI;
623 	return ioctl(p, (struct ioctl_args *)args);
624 
625     case LINUX_SIOCDELMULTI:
626 	args->cmd = SIOCDELMULTI;
627 	return ioctl(p, (struct ioctl_args *)args);
628 
629     case LINUX_TIOCSETD:
630 	switch (args->arg) {
631 	case LINUX_N_TTY:
632 	    bsd_line = TTYDISC;
633 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
634 	case LINUX_N_SLIP:
635 	    bsd_line = SLIPDISC;
636 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
637 	case LINUX_N_PPP:
638 	    bsd_line = PPPDISC;
639 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
640 	default:
641 	    return EINVAL;
642 	}
643 
644     case LINUX_TIOCGETD:
645 	bsd_line = TTYDISC;
646 	if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p))
647 	    return error;
648 	switch (bsd_line) {
649 	case TTYDISC:
650 	    linux_line = LINUX_N_TTY;
651 	    break;
652 	case SLIPDISC:
653 	    linux_line = LINUX_N_SLIP;
654 	    break;
655 	case PPPDISC:
656 	    linux_line = LINUX_N_PPP;
657 	    break;
658 	default:
659 	    return EINVAL;
660 	}
661 	return copyout(&linux_line, (caddr_t)args->arg,
662 		       sizeof(int));
663 
664     case LINUX_SNDCTL_DSP_GETOPTR :
665 	args->cmd = SNDCTL_DSP_GETOPTR;
666 	return ioctl(p, (struct ioctl_args *)args);
667 
668     case LINUX_SNDCTL_DSP_GETIPTR :
669 	args->cmd = SNDCTL_DSP_GETIPTR;
670 	return ioctl(p, (struct ioctl_args *)args);
671 
672     case LINUX_SNDCTL_DSP_SETTRIGGER:
673 	args->cmd = SNDCTL_DSP_SETTRIGGER;
674 	return ioctl(p, (struct ioctl_args *)args);
675 
676     case LINUX_SNDCTL_DSP_GETCAPS:
677 	args->cmd = SNDCTL_DSP_GETCAPS;
678 	return ioctl(p, (struct ioctl_args *)args);
679 
680     case LINUX_SNDCTL_DSP_RESET:
681 	args->cmd = SNDCTL_DSP_RESET;
682 	return ioctl(p, (struct ioctl_args *)args);
683 
684     case LINUX_SNDCTL_DSP_SYNC:
685 	args->cmd = SNDCTL_DSP_SYNC;
686 	return ioctl(p, (struct ioctl_args *)args);
687 
688     case LINUX_SNDCTL_DSP_SPEED:
689 	args->cmd = SNDCTL_DSP_SPEED;
690 	return ioctl(p, (struct ioctl_args *)args);
691 
692     case LINUX_SNDCTL_DSP_STEREO:
693 	args->cmd = SNDCTL_DSP_STEREO;
694 	return ioctl(p, (struct ioctl_args *)args);
695 
696     case LINUX_SNDCTL_DSP_GETBLKSIZE:
697       /* LINUX_SNDCTL_DSP_SETBLKSIZE */
698 	args->cmd = SNDCTL_DSP_GETBLKSIZE;
699 	return ioctl(p, (struct ioctl_args *)args);
700 
701     case LINUX_SNDCTL_DSP_SETFMT:
702 	args->cmd = SNDCTL_DSP_SETFMT;
703 	return ioctl(p, (struct ioctl_args *)args);
704 
705     case LINUX_SOUND_PCM_WRITE_CHANNELS:
706 	args->cmd = SOUND_PCM_WRITE_CHANNELS;
707 	return ioctl(p, (struct ioctl_args *)args);
708 
709     case LINUX_SOUND_PCM_WRITE_FILTER:
710 	args->cmd = SOUND_PCM_WRITE_FILTER;
711 	return ioctl(p, (struct ioctl_args *)args);
712 
713     case LINUX_SNDCTL_DSP_POST:
714 	args->cmd = SNDCTL_DSP_POST;
715 	return ioctl(p, (struct ioctl_args *)args);
716 
717     case LINUX_SNDCTL_DSP_SUBDIVIDE:
718 	args->cmd = SNDCTL_DSP_SUBDIVIDE;
719 	return ioctl(p, (struct ioctl_args *)args);
720 
721     case LINUX_SNDCTL_DSP_SETFRAGMENT:
722 	args->cmd = SNDCTL_DSP_SETFRAGMENT;
723 	return ioctl(p, (struct ioctl_args *)args);
724 
725     case LINUX_SNDCTL_DSP_GETFMTS:
726 	args->cmd = SNDCTL_DSP_GETFMTS;
727 	return ioctl(p, (struct ioctl_args *)args);
728 
729     case LINUX_SNDCTL_DSP_GETOSPACE:
730 	args->cmd = SNDCTL_DSP_GETOSPACE;
731 	return ioctl(p, (struct ioctl_args *)args);
732 
733     case LINUX_SNDCTL_DSP_GETISPACE:
734 	args->cmd = SNDCTL_DSP_GETISPACE;
735 	return ioctl(p, (struct ioctl_args *)args);
736 
737     case LINUX_SNDCTL_DSP_NONBLOCK:
738 	args->cmd = SNDCTL_DSP_NONBLOCK;
739 	return ioctl(p, (struct ioctl_args *)args);
740 
741     case LINUX_SOUND_MIXER_WRITE_VOLUME:
742 	args->cmd = SOUND_MIXER_WRITE_VOLUME;
743 	return ioctl(p, (struct ioctl_args *)args);
744 
745     case LINUX_SOUND_MIXER_WRITE_BASS:
746 	args->cmd = SOUND_MIXER_WRITE_BASS;
747 	return ioctl(p, (struct ioctl_args *)args);
748 
749     case LINUX_SOUND_MIXER_WRITE_TREBLE:
750 	args->cmd = SOUND_MIXER_WRITE_TREBLE;
751 	return ioctl(p, (struct ioctl_args *)args);
752 
753     case LINUX_SOUND_MIXER_WRITE_SYNTH:
754 	args->cmd = SOUND_MIXER_WRITE_SYNTH;
755 	return ioctl(p, (struct ioctl_args *)args);
756 
757     case LINUX_SOUND_MIXER_WRITE_PCM:
758 	args->cmd = SOUND_MIXER_WRITE_PCM;
759 	return ioctl(p, (struct ioctl_args *)args);
760 
761     case LINUX_SOUND_MIXER_WRITE_SPEAKER:
762 	args->cmd = SOUND_MIXER_WRITE_SPEAKER;
763 	return ioctl(p, (struct ioctl_args *)args);
764 
765     case LINUX_SOUND_MIXER_WRITE_LINE:
766 	args->cmd = SOUND_MIXER_WRITE_LINE;
767 	return ioctl(p, (struct ioctl_args *)args);
768 
769     case LINUX_SOUND_MIXER_WRITE_MIC:
770 	args->cmd = SOUND_MIXER_WRITE_MIC;
771 	return ioctl(p, (struct ioctl_args *)args);
772 
773     case LINUX_SOUND_MIXER_WRITE_CD:
774 	args->cmd = SOUND_MIXER_WRITE_CD;
775 	return ioctl(p, (struct ioctl_args *)args);
776 
777     case LINUX_SOUND_MIXER_WRITE_IMIX:
778 	args->cmd = SOUND_MIXER_WRITE_IMIX;
779 	return ioctl(p, (struct ioctl_args *)args);
780 
781     case LINUX_SOUND_MIXER_WRITE_ALTPCM:
782 	args->cmd = SOUND_MIXER_WRITE_ALTPCM;
783 	return ioctl(p, (struct ioctl_args *)args);
784 
785     case LINUX_SOUND_MIXER_WRITE_RECLEV:
786 	args->cmd = SOUND_MIXER_WRITE_RECLEV;
787 	return ioctl(p, (struct ioctl_args *)args);
788 
789     case LINUX_SOUND_MIXER_WRITE_IGAIN:
790 	args->cmd = SOUND_MIXER_WRITE_IGAIN;
791 	return ioctl(p, (struct ioctl_args *)args);
792 
793     case LINUX_SOUND_MIXER_WRITE_OGAIN:
794 	args->cmd = SOUND_MIXER_WRITE_OGAIN;
795 	return ioctl(p, (struct ioctl_args *)args);
796 
797     case LINUX_SOUND_MIXER_WRITE_LINE1:
798 	args->cmd = SOUND_MIXER_WRITE_LINE1;
799 	return ioctl(p, (struct ioctl_args *)args);
800 
801     case LINUX_SOUND_MIXER_WRITE_LINE2:
802 	args->cmd = SOUND_MIXER_WRITE_LINE2;
803 	return ioctl(p, (struct ioctl_args *)args);
804 
805     case LINUX_SOUND_MIXER_WRITE_LINE3:
806 	args->cmd = SOUND_MIXER_WRITE_LINE3;
807 	return ioctl(p, (struct ioctl_args *)args);
808 
809     case LINUX_SOUND_MIXER_READ_DEVMASK:
810 	args->cmd = SOUND_MIXER_READ_DEVMASK;
811 	return ioctl(p, (struct ioctl_args *)args);
812 
813     case LINUX_TIOCGSERIAL:
814         linux_tiocgserial(fp, (struct linux_serial_struct *)args->arg);
815         return 0;
816 
817     case LINUX_TIOCSSERIAL:
818         linux_tiocsserial(fp, (struct linux_serial_struct *)args->arg);
819 	return 0;
820 
821     case LINUX_TCFLSH:
822       args->cmd = TIOCFLUSH;
823       switch (args->arg) {
824         case LINUX_TCIFLUSH:
825                 args->arg = FREAD;
826                 break;
827         case LINUX_TCOFLUSH:
828                 args->arg = FWRITE;
829                 break;
830         case LINUX_TCIOFLUSH:
831                 args->arg = FREAD | FWRITE;
832                 break;
833         default:
834 	        return EINVAL;
835       }
836       return ioctl(p, (struct ioctl_args *)args);
837 
838    case LINUX_VT_OPENQRY:
839 
840 	args->cmd = VT_OPENQRY;
841 	return  ioctl(p, (struct ioctl_args *)args);
842 
843     case LINUX_VT_GETMODE:
844 
845 	args->cmd = VT_GETMODE;
846 	return  ioctl(p, (struct ioctl_args *)args);
847 
848     case LINUX_VT_SETMODE:
849 
850 	args->cmd = VT_SETMODE;
851 	return  ioctl(p, (struct ioctl_args *)args);
852 
853     case LINUX_VT_GETSTATE:
854 
855 	args->cmd = VT_GETACTIVE;
856 	return  ioctl(p, (struct ioctl_args *)args);
857 
858     case LINUX_VT_ACTIVATE:
859 
860 	args->cmd = VT_ACTIVATE;
861 	return  ioctl(p, (struct ioctl_args *)args);
862 
863     case LINUX_VT_WAITACTIVE:
864 
865 	args->cmd = VT_WAITACTIVE;
866 	return  ioctl(p, (struct ioctl_args *)args);
867 
868     case LINUX_KDGKBMODE:
869 
870 	args->cmd = KDGKBMODE;
871 	return ioctl(p, (struct ioctl_args *)args);
872 
873     case LINUX_KDSKBMODE:
874       {
875         int kbdmode;
876 	switch (args->arg) {
877 	case LINUX_KBD_RAW:
878 	    kbdmode = K_RAW;
879 	    return (*func)(fp, KDSKBMODE, (caddr_t)&kbdmode, p);
880 	case LINUX_KBD_XLATE:
881 	    kbdmode = K_XLATE;
882 	    return (*func)(fp, KDSKBMODE , (caddr_t)&kbdmode, p);
883 	case LINUX_KBD_MEDIUMRAW:
884 	    kbdmode = K_RAW;
885 	    return (*func)(fp, KDSKBMODE , (caddr_t)&kbdmode, p);
886 	default:
887 	    return EINVAL;
888 	}
889       }
890     }
891     uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n",
892 	args->fd, (u_int)((args->cmd & 0xffff00) >> 8),
893 	(int)((args->cmd & 0xffff00) >> 8), (u_int)(args->cmd & 0xff));
894     return EINVAL;
895 }
896