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