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