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