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