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/proc.h> 35 #include <sys/cdio.h> 36 #include <sys/consio.h> 37 #include <sys/fcntl.h> 38 #include <sys/file.h> 39 #include <sys/filedesc.h> 40 #include <sys/filio.h> 41 #include <sys/kbio.h> 42 #include <sys/linker_set.h> 43 #include <sys/malloc.h> 44 #include <sys/tty.h> 45 #include <sys/socket.h> 46 #include <net/if.h> 47 #include <net/if_dl.h> 48 #include <net/if_types.h> 49 #include <sys/sockio.h> 50 #include <sys/soundcard.h> 51 #include <sys/disklabel.h> 52 53 #include <machine/../linux/linux.h> 54 #include <machine/../linux/linux_proto.h> 55 56 #ifdef __alpha__ 57 #include <machine/../linux/linux_ioctl.h> 58 #else 59 #include <compat/linux/linux_ioctl.h> 60 #endif 61 #include <compat/linux/linux_mib.h> 62 #include <compat/linux/linux_util.h> 63 64 static linux_ioctl_function_t linux_ioctl_cdrom; 65 static linux_ioctl_function_t linux_ioctl_console; 66 static linux_ioctl_function_t linux_ioctl_disk; 67 static linux_ioctl_function_t linux_ioctl_socket; 68 static linux_ioctl_function_t linux_ioctl_sound; 69 static linux_ioctl_function_t linux_ioctl_termio; 70 71 static struct linux_ioctl_handler cdrom_handler = 72 { linux_ioctl_cdrom, LINUX_IOCTL_CDROM_MIN, LINUX_IOCTL_CDROM_MAX }; 73 static struct linux_ioctl_handler console_handler = 74 { linux_ioctl_console, LINUX_IOCTL_CONSOLE_MIN, LINUX_IOCTL_CONSOLE_MAX }; 75 static struct linux_ioctl_handler disk_handler = 76 { linux_ioctl_disk, LINUX_IOCTL_DISK_MIN, LINUX_IOCTL_DISK_MAX }; 77 static struct linux_ioctl_handler socket_handler = 78 { linux_ioctl_socket, LINUX_IOCTL_SOCKET_MIN, LINUX_IOCTL_SOCKET_MAX }; 79 static struct linux_ioctl_handler sound_handler = 80 { linux_ioctl_sound, LINUX_IOCTL_SOUND_MIN, LINUX_IOCTL_SOUND_MAX }; 81 static struct linux_ioctl_handler termio_handler = 82 { linux_ioctl_termio, LINUX_IOCTL_TERMIO_MIN, LINUX_IOCTL_TERMIO_MAX }; 83 84 DATA_SET(linux_ioctl_handler_set, cdrom_handler); 85 DATA_SET(linux_ioctl_handler_set, console_handler); 86 DATA_SET(linux_ioctl_handler_set, disk_handler); 87 DATA_SET(linux_ioctl_handler_set, socket_handler); 88 DATA_SET(linux_ioctl_handler_set, sound_handler); 89 DATA_SET(linux_ioctl_handler_set, termio_handler); 90 91 struct handler_element 92 { 93 TAILQ_ENTRY(handler_element) list; 94 int (*func)(struct proc *, struct linux_ioctl_args *); 95 int low, high, span; 96 }; 97 98 static TAILQ_HEAD(, handler_element) handlers = 99 TAILQ_HEAD_INITIALIZER(handlers); 100 101 static int 102 linux_ioctl_disk(struct proc *p, struct linux_ioctl_args *args) 103 { 104 struct file *fp = p->p_fd->fd_ofiles[args->fd]; 105 int error; 106 struct disklabel dl; 107 108 switch (args->cmd & 0xffff) { 109 case LINUX_BLKGETSIZE: 110 error = fo_ioctl(fp, DIOCGDINFO, (caddr_t)&dl, p); 111 if (error) 112 return (error); 113 return (copyout(&(dl.d_secperunit), (caddr_t)args->arg, 114 sizeof(dl.d_secperunit))); 115 break; 116 } 117 return (ENOIOCTL); 118 } 119 120 /* 121 * termio related ioctls 122 */ 123 124 struct linux_termio { 125 unsigned short c_iflag; 126 unsigned short c_oflag; 127 unsigned short c_cflag; 128 unsigned short c_lflag; 129 unsigned char c_line; 130 unsigned char c_cc[LINUX_NCC]; 131 }; 132 133 struct linux_termios { 134 unsigned int c_iflag; 135 unsigned int c_oflag; 136 unsigned int c_cflag; 137 unsigned int c_lflag; 138 #ifdef __alpha__ 139 unsigned char c_cc[LINUX_NCCS]; 140 unsigned char c_line; 141 unsigned int c_ispeed; 142 unsigned int c_ospeed; 143 #else 144 unsigned char c_line; 145 unsigned char c_cc[LINUX_NCCS]; 146 #endif 147 }; 148 149 struct linux_winsize { 150 unsigned short ws_row, ws_col; 151 unsigned short ws_xpixel, ws_ypixel; 152 }; 153 154 static struct speedtab sptab[] = { 155 { B0, LINUX_B0 }, { B50, LINUX_B50 }, 156 { B75, LINUX_B75 }, { B110, LINUX_B110 }, 157 { B134, LINUX_B134 }, { B150, LINUX_B150 }, 158 { B200, LINUX_B200 }, { B300, LINUX_B300 }, 159 { B600, LINUX_B600 }, { B1200, LINUX_B1200 }, 160 { B1800, LINUX_B1800 }, { B2400, LINUX_B2400 }, 161 { B4800, LINUX_B4800 }, { B9600, LINUX_B9600 }, 162 { B19200, LINUX_B19200 }, { B38400, LINUX_B38400 }, 163 { B57600, LINUX_B57600 }, { B115200, LINUX_B115200 }, 164 {-1, -1 } 165 }; 166 167 struct linux_serial_struct { 168 int type; 169 int line; 170 int port; 171 int irq; 172 int flags; 173 int xmit_fifo_size; 174 int custom_divisor; 175 int baud_base; 176 unsigned short close_delay; 177 char reserved_char[2]; 178 int hub6; 179 unsigned short closing_wait; 180 unsigned short closing_wait2; 181 int reserved[4]; 182 }; 183 184 static int 185 linux_to_bsd_speed(int code, struct speedtab *table) 186 { 187 for ( ; table->sp_code != -1; table++) 188 if (table->sp_code == code) 189 return (table->sp_speed); 190 return -1; 191 } 192 193 static int 194 bsd_to_linux_speed(int speed, struct speedtab *table) 195 { 196 for ( ; table->sp_speed != -1; table++) 197 if (table->sp_speed == speed) 198 return (table->sp_code); 199 return -1; 200 } 201 202 static void 203 bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios) 204 { 205 int i; 206 207 #ifdef DEBUG 208 if (ldebug(ioctl)) { 209 printf("LINUX: BSD termios structure (input):\n"); 210 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", 211 bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag, 212 bios->c_ispeed, bios->c_ospeed); 213 printf("c_cc "); 214 for (i=0; i<NCCS; i++) 215 printf("%02x ", bios->c_cc[i]); 216 printf("\n"); 217 } 218 #endif 219 220 lios->c_iflag = 0; 221 if (bios->c_iflag & IGNBRK) 222 lios->c_iflag |= LINUX_IGNBRK; 223 if (bios->c_iflag & BRKINT) 224 lios->c_iflag |= LINUX_BRKINT; 225 if (bios->c_iflag & IGNPAR) 226 lios->c_iflag |= LINUX_IGNPAR; 227 if (bios->c_iflag & PARMRK) 228 lios->c_iflag |= LINUX_PARMRK; 229 if (bios->c_iflag & INPCK) 230 lios->c_iflag |= LINUX_INPCK; 231 if (bios->c_iflag & ISTRIP) 232 lios->c_iflag |= LINUX_ISTRIP; 233 if (bios->c_iflag & INLCR) 234 lios->c_iflag |= LINUX_INLCR; 235 if (bios->c_iflag & IGNCR) 236 lios->c_iflag |= LINUX_IGNCR; 237 if (bios->c_iflag & ICRNL) 238 lios->c_iflag |= LINUX_ICRNL; 239 if (bios->c_iflag & IXON) 240 lios->c_iflag |= LINUX_IXON; 241 if (bios->c_iflag & IXANY) 242 lios->c_iflag |= LINUX_IXANY; 243 if (bios->c_iflag & IXOFF) 244 lios->c_iflag |= LINUX_IXOFF; 245 if (bios->c_iflag & IMAXBEL) 246 lios->c_iflag |= LINUX_IMAXBEL; 247 248 lios->c_oflag = 0; 249 if (bios->c_oflag & OPOST) 250 lios->c_oflag |= LINUX_OPOST; 251 if (bios->c_oflag & ONLCR) 252 lios->c_oflag |= LINUX_ONLCR; 253 if (bios->c_oflag & OXTABS) 254 lios->c_oflag |= LINUX_XTABS; 255 256 lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab); 257 lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4; 258 if (bios->c_cflag & CSTOPB) 259 lios->c_cflag |= LINUX_CSTOPB; 260 if (bios->c_cflag & CREAD) 261 lios->c_cflag |= LINUX_CREAD; 262 if (bios->c_cflag & PARENB) 263 lios->c_cflag |= LINUX_PARENB; 264 if (bios->c_cflag & PARODD) 265 lios->c_cflag |= LINUX_PARODD; 266 if (bios->c_cflag & HUPCL) 267 lios->c_cflag |= LINUX_HUPCL; 268 if (bios->c_cflag & CLOCAL) 269 lios->c_cflag |= LINUX_CLOCAL; 270 if (bios->c_cflag & CRTSCTS) 271 lios->c_cflag |= LINUX_CRTSCTS; 272 273 lios->c_lflag = 0; 274 if (bios->c_lflag & ISIG) 275 lios->c_lflag |= LINUX_ISIG; 276 if (bios->c_lflag & ICANON) 277 lios->c_lflag |= LINUX_ICANON; 278 if (bios->c_lflag & ECHO) 279 lios->c_lflag |= LINUX_ECHO; 280 if (bios->c_lflag & ECHOE) 281 lios->c_lflag |= LINUX_ECHOE; 282 if (bios->c_lflag & ECHOK) 283 lios->c_lflag |= LINUX_ECHOK; 284 if (bios->c_lflag & ECHONL) 285 lios->c_lflag |= LINUX_ECHONL; 286 if (bios->c_lflag & NOFLSH) 287 lios->c_lflag |= LINUX_NOFLSH; 288 if (bios->c_lflag & TOSTOP) 289 lios->c_lflag |= LINUX_TOSTOP; 290 if (bios->c_lflag & ECHOCTL) 291 lios->c_lflag |= LINUX_ECHOCTL; 292 if (bios->c_lflag & ECHOPRT) 293 lios->c_lflag |= LINUX_ECHOPRT; 294 if (bios->c_lflag & ECHOKE) 295 lios->c_lflag |= LINUX_ECHOKE; 296 if (bios->c_lflag & FLUSHO) 297 lios->c_lflag |= LINUX_FLUSHO; 298 if (bios->c_lflag & PENDIN) 299 lios->c_lflag |= LINUX_PENDIN; 300 if (bios->c_lflag & IEXTEN) 301 lios->c_lflag |= LINUX_IEXTEN; 302 303 for (i=0; i<LINUX_NCCS; i++) 304 lios->c_cc[i] = LINUX_POSIX_VDISABLE; 305 lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR]; 306 lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT]; 307 lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE]; 308 lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL]; 309 lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF]; 310 lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL]; 311 lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN]; 312 lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME]; 313 lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2]; 314 lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP]; 315 lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART]; 316 lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP]; 317 lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT]; 318 lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD]; 319 lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE]; 320 lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT]; 321 322 for (i=0; i<LINUX_NCCS; i++) { 323 if (lios->c_cc[i] == _POSIX_VDISABLE) 324 lios->c_cc[i] = LINUX_POSIX_VDISABLE; 325 } 326 lios->c_line = 0; 327 328 #ifdef DEBUG 329 if (ldebug(ioctl)) { 330 printf("LINUX: LINUX termios structure (output):\n"); 331 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 332 lios->c_iflag, lios->c_oflag, lios->c_cflag, 333 lios->c_lflag, (int)lios->c_line); 334 printf("c_cc "); 335 for (i=0; i<LINUX_NCCS; i++) 336 printf("%02x ", lios->c_cc[i]); 337 printf("\n"); 338 } 339 #endif 340 } 341 342 static void 343 linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios) 344 { 345 int i; 346 347 #ifdef DEBUG 348 if (ldebug(ioctl)) { 349 printf("LINUX: LINUX termios structure (input):\n"); 350 printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", 351 lios->c_iflag, lios->c_oflag, lios->c_cflag, 352 lios->c_lflag, (int)lios->c_line); 353 printf("c_cc "); 354 for (i=0; i<LINUX_NCCS; i++) 355 printf("%02x ", lios->c_cc[i]); 356 printf("\n"); 357 } 358 #endif 359 360 bios->c_iflag = 0; 361 if (lios->c_iflag & LINUX_IGNBRK) 362 bios->c_iflag |= IGNBRK; 363 if (lios->c_iflag & LINUX_BRKINT) 364 bios->c_iflag |= BRKINT; 365 if (lios->c_iflag & LINUX_IGNPAR) 366 bios->c_iflag |= IGNPAR; 367 if (lios->c_iflag & LINUX_PARMRK) 368 bios->c_iflag |= PARMRK; 369 if (lios->c_iflag & LINUX_INPCK) 370 bios->c_iflag |= INPCK; 371 if (lios->c_iflag & LINUX_ISTRIP) 372 bios->c_iflag |= ISTRIP; 373 if (lios->c_iflag & LINUX_INLCR) 374 bios->c_iflag |= INLCR; 375 if (lios->c_iflag & LINUX_IGNCR) 376 bios->c_iflag |= IGNCR; 377 if (lios->c_iflag & LINUX_ICRNL) 378 bios->c_iflag |= ICRNL; 379 if (lios->c_iflag & LINUX_IXON) 380 bios->c_iflag |= IXON; 381 if (lios->c_iflag & LINUX_IXANY) 382 bios->c_iflag |= IXANY; 383 if (lios->c_iflag & LINUX_IXOFF) 384 bios->c_iflag |= IXOFF; 385 if (lios->c_iflag & LINUX_IMAXBEL) 386 bios->c_iflag |= IMAXBEL; 387 388 bios->c_oflag = 0; 389 if (lios->c_oflag & LINUX_OPOST) 390 bios->c_oflag |= OPOST; 391 if (lios->c_oflag & LINUX_ONLCR) 392 bios->c_oflag |= ONLCR; 393 if (lios->c_oflag & LINUX_XTABS) 394 bios->c_oflag |= OXTABS; 395 396 bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4; 397 if (lios->c_cflag & LINUX_CSTOPB) 398 bios->c_cflag |= CSTOPB; 399 if (lios->c_cflag & LINUX_CREAD) 400 bios->c_cflag |= CREAD; 401 if (lios->c_cflag & LINUX_PARENB) 402 bios->c_cflag |= PARENB; 403 if (lios->c_cflag & LINUX_PARODD) 404 bios->c_cflag |= PARODD; 405 if (lios->c_cflag & LINUX_HUPCL) 406 bios->c_cflag |= HUPCL; 407 if (lios->c_cflag & LINUX_CLOCAL) 408 bios->c_cflag |= CLOCAL; 409 if (lios->c_cflag & LINUX_CRTSCTS) 410 bios->c_cflag |= CRTSCTS; 411 412 bios->c_lflag = 0; 413 if (lios->c_lflag & LINUX_ISIG) 414 bios->c_lflag |= ISIG; 415 if (lios->c_lflag & LINUX_ICANON) 416 bios->c_lflag |= ICANON; 417 if (lios->c_lflag & LINUX_ECHO) 418 bios->c_lflag |= ECHO; 419 if (lios->c_lflag & LINUX_ECHOE) 420 bios->c_lflag |= ECHOE; 421 if (lios->c_lflag & LINUX_ECHOK) 422 bios->c_lflag |= ECHOK; 423 if (lios->c_lflag & LINUX_ECHONL) 424 bios->c_lflag |= ECHONL; 425 if (lios->c_lflag & LINUX_NOFLSH) 426 bios->c_lflag |= NOFLSH; 427 if (lios->c_lflag & LINUX_TOSTOP) 428 bios->c_lflag |= TOSTOP; 429 if (lios->c_lflag & LINUX_ECHOCTL) 430 bios->c_lflag |= ECHOCTL; 431 if (lios->c_lflag & LINUX_ECHOPRT) 432 bios->c_lflag |= ECHOPRT; 433 if (lios->c_lflag & LINUX_ECHOKE) 434 bios->c_lflag |= ECHOKE; 435 if (lios->c_lflag & LINUX_FLUSHO) 436 bios->c_lflag |= FLUSHO; 437 if (lios->c_lflag & LINUX_PENDIN) 438 bios->c_lflag |= PENDIN; 439 if (lios->c_lflag & LINUX_IEXTEN) 440 bios->c_lflag |= IEXTEN; 441 442 for (i=0; i<NCCS; i++) 443 bios->c_cc[i] = _POSIX_VDISABLE; 444 bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR]; 445 bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT]; 446 bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE]; 447 bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL]; 448 bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF]; 449 bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL]; 450 bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN]; 451 bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME]; 452 bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2]; 453 bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP]; 454 bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART]; 455 bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP]; 456 bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT]; 457 bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD]; 458 bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE]; 459 bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT]; 460 461 for (i=0; i<NCCS; i++) { 462 if (bios->c_cc[i] == LINUX_POSIX_VDISABLE) 463 bios->c_cc[i] = _POSIX_VDISABLE; 464 } 465 466 bios->c_ispeed = bios->c_ospeed = 467 linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab); 468 469 #ifdef DEBUG 470 if (ldebug(ioctl)) { 471 printf("LINUX: BSD termios structure (output):\n"); 472 printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", 473 bios->c_iflag, bios->c_oflag, bios->c_cflag, bios->c_lflag, 474 bios->c_ispeed, bios->c_ospeed); 475 printf("c_cc "); 476 for (i=0; i<NCCS; i++) 477 printf("%02x ", bios->c_cc[i]); 478 printf("\n"); 479 } 480 #endif 481 } 482 483 static void 484 bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio) 485 { 486 struct linux_termios lios; 487 488 bsd_to_linux_termios(bios, &lios); 489 lio->c_iflag = lios.c_iflag; 490 lio->c_oflag = lios.c_oflag; 491 lio->c_cflag = lios.c_cflag; 492 lio->c_lflag = lios.c_lflag; 493 lio->c_line = lios.c_line; 494 memcpy(lio->c_cc, lios.c_cc, LINUX_NCC); 495 } 496 497 static void 498 linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios) 499 { 500 struct linux_termios lios; 501 int i; 502 503 lios.c_iflag = lio->c_iflag; 504 lios.c_oflag = lio->c_oflag; 505 lios.c_cflag = lio->c_cflag; 506 lios.c_lflag = lio->c_lflag; 507 for (i=LINUX_NCC; i<LINUX_NCCS; i++) 508 lios.c_cc[i] = LINUX_POSIX_VDISABLE; 509 memcpy(lios.c_cc, lio->c_cc, LINUX_NCC); 510 linux_to_bsd_termios(&lios, bios); 511 } 512 513 static int 514 linux_ioctl_termio(struct proc *p, struct linux_ioctl_args *args) 515 { 516 struct termios bios; 517 struct linux_termios lios; 518 struct linux_termio lio; 519 struct file *fp = p->p_fd->fd_ofiles[args->fd]; 520 int error; 521 522 switch (args->cmd & 0xffff) { 523 524 case LINUX_TCGETS: 525 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p); 526 if (error) 527 return (error); 528 bsd_to_linux_termios(&bios, &lios); 529 return copyout(&lios, (caddr_t)args->arg, sizeof(lios)); 530 531 case LINUX_TCSETS: 532 error = copyin((caddr_t)args->arg, &lios, sizeof(lios)); 533 if (error) 534 return (error); 535 linux_to_bsd_termios(&lios, &bios); 536 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p)); 537 538 case LINUX_TCSETSW: 539 error = copyin((caddr_t)args->arg, &lios, sizeof(lios)); 540 if (error) 541 return (error); 542 linux_to_bsd_termios(&lios, &bios); 543 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p)); 544 545 case LINUX_TCSETSF: 546 error = copyin((caddr_t)args->arg, &lios, sizeof(lios)); 547 if (error) 548 return (error); 549 linux_to_bsd_termios(&lios, &bios); 550 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p)); 551 552 case LINUX_TCGETA: 553 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p); 554 if (error) 555 return (error); 556 bsd_to_linux_termio(&bios, &lio); 557 return (copyout(&lio, (caddr_t)args->arg, sizeof(lio))); 558 559 case LINUX_TCSETA: 560 error = copyin((caddr_t)args->arg, &lio, sizeof(lio)); 561 if (error) 562 return (error); 563 linux_to_bsd_termio(&lio, &bios); 564 return (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, p)); 565 566 case LINUX_TCSETAW: 567 error = copyin((caddr_t)args->arg, &lio, sizeof(lio)); 568 if (error) 569 return (error); 570 linux_to_bsd_termio(&lio, &bios); 571 return (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, p)); 572 573 case LINUX_TCSETAF: 574 error = copyin((caddr_t)args->arg, &lio, sizeof(lio)); 575 if (error) 576 return (error); 577 linux_to_bsd_termio(&lio, &bios); 578 return (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, p)); 579 580 /* LINUX_TCSBRK */ 581 582 case LINUX_TCXONC: { 583 switch (args->arg) { 584 case LINUX_TCOOFF: 585 args->cmd = TIOCSTOP; 586 break; 587 case LINUX_TCOON: 588 args->cmd = TIOCSTART; 589 break; 590 case LINUX_TCIOFF: 591 case LINUX_TCION: { 592 int c; 593 struct write_args wr; 594 error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, p); 595 if (error) 596 return (error); 597 c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART; 598 c = bios.c_cc[c]; 599 if (c != _POSIX_VDISABLE) { 600 wr.fd = args->fd; 601 wr.buf = &c; 602 wr.nbyte = sizeof(c); 603 return (write(p, &wr)); 604 } else 605 return (0); 606 } 607 default: 608 return (EINVAL); 609 } 610 args->arg = 0; 611 return (ioctl(p, (struct ioctl_args *)args)); 612 } 613 614 case LINUX_TCFLSH: { 615 args->cmd = TIOCFLUSH; 616 switch (args->arg) { 617 case LINUX_TCIFLUSH: 618 args->arg = FREAD; 619 break; 620 case LINUX_TCOFLUSH: 621 args->arg = FWRITE; 622 break; 623 case LINUX_TCIOFLUSH: 624 args->arg = FREAD | FWRITE; 625 break; 626 default: 627 return (EINVAL); 628 } 629 return (ioctl(p, (struct ioctl_args *)args)); 630 } 631 632 case LINUX_TIOCEXCL: 633 args->cmd = TIOCEXCL; 634 return (ioctl(p, (struct ioctl_args *)args)); 635 636 case LINUX_TIOCNXCL: 637 args->cmd = TIOCNXCL; 638 return (ioctl(p, (struct ioctl_args *)args)); 639 640 /* LINUX_TIOCSCTTY */ 641 642 case LINUX_TIOCGPGRP: 643 args->cmd = TIOCGPGRP; 644 return (ioctl(p, (struct ioctl_args *)args)); 645 646 case LINUX_TIOCSPGRP: 647 args->cmd = TIOCSPGRP; 648 return (ioctl(p, (struct ioctl_args *)args)); 649 650 /* LINUX_TIOCOUTQ */ 651 /* LINUX_TIOCSTI */ 652 653 case LINUX_TIOCGWINSZ: 654 args->cmd = TIOCGWINSZ; 655 return (ioctl(p, (struct ioctl_args *)args)); 656 657 case LINUX_TIOCSWINSZ: 658 args->cmd = TIOCSWINSZ; 659 return (ioctl(p, (struct ioctl_args *)args)); 660 661 case LINUX_TIOCMGET: 662 args->cmd = TIOCMGET; 663 return (ioctl(p, (struct ioctl_args *)args)); 664 665 case LINUX_TIOCMBIS: 666 args->cmd = TIOCMBIS; 667 return (ioctl(p, (struct ioctl_args *)args)); 668 669 case LINUX_TIOCMBIC: 670 args->cmd = TIOCMBIC; 671 return (ioctl(p, (struct ioctl_args *)args)); 672 673 case LINUX_TIOCMSET: 674 args->cmd = TIOCMSET; 675 return (ioctl(p, (struct ioctl_args *)args)); 676 677 /* TIOCGSOFTCAR */ 678 /* TIOCSSOFTCAR */ 679 680 case LINUX_FIONREAD: /* LINUX_TIOCINQ */ 681 args->cmd = FIONREAD; 682 return (ioctl(p, (struct ioctl_args *)args)); 683 684 /* LINUX_TIOCLINUX */ 685 686 case LINUX_TIOCCONS: 687 args->cmd = TIOCCONS; 688 return (ioctl(p, (struct ioctl_args *)args)); 689 690 case LINUX_TIOCGSERIAL: { 691 struct linux_serial_struct lss; 692 lss.type = LINUX_PORT_16550A; 693 lss.flags = 0; 694 lss.close_delay = 0; 695 return copyout(&lss, (caddr_t)args->arg, sizeof(lss)); 696 } 697 698 case LINUX_TIOCSSERIAL: { 699 struct linux_serial_struct lss; 700 error = copyin((caddr_t)args->arg, &lss, sizeof(lss)); 701 if (error) 702 return (error); 703 /* XXX - It really helps to have an implementation that 704 * does nothing. NOT! 705 */ 706 return (0); 707 } 708 709 /* LINUX_TIOCPKT */ 710 711 case LINUX_FIONBIO: 712 args->cmd = FIONBIO; 713 return (ioctl(p, (struct ioctl_args *)args)); 714 715 case LINUX_TIOCNOTTY: 716 args->cmd = TIOCNOTTY; 717 return (ioctl(p, (struct ioctl_args *)args)); 718 719 case LINUX_TIOCSETD: { 720 int line; 721 switch (args->arg) { 722 case LINUX_N_TTY: 723 line = TTYDISC; 724 break; 725 case LINUX_N_SLIP: 726 line = SLIPDISC; 727 break; 728 case LINUX_N_PPP: 729 line = PPPDISC; 730 break; 731 default: 732 return (EINVAL); 733 } 734 return (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, p)); 735 } 736 737 case LINUX_TIOCGETD: { 738 int linux_line; 739 int bsd_line = TTYDISC; 740 error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line, p); 741 if (error) 742 return (error); 743 switch (bsd_line) { 744 case TTYDISC: 745 linux_line = LINUX_N_TTY; 746 break; 747 case SLIPDISC: 748 linux_line = LINUX_N_SLIP; 749 break; 750 case PPPDISC: 751 linux_line = LINUX_N_PPP; 752 break; 753 default: 754 return (EINVAL); 755 } 756 return (copyout(&linux_line, (caddr_t)args->arg, sizeof(int))); 757 } 758 759 /* LINUX_TCSBRKP */ 760 /* LINUX_TIOCTTYGSTRUCT */ 761 762 case LINUX_FIONCLEX: 763 args->cmd = FIONCLEX; 764 return (ioctl(p, (struct ioctl_args *)args)); 765 766 case LINUX_FIOCLEX: 767 args->cmd = FIOCLEX; 768 return (ioctl(p, (struct ioctl_args *)args)); 769 770 case LINUX_FIOASYNC: 771 args->cmd = FIOASYNC; 772 return (ioctl(p, (struct ioctl_args *)args)); 773 774 /* LINUX_TIOCSERCONFIG */ 775 /* LINUX_TIOCSERGWILD */ 776 /* LINUX_TIOCSERSWILD */ 777 /* LINUX_TIOCGLCKTRMIOS */ 778 /* LINUX_TIOCSLCKTRMIOS */ 779 780 } 781 782 return (ENOIOCTL); 783 } 784 785 /* 786 * CDROM related ioctls 787 */ 788 789 struct linux_cdrom_msf 790 { 791 u_char cdmsf_min0; 792 u_char cdmsf_sec0; 793 u_char cdmsf_frame0; 794 u_char cdmsf_min1; 795 u_char cdmsf_sec1; 796 u_char cdmsf_frame1; 797 }; 798 799 struct linux_cdrom_tochdr 800 { 801 u_char cdth_trk0; 802 u_char cdth_trk1; 803 }; 804 805 union linux_cdrom_addr 806 { 807 struct { 808 u_char minute; 809 u_char second; 810 u_char frame; 811 } msf; 812 int lba; 813 }; 814 815 struct linux_cdrom_tocentry 816 { 817 u_char cdte_track; 818 u_char cdte_adr:4; 819 u_char cdte_ctrl:4; 820 u_char cdte_format; 821 union linux_cdrom_addr cdte_addr; 822 u_char cdte_datamode; 823 }; 824 825 struct linux_cdrom_subchnl 826 { 827 u_char cdsc_format; 828 u_char cdsc_audiostatus; 829 u_char cdsc_adr:4; 830 u_char cdsc_ctrl:4; 831 u_char cdsc_trk; 832 u_char cdsc_ind; 833 union linux_cdrom_addr cdsc_absaddr; 834 union linux_cdrom_addr cdsc_reladdr; 835 }; 836 837 static void 838 bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp) 839 { 840 if (af == CD_LBA_FORMAT) 841 lp->lba = bp->lba; 842 else { 843 lp->msf.minute = bp->msf.minute; 844 lp->msf.second = bp->msf.second; 845 lp->msf.frame = bp->msf.frame; 846 } 847 } 848 849 static void 850 set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba) 851 { 852 if (format == LINUX_CDROM_MSF) { 853 addr->msf.frame = lba % 75; 854 lba /= 75; 855 lba += 2; 856 addr->msf.second = lba % 60; 857 addr->msf.minute = lba / 60; 858 } else 859 addr->lba = lba; 860 } 861 862 static int 863 linux_ioctl_cdrom(struct proc *p, struct linux_ioctl_args *args) 864 { 865 struct file *fp = p->p_fd->fd_ofiles[args->fd]; 866 int error; 867 868 switch (args->cmd & 0xffff) { 869 870 case LINUX_CDROMPAUSE: 871 args->cmd = CDIOCPAUSE; 872 return (ioctl(p, (struct ioctl_args *)args)); 873 874 case LINUX_CDROMRESUME: 875 args->cmd = CDIOCRESUME; 876 return (ioctl(p, (struct ioctl_args *)args)); 877 878 case LINUX_CDROMPLAYMSF: 879 args->cmd = CDIOCPLAYMSF; 880 return (ioctl(p, (struct ioctl_args *)args)); 881 882 case LINUX_CDROMPLAYTRKIND: 883 args->cmd = CDIOCPLAYTRACKS; 884 return (ioctl(p, (struct ioctl_args *)args)); 885 886 case LINUX_CDROMREADTOCHDR: { 887 struct ioc_toc_header th; 888 struct linux_cdrom_tochdr lth; 889 error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th, p); 890 if (!error) { 891 lth.cdth_trk0 = th.starting_track; 892 lth.cdth_trk1 = th.ending_track; 893 copyout(<h, (caddr_t)args->arg, sizeof(lth)); 894 } 895 return (error); 896 } 897 898 case LINUX_CDROMREADTOCENTRY: { 899 struct linux_cdrom_tocentry lte, *ltep = 900 (struct linux_cdrom_tocentry *)args->arg; 901 struct ioc_read_toc_single_entry irtse; 902 irtse.address_format = ltep->cdte_format; 903 irtse.track = ltep->cdte_track; 904 error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse, p); 905 if (!error) { 906 lte = *ltep; 907 lte.cdte_ctrl = irtse.entry.control; 908 lte.cdte_adr = irtse.entry.addr_type; 909 bsd_to_linux_msf_lba(irtse.address_format, 910 &irtse.entry.addr, <e.cdte_addr); 911 copyout(<e, (caddr_t)args->arg, sizeof(lte)); 912 } 913 return (error); 914 } 915 916 case LINUX_CDROMSTOP: 917 args->cmd = CDIOCSTOP; 918 return (ioctl(p, (struct ioctl_args *)args)); 919 920 case LINUX_CDROMSTART: 921 args->cmd = CDIOCSTART; 922 return (ioctl(p, (struct ioctl_args *)args)); 923 924 case LINUX_CDROMEJECT: 925 args->cmd = CDIOCEJECT; 926 return (ioctl(p, (struct ioctl_args *)args)); 927 928 /* LINUX_CDROMVOLCTRL */ 929 930 case LINUX_CDROMSUBCHNL: { 931 struct linux_cdrom_subchnl sc; 932 struct ioc_read_subchannel bsdsc; 933 struct cd_sub_channel_info *bsdinfo; 934 caddr_t sg = stackgap_init(); 935 bsdinfo = (struct cd_sub_channel_info*)stackgap_alloc(&sg, 936 sizeof(struct cd_sub_channel_info)); 937 bsdsc.address_format = CD_LBA_FORMAT; 938 bsdsc.data_format = CD_CURRENT_POSITION; 939 bsdsc.track = 0; 940 bsdsc.data_len = sizeof(struct cd_sub_channel_info); 941 bsdsc.data = bsdinfo; 942 error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc, p); 943 if (error) 944 return (error); 945 error = copyin((caddr_t)args->arg, &sc, 946 sizeof(struct linux_cdrom_subchnl)); 947 if (error) 948 return (error); 949 sc.cdsc_audiostatus = bsdinfo->header.audio_status; 950 sc.cdsc_adr = bsdinfo->what.position.addr_type; 951 sc.cdsc_ctrl = bsdinfo->what.position.control; 952 sc.cdsc_trk = bsdinfo->what.position.track_number; 953 sc.cdsc_ind = bsdinfo->what.position.index_number; 954 set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format, 955 bsdinfo->what.position.absaddr.lba); 956 set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format, 957 bsdinfo->what.position.reladdr.lba); 958 error = copyout(&sc, (caddr_t)args->arg, 959 sizeof(struct linux_cdrom_subchnl)); 960 return (error); 961 } 962 963 /* LINUX_CDROMREADMODE2 */ 964 /* LINUX_CDROMREADMODE1 */ 965 /* LINUX_CDROMREADAUDIO */ 966 /* LINUX_CDROMEJECT_SW */ 967 /* LINUX_CDROMMULTISESSION */ 968 /* LINUX_CDROM_GET_UPC */ 969 970 case LINUX_CDROMRESET: 971 args->cmd = CDIOCRESET; 972 return (ioctl(p, (struct ioctl_args *)args)); 973 974 /* LINUX_CDROMVOLREAD */ 975 /* LINUX_CDROMREADRAW */ 976 /* LINUX_CDROMREADCOOKED */ 977 /* LINUX_CDROMSEEK */ 978 /* LINUX_CDROMPLAYBLK */ 979 /* LINUX_CDROMREADALL */ 980 /* LINUX_CDROMCLOSETRAY */ 981 /* LINUX_CDROMLOADFROMSLOT */ 982 983 } 984 985 return (ENOIOCTL); 986 } 987 988 /* 989 * Sound related ioctls 990 */ 991 992 static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT }; 993 994 #define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30]) 995 996 static int 997 linux_ioctl_sound(struct proc *p, struct linux_ioctl_args *args) 998 { 999 1000 switch (args->cmd & 0xffff) { 1001 1002 case LINUX_SOUND_MIXER_WRITE_VOLUME: 1003 args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME); 1004 return (ioctl(p, (struct ioctl_args *)args)); 1005 1006 case LINUX_SOUND_MIXER_WRITE_BASS: 1007 args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS); 1008 return (ioctl(p, (struct ioctl_args *)args)); 1009 1010 case LINUX_SOUND_MIXER_WRITE_TREBLE: 1011 args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE); 1012 return (ioctl(p, (struct ioctl_args *)args)); 1013 1014 case LINUX_SOUND_MIXER_WRITE_SYNTH: 1015 args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH); 1016 return (ioctl(p, (struct ioctl_args *)args)); 1017 1018 case LINUX_SOUND_MIXER_WRITE_PCM: 1019 args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM); 1020 return (ioctl(p, (struct ioctl_args *)args)); 1021 1022 case LINUX_SOUND_MIXER_WRITE_SPEAKER: 1023 args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER); 1024 return (ioctl(p, (struct ioctl_args *)args)); 1025 1026 case LINUX_SOUND_MIXER_WRITE_LINE: 1027 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE); 1028 return (ioctl(p, (struct ioctl_args *)args)); 1029 1030 case LINUX_SOUND_MIXER_WRITE_MIC: 1031 args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC); 1032 return (ioctl(p, (struct ioctl_args *)args)); 1033 1034 case LINUX_SOUND_MIXER_WRITE_CD: 1035 args->cmd = SETDIR(SOUND_MIXER_WRITE_CD); 1036 return (ioctl(p, (struct ioctl_args *)args)); 1037 1038 case LINUX_SOUND_MIXER_WRITE_IMIX: 1039 args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX); 1040 return (ioctl(p, (struct ioctl_args *)args)); 1041 1042 case LINUX_SOUND_MIXER_WRITE_ALTPCM: 1043 args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM); 1044 return (ioctl(p, (struct ioctl_args *)args)); 1045 1046 case LINUX_SOUND_MIXER_WRITE_RECLEV: 1047 args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV); 1048 return (ioctl(p, (struct ioctl_args *)args)); 1049 1050 case LINUX_SOUND_MIXER_WRITE_IGAIN: 1051 args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN); 1052 return (ioctl(p, (struct ioctl_args *)args)); 1053 1054 case LINUX_SOUND_MIXER_WRITE_OGAIN: 1055 args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN); 1056 return (ioctl(p, (struct ioctl_args *)args)); 1057 1058 case LINUX_SOUND_MIXER_WRITE_LINE1: 1059 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1); 1060 return (ioctl(p, (struct ioctl_args *)args)); 1061 1062 case LINUX_SOUND_MIXER_WRITE_LINE2: 1063 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2); 1064 return (ioctl(p, (struct ioctl_args *)args)); 1065 1066 case LINUX_SOUND_MIXER_WRITE_LINE3: 1067 args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3); 1068 return (ioctl(p, (struct ioctl_args *)args)); 1069 1070 case LINUX_OSS_GETVERSION: { 1071 int version = linux_get_oss_version(p); 1072 return (copyout(&version, (caddr_t)args->arg, sizeof(int))); 1073 } 1074 1075 case LINUX_SOUND_MIXER_READ_DEVMASK: 1076 args->cmd = SOUND_MIXER_READ_DEVMASK; 1077 return (ioctl(p, (struct ioctl_args *)args)); 1078 1079 case LINUX_SNDCTL_DSP_RESET: 1080 args->cmd = SNDCTL_DSP_RESET; 1081 return (ioctl(p, (struct ioctl_args *)args)); 1082 1083 case LINUX_SNDCTL_DSP_SYNC: 1084 args->cmd = SNDCTL_DSP_SYNC; 1085 return (ioctl(p, (struct ioctl_args *)args)); 1086 1087 case LINUX_SNDCTL_DSP_SPEED: 1088 args->cmd = SNDCTL_DSP_SPEED; 1089 return (ioctl(p, (struct ioctl_args *)args)); 1090 1091 case LINUX_SNDCTL_DSP_STEREO: 1092 args->cmd = SNDCTL_DSP_STEREO; 1093 return (ioctl(p, (struct ioctl_args *)args)); 1094 1095 case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */ 1096 args->cmd = SNDCTL_DSP_GETBLKSIZE; 1097 return (ioctl(p, (struct ioctl_args *)args)); 1098 1099 case LINUX_SNDCTL_DSP_SETFMT: 1100 args->cmd = SNDCTL_DSP_SETFMT; 1101 return (ioctl(p, (struct ioctl_args *)args)); 1102 1103 case LINUX_SOUND_PCM_WRITE_CHANNELS: 1104 args->cmd = SOUND_PCM_WRITE_CHANNELS; 1105 return (ioctl(p, (struct ioctl_args *)args)); 1106 1107 case LINUX_SOUND_PCM_WRITE_FILTER: 1108 args->cmd = SOUND_PCM_WRITE_FILTER; 1109 return (ioctl(p, (struct ioctl_args *)args)); 1110 1111 case LINUX_SNDCTL_DSP_POST: 1112 args->cmd = SNDCTL_DSP_POST; 1113 return (ioctl(p, (struct ioctl_args *)args)); 1114 1115 case LINUX_SNDCTL_DSP_SUBDIVIDE: 1116 args->cmd = SNDCTL_DSP_SUBDIVIDE; 1117 return (ioctl(p, (struct ioctl_args *)args)); 1118 1119 case LINUX_SNDCTL_DSP_SETFRAGMENT: 1120 args->cmd = SNDCTL_DSP_SETFRAGMENT; 1121 return (ioctl(p, (struct ioctl_args *)args)); 1122 1123 case LINUX_SNDCTL_DSP_GETFMTS: 1124 args->cmd = SNDCTL_DSP_GETFMTS; 1125 return (ioctl(p, (struct ioctl_args *)args)); 1126 1127 case LINUX_SNDCTL_DSP_GETOSPACE: 1128 args->cmd = SNDCTL_DSP_GETOSPACE; 1129 return (ioctl(p, (struct ioctl_args *)args)); 1130 1131 case LINUX_SNDCTL_DSP_GETISPACE: 1132 args->cmd = SNDCTL_DSP_GETISPACE; 1133 return (ioctl(p, (struct ioctl_args *)args)); 1134 1135 case LINUX_SNDCTL_DSP_NONBLOCK: 1136 args->cmd = SNDCTL_DSP_NONBLOCK; 1137 return (ioctl(p, (struct ioctl_args *)args)); 1138 1139 case LINUX_SNDCTL_DSP_GETCAPS: 1140 args->cmd = SNDCTL_DSP_GETCAPS; 1141 return (ioctl(p, (struct ioctl_args *)args)); 1142 1143 case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */ 1144 args->cmd = SNDCTL_DSP_SETTRIGGER; 1145 return (ioctl(p, (struct ioctl_args *)args)); 1146 1147 case LINUX_SNDCTL_DSP_GETIPTR: 1148 args->cmd = SNDCTL_DSP_GETIPTR; 1149 return (ioctl(p, (struct ioctl_args *)args)); 1150 1151 case LINUX_SNDCTL_DSP_GETOPTR: 1152 args->cmd = SNDCTL_DSP_GETOPTR; 1153 return (ioctl(p, (struct ioctl_args *)args)); 1154 1155 case LINUX_SNDCTL_DSP_GETODELAY: 1156 args->cmd = SNDCTL_DSP_GETODELAY; 1157 return (ioctl(p, (struct ioctl_args *)args)); 1158 1159 case LINUX_SNDCTL_SEQ_RESET: 1160 args->cmd = SNDCTL_SEQ_RESET; 1161 return (ioctl(p, (struct ioctl_args *)args)); 1162 1163 case LINUX_SNDCTL_SEQ_SYNC: 1164 args->cmd = SNDCTL_SEQ_SYNC; 1165 return (ioctl(p, (struct ioctl_args *)args)); 1166 1167 case LINUX_SNDCTL_SYNTH_INFO: 1168 args->cmd = SNDCTL_SYNTH_INFO; 1169 return (ioctl(p, (struct ioctl_args *)args)); 1170 1171 case LINUX_SNDCTL_SEQ_CTRLRATE: 1172 args->cmd = SNDCTL_SEQ_CTRLRATE; 1173 return (ioctl(p, (struct ioctl_args *)args)); 1174 1175 case LINUX_SNDCTL_SEQ_GETOUTCOUNT: 1176 args->cmd = SNDCTL_SEQ_GETOUTCOUNT; 1177 return (ioctl(p, (struct ioctl_args *)args)); 1178 1179 case LINUX_SNDCTL_SEQ_GETINCOUNT: 1180 args->cmd = SNDCTL_SEQ_GETINCOUNT; 1181 return (ioctl(p, (struct ioctl_args *)args)); 1182 1183 case LINUX_SNDCTL_SEQ_PERCMODE: 1184 args->cmd = SNDCTL_SEQ_PERCMODE; 1185 return (ioctl(p, (struct ioctl_args *)args)); 1186 1187 case LINUX_SNDCTL_FM_LOAD_INSTR: 1188 args->cmd = SNDCTL_FM_LOAD_INSTR; 1189 return (ioctl(p, (struct ioctl_args *)args)); 1190 1191 case LINUX_SNDCTL_SEQ_TESTMIDI: 1192 args->cmd = SNDCTL_SEQ_TESTMIDI; 1193 return (ioctl(p, (struct ioctl_args *)args)); 1194 1195 case LINUX_SNDCTL_SEQ_RESETSAMPLES: 1196 args->cmd = SNDCTL_SEQ_RESETSAMPLES; 1197 return (ioctl(p, (struct ioctl_args *)args)); 1198 1199 case LINUX_SNDCTL_SEQ_NRSYNTHS: 1200 args->cmd = SNDCTL_SEQ_NRSYNTHS; 1201 return (ioctl(p, (struct ioctl_args *)args)); 1202 1203 case LINUX_SNDCTL_SEQ_NRMIDIS: 1204 args->cmd = SNDCTL_SEQ_NRMIDIS; 1205 return (ioctl(p, (struct ioctl_args *)args)); 1206 1207 case LINUX_SNDCTL_MIDI_INFO: 1208 args->cmd = SNDCTL_MIDI_INFO; 1209 return (ioctl(p, (struct ioctl_args *)args)); 1210 1211 case LINUX_SNDCTL_SEQ_TRESHOLD: 1212 args->cmd = SNDCTL_SEQ_TRESHOLD; 1213 return (ioctl(p, (struct ioctl_args *)args)); 1214 1215 case LINUX_SNDCTL_SYNTH_MEMAVL: 1216 args->cmd = SNDCTL_SYNTH_MEMAVL; 1217 return (ioctl(p, (struct ioctl_args *)args)); 1218 1219 } 1220 1221 return (ENOIOCTL); 1222 } 1223 1224 /* 1225 * Console related ioctls 1226 */ 1227 1228 #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) 1229 1230 static int 1231 linux_ioctl_console(struct proc *p, struct linux_ioctl_args *args) 1232 { 1233 struct file *fp = p->p_fd->fd_ofiles[args->fd]; 1234 1235 switch (args->cmd & 0xffff) { 1236 1237 case LINUX_KIOCSOUND: 1238 args->cmd = KIOCSOUND; 1239 return (ioctl(p, (struct ioctl_args *)args)); 1240 1241 case LINUX_KDMKTONE: 1242 args->cmd = KDMKTONE; 1243 return (ioctl(p, (struct ioctl_args *)args)); 1244 1245 case LINUX_KDGETLED: 1246 args->cmd = KDGETLED; 1247 return (ioctl(p, (struct ioctl_args *)args)); 1248 1249 case LINUX_KDSETLED: 1250 args->cmd = KDSETLED; 1251 return (ioctl(p, (struct ioctl_args *)args)); 1252 1253 case LINUX_KDSETMODE: 1254 args->cmd = KDSETMODE; 1255 return (ioctl(p, (struct ioctl_args *)args)); 1256 1257 case LINUX_KDGETMODE: 1258 args->cmd = KDGETMODE; 1259 return (ioctl(p, (struct ioctl_args *)args)); 1260 1261 case LINUX_KDGKBMODE: 1262 args->cmd = KDGKBMODE; 1263 return (ioctl(p, (struct ioctl_args *)args)); 1264 1265 case LINUX_KDSKBMODE: { 1266 int kbdmode; 1267 switch (args->arg) { 1268 case LINUX_KBD_RAW: 1269 kbdmode = K_RAW; 1270 break; 1271 case LINUX_KBD_XLATE: 1272 kbdmode = K_XLATE; 1273 break; 1274 case LINUX_KBD_MEDIUMRAW: 1275 kbdmode = K_RAW; 1276 break; 1277 default: 1278 return (EINVAL); 1279 } 1280 return (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode, p)); 1281 } 1282 1283 case LINUX_VT_OPENQRY: 1284 args->cmd = VT_OPENQRY; 1285 return (ioctl(p, (struct ioctl_args *)args)); 1286 1287 case LINUX_VT_GETMODE: 1288 args->cmd = VT_GETMODE; 1289 return (ioctl(p, (struct ioctl_args *)args)); 1290 1291 case LINUX_VT_SETMODE: { 1292 struct vt_mode *mode; 1293 args->cmd = VT_SETMODE; 1294 mode = (struct vt_mode *)args->arg; 1295 if (!ISSIGVALID(mode->frsig) && ISSIGVALID(mode->acqsig)) 1296 mode->frsig = mode->acqsig; 1297 return (ioctl(p, (struct ioctl_args *)args)); 1298 } 1299 1300 case LINUX_VT_GETSTATE: 1301 args->cmd = VT_GETACTIVE; 1302 return (ioctl(p, (struct ioctl_args *)args)); 1303 1304 case LINUX_VT_RELDISP: 1305 args->cmd = VT_RELDISP; 1306 return (ioctl(p, (struct ioctl_args *)args)); 1307 1308 case LINUX_VT_ACTIVATE: 1309 args->cmd = VT_ACTIVATE; 1310 return (ioctl(p, (struct ioctl_args *)args)); 1311 1312 case LINUX_VT_WAITACTIVE: 1313 args->cmd = VT_WAITACTIVE; 1314 return (ioctl(p, (struct ioctl_args *)args)); 1315 1316 } 1317 1318 return (ENOIOCTL); 1319 } 1320 1321 /* 1322 * Socket related ioctls 1323 */ 1324 1325 static int 1326 linux_ioctl_socket(struct proc *p, struct linux_ioctl_args *args) 1327 { 1328 1329 switch (args->cmd & 0xffff) { 1330 1331 case LINUX_FIOSETOWN: 1332 args->cmd = FIOSETOWN; 1333 return (ioctl(p, (struct ioctl_args *)args)); 1334 1335 case LINUX_SIOCSPGRP: 1336 args->cmd = SIOCSPGRP; 1337 return (ioctl(p, (struct ioctl_args *)args)); 1338 1339 case LINUX_FIOGETOWN: 1340 args->cmd = FIOGETOWN; 1341 return (ioctl(p, (struct ioctl_args *)args)); 1342 1343 case LINUX_SIOCGPGRP: 1344 args->cmd = SIOCGPGRP; 1345 return (ioctl(p, (struct ioctl_args *)args)); 1346 1347 case LINUX_SIOCATMARK: 1348 args->cmd = SIOCATMARK; 1349 return (ioctl(p, (struct ioctl_args *)args)); 1350 1351 /* LINUX_SIOCGSTAMP */ 1352 1353 case LINUX_SIOCGIFCONF: 1354 args->cmd = OSIOCGIFCONF; 1355 return (ioctl(p, (struct ioctl_args *)args)); 1356 1357 case LINUX_SIOCGIFFLAGS: 1358 args->cmd = SIOCGIFFLAGS; 1359 return (ioctl(p, (struct ioctl_args *)args)); 1360 1361 case LINUX_SIOCGIFADDR: 1362 args->cmd = OSIOCGIFADDR; 1363 return (ioctl(p, (struct ioctl_args *)args)); 1364 1365 case LINUX_SIOCGIFDSTADDR: 1366 args->cmd = OSIOCGIFDSTADDR; 1367 return (ioctl(p, (struct ioctl_args *)args)); 1368 1369 case LINUX_SIOCGIFBRDADDR: 1370 args->cmd = OSIOCGIFBRDADDR; 1371 return (ioctl(p, (struct ioctl_args *)args)); 1372 1373 case LINUX_SIOCGIFNETMASK: 1374 args->cmd = OSIOCGIFNETMASK; 1375 return (ioctl(p, (struct ioctl_args *)args)); 1376 1377 case LINUX_SIOCGIFHWADDR: { 1378 int ifn; 1379 struct ifnet *ifp; 1380 struct ifaddr *ifa; 1381 struct sockaddr_dl *sdl; 1382 struct linux_ifreq *ifr = (struct linux_ifreq *)args->arg; 1383 1384 /* Note that we don't actually respect the name in the ifreq 1385 * structure, as Linux interface names are all different. 1386 */ 1387 for (ifn = 0; ifn < if_index; ifn++) { 1388 ifp = ifnet_addrs[ifn]->ifa_ifp; 1389 if (ifp->if_type == IFT_ETHER) { 1390 ifa = TAILQ_FIRST(&ifp->if_addrhead); 1391 while (ifa) { 1392 sdl=(struct sockaddr_dl*)ifa->ifa_addr; 1393 if (sdl != NULL && 1394 (sdl->sdl_family == AF_LINK) && 1395 (sdl->sdl_type == IFT_ETHER)) { 1396 return (copyout(LLADDR(sdl), 1397 &ifr->ifr_hwaddr.sa_data, 1398 LINUX_IFHWADDRLEN)); 1399 } 1400 ifa = TAILQ_NEXT(ifa, ifa_link); 1401 } 1402 } 1403 } 1404 return (ENOENT); 1405 } 1406 1407 case LINUX_SIOCADDMULTI: 1408 args->cmd = SIOCADDMULTI; 1409 return (ioctl(p, (struct ioctl_args *)args)); 1410 1411 case LINUX_SIOCDELMULTI: 1412 args->cmd = SIOCDELMULTI; 1413 return (ioctl(p, (struct ioctl_args *)args)); 1414 1415 } 1416 1417 return (ENOIOCTL); 1418 } 1419 1420 /* 1421 * main ioctl syscall function 1422 */ 1423 1424 int 1425 linux_ioctl(struct proc *p, struct linux_ioctl_args *args) 1426 { 1427 struct filedesc *fdp = p->p_fd; 1428 struct file *fp; 1429 struct handler_element *he; 1430 int error, cmd; 1431 1432 #ifdef DEBUG 1433 if (ldebug(ioctl)) 1434 printf(ARGS(ioctl, "%d, %04lx, *"), args->fd, args->cmd); 1435 #endif 1436 1437 if ((unsigned)args->fd >= fdp->fd_nfiles) 1438 return (EBADF); 1439 1440 fp = fdp->fd_ofiles[args->fd]; 1441 if (fp == NULL || (fp->f_flag & (FREAD|FWRITE)) == 0) 1442 return (EBADF); 1443 1444 /* Iterate over the ioctl handlers */ 1445 cmd = args->cmd & 0xffff; 1446 TAILQ_FOREACH(he, &handlers, list) { 1447 if (cmd >= he->low && cmd <= he->high) { 1448 error = (*he->func)(p, args); 1449 if (error != ENOIOCTL) 1450 return (error); 1451 } 1452 } 1453 1454 printf("linux: 'ioctl' fd=%d, cmd=0x%x ('%c',%d) not implemented\n", 1455 args->fd, (int)(args->cmd & 0xffff), 1456 (int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff)); 1457 1458 return (EINVAL); 1459 } 1460 1461 int 1462 linux_ioctl_register_handler(struct linux_ioctl_handler *h) 1463 { 1464 struct handler_element *he, *cur; 1465 1466 if (h == NULL || h->func == NULL) 1467 return (EINVAL); 1468 1469 /* 1470 * Reuse the element if the handler is already on the list, otherwise 1471 * create a new element. 1472 */ 1473 TAILQ_FOREACH(he, &handlers, list) { 1474 if (he->func == h->func) 1475 break; 1476 } 1477 if (he == NULL) { 1478 MALLOC(he, struct handler_element *, sizeof(*he), 1479 M_LINUX, M_WAITOK); 1480 he->func = h->func; 1481 } else 1482 TAILQ_REMOVE(&handlers, he, list); 1483 1484 /* Initialize range information. */ 1485 he->low = h->low; 1486 he->high = h->high; 1487 he->span = h->high - h->low + 1; 1488 1489 /* Add the element to the list, sorted on span. */ 1490 TAILQ_FOREACH(cur, &handlers, list) { 1491 if (cur->span > he->span) { 1492 TAILQ_INSERT_BEFORE(cur, he, list); 1493 return (0); 1494 } 1495 } 1496 TAILQ_INSERT_TAIL(&handlers, he, list); 1497 1498 return (0); 1499 } 1500 1501 int 1502 linux_ioctl_unregister_handler(struct linux_ioctl_handler *h) 1503 { 1504 struct handler_element *he; 1505 1506 if (h == NULL || h->func == NULL) 1507 return (EINVAL); 1508 1509 TAILQ_FOREACH(he, &handlers, list) { 1510 if (he->func == h->func) { 1511 TAILQ_REMOVE(&handlers, he, list); 1512 FREE(he, M_LINUX); 1513 return (0); 1514 } 1515 } 1516 1517 return (EINVAL); 1518 } 1519