rc.c revision 131981
18471Sache/* 28471Sache * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia. 38471Sache * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia. 4105806Sjhb * Copyright (C) 2002 by John Baldwin <jhb@FreeBSD.org> 58471Sache * All rights reserved. 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: head/sys/dev/rc/rc.c 131981 2004-07-11 15:18:39Z phk $ 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 DEV_TO_RC(dev) (struct rc_chans *)((dev)->si_drv1) 62105806Sjhb#define TTY_TO_RC(tty) DEV_TO_RC((tty)->t_dev) 638471Sache 64105806Sjhb#define rcin(sc, port) RC_IN(sc, port) 65105806Sjhb#define rcout(sc, port, v) RC_OUT(sc, port, v) 668471Sache 67105806Sjhb#define WAITFORCCR(sc, chan) rc_wait0((sc), (chan), __LINE__) 688471Sache 69105806Sjhb#define CCRCMD(sc, chan, cmd) do { \ 70105806Sjhb WAITFORCCR((sc), (chan)); \ 71105806Sjhb rcout((sc), CD180_CCR, (cmd)); \ 72105806Sjhb} while (0) 738471Sache 749232Sache#define RC_IBUFSIZE 256 759232Sache#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) 769232Sache#define RC_OBUFSIZE 512 778471Sache#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) 788471Sache#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) 798471Sache#define LOTS_OF_EVENTS 64 808471Sache 818471Sache#define RC_FAKEID 0x10 828471Sache 83105960Sjhb#define CALLOUT(dev) (((intptr_t)(dev)->si_drv2) != 0) 849232Sache 85105806Sjhb/* Per-channel structure */ 86105806Sjhbstruct rc_chans { 87105806Sjhb struct rc_softc *rc_rcb; /* back ptr */ 88130585Sphk struct cdev *rc_dev; /* non-callout device */ 89130585Sphk struct cdev *rc_cdev; /* callout device */ 90105806Sjhb u_short rc_flags; /* Misc. flags */ 91105806Sjhb int rc_chan; /* Channel # */ 92105806Sjhb u_char rc_ier; /* intr. enable reg */ 93105806Sjhb u_char rc_msvr; /* modem sig. status */ 94105806Sjhb u_char rc_cor2; /* options reg */ 95105806Sjhb u_char rc_pendcmd; /* special cmd pending */ 96105806Sjhb u_int rc_dcdwaits; /* how many waits DCD in open */ 97105806Sjhb struct tty rc_tp; /* tty struct */ 98105806Sjhb u_char *rc_iptr; /* Chars input buffer */ 99105806Sjhb u_char *rc_hiwat; /* hi-water mark */ 100105806Sjhb u_char *rc_bufend; /* end of buffer */ 101105806Sjhb u_char *rc_optr; /* ptr in output buf */ 102105806Sjhb u_char *rc_obufend; /* end of output buf */ 103105806Sjhb u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */ 104105806Sjhb u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */ 105105806Sjhb struct callout rc_dtrcallout; 106105806Sjhb}; 1078471Sache 108105806Sjhb/* Per-board structure */ 109105806Sjhbstruct rc_softc { 110105806Sjhb device_t sc_dev; 111105806Sjhb struct resource *sc_irq; 112105806Sjhb struct resource *sc_port[IOBASE_ADDRS]; 113105806Sjhb int sc_irqrid; 114105806Sjhb void *sc_hwicookie; 115105806Sjhb bus_space_tag_t sc_bt; 116105806Sjhb bus_space_handle_t sc_bh; 117105806Sjhb u_int sc_unit; /* unit # */ 118105806Sjhb u_char sc_dtr; /* DTR status */ 119105806Sjhb int sc_opencount; 120105806Sjhb int sc_scheduled_event; 121105806Sjhb void *sc_swicookie; 122105806Sjhb struct rc_chans sc_channels[CD180_NCHAN]; /* channels */ 1238471Sache}; 1248471Sache 125105806Sjhb/* Static prototypes */ 126131373Sphkstatic void rc_break(struct tty *, int); 127105806Sjhbstatic void rc_release_resources(device_t dev); 128105806Sjhbstatic void rc_intr(void *); 129105806Sjhbstatic void rc_hwreset(struct rc_softc *, unsigned int); 130105806Sjhbstatic int rc_test(struct rc_softc *); 131105806Sjhbstatic void rc_discard_output(struct rc_chans *); 132105806Sjhbstatic void rc_hardclose(struct rc_chans *); 133131096Sphkstatic int rc_modem(struct tty *, int, int); 134105806Sjhbstatic void rc_start(struct tty *); 135105806Sjhbstatic void rc_stop(struct tty *, int rw); 136105806Sjhbstatic int rc_param(struct tty *, struct termios *); 137105806Sjhbstatic void rc_pollcard(void *); 138105806Sjhbstatic void rc_reinit(struct rc_softc *); 139105806Sjhb#ifdef RCDEBUG 140105806Sjhbstatic void printrcflags(); 141105806Sjhb#endif 142105806Sjhbstatic void rc_wait0(struct rc_softc *sc, int chan, int line); 143105806Sjhb 14412675Sjulianstatic d_open_t rcopen; 14512675Sjulianstatic d_close_t rcclose; 14612675Sjulian 14747625Sphkstatic struct cdevsw rc_cdevsw = { 148126080Sphk .d_version = D_VERSION, 149111815Sphk .d_open = rcopen, 150111815Sphk .d_close = rcclose, 151111815Sphk .d_name = "rc", 152126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 15338485Sbde}; 15412675Sjulian 155105806Sjhbstatic devclass_t rc_devclass; 1568471Sache 1578471Sache/* Flags */ 1589232Sache#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ 1599232Sache#define RC_ACTOUT 0x0002 /* Dial-out port active */ 1609232Sache#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ 1619232Sache#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ 1629232Sache#define RC_DORXFER 0x0010 /* RXFER event planned */ 1639232Sache#define RC_DOXXFER 0x0020 /* XXFER event planned */ 1649232Sache#define RC_MODCHG 0x0040 /* Modem status changed */ 1659232Sache#define RC_OSUSP 0x0080 /* Output suspended */ 1669232Sache#define RC_OSBUSY 0x0100 /* start() routine in progress */ 1679232Sache#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ 1689232Sache#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ 1699232Sache#define RC_SEND_RDY 0x0800 /* ready to send */ 1708471Sache 1718471Sache/* Table for translation of RCSR status bits to internal form */ 1728471Sachestatic int rc_rcsrt[16] = { 1738471Sache 0, TTY_OE, TTY_FE, 1748471Sache TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE, 1758471Sache TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI, 1768471Sache TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE, 1778471Sache TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE, 1788471Sache TTY_BI|TTY_PE|TTY_FE|TTY_OE 1798471Sache}; 1808471Sache 181105806Sjhbstatic int rc_ports[] = 182105806Sjhb { 0x220, 0x240, 0x250, 0x260, 0x2a0, 0x2b0, 0x300, 0x320 }; 183105806Sjhbstatic int iobase_addrs[IOBASE_ADDRS] = 184105806Sjhb { 0, 0x400, 0x800, 0xc00, 0x1400, 0x1800, 0x1c00, 0x2000, 185105806Sjhb 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x8000 }; 18667551Sjhb 1878471Sache/**********************************************/ 1888471Sache 18912724Sphkstatic int 190105806Sjhbrc_probe(device_t dev) 1918471Sache{ 192105806Sjhb u_int port; 193105806Sjhb int i, found; 1948471Sache 195105806Sjhb /* 196105806Sjhb * We don't know of any PnP ID's for these cards. 197105806Sjhb */ 198105806Sjhb if (isa_get_logicalid(dev) != 0) 199105806Sjhb return (ENXIO); 2009232Sache 201105806Sjhb /* 202105806Sjhb * We have to have an IO port hint that is valid. 203105806Sjhb */ 204105806Sjhb port = isa_get_port(dev); 205105806Sjhb if (port == -1) 206105806Sjhb return (ENXIO); 207105806Sjhb found = 0; 208105806Sjhb for (i = 0; i < sizeof(rc_ports) / sizeof(int); i++) 209105806Sjhb if (rc_ports[i] == port) { 210105806Sjhb found = 1; 211105806Sjhb break; 212105806Sjhb } 213105806Sjhb if (!found) 214105806Sjhb return (ENXIO); 215105806Sjhb 216105806Sjhb /* 217105806Sjhb * We have to have an IRQ hint. 218105806Sjhb */ 219105806Sjhb if (isa_get_irq(dev) == -1) 220105806Sjhb return (ENXIO); 221105806Sjhb 222105806Sjhb device_set_desc(dev, "SDL Riscom/8"); 223105806Sjhb return (0); 2248471Sache} 2258471Sache 22612724Sphkstatic int 227105806Sjhbrc_attach(device_t dev) 2288471Sache{ 229105806Sjhb struct rc_chans *rc; 230105806Sjhb struct tty *tp; 231105806Sjhb struct rc_softc *sc; 232105806Sjhb u_int port; 233105806Sjhb int base, chan, error, i, x; 234130585Sphk struct cdev *cdev; 2358471Sache 236105806Sjhb sc = device_get_softc(dev); 237105806Sjhb sc->sc_dev = dev; 23840565Sbde 239105806Sjhb /* 240105806Sjhb * We need to have IO ports. Lots of them. We need 241105806Sjhb * the following ranges relative to the base port: 242105806Sjhb * 0x0 - 0x10 243105806Sjhb * 0x400 - 0x410 244105806Sjhb * 0x800 - 0x810 245105806Sjhb * 0xc00 - 0xc10 246105806Sjhb * 0x1400 - 0x1410 247105806Sjhb * 0x1800 - 0x1810 248105806Sjhb * 0x1c00 - 0x1c10 249105806Sjhb * 0x2000 - 0x2010 250105806Sjhb * 0x3000 - 0x3010 251105806Sjhb * 0x3400 - 0x3410 252105806Sjhb * 0x3800 - 0x3810 253105806Sjhb * 0x3c00 - 0x3c10 254105806Sjhb * 0x4000 - 0x4010 255105806Sjhb * 0x8000 - 0x8010 256105806Sjhb */ 257105806Sjhb port = isa_get_port(dev); 258105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) 259105806Sjhb if (bus_set_resource(dev, SYS_RES_IOPORT, i, 260105806Sjhb port + iobase_addrs[i], 0x10) != 0) 261105806Sjhb return (ENXIO); 262105806Sjhb error = ENOMEM; 263105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 264105806Sjhb x = i; 265105806Sjhb sc->sc_port[i] = bus_alloc_resource(dev, SYS_RES_IOPORT, &x, 266105806Sjhb 0ul, ~0ul, 0x10, RF_ACTIVE); 267105806Sjhb if (x != i) { 268105806Sjhb device_printf(dev, "ioport %d was rid %d\n", i, x); 269105806Sjhb goto fail; 270105806Sjhb } 271105806Sjhb if (sc->sc_port[i] == NULL) { 272105806Sjhb device_printf(dev, "failed to alloc ioports %x-%x\n", 273105806Sjhb port + iobase_addrs[i], 274105806Sjhb port + iobase_addrs[i] + 0x10); 275105806Sjhb goto fail; 276105806Sjhb } 277105806Sjhb } 278105806Sjhb sc->sc_bt = rman_get_bustag(sc->sc_port[0]); 279105806Sjhb sc->sc_bh = rman_get_bushandle(sc->sc_port[0]); 2808471Sache 281127135Snjl sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, 282127135Snjl RF_ACTIVE); 283105806Sjhb if (sc->sc_irq == NULL) { 284105806Sjhb device_printf(dev, "failed to alloc IRQ\n"); 285105806Sjhb goto fail; 286105806Sjhb } 287105806Sjhb 288105806Sjhb /* 289105806Sjhb * Now do some actual tests to make sure it works. 290105806Sjhb */ 291105806Sjhb error = ENXIO; 292105806Sjhb rcout(sc, CD180_PPRL, 0x22); /* Random values to Prescale reg. */ 293105806Sjhb rcout(sc, CD180_PPRH, 0x11); 294105806Sjhb if (rcin(sc, CD180_PPRL) != 0x22 || rcin(sc, CD180_PPRH) != 0x11) 295105806Sjhb goto fail; 296105806Sjhb if (rc_test(sc)) 297105806Sjhb goto fail; 298105806Sjhb 299105806Sjhb /* 300105806Sjhb * Ok, start actually hooking things up. 301105806Sjhb */ 302105806Sjhb sc->sc_unit = device_get_unit(dev); 303105806Sjhb /*sc->sc_chipid = 0x10 + device_get_unit(dev);*/ 304105806Sjhb device_printf(dev, "%d chans, firmware rev. %c\n", 305105806Sjhb CD180_NCHAN, (rcin(sc, CD180_GFRCR) & 0xF) + 'A'); 306105806Sjhb rc = sc->sc_channels; 307105806Sjhb base = CD180_NCHAN * sc->sc_unit; 3088471Sache for (chan = 0; chan < CD180_NCHAN; chan++, rc++) { 309105806Sjhb rc->rc_rcb = sc; 3108471Sache rc->rc_chan = chan; 3118471Sache rc->rc_iptr = rc->rc_ibuf; 3128471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 3138471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 3148471Sache rc->rc_optr = rc->rc_obufend = rc->rc_obuf; 315105806Sjhb callout_init(&rc->rc_dtrcallout, 0); 316105806Sjhb tp = &rc->rc_tp; 3179232Sache ttychars(tp); 3189232Sache tp->t_lflag = tp->t_iflag = tp->t_oflag = 0; 3199232Sache tp->t_cflag = TTYDEF_CFLAG; 3209232Sache tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 321105806Sjhb cdev = make_dev(&rc_cdevsw, chan + base, 322105806Sjhb UID_ROOT, GID_WHEEL, 0600, "ttym%d", chan + base); 323105806Sjhb cdev->si_drv1 = rc; 324105806Sjhb cdev->si_drv2 = 0; 325105806Sjhb cdev->si_tty = tp; 326105806Sjhb rc->rc_dev = cdev; 327105806Sjhb cdev = make_dev(&rc_cdevsw, chan + base + 128, 328105806Sjhb UID_UUCP, GID_DIALER, 0660, "cuam%d", chan + base); 329105806Sjhb cdev->si_drv1 = rc; 330105806Sjhb cdev->si_drv2 = (void *)1; 331105806Sjhb cdev->si_tty = tp; 332105806Sjhb rc->rc_cdev = cdev; 3338471Sache } 334105806Sjhb 335105806Sjhb error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_TTY, rc_intr, sc, 336105806Sjhb &sc->sc_hwicookie); 337105806Sjhb if (error) { 338105806Sjhb device_printf(dev, "failed to register interrupt handler\n"); 339105806Sjhb goto fail; 3408471Sache } 341105806Sjhb 342105806Sjhb swi_add(&tty_ithd, "tty:rc", rc_pollcard, sc, SWI_TTY, 0, 343105806Sjhb &sc->sc_swicookie); 344105806Sjhb return (0); 345105806Sjhb 346105806Sjhbfail: 347105806Sjhb rc_release_resources(dev); 348105806Sjhb return (error); 3498471Sache} 3508471Sache 351105806Sjhbstatic int 352105806Sjhbrc_detach(device_t dev) 353105806Sjhb{ 354105806Sjhb struct rc_softc *sc; 355105806Sjhb struct rc_chans *rc; 356131981Sphk int error, i; 357105806Sjhb 358105806Sjhb sc = device_get_softc(dev); 359105806Sjhb if (sc->sc_opencount > 0) 360105806Sjhb return (EBUSY); 361105806Sjhb sc->sc_opencount = -1; 362105806Sjhb 363105806Sjhb rc = sc->sc_channels; 364105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) { 365131981Sphk ttygone(&rc->rc_tp); 366105806Sjhb destroy_dev(rc->rc_dev); 367105806Sjhb destroy_dev(rc->rc_cdev); 368105806Sjhb } 369105806Sjhb 370105806Sjhb error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_hwicookie); 371105806Sjhb if (error) 372105806Sjhb device_printf(dev, "failed to deregister interrupt handler\n"); 373105806Sjhb ithread_remove_handler(sc->sc_swicookie); 374105806Sjhb rc_release_resources(dev); 375105806Sjhb 376105806Sjhb return (0); 377105806Sjhb} 378105806Sjhb 37940565Sbdestatic void 380105806Sjhbrc_release_resources(device_t dev) 3818471Sache{ 382105806Sjhb struct rc_softc *sc; 383105806Sjhb int i; 3848471Sache 385105806Sjhb sc = device_get_softc(dev); 386105806Sjhb if (sc->sc_irq != NULL) { 387105806Sjhb bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 388105806Sjhb sc->sc_irq); 389105806Sjhb sc->sc_irq = NULL; 3909232Sache } 391105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 392105806Sjhb if (sc->sc_port[i] == NULL) 393105806Sjhb break; 394105806Sjhb bus_release_resource(dev, SYS_RES_IOPORT, i, sc->sc_port[i]); 395105806Sjhb sc->sc_port[i] = NULL; 396105806Sjhb } 397105806Sjhb} 3988471Sache 399105806Sjhb/* RC interrupt handling */ 400105806Sjhbstatic void 401105806Sjhbrc_intr(void *arg) 402105806Sjhb{ 403105806Sjhb struct rc_softc *sc; 404105806Sjhb struct rc_chans *rc; 405105806Sjhb int resid, chan; 406105806Sjhb u_char val, iack, bsr, ucnt, *optr; 407105806Sjhb int good_data, t_state; 4088471Sache 409105806Sjhb sc = (struct rc_softc *)arg; 410105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 4119232Sache if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { 412105806Sjhb device_printf(sc->sc_dev, "extra interrupt\n"); 413105806Sjhb rcout(sc, CD180_EOIR, 0); 4149232Sache return; 4159232Sache } 4169232Sache 4179232Sache while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { 4189232Sache#ifdef RCDEBUG_DETAILED 419105806Sjhb device_printf(sc->sc_dev, "intr (%p) %s%s%s%s\n", arg, bsr, 4209232Sache (bsr & RC_BSR_TOUT)?"TOUT ":"", 4219232Sache (bsr & RC_BSR_RXINT)?"RXINT ":"", 4229232Sache (bsr & RC_BSR_TXINT)?"TXINT ":"", 4239232Sache (bsr & RC_BSR_MOINT)?"MOINT":""); 4248471Sache#endif 4259232Sache if (bsr & RC_BSR_TOUT) { 426105806Sjhb device_printf(sc->sc_dev, 427105806Sjhb "hardware failure, reset board\n"); 428105806Sjhb rcout(sc, RC_CTOUT, 0); 429105806Sjhb rc_reinit(sc); 4309232Sache return; 4318471Sache } 4329232Sache if (bsr & RC_BSR_RXINT) { 433105806Sjhb iack = rcin(sc, RC_PILR_RX); 4349232Sache good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); 4359232Sache if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { 436105806Sjhb device_printf(sc->sc_dev, 437105806Sjhb "fake rxint: %02x\n", iack); 4389232Sache goto more_intrs; 4399232Sache } 440105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 441105806Sjhb rc = &sc->sc_channels[chan]; 442105806Sjhb t_state = rc->rc_tp.t_state; 4439232Sache /* Do RTS flow control stuff */ 4449232Sache if ( (rc->rc_flags & RC_RTSFLOW) 4459232Sache || !(t_state & TS_ISOPEN) 4469232Sache ) { 4479232Sache if ( ( !(t_state & TS_ISOPEN) 4489232Sache || (t_state & TS_TBLOCK) 4499232Sache ) 4509232Sache && (rc->rc_msvr & MSVR_RTS) 4519232Sache ) 452105806Sjhb rcout(sc, CD180_MSVR, 4539232Sache rc->rc_msvr &= ~MSVR_RTS); 4549232Sache else if (!(rc->rc_msvr & MSVR_RTS)) 455105806Sjhb rcout(sc, CD180_MSVR, 4569232Sache rc->rc_msvr |= MSVR_RTS); 4579232Sache } 458105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 4599232Sache resid = 0; 4608471Sache 4619232Sache if (t_state & TS_ISOPEN) { 4629232Sache /* check for input buffer overflow */ 4639232Sache if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { 4649232Sache resid = ucnt; 4659232Sache ucnt = rc->rc_bufend - rc->rc_iptr; 4669232Sache resid -= ucnt; 4679232Sache if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { 4689232Sache rc->rc_flags |= RC_WAS_BUFOVFL; 469105806Sjhb sc->sc_scheduled_event++; 4709232Sache } 4718471Sache } 4729232Sache optr = rc->rc_iptr; 4739232Sache /* check foor good data */ 4749232Sache if (good_data) { 4759232Sache while (ucnt-- > 0) { 476105806Sjhb val = rcin(sc, CD180_RDR); 4779232Sache optr[0] = val; 4789232Sache optr[INPUT_FLAGS_SHIFT] = 0; 4799232Sache optr++; 480105806Sjhb sc->sc_scheduled_event++; 481131134Sphk if (val != 0 && val == rc->rc_tp.t_hotchar) 482105806Sjhb swi_sched(sc->sc_swicookie, 0); 4838471Sache } 4849232Sache } else { 4859232Sache /* Store also status data */ 4869232Sache while (ucnt-- > 0) { 487105806Sjhb iack = rcin(sc, CD180_RCSR); 4889232Sache if (iack & RCSR_Timeout) 4899232Sache break; 4909232Sache if ( (iack & RCSR_OE) 4919232Sache && !(rc->rc_flags & RC_WAS_SILOVFL)) { 4929232Sache rc->rc_flags |= RC_WAS_SILOVFL; 493105806Sjhb sc->sc_scheduled_event++; 4949232Sache } 495105806Sjhb val = rcin(sc, CD180_RDR); 4969232Sache /* 4979232Sache Don't store PE if IGNPAR and BREAK if IGNBRK, 4989232Sache this hack allows "raw" tty optimization 4999232Sache works even if IGN* is set. 5009232Sache */ 5019232Sache if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) 50246704Speter || ((!(iack & (RCSR_PE|RCSR_FE)) 503105806Sjhb || !(rc->rc_tp.t_iflag & IGNPAR)) 5049232Sache && (!(iack & RCSR_Break) 505105806Sjhb || !(rc->rc_tp.t_iflag & IGNBRK)))) { 5069232Sache if ( (iack & (RCSR_PE|RCSR_FE)) 5079232Sache && (t_state & TS_CAN_BYPASS_L_RINT) 5089232Sache && ((iack & RCSR_FE) 50946704Speter || ((iack & RCSR_PE) 510105806Sjhb && (rc->rc_tp.t_iflag & INPCK)))) 5119232Sache val = 0; 512131134Sphk else if (val != 0 && val == rc->rc_tp.t_hotchar) 513105806Sjhb swi_sched(sc->sc_swicookie, 0); 5149232Sache optr[0] = val; 5159232Sache optr[INPUT_FLAGS_SHIFT] = iack; 5169232Sache optr++; 517105806Sjhb sc->sc_scheduled_event++; 5189232Sache } 5199232Sache } 5208471Sache } 5219232Sache rc->rc_iptr = optr; 5229232Sache rc->rc_flags |= RC_DORXFER; 5239232Sache } else 5249232Sache resid = ucnt; 5259232Sache /* Clear FIFO if necessary */ 5269232Sache while (resid-- > 0) { 5279232Sache if (!good_data) 528105806Sjhb iack = rcin(sc, CD180_RCSR); 5299232Sache else 5309232Sache iack = 0; 5319232Sache if (iack & RCSR_Timeout) 5329232Sache break; 533105806Sjhb (void) rcin(sc, CD180_RDR); 5348471Sache } 5359232Sache goto more_intrs; 5368471Sache } 5379232Sache if (bsr & RC_BSR_MOINT) { 538105806Sjhb iack = rcin(sc, RC_PILR_MODEM); 5399232Sache if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { 540105806Sjhb device_printf(sc->sc_dev, "fake moint: %02x\n", 541105806Sjhb iack); 5429232Sache goto more_intrs; 5439232Sache } 544105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 545105806Sjhb rc = &sc->sc_channels[chan]; 546105806Sjhb iack = rcin(sc, CD180_MCR); 547105806Sjhb rc->rc_msvr = rcin(sc, CD180_MSVR); 548105806Sjhb rcout(sc, CD180_MCR, 0); 5498471Sache#ifdef RCDEBUG 5509232Sache printrcflags(rc, "moint"); 5518471Sache#endif 5529232Sache if (rc->rc_flags & RC_CTSFLOW) { 5539232Sache if (rc->rc_msvr & MSVR_CTS) 5549232Sache rc->rc_flags |= RC_SEND_RDY; 5559232Sache else 5569232Sache rc->rc_flags &= ~RC_SEND_RDY; 5579232Sache } else 5588471Sache rc->rc_flags |= RC_SEND_RDY; 5599232Sache if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { 560105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 5619232Sache rc->rc_flags |= RC_MODCHG; 562105806Sjhb swi_sched(sc->sc_swicookie, 0); 5639232Sache } 5649232Sache goto more_intrs; 5658471Sache } 5669232Sache if (bsr & RC_BSR_TXINT) { 567105806Sjhb iack = rcin(sc, RC_PILR_TX); 5689232Sache if (iack != (GIVR_IT_TDI | RC_FAKEID)) { 569105806Sjhb device_printf(sc->sc_dev, "fake txint: %02x\n", 570105806Sjhb iack); 5719232Sache goto more_intrs; 5729232Sache } 573105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 574105806Sjhb rc = &sc->sc_channels[chan]; 5759232Sache if ( (rc->rc_flags & RC_OSUSP) 5769232Sache || !(rc->rc_flags & RC_SEND_RDY) 5779232Sache ) 5789232Sache goto more_intrs; 5799232Sache /* Handle breaks and other stuff */ 5809232Sache if (rc->rc_pendcmd) { 581105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 |= COR2_ETC); 582105806Sjhb rcout(sc, CD180_TDR, CD180_C_ESC); 583105806Sjhb rcout(sc, CD180_TDR, rc->rc_pendcmd); 584105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); 5859232Sache rc->rc_pendcmd = 0; 5869232Sache goto more_intrs; 5879232Sache } 5889232Sache optr = rc->rc_optr; 5899232Sache resid = rc->rc_obufend - optr; 5909232Sache if (resid > CD180_NFIFO) 5919232Sache resid = CD180_NFIFO; 5929232Sache while (resid-- > 0) 593105806Sjhb rcout(sc, CD180_TDR, *optr++); 5949232Sache rc->rc_optr = optr; 5958471Sache 5969232Sache /* output completed? */ 5979232Sache if (optr >= rc->rc_obufend) { 598105806Sjhb rcout(sc, CD180_IER, rc->rc_ier &= ~IER_TxRdy); 5998471Sache#ifdef RCDEBUG 600105806Sjhb device_printf(sc->sc_dev, 601105806Sjhb "channel %d: output completed\n", 602105806Sjhb rc->rc_chan); 6038471Sache#endif 6049232Sache if (!(rc->rc_flags & RC_DOXXFER)) { 605105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 6069232Sache rc->rc_flags |= RC_DOXXFER; 607105806Sjhb swi_sched(sc->sc_swicookie, 0); 6089232Sache } 6099232Sache } 6108471Sache } 6119232Sache more_intrs: 612105806Sjhb rcout(sc, CD180_EOIR, 0); /* end of interrupt */ 613105806Sjhb rcout(sc, RC_CTOUT, 0); 614105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 6158471Sache } 6168471Sache} 6178471Sache 6188471Sache/* Feed characters to output buffer */ 619105806Sjhbstatic void 620105806Sjhbrc_start(struct tty *tp) 6218471Sache{ 622105806Sjhb struct rc_softc *sc; 623105806Sjhb struct rc_chans *rc; 624105806Sjhb int s; 6258471Sache 626105806Sjhb rc = TTY_TO_RC(tp); 6278471Sache if (rc->rc_flags & RC_OSBUSY) 6288471Sache return; 629105806Sjhb sc = rc->rc_rcb; 6308471Sache s = spltty(); 6318471Sache rc->rc_flags |= RC_OSBUSY; 632106653Sjhb critical_enter(); 6338471Sache if (tp->t_state & TS_TTSTOP) 6348471Sache rc->rc_flags |= RC_OSUSP; 6358471Sache else 6368471Sache rc->rc_flags &= ~RC_OSUSP; 6378471Sache /* Do RTS flow control stuff */ 6389232Sache if ( (rc->rc_flags & RC_RTSFLOW) 6399232Sache && (tp->t_state & TS_TBLOCK) 6409232Sache && (rc->rc_msvr & MSVR_RTS) 6419232Sache ) { 642105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 643105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); 6449232Sache } else if (!(rc->rc_msvr & MSVR_RTS)) { 645105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 646105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr |= MSVR_RTS); 6478471Sache } 648106653Sjhb critical_exit(); 6498471Sache if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 6508471Sache goto out; 6518471Sache#ifdef RCDEBUG 6528471Sache printrcflags(rc, "rcstart"); 6538471Sache#endif 6549626Sbde ttwwakeup(tp); 6558471Sache#ifdef RCDEBUG 6569232Sache printf("rcstart: outq = %d obuf = %d\n", 6578471Sache tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); 6588471Sache#endif 6599232Sache if (tp->t_state & TS_BUSY) 660105806Sjhb goto out; /* output still in progress ... */ 6618471Sache 6628471Sache if (tp->t_outq.c_cc > 0) { 6638471Sache u_int ocnt; 6648471Sache 6658471Sache tp->t_state |= TS_BUSY; 6668471Sache ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); 667106653Sjhb critical_enter(); 6688471Sache rc->rc_optr = rc->rc_obuf; 6699232Sache rc->rc_obufend = rc->rc_optr + ocnt; 670106653Sjhb critical_exit(); 6719232Sache if (!(rc->rc_ier & IER_TxRdy)) { 6728471Sache#ifdef RCDEBUG 673105806Sjhb device_printf(sc->sc_dev, 674105806Sjhb "channel %d: rcstart enable txint\n", rc->rc_chan); 6758471Sache#endif 676105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 677105806Sjhb rcout(sc, CD180_IER, rc->rc_ier |= IER_TxRdy); 6788471Sache } 6798471Sache } 6808471Sacheout: 6818471Sache rc->rc_flags &= ~RC_OSBUSY; 6828471Sache (void) splx(s); 6838471Sache} 6848471Sache 6858471Sache/* Handle delayed events. */ 686105806Sjhbvoid 687105806Sjhbrc_pollcard(void *arg) 6888471Sache{ 689105806Sjhb struct rc_softc *sc; 690105806Sjhb struct rc_chans *rc; 691105806Sjhb struct tty *tp; 692105806Sjhb u_char *tptr, *eptr; 693105806Sjhb int chan, icnt; 6948471Sache 695105806Sjhb sc = (struct rc_softc *)arg; 696105806Sjhb if (sc->sc_scheduled_event == 0) 6978471Sache return; 698105806Sjhb do { 699105806Sjhb rc = sc->sc_channels; 7008471Sache for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { 701105806Sjhb tp = &rc->rc_tp; 7028471Sache#ifdef RCDEBUG 7038471Sache if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| 7048471Sache RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) 7058471Sache printrcflags(rc, "rcevent"); 7068471Sache#endif 7078471Sache if (rc->rc_flags & RC_WAS_BUFOVFL) { 708106653Sjhb critical_enter(); 7098471Sache rc->rc_flags &= ~RC_WAS_BUFOVFL; 710105806Sjhb sc->sc_scheduled_event--; 711106653Sjhb critical_exit(); 712105806Sjhb device_printf(sc->sc_dev, 713105806Sjhb "channel %d: interrupt-level buffer overflow\n", 714105806Sjhb chan); 7158471Sache } 7168471Sache if (rc->rc_flags & RC_WAS_SILOVFL) { 717106653Sjhb critical_enter(); 7188471Sache rc->rc_flags &= ~RC_WAS_SILOVFL; 719105806Sjhb sc->sc_scheduled_event--; 720106653Sjhb critical_exit(); 721105806Sjhb device_printf(sc->sc_dev, 722105806Sjhb "channel %d: silo overflow\n", chan); 7238471Sache } 7248471Sache if (rc->rc_flags & RC_MODCHG) { 725106653Sjhb critical_enter(); 7268471Sache rc->rc_flags &= ~RC_MODCHG; 727105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 728106653Sjhb critical_exit(); 729130077Sphk ttyld_modem(tp, !!(rc->rc_msvr & MSVR_CD)); 7308471Sache } 7318471Sache if (rc->rc_flags & RC_DORXFER) { 732106653Sjhb critical_enter(); 7338471Sache rc->rc_flags &= ~RC_DORXFER; 7348471Sache eptr = rc->rc_iptr; 7358471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) 7368471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7378471Sache else 7388471Sache tptr = rc->rc_ibuf; 7398471Sache icnt = eptr - tptr; 7408471Sache if (icnt > 0) { 7418471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 7428471Sache rc->rc_iptr = rc->rc_ibuf; 7438471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 7448471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 7458471Sache } else { 7468471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7478471Sache rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; 7488471Sache rc->rc_hiwat = 7498471Sache &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; 7508471Sache } 7519232Sache if ( (rc->rc_flags & RC_RTSFLOW) 7529232Sache && (tp->t_state & TS_ISOPEN) 7539232Sache && !(tp->t_state & TS_TBLOCK) 7548471Sache && !(rc->rc_msvr & MSVR_RTS) 7559232Sache ) { 756105806Sjhb rcout(sc, CD180_CAR, chan); 757105806Sjhb rcout(sc, CD180_MSVR, 7588471Sache rc->rc_msvr |= MSVR_RTS); 7598471Sache } 760105806Sjhb sc->sc_scheduled_event -= icnt; 7618471Sache } 762106653Sjhb critical_exit(); 7638471Sache 7649232Sache if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) 7658471Sache goto done1; 7668471Sache 7678471Sache if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) 7688471Sache && !(tp->t_state & TS_LOCAL)) { 7699822Sbde if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER 7709822Sbde && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) 7719822Sbde && !(tp->t_state & TS_TBLOCK)) 7729822Sbde ttyblock(tp); 7738471Sache tk_nin += icnt; 7748471Sache tk_rawcc += icnt; 7758471Sache tp->t_rawcc += icnt; 7768471Sache if (b_to_q(tptr, icnt, &tp->t_rawq)) 777105806Sjhb device_printf(sc->sc_dev, 778105806Sjhb "channel %d: tty-level buffer overflow\n", 779105806Sjhb chan); 7808471Sache ttwakeup(tp); 7818471Sache if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) 7828471Sache || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { 7838471Sache tp->t_state &= ~TS_TTSTOP; 7848471Sache tp->t_lflag &= ~FLUSHO; 7859754Sbde rc_start(tp); 7868471Sache } 7878471Sache } else { 7888471Sache for (; tptr < eptr; tptr++) 789130095Sphk ttyld_rint(tp, 7908471Sache (tptr[0] | 791130095Sphk rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF])); 7928471Sache } 79327125Sbdedone1: ; 7948471Sache } 7958471Sache if (rc->rc_flags & RC_DOXXFER) { 796106653Sjhb critical_enter(); 797105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 7989232Sache rc->rc_flags &= ~RC_DOXXFER; 799105806Sjhb rc->rc_tp.t_state &= ~TS_BUSY; 800106653Sjhb critical_exit(); 801130077Sphk ttyld_start(tp); 8028471Sache } 803111564Sjhb if (sc->sc_scheduled_event == 0) 804111564Sjhb break; 8058471Sache } 806111564Sjhb } while (sc->sc_scheduled_event >= LOTS_OF_EVENTS); 8078471Sache} 8088471Sache 809105806Sjhbstatic void 810105806Sjhbrc_stop(struct tty *tp, int rw) 8118471Sache{ 812105806Sjhb struct rc_softc *sc; 813105806Sjhb struct rc_chans *rc; 8148471Sache u_char *tptr, *eptr; 8158471Sache 816105806Sjhb rc = TTY_TO_RC(tp); 817105806Sjhb sc = rc->rc_rcb; 8188471Sache#ifdef RCDEBUG 819105806Sjhb device_printf(sc->sc_dev, "channel %d: rc_stop %s%s\n", 820105806Sjhb rc->rc_chan, (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); 8218471Sache#endif 8228471Sache if (rw & FWRITE) 8238471Sache rc_discard_output(rc); 824106653Sjhb critical_enter(); 8258471Sache if (rw & FREAD) { 8269232Sache rc->rc_flags &= ~RC_DORXFER; 8278471Sache eptr = rc->rc_iptr; 8288471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 8298471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 8308471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 8318471Sache } else { 8328471Sache tptr = rc->rc_ibuf; 8338471Sache rc->rc_iptr = rc->rc_ibuf; 8348471Sache } 835105806Sjhb sc->sc_scheduled_event -= eptr - tptr; 8368471Sache } 8378471Sache if (tp->t_state & TS_TTSTOP) 8388471Sache rc->rc_flags |= RC_OSUSP; 8398471Sache else 8408471Sache rc->rc_flags &= ~RC_OSUSP; 841106653Sjhb critical_exit(); 8428471Sache} 8438471Sache 844105806Sjhbstatic int 845130585Sphkrcopen(struct cdev *dev, int flag, int mode, d_thread_t *td) 8468471Sache{ 847105806Sjhb struct rc_softc *sc; 848105806Sjhb struct rc_chans *rc; 849105806Sjhb struct tty *tp; 850105806Sjhb int s, error = 0; 8518471Sache 852105806Sjhb rc = DEV_TO_RC(dev); 853105806Sjhb sc = rc->rc_rcb; 854105806Sjhb tp = &rc->rc_tp; 855105806Sjhb if (sc->sc_opencount < 0) 856105806Sjhb return (ENXIO); 857105806Sjhb sc->sc_opencount++; 8588471Sache#ifdef RCDEBUG 859105806Sjhb device_printf(sc->sc_dev, "channel %d: rcopen: dev %p\n", 860105806Sjhb rc->rc_chan, dev); 8618471Sache#endif 8628471Sache s = spltty(); 8638471Sache 8648471Sacheagain: 865131981Sphk error = ttydtrwaitsleep(tp); 866131981Sphk if (error != 0) 867131981Sphk goto out; 8688471Sache if (tp->t_state & TS_ISOPEN) { 8698471Sache if (CALLOUT(dev)) { 8708471Sache if (!(rc->rc_flags & RC_ACTOUT)) { 8718471Sache error = EBUSY; 8728471Sache goto out; 8738471Sache } 8748471Sache } else { 8758471Sache if (rc->rc_flags & RC_ACTOUT) { 8768471Sache if (flag & O_NONBLOCK) { 8778471Sache error = EBUSY; 8788471Sache goto out; 8798471Sache } 88046571Speter error = tsleep(&rc->rc_rcb, 88146571Speter TTIPRI|PCATCH, "rcbi", 0); 88246571Speter if (error) 8838471Sache goto out; 8848471Sache goto again; 8858471Sache } 8868471Sache } 88743425Sphk if (tp->t_state & TS_XCLUDE && 88893593Sjhb suser(td)) { 8898471Sache error = EBUSY; 8908471Sache goto out; 8918471Sache } 8928471Sache } else { 8938471Sache tp->t_oproc = rc_start; 8948471Sache tp->t_param = rc_param; 895131096Sphk tp->t_modem = rc_modem; 896131096Sphk tp->t_break = rc_break; 89751654Sphk tp->t_stop = rc_stop; 8988471Sache tp->t_dev = dev; 8998471Sache 9008471Sache if (CALLOUT(dev)) 9018471Sache tp->t_cflag |= CLOCAL; 9028471Sache else 9038471Sache tp->t_cflag &= ~CLOCAL; 9048471Sache 9058471Sache error = rc_param(tp, &tp->t_termios); 9068471Sache if (error) 9078471Sache goto out; 908131096Sphk (void) rc_modem(tp, SER_DTR | SER_RTS, 0); 9098471Sache 9108471Sache if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev)) 911130077Sphk ttyld_modem(tp, 1); 9128471Sache } 9138471Sache if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev) 9148471Sache && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 9158471Sache rc->rc_dcdwaits++; 9169639Sbde error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0); 9178471Sache rc->rc_dcdwaits--; 9188471Sache if (error != 0) 9198471Sache goto out; 9208471Sache goto again; 9218471Sache } 922130077Sphk error = ttyld_open(tp, dev); 923131134Sphk ttyldoptim(tp); 9248471Sache if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev)) 9258471Sache rc->rc_flags |= RC_ACTOUT; 9268471Sacheout: 9278471Sache (void) splx(s); 9288471Sache 9298471Sache if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN)) 9308471Sache rc_hardclose(rc); 9318471Sache 9328471Sache return error; 9338471Sache} 9348471Sache 935105806Sjhbstatic int 936130585Sphkrcclose(struct cdev *dev, int flag, int mode, d_thread_t *td) 9378471Sache{ 938105806Sjhb struct rc_softc *sc; 939105806Sjhb struct rc_chans *rc; 940105806Sjhb struct tty *tp; 941105806Sjhb int s; 9428471Sache 943105806Sjhb rc = DEV_TO_RC(dev); 944105806Sjhb sc = rc->rc_rcb; 945105806Sjhb tp = &rc->rc_tp; 9469232Sache#ifdef RCDEBUG 947105806Sjhb device_printf(sc->sc_dev, "channel %d: rcclose dev %p\n", 948105806Sjhb rc->rc_chan, dev); 9499232Sache#endif 9508471Sache s = spltty(); 951130077Sphk ttyld_close(tp, flag); 952131134Sphk ttyldoptim(tp); 9538471Sache rc_hardclose(rc); 9548471Sache ttyclose(tp); 9558471Sache splx(s); 956105806Sjhb KASSERT(sc->sc_opencount > 0, ("rcclose: non-positive open count")); 957105806Sjhb sc->sc_opencount--; 9588471Sache return 0; 9598471Sache} 9608471Sache 961105806Sjhbstatic void 962105806Sjhbrc_hardclose(struct rc_chans *rc) 9638471Sache{ 964105806Sjhb struct rc_softc *sc; 965105806Sjhb struct tty *tp; 966105806Sjhb int s; 9678471Sache 968105806Sjhb tp = &rc->rc_tp; 969105806Sjhb sc = rc->rc_rcb; 9708471Sache s = spltty(); 971105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 9728471Sache 9739232Sache /* Disable rx/tx intrs */ 974105806Sjhb rcout(sc, CD180_IER, rc->rc_ier = 0); 9759232Sache if ( (tp->t_cflag & HUPCL) 97646704Speter || (!(rc->rc_flags & RC_ACTOUT) 9778471Sache && !(rc->rc_msvr & MSVR_CD) 97846704Speter && !(tp->t_cflag & CLOCAL)) 9799232Sache || !(tp->t_state & TS_ISOPEN) 9809232Sache ) { 981105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 982105806Sjhb WAITFORCCR(sc, rc->rc_chan); 983131096Sphk (void) rc_modem(tp, SER_RTS, 0); 984131981Sphk ttydtrwaitstart(tp); 9858471Sache } 9868471Sache rc->rc_flags &= ~RC_ACTOUT; 987111748Sdes wakeup( &rc->rc_rcb); /* wake bi */ 9889639Sbde wakeup(TSA_CARR_ON(tp)); 9898471Sache (void) splx(s); 9908471Sache} 9918471Sache 9928471Sache/* Reset the bastard */ 993105806Sjhbstatic void 994118607Sjhbrc_hwreset(struct rc_softc *sc, u_int chipid) 9958471Sache{ 996105806Sjhb CCRCMD(sc, -1, CCR_HWRESET); /* Hardware reset */ 9978471Sache DELAY(20000); 998105806Sjhb WAITFORCCR(sc, -1); 9999232Sache 1000105806Sjhb rcout(sc, RC_CTOUT, 0); /* Clear timeout */ 1001105806Sjhb rcout(sc, CD180_GIVR, chipid); 1002105806Sjhb rcout(sc, CD180_GICR, 0); 10038471Sache 10048471Sache /* Set Prescaler Registers (1 msec) */ 1005105806Sjhb rcout(sc, CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); 1006105806Sjhb rcout(sc, CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); 10078471Sache 10088471Sache /* Initialize Priority Interrupt Level Registers */ 1009105806Sjhb rcout(sc, CD180_PILR1, RC_PILR_MODEM); 1010105806Sjhb rcout(sc, CD180_PILR2, RC_PILR_TX); 1011105806Sjhb rcout(sc, CD180_PILR3, RC_PILR_RX); 10128471Sache 10138471Sache /* Reset DTR */ 1014105806Sjhb rcout(sc, RC_DTREG, ~0); 10158471Sache} 10168471Sache 10178471Sache/* Set channel parameters */ 1018105806Sjhbstatic int 1019105806Sjhbrc_param(struct tty *tp, struct termios *ts) 10208471Sache{ 1021105806Sjhb struct rc_softc *sc; 1022105806Sjhb struct rc_chans *rc; 1023105806Sjhb int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; 10248471Sache 10259855Sache if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 10269855Sache || ts->c_ispeed < 0 || ts->c_ispeed > 76800 10279855Sache ) 10289855Sache return (EINVAL); 10298471Sache if (ts->c_ispeed == 0) 10308471Sache ts->c_ispeed = ts->c_ospeed; 10319855Sache odivs = RC_BRD(ts->c_ospeed); 10329855Sache idivs = RC_BRD(ts->c_ispeed); 10338471Sache 1034105806Sjhb rc = TTY_TO_RC(tp); 1035105806Sjhb sc = rc->rc_rcb; 10368471Sache s = spltty(); 10378471Sache 10389232Sache /* Select channel */ 1039105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 10409232Sache 10418471Sache /* If speed == 0, hangup line */ 10429232Sache if (ts->c_ospeed == 0) { 1043105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 1044105806Sjhb WAITFORCCR(sc, rc->rc_chan); 1045131096Sphk (void) rc_modem(tp, 0, SER_DTR); 10469232Sache } 10478471Sache 10488471Sache tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 10498471Sache cflag = ts->c_cflag; 10508471Sache iflag = ts->c_iflag; 10518471Sache lflag = ts->c_lflag; 10528471Sache 10538471Sache if (idivs > 0) { 1054105806Sjhb rcout(sc, CD180_RBPRL, idivs & 0xFF); 1055105806Sjhb rcout(sc, CD180_RBPRH, idivs >> 8); 10568471Sache } 10578471Sache if (odivs > 0) { 1058105806Sjhb rcout(sc, CD180_TBPRL, odivs & 0xFF); 1059105806Sjhb rcout(sc, CD180_TBPRH, odivs >> 8); 10608471Sache } 10618471Sache 10628471Sache /* set timeout value */ 10639232Sache if (ts->c_ispeed > 0) { 10649232Sache int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; 10658471Sache 10669232Sache if ( !(lflag & ICANON) 10679232Sache && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 10689232Sache && ts->c_cc[VTIME] * 10 > itm) 10699232Sache itm = ts->c_cc[VTIME] * 10; 10709232Sache 1071105806Sjhb rcout(sc, CD180_RTPR, itm <= 255 ? itm : 255); 10729232Sache } 10739232Sache 10748471Sache switch (cflag & CSIZE) { 10758471Sache case CS5: val = COR1_5BITS; break; 10768471Sache case CS6: val = COR1_6BITS; break; 10778471Sache case CS7: val = COR1_7BITS; break; 10788471Sache default: 10798471Sache case CS8: val = COR1_8BITS; break; 10808471Sache } 10818471Sache if (cflag & PARENB) { 10828471Sache val |= COR1_NORMPAR; 10838471Sache if (cflag & PARODD) 10848471Sache val |= COR1_ODDP; 10859232Sache if (!(cflag & INPCK)) 10869232Sache val |= COR1_Ignore; 10878471Sache } else 10889232Sache val |= COR1_Ignore; 10898471Sache if (cflag & CSTOPB) 10908471Sache val |= COR1_2SB; 1091105806Sjhb rcout(sc, CD180_COR1, val); 10928471Sache 10938471Sache /* Set FIFO threshold */ 10949232Sache val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; 10959232Sache inpflow = 0; 10969232Sache if ( (iflag & IXOFF) 10979232Sache && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE 10989232Sache && ( ts->c_cc[VSTART] != _POSIX_VDISABLE 10999232Sache || (iflag & IXANY) 11009232Sache ) 11019232Sache ) 11029232Sache ) { 11039232Sache inpflow = 1; 11049232Sache val |= COR3_SCDE|COR3_FCT; 11059232Sache } 1106105806Sjhb rcout(sc, CD180_COR3, val); 11078471Sache 11088471Sache /* Initialize on-chip automatic flow control */ 11098471Sache val = 0; 11109232Sache rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); 11118471Sache if (cflag & CCTS_OFLOW) { 11128471Sache rc->rc_flags |= RC_CTSFLOW; 11139232Sache val |= COR2_CtsAE; 11149232Sache } else 11159232Sache rc->rc_flags |= RC_SEND_RDY; 11169232Sache if (tp->t_state & TS_TTSTOP) 11179232Sache rc->rc_flags |= RC_OSUSP; 11188471Sache else 11199232Sache rc->rc_flags &= ~RC_OSUSP; 11208471Sache if (cflag & CRTS_IFLOW) 11218471Sache rc->rc_flags |= RC_RTSFLOW; 11229232Sache else 11239232Sache rc->rc_flags &= ~RC_RTSFLOW; 11248471Sache 11259232Sache if (inpflow) { 11269232Sache if (ts->c_cc[VSTART] != _POSIX_VDISABLE) 1127105806Sjhb rcout(sc, CD180_SCHR1, ts->c_cc[VSTART]); 1128105806Sjhb rcout(sc, CD180_SCHR2, ts->c_cc[VSTOP]); 11299232Sache val |= COR2_TxIBE; 11309232Sache if (iflag & IXANY) 11319232Sache val |= COR2_IXM; 11328471Sache } 11338471Sache 1134105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 = val); 11358471Sache 1136105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 11379232Sache 1138131134Sphk ttyldoptim(tp); 11398471Sache 11408471Sache /* modem ctl */ 11419232Sache val = cflag & CLOCAL ? 0 : MCOR1_CDzd; 11429232Sache if (cflag & CCTS_OFLOW) 11439232Sache val |= MCOR1_CTSzd; 1144105806Sjhb rcout(sc, CD180_MCOR1, val); 11458471Sache 11469232Sache val = cflag & CLOCAL ? 0 : MCOR2_CDod; 11479232Sache if (cflag & CCTS_OFLOW) 11489232Sache val |= MCOR2_CTSod; 1149105806Sjhb rcout(sc, CD180_MCOR2, val); 11509232Sache 11518471Sache /* enable i/o and interrupts */ 1152105806Sjhb CCRCMD(sc, rc->rc_chan, 11539232Sache CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); 1154105806Sjhb WAITFORCCR(sc, rc->rc_chan); 11558471Sache 11569232Sache rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; 11579232Sache if (cflag & CCTS_OFLOW) 11589232Sache rc->rc_ier |= IER_CTS; 11599232Sache if (cflag & CREAD) 11609232Sache rc->rc_ier |= IER_RxData; 11619232Sache if (tp->t_state & TS_BUSY) 11629232Sache rc->rc_ier |= IER_TxRdy; 11639232Sache if (ts->c_ospeed != 0) 1164131096Sphk rc_modem(tp, SER_DTR, 0); 11659232Sache if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) 11669232Sache rc->rc_flags |= RC_SEND_RDY; 1167105806Sjhb rcout(sc, CD180_IER, rc->rc_ier); 11688471Sache (void) splx(s); 11698471Sache return 0; 11708471Sache} 11718471Sache 11729232Sache/* Re-initialize board after bogus interrupts */ 1173105806Sjhbstatic void 1174105806Sjhbrc_reinit(struct rc_softc *sc) 11759232Sache{ 1176105806Sjhb struct rc_chans *rc; 1177105806Sjhb int i; 11789232Sache 1179105806Sjhb rc_hwreset(sc, RC_FAKEID); 1180105806Sjhb rc = sc->sc_channels; 1181105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) 1182105806Sjhb (void) rc_param(&rc->rc_tp, &rc->rc_tp.t_termios); 11839232Sache} 11849232Sache 11858471Sache/* Modem control routines */ 11868471Sache 1187105806Sjhbstatic int 1188131096Sphkrc_modem(struct tty *tp, int biton, int bitoff) 11898471Sache{ 1190131096Sphk struct rc_chans *rc; 1191105806Sjhb struct rc_softc *sc; 1192105806Sjhb u_char *dtr; 1193105806Sjhb u_char msvr; 11948471Sache 1195131096Sphk rc = DEV_TO_RC(tp->t_dev); 1196105806Sjhb sc = rc->rc_rcb; 1197105806Sjhb dtr = &sc->sc_dtr; 1198105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 11998471Sache 1200131096Sphk if (biton == 0 && bitoff == 0) { 1201105806Sjhb msvr = rc->rc_msvr = rcin(sc, CD180_MSVR); 12028471Sache 12038471Sache if (msvr & MSVR_RTS) 1204131096Sphk biton |= SER_RTS; 12058471Sache if (msvr & MSVR_CTS) 1206131096Sphk biton |= SER_CTS; 12078471Sache if (msvr & MSVR_DSR) 1208131096Sphk biton |= SER_DSR; 12098471Sache if (msvr & MSVR_DTR) 1210131096Sphk biton |= SER_DTR; 12119232Sache if (msvr & MSVR_CD) 1212131096Sphk biton |= SER_DCD; 1213105806Sjhb if (~rcin(sc, RC_RIREG) & (1 << rc->rc_chan)) 1214131096Sphk biton |= SER_RI; 1215131096Sphk return biton; 12168471Sache } 1217131096Sphk if (biton & SER_DTR) 1218131096Sphk rcout(sc, RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); 1219131096Sphk if (bitoff & SER_DTR) 1220131096Sphk rcout(sc, RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); 1221131096Sphk msvr = rcin(sc, CD180_MSVR); 1222131096Sphk if (biton & SER_DTR) 1223131096Sphk msvr |= MSVR_DTR; 1224131096Sphk if (bitoff & SER_DTR) 1225131096Sphk msvr &= ~MSVR_DTR; 1226131096Sphk if (biton & SER_RTS) 1227131096Sphk msvr |= MSVR_RTS; 1228131096Sphk if (bitoff & SER_RTS) 1229131096Sphk msvr &= ~MSVR_RTS; 1230131096Sphk rcout(sc, CD180_MSVR, msvr); 12318471Sache return 0; 12328471Sache} 12338471Sache 1234131373Sphkstatic void 1235131096Sphkrc_break(struct tty *tp, int brk) 1236131096Sphk{ 1237131096Sphk struct rc_chans *rc; 1238131096Sphk 1239131096Sphk rc = DEV_TO_RC(tp->t_dev); 1240131096Sphk 1241131096Sphk if (brk) 1242131096Sphk rc->rc_pendcmd = CD180_C_SBRK; 1243131096Sphk else 1244131096Sphk rc->rc_pendcmd = CD180_C_EBRK; 1245131096Sphk} 1246131096Sphk 1247105806Sjhb#define ERR(s) do { \ 1248105806Sjhb device_printf(sc->sc_dev, "%s", ""); \ 1249105806Sjhb printf s ; \ 1250105806Sjhb printf("\n"); \ 1251105806Sjhb (void) splx(old_level); \ 1252105806Sjhb return 1; \ 1253105806Sjhb} while (0) 1254105806Sjhb 12558471Sache/* Test the board. */ 1256105806Sjhbint 1257105806Sjhbrc_test(struct rc_softc *sc) 12588471Sache{ 125916322Sgpalmer int chan = 0; 12608471Sache int i = 0, rcnt, old_level; 12618471Sache unsigned int iack, chipid; 12628471Sache unsigned short divs; 12638471Sache static u_char ctest[] = "\377\125\252\045\244\0\377"; 12648471Sache#define CTLEN 8 12658471Sache 12668471Sache struct rtest { 12678471Sache u_char txbuf[CD180_NFIFO]; /* TX buffer */ 12688471Sache u_char rxbuf[CD180_NFIFO]; /* RX buffer */ 12698471Sache int rxptr; /* RX pointer */ 12708471Sache int txptr; /* TX pointer */ 12718471Sache } tchans[CD180_NCHAN]; 12728471Sache 12739232Sache old_level = spltty(); 12748471Sache 12758471Sache chipid = RC_FAKEID; 12768471Sache 12778471Sache /* First, reset board to inital state */ 1278105806Sjhb rc_hwreset(sc, chipid); 12798471Sache 12809232Sache divs = RC_BRD(19200); 12819232Sache 12828471Sache /* Initialize channels */ 12838471Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 12848471Sache 12858471Sache /* Select and reset channel */ 1286105806Sjhb rcout(sc, CD180_CAR, chan); 1287105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 1288105806Sjhb WAITFORCCR(sc, chan); 12898471Sache 12908471Sache /* Set speed */ 1291105806Sjhb rcout(sc, CD180_RBPRL, divs & 0xFF); 1292105806Sjhb rcout(sc, CD180_RBPRH, divs >> 8); 1293105806Sjhb rcout(sc, CD180_TBPRL, divs & 0xFF); 1294105806Sjhb rcout(sc, CD180_TBPRH, divs >> 8); 12958471Sache 12968471Sache /* set timeout value */ 1297105806Sjhb rcout(sc, CD180_RTPR, 0); 12988471Sache 12998471Sache /* Establish local loopback */ 1300105806Sjhb rcout(sc, CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); 1301105806Sjhb rcout(sc, CD180_COR2, COR2_LLM); 1302105806Sjhb rcout(sc, CD180_COR3, CD180_NFIFO); 1303105806Sjhb CCRCMD(sc, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1304105806Sjhb CCRCMD(sc, chan, CCR_RCVREN | CCR_XMTREN); 1305105806Sjhb WAITFORCCR(sc, chan); 1306105806Sjhb rcout(sc, CD180_MSVR, MSVR_RTS); 13078471Sache 13088471Sache /* Fill TXBUF with test data */ 13098471Sache for (i = 0; i < CD180_NFIFO; i++) { 13108471Sache tchans[chan].txbuf[i] = ctest[i]; 13118471Sache tchans[chan].rxbuf[i] = 0; 13128471Sache } 13138471Sache tchans[chan].txptr = tchans[chan].rxptr = 0; 13148471Sache 13158471Sache /* Now, start transmit */ 1316105806Sjhb rcout(sc, CD180_IER, IER_TxMpty|IER_RxData); 13178471Sache } 13188471Sache /* Pseudo-interrupt poll stuff */ 13198471Sache for (rcnt = 10000; rcnt-- > 0; rcnt--) { 1320105806Sjhb i = ~(rcin(sc, RC_BSR)); 13218471Sache if (i & RC_BSR_TOUT) 1322105806Sjhb ERR(("BSR timeout bit set\n")); 13239232Sache else if (i & RC_BSR_TXINT) { 1324105806Sjhb iack = rcin(sc, RC_PILR_TX); 13258471Sache if (iack != (GIVR_IT_TDI | chipid)) 13268471Sache ERR(("Bad TX intr ack (%02x != %02x)\n", 13278471Sache iack, GIVR_IT_TDI | chipid)); 1328105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 13298471Sache /* If no more data to transmit, disable TX intr */ 13308471Sache if (tchans[chan].txptr >= CD180_NFIFO) { 1331105806Sjhb iack = rcin(sc, CD180_IER); 1332105806Sjhb rcout(sc, CD180_IER, iack & ~IER_TxMpty); 13338471Sache } else { 13348471Sache for (iack = tchans[chan].txptr; 13358471Sache iack < CD180_NFIFO; iack++) 1336105806Sjhb rcout(sc, CD180_TDR, 13378471Sache tchans[chan].txbuf[iack]); 13388471Sache tchans[chan].txptr = iack; 13398471Sache } 1340105806Sjhb rcout(sc, CD180_EOIR, 0); 13419232Sache } else if (i & RC_BSR_RXINT) { 13429232Sache u_char ucnt; 13438471Sache 1344105806Sjhb iack = rcin(sc, RC_PILR_RX); 13458471Sache if (iack != (GIVR_IT_RGDI | chipid) && 13468471Sache iack != (GIVR_IT_REI | chipid)) 13478471Sache ERR(("Bad RX intr ack (%02x != %02x)\n", 1348105806Sjhb iack, GIVR_IT_RGDI | chipid)); 1349105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1350105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 13518471Sache while (ucnt-- > 0) { 1352105806Sjhb iack = rcin(sc, CD180_RCSR); 13539232Sache if (iack & RCSR_Timeout) 13548471Sache break; 13558471Sache if (iack & 0xF) 13568471Sache ERR(("Bad char chan %d (RCSR = %02X)\n", 1357105806Sjhb chan, iack)); 13588471Sache if (tchans[chan].rxptr > CD180_NFIFO) 13598471Sache ERR(("Got extra chars chan %d\n", 1360105806Sjhb chan)); 13618471Sache tchans[chan].rxbuf[tchans[chan].rxptr++] = 1362105806Sjhb rcin(sc, CD180_RDR); 13638471Sache } 1364105806Sjhb rcout(sc, CD180_EOIR, 0); 13658471Sache } 1366105806Sjhb rcout(sc, RC_CTOUT, 0); 13678471Sache for (iack = chan = 0; chan < CD180_NCHAN; chan++) 13688471Sache if (tchans[chan].rxptr >= CD180_NFIFO) 13698471Sache iack++; 13708471Sache if (iack == CD180_NCHAN) 13718471Sache break; 13728471Sache } 13739232Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 13749232Sache /* Select and reset channel */ 1375105806Sjhb rcout(sc, CD180_CAR, chan); 1376105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 13779232Sache } 13789232Sache 13798471Sache if (!rcnt) 1380105806Sjhb ERR(("looses characters during local loopback\n")); 13818471Sache /* Now, check data */ 13828471Sache for (chan = 0; chan < CD180_NCHAN; chan++) 13838471Sache for (i = 0; i < CD180_NFIFO; i++) 13848471Sache if (ctest[i] != tchans[chan].rxbuf[i]) 13858471Sache ERR(("data mismatch chan %d ptr %d (%d != %d)\n", 1386105806Sjhb chan, i, ctest[i], tchans[chan].rxbuf[i])); 13878471Sache (void) splx(old_level); 13888471Sache return 0; 13898471Sache} 13908471Sache 13918471Sache#ifdef RCDEBUG 1392105806Sjhbstatic void 1393105806Sjhbprintrcflags(struct rc_chans *rc, char *comment) 13948471Sache{ 1395105806Sjhb struct rc_softc *sc; 13968471Sache u_short f = rc->rc_flags; 13978471Sache 1398105806Sjhb sc = rc->rc_rcb; 13999232Sache printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", 14008471Sache rc->rc_rcb->rcb_unit, rc->rc_chan, comment, 14018471Sache (f & RC_DTR_OFF)?"DTR_OFF " :"", 14029232Sache (f & RC_ACTOUT) ?"ACTOUT " :"", 14039232Sache (f & RC_RTSFLOW)?"RTSFLOW " :"", 14049232Sache (f & RC_CTSFLOW)?"CTSFLOW " :"", 14059232Sache (f & RC_DORXFER)?"DORXFER " :"", 14069232Sache (f & RC_DOXXFER)?"DOXXFER " :"", 14079232Sache (f & RC_MODCHG) ?"MODCHG " :"", 14089232Sache (f & RC_OSUSP) ?"OSUSP " :"", 14099232Sache (f & RC_OSBUSY) ?"OSBUSY " :"", 14109232Sache (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", 14119232Sache (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", 14129232Sache (f & RC_SEND_RDY) ?"SEND_RDY":""); 14139232Sache 1414105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 14159232Sache 14169232Sache printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", 14179232Sache rc->rc_rcb->rcb_unit, rc->rc_chan, 1418105806Sjhb rcin(sc, CD180_MSVR), 1419105806Sjhb rcin(sc, CD180_IER), 1420105806Sjhb rcin(sc, CD180_CCSR)); 14218471Sache} 14228471Sache#endif /* RCDEBUG */ 14238471Sache 14248471Sachestatic void 1425105806Sjhbrc_discard_output(struct rc_chans *rc) 14268471Sache{ 1427106653Sjhb critical_enter(); 14288471Sache if (rc->rc_flags & RC_DOXXFER) { 1429105806Sjhb rc->rc_rcb->sc_scheduled_event -= LOTS_OF_EVENTS; 14308471Sache rc->rc_flags &= ~RC_DOXXFER; 14318471Sache } 14328471Sache rc->rc_optr = rc->rc_obufend; 1433105806Sjhb rc->rc_tp.t_state &= ~TS_BUSY; 1434106653Sjhb critical_exit(); 1435105806Sjhb ttwwakeup(&rc->rc_tp); 14368471Sache} 14378471Sache 14388471Sachestatic void 1439105806Sjhbrc_wait0(struct rc_softc *sc, int chan, int line) 14409232Sache{ 14419232Sache int rcnt; 14429232Sache 1443105806Sjhb for (rcnt = 50; rcnt && rcin(sc, CD180_CCR); rcnt--) 144414441Srgrimes DELAY(30); 14459232Sache if (rcnt == 0) 1446105806Sjhb device_printf(sc->sc_dev, 1447105806Sjhb "channel %d command timeout, rc.c line: %d\n", chan, line); 14489232Sache} 1449105806Sjhb 1450105806Sjhbstatic device_method_t rc_methods[] = { 1451105806Sjhb /* Device interface */ 1452105806Sjhb DEVMETHOD(device_probe, rc_probe), 1453105806Sjhb DEVMETHOD(device_attach, rc_attach), 1454105806Sjhb DEVMETHOD(device_detach, rc_detach), 1455105806Sjhb { 0, 0 } 1456105806Sjhb}; 1457105806Sjhb 1458105806Sjhbstatic driver_t rc_driver = { 1459105806Sjhb "rc", 1460105806Sjhb rc_methods, sizeof(struct rc_softc), 1461105806Sjhb}; 1462105806Sjhb 1463105806SjhbDRIVER_MODULE(rc, isa, rc_driver, rc_devclass, 0, 0); 1464