rc.c revision 118607
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 118607 2003-08-07 15:04:27Z jhb $ 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> 48105806Sjhb#include <sys/tty.h> 49105806Sjhb#include <machine/bus.h> 50105806Sjhb#include <machine/resource.h> 51105806Sjhb#include <sys/rman.h> 5266824Sbde 53105806Sjhb#include <dev/ic/cd180.h> 54105806Sjhb#include <dev/rc/rcreg.h> 55105806Sjhb#include <isa/isavar.h> 568471Sache 57105806Sjhb#define IOBASE_ADDRS 14 588471Sache 59105806Sjhb#define DEV_TO_RC(dev) (struct rc_chans *)((dev)->si_drv1) 60105806Sjhb#define TTY_TO_RC(tty) DEV_TO_RC((tty)->t_dev) 618471Sache 62105806Sjhb#define rcin(sc, port) RC_IN(sc, port) 63105806Sjhb#define rcout(sc, port, v) RC_OUT(sc, port, v) 648471Sache 65105806Sjhb#define WAITFORCCR(sc, chan) rc_wait0((sc), (chan), __LINE__) 668471Sache 67105806Sjhb#define CCRCMD(sc, chan, cmd) do { \ 68105806Sjhb WAITFORCCR((sc), (chan)); \ 69105806Sjhb rcout((sc), CD180_CCR, (cmd)); \ 70105806Sjhb} while (0) 718471Sache 729232Sache#define RC_IBUFSIZE 256 739232Sache#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE) 749232Sache#define RC_OBUFSIZE 512 758471Sache#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4) 768471Sache#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE) 778471Sache#define LOTS_OF_EVENTS 64 788471Sache 798471Sache#define RC_FAKEID 0x10 808471Sache 81105960Sjhb#define CALLOUT(dev) (((intptr_t)(dev)->si_drv2) != 0) 829232Sache 83105806Sjhb/* Per-channel structure */ 84105806Sjhbstruct rc_chans { 85105806Sjhb struct rc_softc *rc_rcb; /* back ptr */ 86105806Sjhb dev_t rc_dev; /* non-callout device */ 87105806Sjhb dev_t rc_cdev; /* callout device */ 88105806Sjhb u_short rc_flags; /* Misc. flags */ 89105806Sjhb int rc_chan; /* Channel # */ 90105806Sjhb u_char rc_ier; /* intr. enable reg */ 91105806Sjhb u_char rc_msvr; /* modem sig. status */ 92105806Sjhb u_char rc_cor2; /* options reg */ 93105806Sjhb u_char rc_pendcmd; /* special cmd pending */ 94105806Sjhb u_int rc_dtrwait; /* dtr timeout */ 95105806Sjhb u_int rc_dcdwaits; /* how many waits DCD in open */ 96105806Sjhb u_char rc_hotchar; /* end packed optimize */ 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 */ 126105806Sjhbstatic void rc_release_resources(device_t dev); 127105806Sjhbstatic void rc_intr(void *); 128105806Sjhbstatic void rc_hwreset(struct rc_softc *, unsigned int); 129105806Sjhbstatic int rc_test(struct rc_softc *); 130105806Sjhbstatic void rc_discard_output(struct rc_chans *); 131105806Sjhbstatic void rc_hardclose(struct rc_chans *); 132105806Sjhbstatic int rc_modctl(struct rc_chans *, int, int); 133105806Sjhbstatic void rc_start(struct tty *); 134105806Sjhbstatic void rc_stop(struct tty *, int rw); 135105806Sjhbstatic int rc_param(struct tty *, struct termios *); 136105806Sjhbstatic void rc_pollcard(void *); 137105806Sjhbstatic void rc_reinit(struct rc_softc *); 138105806Sjhb#ifdef RCDEBUG 139105806Sjhbstatic void printrcflags(); 140105806Sjhb#endif 141105806Sjhbstatic void rc_dtrwakeup(void *); 142105806Sjhbstatic void disc_optim(struct tty *tp, struct termios *t, struct rc_chans *); 143105806Sjhbstatic void rc_wait0(struct rc_softc *sc, int chan, int line); 144105806Sjhb 14512675Sjulianstatic d_open_t rcopen; 14612675Sjulianstatic d_close_t rcclose; 14712675Sjulianstatic d_ioctl_t rcioctl; 14812675Sjulian 14938485Sbde#define CDEV_MAJOR 63 15047625Sphkstatic struct cdevsw rc_cdevsw = { 151111815Sphk .d_open = rcopen, 152111815Sphk .d_close = rcclose, 153111815Sphk .d_read = ttyread, 154111815Sphk .d_write = ttywrite, 155111815Sphk .d_ioctl = rcioctl, 156111815Sphk .d_poll = ttypoll, 157111815Sphk .d_name = "rc", 158111815Sphk .d_maj = CDEV_MAJOR, 159111821Sphk .d_flags = D_TTY, 160111815Sphk .d_kqfilter = ttykqfilter, 16138485Sbde}; 16212675Sjulian 163105806Sjhbstatic devclass_t rc_devclass; 1648471Sache 1658471Sache/* Flags */ 1669232Sache#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */ 1679232Sache#define RC_ACTOUT 0x0002 /* Dial-out port active */ 1689232Sache#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */ 1699232Sache#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */ 1709232Sache#define RC_DORXFER 0x0010 /* RXFER event planned */ 1719232Sache#define RC_DOXXFER 0x0020 /* XXFER event planned */ 1729232Sache#define RC_MODCHG 0x0040 /* Modem status changed */ 1739232Sache#define RC_OSUSP 0x0080 /* Output suspended */ 1749232Sache#define RC_OSBUSY 0x0100 /* start() routine in progress */ 1759232Sache#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */ 1769232Sache#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */ 1779232Sache#define RC_SEND_RDY 0x0800 /* ready to send */ 1788471Sache 1798471Sache/* Table for translation of RCSR status bits to internal form */ 1808471Sachestatic int rc_rcsrt[16] = { 1818471Sache 0, TTY_OE, TTY_FE, 1828471Sache TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE, 1838471Sache TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI, 1848471Sache TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE, 1858471Sache TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE, 1868471Sache TTY_BI|TTY_PE|TTY_FE|TTY_OE 1878471Sache}; 1888471Sache 189105806Sjhbstatic int rc_ports[] = 190105806Sjhb { 0x220, 0x240, 0x250, 0x260, 0x2a0, 0x2b0, 0x300, 0x320 }; 191105806Sjhbstatic int iobase_addrs[IOBASE_ADDRS] = 192105806Sjhb { 0, 0x400, 0x800, 0xc00, 0x1400, 0x1800, 0x1c00, 0x2000, 193105806Sjhb 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000, 0x8000 }; 19467551Sjhb 1958471Sache/**********************************************/ 1968471Sache 19712724Sphkstatic int 198105806Sjhbrc_probe(device_t dev) 1998471Sache{ 200105806Sjhb u_int port; 201105806Sjhb int i, found; 2028471Sache 203105806Sjhb /* 204105806Sjhb * We don't know of any PnP ID's for these cards. 205105806Sjhb */ 206105806Sjhb if (isa_get_logicalid(dev) != 0) 207105806Sjhb return (ENXIO); 2089232Sache 209105806Sjhb /* 210105806Sjhb * We have to have an IO port hint that is valid. 211105806Sjhb */ 212105806Sjhb port = isa_get_port(dev); 213105806Sjhb if (port == -1) 214105806Sjhb return (ENXIO); 215105806Sjhb found = 0; 216105806Sjhb for (i = 0; i < sizeof(rc_ports) / sizeof(int); i++) 217105806Sjhb if (rc_ports[i] == port) { 218105806Sjhb found = 1; 219105806Sjhb break; 220105806Sjhb } 221105806Sjhb if (!found) 222105806Sjhb return (ENXIO); 223105806Sjhb 224105806Sjhb /* 225105806Sjhb * We have to have an IRQ hint. 226105806Sjhb */ 227105806Sjhb if (isa_get_irq(dev) == -1) 228105806Sjhb return (ENXIO); 229105806Sjhb 230105806Sjhb device_set_desc(dev, "SDL Riscom/8"); 231105806Sjhb return (0); 2328471Sache} 2338471Sache 23412724Sphkstatic int 235105806Sjhbrc_attach(device_t dev) 2368471Sache{ 237105806Sjhb struct rc_chans *rc; 238105806Sjhb struct tty *tp; 239105806Sjhb struct rc_softc *sc; 240105806Sjhb u_int port; 241105806Sjhb int base, chan, error, i, x; 242105806Sjhb dev_t cdev; 2438471Sache 244105806Sjhb sc = device_get_softc(dev); 245105806Sjhb sc->sc_dev = dev; 24640565Sbde 247105806Sjhb /* 248105806Sjhb * We need to have IO ports. Lots of them. We need 249105806Sjhb * the following ranges relative to the base port: 250105806Sjhb * 0x0 - 0x10 251105806Sjhb * 0x400 - 0x410 252105806Sjhb * 0x800 - 0x810 253105806Sjhb * 0xc00 - 0xc10 254105806Sjhb * 0x1400 - 0x1410 255105806Sjhb * 0x1800 - 0x1810 256105806Sjhb * 0x1c00 - 0x1c10 257105806Sjhb * 0x2000 - 0x2010 258105806Sjhb * 0x3000 - 0x3010 259105806Sjhb * 0x3400 - 0x3410 260105806Sjhb * 0x3800 - 0x3810 261105806Sjhb * 0x3c00 - 0x3c10 262105806Sjhb * 0x4000 - 0x4010 263105806Sjhb * 0x8000 - 0x8010 264105806Sjhb */ 265105806Sjhb port = isa_get_port(dev); 266105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) 267105806Sjhb if (bus_set_resource(dev, SYS_RES_IOPORT, i, 268105806Sjhb port + iobase_addrs[i], 0x10) != 0) 269105806Sjhb return (ENXIO); 270105806Sjhb error = ENOMEM; 271105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 272105806Sjhb x = i; 273105806Sjhb sc->sc_port[i] = bus_alloc_resource(dev, SYS_RES_IOPORT, &x, 274105806Sjhb 0ul, ~0ul, 0x10, RF_ACTIVE); 275105806Sjhb if (x != i) { 276105806Sjhb device_printf(dev, "ioport %d was rid %d\n", i, x); 277105806Sjhb goto fail; 278105806Sjhb } 279105806Sjhb if (sc->sc_port[i] == NULL) { 280105806Sjhb device_printf(dev, "failed to alloc ioports %x-%x\n", 281105806Sjhb port + iobase_addrs[i], 282105806Sjhb port + iobase_addrs[i] + 0x10); 283105806Sjhb goto fail; 284105806Sjhb } 285105806Sjhb } 286105806Sjhb sc->sc_bt = rman_get_bustag(sc->sc_port[0]); 287105806Sjhb sc->sc_bh = rman_get_bushandle(sc->sc_port[0]); 2888471Sache 289105806Sjhb sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_irqrid, 290105806Sjhb 0ul, ~0ul, 1, RF_ACTIVE); 291105806Sjhb if (sc->sc_irq == NULL) { 292105806Sjhb device_printf(dev, "failed to alloc IRQ\n"); 293105806Sjhb goto fail; 294105806Sjhb } 295105806Sjhb 296105806Sjhb /* 297105806Sjhb * Now do some actual tests to make sure it works. 298105806Sjhb */ 299105806Sjhb error = ENXIO; 300105806Sjhb rcout(sc, CD180_PPRL, 0x22); /* Random values to Prescale reg. */ 301105806Sjhb rcout(sc, CD180_PPRH, 0x11); 302105806Sjhb if (rcin(sc, CD180_PPRL) != 0x22 || rcin(sc, CD180_PPRH) != 0x11) 303105806Sjhb goto fail; 304105806Sjhb if (rc_test(sc)) 305105806Sjhb goto fail; 306105806Sjhb 307105806Sjhb /* 308105806Sjhb * Ok, start actually hooking things up. 309105806Sjhb */ 310105806Sjhb sc->sc_unit = device_get_unit(dev); 311105806Sjhb /*sc->sc_chipid = 0x10 + device_get_unit(dev);*/ 312105806Sjhb device_printf(dev, "%d chans, firmware rev. %c\n", 313105806Sjhb CD180_NCHAN, (rcin(sc, CD180_GFRCR) & 0xF) + 'A'); 314105806Sjhb rc = sc->sc_channels; 315105806Sjhb base = CD180_NCHAN * sc->sc_unit; 3168471Sache for (chan = 0; chan < CD180_NCHAN; chan++, rc++) { 317105806Sjhb rc->rc_rcb = sc; 3188471Sache rc->rc_chan = chan; 3198471Sache rc->rc_iptr = rc->rc_ibuf; 3208471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 3218471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 3228471Sache rc->rc_optr = rc->rc_obufend = rc->rc_obuf; 3238471Sache rc->rc_dtrwait = 3 * hz; 324105806Sjhb callout_init(&rc->rc_dtrcallout, 0); 325105806Sjhb tp = &rc->rc_tp; 3269232Sache ttychars(tp); 3279232Sache tp->t_lflag = tp->t_iflag = tp->t_oflag = 0; 3289232Sache tp->t_cflag = TTYDEF_CFLAG; 3299232Sache tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 330105806Sjhb cdev = make_dev(&rc_cdevsw, chan + base, 331105806Sjhb UID_ROOT, GID_WHEEL, 0600, "ttym%d", chan + base); 332105806Sjhb cdev->si_drv1 = rc; 333105806Sjhb cdev->si_drv2 = 0; 334105806Sjhb cdev->si_tty = tp; 335105806Sjhb rc->rc_dev = cdev; 336105806Sjhb cdev = make_dev(&rc_cdevsw, chan + base + 128, 337105806Sjhb UID_UUCP, GID_DIALER, 0660, "cuam%d", chan + base); 338105806Sjhb cdev->si_drv1 = rc; 339105806Sjhb cdev->si_drv2 = (void *)1; 340105806Sjhb cdev->si_tty = tp; 341105806Sjhb rc->rc_cdev = cdev; 3428471Sache } 343105806Sjhb 344105806Sjhb error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_TTY, rc_intr, sc, 345105806Sjhb &sc->sc_hwicookie); 346105806Sjhb if (error) { 347105806Sjhb device_printf(dev, "failed to register interrupt handler\n"); 348105806Sjhb goto fail; 3498471Sache } 350105806Sjhb 351105806Sjhb swi_add(&tty_ithd, "tty:rc", rc_pollcard, sc, SWI_TTY, 0, 352105806Sjhb &sc->sc_swicookie); 353105806Sjhb return (0); 354105806Sjhb 355105806Sjhbfail: 356105806Sjhb rc_release_resources(dev); 357105806Sjhb return (error); 3588471Sache} 3598471Sache 360105806Sjhbstatic int 361105806Sjhbrc_detach(device_t dev) 362105806Sjhb{ 363105806Sjhb struct rc_softc *sc; 364105806Sjhb struct rc_chans *rc; 365105806Sjhb int error, i, s; 366105806Sjhb 367105806Sjhb sc = device_get_softc(dev); 368105806Sjhb if (sc->sc_opencount > 0) 369105806Sjhb return (EBUSY); 370105806Sjhb sc->sc_opencount = -1; 371105806Sjhb 372105806Sjhb rc = sc->sc_channels; 373105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) { 374105806Sjhb destroy_dev(rc->rc_dev); 375105806Sjhb destroy_dev(rc->rc_cdev); 376105806Sjhb } 377105806Sjhb 378105806Sjhb rc = sc->sc_channels; 379105806Sjhb s = splsoftclock(); 380105806Sjhb for (i = 0; i < CD180_NCHAN; i++) { 381105806Sjhb if ((rc->rc_flags & RC_DTR_OFF) && 382105806Sjhb !callout_stop(&rc->rc_dtrcallout)) 383105806Sjhb tsleep(&rc->rc_dtrwait, TTIPRI, "rcdtrdet", 0); 384105806Sjhb } 385105806Sjhb 386105806Sjhb error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_hwicookie); 387105806Sjhb if (error) 388105806Sjhb device_printf(dev, "failed to deregister interrupt handler\n"); 389105806Sjhb ithread_remove_handler(sc->sc_swicookie); 390105806Sjhb rc_release_resources(dev); 391105806Sjhb 392105806Sjhb return (0); 393105806Sjhb} 394105806Sjhb 39540565Sbdestatic void 396105806Sjhbrc_release_resources(device_t dev) 3978471Sache{ 398105806Sjhb struct rc_softc *sc; 399105806Sjhb int i; 4008471Sache 401105806Sjhb sc = device_get_softc(dev); 402105806Sjhb if (sc->sc_irq != NULL) { 403105806Sjhb bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, 404105806Sjhb sc->sc_irq); 405105806Sjhb sc->sc_irq = NULL; 4069232Sache } 407105806Sjhb for (i = 0; i < IOBASE_ADDRS; i++) { 408105806Sjhb if (sc->sc_port[i] == NULL) 409105806Sjhb break; 410105806Sjhb bus_release_resource(dev, SYS_RES_IOPORT, i, sc->sc_port[i]); 411105806Sjhb sc->sc_port[i] = NULL; 412105806Sjhb } 413105806Sjhb} 4148471Sache 415105806Sjhb/* RC interrupt handling */ 416105806Sjhbstatic void 417105806Sjhbrc_intr(void *arg) 418105806Sjhb{ 419105806Sjhb struct rc_softc *sc; 420105806Sjhb struct rc_chans *rc; 421105806Sjhb int resid, chan; 422105806Sjhb u_char val, iack, bsr, ucnt, *optr; 423105806Sjhb int good_data, t_state; 4248471Sache 425105806Sjhb sc = (struct rc_softc *)arg; 426105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 4279232Sache if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) { 428105806Sjhb device_printf(sc->sc_dev, "extra interrupt\n"); 429105806Sjhb rcout(sc, CD180_EOIR, 0); 4309232Sache return; 4319232Sache } 4329232Sache 4339232Sache while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) { 4349232Sache#ifdef RCDEBUG_DETAILED 435105806Sjhb device_printf(sc->sc_dev, "intr (%p) %s%s%s%s\n", arg, bsr, 4369232Sache (bsr & RC_BSR_TOUT)?"TOUT ":"", 4379232Sache (bsr & RC_BSR_RXINT)?"RXINT ":"", 4389232Sache (bsr & RC_BSR_TXINT)?"TXINT ":"", 4399232Sache (bsr & RC_BSR_MOINT)?"MOINT":""); 4408471Sache#endif 4419232Sache if (bsr & RC_BSR_TOUT) { 442105806Sjhb device_printf(sc->sc_dev, 443105806Sjhb "hardware failure, reset board\n"); 444105806Sjhb rcout(sc, RC_CTOUT, 0); 445105806Sjhb rc_reinit(sc); 4469232Sache return; 4478471Sache } 4489232Sache if (bsr & RC_BSR_RXINT) { 449105806Sjhb iack = rcin(sc, RC_PILR_RX); 4509232Sache good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID)); 4519232Sache if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) { 452105806Sjhb device_printf(sc->sc_dev, 453105806Sjhb "fake rxint: %02x\n", iack); 4549232Sache goto more_intrs; 4559232Sache } 456105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 457105806Sjhb rc = &sc->sc_channels[chan]; 458105806Sjhb t_state = rc->rc_tp.t_state; 4599232Sache /* Do RTS flow control stuff */ 4609232Sache if ( (rc->rc_flags & RC_RTSFLOW) 4619232Sache || !(t_state & TS_ISOPEN) 4629232Sache ) { 4639232Sache if ( ( !(t_state & TS_ISOPEN) 4649232Sache || (t_state & TS_TBLOCK) 4659232Sache ) 4669232Sache && (rc->rc_msvr & MSVR_RTS) 4679232Sache ) 468105806Sjhb rcout(sc, CD180_MSVR, 4699232Sache rc->rc_msvr &= ~MSVR_RTS); 4709232Sache else if (!(rc->rc_msvr & MSVR_RTS)) 471105806Sjhb rcout(sc, CD180_MSVR, 4729232Sache rc->rc_msvr |= MSVR_RTS); 4739232Sache } 474105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 4759232Sache resid = 0; 4768471Sache 4779232Sache if (t_state & TS_ISOPEN) { 4789232Sache /* check for input buffer overflow */ 4799232Sache if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) { 4809232Sache resid = ucnt; 4819232Sache ucnt = rc->rc_bufend - rc->rc_iptr; 4829232Sache resid -= ucnt; 4839232Sache if (!(rc->rc_flags & RC_WAS_BUFOVFL)) { 4849232Sache rc->rc_flags |= RC_WAS_BUFOVFL; 485105806Sjhb sc->sc_scheduled_event++; 4869232Sache } 4878471Sache } 4889232Sache optr = rc->rc_iptr; 4899232Sache /* check foor good data */ 4909232Sache if (good_data) { 4919232Sache while (ucnt-- > 0) { 492105806Sjhb val = rcin(sc, CD180_RDR); 4939232Sache optr[0] = val; 4949232Sache optr[INPUT_FLAGS_SHIFT] = 0; 4959232Sache optr++; 496105806Sjhb sc->sc_scheduled_event++; 4979232Sache if (val != 0 && val == rc->rc_hotchar) 498105806Sjhb swi_sched(sc->sc_swicookie, 0); 4998471Sache } 5009232Sache } else { 5019232Sache /* Store also status data */ 5029232Sache while (ucnt-- > 0) { 503105806Sjhb iack = rcin(sc, CD180_RCSR); 5049232Sache if (iack & RCSR_Timeout) 5059232Sache break; 5069232Sache if ( (iack & RCSR_OE) 5079232Sache && !(rc->rc_flags & RC_WAS_SILOVFL)) { 5089232Sache rc->rc_flags |= RC_WAS_SILOVFL; 509105806Sjhb sc->sc_scheduled_event++; 5109232Sache } 511105806Sjhb val = rcin(sc, CD180_RDR); 5129232Sache /* 5139232Sache Don't store PE if IGNPAR and BREAK if IGNBRK, 5149232Sache this hack allows "raw" tty optimization 5159232Sache works even if IGN* is set. 5169232Sache */ 5179232Sache if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break)) 51846704Speter || ((!(iack & (RCSR_PE|RCSR_FE)) 519105806Sjhb || !(rc->rc_tp.t_iflag & IGNPAR)) 5209232Sache && (!(iack & RCSR_Break) 521105806Sjhb || !(rc->rc_tp.t_iflag & IGNBRK)))) { 5229232Sache if ( (iack & (RCSR_PE|RCSR_FE)) 5239232Sache && (t_state & TS_CAN_BYPASS_L_RINT) 5249232Sache && ((iack & RCSR_FE) 52546704Speter || ((iack & RCSR_PE) 526105806Sjhb && (rc->rc_tp.t_iflag & INPCK)))) 5279232Sache val = 0; 5289232Sache else if (val != 0 && val == rc->rc_hotchar) 529105806Sjhb swi_sched(sc->sc_swicookie, 0); 5309232Sache optr[0] = val; 5319232Sache optr[INPUT_FLAGS_SHIFT] = iack; 5329232Sache optr++; 533105806Sjhb sc->sc_scheduled_event++; 5349232Sache } 5359232Sache } 5368471Sache } 5379232Sache rc->rc_iptr = optr; 5389232Sache rc->rc_flags |= RC_DORXFER; 5399232Sache } else 5409232Sache resid = ucnt; 5419232Sache /* Clear FIFO if necessary */ 5429232Sache while (resid-- > 0) { 5439232Sache if (!good_data) 544105806Sjhb iack = rcin(sc, CD180_RCSR); 5459232Sache else 5469232Sache iack = 0; 5479232Sache if (iack & RCSR_Timeout) 5489232Sache break; 549105806Sjhb (void) rcin(sc, CD180_RDR); 5508471Sache } 5519232Sache goto more_intrs; 5528471Sache } 5539232Sache if (bsr & RC_BSR_MOINT) { 554105806Sjhb iack = rcin(sc, RC_PILR_MODEM); 5559232Sache if (iack != (GIVR_IT_MSCI | RC_FAKEID)) { 556105806Sjhb device_printf(sc->sc_dev, "fake moint: %02x\n", 557105806Sjhb iack); 5589232Sache goto more_intrs; 5599232Sache } 560105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 561105806Sjhb rc = &sc->sc_channels[chan]; 562105806Sjhb iack = rcin(sc, CD180_MCR); 563105806Sjhb rc->rc_msvr = rcin(sc, CD180_MSVR); 564105806Sjhb rcout(sc, CD180_MCR, 0); 5658471Sache#ifdef RCDEBUG 5669232Sache printrcflags(rc, "moint"); 5678471Sache#endif 5689232Sache if (rc->rc_flags & RC_CTSFLOW) { 5699232Sache if (rc->rc_msvr & MSVR_CTS) 5709232Sache rc->rc_flags |= RC_SEND_RDY; 5719232Sache else 5729232Sache rc->rc_flags &= ~RC_SEND_RDY; 5739232Sache } else 5748471Sache rc->rc_flags |= RC_SEND_RDY; 5759232Sache if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) { 576105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 5779232Sache rc->rc_flags |= RC_MODCHG; 578105806Sjhb swi_sched(sc->sc_swicookie, 0); 5799232Sache } 5809232Sache goto more_intrs; 5818471Sache } 5829232Sache if (bsr & RC_BSR_TXINT) { 583105806Sjhb iack = rcin(sc, RC_PILR_TX); 5849232Sache if (iack != (GIVR_IT_TDI | RC_FAKEID)) { 585105806Sjhb device_printf(sc->sc_dev, "fake txint: %02x\n", 586105806Sjhb iack); 5879232Sache goto more_intrs; 5889232Sache } 589105806Sjhb chan = ((rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH); 590105806Sjhb rc = &sc->sc_channels[chan]; 5919232Sache if ( (rc->rc_flags & RC_OSUSP) 5929232Sache || !(rc->rc_flags & RC_SEND_RDY) 5939232Sache ) 5949232Sache goto more_intrs; 5959232Sache /* Handle breaks and other stuff */ 5969232Sache if (rc->rc_pendcmd) { 597105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 |= COR2_ETC); 598105806Sjhb rcout(sc, CD180_TDR, CD180_C_ESC); 599105806Sjhb rcout(sc, CD180_TDR, rc->rc_pendcmd); 600105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 &= ~COR2_ETC); 6019232Sache rc->rc_pendcmd = 0; 6029232Sache goto more_intrs; 6039232Sache } 6049232Sache optr = rc->rc_optr; 6059232Sache resid = rc->rc_obufend - optr; 6069232Sache if (resid > CD180_NFIFO) 6079232Sache resid = CD180_NFIFO; 6089232Sache while (resid-- > 0) 609105806Sjhb rcout(sc, CD180_TDR, *optr++); 6109232Sache rc->rc_optr = optr; 6118471Sache 6129232Sache /* output completed? */ 6139232Sache if (optr >= rc->rc_obufend) { 614105806Sjhb rcout(sc, CD180_IER, rc->rc_ier &= ~IER_TxRdy); 6158471Sache#ifdef RCDEBUG 616105806Sjhb device_printf(sc->sc_dev, 617105806Sjhb "channel %d: output completed\n", 618105806Sjhb rc->rc_chan); 6198471Sache#endif 6209232Sache if (!(rc->rc_flags & RC_DOXXFER)) { 621105806Sjhb sc->sc_scheduled_event += LOTS_OF_EVENTS; 6229232Sache rc->rc_flags |= RC_DOXXFER; 623105806Sjhb swi_sched(sc->sc_swicookie, 0); 6249232Sache } 6259232Sache } 6268471Sache } 6279232Sache more_intrs: 628105806Sjhb rcout(sc, CD180_EOIR, 0); /* end of interrupt */ 629105806Sjhb rcout(sc, RC_CTOUT, 0); 630105806Sjhb bsr = ~(rcin(sc, RC_BSR)); 6318471Sache } 6328471Sache} 6338471Sache 6348471Sache/* Feed characters to output buffer */ 635105806Sjhbstatic void 636105806Sjhbrc_start(struct tty *tp) 6378471Sache{ 638105806Sjhb struct rc_softc *sc; 639105806Sjhb struct rc_chans *rc; 640105806Sjhb int s; 6418471Sache 642105806Sjhb rc = TTY_TO_RC(tp); 6438471Sache if (rc->rc_flags & RC_OSBUSY) 6448471Sache return; 645105806Sjhb sc = rc->rc_rcb; 6468471Sache s = spltty(); 6478471Sache rc->rc_flags |= RC_OSBUSY; 648106653Sjhb critical_enter(); 6498471Sache if (tp->t_state & TS_TTSTOP) 6508471Sache rc->rc_flags |= RC_OSUSP; 6518471Sache else 6528471Sache rc->rc_flags &= ~RC_OSUSP; 6538471Sache /* Do RTS flow control stuff */ 6549232Sache if ( (rc->rc_flags & RC_RTSFLOW) 6559232Sache && (tp->t_state & TS_TBLOCK) 6569232Sache && (rc->rc_msvr & MSVR_RTS) 6579232Sache ) { 658105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 659105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS); 6609232Sache } else if (!(rc->rc_msvr & MSVR_RTS)) { 661105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 662105806Sjhb rcout(sc, CD180_MSVR, rc->rc_msvr |= MSVR_RTS); 6638471Sache } 664106653Sjhb critical_exit(); 6658471Sache if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 6668471Sache goto out; 6678471Sache#ifdef RCDEBUG 6688471Sache printrcflags(rc, "rcstart"); 6698471Sache#endif 6709626Sbde ttwwakeup(tp); 6718471Sache#ifdef RCDEBUG 6729232Sache printf("rcstart: outq = %d obuf = %d\n", 6738471Sache tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr); 6748471Sache#endif 6759232Sache if (tp->t_state & TS_BUSY) 676105806Sjhb goto out; /* output still in progress ... */ 6778471Sache 6788471Sache if (tp->t_outq.c_cc > 0) { 6798471Sache u_int ocnt; 6808471Sache 6818471Sache tp->t_state |= TS_BUSY; 6828471Sache ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf); 683106653Sjhb critical_enter(); 6848471Sache rc->rc_optr = rc->rc_obuf; 6859232Sache rc->rc_obufend = rc->rc_optr + ocnt; 686106653Sjhb critical_exit(); 6879232Sache if (!(rc->rc_ier & IER_TxRdy)) { 6888471Sache#ifdef RCDEBUG 689105806Sjhb device_printf(sc->sc_dev, 690105806Sjhb "channel %d: rcstart enable txint\n", rc->rc_chan); 6918471Sache#endif 692105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 693105806Sjhb rcout(sc, CD180_IER, rc->rc_ier |= IER_TxRdy); 6948471Sache } 6958471Sache } 6968471Sacheout: 6978471Sache rc->rc_flags &= ~RC_OSBUSY; 6988471Sache (void) splx(s); 6998471Sache} 7008471Sache 7018471Sache/* Handle delayed events. */ 702105806Sjhbvoid 703105806Sjhbrc_pollcard(void *arg) 7048471Sache{ 705105806Sjhb struct rc_softc *sc; 706105806Sjhb struct rc_chans *rc; 707105806Sjhb struct tty *tp; 708105806Sjhb u_char *tptr, *eptr; 709105806Sjhb int chan, icnt; 7108471Sache 711105806Sjhb sc = (struct rc_softc *)arg; 712105806Sjhb if (sc->sc_scheduled_event == 0) 7138471Sache return; 714105806Sjhb do { 715105806Sjhb rc = sc->sc_channels; 7168471Sache for (chan = 0; chan < CD180_NCHAN; rc++, chan++) { 717105806Sjhb tp = &rc->rc_tp; 7188471Sache#ifdef RCDEBUG 7198471Sache if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG| 7208471Sache RC_WAS_BUFOVFL|RC_WAS_SILOVFL)) 7218471Sache printrcflags(rc, "rcevent"); 7228471Sache#endif 7238471Sache if (rc->rc_flags & RC_WAS_BUFOVFL) { 724106653Sjhb critical_enter(); 7258471Sache rc->rc_flags &= ~RC_WAS_BUFOVFL; 726105806Sjhb sc->sc_scheduled_event--; 727106653Sjhb critical_exit(); 728105806Sjhb device_printf(sc->sc_dev, 729105806Sjhb "channel %d: interrupt-level buffer overflow\n", 730105806Sjhb chan); 7318471Sache } 7328471Sache if (rc->rc_flags & RC_WAS_SILOVFL) { 733106653Sjhb critical_enter(); 7348471Sache rc->rc_flags &= ~RC_WAS_SILOVFL; 735105806Sjhb sc->sc_scheduled_event--; 736106653Sjhb critical_exit(); 737105806Sjhb device_printf(sc->sc_dev, 738105806Sjhb "channel %d: silo overflow\n", chan); 7398471Sache } 7408471Sache if (rc->rc_flags & RC_MODCHG) { 741106653Sjhb critical_enter(); 7428471Sache rc->rc_flags &= ~RC_MODCHG; 743105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 744106653Sjhb critical_exit(); 7459232Sache (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD)); 7468471Sache } 7478471Sache if (rc->rc_flags & RC_DORXFER) { 748106653Sjhb critical_enter(); 7498471Sache rc->rc_flags &= ~RC_DORXFER; 7508471Sache eptr = rc->rc_iptr; 7518471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) 7528471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7538471Sache else 7548471Sache tptr = rc->rc_ibuf; 7558471Sache icnt = eptr - tptr; 7568471Sache if (icnt > 0) { 7578471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 7588471Sache rc->rc_iptr = rc->rc_ibuf; 7598471Sache rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE]; 7608471Sache rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER]; 7618471Sache } else { 7628471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 7638471Sache rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE]; 7648471Sache rc->rc_hiwat = 7658471Sache &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER]; 7668471Sache } 7679232Sache if ( (rc->rc_flags & RC_RTSFLOW) 7689232Sache && (tp->t_state & TS_ISOPEN) 7699232Sache && !(tp->t_state & TS_TBLOCK) 7708471Sache && !(rc->rc_msvr & MSVR_RTS) 7719232Sache ) { 772105806Sjhb rcout(sc, CD180_CAR, chan); 773105806Sjhb rcout(sc, CD180_MSVR, 7748471Sache rc->rc_msvr |= MSVR_RTS); 7758471Sache } 776105806Sjhb sc->sc_scheduled_event -= icnt; 7778471Sache } 778106653Sjhb critical_exit(); 7798471Sache 7809232Sache if (icnt <= 0 || !(tp->t_state & TS_ISOPEN)) 7818471Sache goto done1; 7828471Sache 7838471Sache if ( (tp->t_state & TS_CAN_BYPASS_L_RINT) 7848471Sache && !(tp->t_state & TS_LOCAL)) { 7859822Sbde if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER 7869822Sbde && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF)) 7879822Sbde && !(tp->t_state & TS_TBLOCK)) 7889822Sbde ttyblock(tp); 7898471Sache tk_nin += icnt; 7908471Sache tk_rawcc += icnt; 7918471Sache tp->t_rawcc += icnt; 7928471Sache if (b_to_q(tptr, icnt, &tp->t_rawq)) 793105806Sjhb device_printf(sc->sc_dev, 794105806Sjhb "channel %d: tty-level buffer overflow\n", 795105806Sjhb chan); 7968471Sache ttwakeup(tp); 7978471Sache if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY) 7988471Sache || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) { 7998471Sache tp->t_state &= ~TS_TTSTOP; 8008471Sache tp->t_lflag &= ~FLUSHO; 8019754Sbde rc_start(tp); 8028471Sache } 8038471Sache } else { 8048471Sache for (; tptr < eptr; tptr++) 8058471Sache (*linesw[tp->t_line].l_rint) 8068471Sache (tptr[0] | 8078471Sache rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp); 8088471Sache } 80927125Sbdedone1: ; 8108471Sache } 8118471Sache if (rc->rc_flags & RC_DOXXFER) { 812106653Sjhb critical_enter(); 813105806Sjhb sc->sc_scheduled_event -= LOTS_OF_EVENTS; 8149232Sache rc->rc_flags &= ~RC_DOXXFER; 815105806Sjhb rc->rc_tp.t_state &= ~TS_BUSY; 816106653Sjhb critical_exit(); 8178471Sache (*linesw[tp->t_line].l_start)(tp); 8188471Sache } 819111564Sjhb if (sc->sc_scheduled_event == 0) 820111564Sjhb break; 8218471Sache } 822111564Sjhb } while (sc->sc_scheduled_event >= LOTS_OF_EVENTS); 8238471Sache} 8248471Sache 825105806Sjhbstatic void 826105806Sjhbrc_stop(struct tty *tp, int rw) 8278471Sache{ 828105806Sjhb struct rc_softc *sc; 829105806Sjhb struct rc_chans *rc; 8308471Sache u_char *tptr, *eptr; 8318471Sache 832105806Sjhb rc = TTY_TO_RC(tp); 833105806Sjhb sc = rc->rc_rcb; 8348471Sache#ifdef RCDEBUG 835105806Sjhb device_printf(sc->sc_dev, "channel %d: rc_stop %s%s\n", 836105806Sjhb rc->rc_chan, (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":""); 8378471Sache#endif 8388471Sache if (rw & FWRITE) 8398471Sache rc_discard_output(rc); 840106653Sjhb critical_enter(); 8418471Sache if (rw & FREAD) { 8429232Sache rc->rc_flags &= ~RC_DORXFER; 8438471Sache eptr = rc->rc_iptr; 8448471Sache if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) { 8458471Sache tptr = &rc->rc_ibuf[RC_IBUFSIZE]; 8468471Sache rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE]; 8478471Sache } else { 8488471Sache tptr = rc->rc_ibuf; 8498471Sache rc->rc_iptr = rc->rc_ibuf; 8508471Sache } 851105806Sjhb sc->sc_scheduled_event -= eptr - tptr; 8528471Sache } 8538471Sache if (tp->t_state & TS_TTSTOP) 8548471Sache rc->rc_flags |= RC_OSUSP; 8558471Sache else 8568471Sache rc->rc_flags &= ~RC_OSUSP; 857106653Sjhb critical_exit(); 8588471Sache} 8598471Sache 860105806Sjhbstatic int 861105806Sjhbrcopen(dev_t dev, int flag, int mode, d_thread_t *td) 8628471Sache{ 863105806Sjhb struct rc_softc *sc; 864105806Sjhb struct rc_chans *rc; 865105806Sjhb struct tty *tp; 866105806Sjhb int s, error = 0; 8678471Sache 868105806Sjhb rc = DEV_TO_RC(dev); 869105806Sjhb sc = rc->rc_rcb; 870105806Sjhb tp = &rc->rc_tp; 871105806Sjhb if (sc->sc_opencount < 0) 872105806Sjhb return (ENXIO); 873105806Sjhb sc->sc_opencount++; 8748471Sache#ifdef RCDEBUG 875105806Sjhb device_printf(sc->sc_dev, "channel %d: rcopen: dev %p\n", 876105806Sjhb rc->rc_chan, dev); 8778471Sache#endif 8788471Sache s = spltty(); 8798471Sache 8808471Sacheagain: 8818471Sache while (rc->rc_flags & RC_DTR_OFF) { 8829232Sache error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0); 8838471Sache if (error != 0) 8848471Sache goto out; 8858471Sache } 8868471Sache if (tp->t_state & TS_ISOPEN) { 8878471Sache if (CALLOUT(dev)) { 8888471Sache if (!(rc->rc_flags & RC_ACTOUT)) { 8898471Sache error = EBUSY; 8908471Sache goto out; 8918471Sache } 8928471Sache } else { 8938471Sache if (rc->rc_flags & RC_ACTOUT) { 8948471Sache if (flag & O_NONBLOCK) { 8958471Sache error = EBUSY; 8968471Sache goto out; 8978471Sache } 89846571Speter error = tsleep(&rc->rc_rcb, 89946571Speter TTIPRI|PCATCH, "rcbi", 0); 90046571Speter if (error) 9018471Sache goto out; 9028471Sache goto again; 9038471Sache } 9048471Sache } 90543425Sphk if (tp->t_state & TS_XCLUDE && 90693593Sjhb suser(td)) { 9078471Sache error = EBUSY; 9088471Sache goto out; 9098471Sache } 9108471Sache } else { 9118471Sache tp->t_oproc = rc_start; 9128471Sache tp->t_param = rc_param; 91351654Sphk tp->t_stop = rc_stop; 9148471Sache tp->t_dev = dev; 9158471Sache 9168471Sache if (CALLOUT(dev)) 9178471Sache tp->t_cflag |= CLOCAL; 9188471Sache else 9198471Sache tp->t_cflag &= ~CLOCAL; 9208471Sache 9218471Sache error = rc_param(tp, &tp->t_termios); 9228471Sache if (error) 9238471Sache goto out; 9249232Sache (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET); 9258471Sache 9268471Sache if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev)) 9278471Sache (*linesw[tp->t_line].l_modem)(tp, 1); 9288471Sache } 9298471Sache if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev) 9308471Sache && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 9318471Sache rc->rc_dcdwaits++; 9329639Sbde error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0); 9338471Sache rc->rc_dcdwaits--; 9348471Sache if (error != 0) 9358471Sache goto out; 9368471Sache goto again; 9378471Sache } 9388471Sache error = (*linesw[tp->t_line].l_open)(dev, tp); 93913074Sache disc_optim(tp, &tp->t_termios, rc); 9408471Sache if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev)) 9418471Sache rc->rc_flags |= RC_ACTOUT; 9428471Sacheout: 9438471Sache (void) splx(s); 9448471Sache 9458471Sache if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN)) 9468471Sache rc_hardclose(rc); 9478471Sache 9488471Sache return error; 9498471Sache} 9508471Sache 951105806Sjhbstatic int 952105806Sjhbrcclose(dev_t dev, int flag, int mode, d_thread_t *td) 9538471Sache{ 954105806Sjhb struct rc_softc *sc; 955105806Sjhb struct rc_chans *rc; 956105806Sjhb struct tty *tp; 957105806Sjhb int s; 9588471Sache 959105806Sjhb rc = DEV_TO_RC(dev); 960105806Sjhb sc = rc->rc_rcb; 961105806Sjhb tp = &rc->rc_tp; 9629232Sache#ifdef RCDEBUG 963105806Sjhb device_printf(sc->sc_dev, "channel %d: rcclose dev %p\n", 964105806Sjhb rc->rc_chan, dev); 9659232Sache#endif 9668471Sache s = spltty(); 9678471Sache (*linesw[tp->t_line].l_close)(tp, flag); 96813074Sache disc_optim(tp, &tp->t_termios, rc); 96951654Sphk rc_stop(tp, FREAD | FWRITE); 9708471Sache rc_hardclose(rc); 9718471Sache ttyclose(tp); 9728471Sache splx(s); 973105806Sjhb KASSERT(sc->sc_opencount > 0, ("rcclose: non-positive open count")); 974105806Sjhb sc->sc_opencount--; 9758471Sache return 0; 9768471Sache} 9778471Sache 978105806Sjhbstatic void 979105806Sjhbrc_hardclose(struct rc_chans *rc) 9808471Sache{ 981105806Sjhb struct rc_softc *sc; 982105806Sjhb struct tty *tp; 983105806Sjhb int s; 9848471Sache 985105806Sjhb tp = &rc->rc_tp; 986105806Sjhb sc = rc->rc_rcb; 9878471Sache s = spltty(); 988105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 9898471Sache 9909232Sache /* Disable rx/tx intrs */ 991105806Sjhb rcout(sc, CD180_IER, rc->rc_ier = 0); 9929232Sache if ( (tp->t_cflag & HUPCL) 99346704Speter || (!(rc->rc_flags & RC_ACTOUT) 9948471Sache && !(rc->rc_msvr & MSVR_CD) 99546704Speter && !(tp->t_cflag & CLOCAL)) 9969232Sache || !(tp->t_state & TS_ISOPEN) 9979232Sache ) { 998105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 999105806Sjhb WAITFORCCR(sc, rc->rc_chan); 10008471Sache (void) rc_modctl(rc, TIOCM_RTS, DMSET); 10018471Sache if (rc->rc_dtrwait) { 1002105806Sjhb callout_reset(&rc->rc_dtrcallout, rc->rc_dtrwait, 1003105806Sjhb rc_dtrwakeup, rc); 10048471Sache rc->rc_flags |= RC_DTR_OFF; 10058471Sache } 10068471Sache } 10078471Sache rc->rc_flags &= ~RC_ACTOUT; 1008111748Sdes wakeup( &rc->rc_rcb); /* wake bi */ 10099639Sbde wakeup(TSA_CARR_ON(tp)); 10108471Sache (void) splx(s); 10118471Sache} 10128471Sache 10138471Sache/* Reset the bastard */ 1014105806Sjhbstatic void 1015118607Sjhbrc_hwreset(struct rc_softc *sc, u_int chipid) 10168471Sache{ 1017105806Sjhb CCRCMD(sc, -1, CCR_HWRESET); /* Hardware reset */ 10188471Sache DELAY(20000); 1019105806Sjhb WAITFORCCR(sc, -1); 10209232Sache 1021105806Sjhb rcout(sc, RC_CTOUT, 0); /* Clear timeout */ 1022105806Sjhb rcout(sc, CD180_GIVR, chipid); 1023105806Sjhb rcout(sc, CD180_GICR, 0); 10248471Sache 10258471Sache /* Set Prescaler Registers (1 msec) */ 1026105806Sjhb rcout(sc, CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF); 1027105806Sjhb rcout(sc, CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8); 10288471Sache 10298471Sache /* Initialize Priority Interrupt Level Registers */ 1030105806Sjhb rcout(sc, CD180_PILR1, RC_PILR_MODEM); 1031105806Sjhb rcout(sc, CD180_PILR2, RC_PILR_TX); 1032105806Sjhb rcout(sc, CD180_PILR3, RC_PILR_RX); 10338471Sache 10348471Sache /* Reset DTR */ 1035105806Sjhb rcout(sc, RC_DTREG, ~0); 10368471Sache} 10378471Sache 10388471Sache/* Set channel parameters */ 1039105806Sjhbstatic int 1040105806Sjhbrc_param(struct tty *tp, struct termios *ts) 10418471Sache{ 1042105806Sjhb struct rc_softc *sc; 1043105806Sjhb struct rc_chans *rc; 1044105806Sjhb int idivs, odivs, s, val, cflag, iflag, lflag, inpflow; 10458471Sache 10469855Sache if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800 10479855Sache || ts->c_ispeed < 0 || ts->c_ispeed > 76800 10489855Sache ) 10499855Sache return (EINVAL); 10508471Sache if (ts->c_ispeed == 0) 10518471Sache ts->c_ispeed = ts->c_ospeed; 10529855Sache odivs = RC_BRD(ts->c_ospeed); 10539855Sache idivs = RC_BRD(ts->c_ispeed); 10548471Sache 1055105806Sjhb rc = TTY_TO_RC(tp); 1056105806Sjhb sc = rc->rc_rcb; 10578471Sache s = spltty(); 10588471Sache 10599232Sache /* Select channel */ 1060105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 10619232Sache 10628471Sache /* If speed == 0, hangup line */ 10639232Sache if (ts->c_ospeed == 0) { 1064105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_ResetChan); 1065105806Sjhb WAITFORCCR(sc, rc->rc_chan); 10669232Sache (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 10679232Sache } 10688471Sache 10698471Sache tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 10708471Sache cflag = ts->c_cflag; 10718471Sache iflag = ts->c_iflag; 10728471Sache lflag = ts->c_lflag; 10738471Sache 10748471Sache if (idivs > 0) { 1075105806Sjhb rcout(sc, CD180_RBPRL, idivs & 0xFF); 1076105806Sjhb rcout(sc, CD180_RBPRH, idivs >> 8); 10778471Sache } 10788471Sache if (odivs > 0) { 1079105806Sjhb rcout(sc, CD180_TBPRL, odivs & 0xFF); 1080105806Sjhb rcout(sc, CD180_TBPRH, odivs >> 8); 10818471Sache } 10828471Sache 10838471Sache /* set timeout value */ 10849232Sache if (ts->c_ispeed > 0) { 10859232Sache int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1; 10868471Sache 10879232Sache if ( !(lflag & ICANON) 10889232Sache && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0 10899232Sache && ts->c_cc[VTIME] * 10 > itm) 10909232Sache itm = ts->c_cc[VTIME] * 10; 10919232Sache 1092105806Sjhb rcout(sc, CD180_RTPR, itm <= 255 ? itm : 255); 10939232Sache } 10949232Sache 10958471Sache switch (cflag & CSIZE) { 10968471Sache case CS5: val = COR1_5BITS; break; 10978471Sache case CS6: val = COR1_6BITS; break; 10988471Sache case CS7: val = COR1_7BITS; break; 10998471Sache default: 11008471Sache case CS8: val = COR1_8BITS; break; 11018471Sache } 11028471Sache if (cflag & PARENB) { 11038471Sache val |= COR1_NORMPAR; 11048471Sache if (cflag & PARODD) 11058471Sache val |= COR1_ODDP; 11069232Sache if (!(cflag & INPCK)) 11079232Sache val |= COR1_Ignore; 11088471Sache } else 11099232Sache val |= COR1_Ignore; 11108471Sache if (cflag & CSTOPB) 11118471Sache val |= COR1_2SB; 1112105806Sjhb rcout(sc, CD180_COR1, val); 11138471Sache 11148471Sache /* Set FIFO threshold */ 11159232Sache val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2; 11169232Sache inpflow = 0; 11179232Sache if ( (iflag & IXOFF) 11189232Sache && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE 11199232Sache && ( ts->c_cc[VSTART] != _POSIX_VDISABLE 11209232Sache || (iflag & IXANY) 11219232Sache ) 11229232Sache ) 11239232Sache ) { 11249232Sache inpflow = 1; 11259232Sache val |= COR3_SCDE|COR3_FCT; 11269232Sache } 1127105806Sjhb rcout(sc, CD180_COR3, val); 11288471Sache 11298471Sache /* Initialize on-chip automatic flow control */ 11308471Sache val = 0; 11319232Sache rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY); 11328471Sache if (cflag & CCTS_OFLOW) { 11338471Sache rc->rc_flags |= RC_CTSFLOW; 11349232Sache val |= COR2_CtsAE; 11359232Sache } else 11369232Sache rc->rc_flags |= RC_SEND_RDY; 11379232Sache if (tp->t_state & TS_TTSTOP) 11389232Sache rc->rc_flags |= RC_OSUSP; 11398471Sache else 11409232Sache rc->rc_flags &= ~RC_OSUSP; 11418471Sache if (cflag & CRTS_IFLOW) 11428471Sache rc->rc_flags |= RC_RTSFLOW; 11439232Sache else 11449232Sache rc->rc_flags &= ~RC_RTSFLOW; 11458471Sache 11469232Sache if (inpflow) { 11479232Sache if (ts->c_cc[VSTART] != _POSIX_VDISABLE) 1148105806Sjhb rcout(sc, CD180_SCHR1, ts->c_cc[VSTART]); 1149105806Sjhb rcout(sc, CD180_SCHR2, ts->c_cc[VSTOP]); 11509232Sache val |= COR2_TxIBE; 11519232Sache if (iflag & IXANY) 11529232Sache val |= COR2_IXM; 11538471Sache } 11548471Sache 1155105806Sjhb rcout(sc, CD180_COR2, rc->rc_cor2 = val); 11568471Sache 1157105806Sjhb CCRCMD(sc, rc->rc_chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 11589232Sache 11598471Sache disc_optim(tp, ts, rc); 11608471Sache 11618471Sache /* modem ctl */ 11629232Sache val = cflag & CLOCAL ? 0 : MCOR1_CDzd; 11639232Sache if (cflag & CCTS_OFLOW) 11649232Sache val |= MCOR1_CTSzd; 1165105806Sjhb rcout(sc, CD180_MCOR1, val); 11668471Sache 11679232Sache val = cflag & CLOCAL ? 0 : MCOR2_CDod; 11689232Sache if (cflag & CCTS_OFLOW) 11699232Sache val |= MCOR2_CTSod; 1170105806Sjhb rcout(sc, CD180_MCOR2, val); 11719232Sache 11728471Sache /* enable i/o and interrupts */ 1173105806Sjhb CCRCMD(sc, rc->rc_chan, 11749232Sache CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS)); 1175105806Sjhb WAITFORCCR(sc, rc->rc_chan); 11768471Sache 11779232Sache rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD; 11789232Sache if (cflag & CCTS_OFLOW) 11799232Sache rc->rc_ier |= IER_CTS; 11809232Sache if (cflag & CREAD) 11819232Sache rc->rc_ier |= IER_RxData; 11829232Sache if (tp->t_state & TS_BUSY) 11839232Sache rc->rc_ier |= IER_TxRdy; 11849232Sache if (ts->c_ospeed != 0) 11859232Sache rc_modctl(rc, TIOCM_DTR, DMBIS); 11869232Sache if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS)) 11879232Sache rc->rc_flags |= RC_SEND_RDY; 1188105806Sjhb rcout(sc, CD180_IER, rc->rc_ier); 11898471Sache (void) splx(s); 11908471Sache return 0; 11918471Sache} 11928471Sache 11939232Sache/* Re-initialize board after bogus interrupts */ 1194105806Sjhbstatic void 1195105806Sjhbrc_reinit(struct rc_softc *sc) 11969232Sache{ 1197105806Sjhb struct rc_chans *rc; 1198105806Sjhb int i; 11999232Sache 1200105806Sjhb rc_hwreset(sc, RC_FAKEID); 1201105806Sjhb rc = sc->sc_channels; 1202105806Sjhb for (i = 0; i < CD180_NCHAN; i++, rc++) 1203105806Sjhb (void) rc_param(&rc->rc_tp, &rc->rc_tp.t_termios); 12049232Sache} 12059232Sache 1206105806Sjhbstatic int 1207105806Sjhbrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, d_thread_t *td) 12088471Sache{ 1209105806Sjhb struct rc_chans *rc; 1210105806Sjhb struct tty *tp; 1211105806Sjhb int s, error; 12128471Sache 1213105806Sjhb rc = DEV_TO_RC(dev); 1214105806Sjhb tp = &rc->rc_tp; 121583366Sjulian error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); 121631577Sbde if (error != ENOIOCTL) 12178471Sache return (error); 12188471Sache error = ttioctl(tp, cmd, data, flag); 121913074Sache disc_optim(tp, &tp->t_termios, rc); 122031577Sbde if (error != ENOIOCTL) 12218471Sache return (error); 12228471Sache s = spltty(); 12238471Sache 12248471Sache switch (cmd) { 12258471Sache case TIOCSBRK: 12268471Sache rc->rc_pendcmd = CD180_C_SBRK; 12278471Sache break; 12288471Sache 12298471Sache case TIOCCBRK: 12308471Sache rc->rc_pendcmd = CD180_C_EBRK; 12318471Sache break; 12328471Sache 12338471Sache case TIOCSDTR: 12349232Sache (void) rc_modctl(rc, TIOCM_DTR, DMBIS); 12358471Sache break; 12368471Sache 12378471Sache case TIOCCDTR: 12388471Sache (void) rc_modctl(rc, TIOCM_DTR, DMBIC); 12398471Sache break; 12408471Sache 12418471Sache case TIOCMGET: 12428471Sache *(int *) data = rc_modctl(rc, 0, DMGET); 12438471Sache break; 12448471Sache 12458471Sache case TIOCMSET: 12468471Sache (void) rc_modctl(rc, *(int *) data, DMSET); 12478471Sache break; 12488471Sache 12498471Sache case TIOCMBIC: 12508471Sache (void) rc_modctl(rc, *(int *) data, DMBIC); 12518471Sache break; 12528471Sache 12538471Sache case TIOCMBIS: 12548471Sache (void) rc_modctl(rc, *(int *) data, DMBIS); 12558471Sache break; 12568471Sache 12578471Sache case TIOCMSDTRWAIT: 125893593Sjhb error = suser(td); 12598471Sache if (error != 0) { 12608471Sache splx(s); 12618471Sache return (error); 12628471Sache } 12638471Sache rc->rc_dtrwait = *(int *)data * hz / 100; 12648471Sache break; 12658471Sache 12668471Sache case TIOCMGDTRWAIT: 12678471Sache *(int *)data = rc->rc_dtrwait * 100 / hz; 12688471Sache break; 12698471Sache 12708471Sache default: 12718471Sache (void) splx(s); 12728471Sache return ENOTTY; 12738471Sache } 12748471Sache (void) splx(s); 12758471Sache return 0; 12768471Sache} 12778471Sache 12788471Sache 12798471Sache/* Modem control routines */ 12808471Sache 1281105806Sjhbstatic int 1282105806Sjhbrc_modctl(struct rc_chans *rc, int bits, int cmd) 12838471Sache{ 1284105806Sjhb struct rc_softc *sc; 1285105806Sjhb u_char *dtr; 1286105806Sjhb u_char msvr; 12878471Sache 1288105806Sjhb sc = rc->rc_rcb; 1289105806Sjhb dtr = &sc->sc_dtr; 1290105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 12918471Sache 12928471Sache switch (cmd) { 12938471Sache case DMSET: 1294105806Sjhb rcout(sc, RC_DTREG, (bits & TIOCM_DTR) ? 12959232Sache ~(*dtr |= 1 << rc->rc_chan) : 12969232Sache ~(*dtr &= ~(1 << rc->rc_chan))); 1297105806Sjhb msvr = rcin(sc, CD180_MSVR); 12989232Sache if (bits & TIOCM_RTS) 12999232Sache msvr |= MSVR_RTS; 13009232Sache else 13019232Sache msvr &= ~MSVR_RTS; 13029232Sache if (bits & TIOCM_DTR) 13039232Sache msvr |= MSVR_DTR; 13049232Sache else 13059232Sache msvr &= ~MSVR_DTR; 1306105806Sjhb rcout(sc, CD180_MSVR, msvr); 13079232Sache break; 13088471Sache 13098471Sache case DMBIS: 13109232Sache if (bits & TIOCM_DTR) 1311105806Sjhb rcout(sc, RC_DTREG, ~(*dtr |= 1 << rc->rc_chan)); 1312105806Sjhb msvr = rcin(sc, CD180_MSVR); 13138471Sache if (bits & TIOCM_RTS) 13149232Sache msvr |= MSVR_RTS; 13158471Sache if (bits & TIOCM_DTR) 13169232Sache msvr |= MSVR_DTR; 1317105806Sjhb rcout(sc, CD180_MSVR, msvr); 13188471Sache break; 13198471Sache 13208471Sache case DMGET: 13218471Sache bits = TIOCM_LE; 1322105806Sjhb msvr = rc->rc_msvr = rcin(sc, CD180_MSVR); 13238471Sache 13248471Sache if (msvr & MSVR_RTS) 13258471Sache bits |= TIOCM_RTS; 13268471Sache if (msvr & MSVR_CTS) 13278471Sache bits |= TIOCM_CTS; 13288471Sache if (msvr & MSVR_DSR) 13298471Sache bits |= TIOCM_DSR; 13308471Sache if (msvr & MSVR_DTR) 13318471Sache bits |= TIOCM_DTR; 13329232Sache if (msvr & MSVR_CD) 13339232Sache bits |= TIOCM_CD; 1334105806Sjhb if (~rcin(sc, RC_RIREG) & (1 << rc->rc_chan)) 13359232Sache bits |= TIOCM_RI; 13368471Sache return bits; 13378471Sache 13388471Sache case DMBIC: 13398471Sache if (bits & TIOCM_DTR) 1340105806Sjhb rcout(sc, RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan))); 1341105806Sjhb msvr = rcin(sc, CD180_MSVR); 13428471Sache if (bits & TIOCM_RTS) 13439232Sache msvr &= ~MSVR_RTS; 13449232Sache if (bits & TIOCM_DTR) 13459232Sache msvr &= ~MSVR_DTR; 1346105806Sjhb rcout(sc, CD180_MSVR, msvr); 13478471Sache break; 13488471Sache } 1349105806Sjhb rc->rc_msvr = rcin(sc, CD180_MSVR); 13508471Sache return 0; 13518471Sache} 13528471Sache 1353105806Sjhb#define ERR(s) do { \ 1354105806Sjhb device_printf(sc->sc_dev, "%s", ""); \ 1355105806Sjhb printf s ; \ 1356105806Sjhb printf("\n"); \ 1357105806Sjhb (void) splx(old_level); \ 1358105806Sjhb return 1; \ 1359105806Sjhb} while (0) 1360105806Sjhb 13618471Sache/* Test the board. */ 1362105806Sjhbint 1363105806Sjhbrc_test(struct rc_softc *sc) 13648471Sache{ 136516322Sgpalmer int chan = 0; 13668471Sache int i = 0, rcnt, old_level; 13678471Sache unsigned int iack, chipid; 13688471Sache unsigned short divs; 13698471Sache static u_char ctest[] = "\377\125\252\045\244\0\377"; 13708471Sache#define CTLEN 8 13718471Sache 13728471Sache struct rtest { 13738471Sache u_char txbuf[CD180_NFIFO]; /* TX buffer */ 13748471Sache u_char rxbuf[CD180_NFIFO]; /* RX buffer */ 13758471Sache int rxptr; /* RX pointer */ 13768471Sache int txptr; /* TX pointer */ 13778471Sache } tchans[CD180_NCHAN]; 13788471Sache 13799232Sache old_level = spltty(); 13808471Sache 13818471Sache chipid = RC_FAKEID; 13828471Sache 13838471Sache /* First, reset board to inital state */ 1384105806Sjhb rc_hwreset(sc, chipid); 13858471Sache 13869232Sache divs = RC_BRD(19200); 13879232Sache 13888471Sache /* Initialize channels */ 13898471Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 13908471Sache 13918471Sache /* Select and reset channel */ 1392105806Sjhb rcout(sc, CD180_CAR, chan); 1393105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 1394105806Sjhb WAITFORCCR(sc, chan); 13958471Sache 13968471Sache /* Set speed */ 1397105806Sjhb rcout(sc, CD180_RBPRL, divs & 0xFF); 1398105806Sjhb rcout(sc, CD180_RBPRH, divs >> 8); 1399105806Sjhb rcout(sc, CD180_TBPRL, divs & 0xFF); 1400105806Sjhb rcout(sc, CD180_TBPRH, divs >> 8); 14018471Sache 14028471Sache /* set timeout value */ 1403105806Sjhb rcout(sc, CD180_RTPR, 0); 14048471Sache 14058471Sache /* Establish local loopback */ 1406105806Sjhb rcout(sc, CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB); 1407105806Sjhb rcout(sc, CD180_COR2, COR2_LLM); 1408105806Sjhb rcout(sc, CD180_COR3, CD180_NFIFO); 1409105806Sjhb CCRCMD(sc, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); 1410105806Sjhb CCRCMD(sc, chan, CCR_RCVREN | CCR_XMTREN); 1411105806Sjhb WAITFORCCR(sc, chan); 1412105806Sjhb rcout(sc, CD180_MSVR, MSVR_RTS); 14138471Sache 14148471Sache /* Fill TXBUF with test data */ 14158471Sache for (i = 0; i < CD180_NFIFO; i++) { 14168471Sache tchans[chan].txbuf[i] = ctest[i]; 14178471Sache tchans[chan].rxbuf[i] = 0; 14188471Sache } 14198471Sache tchans[chan].txptr = tchans[chan].rxptr = 0; 14208471Sache 14218471Sache /* Now, start transmit */ 1422105806Sjhb rcout(sc, CD180_IER, IER_TxMpty|IER_RxData); 14238471Sache } 14248471Sache /* Pseudo-interrupt poll stuff */ 14258471Sache for (rcnt = 10000; rcnt-- > 0; rcnt--) { 1426105806Sjhb i = ~(rcin(sc, RC_BSR)); 14278471Sache if (i & RC_BSR_TOUT) 1428105806Sjhb ERR(("BSR timeout bit set\n")); 14299232Sache else if (i & RC_BSR_TXINT) { 1430105806Sjhb iack = rcin(sc, RC_PILR_TX); 14318471Sache if (iack != (GIVR_IT_TDI | chipid)) 14328471Sache ERR(("Bad TX intr ack (%02x != %02x)\n", 14338471Sache iack, GIVR_IT_TDI | chipid)); 1434105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 14358471Sache /* If no more data to transmit, disable TX intr */ 14368471Sache if (tchans[chan].txptr >= CD180_NFIFO) { 1437105806Sjhb iack = rcin(sc, CD180_IER); 1438105806Sjhb rcout(sc, CD180_IER, iack & ~IER_TxMpty); 14398471Sache } else { 14408471Sache for (iack = tchans[chan].txptr; 14418471Sache iack < CD180_NFIFO; iack++) 1442105806Sjhb rcout(sc, CD180_TDR, 14438471Sache tchans[chan].txbuf[iack]); 14448471Sache tchans[chan].txptr = iack; 14458471Sache } 1446105806Sjhb rcout(sc, CD180_EOIR, 0); 14479232Sache } else if (i & RC_BSR_RXINT) { 14489232Sache u_char ucnt; 14498471Sache 1450105806Sjhb iack = rcin(sc, RC_PILR_RX); 14518471Sache if (iack != (GIVR_IT_RGDI | chipid) && 14528471Sache iack != (GIVR_IT_REI | chipid)) 14538471Sache ERR(("Bad RX intr ack (%02x != %02x)\n", 1454105806Sjhb iack, GIVR_IT_RGDI | chipid)); 1455105806Sjhb chan = (rcin(sc, CD180_GICR) & GICR_CHAN) >> GICR_LSH; 1456105806Sjhb ucnt = rcin(sc, CD180_RDCR) & 0xF; 14578471Sache while (ucnt-- > 0) { 1458105806Sjhb iack = rcin(sc, CD180_RCSR); 14599232Sache if (iack & RCSR_Timeout) 14608471Sache break; 14618471Sache if (iack & 0xF) 14628471Sache ERR(("Bad char chan %d (RCSR = %02X)\n", 1463105806Sjhb chan, iack)); 14648471Sache if (tchans[chan].rxptr > CD180_NFIFO) 14658471Sache ERR(("Got extra chars chan %d\n", 1466105806Sjhb chan)); 14678471Sache tchans[chan].rxbuf[tchans[chan].rxptr++] = 1468105806Sjhb rcin(sc, CD180_RDR); 14698471Sache } 1470105806Sjhb rcout(sc, CD180_EOIR, 0); 14718471Sache } 1472105806Sjhb rcout(sc, RC_CTOUT, 0); 14738471Sache for (iack = chan = 0; chan < CD180_NCHAN; chan++) 14748471Sache if (tchans[chan].rxptr >= CD180_NFIFO) 14758471Sache iack++; 14768471Sache if (iack == CD180_NCHAN) 14778471Sache break; 14788471Sache } 14799232Sache for (chan = 0; chan < CD180_NCHAN; chan++) { 14809232Sache /* Select and reset channel */ 1481105806Sjhb rcout(sc, CD180_CAR, chan); 1482105806Sjhb CCRCMD(sc, chan, CCR_ResetChan); 14839232Sache } 14849232Sache 14858471Sache if (!rcnt) 1486105806Sjhb ERR(("looses characters during local loopback\n")); 14878471Sache /* Now, check data */ 14888471Sache for (chan = 0; chan < CD180_NCHAN; chan++) 14898471Sache for (i = 0; i < CD180_NFIFO; i++) 14908471Sache if (ctest[i] != tchans[chan].rxbuf[i]) 14918471Sache ERR(("data mismatch chan %d ptr %d (%d != %d)\n", 1492105806Sjhb chan, i, ctest[i], tchans[chan].rxbuf[i])); 14938471Sache (void) splx(old_level); 14948471Sache return 0; 14958471Sache} 14968471Sache 14978471Sache#ifdef RCDEBUG 1498105806Sjhbstatic void 1499105806Sjhbprintrcflags(struct rc_chans *rc, char *comment) 15008471Sache{ 1501105806Sjhb struct rc_softc *sc; 15028471Sache u_short f = rc->rc_flags; 15038471Sache 1504105806Sjhb sc = rc->rc_rcb; 15059232Sache printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n", 15068471Sache rc->rc_rcb->rcb_unit, rc->rc_chan, comment, 15078471Sache (f & RC_DTR_OFF)?"DTR_OFF " :"", 15089232Sache (f & RC_ACTOUT) ?"ACTOUT " :"", 15099232Sache (f & RC_RTSFLOW)?"RTSFLOW " :"", 15109232Sache (f & RC_CTSFLOW)?"CTSFLOW " :"", 15119232Sache (f & RC_DORXFER)?"DORXFER " :"", 15129232Sache (f & RC_DOXXFER)?"DOXXFER " :"", 15139232Sache (f & RC_MODCHG) ?"MODCHG " :"", 15149232Sache (f & RC_OSUSP) ?"OSUSP " :"", 15159232Sache (f & RC_OSBUSY) ?"OSBUSY " :"", 15169232Sache (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"", 15179232Sache (f & RC_WAS_SILOVFL) ?"SILOVFL " :"", 15189232Sache (f & RC_SEND_RDY) ?"SEND_RDY":""); 15199232Sache 1520105806Sjhb rcout(sc, CD180_CAR, rc->rc_chan); 15219232Sache 15229232Sache printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n", 15239232Sache rc->rc_rcb->rcb_unit, rc->rc_chan, 1524105806Sjhb rcin(sc, CD180_MSVR), 1525105806Sjhb rcin(sc, CD180_IER), 1526105806Sjhb rcin(sc, CD180_CCSR)); 15278471Sache} 15288471Sache#endif /* RCDEBUG */ 15298471Sache 15308471Sachestatic void 1531105806Sjhbrc_dtrwakeup(void *arg) 15328471Sache{ 15338471Sache struct rc_chans *rc; 15348471Sache 1535105806Sjhb rc = (struct rc_chans *)arg; 15368471Sache rc->rc_flags &= ~RC_DTR_OFF; 15378471Sache wakeup(&rc->rc_dtrwait); 15388471Sache} 15398471Sache 15408471Sachestatic void 1541105806Sjhbrc_discard_output(struct rc_chans *rc) 15428471Sache{ 1543106653Sjhb critical_enter(); 15448471Sache if (rc->rc_flags & RC_DOXXFER) { 1545105806Sjhb rc->rc_rcb->sc_scheduled_event -= LOTS_OF_EVENTS; 15468471Sache rc->rc_flags &= ~RC_DOXXFER; 15478471Sache } 15488471Sache rc->rc_optr = rc->rc_obufend; 1549105806Sjhb rc->rc_tp.t_state &= ~TS_BUSY; 1550106653Sjhb critical_exit(); 1551105806Sjhb ttwwakeup(&rc->rc_tp); 15528471Sache} 15538471Sache 15548471Sachestatic void 1555105806Sjhbdisc_optim(struct tty *tp, struct termios *t, struct rc_chans *rc) 15568471Sache{ 15578471Sache 15589757Sbde if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 15598471Sache && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 15609757Sbde && (!(t->c_iflag & PARMRK) 15619757Sbde || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 15629757Sbde && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 15638471Sache && linesw[tp->t_line].l_rint == ttyinput) 15648471Sache tp->t_state |= TS_CAN_BYPASS_L_RINT; 15658471Sache else 15668471Sache tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 156733322Sphk rc->rc_hotchar = linesw[tp->t_line].l_hotchar; 15688471Sache} 15699232Sache 15709232Sachestatic void 1571105806Sjhbrc_wait0(struct rc_softc *sc, int chan, int line) 15729232Sache{ 15739232Sache int rcnt; 15749232Sache 1575105806Sjhb for (rcnt = 50; rcnt && rcin(sc, CD180_CCR); rcnt--) 157614441Srgrimes DELAY(30); 15779232Sache if (rcnt == 0) 1578105806Sjhb device_printf(sc->sc_dev, 1579105806Sjhb "channel %d command timeout, rc.c line: %d\n", chan, line); 15809232Sache} 1581105806Sjhb 1582105806Sjhbstatic device_method_t rc_methods[] = { 1583105806Sjhb /* Device interface */ 1584105806Sjhb DEVMETHOD(device_probe, rc_probe), 1585105806Sjhb DEVMETHOD(device_attach, rc_attach), 1586105806Sjhb DEVMETHOD(device_detach, rc_detach), 1587105806Sjhb { 0, 0 } 1588105806Sjhb}; 1589105806Sjhb 1590105806Sjhbstatic driver_t rc_driver = { 1591105806Sjhb "rc", 1592105806Sjhb rc_methods, sizeof(struct rc_softc), 1593105806Sjhb}; 1594105806Sjhb 1595105806SjhbDRIVER_MODULE(rc, isa, rc_driver, rc_devclass, 0, 0); 1596