Commit | Line | Data |
---|---|---|
20c73af6 DR |
1 | # |
2 | /* | |
3 | * Copyright 1973 Bell Telephone Laboratories Inc | |
4 | */ | |
5 | ||
6 | /* | |
7 | * general TTY subroutines | |
8 | */ | |
9 | #include "../param.h" | |
10 | #include "../systm.h" | |
11 | #include "../user.h" | |
12 | #include "../tty.h" | |
13 | #include "../proc.h" | |
14 | #include "../inode.h" | |
15 | #include "../file.h" | |
16 | #include "../reg.h" | |
17 | #include "../conf.h" | |
18 | ||
19 | struct { int int; }; | |
20 | #define PS 0177776 | |
21 | ||
22 | char maptab[] | |
23 | { | |
24 | 000,000,000,000,004,000,000,000, | |
25 | 000,000,000,000,000,000,000,000, | |
26 | 000,000,000,000,000,000,000,000, | |
27 | 000,000,000,000,000,000,000,000, | |
28 | 000,'|',000,'#',000,000,000,'`', | |
29 | '{','}',000,000,000,000,000,000, | |
30 | 000,000,000,000,000,000,000,000, | |
31 | 000,000,000,000,000,000,000,000, | |
32 | '@',000,000,000,000,000,000,000, | |
33 | 000,000,000,000,000,000,000,000, | |
34 | 000,000,000,000,000,000,000,000, | |
35 | 000,000,000,000,000,000,'~',000, | |
36 | 000,'A','B','C','D','E','F','G', | |
37 | 'H','I','J','K','L','M','N','O', | |
38 | 'P','Q','R','S','T','U','V','W', | |
39 | 'X','Y','Z',000,000,000,000,000, | |
40 | }; | |
41 | ||
42 | struct cblock { | |
43 | struct cblock *c_next; | |
44 | char info[6]; | |
45 | }; | |
46 | ||
47 | struct cblock cfree[NCLIST]; | |
48 | struct cblock *cfreelist; | |
49 | ||
50 | struct { | |
51 | int ttrcsr; | |
52 | int ttrbuf; | |
53 | int tttcsr; | |
54 | int tttbuf; | |
55 | }; | |
56 | ||
57 | gtty() | |
58 | { | |
59 | int v[3]; | |
60 | register *up, *vp; | |
61 | ||
62 | vp = v; | |
63 | sgtty(vp); | |
64 | if (u.u_error) | |
65 | return; | |
66 | up = u.u_arg[0]; | |
67 | suword(up, *vp++); | |
68 | suword(++up, *vp++); | |
69 | suword(++up, *vp++); | |
70 | } | |
71 | ||
72 | stty() | |
73 | { | |
74 | register int *up; | |
75 | ||
76 | up = u.u_arg[0]; | |
77 | u.u_arg[0] = fuword(up); | |
78 | u.u_arg[1] = fuword(++up); | |
79 | u.u_arg[2] = fuword(++up); | |
80 | sgtty(0); | |
81 | } | |
82 | ||
83 | sgtty(v) | |
84 | { | |
85 | register struct file *fp; | |
86 | register struct inode *ip; | |
87 | ||
88 | if ((fp = getf(u.u_ar0[R0])) == NULL) | |
89 | return; | |
90 | ip = fp->f_inode; | |
91 | if ((ip->i_mode&IFMT) != IFCHR) { | |
92 | u.u_error = ENOTTY; | |
93 | return; | |
94 | } | |
95 | (*cdevsw[ip->i_addr[0].d_major].d_sgtty)(ip->i_addr[0], v); | |
96 | } | |
97 | ||
98 | wflushtty(atp) | |
99 | struct tty *atp; | |
100 | { | |
101 | register struct tty *tp; | |
102 | ||
103 | tp = atp; | |
104 | spl5(); | |
105 | while (tp->t_outq.c_cc) | |
106 | sleep(&tp->t_outq, TTOPRI); | |
107 | flushtty(tp); | |
108 | spl0(); | |
109 | } | |
110 | ||
111 | cinit() | |
112 | { | |
113 | register int ccp; | |
114 | register struct cblock *cp; | |
115 | register struct cdevsw *cdp; | |
116 | ||
117 | ccp = cfree; | |
118 | for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) { | |
119 | cp->c_next = cfreelist; | |
120 | cfreelist = cp; | |
121 | } | |
122 | ccp = 0; | |
123 | for(cdp = cdevsw; cdp->d_open; cdp++) | |
124 | ccp++; | |
125 | nchrdev = ccp; | |
126 | } | |
127 | ||
128 | /* | |
129 | * flush all TTY queues | |
130 | */ | |
131 | flushtty(atp) | |
132 | struct tty *atp; | |
133 | { | |
134 | register struct tty *tp; | |
135 | register int sps; | |
136 | ||
137 | tp = atp; | |
138 | while (getc(&tp->t_canq) >= 0); | |
139 | while (getc(&tp->t_outq) >= 0); | |
140 | wakeup(&tp->t_rawq); | |
141 | wakeup(&tp->t_outq); | |
142 | sps = PS->int; | |
143 | spl5(); | |
144 | while (getc(&tp->t_rawq) >= 0); | |
145 | tp->t_delct = 0; | |
146 | PS->int = sps; | |
147 | } | |
148 | ||
149 | /* | |
150 | * transfer raw list to canonical list, | |
151 | * doing code conversion. | |
152 | */ | |
153 | canon(atp) | |
154 | struct tty *atp; | |
155 | { | |
156 | register char *bp; | |
157 | char *bp1; | |
158 | register struct tty *tp; | |
159 | register int c; | |
160 | ||
161 | tp = atp; | |
162 | spl5(); | |
163 | while (tp->t_delct==0) { | |
164 | if ((tp->t_state&CARR_ON)==0) | |
165 | return(0); | |
166 | sleep(&tp->t_rawq, TTIPRI); | |
167 | } | |
168 | spl0(); | |
169 | loop: | |
170 | bp = &canonb[2]; | |
171 | while ((c=getc(&tp->t_rawq)) >= 0) { | |
172 | if (c==0377) { | |
173 | tp->t_delct--; | |
174 | break; | |
175 | } | |
176 | if ((tp->t_flags&RAW)==0) { | |
177 | if (bp[-1]!='\\') { | |
178 | if (c==tp->t_erase) { | |
179 | if (bp > &canonb[2]) | |
180 | bp--; | |
181 | continue; | |
182 | } | |
183 | if (c==tp->t_kill) | |
184 | goto loop; | |
185 | if (c==CEOT) | |
186 | continue; | |
187 | } else | |
188 | if (maptab[c] && (maptab[c]==c || (tp->t_flags&LCASE))) { | |
189 | if (bp[-2] != '\\') | |
190 | c = maptab[c]; | |
191 | bp--; | |
192 | } | |
193 | } | |
194 | *bp++ = c; | |
195 | if (bp>=canonb+CANBSIZ) | |
196 | break; | |
197 | } | |
198 | bp1 = bp; | |
199 | bp = &canonb[2]; | |
200 | c = &tp->t_canq; | |
201 | while (bp<bp1) | |
202 | putc(*bp++, c); | |
203 | return(1); | |
204 | } | |
205 | ||
206 | /* | |
207 | * place a character on raw TTY input queue, putting in delimiters | |
208 | * and waking up top half as needed. | |
209 | * also echo if required. | |
210 | */ | |
211 | ttyinput(ac, atp) | |
212 | struct tty *atp; | |
213 | { | |
214 | register int t_flags, c; | |
215 | register struct tty *tp; | |
216 | ||
217 | tp = atp; | |
218 | c = ac; | |
219 | t_flags = tp->t_flags; | |
220 | if ((c =& 0177) == '\r' && t_flags&CRMOD) | |
221 | c = '\n'; | |
222 | if ((t_flags&RAW)==0 && (c==CQUIT || c==CINTR)) { | |
223 | signal(tp, c==CINTR? SIGINT:SIGQIT); | |
224 | flushtty(tp); | |
225 | return; | |
226 | } | |
227 | if (tp->t_rawq.c_cc>=TTYHOG) { | |
228 | flushtty(tp); | |
229 | return; | |
230 | } | |
231 | if (t_flags&LCASE && c>='A' && c<='Z') | |
232 | c =+ 'a'-'A'; | |
233 | putc(c, &tp->t_rawq); | |
234 | if (t_flags&RAW || c=='\n' || c==004) { | |
235 | wakeup(&tp->t_rawq); | |
236 | if (putc(0377, &tp->t_rawq)==0) | |
237 | tp->t_delct++; | |
238 | } | |
239 | if (t_flags&ECHO) { | |
240 | ttyoutput(c, tp); | |
241 | ttstart(tp); | |
242 | } | |
243 | } | |
244 | ||
245 | /* | |
246 | * put character on TTY output queue, adding delays, | |
247 | * expanding tabs, and handling the CR/NL bit. | |
248 | */ | |
249 | ttyoutput(ac, tp) | |
250 | struct tty *tp; | |
251 | { | |
252 | register int c; | |
253 | register struct tty *rtp; | |
254 | register char *colp; | |
255 | int ctype; | |
256 | ||
257 | rtp = tp; | |
258 | c = ac&0177; | |
259 | if (c==004 && (rtp->t_flags&RAW)==0) | |
260 | return; | |
261 | if (c=='\t' && rtp->t_flags&XTABS) { | |
262 | do | |
263 | ttyoutput(' ', rtp); | |
264 | while (rtp->t_col&07); | |
265 | return; | |
266 | } | |
267 | if (rtp->t_flags&LCASE) { | |
268 | colp = "({)}!|^~'`"; | |
269 | while(*colp++) | |
270 | if(c == *colp++) { | |
271 | ttyoutput('\\', rtp); | |
272 | c = colp[-2]; | |
273 | break; | |
274 | } | |
275 | if ('a'<=c && c<='z') | |
276 | c =+ 'A' - 'a'; | |
277 | } | |
278 | if (c=='\n' && rtp->t_flags&CRMOD) | |
279 | ttyoutput('\r', rtp); | |
280 | if (putc(c, &rtp->t_outq)) | |
281 | return; | |
282 | colp = &rtp->t_col; | |
283 | ctype = partab[c]; | |
284 | c = 0; | |
285 | switch (ctype&077) { | |
286 | ||
287 | /* ordinary */ | |
288 | case 0: | |
289 | (*colp)++; | |
290 | ||
291 | /* non-printing */ | |
292 | case 1: | |
293 | break; | |
294 | ||
295 | /* backspace */ | |
296 | case 2: | |
297 | if (*colp) | |
298 | (*colp)--; | |
299 | break; | |
300 | ||
301 | /* newline */ | |
302 | case 3: | |
303 | if (*colp) | |
304 | c = max((*colp>>4) + 3, 6); | |
305 | *colp = 0; | |
306 | break; | |
307 | ||
308 | /* tab */ | |
309 | case 4: | |
310 | if ((rtp->t_flags&NTDELAY)==0) | |
311 | c = 1 - (*colp | ~07); | |
312 | *colp =| 07; | |
313 | (*colp)++; | |
314 | break; | |
315 | ||
316 | /* vertical motion */ | |
317 | case 5: | |
318 | c = 0177; | |
319 | break; | |
320 | ||
321 | /* carriage return */ | |
322 | case 6: | |
323 | c = 6; | |
324 | *colp = 0; | |
325 | } | |
326 | if (c && (rtp->t_flags&NODELAY)==0) | |
327 | putc(c|0200, &rtp->t_outq); | |
328 | } | |
329 | ||
330 | ttrstrt(atp) | |
331 | { | |
332 | register struct tty *tp; | |
333 | ||
334 | tp = atp; | |
335 | tp->t_state =& ~TIMEOUT; | |
336 | ttstart(tp); | |
337 | } | |
338 | ||
339 | ttstart(atp) | |
340 | struct tty *atp; | |
341 | { | |
342 | register int *addr, c; | |
343 | register struct tty *tp; | |
344 | struct { int (*func)(); }; | |
345 | ||
346 | tp = atp; | |
347 | addr = tp->t_addr; | |
348 | if (tp->t_state&SSTART) { | |
349 | (*addr.func)(tp); | |
350 | return; | |
351 | } | |
352 | if ((addr->tttcsr&DONE)==0 || tp->t_state&TIMEOUT) | |
353 | return; | |
354 | if ((c=getc(&tp->t_outq)) >= 0) { | |
355 | if (c<=0177) | |
356 | addr->tttbuf = c | (partab[c]&0200); | |
357 | else { | |
358 | timeout(ttrstrt, tp, c&0177); | |
359 | tp->t_state =| TIMEOUT; | |
360 | } | |
361 | } | |
362 | } | |
363 | ||
364 | ttread(atp) | |
365 | struct tty *atp; | |
366 | { | |
367 | register struct tty *tp; | |
368 | ||
369 | tp = atp; | |
370 | if (tp->t_canq.c_cc || canon(tp)) | |
371 | while (tp->t_canq.c_cc && passc(getc(&tp->t_canq))>=0); | |
372 | } | |
373 | ||
374 | ttwrite(atp) | |
375 | struct tty *atp; | |
376 | { | |
377 | register struct tty *tp; | |
378 | register int c; | |
379 | ||
380 | tp = atp; | |
381 | while ((c=cpass())>=0) { | |
382 | spl5(); | |
383 | while (tp->t_outq.c_cc > TTHIWAT) { | |
384 | ttstart(tp); | |
385 | sleep(&tp->t_outq, TTOPRI); | |
386 | } | |
387 | spl0(); | |
388 | ttyoutput(c, tp); | |
389 | } | |
390 | ttstart(tp); | |
391 | } | |
392 | ||
393 | ttystty(atp, av) | |
394 | int *atp, *av; | |
395 | { | |
396 | register *tp, *v; | |
397 | ||
398 | tp = atp; | |
399 | if(v = av) { | |
400 | *v++ = tp->t_speeds; | |
401 | v->lobyte = tp->t_erase; | |
402 | v->hibyte = tp->t_kill; | |
403 | v[1] = tp->t_flags; | |
404 | return(1); | |
405 | } | |
406 | wflushtty(tp); | |
407 | v = u.u_arg; | |
408 | tp->t_speeds = *v++; | |
409 | tp->t_erase = v->lobyte; | |
410 | tp->t_kill = v->hibyte; | |
411 | tp->t_flags = v[1]; | |
412 | return(0); | |
413 | } |