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