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