diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-06-20 11:39:13 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-06-20 11:39:13 +0000 |
commit | c4ebf8483d48c223705bc6538c8f09f48fcff6e9 (patch) | |
tree | 9994c508f1c7fcf2755b1059360ecac6b0d7a012 | |
parent | 513b9524458d966c9ae5e2d7c4334978810c790d (diff) |
Cyclades Cyclom driver for isa/pci; by Timo Rossi; via jmarin@muikku.jmp.fi
-rw-r--r-- | sys/dev/ic/cd1400reg.h | 253 | ||||
-rw-r--r-- | sys/dev/isa/cy.c | 2783 | ||||
-rw-r--r-- | sys/dev/isa/cyreg.h | 66 | ||||
-rw-r--r-- | sys/dev/isa/files.isa | 6 |
4 files changed, 1637 insertions, 1471 deletions
diff --git a/sys/dev/ic/cd1400reg.h b/sys/dev/ic/cd1400reg.h index 9481f71f004..d911f2f3940 100644 --- a/sys/dev/ic/cd1400reg.h +++ b/sys/dev/ic/cd1400reg.h @@ -1,6 +1,6 @@ -/* $NetBSD: cd1400reg.h,v 1.2 1994/10/27 04:18:37 cgd Exp $ */ +/* $OpenBSD: cd1400reg.h,v 1.2 1996/06/20 11:39:12 deraadt Exp $ */ -/* +/*- * cyclades cyclom-y serial driver * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993 * @@ -30,94 +30,169 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#define CD1400_NO_OF_CHANNELS 4 /* four serial channels per chip */ -#define CD1400_FIFOSIZE 12 /* 12 chars */ - -/* register definitions */ - -#define CD1400_CCR 2*0x05 /* channel control */ -#define CD1400_CMD_RESET 0x81 /* full reset */ - -#define CD1400_SRER 2*0x06 /* service request enable */ - -#define CD1400_GFRCR 2*0x40 /* global firmware revision code */ - -#define CD1400_LIVR 2*0x18 /* local intr vector */ -#define CD1400_MIVR 2*0x41 /* modem intr vector */ -#define CD1400_TIVR 2*0x42 /* transmit intr vector */ -#define CD1400_RIVR 2*0x43 /* receive intr vector */ -#define CD1400_RIVR_EXCEPTION (1<<2) /* receive exception bit */ - -#define CD1400_RICR 2*0x44 /* receive intr channel */ -#define CD1400_TICR 2*0x45 /* transmit intr channel */ -#define CD1400_MICR 2*0x46 /* modem intr channel */ - -#define CD1400_RDCR 2*0x0e /* rx data count */ - -#define CD1400_EOSRR 2*0x60 /* end of service request */ -#define CD1400_RDSR 2*0x62 /* rx data/status */ -#define CD1400_RDSR_OVERRUN (1<<0) /* rx overrun error */ -#define CD1400_RDSR_FRAMING (1<<1) /* rx framing error */ -#define CD1400_RDSR_PARITY (1<<2) /* rx parity error */ -#define CD1400_RDSR_BREAK (1<<3) /* rx break */ -#define CD1400_RDSR_SPECIAL (7<<4) /* rx special char */ -#define CD1400_RDSR_SPECIAL_SHIFT 4 /* rx special char shift */ -#define CD1400_RDSR_TIMEOUT (1<<7) /* rx timeout */ - -#define CD1400_TDR 2*0x63 /* tx data */ - -#define CD1400_MISR 2*0x4c /* modem intr status */ -#define CD1400_MISR_DSRd (1<<7) /* DSR delta */ -#define CD1400_MISR_CTSd (1<<6) /* CTS delta */ -#define CD1400_MISR_RId (1<<5) /* RI delta */ -#define CD1400_MISR_CDd (1<<4) /* CD delta */ - -#define CD1400_MSVR 2*0x6d /* modem signals */ -#define CD1400_MSVR_DSR (1<<7) /* !DSR line */ -#define CD1400_MSVR_CTS (1<<6) /* !CTS line */ -#define CD1400_MSVR_RI (1<<5) /* !RI line */ -#define CD1400_MSVR_CD (1<<4) /* !CD line */ -#define CD1400_MSVR_DTR (1<<1) /* DTR line */ - -#define CD1400_DTR 2*0x6d /* dtr control */ -#define CD1400_DTR_CLEAR 0 -#define CD1400_DTR_SET (1<<1) - -#define CD1400_PPR 2*0x7e -#define CD1400_CLOCK_25_1MS 0x31 - -#define CD1400_CAR 2*0x68 /* channel access */ - -#define CD1400_RIR 2*0x6B /* receive interrupt status */ -#define CD1400_TIR 2*0x6A /* transmit interrupt status */ -#define CD1400_MIR 2*0x69 /* modem interrupt status */ - -#define CD1400_RBPR 2*0x78 /* receive baud rate period */ -#define CD1400_RCOR 2*0x7C /* receive clock option */ -#define CD1400_TBPR 2*0x72 /* transmit baud rate period */ -#define CD1400_TCOR 2*0x76 /* transmit clock option */ - -#define CD1400_COR1 2*0x08 /* channel option 1 */ -#define CD1400_COR2 2*0x09 /* channel option 2 */ -#define CD1400_COR3 2*0x0A /* channel option 3 */ -#define CD1400_COR4 2*0x1E /* channel option 4 */ -#define CD1400_COR5 2*0x1F /* channel option 5 */ +/* + * Definitions for Cirrus Logic CD1400 serial/parallel chips. + */ -#define CD1400_SCHR1 2*0x1A /* special character 1 */ -#define CD1400_SCHR2 2*0x1B /* special character 2 */ -#define CD1400_SCHR3 2*0x1C /* special character 3 */ -#define CD1400_SCHR4 2*0x1D /* special character 4 */ +#define CD1400_NO_OF_CHANNELS 4 /* 4 serial channels per chip */ +#define CD1400_RX_FIFO_SIZE 12 +#define CD1400_TX_FIFO_SIZE 12 -#define CD1400_MCOR1 2*0x15 /* modem change 1 */ -#define CD1400_MCOR2 2*0x16 /* modem change 2 */ -#define CD1400_RTPR 2*0x21 /* receive timeout period */ +/* + * Global registers. + */ +#define CD1400_GFRCR 0x40 /* global firmware revision code */ +#define CD1400_CAR 0x68 /* channel access */ +#define CD1400_CAR_CHAN (3<<0) /* channel select */ +#define CD1400_GCR 0x4B /* global configuration */ +#define CD1400_GCR_PARALLEL (1<<7) /* channel 0 is parallel */ +#define CD1400_SVRR 0x67 /* service request */ +#define CD1400_SVRR_MDMCH (1<<2) +#define CD1400_SVRR_TXRDY (1<<1) +#define CD1400_SVRR_RXRDY (1<<0) +#define CD1400_RICR 0x44 /* receive interrupting channel */ +#define CD1400_TICR 0x45 /* transmit interrupting channel */ +#define CD1400_MICR 0x46 /* modem interrupting channel */ +#define CD1400_RIR 0x6B /* receive interrupt status */ +#define CD1400_RIR_RDIREQ (1<<7) /* rx service required */ +#define CD1400_RIR_RBUSY (1<<6) /* rx service in progress */ +#define CD1400_RIR_CHAN (3<<0) /* channel select */ +#define CD1400_TIR 0x6A /* transmit interrupt status */ +#define CD1400_TIR_RDIREQ (1<<7) /* tx service required */ +#define CD1400_TIR_RBUSY (1<<6) /* tx service in progress */ +#define CD1400_TIR_CHAN (3<<0) /* channel select */ +#define CD1400_MIR 0x69 /* modem interrupt status */ +#define CD1400_MIR_RDIREQ (1<<7) /* modem service required */ +#define CD1400_MIR_RBUSY (1<<6) /* modem service in progress */ +#define CD1400_MIR_CHAN (3<<0) /* channel select */ +#define CD1400_PPR 0x7E /* prescaler period */ +#define CD1400_PPR_PRESCALER 512 -#define CD1400_SVRR 2*0x67 /* service request */ -#define CD1400_SVRR_RX (1<<0) -#define CD1400_SVRR_TX (1<<1) -#define CD1400_SVRR_MDM (1<<2) +/* + * Virtual registers. + */ +#define CD1400_RIVR 0x43 /* receive interrupt vector */ +#define CD1400_RIVR_EXCEPTION (1<<2) /* receive exception bit */ +#define CD1400_TIVR 0x42 /* transmit interrupt vector */ +#define CD1400_MIVR 0x41 /* modem interrupt vector */ +#define CD1400_TDR 0x63 /* transmit data */ +#define CD1400_RDSR 0x62 /* receive data/status */ +#define CD1400_RDSR_TIMEOUT (1<<7) /* rx timeout */ +#define CD1400_RDSR_SPECIAL_SHIFT 4 /* rx special char shift */ +#define CD1400_RDSR_SPECIAL (7<<4) /* rx special char */ +#define CD1400_RDSR_BREAK (1<<3) /* rx break */ +#define CD1400_RDSR_PE (1<<2) /* rx parity error */ +#define CD1400_RDSR_FE (1<<1) /* rx framing error */ +#define CD1400_RDSR_OE (1<<0) /* rx overrun error */ +#define CD1400_MISR 0x4C /* modem interrupt status */ +#define CD1400_MISR_DSRd (1<<7) /* DSR delta */ +#define CD1400_MISR_CTSd (1<<6) /* CTS delta */ +#define CD1400_MISR_RId (1<<5) /* RI delta */ +#define CD1400_MISR_CDd (1<<4) /* CD delta */ +#define CD1400_EOSRR 0x60 /* end of service request */ -/* hardware SVCACK addresses, for use in interrupt handlers */ -#define CD1400_SVCACKR 0x100 -#define CD1400_SVCACKT 0x200 -#define CD1400_SVCACKM 0x300 +/* + * Channel registers. + */ +#define CD1400_LIVR 0x18 /* local interrupt vector */ +#define CD1400_CCR 0x05 /* channel control */ +#define CD1400_CCR_CMDRESET (1<<7) /* enables following: */ +#define CD1400_CCR_FTF (1<<1) /* flush tx fifo */ +#define CD1400_CCR_FULLRESET (1<<0) /* full reset */ +#define CD1400_CCR_CMDCORCHG (1<<6) /* enables following: */ +#define CD1400_CCR_COR3 (1<<3) /* COR3 changed */ +#define CD1400_CCR_COR2 (1<<2) /* COR2 changed */ +#define CD1400_CCR_COR1 (1<<1) /* COR1 changed */ +#define CD1400_CCR_CMDSENDSC (1<<5) /* enables following: */ +#define CD1400_CCR_SC (7<<0) /* special char 1-4 */ +#define CD1400_CCR_CMDCHANCTL (1<<4) /* enables following: */ +#define CD1400_CCR_XMTEN (1<<3) /* tx enable */ +#define CD1400_CCR_XMTDIS (1<<2) /* tx disable */ +#define CD1400_CCR_RCVEN (1<<1) /* rx enable */ +#define CD1400_CCR_RCVDIS (1<<0) /* rx disable */ +#define CD1400_SRER 0x06 /* service request enable */ +#define CD1400_SRER_MDMCH (1<<7) /* modem change */ +#define CD1400_SRER_RXDATA (1<<4) /* rx data */ +#define CD1400_SRER_TXRDY (1<<2) /* tx fifo empty */ +#define CD1400_SRER_TXMPTY (1<<1) /* tx shift reg empty */ +#define CD1400_SRER_NNDT (1<<0) /* no new data */ +#define CD1400_COR1 0x08 /* channel option 1 */ +#define CD1400_COR1_PARODD (1<<7) +#define CD1400_COR1_PARNORMAL (2<<5) +#define CD1400_COR1_PARFORCE (1<<5) /* odd/even = force 1/0 */ +#define CD1400_COR1_PARNONE (0<<5) +#define CD1400_COR1_NOINPCK (1<<4) +#define CD1400_COR1_STOP2 (2<<2) +#define CD1400_COR1_STOP15 (1<<2) /* 1.5 stop bits */ +#define CD1400_COR1_STOP1 (0<<2) +#define CD1400_COR1_CS8 (3<<0) +#define CD1400_COR1_CS7 (2<<0) +#define CD1400_COR1_CS6 (1<<0) +#define CD1400_COR1_CS5 (0<<0) +#define CD1400_COR2 0x09 /* channel option 2 */ +#define CD1400_COR2_IXANY (1<<7) /* implied XON mode */ +#define CD1400_COR2_IXOFF (1<<6) /* in-band tx flow control */ +#define CD1400_COR2_ETC (1<<5) /* embedded tx command */ +#define CD1400_COR2_LLM (1<<4) /* local loopback mode */ +#define CD1400_COR2_RLM (1<<3) /* remote loopback mode */ +#define CD1400_COR2_RTSAO (1<<2) /* RTS auto output */ +#define CD1400_COR2_CCTS_OFLOW (1<<1) /* CTS auto enable */ +#define CD1400_COR2_CDSR_OFLOW (1<<0) /* DSR auto enable */ +#define CD1400_COR3 0x0A /* channel option 3 */ +#define CD1400_COR3_SCDRNG (1<<7) /* special char detect range */ +#define CD1400_COR3_SCD34 (1<<6) /* special char detect 3-4 */ +#define CD1400_COR3_FTC (1<<5) /* flow control transparency */ +#define CD1400_COR3_SCD12 (1<<4) /* special char detect 1-2 */ +#define CD1400_COR3_RXTH (15<<0) /* rx fifo threshold */ +#define CD1400_COR4 0x1E /* channel option 4 */ +#define CD1400_COR4_IGNCR (1<<7) +#define CD1400_COR4_ICRNL (1<<6) +#define CD1400_COR4_INLCR (1<<5) +#define CD1400_COR4_IGNBRK (1<<4) +#define CD1400_COR4_NOBRKINT (1<<3) +#define CD1400_COR4_PFO_ESC (4<<0) /* parity/framing/overrun... */ +#define CD1400_COR4_PFO_NUL (3<<0) +#define CD1400_COR4_PFO_DISCARD (2<<0) +#define CD1400_COR4_PFO_GOOD (1<<0) +#define CD1400_COR4_PFO_EXCEPTION (0<<0) +#define CD1400_COR5 0x1F /* channel option 5 */ +#define CD1400_COR5_ISTRIP (1<<7) +#define CD1400_COR5_LNEXT (1<<6) +#define CD1400_COR5_CMOE (1<<5) /* char matching on error */ +#define CD1400_COR5_EBD (1<<2) /* end of break detected */ +#define CD1400_COR5_ONLCR (1<<1) +#define CD1400_COR5_OCRNL (1<<0) +#define CD1400_CCSR 0x0B /* channel control status */ +#define CD1400_RDCR 0x0E /* received data count */ +#define CD1400_SCHR1 0x1A /* special character 1 */ +#define CD1400_SCHR2 0x1B /* special character 2 */ +#define CD1400_SCHR3 0x1C /* special character 3 */ +#define CD1400_SCHR4 0x1D /* special character 4 */ +#define CD1400_SCRL 0x22 /* special character range, low */ +#define CD1400_SCRH 0x23 /* special character range, high */ +#define CD1400_LNC 0x24 /* lnext character */ +#define CD1400_MCOR1 0x15 /* modem change option 1 */ +#define CD1400_MCOR1_DSRzd (1<<7) /* DSR one-to-zero delta */ +#define CD1400_MCOR1_CTSzd (1<<6) +#define CD1400_MCOR1_RIzd (1<<5) +#define CD1400_MCOR1_CDzd (1<<4) +#define CD1400_MCOR1_DTRth (15<<0) /* dtrflow threshold */ +#define CD1400_MCOR2 0x16 /* modem change option 2 */ +#define CD1400_MCOR2_DSRod (1<<7) /* DSR zero-to-one delta */ +#define CD1400_MCOR2_CTSod (1<<6) +#define CD1400_MCOR2_RIod (1<<5) +#define CD1400_MCOR2_CDod (1<<4) +#define CD1400_RTPR 0x21 /* receive timeout period */ +#define CD1400_MSVR1 0x6C /* modem signal value 1 */ +#define CD1400_MSVR1_RTS (1<<0) /* RTS line (r/w) */ +#define CD1400_MSVR2 0x6D /* modem signal value 2 */ +#define CD1400_MSVR2_DSR (1<<7) /* !DSR line (r) */ +#define CD1400_MSVR2_CTS (1<<6) /* !CTS line (r) */ +#define CD1400_MSVR2_RI (1<<5) /* !RI line (r) */ +#define CD1400_MSVR2_CD (1<<4) /* !CD line (r) */ +#define CD1400_MSVR2_DTR (1<<1) /* DTR line (r/w) */ +#define CD1400_PSVR 0x6F /* printer signal value */ +#define CD1400_RBPR 0x78 /* receive baud rate period */ +#define CD1400_RCOR 0x7C /* receive clock option */ +#define CD1400_TBPR 0x72 /* transmit baud rate period */ +#define CD1400_TCOR 0x76 /* transmit clock option */ diff --git a/sys/dev/isa/cy.c b/sys/dev/isa/cy.c index 03e1cf74756..61d80172dcd 100644 --- a/sys/dev/isa/cy.c +++ b/sys/dev/isa/cy.c @@ -1,1650 +1,1675 @@ -/* $NetBSD: cy.c,v 1.12.6.1 1996/06/02 09:08:03 mrg Exp $ */ - -/* XXX THIS DRIVER IS BROKEN. IT WILL NOT EVEN COMPILE. */ +/* $OpenBSD: cy.c,v 1.3 1996/06/20 11:39:10 deraadt Exp $ */ /* - * cyclades cyclom-y serial driver - * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993 + * cy.c * - * Copyright (c) 1993 Andrew Herbert. - * All rights reserved. + * Driver for Cyclades Cyclom-8/16/32 multiport serial cards + * (currently not tested with Cyclom-32 cards) * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name Andrew Herbert may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * Timo Rossi, 1996 * - * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Device minor number encoding: + * Supports both ISA and PCI Cyclom cards * - * c c x x u u u u - bits in the minor device number + * Uses CD1400 automatic CTS flow control, and + * if CY_HW_RTS is defined, uses CD1400 automatic input flow control. + * This requires a special cable that exchanges the RTS and DTR lines. * - * bits meaning - * ---- ------- - * uuuu physical serial line (i.e. unit) to use - * 0-7 on a cyclom-8Y, 0-15 on a cyclom-16Y - * xx unused - * cc carrier control mode - * 00 complete hardware carrier control of the tty. - * DCD must be high for the open(2) to complete. - * 01 dialin pseudo-device (not yet implemented) - * 10 carrier ignored until a high->low transition - * 11 carrier completed ignored - */ - -/* - * Known deficiencies: + * Lots of debug output can be enabled by defining CY_DEBUG + * Some debugging counters (number of receive/transmit interrupts etc.) + * can be enabled by defining CY_DEBUG1 + * + * This version uses the bus_mem/io_??() stuff + * + * NOT TESTED !!! * - * * no BREAK handling - breaks are ignored, and can't be sent either - * * no support for bad-char reporting, except via PARMRK - * * no support for dialin + dialout devices */ +#define CY_DEBUG +#define CY_DEBUG1 + +/* NCY is the number of Cyclom cards in the machine */ #include "cy.h" #if NCY > 0 +#include "isa.h" +#include "pci.h" + +#include <sys/types.h> #include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> #include <sys/ioctl.h> +#include <sys/syslog.h> +#include <sys/fcntl.h> #include <sys/tty.h> #include <sys/proc.h> -#include <sys/user.h> #include <sys/conf.h> -#include <sys/file.h> -#include <sys/uio.h> -#include <sys/kernel.h> -#include <sys/syslog.h> - -#include <machine/cpu.h> -#include <machine/pio.h> -#include <machine/cpufunc.h> - -#include <i386/isa/isa_device.h> /* XXX BROKEN */ +#include <sys/user.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/systm.h> +#include <machine/bus.h> +#if NISA > 0 +#include <dev/isa/isavar.h> +#include <dev/isa/isareg.h> +#endif /* NISA > 0 */ +#if NPCI > 0 +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> +#endif /* NPCI > 0 */ + +#include <dev/isa/cyreg.h> #include <dev/ic/cd1400reg.h> -#define RxFifoThreshold 3 /* 3 characters (out of 12) in the receive - * FIFO before an interrupt is generated - */ -#define FastRawInput /* bypass the regular char-by-char canonical input - * processing whenever possible - */ -#define PollMode /* use polling-based irq service routine, not the - * hardware svcack lines. Must be defined for - * cyclom-16y boards. - * - * XXX cyclom-8y doesn't work without this defined - * either (!) - */ -#undef LogOverruns /* log receive fifo overruns */ -#undef TxBuffer /* buffer driver output, to be slightly more - * efficient - * - * XXX presently buggy - */ -#undef Smarts /* enable slightly more CD1400 intelligence. Mainly - * the output CR/LF processing, plus we can avoid a - * few checks usually done in ttyinput(). - * - * XXX not yet implemented, and not particularly - * worthwhile either. - */ -#define CyDebug /* include debugging code (minimal effect on - * performance) - */ - -#define CY_RX_BUFS 2 /* two receive buffers per port */ -#define CY_RX_BUF_SIZE 256 /* bytes per receive buffer */ -#define CY_TX_BUF_SIZE 512 /* bytes per transmit buffer */ - -/* #define CD1400s_PER_CYCLOM 1 */ /* cyclom-4y */ -#define CD1400s_PER_CYCLOM 2 /* cyclom-8y */ -/* #define CD1400s_PER_CYCLOM 4 */ /* cyclom-16y */ - -#if CD1400s_PER_CYCLOM < 4 -#define CD1400_MEMSIZE 0x400 /* 4*256 bytes per chip: cyclom-[48]y */ -#else -#define CD1400_MEMSIZE 0x100 /* 256 bytes per chip: cyclom-16y */ - /* XXX or is it 0x400 like the rest? */ -#endif - -#define PORTS_PER_CYCLOM (CD1400_NO_OF_CHANNELS * CD1400s_PER_CYCLOM) -#define CYCLOM_RESET_16 0x1400 /* cyclom-16y reset */ -#define CYCLOM_CLEAR_INTR 0x1800 /* intr ack address */ -#define CYCLOM_CLOCK 25000000 /* baud rate clock */ - -#define CY_UNITMASK 0x0f -#define CY_CARRIERMASK 0xC0 -#define CY_CARRIERSHIFT 6 - -#define UNIT(x) (minor(x) & CY_UNITMASK) -#define CARRIER_MODE(x) ((minor(x) & CY_CARRIERMASK) >> CY_CARRIERSHIFT) - -typedef u_char * volatile cy_addr; - -int cyprobe(struct isa_device *dev); -int cyattach(struct isa_device *isdp); -void cystart(struct tty *tp); -int cyparam(struct tty *tp, struct termios *t); -int cyspeed(int speed, int *prescaler_io); -static void cy_channel_init(dev_t dev, int reset); -static void cd1400_channel_cmd(cy_addr base, u_char cmd); +/* Macros to clear/set/test flags. */ +#define SET(t, f) (t) |= (f) +#define CLR(t, f) (t) &= ~(f) +#define ISSET(t, f) ((t) & (f)) -void delay(int delay); +/* + * Maximum number of ports per card + */ +#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s) -extern unsigned int delaycount; /* calibrated 1 ms cpu-spin delay */ +#define RX_FIFO_THRESHOLD 6 -struct isa_driver cydriver = { - cyprobe, cyattach, "cy" -}; +/* Automatic RTS (or actually DTR, the RTS and DTR lines need to be exchanged) + * handshake threshold used if CY_HW_RTS is defined + */ +#define RX_DTR_THRESHOLD 9 -/* low-level ping-pong buffer structure */ +/* + * Port number on card encoded in low 5 bits + * card number in next 2 bits (only space for 4 cards) + * high bit reserved for dialout flag + */ +#define CY_PORT(x) (minor(x) & 0xf) +#define CY_CARD(x) ((minor(x) >> 5) & 3) +#define CY_DIALOUT(x) ((minor(x) & 0x80) != 0) +#define CY_DIALIN(x) (!CY_DIALOUT(x)) -struct cy_buf { - u_char *next_char; /* location of next char to write */ - u_int free; /* free chars remaining in buffer */ - struct cy_buf *next_buf; /* circular, you know */ - u_char buf[CY_RX_BUF_SIZE]; /* start of the buffer */ -}; +/* + * read/write cd1400 registers (when cy_port-structure is available) + */ +#define cd_read_reg(cy,reg) bus_mem_read_1(cy->cy_bc, cy->cy_memh, \ + cy->cy_chip_offs+(((reg<<1))<<cy->cy_bustype)) -/* low-level ring buffer */ +#define cd_write_reg(cy,reg,val) bus_mem_write_1(cy->cy_bc, cy->cy_memh, \ + cy->cy_chip_offs+(((reg<<1))<<cy->cy_bustype), \ + (val)) -#ifdef TxBuffer -struct cy_ring { - u_char buf[CY_TX_BUF_SIZE]; - u_char *head; - u_char *tail; /* next pos. to insert char */ - u_char *endish; /* physical end of buf */ - u_int used; /* no. of chars in queue */ -}; -#endif +/* + * read/write cd1400 registers (when sc_softc-structure is available) + */ +#define cd_read_reg_sc(sc,chip,reg) bus_mem_read_1(sc->sc_bc, \ + sc->sc_memh, \ + sc->sc_cd1400_offs[chip]+\ + (((reg<<1))<<sc->sc_bustype)) +#define cd_write_reg_sc(sc,chip,reg,val) bus_mem_write_1(sc->sc_bc, \ + sc->sc_memh, \ + sc->sc_cd1400_offs[chip]+\ + (((reg<<1))<<sc->sc_bustype), \ + (val)) /* - * define a structure to keep track of each serial line + * ibuf is a simple ring buffer. It is always used two + * bytes at a time (status and data) */ +#define IBUF_SIZE (2*512) + +/* software state for one port */ +struct cy_port { + int cy_port_num; + bus_chipset_tag_t cy_bc; + bus_mem_handle_t cy_memh; + int cy_chip_offs; + int cy_bustype; + struct tty *cy_tty; + int cy_openflags; + int cy_fifo_overruns; + int cy_ibuf_overruns; + u_char cy_channel_control; /* last CCR channel control command bits */ + u_char cy_carrier_stat; /* copied from MSVR2 */ + u_char cy_flags; + u_char *cy_ibuf, *cy_ibuf_end; + u_char *cy_ibuf_rd_ptr, *cy_ibuf_wr_ptr; +#ifdef CY_DEBUG1 + int cy_rx_int_count; + int cy_tx_int_count; + int cy_modem_int_count; + int cy_start_count; +#endif /* CY_DEBUG1 */ +}; -struct cy { - cy_addr base_addr; /* base address of this port's cd1400 */ - struct tty *tty; - u_int dtrwait; /* time (in ticks) to hold dtr low after close */ - u_int recv_exception; /* exception chars received */ - u_int recv_normal; /* normal chars received */ - u_int xmit; /* chars transmitted */ - u_int mdm; /* modem signal changes */ -#ifdef CyDebug - u_int start_count; /* no. of calls to cystart() */ - u_int start_real; /* no. of calls that did something */ -#endif - u_char carrier_mode; /* hardware carrier handling mode */ - /* - * 0 = always use - * 1 = always use (dialin port) - * 2 = ignore during open, then use it - * 3 = ignore completely - */ - u_char carrier_delta; /* true if carrier has changed state */ - u_char fifo_overrun; /* true if cd1400 receive fifo has... */ - u_char rx_buf_overrun; /* true if low-level buf overflow */ - u_char intr_enable; /* CD1400 SRER shadow */ - u_char modem_sig; /* CD1400 modem signal shadow */ - u_char channel_control;/* CD1400 CCR control command shadow */ - u_char cor[3]; /* CD1400 COR1-3 shadows */ -#ifdef Smarts - u_char spec_char[4]; /* CD1400 SCHR1-4 shadows */ -#endif - struct cy_buf *rx_buf; /* current receive buffer */ - struct cy_buf rx_buf_pool[CY_RX_BUFS];/* receive ping-pong buffers */ -#ifdef TxBuffer - struct cy_ring tx_buf; /* transmit buffer */ +#define CYF_CARRIER_CHANGED 0x01 +#define CYF_START_BREAK 0x02 +#define CYF_END_BREAK 0x04 +#define CYF_STOP 0x08 +#define CYF_SEND_NUL 0x10 +#define CYF_START 0x20 + +/* software state for one card */ +struct cy_softc { + struct device sc_dev; + void *sc_ih; + bus_chipset_tag_t sc_bc; + bus_mem_handle_t sc_memh; + int sc_bustype; + int sc_nports; /* number of ports on this card */ + int sc_cd1400_offs[CY_MAX_CD1400s]; + struct cy_port sc_ports[CY_MAX_PORTS]; +#ifdef CY_DEBUG1 + int sc_poll_count1; + int sc_poll_count2; #endif }; -int cydefaultrate = TTYDEF_SPEED; -cy_addr cyclom_base; /* base address of the card */ -static struct cy *info[NCY*PORTS_PER_CYCLOM]; -struct tty *cy_tty[NCY*PORTS_PER_CYCLOM]; -static volatile u_char timeout_scheduled = 0; /* true if a timeout has been scheduled */ +int cy_probe_isa __P((struct device *, void *, void *)); +int cy_probe_pci __P((struct device *, void *, void *)); +int cy_probe_common __P((int card, bus_chipset_tag_t, + bus_mem_handle_t, int bustype)); + +void cyattach __P((struct device *, struct device *, void *)); + +static int cyintr __P((void *)); +static int cyparam __P((struct tty *, struct termios *)); +static void cystart __P((struct tty *)); +static void cy_poll __P((void *)); +static int cy_modem_control __P((struct cy_port *, int, int)); +static void cy_enable_transmitter __P((struct cy_port *)); +static void cd1400_channel_cmd __P((struct cy_port *, int)); +static int cy_speed __P((speed_t, int *, int *)); + +#if NISA > 0 +struct cfattach cy_isa_ca = { + sizeof(struct cy_softc), cy_probe_isa, cyattach +}; +#endif -#ifdef CyDebug -u_int cy_svrr_probes = 0; /* debugging */ -u_int cy_timeouts = 0; -u_int cy_timeout_req = 0; +#if NPCI > 0 +struct cfattach cy_pci_ca = { + sizeof(struct cy_softc), cy_probe_pci, cyattach +}; #endif -/**********************************************************************/ +struct cfdriver cy_cd = { + NULL, "cy", DV_TTY +}; + +static int cy_nr_cd1400s[NCY]; +static int cy_bus_types[NCY]; +static bus_mem_handle_t cy_card_memh[NCY]; +static int cy_open = 0; +static int cy_events = 0; +#if NISA > 0 +/* + * ISA probe + */ int -cyprobe(struct isa_device *dev) +cy_probe_isa(parent, match, aux) + struct device *parent; + void *match, *aux; { - int i, j; - u_char version = 0; /* firmware version */ - - /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */ - i = *(cy_addr)(dev->id_maddr + CYCLOM_RESET_16); - - delay(500); /* wait for the board to get its act together (500 us) */ - - for (i = 0; i < CD1400s_PER_CYCLOM; i++) { - cy_addr base = dev->id_maddr + i * CD1400_MEMSIZE; - - /* wait for chip to become ready for new command */ - for (j = 0; j < 100; j += 50) { - delay(50); /* wait 50 us */ - - if (!*(base + CD1400_CCR)) - break; - } + int card = ((struct device *)match)->dv_unit; + struct isa_attach_args *ia = aux; + bus_chipset_tag_t bc; + bus_mem_handle_t memh; - /* clear the GFRCR register */ - *(base + CD1400_GFRCR) = 0; - - /* issue a reset command */ - *(base + CD1400_CCR) = CD1400_CMD_RESET; - - /* wait for the CD1400 to initialise itself */ - for (j = 0; j < 1000; j += 50) { - delay(50); /* wait 50 us */ + if(ia->ia_irq == IRQUNK) { + printf("cy%d error: interrupt not defined\n", card); + return 0; + } - /* retrieve firmware version */ - version = *(base + CD1400_GFRCR); - if (version) - break; - } + bc = ia->ia_bc; + if(bus_mem_map(bc, ia->ia_maddr, 0x2000, 0, &memh) != 0) + return 0; - /* anything in the 40-4f range is fine */ - if ((version & 0xf0) != 0x40) { - return 0; - } - } + if(cy_probe_common(card, bc, memh, CY_BUSTYPE_ISA) == 0) { + bus_mem_unmap(bc, memh, 0x2000); + return 0; + } - return 1; /* found */ + ia->ia_iosize = 0; + ia->ia_msize = 0x2000; + return 1; } +#endif /* NISA > 0 */ - +#if NPCI > 0 +/* + * PCI probe + */ int -cyattach(struct isa_device *isdp) +cy_probe_pci(parent, match, aux) + struct device *parent; + void *match, *aux; { -/* u_char unit = UNIT(isdp->id_unit); */ - int i, j, k; + vm_offset_t v_addr, p_addr; + int card = ((struct device *)match)->dv_unit; + struct pci_attach_args *pa = aux; + bus_chipset_tag_t bc; + bus_mem_handle_t memh; + bus_mem_addr_t memaddr; + bus_mem_size_t memsize; + bus_io_handle_t ioh; + bus_io_addr_t iobase; + bus_io_size_t iosize; + int cacheable; + + if(!(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_CYCLADES && + (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CYCLADES_CYCLOMY_1 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CYCLADES_CYCLOMY_2))) + return 0; - /* global variable used various routines */ - cyclom_base = (cy_addr)isdp->id_maddr; +#ifdef CY_DEBUG + printf("cy: Found Cyclades PCI device, id = 0x%x\n", pa->pa_id); +#endif - for (i = 0, k = 0; i < CD1400s_PER_CYCLOM; i++) { - cy_addr base = cyclom_base + i * CD1400_MEMSIZE; + bc = pa->pa_bc; - /* setup a 1ms clock tick */ - *(base + CD1400_PPR) = CD1400_CLOCK_25_1MS; + if(pci_mem_find(pa->pa_pc, pa->pa_tag, 0x18, + &memaddr, &memsize, &cacheable) != 0) { + printf("cy%d: can't find PCI card memory", card); + return 0; + } - for (j = 0; j < CD1400_NO_OF_CHANNELS; j++, k++) { - struct cy *ip; + /* map the memory (non-cacheable) */ + if(bus_mem_map(bc, memaddr, memsize, 0, &memh) != 0) { + printf("cy%d: couldn't map PCI memory region\n", card); + return 0; + } - /* - * grab some space. it'd be more polite to do this in cyopen(), - * but hey. - */ - info[k] = ip = malloc(sizeof(struct cy), M_DEVBUF, M_WAITOK); + /* the PCI Cyclom IO space is only used for enabling interrupts */ + if(pci_io_find(pa->pa_pc, pa->pa_tag, 0x14, &iobase, &iosize) != 0) { + bus_mem_unmap(bc, memh, memsize); + printf("cy%d: couldn't find PCI io region\n", card); + return 0; + } - /* clear all sorts of junk */ - bzero(ip, sizeof(struct cy)); + if(bus_io_map(bc, iobase, iosize, &ioh) != 0) { + bus_mem_unmap(bc, memh, memsize); + printf("cy%d: couldn't map PCI io region\n", card); + return 0; + } - ip->base_addr = base; +#ifdef CY_DEBUG + printf("cy%d: pci mapped mem 0x%lx (size %d), io 0x%x (size %d)\n", + card, memaddr, memsize, iobase, iosize); +#endif - /* initialise the channel, without resetting it first */ - cy_channel_init(k, 0); - } - } + if(cy_probe_common(card, bc, memh, CY_BUSTYPE_PCI) == 0) { + bus_mem_unmap(bc, memh, memsize); + bus_io_unmap(bc, ioh, iosize); + printf("cy%d: PCI Cyclom card with no CD1400s!?\n", card); + return 0; + } - /* clear interrupts */ - *(cyclom_base + CYCLOM_CLEAR_INTR) = (u_char)0; + /* Enable PCI card interrupts */ + bus_io_write_2(bc, ioh, CY_PCI_INTENA, + bus_io_read_2(bc, ioh, CY_PCI_INTENA) | 0x900); - return 1; + return 1; } +#endif /* NPCI > 0 */ - +/* + * Common probe routine + */ int -cyopen(dev_t dev, int flag, int mode, struct proc *p) +cy_probe_common(card, bc, memh, bustype) + int card, bustype; + bus_chipset_tag_t bc; + bus_mem_handle_t memh; { - u_int unit = UNIT(dev); - struct cy *infop; - cy_addr base; - struct tty *tp; - int error = 0; - u_char carrier; - - if (unit >= PORTS_PER_CYCLOM) - return (ENXIO); - - infop = info[unit]; - base = infop->base_addr; - if (!cy_tty[unit]) { - infop->tty = cy_tty[unit] = ttymalloc(); - tty_attach(infop->tty); - } - tp = infop->tty; - - tp->t_oproc = cystart; - tp->t_param = cyparam; - tp->t_dev = dev; - if (!(tp->t_state & TS_ISOPEN)) { - tp->t_state |= TS_WOPEN; - ttychars(tp); - if (tp->t_ispeed == 0) { - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = TTYDEF_CFLAG; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_ispeed = tp->t_ospeed = cydefaultrate; - } + int cy_chip, chip_offs; + u_char firmware_ver; - (void) spltty(); - cy_channel_init(unit, 1); /* reset the hardware */ + /* Cyclom card hardware reset */ + bus_mem_write_1(bc, memh, CY16_RESET<<bustype, 0); + DELAY(500); /* wait for reset to complete */ + bus_mem_write_1(bc, memh, CY_CLEAR_INTR<<bustype, 0); - /* - * raise dtr and generally set things up correctly. this - * has the side-effect of selecting the appropriate cd1400 - * channel, to help us with subsequent channel control stuff - */ - cyparam(tp, &tp->t_termios); - - /* check carrier, and set t_state's TS_CARR_ON flag accordingly */ - infop->modem_sig = *(base + CD1400_MSVR); - carrier = infop->modem_sig & CD1400_MSVR_CD; - - if (carrier || (infop->carrier_mode >= 2)) - tp->t_state |= TS_CARR_ON; - else - tp->t_state &=~ TS_CARR_ON; - - /* - * enable modem & rx interrupts - relies on cyparam() - * having selected the appropriate cd1400 channel - */ - infop->intr_enable = (1 << 7) | (1 << 4); - *(base + CD1400_SRER) = infop->intr_enable; - - ttsetwater(tp); - } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) - return (EBUSY); +#ifdef CY_DEBUG + printf("cy: card reset done\n"); +#endif - if (!(flag & O_NONBLOCK)) - while (!(tp->t_cflag & CLOCAL) && - !(tp->t_state & TS_CARR_ON) && !error) - error = ttysleep(tp, (caddr_t)&tp->t_rawq, - TTIPRI|PCATCH, ttopen, 0); - (void) spl0(); + cy_nr_cd1400s[card] = 0; - if (!error) - error = (*linesw[(u_char)tp->t_line].l_open)(dev, tp); - return (error); -} /* end of cyopen() */ + for(cy_chip = 0, chip_offs = 0; + cy_chip < CY_MAX_CD1400s; + cy_chip++, chip_offs += (CY_CD1400_MEMSPACING<<bustype)) { + int i; + /* the last 4 cd1400s are 'interleaved' + with the first 4 on 32-port boards */ + if(cy_chip == 4) + chip_offs -= (CY32_ADDR_FIX<<bustype); -void -cyclose_wakeup(caddr_t arg) -{ - wakeup(arg); -} /* end of cyclose_wakeup() */ +#ifdef CY_DEBUG + printf("cy%d probe chip %d offset 0x%lx ... ", + card, cy_chip, chip_offs); +#endif + /* wait until the chip is ready for command */ + DELAY(1000); + if(bus_mem_read_1(bc, memh, chip_offs + + ((CD1400_CCR<<1) << bustype)) != 0) { +#ifdef CY_DEBUG + printf("not ready for command\n"); +#endif + break; + } -int -cyclose(dev_t dev, int flag, int mode, struct proc *p) -{ - u_int unit = UNIT(dev); - struct cy *infop = info[unit]; - struct tty *tp = infop->tty; - cy_addr base = infop->base_addr; - int s; + /* clear the firmware version reg. */ + bus_mem_write_1(bc, memh, chip_offs + + ((CD1400_GFRCR<<1) << bustype), 0); + + /* + * On Cyclom-16 references to non-existent chip 4 + * actually access chip 0 (address line 9 not decoded). + * Here we check if the clearing of chip 4 GFRCR actually + * cleared chip 0 GFRCR. In that case we have a 16 port card. + */ + if(cy_chip == 4 && + bus_mem_read_1(bc, memh, chip_offs + + ((CD1400_GFRCR<<1) << bustype)) ==0) + break; + + /* reset the chip */ + bus_mem_write_1(bc, memh, chip_offs + + ((CD1400_CCR<<1) << bustype), + CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET); + + /* wait for the chip to initialize itself */ + for(i = 0; i < 200; i++) { + DELAY(50); + firmware_ver = + bus_mem_read_1(bc, memh, chip_offs + + ((CD1400_GFRCR<<1) << bustype)); + if((firmware_ver & 0xf0) == 0x40) /* found a CD1400 */ + break; + } +#ifdef CY_DEBUG + printf("firmware version 0x%x\n", firmware_ver); +#endif - (*linesw[(u_char)tp->t_line].l_close)(tp, flag); + if((firmware_ver & 0xf0) != 0x40) + break; - s = spltty(); - /* select the appropriate channel on the CD1400 */ - *(base + CD1400_CAR) = (u_char)(unit & 0x03); - - /* disable this channel and lower DTR */ - infop->intr_enable = 0; - *(base + CD1400_SRER) = (u_char)0; /* no intrs */ - *(base + CD1400_DTR) = (u_char)CD1400_DTR_CLEAR; /* no DTR */ - infop->modem_sig &= ~CD1400_MSVR_DTR; - - /* disable receiver (leave transmitter enabled) */ - infop->channel_control = (1 << 4) | (1 << 3) | 1; - cd1400_channel_cmd(base, infop->channel_control); - splx(s); + /* firmware version OK, CD1400 found */ + cy_nr_cd1400s[card]++; + } - ttyclose(tp); -#ifdef broken /* session holds a ref to the tty; can't deallocate */ - ttyfree(tp); - infop->tty = cy_tty[unit] = (struct tty *)NULL; + if(cy_nr_cd1400s[card] == 0) { +#ifdef CY_DEBUG + printf("no CD1400s found\n"); #endif + return 0; + } - if (infop->dtrwait) { - int error; - - timeout(cyclose_wakeup, (caddr_t)&infop->dtrwait, infop->dtrwait); - do { - error = tsleep((caddr_t)&infop->dtrwait, - TTIPRI|PCATCH, "cyclose", 0); - } while (error == ERESTART); - } +#ifdef CY_DEBUG + printf("found %d CD1400s\n", cy_nr_cd1400s[card]); +#endif - return 0; -} /* end of cyclose() */ + cy_card_memh[card] = memh; + cy_bus_types[card] = bustype; + return 1; +} -int -cyread(dev_t dev, struct uio *uio, int flag) +/* + * Attach (ISA/PCI) + */ +void +cyattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - u_int unit = UNIT(dev); - struct tty *tp = info[unit]->tty; + struct cy_softc *sc = (void *)self; + int card, port, cy_chip, num_chips, cdu, chip_offs; + + card = sc->sc_dev.dv_unit; + num_chips = cy_nr_cd1400s[card]; + if(num_chips == 0) + return; + + sc->sc_bustype = cy_bus_types[card]; + sc->sc_memh = cy_card_memh[card]; + switch(sc->sc_bustype) { +#if NISA > 0 + case CY_BUSTYPE_ISA: + sc->sc_bc = ((struct isa_attach_args *)(aux))->ia_bc; + break; +#endif +#if NPCI > 0 + case CY_BUSTYPE_PCI: + sc->sc_bc = ((struct pci_attach_args *)aux)->pa_bc; + break; +#endif + } - return (*linesw[(u_char)tp->t_line].l_read)(tp, uio, flag); -} /* end of cyread() */ + bzero(sc->sc_ports, sizeof(sc->sc_ports)); + sc->sc_nports = num_chips * CD1400_NO_OF_CHANNELS; + port = 0; + for(cy_chip = 0, chip_offs = 0; + cy_chip < num_chips; cy_chip++, + chip_offs += (CY_CD1400_MEMSPACING<<sc->sc_bustype)) { -int -cywrite(dev_t dev, struct uio *uio, int flag) -{ - u_int unit = UNIT(dev); - struct tty *tp = info[unit]->tty; + if(cy_chip == 4) + chip_offs -= (CY32_ADDR_FIX<<sc->sc_bustype); -#ifdef Smarts - /* XXX duplicate ttwrite(), but without so much output processing on - * CR & LF chars. Hardly worth the effort, given that high-throughput - * sessions are raw anyhow. - */ -#else - return (*linesw[(u_char)tp->t_line].l_write)(tp, uio, flag); +#ifdef CY_DEBUG + printf("attach CD1400 #%d offset 0x%x\n", cy_chip, chip_offs); #endif -} /* end of cywrite() */ + sc->sc_cd1400_offs[cy_chip] = chip_offs; + + /* configure port 0 as serial port (should already be after reset) */ + cd_write_reg_sc(sc, cy_chip, CD1400_GCR, 0); + + /* set up a receive timeout period (1ms) */ + cd_write_reg_sc(sc, cy_chip, CD1400_PPR, + (CY_CLOCK / CD1400_PPR_PRESCALER / 1000) + 1); + + for(cdu = 0; cdu < CD1400_NO_OF_CHANNELS; cdu++) { + sc->sc_ports[port].cy_port_num = port; + sc->sc_ports[port].cy_bc = sc->sc_bc; + sc->sc_ports[port].cy_memh = sc->sc_memh; + sc->sc_ports[port].cy_chip_offs = chip_offs; + sc->sc_ports[port].cy_bustype = sc->sc_bustype; + + /* should we initialize anything else here? */ + port++; + } /* for(each port on one CD1400...) */ + + } /* for(each CD1400 on a card... ) */ + + printf(" (%d ports)\n", port); + + /* ensure an edge for the next interrupt */ + bus_mem_write_1(sc->sc_bc, sc->sc_memh, + CY_CLEAR_INTR<<sc->sc_bustype, 0); + + switch(sc->sc_bustype) { +#if NISA > 0 + case CY_BUSTYPE_ISA: + { + struct isa_attach_args *ia = aux; + + sc->sc_ih = + isa_intr_establish(ia->ia_ic, ia->ia_irq, + IST_EDGE, IPL_TTY, cyintr, sc, sc->sc_dev.dv_xname); + } + break; +#endif /* NISA > 0 */ +#if NPCI > 0 + case CY_BUSTYPE_PCI: + { + pci_intr_handle_t intrhandle; + struct pci_attach_args *pa = aux; + + if(pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &intrhandle) != 0) + panic("cy: couldn't map PCI interrupt"); + + sc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle, + IPL_TTY, cyintr, sc, sc->sc_dev.dv_xname); + } + break; + } +#endif /* NPCI > 0 */ + + if(sc->sc_ih == NULL) + panic("cy: couldn't establish interrupt"); +} +#undef CY_DEBUG /*!!*/ -#ifdef Smarts -/* standard line discipline input routine */ +/* + * open routine. returns zero if successfull, else error code + */ int -cyinput(int c, struct tty *tp) +cyopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; { - /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK - * bits, as they are done by the CD1400. Hardly worth the effort, - * given that high-throughput sessions are raw anyhow. - */ -} /* end of cyinput() */ -#endif /* Smarts */ - + int card = CY_CARD(dev); + int port = CY_PORT(dev); + struct cy_softc *sc; + struct cy_port *cy; + struct tty *tp; + int s, error; + +#ifdef CY_DEBUG + printf("cy%d open port %d flag 0x%x mode 0x%x\n", + card, port, flag, mode); +#endif -inline static void -service_upper_rx(int unit) -{ - struct cy *ip = info[unit]; - struct tty *tp = ip->tty; - struct cy_buf *buf; - int i; - u_char *ch; + if(card >= cy_cd.cd_ndevs || + (sc = cy_cd.cd_devs[card]) == NULL) + return ENXIO; - buf = ip->rx_buf; + cy = &sc->sc_ports[port]; - /* give service_rx() a new one */ - disable_intr(); /* faster than spltty() */ - ip->rx_buf = buf->next_buf; - enable_intr(); + s = spltty(); + if(cy->cy_tty == NULL) { + if((cy->cy_tty = ttymalloc()) == NULL) { + splx(s); + printf("cy%d port %d open: can't allocate tty\n", card, port); + return ENOMEM; + } + } + splx(s); + + tty_attach(tp); + tp = cy->cy_tty; + tp->t_oproc = cystart; + tp->t_param = cyparam; + tp->t_dev = dev; + + if(!ISSET(tp->t_state, TS_ISOPEN)) { + SET(tp->t_state, TS_WOPEN); + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + if(ISSET(cy->cy_openflags, TIOCFLAG_CLOCAL)) + SET(tp->t_cflag, CLOCAL); + if(ISSET(cy->cy_openflags, TIOCFLAG_CRTSCTS)) + SET(tp->t_cflag, CRTSCTS); + if(ISSET(cy->cy_openflags, TIOCFLAG_MDMBUF)) + SET(tp->t_cflag, MDMBUF); + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; - if (tp->t_state & TS_ISOPEN) { - ch = buf->buf; - i = buf->next_char - buf->buf; - -#ifdef FastRawInput - /* try to avoid calling the line discipline stuff if we can */ - if ((tp->t_line == 0) && - !(tp->t_iflag & (ICRNL | IMAXBEL | INLCR)) && - !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | - ISIG | PENDIN)) && - !(tp->t_state & (TS_CNTTB | TS_LNCH))) { - - i = b_to_q(ch, i, &tp->t_rawq); - if (i) { - /* - * we have no RTS flow control support on cy-8 - * boards, so this is really just tough luck - */ - - log(LOG_WARNING, "cy%d: tty input queue overflow\n", - unit); - } + s = spltty(); - ttwakeup(tp); /* notify any readers */ - } - else -#endif /* FastRawInput */ - { - while (i--) - (*linesw[(u_char)tp->t_line].l_rint)((int)*ch++, tp); + /* + * Allocate input ring buffer if we don't already have one + */ + if(cy->cy_ibuf == NULL) { + cy->cy_ibuf = malloc(IBUF_SIZE, M_DEVBUF, M_NOWAIT); + if(cy->cy_ibuf == NULL) { + printf("cy%d: (port %d) can't allocate input buffer\n", + card, port); + splx(s); + return ENOMEM; } + cy->cy_ibuf_end = cy->cy_ibuf + IBUF_SIZE; } - /* clear the buffer we've just processed */ - buf->next_char = buf->buf; - buf->free = CY_RX_BUF_SIZE; -} /* end of service_upper_rx() */ - - -#ifdef TxBuffer -static void -service_upper_tx(int unit) -{ - struct cy *ip = info[unit]; - struct tty *tp = ip->tty; + /* mark the ring buffer as empty */ + cy->cy_ibuf_rd_ptr = cy->cy_ibuf_wr_ptr = cy->cy_ibuf; - tp->t_state &=~ (TS_BUSY|TS_FLUSH); + /* select CD1400 channel */ + cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN); + /* reset the channel */ + cd1400_channel_cmd(cy, CD1400_CCR_CMDRESET); + /* encode unit (port) number in LIVR */ + /* there is just enough space for 5 bits (32 ports) */ + cd_write_reg(cy, CD1400_LIVR, port << 3); - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state&TS_ASLEEP) { - tp->t_state &= ~TS_ASLEEP; - wakeup((caddr_t)&tp->t_outq); - } - selwakeup(&tp->t_wsel); - } + cy->cy_channel_control = 0; - if (tp->t_outq.c_cc > 0) { - struct cy_ring *txq = &ip->tx_buf; - int free_count = CY_TX_BUF_SIZE - ip->tx_buf.used; - u_char *cp = txq->tail; - int count; - int chars_done; + /* hmm... need spltty() here? */ + if(cy_open == 0) + { + cy_open = 1; + timeout(cy_poll, NULL, 1); + } - tp->t_state |= TS_BUSY; + /* this sets parameters and raises DTR */ + cyparam(tp, &tp->t_termios); - /* find the largest contig. copy we can do */ - count = ((txq->endish - cp) > free_count) ? - free_count : txq->endish - cp; + ttsetwater(tp); - count = ((cp + free_count) > txq->endish) ? - txq->endish - cp : free_count; + /* raise RTS too */ + cy_modem_control(cy, TIOCM_RTS, DMBIS); - /* copy the first slab */ - chars_done = q_to_b(&tp->t_outq, cp, count); + cy->cy_carrier_stat = + cd_read_reg(cy, CD1400_MSVR2); - /* check for wrap-around time */ - cp += chars_done; - if (cp == txq->endish) - cp = txq->buf; /* back to the start */ + /* enable receiver and modem change interrupts */ + cd_write_reg(cy, CD1400_SRER, CD1400_SRER_MDMCH | CD1400_SRER_RXDATA); - /* copy anything else, after we've wrapped around */ - if ((chars_done == count) && (count != free_count)) { - /* copy the second slab */ - count = q_to_b(&tp->t_outq, cp, free_count - count); - cp += count; - chars_done += count; - } + if(CY_DIALOUT(dev) || + ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR) || + ISSET(tp->t_cflag, MDMBUF) || + ISSET(cy->cy_carrier_stat, CD1400_MSVR2_CD)) + SET(tp->t_state, TS_CARR_ON); + else + CLR(tp->t_state, TS_CARR_ON); + } else if(ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) { + return EBUSY; + } else { + s = spltty(); + } - /* - * update queue, protecting ourselves from any rampant - * lower-layers - */ - disable_intr(); - txq->tail = cp; - txq->used += chars_done; - enable_intr(); + /* wait for carrier if necessary */ + if(!ISSET(flag, O_NONBLOCK)) { + while(!ISSET(tp->t_cflag, CLOCAL) && + !ISSET(tp->t_state, TS_CARR_ON)) { + SET(tp->t_state, TS_WOPEN); + error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, "cydcd", 0); + if(error != 0) { + splx(s); + return error; + } } + } - if (!tp->t_outq.c_cc) - tp->t_state &=~ TS_BUSY; -} /* end of service_upper_tx() */ -#endif /* TxBuffer */ + splx(s); + return (*linesw[tp->t_line].l_open)(dev, tp); +} -inline static void -service_upper_mdm(int unit) +/* + * close routine. returns zero if successfull, else error code + */ +int +cyclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; { - struct cy *ip = info[unit]; - - if (ip->carrier_delta) { - int carrier = ip->modem_sig & CD1400_MSVR_CD; - struct tty *tp = ip->tty; - - if (!(*linesw[(u_char)tp->t_line].l_modem)(tp, carrier)) { - cy_addr base = ip->base_addr; - - /* clear DTR */ - disable_intr(); - *(base + CD1400_CAR) = (u_char)(unit & 0x03); - *(base + CD1400_DTR) = (u_char)CD1400_DTR_CLEAR; - ip->modem_sig &= ~CD1400_MSVR_DTR; - ip->carrier_delta = 0; - enable_intr(); - } - else { - disable_intr(); - ip->carrier_delta = 0; - enable_intr(); - } - } -} /* end of service_upper_mdm() */ + int card = CY_CARD(dev); + int port = CY_PORT(dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + struct tty *tp = cy->cy_tty; + int s; + +#ifdef CY_DEBUG + printf("cy%d close port %d, flag 0x%x, mode 0x%x\n", + card, port, flag, mode); +#endif + (*linesw[tp->t_line].l_close)(tp, flag); + s = spltty(); -/* upper level character processing routine */ -static void -cytimeout(caddr_t ptr) -{ - int unit; + if(ISSET(tp->t_cflag, HUPCL) && + !ISSET(cy->cy_openflags, TIOCFLAG_SOFTCAR)) { + /* drop DTR and RTS + (should we wait for output buffer to become empty first?) */ + cy_modem_control(cy, 0, DMSET); + } - timeout_scheduled = 0; +/* + * XXX should we disable modem change and + * receive interrupts here or somewhere ? + */ + CLR(tp->t_state, TS_BUSY | TS_FLUSH); -#ifdef CyDebug - cy_timeouts++; -#endif + splx(s); + ttyclose(tp); - /* check each port in turn */ - for (unit = 0; unit < NCY*PORTS_PER_CYCLOM; unit++) { - struct cy *ip = info[unit]; -#ifndef TxBuffer - struct tty *tp = ip->tty; -#endif + return 0; +} - /* ignore anything that is not open */ - if (!ip->tty) - continue; +/* + * Read routine + */ +int +cyread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int card = CY_CARD(dev); + int port = CY_PORT(dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + struct tty *tp = cy->cy_tty; + +#ifdef CY_DEBUG + printf("cy%d read port %d uio 0x%x flag 0x%x\n", + card, port, uio, flag); +#endif - /* - * any received chars to handle? (doesn't matter if intr routine - * kicks in while we're testing this) - */ - if (ip->rx_buf->free != CY_RX_BUF_SIZE) - service_upper_rx(unit); + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} -#ifdef TxBuffer - /* anything to add to the transmit buffer (low-water mark)? */ - if (ip->tx_buf.used < CY_TX_BUF_SIZE/2) - service_upper_tx(unit); -#else - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state&TS_ASLEEP) { - tp->t_state &= ~TS_ASLEEP; - wakeup((caddr_t)&tp->t_outq); - } - selwakeup(&tp->t_wsel); - } +/* + * Write routine + */ +int +cywrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int card = CY_CARD(dev); + int port = CY_PORT(dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + struct tty *tp = cy->cy_tty; + +#ifdef CY_DEBUG + printf("cy%d write port %d uio 0x%x flag 0x%x\n", + card, port, uio, flag); #endif - /* anything modem signals altered? */ - service_upper_mdm(unit); - - /* any overruns to log? */ -#ifdef LogOverruns - if (ip->fifo_overrun) { - /* - * turn off the alarm - not important enough to bother - * with interrupt protection. - */ - ip->fifo_overrun = 0; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} - log(LOG_WARNING, "cy%d: receive fifo overrun\n", unit); - } +/* + * return tty pointer + */ +struct tty * +cytty(dev) + dev_t dev; +{ + int card = CY_CARD(dev); + int port = CY_PORT(dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + struct tty *tp = cy->cy_tty; + +#ifdef CY_DEBUG + printf("cy%d tty port %d tp 0x%x\n", + card, port, tp); #endif - if (ip->rx_buf_overrun) { - /* - * turn off the alarm - not important enough to bother - * with interrupt protection. - */ - ip->rx_buf_overrun = 0; - - log(LOG_WARNING, "cy%d: receive buffer full\n", unit); - } - } -} /* cytimeout() */ + return tp; +} -inline static void -schedule_upper_service(void) +/* + * ioctl routine + */ +int +cyioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; { -#ifdef CyDebug - cy_timeout_req++; + int card = CY_CARD(dev); + int port = CY_PORT(dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + struct tty *tp = cy->cy_tty; + int error; + +#ifdef CY_DEBUG + printf("cy%d port %d ioctl cmd 0x%x data 0x%x flag 0x%x\n", + card, port, cmd, data, flag); #endif - if (!timeout_scheduled) { - timeout(cytimeout, (caddr_t)0, 1); /* call next tick */ - timeout_scheduled = 1; - } -} /* end of schedule_upper_service() */ + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if(error >= 0) + return error; + error = ttioctl(tp, cmd, data, flag, p); + if(error >= 0) + return error; -/* initialise a channel on the cyclom board */ +/* XXX should not allow dropping DTR when dialin? */ -static void -cy_channel_init(dev_t dev, int reset) -{ - u_int unit = UNIT(dev); - int carrier_mode = CARRIER_MODE(dev); - struct cy *ip = info[unit]; - cy_addr base = ip->base_addr; - struct tty *tp = ip->tty; - struct cy_buf *buf, *next_buf; - int i; -#ifndef PollMode - u_char cd1400_unit; -#endif + switch(cmd) { + case TIOCSBRK: /* start break */ + SET(cy->cy_flags, CYF_START_BREAK); + cy_enable_transmitter(cy); + break; - /* clear the structure and refill it */ - bzero(ip, sizeof(struct cy)); - ip->base_addr = base; - ip->tty = tp; - ip->carrier_mode = carrier_mode; + case TIOCCBRK: /* stop break */ + SET(cy->cy_flags, CYF_END_BREAK); + cy_enable_transmitter(cy); + break; - /* select channel of the CD1400 */ - *(base + CD1400_CAR) = (u_char)(unit & 0x03); + case TIOCSDTR: /* DTR on */ + cy_modem_control(cy, TIOCM_DTR, DMBIS); + break; - if (reset) - cd1400_channel_cmd(base, 0x80); /* reset the channel */ + case TIOCCDTR: /* DTR off */ + cy_modem_control(cy, TIOCM_DTR, DMBIC); + break; - /* set LIVR to 0 - intr routines depend on this */ - *(base + CD1400_LIVR) = 0; + case TIOCMSET: /* set new modem control line values */ + cy_modem_control(cy, *((int *)data), DMSET); + break; -#ifndef PollMode - /* set top four bits of {R,T,M}ICR to the cd1400 - * number, cd1400_unit - */ - cd1400_unit = unit / CD1400_NO_OF_CHANNELS; - *(base + CD1400_RICR) = (u_char)(cd1400_unit << 4); - *(base + CD1400_TICR) = (u_char)(cd1400_unit << 4); - *(base + CD1400_MICR) = (u_char)(cd1400_unit << 4); -#endif + case TIOCMBIS: /* turn modem control bits on */ + cy_modem_control(cy, *((int *)data), DMBIS); + break; - ip->dtrwait = hz/4; /* quarter of a second */ + case TIOCMBIC: /* turn modem control bits off */ + cy_modem_control(cy, *((int *)data), DMBIC); + break; - /* setup low-level buffers */ - i = CY_RX_BUFS; - ip->rx_buf = next_buf = &ip->rx_buf_pool[0]; - while (i--) { - buf = &ip->rx_buf_pool[i]; + case TIOCMGET: /* get modem control/status line state */ + *((int *)data) = cy_modem_control(cy, 0, DMGET); + break; - buf->next_char = buf->buf; /* first char to use */ - buf->free = CY_RX_BUF_SIZE; /* i.e. empty */ - buf->next_buf = next_buf; /* where to go next */ - next_buf = buf; - } + case TIOCGFLAGS: + *((int *)data) = cy->cy_openflags | + (CY_DIALOUT(dev) ? TIOCFLAG_SOFTCAR : 0); + break; -#ifdef TxBuffer - ip->tx_buf.endish = ip->tx_buf.buf + CY_TX_BUF_SIZE; + case TIOCSFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if(error != 0) + return EPERM; - /* clear the low-level tx buffer */ - ip->tx_buf.head = ip->tx_buf.tail = ip->tx_buf.buf; - ip->tx_buf.used = 0; -#endif + cy->cy_openflags = *((int *)data) & + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | + TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF); + break; - /* clear the low-level rx buffer */ - ip->rx_buf->next_char = ip->rx_buf->buf; /* first char to use */ - ip->rx_buf->free = CY_RX_BUF_SIZE; /* completely empty */ -} /* end of cy_channel_init() */ + default: + return ENOTTY; + } + return 0; +} -/* service a receive interrupt */ -inline static void -service_rx(int cd, caddr_t base) +/* + * start output + */ +void +cystart(tp) + struct tty *tp; { - struct cy *infop; - unsigned count; - int ch; - u_char serv_type, channel; -#ifdef PollMode - u_char save_rir, save_car; + int card = CY_CARD(tp->t_dev); + int port = CY_PORT(tp->t_dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + int s; + +#ifdef CY_DEBUG + printf("cy%d port %d start, tty 0x%x\n", card, port, tp); #endif - /* setup */ -#ifdef PollMode - save_rir = *(base + CD1400_RIR); - channel = cd * CD1400_NO_OF_CHANNELS + (save_rir & 0x3); - save_car = *(base + CD1400_CAR); - *(base + CD1400_CAR) = save_rir; /* enter modem service */ - serv_type = *(base + CD1400_RIVR); -#else - serv_type = *(base + CD1400_SVCACKR); /* ack receive service */ - channel = ((u_char)*(base + CD1400_RICR)) >> 2; /* get cyclom channel # */ -#ifdef CyDebug - if (channel >= PORTS_PER_CYCLOM) { - printf("cy: service_rx - channel %02x\n", channel); - panic("cy: service_rx - bad channel"); - } -#endif + s = spltty(); + +#ifdef CY_DEBUG1 + cy->cy_start_count++; #endif - infop = info[channel]; + if(!ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY)) { + if(tp->t_outq.c_cc <= tp->t_lowat) { + if(ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup(&tp->t_outq); + } - /* read those chars */ - if (serv_type & CD1400_RIVR_EXCEPTION) { - /* read the exception status */ - u_char status = *(base + CD1400_RDSR); + selwakeup(&tp->t_wsel); - /* XXX is it a break? Do something if it is! */ + if(tp->t_outq.c_cc == 0) + goto out; + } - /* XXX is IGNPAR not set? Store a null in the buffer. */ + SET(tp->t_state, TS_BUSY); + cy_enable_transmitter(cy); + } +out: -#ifdef LogOverruns - if (status & CD1400_RDSR_OVERRUN) { -#if 0 - ch |= TTY_PE; /* for SLIP */ -#endif - infop->fifo_overrun++; - } -#endif - infop->recv_exception++; - } - else { - struct cy_buf *buf = infop->rx_buf; + splx(s); +} - count = (u_char)*(base + CD1400_RDCR); /* how many to read? */ - infop->recv_normal += count; - if (buf->free < count) { - infop->rx_buf_overrun += count; +/* + * stop output + */ +void +cystop(tp, flag) + struct tty *tp; + int flag; +{ + int card = CY_CARD(tp->t_dev); + int port = CY_PORT(tp->t_dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + int s; + +#ifdef CY_DEBUG + printf("cy%d port %d stop tty 0x%x flag 0x%x\n", + card, port, tp, flag); +#endif - /* read & discard everything */ - while (count--) - ch = (u_char)*(base + CD1400_RDSR); - } - else { - /* slurp it into our low-level buffer */ - buf->free -= count; - while (count--) { - ch = (u_char)*(base + CD1400_RDSR); /* read the char */ - *(buf->next_char++) = ch; - } - } - } + s = spltty(); -#ifdef PollMode - *(base + CD1400_RIR) = (u_char)(save_rir & 0x3f); /* terminate service context */ -#else - *(base + CD1400_EOSRR) = (u_char)0; /* terminate service context */ -#endif -} /* end of service_rx */ + if(ISSET(tp->t_state, TS_BUSY)) { + if(!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + /* + * the transmit interrupt routine will disable transmit when it + * notices that CYF_STOP has been set. + */ + SET(cy->cy_flags, CYF_STOP); + } + splx(s); +} -/* service a transmit interrupt */ -inline static void -service_tx(int cd, caddr_t base) +/* + * parameter setting routine. + * returns 0 if successfull, else returns error code + */ +static int +cyparam(tp, t) + struct tty *tp; + struct termios *t; { - struct cy *ip; -#ifdef TxBuffer - struct cy_ring *txq; -#else - struct tty *tp; -#endif - u_char channel; -#ifdef PollMode - u_char save_tir, save_car; -#else - u_char vector; + int card = CY_CARD(tp->t_dev); + int port = CY_PORT(tp->t_dev); + struct cy_softc *sc = cy_cd.cd_devs[card]; + struct cy_port *cy = &sc->sc_ports[port]; + int ibpr, obpr, i_clk_opt, o_clk_opt; + int s, opt; + +#ifdef CY_DEBUG + printf("cy%d port %d param tty 0x%x termios 0x%x\n", + card, port, tp, t); + printf("ispeed %d ospeed %d\n", t->c_ispeed, t->c_ospeed); #endif - /* setup */ -#ifdef PollMode - save_tir = *(base + CD1400_TIR); - channel = cd * CD1400_NO_OF_CHANNELS + (save_tir & 0x3); - save_car = *(base + CD1400_CAR); - *(base + CD1400_CAR) = save_tir; /* enter tx service */ -#else - vector = *(base + CD1400_SVCACKT); /* ack transmit service */ - channel = ((u_char)*(base + CD1400_TICR)) >> 2; /* get cyclom channel # */ + if(t->c_ospeed != 0 && cy_speed(t->c_ospeed, &o_clk_opt, &obpr) < 0) + return EINVAL; -#ifdef CyDebug - if (channel >= PORTS_PER_CYCLOM) { - printf("cy: service_tx - channel %02x\n", channel); - panic("cy: service_tx - bad channel"); - } -#endif -#endif + if(t->c_ispeed != 0 && cy_speed(t->c_ispeed, &i_clk_opt, &ibpr) < 0) + return EINVAL; - ip = info[channel]; -#ifdef TxBuffer - txq = &ip->tx_buf; - - if (txq->used > 0) { - cy_addr base = ip->base_addr; - int count = min(CD1400_FIFOSIZE, txq->used); - int chars_done = count; - u_char *cp = txq->head; - u_char *buf_end = txq->endish; - - /* ip->state |= CY_BUSY; */ - while (count--) { - *(base + CD1400_TDR) = *cp++; - if (cp >= buf_end) - cp = txq->buf; - }; - txq->head = cp; - txq->used -= chars_done; /* important that this is atomic */ - ip->xmit += chars_done; - } + s = spltty(); - /* - * disable tx intrs if no more chars to send. we re-enable - * them in cystart() - */ - if (!txq->used) { - ip->intr_enable &=~ (1 << 2); - *(base + CD1400_SRER) = ip->intr_enable; - /* ip->state &= ~CY_BUSY; */ - } -#else - tp = ip->tty; + /* hang up the line is ospeed is zero, else turn DTR on */ + cy_modem_control(cy, TIOCM_DTR, (t->c_ospeed == 0 ? DMBIC : DMBIS)); - if (!(tp->t_state & TS_TTSTOP) && (tp->t_outq.c_cc > 0)) { - cy_addr base = ip->base_addr; - int count = min(CD1400_FIFOSIZE, tp->t_outq.c_cc); + /* channel was selected by the above call to cy_modem_control() */ + /* cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN); */ - ip->xmit += count; - tp->t_state |= TS_BUSY; - while (count--) - *(base + CD1400_TDR) = getc(&tp->t_outq); - } + /* set transmit speed */ + if(t->c_ospeed != 0) { + cd_write_reg(cy, CD1400_TCOR, o_clk_opt); + cd_write_reg(cy, CD1400_TBPR, obpr); + } + /* set receive speed */ + if(t->c_ispeed != 0) { + cd_write_reg(cy, CD1400_RCOR, i_clk_opt); + cd_write_reg(cy, CD1400_RBPR, ibpr); + } - /* - * disable tx intrs if no more chars to send. we re-enable them - * in cystart() - */ - if (!tp->t_outq.c_cc) { - ip->intr_enable &=~ (1 << 2); - *(base + CD1400_SRER) = ip->intr_enable; - tp->t_state &= ~TS_BUSY; - } -#endif + opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN + | (ISSET(t->c_cflag, CREAD) ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS); -#ifdef PollMode - *(base + CD1400_TIR) = (u_char)(save_tir & 0x3f); /* terminate service context */ -#else - *(base + CD1400_EOSRR) = (u_char)0; /* terminate service context */ -#endif -} /* end of service_tx */ + if(opt != cy->cy_channel_control) { + cy->cy_channel_control = opt; + cd1400_channel_cmd(cy, opt); + } + /* compute COR1 contents */ + opt = 0; + if(ISSET(t->c_cflag, PARENB)) { + if(ISSET(t->c_cflag, PARODD)) + opt |= CD1400_COR1_PARODD; + opt |= CD1400_COR1_PARNORMAL; + } -/* service a modem status interrupt */ -inline static void -service_mdm(int cd, caddr_t base) -{ - struct cy *infop; - u_char channel, deltas; -#ifdef PollMode - u_char save_mir, save_car; -#else - u_char vector; -#endif + if(!ISSET(t->c_iflag, INPCK)) + opt |= CD1400_COR1_NOINPCK; /* no parity checking */ - /* setup */ -#ifdef PollMode - save_mir = *(base + CD1400_MIR); - channel = cd * CD1400_NO_OF_CHANNELS + (save_mir & 0x3); - save_car = *(base + CD1400_CAR); - *(base + CD1400_CAR) = save_mir; /* enter modem service */ -#else - vector = *(base + CD1400_SVCACKM); /* ack modem service */ - channel = ((u_char)*(base + CD1400_MICR)) >> 2; /* get cyclom channel # */ + if(ISSET(t->c_cflag, CSTOPB)) + opt |= CD1400_COR1_STOP2; -#ifdef CyDebug - if (channel >= PORTS_PER_CYCLOM) { - printf("cy: service_mdm - channel %02x\n", channel); - panic("cy: service_mdm - bad channel"); - } -#endif -#endif + switch(t->c_cflag & CSIZE) { + case CS5: + opt |= CD1400_COR1_CS5; + break; - infop = info[channel]; + case CS6: + opt |= CD1400_COR1_CS6; + break; - /* read the siggies and see what's changed */ - infop->modem_sig = (u_char)*(base + CD1400_MSVR); - deltas = (u_char)*(base + CD1400_MISR); + case CS7: + opt |= CD1400_COR1_CS7; + break; - if ((infop->carrier_mode <= 2) && (deltas & CD1400_MISR_CDd)) - /* something for the upper layer to deal with */ - infop->carrier_delta = 1; + default: + opt |= CD1400_COR1_CS8; + break; + } - infop->mdm++; + cd_write_reg(cy, CD1400_COR1, opt); - /* terminate service context */ -#ifdef PollMode - *(base + CD1400_MIR) = (u_char)(save_mir & 0x3f); -#else - *(base + CD1400_EOSRR) = (u_char)0; +#ifdef CY_DEBUG + printf("cor1 = 0x%x...", opt); #endif -} /* end of service_mdm */ +/* + * use the CD1400 automatic CTS flow control if CRTSCTS is set + * + * CD1400_COR2_ETC is used because breaks are generated with + * embedded transmit commands + */ + cd_write_reg(cy, CD1400_COR2, + CD1400_COR2_ETC | + (ISSET(t->c_cflag, CRTSCTS) ? CD1400_COR2_CCTS_OFLOW : 0)); + + cd_write_reg(cy, CD1400_COR3, RX_FIFO_THRESHOLD); + + cd1400_channel_cmd(cy, + CD1400_CCR_CMDCORCHG | + CD1400_CCR_COR1 | CD1400_CCR_COR2 | CD1400_CCR_COR3); + + cd_write_reg(cy, CD1400_COR4, CD1400_COR4_PFO_EXCEPTION); + cd_write_reg(cy, CD1400_COR5, 0); + + /* + * set modem change option registers to generate interrupts + * on carrier detect changes. + * + * if hardware RTS handshaking is used (CY_HW_RTS, DTR and RTS lines + * exchanged), also set the handshaking threshold. + */ +#ifdef CY_HW_RTS + cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd | + (ISSET(t->c_cflag, CRTSCTS) ? RX_DTR_THRESHOLD : 0)); +#else + cd_write_reg(cy, CD1400_MCOR1, CD1400_MCOR1_CDzd); +#endif /* CY_HW_RTS */ -int -cyintr(int unit) -{ - int cd; - u_char status; - - /* check each CD1400 in turn */ - for (cd = 0; cd < CD1400s_PER_CYCLOM; cd++) { - cy_addr base = cyclom_base + cd*CD1400_MEMSIZE; - - /* poll to see if it has any work */ - while (status = (u_char)*(base + CD1400_SVRR)) { -#ifdef CyDebug - cy_svrr_probes++; -#endif - /* service requests as appropriate, giving priority to RX */ - if (status & CD1400_SVRR_RX) - service_rx(cd, base); - if (status & CD1400_SVRR_TX) - service_tx(cd, base); - if (status & CD1400_SVRR_MDM) - service_mdm(cd, base); - } - } + cd_write_reg(cy, CD1400_MCOR2, CD1400_MCOR2_CDod); - /* request upper level service to deal with whatever happened */ - schedule_upper_service(); + /* + * set receive timeout to approx. 2ms + * could use more complex logic here... + * (but is it actually needed or even useful?) + */ + cd_write_reg(cy, CD1400_RTPR, 2); - /* re-enable interrupts on the cyclom */ - *(cyclom_base + CYCLOM_CLEAR_INTR) = (u_char)0; + /* + * should do anything else here? + * XXX check MDMBUF handshaking like in com.c? + */ - return 1; + splx(s); + return 0; } +/* + * set/get modem line status + * + * bits can be: TIOCM_DTR, TIOCM_RTS, TIOCM_CTS, TIOCM_CD, TIOCM_RI, TIOCM_DSR + * + * RTS and DTR are exchanged if CY_HW_RTS is set + * + */ +static int +cy_modem_control(cy, bits, howto) + struct cy_port *cy; + int bits; + int howto; +{ + int s, msvr; + + s = spltty(); + + /* select channel */ + cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN); + +/* does not manipulate RTS if it is used for flow control */ + switch(howto) { + case DMGET: + splx(s); + bits = 0; + if(cy->cy_channel_control & CD1400_CCR_RCVEN) + bits |= TIOCM_LE; + msvr = cd_read_reg(cy, CD1400_MSVR2); +#ifdef CY_HW_RTS + if(cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS) + bits |= TIOCM_DTR; + if(msvr & CD1400_MSVR2_DTR) + bits |= TIOCM_RTS; +#else + if(cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS) + bits |= TIOCM_RTS; + if(msvr & CD1400_MSVR2_DTR) + bits |= TIOCM_DTR; +#endif /* CY_HW_RTS */ + if(msvr & CD1400_MSVR2_CTS) + bits |= TIOCM_CTS; + if(msvr & CD1400_MSVR2_CD) + bits |= TIOCM_CD; + if(msvr & CD1400_MSVR2_DSR) /* not connected on some Cyclom cards? */ + bits |= TIOCM_DSR; + if(msvr & CD1400_MSVR2_RI) /* not connected on Cyclom-8Y cards? */ + bits |= TIOCM_RI; + splx(s); + return bits; + + case DMSET: /* replace old values with new ones */ +#ifdef CY_HW_RTS + if(!ISSET(cy->cy_tty->t_cflag, CRTSCTS)) + cd_write_reg(cy, CD1400_MSVR2, + ((bits & TIOCM_RTS) ? CD1400_MSVR2_DTR : 0)); + cd_write_reg(cy, CD1400_MSVR1, + ((bits & TIOCM_DTR) ? CD1400_MSVR1_RTS : 0)); +#else + if(!ISSET(cy->cy_tty->t_cflag, CRTSCTS)) + cd_write_reg(cy, CD1400_MSVR1, + ((bits & TIOCM_RTS) ? CD1400_MSVR1_RTS : 0)); + cd_write_reg(cy, CD1400_MSVR2, + ((bits & TIOCM_DTR) ? CD1400_MSVR2_DTR : 0)); +#endif /* CY_HW_RTS */ + break; + + case DMBIS: /* set bits */ +#ifdef CY_HW_RTS + if(!ISSET(cy->cy_tty->t_cflag, CRTSCTS) && + (bits & TIOCM_RTS) != 0) + cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR); + if(bits & TIOCM_DTR) + cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS); +#else + if(!ISSET(cy->cy_tty->t_cflag, CRTSCTS) && + (bits & TIOCM_RTS) != 0) + cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS); + if(bits & TIOCM_DTR) + cd_write_reg(cy, CD1400_MSVR2, CD1400_MSVR2_DTR); +#endif /* CY_HW_RTS */ + break; + + case DMBIC: /* clear bits */ +#ifdef CY_HW_RTS + if(!ISSET(cy->cy_tty->t_cflag, CRTSCTS) && + (bits & TIOCM_RTS)) + cd_write_reg(cy, CD1400_MSVR2, 0); + if(bits & TIOCM_DTR) + cd_write_reg(cy, CD1400_MSVR1, 0); +#else + if(!ISSET(cy->cy_tty->t_cflag, CRTSCTS) && + (bits & TIOCM_RTS)) + cd_write_reg(cy, CD1400_MSVR1, 0); + if(bits & TIOCM_DTR) + cd_write_reg(cy, CD1400_MSVR2, 0); +#endif /* CY_HW_RTS */ + break; + } + splx(s); + return 0; +} -int -cyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +/* + * Upper-level handler loop (called from timer interrupt?) + * This routine is common for multiple cards + */ +static void +cy_poll(arg) + void *arg; { - int unit = UNIT(dev); - struct cy *infop = info[unit]; - struct tty *tp = infop->tty; - int error; - - error = (*linesw[(u_char)tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (error >= 0) - return (error); - error = ttioctl(tp, cmd, data, flag, p); - if (error >= 0) - return (error); - - switch (cmd) { -#ifdef notyet /* sigh - more junk to do XXX */ - case TIOCSBRK: - break; - case TIOCCBRK: - break; - case TIOCSDTR: - break; - case TIOCCDTR: - break; - - case TIOCMSET: - break; - case TIOCMBIS: - break; - case TIOCMBIC: - break; -#endif /* notyet */ - - case TIOCMGET: { - int bits = 0; - u_char status = infop->modem_sig; - - if (status & CD1400_MSVR_DTR) bits |= TIOCM_DTR | TIOCM_RTS; - if (status & CD1400_MSVR_CD) bits |= TIOCM_CD; - if (status & CD1400_MSVR_CTS) bits |= TIOCM_CTS; - if (status & CD1400_MSVR_DSR) bits |= TIOCM_DSR; -#ifdef CYCLOM_16 - if (status & CD1400_MSVR_RI) bits |= TIOCM_RI; + int card, port; + struct cy_softc *sc; + struct cy_port *cy; + struct tty *tp; + static int counter = 0; +#ifdef CY_DEBUG1 + int did_something; #endif - if (infop->channel_control & 0x02) bits |= TIOCM_LE; - *(int *)data = bits; - break; - } - -#ifdef TIOCMSBIDIR - case TIOCMSBIDIR: - return (ENOTTY); -#endif /* TIOCMSBIDIR */ - -#ifdef TIOCMGBIDIR - case TIOCMGBIDIR: - return (ENOTTY); -#endif /* TIOCMGBIDIR */ -#ifdef TIOCMSDTRWAIT - case TIOCMSDTRWAIT: - /* must be root to set dtr delay */ - if (p->p_ucred->cr_uid != 0) - return(EPERM); - - infop->dtrwait = *(u_int *)data; - break; -#endif /* TIOCMSDTRWAIT */ + disable_intr(); + if(cy_events == 0 && ++counter < 200) { + enable_intr(); + goto out; + } -#ifdef TIOCMGDTRWAIT - case TIOCMGDTRWAIT: - *(u_int *)data = infop->dtrwait; - break; -#endif /* TIOCMGDTRWAIT */ + cy_events = 0; + enable_intr(); - default: - return (ENOTTY); - } + for(card = 0; card < cy_cd.cd_ndevs; card++) { + sc = cy_cd.cd_devs[card]; + if(sc == NULL) + continue; - return 0; -} /* end of cyioctl() */ +#ifdef CY_DEBUG1 + sc->sc_poll_count1++; + did_something = 0; +#endif + for(port = 0; port < sc->sc_nports; port++) { + cy = &sc->sc_ports[port]; + if((tp = cy->cy_tty) == NULL || cy->cy_ibuf == NULL || + !ISSET(tp->t_state, TS_ISOPEN | TS_WOPEN)) + continue; -int -cyparam(struct tty *tp, struct termios *t) -{ - u_char unit = UNIT(tp->t_dev); - struct cy *infop = info[unit]; - cy_addr base = infop->base_addr; - int cflag = t->c_cflag; - int iflag = t->c_iflag; - int ispeed, ospeed; - int itimeout; - int iprescaler, oprescaler; - int s; - u_char cor_change = 0; - u_char opt; - - if (!t->c_ispeed) - t->c_ispeed = t->c_ospeed; + /* + * handle received data + */ + while(cy->cy_ibuf_rd_ptr != cy->cy_ibuf_wr_ptr) { + u_char line_stat; + int chr; - s = spltty(); + line_stat = cy->cy_ibuf_rd_ptr[0]; + chr = cy->cy_ibuf_rd_ptr[1]; - /* select the appropriate channel on the CD1400 */ - *(base + CD1400_CAR) = unit & 0x03; + if(line_stat & (CD1400_RDSR_BREAK|CD1400_RDSR_FE)) + chr |= TTY_FE; + if(line_stat & CD1400_RDSR_PE) + chr |= TTY_PE; - /* handle DTR drop on speed == 0 trick */ - if (t->c_ospeed == 0) { - *(base + CD1400_DTR) = CD1400_DTR_CLEAR; - infop->modem_sig &= ~CD1400_MSVR_DTR; - } - else { - *(base + CD1400_DTR) = CD1400_DTR_SET; - infop->modem_sig |= CD1400_MSVR_DTR; - } + /* + * on an overrun error the data is treated as good + * just as it should be. + */ - /* set baud rates if they've changed from last time */ +#ifdef CY_DEBUG + printf("cy%d port %d ttyinput 0x%x\n", + card, port, chr); +#endif - if ((ospeed = cyspeed(t->c_ospeed, &oprescaler)) < 0) - return EINVAL; - *(base + CD1400_TBPR) = (u_char)ospeed; - *(base + CD1400_TCOR) = (u_char)oprescaler; + (*linesw[tp->t_line].l_rint)(chr, tp); - if ((ispeed = cyspeed(t->c_ispeed, &iprescaler)) < 0) - return EINVAL; - *(base + CD1400_RBPR) = (u_char)ispeed; - *(base + CD1400_RCOR) = (u_char)iprescaler; + disable_intr(); /* really necessary? */ + if((cy->cy_ibuf_rd_ptr += 2) == cy->cy_ibuf_end) + cy->cy_ibuf_rd_ptr = cy->cy_ibuf; + enable_intr(); - /* - * set receive time-out period - * generate a rx interrupt if no new chars are received in - * this many ticks - * don't bother comparing old & new VMIN, VTIME and ispeed - it - * can't be much worse just to calculate and set it each time! - * certainly less hassle. :-) - */ +#ifdef CY_DEBUG1 + did_something = 1; +#endif + } - /* - * calculate minimum timeout period: - * 5 ms or the time it takes to receive 1 char, rounded up to the - * next ms, whichever is greater - */ - if (t->c_ispeed > 0) { - itimeout = (t->c_ispeed > 2200) ? 5 : (10000/t->c_ispeed + 1); +#ifndef CY_HW_RTS + /* If we don't have any received data in ibuf and + * CRTSCTS is on and RTS is turned off, it is time + * to turn RTS back on + */ + if(ISSET(tp->t_cflag, CRTSCTS)) { + /* we can't use cy_modem_control() here as it doesn't + change RTS if RTSCTS is on */ + cd_write_reg(cy, CD1400_CAR, port & CD1400_CAR_CHAN); + + if((cd_read_reg(cy, CD1400_MSVR1) & CD1400_MSVR1_RTS) == 0) { + cd_write_reg(cy, CD1400_MSVR1, CD1400_MSVR1_RTS); +#ifdef CY_DEBUG1 + did_something = 1; +#endif + } + } +#endif /* CY_HW_RTS */ - /* if we're using VTIME as an inter-char timeout, and it is set to - * be longer than the minimum calculated above, go for it + /* + * handle carrier changes */ - if (t->c_cc[VMIN] && t->c_cc[VTIME] && t->c_cc[VTIME]*10 > itimeout) - itimeout = t->c_cc[VTIME]*10; + disable_intr(); + if(ISSET(cy->cy_flags, CYF_CARRIER_CHANGED)) { + int carrier; - /* store it, taking care not to overflow the byte-sized register */ - *(base + CD1400_RTPR) = (u_char)((itimeout <= 255) ? itimeout : 255); - } + CLR(cy->cy_flags, CYF_CARRIER_CHANGED); + enable_intr(); + carrier = ((cy->cy_carrier_stat & CD1400_MSVR2_CD) != 0); - /* - * channel control - * receiver enable - * transmitter enable (always set) - */ - opt = (1 << 4) | (1 << 3) | ((cflag & CREAD) ? (1 << 1) : 1); - if (opt != infop->channel_control) { - infop->channel_control = opt; - cd1400_channel_cmd(base, opt); - } +#ifdef CY_DEBUG + printf("cy_poll: carrier change " + "(card %d, port %d, carrier %d)\n", + card, port, carrier); +#endif + if(CY_DIALIN(tp->t_dev) && + !(*linesw[tp->t_line].l_modem)(tp, carrier)) + cy_modem_control(cy, TIOCM_DTR, DMBIC); -#ifdef Smarts - /* set special chars */ - if (t->c_cc[VSTOP] != _POSIX_VDISABLE && - (t->c_cc[VSTOP] != infop->spec_char[0])) { - *(base + CD1400_SCHR1) = infop->spec_char[0] = t->c_cc[VSTOP]; - } - if (t->c_cc[VSTART] != _POSIX_VDISABLE && - (t->c_cc[VSTART] != infop->spec_char[1])) { - *(base + CD1400_SCHR2) = infop->spec_char[0] = t->c_cc[VSTART]; - } - if (t->c_cc[VINTR] != _POSIX_VDISABLE && - (t->c_cc[VINTR] != infop->spec_char[2])) { - *(base + CD1400_SCHR3) = infop->spec_char[0] = t->c_cc[VINTR]; - } - if (t->c_cc[VSUSP] != _POSIX_VDISABLE && - (t->c_cc[VSUSP] != infop->spec_char[3])) { - *(base + CD1400_SCHR4) = infop->spec_char[0] = t->c_cc[VSUSP]; - } +#ifdef CY_DEBUG1 + did_something = 1; #endif + } else { + enable_intr(); + } - /* - * set channel option register 1 - - * parity mode - * stop bits - * char length - */ - opt = 0; - /* parity */ - if (cflag & PARENB) { - if (cflag & PARODD) - opt |= 1 << 7; - opt |= 2 << 5; /* normal parity mode */ - } - if (!(iflag & INPCK)) - opt |= 1 << 4; /* ignore parity */ - /* stop bits */ - if (cflag & CSTOPB) - opt |= 2 << 2; - /* char length */ - opt |= (cflag & CSIZE) >> 8; /* nasty, but fast */ - if (opt != infop->cor[0]) { - cor_change |= 1 << 1; - *(base + CD1400_COR1) = opt; - } + disable_intr(); + if(ISSET(cy->cy_flags, CYF_START)) { + CLR(cy->cy_flags, CYF_START); + enable_intr(); - /* - * set channel option register 2 - - * flow control - */ - opt = 0; -#ifdef Smarts - if (iflag & IXANY) - opt |= 1 << 7; /* auto output restart on any char after XOFF */ - if (iflag & IXOFF) - opt |= 1 << 6; /* auto XOFF output flow-control */ + (*linesw[tp->t_line].l_start)(tp); + +#ifdef CY_DEBUG1 + did_something = 1; #endif - if (cflag & CCTS_OFLOW) - opt |= 1 << 1; /* auto CTS flow-control */ - if (opt != infop->cor[1]) { - cor_change |= 1 << 2; - *(base + CD1400_COR2) = opt; - } + } else { + enable_intr(); + } - /* - * set channel option register 3 - - * receiver FIFO interrupt threshold - * flow control - */ - opt = RxFifoThreshold; /* rx fifo threshold */ -#ifdef Smarts - if (t->c_lflag & ICANON) - opt |= 1 << 6; /* detect INTR & SUSP chars */ - if (iflag & IXOFF) - opt |= (1 << 5) | (1 << 4); /* transparent in-band flow control */ + /* could move this to even upper level... */ + if(cy->cy_fifo_overruns) { + cy->cy_fifo_overruns = 0; + /* doesn't report overrun count, + but shouldn't really matter */ + log(LOG_WARNING, "cy%d port %d fifo overrun\n", + card, port); + } + if(cy->cy_ibuf_overruns) { + cy->cy_ibuf_overruns = 0; + log(LOG_WARNING, "cy%d port %d ibuf overrun\n", + card, port); + } + } /* for(port...) */ +#ifdef CY_DEBUG1 + if(did_something && counter >= 200) + sc->sc_poll_count2++; #endif - if (opt != infop->cor[2]) { - cor_change |= 1 << 3; - *(base + CD1400_COR3) = opt; - } + } /* for(card...) */ + counter = 0; - /* notify the CD1400 if COR1-3 have changed */ - if (cor_change) { - cor_change |= 1 << 6; /* COR change flag */ - cd1400_channel_cmd(base, cor_change); - } +out: + timeout(cy_poll, NULL, 1); +} - /* - * set channel option register 4 - - * CR/NL processing - * break processing - * received exception processing - */ - opt = 0; - if (iflag & IGNCR) - opt |= 1 << 7; -#ifdef Smarts - /* - * we need a new ttyinput() for this, as we don't want to - * have ICRNL && INLCR being done in both layers, or to have - * synchronisation problems - */ - if (iflag & ICRNL) - opt |= 1 << 6; - if (iflag & INLCR) - opt |= 1 << 5; -#endif - if (iflag & IGNBRK) - opt |= 1 << 4; - if (!(iflag & BRKINT)) - opt |= 1 << 3; - if (iflag & IGNPAR) -#ifdef LogOverruns - opt |= 0; /* broken chars cause receive exceptions */ -#else - opt |= 2; /* discard broken chars */ -#endif - else { - if (iflag & PARMRK) - opt |= 4; /* precede broken chars with 0xff 0x0 */ - else -#ifdef LogOverruns - opt |= 0; /* broken chars cause receive exceptions */ -#else - opt |= 3; /* convert framing/parity errs to nulls */ -#endif - } - *(base + CD1400_COR4) = opt; +/* + * hardware interrupt routine + */ +int +cyintr(arg) + void *arg; +{ + struct cy_softc *sc = arg; + struct cy_port *cy; + int card = sc->sc_dev.dv_unit; + int cy_chip, stat; + int int_serviced = 0; - /* - * set channel option register 5 - - */ - opt = 0; - if (iflag & ISTRIP) - opt |= 1 << 7; - if (t->c_iflag & IEXTEN) { - opt |= 1 << 6; /* enable LNEXT (e.g. ctrl-v quoting) handling */ - } -#ifdef Smarts - if (t->c_oflag & ONLCR) - opt |= 1 << 1; - if (t->c_oflag & OCRNL) - opt |= 1; -#endif - *(base + CD1400_COR5) = opt; +/* + * Check interrupt status of each CD1400 chip on this card + * (multiple cards cannot share the same interrupt) + */ + for(cy_chip = 0; cy_chip < cy_nr_cd1400s[card]; cy_chip++) { - /* - * set modem change option register 1 - * generate modem interrupts on which 1 -> 0 input transitions - * also controls auto-DTR output flow-control, which we don't use - */ - opt = (cflag & CLOCAL) ? 0 : 1 << 4; /* CD */ - *(base + CD1400_MCOR1) = opt; + stat = cd_read_reg_sc(sc, cy_chip, CD1400_SVRR); + if(stat == 0) + continue; - /* - * set modem change option register 2 - * generate modem interrupts on specific 0 -> 1 input transitions - */ - opt = (cflag & CLOCAL) ? 0 : 1 << 4; /* CD */ - *(base + CD1400_MCOR2) = opt; + if(ISSET(stat, CD1400_SVRR_RXRDY)) { + u_char save_car, save_rir, serv_type; + u_char line_stat, recv_data, n_chars; + u_char *buf_p; - splx(s); + save_rir = cd_read_reg_sc(sc, cy_chip, CD1400_RIR); + save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR); + /* enter rx service */ + cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_rir); - return 0; -} /* end of cyparam */ + serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_RIVR); + cy = &sc->sc_ports[serv_type >> 3]; +#ifdef CY_DEBUG1 + cy->cy_rx_int_count++; +#endif -void -cystart(struct tty *tp) -{ - u_char unit = UNIT(tp->t_dev); - struct cy *infop = info[unit]; - cy_addr base = infop->base_addr; - int s; + if(cy->cy_tty == NULL || + !ISSET(cy->cy_tty->t_state, TS_ISOPEN)) + goto end_rx_serv; -#ifdef CyDebug - infop->start_count++; -#endif + buf_p = cy->cy_ibuf_wr_ptr; - /* check the flow-control situation */ - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) - return; + if(ISSET(serv_type, CD1400_RIVR_EXCEPTION)) { + line_stat = cd_read_reg(cy, CD1400_RDSR); + recv_data = cd_read_reg(cy, CD1400_RDSR); - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state&TS_ASLEEP) { - tp->t_state &= ~TS_ASLEEP; - wakeup((caddr_t)&tp->t_outq); +#ifdef CY_DEBUG + printf("cy%d port %d recv exception, " + "line_stat 0x%x, char 0x%x\n", + card, cy->cy_port_num, line_stat, recv_data); +#endif + if(ISSET(line_stat, CD1400_RDSR_OE)) + cy->cy_fifo_overruns++; + + *buf_p++ = line_stat; + *buf_p++ = recv_data; + if(buf_p == cy->cy_ibuf_end) + buf_p = cy->cy_ibuf; + + if(buf_p == cy->cy_ibuf_rd_ptr) { + if(buf_p == cy->cy_ibuf) + buf_p = cy->cy_ibuf_end; + buf_p -= 2; + cy->cy_ibuf_overruns++; } - selwakeup(&tp->t_wsel); - } - -#ifdef TxBuffer - service_upper_tx(unit); /* feed the monster */ + cy_events = 1; + } else { /* no exception, received data OK */ + n_chars = cd_read_reg(cy, CD1400_RDCR); +#ifdef CY_DEBUG + printf("cy%d port %d receive ok %d chars\n", + card, cy->cy_port_num, n_chars); #endif + while(n_chars--) { + *buf_p++ = 0; /* status: OK */ + *buf_p++ = + cd_read_reg(cy, CD1400_RDSR); /* data byte */ + if(buf_p == cy->cy_ibuf_end) + buf_p = cy->cy_ibuf; + if(buf_p == cy->cy_ibuf_rd_ptr) { + if(buf_p == cy->cy_ibuf) + buf_p = cy->cy_ibuf_end; + buf_p -= 2; + cy->cy_ibuf_overruns++; + break; + } + } + cy_events = 1; + } - s = spltty(); + cy->cy_ibuf_wr_ptr = buf_p; - if (!(infop->intr_enable & (1 << 2))) { - /* select the channel */ - *(base + CD1400_CAR) = unit & (u_char)3; +#ifndef CY_HW_RTS + /* RTS handshaking for incoming data */ + if(ISSET(cy->cy_tty->t_cflag, CRTSCTS)) { + int bf; - /* (re)enable interrupts to set things in motion */ - infop->intr_enable |= (1 << 2); - *(base + CD1400_SRER) = infop->intr_enable; + bf = buf_p - cy->cy_ibuf_rd_ptr; + if(bf < 0) + bf += IBUF_SIZE; - infop->start_real++; - } + if(bf > (IBUF_SIZE/2)) /* turn RTS off */ + cd_write_reg(cy, CD1400_MSVR1, 0); + } +#endif /* CY_HW_RTS */ - splx(s); -} /* end of cystart() */ +end_rx_serv: + /* terminate service context */ + cd_write_reg(cy, CD1400_RIR, save_rir & 0x3f); + cd_write_reg(cy, CD1400_CAR, save_car); + int_serviced = 1; + } /* if(rx_service...) */ + if(ISSET(stat, CD1400_SVRR_MDMCH)) { + u_char save_car, save_mir, serv_type, modem_stat; -int -cystop(struct tty *tp, int flag) -{ - u_char unit = UNIT(tp->t_dev); - struct cy *ip = info[unit]; - cy_addr base = ip->base_addr; - int s; + save_mir = cd_read_reg_sc(sc, cy_chip, CD1400_MIR); + save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR); + /* enter modem service */ + cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_mir); - s = spltty(); + serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_MIVR); + cy = &sc->sc_ports[serv_type >> 3]; - /* select the channel */ - *(base + CD1400_CAR) = unit & 3; +#ifdef CY_DEBUG1 + cy->cy_modem_int_count++; +#endif - /* halt output by disabling transmit interrupts */ - ip->intr_enable &=~ (1 << 2); - *(base + CD1400_SRER) = ip->intr_enable; + modem_stat = cd_read_reg(cy, CD1400_MSVR2); - splx(s); +#ifdef CY_DEBUG + printf("cy%d port %d modem line change, new stat 0x%x\n", + card, cy->cy_port_num, modem_stat); +#endif + if(ISSET((cy->cy_carrier_stat ^ modem_stat), CD1400_MSVR2_CD)) { + SET(cy->cy_flags, CYF_CARRIER_CHANGED); + cy_events = 1; + } - return 0; -} + cy->cy_carrier_stat = modem_stat; + /* terminate service context */ + cd_write_reg(cy, CD1400_MIR, save_mir & 0x3f); + cd_write_reg(cy, CD1400_CAR, save_car); + int_serviced = 1; + } /* if(modem_service...) */ -int -cyselect(dev_t dev, int rw, struct proc *p) -{ - struct tty *tp = info[UNIT(dev)]->tty; - int s = spltty(); - int nread; - - switch (rw) { - - case FREAD: - nread = ttnread(tp); - if (nread > 0 || - ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) - goto win; - selrecord(p, &tp->t_rsel); - break; - - case FWRITE: - if (tp->t_outq.c_cc <= tp->t_lowat) - goto win; - selrecord(p, &tp->t_wsel); - break; - } - splx(s); - return (0); - win: - splx(s); - return (1); -} /* end of cyselect() */ + if(ISSET(stat, CD1400_SVRR_TXRDY)) { + u_char save_car, save_tir, serv_type, count, ch; + struct tty *tp; + save_tir = cd_read_reg_sc(sc, cy_chip, CD1400_TIR); + save_car = cd_read_reg_sc(sc, cy_chip, CD1400_CAR); + /* enter tx service */ + cd_write_reg_sc(sc, cy_chip, CD1400_CAR, save_tir); -int -cyspeed(int speed, int *prescaler_io) -{ - int actual; - int error; - int divider; - int prescaler; - int prescaler_unit; - - if (speed == 0) - return 0; - - if (speed < 0 || speed > 150000) - return -1; - - /* determine which prescaler to use */ - for (prescaler_unit = 4, prescaler = 2048; prescaler_unit; - prescaler_unit--, prescaler >>= 2) { - if (CYCLOM_CLOCK/prescaler/speed > 63) - break; - } + serv_type = cd_read_reg_sc(sc, cy_chip, CD1400_TIVR); + cy = &sc->sc_ports[serv_type >> 3]; - divider = (CYCLOM_CLOCK/prescaler*2/speed + 1)/2; /* round off */ - if (divider > 255) - divider = 255; - actual = CYCLOM_CLOCK/prescaler/divider; - error = ((actual-speed)*2000/speed +1)/2; /* percentage */ - - /* 3.0% max error tolerance */ - if (error < -30 || error > 30) - return -1; - -#if 0 - printf("prescaler = %d (%d)\n", prescaler, prescaler_unit); - printf("divider = %d (%x)\n", divider, divider); - printf("actual = %d\n", actual); - printf("error = %d\n", error); +#ifdef CY_DEBUG1 + cy->cy_tx_int_count++; +#endif +#ifdef CY_DEBUG + printf("cy%d port %d tx service\n", card, cy->cy_port_num); #endif - *prescaler_io = prescaler_unit; - return divider; -} /* end of cyspeed() */ + /* stop transmitting if no tty or CYF_STOP set */ + tp = cy->cy_tty; + if(tp == NULL || ISSET(cy->cy_flags, CYF_STOP)) + goto txdone; + + count = 0; + if(ISSET(cy->cy_flags, CYF_SEND_NUL)) { + cd_write_reg(cy, CD1400_TDR, 0); + cd_write_reg(cy, CD1400_TDR, 0); + count += 2; + CLR(cy->cy_flags, CYF_SEND_NUL); + } + if(tp->t_outq.c_cc > 0) { + SET(tp->t_state, TS_BUSY); + while(tp->t_outq.c_cc > 0 && count < CD1400_TX_FIFO_SIZE) { + ch = getc(&tp->t_outq); + /* remember to double NUL characters because + embedded transmit commands are enabled */ + if(ch == 0) { + if(count >= CD1400_TX_FIFO_SIZE-2) { + SET(cy->cy_flags, CYF_SEND_NUL); + break; + } -static void -cd1400_channel_cmd(cy_addr base, u_char cmd) -{ - unsigned maxwait = delaycount * 5; /* approx. 5 ms */ + cd_write_reg(cy, CD1400_TDR, ch); + count++; + } - /* wait for processing of previous command to complete */ - while (*(base + CD1400_CCR) && maxwait--) - ; + cd_write_reg(cy, CD1400_TDR, ch); + count++; + } + } else { + /* no data to send -- check if we should start/stop a break */ + /* XXX does this cause too much delay before breaks? */ + if(ISSET(cy->cy_flags, CYF_START_BREAK)) { + cd_write_reg(cy, CD1400_TDR, 0); + cd_write_reg(cy, CD1400_TDR, 0x81); + CLR(cy->cy_flags, CYF_START_BREAK); + } + if(ISSET(cy->cy_flags, CYF_END_BREAK)) { + cd_write_reg(cy, CD1400_TDR, 0); + cd_write_reg(cy, CD1400_TDR, 0x83); + CLR(cy->cy_flags, CYF_END_BREAK); + } + } - if (!maxwait) - log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n", - delaycount * 5); + if(tp->t_outq.c_cc == 0) { +txdone: + /* + * No data to send or requested to stop. + * Disable transmit interrupt + */ + cd_write_reg(cy, CD1400_SRER, + cd_read_reg(cy, CD1400_SRER) + & ~CD1400_SRER_TXRDY); + CLR(cy->cy_flags, CYF_STOP); + CLR(tp->t_state, TS_BUSY); + } - *(base + CD1400_CCR) = cmd; -} /* end of cd1400_channel_cmd() */ + if(tp->t_outq.c_cc <= tp->t_lowat) { + SET(cy->cy_flags, CYF_START); + cy_events = 1; + } + /* terminate service context */ + cd_write_reg(cy, CD1400_TIR, save_tir & 0x3f); + cd_write_reg(cy, CD1400_CAR, save_car); + int_serviced = 1; + } /* if(tx_service...) */ + } /* for(...all CD1400s on a card) */ + + /* ensure an edge for next interrupt */ + bus_mem_write_1(sc->sc_bc, sc->sc_memh, + CY_CLEAR_INTR<<sc->sc_bustype, 0); + return int_serviced; +} -#ifdef CyDebug -/* useful in ddb */ -void -cyclear(void) +/* + * subroutine to enable CD1400 transmitter + */ +static void +cy_enable_transmitter(cy) + struct cy_port *cy; { - /* clear the timeout request */ disable_intr(); - timeout_scheduled = 0; + cd_write_reg(cy, CD1400_CAR, cy->cy_port_num & CD1400_CAR_CHAN); + cd_write_reg(cy, CD1400_SRER, cd_read_reg(cy, CD1400_SRER) + | CD1400_SRER_TXRDY); enable_intr(); } -void -cyclearintr(void) +/* + * Execute a CD1400 channel command + */ +static void +cd1400_channel_cmd(cy, cmd) + struct cy_port *cy; + int cmd; { - /* clear interrupts */ - *(cyclom_base + CYCLOM_CLEAR_INTR) = (u_char)0; -} + u_int waitcnt = 5 * 8 * 1024; /* approx 5 ms */ -int -cyparam_dummy(struct tty *tp, struct termios *t) -{ - return 0; +#ifdef CY_DEBUG + printf("c1400_channel_cmd cy 0x%x command 0x%x\n", cy, cmd); +#endif + + /* wait until cd1400 is ready to process a new command */ + while(cd_read_reg(cy, CD1400_CCR) != 0 && waitcnt-- > 0) + ; + + if(waitcnt == 0) + log(LOG_ERR, "cy: channel command timeout\n"); + + cd_write_reg(cy, CD1400_CCR, cmd); } -void -cyset(int unit, int active) +/* + * Compute clock option register and baud rate register values + * for a given speed. Return 0 on success, -1 on failure. + * + * The error between requested and actual speed seems + * to be well within allowed limits (less than 3%) + * with every speed value between 50 and 150000 bps. + */ +static int +cy_speed(speed_t speed, int *cor, int *bpr) { - if (unit < 0 || unit > PORTS_PER_CYCLOM) { - printf("bad unit number %d\n", unit); - return; - } - cy_tty[unit]->t_param = active ? cyparam : cyparam_dummy; -} + int c, co, br; + if(speed < 50 || speed > 150000) + return -1; -/* useful in ddb */ -void -cystatus(int unit) -{ - struct cy *infop = info[unit]; - struct tty *tp = infop->tty; - cy_addr base = infop->base_addr; - - printf("info for channel %d\n", unit); - printf("------------------\n"); - - printf("cd1400 base address:\t0x%x\n", (int)infop->base_addr); - - /* select the port */ - *(base + CD1400_CAR) = (u_char)unit; - - printf("saved channel_control:\t%02x\n", infop->channel_control); - printf("saved cor1:\t\t%02x\n", infop->cor[0]); - printf("service request enable reg:\t%02x (%02x cached)\n", - (u_char)*(base + CD1400_SRER), infop->intr_enable); - printf("service request register:\t%02x\n", - (u_char)*(base + CD1400_SVRR)); - printf("\n"); - printf("modem status:\t\t\t%02x (%02x cached)\n", - (u_char)*(base + CD1400_MSVR), infop->modem_sig); - printf("rx/tx/mdm interrupt registers:\t%02x %02x %02x\n", - (u_char)*(base + CD1400_RIR), (u_char)*(base + CD1400_TIR), - (u_char)*(base + CD1400_MIR)); - printf("\n"); - if (tp) { - printf("tty state:\t\t\t%04x\n", tp->t_state); - printf("upper layer queue lengths:\t%d raw, %d canon, %d output\n", - tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc); + for(c = 0, co = 8; co <= 2048; co <<= 2, c++) { + br = (CY_CLOCK + (co * speed) / 2) / (co * speed); + if(br < 0x100) { + *bpr = br; + *cor = c; + return 0; } - else - printf("tty state:\t\t\tclosed\n"); - printf("\n"); - - printf("calls to cystart():\t\t%d (%d useful)\n", - infop->start_count, infop->start_real); - printf("\n"); - printf("total cyclom service probes:\t%d\n", cy_svrr_probes); - printf("calls to upper layer:\t\t%d\n", cy_timeouts); - printf("rx buffer chars free:\t\t%d\n", infop->rx_buf->free); -#ifdef TxBuffer - printf("tx buffer chars used:\t\t%d\n", infop->tx_buf.used); -#endif - printf("received chars:\t\t\t%d good, %d exception\n", - infop->recv_normal, infop->recv_exception); - printf("transmitted chars:\t\t%d\n", infop->xmit); - printf("modem signal deltas:\t\t%d\n", infop->mdm); - printf("\n"); -} /* end of cystatus() */ -#endif + } + + return -1; +} + #endif /* NCY > 0 */ diff --git a/sys/dev/isa/cyreg.h b/sys/dev/isa/cyreg.h new file mode 100644 index 00000000000..e4cfc5f22e4 --- /dev/null +++ b/sys/dev/isa/cyreg.h @@ -0,0 +1,66 @@ +/* $OpenBSD: cyreg.h,v 1.1 1996/06/20 11:39:11 deraadt Exp $ */ +/* $FreeBSD: cyreg.h,v 1.1 1995/07/05 12:15:51 bde Exp $ */ + +/*- + * Copyright (c) 1995 Bruce Evans. + * All rights reserved. + * + * Modified by Timo Rossi, 1996 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Definitions for Cyclades Cyclom-Y serial boards. + */ + +#define CY8_SVCACKR 0x100 +#define CY8_SVCACKT 0x200 +#define CY8_SVCACKM 0x300 + +/* twice this in PCI mode (shifed BUSTYPE bits left) */ +#define CY_CD1400_MEMSPACING 0x400 + +/* adjustment value for accessing the last 4 cd1400s on Cyclom-32 */ +#define CY32_ADDR_FIX 0xe00 + +#define CY16_RESET 0x1400 +#define CY_CLEAR_INTR 0x1800 /* intr ack address */ + +#define CY_MAX_CD1400s 8 /* for Cyclom-32 */ + +/* I/O location for enabling interrupts on PCI Cyclom cards */ +#define CY_PCI_INTENA 0x68 + +#define CY_CLOCK 25000000 /* baud rate clock */ + +/* + * bustype is actually the shift count for the offset + * ISA card addresses are multiplied by 2 (shifted 1 bit) + * and PCI addresses multiplied by 4 (shifted 2 bits) + */ +#define CY_BUSTYPE_ISA 0 +#define CY_BUSTYPE_PCI 1 + diff --git a/sys/dev/isa/files.isa b/sys/dev/isa/files.isa index a143a506f86..23ad6d7cd3d 100644 --- a/sys/dev/isa/files.isa +++ b/sys/dev/isa/files.isa @@ -1,4 +1,4 @@ -# $OpenBSD: files.isa,v 1.20 1996/06/16 10:31:25 deraadt Exp $ +# $OpenBSD: files.isa,v 1.21 1996/06/20 11:39:10 deraadt Exp $ # $NetBSD: files.isa,v 1.21 1996/05/16 03:45:55 mycroft Exp $ # # Config.new file and device description for machine-independent ISA code. @@ -55,9 +55,9 @@ attach com at pcmcia with com_pcmcia file dev/isa/com.c com & (com_isa | com_commulti | com_pcmcia) needs-flag # Cyclades Cyclom multiport serial cards -# XXX currently broken device cy: tty -attach cy at isa +attach cy at isa with cy_isa +attach cy at pci with cy_pci file dev/isa/cy.c cy needs-count # PC parallel ports (XXX what chip?) |