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