1139749Simp/*- 28471Sache * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia. 38471Sache * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia. 4367457Sdim * All rights reserved. 5105806Sjhb * Copyright (C) 2002 by John Baldwin <jhb@FreeBSD.org> 68471Sache * 78471Sache * Redistribution and use in source and binary forms, with or without 88471Sache * modification, are permitted provided that the following conditions 98471Sache * are met: 108471Sache * 1. Redistributions of source code must retain the above copyright 118471Sache * notice, this list of conditions and the following disclaimer. 128471Sache * 2. Redistributions in binary form must reproduce the above copyright 138471Sache * notice, this list of conditions and the following disclaimer in the 148471Sache * documentation and/or other materials provided with the distribution. 158471Sache * 168471Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND 178471Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188471Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198471Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 208471Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218471Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228471Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238471Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248471Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258471Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268471Sache * SUCH DAMAGE. 2751654Sphk * 2851654Sphk * $FreeBSD: stable/11/sys/dev/rc/rc.c 367457 2020-11-07 18:10:59Z dim $ 298471Sache */ 308471Sache 318471Sache/* 328471Sache * SDL Communications Riscom/8 (based on Cirrus Logic CL-CD180) driver 338471Sache * 348471Sache */ 358471Sache 369232Sache/*#define RCDEBUG*/ 378471Sache 38111899Sdas#include "opt_tty.h" 39111899Sdas 408471Sache#include <sys/param.h> 418471Sache#include <sys/systm.h> 42105806Sjhb#include <sys/bus.h> 438471Sache#include <sys/conf.h> 4424131Sbde#include <sys/fcntl.h> 4538246Sbde#include <sys/interrupt.h> 46105806Sjhb#include <sys/kernel.h> 47105806Sjhb#include <sys/malloc.h> 48129879Sphk#include <sys/module.h> 49131096Sphk#include <sys/serial.h> 50105806Sjhb#include <sys/tty.h> 51105806Sjhb#include <machine/bus.h> 52105806Sjhb#include <machine/resource.h> 53105806Sjhb#include <sys/rman.h> 5466824Sbde 55105806Sjhb#include <dev/ic/cd180.h> 56105806Sjhb#include <dev/rc/rcreg.h> 57105806Sjhb#include <isa/isavar.h> 588471Sache 59105806Sjhb#define IOBASE_ADDRS 14 608471Sache 61105806Sjhb#define rcin(sc, port) RC_IN(sc, port) 62105806Sjhb#define rcout(sc, port, v) RC_OUT(sc, port, v) 638471Sache 64105806Sjhb#define WAITFORCCR(sc, chan) rc_wait0((sc), (chan), __LINE__) 658471Sache 66105806Sjhb#define CCRCMD(sc, chan, cmd) do { \ 67105806Sjhb WAITFORCCR((sc), (chan)); \ 68105806Sjhb rcout((sc), CD180_CCR, (cmd)); \ 69105806Sjhb} while (0) 708471Sache 719232Sache#define RC_IBUFSIZE 256 729232Sache#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) 739232Sache#define RC_OBUFSIZE 512 748471Sache#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) 758471Sache#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) 768471Sache#define LOTS_OF_EVENTS 64 778471Sache 788471Sache#define RC_FAKEID 0x10 798471Sache 80105806Sjhb/* Per-channel structure */ 81105806Sjhbstruct rc_chans { 82105806Sjhb struct rc_softc *rc_rcb; /* back ptr */ 83105806Sjhb u_short rc_flags; /* Misc. flags */ 84105806Sjhb int rc_chan; /* Channel # */ 85105806Sjhb u_char rc_ier; /* intr. enable reg */ 86105806Sjhb u_char rc_msvr; /* modem sig. status */ 87105806Sjhb u_char rc_cor2; /* options reg */ 88105806Sjhb u_char rc_pendcmd; /* special cmd pending */ 89105806Sjhb u_int rc_dcdwaits; /* how many waits DCD in open */ 90136210Sphk struct tty *rc_tp; /* tty struct */ 91105806Sjhb u_char *rc_iptr; /* Chars input buffer */ 92105806Sjhb u_char *rc_hiwat; /* hi-water mark */ 93105806Sjhb u_char *rc_bufend; /* end of buffer */ 94105806Sjhb u_char *rc_optr; /* ptr in output buf */ 95105806Sjhb u_char *rc_obufend; /* end of output buf */ 96105806Sjhb u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */ 97105806Sjhb u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */ 98105806Sjhb struct callout rc_dtrcallout; 99105806Sjhb}; 1008471Sache 101105806Sjhb/* Per-board structure */ 102105806Sjhbstruct rc_softc { 103105806Sjhb device_t sc_dev; 104105806Sjhb struct resource *sc_irq; 105105806Sjhb struct resource *sc_port[IOBASE_ADDRS]; 106105806Sjhb int sc_irqrid; 107105806Sjhb void *sc_hwicookie; 108105806Sjhb bus_space_tag_t sc_bt; 109105806Sjhb bus_space_handle_t sc_bh; 110105806Sjhb u_int sc_unit; /* unit # */ 111105806Sjhb u_char sc_dtr; /* DTR status */ 112105806Sjhb int sc_scheduled_event; 113105806Sjhb void *sc_swicookie; 114105806Sjhb struct rc_chans sc_channels[CD180_NCHAN]; /* channels */ 1158471Sache}; 1168471Sache 117105806Sjhb/* Static prototypes */ 118136210Sphkstatic t_close_t rc_close; 119131373Sphkstatic void rc_break(struct tty *, int); 120105806Sjhbstatic void rc_release_resources(device_t dev); 121105806Sjhbstatic void rc_intr(void *); 122105806Sjhbstatic void rc_hwreset(struct rc_softc *, unsigned int); 123105806Sjhbstatic int rc_test(struct rc_softc *); 124105806Sjhbstatic void rc_discard_output(struct rc_chans *); 125131096Sphkstatic int rc_modem(struct tty *, int, int); 126105806Sjhbstatic void rc_start(struct tty *); 127105806Sjhbstatic void rc_stop(struct tty *, int rw); 128105806Sjhbstatic int rc_param(struct tty *, struct termios *); 129105806Sjhbstatic void rc_pollcard(void *); 130105806Sjhbstatic void rc_reinit(struct rc_softc *); 131105806Sjhb#ifdef RCDEBUG 132105806Sjhbstatic void printrcflags(); 133105806Sjhb#endif 134105806Sjhbstatic void rc_wait0(struct rc_softc *sc, int chan, int line); 135105806Sjhb 136105806Sjhbstatic devclass_t rc_devclass; 1378471Sache 1388471Sache/* Flags */ 1399232Sache#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ 1409232Sache#define RC_ACTOUT 0x0002 /* Dial-out port active */ 1419232Sache#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ 1429232Sache#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ 1439232Sache#define RC_DORXFER 0x0010 /* RXFER event planned */ 1449232Sache#define RC_DOXXFER 0x0020 /* XXFER event planned */ 1459232Sache#define RC_MODCHG 0x0040 /* Modem status changed */ 1469232Sache#define RC_OSUSP 0x0080 /* Output suspended */ 1479232Sache#define RC_OSBUSY 0x0100 /* start() routine in progress */ 1489232Sache#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ 1499232Sache#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ 1509232Sache#define RC_SEND_RDY 0x0800 /* ready to send */ 1518471Sache 1528471Sache/* Table for translation of RCSR status bits to internal form */ 1538471Sachestatic int rc_rcsrt[16] = { 1548471Sache 0, TTY_OE, TTY_FE, 1558471Sache TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE, 1568471Sache TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI, 1578471Sache TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE, 1588471Sache TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE, 1598471Sache TTY_BI|TTY_PE|TTY_FE|TTY_OE 1608471Sache}; 1618471Sache 162105806Sjhbstatic int rc_ports[] = 163105806Sjhb { 0x220, 0x240, 0x250, 0x260, 0x2a0, 0x2b0, 0x300, 0x320 }; 164105806Sjhbstatic int iobase_addrs[IOBASE_ADDRS] = 165105806Sjhb { 0, 0x400, 0x800, 0xc00, 0x1400, 0x1800, 0x1c00, 0x2000, 166105806Sjhb 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x8000 }; 16767551Sjhb 1688471Sache/**********************************************/ 1698471Sache 17012724Sphkstatic int 171105806Sjhbrc_probe(device_t dev) 1728471Sache{ 173105806Sjhb u_int port; 174105806Sjhb int i, found; 1758471Sache 176105806Sjhb /* 177105806Sjhb * We don't know of any PnP ID's for these cards. 178105806Sjhb */ 179105806Sjhb if (isa_get_logicalid(dev) != 0) 180105806Sjhb return (ENXIO); 1819232Sache 182105806Sjhb /* 183105806Sjhb * We have to have an IO port hint that is valid. 184105806Sjhb */ 185105806Sjhb port = isa_get_port(dev); 186105806Sjhb if (port == -1) 187105806Sjhb return (ENXIO); 188105806Sjhb found = 0; 189298307Spfg for (i = 0; i < nitems(rc_ports); i++) 190105806Sjhb if (rc_ports[i] == port) { 191105806Sjhb found = 1; 192105806Sjhb break; 193105806Sjhb } 194105806Sjhb if (!found) 195105806Sjhb return (ENXIO); 196105806Sjhb 197105806Sjhb /* 198105806Sjhb * We have to have an IRQ hint. 199105806Sjhb */ 200105806Sjhb if (isa_get_irq(dev) == -1) 201105806Sjhb return (ENXIO); 202105806Sjhb 203105806Sjhb device_set_desc(dev, "SDL Riscom/8"); 204105806Sjhb return (0); 2058471Sache} 2068471Sache 20712724Sphkstatic int 208105806Sjhbrc_attach(device_t dev) 2098471Sache{ 210105806Sjhb struct rc_chans *rc; 211105806Sjhb struct tty *tp; 212105806Sjhb struct rc_softc *sc; 213105806Sjhb u_int port; 214105806Sjhb int base, chan, error, i, x; 2158471Sache 216105806Sjhb sc = device_get_softc(dev); 217105806Sjhb sc->sc_dev = dev; 21840565Sbde 219105806Sjhb /* 220105806Sjhb * We need to have IO ports. Lots of them. We need 221105806Sjhb * the following ranges relative to the base port: 222105806Sjhb * 0x0 - 0x10 223105806Sjhb * 0x400 - 0x410 224105806Sjhb * 0x800 - 0x810 225105806Sjhb * 0xc00 - 0xc10 226105806Sjhb * 0x1400 - 0x1410 227105806Sjhb * 0x1800 - 0x1810 228105806Sjhb * 0x1c00 - 0x1c10 229105806Sjhb * 0x2000 - 0x2010 230105806Sjhb * 0x3000 - 0x3010 231105806Sjhb * 0x3400 - 0x3410 232105806Sjhb * 0x3800 - 0x3810 233105806Sjhb * 0x3c00 - 0x3c10 234105806Sjhb * 0x4000 - 0x4010 235105806Sjhb * 0x8000 - 0x8010 236105806Sjhb */ 237105806Sjhb port = isa_get_port(dev); 238105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) 239105806Sjhb if (bus_set_resource(dev, SYS_RES_IOPORT, i, 240105806Sjhb port + iobase_addrs[i], 0x10) != 0) 241105806Sjhb return (ENXIO); 242105806Sjhb error = ENOMEM; 243105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 244105806Sjhb x = i; 245296137Sjhibbits sc->sc_port[i] = bus_alloc_resource_anywhere(dev, 246296137Sjhibbits SYS_RES_IOPORT, &x, 0x10, RF_ACTIVE); 247105806Sjhb if (x != i) { 248105806Sjhb device_printf(dev, "ioport %d was rid %d\n", i, x); 249105806Sjhb goto fail; 250105806Sjhb } 251105806Sjhb if (sc->sc_port[i] == NULL) { 252105806Sjhb device_printf(dev, "failed to alloc ioports %x-%x\n", 253105806Sjhb port + iobase_addrs[i], 254105806Sjhb port + iobase_addrs[i] + 0x10); 255105806Sjhb goto fail; 256105806Sjhb } 257105806Sjhb } 258105806Sjhb sc->sc_bt = rman_get_bustag(sc->sc_port[0]); 259105806Sjhb sc->sc_bh = rman_get_bushandle(sc->sc_port[0]); 2608471Sache 261127135Snjl sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, 262127135Snjl RF_ACTIVE); 263105806Sjhb if (sc->sc_irq == NULL) { 264105806Sjhb device_printf(dev, "failed to alloc IRQ\n"); 265105806Sjhb goto fail; 266105806Sjhb } 267105806Sjhb 268105806Sjhb /* 269105806Sjhb * Now do some actual tests to make sure it works. 270105806Sjhb */ 271105806Sjhb error = ENXIO; 272105806Sjhb rcout(sc, CD180_PPRL, 0x22); /* Random values to Prescale reg. */ 273105806Sjhb rcout(sc, CD180_PPRH, 0x11); 274105806Sjhb if (rcin(sc, CD180_PPRL) != 0x22 || rcin(sc, CD180_PPRH) != 0x11) 275105806Sjhb goto fail; 276105806Sjhb if (rc_test(sc)) 277105806Sjhb goto fail; 278105806Sjhb 279105806Sjhb /* 280105806Sjhb * Ok, start actually hooking things up. 281105806Sjhb */ 282105806Sjhb sc->sc_unit = device_get_unit(dev); 283105806Sjhb /*sc->sc_chipid = 0x10 + device_get_unit(dev);*/ 284105806Sjhb device_printf(dev, "%d chans, firmware rev. %c\n", 285105806Sjhb CD180_NCHAN, (rcin(sc, CD180_GFRCR) & 0xF) + 'A'); 286105806Sjhb rc = sc->sc_channels; 287105806Sjhb base = CD180_NCHAN * sc->sc_unit; 2888471Sache for (chan = 0; chan < CD180_NCHAN; chan++, rc++) { 289105806Sjhb rc->rc_rcb = sc; 2908471Sache rc->rc_chan = chan; 2918471Sache rc->rc_iptr = rc->rc_ibuf; 2928471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 2938471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 2948471Sache rc->rc_optr = rc->rc_obufend = rc->rc_obuf; 295105806Sjhb callout_init(&rc->rc_dtrcallout, 0); 296136210Sphk tp = rc->rc_tp = ttyalloc(); 297136210Sphk tp->t_sc = rc; 298136210Sphk tp->t_oproc = rc_start; 299136210Sphk tp->t_param = rc_param; 300136210Sphk tp->t_modem = rc_modem; 301136210Sphk tp->t_break = rc_break; 302136210Sphk tp->t_close = rc_close; 303136210Sphk tp->t_stop = rc_stop; 304151383Sphk ttycreate(tp, TS_CALLOUT, "m%d", chan + base); 3058471Sache } 306105806Sjhb 307166901Spiso error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_TTY, NULL, rc_intr, 308166901Spiso sc, &sc->sc_hwicookie); 309105806Sjhb if (error) { 310105806Sjhb device_printf(dev, "failed to register interrupt handler\n"); 311105806Sjhb goto fail; 3128471Sache } 313105806Sjhb 314151700Sjhb swi_add(&tty_intr_event, "rc", rc_pollcard, sc, SWI_TTY, 0, 315105806Sjhb &sc->sc_swicookie); 316105806Sjhb return (0); 317105806Sjhb 318105806Sjhbfail: 319105806Sjhb rc_release_resources(dev); 320105806Sjhb return (error); 3218471Sache} 3228471Sache 323105806Sjhbstatic int 324105806Sjhbrc_detach(device_t dev) 325105806Sjhb{ 326105806Sjhb struct rc_softc *sc; 327105806Sjhb struct rc_chans *rc; 328131981Sphk int error, i; 329105806Sjhb 330105806Sjhb sc = device_get_softc(dev); 331105806Sjhb 332105806Sjhb rc = sc->sc_channels; 333136210Sphk for (i = 0; i < CD180_NCHAN; i++, rc++) 334136210Sphk ttyfree(rc->rc_tp); 335105806Sjhb 336105806Sjhb error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_hwicookie); 337105806Sjhb if (error) 338105806Sjhb device_printf(dev, "failed to deregister interrupt handler\n"); 339151700Sjhb swi_remove(sc->sc_swicookie); 340105806Sjhb rc_release_resources(dev); 341105806Sjhb 342105806Sjhb return (0); 343105806Sjhb} 344105806Sjhb 34540565Sbdestatic void 346105806Sjhbrc_release_resources(device_t dev) 3478471Sache{ 348105806Sjhb struct rc_softc *sc; 349105806Sjhb int i; 3508471Sache 351105806Sjhb sc = device_get_softc(dev); 352105806Sjhb if (sc->sc_irq != NULL) { 353105806Sjhb bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 354105806Sjhb sc->sc_irq); 355105806Sjhb sc->sc_irq = NULL; 3569232Sache } 357105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 358105806Sjhb if (sc->sc_port[i] == NULL) 359105806Sjhb break; 360105806Sjhb bus_release_resource(dev, SYS_RES_IOPORT, i, sc->sc_port[i]); 361105806Sjhb sc->sc_port[i] = NULL; 362105806Sjhb } 363105806Sjhb} 3648471Sache 365105806Sjhb/* RC interrupt handling */ 366105806Sjhbstatic void 367105806Sjhbrc_intr(void *arg) 368105806Sjhb{ 369105806Sjhb struct rc_softc *sc; 370105806Sjhb struct rc_chans *rc; 371105806Sjhb int resid, chan; 372105806Sjhb u_char val, iack, bsr, ucnt, *optr; 373105806Sjhb int good_data, t_state; 3748471Sache 375105806Sjhb sc = (struct rc_softc *)arg; 376105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 3779232Sache if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { 378105806Sjhb device_printf(sc->sc_dev, "extra interrupt\n"); 379105806Sjhb rcout(sc, CD180_EOIR, 0); 3809232Sache return; 3819232Sache } 3829232Sache 3839232Sache while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { 3849232Sache#ifdef RCDEBUG_DETAILED 385105806Sjhb device_printf(sc->sc_dev, "intr (%p) %s%s%s%s\n", arg, bsr, 3869232Sache (bsr & RC_BSR_TOUT)?"TOUT ":"", 3879232Sache (bsr & RC_BSR_RXINT)?"RXINT ":"", 3889232Sache (bsr & RC_BSR_TXINT)?"TXINT ":"", 3899232Sache (bsr & RC_BSR_MOINT)?"MOINT":""); 3908471Sache#endif 3919232Sache if (bsr & RC_BSR_TOUT) { 392105806Sjhb device_printf(sc->sc_dev, 393105806Sjhb "hardware failure, reset board\n"); 394105806Sjhb rcout(sc, RC_CTOUT, 0); 395105806Sjhb rc_reinit(sc); 3969232Sache return; 3978471Sache } 3989232Sache if (bsr & RC_BSR_RXINT) { 399105806Sjhb iack = rcin(sc, RC_PILR_RX); 4009232Sache good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); 4019232Sache if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { 402105806Sjhb device_printf(sc->sc_dev, 403105806Sjhb "fake rxint: %02x\n", iack); 4049232Sache goto more_intrs; 4059232Sache } 406105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 407105806Sjhb rc = &sc->sc_channels[chan]; 408136210Sphk t_state = rc->rc_tp->t_state; 4099232Sache /* Do RTS flow control stuff */ 4109232Sache if ( (rc->rc_flags & RC_RTSFLOW) 4119232Sache || !(t_state & TS_ISOPEN) 4129232Sache ) { 4139232Sache if ( ( !(t_state & TS_ISOPEN) 4149232Sache || (t_state & TS_TBLOCK) 4159232Sache ) 4169232Sache && (rc->rc_msvr & MSVR_RTS) 4179232Sache ) 418105806Sjhb rcout(sc, CD180_MSVR, 4199232Sache rc->rc_msvr &= ~MSVR_RTS); 4209232Sache else if (!(rc->rc_msvr & MSVR_RTS)) 421105806Sjhb rcout(sc, CD180_MSVR, 4229232Sache rc->rc_msvr |= MSVR_RTS); 4239232Sache } 424105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 4259232Sache resid = 0; 4268471Sache 4279232Sache if (t_state & TS_ISOPEN) { 4289232Sache /* check for input buffer overflow */ 4299232Sache if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { 4309232Sache resid = ucnt; 4319232Sache ucnt = rc->rc_bufend - rc->rc_iptr; 4329232Sache resid -= ucnt; 4339232Sache if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { 4349232Sache rc->rc_flags |= RC_WAS_BUFOVFL; 435105806Sjhb sc->sc_scheduled_event++; 4369232Sache } 4378471Sache } 4389232Sache optr = rc->rc_iptr; 4399232Sache /* check foor good data */ 4409232Sache if (good_data) { 4419232Sache while (ucnt-- > 0) { 442105806Sjhb val = rcin(sc, CD180_RDR); 4439232Sache optr[0] = val; 4449232Sache optr[INPUT_FLAGS_SHIFT] = 0; 4459232Sache optr++; 446105806Sjhb sc->sc_scheduled_event++; 447136210Sphk if (val != 0 && val == rc->rc_tp->t_hotchar) 448105806Sjhb swi_sched(sc->sc_swicookie, 0); 4498471Sache } 4509232Sache } else { 4519232Sache /* Store also status data */ 4529232Sache while (ucnt-- > 0) { 453105806Sjhb iack = rcin(sc, CD180_RCSR); 4549232Sache if (iack & RCSR_Timeout) 4559232Sache break; 4569232Sache if ( (iack & RCSR_OE) 4579232Sache && !(rc->rc_flags & RC_WAS_SILOVFL)) { 4589232Sache rc->rc_flags |= RC_WAS_SILOVFL; 459105806Sjhb sc->sc_scheduled_event++; 4609232Sache } 461105806Sjhb val = rcin(sc, CD180_RDR); 4629232Sache /* 4639232Sache Don't store PE if IGNPAR and BREAK if IGNBRK, 4649232Sache this hack allows "raw" tty optimization 4659232Sache works even if IGN* is set. 4669232Sache */ 4679232Sache if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) 46846704Speter || ((!(iack & (RCSR_PE|RCSR_FE)) 469136210Sphk || !(rc->rc_tp->t_iflag & IGNPAR)) 4709232Sache && (!(iack & RCSR_Break) 471136210Sphk || !(rc->rc_tp->t_iflag & IGNBRK)))) { 4729232Sache if ( (iack & (RCSR_PE|RCSR_FE)) 4739232Sache && (t_state & TS_CAN_BYPASS_L_RINT) 4749232Sache && ((iack & RCSR_FE) 47546704Speter || ((iack & RCSR_PE) 476136210Sphk && (rc->rc_tp->t_iflag & INPCK)))) 4779232Sache val = 0; 478136210Sphk else if (val != 0 && val == rc->rc_tp->t_hotchar) 479105806Sjhb swi_sched(sc->sc_swicookie, 0); 4809232Sache optr[0] = val; 4819232Sache optr[INPUT_FLAGS_SHIFT] = iack; 4829232Sache optr++; 483105806Sjhb sc->sc_scheduled_event++; 4849232Sache } 4859232Sache } 4868471Sache } 4879232Sache rc->rc_iptr = optr; 4889232Sache rc->rc_flags |= RC_DORXFER; 4899232Sache } else 4909232Sache resid = ucnt; 4919232Sache /* Clear FIFO if necessary */ 4929232Sache while (resid-- > 0) { 4939232Sache if (!good_data) 494105806Sjhb iack = rcin(sc, CD180_RCSR); 4959232Sache else 4969232Sache iack = 0; 4979232Sache if (iack & RCSR_Timeout) 4989232Sache break; 499105806Sjhb (void) rcin(sc, CD180_RDR); 5008471Sache } 5019232Sache goto more_intrs; 5028471Sache } 5039232Sache if (bsr & RC_BSR_MOINT) { 504105806Sjhb iack = rcin(sc, RC_PILR_MODEM); 5059232Sache if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { 506105806Sjhb device_printf(sc->sc_dev, "fake moint: %02x\n", 507105806Sjhb iack); 5089232Sache goto more_intrs; 5099232Sache } 510105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 511105806Sjhb rc = &sc->sc_channels[chan]; 512105806Sjhb iack = rcin(sc, CD180_MCR); 513105806Sjhb rc->rc_msvr = rcin(sc, CD180_MSVR); 514105806Sjhb rcout(sc, CD180_MCR, 0); 5158471Sache#ifdef RCDEBUG 5169232Sache printrcflags(rc, "moint"); 5178471Sache#endif 5189232Sache if (rc->rc_flags & RC_CTSFLOW) { 5199232Sache if (rc->rc_msvr & MSVR_CTS) 5209232Sache rc->rc_flags |= RC_SEND_RDY; 5219232Sache else 5229232Sache rc->rc_flags &= ~RC_SEND_RDY; 5239232Sache } else 5248471Sache rc->rc_flags |= RC_SEND_RDY; 5259232Sache if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { 526105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 5279232Sache rc->rc_flags |= RC_MODCHG; 528105806Sjhb swi_sched(sc->sc_swicookie, 0); 5299232Sache } 5309232Sache goto more_intrs; 5318471Sache } 5329232Sache if (bsr & RC_BSR_TXINT) { 533105806Sjhb iack = rcin(sc, RC_PILR_TX); 5349232Sache if (iack != (GIVR_IT_TDI | RC_FAKEID)) { 535105806Sjhb device_printf(sc->sc_dev, "fake txint: %02x\n", 536105806Sjhb iack); 5379232Sache goto more_intrs; 5389232Sache } 539105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 540105806Sjhb rc = &sc->sc_channels[chan]; 5419232Sache if ( (rc->rc_flags & RC_OSUSP) 5429232Sache || !(rc->rc_flags & RC_SEND_RDY) 5439232Sache ) 5449232Sache goto more_intrs; 5459232Sache /* Handle breaks and other stuff */ 5469232Sache if (rc->rc_pendcmd) { 547105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 |= COR2_ETC); 548105806Sjhb rcout(sc, CD180_TDR, CD180_C_ESC); 549105806Sjhb rcout(sc, CD180_TDR, rc->rc_pendcmd); 550105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); 5519232Sache rc->rc_pendcmd = 0; 5529232Sache goto more_intrs; 5539232Sache } 5549232Sache optr = rc->rc_optr; 5559232Sache resid = rc->rc_obufend - optr; 5569232Sache if (resid > CD180_NFIFO) 5579232Sache resid = CD180_NFIFO; 5589232Sache while (resid-- > 0) 559105806Sjhb rcout(sc, CD180_TDR, *optr++); 5609232Sache rc->rc_optr = optr; 5618471Sache 5629232Sache /* output completed? */ 5639232Sache if (optr >= rc->rc_obufend) { 564105806Sjhb rcout(sc, CD180_IER, rc->rc_ier &= ~IER_TxRdy); 5658471Sache#ifdef RCDEBUG 566105806Sjhb device_printf(sc->sc_dev, 567105806Sjhb "channel %d: output completed\n", 568105806Sjhb rc->rc_chan); 5698471Sache#endif 5709232Sache if (!(rc->rc_flags & RC_DOXXFER)) { 571105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 5729232Sache rc->rc_flags |= RC_DOXXFER; 573105806Sjhb swi_sched(sc->sc_swicookie, 0); 5749232Sache } 5759232Sache } 5768471Sache } 5779232Sache more_intrs: 578105806Sjhb rcout(sc, CD180_EOIR, 0); /* end of interrupt */ 579105806Sjhb rcout(sc, RC_CTOUT, 0); 580105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 5818471Sache } 5828471Sache} 5838471Sache 5848471Sache/* Feed characters to output buffer */ 585105806Sjhbstatic void 586105806Sjhbrc_start(struct tty *tp) 5878471Sache{ 588105806Sjhb struct rc_softc *sc; 589105806Sjhb struct rc_chans *rc; 590105806Sjhb int s; 5918471Sache 592136210Sphk rc = tp->t_sc; 5938471Sache if (rc->rc_flags & RC_OSBUSY) 5948471Sache return; 595105806Sjhb sc = rc->rc_rcb; 5968471Sache s = spltty(); 5978471Sache rc->rc_flags |= RC_OSBUSY; 598106653Sjhb critical_enter(); 5998471Sache if (tp->t_state & TS_TTSTOP) 6008471Sache rc->rc_flags |= RC_OSUSP; 6018471Sache else 6028471Sache rc->rc_flags &= ~RC_OSUSP; 6038471Sache /* Do RTS flow control stuff */ 6049232Sache if ( (rc->rc_flags & RC_RTSFLOW) 6059232Sache && (tp->t_state & TS_TBLOCK) 6069232Sache && (rc->rc_msvr & MSVR_RTS) 6079232Sache ) { 608105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 609105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); 6109232Sache } else if (!(rc->rc_msvr & MSVR_RTS)) { 611105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 612105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr |= MSVR_RTS); 6138471Sache } 614106653Sjhb critical_exit(); 6158471Sache if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 6168471Sache goto out; 6178471Sache#ifdef RCDEBUG 6188471Sache printrcflags(rc, "rcstart"); 6198471Sache#endif 6209626Sbde ttwwakeup(tp); 6218471Sache#ifdef RCDEBUG 6229232Sache printf("rcstart: outq = %d obuf = %d\n", 6238471Sache tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); 6248471Sache#endif 6259232Sache if (tp->t_state & TS_BUSY) 626105806Sjhb goto out; /* output still in progress ... */ 6278471Sache 6288471Sache if (tp->t_outq.c_cc > 0) { 6298471Sache u_int ocnt; 6308471Sache 6318471Sache tp->t_state |= TS_BUSY; 6328471Sache ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); 633106653Sjhb critical_enter(); 6348471Sache rc->rc_optr = rc->rc_obuf; 6359232Sache rc->rc_obufend = rc->rc_optr + ocnt; 636106653Sjhb critical_exit(); 6379232Sache if (!(rc->rc_ier & IER_TxRdy)) { 6388471Sache#ifdef RCDEBUG 639105806Sjhb device_printf(sc->sc_dev, 640105806Sjhb "channel %d: rcstart enable txint\n", rc->rc_chan); 6418471Sache#endif 642105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 643105806Sjhb rcout(sc, CD180_IER, rc->rc_ier |= IER_TxRdy); 6448471Sache } 6458471Sache } 6468471Sacheout: 6478471Sache rc->rc_flags &= ~RC_OSBUSY; 6488471Sache (void) splx(s); 6498471Sache} 6508471Sache 6518471Sache/* Handle delayed events. */ 652105806Sjhbvoid 653105806Sjhbrc_pollcard(void *arg) 6548471Sache{ 655105806Sjhb struct rc_softc *sc; 656105806Sjhb struct rc_chans *rc; 657105806Sjhb struct tty *tp; 658105806Sjhb u_char *tptr, *eptr; 659105806Sjhb int chan, icnt; 6608471Sache 661105806Sjhb sc = (struct rc_softc *)arg; 662105806Sjhb if (sc->sc_scheduled_event == 0) 6638471Sache return; 664105806Sjhb do { 665105806Sjhb rc = sc->sc_channels; 6668471Sache for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { 667136210Sphk tp = rc->rc_tp; 6688471Sache#ifdef RCDEBUG 6698471Sache if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| 6708471Sache RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) 6718471Sache printrcflags(rc, "rcevent"); 6728471Sache#endif 6738471Sache if (rc->rc_flags & RC_WAS_BUFOVFL) { 674106653Sjhb critical_enter(); 6758471Sache rc->rc_flags &= ~RC_WAS_BUFOVFL; 676105806Sjhb sc->sc_scheduled_event--; 677106653Sjhb critical_exit(); 678105806Sjhb device_printf(sc->sc_dev, 679105806Sjhb "channel %d: interrupt-level buffer overflow\n", 680105806Sjhb chan); 6818471Sache } 6828471Sache if (rc->rc_flags & RC_WAS_SILOVFL) { 683106653Sjhb critical_enter(); 6848471Sache rc->rc_flags &= ~RC_WAS_SILOVFL; 685105806Sjhb sc->sc_scheduled_event--; 686106653Sjhb critical_exit(); 687105806Sjhb device_printf(sc->sc_dev, 688105806Sjhb "channel %d: silo overflow\n", chan); 6898471Sache } 6908471Sache if (rc->rc_flags & RC_MODCHG) { 691106653Sjhb critical_enter(); 6928471Sache rc->rc_flags &= ~RC_MODCHG; 693105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 694106653Sjhb critical_exit(); 695130077Sphk ttyld_modem(tp, !!(rc->rc_msvr & MSVR_CD)); 6968471Sache } 6978471Sache if (rc->rc_flags & RC_DORXFER) { 698106653Sjhb critical_enter(); 6998471Sache rc->rc_flags &= ~RC_DORXFER; 7008471Sache eptr = rc->rc_iptr; 7018471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) 7028471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7038471Sache else 7048471Sache tptr = rc->rc_ibuf; 7058471Sache icnt = eptr - tptr; 7068471Sache if (icnt > 0) { 7078471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 7088471Sache rc->rc_iptr = rc->rc_ibuf; 7098471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 7108471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 7118471Sache } else { 7128471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7138471Sache rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; 7148471Sache rc->rc_hiwat = 7158471Sache &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; 7168471Sache } 7179232Sache if ( (rc->rc_flags & RC_RTSFLOW) 7189232Sache && (tp->t_state & TS_ISOPEN) 7199232Sache && !(tp->t_state & TS_TBLOCK) 7208471Sache && !(rc->rc_msvr & MSVR_RTS) 7219232Sache ) { 722105806Sjhb rcout(sc, CD180_CAR, chan); 723105806Sjhb rcout(sc, CD180_MSVR, 7248471Sache rc->rc_msvr |= MSVR_RTS); 7258471Sache } 726105806Sjhb sc->sc_scheduled_event -= icnt; 7278471Sache } 728106653Sjhb critical_exit(); 7298471Sache 7309232Sache if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) 7318471Sache goto done1; 7328471Sache 7338471Sache if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) 7348471Sache && !(tp->t_state & TS_LOCAL)) { 7359822Sbde if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER 7369822Sbde && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) 7379822Sbde && !(tp->t_state & TS_TBLOCK)) 7389822Sbde ttyblock(tp); 7398471Sache tk_nin += icnt; 7408471Sache tk_rawcc += icnt; 7418471Sache tp->t_rawcc += icnt; 7428471Sache if (b_to_q(tptr, icnt, &tp->t_rawq)) 743105806Sjhb device_printf(sc->sc_dev, 744105806Sjhb "channel %d: tty-level buffer overflow\n", 745105806Sjhb chan); 7468471Sache ttwakeup(tp); 7478471Sache if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) 7488471Sache || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { 7498471Sache tp->t_state &= ~TS_TTSTOP; 7508471Sache tp->t_lflag &= ~FLUSHO; 7519754Sbde rc_start(tp); 7528471Sache } 7538471Sache } else { 7548471Sache for (; tptr < eptr; tptr++) 755130095Sphk ttyld_rint(tp, 7568471Sache (tptr[0] | 757130095Sphk rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF])); 7588471Sache } 75927125Sbdedone1: ; 7608471Sache } 7618471Sache if (rc->rc_flags & RC_DOXXFER) { 762106653Sjhb critical_enter(); 763105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 7649232Sache rc->rc_flags &= ~RC_DOXXFER; 765136210Sphk rc->rc_tp->t_state &= ~TS_BUSY; 766106653Sjhb critical_exit(); 767130077Sphk ttyld_start(tp); 7688471Sache } 769111564Sjhb if (sc->sc_scheduled_event == 0) 770111564Sjhb break; 7718471Sache } 772111564Sjhb } while (sc->sc_scheduled_event >= LOTS_OF_EVENTS); 7738471Sache} 7748471Sache 775105806Sjhbstatic void 776105806Sjhbrc_stop(struct tty *tp, int rw) 7778471Sache{ 778105806Sjhb struct rc_softc *sc; 779105806Sjhb struct rc_chans *rc; 7808471Sache u_char *tptr, *eptr; 7818471Sache 782136210Sphk rc = tp->t_sc; 783105806Sjhb sc = rc->rc_rcb; 7848471Sache#ifdef RCDEBUG 785105806Sjhb device_printf(sc->sc_dev, "channel %d: rc_stop %s%s\n", 786105806Sjhb rc->rc_chan, (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); 7878471Sache#endif 7888471Sache if (rw & FWRITE) 7898471Sache rc_discard_output(rc); 790106653Sjhb critical_enter(); 7918471Sache if (rw & FREAD) { 7929232Sache rc->rc_flags &= ~RC_DORXFER; 7938471Sache eptr = rc->rc_iptr; 7948471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 7958471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7968471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7978471Sache } else { 7988471Sache tptr = rc->rc_ibuf; 7998471Sache rc->rc_iptr = rc->rc_ibuf; 8008471Sache } 801105806Sjhb sc->sc_scheduled_event -= eptr - tptr; 8028471Sache } 8038471Sache if (tp->t_state & TS_TTSTOP) 8048471Sache rc->rc_flags |= RC_OSUSP; 8058471Sache else 8068471Sache rc->rc_flags &= ~RC_OSUSP; 807106653Sjhb critical_exit(); 8088471Sache} 8098471Sache 810136210Sphkstatic void 811136210Sphkrc_close(struct tty *tp) 8128471Sache{ 813105806Sjhb struct rc_chans *rc; 814105806Sjhb struct rc_softc *sc; 815105806Sjhb int s; 8168471Sache 817136210Sphk rc = tp->t_sc; 818105806Sjhb sc = rc->rc_rcb; 8198471Sache s = spltty(); 820105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 8218471Sache 8229232Sache /* Disable rx/tx intrs */ 823105806Sjhb rcout(sc, CD180_IER, rc->rc_ier = 0); 8249232Sache if ( (tp->t_cflag & HUPCL) 82546704Speter || (!(rc->rc_flags & RC_ACTOUT) 8268471Sache && !(rc->rc_msvr & MSVR_CD) 82746704Speter && !(tp->t_cflag & CLOCAL)) 8289232Sache || !(tp->t_state & TS_ISOPEN) 8299232Sache ) { 830105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 831105806Sjhb WAITFORCCR(sc, rc->rc_chan); 832131096Sphk (void) rc_modem(tp, SER_RTS, 0); 833131981Sphk ttydtrwaitstart(tp); 8348471Sache } 8358471Sache rc->rc_flags &= ~RC_ACTOUT; 836111748Sdes wakeup( &rc->rc_rcb); /* wake bi */ 8379639Sbde wakeup(TSA_CARR_ON(tp)); 8388471Sache (void) splx(s); 8398471Sache} 8408471Sache 8418471Sache/* Reset the bastard */ 842105806Sjhbstatic void 843118607Sjhbrc_hwreset(struct rc_softc *sc, u_int chipid) 8448471Sache{ 845105806Sjhb CCRCMD(sc, -1, CCR_HWRESET); /* Hardware reset */ 8468471Sache DELAY(20000); 847105806Sjhb WAITFORCCR(sc, -1); 8489232Sache 849105806Sjhb rcout(sc, RC_CTOUT, 0); /* Clear timeout */ 850105806Sjhb rcout(sc, CD180_GIVR, chipid); 851105806Sjhb rcout(sc, CD180_GICR, 0); 8528471Sache 8538471Sache /* Set Prescaler Registers (1 msec) */ 854105806Sjhb rcout(sc, CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); 855105806Sjhb rcout(sc, CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); 8568471Sache 8578471Sache /* Initialize Priority Interrupt Level Registers */ 858105806Sjhb rcout(sc, CD180_PILR1, RC_PILR_MODEM); 859105806Sjhb rcout(sc, CD180_PILR2, RC_PILR_TX); 860105806Sjhb rcout(sc, CD180_PILR3, RC_PILR_RX); 8618471Sache 8628471Sache /* Reset DTR */ 863105806Sjhb rcout(sc, RC_DTREG, ~0); 8648471Sache} 8658471Sache 8668471Sache/* Set channel parameters */ 867105806Sjhbstatic int 868105806Sjhbrc_param(struct tty *tp, struct termios *ts) 8698471Sache{ 870105806Sjhb struct rc_softc *sc; 871105806Sjhb struct rc_chans *rc; 872105806Sjhb int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; 8738471Sache 8749855Sache if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 8759855Sache || ts->c_ispeed < 0 || ts->c_ispeed > 76800 8769855Sache ) 8779855Sache return (EINVAL); 8788471Sache if (ts->c_ispeed == 0) 8798471Sache ts->c_ispeed = ts->c_ospeed; 8809855Sache odivs = RC_BRD(ts->c_ospeed); 8819855Sache idivs = RC_BRD(ts->c_ispeed); 8828471Sache 883136210Sphk rc = tp->t_sc; 884105806Sjhb sc = rc->rc_rcb; 8858471Sache s = spltty(); 8868471Sache 8879232Sache /* Select channel */ 888105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 8899232Sache 8908471Sache /* If speed == 0, hangup line */ 8919232Sache if (ts->c_ospeed == 0) { 892105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 893105806Sjhb WAITFORCCR(sc, rc->rc_chan); 894131096Sphk (void) rc_modem(tp, 0, SER_DTR); 8959232Sache } 8968471Sache 8978471Sache tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 8988471Sache cflag = ts->c_cflag; 8998471Sache iflag = ts->c_iflag; 9008471Sache lflag = ts->c_lflag; 9018471Sache 9028471Sache if (idivs > 0) { 903105806Sjhb rcout(sc, CD180_RBPRL, idivs & 0xFF); 904105806Sjhb rcout(sc, CD180_RBPRH, idivs >> 8); 9058471Sache } 9068471Sache if (odivs > 0) { 907105806Sjhb rcout(sc, CD180_TBPRL, odivs & 0xFF); 908105806Sjhb rcout(sc, CD180_TBPRH, odivs >> 8); 9098471Sache } 9108471Sache 9118471Sache /* set timeout value */ 9129232Sache if (ts->c_ispeed > 0) { 9139232Sache int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; 9148471Sache 9159232Sache if ( !(lflag & ICANON) 9169232Sache && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 9179232Sache && ts->c_cc[VTIME] * 10 > itm) 9189232Sache itm = ts->c_cc[VTIME] * 10; 9199232Sache 920105806Sjhb rcout(sc, CD180_RTPR, itm <= 255 ? itm : 255); 9219232Sache } 9229232Sache 9238471Sache switch (cflag & CSIZE) { 9248471Sache case CS5: val = COR1_5BITS; break; 9258471Sache case CS6: val = COR1_6BITS; break; 9268471Sache case CS7: val = COR1_7BITS; break; 9278471Sache default: 9288471Sache case CS8: val = COR1_8BITS; break; 9298471Sache } 9308471Sache if (cflag & PARENB) { 9318471Sache val |= COR1_NORMPAR; 9328471Sache if (cflag & PARODD) 9338471Sache val |= COR1_ODDP; 9349232Sache if (!(cflag & INPCK)) 9359232Sache val |= COR1_Ignore; 9368471Sache } else 9379232Sache val |= COR1_Ignore; 9388471Sache if (cflag & CSTOPB) 9398471Sache val |= COR1_2SB; 940105806Sjhb rcout(sc, CD180_COR1, val); 9418471Sache 9428471Sache /* Set FIFO threshold */ 9439232Sache val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; 9449232Sache inpflow = 0; 9459232Sache if ( (iflag & IXOFF) 9469232Sache && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE 9479232Sache && ( ts->c_cc[VSTART] != _POSIX_VDISABLE 9489232Sache || (iflag & IXANY) 9499232Sache ) 9509232Sache ) 9519232Sache ) { 9529232Sache inpflow = 1; 9539232Sache val |= COR3_SCDE|COR3_FCT; 9549232Sache } 955105806Sjhb rcout(sc, CD180_COR3, val); 9568471Sache 9578471Sache /* Initialize on-chip automatic flow control */ 9588471Sache val = 0; 9599232Sache rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); 9608471Sache if (cflag & CCTS_OFLOW) { 9618471Sache rc->rc_flags |= RC_CTSFLOW; 9629232Sache val |= COR2_CtsAE; 9639232Sache } else 9649232Sache rc->rc_flags |= RC_SEND_RDY; 9659232Sache if (tp->t_state & TS_TTSTOP) 9669232Sache rc->rc_flags |= RC_OSUSP; 9678471Sache else 9689232Sache rc->rc_flags &= ~RC_OSUSP; 9698471Sache if (cflag & CRTS_IFLOW) 9708471Sache rc->rc_flags |= RC_RTSFLOW; 9719232Sache else 9729232Sache rc->rc_flags &= ~RC_RTSFLOW; 9738471Sache 9749232Sache if (inpflow) { 9759232Sache if (ts->c_cc[VSTART] != _POSIX_VDISABLE) 976105806Sjhb rcout(sc, CD180_SCHR1, ts->c_cc[VSTART]); 977105806Sjhb rcout(sc, CD180_SCHR2, ts->c_cc[VSTOP]); 9789232Sache val |= COR2_TxIBE; 9799232Sache if (iflag & IXANY) 9809232Sache val |= COR2_IXM; 9818471Sache } 9828471Sache 983105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 = val); 9848471Sache 985105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 9869232Sache 987131134Sphk ttyldoptim(tp); 9888471Sache 9898471Sache /* modem ctl */ 9909232Sache val = cflag & CLOCAL ? 0 : MCOR1_CDzd; 9919232Sache if (cflag & CCTS_OFLOW) 9929232Sache val |= MCOR1_CTSzd; 993105806Sjhb rcout(sc, CD180_MCOR1, val); 9948471Sache 9959232Sache val = cflag & CLOCAL ? 0 : MCOR2_CDod; 9969232Sache if (cflag & CCTS_OFLOW) 9979232Sache val |= MCOR2_CTSod; 998105806Sjhb rcout(sc, CD180_MCOR2, val); 9999232Sache 10008471Sache /* enable i/o and interrupts */ 1001105806Sjhb CCRCMD(sc, rc->rc_chan, 10029232Sache CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); 1003105806Sjhb WAITFORCCR(sc, rc->rc_chan); 10048471Sache 10059232Sache rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; 10069232Sache if (cflag & CCTS_OFLOW) 10079232Sache rc->rc_ier |= IER_CTS; 10089232Sache if (cflag & CREAD) 10099232Sache rc->rc_ier |= IER_RxData; 10109232Sache if (tp->t_state & TS_BUSY) 10119232Sache rc->rc_ier |= IER_TxRdy; 10129232Sache if (ts->c_ospeed != 0) 1013131096Sphk rc_modem(tp, SER_DTR, 0); 10149232Sache if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) 10159232Sache rc->rc_flags |= RC_SEND_RDY; 1016105806Sjhb rcout(sc, CD180_IER, rc->rc_ier); 10178471Sache (void) splx(s); 10188471Sache return 0; 10198471Sache} 10208471Sache 10219232Sache/* Re-initialize board after bogus interrupts */ 1022105806Sjhbstatic void 1023105806Sjhbrc_reinit(struct rc_softc *sc) 10249232Sache{ 1025105806Sjhb struct rc_chans *rc; 1026105806Sjhb int i; 10279232Sache 1028105806Sjhb rc_hwreset(sc, RC_FAKEID); 1029105806Sjhb rc = sc->sc_channels; 1030105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) 1031136210Sphk (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios); 10329232Sache} 10339232Sache 10348471Sache/* Modem control routines */ 10358471Sache 1036105806Sjhbstatic int 1037131096Sphkrc_modem(struct tty *tp, int biton, int bitoff) 10388471Sache{ 1039131096Sphk struct rc_chans *rc; 1040105806Sjhb struct rc_softc *sc; 1041105806Sjhb u_char *dtr; 1042105806Sjhb u_char msvr; 10438471Sache 1044136210Sphk rc = tp->t_sc; 1045105806Sjhb sc = rc->rc_rcb; 1046105806Sjhb dtr = &sc->sc_dtr; 1047105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 10488471Sache 1049131096Sphk if (biton == 0 && bitoff == 0) { 1050105806Sjhb msvr = rc->rc_msvr = rcin(sc, CD180_MSVR); 10518471Sache 10528471Sache if (msvr & MSVR_RTS) 1053131096Sphk biton |= SER_RTS; 10548471Sache if (msvr & MSVR_CTS) 1055131096Sphk biton |= SER_CTS; 10568471Sache if (msvr & MSVR_DSR) 1057131096Sphk biton |= SER_DSR; 10588471Sache if (msvr & MSVR_DTR) 1059131096Sphk biton |= SER_DTR; 10609232Sache if (msvr & MSVR_CD) 1061131096Sphk biton |= SER_DCD; 1062105806Sjhb if (~rcin(sc, RC_RIREG) & (1 << rc->rc_chan)) 1063131096Sphk biton |= SER_RI; 1064131096Sphk return biton; 10658471Sache } 1066131096Sphk if (biton & SER_DTR) 1067131096Sphk rcout(sc, RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); 1068131096Sphk if (bitoff & SER_DTR) 1069131096Sphk rcout(sc, RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); 1070131096Sphk msvr = rcin(sc, CD180_MSVR); 1071131096Sphk if (biton & SER_DTR) 1072131096Sphk msvr |= MSVR_DTR; 1073131096Sphk if (bitoff & SER_DTR) 1074131096Sphk msvr &= ~MSVR_DTR; 1075131096Sphk if (biton & SER_RTS) 1076131096Sphk msvr |= MSVR_RTS; 1077131096Sphk if (bitoff & SER_RTS) 1078131096Sphk msvr &= ~MSVR_RTS; 1079131096Sphk rcout(sc, CD180_MSVR, msvr); 10808471Sache return 0; 10818471Sache} 10828471Sache 1083131373Sphkstatic void 1084131096Sphkrc_break(struct tty *tp, int brk) 1085131096Sphk{ 1086131096Sphk struct rc_chans *rc; 1087131096Sphk 1088136210Sphk rc = tp->t_sc; 1089131096Sphk 1090131096Sphk if (brk) 1091131096Sphk rc->rc_pendcmd = CD180_C_SBRK; 1092131096Sphk else 1093131096Sphk rc->rc_pendcmd = CD180_C_EBRK; 1094131096Sphk} 1095131096Sphk 1096105806Sjhb#define ERR(s) do { \ 1097105806Sjhb device_printf(sc->sc_dev, "%s", ""); \ 1098105806Sjhb printf s ; \ 1099105806Sjhb printf("\n"); \ 1100105806Sjhb (void) splx(old_level); \ 1101105806Sjhb return 1; \ 1102105806Sjhb} while (0) 1103105806Sjhb 11048471Sache/* Test the board. */ 1105105806Sjhbint 1106105806Sjhbrc_test(struct rc_softc *sc) 11078471Sache{ 110816322Sgpalmer int chan = 0; 11098471Sache int i = 0, rcnt, old_level; 11108471Sache unsigned int iack, chipid; 11118471Sache unsigned short divs; 11128471Sache static u_char ctest[] = "\377\125\252\045\244\0\377"; 11138471Sache#define CTLEN 8 11148471Sache 11158471Sache struct rtest { 11168471Sache u_char txbuf[CD180_NFIFO]; /* TX buffer */ 11178471Sache u_char rxbuf[CD180_NFIFO]; /* RX buffer */ 11188471Sache int rxptr; /* RX pointer */ 11198471Sache int txptr; /* TX pointer */ 11208471Sache } tchans[CD180_NCHAN]; 11218471Sache 11229232Sache old_level = spltty(); 11238471Sache 11248471Sache chipid = RC_FAKEID; 11258471Sache 1126298955Spfg /* First, reset board to initial state */ 1127105806Sjhb rc_hwreset(sc, chipid); 11288471Sache 11299232Sache divs = RC_BRD(19200); 11309232Sache 11318471Sache /* Initialize channels */ 11328471Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 11338471Sache 11348471Sache /* Select and reset channel */ 1135105806Sjhb rcout(sc, CD180_CAR, chan); 1136105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 1137105806Sjhb WAITFORCCR(sc, chan); 11388471Sache 11398471Sache /* Set speed */ 1140105806Sjhb rcout(sc, CD180_RBPRL, divs & 0xFF); 1141105806Sjhb rcout(sc, CD180_RBPRH, divs >> 8); 1142105806Sjhb rcout(sc, CD180_TBPRL, divs & 0xFF); 1143105806Sjhb rcout(sc, CD180_TBPRH, divs >> 8); 11448471Sache 11458471Sache /* set timeout value */ 1146105806Sjhb rcout(sc, CD180_RTPR, 0); 11478471Sache 11488471Sache /* Establish local loopback */ 1149105806Sjhb rcout(sc, CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); 1150105806Sjhb rcout(sc, CD180_COR2, COR2_LLM); 1151105806Sjhb rcout(sc, CD180_COR3, CD180_NFIFO); 1152105806Sjhb CCRCMD(sc, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1153105806Sjhb CCRCMD(sc, chan, CCR_RCVREN | CCR_XMTREN); 1154105806Sjhb WAITFORCCR(sc, chan); 1155105806Sjhb rcout(sc, CD180_MSVR, MSVR_RTS); 11568471Sache 11578471Sache /* Fill TXBUF with test data */ 11588471Sache for (i = 0; i < CD180_NFIFO; i++) { 11598471Sache tchans[chan].txbuf[i] = ctest[i]; 11608471Sache tchans[chan].rxbuf[i] = 0; 11618471Sache } 11628471Sache tchans[chan].txptr = tchans[chan].rxptr = 0; 11638471Sache 11648471Sache /* Now, start transmit */ 1165105806Sjhb rcout(sc, CD180_IER, IER_TxMpty|IER_RxData); 11668471Sache } 11678471Sache /* Pseudo-interrupt poll stuff */ 11688471Sache for (rcnt = 10000; rcnt-- > 0; rcnt--) { 1169105806Sjhb i = ~(rcin(sc, RC_BSR)); 11708471Sache if (i & RC_BSR_TOUT) 1171105806Sjhb ERR(("BSR timeout bit set\n")); 11729232Sache else if (i & RC_BSR_TXINT) { 1173105806Sjhb iack = rcin(sc, RC_PILR_TX); 11748471Sache if (iack != (GIVR_IT_TDI | chipid)) 11758471Sache ERR(("Bad TX intr ack (%02x != %02x)\n", 11768471Sache iack, GIVR_IT_TDI | chipid)); 1177105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 11788471Sache /* If no more data to transmit, disable TX intr */ 11798471Sache if (tchans[chan].txptr >= CD180_NFIFO) { 1180105806Sjhb iack = rcin(sc, CD180_IER); 1181105806Sjhb rcout(sc, CD180_IER, iack & ~IER_TxMpty); 11828471Sache } else { 11838471Sache for (iack = tchans[chan].txptr; 11848471Sache iack < CD180_NFIFO; iack++) 1185105806Sjhb rcout(sc, CD180_TDR, 11868471Sache tchans[chan].txbuf[iack]); 11878471Sache tchans[chan].txptr = iack; 11888471Sache } 1189105806Sjhb rcout(sc, CD180_EOIR, 0); 11909232Sache } else if (i & RC_BSR_RXINT) { 11919232Sache u_char ucnt; 11928471Sache 1193105806Sjhb iack = rcin(sc, RC_PILR_RX); 11948471Sache if (iack != (GIVR_IT_RGDI | chipid) && 11958471Sache iack != (GIVR_IT_REI | chipid)) 11968471Sache ERR(("Bad RX intr ack (%02x != %02x)\n", 1197105806Sjhb iack, GIVR_IT_RGDI | chipid)); 1198105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1199105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 12008471Sache while (ucnt-- > 0) { 1201105806Sjhb iack = rcin(sc, CD180_RCSR); 12029232Sache if (iack & RCSR_Timeout) 12038471Sache break; 12048471Sache if (iack & 0xF) 12058471Sache ERR(("Bad char chan %d (RCSR = %02X)\n", 1206105806Sjhb chan, iack)); 12078471Sache if (tchans[chan].rxptr > CD180_NFIFO) 12088471Sache ERR(("Got extra chars chan %d\n", 1209105806Sjhb chan)); 12108471Sache tchans[chan].rxbuf[tchans[chan].rxptr++] = 1211105806Sjhb rcin(sc, CD180_RDR); 12128471Sache } 1213105806Sjhb rcout(sc, CD180_EOIR, 0); 12148471Sache } 1215105806Sjhb rcout(sc, RC_CTOUT, 0); 12168471Sache for (iack = chan = 0; chan < CD180_NCHAN; chan++) 12178471Sache if (tchans[chan].rxptr >= CD180_NFIFO) 12188471Sache iack++; 12198471Sache if (iack == CD180_NCHAN) 12208471Sache break; 12218471Sache } 12229232Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 12239232Sache /* Select and reset channel */ 1224105806Sjhb rcout(sc, CD180_CAR, chan); 1225105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 12269232Sache } 12279232Sache 12288471Sache if (!rcnt) 1229105806Sjhb ERR(("looses characters during local loopback\n")); 12308471Sache /* Now, check data */ 12318471Sache for (chan = 0; chan < CD180_NCHAN; chan++) 12328471Sache for (i = 0; i < CD180_NFIFO; i++) 12338471Sache if (ctest[i] != tchans[chan].rxbuf[i]) 12348471Sache ERR(("data mismatch chan %d ptr %d (%d != %d)\n", 1235105806Sjhb chan, i, ctest[i], tchans[chan].rxbuf[i])); 12368471Sache (void) splx(old_level); 12378471Sache return 0; 12388471Sache} 12398471Sache 12408471Sache#ifdef RCDEBUG 1241105806Sjhbstatic void 1242105806Sjhbprintrcflags(struct rc_chans *rc, char *comment) 12438471Sache{ 1244105806Sjhb struct rc_softc *sc; 12458471Sache u_short f = rc->rc_flags; 12468471Sache 1247105806Sjhb sc = rc->rc_rcb; 12489232Sache printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", 12498471Sache rc->rc_rcb->rcb_unit, rc->rc_chan, comment, 12508471Sache (f & RC_DTR_OFF)?"DTR_OFF " :"", 12519232Sache (f & RC_ACTOUT) ?"ACTOUT " :"", 12529232Sache (f & RC_RTSFLOW)?"RTSFLOW " :"", 12539232Sache (f & RC_CTSFLOW)?"CTSFLOW " :"", 12549232Sache (f & RC_DORXFER)?"DORXFER " :"", 12559232Sache (f & RC_DOXXFER)?"DOXXFER " :"", 12569232Sache (f & RC_MODCHG) ?"MODCHG " :"", 12579232Sache (f & RC_OSUSP) ?"OSUSP " :"", 12589232Sache (f & RC_OSBUSY) ?"OSBUSY " :"", 12599232Sache (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", 12609232Sache (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", 12619232Sache (f & RC_SEND_RDY) ?"SEND_RDY":""); 12629232Sache 1263105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 12649232Sache 12659232Sache printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", 12669232Sache rc->rc_rcb->rcb_unit, rc->rc_chan, 1267105806Sjhb rcin(sc, CD180_MSVR), 1268105806Sjhb rcin(sc, CD180_IER), 1269105806Sjhb rcin(sc, CD180_CCSR)); 12708471Sache} 12718471Sache#endif /* RCDEBUG */ 12728471Sache 12738471Sachestatic void 1274105806Sjhbrc_discard_output(struct rc_chans *rc) 12758471Sache{ 1276106653Sjhb critical_enter(); 12778471Sache if (rc->rc_flags & RC_DOXXFER) { 1278105806Sjhb rc->rc_rcb->sc_scheduled_event -= LOTS_OF_EVENTS; 12798471Sache rc->rc_flags &= ~RC_DOXXFER; 12808471Sache } 12818471Sache rc->rc_optr = rc->rc_obufend; 1282136210Sphk rc->rc_tp->t_state &= ~TS_BUSY; 1283106653Sjhb critical_exit(); 1284136210Sphk ttwwakeup(rc->rc_tp); 12858471Sache} 12868471Sache 12878471Sachestatic void 1288105806Sjhbrc_wait0(struct rc_softc *sc, int chan, int line) 12899232Sache{ 12909232Sache int rcnt; 12919232Sache 1292105806Sjhb for (rcnt = 50; rcnt && rcin(sc, CD180_CCR); rcnt--) 129314441Srgrimes DELAY(30); 12949232Sache if (rcnt == 0) 1295105806Sjhb device_printf(sc->sc_dev, 1296105806Sjhb "channel %d command timeout, rc.c line: %d\n", chan, line); 12979232Sache} 1298105806Sjhb 1299105806Sjhbstatic device_method_t rc_methods[] = { 1300105806Sjhb /* Device interface */ 1301105806Sjhb DEVMETHOD(device_probe, rc_probe), 1302105806Sjhb DEVMETHOD(device_attach, rc_attach), 1303105806Sjhb DEVMETHOD(device_detach, rc_detach), 1304105806Sjhb { 0, 0 } 1305105806Sjhb}; 1306105806Sjhb 1307105806Sjhbstatic driver_t rc_driver = { 1308105806Sjhb "rc", 1309105806Sjhb rc_methods, sizeof(struct rc_softc), 1310105806Sjhb}; 1311105806Sjhb 1312105806SjhbDRIVER_MODULE(rc, isa, rc_driver, rc_devclass, 0, 0); 1313