Chinaunix首页 | 论坛 | 博客
  • 博客访问: 20882
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-02 19:09
文章分类
文章存档

2013年(7)

我的朋友

分类: LINUX

2013-12-28 14:51:18

static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                  char *fp, int count)
{
    const unsigned char *p;
    char *f, flags = TTY_NORMAL;
    int    i;
    char    buf[64];
    unsigned long cpuflags;

    if (!tty->read_buf)//在TTY OPEN时调用n_tty_open分配
        return;

    if (tty->real_raw) {//不是real_raw
        spin_lock_irqsave(&tty->read_lock, cpuflags);
        i = min(N_TTY_BUF_SIZE - tty->read_cnt,
            N_TTY_BUF_SIZE - tty->read_head);
        i = min(count, i);
        memcpy(tty->read_buf + tty->read_head, cp, i);
        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
        tty->read_cnt += i;
        cp += i;
        count -= i;

        i = min(N_TTY_BUF_SIZE - tty->read_cnt,
            N_TTY_BUF_SIZE - tty->read_head);
        i = min(count, i);
        memcpy(tty->read_buf + tty->read_head, cp, i);
        tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
        tty->read_cnt += i;
        spin_unlock_irqrestore(&tty->read_lock, cpuflags);
    } else {
        for (i = count, p = cp, f = fp; i; i--, p++) {
            if (f)
                flags = *f++;
            switch (flags) {//当输入'l'时flags为TTY_NORMAL
            case TTY_NORMAL:
                n_tty_receive_char(tty, *p);
                break;
            case TTY_BREAK:
                n_tty_receive_break(tty);
                break;
            case TTY_PARITY:
            case TTY_FRAME:
                n_tty_receive_parity_error(tty, *p);
                break;
            case TTY_OVERRUN:
                n_tty_receive_overrun(tty);
                break;
            default:
                printk(KERN_ERR "%s: unknown flag %d\n",
                       tty_name(tty, buf), flags);
                break;
            }
        }
        if (tty->ops->flush_chars)
            tty->ops->flush_chars(tty);
    }

    n_tty_set_room(tty);

    if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
        kill_fasync(&tty->fasync, SIGIO, POLL_IN);
        if (waitqueue_active(&tty->read_wait))
            wake_up_interruptible(&tty->read_wait);
    }

    /*
     * Check the remaining room for the input canonicalization
     * mode.  We don't want to throttle the driver if we're in
     * canonical mode and don't have a newline yet!
     */
    if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
        tty_throttle(tty);
}

static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
    unsigned long flags;
    int parmrk;

    if (tty->raw) {//false
        put_tty_queue(c, tty);
        return;
    }

    if (I_ISTRIP(tty))//false
        c &= 0x7f;
    if (I_IUCLC(tty) && L_IEXTEN(tty))//I_IUCLC(tty)为false
        c = tolower(c);

    if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
        I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
        c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
        start_tty(tty);
        process_echoes(tty);
    }

    if (tty->closing) {
        if (I_IXON(tty)) {
            if (c == START_CHAR(tty)) {
                start_tty(tty);
                process_echoes(tty);
            } else if (c == STOP_CHAR(tty))
                stop_tty(tty);
        }
        return;
    }

    /*
     * If the previous character was LNEXT, or we know that this
     * character is not one of the characters that we'll have to
     * handle specially, do shortcut processing to speed things
     * up.
     */
    if (!test_bit(c, tty->process_char_map) || tty->lnext) {//输入'l'
        tty->lnext = 0;
        parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
        if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
            /* beep if no space */
            if (L_ECHO(tty))
                process_output('\a', tty);
            return;
        }
        if (L_ECHO(tty)) {//字符回显处理
            finish_erasing(tty);
            /* Record the column of first canon char. */
            if (tty->canon_head == tty->read_head)
                echo_set_canon_col(tty);
            echo_char(c, tty);//字符方式回显buf
            process_echoes(tty);//处理回显
        }
        if (parmrk)
            put_tty_queue(c, tty);
        put_tty_queue(c, tty);
        return;
    }

    if (I_IXON(tty)) {
        if (c == START_CHAR(tty)) {
            start_tty(tty);
            process_echoes(tty);
            return;
        }
        if (c == STOP_CHAR(tty)) {
            stop_tty(tty);
            return;
        }
    }

    if (L_ISIG(tty)) {
        int signal;
        signal = SIGINT;
        if (c == INTR_CHAR(tty))
            goto send_signal;
        signal = SIGQUIT;
        if (c == QUIT_CHAR(tty))
            goto send_signal;
        signal = SIGTSTP;
        if (c == SUSP_CHAR(tty)) {
send_signal:
            /*
             * Note that we do not use isig() here because we want
             * the order to be:
             * 1) flush, 2) echo, 3) signal
             */
            if (!L_NOFLSH(tty)) {
                n_tty_flush_buffer(tty);
                tty_driver_flush_buffer(tty);
            }
            if (I_IXON(tty))
                start_tty(tty);
            if (L_ECHO(tty)) {
                echo_char(c, tty);
                process_echoes(tty);
            }
            if (tty->pgrp)
                kill_pgrp(tty->pgrp, signal, 1);
            return;
        }
    }

    if (c == '\r') {
        if (I_IGNCR(tty))
            return;
        if (I_ICRNL(tty))
            c = '\n';
    } else if (c == '\n' && I_INLCR(tty))
        c = '\r';

    if (tty->icanon) {
        if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
            (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
            eraser(c, tty);
            process_echoes(tty);
            return;
        }
        if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
            tty->lnext = 1;
            if (L_ECHO(tty)) {
                finish_erasing(tty);
                if (L_ECHOCTL(tty)) {
                    echo_char_raw('^', tty);
                    echo_char_raw('\b', tty);
                    process_echoes(tty);
                }
            }
            return;
        }
        if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
            L_IEXTEN(tty)) {
            unsigned long tail = tty->canon_head;

            finish_erasing(tty);
            echo_char(c, tty);
            echo_char_raw('\n', tty);
            while (tail != tty->read_head) {
                echo_char(tty->read_buf[tail], tty);
                tail = (tail+1) & (N_TTY_BUF_SIZE-1);
            }
            process_echoes(tty);
            return;
        }
        if (c == '\n') {
            if (tty->read_cnt >= N_TTY_BUF_SIZE) {
                if (L_ECHO(tty))
                    process_output('\a', tty);
                return;
            }
            if (L_ECHO(tty) || L_ECHONL(tty)) {
                echo_char_raw('\n', tty);
                process_echoes(tty);
            }
            goto handle_newline;
        }
        if (c == EOF_CHAR(tty)) {
            if (tty->read_cnt >= N_TTY_BUF_SIZE)
                return;
            if (tty->canon_head != tty->read_head)
                set_bit(TTY_PUSH, &tty->flags);
            c = __DISABLED_CHAR;
            goto handle_newline;
        }
        if ((c == EOL_CHAR(tty)) ||
            (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
            parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
                 ? 1 : 0;
            if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
                if (L_ECHO(tty))
                    process_output('\a', tty);
                return;
            }
            /*
             * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
             */
            if (L_ECHO(tty)) {
                /* Record the column of first canon char. */
                if (tty->canon_head == tty->read_head)
                    echo_set_canon_col(tty);
                echo_char(c, tty);
                process_echoes(tty);
            }
            /*
             * XXX does PARMRK doubling happen for
             * EOL_CHAR and EOL2_CHAR?
             */
            if (parmrk)
                put_tty_queue(c, tty);

handle_newline:
            spin_lock_irqsave(&tty->read_lock, flags);
            set_bit(tty->read_head, tty->read_flags);
            put_tty_queue_nolock(c, tty);
            tty->canon_head = tty->read_head;
            tty->canon_data++;
            spin_unlock_irqrestore(&tty->read_lock, flags);
            kill_fasync(&tty->fasync, SIGIO, POLL_IN);
            if (waitqueue_active(&tty->read_wait))
                wake_up_interruptible(&tty->read_wait);
            return;
        }
    }

    parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
    if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
        /* beep if no space */
        if (L_ECHO(tty))
            process_output('\a', tty);
        return;
    }
    if (L_ECHO(tty)) {
        finish_erasing(tty);
        if (c == '\n')
            echo_char_raw('\n', tty);
        else {
            /* Record the column of first canon char. */
            if (tty->canon_head == tty->read_head)
                echo_set_canon_col(tty);
            echo_char(c, tty);
        }
        process_echoes(tty);
    }

    if (parmrk)
        put_tty_queue(c, tty);

    put_tty_queue(c, tty);
}
阅读(1178) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~