rc.c revision 130077
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 130077 2004-06-04 16:02:56Z 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> 49105806Sjhb#include <sys/tty.h> 50105806Sjhb#include <machine/bus.h> 51105806Sjhb#include <machine/resource.h> 52105806Sjhb#include <sys/rman.h> 5366824Sbde 54105806Sjhb#include <dev/ic/cd180.h> 55105806Sjhb#include <dev/rc/rcreg.h> 56105806Sjhb#include <isa/isavar.h> 578471Sache 58105806Sjhb#define IOBASE_ADDRS 14 598471Sache 60105806Sjhb#define DEV_TO_RC(dev) (struct rc_chans *)((dev)->si_drv1) 61105806Sjhb#define TTY_TO_RC(tty) DEV_TO_RC((tty)->t_dev) 628471Sache 63105806Sjhb#define rcin(sc, port) RC_IN(sc, port) 64105806Sjhb#define rcout(sc, port, v) RC_OUT(sc, port, v) 658471Sache 66105806Sjhb#define WAITFORCCR(sc, chan) rc_wait0((sc), (chan), __LINE__) 678471Sache 68105806Sjhb#define CCRCMD(sc, chan, cmd) do { \ 69105806Sjhb WAITFORCCR((sc), (chan)); \ 70105806Sjhb rcout((sc), CD180_CCR, (cmd)); \ 71105806Sjhb} while (0) 728471Sache 739232Sache#define RC_IBUFSIZE 256 749232Sache#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) 759232Sache#define RC_OBUFSIZE 512 768471Sache#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) 778471Sache#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) 788471Sache#define LOTS_OF_EVENTS 64 798471Sache 808471Sache#define RC_FAKEID 0x10 818471Sache 82105960Sjhb#define CALLOUT(dev) (((intptr_t)(dev)->si_drv2) != 0) 839232Sache 84105806Sjhb/* Per-channel structure */ 85105806Sjhbstruct rc_chans { 86105806Sjhb struct rc_softc *rc_rcb; /* back ptr */ 87105806Sjhb dev_t rc_dev; /* non-callout device */ 88105806Sjhb dev_t rc_cdev; /* callout device */ 89105806Sjhb u_short rc_flags; /* Misc. flags */ 90105806Sjhb int rc_chan; /* Channel # */ 91105806Sjhb u_char rc_ier; /* intr. enable reg */ 92105806Sjhb u_char rc_msvr; /* modem sig. status */ 93105806Sjhb u_char rc_cor2; /* options reg */ 94105806Sjhb u_char rc_pendcmd; /* special cmd pending */ 95105806Sjhb u_int rc_dtrwait; /* dtr timeout */ 96105806Sjhb u_int rc_dcdwaits; /* how many waits DCD in open */ 97105806Sjhb u_char rc_hotchar; /* end packed optimize */ 98105806Sjhb struct tty rc_tp; /* tty struct */ 99105806Sjhb u_char *rc_iptr; /* Chars input buffer */ 100105806Sjhb u_char *rc_hiwat; /* hi-water mark */ 101105806Sjhb u_char *rc_bufend; /* end of buffer */ 102105806Sjhb u_char *rc_optr; /* ptr in output buf */ 103105806Sjhb u_char *rc_obufend; /* end of output buf */ 104105806Sjhb u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */ 105105806Sjhb u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */ 106105806Sjhb struct callout rc_dtrcallout; 107105806Sjhb}; 1088471Sache 109105806Sjhb/* Per-board structure */ 110105806Sjhbstruct rc_softc { 111105806Sjhb device_t sc_dev; 112105806Sjhb struct resource *sc_irq; 113105806Sjhb struct resource *sc_port[IOBASE_ADDRS]; 114105806Sjhb int sc_irqrid; 115105806Sjhb void *sc_hwicookie; 116105806Sjhb bus_space_tag_t sc_bt; 117105806Sjhb bus_space_handle_t sc_bh; 118105806Sjhb u_int sc_unit; /* unit # */ 119105806Sjhb u_char sc_dtr; /* DTR status */ 120105806Sjhb int sc_opencount; 121105806Sjhb int sc_scheduled_event; 122105806Sjhb void *sc_swicookie; 123105806Sjhb struct rc_chans sc_channels[CD180_NCHAN]; /* channels */ 1248471Sache}; 1258471Sache 126105806Sjhb/* Static prototypes */ 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 *); 133105806Sjhbstatic int rc_modctl(struct rc_chans *, 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_dtrwakeup(void *); 143105806Sjhbstatic void disc_optim(struct tty *tp, struct termios *t, struct rc_chans *); 144105806Sjhbstatic void rc_wait0(struct rc_softc *sc, int chan, int line); 145105806Sjhb 14612675Sjulianstatic d_open_t rcopen; 14712675Sjulianstatic d_close_t rcclose; 14812675Sjulianstatic d_ioctl_t rcioctl; 14912675Sjulian 15047625Sphkstatic struct cdevsw rc_cdevsw = { 151126080Sphk .d_version = D_VERSION, 152111815Sphk .d_open = rcopen, 153111815Sphk .d_close = rcclose, 154111815Sphk .d_ioctl = rcioctl, 155111815Sphk .d_name = "rc", 156126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 15738485Sbde}; 15812675Sjulian 159105806Sjhbstatic devclass_t rc_devclass; 1608471Sache 1618471Sache/* Flags */ 1629232Sache#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ 1639232Sache#define RC_ACTOUT 0x0002 /* Dial-out port active */ 1649232Sache#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ 1659232Sache#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ 1669232Sache#define RC_DORXFER 0x0010 /* RXFER event planned */ 1679232Sache#define RC_DOXXFER 0x0020 /* XXFER event planned */ 1689232Sache#define RC_MODCHG 0x0040 /* Modem status changed */ 1699232Sache#define RC_OSUSP 0x0080 /* Output suspended */ 1709232Sache#define RC_OSBUSY 0x0100 /* start() routine in progress */ 1719232Sache#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ 1729232Sache#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ 1739232Sache#define RC_SEND_RDY 0x0800 /* ready to send */ 1748471Sache 1758471Sache/* Table for translation of RCSR status bits to internal form */ 1768471Sachestatic int rc_rcsrt[16] = { 1778471Sache 0, TTY_OE, TTY_FE, 1788471Sache TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE, 1798471Sache TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI, 1808471Sache TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE, 1818471Sache TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE, 1828471Sache TTY_BI|TTY_PE|TTY_FE|TTY_OE 1838471Sache}; 1848471Sache 185105806Sjhbstatic int rc_ports[] = 186105806Sjhb { 0x220, 0x240, 0x250, 0x260, 0x2a0, 0x2b0, 0x300, 0x320 }; 187105806Sjhbstatic int iobase_addrs[IOBASE_ADDRS] = 188105806Sjhb { 0, 0x400, 0x800, 0xc00, 0x1400, 0x1800, 0x1c00, 0x2000, 189105806Sjhb 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x8000 }; 19067551Sjhb 1918471Sache/**********************************************/ 1928471Sache 19312724Sphkstatic int 194105806Sjhbrc_probe(device_t dev) 1958471Sache{ 196105806Sjhb u_int port; 197105806Sjhb int i, found; 1988471Sache 199105806Sjhb /* 200105806Sjhb * We don't know of any PnP ID's for these cards. 201105806Sjhb */ 202105806Sjhb if (isa_get_logicalid(dev) != 0) 203105806Sjhb return (ENXIO); 2049232Sache 205105806Sjhb /* 206105806Sjhb * We have to have an IO port hint that is valid. 207105806Sjhb */ 208105806Sjhb port = isa_get_port(dev); 209105806Sjhb if (port == -1) 210105806Sjhb return (ENXIO); 211105806Sjhb found = 0; 212105806Sjhb for (i = 0; i < sizeof(rc_ports) / sizeof(int); i++) 213105806Sjhb if (rc_ports[i] == port) { 214105806Sjhb found = 1; 215105806Sjhb break; 216105806Sjhb } 217105806Sjhb if (!found) 218105806Sjhb return (ENXIO); 219105806Sjhb 220105806Sjhb /* 221105806Sjhb * We have to have an IRQ hint. 222105806Sjhb */ 223105806Sjhb if (isa_get_irq(dev) == -1) 224105806Sjhb return (ENXIO); 225105806Sjhb 226105806Sjhb device_set_desc(dev, "SDL Riscom/8"); 227105806Sjhb return (0); 2288471Sache} 2298471Sache 23012724Sphkstatic int 231105806Sjhbrc_attach(device_t dev) 2328471Sache{ 233105806Sjhb struct rc_chans *rc; 234105806Sjhb struct tty *tp; 235105806Sjhb struct rc_softc *sc; 236105806Sjhb u_int port; 237105806Sjhb int base, chan, error, i, x; 238105806Sjhb dev_t cdev; 2398471Sache 240105806Sjhb sc = device_get_softc(dev); 241105806Sjhb sc->sc_dev = dev; 24240565Sbde 243105806Sjhb /* 244105806Sjhb * We need to have IO ports. Lots of them. We need 245105806Sjhb * the following ranges relative to the base port: 246105806Sjhb * 0x0 - 0x10 247105806Sjhb * 0x400 - 0x410 248105806Sjhb * 0x800 - 0x810 249105806Sjhb * 0xc00 - 0xc10 250105806Sjhb * 0x1400 - 0x1410 251105806Sjhb * 0x1800 - 0x1810 252105806Sjhb * 0x1c00 - 0x1c10 253105806Sjhb * 0x2000 - 0x2010 254105806Sjhb * 0x3000 - 0x3010 255105806Sjhb * 0x3400 - 0x3410 256105806Sjhb * 0x3800 - 0x3810 257105806Sjhb * 0x3c00 - 0x3c10 258105806Sjhb * 0x4000 - 0x4010 259105806Sjhb * 0x8000 - 0x8010 260105806Sjhb */ 261105806Sjhb port = isa_get_port(dev); 262105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) 263105806Sjhb if (bus_set_resource(dev, SYS_RES_IOPORT, i, 264105806Sjhb port + iobase_addrs[i], 0x10) != 0) 265105806Sjhb return (ENXIO); 266105806Sjhb error = ENOMEM; 267105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 268105806Sjhb x = i; 269105806Sjhb sc->sc_port[i] = bus_alloc_resource(dev, SYS_RES_IOPORT, &x, 270105806Sjhb 0ul, ~0ul, 0x10, RF_ACTIVE); 271105806Sjhb if (x != i) { 272105806Sjhb device_printf(dev, "ioport %d was rid %d\n", i, x); 273105806Sjhb goto fail; 274105806Sjhb } 275105806Sjhb if (sc->sc_port[i] == NULL) { 276105806Sjhb device_printf(dev, "failed to alloc ioports %x-%x\n", 277105806Sjhb port + iobase_addrs[i], 278105806Sjhb port + iobase_addrs[i] + 0x10); 279105806Sjhb goto fail; 280105806Sjhb } 281105806Sjhb } 282105806Sjhb sc->sc_bt = rman_get_bustag(sc->sc_port[0]); 283105806Sjhb sc->sc_bh = rman_get_bushandle(sc->sc_port[0]); 2848471Sache 285127135Snjl sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid, 286127135Snjl RF_ACTIVE); 287105806Sjhb if (sc->sc_irq == NULL) { 288105806Sjhb device_printf(dev, "failed to alloc IRQ\n"); 289105806Sjhb goto fail; 290105806Sjhb } 291105806Sjhb 292105806Sjhb /* 293105806Sjhb * Now do some actual tests to make sure it works. 294105806Sjhb */ 295105806Sjhb error = ENXIO; 296105806Sjhb rcout(sc, CD180_PPRL, 0x22); /* Random values to Prescale reg. */ 297105806Sjhb rcout(sc, CD180_PPRH, 0x11); 298105806Sjhb if (rcin(sc, CD180_PPRL) != 0x22 || rcin(sc, CD180_PPRH) != 0x11) 299105806Sjhb goto fail; 300105806Sjhb if (rc_test(sc)) 301105806Sjhb goto fail; 302105806Sjhb 303105806Sjhb /* 304105806Sjhb * Ok, start actually hooking things up. 305105806Sjhb */ 306105806Sjhb sc->sc_unit = device_get_unit(dev); 307105806Sjhb /*sc->sc_chipid = 0x10 + device_get_unit(dev);*/ 308105806Sjhb device_printf(dev, "%d chans, firmware rev. %c\n", 309105806Sjhb CD180_NCHAN, (rcin(sc, CD180_GFRCR) & 0xF) + 'A'); 310105806Sjhb rc = sc->sc_channels; 311105806Sjhb base = CD180_NCHAN * sc->sc_unit; 3128471Sache for (chan = 0; chan < CD180_NCHAN; chan++, rc++) { 313105806Sjhb rc->rc_rcb = sc; 3148471Sache rc->rc_chan = chan; 3158471Sache rc->rc_iptr = rc->rc_ibuf; 3168471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 3178471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 3188471Sache rc->rc_optr = rc->rc_obufend = rc->rc_obuf; 3198471Sache rc->rc_dtrwait = 3 * hz; 320105806Sjhb callout_init(&rc->rc_dtrcallout, 0); 321105806Sjhb tp = &rc->rc_tp; 3229232Sache ttychars(tp); 3239232Sache tp->t_lflag = tp->t_iflag = tp->t_oflag = 0; 3249232Sache tp->t_cflag = TTYDEF_CFLAG; 3259232Sache tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 326105806Sjhb cdev = make_dev(&rc_cdevsw, chan + base, 327105806Sjhb UID_ROOT, GID_WHEEL, 0600, "ttym%d", chan + base); 328105806Sjhb cdev->si_drv1 = rc; 329105806Sjhb cdev->si_drv2 = 0; 330105806Sjhb cdev->si_tty = tp; 331105806Sjhb rc->rc_dev = cdev; 332105806Sjhb cdev = make_dev(&rc_cdevsw, chan + base + 128, 333105806Sjhb UID_UUCP, GID_DIALER, 0660, "cuam%d", chan + base); 334105806Sjhb cdev->si_drv1 = rc; 335105806Sjhb cdev->si_drv2 = (void *)1; 336105806Sjhb cdev->si_tty = tp; 337105806Sjhb rc->rc_cdev = cdev; 3388471Sache } 339105806Sjhb 340105806Sjhb error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_TTY, rc_intr, sc, 341105806Sjhb &sc->sc_hwicookie); 342105806Sjhb if (error) { 343105806Sjhb device_printf(dev, "failed to register interrupt handler\n"); 344105806Sjhb goto fail; 3458471Sache } 346105806Sjhb 347105806Sjhb swi_add(&tty_ithd, "tty:rc", rc_pollcard, sc, SWI_TTY, 0, 348105806Sjhb &sc->sc_swicookie); 349105806Sjhb return (0); 350105806Sjhb 351105806Sjhbfail: 352105806Sjhb rc_release_resources(dev); 353105806Sjhb return (error); 3548471Sache} 3558471Sache 356105806Sjhbstatic int 357105806Sjhbrc_detach(device_t dev) 358105806Sjhb{ 359105806Sjhb struct rc_softc *sc; 360105806Sjhb struct rc_chans *rc; 361105806Sjhb int error, i, s; 362105806Sjhb 363105806Sjhb sc = device_get_softc(dev); 364105806Sjhb if (sc->sc_opencount > 0) 365105806Sjhb return (EBUSY); 366105806Sjhb sc->sc_opencount = -1; 367105806Sjhb 368105806Sjhb rc = sc->sc_channels; 369105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) { 370105806Sjhb destroy_dev(rc->rc_dev); 371105806Sjhb destroy_dev(rc->rc_cdev); 372105806Sjhb } 373105806Sjhb 374105806Sjhb rc = sc->sc_channels; 375105806Sjhb s = splsoftclock(); 376105806Sjhb for (i = 0; i < CD180_NCHAN; i++) { 377105806Sjhb if ((rc->rc_flags & RC_DTR_OFF) && 378105806Sjhb !callout_stop(&rc->rc_dtrcallout)) 379105806Sjhb tsleep(&rc->rc_dtrwait, TTIPRI, "rcdtrdet", 0); 380105806Sjhb } 381105806Sjhb 382105806Sjhb error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_hwicookie); 383105806Sjhb if (error) 384105806Sjhb device_printf(dev, "failed to deregister interrupt handler\n"); 385105806Sjhb ithread_remove_handler(sc->sc_swicookie); 386105806Sjhb rc_release_resources(dev); 387105806Sjhb 388105806Sjhb return (0); 389105806Sjhb} 390105806Sjhb 39140565Sbdestatic void 392105806Sjhbrc_release_resources(device_t dev) 3938471Sache{ 394105806Sjhb struct rc_softc *sc; 395105806Sjhb int i; 3968471Sache 397105806Sjhb sc = device_get_softc(dev); 398105806Sjhb if (sc->sc_irq != NULL) { 399105806Sjhb bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 400105806Sjhb sc->sc_irq); 401105806Sjhb sc->sc_irq = NULL; 4029232Sache } 403105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 404105806Sjhb if (sc->sc_port[i] == NULL) 405105806Sjhb break; 406105806Sjhb bus_release_resource(dev, SYS_RES_IOPORT, i, sc->sc_port[i]); 407105806Sjhb sc->sc_port[i] = NULL; 408105806Sjhb } 409105806Sjhb} 4108471Sache 411105806Sjhb/* RC interrupt handling */ 412105806Sjhbstatic void 413105806Sjhbrc_intr(void *arg) 414105806Sjhb{ 415105806Sjhb struct rc_softc *sc; 416105806Sjhb struct rc_chans *rc; 417105806Sjhb int resid, chan; 418105806Sjhb u_char val, iack, bsr, ucnt, *optr; 419105806Sjhb int good_data, t_state; 4208471Sache 421105806Sjhb sc = (struct rc_softc *)arg; 422105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 4239232Sache if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { 424105806Sjhb device_printf(sc->sc_dev, "extra interrupt\n"); 425105806Sjhb rcout(sc, CD180_EOIR, 0); 4269232Sache return; 4279232Sache } 4289232Sache 4299232Sache while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { 4309232Sache#ifdef RCDEBUG_DETAILED 431105806Sjhb device_printf(sc->sc_dev, "intr (%p) %s%s%s%s\n", arg, bsr, 4329232Sache (bsr & RC_BSR_TOUT)?"TOUT ":"", 4339232Sache (bsr & RC_BSR_RXINT)?"RXINT ":"", 4349232Sache (bsr & RC_BSR_TXINT)?"TXINT ":"", 4359232Sache (bsr & RC_BSR_MOINT)?"MOINT":""); 4368471Sache#endif 4379232Sache if (bsr & RC_BSR_TOUT) { 438105806Sjhb device_printf(sc->sc_dev, 439105806Sjhb "hardware failure, reset board\n"); 440105806Sjhb rcout(sc, RC_CTOUT, 0); 441105806Sjhb rc_reinit(sc); 4429232Sache return; 4438471Sache } 4449232Sache if (bsr & RC_BSR_RXINT) { 445105806Sjhb iack = rcin(sc, RC_PILR_RX); 4469232Sache good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); 4479232Sache if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { 448105806Sjhb device_printf(sc->sc_dev, 449105806Sjhb "fake rxint: %02x\n", iack); 4509232Sache goto more_intrs; 4519232Sache } 452105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 453105806Sjhb rc = &sc->sc_channels[chan]; 454105806Sjhb t_state = rc->rc_tp.t_state; 4559232Sache /* Do RTS flow control stuff */ 4569232Sache if ( (rc->rc_flags & RC_RTSFLOW) 4579232Sache || !(t_state & TS_ISOPEN) 4589232Sache ) { 4599232Sache if ( ( !(t_state & TS_ISOPEN) 4609232Sache || (t_state & TS_TBLOCK) 4619232Sache ) 4629232Sache && (rc->rc_msvr & MSVR_RTS) 4639232Sache ) 464105806Sjhb rcout(sc, CD180_MSVR, 4659232Sache rc->rc_msvr &= ~MSVR_RTS); 4669232Sache else if (!(rc->rc_msvr & MSVR_RTS)) 467105806Sjhb rcout(sc, CD180_MSVR, 4689232Sache rc->rc_msvr |= MSVR_RTS); 4699232Sache } 470105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 4719232Sache resid = 0; 4728471Sache 4739232Sache if (t_state & TS_ISOPEN) { 4749232Sache /* check for input buffer overflow */ 4759232Sache if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { 4769232Sache resid = ucnt; 4779232Sache ucnt = rc->rc_bufend - rc->rc_iptr; 4789232Sache resid -= ucnt; 4799232Sache if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { 4809232Sache rc->rc_flags |= RC_WAS_BUFOVFL; 481105806Sjhb sc->sc_scheduled_event++; 4829232Sache } 4838471Sache } 4849232Sache optr = rc->rc_iptr; 4859232Sache /* check foor good data */ 4869232Sache if (good_data) { 4879232Sache while (ucnt-- > 0) { 488105806Sjhb val = rcin(sc, CD180_RDR); 4899232Sache optr[0] = val; 4909232Sache optr[INPUT_FLAGS_SHIFT] = 0; 4919232Sache optr++; 492105806Sjhb sc->sc_scheduled_event++; 4939232Sache if (val != 0 && val == rc->rc_hotchar) 494105806Sjhb swi_sched(sc->sc_swicookie, 0); 4958471Sache } 4969232Sache } else { 4979232Sache /* Store also status data */ 4989232Sache while (ucnt-- > 0) { 499105806Sjhb iack = rcin(sc, CD180_RCSR); 5009232Sache if (iack & RCSR_Timeout) 5019232Sache break; 5029232Sache if ( (iack & RCSR_OE) 5039232Sache && !(rc->rc_flags & RC_WAS_SILOVFL)) { 5049232Sache rc->rc_flags |= RC_WAS_SILOVFL; 505105806Sjhb sc->sc_scheduled_event++; 5069232Sache } 507105806Sjhb val = rcin(sc, CD180_RDR); 5089232Sache /* 5099232Sache Don't store PE if IGNPAR and BREAK if IGNBRK, 5109232Sache this hack allows "raw" tty optimization 5119232Sache works even if IGN* is set. 5129232Sache */ 5139232Sache if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) 51446704Speter || ((!(iack & (RCSR_PE|RCSR_FE)) 515105806Sjhb || !(rc->rc_tp.t_iflag & IGNPAR)) 5169232Sache && (!(iack & RCSR_Break) 517105806Sjhb || !(rc->rc_tp.t_iflag & IGNBRK)))) { 5189232Sache if ( (iack & (RCSR_PE|RCSR_FE)) 5199232Sache && (t_state & TS_CAN_BYPASS_L_RINT) 5209232Sache && ((iack & RCSR_FE) 52146704Speter || ((iack & RCSR_PE) 522105806Sjhb && (rc->rc_tp.t_iflag & INPCK)))) 5239232Sache val = 0; 5249232Sache else if (val != 0 && val == rc->rc_hotchar) 525105806Sjhb swi_sched(sc->sc_swicookie, 0); 5269232Sache optr[0] = val; 5279232Sache optr[INPUT_FLAGS_SHIFT] = iack; 5289232Sache optr++; 529105806Sjhb sc->sc_scheduled_event++; 5309232Sache } 5319232Sache } 5328471Sache } 5339232Sache rc->rc_iptr = optr; 5349232Sache rc->rc_flags |= RC_DORXFER; 5359232Sache } else 5369232Sache resid = ucnt; 5379232Sache /* Clear FIFO if necessary */ 5389232Sache while (resid-- > 0) { 5399232Sache if (!good_data) 540105806Sjhb iack = rcin(sc, CD180_RCSR); 5419232Sache else 5429232Sache iack = 0; 5439232Sache if (iack & RCSR_Timeout) 5449232Sache break; 545105806Sjhb (void) rcin(sc, CD180_RDR); 5468471Sache } 5479232Sache goto more_intrs; 5488471Sache } 5499232Sache if (bsr & RC_BSR_MOINT) { 550105806Sjhb iack = rcin(sc, RC_PILR_MODEM); 5519232Sache if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { 552105806Sjhb device_printf(sc->sc_dev, "fake moint: %02x\n", 553105806Sjhb iack); 5549232Sache goto more_intrs; 5559232Sache } 556105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 557105806Sjhb rc = &sc->sc_channels[chan]; 558105806Sjhb iack = rcin(sc, CD180_MCR); 559105806Sjhb rc->rc_msvr = rcin(sc, CD180_MSVR); 560105806Sjhb rcout(sc, CD180_MCR, 0); 5618471Sache#ifdef RCDEBUG 5629232Sache printrcflags(rc, "moint"); 5638471Sache#endif 5649232Sache if (rc->rc_flags & RC_CTSFLOW) { 5659232Sache if (rc->rc_msvr & MSVR_CTS) 5669232Sache rc->rc_flags |= RC_SEND_RDY; 5679232Sache else 5689232Sache rc->rc_flags &= ~RC_SEND_RDY; 5699232Sache } else 5708471Sache rc->rc_flags |= RC_SEND_RDY; 5719232Sache if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { 572105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 5739232Sache rc->rc_flags |= RC_MODCHG; 574105806Sjhb swi_sched(sc->sc_swicookie, 0); 5759232Sache } 5769232Sache goto more_intrs; 5778471Sache } 5789232Sache if (bsr & RC_BSR_TXINT) { 579105806Sjhb iack = rcin(sc, RC_PILR_TX); 5809232Sache if (iack != (GIVR_IT_TDI | RC_FAKEID)) { 581105806Sjhb device_printf(sc->sc_dev, "fake txint: %02x\n", 582105806Sjhb iack); 5839232Sache goto more_intrs; 5849232Sache } 585105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 586105806Sjhb rc = &sc->sc_channels[chan]; 5879232Sache if ( (rc->rc_flags & RC_OSUSP) 5889232Sache || !(rc->rc_flags & RC_SEND_RDY) 5899232Sache ) 5909232Sache goto more_intrs; 5919232Sache /* Handle breaks and other stuff */ 5929232Sache if (rc->rc_pendcmd) { 593105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 |= COR2_ETC); 594105806Sjhb rcout(sc, CD180_TDR, CD180_C_ESC); 595105806Sjhb rcout(sc, CD180_TDR, rc->rc_pendcmd); 596105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); 5979232Sache rc->rc_pendcmd = 0; 5989232Sache goto more_intrs; 5999232Sache } 6009232Sache optr = rc->rc_optr; 6019232Sache resid = rc->rc_obufend - optr; 6029232Sache if (resid > CD180_NFIFO) 6039232Sache resid = CD180_NFIFO; 6049232Sache while (resid-- > 0) 605105806Sjhb rcout(sc, CD180_TDR, *optr++); 6069232Sache rc->rc_optr = optr; 6078471Sache 6089232Sache /* output completed? */ 6099232Sache if (optr >= rc->rc_obufend) { 610105806Sjhb rcout(sc, CD180_IER, rc->rc_ier &= ~IER_TxRdy); 6118471Sache#ifdef RCDEBUG 612105806Sjhb device_printf(sc->sc_dev, 613105806Sjhb "channel %d: output completed\n", 614105806Sjhb rc->rc_chan); 6158471Sache#endif 6169232Sache if (!(rc->rc_flags & RC_DOXXFER)) { 617105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 6189232Sache rc->rc_flags |= RC_DOXXFER; 619105806Sjhb swi_sched(sc->sc_swicookie, 0); 6209232Sache } 6219232Sache } 6228471Sache } 6239232Sache more_intrs: 624105806Sjhb rcout(sc, CD180_EOIR, 0); /* end of interrupt */ 625105806Sjhb rcout(sc, RC_CTOUT, 0); 626105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 6278471Sache } 6288471Sache} 6298471Sache 6308471Sache/* Feed characters to output buffer */ 631105806Sjhbstatic void 632105806Sjhbrc_start(struct tty *tp) 6338471Sache{ 634105806Sjhb struct rc_softc *sc; 635105806Sjhb struct rc_chans *rc; 636105806Sjhb int s; 6378471Sache 638105806Sjhb rc = TTY_TO_RC(tp); 6398471Sache if (rc->rc_flags & RC_OSBUSY) 6408471Sache return; 641105806Sjhb sc = rc->rc_rcb; 6428471Sache s = spltty(); 6438471Sache rc->rc_flags |= RC_OSBUSY; 644106653Sjhb critical_enter(); 6458471Sache if (tp->t_state & TS_TTSTOP) 6468471Sache rc->rc_flags |= RC_OSUSP; 6478471Sache else 6488471Sache rc->rc_flags &= ~RC_OSUSP; 6498471Sache /* Do RTS flow control stuff */ 6509232Sache if ( (rc->rc_flags & RC_RTSFLOW) 6519232Sache && (tp->t_state & TS_TBLOCK) 6529232Sache && (rc->rc_msvr & MSVR_RTS) 6539232Sache ) { 654105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 655105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); 6569232Sache } else if (!(rc->rc_msvr & MSVR_RTS)) { 657105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 658105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr |= MSVR_RTS); 6598471Sache } 660106653Sjhb critical_exit(); 6618471Sache if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 6628471Sache goto out; 6638471Sache#ifdef RCDEBUG 6648471Sache printrcflags(rc, "rcstart"); 6658471Sache#endif 6669626Sbde ttwwakeup(tp); 6678471Sache#ifdef RCDEBUG 6689232Sache printf("rcstart: outq = %d obuf = %d\n", 6698471Sache tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); 6708471Sache#endif 6719232Sache if (tp->t_state & TS_BUSY) 672105806Sjhb goto out; /* output still in progress ... */ 6738471Sache 6748471Sache if (tp->t_outq.c_cc > 0) { 6758471Sache u_int ocnt; 6768471Sache 6778471Sache tp->t_state |= TS_BUSY; 6788471Sache ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); 679106653Sjhb critical_enter(); 6808471Sache rc->rc_optr = rc->rc_obuf; 6819232Sache rc->rc_obufend = rc->rc_optr + ocnt; 682106653Sjhb critical_exit(); 6839232Sache if (!(rc->rc_ier & IER_TxRdy)) { 6848471Sache#ifdef RCDEBUG 685105806Sjhb device_printf(sc->sc_dev, 686105806Sjhb "channel %d: rcstart enable txint\n", rc->rc_chan); 6878471Sache#endif 688105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 689105806Sjhb rcout(sc, CD180_IER, rc->rc_ier |= IER_TxRdy); 6908471Sache } 6918471Sache } 6928471Sacheout: 6938471Sache rc->rc_flags &= ~RC_OSBUSY; 6948471Sache (void) splx(s); 6958471Sache} 6968471Sache 6978471Sache/* Handle delayed events. */ 698105806Sjhbvoid 699105806Sjhbrc_pollcard(void *arg) 7008471Sache{ 701105806Sjhb struct rc_softc *sc; 702105806Sjhb struct rc_chans *rc; 703105806Sjhb struct tty *tp; 704105806Sjhb u_char *tptr, *eptr; 705105806Sjhb int chan, icnt; 7068471Sache 707105806Sjhb sc = (struct rc_softc *)arg; 708105806Sjhb if (sc->sc_scheduled_event == 0) 7098471Sache return; 710105806Sjhb do { 711105806Sjhb rc = sc->sc_channels; 7128471Sache for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { 713105806Sjhb tp = &rc->rc_tp; 7148471Sache#ifdef RCDEBUG 7158471Sache if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| 7168471Sache RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) 7178471Sache printrcflags(rc, "rcevent"); 7188471Sache#endif 7198471Sache if (rc->rc_flags & RC_WAS_BUFOVFL) { 720106653Sjhb critical_enter(); 7218471Sache rc->rc_flags &= ~RC_WAS_BUFOVFL; 722105806Sjhb sc->sc_scheduled_event--; 723106653Sjhb critical_exit(); 724105806Sjhb device_printf(sc->sc_dev, 725105806Sjhb "channel %d: interrupt-level buffer overflow\n", 726105806Sjhb chan); 7278471Sache } 7288471Sache if (rc->rc_flags & RC_WAS_SILOVFL) { 729106653Sjhb critical_enter(); 7308471Sache rc->rc_flags &= ~RC_WAS_SILOVFL; 731105806Sjhb sc->sc_scheduled_event--; 732106653Sjhb critical_exit(); 733105806Sjhb device_printf(sc->sc_dev, 734105806Sjhb "channel %d: silo overflow\n", chan); 7358471Sache } 7368471Sache if (rc->rc_flags & RC_MODCHG) { 737106653Sjhb critical_enter(); 7388471Sache rc->rc_flags &= ~RC_MODCHG; 739105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 740106653Sjhb critical_exit(); 741130077Sphk ttyld_modem(tp, !!(rc->rc_msvr & MSVR_CD)); 7428471Sache } 7438471Sache if (rc->rc_flags & RC_DORXFER) { 744106653Sjhb critical_enter(); 7458471Sache rc->rc_flags &= ~RC_DORXFER; 7468471Sache eptr = rc->rc_iptr; 7478471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) 7488471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7498471Sache else 7508471Sache tptr = rc->rc_ibuf; 7518471Sache icnt = eptr - tptr; 7528471Sache if (icnt > 0) { 7538471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 7548471Sache rc->rc_iptr = rc->rc_ibuf; 7558471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 7568471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 7578471Sache } else { 7588471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7598471Sache rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; 7608471Sache rc->rc_hiwat = 7618471Sache &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; 7628471Sache } 7639232Sache if ( (rc->rc_flags & RC_RTSFLOW) 7649232Sache && (tp->t_state & TS_ISOPEN) 7659232Sache && !(tp->t_state & TS_TBLOCK) 7668471Sache && !(rc->rc_msvr & MSVR_RTS) 7679232Sache ) { 768105806Sjhb rcout(sc, CD180_CAR, chan); 769105806Sjhb rcout(sc, CD180_MSVR, 7708471Sache rc->rc_msvr |= MSVR_RTS); 7718471Sache } 772105806Sjhb sc->sc_scheduled_event -= icnt; 7738471Sache } 774106653Sjhb critical_exit(); 7758471Sache 7769232Sache if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) 7778471Sache goto done1; 7788471Sache 7798471Sache if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) 7808471Sache && !(tp->t_state & TS_LOCAL)) { 7819822Sbde if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER 7829822Sbde && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) 7839822Sbde && !(tp->t_state & TS_TBLOCK)) 7849822Sbde ttyblock(tp); 7858471Sache tk_nin += icnt; 7868471Sache tk_rawcc += icnt; 7878471Sache tp->t_rawcc += icnt; 7888471Sache if (b_to_q(tptr, icnt, &tp->t_rawq)) 789105806Sjhb device_printf(sc->sc_dev, 790105806Sjhb "channel %d: tty-level buffer overflow\n", 791105806Sjhb chan); 7928471Sache ttwakeup(tp); 7938471Sache if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) 7948471Sache || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { 7958471Sache tp->t_state &= ~TS_TTSTOP; 7968471Sache tp->t_lflag &= ~FLUSHO; 7979754Sbde rc_start(tp); 7988471Sache } 7998471Sache } else { 8008471Sache for (; tptr < eptr; tptr++) 8018471Sache (*linesw[tp->t_line].l_rint) 8028471Sache (tptr[0] | 8038471Sache rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp); 8048471Sache } 80527125Sbdedone1: ; 8068471Sache } 8078471Sache if (rc->rc_flags & RC_DOXXFER) { 808106653Sjhb critical_enter(); 809105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 8109232Sache rc->rc_flags &= ~RC_DOXXFER; 811105806Sjhb rc->rc_tp.t_state &= ~TS_BUSY; 812106653Sjhb critical_exit(); 813130077Sphk ttyld_start(tp); 8148471Sache } 815111564Sjhb if (sc->sc_scheduled_event == 0) 816111564Sjhb break; 8178471Sache } 818111564Sjhb } while (sc->sc_scheduled_event >= LOTS_OF_EVENTS); 8198471Sache} 8208471Sache 821105806Sjhbstatic void 822105806Sjhbrc_stop(struct tty *tp, int rw) 8238471Sache{ 824105806Sjhb struct rc_softc *sc; 825105806Sjhb struct rc_chans *rc; 8268471Sache u_char *tptr, *eptr; 8278471Sache 828105806Sjhb rc = TTY_TO_RC(tp); 829105806Sjhb sc = rc->rc_rcb; 8308471Sache#ifdef RCDEBUG 831105806Sjhb device_printf(sc->sc_dev, "channel %d: rc_stop %s%s\n", 832105806Sjhb rc->rc_chan, (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); 8338471Sache#endif 8348471Sache if (rw & FWRITE) 8358471Sache rc_discard_output(rc); 836106653Sjhb critical_enter(); 8378471Sache if (rw & FREAD) { 8389232Sache rc->rc_flags &= ~RC_DORXFER; 8398471Sache eptr = rc->rc_iptr; 8408471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 8418471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 8428471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 8438471Sache } else { 8448471Sache tptr = rc->rc_ibuf; 8458471Sache rc->rc_iptr = rc->rc_ibuf; 8468471Sache } 847105806Sjhb sc->sc_scheduled_event -= eptr - tptr; 8488471Sache } 8498471Sache if (tp->t_state & TS_TTSTOP) 8508471Sache rc->rc_flags |= RC_OSUSP; 8518471Sache else 8528471Sache rc->rc_flags &= ~RC_OSUSP; 853106653Sjhb critical_exit(); 8548471Sache} 8558471Sache 856105806Sjhbstatic int 857105806Sjhbrcopen(dev_t dev, int flag, int mode, d_thread_t *td) 8588471Sache{ 859105806Sjhb struct rc_softc *sc; 860105806Sjhb struct rc_chans *rc; 861105806Sjhb struct tty *tp; 862105806Sjhb int s, error = 0; 8638471Sache 864105806Sjhb rc = DEV_TO_RC(dev); 865105806Sjhb sc = rc->rc_rcb; 866105806Sjhb tp = &rc->rc_tp; 867105806Sjhb if (sc->sc_opencount < 0) 868105806Sjhb return (ENXIO); 869105806Sjhb sc->sc_opencount++; 8708471Sache#ifdef RCDEBUG 871105806Sjhb device_printf(sc->sc_dev, "channel %d: rcopen: dev %p\n", 872105806Sjhb rc->rc_chan, dev); 8738471Sache#endif 8748471Sache s = spltty(); 8758471Sache 8768471Sacheagain: 8778471Sache while (rc->rc_flags & RC_DTR_OFF) { 8789232Sache error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0); 8798471Sache if (error != 0) 8808471Sache goto out; 8818471Sache } 8828471Sache if (tp->t_state & TS_ISOPEN) { 8838471Sache if (CALLOUT(dev)) { 8848471Sache if (!(rc->rc_flags & RC_ACTOUT)) { 8858471Sache error = EBUSY; 8868471Sache goto out; 8878471Sache } 8888471Sache } else { 8898471Sache if (rc->rc_flags & RC_ACTOUT) { 8908471Sache if (flag & O_NONBLOCK) { 8918471Sache error = EBUSY; 8928471Sache goto out; 8938471Sache } 89446571Speter error = tsleep(&rc->rc_rcb, 89546571Speter TTIPRI|PCATCH, "rcbi", 0); 89646571Speter if (error) 8978471Sache goto out; 8988471Sache goto again; 8998471Sache } 9008471Sache } 90143425Sphk if (tp->t_state & TS_XCLUDE && 90293593Sjhb suser(td)) { 9038471Sache error = EBUSY; 9048471Sache goto out; 9058471Sache } 9068471Sache } else { 9078471Sache tp->t_oproc = rc_start; 9088471Sache tp->t_param = rc_param; 90951654Sphk tp->t_stop = rc_stop; 9108471Sache tp->t_dev = dev; 9118471Sache 9128471Sache if (CALLOUT(dev)) 9138471Sache tp->t_cflag |= CLOCAL; 9148471Sache else 9158471Sache tp->t_cflag &= ~CLOCAL; 9168471Sache 9178471Sache error = rc_param(tp, &tp->t_termios); 9188471Sache if (error) 9198471Sache goto out; 9209232Sache (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET); 9218471Sache 9228471Sache if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev)) 923130077Sphk ttyld_modem(tp, 1); 9248471Sache } 9258471Sache if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev) 9268471Sache && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 9278471Sache rc->rc_dcdwaits++; 9289639Sbde error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0); 9298471Sache rc->rc_dcdwaits--; 9308471Sache if (error != 0) 9318471Sache goto out; 9328471Sache goto again; 9338471Sache } 934130077Sphk error = ttyld_open(tp, dev); 93513074Sache disc_optim(tp, &tp->t_termios, rc); 9368471Sache if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev)) 9378471Sache rc->rc_flags |= RC_ACTOUT; 9388471Sacheout: 9398471Sache (void) splx(s); 9408471Sache 9418471Sache if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN)) 9428471Sache rc_hardclose(rc); 9438471Sache 9448471Sache return error; 9458471Sache} 9468471Sache 947105806Sjhbstatic int 948105806Sjhbrcclose(dev_t dev, int flag, int mode, d_thread_t *td) 9498471Sache{ 950105806Sjhb struct rc_softc *sc; 951105806Sjhb struct rc_chans *rc; 952105806Sjhb struct tty *tp; 953105806Sjhb int s; 9548471Sache 955105806Sjhb rc = DEV_TO_RC(dev); 956105806Sjhb sc = rc->rc_rcb; 957105806Sjhb tp = &rc->rc_tp; 9589232Sache#ifdef RCDEBUG 959105806Sjhb device_printf(sc->sc_dev, "channel %d: rcclose dev %p\n", 960105806Sjhb rc->rc_chan, dev); 9619232Sache#endif 9628471Sache s = spltty(); 963130077Sphk ttyld_close(tp, flag); 96413074Sache disc_optim(tp, &tp->t_termios, rc); 9658471Sache rc_hardclose(rc); 9668471Sache ttyclose(tp); 9678471Sache splx(s); 968105806Sjhb KASSERT(sc->sc_opencount > 0, ("rcclose: non-positive open count")); 969105806Sjhb sc->sc_opencount--; 9708471Sache return 0; 9718471Sache} 9728471Sache 973105806Sjhbstatic void 974105806Sjhbrc_hardclose(struct rc_chans *rc) 9758471Sache{ 976105806Sjhb struct rc_softc *sc; 977105806Sjhb struct tty *tp; 978105806Sjhb int s; 9798471Sache 980105806Sjhb tp = &rc->rc_tp; 981105806Sjhb sc = rc->rc_rcb; 9828471Sache s = spltty(); 983105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 9848471Sache 9859232Sache /* Disable rx/tx intrs */ 986105806Sjhb rcout(sc, CD180_IER, rc->rc_ier = 0); 9879232Sache if ( (tp->t_cflag & HUPCL) 98846704Speter || (!(rc->rc_flags & RC_ACTOUT) 9898471Sache && !(rc->rc_msvr & MSVR_CD) 99046704Speter && !(tp->t_cflag & CLOCAL)) 9919232Sache || !(tp->t_state & TS_ISOPEN) 9929232Sache ) { 993105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 994105806Sjhb WAITFORCCR(sc, rc->rc_chan); 9958471Sache (void) rc_modctl(rc, TIOCM_RTS, DMSET); 9968471Sache if (rc->rc_dtrwait) { 997105806Sjhb callout_reset(&rc->rc_dtrcallout, rc->rc_dtrwait, 998105806Sjhb rc_dtrwakeup, rc); 9998471Sache rc->rc_flags |= RC_DTR_OFF; 10008471Sache } 10018471Sache } 10028471Sache rc->rc_flags &= ~RC_ACTOUT; 1003111748Sdes wakeup( &rc->rc_rcb); /* wake bi */ 10049639Sbde wakeup(TSA_CARR_ON(tp)); 10058471Sache (void) splx(s); 10068471Sache} 10078471Sache 10088471Sache/* Reset the bastard */ 1009105806Sjhbstatic void 1010118607Sjhbrc_hwreset(struct rc_softc *sc, u_int chipid) 10118471Sache{ 1012105806Sjhb CCRCMD(sc, -1, CCR_HWRESET); /* Hardware reset */ 10138471Sache DELAY(20000); 1014105806Sjhb WAITFORCCR(sc, -1); 10159232Sache 1016105806Sjhb rcout(sc, RC_CTOUT, 0); /* Clear timeout */ 1017105806Sjhb rcout(sc, CD180_GIVR, chipid); 1018105806Sjhb rcout(sc, CD180_GICR, 0); 10198471Sache 10208471Sache /* Set Prescaler Registers (1 msec) */ 1021105806Sjhb rcout(sc, CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); 1022105806Sjhb rcout(sc, CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); 10238471Sache 10248471Sache /* Initialize Priority Interrupt Level Registers */ 1025105806Sjhb rcout(sc, CD180_PILR1, RC_PILR_MODEM); 1026105806Sjhb rcout(sc, CD180_PILR2, RC_PILR_TX); 1027105806Sjhb rcout(sc, CD180_PILR3, RC_PILR_RX); 10288471Sache 10298471Sache /* Reset DTR */ 1030105806Sjhb rcout(sc, RC_DTREG, ~0); 10318471Sache} 10328471Sache 10338471Sache/* Set channel parameters */ 1034105806Sjhbstatic int 1035105806Sjhbrc_param(struct tty *tp, struct termios *ts) 10368471Sache{ 1037105806Sjhb struct rc_softc *sc; 1038105806Sjhb struct rc_chans *rc; 1039105806Sjhb int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; 10408471Sache 10419855Sache if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 10429855Sache || ts->c_ispeed < 0 || ts->c_ispeed > 76800 10439855Sache ) 10449855Sache return (EINVAL); 10458471Sache if (ts->c_ispeed == 0) 10468471Sache ts->c_ispeed = ts->c_ospeed; 10479855Sache odivs = RC_BRD(ts->c_ospeed); 10489855Sache idivs = RC_BRD(ts->c_ispeed); 10498471Sache 1050105806Sjhb rc = TTY_TO_RC(tp); 1051105806Sjhb sc = rc->rc_rcb; 10528471Sache s = spltty(); 10538471Sache 10549232Sache /* Select channel */ 1055105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 10569232Sache 10578471Sache /* If speed == 0, hangup line */ 10589232Sache if (ts->c_ospeed == 0) { 1059105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 1060105806Sjhb WAITFORCCR(sc, rc->rc_chan); 10619232Sache (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 10629232Sache } 10638471Sache 10648471Sache tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 10658471Sache cflag = ts->c_cflag; 10668471Sache iflag = ts->c_iflag; 10678471Sache lflag = ts->c_lflag; 10688471Sache 10698471Sache if (idivs > 0) { 1070105806Sjhb rcout(sc, CD180_RBPRL, idivs & 0xFF); 1071105806Sjhb rcout(sc, CD180_RBPRH, idivs >> 8); 10728471Sache } 10738471Sache if (odivs > 0) { 1074105806Sjhb rcout(sc, CD180_TBPRL, odivs & 0xFF); 1075105806Sjhb rcout(sc, CD180_TBPRH, odivs >> 8); 10768471Sache } 10778471Sache 10788471Sache /* set timeout value */ 10799232Sache if (ts->c_ispeed > 0) { 10809232Sache int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; 10818471Sache 10829232Sache if ( !(lflag & ICANON) 10839232Sache && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 10849232Sache && ts->c_cc[VTIME] * 10 > itm) 10859232Sache itm = ts->c_cc[VTIME] * 10; 10869232Sache 1087105806Sjhb rcout(sc, CD180_RTPR, itm <= 255 ? itm : 255); 10889232Sache } 10899232Sache 10908471Sache switch (cflag & CSIZE) { 10918471Sache case CS5: val = COR1_5BITS; break; 10928471Sache case CS6: val = COR1_6BITS; break; 10938471Sache case CS7: val = COR1_7BITS; break; 10948471Sache default: 10958471Sache case CS8: val = COR1_8BITS; break; 10968471Sache } 10978471Sache if (cflag & PARENB) { 10988471Sache val |= COR1_NORMPAR; 10998471Sache if (cflag & PARODD) 11008471Sache val |= COR1_ODDP; 11019232Sache if (!(cflag & INPCK)) 11029232Sache val |= COR1_Ignore; 11038471Sache } else 11049232Sache val |= COR1_Ignore; 11058471Sache if (cflag & CSTOPB) 11068471Sache val |= COR1_2SB; 1107105806Sjhb rcout(sc, CD180_COR1, val); 11088471Sache 11098471Sache /* Set FIFO threshold */ 11109232Sache val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; 11119232Sache inpflow = 0; 11129232Sache if ( (iflag & IXOFF) 11139232Sache && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE 11149232Sache && ( ts->c_cc[VSTART] != _POSIX_VDISABLE 11159232Sache || (iflag & IXANY) 11169232Sache ) 11179232Sache ) 11189232Sache ) { 11199232Sache inpflow = 1; 11209232Sache val |= COR3_SCDE|COR3_FCT; 11219232Sache } 1122105806Sjhb rcout(sc, CD180_COR3, val); 11238471Sache 11248471Sache /* Initialize on-chip automatic flow control */ 11258471Sache val = 0; 11269232Sache rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); 11278471Sache if (cflag & CCTS_OFLOW) { 11288471Sache rc->rc_flags |= RC_CTSFLOW; 11299232Sache val |= COR2_CtsAE; 11309232Sache } else 11319232Sache rc->rc_flags |= RC_SEND_RDY; 11329232Sache if (tp->t_state & TS_TTSTOP) 11339232Sache rc->rc_flags |= RC_OSUSP; 11348471Sache else 11359232Sache rc->rc_flags &= ~RC_OSUSP; 11368471Sache if (cflag & CRTS_IFLOW) 11378471Sache rc->rc_flags |= RC_RTSFLOW; 11389232Sache else 11399232Sache rc->rc_flags &= ~RC_RTSFLOW; 11408471Sache 11419232Sache if (inpflow) { 11429232Sache if (ts->c_cc[VSTART] != _POSIX_VDISABLE) 1143105806Sjhb rcout(sc, CD180_SCHR1, ts->c_cc[VSTART]); 1144105806Sjhb rcout(sc, CD180_SCHR2, ts->c_cc[VSTOP]); 11459232Sache val |= COR2_TxIBE; 11469232Sache if (iflag & IXANY) 11479232Sache val |= COR2_IXM; 11488471Sache } 11498471Sache 1150105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 = val); 11518471Sache 1152105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 11539232Sache 11548471Sache disc_optim(tp, ts, rc); 11558471Sache 11568471Sache /* modem ctl */ 11579232Sache val = cflag & CLOCAL ? 0 : MCOR1_CDzd; 11589232Sache if (cflag & CCTS_OFLOW) 11599232Sache val |= MCOR1_CTSzd; 1160105806Sjhb rcout(sc, CD180_MCOR1, val); 11618471Sache 11629232Sache val = cflag & CLOCAL ? 0 : MCOR2_CDod; 11639232Sache if (cflag & CCTS_OFLOW) 11649232Sache val |= MCOR2_CTSod; 1165105806Sjhb rcout(sc, CD180_MCOR2, val); 11669232Sache 11678471Sache /* enable i/o and interrupts */ 1168105806Sjhb CCRCMD(sc, rc->rc_chan, 11699232Sache CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); 1170105806Sjhb WAITFORCCR(sc, rc->rc_chan); 11718471Sache 11729232Sache rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; 11739232Sache if (cflag & CCTS_OFLOW) 11749232Sache rc->rc_ier |= IER_CTS; 11759232Sache if (cflag & CREAD) 11769232Sache rc->rc_ier |= IER_RxData; 11779232Sache if (tp->t_state & TS_BUSY) 11789232Sache rc->rc_ier |= IER_TxRdy; 11799232Sache if (ts->c_ospeed != 0) 11809232Sache rc_modctl(rc, TIOCM_DTR, DMBIS); 11819232Sache if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) 11829232Sache rc->rc_flags |= RC_SEND_RDY; 1183105806Sjhb rcout(sc, CD180_IER, rc->rc_ier); 11848471Sache (void) splx(s); 11858471Sache return 0; 11868471Sache} 11878471Sache 11889232Sache/* Re-initialize board after bogus interrupts */ 1189105806Sjhbstatic void 1190105806Sjhbrc_reinit(struct rc_softc *sc) 11919232Sache{ 1192105806Sjhb struct rc_chans *rc; 1193105806Sjhb int i; 11949232Sache 1195105806Sjhb rc_hwreset(sc, RC_FAKEID); 1196105806Sjhb rc = sc->sc_channels; 1197105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) 1198105806Sjhb (void) rc_param(&rc->rc_tp, &rc->rc_tp.t_termios); 11999232Sache} 12009232Sache 1201105806Sjhbstatic int 1202105806Sjhbrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td) 12038471Sache{ 1204105806Sjhb struct rc_chans *rc; 1205105806Sjhb struct tty *tp; 1206105806Sjhb int s, error; 12078471Sache 1208105806Sjhb rc = DEV_TO_RC(dev); 1209105806Sjhb tp = &rc->rc_tp; 1210130057Sphk error = ttyioctl(dev, cmd, data, flag, td); 121113074Sache disc_optim(tp, &tp->t_termios, rc); 1212130057Sphk if (error != ENOTTY) 12138471Sache return (error); 12148471Sache s = spltty(); 12158471Sache 12168471Sache switch (cmd) { 12178471Sache case TIOCSBRK: 12188471Sache rc->rc_pendcmd = CD180_C_SBRK; 12198471Sache break; 12208471Sache 12218471Sache case TIOCCBRK: 12228471Sache rc->rc_pendcmd = CD180_C_EBRK; 12238471Sache break; 12248471Sache 12258471Sache case TIOCSDTR: 12269232Sache (void) rc_modctl(rc, TIOCM_DTR, DMBIS); 12278471Sache break; 12288471Sache 12298471Sache case TIOCCDTR: 12308471Sache (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 12318471Sache break; 12328471Sache 12338471Sache case TIOCMGET: 12348471Sache *(int *) data = rc_modctl(rc, 0, DMGET); 12358471Sache break; 12368471Sache 12378471Sache case TIOCMSET: 12388471Sache (void) rc_modctl(rc, *(int *) data, DMSET); 12398471Sache break; 12408471Sache 12418471Sache case TIOCMBIC: 12428471Sache (void) rc_modctl(rc, *(int *) data, DMBIC); 12438471Sache break; 12448471Sache 12458471Sache case TIOCMBIS: 12468471Sache (void) rc_modctl(rc, *(int *) data, DMBIS); 12478471Sache break; 12488471Sache 12498471Sache case TIOCMSDTRWAIT: 125093593Sjhb error = suser(td); 12518471Sache if (error != 0) { 12528471Sache splx(s); 12538471Sache return (error); 12548471Sache } 12558471Sache rc->rc_dtrwait = *(int *)data * hz / 100; 12568471Sache break; 12578471Sache 12588471Sache case TIOCMGDTRWAIT: 12598471Sache *(int *)data = rc->rc_dtrwait * 100 / hz; 12608471Sache break; 12618471Sache 12628471Sache default: 12638471Sache (void) splx(s); 12648471Sache return ENOTTY; 12658471Sache } 12668471Sache (void) splx(s); 12678471Sache return 0; 12688471Sache} 12698471Sache 12708471Sache 12718471Sache/* Modem control routines */ 12728471Sache 1273105806Sjhbstatic int 1274105806Sjhbrc_modctl(struct rc_chans *rc, int bits, int cmd) 12758471Sache{ 1276105806Sjhb struct rc_softc *sc; 1277105806Sjhb u_char *dtr; 1278105806Sjhb u_char msvr; 12798471Sache 1280105806Sjhb sc = rc->rc_rcb; 1281105806Sjhb dtr = &sc->sc_dtr; 1282105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 12838471Sache 12848471Sache switch (cmd) { 12858471Sache case DMSET: 1286105806Sjhb rcout(sc, RC_DTREG, (bits & TIOCM_DTR) ? 12879232Sache ~(*dtr |= 1 << rc->rc_chan) : 12889232Sache ~(*dtr &= ~(1 << rc->rc_chan))); 1289105806Sjhb msvr = rcin(sc, CD180_MSVR); 12909232Sache if (bits & TIOCM_RTS) 12919232Sache msvr |= MSVR_RTS; 12929232Sache else 12939232Sache msvr &= ~MSVR_RTS; 12949232Sache if (bits & TIOCM_DTR) 12959232Sache msvr |= MSVR_DTR; 12969232Sache else 12979232Sache msvr &= ~MSVR_DTR; 1298105806Sjhb rcout(sc, CD180_MSVR, msvr); 12999232Sache break; 13008471Sache 13018471Sache case DMBIS: 13029232Sache if (bits & TIOCM_DTR) 1303105806Sjhb rcout(sc, RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); 1304105806Sjhb msvr = rcin(sc, CD180_MSVR); 13058471Sache if (bits & TIOCM_RTS) 13069232Sache msvr |= MSVR_RTS; 13078471Sache if (bits & TIOCM_DTR) 13089232Sache msvr |= MSVR_DTR; 1309105806Sjhb rcout(sc, CD180_MSVR, msvr); 13108471Sache break; 13118471Sache 13128471Sache case DMGET: 13138471Sache bits = TIOCM_LE; 1314105806Sjhb msvr = rc->rc_msvr = rcin(sc, CD180_MSVR); 13158471Sache 13168471Sache if (msvr & MSVR_RTS) 13178471Sache bits |= TIOCM_RTS; 13188471Sache if (msvr & MSVR_CTS) 13198471Sache bits |= TIOCM_CTS; 13208471Sache if (msvr & MSVR_DSR) 13218471Sache bits |= TIOCM_DSR; 13228471Sache if (msvr & MSVR_DTR) 13238471Sache bits |= TIOCM_DTR; 13249232Sache if (msvr & MSVR_CD) 13259232Sache bits |= TIOCM_CD; 1326105806Sjhb if (~rcin(sc, RC_RIREG) & (1 << rc->rc_chan)) 13279232Sache bits |= TIOCM_RI; 13288471Sache return bits; 13298471Sache 13308471Sache case DMBIC: 13318471Sache if (bits & TIOCM_DTR) 1332105806Sjhb rcout(sc, RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); 1333105806Sjhb msvr = rcin(sc, CD180_MSVR); 13348471Sache if (bits & TIOCM_RTS) 13359232Sache msvr &= ~MSVR_RTS; 13369232Sache if (bits & TIOCM_DTR) 13379232Sache msvr &= ~MSVR_DTR; 1338105806Sjhb rcout(sc, CD180_MSVR, msvr); 13398471Sache break; 13408471Sache } 1341105806Sjhb rc->rc_msvr = rcin(sc, CD180_MSVR); 13428471Sache return 0; 13438471Sache} 13448471Sache 1345105806Sjhb#define ERR(s) do { \ 1346105806Sjhb device_printf(sc->sc_dev, "%s", ""); \ 1347105806Sjhb printf s ; \ 1348105806Sjhb printf("\n"); \ 1349105806Sjhb (void) splx(old_level); \ 1350105806Sjhb return 1; \ 1351105806Sjhb} while (0) 1352105806Sjhb 13538471Sache/* Test the board. */ 1354105806Sjhbint 1355105806Sjhbrc_test(struct rc_softc *sc) 13568471Sache{ 135716322Sgpalmer int chan = 0; 13588471Sache int i = 0, rcnt, old_level; 13598471Sache unsigned int iack, chipid; 13608471Sache unsigned short divs; 13618471Sache static u_char ctest[] = "\377\125\252\045\244\0\377"; 13628471Sache#define CTLEN 8 13638471Sache 13648471Sache struct rtest { 13658471Sache u_char txbuf[CD180_NFIFO]; /* TX buffer */ 13668471Sache u_char rxbuf[CD180_NFIFO]; /* RX buffer */ 13678471Sache int rxptr; /* RX pointer */ 13688471Sache int txptr; /* TX pointer */ 13698471Sache } tchans[CD180_NCHAN]; 13708471Sache 13719232Sache old_level = spltty(); 13728471Sache 13738471Sache chipid = RC_FAKEID; 13748471Sache 13758471Sache /* First, reset board to inital state */ 1376105806Sjhb rc_hwreset(sc, chipid); 13778471Sache 13789232Sache divs = RC_BRD(19200); 13799232Sache 13808471Sache /* Initialize channels */ 13818471Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 13828471Sache 13838471Sache /* Select and reset channel */ 1384105806Sjhb rcout(sc, CD180_CAR, chan); 1385105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 1386105806Sjhb WAITFORCCR(sc, chan); 13878471Sache 13888471Sache /* Set speed */ 1389105806Sjhb rcout(sc, CD180_RBPRL, divs & 0xFF); 1390105806Sjhb rcout(sc, CD180_RBPRH, divs >> 8); 1391105806Sjhb rcout(sc, CD180_TBPRL, divs & 0xFF); 1392105806Sjhb rcout(sc, CD180_TBPRH, divs >> 8); 13938471Sache 13948471Sache /* set timeout value */ 1395105806Sjhb rcout(sc, CD180_RTPR, 0); 13968471Sache 13978471Sache /* Establish local loopback */ 1398105806Sjhb rcout(sc, CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); 1399105806Sjhb rcout(sc, CD180_COR2, COR2_LLM); 1400105806Sjhb rcout(sc, CD180_COR3, CD180_NFIFO); 1401105806Sjhb CCRCMD(sc, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1402105806Sjhb CCRCMD(sc, chan, CCR_RCVREN | CCR_XMTREN); 1403105806Sjhb WAITFORCCR(sc, chan); 1404105806Sjhb rcout(sc, CD180_MSVR, MSVR_RTS); 14058471Sache 14068471Sache /* Fill TXBUF with test data */ 14078471Sache for (i = 0; i < CD180_NFIFO; i++) { 14088471Sache tchans[chan].txbuf[i] = ctest[i]; 14098471Sache tchans[chan].rxbuf[i] = 0; 14108471Sache } 14118471Sache tchans[chan].txptr = tchans[chan].rxptr = 0; 14128471Sache 14138471Sache /* Now, start transmit */ 1414105806Sjhb rcout(sc, CD180_IER, IER_TxMpty|IER_RxData); 14158471Sache } 14168471Sache /* Pseudo-interrupt poll stuff */ 14178471Sache for (rcnt = 10000; rcnt-- > 0; rcnt--) { 1418105806Sjhb i = ~(rcin(sc, RC_BSR)); 14198471Sache if (i & RC_BSR_TOUT) 1420105806Sjhb ERR(("BSR timeout bit set\n")); 14219232Sache else if (i & RC_BSR_TXINT) { 1422105806Sjhb iack = rcin(sc, RC_PILR_TX); 14238471Sache if (iack != (GIVR_IT_TDI | chipid)) 14248471Sache ERR(("Bad TX intr ack (%02x != %02x)\n", 14258471Sache iack, GIVR_IT_TDI | chipid)); 1426105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 14278471Sache /* If no more data to transmit, disable TX intr */ 14288471Sache if (tchans[chan].txptr >= CD180_NFIFO) { 1429105806Sjhb iack = rcin(sc, CD180_IER); 1430105806Sjhb rcout(sc, CD180_IER, iack & ~IER_TxMpty); 14318471Sache } else { 14328471Sache for (iack = tchans[chan].txptr; 14338471Sache iack < CD180_NFIFO; iack++) 1434105806Sjhb rcout(sc, CD180_TDR, 14358471Sache tchans[chan].txbuf[iack]); 14368471Sache tchans[chan].txptr = iack; 14378471Sache } 1438105806Sjhb rcout(sc, CD180_EOIR, 0); 14399232Sache } else if (i & RC_BSR_RXINT) { 14409232Sache u_char ucnt; 14418471Sache 1442105806Sjhb iack = rcin(sc, RC_PILR_RX); 14438471Sache if (iack != (GIVR_IT_RGDI | chipid) && 14448471Sache iack != (GIVR_IT_REI | chipid)) 14458471Sache ERR(("Bad RX intr ack (%02x != %02x)\n", 1446105806Sjhb iack, GIVR_IT_RGDI | chipid)); 1447105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1448105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 14498471Sache while (ucnt-- > 0) { 1450105806Sjhb iack = rcin(sc, CD180_RCSR); 14519232Sache if (iack & RCSR_Timeout) 14528471Sache break; 14538471Sache if (iack & 0xF) 14548471Sache ERR(("Bad char chan %d (RCSR = %02X)\n", 1455105806Sjhb chan, iack)); 14568471Sache if (tchans[chan].rxptr > CD180_NFIFO) 14578471Sache ERR(("Got extra chars chan %d\n", 1458105806Sjhb chan)); 14598471Sache tchans[chan].rxbuf[tchans[chan].rxptr++] = 1460105806Sjhb rcin(sc, CD180_RDR); 14618471Sache } 1462105806Sjhb rcout(sc, CD180_EOIR, 0); 14638471Sache } 1464105806Sjhb rcout(sc, RC_CTOUT, 0); 14658471Sache for (iack = chan = 0; chan < CD180_NCHAN; chan++) 14668471Sache if (tchans[chan].rxptr >= CD180_NFIFO) 14678471Sache iack++; 14688471Sache if (iack == CD180_NCHAN) 14698471Sache break; 14708471Sache } 14719232Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 14729232Sache /* Select and reset channel */ 1473105806Sjhb rcout(sc, CD180_CAR, chan); 1474105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 14759232Sache } 14769232Sache 14778471Sache if (!rcnt) 1478105806Sjhb ERR(("looses characters during local loopback\n")); 14798471Sache /* Now, check data */ 14808471Sache for (chan = 0; chan < CD180_NCHAN; chan++) 14818471Sache for (i = 0; i < CD180_NFIFO; i++) 14828471Sache if (ctest[i] != tchans[chan].rxbuf[i]) 14838471Sache ERR(("data mismatch chan %d ptr %d (%d != %d)\n", 1484105806Sjhb chan, i, ctest[i], tchans[chan].rxbuf[i])); 14858471Sache (void) splx(old_level); 14868471Sache return 0; 14878471Sache} 14888471Sache 14898471Sache#ifdef RCDEBUG 1490105806Sjhbstatic void 1491105806Sjhbprintrcflags(struct rc_chans *rc, char *comment) 14928471Sache{ 1493105806Sjhb struct rc_softc *sc; 14948471Sache u_short f = rc->rc_flags; 14958471Sache 1496105806Sjhb sc = rc->rc_rcb; 14979232Sache printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", 14988471Sache rc->rc_rcb->rcb_unit, rc->rc_chan, comment, 14998471Sache (f & RC_DTR_OFF)?"DTR_OFF " :"", 15009232Sache (f & RC_ACTOUT) ?"ACTOUT " :"", 15019232Sache (f & RC_RTSFLOW)?"RTSFLOW " :"", 15029232Sache (f & RC_CTSFLOW)?"CTSFLOW " :"", 15039232Sache (f & RC_DORXFER)?"DORXFER " :"", 15049232Sache (f & RC_DOXXFER)?"DOXXFER " :"", 15059232Sache (f & RC_MODCHG) ?"MODCHG " :"", 15069232Sache (f & RC_OSUSP) ?"OSUSP " :"", 15079232Sache (f & RC_OSBUSY) ?"OSBUSY " :"", 15089232Sache (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", 15099232Sache (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", 15109232Sache (f & RC_SEND_RDY) ?"SEND_RDY":""); 15119232Sache 1512105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 15139232Sache 15149232Sache printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", 15159232Sache rc->rc_rcb->rcb_unit, rc->rc_chan, 1516105806Sjhb rcin(sc, CD180_MSVR), 1517105806Sjhb rcin(sc, CD180_IER), 1518105806Sjhb rcin(sc, CD180_CCSR)); 15198471Sache} 15208471Sache#endif /* RCDEBUG */ 15218471Sache 15228471Sachestatic void 1523105806Sjhbrc_dtrwakeup(void *arg) 15248471Sache{ 15258471Sache struct rc_chans *rc; 15268471Sache 1527105806Sjhb rc = (struct rc_chans *)arg; 15288471Sache rc->rc_flags &= ~RC_DTR_OFF; 15298471Sache wakeup(&rc->rc_dtrwait); 15308471Sache} 15318471Sache 15328471Sachestatic void 1533105806Sjhbrc_discard_output(struct rc_chans *rc) 15348471Sache{ 1535106653Sjhb critical_enter(); 15368471Sache if (rc->rc_flags & RC_DOXXFER) { 1537105806Sjhb rc->rc_rcb->sc_scheduled_event -= LOTS_OF_EVENTS; 15388471Sache rc->rc_flags &= ~RC_DOXXFER; 15398471Sache } 15408471Sache rc->rc_optr = rc->rc_obufend; 1541105806Sjhb rc->rc_tp.t_state &= ~TS_BUSY; 1542106653Sjhb critical_exit(); 1543105806Sjhb ttwwakeup(&rc->rc_tp); 15448471Sache} 15458471Sache 15468471Sachestatic void 1547105806Sjhbdisc_optim(struct tty *tp, struct termios *t, struct rc_chans *rc) 15488471Sache{ 15498471Sache 15509757Sbde if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 15518471Sache && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 15529757Sbde && (!(t->c_iflag & PARMRK) 15539757Sbde || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 15549757Sbde && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 15558471Sache && linesw[tp->t_line].l_rint == ttyinput) 15568471Sache tp->t_state |= TS_CAN_BYPASS_L_RINT; 15578471Sache else 15588471Sache tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 155933322Sphk rc->rc_hotchar = linesw[tp->t_line].l_hotchar; 15608471Sache} 15619232Sache 15629232Sachestatic void 1563105806Sjhbrc_wait0(struct rc_softc *sc, int chan, int line) 15649232Sache{ 15659232Sache int rcnt; 15669232Sache 1567105806Sjhb for (rcnt = 50; rcnt && rcin(sc, CD180_CCR); rcnt--) 156814441Srgrimes DELAY(30); 15699232Sache if (rcnt == 0) 1570105806Sjhb device_printf(sc->sc_dev, 1571105806Sjhb "channel %d command timeout, rc.c line: %d\n", chan, line); 15729232Sache} 1573105806Sjhb 1574105806Sjhbstatic device_method_t rc_methods[] = { 1575105806Sjhb /* Device interface */ 1576105806Sjhb DEVMETHOD(device_probe, rc_probe), 1577105806Sjhb DEVMETHOD(device_attach, rc_attach), 1578105806Sjhb DEVMETHOD(device_detach, rc_detach), 1579105806Sjhb { 0, 0 } 1580105806Sjhb}; 1581105806Sjhb 1582105806Sjhbstatic driver_t rc_driver = { 1583105806Sjhb "rc", 1584105806Sjhb rc_methods, sizeof(struct rc_softc), 1585105806Sjhb}; 1586105806Sjhb 1587105806SjhbDRIVER_MODULE(rc, isa, rc_driver, rc_devclass, 0, 0); 1588