|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/base/tty.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /*- 2 * Copyright (c) 1982, 1986, 1990, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)tty.c 8.13 (Berkeley) 1/9/95 35 */ 36 37 /* Modified for Prex by Kohsuke Ohtani. */ 38 39 /* 40 * tty.c - TTY device helper 41 */ 42 43 #include <driver.h> 44 #include <sys/signal.h> 45 #include <sys/termios.h> 46 #include <tty.h> 47 #include <pm.h> 48 #include <kd.h> 49 50 /* #define DEBUG_TTY 1 */ 51 52 #ifdef DEBUG_TTY 53 #define DPRINTF(a) printf a 54 #else 55 #define DPRINTF(a) 56 #endif 57 58 #define FREAD 0x0001 59 #define FWRITE 0x0002 60 61 static void tty_output(int c, struct tty *tp); 62 63 /* default control characters */ 64 static const cc_t ttydefchars[NCCS] = TTYDEFCHARS; 65 66 #define is_ctrl(c) ((c) < 32 || (c) == 0x7f) 67 68 /* 69 * TTY queue operations 70 */ 71 #define ttyq_next(i) (((i) + 1) & (TTYQ_SIZE - 1)) 72 #define ttyq_prev(i) (((i) - 1) & (TTYQ_SIZE - 1)) 73 #define ttyq_full(q) ((q)->tq_count >= TTYQ_SIZE) 74 #define ttyq_empty(q) ((q)->tq_count == 0) 75 76 /* 77 * Get a character from a queue. 78 */ 79 int 80 tty_getc(struct tty_queue *tq) 81 { 82 char c; 83 int s; 84 85 s = splhigh(); 86 if (ttyq_empty(tq)) { 87 splx(s); 88 return -1; 89 } 90 c = tq->tq_buf[tq->tq_head]; 91 tq->tq_head = ttyq_next(tq->tq_head); 92 tq->tq_count--; 93 splx(s); 94 return (int)c; 95 } 96 97 /* 98 * Put a character into a queue. 99 */ 100 static void 101 tty_putc(int c, struct tty_queue *tq) 102 { 103 int s; 104 105 s = splhigh(); 106 if (ttyq_full(tq)) { 107 splx(s); 108 return; 109 } 110 tq->tq_buf[tq->tq_tail] = (char)(c & 0xff); 111 tq->tq_tail = ttyq_next(tq->tq_tail); 112 tq->tq_count++; 113 splx(s); 114 } 115 116 /* 117 * Remove the last character in a queue and return it. 118 */ 119 static int 120 tty_unputc(struct tty_queue *tq) 121 { 122 char c; 123 int s; 124 125 if (ttyq_empty(tq)) 126 return -1; 127 s = splhigh(); 128 tq->tq_tail = ttyq_prev(tq->tq_tail); 129 c = tq->tq_buf[tq->tq_tail]; 130 tq->tq_count--; 131 splx(s); 132 return (int)c; 133 } 134 135 /* 136 * Put the chars in the from queue on the end of the to queue. 137 */ 138 static void 139 tty_catq(struct tty_queue *from, struct tty_queue *to) 140 { 141 int c; 142 143 while ((c = tty_getc(from)) != -1) 144 tty_putc(c, to); 145 } 146 147 /* 148 * Rubout one character from the rawq of tp 149 */ 150 static void 151 tty_rubout(int c, struct tty *tp) 152 { 153 154 if (!(tp->t_lflag & ECHO)) 155 return; 156 if (tp->t_lflag & ECHOE) { 157 tty_output('\b', tp); 158 tty_output(' ', tp); 159 tty_output('\b', tp); 160 } else 161 tty_output(tp->t_cc[VERASE], tp); 162 } 163 164 /* 165 * Echo char 166 */ 167 static void 168 tty_echo(int c, struct tty *tp) 169 { 170 171 if (!(tp->t_lflag & ECHO)) { 172 if (c == '\n' && (tp->t_lflag & ECHONL)) 173 tty_output('\n', tp); 174 return; 175 } 176 if (is_ctrl(c) && c != '\n' && c != '\t' && c != '\b') { 177 tty_output('^', tp); 178 tty_output(c + 'A' - 1, tp); 179 } else 180 tty_output(c, tp); 181 } 182 183 /* 184 * Start output. 185 */ 186 static void 187 tty_start(struct tty *tp) 188 { 189 190 DPRINTF(("tty_start\n")); 191 192 if (tp->t_state & (TS_TTSTOP|TS_BUSY)) 193 return; 194 if (tp->t_oproc) 195 (*tp->t_oproc)(tp); 196 } 197 198 /* 199 * Flush tty read and/or write queues, notifying anyone waiting. 200 */ 201 static void 202 tty_flush(struct tty *tp, int rw) 203 { 204 205 DPRINTF(("tty_flush rw=%d\n", rw)); 206 207 if (rw & FREAD) { 208 while (tty_getc(&tp->t_canq) != -1) 209 ; 210 while (tty_getc(&tp->t_rawq) != -1) 211 ; 212 sched_wakeup(&tp->t_input); 213 } 214 if (rw & FWRITE) { 215 tp->t_state &= ~TS_TTSTOP; 216 tty_start(tp); 217 } 218 } 219 220 /* 221 * Output is completed. 222 */ 223 void 224 tty_done(struct tty *tp) 225 { 226 227 if (tp->t_outq.tq_count == 0) 228 tp->t_state &= ~TS_BUSY; 229 if (tp->t_state & TS_ASLEEP) { 230 tp->t_state &= ~TS_ASLEEP; 231 sched_wakeup(&tp->t_output); 232 } 233 } 234 235 /* 236 * Wait for output to drain. 237 */ 238 static void 239 tty_wait(struct tty *tp) 240 { 241 242 /* DPRINTF(("tty_wait\n")); */ 243 244 if ((tp->t_outq.tq_count > 0) && tp->t_oproc) { 245 tp->t_state |= TS_BUSY; 246 while (1) { 247 (*tp->t_oproc)(tp); 248 if ((tp->t_state & TS_BUSY) == 0) 249 break; 250 tp->t_state |= TS_ASLEEP; 251 sched_sleep(&tp->t_output); 252 } 253 } 254 } 255 256 /* 257 * Send TTY signal at DPC level. 258 */ 259 static void 260 tty_signal(void *arg) 261 { 262 struct tty *tp = arg; 263 264 DPRINTF(("tty_signal sig=%d\n", tp->t_signo)); 265 exception_post(tp->t_sigtask, tp->t_signo); 266 } 267 268 /* 269 * Process input of a single character received on a tty. 270 * echo if required. 271 * This may be called with interrupt level. 272 */ 273 void 274 tty_input(int c, struct tty *tp) 275 { 276 unsigned char *cc; 277 tcflag_t iflag, lflag; 278 int sig = -1; 279 280 DPRINTF(("tty_input: %d\n", c)); 281 282 /* Reload power management timer */ 283 pm_notify(PME_USER_ACTIVITY); 284 285 lflag = tp->t_lflag; 286 iflag = tp->t_iflag; 287 cc = tp->t_cc; 288 289 #if defined(DEBUG) && defined(CONFIG_KD) 290 if (c == cc[VDDB]) { 291 kd_enter(); 292 tty_flush(tp, FREAD | FWRITE); 293 goto endcase; 294 } 295 #endif /* !CONFIG_KD*/ 296 297 /* IGNCR, ICRNL, INLCR */ 298 if (c == '\r') { 299 if (iflag & IGNCR) 300 goto endcase; 301 else if (iflag & ICRNL) 302 c = '\n'; 303 } else if (c == '\n' && (iflag & INLCR)) 304 c = '\r'; 305 306 if (iflag & IXON) { 307 /* stop (^S) */ 308 if (c == cc[VSTOP]) { 309 if (!(tp->t_state & TS_TTSTOP)) { 310 tp->t_state |= TS_TTSTOP; 311 return; 312 } 313 if (c != cc[VSTART]) 314 return; 315 /* if VSTART == VSTOP then toggle */ 316 goto endcase; 317 } 318 /* start (^Q) */ 319 if (c == cc[VSTART]) 320 goto restartoutput; 321 } 322 if (lflag & ICANON) { 323 /* erase (^H / ^?) or backspace */ 324 if (c == cc[VERASE] || c == '\b') { 325 if (!ttyq_empty(&tp->t_rawq)) 326 tty_rubout(tty_unputc(&tp->t_rawq), tp); 327 goto endcase; 328 } 329 /* kill (^U) */ 330 if (c == cc[VKILL]) { 331 while (!ttyq_empty(&tp->t_rawq)) 332 tty_rubout(tty_unputc(&tp->t_rawq), tp); 333 goto endcase; 334 } 335 } 336 if (lflag & ISIG) { 337 /* quit (^C) */ 338 if (c == cc[VINTR] || c == cc[VQUIT]) { 339 if (!(lflag & NOFLSH)) { 340 tp->t_state |= TS_ISIG; 341 tty_flush(tp, FREAD | FWRITE); 342 } 343 tty_echo(c, tp); 344 sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT; 345 goto endcase; 346 } 347 /* suspend (^Z) */ 348 if (c == cc[VSUSP]) { 349 if (!(lflag & NOFLSH)) { 350 tp->t_state |= TS_ISIG; 351 tty_flush(tp, FREAD | FWRITE); 352 } 353 tty_echo(c, tp); 354 sig = SIGTSTP; 355 goto endcase; 356 } 357 } 358 359 /* 360 * Check for input buffer overflow 361 */ 362 if (ttyq_full(&tp->t_rawq)) { 363 tty_flush(tp, FREAD | FWRITE); 364 goto endcase; 365 } 366 tty_putc(c, &tp->t_rawq); 367 368 if (lflag & ICANON) { 369 if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) { 370 tty_catq(&tp->t_rawq, &tp->t_canq); 371 sched_wakeup(&tp->t_input); 372 } 373 } else 374 sched_wakeup(&tp->t_input); 375 376 if (lflag & ECHO) 377 tty_echo(c, tp); 378 endcase: 379 /* 380 * IXANY means allow any character to restart output. 381 */ 382 if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 && 383 cc[VSTART] != cc[VSTOP]) 384 return; 385 restartoutput: 386 tp->t_state &= ~TS_TTSTOP; 387 388 if (sig != -1) { 389 if (tp->t_sigtask) { 390 tp->t_signo = sig; 391 sched_dpc(&tp->t_dpc, &tty_signal, tp); 392 } 393 } 394 tty_start(tp); 395 } 396 397 /* 398 * Output a single character on a tty, doing output processing 399 * as needed (expanding tabs, newline processing, etc.). 400 */ 401 static void 402 tty_output(int c, struct tty *tp) 403 { 404 int i, col; 405 406 if ((tp->t_lflag & ICANON) == 0) { 407 tty_putc(c, &tp->t_outq); 408 return; 409 } 410 /* Expand tab */ 411 if (c == '\t' && (tp->t_oflag & OXTABS)) { 412 i = 8 - (tp->t_column & 7); 413 tp->t_column += i; 414 do 415 tty_putc(' ', &tp->t_outq); 416 while (--i > 0); 417 return; 418 } 419 /* Translate newline into "\r\n" */ 420 if (c == '\n' && (tp->t_oflag & ONLCR)) 421 tty_putc('\r', &tp->t_outq); 422 423 tty_putc(c, &tp->t_outq); 424 425 col = tp->t_column; 426 switch (c) { 427 case '\b': /* back space */ 428 if (col > 0) 429 --col; 430 break; 431 case '\t': /* tab */ 432 col = (col + 8) & ~7; 433 break; 434 case '\n': /* newline */ 435 col = 0; 436 break; 437 case '\r': /* return */ 438 col = 0; 439 break; 440 default: 441 if (!is_ctrl(c)) 442 ++col; 443 break; 444 } 445 tp->t_column = col; 446 return; 447 } 448 449 /* 450 * Process a read call on a tty device. 451 */ 452 int 453 tty_read(struct tty *tp, char *buf, size_t *nbyte) 454 { 455 unsigned char *cc; 456 struct tty_queue *qp; 457 int rc, tmp; 458 u_char c; 459 size_t count = 0; 460 tcflag_t lflag; 461 462 DPRINTF(("tty_read\n")); 463 464 lflag = tp->t_lflag; 465 cc = tp->t_cc; 466 qp = (lflag & ICANON) ? &tp->t_canq : &tp->t_rawq; 467 468 /* If there is no input, wait it */ 469 while (ttyq_empty(qp)) { 470 rc = sched_sleep(&tp->t_input); 471 if (rc == SLP_INTR || tp->t_state & TS_ISIG) { 472 tp->t_state &= ~TS_ISIG; 473 return EINTR; 474 } 475 } 476 while (count < *nbyte) { 477 if ((tmp = tty_getc(qp)) == -1) 478 break; 479 c = (u_char)tmp; 480 if (c == cc[VEOF] && (lflag & ICANON)) 481 break; 482 count++; 483 if (copyout(&c, buf, 1)) 484 return EFAULT; 485 if ((lflag & ICANON) && (c == '\n' || c == cc[VEOL])) 486 break; 487 buf++; 488 } 489 *nbyte = count; 490 return 0; 491 } 492 493 /* 494 * Process a write call on a tty device. 495 */ 496 int 497 tty_write(struct tty *tp, char *buf, size_t *nbyte) 498 { 499 size_t remain, count = 0; 500 u_char c; 501 502 DPRINTF(("tty_write\n")); 503 504 remain = *nbyte; 505 while (remain > 0) { 506 if (tp->t_outq.tq_count > TTYQ_HIWAT) { 507 tty_start(tp); 508 if (tp->t_outq.tq_count <= TTYQ_HIWAT) 509 continue; 510 tp->t_state |= TS_ASLEEP; 511 sched_sleep(&tp->t_output); 512 continue; 513 } 514 if (copyin(buf, &c, 1)) 515 return EFAULT; 516 tty_output((int)c, tp); 517 buf++; 518 remain--; 519 count++; 520 } 521 tty_start(tp); 522 *nbyte = count; 523 return 0; 524 } 525 526 /* 527 * Ioctls for all tty devices. 528 */ 529 int 530 tty_ioctl(struct tty *tp, u_long cmd, void *data) 531 { 532 int flags; 533 struct tty_queue *qp; 534 535 switch (cmd) { 536 case TIOCGETA: 537 if (copyout(&tp->t_termios, data, 538 sizeof(struct termios))) 539 return EFAULT; 540 break; 541 case TIOCSETAW: 542 case TIOCSETAF: 543 tty_wait(tp); 544 if (cmd == TIOCSETAF) 545 tty_flush(tp, FREAD); 546 /* FALLTHROUGH */ 547 case TIOCSETA: 548 if (copyin(data, &tp->t_termios, 549 sizeof(struct termios))) 550 return EFAULT; 551 break; 552 case TIOCSPGRP: /* set pgrp of tty */ 553 if (copyin(data, &tp->t_pgid, sizeof(pid_t))) 554 return EFAULT; 555 break; 556 case TIOCGPGRP: 557 if (copyout(&tp->t_pgid, data, sizeof(pid_t))) 558 return EFAULT; 559 break; 560 case TIOCFLUSH: 561 if (copyin(data, &flags, sizeof(flags))) 562 return EFAULT; 563 if (flags == 0) 564 flags = FREAD | FWRITE; 565 else 566 flags &= FREAD | FWRITE; 567 tty_flush(tp, flags); 568 break; 569 case TIOCSTART: 570 if (tp->t_state & TS_TTSTOP) { 571 tp->t_state &= ~TS_TTSTOP; 572 tty_start(tp); 573 } 574 break; 575 case TIOCSTOP: 576 if (!(tp->t_state & TS_TTSTOP)) { 577 tp->t_state |= TS_TTSTOP; 578 } 579 break; 580 case TIOCGWINSZ: 581 if (copyout(&tp->t_winsize, data, 582 sizeof(struct winsize))) 583 return EFAULT; 584 break; 585 case TIOCSWINSZ: 586 if (copyin(data, &tp->t_winsize, 587 sizeof(struct winsize))) 588 return EFAULT; 589 break; 590 case TIOCSETSIGT: /* Prex */ 591 if (copyin(data, &tp->t_sigtask, sizeof(task_t))) 592 return EFAULT; 593 break; 594 case TIOCINQ: 595 qp = (tp->t_lflag & ICANON) ? &tp->t_canq : &tp->t_rawq; 596 if (copyout(&qp->tq_count, data, sizeof(int))) 597 return EFAULT; 598 break; 599 case TIOCOUTQ: 600 if (copyout(&tp->t_outq.tq_count, data, sizeof(int))) 601 return EFAULT; 602 break; 603 } 604 return 0; 605 } 606 607 /* 608 * Attach a tty to the tty list. 609 */ 610 void 611 tty_attach(struct tty *tp) 612 { 613 struct bootinfo *bi; 614 615 /* Initialize tty */ 616 memset(tp, 0, sizeof(struct tty)); 617 memcpy(&tp->t_termios.c_cc, ttydefchars, sizeof(ttydefchars)); 618 619 event_init(&tp->t_input, "TTY input"); 620 event_init(&tp->t_output, "TTY output"); 621 622 tp->t_iflag = TTYDEF_IFLAG; 623 tp->t_oflag = TTYDEF_OFLAG; 624 tp->t_cflag = TTYDEF_CFLAG; 625 tp->t_lflag = TTYDEF_LFLAG; 626 tp->t_ispeed = TTYDEF_SPEED; 627 tp->t_ospeed = TTYDEF_SPEED; 628 629 machine_bootinfo(&bi); 630 tp->t_winsize.ws_row = (u_short)bi->video.text_y; 631 tp->t_winsize.ws_col = (u_short)bi->video.text_x; 632 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |