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