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