|
|
1.1 root 1: /*
2: * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
3: * or rs-channels. It also implements echoing, cooked mode etc (well,
4: * not currently, but ...)
5: */
6: #include <ctype.h>
7: #include <errno.h>
8: #include <signal.h>
9:
10: #define ALRMMASK (1<<(SIGALRM-1))
11:
12: #include <linux/sched.h>
13: #include <linux/tty.h>
14: #include <asm/segment.h>
15: #include <asm/system.h>
16:
17: #define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f)
18: #define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f)
19: #define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f)
20:
21: #define L_CANON(tty) _L_FLAG((tty),ICANON)
22: #define L_ISIG(tty) _L_FLAG((tty),ISIG)
23: #define L_ECHO(tty) _L_FLAG((tty),ECHO)
24: #define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
25: #define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
26: #define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
27: #define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
28:
29: #define I_UCLC(tty) _I_FLAG((tty),IUCLC)
30: #define I_NLCR(tty) _I_FLAG((tty),INLCR)
31: #define I_CRNL(tty) _I_FLAG((tty),ICRNL)
32: #define I_NOCR(tty) _I_FLAG((tty),IGNCR)
33:
34: #define O_POST(tty) _O_FLAG((tty),OPOST)
35: #define O_NLCR(tty) _O_FLAG((tty),ONLCR)
36: #define O_CRNL(tty) _O_FLAG((tty),OCRNL)
37: #define O_NLRET(tty) _O_FLAG((tty),ONLRET)
38: #define O_LCUC(tty) _O_FLAG((tty),OLCUC)
39:
40: struct tty_struct tty_table[] = {
41: {
42: {0,
43: OPOST|ONLCR, /* change outgoing NL to CRNL */
44: 0,
45: ICANON | ECHO | ECHOCTL | ECHOKE,
46: 0, /* console termio */
47: INIT_C_CC},
48: 0, /* initial pgrp */
49: 0, /* initial stopped */
50: con_write,
51: {0,0,0,0,""}, /* console read-queue */
52: {0,0,0,0,""}, /* console write-queue */
53: {0,0,0,0,""} /* console secondary queue */
54: },{
55: {0, /*IGNCR*/
56: OPOST | ONLRET, /* change outgoing NL to CR */
57: B2400 | CS8,
58: 0,
59: 0,
60: INIT_C_CC},
61: 0,
62: 0,
63: rs_write,
64: {0x3f8,0,0,0,""}, /* rs 1 */
65: {0x3f8,0,0,0,""},
66: {0,0,0,0,""}
67: },{
68: {0, /*IGNCR*/
69: OPOST | ONLRET, /* change outgoing NL to CR */
70: B2400 | CS8,
71: 0,
72: 0,
73: INIT_C_CC},
74: 0,
75: 0,
76: rs_write,
77: {0x2f8,0,0,0,""}, /* rs 2 */
78: {0x2f8,0,0,0,""},
79: {0,0,0,0,""}
80: }
81: };
82:
83: /*
84: * these are the tables used by the machine code handlers.
85: * you can implement pseudo-tty's or something by changing
86: * them. Currently not done.
87: */
88: struct tty_queue * table_list[]={
89: &tty_table[0].read_q, &tty_table[0].write_q,
90: &tty_table[1].read_q, &tty_table[1].write_q,
91: &tty_table[2].read_q, &tty_table[2].write_q
92: };
93:
94: void tty_init(void)
95: {
96: rs_init();
97: con_init();
98: }
99:
100: void tty_intr(struct tty_struct * tty, int signal)
101: {
102: int i;
103:
104: if (tty->pgrp <= 0)
105: return;
106: for (i=0;i<NR_TASKS;i++)
107: if (task[i] && task[i]->pgrp==tty->pgrp)
108: task[i]->signal |= 1<<(signal-1);
109: }
110:
111: static void sleep_if_empty(struct tty_queue * queue)
112: {
113: cli();
114: while (!current->signal && EMPTY(*queue))
115: interruptible_sleep_on(&queue->proc_list);
116: sti();
117: }
118:
119: static void sleep_if_full(struct tty_queue * queue)
120: {
121: if (!FULL(*queue))
122: return;
123: cli();
124: while (!current->signal && LEFT(*queue)<128)
125: interruptible_sleep_on(&queue->proc_list);
126: sti();
127: }
128:
129: void copy_to_cooked(struct tty_struct * tty)
130: {
131: signed char c;
132:
133: while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
134: GETCH(tty->read_q,c);
135: if (c==13)
136: if (I_CRNL(tty))
137: c=10;
138: else if (I_NOCR(tty))
139: continue;
140: else ;
141: else if (c==10 && I_NLCR(tty))
142: c=13;
143: if (I_UCLC(tty))
144: c=tolower(c);
145: if (L_CANON(tty)) {
146: if (c==ERASE_CHAR(tty)) {
147: if (EMPTY(tty->secondary) ||
148: (c=LAST(tty->secondary))==10 ||
149: c==EOF_CHAR(tty))
150: continue;
151: if (L_ECHO(tty)) {
152: if (c<32)
153: PUTCH(127,tty->write_q);
154: PUTCH(127,tty->write_q);
155: tty->write(tty);
156: }
157: DEC(tty->secondary.head);
158: continue;
159: }
160: if (c==STOP_CHAR(tty)) {
161: tty->stopped=1;
162: continue;
163: }
164: if (c==START_CHAR(tty)) {
165: tty->stopped=0;
166: continue;
167: }
168: }
169: if (!L_ISIG(tty)) {
170: if (c==INTR_CHAR(tty)) {
171: tty_intr(tty,SIGINT);
172: continue;
173: }
174: }
175: if (c==10 || c==EOF_CHAR(tty))
176: tty->secondary.data++;
177: if (L_ECHO(tty)) {
178: if (c==10) {
179: PUTCH(10,tty->write_q);
180: PUTCH(13,tty->write_q);
181: } else if (c<32) {
182: if (L_ECHOCTL(tty)) {
183: PUTCH('^',tty->write_q);
184: PUTCH(c+64,tty->write_q);
185: }
186: } else
187: PUTCH(c,tty->write_q);
188: tty->write(tty);
189: }
190: PUTCH(c,tty->secondary);
191: }
192: wake_up(&tty->secondary.proc_list);
193: }
194:
195: int tty_read(unsigned channel, char * buf, int nr)
196: {
197: struct tty_struct * tty;
198: char c, * b=buf;
199: int minimum,time,flag=0;
200: long oldalarm;
201:
202: if (channel>2 || nr<0) return -1;
203: tty = &tty_table[channel];
204: oldalarm = current->alarm;
205: time = (unsigned) 10*tty->termios.c_cc[VTIME];
206: minimum = (unsigned) tty->termios.c_cc[VMIN];
207: if (time && !minimum) {
208: minimum=1;
209: if (flag=(!oldalarm || time+jiffies<oldalarm))
210: current->alarm = time+jiffies;
211: }
212: if (minimum>nr)
213: minimum=nr;
214: while (nr>0) {
215: if (flag && (current->signal & ALRMMASK)) {
216: current->signal &= ~ALRMMASK;
217: break;
218: }
219: if (current->signal)
220: break;
221: if (EMPTY(tty->secondary) || (L_CANON(tty) &&
222: !tty->secondary.data && LEFT(tty->secondary)>20)) {
223: sleep_if_empty(&tty->secondary);
224: continue;
225: }
226: do {
227: GETCH(tty->secondary,c);
228: if (c==EOF_CHAR(tty) || c==10)
229: tty->secondary.data--;
230: if (c==EOF_CHAR(tty) && L_CANON(tty))
231: return (b-buf);
232: else {
233: put_fs_byte(c,b++);
234: if (!--nr)
235: break;
236: }
237: } while (nr>0 && !EMPTY(tty->secondary));
238: if (time && !L_CANON(tty))
239: if (flag=(!oldalarm || time+jiffies<oldalarm))
240: current->alarm = time+jiffies;
241: else
242: current->alarm = oldalarm;
243: if (L_CANON(tty)) {
244: if (b-buf)
245: break;
246: } else if (b-buf >= minimum)
247: break;
248: }
249: current->alarm = oldalarm;
250: if (current->signal && !(b-buf))
251: return -EINTR;
252: return (b-buf);
253: }
254:
255: int tty_write(unsigned channel, char * buf, int nr)
256: {
257: static cr_flag=0;
258: struct tty_struct * tty;
259: char c, *b=buf;
260:
261: if (channel>2 || nr<0) return -1;
262: tty = channel + tty_table;
263: while (nr>0) {
264: sleep_if_full(&tty->write_q);
265: if (current->signal)
266: break;
267: while (nr>0 && !FULL(tty->write_q)) {
268: c=get_fs_byte(b);
269: if (O_POST(tty)) {
270: if (c=='\r' && O_CRNL(tty))
271: c='\n';
272: else if (c=='\n' && O_NLRET(tty))
273: c='\r';
274: if (c=='\n' && !cr_flag && O_NLCR(tty)) {
275: cr_flag = 1;
276: PUTCH(13,tty->write_q);
277: continue;
278: }
279: if (O_LCUC(tty))
280: c=toupper(c);
281: }
282: b++; nr--;
283: cr_flag = 0;
284: PUTCH(c,tty->write_q);
285: }
286: tty->write(tty);
287: if (nr>0)
288: schedule();
289: }
290: return (b-buf);
291: }
292:
293: /*
294: * Jeh, sometimes I really like the 386.
295: * This routine is called from an interrupt,
296: * and there should be absolutely no problem
297: * with sleeping even in an interrupt (I hope).
298: * Of course, if somebody proves me wrong, I'll
299: * hate intel for all time :-). We'll have to
300: * be careful and see to reinstating the interrupt
301: * chips before calling this, though.
302: */
303: void do_tty_interrupt(int tty)
304: {
305: copy_to_cooked(tty_table+tty);
306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.