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