/* * Process input of a single character received on a tty. * echo if required. * This may be called with interrupt level. */ void tty_input(int c, struct tty *tp) { unsigned char *cc; tcflag_t iflag, lflag; int sig = -1; DPRINTF(TTYDB_CORE, ("tty_input: %d\n", c)); // Reload power management timer */ pm_notify(PME_USER_ACTIVITY); lflag = tp->t_lflag; iflag = tp->t_iflag; cc = tp->t_cc; #if defined(DEBUG) && defined(CONFIG_KD) if (c == cc[VDDB]) { kd_enter(); tty_flush(tp, FREAD | FWRITE); goto endcase; } #endif /* !CONFIG_KD*/ /* IGNCR, ICRNL, INLCR */ if (c == '\r') { if (iflag & IGNCR) goto endcase; else if (iflag & ICRNL) c = '\n'; } else if (c == '\n' && (iflag & INLCR)) { c = '\r'; } if (iflag & IXON) { /* stop (^S) */ if (c == cc[VSTOP]) { if (!(tp->t_state & TS_TTSTOP)) { tp->t_state |= TS_TTSTOP; return; } if (c != cc[VSTART]) return; /* if VSTART == VSTOP then toggle */ goto endcase; } /* start (^Q) */ if (c == cc[VSTART]) goto restartoutput; } if (lflag & ICANON) { /* erase (^H / ^?) or backspace */ if (c == cc[VERASE] || c == '\b') { if (!ttyq_empty(&tp->t_rawq)) tty_rubout(tty_unputc(&tp->t_rawq), tp); goto endcase; } /* kill (^U) */ if (c == cc[VKILL]) { while (!ttyq_empty(&tp->t_rawq)) tty_rubout(tty_unputc(&tp->t_rawq), tp); goto endcase; } } if (lflag & ISIG) { /* quit (^C) */ if (c == cc[VINTR] || c == cc[VQUIT]) { if (!(lflag & NOFLSH)) { tp->t_state |= TS_ISIG; tty_flush(tp, FREAD | FWRITE); } tty_echo(c, tp); sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT; goto endcase; } /* suspend (^Z) */ if (c == cc[VSUSP]) { if (!(lflag & NOFLSH)) { tp->t_state |= TS_ISIG; tty_flush(tp, FREAD | FWRITE); } tty_echo(c, tp); sig = SIGTSTP; goto endcase; } } /* * Check for input buffer overflow */ if (ttyq_full(&tp->t_rawq)) { tty_flush(tp, FREAD | FWRITE); goto endcase; } tty_putc(c, &tp->t_rawq); if (lflag & ICANON) { if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) { tty_catq(&tp->t_rawq, &tp->t_canq); sem_post(&tp->t_input); } } else { sem_post(&tp->t_input); } if (lflag & ECHO) tty_echo(c, tp); endcase: /* * IXANY means allow any character to restart output. */ if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 && cc[VSTART] != cc[VSTOP]) return; restartoutput: tp->t_state &= ~TS_TTSTOP; if (sig != -1) { if (tp->t_pid) { tp->t_signo = sig; sched_dpc(&tp->t_dpc, &tty_signal, tp); } } tty_start(tp); }
/* * Process input of a single character received on a tty. * echo if required. * This may be called with interrupt level. */ void tty_input(int c, struct tty *tp) { unsigned char *cc; tcflag_t iflag, lflag; int sig = -1; #ifdef CONFIG_CPUFREQ /* Reload power management timer */ pm_active(); #endif lflag = tp->t_lflag; iflag = tp->t_iflag; cc = tp->t_cc; /* IGNCR, ICRNL, INLCR */ if (c == '\r') { if (iflag & IGNCR) goto endcase; else if (iflag & ICRNL) c = '\n'; } else if (c == '\n' && (iflag & INLCR)) c = '\r'; if (iflag & IXON) { /* stop (^S) */ if (c == cc[VSTOP]) { if (!(tp->t_state & TS_TTSTOP)) { tp->t_state |= TS_TTSTOP; return; } if (c != cc[VSTART]) return; /* if VSTART == VSTOP then toggle */ goto endcase; } /* start (^Q) */ if (c == cc[VSTART]) goto restartoutput; } if (lflag & ICANON) { /* erase (^H / ^?) or backspace */ if (c == cc[VERASE] || c == '\b') { if (!ttyq_empty(&tp->t_rawq)) { ttyq_unputc(&tp->t_rawq); tty_rubout(tp); } goto endcase; } /* kill (^U) */ if (c == cc[VKILL]) { while (!ttyq_empty(&tp->t_rawq)) { ttyq_unputc(&tp->t_rawq); tty_rubout(tp); } goto endcase; } } if (lflag & ISIG) { /* quit (^C) */ if (c == cc[VINTR] || c == cc[VQUIT]) { if (!(lflag & NOFLSH)) tty_flush(tp, FREAD | FWRITE); tty_echo(c, tp); sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT; goto endcase; } /* suspend (^Z) */ if (c == cc[VSUSP]) { if (!(lflag & NOFLSH)) tty_flush(tp, FREAD | FWRITE); tty_echo(c, tp); sig = SIGTSTP; goto endcase; } } /* * Check for input buffer overflow */ if (ttyq_full(&tp->t_rawq)) { tty_flush(tp, FREAD | FWRITE); goto endcase; } ttyq_putc(c, &tp->t_rawq); if (lflag & ICANON) { if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) { tty_catq(&tp->t_rawq, &tp->t_canq); sched_wakeup(&tp->t_input); } } else sched_wakeup(&tp->t_input); if (lflag & ECHO) tty_echo(c, tp); endcase: /* * IXANY means allow any character to restart output. */ if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 && cc[VSTART] != cc[VSTOP]) return; restartoutput: tp->t_state &= ~TS_TTSTOP; if (sig != -1) { if (sig_task) exception_post(sig_task, sig); } tty_start(tp); }