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