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