1 /* $NetBSD: dcm.c,v 1.51 2002/03/17 19:40:38 atatat Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1988 University of Utah. 41 * Copyright (c) 1982, 1986, 1990, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from Utah: $Hdr: dcm.c 1.29 92/01/21$ 77 * 78 * @(#)dcm.c 8.4 (Berkeley) 1/12/94 79 */ 80 81 /* 82 * TODO: 83 * Timeouts 84 * Test console support. 85 */ 86 87 /* 88 * 98642/MUX 89 */ 90 91 #include <sys/cdefs.h> 92 __KERNEL_RCSID(0, "$NetBSD: dcm.c,v 1.51 2002/03/17 19:40:38 atatat Exp $"); 93 94 #include "opt_kgdb.h" 95 96 #include <sys/param.h> 97 #include <sys/systm.h> 98 #include <sys/ioctl.h> 99 #include <sys/proc.h> 100 #include <sys/tty.h> 101 #include <sys/conf.h> 102 #include <sys/file.h> 103 #include <sys/uio.h> 104 #include <sys/kernel.h> 105 #include <sys/syslog.h> 106 #include <sys/time.h> 107 #include <sys/device.h> 108 109 #include <machine/autoconf.h> 110 #include <machine/cpu.h> 111 #include <machine/intr.h> 112 113 #include <dev/cons.h> 114 115 #include <hp300/dev/dioreg.h> 116 #include <hp300/dev/diovar.h> 117 #include <hp300/dev/diodevs.h> 118 #include <hp300/dev/dcmreg.h> 119 120 #ifndef DEFAULT_BAUD_RATE 121 #define DEFAULT_BAUD_RATE 9600 122 #endif 123 124 struct speedtab dcmspeedtab[] = { 125 { 0, BR_0 }, 126 { 50, BR_50 }, 127 { 75, BR_75 }, 128 { 110, BR_110 }, 129 { 134, BR_134 }, 130 { 150, BR_150 }, 131 { 300, BR_300 }, 132 { 600, BR_600 }, 133 { 1200, BR_1200 }, 134 { 1800, BR_1800 }, 135 { 2400, BR_2400 }, 136 { 4800, BR_4800 }, 137 { 9600, BR_9600 }, 138 { 19200, BR_19200 }, 139 { 38400, BR_38400 }, 140 { -1, -1 }, 141 }; 142 143 /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */ 144 #define DCM_USPERCH(s) (10000000 / (s)) 145 146 /* 147 * Per board interrupt scheme. 16.7ms is the polling interrupt rate 148 * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms). 149 */ 150 #define DIS_TIMER 0 151 #define DIS_PERCHAR 1 152 #define DIS_RESET 2 153 154 int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */ 155 int dcminterval = 5; /* interval (secs) between checks */ 156 struct dcmischeme { 157 int dis_perchar; /* non-zero if interrupting per char */ 158 long dis_time; /* last time examined */ 159 int dis_intr; /* recv interrupts during last interval */ 160 int dis_char; /* characters read during last interval */ 161 }; 162 163 #ifdef KGDB 164 /* 165 * Kernel GDB support 166 */ 167 #include <machine/remote-sl.h> 168 169 extern dev_t kgdb_dev; 170 extern int kgdb_rate; 171 extern int kgdb_debug_init; 172 #endif 173 174 /* #define DCMSTATS */ 175 176 #ifdef DEBUG 177 int dcmdebug = 0x0; 178 #define DDB_SIOERR 0x01 179 #define DDB_PARAM 0x02 180 #define DDB_INPUT 0x04 181 #define DDB_OUTPUT 0x08 182 #define DDB_INTR 0x10 183 #define DDB_IOCTL 0x20 184 #define DDB_INTSCHM 0x40 185 #define DDB_MODEM 0x80 186 #define DDB_OPENCLOSE 0x100 187 #endif 188 189 #ifdef DCMSTATS 190 #define DCMRBSIZE 94 191 #define DCMXBSIZE 24 192 193 struct dcmstats { 194 long xints; /* # of xmit ints */ 195 long xchars; /* # of xmit chars */ 196 long xempty; /* times outq is empty in dcmstart */ 197 long xrestarts; /* times completed while xmitting */ 198 long rints; /* # of recv ints */ 199 long rchars; /* # of recv chars */ 200 long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */ 201 long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */ 202 }; 203 #endif 204 205 #define DCMUNIT(x) (minor(x) & 0x7ffff) 206 #define DCMDIALOUT(x) (minor(x) & 0x80000) 207 #define DCMBOARD(x) (((x) >> 2) & 0x3f) 208 #define DCMPORT(x) ((x) & 3) 209 210 /* 211 * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux, 212 * the distribution panel uses "HP DCE" conventions. If requested via 213 * the device flags, we swap the inputs to something closer to normal DCE, 214 * allowing a straight-through cable to a DTE or a reversed cable 215 * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected; 216 * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect 217 * DSR or make RTS work, though). The following gives the full 218 * details of a cable from this mux panel to a modem: 219 * 220 * HP modem 221 * name pin pin name 222 * HP inputs: 223 * "Rx" 2 3 Tx 224 * CTS 4 5 CTS (only needed for CCTS_OFLOW) 225 * DCD 20 8 DCD 226 * "DSR" 9 6 DSR (unneeded) 227 * RI 22 22 RI (unneeded) 228 * 229 * HP outputs: 230 * "Tx" 3 2 Rx 231 * "DTR" 6 not connected 232 * "RTS" 8 20 DTR 233 * "SR" 23 4 RTS (often not needed) 234 */ 235 #define hp2dce_in(ibits) (iconv[(ibits) & 0xf]) 236 static char iconv[16] = { 237 0, MI_DM, MI_CTS, MI_CTS|MI_DM, 238 MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM, 239 MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM, 240 MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS, 241 MI_RI|MI_CD|MI_CTS|MI_DM 242 }; 243 244 /* 245 * Note that 8-port boards appear as 2 4-port boards at consecutive 246 * select codes. 247 */ 248 #define NDCMPORT 4 249 250 struct dcm_softc { 251 struct device sc_dev; /* generic device glue */ 252 struct dcmdevice *sc_dcm; /* pointer to hardware */ 253 struct tty *sc_tty[NDCMPORT]; /* our tty instances */ 254 struct modemreg *sc_modem[NDCMPORT]; /* modem control */ 255 char sc_mcndlast[NDCMPORT]; /* XXX last modem status for port */ 256 short sc_softCAR; /* mask of ports with soft-carrier */ 257 struct dcmischeme sc_scheme; /* interrupt scheme for board */ 258 259 /* 260 * Mask of soft-carrier bits in config flags. 261 */ 262 #define DCM_SOFTCAR 0x0000000f 263 264 int sc_flags; /* misc. configuration info */ 265 266 /* 267 * Bits for sc_flags 268 */ 269 #define DCM_ACTIVE 0x00000001 /* indicates board is alive */ 270 #define DCM_ISCONSOLE 0x00000002 /* indicates board is console */ 271 #define DCM_STDDCE 0x00000010 /* re-map DCE to standard */ 272 #define DCM_FLAGMASK (DCM_STDDCE) /* mask of valid bits in config flags */ 273 274 #ifdef DCMSTATS 275 struct dcmstats sc_stats; /* metrics gathering */ 276 #endif 277 }; 278 279 cdev_decl(dcm); 280 281 int dcmintr __P((void *)); 282 void dcmpint __P((struct dcm_softc *, int, int)); 283 void dcmrint __P((struct dcm_softc *)); 284 void dcmreadbuf __P((struct dcm_softc *, int)); 285 void dcmxint __P((struct dcm_softc *, int)); 286 void dcmmint __P((struct dcm_softc *, int, int)); 287 288 int dcmparam __P((struct tty *, struct termios *)); 289 void dcmstart __P((struct tty *)); 290 void dcmstop __P((struct tty *, int)); 291 int dcmmctl __P((dev_t, int, int)); 292 void dcmsetischeme __P((int, int)); 293 void dcminit __P((struct dcmdevice *, int, int)); 294 295 int dcmselftest __P((struct dcm_softc *)); 296 297 int dcmcnattach __P((bus_space_tag_t, bus_addr_t, int)); 298 int dcmcngetc __P((dev_t)); 299 void dcmcnputc __P((dev_t, int)); 300 301 int dcmmatch __P((struct device *, struct cfdata *, void *)); 302 void dcmattach __P((struct device *, struct device *, void *)); 303 304 struct cfattach dcm_ca = { 305 sizeof(struct dcm_softc), dcmmatch, dcmattach 306 }; 307 308 /* 309 * Stuff for DCM console support. This could probably be done a little 310 * better. 311 */ 312 static struct dcmdevice *dcm_cn = NULL; /* pointer to hardware */ 313 static int dcmconsinit; /* has been initialized */ 314 /* static int dcm_lastcnpri = CN_DEAD; */ /* XXX last priority */ 315 316 static struct consdev dcm_cons = { 317 NULL, NULL, dcmcngetc, dcmcnputc, nullcnpollc, NULL, NODEV, CN_REMOTE 318 }; 319 int dcmconscode; 320 int dcmdefaultrate = DEFAULT_BAUD_RATE; 321 int dcmconbrdbusy = 0; 322 int dcmmajor; 323 324 extern struct cfdriver dcm_cd; 325 326 int 327 dcmmatch(parent, match, aux) 328 struct device *parent; 329 struct cfdata *match; 330 void *aux; 331 { 332 struct dio_attach_args *da = aux; 333 334 switch (da->da_id) { 335 case DIO_DEVICE_ID_DCM: 336 case DIO_DEVICE_ID_DCMREM: 337 return (1); 338 } 339 340 return (0); 341 } 342 343 void 344 dcmattach(parent, self, aux) 345 struct device *parent, *self; 346 void *aux; 347 { 348 struct dcm_softc *sc = (struct dcm_softc *)self; 349 struct dio_attach_args *da = aux; 350 struct dcmdevice *dcm; 351 int brd = self->dv_unit; 352 int scode = da->da_scode; 353 int i, mbits, code, ipl; 354 355 sc->sc_flags = 0; 356 357 if (scode == dcmconscode) { 358 dcm = dcm_cn; 359 sc->sc_flags |= DCM_ISCONSOLE; 360 361 /* 362 * We didn't know which unit this would be during 363 * the console probe, so we have to fixup cn_dev here. 364 * Note that we always assume port 1 on the board. 365 */ 366 cn_tab->cn_dev = makedev(dcmmajor, (brd << 2) | DCMCONSPORT); 367 } else { 368 dcm = (struct dcmdevice *)iomap(dio_scodetopa(da->da_scode), 369 da->da_size); 370 if (dcm == NULL) { 371 printf("\n%s: can't map registers\n", 372 sc->sc_dev.dv_xname); 373 return; 374 } 375 } 376 377 sc->sc_dcm = dcm; 378 379 ipl = DIO_IPL(dcm); 380 printf(" ipl %d", ipl); 381 382 /* 383 * XXX someone _should_ fix this; the self test screws 384 * autoconfig messages. 385 */ 386 if ((sc->sc_flags & DCM_ISCONSOLE) && dcmselftest(sc)) { 387 printf("\n%s: self-test failed\n", sc->sc_dev.dv_xname); 388 return; 389 } 390 391 /* Extract configuration info from flags. */ 392 sc->sc_softCAR = self->dv_cfdata->cf_flags & DCM_SOFTCAR; 393 sc->sc_flags |= self->dv_cfdata->cf_flags & DCM_FLAGMASK; 394 395 /* Mark our unit as configured. */ 396 sc->sc_flags |= DCM_ACTIVE; 397 398 /* Establish the interrupt handler. */ 399 (void) dio_intr_establish(dcmintr, sc, ipl, IPL_TTY); 400 401 if (dcmistype == DIS_TIMER) 402 dcmsetischeme(brd, DIS_RESET|DIS_TIMER); 403 else 404 dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR); 405 406 /* load pointers to modem control */ 407 sc->sc_modem[0] = &dcm->dcm_modem0; 408 sc->sc_modem[1] = &dcm->dcm_modem1; 409 sc->sc_modem[2] = &dcm->dcm_modem2; 410 sc->sc_modem[3] = &dcm->dcm_modem3; 411 412 /* set DCD (modem) and CTS (flow control) on all ports */ 413 if (sc->sc_flags & DCM_STDDCE) 414 mbits = hp2dce_in(MI_CD|MI_CTS); 415 else 416 mbits = MI_CD|MI_CTS; 417 418 for (i = 0; i < NDCMPORT; i++) 419 sc->sc_modem[i]->mdmmsk = mbits; 420 421 /* 422 * Get current state of mdmin register on all ports, so that 423 * deltas will work properly. 424 */ 425 for (i = 0; i < NDCMPORT; i++) { 426 code = sc->sc_modem[i]->mdmin; 427 if (sc->sc_flags & DCM_STDDCE) 428 code = hp2dce_in(code); 429 sc->sc_mcndlast[i] = code; 430 } 431 432 dcm->dcm_ic = IC_IE; /* turn all interrupts on */ 433 434 /* 435 * Need to reset baud rate, etc. of next print so reset dcmconsinit. 436 * Also make sure console is always "hardwired" 437 */ 438 if (sc->sc_flags & DCM_ISCONSOLE) { 439 dcmconsinit = 0; 440 sc->sc_softCAR |= (1 << DCMCONSPORT); 441 printf(": console on port %d\n", DCMCONSPORT); 442 } else 443 printf("\n"); 444 445 #ifdef KGDB 446 if (major(kgdb_dev) == dcmmajor && 447 DCMBOARD(DCMUNIT(kgdb_dev)) == brd) { 448 if (dcmconsole == DCMUNIT(kgdb_dev)) /* XXX fixme */ 449 kgdb_dev = NODEV; /* can't debug over console port */ 450 #ifndef KGDB_CHEAT 451 /* 452 * The following could potentially be replaced 453 * by the corresponding code in dcmcnprobe. 454 */ 455 else { 456 dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)), 457 kgdb_rate); 458 if (kgdb_debug_init) { 459 printf("%s port %d: ", sc->sc_dev.dv_xname, 460 DCMPORT(DCMUNIT(kgdb_dev))); 461 kgdb_connect(1); 462 } else 463 printf("%s port %d: kgdb enabled\n", 464 sc->sc_dev.dv_xname, 465 DCMPORT(DCMUNIT(kgdb_dev))); 466 } 467 /* end could be replaced */ 468 #endif /* KGDB_CHEAT */ 469 } 470 #endif /* KGDB */ 471 } 472 473 /* ARGSUSED */ 474 int 475 dcmopen(dev, flag, mode, p) 476 dev_t dev; 477 int flag, mode; 478 struct proc *p; 479 { 480 struct dcm_softc *sc; 481 struct tty *tp; 482 int unit, brd, port; 483 int error = 0, mbits, s; 484 485 unit = DCMUNIT(dev); 486 brd = DCMBOARD(unit); 487 port = DCMPORT(unit); 488 489 if (brd >= dcm_cd.cd_ndevs || port >= NDCMPORT || 490 (sc = dcm_cd.cd_devs[brd]) == NULL) 491 return (ENXIO); 492 493 if ((sc->sc_flags & DCM_ACTIVE) == 0) 494 return (ENXIO); 495 496 if (sc->sc_tty[port] == NULL) { 497 tp = sc->sc_tty[port] = ttymalloc(); 498 tty_attach(tp); 499 } else 500 tp = sc->sc_tty[port]; 501 502 tp->t_oproc = dcmstart; 503 tp->t_param = dcmparam; 504 tp->t_dev = dev; 505 506 if ((tp->t_state & TS_ISOPEN) && 507 (tp->t_state & TS_XCLUDE) && 508 p->p_ucred->cr_uid != 0) 509 return (EBUSY); 510 511 s = spltty(); 512 513 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 514 /* 515 * Sanity clause: reset the card on first open. 516 * The card might be left in an inconsistent state 517 * if the card memory is read inadvertently. 518 */ 519 dcminit(sc->sc_dcm, port, dcmdefaultrate); 520 521 ttychars(tp); 522 tp->t_iflag = TTYDEF_IFLAG; 523 tp->t_oflag = TTYDEF_OFLAG; 524 tp->t_cflag = TTYDEF_CFLAG; 525 tp->t_lflag = TTYDEF_LFLAG; 526 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 527 528 (void) dcmparam(tp, &tp->t_termios); 529 ttsetwater(tp); 530 531 /* Set modem control state. */ 532 mbits = MO_ON; 533 if (sc->sc_flags & DCM_STDDCE) 534 mbits |= MO_SR; /* pin 23, could be used as RTS */ 535 536 (void) dcmmctl(dev, mbits, DMSET); /* enable port */ 537 538 /* Set soft-carrier if so configured. */ 539 if ((sc->sc_softCAR & (1 << port)) || 540 (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)) 541 tp->t_state |= TS_CARR_ON; 542 } 543 544 splx(s); 545 546 #ifdef DEBUG 547 if (dcmdebug & DDB_MODEM) 548 printf("%s: dcmopen port %d softcarr %c\n", 549 sc->sc_dev.dv_xname, port, 550 (tp->t_state & TS_CARR_ON) ? '1' : '0'); 551 #endif 552 553 error = ttyopen(tp, DCMDIALOUT(dev), (flag & O_NONBLOCK)); 554 if (error) 555 goto bad; 556 557 #ifdef DEBUG 558 if (dcmdebug & DDB_OPENCLOSE) 559 printf("%s port %d: dcmopen: st %x fl %x\n", 560 sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags); 561 #endif 562 error = (*tp->t_linesw->l_open)(dev, tp); 563 564 bad: 565 return (error); 566 } 567 568 /*ARGSUSED*/ 569 int 570 dcmclose(dev, flag, mode, p) 571 dev_t dev; 572 int flag, mode; 573 struct proc *p; 574 { 575 int s, unit, board, port; 576 struct dcm_softc *sc; 577 struct tty *tp; 578 579 unit = DCMUNIT(dev); 580 board = DCMBOARD(unit); 581 port = DCMPORT(unit); 582 583 sc = dcm_cd.cd_devs[board]; 584 tp = sc->sc_tty[port]; 585 586 (*tp->t_linesw->l_close)(tp, flag); 587 588 s = spltty(); 589 590 if (tp->t_cflag & HUPCL || tp->t_wopen != 0 || 591 (tp->t_state & TS_ISOPEN) == 0) 592 (void) dcmmctl(dev, MO_OFF, DMSET); 593 #ifdef DEBUG 594 if (dcmdebug & DDB_OPENCLOSE) 595 printf("%s port %d: dcmclose: st %x fl %x\n", 596 sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags); 597 #endif 598 splx(s); 599 ttyclose(tp); 600 #if 0 601 tty_detach(tp); 602 ttyfree(tp); 603 sc->sc_tty[port] == NULL; 604 #endif 605 return (0); 606 } 607 608 int 609 dcmread(dev, uio, flag) 610 dev_t dev; 611 struct uio *uio; 612 int flag; 613 { 614 int unit, board, port; 615 struct dcm_softc *sc; 616 struct tty *tp; 617 618 unit = DCMUNIT(dev); 619 board = DCMBOARD(unit); 620 port = DCMPORT(unit); 621 622 sc = dcm_cd.cd_devs[board]; 623 tp = sc->sc_tty[port]; 624 625 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 626 } 627 628 int 629 dcmwrite(dev, uio, flag) 630 dev_t dev; 631 struct uio *uio; 632 int flag; 633 { 634 int unit, board, port; 635 struct dcm_softc *sc; 636 struct tty *tp; 637 638 unit = DCMUNIT(dev); 639 board = DCMBOARD(unit); 640 port = DCMPORT(unit); 641 642 sc = dcm_cd.cd_devs[board]; 643 tp = sc->sc_tty[port]; 644 645 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 646 } 647 648 int 649 dcmpoll(dev, events, p) 650 dev_t dev; 651 int events; 652 struct proc *p; 653 { 654 int unit, board, port; 655 struct dcm_softc *sc; 656 struct tty *tp; 657 658 unit = DCMUNIT(dev); 659 board = DCMBOARD(unit); 660 port = DCMPORT(unit); 661 662 sc = dcm_cd.cd_devs[board]; 663 tp = sc->sc_tty[port]; 664 665 return ((*tp->t_linesw->l_poll)(tp, events, p)); 666 } 667 668 struct tty * 669 dcmtty(dev) 670 dev_t dev; 671 { 672 int unit, board, port; 673 struct dcm_softc *sc; 674 675 unit = DCMUNIT(dev); 676 board = DCMBOARD(unit); 677 port = DCMPORT(unit); 678 679 sc = dcm_cd.cd_devs[board]; 680 681 return (sc->sc_tty[port]); 682 } 683 684 int 685 dcmintr(arg) 686 void *arg; 687 { 688 struct dcm_softc *sc = arg; 689 struct dcmdevice *dcm = sc->sc_dcm; 690 struct dcmischeme *dis = &sc->sc_scheme; 691 int brd = sc->sc_dev.dv_unit; 692 int code, i; 693 int pcnd[4], mcode, mcnd[4]; 694 695 /* 696 * Do all guarded accesses right off to minimize 697 * block out of hardware. 698 */ 699 SEM_LOCK(dcm); 700 if ((dcm->dcm_ic & IC_IR) == 0) { 701 SEM_UNLOCK(dcm); 702 return (0); 703 } 704 for (i = 0; i < 4; i++) { 705 pcnd[i] = dcm->dcm_icrtab[i].dcm_data; 706 dcm->dcm_icrtab[i].dcm_data = 0; 707 code = sc->sc_modem[i]->mdmin; 708 if (sc->sc_flags & DCM_STDDCE) 709 code = hp2dce_in(code); 710 mcnd[i] = code; 711 } 712 code = dcm->dcm_iir & IIR_MASK; 713 dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ 714 mcode = dcm->dcm_modemintr; 715 dcm->dcm_modemintr = 0; 716 SEM_UNLOCK(dcm); 717 718 #ifdef DEBUG 719 if (dcmdebug & DDB_INTR) { 720 printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ", 721 sc->sc_dev.dv_xname, code, pcnd[0], pcnd[1], 722 pcnd[2], pcnd[3]); 723 printf("miir %x mc %x/%x/%x/%x\n", 724 mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); 725 } 726 #endif 727 if (code & IIR_TIMEO) 728 dcmrint(sc); 729 if (code & IIR_PORT0) 730 dcmpint(sc, 0, pcnd[0]); 731 if (code & IIR_PORT1) 732 dcmpint(sc, 1, pcnd[1]); 733 if (code & IIR_PORT2) 734 dcmpint(sc, 2, pcnd[2]); 735 if (code & IIR_PORT3) 736 dcmpint(sc, 3, pcnd[3]); 737 if (code & IIR_MODM) { 738 if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ 739 dcmmint(sc, 0, mcnd[0]); 740 if (mcode & 0x2) 741 dcmmint(sc, 1, mcnd[1]); 742 if (mcode & 0x4) 743 dcmmint(sc, 2, mcnd[2]); 744 if (mcode & 0x8) 745 dcmmint(sc, 3, mcnd[3]); 746 } 747 748 /* 749 * Chalk up a receiver interrupt if the timer running or one of 750 * the ports reports a special character interrupt. 751 */ 752 if ((code & IIR_TIMEO) || 753 ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) 754 dis->dis_intr++; 755 /* 756 * See if it is time to check/change the interrupt rate. 757 */ 758 if (dcmistype < 0 && 759 (i = time.tv_sec - dis->dis_time) >= dcminterval) { 760 /* 761 * If currently per-character and averaged over 70 interrupts 762 * per-second (66 is threshold of 600 baud) in last interval, 763 * switch to timer mode. 764 * 765 * XXX decay counts ala load average to avoid spikes? 766 */ 767 if (dis->dis_perchar && dis->dis_intr > 70 * i) 768 dcmsetischeme(brd, DIS_TIMER); 769 /* 770 * If currently using timer and had more interrupts than 771 * received characters in the last interval, switch back 772 * to per-character. Note that after changing to per-char 773 * we must process any characters already in the queue 774 * since they may have arrived before the bitmap was setup. 775 * 776 * XXX decay counts? 777 */ 778 else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { 779 dcmsetischeme(brd, DIS_PERCHAR); 780 dcmrint(sc); 781 } 782 dis->dis_intr = dis->dis_char = 0; 783 dis->dis_time = time.tv_sec; 784 } 785 return (1); 786 } 787 788 /* 789 * Port interrupt. Can be two things: 790 * First, it might be a special character (exception interrupt); 791 * Second, it may be a buffer empty (transmit interrupt); 792 */ 793 void 794 dcmpint(sc, port, code) 795 struct dcm_softc *sc; 796 int port, code; 797 { 798 799 if (code & IT_SPEC) 800 dcmreadbuf(sc, port); 801 if (code & IT_TX) 802 dcmxint(sc, port); 803 } 804 805 void 806 dcmrint(sc) 807 struct dcm_softc *sc; 808 { 809 int port; 810 811 for (port = 0; port < NDCMPORT; port++) 812 dcmreadbuf(sc, port); 813 } 814 815 void 816 dcmreadbuf(sc, port) 817 struct dcm_softc *sc; 818 int port; 819 { 820 struct dcmdevice *dcm = sc->sc_dcm; 821 struct dcmpreg *pp = dcm_preg(dcm, port); 822 struct dcmrfifo *fifo; 823 struct tty *tp; 824 int c, stat; 825 u_int head; 826 int nch = 0; 827 #ifdef DCMSTATS 828 struct dcmstats *dsp = &sc->sc_stats; 829 830 dsp->rints++; 831 #endif 832 tp = sc->sc_tty[port]; 833 if (tp == NULL) 834 return; 835 836 if ((tp->t_state & TS_ISOPEN) == 0) { 837 #ifdef KGDB 838 if ((makedev(dcmmajor, minor(tp->t_dev)) == kgdb_dev) && 839 (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && 840 dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) { 841 pp->r_head = (head + 2) & RX_MASK; 842 kgdb_connect(0); /* trap into kgdb */ 843 return; 844 } 845 #endif /* KGDB */ 846 pp->r_head = pp->r_tail & RX_MASK; 847 return; 848 } 849 850 head = pp->r_head & RX_MASK; 851 fifo = &dcm->dcm_rfifos[3-port][head>>1]; 852 /* 853 * XXX upper bound on how many chars we will take in one swallow? 854 */ 855 while (head != (pp->r_tail & RX_MASK)) { 856 /* 857 * Get character/status and update head pointer as fast 858 * as possible to make room for more characters. 859 */ 860 c = fifo->data_char; 861 stat = fifo->data_stat; 862 head = (head + 2) & RX_MASK; 863 pp->r_head = head; 864 fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; 865 nch++; 866 867 #ifdef DEBUG 868 if (dcmdebug & DDB_INPUT) 869 printf("%s port %d: dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n", 870 sc->sc_dev.dv_xname, port, 871 c&0xFF, c, stat&0xFF, 872 tp->t_flags, head, pp->r_tail); 873 #endif 874 /* 875 * Check for and handle errors 876 */ 877 if (stat & RD_MASK) { 878 #ifdef DEBUG 879 if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) 880 printf("%s port %d: dcmreadbuf: err: c%x('%c') s%x\n", 881 sc->sc_dev.dv_xname, port, 882 stat, c&0xFF, c); 883 #endif 884 if (stat & (RD_BD | RD_FE)) 885 c |= TTY_FE; 886 else if (stat & RD_PE) 887 c |= TTY_PE; 888 else if (stat & RD_OVF) 889 log(LOG_WARNING, 890 "%s port %d: silo overflow\n", 891 sc->sc_dev.dv_xname, port); 892 else if (stat & RD_OE) 893 log(LOG_WARNING, 894 "%s port %d: uart overflow\n", 895 sc->sc_dev.dv_xname, port); 896 } 897 (*tp->t_linesw->l_rint)(c, tp); 898 } 899 sc->sc_scheme.dis_char += nch; 900 901 #ifdef DCMSTATS 902 dsp->rchars += nch; 903 if (nch <= DCMRBSIZE) 904 dsp->rsilo[nch]++; 905 else 906 dsp->rsilo[DCMRBSIZE+1]++; 907 #endif 908 } 909 910 void 911 dcmxint(sc, port) 912 struct dcm_softc *sc; 913 int port; 914 { 915 struct tty *tp; 916 917 tp = sc->sc_tty[port]; 918 if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) 919 return; 920 921 tp->t_state &= ~TS_BUSY; 922 if (tp->t_state & TS_FLUSH) 923 tp->t_state &= ~TS_FLUSH; 924 (*tp->t_linesw->l_start)(tp); 925 } 926 927 void 928 dcmmint(sc, port, mcnd) 929 struct dcm_softc *sc; 930 int port, mcnd; 931 { 932 int delta; 933 struct tty *tp; 934 struct dcmdevice *dcm = sc->sc_dcm; 935 936 tp = sc->sc_tty[port]; 937 if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) 938 return; 939 940 #ifdef DEBUG 941 if (dcmdebug & DDB_MODEM) 942 printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n", 943 sc->sc_dev.dv_xname, port, mcnd, sc->sc_mcndlast[port]); 944 #endif 945 delta = mcnd ^ sc->sc_mcndlast[port]; 946 sc->sc_mcndlast[port] = mcnd; 947 if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && 948 (tp->t_flags & CCTS_OFLOW)) { 949 if (mcnd & MI_CTS) { 950 tp->t_state &= ~TS_TTSTOP; 951 ttstart(tp); 952 } else 953 tp->t_state |= TS_TTSTOP; /* inline dcmstop */ 954 } 955 if (delta & MI_CD) { 956 if (mcnd & MI_CD) 957 (void)(*tp->t_linesw->l_modem)(tp, 1); 958 else if ((sc->sc_softCAR & (1 << port)) == 0 && 959 (*tp->t_linesw->l_modem)(tp, 0) == 0) { 960 sc->sc_modem[port]->mdmout = MO_OFF; 961 SEM_LOCK(dcm); 962 dcm->dcm_modemchng |= (1 << port); 963 dcm->dcm_cr |= CR_MODM; 964 SEM_UNLOCK(dcm); 965 DELAY(10); /* time to change lines */ 966 } 967 } 968 } 969 970 int 971 dcmioctl(dev, cmd, data, flag, p) 972 dev_t dev; 973 u_long cmd; 974 caddr_t data; 975 int flag; 976 struct proc *p; 977 { 978 struct dcm_softc *sc; 979 struct tty *tp; 980 struct dcmdevice *dcm; 981 int board, port, unit = DCMUNIT(dev); 982 int error, s; 983 984 port = DCMPORT(unit); 985 board = DCMBOARD(unit); 986 987 sc = dcm_cd.cd_devs[board]; 988 dcm = sc->sc_dcm; 989 tp = sc->sc_tty[port]; 990 991 #ifdef DEBUG 992 if (dcmdebug & DDB_IOCTL) 993 printf("%s port %d: dcmioctl: cmd %lx data %x flag %x\n", 994 sc->sc_dev.dv_xname, port, cmd, *data, flag); 995 #endif 996 997 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p); 998 if (error != EPASSTHROUGH) 999 return (error); 1000 1001 error = ttioctl(tp, cmd, data, flag, p); 1002 if (error != EPASSTHROUGH) 1003 return (error); 1004 1005 switch (cmd) { 1006 case TIOCSBRK: 1007 /* 1008 * Wait for transmitter buffer to empty 1009 */ 1010 s = spltty(); 1011 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 1012 DELAY(DCM_USPERCH(tp->t_ospeed)); 1013 SEM_LOCK(dcm); 1014 dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 1015 dcm->dcm_cr |= (1 << port); /* start break */ 1016 SEM_UNLOCK(dcm); 1017 splx(s); 1018 break; 1019 1020 case TIOCCBRK: 1021 SEM_LOCK(dcm); 1022 dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 1023 dcm->dcm_cr |= (1 << port); /* end break */ 1024 SEM_UNLOCK(dcm); 1025 break; 1026 1027 case TIOCSDTR: 1028 (void) dcmmctl(dev, MO_ON, DMBIS); 1029 break; 1030 1031 case TIOCCDTR: 1032 (void) dcmmctl(dev, MO_ON, DMBIC); 1033 break; 1034 1035 case TIOCMSET: 1036 (void) dcmmctl(dev, *(int *)data, DMSET); 1037 break; 1038 1039 case TIOCMBIS: 1040 (void) dcmmctl(dev, *(int *)data, DMBIS); 1041 break; 1042 1043 case TIOCMBIC: 1044 (void) dcmmctl(dev, *(int *)data, DMBIC); 1045 break; 1046 1047 case TIOCMGET: 1048 *(int *)data = dcmmctl(dev, 0, DMGET); 1049 break; 1050 1051 case TIOCGFLAGS: { 1052 int bits = 0; 1053 1054 if ((sc->sc_softCAR & (1 << port))) 1055 bits |= TIOCFLAG_SOFTCAR; 1056 1057 if (tp->t_cflag & CLOCAL) 1058 bits |= TIOCFLAG_CLOCAL; 1059 1060 *(int *)data = bits; 1061 break; 1062 } 1063 1064 case TIOCSFLAGS: { 1065 int userbits; 1066 1067 error = suser(p->p_ucred, &p->p_acflag); 1068 if (error) 1069 return (EPERM); 1070 1071 userbits = *(int *)data; 1072 1073 if ((userbits & TIOCFLAG_SOFTCAR) || 1074 ((sc->sc_flags & DCM_ISCONSOLE) && 1075 (port == DCMCONSPORT))) 1076 sc->sc_softCAR |= (1 << port); 1077 1078 if (userbits & TIOCFLAG_CLOCAL) 1079 tp->t_cflag |= CLOCAL; 1080 1081 break; 1082 } 1083 1084 default: 1085 return (EPASSTHROUGH); 1086 } 1087 return (0); 1088 } 1089 1090 int 1091 dcmparam(tp, t) 1092 struct tty *tp; 1093 struct termios *t; 1094 { 1095 struct dcm_softc *sc; 1096 struct dcmdevice *dcm; 1097 int unit, board, port, mode, cflag = t->c_cflag; 1098 int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); 1099 1100 unit = DCMUNIT(tp->t_dev); 1101 board = DCMBOARD(unit); 1102 port = DCMPORT(unit); 1103 1104 sc = dcm_cd.cd_devs[board]; 1105 dcm = sc->sc_dcm; 1106 1107 /* check requested parameters */ 1108 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 1109 return (EINVAL); 1110 /* and copy to tty */ 1111 tp->t_ispeed = t->c_ispeed; 1112 tp->t_ospeed = t->c_ospeed; 1113 tp->t_cflag = cflag; 1114 if (ospeed == 0) { 1115 (void) dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET); 1116 return (0); 1117 } 1118 1119 mode = 0; 1120 switch (cflag&CSIZE) { 1121 case CS5: 1122 mode = LC_5BITS; break; 1123 case CS6: 1124 mode = LC_6BITS; break; 1125 case CS7: 1126 mode = LC_7BITS; break; 1127 case CS8: 1128 mode = LC_8BITS; break; 1129 } 1130 if (cflag&PARENB) { 1131 if (cflag&PARODD) 1132 mode |= LC_PODD; 1133 else 1134 mode |= LC_PEVEN; 1135 } 1136 if (cflag&CSTOPB) 1137 mode |= LC_2STOP; 1138 else 1139 mode |= LC_1STOP; 1140 #ifdef DEBUG 1141 if (dcmdebug & DDB_PARAM) 1142 printf("%s port %d: dcmparam: cflag %x mode %x speed %d uperch %d\n", 1143 sc->sc_dev.dv_xname, port, cflag, mode, tp->t_ospeed, 1144 DCM_USPERCH(tp->t_ospeed)); 1145 #endif 1146 1147 /* 1148 * Wait for transmitter buffer to empty. 1149 */ 1150 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 1151 DELAY(DCM_USPERCH(tp->t_ospeed)); 1152 /* 1153 * Make changes known to hardware. 1154 */ 1155 dcm->dcm_data[port].dcm_baud = ospeed; 1156 dcm->dcm_data[port].dcm_conf = mode; 1157 SEM_LOCK(dcm); 1158 dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 1159 dcm->dcm_cr |= (1 << port); 1160 SEM_UNLOCK(dcm); 1161 /* 1162 * Delay for config change to take place. Weighted by baud. 1163 * XXX why do we do this? 1164 */ 1165 DELAY(16 * DCM_USPERCH(tp->t_ospeed)); 1166 return (0); 1167 } 1168 1169 void 1170 dcmstart(tp) 1171 struct tty *tp; 1172 { 1173 struct dcm_softc *sc; 1174 struct dcmdevice *dcm; 1175 struct dcmpreg *pp; 1176 struct dcmtfifo *fifo; 1177 char *bp; 1178 u_int head, tail, next; 1179 int unit, board, port, nch; 1180 char buf[16]; 1181 int s; 1182 #ifdef DCMSTATS 1183 struct dcmstats *dsp = &sc->sc_stats; 1184 int tch = 0; 1185 #endif 1186 1187 unit = DCMUNIT(tp->t_dev); 1188 board = DCMBOARD(unit); 1189 port = DCMPORT(unit); 1190 1191 sc = dcm_cd.cd_devs[board]; 1192 dcm = sc->sc_dcm; 1193 1194 s = spltty(); 1195 #ifdef DCMSTATS 1196 dsp->xints++; 1197 #endif 1198 #ifdef DEBUG 1199 if (dcmdebug & DDB_OUTPUT) 1200 printf("%s port %d: dcmstart: state %x flags %x outcc %d\n", 1201 sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags, 1202 tp->t_outq.c_cc); 1203 #endif 1204 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 1205 goto out; 1206 if (tp->t_outq.c_cc <= tp->t_lowat) { 1207 if (tp->t_state&TS_ASLEEP) { 1208 tp->t_state &= ~TS_ASLEEP; 1209 wakeup((caddr_t)&tp->t_outq); 1210 } 1211 selwakeup(&tp->t_wsel); 1212 } 1213 if (tp->t_outq.c_cc == 0) { 1214 #ifdef DCMSTATS 1215 dsp->xempty++; 1216 #endif 1217 goto out; 1218 } 1219 1220 pp = dcm_preg(dcm, port); 1221 tail = pp->t_tail & TX_MASK; 1222 next = (tail + 1) & TX_MASK; 1223 head = pp->t_head & TX_MASK; 1224 if (head == next) 1225 goto out; 1226 fifo = &dcm->dcm_tfifos[3-port][tail]; 1227 again: 1228 nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK); 1229 #ifdef DCMSTATS 1230 tch += nch; 1231 #endif 1232 #ifdef DEBUG 1233 if (dcmdebug & DDB_OUTPUT) 1234 printf("\thead %x tail %x nch %d\n", head, tail, nch); 1235 #endif 1236 /* 1237 * Loop transmitting all the characters we can. 1238 */ 1239 for (bp = buf; --nch >= 0; bp++) { 1240 fifo->data_char = *bp; 1241 pp->t_tail = next; 1242 /* 1243 * If this is the first character, 1244 * get the hardware moving right now. 1245 */ 1246 if (bp == buf) { 1247 tp->t_state |= TS_BUSY; 1248 SEM_LOCK(dcm); 1249 dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 1250 dcm->dcm_cr |= (1 << port); 1251 SEM_UNLOCK(dcm); 1252 } 1253 tail = next; 1254 fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; 1255 next = (next + 1) & TX_MASK; 1256 } 1257 /* 1258 * Head changed while we were loading the buffer, 1259 * go back and load some more if we can. 1260 */ 1261 if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) { 1262 #ifdef DCMSTATS 1263 dsp->xrestarts++; 1264 #endif 1265 head = pp->t_head & TX_MASK; 1266 goto again; 1267 } 1268 1269 /* 1270 * Kick it one last time in case it finished while we were 1271 * loading the last bunch. 1272 */ 1273 if (bp > &buf[1]) { 1274 tp->t_state |= TS_BUSY; 1275 SEM_LOCK(dcm); 1276 dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 1277 dcm->dcm_cr |= (1 << port); 1278 SEM_UNLOCK(dcm); 1279 } 1280 #ifdef DEBUG 1281 if (dcmdebug & DDB_INTR) 1282 printf("%s port %d: dcmstart: head %x tail %x outqcc %d\n", 1283 sc->sc_dev.dv_xname, port, head, tail, tp->t_outq.c_cc); 1284 #endif 1285 out: 1286 #ifdef DCMSTATS 1287 dsp->xchars += tch; 1288 if (tch <= DCMXBSIZE) 1289 dsp->xsilo[tch]++; 1290 else 1291 dsp->xsilo[DCMXBSIZE+1]++; 1292 #endif 1293 splx(s); 1294 } 1295 1296 /* 1297 * Stop output on a line. 1298 */ 1299 void 1300 dcmstop(tp, flag) 1301 struct tty *tp; 1302 int flag; 1303 { 1304 int s; 1305 1306 s = spltty(); 1307 if (tp->t_state & TS_BUSY) { 1308 /* XXX is there some way to safely stop transmission? */ 1309 if ((tp->t_state&TS_TTSTOP) == 0) 1310 tp->t_state |= TS_FLUSH; 1311 } 1312 splx(s); 1313 } 1314 1315 /* 1316 * Modem control 1317 */ 1318 int 1319 dcmmctl(dev, bits, how) 1320 dev_t dev; 1321 int bits, how; 1322 { 1323 struct dcm_softc *sc; 1324 struct dcmdevice *dcm; 1325 int s, unit, brd, port, hit = 0; 1326 1327 unit = DCMUNIT(dev); 1328 brd = DCMBOARD(unit); 1329 port = DCMPORT(unit); 1330 1331 sc = dcm_cd.cd_devs[brd]; 1332 dcm = sc->sc_dcm; 1333 1334 #ifdef DEBUG 1335 if (dcmdebug & DDB_MODEM) 1336 printf("%s port %d: dcmmctl: bits 0x%x how %x\n", 1337 sc->sc_dev.dv_xname, port, bits, how); 1338 #endif 1339 1340 s = spltty(); 1341 1342 switch (how) { 1343 case DMSET: 1344 sc->sc_modem[port]->mdmout = bits; 1345 hit++; 1346 break; 1347 1348 case DMBIS: 1349 sc->sc_modem[port]->mdmout |= bits; 1350 hit++; 1351 break; 1352 1353 case DMBIC: 1354 sc->sc_modem[port]->mdmout &= ~bits; 1355 hit++; 1356 break; 1357 1358 case DMGET: 1359 bits = sc->sc_modem[port]->mdmin; 1360 if (sc->sc_flags & DCM_STDDCE) 1361 bits = hp2dce_in(bits); 1362 break; 1363 } 1364 if (hit) { 1365 SEM_LOCK(dcm); 1366 dcm->dcm_modemchng |= 1<<(unit & 3); 1367 dcm->dcm_cr |= CR_MODM; 1368 SEM_UNLOCK(dcm); 1369 DELAY(10); /* delay until done */ 1370 splx(s); 1371 } 1372 return (bits); 1373 } 1374 1375 /* 1376 * Set board to either interrupt per-character or at a fixed interval. 1377 */ 1378 void 1379 dcmsetischeme(brd, flags) 1380 int brd, flags; 1381 { 1382 struct dcm_softc *sc = dcm_cd.cd_devs[brd]; 1383 struct dcmdevice *dcm = sc->sc_dcm; 1384 struct dcmischeme *dis = &sc->sc_scheme; 1385 int i; 1386 u_char mask; 1387 int perchar = flags & DIS_PERCHAR; 1388 1389 #ifdef DEBUG 1390 if (dcmdebug & DDB_INTSCHM) 1391 printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n", 1392 sc->sc_dev.dv_xname, perchar, dis->dis_perchar, 1393 dis->dis_intr, dis->dis_char); 1394 if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { 1395 printf("%s: dcmsetischeme: redundent request %d\n", 1396 sc->sc_dev.dv_xname, perchar); 1397 return; 1398 } 1399 #endif 1400 /* 1401 * If perchar is non-zero, we enable interrupts on all characters 1402 * otherwise we disable perchar interrupts and use periodic 1403 * polling interrupts. 1404 */ 1405 dis->dis_perchar = perchar; 1406 mask = perchar ? 0xf : 0x0; 1407 for (i = 0; i < 256; i++) 1408 dcm->dcm_bmap[i].data_data = mask; 1409 /* 1410 * Don't slow down tandem mode, interrupt on flow control 1411 * chars for any port on the board. 1412 */ 1413 if (!perchar) { 1414 struct tty *tp; 1415 int c; 1416 1417 for (i = 0; i < NDCMPORT; i++) { 1418 tp = sc->sc_tty[i]; 1419 1420 if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) 1421 dcm->dcm_bmap[c].data_data |= (1 << i); 1422 if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) 1423 dcm->dcm_bmap[c].data_data |= (1 << i); 1424 } 1425 } 1426 /* 1427 * Board starts with timer disabled so if first call is to 1428 * set perchar mode then we don't want to toggle the timer. 1429 */ 1430 if (flags == (DIS_RESET|DIS_PERCHAR)) 1431 return; 1432 /* 1433 * Toggle card 16.7ms interrupts (we first make sure that card 1434 * has cleared the bit so it will see the toggle). 1435 */ 1436 while (dcm->dcm_cr & CR_TIMER) 1437 ; 1438 SEM_LOCK(dcm); 1439 dcm->dcm_cr |= CR_TIMER; 1440 SEM_UNLOCK(dcm); 1441 } 1442 1443 void 1444 dcminit(dcm, port, rate) 1445 struct dcmdevice *dcm; 1446 int port, rate; 1447 { 1448 int s, mode; 1449 1450 mode = LC_8BITS | LC_1STOP; 1451 1452 s = splhigh(); 1453 1454 /* 1455 * Wait for transmitter buffer to empty. 1456 */ 1457 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 1458 DELAY(DCM_USPERCH(rate)); 1459 1460 /* 1461 * Make changes known to hardware. 1462 */ 1463 dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); 1464 dcm->dcm_data[port].dcm_conf = mode; 1465 SEM_LOCK(dcm); 1466 dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 1467 dcm->dcm_cr |= (1 << port); 1468 SEM_UNLOCK(dcm); 1469 1470 /* 1471 * Delay for config change to take place. Weighted by baud. 1472 * XXX why do we do this? 1473 */ 1474 DELAY(16 * DCM_USPERCH(rate)); 1475 splx(s); 1476 } 1477 1478 /* 1479 * Empirically derived self-test magic 1480 */ 1481 int 1482 dcmselftest(sc) 1483 struct dcm_softc *sc; 1484 { 1485 struct dcmdevice *dcm = sc->sc_dcm; 1486 int timo = 0; 1487 int s, rv; 1488 1489 rv = 1; 1490 1491 s = splhigh(); 1492 dcm->dcm_rsid = DCMRS; 1493 DELAY(50000); /* 5000 is not long enough */ 1494 dcm->dcm_rsid = 0; 1495 dcm->dcm_ic = IC_IE; 1496 dcm->dcm_cr = CR_SELFT; 1497 while ((dcm->dcm_ic & IC_IR) == 0) { 1498 if (++timo == 20000) 1499 goto out; 1500 DELAY(1); 1501 } 1502 DELAY(50000); /* XXX why is this needed ???? */ 1503 while ((dcm->dcm_iir & IIR_SELFT) == 0) { 1504 if (++timo == 400000) 1505 goto out; 1506 DELAY(1); 1507 } 1508 DELAY(50000); /* XXX why is this needed ???? */ 1509 if (dcm->dcm_stcon != ST_OK) { 1510 #if 0 1511 if (hd->hp_args->hw_sc != conscode) 1512 printf("dcm%d: self test failed: %x\n", 1513 brd, dcm->dcm_stcon); 1514 #endif 1515 goto out; 1516 } 1517 dcm->dcm_ic = IC_ID; 1518 rv = 0; 1519 1520 out: 1521 splx(s); 1522 return (rv); 1523 } 1524 1525 /* 1526 * Following are all routines needed for DCM to act as console 1527 */ 1528 1529 int 1530 dcmcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode) 1531 { 1532 bus_space_handle_t bsh; 1533 caddr_t va; 1534 struct dcmdevice *dcm; 1535 1536 if (bus_space_map(bst, addr, DIOCSIZE, 0, &bsh)) 1537 return (1); 1538 1539 va = bus_space_vaddr(bst, bsh); 1540 dcm = (struct dcmdevice *)va; 1541 1542 switch (dcm->dcm_rsid) { 1543 #ifdef CONSCODE 1544 case DCMID: 1545 #endif 1546 case DCMID|DCMCON: 1547 break; 1548 default: 1549 goto error; 1550 } 1551 1552 dcminit(dcm, DCMCONSPORT, dcmdefaultrate); 1553 dcmconsinit = 1; 1554 dcmconscode = scode; 1555 dcm_cn = dcm; 1556 1557 /* locate the major number */ 1558 for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) 1559 if (cdevsw[dcmmajor].d_open == dcmopen) 1560 break; 1561 1562 /* initialize required fields */ 1563 cn_tab = &dcm_cons; 1564 cn_tab->cn_dev = makedev(dcmmajor, 0); 1565 1566 #ifdef KGDB_CHEAT 1567 /* XXX this needs to be fixed. */ 1568 /* 1569 * This doesn't currently work, at least not with ite consoles; 1570 * the console hasn't been initialized yet. 1571 */ 1572 if (major(kgdb_dev) == dcmmajor && 1573 DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) { 1574 dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate); 1575 if (kgdb_debug_init) { 1576 /* 1577 * We assume that console is ready for us... 1578 * this assumes that a dca or ite console 1579 * has been selected already and will init 1580 * on the first putc. 1581 */ 1582 printf("dcm%d: ", DCMUNIT(kgdb_dev)); 1583 kgdb_connect(1); 1584 } 1585 } 1586 #endif 1587 1588 1589 return (0); 1590 1591 error: 1592 bus_space_unmap(bst, bsh, DIOCSIZE); 1593 return (1); 1594 } 1595 1596 /* ARGSUSED */ 1597 int 1598 dcmcngetc(dev) 1599 dev_t dev; 1600 { 1601 struct dcmrfifo *fifo; 1602 struct dcmpreg *pp; 1603 u_int head; 1604 int s, c, stat; 1605 1606 pp = dcm_preg(dcm_cn, DCMCONSPORT); 1607 1608 s = splhigh(); 1609 head = pp->r_head & RX_MASK; 1610 fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1]; 1611 while (head == (pp->r_tail & RX_MASK)) 1612 ; 1613 /* 1614 * If board interrupts are enabled, just let our received char 1615 * interrupt through in case some other port on the board was 1616 * busy. Otherwise we must clear the interrupt. 1617 */ 1618 SEM_LOCK(dcm_cn); 1619 if ((dcm_cn->dcm_ic & IC_IE) == 0) 1620 stat = dcm_cn->dcm_iir; 1621 SEM_UNLOCK(dcm_cn); 1622 c = fifo->data_char; 1623 stat = fifo->data_stat; 1624 pp->r_head = (head + 2) & RX_MASK; 1625 splx(s); 1626 return (c); 1627 } 1628 1629 /* 1630 * Console kernel output character routine. 1631 */ 1632 /* ARGSUSED */ 1633 void 1634 dcmcnputc(dev, c) 1635 dev_t dev; 1636 int c; 1637 { 1638 struct dcmpreg *pp; 1639 unsigned tail; 1640 int s, stat; 1641 1642 pp = dcm_preg(dcm_cn, DCMCONSPORT); 1643 1644 s = splhigh(); 1645 #ifdef KGDB 1646 if (dev != kgdb_dev) 1647 #endif 1648 if (dcmconsinit == 0) { 1649 dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate); 1650 dcmconsinit = 1; 1651 } 1652 tail = pp->t_tail & TX_MASK; 1653 while (tail != (pp->t_head & TX_MASK)) 1654 ; 1655 dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c; 1656 pp->t_tail = tail = (tail + 1) & TX_MASK; 1657 SEM_LOCK(dcm_cn); 1658 dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX; 1659 dcm_cn->dcm_cr |= (1 << DCMCONSPORT); 1660 SEM_UNLOCK(dcm_cn); 1661 while (tail != (pp->t_head & TX_MASK)) 1662 ; 1663 /* 1664 * If board interrupts are enabled, just let our completion 1665 * interrupt through in case some other port on the board 1666 * was busy. Otherwise we must clear the interrupt. 1667 */ 1668 if ((dcm_cn->dcm_ic & IC_IE) == 0) { 1669 SEM_LOCK(dcm_cn); 1670 stat = dcm_cn->dcm_iir; 1671 SEM_UNLOCK(dcm_cn); 1672 } 1673 splx(s); 1674 } 1675