|
|
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.