这篇文章,很多语句我并没有给出注释,因为大都是宏定义、表格定义等语句,贴出来更多的是为了这一系列的完整性。
1 /*
2 * linux/kernel/serial.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * serial.c
9 *
10 * This module implements the rs232 io functions
11 * void rs_write(struct tty_struct * queue);
12 * void rs_init(void);
13 * and all interrupts pertaining to serial IO.
14 */
16 #include <linux/tty.h>
17 #include <linux/sched.h>
18 #include <asm/system.h>
19 #include <asm/io.h>
21 #define WAKEUP_CHARS (TTY_BUF_SIZE/4)
23 extern void rs1_interrupt(void);
24 extern void rs2_interrupt(void);
26 static void init(int port)
27 {
28 outb_p(0x80,port+3); /* set DLAB of line control reg */
29 outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
30 outb_p(0x00,port+1); /* MS of divisor */
31 outb_p(0x03,port+3); /* reset DLAB */
32 outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */
33 outb_p(0x0d,port+1); /* enable all intrs but writes */
34 (void)inb(port); /* read data port to reset things (?) */
35 }
1 /*
2 * linux/kernel/serial.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * serial.c
9 *
10 * This module implements the rs232 io functions
11 * void rs_write(struct tty_struct * queue);
12 * void rs_init(void);
13 * and all interrupts pertaining to serial IO.
14 */
16 #include <linux/tty.h>
17 #include <linux/sched.h>
18 #include <asm/system.h>
19 #include <asm/io.h>
21 #define WAKEUP_CHARS (TTY_BUF_SIZE/4)
23 extern void rs1_interrupt(void);
24 extern void rs2_interrupt(void);
26 static void init(int port)
27 {
28 outb_p(0x80,port+3); /* set DLAB of line control reg */
29 outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */
30 outb_p(0x00,port+1); /* MS of divisor */
31 outb_p(0x03,port+3); /* reset DLAB */
32 outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */
33 outb_p(0x0d,port+1); /* enable all intrs but writes */
34 (void)inb(port); /* read data port to reset things (?) */
35 }
37 void rs_init(void)
38 {
39 set_intr_gate(0x24,rs1_interrupt);
40 set_intr_gate(0x23,rs2_interrupt);
41 init(tty_table[1].read_q.data);
42 init(tty_table[2].read_q.data);
43 outb(inb_p(0x21)&0xE7,0x21);
44 }
45
46 /*
47 * This routine gets called when tty_write has put something into
48 * the write_queue. It must check wheter the queue is empty, and
49 * set the interrupt register accordingly
50 *
51 * void _rs_write(struct tty_struct * tty);
52 */
53 void rs_write(struct tty_struct * tty)
54 {
55 cli();
56 if (!EMPTY(tty->write_q))
57 outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1);
58 sti();
59 }
ttyio.c
1 /*
2 * linux/kernel/tty_io.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7 /*
8 * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
9 * or rs-channels. It also implements echoing, cooked mode etc.
10 *
11 * Kill-line thanks to John T Kohl.
12 */
13 #include <ctype.h>
14 #include <errno.h>
15 #include <signal.h>
16
17 #define ALRMMASK (1<<(SIGALRM-1))
18 #define KILLMASK (1<<(SIGKILL-1))
19 #define INTMASK (1<<(SIGINT-1))
20 #define QUITMASK (1<<(SIGQUIT-1))
21 #define TSTPMASK (1<<(SIGTSTP-1))
22
23 #include <linux/sched.h>
24 #include <linux/tty.h>
25 #include <asm/segment.h>
26 #include <asm/system.h>
27
28 #define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
29 #define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
30 #define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
31
32 #define L_CANON(tty) _L_FLAG((tty),ICANON)
33 #define L_ISIG(tty) _L_FLAG((tty),ISIG)
34 #define L_ECHO(tty) _L_FLAG((tty),ECHO)
35 #define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
36 #define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
37 #define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
38 #define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
39
40 #define I_UCLC(tty) _I_FLAG((tty),IUCLC)
41 #define I_NLCR(tty) _I_FLAG((tty),INLCR)
42 #define I_CRNL(tty) _I_FLAG((tty),ICRNL)
43 #define I_NOCR(tty) _I_FLAG((tty),IGNCR)
44
45 #define O_POST(tty) _O_FLAG((tty),OPOST)
46 #define O_NLCR(tty) _O_FLAG((tty),ONLCR)
47 #define O_CRNL(tty) _O_FLAG((tty),OCRNL)
48 #define O_NLRET(tty) _O_FLAG((tty),ONLRET)
49 #define O_LCUC(tty) _O_FLAG((tty),OLCUC)
50
51 struct tty_struct tty_table[] = {
52 {
53 {ICRNL, /* change incoming CR to NL */
54 OPOST|ONLCR, /* change outgoing NL to CRNL */
55 0,
56 ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
57 0, /* console termio */
58 INIT_C_CC},
59 0, /* initial pgrp */
60 0, /* initial stopped */
61 con_write,
62 {0,0,0,0,""}, /* console read-queue */
63 {0,0,0,0,""}, /* console write-queue */
64 {0,0,0,0,""} /* console secondary queue */
65 },{
66 {0, /* no translation */
67 0, /* no translation */
68 B2400 | CS8,
69 0,
70 0,
71 INIT_C_CC},
72 0,
73 0,
74 rs_write,
75 {0x3f8,0,0,0,""}, /* rs 1 */
76 {0x3f8,0,0,0,""},
77 {0,0,0,0,""}
78 },{
79 {0, /* no translation */
80 0, /* no translation */
81 B2400 | CS8,
82 0,
83 0,
84 INIT_C_CC},
85 0,
86 0,
87 rs_write,
88 {0x2f8,0,0,0,""}, /* rs 2 */
89 {0x2f8,0,0,0,""},
90 {0,0,0,0,""}
91 }
92 };
93
94 /*
95 * these are the tables used by the machine code handlers.
96 * you can implement pseudo-tty's or something by changing
97 * them. Currently not done.
98 */
99 struct tty_queue * table_list[]={
100 &tty_table[0].read_q, &tty_table[0].write_q,
101 &tty_table[1].read_q, &tty_table[1].write_q,
102 &tty_table[2].read_q, &tty_table[2].write_q
103 };
104
105 void tty_init(void)
106 {
107 rs_init();
108 con_init();
109 }
110
111 void tty_intr(struct tty_struct * tty, int mask)
112 {
113 int i;
114
115 if (tty->pgrp <= 0)
116 return;
117 for (i=0;i<NR_TASKS;i++)
118 if (task[i] && task[i]->pgrp==tty->pgrp)
119 task[i]->signal |= mask;
120 }
121
122 static void sleep_if_empty(struct tty_queue * queue)
123 {
124 cli();
125 while (!current->signal && EMPTY(*queue))
126 interruptible_sleep_on(&queue->proc_list);
127 sti();
128 }
130 static void sleep_if_full(struct tty_queue * queue)
131 {
132 if (!FULL(*queue))
133 return;
134 cli();
135 while (!current->signal && LEFT(*queue)<128)
136 interruptible_sleep_on(&queue->proc_list);
137 sti();
138 }
140 void wait_for_keypress(void)
141 {
142 sleep_if_empty(&tty_table[0].secondary);
143 }
145 void copy_to_cooked(struct tty_struct * tty)
146 {
147 signed char c;
148
149 while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
150 GETCH(tty->read_q,c);
151 if (c==13)
152 if (I_CRNL(tty))
153 c=10;
154 else if (I_NOCR(tty))
155 continue;
156 else ;
157 else if (c==10 && I_NLCR(tty))
158 c=13;
159 if (I_UCLC(tty))
160 c=tolower(c);
161 if (L_CANON(tty)) {
162 if (c==KILL_CHAR(tty)) {
163 /* deal with killing the input line */
164 while(!(EMPTY(tty->secondary) ||
165 (c=LAST(tty->secondary))==10 ||
166 c==EOF_CHAR(tty))) {
167 if (L_ECHO(tty)) {
168 if (c<32)
169 PUTCH(127,tty->write_q);
170 PUTCH(127,tty->write_q);
171 tty->write(tty);
172 }
173 DEC(tty->secondary.head);
174 }
175 continue;
176 }
177 if (c==ERASE_CHAR(tty)) {
178 if (EMPTY(tty->secondary) ||
179 (c=LAST(tty->secondary))==10 ||
180 c==EOF_CHAR(tty))
181 continue;
182 if (L_ECHO(tty)) {
183 if (c<32)
184 PUTCH(127,tty->write_q);
185 PUTCH(127,tty->write_q);
186 tty->write(tty);
187 }
188 DEC(tty->secondary.head);
189 continue;
190 }
191 if (c==STOP_CHAR(tty)) {
192 tty->stopped=1;
193 continue;
194 }
195 if (c==START_CHAR(tty)) {
196 tty->stopped=0;
197 continue;
198 }
199 }
200 if (L_ISIG(tty)) {
201 if (c==INTR_CHAR(tty)) {
202 tty_intr(tty,INTMASK);
203 continue;
204 }
205 if (c==QUIT_CHAR(tty)) {
206 tty_intr(tty,QUITMASK);
207 continue;
208 }
209 }
210 if (c==10 || c==EOF_CHAR(tty))
211 tty->secondary.data+