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.12 (Berkeley) 06/06/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 (error = ttclosed(tp))) 264 goto bad; 265 /* 266 * a mpclose() might have disabled port. if so restart 267 */ 268 if (mp->mp_proto != MPPROTO_ASYNC) 269 goto restart; 270 tp->t_state |= TS_WOPEN; 271 } 272 error = (*linesw[tp->t_line].l_open)(dev,tp); 273 done: 274 splx(s); 275 /* 276 * wakeup those processes waiting for the open to complete 277 */ 278 wakeup((caddr_t)&tp->t_canq); 279 return (error); 280 bad: 281 tp->t_state &= ~TS_WOPEN; 282 goto done; 283 } 284 285 /* 286 * Close an mpcc port. 287 */ 288 /* ARGSUSED */ 289 mpclose(dev, flag) 290 dev_t dev; 291 { 292 register struct tty *tp; 293 register struct mpport *mp; 294 register struct mpevent *ev; 295 int s, port, unit, error = 0; 296 struct mblok *mb; 297 298 unit = minor(dev); 299 tp = &mp_tty[unit]; 300 port = MPPORT(unit); 301 mb = mp_softc[MPUNIT(unit)].ms_mb; 302 mp = &mb->mb_port[port]; 303 s = spl8(); 304 if (mp->mp_flags & MP_PROGRESS) { 305 if (mp->mp_flags & MP_REMBSY) { 306 mp->mp_flags &= ~MP_REMBSY; 307 splx(s); 308 return (0); 309 } 310 while (mp->mp_flags & MP_PROGRESS) 311 if (error = tsleep((caddr_t)&tp->t_canq, 312 TTIPRI | PCATCH, ttclos, 0)) { 313 splx(s); 314 return (error); 315 } 316 } 317 mp->mp_flags |= MP_PROGRESS; 318 (*linesw[tp->t_line].l_close)(tp); 319 ev = mp_getevent(mp, unit, 1); 320 if (ev == 0) { 321 error = ENOBUFS; 322 mp->mp_flags &= ~MP_PROGRESS; 323 goto out; 324 } 325 if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0) 326 mpmodem(unit, MMOD_OFF); 327 else 328 mpmodem(unit, MMOD_ON); 329 mpcmd(ev, EVCMD_CLOSE, 0, mb, port); 330 error = ttyclose(tp); 331 out: 332 if (mp->mp_flags & MP_REMBSY) 333 mpclean(mb, port); 334 else 335 while (mp->mp_flags & MP_PROGRESS && error == 0) 336 error = tsleep((caddr_t)&tp->t_canq, TTIPRI | PCATCH, 337 ttclos, 0); 338 splx(s); 339 return (error); 340 } 341 342 /* 343 * Read from an mpcc port. 344 */ 345 mpread(dev, uio, flag) 346 dev_t dev; 347 struct uio *uio; 348 { 349 struct tty *tp; 350 351 tp = &mp_tty[minor(dev)]; 352 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 353 } 354 355 /* 356 * Write to an mpcc port. 357 */ 358 mpwrite(dev, uio, flag) 359 dev_t dev; 360 struct uio *uio; 361 { 362 struct tty *tp; 363 364 tp = &mp_tty[minor(dev)]; 365 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 366 } 367 368 /* 369 * Ioctl for a mpcc port 370 */ 371 mpioctl(dev, cmd, data, flag) 372 dev_t dev; 373 caddr_t data; 374 { 375 register struct tty *tp; 376 register struct mpsoftc *ms; 377 register struct mpport *mp; 378 register struct mpevent *ev; 379 int s, port, error, unit; 380 struct mblok *mb; 381 382 unit = minor(dev); 383 tp = &mp_tty[unit]; 384 ms = &mp_softc[MPUNIT(unit)]; 385 mb = ms->ms_mb; 386 port = MPPORT(unit); 387 mp = &mb->mb_port[port]; 388 if (mp->mp_proto != MPPROTO_ASYNC) 389 return(ENXIO); 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 switch (cmd) { 397 case TIOCSBRK: /* send break */ 398 case TIOCCBRK: /* clear break */ 399 s = spl8(); 400 while (mp->mp_flags & MP_IOCTL) { 401 if (error = tsleep((caddr_t)&tp->t_canq, 402 TTIPRI | PCATCH, ttyout, 0)) { 403 splx(s); 404 return (error); 405 } 406 if (mp->mp_proto != MPPROTO_ASYNC) { 407 splx(s); 408 return (ENXIO); 409 } 410 } 411 ev = mp_getevent(mp, unit, 0); 412 if (ev) { 413 mp->mp_flags |= MP_IOCTL; 414 mpcmd(ev, EVCMD_IOCTL, 415 (cmd == TIOCSBRK ? A_BRKON : A_BRKOFF), mb, port); 416 } else 417 error = ENOBUFS; 418 splx(s); 419 break; 420 case TIOCSDTR: /* set dtr control line */ 421 break; 422 case TIOCCDTR: /* clear dtr control line */ 423 break; 424 default: 425 error = ENOTTY; 426 break; 427 } 428 return (error); 429 } 430 431 mpparam(tp, t) 432 struct tty *tp; 433 struct termios *t; 434 { 435 register struct mpevent *ev; 436 int unit = minor(tp->t_dev); 437 struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 438 struct mblok *mb = ms->ms_mb; 439 440 ev = mpparam2(tp, t); 441 if (ev == 0) 442 return (ENOBUFS); 443 mpcmd(ev, EVCMD_IOCTL, A_CHGALL, mb, MPPORT(unit)); 444 return (0); 445 } 446 447 struct mpevent * 448 mpparam2(tp, t) 449 register struct tty *tp; 450 struct termios *t; 451 { 452 register struct mpevent *ev; 453 register struct mpport *mp; 454 int unit = minor(tp->t_dev); 455 struct mblok *mb; 456 struct mpsoftc *ms; 457 register struct asyncparam *asp; 458 int port, speedcode; 459 460 ms = &mp_softc[MPUNIT(unit)]; 461 mb = ms->ms_mb; 462 port = MPPORT(unit); 463 mp = &mb->mb_port[port]; 464 ev = mp_getevent(mp, unit, 0); /* XXX */ 465 speedcode = ttspeedtab(t->c_ospeed, mpspeedtab); 466 if (ev == 0 || speedcode < 0) { 467 printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n", 468 MPUNIT(unit), port, ev, speedcode, t->c_ospeed); 469 return (0); /* XXX */ 470 } 471 /* YUCK */ 472 asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 473 asp->ap_xon = t->c_cc[VSTART]; 474 asp->ap_xoff = t->c_cc[VSTOP]; 475 if (!(t->c_iflag&IXON) || (asp->ap_xon == _POSIX_VDISABLE) || 476 (asp->ap_xoff == _POSIX_VDISABLE)) 477 asp->ap_xena = MPA_DIS; 478 else 479 asp->ap_xena = MPA_ENA; 480 asp->ap_xany = ((t->c_iflag & IXANY) ? MPA_ENA : MPA_DIS); 481 #ifdef notnow 482 if (t->t_cflag&CSIZE) == CS8) { 483 #endif 484 asp->ap_data = MPCHAR_8; 485 asp->ap_parity = MPPAR_NONE; 486 #ifdef notnow 487 } else { 488 asp->ap_data = MPCHAR_7; 489 if ((t->c_flags & (EVENP|ODDP)) == ODDP) /* XXX */ 490 asp->ap_parity = MPPAR_ODD; 491 else 492 asp->ap_parity = MPPAR_EVEN; 493 } 494 #endif 495 asp->ap_loop = MPA_DIS; /* disable loopback */ 496 asp->ap_rtimer = A_RCVTIM; /* default receive timer */ 497 if (t->c_ospeed == B110) 498 asp->ap_stop = MPSTOP_2; 499 else 500 asp->ap_stop = MPSTOP_1; 501 if (t->c_ospeed == 0) { 502 tp->t_state |= TS_HUPCLS; 503 setm(&asp->ap_modem, 0, DROP); 504 seti(&asp->ap_intena, A_DCD); 505 return (ev); 506 } 507 if (t->c_ospeed == EXTA || t->c_ospeed == EXTB) 508 asp->ap_baud = M19200; 509 else 510 asp->ap_baud = speedcode; 511 if (1 || ms->ms_softCAR & (1<<port)) /* XXX HARDWIRE FOR NOW */ 512 setm(&asp->ap_modem, A_DTR, ASSERT); 513 else 514 setm(&asp->ap_modem, A_DTR, AUTO); 515 seti(&asp->ap_intena, A_DCD); 516 return(ev); 517 } 518 519 mpstart(tp) 520 register struct tty *tp; 521 { 522 register struct mpevent *ev; 523 register struct mpport *mp; 524 struct mblok *mb; 525 struct mpsoftc *ms; 526 int port, unit, xcnt, n, s, i; 527 struct hxmtl *hxp; 528 struct clist outq; 529 530 s = spl8(); 531 unit = minor(tp->t_dev); 532 ms = &mp_softc[MPUNIT(unit)]; 533 mb = ms->ms_mb; 534 port = MPPORT(unit); 535 mp = &mb->mb_port[port]; 536 hxp = &ms->ms_hxl[port]; 537 xcnt = 0; 538 outq = tp->t_outq; 539 for (i = 0; i < MPXMIT; i++) { 540 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 541 break; 542 if (outq.c_cc <= tp->t_lowat) { 543 if (tp->t_state & TS_ASLEEP) { 544 tp->t_state &= ~TS_ASLEEP; 545 wakeup((caddr_t)&tp->t_outq); 546 } 547 if (tp->t_wsel) { 548 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 549 tp->t_wsel = 0; 550 tp->t_state &= ~TS_WCOLL; 551 } 552 } 553 if (outq.c_cc == 0) 554 break; 555 /* 556 * If we're not currently busy outputting, 557 * and there is data to be output, set up 558 * port transmit structure to send to mpcc. 559 */ 560 if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */ 561 n = ndqb(&outq, 0); 562 else { 563 n = ndqb(&outq, 0200); 564 if (n == 0) { 565 if (xcnt > 0) 566 break; 567 n = getc(&outq); 568 timeout(ttrstrt, (caddr_t)tp, (n&0177)+6); 569 tp->t_state |= TS_TIMEOUT; 570 break; 571 } 572 } 573 hxp->dblock[i] = (caddr_t)kvtophys(outq.c_cf); 574 hxp->size[i] = n; 575 xcnt++; /* count of xmts to send */ 576 ndadvance(&outq, n); 577 } 578 /* 579 * If data to send, poke mpcc. 580 */ 581 if (xcnt) { 582 ev = mp_getevent(mp, unit, 0); 583 if (ev == 0) { 584 tp->t_state &= ~(TS_BUSY|TS_TIMEOUT); 585 } else { 586 tp->t_state |= TS_BUSY; 587 ev->ev_count = xcnt; 588 mpcmd(ev, EVCMD_WRITE, 0, mb, MPPORT(unit)); 589 } 590 } 591 splx(s); 592 } 593 594 /* 595 * Advance cc bytes from q but don't free memory. 596 */ 597 ndadvance(q, cc) 598 register struct clist *q; 599 register cc; 600 { 601 register struct cblock *bp; 602 char *end; 603 int rem, s; 604 605 s = spltty(); 606 if (q->c_cc <= 0) 607 goto out; 608 while (cc>0 && q->c_cc) { 609 bp = (struct cblock *)((int)q->c_cf & ~CROUND); 610 if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 611 end = q->c_cl; 612 } else { 613 end = (char *)((int)bp + sizeof (struct cblock)); 614 } 615 rem = end - q->c_cf; 616 if (cc >= rem) { 617 cc -= rem; 618 q->c_cc -= rem; 619 q->c_cf = bp->c_next->c_info; 620 } else { 621 q->c_cc -= cc; 622 q->c_cf += cc; 623 break; 624 } 625 } 626 if (q->c_cc <= 0) { 627 q->c_cf = q->c_cl = NULL; 628 q->c_cc = 0; 629 } 630 out: 631 splx(s); 632 } 633 634 /* 635 * Stop output on a line, e.g. for ^S/^Q or output flush. 636 */ 637 /* ARGSUSED */ 638 mpstop(tp, rw) 639 register struct tty *tp; 640 int rw; 641 { 642 register struct mpport *mp; 643 register struct mpevent *ev; 644 int unit = minor(tp->t_dev); 645 int port; 646 struct mblok *mb; 647 int s; 648 649 s = spl8(); 650 if (tp->t_state & TS_BUSY) { 651 if ((tp->t_state & TS_TTSTOP) == 0) { 652 tp->t_state |= TS_FLUSH; 653 port = MPPORT(unit); 654 mb = mp_softc[MPUNIT(unit)].ms_mb; 655 mp = &mb->mb_port[port]; 656 ev = mp_getevent(mp, unit, 0); 657 if (ev == 0) { 658 splx(s); 659 return; 660 } 661 mpcmd(ev, EVCMD_WRITE, A_FLUSH, mb, port); 662 } 663 } 664 splx(s); 665 } 666 667 /* 668 * Initialize an async port's MPCC state. 669 */ 670 mpportinit(ms, mp, port) 671 register struct mpsoftc *ms; 672 register struct mpport *mp; 673 int port; 674 { 675 register struct mpevent *ev; 676 register int i; 677 caddr_t ptr; 678 679 mp->mp_on = mp->mp_off = 0; 680 mp->mp_nextrcv = 0; 681 mp->mp_flags = 0; 682 ev = &mp->mp_recvq[0]; 683 for (i = 0; ev < &mp->mp_recvq[MPINSET]; ev++, i++) { 684 ev->ev_status = EVSTATUS_FREE; 685 ev->ev_cmd = 0; 686 ev->ev_opts = 0; 687 ev->ev_error = 0; 688 ev->ev_flags = 0; 689 ev->ev_count = 0; 690 ev->ev_un.hxl = (struct hxmtl *) kvtophys(&ms->ms_hxl[port]); 691 ev->ev_params = (caddr_t) kvtophys(&ms->ms_async[port][i]); 692 } 693 ev = &mp->mp_sendq[0]; 694 for (i = 0; ev < &mp->mp_sendq[MPOUTSET]; ev++, i++) { 695 /* init so that L2 can't send any events */ 696 /* to host until open has completed */ 697 ev->ev_status = EVSTATUS_FREE; 698 ev->ev_cmd = 0; 699 ev->ev_opts = 0; 700 ev->ev_error = 0; 701 ev->ev_flags = 0; 702 ev->ev_count = 0; 703 ptr = (caddr_t) &ms->ms_cbuf[port][i][0]; 704 ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 705 ev->ev_params = (caddr_t) kvtophys(ptr); 706 } 707 return (0); 708 } 709 710 /* 711 * Send an event to an mpcc. 712 */ 713 mpcmd(ev, cmd, flags, mb, port) 714 register struct mpevent *ev; 715 struct mblok *mb; 716 { 717 int s; 718 719 s = spl8(); 720 /* move host values to inbound entry */ 721 ev->ev_cmd = cmd; 722 ev->ev_opts = flags; 723 /* show event ready for mpcc */ 724 ev->ev_status = EVSTATUS_GO; 725 mpintmpcc(mb, port); 726 splx(s); 727 } 728 729 /* 730 * Return the next available event entry for the indicated port. 731 */ 732 struct mpevent * 733 mp_getevent(mp, unit, cls_req) 734 register struct mpport *mp; 735 int unit; 736 int cls_req; 737 { 738 register struct mpevent *ev; 739 int i, s; 740 741 s = spl8(); 742 ev = &mp->mp_recvq[mp->mp_on]; 743 if (ev->ev_status != EVSTATUS_FREE) 744 goto bad; 745 /* 746 * If not a close request, verify one extra 747 * event is available for closing the port. 748 */ 749 if (!cls_req) { 750 if ((i = mp->mp_on + 1) >= MPINSET) 751 i = 0; 752 if (mp->mp_recvq[i].ev_status != EVSTATUS_FREE) 753 goto bad; 754 } 755 /* init inbound fields marking this entry as busy */ 756 ev->ev_cmd = 0; 757 ev->ev_opts = 0; 758 ev->ev_error = 0; 759 ev->ev_flags = 0; 760 ev->ev_count = 0; 761 ev->ev_status = EVSTATUS_BUSY; 762 /* adjust pointer to next available inbound entry */ 763 adjptr(mp->mp_on, MPINSET); 764 splx(s); 765 return (ev); 766 bad: 767 splx(s); 768 log(LOG_ERR, "mp%d: port%d, out of events\n", 769 MPUNIT(unit), MPPORT(unit)); 770 return ((struct mpevent *)0); 771 } 772 773 mpmodem(unit, flag) 774 int unit, flag; 775 { 776 struct mpsoftc *ms = &mp_softc[MPUNIT(unit)]; 777 int port = MPPORT(unit); 778 register struct mpport *mp; 779 register struct asyncparam *asp; 780 781 mp = &ms->ms_mb->mb_port[port]; 782 asp = &ms->ms_async[port][mp->mp_on?mp->mp_on-1:MPINSET-1]; 783 if (flag == MMOD_ON) { 784 if (1 || ms->ms_softCAR & (1 << port))/* XXX HARDWIRE FOR NOW */ 785 setm(&asp->ap_modem, A_DTR, ASSERT); 786 else 787 setm(&asp->ap_modem, A_DTR, AUTO); 788 seti(&asp->ap_intena, A_DCD); 789 } else { 790 setm(&asp->ap_modem, 0, DROP); 791 seti(&asp->ap_intena, 0); 792 } 793 } 794 795 /* 796 * Set up the modem control structure according to mask. 797 * Each set bit in the mask means assert the corresponding 798 * modem control line, otherwise, it will be dropped. 799 * RTS is special since it can either be asserted, dropped 800 * or put in auto mode for auto modem control. 801 */ 802 static 803 setm(mc, mask, rts) 804 register struct mdmctl *mc; 805 register int mask; 806 { 807 808 mc->mc_rngdsr = (mask & A_RNGDSR) ? ASSERT : DROP; 809 mc->mc_rate = (mask & A_RATE) ? ASSERT : DROP; 810 mc->mc_dcd = (mask & A_DCD) ? ASSERT : DROP; 811 mc->mc_sectx = (mask & A_SECTX) ? ASSERT : DROP; 812 mc->mc_cts = (mask & A_CTS) ? ASSERT : DROP; 813 mc->mc_secrx = (mask & A_SECRX) ? ASSERT : DROP; 814 mc->mc_dtr = (mask & A_DTR) ? ASSERT : DROP; 815 mc->mc_rts = rts; 816 } 817 818 /* 819 * Set up the status change enable field from mask. 820 * When a signal is enabled in this structure and 821 * and a change in state on a corresponding modem 822 * control line occurs, a status change event will 823 * be delivered to the host. 824 */ 825 static 826 seti(mc, mask) 827 register struct mdmctl *mc; 828 register int mask; 829 { 830 831 mc->mc_rngdsr = (mask & A_RNGDSR) ? MDM_ON : MDM_OFF; 832 mc->mc_rate = (mask & A_RATE) ? MDM_ON : MDM_OFF; 833 mc->mc_dcd = (mask & A_DCD) ? MDM_ON : MDM_OFF; 834 mc->mc_sectx = (mask & A_SECTX) ? MDM_ON : MDM_OFF; 835 mc->mc_cts = (mask & A_CTS) ? MDM_ON : MDM_OFF; 836 mc->mc_secrx = (mask & A_SECRX) ? MDM_ON : MDM_OFF; 837 mc->mc_dtr = (mask & A_DTR) ? MDM_ON : MDM_OFF; 838 mc->mc_rts = (mask & A_RTS) ? MDM_ON : MDM_OFF; 839 } 840 841 mpcleanport(mb, port) 842 struct mblok *mb; 843 int port; 844 { 845 register struct mpport *mp; 846 register struct tty *tp; 847 848 mp = &mb->mb_port[port]; 849 if (mp->mp_proto == MPPROTO_ASYNC) { 850 mp->mp_flags = MP_REMBSY; 851 /* signal loss of carrier and close */ 852 tp = &mp_tty[mb->mb_unit*MPCHUNK+port]; 853 ttyflush(tp, FREAD|FWRITE); 854 (void) (*linesw[tp->t_line].l_modem)(tp, 0); 855 } 856 } 857 858 mpclean(mb, port) 859 register struct mblok *mb; 860 int port; 861 { 862 register struct mpport *mp; 863 register struct mpevent *ev; 864 register int i; 865 u_char list[2]; 866 int unit; 867 868 mp = &mb->mb_port[port]; 869 unit = mb->mb_unit; 870 for (i = mp->mp_off; i != mp->mp_on; i = (i+1 % MPINSET)) { 871 ev = &mp->mp_recvq[i]; 872 ev->ev_error = ENXIO; 873 ev->ev_status = EVSTATUS_DONE; 874 } 875 list[0] = port, list[1] = MPPORT_EOL; 876 mpxintr(unit, list); 877 mprintr(unit, list); 878 /* Clear async for port */ 879 mp->mp_proto = MPPROTO_UNUSED; 880 mp->mp_flags = 0; 881 mp->mp_on = 0; 882 mp->mp_off = 0; 883 mp->mp_nextrcv = 0; 884 885 mp_tty[unit*MPCHUNK + port].t_state = 0; 886 for (ev = &mp->mp_sendq[0]; ev < &mp->mp_sendq[MPOUTSET]; ev++) { 887 ev->ev_status = EVSTATUS_FREE; 888 ev->ev_cmd = 0; 889 ev->ev_error = 0; 890 ev->ev_un.rcvblk = 0; 891 ev->ev_params = 0; 892 } 893 for (ev = &mp->mp_recvq[0]; ev < &mp->mp_recvq[MPINSET]; ev++) { 894 ev->ev_status = EVSTATUS_FREE; 895 ev->ev_cmd = 0; 896 ev->ev_error = 0; 897 ev->ev_params = 0; 898 } 899 } 900 901 /* 902 * MPCC interrupt handler. 903 */ 904 mpintr(mpcc) 905 int mpcc; 906 { 907 register struct mblok *mb; 908 register struct his *his; 909 910 mb = mp_softc[mpcc].ms_mb; 911 if (mb == 0) { 912 printf("mp%d: stray interrupt\n", mpcc); 913 return; 914 } 915 his = &mb->mb_hostint; 916 his->semaphore &= ~MPSEMA_AVAILABLE; 917 /* 918 * Check for events to be processed. 919 */ 920 if (his->proto[MPPROTO_ASYNC].outbdone[0] != MPPORT_EOL) 921 mprintr(mpcc, his->proto[MPPROTO_ASYNC].outbdone); 922 if (his->proto[MPPROTO_ASYNC].inbdone[0] != MPPORT_EOL) 923 mpxintr(mpcc, his->proto[MPPROTO_ASYNC].inbdone); 924 if (mb->mb_harderr || mb->mb_softerr) 925 mperror(mb, mpcc); 926 his->semaphore |= MPSEMA_AVAILABLE; 927 } 928 929 /* 930 * Handler for processing completion of transmitted events. 931 */ 932 mpxintr(unit, list) 933 register u_char *list; 934 { 935 register struct mpport *mp; 936 register struct mpevent *ev; 937 register struct mblok *mb; 938 register struct tty *tp; 939 register struct asyncparam *ap; 940 struct mpsoftc *ms; 941 int port, i, j; 942 # define nextevent(mp) &mp->mp_recvq[mp->mp_off] 943 944 ms = &mp_softc[unit]; 945 mb = mp_softc[unit].ms_mb; 946 for (j = 0; j < MPMAXPORT && ((port = *list++) != MPPORT_EOL); j++) { 947 /* 948 * Process each completed entry in the inbound queue. 949 */ 950 mp = &mb->mb_port[port]; 951 tp = &mp_tty[unit*MPCHUNK + port]; 952 ev = nextevent(mp); 953 for (; ev->ev_status & EVSTATUS_DONE; ev = nextevent(mp)) { 954 /* YUCK */ 955 ap = &ms->ms_async[port][mp->mp_off]; 956 mppurge((caddr_t)ap, (int)sizeof (*ap)); 957 switch (ev->ev_cmd) { 958 case EVCMD_OPEN: 959 /* 960 * Open completion, start all reads and 961 * assert modem status information. 962 */ 963 for (i = 0; i < MPOUTSET; i++) 964 mp->mp_sendq[i].ev_status = EVSTATUS_GO; 965 (*linesw[tp->t_line].l_modem) 966 (tp, ap->ap_modem.mc_dcd == ASSERT); 967 mp_freein(ev); 968 adjptr(mp->mp_off, MPINSET); 969 mp->mp_proto = MPPROTO_ASYNC; /* XXX */ 970 wakeup((caddr_t)&tp->t_canq); 971 break; 972 case EVCMD_CLOSE: 973 /* 974 * Close completion, flush all pending 975 * transmissions, free resources, and 976 * cleanup mpcc port state. 977 */ 978 for (i = 0; i < MPOUTSET; i++) { 979 mp->mp_sendq[i].ev_status = 980 EVSTATUS_FREE; 981 mp->mp_sendq[i].ev_un.rcvblk = 0; 982 mp->mp_sendq[i].ev_params = 0; 983 } 984 mp_freein(ev); 985 adjptr(mp->mp_off, MPINSET); 986 tp->t_state &= ~(TS_CARR_ON|TS_BUSY|TS_FLUSH); 987 mp->mp_on = mp->mp_off = mp->mp_nextrcv = 0; 988 mp->mp_flags &= ~MP_PROGRESS; 989 mp->mp_proto = MPPROTO_UNUSED; 990 wakeup((caddr_t)&tp->t_canq); 991 break; 992 case EVCMD_IOCTL: 993 mp_freein(ev); 994 adjptr(mp->mp_off, MPINSET); 995 mp->mp_flags &= ~MP_IOCTL; 996 wakeup((caddr_t)&tp->t_canq); 997 break; 998 case EVCMD_WRITE: 999 /* 1000 * Transmission completed, update tty 1001 * state and restart output. 1002 */ 1003 if (ev->ev_opts != A_FLUSH) { 1004 tp->t_state &= ~TS_BUSY; 1005 if (tp->t_state & TS_FLUSH) 1006 tp->t_state &= ~TS_FLUSH; 1007 else { 1008 register int cc = 0, n; 1009 struct hxmtl *hxp; 1010 1011 hxp = &ms->ms_hxl[port]; 1012 for (n=0;n < ev->ev_count; n++) 1013 cc += hxp->size[n]; 1014 ndflush(&tp->t_outq, cc); 1015 } 1016 } 1017 switch (ev->ev_error) { 1018 case A_SIZERR: /*# error in xmt data size */ 1019 mplog(unit, port, A_XSIZE, 0); 1020 break; 1021 case A_NXBERR: /*# no more xmt evt buffers */ 1022 mplog(unit, port, A_NOXBUF, 0); 1023 break; 1024 } 1025 mp_freein(ev); 1026 adjptr(mp->mp_off, MPINSET); 1027 mpstart(tp); 1028 break; 1029 default: 1030 mplog(unit, port, A_INVCMD, (int)ev->ev_cmd); 1031 mp_freein(ev); 1032 adjptr(mp->mp_off, MPINSET); 1033 break; 1034 } 1035 } 1036 } 1037 #undef nextevent 1038 } 1039 1040 mp_freein(ev) 1041 register struct mpevent *ev; 1042 { 1043 /* re-init all values in this entry */ 1044 ev->ev_cmd = 0; 1045 ev->ev_opts = 0; 1046 ev->ev_error = 0; 1047 ev->ev_flags = 0; 1048 ev->ev_count = 0; 1049 /* show this entry is available for use */ 1050 ev->ev_status = EVSTATUS_FREE; 1051 } 1052 1053 /* 1054 * Handler for processing received events. 1055 */ 1056 mprintr(unit, list) 1057 u_char *list; 1058 { 1059 register struct tty *tp; 1060 register struct mpport *mp; 1061 register struct mpevent *ev; 1062 struct mblok *mb; 1063 register int cc; 1064 register char *cp; 1065 struct mpsoftc *ms; 1066 caddr_t ptr; 1067 char *rcverr; 1068 int port, i; 1069 1070 ms = &mp_softc[unit]; 1071 mb = mp_softc[unit].ms_mb; 1072 for (i = 0; i < MPMAXPORT && (port = *list++) != MPPORT_EOL; i++) { 1073 tp = &mp_tty[unit*MPCHUNK + port]; 1074 mp = &mb->mb_port[port]; 1075 ev = &mp->mp_sendq[mp->mp_nextrcv]; 1076 while (ev->ev_status & EVSTATUS_DONE) { 1077 switch(ev->ev_cmd) { 1078 case EVCMD_STATUS: 1079 /* 1080 * Status change, look for carrier changes. 1081 */ 1082 switch(ev->ev_opts) { 1083 case DCDASRT: 1084 (*linesw[tp->t_line].l_modem)(tp, 1); 1085 wakeup((caddr_t)&tp->t_canq); 1086 break; 1087 case DCDDROP: 1088 (*linesw[tp->t_line].l_modem)(tp, 0); 1089 wakeup((caddr_t)&tp->t_canq); 1090 break; 1091 case NORBUF: 1092 case NOEBUF: 1093 mplog(unit, port, 1094 "out of receive events", 0); 1095 break; 1096 default: 1097 mplog(unit, port, 1098 "unexpect status command", 1099 (int)ev->ev_opts); 1100 break; 1101 } 1102 break; 1103 case EVCMD_READ: 1104 /* 1105 * Process received data. 1106 */ 1107 if ((tp->t_state & TS_ISOPEN) == 0) { 1108 wakeup((caddr_t)&tp->t_rawq); 1109 break; 1110 } 1111 if ((cc = ev->ev_count) == 0) 1112 break; 1113 cp = ms->ms_cbuf[port][mp->mp_nextrcv]; 1114 mppurge(cp, CBSIZE); 1115 while (cc-- > 0) { 1116 /* 1117 * A null character is inserted, 1118 * potentially when a break or framing 1119 * error occurs. If we're not in raw 1120 * mode, substitute the interrupt 1121 * character. 1122 */ 1123 /*** XXX - FIXUP ***/ 1124 if (*cp == 0 && 1125 (ev->ev_error == BRKASRT || 1126 ev->ev_error == FRAMERR)) 1127 if ((tp->t_flags&RAW) == 0) 1128 ; 1129 /* XXX was break */ 1130 (*linesw[tp->t_line].l_rint)(*cp++, tp); 1131 } 1132 /* setup for next read */ 1133 ptr = (caddr_t)&mp_softc[unit].ms_cbuf[port][mp->mp_nextrcv][0]; 1134 ev->ev_un.rcvblk = (u_char *)kvtophys(ptr); 1135 ev->ev_params = (caddr_t) kvtophys(ptr); 1136 switch(ev->ev_error) { 1137 case RCVDTA: 1138 /* Normal (good) rcv data do not 1139 * report the following they are 1140 * "normal" errors 1141 */ 1142 case FRAMERR: 1143 /* frame error */ 1144 case BRKASRT: 1145 /* Break condition */ 1146 case PARERR: 1147 /* parity error */ 1148 rcverr = (char *)0; 1149 break; 1150 case OVRNERR: 1151 /* Overrun error */ 1152 rcverr = "overrun error"; 1153 break; 1154 case OVFERR: 1155 /* Overflow error */ 1156 rcverr = "overflow error"; 1157 break; 1158 default: 1159 rcverr = "undefined rcv error"; 1160 break; 1161 } 1162 if (rcverr != (char *)0) 1163 mplog(unit, port, rcverr, 1164 (int)ev->ev_error); 1165 break; 1166 default: 1167 mplog(unit, port, "unexpected command", 1168 (int)ev->ev_cmd); 1169 break; 1170 } 1171 ev->ev_cmd = 0; 1172 ev->ev_opts = 0; 1173 ev->ev_error = 0; 1174 ev->ev_flags = 0; 1175 ev->ev_count = 0; 1176 ev->ev_status = EVSTATUS_GO; /* start next read */ 1177 adjptr(mp->mp_nextrcv, MPOUTSET); 1178 ev = &mp->mp_sendq[mp->mp_nextrcv]; 1179 } 1180 } 1181 } 1182 1183 /* 1184 * Log an mpcc diagnostic. 1185 */ 1186 mplog(unit, port, cp, flags) 1187 char *cp; 1188 { 1189 1190 if (flags) 1191 log(LOG_ERR, "mp%d: port%d, %s (%d)\n", 1192 unit, port, cp, flags); 1193 else 1194 log(LOG_ERR, "mp%d: port%d, %s\n", unit, port, cp); 1195 } 1196 1197 int MPHOSTINT = 1; 1198 1199 mptimeint(mb) 1200 register struct mblok *mb; 1201 { 1202 1203 mb->mb_mpintcnt = 0; 1204 mb->mb_mpintclk = (caddr_t)0; 1205 *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 1206 } 1207 1208 /* 1209 * Interupt mpcc 1210 */ 1211 mpintmpcc(mb, port) 1212 register struct mblok *mb; 1213 { 1214 1215 mb->mb_intr[port] |= MPSEMA_WORK; 1216 if (++mb->mb_mpintcnt == MPHOSTINT) { 1217 mb->mb_mpintcnt = 0; 1218 *(u_short *)mpinfo[mb->mb_unit]->ui_addr = 2; 1219 if (mb->mb_mpintclk) { 1220 untimeout(mptimeint, (caddr_t)mb); 1221 mb->mb_mpintclk = 0; 1222 } 1223 } else { 1224 if (mb->mb_mpintclk == 0) { 1225 timeout(mptimeint, (caddr_t)mb, 4); 1226 mb->mb_mpintclk = (caddr_t)1; 1227 } 1228 } 1229 } 1230 1231 static char *mpherrmsg[] = { 1232 "", 1233 "Bus error", /* MPBUSERR */ 1234 "Address error", /* ADDRERR */ 1235 "Undefined ecc interrupt", /* UNDECC */ 1236 "Undefined interrupt", /* UNDINT */ 1237 "Power failure occurred", /* PWRFL */ 1238 "Stray transmit done interrupt", /* NOXENTRY */ 1239 "Two fast timers on one port", /* TWOFTMRS */ 1240 "Interrupt queue full", /* INTQFULL */ 1241 "Interrupt queue ack error", /* INTQERR */ 1242 "Uncorrectable dma parity error", /* CBPERR */ 1243 "32 port ACAP failed power up", /* ACPDEAD */ 1244 }; 1245 #define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0])) 1246 1247 mperror(mb, unit) 1248 register struct mblok *mb; 1249 int unit; 1250 { 1251 register char *cp; 1252 register int i; 1253 1254 if (mb->mb_softerr) { 1255 switch (mb->mb_softerr) { 1256 case DMAPERR: /* dma parity error */ 1257 cp = "dma parity error"; 1258 break; 1259 case ECCERR: 1260 cp = "local memory ecc error"; 1261 break; 1262 default: 1263 cp = "unknown error"; 1264 break; 1265 } 1266 log(LOG_ERR, "mp%d: soft error, %s", unit, cp); 1267 mb->mb_softerr = 0; 1268 } 1269 if (mb->mb_harderr) { 1270 if (mb->mb_harderr < NHERRS) 1271 cp = mpherrmsg[mb->mb_harderr]; 1272 else 1273 cp = "unknown error"; 1274 log(LOG_ERR, "mp%d: hard error, %s", unit, cp); 1275 if (mb->mb_status == MP_OPOPEN) { 1276 for (i = 0; i < MPMAXPORT; i++) { 1277 mpcleanport(mb, i); 1278 mb->mb_proto[i] = MPPROTO_UNUSED; 1279 } 1280 } 1281 mb->mb_harderr = 0; 1282 mb->mb_status = 0; 1283 } 1284 } 1285 1286 mppurge(addr, cc) 1287 register caddr_t addr; 1288 register int cc; 1289 { 1290 1291 for (; cc >= 0; addr += NBPG, cc -= NBPG) 1292 mtpr(P1DC, addr); 1293 } 1294 1295 /* 1296 * MPCC Download Pseudo-device. 1297 */ 1298 char mpdlbuf[MPDLBUFSIZE]; 1299 int mpdlbusy; /* interlock on download buffer */ 1300 int mpdlerr; 1301 1302 mpdlopen(dev) 1303 dev_t dev; 1304 { 1305 int unit, mpu; 1306 struct vba_device *vi; 1307 1308 unit = minor(dev); 1309 mpu = MPUNIT(unit); 1310 if (mpu >= NMP || (vi = mpinfo[mpu]) == 0 || vi->ui_alive == 0) 1311 return (ENODEV); 1312 return (0); 1313 } 1314 1315 mpdlwrite(dev, uio) 1316 dev_t dev; 1317 struct uio *uio; 1318 { 1319 register struct mpsoftc *ms = &mp_softc[MPUNIT(minor(dev))]; 1320 register struct mpdl *dl; 1321 int error; 1322 1323 if (ms->ms_mb == 0 || ms->ms_mb->mb_status != MP_DLOPEN) 1324 return (EFAULT); 1325 dl = &ms->ms_mb->mb_dl; 1326 dl->mpdl_count = uio->uio_iov->iov_len; 1327 dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 1328 if (error = uiomove(mpdlbuf, (int)dl->mpdl_count, uio)) 1329 return (error); 1330 uio->uio_resid -= dl->mpdl_count; /* set up return from write */ 1331 dl->mpdl_cmd = MPDLCMD_NORMAL; 1332 error = mpdlwait(dl); 1333 return (error); 1334 } 1335 1336 mpdlclose(dev) 1337 dev_t dev; 1338 { 1339 register struct mblok *mb = mp_softc[MPUNIT(minor(dev))].ms_mb; 1340 1341 if (mb == 0 || mb->mb_status != MP_DLDONE) { 1342 mpbogus.status = 0; 1343 if (mpbogus.mb == mpbogus.mbloks[MPUNIT(minor(dev))]) 1344 mpdlbusy--; 1345 return (EEXIST); 1346 } 1347 mb->mb_status = MP_OPOPEN; 1348 mpbogus.status = 0; 1349 /* set to dead, for board handshake */ 1350 mb->mb_hostint.imok = MPIMOK_DEAD; 1351 return (0); 1352 } 1353 1354 /* ARGSUSED */ 1355 mpdlioctl(dev, cmd, data, flag) 1356 dev_t dev; 1357 caddr_t data; 1358 { 1359 register struct mblok *mb; 1360 register struct mpdl *dl; 1361 int unit, error = 0, s, i; 1362 1363 mb = mp_softc[unit=MPUNIT(minor(dev))].ms_mb; 1364 if (mb == 0) 1365 return (EEXIST); 1366 dl = &mb->mb_dl; 1367 error = 0; 1368 switch (cmd) { 1369 case MPIOPORTMAP: 1370 bcopy(data, (caddr_t)mb->mb_proto, sizeof (mb->mb_proto)); 1371 break; 1372 case MPIOHILO: 1373 bcopy(data, (caddr_t)&mb->mb_hiport, 2*(sizeof(mb->mb_hiport))); 1374 break; 1375 case MPIOENDDL: 1376 dl->mpdl_count = 0; 1377 dl->mpdl_data = 0; 1378 dl->mpdl_cmd = MPIOENDDL&IOCPARM_MASK; 1379 error = mpdlwait(dl); 1380 mpccinit(unit); 1381 mb->mb_status = MP_DLDONE; 1382 mpdlbusy--; 1383 break; 1384 case MPIOENDCODE: 1385 dl->mpdl_count = 0; 1386 dl->mpdl_data = 0; 1387 dl->mpdl_cmd = MPIOENDCODE&IOCPARM_MASK; 1388 error = mpdlwait(dl); 1389 break; 1390 case MPIOASYNCNF: 1391 bcopy(data, mpdlbuf, sizeof (struct abdcf)); 1392 dl->mpdl_data = (caddr_t) kvtophys(mpdlbuf); 1393 dl->mpdl_count = sizeof (struct abdcf); 1394 dl->mpdl_cmd = MPIOASYNCNF&IOCPARM_MASK; 1395 error = mpdlwait(dl); 1396 break; 1397 case MPIOSTARTDL: 1398 s = spl8(); 1399 while (mpdlbusy) 1400 if (error = tsleep((caddr_t)&mpdlbusy, 1401 (PZERO+1) | PCATCH, devioc, 0)) 1402 break; 1403 splx(s); 1404 if (error) 1405 break; 1406 mpdlbusy++; 1407 /* initialize the downloading interface */ 1408 mpbogus.magic = MPMAGIC; 1409 mpbogus.mb = mpbogus.mbloks[unit]; 1410 mpbogus.status = 1; 1411 dl->mpdl_status = EVSTATUS_FREE; 1412 dl->mpdl_count = 0; 1413 dl->mpdl_cmd = 0; 1414 dl->mpdl_data = (char *) 0; 1415 mpdlerr = 0; 1416 mb->mb_magic = MPMAGIC; 1417 mb->mb_ivec = mp_softc[unit].ms_ivec+1; /* download vector */ 1418 mb->mb_status = MP_DLPEND; 1419 mb->mb_diagswitch[0] = 'A'; 1420 mb->mb_diagswitch[1] = 'P'; 1421 s = spl8(); 1422 *(u_short *)mpinfo[unit]->ui_addr = 2; 1423 error = tsleep((caddr_t)&mb->mb_status, (PZERO+1) | PCATCH, 1424 devio, 30*hz); 1425 splx(s); 1426 if (error == EWOULDBLOCK) 1427 error = ETIMEDOUT; 1428 if (error) 1429 mpbogus.status = 0; 1430 bzero((caddr_t)mb->mb_port, sizeof (mb->mb_port)); 1431 break; 1432 case MPIORESETBOARD: 1433 s = spl8(); 1434 if (mb->mb_imokclk) 1435 mb->mb_imokclk = 0; 1436 *(u_short *)mpinfo[unit]->ui_addr = 0x100; 1437 if (mb->mb_status == MP_DLOPEN || mb->mb_status == MP_DLDONE) { 1438 mpdlerr = MP_DLERROR; 1439 dl->mpdl_status = EVSTATUS_FREE; 1440 wakeup((caddr_t)&dl->mpdl_status); 1441 mpbogus.status = 0; 1442 } 1443 for (i = 0; i < MPMAXPORT; i++) { 1444 if (mb->mb_harderr || mb->mb_softerr) 1445 mperror(mb, i); 1446 mpcleanport(mb, i); 1447 mb->mb_proto[i] = MPPROTO_UNUSED; 1448 } 1449 mb->mb_status = 0; 1450 splx(s); 1451 break; 1452 default: 1453 error = EINVAL; 1454 break; 1455 } 1456 return (error); 1457 } 1458 1459 mpccinit(unit) 1460 int unit; 1461 { 1462 register struct mblok *mb = mp_softc[unit].ms_mb; 1463 register struct his *his; 1464 register int i, j; 1465 1466 mb->mb_status = MP_DLDONE; 1467 mb->mb_ivec = mp_softc[unit].ms_ivec; 1468 mb->mb_magic = MPMAGIC; 1469 /* Init host interface structure */ 1470 his = &mb->mb_hostint; 1471 his->semaphore = MPSEMA_AVAILABLE; 1472 for (i = 0; i < NMPPROTO; i++) 1473 for (j = 0; j < MPMAXPORT; j++) { 1474 his->proto[i].inbdone[j] = MPPORT_EOL; 1475 his->proto[i].outbdone[j] = MPPORT_EOL; 1476 } 1477 mb->mb_unit = unit; 1478 } 1479 1480 mpdlintr(mpcc) 1481 int mpcc; 1482 { 1483 register struct mblok *mb; 1484 register struct mpdl *dl; 1485 1486 mb = mp_softc[mpcc].ms_mb; 1487 if (mb == 0) { 1488 printf("mp%d: stray download interrupt\n", mpcc); 1489 return; 1490 } 1491 dl = &mb->mb_dl; 1492 switch (mb->mb_status) { 1493 case MP_DLOPEN: 1494 if (dl->mpdl_status != EVSTATUS_DONE) 1495 mpdlerr = MP_DLERROR; 1496 dl->mpdl_status = EVSTATUS_FREE; 1497 wakeup((caddr_t)&dl->mpdl_status); 1498 return; 1499 case MP_DLPEND: 1500 mb->mb_status = MP_DLOPEN; 1501 wakeup((caddr_t)&mb->mb_status); 1502 /* fall thru... */ 1503 case MP_DLTIME: 1504 return; 1505 case MP_OPOPEN: 1506 if (mb->mb_imokclk) 1507 mb->mb_imokclk = 0; 1508 mb->mb_nointcnt = 0; /* reset no interrupt count */ 1509 mb->mb_hostint.imok = MPIMOK_DEAD; 1510 mb->mb_imokclk = (caddr_t)1; 1511 break; 1512 default: 1513 log(LOG_ERR, "mp%d: mpdlintr, status %x\n", 1514 mpcc, mb->mb_status); 1515 break; 1516 } 1517 } 1518 1519 /* 1520 * Wait for a transfer to complete or a timeout to occur. 1521 */ 1522 mpdlwait(dl) 1523 register struct mpdl *dl; 1524 { 1525 int s, error = 0; 1526 1527 s = spl8(); 1528 dl->mpdl_status = EVSTATUS_GO; 1529 while (dl->mpdl_status != EVSTATUS_FREE) { 1530 error = tsleep((caddr_t)&dl->mpdl_status, (PZERO+1) | PCATCH, 1531 devout, 0); 1532 if (mpdlerr == MP_DLERROR) 1533 error = EIO; 1534 if (error) 1535 break; 1536 } 1537 splx(s); 1538 return (error); 1539 } 1540 #endif 1541