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