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