rc.c revision 96970
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 96970 2002-05-20 05:12:56Z rwatson $ 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. */ 565void rcpoll(void *arg) 566{ 567 register struct rc_chans *rc; 568 register struct rc_softc *rcb; 569 register u_char *tptr, *eptr; 570 register struct tty *tp; 571 register int chan, icnt, nec, unit; 572 573 if (rc_scheduled_event == 0) 574 return; 575repeat: 576 for (unit = 0; unit < NRC; unit++) { 577 rcb = &rc_softc[unit]; 578 rc = rcb->rcb_baserc; 579 nec = rc->rc_rcb->rcb_addr; 580 for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { 581 tp = rc->rc_tp; 582#ifdef RCDEBUG 583 if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| 584 RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) 585 printrcflags(rc, "rcevent"); 586#endif 587 if (rc->rc_flags & RC_WAS_BUFOVFL) { 588 disable_intr(); 589 rc->rc_flags &= ~RC_WAS_BUFOVFL; 590 rc_scheduled_event--; 591 enable_intr(); 592 printf("rc%d/%d: interrupt-level buffer overflow\n", 593 unit, chan); 594 } 595 if (rc->rc_flags & RC_WAS_SILOVFL) { 596 disable_intr(); 597 rc->rc_flags &= ~RC_WAS_SILOVFL; 598 rc_scheduled_event--; 599 enable_intr(); 600 printf("rc%d/%d: silo overflow\n", 601 unit, chan); 602 } 603 if (rc->rc_flags & RC_MODCHG) { 604 disable_intr(); 605 rc->rc_flags &= ~RC_MODCHG; 606 rc_scheduled_event -= LOTS_OF_EVENTS; 607 enable_intr(); 608 (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD)); 609 } 610 if (rc->rc_flags & RC_DORXFER) { 611 disable_intr(); 612 rc->rc_flags &= ~RC_DORXFER; 613 eptr = rc->rc_iptr; 614 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) 615 tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 616 else 617 tptr = rc->rc_ibuf; 618 icnt = eptr - tptr; 619 if (icnt > 0) { 620 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 621 rc->rc_iptr = rc->rc_ibuf; 622 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 623 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 624 } else { 625 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 626 rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; 627 rc->rc_hiwat = 628 &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; 629 } 630 if ( (rc->rc_flags & RC_RTSFLOW) 631 && (tp->t_state & TS_ISOPEN) 632 && !(tp->t_state & TS_TBLOCK) 633 && !(rc->rc_msvr & MSVR_RTS) 634 ) { 635 rcout(CD180_CAR, chan); 636 rcout(CD180_MSVR, 637 rc->rc_msvr |= MSVR_RTS); 638 } 639 rc_scheduled_event -= icnt; 640 } 641 enable_intr(); 642 643 if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) 644 goto done1; 645 646 if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) 647 && !(tp->t_state & TS_LOCAL)) { 648 if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER 649 && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) 650 && !(tp->t_state & TS_TBLOCK)) 651 ttyblock(tp); 652 tk_nin += icnt; 653 tk_rawcc += icnt; 654 tp->t_rawcc += icnt; 655 if (b_to_q(tptr, icnt, &tp->t_rawq)) 656 printf("rc%d/%d: tty-level buffer overflow\n", 657 unit, chan); 658 ttwakeup(tp); 659 if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) 660 || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { 661 tp->t_state &= ~TS_TTSTOP; 662 tp->t_lflag &= ~FLUSHO; 663 rc_start(tp); 664 } 665 } else { 666 for (; tptr < eptr; tptr++) 667 (*linesw[tp->t_line].l_rint) 668 (tptr[0] | 669 rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp); 670 } 671done1: ; 672 } 673 if (rc->rc_flags & RC_DOXXFER) { 674 disable_intr(); 675 rc_scheduled_event -= LOTS_OF_EVENTS; 676 rc->rc_flags &= ~RC_DOXXFER; 677 rc->rc_tp->t_state &= ~TS_BUSY; 678 enable_intr(); 679 (*linesw[tp->t_line].l_start)(tp); 680 } 681 } 682 if (rc_scheduled_event == 0) 683 break; 684 } 685 if (rc_scheduled_event >= LOTS_OF_EVENTS) 686 goto repeat; 687} 688 689static void 690rc_stop(tp, rw) 691 register struct tty *tp; 692 int rw; 693{ 694 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; 695 u_char *tptr, *eptr; 696 697#ifdef RCDEBUG 698 printf("rc%d/%d: rc_stop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan, 699 (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); 700#endif 701 if (rw & FWRITE) 702 rc_discard_output(rc); 703 disable_intr(); 704 if (rw & FREAD) { 705 rc->rc_flags &= ~RC_DORXFER; 706 eptr = rc->rc_iptr; 707 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 708 tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 709 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 710 } else { 711 tptr = rc->rc_ibuf; 712 rc->rc_iptr = rc->rc_ibuf; 713 } 714 rc_scheduled_event -= eptr - tptr; 715 } 716 if (tp->t_state & TS_TTSTOP) 717 rc->rc_flags |= RC_OSUSP; 718 else 719 rc->rc_flags &= ~RC_OSUSP; 720 enable_intr(); 721} 722 723static int 724rcopen(dev, flag, mode, td) 725 dev_t dev; 726 int flag, mode; 727 struct thread *td; 728{ 729 register struct rc_chans *rc; 730 register struct tty *tp; 731 int unit, nec, s, error = 0; 732 733 unit = GET_UNIT(dev); 734 if (unit >= NRC * CD180_NCHAN) 735 return ENXIO; 736 if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED) 737 return ENXIO; 738 rc = &rc_chans[unit]; 739 tp = rc->rc_tp; 740 dev->si_tty = tp; 741 nec = rc->rc_rcb->rcb_addr; 742#ifdef RCDEBUG 743 printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev); 744#endif 745 s = spltty(); 746 747again: 748 while (rc->rc_flags & RC_DTR_OFF) { 749 error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0); 750 if (error != 0) 751 goto out; 752 } 753 if (tp->t_state & TS_ISOPEN) { 754 if (CALLOUT(dev)) { 755 if (!(rc->rc_flags & RC_ACTOUT)) { 756 error = EBUSY; 757 goto out; 758 } 759 } else { 760 if (rc->rc_flags & RC_ACTOUT) { 761 if (flag & O_NONBLOCK) { 762 error = EBUSY; 763 goto out; 764 } 765 error = tsleep(&rc->rc_rcb, 766 TTIPRI|PCATCH, "rcbi", 0); 767 if (error) 768 goto out; 769 goto again; 770 } 771 } 772 if (tp->t_state & TS_XCLUDE && 773 suser(td)) { 774 error = EBUSY; 775 goto out; 776 } 777 } else { 778 tp->t_oproc = rc_start; 779 tp->t_param = rc_param; 780 tp->t_stop = rc_stop; 781 tp->t_dev = dev; 782 783 if (CALLOUT(dev)) 784 tp->t_cflag |= CLOCAL; 785 else 786 tp->t_cflag &= ~CLOCAL; 787 788 error = rc_param(tp, &tp->t_termios); 789 if (error) 790 goto out; 791 (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET); 792 793 if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev)) 794 (*linesw[tp->t_line].l_modem)(tp, 1); 795 } 796 if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev) 797 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 798 rc->rc_dcdwaits++; 799 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0); 800 rc->rc_dcdwaits--; 801 if (error != 0) 802 goto out; 803 goto again; 804 } 805 error = (*linesw[tp->t_line].l_open)(dev, tp); 806 disc_optim(tp, &tp->t_termios, rc); 807 if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev)) 808 rc->rc_flags |= RC_ACTOUT; 809out: 810 (void) splx(s); 811 812 if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN)) 813 rc_hardclose(rc); 814 815 return error; 816} 817 818static int 819rcclose(dev, flag, mode, td) 820 dev_t dev; 821 int flag, mode; 822 struct thread *td; 823{ 824 register struct rc_chans *rc; 825 register struct tty *tp; 826 int s, unit = GET_UNIT(dev); 827 828 if (unit >= NRC * CD180_NCHAN) 829 return ENXIO; 830 rc = &rc_chans[unit]; 831 tp = rc->rc_tp; 832#ifdef RCDEBUG 833 printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev); 834#endif 835 s = spltty(); 836 (*linesw[tp->t_line].l_close)(tp, flag); 837 disc_optim(tp, &tp->t_termios, rc); 838 rc_stop(tp, FREAD | FWRITE); 839 rc_hardclose(rc); 840 ttyclose(tp); 841 splx(s); 842 return 0; 843} 844 845static void rc_hardclose(rc) 846register struct rc_chans *rc; 847{ 848 register int s, nec = rc->rc_rcb->rcb_addr; 849 register struct tty *tp = rc->rc_tp; 850 851 s = spltty(); 852 rcout(CD180_CAR, rc->rc_chan); 853 854 /* Disable rx/tx intrs */ 855 rcout(CD180_IER, rc->rc_ier = 0); 856 if ( (tp->t_cflag & HUPCL) 857 || (!(rc->rc_flags & RC_ACTOUT) 858 && !(rc->rc_msvr & MSVR_CD) 859 && !(tp->t_cflag & CLOCAL)) 860 || !(tp->t_state & TS_ISOPEN) 861 ) { 862 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan); 863 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); 864 (void) rc_modctl(rc, TIOCM_RTS, DMSET); 865 if (rc->rc_dtrwait) { 866 timeout(rc_dtrwakeup, rc, rc->rc_dtrwait); 867 rc->rc_flags |= RC_DTR_OFF; 868 } 869 } 870 rc->rc_flags &= ~RC_ACTOUT; 871 wakeup((caddr_t) &rc->rc_rcb); /* wake bi */ 872 wakeup(TSA_CARR_ON(tp)); 873 (void) splx(s); 874} 875 876/* Reset the bastard */ 877static void rc_hwreset(unit, nec, chipid) 878 register int unit, nec; 879 unsigned int chipid; 880{ 881 CCRCMD(unit, -1, CCR_HWRESET); /* Hardware reset */ 882 DELAY(20000); 883 WAITFORCCR(unit, -1); 884 885 rcout(RC_CTOUT, 0); /* Clear timeout */ 886 rcout(CD180_GIVR, chipid); 887 rcout(CD180_GICR, 0); 888 889 /* Set Prescaler Registers (1 msec) */ 890 rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); 891 rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); 892 893 /* Initialize Priority Interrupt Level Registers */ 894 rcout(CD180_PILR1, RC_PILR_MODEM); 895 rcout(CD180_PILR2, RC_PILR_TX); 896 rcout(CD180_PILR3, RC_PILR_RX); 897 898 /* Reset DTR */ 899 rcout(RC_DTREG, ~0); 900} 901 902/* Set channel parameters */ 903static int rc_param(tp, ts) 904 register struct tty *tp; 905 struct termios *ts; 906{ 907 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)]; 908 register int nec = rc->rc_rcb->rcb_addr; 909 int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; 910 911 if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 912 || ts->c_ispeed < 0 || ts->c_ispeed > 76800 913 ) 914 return (EINVAL); 915 if (ts->c_ispeed == 0) 916 ts->c_ispeed = ts->c_ospeed; 917 odivs = RC_BRD(ts->c_ospeed); 918 idivs = RC_BRD(ts->c_ispeed); 919 920 s = spltty(); 921 922 /* Select channel */ 923 rcout(CD180_CAR, rc->rc_chan); 924 925 /* If speed == 0, hangup line */ 926 if (ts->c_ospeed == 0) { 927 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan); 928 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); 929 (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 930 } 931 932 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 933 cflag = ts->c_cflag; 934 iflag = ts->c_iflag; 935 lflag = ts->c_lflag; 936 937 if (idivs > 0) { 938 rcout(CD180_RBPRL, idivs & 0xFF); 939 rcout(CD180_RBPRH, idivs >> 8); 940 } 941 if (odivs > 0) { 942 rcout(CD180_TBPRL, odivs & 0xFF); 943 rcout(CD180_TBPRH, odivs >> 8); 944 } 945 946 /* set timeout value */ 947 if (ts->c_ispeed > 0) { 948 int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; 949 950 if ( !(lflag & ICANON) 951 && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 952 && ts->c_cc[VTIME] * 10 > itm) 953 itm = ts->c_cc[VTIME] * 10; 954 955 rcout(CD180_RTPR, itm <= 255 ? itm : 255); 956 } 957 958 switch (cflag & CSIZE) { 959 case CS5: val = COR1_5BITS; break; 960 case CS6: val = COR1_6BITS; break; 961 case CS7: val = COR1_7BITS; break; 962 default: 963 case CS8: val = COR1_8BITS; break; 964 } 965 if (cflag & PARENB) { 966 val |= COR1_NORMPAR; 967 if (cflag & PARODD) 968 val |= COR1_ODDP; 969 if (!(cflag & INPCK)) 970 val |= COR1_Ignore; 971 } else 972 val |= COR1_Ignore; 973 if (cflag & CSTOPB) 974 val |= COR1_2SB; 975 rcout(CD180_COR1, val); 976 977 /* Set FIFO threshold */ 978 val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; 979 inpflow = 0; 980 if ( (iflag & IXOFF) 981 && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE 982 && ( ts->c_cc[VSTART] != _POSIX_VDISABLE 983 || (iflag & IXANY) 984 ) 985 ) 986 ) { 987 inpflow = 1; 988 val |= COR3_SCDE|COR3_FCT; 989 } 990 rcout(CD180_COR3, val); 991 992 /* Initialize on-chip automatic flow control */ 993 val = 0; 994 rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); 995 if (cflag & CCTS_OFLOW) { 996 rc->rc_flags |= RC_CTSFLOW; 997 val |= COR2_CtsAE; 998 } else 999 rc->rc_flags |= RC_SEND_RDY; 1000 if (tp->t_state & TS_TTSTOP) 1001 rc->rc_flags |= RC_OSUSP; 1002 else 1003 rc->rc_flags &= ~RC_OSUSP; 1004 if (cflag & CRTS_IFLOW) 1005 rc->rc_flags |= RC_RTSFLOW; 1006 else 1007 rc->rc_flags &= ~RC_RTSFLOW; 1008 1009 if (inpflow) { 1010 if (ts->c_cc[VSTART] != _POSIX_VDISABLE) 1011 rcout(CD180_SCHR1, ts->c_cc[VSTART]); 1012 rcout(CD180_SCHR2, ts->c_cc[VSTOP]); 1013 val |= COR2_TxIBE; 1014 if (iflag & IXANY) 1015 val |= COR2_IXM; 1016 } 1017 1018 rcout(CD180_COR2, rc->rc_cor2 = val); 1019 1020 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, 1021 CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1022 1023 disc_optim(tp, ts, rc); 1024 1025 /* modem ctl */ 1026 val = cflag & CLOCAL ? 0 : MCOR1_CDzd; 1027 if (cflag & CCTS_OFLOW) 1028 val |= MCOR1_CTSzd; 1029 rcout(CD180_MCOR1, val); 1030 1031 val = cflag & CLOCAL ? 0 : MCOR2_CDod; 1032 if (cflag & CCTS_OFLOW) 1033 val |= MCOR2_CTSod; 1034 rcout(CD180_MCOR2, val); 1035 1036 /* enable i/o and interrupts */ 1037 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, 1038 CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); 1039 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan); 1040 1041 rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; 1042 if (cflag & CCTS_OFLOW) 1043 rc->rc_ier |= IER_CTS; 1044 if (cflag & CREAD) 1045 rc->rc_ier |= IER_RxData; 1046 if (tp->t_state & TS_BUSY) 1047 rc->rc_ier |= IER_TxRdy; 1048 if (ts->c_ospeed != 0) 1049 rc_modctl(rc, TIOCM_DTR, DMBIS); 1050 if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) 1051 rc->rc_flags |= RC_SEND_RDY; 1052 rcout(CD180_IER, rc->rc_ier); 1053 (void) splx(s); 1054 return 0; 1055} 1056 1057/* Re-initialize board after bogus interrupts */ 1058static void rc_reinit(rcb) 1059struct rc_softc *rcb; 1060{ 1061 register struct rc_chans *rc, *rce; 1062 register int nec; 1063 1064 nec = rcb->rcb_addr; 1065 rc_hwreset(rcb->rcb_unit, nec, RC_FAKEID); 1066 rc = &rc_chans[rcb->rcb_unit * CD180_NCHAN]; 1067 rce = rc + CD180_NCHAN; 1068 for (; rc < rce; rc++) 1069 (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios); 1070} 1071 1072static int 1073rcioctl(dev, cmd, data, flag, td) 1074dev_t dev; 1075u_long cmd; 1076int flag; 1077caddr_t data; 1078struct thread *td; 1079{ 1080 register struct rc_chans *rc = &rc_chans[GET_UNIT(dev)]; 1081 register int s, error; 1082 struct tty *tp = rc->rc_tp; 1083 1084 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); 1085 if (error != ENOIOCTL) 1086 return (error); 1087 error = ttioctl(tp, cmd, data, flag); 1088 disc_optim(tp, &tp->t_termios, rc); 1089 if (error != ENOIOCTL) 1090 return (error); 1091 s = spltty(); 1092 1093 switch (cmd) { 1094 case TIOCSBRK: 1095 rc->rc_pendcmd = CD180_C_SBRK; 1096 break; 1097 1098 case TIOCCBRK: 1099 rc->rc_pendcmd = CD180_C_EBRK; 1100 break; 1101 1102 case TIOCSDTR: 1103 (void) rc_modctl(rc, TIOCM_DTR, DMBIS); 1104 break; 1105 1106 case TIOCCDTR: 1107 (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 1108 break; 1109 1110 case TIOCMGET: 1111 *(int *) data = rc_modctl(rc, 0, DMGET); 1112 break; 1113 1114 case TIOCMSET: 1115 (void) rc_modctl(rc, *(int *) data, DMSET); 1116 break; 1117 1118 case TIOCMBIC: 1119 (void) rc_modctl(rc, *(int *) data, DMBIC); 1120 break; 1121 1122 case TIOCMBIS: 1123 (void) rc_modctl(rc, *(int *) data, DMBIS); 1124 break; 1125 1126 case TIOCMSDTRWAIT: 1127 error = suser(td); 1128 if (error != 0) { 1129 splx(s); 1130 return (error); 1131 } 1132 rc->rc_dtrwait = *(int *)data * hz / 100; 1133 break; 1134 1135 case TIOCMGDTRWAIT: 1136 *(int *)data = rc->rc_dtrwait * 100 / hz; 1137 break; 1138 1139 default: 1140 (void) splx(s); 1141 return ENOTTY; 1142 } 1143 (void) splx(s); 1144 return 0; 1145} 1146 1147 1148/* Modem control routines */ 1149 1150static int rc_modctl(rc, bits, cmd) 1151register struct rc_chans *rc; 1152int bits, cmd; 1153{ 1154 register int nec = rc->rc_rcb->rcb_addr; 1155 u_char *dtr = &rc->rc_rcb->rcb_dtr, msvr; 1156 1157 rcout(CD180_CAR, rc->rc_chan); 1158 1159 switch (cmd) { 1160 case DMSET: 1161 rcout(RC_DTREG, (bits & TIOCM_DTR) ? 1162 ~(*dtr |= 1 << rc->rc_chan) : 1163 ~(*dtr &= ~(1 << rc->rc_chan))); 1164 msvr = rcin(CD180_MSVR); 1165 if (bits & TIOCM_RTS) 1166 msvr |= MSVR_RTS; 1167 else 1168 msvr &= ~MSVR_RTS; 1169 if (bits & TIOCM_DTR) 1170 msvr |= MSVR_DTR; 1171 else 1172 msvr &= ~MSVR_DTR; 1173 rcout(CD180_MSVR, msvr); 1174 break; 1175 1176 case DMBIS: 1177 if (bits & TIOCM_DTR) 1178 rcout(RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); 1179 msvr = rcin(CD180_MSVR); 1180 if (bits & TIOCM_RTS) 1181 msvr |= MSVR_RTS; 1182 if (bits & TIOCM_DTR) 1183 msvr |= MSVR_DTR; 1184 rcout(CD180_MSVR, msvr); 1185 break; 1186 1187 case DMGET: 1188 bits = TIOCM_LE; 1189 msvr = rc->rc_msvr = rcin(CD180_MSVR); 1190 1191 if (msvr & MSVR_RTS) 1192 bits |= TIOCM_RTS; 1193 if (msvr & MSVR_CTS) 1194 bits |= TIOCM_CTS; 1195 if (msvr & MSVR_DSR) 1196 bits |= TIOCM_DSR; 1197 if (msvr & MSVR_DTR) 1198 bits |= TIOCM_DTR; 1199 if (msvr & MSVR_CD) 1200 bits |= TIOCM_CD; 1201 if (~rcin(RC_RIREG) & (1 << rc->rc_chan)) 1202 bits |= TIOCM_RI; 1203 return bits; 1204 1205 case DMBIC: 1206 if (bits & TIOCM_DTR) 1207 rcout(RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); 1208 msvr = rcin(CD180_MSVR); 1209 if (bits & TIOCM_RTS) 1210 msvr &= ~MSVR_RTS; 1211 if (bits & TIOCM_DTR) 1212 msvr &= ~MSVR_DTR; 1213 rcout(CD180_MSVR, msvr); 1214 break; 1215 } 1216 rc->rc_msvr = rcin(CD180_MSVR); 1217 return 0; 1218} 1219 1220/* Test the board. */ 1221int rc_test(nec, unit) 1222 register int nec; 1223 int unit; 1224{ 1225 int chan = 0; 1226 int i = 0, rcnt, old_level; 1227 unsigned int iack, chipid; 1228 unsigned short divs; 1229 static u_char ctest[] = "\377\125\252\045\244\0\377"; 1230#define CTLEN 8 1231#define ERR(s) { \ 1232 printf("rc%d: ", unit); printf s ; printf("\n"); \ 1233 (void) splx(old_level); return 1; } 1234 1235 struct rtest { 1236 u_char txbuf[CD180_NFIFO]; /* TX buffer */ 1237 u_char rxbuf[CD180_NFIFO]; /* RX buffer */ 1238 int rxptr; /* RX pointer */ 1239 int txptr; /* TX pointer */ 1240 } tchans[CD180_NCHAN]; 1241 1242 old_level = spltty(); 1243 1244 chipid = RC_FAKEID; 1245 1246 /* First, reset board to inital state */ 1247 rc_hwreset(unit, nec, chipid); 1248 1249 divs = RC_BRD(19200); 1250 1251 /* Initialize channels */ 1252 for (chan = 0; chan < CD180_NCHAN; chan++) { 1253 1254 /* Select and reset channel */ 1255 rcout(CD180_CAR, chan); 1256 CCRCMD(unit, chan, CCR_ResetChan); 1257 WAITFORCCR(unit, chan); 1258 1259 /* Set speed */ 1260 rcout(CD180_RBPRL, divs & 0xFF); 1261 rcout(CD180_RBPRH, divs >> 8); 1262 rcout(CD180_TBPRL, divs & 0xFF); 1263 rcout(CD180_TBPRH, divs >> 8); 1264 1265 /* set timeout value */ 1266 rcout(CD180_RTPR, 0); 1267 1268 /* Establish local loopback */ 1269 rcout(CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); 1270 rcout(CD180_COR2, COR2_LLM); 1271 rcout(CD180_COR3, CD180_NFIFO); 1272 CCRCMD(unit, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1273 CCRCMD(unit, chan, CCR_RCVREN | CCR_XMTREN); 1274 WAITFORCCR(unit, chan); 1275 rcout(CD180_MSVR, MSVR_RTS); 1276 1277 /* Fill TXBUF with test data */ 1278 for (i = 0; i < CD180_NFIFO; i++) { 1279 tchans[chan].txbuf[i] = ctest[i]; 1280 tchans[chan].rxbuf[i] = 0; 1281 } 1282 tchans[chan].txptr = tchans[chan].rxptr = 0; 1283 1284 /* Now, start transmit */ 1285 rcout(CD180_IER, IER_TxMpty|IER_RxData); 1286 } 1287 /* Pseudo-interrupt poll stuff */ 1288 for (rcnt = 10000; rcnt-- > 0; rcnt--) { 1289 i = ~(rcin(RC_BSR)); 1290 if (i & RC_BSR_TOUT) 1291 ERR(("BSR timeout bit set\n")) 1292 else if (i & RC_BSR_TXINT) { 1293 iack = rcin(RC_PILR_TX); 1294 if (iack != (GIVR_IT_TDI | chipid)) 1295 ERR(("Bad TX intr ack (%02x != %02x)\n", 1296 iack, GIVR_IT_TDI | chipid)); 1297 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1298 /* If no more data to transmit, disable TX intr */ 1299 if (tchans[chan].txptr >= CD180_NFIFO) { 1300 iack = rcin(CD180_IER); 1301 rcout(CD180_IER, iack & ~IER_TxMpty); 1302 } else { 1303 for (iack = tchans[chan].txptr; 1304 iack < CD180_NFIFO; iack++) 1305 rcout(CD180_TDR, 1306 tchans[chan].txbuf[iack]); 1307 tchans[chan].txptr = iack; 1308 } 1309 rcout(CD180_EOIR, 0); 1310 } else if (i & RC_BSR_RXINT) { 1311 u_char ucnt; 1312 1313 iack = rcin(RC_PILR_RX); 1314 if (iack != (GIVR_IT_RGDI | chipid) && 1315 iack != (GIVR_IT_REI | chipid)) 1316 ERR(("Bad RX intr ack (%02x != %02x)\n", 1317 iack, GIVR_IT_RGDI | chipid)) 1318 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1319 ucnt = rcin(CD180_RDCR) & 0xF; 1320 while (ucnt-- > 0) { 1321 iack = rcin(CD180_RCSR); 1322 if (iack & RCSR_Timeout) 1323 break; 1324 if (iack & 0xF) 1325 ERR(("Bad char chan %d (RCSR = %02X)\n", 1326 chan, iack)) 1327 if (tchans[chan].rxptr > CD180_NFIFO) 1328 ERR(("Got extra chars chan %d\n", 1329 chan)) 1330 tchans[chan].rxbuf[tchans[chan].rxptr++] = 1331 rcin(CD180_RDR); 1332 } 1333 rcout(CD180_EOIR, 0); 1334 } 1335 rcout(RC_CTOUT, 0); 1336 for (iack = chan = 0; chan < CD180_NCHAN; chan++) 1337 if (tchans[chan].rxptr >= CD180_NFIFO) 1338 iack++; 1339 if (iack == CD180_NCHAN) 1340 break; 1341 } 1342 for (chan = 0; chan < CD180_NCHAN; chan++) { 1343 /* Select and reset channel */ 1344 rcout(CD180_CAR, chan); 1345 CCRCMD(unit, chan, CCR_ResetChan); 1346 } 1347 1348 if (!rcnt) 1349 ERR(("looses characters during local loopback\n")) 1350 /* Now, check data */ 1351 for (chan = 0; chan < CD180_NCHAN; chan++) 1352 for (i = 0; i < CD180_NFIFO; i++) 1353 if (ctest[i] != tchans[chan].rxbuf[i]) 1354 ERR(("data mismatch chan %d ptr %d (%d != %d)\n", 1355 chan, i, ctest[i], tchans[chan].rxbuf[i])) 1356 (void) splx(old_level); 1357 return 0; 1358} 1359 1360#ifdef RCDEBUG 1361static void printrcflags(rc, comment) 1362struct rc_chans *rc; 1363char *comment; 1364{ 1365 u_short f = rc->rc_flags; 1366 register int nec = rc->rc_rcb->rcb_addr; 1367 1368 printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", 1369 rc->rc_rcb->rcb_unit, rc->rc_chan, comment, 1370 (f & RC_DTR_OFF)?"DTR_OFF " :"", 1371 (f & RC_ACTOUT) ?"ACTOUT " :"", 1372 (f & RC_RTSFLOW)?"RTSFLOW " :"", 1373 (f & RC_CTSFLOW)?"CTSFLOW " :"", 1374 (f & RC_DORXFER)?"DORXFER " :"", 1375 (f & RC_DOXXFER)?"DOXXFER " :"", 1376 (f & RC_MODCHG) ?"MODCHG " :"", 1377 (f & RC_OSUSP) ?"OSUSP " :"", 1378 (f & RC_OSBUSY) ?"OSBUSY " :"", 1379 (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", 1380 (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", 1381 (f & RC_SEND_RDY) ?"SEND_RDY":""); 1382 1383 rcout(CD180_CAR, rc->rc_chan); 1384 1385 printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", 1386 rc->rc_rcb->rcb_unit, rc->rc_chan, 1387 rcin(CD180_MSVR), 1388 rcin(CD180_IER), 1389 rcin(CD180_CCSR)); 1390} 1391#endif /* RCDEBUG */ 1392 1393static void 1394rc_dtrwakeup(chan) 1395 void *chan; 1396{ 1397 struct rc_chans *rc; 1398 1399 rc = (struct rc_chans *)chan; 1400 rc->rc_flags &= ~RC_DTR_OFF; 1401 wakeup(&rc->rc_dtrwait); 1402} 1403 1404static void 1405rc_discard_output(rc) 1406 struct rc_chans *rc; 1407{ 1408 disable_intr(); 1409 if (rc->rc_flags & RC_DOXXFER) { 1410 rc_scheduled_event -= LOTS_OF_EVENTS; 1411 rc->rc_flags &= ~RC_DOXXFER; 1412 } 1413 rc->rc_optr = rc->rc_obufend; 1414 rc->rc_tp->t_state &= ~TS_BUSY; 1415 enable_intr(); 1416 ttwwakeup(rc->rc_tp); 1417} 1418 1419static void 1420rc_wakeup(chan) 1421 void *chan; 1422{ 1423 timeout(rc_wakeup, (caddr_t)NULL, 1); 1424 1425 if (rc_scheduled_event != 0) { 1426 int s; 1427 1428 s = splsofttty(); 1429 rcpoll(NULL); 1430 splx(s); 1431 } 1432} 1433 1434static void 1435disc_optim(tp, t, rc) 1436 struct tty *tp; 1437 struct termios *t; 1438 struct rc_chans *rc; 1439{ 1440 1441 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 1442 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 1443 && (!(t->c_iflag & PARMRK) 1444 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 1445 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 1446 && linesw[tp->t_line].l_rint == ttyinput) 1447 tp->t_state |= TS_CAN_BYPASS_L_RINT; 1448 else 1449 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 1450 rc->rc_hotchar = linesw[tp->t_line].l_hotchar; 1451} 1452 1453static void 1454rc_wait0(nec, unit, chan, line) 1455 int nec, unit, chan, line; 1456{ 1457 int rcnt; 1458 1459 for (rcnt = 50; rcnt && rcin(CD180_CCR); rcnt--) 1460 DELAY(30); 1461 if (rcnt == 0) 1462 printf("rc%d/%d: channel command timeout, rc.c line: %d\n", 1463 unit, chan, line); 1464} 1465