xref: /freebsd/sys/compat/linux/linux_ioctl.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
1 /*
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/proc.h>
35 #include <sys/cdio.h>
36 #include <sys/fcntl.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/filio.h>
40 #include <sys/linker_set.h>
41 #include <sys/malloc.h>
42 #include <sys/tty.h>
43 #include <sys/socket.h>
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <net/if_types.h>
47 #include <sys/sockio.h>
48 #include <sys/soundcard.h>
49 #include <sys/disklabel.h>
50 
51 #include <machine/console.h>
52 
53 #include <i386/linux/linux.h>
54 #include <i386/linux/linux_ioctl.h>
55 #include <i386/linux/linux_mib.h>
56 #include <i386/linux/linux_proto.h>
57 #include <i386/linux/linux_util.h>
58 
59 static linux_ioctl_function_t linux_ioctl_cdrom;
60 static linux_ioctl_function_t linux_ioctl_console;
61 static linux_ioctl_function_t linux_ioctl_disk;
62 static linux_ioctl_function_t linux_ioctl_socket;
63 static linux_ioctl_function_t linux_ioctl_sound;
64 static linux_ioctl_function_t linux_ioctl_termio;
65 
66 static struct linux_ioctl_handler cdrom_handler =
67 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX };
68 static struct linux_ioctl_handler console_handler =
69 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX };
70 static struct linux_ioctl_handler disk_handler =
71 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX };
72 static struct linux_ioctl_handler socket_handler =
73 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX };
74 static struct linux_ioctl_handler sound_handler =
75 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX };
76 static struct linux_ioctl_handler termio_handler =
77 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX };
78 
79 DATA_SET(linux_ioctl_handler_set, cdrom_handler);
80 DATA_SET(linux_ioctl_handler_set, console_handler);
81 DATA_SET(linux_ioctl_handler_set, disk_handler);
82 DATA_SET(linux_ioctl_handler_set, socket_handler);
83 DATA_SET(linux_ioctl_handler_set, sound_handler);
84 DATA_SET(linux_ioctl_handler_set, termio_handler);
85 
86 struct handler_element
87 {
88 	TAILQ_ENTRY(handler_element) list;
89 	int	(*func)(struct proc *, struct linux_ioctl_args *);
90 	int	low, high, span;
91 };
92 
93 static TAILQ_HEAD(, handler_element) handlers =
94 	TAILQ_HEAD_INITIALIZER(handlers);
95 
96 static int
97 linux_ioctl_disk(struct proc *p, struct linux_ioctl_args *args)
98 {
99 	struct file *fp = p->p_fd->fd_ofiles[args->fd];
100 	int error;
101 	struct disklabel dl;
102 
103 	switch (args->cmd & 0xffff) {
104 	case LINUX_BLKGETSIZE:
105 		error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, p);
106 		if (error)
107 			return (error);
108 		return copyout(&(dl.d_secperunit), (caddr_t)args->arg, sizeof(dl.d_secperunit));
109 		break;
110 	}
111 	return (ENOIOCTL);
112 }
113 
114 /*
115  * termio related ioctls
116  */
117 
118 struct linux_termio {
119 	unsigned short c_iflag;
120 	unsigned short c_oflag;
121 	unsigned short c_cflag;
122 	unsigned short c_lflag;
123 	unsigned char c_line;
124 	unsigned char c_cc[LINUX_NCC];
125 };
126 
127 struct linux_termios {
128 	unsigned int c_iflag;
129 	unsigned int c_oflag;
130 	unsigned int c_cflag;
131 	unsigned int c_lflag;
132 	unsigned char c_line;
133 	unsigned char c_cc[LINUX_NCCS];
134 };
135 
136 struct linux_winsize {
137 	unsigned short ws_row, ws_col;
138 	unsigned short ws_xpixel, ws_ypixel;
139 };
140 
141 static struct speedtab sptab[] = {
142 	{ B0, LINUX_B0 }, { B50, LINUX_B50 },
143 	{ B75, LINUX_B75 }, { B110, LINUX_B110 },
144 	{ B134, LINUX_B134 }, { B150, LINUX_B150 },
145 	{ B200, LINUX_B200 }, { B300, LINUX_B300 },
146 	{ B600, LINUX_B600 }, { B1200, LINUX_B1200 },
147 	{ B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
148 	{ B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
149 	{ B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
150 	{ B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
151 	{-1, -1 }
152 };
153 
154 struct linux_serial_struct {
155 	int	type;
156 	int	line;
157 	int	port;
158 	int	irq;
159 	int	flags;
160 	int	xmit_fifo_size;
161 	int	custom_divisor;
162 	int	baud_base;
163 	unsigned short close_delay;
164 	char	reserved_char[2];
165 	int	hub6;
166 	unsigned short closing_wait;
167 	unsigned short closing_wait2;
168 	int	reserved[4];
169 };
170 
171 static int
172 linux_to_bsd_speed(int code, struct speedtab *table)
173 {
174 	for ( ; table->sp_code != -1; table++)
175 		if (table->sp_code == code)
176 			return (table->sp_speed);
177 	return -1;
178 }
179 
180 static int
181 bsd_to_linux_speed(int speed, struct speedtab *table)
182 {
183 	for ( ; table->sp_speed != -1; table++)
184 		if (table->sp_speed == speed)
185 			return (table->sp_code);
186 	return -1;
187 }
188 
189 static void
190 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
191 {
192 	int i;
193 
194 #ifdef DEBUG
195 	printf("LINUX: BSD termios structure (input):\n");
196 	printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
197 	    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
198 	    bios->c_ispeed, bios->c_ospeed);
199 	printf("c_cc ");
200 	for (i=0; i<NCCS; i++)
201 		printf("%02x ", bios->c_cc[i]);
202 	printf("\n");
203 #endif
204 
205 	lios->c_iflag = 0;
206 	if (bios->c_iflag & IGNBRK)
207 		lios->c_iflag |= LINUX_IGNBRK;
208 	if (bios->c_iflag & BRKINT)
209 		lios->c_iflag |= LINUX_BRKINT;
210 	if (bios->c_iflag & IGNPAR)
211 		lios->c_iflag |= LINUX_IGNPAR;
212 	if (bios->c_iflag & PARMRK)
213 		lios->c_iflag |= LINUX_PARMRK;
214 	if (bios->c_iflag & INPCK)
215 		lios->c_iflag |= LINUX_INPCK;
216 	if (bios->c_iflag & ISTRIP)
217 		lios->c_iflag |= LINUX_ISTRIP;
218 	if (bios->c_iflag & INLCR)
219 		lios->c_iflag |= LINUX_INLCR;
220 	if (bios->c_iflag & IGNCR)
221 		lios->c_iflag |= LINUX_IGNCR;
222 	if (bios->c_iflag & ICRNL)
223 		lios->c_iflag |= LINUX_ICRNL;
224 	if (bios->c_iflag & IXON)
225 		lios->c_iflag |= LINUX_IXON;
226 	if (bios->c_iflag & IXANY)
227 		lios->c_iflag |= LINUX_IXANY;
228 	if (bios->c_iflag & IXOFF)
229 		lios->c_iflag |= LINUX_IXOFF;
230 	if (bios->c_iflag & IMAXBEL)
231 		lios->c_iflag |= LINUX_IMAXBEL;
232 
233 	lios->c_oflag = 0;
234 	if (bios->c_oflag & OPOST)
235 		lios->c_oflag |= LINUX_OPOST;
236 	if (bios->c_oflag & ONLCR)
237 		lios->c_oflag |= LINUX_ONLCR;
238 	if (bios->c_oflag & OXTABS)
239 		lios->c_oflag |= LINUX_XTABS;
240 
241 	lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
242 	lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
243 	if (bios->c_cflag & CSTOPB)
244 		lios->c_cflag |= LINUX_CSTOPB;
245 	if (bios->c_cflag & CREAD)
246 		lios->c_cflag |= LINUX_CREAD;
247 	if (bios->c_cflag & PARENB)
248 		lios->c_cflag |= LINUX_PARENB;
249 	if (bios->c_cflag & PARODD)
250 		lios->c_cflag |= LINUX_PARODD;
251 	if (bios->c_cflag & HUPCL)
252 		lios->c_cflag |= LINUX_HUPCL;
253 	if (bios->c_cflag & CLOCAL)
254 		lios->c_cflag |= LINUX_CLOCAL;
255 	if (bios->c_cflag & CRTSCTS)
256 		lios->c_cflag |= LINUX_CRTSCTS;
257 
258 	lios->c_lflag = 0;
259 	if (bios->c_lflag & ISIG)
260 		lios->c_lflag |= LINUX_ISIG;
261 	if (bios->c_lflag & ICANON)
262 		lios->c_lflag |= LINUX_ICANON;
263 	if (bios->c_lflag & ECHO)
264 		lios->c_lflag |= LINUX_ECHO;
265 	if (bios->c_lflag & ECHOE)
266 		lios->c_lflag |= LINUX_ECHOE;
267 	if (bios->c_lflag & ECHOK)
268 		lios->c_lflag |= LINUX_ECHOK;
269 	if (bios->c_lflag & ECHONL)
270 		lios->c_lflag |= LINUX_ECHONL;
271 	if (bios->c_lflag & NOFLSH)
272 		lios->c_lflag |= LINUX_NOFLSH;
273 	if (bios->c_lflag & TOSTOP)
274 		lios->c_lflag |= LINUX_TOSTOP;
275 	if (bios->c_lflag & ECHOCTL)
276 		lios->c_lflag |= LINUX_ECHOCTL;
277 	if (bios->c_lflag & ECHOPRT)
278 		lios->c_lflag |= LINUX_ECHOPRT;
279 	if (bios->c_lflag & ECHOKE)
280 		lios->c_lflag |= LINUX_ECHOKE;
281 	if (bios->c_lflag & FLUSHO)
282 		lios->c_lflag |= LINUX_FLUSHO;
283 	if (bios->c_lflag & PENDIN)
284 		lios->c_lflag |= LINUX_PENDIN;
285 	if (bios->c_lflag & IEXTEN)
286 		lios->c_lflag |= LINUX_IEXTEN;
287 
288 	for (i=0; i<LINUX_NCCS; i++)
289 		lios->c_cc[i] = LINUX_POSIX_VDISABLE;
290 	lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
291 	lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
292 	lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
293 	lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
294 	lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
295 	lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
296 	lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
297 	lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
298 	lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
299 	lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
300 	lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
301 	lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
302 	lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
303 	lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
304 	lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
305 	lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
306 
307 	for (i=0; i<LINUX_NCCS; i++) {
308 		if (lios->c_cc[i] == _POSIX_VDISABLE)
309 			lios->c_cc[i] = LINUX_POSIX_VDISABLE;
310 	}
311 	lios->c_line = 0;
312 
313 #ifdef DEBUG
314 	printf("LINUX: LINUX termios structure (output):\n");
315 	printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", lios->c_iflag,
316 	    lios->c_oflag, lios->c_cflag, lios->c_lflag, (int)lios->c_line);
317 	printf("c_cc ");
318 	for (i=0; i<LINUX_NCCS; i++)
319 		printf("%02x ", lios->c_cc[i]);
320 	printf("\n");
321 #endif
322 }
323 
324 static void
325 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
326 {
327 	int i;
328 
329 #ifdef DEBUG
330 	printf("LINUX: LINUX termios structure (input):\n");
331 	printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", lios->c_iflag,
332 	    lios->c_oflag, lios->c_cflag, lios->c_lflag, (int)lios->c_line);
333 	printf("c_cc ");
334 	for (i=0; i<LINUX_NCCS; i++)
335 		printf("%02x ", lios->c_cc[i]);
336 	printf("\n");
337 #endif
338 
339 	bios->c_iflag = 0;
340 	if (lios->c_iflag & LINUX_IGNBRK)
341 		bios->c_iflag |= IGNBRK;
342 	if (lios->c_iflag & LINUX_BRKINT)
343 		bios->c_iflag |= BRKINT;
344 	if (lios->c_iflag & LINUX_IGNPAR)
345 		bios->c_iflag |= IGNPAR;
346 	if (lios->c_iflag & LINUX_PARMRK)
347 		bios->c_iflag |= PARMRK;
348 	if (lios->c_iflag & LINUX_INPCK)
349 		bios->c_iflag |= INPCK;
350 	if (lios->c_iflag & LINUX_ISTRIP)
351 		bios->c_iflag |= ISTRIP;
352 	if (lios->c_iflag & LINUX_INLCR)
353 		bios->c_iflag |= INLCR;
354 	if (lios->c_iflag & LINUX_IGNCR)
355 		bios->c_iflag |= IGNCR;
356 	if (lios->c_iflag & LINUX_ICRNL)
357 		bios->c_iflag |= ICRNL;
358 	if (lios->c_iflag & LINUX_IXON)
359 		bios->c_iflag |= IXON;
360 	if (lios->c_iflag & LINUX_IXANY)
361 		bios->c_iflag |= IXANY;
362 	if (lios->c_iflag & LINUX_IXOFF)
363 		bios->c_iflag |= IXOFF;
364 	if (lios->c_iflag & LINUX_IMAXBEL)
365 		bios->c_iflag |= IMAXBEL;
366 
367 	bios->c_oflag = 0;
368 	if (lios->c_oflag & LINUX_OPOST)
369 		bios->c_oflag |= OPOST;
370 	if (lios->c_oflag & LINUX_ONLCR)
371 		bios->c_oflag |= ONLCR;
372 	if (lios->c_oflag & LINUX_XTABS)
373 		bios->c_oflag |= OXTABS;
374 
375 	bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
376 	if (lios->c_cflag & LINUX_CSTOPB)
377 		bios->c_cflag |= CSTOPB;
378 	if (lios->c_cflag & LINUX_CREAD)
379 		bios->c_cflag |= CREAD;
380 	if (lios->c_cflag & LINUX_PARENB)
381 		bios->c_cflag |= PARENB;
382 	if (lios->c_cflag & LINUX_PARODD)
383 		bios->c_cflag |= PARODD;
384 	if (lios->c_cflag & LINUX_HUPCL)
385 		bios->c_cflag |= HUPCL;
386 	if (lios->c_cflag & LINUX_CLOCAL)
387 		bios->c_cflag |= CLOCAL;
388 	if (lios->c_cflag & LINUX_CRTSCTS)
389 		bios->c_cflag |= CRTSCTS;
390 
391 	bios->c_lflag = 0;
392 	if (lios->c_lflag & LINUX_ISIG)
393 		bios->c_lflag |= ISIG;
394 	if (lios->c_lflag & LINUX_ICANON)
395 		bios->c_lflag |= ICANON;
396 	if (lios->c_lflag & LINUX_ECHO)
397 		bios->c_lflag |= ECHO;
398 	if (lios->c_lflag & LINUX_ECHOE)
399 		bios->c_lflag |= ECHOE;
400 	if (lios->c_lflag & LINUX_ECHOK)
401 		bios->c_lflag |= ECHOK;
402 	if (lios->c_lflag & LINUX_ECHONL)
403 		bios->c_lflag |= ECHONL;
404 	if (lios->c_lflag & LINUX_NOFLSH)
405 		bios->c_lflag |= NOFLSH;
406 	if (lios->c_lflag & LINUX_TOSTOP)
407 		bios->c_lflag |= TOSTOP;
408 	if (lios->c_lflag & LINUX_ECHOCTL)
409 		bios->c_lflag |= ECHOCTL;
410 	if (lios->c_lflag & LINUX_ECHOPRT)
411 		bios->c_lflag |= ECHOPRT;
412 	if (lios->c_lflag & LINUX_ECHOKE)
413 		bios->c_lflag |= ECHOKE;
414 	if (lios->c_lflag & LINUX_FLUSHO)
415 		bios->c_lflag |= FLUSHO;
416 	if (lios->c_lflag & LINUX_PENDIN)
417 		bios->c_lflag |= PENDIN;
418 	if (lios->c_lflag & LINUX_IEXTEN)
419 		bios->c_lflag |= IEXTEN;
420 
421 	for (i=0; i<NCCS; i++)
422 		bios->c_cc[i] = _POSIX_VDISABLE;
423 	bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
424 	bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
425 	bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
426 	bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
427 	bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
428 	bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
429 	bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
430 	bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
431 	bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
432 	bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
433 	bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
434 	bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
435 	bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
436 	bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
437 	bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
438 	bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
439 
440 	for (i=0; i<NCCS; i++) {
441 		if (bios->c_cc[i] == LINUX_POSIX_VDISABLE)
442 			bios->c_cc[i] = _POSIX_VDISABLE;
443 	}
444 
445 	bios->c_ispeed = bios->c_ospeed =
446 	    linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
447 
448 #ifdef DEBUG
449 	printf("LINUX: BSD termios structure (output):\n");
450 	printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n",
451 	    bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag,
452 	    bios->c_ispeed, bios->c_ospeed);
453 	printf("c_cc ");
454 	for (i=0; i<NCCS; i++)
455 		printf("%02x ", bios->c_cc[i]);
456 	printf("\n");
457 #endif
458 }
459 
460 static void
461 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
462 {
463 	struct linux_termios lios;
464 
465 	bsd_to_linux_termios(bios, &lios);
466 	lio->c_iflag = lios.c_iflag;
467 	lio->c_oflag = lios.c_oflag;
468 	lio->c_cflag = lios.c_cflag;
469 	lio->c_lflag = lios.c_lflag;
470 	lio->c_line  = lios.c_line;
471 	memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
472 }
473 
474 static void
475 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
476 {
477 	struct linux_termios lios;
478 	int i;
479 
480 	lios.c_iflag = lio->c_iflag;
481 	lios.c_oflag = lio->c_oflag;
482 	lios.c_cflag = lio->c_cflag;
483 	lios.c_lflag = lio->c_lflag;
484 	for (i=LINUX_NCC; i<LINUX_NCCS; i++)
485 		lios.c_cc[i] = LINUX_POSIX_VDISABLE;
486 	memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
487 	linux_to_bsd_termios(&lios, bios);
488 }
489 
490 static int
491 linux_ioctl_termio(struct proc *p, struct linux_ioctl_args *args)
492 {
493 	struct termios bios;
494 	struct linux_termios lios;
495 	struct linux_termio lio;
496 	struct file *fp = p->p_fd->fd_ofiles[args->fd];
497 	int error;
498 
499 	switch (args->cmd & 0xffff) {
500 
501 	case LINUX_TCGETS:
502 		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
503 		if (error)
504 			return (error);
505 		bsd_to_linux_termios(&bios, &lios);
506 		return copyout(&lios, (caddr_t)args->arg, sizeof(lios));
507 
508 	case LINUX_TCSETS:
509 		error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
510 		if (error)
511 			return (error);
512 		linux_to_bsd_termios(&lios, &bios);
513 		return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p));
514 
515 	case LINUX_TCSETSW:
516 		error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
517 		if (error)
518 			return (error);
519 		linux_to_bsd_termios(&lios, &bios);
520 		return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p));
521 
522 	case LINUX_TCSETSF:
523 		error = copyin((caddr_t)args->arg, &lios, sizeof(lios));
524 		if (error)
525 			return (error);
526 		linux_to_bsd_termios(&lios, &bios);
527 		return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p));
528 
529 	case LINUX_TCGETA:
530 		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
531 		if (error)
532 			return (error);
533 		bsd_to_linux_termio(&bios, &lio);
534 		return (copyout(&lio, (caddr_t)args->arg, sizeof(lio)));
535 
536 	case LINUX_TCSETA:
537 		error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
538 		if (error)
539 			return (error);
540 		linux_to_bsd_termio(&lio, &bios);
541 		return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p));
542 
543 	case LINUX_TCSETAW:
544 		error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
545 		if (error)
546 			return (error);
547 		linux_to_bsd_termio(&lio, &bios);
548 		return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p));
549 
550 	case LINUX_TCSETAF:
551 		error = copyin((caddr_t)args->arg, &lio, sizeof(lio));
552 		if (error)
553 			return (error);
554 		linux_to_bsd_termio(&lio, &bios);
555 		return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p));
556 
557 	/* LINUX_TCSBRK */
558 
559 	case LINUX_TCXONC: {
560 		switch (args->arg) {
561 		case LINUX_TCOOFF:
562 			args->cmd = TIOCSTOP;
563 			break;
564 		case LINUX_TCOON:
565 			args->cmd = TIOCSTART;
566 			break;
567 		case LINUX_TCIOFF:
568 		case LINUX_TCION: {
569 			int c;
570 			struct write_args wr;
571 			error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p);
572 			if (error)
573 				return (error);
574 			c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
575 			c = bios.c_cc[c];
576 			if (c != _POSIX_VDISABLE) {
577 				wr.fd = args->fd;
578 				wr.buf = &c;
579 				wr.nbyte = sizeof(c);
580 				return (write(p, &wr));
581 			} else
582 				return (0);
583 		}
584 		default:
585 			return (EINVAL);
586 		}
587 		args->arg = 0;
588 		return (ioctl(p, (struct ioctl_args *)args));
589 	}
590 
591 	case LINUX_TCFLSH: {
592 		args->cmd = TIOCFLUSH;
593 		switch (args->arg) {
594 		case LINUX_TCIFLUSH:
595 			args->arg = FREAD;
596 			break;
597 		case LINUX_TCOFLUSH:
598 			args->arg = FWRITE;
599 			break;
600 		case LINUX_TCIOFLUSH:
601 			args->arg = FREAD | FWRITE;
602 			break;
603 		default:
604 			return (EINVAL);
605 		}
606 		return (ioctl(p, (struct ioctl_args *)args));
607 	}
608 
609 	case LINUX_TIOCEXCL:
610 		args->cmd = TIOCEXCL;
611 		return (ioctl(p, (struct ioctl_args *)args));
612 
613 	case LINUX_TIOCNXCL:
614 		args->cmd = TIOCNXCL;
615 		return (ioctl(p, (struct ioctl_args *)args));
616 
617 	/* LINUX_TIOCSCTTY */
618 
619 	case LINUX_TIOCGPGRP:
620 		args->cmd = TIOCGPGRP;
621 		return (ioctl(p, (struct ioctl_args *)args));
622 
623 	case LINUX_TIOCSPGRP:
624 		args->cmd = TIOCSPGRP;
625 		return (ioctl(p, (struct ioctl_args *)args));
626 
627 	/* LINUX_TIOCOUTQ */
628 	/* LINUX_TIOCSTI */
629 
630 	case LINUX_TIOCGWINSZ:
631 		args->cmd = TIOCGWINSZ;
632 		return (ioctl(p, (struct ioctl_args *)args));
633 
634 	case LINUX_TIOCSWINSZ:
635 		args->cmd = TIOCSWINSZ;
636 		return (ioctl(p, (struct ioctl_args *)args));
637 
638 	case LINUX_TIOCMGET:
639 		args->cmd = TIOCMGET;
640 		return (ioctl(p, (struct ioctl_args *)args));
641 
642 	case LINUX_TIOCMBIS:
643 		args->cmd = TIOCMBIS;
644 		return (ioctl(p, (struct ioctl_args *)args));
645 
646 	case LINUX_TIOCMBIC:
647 		args->cmd = TIOCMBIC;
648 		return (ioctl(p, (struct ioctl_args *)args));
649 
650 	case LINUX_TIOCMSET:
651 		args->cmd = TIOCMSET;
652 		return (ioctl(p, (struct ioctl_args *)args));
653 
654 	/* TIOCGSOFTCAR */
655 	/* TIOCSSOFTCAR */
656 
657 	case LINUX_FIONREAD: /* LINUX_TIOCINQ */
658 		args->cmd = FIONREAD;
659 		return (ioctl(p, (struct ioctl_args *)args));
660 
661 	/* LINUX_TIOCLINUX */
662 
663 	case LINUX_TIOCCONS:
664 		args->cmd = TIOCCONS;
665 		return (ioctl(p, (struct ioctl_args *)args));
666 
667 	case LINUX_TIOCGSERIAL: {
668 		struct linux_serial_struct lss;
669 		lss.type = LINUX_PORT_16550A;
670 		lss.flags = 0;
671 		lss.close_delay = 0;
672 		return copyout(&lss, (caddr_t)args->arg, sizeof(lss));
673 	}
674 
675 	case LINUX_TIOCSSERIAL: {
676 		struct linux_serial_struct lss;
677 		error = copyin((caddr_t)args->arg, &lss, sizeof(lss));
678 		if (error)
679 			return (error);
680 		/* XXX - It really helps to have an implementation that
681 		 * does nothing. NOT!
682 		 */
683 		return (0);
684 	}
685 
686 	/* LINUX_TIOCPKT */
687 
688 	case LINUX_FIONBIO:
689 		args->cmd = FIONBIO;
690 		return (ioctl(p, (struct ioctl_args *)args));
691 
692 	case LINUX_TIOCNOTTY:
693 		args->cmd = TIOCNOTTY;
694 		return (ioctl(p, (struct ioctl_args *)args));
695 
696 	case LINUX_TIOCSETD: {
697 		int line;
698 		switch (args->arg) {
699 		case LINUX_N_TTY:
700 			line = TTYDISC;
701 			break;
702 		case LINUX_N_SLIP:
703 			line = SLIPDISC;
704 			break;
705 		case LINUX_N_PPP:
706 			line = PPPDISC;
707 			break;
708 		default:
709 			return (EINVAL);
710 		}
711 		return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, p));
712 	}
713 
714 	case LINUX_TIOCGETD: {
715 		int linux_line;
716 		int bsd_line = TTYDISC;
717 		error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, p);
718 		if (error)
719 			return (error);
720 		switch (bsd_line) {
721 		case TTYDISC:
722 			linux_line = LINUX_N_TTY;
723 			break;
724 		case SLIPDISC:
725 			linux_line = LINUX_N_SLIP;
726 			break;
727 		case PPPDISC:
728 			linux_line = LINUX_N_PPP;
729 			break;
730 		default:
731 			return (EINVAL);
732 		}
733 		return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int)));
734 	}
735 
736 	/* LINUX_TCSBRKP */
737 	/* LINUX_TIOCTTYGSTRUCT */
738 
739 	case LINUX_FIONCLEX:
740 		args->cmd = FIONCLEX;
741 		return (ioctl(p, (struct ioctl_args *)args));
742 
743 	case LINUX_FIOCLEX:
744 		args->cmd = FIOCLEX;
745 		return (ioctl(p, (struct ioctl_args *)args));
746 
747 	case LINUX_FIOASYNC:
748 		args->cmd = FIOASYNC;
749 		return (ioctl(p, (struct ioctl_args *)args));
750 
751 	/* LINUX_TIOCSERCONFIG */
752 	/* LINUX_TIOCSERGWILD */
753 	/* LINUX_TIOCSERSWILD */
754 	/* LINUX_TIOCGLCKTRMIOS */
755 	/* LINUX_TIOCSLCKTRMIOS */
756 
757 	}
758 
759 	return (ENOIOCTL);
760 }
761 
762 /*
763  * CDROM related ioctls
764  */
765 
766 struct linux_cdrom_msf
767 {
768 	u_char	cdmsf_min0;
769 	u_char	cdmsf_sec0;
770 	u_char	cdmsf_frame0;
771 	u_char	cdmsf_min1;
772 	u_char	cdmsf_sec1;
773 	u_char	cdmsf_frame1;
774 };
775 
776 struct linux_cdrom_tochdr
777 {
778 	u_char	cdth_trk0;
779 	u_char	cdth_trk1;
780 };
781 
782 union linux_cdrom_addr
783 {
784 	struct {
785 		u_char	minute;
786 		u_char	second;
787 		u_char	frame;
788 	} msf;
789 	int	lba;
790 };
791 
792 struct linux_cdrom_tocentry
793 {
794 	u_char	cdte_track;
795 	u_char	cdte_adr:4;
796 	u_char	cdte_ctrl:4;
797 	u_char	cdte_format;
798 	union linux_cdrom_addr cdte_addr;
799 	u_char	cdte_datamode;
800 };
801 
802 struct linux_cdrom_subchnl
803 {
804 	u_char	cdsc_format;
805 	u_char	cdsc_audiostatus;
806 	u_char	cdsc_adr:4;
807 	u_char	cdsc_ctrl:4;
808 	u_char	cdsc_trk;
809 	u_char	cdsc_ind;
810 	union linux_cdrom_addr cdsc_absaddr;
811 	union linux_cdrom_addr cdsc_reladdr;
812 };
813 
814 static void
815 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
816 {
817 	if (af == CD_LBA_FORMAT)
818 		lp->lba = bp->lba;
819 	else {
820 		lp->msf.minute = bp->msf.minute;
821 		lp->msf.second = bp->msf.second;
822 		lp->msf.frame = bp->msf.frame;
823 	}
824 }
825 
826 static void
827 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
828 {
829 	if (format == LINUX_CDROM_MSF) {
830 		addr->msf.frame = lba % 75;
831 		lba /= 75;
832 		lba += 2;
833 		addr->msf.second = lba % 60;
834 		addr->msf.minute = lba / 60;
835 	} else
836 		addr->lba = lba;
837 }
838 
839 static int
840 linux_ioctl_cdrom(struct proc *p, struct linux_ioctl_args *args)
841 {
842 	struct file *fp = p->p_fd->fd_ofiles[args->fd];
843 	int error;
844 
845 	switch (args->cmd & 0xffff) {
846 
847 	case LINUX_CDROMPAUSE:
848 		args->cmd = CDIOCPAUSE;
849 		return (ioctl(p, (struct ioctl_args *)args));
850 
851 	case LINUX_CDROMRESUME:
852 		args->cmd = CDIOCRESUME;
853 		return (ioctl(p, (struct ioctl_args *)args));
854 
855 	case LINUX_CDROMPLAYMSF:
856 		args->cmd = CDIOCPLAYMSF;
857 		return (ioctl(p, (struct ioctl_args *)args));
858 
859 	case LINUX_CDROMPLAYTRKIND:
860 		args->cmd = CDIOCPLAYTRACKS;
861 		return (ioctl(p, (struct ioctl_args *)args));
862 
863 	case LINUX_CDROMREADTOCHDR: {
864 		struct ioc_toc_header th;
865 		struct linux_cdrom_tochdr lth;
866 		error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, p);
867 		if (!error) {
868 			lth.cdth_trk0 = th.starting_track;
869 			lth.cdth_trk1 = th.ending_track;
870 			copyout(&lth, (caddr_t)args->arg, sizeof(lth));
871 		}
872 		return (error);
873 	}
874 
875 	case LINUX_CDROMREADTOCENTRY: {
876 		struct linux_cdrom_tocentry lte, *ltep =
877 		    (struct linux_cdrom_tocentry *)args->arg;
878 		struct ioc_read_toc_single_entry irtse;
879 		irtse.address_format = ltep->cdte_format;
880 		irtse.track = ltep->cdte_track;
881 		error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, p);
882 		if (!error) {
883 			lte = *ltep;
884 			lte.cdte_ctrl = irtse.entry.control;
885 			lte.cdte_adr = irtse.entry.addr_type;
886 			bsd_to_linux_msf_lba(irtse.address_format,
887 			    &irtse.entry.addr, &lte.cdte_addr);
888 			copyout(&lte, (caddr_t)args->arg, sizeof(lte));
889 		}
890 		return (error);
891 	}
892 
893 	case LINUX_CDROMSTOP:
894 		args->cmd = CDIOCSTOP;
895 		return (ioctl(p, (struct ioctl_args *)args));
896 
897 	case LINUX_CDROMSTART:
898 		args->cmd = CDIOCSTART;
899 		return (ioctl(p, (struct ioctl_args *)args));
900 
901 	case LINUX_CDROMEJECT:
902 		args->cmd = CDIOCEJECT;
903 		return (ioctl(p, (struct ioctl_args *)args));
904 
905 	/* LINUX_CDROMVOLCTRL */
906 
907 	case LINUX_CDROMSUBCHNL: {
908 		struct linux_cdrom_subchnl sc;
909 		struct ioc_read_subchannel bsdsc;
910 		struct cd_sub_channel_info *bsdinfo;
911 		caddr_t sg = stackgap_init();
912 		bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg,
913 		    sizeof(struct cd_sub_channel_info));
914 		bsdsc.address_format = CD_LBA_FORMAT;
915 		bsdsc.data_format = CD_CURRENT_POSITION;
916 		bsdsc.track = 0;
917 		bsdsc.data_len = sizeof(struct cd_sub_channel_info);
918 		bsdsc.data = bsdinfo;
919 		error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, p);
920 		if (error)
921 			return (error);
922 		error = copyin((caddr_t)args->arg, &sc,
923 		    sizeof(struct linux_cdrom_subchnl));
924 		if (error)
925 			return (error);
926 		sc.cdsc_audiostatus = bsdinfo->header.audio_status;
927 		sc.cdsc_adr = bsdinfo->what.position.addr_type;
928 		sc.cdsc_ctrl = bsdinfo->what.position.control;
929 		sc.cdsc_trk = bsdinfo->what.position.track_number;
930 		sc.cdsc_ind = bsdinfo->what.position.index_number;
931 		set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
932 		    bsdinfo->what.position.absaddr.lba);
933 		set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
934 		    bsdinfo->what.position.reladdr.lba);
935 		error = copyout(&sc, (caddr_t)args->arg,
936 		    sizeof(struct linux_cdrom_subchnl));
937 		return (error);
938 	}
939 
940 	/* LINUX_CDROMREADMODE2 */
941 	/* LINUX_CDROMREADMODE1 */
942 	/* LINUX_CDROMREADAUDIO */
943 	/* LINUX_CDROMEJECT_SW */
944 	/* LINUX_CDROMMULTISESSION */
945 	/* LINUX_CDROM_GET_UPC */
946 
947 	case LINUX_CDROMRESET:
948 		args->cmd = CDIOCRESET;
949 		return (ioctl(p, (struct ioctl_args *)args));
950 
951 	/* LINUX_CDROMVOLREAD */
952 	/* LINUX_CDROMREADRAW */
953 	/* LINUX_CDROMREADCOOKED */
954 	/* LINUX_CDROMSEEK */
955 	/* LINUX_CDROMPLAYBLK */
956 	/* LINUX_CDROMREADALL */
957 	/* LINUX_CDROMCLOSETRAY */
958 	/* LINUX_CDROMLOADFROMSLOT */
959 
960 	}
961 
962 	return (ENOIOCTL);
963 }
964 
965 /*
966  * Sound related ioctls
967  */
968 
969 static unsigned dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
970 
971 #define	SETDIR(c)	(((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
972 
973 static int
974 linux_ioctl_sound(struct proc *p, struct linux_ioctl_args *args)
975 {
976 
977 	switch (args->cmd & 0xffff) {
978 
979 	case LINUX_SOUND_MIXER_WRITE_VOLUME:
980 		args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
981 		return (ioctl(p, (struct ioctl_args *)args));
982 
983 	case LINUX_SOUND_MIXER_WRITE_BASS:
984 		args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
985 		return (ioctl(p, (struct ioctl_args *)args));
986 
987 	case LINUX_SOUND_MIXER_WRITE_TREBLE:
988 		args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
989 		return (ioctl(p, (struct ioctl_args *)args));
990 
991 	case LINUX_SOUND_MIXER_WRITE_SYNTH:
992 		args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
993 		return (ioctl(p, (struct ioctl_args *)args));
994 
995 	case LINUX_SOUND_MIXER_WRITE_PCM:
996 		args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
997 		return (ioctl(p, (struct ioctl_args *)args));
998 
999 	case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1000 		args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1001 		return (ioctl(p, (struct ioctl_args *)args));
1002 
1003 	case LINUX_SOUND_MIXER_WRITE_LINE:
1004 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1005 		return (ioctl(p, (struct ioctl_args *)args));
1006 
1007 	case LINUX_SOUND_MIXER_WRITE_MIC:
1008 		args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1009 		return (ioctl(p, (struct ioctl_args *)args));
1010 
1011 	case LINUX_SOUND_MIXER_WRITE_CD:
1012 		args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1013 		return (ioctl(p, (struct ioctl_args *)args));
1014 
1015 	case LINUX_SOUND_MIXER_WRITE_IMIX:
1016 		args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1017 		return (ioctl(p, (struct ioctl_args *)args));
1018 
1019 	case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1020 		args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1021 		return (ioctl(p, (struct ioctl_args *)args));
1022 
1023 	case LINUX_SOUND_MIXER_WRITE_RECLEV:
1024 		args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1025 		return (ioctl(p, (struct ioctl_args *)args));
1026 
1027 	case LINUX_SOUND_MIXER_WRITE_IGAIN:
1028 		args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1029 		return (ioctl(p, (struct ioctl_args *)args));
1030 
1031 	case LINUX_SOUND_MIXER_WRITE_OGAIN:
1032 		args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1033 		return (ioctl(p, (struct ioctl_args *)args));
1034 
1035 	case LINUX_SOUND_MIXER_WRITE_LINE1:
1036 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1037 		return (ioctl(p, (struct ioctl_args *)args));
1038 
1039 	case LINUX_SOUND_MIXER_WRITE_LINE2:
1040 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1041 		return (ioctl(p, (struct ioctl_args *)args));
1042 
1043 	case LINUX_SOUND_MIXER_WRITE_LINE3:
1044 		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1045 		return (ioctl(p, (struct ioctl_args *)args));
1046 
1047 	case LINUX_OSS_GETVERSION: {
1048 		int version = linux_get_oss_version(p);
1049 		return (copyout(&version, (caddr_t)args->arg, sizeof(int)));
1050 	}
1051 
1052 	case LINUX_SOUND_MIXER_READ_DEVMASK:
1053 		args->cmd = SOUND_MIXER_READ_DEVMASK;
1054 		return (ioctl(p, (struct ioctl_args *)args));
1055 
1056 	case LINUX_SNDCTL_DSP_RESET:
1057 		args->cmd = SNDCTL_DSP_RESET;
1058 		return (ioctl(p, (struct ioctl_args *)args));
1059 
1060 	case LINUX_SNDCTL_DSP_SYNC:
1061 		args->cmd = SNDCTL_DSP_SYNC;
1062 		return (ioctl(p, (struct ioctl_args *)args));
1063 
1064 	case LINUX_SNDCTL_DSP_SPEED:
1065 		args->cmd = SNDCTL_DSP_SPEED;
1066 		return (ioctl(p, (struct ioctl_args *)args));
1067 
1068 	case LINUX_SNDCTL_DSP_STEREO:
1069 		args->cmd = SNDCTL_DSP_STEREO;
1070 		return (ioctl(p, (struct ioctl_args *)args));
1071 
1072 	case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1073 		args->cmd = SNDCTL_DSP_GETBLKSIZE;
1074 		return (ioctl(p, (struct ioctl_args *)args));
1075 
1076 	case LINUX_SNDCTL_DSP_SETFMT:
1077 		args->cmd = SNDCTL_DSP_SETFMT;
1078 		return (ioctl(p, (struct ioctl_args *)args));
1079 
1080 	case LINUX_SOUND_PCM_WRITE_CHANNELS:
1081 		args->cmd = SOUND_PCM_WRITE_CHANNELS;
1082 		return (ioctl(p, (struct ioctl_args *)args));
1083 
1084 	case LINUX_SOUND_PCM_WRITE_FILTER:
1085 		args->cmd = SOUND_PCM_WRITE_FILTER;
1086 		return (ioctl(p, (struct ioctl_args *)args));
1087 
1088 	case LINUX_SNDCTL_DSP_POST:
1089 		args->cmd = SNDCTL_DSP_POST;
1090 		return (ioctl(p, (struct ioctl_args *)args));
1091 
1092 	case LINUX_SNDCTL_DSP_SUBDIVIDE:
1093 		args->cmd = SNDCTL_DSP_SUBDIVIDE;
1094 		return (ioctl(p, (struct ioctl_args *)args));
1095 
1096 	case LINUX_SNDCTL_DSP_SETFRAGMENT:
1097 		args->cmd = SNDCTL_DSP_SETFRAGMENT;
1098 		return (ioctl(p, (struct ioctl_args *)args));
1099 
1100 	case LINUX_SNDCTL_DSP_GETFMTS:
1101 		args->cmd = SNDCTL_DSP_GETFMTS;
1102 		return (ioctl(p, (struct ioctl_args *)args));
1103 
1104 	case LINUX_SNDCTL_DSP_GETOSPACE:
1105 		args->cmd = SNDCTL_DSP_GETOSPACE;
1106 		return (ioctl(p, (struct ioctl_args *)args));
1107 
1108 	case LINUX_SNDCTL_DSP_GETISPACE:
1109 		args->cmd = SNDCTL_DSP_GETISPACE;
1110 		return (ioctl(p, (struct ioctl_args *)args));
1111 
1112 	case LINUX_SNDCTL_DSP_NONBLOCK:
1113 		args->cmd = SNDCTL_DSP_NONBLOCK;
1114 		return (ioctl(p, (struct ioctl_args *)args));
1115 
1116 	case LINUX_SNDCTL_DSP_GETCAPS:
1117 		args->cmd = SNDCTL_DSP_GETCAPS;
1118 		return (ioctl(p, (struct ioctl_args *)args));
1119 
1120 	case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1121 		args->cmd = SNDCTL_DSP_SETTRIGGER;
1122 		return (ioctl(p, (struct ioctl_args *)args));
1123 
1124 	case LINUX_SNDCTL_DSP_GETIPTR:
1125 		args->cmd = SNDCTL_DSP_GETIPTR;
1126 		return (ioctl(p, (struct ioctl_args *)args));
1127 
1128 	case LINUX_SNDCTL_DSP_GETOPTR:
1129 		args->cmd = SNDCTL_DSP_GETOPTR;
1130 		return (ioctl(p, (struct ioctl_args *)args));
1131 
1132 	case LINUX_SNDCTL_DSP_GETODELAY:
1133 		args->cmd = SNDCTL_DSP_GETODELAY;
1134 		return (ioctl(p, (struct ioctl_args *)args));
1135 
1136 	case LINUX_SNDCTL_SEQ_RESET:
1137 		args->cmd = SNDCTL_SEQ_RESET;
1138 		return (ioctl(p, (struct ioctl_args *)args));
1139 
1140 	case LINUX_SNDCTL_SEQ_SYNC:
1141 		args->cmd = SNDCTL_SEQ_SYNC;
1142 		return (ioctl(p, (struct ioctl_args *)args));
1143 
1144 	case LINUX_SNDCTL_SYNTH_INFO:
1145 		args->cmd = SNDCTL_SYNTH_INFO;
1146 		return (ioctl(p, (struct ioctl_args *)args));
1147 
1148 	case LINUX_SNDCTL_SEQ_CTRLRATE:
1149 		args->cmd = SNDCTL_SEQ_CTRLRATE;
1150 		return (ioctl(p, (struct ioctl_args *)args));
1151 
1152 	case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1153 		args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1154 		return (ioctl(p, (struct ioctl_args *)args));
1155 
1156 	case LINUX_SNDCTL_SEQ_GETINCOUNT:
1157 		args->cmd = SNDCTL_SEQ_GETINCOUNT;
1158 		return (ioctl(p, (struct ioctl_args *)args));
1159 
1160 	case LINUX_SNDCTL_SEQ_PERCMODE:
1161 		args->cmd = SNDCTL_SEQ_PERCMODE;
1162 		return (ioctl(p, (struct ioctl_args *)args));
1163 
1164 	case LINUX_SNDCTL_FM_LOAD_INSTR:
1165 		args->cmd = SNDCTL_FM_LOAD_INSTR;
1166 		return (ioctl(p, (struct ioctl_args *)args));
1167 
1168 	case LINUX_SNDCTL_SEQ_TESTMIDI:
1169 		args->cmd = SNDCTL_SEQ_TESTMIDI;
1170 		return (ioctl(p, (struct ioctl_args *)args));
1171 
1172 	case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1173 		args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1174 		return (ioctl(p, (struct ioctl_args *)args));
1175 
1176 	case LINUX_SNDCTL_SEQ_NRSYNTHS:
1177 		args->cmd = SNDCTL_SEQ_NRSYNTHS;
1178 		return (ioctl(p, (struct ioctl_args *)args));
1179 
1180 	case LINUX_SNDCTL_SEQ_NRMIDIS:
1181 		args->cmd = SNDCTL_SEQ_NRMIDIS;
1182 		return (ioctl(p, (struct ioctl_args *)args));
1183 
1184 	case LINUX_SNDCTL_MIDI_INFO:
1185 		args->cmd = SNDCTL_MIDI_INFO;
1186 		return (ioctl(p, (struct ioctl_args *)args));
1187 
1188 	case LINUX_SNDCTL_SEQ_TRESHOLD:
1189 		args->cmd = SNDCTL_SEQ_TRESHOLD;
1190 		return (ioctl(p, (struct ioctl_args *)args));
1191 
1192 	case LINUX_SNDCTL_SYNTH_MEMAVL:
1193 		args->cmd = SNDCTL_SYNTH_MEMAVL;
1194 		return (ioctl(p, (struct ioctl_args *)args));
1195 
1196 	}
1197 
1198 	return (ENOIOCTL);
1199 }
1200 
1201 /*
1202  * Console related ioctls
1203  */
1204 
1205 #define ISSIGVALID(sig)		((sig) > 0 && (sig) < NSIG)
1206 
1207 static int
1208 linux_ioctl_console(struct proc *p, struct linux_ioctl_args *args)
1209 {
1210 	struct file *fp = p->p_fd->fd_ofiles[args->fd];
1211 
1212 	switch (args->cmd & 0xffff) {
1213 
1214 	case LINUX_KIOCSOUND:
1215 		args->cmd = KIOCSOUND;
1216 		return (ioctl(p, (struct ioctl_args *)args));
1217 
1218 	case LINUX_KDMKTONE:
1219 		args->cmd = KDMKTONE;
1220 		return (ioctl(p, (struct ioctl_args *)args));
1221 
1222 	case LINUX_KDGETLED:
1223 		args->cmd = KDGETLED;
1224 		return (ioctl(p, (struct ioctl_args *)args));
1225 
1226 	case LINUX_KDSETLED:
1227 		args->cmd = KDSETLED;
1228 		return (ioctl(p, (struct ioctl_args *)args));
1229 
1230 	case LINUX_KDSETMODE:
1231 		args->cmd = KDSETMODE;
1232 		return (ioctl(p, (struct ioctl_args *)args));
1233 
1234 	case LINUX_KDGETMODE:
1235 		args->cmd = KDGETMODE;
1236 		return (ioctl(p, (struct ioctl_args *)args));
1237 
1238 	case LINUX_KDGKBMODE:
1239 		args->cmd = KDGKBMODE;
1240 		return (ioctl(p, (struct ioctl_args *)args));
1241 
1242 	case LINUX_KDSKBMODE: {
1243 		int kbdmode;
1244 		switch (args->arg) {
1245 		case LINUX_KBD_RAW:
1246 			kbdmode = K_RAW;
1247 			break;
1248 		case LINUX_KBD_XLATE:
1249 			kbdmode = K_XLATE;
1250 			break;
1251 		case LINUX_KBD_MEDIUMRAW:
1252 			kbdmode = K_RAW;
1253 			break;
1254 		default:
1255 			return (EINVAL);
1256 		}
1257 		return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, p));
1258 	}
1259 
1260 	case LINUX_VT_OPENQRY:
1261 		args->cmd = VT_OPENQRY;
1262 		return (ioctl(p, (struct ioctl_args *)args));
1263 
1264 	case LINUX_VT_GETMODE:
1265 		args->cmd = VT_GETMODE;
1266 		return  (ioctl(p, (struct ioctl_args *)args));
1267 
1268 	case LINUX_VT_SETMODE: {
1269 		struct vt_mode *mode;
1270 		args->cmd = VT_SETMODE;
1271 		mode = (struct vt_mode *)args->arg;
1272 		if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig))
1273 			mode->frsig = mode->acqsig;
1274 		return (ioctl(p, (struct ioctl_args *)args));
1275 	}
1276 
1277 	case LINUX_VT_GETSTATE:
1278 		args->cmd = VT_GETACTIVE;
1279 		return (ioctl(p, (struct ioctl_args *)args));
1280 
1281 	case LINUX_VT_RELDISP:
1282 		args->cmd = VT_RELDISP;
1283 		return (ioctl(p, (struct ioctl_args *)args));
1284 
1285 	case LINUX_VT_ACTIVATE:
1286 		args->cmd = VT_ACTIVATE;
1287 		return (ioctl(p, (struct ioctl_args *)args));
1288 
1289 	case LINUX_VT_WAITACTIVE:
1290 		args->cmd = VT_WAITACTIVE;
1291 		return (ioctl(p, (struct ioctl_args *)args));
1292 
1293 	}
1294 
1295 	return (ENOIOCTL);
1296 }
1297 
1298 /*
1299  * Socket related ioctls
1300  */
1301 
1302 static int
1303 linux_ioctl_socket(struct proc *p, struct linux_ioctl_args *args)
1304 {
1305 
1306 	switch (args->cmd & 0xffff) {
1307 
1308 	case LINUX_FIOSETOWN:
1309 		args->cmd = FIOSETOWN;
1310 		return (ioctl(p, (struct ioctl_args *)args));
1311 
1312 	case LINUX_SIOCSPGRP:
1313 		args->cmd = SIOCSPGRP;
1314 		return (ioctl(p, (struct ioctl_args *)args));
1315 
1316 	case LINUX_FIOGETOWN:
1317 		args->cmd = FIOGETOWN;
1318 		return (ioctl(p, (struct ioctl_args *)args));
1319 
1320 	case LINUX_SIOCGPGRP:
1321 		args->cmd = SIOCGPGRP;
1322 		return (ioctl(p, (struct ioctl_args *)args));
1323 
1324 	case LINUX_SIOCATMARK:
1325 		args->cmd = SIOCATMARK;
1326 		return (ioctl(p, (struct ioctl_args *)args));
1327 
1328 	/* LINUX_SIOCGSTAMP */
1329 
1330 	case LINUX_SIOCGIFCONF:
1331 		args->cmd = OSIOCGIFCONF;
1332 		return (ioctl(p, (struct ioctl_args *)args));
1333 
1334 	case LINUX_SIOCGIFFLAGS:
1335 		args->cmd = SIOCGIFFLAGS;
1336 		return (ioctl(p, (struct ioctl_args *)args));
1337 
1338 	case LINUX_SIOCGIFADDR:
1339 		args->cmd = OSIOCGIFADDR;
1340 		return (ioctl(p, (struct ioctl_args *)args));
1341 
1342 	case LINUX_SIOCGIFDSTADDR:
1343 		args->cmd = OSIOCGIFDSTADDR;
1344 		return (ioctl(p, (struct ioctl_args *)args));
1345 
1346 	case LINUX_SIOCGIFBRDADDR:
1347 		args->cmd = OSIOCGIFBRDADDR;
1348 		return (ioctl(p, (struct ioctl_args *)args));
1349 
1350 	case LINUX_SIOCGIFNETMASK:
1351 		args->cmd = OSIOCGIFNETMASK;
1352 		return (ioctl(p, (struct ioctl_args *)args));
1353 
1354 	case LINUX_SIOCGIFHWADDR: {
1355 		int ifn;
1356 		struct ifnet *ifp;
1357 		struct ifaddr *ifa;
1358 		struct sockaddr_dl *sdl;
1359 		struct linux_ifreq *ifr = (struct linux_ifreq *)args->arg;
1360 
1361 		/* Note that we don't actually respect the name in the ifreq
1362 		 * structure, as Linux interface names are all different.
1363 		 */
1364 		for (ifn = 0; ifn < if_index; ifn++) {
1365 			ifp = ifnet_addrs[ifn]->ifa_ifp;
1366 			if (ifp->if_type == IFT_ETHER) {
1367 				ifa = TAILQ_FIRST(&ifp->if_addrhead);
1368 				while (ifa) {
1369 					sdl=(struct sockaddr_dl*)ifa->ifa_addr;
1370 					if (sdl != NULL &&
1371 					    (sdl->sdl_family == AF_LINK) &&
1372 					    (sdl->sdl_type == IFT_ETHER)) {
1373 						return (copyout(LLADDR(sdl),
1374 						    &ifr->ifr_hwaddr.sa_data,
1375 						    LINUX_IFHWADDRLEN));
1376 					}
1377 					ifa = TAILQ_NEXT(ifa, ifa_link);
1378 				}
1379 			}
1380 		}
1381 		return (ENOENT);
1382 	}
1383 
1384 	case LINUX_SIOCADDMULTI:
1385 		args->cmd = SIOCADDMULTI;
1386 		return (ioctl(p, (struct ioctl_args *)args));
1387 
1388 	case LINUX_SIOCDELMULTI:
1389 		args->cmd = SIOCDELMULTI;
1390 		return (ioctl(p, (struct ioctl_args *)args));
1391 
1392 	}
1393 
1394 	return (ENOIOCTL);
1395 }
1396 
1397 /*
1398  * main ioctl syscall function
1399  */
1400 
1401 int
1402 linux_ioctl(struct proc *p, struct linux_ioctl_args *args)
1403 {
1404 	struct filedesc *fdp = p->p_fd;
1405 	struct file *fp;
1406 	struct handler_element *he;
1407 	int error, cmd;
1408 
1409 #ifdef DEBUG
1410 	printf("Linux-emul(%ld): ioctl(%d, %04lx, *)\n", (long)p->p_pid,
1411 	    args->fd, args->cmd);
1412 #endif
1413 
1414 	if ((unsigned)args->fd >= fdp->fd_nfiles)
1415 		return (EBADF);
1416 
1417 	fp = fdp->fd_ofiles[args->fd];
1418 	if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0)
1419 		return (EBADF);
1420 
1421 	/* Iterate over the ioctl handlers */
1422 	cmd = args->cmd & 0xffff;
1423 	TAILQ_FOREACH(he, &handlers, list) {
1424 		if (cmd >= he->low && cmd <= he->high) {
1425 			error = (*he->func)(p, args);
1426 			if (error != ENOIOCTL)
1427 				return (error);
1428 		}
1429 	}
1430 
1431 	printf("linux: 'ioctl' fd=%d, cmd=%x ('%c',%d) not implemented\n",
1432 	    args->fd, (int)(args->cmd & 0xffff),
1433 	    (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
1434 
1435 	return (EINVAL);
1436 }
1437 
1438 int
1439 linux_ioctl_register_handler(struct linux_ioctl_handler *h)
1440 {
1441 	struct handler_element *he, *cur;
1442 
1443 	if (h == NULL || h->func == NULL)
1444 		return (EINVAL);
1445 
1446 	/*
1447 	 * Reuse the element if the handler is already on the list, otherwise
1448 	 * create a new element.
1449 	 */
1450 	TAILQ_FOREACH(he, &handlers, list) {
1451 		if (he->func == h->func)
1452 			break;
1453 	}
1454 	if (he == NULL) {
1455 		MALLOC(he, struct handler_element *, sizeof(*he),
1456 		    M_LINUX, M_WAITOK);
1457 		he->func = h->func;
1458 	} else
1459 		TAILQ_REMOVE(&handlers, he, list);
1460 
1461 	/* Initialize range information. */
1462 	he->low = h->low;
1463 	he->high = h->high;
1464 	he->span = h->high - h->low + 1;
1465 
1466 	/* Add the element to the list, sorted on span. */
1467 	TAILQ_FOREACH(cur, &handlers, list) {
1468 		if (cur->span > he->span) {
1469 			TAILQ_INSERT_BEFORE(cur, he, list);
1470 			return (0);
1471 		}
1472 	}
1473 	TAILQ_INSERT_TAIL(&handlers, he, list);
1474 
1475 	return (0);
1476 }
1477 
1478 int
1479 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
1480 {
1481 	struct handler_element *he;
1482 
1483 	if (h == NULL || h->func == NULL)
1484 		return (EINVAL);
1485 
1486 	TAILQ_FOREACH(he, &handlers, list) {
1487 		if (he->func == h->func) {
1488 			TAILQ_REMOVE(&handlers, he, list);
1489 			FREE(he, M_LINUX);
1490 			return (0);
1491 		}
1492 	}
1493 
1494 	return (EINVAL);
1495 }
1496 
1497 int
1498 linux_ioctl_register_handlers(struct linker_set *s)
1499 {
1500 	int error, i;
1501 
1502 	if (s == NULL)
1503 		return (EINVAL);
1504 
1505 	for (i = 0; i < s->ls_length; i++) {
1506 		error = linux_ioctl_register_handler(s->ls_items[i]);
1507 		if (error)
1508 			return (error);
1509 	}
1510 
1511 	return (0);
1512 }
1513 
1514 int
1515 linux_ioctl_unregister_handlers(struct linker_set *s)
1516 {
1517 	int error, i;
1518 
1519 	if (s == NULL)
1520 		return (EINVAL);
1521 
1522 	for (i = 0; i < s->ls_length; i++) {
1523 		error = linux_ioctl_unregister_handler(s->ls_items[i]);
1524 		if (error)
1525 			return (error);
1526 	}
1527 
1528 	return (0);
1529 }
1530