clocal, nonblock, other carrier related stuff
[unix-history] / usr / src / sys / kern / tty_subr.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1982, 1986 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)tty_subr.c 7.4 (Berkeley) %G%
7 */
8
9#include "param.h"
10#include "systm.h"
11#include "buf.h"
12#include "ioctl.h"
13#include "tty.h"
14#include "clist.h"
15
16char cwaiting;
17
18#define setquote(cp) \
19 setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
20 (int)(cp)&CROUND)
21#define isquote(cp) \
22 isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
23 (int)(cp)&CROUND)
24#define cbptr(x) ((struct cblock *)(x))
25
26/*
27 * Character list get/put
28 */
29getc(p)
30 register struct clist *p;
31{
32 register struct cblock *bp;
33 register int c, s;
34
35 s = spltty();
36 if (p->c_cc <= 0) {
37 c = -1;
38 p->c_cc = 0;
39 p->c_cf = p->c_cl = NULL;
40 } else {
41 c = *p->c_cf & 0377;
42 if (isquote(p->c_cf))
43 c |= TTY_QUOTE;
44 p->c_cf++;
45 if (--p->c_cc<=0) {
46 bp = cbptr(p->c_cf-1);
47 bp = cbptr((int)bp & ~CROUND);
48 p->c_cf = NULL;
49 p->c_cl = NULL;
50 bp->c_next = cfreelist;
51 cfreelist = bp;
52 cfreecount += CBSIZE;
53 if (cwaiting) {
54 wakeup(&cwaiting);
55 cwaiting = 0;
56 }
57 } else if (((int)p->c_cf & CROUND) == 0){
58 bp = cbptr(p->c_cf);
59 bp--;
60 p->c_cf = bp->c_next->c_info;
61 bp->c_next = cfreelist;
62 cfreelist = bp;
63 cfreecount += CBSIZE;
64 if (cwaiting) {
65 wakeup(&cwaiting);
66 cwaiting = 0;
67 }
68 }
69 }
70 splx(s);
71 return (c);
72}
73
74/*
75 * copy clist to buffer.
76 * return number of bytes moved.
77 */
78q_to_b(q, cp, cc)
79 register struct clist *q;
80 register char *cp;
81{
82 register struct cblock *bp;
83 register int s;
84 register nc;
85 char *acp;
86
87 if (cc <= 0)
88 return (0);
89 s = spltty();
90 if (q->c_cc <= 0) {
91 q->c_cc = 0;
92 q->c_cf = q->c_cl = NULL;
93 splx(s);
94 return (0);
95 }
96 acp = cp;
97
98 while (cc) {
99 nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
100 nc = MIN(nc, cc);
101 nc = MIN(nc, q->c_cc);
102 (void) bcopy(q->c_cf, cp, (unsigned)nc);
103 q->c_cf += nc;
104 q->c_cc -= nc;
105 cc -= nc;
106 cp += nc;
107 if (q->c_cc <= 0) {
108 bp = cbptr(q->c_cf - 1);
109 bp = cbptr((int)bp & ~CROUND);
110 q->c_cf = q->c_cl = NULL;
111 bp->c_next = cfreelist;
112 cfreelist = bp;
113 cfreecount += CBSIZE;
114 if (cwaiting) {
115 wakeup(&cwaiting);
116 cwaiting = 0;
117 }
118 break;
119 }
120 if (((int)q->c_cf & CROUND) == 0) {
121 bp = cbptr(q->c_cf);
122 bp--;
123 q->c_cf = bp->c_next->c_info;
124 bp->c_next = cfreelist;
125 cfreelist = bp;
126 cfreecount += CBSIZE;
127 if (cwaiting) {
128 wakeup(&cwaiting);
129 cwaiting = 0;
130 }
131 }
132 }
133 splx(s);
134 return (cp-acp);
135}
136
137/*
138 * Return count of contiguous characters
139 * in clist starting at q->c_cf.
140 * Stop counting if flag&character is non-null.
141 */
142ndqb(q, flag)
143 register struct clist *q;
144{
145 register cc;
146 int s;
147
148 s = spltty();
149 if (q->c_cc <= 0) {
150 cc = -q->c_cc;
151 goto out;
152 }
153 cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
154 cc -= (int)q->c_cf;
155 if (q->c_cc < cc)
156 cc = q->c_cc;
157 if (flag) {
158 register char *p, *end;
159
160 p = q->c_cf;
161 end = p;
162 end += cc;
163 while (p < end) {
164 if (*p & flag) {
165 cc = (int)p;
166 cc -= (int)q->c_cf;
167 break;
168 }
169 p++;
170 }
171 }
172out:
173 splx(s);
174 return (cc);
175}
176
177/*
178 * Flush cc bytes from q.
179 */
180ndflush(q, cc)
181 register struct clist *q;
182 register cc;
183{
184 register struct cblock *bp;
185 char *end;
186 int rem, s;
187
188 s = spltty();
189 if (q->c_cc <= 0)
190 goto out;
191 while (cc>0 && q->c_cc) {
192 bp = cbptr((int)q->c_cf & ~CROUND);
193 if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
194 end = q->c_cl;
195 } else {
196 end = (char *)((int)bp + sizeof (struct cblock));
197 }
198 rem = end - q->c_cf;
199 if (cc >= rem) {
200 cc -= rem;
201 q->c_cc -= rem;
202 q->c_cf = bp->c_next->c_info;
203 bp->c_next = cfreelist;
204 cfreelist = bp;
205 cfreecount += CBSIZE;
206 if (cwaiting) {
207 wakeup(&cwaiting);
208 cwaiting = 0;
209 }
210 } else {
211 q->c_cc -= cc;
212 q->c_cf += cc;
213 if (q->c_cc <= 0) {
214 bp->c_next = cfreelist;
215 cfreelist = bp;
216 cfreecount += CBSIZE;
217 if (cwaiting) {
218 wakeup(&cwaiting);
219 cwaiting = 0;
220 }
221 }
222 break;
223 }
224 }
225 if (q->c_cc <= 0) {
226 q->c_cf = q->c_cl = NULL;
227 q->c_cc = 0;
228 }
229out:
230 splx(s);
231}
232
233
234putc(c, p)
235 register struct clist *p;
236{
237 register struct cblock *bp;
238 register char *cp;
239 register s;
240
241 s = spltty();
242 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */
243 if ((bp = cfreelist) == NULL) {
244 splx(s);
245 return (-1);
246 }
247 cfreelist = bp->c_next;
248 cfreecount -= CBSIZE;
249 bp->c_next = NULL;
250 bzero(bp->c_quote, CBQSIZE);
251 p->c_cf = cp = bp->c_info;
252 } else if (((int)cp & CROUND) == 0) {
253 bp = cbptr(cp) - 1; /* pointer arith */
254 if ((bp->c_next = cfreelist) == NULL) {
255 splx(s);
256 return (-1);
257 }
258 bp = bp->c_next;
259 cfreelist = bp->c_next;
260 cfreecount -= CBSIZE;
261 bp->c_next = NULL;
262 cp = bp->c_info;
263 }
264 if (c&TTY_QUOTE)
265 setquote(cp);
266 *cp++ = c;
267 p->c_cc++;
268 p->c_cl = cp;
269 splx(s);
270 return (0);
271}
272
273/*
274 * copy buffer to clist.
275 * return number of bytes not transfered.
276 */
277b_to_q(cp, cc, q)
278 register char *cp;
279 struct clist *q;
280 register int cc;
281{
282 register char *cq;
283 register struct cblock *bp;
284 register s, nc;
285 int acc;
286
287 if (cc <= 0)
288 return (0);
289 acc = cc;
290 s = spltty();
291 if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
292 if ((bp = cfreelist) == NULL)
293 goto out;
294 cfreelist = bp->c_next;
295 cfreecount -= CBSIZE;
296 bzero(bp->c_quote, CBQSIZE);
297 bp->c_next = NULL;
298 q->c_cf = cq = bp->c_info;
299 }
300
301 while (cc) {
302 if (((int)cq & CROUND) == 0) {
303 bp = cbptr(cq) - 1;
304 if ((bp->c_next = cfreelist) == NULL)
305 goto out;
306 bp = bp->c_next;
307 cfreelist = bp->c_next;
308 cfreecount -= CBSIZE;
309 bzero(bp->c_quote, CBQSIZE);
310 bp->c_next = NULL;
311 cq = bp->c_info;
312 }
313 nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND));
314 (void) bcopy(cp, cq, (unsigned)nc);
315 cp += nc;
316 cq += nc;
317 cc -= nc;
318 }
319out:
320 q->c_cl = cq;
321 q->c_cc += acc - cc;
322 splx(s);
323 return (cc);
324}
325
326/*
327 * Given a non-NULL pointter into the list (like c_cf which
328 * always points to a real character if non-NULL) return the pointer
329 * to the next character in the list or return NULL if no more chars.
330 *
331 * Callers must not allow getc's to happen between nextc's so that the
332 * pointer becomes invalid. Note that interrupts are NOT masked.
333 */
334char *
335nextc(p, cp, c)
336 register struct clist *p;
337 register char *cp;
338 register int *c;
339{
340
341 if (p->c_cc && ++cp != p->c_cl) {
342 if (((int)cp & CROUND) == 0) {
343 cp = (cbptr(cp))[-1].c_next->c_info;
344 }
345 *c = *cp;
346 if (isquote(cp))
347 *c |= TTY_QUOTE;
348 return (cp);
349 }
350 return (0);
351}
352
353/*
354 * Remove the last character in the list and return it.
355 */
356unputc(p)
357 register struct clist *p;
358{
359 register struct cblock *bp;
360 register int c, s;
361 struct cblock *obp;
362 register int first = 1;
363
364 s = spltty();
365 if (p->c_cc <= 0)
366 c = -1;
367 else {
368 c = *--p->c_cl;
369 if (isquote(p->c_cl))
370 c |= TTY_QUOTE;
371 if (--p->c_cc <= 0) {
372 bp = cbptr(p->c_cl);
373 bp = cbptr((int)bp & ~CROUND);
374 p->c_cl = p->c_cf = NULL;
375 bp->c_next = cfreelist;
376 cfreelist = bp;
377 cfreecount += CBSIZE;
378 } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) {
379 p->c_cl = (char *)((int)p->c_cl & ~CROUND);
380
381 bp = cbptr(p->c_cf);
382 bp = cbptr((int)bp & ~CROUND);
383 while (bp->c_next != cbptr(p->c_cl))
384 bp = bp->c_next;
385 obp = bp;
386 p->c_cl = (char *)(bp + 1);
387 bp = bp->c_next;
388 bp->c_next = cfreelist;
389 cfreelist = bp;
390 cfreecount += CBSIZE;
391 obp->c_next = NULL;
392 }
393 }
394 splx(s);
395 return (c);
396}
397
398/*
399 * Put the chars in the from que
400 * on the end of the to que.
401 */
402catq(from, to)
403 struct clist *from, *to;
404{
405#ifdef notdef
406 char bbuf[CBSIZE*4];
407#endif
408 register s, c;
409
410 s = spltty();
411 if (to->c_cc == 0) {
412 *to = *from;
413 from->c_cc = 0;
414 from->c_cf = NULL;
415 from->c_cl = NULL;
416 splx(s);
417 return;
418 }
419 splx(s);
420#ifdef notdef
421 while (from->c_cc > 0) {
422 c = q_to_b(from, bbuf, sizeof bbuf);
423 (void) b_to_q(bbuf, c, to);
424 }
425#endif
426 /* XXX - FIX */
427 while ((c = getc(from)) >= 0)
428 putc(c, to);
429}
430
431#ifdef unneeded
432/*
433 * Integer (short) get/put using clists.
434 */
435typedef u_short word_t;
436
437getw(p)
438 register struct clist *p;
439{
440 register int s, c;
441 register struct cblock *bp;
442
443 if (p->c_cc <= 1)
444 return(-1);
445 if (p->c_cc & 01) {
446 c = getc(p);
447#if BYTE_ORDER == LITTLE_ENDIAN
448 return (c | (getc(p)<<8));
449#else
450 return (getc(p) | (c<<8));
451#endif
452 }
453 s = spltty();
454#if BYTE_ORDER == LITTLE_ENDIAN
455 c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1];
456#else
457 c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0];
458#endif
459 p->c_cf += sizeof (word_t);
460 p->c_cc -= sizeof (word_t);
461 if (p->c_cc <= 0) {
462 bp = cbptr(p->c_cf-1);
463 bp = cbptr((int)bp & ~CROUND);
464 p->c_cf = NULL;
465 p->c_cl = NULL;
466 bp->c_next = cfreelist;
467 cfreelist = bp;
468 cfreecount += CBSIZE;
469 if (cwaiting) {
470 wakeup(&cwaiting);
471 cwaiting = 0;
472 }
473 } else if (((int)p->c_cf & CROUND) == 0) {
474 bp = cbptr(p->c_cf);
475 bp--;
476 p->c_cf = bp->c_next->c_info;
477 bp->c_next = cfreelist;
478 cfreelist = bp;
479 cfreecount += CBSIZE;
480 if (cwaiting) {
481 wakeup(&cwaiting);
482 cwaiting = 0;
483 }
484 }
485 splx(s);
486 return (c);
487}
488
489putw(c, p)
490 register struct clist *p;
491 word_t c;
492{
493 register s;
494 register struct cblock *bp;
495 register char *cp;
496
497 s = spltty();
498 if (cfreelist==NULL) {
499 splx(s);
500 return(-1);
501 }
502 if (p->c_cc & 01) {
503#if BYTE_ORDER == LITTLE_ENDIAN
504 (void) putc(c, p);
505 (void) putc(c>>8, p);
506#else
507 (void) putc(c>>8, p);
508 (void) putc(c, p);
509#endif
510 } else {
511 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
512 if ((bp = cfreelist) == NULL) {
513 splx(s);
514 return (-1);
515 }
516 cfreelist = bp->c_next;
517 cfreecount -= CBSIZE;
518 bp->c_next = NULL;
519 p->c_cf = cp = bp->c_info;
520 } else if (((int)cp & CROUND) == 0) {
521 bp = cbptr(cp) - 1;
522 if ((bp->c_next = cfreelist) == NULL) {
523 splx(s);
524 return (-1);
525 }
526 bp = bp->c_next;
527 cfreelist = bp->c_next;
528 cfreecount -= CBSIZE;
529 bp->c_next = NULL;
530 cp = bp->c_info;
531 }
532#if defined(vax)
533 *(word_t *)cp = c;
534#else
535 ((u_char *)cp)[0] = c>>8;
536 ((u_char *)cp)[1] = c;
537#endif
538 p->c_cl = cp + sizeof (word_t);
539 p->c_cc += sizeof (word_t);
540 }
541 splx(s);
542 return (0);
543}
544#endif unneeded