Ejemplo n.º 1
0
/*
 * Initialize the fields of the n_tty_t struct, allocate any memory
 * you will need later, and set the tty_ldisc field of the tty.
 */
void
n_tty_attach(tty_ldisc_t *ldisc, tty_device_t *tty)
{
        /* DRIVERS {{{ */
        n_tty_t *ntty;

        KASSERT(NULL != ldisc);
        KASSERT(NULL != tty);
        KASSERT(NULL == tty->tty_ldisc);

        ntty = ldisc_to_ntty(ldisc);

        dprintf("Attaching n_tty line discipline to tty %u\n", tty->tty_id);

        kmutex_init(&ntty->ntty_rlock);
        sched_queue_init(&ntty->ntty_rwaitq);
        ntty->ntty_inbuf = (char *)kmalloc(sizeof(char) * TTY_BUF_SIZE);
        if (NULL == ntty->ntty_inbuf)
                panic("Not enough memory for n_tty input buffer\n");
        KASSERT(NULL != ntty->ntty_inbuf);

        ntty->ntty_rhead = 0;
        ntty->ntty_rawtail = 0;
        ntty->ntty_ckdtail = 0;

        tty->tty_ldisc = ldisc;

        KASSERT(n_tty_rawbuf_empty(ntty));
        KASSERT(!n_tty_rawbuf_full(ntty));
        KASSERT(n_tty_rawbuf_size(ntty) == 0);
        KASSERT(n_tty_ckdbuf_empty(ntty));
        KASSERT(n_tty_ckdbuf_size(ntty) == 0);
        /* DRIVERS }}} */
}
Ejemplo n.º 2
0
/*
 * Free any memory allocated in n_tty_attach and set the tty_ldisc
 * field of the tty.
 */
void
n_tty_detach(tty_ldisc_t *ldisc, tty_device_t *tty)
{
        /* DRIVERS {{{ */
        n_tty_t *ntty;

        KASSERT(NULL != ldisc);
        ntty = ldisc_to_ntty(ldisc);

        KASSERT(NULL != tty);
        KASSERT(tty->tty_ldisc == ldisc);
        tty->tty_ldisc = NULL;

        kfree(ntty->ntty_inbuf);
        /* DRIVERS}}} */
}
Ejemplo n.º 3
0
/*
 * Read a maximum of len bytes from the line discipline into buf. If
 * the buffer is empty, sleep until some characters appear. This might
 * be a long wait, so it's best to let the thread be cancellable.
 *
 * Then, read from the head of the buffer up to the tail, stopping at
 * len bytes or a newline character, and leaving the buffer partially
 * full if necessary. Return the number of bytes you read into the
 * buf.

 * In this function, you will be accessing the input buffer, which
 * could be modified by other threads. Make sure to make the
 * appropriate calls to ensure that no one else will modify the input
 * buffer when we are not expecting it.
 *
 * Remember to handle newline characters and CTRL-D, or ASCII 0x04,
 * properly.
 */
int
n_tty_read(tty_ldisc_t *ldisc, void *buf, int len)
{
        /* DRIVERS {{{ */
        int i;
        char *cbuf = (char *)buf;
        n_tty_t *ntty;

        KASSERT(TTY_BUF_SIZE < PAGE_SIZE);
        KASSERT(NULL != ldisc);

        ntty = ldisc_to_ntty(ldisc);

        N_TTY_ASSERT_VALID(ntty);
        KASSERT(NULL != buf);
        KASSERT(len >= 0);

        kmutex_lock(&ntty->ntty_rlock);

        if (n_tty_ckdbuf_empty(ntty)) {
                dprintf("Cooked buffer is empty. Sleeping\n");

                if (sched_cancellable_sleep_on(&ntty->ntty_rwaitq) == -EINTR) {
                        dprintf("Sleep cancelled. Returning -EINTR\n");
                        kmutex_unlock(&ntty->ntty_rlock);
                        return -EINTR;
                }
                dprintf("Woken up from sleep\n");
        }

        for (i = 0; i < len && !n_tty_ckdbuf_empty(ntty); ++i) {
                cbuf[i] = n_tty_ckdbuf_dequeue(ntty);
                if (cbuf[i] == LF) {
                        ++i;
                        break;
                } else if (cbuf[i] == EOT) {
                        break;
                }
        }

        kmutex_unlock(&ntty->ntty_rlock);

        return i;
        /* DRIVERS }}} */
        return 0;
}
Ejemplo n.º 4
0
void
n_tty_destroy(tty_ldisc_t *ldisc)
{
    KASSERT(NULL != ldisc);
    kfree(ldisc_to_ntty(ldisc));
}
Ejemplo n.º 5
0
/*
 * The tty subsystem calls this when the tty driver has received a
 * character. Now, the line discipline needs to store it in its read
 * buffer and move the read tail forward.
 *
 * Special cases to watch out for: backspaces (both ASCII characters
 * 0x08 and 0x7F should be treated as backspaces), newlines ('\r' or
 * '\n'), and full buffers.
 *
 * Return a null terminated string containing the characters which
 * need to be echoed to the screen. For a normal, printable character,
 * just the character to be echoed.
 */
const char *
n_tty_receive_char(tty_ldisc_t *ldisc, char c)
{
        /* DRIVERS{{{ */
        static const char echo_newline[] = {CR, LF, '\0'};
        static const char echo_bs[]      = {BS, SPACE, BS, '\0'};
        static const char echo_esc[]     = { '^', '\0' };
        static const char echo_null[]    = { '\0' };
        static char echo_char[]          = { ' ', '\0' };

        n_tty_t *ntty;

        KASSERT(NULL != ldisc);

        ntty = ldisc_to_ntty(ldisc);
        N_TTY_ASSERT_VALID(ntty);

        switch (c) {
                case BS:
                case DEL:
                        dprintf("Received backspace\n");
                        if (!n_tty_rawbuf_empty(ntty)) {
                                n_tty_rawbuf_remove_last(ntty);
                                return echo_bs;
                        }
                        return echo_null;
                case ESC:
                        dprintf("Received escape\n");
                        if (n_tty_rawbuf_almost_full(ntty)) return echo_null;
                        n_tty_rawbuf_enqueue(ntty, c);
                        return echo_esc;
                case CR:
                        c = LF;
                case LF:
                        dprintf("Received newline\n");
                        if (n_tty_rawbuf_full(ntty)) return echo_null;
                        n_tty_rawbuf_enqueue(ntty, c);
                        n_tty_rawbuf_cook(ntty);
                        if (!sched_queue_empty(&ntty->ntty_rwaitq)) {
                                kthread_t *thr = sched_wakeup_on(&ntty->ntty_rwaitq);
                                KASSERT(NULL != thr);
                        }
                        return echo_newline;
                case EOT:
                        dprintf("Received EOT\n");
                        n_tty_rawbuf_cook(ntty);
                        if (!sched_queue_empty(&ntty->ntty_rwaitq)) {
                                kthread_t *thr = sched_wakeup_on(&ntty->ntty_rwaitq);
                                KASSERT(NULL != thr);
                        }
                        return echo_null;
                default:
                        dprintf("Receiving printable character\n");
                        if (n_tty_rawbuf_almost_full(ntty)) return echo_null;
                        n_tty_rawbuf_enqueue(ntty, c);
                        echo_char[0] = c;
                        return echo_char;
        }

        panic("Should never get here\n");
        /* DRIVERS }}} */
        return NULL;
}