fix to conditionals
[unix-history] / usr / src / sys / vax / uba / dh.c
CommitLineData
ae7f533a 1/* dh.c 4.3 %G% */
a18f326f 2
a5cc519e
BJ
3#include "../conf/dh.h"
4#if NDH11 > 0
a18f326f 5/*
a5cc519e
BJ
6 * DH-11 driver
7 *
8 * Loaded with dhdm if there are DM-11's otherwise with dhfdm.
9 *
10 * NB: WE HAVEN'T TESTED dhdm CODE ON VAX.
a18f326f
BJ
11 */
12
13#include "../h/param.h"
14#include "../h/conf.h"
15#include "../h/dir.h"
16#include "../h/user.h"
17#include "../h/tty.h"
18#include "../h/map.h"
19#include "../h/pte.h"
20#include "../h/uba.h"
038bbe6b 21#include "../h/bk.h"
a5cc519e 22#include "../h/clist.h"
1b05b375 23#include "../h/mx.h"
a18f326f 24
d3ebf5ee
BJ
25/*
26 * When running dz's using only SAE (silo alarm) on input
27 * it is necessary to call dzrint() at clock interrupt time.
28 * This is unsafe unless spl5()s in tty code are changed to
29 * spl6()s to block clock interrupts. Note that the dh driver
30 * currently in use works the same way as the dz, even though
31 * we could try to more intelligently manage its silo.
32 * Thus don't take this out if you have no dz's unless you
33 * change clock.c and dhtimer().
34 */
35#define spl5 spl6
36
a5cc519e 37#define UBACVT(x) (cbase + (short)((x)-(char *)cfree))
a18f326f
BJ
38
39struct tty dh11[NDH11];
0e239190 40int dhact;
5c30d566 41int dhisilo;
a18f326f
BJ
42int ndh11 = NDH11;
43int dhstart();
44int ttrstrt();
5c30d566
BJ
45int dh_ubinfo;
46int cbase;
47int getcbase;
a18f326f
BJ
48
49/*
50 * Hardware control bits
51 */
52#define BITS6 01
53#define BITS7 02
54#define BITS8 03
55#define TWOSB 04
56#define PENABLE 020
57/* DEC manuals incorrectly say this bit causes generation of even parity. */
58#define OPAR 040
59#define HDUPLX 040000
60
61#define IENAB 030100
b4ec79ea
BJ
62#define NXM 02000
63#define CLRNXM 0400
a18f326f
BJ
64#define PERROR 010000
65#define FRERROR 020000
66#define OVERRUN 040000
67#define XINT 0100000
68#define SSPEED 7 /* standard speed: 300 baud */
69
a18f326f
BJ
70/*
71 * DM control bits
72 */
73#define TURNON 03 /* CD lead + line enable */
74#define TURNOFF 01 /* line enable */
87f51a66 75#define DTR 02 /* data terminal ready */
a18f326f
BJ
76#define RQS 04 /* request to send */
77
78/*
79 * Software copy of last dhbar
80 */
81short dhsar[(NDH11+15)/16];
82
83struct device
84{
85 union {
86 short dhcsr;
87 char dhcsrl;
88 } un;
89 short dhnxch;
90 short dhlpr;
91 unsigned short dhcar;
92 short dhbcr;
93 unsigned short dhbar;
94 short dhbreak;
95 short dhsilo;
96};
97
98/*
99 * Open a DH11 line.
100 */
101/*ARGSUSED*/
102dhopen(dev, flag)
103{
104 register struct tty *tp;
105 register d;
106 register struct device *addr;
a18f326f
BJ
107 int s;
108
109 d = minor(dev) & 0177;
110 if (d >= NDH11) {
111 u.u_error = ENXIO;
112 return;
113 }
114 tp = &dh11[d];
115 addr = DHADDR;
116 addr += d>>4;
117 tp->t_addr = (caddr_t)addr;
118 tp->t_oproc = dhstart;
119 tp->t_iproc = NULL;
120 tp->t_state |= WOPEN;
121 s = spl6();
0e239190
BJ
122 if (!getcbase) {
123 getcbase++;
d319892b
BJ
124 /* 512+ is a kludge to try to get around a hardware problem */
125 dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0);
5c30d566 126 cbase = (short)dh_ubinfo;
a18f326f
BJ
127 }
128 splx(s);
129 addr->un.dhcsr |= IENAB;
0e239190 130 dhact |= (1<<(d>>4));
a18f326f
BJ
131 if ((tp->t_state&ISOPEN) == 0) {
132 ttychars(tp);
87f51a66
BJ
133 if (tp->t_ispeed == 0) {
134 tp->t_ispeed = SSPEED;
135 tp->t_ospeed = SSPEED;
136 tp->t_flags = ODDP|EVENP|ECHO;
137 }
a18f326f
BJ
138 dhparam(d);
139 }
140 if (tp->t_state&XCLUDE && u.u_uid!=0) {
141 u.u_error = EBUSY;
142 return;
143 }
144 dmopen(dev);
145 (*linesw[tp->t_line].l_open)(dev,tp);
146}
147
148/*
149 * Close a DH11 line.
150 */
151/*ARGSUSED*/
152dhclose(dev, flag)
153dev_t dev;
154int flag;
155{
156 register struct tty *tp;
157 register d;
158
159 d = minor(dev) & 0177;
160 tp = &dh11[d];
161 (*linesw[tp->t_line].l_close)(tp);
162 if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
87f51a66 163 dmctl(d, TURNOFF, DMSET);
a18f326f
BJ
164 ttyclose(tp);
165}
166
167/*
168 * Read from a DH11 line.
169 */
170dhread(dev)
171{
172register struct tty *tp;
173
174 tp = &dh11[minor(dev) & 0177];
175 (*linesw[tp->t_line].l_read)(tp);
176}
177
178/*
179 * write on a DH11 line
180 */
181dhwrite(dev)
182{
183register struct tty *tp;
184
185 tp = &dh11[minor(dev) & 0177];
186 (*linesw[tp->t_line].l_write)(tp);
187}
188
189/*
190 * DH11 receiver interrupt.
191 */
192dhrint(dev)
193{
194 register struct tty *tp;
195 register short c;
196 register struct device *addr;
0e239190 197 register struct tty *tp0;
5c6adb3e 198 int s;
a18f326f 199
5c6adb3e 200 s = spl6(); /* see comment in clock.c */
a18f326f
BJ
201 addr = DHADDR;
202 addr += minor(dev) & 0177;
0e239190 203 tp0 = &dh11[((minor(dev)&0177)<<4)];
a18f326f 204 while ((c = addr->dhnxch) < 0) { /* char. present */
0e239190 205 tp = tp0 + ((c>>8)&017);
a18f326f
BJ
206 if (tp >= &dh11[NDH11])
207 continue;
208 if((tp->t_state&ISOPEN)==0) {
209 wakeup((caddr_t)tp);
210 continue;
211 }
212 if (c&PERROR)
213 if ((tp->t_flags&(EVENP|ODDP))==EVENP
214 || (tp->t_flags&(EVENP|ODDP))==ODDP )
215 continue;
216 if (c&OVERRUN)
217 printf("O");
218 if (c&FRERROR) /* break */
219 if (tp->t_flags&RAW)
220 c = 0; /* null (for getty) */
221 else
87f51a66
BJ
222#ifdef IIASA
223 continue;
224#else
1c17c385 225 c = tun.t_intrc;
87f51a66 226#endif
5c6adb3e 227 if (tp->t_line == NETLDISC) {
0e239190 228 c &= 0177;
87f51a66 229 BKINPUT(c, tp);
0e239190 230 } else
0e239190 231 (*linesw[tp->t_line].l_rint)(c,tp);
a18f326f 232 }
5c6adb3e 233 splx(s);
a18f326f
BJ
234}
235
236/*
237 * stty/gtty for DH11
238 */
239/*ARGSUSED*/
240dhioctl(dev, cmd, addr, flag)
241caddr_t addr;
242{
243 register struct tty *tp;
244
245 tp = &dh11[minor(dev) & 0177];
038bbe6b
BJ
246 cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
247 if (cmd==0)
248 return;
50e2732b 249 if (ttioctl(cmd, tp, addr, dev, flag)) {
a18f326f
BJ
250 if (cmd==TIOCSETP||cmd==TIOCSETN)
251 dhparam(dev);
87f51a66
BJ
252 } else switch(cmd) {
253 case TIOCSBRK:
254 ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017);
255 break;
256 case TIOCCBRK:
257 ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
258 break;
259 case TIOCSDTR:
260 dmctl(minor(dev), DTR|RQS, DMBIS);
261 break;
262 case TIOCCDTR:
263 dmctl(minor(dev), DTR|RQS, DMBIC);
264 break;
265 default:
a18f326f 266 u.u_error = ENOTTY;
87f51a66 267 }
a18f326f
BJ
268}
269
270/*
271 * Set parameters from open or stty into the DH hardware
272 * registers.
273 */
274dhparam(dev)
275{
276 register struct tty *tp;
277 register struct device *addr;
278 register d;
0072a3c2 279 int s;
a18f326f
BJ
280
281 d = minor(dev) & 0177;
282 tp = &dh11[d];
283 addr = (struct device *)tp->t_addr;
0072a3c2 284 s = spl5();
a18f326f
BJ
285 addr->un.dhcsrl = (d&017) | IENAB;
286 /*
287 * Hang up line?
288 */
289 if ((tp->t_ispeed)==0) {
290 tp->t_state |= HUPCLS;
87f51a66 291 dmctl(d, TURNOFF, DMSET);
a18f326f
BJ
292 return;
293 }
294 d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
295 if ((tp->t_ispeed) == 4) /* 134.5 baud */
296 d |= BITS6|PENABLE|HDUPLX;
297 else if (tp->t_flags&RAW)
298 d |= BITS8;
299 else
300 d |= BITS7|PENABLE;
301 if ((tp->t_flags&EVENP) == 0)
302 d |= OPAR;
303 if ((tp->t_ospeed) == 3) /* 110 baud */
304 d |= TWOSB;
305 addr->dhlpr = d;
0072a3c2 306 splx(s);
a18f326f
BJ
307}
308
309/*
310 * DH11 transmitter interrupt.
311 * Restart each line which used to be active but has
312 * terminated transmission since the last interrupt.
313 */
314dhxint(dev)
315{
316 register struct tty *tp;
317 register struct device *addr;
318 register d;
319 short ttybit, bar, *sbar;
d3ebf5ee 320 int s;
a18f326f 321
d3ebf5ee 322 s = spl6(); /* block the clock */
a18f326f
BJ
323 d = minor(dev) & 0177;
324 addr = DHADDR + d;
325 addr->un.dhcsr &= (short)~XINT;
b4ec79ea
BJ
326 if (addr->un.dhcsr & NXM) {
327 addr->un.dhcsr |= CLRNXM;
328 printf("dh clr NXM\n");
329 }
a18f326f
BJ
330 sbar = &dhsar[d];
331 bar = *sbar & ~addr->dhbar;
332 d <<= 4; ttybit = 1;
333
334 for(; bar; d++, ttybit <<= 1) {
335 if(bar&ttybit) {
336 *sbar &= ~ttybit;
337 bar &= ~ttybit;
338 tp = &dh11[d];
038bbe6b
BJ
339 tp->t_state &= ~BUSY;
340 if (tp->t_state&FLUSH)
341 tp->t_state &= ~FLUSH;
342 else {
a18f326f 343 addr->un.dhcsrl = (d&017)|IENAB;
293c7069 344 ndflush(&tp->t_outq,
4905b7c3 345 (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf));
a18f326f 346 }
038bbe6b
BJ
347 if (tp->t_line)
348 (*linesw[tp->t_line].l_start)(tp);
349 else
350 dhstart(tp);
a18f326f
BJ
351 }
352 }
d3ebf5ee 353 splx(s);
a18f326f
BJ
354}
355
356/*
357 * Start (restart) transmission on the given DH11 line.
358 */
359dhstart(tp)
360register struct tty *tp;
361{
362 register struct device *addr;
363 register short nch;
364 int s, d;
365
366 /*
367 * If it's currently active, or delaying,
368 * no need to do anything.
369 */
370 s = spl5();
371 d = tp-dh11;
372 addr = (struct device *)tp->t_addr;
373 if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
374 goto out;
375
a18f326f
BJ
376 /*
377 * If the writer was sleeping on output overflow,
378 * wake him when low tide is reached.
379 */
b25a5292 380 if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) {
a18f326f
BJ
381 tp->t_state &= ~ASLEEP;
382 if (tp->t_chan)
87f51a66
BJ
383 mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
384 else
a18f326f
BJ
385 wakeup((caddr_t)&tp->t_outq);
386 }
387
388 if (tp->t_outq.c_cc == 0)
389 goto out;
390
a18f326f
BJ
391 /*
392 * Find number of characters to transfer.
393 */
394 if (tp->t_flags & RAW) {
395 nch = ndqb(&tp->t_outq, 0);
396 } else {
397 nch = ndqb(&tp->t_outq, 0200);
398 if (nch == 0) {
399 nch = getc(&tp->t_outq);
400 timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
401 tp->t_state |= TIMEOUT;
402 goto out;
403 }
404 }
405 /*
406 * If any characters were set up, start transmission;
407 */
408 if (nch) {
409 addr->un.dhcsrl = (d&017)|IENAB;
410 addr->dhcar = UBACVT(tp->t_outq.c_cf);
411 addr->dhbcr = -nch;
a18f326f
BJ
412 nch = 1<<(d&017);
413 addr->dhbar |= nch;
414 dhsar[d>>4] |= nch;
415 tp->t_state |= BUSY;
416 }
417 out:
418 splx(s);
419}
420
a18f326f
BJ
421/*
422 * Stop output on a line.
423 * Assume call is made at spl6.
424 */
425/*ARGSUSED*/
426dhstop(tp, flag)
427register struct tty *tp;
428{
038bbe6b
BJ
429 register struct device *addr;
430 register d, s;
a18f326f 431
038bbe6b 432 addr = (struct device *)tp->t_addr;
a18f326f 433 s = spl6();
038bbe6b
BJ
434 if (tp->t_state & BUSY) {
435 d = minor(tp->t_dev);
436 addr->un.dhcsrl = (d&017) | IENAB;
a18f326f
BJ
437 if ((tp->t_state&TTSTOP)==0)
438 tp->t_state |= FLUSH;
038bbe6b
BJ
439 addr->dhbcr = -1;
440 }
a18f326f
BJ
441 splx(s);
442}
443
0e239190 444int dhsilo = 16;
87f51a66
BJ
445/*
446 * Silo control is fixed strategy
447 * here, paralleling only option available
448 * on DZ-11.
449 */
a18f326f 450/*ARGSUSED*/
87f51a66 451dhtimer()
a18f326f 452{
87f51a66 453 register d;
0e239190
BJ
454 register struct device *addr;
455
a18f326f
BJ
456 addr = DHADDR; d = 0;
457 do {
0e239190 458 if (dhact & (1<<d)) {
5c30d566
BJ
459 if ((dhisilo & (1<<d)) == 0) {
460 addr->dhsilo = dhsilo;
461 dhisilo |= 1<<d;
462 }
0e239190
BJ
463 dhrint(d);
464 }
465 d++;
a18f326f 466 addr++;
a18f326f 467 } while (d < (NDH11+15)/16);
a18f326f 468}
5c30d566
BJ
469
470/*
471 * Reset state of driver if UBA reset was necessary.
472 * Reset the csrl and lpr registers on open lines, and
473 * restart transmitters.
474 */
475dhreset()
476{
477 int d;
478 register struct tty *tp;
479 register struct device *addr;
480
481 if (getcbase == 0)
482 return;
483 printf(" dh");
5c30d566
BJ
484 dhisilo = 0;
485 ubafree(dh_ubinfo);
486 dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0);
487 cbase = (short)dh_ubinfo;
5c30d566
BJ
488 d = 0;
489 do {
490 addr = DHADDR + d;
5c30d566 491 if (dhact & (1<<d))
0072a3c2 492 addr->un.dhcsr |= IENAB;
5c30d566
BJ
493 d++;
494 } while (d < (NDH11+15)/16);
0072a3c2
BJ
495 for (d = 0; d < NDH11; d++) {
496 tp = &dh11[d];
497 if (tp->t_state & (ISOPEN|WOPEN)) {
498 dhparam(d);
499 dmctl(d, TURNON, DMSET);
500 tp->t_state &= ~BUSY;
501 dhstart(tp);
502 }
503 }
504 dhtimer();
5c30d566 505}
ae7f533a 506#endif