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