typo
[unix-history] / usr / src / sys / vax / uba / dh.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6ddc83ab 6 * @(#)dh.c 7.5 (Berkeley) %G%
da7c5cc6 7 */
a18f326f 8
66b4fb09 9#include "dh.h"
0916e0d1 10#if NDH > 0
a18f326f 11/*
d4638843 12 * DH-11/DM-11 driver
a18f326f 13 */
961945a8
SL
14#include "../machine/pte.h"
15
e2c4935e 16#include "bk.h"
66e92dcf 17#include "uba.h"
52163dab
JB
18#include "param.h"
19#include "conf.h"
20#include "dir.h"
21#include "user.h"
22#include "proc.h"
23#include "ioctl.h"
24#include "tty.h"
25#include "map.h"
26#include "buf.h"
27#include "vm.h"
28#include "kernel.h"
b50ce881 29#include "syslog.h"
896962b1 30
52163dab
JB
31#include "ubareg.h"
32#include "ubavar.h"
33#include "dhreg.h"
34#include "dmreg.h"
896962b1 35
52163dab
JB
36#include "bkmac.h"
37#include "clist.h"
38#include "file.h"
39#include "uio.h"
a18f326f 40
7e00c42b 41/*
d4638843
BJ
42 * Definition of the driver for the auto-configuration program.
43 * There is one definition for the dh and one for the dm.
7e00c42b 44 */
acd2f01b 45int dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
b09915c5 46struct uba_device *dhinfo[NDH];
3f3a34c3 47u_short dhstd[] = { 0 };
3f3a34c3 48struct uba_driver dhdriver =
71236e46 49 { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
3f3a34c3 50
71236e46 51int dmprobe(), dmattach(), dmintr();
b09915c5 52struct uba_device *dminfo[NDH];
d4638843
BJ
53u_short dmstd[] = { 0 };
54struct uba_driver dmdriver =
71236e46 55 { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
a18f326f 56
df07bd9e 57#ifndef PORTSELECTOR
74bfa0d5 58#define ISPEED B9600
df07bd9e
SL
59#define IFLAGS (EVENP|ODDP|ECHO)
60#else
61#define ISPEED B4800
62#define IFLAGS (EVENP|ODDP)
63#endif
64
acd2f01b
MK
65#define FASTTIMER (hz/30) /* scan rate with silos on */
66
a18f326f 67/*
d4638843 68 * Local variables for the driver
a18f326f 69 */
0916e0d1
BJ
70short dhsar[NDH]; /* software copy of last bar */
71short dhsoftCAR[NDH];
a18f326f 72
0916e0d1
BJ
73struct tty dh11[NDH*16];
74int ndh11 = NDH*16;
d4638843 75int dhact; /* mask of active dh's */
acd2f01b
MK
76int dhsilos; /* mask of dh's with silo in use */
77int dhchars[NDH]; /* recent input count */
78int dhrate[NDH]; /* smoothed input count */
79int dhhighrate = 100; /* silo on if dhchars > dhhighrate */
80int dhlowrate = 75; /* silo off if dhrate < dhlowrate */
81static short timerstarted;
d4638843 82int dhstart(), ttrstrt();
a18f326f 83
d4638843 84/*
e965c38b
MK
85 * The clist space is mapped by one terminal driver onto each UNIBUS.
86 * The identity of the board which allocated resources is recorded,
87 * so the process may be repeated after UNIBUS resets.
d4638843
BJ
88 * The UBACVT macro converts a clist space address for unibus uban
89 * into an i/o space address for the DMA routine.
90 */
e965c38b
MK
91int dh_uballoc[NUBA]; /* which dh (if any) allocated unibus map */
92int cbase[NUBA]; /* base address of clists in unibus map */
d4638843 93#define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
a18f326f 94
88d5b764
BJ
95/*
96 * Routine for configuration to force a dh to interrupt.
97 * Set to transmit at 9600 baud, and cause a transmitter interrupt.
98 */
7e00c42b 99/*ARGSUSED*/
71236e46 100dhprobe(reg)
3f3a34c3
BJ
101 caddr_t reg;
102{
7e00c42b 103 register int br, cvec; /* these are ``value-result'' */
d4638843 104 register struct dhdevice *dhaddr = (struct dhdevice *)reg;
5aa9d5ea 105
71236e46
BJ
106#ifdef lint
107 br = 0; cvec = br; br = cvec;
fde2e6c9 108 if (ndh11 == 0) ndh11 = 1;
89b8a44c 109 dhrint(0); dhxint(0);
71236e46 110#endif
52ab9b2b 111#ifndef notdef
7e286c72 112 dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
5e7ab705 113 DELAY(1000);
fde2e6c9 114 dhaddr->un.dhcsr &= ~DH_RI;
7e286c72
BJ
115 dhaddr->un.dhcsr = 0;
116#else
88d5b764
BJ
117 dhaddr->un.dhcsr = DH_TIE;
118 DELAY(5);
119 dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
5aa9d5ea 120 dhaddr->dhbcr = -1;
5aa9d5ea 121 dhaddr->dhcar = 0;
88d5b764
BJ
122 dhaddr->dhbar = 1;
123 DELAY(100000); /* wait 1/10'th of a sec for interrupt */
5aa9d5ea 124 dhaddr->un.dhcsr = 0;
88d5b764
BJ
125 if (cvec && cvec != 0x200)
126 cvec -= 4; /* transmit -> receive */
4afc81c0 127#endif
9c0adba0 128 return (sizeof (struct dhdevice));
3f3a34c3
BJ
129}
130
88d5b764 131/*
71236e46 132 * Routine called to attach a dh.
88d5b764 133 */
71236e46 134dhattach(ui)
b09915c5 135 struct uba_device *ui;
3f3a34c3
BJ
136{
137
7e286c72 138 dhsoftCAR[ui->ui_unit] = ui->ui_flags;
27f8c1d5 139 cbase[ui->ui_ubanum] = -1;
e965c38b 140 dh_uballoc[ui->ui_unit] = -1;
3f3a34c3
BJ
141}
142
d4638843
BJ
143/*
144 * Configuration routine to cause a dm to interrupt.
145 */
71236e46
BJ
146dmprobe(reg)
147 caddr_t reg;
d4638843
BJ
148{
149 register int br, vec; /* value-result */
71236e46 150 register struct dmdevice *dmaddr = (struct dmdevice *)reg;
d4638843 151
71236e46 152#ifdef lint
a0eab615 153 br = 0; vec = br; br = vec;
155d9ff0 154 dmintr(0);
71236e46 155#endif
d4638843
BJ
156 dmaddr->dmcsr = DM_DONE|DM_IE;
157 DELAY(20);
158 dmaddr->dmcsr = 0;
71236e46 159 return (1);
d4638843
BJ
160}
161
71236e46
BJ
162/*ARGSUSED*/
163dmattach(ui)
b09915c5 164 struct uba_device *ui;
d4638843
BJ
165{
166
167 /* no local state to set up */
168}
169
a18f326f 170/*
7e00c42b
BJ
171 * Open a DH11 line, mapping the clist onto the uba if this
172 * is the first dh on this uba. Turn on this dh if this is
173 * the first use of it. Also do a dmopen to wait for carrier.
a18f326f
BJ
174 */
175/*ARGSUSED*/
176dhopen(dev, flag)
3f3a34c3 177 dev_t dev;
a18f326f
BJ
178{
179 register struct tty *tp;
3f3a34c3 180 register int unit, dh;
d4638843 181 register struct dhdevice *addr;
b09915c5 182 register struct uba_device *ui;
a18f326f
BJ
183 int s;
184
3f3a34c3
BJ
185 unit = minor(dev);
186 dh = unit >> 4;
7da157da
BJ
187 if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
188 return (ENXIO);
3f3a34c3 189 tp = &dh11[unit];
7da157da
BJ
190 if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
191 return (EBUSY);
d4638843 192 addr = (struct dhdevice *)ui->ui_addr;
a18f326f
BJ
193 tp->t_addr = (caddr_t)addr;
194 tp->t_oproc = dhstart;
941944c9 195 tp->t_state |= TS_WOPEN;
7e00c42b
BJ
196 /*
197 * While setting up state for this uba and this dh,
198 * block uba resets which can clear the state.
199 */
200 s = spl5();
27f8c1d5 201 if (cbase[ui->ui_ubanum] == -1) {
e965c38b
MK
202 dh_uballoc[ui->ui_ubanum] = dh;
203 cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
204 (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
88d5b764 205 }
acd2f01b
MK
206 if (timerstarted == 0) {
207 timerstarted++;
208 timeout(dhtimer, (caddr_t) 0, hz);
209 }
88d5b764
BJ
210 if ((dhact&(1<<dh)) == 0) {
211 addr->un.dhcsr |= DH_IE;
88d5b764 212 dhact |= (1<<dh);
acd2f01b 213 addr->dhsilo = 0;
a18f326f
BJ
214 }
215 splx(s);
7e00c42b 216 /*
74cd2624 217 * If this is first open, initialize tty state to default.
7e00c42b 218 */
941944c9 219 if ((tp->t_state&TS_ISOPEN) == 0) {
a18f326f 220 ttychars(tp);
74cd2624
MK
221#ifndef PORTSELECTOR
222 if (tp->t_ispeed == 0) {
223#else
224 tp->t_state |= TS_HUPCLS;
225#endif PORTSELECTOR
226 tp->t_ispeed = ISPEED;
227 tp->t_ospeed = ISPEED;
228 tp->t_flags = IFLAGS;
229#ifndef PORTSELECTOR
230 }
231#endif PORTSELECTOR
3f3a34c3 232 dhparam(unit);
a18f326f 233 }
7e00c42b
BJ
234 /*
235 * Wait for carrier, then process line discipline specific open.
236 */
a18f326f 237 dmopen(dev);
7da157da 238 return ((*linesw[tp->t_line].l_open)(dev, tp));
a18f326f
BJ
239}
240
241/*
7e00c42b 242 * Close a DH11 line, turning off the DM11.
a18f326f
BJ
243 */
244/*ARGSUSED*/
245dhclose(dev, flag)
3f3a34c3
BJ
246 dev_t dev;
247 int flag;
a18f326f
BJ
248{
249 register struct tty *tp;
3f3a34c3 250 register unit;
a18f326f 251
3f3a34c3
BJ
252 unit = minor(dev);
253 tp = &dh11[unit];
a18f326f 254 (*linesw[tp->t_line].l_close)(tp);
d4638843 255 ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
941944c9 256 if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
d4638843 257 dmctl(unit, DML_OFF, DMSET);
a18f326f
BJ
258 ttyclose(tp);
259}
260
740e4029 261dhread(dev, uio)
3f3a34c3 262 dev_t dev;
740e4029 263 struct uio *uio;
a18f326f 264{
b91c756d 265 register struct tty *tp = &dh11[minor(dev)];
a18f326f 266
740e4029 267 return ((*linesw[tp->t_line].l_read)(tp, uio));
a18f326f
BJ
268}
269
406ddcbe 270dhwrite(dev, uio)
3f3a34c3 271 dev_t dev;
406ddcbe 272 struct uio *uio;
a18f326f 273{
b91c756d 274 register struct tty *tp = &dh11[minor(dev)];
a18f326f 275
b91c756d 276 return ((*linesw[tp->t_line].l_write)(tp, uio));
a18f326f
BJ
277}
278
279/*
280 * DH11 receiver interrupt.
281 */
3f3a34c3
BJ
282dhrint(dh)
283 int dh;
a18f326f
BJ
284{
285 register struct tty *tp;
3f3a34c3 286 register c;
d4638843 287 register struct dhdevice *addr;
0e239190 288 register struct tty *tp0;
b09915c5 289 register struct uba_device *ui;
b19fe459 290 int overrun = 0;
a18f326f 291
3f3a34c3 292 ui = dhinfo[dh];
d4638843
BJ
293 if (ui == 0 || ui->ui_alive == 0)
294 return;
295 addr = (struct dhdevice *)ui->ui_addr;
7e00c42b
BJ
296 tp0 = &dh11[dh<<4];
297 /*
298 * Loop fetching characters from the silo for this
299 * dh until there are no more in the silo.
300 */
301 while ((c = addr->dhrcr) < 0) {
302 tp = tp0 + ((c>>8)&0xf);
acd2f01b 303 dhchars[dh]++;
941944c9 304 if ((tp->t_state&TS_ISOPEN)==0) {
74bfa0d5
MK
305 wakeup((caddr_t)&tp->t_rawq);
306#ifdef PORTSELECTOR
307 if ((tp->t_state&TS_WOPEN) == 0)
df07bd9e 308#endif
74bfa0d5 309 continue;
a18f326f 310 }
7e00c42b 311 if (c & DH_PE)
a18f326f
BJ
312 if ((tp->t_flags&(EVENP|ODDP))==EVENP
313 || (tp->t_flags&(EVENP|ODDP))==ODDP )
314 continue;
b19fe459 315 if ((c & DH_DO) && overrun == 0) {
283ffc90 316 log(LOG_WARNING, "dh%d: silo overflow\n", dh);
b19fe459
BJ
317 overrun = 1;
318 }
7e00c42b
BJ
319 if (c & DH_FE)
320 /*
321 * At framing error (break) generate
322 * a null (in raw mode, for getty), or a
323 * interrupt (in cooked/cbreak mode).
324 */
a18f326f 325 if (tp->t_flags&RAW)
7e00c42b 326 c = 0;
a18f326f 327 else
21a85e60 328 c = tp->t_intrc;
e2c4935e 329#if NBK > 0
5c6adb3e 330 if (tp->t_line == NETLDISC) {
0e239190 331 c &= 0177;
87f51a66 332 BKINPUT(c, tp);
0e239190 333 } else
e2c4935e 334#endif
7e00c42b 335 (*linesw[tp->t_line].l_rint)(c, tp);
a18f326f
BJ
336 }
337}
338
339/*
7e00c42b 340 * Ioctl for DH11.
a18f326f
BJ
341 */
342/*ARGSUSED*/
942f05a9
SL
343dhioctl(dev, cmd, data, flag)
344 caddr_t data;
a18f326f
BJ
345{
346 register struct tty *tp;
7da157da
BJ
347 register int unit = minor(dev);
348 int error;
a18f326f 349
3f3a34c3 350 tp = &dh11[unit];
7da157da
BJ
351 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
352 if (error >= 0)
353 return (error);
354 error = ttioctl(tp, cmd, data, flag);
355 if (error >= 0) {
21220e35
JB
356 if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
357 cmd == TIOCLBIC || cmd == TIOCLSET)
3f3a34c3 358 dhparam(unit);
7da157da
BJ
359 return (error);
360 }
361 switch (cmd) {
942f05a9 362
87f51a66 363 case TIOCSBRK:
d4638843 364 ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
87f51a66 365 break;
942f05a9 366
87f51a66 367 case TIOCCBRK:
d4638843 368 ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
87f51a66 369 break;
942f05a9 370
87f51a66 371 case TIOCSDTR:
d4638843 372 dmctl(unit, DML_DTR|DML_RTS, DMBIS);
87f51a66 373 break;
942f05a9 374
87f51a66 375 case TIOCCDTR:
d4638843 376 dmctl(unit, DML_DTR|DML_RTS, DMBIC);
87f51a66 377 break;
942f05a9 378
87f51a66 379 default:
7da157da 380 return (ENOTTY);
87f51a66 381 }
7da157da 382 return (0);
a18f326f
BJ
383}
384
385/*
386 * Set parameters from open or stty into the DH hardware
387 * registers.
388 */
3f3a34c3
BJ
389dhparam(unit)
390 register int unit;
a18f326f
BJ
391{
392 register struct tty *tp;
d4638843 393 register struct dhdevice *addr;
3f3a34c3 394 register int lpar;
0072a3c2 395 int s;
a18f326f 396
3f3a34c3 397 tp = &dh11[unit];
d4638843 398 addr = (struct dhdevice *)tp->t_addr;
7e00c42b
BJ
399 /*
400 * Block interrupts so parameters will be set
401 * before the line interrupts.
402 */
0072a3c2 403 s = spl5();
7e00c42b 404 addr->un.dhcsrl = (unit&0xf) | DH_IE;
a18f326f 405 if ((tp->t_ispeed)==0) {
941944c9 406 tp->t_state |= TS_HUPCLS;
d4638843 407 dmctl(unit, DML_OFF, DMSET);
3371117b 408 splx(s);
a18f326f
BJ
409 return;
410 }
3f3a34c3 411 lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
7e00c42b 412 if ((tp->t_ispeed) == B134)
3f3a34c3 413 lpar |= BITS6|PENABLE|HDUPLX;
fb01874e 414 else if (tp->t_flags & (RAW|LITOUT|PASS8))
3f3a34c3 415 lpar |= BITS8;
a18f326f 416 else
3f3a34c3 417 lpar |= BITS7|PENABLE;
a18f326f 418 if ((tp->t_flags&EVENP) == 0)
3f3a34c3 419 lpar |= OPAR;
7e00c42b 420 if ((tp->t_ospeed) == B110)
3f3a34c3
BJ
421 lpar |= TWOSB;
422 addr->dhlpr = lpar;
0072a3c2 423 splx(s);
a18f326f
BJ
424}
425
426/*
427 * DH11 transmitter interrupt.
428 * Restart each line which used to be active but has
429 * terminated transmission since the last interrupt.
430 */
3f3a34c3
BJ
431dhxint(dh)
432 int dh;
a18f326f
BJ
433{
434 register struct tty *tp;
d4638843 435 register struct dhdevice *addr;
a18f326f 436 short ttybit, bar, *sbar;
b09915c5 437 register struct uba_device *ui;
7e00c42b 438 register int unit;
71236e46 439 u_short cntr;
a18f326f 440
3f3a34c3 441 ui = dhinfo[dh];
d4638843 442 addr = (struct dhdevice *)ui->ui_addr;
88d5b764
BJ
443 if (addr->un.dhcsr & DH_NXM) {
444 addr->un.dhcsr |= DH_CNI;
b19fe459 445 printf("dh%d: NXM\n", dh);
b4ec79ea 446 }
3f3a34c3 447 sbar = &dhsar[dh];
a18f326f 448 bar = *sbar & ~addr->dhbar;
3f3a34c3 449 unit = dh * 16; ttybit = 1;
7e00c42b
BJ
450 addr->un.dhcsr &= (short)~DH_TI;
451 for (; bar; unit++, ttybit <<= 1) {
452 if (bar & ttybit) {
a18f326f
BJ
453 *sbar &= ~ttybit;
454 bar &= ~ttybit;
3f3a34c3 455 tp = &dh11[unit];
941944c9
BJ
456 tp->t_state &= ~TS_BUSY;
457 if (tp->t_state&TS_FLUSH)
458 tp->t_state &= ~TS_FLUSH;
038bbe6b 459 else {
88d5b764 460 addr->un.dhcsrl = (unit&017)|DH_IE;
7e00c42b
BJ
461 /*
462 * Do arithmetic in a short to make up
463 * for lost 16&17 bits.
464 */
71236e46 465 cntr = addr->dhcar -
7e00c42b 466 UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
a0eab615 467 ndflush(&tp->t_outq, (int)cntr);
a18f326f 468 }
038bbe6b
BJ
469 if (tp->t_line)
470 (*linesw[tp->t_line].l_start)(tp);
471 else
472 dhstart(tp);
a18f326f
BJ
473 }
474 }
475}
476
477/*
478 * Start (restart) transmission on the given DH11 line.
479 */
480dhstart(tp)
3f3a34c3 481 register struct tty *tp;
a18f326f 482{
d4638843 483 register struct dhdevice *addr;
7e00c42b 484 register int car, dh, unit, nch;
3f3a34c3 485 int s;
a18f326f 486
3f3a34c3
BJ
487 unit = minor(tp->t_dev);
488 dh = unit >> 4;
7e00c42b 489 unit &= 0xf;
d4638843 490 addr = (struct dhdevice *)tp->t_addr;
7e00c42b
BJ
491
492 /*
493 * Must hold interrupts in following code to prevent
494 * state of the tp from changing.
495 */
496 s = spl5();
497 /*
498 * If it's currently active, or delaying, no need to do anything.
499 */
941944c9 500 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
a18f326f 501 goto out;
7e00c42b
BJ
502 /*
503 * If there are sleepers, and output has drained below low
504 * water mark, wake up the sleepers.
505 */
941944c9
BJ
506 if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
507 if (tp->t_state&TS_ASLEEP) {
508 tp->t_state &= ~TS_ASLEEP;
509 wakeup((caddr_t)&tp->t_outq);
510 }
511 if (tp->t_wsel) {
512 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
513 tp->t_wsel = 0;
514 tp->t_state &= ~TS_WCOLL;
515 }
a18f326f 516 }
7e00c42b
BJ
517 /*
518 * Now restart transmission unless the output queue is
519 * empty.
520 */
a18f326f
BJ
521 if (tp->t_outq.c_cc == 0)
522 goto out;
21a85e60 523 if (tp->t_flags & (RAW|LITOUT))
a18f326f 524 nch = ndqb(&tp->t_outq, 0);
3f3a34c3 525 else {
a18f326f 526 nch = ndqb(&tp->t_outq, 0200);
7e00c42b
BJ
527 /*
528 * If first thing on queue is a delay process it.
529 */
a18f326f
BJ
530 if (nch == 0) {
531 nch = getc(&tp->t_outq);
7e00c42b 532 timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
941944c9 533 tp->t_state |= TS_TIMEOUT;
a18f326f
BJ
534 goto out;
535 }
536 }
7e00c42b
BJ
537 /*
538 * If characters to transmit, restart transmission.
539 */
a18f326f 540 if (nch) {
7e00c42b
BJ
541 car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
542 addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
a1b41f3d
BJ
543 /*
544 * The following nonsense with short word
545 * is to make sure the dhbar |= word below
546 * is done with an interlocking bisw2 instruction.
547 */
548 { short word = 1 << unit;
549 dhsar[dh] |= word;
7e00c42b 550 addr->dhcar = car;
a18f326f 551 addr->dhbcr = -nch;
a1b41f3d
BJ
552 addr->dhbar |= word;
553 }
941944c9 554 tp->t_state |= TS_BUSY;
a18f326f 555 }
3f3a34c3 556out:
a18f326f
BJ
557 splx(s);
558}
559
a18f326f 560/*
7e00c42b 561 * Stop output on a line, e.g. for ^S/^Q or output flush.
a18f326f
BJ
562 */
563/*ARGSUSED*/
564dhstop(tp, flag)
7e00c42b 565 register struct tty *tp;
a18f326f 566{
d4638843 567 register struct dhdevice *addr;
3f3a34c3 568 register int unit, s;
a18f326f 569
d4638843 570 addr = (struct dhdevice *)tp->t_addr;
7e00c42b
BJ
571 /*
572 * Block input/output interrupts while messing with state.
573 */
574 s = spl5();
941944c9 575 if (tp->t_state & TS_BUSY) {
7e00c42b
BJ
576 /*
577 * Device is transmitting; stop output
578 * by selecting the line and setting the byte
579 * count to -1. We will clean up later
580 * by examining the address where the dh stopped.
581 */
3f3a34c3 582 unit = minor(tp->t_dev);
88d5b764 583 addr->un.dhcsrl = (unit&017) | DH_IE;
941944c9
BJ
584 if ((tp->t_state&TS_TTSTOP)==0)
585 tp->t_state |= TS_FLUSH;
038bbe6b
BJ
586 addr->dhbcr = -1;
587 }
a18f326f
BJ
588 splx(s);
589}
590
5c30d566
BJ
591/*
592 * Reset state of driver if UBA reset was necessary.
593 * Reset the csrl and lpr registers on open lines, and
594 * restart transmitters.
595 */
3f3a34c3 596dhreset(uban)
7e00c42b 597 int uban;
5c30d566 598{
3f3a34c3 599 register int dh, unit;
5c30d566 600 register struct tty *tp;
b09915c5 601 register struct uba_device *ui;
5aa9d5ea 602 int i;
5c30d566 603
3f3a34c3 604 dh = 0;
0916e0d1 605 for (dh = 0; dh < NDH; dh++) {
5aa9d5ea
RE
606 ui = dhinfo[dh];
607 if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
608 continue;
b19fe459 609 printf(" dh%d", dh);
e965c38b
MK
610 if (dh_uballoc[uban] == dh) {
611 int info;
612
613 info = uballoc(uban, (caddr_t)cfree,
614 nclist * sizeof(struct cblock), UBA_CANTWAIT);
615 if (info)
616 cbase[uban] = UBAI_ADDR(info);
617 else {
618 printf(" [can't get uba map]");
619 cbase[uban] = -1;
620 }
c18c7ccc 621 }
d4638843 622 ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
acd2f01b 623 ((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
5aa9d5ea
RE
624 unit = dh * 16;
625 for (i = 0; i < 16; i++) {
626 tp = &dh11[unit];
941944c9 627 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
5aa9d5ea 628 dhparam(unit);
d4638843 629 dmctl(unit, DML_ON, DMSET);
941944c9 630 tp->t_state &= ~TS_BUSY;
5aa9d5ea
RE
631 dhstart(tp);
632 }
633 unit++;
0072a3c2
BJ
634 }
635 }
acd2f01b 636 dhsilos = 0;
5c30d566 637}
3f3a34c3 638
acd2f01b 639int dhtransitions, dhslowtimers, dhfasttimers; /*DEBUG*/
7e00c42b 640/*
acd2f01b
MK
641 * At software clock interrupt time, check status.
642 * Empty all the dh silos that are in use, and decide whether
643 * to turn any silos off or on.
7e00c42b 644 */
88d5b764
BJ
645dhtimer()
646{
acd2f01b
MK
647 register int dh, s;
648 static int timercalls;
649
650 if (dhsilos) {
651 dhfasttimers++; /*DEBUG*/
652 timercalls++;
653 s = spl5();
654 for (dh = 0; dh < NDH; dh++)
655 if (dhsilos & (1 << dh))
656 dhrint(dh);
657 splx(s);
658 }
659 if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
660 dhslowtimers++; /*DEBUG*/
661 timercalls = 0;
662 for (dh = 0; dh < NDH; dh++) {
663 ave(dhrate[dh], dhchars[dh], 8);
664 if ((dhchars[dh] > dhhighrate) &&
665 ((dhsilos & (1 << dh)) == 0)) {
666 ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
667 (dhchars[dh] > 500? 32 : 16);
668 dhsilos |= (1 << dh);
669 dhtransitions++; /*DEBUG*/
670 } else if ((dhsilos & (1 << dh)) &&
671 (dhrate[dh] < dhlowrate)) {
672 ((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
673 dhsilos &= ~(1 << dh);
674 }
675 dhchars[dh] = 0;
676 }
677 }
678 timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
88d5b764
BJ
679}
680
7e00c42b 681/*
d4638843 682 * Turn on the line associated with dh dev.
7e00c42b
BJ
683 */
684dmopen(dev)
685 dev_t dev;
686{
687 register struct tty *tp;
688 register struct dmdevice *addr;
b09915c5 689 register struct uba_device *ui;
7e00c42b
BJ
690 register int unit;
691 register int dm;
1d6c2d43 692 int s;
7e00c42b
BJ
693
694 unit = minor(dev);
d4638843 695 dm = unit >> 4;
7e00c42b 696 tp = &dh11[unit];
7e286c72 697 unit &= 0xf;
efbbc69a 698 if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
941944c9 699 tp->t_state |= TS_CARR_ON;
7e00c42b
BJ
700 return;
701 }
702 addr = (struct dmdevice *)ui->ui_addr;
1d6c2d43 703 s = spl5();
6e095954
MK
704 for (;;) {
705 addr->dmcsr &= ~DM_SE;
706 while (addr->dmcsr & DM_BUSY)
707 ;
708 addr->dmcsr = unit;
709 addr->dmlstat = DML_ON;
f5369e9c 710 if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit)))
6e095954
MK
711 tp->t_state |= TS_CARR_ON;
712 addr->dmcsr = DM_IE|DM_SE;
713 if (tp->t_state & TS_CARR_ON)
714 break;
7e00c42b 715 sleep((caddr_t)&tp->t_rawq, TTIPRI);
6e095954 716 }
1d6c2d43 717 splx(s);
7e00c42b
BJ
718}
719
720/*
721 * Dump control bits into the DM registers.
722 */
723dmctl(dev, bits, how)
724 dev_t dev;
725 int bits, how;
726{
b09915c5 727 register struct uba_device *ui;
7e00c42b
BJ
728 register struct dmdevice *addr;
729 register int unit, s;
730 int dm;
731
732 unit = minor(dev);
733 dm = unit >> 4;
734 if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
735 return;
736 addr = (struct dmdevice *)ui->ui_addr;
737 s = spl5();
d4638843
BJ
738 addr->dmcsr &= ~DM_SE;
739 while (addr->dmcsr & DM_BUSY)
7e00c42b
BJ
740 ;
741 addr->dmcsr = unit & 0xf;
742 switch(how) {
743 case DMSET:
744 addr->dmlstat = bits;
745 break;
746 case DMBIS:
747 addr->dmlstat |= bits;
748 break;
749 case DMBIC:
750 addr->dmlstat &= ~bits;
751 break;
752 }
1d6c2d43 753 addr->dmcsr = DM_IE|DM_SE;
7e00c42b
BJ
754 splx(s);
755}
756
757/*
758 * DM11 interrupt; deal with carrier transitions.
759 */
760dmintr(dm)
761 register int dm;
762{
b09915c5 763 register struct uba_device *ui;
7e00c42b
BJ
764 register struct tty *tp;
765 register struct dmdevice *addr;
efbbc69a 766 int unit;
7e00c42b
BJ
767
768 ui = dminfo[dm];
d4638843
BJ
769 if (ui == 0)
770 return;
7e00c42b 771 addr = (struct dmdevice *)ui->ui_addr;
658d2f56
BJ
772 if (addr->dmcsr&DM_DONE) {
773 if (addr->dmcsr&DM_CF) {
efbbc69a
MK
774 unit = addr->dmcsr & 0xf;
775 tp = &dh11[(dm << 4) + unit];
74bfa0d5
MK
776 if (addr->dmlstat & DML_CAR)
777 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
778 else if ((dhsoftCAR[dm] & (1<<unit)) == 0 &&
779 (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
780 addr->dmlstat = 0;
658d2f56
BJ
781 }
782 addr->dmcsr = DM_IE|DM_SE;
7e00c42b
BJ
783 }
784}
4569bb70 785#endif