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