date and time created 80/04/09 16:03:03 by bill
[unix-history] / usr / src / sys / vax / uba / dh.c
CommitLineData
a18f326f
BJ
1/* dh.c 3.1 %H% */
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"
19
20#define q3 tp->t_outq
21#define DHADDR ((struct device *)(UBA0_DEV + 0160020))
22#define NDH11 16 /* number of lines */
23#define UBACVT(x) (cbase + (short)((x)-(char *)cfree))
24
25struct cblock {
26 struct cblock *c_next;
27 char c_info[CBSIZE];
28};
29
30struct tty dh11[NDH11];
31short dhcc[NDH11];
32int dhchars[(NDH11+15)/16];
33int ndh11 = NDH11;
34int dhstart();
35int ttrstrt();
36int cbase;
37extern struct cblock cfree[];
38
39/*
40 * Hardware control bits
41 */
42#define BITS6 01
43#define BITS7 02
44#define BITS8 03
45#define TWOSB 04
46#define PENABLE 020
47/* DEC manuals incorrectly say this bit causes generation of even parity. */
48#define OPAR 040
49#define HDUPLX 040000
50
51#define IENAB 030100
52#define PERROR 010000
53#define FRERROR 020000
54#define OVERRUN 040000
55#define XINT 0100000
56#define SSPEED 7 /* standard speed: 300 baud */
57
58#ifdef ERNIE
59#define DHTIME 2 /* Since Berknet packets are only 100 chars */
60#else
61#define DHTIME 6
62#endif
63extern int dhtimer();
64
65/*
66 * DM control bits
67 */
68#define TURNON 03 /* CD lead + line enable */
69#define TURNOFF 01 /* line enable */
70#define RQS 04 /* request to send */
71
72/*
73 * Software copy of last dhbar
74 */
75short dhsar[(NDH11+15)/16];
76
77struct device
78{
79 union {
80 short dhcsr;
81 char dhcsrl;
82 } un;
83 short dhnxch;
84 short dhlpr;
85 unsigned short dhcar;
86 short dhbcr;
87 unsigned short dhbar;
88 short dhbreak;
89 short dhsilo;
90};
91
92/*
93 * Open a DH11 line.
94 */
95/*ARGSUSED*/
96dhopen(dev, flag)
97{
98 register struct tty *tp;
99 register d;
100 register struct device *addr;
101 static timer_on;
102 int s;
103
104 d = minor(dev) & 0177;
105 if (d >= NDH11) {
106 u.u_error = ENXIO;
107 return;
108 }
109 tp = &dh11[d];
110 addr = DHADDR;
111 addr += d>>4;
112 tp->t_addr = (caddr_t)addr;
113 tp->t_oproc = dhstart;
114 tp->t_iproc = NULL;
115 tp->t_state |= WOPEN;
116 s = spl6();
117 if (!timer_on) {
118 timer_on++;
119 timeout(dhtimer, (caddr_t)0, DHTIME);
120 cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0);
121 }
122 splx(s);
123 addr->un.dhcsr |= IENAB;
124 if ((tp->t_state&ISOPEN) == 0) {
125 ttychars(tp);
126 tp->t_ispeed = SSPEED;
127 tp->t_ospeed = SSPEED;
128 tp->t_flags = ODDP|EVENP|ECHO;
129 dhparam(d);
130 }
131 if (tp->t_state&XCLUDE && u.u_uid!=0) {
132 u.u_error = EBUSY;
133 return;
134 }
135 dmopen(dev);
136 (*linesw[tp->t_line].l_open)(dev,tp);
137}
138
139/*
140 * Close a DH11 line.
141 */
142/*ARGSUSED*/
143dhclose(dev, flag)
144dev_t dev;
145int flag;
146{
147 register struct tty *tp;
148 register d;
149
150 d = minor(dev) & 0177;
151 tp = &dh11[d];
152 (*linesw[tp->t_line].l_close)(tp);
153 if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
154 dmctl(d, TURNOFF);
155 ttyclose(tp);
156}
157
158/*
159 * Read from a DH11 line.
160 */
161dhread(dev)
162{
163register struct tty *tp;
164
165 tp = &dh11[minor(dev) & 0177];
166 (*linesw[tp->t_line].l_read)(tp);
167}
168
169/*
170 * write on a DH11 line
171 */
172dhwrite(dev)
173{
174register struct tty *tp;
175
176 tp = &dh11[minor(dev) & 0177];
177 (*linesw[tp->t_line].l_write)(tp);
178}
179
180/*
181 * DH11 receiver interrupt.
182 */
183dhrint(dev)
184{
185 register struct tty *tp;
186 register short c;
187 register struct device *addr;
188
189 addr = DHADDR;
190 addr += minor(dev) & 0177;
191 while ((c = addr->dhnxch) < 0) { /* char. present */
192 tp = &dh11[((minor(dev)&0177)<<4) + ((c>>8)&017)];
193 dhchars[minor(dev)&0177]++;
194 if (tp >= &dh11[NDH11])
195 continue;
196 if((tp->t_state&ISOPEN)==0) {
197 wakeup((caddr_t)tp);
198 continue;
199 }
200 if (c&PERROR)
201 if ((tp->t_flags&(EVENP|ODDP))==EVENP
202 || (tp->t_flags&(EVENP|ODDP))==ODDP )
203 continue;
204 if (c&OVERRUN)
205 printf("O");
206 if (c&FRERROR) /* break */
207 if (tp->t_flags&RAW)
208 c = 0; /* null (for getty) */
209 else
210 c = 0177; /* DEL (intr) */
211 (*linesw[tp->t_line].l_rint)(c,tp);
212 }
213}
214
215/*
216 * stty/gtty for DH11
217 */
218/*ARGSUSED*/
219dhioctl(dev, cmd, addr, flag)
220caddr_t addr;
221{
222 register struct tty *tp;
223
224 tp = &dh11[minor(dev) & 0177];
225 if (ttioccomm(cmd, tp, addr, dev)) {
226 if (cmd==TIOCSETP||cmd==TIOCSETN)
227 dhparam(dev);
228 } else if (cmd==TIOCSBRK) {
229 /* send a break */
230 register int linebit = 1 << (dev&017);
231 extern dhunbrk();
232
233 wflushtty(tp);
234 spl5();
235 ((struct device *)tp->t_addr)->dhbreak |= linebit;
236 tp->t_state |= TIMEOUT;
237 timeout(dhunbrk, (caddr_t)tp, 25); /* 300-500 ms */
238 while (((struct device *)tp->t_addr)->dhbreak & linebit)
239 sleep((caddr_t)&tp->t_rawq, TTIPRI);
240 tp->t_state &= ~TIMEOUT;
241 spl0();
242 flushtty(tp);
243 return;
244 } else
245 u.u_error = ENOTTY;
246}
247
248dhunbrk(tp)
249register struct tty *tp;
250{
251
252 ((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017));
253 wakeup((caddr_t)&tp->t_rawq);
254}
255
256/*
257 * Set parameters from open or stty into the DH hardware
258 * registers.
259 */
260dhparam(dev)
261{
262 register struct tty *tp;
263 register struct device *addr;
264 register d;
265
266 d = minor(dev) & 0177;
267 tp = &dh11[d];
268 addr = (struct device *)tp->t_addr;
269 spl5();
270 addr->un.dhcsrl = (d&017) | IENAB;
271 /*
272 * Hang up line?
273 */
274 if ((tp->t_ispeed)==0) {
275 tp->t_state |= HUPCLS;
276 dmctl(d, TURNOFF);
277 return;
278 }
279 d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
280 if ((tp->t_ispeed) == 4) /* 134.5 baud */
281 d |= BITS6|PENABLE|HDUPLX;
282 else if (tp->t_flags&RAW)
283 d |= BITS8;
284 else
285 d |= BITS7|PENABLE;
286 if ((tp->t_flags&EVENP) == 0)
287 d |= OPAR;
288 if ((tp->t_ospeed) == 3) /* 110 baud */
289 d |= TWOSB;
290 addr->dhlpr = d;
291 spl0();
292}
293
294/*
295 * DH11 transmitter interrupt.
296 * Restart each line which used to be active but has
297 * terminated transmission since the last interrupt.
298 */
299dhxint(dev)
300{
301 register struct tty *tp;
302 register struct device *addr;
303 register d;
304 short ttybit, bar, *sbar;
305
306 d = minor(dev) & 0177;
307 addr = DHADDR + d;
308 addr->un.dhcsr &= (short)~XINT;
309 sbar = &dhsar[d];
310 bar = *sbar & ~addr->dhbar;
311 d <<= 4; ttybit = 1;
312
313 for(; bar; d++, ttybit <<= 1) {
314 if(bar&ttybit) {
315 *sbar &= ~ttybit;
316 bar &= ~ttybit;
317 tp = &dh11[d];
318 if (tp->t_line) {
319 (*linesw[tp->t_line].l_start)(tp);
320 } else {
321 addr->un.dhcsrl = (d&017)|IENAB;
322 if (tp->t_state&FLUSH)
323 tp->t_state &= ~FLUSH;
324 else {
325 ndflush(&q3, dhcc[d]);
326 }
327 tp->t_state &= ~BUSY;
328 dhstart(tp);
329 }
330 }
331 }
332}
333
334/*
335 * Start (restart) transmission on the given DH11 line.
336 */
337dhstart(tp)
338register struct tty *tp;
339{
340 register struct device *addr;
341 register short nch;
342 int s, d;
343
344 /*
345 * If it's currently active, or delaying,
346 * no need to do anything.
347 */
348 s = spl5();
349 d = tp-dh11;
350 addr = (struct device *)tp->t_addr;
351 if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
352 goto out;
353
354
355 /*
356 * If the writer was sleeping on output overflow,
357 * wake him when low tide is reached.
358 */
359 if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) {
360 tp->t_state &= ~ASLEEP;
361 if (tp->t_chan)
362 mcstart(tp->t_chan, (caddr_t)&tp->t_outq); else
363 wakeup((caddr_t)&tp->t_outq);
364 }
365
366 if (tp->t_outq.c_cc == 0)
367 goto out;
368
369
370
371 /*
372 * Find number of characters to transfer.
373 */
374 if (tp->t_flags & RAW) {
375 nch = ndqb(&tp->t_outq, 0);
376 } else {
377 nch = ndqb(&tp->t_outq, 0200);
378 if (nch == 0) {
379 nch = getc(&tp->t_outq);
380 timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
381 tp->t_state |= TIMEOUT;
382 goto out;
383 }
384 }
385 /*
386 * If any characters were set up, start transmission;
387 */
388 if (nch) {
389 addr->un.dhcsrl = (d&017)|IENAB;
390 addr->dhcar = UBACVT(tp->t_outq.c_cf);
391 addr->dhbcr = -nch;
392 dhcc[d] = nch;
393 nch = 1<<(d&017);
394 addr->dhbar |= nch;
395 dhsar[d>>4] |= nch;
396 tp->t_state |= BUSY;
397 }
398 out:
399 splx(s);
400}
401
402
403/*
404 * Stop output on a line.
405 * Assume call is made at spl6.
406 */
407/*ARGSUSED*/
408dhstop(tp, flag)
409register struct tty *tp;
410{
411 register s;
412
413 s = spl6();
414 if (tp->t_state & BUSY)
415 if ((tp->t_state&TTSTOP)==0)
416 tp->t_state |= FLUSH;
417 splx(s);
418}
419
420/*ARGSUSED*/
421dhtimer(dev)
422{
423register d,cc;
424register struct device *addr;
425 addr = DHADDR; d = 0;
426 do {
427 cc = dhchars[d];
428 dhchars[d] = 0;
429 if (cc > 8*DHTIME)
430 cc = 32; else
431 if (cc > 3*DHTIME)
432 cc = 16; else
433 cc = 0;
434 addr->dhsilo = cc;
435 addr++;
436 dhrint(d++);
437 } while (d < (NDH11+15)/16);
438 timeout(dhtimer, (caddr_t)0, DHTIME);
439}