|
|
1.1 root 1: /*
2: * DZ-11 driver
3: * ------------
4: *
5: * OPTIMIZED dz driver to handle multiple dzs as efficiently
6: * as possible. The efficiency is gained by disabling all
7: * dz transmitter interrupts and using a KW11-P to generate
8: * suitable interrupts. Carrier is supported but not Ring.
9: *
10: * Ian Johnstone UNSW
11: * May 1979
12: */
13:
14: #include "../defines.h"
15: #include "../param.h"
16: #include "../conf.h"
17: #include "../user.h"
18: #include "../tty.h"
19: #include "../proc.h"
20:
21: #define NDZ 7 /* no. of dz-11s */
22:
23: #define NDZLIN 8 /* no. of lines per dz DO NOT ALTER */
24: #define NLINES (NDZLIN*NDZ) /* total no. of lines available */
25:
26: #define SSPEED 11 /* standard speed 2400 bd */
27:
28: #define CLOCK 0172540 /* kw11-p lives here */
29:
30: struct
31: {
32: int csr; /* control and status */
33: #define GO 0101 /* down, single, 100K, run */
34: unsigned counter; /* counter */
35: };
36:
37: struct tty dz11[NLINES]; /* tty structures for this dz */
38:
39: struct dz /* one for each dz-11 */
40: {
41: int *dzaddr; /* control registers for this dz */
42: char nocarr; /* set for lines WITHOUT carrier */
43: char sopen; /* set for lines with exclusive use */
44: struct tty *ttys[NDZLIN]; /* address of tty structs this dz */
45: /* that is only ONE `open' allowed */
46: char openl; /* flags for open lines */
47: char closl; /* flags to indicate closing lines */
48: char xmit; /* set for lines to transmit on */
49: unsigned pyerrors; /* number of parity errors on input */
50: unsigned overrors; /* number of overrun errors on input */
51: int closet[NDZLIN]; /* handle closing via this field */
52: }
53: dz[NDZ]
54: {
55: {
56: 0160100, 0377, 0000,
57: &dz11[000],&dz11[001],&dz11[002],&dz11[003],
58: &dz11[004],&dz11[005],&dz11[006],&dz11[007]
59: },
60: {
61: 0160110, 0007, 0000,
62: &dz11[010],&dz11[011],&dz11[012],&dz11[013],
63: &dz11[014],&dz11[015],&dz11[016],&dz11[017]
64: },
65: {
66: 0160120, 0320, 0020,
67: &dz11[020],&dz11[021],&dz11[022],&dz11[023],
68: &dz11[024],&dz11[025],&dz11[026],&dz11[027]
69: },
70: {
71: 0160130, 0000, 0000,
72: &dz11[030],&dz11[031],&dz11[032],&dz11[033],
73: &dz11[034],&dz11[035],&dz11[036],&dz11[037]
74: },
75: {
76: 0160140, 0000, 0000,
77: &dz11[040],&dz11[041],&dz11[042],&dz11[043],
78: &dz11[044],&dz11[045],&dz11[046],&dz11[047]
79: },
80: {
81: 0160150, 0360, 0100,
82: &dz11[050],&dz11[051],&dz11[052],&dz11[053],
83: &dz11[054],&dz11[055],&dz11[056],&dz11[057]
84: },
85: {
86: 0160160, 0110, 0013,
87: &dz11[060],&dz11[061],&dz11[062],&dz11[063],
88: &dz11[064],&dz11[065],&dz11[066],&dz11[067]
89: },
90: /*
91: {
92: 0160170, 0377, 0000,
93: &dz11[070],&dz11[071],&dz11[072],&dz11[073],
94: &dz11[074],&dz11[075],&dz11[076],&dz11[077]
95: }
96: */
97: };
98:
99: int dzopenc; /* equal to total number of 'open' lines */
100:
101: int dzrcvscan; /* when <= 0 scan receiver silos */
102:
103: char dzbitab[NDZLIN] /* convert line numbers to bit pattern */
104: {
105: 0001, 0002, 0004, 0010, 0020, 0040, 0100, 0200
106: };
107:
108: #define SPLDZ spl5 /* dz interrupts at this priority */
109:
110: /*
111: * DZ11 register layout
112: */
113: struct dzr_read
114: {
115: int dzcsr; /* r/w */
116: int dzrbuf; /* no bit, byte, or tst ops */
117: char dztcr; /* r/w */
118: char dzdtr; /* r/w */
119: char dzring;
120: char dzcarr;
121: };
122: struct dzr_write
123: {
124: int dzcsr;
125: int dzlpr; /* no bit or byte ops */
126: char dztcr;
127: char dzdtr;
128: char dztbuf; /* no bit ops */
129: char dzbrk; /* no bit ops */
130: };
131: /*
132: * register control bits
133: */
134: #define SAE 010000 /* dzcsr */
135: #define RIE 0100
136: #define MSE 040
137: #define RCVR_ON 010000 /* dzlpr */
138: #define ODD_PAR 0300
139: #define EVN_PAR 0100
140: #define TWOSBIT 040
141: #define C8BIT 030
142: #define C7BIT 020
143: #define RERROR 070000 /* dzrbuf */
144: #define OVR_RUN 040000
145: #define FRAME 020000
146: #define PARITY 010000
147:
148: /*
149: * Table to map UNIX standard speeds to DZ11 speeds.
150: * Illegal speeds are ignored, and are indicated by 0200 bit.
151: */
152: char dzspeedmap[16]
153: {
154: 0200 /* 0 - zero */
155: , 0220 /* 1 - 50 */
156: , 0221 /* 2 - 75 */
157: , 0222 /* 3 - 110 */
158: , 0223 /* 4 - 134.5 */
159: , 0224 /* 5 - 150 */
160: , 0200 /* 6 - ILLEGAL */
161: #define LOWSPEED 7 /* lowest speed allowed on dz */
162: , 025 /* 7 - 300 */
163: , 026 /* 8 - 600 */
164: , 027 /* 9 - 1200 */
165: , 0230 /* 10 - 1800 */
166: , 032 /* 11 - 2400 */
167: , 034 /* 12 - 4800 */
168: , 036 /* 13 - 9600 */
169: , 0231 /* 14 - ext A - maps to 2000 */
170: , 0237 /* 15 - ext B - maps to 19200 */
171: };
172:
173: /*
174: * Table to map UNIX standard speeds to time between interrupts for
175: * a line running at that speed. The value in the table is multiplied
176: * by 10 to get a value in microseconds. A nominal 20 microseconds
177: * is subtracted to make up for interrupt overhead.
178: */
179:
180: unsigned dzmicmap[16]
181: {
182: 0 /* 0 - zero */
183: , 19998 /* 1 - 50 */
184: , 13331 /* 2 - 75 */
185: , 9088 /* 3 - 110 */
186: , 7433 /* 4 - 134.5 */
187: , 6665 /* 5 - 150 */
188: , 0 /* 6 - ILLEGAL */
189: , 3331 /* 7 - 300 */
190: , 1665 /* 8 - 600 */
191: , 831 /* 9 - 1200 */
192: , 554 /* 10 - 1800 */
193: , 415 /* 11 - 2400 */
194: , 206 /* 12 - 4800 */
195: , 102 /* 13 - 9600 */
196: , 498 /* 14 - ext A - maps to 2000 */
197: , 50 /* 15 - ext B - maps to 19200 */
198: };
199:
200: /*
201: * open a DZ11 line
202: */
203: dzopen(dev, flag)
204: {
205: extern dzstart();
206: register struct tty *tp;
207: register struct dz *dzp;
208: register lino;
209:
210: lino = dev.d_minor;
211: if(lino >= NLINES)
212: {
213: u.u_error = ENXIO;
214: return;
215: }
216: dzp = &dz[lino>>3];
217: if(!fkword(dzp->dzaddr)) /* fix036 */
218: {
219: u.u_error = ENXIO;
220: return;
221: } /* fix036 */
222: tp = &dz11[lino];
223: lino =& 07;
224:
225: if( (dzp->sopen&dzbitab[lino]) && (dzp->openl&dzbitab[lino]) )
226: {
227: u.u_error = EOPENFAIL;
228: return;
229: }
230:
231: if(u.u_procp->p_ttyp == 0)
232: u.u_procp->p_ttyp = tp;
233:
234: SPLDZ();
235:
236: if( (dzp->openl&dzbitab[lino]) == 0 )
237: {
238: tp->t_dev = dev;
239: tp->t_state = (ISOPEN|CARR_ON|SSTART);
240: tp->t_addr = &dzstart;
241: tp->t_speeds = SSPEED|(SSPEED<<8);
242: tp->t_flags = ODDP|EVENP|XTABS|RAW;
243: tp->t_erase = CERASE;
244: tp->t_kill = CKILL;
245:
246: dzparam(tp);
247:
248: if(dzp->openl == 0)
249: dzp->dzaddr->dzcsr =| (RIE|SAE|MSE); /* init */
250:
251: dzp->openl =| dzbitab[lino];
252:
253: if(dzopenc++ == 0)
254: dzxint(); /* start transmitting */
255:
256: }
257: else
258: dzp->closl =& ~dzbitab[lino];
259: spl0();
260: }
261:
262: /*
263: * close a DZ11 line
264: */
265: dzclose(dev)
266: {
267: register struct tty *tp;
268: register struct dz *dzp;
269: register lino;
270:
271: lino = dev.d_minor;
272: dzp = &dz[lino>>3];
273: tp = &dz11[lino];
274: lino =& 07;
275:
276: dzp->closet[lino] = tp->t_outq.c_cc << 1; /* time for close */
277: dzp->closl =| dzbitab[lino];
278: dzp->xmit =| dzbitab[lino]; /* start transmitting */
279: dzp->dzaddr->dztcr =| dzbitab[lino]; /* start transmitting */
280: }
281:
282: /*
283: * read from a DZ11 line
284: */
285: dzread(dev)
286: {
287: ttread( &dz11[dev.d_minor] );
288: }
289:
290: /*
291: * write on a DZ11 line
292: */
293: dzwrite(dev)
294: {
295: ttwrite( &dz11[dev.d_minor] );
296: }
297:
298: /*
299: * stty/gtty for DZ11
300: */
301: dzsgtty(dev, av)
302: {
303: register struct tty *tp;
304:
305: if((av == 0) && (dzspeedmap[u.u_arg[0]&017] < 0))
306: {
307: u.u_error = ENXIO; /* illegal speed */
308: return;
309: }
310: tp = &dz11[dev.d_minor];
311: if(ttystty(tp, av))
312: return;
313: dzparam(tp);
314: }
315:
316: /*
317: * set parameters from open or stty into DZ hardware registers
318: */
319: dzparam(tp)
320: register struct tty *tp;
321: {
322: register lpr, x;
323: extern wakeup();
324:
325: lpr = dzspeedmap[tp->t_speeds&017]<<8;
326:
327: if((x = tp->t_flags)&EVENP)
328: if((x&ODDP) == 0)
329: lpr =| (EVN_PAR|C7BIT);
330: else
331: lpr =| C8BIT;
332: else if(x&ODDP)
333: lpr =| (ODD_PAR|C7BIT);
334: else
335: lpr =| C8BIT;
336:
337: /* set new speed, char currently in uart may be screwed */
338:
339: dz[tp->t_dev.d_minor>>3].dzaddr->dzlpr = lpr|(tp->t_dev.d_minor&07);
340: }
341: /*
342: * dz start routine
343: */
344: dzstart(tp) /* at SPLDZ */
345: struct tty *tp;
346: {
347: register lino = tp->t_dev.d_minor;
348: register struct dz *dzp;
349:
350: dzp = &dz[lino>>3];
351: lino =& 07;
352: dzp->xmit =| dzbitab[lino]; /* start transmitting */
353: dzp->dzaddr->dztcr =| dzbitab[lino]; /* start transmitting */
354: }
355:
356: /*
357: * DZ11 transmitter interrupt.
358: *
359: * Scan every line on each dz. Internal dz limitations
360: * force this scan to take an unusual form. One line
361: * from each dz is serviced each scan until no dz requires
362: * service. This is less efficient than servicing
363: * entirely a dz prior to scanning the next dz but it
364: * it is necessary.
365: *
366: * dzxint is not actually invoked by a dz interrupt
367: * rather it is invoked by a clock interrupt.
368: * to drive multiple dz's efficiently utilizing dz
369: * transmitter interrupts is just NOT possible.
370: */
371: int dzxc;
372: dzxint() /* at SPLDZ */
373: {
374: extern ttrstrt();
375: register struct dz *dzp;
376: int hspeed = LOWSPEED; /* to determine clock speed */
377: int flag; /* control dz scanning */
378:
379: dzxc++; /* count */
380: if( dzopenc == 0 ) return; /* stop if inactive */
381:
382: /* scan every dz for characters to transmit */
383:
384: do
385: {
386: for(dzp = &dz[0], flag=0; dzp < &dz[NDZ]; dzp++ )
387: {
388: register struct tty *tp;
389: register struct dzr_read *dza = dzp->dzaddr;
390: int lino, t_bit;
391:
392: if((lino = dza->dzcsr.hibyte) < 0) /* xmit ?? */
393: {
394: lino =& 07; /* isolate line number */
395: tp = dzp->ttys[lino];
396: t_bit = dzbitab[lino]; /* bit mask, not line number */
397: flag++; /* note service */
398: if( (dzp->closl & t_bit)
399: && ((--(dzp->closet[lino]) <= 0) || (tp->t_outq.c_cc == 0)) )
400: {
401: /* line closed, no time or chars left */
402: flushtty(tp);
403: tp->t_state = SSTART;
404: dzp->closl =& ~t_bit;
405: dzp->openl =& ~t_bit;
406: dzp->xmit =& ~t_bit;
407: dza->dztcr =& ~t_bit;
408: dza->dzdtr =& ~t_bit;
409: if( (dzp->closl==0) && (dzp->openl==0) )
410: dza->dzcsr = 0;
411: if( --dzopenc == 0 )
412: return;
413: }
414: else if(tp->t_outq.c_cc == 0)
415: {
416: dzp->xmit =& ~t_bit;
417: dza->dztcr =& ~t_bit;
418: }
419: else if((dzp->nocarr&t_bit)||(dza->dzcarr&t_bit))
420: {
421: int c = getc(&tp->t_outq);
422: if( c <= 0177 || tp->t_flags == RAW )
423: {
424: /* transmit the char for this line */
425: dza->dztbuf = c;
426: if( tp->t_speeds.lobyte > hspeed )
427: hspeed = tp->t_speeds.lobyte;
428: }
429: else
430: {
431: dzp->xmit =& ~t_bit;
432: dza->dztcr =& ~t_bit;
433: timeout( &ttrstrt, tp, c&0177 );
434: tp->t_state =| TIMEOUT;
435: }
436: /* if low water mark then want more */
437: if( tp->t_state&ASLEEP
438: && tp->t_outq.c_cc <= TTLOWAT )
439: {
440: tp->t_state =& ~ASLEEP;
441: wakeup(&tp->t_outq);
442: }
443: }
444: else
445: {
446: dza->dztcr =& ~t_bit;
447: }
448: }
449: }
450: } while( flag );
451:
452: /* finalize state of DZs prior to exitting */
453:
454: for(dzp = &dz[0]; dzp < &dz[NDZ]; dzp++ )
455: {
456: register struct dzr_read *dza = dzp->dzaddr;
457:
458: /* dtr to reflect state of carrier, for carrier lines */
459:
460: dza->dzdtr = (dza->dzcarr | dzp->nocarr) & dzp->openl;
461:
462: /* Enable all lines still with characters to send */
463:
464: dza->dztcr = dzp->xmit;
465: }
466:
467: /* setup for next interrupt */
468:
469: CLOCK->counter = dzmicmap[hspeed]; /* count in 10microseconds */
470: CLOCK->csr = GO;
471:
472: /* call dzrint if needed */
473:
474: if( dzrcvscan <= 0 )
475: dzrint(0);
476: dzrcvscan =- dzmicmap[hspeed];
477: }
478:
479: /*
480: * DZ11 receiver interrupt
481: *
482: * Scan each dz commencing with the particular device that caused this call
483: * Scan at least every dzmicmap[LOWSPEED] microseconds.
484: */
485: dzrint(dev)
486: {
487: register struct tty *tp;
488: register struct dz *dzp;
489: register int lino;
490: int i, c;
491:
492: for(dzp = &dz[dev], i = 0; i < NDZ; i++)
493: {
494: while((c = dzp->dzaddr->dzrbuf) < 0) /* char present in silo */
495: {
496: lino = c.hibyte; lino =& 07;
497: if( ((dzp->nocarr&dzbitab[lino]) == 0 )
498: && ((dzp->dzaddr->dzcarr&dzbitab[lino]) == 0 )) continue;
499: if( (dzp->openl&dzbitab[lino]) == 0 ) continue;
500: tp = dzp->ttys[lino];
501: if(c&RERROR)
502: {
503: if( (c & FRAME) && (tp->t_flags & RAW ) )
504: ttyinput(0, tp); /* break for getty */
505: else if(c & OVR_RUN)
506: dzp->overrors++;
507: else if(c & PARITY)
508: dzp->pyerrors++;
509: }
510: else
511: {
512: ttyinput(c, tp);
513: }
514: }
515: if( ++dzp >= &dz[NDZ] ) dzp = &dz[0];
516: }
517: dzrcvscan = dzmicmap[LOWSPEED];
518: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.