1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1994-1995 S��ren Schmidt
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/capsicum.h>
31#include <sys/cdio.h>
32#include <sys/consio.h>
33#include <sys/disk.h>
34#include <sys/dvdio.h>
35#include <sys/fcntl.h>
36#include <sys/filio.h>
37#include <sys/jail.h>
38#include <sys/kbio.h>
39#include <sys/kcov.h>
40#include <sys/kernel.h>
41#include <sys/linker_set.h>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mman.h>
45#include <sys/proc.h>
46#include <sys/sbuf.h>
47#include <sys/sockio.h>
48#include <sys/soundcard.h>
49#include <sys/syscallsubr.h>
50#include <sys/sysctl.h>
51#include <sys/sysproto.h>
52#include <sys/sx.h>
53#include <sys/tty.h>
54
55#include <net/if.h>
56#include <net/if_var.h>
57#include <net/if_dl.h>
58#include <net/if_types.h>
59
60#include <dev/evdev/input.h>
61#include <dev/usb/usb_ioctl.h>
62
63#ifdef COMPAT_LINUX32
64#include <machine/../linux32/linux.h>
65#include <machine/../linux32/linux32_proto.h>
66#else
67#include <machine/../linux/linux.h>
68#include <machine/../linux/linux_proto.h>
69#endif
70
71#include <compat/linux/linux_common.h>
72#include <compat/linux/linux_ioctl.h>
73#include <compat/linux/linux_mib.h>
74#include <compat/linux/linux_socket.h>
75#include <compat/linux/linux_time.h>
76#include <compat/linux/linux_util.h>
77
78#include <contrib/v4l/videodev.h>
79#include <compat/linux/linux_videodev_compat.h>
80
81#include <contrib/v4l/videodev2.h>
82#include <compat/linux/linux_videodev2_compat.h>
83
84#include <cam/scsi/scsi_sg.h>
85
86#define	DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME)		\
87static linux_ioctl_function_t linux_ioctl_ ## shortname;	\
88static struct linux_ioctl_handler shortname ## _handler = {	\
89	.func = linux_ioctl_ ## shortname,			\
90	.low = LINUX_IOCTL_ ## SHORTNAME ## _MIN,		\
91	.high = LINUX_IOCTL_ ## SHORTNAME ## _MAX,		\
92};								\
93DATA_SET(linux_ioctl_handler_set, shortname ## _handler)
94
95DEFINE_LINUX_IOCTL_SET(cdrom, CDROM);
96DEFINE_LINUX_IOCTL_SET(vfat, VFAT);
97DEFINE_LINUX_IOCTL_SET(console, CONSOLE);
98DEFINE_LINUX_IOCTL_SET(hdio, HDIO);
99DEFINE_LINUX_IOCTL_SET(disk, DISK);
100DEFINE_LINUX_IOCTL_SET(socket, SOCKET);
101DEFINE_LINUX_IOCTL_SET(sound, SOUND);
102DEFINE_LINUX_IOCTL_SET(termio, TERMIO);
103DEFINE_LINUX_IOCTL_SET(private, PRIVATE);
104DEFINE_LINUX_IOCTL_SET(drm, DRM);
105DEFINE_LINUX_IOCTL_SET(sg, SG);
106DEFINE_LINUX_IOCTL_SET(v4l, VIDEO);
107DEFINE_LINUX_IOCTL_SET(v4l2, VIDEO2);
108DEFINE_LINUX_IOCTL_SET(fbsd_usb, FBSD_LUSB);
109DEFINE_LINUX_IOCTL_SET(evdev, EVDEV);
110DEFINE_LINUX_IOCTL_SET(kcov, KCOV);
111
112#undef DEFINE_LINUX_IOCTL_SET
113
114static int linux_ioctl_special(struct thread *, struct linux_ioctl_args *);
115
116/*
117 * Keep sorted by low.
118 */
119static struct linux_ioctl_handler linux_ioctls[] = {
120	{ .func = linux_ioctl_termio, .low = LINUX_IOCTL_TERMIO_MIN,
121	    .high = LINUX_IOCTL_TERMIO_MAX },
122};
123
124#ifdef __i386__
125static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
126    TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
127static struct sx linux_ioctl_sx;
128SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
129#else
130extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers;
131extern struct sx linux_ioctl_sx;
132#endif
133#ifdef COMPAT_LINUX32
134static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers =
135    TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers);
136#endif
137
138/*
139 * hdio related ioctls for VMWare support
140 */
141
142struct linux_hd_geometry {
143	uint8_t		heads;
144	uint8_t		sectors;
145	uint16_t	cylinders;
146	uint32_t	start;
147};
148
149struct linux_hd_big_geometry {
150	uint8_t		heads;
151	uint8_t		sectors;
152	uint32_t	cylinders;
153	uint32_t	start;
154};
155
156static int
157linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
158{
159	struct file *fp;
160	int error;
161	u_int sectorsize, fwcylinders, fwheads, fwsectors;
162	off_t mediasize, bytespercyl;
163
164	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
165	if (error != 0)
166		return (error);
167	switch (args->cmd & 0xffff) {
168	case LINUX_HDIO_GET_GEO:
169	case LINUX_HDIO_GET_GEO_BIG:
170		error = fo_ioctl(fp, DIOCGMEDIASIZE,
171			(caddr_t)&mediasize, td->td_ucred, td);
172		if (!error)
173			error = fo_ioctl(fp, DIOCGSECTORSIZE,
174				(caddr_t)&sectorsize, td->td_ucred, td);
175		if (!error)
176			error = fo_ioctl(fp, DIOCGFWHEADS,
177				(caddr_t)&fwheads, td->td_ucred, td);
178		if (!error)
179			error = fo_ioctl(fp, DIOCGFWSECTORS,
180				(caddr_t)&fwsectors, td->td_ucred, td);
181		/*
182		 * XXX: DIOCGFIRSTOFFSET is not yet implemented, so
183		 * so pretend that GEOM always says 0. This is NOT VALID
184		 * for slices or partitions, only the per-disk raw devices.
185		 */
186
187		fdrop(fp, td);
188		if (error)
189			return (error);
190		/*
191		 * 1. Calculate the number of bytes in a cylinder,
192		 *    given the firmware's notion of heads and sectors
193		 *    per cylinder.
194		 * 2. Calculate the number of cylinders, given the total
195		 *    size of the media.
196		 * All internal calculations should have 64-bit precision.
197		 */
198		bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
199		fwcylinders = mediasize / bytespercyl;
200
201		if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
202			struct linux_hd_geometry hdg;
203
204			hdg.cylinders = fwcylinders;
205			hdg.heads = fwheads;
206			hdg.sectors = fwsectors;
207			hdg.start = 0;
208			error = copyout(&hdg, (void *)args->arg, sizeof(hdg));
209		} else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
210			struct linux_hd_big_geometry hdbg;
211
212			memset(&hdbg, 0, sizeof(hdbg));
213			hdbg.cylinders = fwcylinders;
214			hdbg.heads = fwheads;
215			hdbg.sectors = fwsectors;
216			hdbg.start = 0;
217			error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg));
218		}
219		return (error);
220		break;
221	default:
222		/* XXX */
223		linux_msg(td,
224			"%s fd=%d, cmd=0x%x ('%c',%d) is not implemented",
225			__func__, args->fd, args->cmd,
226			(int)(args->cmd & 0xff00) >> 8,
227			(int)(args->cmd & 0xff));
228		break;
229	}
230	fdrop(fp, td);
231	return (ENOIOCTL);
232}
233
234static int
235linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
236{
237	struct file *fp;
238	int error;
239	u_int sectorsize, psectorsize;
240	uint64_t blksize64;
241	off_t mediasize, stripesize;
242
243	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
244	if (error != 0)
245		return (error);
246	switch (args->cmd & 0xffff) {
247	case LINUX_BLKGETSIZE:
248		error = fo_ioctl(fp, DIOCGSECTORSIZE,
249		    (caddr_t)&sectorsize, td->td_ucred, td);
250		if (!error)
251			error = fo_ioctl(fp, DIOCGMEDIASIZE,
252			    (caddr_t)&mediasize, td->td_ucred, td);
253		fdrop(fp, td);
254		if (error)
255			return (error);
256		sectorsize = mediasize / sectorsize;
257		/*
258		 * XXX: How do we know we return the right size of integer ?
259		 */
260		return (copyout(&sectorsize, (void *)args->arg,
261		    sizeof(sectorsize)));
262		break;
263	case LINUX_BLKGETSIZE64:
264		error = fo_ioctl(fp, DIOCGMEDIASIZE,
265		    (caddr_t)&mediasize, td->td_ucred, td);
266		fdrop(fp, td);
267		if (error)
268			return (error);
269		blksize64 = mediasize;
270		return (copyout(&blksize64, (void *)args->arg,
271		    sizeof(blksize64)));
272	case LINUX_BLKSSZGET:
273		error = fo_ioctl(fp, DIOCGSECTORSIZE,
274		    (caddr_t)&sectorsize, td->td_ucred, td);
275		fdrop(fp, td);
276		if (error)
277			return (error);
278		return (copyout(&sectorsize, (void *)args->arg,
279		    sizeof(sectorsize)));
280		break;
281	case LINUX_BLKPBSZGET:
282		error = fo_ioctl(fp, DIOCGSTRIPESIZE,
283		    (caddr_t)&stripesize, td->td_ucred, td);
284		if (error != 0) {
285			fdrop(fp, td);
286			return (error);
287		}
288		if (stripesize > 0 && stripesize <= 4096) {
289			psectorsize = stripesize;
290		} else  {
291			error = fo_ioctl(fp, DIOCGSECTORSIZE,
292			    (caddr_t)&sectorsize, td->td_ucred, td);
293			if (error != 0) {
294				fdrop(fp, td);
295				return (error);
296			}
297			psectorsize = sectorsize;
298		}
299		fdrop(fp, td);
300		return (copyout(&psectorsize, (void *)args->arg,
301		    sizeof(psectorsize)));
302	}
303	fdrop(fp, td);
304	return (ENOIOCTL);
305}
306
307/*
308 * termio related ioctls
309 */
310
311struct linux_termio {
312	unsigned short c_iflag;
313	unsigned short c_oflag;
314	unsigned short c_cflag;
315	unsigned short c_lflag;
316	unsigned char c_line;
317	unsigned char c_cc[LINUX_NCC];
318};
319
320struct linux_termios {
321	unsigned int c_iflag;
322	unsigned int c_oflag;
323	unsigned int c_cflag;
324	unsigned int c_lflag;
325	unsigned char c_line;
326	unsigned char c_cc[LINUX_NCCS];
327};
328
329struct linux_winsize {
330	unsigned short ws_row, ws_col;
331	unsigned short ws_xpixel, ws_ypixel;
332};
333
334struct speedtab {
335	int sp_speed;			/* Speed. */
336	int sp_code;			/* Code. */
337};
338
339static struct speedtab sptab[] = {
340	{ B0, LINUX_B0 }, { B50, LINUX_B50 },
341	{ B75, LINUX_B75 }, { B110, LINUX_B110 },
342	{ B134, LINUX_B134 }, { B150, LINUX_B150 },
343	{ B200, LINUX_B200 }, { B300, LINUX_B300 },
344	{ B600, LINUX_B600 }, { B1200, LINUX_B1200 },
345	{ B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
346	{ B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
347	{ B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
348	{ B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
349	{-1, -1 }
350};
351
352struct linux_serial_struct {
353	int	type;
354	int	line;
355	int	port;
356	int	irq;
357	int	flags;
358	int	xmit_fifo_size;
359	int	custom_divisor;
360	int	baud_base;
361	unsigned short close_delay;
362	char	reserved_char[2];
363	int	hub6;
364	unsigned short closing_wait;
365	unsigned short closing_wait2;
366	int	reserved[4];
367};
368
369static int
370linux_to_bsd_speed(int code, struct speedtab *table)
371{
372	for ( ; table->sp_code != -1; table++)
373		if (table->sp_code == code)
374			return (table->sp_speed);
375	return (-1);
376}
377
378static int
379bsd_to_linux_speed(int speed, struct speedtab *table)
380{
381	for ( ; table->sp_speed != -1; table++)
382		if (table->sp_speed == speed)
383			return (table->sp_code);
384	return (-1);
385}
386
387static void
388bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
389{
390	int i;
391
392	lios->c_iflag = 0;
393	if (bios->c_iflag & IGNBRK)
394		lios->c_iflag |= LINUX_IGNBRK;
395	if (bios->c_iflag & BRKINT)
396		lios->c_iflag |= LINUX_BRKINT;
397	if (bios->c_iflag & IGNPAR)
398		lios->c_iflag |= LINUX_IGNPAR;
399	if (bios->c_iflag & PARMRK)
400		lios->c_iflag |= LINUX_PARMRK;
401	if (bios->c_iflag & INPCK)
402		lios->c_iflag |= LINUX_INPCK;
403	if (bios->c_iflag & ISTRIP)
404		lios->c_iflag |= LINUX_ISTRIP;
405	if (bios->c_iflag & INLCR)
406		lios->c_iflag |= LINUX_INLCR;
407	if (bios->c_iflag & IGNCR)
408		lios->c_iflag |= LINUX_IGNCR;
409	if (bios->c_iflag & ICRNL)
410		lios->c_iflag |= LINUX_ICRNL;
411	if (bios->c_iflag & IXON)
412		lios->c_iflag |= LINUX_IXON;
413	if (bios->c_iflag & IXANY)
414		lios->c_iflag |= LINUX_IXANY;
415	if (bios->c_iflag & IXOFF)
416		lios->c_iflag |= LINUX_IXOFF;
417	if (bios->c_iflag & IMAXBEL)
418		lios->c_iflag |= LINUX_IMAXBEL;
419
420	lios->c_oflag = 0;
421	if (bios->c_oflag & OPOST)
422		lios->c_oflag |= LINUX_OPOST;
423	if (bios->c_oflag & ONLCR)
424		lios->c_oflag |= LINUX_ONLCR;
425	if (bios->c_oflag & TAB3)
426		lios->c_oflag |= LINUX_XTABS;
427
428	lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
429	lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
430	if (bios->c_cflag & CSTOPB)
431		lios->c_cflag |= LINUX_CSTOPB;
432	if (bios->c_cflag & CREAD)
433		lios->c_cflag |= LINUX_CREAD;
434	if (bios->c_cflag & PARENB)
435		lios->c_cflag |= LINUX_PARENB;
436	if (bios->c_cflag & PARODD)
437		lios->c_cflag |= LINUX_PARODD;
438	if (bios->c_cflag & HUPCL)
439		lios->c_cflag |= LINUX_HUPCL;
440	if (bios->c_cflag & CLOCAL)
441		lios->c_cflag |= LINUX_CLOCAL;
442	if (bios->c_cflag & CRTSCTS)
443		lios->c_cflag |= LINUX_CRTSCTS;
444
445	lios->c_lflag = 0;
446	if (bios->c_lflag & ISIG)
447		lios->c_lflag |= LINUX_ISIG;
448	if (bios->c_lflag & ICANON)
449		lios->c_lflag |= LINUX_ICANON;
450	if (bios->c_lflag & ECHO)
451		lios->c_lflag |= LINUX_ECHO;
452	if (bios->c_lflag & ECHOE)
453		lios->c_lflag |= LINUX_ECHOE;
454	if (bios->c_lflag & ECHOK)
455		lios->c_lflag |= LINUX_ECHOK;
456	if (bios->c_lflag & ECHONL)
457		lios->c_lflag |= LINUX_ECHONL;
458	if (bios->c_lflag & NOFLSH)
459		lios->c_lflag |= LINUX_NOFLSH;
460	if (bios->c_lflag & TOSTOP)
461		lios->c_lflag |= LINUX_TOSTOP;
462	if (bios->c_lflag & ECHOCTL)
463		lios->c_lflag |= LINUX_ECHOCTL;
464	if (bios->c_lflag & ECHOPRT)
465		lios->c_lflag |= LINUX_ECHOPRT;
466	if (bios->c_lflag & ECHOKE)
467		lios->c_lflag |= LINUX_ECHOKE;
468	if (bios->c_lflag & FLUSHO)
469		lios->c_lflag |= LINUX_FLUSHO;
470	if (bios->c_lflag & PENDIN)
471		lios->c_lflag |= LINUX_PENDIN;
472	if (bios->c_lflag & IEXTEN)
473		lios->c_lflag |= LINUX_IEXTEN;
474
475	for (i=0; i<LINUX_NCCS; i++)
476		lios->c_cc[i] = LINUX_POSIX_VDISABLE;
477	lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
478	lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
479	lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
480	lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
481	lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
482	lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
483	lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
484	lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
485	lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
486	lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
487	lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
488	lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
489	lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
490	lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
491	lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
492	lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
493	if (linux_preserve_vstatus)
494		lios->c_cc[LINUX_VSTATUS] = bios->c_cc[VSTATUS];
495
496	for (i=0; i<LINUX_NCCS; i++) {
497		if (i != LINUX_VMIN && i != LINUX_VTIME &&
498		    lios->c_cc[i] == _POSIX_VDISABLE)
499			lios->c_cc[i] = LINUX_POSIX_VDISABLE;
500	}
501	lios->c_line = 0;
502}
503
504static void
505linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
506{
507	int i;
508
509	bios->c_iflag = 0;
510	if (lios->c_iflag & LINUX_IGNBRK)
511		bios->c_iflag |= IGNBRK;
512	if (lios->c_iflag & LINUX_BRKINT)
513		bios->c_iflag |= BRKINT;
514	if (lios->c_iflag & LINUX_IGNPAR)
515		bios->c_iflag |= IGNPAR;
516	if (lios->c_iflag & LINUX_PARMRK)
517		bios->c_iflag |= PARMRK;
518	if (lios->c_iflag & LINUX_INPCK)
519		bios->c_iflag |= INPCK;
520	if (lios->c_iflag & LINUX_ISTRIP)
521		bios->c_iflag |= ISTRIP;
522	if (lios->c_iflag & LINUX_INLCR)
523		bios->c_iflag |= INLCR;
524	if (lios->c_iflag & LINUX_IGNCR)
525		bios->c_iflag |= IGNCR;
526	if (lios->c_iflag & LINUX_ICRNL)
527		bios->c_iflag |= ICRNL;
528	if (lios->c_iflag & LINUX_IXON)
529		bios->c_iflag |= IXON;
530	if (lios->c_iflag & LINUX_IXANY)
531		bios->c_iflag |= IXANY;
532	if (lios->c_iflag & LINUX_IXOFF)
533		bios->c_iflag |= IXOFF;
534	if (lios->c_iflag & LINUX_IMAXBEL)
535		bios->c_iflag |= IMAXBEL;
536
537	bios->c_oflag = 0;
538	if (lios->c_oflag & LINUX_OPOST)
539		bios->c_oflag |= OPOST;
540	if (lios->c_oflag & LINUX_ONLCR)
541		bios->c_oflag |= ONLCR;
542	if (lios->c_oflag & LINUX_XTABS)
543		bios->c_oflag |= TAB3;
544
545	bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
546	if (lios->c_cflag & LINUX_CSTOPB)
547		bios->c_cflag |= CSTOPB;
548	if (lios->c_cflag & LINUX_CREAD)
549		bios->c_cflag |= CREAD;
550	if (lios->c_cflag & LINUX_PARENB)
551		bios->c_cflag |= PARENB;
552	if (lios->c_cflag & LINUX_PARODD)
553		bios->c_cflag |= PARODD;
554	if (lios->c_cflag & LINUX_HUPCL)
555		bios->c_cflag |= HUPCL;
556	if (lios->c_cflag & LINUX_CLOCAL)
557		bios->c_cflag |= CLOCAL;
558	if (lios->c_cflag & LINUX_CRTSCTS)
559		bios->c_cflag |= CRTSCTS;
560
561	bios->c_lflag = 0;
562	if (lios->c_lflag & LINUX_ISIG)
563		bios->c_lflag |= ISIG;
564	if (lios->c_lflag & LINUX_ICANON)
565		bios->c_lflag |= ICANON;
566	if (lios->c_lflag & LINUX_ECHO)
567		bios->c_lflag |= ECHO;
568	if (lios->c_lflag & LINUX_ECHOE)
569		bios->c_lflag |= ECHOE;
570	if (lios->c_lflag & LINUX_ECHOK)
571		bios->c_lflag |= ECHOK;
572	if (lios->c_lflag & LINUX_ECHONL)
573		bios->c_lflag |= ECHONL;
574	if (lios->c_lflag & LINUX_NOFLSH)
575		bios->c_lflag |= NOFLSH;
576	if (lios->c_lflag & LINUX_TOSTOP)
577		bios->c_lflag |= TOSTOP;
578	if (lios->c_lflag & LINUX_ECHOCTL)
579		bios->c_lflag |= ECHOCTL;
580	if (lios->c_lflag & LINUX_ECHOPRT)
581		bios->c_lflag |= ECHOPRT;
582	if (lios->c_lflag & LINUX_ECHOKE)
583		bios->c_lflag |= ECHOKE;
584	if (lios->c_lflag & LINUX_FLUSHO)
585		bios->c_lflag |= FLUSHO;
586	if (lios->c_lflag & LINUX_PENDIN)
587		bios->c_lflag |= PENDIN;
588	if (lios->c_lflag & LINUX_IEXTEN)
589		bios->c_lflag |= IEXTEN;
590
591	for (i=0; i<NCCS; i++)
592		bios->c_cc[i] = _POSIX_VDISABLE;
593	bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
594	bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
595	bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
596	bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
597	bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
598	bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
599	bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
600	bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
601	bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
602	bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
603	bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
604	bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
605	bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
606	bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
607	bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
608	bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
609	if (linux_preserve_vstatus)
610		bios->c_cc[VSTATUS] = lios->c_cc[LINUX_VSTATUS];
611
612	for (i=0; i<NCCS; i++) {
613		if (i != VMIN && i != VTIME &&
614		    bios->c_cc[i] == LINUX_POSIX_VDISABLE)
615			bios->c_cc[i] = _POSIX_VDISABLE;
616	}
617
618	bios->c_ispeed = bios->c_ospeed =
619	    linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
620}
621
622static void
623bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
624{
625	struct linux_termios lios;
626
627	memset(lio, 0, sizeof(*lio));
628	bsd_to_linux_termios(bios, &lios);
629	lio->c_iflag = lios.c_iflag;
630	lio->c_oflag = lios.c_oflag;
631	lio->c_cflag = lios.c_cflag;
632	lio->c_lflag = lios.c_lflag;
633	lio->c_line  = lios.c_line;
634	memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
635}
636
637static void
638linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
639{
640	struct linux_termios lios;
641	int i;
642
643	lios.c_iflag = lio->c_iflag;
644	lios.c_oflag = lio->c_oflag;
645	lios.c_cflag = lio->c_cflag;
646	lios.c_lflag = lio->c_lflag;
647	for (i=LINUX_NCC; i<LINUX_NCCS; i++)
648		lios.c_cc[i] = LINUX_POSIX_VDISABLE;
649	memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
650	linux_to_bsd_termios(&lios, bios);
651}
652
653static int
654linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
655{
656	struct termios bios;
657	struct linux_termios lios;
658	struct linux_termio lio;
659	struct file *fp;
660	int error;
661
662	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
663	if (error != 0)
664		return (error);
665
666	switch (args->cmd & 0xffff) {
667	case LINUX_TCGETS:
668		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
669		    td);
670		if (error)
671			break;
672		bsd_to_linux_termios(&bios, &lios);
673		error = copyout(&lios, (void *)args->arg, sizeof(lios));
674		break;
675
676	case LINUX_TCSETS:
677		error = copyin((void *)args->arg, &lios, sizeof(lios));
678		if (error)
679			break;
680		linux_to_bsd_termios(&lios, &bios);
681		error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
682		    td));
683		break;
684
685	case LINUX_TCSETSW:
686		error = copyin((void *)args->arg, &lios, sizeof(lios));
687		if (error)
688			break;
689		linux_to_bsd_termios(&lios, &bios);
690		error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
691		    td));
692		break;
693
694	case LINUX_TCSETSF:
695		error = copyin((void *)args->arg, &lios, sizeof(lios));
696		if (error)
697			break;
698		linux_to_bsd_termios(&lios, &bios);
699		error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
700		    td));
701		break;
702
703	case LINUX_TCGETA:
704		error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
705		    td);
706		if (error)
707			break;
708		bsd_to_linux_termio(&bios, &lio);
709		error = (copyout(&lio, (void *)args->arg, sizeof(lio)));
710		break;
711
712	case LINUX_TCSETA:
713		error = copyin((void *)args->arg, &lio, sizeof(lio));
714		if (error)
715			break;
716		linux_to_bsd_termio(&lio, &bios);
717		error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
718		    td));
719		break;
720
721	case LINUX_TCSETAW:
722		error = copyin((void *)args->arg, &lio, sizeof(lio));
723		if (error)
724			break;
725		linux_to_bsd_termio(&lio, &bios);
726		error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
727		    td));
728		break;
729
730	case LINUX_TCSETAF:
731		error = copyin((void *)args->arg, &lio, sizeof(lio));
732		if (error)
733			break;
734		linux_to_bsd_termio(&lio, &bios);
735		error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
736		    td));
737		break;
738
739	case LINUX_TCSBRK:
740		if (args->arg != 0) {
741			error = (fo_ioctl(fp, TIOCDRAIN, (caddr_t)&bios, td->td_ucred,
742			    td));
743		} else {
744			linux_msg(td, "ioctl TCSBRK arg 0 not implemented");
745			error = ENOIOCTL;
746		}
747		break;
748
749	case LINUX_TCXONC: {
750		switch (args->arg) {
751		case LINUX_TCOOFF:
752			args->cmd = TIOCSTOP;
753			break;
754		case LINUX_TCOON:
755			args->cmd = TIOCSTART;
756			break;
757		case LINUX_TCIOFF:
758		case LINUX_TCION: {
759			int c;
760			struct write_args wr;
761			error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios,
762			    td->td_ucred, td);
763			if (error)
764				break;
765			fdrop(fp, td);
766			c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
767			c = bios.c_cc[c];
768			if (c != _POSIX_VDISABLE) {
769				wr.fd = args->fd;
770				wr.buf = &c;
771				wr.nbyte = sizeof(c);
772				return (sys_write(td, &wr));
773			} else
774				return (0);
775		}
776		default:
777			fdrop(fp, td);
778			return (EINVAL);
779		}
780		args->arg = 0;
781		error = (sys_ioctl(td, (struct ioctl_args *)args));
782		break;
783	}
784
785	case LINUX_TCFLSH: {
786		int val;
787		switch (args->arg) {
788		case LINUX_TCIFLUSH:
789			val = FREAD;
790			break;
791		case LINUX_TCOFLUSH:
792			val = FWRITE;
793			break;
794		case LINUX_TCIOFLUSH:
795			val = FREAD | FWRITE;
796			break;
797		default:
798			fdrop(fp, td);
799			return (EINVAL);
800		}
801		error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td));
802		break;
803	}
804
805	case LINUX_TIOCEXCL:
806		args->cmd = TIOCEXCL;
807		error = (sys_ioctl(td, (struct ioctl_args *)args));
808		break;
809
810	case LINUX_TIOCNXCL:
811		args->cmd = TIOCNXCL;
812		error = (sys_ioctl(td, (struct ioctl_args *)args));
813		break;
814
815	case LINUX_TIOCSCTTY:
816		args->cmd = TIOCSCTTY;
817		error = (sys_ioctl(td, (struct ioctl_args *)args));
818		break;
819
820	case LINUX_TIOCGPGRP:
821		args->cmd = TIOCGPGRP;
822		error = (sys_ioctl(td, (struct ioctl_args *)args));
823		break;
824
825	case LINUX_TIOCSPGRP:
826		args->cmd = TIOCSPGRP;
827		error = (sys_ioctl(td, (struct ioctl_args *)args));
828		break;
829
830	/* LINUX_TIOCOUTQ */
831	/* LINUX_TIOCSTI */
832
833	case LINUX_TIOCGWINSZ:
834		args->cmd = TIOCGWINSZ;
835		error = (sys_ioctl(td, (struct ioctl_args *)args));
836		break;
837
838	case LINUX_TIOCSWINSZ:
839		args->cmd = TIOCSWINSZ;
840		error = (sys_ioctl(td, (struct ioctl_args *)args));
841		break;
842
843	case LINUX_TIOCMGET:
844		args->cmd = TIOCMGET;
845		error = (sys_ioctl(td, (struct ioctl_args *)args));
846		break;
847
848	case LINUX_TIOCMBIS:
849		args->cmd = TIOCMBIS;
850		error = (sys_ioctl(td, (struct ioctl_args *)args));
851		break;
852
853	case LINUX_TIOCMBIC:
854		args->cmd = TIOCMBIC;
855		error = (sys_ioctl(td, (struct ioctl_args *)args));
856		break;
857
858	case LINUX_TIOCMSET:
859		args->cmd = TIOCMSET;
860		error = (sys_ioctl(td, (struct ioctl_args *)args));
861		break;
862
863	/* TIOCGSOFTCAR */
864	/* TIOCSSOFTCAR */
865
866	case LINUX_FIONREAD: /* LINUX_TIOCINQ */
867		args->cmd = FIONREAD;
868		error = (sys_ioctl(td, (struct ioctl_args *)args));
869		break;
870
871	/* LINUX_TIOCLINUX */
872
873	case LINUX_TIOCCONS:
874		args->cmd = TIOCCONS;
875		error = (sys_ioctl(td, (struct ioctl_args *)args));
876		break;
877
878	case LINUX_TIOCGSERIAL: {
879		struct linux_serial_struct lss;
880
881		bzero(&lss, sizeof(lss));
882		lss.type = LINUX_PORT_16550A;
883		lss.flags = 0;
884		lss.close_delay = 0;
885		error = copyout(&lss, (void *)args->arg, sizeof(lss));
886		break;
887	}
888
889	case LINUX_TIOCSSERIAL: {
890		struct linux_serial_struct lss;
891		error = copyin((void *)args->arg, &lss, sizeof(lss));
892		if (error)
893			break;
894		/* XXX - It really helps to have an implementation that
895		 * does nothing. NOT!
896		 */
897		error = 0;
898		break;
899	}
900
901	case LINUX_TIOCPKT:
902		args->cmd = TIOCPKT;
903		error = (sys_ioctl(td, (struct ioctl_args *)args));
904		break;
905
906	case LINUX_FIONBIO:
907		args->cmd = FIONBIO;
908		error = (sys_ioctl(td, (struct ioctl_args *)args));
909		break;
910
911	case LINUX_TIOCNOTTY:
912		args->cmd = TIOCNOTTY;
913		error = (sys_ioctl(td, (struct ioctl_args *)args));
914		break;
915
916	case LINUX_TIOCSETD: {
917		int line;
918		switch (args->arg) {
919		case LINUX_N_TTY:
920			line = TTYDISC;
921			break;
922		case LINUX_N_SLIP:
923			line = SLIPDISC;
924			break;
925		case LINUX_N_PPP:
926			line = PPPDISC;
927			break;
928		default:
929			fdrop(fp, td);
930			return (EINVAL);
931		}
932		error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred,
933		    td));
934		break;
935	}
936
937	case LINUX_TIOCGETD: {
938		int linux_line;
939		int bsd_line = TTYDISC;
940		error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
941		    td->td_ucred, td);
942		if (error)
943			break;
944		switch (bsd_line) {
945		case TTYDISC:
946			linux_line = LINUX_N_TTY;
947			break;
948		case SLIPDISC:
949			linux_line = LINUX_N_SLIP;
950			break;
951		case PPPDISC:
952			linux_line = LINUX_N_PPP;
953			break;
954		default:
955			fdrop(fp, td);
956			return (EINVAL);
957		}
958		error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
959		break;
960	}
961
962	/* LINUX_TCSBRKP */
963	/* LINUX_TIOCTTYGSTRUCT */
964
965	case LINUX_FIONCLEX:
966		args->cmd = FIONCLEX;
967		error = (sys_ioctl(td, (struct ioctl_args *)args));
968		break;
969
970	case LINUX_FIOCLEX:
971		args->cmd = FIOCLEX;
972		error = (sys_ioctl(td, (struct ioctl_args *)args));
973		break;
974
975	case LINUX_FIOASYNC:
976		args->cmd = FIOASYNC;
977		error = (sys_ioctl(td, (struct ioctl_args *)args));
978		break;
979
980	/* LINUX_TIOCSERCONFIG */
981	/* LINUX_TIOCSERGWILD */
982	/* LINUX_TIOCSERSWILD */
983	/* LINUX_TIOCGLCKTRMIOS */
984	/* LINUX_TIOCSLCKTRMIOS */
985
986	case LINUX_TIOCSBRK:
987		args->cmd = TIOCSBRK;
988		error = (sys_ioctl(td, (struct ioctl_args *)args));
989		break;
990
991	case LINUX_TIOCCBRK:
992		args->cmd = TIOCCBRK;
993		error = (sys_ioctl(td, (struct ioctl_args *)args));
994		break;
995	case LINUX_TIOCGPTN: {
996		int nb;
997
998		error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td);
999		if (!error)
1000			error = copyout(&nb, (void *)args->arg,
1001			    sizeof(int));
1002		break;
1003	}
1004	case LINUX_TIOCGPTPEER:
1005		linux_msg(td, "unsupported ioctl TIOCGPTPEER");
1006		error = ENOIOCTL;
1007		break;
1008	case LINUX_TIOCSPTLCK:
1009		/*
1010		 * Our unlockpt() does nothing. Check that fd refers
1011		 * to a pseudo-terminal master device.
1012		 */
1013		args->cmd = TIOCPTMASTER;
1014		error = (sys_ioctl(td, (struct ioctl_args *)args));
1015		break;
1016	default:
1017		error = ENOIOCTL;
1018		break;
1019	}
1020
1021	fdrop(fp, td);
1022	return (error);
1023}
1024
1025/*
1026 * CDROM related ioctls
1027 */
1028
1029struct linux_cdrom_msf
1030{
1031	u_char	cdmsf_min0;
1032	u_char	cdmsf_sec0;
1033	u_char	cdmsf_frame0;
1034	u_char	cdmsf_min1;
1035	u_char	cdmsf_sec1;
1036	u_char	cdmsf_frame1;
1037};
1038
1039struct linux_cdrom_tochdr
1040{
1041	u_char	cdth_trk0;
1042	u_char	cdth_trk1;
1043};
1044
1045union linux_cdrom_addr
1046{
1047	struct {
1048		u_char	minute;
1049		u_char	second;
1050		u_char	frame;
1051	} msf;
1052	int	lba;
1053};
1054
1055struct linux_cdrom_tocentry
1056{
1057	u_char	cdte_track;
1058	u_char	cdte_adr:4;
1059	u_char	cdte_ctrl:4;
1060	u_char	cdte_format;
1061	union linux_cdrom_addr cdte_addr;
1062	u_char	cdte_datamode;
1063};
1064
1065struct linux_cdrom_subchnl
1066{
1067	u_char	cdsc_format;
1068	u_char	cdsc_audiostatus;
1069	u_char	cdsc_adr:4;
1070	u_char	cdsc_ctrl:4;
1071	u_char	cdsc_trk;
1072	u_char	cdsc_ind;
1073	union linux_cdrom_addr cdsc_absaddr;
1074	union linux_cdrom_addr cdsc_reladdr;
1075};
1076
1077struct l_cdrom_read_audio {
1078	union linux_cdrom_addr addr;
1079	u_char		addr_format;
1080	l_int		nframes;
1081	u_char		*buf;
1082};
1083
1084struct l_dvd_layer {
1085	u_char		book_version:4;
1086	u_char		book_type:4;
1087	u_char		min_rate:4;
1088	u_char		disc_size:4;
1089	u_char		layer_type:4;
1090	u_char		track_path:1;
1091	u_char		nlayers:2;
1092	u_char		track_density:4;
1093	u_char		linear_density:4;
1094	u_char		bca:1;
1095	uint32_t	start_sector;
1096	uint32_t	end_sector;
1097	uint32_t	end_sector_l0;
1098};
1099
1100struct l_dvd_physical {
1101	u_char		type;
1102	u_char		layer_num;
1103	struct l_dvd_layer layer[4];
1104};
1105
1106struct l_dvd_copyright {
1107	u_char		type;
1108	u_char		layer_num;
1109	u_char		cpst;
1110	u_char		rmi;
1111};
1112
1113struct l_dvd_disckey {
1114	u_char		type;
1115	l_uint		agid:2;
1116	u_char		value[2048];
1117};
1118
1119struct l_dvd_bca {
1120	u_char		type;
1121	l_int		len;
1122	u_char		value[188];
1123};
1124
1125struct l_dvd_manufact {
1126	u_char		type;
1127	u_char		layer_num;
1128	l_int		len;
1129	u_char		value[2048];
1130};
1131
1132typedef union {
1133	u_char			type;
1134	struct l_dvd_physical	physical;
1135	struct l_dvd_copyright	copyright;
1136	struct l_dvd_disckey	disckey;
1137	struct l_dvd_bca	bca;
1138	struct l_dvd_manufact	manufact;
1139} l_dvd_struct;
1140
1141typedef u_char l_dvd_key[5];
1142typedef u_char l_dvd_challenge[10];
1143
1144struct l_dvd_lu_send_agid {
1145	u_char		type;
1146	l_uint		agid:2;
1147};
1148
1149struct l_dvd_host_send_challenge {
1150	u_char		type;
1151	l_uint		agid:2;
1152	l_dvd_challenge	chal;
1153};
1154
1155struct l_dvd_send_key {
1156	u_char		type;
1157	l_uint		agid:2;
1158	l_dvd_key	key;
1159};
1160
1161struct l_dvd_lu_send_challenge {
1162	u_char		type;
1163	l_uint		agid:2;
1164	l_dvd_challenge	chal;
1165};
1166
1167struct l_dvd_lu_send_title_key {
1168	u_char		type;
1169	l_uint		agid:2;
1170	l_dvd_key	title_key;
1171	l_int		lba;
1172	l_uint		cpm:1;
1173	l_uint		cp_sec:1;
1174	l_uint		cgms:2;
1175};
1176
1177struct l_dvd_lu_send_asf {
1178	u_char		type;
1179	l_uint		agid:2;
1180	l_uint		asf:1;
1181};
1182
1183struct l_dvd_host_send_rpcstate {
1184	u_char		type;
1185	u_char		pdrc;
1186};
1187
1188struct l_dvd_lu_send_rpcstate {
1189	u_char		type:2;
1190	u_char		vra:3;
1191	u_char		ucca:3;
1192	u_char		region_mask;
1193	u_char		rpc_scheme;
1194};
1195
1196typedef union {
1197	u_char				type;
1198	struct l_dvd_lu_send_agid	lsa;
1199	struct l_dvd_host_send_challenge hsc;
1200	struct l_dvd_send_key		lsk;
1201	struct l_dvd_lu_send_challenge	lsc;
1202	struct l_dvd_send_key		hsk;
1203	struct l_dvd_lu_send_title_key	lstk;
1204	struct l_dvd_lu_send_asf	lsasf;
1205	struct l_dvd_host_send_rpcstate	hrpcs;
1206	struct l_dvd_lu_send_rpcstate	lrpcs;
1207} l_dvd_authinfo;
1208
1209static void
1210bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
1211{
1212	if (af == CD_LBA_FORMAT)
1213		lp->lba = bp->lba;
1214	else {
1215		lp->msf.minute = bp->msf.minute;
1216		lp->msf.second = bp->msf.second;
1217		lp->msf.frame = bp->msf.frame;
1218	}
1219}
1220
1221static void
1222set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
1223{
1224	if (format == LINUX_CDROM_MSF) {
1225		addr->msf.frame = lba % 75;
1226		lba /= 75;
1227		lba += 2;
1228		addr->msf.second = lba % 60;
1229		addr->msf.minute = lba / 60;
1230	} else
1231		addr->lba = lba;
1232}
1233
1234static int
1235linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp)
1236{
1237	bp->format = lp->type;
1238	switch (bp->format) {
1239	case DVD_STRUCT_PHYSICAL:
1240		if (bp->layer_num >= 4)
1241			return (EINVAL);
1242		bp->layer_num = lp->physical.layer_num;
1243		break;
1244	case DVD_STRUCT_COPYRIGHT:
1245		bp->layer_num = lp->copyright.layer_num;
1246		break;
1247	case DVD_STRUCT_DISCKEY:
1248		bp->agid = lp->disckey.agid;
1249		break;
1250	case DVD_STRUCT_BCA:
1251	case DVD_STRUCT_MANUFACT:
1252		break;
1253	default:
1254		return (EINVAL);
1255	}
1256	return (0);
1257}
1258
1259static int
1260bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp)
1261{
1262	switch (bp->format) {
1263	case DVD_STRUCT_PHYSICAL: {
1264		struct dvd_layer *blp = (struct dvd_layer *)bp->data;
1265		struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num];
1266		memset(llp, 0, sizeof(*llp));
1267		llp->book_version = blp->book_version;
1268		llp->book_type = blp->book_type;
1269		llp->min_rate = blp->max_rate;
1270		llp->disc_size = blp->disc_size;
1271		llp->layer_type = blp->layer_type;
1272		llp->track_path = blp->track_path;
1273		llp->nlayers = blp->nlayers;
1274		llp->track_density = blp->track_density;
1275		llp->linear_density = blp->linear_density;
1276		llp->bca = blp->bca;
1277		llp->start_sector = blp->start_sector;
1278		llp->end_sector = blp->end_sector;
1279		llp->end_sector_l0 = blp->end_sector_l0;
1280		break;
1281	}
1282	case DVD_STRUCT_COPYRIGHT:
1283		lp->copyright.cpst = bp->cpst;
1284		lp->copyright.rmi = bp->rmi;
1285		break;
1286	case DVD_STRUCT_DISCKEY:
1287		memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value));
1288		break;
1289	case DVD_STRUCT_BCA:
1290		lp->bca.len = bp->length;
1291		memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value));
1292		break;
1293	case DVD_STRUCT_MANUFACT:
1294		lp->manufact.len = bp->length;
1295		memcpy(lp->manufact.value, bp->data,
1296		    sizeof(lp->manufact.value));
1297		/* lp->manufact.layer_num is unused in Linux (redhat 7.0). */
1298		break;
1299	default:
1300		return (EINVAL);
1301	}
1302	return (0);
1303}
1304
1305static int
1306linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode,
1307    struct dvd_authinfo *bp)
1308{
1309	switch (lp->type) {
1310	case LINUX_DVD_LU_SEND_AGID:
1311		*bcode = DVDIOCREPORTKEY;
1312		bp->format = DVD_REPORT_AGID;
1313		bp->agid = lp->lsa.agid;
1314		break;
1315	case LINUX_DVD_HOST_SEND_CHALLENGE:
1316		*bcode = DVDIOCSENDKEY;
1317		bp->format = DVD_SEND_CHALLENGE;
1318		bp->agid = lp->hsc.agid;
1319		memcpy(bp->keychal, lp->hsc.chal, 10);
1320		break;
1321	case LINUX_DVD_LU_SEND_KEY1:
1322		*bcode = DVDIOCREPORTKEY;
1323		bp->format = DVD_REPORT_KEY1;
1324		bp->agid = lp->lsk.agid;
1325		break;
1326	case LINUX_DVD_LU_SEND_CHALLENGE:
1327		*bcode = DVDIOCREPORTKEY;
1328		bp->format = DVD_REPORT_CHALLENGE;
1329		bp->agid = lp->lsc.agid;
1330		break;
1331	case LINUX_DVD_HOST_SEND_KEY2:
1332		*bcode = DVDIOCSENDKEY;
1333		bp->format = DVD_SEND_KEY2;
1334		bp->agid = lp->hsk.agid;
1335		memcpy(bp->keychal, lp->hsk.key, 5);
1336		break;
1337	case LINUX_DVD_LU_SEND_TITLE_KEY:
1338		*bcode = DVDIOCREPORTKEY;
1339		bp->format = DVD_REPORT_TITLE_KEY;
1340		bp->agid = lp->lstk.agid;
1341		bp->lba = lp->lstk.lba;
1342		break;
1343	case LINUX_DVD_LU_SEND_ASF:
1344		*bcode = DVDIOCREPORTKEY;
1345		bp->format = DVD_REPORT_ASF;
1346		bp->agid = lp->lsasf.agid;
1347		break;
1348	case LINUX_DVD_INVALIDATE_AGID:
1349		*bcode = DVDIOCREPORTKEY;
1350		bp->format = DVD_INVALIDATE_AGID;
1351		bp->agid = lp->lsa.agid;
1352		break;
1353	case LINUX_DVD_LU_SEND_RPC_STATE:
1354		*bcode = DVDIOCREPORTKEY;
1355		bp->format = DVD_REPORT_RPC;
1356		break;
1357	case LINUX_DVD_HOST_SEND_RPC_STATE:
1358		*bcode = DVDIOCSENDKEY;
1359		bp->format = DVD_SEND_RPC;
1360		bp->region = lp->hrpcs.pdrc;
1361		break;
1362	default:
1363		return (EINVAL);
1364	}
1365	return (0);
1366}
1367
1368static int
1369bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
1370{
1371	switch (lp->type) {
1372	case LINUX_DVD_LU_SEND_AGID:
1373		lp->lsa.agid = bp->agid;
1374		break;
1375	case LINUX_DVD_HOST_SEND_CHALLENGE:
1376		lp->type = LINUX_DVD_LU_SEND_KEY1;
1377		break;
1378	case LINUX_DVD_LU_SEND_KEY1:
1379		memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key));
1380		break;
1381	case LINUX_DVD_LU_SEND_CHALLENGE:
1382		memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal));
1383		break;
1384	case LINUX_DVD_HOST_SEND_KEY2:
1385		lp->type = LINUX_DVD_AUTH_ESTABLISHED;
1386		break;
1387	case LINUX_DVD_LU_SEND_TITLE_KEY:
1388		memcpy(lp->lstk.title_key, bp->keychal,
1389		    sizeof(lp->lstk.title_key));
1390		lp->lstk.cpm = bp->cpm;
1391		lp->lstk.cp_sec = bp->cp_sec;
1392		lp->lstk.cgms = bp->cgms;
1393		break;
1394	case LINUX_DVD_LU_SEND_ASF:
1395		lp->lsasf.asf = bp->asf;
1396		break;
1397	case LINUX_DVD_INVALIDATE_AGID:
1398		break;
1399	case LINUX_DVD_LU_SEND_RPC_STATE:
1400		lp->lrpcs.type = bp->reg_type;
1401		lp->lrpcs.vra = bp->vend_rsts;
1402		lp->lrpcs.ucca = bp->user_rsts;
1403		lp->lrpcs.region_mask = bp->region;
1404		lp->lrpcs.rpc_scheme = bp->rpc_scheme;
1405		break;
1406	case LINUX_DVD_HOST_SEND_RPC_STATE:
1407		break;
1408	default:
1409		return (EINVAL);
1410	}
1411	return (0);
1412}
1413
1414static int
1415linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
1416{
1417	struct file *fp;
1418	int error;
1419
1420	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
1421	if (error != 0)
1422		return (error);
1423	switch (args->cmd & 0xffff) {
1424	case LINUX_CDROMPAUSE:
1425		args->cmd = CDIOCPAUSE;
1426		error = (sys_ioctl(td, (struct ioctl_args *)args));
1427		break;
1428
1429	case LINUX_CDROMRESUME:
1430		args->cmd = CDIOCRESUME;
1431		error = (sys_ioctl(td, (struct ioctl_args *)args));
1432		break;
1433
1434	case LINUX_CDROMPLAYMSF:
1435		args->cmd = CDIOCPLAYMSF;
1436		error = (sys_ioctl(td, (struct ioctl_args *)args));
1437		break;
1438
1439	case LINUX_CDROMPLAYTRKIND:
1440		args->cmd = CDIOCPLAYTRACKS;
1441		error = (sys_ioctl(td, (struct ioctl_args *)args));
1442		break;
1443
1444	case LINUX_CDROMREADTOCHDR: {
1445		struct ioc_toc_header th;
1446		struct linux_cdrom_tochdr lth;
1447		error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th,
1448		    td->td_ucred, td);
1449		if (!error) {
1450			lth.cdth_trk0 = th.starting_track;
1451			lth.cdth_trk1 = th.ending_track;
1452			error = copyout(&lth, (void *)args->arg, sizeof(lth));
1453		}
1454		break;
1455	}
1456
1457	case LINUX_CDROMREADTOCENTRY: {
1458		struct linux_cdrom_tocentry lte;
1459		struct ioc_read_toc_single_entry irtse;
1460
1461		error = copyin((void *)args->arg, &lte, sizeof(lte));
1462		if (error)
1463			break;
1464		irtse.address_format = lte.cdte_format;
1465		irtse.track = lte.cdte_track;
1466		error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse,
1467		    td->td_ucred, td);
1468		if (!error) {
1469			lte.cdte_ctrl = irtse.entry.control;
1470			lte.cdte_adr = irtse.entry.addr_type;
1471			bsd_to_linux_msf_lba(irtse.address_format,
1472			    &irtse.entry.addr, &lte.cdte_addr);
1473			error = copyout(&lte, (void *)args->arg, sizeof(lte));
1474		}
1475		break;
1476	}
1477
1478	case LINUX_CDROMSTOP:
1479		args->cmd = CDIOCSTOP;
1480		error = (sys_ioctl(td, (struct ioctl_args *)args));
1481		break;
1482
1483	case LINUX_CDROMSTART:
1484		args->cmd = CDIOCSTART;
1485		error = (sys_ioctl(td, (struct ioctl_args *)args));
1486		break;
1487
1488	case LINUX_CDROMEJECT:
1489		args->cmd = CDIOCEJECT;
1490		error = (sys_ioctl(td, (struct ioctl_args *)args));
1491		break;
1492
1493	/* LINUX_CDROMVOLCTRL */
1494
1495	case LINUX_CDROMSUBCHNL: {
1496		struct linux_cdrom_subchnl sc;
1497		struct ioc_read_subchannel bsdsc;
1498		struct cd_sub_channel_info bsdinfo;
1499
1500		error = copyin((void *)args->arg, &sc, sizeof(sc));
1501		if (error)
1502			break;
1503
1504		/*
1505		 * Invoke the native ioctl and bounce the returned data through
1506		 * the userspace buffer.  This works because the Linux structure
1507		 * is the same size as our structures for the subchannel header
1508		 * and position data.
1509		 */
1510		bsdsc.address_format = CD_LBA_FORMAT;
1511		bsdsc.data_format = CD_CURRENT_POSITION;
1512		bsdsc.track = 0;
1513		bsdsc.data_len = sizeof(sc);
1514		bsdsc.data = (void *)args->arg;
1515		error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc,
1516		    td->td_ucred, td);
1517		if (error)
1518			break;
1519		error = copyin((void *)args->arg, &bsdinfo, sizeof(bsdinfo));
1520		if (error)
1521			break;
1522		sc.cdsc_audiostatus = bsdinfo.header.audio_status;
1523		sc.cdsc_adr = bsdinfo.what.position.addr_type;
1524		sc.cdsc_ctrl = bsdinfo.what.position.control;
1525		sc.cdsc_trk = bsdinfo.what.position.track_number;
1526		sc.cdsc_ind = bsdinfo.what.position.index_number;
1527		set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
1528		    bsdinfo.what.position.absaddr.lba);
1529		set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
1530		    bsdinfo.what.position.reladdr.lba);
1531		error = copyout(&sc, (void *)args->arg, sizeof(sc));
1532		break;
1533	}
1534
1535	/* LINUX_CDROMREADMODE2 */
1536	/* LINUX_CDROMREADMODE1 */
1537	/* LINUX_CDROMREADAUDIO */
1538	/* LINUX_CDROMEJECT_SW */
1539	/* LINUX_CDROMMULTISESSION */
1540	/* LINUX_CDROM_GET_UPC */
1541
1542	case LINUX_CDROMRESET:
1543		args->cmd = CDIOCRESET;
1544		error = (sys_ioctl(td, (struct ioctl_args *)args));
1545		break;
1546
1547	/* LINUX_CDROMVOLREAD */
1548	/* LINUX_CDROMREADRAW */
1549	/* LINUX_CDROMREADCOOKED */
1550	/* LINUX_CDROMSEEK */
1551	/* LINUX_CDROMPLAYBLK */
1552	/* LINUX_CDROMREADALL */
1553	/* LINUX_CDROMCLOSETRAY */
1554	/* LINUX_CDROMLOADFROMSLOT */
1555	/* LINUX_CDROMGETSPINDOWN */
1556	/* LINUX_CDROMSETSPINDOWN */
1557	/* LINUX_CDROM_SET_OPTIONS */
1558	/* LINUX_CDROM_CLEAR_OPTIONS */
1559	/* LINUX_CDROM_SELECT_SPEED */
1560	/* LINUX_CDROM_SELECT_DISC */
1561	/* LINUX_CDROM_MEDIA_CHANGED */
1562	/* LINUX_CDROM_DRIVE_STATUS */
1563	/* LINUX_CDROM_DISC_STATUS */
1564	/* LINUX_CDROM_CHANGER_NSLOTS */
1565	/* LINUX_CDROM_LOCKDOOR */
1566	/* LINUX_CDROM_DEBUG */
1567	/* LINUX_CDROM_GET_CAPABILITY */
1568	/* LINUX_CDROMAUDIOBUFSIZ */
1569
1570	case LINUX_DVD_READ_STRUCT: {
1571		l_dvd_struct *lds;
1572		struct dvd_struct *bds;
1573
1574		lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK);
1575		bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK);
1576		error = copyin((void *)args->arg, lds, sizeof(*lds));
1577		if (error)
1578			goto out;
1579		error = linux_to_bsd_dvd_struct(lds, bds);
1580		if (error)
1581			goto out;
1582		error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds,
1583		    td->td_ucred, td);
1584		if (error)
1585			goto out;
1586		error = bsd_to_linux_dvd_struct(bds, lds);
1587		if (error)
1588			goto out;
1589		error = copyout(lds, (void *)args->arg, sizeof(*lds));
1590	out:
1591		free(bds, M_LINUX);
1592		free(lds, M_LINUX);
1593		break;
1594	}
1595
1596	/* LINUX_DVD_WRITE_STRUCT */
1597
1598	case LINUX_DVD_AUTH: {
1599		l_dvd_authinfo lda;
1600		struct dvd_authinfo bda;
1601		int bcode;
1602
1603		error = copyin((void *)args->arg, &lda, sizeof(lda));
1604		if (error)
1605			break;
1606		error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
1607		if (error)
1608			break;
1609		error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred,
1610		    td);
1611		if (error) {
1612			if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
1613				lda.type = LINUX_DVD_AUTH_FAILURE;
1614				(void)copyout(&lda, (void *)args->arg,
1615				    sizeof(lda));
1616			}
1617			break;
1618		}
1619		error = bsd_to_linux_dvd_authinfo(&bda, &lda);
1620		if (error)
1621			break;
1622		error = copyout(&lda, (void *)args->arg, sizeof(lda));
1623		break;
1624	}
1625
1626	case LINUX_SCSI_GET_BUS_NUMBER:
1627	{
1628		struct sg_scsi_id id;
1629
1630		error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
1631		    td->td_ucred, td);
1632		if (error)
1633			break;
1634		error = copyout(&id.channel, (void *)args->arg, sizeof(int));
1635		break;
1636	}
1637
1638	case LINUX_SCSI_GET_IDLUN:
1639	{
1640		struct sg_scsi_id id;
1641		struct scsi_idlun idl;
1642
1643		error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
1644		    td->td_ucred, td);
1645		if (error)
1646			break;
1647		idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) +
1648		    ((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24);
1649		idl.host_unique_id = id.host_no;
1650		error = copyout(&idl, (void *)args->arg, sizeof(idl));
1651		break;
1652	}
1653
1654	/* LINUX_CDROM_SEND_PACKET */
1655	/* LINUX_CDROM_NEXT_WRITABLE */
1656	/* LINUX_CDROM_LAST_WRITTEN */
1657
1658	default:
1659		error = ENOIOCTL;
1660		break;
1661	}
1662
1663	fdrop(fp, td);
1664	return (error);
1665}
1666
1667static int
1668linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args)
1669{
1670
1671	return (ENOTTY);
1672}
1673
1674/*
1675 * Sound related ioctls
1676 */
1677
1678struct linux_old_mixer_info {
1679	char	id[16];
1680	char	name[32];
1681};
1682
1683static uint32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1684
1685#define	SETDIR(c)	(((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1686
1687static int
1688linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
1689{
1690
1691	switch (args->cmd & 0xffff) {
1692	case LINUX_SOUND_MIXER_WRITE_VOLUME:
1693		args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1694		return (sys_ioctl(td, (struct ioctl_args *)args));
1695
1696	case LINUX_SOUND_MIXER_WRITE_BASS:
1697		args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1698		return (sys_ioctl(td, (struct ioctl_args *)args));
1699
1700	case LINUX_SOUND_MIXER_WRITE_TREBLE:
1701		args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1702		return (sys_ioctl(td, (struct ioctl_args *)args));
1703
1704	case LINUX_SOUND_MIXER_WRITE_SYNTH:
1705		args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1706		return (sys_ioctl(td, (struct ioctl_args *)args));
1707
1708	case LINUX_SOUND_MIXER_WRITE_PCM:
1709		args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1710		return (sys_ioctl(td, (struct ioctl_args *)args));
1711
1712	case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1713		args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1714		return (sys_ioctl(td, (struct ioctl_args *)args));
1715
1716	case LINUX_SOUND_MIXER_WRITE_LINE:
1717		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1718		return (sys_ioctl(td, (struct ioctl_args *)args));
1719
1720	case LINUX_SOUND_MIXER_WRITE_MIC:
1721		args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1722		return (sys_ioctl(td, (struct ioctl_args *)args));
1723
1724	case LINUX_SOUND_MIXER_WRITE_CD:
1725		args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1726		return (sys_ioctl(td, (struct ioctl_args *)args));
1727
1728	case LINUX_SOUND_MIXER_WRITE_IMIX:
1729		args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1730		return (sys_ioctl(td, (struct ioctl_args *)args));
1731
1732	case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1733		args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1734		return (sys_ioctl(td, (struct ioctl_args *)args));
1735
1736	case LINUX_SOUND_MIXER_WRITE_RECLEV:
1737		args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1738		return (sys_ioctl(td, (struct ioctl_args *)args));
1739
1740	case LINUX_SOUND_MIXER_WRITE_IGAIN:
1741		args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1742		return (sys_ioctl(td, (struct ioctl_args *)args));
1743
1744	case LINUX_SOUND_MIXER_WRITE_OGAIN:
1745		args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1746		return (sys_ioctl(td, (struct ioctl_args *)args));
1747
1748	case LINUX_SOUND_MIXER_WRITE_LINE1:
1749		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1750		return (sys_ioctl(td, (struct ioctl_args *)args));
1751
1752	case LINUX_SOUND_MIXER_WRITE_LINE2:
1753		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1754		return (sys_ioctl(td, (struct ioctl_args *)args));
1755
1756	case LINUX_SOUND_MIXER_WRITE_LINE3:
1757		args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1758		return (sys_ioctl(td, (struct ioctl_args *)args));
1759
1760	case LINUX_SOUND_MIXER_WRITE_MONITOR:
1761		args->cmd = SETDIR(SOUND_MIXER_WRITE_MONITOR);
1762		return (sys_ioctl(td, (struct ioctl_args *)args));
1763
1764	case LINUX_SOUND_MIXER_INFO: {
1765		/* Key on encoded length */
1766		switch ((args->cmd >> 16) & 0x1fff) {
1767		case 0x005c: {	/* SOUND_MIXER_INFO */
1768			args->cmd = SOUND_MIXER_INFO;
1769			return (sys_ioctl(td, (struct ioctl_args *)args));
1770		}
1771		case 0x0030: {	/* SOUND_OLD_MIXER_INFO */
1772			struct linux_old_mixer_info info;
1773			bzero(&info, sizeof(info));
1774			strncpy(info.id, "OSS", sizeof(info.id) - 1);
1775			strncpy(info.name, "FreeBSD OSS Mixer",
1776			    sizeof(info.name) - 1);
1777			return (copyout(&info, (void *)args->arg,
1778			    sizeof(info)));
1779		}
1780		default:
1781			return (ENOIOCTL);
1782		}
1783		break;
1784	}
1785
1786	case LINUX_OSS_GETVERSION: {
1787		int version = linux_get_oss_version(td);
1788		return (copyout(&version, (void *)args->arg, sizeof(int)));
1789	}
1790
1791	case LINUX_SOUND_MIXER_READ_STEREODEVS:
1792		args->cmd = SOUND_MIXER_READ_STEREODEVS;
1793		return (sys_ioctl(td, (struct ioctl_args *)args));
1794
1795	case LINUX_SOUND_MIXER_READ_CAPS:
1796		args->cmd = SOUND_MIXER_READ_CAPS;
1797		return (sys_ioctl(td, (struct ioctl_args *)args));
1798
1799	case LINUX_SOUND_MIXER_READ_RECMASK:
1800		args->cmd = SOUND_MIXER_READ_RECMASK;
1801		return (sys_ioctl(td, (struct ioctl_args *)args));
1802
1803	case LINUX_SOUND_MIXER_READ_DEVMASK:
1804		args->cmd = SOUND_MIXER_READ_DEVMASK;
1805		return (sys_ioctl(td, (struct ioctl_args *)args));
1806
1807	case LINUX_SOUND_MIXER_WRITE_RECSRC:
1808		args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
1809		return (sys_ioctl(td, (struct ioctl_args *)args));
1810
1811	case LINUX_SNDCTL_DSP_RESET:
1812		args->cmd = SNDCTL_DSP_RESET;
1813		return (sys_ioctl(td, (struct ioctl_args *)args));
1814
1815	case LINUX_SNDCTL_DSP_SYNC:
1816		args->cmd = SNDCTL_DSP_SYNC;
1817		return (sys_ioctl(td, (struct ioctl_args *)args));
1818
1819	case LINUX_SNDCTL_DSP_SPEED:
1820		args->cmd = SNDCTL_DSP_SPEED;
1821		return (sys_ioctl(td, (struct ioctl_args *)args));
1822
1823	case LINUX_SNDCTL_DSP_STEREO:
1824		args->cmd = SNDCTL_DSP_STEREO;
1825		return (sys_ioctl(td, (struct ioctl_args *)args));
1826
1827	case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1828		args->cmd = SNDCTL_DSP_GETBLKSIZE;
1829		return (sys_ioctl(td, (struct ioctl_args *)args));
1830
1831	case LINUX_SNDCTL_DSP_SETFMT:
1832		args->cmd = SNDCTL_DSP_SETFMT;
1833		return (sys_ioctl(td, (struct ioctl_args *)args));
1834
1835	case LINUX_SOUND_PCM_WRITE_CHANNELS:
1836		args->cmd = SOUND_PCM_WRITE_CHANNELS;
1837		return (sys_ioctl(td, (struct ioctl_args *)args));
1838
1839	case LINUX_SOUND_PCM_WRITE_FILTER:
1840		args->cmd = SOUND_PCM_WRITE_FILTER;
1841		return (sys_ioctl(td, (struct ioctl_args *)args));
1842
1843	case LINUX_SNDCTL_DSP_POST:
1844		args->cmd = SNDCTL_DSP_POST;
1845		return (sys_ioctl(td, (struct ioctl_args *)args));
1846
1847	case LINUX_SNDCTL_DSP_SUBDIVIDE:
1848		args->cmd = SNDCTL_DSP_SUBDIVIDE;
1849		return (sys_ioctl(td, (struct ioctl_args *)args));
1850
1851	case LINUX_SNDCTL_DSP_SETFRAGMENT:
1852		args->cmd = SNDCTL_DSP_SETFRAGMENT;
1853		return (sys_ioctl(td, (struct ioctl_args *)args));
1854
1855	case LINUX_SNDCTL_DSP_GETFMTS:
1856		args->cmd = SNDCTL_DSP_GETFMTS;
1857		return (sys_ioctl(td, (struct ioctl_args *)args));
1858
1859	case LINUX_SNDCTL_DSP_GETOSPACE:
1860		args->cmd = SNDCTL_DSP_GETOSPACE;
1861		return (sys_ioctl(td, (struct ioctl_args *)args));
1862
1863	case LINUX_SNDCTL_DSP_GETISPACE:
1864		args->cmd = SNDCTL_DSP_GETISPACE;
1865		return (sys_ioctl(td, (struct ioctl_args *)args));
1866
1867	case LINUX_SNDCTL_DSP_NONBLOCK:
1868		args->cmd = SNDCTL_DSP_NONBLOCK;
1869		return (sys_ioctl(td, (struct ioctl_args *)args));
1870
1871	case LINUX_SNDCTL_DSP_GETCAPS:
1872		args->cmd = SNDCTL_DSP_GETCAPS;
1873		return (sys_ioctl(td, (struct ioctl_args *)args));
1874
1875	case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1876		args->cmd = SNDCTL_DSP_SETTRIGGER;
1877		return (sys_ioctl(td, (struct ioctl_args *)args));
1878
1879	case LINUX_SNDCTL_DSP_GETIPTR:
1880		args->cmd = SNDCTL_DSP_GETIPTR;
1881		return (sys_ioctl(td, (struct ioctl_args *)args));
1882
1883	case LINUX_SNDCTL_DSP_GETOPTR:
1884		args->cmd = SNDCTL_DSP_GETOPTR;
1885		return (sys_ioctl(td, (struct ioctl_args *)args));
1886
1887	case LINUX_SNDCTL_DSP_SETDUPLEX:
1888		args->cmd = SNDCTL_DSP_SETDUPLEX;
1889		return (sys_ioctl(td, (struct ioctl_args *)args));
1890
1891	case LINUX_SNDCTL_DSP_GETODELAY:
1892		args->cmd = SNDCTL_DSP_GETODELAY;
1893		return (sys_ioctl(td, (struct ioctl_args *)args));
1894
1895	case LINUX_SNDCTL_SEQ_RESET:
1896		args->cmd = SNDCTL_SEQ_RESET;
1897		return (sys_ioctl(td, (struct ioctl_args *)args));
1898
1899	case LINUX_SNDCTL_SEQ_SYNC:
1900		args->cmd = SNDCTL_SEQ_SYNC;
1901		return (sys_ioctl(td, (struct ioctl_args *)args));
1902
1903	case LINUX_SNDCTL_SYNTH_INFO:
1904		args->cmd = SNDCTL_SYNTH_INFO;
1905		return (sys_ioctl(td, (struct ioctl_args *)args));
1906
1907	case LINUX_SNDCTL_SEQ_CTRLRATE:
1908		args->cmd = SNDCTL_SEQ_CTRLRATE;
1909		return (sys_ioctl(td, (struct ioctl_args *)args));
1910
1911	case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1912		args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1913		return (sys_ioctl(td, (struct ioctl_args *)args));
1914
1915	case LINUX_SNDCTL_SEQ_GETINCOUNT:
1916		args->cmd = SNDCTL_SEQ_GETINCOUNT;
1917		return (sys_ioctl(td, (struct ioctl_args *)args));
1918
1919	case LINUX_SNDCTL_SEQ_PERCMODE:
1920		args->cmd = SNDCTL_SEQ_PERCMODE;
1921		return (sys_ioctl(td, (struct ioctl_args *)args));
1922
1923	case LINUX_SNDCTL_FM_LOAD_INSTR:
1924		args->cmd = SNDCTL_FM_LOAD_INSTR;
1925		return (sys_ioctl(td, (struct ioctl_args *)args));
1926
1927	case LINUX_SNDCTL_SEQ_TESTMIDI:
1928		args->cmd = SNDCTL_SEQ_TESTMIDI;
1929		return (sys_ioctl(td, (struct ioctl_args *)args));
1930
1931	case LINUX_SNDCTL_SEQ_RESETSAMPLES:
1932		args->cmd = SNDCTL_SEQ_RESETSAMPLES;
1933		return (sys_ioctl(td, (struct ioctl_args *)args));
1934
1935	case LINUX_SNDCTL_SEQ_NRSYNTHS:
1936		args->cmd = SNDCTL_SEQ_NRSYNTHS;
1937		return (sys_ioctl(td, (struct ioctl_args *)args));
1938
1939	case LINUX_SNDCTL_SEQ_NRMIDIS:
1940		args->cmd = SNDCTL_SEQ_NRMIDIS;
1941		return (sys_ioctl(td, (struct ioctl_args *)args));
1942
1943	case LINUX_SNDCTL_MIDI_INFO:
1944		args->cmd = SNDCTL_MIDI_INFO;
1945		return (sys_ioctl(td, (struct ioctl_args *)args));
1946
1947	case LINUX_SNDCTL_SEQ_TRESHOLD:
1948		args->cmd = SNDCTL_SEQ_TRESHOLD;
1949		return (sys_ioctl(td, (struct ioctl_args *)args));
1950
1951	case LINUX_SNDCTL_SYNTH_MEMAVL:
1952		args->cmd = SNDCTL_SYNTH_MEMAVL;
1953		return (sys_ioctl(td, (struct ioctl_args *)args));
1954	}
1955
1956	return (ENOIOCTL);
1957}
1958
1959/*
1960 * Console related ioctls
1961 */
1962
1963static int
1964linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
1965{
1966	struct file *fp;
1967	int error;
1968
1969	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
1970	if (error != 0)
1971		return (error);
1972	switch (args->cmd & 0xffff) {
1973	case LINUX_KIOCSOUND:
1974		args->cmd = KIOCSOUND;
1975		error = (sys_ioctl(td, (struct ioctl_args *)args));
1976		break;
1977
1978	case LINUX_KDMKTONE:
1979		args->cmd = KDMKTONE;
1980		error = (sys_ioctl(td, (struct ioctl_args *)args));
1981		break;
1982
1983	case LINUX_KDGETLED:
1984		args->cmd = KDGETLED;
1985		error = (sys_ioctl(td, (struct ioctl_args *)args));
1986		break;
1987
1988	case LINUX_KDSETLED:
1989		args->cmd = KDSETLED;
1990		error = (sys_ioctl(td, (struct ioctl_args *)args));
1991		break;
1992
1993	case LINUX_KDSETMODE:
1994		args->cmd = KDSETMODE;
1995		error = (sys_ioctl(td, (struct ioctl_args *)args));
1996		break;
1997
1998	case LINUX_KDGETMODE:
1999		args->cmd = KDGETMODE;
2000		error = (sys_ioctl(td, (struct ioctl_args *)args));
2001		break;
2002
2003	case LINUX_KDGKBMODE:
2004		args->cmd = KDGKBMODE;
2005		error = (sys_ioctl(td, (struct ioctl_args *)args));
2006		break;
2007
2008	case LINUX_KDSKBMODE: {
2009		int kbdmode;
2010		switch (args->arg) {
2011		case LINUX_KBD_RAW:
2012			kbdmode = K_RAW;
2013			break;
2014		case LINUX_KBD_XLATE:
2015			kbdmode = K_XLATE;
2016			break;
2017		case LINUX_KBD_MEDIUMRAW:
2018			kbdmode = K_RAW;
2019			break;
2020		default:
2021			fdrop(fp, td);
2022			return (EINVAL);
2023		}
2024		error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode,
2025		    td->td_ucred, td));
2026		break;
2027	}
2028
2029	case LINUX_VT_OPENQRY:
2030		args->cmd = VT_OPENQRY;
2031		error = (sys_ioctl(td, (struct ioctl_args *)args));
2032		break;
2033
2034	case LINUX_VT_GETMODE:
2035		args->cmd = VT_GETMODE;
2036		error = (sys_ioctl(td, (struct ioctl_args *)args));
2037		break;
2038
2039	case LINUX_VT_SETMODE: {
2040		struct vt_mode mode;
2041		if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
2042			break;
2043		if (LINUX_SIG_VALID(mode.relsig))
2044			mode.relsig = linux_to_bsd_signal(mode.relsig);
2045		else
2046			mode.relsig = 0;
2047		if (LINUX_SIG_VALID(mode.acqsig))
2048			mode.acqsig = linux_to_bsd_signal(mode.acqsig);
2049		else
2050			mode.acqsig = 0;
2051		/* XXX. Linux ignores frsig and set it to 0. */
2052		mode.frsig = 0;
2053		if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
2054			break;
2055		args->cmd = VT_SETMODE;
2056		error = (sys_ioctl(td, (struct ioctl_args *)args));
2057		break;
2058	}
2059
2060	case LINUX_VT_GETSTATE:
2061		args->cmd = VT_GETACTIVE;
2062		error = (sys_ioctl(td, (struct ioctl_args *)args));
2063		break;
2064
2065	case LINUX_VT_RELDISP:
2066		args->cmd = VT_RELDISP;
2067		error = (sys_ioctl(td, (struct ioctl_args *)args));
2068		break;
2069
2070	case LINUX_VT_ACTIVATE:
2071		args->cmd = VT_ACTIVATE;
2072		error = (sys_ioctl(td, (struct ioctl_args *)args));
2073		break;
2074
2075	case LINUX_VT_WAITACTIVE:
2076		args->cmd = VT_WAITACTIVE;
2077		error = (sys_ioctl(td, (struct ioctl_args *)args));
2078		break;
2079
2080	default:
2081		error = ENOIOCTL;
2082		break;
2083	}
2084
2085	fdrop(fp, td);
2086	return (error);
2087}
2088
2089/*
2090 * Implement the SIOCGIFNAME ioctl
2091 */
2092
2093static int
2094linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
2095{
2096	struct l_ifreq ifr;
2097	int error, ret;
2098
2099	error = copyin(uifr, &ifr, sizeof(ifr));
2100	if (error != 0)
2101		return (error);
2102	ret = ifname_bsd_to_linux_idx(ifr.ifr_index, ifr.ifr_name,
2103	    LINUX_IFNAMSIZ);
2104	if (ret > 0)
2105		return (copyout(&ifr, uifr, sizeof(ifr)));
2106	else
2107		return (ENODEV);
2108}
2109
2110/*
2111 * Implement the SIOCGIFCONF ioctl
2112 */
2113static u_int
2114linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
2115{
2116#ifdef COMPAT_LINUX32
2117	struct l_ifconf *ifc;
2118#else
2119	struct ifconf *ifc;
2120#endif
2121
2122	ifc = arg;
2123	ifc->ifc_len += sizeof(struct l_ifreq);
2124	return (1);
2125}
2126
2127static int
2128linux_ifconf_ifnet_cb(if_t ifp, void *arg)
2129{
2130
2131	if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg);
2132	return (0);
2133}
2134
2135struct linux_ifconfig_ifaddr_cb2_s {
2136	struct l_ifreq ifr;
2137	struct sbuf *sb;
2138	size_t max_len;
2139	size_t valid_len;
2140};
2141
2142static u_int
2143linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len)
2144{
2145	struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
2146	struct sockaddr *sa = ifa->ifa_addr;
2147
2148	cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET;
2149	memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data,
2150	    sizeof(cbs->ifr.ifr_addr.sa_data));
2151	sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
2152	cbs->max_len += sizeof(cbs->ifr);
2153
2154	if (sbuf_error(cbs->sb) == 0)
2155		cbs->valid_len = sbuf_len(cbs->sb);
2156	return (1);
2157}
2158
2159static int
2160linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
2161{
2162	struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
2163
2164	bzero(&cbs->ifr, sizeof(cbs->ifr));
2165	ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name,
2166	    sizeof(cbs->ifr.ifr_name));
2167
2168	/* Walk the address list */
2169	if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs);
2170	return (0);
2171}
2172
2173static int
2174linux_ifconf(struct thread *td, struct ifconf *uifc)
2175{
2176	struct linux_ifconfig_ifaddr_cb2_s cbs;
2177	struct epoch_tracker et;
2178#ifdef COMPAT_LINUX32
2179	struct l_ifconf ifc;
2180#else
2181	struct ifconf ifc;
2182#endif
2183	struct sbuf *sb;
2184	int error, full;
2185
2186	error = copyin(uifc, &ifc, sizeof(ifc));
2187	if (error != 0)
2188		return (error);
2189
2190	/* handle the 'request buffer size' case */
2191	if (PTRIN(ifc.ifc_buf) == NULL) {
2192		ifc.ifc_len = 0;
2193		NET_EPOCH_ENTER(et);
2194		if_foreach(linux_ifconf_ifnet_cb, &ifc);
2195		NET_EPOCH_EXIT(et);
2196		return (copyout(&ifc, uifc, sizeof(ifc)));
2197	}
2198	if (ifc.ifc_len <= 0)
2199		return (EINVAL);
2200
2201	full = 0;
2202	cbs.max_len = maxphys - 1;
2203
2204again:
2205	if (ifc.ifc_len <= cbs.max_len) {
2206		cbs.max_len = ifc.ifc_len;
2207		full = 1;
2208	}
2209	cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
2210	cbs.max_len = 0;
2211	cbs.valid_len = 0;
2212
2213	/* Return all AF_INET addresses of all interfaces */
2214	NET_EPOCH_ENTER(et);
2215	if_foreach(linux_ifconf_ifnet_cb2, &cbs);
2216	NET_EPOCH_EXIT(et);
2217
2218	if (cbs.valid_len != cbs.max_len && !full) {
2219		sbuf_delete(sb);
2220		goto again;
2221	}
2222
2223	ifc.ifc_len = cbs.valid_len;
2224	sbuf_finish(sb);
2225	error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
2226	if (error == 0)
2227		error = copyout(&ifc, uifc, sizeof(ifc));
2228	sbuf_delete(sb);
2229
2230	return (error);
2231}
2232
2233static int
2234linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd,
2235    struct l_ifreq *uifr)
2236{
2237	struct l_ifreq lifr;
2238	struct ifreq bifr;
2239	size_t ifrusiz;
2240	int error, temp_flags;
2241
2242	switch (cmd) {
2243	case LINUX_SIOCGIFINDEX:
2244		cmd = SIOCGIFINDEX;
2245		break;
2246	case LINUX_SIOCGIFFLAGS:
2247		cmd = SIOCGIFFLAGS;
2248		break;
2249	case LINUX_SIOCGIFADDR:
2250		cmd = SIOCGIFADDR;
2251		break;
2252	case LINUX_SIOCSIFADDR:
2253		cmd = SIOCSIFADDR;
2254		break;
2255	case LINUX_SIOCGIFDSTADDR:
2256		cmd = SIOCGIFDSTADDR;
2257		break;
2258	case LINUX_SIOCGIFBRDADDR:
2259		cmd = SIOCGIFBRDADDR;
2260		break;
2261	case LINUX_SIOCGIFNETMASK:
2262		cmd = SIOCGIFNETMASK;
2263		break;
2264	case LINUX_SIOCSIFNETMASK:
2265		cmd = SIOCSIFNETMASK;
2266		break;
2267	case LINUX_SIOCGIFMTU:
2268		cmd = SIOCGIFMTU;
2269		break;
2270	case LINUX_SIOCSIFMTU:
2271		cmd = SIOCSIFMTU;
2272		break;
2273	case LINUX_SIOCGIFHWADDR:
2274		cmd = SIOCGHWADDR;
2275		break;
2276	case LINUX_SIOCGIFMETRIC:
2277		cmd = SIOCGIFMETRIC;
2278		break;
2279	case LINUX_SIOCSIFMETRIC:
2280		cmd = SIOCSIFMETRIC;
2281		break;
2282	/*
2283	 * XXX This is slightly bogus, but these ioctls are currently
2284	 * XXX only used by the aironet (if_an) network driver.
2285	 */
2286	case LINUX_SIOCDEVPRIVATE:
2287		cmd = SIOCGPRIVATE_0;
2288		break;
2289	case LINUX_SIOCDEVPRIVATE+1:
2290		cmd = SIOCGPRIVATE_1;
2291		break;
2292	default:
2293		LINUX_RATELIMIT_MSG_OPT2(
2294		    "ioctl_socket_ifreq fd=%d, cmd=0x%x is not implemented",
2295		    fd, cmd);
2296		return (ENOIOCTL);
2297	}
2298
2299	error = copyin(uifr, &lifr, sizeof(lifr));
2300	if (error != 0)
2301		return (error);
2302	bzero(&bifr, sizeof(bifr));
2303
2304	/*
2305	 * The size of Linux enum ifr_ifru is bigger than
2306	 * the FreeBSD size due to the struct ifmap.
2307	 */
2308	ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) :
2309	    sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru);
2310	bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz);
2311
2312	error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name);
2313	if (error != 0)
2314		return (error);
2315
2316	/* Translate in values. */
2317	switch (cmd) {
2318	case SIOCGIFINDEX:
2319		bifr.ifr_index = lifr.ifr_index;
2320		break;
2321	case SIOCSIFADDR:
2322	case SIOCSIFNETMASK:
2323		bifr.ifr_addr.sa_len = sizeof(struct sockaddr);
2324		bifr.ifr_addr.sa_family =
2325		    linux_to_bsd_domain(lifr.ifr_addr.sa_family);
2326		break;
2327	default:
2328		break;
2329	}
2330
2331	error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr);
2332	if (error != 0)
2333		return (error);
2334	bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru));
2335
2336	/* Translate out values. */
2337 	switch (cmd) {
2338	case SIOCGIFINDEX:
2339		lifr.ifr_index = bifr.ifr_index;
2340		break;
2341	case SIOCGIFFLAGS:
2342		temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16);
2343		lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags);
2344		break;
2345	case SIOCGIFADDR:
2346	case SIOCSIFADDR:
2347	case SIOCGIFDSTADDR:
2348	case SIOCGIFBRDADDR:
2349	case SIOCGIFNETMASK:
2350		bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr));
2351		lifr.ifr_addr.sa_family =
2352		    bsd_to_linux_domain(bifr.ifr_addr.sa_family);
2353		break;
2354	case SIOCGHWADDR:
2355		bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr));
2356		lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER;
2357		break;
2358	default:
2359		bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz);
2360		break;
2361	}
2362
2363	return (copyout(&lifr, uifr, sizeof(lifr)));
2364}
2365
2366/*
2367 * Socket related ioctls
2368 */
2369
2370static int
2371linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
2372{
2373	struct file *fp;
2374	int error, type;
2375
2376	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2377	if (error != 0)
2378		return (error);
2379	type = fp->f_type;
2380	fdrop(fp, td);
2381
2382	CURVNET_SET(TD_TO_VNET(td));
2383
2384	if (type != DTYPE_SOCKET) {
2385		/* not a socket - probably a tap / vmnet device */
2386		switch (args->cmd) {
2387		case LINUX_SIOCGIFADDR:
2388		case LINUX_SIOCSIFADDR:
2389		case LINUX_SIOCGIFFLAGS:
2390			error = linux_ioctl_special(td, args);
2391			break;
2392		default:
2393			error = ENOIOCTL;
2394			break;
2395		}
2396		CURVNET_RESTORE();
2397		return (error);
2398	}
2399
2400	switch (args->cmd) {
2401	case LINUX_FIOSETOWN:
2402		args->cmd = FIOSETOWN;
2403		error = sys_ioctl(td, (struct ioctl_args *)args);
2404		break;
2405
2406	case LINUX_SIOCSPGRP:
2407		args->cmd = SIOCSPGRP;
2408		error = sys_ioctl(td, (struct ioctl_args *)args);
2409		break;
2410
2411	case LINUX_FIOGETOWN:
2412		args->cmd = FIOGETOWN;
2413		error = sys_ioctl(td, (struct ioctl_args *)args);
2414		break;
2415
2416	case LINUX_SIOCGPGRP:
2417		args->cmd = SIOCGPGRP;
2418		error = sys_ioctl(td, (struct ioctl_args *)args);
2419		break;
2420
2421	case LINUX_SIOCATMARK:
2422		args->cmd = SIOCATMARK;
2423		error = sys_ioctl(td, (struct ioctl_args *)args);
2424		break;
2425
2426	/* LINUX_SIOCGSTAMP */
2427
2428	case LINUX_SIOCGIFNAME:
2429		error = linux_ioctl_ifname(td, (struct l_ifreq *)args->arg);
2430		break;
2431
2432	case LINUX_SIOCGIFCONF:
2433		error = linux_ifconf(td, (struct ifconf *)args->arg);
2434		break;
2435
2436	case LINUX_SIOCADDMULTI:
2437		args->cmd = SIOCADDMULTI;
2438		error = sys_ioctl(td, (struct ioctl_args *)args);
2439		break;
2440
2441	case LINUX_SIOCDELMULTI:
2442		args->cmd = SIOCDELMULTI;
2443		error = sys_ioctl(td, (struct ioctl_args *)args);
2444		break;
2445
2446	case LINUX_SIOCGIFCOUNT:
2447		error = 0;
2448		break;
2449
2450	default:
2451		error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd,
2452		    PTRIN(args->arg));
2453		break;
2454	}
2455
2456	CURVNET_RESTORE();
2457	return (error);
2458}
2459
2460/*
2461 * Device private ioctl handler
2462 */
2463static int
2464linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
2465{
2466	struct file *fp;
2467	int error, type;
2468
2469	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2470	if (error != 0)
2471		return (error);
2472	type = fp->f_type;
2473	fdrop(fp, td);
2474	if (type == DTYPE_SOCKET)
2475		return (linux_ioctl_socket(td, args));
2476	return (ENOIOCTL);
2477}
2478
2479/*
2480 * DRM ioctl handler (sys/dev/drm)
2481 */
2482static int
2483linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
2484{
2485	args->cmd = SETDIR(args->cmd);
2486	return (sys_ioctl(td, (struct ioctl_args *)args));
2487}
2488
2489#ifdef COMPAT_LINUX32
2490static int
2491linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args)
2492{
2493	struct sg_io_hdr io;
2494	struct sg_io_hdr32 io32;
2495	struct file *fp;
2496	int error;
2497
2498	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2499	if (error != 0) {
2500		printf("sg_linux_ioctl: fget returned %d\n", error);
2501		return (error);
2502	}
2503
2504	if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0)
2505		goto out;
2506
2507	CP(io32, io, interface_id);
2508	CP(io32, io, dxfer_direction);
2509	CP(io32, io, cmd_len);
2510	CP(io32, io, mx_sb_len);
2511	CP(io32, io, iovec_count);
2512	CP(io32, io, dxfer_len);
2513	PTRIN_CP(io32, io, dxferp);
2514	PTRIN_CP(io32, io, cmdp);
2515	PTRIN_CP(io32, io, sbp);
2516	CP(io32, io, timeout);
2517	CP(io32, io, flags);
2518	CP(io32, io, pack_id);
2519	PTRIN_CP(io32, io, usr_ptr);
2520	CP(io32, io, status);
2521	CP(io32, io, masked_status);
2522	CP(io32, io, msg_status);
2523	CP(io32, io, sb_len_wr);
2524	CP(io32, io, host_status);
2525	CP(io32, io, driver_status);
2526	CP(io32, io, resid);
2527	CP(io32, io, duration);
2528	CP(io32, io, info);
2529
2530	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
2531		goto out;
2532
2533	CP(io, io32, interface_id);
2534	CP(io, io32, dxfer_direction);
2535	CP(io, io32, cmd_len);
2536	CP(io, io32, mx_sb_len);
2537	CP(io, io32, iovec_count);
2538	CP(io, io32, dxfer_len);
2539	PTROUT_CP(io, io32, dxferp);
2540	PTROUT_CP(io, io32, cmdp);
2541	PTROUT_CP(io, io32, sbp);
2542	CP(io, io32, timeout);
2543	CP(io, io32, flags);
2544	CP(io, io32, pack_id);
2545	PTROUT_CP(io, io32, usr_ptr);
2546	CP(io, io32, status);
2547	CP(io, io32, masked_status);
2548	CP(io, io32, msg_status);
2549	CP(io, io32, sb_len_wr);
2550	CP(io, io32, host_status);
2551	CP(io, io32, driver_status);
2552	CP(io, io32, resid);
2553	CP(io, io32, duration);
2554	CP(io, io32, info);
2555
2556	error = copyout(&io32, (void *)args->arg, sizeof(io32));
2557
2558out:
2559	fdrop(fp, td);
2560	return (error);
2561}
2562#endif
2563
2564static int
2565linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
2566{
2567
2568	switch (args->cmd) {
2569	case LINUX_SG_GET_VERSION_NUM:
2570		args->cmd = SG_GET_VERSION_NUM;
2571		break;
2572	case LINUX_SG_SET_TIMEOUT:
2573		args->cmd = SG_SET_TIMEOUT;
2574		break;
2575	case LINUX_SG_GET_TIMEOUT:
2576		args->cmd = SG_GET_TIMEOUT;
2577		break;
2578	case LINUX_SG_IO:
2579		args->cmd = SG_IO;
2580#ifdef COMPAT_LINUX32
2581		return (linux_ioctl_sg_io(td, args));
2582#endif
2583		break;
2584	case LINUX_SG_GET_RESERVED_SIZE:
2585		args->cmd = SG_GET_RESERVED_SIZE;
2586		break;
2587	case LINUX_SG_GET_SCSI_ID:
2588		args->cmd = SG_GET_SCSI_ID;
2589		break;
2590	case LINUX_SG_GET_SG_TABLESIZE:
2591		args->cmd = SG_GET_SG_TABLESIZE;
2592		break;
2593	default:
2594		return (ENODEV);
2595	}
2596	return (sys_ioctl(td, (struct ioctl_args *)args));
2597}
2598
2599/*
2600 * Video4Linux (V4L) ioctl handler
2601 */
2602static int
2603linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt)
2604{
2605	vt->tuner = lvt->tuner;
2606	strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2607	vt->rangelow = lvt->rangelow;	/* possible long size conversion */
2608	vt->rangehigh = lvt->rangehigh;	/* possible long size conversion */
2609	vt->flags = lvt->flags;
2610	vt->mode = lvt->mode;
2611	vt->signal = lvt->signal;
2612	return (0);
2613}
2614
2615static int
2616bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt)
2617{
2618	lvt->tuner = vt->tuner;
2619	strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2620	lvt->rangelow = vt->rangelow;	/* possible long size conversion */
2621	lvt->rangehigh = vt->rangehigh;	/* possible long size conversion */
2622	lvt->flags = vt->flags;
2623	lvt->mode = vt->mode;
2624	lvt->signal = vt->signal;
2625	return (0);
2626}
2627
2628#ifdef COMPAT_LINUX_V4L_CLIPLIST
2629static int
2630linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc)
2631{
2632	vc->x = lvc->x;
2633	vc->y = lvc->y;
2634	vc->width = lvc->width;
2635	vc->height = lvc->height;
2636	vc->next = PTRIN(lvc->next);	/* possible pointer size conversion */
2637	return (0);
2638}
2639#endif
2640
2641static int
2642linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw)
2643{
2644	vw->x = lvw->x;
2645	vw->y = lvw->y;
2646	vw->width = lvw->width;
2647	vw->height = lvw->height;
2648	vw->chromakey = lvw->chromakey;
2649	vw->flags = lvw->flags;
2650	vw->clips = PTRIN(lvw->clips);	/* possible pointer size conversion */
2651	vw->clipcount = lvw->clipcount;
2652	return (0);
2653}
2654
2655static int
2656bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw)
2657{
2658	memset(lvw, 0, sizeof(*lvw));
2659
2660	lvw->x = vw->x;
2661	lvw->y = vw->y;
2662	lvw->width = vw->width;
2663	lvw->height = vw->height;
2664	lvw->chromakey = vw->chromakey;
2665	lvw->flags = vw->flags;
2666	lvw->clips = PTROUT(vw->clips);	/* possible pointer size conversion */
2667	lvw->clipcount = vw->clipcount;
2668	return (0);
2669}
2670
2671static int
2672linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb)
2673{
2674	vb->base = PTRIN(lvb->base);	/* possible pointer size conversion */
2675	vb->height = lvb->height;
2676	vb->width = lvb->width;
2677	vb->depth = lvb->depth;
2678	vb->bytesperline = lvb->bytesperline;
2679	return (0);
2680}
2681
2682static int
2683bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb)
2684{
2685	lvb->base = PTROUT(vb->base);	/* possible pointer size conversion */
2686	lvb->height = vb->height;
2687	lvb->width = vb->width;
2688	lvb->depth = vb->depth;
2689	lvb->bytesperline = vb->bytesperline;
2690	return (0);
2691}
2692
2693static int
2694linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc)
2695{
2696	strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE);
2697	vc->datasize = lvc->datasize;
2698	vc->data = PTRIN(lvc->data);	/* possible pointer size conversion */
2699	return (0);
2700}
2701
2702#ifdef COMPAT_LINUX_V4L_CLIPLIST
2703static int
2704linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc)
2705{
2706	int error;
2707	struct video_clip vclip;
2708	struct l_video_clip l_vclip;
2709
2710	error = copyin(lvc, &l_vclip, sizeof(l_vclip));
2711	if (error) return (error);
2712	linux_to_bsd_v4l_clip(&l_vclip, &vclip);
2713	/* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */
2714	if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL)
2715		return (ENOMEM);    /* XXX: Linux has no ENOMEM here. */
2716	memcpy(*ppvc, &vclip, sizeof(vclip));
2717	(*ppvc)->next = NULL;
2718	return (0);
2719}
2720
2721static int
2722linux_v4l_cliplist_free(struct video_window *vw)
2723{
2724	struct video_clip **ppvc;
2725	struct video_clip **ppvc_next;
2726
2727	for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) {
2728		ppvc_next = &((*ppvc)->next);
2729		free(*ppvc, M_LINUX);
2730	}
2731	vw->clips = NULL;
2732
2733	return (0);
2734}
2735
2736static int
2737linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
2738{
2739	int error;
2740	int clipcount;
2741	void *plvc;
2742	struct video_clip **ppvc;
2743
2744	/*
2745	 * XXX: The cliplist is used to pass in a list of clipping
2746	 *	rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a
2747	 *	clipping bitmap.  Some Linux apps, however, appear to
2748	 *	leave cliplist and clips uninitialized.  In any case,
2749	 *	the cliplist is not used by pwc(4), at the time of
2750	 *	writing, FreeBSD's only V4L driver.  When a driver
2751	 *	that uses the cliplist is developed, this code may
2752	 *	need re-examiniation.
2753	 */
2754	error = 0;
2755	clipcount = vw->clipcount;
2756	if (clipcount == VIDEO_CLIP_BITMAP) {
2757		/*
2758		 * In this case, the pointer (clips) is overloaded
2759		 * to be a "void *" to a bitmap, therefore there
2760		 * is no struct video_clip to copy now.
2761		 */
2762	} else if (clipcount > 0 && clipcount <= 16384) {
2763		/*
2764		 * Clips points to list of clip rectangles, so
2765		 * copy the list.
2766		 *
2767		 * XXX: Upper limit of 16384 was used here to try to
2768		 *	avoid cases when clipcount and clips pointer
2769		 *	are uninitialized and therefore have high random
2770		 *	values, as is the case in the Linux Skype
2771		 *	application.  The value 16384 was chosen as that
2772		 *	is what is used in the Linux stradis(4) MPEG
2773		 *	decoder driver, the only place we found an
2774		 *	example of cliplist use.
2775		 */
2776		plvc = PTRIN(lvw->clips);
2777		vw->clips = NULL;
2778		ppvc = &(vw->clips);
2779		while (clipcount-- > 0) {
2780			if (plvc == NULL) {
2781				error = EFAULT;
2782				break;
2783			} else {
2784				error = linux_v4l_clip_copy(plvc, ppvc);
2785				if (error) {
2786					linux_v4l_cliplist_free(vw);
2787					break;
2788				}
2789			}
2790			ppvc = &((*ppvc)->next);
2791			plvc = PTRIN(((struct l_video_clip *) plvc)->next);
2792		}
2793	} else {
2794		/*
2795		 * clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP)
2796		 * Force cliplist to null.
2797		 */
2798		vw->clipcount = 0;
2799		vw->clips = NULL;
2800	}
2801	return (error);
2802}
2803#endif
2804
2805static int
2806linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
2807{
2808	struct file *fp;
2809	int error;
2810	struct video_tuner vtun;
2811	struct video_window vwin;
2812	struct video_buffer vbuf;
2813	struct video_code vcode;
2814	struct l_video_tuner l_vtun;
2815	struct l_video_window l_vwin;
2816	struct l_video_buffer l_vbuf;
2817	struct l_video_code l_vcode;
2818
2819	switch (args->cmd & 0xffff) {
2820	case LINUX_VIDIOCGCAP:		args->cmd = VIDIOCGCAP; break;
2821	case LINUX_VIDIOCGCHAN:		args->cmd = VIDIOCGCHAN; break;
2822	case LINUX_VIDIOCSCHAN:		args->cmd = VIDIOCSCHAN; break;
2823
2824	case LINUX_VIDIOCGTUNER:
2825		error = fget(td, args->fd,
2826		    &cap_ioctl_rights, &fp);
2827		if (error != 0)
2828			return (error);
2829		error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2830		if (error) {
2831			fdrop(fp, td);
2832			return (error);
2833		}
2834		linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2835		error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td);
2836		if (!error) {
2837			bsd_to_linux_v4l_tuner(&vtun, &l_vtun);
2838			error = copyout(&l_vtun, (void *) args->arg,
2839			    sizeof(l_vtun));
2840		}
2841		fdrop(fp, td);
2842		return (error);
2843
2844	case LINUX_VIDIOCSTUNER:
2845		error = fget(td, args->fd,
2846		    &cap_ioctl_rights, &fp);
2847		if (error != 0)
2848			return (error);
2849		error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2850		if (error) {
2851			fdrop(fp, td);
2852			return (error);
2853		}
2854		linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2855		error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td);
2856		fdrop(fp, td);
2857		return (error);
2858
2859	case LINUX_VIDIOCGPICT:		args->cmd = VIDIOCGPICT; break;
2860	case LINUX_VIDIOCSPICT:		args->cmd = VIDIOCSPICT; break;
2861	case LINUX_VIDIOCCAPTURE:	args->cmd = VIDIOCCAPTURE; break;
2862
2863	case LINUX_VIDIOCGWIN:
2864		error = fget(td, args->fd,
2865		    &cap_ioctl_rights, &fp);
2866		if (error != 0)
2867			return (error);
2868		error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
2869		if (!error) {
2870			bsd_to_linux_v4l_window(&vwin, &l_vwin);
2871			error = copyout(&l_vwin, (void *) args->arg,
2872			    sizeof(l_vwin));
2873		}
2874		fdrop(fp, td);
2875		return (error);
2876
2877	case LINUX_VIDIOCSWIN:
2878		error = fget(td, args->fd,
2879		    &cap_ioctl_rights, &fp);
2880		if (error != 0)
2881			return (error);
2882		error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
2883		if (error) {
2884			fdrop(fp, td);
2885			return (error);
2886		}
2887		linux_to_bsd_v4l_window(&l_vwin, &vwin);
2888#ifdef COMPAT_LINUX_V4L_CLIPLIST
2889		error = linux_v4l_cliplist_copy(&l_vwin, &vwin);
2890		if (error) {
2891			fdrop(fp, td);
2892			return (error);
2893		}
2894#endif
2895		error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td);
2896		fdrop(fp, td);
2897#ifdef COMPAT_LINUX_V4L_CLIPLIST
2898		linux_v4l_cliplist_free(&vwin);
2899#endif
2900		return (error);
2901
2902	case LINUX_VIDIOCGFBUF:
2903		error = fget(td, args->fd,
2904		    &cap_ioctl_rights, &fp);
2905		if (error != 0)
2906			return (error);
2907		error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
2908		if (!error) {
2909			bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf);
2910			error = copyout(&l_vbuf, (void *) args->arg,
2911			    sizeof(l_vbuf));
2912		}
2913		fdrop(fp, td);
2914		return (error);
2915
2916	case LINUX_VIDIOCSFBUF:
2917		error = fget(td, args->fd,
2918		    &cap_ioctl_rights, &fp);
2919		if (error != 0)
2920			return (error);
2921		error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
2922		if (error) {
2923			fdrop(fp, td);
2924			return (error);
2925		}
2926		linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf);
2927		error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td);
2928		fdrop(fp, td);
2929		return (error);
2930
2931	case LINUX_VIDIOCKEY:		args->cmd = VIDIOCKEY; break;
2932	case LINUX_VIDIOCGFREQ:		args->cmd = VIDIOCGFREQ; break;
2933	case LINUX_VIDIOCSFREQ:		args->cmd = VIDIOCSFREQ; break;
2934	case LINUX_VIDIOCGAUDIO:	args->cmd = VIDIOCGAUDIO; break;
2935	case LINUX_VIDIOCSAUDIO:	args->cmd = VIDIOCSAUDIO; break;
2936	case LINUX_VIDIOCSYNC:		args->cmd = VIDIOCSYNC; break;
2937	case LINUX_VIDIOCMCAPTURE:	args->cmd = VIDIOCMCAPTURE; break;
2938	case LINUX_VIDIOCGMBUF:		args->cmd = VIDIOCGMBUF; break;
2939	case LINUX_VIDIOCGUNIT:		args->cmd = VIDIOCGUNIT; break;
2940	case LINUX_VIDIOCGCAPTURE:	args->cmd = VIDIOCGCAPTURE; break;
2941	case LINUX_VIDIOCSCAPTURE:	args->cmd = VIDIOCSCAPTURE; break;
2942	case LINUX_VIDIOCSPLAYMODE:	args->cmd = VIDIOCSPLAYMODE; break;
2943	case LINUX_VIDIOCSWRITEMODE:	args->cmd = VIDIOCSWRITEMODE; break;
2944	case LINUX_VIDIOCGPLAYINFO:	args->cmd = VIDIOCGPLAYINFO; break;
2945
2946	case LINUX_VIDIOCSMICROCODE:
2947		error = fget(td, args->fd,
2948		    &cap_ioctl_rights, &fp);
2949		if (error != 0)
2950			return (error);
2951		error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
2952		if (error) {
2953			fdrop(fp, td);
2954			return (error);
2955		}
2956		linux_to_bsd_v4l_code(&l_vcode, &vcode);
2957		error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td);
2958		fdrop(fp, td);
2959		return (error);
2960
2961	case LINUX_VIDIOCGVBIFMT:	args->cmd = VIDIOCGVBIFMT; break;
2962	case LINUX_VIDIOCSVBIFMT:	args->cmd = VIDIOCSVBIFMT; break;
2963	default:			return (ENOIOCTL);
2964	}
2965
2966	error = sys_ioctl(td, (struct ioctl_args *)args);
2967	return (error);
2968}
2969
2970/*
2971 * Special ioctl handler
2972 */
2973static int
2974linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
2975{
2976	int error;
2977
2978	switch (args->cmd) {
2979	case LINUX_SIOCGIFADDR:
2980		args->cmd = SIOCGIFADDR;
2981		error = sys_ioctl(td, (struct ioctl_args *)args);
2982		break;
2983	case LINUX_SIOCSIFADDR:
2984		args->cmd = SIOCSIFADDR;
2985		error = sys_ioctl(td, (struct ioctl_args *)args);
2986		break;
2987	case LINUX_SIOCGIFFLAGS:
2988		args->cmd = SIOCGIFFLAGS;
2989		error = sys_ioctl(td, (struct ioctl_args *)args);
2990		break;
2991	default:
2992		error = ENOIOCTL;
2993	}
2994
2995	return (error);
2996}
2997
2998static int
2999linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd)
3000{
3001	vstd->index = lvstd->index;
3002	vstd->id = lvstd->id;
3003	CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
3004	memcpy(vstd->name, lvstd->name, sizeof(vstd->name));
3005	vstd->frameperiod = lvstd->frameperiod;
3006	vstd->framelines = lvstd->framelines;
3007	CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
3008	memcpy(vstd->reserved, lvstd->reserved, sizeof(vstd->reserved));
3009	return (0);
3010}
3011
3012static int
3013bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd)
3014{
3015	lvstd->index = vstd->index;
3016	lvstd->id = vstd->id;
3017	CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
3018	memcpy(lvstd->name, vstd->name, sizeof(lvstd->name));
3019	lvstd->frameperiod = vstd->frameperiod;
3020	lvstd->framelines = vstd->framelines;
3021	CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
3022	memcpy(lvstd->reserved, vstd->reserved, sizeof(lvstd->reserved));
3023	return (0);
3024}
3025
3026static int
3027linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb)
3028{
3029	vb->index = lvb->index;
3030	vb->type = lvb->type;
3031	vb->bytesused = lvb->bytesused;
3032	vb->flags = lvb->flags;
3033	vb->field = lvb->field;
3034	vb->timestamp.tv_sec = lvb->timestamp.tv_sec;
3035	vb->timestamp.tv_usec = lvb->timestamp.tv_usec;
3036	memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode));
3037	vb->sequence = lvb->sequence;
3038	vb->memory = lvb->memory;
3039	if (lvb->memory == V4L2_MEMORY_USERPTR)
3040		/* possible pointer size conversion */
3041		vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr);
3042	else
3043		vb->m.offset = lvb->m.offset;
3044	vb->length = lvb->length;
3045	vb->input = lvb->input;
3046	vb->reserved = lvb->reserved;
3047	return (0);
3048}
3049
3050static int
3051bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb)
3052{
3053	lvb->index = vb->index;
3054	lvb->type = vb->type;
3055	lvb->bytesused = vb->bytesused;
3056	lvb->flags = vb->flags;
3057	lvb->field = vb->field;
3058	lvb->timestamp.tv_sec = vb->timestamp.tv_sec;
3059	lvb->timestamp.tv_usec = vb->timestamp.tv_usec;
3060	memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode));
3061	lvb->sequence = vb->sequence;
3062	lvb->memory = vb->memory;
3063	if (vb->memory == V4L2_MEMORY_USERPTR)
3064		/* possible pointer size conversion */
3065		lvb->m.userptr = PTROUT(vb->m.userptr);
3066	else
3067		lvb->m.offset = vb->m.offset;
3068	lvb->length = vb->length;
3069	lvb->input = vb->input;
3070	lvb->reserved = vb->reserved;
3071	return (0);
3072}
3073
3074static int
3075linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf)
3076{
3077	vf->type = lvf->type;
3078	if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
3079#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3080	    || lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3081#endif
3082	    )
3083		/*
3084		 * XXX TODO - needs 32 -> 64 bit conversion:
3085		 * (unused by webcams?)
3086		 */
3087		return (EINVAL);
3088	memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt));
3089	return (0);
3090}
3091
3092static int
3093bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf)
3094{
3095	lvf->type = vf->type;
3096	if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
3097#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3098	    || vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3099#endif
3100	    )
3101		/*
3102		 * XXX TODO - needs 32 -> 64 bit conversion:
3103		 * (unused by webcams?)
3104		 */
3105		return (EINVAL);
3106	memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt));
3107	return (0);
3108}
3109static int
3110linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
3111{
3112	struct file *fp;
3113	int error;
3114	struct v4l2_format vformat;
3115	struct l_v4l2_format l_vformat;
3116	struct v4l2_standard vstd;
3117	struct l_v4l2_standard l_vstd;
3118	struct l_v4l2_buffer l_vbuf;
3119	struct v4l2_buffer vbuf;
3120	struct v4l2_input vinp;
3121
3122	switch (args->cmd & 0xffff) {
3123	case LINUX_VIDIOC_RESERVED:
3124	case LINUX_VIDIOC_LOG_STATUS:
3125		if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID)
3126			return (ENOIOCTL);
3127		args->cmd = (args->cmd & 0xffff) | IOC_VOID;
3128		break;
3129
3130	case LINUX_VIDIOC_OVERLAY:
3131	case LINUX_VIDIOC_STREAMON:
3132	case LINUX_VIDIOC_STREAMOFF:
3133	case LINUX_VIDIOC_S_STD:
3134	case LINUX_VIDIOC_S_TUNER:
3135	case LINUX_VIDIOC_S_AUDIO:
3136	case LINUX_VIDIOC_S_AUDOUT:
3137	case LINUX_VIDIOC_S_MODULATOR:
3138	case LINUX_VIDIOC_S_FREQUENCY:
3139	case LINUX_VIDIOC_S_CROP:
3140	case LINUX_VIDIOC_S_JPEGCOMP:
3141	case LINUX_VIDIOC_S_PRIORITY:
3142	case LINUX_VIDIOC_DBG_S_REGISTER:
3143	case LINUX_VIDIOC_S_HW_FREQ_SEEK:
3144	case LINUX_VIDIOC_SUBSCRIBE_EVENT:
3145	case LINUX_VIDIOC_UNSUBSCRIBE_EVENT:
3146		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN;
3147		break;
3148
3149	case LINUX_VIDIOC_QUERYCAP:
3150	case LINUX_VIDIOC_G_STD:
3151	case LINUX_VIDIOC_G_AUDIO:
3152	case LINUX_VIDIOC_G_INPUT:
3153	case LINUX_VIDIOC_G_OUTPUT:
3154	case LINUX_VIDIOC_G_AUDOUT:
3155	case LINUX_VIDIOC_G_JPEGCOMP:
3156	case LINUX_VIDIOC_QUERYSTD:
3157	case LINUX_VIDIOC_G_PRIORITY:
3158	case LINUX_VIDIOC_QUERY_DV_PRESET:
3159		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT;
3160		break;
3161
3162	case LINUX_VIDIOC_ENUM_FMT:
3163	case LINUX_VIDIOC_REQBUFS:
3164	case LINUX_VIDIOC_G_PARM:
3165	case LINUX_VIDIOC_S_PARM:
3166	case LINUX_VIDIOC_G_CTRL:
3167	case LINUX_VIDIOC_S_CTRL:
3168	case LINUX_VIDIOC_G_TUNER:
3169	case LINUX_VIDIOC_QUERYCTRL:
3170	case LINUX_VIDIOC_QUERYMENU:
3171	case LINUX_VIDIOC_S_INPUT:
3172	case LINUX_VIDIOC_S_OUTPUT:
3173	case LINUX_VIDIOC_ENUMOUTPUT:
3174	case LINUX_VIDIOC_G_MODULATOR:
3175	case LINUX_VIDIOC_G_FREQUENCY:
3176	case LINUX_VIDIOC_CROPCAP:
3177	case LINUX_VIDIOC_G_CROP:
3178	case LINUX_VIDIOC_ENUMAUDIO:
3179	case LINUX_VIDIOC_ENUMAUDOUT:
3180	case LINUX_VIDIOC_G_SLICED_VBI_CAP:
3181#ifdef VIDIOC_ENUM_FRAMESIZES
3182	case LINUX_VIDIOC_ENUM_FRAMESIZES:
3183	case LINUX_VIDIOC_ENUM_FRAMEINTERVALS:
3184	case LINUX_VIDIOC_ENCODER_CMD:
3185	case LINUX_VIDIOC_TRY_ENCODER_CMD:
3186#endif
3187	case LINUX_VIDIOC_DBG_G_REGISTER:
3188	case LINUX_VIDIOC_DBG_G_CHIP_IDENT:
3189	case LINUX_VIDIOC_ENUM_DV_PRESETS:
3190	case LINUX_VIDIOC_S_DV_PRESET:
3191	case LINUX_VIDIOC_G_DV_PRESET:
3192	case LINUX_VIDIOC_S_DV_TIMINGS:
3193	case LINUX_VIDIOC_G_DV_TIMINGS:
3194		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
3195		break;
3196
3197	case LINUX_VIDIOC_G_FMT:
3198	case LINUX_VIDIOC_S_FMT:
3199	case LINUX_VIDIOC_TRY_FMT:
3200		error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat));
3201		if (error)
3202			return (error);
3203		error = fget(td, args->fd,
3204		    &cap_ioctl_rights, &fp);
3205		if (error)
3206			return (error);
3207		if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0)
3208			error = EINVAL;
3209		else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT)
3210			error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat,
3211			    td->td_ucred, td);
3212		else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT)
3213			error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat,
3214			    td->td_ucred, td);
3215		else
3216			error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat,
3217			    td->td_ucred, td);
3218		bsd_to_linux_v4l2_format(&vformat, &l_vformat);
3219		if (error == 0)
3220			error = copyout(&l_vformat, (void *)args->arg,
3221			    sizeof(l_vformat));
3222		fdrop(fp, td);
3223		return (error);
3224
3225	case LINUX_VIDIOC_ENUMSTD:
3226		error = copyin((void *)args->arg, &l_vstd, sizeof(l_vstd));
3227		if (error)
3228			return (error);
3229		linux_to_bsd_v4l2_standard(&l_vstd, &vstd);
3230		error = fget(td, args->fd,
3231		    &cap_ioctl_rights, &fp);
3232		if (error)
3233			return (error);
3234		error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd,
3235		    td->td_ucred, td);
3236		if (error) {
3237			fdrop(fp, td);
3238			return (error);
3239		}
3240		bsd_to_linux_v4l2_standard(&vstd, &l_vstd);
3241		error = copyout(&l_vstd, (void *)args->arg, sizeof(l_vstd));
3242		fdrop(fp, td);
3243		return (error);
3244
3245	case LINUX_VIDIOC_ENUMINPUT:
3246		/*
3247		 * The Linux struct l_v4l2_input differs only in size,
3248		 * it has no padding at the end.
3249		 */
3250		error = copyin((void *)args->arg, &vinp,
3251				sizeof(struct l_v4l2_input));
3252		if (error != 0)
3253			return (error);
3254		error = fget(td, args->fd,
3255		    &cap_ioctl_rights, &fp);
3256		if (error != 0)
3257			return (error);
3258		error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp,
3259		    td->td_ucred, td);
3260		if (error) {
3261			fdrop(fp, td);
3262			return (error);
3263		}
3264		error = copyout(&vinp, (void *)args->arg,
3265				sizeof(struct l_v4l2_input));
3266		fdrop(fp, td);
3267		return (error);
3268
3269	case LINUX_VIDIOC_QUERYBUF:
3270	case LINUX_VIDIOC_QBUF:
3271	case LINUX_VIDIOC_DQBUF:
3272		error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf));
3273		if (error)
3274			return (error);
3275		error = fget(td, args->fd,
3276		    &cap_ioctl_rights, &fp);
3277		if (error)
3278			return (error);
3279		linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf);
3280		if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF)
3281			error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf,
3282			    td->td_ucred, td);
3283		else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF)
3284			error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf,
3285			    td->td_ucred, td);
3286		else
3287			error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf,
3288			    td->td_ucred, td);
3289		bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf);
3290		if (error == 0)
3291			error = copyout(&l_vbuf, (void *)args->arg,
3292			    sizeof(l_vbuf));
3293		fdrop(fp, td);
3294		return (error);
3295
3296	/*
3297	 * XXX TODO - these need 32 -> 64 bit conversion:
3298	 * (are any of them needed for webcams?)
3299	 */
3300	case LINUX_VIDIOC_G_FBUF:
3301	case LINUX_VIDIOC_S_FBUF:
3302
3303	case LINUX_VIDIOC_G_EXT_CTRLS:
3304	case LINUX_VIDIOC_S_EXT_CTRLS:
3305	case LINUX_VIDIOC_TRY_EXT_CTRLS:
3306
3307	case LINUX_VIDIOC_DQEVENT:
3308
3309	default:			return (ENOIOCTL);
3310	}
3311
3312	error = sys_ioctl(td, (struct ioctl_args *)args);
3313	return (error);
3314}
3315
3316/*
3317 * Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros
3318 * instead of USB* ones. This lets us to provide correct values for cmd.
3319 * 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone.
3320 */
3321static int
3322linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args)
3323{
3324	int error;
3325
3326	error = 0;
3327	switch (args->cmd) {
3328	case FBSD_LUSB_DEVICEENUMERATE:
3329		args->cmd = USB_DEVICEENUMERATE;
3330		break;
3331	case FBSD_LUSB_DEV_QUIRK_ADD:
3332		args->cmd = USB_DEV_QUIRK_ADD;
3333		break;
3334	case FBSD_LUSB_DEV_QUIRK_GET:
3335		args->cmd = USB_DEV_QUIRK_GET;
3336		break;
3337	case FBSD_LUSB_DEV_QUIRK_REMOVE:
3338		args->cmd = USB_DEV_QUIRK_REMOVE;
3339		break;
3340	case FBSD_LUSB_DO_REQUEST:
3341		args->cmd = USB_DO_REQUEST;
3342		break;
3343	case FBSD_LUSB_FS_CLEAR_STALL_SYNC:
3344		args->cmd = USB_FS_CLEAR_STALL_SYNC;
3345		break;
3346	case FBSD_LUSB_FS_CLOSE:
3347		args->cmd = USB_FS_CLOSE;
3348		break;
3349	case FBSD_LUSB_FS_COMPLETE:
3350		args->cmd = USB_FS_COMPLETE;
3351		break;
3352	case FBSD_LUSB_FS_INIT:
3353		args->cmd = USB_FS_INIT;
3354		break;
3355	case FBSD_LUSB_FS_OPEN:
3356		args->cmd = USB_FS_OPEN;
3357		break;
3358	case FBSD_LUSB_FS_START:
3359		args->cmd = USB_FS_START;
3360		break;
3361	case FBSD_LUSB_FS_STOP:
3362		args->cmd = USB_FS_STOP;
3363		break;
3364	case FBSD_LUSB_FS_UNINIT:
3365		args->cmd = USB_FS_UNINIT;
3366		break;
3367	case FBSD_LUSB_GET_CONFIG:
3368		args->cmd = USB_GET_CONFIG;
3369		break;
3370	case FBSD_LUSB_GET_DEVICEINFO:
3371		args->cmd = USB_GET_DEVICEINFO;
3372		break;
3373	case FBSD_LUSB_GET_DEVICE_DESC:
3374		args->cmd = USB_GET_DEVICE_DESC;
3375		break;
3376	case FBSD_LUSB_GET_FULL_DESC:
3377		args->cmd = USB_GET_FULL_DESC;
3378		break;
3379	case FBSD_LUSB_GET_IFACE_DRIVER:
3380		args->cmd = USB_GET_IFACE_DRIVER;
3381		break;
3382	case FBSD_LUSB_GET_PLUGTIME:
3383		args->cmd = USB_GET_PLUGTIME;
3384		break;
3385	case FBSD_LUSB_GET_POWER_MODE:
3386		args->cmd = USB_GET_POWER_MODE;
3387		break;
3388	case FBSD_LUSB_GET_REPORT_DESC:
3389		args->cmd = USB_GET_REPORT_DESC;
3390		break;
3391	case FBSD_LUSB_GET_REPORT_ID:
3392		args->cmd = USB_GET_REPORT_ID;
3393		break;
3394	case FBSD_LUSB_GET_TEMPLATE:
3395		args->cmd = USB_GET_TEMPLATE;
3396		break;
3397	case FBSD_LUSB_IFACE_DRIVER_ACTIVE:
3398		args->cmd = USB_IFACE_DRIVER_ACTIVE;
3399		break;
3400	case FBSD_LUSB_IFACE_DRIVER_DETACH:
3401		args->cmd = USB_IFACE_DRIVER_DETACH;
3402		break;
3403	case FBSD_LUSB_QUIRK_NAME_GET:
3404		args->cmd = USB_QUIRK_NAME_GET;
3405		break;
3406	case FBSD_LUSB_READ_DIR:
3407		args->cmd = USB_READ_DIR;
3408		break;
3409	case FBSD_LUSB_SET_ALTINTERFACE:
3410		args->cmd = USB_SET_ALTINTERFACE;
3411		break;
3412	case FBSD_LUSB_SET_CONFIG:
3413		args->cmd = USB_SET_CONFIG;
3414		break;
3415	case FBSD_LUSB_SET_IMMED:
3416		args->cmd = USB_SET_IMMED;
3417		break;
3418	case FBSD_LUSB_SET_POWER_MODE:
3419		args->cmd = USB_SET_POWER_MODE;
3420		break;
3421	case FBSD_LUSB_SET_TEMPLATE:
3422		args->cmd = USB_SET_TEMPLATE;
3423		break;
3424	case FBSD_LUSB_FS_OPEN_STREAM:
3425		args->cmd = USB_FS_OPEN_STREAM;
3426		break;
3427	case FBSD_LUSB_GET_DEV_PORT_PATH:
3428		args->cmd = USB_GET_DEV_PORT_PATH;
3429		break;
3430	case FBSD_LUSB_GET_POWER_USAGE:
3431		args->cmd = USB_GET_POWER_USAGE;
3432		break;
3433	case FBSD_LUSB_DEVICESTATS:
3434		args->cmd = USB_DEVICESTATS;
3435		break;
3436	default:
3437		error = ENOIOCTL;
3438	}
3439	if (error != ENOIOCTL)
3440		error = sys_ioctl(td, (struct ioctl_args *)args);
3441	return (error);
3442}
3443
3444/*
3445 * Some evdev ioctls must be translated.
3446 *  - EVIOCGMTSLOTS is a IOC_READ ioctl on Linux although it has input data
3447 *    (must be IOC_INOUT on FreeBSD).
3448 *  - On Linux, EVIOCGRAB, EVIOCREVOKE and EVIOCRMFF are defined as _IOW with
3449 *    an int argument. You don't pass an int pointer to the ioctl(), however,
3450 *    but just the int directly. On FreeBSD, they are defined as _IOWINT for
3451 *    this to work.
3452 */
3453static int
3454linux_ioctl_evdev(struct thread *td, struct linux_ioctl_args *args)
3455{
3456	struct file *fp;
3457	clockid_t clock;
3458	int error;
3459
3460	args->cmd = SETDIR(args->cmd);
3461
3462	switch (args->cmd) {
3463	case (EVIOCGRAB & ~IOC_DIRMASK) | IOC_IN:
3464		args->cmd = EVIOCGRAB;
3465		break;
3466	case (EVIOCREVOKE & ~IOC_DIRMASK) | IOC_IN:
3467		args->cmd = EVIOCREVOKE;
3468		break;
3469	case (EVIOCRMFF & ~IOC_DIRMASK) | IOC_IN:
3470		args->cmd = EVIOCRMFF;
3471		break;
3472	case EVIOCSCLOCKID: {
3473		error = copyin(PTRIN(args->arg), &clock, sizeof(clock));
3474		if (error != 0)
3475			return (error);
3476		if (clock & ~(LINUX_IOCTL_EVDEV_CLK))
3477			return (EINVAL);
3478		error = linux_to_native_clockid(&clock, clock);
3479		if (error != 0)
3480			return (error);
3481
3482		error = fget(td, args->fd,
3483		    &cap_ioctl_rights, &fp);
3484		if (error != 0)
3485			return (error);
3486
3487		error = fo_ioctl(fp, EVIOCSCLOCKID, &clock, td->td_ucred, td);
3488		fdrop(fp, td);
3489		return (error);
3490	}
3491	default:
3492		break;
3493	}
3494
3495	if (IOCBASECMD(args->cmd) ==
3496	    ((EVIOCGMTSLOTS(0) & ~IOC_DIRMASK) | IOC_OUT))
3497		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
3498
3499	return (sys_ioctl(td, (struct ioctl_args *)args));
3500}
3501
3502static int
3503linux_ioctl_kcov(struct thread *td, struct linux_ioctl_args *args)
3504{
3505	int error;
3506
3507	error = 0;
3508	switch (args->cmd & 0xffff) {
3509	case LINUX_KCOV_INIT_TRACE:
3510		args->cmd = KIOSETBUFSIZE;
3511		break;
3512	case LINUX_KCOV_ENABLE:
3513		args->cmd = KIOENABLE;
3514		if (args->arg == 0)
3515			args->arg = KCOV_MODE_TRACE_PC;
3516		else if (args->arg == 1)
3517			args->arg = KCOV_MODE_TRACE_CMP;
3518		else
3519			error = EINVAL;
3520		break;
3521	case LINUX_KCOV_DISABLE:
3522		args->cmd = KIODISABLE;
3523		break;
3524	default:
3525		error = ENOTTY;
3526		break;
3527	}
3528
3529	if (error == 0)
3530		error = sys_ioctl(td, (struct ioctl_args *)args);
3531	return (error);
3532}
3533
3534/*
3535 * main ioctl syscall function
3536 */
3537
3538static int
3539linux_ioctl_fallback(struct thread *td, struct linux_ioctl_args *args)
3540{
3541	struct file *fp;
3542	struct linux_ioctl_handler_element *he;
3543	int error, cmd;
3544
3545	error = fget(td, args->fd, &cap_ioctl_rights, &fp);
3546	if (error != 0)
3547		return (error);
3548	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
3549		fdrop(fp, td);
3550		return (EBADF);
3551	}
3552
3553	/* Iterate over the ioctl handlers */
3554	cmd = args->cmd & 0xffff;
3555	sx_slock(&linux_ioctl_sx);
3556	mtx_lock(&Giant);
3557#ifdef COMPAT_LINUX32
3558	TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
3559		if (cmd >= he->low && cmd <= he->high) {
3560			error = (*he->func)(td, args);
3561			if (error != ENOIOCTL) {
3562				mtx_unlock(&Giant);
3563				sx_sunlock(&linux_ioctl_sx);
3564				fdrop(fp, td);
3565				return (error);
3566			}
3567		}
3568	}
3569#endif
3570	TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
3571		if (cmd >= he->low && cmd <= he->high) {
3572			error = (*he->func)(td, args);
3573			if (error != ENOIOCTL) {
3574				mtx_unlock(&Giant);
3575				sx_sunlock(&linux_ioctl_sx);
3576				fdrop(fp, td);
3577				return (error);
3578			}
3579		}
3580	}
3581	mtx_unlock(&Giant);
3582	sx_sunlock(&linux_ioctl_sx);
3583	fdrop(fp, td);
3584
3585	switch (args->cmd & 0xffff) {
3586	case LINUX_BTRFS_IOC_CLONE:
3587	case LINUX_F2FS_IOC_GET_FEATURES:
3588	case LINUX_FS_IOC_FIEMAP:
3589		return (ENOTSUP);
3590
3591	default:
3592		linux_msg(td, "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented",
3593		    __func__, args->fd, args->cmd,
3594		    (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
3595		break;
3596	}
3597
3598	return (EINVAL);
3599}
3600
3601int
3602linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
3603{
3604	struct linux_ioctl_handler *handler;
3605	int error, cmd, i;
3606
3607	cmd = args->cmd & 0xffff;
3608
3609	/*
3610	 * array of ioctls known at compilation time. Elides a lot of work on
3611	 * each call compared to the list variant. Everything frequently used
3612	 * should be moved here.
3613	 *
3614	 * Arguably the magic creating the list should create an array instead.
3615	 *
3616	 * For now just a linear scan.
3617	 */
3618	for (i = 0; i < nitems(linux_ioctls); i++) {
3619		handler = &linux_ioctls[i];
3620		if (cmd >= handler->low && cmd <= handler->high) {
3621			error = (*handler->func)(td, args);
3622			if (error != ENOIOCTL) {
3623				return (error);
3624			}
3625		}
3626	}
3627	return (linux_ioctl_fallback(td, args));
3628}
3629
3630int
3631linux_ioctl_register_handler(struct linux_ioctl_handler *h)
3632{
3633	struct linux_ioctl_handler_element *he, *cur;
3634
3635	if (h == NULL || h->func == NULL)
3636		return (EINVAL);
3637
3638	/*
3639	 * Reuse the element if the handler is already on the list, otherwise
3640	 * create a new element.
3641	 */
3642	sx_xlock(&linux_ioctl_sx);
3643	TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
3644		if (he->func == h->func)
3645			break;
3646	}
3647	if (he == NULL) {
3648		he = malloc(sizeof(*he),
3649		    M_LINUX, M_WAITOK);
3650		he->func = h->func;
3651	} else
3652		TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
3653
3654	/* Initialize range information. */
3655	he->low = h->low;
3656	he->high = h->high;
3657	he->span = h->high - h->low + 1;
3658
3659	/* Add the element to the list, sorted on span. */
3660	TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) {
3661		if (cur->span > he->span) {
3662			TAILQ_INSERT_BEFORE(cur, he, list);
3663			sx_xunlock(&linux_ioctl_sx);
3664			return (0);
3665		}
3666	}
3667	TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list);
3668	sx_xunlock(&linux_ioctl_sx);
3669
3670	return (0);
3671}
3672
3673int
3674linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
3675{
3676	struct linux_ioctl_handler_element *he;
3677
3678	if (h == NULL || h->func == NULL)
3679		return (EINVAL);
3680
3681	sx_xlock(&linux_ioctl_sx);
3682	TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
3683		if (he->func == h->func) {
3684			TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
3685			sx_xunlock(&linux_ioctl_sx);
3686			free(he, M_LINUX);
3687			return (0);
3688		}
3689	}
3690	sx_xunlock(&linux_ioctl_sx);
3691
3692	return (EINVAL);
3693}
3694
3695#ifdef COMPAT_LINUX32
3696int
3697linux32_ioctl_register_handler(struct linux_ioctl_handler *h)
3698{
3699	struct linux_ioctl_handler_element *he, *cur;
3700
3701	if (h == NULL || h->func == NULL)
3702		return (EINVAL);
3703
3704	/*
3705	 * Reuse the element if the handler is already on the list, otherwise
3706	 * create a new element.
3707	 */
3708	sx_xlock(&linux_ioctl_sx);
3709	TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
3710		if (he->func == h->func)
3711			break;
3712	}
3713	if (he == NULL) {
3714		he = malloc(sizeof(*he), M_LINUX, M_WAITOK);
3715		he->func = h->func;
3716	} else
3717		TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
3718
3719	/* Initialize range information. */
3720	he->low = h->low;
3721	he->high = h->high;
3722	he->span = h->high - h->low + 1;
3723
3724	/* Add the element to the list, sorted on span. */
3725	TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) {
3726		if (cur->span > he->span) {
3727			TAILQ_INSERT_BEFORE(cur, he, list);
3728			sx_xunlock(&linux_ioctl_sx);
3729			return (0);
3730		}
3731	}
3732	TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list);
3733	sx_xunlock(&linux_ioctl_sx);
3734
3735	return (0);
3736}
3737
3738int
3739linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h)
3740{
3741	struct linux_ioctl_handler_element *he;
3742
3743	if (h == NULL || h->func == NULL)
3744		return (EINVAL);
3745
3746	sx_xlock(&linux_ioctl_sx);
3747	TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
3748		if (he->func == h->func) {
3749			TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
3750			sx_xunlock(&linux_ioctl_sx);
3751			free(he, M_LINUX);
3752			return (0);
3753		}
3754	}
3755	sx_xunlock(&linux_ioctl_sx);
3756
3757	return (EINVAL);
3758}
3759#endif
3760