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