示例#1
0
文件: tty.c 项目: cya410/libraries
/*
 * 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);
}
示例#2
0
文件: tty.c 项目: AndrewD/prex
/*
 * 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);
}