summaryrefslogtreecommitdiffstats
path: root/src/kernel/chr_drv/tty_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/chr_drv/tty_io.c')
-rw-r--r--src/kernel/chr_drv/tty_io.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/kernel/chr_drv/tty_io.c b/src/kernel/chr_drv/tty_io.c
new file mode 100644
index 0000000..ed14fa8
--- /dev/null
+++ b/src/kernel/chr_drv/tty_io.c
@@ -0,0 +1,350 @@
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
51struct 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 */
99struct 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
105void tty_init(void)
106{
107 rs_init();
108 con_init();
109}
110
111void 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
122static 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}
129
130static 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}
139
140void wait_for_keypress(void)
141{
142 sleep_if_empty(&tty_table[0].secondary);
143}
144
145void 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++;
212 if (L_ECHO(tty)) {
213 if (c==10) {
214 PUTCH(10,tty->write_q);
215 PUTCH(13,tty->write_q);
216 } else if (c<32) {
217 if (L_ECHOCTL(tty)) {
218 PUTCH('^',tty->write_q);
219 PUTCH(c+64,tty->write_q);
220 }
221 } else
222 PUTCH(c,tty->write_q);
223 tty->write(tty);
224 }
225 PUTCH(c,tty->secondary);
226 }
227 wake_up(&tty->secondary.proc_list);
228}
229
230int tty_read(unsigned channel, char * buf, int nr)
231{
232 struct tty_struct * tty;
233 char c, * b=buf;
234 int minimum,time,flag=0;
235 long oldalarm;
236
237 if (channel>2 || nr<0) return -1;
238 tty = &tty_table[channel];
239 oldalarm = current->alarm;
240 time = 10L*tty->termios.c_cc[VTIME];
241 minimum = tty->termios.c_cc[VMIN];
242 if (time && !minimum) {
243 minimum=1;
244 if ((flag=(!oldalarm || time+jiffies<oldalarm)))
245 current->alarm = time+jiffies;
246 }
247 if (minimum>nr)
248 minimum=nr;
249 while (nr>0) {
250 if (flag && (current->signal & ALRMMASK)) {
251 current->signal &= ~ALRMMASK;
252 break;
253 }
254 if (current->signal)
255 break;
256 if (EMPTY(tty->secondary) || (L_CANON(tty) &&
257 !tty->secondary.data && LEFT(tty->secondary)>20)) {
258 sleep_if_empty(&tty->secondary);
259 continue;
260 }
261 do {
262 GETCH(tty->secondary,c);
263 if (c==EOF_CHAR(tty) || c==10)
264 tty->secondary.data--;
265 if (c==EOF_CHAR(tty) && L_CANON(tty))
266 return (b-buf);
267 else {
268 put_fs_byte(c,b++);
269 if (!--nr)
270 break;
271 }
272 } while (nr>0 && !EMPTY(tty->secondary));
273 if (time && !L_CANON(tty)) {
274 if ((flag=(!oldalarm || time+jiffies<oldalarm)))
275 current->alarm = time+jiffies;
276 else
277 current->alarm = oldalarm;
278 }
279 if (L_CANON(tty)) {
280 if (b-buf)
281 break;
282 } else if (b-buf >= minimum)
283 break;
284 }
285 current->alarm = oldalarm;
286 if (current->signal && !(b-buf))
287 return -EINTR;
288 return (b-buf);
289}
290
291int tty_write(unsigned channel, char * buf, int nr)
292{
293 static int cr_flag=0;
294 struct tty_struct * tty;
295 char c, *b=buf;
296
297 if (channel>2 || nr<0) return -1;
298 tty = channel + tty_table;
299 while (nr>0) {
300 sleep_if_full(&tty->write_q);
301 if (current->signal)
302 break;
303 while (nr>0 && !FULL(tty->write_q)) {
304 c=get_fs_byte(b);
305 if (O_POST(tty)) {
306 if (c=='\r' && O_CRNL(tty))
307 c='\n';
308 else if (c=='\n' && O_NLRET(tty))
309 c='\r';
310 if (c=='\n' && !cr_flag && O_NLCR(tty)) {
311 cr_flag = 1;
312 PUTCH(13,tty->write_q);
313 continue;
314 }
315 if (O_LCUC(tty))
316 c=toupper(c);
317 }
318 b++; nr--;
319 cr_flag = 0;
320 PUTCH(c,tty->write_q);
321 }
322 tty->write(tty);
323 if (nr>0)
324 schedule();
325 }
326 return (b-buf);
327}
328
329/*
330 * Jeh, sometimes I really like the 386.
331 * This routine is called from an interrupt,
332 * and there should be absolutely no problem
333 * with sleeping even in an interrupt (I hope).
334 * Of course, if somebody proves me wrong, I'll
335 * hate intel for all time :-). We'll have to
336 * be careful and see to reinstating the interrupt
337 * chips before calling this, though.
338 *
339 * I don't think we sleep here under normal circumstances
340 * anyway, which is good, as the task sleeping might be
341 * totally innocent.
342 */
343void do_tty_interrupt(int tty)
344{
345 copy_to_cooked(tty_table+tty);
346}
347
348void chr_dev_init(void)
349{
350}