diff options
Diffstat (limited to 'src/kernel/chr_drv/tty_io.c')
-rw-r--r-- | src/kernel/chr_drv/tty_io.c | 350 |
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 | |||
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 | } | ||
129 | |||
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 | } | ||
139 | |||
140 | void wait_for_keypress(void) | ||
141 | { | ||
142 | sleep_if_empty(&tty_table[0].secondary); | ||
143 | } | ||
144 | |||
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++; | ||
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 | |||
230 | int 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 | |||
291 | int 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 | */ | ||
343 | void do_tty_interrupt(int tty) | ||
344 | { | ||
345 | copy_to_cooked(tty_table+tty); | ||
346 | } | ||
347 | |||
348 | void chr_dev_init(void) | ||
349 | { | ||
350 | } | ||