xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision 33b77e2decd50e53798014b70bf7ca3bdc4c0c7e)
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.22 1997/11/17 04:00:32 ahasty 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=%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;
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)
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, int com, caddr_t data, struct proc *p);
459     int bsd_line, linux_line;
460     int error;
461 
462 #ifdef DEBUG
463     printf("Linux-emul(%d): ioctl(%d, %04x, *)\n",
464 	   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_TIOCSETD:
632 	switch (args->arg) {
633 	case LINUX_N_TTY:
634 	    bsd_line = TTYDISC;
635 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
636 	case LINUX_N_SLIP:
637 	    bsd_line = SLIPDISC;
638 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
639 	case LINUX_N_PPP:
640 	    bsd_line = PPPDISC;
641 	    return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p);
642 	default:
643 	    return EINVAL;
644 	}
645 
646     case LINUX_TIOCGETD:
647 	bsd_line = TTYDISC;
648 	if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p))
649 	    return error;
650 	switch (bsd_line) {
651 	case TTYDISC:
652 	    linux_line = LINUX_N_TTY;
653 	    break;
654 	case SLIPDISC:
655 	    linux_line = LINUX_N_SLIP;
656 	    break;
657 	case PPPDISC:
658 	    linux_line = LINUX_N_PPP;
659 	    break;
660 	default:
661 	    return EINVAL;
662 	}
663 	return copyout(&linux_line, (caddr_t)args->arg,
664 		       sizeof(int));
665 
666     case LINUX_SNDCTL_DSP_GETOPTR :
667 	args->cmd = SNDCTL_DSP_GETOPTR;
668 	return ioctl(p, (struct ioctl_args *)args);
669 
670     case LINUX_SNDCTL_DSP_GETIPTR :
671 	args->cmd = SNDCTL_DSP_GETIPTR;
672 	return ioctl(p, (struct ioctl_args *)args);
673 
674     case LINUX_SNDCTL_DSP_SETTRIGGER:
675 	args->cmd = SNDCTL_DSP_SETTRIGGER;
676 	return ioctl(p, (struct ioctl_args *)args);
677 
678     case LINUX_SNDCTL_DSP_GETCAPS:
679 	args->cmd = SNDCTL_DSP_GETCAPS;
680 	return ioctl(p, (struct ioctl_args *)args);
681 
682     case LINUX_SNDCTL_DSP_RESET:
683 	args->cmd = SNDCTL_DSP_RESET;
684 	return ioctl(p, (struct ioctl_args *)args);
685 
686     case LINUX_SNDCTL_DSP_SYNC:
687 	args->cmd = SNDCTL_DSP_SYNC;
688 	return ioctl(p, (struct ioctl_args *)args);
689 
690     case LINUX_SNDCTL_DSP_SPEED:
691 	args->cmd = SNDCTL_DSP_SPEED;
692 	return ioctl(p, (struct ioctl_args *)args);
693 
694     case LINUX_SNDCTL_DSP_STEREO:
695 	args->cmd = SNDCTL_DSP_STEREO;
696 	return ioctl(p, (struct ioctl_args *)args);
697 
698     case LINUX_SNDCTL_DSP_GETBLKSIZE:
699       /* LINUX_SNDCTL_DSP_SETBLKSIZE */
700 	args->cmd = SNDCTL_DSP_GETBLKSIZE;
701 	return ioctl(p, (struct ioctl_args *)args);
702 
703     case LINUX_SNDCTL_DSP_SETFMT:
704 	args->cmd = SNDCTL_DSP_SETFMT;
705 	return ioctl(p, (struct ioctl_args *)args);
706 
707     case LINUX_SOUND_PCM_WRITE_CHANNELS:
708 	args->cmd = SOUND_PCM_WRITE_CHANNELS;
709 	return ioctl(p, (struct ioctl_args *)args);
710 
711     case LINUX_SOUND_PCM_WRITE_FILTER:
712 	args->cmd = SOUND_PCM_WRITE_FILTER;
713 	return ioctl(p, (struct ioctl_args *)args);
714 
715     case LINUX_SNDCTL_DSP_POST:
716 	args->cmd = SNDCTL_DSP_POST;
717 	return ioctl(p, (struct ioctl_args *)args);
718 
719     case LINUX_SNDCTL_DSP_SUBDIVIDE:
720 	args->cmd = SNDCTL_DSP_SUBDIVIDE;
721 	return ioctl(p, (struct ioctl_args *)args);
722 
723     case LINUX_SNDCTL_DSP_SETFRAGMENT:
724 	args->cmd = SNDCTL_DSP_SETFRAGMENT;
725 	return ioctl(p, (struct ioctl_args *)args);
726 
727     case LINUX_SNDCTL_DSP_GETFMTS:
728 	args->cmd = SNDCTL_DSP_GETFMTS;
729 	return ioctl(p, (struct ioctl_args *)args);
730 
731     case LINUX_SNDCTL_DSP_GETOSPACE:
732 	args->cmd = SNDCTL_DSP_GETOSPACE;
733 	return ioctl(p, (struct ioctl_args *)args);
734 
735     case LINUX_SNDCTL_DSP_GETISPACE:
736 	args->cmd = SNDCTL_DSP_GETISPACE;
737 	return ioctl(p, (struct ioctl_args *)args);
738 
739     case LINUX_SNDCTL_DSP_NONBLOCK:
740 	args->cmd = SNDCTL_DSP_NONBLOCK;
741 	return ioctl(p, (struct ioctl_args *)args);
742 
743     case LINUX_SOUND_MIXER_WRITE_VOLUME:
744 	args->cmd = SOUND_MIXER_WRITE_VOLUME;
745 	return ioctl(p, (struct ioctl_args *)args);
746 
747     case LINUX_SOUND_MIXER_WRITE_BASS:
748 	args->cmd = SOUND_MIXER_WRITE_BASS;
749 	return ioctl(p, (struct ioctl_args *)args);
750 
751     case LINUX_SOUND_MIXER_WRITE_TREBLE:
752 	args->cmd = SOUND_MIXER_WRITE_TREBLE;
753 	return ioctl(p, (struct ioctl_args *)args);
754 
755     case LINUX_SOUND_MIXER_WRITE_SYNTH:
756 	args->cmd = SOUND_MIXER_WRITE_SYNTH;
757 	return ioctl(p, (struct ioctl_args *)args);
758 
759     case LINUX_SOUND_MIXER_WRITE_PCM:
760 	args->cmd = SOUND_MIXER_WRITE_PCM;
761 	return ioctl(p, (struct ioctl_args *)args);
762 
763     case LINUX_SOUND_MIXER_WRITE_SPEAKER:
764 	args->cmd = SOUND_MIXER_WRITE_SPEAKER;
765 	return ioctl(p, (struct ioctl_args *)args);
766 
767     case LINUX_SOUND_MIXER_WRITE_LINE:
768 	args->cmd = SOUND_MIXER_WRITE_LINE;
769 	return ioctl(p, (struct ioctl_args *)args);
770 
771     case LINUX_SOUND_MIXER_WRITE_MIC:
772 	args->cmd = SOUND_MIXER_WRITE_MIC;
773 	return ioctl(p, (struct ioctl_args *)args);
774 
775     case LINUX_SOUND_MIXER_WRITE_CD:
776 	args->cmd = SOUND_MIXER_WRITE_CD;
777 	return ioctl(p, (struct ioctl_args *)args);
778 
779     case LINUX_SOUND_MIXER_WRITE_IMIX:
780 	args->cmd = SOUND_MIXER_WRITE_IMIX;
781 	return ioctl(p, (struct ioctl_args *)args);
782 
783     case LINUX_SOUND_MIXER_WRITE_ALTPCM:
784 	args->cmd = SOUND_MIXER_WRITE_ALTPCM;
785 	return ioctl(p, (struct ioctl_args *)args);
786 
787     case LINUX_SOUND_MIXER_WRITE_RECLEV:
788 	args->cmd = SOUND_MIXER_WRITE_RECLEV;
789 	return ioctl(p, (struct ioctl_args *)args);
790 
791     case LINUX_SOUND_MIXER_WRITE_IGAIN:
792 	args->cmd = SOUND_MIXER_WRITE_IGAIN;
793 	return ioctl(p, (struct ioctl_args *)args);
794 
795     case LINUX_SOUND_MIXER_WRITE_OGAIN:
796 	args->cmd = SOUND_MIXER_WRITE_OGAIN;
797 	return ioctl(p, (struct ioctl_args *)args);
798 
799     case LINUX_SOUND_MIXER_WRITE_LINE1:
800 	args->cmd = SOUND_MIXER_WRITE_LINE1;
801 	return ioctl(p, (struct ioctl_args *)args);
802 
803     case LINUX_SOUND_MIXER_WRITE_LINE2:
804 	args->cmd = SOUND_MIXER_WRITE_LINE2;
805 	return ioctl(p, (struct ioctl_args *)args);
806 
807     case LINUX_SOUND_MIXER_WRITE_LINE3:
808 	args->cmd = SOUND_MIXER_WRITE_LINE3;
809 	return ioctl(p, (struct ioctl_args *)args);
810 
811     case LINUX_SOUND_MIXER_READ_DEVMASK:
812 	args->cmd = SOUND_MIXER_READ_DEVMASK;
813 	return ioctl(p, (struct ioctl_args *)args);
814 
815     case LINUX_TIOCGSERIAL:
816         linux_tiocgserial(fp, (struct linux_serial_struct *)args->arg);
817         return 0;
818 
819     case LINUX_TIOCSSERIAL:
820         linux_tiocsserial(fp, (struct linux_serial_struct *)args->arg);
821 	return 0;
822 
823     case LINUX_TCFLSH:
824       args->cmd = TIOCFLUSH;
825       switch (args->arg) {
826         case LINUX_TCIFLUSH:
827                 args->arg = FREAD;
828                 break;
829         case LINUX_TCOFLUSH:
830                 args->arg = FWRITE;
831                 break;
832         case LINUX_TCIOFLUSH:
833                 args->arg = FREAD | FWRITE;
834                 break;
835         default:
836 	        return EINVAL;
837       }
838       return ioctl(p, (struct ioctl_args *)args);
839 
840    case LINUX_VT_OPENQRY:
841 
842 	args->cmd = VT_OPENQRY;
843 	return  ioctl(p, (struct ioctl_args *)args);
844 
845     case LINUX_VT_GETMODE:
846 
847 	args->cmd = VT_GETMODE;
848 	return  ioctl(p, (struct ioctl_args *)args);
849 
850     case LINUX_VT_SETMODE:
851 
852 	args->cmd = VT_SETMODE;
853 	return  ioctl(p, (struct ioctl_args *)args);
854 
855     case LINUX_VT_GETSTATE:
856 
857 	args->cmd = VT_GETACTIVE;
858 	return  ioctl(p, (struct ioctl_args *)args);
859 
860     case LINUX_VT_ACTIVATE:
861 
862 	args->cmd = VT_ACTIVATE;
863 	return  ioctl(p, (struct ioctl_args *)args);
864 
865     case LINUX_VT_WAITACTIVE:
866 
867 	args->cmd = VT_WAITACTIVE;
868 	return  ioctl(p, (struct ioctl_args *)args);
869 
870     case LINUX_KDGKBMODE:
871 
872 	args->cmd = KDGKBMODE;
873 	return ioctl(p, (struct ioctl_args *)args);
874 
875     case LINUX_KDSKBMODE:
876       {
877         int kbdmode;
878 	switch (args->arg) {
879 	case LINUX_KBD_RAW:
880 	    kbdmode = K_RAW;
881 	    return (*func)(fp, KDSKBMODE, (caddr_t)&kbdmode, p);
882 	case LINUX_KBD_XLATE:
883 	    kbdmode = K_XLATE;
884 	    return (*func)(fp, KDSKBMODE , (caddr_t)&kbdmode, p);
885 	case LINUX_KBD_MEDIUMRAW:
886 	    kbdmode = K_RAW;
887 	    return (*func)(fp, KDSKBMODE , (caddr_t)&kbdmode, p);
888 	default:
889 	    return EINVAL;
890 	}
891       }
892     }
893     uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n",
894 	    args->fd, (args->cmd&0xffff00)>>8,
895 	    (args->cmd&0xffff00)>>8, args->cmd&0xff);
896     return EINVAL;
897 }
898