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