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