荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: GyeaonWoo (柏林恋人), 信区: Linux
标  题: Linus's Linux--kernel/tty_io.c
发信站: 荔园晨风BBS站 (Mon Aug 25 20:37:55 2003), 站内信件

/*
 * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
 * or rs-channels. It also implements echoing, cooked mode etc (well,
 * not currently, but ...)
 */
#include <ctype.h>
#include <errno.h>
#include <signal.h>

#define ALRMMASK (1<<(SIGALRM-1))

#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/segment.h>
#include <asm/system.h>

#define _L_FLAG(tty,f)  ((tty)->termios.c_lflag & f)
#define _I_FLAG(tty,f)  ((tty)->termios.c_iflag & f)
#define _O_FLAG(tty,f)  ((tty)->termios.c_oflag & f)

#define L_CANON(tty)    _L_FLAG((tty),ICANON)
#define L_ISIG(tty)     _L_FLAG((tty),ISIG)
#define L_ECHO(tty)     _L_FLAG((tty),ECHO)
#define L_ECHOE(tty)    _L_FLAG((tty),ECHOE)
#define L_ECHOK(tty)    _L_FLAG((tty),ECHOK)
#define L_ECHOCTL(tty)  _L_FLAG((tty),ECHOCTL)
#define L_ECHOKE(tty)   _L_FLAG((tty),ECHOKE)

#define I_UCLC(tty)     _I_FLAG((tty),IUCLC)
#define I_NLCR(tty)     _I_FLAG((tty),INLCR)
#define I_CRNL(tty)     _I_FLAG((tty),ICRNL)
#define I_NOCR(tty)     _I_FLAG((tty),IGNCR)

#define O_POST(tty)     _O_FLAG((tty),OPOST)
#define O_NLCR(tty)     _O_FLAG((tty),ONLCR)
#define O_CRNL(tty)     _O_FLAG((tty),OCRNL)
#define O_NLRET(tty)    _O_FLAG((tty),ONLRET)
#define O_LCUC(tty)     _O_FLAG((tty),OLCUC)

struct tty_struct tty_table[] = {
        {
                {0,
                OPOST|ONLCR,    /* change outgoing NL to CRNL */
                0,
                ICANON | ECHO | ECHOCTL | ECHOKE,
                0,              /* console termio */
                INIT_C_CC},
                0,                      /* initial pgrp */
                0,                      /* initial stopped */
                con_write,
                {0,0,0,0,""},           /* console read-queue */
                {0,0,0,0,""},           /* console write-queue */
                {0,0,0,0,""}            /* console secondary queue */
        },{
                {0, /*IGNCR*/
                OPOST | ONLRET,         /* change outgoing NL to CR */
                B2400 | CS8,
                0,
                0,
                INIT_C_CC},
                0,
                0,
                rs_write,
                {0x3f8,0,0,0,""},               /* rs 1 */
                {0x3f8,0,0,0,""},
                {0,0,0,0,""}
        },{
                {0, /*IGNCR*/
                OPOST | ONLRET,         /* change outgoing NL to CR */
                B2400 | CS8,
                0,
                0,
                INIT_C_CC},
                0,
                0,
                rs_write,
                {0x2f8,0,0,0,""},               /* rs 2 */
                {0x2f8,0,0,0,""},
                {0,0,0,0,""}
        }
};

/*
 * these are the tables used by the machine code handlers.
 * you can implement pseudo-tty's or something by changing
 * them. Currently not done.
 */
struct tty_queue * table_list[]={
        &tty_table[0].read_q, &tty_table[0].write_q,
        &tty_table[1].read_q, &tty_table[1].write_q,
        &tty_table[2].read_q, &tty_table[2].write_q
        };

void tty_init(void)
{
        rs_init();
        con_init();
}

void tty_intr(struct tty_struct * tty, int signal)
{
        int i;

        if (tty->pgrp <= 0)
                return;
        for (i=0;i<NR_TASKS;i++)
                if (task[i] && task[i]->pgrp==tty->pgrp)
                        task[i]->signal |= 1<<(signal-1);
}

static void sleep_if_empty(struct tty_queue * queue)
{
        cli();
        while (!current->signal && EMPTY(*queue))
                interruptible_sleep_on(&queue->proc_list);
        sti();
}

static void sleep_if_full(struct tty_queue * queue)
{
        if (!FULL(*queue))
                return;
        cli();
        while (!current->signal && LEFT(*queue)<128)
                interruptible_sleep_on(&queue->proc_list);
        sti();
}

void copy_to_cooked(struct tty_struct * tty)
{
        signed char c;

        while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
                GETCH(tty->read_q,c);
                if (c==13)
                        if (I_CRNL(tty))
                                c=10;
                        else if (I_NOCR(tty))
                                continue;
                        else ;
                else if (c==10 && I_NLCR(tty))
                        c=13;
                if (I_UCLC(tty))
                        c=tolower(c);
                if (L_CANON(tty)) {
                        if (c==ERASE_CHAR(tty)) {
                                if (EMPTY(tty->secondary) ||
                                   (c=LAST(tty->secondary))==10 ||
                                   c==EOF_CHAR(tty))
                                        continue;
                                if (L_ECHO(tty)) {
                                        if (c<32)
                                                PUTCH(127,tty->write_q);
                                        PUTCH(127,tty->write_q);
                                        tty->write(tty);
                                }
                                DEC(tty->secondary.head);
                                continue;
                        }
                        if (c==STOP_CHAR(tty)) {
                                tty->stopped=1;
                                continue;
                        }
                        if (c==START_CHAR(tty)) {
                                tty->stopped=0;
                                continue;
                        }
                }
                if (!L_ISIG(tty)) {
                        if (c==INTR_CHAR(tty)) {
                                tty_intr(tty,SIGINT);
                                continue;
                        }
                }
                if (c==10 || c==EOF_CHAR(tty))
                        tty->secondary.data++;
                if (L_ECHO(tty)) {
                        if (c==10) {
                                PUTCH(10,tty->write_q);
                                PUTCH(13,tty->write_q);
                        } else if (c<32) {
                                if (L_ECHOCTL(tty)) {
                                        PUTCH('^',tty->write_q);
                                        PUTCH(c+64,tty->write_q);
                                }
                        } else
                                PUTCH(c,tty->write_q);
                        tty->write(tty);
                }
                PUTCH(c,tty->secondary);
        }
        wake_up(&tty->secondary.proc_list);
}

int tty_read(unsigned channel, char * buf, int nr)
{
        struct tty_struct * tty;
        char c, * b=buf;
        int minimum,time,flag=0;
        long oldalarm;

        if (channel>2 || nr<0) return -1;
        tty = &tty_table[channel];
        oldalarm = current->alarm;
        time = (unsigned) 10*tty->termios.c_cc[VTIME];
        minimum = (unsigned) tty->termios.c_cc[VMIN];
        if (time && !minimum) {
                minimum=1;
                if (flag=(!oldalarm || time+jiffies<oldalarm))
                        current->alarm = time+jiffies;
        }
        if (minimum>nr)
                minimum=nr;
        while (nr>0) {
                if (flag && (current->signal & ALRMMASK)) {
                        current->signal &= ~ALRMMASK;
                        break;
                }
                if (current->signal)
                        break;
                if (EMPTY(tty->secondary) || (L_CANON(tty) &&
                !tty->secondary.data && LEFT(tty->secondary)>20)) {
                        sleep_if_empty(&tty->secondary);
                        continue;
                }
                do {
                        GETCH(tty->secondary,c);
                        if (c==EOF_CHAR(tty) || c==10)
                                tty->secondary.data--;
                        if (c==EOF_CHAR(tty) && L_CANON(tty))
                                return (b-buf);
                        else {
                                put_fs_byte(c,b++);
                                if (!--nr)
                                        break;
                        }
                } while (nr>0 && !EMPTY(tty->secondary));
                if (time && !L_CANON(tty))
                        if (flag=(!oldalarm || time+jiffies<oldalarm))
                                current->alarm = time+jiffies;
                        else
                                current->alarm = oldalarm;
                if (L_CANON(tty)) {
                        if (b-buf)
                                break;
                } else if (b-buf >= minimum)
                        break;
        }
        current->alarm = oldalarm;
        if (current->signal && !(b-buf))
                return -EINTR;
        return (b-buf);
}

int tty_write(unsigned channel, char * buf, int nr)
{
        static cr_flag=0;
        struct tty_struct * tty;
        char c, *b=buf;

        if (channel>2 || nr<0) return -1;
        tty = channel + tty_table;
        while (nr>0) {
                sleep_if_full(&tty->write_q);
                if (current->signal)
                        break;
                while (nr>0 && !FULL(tty->write_q)) {
                        c=get_fs_byte(b);
                        if (O_POST(tty)) {
                                if (c=='\r' && O_CRNL(tty))
                                        c='\n';
                                else if (c=='\n' && O_NLRET(tty))
                                        c='\r';
                                if (c=='\n' && !cr_flag && O_NLCR(tty)) {
                                        cr_flag = 1;
                                        PUTCH(13,tty->write_q);
                                        continue;
                                }
                                if (O_LCUC(tty))
                                        c=toupper(c);
                        }
                        b++; nr--;
                        cr_flag = 0;
                        PUTCH(c,tty->write_q);
                }
                tty->write(tty);
                if (nr>0)
                        schedule();
        }
        return (b-buf);
}

/*
 * Jeh, sometimes I really like the 386.
 * This routine is called from an interrupt,
 * and there should be absolutely no problem
 * with sleeping even in an interrupt (I hope).
 * Of course, if somebody proves me wrong, I'll
 * hate intel for all time :-). We'll have to
 * be careful and see to reinstating the interrupt
 * chips before calling this, though.
 */
void do_tty_interrupt(int tty)
{
        copy_to_cooked(tty_table+tty);
}

--
暧昧中透出薄雾的晨花 无意间岁月发出的嫩芽
浅笑里波光闪动的艳影 惬意后醉了眉眼的旧话
旧梦中锋利的剑与白马 传说里等情人白了头发
追忆前寒窗明月的红腊 多年后流水洗尽的铅华桃李春风一杯酒  江湖夜雨十年灯紫薇雨中?

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.35.5]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店