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