restored UPAGES to 6, that wasn't the problem
[unix-history] / usr / src / sys / vax / uba / dh.c
CommitLineData
be5b7974 1/* dh.c 4.11 %G% */
a18f326f 2
66b4fb09 3#include "dh.h"
a5cc519e 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);
8196703b
MT
162 /*
163 * Turn of the break bit in case somebody did a TIOCSBRK without
164 * a TIOCCBRK.
165 */
166 ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
a18f326f 167 if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
87f51a66 168 dmctl(d, TURNOFF, DMSET);
a18f326f
BJ
169 ttyclose(tp);
170}
171
172/*
173 * Read from a DH11 line.
174 */
175dhread(dev)
176{
177register struct tty *tp;
178
179 tp = &dh11[minor(dev) & 0177];
180 (*linesw[tp->t_line].l_read)(tp);
181}
182
183/*
184 * write on a DH11 line
185 */
186dhwrite(dev)
187{
188register struct tty *tp;
189
190 tp = &dh11[minor(dev) & 0177];
191 (*linesw[tp->t_line].l_write)(tp);
192}
193
194/*
195 * DH11 receiver interrupt.
196 */
197dhrint(dev)
198{
199 register struct tty *tp;
200 register short c;
201 register struct device *addr;
0e239190 202 register struct tty *tp0;
5c6adb3e 203 int s;
a18f326f 204
5c6adb3e 205 s = spl6(); /* see comment in clock.c */
a18f326f
BJ
206 addr = DHADDR;
207 addr += minor(dev) & 0177;
0e239190 208 tp0 = &dh11[((minor(dev)&0177)<<4)];
a18f326f 209 while ((c = addr->dhnxch) < 0) { /* char. present */
0e239190 210 tp = tp0 + ((c>>8)&017);
a18f326f
BJ
211 if (tp >= &dh11[NDH11])
212 continue;
213 if((tp->t_state&ISOPEN)==0) {
214 wakeup((caddr_t)tp);
215 continue;
216 }
217 if (c&PERROR)
218 if ((tp->t_flags&(EVENP|ODDP))==EVENP
219 || (tp->t_flags&(EVENP|ODDP))==ODDP )
220 continue;
221 if (c&OVERRUN)
222 printf("O");
223 if (c&FRERROR) /* break */
224 if (tp->t_flags&RAW)
225 c = 0; /* null (for getty) */
226 else
87f51a66
BJ
227#ifdef IIASA
228 continue;
229#else
1c17c385 230 c = tun.t_intrc;
87f51a66 231#endif
5c6adb3e 232 if (tp->t_line == NETLDISC) {
0e239190 233 c &= 0177;
87f51a66 234 BKINPUT(c, tp);
0e239190 235 } else
0e239190 236 (*linesw[tp->t_line].l_rint)(c,tp);
a18f326f 237 }
5c6adb3e 238 splx(s);
a18f326f
BJ
239}
240
241/*
242 * stty/gtty for DH11
243 */
244/*ARGSUSED*/
245dhioctl(dev, cmd, addr, flag)
246caddr_t addr;
247{
248 register struct tty *tp;
249
250 tp = &dh11[minor(dev) & 0177];
038bbe6b
BJ
251 cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
252 if (cmd==0)
253 return;
f4e18828 254 if (ttioctl(tp, cmd, addr, flag)) {
a18f326f
BJ
255 if (cmd==TIOCSETP||cmd==TIOCSETN)
256 dhparam(dev);
87f51a66
BJ
257 } else switch(cmd) {
258 case TIOCSBRK:
259 ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017);
260 break;
261 case TIOCCBRK:
262 ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
263 break;
264 case TIOCSDTR:
265 dmctl(minor(dev), DTR|RQS, DMBIS);
266 break;
267 case TIOCCDTR:
268 dmctl(minor(dev), DTR|RQS, DMBIC);
269 break;
270 default:
a18f326f 271 u.u_error = ENOTTY;
87f51a66 272 }
a18f326f
BJ
273}
274
275/*
276 * Set parameters from open or stty into the DH hardware
277 * registers.
278 */
279dhparam(dev)
280{
281 register struct tty *tp;
282 register struct device *addr;
283 register d;
0072a3c2 284 int s;
a18f326f
BJ
285
286 d = minor(dev) & 0177;
287 tp = &dh11[d];
288 addr = (struct device *)tp->t_addr;
0072a3c2 289 s = spl5();
a18f326f
BJ
290 addr->un.dhcsrl = (d&017) | IENAB;
291 /*
292 * Hang up line?
293 */
294 if ((tp->t_ispeed)==0) {
295 tp->t_state |= HUPCLS;
87f51a66 296 dmctl(d, TURNOFF, DMSET);
a18f326f
BJ
297 return;
298 }
299 d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
300 if ((tp->t_ispeed) == 4) /* 134.5 baud */
301 d |= BITS6|PENABLE|HDUPLX;
be5b7974 302 else if ((tp->t_flag&RAW) || (tp->t_local&LLITOUT))
a18f326f
BJ
303 d |= BITS8;
304 else
305 d |= BITS7|PENABLE;
306 if ((tp->t_flags&EVENP) == 0)
307 d |= OPAR;
308 if ((tp->t_ospeed) == 3) /* 110 baud */
309 d |= TWOSB;
310 addr->dhlpr = d;
0072a3c2 311 splx(s);
a18f326f
BJ
312}
313
314/*
315 * DH11 transmitter interrupt.
316 * Restart each line which used to be active but has
317 * terminated transmission since the last interrupt.
318 */
319dhxint(dev)
320{
321 register struct tty *tp;
322 register struct device *addr;
323 register d;
324 short ttybit, bar, *sbar;
d3ebf5ee 325 int s;
a18f326f 326
d3ebf5ee 327 s = spl6(); /* block the clock */
a18f326f
BJ
328 d = minor(dev) & 0177;
329 addr = DHADDR + d;
330 addr->un.dhcsr &= (short)~XINT;
b4ec79ea
BJ
331 if (addr->un.dhcsr & NXM) {
332 addr->un.dhcsr |= CLRNXM;
333 printf("dh clr NXM\n");
334 }
a18f326f
BJ
335 sbar = &dhsar[d];
336 bar = *sbar & ~addr->dhbar;
337 d <<= 4; ttybit = 1;
338
339 for(; bar; d++, ttybit <<= 1) {
340 if(bar&ttybit) {
341 *sbar &= ~ttybit;
342 bar &= ~ttybit;
343 tp = &dh11[d];
038bbe6b
BJ
344 tp->t_state &= ~BUSY;
345 if (tp->t_state&FLUSH)
346 tp->t_state &= ~FLUSH;
347 else {
a18f326f 348 addr->un.dhcsrl = (d&017)|IENAB;
293c7069 349 ndflush(&tp->t_outq,
4905b7c3 350 (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf));
a18f326f 351 }
038bbe6b
BJ
352 if (tp->t_line)
353 (*linesw[tp->t_line].l_start)(tp);
354 else
355 dhstart(tp);
a18f326f
BJ
356 }
357 }
d3ebf5ee 358 splx(s);
a18f326f
BJ
359}
360
361/*
362 * Start (restart) transmission on the given DH11 line.
363 */
364dhstart(tp)
365register struct tty *tp;
366{
367 register struct device *addr;
368 register short nch;
369 int s, d;
370
371 /*
372 * If it's currently active, or delaying,
373 * no need to do anything.
374 */
375 s = spl5();
376 d = tp-dh11;
377 addr = (struct device *)tp->t_addr;
378 if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
379 goto out;
380
a18f326f
BJ
381 /*
382 * If the writer was sleeping on output overflow,
383 * wake him when low tide is reached.
384 */
b25a5292 385 if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) {
a18f326f
BJ
386 tp->t_state &= ~ASLEEP;
387 if (tp->t_chan)
87f51a66
BJ
388 mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
389 else
a18f326f
BJ
390 wakeup((caddr_t)&tp->t_outq);
391 }
392
393 if (tp->t_outq.c_cc == 0)
394 goto out;
395
a18f326f
BJ
396 /*
397 * Find number of characters to transfer.
398 */
399 if (tp->t_flags & RAW) {
400 nch = ndqb(&tp->t_outq, 0);
401 } else {
402 nch = ndqb(&tp->t_outq, 0200);
403 if (nch == 0) {
404 nch = getc(&tp->t_outq);
405 timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
406 tp->t_state |= TIMEOUT;
407 goto out;
408 }
409 }
410 /*
411 * If any characters were set up, start transmission;
412 */
413 if (nch) {
414 addr->un.dhcsrl = (d&017)|IENAB;
415 addr->dhcar = UBACVT(tp->t_outq.c_cf);
416 addr->dhbcr = -nch;
a18f326f
BJ
417 nch = 1<<(d&017);
418 addr->dhbar |= nch;
419 dhsar[d>>4] |= nch;
420 tp->t_state |= BUSY;
421 }
422 out:
423 splx(s);
424}
425
a18f326f
BJ
426/*
427 * Stop output on a line.
428 * Assume call is made at spl6.
429 */
430/*ARGSUSED*/
431dhstop(tp, flag)
432register struct tty *tp;
433{
038bbe6b
BJ
434 register struct device *addr;
435 register d, s;
a18f326f 436
038bbe6b 437 addr = (struct device *)tp->t_addr;
a18f326f 438 s = spl6();
038bbe6b
BJ
439 if (tp->t_state & BUSY) {
440 d = minor(tp->t_dev);
441 addr->un.dhcsrl = (d&017) | IENAB;
a18f326f
BJ
442 if ((tp->t_state&TTSTOP)==0)
443 tp->t_state |= FLUSH;
038bbe6b
BJ
444 addr->dhbcr = -1;
445 }
a18f326f
BJ
446 splx(s);
447}
448
0e239190 449int dhsilo = 16;
87f51a66
BJ
450/*
451 * Silo control is fixed strategy
452 * here, paralleling only option available
453 * on DZ-11.
454 */
a18f326f 455/*ARGSUSED*/
87f51a66 456dhtimer()
a18f326f 457{
87f51a66 458 register d;
0e239190
BJ
459 register struct device *addr;
460
a18f326f
BJ
461 addr = DHADDR; d = 0;
462 do {
0e239190 463 if (dhact & (1<<d)) {
5c30d566
BJ
464 if ((dhisilo & (1<<d)) == 0) {
465 addr->dhsilo = dhsilo;
466 dhisilo |= 1<<d;
467 }
0e239190
BJ
468 dhrint(d);
469 }
470 d++;
a18f326f 471 addr++;
a18f326f 472 } while (d < (NDH11+15)/16);
a18f326f 473}
5c30d566
BJ
474
475/*
476 * Reset state of driver if UBA reset was necessary.
477 * Reset the csrl and lpr registers on open lines, and
478 * restart transmitters.
479 */
480dhreset()
481{
482 int d;
483 register struct tty *tp;
484 register struct device *addr;
485
486 if (getcbase == 0)
487 return;
488 printf(" dh");
5c30d566 489 dhisilo = 0;
b28deaf8 490 ubarelse(&dh_ubinfo);
5c30d566
BJ
491 dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0);
492 cbase = (short)dh_ubinfo;
5c30d566
BJ
493 d = 0;
494 do {
495 addr = DHADDR + d;
5c30d566 496 if (dhact & (1<<d))
0072a3c2 497 addr->un.dhcsr |= IENAB;
5c30d566
BJ
498 d++;
499 } while (d < (NDH11+15)/16);
0072a3c2
BJ
500 for (d = 0; d < NDH11; d++) {
501 tp = &dh11[d];
502 if (tp->t_state & (ISOPEN|WOPEN)) {
503 dhparam(d);
504 dmctl(d, TURNON, DMSET);
505 tp->t_state &= ~BUSY;
506 dhstart(tp);
507 }
508 }
509 dhtimer();
5c30d566 510}
ea99d5bf
BJ
511#if DHDM > 0
512#include "../dev/dhdm.c"
513#else
514#include "../dev/dhfdm.c"
515#endif
ae7f533a 516#endif