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