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