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