add onyx machine
[unix-history] / usr / src / sys / vax / uba / dh.c
CommitLineData
3f3a34c3 1/* dh.c 4.13 81/02/10 */
a18f326f 2
66b4fb09 3#include "dh.h"
a5cc519e 4#if NDH11 > 0
a18f326f 5/*
a5cc519e
BJ
6 * DH-11 driver
7 *
8 * Loaded with dhdm if there are DM-11's otherwise with dhfdm.
9 *
10 * NB: WE HAVEN'T TESTED dhdm CODE ON VAX.
a18f326f
BJ
11 */
12
13#include "../h/param.h"
14#include "../h/conf.h"
15#include "../h/dir.h"
16#include "../h/user.h"
17#include "../h/tty.h"
18#include "../h/map.h"
19#include "../h/pte.h"
3f3a34c3 20#include "../h/buf.h"
a18f326f 21#include "../h/uba.h"
038bbe6b 22#include "../h/bk.h"
a5cc519e 23#include "../h/clist.h"
1b05b375 24#include "../h/mx.h"
a18f326f 25
3f3a34c3
BJ
26/* This is to block the clock because we are using the silos */
27/* SHOULD RATHER QUEUE SOFTWARE INTERRUPT AT CLOCK TIME */
d3ebf5ee
BJ
28#define spl5 spl6
29
3f3a34c3 30#define UBACVT(x,uban) (cbase[uban] + (short)((x)-(char *)cfree))
a18f326f 31
3f3a34c3
BJ
32int dhcntrlr(), dhslave(), dhrint(), dhxint();
33struct uba_dinfo *dhinfo[NDH11];
34u_short dhstd[] = { 0 };
35int (*dhivec[])() = { dhrint, dhxint, 0 }; /* note: order matters */
36struct uba_driver dhdriver =
37 { dhcntrlr, dhslave, (int (*)())0, 0, 0, dhstd, dhinfo, dhivec };
38
39struct tty dh11[NDH11*16];
0e239190 40int dhact;
5c30d566 41int dhisilo;
3f3a34c3 42int ndh11 = NDH11*16;
a18f326f
BJ
43int dhstart();
44int ttrstrt();
3f3a34c3
BJ
45int dh_ubinfo[4];
46int cbase[4];
a18f326f
BJ
47
48/*
49 * Hardware control bits
50 */
51#define BITS6 01
52#define BITS7 02
53#define BITS8 03
54#define TWOSB 04
55#define PENABLE 020
56/* DEC manuals incorrectly say this bit causes generation of even parity. */
57#define OPAR 040
58#define HDUPLX 040000
59
60#define IENAB 030100
b4ec79ea
BJ
61#define NXM 02000
62#define CLRNXM 0400
a18f326f
BJ
63#define PERROR 010000
64#define FRERROR 020000
65#define OVERRUN 040000
66#define XINT 0100000
67#define SSPEED 7 /* standard speed: 300 baud */
68
a18f326f
BJ
69/*
70 * DM control bits
71 */
72#define TURNON 03 /* CD lead + line enable */
73#define TURNOFF 01 /* line enable */
87f51a66 74#define DTR 02 /* data terminal ready */
a18f326f
BJ
75#define RQS 04 /* request to send */
76
77/*
78 * Software copy of last dhbar
79 */
3f3a34c3 80short dhsar[NDH11];
a18f326f
BJ
81
82struct device
83{
84 union {
85 short dhcsr;
86 char dhcsrl;
87 } un;
88 short dhnxch;
89 short dhlpr;
90 unsigned short dhcar;
91 short dhbcr;
92 unsigned short dhbar;
93 short dhbreak;
94 short dhsilo;
95};
96
3f3a34c3
BJ
97dhcntrlr(ui, reg)
98 struct uba_dinfo *ui;
99 caddr_t reg;
100{
101
102 ((struct device *)reg)->un.dhcsr |= IENABLE;
103 /* get it to interrupt */
104}
105
106dhslave(ui, reg, slaveno)
107 struct uba_dinfo *ui;
108 caddr_t reg;
109{
110
111 /* could fill in local tables for the dh here */
112}
113
a18f326f
BJ
114/*
115 * Open a DH11 line.
116 */
117/*ARGSUSED*/
118dhopen(dev, flag)
3f3a34c3 119 dev_t dev;
a18f326f
BJ
120{
121 register struct tty *tp;
3f3a34c3 122 register int unit, dh;
a18f326f 123 register struct device *addr;
3f3a34c3 124 register struct uba_dinfo *ui;
a18f326f
BJ
125 int s;
126
3f3a34c3
BJ
127 unit = minor(dev);
128 dh = unit >> 4;
129 if (unit >= NDH11*16 || (ui = dhinfo[dh])->ui_alive == 0) {
a18f326f
BJ
130 u.u_error = ENXIO;
131 return;
132 }
3f3a34c3
BJ
133 tp = &dh11[unit];
134 ui = dhinfo[dh];
135 addr = (struct device *)ui->ui_addr;
a18f326f
BJ
136 tp->t_addr = (caddr_t)addr;
137 tp->t_oproc = dhstart;
138 tp->t_iproc = NULL;
139 tp->t_state |= WOPEN;
140 s = spl6();
3f3a34c3 141 if (dh_ubinfo[ui->ui_ubanum]) {
d319892b 142 /* 512+ is a kludge to try to get around a hardware problem */
3f3a34c3
BJ
143 dh_ubinfo[ui->ui_ubanum] =
144 uballoc((caddr_t)cfree,
145 512+NCLIST*sizeof(struct cblock), 0);
146 cbase[ui->ui_ubanum] = (short)dh_ubinfo[ui->ui_ubanum];
a18f326f
BJ
147 }
148 splx(s);
149 addr->un.dhcsr |= IENAB;
3f3a34c3 150 dhact |= (1<<dh);
a18f326f
BJ
151 if ((tp->t_state&ISOPEN) == 0) {
152 ttychars(tp);
87f51a66
BJ
153 if (tp->t_ispeed == 0) {
154 tp->t_ispeed = SSPEED;
155 tp->t_ospeed = SSPEED;
156 tp->t_flags = ODDP|EVENP|ECHO;
157 }
3f3a34c3 158 dhparam(unit);
a18f326f
BJ
159 }
160 if (tp->t_state&XCLUDE && u.u_uid!=0) {
161 u.u_error = EBUSY;
162 return;
163 }
164 dmopen(dev);
3f3a34c3 165 (*linesw[tp->t_line].l_open)(dev, tp);
a18f326f
BJ
166}
167
168/*
169 * Close a DH11 line.
170 */
171/*ARGSUSED*/
172dhclose(dev, flag)
3f3a34c3
BJ
173 dev_t dev;
174 int flag;
a18f326f
BJ
175{
176 register struct tty *tp;
3f3a34c3 177 register unit;
a18f326f 178
3f3a34c3
BJ
179 unit = minor(dev);
180 tp = &dh11[unit];
a18f326f 181 (*linesw[tp->t_line].l_close)(tp);
8196703b
MT
182 /*
183 * Turn of the break bit in case somebody did a TIOCSBRK without
184 * a TIOCCBRK.
185 */
3f3a34c3 186 ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
a18f326f 187 if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
3f3a34c3 188 dmctl(unit, TURNOFF, DMSET);
a18f326f
BJ
189 ttyclose(tp);
190}
191
192/*
193 * Read from a DH11 line.
194 */
195dhread(dev)
3f3a34c3 196 dev_t dev;
a18f326f 197{
3f3a34c3 198 register struct tty *tp;
a18f326f 199
3f3a34c3 200 tp = &dh11[minor(dev)];
a18f326f
BJ
201 (*linesw[tp->t_line].l_read)(tp);
202}
203
204/*
205 * write on a DH11 line
206 */
207dhwrite(dev)
3f3a34c3 208 dev_t dev;
a18f326f 209{
3f3a34c3 210 register struct tty *tp;
a18f326f 211
3f3a34c3 212 tp = &dh11[minor(dev)];
a18f326f
BJ
213 (*linesw[tp->t_line].l_write)(tp);
214}
215
216/*
217 * DH11 receiver interrupt.
218 */
3f3a34c3
BJ
219dhrint(dh)
220 int dh;
a18f326f
BJ
221{
222 register struct tty *tp;
3f3a34c3 223 register c;
a18f326f 224 register struct device *addr;
0e239190 225 register struct tty *tp0;
3f3a34c3 226 register struct uba_dinfo *ui;
5c6adb3e 227 int s;
a18f326f 228
5c6adb3e 229 s = spl6(); /* see comment in clock.c */
3f3a34c3
BJ
230 ui = dhinfo[dh];
231 addr = (struct device *)ui->ui_addr;
232 tp0 = &dh11[dh*16];
a18f326f 233 while ((c = addr->dhnxch) < 0) { /* char. present */
0e239190 234 tp = tp0 + ((c>>8)&017);
3f3a34c3 235 if (tp >= &dh11[NDH11*16])
a18f326f
BJ
236 continue;
237 if((tp->t_state&ISOPEN)==0) {
238 wakeup((caddr_t)tp);
239 continue;
240 }
241 if (c&PERROR)
242 if ((tp->t_flags&(EVENP|ODDP))==EVENP
243 || (tp->t_flags&(EVENP|ODDP))==ODDP )
244 continue;
245 if (c&OVERRUN)
246 printf("O");
247 if (c&FRERROR) /* break */
248 if (tp->t_flags&RAW)
249 c = 0; /* null (for getty) */
250 else
87f51a66
BJ
251#ifdef IIASA
252 continue;
253#else
1c17c385 254 c = tun.t_intrc;
87f51a66 255#endif
5c6adb3e 256 if (tp->t_line == NETLDISC) {
0e239190 257 c &= 0177;
87f51a66 258 BKINPUT(c, tp);
0e239190 259 } else
0e239190 260 (*linesw[tp->t_line].l_rint)(c,tp);
a18f326f 261 }
5c6adb3e 262 splx(s);
a18f326f
BJ
263}
264
265/*
266 * stty/gtty for DH11
267 */
268/*ARGSUSED*/
269dhioctl(dev, cmd, addr, flag)
3f3a34c3 270 caddr_t addr;
a18f326f
BJ
271{
272 register struct tty *tp;
3f3a34c3 273 register unit = minor(dev);
a18f326f 274
3f3a34c3 275 tp = &dh11[unit];
038bbe6b
BJ
276 cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
277 if (cmd==0)
278 return;
f4e18828 279 if (ttioctl(tp, cmd, addr, flag)) {
a18f326f 280 if (cmd==TIOCSETP||cmd==TIOCSETN)
3f3a34c3 281 dhparam(unit);
87f51a66
BJ
282 } else switch(cmd) {
283 case TIOCSBRK:
3f3a34c3 284 ((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
87f51a66
BJ
285 break;
286 case TIOCCBRK:
3f3a34c3 287 ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
87f51a66
BJ
288 break;
289 case TIOCSDTR:
3f3a34c3 290 dmctl(unit, DTR|RQS, DMBIS);
87f51a66
BJ
291 break;
292 case TIOCCDTR:
3f3a34c3 293 dmctl(unit, DTR|RQS, DMBIC);
87f51a66
BJ
294 break;
295 default:
a18f326f 296 u.u_error = ENOTTY;
87f51a66 297 }
a18f326f
BJ
298}
299
300/*
301 * Set parameters from open or stty into the DH hardware
302 * registers.
303 */
3f3a34c3
BJ
304dhparam(unit)
305 register int unit;
a18f326f
BJ
306{
307 register struct tty *tp;
308 register struct device *addr;
3f3a34c3 309 register int lpar;
0072a3c2 310 int s;
a18f326f 311
3f3a34c3 312 tp = &dh11[unit];
a18f326f 313 addr = (struct device *)tp->t_addr;
0072a3c2 314 s = spl5();
3f3a34c3 315 addr->un.dhcsrl = (unit&017) | IENAB;
a18f326f
BJ
316 /*
317 * Hang up line?
318 */
319 if ((tp->t_ispeed)==0) {
320 tp->t_state |= HUPCLS;
3f3a34c3 321 dmctl(unit, TURNOFF, DMSET);
a18f326f
BJ
322 return;
323 }
3f3a34c3 324 lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
a18f326f 325 if ((tp->t_ispeed) == 4) /* 134.5 baud */
3f3a34c3 326 lpar |= BITS6|PENABLE|HDUPLX;
131b2e17 327 else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
3f3a34c3 328 lpar |= BITS8;
a18f326f 329 else
3f3a34c3 330 lpar |= BITS7|PENABLE;
a18f326f 331 if ((tp->t_flags&EVENP) == 0)
3f3a34c3 332 lpar |= OPAR;
a18f326f 333 if ((tp->t_ospeed) == 3) /* 110 baud */
3f3a34c3
BJ
334 lpar |= TWOSB;
335 addr->dhlpr = lpar;
0072a3c2 336 splx(s);
a18f326f
BJ
337}
338
339/*
340 * DH11 transmitter interrupt.
341 * Restart each line which used to be active but has
342 * terminated transmission since the last interrupt.
343 */
3f3a34c3
BJ
344dhxint(dh)
345 int dh;
a18f326f
BJ
346{
347 register struct tty *tp;
348 register struct device *addr;
a18f326f 349 short ttybit, bar, *sbar;
3f3a34c3
BJ
350 register struct uba_dinfo *ui;
351 register unit;
d3ebf5ee 352 int s;
a18f326f 353
d3ebf5ee 354 s = spl6(); /* block the clock */
3f3a34c3
BJ
355 ui = dhinfo[dh];
356 addr = (struct device *)ui->ui_addr;
a18f326f 357 addr->un.dhcsr &= (short)~XINT;
b4ec79ea
BJ
358 if (addr->un.dhcsr & NXM) {
359 addr->un.dhcsr |= CLRNXM;
360 printf("dh clr NXM\n");
361 }
3f3a34c3 362 sbar = &dhsar[dh];
a18f326f 363 bar = *sbar & ~addr->dhbar;
3f3a34c3
BJ
364 unit = dh * 16; ttybit = 1;
365 for(; bar; unit++, ttybit <<= 1) {
a18f326f
BJ
366 if(bar&ttybit) {
367 *sbar &= ~ttybit;
368 bar &= ~ttybit;
3f3a34c3 369 tp = &dh11[unit];
038bbe6b
BJ
370 tp->t_state &= ~BUSY;
371 if (tp->t_state&FLUSH)
372 tp->t_state &= ~FLUSH;
373 else {
3f3a34c3 374 addr->un.dhcsrl = (unit&017)|IENAB;
293c7069 375 ndflush(&tp->t_outq,
3f3a34c3
BJ
376 (int)(short)addr->dhcar-
377 UBACVT(tp->t_outq.c_cf,ui->ui_ubanum));
a18f326f 378 }
038bbe6b
BJ
379 if (tp->t_line)
380 (*linesw[tp->t_line].l_start)(tp);
381 else
382 dhstart(tp);
a18f326f
BJ
383 }
384 }
d3ebf5ee 385 splx(s);
a18f326f
BJ
386}
387
388/*
389 * Start (restart) transmission on the given DH11 line.
390 */
391dhstart(tp)
3f3a34c3 392 register struct tty *tp;
a18f326f
BJ
393{
394 register struct device *addr;
3f3a34c3
BJ
395 register int nch, dh, unit;
396 int s;
a18f326f
BJ
397
398 /*
399 * If it's currently active, or delaying,
400 * no need to do anything.
401 */
402 s = spl5();
3f3a34c3
BJ
403 unit = minor(tp->t_dev);
404 dh = unit >> 4;
a18f326f
BJ
405 addr = (struct device *)tp->t_addr;
406 if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
407 goto out;
3f3a34c3 408 if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
a18f326f
BJ
409 tp->t_state &= ~ASLEEP;
410 if (tp->t_chan)
87f51a66
BJ
411 mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
412 else
a18f326f
BJ
413 wakeup((caddr_t)&tp->t_outq);
414 }
a18f326f
BJ
415 if (tp->t_outq.c_cc == 0)
416 goto out;
3f3a34c3 417 if (tp->t_flags & RAW)
a18f326f 418 nch = ndqb(&tp->t_outq, 0);
3f3a34c3 419 else {
a18f326f
BJ
420 nch = ndqb(&tp->t_outq, 0200);
421 if (nch == 0) {
422 nch = getc(&tp->t_outq);
423 timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
424 tp->t_state |= TIMEOUT;
425 goto out;
426 }
427 }
a18f326f 428 if (nch) {
3f3a34c3
BJ
429 addr->un.dhcsrl = (unit&017)|IENAB;
430 addr->dhcar = UBACVT(tp->t_outq.c_cf,
431 dhinfo[dh]->ui_ubanum);
a18f326f 432 addr->dhbcr = -nch;
3f3a34c3 433 nch = 1<<(unit&017);
a18f326f 434 addr->dhbar |= nch;
3f3a34c3 435 dhsar[dh] |= nch;
a18f326f
BJ
436 tp->t_state |= BUSY;
437 }
3f3a34c3 438out:
a18f326f
BJ
439 splx(s);
440}
441
a18f326f
BJ
442/*
443 * Stop output on a line.
444 * Assume call is made at spl6.
445 */
446/*ARGSUSED*/
447dhstop(tp, flag)
448register struct tty *tp;
449{
038bbe6b 450 register struct device *addr;
3f3a34c3 451 register int unit, s;
a18f326f 452
038bbe6b 453 addr = (struct device *)tp->t_addr;
a18f326f 454 s = spl6();
038bbe6b 455 if (tp->t_state & BUSY) {
3f3a34c3
BJ
456 unit = minor(tp->t_dev);
457 addr->un.dhcsrl = (unit&017) | IENAB;
a18f326f
BJ
458 if ((tp->t_state&TTSTOP)==0)
459 tp->t_state |= FLUSH;
038bbe6b
BJ
460 addr->dhbcr = -1;
461 }
a18f326f
BJ
462 splx(s);
463}
464
0e239190 465int dhsilo = 16;
87f51a66
BJ
466/*
467 * Silo control is fixed strategy
468 * here, paralleling only option available
469 * on DZ-11.
470 */
a18f326f 471/*ARGSUSED*/
87f51a66 472dhtimer()
a18f326f 473{
3f3a34c3 474 register int dh;
0e239190 475 register struct device *addr;
3f3a34c3 476 register struct uba_dinfo *ui;
0e239190 477
3f3a34c3 478 dh = 0;
a18f326f 479 do {
3f3a34c3
BJ
480 ui = dhinfo[dh];
481 addr = (struct device *)ui->ui_addr;
482 if (dhact & (1<<dh)) {
483 if ((dhisilo & (1<<dh)) == 0) {
5c30d566 484 addr->dhsilo = dhsilo;
3f3a34c3 485 dhisilo |= 1<<dh;
5c30d566 486 }
3f3a34c3 487 dhrint(dh);
0e239190 488 }
3f3a34c3
BJ
489 dh++;
490 } while (dh < NDH11);
a18f326f 491}
5c30d566
BJ
492
493/*
494 * Reset state of driver if UBA reset was necessary.
495 * Reset the csrl and lpr registers on open lines, and
496 * restart transmitters.
497 */
3f3a34c3 498dhreset(uban)
5c30d566 499{
3f3a34c3 500 register int dh, unit;
5c30d566
BJ
501 register struct tty *tp;
502 register struct device *addr;
3f3a34c3
BJ
503 register struct uba_dinfo *ui;
504 int uba;
505
506 /*** WE SHOULD LOOK TO SEE IF UBA BEING RESET IS INTERESTING ***/
5c30d566 507
5c30d566 508 printf(" dh");
5c30d566 509 dhisilo = 0;
3f3a34c3
BJ
510 for (uba = 0; uba < numuba; uba++)
511 if (dh_ubinfo[uba]) {
512 ubarelse(uba, &dh_ubinfo[uba]);
513 dh_ubinfo[uba] = uballoc(uba, (caddr_t)cfree,
514 512+NCLIST*sizeof (struct cblock), 0);
515 cbase[uba] = (short)dh_ubinfo;
516 }
517 dh = 0;
5c30d566 518 do {
3f3a34c3
BJ
519 if (dhact & (1<<dh))
520 ((struct device *)dhinfo[dh]->ui_addr)->un.dhcsr |=
521 IENAB;
522 dh++;
523 } while (dh < NDH11);
524 for (unit = 0; unit < NDH11*16; unit++) {
525 tp = &dh11[unit];
0072a3c2 526 if (tp->t_state & (ISOPEN|WOPEN)) {
3f3a34c3
BJ
527 dhparam(unit);
528 dmctl(unit, TURNON, DMSET);
0072a3c2
BJ
529 tp->t_state &= ~BUSY;
530 dhstart(tp);
531 }
532 }
533 dhtimer();
5c30d566 534}
3f3a34c3
BJ
535
536#if DHDM
ea99d5bf
BJ
537#include "../dev/dhdm.c"
538#else
539#include "../dev/dhfdm.c"
540#endif
ae7f533a 541#endif