1 /* $NetBSD: mfc.c,v 1.5 1995/04/23 18:24:38 chopps Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Michael L. Hitch 5 * Copyright (c) 1982, 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/device.h> 41 #include <sys/tty.h> 42 #include <sys/proc.h> 43 #include <sys/conf.h> 44 #include <sys/file.h> 45 #include <sys/malloc.h> 46 #include <sys/uio.h> 47 #include <sys/kernel.h> 48 #include <sys/syslog.h> 49 #include <sys/queue.h> 50 #include <machine/cpu.h> 51 #include <amiga/amiga/device.h> 52 #include <amiga/amiga/isr.h> 53 #include <amiga/amiga/custom.h> 54 #include <amiga/amiga/cia.h> 55 #include <amiga/amiga/cc.h> 56 #include <amiga/dev/zbusvar.h> 57 58 #include <dev/cons.h> 59 60 #include "mfcs.h" 61 62 #define SEROBUF_SIZE 128 63 #define SERIBUF_SIZE 1024 64 65 #define splser() spl6() 66 67 /* 68 * 68581 DUART registers 69 */ 70 struct mfc_regs { 71 volatile u_char du_mr1a; 72 #define du_mr2a du_mr1a 73 u_char pad0; 74 volatile u_char du_csra; 75 #define du_sra du_csra 76 u_char pad2; 77 volatile u_char du_cra; 78 u_char pad4; 79 volatile u_char du_tba; 80 #define du_rba du_tba 81 u_char pad6; 82 volatile u_char du_acr; 83 #define du_ipcr du_acr 84 u_char pad8; 85 volatile u_char du_imr; 86 #define du_isr du_imr 87 u_char pad10; 88 volatile u_char du_ctur; 89 #define du_cmsb du_ctur 90 u_char pad12; 91 volatile u_char du_ctlr; 92 #define du_clsb du_ctlr 93 u_char pad14; 94 volatile u_char du_mr1b; 95 #define du_mr2b du_mr1b 96 u_char pad16; 97 volatile u_char du_csrb; 98 #define du_srb du_csrb 99 u_char pad18; 100 volatile u_char du_crb; 101 u_char pad20; 102 volatile u_char du_tbb; 103 #define du_rbb du_tbb 104 u_char pad22; 105 volatile u_char du_ivr; 106 u_char pad24; 107 volatile u_char du_opcr; 108 #define du_ip du_opcr 109 u_char pad26; 110 volatile u_char du_btst; 111 #define du_strc du_btst 112 u_char pad28; 113 volatile u_char du_btrst; 114 #define du_stpc du_btrst 115 u_char pad30; 116 }; 117 118 /* 119 * 68681 DUART serial port registers 120 */ 121 struct duart_regs { 122 volatile u_char ch_mr1; 123 #define ch_mr2 ch_mr1 124 u_char pad0; 125 volatile u_char ch_csr; 126 #define ch_sr ch_csr 127 u_char pad1; 128 volatile u_char ch_cr; 129 u_char pad2; 130 volatile u_char ch_tb; 131 #define ch_rb ch_tb 132 u_char pad3; 133 }; 134 135 struct mfc_softc { 136 struct device sc_dev; 137 struct isr sc_isr; 138 struct mfc_regs *sc_regs; 139 u_long clk_frq; 140 u_short ct_val; 141 u_char ct_usecnt; 142 u_char imask; 143 u_char mfc_iii; 144 u_char last_ip; 145 }; 146 147 #if NMFCS > 0 148 struct mfcs_softc { 149 struct device sc_dev; 150 struct duart_regs *sc_duart; 151 struct mfc_regs *sc_regs; 152 struct mfc_softc *sc_mfc; 153 long flags; /* XXX */ 154 #define CT_USED 1 /* CT in use */ 155 u_short *rptr, *wptr, incnt, ovfl; 156 u_short inbuf[SERIBUF_SIZE]; 157 char *ptr, *end; 158 char outbuf[SEROBUF_SIZE]; 159 }; 160 #endif 161 162 #if NMFCP > 0 163 struct mfcp_softc { 164 }; 165 #endif 166 167 struct mfc_args { 168 struct zbus_args zargs; 169 char *subdev; 170 char unit; 171 }; 172 173 int mfcprint __P((void *auxp, char *)); 174 void mfcattach __P((struct device *, struct device *, void *)); 175 int mfcmatch __P((struct device *, struct cfdata *, void *)); 176 #if NMFCS > 0 177 void mfcsattach __P((struct device *, struct device *, void *)); 178 int mfcsmatch __P((struct device *, struct cfdata *, void *)); 179 #endif 180 #if NMFCP > 0 181 void mfcpattach __P((struct device *, struct device *, void *)); 182 int mfcpmatch __P((struct device *, struct cfdata *, void *)); 183 #endif 184 int mfcintr __P((struct mfc_softc *)); 185 void mfcsmint __P((register int unit)); 186 187 struct cfdriver mfccd = { 188 NULL, "mfc", (cfmatch_t) mfcmatch, mfcattach, 189 DV_DULL, sizeof(struct mfc_softc), NULL, 0 }; 190 191 #if NMFCS > 0 192 struct cfdriver mfcscd = { 193 NULL, "mfcs", (cfmatch_t) mfcsmatch, mfcsattach, 194 DV_TTY, sizeof(struct mfcs_softc), NULL, 0 }; 195 #endif 196 197 #if NMFCP > 0 198 struct cfdriver mfcpcd = { 199 NULL, "mfcp", (cfmatch_t) mfcpmatch, mfcpattach, 200 DV_DULL, sizeof(struct mfcp_softc), NULL, 0 }; 201 #endif 202 203 int mfcsstart(), mfcsparam(), mfcshwiflow(); 204 int mfcs_active; 205 int mfcsdefaultrate = 38400 /*TTYDEF_SPEED*/; 206 int mfcsswflags[NMFCS]; 207 #define SWFLAGS(dev) (mfcsswflags[dev & 31] | (((dev) & 0x80) == 0 ? TIOCFLAG_SOFTCAR : 0)) 208 209 struct vbl_node mfcs_vbl_node[NMFCS]; 210 struct tty *mfcs_tty[NMFCS]; 211 212 #ifdef notyet 213 /* 214 * MultiFaceCard III, II+ (not supported yet), and 215 * SerialMaster 500+ (not supported yet) 216 * baud rate tables for BRG set 1 [not used yet] 217 */ 218 219 struct speedtab mfcs3speedtab1[] = { 220 0, 0, 221 100, 0x00, 222 220, 0x11, 223 600, 0x44, 224 1200, 0x55, 225 2400, 0x66, 226 4800, 0x88, 227 9600, 0x99, 228 19200, 0xbb, 229 115200, 0xcc, 230 -1, -1 231 }; 232 233 /* 234 * MultiFaceCard II, I, and SerialMaster 500 235 * baud rate tables for BRG set 1 [not used yet] 236 */ 237 238 struct speedtab mfcs2speedtab1[] = { 239 0, 0, 240 50, 0x00, 241 110, 0x11, 242 300, 0x44, 243 600, 0x55, 244 1200, 0x66, 245 2400, 0x88, 246 4800, 0x99, 247 9600, 0xbb, 248 38400, 0xcc, 249 -1, -1 250 }; 251 #endif 252 253 /* 254 * MultiFaceCard III, II+ (not supported yet), and 255 * SerialMaster 500+ (not supported yet) 256 * baud rate tables for BRG set 2 257 */ 258 259 struct speedtab mfcs3speedtab2[] = { 260 0, 0, 261 150, 0x00, 262 200, 0x11, 263 300, 0x33, 264 600, 0x44, 265 1200, 0x55, 266 2400, 0x66, 267 4800, 0x88, 268 9600, 0x99, 269 19200, 0xbb, 270 38400, 0xcc, 271 -1, -1 272 }; 273 274 /* 275 * MultiFaceCard II, I, and SerialMaster 500 276 * baud rate tables for BRG set 2 277 */ 278 279 struct speedtab mfcs2speedtab2[] = { 280 0, 0, 281 75, 0x00, 282 100, 0x11, 283 150, 0x33, 284 300, 0x44, 285 600, 0x55, 286 1200, 0x66, 287 2400, 0x88, 288 4800, 0x99, 289 9600, 0xbb, 290 19200, 0xcc, 291 -1, -1 292 }; 293 294 /* 295 * if we are an bsc/Alf Data MultFaceCard (I, II, and III) 296 */ 297 int 298 mfcmatch(pdp, cdp, auxp) 299 struct device *pdp; 300 struct cfdata *cdp; 301 void *auxp; 302 { 303 struct zbus_args *zap; 304 305 zap = auxp; 306 if (zap->manid == 2092 && 307 (zap->prodid == 16 || zap->prodid == 17 || zap->prodid == 18)) 308 309 return(1); 310 return(0); 311 } 312 313 void 314 mfcattach(pdp, dp, auxp) 315 struct device *pdp, *dp; 316 void *auxp; 317 { 318 struct mfc_softc *scc; 319 struct zbus_args *zap; 320 struct mfc_args ma; 321 int unit; 322 struct mfc_regs *rp; 323 324 zap = auxp; 325 326 printf ("\n"); 327 328 scc = (struct mfc_softc *)dp; 329 unit = scc->sc_dev.dv_unit; 330 scc->sc_regs = rp = zap->va; 331 if (zap->prodid == 18) 332 scc->mfc_iii = 3; 333 scc->clk_frq = scc->mfc_iii ? 230400 : 115200; 334 335 rp->du_opcr = 0x00; /* configure output port? */ 336 rp->du_btrst = 0x0f; /* clear modem lines */ 337 rp->du_ivr = 0; /* IVR */ 338 rp->du_imr = 0; /* IMR */ 339 rp->du_acr = 0xe0; /* baud rate generate set 2 */ 340 rp->du_ctur = 0; 341 rp->du_ctlr = 4; 342 rp->du_csra = 0xcc; /* clock select = 38400 */ 343 rp->du_cra = 0x10; /* reset mode register ptr */ 344 rp->du_cra = 0x20; 345 rp->du_cra = 0x30; 346 rp->du_cra = 0x40; 347 rp->du_mr1a = 0x93; /* MRA1 */ 348 rp->du_mr2a = 0x17; /* MRA2 */ 349 rp->du_csrb = 0xcc; /* clock select = 38400 */ 350 rp->du_crb = 0x10; /* reset mode register ptr */ 351 rp->du_crb = 0x20; 352 rp->du_crb = 0x30; 353 rp->du_crb = 0x40; 354 rp->du_mr1b = 0x93; /* MRB1 */ 355 rp->du_mr2b = 0x17; /* MRB2 */ 356 rp->du_cra = 0x05; /* enable A Rx & Tx */ 357 rp->du_crb = 0x05; /* enable B Rx & Tx */ 358 359 scc->sc_isr.isr_intr = mfcintr; 360 scc->sc_isr.isr_arg = scc; 361 scc->sc_isr.isr_ipl = 6; 362 add_isr(&scc->sc_isr); 363 364 /* configure ports */ 365 bcopy(zap, &ma.zargs, sizeof(struct zbus_args)); 366 ma.subdev = "mfcs"; 367 ma.unit = unit * 2; 368 config_found(dp, &ma, mfcprint); 369 ma.unit = unit * 2 + 1; 370 config_found(dp, &ma, mfcprint); 371 ma.subdev = "mfcp"; 372 ma.unit = unit; 373 config_found(dp, &ma, mfcprint); 374 } 375 376 /* 377 * 378 */ 379 int 380 mfcsmatch(pdp, cdp, auxp) 381 struct device *pdp; 382 struct cfdata *cdp; 383 void *auxp; 384 { 385 struct mfc_args *ma; 386 387 ma = auxp; 388 if (strcmp(ma->subdev, "mfcs") == 0) 389 return (1); 390 return (0); 391 } 392 393 void 394 mfcsattach(pdp, dp, auxp) 395 struct device *pdp, *dp; 396 void *auxp; 397 { 398 int unit; 399 struct mfcs_softc *sc; 400 struct mfc_softc *scc; 401 struct mfc_args *ma; 402 struct mfc_regs *rp; 403 404 sc = (struct mfcs_softc *) dp; 405 scc = (struct mfc_softc *) pdp; 406 ma = auxp; 407 408 if (dp) { 409 printf (": input fifo %d output fifo %d\n", SERIBUF_SIZE, 410 SEROBUF_SIZE); 411 alloc_sicallback(); 412 } 413 414 unit = ma->unit; 415 mfcs_active |= 1 << unit; 416 sc->rptr = sc->wptr = sc->inbuf; 417 sc->sc_mfc = scc; 418 sc->sc_regs = rp = scc->sc_regs; 419 sc->sc_duart = (struct duart_regs *) ((unit & 1) ? &rp->du_mr1b : 420 &rp->du_mr1a); 421 /* 422 * should have only one vbl routine to handle all ports? 423 */ 424 mfcs_vbl_node[unit].function = (void (*) (void *)) mfcsmint; 425 mfcs_vbl_node[unit].data = (void *) unit; 426 add_vbl_function(&mfcs_vbl_node[unit], 1, (void *) unit); 427 } 428 429 /* 430 * print diag if pnp is NULL else just extra 431 */ 432 int 433 mfcprint(auxp, pnp) 434 void *auxp; 435 char *pnp; 436 { 437 if (pnp == NULL) 438 return(UNCONF); 439 return(QUIET); 440 } 441 442 int 443 mfcsopen(dev, flag, mode, p) 444 dev_t dev; 445 int flag, mode; 446 struct proc *p; 447 { 448 struct tty *tp; 449 int unit, error, s; 450 451 error = 0; 452 unit = dev & 0x1f; 453 454 if (unit >= NMFCS || (mfcs_active & (1 << unit)) == 0) 455 return (ENXIO); 456 457 s = spltty(); 458 459 if (mfcs_tty[unit]) 460 tp = mfcs_tty[unit]; 461 else 462 tp = mfcs_tty[unit] = ttymalloc(); 463 464 tp->t_oproc = (void (*) (struct tty *)) mfcsstart; 465 tp->t_param = mfcsparam; 466 tp->t_dev = dev; 467 tp->t_hwiflow = mfcshwiflow; 468 469 if ((tp->t_state & TS_ISOPEN) == 0) { 470 tp->t_state |= TS_WOPEN; 471 ttychars(tp); 472 if (tp->t_ispeed == 0) { 473 /* 474 * only when cleared do we reset to defaults. 475 */ 476 tp->t_iflag = TTYDEF_IFLAG; 477 tp->t_oflag = TTYDEF_OFLAG; 478 tp->t_cflag = TTYDEF_CFLAG; 479 tp->t_lflag = TTYDEF_LFLAG; 480 tp->t_ispeed = tp->t_ospeed = mfcsdefaultrate; 481 } 482 /* 483 * do these all the time 484 */ 485 if (mfcsswflags[unit] & TIOCFLAG_CLOCAL) 486 tp->t_cflag |= CLOCAL; 487 if (mfcsswflags[unit] & TIOCFLAG_CRTSCTS) 488 tp->t_cflag |= CRTSCTS; 489 if (mfcsswflags[unit] & TIOCFLAG_MDMBUF) 490 tp->t_cflag |= MDMBUF; 491 mfcsparam(tp, &tp->t_termios); 492 ttsetwater(tp); 493 494 (void)mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET); 495 if ((SWFLAGS(dev) & TIOCFLAG_SOFTCAR) || 496 (mfcsmctl(dev, 0, DMGET) & TIOCM_CD)) 497 tp->t_state |= TS_CARR_ON; 498 else 499 tp->t_state &= ~TS_CARR_ON; 500 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { 501 splx(s); 502 return(EBUSY); 503 } 504 505 /* 506 * if NONBLOCK requested, ignore carrier 507 */ 508 if (flag & O_NONBLOCK) 509 goto done; 510 511 /* 512 * block waiting for carrier 513 */ 514 while ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) { 515 tp->t_state |= TS_WOPEN; 516 error = ttysleep(tp, (caddr_t)&tp->t_rawq, 517 TTIPRI | PCATCH, ttopen, 0); 518 if (error) { 519 splx(s); 520 return(error); 521 } 522 } 523 done: 524 /* This is a way to handle lost XON characters */ 525 if ((flag & O_TRUNC) && (tp->t_state & TS_TTSTOP)) { 526 tp->t_state &= ~TS_TTSTOP; 527 ttstart (tp); 528 } 529 530 splx(s); 531 /* 532 * Reset the tty pointer, as there could have been a dialout 533 * use of the tty with a dialin open waiting. 534 */ 535 tp->t_dev = dev; 536 return((*linesw[tp->t_line].l_open)(dev, tp)); 537 } 538 539 /*ARGSUSED*/ 540 int 541 mfcsclose(dev, flag, mode, p) 542 dev_t dev; 543 int flag, mode; 544 struct proc *p; 545 { 546 struct tty *tp; 547 int unit; 548 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31]; 549 struct mfc_softc *scc= sc->sc_mfc; 550 551 unit = dev & 31; 552 553 tp = mfcs_tty[unit]; 554 (*linesw[tp->t_line].l_close)(tp, flag); 555 sc->sc_duart->ch_cr = 0x70; /* stop break */ 556 557 scc->imask &= ~(0x7 << ((unit & 1) * 4)); 558 scc->sc_regs->du_imr = scc->imask; 559 if (sc->flags & CT_USED) { 560 --scc->ct_usecnt; 561 sc->flags &= ~CT_USED; 562 } 563 564 /* 565 * If the device is closed, it's close, no matter whether we deal with 566 * modem control signals nor not. 567 */ 568 #if 0 569 if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || 570 (tp->t_state & TS_ISOPEN) == 0) 571 #endif 572 (void) mfcsmctl(dev, 0, DMSET); 573 ttyclose(tp); 574 #if not_yet 575 if (tp != &mfcs_cons) { 576 remove_vbl_function(&mfcs_vbl_node[unit]); 577 ttyfree(tp); 578 mfcs_tty[unit] = (struct tty *) NULL; 579 } 580 #endif 581 return (0); 582 } 583 584 int 585 mfcsread(dev, uio, flag) 586 dev_t dev; 587 struct uio *uio; 588 int flag; 589 { 590 struct tty *tp; 591 if ((tp = mfcs_tty[dev & 31]) == NULL) 592 return(ENXIO); 593 return((*linesw[tp->t_line].l_read)(tp, uio, flag)); 594 } 595 596 int 597 mfcswrite(dev, uio, flag) 598 dev_t dev; 599 struct uio *uio; 600 int flag; 601 { 602 struct tty *tp; 603 604 if ((tp = mfcs_tty[dev & 31]) == NULL) 605 return(ENXIO); 606 return((*linesw[tp->t_line].l_write)(tp, uio, flag)); 607 } 608 609 struct tty * 610 mfcstty(dev) 611 dev_t dev; 612 { 613 return (mfcs_tty[dev & 31]); 614 } 615 616 int 617 mfcsioctl(dev, cmd, data, flag, p) 618 dev_t dev; 619 caddr_t data; 620 struct proc *p; 621 { 622 register struct tty *tp; 623 register int unit = dev & 31; 624 register int error; 625 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31]; 626 627 tp = mfcs_tty[unit]; 628 if (!tp) 629 return ENXIO; 630 631 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 632 if (error >= 0) 633 return(error); 634 635 error = ttioctl(tp, cmd, data, flag, p); 636 if (error >= 0) 637 return(error); 638 639 switch (cmd) { 640 case TIOCSBRK: 641 sc->sc_duart->ch_cr = 0x60; /* start break */ 642 break; 643 644 case TIOCCBRK: 645 sc->sc_duart->ch_cr = 0x70; /* stop break */ 646 break; 647 648 case TIOCSDTR: 649 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); 650 break; 651 652 case TIOCCDTR: 653 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); 654 break; 655 656 case TIOCMSET: 657 (void) mfcsmctl(dev, *(int *) data, DMSET); 658 break; 659 660 case TIOCMBIS: 661 (void) mfcsmctl(dev, *(int *) data, DMBIS); 662 break; 663 664 case TIOCMBIC: 665 (void) mfcsmctl(dev, *(int *) data, DMBIC); 666 break; 667 668 case TIOCMGET: 669 *(int *)data = mfcsmctl(dev, 0, DMGET); 670 break; 671 case TIOCGFLAGS: 672 *(int *)data = SWFLAGS(dev); 673 break; 674 case TIOCSFLAGS: 675 error = suser(p->p_ucred, &p->p_acflag); 676 if (error != 0) 677 return(EPERM); 678 679 mfcsswflags[unit] = *(int *)data; 680 mfcsswflags[unit] &= /* only allow valid flags */ 681 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 682 /* XXXX need to change duart parameters? */ 683 break; 684 default: 685 return(ENOTTY); 686 } 687 688 return(0); 689 } 690 691 int 692 mfcsparam(tp, t) 693 struct tty *tp; 694 struct termios *t; 695 { 696 int cfcr, cflag, unit, ospeed; 697 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31]; 698 struct mfc_softc *scc= sc->sc_mfc; 699 700 cflag = t->c_cflag; 701 unit = tp->t_dev & 31; 702 if (sc->flags & CT_USED) { 703 --scc->ct_usecnt; 704 sc->flags &= ~CT_USED; 705 } 706 ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab2 : 707 mfcs2speedtab2); 708 709 /* 710 * If Baud Rate Generator can't generate requested speed, 711 * try to use the counter/timer. 712 */ 713 if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) { 714 ospeed = scc->clk_frq / t->c_ospeed; /* divisor */ 715 if (scc->ct_usecnt > 0 && scc->ct_val != ospeed) 716 ospeed = -1; 717 else { 718 scc->sc_regs->du_ctur = ospeed >> 8; 719 scc->sc_regs->du_ctlr = ospeed; 720 scc->ct_val = ospeed; 721 ++scc->ct_usecnt; 722 sc->flags |= CT_USED; 723 ospeed = 0xdd; 724 } 725 } 726 /* XXXX 68681 duart could handle split speeds */ 727 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 728 return(EINVAL); 729 730 /* XXXX handle parity, character size, stop bits, flow control */ 731 732 /* 733 * copy to tty 734 */ 735 tp->t_ispeed = t->c_ispeed; 736 tp->t_ospeed = t->c_ospeed; 737 tp->t_cflag = cflag; 738 739 /* 740 * enable interrupts 741 */ 742 scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80; 743 scc->sc_regs->du_imr = scc->imask; 744 #if defined(DEBUG) && 0 745 printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n", 746 t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag); 747 #endif 748 if (ospeed == 0) 749 (void)mfcsmctl(tp->t_dev, 0, DMSET); /* hang up line */ 750 else { 751 /* 752 * (re)enable DTR 753 * and set baud rate. (8 bit mode) 754 */ 755 (void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET); 756 sc->sc_duart->ch_csr = ospeed; 757 } 758 return(0); 759 } 760 761 int mfcshwiflow(tp, flag) 762 struct tty *tp; 763 int flag; 764 { 765 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31]; 766 int unit = tp->t_dev & 1; 767 768 if (flag) 769 sc->sc_regs->du_btrst = 1 << unit; 770 else 771 sc->sc_regs->du_btst = 1 << unit; 772 return 1; 773 } 774 775 int 776 mfcsstart(tp) 777 struct tty *tp; 778 { 779 int cc, s, unit; 780 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31]; 781 struct mfc_softc *scc= sc->sc_mfc; 782 783 if ((tp->t_state & TS_ISOPEN) == 0) 784 return; 785 786 unit = tp->t_dev & 1; 787 788 s = splser(); 789 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 790 goto out; 791 792 cc = tp->t_outq.c_cc; 793 if (cc <= tp->t_lowat) { 794 if (tp->t_state & TS_ASLEEP) { 795 tp->t_state &= ~TS_ASLEEP; 796 wakeup((caddr_t) & tp->t_outq); 797 } 798 selwakeup(&tp->t_wsel); 799 } 800 if (cc == 0 || (tp->t_state & TS_BUSY)) 801 goto out; 802 803 /* 804 * We only do bulk transfers if using CTSRTS flow control, not for 805 * (probably sloooow) ixon/ixoff devices. 806 */ 807 if ((tp->t_cflag & CRTSCTS) == 0) 808 cc = 1; 809 810 /* 811 * Limit the amount of output we do in one burst 812 * to prevent hogging the CPU. 813 */ 814 if (cc > SEROBUF_SIZE) 815 cc = SEROBUF_SIZE; 816 cc = q_to_b(&tp->t_outq, sc->outbuf, cc); 817 if (cc > 0) { 818 tp->t_state |= TS_BUSY; 819 820 sc->ptr = sc->outbuf; 821 sc->end = sc->outbuf + cc; 822 823 /* 824 * Get first character out, then have TBE-interrupts blow out 825 * further characters, until buffer is empty, and TS_BUSY gets 826 * cleared. 827 */ 828 sc->sc_duart->ch_tb = *sc->ptr++; 829 scc->imask |= 1 << (unit * 4); 830 sc->sc_regs->du_imr = scc->imask; 831 } 832 out: 833 splx(s); 834 } 835 836 /* 837 * Stop output on a line. 838 */ 839 /*ARGSUSED*/ 840 int 841 mfcsstop(tp, flag) 842 struct tty *tp; 843 { 844 int s; 845 846 s = splser(); 847 if (tp->t_state & TS_BUSY) { 848 if ((tp->t_state & TS_TTSTOP) == 0) 849 tp->t_state |= TS_FLUSH; 850 } 851 splx(s); 852 } 853 854 int 855 mfcsmctl(dev, bits, how) 856 dev_t dev; 857 int bits, how; 858 { 859 int unit, s; 860 u_char ub; 861 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31]; 862 863 unit = dev & 1; 864 865 /* 866 * convert TIOCM* mask into CIA mask 867 * which is active low 868 */ 869 if (how != DMGET) { 870 ub = 0; 871 /* 872 * need to save current state of DTR & RTS ? 873 */ 874 if (bits & TIOCM_DTR) 875 ub |= 0x04 << unit; 876 if (bits & TIOCM_RTS) 877 ub |= 0x01 << unit; 878 } 879 s = splser(); 880 switch (how) { 881 case DMSET: 882 sc->sc_regs->du_btst = ub; 883 sc->sc_regs->du_btrst = ub ^ (0x05 << unit); 884 break; 885 886 case DMBIC: 887 sc->sc_regs->du_btrst = ub; 888 ub = ~sc->sc_regs->du_ip; 889 break; 890 891 case DMBIS: 892 sc->sc_regs->du_btst = ub; 893 ub = ~sc->sc_regs->du_ip; 894 break; 895 896 case DMGET: 897 ub = ~sc->sc_regs->du_ip; 898 break; 899 } 900 (void)splx(s); 901 902 /* XXXX should keep DTR & RTS states in softc? */ 903 bits = TIOCM_DTR | TIOCM_RTS; 904 if (ub & (1 << unit)) 905 bits |= TIOCM_CTS; 906 if (ub & (4 << unit)) 907 bits |= TIOCM_DSR; 908 if (ub & (0x10 << unit)) 909 bits |= TIOCM_CD; 910 /* XXXX RI is not supported on all boards */ 911 if (sc->sc_regs->pad26 & (1 << unit)) 912 bits |= TIOCM_RI; 913 914 return(bits); 915 } 916 917 /* 918 * Level 6 interrupt processing for the MultiFaceCard 68681 DUART 919 */ 920 921 int 922 mfcintr (scc) 923 struct mfc_softc *scc; 924 { 925 struct mfcs_softc *sc; 926 struct mfc_regs *regs; 927 struct tty *tp; 928 int istat, unit; 929 u_short c; 930 931 regs = scc->sc_regs; 932 istat = regs->du_isr & scc->imask; 933 if (istat == 0) 934 return (0); 935 unit = scc->sc_dev.dv_unit * 2; 936 if (istat & 0x02) { /* channel A receive interrupt */ 937 sc = mfcscd.cd_devs[unit]; 938 while (1) { 939 c = regs->du_sra << 8; 940 if ((c & 0x0100) == 0) 941 break; 942 c |= regs->du_rba; 943 if (sc->incnt == SERIBUF_SIZE) 944 ++sc->ovfl; 945 else { 946 *sc->wptr++ = c; 947 if (sc->wptr == sc->inbuf + SERIBUF_SIZE) 948 sc->wptr = sc->inbuf; 949 ++sc->incnt; 950 if (sc->incnt > SERIBUF_SIZE - 16) 951 regs->du_btrst = 1; 952 } 953 if (c & 0x1000) 954 regs->du_cra = 0x40; 955 } 956 } 957 if (istat & 0x20) { /* channel B receive interrupt */ 958 sc = mfcscd.cd_devs[unit + 1]; 959 while (1) { 960 c = regs->du_srb << 8; 961 if ((c & 0x0100) == 0) 962 break; 963 c |= regs->du_rbb; 964 if (sc->incnt == SERIBUF_SIZE) 965 ++sc->ovfl; 966 else { 967 *sc->wptr++ = c; 968 if (sc->wptr == sc->inbuf + SERIBUF_SIZE) 969 sc->wptr = sc->inbuf; 970 ++sc->incnt; 971 if (sc->incnt > SERIBUF_SIZE - 16) 972 regs->du_btrst = 2; 973 } 974 if (c & 0x1000) 975 regs->du_crb = 0x40; 976 } 977 } 978 if (istat & 0x01) { /* channel A transmit interrupt */ 979 tp = mfcs_tty[unit]; 980 sc = mfcscd.cd_devs[unit]; 981 if (sc->ptr == sc->end) { 982 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 983 scc->imask &= ~0x01; 984 regs->du_imr = scc->imask; 985 add_sicallback (tp->t_line ? 986 linesw[tp->t_line].l_start : mfcsstart, 987 tp, NULL); 988 989 } 990 else 991 regs->du_tba = *sc->ptr++; 992 } 993 if (istat & 0x10) { /* channel B transmit interrupt */ 994 tp = mfcs_tty[unit + 1]; 995 sc = mfcscd.cd_devs[unit + 1]; 996 if (sc->ptr == sc->end) { 997 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 998 scc->imask &= ~0x10; 999 regs->du_imr = scc->imask; 1000 add_sicallback (tp->t_line ? 1001 linesw[tp->t_line].l_start : mfcsstart, 1002 tp, NULL); 1003 } 1004 else 1005 regs->du_tbb = *sc->ptr++; 1006 } 1007 if (istat & 0x80) { /* input port change interrupt */ 1008 c = regs->du_ipcr; 1009 printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c); 1010 } 1011 return(1); 1012 } 1013 1014 int 1015 mfcsxintr(unit) 1016 int unit; 1017 { 1018 int s1, s2, ovfl; 1019 struct mfcs_softc *sc = mfcscd.cd_devs[unit]; 1020 struct tty *tp = mfcs_tty[unit]; 1021 1022 /* 1023 * Make sure we're not interrupted by another 1024 * vbl, but allow level6 ints 1025 */ 1026 s1 = spltty(); 1027 1028 /* 1029 * pass along any acumulated information 1030 * while input is not blocked 1031 */ 1032 while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) { 1033 /* 1034 * no collision with ser_fastint() 1035 */ 1036 mfcseint(unit, *sc->rptr++); 1037 1038 ovfl = 0; 1039 /* lock against mfcs_fastint() */ 1040 s2 = splser(); 1041 --sc->incnt; 1042 if (sc->rptr == sc->inbuf + SERIBUF_SIZE) 1043 sc->rptr = sc->inbuf; 1044 if (sc->ovfl != 0) { 1045 ovfl = sc->ovfl; 1046 sc->ovfl = 0; 1047 } 1048 splx(s2); 1049 if (ovfl != 0) 1050 log(LOG_WARNING, "%s: %d buffer overflow!\n", 1051 sc->sc_dev.dv_xname, ovfl); 1052 } 1053 if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) { 1054 sc->sc_regs->du_btst = 1 << unit; /* XXXX */ 1055 } 1056 splx(s1); 1057 } 1058 1059 int 1060 mfcseint(unit, stat) 1061 int unit, stat; 1062 { 1063 struct tty *tp; 1064 u_char ch; 1065 int c; 1066 1067 tp = mfcs_tty[unit]; 1068 ch = stat & 0xff; 1069 c = ch; 1070 1071 if ((tp->t_state & TS_ISOPEN) == 0) { 1072 #ifdef KGDB 1073 /* we don't care about parity errors */ 1074 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END) 1075 kgdb_connect(0); /* trap into kgdb */ 1076 #endif 1077 return; 1078 } 1079 1080 /* 1081 * Check for break and (if enabled) parity error. 1082 */ 1083 if (stat & 0xc000) 1084 c |= TTY_FE; 1085 else if (stat & 0x2000) 1086 c |= TTY_PE; 1087 1088 if (stat & 0x1000) 1089 log(LOG_WARNING, "%s: fifo overflow\n", 1090 ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname); 1091 1092 (*linesw[tp->t_line].l_rint)(c, tp); 1093 } 1094 1095 /* 1096 * This interrupt is periodically invoked in the vertical blank 1097 * interrupt. It's used to keep track of the modem control lines 1098 * and (new with the fast_int code) to move accumulated data 1099 * up into the tty layer. 1100 */ 1101 void 1102 mfcsmint(unit) 1103 int unit; 1104 { 1105 struct tty *tp; 1106 struct mfcs_softc *sc = mfcscd.cd_devs[unit]; 1107 u_char stat, last, istat; 1108 1109 tp = mfcs_tty[unit]; 1110 if (!tp) 1111 return; 1112 1113 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) { 1114 sc->rptr = sc->wptr = sc->inbuf; 1115 sc->incnt = 0; 1116 return; 1117 } 1118 /* 1119 * empty buffer 1120 */ 1121 mfcsxintr(unit); 1122 1123 stat = ~sc->sc_regs->du_ip; 1124 last = sc->sc_mfc->last_ip; 1125 sc->sc_mfc->last_ip = stat; 1126 1127 /* 1128 * check whether any interesting signal changed state 1129 */ 1130 istat = stat ^ last; 1131 1132 if ((istat & (0x10 << (unit & 1))) && /* CD changed */ 1133 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) { 1134 if (stat & (0x10 << (unit & 1))) 1135 (*linesw[tp->t_line].l_modem)(tp, 1); 1136 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 1137 sc->sc_regs->du_btrst = 0x0a << (unit & 1); 1138 } 1139 } 1140 } 1141