rc.c revision 105224
1/* 2 * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia. 3 * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/rc/rc.c 105224 2002-10-16 10:16:17Z phk $ 28 * 29 */ 30 31/* 32 * SDL Communications Riscom/8 (based on Cirrus Logic CL-CD180) driver 33 * 34 */ 35 36#include "rc.h" 37 38/*#define RCDEBUG*/ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/tty.h> 44#include <sys/conf.h> 45#include <sys/dkstat.h> 46#include <sys/fcntl.h> 47#include <sys/bus.h> 48#include <sys/interrupt.h> 49 50 51#include <i386/isa/isa_device.h> 52 53#include <i386/isa/ic/cd180.h> 54#include <i386/isa/rcreg.h> 55 56/* Prototypes */ 57static int rcprobe(struct isa_device *); 58static int rcattach(struct isa_device *); 59 60#define rcin(port) RC_IN (nec, port) 61#define rcout(port,v) RC_OUT (nec, port, v) 62 63#define WAITFORCCR(u,c) rc_wait0(nec, (u), (c), __LINE__) 64#define CCRCMD(u,c,cmd) WAITFORCCR((u), (c)); rcout(CD180_CCR, (cmd)) 65 66#define RC_IBUFSIZE 256 67#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) 68#define RC_OBUFSIZE 512 69#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) 70#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) 71#define LOTS_OF_EVENTS 64 72 73#define RC_FAKEID 0x10 74 75#define RC_PROBED 1 76#define RC_ATTACHED 2 77 78#define GET_UNIT(dev) (minor(dev) & 0x3F) 79#define CALLOUT(dev) (minor(dev) & 0x80) 80 81/* For isa routines */ 82struct isa_driver rcdriver = { 83 INTR_TYPE_TTY, 84 rcprobe, 85 rcattach, 86 "rc" 87}; 88COMPAT_ISA_DRIVER(rc, rcdriver); 89 90static d_open_t rcopen; 91static d_close_t rcclose; 92static d_ioctl_t rcioctl; 93 94#define CDEV_MAJOR 63 95static struct cdevsw rc_cdevsw = { 96 /* open */ rcopen, 97 /* close */ rcclose, 98 /* read */ ttyread, 99 /* write */ ttywrite, 100 /* ioctl */ rcioctl, 101 /* poll */ ttypoll, 102 /* mmap */ nommap, 103 /* strategy */ nostrategy, 104 /* name */ "rc", 105 /* maj */ CDEV_MAJOR, 106 /* dump */ nodump, 107 /* psize */ nopsize, 108 /* flags */ D_TTY | D_KQFILTER, 109 /* kqfilter */ ttykqfilter, 110}; 111 112/* Per-board structure */ 113static struct rc_softc { 114 u_int rcb_probed; /* 1 - probed, 2 - attached */ 115 u_int rcb_addr; /* Base I/O addr */ 116 u_int rcb_unit; /* unit # */ 117 u_char rcb_dtr; /* DTR status */ 118 struct rc_chans *rcb_baserc; /* base rc ptr */ 119} rc_softc[NRC]; 120 121/* Per-channel structure */ 122static struct rc_chans { 123 struct rc_softc *rc_rcb; /* back ptr */ 124 u_short rc_flags; /* Misc. flags */ 125 int rc_chan; /* Channel # */ 126 u_char rc_ier; /* intr. enable reg */ 127 u_char rc_msvr; /* modem sig. status */ 128 u_char rc_cor2; /* options reg */ 129 u_char rc_pendcmd; /* special cmd pending */ 130 u_int rc_dtrwait; /* dtr timeout */ 131 u_int rc_dcdwaits; /* how many waits DCD in open */ 132 u_char rc_hotchar; /* end packed optimize */ 133 struct tty *rc_tp; /* tty struct */ 134 u_char *rc_iptr; /* Chars input buffer */ 135 u_char *rc_hiwat; /* hi-water mark */ 136 u_char *rc_bufend; /* end of buffer */ 137 u_char *rc_optr; /* ptr in output buf */ 138 u_char *rc_obufend; /* end of output buf */ 139 u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */ 140 u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */ 141} rc_chans[NRC * CD180_NCHAN]; 142 143static int rc_scheduled_event = 0; 144 145/* for pstat -t */ 146static struct tty rc_tty[NRC * CD180_NCHAN]; 147static const int nrc_tty = NRC * CD180_NCHAN; 148 149/* Flags */ 150#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ 151#define RC_ACTOUT 0x0002 /* Dial-out port active */ 152#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ 153#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ 154#define RC_DORXFER 0x0010 /* RXFER event planned */ 155#define RC_DOXXFER 0x0020 /* XXFER event planned */ 156#define RC_MODCHG 0x0040 /* Modem status changed */ 157#define RC_OSUSP 0x0080 /* Output suspended */ 158#define RC_OSBUSY 0x0100 /* start() routine in progress */ 159#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ 160#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ 161#define RC_SEND_RDY 0x0800 /* ready to send */ 162 163/* Table for translation of RCSR status bits to internal form */ 164static int rc_rcsrt[16] = { 165 0, TTY_OE, TTY_FE, 166 TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE, 167 TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI, 168 TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE, 169 TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE, 170 TTY_BI|TTY_PE|TTY_FE|TTY_OE 171}; 172 173static void *rc_ih; 174 175/* Static prototypes */ 176static ointhand2_t rcintr; 177static void rc_hwreset(int, int, unsigned int); 178static int rc_test(int, int); 179static void rc_discard_output(struct rc_chans *); 180static void rc_hardclose(struct rc_chans *); 181static int rc_modctl(struct rc_chans *, int, int); 182static void rc_start(struct tty *); 183static void rc_stop(struct tty *, int rw); 184static int rc_param(struct tty *, struct termios *); 185static void rcpoll(void *); 186static void rc_reinit(struct rc_softc *); 187#ifdef RCDEBUG 188static void printrcflags(); 189#endif 190static timeout_t rc_dtrwakeup; 191static timeout_t rc_wakeup; 192static void disc_optim(struct tty *tp, struct termios *t, struct rc_chans *); 193static void rc_wait0(int nec, int unit, int chan, int line); 194 195/**********************************************/ 196 197/* Quick device probing */ 198static int 199rcprobe(dvp) 200 struct isa_device *dvp; 201{ 202 int irq = ffs(dvp->id_irq) - 1; 203 register int nec = dvp->id_iobase; 204 205 if (dvp->id_unit > NRC) 206 return 0; 207 if (!RC_VALIDADDR(nec)) { 208 printf("rc%d: illegal base address %x\n", dvp->id_unit, nec); 209 return 0; 210 } 211 if (!RC_VALIDIRQ(irq)) { 212 printf("rc%d: illegal IRQ value %d\n", dvp->id_unit, irq); 213 return 0; 214 } 215 rcout(CD180_PPRL, 0x22); /* Random values to Prescale reg. */ 216 rcout(CD180_PPRH, 0x11); 217 if (rcin(CD180_PPRL) != 0x22 || rcin(CD180_PPRH) != 0x11) 218 return 0; 219 /* Now, test the board more thoroughly, with diagnostic */ 220 if (rc_test(nec, dvp->id_unit)) 221 return 0; 222 rc_softc[dvp->id_unit].rcb_probed = RC_PROBED; 223 224 return 0xF; 225} 226 227static int 228rcattach(dvp) 229 struct isa_device *dvp; 230{ 231 register int chan, nec = dvp->id_iobase; 232 struct rc_softc *rcb = &rc_softc[dvp->id_unit]; 233 struct rc_chans *rc = &rc_chans[dvp->id_unit * CD180_NCHAN]; 234 static int rc_started = 0; 235 struct tty *tp; 236 237 dvp->id_ointr = rcintr; 238 239 /* Thorooughly test the device */ 240 if (rcb->rcb_probed != RC_PROBED) 241 return 0; 242 rcb->rcb_addr = nec; 243 rcb->rcb_dtr = 0; 244 rcb->rcb_baserc = rc; 245 rcb->rcb_unit = dvp->id_unit; 246 /*rcb->rcb_chipid = 0x10 + dvp->id_unit;*/ 247 printf("rc%d: %d chans, firmware rev. %c\n", rcb->rcb_unit, 248 CD180_NCHAN, (rcin(CD180_GFRCR) & 0xF) + 'A'); 249 250 for (chan = 0; chan < CD180_NCHAN; chan++, rc++) { 251 rc->rc_rcb = rcb; 252 rc->rc_chan = chan; 253 rc->rc_iptr = rc->rc_ibuf; 254 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 255 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 256 rc->rc_flags = rc->rc_ier = rc->rc_msvr = 0; 257 rc->rc_cor2 = rc->rc_pendcmd = 0; 258 rc->rc_optr = rc->rc_obufend = rc->rc_obuf; 259 rc->rc_dtrwait = 3 * hz; 260 rc->rc_dcdwaits= 0; 261 rc->rc_hotchar = 0; 262 tp = rc->rc_tp = &rc_tty[chan + (dvp->id_unit * CD180_NCHAN)]; 263 ttychars(tp); 264 tp->t_lflag = tp->t_iflag = tp->t_oflag = 0; 265 tp->t_cflag = TTYDEF_CFLAG; 266 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 267 make_dev(&rc_cdevsw, chan + CD180_NCHAN * rcb->rcb_unit, 268 UID_ROOT, GID_WHEEL, 0600, "ttym%d", chan + CD180_NCHAN * 269 rcb->rcb_unit); 270 make_dev(&rc_cdevsw, chan + CD180_NCHAN * rcb->rcb_unit + 128, 271 UID_UUCP, GID_DIALER, 0660, "cuam%d", chan + CD180_NCHAN * 272 rcb->rcb_unit); 273 } 274 rcb->rcb_probed = RC_ATTACHED; 275 if (!rc_started) { 276 cdevsw_add(&rc_cdevsw); 277 swi_add(&tty_ithd, "tty:rc", rcpoll, NULL, SWI_TTY, 0, &rc_ih); 278 rc_wakeup((void *)NULL); 279 rc_started = 1; 280 } 281 return 1; 282} 283 284/* RC interrupt handling */ 285static void 286rcintr(unit) 287 int unit; 288{ 289 register struct rc_softc *rcb = &rc_softc[unit]; 290 register struct rc_chans *rc; 291 register int nec, resid; 292 register u_char val, iack, bsr, ucnt, *optr; 293 int good_data, t_state; 294 295 if (rcb->rcb_probed != RC_ATTACHED) { 296 printf("rc%d: bogus interrupt\n", unit); 297 return; 298 } 299 nec = rcb->rcb_addr; 300 301 bsr = ~(rcin(RC_BSR)); 302 303 if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { 304 printf("rc%d: extra interrupt\n", unit); 305 rcout(CD180_EOIR, 0); 306 return; 307 } 308 309 while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { 310#ifdef RCDEBUG_DETAILED 311 printf("rc%d: intr (%02x) %s%s%s%s\n", unit, bsr, 312 (bsr & RC_BSR_TOUT)?"TOUT ":"", 313 (bsr & RC_BSR_RXINT)?"RXINT ":"", 314 (bsr & RC_BSR_TXINT)?"TXINT ":"", 315 (bsr & RC_BSR_MOINT)?"MOINT":""); 316#endif 317 if (bsr & RC_BSR_TOUT) { 318 printf("rc%d: hardware failure, reset board\n", unit); 319 rcout(RC_CTOUT, 0); 320 rc_reinit(rcb); 321 return; 322 } 323 if (bsr & RC_BSR_RXINT) { 324 iack = rcin(RC_PILR_RX); 325 good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); 326 if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { 327 printf("rc%d: fake rxint: %02x\n", unit, iack); 328 goto more_intrs; 329 } 330 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH); 331 t_state = rc->rc_tp->t_state; 332 /* Do RTS flow control stuff */ 333 if ( (rc->rc_flags & RC_RTSFLOW) 334 || !(t_state & TS_ISOPEN) 335 ) { 336 if ( ( !(t_state & TS_ISOPEN) 337 || (t_state & TS_TBLOCK) 338 ) 339 && (rc->rc_msvr & MSVR_RTS) 340 ) 341 rcout(CD180_MSVR, 342 rc->rc_msvr &= ~MSVR_RTS); 343 else if (!(rc->rc_msvr & MSVR_RTS)) 344 rcout(CD180_MSVR, 345 rc->rc_msvr |= MSVR_RTS); 346 } 347 ucnt = rcin(CD180_RDCR) & 0xF; 348 resid = 0; 349 350 if (t_state & TS_ISOPEN) { 351 /* check for input buffer overflow */ 352 if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { 353 resid = ucnt; 354 ucnt = rc->rc_bufend - rc->rc_iptr; 355 resid -= ucnt; 356 if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { 357 rc->rc_flags |= RC_WAS_BUFOVFL; 358 rc_scheduled_event++; 359 } 360 } 361 optr = rc->rc_iptr; 362 /* check foor good data */ 363 if (good_data) { 364 while (ucnt-- > 0) { 365 val = rcin(CD180_RDR); 366 optr[0] = val; 367 optr[INPUT_FLAGS_SHIFT] = 0; 368 optr++; 369 rc_scheduled_event++; 370 if (val != 0 && val == rc->rc_hotchar) 371 swi_sched(rc_ih, 0); 372 } 373 } else { 374 /* Store also status data */ 375 while (ucnt-- > 0) { 376 iack = rcin(CD180_RCSR); 377 if (iack & RCSR_Timeout) 378 break; 379 if ( (iack & RCSR_OE) 380 && !(rc->rc_flags & RC_WAS_SILOVFL)) { 381 rc->rc_flags |= RC_WAS_SILOVFL; 382 rc_scheduled_event++; 383 } 384 val = rcin(CD180_RDR); 385 /* 386 Don't store PE if IGNPAR and BREAK if IGNBRK, 387 this hack allows "raw" tty optimization 388 works even if IGN* is set. 389 */ 390 if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) 391 || ((!(iack & (RCSR_PE|RCSR_FE)) 392 || !(rc->rc_tp->t_iflag & IGNPAR)) 393 && (!(iack & RCSR_Break) 394 || !(rc->rc_tp->t_iflag & IGNBRK)))) { 395 if ( (iack & (RCSR_PE|RCSR_FE)) 396 && (t_state & TS_CAN_BYPASS_L_RINT) 397 && ((iack & RCSR_FE) 398 || ((iack & RCSR_PE) 399 && (rc->rc_tp->t_iflag & INPCK)))) 400 val = 0; 401 else if (val != 0 && val == rc->rc_hotchar) 402 swi_sched(rc_ih, 0); 403 optr[0] = val; 404 optr[INPUT_FLAGS_SHIFT] = iack; 405 optr++; 406 rc_scheduled_event++; 407 } 408 } 409 } 410 rc->rc_iptr = optr; 411 rc->rc_flags |= RC_DORXFER; 412 } else 413 resid = ucnt; 414 /* Clear FIFO if necessary */ 415 while (resid-- > 0) { 416 if (!good_data) 417 iack = rcin(CD180_RCSR); 418 else 419 iack = 0; 420 if (iack & RCSR_Timeout) 421 break; 422 (void) rcin(CD180_RDR); 423 } 424 goto more_intrs; 425 } 426 if (bsr & RC_BSR_MOINT) { 427 iack = rcin(RC_PILR_MODEM); 428 if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { 429 printf("rc%d: fake moint: %02x\n", unit, iack); 430 goto more_intrs; 431 } 432 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH); 433 iack = rcin(CD180_MCR); 434 rc->rc_msvr = rcin(CD180_MSVR); 435 rcout(CD180_MCR, 0); 436#ifdef RCDEBUG 437 printrcflags(rc, "moint"); 438#endif 439 if (rc->rc_flags & RC_CTSFLOW) { 440 if (rc->rc_msvr & MSVR_CTS) 441 rc->rc_flags |= RC_SEND_RDY; 442 else 443 rc->rc_flags &= ~RC_SEND_RDY; 444 } else 445 rc->rc_flags |= RC_SEND_RDY; 446 if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { 447 rc_scheduled_event += LOTS_OF_EVENTS; 448 rc->rc_flags |= RC_MODCHG; 449 swi_sched(rc_ih, 0); 450 } 451 goto more_intrs; 452 } 453 if (bsr & RC_BSR_TXINT) { 454 iack = rcin(RC_PILR_TX); 455 if (iack != (GIVR_IT_TDI | RC_FAKEID)) { 456 printf("rc%d: fake txint: %02x\n", unit, iack); 457 goto more_intrs; 458 } 459 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH); 460 if ( (rc->rc_flags & RC_OSUSP) 461 || !(rc->rc_flags & RC_SEND_RDY) 462 ) 463 goto more_intrs; 464 /* Handle breaks and other stuff */ 465 if (rc->rc_pendcmd) { 466 rcout(CD180_COR2, rc->rc_cor2 |= COR2_ETC); 467 rcout(CD180_TDR, CD180_C_ESC); 468 rcout(CD180_TDR, rc->rc_pendcmd); 469 rcout(CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); 470 rc->rc_pendcmd = 0; 471 goto more_intrs; 472 } 473 optr = rc->rc_optr; 474 resid = rc->rc_obufend - optr; 475 if (resid > CD180_NFIFO) 476 resid = CD180_NFIFO; 477 while (resid-- > 0) 478 rcout(CD180_TDR, *optr++); 479 rc->rc_optr = optr; 480 481 /* output completed? */ 482 if (optr >= rc->rc_obufend) { 483 rcout(CD180_IER, rc->rc_ier &= ~IER_TxRdy); 484#ifdef RCDEBUG 485 printf("rc%d/%d: output completed\n", unit, rc->rc_chan); 486#endif 487 if (!(rc->rc_flags & RC_DOXXFER)) { 488 rc_scheduled_event += LOTS_OF_EVENTS; 489 rc->rc_flags |= RC_DOXXFER; 490 swi_sched(rc_ih, 0); 491 } 492 } 493 } 494 more_intrs: 495 rcout(CD180_EOIR, 0); /* end of interrupt */ 496 rcout(RC_CTOUT, 0); 497 bsr = ~(rcin(RC_BSR)); 498 } 499} 500 501/* Feed characters to output buffer */ 502static void rc_start(tp) 503register struct tty *tp; 504{ 505 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; 506 register int nec = rc->rc_rcb->rcb_addr, s; 507 508 if (rc->rc_flags & RC_OSBUSY) 509 return; 510 s = spltty(); 511 rc->rc_flags |= RC_OSBUSY; 512 disable_intr(); 513 if (tp->t_state & TS_TTSTOP) 514 rc->rc_flags |= RC_OSUSP; 515 else 516 rc->rc_flags &= ~RC_OSUSP; 517 /* Do RTS flow control stuff */ 518 if ( (rc->rc_flags & RC_RTSFLOW) 519 && (tp->t_state & TS_TBLOCK) 520 && (rc->rc_msvr & MSVR_RTS) 521 ) { 522 rcout(CD180_CAR, rc->rc_chan); 523 rcout(CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); 524 } else if (!(rc->rc_msvr & MSVR_RTS)) { 525 rcout(CD180_CAR, rc->rc_chan); 526 rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS); 527 } 528 enable_intr(); 529 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 530 goto out; 531#ifdef RCDEBUG 532 printrcflags(rc, "rcstart"); 533#endif 534 ttwwakeup(tp); 535#ifdef RCDEBUG 536 printf("rcstart: outq = %d obuf = %d\n", 537 tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); 538#endif 539 if (tp->t_state & TS_BUSY) 540 goto out; /* output still in progress ... */ 541 542 if (tp->t_outq.c_cc > 0) { 543 u_int ocnt; 544 545 tp->t_state |= TS_BUSY; 546 ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); 547 disable_intr(); 548 rc->rc_optr = rc->rc_obuf; 549 rc->rc_obufend = rc->rc_optr + ocnt; 550 enable_intr(); 551 if (!(rc->rc_ier & IER_TxRdy)) { 552#ifdef RCDEBUG 553 printf("rc%d/%d: rcstart enable txint\n", rc->rc_rcb->rcb_unit, rc->rc_chan); 554#endif 555 rcout(CD180_CAR, rc->rc_chan); 556 rcout(CD180_IER, rc->rc_ier |= IER_TxRdy); 557 } 558 } 559out: 560 rc->rc_flags &= ~RC_OSBUSY; 561 (void) splx(s); 562} 563 564/* Handle delayed events. */ 565static void 566rcpoll(void *arg) 567{ 568 register struct rc_chans *rc; 569 register struct rc_softc *rcb; 570 register u_char *tptr, *eptr; 571 register struct tty *tp; 572 register int chan, icnt, nec, unit; 573 574 if (rc_scheduled_event == 0) 575 return; 576repeat: 577 for (unit = 0; unit < NRC; unit++) { 578 rcb = &rc_softc[unit]; 579 rc = rcb->rcb_baserc; 580 nec = rc->rc_rcb->rcb_addr; 581 for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { 582 tp = rc->rc_tp; 583#ifdef RCDEBUG 584 if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| 585 RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) 586 printrcflags(rc, "rcevent"); 587#endif 588 if (rc->rc_flags & RC_WAS_BUFOVFL) { 589 disable_intr(); 590 rc->rc_flags &= ~RC_WAS_BUFOVFL; 591 rc_scheduled_event--; 592 enable_intr(); 593 printf("rc%d/%d: interrupt-level buffer overflow\n", 594 unit, chan); 595 } 596 if (rc->rc_flags & RC_WAS_SILOVFL) { 597 disable_intr(); 598 rc->rc_flags &= ~RC_WAS_SILOVFL; 599 rc_scheduled_event--; 600 enable_intr(); 601 printf("rc%d/%d: silo overflow\n", 602 unit, chan); 603 } 604 if (rc->rc_flags & RC_MODCHG) { 605 disable_intr(); 606 rc->rc_flags &= ~RC_MODCHG; 607 rc_scheduled_event -= LOTS_OF_EVENTS; 608 enable_intr(); 609 (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD)); 610 } 611 if (rc->rc_flags & RC_DORXFER) { 612 disable_intr(); 613 rc->rc_flags &= ~RC_DORXFER; 614 eptr = rc->rc_iptr; 615 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) 616 tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 617 else 618 tptr = rc->rc_ibuf; 619 icnt = eptr - tptr; 620 if (icnt > 0) { 621 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 622 rc->rc_iptr = rc->rc_ibuf; 623 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 624 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 625 } else { 626 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 627 rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; 628 rc->rc_hiwat = 629 &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; 630 } 631 if ( (rc->rc_flags & RC_RTSFLOW) 632 && (tp->t_state & TS_ISOPEN) 633 && !(tp->t_state & TS_TBLOCK) 634 && !(rc->rc_msvr & MSVR_RTS) 635 ) { 636 rcout(CD180_CAR, chan); 637 rcout(CD180_MSVR, 638 rc->rc_msvr |= MSVR_RTS); 639 } 640 rc_scheduled_event -= icnt; 641 } 642 enable_intr(); 643 644 if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) 645 goto done1; 646 647 if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) 648 && !(tp->t_state & TS_LOCAL)) { 649 if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER 650 && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) 651 && !(tp->t_state & TS_TBLOCK)) 652 ttyblock(tp); 653 tk_nin += icnt; 654 tk_rawcc += icnt; 655 tp->t_rawcc += icnt; 656 if (b_to_q(tptr, icnt, &tp->t_rawq)) 657 printf("rc%d/%d: tty-level buffer overflow\n", 658 unit, chan); 659 ttwakeup(tp); 660 if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) 661 || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { 662 tp->t_state &= ~TS_TTSTOP; 663 tp->t_lflag &= ~FLUSHO; 664 rc_start(tp); 665 } 666 } else { 667 for (; tptr < eptr; tptr++) 668 (*linesw[tp->t_line].l_rint) 669 (tptr[0] | 670 rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp); 671 } 672done1: ; 673 } 674 if (rc->rc_flags & RC_DOXXFER) { 675 disable_intr(); 676 rc_scheduled_event -= LOTS_OF_EVENTS; 677 rc->rc_flags &= ~RC_DOXXFER; 678 rc->rc_tp->t_state &= ~TS_BUSY; 679 enable_intr(); 680 (*linesw[tp->t_line].l_start)(tp); 681 } 682 } 683 if (rc_scheduled_event == 0) 684 break; 685 } 686 if (rc_scheduled_event >= LOTS_OF_EVENTS) 687 goto repeat; 688} 689 690static void 691rc_stop(tp, rw) 692 register struct tty *tp; 693 int rw; 694{ 695 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; 696 u_char *tptr, *eptr; 697 698#ifdef RCDEBUG 699 printf("rc%d/%d: rc_stop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan, 700 (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); 701#endif 702 if (rw & FWRITE) 703 rc_discard_output(rc); 704 disable_intr(); 705 if (rw & FREAD) { 706 rc->rc_flags &= ~RC_DORXFER; 707 eptr = rc->rc_iptr; 708 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 709 tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 710 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 711 } else { 712 tptr = rc->rc_ibuf; 713 rc->rc_iptr = rc->rc_ibuf; 714 } 715 rc_scheduled_event -= eptr - tptr; 716 } 717 if (tp->t_state & TS_TTSTOP) 718 rc->rc_flags |= RC_OSUSP; 719 else 720 rc->rc_flags &= ~RC_OSUSP; 721 enable_intr(); 722} 723 724static int 725rcopen(dev, flag, mode, td) 726 dev_t dev; 727 int flag, mode; 728 struct thread *td; 729{ 730 register struct rc_chans *rc; 731 register struct tty *tp; 732 int unit, nec, s, error = 0; 733 734 unit = GET_UNIT(dev); 735 if (unit >= NRC * CD180_NCHAN) 736 return ENXIO; 737 if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED) 738 return ENXIO; 739 rc = &rc_chans[unit]; 740 tp = rc->rc_tp; 741 dev->si_tty = tp; 742 nec = rc->rc_rcb->rcb_addr; 743#ifdef RCDEBUG 744 printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev); 745#endif 746 s = spltty(); 747 748again: 749 while (rc->rc_flags & RC_DTR_OFF) { 750 error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0); 751 if (error != 0) 752 goto out; 753 } 754 if (tp->t_state & TS_ISOPEN) { 755 if (CALLOUT(dev)) { 756 if (!(rc->rc_flags & RC_ACTOUT)) { 757 error = EBUSY; 758 goto out; 759 } 760 } else { 761 if (rc->rc_flags & RC_ACTOUT) { 762 if (flag & O_NONBLOCK) { 763 error = EBUSY; 764 goto out; 765 } 766 error = tsleep(&rc->rc_rcb, 767 TTIPRI|PCATCH, "rcbi", 0); 768 if (error) 769 goto out; 770 goto again; 771 } 772 } 773 if (tp->t_state & TS_XCLUDE && 774 suser(td)) { 775 error = EBUSY; 776 goto out; 777 } 778 } else { 779 tp->t_oproc = rc_start; 780 tp->t_param = rc_param; 781 tp->t_stop = rc_stop; 782 tp->t_dev = dev; 783 784 if (CALLOUT(dev)) 785 tp->t_cflag |= CLOCAL; 786 else 787 tp->t_cflag &= ~CLOCAL; 788 789 error = rc_param(tp, &tp->t_termios); 790 if (error) 791 goto out; 792 (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET); 793 794 if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev)) 795 (*linesw[tp->t_line].l_modem)(tp, 1); 796 } 797 if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev) 798 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 799 rc->rc_dcdwaits++; 800 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0); 801 rc->rc_dcdwaits--; 802 if (error != 0) 803 goto out; 804 goto again; 805 } 806 error = (*linesw[tp->t_line].l_open)(dev, tp); 807 disc_optim(tp, &tp->t_termios, rc); 808 if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev)) 809 rc->rc_flags |= RC_ACTOUT; 810out: 811 (void) splx(s); 812 813 if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN)) 814 rc_hardclose(rc); 815 816 return error; 817} 818 819static int 820rcclose(dev, flag, mode, td) 821 dev_t dev; 822 int flag, mode; 823 struct thread *td; 824{ 825 register struct rc_chans *rc; 826 register struct tty *tp; 827 int s, unit = GET_UNIT(dev); 828 829 if (unit >= NRC * CD180_NCHAN) 830 return ENXIO; 831 rc = &rc_chans[unit]; 832 tp = rc->rc_tp; 833#ifdef RCDEBUG 834 printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev); 835#endif 836 s = spltty(); 837 (*linesw[tp->t_line].l_close)(tp, flag); 838 disc_optim(tp, &tp->t_termios, rc); 839 rc_stop(tp, FREAD | FWRITE); 840 rc_hardclose(rc); 841 ttyclose(tp); 842 splx(s); 843 return 0; 844} 845 846static void rc_hardclose(rc) 847register struct rc_chans *rc; 848{ 849 register int s, nec = rc->rc_rcb->rcb_addr; 850 register struct tty *tp = rc->rc_tp; 851 852 s = spltty(); 853 rcout(CD180_CAR, rc->rc_chan); 854 855 /* Disable rx/tx intrs */ 856 rcout(CD180_IER, rc->rc_ier = 0); 857 if ( (tp->t_cflag & HUPCL) 858 || (!(rc->rc_flags & RC_ACTOUT) 859 && !(rc->rc_msvr & MSVR_CD) 860 && !(tp->t_cflag & CLOCAL)) 861 || !(tp->t_state & TS_ISOPEN) 862 ) { 863 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan); 864 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); 865 (void) rc_modctl(rc, TIOCM_RTS, DMSET); 866 if (rc->rc_dtrwait) { 867 timeout(rc_dtrwakeup, rc, rc->rc_dtrwait); 868 rc->rc_flags |= RC_DTR_OFF; 869 } 870 } 871 rc->rc_flags &= ~RC_ACTOUT; 872 wakeup((caddr_t) &rc->rc_rcb); /* wake bi */ 873 wakeup(TSA_CARR_ON(tp)); 874 (void) splx(s); 875} 876 877/* Reset the bastard */ 878static void rc_hwreset(unit, nec, chipid) 879 register int unit, nec; 880 unsigned int chipid; 881{ 882 CCRCMD(unit, -1, CCR_HWRESET); /* Hardware reset */ 883 DELAY(20000); 884 WAITFORCCR(unit, -1); 885 886 rcout(RC_CTOUT, 0); /* Clear timeout */ 887 rcout(CD180_GIVR, chipid); 888 rcout(CD180_GICR, 0); 889 890 /* Set Prescaler Registers (1 msec) */ 891 rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); 892 rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); 893 894 /* Initialize Priority Interrupt Level Registers */ 895 rcout(CD180_PILR1, RC_PILR_MODEM); 896 rcout(CD180_PILR2, RC_PILR_TX); 897 rcout(CD180_PILR3, RC_PILR_RX); 898 899 /* Reset DTR */ 900 rcout(RC_DTREG, ~0); 901} 902 903/* Set channel parameters */ 904static int rc_param(tp, ts) 905 register struct tty *tp; 906 struct termios *ts; 907{ 908 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; 909 register int nec = rc->rc_rcb->rcb_addr; 910 int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; 911 912 if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 913 || ts->c_ispeed < 0 || ts->c_ispeed > 76800 914 ) 915 return (EINVAL); 916 if (ts->c_ispeed == 0) 917 ts->c_ispeed = ts->c_ospeed; 918 odivs = RC_BRD(ts->c_ospeed); 919 idivs = RC_BRD(ts->c_ispeed); 920 921 s = spltty(); 922 923 /* Select channel */ 924 rcout(CD180_CAR, rc->rc_chan); 925 926 /* If speed == 0, hangup line */ 927 if (ts->c_ospeed == 0) { 928 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan); 929 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); 930 (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 931 } 932 933 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 934 cflag = ts->c_cflag; 935 iflag = ts->c_iflag; 936 lflag = ts->c_lflag; 937 938 if (idivs > 0) { 939 rcout(CD180_RBPRL, idivs & 0xFF); 940 rcout(CD180_RBPRH, idivs >> 8); 941 } 942 if (odivs > 0) { 943 rcout(CD180_TBPRL, odivs & 0xFF); 944 rcout(CD180_TBPRH, odivs >> 8); 945 } 946 947 /* set timeout value */ 948 if (ts->c_ispeed > 0) { 949 int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; 950 951 if ( !(lflag & ICANON) 952 && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 953 && ts->c_cc[VTIME] * 10 > itm) 954 itm = ts->c_cc[VTIME] * 10; 955 956 rcout(CD180_RTPR, itm <= 255 ? itm : 255); 957 } 958 959 switch (cflag & CSIZE) { 960 case CS5: val = COR1_5BITS; break; 961 case CS6: val = COR1_6BITS; break; 962 case CS7: val = COR1_7BITS; break; 963 default: 964 case CS8: val = COR1_8BITS; break; 965 } 966 if (cflag & PARENB) { 967 val |= COR1_NORMPAR; 968 if (cflag & PARODD) 969 val |= COR1_ODDP; 970 if (!(cflag & INPCK)) 971 val |= COR1_Ignore; 972 } else 973 val |= COR1_Ignore; 974 if (cflag & CSTOPB) 975 val |= COR1_2SB; 976 rcout(CD180_COR1, val); 977 978 /* Set FIFO threshold */ 979 val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; 980 inpflow = 0; 981 if ( (iflag & IXOFF) 982 && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE 983 && ( ts->c_cc[VSTART] != _POSIX_VDISABLE 984 || (iflag & IXANY) 985 ) 986 ) 987 ) { 988 inpflow = 1; 989 val |= COR3_SCDE|COR3_FCT; 990 } 991 rcout(CD180_COR3, val); 992 993 /* Initialize on-chip automatic flow control */ 994 val = 0; 995 rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); 996 if (cflag & CCTS_OFLOW) { 997 rc->rc_flags |= RC_CTSFLOW; 998 val |= COR2_CtsAE; 999 } else 1000 rc->rc_flags |= RC_SEND_RDY; 1001 if (tp->t_state & TS_TTSTOP) 1002 rc->rc_flags |= RC_OSUSP; 1003 else 1004 rc->rc_flags &= ~RC_OSUSP; 1005 if (cflag & CRTS_IFLOW) 1006 rc->rc_flags |= RC_RTSFLOW; 1007 else 1008 rc->rc_flags &= ~RC_RTSFLOW; 1009 1010 if (inpflow) { 1011 if (ts->c_cc[VSTART] != _POSIX_VDISABLE) 1012 rcout(CD180_SCHR1, ts->c_cc[VSTART]); 1013 rcout(CD180_SCHR2, ts->c_cc[VSTOP]); 1014 val |= COR2_TxIBE; 1015 if (iflag & IXANY) 1016 val |= COR2_IXM; 1017 } 1018 1019 rcout(CD180_COR2, rc->rc_cor2 = val); 1020 1021 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, 1022 CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1023 1024 disc_optim(tp, ts, rc); 1025 1026 /* modem ctl */ 1027 val = cflag & CLOCAL ? 0 : MCOR1_CDzd; 1028 if (cflag & CCTS_OFLOW) 1029 val |= MCOR1_CTSzd; 1030 rcout(CD180_MCOR1, val); 1031 1032 val = cflag & CLOCAL ? 0 : MCOR2_CDod; 1033 if (cflag & CCTS_OFLOW) 1034 val |= MCOR2_CTSod; 1035 rcout(CD180_MCOR2, val); 1036 1037 /* enable i/o and interrupts */ 1038 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, 1039 CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); 1040 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); 1041 1042 rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; 1043 if (cflag & CCTS_OFLOW) 1044 rc->rc_ier |= IER_CTS; 1045 if (cflag & CREAD) 1046 rc->rc_ier |= IER_RxData; 1047 if (tp->t_state & TS_BUSY) 1048 rc->rc_ier |= IER_TxRdy; 1049 if (ts->c_ospeed != 0) 1050 rc_modctl(rc, TIOCM_DTR, DMBIS); 1051 if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) 1052 rc->rc_flags |= RC_SEND_RDY; 1053 rcout(CD180_IER, rc->rc_ier); 1054 (void) splx(s); 1055 return 0; 1056} 1057 1058/* Re-initialize board after bogus interrupts */ 1059static void rc_reinit(rcb) 1060struct rc_softc *rcb; 1061{ 1062 register struct rc_chans *rc, *rce; 1063 register int nec; 1064 1065 nec = rcb->rcb_addr; 1066 rc_hwreset(rcb->rcb_unit, nec, RC_FAKEID); 1067 rc = &rc_chans[rcb->rcb_unit * CD180_NCHAN]; 1068 rce = rc + CD180_NCHAN; 1069 for (; rc < rce; rc++) 1070 (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios); 1071} 1072 1073static int 1074rcioctl(dev, cmd, data, flag, td) 1075dev_t dev; 1076u_long cmd; 1077int flag; 1078caddr_t data; 1079struct thread *td; 1080{ 1081 register struct rc_chans *rc = &rc_chans[GET_UNIT(dev)]; 1082 register int s, error; 1083 struct tty *tp = rc->rc_tp; 1084 1085 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); 1086 if (error != ENOIOCTL) 1087 return (error); 1088 error = ttioctl(tp, cmd, data, flag); 1089 disc_optim(tp, &tp->t_termios, rc); 1090 if (error != ENOIOCTL) 1091 return (error); 1092 s = spltty(); 1093 1094 switch (cmd) { 1095 case TIOCSBRK: 1096 rc->rc_pendcmd = CD180_C_SBRK; 1097 break; 1098 1099 case TIOCCBRK: 1100 rc->rc_pendcmd = CD180_C_EBRK; 1101 break; 1102 1103 case TIOCSDTR: 1104 (void) rc_modctl(rc, TIOCM_DTR, DMBIS); 1105 break; 1106 1107 case TIOCCDTR: 1108 (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 1109 break; 1110 1111 case TIOCMGET: 1112 *(int *) data = rc_modctl(rc, 0, DMGET); 1113 break; 1114 1115 case TIOCMSET: 1116 (void) rc_modctl(rc, *(int *) data, DMSET); 1117 break; 1118 1119 case TIOCMBIC: 1120 (void) rc_modctl(rc, *(int *) data, DMBIC); 1121 break; 1122 1123 case TIOCMBIS: 1124 (void) rc_modctl(rc, *(int *) data, DMBIS); 1125 break; 1126 1127 case TIOCMSDTRWAIT: 1128 error = suser(td); 1129 if (error != 0) { 1130 splx(s); 1131 return (error); 1132 } 1133 rc->rc_dtrwait = *(int *)data * hz / 100; 1134 break; 1135 1136 case TIOCMGDTRWAIT: 1137 *(int *)data = rc->rc_dtrwait * 100 / hz; 1138 break; 1139 1140 default: 1141 (void) splx(s); 1142 return ENOTTY; 1143 } 1144 (void) splx(s); 1145 return 0; 1146} 1147 1148 1149/* Modem control routines */ 1150 1151static int rc_modctl(rc, bits, cmd) 1152register struct rc_chans *rc; 1153int bits, cmd; 1154{ 1155 register int nec = rc->rc_rcb->rcb_addr; 1156 u_char *dtr = &rc->rc_rcb->rcb_dtr, msvr; 1157 1158 rcout(CD180_CAR, rc->rc_chan); 1159 1160 switch (cmd) { 1161 case DMSET: 1162 rcout(RC_DTREG, (bits & TIOCM_DTR) ? 1163 ~(*dtr |= 1 << rc->rc_chan) : 1164 ~(*dtr &= ~(1 << rc->rc_chan))); 1165 msvr = rcin(CD180_MSVR); 1166 if (bits & TIOCM_RTS) 1167 msvr |= MSVR_RTS; 1168 else 1169 msvr &= ~MSVR_RTS; 1170 if (bits & TIOCM_DTR) 1171 msvr |= MSVR_DTR; 1172 else 1173 msvr &= ~MSVR_DTR; 1174 rcout(CD180_MSVR, msvr); 1175 break; 1176 1177 case DMBIS: 1178 if (bits & TIOCM_DTR) 1179 rcout(RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); 1180 msvr = rcin(CD180_MSVR); 1181 if (bits & TIOCM_RTS) 1182 msvr |= MSVR_RTS; 1183 if (bits & TIOCM_DTR) 1184 msvr |= MSVR_DTR; 1185 rcout(CD180_MSVR, msvr); 1186 break; 1187 1188 case DMGET: 1189 bits = TIOCM_LE; 1190 msvr = rc->rc_msvr = rcin(CD180_MSVR); 1191 1192 if (msvr & MSVR_RTS) 1193 bits |= TIOCM_RTS; 1194 if (msvr & MSVR_CTS) 1195 bits |= TIOCM_CTS; 1196 if (msvr & MSVR_DSR) 1197 bits |= TIOCM_DSR; 1198 if (msvr & MSVR_DTR) 1199 bits |= TIOCM_DTR; 1200 if (msvr & MSVR_CD) 1201 bits |= TIOCM_CD; 1202 if (~rcin(RC_RIREG) & (1 << rc->rc_chan)) 1203 bits |= TIOCM_RI; 1204 return bits; 1205 1206 case DMBIC: 1207 if (bits & TIOCM_DTR) 1208 rcout(RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); 1209 msvr = rcin(CD180_MSVR); 1210 if (bits & TIOCM_RTS) 1211 msvr &= ~MSVR_RTS; 1212 if (bits & TIOCM_DTR) 1213 msvr &= ~MSVR_DTR; 1214 rcout(CD180_MSVR, msvr); 1215 break; 1216 } 1217 rc->rc_msvr = rcin(CD180_MSVR); 1218 return 0; 1219} 1220 1221/* Test the board. */ 1222static int 1223rc_test(nec, unit) 1224 register int nec; 1225 int unit; 1226{ 1227 int chan = 0; 1228 int i = 0, rcnt, old_level; 1229 unsigned int iack, chipid; 1230 unsigned short divs; 1231 static u_char ctest[] = "\377\125\252\045\244\0\377"; 1232#define CTLEN 8 1233#define ERR(s) { \ 1234 printf("rc%d: ", unit); printf s ; printf("\n"); \ 1235 (void) splx(old_level); return 1; } 1236 1237 struct rtest { 1238 u_char txbuf[CD180_NFIFO]; /* TX buffer */ 1239 u_char rxbuf[CD180_NFIFO]; /* RX buffer */ 1240 int rxptr; /* RX pointer */ 1241 int txptr; /* TX pointer */ 1242 } tchans[CD180_NCHAN]; 1243 1244 old_level = spltty(); 1245 1246 chipid = RC_FAKEID; 1247 1248 /* First, reset board to inital state */ 1249 rc_hwreset(unit, nec, chipid); 1250 1251 divs = RC_BRD(19200); 1252 1253 /* Initialize channels */ 1254 for (chan = 0; chan < CD180_NCHAN; chan++) { 1255 1256 /* Select and reset channel */ 1257 rcout(CD180_CAR, chan); 1258 CCRCMD(unit, chan, CCR_ResetChan); 1259 WAITFORCCR(unit, chan); 1260 1261 /* Set speed */ 1262 rcout(CD180_RBPRL, divs & 0xFF); 1263 rcout(CD180_RBPRH, divs >> 8); 1264 rcout(CD180_TBPRL, divs & 0xFF); 1265 rcout(CD180_TBPRH, divs >> 8); 1266 1267 /* set timeout value */ 1268 rcout(CD180_RTPR, 0); 1269 1270 /* Establish local loopback */ 1271 rcout(CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); 1272 rcout(CD180_COR2, COR2_LLM); 1273 rcout(CD180_COR3, CD180_NFIFO); 1274 CCRCMD(unit, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1275 CCRCMD(unit, chan, CCR_RCVREN | CCR_XMTREN); 1276 WAITFORCCR(unit, chan); 1277 rcout(CD180_MSVR, MSVR_RTS); 1278 1279 /* Fill TXBUF with test data */ 1280 for (i = 0; i < CD180_NFIFO; i++) { 1281 tchans[chan].txbuf[i] = ctest[i]; 1282 tchans[chan].rxbuf[i] = 0; 1283 } 1284 tchans[chan].txptr = tchans[chan].rxptr = 0; 1285 1286 /* Now, start transmit */ 1287 rcout(CD180_IER, IER_TxMpty|IER_RxData); 1288 } 1289 /* Pseudo-interrupt poll stuff */ 1290 for (rcnt = 10000; rcnt-- > 0; rcnt--) { 1291 i = ~(rcin(RC_BSR)); 1292 if (i & RC_BSR_TOUT) 1293 ERR(("BSR timeout bit set\n")) 1294 else if (i & RC_BSR_TXINT) { 1295 iack = rcin(RC_PILR_TX); 1296 if (iack != (GIVR_IT_TDI | chipid)) 1297 ERR(("Bad TX intr ack (%02x != %02x)\n", 1298 iack, GIVR_IT_TDI | chipid)); 1299 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1300 /* If no more data to transmit, disable TX intr */ 1301 if (tchans[chan].txptr >= CD180_NFIFO) { 1302 iack = rcin(CD180_IER); 1303 rcout(CD180_IER, iack & ~IER_TxMpty); 1304 } else { 1305 for (iack = tchans[chan].txptr; 1306 iack < CD180_NFIFO; iack++) 1307 rcout(CD180_TDR, 1308 tchans[chan].txbuf[iack]); 1309 tchans[chan].txptr = iack; 1310 } 1311 rcout(CD180_EOIR, 0); 1312 } else if (i & RC_BSR_RXINT) { 1313 u_char ucnt; 1314 1315 iack = rcin(RC_PILR_RX); 1316 if (iack != (GIVR_IT_RGDI | chipid) && 1317 iack != (GIVR_IT_REI | chipid)) 1318 ERR(("Bad RX intr ack (%02x != %02x)\n", 1319 iack, GIVR_IT_RGDI | chipid)) 1320 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1321 ucnt = rcin(CD180_RDCR) & 0xF; 1322 while (ucnt-- > 0) { 1323 iack = rcin(CD180_RCSR); 1324 if (iack & RCSR_Timeout) 1325 break; 1326 if (iack & 0xF) 1327 ERR(("Bad char chan %d (RCSR = %02X)\n", 1328 chan, iack)) 1329 if (tchans[chan].rxptr > CD180_NFIFO) 1330 ERR(("Got extra chars chan %d\n", 1331 chan)) 1332 tchans[chan].rxbuf[tchans[chan].rxptr++] = 1333 rcin(CD180_RDR); 1334 } 1335 rcout(CD180_EOIR, 0); 1336 } 1337 rcout(RC_CTOUT, 0); 1338 for (iack = chan = 0; chan < CD180_NCHAN; chan++) 1339 if (tchans[chan].rxptr >= CD180_NFIFO) 1340 iack++; 1341 if (iack == CD180_NCHAN) 1342 break; 1343 } 1344 for (chan = 0; chan < CD180_NCHAN; chan++) { 1345 /* Select and reset channel */ 1346 rcout(CD180_CAR, chan); 1347 CCRCMD(unit, chan, CCR_ResetChan); 1348 } 1349 1350 if (!rcnt) 1351 ERR(("looses characters during local loopback\n")) 1352 /* Now, check data */ 1353 for (chan = 0; chan < CD180_NCHAN; chan++) 1354 for (i = 0; i < CD180_NFIFO; i++) 1355 if (ctest[i] != tchans[chan].rxbuf[i]) 1356 ERR(("data mismatch chan %d ptr %d (%d != %d)\n", 1357 chan, i, ctest[i], tchans[chan].rxbuf[i])) 1358 (void) splx(old_level); 1359 return 0; 1360} 1361 1362#ifdef RCDEBUG 1363static void printrcflags(rc, comment) 1364struct rc_chans *rc; 1365char *comment; 1366{ 1367 u_short f = rc->rc_flags; 1368 register int nec = rc->rc_rcb->rcb_addr; 1369 1370 printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", 1371 rc->rc_rcb->rcb_unit, rc->rc_chan, comment, 1372 (f & RC_DTR_OFF)?"DTR_OFF " :"", 1373 (f & RC_ACTOUT) ?"ACTOUT " :"", 1374 (f & RC_RTSFLOW)?"RTSFLOW " :"", 1375 (f & RC_CTSFLOW)?"CTSFLOW " :"", 1376 (f & RC_DORXFER)?"DORXFER " :"", 1377 (f & RC_DOXXFER)?"DOXXFER " :"", 1378 (f & RC_MODCHG) ?"MODCHG " :"", 1379 (f & RC_OSUSP) ?"OSUSP " :"", 1380 (f & RC_OSBUSY) ?"OSBUSY " :"", 1381 (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", 1382 (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", 1383 (f & RC_SEND_RDY) ?"SEND_RDY":""); 1384 1385 rcout(CD180_CAR, rc->rc_chan); 1386 1387 printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", 1388 rc->rc_rcb->rcb_unit, rc->rc_chan, 1389 rcin(CD180_MSVR), 1390 rcin(CD180_IER), 1391 rcin(CD180_CCSR)); 1392} 1393#endif /* RCDEBUG */ 1394 1395static void 1396rc_dtrwakeup(chan) 1397 void *chan; 1398{ 1399 struct rc_chans *rc; 1400 1401 rc = (struct rc_chans *)chan; 1402 rc->rc_flags &= ~RC_DTR_OFF; 1403 wakeup(&rc->rc_dtrwait); 1404} 1405 1406static void 1407rc_discard_output(rc) 1408 struct rc_chans *rc; 1409{ 1410 disable_intr(); 1411 if (rc->rc_flags & RC_DOXXFER) { 1412 rc_scheduled_event -= LOTS_OF_EVENTS; 1413 rc->rc_flags &= ~RC_DOXXFER; 1414 } 1415 rc->rc_optr = rc->rc_obufend; 1416 rc->rc_tp->t_state &= ~TS_BUSY; 1417 enable_intr(); 1418 ttwwakeup(rc->rc_tp); 1419} 1420 1421static void 1422rc_wakeup(chan) 1423 void *chan; 1424{ 1425 timeout(rc_wakeup, (caddr_t)NULL, 1); 1426 1427 if (rc_scheduled_event != 0) { 1428 int s; 1429 1430 s = splsofttty(); 1431 rcpoll(NULL); 1432 splx(s); 1433 } 1434} 1435 1436static void 1437disc_optim(tp, t, rc) 1438 struct tty *tp; 1439 struct termios *t; 1440 struct rc_chans *rc; 1441{ 1442 1443 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 1444 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 1445 && (!(t->c_iflag & PARMRK) 1446 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 1447 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 1448 && linesw[tp->t_line].l_rint == ttyinput) 1449 tp->t_state |= TS_CAN_BYPASS_L_RINT; 1450 else 1451 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 1452 rc->rc_hotchar = linesw[tp->t_line].l_hotchar; 1453} 1454 1455static void 1456rc_wait0(nec, unit, chan, line) 1457 int nec, unit, chan, line; 1458{ 1459 int rcnt; 1460 1461 for (rcnt = 50; rcnt && rcin(CD180_CCR); rcnt--) 1462 DELAY(30); 1463 if (rcnt == 0) 1464 printf("rc%d/%d: channel command timeout, rc.c line: %d\n", 1465 unit, chan, line); 1466} 1467