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