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