summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-06-20 11:39:13 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-06-20 11:39:13 +0000
commitc4ebf8483d48c223705bc6538c8f09f48fcff6e9 (patch)
tree9994c508f1c7fcf2755b1059360ecac6b0d7a012
parent513b9524458d966c9ae5e2d7c4334978810c790d (diff)
Cyclades Cyclom driver for isa/pci; by Timo Rossi; via jmarin@muikku.jmp.fi
-rw-r--r--sys/dev/ic/cd1400reg.h253
-rw-r--r--sys/dev/isa/cy.c2783
-rw-r--r--sys/dev/isa/cyreg.h66
-rw-r--r--sys/dev/isa/files.isa6
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?)