1 /* $NetBSD: mfc.c,v 1.4 1995/04/02 20:38:49 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 + 128]; 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] = mfcs_tty[unit + 128] = 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 int 609 mfcsioctl(dev, cmd, data, flag, p) 610 dev_t dev; 611 caddr_t data; 612 struct proc *p; 613 { 614 register struct tty *tp; 615 register int unit = dev & 31; 616 register int error; 617 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31]; 618 619 tp = mfcs_tty[unit]; 620 if (!tp) 621 return ENXIO; 622 623 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 624 if (error >= 0) 625 return(error); 626 627 error = ttioctl(tp, cmd, data, flag, p); 628 if (error >= 0) 629 return(error); 630 631 switch (cmd) { 632 case TIOCSBRK: 633 sc->sc_duart->ch_cr = 0x60; /* start break */ 634 break; 635 636 case TIOCCBRK: 637 sc->sc_duart->ch_cr = 0x70; /* stop break */ 638 break; 639 640 case TIOCSDTR: 641 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); 642 break; 643 644 case TIOCCDTR: 645 (void) mfcsmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); 646 break; 647 648 case TIOCMSET: 649 (void) mfcsmctl(dev, *(int *) data, DMSET); 650 break; 651 652 case TIOCMBIS: 653 (void) mfcsmctl(dev, *(int *) data, DMBIS); 654 break; 655 656 case TIOCMBIC: 657 (void) mfcsmctl(dev, *(int *) data, DMBIC); 658 break; 659 660 case TIOCMGET: 661 *(int *)data = mfcsmctl(dev, 0, DMGET); 662 break; 663 case TIOCGFLAGS: 664 *(int *)data = SWFLAGS(dev); 665 break; 666 case TIOCSFLAGS: 667 error = suser(p->p_ucred, &p->p_acflag); 668 if (error != 0) 669 return(EPERM); 670 671 mfcsswflags[unit] = *(int *)data; 672 mfcsswflags[unit] &= /* only allow valid flags */ 673 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 674 /* XXXX need to change duart parameters? */ 675 break; 676 default: 677 return(ENOTTY); 678 } 679 680 return(0); 681 } 682 683 int 684 mfcsparam(tp, t) 685 struct tty *tp; 686 struct termios *t; 687 { 688 int cfcr, cflag, unit, ospeed; 689 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31]; 690 struct mfc_softc *scc= sc->sc_mfc; 691 692 cflag = t->c_cflag; 693 unit = tp->t_dev & 31; 694 if (sc->flags & CT_USED) { 695 --scc->ct_usecnt; 696 sc->flags &= ~CT_USED; 697 } 698 ospeed = ttspeedtab(t->c_ospeed, scc->mfc_iii ? mfcs3speedtab2 : 699 mfcs2speedtab2); 700 701 /* 702 * If Baud Rate Generator can't generate requested speed, 703 * try to use the counter/timer. 704 */ 705 if (ospeed < 0 && (scc->clk_frq % t->c_ospeed) == 0) { 706 ospeed = scc->clk_frq / t->c_ospeed; /* divisor */ 707 if (scc->ct_usecnt > 0 && scc->ct_val != ospeed) 708 ospeed = -1; 709 else { 710 scc->sc_regs->du_ctur = ospeed >> 8; 711 scc->sc_regs->du_ctlr = ospeed; 712 scc->ct_val = ospeed; 713 ++scc->ct_usecnt; 714 sc->flags |= CT_USED; 715 ospeed = 0xdd; 716 } 717 } 718 /* XXXX 68681 duart could handle split speeds */ 719 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 720 return(EINVAL); 721 722 /* XXXX handle parity, character size, stop bits, flow control */ 723 724 /* 725 * copy to tty 726 */ 727 tp->t_ispeed = t->c_ispeed; 728 tp->t_ospeed = t->c_ospeed; 729 tp->t_cflag = cflag; 730 731 /* 732 * enable interrupts 733 */ 734 scc->imask |= (0x2 << ((unit & 1) * 4)) | 0x80; 735 scc->sc_regs->du_imr = scc->imask; 736 #if defined(DEBUG) && 0 737 printf("mfcsparam: speed %d => %x ct %d imask %x cflag %x\n", 738 t->c_ospeed, ospeed, scc->ct_val, scc->imask, cflag); 739 #endif 740 if (ospeed == 0) 741 (void)mfcsmctl(tp->t_dev, 0, DMSET); /* hang up line */ 742 else { 743 /* 744 * (re)enable DTR 745 * and set baud rate. (8 bit mode) 746 */ 747 (void)mfcsmctl(tp->t_dev, TIOCM_DTR | TIOCM_RTS, DMSET); 748 sc->sc_duart->ch_csr = ospeed; 749 } 750 return(0); 751 } 752 753 int mfcshwiflow(tp, flag) 754 struct tty *tp; 755 int flag; 756 { 757 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31]; 758 int unit = tp->t_dev & 1; 759 760 if (flag) 761 sc->sc_regs->du_btrst = 1 << unit; 762 else 763 sc->sc_regs->du_btst = 1 << unit; 764 return 1; 765 } 766 767 int 768 mfcsstart(tp) 769 struct tty *tp; 770 { 771 int cc, s, unit; 772 struct mfcs_softc *sc = mfcscd.cd_devs[tp->t_dev & 31]; 773 struct mfc_softc *scc= sc->sc_mfc; 774 775 if ((tp->t_state & TS_ISOPEN) == 0) 776 return; 777 778 unit = tp->t_dev & 1; 779 780 s = splser(); 781 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 782 goto out; 783 784 cc = tp->t_outq.c_cc; 785 if (cc <= tp->t_lowat) { 786 if (tp->t_state & TS_ASLEEP) { 787 tp->t_state &= ~TS_ASLEEP; 788 wakeup((caddr_t) & tp->t_outq); 789 } 790 selwakeup(&tp->t_wsel); 791 } 792 if (cc == 0 || (tp->t_state & TS_BUSY)) 793 goto out; 794 795 /* 796 * We only do bulk transfers if using CTSRTS flow control, not for 797 * (probably sloooow) ixon/ixoff devices. 798 */ 799 if ((tp->t_cflag & CRTSCTS) == 0) 800 cc = 1; 801 802 /* 803 * Limit the amount of output we do in one burst 804 * to prevent hogging the CPU. 805 */ 806 if (cc > SEROBUF_SIZE) 807 cc = SEROBUF_SIZE; 808 cc = q_to_b(&tp->t_outq, sc->outbuf, cc); 809 if (cc > 0) { 810 tp->t_state |= TS_BUSY; 811 812 sc->ptr = sc->outbuf; 813 sc->end = sc->outbuf + cc; 814 815 /* 816 * Get first character out, then have TBE-interrupts blow out 817 * further characters, until buffer is empty, and TS_BUSY gets 818 * cleared. 819 */ 820 sc->sc_duart->ch_tb = *sc->ptr++; 821 scc->imask |= 1 << (unit * 4); 822 sc->sc_regs->du_imr = scc->imask; 823 } 824 out: 825 splx(s); 826 } 827 828 /* 829 * Stop output on a line. 830 */ 831 /*ARGSUSED*/ 832 int 833 mfcsstop(tp, flag) 834 struct tty *tp; 835 { 836 int s; 837 838 s = splser(); 839 if (tp->t_state & TS_BUSY) { 840 if ((tp->t_state & TS_TTSTOP) == 0) 841 tp->t_state |= TS_FLUSH; 842 } 843 splx(s); 844 } 845 846 int 847 mfcsmctl(dev, bits, how) 848 dev_t dev; 849 int bits, how; 850 { 851 int unit, s; 852 u_char ub; 853 struct mfcs_softc *sc = mfcscd.cd_devs[dev & 31]; 854 855 unit = dev & 1; 856 857 /* 858 * convert TIOCM* mask into CIA mask 859 * which is active low 860 */ 861 if (how != DMGET) { 862 ub = 0; 863 /* 864 * need to save current state of DTR & RTS ? 865 */ 866 if (bits & TIOCM_DTR) 867 ub |= 0x04 << unit; 868 if (bits & TIOCM_RTS) 869 ub |= 0x01 << unit; 870 } 871 s = splser(); 872 switch (how) { 873 case DMSET: 874 sc->sc_regs->du_btst = ub; 875 sc->sc_regs->du_btrst = ub ^ (0x05 << unit); 876 break; 877 878 case DMBIC: 879 sc->sc_regs->du_btrst = ub; 880 ub = ~sc->sc_regs->du_ip; 881 break; 882 883 case DMBIS: 884 sc->sc_regs->du_btst = ub; 885 ub = ~sc->sc_regs->du_ip; 886 break; 887 888 case DMGET: 889 ub = ~sc->sc_regs->du_ip; 890 break; 891 } 892 (void)splx(s); 893 894 /* XXXX should keep DTR & RTS states in softc? */ 895 bits = TIOCM_DTR | TIOCM_RTS; 896 if (ub & (1 << unit)) 897 bits |= TIOCM_CTS; 898 if (ub & (4 << unit)) 899 bits |= TIOCM_DSR; 900 if (ub & (0x10 << unit)) 901 bits |= TIOCM_CD; 902 /* XXXX RI is not supported on all boards */ 903 if (sc->sc_regs->pad26 & (1 << unit)) 904 bits |= TIOCM_RI; 905 906 return(bits); 907 } 908 909 /* 910 * Level 6 interrupt processing for the MultiFaceCard 68681 DUART 911 */ 912 913 int 914 mfcintr (scc) 915 struct mfc_softc *scc; 916 { 917 struct mfcs_softc *sc; 918 struct mfc_regs *regs; 919 struct tty *tp; 920 int istat, unit; 921 u_short c; 922 923 regs = scc->sc_regs; 924 istat = regs->du_isr & scc->imask; 925 if (istat == 0) 926 return (0); 927 unit = scc->sc_dev.dv_unit * 2; 928 if (istat & 0x02) { /* channel A receive interrupt */ 929 sc = mfcscd.cd_devs[unit]; 930 while (1) { 931 c = regs->du_sra << 8; 932 if ((c & 0x0100) == 0) 933 break; 934 c |= regs->du_rba; 935 if (sc->incnt == SERIBUF_SIZE) 936 ++sc->ovfl; 937 else { 938 *sc->wptr++ = c; 939 if (sc->wptr == sc->inbuf + SERIBUF_SIZE) 940 sc->wptr = sc->inbuf; 941 ++sc->incnt; 942 if (sc->incnt > SERIBUF_SIZE - 16) 943 regs->du_btrst = 1; 944 } 945 if (c & 0x1000) 946 regs->du_cra = 0x40; 947 } 948 } 949 if (istat & 0x20) { /* channel B receive interrupt */ 950 sc = mfcscd.cd_devs[unit + 1]; 951 while (1) { 952 c = regs->du_srb << 8; 953 if ((c & 0x0100) == 0) 954 break; 955 c |= regs->du_rbb; 956 if (sc->incnt == SERIBUF_SIZE) 957 ++sc->ovfl; 958 else { 959 *sc->wptr++ = c; 960 if (sc->wptr == sc->inbuf + SERIBUF_SIZE) 961 sc->wptr = sc->inbuf; 962 ++sc->incnt; 963 if (sc->incnt > SERIBUF_SIZE - 16) 964 regs->du_btrst = 2; 965 } 966 if (c & 0x1000) 967 regs->du_crb = 0x40; 968 } 969 } 970 if (istat & 0x01) { /* channel A transmit interrupt */ 971 tp = mfcs_tty[unit]; 972 sc = mfcscd.cd_devs[unit]; 973 if (sc->ptr == sc->end) { 974 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 975 scc->imask &= ~0x01; 976 regs->du_imr = scc->imask; 977 add_sicallback (tp->t_line ? 978 linesw[tp->t_line].l_start : mfcsstart, 979 tp, NULL); 980 981 } 982 else 983 regs->du_tba = *sc->ptr++; 984 } 985 if (istat & 0x10) { /* channel B transmit interrupt */ 986 tp = mfcs_tty[unit + 1]; 987 sc = mfcscd.cd_devs[unit + 1]; 988 if (sc->ptr == sc->end) { 989 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 990 scc->imask &= ~0x10; 991 regs->du_imr = scc->imask; 992 add_sicallback (tp->t_line ? 993 linesw[tp->t_line].l_start : mfcsstart, 994 tp, NULL); 995 } 996 else 997 regs->du_tbb = *sc->ptr++; 998 } 999 if (istat & 0x80) { /* input port change interrupt */ 1000 c = regs->du_ipcr; 1001 printf ("%s: ipcr %02x", scc->sc_dev.dv_xname, c); 1002 } 1003 return(1); 1004 } 1005 1006 int 1007 mfcsxintr(unit) 1008 int unit; 1009 { 1010 int s1, s2, ovfl; 1011 struct mfcs_softc *sc = mfcscd.cd_devs[unit]; 1012 struct tty *tp = mfcs_tty[unit]; 1013 1014 /* 1015 * Make sure we're not interrupted by another 1016 * vbl, but allow level6 ints 1017 */ 1018 s1 = spltty(); 1019 1020 /* 1021 * pass along any acumulated information 1022 * while input is not blocked 1023 */ 1024 while (sc->incnt && (tp->t_state & TS_TBLOCK) == 0) { 1025 /* 1026 * no collision with ser_fastint() 1027 */ 1028 mfcseint(unit, *sc->rptr++); 1029 1030 ovfl = 0; 1031 /* lock against mfcs_fastint() */ 1032 s2 = splser(); 1033 --sc->incnt; 1034 if (sc->rptr == sc->inbuf + SERIBUF_SIZE) 1035 sc->rptr = sc->inbuf; 1036 if (sc->ovfl != 0) { 1037 ovfl = sc->ovfl; 1038 sc->ovfl = 0; 1039 } 1040 splx(s2); 1041 if (ovfl != 0) 1042 log(LOG_WARNING, "%s: %d buffer overflow!\n", 1043 sc->sc_dev.dv_xname, ovfl); 1044 } 1045 if (sc->incnt == 0 && (tp->t_state & TS_TBLOCK) == 0) { 1046 sc->sc_regs->du_btst = 1 << unit; /* XXXX */ 1047 } 1048 splx(s1); 1049 } 1050 1051 int 1052 mfcseint(unit, stat) 1053 int unit, stat; 1054 { 1055 struct tty *tp; 1056 u_char ch; 1057 int c; 1058 1059 tp = mfcs_tty[unit]; 1060 ch = stat & 0xff; 1061 c = ch; 1062 1063 if ((tp->t_state & TS_ISOPEN) == 0) { 1064 #ifdef KGDB 1065 /* we don't care about parity errors */ 1066 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END) 1067 kgdb_connect(0); /* trap into kgdb */ 1068 #endif 1069 return; 1070 } 1071 1072 /* 1073 * Check for break and (if enabled) parity error. 1074 */ 1075 if (stat & 0xc000) 1076 c |= TTY_FE; 1077 else if (stat & 0x2000) 1078 c |= TTY_PE; 1079 1080 if (stat & 0x1000) 1081 log(LOG_WARNING, "%s: fifo overflow\n", 1082 ((struct mfcs_softc *)mfcscd.cd_devs[unit])->sc_dev.dv_xname); 1083 1084 (*linesw[tp->t_line].l_rint)(c, tp); 1085 } 1086 1087 /* 1088 * This interrupt is periodically invoked in the vertical blank 1089 * interrupt. It's used to keep track of the modem control lines 1090 * and (new with the fast_int code) to move accumulated data 1091 * up into the tty layer. 1092 */ 1093 void 1094 mfcsmint(unit) 1095 int unit; 1096 { 1097 struct tty *tp; 1098 struct mfcs_softc *sc = mfcscd.cd_devs[unit]; 1099 u_char stat, last, istat; 1100 1101 tp = mfcs_tty[unit]; 1102 if (!tp) 1103 return; 1104 1105 if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) { 1106 sc->rptr = sc->wptr = sc->inbuf; 1107 sc->incnt = 0; 1108 return; 1109 } 1110 /* 1111 * empty buffer 1112 */ 1113 mfcsxintr(unit); 1114 1115 stat = ~sc->sc_regs->du_ip; 1116 last = sc->sc_mfc->last_ip; 1117 sc->sc_mfc->last_ip = stat; 1118 1119 /* 1120 * check whether any interesting signal changed state 1121 */ 1122 istat = stat ^ last; 1123 1124 if ((istat & (0x10 << (unit & 1))) && /* CD changed */ 1125 (SWFLAGS(tp->t_dev) & TIOCFLAG_SOFTCAR) == 0) { 1126 if (stat & (0x10 << (unit & 1))) 1127 (*linesw[tp->t_line].l_modem)(tp, 1); 1128 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 1129 sc->sc_regs->du_btrst = 0x0a << (unit & 1); 1130 } 1131 } 1132 } 1133