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