1 /* tty_subr.c 3.4 06/07/80 */ 2 3 #include "../h/param.h" 4 #include "../h/tty.h" 5 #include "../h/systm.h" 6 #include "../h/conf.h" 7 #include "../h/buf.h" 8 9 struct cblock { 10 struct cblock *c_next; 11 char c_info[CBSIZE]; 12 }; 13 14 struct cblock cfree[NCLIST]; 15 int cbad; 16 struct cblock *cfreelist; 17 18 /* 19 * Character list get/put 20 */ 21 getc(p) 22 register struct clist *p; 23 { 24 register struct cblock *bp; 25 register int c, s; 26 27 s = spl6(); 28 if (p->c_cc <= 0) { 29 c = -1; 30 p->c_cc = 0; 31 p->c_cf = p->c_cl = NULL; 32 } else { 33 c = *p->c_cf++ & 0377; 34 if (--p->c_cc<=0) { 35 bp = (struct cblock *)(p->c_cf-1); 36 bp = (struct cblock *) ((int)bp & ~CROUND); 37 p->c_cf = NULL; 38 p->c_cl = NULL; 39 bp->c_next = cfreelist; 40 cfreelist = bp; 41 } else if (((int)p->c_cf & CROUND) == 0){ 42 bp = (struct cblock *)(p->c_cf); 43 bp--; 44 p->c_cf = bp->c_next->c_info; 45 bp->c_next = cfreelist; 46 cfreelist = bp; 47 } 48 } 49 splx(s); 50 return(c); 51 } 52 53 /* 54 * copy clist to buffer. 55 * return number of bytes moved. 56 */ 57 q_to_b(q, cp, cc) 58 register struct clist *q; 59 register char *cp; 60 { 61 register struct cblock *bp; 62 register int s; 63 char *acp; 64 65 if (cc <= 0) 66 return(0); 67 s = spl6(); 68 if (q->c_cc <= 0) { 69 q->c_cc = 0; 70 q->c_cf = q->c_cl = NULL; 71 return(0); 72 } 73 acp = cp; 74 cc++; 75 76 while (--cc) { 77 *cp++ = *q->c_cf++; 78 if (--q->c_cc <= 0) { 79 bp = (struct cblock *)(q->c_cf-1); 80 bp = (struct cblock *)((int)bp & ~CROUND); 81 q->c_cf = q->c_cl = NULL; 82 bp->c_next = cfreelist; 83 cfreelist = bp; 84 break; 85 } 86 if (((int)q->c_cf & CROUND) == 0) { 87 bp = (struct cblock *)(q->c_cf); 88 bp--; 89 q->c_cf = bp->c_next->c_info; 90 bp->c_next = cfreelist; 91 cfreelist = bp; 92 } 93 } 94 splx(s); 95 return(cp-acp); 96 } 97 98 /* 99 * Return count of contiguous characters 100 * in clist starting at q->c_cf. 101 * Stop counting if flag&character is non-null. 102 */ 103 ndqb(q, flag) 104 register struct clist *q; 105 { 106 register cc; 107 int s; 108 109 s = spl6(); 110 if (q->c_cc <= 0) { 111 cc = -q->c_cc; 112 goto out; 113 } 114 cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 115 cc -= (int)q->c_cf; 116 if (q->c_cc < cc) 117 cc = q->c_cc; 118 if (flag) { 119 register char *p, *end; 120 121 p = q->c_cf; 122 end = p; 123 end += cc; 124 while (p < end) { 125 if (*p & flag) { 126 cc = (int)p - (int)q->c_cf; 127 break; 128 } 129 p++; 130 } 131 } 132 out: 133 splx(s); 134 return(cc); 135 } 136 137 /* 138 * Update clist to show that cc characters 139 * were removed. It is assumed that cc < CBSIZE. 140 */ 141 ndflush(q, cc) 142 register struct clist *q; 143 register cc; 144 { 145 register s; 146 147 if (cc == 0) 148 return; 149 s = spl6(); 150 if (q->c_cc < 0) { 151 if (q->c_cf != NULL) { 152 q->c_cc += cc; 153 q->c_cf += cc; 154 goto out; 155 } 156 q->c_cc = 0; 157 goto out; 158 } 159 if (q->c_cc == 0) { 160 goto out; 161 } 162 if (cc > CBSIZE || cc <= 0) { 163 cbad++; 164 goto out; 165 } 166 q->c_cc -= cc; 167 q->c_cf += cc; 168 if (((int)q->c_cf & CROUND) == 0) { 169 register struct cblock *bp; 170 171 bp = (struct cblock *)(q->c_cf) -1; 172 if (bp->c_next) { 173 q->c_cf = bp->c_next->c_info; 174 } else { 175 q->c_cf = q->c_cl = NULL; 176 } 177 bp->c_next = cfreelist; 178 cfreelist = bp; 179 } else 180 if (q->c_cc == 0) { 181 register struct cblock *bp; 182 q->c_cf = (char *)((int)q->c_cf & ~CROUND); 183 bp = (struct cblock *)(q->c_cf); 184 bp->c_next = cfreelist; 185 cfreelist = bp; 186 q->c_cf = q->c_cl = NULL; 187 } 188 out: 189 splx(s); 190 } 191 192 /* 193 * Put character c in queue p. 194 */ 195 putc(c, p) 196 register struct clist *p; 197 { 198 register struct cblock *bp; 199 register char *cp; 200 register s; 201 202 s = spl6(); 203 if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 204 if ((bp = cfreelist) == NULL) { 205 splx(s); 206 return(-1); 207 } 208 cfreelist = bp->c_next; 209 bp->c_next = NULL; 210 p->c_cf = cp = bp->c_info; 211 } else if (((int)cp & CROUND) == 0) { 212 bp = (struct cblock *)cp - 1; 213 if ((bp->c_next = cfreelist) == NULL) { 214 splx(s); 215 return(-1); 216 } 217 bp = bp->c_next; 218 cfreelist = bp->c_next; 219 bp->c_next = NULL; 220 cp = bp->c_info; 221 } 222 *cp++ = c; 223 p->c_cc++; 224 p->c_cl = cp; 225 splx(s); 226 return(0); 227 } 228 229 /* 230 * copy buffer to clist. 231 * return number of bytes not transfered. 232 */ 233 b_to_q(cp, cc, q) 234 register char *cp; 235 struct clist *q; 236 register int cc; 237 { 238 register char *cq; 239 register struct cblock *bp; 240 register s, acc; 241 242 if (cc <= 0) 243 return(0); 244 acc = cc; 245 s = spl6(); 246 if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 247 if ((bp = cfreelist) == NULL) 248 goto out; 249 cfreelist = bp->c_next; 250 bp->c_next = NULL; 251 q->c_cf = cq = bp->c_info; 252 } 253 254 while (cc) { 255 if (((int)cq & CROUND) == 0) { 256 bp = (struct cblock *) cq - 1; 257 if ((bp->c_next = cfreelist) == NULL) 258 goto out; 259 bp = bp->c_next; 260 cfreelist = bp->c_next; 261 bp->c_next = NULL; 262 cq = bp->c_info; 263 } 264 *cq++ = *cp++; 265 cc--; 266 } 267 out: 268 q->c_cl = cq; 269 q->c_cc += acc-cc; 270 splx(s); 271 return(cc); 272 } 273 274 /* 275 * Given a non-NULL pointter into the list (like c_cf which 276 * always points to a real character if non-NULL) return the pointer 277 * to the next character in the list or return NULL if no more chars. 278 * 279 * Callers must not allow getc's to happen between nextc's so that the 280 * pointer becomes invalid. Note that interrupts are NOT masked. 281 */ 282 char * 283 nextc(p, cp) 284 register struct clist *p; 285 register char *cp; 286 { 287 288 if (p->c_cc && ++cp != p->c_cl) { 289 if (((int)cp & CROUND) == 0) 290 return (((struct cblock *)cp)[-1].c_next->c_info); 291 return (cp); 292 } 293 return (0); 294 } 295 296 /* 297 * Remove the last character in the list and return it. 298 */ 299 unputc(p) 300 register struct clist *p; 301 { 302 register struct cblock *bp; 303 register int c, s; 304 struct cblock *obp; 305 306 s = spl6(); 307 if (p->c_cc <= 0) 308 c = -1; 309 else { 310 c = *--p->c_cl; 311 if (--p->c_cc <= 0) { 312 bp = (struct cblock *)p->c_cl; 313 bp = (struct cblock *)((int)bp & ~CROUND); 314 p->c_cl = p->c_cf = NULL; 315 bp->c_next = cfreelist; 316 cfreelist = bp; 317 } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) { 318 p->c_cl = (char *)((int)p->c_cl & ~CROUND); 319 bp = (struct cblock *)p->c_cf; 320 bp = (struct cblock *)((int)bp & ~CROUND); 321 while (bp->c_next != (struct cblock *)p->c_cl) 322 bp = bp->c_next; 323 obp = bp; 324 p->c_cl = (char *)(bp + 1); 325 bp = bp->c_next; 326 bp->c_next = cfreelist; 327 cfreelist = bp; 328 obp->c_next = NULL; 329 } 330 } 331 splx(s); 332 return (c); 333 } 334 335 /* 336 * Put the chars in the from que 337 * on the end of the to que. 338 * 339 * SHOULD JUST USE q_to_b AND THEN b_to_q HERE. 340 */ 341 catq(from, to) 342 struct clist *from, *to; 343 { 344 register c; 345 346 while ((c = getc(from)) >= 0) 347 (void) putc(c, to); 348 } 349 350 /* 351 * Initialize clist by freeing all character blocks, then count 352 * number of character devices. (Once-only routine) 353 */ 354 cinit() 355 { 356 register int ccp; 357 register struct cblock *cp; 358 register struct cdevsw *cdp; 359 360 ccp = (int)cfree; 361 ccp = (ccp+CROUND) & ~CROUND; 362 for(cp=(struct cblock *)ccp; cp <= &cfree[NCLIST-1]; cp++) { 363 cp->c_next = cfreelist; 364 cfreelist = cp; 365 } 366 ccp = 0; 367 for(cdp = cdevsw; cdp->d_open; cdp++) 368 ccp++; 369 nchrdev = ccp; 370 } 371 372 /* 373 * integer (2-byte) get/put 374 * using clists 375 */ 376 /* 377 getw(p) 378 register struct clist *p; 379 { 380 register int s; 381 382 if (p->c_cc <= 1) 383 return(-1); 384 s = getc(p); 385 return(s | (getc(p)<<8)); 386 } 387 */ 388 389 putw(c, p) 390 register struct clist *p; 391 { 392 register s; 393 394 s = spl6(); 395 if (cfreelist==NULL) { 396 splx(s); 397 return(-1); 398 } 399 (void) putc(c, p); 400 (void) putc(c>>8, p); 401 splx(s); 402 return(0); 403 } 404