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