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