1 /* 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/sysproto.h> 34 #include <sys/cdio.h> 35 #include <sys/consio.h> 36 #include <sys/ctype.h> 37 #include <sys/disklabel.h> 38 #include <sys/fcntl.h> 39 #include <sys/file.h> 40 #include <sys/filedesc.h> 41 #include <sys/filio.h> 42 #include <sys/kbio.h> 43 #include <sys/linker_set.h> 44 #include <sys/malloc.h> 45 #include <sys/proc.h> 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <sys/soundcard.h> 49 #include <sys/tty.h> 50 #include <sys/uio.h> 51 #include <net/if.h> 52 #include <net/if_dl.h> 53 #include <net/if_types.h> 54 55 #include <machine/../linux/linux.h> 56 #include <machine/../linux/linux_proto.h> 57 58 #include <compat/linux/linux_ioctl.h> 59 #include <compat/linux/linux_mib.h> 60 #include <compat/linux/linux_util.h> 61 62 static linux_ioctl_function_t linux_ioctl_cdrom; 63 static linux_ioctl_function_t linux_ioctl_console; 64 static linux_ioctl_function_t linux_ioctl_disk; 65 static linux_ioctl_function_t linux_ioctl_socket; 66 static linux_ioctl_function_t linux_ioctl_sound; 67 static linux_ioctl_function_t linux_ioctl_termio; 68 static linux_ioctl_function_t linux_ioctl_private; 69 70 static struct linux_ioctl_handler cdrom_handler = 71 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX }; 72 static struct linux_ioctl_handler console_handler = 73 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX }; 74 static struct linux_ioctl_handler disk_handler = 75 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX }; 76 static struct linux_ioctl_handler socket_handler = 77 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX }; 78 static struct linux_ioctl_handler sound_handler = 79 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX }; 80 static struct linux_ioctl_handler termio_handler = 81 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX }; 82 static struct linux_ioctl_handler private_handler = 83 { linux_ioctl_private, LINUX_IOCTL_PRIVATE_MIN, LINUX_IOCTL_PRIVATE_MAX }; 84 85 DATA_SET(linux_ioctl_handler_set, cdrom_handler); 86 DATA_SET(linux_ioctl_handler_set, console_handler); 87 DATA_SET(linux_ioctl_handler_set, disk_handler); 88 DATA_SET(linux_ioctl_handler_set, socket_handler); 89 DATA_SET(linux_ioctl_handler_set, sound_handler); 90 DATA_SET(linux_ioctl_handler_set, termio_handler); 91 DATA_SET(linux_ioctl_handler_set, private_handler); 92 93 struct handler_element 94 { 95 TAILQ_ENTRY(handler_element) list; 96 int (*func)(struct thread *, struct linux_ioctl_args *); 97 int low, high, span; 98 }; 99 100 static TAILQ_HEAD(, handler_element) handlers = 101 TAILQ_HEAD_INITIALIZER(handlers); 102 103 static int 104 linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args) 105 { 106 struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd]; 107 int error; 108 struct disklabel dl; 109 110 switch (args->cmd & 0xffff) { 111 case LINUX_BLKGETSIZE: 112 error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, td); 113 if (error) 114 return (error); 115 return (copyout(&(dl.d_secperunit), (caddr_t)args->arg, 116 sizeof(dl.d_secperunit))); 117 break; 118 } 119 return (ENOIOCTL); 120 } 121 122 /* 123 * termio related ioctls 124 */ 125 126 struct linux_termio { 127 unsigned short c_iflag; 128 unsigned short c_oflag; 129 unsigned short c_cflag; 130 unsigned short c_lflag; 131 unsigned char c_line; 132 unsigned char c_cc[LINUX_NCC]; 133 }; 134 135 struct linux_termios { 136 unsigned int c_iflag; 137 unsigned int c_oflag; 138 unsigned int c_cflag; 139 unsigned int c_lflag; 140 #ifdef __alpha__ 141 unsigned char c_cc[LINUX_NCCS]; 142 unsigned char c_line; 143 unsigned int c_ispeed; 144 unsigned int c_ospeed; 145 #else 146 unsigned char c_line; 147 unsigned char c_cc[LINUX_NCCS]; 148 #endif 149 }; 150 151 struct linux_winsize { 152 unsigned short ws_row, ws_col; 153 unsigned short ws_xpixel, ws_ypixel; 154 }; 155 156 static struct speedtab sptab[] = { 157 { B0, LINUX_B0 }, { B50, LINUX_B50 }, 158 { B75, LINUX_B75 }, { B110, LINUX_B110 }, 159 { B134, LINUX_B134 }, { B150, LINUX_B150 }, 160 { B200, LINUX_B200 }, { B300, LINUX_B300 }, 161 { B600, LINUX_B600 }, { B1200, LINUX_B1200 }, 162 { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 }, 163 { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 }, 164 { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 }, 165 { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 }, 166 {-1, -1 } 167 }; 168 169 struct linux_serial_struct { 170 int type; 171 int line; 172 int port; 173 int irq; 174 int flags; 175 int xmit_fifo_size; 176 int custom_divisor; 177 int baud_base; 178 unsigned short close_delay; 179 char reserved_char[2]; 180 int hub6; 181 unsigned short closing_wait; 182 unsigned short closing_wait2; 183 int reserved[4]; 184 }; 185 186 static int 187 linux_to_bsd_speed(int code, struct speedtab *table) 188 { 189 for ( ; table->sp_code != -1; table++) 190 if (table->sp_code == code) 191 return (table->sp_speed); 192 return -1; 193 } 194 195 static int 196 bsd_to_linux_speed(int speed, struct speedtab *table) 197 { 198 for ( ; table->sp_speed != -1; table++) 199 if (table->sp_speed == speed) 200 return (table->sp_code); 201 return -1; 202 } 203 204 static void 205 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios) 206 { 207 int i; 208 209 #ifdef DEBUG 210 if (ldebug(ioctl)) { 211 printf("LINUX: BSD termios structure (input):\n"); 212 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", 213 bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag, 214 bios->c_ispeed, bios->c_ospeed); 215 printf("c_cc "); 216 for (i=0; i<NCCS; i++) 217 printf("%02x ", bios->c_cc[i]); 218 printf("\n"); 219 } 220 #endif 221 222 lios->c_iflag = 0; 223 if (bios->c_iflag & IGNBRK) 224 lios->c_iflag |= LINUX_IGNBRK; 225 if (bios->c_iflag & BRKINT) 226 lios->c_iflag |= LINUX_BRKINT; 227 if (bios->c_iflag & IGNPAR) 228 lios->c_iflag |= LINUX_IGNPAR; 229 if (bios->c_iflag & PARMRK) 230 lios->c_iflag |= LINUX_PARMRK; 231 if (bios->c_iflag & INPCK) 232 lios->c_iflag |= LINUX_INPCK; 233 if (bios->c_iflag & ISTRIP) 234 lios->c_iflag |= LINUX_ISTRIP; 235 if (bios->c_iflag & INLCR) 236 lios->c_iflag |= LINUX_INLCR; 237 if (bios->c_iflag & IGNCR) 238 lios->c_iflag |= LINUX_IGNCR; 239 if (bios->c_iflag & ICRNL) 240 lios->c_iflag |= LINUX_ICRNL; 241 if (bios->c_iflag & IXON) 242 lios->c_iflag |= LINUX_IXON; 243 if (bios->c_iflag & IXANY) 244 lios->c_iflag |= LINUX_IXANY; 245 if (bios->c_iflag & IXOFF) 246 lios->c_iflag |= LINUX_IXOFF; 247 if (bios->c_iflag & IMAXBEL) 248 lios->c_iflag |= LINUX_IMAXBEL; 249 250 lios->c_oflag = 0; 251 if (bios->c_oflag & OPOST) 252 lios->c_oflag |= LINUX_OPOST; 253 if (bios->c_oflag & ONLCR) 254 lios->c_oflag |= LINUX_ONLCR; 255 if (bios->c_oflag & OXTABS) 256 lios->c_oflag |= LINUX_XTABS; 257 258 lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab); 259 lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4; 260 if (bios->c_cflag & CSTOPB) 261 lios->c_cflag |= LINUX_CSTOPB; 262 if (bios->c_cflag & CREAD) 263 lios->c_cflag |= LINUX_CREAD; 264 if (bios->c_cflag & PARENB) 265 lios->c_cflag |= LINUX_PARENB; 266 if (bios->c_cflag & PARODD) 267 lios->c_cflag |= LINUX_PARODD; 268 if (bios->c_cflag & HUPCL) 269 lios->c_cflag |= LINUX_HUPCL; 270 if (bios->c_cflag & CLOCAL) 271 lios->c_cflag |= LINUX_CLOCAL; 272 if (bios->c_cflag & CRTSCTS) 273 lios->c_cflag |= LINUX_CRTSCTS; 274 275 lios->c_lflag = 0; 276 if (bios->c_lflag & ISIG) 277 lios->c_lflag |= LINUX_ISIG; 278 if (bios->c_lflag & ICANON) 279 lios->c_lflag |= LINUX_ICANON; 280 if (bios->c_lflag & ECHO) 281 lios->c_lflag |= LINUX_ECHO; 282 if (bios->c_lflag & ECHOE) 283 lios->c_lflag |= LINUX_ECHOE; 284 if (bios->c_lflag & ECHOK) 285 lios->c_lflag |= LINUX_ECHOK; 286 if (bios->c_lflag & ECHONL) 287 lios->c_lflag |= LINUX_ECHONL; 288 if (bios->c_lflag & NOFLSH) 289 lios->c_lflag |= LINUX_NOFLSH; 290 if (bios->c_lflag & TOSTOP) 291 lios->c_lflag |= LINUX_TOSTOP; 292 if (bios->c_lflag & ECHOCTL) 293 lios->c_lflag |= LINUX_ECHOCTL; 294 if (bios->c_lflag & ECHOPRT) 295 lios->c_lflag |= LINUX_ECHOPRT; 296 if (bios->c_lflag & ECHOKE) 297 lios->c_lflag |= LINUX_ECHOKE; 298 if (bios->c_lflag & FLUSHO) 299 lios->c_lflag |= LINUX_FLUSHO; 300 if (bios->c_lflag & PENDIN) 301 lios->c_lflag |= LINUX_PENDIN; 302 if (bios->c_lflag & IEXTEN) 303 lios->c_lflag |= LINUX_IEXTEN; 304 305 for (i=0; i<LINUX_NCCS; i++) 306 lios->c_cc[i] = LINUX_POSIX_VDISABLE; 307 lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR]; 308 lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT]; 309 lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE]; 310 lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL]; 311 lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF]; 312 lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL]; 313 lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN]; 314 lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME]; 315 lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2]; 316 lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP]; 317 lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART]; 318 lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP]; 319 lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT]; 320 lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD]; 321 lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE]; 322 lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT]; 323 324 for (i=0; i<LINUX_NCCS; i++) { 325 if (lios->c_cc[i] == _POSIX_VDISABLE) 326 lios->c_cc[i] = LINUX_POSIX_VDISABLE; 327 } 328 lios->c_line = 0; 329 330 #ifdef DEBUG 331 if (ldebug(ioctl)) { 332 printf("LINUX: LINUX termios structure (output):\n"); 333 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 334 lios->c_iflag, lios->c_oflag, lios->c_cflag, 335 lios->c_lflag, (int)lios->c_line); 336 printf("c_cc "); 337 for (i=0; i<LINUX_NCCS; i++) 338 printf("%02x ", lios->c_cc[i]); 339 printf("\n"); 340 } 341 #endif 342 } 343 344 static void 345 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios) 346 { 347 int i; 348 349 #ifdef DEBUG 350 if (ldebug(ioctl)) { 351 printf("LINUX: LINUX termios structure (input):\n"); 352 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 353 lios->c_iflag, lios->c_oflag, lios->c_cflag, 354 lios->c_lflag, (int)lios->c_line); 355 printf("c_cc "); 356 for (i=0; i<LINUX_NCCS; i++) 357 printf("%02x ", lios->c_cc[i]); 358 printf("\n"); 359 } 360 #endif 361 362 bios->c_iflag = 0; 363 if (lios->c_iflag & LINUX_IGNBRK) 364 bios->c_iflag |= IGNBRK; 365 if (lios->c_iflag & LINUX_BRKINT) 366 bios->c_iflag |= BRKINT; 367 if (lios->c_iflag & LINUX_IGNPAR) 368 bios->c_iflag |= IGNPAR; 369 if (lios->c_iflag & LINUX_PARMRK) 370 bios->c_iflag |= PARMRK; 371 if (lios->c_iflag & LINUX_INPCK) 372 bios->c_iflag |= INPCK; 373 if (lios->c_iflag & LINUX_ISTRIP) 374 bios->c_iflag |= ISTRIP; 375 if (lios->c_iflag & LINUX_INLCR) 376 bios->c_iflag |= INLCR; 377 if (lios->c_iflag & LINUX_IGNCR) 378 bios->c_iflag |= IGNCR; 379 if (lios->c_iflag & LINUX_ICRNL) 380 bios->c_iflag |= ICRNL; 381 if (lios->c_iflag & LINUX_IXON) 382 bios->c_iflag |= IXON; 383 if (lios->c_iflag & LINUX_IXANY) 384 bios->c_iflag |= IXANY; 385 if (lios->c_iflag & LINUX_IXOFF) 386 bios->c_iflag |= IXOFF; 387 if (lios->c_iflag & LINUX_IMAXBEL) 388 bios->c_iflag |= IMAXBEL; 389 390 bios->c_oflag = 0; 391 if (lios->c_oflag & LINUX_OPOST) 392 bios->c_oflag |= OPOST; 393 if (lios->c_oflag & LINUX_ONLCR) 394 bios->c_oflag |= ONLCR; 395 if (lios->c_oflag & LINUX_XTABS) 396 bios->c_oflag |= OXTABS; 397 398 bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4; 399 if (lios->c_cflag & LINUX_CSTOPB) 400 bios->c_cflag |= CSTOPB; 401 if (lios->c_cflag & LINUX_CREAD) 402 bios->c_cflag |= CREAD; 403 if (lios->c_cflag & LINUX_PARENB) 404 bios->c_cflag |= PARENB; 405 if (lios->c_cflag & LINUX_PARODD) 406 bios->c_cflag |= PARODD; 407 if (lios->c_cflag & LINUX_HUPCL) 408 bios->c_cflag |= HUPCL; 409 if (lios->c_cflag & LINUX_CLOCAL) 410 bios->c_cflag |= CLOCAL; 411 if (lios->c_cflag & LINUX_CRTSCTS) 412 bios->c_cflag |= CRTSCTS; 413 414 bios->c_lflag = 0; 415 if (lios->c_lflag & LINUX_ISIG) 416 bios->c_lflag |= ISIG; 417 if (lios->c_lflag & LINUX_ICANON) 418 bios->c_lflag |= ICANON; 419 if (lios->c_lflag & LINUX_ECHO) 420 bios->c_lflag |= ECHO; 421 if (lios->c_lflag & LINUX_ECHOE) 422 bios->c_lflag |= ECHOE; 423 if (lios->c_lflag & LINUX_ECHOK) 424 bios->c_lflag |= ECHOK; 425 if (lios->c_lflag & LINUX_ECHONL) 426 bios->c_lflag |= ECHONL; 427 if (lios->c_lflag & LINUX_NOFLSH) 428 bios->c_lflag |= NOFLSH; 429 if (lios->c_lflag & LINUX_TOSTOP) 430 bios->c_lflag |= TOSTOP; 431 if (lios->c_lflag & LINUX_ECHOCTL) 432 bios->c_lflag |= ECHOCTL; 433 if (lios->c_lflag & LINUX_ECHOPRT) 434 bios->c_lflag |= ECHOPRT; 435 if (lios->c_lflag & LINUX_ECHOKE) 436 bios->c_lflag |= ECHOKE; 437 if (lios->c_lflag & LINUX_FLUSHO) 438 bios->c_lflag |= FLUSHO; 439 if (lios->c_lflag & LINUX_PENDIN) 440 bios->c_lflag |= PENDIN; 441 if (lios->c_lflag & LINUX_IEXTEN) 442 bios->c_lflag |= IEXTEN; 443 444 for (i=0; i<NCCS; i++) 445 bios->c_cc[i] = _POSIX_VDISABLE; 446 bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR]; 447 bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT]; 448 bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE]; 449 bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL]; 450 bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF]; 451 bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL]; 452 bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN]; 453 bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME]; 454 bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2]; 455 bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP]; 456 bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART]; 457 bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP]; 458 bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT]; 459 bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD]; 460 bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE]; 461 bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT]; 462 463 for (i=0; i<NCCS; i++) { 464 if (bios->c_cc[i] == LINUX_POSIX_VDISABLE) 465 bios->c_cc[i] = _POSIX_VDISABLE; 466 } 467 468 bios->c_ispeed = bios->c_ospeed = 469 linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab); 470 471 #ifdef DEBUG 472 if (ldebug(ioctl)) { 473 printf("LINUX: BSD termios structure (output):\n"); 474 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", 475 bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag, 476 bios->c_ispeed, bios->c_ospeed); 477 printf("c_cc "); 478 for (i=0; i<NCCS; i++) 479 printf("%02x ", bios->c_cc[i]); 480 printf("\n"); 481 } 482 #endif 483 } 484 485 static void 486 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio) 487 { 488 struct linux_termios lios; 489 490 bsd_to_linux_termios(bios, &lios); 491 lio->c_iflag = lios.c_iflag; 492 lio->c_oflag = lios.c_oflag; 493 lio->c_cflag = lios.c_cflag; 494 lio->c_lflag = lios.c_lflag; 495 lio->c_line = lios.c_line; 496 #ifdef __alpha__ 497 lio->c_cc[LINUX__VINTR] = lios.c_cc[LINUX_VINTR]; 498 lio->c_cc[LINUX__VQUIT] = lios.c_cc[LINUX_VQUIT]; 499 lio->c_cc[LINUX__VERASE] = lios.c_cc[LINUX_VERASE]; 500 lio->c_cc[LINUX__VKILL] = lios.c_cc[LINUX_VKILL]; 501 lio->c_cc[LINUX__VEOF] = 502 lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN]; 503 lio->c_cc[LINUX__VEOL] = 504 lios.c_cc[(lios.c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME]; 505 lio->c_cc[LINUX__VEOL2] = lios.c_cc[LINUX_VEOL2]; 506 lio->c_cc[LINUX__VSWTC] = lios.c_cc[LINUX_VSWTC]; 507 #else 508 memcpy(lio->c_cc, lios.c_cc, LINUX_NCC); 509 #endif 510 } 511 512 static void 513 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios) 514 { 515 struct linux_termios lios; 516 int i; 517 518 lios.c_iflag = lio->c_iflag; 519 lios.c_oflag = lio->c_oflag; 520 lios.c_cflag = lio->c_cflag; 521 lios.c_lflag = lio->c_lflag; 522 #ifdef __alpha__ 523 for (i=0; i<LINUX_NCCS; i++) 524 lios.c_cc[i] = LINUX_POSIX_VDISABLE; 525 lios.c_cc[LINUX_VINTR] = lio->c_cc[LINUX__VINTR]; 526 lios.c_cc[LINUX_VQUIT] = lio->c_cc[LINUX__VQUIT]; 527 lios.c_cc[LINUX_VERASE] = lio->c_cc[LINUX__VERASE]; 528 lios.c_cc[LINUX_VKILL] = lio->c_cc[LINUX__VKILL]; 529 lios.c_cc[LINUX_VEOL2] = lio->c_cc[LINUX__VEOL2]; 530 lios.c_cc[LINUX_VSWTC] = lio->c_cc[LINUX__VSWTC]; 531 lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOF : LINUX_VMIN] = 532 lio->c_cc[LINUX__VEOF]; 533 lios.c_cc[(lio->c_lflag & ICANON) ? LINUX_VEOL : LINUX_VTIME] = 534 lio->c_cc[LINUX__VEOL]; 535 #else 536 for (i=LINUX_NCC; i<LINUX_NCCS; i++) 537 lios.c_cc[i] = LINUX_POSIX_VDISABLE; 538 memcpy(lios.c_cc, lio->c_cc, LINUX_NCC); 539 #endif 540 linux_to_bsd_termios(&lios, bios); 541 } 542 543 static int 544 linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args) 545 { 546 struct termios bios; 547 struct linux_termios lios; 548 struct linux_termio lio; 549 struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd]; 550 int error; 551 552 switch (args->cmd & 0xffff) { 553 554 case LINUX_TCGETS: 555 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td); 556 if (error) 557 return (error); 558 bsd_to_linux_termios(&bios, &lios); 559 return copyout(&lios, (caddr_t)args->arg, sizeof(lios)); 560 561 case LINUX_TCSETS: 562 error = copyin((caddr_t)args->arg, &lios, sizeof(lios)); 563 if (error) 564 return (error); 565 linux_to_bsd_termios(&lios, &bios); 566 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td)); 567 568 case LINUX_TCSETSW: 569 error = copyin((caddr_t)args->arg, &lios, sizeof(lios)); 570 if (error) 571 return (error); 572 linux_to_bsd_termios(&lios, &bios); 573 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td)); 574 575 case LINUX_TCSETSF: 576 error = copyin((caddr_t)args->arg, &lios, sizeof(lios)); 577 if (error) 578 return (error); 579 linux_to_bsd_termios(&lios, &bios); 580 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td)); 581 582 case LINUX_TCGETA: 583 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td); 584 if (error) 585 return (error); 586 bsd_to_linux_termio(&bios, &lio); 587 return (copyout(&lio, (caddr_t)args->arg, sizeof(lio))); 588 589 case LINUX_TCSETA: 590 error = copyin((caddr_t)args->arg, &lio, sizeof(lio)); 591 if (error) 592 return (error); 593 linux_to_bsd_termio(&lio, &bios); 594 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td)); 595 596 case LINUX_TCSETAW: 597 error = copyin((caddr_t)args->arg, &lio, sizeof(lio)); 598 if (error) 599 return (error); 600 linux_to_bsd_termio(&lio, &bios); 601 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td)); 602 603 case LINUX_TCSETAF: 604 error = copyin((caddr_t)args->arg, &lio, sizeof(lio)); 605 if (error) 606 return (error); 607 linux_to_bsd_termio(&lio, &bios); 608 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td)); 609 610 /* LINUX_TCSBRK */ 611 612 case LINUX_TCXONC: { 613 switch (args->arg) { 614 case LINUX_TCOOFF: 615 args->cmd = TIOCSTOP; 616 break; 617 case LINUX_TCOON: 618 args->cmd = TIOCSTART; 619 break; 620 case LINUX_TCIOFF: 621 case LINUX_TCION: { 622 int c; 623 struct write_args wr; 624 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td); 625 if (error) 626 return (error); 627 c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART; 628 c = bios.c_cc[c]; 629 if (c != _POSIX_VDISABLE) { 630 wr.fd = args->fd; 631 wr.buf = &c; 632 wr.nbyte = sizeof(c); 633 return (write(td, &wr)); 634 } else 635 return (0); 636 } 637 default: 638 return (EINVAL); 639 } 640 args->arg = 0; 641 return (ioctl(td, (struct ioctl_args *)args)); 642 } 643 644 case LINUX_TCFLSH: { 645 args->cmd = TIOCFLUSH; 646 switch (args->arg) { 647 case LINUX_TCIFLUSH: 648 args->arg = FREAD; 649 break; 650 case LINUX_TCOFLUSH: 651 args->arg = FWRITE; 652 break; 653 case LINUX_TCIOFLUSH: 654 args->arg = FREAD | FWRITE; 655 break; 656 default: 657 return (EINVAL); 658 } 659 return (ioctl(td, (struct ioctl_args *)args)); 660 } 661 662 case LINUX_TIOCEXCL: 663 args->cmd = TIOCEXCL; 664 return (ioctl(td, (struct ioctl_args *)args)); 665 666 case LINUX_TIOCNXCL: 667 args->cmd = TIOCNXCL; 668 return (ioctl(td, (struct ioctl_args *)args)); 669 670 /* LINUX_TIOCSCTTY */ 671 672 case LINUX_TIOCGPGRP: 673 args->cmd = TIOCGPGRP; 674 return (ioctl(td, (struct ioctl_args *)args)); 675 676 case LINUX_TIOCSPGRP: 677 args->cmd = TIOCSPGRP; 678 return (ioctl(td, (struct ioctl_args *)args)); 679 680 /* LINUX_TIOCOUTQ */ 681 /* LINUX_TIOCSTI */ 682 683 case LINUX_TIOCGWINSZ: 684 args->cmd = TIOCGWINSZ; 685 return (ioctl(td, (struct ioctl_args *)args)); 686 687 case LINUX_TIOCSWINSZ: 688 args->cmd = TIOCSWINSZ; 689 return (ioctl(td, (struct ioctl_args *)args)); 690 691 case LINUX_TIOCMGET: 692 args->cmd = TIOCMGET; 693 return (ioctl(td, (struct ioctl_args *)args)); 694 695 case LINUX_TIOCMBIS: 696 args->cmd = TIOCMBIS; 697 return (ioctl(td, (struct ioctl_args *)args)); 698 699 case LINUX_TIOCMBIC: 700 args->cmd = TIOCMBIC; 701 return (ioctl(td, (struct ioctl_args *)args)); 702 703 case LINUX_TIOCMSET: 704 args->cmd = TIOCMSET; 705 return (ioctl(td, (struct ioctl_args *)args)); 706 707 /* TIOCGSOFTCAR */ 708 /* TIOCSSOFTCAR */ 709 710 case LINUX_FIONREAD: /* LINUX_TIOCINQ */ 711 args->cmd = FIONREAD; 712 return (ioctl(td, (struct ioctl_args *)args)); 713 714 /* LINUX_TIOCLINUX */ 715 716 case LINUX_TIOCCONS: 717 args->cmd = TIOCCONS; 718 return (ioctl(td, (struct ioctl_args *)args)); 719 720 case LINUX_TIOCGSERIAL: { 721 struct linux_serial_struct lss; 722 lss.type = LINUX_PORT_16550A; 723 lss.flags = 0; 724 lss.close_delay = 0; 725 return copyout(&lss, (caddr_t)args->arg, sizeof(lss)); 726 } 727 728 case LINUX_TIOCSSERIAL: { 729 struct linux_serial_struct lss; 730 error = copyin((caddr_t)args->arg, &lss, sizeof(lss)); 731 if (error) 732 return (error); 733 /* XXX - It really helps to have an implementation that 734 * does nothing. NOT! 735 */ 736 return (0); 737 } 738 739 /* LINUX_TIOCPKT */ 740 741 case LINUX_FIONBIO: 742 args->cmd = FIONBIO; 743 return (ioctl(td, (struct ioctl_args *)args)); 744 745 case LINUX_TIOCNOTTY: 746 args->cmd = TIOCNOTTY; 747 return (ioctl(td, (struct ioctl_args *)args)); 748 749 case LINUX_TIOCSETD: { 750 int line; 751 switch (args->arg) { 752 case LINUX_N_TTY: 753 line = TTYDISC; 754 break; 755 case LINUX_N_SLIP: 756 line = SLIPDISC; 757 break; 758 case LINUX_N_PPP: 759 line = PPPDISC; 760 break; 761 default: 762 return (EINVAL); 763 } 764 return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td)); 765 } 766 767 case LINUX_TIOCGETD: { 768 int linux_line; 769 int bsd_line = TTYDISC; 770 error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, td); 771 if (error) 772 return (error); 773 switch (bsd_line) { 774 case TTYDISC: 775 linux_line = LINUX_N_TTY; 776 break; 777 case SLIPDISC: 778 linux_line = LINUX_N_SLIP; 779 break; 780 case PPPDISC: 781 linux_line = LINUX_N_PPP; 782 break; 783 default: 784 return (EINVAL); 785 } 786 return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int))); 787 } 788 789 /* LINUX_TCSBRKP */ 790 /* LINUX_TIOCTTYGSTRUCT */ 791 792 case LINUX_FIONCLEX: 793 args->cmd = FIONCLEX; 794 return (ioctl(td, (struct ioctl_args *)args)); 795 796 case LINUX_FIOCLEX: 797 args->cmd = FIOCLEX; 798 return (ioctl(td, (struct ioctl_args *)args)); 799 800 case LINUX_FIOASYNC: 801 args->cmd = FIOASYNC; 802 return (ioctl(td, (struct ioctl_args *)args)); 803 804 /* LINUX_TIOCSERCONFIG */ 805 /* LINUX_TIOCSERGWILD */ 806 /* LINUX_TIOCSERSWILD */ 807 /* LINUX_TIOCGLCKTRMIOS */ 808 /* LINUX_TIOCSLCKTRMIOS */ 809 810 } 811 812 return (ENOIOCTL); 813 } 814 815 /* 816 * CDROM related ioctls 817 */ 818 819 struct linux_cdrom_msf 820 { 821 u_char cdmsf_min0; 822 u_char cdmsf_sec0; 823 u_char cdmsf_frame0; 824 u_char cdmsf_min1; 825 u_char cdmsf_sec1; 826 u_char cdmsf_frame1; 827 }; 828 829 struct linux_cdrom_tochdr 830 { 831 u_char cdth_trk0; 832 u_char cdth_trk1; 833 }; 834 835 union linux_cdrom_addr 836 { 837 struct { 838 u_char minute; 839 u_char second; 840 u_char frame; 841 } msf; 842 int lba; 843 }; 844 845 struct linux_cdrom_tocentry 846 { 847 u_char cdte_track; 848 u_char cdte_adr:4; 849 u_char cdte_ctrl:4; 850 u_char cdte_format; 851 union linux_cdrom_addr cdte_addr; 852 u_char cdte_datamode; 853 }; 854 855 struct linux_cdrom_subchnl 856 { 857 u_char cdsc_format; 858 u_char cdsc_audiostatus; 859 u_char cdsc_adr:4; 860 u_char cdsc_ctrl:4; 861 u_char cdsc_trk; 862 u_char cdsc_ind; 863 union linux_cdrom_addr cdsc_absaddr; 864 union linux_cdrom_addr cdsc_reladdr; 865 }; 866 867 static void 868 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp) 869 { 870 if (af == CD_LBA_FORMAT) 871 lp->lba = bp->lba; 872 else { 873 lp->msf.minute = bp->msf.minute; 874 lp->msf.second = bp->msf.second; 875 lp->msf.frame = bp->msf.frame; 876 } 877 } 878 879 static void 880 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba) 881 { 882 if (format == LINUX_CDROM_MSF) { 883 addr->msf.frame = lba % 75; 884 lba /= 75; 885 lba += 2; 886 addr->msf.second = lba % 60; 887 addr->msf.minute = lba / 60; 888 } else 889 addr->lba = lba; 890 } 891 892 static int 893 linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args) 894 { 895 struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd]; 896 int error; 897 898 switch (args->cmd & 0xffff) { 899 900 case LINUX_CDROMPAUSE: 901 args->cmd = CDIOCPAUSE; 902 return (ioctl(td, (struct ioctl_args *)args)); 903 904 case LINUX_CDROMRESUME: 905 args->cmd = CDIOCRESUME; 906 return (ioctl(td, (struct ioctl_args *)args)); 907 908 case LINUX_CDROMPLAYMSF: 909 args->cmd = CDIOCPLAYMSF; 910 return (ioctl(td, (struct ioctl_args *)args)); 911 912 case LINUX_CDROMPLAYTRKIND: 913 args->cmd = CDIOCPLAYTRACKS; 914 return (ioctl(td, (struct ioctl_args *)args)); 915 916 case LINUX_CDROMREADTOCHDR: { 917 struct ioc_toc_header th; 918 struct linux_cdrom_tochdr lth; 919 error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, td); 920 if (!error) { 921 lth.cdth_trk0 = th.starting_track; 922 lth.cdth_trk1 = th.ending_track; 923 copyout(<h, (caddr_t)args->arg, sizeof(lth)); 924 } 925 return (error); 926 } 927 928 case LINUX_CDROMREADTOCENTRY: { 929 struct linux_cdrom_tocentry lte, *ltep = 930 (struct linux_cdrom_tocentry *)args->arg; 931 struct ioc_read_toc_single_entry irtse; 932 irtse.address_format = ltep->cdte_format; 933 irtse.track = ltep->cdte_track; 934 error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, td); 935 if (!error) { 936 lte = *ltep; 937 lte.cdte_ctrl = irtse.entry.control; 938 lte.cdte_adr = irtse.entry.addr_type; 939 bsd_to_linux_msf_lba(irtse.address_format, 940 &irtse.entry.addr, <e.cdte_addr); 941 copyout(<e, (caddr_t)args->arg, sizeof(lte)); 942 } 943 return (error); 944 } 945 946 case LINUX_CDROMSTOP: 947 args->cmd = CDIOCSTOP; 948 return (ioctl(td, (struct ioctl_args *)args)); 949 950 case LINUX_CDROMSTART: 951 args->cmd = CDIOCSTART; 952 return (ioctl(td, (struct ioctl_args *)args)); 953 954 case LINUX_CDROMEJECT: 955 args->cmd = CDIOCEJECT; 956 return (ioctl(td, (struct ioctl_args *)args)); 957 958 /* LINUX_CDROMVOLCTRL */ 959 960 case LINUX_CDROMSUBCHNL: { 961 struct linux_cdrom_subchnl sc; 962 struct ioc_read_subchannel bsdsc; 963 struct cd_sub_channel_info *bsdinfo; 964 caddr_t sg = stackgap_init(); 965 bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg, 966 sizeof(struct cd_sub_channel_info)); 967 bsdsc.address_format = CD_LBA_FORMAT; 968 bsdsc.data_format = CD_CURRENT_POSITION; 969 bsdsc.track = 0; 970 bsdsc.data_len = sizeof(struct cd_sub_channel_info); 971 bsdsc.data = bsdinfo; 972 error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, td); 973 if (error) 974 return (error); 975 error = copyin((caddr_t)args->arg, &sc, 976 sizeof(struct linux_cdrom_subchnl)); 977 if (error) 978 return (error); 979 sc.cdsc_audiostatus = bsdinfo->header.audio_status; 980 sc.cdsc_adr = bsdinfo->what.position.addr_type; 981 sc.cdsc_ctrl = bsdinfo->what.position.control; 982 sc.cdsc_trk = bsdinfo->what.position.track_number; 983 sc.cdsc_ind = bsdinfo->what.position.index_number; 984 set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format, 985 bsdinfo->what.position.absaddr.lba); 986 set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format, 987 bsdinfo->what.position.reladdr.lba); 988 error = copyout(&sc, (caddr_t)args->arg, 989 sizeof(struct linux_cdrom_subchnl)); 990 return (error); 991 } 992 993 /* LINUX_CDROMREADMODE2 */ 994 /* LINUX_CDROMREADMODE1 */ 995 /* LINUX_CDROMREADAUDIO */ 996 /* LINUX_CDROMEJECT_SW */ 997 /* LINUX_CDROMMULTISESSION */ 998 /* LINUX_CDROM_GET_UPC */ 999 1000 case LINUX_CDROMRESET: 1001 args->cmd = CDIOCRESET; 1002 return (ioctl(td, (struct ioctl_args *)args)); 1003 1004 /* LINUX_CDROMVOLREAD */ 1005 /* LINUX_CDROMREADRAW */ 1006 /* LINUX_CDROMREADCOOKED */ 1007 /* LINUX_CDROMSEEK */ 1008 /* LINUX_CDROMPLAYBLK */ 1009 /* LINUX_CDROMREADALL */ 1010 /* LINUX_CDROMCLOSETRAY */ 1011 /* LINUX_CDROMLOADFROMSLOT */ 1012 1013 } 1014 1015 return (ENOIOCTL); 1016 } 1017 1018 /* 1019 * Sound related ioctls 1020 */ 1021 1022 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT }; 1023 1024 #define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30]) 1025 1026 static int 1027 linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args) 1028 { 1029 1030 switch (args->cmd & 0xffff) { 1031 1032 case LINUX_SOUND_MIXER_WRITE_VOLUME: 1033 args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME); 1034 return (ioctl(td, (struct ioctl_args *)args)); 1035 1036 case LINUX_SOUND_MIXER_WRITE_BASS: 1037 args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS); 1038 return (ioctl(td, (struct ioctl_args *)args)); 1039 1040 case LINUX_SOUND_MIXER_WRITE_TREBLE: 1041 args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE); 1042 return (ioctl(td, (struct ioctl_args *)args)); 1043 1044 case LINUX_SOUND_MIXER_WRITE_SYNTH: 1045 args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH); 1046 return (ioctl(td, (struct ioctl_args *)args)); 1047 1048 case LINUX_SOUND_MIXER_WRITE_PCM: 1049 args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM); 1050 return (ioctl(td, (struct ioctl_args *)args)); 1051 1052 case LINUX_SOUND_MIXER_WRITE_SPEAKER: 1053 args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER); 1054 return (ioctl(td, (struct ioctl_args *)args)); 1055 1056 case LINUX_SOUND_MIXER_WRITE_LINE: 1057 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE); 1058 return (ioctl(td, (struct ioctl_args *)args)); 1059 1060 case LINUX_SOUND_MIXER_WRITE_MIC: 1061 args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC); 1062 return (ioctl(td, (struct ioctl_args *)args)); 1063 1064 case LINUX_SOUND_MIXER_WRITE_CD: 1065 args->cmd = SETDIR(SOUND_MIXER_WRITE_CD); 1066 return (ioctl(td, (struct ioctl_args *)args)); 1067 1068 case LINUX_SOUND_MIXER_WRITE_IMIX: 1069 args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX); 1070 return (ioctl(td, (struct ioctl_args *)args)); 1071 1072 case LINUX_SOUND_MIXER_WRITE_ALTPCM: 1073 args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM); 1074 return (ioctl(td, (struct ioctl_args *)args)); 1075 1076 case LINUX_SOUND_MIXER_WRITE_RECLEV: 1077 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV); 1078 return (ioctl(td, (struct ioctl_args *)args)); 1079 1080 case LINUX_SOUND_MIXER_WRITE_IGAIN: 1081 args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN); 1082 return (ioctl(td, (struct ioctl_args *)args)); 1083 1084 case LINUX_SOUND_MIXER_WRITE_OGAIN: 1085 args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN); 1086 return (ioctl(td, (struct ioctl_args *)args)); 1087 1088 case LINUX_SOUND_MIXER_WRITE_LINE1: 1089 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1); 1090 return (ioctl(td, (struct ioctl_args *)args)); 1091 1092 case LINUX_SOUND_MIXER_WRITE_LINE2: 1093 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2); 1094 return (ioctl(td, (struct ioctl_args *)args)); 1095 1096 case LINUX_SOUND_MIXER_WRITE_LINE3: 1097 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3); 1098 return (ioctl(td, (struct ioctl_args *)args)); 1099 1100 case LINUX_OSS_GETVERSION: { 1101 int version = linux_get_oss_version(td->td_proc); 1102 return (copyout(&version, (caddr_t)args->arg, sizeof(int))); 1103 } 1104 1105 case LINUX_SOUND_MIXER_READ_DEVMASK: 1106 args->cmd = SOUND_MIXER_READ_DEVMASK; 1107 return (ioctl(td, (struct ioctl_args *)args)); 1108 1109 case LINUX_SNDCTL_DSP_RESET: 1110 args->cmd = SNDCTL_DSP_RESET; 1111 return (ioctl(td, (struct ioctl_args *)args)); 1112 1113 case LINUX_SNDCTL_DSP_SYNC: 1114 args->cmd = SNDCTL_DSP_SYNC; 1115 return (ioctl(td, (struct ioctl_args *)args)); 1116 1117 case LINUX_SNDCTL_DSP_SPEED: 1118 args->cmd = SNDCTL_DSP_SPEED; 1119 return (ioctl(td, (struct ioctl_args *)args)); 1120 1121 case LINUX_SNDCTL_DSP_STEREO: 1122 args->cmd = SNDCTL_DSP_STEREO; 1123 return (ioctl(td, (struct ioctl_args *)args)); 1124 1125 case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */ 1126 args->cmd = SNDCTL_DSP_GETBLKSIZE; 1127 return (ioctl(td, (struct ioctl_args *)args)); 1128 1129 case LINUX_SNDCTL_DSP_SETFMT: 1130 args->cmd = SNDCTL_DSP_SETFMT; 1131 return (ioctl(td, (struct ioctl_args *)args)); 1132 1133 case LINUX_SOUND_PCM_WRITE_CHANNELS: 1134 args->cmd = SOUND_PCM_WRITE_CHANNELS; 1135 return (ioctl(td, (struct ioctl_args *)args)); 1136 1137 case LINUX_SOUND_PCM_WRITE_FILTER: 1138 args->cmd = SOUND_PCM_WRITE_FILTER; 1139 return (ioctl(td, (struct ioctl_args *)args)); 1140 1141 case LINUX_SNDCTL_DSP_POST: 1142 args->cmd = SNDCTL_DSP_POST; 1143 return (ioctl(td, (struct ioctl_args *)args)); 1144 1145 case LINUX_SNDCTL_DSP_SUBDIVIDE: 1146 args->cmd = SNDCTL_DSP_SUBDIVIDE; 1147 return (ioctl(td, (struct ioctl_args *)args)); 1148 1149 case LINUX_SNDCTL_DSP_SETFRAGMENT: 1150 args->cmd = SNDCTL_DSP_SETFRAGMENT; 1151 return (ioctl(td, (struct ioctl_args *)args)); 1152 1153 case LINUX_SNDCTL_DSP_GETFMTS: 1154 args->cmd = SNDCTL_DSP_GETFMTS; 1155 return (ioctl(td, (struct ioctl_args *)args)); 1156 1157 case LINUX_SNDCTL_DSP_GETOSPACE: 1158 args->cmd = SNDCTL_DSP_GETOSPACE; 1159 return (ioctl(td, (struct ioctl_args *)args)); 1160 1161 case LINUX_SNDCTL_DSP_GETISPACE: 1162 args->cmd = SNDCTL_DSP_GETISPACE; 1163 return (ioctl(td, (struct ioctl_args *)args)); 1164 1165 case LINUX_SNDCTL_DSP_NONBLOCK: 1166 args->cmd = SNDCTL_DSP_NONBLOCK; 1167 return (ioctl(td, (struct ioctl_args *)args)); 1168 1169 case LINUX_SNDCTL_DSP_GETCAPS: 1170 args->cmd = SNDCTL_DSP_GETCAPS; 1171 return (ioctl(td, (struct ioctl_args *)args)); 1172 1173 case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */ 1174 args->cmd = SNDCTL_DSP_SETTRIGGER; 1175 return (ioctl(td, (struct ioctl_args *)args)); 1176 1177 case LINUX_SNDCTL_DSP_GETIPTR: 1178 args->cmd = SNDCTL_DSP_GETIPTR; 1179 return (ioctl(td, (struct ioctl_args *)args)); 1180 1181 case LINUX_SNDCTL_DSP_GETOPTR: 1182 args->cmd = SNDCTL_DSP_GETOPTR; 1183 return (ioctl(td, (struct ioctl_args *)args)); 1184 1185 case LINUX_SNDCTL_DSP_GETODELAY: 1186 args->cmd = SNDCTL_DSP_GETODELAY; 1187 return (ioctl(td, (struct ioctl_args *)args)); 1188 1189 case LINUX_SNDCTL_SEQ_RESET: 1190 args->cmd = SNDCTL_SEQ_RESET; 1191 return (ioctl(td, (struct ioctl_args *)args)); 1192 1193 case LINUX_SNDCTL_SEQ_SYNC: 1194 args->cmd = SNDCTL_SEQ_SYNC; 1195 return (ioctl(td, (struct ioctl_args *)args)); 1196 1197 case LINUX_SNDCTL_SYNTH_INFO: 1198 args->cmd = SNDCTL_SYNTH_INFO; 1199 return (ioctl(td, (struct ioctl_args *)args)); 1200 1201 case LINUX_SNDCTL_SEQ_CTRLRATE: 1202 args->cmd = SNDCTL_SEQ_CTRLRATE; 1203 return (ioctl(td, (struct ioctl_args *)args)); 1204 1205 case LINUX_SNDCTL_SEQ_GETOUTCOUNT: 1206 args->cmd = SNDCTL_SEQ_GETOUTCOUNT; 1207 return (ioctl(td, (struct ioctl_args *)args)); 1208 1209 case LINUX_SNDCTL_SEQ_GETINCOUNT: 1210 args->cmd = SNDCTL_SEQ_GETINCOUNT; 1211 return (ioctl(td, (struct ioctl_args *)args)); 1212 1213 case LINUX_SNDCTL_SEQ_PERCMODE: 1214 args->cmd = SNDCTL_SEQ_PERCMODE; 1215 return (ioctl(td, (struct ioctl_args *)args)); 1216 1217 case LINUX_SNDCTL_FM_LOAD_INSTR: 1218 args->cmd = SNDCTL_FM_LOAD_INSTR; 1219 return (ioctl(td, (struct ioctl_args *)args)); 1220 1221 case LINUX_SNDCTL_SEQ_TESTMIDI: 1222 args->cmd = SNDCTL_SEQ_TESTMIDI; 1223 return (ioctl(td, (struct ioctl_args *)args)); 1224 1225 case LINUX_SNDCTL_SEQ_RESETSAMPLES: 1226 args->cmd = SNDCTL_SEQ_RESETSAMPLES; 1227 return (ioctl(td, (struct ioctl_args *)args)); 1228 1229 case LINUX_SNDCTL_SEQ_NRSYNTHS: 1230 args->cmd = SNDCTL_SEQ_NRSYNTHS; 1231 return (ioctl(td, (struct ioctl_args *)args)); 1232 1233 case LINUX_SNDCTL_SEQ_NRMIDIS: 1234 args->cmd = SNDCTL_SEQ_NRMIDIS; 1235 return (ioctl(td, (struct ioctl_args *)args)); 1236 1237 case LINUX_SNDCTL_MIDI_INFO: 1238 args->cmd = SNDCTL_MIDI_INFO; 1239 return (ioctl(td, (struct ioctl_args *)args)); 1240 1241 case LINUX_SNDCTL_SEQ_TRESHOLD: 1242 args->cmd = SNDCTL_SEQ_TRESHOLD; 1243 return (ioctl(td, (struct ioctl_args *)args)); 1244 1245 case LINUX_SNDCTL_SYNTH_MEMAVL: 1246 args->cmd = SNDCTL_SYNTH_MEMAVL; 1247 return (ioctl(td, (struct ioctl_args *)args)); 1248 1249 } 1250 1251 return (ENOIOCTL); 1252 } 1253 1254 /* 1255 * Console related ioctls 1256 */ 1257 1258 #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) 1259 1260 static int 1261 linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args) 1262 { 1263 struct file *fp = td->td_proc->p_fd->fd_ofiles[args->fd]; 1264 1265 switch (args->cmd & 0xffff) { 1266 1267 case LINUX_KIOCSOUND: 1268 args->cmd = KIOCSOUND; 1269 return (ioctl(td, (struct ioctl_args *)args)); 1270 1271 case LINUX_KDMKTONE: 1272 args->cmd = KDMKTONE; 1273 return (ioctl(td, (struct ioctl_args *)args)); 1274 1275 case LINUX_KDGETLED: 1276 args->cmd = KDGETLED; 1277 return (ioctl(td, (struct ioctl_args *)args)); 1278 1279 case LINUX_KDSETLED: 1280 args->cmd = KDSETLED; 1281 return (ioctl(td, (struct ioctl_args *)args)); 1282 1283 case LINUX_KDSETMODE: 1284 args->cmd = KDSETMODE; 1285 return (ioctl(td, (struct ioctl_args *)args)); 1286 1287 case LINUX_KDGETMODE: 1288 args->cmd = KDGETMODE; 1289 return (ioctl(td, (struct ioctl_args *)args)); 1290 1291 case LINUX_KDGKBMODE: 1292 args->cmd = KDGKBMODE; 1293 return (ioctl(td, (struct ioctl_args *)args)); 1294 1295 case LINUX_KDSKBMODE: { 1296 int kbdmode; 1297 switch (args->arg) { 1298 case LINUX_KBD_RAW: 1299 kbdmode = K_RAW; 1300 break; 1301 case LINUX_KBD_XLATE: 1302 kbdmode = K_XLATE; 1303 break; 1304 case LINUX_KBD_MEDIUMRAW: 1305 kbdmode = K_RAW; 1306 break; 1307 default: 1308 return (EINVAL); 1309 } 1310 return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, td)); 1311 } 1312 1313 case LINUX_VT_OPENQRY: 1314 args->cmd = VT_OPENQRY; 1315 return (ioctl(td, (struct ioctl_args *)args)); 1316 1317 case LINUX_VT_GETMODE: 1318 args->cmd = VT_GETMODE; 1319 return (ioctl(td, (struct ioctl_args *)args)); 1320 1321 case LINUX_VT_SETMODE: { 1322 struct vt_mode *mode; 1323 args->cmd = VT_SETMODE; 1324 mode = (struct vt_mode *)args->arg; 1325 if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig)) 1326 mode->frsig = mode->acqsig; 1327 return (ioctl(td, (struct ioctl_args *)args)); 1328 } 1329 1330 case LINUX_VT_GETSTATE: 1331 args->cmd = VT_GETACTIVE; 1332 return (ioctl(td, (struct ioctl_args *)args)); 1333 1334 case LINUX_VT_RELDISP: 1335 args->cmd = VT_RELDISP; 1336 return (ioctl(td, (struct ioctl_args *)args)); 1337 1338 case LINUX_VT_ACTIVATE: 1339 args->cmd = VT_ACTIVATE; 1340 return (ioctl(td, (struct ioctl_args *)args)); 1341 1342 case LINUX_VT_WAITACTIVE: 1343 args->cmd = VT_WAITACTIVE; 1344 return (ioctl(td, (struct ioctl_args *)args)); 1345 1346 } 1347 1348 return (ENOIOCTL); 1349 } 1350 1351 #define IFP_IS_ETH(ifp) ((ifp->if_flags & \ 1352 (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST)) == \ 1353 IFF_BROADCAST) 1354 1355 /* 1356 * Construct the Linux name for an interface 1357 */ 1358 1359 int 1360 linux_ifname(struct ifnet *ifp, char *name, size_t size) 1361 { 1362 if (IFP_IS_ETH(ifp)) 1363 return snprintf(name, LINUX_IFNAMSIZ, 1364 "eth%d", ifp->if_index); 1365 return snprintf(name, LINUX_IFNAMSIZ, 1366 "%s%d", ifp->if_name, ifp->if_unit); 1367 } 1368 1369 /* 1370 * Translate a FreeBSD interface name to a Linux interface name, 1371 * and return the associated ifnet structure. 1372 * bsdname and lxname need to be least IFNAMSIZ bytes long, but 1373 * can point to the same buffer. 1374 */ 1375 1376 static struct ifnet * 1377 ifname_bsd_to_linux(const char *bsdname, char *lxname) 1378 { 1379 struct ifnet *ifp; 1380 int len, unit; 1381 char *ep; 1382 1383 for (len = 0; len < IFNAMSIZ; ++len) 1384 if (!isalpha(bsdname[len])) 1385 break; 1386 if (len == 0 || len == IFNAMSIZ) 1387 return (NULL); 1388 unit = (int)strtoul(bsdname + len, &ep, 10); 1389 if (ep == NULL || ep == bsdname + len || ep >= bsdname + IFNAMSIZ) 1390 return (NULL); 1391 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1392 if (ifp->if_unit == unit && ifp->if_name[len] == '\0' && 1393 strncmp(ifp->if_name, bsdname, len) == 0) 1394 break; 1395 } 1396 if (ifp != NULL) 1397 linux_ifname(ifp, lxname, LINUX_IFNAMSIZ); 1398 1399 return (ifp); 1400 } 1401 1402 /* 1403 * Translate a Linux interface name to a FreeBSD interface name, 1404 * and return the associated ifnet structure 1405 * bsdname and lxname need to be least IFNAMSIZ bytes long, but 1406 * can point to the same buffer. 1407 */ 1408 1409 static struct ifnet * 1410 ifname_linux_to_bsd(const char *lxname, char *bsdname) 1411 { 1412 struct ifnet *ifp; 1413 int len, unit; 1414 char *ep; 1415 1416 for (len = 0; len < LINUX_IFNAMSIZ; ++len) 1417 if (!isalpha(lxname[len])) 1418 break; 1419 if (len == 0 || len == LINUX_IFNAMSIZ) 1420 return (NULL); 1421 unit = (int)strtoul(lxname + len, &ep, 10); 1422 if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) 1423 return (NULL); 1424 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1425 /* allow Linux programs to use FreeBSD names */ 1426 if (ifp->if_unit == unit && ifp->if_name[len] == '\0' && 1427 strncmp(ifp->if_name, lxname, len) == 0) 1428 break; 1429 if (ifp->if_index == unit && IFP_IS_ETH(ifp) && 1430 strncmp(lxname, "eth", len) == 0) 1431 break; 1432 } 1433 if (ifp != NULL) 1434 snprintf(bsdname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit); 1435 return (ifp); 1436 } 1437 1438 /* 1439 * Implement the SIOCGIFCONF ioctl 1440 */ 1441 1442 static int 1443 linux_ifconf(struct thread *td, struct ifconf *uifc) 1444 { 1445 struct ifconf ifc; 1446 struct l_ifreq ifr; 1447 struct ifnet *ifp; 1448 struct iovec iov; 1449 struct uio uio; 1450 int error; 1451 1452 error = copyin(uifc, &ifc, sizeof ifc); 1453 if (error != 0) 1454 return (error); 1455 1456 /* much easier to use uiomove than keep track ourselves */ 1457 iov.iov_base = ifc.ifc_buf; 1458 iov.iov_len = ifc.ifc_len; 1459 uio.uio_iov = &iov; 1460 uio.uio_iovcnt = 1; 1461 uio.uio_offset = 0; 1462 uio.uio_resid = ifc.ifc_len; 1463 uio.uio_segflg = UIO_USERSPACE; 1464 uio.uio_rw = UIO_READ; 1465 uio.uio_td = td; 1466 1467 /* return interface names but no addresses. */ 1468 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1469 if (uio.uio_resid <= 0) 1470 break; 1471 bzero(&ifr, sizeof ifr); 1472 linux_ifname(ifp, ifr.ifr_name, LINUX_IFNAMSIZ); 1473 error = uiomove((caddr_t)&ifr, sizeof ifr, &uio); 1474 if (error != 0) 1475 return (error); 1476 } 1477 1478 ifc.ifc_len -= uio.uio_resid; 1479 error = copyout(&ifc, uifc, sizeof ifc); 1480 1481 return (error); 1482 } 1483 1484 static int 1485 linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr) 1486 { 1487 l_short flags; 1488 1489 flags = ifp->if_flags; 1490 /* these flags have no Linux equivalent */ 1491 flags &= ~(IFF_SMART|IFF_OACTIVE|IFF_SIMPLEX| 1492 IFF_LINK0|IFF_LINK1|IFF_LINK2); 1493 /* Linux' multicast flag is in a different bit */ 1494 if (flags & IFF_MULTICAST) { 1495 flags &= ~IFF_MULTICAST; 1496 flags |= 0x1000; 1497 } 1498 1499 return (copyout(&flags, &ifr->ifr_flags, sizeof flags)); 1500 } 1501 1502 #define ARPHRD_ETHER 1 1503 #define ARPHRD_LOOPBACK 772 1504 1505 static int 1506 linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr) 1507 { 1508 struct ifaddr *ifa; 1509 struct sockaddr_dl *sdl; 1510 struct l_sockaddr lsa; 1511 1512 if (ifp->if_type == IFT_LOOP) { 1513 bzero(&lsa, sizeof lsa); 1514 lsa.sa_family = ARPHRD_LOOPBACK; 1515 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa)); 1516 } 1517 1518 if (ifp->if_type != IFT_ETHER) 1519 return (ENOENT); 1520 1521 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1522 sdl = (struct sockaddr_dl*)ifa->ifa_addr; 1523 if (sdl != NULL && (sdl->sdl_family == AF_LINK) && 1524 (sdl->sdl_type == IFT_ETHER)) { 1525 bzero(&lsa, sizeof lsa); 1526 lsa.sa_family = ARPHRD_ETHER; 1527 bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN); 1528 return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof lsa)); 1529 } 1530 } 1531 1532 return (ENOENT); 1533 } 1534 1535 /* 1536 * Socket related ioctls 1537 */ 1538 1539 static int 1540 linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args) 1541 { 1542 char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ]; 1543 struct ifnet *ifp; 1544 int error; 1545 1546 KASSERT(LINUX_IFNAMSIZ == IFNAMSIZ, 1547 (__FUNCTION__ "(): LINUX_IFNAMSIZ != IFNAMSIZ")); 1548 1549 ifp = NULL; 1550 error = 0; 1551 1552 switch (args->cmd & 0xffff) { 1553 1554 case LINUX_FIOGETOWN: 1555 case LINUX_FIOSETOWN: 1556 case LINUX_SIOCADDMULTI: 1557 case LINUX_SIOCATMARK: 1558 case LINUX_SIOCDELMULTI: 1559 case LINUX_SIOCGIFCONF: 1560 case LINUX_SIOCGPGRP: 1561 case LINUX_SIOCSPGRP: 1562 /* these ioctls don't take an interface name */ 1563 #ifdef DEBUG 1564 printf(__FUNCTION__ "(): ioctl %d\n", 1565 args->cmd & 0xffff); 1566 #endif 1567 break; 1568 1569 case LINUX_SIOCGIFFLAGS: 1570 case LINUX_SIOCGIFADDR: 1571 case LINUX_SIOCGIFDSTADDR: 1572 case LINUX_SIOCGIFBRDADDR: 1573 case LINUX_SIOCGIFNETMASK: 1574 case LINUX_SIOCSIFNETMASK: 1575 case LINUX_SIOCGIFMTU: 1576 case LINUX_SIOCSIFMTU: 1577 case LINUX_SIOCSIFNAME: 1578 case LINUX_SIOCGIFHWADDR: 1579 case LINUX_SIOCSIFHWADDR: 1580 case LINUX_SIOCDEVPRIVATE: 1581 case LINUX_SIOCDEVPRIVATE+1: 1582 /* copy in the interface name and translate it. */ 1583 error = copyin((char *)args->arg, lifname, LINUX_IFNAMSIZ); 1584 if (error != 0) 1585 return (error); 1586 #ifdef DEBUG 1587 printf(__FUNCTION__ "(): ioctl %d on %.*s\n", 1588 args->cmd & 0xffff, LINUX_IFNAMSIZ, lifname); 1589 #endif 1590 ifp = ifname_linux_to_bsd(lifname, ifname); 1591 if (ifp == NULL) 1592 return (EINVAL); 1593 /* 1594 * We need to copy it back out in case we pass the 1595 * request on to our native ioctl(), which will expect 1596 * the ifreq to be in user space and have the correct 1597 * interface name. 1598 */ 1599 error = copyout(ifname, (char *)args->arg, IFNAMSIZ); 1600 if (error != 0) 1601 return (error); 1602 #ifdef DEBUG 1603 printf(__FUNCTION__ "(): %s translated to %s\n", 1604 lifname, ifname); 1605 #endif 1606 break; 1607 1608 default: 1609 return (ENOIOCTL); 1610 } 1611 1612 switch (args->cmd & 0xffff) { 1613 1614 case LINUX_FIOSETOWN: 1615 args->cmd = FIOSETOWN; 1616 error = ioctl(td, (struct ioctl_args *)args); 1617 break; 1618 1619 case LINUX_SIOCSPGRP: 1620 args->cmd = SIOCSPGRP; 1621 error = ioctl(td, (struct ioctl_args *)args); 1622 break; 1623 1624 case LINUX_FIOGETOWN: 1625 args->cmd = FIOGETOWN; 1626 error = ioctl(td, (struct ioctl_args *)args); 1627 break; 1628 1629 case LINUX_SIOCGPGRP: 1630 args->cmd = SIOCGPGRP; 1631 error = ioctl(td, (struct ioctl_args *)args); 1632 break; 1633 1634 case LINUX_SIOCATMARK: 1635 args->cmd = SIOCATMARK; 1636 error = ioctl(td, (struct ioctl_args *)args); 1637 break; 1638 1639 /* LINUX_SIOCGSTAMP */ 1640 1641 case LINUX_SIOCGIFCONF: 1642 error = linux_ifconf(td, (struct ifconf *)args->arg); 1643 break; 1644 1645 case LINUX_SIOCGIFFLAGS: 1646 args->cmd = SIOCGIFFLAGS; 1647 error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg); 1648 break; 1649 1650 case LINUX_SIOCGIFADDR: 1651 args->cmd = OSIOCGIFADDR; 1652 error = ioctl(td, (struct ioctl_args *)args); 1653 break; 1654 1655 case LINUX_SIOCGIFDSTADDR: 1656 args->cmd = OSIOCGIFDSTADDR; 1657 error = ioctl(td, (struct ioctl_args *)args); 1658 break; 1659 1660 case LINUX_SIOCGIFBRDADDR: 1661 args->cmd = OSIOCGIFBRDADDR; 1662 error = ioctl(td, (struct ioctl_args *)args); 1663 break; 1664 1665 case LINUX_SIOCGIFNETMASK: 1666 args->cmd = OSIOCGIFNETMASK; 1667 error = ioctl(td, (struct ioctl_args *)args); 1668 break; 1669 1670 case LINUX_SIOCSIFNETMASK: 1671 error = ENOIOCTL; 1672 break; 1673 1674 case LINUX_SIOCGIFMTU: 1675 args->cmd = SIOCGIFMTU; 1676 error = ioctl(td, (struct ioctl_args *)args); 1677 break; 1678 1679 case LINUX_SIOCSIFMTU: 1680 args->cmd = SIOCSIFMTU; 1681 error = ioctl(td, (struct ioctl_args *)args); 1682 break; 1683 1684 case LINUX_SIOCSIFNAME: 1685 error = ENOIOCTL; 1686 break; 1687 1688 case LINUX_SIOCGIFHWADDR: 1689 error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg); 1690 break; 1691 1692 case LINUX_SIOCSIFHWADDR: 1693 error = ENOIOCTL; 1694 break; 1695 1696 case LINUX_SIOCADDMULTI: 1697 args->cmd = SIOCADDMULTI; 1698 error = ioctl(td, (struct ioctl_args *)args); 1699 break; 1700 1701 case LINUX_SIOCDELMULTI: 1702 args->cmd = SIOCDELMULTI; 1703 error = ioctl(td, (struct ioctl_args *)args); 1704 break; 1705 1706 /* 1707 * XXX This is slightly bogus, but these ioctls are currently 1708 * XXX only used by the aironet (if_an) network driver. 1709 */ 1710 case LINUX_SIOCDEVPRIVATE: 1711 args->cmd = SIOCGPRIVATE_0; 1712 error = ioctl(td, (struct ioctl_args *)args); 1713 break; 1714 1715 case LINUX_SIOCDEVPRIVATE+1: 1716 args->cmd = SIOCGPRIVATE_1; 1717 error = ioctl(td, (struct ioctl_args *)args); 1718 break; 1719 } 1720 1721 if (ifp != NULL) 1722 /* restore the original interface name */ 1723 copyout(lifname, (char *)args->arg, LINUX_IFNAMSIZ); 1724 1725 #ifdef DEBUG 1726 printf(__FUNCTION__ "(): returning %d\n", error); 1727 #endif 1728 return (error); 1729 } 1730 1731 /* 1732 * Device private ioctl handler 1733 */ 1734 static int 1735 linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args) 1736 { 1737 struct filedesc *fdp; 1738 struct file *fp; 1739 int type; 1740 1741 /* XXX is it sufficient to PROC_LOCK td->td_proc? */ 1742 mtx_lock(&Giant); 1743 fdp = td->td_proc->p_fd; 1744 if (args->fd >= fdp->fd_nfiles || 1745 (fp = fdp->fd_ofiles[args->fd]) == NULL) { 1746 mtx_unlock(&Giant); 1747 return (EBADF); 1748 } else { 1749 type = fp->f_type; 1750 } 1751 mtx_unlock(&Giant); 1752 if (type == DTYPE_SOCKET) 1753 return (linux_ioctl_socket(td, args)); 1754 return (ioctl(td, (struct ioctl_args *)args)); 1755 } 1756 1757 /* 1758 * main ioctl syscall function 1759 */ 1760 1761 int 1762 linux_ioctl(struct thread *td, struct linux_ioctl_args *args) 1763 { 1764 struct filedesc *fdp; 1765 struct file *fp; 1766 struct handler_element *he; 1767 int error, cmd; 1768 1769 #ifdef DEBUG 1770 if (ldebug(ioctl)) 1771 printf(ARGS(ioctl, "%d, %04lx, *"), args->fd, args->cmd); 1772 #endif 1773 1774 fdp = td->td_proc->p_fd; 1775 if ((unsigned)args->fd >= fdp->fd_nfiles) 1776 return (EBADF); 1777 fp = fdp->fd_ofiles[args->fd]; 1778 if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0) 1779 return (EBADF); 1780 1781 /* Iterate over the ioctl handlers */ 1782 cmd = args->cmd & 0xffff; 1783 TAILQ_FOREACH(he, &handlers, list) { 1784 if (cmd >= he->low && cmd <= he->high) { 1785 error = (*he->func)(td, args); 1786 if (error != ENOIOCTL) 1787 return (error); 1788 } 1789 } 1790 1791 printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n", 1792 args->fd, (int)(args->cmd & 0xffff), 1793 (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff)); 1794 1795 return (EINVAL); 1796 } 1797 1798 int 1799 linux_ioctl_register_handler(struct linux_ioctl_handler *h) 1800 { 1801 struct handler_element *he, *cur; 1802 1803 if (h == NULL || h->func == NULL) 1804 return (EINVAL); 1805 1806 /* 1807 * Reuse the element if the handler is already on the list, otherwise 1808 * create a new element. 1809 */ 1810 TAILQ_FOREACH(he, &handlers, list) { 1811 if (he->func == h->func) 1812 break; 1813 } 1814 if (he == NULL) { 1815 MALLOC(he, struct handler_element *, sizeof(*he), 1816 M_LINUX, M_WAITOK); 1817 he->func = h->func; 1818 } else 1819 TAILQ_REMOVE(&handlers, he, list); 1820 1821 /* Initialize range information. */ 1822 he->low = h->low; 1823 he->high = h->high; 1824 he->span = h->high - h->low + 1; 1825 1826 /* Add the element to the list, sorted on span. */ 1827 TAILQ_FOREACH(cur, &handlers, list) { 1828 if (cur->span > he->span) { 1829 TAILQ_INSERT_BEFORE(cur, he, list); 1830 return (0); 1831 } 1832 } 1833 TAILQ_INSERT_TAIL(&handlers, he, list); 1834 1835 return (0); 1836 } 1837 1838 int 1839 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) 1840 { 1841 struct handler_element *he; 1842 1843 if (h == NULL || h->func == NULL) 1844 return (EINVAL); 1845 1846 TAILQ_FOREACH(he, &handlers, list) { 1847 if (he->func == h->func) { 1848 TAILQ_REMOVE(&handlers, he, list); 1849 FREE(he, M_LINUX); 1850 return (0); 1851 } 1852 } 1853 1854 return (EINVAL); 1855 } 1856