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