|
|
1.1 ! root 1: /* ! 2: * driver for comet (nebula?) console cassette ! 3: */ ! 4: ! 5: #include "../h/param.h" ! 6: #include "../h/dir.h" ! 7: #include "../h/user.h" ! 8: #include "../h/file.h" ! 9: #include "../h/mtpr.h" ! 10: #include "../h/tty.h" ! 11: #include "../h/buf.h" ! 12: ! 13: /* ! 14: * bits in console registers ! 15: */ ! 16: ! 17: #define DONE 0200 ! 18: #define IE 0100 ! 19: #define BRK 01 /* transmit a break */ ! 20: ! 21: /* ! 22: * packet types ! 23: */ ! 24: ! 25: #define DATA 01 /* data packet */ ! 26: #define CTL 02 /* command */ ! 27: #define INIT 04 /* init handshake */ ! 28: #define CONT 020 /* continue */ ! 29: #define STOP 023 /* stop (flow control) */ ! 30: ! 31: /* ! 32: * opcodes in control packets ! 33: */ ! 34: ! 35: #define RESET 01 /* reset controller */ ! 36: #define READ 02 /* read a block */ ! 37: #define WRITE 03 /* write a block */ ! 38: #define END 0100 /* response from tu58 */ ! 39: ! 40: /* ! 41: * switches ! 42: */ ! 43: ! 44: #define MRSP 010 ! 45: ! 46: /* ! 47: * status codes in END packet ! 48: */ ! 49: ! 50: #define SOK 0 ! 51: #define SSOFT 1 /* ok but had to retry */ ! 52: #define SEOT (-2) /* ran off end of tape */ ! 53: #define SBBLK (-55) /* block number too big */ ! 54: ! 55: /* ! 56: * misc sizes ! 57: */ ! 58: ! 59: #define TBSIZE 512 /* size of a block on the tape */ ! 60: #define PMAX sizeof(struct dpkt) /* biggest packet size */ ! 61: #define DMAX 128 /* max bytes of data per packet */ ! 62: #define CCNT 10 /* count for CTL packets */ ! 63: ! 64: /* ! 65: * prototype control packet ! 66: */ ! 67: ! 68: struct cpkt { ! 69: char cp_flag; /* CTL */ ! 70: unsigned char cp_cnt; /* count == 012 */ ! 71: char cp_op; /* op code */ ! 72: char cp_mod; /* modifiers */ ! 73: char cp_unit; /* unit number */ ! 74: char cp_sw; /* switches (eg MRSP) */ ! 75: u_short cp_seq; /* sequence number (always 0) */ ! 76: u_short cp_bcnt; /* byte count */ ! 77: u_short cp_bno; /* desired block number */ ! 78: }; ! 79: ! 80: #define ce_sts cp_mod /* for END packet, success code */ ! 81: #define ce_xsts cp_bno /* extended status */ ! 82: ! 83: /* ! 84: * data packet ! 85: */ ! 86: ! 87: struct dpkt { ! 88: char cp_flag; /* DATA */ ! 89: unsigned char cp_cnt; /* count of data bytes following */ ! 90: char cd_data[DMAX]; ! 91: }; ! 92: ! 93: typedef union packet { ! 94: struct cpkt C; ! 95: struct dpkt D; ! 96: char B[PMAX]; ! 97: u_short W[PMAX / sizeof(u_short)]; ! 98: } PACKET; ! 99: ! 100: /* ! 101: * quick and dirty pseudo-clist ! 102: */ ! 103: ! 104: #define CBDAT 512 ! 105: #define QHI 400 ! 106: #define QLO 200 ! 107: ! 108: struct cbuf { ! 109: int cb_cc; ! 110: unsigned char *cb_rptr; ! 111: unsigned char *cb_wptr; ! 112: unsigned char cb_data[CBDAT]; ! 113: }; ! 114: ! 115: struct cbuf ctuin, ctuout; ! 116: int ctuflag; ! 117: ! 118: #define TBUSY 01 /* output busy */ ! 119: #define OPEN 02 /* device already open */ ! 120: #define WAIT 04 /* someone waiting for input */ ! 121: #define OSLEEP 010 /* someone waiting for output to drain */ ! 122: ! 123: #define DEBUG 0100000 /* debugging flag */ ! 124: ! 125: #define IPRI 28 ! 126: #define OPRI 29 ! 127: ! 128: #define hibyte(x) (((u_char *)&x)[1]) ! 129: #define lobyte(x) (((u_char *)&x)[0]) ! 130: #define hiword(x) (((u_short *)&x)[1]) ! 131: #define loword(x) (((u_short *)&x)[0]) ! 132: ! 133: ctuopen(dev, mode) ! 134: { ! 135: if (ctuflag & OPEN) { ! 136: u.u_error = EBUSY; ! 137: return; ! 138: } ! 139: ctuflag |= OPEN; ! 140: ctuinit(); ! 141: } ! 142: ! 143: ctuclose(dev, mode) ! 144: { ! 145: ! 146: mtpr(CSTS, 0); ! 147: mtpr(CSRS, 0); ! 148: ctuflag &=~ OPEN; ! 149: } ! 150: ! 151: cturead(dev, mode) ! 152: { ! 153: PACKET pkt; ! 154: register PACKET *pk = &pkt; ! 155: ! 156: if (u.u_count & 01) ! 157: u.u_count--; /* tu58 prefers even byte count */ ! 158: pk->C.cp_flag = CTL; ! 159: pk->C.cp_cnt = CCNT; ! 160: pk->C.cp_op = READ; ! 161: pk->C.cp_mod = 0; ! 162: pk->C.cp_unit = 0; ! 163: pk->C.cp_sw = MRSP; ! 164: pk->C.cp_seq = 0; ! 165: pk->C.cp_bcnt = u.u_count; ! 166: pk->C.cp_bno = u.u_offset / TBSIZE; ! 167: ctuput(pk); ! 168: for (;;) { ! 169: if (ctuget(pk) == 0) { ! 170: u.u_error = EIO; ! 171: break; ! 172: } ! 173: if (u.u_count == 0) ! 174: break; ! 175: if (pk->C.cp_flag != DATA) ! 176: break; ! 177: iomove(pk->D.cd_data, pk->C.cp_cnt, B_READ); ! 178: if (u.u_error) ! 179: break; ! 180: } ! 181: if (pk->C.cp_flag != CTL || pk->C.cp_op != END) ! 182: u.u_error = EIO; ! 183: if (u.u_error) { ! 184: ctuinit(); ! 185: return; ! 186: } ! 187: if (pk->C.ce_sts != SOK ! 188: && pk->C.ce_sts != SSOFT ! 189: && pk->C.ce_sts != SEOT /* operation overlapped end of tape */ ! 190: && pk->C.ce_sts != SBBLK) { /* operation past end of block */ ! 191: u.u_error = EIO; ! 192: printf("err on TU58: %o %o\n", pk->C.ce_sts & 0377, pk->C.ce_xsts); ! 193: return; ! 194: } ! 195: } ! 196: ! 197: ctuwrite(dev, mode) ! 198: { ! 199: PACKET pkt; ! 200: register PACKET *pk = &pkt; ! 201: ! 202: if (u.u_count & 01) ! 203: u.u_count--; ! 204: pk->C.cp_flag = CTL; ! 205: pk->C.cp_cnt = CCNT; ! 206: pk->C.cp_op = WRITE; ! 207: pk->C.cp_mod = 0; ! 208: pk->C.cp_unit = 0; ! 209: pk->C.cp_sw = MRSP; ! 210: pk->C.cp_seq = 0; ! 211: pk->C.cp_bcnt = u.u_count; ! 212: pk->C.cp_bno = u.u_offset / TBSIZE; ! 213: ctuput(pk); ! 214: for (;;) { ! 215: if (ctuget(pk) == 0) { ! 216: u.u_error = EIO; ! 217: break; ! 218: } ! 219: if (pk->C.cp_flag != CONT) ! 220: break; ! 221: if (u.u_count == 0) ! 222: break; ! 223: pk->C.cp_cnt = min(u.u_count, DMAX); ! 224: iomove(pk->D.cd_data, pk->C.cp_cnt, B_WRITE); ! 225: if (u.u_error) ! 226: break; ! 227: pk->C.cp_flag = DATA; ! 228: ctuput(pk); ! 229: } ! 230: if (pk->C.cp_flag != CTL || pk->C.cp_op != END) ! 231: u.u_error = EIO; ! 232: if (u.u_error) { ! 233: ctuinit(); ! 234: return; ! 235: } ! 236: if (pk->C.ce_sts != SOK ! 237: && pk->C.ce_sts != SSOFT ! 238: && pk->C.ce_sts != SEOT) { ! 239: u.u_error = EIO; ! 240: printf("err on TU58: %o %o\n", pk->C.ce_sts & 0377, pk->C.ce_xsts); ! 241: return; ! 242: } ! 243: } ! 244: ! 245: /* ! 246: * send a packet to the tu58 ! 247: */ ! 248: ! 249: ctuput(pk) ! 250: register PACKET *pk; ! 251: { ! 252: register u_short *wp; ! 253: register char *cp; ! 254: register int n; ! 255: long sum; ! 256: ! 257: if (ctusbc(pk->C.cp_flag)) { ! 258: ctputc(pk->C.cp_flag, &ctuout); ! 259: ctustart(); ! 260: return; ! 261: } ! 262: while (ctuout.cb_cc >= QHI) { ! 263: ctuflag |= OSLEEP; ! 264: sleep((caddr_t)&ctuout, OPRI); ! 265: } ! 266: wp = pk->W; ! 267: sum = 0; ! 268: n = (pk->C.cp_cnt / sizeof(u_short)) + 1; ! 269: while (--n >= 0) { ! 270: sum += *wp++; ! 271: if (hiword(sum)) { /* wrap carry around */ ! 272: sum++; ! 273: hiword(sum) = 0; ! 274: } ! 275: } ! 276: cp = pk->B; ! 277: n = pk->C.cp_cnt + 2; ! 278: while (--n >= 0) ! 279: ctputc(*cp++, &ctuout); ! 280: ctputc(lobyte(sum), &ctuout); ! 281: ctputc(hibyte(sum), &ctuout); ! 282: ctustart(); ! 283: } ! 284: ! 285: /* ! 286: * retrieve a packet from the tu58 ! 287: * returns zero if packet is illegal (eg bad checksum) ! 288: * if no packet, wait for one ! 289: */ ! 290: ! 291: ctuget(pk) ! 292: register PACKET *pk; ! 293: { ! 294: register u_short *wp; ! 295: register char *cp; ! 296: register int n; ! 297: long sum; ! 298: u_short xsum; ! 299: ! 300: pk->C.cp_flag = ctuchr(); ! 301: if (ctusbc(pk->C.cp_flag)) ! 302: return (1); ! 303: pk->C.cp_cnt = ctuchr(); ! 304: cp = &pk->B[2]; ! 305: n = pk->C.cp_cnt; ! 306: if (n > PMAX) ! 307: return (0); ! 308: while (--n >= 0) ! 309: *cp++ = ctuchr(); ! 310: lobyte(xsum) = ctuchr(); ! 311: hibyte(xsum) = ctuchr(); ! 312: wp = pk->W; ! 313: n = (pk->C.cp_cnt / sizeof(u_short)) + 1; ! 314: sum = 0; ! 315: while (--n >= 0) { ! 316: sum += *wp++; ! 317: if (hiword(sum)) { /* wrap carry around. ugh. */ ! 318: sum++; ! 319: hiword(sum) = 0; ! 320: } ! 321: } ! 322: if (ctuflag & DEBUG) ! 323: printf("ctu %x\n", pk->C.cp_flag); ! 324: if (sum != xsum) { ! 325: printf("ctu: sum %x is %x\n", xsum, sum); ! 326: return (0); ! 327: } ! 328: return (1); ! 329: } ! 330: ! 331: /* ! 332: * is this type a single byte packet? ! 333: */ ! 334: ! 335: ctusbc(type) ! 336: register int type; ! 337: { ! 338: ! 339: switch (type) { ! 340: case DATA: ! 341: case CTL: ! 342: return (0); ! 343: ! 344: default: ! 345: return (1); ! 346: } ! 347: } ! 348: ! 349: /* ! 350: * hard reset ! 351: * called on open or error ! 352: */ ! 353: ! 354: ctuinit() ! 355: { ! 356: ! 357: mtpr(CSRS, 0); ! 358: mtpr(CSTS, BRK); ! 359: DELAY(250000); ! 360: mtpr(CSTS, 0); ! 361: ctflushq(&ctuin); ! 362: ctflushq(&ctuout); ! 363: mtpr(CSRS, IE); ! 364: ctputc(INIT, &ctuout); ! 365: ctputc(INIT, &ctuout); ! 366: ctustart(); ! 367: while (ctuchr() != CONT) ! 368: ; ! 369: } ! 370: ! 371: /* ! 372: * wait for one character from tu58 ! 373: */ ! 374: ! 375: ctuchr() ! 376: { ! 377: register int s; ! 378: ! 379: s = spl7(); ! 380: while (ctuin.cb_cc == 0) { ! 381: ctuflag |= WAIT; ! 382: sleep((caddr_t)&ctuin, IPRI); ! 383: } ! 384: splx(s); ! 385: return (ctgetc(&ctuin)); ! 386: } ! 387: ! 388: /* ! 389: * start output from queue ! 390: */ ! 391: ! 392: ctustart() ! 393: { ! 394: register int c; ! 395: register int s; ! 396: ! 397: s = spl7(); ! 398: if (ctuflag & TBUSY) ! 399: return; ! 400: if ((c = ctgetc(&ctuout)) >= 0) { ! 401: ctuflag |= TBUSY; ! 402: mtpr(CSTD, c); ! 403: mtpr(CSTS, IE); ! 404: } ! 405: if (ctuflag & OSLEEP && ctuout.cb_cc < QLO) { ! 406: wakeup((caddr_t)&ctuout); ! 407: ctuflag &=~ OSLEEP; ! 408: } ! 409: splx(s); ! 410: } ! 411: ! 412: ctuxint(dev) ! 413: { ! 414: ! 415: ctuflag &=~ TBUSY; ! 416: ctustart(); ! 417: } ! 418: ! 419: cturint(dev) ! 420: { ! 421: static char cont = CONT; ! 422: ! 423: while (mfpr(CSRS) & DONE) { ! 424: ctputc(mfpr(CSRD), &ctuin); ! 425: ctuput((PACKET *)&cont); ! 426: if (ctuin.cb_cc > QHI) { ! 427: printf("ctu input overrun\n"); ! 428: ctflushq(&ctuin); ! 429: } ! 430: } ! 431: if (ctuflag & WAIT) { ! 432: ctuflag &=~ WAIT; ! 433: wakeup((caddr_t)&ctuin); ! 434: } ! 435: } ! 436: ! 437: /* ! 438: * fake clist routines ! 439: */ ! 440: ! 441: ctflushq(q) ! 442: register struct cbuf *q; ! 443: { ! 444: register int s; ! 445: ! 446: s = spl7(); ! 447: q->cb_cc = 0; ! 448: q->cb_rptr = q->cb_wptr = q->cb_data; ! 449: splx(s); ! 450: } ! 451: ! 452: int ! 453: ctgetc(q) ! 454: register struct cbuf *q; ! 455: { ! 456: register int s; ! 457: register int c; ! 458: ! 459: s = spl7(); ! 460: if (q->cb_cc <= 0) ! 461: c = -1; ! 462: else { ! 463: q->cb_cc--; ! 464: c = *q->cb_rptr++; ! 465: if (q->cb_rptr >= &q->cb_data[CBDAT]) ! 466: q->cb_rptr = q->cb_data; ! 467: } ! 468: splx(s); ! 469: return (c); ! 470: } ! 471: ! 472: ctputc(c, q) ! 473: char c; ! 474: register struct cbuf *q; ! 475: { ! 476: register int s; ! 477: ! 478: s = spl7(); ! 479: q->cb_cc++; ! 480: *q->cb_wptr++ = c; ! 481: if (q->cb_wptr >= &q->cb_data[CBDAT]) ! 482: q->cb_wptr = q->cb_data; ! 483: splx(s); ! 484: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.