Modify kern/makesyscall.sh to prefix all kernel system call procedures
[dragonfly.git] / sys / emulation / linux / linux_ioctl.c
1 /*
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * Copyright (c) 2004 Simon 'corecode' Schubert
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer
11  *    in this position and unchanged.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software withough specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD: src/sys/compat/linux/linux_ioctl.c,v 1.55.2.11 2003/05/01 20:16:09 anholt Exp $
30  * $DragonFly: src/sys/emulation/linux/linux_ioctl.c,v 1.20 2006/06/05 07:26:09 dillon Exp $
31  */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/cdio.h>
37 #include <sys/consio.h>
38 #include <sys/ctype.h>
39 #include <sys/disklabel.h>
40 #include <sys/fcntl.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/filio.h>
44 #include <sys/ioccom.h>
45 #include <sys/kbio.h>
46 #include <sys/kernel.h>
47 #include <sys/linker_set.h>
48 #include <sys/malloc.h>
49 #include <sys/mapped_ioctl.h>
50 #include <sys/proc.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/soundcard.h>
54 #include <sys/tty.h>
55 #include <sys/uio.h>
56 #include <net/if.h>
57 #include <net/if_dl.h>
58 #include <net/if_types.h>
59 #include <sys/file2.h>
60
61 #include <arch_linux/linux.h>
62 #include <arch_linux/linux_proto.h>
63
64 #include "linux_ioctl.h"
65 #include "linux_mib.h"
66 #include "linux_util.h"
67
68
69 static int
70 linux_ioctl_BLKGETSIZE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
71 {
72         int error;
73         struct disklabel dl;
74
75         error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, cred);
76         if (error)
77                 return (error);
78         bcopy(&(dl.d_secperunit), data, sizeof(dl.d_secperunit));
79         return (0);
80 }
81
82
83 /*
84  * termio related ioctls
85  */
86
87 struct linux_termio {
88         unsigned short c_iflag;
89         unsigned short c_oflag;
90         unsigned short c_cflag;
91         unsigned short c_lflag;
92         unsigned char c_line;
93         unsigned char c_cc[LINUX_NCC];
94 };
95
96 struct linux_termios {
97         unsigned int c_iflag;
98         unsigned int c_oflag;
99         unsigned int c_cflag;
100         unsigned int c_lflag;
101         unsigned char c_line;
102         unsigned char c_cc[LINUX_NCCS];
103 };
104
105 struct linux_winsize {
106         unsigned short ws_row, ws_col;
107         unsigned short ws_xpixel, ws_ypixel;
108 };
109
110 static struct speedtab sptab[] = {
111         { B0, LINUX_B0 }, { B50, LINUX_B50 },
112         { B75, LINUX_B75 }, { B110, LINUX_B110 },
113         { B134, LINUX_B134 }, { B150, LINUX_B150 },
114         { B200, LINUX_B200 }, { B300, LINUX_B300 },
115         { B600, LINUX_B600 }, { B1200, LINUX_B1200 },
116         { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
117         { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
118         { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
119         { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
120         {-1, -1 }
121 };
122
123 struct linux_serial_struct {
124         int     type;
125         int     line;
126         int     port;
127         int     irq;
128         int     flags;
129         int     xmit_fifo_size;
130         int     custom_divisor;
131         int     baud_base;
132         unsigned short close_delay;
133         char    reserved_char[2];
134         int     hub6;
135         unsigned short closing_wait;
136         unsigned short closing_wait2;
137         int     reserved[4];
138 };
139
140 static int
141 linux_to_bsd_speed(int code, struct speedtab *table)
142 {
143         for ( ; table->sp_code != -1; table++)
144                 if (table->sp_code == code)
145                         return (table->sp_speed);
146         return -1;
147 }
148
149 static int
150 bsd_to_linux_speed(int speed, struct speedtab *table)
151 {
152         for ( ; table->sp_speed != -1; table++)
153                 if (table->sp_speed == speed)
154                         return (table->sp_code);
155         return -1;
156 }
157
158 static void
159 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
160 {
161         int i;
162
163 #ifdef DEBUG
164         if (ldebug(ioctl)) {
165                 printf("LINUX: BSD termios structure (input):\n");
166                 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
167                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
168                     bios->c_ispeed, bios->c_ospeed);
169                 printf("c_cc ");
170                 for (i=0; i<NCCS; i++)
171                         printf("%02x ", bios->c_cc[i]);
172                 printf("\n");
173         }
174 #endif
175
176         lios->c_iflag = 0;
177         if (bios->c_iflag & IGNBRK)
178                 lios->c_iflag |= LINUX_IGNBRK;
179         if (bios->c_iflag & BRKINT)
180                 lios->c_iflag |= LINUX_BRKINT;
181         if (bios->c_iflag & IGNPAR)
182                 lios->c_iflag |= LINUX_IGNPAR;
183         if (bios->c_iflag & PARMRK)
184                 lios->c_iflag |= LINUX_PARMRK;
185         if (bios->c_iflag & INPCK)
186                 lios->c_iflag |= LINUX_INPCK;
187         if (bios->c_iflag & ISTRIP)
188                 lios->c_iflag |= LINUX_ISTRIP;
189         if (bios->c_iflag & INLCR)
190                 lios->c_iflag |= LINUX_INLCR;
191         if (bios->c_iflag & IGNCR)
192                 lios->c_iflag |= LINUX_IGNCR;
193         if (bios->c_iflag & ICRNL)
194                 lios->c_iflag |= LINUX_ICRNL;
195         if (bios->c_iflag & IXON)
196                 lios->c_iflag |= LINUX_IXON;
197         if (bios->c_iflag & IXANY)
198                 lios->c_iflag |= LINUX_IXANY;
199         if (bios->c_iflag & IXOFF)
200                 lios->c_iflag |= LINUX_IXOFF;
201         if (bios->c_iflag & IMAXBEL)
202                 lios->c_iflag |= LINUX_IMAXBEL;
203
204         lios->c_oflag = 0;
205         if (bios->c_oflag & OPOST)
206                 lios->c_oflag |= LINUX_OPOST;
207         if (bios->c_oflag & ONLCR)
208                 lios->c_oflag |= LINUX_ONLCR;
209         if (bios->c_oflag & OXTABS)
210                 lios->c_oflag |= LINUX_XTABS;
211
212         lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
213         lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
214         if (bios->c_cflag & CSTOPB)
215                 lios->c_cflag |= LINUX_CSTOPB;
216         if (bios->c_cflag & CREAD)
217                 lios->c_cflag |= LINUX_CREAD;
218         if (bios->c_cflag & PARENB)
219                 lios->c_cflag |= LINUX_PARENB;
220         if (bios->c_cflag & PARODD)
221                 lios->c_cflag |= LINUX_PARODD;
222         if (bios->c_cflag & HUPCL)
223                 lios->c_cflag |= LINUX_HUPCL;
224         if (bios->c_cflag & CLOCAL)
225                 lios->c_cflag |= LINUX_CLOCAL;
226         if (bios->c_cflag & CRTSCTS)
227                 lios->c_cflag |= LINUX_CRTSCTS;
228
229         lios->c_lflag = 0;
230         if (bios->c_lflag & ISIG)
231                 lios->c_lflag |= LINUX_ISIG;
232         if (bios->c_lflag & ICANON)
233                 lios->c_lflag |= LINUX_ICANON;
234         if (bios->c_lflag & ECHO)
235                 lios->c_lflag |= LINUX_ECHO;
236         if (bios->c_lflag & ECHOE)
237                 lios->c_lflag |= LINUX_ECHOE;
238         if (bios->c_lflag & ECHOK)
239                 lios->c_lflag |= LINUX_ECHOK;
240         if (bios->c_lflag & ECHONL)
241                 lios->c_lflag |= LINUX_ECHONL;
242         if (bios->c_lflag & NOFLSH)
243                 lios->c_lflag |= LINUX_NOFLSH;
244         if (bios->c_lflag & TOSTOP)
245                 lios->c_lflag |= LINUX_TOSTOP;
246         if (bios->c_lflag & ECHOCTL)
247                 lios->c_lflag |= LINUX_ECHOCTL;
248         if (bios->c_lflag & ECHOPRT)
249                 lios->c_lflag |= LINUX_ECHOPRT;
250         if (bios->c_lflag & ECHOKE)
251                 lios->c_lflag |= LINUX_ECHOKE;
252         if (bios->c_lflag & FLUSHO)
253                 lios->c_lflag |= LINUX_FLUSHO;
254         if (bios->c_lflag & PENDIN)
255                 lios->c_lflag |= LINUX_PENDIN;
256         if (bios->c_lflag & IEXTEN)
257                 lios->c_lflag |= LINUX_IEXTEN;
258
259         for (i=0; i<LINUX_NCCS; i++)
260                 lios->c_cc[i] = LINUX_POSIX_VDISABLE;
261         lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
262         lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
263         lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
264         lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
265         lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
266         lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
267         lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
268         lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
269         lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
270         lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
271         lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
272         lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
273         lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
274         lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
275         lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
276         lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
277
278         for (i=0; i<LINUX_NCCS; i++) {
279                  if (i != LINUX_VMIN && i != LINUX_VTIME &&
280                     lios->c_cc[i] == _POSIX_VDISABLE)
281                         lios->c_cc[i] = LINUX_POSIX_VDISABLE;
282         }
283         lios->c_line = 0;
284
285 #ifdef DEBUG
286         if (ldebug(ioctl)) {
287                 printf("LINUX: LINUX termios structure (output):\n");
288                 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
289                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
290                     lios->c_lflag, (int)lios->c_line);
291                 printf("c_cc ");
292                 for (i=0; i<LINUX_NCCS; i++) 
293                         printf("%02x ", lios->c_cc[i]);
294                 printf("\n");
295         }
296 #endif
297 }
298
299 static void
300 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
301 {
302         int i;
303
304 #ifdef DEBUG
305         if (ldebug(ioctl)) {
306                 printf("LINUX: LINUX termios structure (input):\n");
307                 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 
308                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
309                     lios->c_lflag, (int)lios->c_line);
310                 printf("c_cc ");
311                 for (i=0; i<LINUX_NCCS; i++)
312                         printf("%02x ", lios->c_cc[i]);
313                 printf("\n");
314         }
315 #endif
316
317         bios->c_iflag = 0;
318         if (lios->c_iflag & LINUX_IGNBRK)
319                 bios->c_iflag |= IGNBRK;
320         if (lios->c_iflag & LINUX_BRKINT)
321                 bios->c_iflag |= BRKINT;
322         if (lios->c_iflag & LINUX_IGNPAR)
323                 bios->c_iflag |= IGNPAR;
324         if (lios->c_iflag & LINUX_PARMRK)
325                 bios->c_iflag |= PARMRK;
326         if (lios->c_iflag & LINUX_INPCK)
327                 bios->c_iflag |= INPCK;
328         if (lios->c_iflag & LINUX_ISTRIP)
329                 bios->c_iflag |= ISTRIP;
330         if (lios->c_iflag & LINUX_INLCR)
331                 bios->c_iflag |= INLCR;
332         if (lios->c_iflag & LINUX_IGNCR)
333                 bios->c_iflag |= IGNCR;
334         if (lios->c_iflag & LINUX_ICRNL)
335                 bios->c_iflag |= ICRNL;
336         if (lios->c_iflag & LINUX_IXON)
337                 bios->c_iflag |= IXON;
338         if (lios->c_iflag & LINUX_IXANY)
339                 bios->c_iflag |= IXANY;
340         if (lios->c_iflag & LINUX_IXOFF)
341                 bios->c_iflag |= IXOFF;
342         if (lios->c_iflag & LINUX_IMAXBEL)
343                 bios->c_iflag |= IMAXBEL;
344
345         bios->c_oflag = 0;
346         if (lios->c_oflag & LINUX_OPOST)
347                 bios->c_oflag |= OPOST;
348         if (lios->c_oflag & LINUX_ONLCR)
349                 bios->c_oflag |= ONLCR;
350         if (lios->c_oflag & LINUX_XTABS)
351                 bios->c_oflag |= OXTABS;
352
353         bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
354         if (lios->c_cflag & LINUX_CSTOPB)
355                 bios->c_cflag |= CSTOPB;
356         if (lios->c_cflag & LINUX_CREAD)
357                 bios->c_cflag |= CREAD;
358         if (lios->c_cflag & LINUX_PARENB)
359                 bios->c_cflag |= PARENB;
360         if (lios->c_cflag & LINUX_PARODD)
361                 bios->c_cflag |= PARODD;
362         if (lios->c_cflag & LINUX_HUPCL)
363                 bios->c_cflag |= HUPCL;
364         if (lios->c_cflag & LINUX_CLOCAL)
365                 bios->c_cflag |= CLOCAL;
366         if (lios->c_cflag & LINUX_CRTSCTS)
367                 bios->c_cflag |= CRTSCTS;
368
369         bios->c_lflag = 0;
370         if (lios->c_lflag & LINUX_ISIG)
371                 bios->c_lflag |= ISIG;
372         if (lios->c_lflag & LINUX_ICANON)
373                 bios->c_lflag |= ICANON;
374         if (lios->c_lflag & LINUX_ECHO)
375                 bios->c_lflag |= ECHO;
376         if (lios->c_lflag & LINUX_ECHOE)
377                 bios->c_lflag |= ECHOE;
378         if (lios->c_lflag & LINUX_ECHOK)
379                 bios->c_lflag |= ECHOK;
380         if (lios->c_lflag & LINUX_ECHONL)
381                 bios->c_lflag |= ECHONL;
382         if (lios->c_lflag & LINUX_NOFLSH)
383                 bios->c_lflag |= NOFLSH;
384         if (lios->c_lflag & LINUX_TOSTOP)
385                 bios->c_lflag |= TOSTOP;
386         if (lios->c_lflag & LINUX_ECHOCTL)
387                 bios->c_lflag |= ECHOCTL;
388         if (lios->c_lflag & LINUX_ECHOPRT)
389                 bios->c_lflag |= ECHOPRT;
390         if (lios->c_lflag & LINUX_ECHOKE)
391                 bios->c_lflag |= ECHOKE;
392         if (lios->c_lflag & LINUX_FLUSHO)
393                 bios->c_lflag |= FLUSHO;
394         if (lios->c_lflag & LINUX_PENDIN)
395                 bios->c_lflag |= PENDIN;
396         if (lios->c_lflag & LINUX_IEXTEN)
397                 bios->c_lflag |= IEXTEN;
398
399         for (i=0; i<NCCS; i++)
400                 bios->c_cc[i] = _POSIX_VDISABLE;
401         bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
402         bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
403         bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
404         bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
405         bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
406         bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
407         bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
408         bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
409         bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
410         bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
411         bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
412         bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
413         bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
414         bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
415         bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
416         bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
417
418         for (i=0; i<NCCS; i++) {
419                  if (i != VMIN && i != VTIME &&
420                     bios->c_cc[i] == LINUX_POSIX_VDISABLE)
421                         bios->c_cc[i] = _POSIX_VDISABLE;
422         }
423
424         bios->c_ispeed = bios->c_ospeed =
425             linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
426
427 #ifdef DEBUG
428         if (ldebug(ioctl)) {
429                 printf("LINUX: BSD termios structure (output):\n");
430                 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
431                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
432                     bios->c_ispeed, bios->c_ospeed);
433                 printf("c_cc ");
434                 for (i=0; i<NCCS; i++) 
435                         printf("%02x ", bios->c_cc[i]);
436                 printf("\n");
437         }
438 #endif
439 }
440
441 static void
442 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
443 {
444         struct linux_termios lios;
445
446         bsd_to_linux_termios(bios, &lios);
447         lio->c_iflag = lios.c_iflag;
448         lio->c_oflag = lios.c_oflag;
449         lio->c_cflag = lios.c_cflag;
450         lio->c_lflag = lios.c_lflag;
451         lio->c_line  = lios.c_line;
452         memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
453 }
454
455 static void
456 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
457 {
458         struct linux_termios lios;
459         int i;
460
461         lios.c_iflag = lio->c_iflag;
462         lios.c_oflag = lio->c_oflag;
463         lios.c_cflag = lio->c_cflag;
464         lios.c_lflag = lio->c_lflag;
465         for (i=LINUX_NCC; i<LINUX_NCCS; i++)
466                 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
467         memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
468         linux_to_bsd_termios(&lios, bios);
469 }
470
471 static int
472 linux_ioctl_TCGETS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
473 {
474         struct termios bios;
475         struct linux_termios lios;
476         int error;
477
478         error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, cred);
479         if (error)
480                 return (error);
481         bsd_to_linux_termios(&bios, &lios);
482         bcopy(&lios, data, sizeof(lios));
483         return (0);
484 }
485
486 static int
487 linux_ioctl_TCSETS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
488 {
489         struct termios bios;
490         struct linux_termios lios;
491
492         bcopy(data, &lios, sizeof(lios));
493         linux_to_bsd_termios(&lios, &bios);
494         return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, cred));
495 }
496
497 static int
498 linux_ioctl_TCSETSW(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
499 {
500         struct termios bios;
501         struct linux_termios lios;
502
503         bcopy(data, &lios, sizeof(lios));
504         linux_to_bsd_termios(&lios, &bios);
505         return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, cred));
506 }
507
508 static int
509 linux_ioctl_TCSETSF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
510 {
511         struct termios bios;
512         struct linux_termios lios;
513
514         bcopy(data, &lios, sizeof(lios));
515         linux_to_bsd_termios(&lios, &bios);
516         return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred));
517 }
518
519 static int
520 linux_ioctl_TCGETA(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
521 {
522         struct termios bios;
523         struct linux_termio lio;
524         int error;
525
526         error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, cred);
527         if (error)
528                 return (error);
529         bsd_to_linux_termio(&bios, &lio);
530         bcopy(&lio, data, sizeof(lio));
531         return (0);
532 }
533
534 static int
535 linux_ioctl_TCSETA(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
536 {
537         struct termios bios;
538         struct linux_termio lio;
539
540         bcopy(data, &lio, sizeof(lio));
541         linux_to_bsd_termio(&lio, &bios);
542         return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, cred));
543 }
544
545 static int
546 linux_ioctl_TCSETAW(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
547 {
548         struct termios bios;
549         struct linux_termio lio;
550
551         bcopy(data, &lio, sizeof(lio));
552         linux_to_bsd_termio(&lio, &bios);
553         return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, cred));
554 }
555
556 static int
557 linux_ioctl_TCSETAF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
558 {
559         struct termios bios;
560         struct linux_termio lio;
561
562         bcopy(data, &lio, sizeof(lio));
563         linux_to_bsd_termio(&lio, &bios);
564         return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, cred));
565 }
566
567 static int
568 linux_ioctl_TCXONC(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
569 {
570         switch ((u_long)data) {
571         case LINUX_TCOOFF:
572                 cmd = TIOCSTOP;
573                 break;
574         case LINUX_TCOON:
575                 cmd = TIOCSTART;
576                 break;
577         case LINUX_TCIOFF:
578         case LINUX_TCION: {
579                 struct termios bios;
580                 int error, c;
581                 
582                 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, cred);
583                 if (error)
584                         return (error);
585                 c = ((u_long)data == LINUX_TCIOFF) ? VSTOP : VSTART;
586                 c = bios.c_cc[c];
587                 if (c != _POSIX_VDISABLE) {
588                         struct uio auio;
589                         struct iovec aiov;
590
591                         aiov.iov_base = (char *)&c;
592                         aiov.iov_len = sizeof(*bios.c_cc);
593                         auio.uio_iov = &aiov;
594                         auio.uio_iovcnt = 1;
595                         auio.uio_offset = -1;
596                         auio.uio_resid = sizeof(*bios.c_cc);
597                         auio.uio_rw = UIO_WRITE;
598                         auio.uio_segflg = UIO_SYSSPACE;
599                         auio.uio_td = curthread;
600
601                         return (fo_write(fp, &auio, fp->f_cred, 0));
602                 }
603
604                 return (0);
605         }
606         default:
607                 return (EINVAL);
608         }
609         return (fo_ioctl(fp, cmd, 0, cred));
610 }
611
612 static int
613 linux_ioctl_TCFLSH(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
614 {
615         switch ((u_long)data) {
616         case LINUX_TCIFLUSH:
617                 *(u_long *)data = FREAD;
618                 break;
619         case LINUX_TCOFLUSH:
620                 *(u_long *)data = FWRITE;
621                 break;
622         case LINUX_TCIOFLUSH:
623                 *(u_long *)data = FREAD | FWRITE;
624                 break;
625         default:
626                 return (EINVAL);
627         }
628         return (fo_ioctl(fp, TIOCFLUSH, data, cred));
629 }
630
631 static int
632 linux_ioctl_TIOCGSERIAL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
633 {
634         struct linux_serial_struct lss;
635
636         lss.type = LINUX_PORT_16550A;
637         lss.flags = 0;
638         lss.close_delay = 0;
639         bcopy(&lss, data, sizeof(lss));
640         return (0);
641 }
642
643 static int
644 linux_ioctl_TIOCSSERIAL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
645 {
646 #if 0
647         struct linux_serial_struct lss;
648
649         bcopy(data, &lss, sizeof(lss));
650         /* XXX - It really helps to have an implementation that
651          * does nothing. NOT!
652          */
653 #endif
654         return (0);
655 }
656
657 static int
658 linux_ioctl_TIOCSETD(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
659 {
660         int line;
661
662         switch ((u_long)data) {
663         case LINUX_N_TTY:
664                 line = TTYDISC;
665                 break;
666         case LINUX_N_SLIP:
667                 line = SLIPDISC;
668                 break;
669         case LINUX_N_PPP:
670                 line = PPPDISC;
671                 break;
672         default:
673                 return (EINVAL);
674         }
675         return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, cred));
676 }
677
678 static int
679 linux_ioctl_TIOCGETD(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
680 {
681         int linux_line, error;
682         int bsd_line = TTYDISC;
683
684         error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, cred);
685         if (error)
686                 return (error);
687         switch (bsd_line) {
688         case TTYDISC:
689                 linux_line = LINUX_N_TTY;
690                 break;
691         case SLIPDISC:
692                 linux_line = LINUX_N_SLIP;
693                 break;
694         case PPPDISC:
695                 linux_line = LINUX_N_PPP;
696                 break;
697         default:
698                 return (EINVAL);
699         }
700         bcopy(&linux_line, data, sizeof(int));
701         return (0);
702 }       
703
704
705 /*
706  * CDROM related ioctls
707  */
708
709 struct linux_cdrom_msf
710 {
711         u_char  cdmsf_min0;
712         u_char  cdmsf_sec0;
713         u_char  cdmsf_frame0;
714         u_char  cdmsf_min1;
715         u_char  cdmsf_sec1;
716         u_char  cdmsf_frame1;
717 };
718
719 struct linux_cdrom_tochdr
720 {
721         u_char  cdth_trk0;
722         u_char  cdth_trk1;
723 };
724
725 union linux_cdrom_addr
726 {
727         struct {
728                 u_char  minute;
729                 u_char  second;
730                 u_char  frame;
731         } msf;
732         int     lba;
733 };
734
735 struct linux_cdrom_tocentry
736 {
737         u_char  cdte_track;     
738         u_char  cdte_adr:4;
739         u_char  cdte_ctrl:4;
740         u_char  cdte_format;    
741         union linux_cdrom_addr cdte_addr;
742         u_char  cdte_datamode;  
743 };
744
745 struct linux_cdrom_subchnl
746 {
747         u_char  cdsc_format;
748         u_char  cdsc_audiostatus;
749         u_char  cdsc_adr:4;
750         u_char  cdsc_ctrl:4;
751         u_char  cdsc_trk;
752         u_char  cdsc_ind;
753         union linux_cdrom_addr cdsc_absaddr;
754         union linux_cdrom_addr cdsc_reladdr;
755 };
756
757 static void
758 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
759 {
760         if (af == CD_LBA_FORMAT)
761                 lp->lba = bp->lba;
762         else {
763                 lp->msf.minute = bp->msf.minute;
764                 lp->msf.second = bp->msf.second;
765                 lp->msf.frame = bp->msf.frame;
766         }
767 }
768
769 static void
770 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
771 {
772         if (format == LINUX_CDROM_MSF) {
773                 addr->msf.frame = lba % 75;
774                 lba /= 75;
775                 lba += 2;
776                 addr->msf.second = lba % 60;
777                 addr->msf.minute = lba / 60;
778         } else
779                 addr->lba = lba;
780 }
781
782 static int
783 linux_ioctl_CDROMREADTOCHDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
784 {
785         struct ioc_toc_header th;
786         struct linux_cdrom_tochdr lth;
787         int error;
788
789         error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, cred);
790         if (error)
791                 return (error);
792         lth.cdth_trk0 = th.starting_track;
793         lth.cdth_trk1 = th.ending_track;
794         bcopy(&lth, data, sizeof(lth));
795         return (0);
796 }
797
798 static int
799 linux_ioctl_CDROMREADTOCENTRY(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
800 {
801         struct linux_cdrom_tocentry *ltep = (struct linux_cdrom_tocentry *)data;
802         struct ioc_read_toc_single_entry irtse;
803         int error;
804
805         irtse.address_format = ltep->cdte_format;
806         irtse.track = ltep->cdte_track;
807         error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, cred);
808         if (error)
809                 return (error);
810
811         ltep->cdte_ctrl = irtse.entry.control;
812         ltep->cdte_adr = irtse.entry.addr_type;
813         bsd_to_linux_msf_lba(irtse.address_format, &irtse.entry.addr,
814                              &ltep->cdte_addr);
815         return (0);
816 }       
817
818 static int
819 linux_ioctl_CDROMSUBCHNL(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
820 {
821         struct linux_cdrom_subchnl *sc = (struct linux_cdrom_subchnl *)data;
822         struct ioc_read_subchannel bsdsc;
823         struct cd_sub_channel_info *bsdinfo;
824         int error;
825         caddr_t sg = stackgap_init();
826
827         bsdinfo = stackgap_alloc(&sg, sizeof(struct cd_sub_channel_info));
828         bsdsc.address_format = CD_LBA_FORMAT;
829         bsdsc.data_format = CD_CURRENT_POSITION;
830         bsdsc.track = 0;
831         bsdsc.data_len = sizeof(struct cd_sub_channel_info);
832         bsdsc.data = bsdinfo;
833         error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, cred);
834         if (error)
835                 return (error);
836         sc->cdsc_audiostatus = bsdinfo->header.audio_status;
837         sc->cdsc_adr = bsdinfo->what.position.addr_type;
838         sc->cdsc_ctrl = bsdinfo->what.position.control;
839         sc->cdsc_trk = bsdinfo->what.position.track_number;
840         sc->cdsc_ind = bsdinfo->what.position.index_number;
841         set_linux_cdrom_addr(&sc->cdsc_absaddr, sc->cdsc_format, bsdinfo->what.position.absaddr.lba);
842         set_linux_cdrom_addr(&sc->cdsc_reladdr, sc->cdsc_format, bsdinfo->what.position.reladdr.lba);
843         return (0);
844 }
845
846
847 /*
848  * Sound related ioctls
849  */
850
851 static int
852 linux_ioctl_OSS_GETVERSION(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
853 {
854         int version = linux_get_oss_version(curthread);
855
856         bcopy(&version, data, sizeof(int));
857         return (0);
858 }
859
860
861 /*
862  * Console related ioctls
863  */
864
865 #define ISSIGVALID(sig)         ((sig) > 0 && (sig) < NSIG)
866
867 static int
868 linux_ioctl_KDSKBMODE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
869 {
870         int kbdmode;
871
872         switch ((u_long)data) {
873         case LINUX_KBD_RAW:
874                 kbdmode = K_RAW;
875                 break;
876         case LINUX_KBD_XLATE:
877                 kbdmode = K_XLATE;
878                 break;
879         case LINUX_KBD_MEDIUMRAW:
880                 kbdmode = K_RAW;
881                 break;
882         default:
883                 return (EINVAL);
884         }
885         return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, cred));
886 }
887
888 static int
889 linux_ioctl_VT_SETMODE(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
890 {
891         struct vt_mode *mode = (struct vt_mode *)data;
892
893         if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
894                 mode->frsig = mode->acqsig;
895         return (fo_ioctl(fp, VT_SETMODE, data, cred));
896 }
897
898
899 /*
900  * Socket related ioctls
901  */
902
903 /*
904  * Criteria for interface name translation
905  */
906 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
907
908 /*
909  * Interface function used by linprocfs (at the time of writing). It's not
910  * used by the Linuxulator itself.
911  */
912 int
913 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
914 {
915         struct ifnet *ifscan;
916         int ethno;
917
918         /* Short-circuit non ethernet interfaces */
919         if (!IFP_IS_ETH(ifp))
920                 return (strlcpy(buffer, ifp->if_xname, buflen));
921
922         /* Determine the (relative) unit number for ethernet interfaces */
923         ethno = 0;
924         TAILQ_FOREACH(ifscan, &ifnet, if_link) {
925                 if (ifscan == ifp)
926                         return (snprintf(buffer, buflen, "eth%d", ethno));
927                 if (IFP_IS_ETH(ifscan))
928                         ethno++;
929         }
930
931         return (0);
932 }
933
934 /*
935  * Translate a Linux interface name to a FreeBSD interface name,
936  * and return the associated ifnet structure
937  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
938  * can point to the same buffer.
939  */
940
941 static struct ifnet *
942 ifname_linux_to_bsd(const char *lxname, char *bsdname)
943 {
944         struct ifnet *ifp;
945         int len, unit;
946         char *ep;
947         int is_eth, index;
948
949         for (len = 0; len < LINUX_IFNAMSIZ; ++len)
950                 if (!isalpha(lxname[len]))
951                         break;
952         if (len == 0 || len == LINUX_IFNAMSIZ)
953                 return (NULL);
954         unit = (int)strtoul(lxname + len, &ep, 10);
955         if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
956                 return (NULL);
957         index = 0;
958         is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
959         TAILQ_FOREACH(ifp, &ifnet, if_link) {
960                 /*
961                  * Allow Linux programs to use FreeBSD names. Don't presume
962                  * we never have an interface named "eth", so don't make
963                  * the test optional based on is_eth.
964                  */
965                 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
966                         break;
967                 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
968                         break;
969         }
970         if (ifp != NULL)
971                 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
972         return (ifp);
973 }
974
975 static int
976 linux_ioctl_SIOCGIFCONF(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
977 {
978         struct ifconf *ifc = (struct ifconf *)data;
979         struct l_ifreq ifr;
980         struct ifnet *ifp;
981         struct ifaddr *ifa;
982         struct iovec iov;
983         struct uio uio;
984         int error, ethno;
985
986         /* much easier to use uiomove than keep track ourselves */
987         iov.iov_base = ifc->ifc_buf;
988         iov.iov_len = ifc->ifc_len;
989         uio.uio_iov = &iov;
990         uio.uio_iovcnt = 1;
991         uio.uio_offset = 0;
992         uio.uio_resid = ifc->ifc_len;
993         uio.uio_segflg = UIO_USERSPACE;
994         uio.uio_rw = UIO_READ;
995         uio.uio_td = curthread;
996
997         /* Keep track of eth interfaces */
998         ethno = 0;
999
1000         /* Return all AF_INET addresses of all interfaces */
1001         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1002                 if (uio.uio_resid <= 0)
1003                         break;
1004
1005                 bzero(&ifr, sizeof ifr);
1006                 if (IFP_IS_ETH(ifp))
1007                         snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
1008                             ethno++);
1009                 else
1010                         strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
1011
1012                 /* Walk the address list */
1013                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1014                         struct sockaddr *sa = ifa->ifa_addr;
1015
1016                         if (uio.uio_resid <= 0)
1017                                 break;
1018
1019                         if (sa->sa_family == AF_INET) {
1020                                 ifr.ifr_addr.sa_family = LINUX_AF_INET;
1021                                 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
1022                                     sizeof(ifr.ifr_addr.sa_data));
1023
1024                                 error = uiomove((caddr_t)&ifr, sizeof ifr,
1025                                     &uio);
1026                                 if (error != 0)
1027                                         return (error);
1028                         }
1029                 }
1030         }
1031
1032         ifc->ifc_len -= uio.uio_resid;
1033
1034         return (0);
1035 }
1036
1037 static int
1038 linux_ioctl_SIOCGIFFLAGS(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1039 {
1040         struct l_ifreq *ifr = (struct l_ifreq *)data;
1041         struct ifnet *ifp;
1042         char ifname[IFNAMSIZ];
1043         l_short flags;
1044
1045         if (fp->f_type != DTYPE_SOCKET) {
1046                 /* XXX: I doubt this is correct because
1047                  *      we don't translate the ifname and
1048                  *      use l_ifreq instead of ifreq
1049                  */
1050                 return (fo_ioctl(fp, SIOCGIFFLAGS, data, cred));
1051         }
1052
1053         ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
1054         flags = ifp->if_flags;
1055         /* these flags have no Linux equivalent */
1056         flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1057             IFF_LINK0|IFF_LINK1|IFF_LINK2);
1058         /* Linux' multicast flag is in a different bit */
1059         if (flags & IFF_MULTICAST) {
1060                 flags &= ~IFF_MULTICAST;
1061                 flags |= 0x1000;
1062         }
1063
1064         ifr->ifr_flags = flags;
1065         return (0);
1066 }
1067
1068 #define ARPHRD_ETHER    1
1069 #define ARPHRD_LOOPBACK 772
1070
1071 static int
1072 linux_ioctl_SIOGIFHWADDR(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1073 {
1074         struct l_ifreq *ifr = (struct l_ifreq *)data;
1075         struct ifnet *ifp;
1076         char ifname[IFNAMSIZ];
1077         struct ifaddr *ifa;
1078         struct sockaddr_dl *sdl;
1079         struct l_sockaddr lsa;
1080
1081         ifp = ifname_linux_to_bsd(ifr->ifr_name, ifname);
1082         if (ifp->if_type == IFT_LOOP) {
1083                 bzero(&ifr->ifr_hwaddr, sizeof lsa);
1084                 ifr->ifr_hwaddr.sa_family = ARPHRD_LOOPBACK;
1085                 return (0);
1086         }
1087         
1088         if (ifp->if_type != IFT_ETHER)
1089                 return (ENOENT);
1090
1091         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1092                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1093                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1094                     (sdl->sdl_type == IFT_ETHER)) {
1095                         bzero(&ifr->ifr_hwaddr, sizeof lsa);
1096                         ifr->ifr_hwaddr.sa_family = ARPHRD_ETHER;
1097                         bcopy(LLADDR(sdl), ifr->ifr_hwaddr.sa_data, LINUX_IFHWADDRLEN);
1098                         return (0);
1099                 }
1100         }
1101         
1102         return (ENOENT);
1103 }
1104
1105 static int
1106 linux_ioctl_map_ifname(struct file *fp, u_long cmd, u_long ocmd, caddr_t data, struct ucred *cred)
1107 {
1108         struct ifnet *ifp;
1109         int error;
1110         char *oifname = (char *)data;
1111         char lifname[LINUX_IFNAMSIZ];
1112
1113         KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1114             ("%s(): LINUX_IFNAMSIZ != IFNAMSIZ", __func__));
1115         
1116         if (fp->f_type != DTYPE_SOCKET) {
1117                 /*
1118                  *  XXX: I doubt this is correct because
1119                  *       we don't map the ifname
1120                  */
1121                 /* not a socket - probably a tap / vmnet device */
1122                 if (ocmd == LINUX_SIOCGIFADDR || ocmd == LINUX_SIOCSIFADDR) {
1123                         cmd = (ocmd == LINUX_SIOCGIFADDR) ? SIOCGIFADDR : SIOCSIFADDR;
1124                         return (fo_ioctl(fp, cmd, data, cred));
1125                 } else
1126                         return (ENOIOCTL);
1127         }
1128
1129         /* Save the original ifname */
1130         bcopy(oifname, lifname, LINUX_IFNAMSIZ);
1131 #ifdef DEBUG
1132         printf("%s(): ioctl %d on %.*s\n", __func__,
1133                 (int)(cmd & 0xffff), LINUX_IFNAMSIZ, lifname);
1134 #endif
1135         /* Replace linux ifname with bsd ifname */
1136         ifp = ifname_linux_to_bsd(lifname, oifname);
1137         if (ifp == NULL) {
1138                 error = EINVAL;
1139                 goto clean_ifname;
1140         }
1141
1142 #ifdef DEBUG
1143         printf("%s(): %s translated to %s\n", __func__,
1144                 lifname, oifname);
1145 #endif
1146
1147         error = fo_ioctl(fp, cmd, data, cred);
1148
1149 clean_ifname:
1150         bcopy(lifname, oifname, LINUX_IFNAMSIZ);
1151         return (error);
1152 }
1153
1154
1155 /*
1156  * generic linux -> BSD syscall direction mapper
1157  */
1158 u_long
1159 linux_gen_dirmap(u_long lstart, u_long lend, u_long bstart, u_long bend, u_long cmd, u_long ocmd)
1160 {
1161         static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1162
1163         return ((cmd & ~IOC_DIRMASK) | dirbits[ocmd >> 30]);
1164 }
1165
1166
1167 static struct ioctl_map_range linux_ioctl_map_entries[] = {
1168         /* disk ioctl */
1169         MAPPED_IOCTL_IOR(LINUX_BLKGETSIZE, linux_ioctl_BLKGETSIZE, uint32_t),
1170         /* termio ioctl */
1171         MAPPED_IOCTL_IOR(LINUX_TCGETS, linux_ioctl_TCGETS, struct linux_termios),
1172         MAPPED_IOCTL_IOW(LINUX_TCSETS, linux_ioctl_TCSETS, struct linux_termios),
1173         MAPPED_IOCTL_IOW(LINUX_TCSETSW, linux_ioctl_TCSETSW, struct linux_termios),
1174         MAPPED_IOCTL_IOW(LINUX_TCSETSF, linux_ioctl_TCSETSF, struct linux_termios),
1175         MAPPED_IOCTL_IOR(LINUX_TCGETA, linux_ioctl_TCGETA, struct linux_termio),
1176         MAPPED_IOCTL_IOW(LINUX_TCSETA, linux_ioctl_TCSETA, struct linux_termio),
1177         MAPPED_IOCTL_IOW(LINUX_TCSETAW, linux_ioctl_TCSETAW, struct linux_termio),
1178         MAPPED_IOCTL_IOW(LINUX_TCSETAF, linux_ioctl_TCSETAF, struct linux_termio),
1179         MAPPED_IOCTL_IO(LINUX_TCXONC, linux_ioctl_TCXONC),
1180         MAPPED_IOCTL_IO(LINUX_TCFLSH, linux_ioctl_TCFLSH),
1181         MAPPED_IOCTL_MAP(LINUX_TIOCEXCL, TIOCEXCL),
1182         MAPPED_IOCTL_MAP(LINUX_TIOCNXCL, TIOCNXCL),
1183         MAPPED_IOCTL_MAP(LINUX_TIOCGPGRP, TIOCGPGRP),
1184         MAPPED_IOCTL_MAP(LINUX_TIOCSPGRP, TIOCSPGRP),
1185         MAPPED_IOCTL_MAP(LINUX_TIOCGWINSZ, TIOCGWINSZ),
1186         MAPPED_IOCTL_MAP(LINUX_TIOCSWINSZ, TIOCSWINSZ),
1187         MAPPED_IOCTL_MAP(LINUX_TIOCMGET, TIOCMGET),
1188         MAPPED_IOCTL_MAP(LINUX_TIOCMBIS, TIOCMBIS),
1189         MAPPED_IOCTL_MAP(LINUX_TIOCMBIC, TIOCMBIC),
1190         MAPPED_IOCTL_MAP(LINUX_TIOCMSET, TIOCMSET),
1191         MAPPED_IOCTL_MAP(LINUX_FIONREAD, FIONREAD),
1192         MAPPED_IOCTL_MAP(LINUX_TIOCCONS, TIOCCONS),
1193         MAPPED_IOCTL_IOR(LINUX_TIOCGSERIAL, linux_ioctl_TIOCGSERIAL, struct linux_serial_struct),
1194         MAPPED_IOCTL_IOW(LINUX_TIOCSSERIAL, linux_ioctl_TIOCSSERIAL, struct linux_serial_struct),
1195         MAPPED_IOCTL_MAP(LINUX_FIONBIO, FIONBIO),
1196         MAPPED_IOCTL_MAP(LINUX_TIOCNOTTY, TIOCNOTTY),
1197         MAPPED_IOCTL_IO(LINUX_TIOCSETD, linux_ioctl_TIOCSETD),
1198         MAPPED_IOCTL_IOR(LINUX_TIOCGETD, linux_ioctl_TIOCGETD, int),
1199         MAPPED_IOCTL_MAP(LINUX_FIONCLEX, FIONCLEX),
1200         MAPPED_IOCTL_MAP(LINUX_FIOCLEX, FIOCLEX),
1201         MAPPED_IOCTL_MAP(LINUX_FIOASYNC, FIOASYNC),
1202         /* cdrom ioctl */
1203         MAPPED_IOCTL_MAP(LINUX_CDROMPAUSE, CDIOCPAUSE),
1204         MAPPED_IOCTL_MAP(LINUX_CDROMRESUME, CDIOCRESUME),
1205         MAPPED_IOCTL_MAP(LINUX_CDROMPLAYMSF, CDIOCPLAYMSF),
1206         MAPPED_IOCTL_MAP(LINUX_CDROMPLAYTRKIND, CDIOCPLAYTRACKS),
1207         MAPPED_IOCTL_IOR(LINUX_CDROMREADTOCHDR, linux_ioctl_CDROMREADTOCHDR, struct linux_cdrom_tochdr),
1208         MAPPED_IOCTL_IOWR(LINUX_CDROMREADTOCENTRY, linux_ioctl_CDROMREADTOCENTRY, struct linux_cdrom_tocentry),
1209         MAPPED_IOCTL_MAP(LINUX_CDROMSTOP, CDIOCSTOP),
1210         MAPPED_IOCTL_MAP(LINUX_CDROMSTART, CDIOCSTART),
1211         MAPPED_IOCTL_MAP(LINUX_CDROMEJECT, CDIOCEJECT),
1212         MAPPED_IOCTL_IOWR(LINUX_CDROMSUBCHNL, linux_ioctl_CDROMSUBCHNL, struct linux_cdrom_subchnl),
1213         MAPPED_IOCTL_MAP(LINUX_CDROMRESET, CDIOCRESET),
1214         /* sound ioctl */
1215         MAPPED_IOCTL_MAPRANGE(LINUX_SOUND_MIXER_WRITE_MIN, LINUX_SOUND_MIXER_WRITE_MAX,
1216                               LINUX_SOUND_MIXER_WRITE_MIN, LINUX_SOUND_MIXER_WRITE_MAX,
1217                               NULL, linux_gen_dirmap),
1218         MAPPED_IOCTL_IOR(LINUX_OSS_GETVERSION, linux_ioctl_OSS_GETVERSION, int),
1219         MAPPED_IOCTL_MAP(LINUX_SOUND_MIXER_READ_DEVMASK, SOUND_MIXER_READ_DEVMASK),
1220         MAPPED_IOCTL_MAPRANGE(LINUX_SNDCTL_DSP_MIN, LINUX_SNDCTL_DSP_MAX, LINUX_SNDCTL_DSP_MIN,
1221                               LINUX_SNDCTL_DSP_MAX, NULL, linux_gen_dirmap),
1222         MAPPED_IOCTL_MAPRANGE(LINUX_SNDCTL_SEQ_MIN, LINUX_SNDCTL_SEQ_MAX, LINUX_SNDCTL_SEQ_MIN,
1223                               LINUX_SNDCTL_SEQ_MAX, NULL, linux_gen_dirmap),
1224         /* console ioctl */
1225         MAPPED_IOCTL_MAP(LINUX_KIOCSOUND, KIOCSOUND),
1226         MAPPED_IOCTL_MAP(LINUX_KDMKTONE, KDMKTONE),
1227         MAPPED_IOCTL_MAP(LINUX_KDGETLED, KDGETLED),
1228         MAPPED_IOCTL_MAP(LINUX_KDSETLED, KDSETLED),
1229         MAPPED_IOCTL_MAP(LINUX_KDSETMODE, KDSETMODE),
1230         MAPPED_IOCTL_MAP(LINUX_KDGETMODE, KDGETMODE),
1231         MAPPED_IOCTL_MAP(LINUX_KDGKBMODE, KDGKBMODE),
1232         MAPPED_IOCTL_IOW(LINUX_KDSKBMODE, linux_ioctl_KDSKBMODE, int),
1233         MAPPED_IOCTL_MAP(LINUX_VT_OPENQRY, VT_OPENQRY),
1234         MAPPED_IOCTL_MAP(LINUX_VT_GETMODE, VT_GETMODE),
1235         MAPPED_IOCTL_IOW(LINUX_VT_SETMODE, linux_ioctl_VT_SETMODE, struct vt_mode),
1236         MAPPED_IOCTL_MAP(LINUX_VT_GETSTATE, VT_GETACTIVE),
1237         MAPPED_IOCTL_MAP(LINUX_VT_RELDISP, VT_RELDISP),
1238         MAPPED_IOCTL_MAP(LINUX_VT_ACTIVATE, VT_ACTIVATE),
1239         MAPPED_IOCTL_MAP(LINUX_VT_WAITACTIVE, VT_WAITACTIVE),
1240         /* socket ioctl */
1241         MAPPED_IOCTL_MAP(LINUX_FIOSETOWN, FIOSETOWN),
1242         MAPPED_IOCTL_MAP(LINUX_SIOCSPGRP, SIOCSPGRP),
1243         MAPPED_IOCTL_MAP(LINUX_FIOGETOWN, FIOGETOWN),
1244         MAPPED_IOCTL_MAP(LINUX_SIOCGPGRP, SIOCGPGRP),
1245         MAPPED_IOCTL_MAP(LINUX_SIOCATMARK, SIOCATMARK),
1246         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFCONF, linux_ioctl_SIOCGIFCONF, struct ifconf),
1247         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFFLAGS, linux_ioctl_SIOCGIFFLAGS, struct l_ifreq),
1248         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFADDR, OSIOCGIFADDR, linux_ioctl_map_ifname),
1249         MAPPED_IOCTL_MAPF(LINUX_SIOCSIFADDR, SIOCSIFADDR, linux_ioctl_map_ifname),
1250         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFDSTADDR, OSIOCGIFDSTADDR, linux_ioctl_map_ifname),
1251         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFBRDADDR, OSIOCGIFBRDADDR, linux_ioctl_map_ifname),
1252         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFNETMASK, OSIOCGIFNETMASK, linux_ioctl_map_ifname),
1253         /*MAPPED_IOCTL_IOx(LINUX_SIOCSIFNETMASK, x, x),*/
1254         MAPPED_IOCTL_MAPF(LINUX_SIOCGIFMTU, SIOCGIFMTU, linux_ioctl_map_ifname),
1255         MAPPED_IOCTL_MAPF(LINUX_SIOCSIFMTU, SIOCSIFMTU, linux_ioctl_map_ifname),
1256         MAPPED_IOCTL_IOWR(LINUX_SIOCGIFHWADDR, linux_ioctl_SIOGIFHWADDR, struct l_ifreq),
1257         MAPPED_IOCTL_MAP(LINUX_SIOCADDMULTI, SIOCADDMULTI),
1258         MAPPED_IOCTL_MAP(LINUX_SIOCDELMULTI, SIOCDELMULTI),
1259         /*
1260          * XXX This is slightly bogus, but these ioctls are currently
1261          * XXX only used by the aironet (if_an) network driver.
1262          */
1263         MAPPED_IOCTL_MAPF(LINUX_SIOCDEVPRIVATE, SIOCGPRIVATE_0, linux_ioctl_map_ifname),
1264         MAPPED_IOCTL_MAPF(LINUX_SIOCDEVPRIVATE+1, SIOCGPRIVATE_1, linux_ioctl_map_ifname),
1265         MAPPED_IOCTL_MAPF(0, 0, NULL)
1266         };
1267
1268 struct ioctl_map linux_ioctl_map = {
1269         0xffff,         /* mask */
1270         "linux",        /* subsys */
1271         LIST_HEAD_INITIALIZER(mapping)
1272         };
1273
1274 static struct ioctl_map_handler linux_ioctl_base_handler = {
1275         &linux_ioctl_map,
1276         "base",
1277         linux_ioctl_map_entries
1278         };
1279
1280 /*
1281  * main ioctl syscall function
1282  */
1283
1284 int
1285 sys_linux_ioctl(struct linux_ioctl_args *args)
1286 {
1287 #ifdef DEBUG
1288         if (ldebug(ioctl))
1289                 printf(ARGS(ioctl, "%d, %04x, *"), args->fd, args->cmd);
1290 #endif
1291
1292         return (mapped_ioctl(args->fd, args->cmd, (caddr_t)args->arg, &linux_ioctl_map));
1293 }
1294
1295 SYSINIT  (linux_ioctl_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
1296           mapped_ioctl_register_handler, &linux_ioctl_base_handler);
1297 SYSUNINIT(linux_ioctl_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
1298           mapped_ioctl_unregister_handler, &linux_ioctl_base_handler);