Initial import from FreeBSD RELENG_4:
[games.git] / sys / emulation / linux / linux_ioctl.c
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  * $FreeBSD: src/sys/compat/linux/linux_ioctl.c,v 1.55.2.11 2003/05/01 20:16:09 anholt Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/cdio.h>
35 #include <sys/consio.h>
36 #include <sys/ctype.h>
37 #include <sys/disklabel.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/filedesc.h>
41 #include <sys/filio.h>
42 #include <sys/kbio.h>
43 #include <sys/linker_set.h>
44 #include <sys/malloc.h>
45 #include <sys/proc.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/soundcard.h>
49 #include <sys/tty.h>
50 #include <sys/uio.h>
51 #include <net/if.h>
52 #include <net/if_dl.h>
53 #include <net/if_types.h>
54
55 #include <machine/../linux/linux.h>
56 #include <machine/../linux/linux_proto.h>
57
58 #include <compat/linux/linux_ioctl.h>
59 #include <compat/linux/linux_mib.h>
60 #include <compat/linux/linux_util.h>
61
62 static linux_ioctl_function_t linux_ioctl_cdrom;
63 static linux_ioctl_function_t linux_ioctl_console;
64 static linux_ioctl_function_t linux_ioctl_disk;
65 static linux_ioctl_function_t linux_ioctl_socket;
66 static linux_ioctl_function_t linux_ioctl_sound;
67 static linux_ioctl_function_t linux_ioctl_termio;
68 static linux_ioctl_function_t linux_ioctl_private;
69 static linux_ioctl_function_t linux_ioctl_drm;
70 static linux_ioctl_function_t linux_ioctl_special;
71
72 static struct linux_ioctl_handler cdrom_handler =
73 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
74 static struct linux_ioctl_handler console_handler =
75 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
76 static struct linux_ioctl_handler disk_handler =
77 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
78 static struct linux_ioctl_handler socket_handler =
79 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
80 static struct linux_ioctl_handler sound_handler =
81 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
82 static struct linux_ioctl_handler termio_handler =
83 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
84 static struct linux_ioctl_handler private_handler =
85 { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
86 static struct linux_ioctl_handler drm_handler =
87 { linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX };
88
89 DATA_SET(linux_ioctl_handler_set, cdrom_handler);
90 DATA_SET(linux_ioctl_handler_set, console_handler);
91 DATA_SET(linux_ioctl_handler_set, disk_handler);
92 DATA_SET(linux_ioctl_handler_set, socket_handler);
93 DATA_SET(linux_ioctl_handler_set, sound_handler);
94 DATA_SET(linux_ioctl_handler_set, termio_handler);
95 DATA_SET(linux_ioctl_handler_set, private_handler);
96 DATA_SET(linux_ioctl_handler_set, drm_handler);
97
98 struct handler_element 
99 {
100         TAILQ_ENTRY(handler_element) list;
101         int     (*func)(struct proc *, struct linux_ioctl_args *);
102         int     low, high, span;
103 };
104
105 static TAILQ_HEAD(, handler_element) handlers =
106         TAILQ_HEAD_INITIALIZER(handlers);
107
108 static int
109 linux_ioctl_disk(struct proc *p, struct linux_ioctl_args *args)
110 {
111         struct file *fp = p->p_fd->fd_ofiles[args->fd];
112         int error;
113         struct disklabel dl;
114
115         switch (args->cmd & 0xffff) {
116         case LINUX_BLKGETSIZE:
117                 error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, p);
118                 if (error)
119                         return (error);
120                 return (copyout(&(dl.d_secperunit), (caddr_t)args->arg,
121                      sizeof(dl.d_secperunit)));
122                 break;
123         }
124         return (ENOIOCTL);
125 }
126
127 /*
128  * termio related ioctls
129  */
130
131 struct linux_termio {
132         unsigned short c_iflag;
133         unsigned short c_oflag;
134         unsigned short c_cflag;
135         unsigned short c_lflag;
136         unsigned char c_line;
137         unsigned char c_cc[LINUX_NCC];
138 };
139
140 struct linux_termios {
141         unsigned int c_iflag;
142         unsigned int c_oflag;
143         unsigned int c_cflag;
144         unsigned int c_lflag;
145 #ifdef __alpha__
146         unsigned char c_cc[LINUX_NCCS];
147         unsigned char c_line;
148         unsigned int  c_ispeed;
149         unsigned int  c_ospeed;
150 #else
151         unsigned char c_line;
152         unsigned char c_cc[LINUX_NCCS];
153 #endif
154 };
155
156 struct linux_winsize {
157         unsigned short ws_row, ws_col;
158         unsigned short ws_xpixel, ws_ypixel;
159 };
160
161 static struct speedtab sptab[] = {
162         { B0, LINUX_B0 }, { B50, LINUX_B50 },
163         { B75, LINUX_B75 }, { B110, LINUX_B110 },
164         { B134, LINUX_B134 }, { B150, LINUX_B150 },
165         { B200, LINUX_B200 }, { B300, LINUX_B300 },
166         { B600, LINUX_B600 }, { B1200, LINUX_B1200 },
167         { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
168         { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
169         { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
170         { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
171         {-1, -1 }
172 };
173
174 struct linux_serial_struct {
175         int     type;
176         int     line;
177         int     port;
178         int     irq;
179         int     flags;
180         int     xmit_fifo_size;
181         int     custom_divisor;
182         int     baud_base;
183         unsigned short close_delay;
184         char    reserved_char[2];
185         int     hub6;
186         unsigned short closing_wait;
187         unsigned short closing_wait2;
188         int     reserved[4];
189 };
190
191 static int
192 linux_to_bsd_speed(int code, struct speedtab *table)
193 {
194         for ( ; table->sp_code != -1; table++)
195                 if (table->sp_code == code)
196                         return (table->sp_speed);
197         return -1;
198 }
199
200 static int
201 bsd_to_linux_speed(int speed, struct speedtab *table)
202 {
203         for ( ; table->sp_speed != -1; table++)
204                 if (table->sp_speed == speed)
205                         return (table->sp_code);
206         return -1;
207 }
208
209 static void
210 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
211 {
212         int i;
213
214 #ifdef DEBUG
215         if (ldebug(ioctl)) {
216                 printf("LINUX: BSD termios structure (input):\n");
217                 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
218                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
219                     bios->c_ispeed, bios->c_ospeed);
220                 printf("c_cc ");
221                 for (i=0; i<NCCS; i++)
222                         printf("%02x ", bios->c_cc[i]);
223                 printf("\n");
224         }
225 #endif
226
227         lios->c_iflag = 0;
228         if (bios->c_iflag & IGNBRK)
229                 lios->c_iflag |= LINUX_IGNBRK;
230         if (bios->c_iflag & BRKINT)
231                 lios->c_iflag |= LINUX_BRKINT;
232         if (bios->c_iflag & IGNPAR)
233                 lios->c_iflag |= LINUX_IGNPAR;
234         if (bios->c_iflag & PARMRK)
235                 lios->c_iflag |= LINUX_PARMRK;
236         if (bios->c_iflag & INPCK)
237                 lios->c_iflag |= LINUX_INPCK;
238         if (bios->c_iflag & ISTRIP)
239                 lios->c_iflag |= LINUX_ISTRIP;
240         if (bios->c_iflag & INLCR)
241                 lios->c_iflag |= LINUX_INLCR;
242         if (bios->c_iflag & IGNCR)
243                 lios->c_iflag |= LINUX_IGNCR;
244         if (bios->c_iflag & ICRNL)
245                 lios->c_iflag |= LINUX_ICRNL;
246         if (bios->c_iflag & IXON)
247                 lios->c_iflag |= LINUX_IXON;
248         if (bios->c_iflag & IXANY)
249                 lios->c_iflag |= LINUX_IXANY;
250         if (bios->c_iflag & IXOFF)
251                 lios->c_iflag |= LINUX_IXOFF;
252         if (bios->c_iflag & IMAXBEL)
253                 lios->c_iflag |= LINUX_IMAXBEL;
254
255         lios->c_oflag = 0;
256         if (bios->c_oflag & OPOST)
257                 lios->c_oflag |= LINUX_OPOST;
258         if (bios->c_oflag & ONLCR)
259                 lios->c_oflag |= LINUX_ONLCR;
260         if (bios->c_oflag & OXTABS)
261                 lios->c_oflag |= LINUX_XTABS;
262
263         lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
264         lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
265         if (bios->c_cflag & CSTOPB)
266                 lios->c_cflag |= LINUX_CSTOPB;
267         if (bios->c_cflag & CREAD)
268                 lios->c_cflag |= LINUX_CREAD;
269         if (bios->c_cflag & PARENB)
270                 lios->c_cflag |= LINUX_PARENB;
271         if (bios->c_cflag & PARODD)
272                 lios->c_cflag |= LINUX_PARODD;
273         if (bios->c_cflag & HUPCL)
274                 lios->c_cflag |= LINUX_HUPCL;
275         if (bios->c_cflag & CLOCAL)
276                 lios->c_cflag |= LINUX_CLOCAL;
277         if (bios->c_cflag & CRTSCTS)
278                 lios->c_cflag |= LINUX_CRTSCTS;
279
280         lios->c_lflag = 0;
281         if (bios->c_lflag & ISIG)
282                 lios->c_lflag |= LINUX_ISIG;
283         if (bios->c_lflag & ICANON)
284                 lios->c_lflag |= LINUX_ICANON;
285         if (bios->c_lflag & ECHO)
286                 lios->c_lflag |= LINUX_ECHO;
287         if (bios->c_lflag & ECHOE)
288                 lios->c_lflag |= LINUX_ECHOE;
289         if (bios->c_lflag & ECHOK)
290                 lios->c_lflag |= LINUX_ECHOK;
291         if (bios->c_lflag & ECHONL)
292                 lios->c_lflag |= LINUX_ECHONL;
293         if (bios->c_lflag & NOFLSH)
294                 lios->c_lflag |= LINUX_NOFLSH;
295         if (bios->c_lflag & TOSTOP)
296                 lios->c_lflag |= LINUX_TOSTOP;
297         if (bios->c_lflag & ECHOCTL)
298                 lios->c_lflag |= LINUX_ECHOCTL;
299         if (bios->c_lflag & ECHOPRT)
300                 lios->c_lflag |= LINUX_ECHOPRT;
301         if (bios->c_lflag & ECHOKE)
302                 lios->c_lflag |= LINUX_ECHOKE;
303         if (bios->c_lflag & FLUSHO)
304                 lios->c_lflag |= LINUX_FLUSHO;
305         if (bios->c_lflag & PENDIN)
306                 lios->c_lflag |= LINUX_PENDIN;
307         if (bios->c_lflag & IEXTEN)
308                 lios->c_lflag |= LINUX_IEXTEN;
309
310         for (i=0; i<LINUX_NCCS; i++)
311                 lios->c_cc[i] = LINUX_POSIX_VDISABLE;
312         lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
313         lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
314         lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
315         lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
316         lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
317         lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
318         lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
319         lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
320         lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
321         lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
322         lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
323         lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
324         lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
325         lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
326         lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
327         lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
328
329         for (i=0; i<LINUX_NCCS; i++) {
330                 if (lios->c_cc[i] == _POSIX_VDISABLE)
331                         lios->c_cc[i] = LINUX_POSIX_VDISABLE;
332         }
333         lios->c_line = 0;
334
335 #ifdef DEBUG
336         if (ldebug(ioctl)) {
337                 printf("LINUX: LINUX termios structure (output):\n");
338                 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
339                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
340                     lios->c_lflag, (int)lios->c_line);
341                 printf("c_cc ");
342                 for (i=0; i<LINUX_NCCS; i++) 
343                         printf("%02x ", lios->c_cc[i]);
344                 printf("\n");
345         }
346 #endif
347 }
348
349 static void
350 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
351 {
352         int i;
353
354 #ifdef DEBUG
355         if (ldebug(ioctl)) {
356                 printf("LINUX: LINUX termios structure (input):\n");
357                 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 
358                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
359                     lios->c_lflag, (int)lios->c_line);
360                 printf("c_cc ");
361                 for (i=0; i<LINUX_NCCS; i++)
362                         printf("%02x ", lios->c_cc[i]);
363                 printf("\n");
364         }
365 #endif
366
367         bios->c_iflag = 0;
368         if (lios->c_iflag & LINUX_IGNBRK)
369                 bios->c_iflag |= IGNBRK;
370         if (lios->c_iflag & LINUX_BRKINT)
371                 bios->c_iflag |= BRKINT;
372         if (lios->c_iflag & LINUX_IGNPAR)
373                 bios->c_iflag |= IGNPAR;
374         if (lios->c_iflag & LINUX_PARMRK)
375                 bios->c_iflag |= PARMRK;
376         if (lios->c_iflag & LINUX_INPCK)
377                 bios->c_iflag |= INPCK;
378         if (lios->c_iflag & LINUX_ISTRIP)
379                 bios->c_iflag |= ISTRIP;
380         if (lios->c_iflag & LINUX_INLCR)
381                 bios->c_iflag |= INLCR;
382         if (lios->c_iflag & LINUX_IGNCR)
383                 bios->c_iflag |= IGNCR;
384         if (lios->c_iflag & LINUX_ICRNL)
385                 bios->c_iflag |= ICRNL;
386         if (lios->c_iflag & LINUX_IXON)
387                 bios->c_iflag |= IXON;
388         if (lios->c_iflag & LINUX_IXANY)
389                 bios->c_iflag |= IXANY;
390         if (lios->c_iflag & LINUX_IXOFF)
391                 bios->c_iflag |= IXOFF;
392         if (lios->c_iflag & LINUX_IMAXBEL)
393                 bios->c_iflag |= IMAXBEL;
394
395         bios->c_oflag = 0;
396         if (lios->c_oflag & LINUX_OPOST)
397                 bios->c_oflag |= OPOST;
398         if (lios->c_oflag & LINUX_ONLCR)
399                 bios->c_oflag |= ONLCR;
400         if (lios->c_oflag & LINUX_XTABS)
401                 bios->c_oflag |= OXTABS;
402
403         bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
404         if (lios->c_cflag & LINUX_CSTOPB)
405                 bios->c_cflag |= CSTOPB;
406         if (lios->c_cflag & LINUX_CREAD)
407                 bios->c_cflag |= CREAD;
408         if (lios->c_cflag & LINUX_PARENB)
409                 bios->c_cflag |= PARENB;
410         if (lios->c_cflag & LINUX_PARODD)
411                 bios->c_cflag |= PARODD;
412         if (lios->c_cflag & LINUX_HUPCL)
413                 bios->c_cflag |= HUPCL;
414         if (lios->c_cflag & LINUX_CLOCAL)
415                 bios->c_cflag |= CLOCAL;
416         if (lios->c_cflag & LINUX_CRTSCTS)
417                 bios->c_cflag |= CRTSCTS;
418
419         bios->c_lflag = 0;
420         if (lios->c_lflag & LINUX_ISIG)
421                 bios->c_lflag |= ISIG;
422         if (lios->c_lflag & LINUX_ICANON)
423                 bios->c_lflag |= ICANON;
424         if (lios->c_lflag & LINUX_ECHO)
425                 bios->c_lflag |= ECHO;
426         if (lios->c_lflag & LINUX_ECHOE)
427                 bios->c_lflag |= ECHOE;
428         if (lios->c_lflag & LINUX_ECHOK)
429                 bios->c_lflag |= ECHOK;
430         if (lios->c_lflag & LINUX_ECHONL)
431                 bios->c_lflag |= ECHONL;
432         if (lios->c_lflag & LINUX_NOFLSH)
433                 bios->c_lflag |= NOFLSH;
434         if (lios->c_lflag & LINUX_TOSTOP)
435                 bios->c_lflag |= TOSTOP;
436         if (lios->c_lflag & LINUX_ECHOCTL)
437                 bios->c_lflag |= ECHOCTL;
438         if (lios->c_lflag & LINUX_ECHOPRT)
439                 bios->c_lflag |= ECHOPRT;
440         if (lios->c_lflag & LINUX_ECHOKE)
441                 bios->c_lflag |= ECHOKE;
442         if (lios->c_lflag & LINUX_FLUSHO)
443                 bios->c_lflag |= FLUSHO;
444         if (lios->c_lflag & LINUX_PENDIN)
445                 bios->c_lflag |= PENDIN;
446         if (lios->c_lflag & LINUX_IEXTEN)
447                 bios->c_lflag |= IEXTEN;
448
449         for (i=0; i<NCCS; i++)
450                 bios->c_cc[i] = _POSIX_VDISABLE;
451         bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
452         bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
453         bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
454         bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
455         bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
456         bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
457         bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
458         bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
459         bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
460         bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
461         bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
462         bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
463         bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
464         bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
465         bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
466         bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
467
468         for (i=0; i<NCCS; i++) {
469                 if (bios->c_cc[i] == LINUX_POSIX_VDISABLE)
470                         bios->c_cc[i] = _POSIX_VDISABLE;
471         }
472
473         bios->c_ispeed = bios->c_ospeed =
474             linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
475
476 #ifdef DEBUG
477         if (ldebug(ioctl)) {
478                 printf("LINUX: BSD termios structure (output):\n");
479                 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
480                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
481                     bios->c_ispeed, bios->c_ospeed);
482                 printf("c_cc ");
483                 for (i=0; i<NCCS; i++) 
484                         printf("%02x ", bios->c_cc[i]);
485                 printf("\n");
486         }
487 #endif
488 }
489
490 static void
491 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
492 {
493         struct linux_termios lios;
494
495         bsd_to_linux_termios(bios, &lios);
496         lio->c_iflag = lios.c_iflag;
497         lio->c_oflag = lios.c_oflag;
498         lio->c_cflag = lios.c_cflag;
499         lio->c_lflag = lios.c_lflag;
500         lio->c_line  = lios.c_line;
501 #ifdef __alpha__
502         lio->c_cc[LINUX__VINTR] = lios.c_cc[LINUX_VINTR];
503         lio->c_cc[LINUX__VQUIT] = lios.c_cc[LINUX_VQUIT];
504         lio->c_cc[LINUX__VERASE] = lios.c_cc[LINUX_VERASE];
505         lio->c_cc[LINUX__VKILL] = lios.c_cc[LINUX_VKILL];
506         lio->c_cc[LINUX__VEOF] =
507             lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN];
508         lio->c_cc[LINUX__VEOL] =
509             lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME];
510         lio->c_cc[LINUX__VEOL2] = lios.c_cc[LINUX_VEOL2];
511         lio->c_cc[LINUX__VSWTC] = lios.c_cc[LINUX_VSWTC];
512 #else
513         memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
514 #endif
515 }
516
517 static void
518 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
519 {
520         struct linux_termios lios;
521         int i;
522
523         lios.c_iflag = lio->c_iflag;
524         lios.c_oflag = lio->c_oflag;
525         lios.c_cflag = lio->c_cflag;
526         lios.c_lflag = lio->c_lflag;
527 #ifdef __alpha__
528         for (i=0; i<LINUX_NCCS; i++)
529                 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
530         lios.c_cc[LINUX_VINTR] = lio->c_cc[LINUX__VINTR];
531         lios.c_cc[LINUX_VQUIT] = lio->c_cc[LINUX__VQUIT];
532         lios.c_cc[LINUX_VERASE] = lio->c_cc[LINUX__VERASE];
533         lios.c_cc[LINUX_VKILL] = lio->c_cc[LINUX__VKILL];
534         lios.c_cc[LINUX_VEOL2] = lio->c_cc[LINUX__VEOL2];
535         lios.c_cc[LINUX_VSWTC] = lio->c_cc[LINUX__VSWTC];
536         lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN] =
537             lio->c_cc[LINUX__VEOF];
538         lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME] =
539             lio->c_cc[LINUX__VEOL];
540 #else
541         for (i=LINUX_NCC; i<LINUX_NCCS; i++)
542                 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
543         memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
544 #endif
545         linux_to_bsd_termios(&lios, bios);
546 }
547
548 static int
549 linux_ioctl_termio(struct proc *p, struct linux_ioctl_args *args)
550 {
551         struct termios bios;
552         struct linux_termios lios;
553         struct linux_termio lio;
554         struct file *fp = p->p_fd->fd_ofiles[args->fd];
555         int error;
556
557         switch (args->cmd & 0xffff) {
558
559         case LINUX_TCGETS:
560                 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
561                 if (error)
562                         return (error);
563                 bsd_to_linux_termios(&bios, &lios);
564                 return copyout(&lios, (caddr_t)args->arg, sizeof(lios));
565
566         case LINUX_TCSETS:
567                 error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
568                 if (error)
569                         return (error);
570                 linux_to_bsd_termios(&lios, &bios);
571                 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p));
572
573         case LINUX_TCSETSW:
574                 error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
575                 if (error)
576                         return (error);
577                 linux_to_bsd_termios(&lios, &bios);
578                 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p));
579
580         case LINUX_TCSETSF:
581                 error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
582                 if (error)
583                         return (error);
584                 linux_to_bsd_termios(&lios, &bios);
585                 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p));
586
587         case LINUX_TCGETA:
588                 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
589                 if (error)
590                         return (error);
591                 bsd_to_linux_termio(&bios, &lio);
592                 return (copyout(&lio, (caddr_t)args->arg, sizeof(lio)));
593
594         case LINUX_TCSETA:
595                 error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
596                 if (error)
597                         return (error);
598                 linux_to_bsd_termio(&lio, &bios);
599                 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p));
600
601         case LINUX_TCSETAW:
602                 error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
603                 if (error)
604                         return (error);
605                 linux_to_bsd_termio(&lio, &bios);
606                 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p));
607
608         case LINUX_TCSETAF:
609                 error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
610                 if (error)
611                         return (error);
612                 linux_to_bsd_termio(&lio, &bios);
613                 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p));
614
615         /* LINUX_TCSBRK */
616
617         case LINUX_TCXONC: {
618                 switch (args->arg) {
619                 case LINUX_TCOOFF:
620                         args->cmd = TIOCSTOP;
621                         break;
622                 case LINUX_TCOON:
623                         args->cmd = TIOCSTART;
624                         break;
625                 case LINUX_TCIOFF:
626                 case LINUX_TCION: {
627                         int c;
628                         struct write_args wr;
629                         error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
630                         if (error)
631                                 return (error);
632                         c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
633                         c = bios.c_cc[c];
634                         if (c != _POSIX_VDISABLE) {
635                                 wr.fd = args->fd;
636                                 wr.buf = &c;
637                                 wr.nbyte = sizeof(c);
638                                 return (write(p, &wr));
639                         } else
640                                 return (0);
641                 }
642                 default:
643                         return (EINVAL);
644                 }
645                 args->arg = 0;
646                 return (ioctl(p, (struct ioctl_args *)args));
647         }
648
649         case LINUX_TCFLSH: {
650                 args->cmd = TIOCFLUSH;
651                 switch (args->arg) {
652                 case LINUX_TCIFLUSH:
653                         args->arg = FREAD;
654                         break;
655                 case LINUX_TCOFLUSH:
656                         args->arg = FWRITE;
657                         break;
658                 case LINUX_TCIOFLUSH:
659                         args->arg = FREAD | FWRITE;
660                         break;
661                 default:
662                         return (EINVAL);
663                 }
664                 return (ioctl(p, (struct ioctl_args *)args));
665         }
666
667         case LINUX_TIOCEXCL:
668                 args->cmd = TIOCEXCL;
669                 return (ioctl(p, (struct ioctl_args *)args));
670
671         case LINUX_TIOCNXCL:
672                 args->cmd = TIOCNXCL;
673                 return (ioctl(p, (struct ioctl_args *)args));
674
675         /* LINUX_TIOCSCTTY */
676
677         case LINUX_TIOCGPGRP:
678                 args->cmd = TIOCGPGRP;
679                 return (ioctl(p, (struct ioctl_args *)args));
680
681         case LINUX_TIOCSPGRP:
682                 args->cmd = TIOCSPGRP;
683                 return (ioctl(p, (struct ioctl_args *)args));
684
685         /* LINUX_TIOCOUTQ */
686         /* LINUX_TIOCSTI */
687
688         case LINUX_TIOCGWINSZ:
689                 args->cmd = TIOCGWINSZ;
690                 return (ioctl(p, (struct ioctl_args *)args));
691
692         case LINUX_TIOCSWINSZ:
693                 args->cmd = TIOCSWINSZ;
694                 return (ioctl(p, (struct ioctl_args *)args));
695
696         case LINUX_TIOCMGET:
697                 args->cmd = TIOCMGET;
698                 return (ioctl(p, (struct ioctl_args *)args));
699
700         case LINUX_TIOCMBIS:
701                 args->cmd = TIOCMBIS;
702                 return (ioctl(p, (struct ioctl_args *)args));
703
704         case LINUX_TIOCMBIC:
705                 args->cmd = TIOCMBIC;
706                 return (ioctl(p, (struct ioctl_args *)args));
707
708         case LINUX_TIOCMSET:
709                 args->cmd = TIOCMSET;
710                 return (ioctl(p, (struct ioctl_args *)args));
711
712         /* TIOCGSOFTCAR */
713         /* TIOCSSOFTCAR */
714
715         case LINUX_FIONREAD: /* LINUX_TIOCINQ */
716                 args->cmd = FIONREAD;
717                 return (ioctl(p, (struct ioctl_args *)args));
718
719         /* LINUX_TIOCLINUX */
720
721         case LINUX_TIOCCONS:
722                 args->cmd = TIOCCONS;
723                 return (ioctl(p, (struct ioctl_args *)args));
724
725         case LINUX_TIOCGSERIAL: {
726                 struct linux_serial_struct lss;
727                 lss.type = LINUX_PORT_16550A;
728                 lss.flags = 0;
729                 lss.close_delay = 0;
730                 return copyout(&lss, (caddr_t)args->arg, sizeof(lss));
731         }
732
733         case LINUX_TIOCSSERIAL: {
734                 struct linux_serial_struct lss;
735                 error = copyin((caddr_t)args->arg, &lss, sizeof(lss));
736                 if (error)
737                         return (error);
738                 /* XXX - It really helps to have an implementation that
739                  * does nothing. NOT!
740                  */
741                 return (0);
742         }
743
744         /* LINUX_TIOCPKT */
745
746         case LINUX_FIONBIO:
747                 args->cmd = FIONBIO;
748                 return (ioctl(p, (struct ioctl_args *)args));
749
750         case LINUX_TIOCNOTTY:
751                 args->cmd = TIOCNOTTY;
752                 return (ioctl(p, (struct ioctl_args *)args));
753
754         case LINUX_TIOCSETD: {
755                 int line;
756                 switch (args->arg) {
757                 case LINUX_N_TTY:
758                         line = TTYDISC;
759                         break;
760                 case LINUX_N_SLIP:
761                         line = SLIPDISC;
762                         break;
763                 case LINUX_N_PPP:
764                         line = PPPDISC;
765                         break;
766                 default:
767                         return (EINVAL);
768                 }
769                 return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, p));
770         }
771
772         case LINUX_TIOCGETD: {
773                 int linux_line;
774                 int bsd_line = TTYDISC;
775                 error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, p);
776                 if (error)
777                         return (error);
778                 switch (bsd_line) {
779                 case TTYDISC:
780                         linux_line = LINUX_N_TTY;
781                         break;
782                 case SLIPDISC:
783                         linux_line = LINUX_N_SLIP;
784                         break;
785                 case PPPDISC:
786                         linux_line = LINUX_N_PPP;
787                         break;
788                 default:
789                         return (EINVAL);
790                 }
791                 return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int)));
792         }
793
794         /* LINUX_TCSBRKP */
795         /* LINUX_TIOCTTYGSTRUCT */
796
797         case LINUX_FIONCLEX:
798                 args->cmd = FIONCLEX;
799                 return (ioctl(p, (struct ioctl_args *)args));
800
801         case LINUX_FIOCLEX:
802                 args->cmd = FIOCLEX;
803                 return (ioctl(p, (struct ioctl_args *)args));
804
805         case LINUX_FIOASYNC:
806                 args->cmd = FIOASYNC;
807                 return (ioctl(p, (struct ioctl_args *)args));
808
809         /* LINUX_TIOCSERCONFIG */
810         /* LINUX_TIOCSERGWILD */
811         /* LINUX_TIOCSERSWILD */
812         /* LINUX_TIOCGLCKTRMIOS */
813         /* LINUX_TIOCSLCKTRMIOS */
814
815         }
816
817         return (ENOIOCTL);
818 }
819
820 /*
821  * CDROM related ioctls
822  */
823
824 struct linux_cdrom_msf
825 {
826         u_char  cdmsf_min0;
827         u_char  cdmsf_sec0;
828         u_char  cdmsf_frame0;
829         u_char  cdmsf_min1;
830         u_char  cdmsf_sec1;
831         u_char  cdmsf_frame1;
832 };
833
834 struct linux_cdrom_tochdr
835 {
836         u_char  cdth_trk0;
837         u_char  cdth_trk1;
838 };
839
840 union linux_cdrom_addr
841 {
842         struct {
843                 u_char  minute;
844                 u_char  second;
845                 u_char  frame;
846         } msf;
847         int     lba;
848 };
849
850 struct linux_cdrom_tocentry
851 {
852         u_char  cdte_track;     
853         u_char  cdte_adr:4;
854         u_char  cdte_ctrl:4;
855         u_char  cdte_format;    
856         union linux_cdrom_addr cdte_addr;
857         u_char  cdte_datamode;  
858 };
859
860 struct linux_cdrom_subchnl
861 {
862         u_char  cdsc_format;
863         u_char  cdsc_audiostatus;
864         u_char  cdsc_adr:4;
865         u_char  cdsc_ctrl:4;
866         u_char  cdsc_trk;
867         u_char  cdsc_ind;
868         union linux_cdrom_addr cdsc_absaddr;
869         union linux_cdrom_addr cdsc_reladdr;
870 };
871
872 static void
873 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
874 {
875         if (af == CD_LBA_FORMAT)
876                 lp->lba = bp->lba;
877         else {
878                 lp->msf.minute = bp->msf.minute;
879                 lp->msf.second = bp->msf.second;
880                 lp->msf.frame = bp->msf.frame;
881         }
882 }
883
884 static void
885 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
886 {
887         if (format == LINUX_CDROM_MSF) {
888                 addr->msf.frame = lba % 75;
889                 lba /= 75;
890                 lba += 2;
891                 addr->msf.second = lba % 60;
892                 addr->msf.minute = lba / 60;
893         } else
894                 addr->lba = lba;
895 }
896
897 static int
898 linux_ioctl_cdrom(struct proc *p, struct linux_ioctl_args *args)
899 {
900         struct file *fp = p->p_fd->fd_ofiles[args->fd];
901         int error;
902
903         switch (args->cmd & 0xffff) {
904
905         case LINUX_CDROMPAUSE:
906                 args->cmd = CDIOCPAUSE;
907                 return (ioctl(p, (struct ioctl_args *)args));
908
909         case LINUX_CDROMRESUME:
910                 args->cmd = CDIOCRESUME;
911                 return (ioctl(p, (struct ioctl_args *)args));
912
913         case LINUX_CDROMPLAYMSF:
914                 args->cmd = CDIOCPLAYMSF;
915                 return (ioctl(p, (struct ioctl_args *)args));
916
917         case LINUX_CDROMPLAYTRKIND:
918                 args->cmd = CDIOCPLAYTRACKS;
919                 return (ioctl(p, (struct ioctl_args *)args));
920
921         case LINUX_CDROMREADTOCHDR: {
922                 struct ioc_toc_header th;
923                 struct linux_cdrom_tochdr lth;
924                 error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, p);
925                 if (!error) {
926                         lth.cdth_trk0 = th.starting_track;
927                         lth.cdth_trk1 = th.ending_track;
928                         copyout(&lth, (caddr_t)args->arg, sizeof(lth));
929                 }
930                 return (error);
931         }
932
933         case LINUX_CDROMREADTOCENTRY: {
934                 struct linux_cdrom_tocentry lte, *ltep =
935                     (struct linux_cdrom_tocentry *)args->arg;
936                 struct ioc_read_toc_single_entry irtse;
937                 irtse.address_format = ltep->cdte_format;
938                 irtse.track = ltep->cdte_track;
939                 error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, p);
940                 if (!error) {
941                         lte = *ltep;
942                         lte.cdte_ctrl = irtse.entry.control;
943                         lte.cdte_adr = irtse.entry.addr_type;
944                         bsd_to_linux_msf_lba(irtse.address_format,
945                             &irtse.entry.addr, &lte.cdte_addr);
946                         copyout(&lte, (caddr_t)args->arg, sizeof(lte));
947                 }
948                 return (error);
949         }
950
951         case LINUX_CDROMSTOP:
952                 args->cmd = CDIOCSTOP;
953                 return (ioctl(p, (struct ioctl_args *)args));
954
955         case LINUX_CDROMSTART:
956                 args->cmd = CDIOCSTART;
957                 return (ioctl(p, (struct ioctl_args *)args));
958
959         case LINUX_CDROMEJECT:
960                 args->cmd = CDIOCEJECT;
961                 return (ioctl(p, (struct ioctl_args *)args));
962
963         /* LINUX_CDROMVOLCTRL */
964
965         case LINUX_CDROMSUBCHNL: {
966                 struct linux_cdrom_subchnl sc;
967                 struct ioc_read_subchannel bsdsc;
968                 struct cd_sub_channel_info *bsdinfo;
969                 caddr_t sg = stackgap_init();
970                 bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg,
971                     sizeof(struct cd_sub_channel_info));
972                 bsdsc.address_format = CD_LBA_FORMAT;
973                 bsdsc.data_format = CD_CURRENT_POSITION;
974                 bsdsc.track = 0;
975                 bsdsc.data_len = sizeof(struct cd_sub_channel_info);
976                 bsdsc.data = bsdinfo;
977                 error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, p);
978                 if (error)
979                         return (error);
980                 error = copyin((caddr_t)args->arg, &sc,
981                     sizeof(struct linux_cdrom_subchnl));
982                 if (error)
983                         return (error);
984                 sc.cdsc_audiostatus = bsdinfo->header.audio_status;
985                 sc.cdsc_adr = bsdinfo->what.position.addr_type;
986                 sc.cdsc_ctrl = bsdinfo->what.position.control;
987                 sc.cdsc_trk = bsdinfo->what.position.track_number;
988                 sc.cdsc_ind = bsdinfo->what.position.index_number;
989                 set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
990                     bsdinfo->what.position.absaddr.lba);
991                 set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
992                     bsdinfo->what.position.reladdr.lba);
993                 error = copyout(&sc, (caddr_t)args->arg,
994                     sizeof(struct linux_cdrom_subchnl));
995                 return (error);
996         }
997
998         /* LINUX_CDROMREADMODE2 */
999         /* LINUX_CDROMREADMODE1 */
1000         /* LINUX_CDROMREADAUDIO */
1001         /* LINUX_CDROMEJECT_SW */
1002         /* LINUX_CDROMMULTISESSION */
1003         /* LINUX_CDROM_GET_UPC */
1004
1005         case LINUX_CDROMRESET:
1006                 args->cmd = CDIOCRESET;
1007                 return (ioctl(p, (struct ioctl_args *)args));
1008
1009         /* LINUX_CDROMVOLREAD */
1010         /* LINUX_CDROMREADRAW */
1011         /* LINUX_CDROMREADCOOKED */
1012         /* LINUX_CDROMSEEK */
1013         /* LINUX_CDROMPLAYBLK */
1014         /* LINUX_CDROMREADALL */
1015         /* LINUX_CDROMCLOSETRAY */
1016         /* LINUX_CDROMLOADFROMSLOT */
1017
1018         }
1019
1020         return (ENOIOCTL);
1021 }
1022
1023 /*
1024  * Sound related ioctls
1025  */
1026
1027 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1028
1029 #define SETDIR(c)       (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1030
1031 static int
1032 linux_ioctl_sound(struct proc *p, struct linux_ioctl_args *args)
1033 {
1034
1035         switch (args->cmd & 0xffff) {
1036
1037         case LINUX_SOUND_MIXER_WRITE_VOLUME:
1038                 args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1039                 return (ioctl(p, (struct ioctl_args *)args));
1040
1041         case LINUX_SOUND_MIXER_WRITE_BASS:
1042                 args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1043                 return (ioctl(p, (struct ioctl_args *)args));
1044
1045         case LINUX_SOUND_MIXER_WRITE_TREBLE:
1046                 args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1047                 return (ioctl(p, (struct ioctl_args *)args));
1048
1049         case LINUX_SOUND_MIXER_WRITE_SYNTH:
1050                 args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1051                 return (ioctl(p, (struct ioctl_args *)args));
1052
1053         case LINUX_SOUND_MIXER_WRITE_PCM:
1054                 args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1055                 return (ioctl(p, (struct ioctl_args *)args));
1056
1057         case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1058                 args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1059                 return (ioctl(p, (struct ioctl_args *)args));
1060
1061         case LINUX_SOUND_MIXER_WRITE_LINE:
1062                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1063                 return (ioctl(p, (struct ioctl_args *)args));
1064
1065         case LINUX_SOUND_MIXER_WRITE_MIC:
1066                 args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1067                 return (ioctl(p, (struct ioctl_args *)args));
1068
1069         case LINUX_SOUND_MIXER_WRITE_CD:
1070                 args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1071                 return (ioctl(p, (struct ioctl_args *)args));
1072
1073         case LINUX_SOUND_MIXER_WRITE_IMIX:
1074                 args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1075                 return (ioctl(p, (struct ioctl_args *)args));
1076
1077         case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1078                 args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1079                 return (ioctl(p, (struct ioctl_args *)args));
1080
1081         case LINUX_SOUND_MIXER_WRITE_RECLEV:
1082                 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1083                 return (ioctl(p, (struct ioctl_args *)args));
1084
1085         case LINUX_SOUND_MIXER_WRITE_IGAIN:
1086                 args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1087                 return (ioctl(p, (struct ioctl_args *)args));
1088
1089         case LINUX_SOUND_MIXER_WRITE_OGAIN:
1090                 args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1091                 return (ioctl(p, (struct ioctl_args *)args));
1092
1093         case LINUX_SOUND_MIXER_WRITE_LINE1:
1094                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1095                 return (ioctl(p, (struct ioctl_args *)args));
1096
1097         case LINUX_SOUND_MIXER_WRITE_LINE2:
1098                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1099                 return (ioctl(p, (struct ioctl_args *)args));
1100
1101         case LINUX_SOUND_MIXER_WRITE_LINE3:
1102                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1103                 return (ioctl(p, (struct ioctl_args *)args));
1104
1105         case LINUX_OSS_GETVERSION: {
1106                 int version = linux_get_oss_version(p);
1107                 return (copyout(&version, (caddr_t)args->arg, sizeof(int)));
1108         }
1109
1110         case LINUX_SOUND_MIXER_READ_DEVMASK:
1111                 args->cmd = SOUND_MIXER_READ_DEVMASK;
1112                 return (ioctl(p, (struct ioctl_args *)args));
1113
1114         case LINUX_SNDCTL_DSP_RESET:
1115                 args->cmd = SNDCTL_DSP_RESET;
1116                 return (ioctl(p, (struct ioctl_args *)args));
1117
1118         case LINUX_SNDCTL_DSP_SYNC:
1119                 args->cmd = SNDCTL_DSP_SYNC;
1120                 return (ioctl(p, (struct ioctl_args *)args));
1121
1122         case LINUX_SNDCTL_DSP_SPEED:
1123                 args->cmd = SNDCTL_DSP_SPEED;
1124                 return (ioctl(p, (struct ioctl_args *)args));
1125
1126         case LINUX_SNDCTL_DSP_STEREO:
1127                 args->cmd = SNDCTL_DSP_STEREO;
1128                 return (ioctl(p, (struct ioctl_args *)args));
1129
1130         case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1131                 args->cmd = SNDCTL_DSP_GETBLKSIZE;
1132                 return (ioctl(p, (struct ioctl_args *)args));
1133
1134         case LINUX_SNDCTL_DSP_SETFMT:
1135                 args->cmd = SNDCTL_DSP_SETFMT;
1136                 return (ioctl(p, (struct ioctl_args *)args));
1137
1138         case LINUX_SOUND_PCM_WRITE_CHANNELS:
1139                 args->cmd = SOUND_PCM_WRITE_CHANNELS;
1140                 return (ioctl(p, (struct ioctl_args *)args));
1141
1142         case LINUX_SOUND_PCM_WRITE_FILTER:
1143                 args->cmd = SOUND_PCM_WRITE_FILTER;
1144                 return (ioctl(p, (struct ioctl_args *)args));
1145
1146         case LINUX_SNDCTL_DSP_POST:
1147                 args->cmd = SNDCTL_DSP_POST;
1148                 return (ioctl(p, (struct ioctl_args *)args));
1149
1150         case LINUX_SNDCTL_DSP_SUBDIVIDE:
1151                 args->cmd = SNDCTL_DSP_SUBDIVIDE;
1152                 return (ioctl(p, (struct ioctl_args *)args));
1153
1154         case LINUX_SNDCTL_DSP_SETFRAGMENT:
1155                 args->cmd = SNDCTL_DSP_SETFRAGMENT;
1156                 return (ioctl(p, (struct ioctl_args *)args));
1157
1158         case LINUX_SNDCTL_DSP_GETFMTS:
1159                 args->cmd = SNDCTL_DSP_GETFMTS;
1160                 return (ioctl(p, (struct ioctl_args *)args));
1161
1162         case LINUX_SNDCTL_DSP_GETOSPACE:
1163                 args->cmd = SNDCTL_DSP_GETOSPACE;
1164                 return (ioctl(p, (struct ioctl_args *)args));
1165
1166         case LINUX_SNDCTL_DSP_GETISPACE:
1167                 args->cmd = SNDCTL_DSP_GETISPACE;
1168                 return (ioctl(p, (struct ioctl_args *)args));
1169
1170         case LINUX_SNDCTL_DSP_NONBLOCK:
1171                 args->cmd = SNDCTL_DSP_NONBLOCK;
1172                 return (ioctl(p, (struct ioctl_args *)args));
1173
1174         case LINUX_SNDCTL_DSP_GETCAPS:
1175                 args->cmd = SNDCTL_DSP_GETCAPS;
1176                 return (ioctl(p, (struct ioctl_args *)args));
1177
1178         case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1179                 args->cmd = SNDCTL_DSP_SETTRIGGER;
1180                 return (ioctl(p, (struct ioctl_args *)args));
1181
1182         case LINUX_SNDCTL_DSP_GETIPTR:
1183                 args->cmd = SNDCTL_DSP_GETIPTR;
1184                 return (ioctl(p, (struct ioctl_args *)args));
1185
1186         case LINUX_SNDCTL_DSP_GETOPTR:
1187                 args->cmd = SNDCTL_DSP_GETOPTR;
1188                 return (ioctl(p, (struct ioctl_args *)args));
1189
1190         case LINUX_SNDCTL_DSP_GETODELAY:
1191                 args->cmd = SNDCTL_DSP_GETODELAY;
1192                 return (ioctl(p, (struct ioctl_args *)args));
1193
1194         case LINUX_SNDCTL_SEQ_RESET:
1195                 args->cmd = SNDCTL_SEQ_RESET;
1196                 return (ioctl(p, (struct ioctl_args *)args));
1197
1198         case LINUX_SNDCTL_SEQ_SYNC:
1199                 args->cmd = SNDCTL_SEQ_SYNC;
1200                 return (ioctl(p, (struct ioctl_args *)args));
1201
1202         case LINUX_SNDCTL_SYNTH_INFO:
1203                 args->cmd = SNDCTL_SYNTH_INFO;
1204                 return (ioctl(p, (struct ioctl_args *)args));
1205
1206         case LINUX_SNDCTL_SEQ_CTRLRATE:
1207                 args->cmd = SNDCTL_SEQ_CTRLRATE;
1208                 return (ioctl(p, (struct ioctl_args *)args));
1209
1210         case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1211                 args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1212                 return (ioctl(p, (struct ioctl_args *)args));
1213
1214         case LINUX_SNDCTL_SEQ_GETINCOUNT:
1215                 args->cmd = SNDCTL_SEQ_GETINCOUNT;
1216                 return (ioctl(p, (struct ioctl_args *)args));
1217
1218         case LINUX_SNDCTL_SEQ_PERCMODE:
1219                 args->cmd = SNDCTL_SEQ_PERCMODE;
1220                 return (ioctl(p, (struct ioctl_args *)args));
1221
1222         case LINUX_SNDCTL_FM_LOAD_INSTR:
1223                 args->cmd = SNDCTL_FM_LOAD_INSTR;
1224                 return (ioctl(p, (struct ioctl_args *)args));
1225
1226         case LINUX_SNDCTL_SEQ_TESTMIDI:
1227                 args->cmd = SNDCTL_SEQ_TESTMIDI;
1228                 return (ioctl(p, (struct ioctl_args *)args));
1229
1230         case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1231                 args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1232                 return (ioctl(p, (struct ioctl_args *)args));
1233
1234         case LINUX_SNDCTL_SEQ_NRSYNTHS:
1235                 args->cmd = SNDCTL_SEQ_NRSYNTHS;
1236                 return (ioctl(p, (struct ioctl_args *)args));
1237
1238         case LINUX_SNDCTL_SEQ_NRMIDIS:
1239                 args->cmd = SNDCTL_SEQ_NRMIDIS;
1240                 return (ioctl(p, (struct ioctl_args *)args));
1241
1242         case LINUX_SNDCTL_MIDI_INFO:
1243                 args->cmd = SNDCTL_MIDI_INFO;
1244                 return (ioctl(p, (struct ioctl_args *)args));
1245
1246         case LINUX_SNDCTL_SEQ_TRESHOLD:
1247                 args->cmd = SNDCTL_SEQ_TRESHOLD;
1248                 return (ioctl(p, (struct ioctl_args *)args));
1249
1250         case LINUX_SNDCTL_SYNTH_MEMAVL:
1251                 args->cmd = SNDCTL_SYNTH_MEMAVL;
1252                 return (ioctl(p, (struct ioctl_args *)args));
1253
1254         }
1255
1256         return (ENOIOCTL);
1257 }
1258
1259 /*
1260  * Console related ioctls
1261  */
1262
1263 #define ISSIGVALID(sig)         ((sig) > 0 && (sig) < NSIG)
1264
1265 static int
1266 linux_ioctl_console(struct proc *p, struct linux_ioctl_args *args)
1267 {
1268         struct file *fp = p->p_fd->fd_ofiles[args->fd];
1269
1270         switch (args->cmd & 0xffff) {
1271
1272         case LINUX_KIOCSOUND:
1273                 args->cmd = KIOCSOUND;
1274                 return (ioctl(p, (struct ioctl_args *)args));
1275
1276         case LINUX_KDMKTONE:
1277                 args->cmd = KDMKTONE;
1278                 return (ioctl(p, (struct ioctl_args *)args));
1279
1280         case LINUX_KDGETLED:
1281                 args->cmd = KDGETLED;
1282                 return (ioctl(p, (struct ioctl_args *)args));
1283
1284         case LINUX_KDSETLED:
1285                 args->cmd = KDSETLED;
1286                 return (ioctl(p, (struct ioctl_args *)args));
1287
1288         case LINUX_KDSETMODE:
1289                 args->cmd = KDSETMODE;
1290                 return (ioctl(p, (struct ioctl_args *)args));
1291
1292         case LINUX_KDGETMODE:
1293                 args->cmd = KDGETMODE;
1294                 return (ioctl(p, (struct ioctl_args *)args));
1295
1296         case LINUX_KDGKBMODE:
1297                 args->cmd = KDGKBMODE;
1298                 return (ioctl(p, (struct ioctl_args *)args));
1299
1300         case LINUX_KDSKBMODE: {
1301                 int kbdmode;
1302                 switch (args->arg) {
1303                 case LINUX_KBD_RAW:
1304                         kbdmode = K_RAW;
1305                         break;
1306                 case LINUX_KBD_XLATE:
1307                         kbdmode = K_XLATE;
1308                         break;
1309                 case LINUX_KBD_MEDIUMRAW:
1310                         kbdmode = K_RAW;
1311                         break;
1312                 default:
1313                         return (EINVAL);
1314                 }
1315                 return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, p));
1316         }
1317
1318         case LINUX_VT_OPENQRY:
1319                 args->cmd = VT_OPENQRY;
1320                 return (ioctl(p, (struct ioctl_args *)args));
1321
1322         case LINUX_VT_GETMODE:
1323                 args->cmd = VT_GETMODE;
1324                 return  (ioctl(p, (struct ioctl_args *)args));
1325
1326         case LINUX_VT_SETMODE: {
1327                 struct vt_mode *mode;
1328                 args->cmd = VT_SETMODE;
1329                 mode = (struct vt_mode *)args->arg;
1330                 if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
1331                         mode->frsig = mode->acqsig;
1332                 return (ioctl(p, (struct ioctl_args *)args));
1333         }
1334
1335         case LINUX_VT_GETSTATE:
1336                 args->cmd = VT_GETACTIVE;
1337                 return (ioctl(p, (struct ioctl_args *)args));
1338
1339         case LINUX_VT_RELDISP:
1340                 args->cmd = VT_RELDISP;
1341                 return (ioctl(p, (struct ioctl_args *)args));
1342
1343         case LINUX_VT_ACTIVATE:
1344                 args->cmd = VT_ACTIVATE;
1345                 return (ioctl(p, (struct ioctl_args *)args));
1346
1347         case LINUX_VT_WAITACTIVE:
1348                 args->cmd = VT_WAITACTIVE;
1349                 return (ioctl(p, (struct ioctl_args *)args));
1350
1351         }
1352         
1353         return (ENOIOCTL);
1354 }
1355
1356 /*
1357  * Criteria for interface name translation
1358  */
1359 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1360
1361 /*
1362  * Interface function used by linprocfs (at the time of writing). It's not
1363  * used by the Linuxulator itself.
1364  */
1365 int
1366 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1367 {
1368         struct ifnet *ifscan;
1369         int ethno;
1370
1371         /* Short-circuit non ethernet interfaces */
1372         if (!IFP_IS_ETH(ifp))
1373                 return (snprintf(buffer, buflen, "%s%d", ifp->if_name,
1374                     ifp->if_unit));
1375
1376         /* Determine the (relative) unit number for ethernet interfaces */
1377         ethno = 0;
1378         TAILQ_FOREACH(ifscan, &ifnet, if_link) {
1379                 if (ifscan == ifp)
1380                         return (snprintf(buffer, buflen, "eth%d", ethno));
1381                 if (IFP_IS_ETH(ifscan))
1382                         ethno++;
1383         }
1384
1385         return (0);
1386 }
1387
1388 /*
1389  * Translate a Linux interface name to a FreeBSD interface name,
1390  * and return the associated ifnet structure
1391  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
1392  * can point to the same buffer.
1393  */
1394
1395 static struct ifnet *
1396 ifname_linux_to_bsd(const char *lxname, char *bsdname)
1397 {
1398         struct ifnet *ifp;
1399         int len, unit;
1400         char *ep;
1401         int is_eth, index;
1402
1403         for (len = 0; len < LINUX_IFNAMSIZ; ++len)
1404                 if (!isalpha(lxname[len]))
1405                         break;
1406         if (len == 0 || len == LINUX_IFNAMSIZ)
1407                 return (NULL);
1408         unit = (int)strtoul(lxname + len, &ep, 10);
1409         if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
1410                 return (NULL);
1411         index = 0;
1412         is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
1413         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1414                 /*
1415                  * Allow Linux programs to use FreeBSD names. Don't presume
1416                  * we never have an interface named "eth", so don't make
1417                  * the test optional based on is_eth.
1418                  */
1419                 if (ifp->if_unit == unit && ifp->if_name[len] == '\0' &&
1420                     strncmp(ifp->if_name, lxname, len) == 0)
1421                         break;
1422                 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
1423                         break;
1424         }
1425         if (ifp != NULL)
1426                 snprintf(bsdname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit);
1427         return (ifp);
1428 }
1429
1430 /*
1431  * Implement the SIOCGIFCONF ioctl
1432  */
1433
1434 static int
1435 linux_ifconf(struct proc *p, struct ifconf *uifc)
1436 {
1437         struct ifconf ifc;
1438         struct l_ifreq ifr;
1439         struct ifnet *ifp;
1440         struct ifaddr *ifa;
1441         struct iovec iov;
1442         struct uio uio;
1443         int error, ethno;
1444
1445         error = copyin(uifc, &ifc, sizeof ifc);
1446         if (error != 0)
1447                 return (error);
1448
1449         /* much easier to use uiomove than keep track ourselves */
1450         iov.iov_base = ifc.ifc_buf;
1451         iov.iov_len = ifc.ifc_len;
1452         uio.uio_iov = &iov;
1453         uio.uio_iovcnt = 1;
1454         uio.uio_offset = 0;
1455         uio.uio_resid = ifc.ifc_len;
1456         uio.uio_segflg = UIO_USERSPACE;
1457         uio.uio_rw = UIO_READ;
1458         uio.uio_procp = p;
1459
1460         /* Keep track of eth interfaces */
1461         ethno = 0;
1462
1463         /* Return all AF_INET addresses of all interfaces */
1464         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1465                 if (uio.uio_resid <= 0)
1466                         break;
1467
1468                 bzero(&ifr, sizeof ifr);
1469                 if (IFP_IS_ETH(ifp))
1470                         snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
1471                             ethno++);
1472                 else
1473                         snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "%s%d",
1474                             ifp->if_name, ifp->if_unit);
1475
1476                 /* Walk the address list */
1477                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1478                         struct sockaddr *sa = ifa->ifa_addr;
1479
1480                         if (uio.uio_resid <= 0)
1481                                 break;
1482
1483                         if (sa->sa_family == AF_INET) {
1484                                 ifr.ifr_addr.sa_family = LINUX_AF_INET;
1485                                 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
1486                                     sizeof(ifr.ifr_addr.sa_data));
1487
1488                                 error = uiomove((caddr_t)&ifr, sizeof ifr,
1489                                     &uio);
1490                                 if (error != 0)
1491                                         return (error);
1492                         }
1493                 }
1494         }
1495
1496         ifc.ifc_len -= uio.uio_resid;
1497         error = copyout(&ifc, uifc, sizeof ifc);
1498
1499         return (error);
1500 }
1501
1502 static int
1503 linux_gifflags(struct proc *p, struct ifnet *ifp, struct l_ifreq *ifr)
1504 {
1505         l_short flags;
1506
1507         flags = ifp->if_flags;
1508         /* these flags have no Linux equivalent */
1509         flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1510             IFF_LINK0|IFF_LINK1|IFF_LINK2);
1511         /* Linux' multicast flag is in a different bit */
1512         if (flags & IFF_MULTICAST) {
1513                 flags &= ~IFF_MULTICAST;
1514                 flags |= 0x1000;
1515         }
1516
1517         return (copyout(&flags, &ifr->ifr_flags, sizeof flags));
1518 }
1519
1520 #define ARPHRD_ETHER    1
1521 #define ARPHRD_LOOPBACK 772
1522
1523 static int
1524 linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
1525 {
1526         struct ifaddr *ifa;
1527         struct sockaddr_dl *sdl;
1528         struct l_sockaddr lsa;
1529
1530         if (ifp->if_type == IFT_LOOP) {
1531                 bzero(&lsa, sizeof lsa);
1532                 lsa.sa_family = ARPHRD_LOOPBACK;
1533                 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1534         }
1535         
1536         if (ifp->if_type != IFT_ETHER)
1537                 return (ENOENT);
1538
1539         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1540                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1541                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1542                     (sdl->sdl_type == IFT_ETHER)) {
1543                         bzero(&lsa, sizeof lsa);
1544                         lsa.sa_family = ARPHRD_ETHER;
1545                         bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
1546                         return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1547                 }
1548         }
1549         
1550         return (ENOENT);
1551 }
1552
1553 /*
1554  * Socket related ioctls
1555  */
1556
1557 static int
1558 linux_ioctl_socket(struct proc *p, struct linux_ioctl_args *args)
1559 {
1560         char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
1561         struct ifnet *ifp;
1562         struct file *fp;
1563         int error, type;
1564
1565         KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1566             (__FUNCTION__ "(): LINUX_IFNAMSIZ != IFNAMSIZ"));
1567         
1568         ifp = NULL;
1569         error = 0;
1570         
1571         if (args->fd >= p->p_fd->fd_nfiles ||
1572             (fp = p->p_fd->fd_ofiles[args->fd]) == NULL)
1573                 return (EBADF);
1574         type = fp->f_type;
1575
1576         if (type != DTYPE_SOCKET) {
1577                 /* not a socket - probably a tap / vmnet device */
1578                 switch (args->cmd) {
1579                 case LINUX_SIOCGIFADDR:
1580                 case LINUX_SIOCSIFADDR:
1581                 case LINUX_SIOCGIFFLAGS:
1582                         return (linux_ioctl_special(p, args));
1583                 default:
1584                         return (ENOIOCTL);
1585                 }
1586         }
1587
1588         switch (args->cmd & 0xffff) {
1589                 
1590         case LINUX_FIOGETOWN:
1591         case LINUX_FIOSETOWN:
1592         case LINUX_SIOCADDMULTI:
1593         case LINUX_SIOCATMARK:
1594         case LINUX_SIOCDELMULTI:
1595         case LINUX_SIOCGIFCONF:
1596         case LINUX_SIOCGPGRP:
1597         case LINUX_SIOCSPGRP:
1598                 /* these ioctls don't take an interface name */
1599 #ifdef DEBUG
1600                 printf(__FUNCTION__ "(): ioctl %d\n",
1601                     args->cmd & 0xffff);
1602 #endif
1603                 break;
1604                 
1605         case LINUX_SIOCGIFFLAGS:
1606         case LINUX_SIOCGIFADDR:
1607         case LINUX_SIOCSIFADDR:
1608         case LINUX_SIOCGIFDSTADDR:
1609         case LINUX_SIOCGIFBRDADDR:
1610         case LINUX_SIOCGIFNETMASK:
1611         case LINUX_SIOCSIFNETMASK:
1612         case LINUX_SIOCGIFMTU:
1613         case LINUX_SIOCSIFMTU:
1614         case LINUX_SIOCSIFNAME:
1615         case LINUX_SIOCGIFHWADDR:
1616         case LINUX_SIOCSIFHWADDR:
1617         case LINUX_SIOCDEVPRIVATE:
1618         case LINUX_SIOCDEVPRIVATE+1:
1619                 /* copy in the interface name and translate it. */
1620                 error = copyin((char *)args->arg, lifname, LINUX_IFNAMSIZ);
1621                 if (error != 0)
1622                         return (error);
1623 #ifdef DEBUG
1624                 printf(__FUNCTION__ "(): ioctl %d on %.*s\n",
1625                     args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
1626 #endif
1627                 ifp = ifname_linux_to_bsd(lifname, ifname);
1628                 if (ifp == NULL)
1629                         return (EINVAL);
1630                 /*
1631                  * We need to copy it back out in case we pass the
1632                  * request on to our native ioctl(), which will expect
1633                  * the ifreq to be in user space and have the correct
1634                  * interface name.
1635                  */
1636                 error = copyout(ifname, (char *)args->arg, IFNAMSIZ);
1637                 if (error != 0)
1638                         return (error);
1639 #ifdef DEBUG
1640                 printf(__FUNCTION__ "(): %s translated to %s\n",
1641                     lifname, ifname);
1642 #endif
1643                 break;
1644                 
1645         default:
1646                 return (ENOIOCTL);
1647         }
1648
1649         switch (args->cmd & 0xffff) {
1650
1651         case LINUX_FIOSETOWN:
1652                 args->cmd = FIOSETOWN;
1653                 error = ioctl(p, (struct ioctl_args *)args);
1654                 break;
1655
1656         case LINUX_SIOCSPGRP:
1657                 args->cmd = SIOCSPGRP;
1658                 error = ioctl(p, (struct ioctl_args *)args);
1659                 break;
1660
1661         case LINUX_FIOGETOWN:
1662                 args->cmd = FIOGETOWN;
1663                 error = ioctl(p, (struct ioctl_args *)args);
1664                 break;
1665
1666         case LINUX_SIOCGPGRP:
1667                 args->cmd = SIOCGPGRP;
1668                 error = ioctl(p, (struct ioctl_args *)args);
1669                 break;
1670
1671         case LINUX_SIOCATMARK:
1672                 args->cmd = SIOCATMARK;
1673                 error = ioctl(p, (struct ioctl_args *)args);
1674                 break;
1675
1676         /* LINUX_SIOCGSTAMP */
1677
1678         case LINUX_SIOCGIFCONF:
1679                 error = linux_ifconf(p, (struct ifconf *)args->arg);
1680                 break;
1681
1682         case LINUX_SIOCGIFFLAGS:
1683                 args->cmd = SIOCGIFFLAGS;
1684                 error = linux_gifflags(p, ifp, (struct l_ifreq *)args->arg);
1685                 break;
1686
1687         case LINUX_SIOCGIFADDR:
1688                 args->cmd = OSIOCGIFADDR;
1689                 error = ioctl(p, (struct ioctl_args *)args);
1690                 break;
1691
1692         case LINUX_SIOCSIFADDR:
1693                 /* XXX probably doesn't work, included for completeness */
1694                 args->cmd = SIOCSIFADDR;
1695                 error = ioctl(p, (struct ioctl_args *)args);
1696                 break;
1697
1698         case LINUX_SIOCGIFDSTADDR:
1699                 args->cmd = OSIOCGIFDSTADDR;
1700                 error = ioctl(p, (struct ioctl_args *)args);
1701                 break;
1702
1703         case LINUX_SIOCGIFBRDADDR:
1704                 args->cmd = OSIOCGIFBRDADDR;
1705                 error = ioctl(p, (struct ioctl_args *)args);
1706                 break;
1707
1708         case LINUX_SIOCGIFNETMASK:
1709                 args->cmd = OSIOCGIFNETMASK;
1710                 error = ioctl(p, (struct ioctl_args *)args);
1711                 break;
1712
1713         case LINUX_SIOCSIFNETMASK:
1714                 error = ENOIOCTL;
1715                 break;
1716                 
1717         case LINUX_SIOCGIFMTU:
1718                 args->cmd = SIOCGIFMTU;
1719                 error = ioctl(p, (struct ioctl_args *)args);
1720                 break;
1721                 
1722         case LINUX_SIOCSIFMTU:
1723                 args->cmd = SIOCSIFMTU;
1724                 error = ioctl(p, (struct ioctl_args *)args);
1725                 break;
1726                 
1727         case LINUX_SIOCSIFNAME:
1728                 error = ENOIOCTL;
1729                 break;
1730                 
1731         case LINUX_SIOCGIFHWADDR:
1732                 error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
1733                 break;
1734
1735         case LINUX_SIOCSIFHWADDR:
1736                 error = ENOIOCTL;
1737                 break;
1738                 
1739         case LINUX_SIOCADDMULTI:
1740                 args->cmd = SIOCADDMULTI;
1741                 error = ioctl(p, (struct ioctl_args *)args);
1742                 break;
1743
1744         case LINUX_SIOCDELMULTI:
1745                 args->cmd = SIOCDELMULTI;
1746                 error = ioctl(p, (struct ioctl_args *)args);
1747                 break;
1748
1749         /*
1750          * XXX This is slightly bogus, but these ioctls are currently
1751          * XXX only used by the aironet (if_an) network driver.
1752          */
1753         case LINUX_SIOCDEVPRIVATE:
1754                 args->cmd = SIOCGPRIVATE_0;
1755                 error = ioctl(p, (struct ioctl_args *)args);
1756                 break;
1757                 
1758         case LINUX_SIOCDEVPRIVATE+1:
1759                 args->cmd = SIOCGPRIVATE_1;
1760                 error = ioctl(p, (struct ioctl_args *)args);
1761                 break;
1762         }
1763
1764         if (ifp != NULL)
1765                 /* restore the original interface name */
1766                 copyout(lifname, (char *)args->arg, LINUX_IFNAMSIZ);
1767
1768 #ifdef DEBUG
1769         printf(__FUNCTION__ "(): returning %d\n", error);
1770 #endif
1771         return (error);
1772 }
1773
1774 /*
1775  * Device private ioctl handler
1776  */
1777 static int
1778 linux_ioctl_private(struct proc *p, struct linux_ioctl_args *args)
1779 {
1780         struct filedesc *fdp;
1781         struct file *fp;
1782         int type;
1783
1784         fdp = p->p_fd;
1785         if (args->fd >= fdp->fd_nfiles ||
1786             (fp = fdp->fd_ofiles[args->fd]) == NULL) {
1787                 return (EBADF);
1788         } else {
1789                 type = fp->f_type;
1790         }
1791         if (type == DTYPE_SOCKET)
1792                 return (linux_ioctl_socket(p, args));
1793         return (ENOIOCTL);
1794 }
1795
1796 /*
1797  * DRM ioctl handler (sys/dev/drm)
1798  */
1799 static int
1800 linux_ioctl_drm(struct proc *p, struct linux_ioctl_args *args)
1801 {
1802         args->cmd = SETDIR(args->cmd);
1803         return ioctl(p, (struct ioctl_args *)args);
1804 }
1805
1806 /*
1807  * Special ioctl handler
1808  */
1809 static int
1810 linux_ioctl_special(struct proc *p, struct linux_ioctl_args *args)
1811 {
1812         int error;
1813
1814         switch (args->cmd) {
1815         case LINUX_SIOCGIFADDR:
1816                 args->cmd = SIOCGIFADDR;
1817                 error = ioctl(p, (struct ioctl_args *)args);
1818                 break;
1819         case LINUX_SIOCSIFADDR:
1820                 args->cmd = SIOCSIFADDR;
1821                 error = ioctl(p, (struct ioctl_args *)args);
1822                 break;
1823         case LINUX_SIOCGIFFLAGS:
1824                 args->cmd = SIOCGIFFLAGS;
1825                 error = ioctl(p, (struct ioctl_args *)args);
1826                 break;
1827         default:
1828                 error = ENOIOCTL;
1829         }
1830
1831         return (error);
1832 }
1833
1834 /*
1835  * main ioctl syscall function
1836  */
1837
1838 int
1839 linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
1840 {
1841         struct filedesc *fdp;
1842         struct file *fp;
1843         struct handler_element *he;
1844         int error, cmd;
1845
1846 #ifdef DEBUG
1847         if (ldebug(ioctl))
1848                 printf(ARGS(ioctl, "%d, %04lx, *"), args->fd, args->cmd);
1849 #endif
1850
1851         fdp = p->p_fd;
1852         if ((unsigned)args->fd >= fdp->fd_nfiles)
1853                 return (EBADF);
1854         fp = fdp->fd_ofiles[args->fd];
1855         if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0)
1856                 return (EBADF);
1857
1858         /* Iterate over the ioctl handlers */
1859         cmd = args->cmd & 0xffff;
1860         TAILQ_FOREACH(he, &handlers, list) {
1861                 if (cmd >= he->low && cmd <= he->high) {
1862                         error = (*he->func)(p, args);
1863                         if (error != ENOIOCTL)
1864                                 return (error);
1865                 }
1866         }
1867
1868         printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n",
1869             args->fd, (int)(args->cmd & 0xffff),
1870             (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
1871
1872         return (EINVAL);
1873 }
1874
1875 int
1876 linux_ioctl_register_handlers(struct linker_set *s)
1877 {
1878         int error, i;
1879
1880         if (s == NULL)
1881                 return (EINVAL);
1882
1883         for (i = 0; i < s->ls_length; i++) {
1884                 error = linux_ioctl_register_handler(s->ls_items[i]);
1885                 if (error)
1886                         return (error);
1887         }
1888
1889         return (0);
1890 }
1891
1892 int
1893 linux_ioctl_unregister_handlers(struct linker_set *s)
1894 {
1895         int error, i;
1896
1897         if (s == NULL)
1898                 return (EINVAL);
1899
1900         for (i = 0; i < s->ls_length; i++) {
1901                 error = linux_ioctl_unregister_handler(s->ls_items[i]);
1902                 if (error)
1903                         return (error);
1904         }
1905
1906         return (0);
1907 }
1908
1909 int
1910 linux_ioctl_register_handler(struct linux_ioctl_handler *h)
1911 {
1912         struct handler_element *he, *cur;
1913
1914         if (h == NULL || h->func == NULL)
1915                 return (EINVAL);
1916
1917         /*
1918          * Reuse the element if the handler is already on the list, otherwise
1919          * create a new element.
1920          */
1921         TAILQ_FOREACH(he, &handlers, list) {
1922                 if (he->func == h->func)
1923                         break;
1924         }
1925         if (he == NULL) {
1926                 MALLOC(he, struct handler_element *, sizeof(*he),
1927                     M_LINUX, M_WAITOK);
1928                 he->func = h->func;
1929         } else
1930                 TAILQ_REMOVE(&handlers, he, list);
1931         
1932         /* Initialize range information. */
1933         he->low = h->low;
1934         he->high = h->high;
1935         he->span = h->high - h->low + 1;
1936
1937         /* Add the element to the list, sorted on span. */
1938         TAILQ_FOREACH(cur, &handlers, list) {
1939                 if (cur->span > he->span) {
1940                         TAILQ_INSERT_BEFORE(cur, he, list);
1941                         return (0);
1942                 }
1943         }
1944         TAILQ_INSERT_TAIL(&handlers, he, list);
1945
1946         return (0);
1947 }
1948
1949 int
1950 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
1951 {
1952         struct handler_element *he;
1953
1954         if (h == NULL || h->func == NULL)
1955                 return (EINVAL);
1956
1957         TAILQ_FOREACH(he, &handlers, list) {
1958                 if (he->func == h->func) {
1959                         TAILQ_REMOVE(&handlers, he, list);
1960                         FREE(he, M_LINUX);
1961                         return (0);
1962                 }
1963         }
1964
1965         return (EINVAL);
1966 }