|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * %W% (Berkeley) %G%
7: */
8:
9: /*
10: * Common code for DMF32 and DMZ32 drivers
11: */
12: #include "dmf.h"
13: #include "dmz.h"
14: #if NDMF + NDMZ > 0
15:
16: #include "../machine/pte.h"
17:
18: #include "bk.h"
19: #include "uba.h"
20: #include "param.h"
21: #include "conf.h"
22: #include "dir.h"
23: #include "user.h"
24: #include "proc.h"
25: #include "ioctl.h"
26: #include "tty.h"
27: #include "map.h"
28: #include "buf.h"
29: #include "vm.h"
30: #include "bkmac.h"
31: #include "clist.h"
32: #include "file.h"
33: #include "uio.h"
34: #include "kernel.h"
35: #include "syslog.h"
36:
37: #include "dmx.h"
38: #include "ubareg.h"
39: #include "ubavar.h"
40: #include "dmxreg.h"
41: #include "dmreg.h"
42:
43: #ifndef PORTSELECTOR
44: #define ISPEED B9600
45: #define IFLAGS (EVENP|ODDP|ECHO)
46: #else
47: #define ISPEED B4800
48: #define IFLAGS (EVENP|ODDP)
49: #endif
50:
51: #ifndef DMX_TIMEOUT
52: #define DMX_TIMEOUT 10
53: #endif
54: int dmx_timeout = DMX_TIMEOUT; /* silo timeout, in ms */
55: int dmx_mindma = 4; /* don't dma below this point */
56:
57: char dmx_speeds[] =
58: { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
59:
60: /*
61: * The clist space is mapped by the drivers onto each UNIBUS.
62: * The UBACVT macro converts a clist space address for unibus uban
63: * into an I/O space address for the DMA routine.
64: */
65: int cbase[NUBA]; /* base address in unibus map */
66: #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
67:
68: int ttrstrt();
69:
70: /*
71: * DMF/DMZ open common code
72: */
73: dmxopen(tp, sc)
74: register struct tty *tp;
75: register struct dmx_softc *sc;
76: {
77: int s, unit;
78:
79: s = spltty();
80: if ((sc->dmx_flags & DMX_ACTIVE) == 0) {
81: sc->dmx_octet->csr |= DMF_IE;
82: sc->dmx_flags |= DMX_ACTIVE;
83: sc->dmx_octet->rsp = dmx_timeout;
84: }
85: splx(s);
86: if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
87: return (EBUSY);
88: /*
89: * If this is first open, initialize tty state to default.
90: */
91: if ((tp->t_state&TS_ISOPEN) == 0) {
92: ttychars(tp);
93: #ifndef PORTSELECTOR
94: if (tp->t_ispeed == 0) {
95: #else
96: tp->t_state |= TS_HUPCLS;
97: #endif PORTSELECTOR
98: tp->t_ispeed = ISPEED;
99: tp->t_ospeed = ISPEED;
100: tp->t_flags = IFLAGS;
101: #ifndef PORTSELECTOR
102: }
103: #endif PORTSELECTOR
104: }
105: dmxparam(tp);
106:
107: unit = minor(tp->t_dev) & 07;
108: /*
109: * Wait for carrier, then process line discipline specific open.
110: */
111: s = spltty();
112: for (;;) {
113: if ((dmxmctl(tp, DMF_ON, DMSET) & DMF_CAR) ||
114: (sc->dmx_softCAR & (1 << unit)))
115: tp->t_state |= TS_CARR_ON;
116: if (tp->t_state & TS_CARR_ON)
117: break;
118: tp->t_state |= TS_WOPEN;
119: sleep((caddr_t)&tp->t_rawq, TTIPRI);
120: }
121: splx(s);
122: return ((*linesw[tp->t_line].l_open)(tp->t_dev, tp));
123: }
124:
125: dmxclose(tp)
126: register struct tty *tp;
127: {
128:
129: (*linesw[tp->t_line].l_close)(tp);
130: (void) dmxmctl(tp, DMF_BRK, DMBIC);
131: if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
132: (void) dmxmctl(tp, DMF_OFF, DMSET);
133: ttyclose(tp);
134: }
135:
136: dmxrint(sc)
137: register struct dmx_softc *sc;
138: {
139: register c;
140: register struct tty *tp;
141: register struct dmx_octet *addr;
142: int unit;
143: int overrun = 0;
144:
145: addr = (struct dmx_octet *)sc->dmx_octet;
146: /*
147: * Loop fetching characters from the silo for this
148: * octet until there are no more in the silo.
149: */
150: while ((c = addr->rbuf) < 0) {
151:
152: unit = (c >> 8) & 07;
153: tp = sc->dmx_tty + unit;
154: if (c & DMF_DSC) {
155: addr->csr = DMF_IE | DMFIR_RMSTSC | unit;
156: if (addr->rmstsc & DMF_CAR)
157: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
158: else if ((sc->dmx_softCAR & (1 << unit)) == 0 &&
159: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
160: addr->csr = DMF_IE | DMFIR_LCR | unit;
161: addr->lctms = DMF_ENA;
162: }
163: continue;
164: }
165: if ((tp->t_state&TS_ISOPEN) == 0) {
166: wakeup((caddr_t)&tp->t_rawq);
167: #ifdef PORTSELECTOR
168: if ((tp->t_state & TS_WOPEN) == 0)
169: #endif
170: continue;
171: }
172: if (c & (DMF_PE|DMF_DO|DMF_FE)) {
173: if (c & DMF_PE)
174: if ((tp->t_flags & (EVENP|ODDP)) == EVENP
175: || (tp->t_flags & (EVENP|ODDP)) == ODDP)
176: continue;
177: if ((c & DMF_DO) && overrun == 0) {
178: log(LOG_WARNING,
179: "dm%c%d: silo overflow, line %d\n",
180: sc->dmx_type, sc->dmx_unit,
181: sc->dmx_unit0 + unit);
182: overrun = 1;
183: }
184: if (c & DMF_FE)
185: /*
186: * At framing error (break) generate
187: * a null (in raw mode, for getty), or an
188: * interrupt (in cooked/cbreak mode).
189: */
190: if (tp->t_flags & RAW)
191: c = 0;
192: else
193: c = tp->t_intrc;
194: }
195: (*linesw[tp->t_line].l_rint)(c, tp);
196: }
197: }
198:
199: dmxioctl(tp, cmd, data, flag)
200: register struct tty *tp;
201: caddr_t data;
202: {
203: int error;
204:
205: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
206: if (error >= 0)
207: return (error);
208: error = ttioctl(tp, cmd, data, flag);
209: if (error >= 0) {
210: if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
211: cmd == TIOCLBIC || cmd == TIOCLSET)
212: dmxparam(tp);
213: return (error);
214: }
215: switch (cmd) {
216:
217: case TIOCSBRK:
218: (void) dmxmctl(tp, DMF_BRK, DMBIS);
219: break;
220:
221: case TIOCCBRK:
222: (void) dmxmctl(tp, DMF_BRK, DMBIC);
223: break;
224:
225: case TIOCSDTR:
226: (void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIS);
227: break;
228:
229: case TIOCCDTR:
230: (void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIC);
231: break;
232:
233: case TIOCMSET:
234: (void) dmxmctl(tp, dmtodmx(*(int *)data), DMSET);
235: break;
236:
237: case TIOCMBIS:
238: (void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIS);
239: break;
240:
241: case TIOCMBIC:
242: (void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIC);
243: break;
244:
245: case TIOCMGET:
246: *(int *)data = dmxmctl(tp, 0, DMGET);
247: break;
248:
249: default:
250: return (ENOTTY);
251: }
252: return (0);
253: }
254:
255: /*
256: * modem control
257: * "bits" are dmf/dmz lcr format;
258: * return of DMGET is DM11 format.
259: */
260: dmxmctl(tp, bits, how)
261: struct tty *tp;
262: int bits, how;
263: {
264: register struct dmx_octet *addr;
265: register int unit, mbits, lcr;
266: int s;
267:
268: unit = minor(tp->t_dev) & 07;
269: addr = (struct dmx_octet *)(tp->t_addr);
270:
271: s = spltty();
272: addr->csr = DMF_IE | DMFIR_RMSTSC | unit;
273: mbits = addr->rmstsc & 0xff00;
274: addr->csr = DMF_IE | DMFIR_LCR | unit;
275: lcr = addr->lctms;
276:
277: switch (how) {
278: case DMSET:
279: lcr = bits;
280: break;
281:
282: case DMBIS:
283: lcr |= bits;
284: break;
285:
286: case DMBIC:
287: lcr &= ~bits;
288: break;
289:
290: case DMGET:
291: splx(s);
292: return (dmxtodm(mbits, lcr));
293: }
294: addr->lctms = lcr;
295: (void) splx(s);
296: return (mbits);
297: }
298:
299: /*
300: * Routine to convert modem status from dm to dmf/dmz lctmr format.
301: */
302: dmtodmx(bits)
303: register int bits;
304: {
305: register int lcr = DMF_ENA;
306:
307: if (bits & DML_DTR)
308: lcr |= DMF_DTR;
309: if (bits & DML_RTS)
310: lcr |= DMF_RTS;
311: if (bits & DML_ST)
312: lcr |= DMF_SRTS;
313: if (bits & DML_USR)
314: lcr |= DMF_USRW;
315: return (lcr);
316: }
317:
318: /*
319: * Routine to convert modem status from dmf/dmz receive modem status
320: * and line control register to dm format.
321: * If dmf/dmz user modem read bit set, set DML_USR.
322: */
323: dmxtodm(mstat, lcr)
324: register int mstat, lcr;
325: {
326:
327: mstat = ((mstat & (DMF_DSR|DMF_RNG|DMF_CAR|DMF_CTS|DMF_SR)) >> 7) |
328: ((mstat & DMF_USRR) >> 1) | DML_LE;
329: if (lcr & DMF_DTR)
330: mstat |= DML_DTR;
331: if (lcr & DMF_SRTS)
332: mstat |= DML_ST;
333: if (lcr & DMF_RTS)
334: mstat |= DML_RTS;
335: return (mstat);
336: }
337:
338:
339: /*
340: * Set parameters from open or ioctl into the hardware registers.
341: */
342: dmxparam(tp)
343: register struct tty *tp;
344: {
345: register struct dmx_octet *addr;
346: register int lpar, lcr;
347: int s, unit;
348:
349: addr = (struct dmx_octet *)tp->t_addr;
350: unit = minor(tp->t_dev) & 07;
351: /*
352: * Block interrupts so parameters will be set
353: * before the line interrupts.
354: */
355: s = spltty();
356: addr->csr = unit | DMFIR_LCR | DMF_IE;
357: if (tp->t_ispeed == 0) {
358: tp->t_state |= TS_HUPCLS;
359: (void) dmxmctl(tp, DMF_OFF, DMSET);
360: splx(s);
361: return;
362: }
363: lpar = (dmx_speeds[tp->t_ospeed]<<12) | (dmx_speeds[tp->t_ispeed]<<8);
364: lcr = DMF_ENA;
365: if ((tp->t_ispeed) == B134)
366: lpar |= BITS6|PENABLE;
367: else if (tp->t_flags & (RAW|LITOUT|PASS8))
368: lpar |= BITS8;
369: else {
370: lpar |= BITS7|PENABLE;
371: /* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
372: }
373: if (tp->t_flags&EVENP)
374: lpar |= EPAR;
375: if ((tp->t_ospeed) == B110)
376: lpar |= TWOSB;
377: lpar |= (unit&07);
378: addr->lpr = lpar;
379: addr->lctms = (addr->lctms &~ 0xff) | lcr;
380: splx(s);
381: }
382:
383: /*
384: * Process a transmit interrupt on an octet.
385: */
386: dmxxint(sc)
387: register struct dmx_softc *sc;
388: {
389: register struct tty *tp;
390: register struct dmx_octet *addr;
391: register int t;
392:
393: addr = (struct dmx_octet *)sc->dmx_octet;
394: while ((t = addr->csr) & DMF_TI) {
395: if (t & DMF_NXM)
396: /* SHOULD RESTART OR SOMETHING... */
397: printf("dm%c%d: NXM line %d\n", sc->dmx_type,
398: sc->dmx_unit, sc->dmx_unit0 + (t >> 8 & 7));
399: t = t >> 8 & 7;
400: tp = sc->dmx_tty + t;
401: tp->t_state &= ~TS_BUSY;
402: if (tp->t_state & TS_FLUSH)
403: tp->t_state &= ~TS_FLUSH;
404: #define new
405: #ifndef new
406: else if (sc->dmx_dmacount[t]) {
407: short cntr;
408:
409: /*
410: * Do arithmetic in a short to make up
411: * for lost 16&17 bits.
412: */
413: addr->csr = DMFIR_TBA | DMF_IE | t;
414: cntr = addr->tba -
415: UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum);
416: ndflush(&tp->t_outq, (int)cntr);
417: }
418: #else
419: else if (sc->dmx_dmacount[t])
420: ndflush(&tp->t_outq, sc->dmx_dmacount[t]);
421: sc->dmx_dmacount[t] = 0;
422: #endif
423: (*linesw[tp->t_line].l_start)(tp);
424: }
425: }
426:
427: dmxstart(tp, sc)
428: register struct tty *tp;
429: struct dmx_softc *sc;
430: {
431: register struct dmx_octet *addr;
432: register int unit, nch;
433: int s;
434:
435: unit = minor(tp->t_dev) & 07;
436: addr = (struct dmx_octet *)tp->t_addr;
437:
438: /*
439: * Must hold interrupts in following code to prevent
440: * state of the tp from changing.
441: */
442: s = spltty();
443: /*
444: * If it's currently active, or delaying, no need to do anything.
445: */
446: if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
447: goto out;
448: /*
449: * If there are still characters to dma or in the silo,
450: * just reenable the transmitter.
451: */
452: addr->csr = DMF_IE | DMFIR_TBUF | unit;
453: #ifdef new
454: if (addr->tsc || sc->dmx_dmacount[unit]) {
455: #else
456: if (addr->tsc) {
457: #endif
458: addr->csr = DMF_IE | DMFIR_LCR | unit;
459: addr->lctms = addr->lctms | DMF_TE;
460: tp->t_state |= TS_BUSY;
461: goto out;
462: }
463: /*
464: * If there are sleepers, and output has drained below low
465: * water mark, wake up the sleepers.
466: */
467: if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
468: if (tp->t_state & TS_ASLEEP) {
469: tp->t_state &= ~TS_ASLEEP;
470: wakeup((caddr_t)&tp->t_outq);
471: }
472: if (tp->t_wsel) {
473: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
474: tp->t_wsel = 0;
475: tp->t_state &= ~TS_WCOLL;
476: }
477: }
478: /*
479: * Now restart transmission unless the output queue is
480: * empty.
481: */
482: if (tp->t_outq.c_cc == 0)
483: goto out;
484: if (tp->t_flags & (RAW|LITOUT))
485: nch = ndqb(&tp->t_outq, 0);
486: else {
487: if ((nch = ndqb(&tp->t_outq, 0200)) == 0) {
488: /*
489: * If first thing on queue is a delay process it.
490: */
491: nch = getc(&tp->t_outq);
492: timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
493: tp->t_state |= TS_TIMEOUT;
494: goto out;
495: }
496: }
497: /*
498: * If characters to transmit, restart transmission.
499: */
500: if (nch >= dmx_mindma) {
501: register car;
502:
503: sc->dmx_dmacount[unit] = nch;
504: addr->csr = DMF_IE | DMFIR_LCR | unit;
505: addr->lctms = addr->lctms | DMF_TE;
506: car = UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum);
507: addr->csr = DMF_IE | DMFIR_TBA | unit;
508: addr->tba = car;
509: addr->tcc = ((car >> 2) & 0xc000) | nch;
510: tp->t_state |= TS_BUSY;
511: } else if (nch) {
512: register char *cp = tp->t_outq.c_cf;
513: register int i;
514:
515: #ifndef new
516: sc->dmx_dmacount[unit] = 0;
517: #endif
518: nch = MIN(nch, DMF_SILOCNT);
519: addr->csr = DMF_IE | DMFIR_LCR | unit;
520: addr->lctms = addr->lctms | DMF_TE;
521: addr->csr = DMF_IE | DMFIR_TBUF | unit;
522: for (i = 0; i < nch; i++)
523: addr->tbuf = *cp++;
524: ndflush(&tp->t_outq, nch);
525: tp->t_state |= TS_BUSY;
526: }
527: out:
528: splx(s);
529: }
530:
531: dmxstop(tp, sc, flag)
532: register struct tty *tp;
533: struct dmx_softc *sc;
534: {
535: register struct dmx_octet *addr;
536: register unit = minor(tp->t_dev) & 7;
537: int s;
538:
539: addr = (struct dmx_octet *)tp->t_addr;
540: /*
541: * Block input/output interrupts while messing with state.
542: */
543: s = spltty();
544: if (flag) {
545: addr->csr = DMF_IE | DMFIR_TBUF | unit;
546: if (addr->tsc) {
547: /*
548: * Flush regardless of whether we're transmitting
549: * (TS_BUSY), if the silo contains untransmitted
550: * characters.
551: */
552: addr->csr = DMFIR_LCR | unit | DMF_IE;
553: addr->lctms = addr->lctms | DMF_TE | DMF_FLUSH;
554: /* this will interrupt so let dmxxint handle the rest */
555: tp->t_state |= TS_FLUSH|TS_BUSY;
556: }
557: /*#ifdef new*/
558: sc->dmx_dmacount[unit] = 0;
559: /*#endif*/
560: } else {
561: /*
562: * Stop transmission by disabling
563: * the transmitter. We'll pick up where we
564: * left off by reenabling in dmxstart.
565: */
566: addr->csr = DMFIR_LCR | unit | DMF_IE;
567: addr->lctms = addr->lctms &~ DMF_TE;
568: /* no interrupt here */
569: tp->t_state &= ~TS_BUSY;
570: }
571: splx(s);
572: }
573: #endif NDMF + NDMZ
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.