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