Example #1
0
/*
 * Remove the last character in a queue and return it.
 */
static int tty_unputc(struct tty_queue *tq)
{
  if (ttyq_empty(tq))
    return -1;

  int s = splhigh();
  tq->tq_tail = ttyq_prev(tq->tq_tail);
  int c = tq->tq_buf[tq->tq_tail];
  tq->tq_count--;
  splx(s);
  return c & 0xFF;
}
Example #2
0
/*
 * Process a read call on a tty device.
 */
int tty_read(struct tty *tp, struct uio *uio, size_t *size)
{
  unsigned char *cc;
  struct tty_queue *qp;
  int rc, tmp;
  u_char c;
  tcflag_t lflag;

  DPRINTF(TTYDB_CORE, ("tty_read\n"));

  lflag = tp->t_lflag;
  cc = tp->t_cc;
  qp = (lflag & ICANON) ? &tp->t_canq : &tp->t_rawq;

  size_t total = 0;
  for (int i = 0; i < uio->iovcnt; ++i) {
    /* If there is no input, wait it */
    while (ttyq_empty(qp)) {
      rc = sem_wait(&tp->t_input);
      if ((rc != 0 && errno == EINTR) || tp->t_state & TS_ISIG) {
        tp->t_state &= ~TS_ISIG;
        return -EINTR;
      }
    }

    size_t count = 0;
    char *buf = uio->iov[i].iov_base;
    size_t nbyte = uio->iov[i].iov_len;
    while (count < nbyte) {
      if ((tmp = tty_getc(qp)) == -1)
        break;

      c = (u_char)tmp;
      if (c == cc[VEOF] && (lflag & ICANON))
        break;

      ++count;
      if (copyout(&c, buf, 1))
        return -EFAULT;

      if ((lflag & ICANON) && (c == '\n' || c == cc[VEOL]))
        break;

      ++buf;
    }

    total += count;
  }

  *size = total;
  return 0;
}
Example #3
0
File: tty.c Project: AndrewD/prex
/*
 * Process a read call on a tty device.
 */
static int
tty_read(file_t file, char *buf, size_t *nbyte, int blkno)
{
	struct tty *tp = file->priv;
	unsigned char *cc;
	struct tty_queue *qp;
	int rc, c;
	unsigned char byte;
	size_t count = 0;
	tcflag_t lflag;

	lflag = tp->t_lflag;
	cc = tp->t_cc;
	qp = (lflag & ICANON) ? &tp->t_canq : &tp->t_rawq;

	if ((file->f_flags & O_NONBLOCK) && ttyq_empty(qp))
		return EAGAIN;
	/* If there is no input, wait it */
	while (ttyq_empty(qp)) {
		rc = sched_sleep(&tp->t_input);
		if (rc == SLP_INTR)
			return EINTR;
	}
	while (count < *nbyte) {
		if ((c = ttyq_getc(qp)) == -1)
			break;
		if (c == cc[VEOF] && (lflag & ICANON))
			break;
		count++;
		byte = c;	/* for BIG_ENDIAN */
		if (umem_copyout(&byte, buf, 1))
			return EFAULT;
		if ((lflag & ICANON) && (c == '\n' || c == cc[VEOL]))
			break;
		buf++;
	}
	*nbyte = count;
	return 0;
}
Example #4
0
/*
 * Get a character from a queue.
 */
int tty_getc(struct tty_queue *tq)
{
  int s = splhigh();
  if (ttyq_empty(tq)) {
    splx(s);
    return -1;
  }

  int c = tq->tq_buf[tq->tq_head];
  tq->tq_head = ttyq_next(tq->tq_head);
  tq->tq_count--;
  splx(s);
  return c & 0xFF;
}
Example #5
0
File: tty.c Project: AndrewD/prex
/*
 * Remove the last character in a queue and return it.
 */
int
ttyq_unputc(struct tty_queue *tq)
{
	int c;

	if (ttyq_empty(tq))
		return -1;
	irq_lock();
	tq->tq_tail = ttyq_prev(tq->tq_tail);
	c = tq->tq_buf[tq->tq_tail];
	tq->tq_count--;
	irq_unlock();
	return c;
}
Example #6
0
File: tty.c Project: AndrewD/prex
/*
 * Get a character from a queue.
 */
int
ttyq_getc(struct tty_queue *tq)
{
	int c;

	irq_lock();
	if (ttyq_empty(tq)) {
		irq_unlock();
		return -1;
	}
	c = tq->tq_buf[tq->tq_head];
	tq->tq_head = ttyq_next(tq->tq_head);
	tq->tq_count--;
	irq_unlock();
	return c;
}
Example #7
0
/*
 * 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);
}
Example #8
0
File: tty.c Project: 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);
}