]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/compat/linux/linux_ioctl.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / compat / 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 without 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
29 #include "opt_compat.h"
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/sysproto.h>
37 #include <sys/cdio.h>
38 #include <sys/dvdio.h>
39 #include <sys/conf.h>
40 #include <sys/disk.h>
41 #include <sys/consio.h>
42 #include <sys/ctype.h>
43 #include <sys/fcntl.h>
44 #include <sys/file.h>
45 #include <sys/filedesc.h>
46 #include <sys/filio.h>
47 #include <sys/jail.h>
48 #include <sys/kbio.h>
49 #include <sys/kernel.h>
50 #include <sys/linker_set.h>
51 #include <sys/lock.h>
52 #include <sys/malloc.h>
53 #include <sys/proc.h>
54 #include <sys/sbuf.h>
55 #include <sys/socket.h>
56 #include <sys/sockio.h>
57 #include <sys/soundcard.h>
58 #include <sys/stdint.h>
59 #include <sys/sx.h>
60 #include <sys/tty.h>
61 #include <sys/uio.h>
62
63 #include <net/if.h>
64 #include <net/if_dl.h>
65 #include <net/if_types.h>
66 #include <net/vnet.h>
67
68 #ifdef COMPAT_LINUX32
69 #include <machine/../linux32/linux.h>
70 #include <machine/../linux32/linux32_proto.h>
71 #else
72 #include <machine/../linux/linux.h>
73 #include <machine/../linux/linux_proto.h>
74 #endif
75
76 #include <compat/linux/linux_ioctl.h>
77 #include <compat/linux/linux_mib.h>
78 #include <compat/linux/linux_socket.h>
79 #include <compat/linux/linux_util.h>
80
81 #include <compat/linux/linux_videodev.h>
82 #include <compat/linux/linux_videodev_compat.h>
83
84 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
85
86 static linux_ioctl_function_t linux_ioctl_cdrom;
87 static linux_ioctl_function_t linux_ioctl_vfat;
88 static linux_ioctl_function_t linux_ioctl_console;
89 static linux_ioctl_function_t linux_ioctl_hdio;
90 static linux_ioctl_function_t linux_ioctl_disk;
91 static linux_ioctl_function_t linux_ioctl_socket;
92 static linux_ioctl_function_t linux_ioctl_sound;
93 static linux_ioctl_function_t linux_ioctl_termio;
94 static linux_ioctl_function_t linux_ioctl_private;
95 static linux_ioctl_function_t linux_ioctl_drm;
96 static linux_ioctl_function_t linux_ioctl_sg;
97 static linux_ioctl_function_t linux_ioctl_v4l;
98 static linux_ioctl_function_t linux_ioctl_special;
99
100 static struct linux_ioctl_handler cdrom_handler =
101 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
102 static struct linux_ioctl_handler vfat_handler =
103 { linux_ioctl_vfat, LINUX_IOCTL_VFAT_MIN, LINUX_IOCTL_VFAT_MAX };
104 static struct linux_ioctl_handler console_handler =
105 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
106 static struct linux_ioctl_handler hdio_handler =
107 { linux_ioctl_hdio, LINUX_IOCTL_HDIO_MIN, LINUX_IOCTL_HDIO_MAX };
108 static struct linux_ioctl_handler disk_handler =
109 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
110 static struct linux_ioctl_handler socket_handler =
111 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
112 static struct linux_ioctl_handler sound_handler =
113 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
114 static struct linux_ioctl_handler termio_handler =
115 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
116 static struct linux_ioctl_handler private_handler =
117 { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX };
118 static struct linux_ioctl_handler drm_handler =
119 { linux_ioctl_drm, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX };
120 static struct linux_ioctl_handler sg_handler =
121 { linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX };
122 static struct linux_ioctl_handler video_handler =
123 { linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX };
124
125 DATA_SET(linux_ioctl_handler_set, cdrom_handler);
126 DATA_SET(linux_ioctl_handler_set, vfat_handler);
127 DATA_SET(linux_ioctl_handler_set, console_handler);
128 DATA_SET(linux_ioctl_handler_set, hdio_handler);
129 DATA_SET(linux_ioctl_handler_set, disk_handler);
130 DATA_SET(linux_ioctl_handler_set, socket_handler);
131 DATA_SET(linux_ioctl_handler_set, sound_handler);
132 DATA_SET(linux_ioctl_handler_set, termio_handler);
133 DATA_SET(linux_ioctl_handler_set, private_handler);
134 DATA_SET(linux_ioctl_handler_set, drm_handler);
135 DATA_SET(linux_ioctl_handler_set, sg_handler);
136 DATA_SET(linux_ioctl_handler_set, video_handler);
137
138 struct handler_element
139 {
140         TAILQ_ENTRY(handler_element) list;
141         int     (*func)(struct thread *, struct linux_ioctl_args *);
142         int     low, high, span;
143 };
144
145 static TAILQ_HEAD(, handler_element) handlers =
146     TAILQ_HEAD_INITIALIZER(handlers);
147 static struct sx linux_ioctl_sx;
148 SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "linux ioctl handlers");
149
150 /*
151  * hdio related ioctls for VMWare support
152  */
153
154 struct linux_hd_geometry {
155         u_int8_t        heads;
156         u_int8_t        sectors;
157         u_int16_t       cylinders;
158         u_int32_t       start;
159 };
160
161 struct linux_hd_big_geometry {
162         u_int8_t        heads;
163         u_int8_t        sectors;
164         u_int32_t       cylinders;
165         u_int32_t       start;
166 };
167
168 static int
169 linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
170 {
171         struct file *fp;
172         int error;
173         u_int sectorsize, fwcylinders, fwheads, fwsectors;
174         off_t mediasize, bytespercyl;
175
176         if ((error = fget(td, args->fd, &fp)) != 0)
177                 return (error);
178         switch (args->cmd & 0xffff) {
179         case LINUX_HDIO_GET_GEO:
180         case LINUX_HDIO_GET_GEO_BIG:
181                 error = fo_ioctl(fp, DIOCGMEDIASIZE,
182                         (caddr_t)&mediasize, td->td_ucred, td);
183                 if (!error)
184                         error = fo_ioctl(fp, DIOCGSECTORSIZE,
185                                 (caddr_t)&sectorsize, td->td_ucred, td);
186                 if (!error)
187                         error = fo_ioctl(fp, DIOCGFWHEADS,
188                                 (caddr_t)&fwheads, td->td_ucred, td);
189                 if (!error)
190                         error = fo_ioctl(fp, DIOCGFWSECTORS,
191                                 (caddr_t)&fwsectors, td->td_ucred, td);
192                 /*
193                  * XXX: DIOCGFIRSTOFFSET is not yet implemented, so
194                  * so pretend that GEOM always says 0. This is NOT VALID
195                  * for slices or partitions, only the per-disk raw devices.
196                  */
197
198                 fdrop(fp, td);
199                 if (error)
200                         return (error);
201                 /*
202                  * 1. Calculate the number of bytes in a cylinder,
203                  *    given the firmware's notion of heads and sectors
204                  *    per cylinder.
205                  * 2. Calculate the number of cylinders, given the total
206                  *    size of the media.
207                  * All internal calculations should have 64-bit precision.
208                  */
209                 bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
210                 fwcylinders = mediasize / bytespercyl;
211 #if defined(DEBUG)
212                 linux_msg(td, "HDIO_GET_GEO: mediasize %jd, c/h/s %d/%d/%d, "
213                           "bpc %jd",
214                           (intmax_t)mediasize, fwcylinders, fwheads, fwsectors, 
215                           (intmax_t)bytespercyl);
216 #endif
217                 if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
218                         struct linux_hd_geometry hdg;
219
220                         hdg.cylinders = fwcylinders;
221                         hdg.heads = fwheads;
222                         hdg.sectors = fwsectors;
223                         hdg.start = 0;
224                         error = copyout(&hdg, (void *)args->arg, sizeof(hdg));
225                 } else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
226                         struct linux_hd_big_geometry hdbg;
227
228                         hdbg.cylinders = fwcylinders;
229                         hdbg.heads = fwheads;
230                         hdbg.sectors = fwsectors;
231                         hdbg.start = 0;
232                         error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg));
233                 }
234                 return (error);
235                 break;
236         default:
237                 /* XXX */
238                 linux_msg(td,
239                         "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
240                         args->fd, (int)(args->cmd & 0xffff),
241                         (int)(args->cmd & 0xff00) >> 8,
242                         (int)(args->cmd & 0xff));
243                 break;
244         }
245         fdrop(fp, td);
246         return (ENOIOCTL);
247 }
248
249 static int
250 linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
251 {
252         struct file *fp;
253         int error;
254         u_int sectorsize;
255         off_t mediasize;
256
257         if ((error = fget(td, args->fd, &fp)) != 0)
258                 return (error);
259         switch (args->cmd & 0xffff) {
260         case LINUX_BLKGETSIZE:
261                 error = fo_ioctl(fp, DIOCGSECTORSIZE,
262                     (caddr_t)&sectorsize, td->td_ucred, td);
263                 if (!error)
264                         error = fo_ioctl(fp, DIOCGMEDIASIZE,
265                             (caddr_t)&mediasize, td->td_ucred, td);
266                 fdrop(fp, td);
267                 if (error)
268                         return (error);
269                 sectorsize = mediasize / sectorsize;
270                 /*
271                  * XXX: How do we know we return the right size of integer ?
272                  */
273                 return (copyout(&sectorsize, (void *)args->arg,
274                     sizeof(sectorsize)));
275                 break;
276         }
277         fdrop(fp, td);
278         return (ENOIOCTL);
279 }
280
281 /*
282  * termio related ioctls
283  */
284
285 struct linux_termio {
286         unsigned short c_iflag;
287         unsigned short c_oflag;
288         unsigned short c_cflag;
289         unsigned short c_lflag;
290         unsigned char c_line;
291         unsigned char c_cc[LINUX_NCC];
292 };
293
294 struct linux_termios {
295         unsigned int c_iflag;
296         unsigned int c_oflag;
297         unsigned int c_cflag;
298         unsigned int c_lflag;
299         unsigned char c_line;
300         unsigned char c_cc[LINUX_NCCS];
301 };
302
303 struct linux_winsize {
304         unsigned short ws_row, ws_col;
305         unsigned short ws_xpixel, ws_ypixel;
306 };
307
308 struct speedtab {
309         int sp_speed;                   /* Speed. */
310         int sp_code;                    /* Code. */
311 };
312
313 static struct speedtab sptab[] = {
314         { B0, LINUX_B0 }, { B50, LINUX_B50 },
315         { B75, LINUX_B75 }, { B110, LINUX_B110 },
316         { B134, LINUX_B134 }, { B150, LINUX_B150 },
317         { B200, LINUX_B200 }, { B300, LINUX_B300 },
318         { B600, LINUX_B600 }, { B1200, LINUX_B1200 },
319         { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
320         { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
321         { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
322         { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
323         {-1, -1 }
324 };
325
326 struct linux_serial_struct {
327         int     type;
328         int     line;
329         int     port;
330         int     irq;
331         int     flags;
332         int     xmit_fifo_size;
333         int     custom_divisor;
334         int     baud_base;
335         unsigned short close_delay;
336         char    reserved_char[2];
337         int     hub6;
338         unsigned short closing_wait;
339         unsigned short closing_wait2;
340         int     reserved[4];
341 };
342
343 static int
344 linux_to_bsd_speed(int code, struct speedtab *table)
345 {
346         for ( ; table->sp_code != -1; table++)
347                 if (table->sp_code == code)
348                         return (table->sp_speed);
349         return -1;
350 }
351
352 static int
353 bsd_to_linux_speed(int speed, struct speedtab *table)
354 {
355         for ( ; table->sp_speed != -1; table++)
356                 if (table->sp_speed == speed)
357                         return (table->sp_code);
358         return -1;
359 }
360
361 static void
362 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
363 {
364         int i;
365
366 #ifdef DEBUG
367         if (ldebug(ioctl)) {
368                 printf("LINUX: BSD termios structure (input):\n");
369                 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
370                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
371                     bios->c_ispeed, bios->c_ospeed);
372                 printf("c_cc ");
373                 for (i=0; i<NCCS; i++)
374                         printf("%02x ", bios->c_cc[i]);
375                 printf("\n");
376         }
377 #endif
378
379         lios->c_iflag = 0;
380         if (bios->c_iflag & IGNBRK)
381                 lios->c_iflag |= LINUX_IGNBRK;
382         if (bios->c_iflag & BRKINT)
383                 lios->c_iflag |= LINUX_BRKINT;
384         if (bios->c_iflag & IGNPAR)
385                 lios->c_iflag |= LINUX_IGNPAR;
386         if (bios->c_iflag & PARMRK)
387                 lios->c_iflag |= LINUX_PARMRK;
388         if (bios->c_iflag & INPCK)
389                 lios->c_iflag |= LINUX_INPCK;
390         if (bios->c_iflag & ISTRIP)
391                 lios->c_iflag |= LINUX_ISTRIP;
392         if (bios->c_iflag & INLCR)
393                 lios->c_iflag |= LINUX_INLCR;
394         if (bios->c_iflag & IGNCR)
395                 lios->c_iflag |= LINUX_IGNCR;
396         if (bios->c_iflag & ICRNL)
397                 lios->c_iflag |= LINUX_ICRNL;
398         if (bios->c_iflag & IXON)
399                 lios->c_iflag |= LINUX_IXON;
400         if (bios->c_iflag & IXANY)
401                 lios->c_iflag |= LINUX_IXANY;
402         if (bios->c_iflag & IXOFF)
403                 lios->c_iflag |= LINUX_IXOFF;
404         if (bios->c_iflag & IMAXBEL)
405                 lios->c_iflag |= LINUX_IMAXBEL;
406
407         lios->c_oflag = 0;
408         if (bios->c_oflag & OPOST)
409                 lios->c_oflag |= LINUX_OPOST;
410         if (bios->c_oflag & ONLCR)
411                 lios->c_oflag |= LINUX_ONLCR;
412         if (bios->c_oflag & TAB3)
413                 lios->c_oflag |= LINUX_XTABS;
414
415         lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
416         lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
417         if (bios->c_cflag & CSTOPB)
418                 lios->c_cflag |= LINUX_CSTOPB;
419         if (bios->c_cflag & CREAD)
420                 lios->c_cflag |= LINUX_CREAD;
421         if (bios->c_cflag & PARENB)
422                 lios->c_cflag |= LINUX_PARENB;
423         if (bios->c_cflag & PARODD)
424                 lios->c_cflag |= LINUX_PARODD;
425         if (bios->c_cflag & HUPCL)
426                 lios->c_cflag |= LINUX_HUPCL;
427         if (bios->c_cflag & CLOCAL)
428                 lios->c_cflag |= LINUX_CLOCAL;
429         if (bios->c_cflag & CRTSCTS)
430                 lios->c_cflag |= LINUX_CRTSCTS;
431
432         lios->c_lflag = 0;
433         if (bios->c_lflag & ISIG)
434                 lios->c_lflag |= LINUX_ISIG;
435         if (bios->c_lflag & ICANON)
436                 lios->c_lflag |= LINUX_ICANON;
437         if (bios->c_lflag & ECHO)
438                 lios->c_lflag |= LINUX_ECHO;
439         if (bios->c_lflag & ECHOE)
440                 lios->c_lflag |= LINUX_ECHOE;
441         if (bios->c_lflag & ECHOK)
442                 lios->c_lflag |= LINUX_ECHOK;
443         if (bios->c_lflag & ECHONL)
444                 lios->c_lflag |= LINUX_ECHONL;
445         if (bios->c_lflag & NOFLSH)
446                 lios->c_lflag |= LINUX_NOFLSH;
447         if (bios->c_lflag & TOSTOP)
448                 lios->c_lflag |= LINUX_TOSTOP;
449         if (bios->c_lflag & ECHOCTL)
450                 lios->c_lflag |= LINUX_ECHOCTL;
451         if (bios->c_lflag & ECHOPRT)
452                 lios->c_lflag |= LINUX_ECHOPRT;
453         if (bios->c_lflag & ECHOKE)
454                 lios->c_lflag |= LINUX_ECHOKE;
455         if (bios->c_lflag & FLUSHO)
456                 lios->c_lflag |= LINUX_FLUSHO;
457         if (bios->c_lflag & PENDIN)
458                 lios->c_lflag |= LINUX_PENDIN;
459         if (bios->c_lflag & IEXTEN)
460                 lios->c_lflag |= LINUX_IEXTEN;
461
462         for (i=0; i<LINUX_NCCS; i++)
463                 lios->c_cc[i] = LINUX_POSIX_VDISABLE;
464         lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
465         lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
466         lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
467         lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
468         lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
469         lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
470         lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
471         lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
472         lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
473         lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
474         lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
475         lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
476         lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
477         lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
478         lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
479         lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
480
481         for (i=0; i<LINUX_NCCS; i++) {
482                 if (i != LINUX_VMIN && i != LINUX_VTIME &&
483                     lios->c_cc[i] == _POSIX_VDISABLE)
484                         lios->c_cc[i] = LINUX_POSIX_VDISABLE;
485         }
486         lios->c_line = 0;
487
488 #ifdef DEBUG
489         if (ldebug(ioctl)) {
490                 printf("LINUX: LINUX termios structure (output):\n");
491                 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
492                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
493                     lios->c_lflag, (int)lios->c_line);
494                 printf("c_cc ");
495                 for (i=0; i<LINUX_NCCS; i++)
496                         printf("%02x ", lios->c_cc[i]);
497                 printf("\n");
498         }
499 #endif
500 }
501
502 static void
503 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
504 {
505         int i;
506
507 #ifdef DEBUG
508         if (ldebug(ioctl)) {
509                 printf("LINUX: LINUX termios structure (input):\n");
510                 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n",
511                     lios->c_iflag, lios->c_oflag, lios->c_cflag,
512                     lios->c_lflag, (int)lios->c_line);
513                 printf("c_cc ");
514                 for (i=0; i<LINUX_NCCS; i++)
515                         printf("%02x ", lios->c_cc[i]);
516                 printf("\n");
517         }
518 #endif
519
520         bios->c_iflag = 0;
521         if (lios->c_iflag & LINUX_IGNBRK)
522                 bios->c_iflag |= IGNBRK;
523         if (lios->c_iflag & LINUX_BRKINT)
524                 bios->c_iflag |= BRKINT;
525         if (lios->c_iflag & LINUX_IGNPAR)
526                 bios->c_iflag |= IGNPAR;
527         if (lios->c_iflag & LINUX_PARMRK)
528                 bios->c_iflag |= PARMRK;
529         if (lios->c_iflag & LINUX_INPCK)
530                 bios->c_iflag |= INPCK;
531         if (lios->c_iflag & LINUX_ISTRIP)
532                 bios->c_iflag |= ISTRIP;
533         if (lios->c_iflag & LINUX_INLCR)
534                 bios->c_iflag |= INLCR;
535         if (lios->c_iflag & LINUX_IGNCR)
536                 bios->c_iflag |= IGNCR;
537         if (lios->c_iflag & LINUX_ICRNL)
538                 bios->c_iflag |= ICRNL;
539         if (lios->c_iflag & LINUX_IXON)
540                 bios->c_iflag |= IXON;
541         if (lios->c_iflag & LINUX_IXANY)
542                 bios->c_iflag |= IXANY;
543         if (lios->c_iflag & LINUX_IXOFF)
544                 bios->c_iflag |= IXOFF;
545         if (lios->c_iflag & LINUX_IMAXBEL)
546                 bios->c_iflag |= IMAXBEL;
547
548         bios->c_oflag = 0;
549         if (lios->c_oflag & LINUX_OPOST)
550                 bios->c_oflag |= OPOST;
551         if (lios->c_oflag & LINUX_ONLCR)
552                 bios->c_oflag |= ONLCR;
553         if (lios->c_oflag & LINUX_XTABS)
554                 bios->c_oflag |= TAB3;
555
556         bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
557         if (lios->c_cflag & LINUX_CSTOPB)
558                 bios->c_cflag |= CSTOPB;
559         if (lios->c_cflag & LINUX_CREAD)
560                 bios->c_cflag |= CREAD;
561         if (lios->c_cflag & LINUX_PARENB)
562                 bios->c_cflag |= PARENB;
563         if (lios->c_cflag & LINUX_PARODD)
564                 bios->c_cflag |= PARODD;
565         if (lios->c_cflag & LINUX_HUPCL)
566                 bios->c_cflag |= HUPCL;
567         if (lios->c_cflag & LINUX_CLOCAL)
568                 bios->c_cflag |= CLOCAL;
569         if (lios->c_cflag & LINUX_CRTSCTS)
570                 bios->c_cflag |= CRTSCTS;
571
572         bios->c_lflag = 0;
573         if (lios->c_lflag & LINUX_ISIG)
574                 bios->c_lflag |= ISIG;
575         if (lios->c_lflag & LINUX_ICANON)
576                 bios->c_lflag |= ICANON;
577         if (lios->c_lflag & LINUX_ECHO)
578                 bios->c_lflag |= ECHO;
579         if (lios->c_lflag & LINUX_ECHOE)
580                 bios->c_lflag |= ECHOE;
581         if (lios->c_lflag & LINUX_ECHOK)
582                 bios->c_lflag |= ECHOK;
583         if (lios->c_lflag & LINUX_ECHONL)
584                 bios->c_lflag |= ECHONL;
585         if (lios->c_lflag & LINUX_NOFLSH)
586                 bios->c_lflag |= NOFLSH;
587         if (lios->c_lflag & LINUX_TOSTOP)
588                 bios->c_lflag |= TOSTOP;
589         if (lios->c_lflag & LINUX_ECHOCTL)
590                 bios->c_lflag |= ECHOCTL;
591         if (lios->c_lflag & LINUX_ECHOPRT)
592                 bios->c_lflag |= ECHOPRT;
593         if (lios->c_lflag & LINUX_ECHOKE)
594                 bios->c_lflag |= ECHOKE;
595         if (lios->c_lflag & LINUX_FLUSHO)
596                 bios->c_lflag |= FLUSHO;
597         if (lios->c_lflag & LINUX_PENDIN)
598                 bios->c_lflag |= PENDIN;
599         if (lios->c_lflag & LINUX_IEXTEN)
600                 bios->c_lflag |= IEXTEN;
601
602         for (i=0; i<NCCS; i++)
603                 bios->c_cc[i] = _POSIX_VDISABLE;
604         bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
605         bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
606         bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
607         bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
608         bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
609         bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
610         bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
611         bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
612         bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
613         bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
614         bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
615         bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
616         bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
617         bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
618         bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
619         bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
620
621         for (i=0; i<NCCS; i++) {
622                 if (i != VMIN && i != VTIME &&
623                     bios->c_cc[i] == LINUX_POSIX_VDISABLE)
624                         bios->c_cc[i] = _POSIX_VDISABLE;
625         }
626
627         bios->c_ispeed = bios->c_ospeed =
628             linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
629
630 #ifdef DEBUG
631         if (ldebug(ioctl)) {
632                 printf("LINUX: BSD termios structure (output):\n");
633                 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
634                     bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
635                     bios->c_ispeed, bios->c_ospeed);
636                 printf("c_cc ");
637                 for (i=0; i<NCCS; i++)
638                         printf("%02x ", bios->c_cc[i]);
639                 printf("\n");
640         }
641 #endif
642 }
643
644 static void
645 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
646 {
647         struct linux_termios lios;
648
649         bsd_to_linux_termios(bios, &lios);
650         lio->c_iflag = lios.c_iflag;
651         lio->c_oflag = lios.c_oflag;
652         lio->c_cflag = lios.c_cflag;
653         lio->c_lflag = lios.c_lflag;
654         lio->c_line  = lios.c_line;
655         memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
656 }
657
658 static void
659 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
660 {
661         struct linux_termios lios;
662         int i;
663
664         lios.c_iflag = lio->c_iflag;
665         lios.c_oflag = lio->c_oflag;
666         lios.c_cflag = lio->c_cflag;
667         lios.c_lflag = lio->c_lflag;
668         for (i=LINUX_NCC; i<LINUX_NCCS; i++)
669                 lios.c_cc[i] = LINUX_POSIX_VDISABLE;
670         memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
671         linux_to_bsd_termios(&lios, bios);
672 }
673
674 static int
675 linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
676 {
677         struct termios bios;
678         struct linux_termios lios;
679         struct linux_termio lio;
680         struct file *fp;
681         int error;
682
683         if ((error = fget(td, args->fd, &fp)) != 0)
684                 return (error);
685
686         switch (args->cmd & 0xffff) {
687
688         case LINUX_TCGETS:
689                 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
690                     td);
691                 if (error)
692                         break;
693                 bsd_to_linux_termios(&bios, &lios);
694                 error = copyout(&lios, (void *)args->arg, sizeof(lios));
695                 break;
696
697         case LINUX_TCSETS:
698                 error = copyin((void *)args->arg, &lios, sizeof(lios));
699                 if (error)
700                         break;
701                 linux_to_bsd_termios(&lios, &bios);
702                 error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
703                     td));
704                 break;
705
706         case LINUX_TCSETSW:
707                 error = copyin((void *)args->arg, &lios, sizeof(lios));
708                 if (error)
709                         break;
710                 linux_to_bsd_termios(&lios, &bios);
711                 error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
712                     td));
713                 break;
714
715         case LINUX_TCSETSF:
716                 error = copyin((void *)args->arg, &lios, sizeof(lios));
717                 if (error)
718                         break;
719                 linux_to_bsd_termios(&lios, &bios);
720                 error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
721                     td));
722                 break;
723
724         case LINUX_TCGETA:
725                 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
726                     td);
727                 if (error)
728                         break;
729                 bsd_to_linux_termio(&bios, &lio);
730                 error = (copyout(&lio, (void *)args->arg, sizeof(lio)));
731                 break;
732
733         case LINUX_TCSETA:
734                 error = copyin((void *)args->arg, &lio, sizeof(lio));
735                 if (error)
736                         break;
737                 linux_to_bsd_termio(&lio, &bios);
738                 error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
739                     td));
740                 break;
741
742         case LINUX_TCSETAW:
743                 error = copyin((void *)args->arg, &lio, sizeof(lio));
744                 if (error)
745                         break;
746                 linux_to_bsd_termio(&lio, &bios);
747                 error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
748                     td));
749                 break;
750
751         case LINUX_TCSETAF:
752                 error = copyin((void *)args->arg, &lio, sizeof(lio));
753                 if (error)
754                         break;
755                 linux_to_bsd_termio(&lio, &bios);
756                 error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
757                     td));
758                 break;
759
760         /* LINUX_TCSBRK */
761
762         case LINUX_TCXONC: {
763                 switch (args->arg) {
764                 case LINUX_TCOOFF:
765                         args->cmd = TIOCSTOP;
766                         break;
767                 case LINUX_TCOON:
768                         args->cmd = TIOCSTART;
769                         break;
770                 case LINUX_TCIOFF:
771                 case LINUX_TCION: {
772                         int c;
773                         struct write_args wr;
774                         error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios,
775                             td->td_ucred, td);
776                         if (error)
777                                 break;
778                         fdrop(fp, td);
779                         c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
780                         c = bios.c_cc[c];
781                         if (c != _POSIX_VDISABLE) {
782                                 wr.fd = args->fd;
783                                 wr.buf = &c;
784                                 wr.nbyte = sizeof(c);
785                                 return (write(td, &wr));
786                         } else
787                                 return (0);
788                 }
789                 default:
790                         fdrop(fp, td);
791                         return (EINVAL);
792                 }
793                 args->arg = 0;
794                 error = (ioctl(td, (struct ioctl_args *)args));
795                 break;
796         }
797
798         case LINUX_TCFLSH: {
799                 int val;
800                 switch (args->arg) {
801                 case LINUX_TCIFLUSH:
802                         val = FREAD;
803                         break;
804                 case LINUX_TCOFLUSH:
805                         val = FWRITE;
806                         break;
807                 case LINUX_TCIOFLUSH:
808                         val = FREAD | FWRITE;
809                         break;
810                 default:
811                         fdrop(fp, td);
812                         return (EINVAL);
813                 }
814                 error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td));
815                 break;
816         }
817
818         case LINUX_TIOCEXCL:
819                 args->cmd = TIOCEXCL;
820                 error = (ioctl(td, (struct ioctl_args *)args));
821                 break;
822
823         case LINUX_TIOCNXCL:
824                 args->cmd = TIOCNXCL;
825                 error = (ioctl(td, (struct ioctl_args *)args));
826                 break;
827
828         case LINUX_TIOCSCTTY:
829                 args->cmd = TIOCSCTTY;
830                 error = (ioctl(td, (struct ioctl_args *)args));
831                 break;
832
833         case LINUX_TIOCGPGRP:
834                 args->cmd = TIOCGPGRP;
835                 error = (ioctl(td, (struct ioctl_args *)args));
836                 break;
837
838         case LINUX_TIOCSPGRP:
839                 args->cmd = TIOCSPGRP;
840                 error = (ioctl(td, (struct ioctl_args *)args));
841                 break;
842
843         /* LINUX_TIOCOUTQ */
844         /* LINUX_TIOCSTI */
845
846         case LINUX_TIOCGWINSZ:
847                 args->cmd = TIOCGWINSZ;
848                 error = (ioctl(td, (struct ioctl_args *)args));
849                 break;
850
851         case LINUX_TIOCSWINSZ:
852                 args->cmd = TIOCSWINSZ;
853                 error = (ioctl(td, (struct ioctl_args *)args));
854                 break;
855
856         case LINUX_TIOCMGET:
857                 args->cmd = TIOCMGET;
858                 error = (ioctl(td, (struct ioctl_args *)args));
859                 break;
860
861         case LINUX_TIOCMBIS:
862                 args->cmd = TIOCMBIS;
863                 error = (ioctl(td, (struct ioctl_args *)args));
864                 break;
865
866         case LINUX_TIOCMBIC:
867                 args->cmd = TIOCMBIC;
868                 error = (ioctl(td, (struct ioctl_args *)args));
869                 break;
870
871         case LINUX_TIOCMSET:
872                 args->cmd = TIOCMSET;
873                 error = (ioctl(td, (struct ioctl_args *)args));
874                 break;
875
876         /* TIOCGSOFTCAR */
877         /* TIOCSSOFTCAR */
878
879         case LINUX_FIONREAD: /* LINUX_TIOCINQ */
880                 args->cmd = FIONREAD;
881                 error = (ioctl(td, (struct ioctl_args *)args));
882                 break;
883
884         /* LINUX_TIOCLINUX */
885
886         case LINUX_TIOCCONS:
887                 args->cmd = TIOCCONS;
888                 error = (ioctl(td, (struct ioctl_args *)args));
889                 break;
890
891         case LINUX_TIOCGSERIAL: {
892                 struct linux_serial_struct lss;
893                 lss.type = LINUX_PORT_16550A;
894                 lss.flags = 0;
895                 lss.close_delay = 0;
896                 error = copyout(&lss, (void *)args->arg, sizeof(lss));
897                 break;
898         }
899
900         case LINUX_TIOCSSERIAL: {
901                 struct linux_serial_struct lss;
902                 error = copyin((void *)args->arg, &lss, sizeof(lss));
903                 if (error)
904                         break;
905                 /* XXX - It really helps to have an implementation that
906                  * does nothing. NOT!
907                  */
908                 error = 0;
909                 break;
910         }
911
912         case LINUX_TIOCPKT:
913                 args->cmd = TIOCPKT;
914                 error = (ioctl(td, (struct ioctl_args *)args));
915                 break;
916
917         case LINUX_FIONBIO:
918                 args->cmd = FIONBIO;
919                 error = (ioctl(td, (struct ioctl_args *)args));
920                 break;
921
922         case LINUX_TIOCNOTTY:
923                 args->cmd = TIOCNOTTY;
924                 error = (ioctl(td, (struct ioctl_args *)args));
925                 break;
926
927         case LINUX_TIOCSETD: {
928                 int line;
929                 switch (args->arg) {
930                 case LINUX_N_TTY:
931                         line = TTYDISC;
932                         break;
933                 case LINUX_N_SLIP:
934                         line = SLIPDISC;
935                         break;
936                 case LINUX_N_PPP:
937                         line = PPPDISC;
938                         break;
939                 default:
940                         fdrop(fp, td);
941                         return (EINVAL);
942                 }
943                 error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred,
944                     td));
945                 break;
946         }
947
948         case LINUX_TIOCGETD: {
949                 int linux_line;
950                 int bsd_line = TTYDISC;
951                 error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
952                     td->td_ucred, td);
953                 if (error)
954                         return (error);
955                 switch (bsd_line) {
956                 case TTYDISC:
957                         linux_line = LINUX_N_TTY;
958                         break;
959                 case SLIPDISC:
960                         linux_line = LINUX_N_SLIP;
961                         break;
962                 case PPPDISC:
963                         linux_line = LINUX_N_PPP;
964                         break;
965                 default:
966                         fdrop(fp, td);
967                         return (EINVAL);
968                 }
969                 error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
970                 break;
971         }
972
973         /* LINUX_TCSBRKP */
974         /* LINUX_TIOCTTYGSTRUCT */
975
976         case LINUX_FIONCLEX:
977                 args->cmd = FIONCLEX;
978                 error = (ioctl(td, (struct ioctl_args *)args));
979                 break;
980
981         case LINUX_FIOCLEX:
982                 args->cmd = FIOCLEX;
983                 error = (ioctl(td, (struct ioctl_args *)args));
984                 break;
985
986         case LINUX_FIOASYNC:
987                 args->cmd = FIOASYNC;
988                 error = (ioctl(td, (struct ioctl_args *)args));
989                 break;
990
991         /* LINUX_TIOCSERCONFIG */
992         /* LINUX_TIOCSERGWILD */
993         /* LINUX_TIOCSERSWILD */
994         /* LINUX_TIOCGLCKTRMIOS */
995         /* LINUX_TIOCSLCKTRMIOS */
996
997         case LINUX_TIOCSBRK:
998                 args->cmd = TIOCSBRK;
999                 error = (ioctl(td, (struct ioctl_args *)args));
1000                 break;
1001
1002         case LINUX_TIOCCBRK:
1003                 args->cmd = TIOCCBRK;
1004                 error = (ioctl(td, (struct ioctl_args *)args));
1005                 break;
1006         case LINUX_TIOCGPTN: {
1007                 int nb;
1008                 
1009                 error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td);
1010                 if (!error)
1011                         error = copyout(&nb, (void *)args->arg,
1012                             sizeof(int));
1013                 break;
1014         }
1015         case LINUX_TIOCSPTLCK:
1016                 /* Our unlockpt() does nothing. */
1017                 error = 0;
1018                 break;
1019         default:
1020                 error = ENOIOCTL;
1021                 break;
1022         }
1023
1024         fdrop(fp, td);
1025         return (error);
1026 }
1027
1028 /*
1029  * CDROM related ioctls
1030  */
1031
1032 struct linux_cdrom_msf
1033 {
1034         u_char  cdmsf_min0;
1035         u_char  cdmsf_sec0;
1036         u_char  cdmsf_frame0;
1037         u_char  cdmsf_min1;
1038         u_char  cdmsf_sec1;
1039         u_char  cdmsf_frame1;
1040 };
1041
1042 struct linux_cdrom_tochdr
1043 {
1044         u_char  cdth_trk0;
1045         u_char  cdth_trk1;
1046 };
1047
1048 union linux_cdrom_addr
1049 {
1050         struct {
1051                 u_char  minute;
1052                 u_char  second;
1053                 u_char  frame;
1054         } msf;
1055         int     lba;
1056 };
1057
1058 struct linux_cdrom_tocentry
1059 {
1060         u_char  cdte_track;
1061         u_char  cdte_adr:4;
1062         u_char  cdte_ctrl:4;
1063         u_char  cdte_format;
1064         union linux_cdrom_addr cdte_addr;
1065         u_char  cdte_datamode;
1066 };
1067
1068 struct linux_cdrom_subchnl
1069 {
1070         u_char  cdsc_format;
1071         u_char  cdsc_audiostatus;
1072         u_char  cdsc_adr:4;
1073         u_char  cdsc_ctrl:4;
1074         u_char  cdsc_trk;
1075         u_char  cdsc_ind;
1076         union linux_cdrom_addr cdsc_absaddr;
1077         union linux_cdrom_addr cdsc_reladdr;
1078 };
1079
1080 struct l_cdrom_read_audio {
1081         union linux_cdrom_addr addr;
1082         u_char          addr_format;
1083         l_int           nframes;
1084         u_char          *buf;
1085 };
1086
1087 struct l_dvd_layer {
1088         u_char          book_version:4;
1089         u_char          book_type:4;
1090         u_char          min_rate:4;
1091         u_char          disc_size:4;
1092         u_char          layer_type:4;
1093         u_char          track_path:1;
1094         u_char          nlayers:2;
1095         u_char          track_density:4;
1096         u_char          linear_density:4;
1097         u_char          bca:1;
1098         u_int32_t       start_sector;
1099         u_int32_t       end_sector;
1100         u_int32_t       end_sector_l0;
1101 };
1102
1103 struct l_dvd_physical {
1104         u_char          type;
1105         u_char          layer_num;
1106         struct l_dvd_layer layer[4];
1107 };
1108
1109 struct l_dvd_copyright {
1110         u_char          type;
1111         u_char          layer_num;
1112         u_char          cpst;
1113         u_char          rmi;
1114 };
1115
1116 struct l_dvd_disckey {
1117         u_char          type;
1118         l_uint          agid:2;
1119         u_char          value[2048];
1120 };
1121
1122 struct l_dvd_bca {
1123         u_char          type;
1124         l_int           len;
1125         u_char          value[188];
1126 };
1127
1128 struct l_dvd_manufact {
1129         u_char          type;
1130         u_char          layer_num;
1131         l_int           len;
1132         u_char          value[2048];
1133 };
1134
1135 typedef union {
1136         u_char                  type;
1137         struct l_dvd_physical   physical;
1138         struct l_dvd_copyright  copyright;
1139         struct l_dvd_disckey    disckey;
1140         struct l_dvd_bca        bca;
1141         struct l_dvd_manufact   manufact;
1142 } l_dvd_struct;
1143
1144 typedef u_char l_dvd_key[5];
1145 typedef u_char l_dvd_challenge[10];
1146
1147 struct l_dvd_lu_send_agid {
1148         u_char          type;
1149         l_uint          agid:2;
1150 };
1151
1152 struct l_dvd_host_send_challenge {
1153         u_char          type;
1154         l_uint          agid:2;
1155         l_dvd_challenge chal;
1156 };
1157
1158 struct l_dvd_send_key {
1159         u_char          type;
1160         l_uint          agid:2;
1161         l_dvd_key       key;
1162 };
1163
1164 struct l_dvd_lu_send_challenge {
1165         u_char          type;
1166         l_uint          agid:2;
1167         l_dvd_challenge chal;
1168 };
1169
1170 struct l_dvd_lu_send_title_key {
1171         u_char          type;
1172         l_uint          agid:2;
1173         l_dvd_key       title_key;
1174         l_int           lba;
1175         l_uint          cpm:1;
1176         l_uint          cp_sec:1;
1177         l_uint          cgms:2;
1178 };
1179
1180 struct l_dvd_lu_send_asf {
1181         u_char          type;
1182         l_uint          agid:2;
1183         l_uint          asf:1;
1184 };
1185
1186 struct l_dvd_host_send_rpcstate {
1187         u_char          type;
1188         u_char          pdrc;
1189 };
1190
1191 struct l_dvd_lu_send_rpcstate {
1192         u_char          type:2;
1193         u_char          vra:3;
1194         u_char          ucca:3;
1195         u_char          region_mask;
1196         u_char          rpc_scheme;
1197 };
1198
1199 typedef union {
1200         u_char                          type;
1201         struct l_dvd_lu_send_agid       lsa;
1202         struct l_dvd_host_send_challenge hsc;
1203         struct l_dvd_send_key           lsk;
1204         struct l_dvd_lu_send_challenge  lsc;
1205         struct l_dvd_send_key           hsk;
1206         struct l_dvd_lu_send_title_key  lstk;
1207         struct l_dvd_lu_send_asf        lsasf;
1208         struct l_dvd_host_send_rpcstate hrpcs;
1209         struct l_dvd_lu_send_rpcstate   lrpcs;
1210 } l_dvd_authinfo;
1211
1212 static void
1213 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
1214 {
1215         if (af == CD_LBA_FORMAT)
1216                 lp->lba = bp->lba;
1217         else {
1218                 lp->msf.minute = bp->msf.minute;
1219                 lp->msf.second = bp->msf.second;
1220                 lp->msf.frame = bp->msf.frame;
1221         }
1222 }
1223
1224 static void
1225 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
1226 {
1227         if (format == LINUX_CDROM_MSF) {
1228                 addr->msf.frame = lba % 75;
1229                 lba /= 75;
1230                 lba += 2;
1231                 addr->msf.second = lba % 60;
1232                 addr->msf.minute = lba / 60;
1233         } else
1234                 addr->lba = lba;
1235 }
1236
1237 static int
1238 linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp)
1239 {
1240         bp->format = lp->type;
1241         switch (bp->format) {
1242         case DVD_STRUCT_PHYSICAL:
1243                 if (bp->layer_num >= 4)
1244                         return (EINVAL);
1245                 bp->layer_num = lp->physical.layer_num;
1246                 break;
1247         case DVD_STRUCT_COPYRIGHT:
1248                 bp->layer_num = lp->copyright.layer_num;
1249                 break;
1250         case DVD_STRUCT_DISCKEY:
1251                 bp->agid = lp->disckey.agid;
1252                 break;
1253         case DVD_STRUCT_BCA:
1254         case DVD_STRUCT_MANUFACT:
1255                 break;
1256         default:
1257                 return (EINVAL);
1258         }
1259         return (0);
1260 }
1261
1262 static int
1263 bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp)
1264 {
1265         switch (bp->format) {
1266         case DVD_STRUCT_PHYSICAL: {
1267                 struct dvd_layer *blp = (struct dvd_layer *)bp->data;
1268                 struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num];
1269                 memset(llp, 0, sizeof(*llp));
1270                 llp->book_version = blp->book_version;
1271                 llp->book_type = blp->book_type;
1272                 llp->min_rate = blp->max_rate;
1273                 llp->disc_size = blp->disc_size;
1274                 llp->layer_type = blp->layer_type;
1275                 llp->track_path = blp->track_path;
1276                 llp->nlayers = blp->nlayers;
1277                 llp->track_density = blp->track_density;
1278                 llp->linear_density = blp->linear_density;
1279                 llp->bca = blp->bca;
1280                 llp->start_sector = blp->start_sector;
1281                 llp->end_sector = blp->end_sector;
1282                 llp->end_sector_l0 = blp->end_sector_l0;
1283                 break;
1284         }
1285         case DVD_STRUCT_COPYRIGHT:
1286                 lp->copyright.cpst = bp->cpst;
1287                 lp->copyright.rmi = bp->rmi;
1288                 break;
1289         case DVD_STRUCT_DISCKEY:
1290                 memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value));
1291                 break;
1292         case DVD_STRUCT_BCA:
1293                 lp->bca.len = bp->length;
1294                 memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value));
1295                 break;
1296         case DVD_STRUCT_MANUFACT:
1297                 lp->manufact.len = bp->length;
1298                 memcpy(lp->manufact.value, bp->data,
1299                     sizeof(lp->manufact.value));
1300                 /* lp->manufact.layer_num is unused in linux (redhat 7.0) */
1301                 break;
1302         default:
1303                 return (EINVAL);
1304         }
1305         return (0);
1306 }
1307
1308 static int
1309 linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode,
1310     struct dvd_authinfo *bp)
1311 {
1312         switch (lp->type) {
1313         case LINUX_DVD_LU_SEND_AGID:
1314                 *bcode = DVDIOCREPORTKEY;
1315                 bp->format = DVD_REPORT_AGID;
1316                 bp->agid = lp->lsa.agid;
1317                 break;
1318         case LINUX_DVD_HOST_SEND_CHALLENGE:
1319                 *bcode = DVDIOCSENDKEY;
1320                 bp->format = DVD_SEND_CHALLENGE;
1321                 bp->agid = lp->hsc.agid;
1322                 memcpy(bp->keychal, lp->hsc.chal, 10);
1323                 break;
1324         case LINUX_DVD_LU_SEND_KEY1:
1325                 *bcode = DVDIOCREPORTKEY;
1326                 bp->format = DVD_REPORT_KEY1;
1327                 bp->agid = lp->lsk.agid;
1328                 break;
1329         case LINUX_DVD_LU_SEND_CHALLENGE:
1330                 *bcode = DVDIOCREPORTKEY;
1331                 bp->format = DVD_REPORT_CHALLENGE;
1332                 bp->agid = lp->lsc.agid;
1333                 break;
1334         case LINUX_DVD_HOST_SEND_KEY2:
1335                 *bcode = DVDIOCSENDKEY;
1336                 bp->format = DVD_SEND_KEY2;
1337                 bp->agid = lp->hsk.agid;
1338                 memcpy(bp->keychal, lp->hsk.key, 5);
1339                 break;
1340         case LINUX_DVD_LU_SEND_TITLE_KEY:
1341                 *bcode = DVDIOCREPORTKEY;
1342                 bp->format = DVD_REPORT_TITLE_KEY;
1343                 bp->agid = lp->lstk.agid;
1344                 bp->lba = lp->lstk.lba;
1345                 break;
1346         case LINUX_DVD_LU_SEND_ASF:
1347                 *bcode = DVDIOCREPORTKEY;
1348                 bp->format = DVD_REPORT_ASF;
1349                 bp->agid = lp->lsasf.agid;
1350                 break;
1351         case LINUX_DVD_INVALIDATE_AGID:
1352                 *bcode = DVDIOCREPORTKEY;
1353                 bp->format = DVD_INVALIDATE_AGID;
1354                 bp->agid = lp->lsa.agid;
1355                 break;
1356         case LINUX_DVD_LU_SEND_RPC_STATE:
1357                 *bcode = DVDIOCREPORTKEY;
1358                 bp->format = DVD_REPORT_RPC;
1359                 break;
1360         case LINUX_DVD_HOST_SEND_RPC_STATE:
1361                 *bcode = DVDIOCSENDKEY;
1362                 bp->format = DVD_SEND_RPC;
1363                 bp->region = lp->hrpcs.pdrc;
1364                 break;
1365         default:
1366                 return (EINVAL);
1367         }
1368         return (0);
1369 }
1370
1371 static int
1372 bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
1373 {
1374         switch (lp->type) {
1375         case LINUX_DVD_LU_SEND_AGID:
1376                 lp->lsa.agid = bp->agid;
1377                 break;
1378         case LINUX_DVD_HOST_SEND_CHALLENGE:
1379                 lp->type = LINUX_DVD_LU_SEND_KEY1;
1380                 break;
1381         case LINUX_DVD_LU_SEND_KEY1:
1382                 memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key));
1383                 break;
1384         case LINUX_DVD_LU_SEND_CHALLENGE:
1385                 memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal));
1386                 break;
1387         case LINUX_DVD_HOST_SEND_KEY2:
1388                 lp->type = LINUX_DVD_AUTH_ESTABLISHED;
1389                 break;
1390         case LINUX_DVD_LU_SEND_TITLE_KEY:
1391                 memcpy(lp->lstk.title_key, bp->keychal,
1392                     sizeof(lp->lstk.title_key));
1393                 lp->lstk.cpm = bp->cpm;
1394                 lp->lstk.cp_sec = bp->cp_sec;
1395                 lp->lstk.cgms = bp->cgms;
1396                 break;
1397         case LINUX_DVD_LU_SEND_ASF:
1398                 lp->lsasf.asf = bp->asf;
1399                 break;
1400         case LINUX_DVD_INVALIDATE_AGID:
1401                 break;
1402         case LINUX_DVD_LU_SEND_RPC_STATE:
1403                 lp->lrpcs.type = bp->reg_type;
1404                 lp->lrpcs.vra = bp->vend_rsts;
1405                 lp->lrpcs.ucca = bp->user_rsts;
1406                 lp->lrpcs.region_mask = bp->region;
1407                 lp->lrpcs.rpc_scheme = bp->rpc_scheme;
1408                 break;
1409         case LINUX_DVD_HOST_SEND_RPC_STATE:
1410                 break;
1411         default:
1412                 return (EINVAL);
1413         }
1414         return (0);
1415 }
1416
1417 static int
1418 linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
1419 {
1420         struct file *fp;
1421         int error;
1422
1423         if ((error = fget(td, args->fd, &fp)) != 0)
1424                 return (error);
1425         switch (args->cmd & 0xffff) {
1426
1427         case LINUX_CDROMPAUSE:
1428                 args->cmd = CDIOCPAUSE;
1429                 error = (ioctl(td, (struct ioctl_args *)args));
1430                 break;
1431
1432         case LINUX_CDROMRESUME:
1433                 args->cmd = CDIOCRESUME;
1434                 error = (ioctl(td, (struct ioctl_args *)args));
1435                 break;
1436
1437         case LINUX_CDROMPLAYMSF:
1438                 args->cmd = CDIOCPLAYMSF;
1439                 error = (ioctl(td, (struct ioctl_args *)args));
1440                 break;
1441
1442         case LINUX_CDROMPLAYTRKIND:
1443                 args->cmd = CDIOCPLAYTRACKS;
1444                 error = (ioctl(td, (struct ioctl_args *)args));
1445                 break;
1446
1447         case LINUX_CDROMREADTOCHDR: {
1448                 struct ioc_toc_header th;
1449                 struct linux_cdrom_tochdr lth;
1450                 error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th,
1451                     td->td_ucred, td);
1452                 if (!error) {
1453                         lth.cdth_trk0 = th.starting_track;
1454                         lth.cdth_trk1 = th.ending_track;
1455                         copyout(&lth, (void *)args->arg, sizeof(lth));
1456                 }
1457                 break;
1458         }
1459
1460         case LINUX_CDROMREADTOCENTRY: {
1461                 struct linux_cdrom_tocentry lte;
1462                 struct ioc_read_toc_single_entry irtse;
1463
1464                 error = copyin((void *)args->arg, &lte, sizeof(lte));
1465                 if (error)
1466                         break;
1467                 irtse.address_format = lte.cdte_format;
1468                 irtse.track = lte.cdte_track;
1469                 error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse,
1470                     td->td_ucred, td);
1471                 if (!error) {
1472                         lte.cdte_ctrl = irtse.entry.control;
1473                         lte.cdte_adr = irtse.entry.addr_type;
1474                         bsd_to_linux_msf_lba(irtse.address_format,
1475                             &irtse.entry.addr, &lte.cdte_addr);
1476                         error = copyout(&lte, (void *)args->arg, sizeof(lte));
1477                 }
1478                 break;
1479         }
1480
1481         case LINUX_CDROMSTOP:
1482                 args->cmd = CDIOCSTOP;
1483                 error = (ioctl(td, (struct ioctl_args *)args));
1484                 break;
1485
1486         case LINUX_CDROMSTART:
1487                 args->cmd = CDIOCSTART;
1488                 error = (ioctl(td, (struct ioctl_args *)args));
1489                 break;
1490
1491         case LINUX_CDROMEJECT:
1492                 args->cmd = CDIOCEJECT;
1493                 error = (ioctl(td, (struct ioctl_args *)args));
1494                 break;
1495
1496         /* LINUX_CDROMVOLCTRL */
1497
1498         case LINUX_CDROMSUBCHNL: {
1499                 struct linux_cdrom_subchnl sc;
1500                 struct ioc_read_subchannel bsdsc;
1501                 struct cd_sub_channel_info bsdinfo;
1502
1503                 bsdsc.address_format = CD_LBA_FORMAT;
1504                 bsdsc.data_format = CD_CURRENT_POSITION;
1505                 bsdsc.track = 0;
1506                 bsdsc.data_len = sizeof(bsdinfo);
1507                 bsdsc.data = &bsdinfo;
1508                 error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE,
1509                     (caddr_t)&bsdsc, td->td_ucred, td);
1510                 if (error)
1511                         break;
1512                 error = copyin((void *)args->arg, &sc, sizeof(sc));
1513                 if (error)
1514                         break;
1515                 sc.cdsc_audiostatus = bsdinfo.header.audio_status;
1516                 sc.cdsc_adr = bsdinfo.what.position.addr_type;
1517                 sc.cdsc_ctrl = bsdinfo.what.position.control;
1518                 sc.cdsc_trk = bsdinfo.what.position.track_number;
1519                 sc.cdsc_ind = bsdinfo.what.position.index_number;
1520                 set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
1521                     bsdinfo.what.position.absaddr.lba);
1522                 set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
1523                     bsdinfo.what.position.reladdr.lba);
1524                 error = copyout(&sc, (void *)args->arg, sizeof(sc));
1525                 break;
1526         }
1527
1528         /* LINUX_CDROMREADMODE2 */
1529         /* LINUX_CDROMREADMODE1 */
1530         /* LINUX_CDROMREADAUDIO */
1531         /* LINUX_CDROMEJECT_SW */
1532         /* LINUX_CDROMMULTISESSION */
1533         /* LINUX_CDROM_GET_UPC */
1534
1535         case LINUX_CDROMRESET:
1536                 args->cmd = CDIOCRESET;
1537                 error = (ioctl(td, (struct ioctl_args *)args));
1538                 break;
1539
1540         /* LINUX_CDROMVOLREAD */
1541         /* LINUX_CDROMREADRAW */
1542         /* LINUX_CDROMREADCOOKED */
1543         /* LINUX_CDROMSEEK */
1544         /* LINUX_CDROMPLAYBLK */
1545         /* LINUX_CDROMREADALL */
1546         /* LINUX_CDROMCLOSETRAY */
1547         /* LINUX_CDROMLOADFROMSLOT */
1548         /* LINUX_CDROMGETSPINDOWN */
1549         /* LINUX_CDROMSETSPINDOWN */
1550         /* LINUX_CDROM_SET_OPTIONS */
1551         /* LINUX_CDROM_CLEAR_OPTIONS */
1552         /* LINUX_CDROM_SELECT_SPEED */
1553         /* LINUX_CDROM_SELECT_DISC */
1554         /* LINUX_CDROM_MEDIA_CHANGED */
1555         /* LINUX_CDROM_DRIVE_STATUS */
1556         /* LINUX_CDROM_DISC_STATUS */
1557         /* LINUX_CDROM_CHANGER_NSLOTS */
1558         /* LINUX_CDROM_LOCKDOOR */
1559         /* LINUX_CDROM_DEBUG */
1560         /* LINUX_CDROM_GET_CAPABILITY */
1561         /* LINUX_CDROMAUDIOBUFSIZ */
1562
1563         case LINUX_DVD_READ_STRUCT: {
1564                 l_dvd_struct *lds;
1565                 struct dvd_struct *bds;
1566
1567                 lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK);
1568                 bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK);
1569                 error = copyin((void *)args->arg, lds, sizeof(*lds));
1570                 if (error)
1571                         goto out;
1572                 error = linux_to_bsd_dvd_struct(lds, bds);
1573                 if (error)
1574                         goto out;
1575                 error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds,
1576                     td->td_ucred, td);
1577                 if (error)
1578                         goto out;
1579                 error = bsd_to_linux_dvd_struct(bds, lds);
1580                 if (error)
1581                         goto out;
1582                 error = copyout(lds, (void *)args->arg, sizeof(*lds));
1583         out:
1584                 free(bds, M_LINUX);
1585                 free(lds, M_LINUX);
1586                 break;
1587         }
1588
1589         /* LINUX_DVD_WRITE_STRUCT */
1590
1591         case LINUX_DVD_AUTH: {
1592                 l_dvd_authinfo lda;
1593                 struct dvd_authinfo bda;
1594                 int bcode;
1595
1596                 error = copyin((void *)args->arg, &lda, sizeof(lda));
1597                 if (error)
1598                         break;
1599                 error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
1600                 if (error)
1601                         break;
1602                 error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred,
1603                     td);
1604                 if (error) {
1605                         if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
1606                                 lda.type = LINUX_DVD_AUTH_FAILURE;
1607                                 copyout(&lda, (void *)args->arg, sizeof(lda));
1608                         }
1609                         break;
1610                 }
1611                 error = bsd_to_linux_dvd_authinfo(&bda, &lda);
1612                 if (error)
1613                         break;
1614                 error = copyout(&lda, (void *)args->arg, sizeof(lda));
1615                 break;
1616         }
1617
1618         case LINUX_SCSI_GET_BUS_NUMBER:
1619         case LINUX_SCSI_GET_IDLUN:
1620                 error = linux_ioctl_sg(td, args);
1621                 break;
1622
1623         /* LINUX_CDROM_SEND_PACKET */
1624         /* LINUX_CDROM_NEXT_WRITABLE */
1625         /* LINUX_CDROM_LAST_WRITTEN */
1626
1627         default:
1628                 error = ENOIOCTL;
1629                 break;
1630         }
1631
1632         fdrop(fp, td);
1633         return (error);
1634 }
1635
1636 static int
1637 linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args)
1638 {
1639
1640         return (ENOTTY);
1641 }
1642
1643 /*
1644  * Sound related ioctls
1645  */
1646
1647 struct linux_mixer_info {
1648         char    id[16];
1649         char    name[32];
1650         int     modify_counter;
1651         int     fillers[10];
1652 };
1653
1654 struct linux_old_mixer_info {
1655         char    id[16];
1656         char    name[32];
1657 };
1658
1659 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1660
1661 #define SETDIR(c)       (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1662
1663 static int
1664 linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
1665 {
1666
1667         switch (args->cmd & 0xffff) {
1668
1669         case LINUX_SOUND_MIXER_WRITE_VOLUME:
1670                 args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1671                 return (ioctl(td, (struct ioctl_args *)args));
1672
1673         case LINUX_SOUND_MIXER_WRITE_BASS:
1674                 args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1675                 return (ioctl(td, (struct ioctl_args *)args));
1676
1677         case LINUX_SOUND_MIXER_WRITE_TREBLE:
1678                 args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1679                 return (ioctl(td, (struct ioctl_args *)args));
1680
1681         case LINUX_SOUND_MIXER_WRITE_SYNTH:
1682                 args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1683                 return (ioctl(td, (struct ioctl_args *)args));
1684
1685         case LINUX_SOUND_MIXER_WRITE_PCM:
1686                 args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1687                 return (ioctl(td, (struct ioctl_args *)args));
1688
1689         case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1690                 args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1691                 return (ioctl(td, (struct ioctl_args *)args));
1692
1693         case LINUX_SOUND_MIXER_WRITE_LINE:
1694                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1695                 return (ioctl(td, (struct ioctl_args *)args));
1696
1697         case LINUX_SOUND_MIXER_WRITE_MIC:
1698                 args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1699                 return (ioctl(td, (struct ioctl_args *)args));
1700
1701         case LINUX_SOUND_MIXER_WRITE_CD:
1702                 args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1703                 return (ioctl(td, (struct ioctl_args *)args));
1704
1705         case LINUX_SOUND_MIXER_WRITE_IMIX:
1706                 args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1707                 return (ioctl(td, (struct ioctl_args *)args));
1708
1709         case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1710                 args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1711                 return (ioctl(td, (struct ioctl_args *)args));
1712
1713         case LINUX_SOUND_MIXER_WRITE_RECLEV:
1714                 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1715                 return (ioctl(td, (struct ioctl_args *)args));
1716
1717         case LINUX_SOUND_MIXER_WRITE_IGAIN:
1718                 args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1719                 return (ioctl(td, (struct ioctl_args *)args));
1720
1721         case LINUX_SOUND_MIXER_WRITE_OGAIN:
1722                 args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1723                 return (ioctl(td, (struct ioctl_args *)args));
1724
1725         case LINUX_SOUND_MIXER_WRITE_LINE1:
1726                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1727                 return (ioctl(td, (struct ioctl_args *)args));
1728
1729         case LINUX_SOUND_MIXER_WRITE_LINE2:
1730                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1731                 return (ioctl(td, (struct ioctl_args *)args));
1732
1733         case LINUX_SOUND_MIXER_WRITE_LINE3:
1734                 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1735                 return (ioctl(td, (struct ioctl_args *)args));
1736
1737         case LINUX_SOUND_MIXER_INFO: {
1738                 /* Key on encoded length */
1739                 switch ((args->cmd >> 16) & 0x1fff) {
1740                 case 0x005c: {  /* SOUND_MIXER_INFO */
1741                         struct linux_mixer_info info;
1742                         bzero(&info, sizeof(info));
1743                         strncpy(info.id, "OSS", sizeof(info.id) - 1);
1744                         strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
1745                         copyout(&info, (void *)args->arg, sizeof(info));
1746                         break;
1747                 }
1748                 case 0x0030: {  /* SOUND_OLD_MIXER_INFO */
1749                         struct linux_old_mixer_info info;
1750                         bzero(&info, sizeof(info));
1751                         strncpy(info.id, "OSS", sizeof(info.id) - 1);
1752                         strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
1753                         copyout(&info, (void *)args->arg, sizeof(info));
1754                         break;
1755                 }
1756                 default:
1757                         return (ENOIOCTL);
1758                 }
1759                 break;
1760         }
1761
1762         case LINUX_OSS_GETVERSION: {
1763                 int version = linux_get_oss_version(td);
1764                 return (copyout(&version, (void *)args->arg, sizeof(int)));
1765         }
1766
1767         case LINUX_SOUND_MIXER_READ_STEREODEVS:
1768                 args->cmd = SOUND_MIXER_READ_STEREODEVS;
1769                 return (ioctl(td, (struct ioctl_args *)args));
1770
1771         case LINUX_SOUND_MIXER_READ_RECMASK:
1772                 args->cmd = SOUND_MIXER_READ_RECMASK;
1773                 return (ioctl(td, (struct ioctl_args *)args));
1774
1775         case LINUX_SOUND_MIXER_READ_DEVMASK:
1776                 args->cmd = SOUND_MIXER_READ_DEVMASK;
1777                 return (ioctl(td, (struct ioctl_args *)args));
1778
1779         case LINUX_SOUND_MIXER_WRITE_RECSRC:
1780                 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
1781                 return (ioctl(td, (struct ioctl_args *)args));
1782
1783         case LINUX_SNDCTL_DSP_RESET:
1784                 args->cmd = SNDCTL_DSP_RESET;
1785                 return (ioctl(td, (struct ioctl_args *)args));
1786
1787         case LINUX_SNDCTL_DSP_SYNC:
1788                 args->cmd = SNDCTL_DSP_SYNC;
1789                 return (ioctl(td, (struct ioctl_args *)args));
1790
1791         case LINUX_SNDCTL_DSP_SPEED:
1792                 args->cmd = SNDCTL_DSP_SPEED;
1793                 return (ioctl(td, (struct ioctl_args *)args));
1794
1795         case LINUX_SNDCTL_DSP_STEREO:
1796                 args->cmd = SNDCTL_DSP_STEREO;
1797                 return (ioctl(td, (struct ioctl_args *)args));
1798
1799         case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1800                 args->cmd = SNDCTL_DSP_GETBLKSIZE;
1801                 return (ioctl(td, (struct ioctl_args *)args));
1802
1803         case LINUX_SNDCTL_DSP_SETFMT:
1804                 args->cmd = SNDCTL_DSP_SETFMT;
1805                 return (ioctl(td, (struct ioctl_args *)args));
1806
1807         case LINUX_SOUND_PCM_WRITE_CHANNELS:
1808                 args->cmd = SOUND_PCM_WRITE_CHANNELS;
1809                 return (ioctl(td, (struct ioctl_args *)args));
1810
1811         case LINUX_SOUND_PCM_WRITE_FILTER:
1812                 args->cmd = SOUND_PCM_WRITE_FILTER;
1813                 return (ioctl(td, (struct ioctl_args *)args));
1814
1815         case LINUX_SNDCTL_DSP_POST:
1816                 args->cmd = SNDCTL_DSP_POST;
1817                 return (ioctl(td, (struct ioctl_args *)args));
1818
1819         case LINUX_SNDCTL_DSP_SUBDIVIDE:
1820                 args->cmd = SNDCTL_DSP_SUBDIVIDE;
1821                 return (ioctl(td, (struct ioctl_args *)args));
1822
1823         case LINUX_SNDCTL_DSP_SETFRAGMENT:
1824                 args->cmd = SNDCTL_DSP_SETFRAGMENT;
1825                 return (ioctl(td, (struct ioctl_args *)args));
1826
1827         case LINUX_SNDCTL_DSP_GETFMTS:
1828                 args->cmd = SNDCTL_DSP_GETFMTS;
1829                 return (ioctl(td, (struct ioctl_args *)args));
1830
1831         case LINUX_SNDCTL_DSP_GETOSPACE:
1832                 args->cmd = SNDCTL_DSP_GETOSPACE;
1833                 return (ioctl(td, (struct ioctl_args *)args));
1834
1835         case LINUX_SNDCTL_DSP_GETISPACE:
1836                 args->cmd = SNDCTL_DSP_GETISPACE;
1837                 return (ioctl(td, (struct ioctl_args *)args));
1838
1839         case LINUX_SNDCTL_DSP_NONBLOCK:
1840                 args->cmd = SNDCTL_DSP_NONBLOCK;
1841                 return (ioctl(td, (struct ioctl_args *)args));
1842
1843         case LINUX_SNDCTL_DSP_GETCAPS:
1844                 args->cmd = SNDCTL_DSP_GETCAPS;
1845                 return (ioctl(td, (struct ioctl_args *)args));
1846
1847         case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1848                 args->cmd = SNDCTL_DSP_SETTRIGGER;
1849                 return (ioctl(td, (struct ioctl_args *)args));
1850
1851         case LINUX_SNDCTL_DSP_GETIPTR:
1852                 args->cmd = SNDCTL_DSP_GETIPTR;
1853                 return (ioctl(td, (struct ioctl_args *)args));
1854
1855         case LINUX_SNDCTL_DSP_GETOPTR:
1856                 args->cmd = SNDCTL_DSP_GETOPTR;
1857                 return (ioctl(td, (struct ioctl_args *)args));
1858
1859         case LINUX_SNDCTL_DSP_SETDUPLEX:
1860                 args->cmd = SNDCTL_DSP_SETDUPLEX;
1861                 return (ioctl(td, (struct ioctl_args *)args));
1862
1863         case LINUX_SNDCTL_DSP_GETODELAY:
1864                 args->cmd = SNDCTL_DSP_GETODELAY;
1865                 return (ioctl(td, (struct ioctl_args *)args));
1866
1867         case LINUX_SNDCTL_SEQ_RESET:
1868                 args->cmd = SNDCTL_SEQ_RESET;
1869                 return (ioctl(td, (struct ioctl_args *)args));
1870
1871         case LINUX_SNDCTL_SEQ_SYNC:
1872                 args->cmd = SNDCTL_SEQ_SYNC;
1873                 return (ioctl(td, (struct ioctl_args *)args));
1874
1875         case LINUX_SNDCTL_SYNTH_INFO:
1876                 args->cmd = SNDCTL_SYNTH_INFO;
1877                 return (ioctl(td, (struct ioctl_args *)args));
1878
1879         case LINUX_SNDCTL_SEQ_CTRLRATE:
1880                 args->cmd = SNDCTL_SEQ_CTRLRATE;
1881                 return (ioctl(td, (struct ioctl_args *)args));
1882
1883         case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1884                 args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1885                 return (ioctl(td, (struct ioctl_args *)args));
1886
1887         case LINUX_SNDCTL_SEQ_GETINCOUNT:
1888                 args->cmd = SNDCTL_SEQ_GETINCOUNT;
1889                 return (ioctl(td, (struct ioctl_args *)args));
1890
1891         case LINUX_SNDCTL_SEQ_PERCMODE:
1892                 args->cmd = SNDCTL_SEQ_PERCMODE;
1893                 return (ioctl(td, (struct ioctl_args *)args));
1894
1895         case LINUX_SNDCTL_FM_LOAD_INSTR:
1896                 args->cmd = SNDCTL_FM_LOAD_INSTR;
1897                 return (ioctl(td, (struct ioctl_args *)args));
1898
1899         case LINUX_SNDCTL_SEQ_TESTMIDI:
1900                 args->cmd = SNDCTL_SEQ_TESTMIDI;
1901                 return (ioctl(td, (struct ioctl_args *)args));
1902
1903         case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1904                 args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1905                 return (ioctl(td, (struct ioctl_args *)args));
1906
1907         case LINUX_SNDCTL_SEQ_NRSYNTHS:
1908                 args->cmd = SNDCTL_SEQ_NRSYNTHS;
1909                 return (ioctl(td, (struct ioctl_args *)args));
1910
1911         case LINUX_SNDCTL_SEQ_NRMIDIS:
1912                 args->cmd = SNDCTL_SEQ_NRMIDIS;
1913                 return (ioctl(td, (struct ioctl_args *)args));
1914
1915         case LINUX_SNDCTL_MIDI_INFO:
1916                 args->cmd = SNDCTL_MIDI_INFO;
1917                 return (ioctl(td, (struct ioctl_args *)args));
1918
1919         case LINUX_SNDCTL_SEQ_TRESHOLD:
1920                 args->cmd = SNDCTL_SEQ_TRESHOLD;
1921                 return (ioctl(td, (struct ioctl_args *)args));
1922
1923         case LINUX_SNDCTL_SYNTH_MEMAVL:
1924                 args->cmd = SNDCTL_SYNTH_MEMAVL;
1925                 return (ioctl(td, (struct ioctl_args *)args));
1926
1927         }
1928
1929         return (ENOIOCTL);
1930 }
1931
1932 /*
1933  * Console related ioctls
1934  */
1935
1936 #define ISSIGVALID(sig)         ((sig) > 0 && (sig) < NSIG)
1937
1938 static int
1939 linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
1940 {
1941         struct file *fp;
1942         int error;
1943
1944         if ((error = fget(td, args->fd, &fp)) != 0)
1945                 return (error);
1946         switch (args->cmd & 0xffff) {
1947
1948         case LINUX_KIOCSOUND:
1949                 args->cmd = KIOCSOUND;
1950                 error = (ioctl(td, (struct ioctl_args *)args));
1951                 break;
1952
1953         case LINUX_KDMKTONE:
1954                 args->cmd = KDMKTONE;
1955                 error = (ioctl(td, (struct ioctl_args *)args));
1956                 break;
1957
1958         case LINUX_KDGETLED:
1959                 args->cmd = KDGETLED;
1960                 error = (ioctl(td, (struct ioctl_args *)args));
1961                 break;
1962
1963         case LINUX_KDSETLED:
1964                 args->cmd = KDSETLED;
1965                 error = (ioctl(td, (struct ioctl_args *)args));
1966                 break;
1967
1968         case LINUX_KDSETMODE:
1969                 args->cmd = KDSETMODE;
1970                 error = (ioctl(td, (struct ioctl_args *)args));
1971                 break;
1972
1973         case LINUX_KDGETMODE:
1974                 args->cmd = KDGETMODE;
1975                 error = (ioctl(td, (struct ioctl_args *)args));
1976                 break;
1977
1978         case LINUX_KDGKBMODE:
1979                 args->cmd = KDGKBMODE;
1980                 error = (ioctl(td, (struct ioctl_args *)args));
1981                 break;
1982
1983         case LINUX_KDSKBMODE: {
1984                 int kbdmode;
1985                 switch (args->arg) {
1986                 case LINUX_KBD_RAW:
1987                         kbdmode = K_RAW;
1988                         break;
1989                 case LINUX_KBD_XLATE:
1990                         kbdmode = K_XLATE;
1991                         break;
1992                 case LINUX_KBD_MEDIUMRAW:
1993                         kbdmode = K_RAW;
1994                         break;
1995                 default:
1996                         fdrop(fp, td);
1997                         return (EINVAL);
1998                 }
1999                 error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode,
2000                     td->td_ucred, td));
2001                 break;
2002         }
2003
2004         case LINUX_VT_OPENQRY:
2005                 args->cmd = VT_OPENQRY;
2006                 error = (ioctl(td, (struct ioctl_args *)args));
2007                 break;
2008
2009         case LINUX_VT_GETMODE:
2010                 args->cmd = VT_GETMODE;
2011                 error = (ioctl(td, (struct ioctl_args *)args));
2012                 break;
2013
2014         case LINUX_VT_SETMODE: {
2015                 struct vt_mode mode;
2016                 if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
2017                         break;
2018                 if (!ISSIGVALID(mode.frsig) && ISSIGVALID(mode.acqsig))
2019                         mode.frsig = mode.acqsig;
2020                 if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
2021                         break;
2022                 args->cmd = VT_SETMODE;
2023                 error = (ioctl(td, (struct ioctl_args *)args));
2024                 break;
2025         }
2026
2027         case LINUX_VT_GETSTATE:
2028                 args->cmd = VT_GETACTIVE;
2029                 error = (ioctl(td, (struct ioctl_args *)args));
2030                 break;
2031
2032         case LINUX_VT_RELDISP:
2033                 args->cmd = VT_RELDISP;
2034                 error = (ioctl(td, (struct ioctl_args *)args));
2035                 break;
2036
2037         case LINUX_VT_ACTIVATE:
2038                 args->cmd = VT_ACTIVATE;
2039                 error = (ioctl(td, (struct ioctl_args *)args));
2040                 break;
2041
2042         case LINUX_VT_WAITACTIVE:
2043                 args->cmd = VT_WAITACTIVE;
2044                 error = (ioctl(td, (struct ioctl_args *)args));
2045                 break;
2046
2047         default:
2048                 error = ENOIOCTL;
2049                 break;
2050         }
2051
2052         fdrop(fp, td);
2053         return (error);
2054 }
2055
2056 /*
2057  * Criteria for interface name translation
2058  */
2059 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
2060
2061 /*
2062  * Interface function used by linprocfs (at the time of writing). It's not
2063  * used by the Linuxulator itself.
2064  */
2065 int
2066 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
2067 {
2068         struct ifnet *ifscan;
2069         int ethno;
2070
2071         IFNET_RLOCK_ASSERT();
2072
2073         /* Short-circuit non ethernet interfaces */
2074         if (!IFP_IS_ETH(ifp))
2075                 return (strlcpy(buffer, ifp->if_xname, buflen));
2076
2077         /* Determine the (relative) unit number for ethernet interfaces */
2078         ethno = 0;
2079         TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
2080                 if (ifscan == ifp)
2081                         return (snprintf(buffer, buflen, "eth%d", ethno));
2082                 if (IFP_IS_ETH(ifscan))
2083                         ethno++;
2084         }
2085
2086         return (0);
2087 }
2088
2089 /*
2090  * Translate a Linux interface name to a FreeBSD interface name,
2091  * and return the associated ifnet structure
2092  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
2093  * can point to the same buffer.
2094  */
2095
2096 static struct ifnet *
2097 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
2098 {
2099         struct ifnet *ifp;
2100         int len, unit;
2101         char *ep;
2102         int is_eth, index;
2103
2104         for (len = 0; len < LINUX_IFNAMSIZ; ++len)
2105                 if (!isalpha(lxname[len]))
2106                         break;
2107         if (len == 0 || len == LINUX_IFNAMSIZ)
2108                 return (NULL);
2109         unit = (int)strtoul(lxname + len, &ep, 10);
2110         if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ)
2111                 return (NULL);
2112         index = 0;
2113         is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0;
2114         CURVNET_SET(TD_TO_VNET(td));
2115         IFNET_RLOCK();
2116         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2117                 /*
2118                  * Allow Linux programs to use FreeBSD names. Don't presume
2119                  * we never have an interface named "eth", so don't make
2120                  * the test optional based on is_eth.
2121                  */
2122                 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
2123                         break;
2124                 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
2125                         break;
2126         }
2127         IFNET_RUNLOCK();
2128         CURVNET_RESTORE();
2129         if (ifp != NULL)
2130                 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
2131         return (ifp);
2132 }
2133
2134 /*
2135  * Implement the SIOCGIFCONF ioctl
2136  */
2137
2138 static int
2139 linux_ifconf(struct thread *td, struct ifconf *uifc)
2140 {
2141 #ifdef COMPAT_LINUX32
2142         struct l_ifconf ifc;
2143 #else
2144         struct ifconf ifc;
2145 #endif
2146         struct l_ifreq ifr;
2147         struct ifnet *ifp;
2148         struct ifaddr *ifa;
2149         struct sbuf *sb;
2150         int error, ethno, full = 0, valid_len, max_len;
2151
2152         error = copyin(uifc, &ifc, sizeof(ifc));
2153         if (error != 0)
2154                 return (error);
2155
2156         max_len = MAXPHYS - 1;
2157
2158         CURVNET_SET(TD_TO_VNET(td));
2159         /* handle the 'request buffer size' case */
2160         if (ifc.ifc_buf == PTROUT(NULL)) {
2161                 ifc.ifc_len = 0;
2162                 IFNET_RLOCK();
2163                 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2164                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2165                                 struct sockaddr *sa = ifa->ifa_addr;
2166                                 if (sa->sa_family == AF_INET)
2167                                         ifc.ifc_len += sizeof(ifr);
2168                         }
2169                 }
2170                 IFNET_RUNLOCK();
2171                 error = copyout(&ifc, uifc, sizeof(ifc));
2172                 CURVNET_RESTORE();
2173                 return (error);
2174         }
2175
2176         if (ifc.ifc_len <= 0) {
2177                 CURVNET_RESTORE();
2178                 return (EINVAL);
2179         }
2180
2181 again:
2182         /* Keep track of eth interfaces */
2183         ethno = 0;
2184         if (ifc.ifc_len <= max_len) {
2185                 max_len = ifc.ifc_len;
2186                 full = 1;
2187         }
2188         sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
2189         max_len = 0;
2190         valid_len = 0;
2191
2192         /* Return all AF_INET addresses of all interfaces */
2193         IFNET_RLOCK();
2194         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2195                 int addrs = 0;
2196
2197                 bzero(&ifr, sizeof(ifr));
2198                 if (IFP_IS_ETH(ifp))
2199                         snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
2200                             ethno++);
2201                 else
2202                         strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
2203
2204                 /* Walk the address list */
2205                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2206                         struct sockaddr *sa = ifa->ifa_addr;
2207
2208                         if (sa->sa_family == AF_INET) {
2209                                 ifr.ifr_addr.sa_family = LINUX_AF_INET;
2210                                 memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
2211                                     sizeof(ifr.ifr_addr.sa_data));
2212                                 sbuf_bcat(sb, &ifr, sizeof(ifr));
2213                                 max_len += sizeof(ifr);
2214                                 addrs++;
2215                         }
2216
2217                         if (!sbuf_overflowed(sb))
2218                                 valid_len = sbuf_len(sb);
2219                 }
2220                 if (addrs == 0) {
2221                         bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
2222                         sbuf_bcat(sb, &ifr, sizeof(ifr));
2223                         max_len += sizeof(ifr);
2224
2225                         if (!sbuf_overflowed(sb))
2226                                 valid_len = sbuf_len(sb);
2227                 }
2228         }
2229         IFNET_RUNLOCK();
2230
2231         if (valid_len != max_len && !full) {
2232                 sbuf_delete(sb);
2233                 goto again;
2234         }
2235
2236         ifc.ifc_len = valid_len; 
2237         sbuf_finish(sb);
2238         memcpy(PTRIN(ifc.ifc_buf), sbuf_data(sb), ifc.ifc_len);
2239         error = copyout(&ifc, uifc, sizeof(ifc));
2240         sbuf_delete(sb);
2241         CURVNET_RESTORE();
2242
2243         return (error);
2244 }
2245
2246 static int
2247 linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
2248 {
2249         l_short flags;
2250
2251         flags = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
2252         /* these flags have no Linux equivalent */
2253         flags &= ~(IFF_SMART|IFF_DRV_OACTIVE|IFF_SIMPLEX|
2254             IFF_LINK0|IFF_LINK1|IFF_LINK2);
2255         /* Linux' multicast flag is in a different bit */
2256         if (flags & IFF_MULTICAST) {
2257                 flags &= ~IFF_MULTICAST;
2258                 flags |= 0x1000;
2259         }
2260
2261         return (copyout(&flags, &ifr->ifr_flags, sizeof(flags)));
2262 }
2263
2264 #define ARPHRD_ETHER    1
2265 #define ARPHRD_LOOPBACK 772
2266
2267 static int
2268 linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
2269 {
2270         struct ifaddr *ifa;
2271         struct sockaddr_dl *sdl;
2272         struct l_sockaddr lsa;
2273
2274         if (ifp->if_type == IFT_LOOP) {
2275                 bzero(&lsa, sizeof(lsa));
2276                 lsa.sa_family = ARPHRD_LOOPBACK;
2277                 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
2278         }
2279
2280         if (ifp->if_type != IFT_ETHER)
2281                 return (ENOENT);
2282
2283         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2284                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
2285                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
2286                     (sdl->sdl_type == IFT_ETHER)) {
2287                         bzero(&lsa, sizeof(lsa));
2288                         lsa.sa_family = ARPHRD_ETHER;
2289                         bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN);
2290                         return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
2291                 }
2292         }
2293
2294         return (ENOENT);
2295 }
2296
2297
2298  /*
2299 * If we fault in bsd_to_linux_ifreq() then we will fault when we call
2300 * the native ioctl().  Thus, we don't really need to check the return
2301 * value of this function.
2302 */
2303 static int
2304 bsd_to_linux_ifreq(struct ifreq *arg)
2305 {
2306         struct ifreq ifr;
2307         size_t ifr_len = sizeof(struct ifreq);
2308         int error;
2309         
2310         if ((error = copyin(arg, &ifr, ifr_len)))
2311                 return (error);
2312         
2313         *(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family;
2314         
2315         error = copyout(&ifr, arg, ifr_len);
2316
2317         return (error);
2318 }
2319
2320 /*
2321  * Socket related ioctls
2322  */
2323
2324 static int
2325 linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
2326 {
2327         char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
2328         struct ifnet *ifp;
2329         struct file *fp;
2330         int error, type;
2331
2332         ifp = NULL;
2333         error = 0;
2334
2335         if ((error = fget(td, args->fd, &fp)) != 0)
2336                 return (error);
2337         type = fp->f_type;
2338         fdrop(fp, td);
2339         if (type != DTYPE_SOCKET) {
2340                 /* not a socket - probably a tap / vmnet device */
2341                 switch (args->cmd) {
2342                 case LINUX_SIOCGIFADDR:
2343                 case LINUX_SIOCSIFADDR:
2344                 case LINUX_SIOCGIFFLAGS:
2345                         return (linux_ioctl_special(td, args));
2346                 default:
2347                         return (ENOIOCTL);
2348                 }
2349         }
2350
2351         switch (args->cmd & 0xffff) {
2352
2353         case LINUX_FIOGETOWN:
2354         case LINUX_FIOSETOWN:
2355         case LINUX_SIOCADDMULTI:
2356         case LINUX_SIOCATMARK:
2357         case LINUX_SIOCDELMULTI:
2358         case LINUX_SIOCGIFCONF:
2359         case LINUX_SIOCGPGRP:
2360         case LINUX_SIOCSPGRP:
2361         case LINUX_SIOCGIFCOUNT:
2362                 /* these ioctls don't take an interface name */
2363 #ifdef DEBUG
2364                 printf("%s(): ioctl %d\n", __func__,
2365                     args->cmd & 0xffff);
2366 #endif
2367                 break;
2368
2369         case LINUX_SIOCGIFFLAGS:
2370         case LINUX_SIOCGIFADDR:
2371         case LINUX_SIOCSIFADDR:
2372         case LINUX_SIOCGIFDSTADDR:
2373         case LINUX_SIOCGIFBRDADDR:
2374         case LINUX_SIOCGIFNETMASK:
2375         case LINUX_SIOCSIFNETMASK:
2376         case LINUX_SIOCGIFMTU:
2377         case LINUX_SIOCSIFMTU:
2378         case LINUX_SIOCSIFNAME:
2379         case LINUX_SIOCGIFHWADDR:
2380         case LINUX_SIOCSIFHWADDR:
2381         case LINUX_SIOCDEVPRIVATE:
2382         case LINUX_SIOCDEVPRIVATE+1:
2383         case LINUX_SIOCGIFINDEX:
2384                 /* copy in the interface name and translate it. */
2385                 error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
2386                 if (error != 0)
2387                         return (error);
2388 #ifdef DEBUG
2389                 printf("%s(): ioctl %d on %.*s\n", __func__,
2390                     args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname);
2391 #endif
2392                 ifp = ifname_linux_to_bsd(td, lifname, ifname);
2393                 if (ifp == NULL)
2394                         return (EINVAL);
2395                 /*
2396                  * We need to copy it back out in case we pass the
2397                  * request on to our native ioctl(), which will expect
2398                  * the ifreq to be in user space and have the correct
2399                  * interface name.
2400                  */
2401                 error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
2402                 if (error != 0)
2403                         return (error);
2404 #ifdef DEBUG
2405                 printf("%s(): %s translated to %s\n", __func__,
2406                     lifname, ifname);
2407 #endif
2408                 break;
2409
2410         default:
2411                 return (ENOIOCTL);
2412         }
2413
2414         switch (args->cmd & 0xffff) {
2415
2416         case LINUX_FIOSETOWN:
2417                 args->cmd = FIOSETOWN;
2418                 error = ioctl(td, (struct ioctl_args *)args);
2419                 break;
2420
2421         case LINUX_SIOCSPGRP:
2422                 args->cmd = SIOCSPGRP;
2423                 error = ioctl(td, (struct ioctl_args *)args);
2424                 break;
2425
2426         case LINUX_FIOGETOWN:
2427                 args->cmd = FIOGETOWN;
2428                 error = ioctl(td, (struct ioctl_args *)args);
2429                 break;
2430
2431         case LINUX_SIOCGPGRP:
2432                 args->cmd = SIOCGPGRP;
2433                 error = ioctl(td, (struct ioctl_args *)args);
2434                 break;
2435
2436         case LINUX_SIOCATMARK:
2437                 args->cmd = SIOCATMARK;
2438                 error = ioctl(td, (struct ioctl_args *)args);
2439                 break;
2440
2441         /* LINUX_SIOCGSTAMP */
2442
2443         case LINUX_SIOCGIFCONF:
2444                 error = linux_ifconf(td, (struct ifconf *)args->arg);
2445                 break;
2446
2447         case LINUX_SIOCGIFFLAGS:
2448                 args->cmd = SIOCGIFFLAGS;
2449                 error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
2450                 break;
2451
2452         case LINUX_SIOCGIFADDR:
2453                 args->cmd = SIOCGIFADDR;
2454                 error = ioctl(td, (struct ioctl_args *)args);
2455                 bsd_to_linux_ifreq((struct ifreq *)args->arg);
2456                 break;
2457
2458         case LINUX_SIOCSIFADDR:
2459                 /* XXX probably doesn't work, included for completeness */
2460                 args->cmd = SIOCSIFADDR;
2461                 error = ioctl(td, (struct ioctl_args *)args);
2462                 break;
2463
2464         case LINUX_SIOCGIFDSTADDR:
2465                 args->cmd = SIOCGIFDSTADDR;
2466                 error = ioctl(td, (struct ioctl_args *)args);
2467                 bsd_to_linux_ifreq((struct ifreq *)args->arg);
2468                 break;
2469
2470         case LINUX_SIOCGIFBRDADDR:
2471                 args->cmd = SIOCGIFBRDADDR;
2472                 error = ioctl(td, (struct ioctl_args *)args);
2473                 bsd_to_linux_ifreq((struct ifreq *)args->arg);
2474                 break;
2475
2476         case LINUX_SIOCGIFNETMASK:
2477                 args->cmd = SIOCGIFNETMASK;
2478                 error = ioctl(td, (struct ioctl_args *)args);
2479                 bsd_to_linux_ifreq((struct ifreq *)args->arg);
2480                 break;
2481
2482         case LINUX_SIOCSIFNETMASK:
2483                 error = ENOIOCTL;
2484                 break;
2485
2486         case LINUX_SIOCGIFMTU:
2487                 args->cmd = SIOCGIFMTU;
2488                 error = ioctl(td, (struct ioctl_args *)args);
2489                 break;
2490
2491         case LINUX_SIOCSIFMTU:
2492                 args->cmd = SIOCSIFMTU;
2493                 error = ioctl(td, (struct ioctl_args *)args);
2494                 break;
2495
2496         case LINUX_SIOCSIFNAME:
2497                 error = ENOIOCTL;
2498                 break;
2499
2500         case LINUX_SIOCGIFHWADDR:
2501                 error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
2502                 break;
2503
2504         case LINUX_SIOCSIFHWADDR:
2505                 error = ENOIOCTL;
2506                 break;
2507
2508         case LINUX_SIOCADDMULTI:
2509                 args->cmd = SIOCADDMULTI;
2510                 error = ioctl(td, (struct ioctl_args *)args);
2511                 break;
2512
2513         case LINUX_SIOCDELMULTI:
2514                 args->cmd = SIOCDELMULTI;
2515                 error = ioctl(td, (struct ioctl_args *)args);
2516                 break;
2517
2518         case LINUX_SIOCGIFINDEX:
2519                 args->cmd = SIOCGIFINDEX;
2520                 error = ioctl(td, (struct ioctl_args *)args);
2521                 break;
2522
2523         case LINUX_SIOCGIFCOUNT:
2524                 error = 0;
2525                 break;
2526
2527         /*
2528          * XXX This is slightly bogus, but these ioctls are currently
2529          * XXX only used by the aironet (if_an) network driver.
2530          */
2531         case LINUX_SIOCDEVPRIVATE:
2532                 args->cmd = SIOCGPRIVATE_0;
2533                 error = ioctl(td, (struct ioctl_args *)args);
2534                 break;
2535
2536         case LINUX_SIOCDEVPRIVATE+1:
2537                 args->cmd = SIOCGPRIVATE_1;
2538                 error = ioctl(td, (struct ioctl_args *)args);
2539                 break;
2540         }
2541
2542         if (ifp != NULL)
2543                 /* restore the original interface name */
2544                 copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
2545
2546 #ifdef DEBUG
2547         printf("%s(): returning %d\n", __func__, error);
2548 #endif
2549         return (error);
2550 }
2551
2552 /*
2553  * Device private ioctl handler
2554  */
2555 static int
2556 linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
2557 {
2558         struct file *fp;
2559         int error, type;
2560
2561         if ((error = fget(td, args->fd, &fp)) != 0)
2562                 return (error);
2563         type = fp->f_type;
2564         fdrop(fp, td);
2565         if (type == DTYPE_SOCKET)
2566                 return (linux_ioctl_socket(td, args));
2567         return (ENOIOCTL);
2568 }
2569
2570 /*
2571  * DRM ioctl handler (sys/dev/drm)
2572  */
2573 static int
2574 linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
2575 {
2576         args->cmd = SETDIR(args->cmd);
2577         return ioctl(td, (struct ioctl_args *)args);
2578 }
2579
2580 static int
2581 linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
2582 {
2583         struct file *fp;
2584         u_long cmd;
2585         int error;
2586
2587         if ((error = fget(td, args->fd, &fp)) != 0) {
2588                 printf("sg_linux_ioctl: fget returned %d\n", error);
2589                 return (error);
2590         }
2591         cmd = args->cmd;
2592
2593         error = (fo_ioctl(fp, cmd, (caddr_t)args->arg, td->td_ucred, td));
2594         fdrop(fp, td);
2595         return (error);
2596 }
2597
2598 /*
2599  * Video4Linux (V4L) ioctl handler
2600  */
2601 static int
2602 linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt)
2603 {
2604         vt->tuner = lvt->tuner;
2605         strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2606         vt->rangelow = lvt->rangelow;   /* possible long size conversion */
2607         vt->rangehigh = lvt->rangehigh; /* possible long size conversion */
2608         vt->flags = lvt->flags;
2609         vt->mode = lvt->mode;
2610         vt->signal = lvt->signal;
2611         return (0);
2612 }
2613
2614 static int
2615 bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt)
2616 {
2617         lvt->tuner = vt->tuner;
2618         strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2619         lvt->rangelow = vt->rangelow;   /* possible long size conversion */
2620         lvt->rangehigh = vt->rangehigh; /* possible long size conversion */
2621         lvt->flags = vt->flags;
2622         lvt->mode = vt->mode;
2623         lvt->signal = vt->signal;
2624         return (0);
2625 }
2626
2627 #ifdef COMPAT_LINUX_V4L_CLIPLIST
2628 static int
2629 linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc)
2630 {
2631         vc->x = lvc->x;
2632         vc->y = lvc->y;
2633         vc->width = lvc->width;
2634         vc->height = lvc->height;
2635         vc->next = PTRIN(lvc->next);    /* possible pointer size conversion */
2636         return (0);
2637 }
2638 #endif
2639
2640 static int
2641 linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw)
2642 {
2643         vw->x = lvw->x;
2644         vw->y = lvw->y;
2645         vw->width = lvw->width;
2646         vw->height = lvw->height;
2647         vw->chromakey = lvw->chromakey;
2648         vw->flags = lvw->flags;
2649         vw->clips = PTRIN(lvw->clips);  /* possible pointer size conversion */
2650         vw->clipcount = lvw->clipcount;
2651         return (0);
2652 }
2653
2654 static int
2655 bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw)
2656 {
2657         lvw->x = vw->x;
2658         lvw->y = vw->y;
2659         lvw->width = vw->width;
2660         lvw->height = vw->height;
2661         lvw->chromakey = vw->chromakey;
2662         lvw->flags = vw->flags;
2663         lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */
2664         lvw->clipcount = vw->clipcount;
2665         return (0);
2666 }
2667
2668 static int
2669 linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb)
2670 {
2671         vb->base = PTRIN(lvb->base);    /* possible pointer size conversion */
2672         vb->height = lvb->height;
2673         vb->width = lvb->width;
2674         vb->depth = lvb->depth;
2675         vb->bytesperline = lvb->bytesperline;
2676         return (0);
2677 }
2678
2679 static int
2680 bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb)
2681 {
2682         lvb->base = PTROUT(vb->base);   /* possible pointer size conversion */
2683         lvb->height = vb->height;
2684         lvb->width = vb->width;
2685         lvb->depth = vb->depth;
2686         lvb->bytesperline = vb->bytesperline;
2687         return (0);
2688 }
2689
2690 static int
2691 linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc)
2692 {
2693         strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE);
2694         vc->datasize = lvc->datasize;
2695         vc->data = PTRIN(lvc->data);    /* possible pointer size conversion */
2696         return (0);
2697 }
2698
2699 #ifdef COMPAT_LINUX_V4L_CLIPLIST
2700 static int
2701 linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc)
2702 {
2703         int error;
2704         struct video_clip vclip;
2705         struct l_video_clip l_vclip;
2706
2707         error = copyin(lvc, &l_vclip, sizeof(l_vclip));
2708         if (error) return (error);
2709         linux_to_bsd_v4l_clip(&l_vclip, &vclip);
2710         /* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */
2711         if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL)
2712                 return (ENOMEM);    /* XXX: linux has no ENOMEM here */
2713         memcpy(*ppvc, &vclip, sizeof(vclip));
2714         (*ppvc)->next = NULL;
2715         return (0);
2716 }
2717
2718 static int
2719 linux_v4l_cliplist_free(struct video_window *vw)
2720 {
2721         struct video_clip **ppvc;
2722         struct video_clip **ppvc_next;
2723
2724         for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) {
2725                 ppvc_next = &((*ppvc)->next);
2726                 free(*ppvc, M_LINUX);
2727         }
2728         vw->clips = NULL;
2729
2730         return (0);
2731 }
2732
2733 static int
2734 linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
2735 {
2736         int error;
2737         int clipcount;
2738         void *plvc;
2739         struct video_clip **ppvc;
2740
2741         /*
2742          * XXX: The cliplist is used to pass in a list of clipping
2743          *      rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a
2744          *      clipping bitmap.  Some Linux apps, however, appear to
2745          *      leave cliplist and clips uninitialized.  In any case,
2746          *      the cliplist is not used by pwc(4), at the time of
2747          *      writing, FreeBSD's only V4L driver.  When a driver
2748          *      that uses the cliplist is developed, this code may
2749          *      need re-examiniation.
2750          */
2751         error = 0;
2752         clipcount = vw->clipcount;
2753         if (clipcount == VIDEO_CLIP_BITMAP) {
2754                 /*
2755                  * In this case, the pointer (clips) is overloaded
2756                  * to be a "void *" to a bitmap, therefore there
2757                  * is no struct video_clip to copy now.
2758                  */
2759         } else if (clipcount > 0 && clipcount <= 16384) {
2760                 /*
2761                  * Clips points to list of clip rectangles, so
2762                  * copy the list.
2763                  *
2764                  * XXX: Upper limit of 16384 was used here to try to
2765                  *      avoid cases when clipcount and clips pointer
2766                  *      are uninitialized and therefore have high random
2767                  *      values, as is the case in the Linux Skype
2768                  *      application.  The value 16384 was chosen as that
2769                  *      is what is used in the Linux stradis(4) MPEG
2770                  *      decoder driver, the only place we found an
2771                  *      example of cliplist use.
2772                  */
2773                 plvc = PTRIN(lvw->clips);
2774                 vw->clips = NULL;
2775                 ppvc = &(vw->clips);
2776                 while (clipcount-- > 0) {
2777                         if (plvc == 0) {
2778                                 error = EFAULT;
2779                                 break;
2780                         } else {
2781                                 error = linux_v4l_clip_copy(plvc, ppvc);
2782                                 if (error) {
2783                                         linux_v4l_cliplist_free(vw);
2784                                         break;
2785                                 }
2786                         }
2787                         ppvc = &((*ppvc)->next);
2788                         plvc = PTRIN(((struct l_video_clip *) plvc)->next);
2789                 }
2790         } else {
2791                 /*
2792                  * clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP)
2793                  * Force cliplist to null.
2794                  */
2795                 vw->clipcount = 0;
2796                 vw->clips = NULL;
2797         }
2798         return (error);
2799 }
2800 #endif
2801
2802 static int
2803 linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
2804 {
2805         struct file *fp;
2806         int error;
2807         struct video_tuner vtun;
2808         struct video_window vwin;
2809         struct video_buffer vbuf;
2810         struct video_code vcode;
2811         struct l_video_tuner l_vtun;
2812         struct l_video_window l_vwin;
2813         struct l_video_buffer l_vbuf;
2814         struct l_video_code l_vcode;
2815
2816         switch (args->cmd & 0xffff) {
2817         case LINUX_VIDIOCGCAP:          args->cmd = VIDIOCGCAP; break;
2818         case LINUX_VIDIOCGCHAN:         args->cmd = VIDIOCGCHAN; break;
2819         case LINUX_VIDIOCSCHAN:         args->cmd = VIDIOCSCHAN; break;
2820
2821         case LINUX_VIDIOCGTUNER:
2822                 if ((error = fget(td, args->fd, &fp)) != 0)
2823                         return (error);
2824                 error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2825                 if (error) {
2826                         fdrop(fp, td);
2827                         return (error);
2828                 }
2829                 linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2830                 error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td);
2831                 if (!error) {
2832                         bsd_to_linux_v4l_tuner(&vtun, &l_vtun);
2833                         error = copyout(&l_vtun, (void *) args->arg,
2834                             sizeof(l_vtun));
2835                 }
2836                 fdrop(fp, td);
2837                 return (error);
2838
2839         case LINUX_VIDIOCSTUNER:
2840                 if ((error = fget(td, args->fd, &fp)) != 0)
2841                         return (error);
2842                 error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2843                 if (error) {
2844                         fdrop(fp, td);
2845                         return (error);
2846                 }
2847                 linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2848                 error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td);
2849                 fdrop(fp, td);
2850                 return (error);
2851
2852         case LINUX_VIDIOCGPICT:         args->cmd = VIDIOCGPICT; break;
2853         case LINUX_VIDIOCSPICT:         args->cmd = VIDIOCSPICT; break;
2854         case LINUX_VIDIOCCAPTURE:       args->cmd = VIDIOCCAPTURE; break;
2855
2856         case LINUX_VIDIOCGWIN:
2857                 if ((error = fget(td, args->fd, &fp)) != 0)
2858                         return (error);
2859                 error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
2860                 if (!error) {
2861                         bsd_to_linux_v4l_window(&vwin, &l_vwin);
2862                         error = copyout(&l_vwin, (void *) args->arg,
2863                             sizeof(l_vwin));
2864                 }
2865                 fdrop(fp, td);
2866                 return (error);
2867
2868         case LINUX_VIDIOCSWIN:
2869                 if ((error = fget(td, args->fd, &fp)) != 0)
2870                         return (error);
2871                 error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
2872                 if (error) {
2873                         fdrop(fp, td);
2874                         return (error);
2875                 }
2876                 linux_to_bsd_v4l_window(&l_vwin, &vwin);
2877 #ifdef COMPAT_LINUX_V4L_CLIPLIST
2878                 error = linux_v4l_cliplist_copy(&l_vwin, &vwin);
2879                 if (error) {
2880                         fdrop(fp, td);
2881                         return (error);
2882                 }
2883 #endif
2884                 error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td);
2885                 fdrop(fp, td);
2886 #ifdef COMPAT_LINUX_V4L_CLIPLIST
2887                 linux_v4l_cliplist_free(&vwin);
2888 #endif
2889                 return (error);
2890
2891         case LINUX_VIDIOCGFBUF:
2892                 if ((error = fget(td, args->fd, &fp)) != 0)
2893                         return (error);
2894                 error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
2895                 if (!error) {
2896                         bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf);
2897                         error = copyout(&l_vbuf, (void *) args->arg,
2898                             sizeof(l_vbuf));
2899                 }
2900                 fdrop(fp, td);
2901                 return (error);
2902
2903         case LINUX_VIDIOCSFBUF:
2904                 if ((error = fget(td, args->fd, &fp)) != 0)
2905                         return (error);
2906                 error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
2907                 if (error) {
2908                         fdrop(fp, td);
2909                         return (error);
2910                 }
2911                 linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf);
2912                 error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td);
2913                 fdrop(fp, td);
2914                 return (error);
2915
2916         case LINUX_VIDIOCKEY:           args->cmd = VIDIOCKEY; break;
2917         case LINUX_VIDIOCGFREQ:         args->cmd = VIDIOCGFREQ; break;
2918         case LINUX_VIDIOCSFREQ:         args->cmd = VIDIOCSFREQ; break;
2919         case LINUX_VIDIOCGAUDIO:        args->cmd = VIDIOCGAUDIO; break;
2920         case LINUX_VIDIOCSAUDIO:        args->cmd = VIDIOCSAUDIO; break;
2921         case LINUX_VIDIOCSYNC:          args->cmd = VIDIOCSYNC; break;
2922         case LINUX_VIDIOCMCAPTURE:      args->cmd = VIDIOCMCAPTURE; break;
2923         case LINUX_VIDIOCGMBUF:         args->cmd = VIDIOCGMBUF; break;
2924         case LINUX_VIDIOCGUNIT:         args->cmd = VIDIOCGUNIT; break;
2925         case LINUX_VIDIOCGCAPTURE:      args->cmd = VIDIOCGCAPTURE; break;
2926         case LINUX_VIDIOCSCAPTURE:      args->cmd = VIDIOCSCAPTURE; break;
2927         case LINUX_VIDIOCSPLAYMODE:     args->cmd = VIDIOCSPLAYMODE; break;
2928         case LINUX_VIDIOCSWRITEMODE:    args->cmd = VIDIOCSWRITEMODE; break;
2929         case LINUX_VIDIOCGPLAYINFO:     args->cmd = VIDIOCGPLAYINFO; break;
2930
2931         case LINUX_VIDIOCSMICROCODE:
2932                 if ((error = fget(td, args->fd, &fp)) != 0)
2933                         return (error);
2934                 error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
2935                 if (error) {
2936                         fdrop(fp, td);
2937                         return (error);
2938                 }
2939                 linux_to_bsd_v4l_code(&l_vcode, &vcode);
2940                 error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td);
2941                 fdrop(fp, td);
2942                 return (error);
2943
2944         case LINUX_VIDIOCGVBIFMT:       args->cmd = VIDIOCGVBIFMT; break;
2945         case LINUX_VIDIOCSVBIFMT:       args->cmd = VIDIOCSVBIFMT; break;
2946         default:                        return (ENOIOCTL);
2947         }
2948
2949         error = ioctl(td, (struct ioctl_args *)args);
2950         return (error);
2951 }
2952
2953 /*
2954  * Special ioctl handler
2955  */
2956 static int
2957 linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
2958 {
2959         int error;
2960
2961         switch (args->cmd) {
2962         case LINUX_SIOCGIFADDR:
2963                 args->cmd = SIOCGIFADDR;
2964                 error = ioctl(td, (struct ioctl_args *)args);
2965                 break;
2966         case LINUX_SIOCSIFADDR:
2967                 args->cmd = SIOCSIFADDR;
2968                 error = ioctl(td, (struct ioctl_args *)args);
2969                 break;
2970         case LINUX_SIOCGIFFLAGS:
2971                 args->cmd = SIOCGIFFLAGS;
2972                 error = ioctl(td, (struct ioctl_args *)args);
2973                 break;
2974         default:
2975                 error = ENOIOCTL;
2976         }
2977
2978         return (error);
2979 }
2980
2981 /*
2982  * main ioctl syscall function
2983  */
2984
2985 int
2986 linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
2987 {
2988         struct file *fp;
2989         struct handler_element *he;
2990         int error, cmd;
2991
2992 #ifdef DEBUG
2993         if (ldebug(ioctl))
2994                 printf(ARGS(ioctl, "%d, %04lx, *"), args->fd,
2995                     (unsigned long)args->cmd);
2996 #endif
2997
2998         if ((error = fget(td, args->fd, &fp)) != 0)
2999                 return (error);
3000         if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
3001                 fdrop(fp, td);
3002                 return (EBADF);
3003         }
3004
3005         /* Iterate over the ioctl handlers */
3006         cmd = args->cmd & 0xffff;
3007         sx_slock(&linux_ioctl_sx);
3008         mtx_lock(&Giant);
3009         TAILQ_FOREACH(he, &handlers, list) {
3010                 if (cmd >= he->low && cmd <= he->high) {
3011                         error = (*he->func)(td, args);
3012                         if (error != ENOIOCTL) {
3013                                 mtx_unlock(&Giant);
3014                                 sx_sunlock(&linux_ioctl_sx);
3015                                 fdrop(fp, td);
3016                                 return (error);
3017                         }
3018                 }
3019         }
3020         mtx_unlock(&Giant);
3021         sx_sunlock(&linux_ioctl_sx);
3022         fdrop(fp, td);
3023
3024         linux_msg(td, "ioctl fd=%d, cmd=0x%x ('%c',%d) is not implemented",
3025             args->fd, (int)(args->cmd & 0xffff),
3026             (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
3027
3028         return (EINVAL);
3029 }
3030
3031 int
3032 linux_ioctl_register_handler(struct linux_ioctl_handler *h)
3033 {
3034         struct handler_element *he, *cur;
3035
3036         if (h == NULL || h->func == NULL)
3037                 return (EINVAL);
3038
3039         /*
3040          * Reuse the element if the handler is already on the list, otherwise
3041          * create a new element.
3042          */
3043         sx_xlock(&linux_ioctl_sx);
3044         TAILQ_FOREACH(he, &handlers, list) {
3045                 if (he->func == h->func)
3046                         break;
3047         }
3048         if (he == NULL) {
3049                 he = malloc(sizeof(*he),
3050                     M_LINUX, M_WAITOK);
3051                 he->func = h->func;
3052         } else
3053                 TAILQ_REMOVE(&handlers, he, list);
3054
3055         /* Initialize range information. */
3056         he->low = h->low;
3057         he->high = h->high;
3058         he->span = h->high - h->low + 1;
3059
3060         /* Add the element to the list, sorted on span. */
3061         TAILQ_FOREACH(cur, &handlers, list) {
3062                 if (cur->span > he->span) {
3063                         TAILQ_INSERT_BEFORE(cur, he, list);
3064                         sx_xunlock(&linux_ioctl_sx);
3065                         return (0);
3066                 }
3067         }
3068         TAILQ_INSERT_TAIL(&handlers, he, list);
3069         sx_xunlock(&linux_ioctl_sx);
3070
3071         return (0);
3072 }
3073
3074 int
3075 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
3076 {
3077         struct handler_element *he;
3078
3079         if (h == NULL || h->func == NULL)
3080                 return (EINVAL);
3081
3082         sx_xlock(&linux_ioctl_sx);
3083         TAILQ_FOREACH(he, &handlers, list) {
3084                 if (he->func == h->func) {
3085                         TAILQ_REMOVE(&handlers, he, list);
3086                         sx_xunlock(&linux_ioctl_sx);
3087                         free(he, M_LINUX);
3088                         return (0);
3089                 }
3090         }
3091         sx_xunlock(&linux_ioctl_sx);
3092
3093         return (EINVAL);
3094 }