[BACK]Return to cy.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/cy.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: cy.c,v 1.25 2005/11/21 18:16:39 millert Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 1996 Timo Rossi.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. Neither the name of the author nor the names of contributors
        !            15:  *    may be used to endorse or promote products derived from this software
        !            16:  *    without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30:
        !            31: /*
        !            32:  * cy.c
        !            33:  *
        !            34:  * Driver for Cyclades Cyclom-8/16/32 multiport serial cards
        !            35:  * (currently not tested with Cyclom-32 cards)
        !            36:  *
        !            37:  * Timo Rossi, 1996
        !            38:  *
        !            39:  * Supports both ISA and PCI Cyclom cards
        !            40:  *
        !            41:  * Uses CD1400 automatic CTS flow control, and
        !            42:  * if CY_HW_RTS is defined, uses CD1400 automatic input flow control.
        !            43:  * This requires a special cable that exchanges the RTS and DTR lines.
        !            44:  *
        !            45:  * Lots of debug output can be enabled by defining CY_DEBUG
        !            46:  * Some debugging counters (number of receive/transmit interrupts etc.)
        !            47:  * can be enabled by defining CY_DEBUG1
        !            48:  *
        !            49:  * This version uses the bus_space/io_??() stuff
        !            50:  *
        !            51:  */
        !            52:
        !            53: /* NCY is the number of Cyclom cards in the machine */
        !            54: #include "cy.h"
        !            55: #if NCY > 0
        !            56:
        !            57: #include <sys/types.h>
        !            58: #include <sys/param.h>
        !            59: #include <sys/ioctl.h>
        !            60: #include <sys/syslog.h>
        !            61: #include <sys/fcntl.h>
        !            62: #include <sys/tty.h>
        !            63: #include <sys/proc.h>
        !            64: #include <sys/conf.h>
        !            65: #include <sys/user.h>
        !            66: #include <sys/selinfo.h>
        !            67: #include <sys/device.h>
        !            68: #include <sys/malloc.h>
        !            69: #include <sys/systm.h>
        !            70:
        !            71: #include <machine/bus.h>
        !            72: #include <machine/intr.h>
        !            73:
        !            74: #if NCY_ISA > 0
        !            75: #include <dev/isa/isavar.h>
        !            76: #include <dev/isa/isareg.h>
        !            77: #endif /* NCY_ISA > 0 */
        !            78: #if NCY_PCI > 0
        !            79: #include <dev/pci/pcivar.h>
        !            80: #include <dev/pci/pcireg.h>
        !            81: #include <dev/pci/pcidevs.h>
        !            82: #endif /* NCY_PCI > 0 */
        !            83:
        !            84: #include <dev/ic/cd1400reg.h>
        !            85: #include <dev/ic/cyreg.h>
        !            86:
        !            87:
        !            88: int    cy_intr(void *);
        !            89: int    cyparam(struct tty *, struct termios *);
        !            90: void   cystart(struct tty *);
        !            91: void   cy_poll(void *);
        !            92: int    cy_modem_control(struct cy_port *, int, int);
        !            93: void   cy_enable_transmitter(struct cy_port *);
        !            94: void   cd1400_channel_cmd(struct cy_port *, int);
        !            95: int    cy_speed(speed_t, int *, int *, int);
        !            96:
        !            97: struct cfdriver cy_cd = {
        !            98:        NULL, "cy", DV_TTY
        !            99: };
        !           100:
        !           101: /*
        !           102:  * Common probe routine
        !           103:  *
        !           104:  * returns the number of chips found.
        !           105:  */
        !           106: int
        !           107: cy_probe_common(bus_space_tag_t memt, bus_space_handle_t memh, int bustype)
        !           108: {
        !           109:        int cy_chip, chip_offs;
        !           110:        u_char firmware_ver;
        !           111:        int nchips;
        !           112:
        !           113:        /* Cyclom card hardware reset */
        !           114:        bus_space_write_1(memt, memh, CY16_RESET<<bustype, 0);
        !           115:        DELAY(500); /* wait for reset to complete */
        !           116:        bus_space_write_1(memt, memh, CY_CLEAR_INTR<<bustype, 0);
        !           117:
        !           118: #ifdef CY_DEBUG
        !           119:        printf("cy: card reset done\n");
        !           120: #endif
        !           121:
        !           122:        nchips = 0;
        !           123:
        !           124:        for (cy_chip = 0, chip_offs = 0;
        !           125:            cy_chip < CY_MAX_CD1400s;
        !           126:            cy_chip++, chip_offs += (CY_CD1400_MEMSPACING << bustype)) {
        !           127:                int i;
        !           128:
        !           129:                /* the last 4 cd1400s are 'interleaved'
        !           130:                   with the first 4 on 32-port boards */
        !           131:                if (cy_chip == 4)
        !           132:                        chip_offs -= (CY32_ADDR_FIX << bustype);
        !           133:
        !           134: #ifdef CY_DEBUG
        !           135:                printf("cy: probe chip %d offset 0x%lx ... ",
        !           136:                    cy_chip, chip_offs);
        !           137: #endif
        !           138:
        !           139:                /* wait until the chip is ready for command */
        !           140:                DELAY(1000);
        !           141:                if (bus_space_read_1(memt, memh, chip_offs +
        !           142:                    ((CD1400_CCR << 1) << bustype)) != 0) {
        !           143: #ifdef CY_DEBUG
        !           144:                        printf("not ready for command\n");
        !           145: #endif
        !           146:                        break;
        !           147:                }
        !           148:
        !           149:                /* clear the firmware version reg. */
        !           150:                bus_space_write_1(memt, memh, chip_offs +
        !           151:                    ((CD1400_GFRCR << 1) << bustype), 0);
        !           152:
        !           153:                /*
        !           154:                 * On Cyclom-16 references to non-existent chip 4
        !           155:                 * actually access chip 0 (address line 9 not decoded).
        !           156:                 * Here we check if the clearing of chip 4 GFRCR actually
        !           157:                 * cleared chip 0 GFRCR. In that case we have a 16 port card.
        !           158:                 */
        !           159:                if (cy_chip == 4 &&
        !           160:                    bus_space_read_1(memt, memh, chip_offs +
        !           161:                        ((CD1400_GFRCR << 1) << bustype)) == 0)
        !           162:                        break;
        !           163:
        !           164:                /* reset the chip */
        !           165:                bus_space_write_1(memt, memh, chip_offs +
        !           166:                    ((CD1400_CCR << 1) << bustype),
        !           167:                    CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
        !           168:
        !           169:                /* wait for the chip to initialize itself */
        !           170:                for (i = 0; i < 200; i++) {
        !           171:                        DELAY(50);
        !           172:                        firmware_ver = bus_space_read_1(memt, memh, chip_offs +
        !           173:                            ((CD1400_GFRCR << 1) << bustype));
        !           174:                        if ((firmware_ver & 0xf0) == 0x40) /* found a CD1400 */
        !           175:                                break;
        !           176:                }
        !           177: #ifdef CY_DEBUG
        !           178:                printf("firmware version 0x%x\n", firmware_ver);
        !           179: #endif
        !           180:
        !           181:                if ((firmware_ver & 0xf0) != 0x40)
        !           182:                        break;
        !           183:
        !           184:                /* firmware version OK, CD1400 found */
        !           185:                nchips++;
        !           186:        }
        !           187:
        !           188:        if (nchips == 0) {
        !           189: #ifdef CY_DEBUG
        !           190:                printf("no CD1400s found\n");
        !           191: #endif
        !           192:                return (0);
        !           193:        }
        !           194:
        !           195: #ifdef CY_DEBUG
        !           196:        printf("found %d CD1400s\n", nchips);
        !           197: #endif
        !           198:
        !           199:        return (nchips);
        !           200: }
        !           201:
        !           202: void
        !           203: cy_attach(parent, self)
        !           204:        struct device *parent, *self;
        !           205: {
        !           206:        int card, port, cy_chip, num_chips, cdu, chip_offs, cy_clock;
        !           207:        struct cy_softc *sc = (void *)self;
        !           208:
        !           209:        card = sc->sc_dev.dv_unit;
        !           210:        num_chips = sc->sc_nr_cd1400s;
        !           211:        if (num_chips == 0)
        !           212:                return;
        !           213:
        !           214:        timeout_set(&sc->sc_poll_to, cy_poll, sc);
        !           215:        bzero(sc->sc_ports, sizeof(sc->sc_ports));
        !           216:        sc->sc_nports = num_chips * CD1400_NO_OF_CHANNELS;
        !           217:
        !           218:        port = 0;
        !           219:        for (cy_chip = 0, chip_offs = 0;
        !           220:            cy_chip < num_chips;
        !           221:            cy_chip++, chip_offs += (CY_CD1400_MEMSPACING<<sc->sc_bustype)) {
        !           222:                if (cy_chip == 4)
        !           223:                        chip_offs -= (CY32_ADDR_FIX<<sc->sc_bustype);
        !           224:
        !           225: #ifdef CY_DEBUG
        !           226:                printf("attach CD1400 #%d offset 0x%x\n", cy_chip, chip_offs);
        !           227: #endif
        !           228:                sc->sc_cd1400_offs[cy_chip] = chip_offs;
        !           229:
        !           230:                /* configure port 0 as serial port
        !           231:                   (should already be after reset) */
        !           232:                cd_write_reg_sc(sc, cy_chip, CD1400_GCR, 0);
        !           233:
        !           234:                /* Set cy_clock depending on firmware version */
        !           235:                if (cd_read_reg_sc(sc, cy_chip, CD1400_GFRCR) <= 0x46)
        !           236:                        cy_clock = CY_CLOCK;
        !           237:                else
        !           238:                        cy_clock = CY_CLOCK_60;
        !           239:
        !           240:                /* set up a receive timeout period (1ms) */
        !           241:                cd_write_reg_sc(sc, cy_chip, CD1400_PPR,
        !           242:                    (cy_clock / CD1400_PPR_PRESCALER / 1000) + 1);
        !           243:
        !           244:                for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; cdu++) {
        !           245:                        sc->sc_ports[port].cy_port_num = port;
        !           246:                        sc->sc_ports[port].cy_memt = sc->sc_memt;
        !           247:                        sc->sc_ports[port].cy_memh = sc->sc_memh;
        !           248:                        sc->sc_ports[port].cy_chip_offs = chip_offs;
        !           249:                        sc->sc_ports[port].cy_bustype = sc->sc_bustype;
        !           250:                        sc->sc_ports[port].cy_clock = cy_clock;
        !           251:
        !           252:                        /* should we initialize anything else here? */
        !           253:                        port++;
        !           254:                } /* for(each port on one CD1400...) */
        !           255:
        !           256:        } /* for(each CD1400 on a card... ) */
        !           257:
        !           258:        printf(": %d ports\n", port);
        !           259:
        !           260:        /* ensure an edge for the next interrupt */
        !           261:        bus_space_write_1(sc->sc_memt, sc->sc_memh,
        !           262:            CY_CLEAR_INTR<<sc->sc_bustype, 0);
        !           263: }
        !           264:
        !           265: /*
        !           266:  * open routine. returns zero if successful, else error code
        !           267:  */
        !           268: int cyopen(dev_t, int, int, struct proc *);
        !           269: int cyclose(dev_t, int, int, struct proc *);
        !           270: int cyread(dev_t, struct uio *, int);
        !           271: int cywrite(dev_t, struct uio *, int);
        !           272: struct tty *cytty(dev_t);
        !           273: int cyioctl(dev_t, u_long, caddr_t, int, struct proc *);
        !           274: int cystop(struct tty *, int flag);
        !           275:
        !           276: int
        !           277: cyopen(dev, flag, mode, p)
        !           278:        dev_t dev;
        !           279:        int flag, mode;
        !           280:        struct proc *p;
        !           281: {
        !           282:        int card = CY_CARD(dev);
        !           283:        int port = CY_PORT(dev);
        !           284:        struct cy_softc *sc;
        !           285:        struct cy_port *cy;
        !           286:        struct tty *tp;
        !           287:        int s, error;
        !           288:
        !           289:        if (card >= cy_cd.cd_ndevs ||
        !           290:            (sc = cy_cd.cd_devs[card]) == NULL) {
        !           291:                return (ENXIO);
        !           292:        }
        !           293:
        !           294: #ifdef CY_DEBUG
        !           295:        printf("%s open port %d flag 0x%x mode 0x%x\n", sc->sc_dev.dv_xname,
        !           296:            port, flag, mode);
        !           297: #endif
        !           298:
        !           299:        cy = &sc->sc_ports[port];
        !           300:
        !           301:        s = spltty();
        !           302:        if (cy->cy_tty == NULL) {
        !           303:                cy->cy_tty = ttymalloc();
        !           304:        }
        !           305:        splx(s);
        !           306:
        !           307:        tp = cy->cy_tty;
        !           308:        tp->t_oproc = cystart;
        !           309:        tp->t_param = cyparam;
        !           310:        tp->t_dev = dev;
        !           311:
        !           312:        if (!ISSET(tp->t_state, TS_ISOPEN)) {
        !           313:                SET(tp->t_state, TS_WOPEN);
        !           314:                ttychars(tp);
        !           315:                tp->t_iflag = TTYDEF_IFLAG;
        !           316:                tp->t_oflag = TTYDEF_OFLAG;
        !           317:                tp->t_cflag = TTYDEF_CFLAG;
        !           318:                if (ISSET(cy->cy_openflags, TIOCFLAG_CLOCAL))
        !           319:                        SET(tp->t_cflag, CLOCAL);
        !           320:                if (ISSET(cy->cy_openflags, TIOCFLAG_CRTSCTS))
        !           321:                        SET(tp->t_cflag, CRTSCTS);
        !           322:                if (ISSET(cy->cy_openflags, TIOCFLAG_MDMBUF))
        !           323:                        SET(tp->t_cflag, MDMBUF);
        !           324:                tp->t_lflag = TTYDEF_LFLAG;
        !           325:                tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
        !           326:
        !           327:                s = spltty();
        !           328:
        !           329:                /*
        !           330:                 * Allocate input ring buffer if we don't already have one
        !           331:                 */
        !           332:                if (cy->cy_ibuf == NULL) {
        !           333:                        cy->cy_ibuf = malloc(IBUF_SIZE, M_DEVBUF, M_NOWAIT);
        !           334:                        if (cy->cy_ibuf == NULL) {
        !           335:                                printf("%s: (port %d) can't allocate input buffer\n",
        !           336:                                       sc->sc_dev.dv_xname, port);
        !           337:                                splx(s);
        !           338:                                return (ENOMEM);
        !           339:                        }
        !           340:                        cy->cy_ibuf_end = cy->cy_ibuf + IBUF_SIZE;
        !           341:                }
        !           342:
        !           343:                /* mark the ring buffer as empty */
        !           344:                cy->cy_ibuf_rd_ptr = cy->cy_ibuf_wr_ptr = cy->cy_ibuf;
        !           345:
        !           346:                /* select CD1400 channel */
        !           347:                cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN);
        !           348:                /* reset the channel */
        !           349:                cd1400_channel_cmd(cy, CD1400_CCR_CMDRESET);
        !           350:                /* encode unit (port) number in LIVR */
        !           351:                /* there is just enough space for 5 bits (32 ports) */
        !           352:                cd_write_reg(cy, CD1400_LIVR, port << 3);
        !           353:
        !           354:                cy->cy_channel_control = 0;
        !           355:
        !           356:                if (!timeout_pending(&sc->sc_poll_to))
        !           357:                        timeout_add(&sc->sc_poll_to, 1);
        !           358:
        !           359:                /* this sets parameters and raises DTR */
        !           360:                cyparam(tp, &tp->t_termios);
        !           361:
        !           362:                ttsetwater(tp);
        !           363:
        !           364:                /* raise RTS too */
        !           365:                cy_modem_control(cy, TIOCM_RTS, DMBIS);
        !           366:
        !           367:                cy->cy_carrier_stat = cd_read_reg(cy, CD1400_MSVR2);
        !           368:
        !           369:                /* enable receiver and modem change interrupts */
        !           370:                cd_write_reg(cy, CD1400_SRER,
        !           371:                    CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
        !           372:
        !           373:                if (CY_DIALOUT(dev) ||
        !           374:                    ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR) ||
        !           375:                    ISSET(tp->t_cflag, MDMBUF) ||
        !           376:                    ISSET(cy->cy_carrier_stat, CD1400_MSVR2_CD))
        !           377:                        SET(tp->t_state, TS_CARR_ON);
        !           378:                else
        !           379:                        CLR(tp->t_state, TS_CARR_ON);
        !           380:        } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) {
        !           381:                return (EBUSY);
        !           382:        } else {
        !           383:                s = spltty();
        !           384:        }
        !           385:
        !           386:        /* wait for carrier if necessary */
        !           387:        if (!ISSET(flag, O_NONBLOCK)) {
        !           388:                while (!ISSET(tp->t_cflag, CLOCAL) &&
        !           389:                    !ISSET(tp->t_state, TS_CARR_ON)) {
        !           390:                        SET(tp->t_state, TS_WOPEN);
        !           391:                        error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
        !           392:                            "cydcd", 0);
        !           393:                        if (error != 0) {
        !           394:                                splx(s);
        !           395:                                CLR(tp->t_state, TS_WOPEN);
        !           396:                                return (error);
        !           397:                        }
        !           398:                }
        !           399:        }
        !           400:
        !           401:        splx(s);
        !           402:
        !           403:        return (*linesw[tp->t_line].l_open)(dev, tp);
        !           404: }
        !           405:
        !           406: /*
        !           407:  * close routine. returns zero if successful, else error code
        !           408:  */
        !           409: int
        !           410: cyclose(dev, flag, mode, p)
        !           411:        dev_t dev;
        !           412:        int flag, mode;
        !           413:        struct proc *p;
        !           414: {
        !           415:        int card = CY_CARD(dev);
        !           416:        int port = CY_PORT(dev);
        !           417:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           418:        struct cy_port *cy = &sc->sc_ports[port];
        !           419:        struct tty *tp = cy->cy_tty;
        !           420:        int s;
        !           421:
        !           422: #ifdef CY_DEBUG
        !           423:        printf("%s close port %d, flag 0x%x, mode 0x%x\n", sc->sc_dev.dv_xname,
        !           424:            port, flag, mode);
        !           425: #endif
        !           426:
        !           427:        (*linesw[tp->t_line].l_close)(tp, flag);
        !           428:        s = spltty();
        !           429:
        !           430:        if (ISSET(tp->t_cflag, HUPCL) &&
        !           431:            !ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR)) {
        !           432:                /* drop DTR and RTS
        !           433:                   (should we wait for output buffer to become empty first?) */
        !           434:                cy_modem_control(cy, 0, DMSET);
        !           435:        }
        !           436:
        !           437:        /*
        !           438:         * XXX should we disable modem change and
        !           439:         * receive interrupts here or somewhere ?
        !           440:         */
        !           441:        CLR(tp->t_state, TS_BUSY | TS_FLUSH);
        !           442:
        !           443:        splx(s);
        !           444:        ttyclose(tp);
        !           445:
        !           446:        return (0);
        !           447: }
        !           448:
        !           449: /*
        !           450:  * Read routine
        !           451:  */
        !           452: int
        !           453: cyread(dev, uio, flag)
        !           454:        dev_t dev;
        !           455:        struct uio *uio;
        !           456:        int flag;
        !           457: {
        !           458:        int card = CY_CARD(dev);
        !           459:        int port = CY_PORT(dev);
        !           460:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           461:        struct cy_port *cy = &sc->sc_ports[port];
        !           462:        struct tty *tp = cy->cy_tty;
        !           463:
        !           464: #ifdef CY_DEBUG
        !           465:        printf("%s read port %d uio 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
        !           466:            port, uio, flag);
        !           467: #endif
        !           468:
        !           469:        return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
        !           470: }
        !           471:
        !           472: /*
        !           473:  * Write routine
        !           474:  */
        !           475: int
        !           476: cywrite(dev, uio, flag)
        !           477:        dev_t dev;
        !           478:        struct uio *uio;
        !           479:        int flag;
        !           480: {
        !           481:        int card = CY_CARD(dev);
        !           482:        int port = CY_PORT(dev);
        !           483:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           484:        struct cy_port *cy = &sc->sc_ports[port];
        !           485:        struct tty *tp = cy->cy_tty;
        !           486:
        !           487: #ifdef CY_DEBUG
        !           488:        printf("%s write port %d uio 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
        !           489:            port, uio, flag);
        !           490: #endif
        !           491:
        !           492:        return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
        !           493: }
        !           494:
        !           495: /*
        !           496:  * return tty pointer
        !           497:  */
        !           498: struct tty *
        !           499: cytty(dev)
        !           500:        dev_t dev;
        !           501: {
        !           502:        int card = CY_CARD(dev);
        !           503:        int port = CY_PORT(dev);
        !           504:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           505:        struct cy_port *cy = &sc->sc_ports[port];
        !           506:        struct tty *tp = cy->cy_tty;
        !           507:
        !           508:        return (tp);
        !           509: }
        !           510:
        !           511: /*
        !           512:  * ioctl routine
        !           513:  */
        !           514: int
        !           515: cyioctl(dev, cmd, data, flag, p)
        !           516:        dev_t dev;
        !           517:        u_long cmd;
        !           518:        caddr_t data;
        !           519:        int flag;
        !           520:        struct proc *p;
        !           521: {
        !           522:        int card = CY_CARD(dev);
        !           523:        int port = CY_PORT(dev);
        !           524:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           525:        struct cy_port *cy = &sc->sc_ports[port];
        !           526:        struct tty *tp = cy->cy_tty;
        !           527:        int error;
        !           528:
        !           529: #ifdef CY_DEBUG
        !           530:        printf("%s port %d ioctl cmd 0x%x data 0x%x flag 0x%x\n",
        !           531:            sc->sc_dev.dv_xname, port, cmd, data, flag);
        !           532: #endif
        !           533:
        !           534:        error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
        !           535:        if (error >= 0)
        !           536:                return (error);
        !           537:
        !           538:        error = ttioctl(tp, cmd, data, flag, p);
        !           539:        if (error >= 0)
        !           540:                return (error);
        !           541:
        !           542:        /* XXX should not allow dropping DTR when dialin? */
        !           543:
        !           544:        switch (cmd) {
        !           545:        case TIOCSBRK:          /* start break */
        !           546:                SET(cy->cy_flags, CYF_START_BREAK);
        !           547:                cy_enable_transmitter(cy);
        !           548:                break;
        !           549:
        !           550:        case TIOCCBRK:          /* stop break */
        !           551:                SET(cy->cy_flags, CYF_END_BREAK);
        !           552:                cy_enable_transmitter(cy);
        !           553:                break;
        !           554:
        !           555:        case TIOCSDTR:          /* DTR on */
        !           556:                cy_modem_control(cy, TIOCM_DTR, DMBIS);
        !           557:                break;
        !           558:
        !           559:        case TIOCCDTR:          /* DTR off */
        !           560:                cy_modem_control(cy, TIOCM_DTR, DMBIC);
        !           561:                break;
        !           562:
        !           563:        case TIOCMSET:          /* set new modem control line values */
        !           564:                cy_modem_control(cy, *((int *)data), DMSET);
        !           565:                break;
        !           566:
        !           567:        case TIOCMBIS:          /* turn modem control bits on */
        !           568:                cy_modem_control(cy, *((int *)data), DMBIS);
        !           569:                break;
        !           570:
        !           571:        case TIOCMBIC:          /* turn modem control bits off */
        !           572:                cy_modem_control(cy, *((int *)data), DMBIC);
        !           573:                break;
        !           574:
        !           575:        case TIOCMGET:          /* get modem control/status line state */
        !           576:                *((int *)data) = cy_modem_control(cy, 0, DMGET);
        !           577:                break;
        !           578:
        !           579:        case TIOCGFLAGS:
        !           580:                *((int *)data) = cy->cy_openflags |
        !           581:                    (CY_DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0);
        !           582:                break;
        !           583:
        !           584:        case TIOCSFLAGS:
        !           585:                error = suser(p, 0);
        !           586:                if (error != 0)
        !           587:                        return (EPERM);
        !           588:
        !           589:                cy->cy_openflags = *((int *)data) &
        !           590:                    (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL |
        !           591:                     TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF);
        !           592:                break;
        !           593:
        !           594:        default:
        !           595:                return (ENOTTY);
        !           596:        }
        !           597:
        !           598:        return (0);
        !           599: }
        !           600:
        !           601: /*
        !           602:  * start output
        !           603:  */
        !           604: void
        !           605: cystart(tp)
        !           606:        struct tty *tp;
        !           607: {
        !           608:        int card = CY_CARD(tp->t_dev);
        !           609:        int port = CY_PORT(tp->t_dev);
        !           610:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           611:        struct cy_port *cy = &sc->sc_ports[port];
        !           612:        int s;
        !           613:
        !           614: #ifdef CY_DEBUG
        !           615:        printf("%s port %d start, tty 0x%x\n", sc->sc_dev.dv_xname, port, tp);
        !           616: #endif
        !           617:
        !           618:        s = spltty();
        !           619:
        !           620: #ifdef CY_DEBUG1
        !           621:        cy->cy_start_count++;
        !           622: #endif
        !           623:
        !           624:        if (!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) {
        !           625:                if (tp->t_outq.c_cc <= tp->t_lowat) {
        !           626:                        if (ISSET(tp->t_state, TS_ASLEEP)) {
        !           627:                                CLR(tp->t_state, TS_ASLEEP);
        !           628:                                wakeup(&tp->t_outq);
        !           629:                        }
        !           630:
        !           631:                        selwakeup(&tp->t_wsel);
        !           632:
        !           633:                        if (tp->t_outq.c_cc == 0)
        !           634:                                goto out;
        !           635:                }
        !           636:
        !           637:                SET(tp->t_state, TS_BUSY);
        !           638:                cy_enable_transmitter(cy);
        !           639:        }
        !           640: out:
        !           641:
        !           642:        splx(s);
        !           643: }
        !           644:
        !           645: /*
        !           646:  * stop output
        !           647:  */
        !           648: int
        !           649: cystop(tp, flag)
        !           650:        struct tty *tp;
        !           651:        int flag;
        !           652: {
        !           653:        int card = CY_CARD(tp->t_dev);
        !           654:        int port = CY_PORT(tp->t_dev);
        !           655:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           656:        struct cy_port *cy = &sc->sc_ports[port];
        !           657:        int s;
        !           658:
        !           659: #ifdef CY_DEBUG
        !           660:        printf("%s port %d stop tty 0x%x flag 0x%x\n", sc->sc_dev.dv_xname,
        !           661:            port, tp, flag);
        !           662: #endif
        !           663:
        !           664:        s = spltty();
        !           665:
        !           666:        if (ISSET(tp->t_state, TS_BUSY)) {
        !           667:                if (!ISSET(tp->t_state, TS_TTSTOP))
        !           668:                        SET(tp->t_state, TS_FLUSH);
        !           669:
        !           670:                /*
        !           671:                 * the transmit interrupt routine will disable transmit when it
        !           672:                 * notices that CYF_STOP has been set.
        !           673:                 */
        !           674:                SET(cy->cy_flags, CYF_STOP);
        !           675:        }
        !           676:        splx(s);
        !           677:        return (0);
        !           678: }
        !           679:
        !           680: /*
        !           681:  * parameter setting routine.
        !           682:  * returns 0 if successful, else returns error code
        !           683:  */
        !           684: int
        !           685: cyparam(tp, t)
        !           686:        struct tty *tp;
        !           687:        struct termios *t;
        !           688: {
        !           689:        int card = CY_CARD(tp->t_dev);
        !           690:        int port = CY_PORT(tp->t_dev);
        !           691:        struct cy_softc *sc = cy_cd.cd_devs[card];
        !           692:        struct cy_port *cy = &sc->sc_ports[port];
        !           693:        int ibpr, obpr, i_clk_opt, o_clk_opt;
        !           694:        int s, opt;
        !           695:
        !           696: #ifdef CY_DEBUG
        !           697:        printf("%s port %d param tty 0x%x termios 0x%x\n", sc->sc_dev.dv_xname,
        !           698:            port, tp, t);
        !           699:        printf("ispeed %d ospeed %d\n", t->c_ispeed, t->c_ospeed);
        !           700: #endif
        !           701:
        !           702:        if (t->c_ospeed != 0 &&
        !           703:            cy_speed(t->c_ospeed, &o_clk_opt, &obpr, cy->cy_clock) < 0)
        !           704:                return (EINVAL);
        !           705:
        !           706:        if (t->c_ispeed != 0 &&
        !           707:            cy_speed(t->c_ispeed, &i_clk_opt, &ibpr, cy->cy_clock) < 0)
        !           708:                return (EINVAL);
        !           709:
        !           710:        s = spltty();
        !           711:
        !           712:        /* hang up the line is ospeed is zero, else turn DTR on */
        !           713:        cy_modem_control(cy, TIOCM_DTR, (t->c_ospeed == 0 ? DMBIC : DMBIS));
        !           714:
        !           715:        /* channel was selected by the above call to cy_modem_control() */
        !           716:        /* cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN); */
        !           717:
        !           718:        /* set transmit speed */
        !           719:        if (t->c_ospeed != 0) {
        !           720:                cd_write_reg(cy, CD1400_TCOR, o_clk_opt);
        !           721:                cd_write_reg(cy, CD1400_TBPR, obpr);
        !           722:        }
        !           723:        /* set receive speed */
        !           724:        if (t->c_ispeed != 0) {
        !           725:                cd_write_reg(cy, CD1400_RCOR, i_clk_opt);
        !           726:                cd_write_reg(cy, CD1400_RBPR, ibpr);
        !           727:        }
        !           728:
        !           729:        opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
        !           730:            | (ISSET(t->c_cflag, CREAD) ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
        !           731:
        !           732:        if (opt != cy->cy_channel_control) {
        !           733:                cy->cy_channel_control = opt;
        !           734:                cd1400_channel_cmd(cy, opt);
        !           735:        }
        !           736:
        !           737:        /* compute COR1 contents */
        !           738:        opt = 0;
        !           739:        if (ISSET(t->c_cflag, PARENB)) {
        !           740:                if (ISSET(t->c_cflag, PARODD))
        !           741:                        opt |= CD1400_COR1_PARODD;
        !           742:                opt |= CD1400_COR1_PARNORMAL;
        !           743:        }
        !           744:
        !           745:        if (!ISSET(t->c_iflag, INPCK))
        !           746:                opt |= CD1400_COR1_NOINPCK;     /* no parity checking */
        !           747:
        !           748:        if (ISSET(t->c_cflag, CSTOPB))
        !           749:                opt |= CD1400_COR1_STOP2;
        !           750:
        !           751:        switch (t->c_cflag & CSIZE) {
        !           752:        case CS5:
        !           753:                opt |= CD1400_COR1_CS5;
        !           754:                break;
        !           755:
        !           756:        case CS6:
        !           757:                opt |= CD1400_COR1_CS6;
        !           758:                break;
        !           759:
        !           760:        case CS7:
        !           761:                opt |= CD1400_COR1_CS7;
        !           762:                break;
        !           763:
        !           764:        default:
        !           765:                opt |= CD1400_COR1_CS8;
        !           766:                break;
        !           767:        }
        !           768:
        !           769:        cd_write_reg(cy, CD1400_COR1, opt);
        !           770:
        !           771: #ifdef CY_DEBUG
        !           772:        printf("cor1 = 0x%x...", opt);
        !           773: #endif
        !           774:
        !           775:        /*
        !           776:         * use the CD1400 automatic CTS flow control if CRTSCTS is set
        !           777:         *
        !           778:         * CD1400_COR2_ETC is used because breaks are generated with
        !           779:         * embedded transmit commands
        !           780:         */
        !           781:        cd_write_reg(cy, CD1400_COR2,
        !           782:            CD1400_COR2_ETC |
        !           783:            (ISSET(t->c_cflag, CRTSCTS) ? CD1400_COR2_CCTS_OFLOW : 0));
        !           784:
        !           785:        cd_write_reg(cy, CD1400_COR3, RX_FIFO_THRESHOLD);
        !           786:
        !           787:        cd1400_channel_cmd(cy,
        !           788:            CD1400_CCR_CMDCORCHG |
        !           789:            CD1400_CCR_COR1 | CD1400_CCR_COR2 | CD1400_CCR_COR3);
        !           790:
        !           791:        cd_write_reg(cy, CD1400_COR4, CD1400_COR4_PFO_EXCEPTION);
        !           792:        cd_write_reg(cy, CD1400_COR5, 0);
        !           793:
        !           794:        /*
        !           795:         * set modem change option registers to generate interrupts
        !           796:         * on carrier detect changes.
        !           797:         *
        !           798:         * if hardware RTS handshaking is used (CY_HW_RTS, DTR and RTS lines
        !           799:         * exchanged), also set the handshaking threshold.
        !           800:         */
        !           801: #ifdef CY_HW_RTS
        !           802:        cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd |
        !           803:            (ISSET(t->c_cflag, CRTSCTS) ? RX_DTR_THRESHOLD : 0));
        !           804: #else
        !           805:        cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd);
        !           806: #endif /* CY_HW_RTS */
        !           807:
        !           808:        cd_write_reg(cy, CD1400_MCOR2, CD1400_MCOR2_CDod);
        !           809:
        !           810:        /*
        !           811:         * set receive timeout to approx. 2ms
        !           812:         * could use more complex logic here...
        !           813:         * (but is it actually needed or even useful?)
        !           814:         */
        !           815:        cd_write_reg(cy, CD1400_RTPR, 2);
        !           816:
        !           817:        /*
        !           818:         * should do anything else here?
        !           819:         * XXX check MDMBUF handshaking like in com.c?
        !           820:         */
        !           821:
        !           822:        splx(s);
        !           823:        return (0);
        !           824: }
        !           825:
        !           826: /*
        !           827:  * set/get modem line status
        !           828:  *
        !           829:  * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR
        !           830:  *
        !           831:  * RTS and DTR are exchanged if CY_HW_RTS is set
        !           832:  *
        !           833:  */
        !           834: int
        !           835: cy_modem_control(cy, bits, howto)
        !           836:        struct cy_port *cy;
        !           837:        int bits;
        !           838:        int howto;
        !           839: {
        !           840:        int s, msvr;
        !           841:
        !           842:        s = spltty();
        !           843:
        !           844:        /* select channel */
        !           845:        cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN);
        !           846:
        !           847: /* does not manipulate RTS if it is used for flow control */
        !           848:        switch (howto) {
        !           849:        case DMGET:
        !           850:                bits = 0;
        !           851:                if (cy->cy_channel_control & CD1400_CCR_RCVEN)
        !           852:                        bits |= TIOCM_LE;
        !           853:                msvr = cd_read_reg(cy, CD1400_MSVR2);
        !           854: #ifdef CY_HW_RTS
        !           855:                if (cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS)
        !           856:                        bits |= TIOCM_DTR;
        !           857:                if (msvr & CD1400_MSVR2_DTR)
        !           858:                        bits |= TIOCM_RTS;
        !           859: #else
        !           860:                if (cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS)
        !           861:                        bits |= TIOCM_RTS;
        !           862:                if (msvr & CD1400_MSVR2_DTR)
        !           863:                        bits |= TIOCM_DTR;
        !           864: #endif /* CY_HW_RTS */
        !           865:                if (msvr & CD1400_MSVR2_CTS)
        !           866:                        bits |= TIOCM_CTS;
        !           867:                if (msvr & CD1400_MSVR2_CD)
        !           868:                        bits |= TIOCM_CD;
        !           869:                if (msvr & CD1400_MSVR2_DSR)    /* not connected on some
        !           870:                                                   Cyclom cards? */
        !           871:                        bits |= TIOCM_DSR;
        !           872:                if (msvr & CD1400_MSVR2_RI)     /* not connected on
        !           873:                                                   Cyclom-8Y cards? */
        !           874:                        bits |= TIOCM_RI;
        !           875:                splx(s);
        !           876:                return (bits);
        !           877:
        !           878:        case DMSET: /* replace old values with new ones */
        !           879: #ifdef CY_HW_RTS
        !           880:                if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS))
        !           881:                        cd_write_reg(cy, CD1400_MSVR2,
        !           882:                            ((bits & TIOCM_RTS) ? CD1400_MSVR2_DTR : 0));
        !           883:                cd_write_reg(cy, CD1400_MSVR1,
        !           884:                    ((bits & TIOCM_DTR) ? CD1400_MSVR1_RTS : 0));
        !           885: #else
        !           886:                if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS))
        !           887:                        cd_write_reg(cy, CD1400_MSVR1,
        !           888:                            ((bits & TIOCM_RTS) ? CD1400_MSVR1_RTS : 0));
        !           889:                cd_write_reg(cy, CD1400_MSVR2,
        !           890:                    ((bits & TIOCM_DTR) ? CD1400_MSVR2_DTR : 0));
        !           891: #endif /* CY_HW_RTS */
        !           892:                break;
        !           893:
        !           894:        case DMBIS: /* set bits */
        !           895: #ifdef CY_HW_RTS
        !           896:                if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
        !           897:                    (bits & TIOCM_RTS) != 0)
        !           898:                        cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR);
        !           899:                if (bits & TIOCM_DTR)
        !           900:                        cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS);
        !           901: #else
        !           902:                if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
        !           903:                    (bits & TIOCM_RTS) != 0)
        !           904:                        cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS);
        !           905:                if (bits & TIOCM_DTR)
        !           906:                        cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR);
        !           907: #endif /* CY_HW_RTS */
        !           908:                break;
        !           909:
        !           910:        case DMBIC: /* clear bits */
        !           911: #ifdef CY_HW_RTS
        !           912:                if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
        !           913:                    (bits & TIOCM_RTS))
        !           914:                        cd_write_reg(cy, CD1400_MSVR2, 0);
        !           915:                if (bits & TIOCM_DTR)
        !           916:                        cd_write_reg(cy, CD1400_MSVR1, 0);
        !           917: #else
        !           918:                if (!ISSET(cy->cy_tty->t_cflag, CRTSCTS) &&
        !           919:                    (bits & TIOCM_RTS))
        !           920:                        cd_write_reg(cy, CD1400_MSVR1, 0);
        !           921:                if (bits & TIOCM_DTR)
        !           922:                        cd_write_reg(cy, CD1400_MSVR2, 0);
        !           923: #endif /* CY_HW_RTS */
        !           924:                break;
        !           925:        }
        !           926:        splx(s);
        !           927:        return (0);
        !           928: }
        !           929:
        !           930: /*
        !           931:  * Upper-level handler loop (called from timer interrupt?)
        !           932:  * This routine is common for multiple cards
        !           933:  */
        !           934: void
        !           935: cy_poll(void *arg)
        !           936: {
        !           937:        int port;
        !           938:        struct cy_softc *sc = arg;
        !           939:        struct cy_port *cy;
        !           940:        struct tty *tp;
        !           941:        static int counter = 0;
        !           942: #ifdef CY_DEBUG1
        !           943:        int did_something;
        !           944: #endif
        !           945:
        !           946:        int s;
        !           947:
        !           948:        s = spltty();
        !           949:
        !           950:        if (sc->sc_events == 0 && ++counter < 200) {
        !           951:                splx(s);
        !           952:                goto out;
        !           953:        }
        !           954:
        !           955:        sc->sc_events = 0;
        !           956:        splx(s);
        !           957:
        !           958: #ifdef CY_DEBUG1
        !           959:        sc->sc_poll_count1++;
        !           960:        did_something = 0;
        !           961: #endif
        !           962:
        !           963:        for (port = 0; port < sc->sc_nports; port++) {
        !           964:                cy = &sc->sc_ports[port];
        !           965:                if ((tp = cy->cy_tty) == NULL || cy->cy_ibuf == NULL ||
        !           966:                    !ISSET(tp->t_state, TS_ISOPEN | TS_WOPEN))
        !           967:                        continue;
        !           968:
        !           969:                /*
        !           970:                 * handle received data
        !           971:                 */
        !           972:                while (cy->cy_ibuf_rd_ptr != cy->cy_ibuf_wr_ptr) {
        !           973:                        u_char line_stat;
        !           974:                        int chr;
        !           975:
        !           976:                        line_stat = cy->cy_ibuf_rd_ptr[0];
        !           977:                        chr = cy->cy_ibuf_rd_ptr[1];
        !           978:
        !           979:                        if (line_stat &
        !           980:                            (CD1400_RDSR_BREAK|CD1400_RDSR_FE))
        !           981:                                chr |= TTY_FE;
        !           982:                        if (line_stat & CD1400_RDSR_PE)
        !           983:                                chr |= TTY_PE;
        !           984:
        !           985:                        /*
        !           986:                         * on an overrun error the data is treated as
        !           987:                         * good just as it should be.
        !           988:                         */
        !           989:
        !           990: #ifdef CY_DEBUG
        !           991:                        printf("%s port %d ttyinput 0x%x\n",
        !           992:                            sc->sc_dev.dv_xname, port, chr);
        !           993: #endif
        !           994:
        !           995:                        (*linesw[tp->t_line].l_rint)(chr, tp);
        !           996:
        !           997:                        s = spltty(); /* really necessary? */
        !           998:                        if ((cy->cy_ibuf_rd_ptr += 2) ==
        !           999:                            cy->cy_ibuf_end)
        !          1000:                                cy->cy_ibuf_rd_ptr = cy->cy_ibuf;
        !          1001:                        splx(s);
        !          1002:
        !          1003: #ifdef CY_DEBUG1
        !          1004:                        did_something = 1;
        !          1005: #endif
        !          1006:                }
        !          1007:
        !          1008: #ifndef CY_HW_RTS
        !          1009:                /*
        !          1010:                 * If we don't have any received data in ibuf and
        !          1011:                 * CRTSCTS is on and RTS is turned off, it is time
        !          1012:                 * to turn RTS back on
        !          1013:                 */
        !          1014:                if (ISSET(tp->t_cflag, CRTSCTS)) {
        !          1015:                        /* we can't use cy_modem_control() here as it
        !          1016:                            doesn't change RTS if RTSCTS is on */
        !          1017:                        cd_write_reg(cy, CD1400_CAR,
        !          1018:                            port & CD1400_CAR_CHAN);
        !          1019:
        !          1020:                        if ((cd_read_reg(cy,
        !          1021:                            CD1400_MSVR1) & CD1400_MSVR1_RTS) == 0) {
        !          1022:                                cd_write_reg(cy, CD1400_MSVR1,
        !          1023:                                    CD1400_MSVR1_RTS);
        !          1024: #ifdef CY_DEBUG1
        !          1025:                                did_something = 1;
        !          1026: #endif
        !          1027:                        }
        !          1028:                }
        !          1029: #endif /* CY_HW_RTS */
        !          1030:
        !          1031:                /*
        !          1032:                 * handle carrier changes
        !          1033:                 */
        !          1034:                s = spltty();
        !          1035:                if (ISSET(cy->cy_flags, CYF_CARRIER_CHANGED)) {
        !          1036:                        int carrier;
        !          1037:
        !          1038:                        CLR(cy->cy_flags, CYF_CARRIER_CHANGED);
        !          1039:                        splx(s);
        !          1040:
        !          1041:                        carrier = ((cy->cy_carrier_stat &
        !          1042:                            CD1400_MSVR2_CD) != 0);
        !          1043:
        !          1044: #ifdef CY_DEBUG
        !          1045:                        printf("%s: cy_poll: carrier change "
        !          1046:                            "(port %d, carrier %d)\n",
        !          1047:                            sc->sc_dev.dv_xname, port, carrier);
        !          1048: #endif
        !          1049:                        if (CY_DIALIN(tp->t_dev) &&
        !          1050:                            !(*linesw[tp->t_line].l_modem)(tp, carrier))
        !          1051:                                cy_modem_control(cy, TIOCM_DTR, DMBIC);
        !          1052:
        !          1053: #ifdef CY_DEBUG1
        !          1054:                        did_something = 1;
        !          1055: #endif
        !          1056:                } else {
        !          1057:                        splx(s);
        !          1058:                }
        !          1059:
        !          1060:                s = spltty();
        !          1061:                if (ISSET(cy->cy_flags, CYF_START)) {
        !          1062:                        CLR(cy->cy_flags, CYF_START);
        !          1063:                        splx(s);
        !          1064:
        !          1065:                        (*linesw[tp->t_line].l_start)(tp);
        !          1066:
        !          1067: #ifdef CY_DEBUG1
        !          1068:                        did_something = 1;
        !          1069: #endif
        !          1070:                } else {
        !          1071:                        splx(s);
        !          1072:                }
        !          1073:
        !          1074:                /* could move this to even upper level... */
        !          1075:                if (cy->cy_fifo_overruns) {
        !          1076:                        cy->cy_fifo_overruns = 0;
        !          1077:                        /* doesn't report overrun count,
        !          1078:                           but shouldn't really matter */
        !          1079:                        log(LOG_WARNING, "%s: port %d fifo overrun\n",
        !          1080:                            sc->sc_dev.dv_xname, port);
        !          1081:                }
        !          1082:                if (cy->cy_ibuf_overruns) {
        !          1083:                        cy->cy_ibuf_overruns = 0;
        !          1084:                        log(LOG_WARNING, "%s: port %d ibuf overrun\n",
        !          1085:                            sc->sc_dev.dv_xname, port);
        !          1086:                }
        !          1087:        } /* for(port...) */
        !          1088: #ifdef CY_DEBUG1
        !          1089:        if (did_something && counter >= 200)
        !          1090:                sc->sc_poll_count2++;
        !          1091: #endif
        !          1092:
        !          1093:        counter = 0;
        !          1094:
        !          1095: out:
        !          1096:        timeout_add(&sc->sc_poll_to, 1);
        !          1097: }
        !          1098:
        !          1099: /*
        !          1100:  * hardware interrupt routine
        !          1101:  */
        !          1102: int
        !          1103: cy_intr(arg)
        !          1104:        void *arg;
        !          1105: {
        !          1106:        struct cy_softc *sc = arg;
        !          1107:        struct cy_port *cy;
        !          1108:        int cy_chip, stat;
        !          1109:        int int_serviced = -1;
        !          1110:
        !          1111:        /*
        !          1112:         * Check interrupt status of each CD1400 chip on this card
        !          1113:         * (multiple cards cannot share the same interrupt)
        !          1114:         */
        !          1115:        for (cy_chip = 0; cy_chip < sc->sc_nr_cd1400s; cy_chip++) {
        !          1116:
        !          1117:                stat = cd_read_reg_sc(sc, cy_chip, CD1400_SVRR);
        !          1118:                if (stat == 0)
        !          1119:                        continue;
        !          1120:
        !          1121:                if (ISSET(stat, CD1400_SVRR_RXRDY)) {
        !          1122:                        u_char save_car, save_rir, serv_type;
        !          1123:                        u_char line_stat, recv_data, n_chars;
        !          1124:                        u_char *buf_p;
        !          1125:
        !          1126:                        save_rir = cd_read_reg_sc(sc, cy_chip, CD1400_RIR);
        !          1127:                        save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
        !          1128:                        /* enter rx service */
        !          1129:                        cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_rir);
        !          1130:
        !          1131:                        serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_RIVR);
        !          1132:                        cy = &sc->sc_ports[serv_type >> 3];
        !          1133:
        !          1134: #ifdef CY_DEBUG1
        !          1135:                        cy->cy_rx_int_count++;
        !          1136: #endif
        !          1137:
        !          1138:                        buf_p = cy->cy_ibuf_wr_ptr;
        !          1139:
        !          1140:                        if (ISSET(serv_type, CD1400_RIVR_EXCEPTION)) {
        !          1141:                                line_stat = cd_read_reg(cy, CD1400_RDSR);
        !          1142:                                recv_data = cd_read_reg(cy, CD1400_RDSR);
        !          1143:
        !          1144:                                if (cy->cy_tty == NULL ||
        !          1145:                                    !ISSET(cy->cy_tty->t_state, TS_ISOPEN))
        !          1146:                                        goto end_rx_serv;
        !          1147:
        !          1148: #ifdef CY_DEBUG
        !          1149:                                printf("%s port %d recv exception, "
        !          1150:                                    "line_stat 0x%x, char 0x%x\n",
        !          1151:                                    sc->sc_dev.dv_xname, cy->cy_port_num,
        !          1152:                                    line_stat, recv_data);
        !          1153: #endif
        !          1154:                                if (ISSET(line_stat, CD1400_RDSR_OE))
        !          1155:                                        cy->cy_fifo_overruns++;
        !          1156:
        !          1157:                                *buf_p++ = line_stat;
        !          1158:                                *buf_p++ = recv_data;
        !          1159:                                if (buf_p == cy->cy_ibuf_end)
        !          1160:                                        buf_p = cy->cy_ibuf;
        !          1161:
        !          1162:                                if (buf_p == cy->cy_ibuf_rd_ptr) {
        !          1163:                                        if (buf_p == cy->cy_ibuf)
        !          1164:                                                buf_p = cy->cy_ibuf_end;
        !          1165:                                        buf_p -= 2;
        !          1166:                                        cy->cy_ibuf_overruns++;
        !          1167:                                }
        !          1168:                                sc->sc_events = 1;
        !          1169:                        } else { /* no exception, received data OK */
        !          1170:                                n_chars = cd_read_reg(cy, CD1400_RDCR);
        !          1171:
        !          1172:                                /* If no tty or not open, discard data */
        !          1173:                                if (cy->cy_tty == NULL ||
        !          1174:                                    !ISSET(cy->cy_tty->t_state, TS_ISOPEN)) {
        !          1175:                                        while (n_chars--)
        !          1176:                                                cd_read_reg(cy, CD1400_RDSR);
        !          1177:                                        goto end_rx_serv;
        !          1178:                                }
        !          1179:
        !          1180: #ifdef CY_DEBUG
        !          1181:                                printf("%s port %d receive ok %d chars\n",
        !          1182:                                    sc->sc_dev.dv_xname, cy->cy_port_num,
        !          1183:                                    n_chars);
        !          1184: #endif
        !          1185:                                while (n_chars--) {
        !          1186:                                        *buf_p++ = 0; /* status: OK */
        !          1187:                                        *buf_p++ = cd_read_reg(cy,
        !          1188:                                            CD1400_RDSR); /* data byte */
        !          1189:                                        if (buf_p == cy->cy_ibuf_end)
        !          1190:                                                buf_p = cy->cy_ibuf;
        !          1191:                                        if (buf_p == cy->cy_ibuf_rd_ptr) {
        !          1192:                                                if (buf_p == cy->cy_ibuf)
        !          1193:                                                        buf_p = cy->cy_ibuf_end;
        !          1194:                                                buf_p -= 2;
        !          1195:                                                cy->cy_ibuf_overruns++;
        !          1196:                                                break;
        !          1197:                                        }
        !          1198:                                }
        !          1199:                                sc->sc_events = 1;
        !          1200:                        }
        !          1201:
        !          1202:                        cy->cy_ibuf_wr_ptr = buf_p;
        !          1203:
        !          1204: #ifndef CY_HW_RTS
        !          1205:                        /* RTS handshaking for incoming data */
        !          1206:                        if (ISSET(cy->cy_tty->t_cflag, CRTSCTS)) {
        !          1207:                                int bf;
        !          1208:
        !          1209:                                bf = buf_p - cy->cy_ibuf_rd_ptr;
        !          1210:                                if (bf < 0)
        !          1211:                                        bf += IBUF_SIZE;
        !          1212:
        !          1213:                                if (bf > (IBUF_SIZE/2)) /* turn RTS off */
        !          1214:                                        cd_write_reg(cy, CD1400_MSVR1, 0);
        !          1215:                        }
        !          1216: #endif /* CY_HW_RTS */
        !          1217:
        !          1218:                end_rx_serv:
        !          1219:                        /* terminate service context */
        !          1220:                        cd_write_reg(cy, CD1400_RIR, save_rir & 0x3f);
        !          1221:                        cd_write_reg(cy, CD1400_CAR, save_car);
        !          1222:                        int_serviced = 1;
        !          1223:                } /* if(rx_service...) */
        !          1224:
        !          1225:                if (ISSET(stat, CD1400_SVRR_MDMCH)) {
        !          1226:                        u_char save_car, save_mir, serv_type, modem_stat;
        !          1227:
        !          1228:                        save_mir = cd_read_reg_sc(sc, cy_chip, CD1400_MIR);
        !          1229:                        save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
        !          1230:                        /* enter modem service */
        !          1231:                        cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_mir);
        !          1232:
        !          1233:                        serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_MIVR);
        !          1234:                        cy = &sc->sc_ports[serv_type >> 3];
        !          1235:
        !          1236: #ifdef CY_DEBUG1
        !          1237:                        cy->cy_modem_int_count++;
        !          1238: #endif
        !          1239:
        !          1240:                        modem_stat = cd_read_reg(cy, CD1400_MSVR2);
        !          1241:
        !          1242: #ifdef CY_DEBUG
        !          1243:                        printf("%s port %d modem line change, new stat 0x%x\n",
        !          1244:                            sc->sc_dev.dv_xname, cy->cy_port_num, modem_stat);
        !          1245: #endif
        !          1246:                        if (ISSET((cy->cy_carrier_stat ^ modem_stat),
        !          1247:                            CD1400_MSVR2_CD)) {
        !          1248:                                SET(cy->cy_flags, CYF_CARRIER_CHANGED);
        !          1249:                                sc->sc_events = 1;
        !          1250:                        }
        !          1251:
        !          1252:                        cy->cy_carrier_stat = modem_stat;
        !          1253:
        !          1254:                        /* terminate service context */
        !          1255:                        cd_write_reg(cy, CD1400_MIR, save_mir & 0x3f);
        !          1256:                        cd_write_reg(cy, CD1400_CAR, save_car);
        !          1257:                        int_serviced = 1;
        !          1258:                } /* if(modem_service...) */
        !          1259:
        !          1260:                if (ISSET(stat, CD1400_SVRR_TXRDY)) {
        !          1261:                        u_char save_car, save_tir, serv_type, count, ch;
        !          1262:                        struct tty *tp;
        !          1263:
        !          1264:                        save_tir = cd_read_reg_sc(sc, cy_chip, CD1400_TIR);
        !          1265:                        save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR);
        !          1266:                        /* enter tx service */
        !          1267:                        cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_tir);
        !          1268:
        !          1269:                        serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_TIVR);
        !          1270:                        cy = &sc->sc_ports[serv_type >> 3];
        !          1271:
        !          1272: #ifdef CY_DEBUG1
        !          1273:                        cy->cy_tx_int_count++;
        !          1274: #endif
        !          1275: #ifdef CY_DEBUG
        !          1276:                        printf("%s port %d tx service\n", sc->sc_dev.dv_xname,
        !          1277:                            cy->cy_port_num);
        !          1278: #endif
        !          1279:
        !          1280:                        /* stop transmitting if no tty or CYF_STOP set */
        !          1281:                        tp = cy->cy_tty;
        !          1282:                        if (tp == NULL || ISSET(cy->cy_flags, CYF_STOP))
        !          1283:                                goto txdone;
        !          1284:
        !          1285:                        count = 0;
        !          1286:                        if (ISSET(cy->cy_flags, CYF_SEND_NUL)) {
        !          1287:                                cd_write_reg(cy, CD1400_TDR, 0);
        !          1288:                                cd_write_reg(cy, CD1400_TDR, 0);
        !          1289:                                count += 2;
        !          1290:                                CLR(cy->cy_flags, CYF_SEND_NUL);
        !          1291:                        }
        !          1292:
        !          1293:                        if (tp->t_outq.c_cc > 0) {
        !          1294:                                SET(tp->t_state, TS_BUSY);
        !          1295:                                while (tp->t_outq.c_cc > 0 &&
        !          1296:                                    count < CD1400_TX_FIFO_SIZE) {
        !          1297:                                        ch = getc(&tp->t_outq);
        !          1298:                                        /* remember to double NUL characters
        !          1299:                                           because embedded transmit commands
        !          1300:                                           are enabled */
        !          1301:                                        if (ch == 0) {
        !          1302:                                                if (count >=
        !          1303:                                                    CD1400_TX_FIFO_SIZE-2) {
        !          1304:                                                        SET(cy->cy_flags,
        !          1305:                                                            CYF_SEND_NUL);
        !          1306:                                                        break;
        !          1307:                                                }
        !          1308:
        !          1309:                                                cd_write_reg(cy, CD1400_TDR, ch);
        !          1310:                                                count++;
        !          1311:                                        }
        !          1312:
        !          1313:                                        cd_write_reg(cy, CD1400_TDR, ch);
        !          1314:                                        count++;
        !          1315:                                }
        !          1316:                        } else {
        !          1317:                                /* no data to send -- check if we should
        !          1318:                                   start/stop a break */
        !          1319:                                /* XXX does this cause too much delay before
        !          1320:                                   breaks? */
        !          1321:                                if (ISSET(cy->cy_flags, CYF_START_BREAK)) {
        !          1322:                                        cd_write_reg(cy, CD1400_TDR, 0);
        !          1323:                                        cd_write_reg(cy, CD1400_TDR, 0x81);
        !          1324:                                        CLR(cy->cy_flags, CYF_START_BREAK);
        !          1325:                                }
        !          1326:                                if (ISSET(cy->cy_flags, CYF_END_BREAK)) {
        !          1327:                                        cd_write_reg(cy, CD1400_TDR, 0);
        !          1328:                                        cd_write_reg(cy, CD1400_TDR, 0x83);
        !          1329:                                        CLR(cy->cy_flags, CYF_END_BREAK);
        !          1330:                                }
        !          1331:                        }
        !          1332:
        !          1333:                        if (tp->t_outq.c_cc == 0) {
        !          1334: txdone:
        !          1335:                                /*
        !          1336:                                 * No data to send or requested to stop.
        !          1337:                                 * Disable transmit interrupt
        !          1338:                                 */
        !          1339:                                cd_write_reg(cy, CD1400_SRER,
        !          1340:                                    cd_read_reg(cy, CD1400_SRER)
        !          1341:                                    & ~CD1400_SRER_TXRDY);
        !          1342:                                CLR(cy->cy_flags, CYF_STOP);
        !          1343:                                CLR(tp->t_state, TS_BUSY);
        !          1344:                        }
        !          1345:
        !          1346:                        if (tp->t_outq.c_cc <= tp->t_lowat) {
        !          1347:                                SET(cy->cy_flags, CYF_START);
        !          1348:                                sc->sc_events = 1;
        !          1349:                        }
        !          1350:
        !          1351:                        /* terminate service context */
        !          1352:                        cd_write_reg(cy, CD1400_TIR, save_tir & 0x3f);
        !          1353:                        cd_write_reg(cy, CD1400_CAR, save_car);
        !          1354:                        int_serviced = 1;
        !          1355:                } /* if(tx_service...) */
        !          1356:        } /* for(...all CD1400s on a card) */
        !          1357:
        !          1358:        /* ensure an edge for next interrupt */
        !          1359:        bus_space_write_1(sc->sc_memt, sc->sc_memh,
        !          1360:            CY_CLEAR_INTR<<sc->sc_bustype, 0);
        !          1361:        return (int_serviced);
        !          1362: }
        !          1363:
        !          1364: /*
        !          1365:  * subroutine to enable CD1400 transmitter
        !          1366:  */
        !          1367: void
        !          1368: cy_enable_transmitter(cy)
        !          1369:        struct cy_port *cy;
        !          1370: {
        !          1371:        int s;
        !          1372:        s = spltty();
        !          1373:        cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN);
        !          1374:        cd_write_reg(cy, CD1400_SRER, cd_read_reg(cy, CD1400_SRER)
        !          1375:            | CD1400_SRER_TXRDY);
        !          1376:        splx(s);
        !          1377: }
        !          1378:
        !          1379: /*
        !          1380:  * Execute a CD1400 channel command
        !          1381:  */
        !          1382: void
        !          1383: cd1400_channel_cmd(cy, cmd)
        !          1384:        struct cy_port *cy;
        !          1385:        int cmd;
        !          1386: {
        !          1387:        u_int waitcnt = 5 * 8 * 1024; /* approx 5 ms */
        !          1388:
        !          1389: #ifdef CY_DEBUG
        !          1390:        printf("c1400_channel_cmd cy 0x%x command 0x%x\n", cy, cmd);
        !          1391: #endif
        !          1392:
        !          1393:        /* wait until cd1400 is ready to process a new command */
        !          1394:        while (cd_read_reg(cy, CD1400_CCR) != 0 && waitcnt-- > 0)
        !          1395:                ;
        !          1396:
        !          1397:        if (waitcnt == 0)
        !          1398:                log(LOG_ERR, "cy: channel command timeout\n");
        !          1399:
        !          1400:        cd_write_reg(cy, CD1400_CCR, cmd);
        !          1401: }
        !          1402:
        !          1403: /*
        !          1404:  * Compute clock option register and baud rate register values
        !          1405:  * for a given speed. Return 0 on success, -1 on failure.
        !          1406:  *
        !          1407:  * The error between requested and actual speed seems
        !          1408:  * to be well within allowed limits (less than 3%)
        !          1409:  * with every speed value between 50 and 150000 bps.
        !          1410:  */
        !          1411: int
        !          1412: cy_speed(speed_t speed, int *cor, int *bpr, int cy_clock)
        !          1413: {
        !          1414:        int c, co, br;
        !          1415:
        !          1416:        if (speed < 50 || speed > 150000)
        !          1417:                return (-1);
        !          1418:
        !          1419:        for (c = 0, co = 8; co <= 2048; co <<= 2, c++) {
        !          1420:                br = (cy_clock + (co * speed) / 2) / (co * speed);
        !          1421:                if (br < 0x100) {
        !          1422:                        *bpr = br;
        !          1423:                        *cor = c;
        !          1424:                        return (0);
        !          1425:                }
        !          1426:        }
        !          1427:
        !          1428:        return (-1);
        !          1429: }
        !          1430:
        !          1431: #endif /* NCY > 0 */

CVSweb