BSD 4 development
[unix-history] / usr / src / cmd / berknet / dz2.c
CommitLineData
ef1865d1
BJ
1/*
2 * DZ-11 driver
3 * ------------
4 *
5 * Written to handle single dz - `carrier'|`ring' support non-existent
6 *
7 * Piers Lauder
8 * SYDNEY UNIVERSITY
9 * July 1977
10 *
11 * Re-written to handle multiple dz's and `carrier'|`ring'.
12 *
13 * Ian Johnstone
14 * UNSW
15 * December 1977
16 * January 1978
17 *
18 * General tidy up, new comments etc. Removal of ifdefs
19 * for CARRIER and RING. If you don't want them, tough.
20 *
21 * Chris Maltby
22 * Basser October 1979
23 */
24
25
26/* ( no messages )
27#define MESSAGES
28 /*
29 * Define this if you want parity and framing errors
30 * to be logged (via printf). It can be very wordy.
31 */
32
33#define INTR_ON_BREAK
34 /*
35 * Define this to translate framing errors (breaks)
36 * to CINTR for terminals which lack a DEL key.
37 * Can be nasty if you get lots of line errors.
38 */
39
40/* (not DEBUG)
41#define DEBUG
42 /*
43 * Define to debug info for dialup lines.
44 * costs approximately 128 bytes
45 */
46
47#include "../defines.h"
48#include "../param.h"
49#ifdef DEBUG
50#ifdef AUSAML
51#include "../lnode.h"
52#endif AUSAML
53#include "../systm.h"
54#endif DEBUG
55#include "../conf.h"
56#include "../user.h"
57#include "../tty.h"
58#include "../proc.h"
59
60
61#define NDZ 2 /* number of DZ-11s */
62#define NLINES 8*NDZ /* total number of lines */
63#define TSCANRATE 2 /* dzscan called every 2 tics */
64 /* Must be >= 2 always */
65
66#define RESPONDTIME (25*HZ) /* Carrier must be raised inside this */
67#define CARRIERTIME (1*HZ) /* Carrier must drop for this before hangup */
68
69#define FLUSHTIME 5 /* time required to allow hardware buffered
70 * characters to flush before setting speed */
71
72#define SSPEED 12 /* standard speed 4800 bd */
73
74struct dz /* one for each dz-11 */
75{
76 int *dzaddr; /* dz device address */
77 char sopen; /* bit set for single open lines */
78 char carrier; /* bits set for carrier controlled lines */
79 char ring; /* bits set for lines with dial in modems */
80 char active; /* bits set for active dialup lines */
81 char openl; /* bits set for open lines */
82 unsigned pyerrors; /* count of of parity errors on input */
83 unsigned overrors; /* count of of overrun errors on input */
84}
85dz[NDZ]
86{
87 /* dzaddr sopen carr ring */
88 { 0160040, 0002, 0077, 0074 },
89 { 0160050, 0000, 0000, 0000 }
90};
91int dzscanning; /* set when scanning for input and modem change */
92
93/*
94 * DZ11 register layout
95 */
96
97struct dzr_read
98{
99 int dzcsr; /* r/w */
100 int dzrbuf; /* no bit, byte, or tst ops */
101 char dztcr; /* r/w */
102 char dzdtr; /* r/w */
103 char dzring;
104 char dzcarr;
105};
106
107struct dzr_write
108{
109 int dzcsr; /* r/w */
110 int dzlpr; /* no bit or byte ops */
111 char dztcr; /* r/w */
112 char dzdtr; /* r/w */
113 char dztbuf; /* no bit ops */
114 char dzbrk; /* no bit ops */
115};
116
117/*
118 * register control bits
119 */
120#define TRDY 0100000 /* dzcsr */
121#define TIE 040000
122#define SA 020000
123#define SAE 010000
124#define TLINE 03400
125#define RDONE 0200
126#define RIE 0100
127#define MSE 040
128#define CLR 020
129
130#define RCVR_ON 010000 /* dzlpr */
131#define S9600 07000
132#define S300 02400
133#define S134_5 01400
134#define S110 01000
135#define ODD_PAR 0300
136#define EVN_PAR 0100
137#define TWOSBIT 040
138#define C8BIT 030
139#define C7BIT 020
140#define C6BIT 010
141/*
142#define IBM2741 RCVR_ON|S134_5|ODD_PAR|C6BIT /* if you must */
143
144#define RERROR 070000 /* dzrbuf */
145#define OVR_RUN 040000
146#define FRAME 020000
147#define PARITY 010000
148#define LINE_NO 03400
149
150/*
151 * table to map UNIX standard speeds to DZ11 speeds
152 * illegal speeds are ignored.
153 */
154char dzspeedmap[16]
155{
156 0 /* 0 - zero */
157 , 020 /* 1 - 50 */
158 , 021 /* 2 - 75 */
159 , 022 /* 3 - 110 */
160 , 023 /* 4 - 134.5 */
161 , 024 /* 5 - 150 */
162 ,0200 /* 6 - 200 -- ## ILLEGAL ## */
163 , 025 /* 7 - 300 */
164 , 026 /* 8 - 600 */
165 , 027 /* 9 - 1200 */
166 , 030 /* 10 - 1800 */
167 , 032 /* 11 - 2400 */
168 , 034 /* 12 - 4800 */
169 , 036 /* 13 - 9600 */
170 , 031 /* 14 - ext A - maps to 2000 */
171 , 037 /* 15 - ext B - maps to 19200 */
172};
173
174
175
176struct tty dz11[NLINES];
177
178char dzdelays[NLINES]; /* Count of clock ticks for per-line
179 * delays. Count of <= 0 means no delay.
180 * Reduces requirement of timeouts.
181 */
182
183int dzringt[NLINES]; /* Delay counts for modem control */
184
185/*
186 * open a DZ11 line
187 */
188dzopen(dev, flag)
189{
190 register struct tty *tp;
191 register struct dz *dzp;
192 register int t_bit;
193 extern dzstart(), dzscan();
194
195
196 if(dev.d_minor >= NLINES)
197 {
198 u.u_error = ENXIO;
199 return;
200 }
201 dzp = &dz[dev.d_minor>>3];
202 t_bit = (1<<(dev.d_minor&07));
203 if((dzp->sopen&t_bit) && (dzp->openl&t_bit))
204 {
205 u.u_error = EOPENFAIL;
206 return;
207 }
208 tp = &dz11[dev.d_minor];
209 if(u.u_procp->p_ttyp == 0)
210 u.u_procp->p_ttyp = tp;
211 if((tp->t_state&ISOPEN) == 0)
212 {
213 tp->t_dev = dev;
214 tp->t_addr = &dzstart;
215 tp->t_speeds = SSPEED|(SSPEED<<8);
216 tp->t_flags = ODDP|EVENP|XTABS|RAW;
217 tp->t_erase = CERASE;
218 tp->t_kill = CKILL;
219 if(dzp->openl == 0)
220 dzp->dzaddr->dzcsr =| (TIE|RIE|SAE|MSE); /* reciever interrupt every 16 chars */
221 dzp->openl =| t_bit;
222 spl5();
223 if(dzscanning == 0)
224 dzscan(); /* start scanning */
225 if(!(dzp->ring&t_bit) && !(dzp->carrier&t_bit))
226 dzp->dzaddr->dzdtr =| t_bit; /* turn on DTR for non-dialup lines */
227 else
228 {
229# ifdef DEBUG
230 printf("%d wo%d\n", time.loint, dev.d_minor);
231# endif DEBUG
232 while(!(dzp->dzaddr->dzcarr&t_bit))
233 {
234 tp->t_state =| WOPEN;
235 sleep(&tp->t_rawq, TTIPRI);
236 }
237# ifdef DEBUG
238 printf("%d op%d\n", time.loint, dev.d_minor);
239# endif DEBUG
240 }
241 spl0();
242 tp->t_state = (ISOPEN|CARR_ON|SSTART);
243 dzparam(tp, 1);
244 }
245}
246
247
248/*
249 * scan open lines for:
250 * 1. modem status changes
251 * 2. process timeouts as dictated by dzdelays
252 * 3. input by calling dzrint
253 */
254dzscan() /* at spl5 */
255{
256 register struct dz *dzp;
257 struct tty *tp;
258 int *p;
259 extern dzstart(), dzrint(), dzscan();
260# define openring (dzp->openl & dzp->ring)
261# define opencarrier (dzp->openl & dzp->carrier)
262
263 /*
264 * scan open dialup/carrier lines.
265 */
266 tp = &dz11[0];
267 p = &dzringt[0];
268 for(dzp = dz; dzp < &dz[NDZ]; dzp++)
269 {
270 register int *dzaddr;
271 char scanl, scanc;
272
273 dzaddr = dzp->dzaddr;
274 if((scanl = openring) | (scanc = opencarrier))
275 {
276 register int t_bit;
277
278 for(t_bit = 1; t_bit&0377; t_bit =<< 1, tp++, p++)
279 {
280 if(scanl&t_bit)
281 {
282 /* this is an open `dialup' line */
283 if(dzp->active&t_bit)
284 {
285 if(!(dzaddr->dzcarr&t_bit))
286 {
287 if(*p == 0)
288 *p = CARRIERTIME;
289 else if((*p =- TSCANRATE) <= 0)
290 {
291 *p = 0; /* disable */
292# ifdef DEBUG
293 printf("%d hu%d\n", time.loint, tp->t_dev.d_minor);
294# endif DEBUG
295 dzaddr->dzdtr =& ~t_bit; /* hang up the phone */
296 signal(tp, SIGHUP);
297 flushtty(tp);
298 dzaddr->dztcr =& ~t_bit; /* disable transmit */
299 dzp->active =& ~t_bit;
300 }
301 }
302 else
303 {
304 if(tp->t_state&WOPEN)
305 wakeup(&tp->t_rawq);
306 *p = 0;
307 if(!(tp->t_state&TIMEOUT) && (tp->t_outq.c_cc))
308 dzaddr->dztcr =| t_bit;
309 }
310 }
311 else
312 {
313 if(!(dzaddr->dzdtr&t_bit) && (dzaddr->dzring&t_bit))
314 {
315 dzaddr->dzdtr =| t_bit; /* answer the phone */
316 *p = RESPONDTIME;
317 dzp->active =| t_bit;
318# ifdef DEBUG
319 printf("%d ap%d\n", time.loint, tp->t_dev.d_minor);
320# endif DEBUG
321 }
322 }
323 }
324 else if((scanc&t_bit) && (dzaddr->dzcarr&t_bit))
325 { /* carrier only line */
326 if(tp->t_state&WOPEN)
327 {
328 dzaddr->dzdtr =| t_bit;
329 wakeup(&tp->t_rawq);
330 }
331 else if((!(tp->t_state&TIMEOUT)) && (tp->t_outq.c_cc))
332 dzaddr->dztcr =| t_bit;
333 }
334 }
335 }
336 else
337 {
338 tp =+ 8; p =+ 8; /* in the case where no dialup/carrier lines on current dz */
339 }
340 }
341
342 /*
343 * process timeouts for each line
344 */
345
346 {
347 register i;
348
349 for(i = 0; i < NLINES; i++)
350 if((dzdelays[i] > 0) && (--dzdelays[i] <= 0))
351 {
352 dz11[i].t_state =& ~TIMEOUT;
353 dzstart(&dz11[i]);
354 }
355 }
356
357 /*
358 * scan each dz for input
359 */
360
361 dzrint(0);
362
363 /*
364 * restart scanning if necessary
365 */
366
367 dzp = dz;
368 do
369 {
370 if(dzp->openl)
371 {
372 dzscanning = timeout(&dzscan, 0, TSCANRATE);
373 return;
374 }
375 dzp++;
376 } while(dzp < &dz[NDZ]);
377 dzscanning = 0;
378}
379
380/*
381 * close a DZ11 line
382 */
383dzclose(dev)
384{
385 register struct tty *tp;
386 register t_bit;
387 register struct dz *dzp;
388
389 tp = &dz11[dev.d_minor];
390 wflushtty(tp);
391 tp->t_state = SSTART;
392 dzp = &dz[dev.d_minor>>3];
393 t_bit = 1<<(dev.d_minor&07);
394 if(dzp->ring&t_bit)
395 {
396 if(tp->t_flags&HUPCL)
397 dzp->dzaddr->dzdtr =& ~t_bit; /* hang up the phone */
398 }
399 else
400 {
401 dzp->dzaddr->dzdtr =& ~t_bit; /* turn off dtr for non-dialup lines */
402 }
403 if((dzp->openl =& ~t_bit) == 0)
404 dzp->dzaddr->dzcsr = 0; /* disable receive on final close */
405}
406
407
408
409/*
410 * read from a DZ11 line
411 */
412dzread(dev)
413{
414 ttread(&dz11[dev.d_minor]);
415}
416
417
418
419/*
420 * write on a DZ11 line
421 */
422dzwrite(dev)
423{
424 ttwrite(&dz11[dev.d_minor]);
425}
426
427
428
429/*
430 * stty/gtty for DZ11
431 */
432dzsgtty(dev, av)
433int *av;
434{
435 register struct tty *tp;
436
437 if((av == 0) && (dzspeedmap[u.u_arg[0]&017] < 0))
438 {
439 u.u_error = ENXIO; /* illegal speed */
440 return;
441 }
442 tp = &dz11[dev.d_minor];
443 if(ttystty(tp, av))
444 return;
445 dzparam(tp, 1);
446}
447
448
449
450/*
451 * set parameters from open or stty into DZ hardware registers
452 */
453dzparam(tp, dflag)
454register struct tty *tp;
455{
456 register lpr, x;
457 extern wakeup();
458
459
460 lpr = dzspeedmap[tp->t_speeds&017]<<8;
461
462#ifdef IBM2741
463 if(lpr == (RCVR_ON|S134_5))
464 lpr = IBM2741;
465 else
466 {
467#endif IBM2741
468 if(lpr == (RCVR_ON|S110))
469 lpr =| TWOSBIT;
470
471 if((x = tp->t_flags)&EVENP)
472 if((x&ODDP) == 0)
473 lpr =| (EVN_PAR|C7BIT);
474 else
475 lpr =| C8BIT;
476 else if(x&ODDP)
477 lpr =| (ODD_PAR|C7BIT);
478 else
479 lpr =| C8BIT;
480#ifdef IBM2741
481 }
482#endif IBM2741
483
484 if(dflag)
485 {
486 /* delay only if it is permissible */
487#ifndef DELAY
488 timeout(&wakeup, tp, FLUSHTIME); /* wakeup in 5 tics */
489 sleep(tp, TTOPRI); /* delay while controller flushes */
490#else
491 delay(FLUSHTIME); /* hang 5 */
492#endif DELAY
493 }
494
495 dz[tp->t_dev.d_minor>>3].dzaddr->dzlpr = lpr|(tp->t_dev.d_minor&07);
496}
497
498
499
500/*
501 * start (restart) transmission on a DZ11 line
502 */
503dzstart(tp)
504register struct tty *tp;
505{
506 register t_bit;
507 register struct dz *dzp;
508
509
510 t_bit = 1<<(tp->t_dev.d_minor&07);
511 dzp = &dz[tp->t_dev.d_minor>>3];
512 if((!(dzp->carrier&t_bit)) || (dzp->dzaddr->dzcarr&t_bit))
513 dzp->dzaddr->dztcr =| t_bit;
514}
515
516
517/*
518 * DZ11 transmitter interrupt.
519 *
520 * Scan every line on each dz.
521 * Commencing with the device that caused
522 * dzxint to be called.
523 */
524dzxint(dev)
525{
526 register struct tty *tp;
527 register c;
528 register struct dzr_read *dzaddr;
529 struct dz *dzp;
530 struct tty *dzbase;
531 int t_bit, lino, i, n;
532
533 n = dev.d_minor;
534 for(i = 0; i < NDZ; i++)
535 {
536 dzaddr = (dzp = &dz[n])->dzaddr;
537 dzbase = &dz11[n*8];
538 while((c = dzaddr->dzcsr) < 0) /* xmit line ready */
539 {
540 t_bit = 1<<(lino = (c>>8)&07);
541
542 tp = &dzbase[lino];
543
544 if((!(dzp->carrier&t_bit) || (dzaddr->dzcarr&t_bit)) && (c = getc(&tp->t_outq)) >= 0)
545 if(c <= 0177 || tp->t_flags == RAW)
546 dzaddr->dztbuf = c;
547 else
548 {
549 dzaddr->dztcr =& ~t_bit;
550 tp->t_state =| TIMEOUT;
551 dzdelays[tp-dz11] = ((c&0177)+(TSCANRATE-1))/TSCANRATE+1; /* set up timeout */
552 continue;
553 }
554 else
555 dzaddr->dztcr =& ~t_bit;
556
557#ifdef TTY_HISPEED
558 if(tp->t_outq.c_cc <= ((tp->t_speeds&017) > B1200?TTHSLOWAT:TTLOWAT) && (tp->t_state&ASLEEP))
559#else
560 if(tp->t_outq.c_cc <= TTLOWAT && (tp->t_state&ASLEEP))
561#endif TTY_HISPEED
562 {
563 tp->t_state =& ~ASLEEP;
564 wakeup(&tp->t_outq);
565 }
566 }
567 if(++n >= NDZ)
568 n = 0;
569 }
570}
571
572
573
574/*
575 * DZ11 receiver interrupt
576 *
577 * Scan each dz commencing with the
578 * particular device that caused this call.
579 * Storing each charater as it comes.
580 */
581dzrint(dev)
582{
583 register struct tty *tp;
584 register c;
585 register struct dzr_read *dzaddr;
586 struct dz *dzp;
587 struct tty *dzbase;
588 int i, n, lino, t_bit;
589
590 n = dev.d_minor;
591 for(i = 0; i < NDZ; i++)
592 {
593 dzp = &dz[n];
594 if(dzp->openl)
595 {
596 dzbase = &dz11[n*8];
597 while((c = dzp->dzaddr->dzrbuf) < 0) /* char present in silo */
598 {
599 tp = &dzbase[lino = ((c>>8)&07)];
600 t_bit = 1<<lino;
601 if(c&RERROR)
602 {
603 if(c&OVR_RUN)
604 {
605 dzp->overrors++;
606# ifdef MESSAGES
607 printf("over run on dz %d/%d\n", n, lino);
608# endif MESSAGES
609 }
610 if(c&FRAME) /* break */
611 if(tp->t_flags&RAW)
612 c = 0; /* null ( for getty ) */
613 else
614# ifdef INTR_ON_BREAK
615 c = CINTR; /* del for NCRs. */
616# else
617 continue; /* ignore framing errors if not raw */
618# endif INTR_ON_BREAK
619 else if(c&PARITY)
620 {
621 dzp->pyerrors++;
622# ifdef MESSAGES
623 printf("parity on dz %d/%d\n", n, lino);
624# endif MESSAGES
625 continue; /* throw away bad chars */
626 }
627 }
628 if((!(dzp->carrier&t_bit)) || (dzp->dzaddr->dzcarr&t_bit))
629 ttyinput(c, tp);
630 }
631 }
632 if(++n >= NDZ)
633 n = 0;
634 }
635}