Exemple #1
0
/*
 * Rubout one character from the rawq of tp
 */
static void tty_rubout(int c, struct tty *tp)
{
  if (!(tp->t_lflag & ECHO))
    return;

  if (tp->t_lflag & ECHOE) {
    tty_output('\b', tp);
    tty_output(' ', tp);
    tty_output('\b', tp);
  } else {
    tty_output(tp->t_cc[VERASE], tp);
  }
}
Exemple #2
0
static void tty_echo_erase(struct tty *t) {
	cc_t *cc = t->termios.c_cc;

	if (!TC_L(t, ECHO))
		return;

	/* See also http://users.sosdg.org/~qiyong/mxr/source/drivers/tty/tty.c#L1430
	 * as example of how ECHOE flag is handled in Minix. */
	if (!TC_L(t, ECHOE))
		tty_output(t, cc[VERASE]);

	else
		for (char *ch = "\b \b"; *ch; ++ch)
			tty_output(t, *ch);
}
Exemple #3
0
/*
 * Echo char
 */
static void tty_echo(int c, struct tty *tp)
{
  if (!(tp->t_lflag & ECHO)) {
    if (c == '\n' && (tp->t_lflag & ECHONL))
      tty_output('\n', tp);
    return;
  }

  if (is_ctrl(c) && c != '\n' && c != '\t' && c != '\b') {
    tty_output('^', tp);
    tty_output(c + 'A' - 1, tp);
  } else {
    tty_output(c, tp);
  }
}
Exemple #4
0
static int tty_blockin_output(struct tty *t, char ch) {
	struct idesc_wait_link iwl;
	int ret;

	idesc_wait_init(&iwl, POLLOUT | POLLERR);

	do {
		if (tty_output(t, ch))
			return 0;

		if (!t->idesc)
			return -EBADF;

		ret = idesc_wait_prepare(t->idesc, &iwl);
		if (!ret) {
			mutex_unlock(&t->lock);

			tty_out_wake(t);
			ret = sched_wait();

			mutex_lock(&t->lock);
		}
		idesc_wait_cleanup(t->idesc, &iwl);
	} while (!ret);

	return ret;
}
Exemple #5
0
/*
 * Process a write call on a tty device.
 */
static int
tty_write(file_t file, char *buf, size_t *nbyte, int blkno)
{
	struct tty *tp = file->priv;
	size_t remain, count = 0;
	unsigned char c;	/* must be char (not int) for BIG ENDIAN */

	DPRINTF(("tty_write\n"));

	remain = *nbyte;
	while (remain > 0) {
		if (tp->t_outq.tq_count > TTYQ_HIWAT) {
			tty_start(tp);
			if (tp->t_outq.tq_count <= TTYQ_HIWAT)
				continue;
			tp->t_state |= TS_ASLEEP;
			sched_sleep(&tp->t_output);
			continue;
		}
		if (umem_copyin(buf, &c, 1))
			return EFAULT;
		tty_output(c, tp);
		buf++;
		remain--;
		count++;
	}
	tty_start(tp);
	*nbyte = count;
	return 0;
}
Exemple #6
0
/*
 * Process a write call on a tty device.
 */
int tty_write(struct tty *tp, struct uio *uio, size_t *size)
{
  u_char c;

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

  size_t total = 0;
  for (int i = 0; i < uio->iovcnt; ++i) {
    size_t count = 0;
    char *buf = uio->iov[i].iov_base;
    size_t nbyte = uio->iov[i].iov_len;
    while (nbyte > 0) {
      if (tp->t_outq.tq_count > TTYQ_HIWAT) {
        tty_start(tp);
        if (tp->t_outq.tq_count <= TTYQ_HIWAT)
          continue;

        tp->t_state |= TS_ASLEEP;
        sem_wait(&tp->t_output);
        continue;
      }

      if (copyin(buf, &c, 1))
        return -EFAULT;

      tty_output((int)c, tp);
      ++buf;
      --nbyte;
      ++count;
    }

    total += count;
  }

  tty_start(tp);
  *size = total;
  return 0;
}
Exemple #7
0
/*
 * Set TTY status.
 * No locks may be held.
 * Calls device start or stop routines; must already be on master if
 * device needs to run on master.
 */
io_return_t tty_set_status(
	register struct tty *tp,
	dev_flavor_t	flavor,
	int *		data,
	natural_t	count)
{
	int	s;

	switch (flavor) {
	    case TTY_FLUSH:
	    {
		register int	flags;
		if (count < TTY_FLUSH_COUNT)
		    return D_INVALID_OPERATION;

		flags = *data;
		if (flags == 0)
		    flags = D_READ | D_WRITE;

		s = spltty();
		simple_lock(&tp->t_lock);
		tty_flush(tp, flags);
		simple_unlock(&tp->t_lock);
		splx(s);

		break;
	    }
	    case TTY_STOP:
		/* stop output */
		s = spltty();
		simple_lock(&tp->t_lock);
		if ((tp->t_state & TS_TTSTOP) == 0) {
		    tp->t_state |= TS_TTSTOP;
		    (*tp->t_stop)(tp, 0);
		}
		simple_unlock(&tp->t_lock);
		splx(s);
		break;

	    case TTY_START:
		/* start output */
		s = spltty();
		simple_lock(&tp->t_lock);
		if (tp->t_state & TS_TTSTOP) {
		    tp->t_state &= ~TS_TTSTOP;
		    tty_output(tp);
		}
		simple_unlock(&tp->t_lock);
		splx(s);
		break;

	    case TTY_STATUS:
		/* set special characters and speed */
	    {
		register struct tty_status *tsp;

		if (count < TTY_STATUS_COUNT)
		    return D_INVALID_OPERATION;

		tsp = (struct tty_status *)data;

		if (tsp->tt_ispeed < 0 ||
		    tsp->tt_ispeed >= NSPEEDS ||
		    tsp->tt_ospeed < 0 ||
		    tsp->tt_ospeed >= NSPEEDS)
		{
		    return D_INVALID_OPERATION;
		}

		s = spltty();
		simple_lock(&tp->t_lock);

		tp->t_ispeed = tsp->tt_ispeed;
		tp->t_ospeed = tsp->tt_ospeed;
		tp->t_breakc = tsp->tt_breakc;
		tp->t_flags  = tsp->tt_flags & ~TF_HUPCLS;
		if (tsp->tt_flags & TF_HUPCLS)
		    tp->t_state |= TS_HUPCLS;

		simple_unlock(&tp->t_lock);
		splx(s);
		break;
	    }
	    default:
		return D_INVALID_OPERATION;
	}
	return D_SUCCESS;
}
Exemple #8
0
/*
 * Write to TTY.
 * No locks may be held.
 * Calls device start routine; must already be on master if
 * device needs to run on master.
 */
io_return_t char_write(
	register struct tty *	tp,
	register io_req_t	ior)
{
	spl_t		s;
	register int	count;
	register char	*data;
	vm_offset_t	addr;
	io_return_t	rc = D_SUCCESS;

	data  = ior->io_data;
	count = ior->io_count;
	if (count == 0)
	    return rc;

	if (!(ior->io_op & IO_INBAND)) {
	    /*
	     * Copy out-of-line data into kernel address space.
	     * Since data is copied as page list, it will be
	     * accessible.
	     */
	    vm_map_copy_t copy = (vm_map_copy_t) data;
	    kern_return_t kr;

	    kr = vm_map_copyout(device_io_map, &addr, copy);
	    if (kr != KERN_SUCCESS)
		return kr;
	    data = (char *) addr;
	}

	/*
	 * Check for tty operating.
	 */
	s = spltty();
	simple_lock(&tp->t_lock);

	if ((tp->t_state & TS_CARR_ON) == 0) {

	    if ((tp->t_state & TS_ONDELAY) == 0) {
		/*
		 * No delayed writes - tell caller that device is down
		 */
		rc = D_IO_ERROR;
		goto out;
	    }

	    if (ior->io_mode & D_NOWAIT) {
		rc = D_WOULD_BLOCK;
		goto out;
	    }
	}

	/*
	 * Copy data into the output buffer.
	 * Report the amount not copied.
	 */

	ior->io_residual = b_to_q(data, count, &tp->t_outq);

	/*
	 * Start hardware output.
	 */

	tp->t_state &= ~TS_TTSTOP;
	tty_output(tp);

	if (tp->t_outq.c_cc > TTHIWAT(tp) ||
	    (tp->t_state & TS_CARR_ON) == 0) {

	    /*
	     * Do not send reply until some characters have been sent.
	     */
	    ior->io_dev_ptr = (char *)tp;
	    queue_delayed_reply(&tp->t_delayed_write, ior, char_write_done);

	    rc = D_IO_QUEUED;
	}
out:
	simple_unlock(&tp->t_lock);
	splx(s);

	if (!(ior->io_op & IO_INBAND))
	    (void) vm_deallocate(device_io_map, addr, ior->io_count);
	return rc;
}