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