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