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 and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)mp.c 7.11 (Berkeley) 04/03/90 21 */ 22 23 #include "mp.h" 24 #if NMP > 0 25 /* 26 * Multi Protocol Communications Controller (MPCC). 27 * Asynchronous Terminal Protocol Support. 28 */ 29 #include "param.h" 30 #include "ioctl.h" 31 #include "tty.h" 32 #include "user.h" 33 #include "map.h" 34 #include "buf.h" 35 #include "conf.h" 36 #include "file.h" 37 #include "errno.h" 38 #include "syslog.h" 39 #include "vmmac.h" 40 #include "kernel.h" 41 #include "clist.h" 42 43 #include "machine/pte.h" 44 #include "machine/mtpr.h" 45 46 #include "../tahoevba/vbavar.h" 47 #include "../tahoevba/mpreg.h" 48 49 #define MPCHUNK 16 50 #define MPPORT(n) ((n) & 0xf) 51 #define MPUNIT(n) ((n) >> 4) 52 53 /* 54 * Driver information for auto-configuration stuff. 55 */ 56 int mpprobe(), mpattach(), mpintr(); 57 struct vba_device *mpinfo[NMP]; 58 long mpstd[] = { 0 }; 59 struct vba_driver mpdriver = 60 { mpprobe, 0, mpattach, 0, mpstd, "mp", mpinfo }; 61 62 int mpstart(); 63 int mpparam(); 64 struct mpevent *mpparam2(); 65 struct mpevent *mp_getevent(); 66 67 /* 68 * The following structure is needed to deal with mpcc's convoluted 69 * method for locating it's mblok structures (hold your stomach). 70 * When an mpcc is reset at boot time it searches host memory 71 * looking for a string that says ``ThIs Is MpCc''. The mpcc 72 * then reads the structure to locate the pointer to it's mblok 73 * structure (you can wretch now). 74 */ 75 struct mpbogus { 76 char s[12]; /* `ThIs Is MpCc'' */ 77 u_char status; 78 u_char unused; 79 u_short magic; 80 struct mblok *mb; 81 struct mblok *mbloks[NMP]; /* can support at most 16 mpcc's */ 82 } mpbogus = { 'T','h','I','s',' ','I','s',' ','M','p','C','c' }; 83 84 /* 85 * Software state per unit. 86 */ 87 struct mpsoftc { 88 u_int ms_ivec; /* interrupt vector */ 89 u_int ms_softCAR; /* software carrier for async */ 90 struct mblok *ms_mb; /* mpcc status area */ 91 struct vb_buf ms_buf; /* vba resources for ms_mb */ 92 struct hxmtl ms_hxl[MPMAXPORT];/* host transmit list */ 93 struct asyncparam ms_async[MPMAXPORT][MPINSET];/* async structs */ 94 char ms_cbuf[MPMAXPORT][MPOUTSET][CBSIZE];/* input character buffers */ 95 } mp_softc[NMP]; 96 97 struct speedtab 98 mpspeedtab[] = { 99 9600, M9600, /* baud rate = 9600 */ 100 4800, M4800, /* baud rate = 4800 */ 101 2400, M2400, /* baud rate = 2400 */ 102 1800, M1800, /* baud rate = 1800 */ 103 1200, M1200, /* baud rate = 1200 */ 104 600, M600, /* baud rate = 600 */ 105 300, M300, /* baud rate = 300 */ 106 200, M200, /* baud rate = 200 */ 107 150, M150, /* baud rate = 150 */ 108 134, M134_5, /* baud rate = 134.5 */ 109 110, M110, /* baud rate = 110 */ 110 75, M75, /* baud rate = 75 */ 111 50, M50, /* baud rate = 50 */ 112 0, M0, /* baud rate = 0 */ 113 2000, M2000, /* baud rate = 2000 */ 114 3600, M3600, /* baud rate = 3600 */ 115 7200, M7200, /* baud rate = 7200 */ 116 19200, M19200, /* baud rate = 19,200 */ 117 24000, M24000, /* baud rate = 24,000 */ 118 28400, M28400, /* baud rate = 28,400 */ 119 37800, M37800, /* baud rate = 37,800 */ 120 40300, M40300, /* baud rate = 40,300 */ 121 48000, M48000, /* baud rate = 48,000 */ 122 52000, M52000, /* baud rate = 52,000 */ 123 56800, M56800, /* baud rate = 56,800 */ 124 EXTA, MEXTA, /* baud rate = Ext A */ 125 EXTB, MEXTB, /* baud rate = Ext B */ 126 -1, -1, 127 }; 128 129 struct tty mp_tty[NMP*MPCHUNK]; 130 #ifndef lint 131 int nmp = NMP*MPCHUNK; 132 #endif 133 134 int ttrstrt(); 135 136 mpprobe(reg, vi) 137 caddr_t reg; 138 struct vba_device *vi; 139 { 140 register int br, cvec; 141 register struct mpsoftc *ms; 142 143 #ifdef lint 144 br = 0; cvec = br; br = cvec; 145 mpintr(0); 146 mpdlintr(0); 147 #endif 148 if (badaddr(reg, 2)) 149 return (0); 150 ms = &mp_softc[vi->ui_unit]; 151 /* 152 * Allocate page tables and mblok 153 * structure (mblok in non-cached memory). 154 */ 155 if (vbainit(&ms->ms_buf, sizeof (struct mblok), VB_32BIT) == 0) { 156 printf("mp%d: vbainit failed\n", vi->ui_unit); 157 return (0); 158 } 159 ms->ms_mb = (struct mblok *)ms->ms_buf.vb_rawbuf; 160 ms->ms_ivec = MPINTRBASE + 2*vi->ui_unit; /* XXX */ 161 br = 0x14, cvec = ms->ms_ivec; /* XXX */ 162 return (sizeof (*reg)); 163 } 164 165 mpattach(vi) 166 register struct vba_device *vi; 167 { 168 register struct mpsoftc *ms = &mp_softc[vi->ui_unit]; 169 170 ms->ms_softCAR = vi->ui_flags; 171 /* 172 * Setup pointer to mblok, initialize bogus 173 * status block used by mpcc to locate the pointer 174 * and then poke the mpcc to get it to search host 175 * memory to find mblok pointer. 176 */ 177 mpbogus.mbloks[vi->ui_unit] = (struct mblok *)ms->ms_buf.vb_physbuf; 178 *(short *)vi->ui_addr = 0x100; /* magic */ 179 } 180 181 /* 182 * Open an mpcc port. 183 */ 184 /* ARGSUSED */ 185 mpopen(dev, mode) 186 dev_t dev; 187 { 188 register struct tty *tp; 189 register struct mpsoftc *ms; 190 int error, s, port, unit, mpu; 191 struct vba_device *vi; 192 struct mpport *mp; 193 struct mpevent *ev; 194 195 unit = minor(dev); 196 mpu = MPUNIT(unit); 197 if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 198 return (ENXIO); 199 tp = &mp_tty[unit]; 200 if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 201 return (EBUSY); 202 ms = &mp_softc[mpu]; 203 port = MPPORT(unit); 204 if (ms->ms_mb->mb_proto[port] != MPPROTO_ASYNC || 205 ms->ms_mb->mb_status != MP_OPOPEN) 206 return (ENXIO); 207 mp = &ms->ms_mb->mb_port[port]; /* host mpcc struct */ 208 s = spl8(); 209 /* 210 * serialize open and close events 211 */ 212 while ((mp->mp_flags & MP_PROGRESS) || ((tp->t_state & TS_WOPEN) && 213 !(mode&O_NONBLOCK) && !(tp->t_cflag&CLOCAL))) 214 if (error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, 215 ttopen, 0)) { 216 splx(s); 217 return (error); 218 } 219 restart: 220 tp->t_state |= TS_WOPEN; 221 tp->t_addr = (caddr_t)ms; 222 tp->t_oproc = mpstart; 223 tp->t_param = mpparam; 224 tp->t_dev = dev; 225 if ((tp->t_state & TS_ISOPEN) == 0) { 226 ttychars(tp); 227 if (tp->t_ispeed == 0) { 228 tp->t_ispeed = TTYDEF_SPEED; 229 tp->t_ospeed = TTYDEF_SPEED; 230 tp->t_iflag = TTYDEF_IFLAG; 231 tp->t_oflag = TTYDEF_OFLAG; 232 tp->t_lflag = TTYDEF_LFLAG; 233 tp->t_cflag = TTYDEF_CFLAG; 234 } 235 /* 236 * Initialize port state: init MPCC interface 237 * structures for port and setup modem control. 238 */ 239 error = mpportinit(ms, mp, port); 240 if (error) 241 goto bad; 242 ev = mpparam2(tp, &tp->t_termios); 243 if (ev == 0) { 244 error = ENOBUFS; 245 goto bad; 246 } 247 mp->mp_flags |= MP_PROGRESS; 248 mpcmd(ev, EVCMD_OPEN, 0, ms->ms_mb, port); 249 /* 250 * wait for port to start 251 */ 252 while (mp->mp_proto != MPPROTO_ASYNC) 253 if (error = tsleep((caddr_t)&tp->t_canq, 254 TTIPRI | PCATCH, ttopen, 0)) 255 goto bad; 256 ttsetwater(tp); 257 mp->mp_flags &= ~MP_PROGRESS; 258 } 259 while ((mode&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 260 (tp->t_state & TS_CARR_ON) == 0) { 261 if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 262 ttopen, 0)) 263 goto bad; 264 /* 265 * a mpclose() might have disabled port. if so restart 266 */ 267 if (mp->mp_proto != MPPROTO_ASYNC) 268 goto restart; 269 tp->t_state |= TS_WOPEN; 270 } 271 error = (*linesw[tp->t_line].l_open)(dev,tp); 272 done: 273 splx(s); 274 /* 275 * wakeup those processes waiting for the open to complete 276 */ 277 wakeup((caddr_t)&tp->t_canq); 278 return (error); 279 bad: 280 tp->t_state &= ~TS_WOPEN; 281 goto done; 282 } 283 284 /* 285 * Close an mpcc port. 286 */ 287 /* ARGSUSED */ 288 mpclose(dev, flag) 289 dev_t dev; 290 { 291 register struct tty *tp; 292 register struct mpport *mp; 293 register struct mpevent *ev; 294 int s, port, unit, error = 0; 295 struct mblok *mb; 296 297 unit = minor(dev); 298 tp = &mp_tty[unit]; 299 port = MPPORT(unit); 300 mb = mp_softc[MPUNIT(unit)].ms_mb; 301 mp = &mb->mb_port[port]; 302 s = spl8(); 303 if (mp->mp_flags & MP_PROGRESS) { 304 if (mp->mp_flags & MP_REMBSY) { 305 mp->mp_flags &= ~MP_REMBSY; 306 splx(s); 307 return (0); 308 } 309 while (mp->mp_flags & MP_PROGRESS) 310 if (error = tsleep((caddr_t)&tp->t_canq, 311 TTIPRI | PCATCH, ttclos, 0)) { 312 splx(s); 313 return (error); 314 } 315 } 316 mp->mp_flags |= MP_PROGRESS; 317 (*linesw[tp->t_line].l_close)(tp); 318 ev = mp_getevent(mp, unit, 1); 319 if (ev == 0) { 320 error = ENOBUFS; 321 mp->mp_flags &= ~MP_PROGRESS; 322 goto out; 323 } 324 if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 325 mpmodem(unit, MMOD_OFF); 326 else 327 mpmodem(unit, MMOD_ON); 328 mpcmd(ev, EVCMD_CLOSE, 0, mb, port); 329 error = ttyclose(tp); 330 out: 331 if (mp->mp_flags & MP_REMBSY) 332 mpclean(mb, port); 333 else 334 while (mp->mp_flags & MP_PROGRESS && error == 0) 335 error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, 336 ttclos, 0); 337 splx(s); 338 return (error); 339 } 340 341 /* 342 * Read from an mpcc port. 343 */ 344 mpread(dev, uio, flag) 345 dev_t dev; 346 struct uio *uio; 347 { 348 struct tty *tp; 349 350 tp = &mp_tty[minor(dev)]; 351 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 352 } 353 354 /* 355 * Write to an mpcc port. 356 */ 357 mpwrite(dev, uio, flag) 358 dev_t dev; 359 struct uio *uio; 360 { 361 struct tty *tp; 362 363 tp = &mp_tty[minor(dev)]; 364 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 365 } 366 367 /* 368 * Ioctl for a mpcc port 369 */ 370 mpioctl(dev, cmd, data, flag) 371 dev_t dev; 372 caddr_t data; 373 { 374 register struct tty *tp; 375 register struct mpsoftc *ms; 376 register struct mpport *mp; 377 register struct mpevent *ev; 378 int s, port, error, unit; 379 struct mblok *mb; 380 381 unit = minor(dev); 382 tp = &mp_tty[unit]; 383 ms = &mp_softc[MPUNIT(unit)]; 384 mb = ms->ms_mb; 385 port = MPPORT(unit); 386 mp = &mb->mb_port[port]; 387 if (mp->mp_proto != MPPROTO_ASYNC) 388 return(ENXIO); 389 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 390 if (error >= 0) 391 return (error); 392 error = ttioctl(tp, cmd, data, flag); 393 if (error >= 0) 394 return (error); 395 switch (cmd) { 396 case TIOCSBRK: /* send break */ 397 case TIOCCBRK: /* clear break */ 398 s = spl8(); 399 while (mp->mp_flags & MP_IOCTL) { 400 if (error = tsleep((caddr_t)&tp->t_canq, 401 TTIPRI | PCATCH, ttyout, 0)) { 402 splx(s); 403 return (error); 404 } 405 if (mp->mp_proto != MPPROTO_ASYNC) { 406 splx(s); 407 return (ENXIO); 408 } 409 } 410 ev = mp_getevent(mp, unit, 0); 411 if (ev) { 412 mp->mp_flags |= MP_IOCTL; 413 mpcmd(ev, EVCMD_IOCTL, 414 (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port); 415 } else 416 error = ENOBUFS; 417 splx(s); 418 break; 419 case TIOCSDTR: /* set dtr control line */ 420 break; 421 case TIOCCDTR: /* clear dtr control line */ 422 break; 423 default: 424 error = ENOTTY; 425 break; 426 } 427 return (error); 428 } 429 430 mpparam(tp, t) 431 struct tty *tp; 432 struct termios *t; 433 { 434 register struct mpevent *ev; 435 int unit = minor(tp->t_dev); 436 struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 437 struct mblok *mb = ms->ms_mb; 438 439 ev = mpparam2(tp, t); 440 if (ev == 0) 441 return (ENOBUFS); 442 mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit)); 443 return (0); 444 } 445 446 struct mpevent * 447 mpparam2(tp, t) 448 register struct tty *tp; 449 struct termios *t; 450 { 451 register struct mpevent *ev; 452 register struct mpport *mp; 453 int unit = minor(tp->t_dev); 454 struct mblok *mb; 455 struct mpsoftc *ms; 456 register struct asyncparam *asp; 457 int port, speedcode; 458 459 ms = &mp_softc[MPUNIT(unit)]; 460 mb = ms->ms_mb; 461 port = MPPORT(unit); 462 mp = &mb->mb_port[port]; 463 ev = mp_getevent(mp, unit, 0); /* XXX */ 464 speedcode = ttspeedtab(t->c_ospeed, mpspeedtab); 465 if (ev == 0 || speedcode < 0) { 466 printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n", 467 MPUNIT(unit), port, ev, speedcode, t->c_ospeed); 468 return (0); /* XXX */ 469 } 470 /* YUCK */ 471 asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 472 asp->ap_xon = t->c_cc[VSTART]; 473 asp->ap_xoff = t->c_cc[VSTOP]; 474 if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) || 475 (asp->ap_xoff == _POSIX_VDISABLE)) 476 asp->ap_xena = MPA_DIS; 477 else 478 asp->ap_xena = MPA_ENA; 479 asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS); 480 #ifdef notnow 481 if (t->t_cflag&CSIZE) == CS8) { 482 #endif 483 asp->ap_data = MPCHAR_8; 484 asp->ap_parity = MPPAR_NONE; 485 #ifdef notnow 486 } else { 487 asp->ap_data = MPCHAR_7; 488 if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */ 489 asp->ap_parity = MPPAR_ODD; 490 else 491 asp->ap_parity = MPPAR_EVEN; 492 } 493 #endif 494 asp->ap_loop = MPA_DIS; /* disable loopback */ 495 asp->ap_rtimer = A_RCVTIM; /* default receive timer */ 496 if (t->c_ospeed == B110) 497 asp->ap_stop = MPSTOP_2; 498 else 499 asp->ap_stop = MPSTOP_1; 500 if (t->c_ospeed == 0) { 501 tp->t_state |= TS_HUPCLS; 502 setm(&asp->ap_modem, 0, DROP); 503 seti(&asp->ap_intena, A_DCD); 504 return (ev); 505 } 506 if (t->c_ospeed == EXTA || t->c_ospeed == EXTB) 507 asp->ap_baud = M19200; 508 else 509 asp->ap_baud = speedcode; 510 if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */ 511 setm(&asp->ap_modem, A_DTR, ASSERT); 512 else 513 setm(&asp->ap_modem, A_DTR, AUTO); 514 seti(&asp->ap_intena, A_DCD); 515 return(ev); 516 } 517 518 mpstart(tp) 519 register struct tty *tp; 520 { 521 register struct mpevent *ev; 522 register struct mpport *mp; 523 struct mblok *mb; 524 struct mpsoftc *ms; 525 int port, unit, xcnt, n, s, i; 526 struct hxmtl *hxp; 527 struct clist outq; 528 529 s = spl8(); 530 unit = minor(tp->t_dev); 531 ms = &mp_softc[MPUNIT(unit)]; 532 mb = ms->ms_mb; 533 port = MPPORT(unit); 534 mp = &mb->mb_port[port]; 535 hxp = &ms->ms_hxl[port]; 536 xcnt = 0; 537 outq = tp->t_outq; 538 for (i = 0; i < MPXMIT; i++) { 539 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 540 break; 541 if (outq.c_cc <= tp->t_lowat) { 542 if (tp->t_state & TS_ASLEEP) { 543 tp->t_state &= ~TS_ASLEEP; 544 wakeup((caddr_t)&tp->t_outq); 545 } 546 if (tp->t_wsel) { 547 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 548 tp->t_wsel = 0; 549 tp->t_state &= ~TS_WCOLL; 550 } 551 } 552 if (outq.c_cc == 0) 553 break; 554 /* 555 * If we're not currently busy outputting, 556 * and there is data to be output, set up 557 * port transmit structure to send to mpcc. 558 */ 559 if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */ 560 n = ndqb(&outq, 0); 561 else { 562 n = ndqb(&outq, 0200); 563 if (n == 0) { 564 if (xcnt > 0) 565 break; 566 n = getc(&outq); 567 timeout(ttrstrt, (caddr_t)tp, (n&0177)+6); 568 tp->t_state |= TS_TIMEOUT; 569 break; 570 } 571 } 572 hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf); 573 hxp->size[i] = n; 574 xcnt++; /* count of xmts to send */ 575 ndadvance(&outq, n); 576 } 577 /* 578 * If data to send, poke mpcc. 579 */ 580 if (xcnt) { 581 ev = mp_getevent(mp, unit, 0); 582 if (ev == 0) { 583 tp->t_state &= ~(TS_BUSY|TS_TIMEOUT); 584 } else { 585 tp->t_state |= TS_BUSY; 586 ev->ev_count = xcnt; 587 mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit)); 588 } 589 } 590 splx(s); 591 } 592 593 /* 594 * Advance cc bytes from q but don't free memory. 595 */ 596 ndadvance(q, cc) 597 register struct clist *q; 598 register cc; 599 { 600 register struct cblock *bp; 601 char *end; 602 int rem, s; 603 604 s = spltty(); 605 if (q->c_cc <= 0) 606 goto out; 607 while (cc>0 && q->c_cc) { 608 bp = (struct cblock *)((int)q->c_cf & ~CROUND); 609 if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 610 end = q->c_cl; 611 } else { 612 end = (char *)((int)bp + sizeof (struct cblock)); 613 } 614 rem = end - q->c_cf; 615 if (cc >= rem) { 616 cc -= rem; 617 q->c_cc -= rem; 618 q->c_cf = bp->c_next->c_info; 619 } else { 620 q->c_cc -= cc; 621 q->c_cf += cc; 622 break; 623 } 624 } 625 if (q->c_cc <= 0) { 626 q->c_cf = q->c_cl = NULL; 627 q->c_cc = 0; 628 } 629 out: 630 splx(s); 631 } 632 633 /* 634 * Stop output on a line, e.g. for ^S/^Q or output flush. 635 */ 636 /* ARGSUSED */ 637 mpstop(tp, rw) 638 register struct tty *tp; 639 int rw; 640 { 641 register struct mpport *mp; 642 register struct mpevent *ev; 643 int unit = minor(tp->t_dev); 644 int port; 645 struct mblok *mb; 646 int s; 647 648 s = spl8(); 649 if (tp->t_state & TS_BUSY) { 650 if ((tp->t_state & TS_TTSTOP) == 0) { 651 tp->t_state |= TS_FLUSH; 652 port = MPPORT(unit); 653 mb = mp_softc[MPUNIT(unit)].ms_mb; 654 mp = &mb->mb_port[port]; 655 ev = mp_getevent(mp, unit, 0); 656 if (ev == 0) { 657 splx(s); 658 return; 659 } 660 mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port); 661 } 662 } 663 splx(s); 664 } 665 666 /* 667 * Initialize an async port's MPCC state. 668 */ 669 mpportinit(ms, mp, port) 670 register struct mpsoftc *ms; 671 register struct mpport *mp; 672 int port; 673 { 674 register struct mpevent *ev; 675 register int i; 676 caddr_t ptr; 677 678 mp->mp_on = mp->mp_off = 0; 679 mp->mp_nextrcv = 0; 680 mp->mp_flags = 0; 681 ev = &mp->mp_recvq[0]; 682 for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) { 683 ev->ev_status = EVSTATUS_FREE; 684 ev->ev_cmd = 0; 685 ev->ev_opts = 0; 686 ev->ev_error = 0; 687 ev->ev_flags = 0; 688 ev->ev_count = 0; 689 ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]); 690 ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]); 691 } 692 ev = &mp->mp_sendq[0]; 693 for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) { 694 /* init so that L2 can't send any events */ 695 /* to host until open has completed */ 696 ev->ev_status = EVSTATUS_FREE; 697 ev->ev_cmd = 0; 698 ev->ev_opts = 0; 699 ev->ev_error = 0; 700 ev->ev_flags = 0; 701 ev->ev_count = 0; 702 ptr = (caddr_t) &ms->ms_cbuf[port][i][0]; 703 ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 704 ev->ev_params = (caddr_t) kvtophys(ptr); 705 } 706 return (0); 707 } 708 709 /* 710 * Send an event to an mpcc. 711 */ 712 mpcmd(ev, cmd, flags, mb, port) 713 register struct mpevent *ev; 714 struct mblok *mb; 715 { 716 int s; 717 718 s = spl8(); 719 /* move host values to inbound entry */ 720 ev->ev_cmd = cmd; 721 ev->ev_opts = flags; 722 /* show event ready for mpcc */ 723 ev->ev_status = EVSTATUS_GO; 724 mpintmpcc(mb, port); 725 splx(s); 726 } 727 728 /* 729 * Return the next available event entry for the indicated port. 730 */ 731 struct mpevent * 732 mp_getevent(mp, unit, cls_req) 733 register struct mpport *mp; 734 int unit; 735 int cls_req; 736 { 737 register struct mpevent *ev; 738 int i, s; 739 740 s = spl8(); 741 ev = &mp->mp_recvq[mp->mp_on]; 742 if (ev->ev_status != EVSTATUS_FREE) 743 goto bad; 744 /* 745 * If not a close request, verify one extra 746 * event is available for closing the port. 747 */ 748 if (!cls_req) { 749 if ((i = mp->mp_on + 1) >= MPINSET) 750 i = 0; 751 if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE) 752 goto bad; 753 } 754 /* init inbound fields marking this entry as busy */ 755 ev->ev_cmd = 0; 756 ev->ev_opts = 0; 757 ev->ev_error = 0; 758 ev->ev_flags = 0; 759 ev->ev_count = 0; 760 ev->ev_status = EVSTATUS_BUSY; 761 /* adjust pointer to next available inbound entry */ 762 adjptr(mp->mp_on, MPINSET); 763 splx(s); 764 return (ev); 765 bad: 766 splx(s); 767 log(LOG_ERR, "mp%d: port%d, out of events\n", 768 MPUNIT(unit), MPPORT(unit)); 769 return ((struct mpevent *)0); 770 } 771 772 mpmodem(unit, flag) 773 int unit, flag; 774 { 775 struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 776 int port = MPPORT(unit); 777 register struct mpport *mp; 778 register struct asyncparam *asp; 779 780 mp = &ms->ms_mb->mb_port[port]; 781 asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 782 if (flag == MMOD_ON) { 783 if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */ 784 setm(&asp->ap_modem, A_DTR, ASSERT); 785 else 786 setm(&asp->ap_modem, A_DTR, AUTO); 787 seti(&asp->ap_intena, A_DCD); 788 } else { 789 setm(&asp->ap_modem, 0, DROP); 790 seti(&asp->ap_intena, 0); 791 } 792 } 793 794 /* 795 * Set up the modem control structure according to mask. 796 * Each set bit in the mask means assert the corresponding 797 * modem control line, otherwise, it will be dropped. 798 * RTS is special since it can either be asserted, dropped 799 * or put in auto mode for auto modem control. 800 */ 801 static 802 setm(mc, mask, rts) 803 register struct mdmctl *mc; 804 register int mask; 805 { 806 807 mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP; 808 mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP; 809 mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP; 810 mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP; 811 mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP; 812 mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP; 813 mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP; 814 mc->mc_rts = rts; 815 } 816 817 /* 818 * Set up the status change enable field from mask. 819 * When a signal is enabled in this structure and 820 * and a change in state on a corresponding modem 821 * control line occurs, a status change event will 822 * be delivered to the host. 823 */ 824 static 825 seti(mc, mask) 826 register struct mdmctl *mc; 827 register int mask; 828 { 829 830 mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF; 831 mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF; 832 mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF; 833 mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF; 834 mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF; 835 mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF; 836 mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF; 837 mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF; 838 } 839 840 mpcleanport(mb, port) 841 struct mblok *mb; 842 int port; 843 { 844 register struct mpport *mp; 845 register struct tty *tp; 846 847 mp = &mb->mb_port[port]; 848 if (mp->mp_proto == MPPROTO_ASYNC) { 849 mp->mp_flags = MP_REMBSY; 850 /* signal loss of carrier and close */ 851 tp = &mp_tty[mb->mb_unit*MPCHUNK+port]; 852 ttyflush(tp, FREAD|FWRITE); 853 (void) (*linesw[tp->t_line].l_modem)(tp, 0); 854 } 855 } 856 857 mpclean(mb, port) 858 register struct mblok *mb; 859 int port; 860 { 861 register struct mpport *mp; 862 register struct mpevent *ev; 863 register int i; 864 u_char list[2]; 865 int unit; 866 867 mp = &mb->mb_port[port]; 868 unit = mb->mb_unit; 869 for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) { 870 ev = &mp->mp_recvq[i]; 871 ev->ev_error = ENXIO; 872 ev->ev_status = EVSTATUS_DONE; 873 } 874 list[0] = port, list[1] = MPPORT_EOL; 875 mpxintr(unit, list); 876 mprintr(unit, list); 877 /* Clear async for port */ 878 mp->mp_proto = MPPROTO_UNUSED; 879 mp->mp_flags = 0; 880 mp->mp_on = 0; 881 mp->mp_off = 0; 882 mp->mp_nextrcv = 0; 883 884 mp_tty[unit*MPCHUNK + port].t_state = 0; 885 for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) { 886 ev->ev_status = EVSTATUS_FREE; 887 ev->ev_cmd = 0; 888 ev->ev_error = 0; 889 ev->ev_un.rcvblk = 0; 890 ev->ev_params = 0; 891 } 892 for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) { 893 ev->ev_status = EVSTATUS_FREE; 894 ev->ev_cmd = 0; 895 ev->ev_error = 0; 896 ev->ev_params = 0; 897 } 898 } 899 900 /* 901 * MPCC interrupt handler. 902 */ 903 mpintr(mpcc) 904 int mpcc; 905 { 906 register struct mblok *mb; 907 register struct his *his; 908 909 mb = mp_softc[mpcc].ms_mb; 910 if (mb == 0) { 911 printf("mp%d: stray interrupt\n", mpcc); 912 return; 913 } 914 his = &mb->mb_hostint; 915 his->semaphore &= ~MPSEMA_AVAILABLE; 916 /* 917 * Check for events to be processed. 918 */ 919 if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL) 920 mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone); 921 if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL) 922 mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone); 923 if (mb->mb_harderr || mb->mb_softerr) 924 mperror(mb, mpcc); 925 his->semaphore |= MPSEMA_AVAILABLE; 926 } 927 928 /* 929 * Handler for processing completion of transmitted events. 930 */ 931 mpxintr(unit, list) 932 register u_char *list; 933 { 934 register struct mpport *mp; 935 register struct mpevent *ev; 936 register struct mblok *mb; 937 register struct tty *tp; 938 register struct asyncparam *ap; 939 struct mpsoftc *ms; 940 int port, i, j; 941 # define nextevent(mp) &mp->mp_recvq[mp->mp_off] 942 943 ms = &mp_softc[unit]; 944 mb = mp_softc[unit].ms_mb; 945 for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) { 946 /* 947 * Process each completed entry in the inbound queue. 948 */ 949 mp = &mb->mb_port[port]; 950 tp = &mp_tty[unit*MPCHUNK + port]; 951 ev = nextevent(mp); 952 for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) { 953 /* YUCK */ 954 ap = &ms->ms_async[port][mp->mp_off]; 955 mppurge((caddr_t)ap, (int)sizeof (*ap)); 956 switch (ev->ev_cmd) { 957 case EVCMD_OPEN: 958 /* 959 * Open completion, start all reads and 960 * assert modem status information. 961 */ 962 for (i = 0; i < MPOUTSET; i++) 963 mp->mp_sendq[i].ev_status = EVSTATUS_GO; 964 (*linesw[tp->t_line].l_modem) 965 (tp, ap->ap_modem.mc_dcd == ASSERT); 966 mp_freein(ev); 967 adjptr(mp->mp_off, MPINSET); 968 mp->mp_proto = MPPROTO_ASYNC; /* XXX */ 969 wakeup((caddr_t)&tp->t_canq); 970 break; 971 case EVCMD_CLOSE: 972 /* 973 * Close completion, flush all pending 974 * transmissions, free resources, and 975 * cleanup mpcc port state. 976 */ 977 for (i = 0; i < MPOUTSET; i++) { 978 mp->mp_sendq[i].ev_status = 979 EVSTATUS_FREE; 980 mp->mp_sendq[i].ev_un.rcvblk = 0; 981 mp->mp_sendq[i].ev_params = 0; 982 } 983 mp_freein(ev); 984 adjptr(mp->mp_off, MPINSET); 985 tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH); 986 mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0; 987 mp->mp_flags &= ~MP_PROGRESS; 988 mp->mp_proto = MPPROTO_UNUSED; 989 wakeup((caddr_t)&tp->t_canq); 990 break; 991 case EVCMD_IOCTL: 992 mp_freein(ev); 993 adjptr(mp->mp_off, MPINSET); 994 mp->mp_flags &= ~MP_IOCTL; 995 wakeup((caddr_t)&tp->t_canq); 996 break; 997 case EVCMD_WRITE: 998 /* 999 * Transmission completed, update tty 1000 * state and restart output. 1001 */ 1002 if (ev->ev_opts != A_FLUSH) { 1003 tp->t_state &= ~TS_BUSY; 1004 if (tp->t_state & TS_FLUSH) 1005 tp->t_state &= ~TS_FLUSH; 1006 else { 1007 register int cc = 0, n; 1008 struct hxmtl *hxp; 1009 1010 hxp = &ms->ms_hxl[port]; 1011 for (n=0;n < ev->ev_count; n++) 1012 cc += hxp->size[n]; 1013 ndflush(&tp->t_outq, cc); 1014 } 1015 } 1016 switch (ev->ev_error) { 1017 case A_SIZERR: /*# error in xmt data size */ 1018 mplog(unit, port, A_XSIZE, 0); 1019 break; 1020 case A_NXBERR: /*# no more xmt evt buffers */ 1021 mplog(unit, port, A_NOXBUF, 0); 1022 break; 1023 } 1024 mp_freein(ev); 1025 adjptr(mp->mp_off, MPINSET); 1026 mpstart(tp); 1027 break; 1028 default: 1029 mplog(unit, port, A_INVCMD, (int)ev->ev_cmd); 1030 mp_freein(ev); 1031 adjptr(mp->mp_off, MPINSET); 1032 break; 1033 } 1034 } 1035 } 1036 #undef nextevent 1037 } 1038 1039 mp_freein(ev) 1040 register struct mpevent *ev; 1041 { 1042 /* re-init all values in this entry */ 1043 ev->ev_cmd = 0; 1044 ev->ev_opts = 0; 1045 ev->ev_error = 0; 1046 ev->ev_flags = 0; 1047 ev->ev_count = 0; 1048 /* show this entry is available for use */ 1049 ev->ev_status = EVSTATUS_FREE; 1050 } 1051 1052 /* 1053 * Handler for processing received events. 1054 */ 1055 mprintr(unit, list) 1056 u_char *list; 1057 { 1058 register struct tty *tp; 1059 register struct mpport *mp; 1060 register struct mpevent *ev; 1061 struct mblok *mb; 1062 register int cc; 1063 register char *cp; 1064 struct mpsoftc *ms; 1065 caddr_t ptr; 1066 char *rcverr; 1067 int port, i; 1068 1069 ms = &mp_softc[unit]; 1070 mb = mp_softc[unit].ms_mb; 1071 for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) { 1072 tp = &mp_tty[unit*MPCHUNK + port]; 1073 mp = &mb->mb_port[port]; 1074 ev = &mp->mp_sendq[mp->mp_nextrcv]; 1075 while (ev->ev_status & EVSTATUS_DONE) { 1076 switch(ev->ev_cmd) { 1077 case EVCMD_STATUS: 1078 /* 1079 * Status change, look for carrier changes. 1080 */ 1081 switch(ev->ev_opts) { 1082 case DCDASRT: 1083 (*linesw[tp->t_line].l_modem)(tp, 1); 1084 wakeup((caddr_t)&tp->t_canq); 1085 break; 1086 case DCDDROP: 1087 (*linesw[tp->t_line].l_modem)(tp, 0); 1088 wakeup((caddr_t)&tp->t_canq); 1089 break; 1090 case NORBUF: 1091 case NOEBUF: 1092 mplog(unit, port, 1093 "out of receive events", 0); 1094 break; 1095 default: 1096 mplog(unit, port, 1097 "unexpect status command", 1098 (int)ev->ev_opts); 1099 break; 1100 } 1101 break; 1102 case EVCMD_READ: 1103 /* 1104 * Process received data. 1105 */ 1106 if ((tp->t_state & TS_ISOPEN) == 0) { 1107 wakeup((caddr_t)&tp->t_rawq); 1108 break; 1109 } 1110 if ((cc = ev->ev_count) == 0) 1111 break; 1112 cp = ms->ms_cbuf[port][mp->mp_nextrcv]; 1113 mppurge(cp, CBSIZE); 1114 while (cc-- > 0) { 1115 /* 1116 * A null character is inserted, 1117 * potentially when a break or framing 1118 * error occurs. If we're not in raw 1119 * mode, substitute the interrupt 1120 * character. 1121 */ 1122 /*** XXX - FIXUP ***/ 1123 if (*cp == 0 && 1124 (ev->ev_error == BRKASRT || 1125 ev->ev_error == FRAMERR)) 1126 if ((tp->t_flags&RAW) == 0) 1127 ; 1128 /* XXX was break */ 1129 (*linesw[tp->t_line].l_rint)(*cp++, tp); 1130 } 1131 /* setup for next read */ 1132 ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0]; 1133 ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 1134 ev->ev_params = (caddr_t) kvtophys(ptr); 1135 switch(ev->ev_error) { 1136 case RCVDTA: 1137 /* Normal (good) rcv data do not 1138 * report the following they are 1139 * "normal" errors 1140 */ 1141 case FRAMERR: 1142 /* frame error */ 1143 case BRKASRT: 1144 /* Break condition */ 1145 case PARERR: 1146 /* parity error */ 1147 rcverr = (char *)0; 1148 break; 1149 case OVRNERR: 1150 /* Overrun error */ 1151 rcverr = "overrun error"; 1152 break; 1153 case OVFERR: 1154 /* Overflow error */ 1155 rcverr = "overflow error"; 1156 break; 1157 default: 1158 rcverr = "undefined rcv error"; 1159 break; 1160 } 1161 if (rcverr != (char *)0) 1162 mplog(unit, port, rcverr, 1163 (int)ev->ev_error); 1164 break; 1165 default: 1166 mplog(unit, port, "unexpected command", 1167 (int)ev->ev_cmd); 1168 break; 1169 } 1170 ev->ev_cmd = 0; 1171 ev->ev_opts = 0; 1172 ev->ev_error = 0; 1173 ev->ev_flags = 0; 1174 ev->ev_count = 0; 1175 ev->ev_status = EVSTATUS_GO; /* start next read */ 1176 adjptr(mp->mp_nextrcv, MPOUTSET); 1177 ev = &mp->mp_sendq[mp->mp_nextrcv]; 1178 } 1179 } 1180 } 1181 1182 /* 1183 * Log an mpcc diagnostic. 1184 */ 1185 mplog(unit, port, cp, flags) 1186 char *cp; 1187 { 1188 1189 if (flags) 1190 log(LOG_ERR, "mp%d: port%d, %s (%d)\n", 1191 unit, port, cp, flags); 1192 else 1193 log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp); 1194 } 1195 1196 int MPHOSTINT = 1; 1197 1198 mptimeint(mb) 1199 register struct mblok *mb; 1200 { 1201 1202 mb->mb_mpintcnt = 0; 1203 mb->mb_mpintclk = (caddr_t)0; 1204 *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 1205 } 1206 1207 /* 1208 * Interupt mpcc 1209 */ 1210 mpintmpcc(mb, port) 1211 register struct mblok *mb; 1212 { 1213 1214 mb->mb_intr[port] |= MPSEMA_WORK; 1215 if (++mb->mb_mpintcnt == MPHOSTINT) { 1216 mb->mb_mpintcnt = 0; 1217 *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 1218 if (mb->mb_mpintclk) { 1219 untimeout(mptimeint, (caddr_t)mb); 1220 mb->mb_mpintclk = 0; 1221 } 1222 } else { 1223 if (mb->mb_mpintclk == 0) { 1224 timeout(mptimeint, (caddr_t)mb, 4); 1225 mb->mb_mpintclk = (caddr_t)1; 1226 } 1227 } 1228 } 1229 1230 static char *mpherrmsg[] = { 1231 "", 1232 "Bus error", /* MPBUSERR */ 1233 "Address error", /* ADDRERR */ 1234 "Undefined ecc interrupt", /* UNDECC */ 1235 "Undefined interrupt", /* UNDINT */ 1236 "Power failure occurred", /* PWRFL */ 1237 "Stray transmit done interrupt", /* NOXENTRY */ 1238 "Two fast timers on one port", /* TWOFTMRS */ 1239 "Interrupt queue full", /* INTQFULL */ 1240 "Interrupt queue ack error", /* INTQERR */ 1241 "Uncorrectable dma parity error", /* CBPERR */ 1242 "32 port ACAP failed power up", /* ACPDEAD */ 1243 }; 1244 #define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0])) 1245 1246 mperror(mb, unit) 1247 register struct mblok *mb; 1248 int unit; 1249 { 1250 register char *cp; 1251 register int i; 1252 1253 if (mb->mb_softerr) { 1254 switch (mb->mb_softerr) { 1255 case DMAPERR: /* dma parity error */ 1256 cp = "dma parity error"; 1257 break; 1258 case ECCERR: 1259 cp = "local memory ecc error"; 1260 break; 1261 default: 1262 cp = "unknown error"; 1263 break; 1264 } 1265 log(LOG_ERR, "mp%d: soft error, %s", unit, cp); 1266 mb->mb_softerr = 0; 1267 } 1268 if (mb->mb_harderr) { 1269 if (mb->mb_harderr < NHERRS) 1270 cp = mpherrmsg[mb->mb_harderr]; 1271 else 1272 cp = "unknown error"; 1273 log(LOG_ERR, "mp%d: hard error, %s", unit, cp); 1274 if (mb->mb_status == MP_OPOPEN) { 1275 for (i = 0; i < MPMAXPORT; i++) { 1276 mpcleanport(mb, i); 1277 mb->mb_proto[i] = MPPROTO_UNUSED; 1278 } 1279 } 1280 mb->mb_harderr = 0; 1281 mb->mb_status = 0; 1282 } 1283 } 1284 1285 mppurge(addr, cc) 1286 register caddr_t addr; 1287 register int cc; 1288 { 1289 1290 for (; cc >= 0; addr += NBPG, cc -= NBPG) 1291 mtpr(P1DC, addr); 1292 } 1293 1294 /* 1295 * MPCC Download Pseudo-device. 1296 */ 1297 char mpdlbuf[MPDLBUFSIZE]; 1298 int mpdlbusy; /* interlock on download buffer */ 1299 int mpdlerr; 1300 1301 mpdlopen(dev) 1302 dev_t dev; 1303 { 1304 int unit, mpu; 1305 struct vba_device *vi; 1306 1307 unit = minor(dev); 1308 mpu = MPUNIT(unit); 1309 if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 1310 return (ENODEV); 1311 return (0); 1312 } 1313 1314 mpdlwrite(dev, uio) 1315 dev_t dev; 1316 struct uio *uio; 1317 { 1318 register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))]; 1319 register struct mpdl *dl; 1320 int error; 1321 1322 if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN) 1323 return (EFAULT); 1324 dl = &ms->ms_mb->mb_dl; 1325 dl->mpdl_count = uio->uio_iov->iov_len; 1326 dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 1327 if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, uio)) 1328 return (error); 1329 uio->uio_resid -= dl->mpdl_count; /* set up return from write */ 1330 dl->mpdl_cmd = MPDLCMD_NORMAL; 1331 error = mpdlwait(dl); 1332 return (error); 1333 } 1334 1335 mpdlclose(dev) 1336 dev_t dev; 1337 { 1338 register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb; 1339 1340 if (mb == 0 || mb->mb_status != MP_DLDONE) { 1341 mpbogus.status = 0; 1342 if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))]) 1343 mpdlbusy--; 1344 return (EEXIST); 1345 } 1346 mb->mb_status = MP_OPOPEN; 1347 mpbogus.status = 0; 1348 /* set to dead, for board handshake */ 1349 mb->mb_hostint.imok = MPIMOK_DEAD; 1350 return (0); 1351 } 1352 1353 /* ARGSUSED */ 1354 mpdlioctl(dev, cmd, data, flag) 1355 dev_t dev; 1356 caddr_t data; 1357 { 1358 register struct mblok *mb; 1359 register struct mpdl *dl; 1360 int unit, error = 0, s, i; 1361 1362 mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb; 1363 if (mb == 0) 1364 return (EEXIST); 1365 dl = &mb->mb_dl; 1366 error = 0; 1367 switch (cmd) { 1368 case MPIOPORTMAP: 1369 bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto)); 1370 break; 1371 case MPIOHILO: 1372 bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport))); 1373 break; 1374 case MPIOENDDL: 1375 dl->mpdl_count = 0; 1376 dl->mpdl_data = 0; 1377 dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK; 1378 error = mpdlwait(dl); 1379 mpccinit(unit); 1380 mb->mb_status = MP_DLDONE; 1381 mpdlbusy--; 1382 break; 1383 case MPIOENDCODE: 1384 dl->mpdl_count = 0; 1385 dl->mpdl_data = 0; 1386 dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK; 1387 error = mpdlwait(dl); 1388 break; 1389 case MPIOASYNCNF: 1390 bcopy(data, mpdlbuf, sizeof (struct abdcf)); 1391 dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 1392 dl->mpdl_count = sizeof (struct abdcf); 1393 dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK; 1394 error = mpdlwait(dl); 1395 break; 1396 case MPIOSTARTDL: 1397 s = spl8(); 1398 while (mpdlbusy) 1399 if (error = tsleep((caddr_t)&mpdlbusy, 1400 (PZERO+1) | PCATCH, devioc, 0)) 1401 break; 1402 splx(s); 1403 if (error) 1404 break; 1405 mpdlbusy++; 1406 /* initialize the downloading interface */ 1407 mpbogus.magic = MPMAGIC; 1408 mpbogus.mb = mpbogus.mbloks[unit]; 1409 mpbogus.status = 1; 1410 dl->mpdl_status = EVSTATUS_FREE; 1411 dl->mpdl_count = 0; 1412 dl->mpdl_cmd = 0; 1413 dl->mpdl_data = (char *) 0; 1414 mpdlerr = 0; 1415 mb->mb_magic = MPMAGIC; 1416 mb->mb_ivec = mp_softc[unit].ms_ivec+1; /* download vector */ 1417 mb->mb_status = MP_DLPEND; 1418 mb->mb_diagswitch[0] = 'A'; 1419 mb->mb_diagswitch[1] = 'P'; 1420 s = spl8(); 1421 *(u_short *)mpinfo[unit]->ui_addr = 2; 1422 error = tsleep((caddr_t)&mb->mb_status, (PZERO+1) | PCATCH, 1423 devio, 30*hz); 1424 splx(s); 1425 if (error == EWOULDBLOCK) 1426 error = ETIMEDOUT; 1427 if (error) 1428 mpbogus.status = 0; 1429 bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port)); 1430 break; 1431 case MPIORESETBOARD: 1432 s = spl8(); 1433 if (mb->mb_imokclk) 1434 mb->mb_imokclk = 0; 1435 *(u_short *)mpinfo[unit]->ui_addr = 0x100; 1436 if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) { 1437 mpdlerr = MP_DLERROR; 1438 dl->mpdl_status = EVSTATUS_FREE; 1439 wakeup((caddr_t)&dl->mpdl_status); 1440 mpbogus.status = 0; 1441 } 1442 for (i = 0; i < MPMAXPORT; i++) { 1443 if (mb->mb_harderr || mb->mb_softerr) 1444 mperror(mb, i); 1445 mpcleanport(mb, i); 1446 mb->mb_proto[i] = MPPROTO_UNUSED; 1447 } 1448 mb->mb_status = 0; 1449 splx(s); 1450 break; 1451 default: 1452 error = EINVAL; 1453 break; 1454 } 1455 return (error); 1456 } 1457 1458 mpccinit(unit) 1459 int unit; 1460 { 1461 register struct mblok *mb = mp_softc[unit].ms_mb; 1462 register struct his *his; 1463 register int i, j; 1464 1465 mb->mb_status = MP_DLDONE; 1466 mb->mb_ivec = mp_softc[unit].ms_ivec; 1467 mb->mb_magic = MPMAGIC; 1468 /* Init host interface structure */ 1469 his = &mb->mb_hostint; 1470 his->semaphore = MPSEMA_AVAILABLE; 1471 for (i = 0; i < NMPPROTO; i++) 1472 for (j = 0; j < MPMAXPORT; j++) { 1473 his->proto[i].inbdone[j] = MPPORT_EOL; 1474 his->proto[i].outbdone[j] = MPPORT_EOL; 1475 } 1476 mb->mb_unit = unit; 1477 } 1478 1479 mpdlintr(mpcc) 1480 int mpcc; 1481 { 1482 register struct mblok *mb; 1483 register struct mpdl *dl; 1484 1485 mb = mp_softc[mpcc].ms_mb; 1486 if (mb == 0) { 1487 printf("mp%d: stray download interrupt\n", mpcc); 1488 return; 1489 } 1490 dl = &mb->mb_dl; 1491 switch (mb->mb_status) { 1492 case MP_DLOPEN: 1493 if (dl->mpdl_status != EVSTATUS_DONE) 1494 mpdlerr = MP_DLERROR; 1495 dl->mpdl_status = EVSTATUS_FREE; 1496 wakeup((caddr_t)&dl->mpdl_status); 1497 return; 1498 case MP_DLPEND: 1499 mb->mb_status = MP_DLOPEN; 1500 wakeup((caddr_t)&mb->mb_status); 1501 /* fall thru... */ 1502 case MP_DLTIME: 1503 return; 1504 case MP_OPOPEN: 1505 if (mb->mb_imokclk) 1506 mb->mb_imokclk = 0; 1507 mb->mb_nointcnt = 0; /* reset no interrupt count */ 1508 mb->mb_hostint.imok = MPIMOK_DEAD; 1509 mb->mb_imokclk = (caddr_t)1; 1510 break; 1511 default: 1512 log(LOG_ERR, "mp%d: mpdlintr, status %x\n", 1513 mpcc, mb->mb_status); 1514 break; 1515 } 1516 } 1517 1518 /* 1519 * Wait for a transfer to complete or a timeout to occur. 1520 */ 1521 mpdlwait(dl) 1522 register struct mpdl *dl; 1523 { 1524 int s, error = 0; 1525 1526 s = spl8(); 1527 dl->mpdl_status = EVSTATUS_GO; 1528 while (dl->mpdl_status != EVSTATUS_FREE) { 1529 error = tsleep((caddr_t)&dl->mpdl_status, (PZERO+1) | PCATCH, 1530 devout, 0); 1531 if (mpdlerr == MP_DLERROR) 1532 error = EIO; 1533 if (error) 1534 break; 1535 } 1536 splx(s); 1537 return (error); 1538 } 1539 #endif 1540