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