Merge from vendor branch OPENSSH:
[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.14 2004/07/11 04:47:07 drhodus 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;
947                 struct ioc_read_toc_single_entry irtse;
948
949                 error = copyin((caddr_t)args->arg, &lte, sizeof(lte));
950                 if (error)
951                         return (error);
952                 irtse.address_format = lte.cdte_format;
953                 irtse.track = lte.cdte_track;
954                 error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, td);
955                 if (!error) {
956                         lte.cdte_ctrl = irtse.entry.control;
957                         lte.cdte_adr = irtse.entry.addr_type;
958                         bsd_to_linux_msf_lba(irtse.address_format,
959                             &irtse.entry.addr, &lte.cdte_addr);
960                         error = copyout(&lte, (caddr_t)args->arg, sizeof(lte));
961                 }
962                 return (error);
963         }
964
965         case LINUX_CDROMSTOP:
966                 args->cmd = CDIOCSTOP;
967                 return (ioctl((struct ioctl_args *)args));
968
969         case LINUX_CDROMSTART:
970                 args->cmd = CDIOCSTART;
971                 return (ioctl((struct ioctl_args *)args));
972
973         case LINUX_CDROMEJECT:
974                 args->cmd = CDIOCEJECT;
975                 return (ioctl((struct ioctl_args *)args));
976
977         /* LINUX_CDROMVOLCTRL */
978
979         case LINUX_CDROMSUBCHNL: {
980                 struct linux_cdrom_subchnl sc;
981                 struct ioc_read_subchannel bsdsc;
982                 struct cd_sub_channel_info *bsdinfo;
983                 caddr_t sg = stackgap_init();
984                 bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg,
985                     sizeof(struct cd_sub_channel_info));
986                 bsdsc.address_format = CD_LBA_FORMAT;
987                 bsdsc.data_format = CD_CURRENT_POSITION;
988                 bsdsc.track = 0;
989                 bsdsc.data_len = sizeof(struct cd_sub_channel_info);
990                 bsdsc.data = bsdinfo;
991                 error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, td);
992                 if (error)
993                         return (error);
994                 error = copyin((caddr_t)args->arg, &sc,
995                     sizeof(struct linux_cdrom_subchnl));
996                 if (error)
997                         return (error);
998                 sc.cdsc_audiostatus = bsdinfo->header.audio_status;
999                 sc.cdsc_adr = bsdinfo->what.position.addr_type;
1000                 sc.cdsc_ctrl = bsdinfo->what.position.control;
1001                 sc.cdsc_trk = bsdinfo->what.position.track_number;
1002                 sc.cdsc_ind = bsdinfo->what.position.index_number;
1003                 set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
1004                     bsdinfo->what.position.absaddr.lba);
1005                 set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
1006                     bsdinfo->what.position.reladdr.lba);
1007                 error = copyout(&sc, (caddr_t)args->arg,
1008                     sizeof(struct linux_cdrom_subchnl));
1009                 return (error);
1010         }
1011
1012         /* LINUX_CDROMREADMODE2 */
1013         /* LINUX_CDROMREADMODE1 */
1014         /* LINUX_CDROMREADAUDIO */
1015         /* LINUX_CDROMEJECT_SW */
1016         /* LINUX_CDROMMULTISESSION */
1017         /* LINUX_CDROM_GET_UPC */
1018
1019         case LINUX_CDROMRESET:
1020                 args->cmd = CDIOCRESET;
1021                 return (ioctl((struct ioctl_args *)args));
1022
1023         /* LINUX_CDROMVOLREAD */
1024         /* LINUX_CDROMREADRAW */
1025         /* LINUX_CDROMREADCOOKED */
1026         /* LINUX_CDROMSEEK */
1027         /* LINUX_CDROMPLAYBLK */
1028         /* LINUX_CDROMREADALL */
1029         /* LINUX_CDROMCLOSETRAY */
1030         /* LINUX_CDROMLOADFROMSLOT */
1031
1032         }
1033
1034         return (ENOIOCTL);
1035 }
1036
1037 /*
1038  * Sound related ioctls
1039  */
1040
1041 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1042
1043 #define SETDIR(c)       (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1044
1045 static int
1046 linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
1047 {
1048
1049         switch (args->cmd & 0xffff) {
1050
1051         case LINUX_SOUND_MIXER_WRITE_VOLUME:
1052                 args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1053                 return (ioctl((struct ioctl_args *)args));
1054
1055         case LINUX_SOUND_MIXER_WRITE_BASS:
1056                 args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1057                 return (ioctl((struct ioctl_args *)args));
1058
1059         case LINUX_SOUND_MIXER_WRITE_TREBLE:
1060                 args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1061                 return (ioctl((struct ioctl_args *)args));
1062
1063         case LINUX_SOUND_MIXER_WRITE_SYNTH:
1064                 args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1065                 return (ioctl((struct ioctl_args *)args));
1066
1067         case LINUX_SOUND_MIXER_WRITE_PCM:
1068                 args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1069                 return (ioctl((struct ioctl_args *)args));
1070
1071         case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1072                 args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1073                 return (ioctl((struct ioctl_args *)args));
1074
1075         case LINUX_SOUND_MIXER_WRITE_LINE:
1076                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1077                 return (ioctl((struct ioctl_args *)args));
1078
1079         case LINUX_SOUND_MIXER_WRITE_MIC:
1080                 args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1081                 return (ioctl((struct ioctl_args *)args));
1082
1083         case LINUX_SOUND_MIXER_WRITE_CD:
1084                 args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1085                 return (ioctl((struct ioctl_args *)args));
1086
1087         case LINUX_SOUND_MIXER_WRITE_IMIX:
1088                 args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1089                 return (ioctl((struct ioctl_args *)args));
1090
1091         case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1092                 args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1093                 return (ioctl((struct ioctl_args *)args));
1094
1095         case LINUX_SOUND_MIXER_WRITE_RECLEV:
1096                 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1097                 return (ioctl((struct ioctl_args *)args));
1098
1099         case LINUX_SOUND_MIXER_WRITE_IGAIN:
1100                 args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1101                 return (ioctl((struct ioctl_args *)args));
1102
1103         case LINUX_SOUND_MIXER_WRITE_OGAIN:
1104                 args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1105                 return (ioctl((struct ioctl_args *)args));
1106
1107         case LINUX_SOUND_MIXER_WRITE_LINE1:
1108                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1109                 return (ioctl((struct ioctl_args *)args));
1110
1111         case LINUX_SOUND_MIXER_WRITE_LINE2:
1112                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1113                 return (ioctl((struct ioctl_args *)args));
1114
1115         case LINUX_SOUND_MIXER_WRITE_LINE3:
1116                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1117                 return (ioctl((struct ioctl_args *)args));
1118
1119         case LINUX_OSS_GETVERSION: {
1120                 int version = linux_get_oss_version(td);
1121                 return (copyout(&version, (caddr_t)args->arg, sizeof(int)));
1122         }
1123
1124         case LINUX_SOUND_MIXER_READ_DEVMASK:
1125                 args->cmd = SOUND_MIXER_READ_DEVMASK;
1126                 return (ioctl((struct ioctl_args *)args));
1127
1128         case LINUX_SNDCTL_DSP_RESET:
1129                 args->cmd = SNDCTL_DSP_RESET;
1130                 return (ioctl((struct ioctl_args *)args));
1131
1132         case LINUX_SNDCTL_DSP_SYNC:
1133                 args->cmd = SNDCTL_DSP_SYNC;
1134                 return (ioctl((struct ioctl_args *)args));
1135
1136         case LINUX_SNDCTL_DSP_SPEED:
1137                 args->cmd = SNDCTL_DSP_SPEED;
1138                 return (ioctl((struct ioctl_args *)args));
1139
1140         case LINUX_SNDCTL_DSP_STEREO:
1141                 args->cmd = SNDCTL_DSP_STEREO;
1142                 return (ioctl((struct ioctl_args *)args));
1143
1144         case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1145                 args->cmd = SNDCTL_DSP_GETBLKSIZE;
1146                 return (ioctl((struct ioctl_args *)args));
1147
1148         case LINUX_SNDCTL_DSP_SETFMT:
1149                 args->cmd = SNDCTL_DSP_SETFMT;
1150                 return (ioctl((struct ioctl_args *)args));
1151
1152         case LINUX_SOUND_PCM_WRITE_CHANNELS:
1153                 args->cmd = SOUND_PCM_WRITE_CHANNELS;
1154                 return (ioctl((struct ioctl_args *)args));
1155
1156         case LINUX_SOUND_PCM_WRITE_FILTER:
1157                 args->cmd = SOUND_PCM_WRITE_FILTER;
1158                 return (ioctl((struct ioctl_args *)args));
1159
1160         case LINUX_SNDCTL_DSP_POST:
1161                 args->cmd = SNDCTL_DSP_POST;
1162                 return (ioctl((struct ioctl_args *)args));
1163
1164         case LINUX_SNDCTL_DSP_SUBDIVIDE:
1165                 args->cmd = SNDCTL_DSP_SUBDIVIDE;
1166                 return (ioctl((struct ioctl_args *)args));
1167
1168         case LINUX_SNDCTL_DSP_SETFRAGMENT:
1169                 args->cmd = SNDCTL_DSP_SETFRAGMENT;
1170                 return (ioctl((struct ioctl_args *)args));
1171
1172         case LINUX_SNDCTL_DSP_GETFMTS:
1173                 args->cmd = SNDCTL_DSP_GETFMTS;
1174                 return (ioctl((struct ioctl_args *)args));
1175
1176         case LINUX_SNDCTL_DSP_GETOSPACE:
1177                 args->cmd = SNDCTL_DSP_GETOSPACE;
1178                 return (ioctl((struct ioctl_args *)args));
1179
1180         case LINUX_SNDCTL_DSP_GETISPACE:
1181                 args->cmd = SNDCTL_DSP_GETISPACE;
1182                 return (ioctl((struct ioctl_args *)args));
1183
1184         case LINUX_SNDCTL_DSP_NONBLOCK:
1185                 args->cmd = SNDCTL_DSP_NONBLOCK;
1186                 return (ioctl((struct ioctl_args *)args));
1187
1188         case LINUX_SNDCTL_DSP_GETCAPS:
1189                 args->cmd = SNDCTL_DSP_GETCAPS;
1190                 return (ioctl((struct ioctl_args *)args));
1191
1192         case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1193                 args->cmd = SNDCTL_DSP_SETTRIGGER;
1194                 return (ioctl((struct ioctl_args *)args));
1195
1196         case LINUX_SNDCTL_DSP_GETIPTR:
1197                 args->cmd = SNDCTL_DSP_GETIPTR;
1198                 return (ioctl((struct ioctl_args *)args));
1199
1200         case LINUX_SNDCTL_DSP_GETOPTR:
1201                 args->cmd = SNDCTL_DSP_GETOPTR;
1202                 return (ioctl((struct ioctl_args *)args));
1203
1204         case LINUX_SNDCTL_DSP_GETODELAY:
1205                 args->cmd = SNDCTL_DSP_GETODELAY;
1206                 return (ioctl((struct ioctl_args *)args));
1207
1208         case LINUX_SNDCTL_SEQ_RESET:
1209                 args->cmd = SNDCTL_SEQ_RESET;
1210                 return (ioctl((struct ioctl_args *)args));
1211
1212         case LINUX_SNDCTL_SEQ_SYNC:
1213                 args->cmd = SNDCTL_SEQ_SYNC;
1214                 return (ioctl((struct ioctl_args *)args));
1215
1216         case LINUX_SNDCTL_SYNTH_INFO:
1217                 args->cmd = SNDCTL_SYNTH_INFO;
1218                 return (ioctl((struct ioctl_args *)args));
1219
1220         case LINUX_SNDCTL_SEQ_CTRLRATE:
1221                 args->cmd = SNDCTL_SEQ_CTRLRATE;
1222                 return (ioctl((struct ioctl_args *)args));
1223
1224         case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1225                 args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1226                 return (ioctl((struct ioctl_args *)args));
1227
1228         case LINUX_SNDCTL_SEQ_GETINCOUNT:
1229                 args->cmd = SNDCTL_SEQ_GETINCOUNT;
1230                 return (ioctl((struct ioctl_args *)args));
1231
1232         case LINUX_SNDCTL_SEQ_PERCMODE:
1233                 args->cmd = SNDCTL_SEQ_PERCMODE;
1234                 return (ioctl((struct ioctl_args *)args));
1235
1236         case LINUX_SNDCTL_FM_LOAD_INSTR:
1237                 args->cmd = SNDCTL_FM_LOAD_INSTR;
1238                 return (ioctl((struct ioctl_args *)args));
1239
1240         case LINUX_SNDCTL_SEQ_TESTMIDI:
1241                 args->cmd = SNDCTL_SEQ_TESTMIDI;
1242                 return (ioctl((struct ioctl_args *)args));
1243
1244         case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1245                 args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1246                 return (ioctl((struct ioctl_args *)args));
1247
1248         case LINUX_SNDCTL_SEQ_NRSYNTHS:
1249                 args->cmd = SNDCTL_SEQ_NRSYNTHS;
1250                 return (ioctl((struct ioctl_args *)args));
1251
1252         case LINUX_SNDCTL_SEQ_NRMIDIS:
1253                 args->cmd = SNDCTL_SEQ_NRMIDIS;
1254                 return (ioctl((struct ioctl_args *)args));
1255
1256         case LINUX_SNDCTL_MIDI_INFO:
1257                 args->cmd = SNDCTL_MIDI_INFO;
1258                 return (ioctl((struct ioctl_args *)args));
1259
1260         case LINUX_SNDCTL_SEQ_TRESHOLD:
1261                 args->cmd = SNDCTL_SEQ_TRESHOLD;
1262                 return (ioctl((struct ioctl_args *)args));
1263
1264         case LINUX_SNDCTL_SYNTH_MEMAVL:
1265                 args->cmd = SNDCTL_SYNTH_MEMAVL;
1266                 return (ioctl((struct ioctl_args *)args));
1267
1268         }
1269
1270         return (ENOIOCTL);
1271 }
1272
1273 /*
1274  * Console related ioctls
1275  */
1276
1277 #define ISSIGVALID(sig)         ((sig) > 0 && (sig) < NSIG)
1278
1279 static int
1280 linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
1281 {
1282         struct file *fp;
1283         int error;
1284
1285         KKASSERT(td->td_proc);
1286         fp = td->td_proc->p_fd->fd_ofiles[args->fd];
1287
1288         switch (args->cmd & 0xffff) {
1289
1290         case LINUX_KIOCSOUND:
1291                 args->cmd = KIOCSOUND;
1292                 return (ioctl((struct ioctl_args *)args));
1293
1294         case LINUX_KDMKTONE:
1295                 args->cmd = KDMKTONE;
1296                 return (ioctl((struct ioctl_args *)args));
1297
1298         case LINUX_KDGETLED:
1299                 args->cmd = KDGETLED;
1300                 return (ioctl((struct ioctl_args *)args));
1301
1302         case LINUX_KDSETLED:
1303                 args->cmd = KDSETLED;
1304                 return (ioctl((struct ioctl_args *)args));
1305
1306         case LINUX_KDSETMODE:
1307                 args->cmd = KDSETMODE;
1308                 return (ioctl((struct ioctl_args *)args));
1309
1310         case LINUX_KDGETMODE:
1311                 args->cmd = KDGETMODE;
1312                 return (ioctl((struct ioctl_args *)args));
1313
1314         case LINUX_KDGKBMODE:
1315                 args->cmd = KDGKBMODE;
1316                 return (ioctl((struct ioctl_args *)args));
1317
1318         case LINUX_KDSKBMODE: {
1319                 int kbdmode;
1320                 switch (args->arg) {
1321                 case LINUX_KBD_RAW:
1322                         kbdmode = K_RAW;
1323                         break;
1324                 case LINUX_KBD_XLATE:
1325                         kbdmode = K_XLATE;
1326                         break;
1327                 case LINUX_KBD_MEDIUMRAW:
1328                         kbdmode = K_RAW;
1329                         break;
1330                 default:
1331                         return (EINVAL);
1332                 }
1333                 return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, td));
1334         }
1335
1336         case LINUX_VT_OPENQRY:
1337                 args->cmd = VT_OPENQRY;
1338                 return (ioctl((struct ioctl_args *)args));
1339
1340         case LINUX_VT_GETMODE:
1341                 args->cmd = VT_GETMODE;
1342                 return  (ioctl((struct ioctl_args *)args));
1343
1344         case LINUX_VT_SETMODE: {
1345                 struct vt_mode mode;
1346                 error = copyin((caddr_t)args->arg, &mode, sizeof(mode));
1347                 if (error)
1348                         return (error);
1349                 if (!ISSIGVALID(mode.frsig) && ISSIGVALID(mode.acqsig))
1350                         mode.frsig = mode.acqsig;
1351                 error = copyout(&mode, (caddr_t)args->arg, sizeof(mode));
1352                 if (error)
1353                         return (error);
1354                 args->cmd = VT_SETMODE;
1355                 return (ioctl((struct ioctl_args *)args));
1356         }
1357
1358         case LINUX_VT_GETSTATE:
1359                 args->cmd = VT_GETACTIVE;
1360                 return (ioctl((struct ioctl_args *)args));
1361
1362         case LINUX_VT_RELDISP:
1363                 args->cmd = VT_RELDISP;
1364                 return (ioctl((struct ioctl_args *)args));
1365
1366         case LINUX_VT_ACTIVATE:
1367                 args->cmd = VT_ACTIVATE;
1368                 return (ioctl((struct ioctl_args *)args));
1369
1370         case LINUX_VT_WAITACTIVE:
1371                 args->cmd = VT_WAITACTIVE;
1372                 return (ioctl((struct ioctl_args *)args));
1373
1374         }
1375         
1376         return (ENOIOCTL);
1377 }
1378
1379 /*
1380  * Criteria for interface name translation
1381  */
1382 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1383
1384 /*
1385  * Interface function used by linprocfs (at the time of writing). It's not
1386  * used by the Linuxulator itself.
1387  */
1388 int
1389 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1390 {
1391         struct ifnet *ifscan;
1392         int ethno;
1393
1394         /* Short-circuit non ethernet interfaces */
1395         if (!IFP_IS_ETH(ifp))
1396                 return (strlcpy(buffer, ifp->if_xname, buflen));
1397
1398         /* Determine the (relative) unit number for ethernet interfaces */
1399         ethno = 0;
1400         TAILQ_FOREACH(ifscan, &ifnet, if_link) {
1401                 if (ifscan == ifp)
1402                         return (snprintf(buffer, buflen, "eth%d", ethno));
1403                 if (IFP_IS_ETH(ifscan))
1404                         ethno++;
1405         }
1406
1407         return (0);
1408 }
1409
1410 /*
1411  * Translate a Linux interface name to a FreeBSD interface name,
1412  * and return the associated ifnet structure
1413  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
1414  * can point to the same buffer.
1415  */
1416
1417 static struct ifnet *
1418 ifname_linux_to_bsd(const char *lxname, char *bsdname)
1419 {
1420         struct ifnet *ifp;
1421         int len, unit;
1422         char *ep;
1423         int is_eth, index;
1424
1425         for (len = 0; len < LINUX_IFNAMSIZ; ++len)
1426                 if (!isalpha(lxname[len]))
1427                         break;
1428         if (len == 0 || len == LINUX_IFNAMSIZ)
1429                 return (NULL);
1430         unit = (int)strtoul(lxname + len, &ep, 10);
1431         if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
1432                 return (NULL);
1433         index = 0;
1434         is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
1435         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1436                 /*
1437                  * Allow Linux programs to use FreeBSD names. Don't presume
1438                  * we never have an interface named "eth", so don't make
1439                  * the test optional based on is_eth.
1440                  */
1441                 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
1442                         break;
1443                 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
1444                         break;
1445         }
1446         if (ifp != NULL)
1447                 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
1448         return (ifp);
1449 }
1450
1451 /*
1452  * Implement the SIOCGIFCONF ioctl
1453  */
1454
1455 static int
1456 linux_ifconf(struct proc *p, struct ifconf *uifc)
1457 {
1458         struct ifconf ifc;
1459         struct l_ifreq ifr;
1460         struct ifnet *ifp;
1461         struct ifaddr *ifa;
1462         struct iovec iov;
1463         struct uio uio;
1464         int error, ethno;
1465         struct thread *td = p->p_thread;
1466
1467         error = copyin(uifc, &ifc, sizeof ifc);
1468         if (error != 0)
1469                 return (error);
1470
1471         /* much easier to use uiomove than keep track ourselves */
1472         iov.iov_base = ifc.ifc_buf;
1473         iov.iov_len = ifc.ifc_len;
1474         uio.uio_iov = &iov;
1475         uio.uio_iovcnt = 1;
1476         uio.uio_offset = 0;
1477         uio.uio_resid = ifc.ifc_len;
1478         uio.uio_segflg = UIO_USERSPACE;
1479         uio.uio_rw = UIO_READ;
1480         uio.uio_td = td;
1481
1482         /* Keep track of eth interfaces */
1483         ethno = 0;
1484
1485         /* Return all AF_INET addresses of all interfaces */
1486         TAILQ_FOREACH(ifp, &ifnet, if_link) {
1487                 if (uio.uio_resid <= 0)
1488                         break;
1489
1490                 bzero(&ifr, sizeof ifr);
1491                 if (IFP_IS_ETH(ifp))
1492                         snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
1493                             ethno++);
1494                 else
1495                         strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
1496
1497                 /* Walk the address list */
1498                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1499                         struct sockaddr *sa = ifa->ifa_addr;
1500
1501                         if (uio.uio_resid <= 0)
1502                                 break;
1503
1504                         if (sa->sa_family == AF_INET) {
1505                                 ifr.ifr_addr.sa_family = LINUX_AF_INET;
1506                                 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
1507                                     sizeof(ifr.ifr_addr.sa_data));
1508
1509                                 error = uiomove((caddr_t)&ifr, sizeof ifr,
1510                                     &uio);
1511                                 if (error != 0)
1512                                         return (error);
1513                         }
1514                 }
1515         }
1516
1517         ifc.ifc_len -= uio.uio_resid;
1518         error = copyout(&ifc, uifc, sizeof ifc);
1519
1520         return (error);
1521 }
1522
1523 static int
1524 linux_gifflags(struct proc *p, struct ifnet *ifp, struct l_ifreq *ifr)
1525 {
1526         l_short flags;
1527
1528         flags = ifp->if_flags;
1529         /* these flags have no Linux equivalent */
1530         flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX|
1531             IFF_LINK0|IFF_LINK1|IFF_LINK2);
1532         /* Linux' multicast flag is in a different bit */
1533         if (flags & IFF_MULTICAST) {
1534                 flags &= ~IFF_MULTICAST;
1535                 flags |= 0x1000;
1536         }
1537
1538         return (copyout(&flags, &ifr->ifr_flags, sizeof flags));
1539 }
1540
1541 #define ARPHRD_ETHER    1
1542 #define ARPHRD_LOOPBACK 772
1543
1544 static int
1545 linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
1546 {
1547         struct ifaddr *ifa;
1548         struct sockaddr_dl *sdl;
1549         struct l_sockaddr lsa;
1550
1551         if (ifp->if_type == IFT_LOOP) {
1552                 bzero(&lsa, sizeof lsa);
1553                 lsa.sa_family = ARPHRD_LOOPBACK;
1554                 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1555         }
1556         
1557         if (ifp->if_type != IFT_ETHER)
1558                 return (ENOENT);
1559
1560         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1561                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1562                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
1563                     (sdl->sdl_type == IFT_ETHER)) {
1564                         bzero(&lsa, sizeof lsa);
1565                         lsa.sa_family = ARPHRD_ETHER;
1566                         bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
1567                         return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa));
1568                 }
1569         }
1570         
1571         return (ENOENT);
1572 }
1573
1574 /*
1575  * Socket related ioctls
1576  */
1577
1578 static int
1579 linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
1580 {
1581         struct proc *p = td->td_proc;
1582         char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
1583         struct ifnet *ifp;
1584         struct file *fp;
1585         int error, type;
1586
1587         KKASSERT(p);
1588         KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ,
1589             ("%s(): LINUX_IFNAMSIZ != IFNAMSIZ", __FUNCTION__));
1590         
1591         ifp = NULL;
1592         error = 0;
1593         
1594         if (args->fd >= p->p_fd->fd_nfiles ||
1595             (fp = p->p_fd->fd_ofiles[args->fd]) == NULL)
1596                 return (EBADF);
1597         type = fp->f_type;
1598
1599         if (type != DTYPE_SOCKET) {
1600                 /* not a socket - probably a tap / vmnet device */
1601                 switch (args->cmd) {
1602                 case LINUX_SIOCGIFADDR:
1603                 case LINUX_SIOCSIFADDR:
1604                 case LINUX_SIOCGIFFLAGS:
1605                         return (linux_ioctl_special(td, args));
1606                 default:
1607                         return (ENOIOCTL);
1608                 }
1609         }
1610
1611         switch (args->cmd & 0xffff) {
1612                 
1613         case LINUX_FIOGETOWN:
1614         case LINUX_FIOSETOWN:
1615         case LINUX_SIOCADDMULTI:
1616         case LINUX_SIOCATMARK:
1617         case LINUX_SIOCDELMULTI:
1618         case LINUX_SIOCGIFCONF:
1619         case LINUX_SIOCGPGRP:
1620         case LINUX_SIOCSPGRP:
1621                 /* these ioctls don't take an interface name */
1622 #ifdef DEBUG
1623                 printf("%s(): ioctl %d\n", __FUNCTION__, args->cmd & 0xffff);
1624 #endif
1625                 break;
1626                 
1627         case LINUX_SIOCGIFFLAGS:
1628         case LINUX_SIOCGIFADDR:
1629         case LINUX_SIOCSIFADDR:
1630         case LINUX_SIOCGIFDSTADDR:
1631         case LINUX_SIOCGIFBRDADDR:
1632         case LINUX_SIOCGIFNETMASK:
1633         case LINUX_SIOCSIFNETMASK:
1634         case LINUX_SIOCGIFMTU:
1635         case LINUX_SIOCSIFMTU:
1636         case LINUX_SIOCSIFNAME:
1637         case LINUX_SIOCGIFHWADDR:
1638         case LINUX_SIOCSIFHWADDR:
1639         case LINUX_SIOCDEVPRIVATE:
1640         case LINUX_SIOCDEVPRIVATE+1:
1641                 /* copy in the interface name and translate it. */
1642                 error = copyin((char *)args->arg, lifname, LINUX_IFNAMSIZ);
1643                 if (error != 0)
1644                         return (error);
1645 #ifdef DEBUG
1646                 printf("%s(): ioctl %d on %.*s\n", __FUNCTION__,
1647                         args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
1648 #endif
1649                 ifp = ifname_linux_to_bsd(lifname, ifname);
1650                 if (ifp == NULL)
1651                         return (EINVAL);
1652                 /*
1653                  * We need to copy it back out in case we pass the
1654                  * request on to our native ioctl(), which will expect
1655                  * the ifreq to be in user space and have the correct
1656                  * interface name.
1657                  */
1658                 error = copyout(ifname, (char *)args->arg, IFNAMSIZ);
1659                 if (error != 0)
1660                         return (error);
1661 #ifdef DEBUG
1662                 printf("%s(): %s translated to %s\n", __FUNCTION__,
1663                         lifname, ifname);
1664 #endif
1665                 break;
1666                 
1667         default:
1668                 return (ENOIOCTL);
1669         }
1670
1671         switch (args->cmd & 0xffff) {
1672
1673         case LINUX_FIOSETOWN:
1674                 args->cmd = FIOSETOWN;
1675                 error = ioctl((struct ioctl_args *)args);
1676                 break;
1677
1678         case LINUX_SIOCSPGRP:
1679                 args->cmd = SIOCSPGRP;
1680                 error = ioctl((struct ioctl_args *)args);
1681                 break;
1682
1683         case LINUX_FIOGETOWN:
1684                 args->cmd = FIOGETOWN;
1685                 error = ioctl((struct ioctl_args *)args);
1686                 break;
1687
1688         case LINUX_SIOCGPGRP:
1689                 args->cmd = SIOCGPGRP;
1690                 error = ioctl((struct ioctl_args *)args);
1691                 break;
1692
1693         case LINUX_SIOCATMARK:
1694                 args->cmd = SIOCATMARK;
1695                 error = ioctl((struct ioctl_args *)args);
1696                 break;
1697
1698         /* LINUX_SIOCGSTAMP */
1699
1700         case LINUX_SIOCGIFCONF:
1701                 error = linux_ifconf(p, (struct ifconf *)args->arg);
1702                 break;
1703
1704         case LINUX_SIOCGIFFLAGS:
1705                 args->cmd = SIOCGIFFLAGS;
1706                 error = linux_gifflags(p, ifp, (struct l_ifreq *)args->arg);
1707                 break;
1708
1709         case LINUX_SIOCGIFADDR:
1710                 args->cmd = OSIOCGIFADDR;
1711                 error = ioctl((struct ioctl_args *)args);
1712                 break;
1713
1714         case LINUX_SIOCSIFADDR:
1715                 /* XXX probably doesn't work, included for completeness */
1716                 args->cmd = SIOCSIFADDR;
1717                 error = ioctl((struct ioctl_args *)args);
1718                 break;
1719
1720         case LINUX_SIOCGIFDSTADDR:
1721                 args->cmd = OSIOCGIFDSTADDR;
1722                 error = ioctl((struct ioctl_args *)args);
1723                 break;
1724
1725         case LINUX_SIOCGIFBRDADDR:
1726                 args->cmd = OSIOCGIFBRDADDR;
1727                 error = ioctl((struct ioctl_args *)args);
1728                 break;
1729
1730         case LINUX_SIOCGIFNETMASK:
1731                 args->cmd = OSIOCGIFNETMASK;
1732                 error = ioctl((struct ioctl_args *)args);
1733                 break;
1734
1735         case LINUX_SIOCSIFNETMASK:
1736                 error = ENOIOCTL;
1737                 break;
1738                 
1739         case LINUX_SIOCGIFMTU:
1740                 args->cmd = SIOCGIFMTU;
1741                 error = ioctl((struct ioctl_args *)args);
1742                 break;
1743                 
1744         case LINUX_SIOCSIFMTU:
1745                 args->cmd = SIOCSIFMTU;
1746                 error = ioctl((struct ioctl_args *)args);
1747                 break;
1748                 
1749         case LINUX_SIOCSIFNAME:
1750                 error = ENOIOCTL;
1751                 break;
1752                 
1753         case LINUX_SIOCGIFHWADDR:
1754                 error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
1755                 break;
1756
1757         case LINUX_SIOCSIFHWADDR:
1758                 error = ENOIOCTL;
1759                 break;
1760                 
1761         case LINUX_SIOCADDMULTI:
1762                 args->cmd = SIOCADDMULTI;
1763                 error = ioctl((struct ioctl_args *)args);
1764                 break;
1765
1766         case LINUX_SIOCDELMULTI:
1767                 args->cmd = SIOCDELMULTI;
1768                 error = ioctl((struct ioctl_args *)args);
1769                 break;
1770
1771         /*
1772          * XXX This is slightly bogus, but these ioctls are currently
1773          * XXX only used by the aironet (if_an) network driver.
1774          */
1775         case LINUX_SIOCDEVPRIVATE:
1776                 args->cmd = SIOCGPRIVATE_0;
1777                 error = ioctl((struct ioctl_args *)args);
1778                 break;
1779                 
1780         case LINUX_SIOCDEVPRIVATE+1:
1781                 args->cmd = SIOCGPRIVATE_1;
1782                 error = ioctl((struct ioctl_args *)args);
1783                 break;
1784         }
1785
1786         if (ifp != NULL)
1787                 /* restore the original interface name */
1788                 copyout(lifname, (char *)args->arg, LINUX_IFNAMSIZ);
1789
1790 #ifdef DEBUG
1791         printf("%s(): returning %d\n", __FUNCTION__, error);
1792 #endif
1793         return (error);
1794 }
1795
1796 /*
1797  * Device private ioctl handler
1798  */
1799 static int
1800 linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
1801 {
1802         struct filedesc *fdp;
1803         struct file *fp;
1804         int type;
1805
1806         KKASSERT(td->td_proc);
1807         fdp = td->td_proc->p_fd;
1808         if (args->fd >= fdp->fd_nfiles ||
1809             (fp = fdp->fd_ofiles[args->fd]) == NULL) {
1810                 return (EBADF);
1811         } else {
1812                 type = fp->f_type;
1813         }
1814         if (type == DTYPE_SOCKET)
1815                 return (linux_ioctl_socket(td, args));
1816         return (ENOIOCTL);
1817 }
1818
1819 /*
1820  * DRM ioctl handler (sys/dev/drm)
1821  */
1822 static int
1823 linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
1824 {
1825         args->cmd = SETDIR(args->cmd);
1826         return ioctl((struct ioctl_args *)args);
1827 }
1828
1829 /*
1830  * Special ioctl handler
1831  */
1832 static int
1833 linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
1834 {
1835         int error;
1836
1837         switch (args->cmd) {
1838         case LINUX_SIOCGIFADDR:
1839                 args->cmd = SIOCGIFADDR;
1840                 error = ioctl((struct ioctl_args *)args);
1841                 break;
1842         case LINUX_SIOCSIFADDR:
1843                 args->cmd = SIOCSIFADDR;
1844                 error = ioctl((struct ioctl_args *)args);
1845                 break;
1846         case LINUX_SIOCGIFFLAGS:
1847                 args->cmd = SIOCGIFFLAGS;
1848                 error = ioctl((struct ioctl_args *)args);
1849                 break;
1850         default:
1851                 error = ENOIOCTL;
1852         }
1853
1854         return (error);
1855 }
1856
1857 /*
1858  * main ioctl syscall function
1859  */
1860
1861 int
1862 linux_ioctl(struct linux_ioctl_args *args)
1863 {
1864         struct thread *td = curthread;
1865         struct proc *p = td->td_proc;
1866         struct filedesc *fdp;
1867         struct file *fp;
1868         struct handler_element *he;
1869         int error, cmd;
1870
1871         KKASSERT(p);
1872
1873 #ifdef DEBUG
1874         if (ldebug(ioctl))
1875                 printf(ARGS(ioctl, "%d, %04x, *"), args->fd, args->cmd);
1876 #endif
1877
1878         fdp = p->p_fd;
1879         if ((unsigned)args->fd >= fdp->fd_nfiles)
1880                 return (EBADF);
1881         fp = fdp->fd_ofiles[args->fd];
1882         if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0)
1883                 return (EBADF);
1884
1885         /* Iterate over the ioctl handlers */
1886         cmd = args->cmd & 0xffff;
1887         TAILQ_FOREACH(he, &handlers, list) {
1888                 if (cmd >= he->low && cmd <= he->high) {
1889                         error = (*he->func)(td, args);
1890                         if (error != ENOIOCTL)
1891                                 return (error);
1892                 }
1893         }
1894
1895         printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n",
1896             args->fd, (int)(args->cmd & 0xffff),
1897             (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
1898
1899         return (EINVAL);
1900 }
1901
1902 int
1903 linux_ioctl_register_handler(struct linux_ioctl_handler *h)
1904 {
1905         struct handler_element *he, *cur;
1906
1907         if (h == NULL || h->func == NULL)
1908                 return (EINVAL);
1909
1910         /*
1911          * Reuse the element if the handler is already on the list, otherwise
1912          * create a new element.
1913          */
1914         TAILQ_FOREACH(he, &handlers, list) {
1915                 if (he->func == h->func)
1916                         break;
1917         }
1918         if (he == NULL) {
1919                 MALLOC(he, struct handler_element *, sizeof(*he),
1920                     M_LINUX, M_WAITOK);
1921                 he->func = h->func;
1922         } else
1923                 TAILQ_REMOVE(&handlers, he, list);
1924         
1925         /* Initialize range information. */
1926         he->low = h->low;
1927         he->high = h->high;
1928         he->span = h->high - h->low + 1;
1929
1930         /* Add the element to the list, sorted on span. */
1931         TAILQ_FOREACH(cur, &handlers, list) {
1932                 if (cur->span > he->span) {
1933                         TAILQ_INSERT_BEFORE(cur, he, list);
1934                         return (0);
1935                 }
1936         }
1937         TAILQ_INSERT_TAIL(&handlers, he, list);
1938
1939         return (0);
1940 }
1941
1942 int
1943 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
1944 {
1945         struct handler_element *he;
1946
1947         if (h == NULL || h->func == NULL)
1948                 return (EINVAL);
1949
1950         TAILQ_FOREACH(he, &handlers, list) {
1951                 if (he->func == h->func) {
1952                         TAILQ_REMOVE(&handlers, he, list);
1953                         FREE(he, M_LINUX);
1954                         return (0);
1955                 }
1956         }
1957
1958         return (EINVAL);
1959 }