|
|
1.1 root 1: /*
2: * This file is derived from version 7.2 of the VX driver to create
3: * a driver compatible with the 4.3BSD-tahoe release.
4: */
5:
6: /*
7: * Copyright (c) 1988 Regents of the University of California.
8: * All rights reserved.
9: *
10: * This code is derived from software contributed to Berkeley by
11: * Computer Consoles Inc.
12: *
13: * Redistribution and use in source and binary forms are permitted
14: * provided that the above copyright notice and this paragraph are
15: * duplicated in all such forms and that any documentation,
16: * advertising materials, and other materials related to such
17: * distribution and use acknowledge that the software was developed
18: * by the University of California, Berkeley. The name of the
19: * University may not be used to endorse or promote products derived
20: * from this software without specific prior written permission.
21: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
22: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24: *
25: * @(#)vx.c 7.2 (Berkeley) 7/9/88
26: */
27:
28: #include "vx.h"
29: #if NVX > 0
30: /*
31: * VIOC-X driver
32: */
33: #ifdef VXPERF
34: #define DOSCOPE
35: #endif
36:
37: #include "param.h"
38: #include "ioctl.h"
39: #include "tty.h"
40: #include "dir.h"
41: #include "user.h"
42: #include "map.h"
43: #include "buf.h"
44: #include "conf.h"
45: #include "file.h"
46: #include "uio.h"
47: #include "proc.h"
48: #include "vm.h"
49: #include "kernel.h"
50: #include "syslog.h"
51:
52: #include "../tahoe/pte.h"
53:
54: #include "../tahoevba/vbavar.h"
55: #include "../tahoevba/vbaparam.h"
56: #include "../tahoevba/vxreg.h"
57: #include "../tahoevba/scope.h"
58:
59: #ifdef VX_DEBUG
60: long vxintr4 = 0;
61: #define VXERR4 1
62: #define VXNOBUF 2
63: long vxdebug = 0;
64: #define VXVCM 1
65: #define VXVCC 2
66: #define VXVCX 4
67: #endif
68:
69: /*
70: * Interrupt type bits passed to vinthandl().
71: */
72: #define CMDquals 0 /* command completed interrupt */
73: #define RSPquals 1 /* command response interrupt */
74: #define UNSquals 2 /* unsolicited interrupt */
75:
76: #define VXUNIT(n) ((n) >> 4)
77: #define VXPORT(n) ((n) & 0xf)
78:
79: struct tty vx_tty[NVX*16];
80: #ifndef lint
81: int nvx = NVX*16;
82: #endif
83: int vxstart(), ttrstrt();
84: struct vxcmd *vobtain(), *nextcmd();
85:
86: /*
87: * Driver information for auto-configuration stuff.
88: */
89: int vxprobe(), vxattach(), vxrint();
90: struct vba_device *vxinfo[NVX];
91: long vxstd[] = { 0 };
92: struct vba_driver vxdriver =
93: { vxprobe, 0, vxattach, 0, vxstd, "vx", vxinfo };
94:
95: struct vx_softc {
96: u_char vs_type; /* 0: viox-x/vioc-b, 1: vioc-bop */
97: u_char vs_bop; /* bop board # for vioc-bop's */
98: u_char vs_loport; /* low port nbr */
99: u_char vs_hiport; /* high port nbr */
100: u_short vs_nbr; /* viocx number */
101: u_short vs_maxcmd; /* max number of concurrent cmds */
102: u_short vs_silosiz; /* silo size */
103: short vs_vers; /* vioc/pvioc version */
104: #define VXV_OLD 0 /* PVIOCX | VIOCX */
105: #define VXV_NEW 1 /* NPVIOCX | NVIOCX */
106: short vs_xmtcnt; /* xmit commands pending */
107: short vs_brkreq; /* send break requests pending */
108: short vs_state; /* controller state */
109: #define VXS_READY 0 /* ready for commands */
110: #define VXS_RESET 1 /* in process of reseting */
111: u_short vs_softCAR; /* soft carrier */
112: caddr_t vs_mricmd; /* most recent issued cmd */
113: u_int vs_ivec; /* interrupt vector base */
114: struct vxcmd *vs_avail;/* next available command buffer */
115: struct vxcmd *vs_build;
116: struct vxcmd vs_lst[NVCXBUFS];
117: struct vcmds vs_cmds;
118: } vx_softc[NVX];
119:
120: vxprobe(reg, vi)
121: caddr_t reg;
122: struct vba_device *vi;
123: {
124: register int br, cvec; /* must be r12, r11 */
125: register struct vxdevice *vp;
126: register struct vx_softc *vs;
127: struct pte *dummypte;
128:
129: #ifdef lint
130: br = 0; cvec = br; br = cvec;
131: vackint(0); vunsol(0); vcmdrsp(0); vxfreset(0);
132: #endif
133: if (!VBIOMAPPED(reg) && !vbmemalloc(16, reg, &dummypte, ®)) {
134: printf("vx%d: vbmemalloc failed.\n", vi->ui_unit);
135: return(0);
136: }
137: vp = (struct vxdevice *)reg;
138: if (badaddr((caddr_t)vp, 1))
139: return (0);
140: vi->ui_addr = reg;
141: vp->v_fault = 0;
142: vp->v_vioc = V_BSY;
143: vp->v_hdwre = V_RESET; /* reset interrupt */
144: DELAY(4000000);
145: if (vp->v_fault != VXF_READY)
146: return (0);
147: vs = &vx_softc[vi->ui_unit];
148: #ifdef notdef
149: /*
150: * Align vioc interrupt vector base to 4 vector
151: * boundary and fitting in 8 bits (is this necessary,
152: * wish we had documentation).
153: */
154: if ((vi->ui_hd->vh_lastiv -= 3) > 0xff)
155: vi->ui_hd->vh_lastiv = 0xff;
156: vs->vs_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x3;
157: #else
158: vs->vs_ivec = 0x40+vi->ui_unit*4;
159: #endif
160: br = 0x18, cvec = vs->vs_ivec; /* XXX */
161: return (sizeof (struct vxdevice));
162: }
163:
164: vxattach(vi)
165: register struct vba_device *vi;
166: {
167:
168: vx_softc[vi->ui_unit].vs_softCAR = vi->ui_flags;
169: vxinit(vi->ui_unit, 1);
170: }
171:
172: /*
173: * Open a VX line.
174: */
175: /*ARGSUSED*/
176: vxopen(dev, flag)
177: dev_t dev;
178: int flag;
179: {
180: register struct tty *tp; /* pointer to tty struct for port */
181: register struct vx_softc *vs;
182: register struct vba_device *vi;
183: int unit, vx, s, error;
184:
185: unit = minor(dev);
186: vx = VXUNIT(unit);
187: if (vx >= NVX || (vi = vxinfo[vx])== 0 || vi->ui_alive == 0)
188: return (ENXIO);
189: vs = &vx_softc[vx];
190: tp = &vx_tty[unit];
191: unit = VXPORT(unit);
192: if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
193: return (EBUSY);
194: if (unit < vs->vs_loport || unit > vs->vs_hiport)
195: return (ENXIO);
196: tp->t_addr = (caddr_t)vs;
197: tp->t_oproc = vxstart;
198: tp->t_dev = dev;
199: s = spl8();
200: tp->t_state |= TS_WOPEN;
201: if ((tp->t_state&TS_ISOPEN) == 0) {
202: ttychars(tp);
203: if (tp->t_ispeed == 0) {
204: tp->t_ispeed = SSPEED;
205: tp->t_ospeed = SSPEED;
206: tp->t_flags |= ODDP|EVENP|ECHO;
207: }
208: vxparam(dev);
209: }
210: vcmodem(dev, VMOD_ON);
211: while ((tp->t_state&TS_CARR_ON) == 0)
212: sleep((caddr_t)&tp->t_rawq, TTIPRI);
213: error = (*linesw[tp->t_line].l_open)(dev,tp);
214: splx(s);
215: return (error);
216: }
217:
218: /*
219: * Close a VX line.
220: */
221: /*ARGSUSED*/
222: vxclose(dev, flag)
223: dev_t dev;
224: int flag;
225: {
226: register struct tty *tp;
227: int unit, s;
228:
229: unit = minor(dev);
230: tp = &vx_tty[unit];
231: s = spl8();
232: (*linesw[tp->t_line].l_close)(tp);
233: if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
234: vcmodem(dev, VMOD_OFF);
235: /* wait for the last response */
236: while (tp->t_state&TS_FLUSH)
237: sleep((caddr_t)&tp->t_state, TTOPRI);
238: ttyclose(tp);
239: splx(s);
240: }
241:
242: /*
243: * Read from a VX line.
244: */
245: vxread(dev, uio)
246: dev_t dev;
247: struct uio *uio;
248: {
249: struct tty *tp = &vx_tty[minor(dev)];
250:
251: return ((*linesw[tp->t_line].l_read)(tp, uio));
252: }
253:
254: /*
255: * write on a VX line
256: */
257: vxwrite(dev, uio)
258: dev_t dev;
259: struct uio *uio;
260: {
261: register struct tty *tp = &vx_tty[minor(dev)];
262:
263: return ((*linesw[tp->t_line].l_write)(tp, uio));
264: }
265:
266: /*
267: * VIOCX unsolicited interrupt.
268: */
269: vxrint(vx)
270: register vx;
271: {
272: register struct tty *tp, *tp0;
273: register struct vxdevice *addr;
274: register struct vx_softc *vs;
275: struct vba_device *vi;
276: register int nc, c;
277: register struct silo {
278: char data, port;
279: } *sp;
280: short *osp;
281: int overrun = 0;
282:
283: vi = vxinfo[vx];
284: if (vi == 0 || vi->ui_alive == 0)
285: return;
286: addr = (struct vxdevice *)vi->ui_addr;
287: switch (addr->v_uqual&037) {
288: case 0:
289: break;
290: case 2:
291: printf("vx%d: vc proc err, ustat %x\n", vx, addr->v_ustat);
292: vxstreset(vx);
293: return;
294: case 3:
295: vcmintr(vx);
296: return;
297: case 4:
298: return;
299: default:
300: printf("vx%d: vc uqual err, uqual %x\n", vx, addr->v_uqual);
301: vxstreset(vx);
302: return;
303: }
304: vs = &vx_softc[vx];
305: if (vs->vs_vers == VXV_NEW)
306: sp = (struct silo *)((caddr_t)addr + *(short *)addr->v_usdata);
307: else
308: sp = (struct silo *)((caddr_t)addr+VX_SILO+(addr->v_usdata[0]<<6));
309: nc = *(osp = (short *)sp);
310: if (nc == 0)
311: return;
312: if (vs->vs_vers == VXV_NEW && nc > vs->vs_silosiz) {
313: printf("vx%d: %d exceeds silo size\n", nc);
314: nc = vs->vs_silosiz;
315: }
316: tp0 = &vx_tty[vx*16];
317: sp = (struct silo *)(((short *)sp)+1);
318: for (; nc > 0; nc--, sp = (struct silo *)(((short *)sp)+1)) {
319: c = sp->port & 017;
320: if (vs->vs_loport > c || c > vs->vs_hiport)
321: continue;
322: tp = tp0 + c;
323: if( (tp->t_state&TS_ISOPEN) == 0) {
324: wakeup((caddr_t)&tp->t_rawq);
325: continue;
326: }
327: c = sp->data;
328: if ((sp->port&VX_RO) == VX_RO && !overrun) {
329: log(LOG_ERR, "vx%d: receiver overrun\n", vi->ui_unit);
330: overrun = 1;
331: continue;
332: }
333: if (sp->port&VX_PE)
334: if ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
335: (tp->t_flags&(EVENP|ODDP)) == ODDP)
336: continue;
337: if ((tp->t_flags & (RAW | PASS8)) == 0)
338: c &= 0177;
339: if (sp->port&VX_FE) {
340: /*
341: * At framing error (break) generate
342: * a null (in raw mode, for getty), or a
343: * interrupt (in cooked/cbreak mode).
344: */
345: if (tp->t_flags&RAW)
346: c = 0;
347: else
348: c = tp->t_intrc;
349: }
350: (*linesw[tp->t_line].l_rint)(c, tp);
351: }
352: *osp = 0;
353: }
354:
355: /*
356: * Ioctl for VX.
357: */
358: vxioctl(dev, cmd, data, flag)
359: dev_t dev;
360: caddr_t data;
361: {
362: register struct tty *tp;
363: int error;
364:
365: tp = &vx_tty[minor(dev)];
366: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
367: if (error == 0)
368: return (error);
369: error = ttioctl(tp, cmd, data, flag);
370: if (error >= 0) {
371: if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
372: cmd == TIOCLBIC || cmd == TIOCLSET)
373: vxparam(dev);
374: return (error);
375: }
376: return (ENOTTY);
377: }
378:
379: vxparam(dev)
380: dev_t dev;
381: {
382:
383: vxcparam(dev, 1);
384: }
385:
386: /*
387: * Set parameters from open or stty into the VX hardware
388: * registers.
389: */
390: vxcparam(dev, wait)
391: dev_t dev;
392: int wait;
393: {
394: register struct tty *tp;
395: register struct vx_softc *vs;
396: register struct vxcmd *cp;
397: int s, unit = minor(dev);
398:
399: tp = &vx_tty[unit];
400: if ((tp->t_ispeed)==0) {
401: tp->t_state |= TS_HUPCLS;
402: vcmodem(dev, VMOD_OFF);
403: return;
404: }
405: vs = (struct vx_softc *)tp->t_addr;
406: cp = vobtain(vs);
407: s = spl8();
408: /*
409: * Construct ``load parameters'' command block
410: * to setup baud rates, xon-xoff chars, parity,
411: * and stop bits for the specified port.
412: */
413: cp->cmd = VXC_LPARAX;
414: cp->par[1] = VXPORT(unit);
415: cp->par[2] = (tp->t_flags&RAW) ? 0 : tp->t_startc;
416: cp->par[3] = (tp->t_flags&RAW) ? 0 : tp->t_stopc;
417: #ifdef notnow
418: if (tp->t_flags & (RAW|LITOUT|PASS8)) {
419: #endif
420: cp->par[4] = BITS8; /* 8 bits of data */
421: cp->par[7] = VNOPARITY; /* no parity */
422: #ifdef notnow
423: } else {
424: cp->par[4] = BITS7; /* 7 bits of data */
425: if ((tp->t_flags&(EVENP|ODDP)) == ODDP)
426: cp->par[7] = VODDP; /* odd parity */
427: else
428: cp->par[7] = VEVENP; /* even parity */
429: }
430: #endif
431: if (tp->t_ospeed == B110)
432: cp->par[5] = VSTOP2; /* 2 stop bits */
433: else
434: cp->par[5] = VSTOP1; /* 1 stop bit */
435: if (tp->t_ospeed == EXTA || tp->t_ospeed == EXTB)
436: cp->par[6] = V19200;
437: else
438: cp->par[6] = tp->t_ospeed;
439: if (vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd) && wait)
440: sleep((caddr_t)cp,TTIPRI);
441: splx(s);
442: }
443:
444: /*
445: * VIOCX command response interrupt.
446: * For transmission, restart output to any active port.
447: * For all other commands, just clean up.
448: */
449: vxxint(vx, cp)
450: register int vx;
451: register struct vxcmd *cp;
452: {
453: register struct vxmit *vp;
454: register struct tty *tp, *tp0;
455: register struct vx_softc *vs;
456:
457: vs = &vx_softc[vx];
458: cp = (struct vxcmd *)((long *)cp-1);
459:
460: switch (cp->cmd&0xff00) {
461:
462: case VXC_LIDENT: /* initialization complete */
463: if (vs->vs_state == VXS_RESET) {
464: vxfnreset(vx, cp);
465: vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
466: }
467: cp->cmd++;
468: return;
469:
470: case VXC_XMITDTA:
471: case VXC_XMITIMM:
472: break;
473:
474: case VXC_LPARAX:
475: wakeup((caddr_t)cp);
476: /* fall thru... */
477: default: /* VXC_MDMCTL or VXC_FDTATOX */
478: vrelease(vs, cp);
479: if (vs->vs_state == VXS_RESET)
480: vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
481: return;
482: }
483: tp0 = &vx_tty[vx*16];
484: vp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizeof (struct vxmit));
485: for (; vp >= (struct vxmit *)cp->par; vp--) {
486: tp = tp0 + (vp->line & 017);
487: tp->t_state &= ~TS_BUSY;
488: if (tp->t_state & TS_FLUSH) {
489: tp->t_state &= ~TS_FLUSH;
490: wakeup((caddr_t)&tp->t_state);
491: } else
492: ndflush(&tp->t_outq, vp->bcount+1);
493: }
494: vrelease(vs, cp);
495: if (vs->vs_vers == VXV_NEW)
496: (*linesw[tp->t_line].l_start)(tp);
497: else {
498: tp0 = &vx_tty[vx*16 + vs->vs_hiport];
499: for(tp = &vx_tty[vx*16 + vs->vs_loport]; tp <= tp0; tp++)
500: (*linesw[tp->t_line].l_start)(tp);
501: if ((cp = nextcmd(vs)) != NULL) { /* command to send? */
502: vs->vs_xmtcnt++;
503: (void) vcmd(vx, (caddr_t)&cp->cmd);
504: }
505: }
506: vs->vs_xmtcnt--;
507: }
508:
509: /*
510: * Force out partial XMIT command after timeout
511: */
512: vxforce(vs)
513: register struct vx_softc *vs;
514: {
515: register struct vxcmd *cp;
516: int s;
517:
518: s = spl8();
519: if ((cp = nextcmd(vs)) != NULL) {
520: vs->vs_xmtcnt++;
521: (void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
522: }
523: splx(s);
524: }
525:
526: /*
527: * Start (restart) transmission on the given VX line.
528: */
529: vxstart(tp)
530: register struct tty *tp;
531: {
532: register short n;
533: register struct vx_softc *vs;
534: int s, port;
535:
536: s = spl8();
537: port = minor(tp->t_dev) & 017;
538: vs = (struct vx_softc *)tp->t_addr;
539: if ((tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) == 0) {
540: if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
541: if (tp->t_state&TS_ASLEEP) {
542: tp->t_state &= ~TS_ASLEEP;
543: wakeup((caddr_t)&tp->t_outq);
544: }
545: if (tp->t_wsel) {
546: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
547: tp->t_wsel = 0;
548: tp->t_state &= ~TS_WCOLL;
549: }
550: }
551: if (tp->t_outq.c_cc == 0) {
552: splx(s);
553: return;
554: }
555: scope_out(3);
556: if (tp->t_flags & (RAW|LITOUT))
557: n = ndqb(&tp->t_outq, 0);
558: else {
559: n = ndqb(&tp->t_outq, 0200);
560: if (n == 0) {
561: n = getc(&tp->t_outq);
562: timeout(ttrstrt, (caddr_t)tp, (n&0177)+6);
563: tp->t_state |= TS_TIMEOUT;
564: n = 0;
565: }
566: }
567: if (n) {
568: tp->t_state |= TS_BUSY;
569: vsetq(vs, port, (char *)tp->t_outq.c_cf, n);
570: }
571: }
572: splx(s);
573: }
574:
575: /*
576: * Stop output on a line.
577: */
578: vxstop(tp)
579: register struct tty *tp;
580: {
581: int s;
582:
583: s = spl8();
584: if (tp->t_state&TS_BUSY)
585: if ((tp->t_state&TS_TTSTOP) == 0)
586: tp->t_state |= TS_FLUSH;
587: splx(s);
588: }
589:
590: static int vxbbno = -1;
591: /*
592: * VIOCX Initialization. Makes free lists of command buffers.
593: * Resets all viocx's. Issues a LIDENT command to each
594: * viocx to establish interrupt vectors and logical port numbers.
595: */
596: vxinit(vx, wait)
597: register int vx;
598: int wait;
599: {
600: register struct vx_softc *vs;
601: register struct vxdevice *addr;
602: register struct vxcmd *cp;
603: register char *resp;
604: register int j;
605: char type, *typestring;
606:
607: vs = &vx_softc[vx];
608: vs->vs_type = 0; /* vioc-x by default */
609: addr = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
610: type = addr->v_ident;
611: vs->vs_vers = (type&VXT_NEW) ? VXV_NEW : VXV_OLD;
612: if (vs->vs_vers == VXV_NEW)
613: vs->vs_silosiz = addr->v_maxsilo;
614: switch (type) {
615:
616: case VXT_VIOCX:
617: case VXT_VIOCX|VXT_NEW:
618: typestring = "VIOC-X";
619: /* set soft carrier for printer ports */
620: for (j = 0; j < 16; j++)
621: if (addr->v_portyp[j] == VXT_PARALLEL) {
622: vs->vs_softCAR |= 1 << j;
623: addr->v_dcd |= 1 << j;
624: }
625: break;
626:
627: case VXT_PVIOCX:
628: case VXT_PVIOCX|VXT_NEW:
629: typestring = "VIOC-X (old connector panel)";
630: break;
631: case VXT_VIOCBOP: /* VIOC-BOP */
632: vs->vs_type = 1;
633: vs->vs_bop = ++vxbbno;
634: printf("VIOC-BOP no. %d at %x\n", vs->vs_bop, addr);
635:
636: default:
637: printf("vx%d: unknown type %x\n", vx, type);
638: vxinfo[vx]->ui_alive = 0;
639: return;
640: }
641: vs->vs_nbr = -1;
642: vs->vs_maxcmd = (vs->vs_vers == VXV_NEW) ? 24 : 4;
643: /*
644: * Initialize all cmd buffers by linking them
645: * into a free list.
646: */
647: for (j = 0; j < NVCXBUFS; j++) {
648: cp = &vs->vs_lst[j];
649: cp->c_fwd = &vs->vs_lst[j+1];
650: }
651: vs->vs_avail = &vs->vs_lst[0]; /* set idx to 1st free buf */
652: cp->c_fwd = (struct vxcmd *)0; /* mark last buf in free list */
653:
654: /*
655: * Establish the interrupt vectors and define the port numbers.
656: */
657: cp = vobtain(vs);
658: cp->cmd = VXC_LIDENT;
659: cp->par[0] = vs->vs_ivec; /* ack vector */
660: cp->par[1] = cp->par[0]+1; /* cmd resp vector */
661: cp->par[3] = cp->par[0]+2; /* unsol intr vector */
662: cp->par[4] = 15; /* max ports, no longer used */
663: cp->par[5] = 0; /* set 1st port number */
664: (void) vcmd(vx, (caddr_t)&cp->cmd);
665: if (!wait)
666: return;
667: for (j = 0; cp->cmd == VXC_LIDENT && j < 4000000; j++)
668: ;
669: if (j >= 4000000)
670: printf("vx%d: didn't respond to LIDENT\n", vx);
671:
672: /* calculate address of response buffer */
673: resp = (char *)addr + (addr->v_rspoff&0x3fff);
674: if (resp[0] != 0 && (resp[0]&0177) != 3) {
675: vrelease(vs, cp); /* init failed */
676: return;
677: }
678: vs->vs_loport = cp->par[5];
679: vs->vs_hiport = cp->par[7];
680: printf("vx%d: %s%s, ports %d-%d\n", vx,
681: (vs->vs_vers == VXV_NEW) ? "" : "old ", typestring,
682: vs->vs_loport, vs->vs_hiport);
683: vrelease(vs, cp);
684: vs->vs_nbr = vx; /* assign board number */
685: }
686:
687: /*
688: * Obtain a command buffer
689: */
690: struct vxcmd *
691: vobtain(vs)
692: register struct vx_softc *vs;
693: {
694: register struct vxcmd *p;
695: int s;
696:
697: s = spl8();
698: p = vs->vs_avail;
699: if (p == (struct vxcmd *)0) {
700: #ifdef VX_DEBUG
701: if (vxintr4&VXNOBUF)
702: vxintr4 &= ~VXNOBUF;
703: #endif
704: printf("vx%d: no buffers\n", vs - vx_softc);
705: vxstreset(vs - vx_softc);
706: splx(s);
707: return (vobtain(vs));
708: }
709: vs->vs_avail = p->c_fwd;
710: splx(s);
711: return ((struct vxcmd *)p);
712: }
713:
714: /*
715: * Release a command buffer
716: */
717: vrelease(vs, cp)
718: register struct vx_softc *vs;
719: register struct vxcmd *cp;
720: {
721: int s;
722:
723: #ifdef VX_DEBUG
724: if (vxintr4&VXNOBUF)
725: return;
726: #endif
727: s = spl8();
728: cp->c_fwd = vs->vs_avail;
729: vs->vs_avail = cp;
730: splx(s);
731: }
732:
733: struct vxcmd *
734: nextcmd(vs)
735: register struct vx_softc *vs;
736: {
737: register struct vxcmd *cp;
738: int s;
739:
740: s = spl8();
741: cp = vs->vs_build;
742: vs->vs_build = (struct vxcmd *)0;
743: splx(s);
744: return (cp);
745: }
746:
747: /*
748: * Assemble transmits into a multiple command;
749: * up to 8 transmits to 8 lines can be assembled together
750: * (on PVIOCX only).
751: */
752: vsetq(vs, line, addr, n)
753: register struct vx_softc *vs;
754: caddr_t addr;
755: {
756: register struct vxcmd *cp;
757: register struct vxmit *mp;
758:
759: /*
760: * Grab a new command buffer or append
761: * to the current one being built.
762: */
763: cp = vs->vs_build;
764: if (cp == (struct vxcmd *)0) {
765: cp = vobtain(vs);
766: vs->vs_build = cp;
767: cp->cmd = VXC_XMITDTA;
768: } else {
769: if ((cp->cmd & 07) == 07 || vs->vs_vers == VXV_NEW) {
770: printf("vx%d: setq overflow\n", vs-vx_softc);
771: vxstreset((int)vs->vs_nbr);
772: return;
773: }
774: cp->cmd++;
775: }
776: /*
777: * Select the next vxmit buffer and copy the
778: * characters into the buffer (if there's room
779: * and the device supports ``immediate mode'',
780: * or store an indirect pointer to the data.
781: */
782: mp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizeof (struct vxmit));
783: mp->bcount = n-1;
784: mp->line = line;
785: if (vs->vs_vers == VXV_NEW && n <= sizeof (mp->ostream)) {
786: cp->cmd = VXC_XMITIMM;
787: bcopy(addr, mp->ostream, (unsigned)n);
788: } else {
789: /* get system address of clist block */
790: addr = (caddr_t)vtoph((struct proc *)0, (unsigned)addr);
791: bcopy((caddr_t)&addr, mp->ostream, sizeof (addr));
792: }
793: /*
794: * We send the data immediately if a VIOCX,
795: * the command buffer is full, or if we've nothing
796: * currently outstanding. If we don't send it,
797: * set a timeout to force the data to be sent soon.
798: */
799: if (vs->vs_vers == VXV_NEW || (cp->cmd & 07) == 7 ||
800: vs->vs_xmtcnt == 0) {
801: vs->vs_xmtcnt++;
802: (void) vcmd((int)vs->vs_nbr, (char *)&cp->cmd);
803: vs->vs_build = 0;
804: } else
805: timeout(vxforce, (caddr_t)vs, 3);
806: }
807:
808: /*
809: * Write a command out to the VIOC
810: */
811: vcmd(vx, cmdad)
812: register int vx;
813: register caddr_t cmdad;
814: {
815: register struct vcmds *cp;
816: register struct vx_softc *vs;
817: int s;
818:
819: s = spl8();
820: vs = &vx_softc[vx];
821: /*
822: * When the vioc is resetting, don't process
823: * anything other than VXC_LIDENT commands.
824: */
825: if (vs->vs_state == VXS_RESET && cmdad != NULL) {
826: struct vxcmd *vcp = (struct vxcmd *)(cmdad-sizeof (vcp->c_fwd));
827:
828: if (vcp->cmd != VXC_LIDENT) {
829: vrelease(vs, vcp);
830: return (0);
831: }
832: }
833: cp = &vs->vs_cmds;
834: if (cmdad != (caddr_t)0) {
835: cp->cmdbuf[cp->v_fill] = cmdad;
836: if (++cp->v_fill >= VC_CMDBUFL)
837: cp->v_fill = 0;
838: if (cp->v_fill == cp->v_empty) {
839: printf("vx%d: cmd q overflow\n", vx);
840: vxstreset(vx);
841: splx(s);
842: return (0);
843: }
844: cp->v_cmdsem++;
845: }
846: if (cp->v_cmdsem && cp->v_curcnt < vs->vs_maxcmd) {
847: cp->v_cmdsem--;
848: cp->v_curcnt++;
849: vinthandl(vx, ((V_BSY|CMDquals) << 8)|V_INTR);
850: }
851: splx(s);
852: return (1);
853: }
854:
855: /*
856: * VIOC acknowledge interrupt. The VIOC has received the new
857: * command. If no errors, the new command becomes one of 16 (max)
858: * current commands being executed.
859: */
860: vackint(vx)
861: register vx;
862: {
863: register struct vxdevice *vp;
864: register struct vcmds *cp;
865: struct vx_softc *vs;
866: int s;
867:
868: scope_out(5);
869: vs = &vx_softc[vx];
870: if (vs->vs_type) /* Its a BOP */
871: return;
872: s = spl8();
873: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
874: cp = &vs->vs_cmds;
875: if (vp->v_vcid&V_ERR) {
876: register char *resp;
877: register i;
878:
879: printf("vx%d: ackint error type %x v_dcd %x\n", vx,
880: vp->v_vcid & 07, vp->v_dcd & 0xff);
881: resp = (char *)vs->vs_mricmd;
882: for (i = 0; i < 16; i++)
883: printf("%x ", resp[i]&0xff);
884: printf("\n");
885: splx(s);
886: vxstreset(vx);
887: return;
888: }
889: if ((vp->v_hdwre&017) == CMDquals) {
890: #ifdef VX_DEBUG
891: if (vxintr4 & VXERR4) { /* causes VIOC INTR ERR 4 */
892: struct vxcmd *cp1, *cp0;
893:
894: cp0 = (struct vxcmd *)
895: ((caddr_t)cp->cmdbuf[cp->v_empty]-sizeof (cp0->c_fwd));
896: if (cp0->cmd == VXC_XMITDTA || cp0->cmd == VXC_XMITIMM) {
897: cp1 = vobtain(vs);
898: *cp1 = *cp0;
899: vxintr4 &= ~VXERR4;
900: (void) vcmd(vx, &cp1->cmd);
901: }
902: }
903: #endif
904: cp->v_curcmd[vp->v_vcid & VCMDLEN-1] = cp->cmdbuf[cp->v_empty];
905: if (++cp->v_empty >= VC_CMDBUFL)
906: cp->v_empty = 0;
907: }
908: if (++cp->v_itrempt >= VC_IQLEN)
909: cp->v_itrempt = 0;
910: vintempt(vx);
911: splx(s);
912: (void) vcmd(vx, (caddr_t)0); /* queue next cmd, if any */
913: }
914:
915: /*
916: * Command Response interrupt. The Vioc has completed
917: * a command. The command may now be returned to
918: * the appropriate device driver.
919: */
920: vcmdrsp(vx)
921: register vx;
922: {
923: register struct vxdevice *vp;
924: register struct vcmds *cp;
925: register caddr_t cmd;
926: register struct vx_softc *vs;
927: register char *resp;
928: register k;
929: register int s;
930:
931: scope_out(6);
932: vs = &vx_softc[vx];
933: if (vs->vs_type) { /* Its a BOP */
934: printf("vx%d: vcmdrsp interrupt\n", vx);
935: return;
936: }
937: s = spl8();
938: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
939: cp = &vs->vs_cmds;
940: resp = (char *)vp + (vp->v_rspoff&0x7fff);
941: if (((k = resp[1])&V_UNBSY) == 0) {
942: printf("vx%d: cmdresp debug\n", vx);
943: splx(s);
944: vxstreset(vx);
945: return;
946: }
947: k &= VCMDLEN-1;
948: cmd = cp->v_curcmd[k];
949: cp->v_curcmd[k] = (caddr_t)0;
950: cp->v_curcnt--;
951: k = *((short *)&resp[4]); /* cmd operation code */
952: if ((k&0xff00) == VXC_LIDENT) /* want hiport number */
953: for (k = 0; k < VRESPLEN; k++)
954: cmd[k] = resp[k+4];
955: resp[1] = 0;
956: vxxint(vx, (struct vxcmd *)cmd);
957: if (vs->vs_state == VXS_READY)
958: vinthandl(vx, ((V_BSY|RSPquals) << 8)|V_INTR);
959: splx(s);
960: }
961:
962: /*
963: * Unsolicited interrupt.
964: */
965: vunsol(vx)
966: register vx;
967: {
968: register struct vxdevice *vp;
969: struct vx_softc *vs;
970: int s;
971:
972: scope_out(1);
973: vs = &vx_softc[vx];
974: if (vs->vs_type) { /* Its a BOP */
975: printf("vx%d: vunsol from BOP\n", vx);
976: return;
977: }
978: s = spl8();
979: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
980: if (vp->v_uqual&V_UNBSY) {
981: vxrint(vx);
982: vinthandl(vx, ((V_BSY|UNSquals) << 8)|V_INTR);
983: #ifdef notdef
984: } else {
985: printf("vx%d: unsolicited interrupt error\n", vx);
986: splx(s);
987: vxstreset(vx);
988: #endif
989: }
990: splx(s);
991: }
992:
993: /*
994: * Enqueue an interrupt.
995: */
996: vinthandl(vx, item)
997: register int vx;
998: register item;
999: {
1000: register struct vcmds *cp;
1001: int empty;
1002:
1003: cp = &vx_softc[vx].vs_cmds;
1004: empty = (cp->v_itrfill == cp->v_itrempt);
1005: cp->v_itrqueu[cp->v_itrfill] = item;
1006: if (++cp->v_itrfill >= VC_IQLEN)
1007: cp->v_itrfill = 0;
1008: if (cp->v_itrfill == cp->v_itrempt) {
1009: printf("vx%d: interrupt q overflow\n", vx);
1010: vxstreset(vx);
1011: } else if (empty)
1012: vintempt(vx);
1013: }
1014:
1015: vintempt(vx)
1016: register int vx;
1017: {
1018: register struct vcmds *cp;
1019: register struct vxdevice *vp;
1020: register short item;
1021: register short *intr;
1022:
1023: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
1024: if (vp->v_vioc&V_BSY)
1025: return;
1026: cp = &vx_softc[vx].vs_cmds;
1027: if (cp->v_itrempt == cp->v_itrfill)
1028: return;
1029: item = cp->v_itrqueu[cp->v_itrempt];
1030: intr = (short *)&vp->v_vioc;
1031: switch ((item >> 8)&03) {
1032:
1033: case CMDquals: { /* command */
1034: int phys;
1035:
1036: if (cp->v_empty == cp->v_fill || vp->v_vcbsy&V_BSY)
1037: break;
1038: vx_softc[vx].vs_mricmd = (caddr_t)cp->cmdbuf[cp->v_empty];
1039: phys = vtoph((struct proc *)0,
1040: (unsigned)cp->cmdbuf[cp->v_empty]);
1041: vp->v_vcp[0] = ((short *)&phys)[0];
1042: vp->v_vcp[1] = ((short *)&phys)[1];
1043: vp->v_vcbsy = V_BSY;
1044: *intr = item;
1045: scope_out(4);
1046: break;
1047: }
1048:
1049: case RSPquals: /* command response */
1050: *intr = item;
1051: scope_out(7);
1052: break;
1053:
1054: case UNSquals: /* unsolicited interrupt */
1055: vp->v_uqual = 0;
1056: *intr = item;
1057: scope_out(2);
1058: break;
1059: }
1060: }
1061:
1062: /*
1063: * Start a reset on a vioc after error (hopefully)
1064: */
1065: vxstreset(vx)
1066: register vx;
1067: {
1068: register struct vx_softc *vs;
1069: register struct vxdevice *vp;
1070: register struct vxcmd *cp;
1071: register int j;
1072: extern int vxinreset();
1073: int s;
1074:
1075: s = spl8() ;
1076: vs = &vx_softc[vx];
1077: if (vs->vs_state == VXS_RESET) { /* avoid recursion */
1078: splx(s);
1079: return;
1080: }
1081: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
1082: /*
1083: * Zero out the vioc structures, mark the vioc as being
1084: * reset, reinitialize the free command list, reset the vioc
1085: * and start a timer to check on the progress of the reset.
1086: */
1087: bzero((caddr_t)vs, (unsigned)sizeof (*vs));
1088:
1089: /*
1090: * Setting VXS_RESET prevents others from issuing
1091: * commands while allowing currently queued commands to
1092: * be passed to the VIOC.
1093: */
1094: vs->vs_state = VXS_RESET;
1095: /* init all cmd buffers */
1096: for (j = 0; j < NVCXBUFS; j++) {
1097: cp = &vs->vs_lst[j];
1098: cp->c_fwd = &vs->vs_lst[j+1];
1099: }
1100: vs->vs_avail = &vs->vs_lst[0];
1101: cp->c_fwd = (struct vxcmd *)0;
1102: printf("vx%d: reset...", vx);
1103: vp->v_fault = 0;
1104: vp->v_vioc = V_BSY;
1105: vp->v_hdwre = V_RESET; /* generate reset interrupt */
1106: timeout(vxinreset, (caddr_t)vx, hz*5);
1107: splx(s);
1108: }
1109:
1110: /* continue processing a reset on a vioc after an error (hopefully) */
1111: vxinreset(vx)
1112: int vx;
1113: {
1114: register struct vxdevice *vp;
1115: int s = spl8();
1116:
1117: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
1118: /*
1119: * See if the vioc has reset.
1120: */
1121: if (vp->v_fault != VXF_READY) {
1122: printf("failed\n");
1123: splx(s);
1124: return;
1125: }
1126: /*
1127: * Send a LIDENT to the vioc and mess with carrier flags
1128: * on parallel printer ports.
1129: */
1130: vxinit(vx, 0);
1131: splx(s);
1132: }
1133:
1134: /*
1135: * Finish the reset on the vioc after an error (hopefully).
1136: *
1137: * Restore modem control, parameters and restart output.
1138: * Since the vioc can handle no more then 24 commands at a time
1139: * and we could generate as many as 48 commands, we must do this in
1140: * phases, issuing no more then 16 commands at a time.
1141: */
1142: vxfnreset(vx, cp)
1143: register int vx;
1144: register struct vxcmd *cp;
1145: {
1146: register struct vx_softc *vs;
1147: register struct vxdevice *vp ;
1148: register struct tty *tp, *tp0;
1149: register int i;
1150: #ifdef notdef
1151: register int on;
1152: #endif
1153: extern int vxrestart();
1154: int s = spl8();
1155:
1156: vs = &vx_softc[vx];
1157: vs->vs_loport = cp->par[5];
1158: vs->vs_hiport = cp->par[7];
1159: vrelease(vs, cp);
1160: vs->vs_nbr = vx; /* assign VIOC-X board number */
1161: vs->vs_state = VXS_READY;
1162:
1163: vp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
1164: vp->v_vcid = 0;
1165:
1166: /*
1167: * Restore modem information and control.
1168: */
1169: tp0 = &vx_tty[vx*16];
1170: for (i = vs->vs_loport; i <= vs->vs_hiport; i++) {
1171: tp = tp0 + i;
1172: if (tp->t_state&(TS_ISOPEN|TS_WOPEN)) {
1173: tp->t_state &= ~TS_CARR_ON;
1174: vcmodem(tp->t_dev, VMOD_ON);
1175: if (tp->t_state&TS_CARR_ON)
1176: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1177: else if (tp->t_state & TS_ISOPEN)
1178: (void)(*linesw[tp->t_line].l_modem)(tp, 0);
1179: }
1180: #ifdef notdef
1181: /*
1182: * If carrier has changed while we were resetting,
1183: * take appropriate action.
1184: */
1185: on = vp->v_dcd & 1<<i;
1186: if (on && (tp->t_state&TS_CARR_ON) == 0)
1187: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1188: else if (!on && tp->t_state&TS_CARR_ON)
1189: (void)(*linesw[tp->t_line].l_modem)(tp, 0);
1190: #endif
1191: }
1192: vs->vs_state = VXS_RESET;
1193: timeout(vxrestart, (caddr_t)vx, hz);
1194: splx(s);
1195: }
1196:
1197: /*
1198: * Restore a particular aspect of the VIOC.
1199: */
1200: vxrestart(vx)
1201: int vx;
1202: {
1203: register struct tty *tp, *tp0;
1204: register struct vx_softc *vs;
1205: register int i, count;
1206: int s = spl8();
1207:
1208: count = vx >> 8;
1209: vx &= 0xff;
1210: vs = &vx_softc[vx];
1211: vs->vs_state = VXS_READY;
1212: tp0 = &vx_tty[vx*16];
1213: for (i = vs->vs_loport; i <= vs->vs_hiport; i++) {
1214: tp = tp0 + i;
1215: if (count != 0) {
1216: tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
1217: if (tp->t_state&(TS_ISOPEN|TS_WOPEN))
1218: vxstart(tp); /* restart pending output */
1219: } else {
1220: if (tp->t_state&(TS_WOPEN|TS_ISOPEN))
1221: vxcparam(tp->t_dev, 0);
1222: }
1223: }
1224: if (count == 0) {
1225: vs->vs_state = VXS_RESET;
1226: timeout(vxrestart, (caddr_t)(vx + 1*256), hz);
1227: } else
1228: printf("done\n");
1229: splx(s);
1230: }
1231:
1232: vxreset(dev)
1233: dev_t dev;
1234: {
1235:
1236: vxstreset((int)VXUNIT(minor(dev))); /* completes asynchronously */
1237: }
1238:
1239: #ifdef notdef
1240: vxfreset(vx)
1241: register int vx;
1242: {
1243: struct vba_device *vi;
1244:
1245: if ((unsigned)vx > NVX || (vi = vxinfo[vx]) == 0 || vi->ui_addr == 0)
1246: return (ENODEV);
1247: vx_softc[vx].vs_state = VXS_READY;
1248: vxstreset(vx);
1249: return (0); /* completes asynchronously */
1250: }
1251: #endif
1252:
1253: vcmodem(dev, flag)
1254: dev_t dev;
1255: {
1256: struct tty *tp;
1257: register struct vxcmd *cp;
1258: register struct vx_softc *vs;
1259: register struct vxdevice *kp;
1260: register port;
1261: int unit;
1262:
1263: unit = minor(dev);
1264: tp = &vx_tty[unit];
1265: vs = (struct vx_softc *)tp->t_addr;
1266: if (vs->vs_state != VXS_READY)
1267: return;
1268: cp = vobtain(vs);
1269: kp = (struct vxdevice *)((struct vba_device *)vxinfo[vs->vs_nbr])->ui_addr;
1270:
1271: port = unit & 017;
1272: /*
1273: * Issue MODEM command
1274: */
1275: cp->cmd = VXC_MDMCTL;
1276: if (flag == VMOD_ON) {
1277: if (vs->vs_softCAR & (1 << port))
1278: cp->par[0] = V_MANUAL | V_DTR_ON | V_RTS;
1279: else
1280: cp->par[0] = V_AUTO | V_DTR_ON | V_RTS;
1281: } else
1282: cp->par[0] = V_DTR_OFF;
1283: cp->par[1] = port;
1284: (void) vcmd((int)vs->vs_nbr, (caddr_t)&cp->cmd);
1285: if (vs->vs_softCAR & (1 << port))
1286: kp->v_dcd |= (1 << port);
1287: if ((kp->v_dcd | vs->vs_softCAR) & (1 << port) && flag == VMOD_ON)
1288: tp->t_state |= TS_CARR_ON;
1289: }
1290:
1291: /*
1292: * VCMINTR called when an unsolicited interrup occurs signaling
1293: * some change of modem control state.
1294: */
1295: vcmintr(vx)
1296: register vx;
1297: {
1298: register struct vxdevice *kp;
1299: register struct tty *tp;
1300: register port;
1301: register struct vx_softc *vs;
1302:
1303: kp = (struct vxdevice *)((struct vba_device *)vxinfo[vx])->ui_addr;
1304: port = kp->v_usdata[0] & 017;
1305: tp = &vx_tty[vx*16+port];
1306: vs = &vx_softc[vx];
1307:
1308: if (kp->v_ustat & DCD_ON)
1309: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1310: else if ((kp->v_ustat & DCD_OFF) &&
1311: ((vs->vs_softCAR & (1 << port))) == 0 &&
1312: (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
1313: register struct vcmds *cp;
1314: register struct vxcmd *cmdp;
1315:
1316: /* clear all pending transmits */
1317: if (tp->t_state&(TS_BUSY|TS_FLUSH) &&
1318: vs->vs_vers == VXV_NEW) {
1319: int i, cmdfound = 0;
1320:
1321: cp = &vs->vs_cmds;
1322: for (i = cp->v_empty; i != cp->v_fill; ) {
1323: cmdp = (struct vxcmd *)((long *)cp->cmdbuf[i]-1);
1324: if ((cmdp->cmd == VXC_XMITDTA ||
1325: cmdp->cmd == VXC_XMITIMM) &&
1326: ((struct vxmit *)cmdp->par)->line == port) {
1327: cmdfound++;
1328: cmdp->cmd = VXC_FDTATOX;
1329: cmdp->par[1] = port;
1330: }
1331: if (++i >= VC_CMDBUFL)
1332: i = 0;
1333: }
1334: if (cmdfound)
1335: tp->t_state &= ~(TS_BUSY|TS_FLUSH);
1336: /* cmd is already in vioc, have to flush it */
1337: else {
1338: cmdp = vobtain(vs);
1339: cmdp->cmd = VXC_FDTATOX;
1340: cmdp->par[1] = port;
1341: (void) vcmd(vx, (caddr_t)&cmdp->cmd);
1342: }
1343: }
1344: } else if ((kp->v_ustat&BRK_CHR) && (tp->t_state&TS_ISOPEN)) {
1345: (*linesw[tp->t_line].l_rint)((tp->t_flags & RAW) ?
1346: 0 : tp->t_intrc, tp);
1347: return;
1348: }
1349: }
1350: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.