summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/i386/Makefile5
-rw-r--r--sbin/i386/cxconfig/Makefile4
-rw-r--r--sbin/i386/cxconfig/cxconfig.8297
-rw-r--r--sbin/i386/cxconfig/cxconfig.c704
-rw-r--r--share/man/man4/man4.i386/cx.4239
-rw-r--r--sys/i386/include/cronyx.h475
-rw-r--r--sys/i386/isa/cronyx.c1041
-rw-r--r--sys/i386/isa/cx.c898
-rw-r--r--sys/i386/isa/cxreg.h429
-rw-r--r--sys/i386/isa/if_cx.c818
-rw-r--r--sys/net/if_sppp.h70
-rw-r--r--sys/net/if_spppsubr.c1219
12 files changed, 6199 insertions, 0 deletions
diff --git a/sbin/i386/Makefile b/sbin/i386/Makefile
new file mode 100644
index 0000000..c480c16
--- /dev/null
+++ b/sbin/i386/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBDIR= cxconfig
+
+.include <bsd.subdir.mk>
diff --git a/sbin/i386/cxconfig/Makefile b/sbin/i386/cxconfig/Makefile
new file mode 100644
index 0000000..59c828d
--- /dev/null
+++ b/sbin/i386/cxconfig/Makefile
@@ -0,0 +1,4 @@
+PROG = cxconfig
+MAN8 = cxconfig.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/i386/cxconfig/cxconfig.8 b/sbin/i386/cxconfig/cxconfig.8
new file mode 100644
index 0000000..9907435
--- /dev/null
+++ b/sbin/i386/cxconfig/cxconfig.8
@@ -0,0 +1,297 @@
+.TH Cronyx-Sigma 1
+.rm ES
+.rm EE
+.de ES
+.PP
+.nf
+.in +0.5i
+..
+.de EE
+.in -0.5i
+.fi
+..
+.na
+.SH NAME
+.B cxconfig
+\- channel options management utility for Cronyx-Sigma adapter
+.SH DESCRIPTION
+.PP
+The \fBcxconfig\fP utility is used for configuring the channel options of
+the Cronyx-Sigma adapter.
+.PP
+To change cha options the channel should be free: the corresponding
+network interface in ``down'' state, the asynchronous terminal device /dev/tty*
+closed.
+Generally, the channel options are set up during the operating
+system startup, for example from the \fI/etc/rc\fP file.
+.PP
+Note, that not all options have a sense for every particular
+case, and an attempt to set some of them can hang up the channel or
+the whole adapter.
+.SH "Usage"
+.IP "cxconfig"
+The brief information about all channels.
+.IP "cxconfig -a"
+The full information about all channels.
+.IP "cxconfig <channel>"
+The brief information about the channel.
+.IP "cxconfig -a <channel>"
+The full information about the channel.
+.IP "cxconfig <channel> <option>..."
+Setting the channel options.
+.SH "Channel options"
+.IP ispeed=#
+Set the receiver baud rate to the number given.
+The maximal value is 256000 bits/sec.
+In the synchronous mode the receiver baud rate is significant
+only when DPLL mode is used.
+.IP ospeed=#
+Set the transmitter baud rate to the number given.
+The maximal value is 256000 bits/sec.
+In the synchronous mode the transmitter baud rate is significant
+only in the case of the internal clock source.
+If receiver and transmitter have equal data rate, then it could
+be set by specifying only the numerical argument.
+.IP async
+Set the asynchronous channel mode.
+.IP "hdlc, bisync, bsc, x.21, x21
+Set the synchronous channel mode: HDLC, Bisync (BSC) or X.21.
+.IP ppp
+Set the link-level protocol: PPP/HDLC. The built-in simplified synchronous PPP
+implementation is used (see RFC-1548, RFC-1549).
+.IP cisco
+Set the link-level protocol: Cisco/HDLC (see RFC-1547).
+This protocol is intended for compatibility with old models of Cisco routers,
+and with early versions of BSD/386 drivers.
+The extensive usage of this protocol is not recommended.
+.IP ext
+Use the external link-level protocol suite (for BSD/386 only).
+.IP "+keepalive, -keepalive"
+Enable the automatic line state control sub-protocol.
+This setting is not significant when the external link-level protocol is used.
+.IP "+autorts, -autorts"
+Enable the automatic RTS signal control.
+When enabled, the RTS signal goes up only when both halves of
+the receiver ring buffer are free and ready for receive,
+and goes down when one or both buffers are busy.
+.IP "port=rs232, port=rs449, port=v35
+Set the zero channel hardware interface type.
+.SH "Common options"
+.IP "nrz, nrzi, manchester
+Set the data line signal encoding.
+In the case of \fINRZ\fP encoding the zero bit is transmitted by the zero signal
+level, the one bit - by the positive signal level.
+In the case of \fINRZI\fP encoding the zero bit is transmitted by the change of
+the signal level, the one bit - by the constant signal level.
+In the case of \fIManchester\fP encoding the zero bit is encoded as 01 value,
+the one bit - as 10 value.
+.IP "+dpll, -dpll"
+Enable the digital phase locked loop mode (DPLL).
+When enabled, the receiver timing clock signal
+is derived from the received data.
+.IP "+lloop, -lloop"
+Set the local loopback mode.
+.IP "+extclock, -extclock"
+Set the timing clock source of synchronous channels. There are
+two possible variants: \fIexternal clock\fP source or \fIinternal clock\fP
+generation.
+.br
+\fIExternal clock\fP mode is the most common method for connecting
+external modem hardware. In this mode the external timing
+signal is received on TXCIN pin of the connector, and it is
+used as a synchronization clock for transmitting data (TXD).
+.br
+In the case of \fIinternal clock\fP mode the transmitted data (TXD)
+are synchronized using the internal on-board timing generator,
+the internally generated timing signal is driven on the TXCOUT
+pin, and the signal on the TXCIN pin is ignored. This mode
+is used for direct terminal-to-terminal communication,
+e.g. for connecting two computers together in a synchronous mode
+via relatively short cable. This method should also be used
+for testing channels with an external loopback connector.
+.IP fifo=#
+FIFO threshold level setup for receiver and transmitter.
+.IP rfifo=#
+Hardware RTS/CTS flow control FIFO threshold setup.
+.IP "+ctsup, -ctsup"
+Enable/disable interrupts on CTS (Clear To Send) signal setup (0 to 1 transition).
+.IP "+ctsdown, -ctsdown"
+Enable/disable interrupts on CTS (Clear To Send) signal clear (1 to 0 transition).
+.IP "+cdup, -cdup"
+Enable/disable interrupts on CD (Carrier Detect) signal setup (0 to 1 transition).
+.IP "+cddown, -cddown"
+Enable/disable interrupts on CD (Carrier Detect) signal clear (1 to 0 transition).
+.IP "+dsrup, -dsrup"
+Enable/disable interrupts on DSR (Data Set Ready) signal setup (0 to 1 transition).
+.IP "+dsrdown, -dsrdown"
+Enable/disable interrupts on DSR (Data Set Ready) signal clear (1 to 0 transition).
+.SH "Asynchronous mode options"
+.IP cs#
+Select character size: 5, 6, 7 or 8 bits.
+.IP "parodd, pareven
+Parity mode: odd or even.
+.IP "+ignpar, -ignpar
+Disable/enable parity detection.
+.IP nopar
+Disable parity bit generation.
+.IP forcepar
+Force parity: even - 0, odd - 1.
+.IP "stopb1, stopb1.5, stopb2
+Use 1 or 1.5 or 2 stop bits per character.
+.IP "+dsr, -dsr"
+Use the DSR input signal as receiver enable/disable.
+.IP "+cts, -cts"
+Use the CTS input signal as transmitter enable/disable.
+.IP "+rts, -rts"
+Drive the RTS output signal as transmitter ready.
+.IP "+rloop, -rloop"
+Set the remote loopback mode.
+.IP "+etc, -etc"
+Enable the embedded transmit commands mode.
+.IP "+ixon, -ixon"
+Enable the hardware XON/XOFF flow control support.
+.IP "+ixany, -ixany"
+Use the hardware IXANY mode support.
+.IP "+sdt, -sdt"
+Detect the spec. characters SCHR1 and SCHR2 in the receive data.
+.IP "+flowct, -flowct"
+Receive the flow control spec. characters as data.
+.IP "+rdt, -rdt"
+Detect the spec. characters in range SCRL..SCRH in the receive data.
+.IP "+exdt, -exdt"
+Detect the spec. characters SCHR3 and SCHR4 in the receive data.
+.IP "parintr, parnull, parign, pardisc, parffnull
+Action on parity errors:
+.ES
+ Mode Action
+ -----------------------------------------------------
+ parintr Generate the receiver error interrupt
+ parnull Input the NULL character
+ parign Ignore the error, receive as good data
+ pardisc Ignore the character
+ parffnull Input the sequence <0xFF, NULL, character>
+.EE
+.IP "brkintr, brknull, brkdisc
+Line break state action:
+.ES
+ Mode Action
+ ---------------------------------------------------
+ brkintr Generate the receiver error interrupt
+ brknull Input the NULL character
+ brkdisc Ignore the line break state
+.EE
+.IP "+inlcr, -inlcr"
+Translate received NL characters to CR.
+.IP "+icrnl, -icrnl"
+Translate received CR characters to NL.
+.IP "+igncr, -igncr"
+Ignore received CR characters.
+.IP "+ocrnl, -ocrnl"
+Translate transmitted CR characters to NL.
+.IP "+onlcr, -onlcr"
+Translate transmitted NL characters to CR.
+.IP "+fcerr, -fcerr"
+Process (don't process) the characters, received with errors,
+for special character/flow control matching.
+.IP "+lnext, -lnext"
+Enable the LNEXT character option: the character following
+the LNEXT character is not processed for special character/flow
+control matching.
+.IP "+istrip, -istrip"
+Strip input characters to seven bits.
+.IP schr1=#
+The XON flow control character value.
+.IP schr2=#
+The XOFF flow control character value.
+.IP schr3=#
+The SCHR3 spec. character value.
+.IP schr4=#
+The SCHR4 spec. character value.
+.IP "scrl=#, scrh=#
+The spec. character range (inclusive).
+.IP lnext=#
+The LNEXT spec. character value.
+.SH "HDLC mode options"
+.IP if#
+The minimum number of flags transmitted before a frame is started.
+.IP noaddr
+No frame address recognition.
+.IP "addrlen1, addrlen2"
+Address field length: 1 or 2 bytes.
+.IP "addr1, addr2"
+Addressing mode: 4x1 bytes or 2x2 bytes.
+Registers RFAR1..RFAR4 should contain the address to be matched.
+.IP "+clrdet, -clrdet"
+Enable/disable clear detect for X.21 protocol support.
+.IP "+dsr, -dsr"
+Use the DSR input signal as receiver enable/disable.
+.IP "+cts, -cts"
+Use the CTS input signal as transmitter enable/disable.
+.IP "+rts, -rts"
+Drive the RTS output signal as transmitter ready.
+.IP "+fcs, -fcs"
+Enable/disable the frame checksum generation and checking.
+.IP "crc-16, crc-v.41
+Select the CRC polynomial: CRC-16 (x^16+x^15+x^2+1)
+or CRC V.41 (x^16+x^12+x^5+1).
+.IP "fcs-crc-16, fcs-v.41
+Frame checksum preset: all zeros (CRC-16) or all ones (CRC V.41).
+.IP "+crcinv, -crcinv"
+Invert (ie. CRC V.41) or don't invert (ie. CRC-16) the transmitted frame checksum.
+.IP "+fcsapd, -fcsapd"
+Pass the received CRC to the host at the end of receiver data buffer.
+.IP "idlemark, idleflag
+Idle mode: idle in mark (transmit all ones) or idle in flag (transmit flag).
+.IP "+syn, -syn"
+Enable/disable sending pad characters before sending flag when coming out
+of the idle mode.
+.IP pad#
+The number of synchronous characters sent (0..4).
+.IP "syn=0xaa, syn=0x00
+Send sync pattern.
+.IP "rfar1=#, rfar2=#, rfar3=#, rfar4=#
+Frame address registers for address recognition.
+.SH EXAMPLES
+.PP
+Set up the channel 7 of the adapter Sigma-400 under FreeBSD.
+Physical 4-wire leased line with Zelax+ M115 short-range modems.
+Synchronous mode, 128000 bits/sec, interface RS-232,
+protocol PPP/HDLC without keepalive support, NRZI encoding,
+DPLL mode, no flow control:
+.ES
+cxconfig cx7 128000 hdlc ppp -keepalive nrzi -cts +dpll -extclock
+ifconfig cx7 158.250.244.2 158.250.244.1 up
+.EE
+.PP
+Set up the channel 0 of the adapter Sigma-100 under FreeBSD.
+Attachment to the near computer by short cable, internal clock source.
+Synchronous mode, 256000 bits/sec, interface RS-232,
+protocol Cisco/HDLC with keepalive support:
+.ES
+cxconfig cx0 hdlc 256000 cisco +keepalive -extclock
+ifconfig cx0 200.1.1.1 200.1.1.2 up
+.EE
+.PP
+Set up the channel 1 of the adapter Sigma-840 under BSD/386.
+Synchronous 64 kbit/sec leased line, external clock source.
+Synchronous mode, interface V.35, external protocol suite:
+.ES
+cxconfig cx1 hdlc ext
+ifconfig cx1 193.124.254.50 193.124.254.49 multicast up
+.EE
+.PP
+Set up the channel 0 of the adapter Sigma-840 under FreeBSD.
+Attachment to the Cisco-4000 router by null-modem cable, internal clock source.
+Synchronous mode, 64000 bits/sec, interface RS-232,
+protocol PPP/HDLC with keepalive support and flow control,
+LCP and IPCP protocols (see RFC-1548 and RFC-1332) debug tracing enabled:
+.ES
+cxconfig cx0 hdlc 64000 port=rs232 ppp +keepalive -extclock +cts
+ifconfig cx0 100.0.0.2 100.0.0.1 debug up
+.EE
+.SH FILES
+.IP /dev/cronyx
+The special device file for adapter options management.
+.SH SEE ALSO
+.PP
+cx(4)
diff --git a/sbin/i386/cxconfig/cxconfig.c b/sbin/i386/cxconfig/cxconfig.c
new file mode 100644
index 0000000..0a2391f
--- /dev/null
+++ b/sbin/i386/cxconfig/cxconfig.c
@@ -0,0 +1,704 @@
+/*
+ * Cronyx-Sigma adapter configuration utility for Unix.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.1, Wed Oct 26 16:08:09 MSK 1994
+ *
+ * Usage:
+ * cxconfig [-a]
+ * -- print status of all channels
+ * cxconfig [-a] <channel>
+ * -- print status of the channel
+ * cxconfig <channel> <option>...
+ * -- set channel options
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/cronyx.h>
+#include <net/if.h>
+#include <stdio.h>
+
+#define CXDEV "/dev/cronyx"
+#define atoi(a) strtol((a), (char**)0, 0)
+
+cx_options_t o;
+int aflag;
+
+char *symbol (unsigned char sym)
+{
+ static char buf[40];
+
+ if (sym < ' ')
+ sprintf (buf, "^%c", sym+0100);
+ else if (sym == '\\')
+ strcat (buf, "\\\\");
+ else if (sym < 127)
+ sprintf (buf, "%c", sym);
+ else
+ sprintf (buf, "\\%03o", sym);
+ return (buf);
+}
+
+unsigned char atosym (char *s)
+{
+ unsigned char c;
+
+ if (*s == '^')
+ return (*++s & 037);
+ if (*s == '\\')
+ return (strtol (++s, 0, 8));
+ return (*s);
+}
+
+void usage ()
+{
+ printf ("Cronyx-Sigma Adapter Configuration Utility, Version 1.0\n");
+ printf ("Copyright (C) 1994 Cronyx Ltd.\n");
+ printf ("Usage:\n");
+ printf ("\tcxconfig [-a]\n");
+ printf ("\t\t-- print status of all channels\n");
+ printf ("\tcxconfig [-a] <channel>\n");
+ printf ("\t\t-- print status of the channel\n");
+ printf ("\tcxconfig <channel> [async | hdlc | bisync | x.21] [ispeed #] [ospeed #]\n");
+ printf ("\t\t[+cts | -cts]\n");
+ printf ("\t\t-- set channel options\n");
+ exit (1);
+}
+
+char *chantype (int type)
+{
+ switch (type) {
+ case T_NONE: return ("none");
+ case T_ASYNC: return ("RS-232");
+ case T_UNIV_RS232: return ("RS-232");
+ case T_UNIV_RS449: return ("RS-232/RS-449");
+ case T_UNIV_V35: return ("RS-232/V.35");
+ case T_SYNC_RS232: return ("RS-232");
+ case T_SYNC_V35: return ("V.35");
+ case T_SYNC_RS449: return ("RS-449");
+ }
+}
+
+char *chanmode (int mode)
+{
+ switch (mode) {
+ case M_ASYNC: return ("Async");
+ case M_HDLC: return ("HDLC");
+ case M_BISYNC: return ("Bisync");
+ case M_X21: return ("X.21");
+ default: return ("???");
+ }
+}
+
+void getchan (int channel)
+{
+ int s = open (CXDEV, 0);
+ if (s < 0) {
+ perror (CXDEV);
+ exit (1);
+ }
+ o.board = channel/NCHAN;
+ o.channel = channel%NCHAN;
+ if (ioctl (s, CXIOCGETMODE, (caddr_t)&o) < 0) {
+ perror ("cxconfig: CXIOCGETMODE");
+ exit (1);
+ }
+ close (s);
+ if (o.type == T_NONE) {
+ fprintf (stderr, "cx%d: channel %d not configured\n", o.board,
+ o.channel);
+ exit (1);
+ }
+}
+
+void setchan (int channel)
+{
+ int s = open (CXDEV, 0);
+ if (s < 0) {
+ perror (CXDEV);
+ exit (1);
+ }
+ o.board = channel/NCHAN;
+ o.channel = channel%NCHAN;
+ if (ioctl (s, CXIOCSETMODE, (caddr_t)&o) < 0) {
+ perror ("cxconfig: CXIOCSETMODE");
+ exit (1);
+ }
+ close (s);
+}
+
+void printopt ()
+{
+ /* Common channel options */
+ /* channel option register 4 */
+ printf ("\t");
+ printf ("fifo=%d ", o.opt.cor4.thr); /* FIFO threshold */
+ printf ("%cctsdown ", o.opt.cor4.cts_zd ? '+' : '-'); /* detect 1 to 0 transition on the CTS */
+ printf ("%ccddown ", o.opt.cor4.cd_zd ? '+' : '-'); /* detect 1 to 0 transition on the CD */
+ printf ("%cdsrdown ", o.opt.cor4.dsr_zd ? '+' : '-'); /* detect 1 to 0 transition on the DSR */
+ printf ("\n");
+
+ /* channel option register 5 */
+ printf ("\t");
+ printf ("rfifo=%d ", o.opt.cor5.rx_thr); /* receive flow control FIFO threshold */
+ printf ("%cctsup ", o.opt.cor5.cts_od ? '+' : '-'); /* detect 0 to 1 transition on the CTS */
+ printf ("%ccdup ", o.opt.cor5.cd_od ? '+' : '-'); /* detect 0 to 1 transition on the CD */
+ printf ("%cdsrup ", o.opt.cor5.dsr_od ? '+' : '-'); /* detect 0 to 1 transition on the DSR */
+ printf ("\n");
+
+ /* receive clock option register */
+ printf ("\t");
+ printf ("%s ", o.opt.rcor.encod == ENCOD_NRZ ? "nrz" : /* signal encoding */
+ o.opt.rcor.encod == ENCOD_NRZI ? "nrzi" :
+ o.opt.rcor.encod == ENCOD_MANCHESTER ? "manchester" : "???");
+ printf ("%cdpll ", o.opt.rcor.dpll ? '+' : '-'); /* DPLL enable */
+
+ /* transmit clock option register */
+ printf ("%clloop ", o.opt.tcor.llm ? '+' : '-'); /* local loopback mode */
+ printf ("%cextclock ", o.opt.tcor.ext1x ? '+' : '-'); /* external 1x clock mode */
+ printf ("\n");
+
+ switch (o.mode) {
+ case M_ASYNC: /* async mode options */
+ /* channel option register 1 */
+ printf ("\t");
+ printf ("cs%d ", o.aopt.cor1.charlen+1); /* character length, 5..8 */
+ printf ("par%s ", o.aopt.cor1.parity ? "odd" : "even"); /* parity */
+ printf ("%cignpar ", o.aopt.cor1.ignpar ? '+' : '-'); /* ignore parity */
+ if (o.aopt.cor1.parmode != PARM_NORMAL) /* parity mode */
+ printf ("%s ", o.aopt.cor1.parmode == PARM_NOPAR ? "nopar" :
+ o.aopt.cor1.parmode == PARM_FORCE ? "forcepar" : "???");
+ printf ("\n");
+
+ /* channel option register 2 */
+ printf ("\t");
+ printf ("%cdsr ", o.aopt.cor2.dsrae ? '+' : '-'); /* DSR automatic enable */
+ printf ("%ccts ", o.aopt.cor2.ctsae ? '+' : '-'); /* CTS automatic enable */
+ printf ("%crts ", o.aopt.cor2.rtsao ? '+' : '-'); /* RTS automatic output enable */
+ printf ("%crloop ", o.aopt.cor2.rlm ? '+' : '-'); /* remote loopback mode enable */
+ printf ("%cetc ", o.aopt.cor2.etc ? '+' : '-'); /* embedded transmitter cmd enable */
+ printf ("%cxon ", o.aopt.cor2.ixon ? '+' : '-'); /* in-band XON/XOFF enable */
+ printf ("%cxany ", o.aopt.cor2.ixany ? '+' : '-'); /* XON on any character */
+ printf ("\n");
+
+ /* option register 3 */
+ printf ("\t");
+ printf ("%s ", o.aopt.cor3.stopb == STOPB_1 ? "stopb1" : /* stop bit length */
+ o.aopt.cor3.stopb == STOPB_15 ? "stopb1.5" :
+ o.aopt.cor3.stopb == STOPB_2 ? "stopb2" : "???");
+ printf ("%csdt ", o.aopt.cor3.scde ? '+' : '-'); /* special char detection enable */
+ printf ("%cflowct ", o.aopt.cor3.flowct ? '+' : '-'); /* flow control transparency mode */
+ printf ("%crdt ", o.aopt.cor3.rngde ? '+' : '-'); /* range detect enable */
+ printf ("%cexdt ", o.aopt.cor3.escde ? '+' : '-'); /* extended spec. char detect enable */
+ printf ("\n");
+
+ /* channel option register 6 */
+ printf ("\t");
+ printf ("%s ", o.aopt.cor6.parerr == PERR_INTR ? "parintr" : /* parity/framing error actions */
+ o.aopt.cor6.parerr == PERR_NULL ? "parnull" :
+ o.aopt.cor6.parerr == PERR_IGNORE ? "parign" :
+ o.aopt.cor6.parerr == PERR_DISCARD ? "pardisc" :
+ o.aopt.cor6.parerr == PERR_FFNULL ? "parffnull" : "???");
+ printf ("%s ", o.aopt.cor6.brk == BRK_INTR ? "brkintr" : /* action on break condition */
+ o.aopt.cor6.brk == BRK_NULL ? "brknull" :
+ o.aopt.cor6.brk == BRK_DISCARD ? "brkdisc" : "???");
+ printf ("%cinlcr ", o.aopt.cor6.inlcr ? '+' : '-'); /* translate NL to CR on input */
+ printf ("%cicrnl ", o.aopt.cor6.icrnl ? '+' : '-'); /* translate CR to NL on input */
+ printf ("%cigncr ", o.aopt.cor6.igncr ? '+' : '-'); /* discard CR on input */
+ printf ("\n");
+
+ /* channel option register 7 */
+ printf ("\t");
+ printf ("%cocrnl ", o.aopt.cor7.ocrnl ? '+' : '-'); /* translate CR to NL on output */
+ printf ("%conlcr ", o.aopt.cor7.onlcr ? '+' : '-'); /* translate NL to CR on output */
+ printf ("%cfcerr ", o.aopt.cor7.fcerr ? '+' : '-'); /* process flow ctl err chars enable */
+ printf ("%clnext ", o.aopt.cor7.lnext ? '+' : '-'); /* LNext option enable */
+ printf ("%cistrip ", o.aopt.cor7.istrip ? '+' : '-'); /* strip 8-bit on input */
+ printf ("\n");
+
+ printf ("\t");
+ printf ("schr1=%s ", symbol (o.aopt.schr1)); /* special character register 1 (XON) */
+ printf ("schr2=%s ", symbol (o.aopt.schr2)); /* special character register 2 (XOFF) */
+ printf ("schr3=%s ", symbol (o.aopt.schr3)); /* special character register 3 */
+ printf ("schr4=%s ", symbol (o.aopt.schr4)); /* special character register 4 */
+ printf ("scrl=%s ", symbol (o.aopt.scrl)); /* special character range low */
+ printf ("scrh=%s ", symbol (o.aopt.scrh)); /* special character range high */
+ printf ("lnext=%s ", symbol (o.aopt.lnxt)); /* LNext character */
+ printf ("\n");
+ break;
+
+ case M_HDLC: /* hdlc mode options */
+ /* hdlc channel option register 1 */
+ printf ("\t");
+ printf ("if%d ", o.hopt.cor1.ifflags); /* number of inter-frame flags sent */
+ printf ("%s ", o.hopt.cor1.admode == ADMODE_NOADDR ? "noaddr" : /* addressing mode */
+ o.hopt.cor1.admode == ADMODE_4_1 ? "addr1" :
+ o.hopt.cor1.admode == ADMODE_2_2 ? "addr2" : "???");
+ printf ("%cclrdet ", o.hopt.cor1.clrdet ? '+' : '-'); /* clear detect for X.21 data transfer phase */
+ printf ("addrlen%d ", o.hopt.cor1.aflo + 1); /* address field length option */
+ printf ("\n");
+
+ /* hdlc channel option register 2 */
+ printf ("\t");
+ printf ("%cdsr ", o.hopt.cor2.dsrae ? '+' : '-'); /* DSR automatic enable */
+ printf ("%ccts ", o.hopt.cor2.ctsae ? '+' : '-'); /* CTS automatic enable */
+ printf ("%crts ", o.hopt.cor2.rtsao ? '+' : '-'); /* RTS automatic output enable */
+ printf ("%ccrcinv ", o.hopt.cor2.crcninv ? '-' : '+'); /* CRC invertion option */
+ printf ("%cfcsapd ", o.hopt.cor2.fcsapd ? '+' : '-'); /* FCS append */
+ printf ("\n");
+
+ /* hdlc channel option register 3 */
+ printf ("\t");
+ printf ("pad%d ", o.hopt.cor3.padcnt); /* pad character count */
+ printf ("idle%s ", o.hopt.cor3.idle ? "mark" : "flag"); /* idle mode */
+ printf ("%cfcs ", o.hopt.cor3.nofcs ? '-' : '+'); /* FCS disable */
+ printf ("fcs-%s ", o.hopt.cor3.fcspre ? "crc-16" : "v.41"); /* FCS preset */
+ printf ("syn=%s ", o.hopt.cor3.syncpat ? "0xAA" : "0x00"); /* send sync pattern */
+ printf ("%csyn ", o.hopt.cor3.sndpad ? '+' : '-'); /* send pad characters before flag enable */
+ printf ("\n");
+
+ printf ("\t");
+ printf ("rfar1=0x%02x ", o.hopt.rfar1); /* receive frame address register 1 */
+ printf ("rfar2=0x%02x ", o.hopt.rfar2); /* receive frame address register 2 */
+ printf ("rfar3=0x%02x ", o.hopt.rfar3); /* receive frame address register 3 */
+ printf ("rfar4=0x%02x ", o.hopt.rfar4); /* receive frame address register 4 */
+ printf ("crc-%s ", o.hopt.cpsr ? "16" : "v.41"); /* CRC polynomial select */
+ printf ("\n");
+ break;
+
+ case M_BISYNC: /* bisync mode options */
+ /* channel option register 1 */
+ printf ("\t");
+ printf ("cs%d ", o.bopt.cor1.charlen+1); /* character length, 5..8 */
+ printf ("par%s ", o.bopt.cor1.parity ? "odd" : "even"); /* parity */
+ printf ("%cignpar ", o.bopt.cor1.ignpar ? '+' : '-'); /* ignore parity */
+ if (o.bopt.cor1.parmode != PARM_NORMAL) /* parity mode */
+ printf ("%s ", o.bopt.cor1.parmode == PARM_NOPAR ? "nopar" :
+ o.bopt.cor1.parmode == PARM_FORCE ? "forcepar" : "???");
+ printf ("\n");
+
+ /* channel option register 2 */
+ printf ("\t");
+ printf ("syn%d ", o.bopt.cor2.syns+2); /* number of extra SYN chars before a frame */
+ printf ("%ccrcinv ", o.bopt.cor2.crcninv ? '-' : '+'); /* CRC invertion option */
+ printf ("%s ", o.bopt.cor2.ebcdic ? "ebcdic" : "ascii"); /* use EBCDIC as char set (instead of ASCII) */
+ printf ("%cbccapd ", o.bopt.cor2.bcc ? '+' : '-'); /* BCC append enable */
+ printf ("%s ", o.bopt.cor2.lrc ? "lrc" : "crc-16"); /* longitudinal redundancy check */
+ printf ("\n");
+
+ /* channel option register 3 */
+ printf ("\t");
+ printf ("pad%d ", o.bopt.cor3.padcnt); /* pad character count */
+ printf ("idle%s ", o.bopt.cor3.idle ? "mark" : "syn"); /* idle mode */
+ printf ("%cfcs ", o.bopt.cor3.nofcs ? '-' : '+'); /* FCS disable */
+ printf ("fcs-%s ", o.bopt.cor3.fcspre ? "crc-16" : "v.41"); /* FCS preset */
+ printf ("syn=%s ", o.bopt.cor3.padpat ? "0x55" : "0xAA"); /* send sync pattern */
+ printf ("%csyn ", o.bopt.cor3.sndpad ? '+' : '-'); /* send pad characters before flag enable */
+ printf ("\n");
+
+ /* channel option register 6 */
+ printf ("\t");
+ printf ("specterm=%s ", symbol (o.bopt.cor6.specterm)); /* special termination character */
+
+ printf ("crc-%s ", o.bopt.cpsr ? "16" : "v.41"); /* CRC polynomial select */
+ printf ("\n");
+ break;
+
+ case M_X21: /* x.21 mode options */
+ /* channel option register 1 */
+ printf ("\t");
+ printf ("cs%d ", o.xopt.cor1.charlen+1); /* character length, 5..8 */
+ printf ("par%s ", o.xopt.cor1.parity ? "odd" : "even"); /* parity */
+ printf ("%cignpar ", o.xopt.cor1.ignpar ? '+' : '-'); /* ignore parity */
+ if (o.xopt.cor1.parmode != PARM_NORMAL) /* parity mode */
+ printf ("%s ", o.xopt.cor1.parmode == PARM_NOPAR ? "nopar" :
+ o.xopt.cor1.parmode == PARM_FORCE ? "forcepar" : "???");
+ printf ("\n");
+
+ /* channel option register 2 */
+ printf ("\t");
+ printf ("%cetc ", o.xopt.cor2.etc ? '+' : '-'); /* embedded transmitter cmd enable */
+
+ /* channel option register 3 */
+ printf ("%csdt ", o.xopt.cor3.scde ? '+' : '-'); /* special char detection enable */
+ printf ("%cstripsyn ", o.xopt.cor3.stripsyn ? '+' : '-'); /* treat SYN chars as special condition */
+ printf ("%cssdt ", o.xopt.cor3.ssde ? '+' : '-'); /* steady state detect enable */
+ printf ("syn%c ", o.xopt.cor3.syn ? '1' : '2'); /* the number of SYN chars on receive */
+ printf ("\n");
+
+ /* channel option register 6 */
+ printf ("\t");
+ printf ("syn=%s ", symbol (o.xopt.cor6.synchar)); /* syn character */
+
+ printf ("schr1=%s ", symbol (o.xopt.schr1)); /* special character register 1 */
+ printf ("schr2=%s ", symbol (o.xopt.schr2)); /* special character register 2 */
+ printf ("schr3=%s ", symbol (o.xopt.schr3)); /* special character register 3 */
+ printf ("\n");
+ break;
+ }
+}
+
+void printchan (int channel)
+{
+ printf ("cx%d (%s) %s", channel, chantype (o.type), chanmode (o.mode));
+ if (o.txbaud == o.rxbaud)
+ printf (" %d", o.rxbaud);
+ else
+ printf (" ospeed=%d ispeed=%d", o.txbaud, o.rxbaud);
+ if ((o.channel == 0 || o.channel == 8) &&
+ (o.type == T_UNIV_V35 || o.type == T_UNIV_RS449))
+ printf (" port=%s", o.iftype ? (o.type == T_UNIV_V35 ?
+ "v35" : "rs449") : "rs232");
+ printf (o.sopt.ext ? " ext" : o.sopt.cisco ? " cisco" : " ppp");
+ printf (" %ckeepalive", o.sopt.keepalive ? '+' : '-');
+ printf (" %cautorts", o.sopt.norts ? '-' : '+');
+ printf ("\n");
+ if (aflag)
+ printopt ();
+}
+
+void printall ()
+{
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ char buf[BUFSIZ], *cp;
+ int s, c;
+
+ s = socket (AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror ("cxconfig: socket");
+ exit (1);
+ }
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (s, SIOCGIFCONF, (caddr_t)&ifc) < 0) {
+ perror ("cxconfig: SIOCGIFCONF");
+ exit (1);
+ }
+ close (s);
+ s = open (CXDEV, 0);
+ if (s < 0) {
+ perror (CXDEV);
+ exit (1);
+ }
+
+ ifr = ifc.ifc_req;
+#define max(a,b) ((a)>(b) ? (a) : (b))
+#define size(p) max((p).sa_len, sizeof(p))
+ for (cp=buf; cp<buf+ifc.ifc_len; cp+=sizeof(ifr->ifr_name)+size(ifr->ifr_addr)) {
+ ifr = (struct ifreq*) cp;
+ if (ifr->ifr_addr.sa_family != AF_LINK)
+ continue;
+ if (strncmp (ifr->ifr_name, "cx", 2) != 0)
+ continue;
+ c = atoi (ifr->ifr_name + 2);
+ o.board = c/NCHAN;
+ o.channel = c%NCHAN;
+ if (ioctl (s, CXIOCGETMODE, (caddr_t)&o) < 0) {
+ perror ("cxconfig: CXIOCGETMODE");
+ exit (1);
+ }
+ printchan (c);
+ }
+ close (s);
+}
+
+void set_interface_type (char *type)
+{
+ if (o.channel != 0 && o.channel != 8) {
+ printf ("interface option is applicable only for channels 0 and 8\n");
+ exit (1);
+ }
+ if (o.type != T_UNIV_V35 && o.type != T_UNIV_RS449) {
+ printf ("interface option is applicable only for universal channels\n");
+ exit (1);
+ }
+ if (! strcasecmp (type, "port=rs232"))
+ o.iftype = 0;
+ else
+ o.iftype = 1;
+}
+
+void set_async_opt (char *opt)
+{
+ /* channel option register 1 */
+ if (! strncasecmp (opt, "cs", 2)) o.aopt.cor1.charlen = atoi (opt + 2) - 1;
+ else if (! strcasecmp (opt, "parodd")) o.aopt.cor1.parity = 1;
+ else if (! strcasecmp (opt, "pareven")) o.aopt.cor1.parity = 0;
+ else if (! strcasecmp (opt, "-ignpar")) o.aopt.cor1.ignpar = 0;
+ else if (! strcasecmp (opt, "+ignpar")) o.aopt.cor1.ignpar = 1;
+ else if (! strcasecmp (opt, "nopar")) o.aopt.cor1.parmode = PARM_NOPAR;
+ else if (! strcasecmp (opt, "forcepar")) o.aopt.cor1.parmode = PARM_FORCE;
+
+ /* channel option register 2 */
+ else if (! strcasecmp (opt, "-dsr")) o.aopt.cor2.dsrae = 0;
+ else if (! strcasecmp (opt, "+dsr")) o.aopt.cor2.dsrae = 1;
+ else if (! strcasecmp (opt, "-cts")) o.aopt.cor2.ctsae = 0;
+ else if (! strcasecmp (opt, "+cts")) o.aopt.cor2.ctsae = 1;
+ else if (! strcasecmp (opt, "-rts")) o.aopt.cor2.rtsao = 0;
+ else if (! strcasecmp (opt, "+rts")) o.aopt.cor2.rtsao = 1;
+ else if (! strcasecmp (opt, "-rloop")) o.aopt.cor2.rlm = 0;
+ else if (! strcasecmp (opt, "+rloop")) o.aopt.cor2.rlm = 1;
+ else if (! strcasecmp (opt, "-etc")) o.aopt.cor2.etc = 0;
+ else if (! strcasecmp (opt, "+etc")) o.aopt.cor2.etc = 1;
+ else if (! strcasecmp (opt, "-ixon")) o.aopt.cor2.ixon = 0;
+ else if (! strcasecmp (opt, "+ixon")) o.aopt.cor2.ixon = 1;
+ else if (! strcasecmp (opt, "-ixany")) o.aopt.cor2.ixany = 0;
+ else if (! strcasecmp (opt, "+ixany")) o.aopt.cor2.ixany = 1;
+
+ /* option register 3 */
+ else if (! strcasecmp (opt, "stopb1")) o.aopt.cor3.stopb = STOPB_1;
+ else if (! strcasecmp (opt, "stopb1.5")) o.aopt.cor3.stopb = STOPB_15;
+ else if (! strcasecmp (opt, "stopb2")) o.aopt.cor3.stopb = STOPB_2;
+ else if (! strcasecmp (opt, "-sdt")) o.aopt.cor3.scde = 0;
+ else if (! strcasecmp (opt, "+sdt")) o.aopt.cor3.scde = 1;
+ else if (! strcasecmp (opt, "-flowct")) o.aopt.cor3.flowct = 0;
+ else if (! strcasecmp (opt, "+flowct")) o.aopt.cor3.flowct = 1;
+ else if (! strcasecmp (opt, "-rdt")) o.aopt.cor3.rngde = 0;
+ else if (! strcasecmp (opt, "+rdt")) o.aopt.cor3.rngde = 1;
+ else if (! strcasecmp (opt, "-exdt")) o.aopt.cor3.escde = 0;
+ else if (! strcasecmp (opt, "+exdt")) o.aopt.cor3.escde = 1;
+
+ /* channel option register 6 */
+ else if (! strcasecmp (opt, "parintr")) o.aopt.cor6.parerr = PERR_INTR;
+ else if (! strcasecmp (opt, "parnull")) o.aopt.cor6.parerr = PERR_NULL;
+ else if (! strcasecmp (opt, "parign")) o.aopt.cor6.parerr = PERR_IGNORE;
+ else if (! strcasecmp (opt, "pardisc")) o.aopt.cor6.parerr = PERR_DISCARD;
+ else if (! strcasecmp (opt, "parffnull")) o.aopt.cor6.parerr = PERR_FFNULL;
+ else if (! strcasecmp (opt, "brkintr")) o.aopt.cor6.brk = BRK_INTR;
+ else if (! strcasecmp (opt, "brknull")) o.aopt.cor6.brk = BRK_NULL;
+ else if (! strcasecmp (opt, "brkdisc")) o.aopt.cor6.brk = BRK_DISCARD;
+ else if (! strcasecmp (opt, "-inlcr")) o.aopt.cor6.inlcr = 0;
+ else if (! strcasecmp (opt, "+inlcr")) o.aopt.cor6.inlcr = 1;
+ else if (! strcasecmp (opt, "-icrnl")) o.aopt.cor6.icrnl = 0;
+ else if (! strcasecmp (opt, "+icrnl")) o.aopt.cor6.icrnl = 1;
+ else if (! strcasecmp (opt, "-igncr")) o.aopt.cor6.igncr = 0;
+ else if (! strcasecmp (opt, "+igncr")) o.aopt.cor6.igncr = 1;
+
+ /* channel option register 7 */
+ else if (! strcasecmp (opt, "-ocrnl")) o.aopt.cor7.ocrnl = 0;
+ else if (! strcasecmp (opt, "+ocrnl")) o.aopt.cor7.ocrnl = 1;
+ else if (! strcasecmp (opt, "-onlcr")) o.aopt.cor7.onlcr = 0;
+ else if (! strcasecmp (opt, "+onlcr")) o.aopt.cor7.onlcr = 1;
+ else if (! strcasecmp (opt, "-fcerr")) o.aopt.cor7.fcerr = 0;
+ else if (! strcasecmp (opt, "+fcerr")) o.aopt.cor7.fcerr = 1;
+ else if (! strcasecmp (opt, "-lnext")) o.aopt.cor7.lnext = 0;
+ else if (! strcasecmp (opt, "+lnext")) o.aopt.cor7.lnext = 1;
+ else if (! strcasecmp (opt, "-istrip")) o.aopt.cor7.istrip = 0;
+ else if (! strcasecmp (opt, "+istrip")) o.aopt.cor7.istrip = 1;
+
+ else if (! strncasecmp (opt, "schr1=", 6)) o.aopt.schr1 = atosym (opt+6);
+ else if (! strncasecmp (opt, "schr2=", 6)) o.aopt.schr2 = atosym (opt+6);
+ else if (! strncasecmp (opt, "schr3=", 6)) o.aopt.schr3 = atosym (opt+6);
+ else if (! strncasecmp (opt, "schr4=", 6)) o.aopt.schr4 = atosym (opt+6);
+ else if (! strncasecmp (opt, "scrl=", 5)) o.aopt.scrl = atosym (opt+5);
+ else if (! strncasecmp (opt, "scrh=", 5)) o.aopt.scrh = atosym (opt+5);
+ else if (! strncasecmp (opt, "lnext=", 6)) o.aopt.lnxt = atosym (opt+6);
+ else
+ usage ();
+}
+
+void set_hdlc_opt (char *opt)
+{
+ /* hdlc channel option register 1 */
+ if (! strncasecmp (opt, "if", 2)) o.hopt.cor1.ifflags = atoi (opt + 2);
+ else if (! strcasecmp (opt, "noaddr")) o.hopt.cor1.admode = ADMODE_NOADDR;
+ else if (! strcasecmp (opt, "addr1")) o.hopt.cor1.admode = ADMODE_4_1;
+ else if (! strcasecmp (opt, "addr2")) o.hopt.cor1.admode = ADMODE_2_2;
+ else if (! strcasecmp (opt, "-clrdet")) o.hopt.cor1.clrdet = 0;
+ else if (! strcasecmp (opt, "+clrdet")) o.hopt.cor1.clrdet = 1;
+ else if (! strcasecmp (opt, "addrlen1")) o.hopt.cor1.aflo = 0;
+ else if (! strcasecmp (opt, "addrlen2")) o.hopt.cor1.aflo = 1;
+
+ /* hdlc channel option register 2 */
+ else if (! strcasecmp (opt, "-dsr")) o.hopt.cor2.dsrae = 0;
+ else if (! strcasecmp (opt, "+dsr")) o.hopt.cor2.dsrae = 1;
+ else if (! strcasecmp (opt, "-cts")) o.hopt.cor2.ctsae = 0;
+ else if (! strcasecmp (opt, "+cts")) o.hopt.cor2.ctsae = 1;
+ else if (! strcasecmp (opt, "-rts")) o.hopt.cor2.rtsao = 0;
+ else if (! strcasecmp (opt, "+rts")) o.hopt.cor2.rtsao = 1;
+ else if (! strcasecmp (opt, "-fcsapd")) o.hopt.cor2.fcsapd = 0;
+ else if (! strcasecmp (opt, "+fcsapd")) o.hopt.cor2.fcsapd = 1;
+ else if (! strcasecmp (opt, "-crcinv")) o.hopt.cor2.crcninv = 1;
+ else if (! strcasecmp (opt, "+crcinv")) o.hopt.cor2.crcninv = 0;
+
+ /* hdlc channel option register 3 */
+ else if (! strncasecmp (opt, "pad", 3)) o.hopt.cor3.padcnt = atoi (opt + 3);
+ else if (! strcasecmp (opt, "idlemark")) o.hopt.cor3.idle = 1;
+ else if (! strcasecmp (opt, "idleflag")) o.hopt.cor3.idle = 0;
+ else if (! strcasecmp (opt, "-fcs")) o.hopt.cor3.nofcs = 1;
+ else if (! strcasecmp (opt, "+fcs")) o.hopt.cor3.nofcs = 0;
+ else if (! strcasecmp (opt, "fcs-crc-16")) o.hopt.cor3.fcspre = 1;
+ else if (! strcasecmp (opt, "fcs-v.41")) o.hopt.cor3.fcspre = 0;
+ else if (! strcasecmp (opt, "syn=0xaa")) o.hopt.cor3.syncpat = 1;
+ else if (! strcasecmp (opt, "syn=0x00")) o.hopt.cor3.syncpat = 0;
+ else if (! strcasecmp (opt, "-syn")) o.hopt.cor3.sndpad = 0;
+ else if (! strcasecmp (opt, "+syn")) o.hopt.cor3.sndpad = 1;
+
+ else if (! strncasecmp (opt, "rfar1=", 6)) o.hopt.rfar1 = atoi (opt + 6);
+ else if (! strncasecmp (opt, "rfar2=", 6)) o.hopt.rfar2 = atoi (opt + 6);
+ else if (! strncasecmp (opt, "rfar3=", 6)) o.hopt.rfar3 = atoi (opt + 6);
+ else if (! strncasecmp (opt, "rfar4=", 6)) o.hopt.rfar4 = atoi (opt + 6);
+ else if (! strcasecmp (opt, "crc-16")) o.hopt.cpsr = 1;
+ else if (! strcasecmp (opt, "crc-v.41")) o.hopt.cpsr = 0;
+ else usage ();
+}
+
+void set_bisync_opt (char *opt)
+{
+ usage ();
+}
+
+void set_x21_opt (char *opt)
+{
+ usage ();
+}
+
+int main (int argc, char **argv)
+{
+ int channel;
+
+ for (--argc, ++argv; argc>0 && **argv=='-'; --argc, ++argv)
+ if (! strcasecmp (*argv, "-a"))
+ ++aflag;
+ else
+ usage ();
+
+ if (argc <= 0) {
+ printall ();
+ return (0);
+ }
+
+ if (argv[0][0]=='c' && argv[0][1]=='x')
+ *argv += 2;
+ if (**argv<'0' || **argv>'9')
+ usage ();
+ channel = atoi (*argv);
+ --argc, ++argv;
+ getchan (channel);
+
+ if (argc <= 0) {
+ printchan (channel);
+ return (0);
+ }
+
+ for (; argc>0; --argc, ++argv)
+ if (**argv == '(')
+ continue;
+ else if (! strncasecmp (*argv, "ispeed=", 7))
+ o.rxbaud = atoi (*argv+7);
+ else if (! strncasecmp (*argv, "ospeed=", 7))
+ o.txbaud = atoi (*argv+7);
+ else if (! strcasecmp (*argv, "async"))
+ o.mode = M_ASYNC;
+ else if (! strcasecmp (*argv, "hdlc"))
+ o.mode = M_HDLC;
+ else if (! strcasecmp (*argv, "bisync") ||
+ ! strcasecmp (*argv, "bsc"))
+ o.mode = M_BISYNC;
+ else if (! strcasecmp (*argv, "x.21") ||
+ ! strcasecmp (*argv, "x21"))
+ o.mode = M_X21;
+ else if (**argv>='0' && **argv<='9')
+ o.txbaud = o.rxbaud = atoi (*argv);
+ else if (! strcasecmp (*argv, "cisco")) {
+ o.sopt.cisco = 1;
+ o.sopt.ext = 0;
+ } else if (! strcasecmp (*argv, "ppp")) {
+ o.sopt.cisco = 0;
+ o.sopt.ext = 0;
+ } else if (! strcasecmp (*argv, "ext"))
+ o.sopt.ext = 1;
+ else if (! strcasecmp (*argv, "+keepalive"))
+ o.sopt.keepalive = 1;
+ else if (! strcasecmp (*argv, "-keepalive"))
+ o.sopt.keepalive = 0;
+ else if (! strcasecmp (*argv, "+autorts"))
+ o.sopt.norts = 0;
+ else if (! strcasecmp (*argv, "-autorts"))
+ o.sopt.norts = 1;
+ else if (! strcasecmp (*argv, "port=rs232") ||
+ ! strcasecmp (*argv, "port=rs449") ||
+ ! strcasecmp (*argv, "port=v35"))
+ set_interface_type (*argv);
+
+ /*
+ * Common channel options
+ */
+ /* channel option register 4 */
+ else if (! strcasecmp (*argv, "-ctsdown"))
+ o.opt.cor4.cts_zd = 0;
+ else if (! strcasecmp (*argv, "+ctsdown"))
+ o.opt.cor4.cts_zd = 1;
+ else if (! strcasecmp (*argv, "-cddown"))
+ o.opt.cor4.cd_zd = 0;
+ else if (! strcasecmp (*argv, "+cddown"))
+ o.opt.cor4.cd_zd = 1;
+ else if (! strcasecmp (*argv, "-dsrdown"))
+ o.opt.cor4.dsr_zd = 0;
+ else if (! strcasecmp (*argv, "+dsrdown"))
+ o.opt.cor4.dsr_zd = 1;
+ else if (! strncasecmp (*argv, "fifo=", 5))
+ o.opt.cor4.thr = atoi (*argv + 5);
+
+ /* channel option register 5 */
+ else if (! strcasecmp (*argv, "-ctsup"))
+ o.opt.cor5.cts_od = 0;
+ else if (! strcasecmp (*argv, "+ctsup"))
+ o.opt.cor5.cts_od = 1;
+ else if (! strcasecmp (*argv, "-cdup"))
+ o.opt.cor5.cd_od = 0;
+ else if (! strcasecmp (*argv, "+cdup"))
+ o.opt.cor5.cd_od = 1;
+ else if (! strcasecmp (*argv, "-dsrup"))
+ o.opt.cor5.dsr_od = 0;
+ else if (! strcasecmp (*argv, "+dsrup"))
+ o.opt.cor5.dsr_od = 1;
+ else if (! strncasecmp (*argv, "rfifo=", 6))
+ o.opt.cor5.rx_thr = atoi (*argv + 6);
+
+ /* receive clock option register */
+ else if (! strcasecmp (*argv, "nrz"))
+ o.opt.rcor.encod = ENCOD_NRZ;
+ else if (! strcasecmp (*argv, "nrzi"))
+ o.opt.rcor.encod = ENCOD_NRZI;
+ else if (! strcasecmp (*argv, "manchester"))
+ o.opt.rcor.encod = ENCOD_MANCHESTER;
+ else if (! strcasecmp (*argv, "-dpll"))
+ o.opt.rcor.dpll = 0;
+ else if (! strcasecmp (*argv, "+dpll"))
+ o.opt.rcor.dpll = 1;
+
+ /* transmit clock option register */
+ else if (! strcasecmp (*argv, "-lloop"))
+ o.opt.tcor.llm = 0;
+ else if (! strcasecmp (*argv, "+lloop"))
+ o.opt.tcor.llm = 1;
+ else if (! strcasecmp (*argv, "-extclock"))
+ o.opt.tcor.ext1x = 0;
+ else if (! strcasecmp (*argv, "+extclock"))
+ o.opt.tcor.ext1x = 1;
+
+ /*
+ * Mode dependent channel options
+ */
+ else switch (o.mode) {
+ case M_ASYNC: set_async_opt (*argv); break;
+ case M_HDLC: set_hdlc_opt (*argv); break;
+ case M_BISYNC: set_bisync_opt (*argv); break;
+ case M_X21: set_x21_opt (*argv); break;
+ }
+
+ setchan (channel);
+ return (0);
+}
diff --git a/share/man/man4/man4.i386/cx.4 b/share/man/man4/man4.i386/cx.4
new file mode 100644
index 0000000..969b735
--- /dev/null
+++ b/share/man/man4/man4.i386/cx.4
@@ -0,0 +1,239 @@
+.TH Cronyx-Sigma 1
+.rm ES
+.rm EE
+.de ES
+.PP
+.nf
+.in +0.5i
+..
+.de EE
+.in -0.5i
+.fi
+..
+.na
+.SH NAME
+.B cx
+\- asynchronous Cronyx-Sigma adapter driver
+.br
+.B if_cx
+\- synchronous Cronyx-Sigma adapter driver
+.SH CONFIGURATION
+.B
+device cx0 at isa? port 0x240 irq 15 drq 7
+.br
+.B
+device cx1 at isa? port 0x260 irq 12 drq 6
+.br
+.B
+pseudo-device sppp
+.P
+The base i/o port address should be set by jumpers on the board.
+The DMA i/o channel and interrupt request numbers are configured
+by software at adapter initialization. Legal values are:
+.IP Port
+0x240, 0x260, 0x280, 0x300, 0x320, 0x380
+.IP IRQ
+3, 5, 7, 10, 11, 12, 15
+.IP DMA
+5, 6, 7
+.SH DESCRIPTION
+.PP
+The Cronyx-Sigma driver supports the adapters of models 100,
+400, 500, 401, 404, 410, 440, 703, 801, 810, 840. Different models have
+different set of channels:
+.ES
+ Model Channels
+----------------------------------------------
+ Cronyx-Sigma-100 0
+ Cronyx-Sigma-400 4, 5, 6, 7
+ Cronyx-Sigma-500 0, 4, 5, 6, 7
+ Cronyx-Sigma-401 0, 1, 2, 3
+ Cronyx-Sigma-404 0, 1, 2, 3
+ Cronyx-Sigma-410 0, 1, 2, 3
+ Cronyx-Sigma-440 0, 1, 2, 3
+ Cronyx-Sigma-703 0, 1, 2, 4, 5, 6, 7
+ Cronyx-Sigma-801 0, 1, 2, 3, 4, 5, 6, 7
+ Cronyx-Sigma-810 0, 1, 2, 3, 4, 5, 6, 7
+ Cronyx-Sigma-840 0, 1, 2, 3, 4, 5, 6, 7
+.EE
+.PP
+A pair of two adapters can be united together by the special
+short inter-board cable. Two united adapters use the same
+IRQ and DMA channels and from the point of driver works
+as the single 16-channel multiplexer. One of the united
+boards is ``master'' and the other is ``slave''.
+.PP
+The channels of the slave united board are numbered by the driver
+beginning with 8, for example, the united adapter of the model 100/500
+has channels 0, 8, 12, 13, 14, 15.
+.PP
+The channels which have the RS-232 interface can be used
+both in synchronous and asynchronous modes (software selectable
+by cxconfig utility) and hence are called ``universal'' channels.
+.PP
+The special device files (/dev/*) for the adapter Cronyx-Sigma
+are created by the command file ``/dev/MAKEDEV.cx''.
+An example:
+.ES
+cd /dev
+sh MAKEDEV.cx cronyx ttyx0 ttyx1 ttyy0
+.EE
+.SH "Asynchronous driver"
+.PP
+The asynchronous channel device files have the names:
+/dev/ttyx# - for adapter cx0, /dev/ttyy# - for adapter cx1,
+/dev/ttyz# - for cx2.
+Here\ # is the channel number in hexadecimal form, 0-9-a-f.
+.PP
+The driver fulfills the following standard ioctl requests (see ioctl(2)):
+.IP TIOCSBRK
+Start sending BREAK.
+.IP TIOCCBRK
+Stop sending BREAK.
+.IP TIOCSDTR
+Set DTR signal (DTR := 1). The DTR signal is always set
+on the first open(2) and could be changed by
+TIOCCDTR, TIOCSDTR, TIOCMSET, TIOCMBIS, TIOCMBIC ioctl calls.
+.IP TIOCCDTR
+Clear DTR signal (DTR := 0).
+.IP TIOCMSET
+Set the given values of DTR and RTS signals (<DTR:RTS> := data).
+The signals DTR and RTS are controlled by TIOCM_DTR and TIOCM_RTS
+bits of the data argument of the ioctl system call.
+.IP TIOCMBIS
+Set DTR and RTS signals (<DTR:RTS> |= data).
+The signals DTR and RTS are controlled by TIOCM_DTR and TIOCM_RTS
+bits of the data argument of the ioctl system call.
+.IP TIOCMBIC
+Clear DTR and RTS signals (<DTR:RTS> &= ~data).
+The signals DTR and RTS are controlled by TIOCM_DTR and TIOCM_RTS
+bits of the data argument of the ioctl system call.
+.IP TIOCMGET
+Determine the state of the modem signals of the line.
+After the call the data argument contains the following bits:
+.ES
+TIOCM_LE - always set (Line Enabled)
+TIOCM_DSR - Data Set Ready signal received
+TIOCM_CTS - Clear To Send signal received
+TIOCM_CD - Data Carrier Detect signal received
+TIOCM_DTR - Data Terminal Ready signal transmitted
+TIOCM_RTS - Request To Send signal transmitted
+.EE
+.SH "Synchronous driver"
+.PP
+The synchronous channels and universal channels, turned to the synchronous
+mode by the cxconfig(8) utility, are accessible as network
+interfaces named ``cx#'' where\ # is the channel number, 0..47.
+All standard network interface parameters could be set by ifconfig(8) utility.
+The cxconfig(8) command is used to change some extended channel
+options, and also for setting the high-level software protocol
+(e.g. PPP or Cisco HDLC).
+.PP
+The universal channels could be used both in asynchronous and synchronous modes.
+By default the asynchronous mode is set.
+The mode could be changed by cxconfig(8) utility.
+The mode is blocked while the channel is busy (an asynchronous channel
+in open state or the network interface is up).
+.SH "Synchronous Point-to-Point protocol"
+.PP
+The Cronyx-Sigma driver uses the built-in implementation of the synchronous
+Point-to-Point protocol (sppp). It includes the support for such
+protocols as PPP/HDLC and Cisco/HDLC, and also the automatic
+connection loss test (via keepalive packets).
+The sppp protocol set is implemented as an independent module
+and could be used by other drivers of synchronous serial channels.
+The version of the driver for BSD/386 (BSDI) operating system
+also supports the usage of the general set of synchronous
+protocols, implemented inside the OS.
+The external protocol set could be selected by ``cxconfig ext'' command
+(see cxconfig(8)).
+.SH "Channel Options Management"
+.PP
+The cxconfig(8) utility is used for setting the channels options.
+The channel options are generally set at the start of the operating
+system (for example, from the file /etc/rc).
+Note, that not all options have a sense for every particular
+case, and an attempt to set some of them can hang up the channel or
+the whole adapter.
+.PP
+The actual channel options control functions are implemented via
+the ioctl-s on the special device file /dev/cronyx.
+There are the following ioctl-s available:
+.IP CXIOCGETMODE
+Get the channel option values.
+.IP CXIOCSETMODE
+Set the channel option values.
+.PP
+The data argument of the ioctl call has an address of the options structure:
+.ES
+typedef struct {
+ unsigned char board; /* adapter number, 0..2 */
+ unsigned char channel; /* channel number, 0..15 */
+ unsigned char type; /* channel type (read only) */
+ unsigned char iftype; /* chan0 interface */
+ unsigned long rxbaud; /* receiver speed */
+ unsigned long txbaud; /* transmitter speed */
+ cx_chan_mode_t mode; /* channel mode */
+ cx_chan_opt_t opt; /* common channel options */
+ cx_opt_async_t aopt; /* async mode options */
+ cx_opt_hdlc_t hopt; /* hdlc mode options */
+ cx_opt_bisync_t bopt; /* bisync mode options */
+ cx_opt_x21_t xopt; /* x.21 mode options */
+ cx_soft_opt_t sopt; /* software options and state flags */
+} cx_options_t; /* user settable options */
+.EE
+.IP board
+The adapter number, 0..2.
+.IP channel
+The channel number, 0..15.
+.IP type
+The type of the channel (read-only argument).
+.IP iftype
+The interface type of the zero (and also the eight) channel: 0 - RS-232,
+1 - RS-449/V.35.
+.IP rxbaud
+The receiver data baud rate.
+.IP txbaud
+The transmitter data baud rate.
+.IP mode
+The channel mode: asynchronous/HDLC/Bisync/X.21.
+.IP opt
+The general channel options.
+.IP aopt
+The asynchronous mode options.
+.IP hopt
+The HDLC mode options.
+.IP bopt
+The Bisync mode options.
+.IP xopt
+The X.21 mode options.
+.IP sopt
+The software protocol options.
+.SH FILES
+.PP
+/dev/cx??
+.IP
+Asynchronous channels.
+.PP
+/dev/cronyx
+.IP
+The special device file for the channel options management.
+.PP
+/sys/i386/isa/cronyx.c
+.br
+/sys/i386/isa/cx.c
+.br
+/sys/i386/isa/if_cx.c
+.br
+/sys/i386/isa/cronyx.h
+.br
+/sys/i386/isa/cxreg.h
+.br
+/sys/net/if_spppsubr.c
+.br
+/sys/net/if_sppp.h
+.IP
+The sources of the driver.
+.SH SEE ALSO
+.PP
+cxconfig(8)
diff --git a/sys/i386/include/cronyx.h b/sys/i386/include/cronyx.h
new file mode 100644
index 0000000..db56cf9
--- /dev/null
+++ b/sys/i386/include/cronyx.h
@@ -0,0 +1,475 @@
+/*
+ * Defines for Cronyx-Sigma adapter driver.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.1, Wed Oct 26 16:09:46 MSK 1994
+ */
+/*
+ * Asynchronous channel mode -------------------------------------------------
+ */
+
+/* Parity */
+#define PAR_EVEN 0 /* even parity */
+#define PAR_ODD 1 /* odd parity */
+
+/* Parity mode */
+#define PARM_NOPAR 0 /* no parity */
+#define PARM_FORCE 1 /* force parity (odd = force 1, even = 0) */
+#define PARM_NORMAL 2 /* normal parity */
+
+/* Flow control transparency mode */
+#define FLOWCC_PASS 0 /* pass flow ctl chars as exceptions */
+#define FLOWCC_NOTPASS 1 /* don't pass flow ctl chars to the host */
+
+/* Stop bit length */
+#define STOPB_1 2 /* 1 stop bit */
+#define STOPB_15 3 /* 1.5 stop bits */
+#define STOPB_2 4 /* 2 stop bits */
+
+/* Action on break condition */
+#define BRK_INTR 0 /* generate an exception interrupt */
+#define BRK_NULL 1 /* translate to a NULL character */
+#define BRK_RESERVED 2 /* reserved */
+#define BRK_DISCARD 3 /* discard character */
+
+/* Parity/framing error actions */
+#define PERR_INTR 0 /* generate an exception interrupt */
+#define PERR_NULL 1 /* translate to a NULL character */
+#define PERR_IGNORE 2 /* ignore error; char passed as good data */
+#define PERR_DISCARD 3 /* discard error character */
+#define PERR_FFNULL 5 /* translate to FF NULL char */
+
+typedef struct { /* async channel option register 1 */
+ unsigned charlen : 4; /* character length, 5..8 */
+ unsigned ignpar : 1; /* ignore parity */
+ unsigned parmode : 2; /* parity mode */
+ unsigned parity : 1; /* parity */
+} cx_cor1_async_t;
+
+typedef struct { /* async channel option register 2 */
+ unsigned dsrae : 1; /* DSR automatic enable */
+ unsigned ctsae : 1; /* CTS automatic enable */
+ unsigned rtsao : 1; /* RTS automatic output enable */
+ unsigned rlm : 1; /* remote loopback mode enable */
+ unsigned zero : 1;
+ unsigned etc : 1; /* embedded transmitter cmd enable */
+ unsigned ixon : 1; /* in-band XON/XOFF enable */
+ unsigned ixany : 1; /* XON on any character */
+} cx_cor2_async_t;
+
+typedef struct { /* async channel option register 3 */
+ unsigned stopb : 3; /* stop bit length */
+ unsigned zero : 1;
+ unsigned scde : 1; /* special char detection enable */
+ unsigned flowct : 1; /* flow control transparency mode */
+ unsigned rngde : 1; /* range detect enable */
+ unsigned escde : 1; /* extended spec. char detect enable */
+} cx_cor3_async_t;
+
+typedef struct { /* async channel option register 6 */
+ unsigned parerr : 3; /* parity/framing error actions */
+ unsigned brk : 2; /* action on break condition */
+ unsigned inlcr : 1; /* translate NL to CR on input */
+ unsigned icrnl : 1; /* translate CR to NL on input */
+ unsigned igncr : 1; /* discard CR on input */
+} cx_cor6_async_t;
+
+typedef struct { /* async channel option register 7 */
+ unsigned ocrnl : 1; /* translate CR to NL on output */
+ unsigned onlcr : 1; /* translate NL to CR on output */
+ unsigned zero : 3;
+ unsigned fcerr : 1; /* process flow ctl err chars enable */
+ unsigned lnext : 1; /* LNext option enable */
+ unsigned istrip : 1; /* strip 8-bit on input */
+} cx_cor7_async_t;
+
+typedef struct { /* async channel options */
+ cx_cor1_async_t cor1; /* channel option register 1 */
+ cx_cor2_async_t cor2; /* channel option register 2 */
+ cx_cor3_async_t cor3; /* option register 3 */
+ cx_cor6_async_t cor6; /* channel option register 6 */
+ cx_cor7_async_t cor7; /* channel option register 7 */
+ unsigned char schr1; /* special character register 1 (XON) */
+ unsigned char schr2; /* special character register 2 (XOFF) */
+ unsigned char schr3; /* special character register 3 */
+ unsigned char schr4; /* special character register 4 */
+ unsigned char scrl; /* special character range low */
+ unsigned char scrh; /* special character range high */
+ unsigned char lnxt; /* LNext character */
+} cx_opt_async_t;
+
+/*
+ * HDLC channel mode ---------------------------------------------------------
+ */
+/* Address field length option */
+#define AFLO_1OCT 0 /* address field is 1 octet in length */
+#define AFLO_2OCT 1 /* address field is 2 octet in length */
+
+/* Clear detect for X.21 data transfer phase */
+#define CLRDET_DISABLE 0 /* clear detect disabled */
+#define CLRDET_ENABLE 1 /* clear detect enabled */
+
+/* Addressing mode */
+#define ADMODE_NOADDR 0 /* no address */
+#define ADMODE_4_1 1 /* 4 * 1 byte */
+#define ADMODE_2_2 2 /* 2 * 2 byte */
+
+/* FCS append */
+#define FCS_NOTPASS 0 /* receive CRC is not passed to the host */
+#define FCS_PASS 1 /* receive CRC is passed to the host */
+
+/* CRC modes */
+#define CRC_INVERT 0 /* CRC is transmitted inverted (CRC V.41) */
+#define CRC_DONT_INVERT 1 /* CRC is not transmitted inverted (CRC-16) */
+
+/* Send sync pattern */
+#define SYNC_00 0 /* send 00h as pad char (NRZI encoding) */
+#define SYNC_AA 1 /* send AAh (Manchester/NRZ encoding) */
+
+/* FCS preset */
+#define FCSP_ONES 0 /* FCS is preset to all ones (CRC V.41) */
+#define FCSP_ZEROS 1 /* FCS is preset to all zeros (CRC-16) */
+
+/* idle mode */
+#define IDLE_FLAG 0 /* idle in flag */
+#define IDLE_MARK 1 /* idle in mark */
+
+/* CRC polynomial select */
+#define POLY_V41 0 /* x^16+x^12+x^5+1 (HDLC, preset to 1) */
+#define POLY_16 1 /* x^16+x^15+x^2+1 (bisync, preset to 0) */
+
+typedef struct { /* hdlc channel option register 1 */
+ unsigned ifflags : 4; /* number of inter-frame flags sent */
+ unsigned admode : 2; /* addressing mode */
+ unsigned clrdet : 1; /* clear detect for X.21 data transfer phase */
+ unsigned aflo : 1; /* address field length option */
+} cx_cor1_hdlc_t;
+
+typedef struct { /* hdlc channel option register 2 */
+ unsigned dsrae : 1; /* DSR automatic enable */
+ unsigned ctsae : 1; /* CTS automatic enable */
+ unsigned rtsao : 1; /* RTS automatic output enable */
+ unsigned zero1 : 1;
+ unsigned crcninv : 1; /* CRC invertion option */
+ unsigned zero2 : 1;
+ unsigned fcsapd : 1; /* FCS append */
+ unsigned zero3 : 1;
+} cx_cor2_hdlc_t;
+
+typedef struct { /* hdlc channel option register 3 */
+ unsigned padcnt : 3; /* pad character count */
+ unsigned idle : 1; /* idle mode */
+ unsigned nofcs : 1; /* FCS disable */
+ unsigned fcspre : 1; /* FCS preset */
+ unsigned syncpat : 1; /* send sync pattern */
+ unsigned sndpad : 1; /* send pad characters before flag enable */
+} cx_cor3_hdlc_t;
+
+typedef struct { /* hdlc channel options */
+ cx_cor1_hdlc_t cor1; /* hdlc channel option register 1 */
+ cx_cor2_hdlc_t cor2; /* hdlc channel option register 2 */
+ cx_cor3_hdlc_t cor3; /* hdlc channel option register 3 */
+ unsigned char rfar1; /* receive frame address register 1 */
+ unsigned char rfar2; /* receive frame address register 2 */
+ unsigned char rfar3; /* receive frame address register 3 */
+ unsigned char rfar4; /* receive frame address register 4 */
+ unsigned char cpsr; /* CRC polynomial select */
+} cx_opt_hdlc_t;
+
+/*
+ * BISYNC channel mode -------------------------------------------------------
+ */
+
+/* Longitudinal redundancy check */
+#define BCC_CRC16 0 /* CRC16 is used for BCC */
+#define BCC_LRC 1 /* LRC is used for BCC */
+
+/* Send pad pattern */
+#define PAD_AA 0 /* send AAh as pad character */
+#define PAD_55 1 /* send 55h as pad character */
+
+typedef struct { /* channel option register 1 */
+ unsigned charlen : 4; /* character length, 5..8 */
+ unsigned ignpar : 1; /* ignore parity */
+ unsigned parmode : 2; /* parity mode */
+ unsigned parity : 1; /* parity */
+} cx_cor1_bisync_t;
+
+typedef struct { /* channel option register 2 */
+ unsigned syns : 4; /* number of extra SYN chars before a frame */
+ unsigned crcninv : 1; /* CRC invertion option */
+ unsigned ebcdic : 1; /* use EBCDIC as char set (instead of ASCII) */
+ unsigned bcc : 1; /* BCC append enable */
+ unsigned lrc : 1; /* longitudinal redundancy check */
+} cx_cor2_bisync_t;
+
+typedef struct { /* channel option register 3 */
+ unsigned padcnt : 3; /* pad character count */
+ unsigned idle : 1; /* idle mode */
+ unsigned nofcs : 1; /* FCS disable */
+ unsigned fcspre : 1; /* FCS preset */
+ unsigned padpat : 1; /* send pad pattern */
+ unsigned sndpad : 1; /* send pad characters before SYN enable */
+} cx_cor3_bisync_t;
+
+typedef struct { /* channel option register 6 */
+ unsigned char specterm; /* special termination character */
+} cx_cor6_bisync_t;
+
+typedef struct { /* bisync channel options */
+ cx_cor1_bisync_t cor1; /* channel option register 1 */
+ cx_cor2_bisync_t cor2; /* channel option register 2 */
+ cx_cor3_bisync_t cor3; /* channel option register 3 */
+ cx_cor6_bisync_t cor6; /* channel option register 6 */
+ unsigned char cpsr; /* CRC polynomial select */
+} cx_opt_bisync_t;
+
+/*
+ * X.21 channel mode ---------------------------------------------------------
+ */
+
+/* The number of SYN chars on receive */
+#define X21SYN_2 0 /* two SYN characters are required */
+#define X21SYN_1 1 /* one SYN character is required */
+
+typedef struct { /* channel option register 1 */
+ unsigned charlen : 4; /* character length, 5..8 */
+ unsigned ignpar : 1; /* ignore parity */
+ unsigned parmode : 2; /* parity mode */
+ unsigned parity : 1; /* parity */
+} cx_cor1_x21_t;
+
+typedef struct { /* channel option register 2 */
+ unsigned zero1 : 5;
+ unsigned etc : 1; /* embedded transmitter command enable */
+ unsigned zero2 : 2;
+} cx_cor2_x21_t;
+
+typedef struct { /* channel option register 3 */
+ unsigned zero : 4;
+ unsigned scde : 1; /* special character detect enable */
+ unsigned stripsyn : 1; /* treat SYN chars as special condition */
+ unsigned ssde : 1; /* steady state detect enable */
+ unsigned syn : 1; /* the number of SYN chars on receive */
+} cx_cor3_x21_t;
+
+typedef struct { /* channel option register 6 */
+ unsigned char synchar; /* syn character */
+} cx_cor6_x21_t;
+
+typedef struct { /* x21 channel options */
+ cx_cor1_x21_t cor1; /* channel option register 1 */
+ cx_cor2_x21_t cor2; /* channel option register 2 */
+ cx_cor3_x21_t cor3; /* channel option register 3 */
+ cx_cor6_x21_t cor6; /* channel option register 6 */
+ unsigned char schr1; /* special character register 1 */
+ unsigned char schr2; /* special character register 2 */
+ unsigned char schr3; /* special character register 3 */
+} cx_opt_x21_t;
+
+/*
+ * CD2400 channel state structure --------------------------------------------
+ */
+
+/* Signal encoding */
+#define ENCOD_NRZ 0 /* NRZ mode */
+#define ENCOD_NRZI 1 /* NRZI mode */
+#define ENCOD_MANCHESTER 2 /* Manchester mode */
+
+/* Clock source */
+#define CLK_0 0 /* clock 0 */
+#define CLK_1 1 /* clock 1 */
+#define CLK_2 2 /* clock 2 */
+#define CLK_3 3 /* clock 3 */
+#define CLK_4 4 /* clock 4 */
+#define CLK_EXT 6 /* external clock */
+#define CLK_RCV 7 /* receive clock */
+
+/* Channel type */
+#define T_NONE 0 /* no channel */
+#define T_ASYNC 1 /* pure asynchronous RS-232 channel */
+#define T_SYNC_RS232 2 /* pure synchronous RS-232 channel */
+#define T_SYNC_V35 3 /* pure synchronous V.35 channel */
+#define T_SYNC_RS449 4 /* pure synchronous RS-449 channel */
+#define T_UNIV_RS232 5 /* sync/async RS-232 channel */
+#define T_UNIV_RS449 6 /* sync/async RS-232/RS-449 channel */
+#define T_UNIV_V35 7 /* sync/async RS-232/V.35 channel */
+
+typedef enum { /* channel mode */
+ M_ASYNC, /* asynchronous mode */
+ M_HDLC, /* HDLC mode */
+ M_BISYNC, /* BISYNC mode */
+ M_X21, /* X.21 mode */
+} cx_chan_mode_t;
+
+typedef struct { /* channel option register 4 */
+ unsigned thr : 4; /* FIFO threshold */
+ unsigned zero : 1;
+ unsigned cts_zd : 1; /* detect 1 to 0 transition on the CTS */
+ unsigned cd_zd : 1; /* detect 1 to 0 transition on the CD */
+ unsigned dsr_zd : 1; /* detect 1 to 0 transition on the DSR */
+} cx_cor4_t;
+
+typedef struct { /* channel option register 5 */
+ unsigned rx_thr : 4; /* receive flow control FIFO threshold */
+ unsigned zero : 1;
+ unsigned cts_od : 1; /* detect 0 to 1 transition on the CTS */
+ unsigned cd_od : 1; /* detect 0 to 1 transition on the CD */
+ unsigned dsr_od : 1; /* detect 0 to 1 transition on the DSR */
+} cx_cor5_t;
+
+typedef struct { /* receive clock option register */
+ unsigned clk : 3; /* receive clock source */
+ unsigned encod : 2; /* signal encoding NRZ/NRZI/Manchester */
+ unsigned dpll : 1; /* DPLL enable */
+ unsigned zero : 1;
+ unsigned tlval : 1; /* transmit line value */
+} cx_rcor_t;
+
+typedef struct { /* transmit clock option register */
+ unsigned zero1 : 1;
+ unsigned llm : 1; /* local loopback mode */
+ unsigned zero2 : 1;
+ unsigned ext1x : 1; /* external 1x clock mode */
+ unsigned zero3 : 1;
+ unsigned clk : 3; /* transmit clock source */
+} cx_tcor_t;
+
+typedef struct {
+ cx_cor4_t cor4; /* channel option register 4 */
+ cx_cor5_t cor5; /* channel option register 5 */
+ cx_rcor_t rcor; /* receive clock option register */
+ cx_tcor_t tcor; /* transmit clock option register */
+} cx_chan_opt_t;
+
+typedef enum { /* line break mode */
+ BRK_IDLE, /* normal line mode */
+ BRK_SEND, /* start sending break */
+ BRK_STOP, /* stop sending break */
+} cx_break_t;
+
+typedef struct {
+ unsigned cisco : 1; /* cisco mode */
+ unsigned keepalive : 1; /* keepalive enable */
+ unsigned ext : 1; /* use external ppp implementation */
+ unsigned lock : 1; /* channel locked for use by driver */
+ unsigned norts : 1; /* disable automatic RTS control */
+} cx_soft_opt_t;
+
+#define NCHIP 4 /* the number of controllers per board */
+#define NCHAN 16 /* the number of channels on the board */
+
+typedef struct {
+ unsigned char board; /* adapter number, 0..2 */
+ unsigned char channel; /* channel number, 0..15 */
+ unsigned char type; /* channel type (read only) */
+ unsigned char iftype; /* chan0 interface RS-232/RS-449/V.35 */
+ unsigned long rxbaud; /* receiver speed */
+ unsigned long txbaud; /* transmitter speed */
+ cx_chan_mode_t mode; /* channel mode */
+ cx_chan_opt_t opt; /* common channel options */
+ cx_opt_async_t aopt; /* async mode options */
+ cx_opt_hdlc_t hopt; /* hdlc mode options */
+ cx_opt_bisync_t bopt; /* bisync mode options */
+ cx_opt_x21_t xopt; /* x.21 mode options */
+ cx_soft_opt_t sopt; /* software options and state flags */
+} cx_options_t; /* user settable options */
+
+typedef struct _chan_t {
+ unsigned char type; /* channel type */
+ unsigned char num; /* channel number, 0..15 */
+ struct _board_t *board; /* board pointer */
+ struct _chip_t *chip; /* controller pointer */
+ unsigned long rxbaud; /* receiver speed */
+ unsigned long txbaud; /* transmitter speed */
+ cx_chan_mode_t mode; /* channel mode */
+ cx_chan_opt_t opt; /* common channel options */
+ cx_opt_async_t aopt; /* async mode options */
+ cx_opt_hdlc_t hopt; /* hdlc mode options */
+ cx_opt_bisync_t bopt; /* bisync mode options */
+ cx_opt_x21_t xopt; /* x.21 mode options */
+ unsigned char *arbuf; /* receiver A dma buffer */
+ unsigned char *brbuf; /* receiver B dma buffer */
+ unsigned char *atbuf; /* transmitter A dma buffer */
+ unsigned char *btbuf; /* transmitter B dma buffer */
+ unsigned long arphys; /* receiver A phys address */
+ unsigned long brphys; /* receiver B phys address */
+ unsigned long atphys; /* transmitter A phys address */
+ unsigned long btphys; /* transmitter B phys address */
+ unsigned char dtr; /* DTR signal value */
+ unsigned char rts; /* RTS signal value */
+#ifdef KERNEL
+ struct tty *ttyp; /* tty structure pointer */
+ struct ifnet *ifp; /* network interface data */
+ caddr_t bpf; /* packet filter data */
+ cx_soft_opt_t sopt; /* software options and state flags */
+ cx_break_t brk; /* line break mode */
+#ifdef __bsdi__
+ struct ttydevice_tmp *ttydev; /* tty statistics structure */
+#endif
+#endif
+} cx_chan_t;
+
+typedef struct _chip_t {
+ unsigned short port; /* base port address, or 0 if no chip */
+ unsigned char num; /* controller number, 0..3 */
+ struct _board_t *board; /* board pointer */
+ unsigned long oscfreq; /* oscillator frequency in Hz */
+} cx_chip_t;
+
+typedef struct _board_t {
+ unsigned short port; /* base board port, 0..3f0 */
+ unsigned short num; /* board number, 0..2 */
+ unsigned char irq; /* intterupt request {3 5 7 10 11 12 15} */
+ unsigned char dma; /* DMA request {5 6 7} */
+ unsigned char if0type; /* chan0 interface RS-232/RS-449/V.35 */
+ unsigned char if8type; /* chan8 interface RS-232/RS-449/V.35 */
+ unsigned short bcr0; /* BCR0 image */
+ unsigned short bcr0b; /* BCR0b image */
+ unsigned short bcr1; /* BCR1 image */
+ unsigned short bcr1b; /* BCR1b image */
+ cx_chip_t chip[NCHIP]; /* controller structures */
+ cx_chan_t chan[NCHAN]; /* channel structures */
+ char name[16]; /* board version name */
+ unsigned char nuniv; /* number of universal channels */
+ unsigned char nsync; /* number of sync. channels */
+ unsigned char nasync; /* number of async. channels */
+} cx_board_t;
+
+#define CX_SPEED_DFLT 9600
+
+extern long cx_rxbaud, cx_txbaud;
+extern int cx_univ_mode, cx_sync_mode, cx_iftype;
+
+extern cx_chan_opt_t chan_opt_dflt; /* default mode-independent options */
+extern cx_opt_async_t opt_async_dflt; /* default async options */
+extern cx_opt_hdlc_t opt_hdlc_dflt; /* default hdlc options */
+extern cx_opt_bisync_t opt_bisync_dflt; /* default bisync options */
+extern cx_opt_x21_t opt_x21_dflt; /* default x21 options */
+
+int cx_probe_board (int port);
+void cx_init (cx_board_t *b, int num, int port, int irq, int dma);
+void cx_init_board (cx_board_t *b, int num, int port, int irq, int dma,
+ int chain, int rev, int osc, int rev2, int osc2);
+void cx_setup_board (cx_board_t *b);
+void cx_setup_chan (cx_chan_t *c);
+void cx_chan_dtr (cx_chan_t *c, int on);
+void cx_chan_rts (cx_chan_t *c, int on);
+void cx_cmd (int base, int cmd);
+void cx_disable_dma (cx_board_t *b);
+void cx_reinit_board (cx_board_t *b);
+int cx_chan_dsr (cx_chan_t *c);
+int cx_chan_cd (cx_chan_t *c);
+void cx_clock (long hz, long ba, int *clk, int *div);
+
+#define CXIOCGETMODE _IOWR('x', 1, cx_options_t) /* get channel options */
+#define CXIOCSETMODE _IOW('x', 2, cx_options_t) /* set channel options */
diff --git a/sys/i386/isa/cronyx.c b/sys/i386/isa/cronyx.c
new file mode 100644
index 0000000..4cee6b8
--- /dev/null
+++ b/sys/i386/isa/cronyx.c
@@ -0,0 +1,1041 @@
+/*
+ * Low-level subroutines for Cronyx-Sigma adapter.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.2, Mon Nov 28 16:12:18 MSK 1994
+ */
+#include <string.h>
+#if defined (MSDOS) || defined (__MSDOS__)
+# include <dos.h>
+# define inb(port) inportb(port)
+# define inw(port) inport(port)
+# define outb(port,b) outportb(port,b)
+# define outw(port,w) outport(port,w)
+# define vtophys(a) (((unsigned long)(a)>>12 & 0xffff0) +\
+ ((unsigned)(a) & 0xffff))
+#else
+# include <sys/param.h>
+# include <sys/socket.h>
+# include <net/if.h>
+# include <vm/vm.h>
+# ifdef __FreeBSD__
+# if __FreeBSD__ < 2
+# include <i386/include/pio.h>
+# else
+# include <i386/include/cpufunc.h>
+# endif
+# else
+# include <i386/include/inline.h>
+# endif
+#endif
+
+#include "cronyx.h"
+#include "cxreg.h"
+
+#define DMA_MASK 0xd4 /* DMA mask register */
+#define DMA_MASK_CLEAR 0x04 /* DMA clear mask */
+#define DMA_MODE 0xd6 /* DMA mode register */
+#define DMA_MODE_MASTER 0xc0 /* DMA master mode */
+
+#define BYTE *(unsigned char*)&
+
+static unsigned char irqmask [] = {
+ BCR0_IRQ_DIS, BCR0_IRQ_DIS, BCR0_IRQ_DIS, BCR0_IRQ_3,
+ BCR0_IRQ_DIS, BCR0_IRQ_5, BCR0_IRQ_DIS, BCR0_IRQ_7,
+ BCR0_IRQ_DIS, BCR0_IRQ_DIS, BCR0_IRQ_10, BCR0_IRQ_11,
+ BCR0_IRQ_12, BCR0_IRQ_DIS, BCR0_IRQ_DIS, BCR0_IRQ_15,
+};
+
+static unsigned char dmamask [] = {
+ BCR0_DMA_DIS, BCR0_DMA_DIS, BCR0_DMA_DIS, BCR0_DMA_DIS,
+ BCR0_DMA_DIS, BCR0_DMA_5, BCR0_DMA_6, BCR0_DMA_7,
+};
+
+long cx_rxbaud = CX_SPEED_DFLT; /* receiver baud rate */
+long cx_txbaud = CX_SPEED_DFLT; /* transmitter baud rate */
+
+int cx_univ_mode = M_ASYNC; /* univ. chan. mode: async or sync */
+int cx_sync_mode = M_HDLC; /* sync. chan. mode: HDLC, Bisync or X.21 */
+int cx_iftype = 0; /* univ. chan. interface: upper/lower */
+
+static int cx_probe_chip (int base);
+static void cx_setup_chip (cx_chip_t *c);
+
+/*
+ * Wait for CCR to clear.
+ */
+void cx_cmd (int base, int cmd)
+{
+ unsigned short port = CCR(base);
+ unsigned short count;
+
+ /* Wait 10 msec for the previous command to complete. */
+ for (count=0; inb(port) && count<20000; ++count)
+ continue;
+
+ /* Issue the command. */
+ outb (port, cmd);
+
+ /* Wait 10 msec for the command to complete. */
+ for (count=0; inb(port) && count<20000; ++count)
+ continue;
+}
+
+/*
+ * Reset the chip.
+ */
+static int cx_reset (unsigned short port)
+{
+ int count;
+
+ /* Wait up to 10 msec for revision code to appear after reset. */
+ for (count=0; count<20000; ++count)
+ if (inb(GFRCR(port)) != 0)
+ break;
+
+ cx_cmd (port, CCR_RSTALL);
+
+ /* Firmware revision code should clear imediately. */
+ /* Wait up to 10 msec for revision code to appear again. */
+ for (count=0; count<20000; ++count)
+ if (inb(GFRCR(port)) != 0)
+ return (1);
+
+ /* Reset failed. */
+ return (0);
+}
+
+/*
+ * Check if the CD2400 board is present at the given base port.
+ */
+static int cx_probe_chained_board (int port, int *c0, int *c1)
+{
+ int rev, i;
+
+ /* Read and check the board revision code. */
+ rev = inb (BSR(port));
+ *c0 = *c1 = 0;
+ switch (rev & BSR_VAR_MASK) {
+ case CRONYX_100: *c0 = 1; break;
+ case CRONYX_400: *c1 = 1; break;
+ case CRONYX_500: *c0 = *c1 = 1; break;
+ case CRONYX_410: *c0 = 1; break;
+ case CRONYX_810: *c0 = *c1 = 1; break;
+ case CRONYX_410s: *c0 = 1; break;
+ case CRONYX_810s: *c0 = *c1 = 1; break;
+ case CRONYX_440: *c0 = 1; break;
+ case CRONYX_840: *c0 = *c1 = 1; break;
+ case CRONYX_401: *c0 = 1; break;
+ case CRONYX_801: *c0 = *c1 = 1; break;
+ case CRONYX_401s: *c0 = 1; break;
+ case CRONYX_801s: *c0 = *c1 = 1; break;
+ case CRONYX_404: *c0 = 1; break;
+ case CRONYX_703: *c0 = *c1 = 1; break;
+ default: return (0); /* invalid variant code */
+ }
+
+ switch (rev & BSR_OSC_MASK) {
+ case BSR_OSC_20: /* 20 MHz */
+ case BSR_OSC_18432: /* 18.432 MHz */
+ break;
+ default:
+ return (0); /* oscillator frequency does not match */
+ }
+
+ for (i=2; i<0x10; i+=2)
+ if ((inb (BSR(port)+i) & BSR_REV_MASK) != (rev & BSR_REV_MASK))
+ return (0); /* status changed? */
+ return (1);
+}
+
+/*
+ * Check if the CD2400 board is present at the given base port.
+ */
+int cx_probe_board (int port)
+{
+ int c0, c1, c2=0, c3=0, result;
+
+ if (! cx_probe_chained_board (port, &c0, &c1))
+ return (0); /* no board detected */
+
+ if (! (inb (BSR(port)) & BSR_NOCHAIN)) { /* chained board attached */
+ if (! cx_probe_chained_board (port + 0x10, &c2, &c3))
+ return (0); /* invalid chained board? */
+
+ if (! (inb (BSR(port+0x10)) & BSR_NOCHAIN))
+ return (0); /* invalid chained board flag? */
+ }
+
+ /* Turn off the reset bit. */
+ outb (BCR0(port), BCR0_NORESET);
+ if (c2 || c3)
+ outb (BCR0(port + 0x10), BCR0_NORESET);
+
+ result = 1;
+ if (c0 && ! cx_probe_chip (CS0(port)))
+ result = 0; /* no CD2400 chip here */
+ else if (c1 && ! cx_probe_chip (CS1(port)))
+ result = 0; /* no second CD2400 chip */
+ else if (c2 && ! cx_probe_chip (CS0(port + 0x10)))
+ result = 0; /* no CD2400 chip on the slave board */
+ else if (c3 && ! cx_probe_chip (CS1(port + 0x10)))
+ result = 0; /* no second CD2400 chip on the slave board */
+
+ /* Reset the controller. */
+ outb (BCR0(port), 0);
+ if (c2 || c3)
+ outb (BCR0(port + 0x10), 0);
+
+ /* Yes, we really have valid CD2400 board. */
+ return (result);
+}
+
+/*
+ * Check if the CD2400 chip is present at the given base port.
+ */
+static int cx_probe_chip (int base)
+{
+ int rev, newrev, count;
+
+ /* Wait up to 10 msec for revision code to appear after reset. */
+ for (count=0; inb(GFRCR(base))==0; ++count)
+ if (count >= 20000)
+ return (0); /* reset failed */
+
+ /* Read and check the global firmware revision code. */
+ rev = inb (GFRCR(base));
+ if (rev<REVCL_MIN || rev>REVCL_MAX)
+ return (0); /* CD2400 revision does not match */
+
+ /* Reset the chip. */
+ if (! cx_reset (base))
+ return (0);
+
+ /* Read and check the new global firmware revision code. */
+ newrev = inb (GFRCR(base));
+ if (newrev != rev)
+ return (0); /* revision changed */
+
+ /* Yes, we really have CD2400 chip here. */
+ return (1);
+}
+
+/*
+ * Probe and initialize the board structure.
+ */
+void cx_init (cx_board_t *b, int num, int port, int irq, int dma)
+{
+ int rev, chain, rev2;
+
+ rev = inb (BSR(port));
+ chain = !(rev & BSR_NOCHAIN);
+ rev2 = chain ? inb (BSR(port+0x10)) : 0;
+ cx_init_board (b, num, port, irq, dma, chain,
+ (rev & BSR_VAR_MASK), (rev & BSR_OSC_MASK),
+ (rev2 & BSR_VAR_MASK), (rev2 & BSR_OSC_MASK));
+}
+
+/*
+ * Initialize the board structure, given the type of the board.
+ */
+void cx_init_board (cx_board_t *b, int num, int port, int irq, int dma,
+ int chain, int rev, int osc, int rev2, int osc2)
+{
+ cx_chan_t *c;
+ int i, c0, c1;
+
+ /* Initialize board structure. */
+ b->port = port;
+ b->num = num;
+ b->irq = irq;
+ b->dma = dma;
+ b->if0type = b->if8type = cx_iftype;
+
+ /* Set channels 0 and 8 mode, set DMA and IRQ. */
+ b->bcr0 = b->bcr0b = BCR0_NORESET | dmamask[b->dma] | irqmask[b->irq];
+
+ /* Clear DTR[0..3] and DTR[8..12]. */
+ b->bcr1 = b->bcr1b = 0;
+
+ /* Initialize chip structures. */
+ for (i=0; i<NCHIP; ++i) {
+ b->chip[i].num = i;
+ b->chip[i].board = b;
+ }
+ b->chip[0].port = CS0(port);
+ b->chip[1].port = CS1(port);
+ b->chip[2].port = CS0(port+0x10);
+ b->chip[3].port = CS1(port+0x10);
+
+ /*------------------ Master board -------------------*/
+
+ /* Read and check the board revision code. */
+ c0 = c1 = 0;
+ b->name[0] = 0;
+ switch (rev) {
+ case CRONYX_100: strcpy (b->name, "100"); c0 = 1; break;
+ case CRONYX_400: strcpy (b->name, "400"); c1 = 1; break;
+ case CRONYX_500: strcpy (b->name, "500"); c0 = c1 = 1; break;
+ case CRONYX_410: strcpy (b->name, "410"); c0 = 1; break;
+ case CRONYX_810: strcpy (b->name, "810"); c0 = c1 = 1; break;
+ case CRONYX_410s: strcpy (b->name, "410s"); c0 = 1; break;
+ case CRONYX_810s: strcpy (b->name, "810s"); c0 = c1 = 1; break;
+ case CRONYX_440: strcpy (b->name, "440"); c0 = 1; break;
+ case CRONYX_840: strcpy (b->name, "840"); c0 = c1 = 1; break;
+ case CRONYX_401: strcpy (b->name, "401"); c0 = 1; break;
+ case CRONYX_801: strcpy (b->name, "801"); c0 = c1 = 1; break;
+ case CRONYX_401s: strcpy (b->name, "401s"); c0 = 1; break;
+ case CRONYX_801s: strcpy (b->name, "801s"); c0 = c1 = 1; break;
+ case CRONYX_404: strcpy (b->name, "404"); c0 = 1; break;
+ case CRONYX_703: strcpy (b->name, "703"); c0 = c1 = 1; break;
+ }
+
+ switch (osc) {
+ default:
+ case BSR_OSC_20: /* 20 MHz */
+ b->chip[0].oscfreq = b->chip[1].oscfreq = 20000000L;
+ strcat (b->name, "a");
+ break;
+ case BSR_OSC_18432: /* 18.432 MHz */
+ b->chip[0].oscfreq = b->chip[1].oscfreq = 18432000L;
+ strcat (b->name, "b");
+ break;
+ }
+
+ if (! c0)
+ b->chip[0].port = 0;
+ if (! c1)
+ b->chip[1].port = 0;
+
+ /*------------------ Slave board -------------------*/
+
+ if (! chain) {
+ b->chip[2].oscfreq = b->chip[3].oscfreq = 0L;
+ b->chip[2].port = b->chip[3].port = 0;
+ } else {
+ /* Read and check the board revision code. */
+ c0 = c1 = 0;
+ strcat (b->name, "/");
+ switch (rev2) {
+ case CRONYX_100: strcat(b->name,"100"); c0=1; break;
+ case CRONYX_400: strcat(b->name,"400"); c1=1; break;
+ case CRONYX_500: strcat(b->name,"500"); c0=c1=1; break;
+ case CRONYX_410: strcat(b->name,"410"); c0=1; break;
+ case CRONYX_810: strcat(b->name,"810"); c0=c1=1; break;
+ case CRONYX_410s: strcat(b->name,"410s"); c0=1; break;
+ case CRONYX_810s: strcat(b->name,"810s"); c0=c1=1; break;
+ case CRONYX_440: strcat(b->name,"440"); c0=1; break;
+ case CRONYX_840: strcat(b->name,"840"); c0=c1=1; break;
+ case CRONYX_401: strcat(b->name,"401"); c0=1; break;
+ case CRONYX_801: strcat(b->name,"801"); c0=c1=1; break;
+ case CRONYX_401s: strcat(b->name,"401s"); c0=1; break;
+ case CRONYX_801s: strcat(b->name,"801s"); c0=c1=1; break;
+ case CRONYX_404: strcat(b->name,"404"); c0=1; break;
+ case CRONYX_703: strcat(b->name,"703"); c0=c1=1; break;
+ }
+
+ switch (osc2) {
+ default:
+ case BSR_OSC_20: /* 20 MHz */
+ b->chip[2].oscfreq = b->chip[3].oscfreq = 20000000L;
+ strcat (b->name, "a");
+ break;
+ case BSR_OSC_18432: /* 18.432 MHz */
+ b->chip[2].oscfreq = b->chip[3].oscfreq = 18432000L;
+ strcat (b->name, "b");
+ break;
+ }
+
+ if (! c0)
+ b->chip[2].port = 0;
+ if (! c1)
+ b->chip[3].port = 0;
+ }
+
+ /* Initialize channel structures. */
+ for (i=0; i<NCHAN; ++i) {
+ cx_chan_t *c = b->chan + i;
+
+ c->num = i;
+ c->board = b;
+ c->chip = b->chip + i*NCHIP/NCHAN;
+ c->type = T_NONE;
+ }
+
+ /*------------------ Master board -------------------*/
+
+ switch (rev) {
+ case CRONYX_400:
+ break;
+ case CRONYX_100:
+ case CRONYX_500:
+ b->chan[0].type = T_UNIV_RS232;
+ break;
+ case CRONYX_410:
+ case CRONYX_810:
+ b->chan[0].type = T_UNIV_V35;
+ for (i=1; i<4; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+ break;
+ case CRONYX_410s:
+ case CRONYX_810s:
+ b->chan[0].type = T_UNIV_V35;
+ for (i=1; i<4; ++i)
+ b->chan[i].type = T_SYNC_RS232;
+ break;
+ case CRONYX_440:
+ case CRONYX_840:
+ b->chan[0].type = T_UNIV_V35;
+ for (i=1; i<4; ++i)
+ b->chan[i].type = T_SYNC_V35;
+ break;
+ case CRONYX_401:
+ case CRONYX_801:
+ b->chan[0].type = T_UNIV_RS449;
+ for (i=1; i<4; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+ break;
+ case CRONYX_401s:
+ case CRONYX_801s:
+ b->chan[0].type = T_UNIV_RS449;
+ for (i=1; i<4; ++i)
+ b->chan[i].type = T_SYNC_RS232;
+ break;
+ case CRONYX_404:
+ b->chan[0].type = T_UNIV_RS449;
+ for (i=1; i<4; ++i)
+ b->chan[i].type = T_SYNC_RS449;
+ break;
+ case CRONYX_703:
+ b->chan[0].type = T_UNIV_RS449;
+ for (i=1; i<3; ++i)
+ b->chan[i].type = T_SYNC_RS449;
+ break;
+ }
+
+ /* If the second controller is present,
+ * then we have 4..7 channels in async. mode */
+ if (b->chip[1].port)
+ for (i=4; i<8; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+
+ /*------------------ Slave board -------------------*/
+
+ if (chain) {
+ switch (rev2) {
+ case CRONYX_400:
+ break;
+ case CRONYX_100:
+ case CRONYX_500:
+ b->chan[8].type = T_UNIV_RS232;
+ break;
+ case CRONYX_410:
+ case CRONYX_810:
+ b->chan[8].type = T_UNIV_V35;
+ for (i=9; i<12; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+ break;
+ case CRONYX_410s:
+ case CRONYX_810s:
+ b->chan[8].type = T_UNIV_V35;
+ for (i=9; i<12; ++i)
+ b->chan[i].type = T_SYNC_RS232;
+ break;
+ case CRONYX_440:
+ case CRONYX_840:
+ b->chan[8].type = T_UNIV_V35;
+ for (i=9; i<12; ++i)
+ b->chan[i].type = T_SYNC_V35;
+ break;
+ case CRONYX_401:
+ case CRONYX_801:
+ b->chan[8].type = T_UNIV_RS449;
+ for (i=9; i<12; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+ break;
+ case CRONYX_401s:
+ case CRONYX_801s:
+ b->chan[8].type = T_UNIV_RS449;
+ for (i=9; i<12; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+ break;
+ case CRONYX_404:
+ b->chan[8].type = T_UNIV_RS449;
+ for (i=9; i<12; ++i)
+ b->chan[i].type = T_SYNC_RS449;
+ break;
+ case CRONYX_703:
+ b->chan[8].type = T_UNIV_RS449;
+ for (i=9; i<11; ++i)
+ b->chan[i].type = T_SYNC_RS449;
+ break;
+ }
+
+ /* If the second controller is present,
+ * then we have 4..7 channels in async. mode */
+ if (b->chip[3].port)
+ for (i=12; i<16; ++i)
+ b->chan[i].type = T_UNIV_RS232;
+ }
+
+ b->nuniv = b->nsync = b->nasync = 0;
+ for (c=b->chan; c<b->chan+NCHAN; ++c)
+ switch (c->type) {
+ case T_ASYNC: ++b->nasync; break;
+ case T_UNIV_RS232:
+ case T_UNIV_RS449:
+ case T_UNIV_V35: ++b->nuniv; break;
+ case T_SYNC_RS232:
+ case T_SYNC_V35:
+ case T_SYNC_RS449: ++b->nsync; break;
+ }
+
+ cx_reinit_board (b);
+}
+
+/*
+ * Reinitialize all channels, using new options and baud rate.
+ */
+void cx_reinit_board (cx_board_t *b)
+{
+ cx_chan_t *c;
+
+ b->if0type = b->if8type = cx_iftype;
+ for (c=b->chan; c<b->chan+NCHAN; ++c) {
+ switch (c->type) {
+ default:
+ case T_NONE:
+ continue;
+ case T_UNIV_RS232:
+ case T_UNIV_RS449:
+ case T_UNIV_V35:
+ c->mode = (cx_univ_mode == M_ASYNC) ?
+ M_ASYNC : cx_sync_mode;
+ break;
+ case T_SYNC_RS232:
+ case T_SYNC_V35:
+ case T_SYNC_RS449:
+ c->mode = cx_sync_mode;
+ break;
+ case T_ASYNC:
+ c->mode = M_ASYNC;
+ break;
+ }
+ c->rxbaud = cx_rxbaud;
+ c->txbaud = cx_txbaud;
+ c->opt = chan_opt_dflt;
+ c->aopt = opt_async_dflt;
+ c->hopt = opt_hdlc_dflt;
+ c->bopt = opt_bisync_dflt;
+ c->xopt = opt_x21_dflt;
+ }
+}
+
+/*
+ * Set up the board.
+ */
+void cx_setup_board (cx_board_t *b)
+{
+ int i;
+
+ /* Disable DMA channel. */
+ outb (DMA_MASK, (b->dma & 3) | DMA_MASK_CLEAR);
+
+ /* Reset the controller. */
+ outb (BCR0(b->port), 0);
+ if (b->chip[2].port || b->chip[3].port)
+ outb (BCR0(b->port+0x10), 0);
+
+ /*
+ * Set channels 0 and 8 to RS232 async. mode.
+ * Enable DMA and IRQ.
+ */
+ outb (BCR0(b->port), b->bcr0);
+ if (b->chip[2].port || b->chip[3].port)
+ outb (BCR0(b->port+0x10), b->bcr0b);
+
+ /* Clear DTR[0..3] and DTR[8..12]. */
+ outw (BCR1(b->port), b->bcr1);
+ if (b->chip[2].port || b->chip[3].port)
+ outw (BCR1(b->port+0x10), b->bcr1b);
+
+ /* Initialize all controllers. */
+ for (i=0; i<NCHIP; ++i)
+ if (b->chip[i].port)
+ cx_setup_chip (b->chip + i);
+
+ /* Set up DMA channel to master mode. */
+ outb (DMA_MODE, (b->dma & 3) | DMA_MODE_MASTER);
+
+ /* Enable DMA channel. */
+ outb (DMA_MASK, b->dma & 3);
+
+ /* Initialize all channels. */
+ for (i=0; i<NCHAN; ++i)
+ if (b->chan[i].type != T_NONE)
+ cx_setup_chan (b->chan + i);
+}
+
+/*
+ * Initialize the board.
+ */
+static void cx_setup_chip (cx_chip_t *c)
+{
+ /* Reset the chip. */
+ cx_reset (c->port);
+
+ /*
+ * Set all interrupt level registers to the same value.
+ * This enables the internal CD2400 priority scheme.
+ */
+ outb (RPILR(c->port), BRD_INTR_LEVEL);
+ outb (TPILR(c->port), BRD_INTR_LEVEL);
+ outb (MPILR(c->port), BRD_INTR_LEVEL);
+
+ /* Set bus error count to zero. */
+ outb (BERCNT(c->port), 0);
+
+ /* Set 16-bit DMA mode. */
+ outb (DMR(c->port), 0);
+
+ /* Set timer period register to 1 msec (approximately). */
+ outb (TPR(c->port), 10);
+}
+
+/*
+ * Initialize the CD2400 channel.
+ */
+void cx_setup_chan (cx_chan_t *c)
+{
+ unsigned short port = c->chip->port;
+ int clock, period;
+
+ if (c->num == 0) {
+ c->board->bcr0 &= ~BCR0_UMASK;
+ if (c->mode != M_ASYNC)
+ c->board->bcr0 |= BCR0_UM_SYNC;
+ if (c->board->if0type &&
+ (c->type==T_UNIV_RS449 || c->type==T_UNIV_V35))
+ c->board->bcr0 |= BCR0_UI_RS449;
+ outb (BCR0(c->board->port), c->board->bcr0);
+ } else if (c->num == 8) {
+ c->board->bcr0b &= ~BCR0_UMASK;
+ if (c->mode != M_ASYNC)
+ c->board->bcr0b |= BCR0_UM_SYNC;
+ if (c->board->if8type &&
+ (c->type==T_UNIV_RS449 || c->type==T_UNIV_V35))
+ c->board->bcr0b |= BCR0_UI_RS449;
+ outb (BCR0(c->board->port+0x10), c->board->bcr0b);
+ }
+
+ /* set current channel number */
+ outb (CAR(port), c->num & 3);
+
+ /* reset the channel */
+ cx_cmd (port, CCR_CLRCH);
+
+ /* set LIVR to contain the board and channel numbers */
+ outb (LIVR(port), c->board->num << 6 | c->num << 2);
+
+ /* clear DTR, RTS, set TXCout/DTR pin */
+ outb (MSVR_RTS(port), 0);
+ outb (MSVR_DTR(port), c->mode==M_ASYNC ? 0 : MSV_TXCOUT);
+
+ switch (c->mode) { /* initialize the channel mode */
+ case M_ASYNC:
+ /* set receiver timeout register */
+ outw (RTPR(port), 10); /* 10 msec, see TPR */
+
+ outb (CMR(port), CMR_RXDMA | CMR_TXDMA | CMR_ASYNC);
+ outb (COR1(port), BYTE c->aopt.cor1);
+ outb (COR2(port), BYTE c->aopt.cor2);
+ outb (COR3(port), BYTE c->aopt.cor3);
+ outb (COR6(port), BYTE c->aopt.cor6);
+ outb (COR7(port), BYTE c->aopt.cor7);
+ outb (SCHR1(port), c->aopt.schr1);
+ outb (SCHR2(port), c->aopt.schr2);
+ outb (SCHR3(port), c->aopt.schr3);
+ outb (SCHR4(port), c->aopt.schr4);
+ outb (SCRL(port), c->aopt.scrl);
+ outb (SCRH(port), c->aopt.scrh);
+ outb (LNXT(port), c->aopt.lnxt);
+ break;
+ case M_HDLC:
+ outb (CMR(port), CMR_RXDMA | CMR_TXDMA | CMR_HDLC);
+ outb (COR1(port), BYTE c->hopt.cor1);
+ outb (COR2(port), BYTE c->hopt.cor2);
+ outb (COR3(port), BYTE c->hopt.cor3);
+ outb (RFAR1(port), c->hopt.rfar1);
+ outb (RFAR2(port), c->hopt.rfar2);
+ outb (RFAR3(port), c->hopt.rfar3);
+ outb (RFAR4(port), c->hopt.rfar4);
+ outb (CPSR(port), c->hopt.cpsr);
+ break;
+ case M_BISYNC:
+ outb (CMR(port), CMR_RXDMA | CMR_TXDMA | CMR_BISYNC);
+ outb (COR1(port), BYTE c->bopt.cor1);
+ outb (COR2(port), BYTE c->bopt.cor2);
+ outb (COR3(port), BYTE c->bopt.cor3);
+ outb (COR6(port), BYTE c->bopt.cor6);
+ outb (CPSR(port), c->bopt.cpsr);
+ break;
+ case M_X21:
+ outb (CMR(port), CMR_RXDMA | CMR_TXDMA | CMR_X21);
+ outb (COR1(port), BYTE c->xopt.cor1);
+ outb (COR2(port), BYTE c->xopt.cor2);
+ outb (COR3(port), BYTE c->xopt.cor3);
+ outb (COR6(port), BYTE c->xopt.cor6);
+ outb (SCHR1(port), c->xopt.schr1);
+ outb (SCHR2(port), c->xopt.schr2);
+ outb (SCHR3(port), c->xopt.schr3);
+ break;
+ }
+
+ /* set mode-independent options */
+ outb (COR4(port), BYTE c->opt.cor4);
+ outb (COR5(port), BYTE c->opt.cor5);
+
+ /* set up receiver clock values */
+ if (c->mode == M_ASYNC || c->opt.rcor.dpll) {
+ cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period);
+ c->opt.rcor.clk = clock;
+ } else {
+ c->opt.rcor.clk = CLK_EXT;
+ period = 1;
+ }
+ outb (RCOR(port), BYTE c->opt.rcor);
+ outb (RBPR(port), period);
+
+ /* set up transmitter clock values */
+ if (c->mode == M_ASYNC || !c->opt.tcor.ext1x) {
+ unsigned ext1x = c->opt.tcor.ext1x;
+ c->opt.tcor.ext1x = 0;
+ cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period);
+ c->opt.tcor.clk = clock;
+ c->opt.tcor.ext1x = ext1x;
+ } else {
+ c->opt.tcor.clk = CLK_EXT;
+ period = 1;
+ }
+ outb (TCOR(port), BYTE c->opt.tcor);
+ outb (TBPR(port), period);
+
+ /* set receiver A buffer physical address */
+ c->arphys = vtophys (c->arbuf);
+ outw (ARBADRU(port), (unsigned short) (c->arphys>>16));
+ outw (ARBADRL(port), (unsigned short) c->arphys);
+
+ /* set receiver B buffer physical address */
+ c->brphys = vtophys (c->brbuf);
+ outw (BRBADRU(port), (unsigned short) (c->brphys>>16));
+ outw (BRBADRL(port), (unsigned short) c->brphys);
+
+ /* set transmitter A buffer physical address */
+ c->atphys = vtophys (c->atbuf);
+ outw (ATBADRU(port), (unsigned short) (c->atphys>>16));
+ outw (ATBADRL(port), (unsigned short) c->atphys);
+
+ /* set transmitter B buffer physical address */
+ c->btphys = vtophys (c->btbuf);
+ outw (BTBADRU(port), (unsigned short) (c->btphys>>16));
+ outw (BTBADRL(port), (unsigned short) c->btphys);
+
+ c->dtr = 0;
+ c->rts = 0;
+}
+
+/*
+ * Control DTR signal for the channel.
+ * Turn it on/off.
+ */
+void cx_chan_dtr (cx_chan_t *c, int on)
+{
+ c->dtr = on ? 1 : 0;
+
+ if (c->mode == M_ASYNC) {
+ outb (CAR(c->chip->port), c->num & 3);
+ outb (MSVR_DTR(c->chip->port), on ? MSV_DTR : 0);
+ return;
+ }
+
+ switch (c->num) {
+ default:
+ /* Channels 4..7 and 12..15 in syncronous mode
+ * have no DTR signal. */
+ break;
+ case 0: case 1: case 2: case 3:
+ if (on)
+ c->board->bcr1 |= 0x100 << c->num;
+ else
+ c->board->bcr1 &= ~(0x100 << c->num);
+ outb (CAR(c->chip->port), c->num);
+ outw (BCR1(c->board->port), c->board->bcr1);
+ break;
+ case 8: case 9: case 10: case 11:
+ if (on)
+ c->board->bcr1b |= 0x100 << (c->num & 3);
+ else
+ c->board->bcr1b &= ~(0x100 << (c->num & 3));
+ outb (CAR(c->chip->port), c->num & 3);
+ outw (BCR1(c->board->port+0x10), c->board->bcr1b);
+ break;
+ }
+}
+
+/*
+ * Control RTS signal for the channel.
+ * Turn it on/off.
+ */
+void cx_chan_rts (cx_chan_t *c, int on)
+{
+ c->rts = on ? 1 : 0;
+ outb (CAR(c->chip->port), c->num & 3);
+ outb (MSVR_RTS(c->chip->port), on ? MSV_RTS : 0);
+}
+
+/*
+ * Get the state of DSR signal of the channel.
+ */
+int cx_chan_dsr (cx_chan_t *c)
+{
+ unsigned char sigval;
+
+ if (c->mode == M_ASYNC) {
+ outb (CAR(c->chip->port), c->num & 3);
+ return (inb (MSVR(c->chip->port)) & MSV_DSR ? 1 : 0);
+ }
+
+ /*
+ * Channels 4..7 and 12..15 don't have DSR signal available.
+ */
+ switch (c->num) {
+ default:
+ return (1);
+ case 0: case 1: case 2: case 3:
+ sigval = inw (BSR(c->board->port)) >> 8;
+ break;
+ case 8: case 9: case 10: case 11:
+ sigval = inw (BSR(c->board->port+0x10)) >> 8;
+ break;
+ }
+ return (~sigval >> (c->num & 3) & 1);
+}
+
+/*
+ * Get the state of CARRIER signal of the channel.
+ */
+int cx_chan_cd (cx_chan_t *c)
+{
+ unsigned char sigval;
+
+ if (c->mode == M_ASYNC) {
+ outb (CAR(c->chip->port), c->num & 3);
+ return (inb (MSVR(c->chip->port)) & MSV_CD ? 1 : 0);
+ }
+
+ /*
+ * Channels 4..7 and 12..15 don't have CD signal available.
+ */
+ switch (c->num) {
+ default:
+ return (1);
+ case 0: case 1: case 2: case 3:
+ sigval = inw (BSR(c->board->port)) >> 8;
+ break;
+ case 8: case 9: case 10: case 11:
+ sigval = inw (BSR(c->board->port+0x10)) >> 8;
+ break;
+ }
+ return (~sigval >> 4 >> (c->num & 3) & 1);
+}
+
+/*
+ * Compute CD2400 clock values.
+ */
+void cx_clock (long hz, long ba, int *clk, int *div)
+{
+ static short clocktab[] = { 8, 32, 128, 512, 2048, 0 };
+
+ for (*clk=0; clocktab[*clk]; ++*clk) {
+ long c = ba * clocktab[*clk];
+ if (hz <= c*256) {
+ *div = (2 * hz + c) / (2 * c) - 1;
+ return;
+ }
+ }
+ /* Incorrect baud rate. Return some meaningful values. */
+ *clk = 0;
+ *div = 255;
+}
+
+void cx_disable_dma (cx_board_t *b)
+{
+ /* Disable DMA channel. */
+ outb (DMA_MASK, (b->dma & 3) | DMA_MASK_CLEAR);
+}
+
+cx_chan_opt_t chan_opt_dflt = { /* mode-independent options */
+ { /* cor4 */
+ 7, /* FIFO threshold, odd is better */
+ 0,
+ 0, /* don't detect 1 to 0 on CTS */
+ 1, /* detect 1 to 0 on CD */
+ 0, /* detect 1 to 0 on DSR */
+ },
+ { /* cor5 */
+ 0, /* receive flow control FIFO threshold */
+ 0,
+ 0, /* don't detect 0 to 1 on CTS */
+ 1, /* detect 0 to 1 on CD */
+ 0, /* detect 0 to 1 on DSR */
+ },
+ { /* rcor */
+ 0, /* dummy clock source */
+ ENCOD_NRZ, /* NRZ mode */
+ 0, /* disable DPLL */
+ 0,
+ 0, /* transmit line value */
+ },
+ { /* tcor */
+ 0,
+ 0, /* local loopback mode */
+ 0,
+ 1, /* external 1x clock mode */
+ 0,
+ 0, /* dummy transmit clock source */
+ },
+};
+
+cx_opt_async_t opt_async_dflt = { /* default async options */
+ { /* cor1 */
+ 8-1, /* 8-bit char length */
+ 0, /* don't ignore parity */
+ PARM_NOPAR, /* no parity */
+ PAR_EVEN, /* even parity */
+ },
+ { /* cor2 */
+ 0, /* disable automatic DSR */
+ 1, /* enable automatic CTS */
+ 0, /* disable automatic RTS */
+ 0, /* no remote loopback */
+ 0,
+ 0, /* disable embedded cmds */
+ 0, /* disable XON/XOFF */
+ 0, /* disable XANY */
+ },
+ { /* cor3 */
+ STOPB_1, /* 1 stop bit */
+ 0,
+ 0, /* disable special char detection */
+ FLOWCC_PASS, /* pass flow ctl chars to the host */
+ 0, /* range detect disable */
+ 0, /* disable extended spec. char detect */
+ },
+ { /* cor6 */
+ PERR_INTR, /* generate exception on parity errors */
+ BRK_INTR, /* generate exception on break condition */
+ 0, /* don't translate NL to CR on input */
+ 0, /* don't translate CR to NL on input */
+ 0, /* don't discard CR on input */
+ },
+ { /* cor7 */
+ 0, /* don't translate CR to NL on output */
+ 0, /* don't translate NL to CR on output */
+ 0,
+ 0, /* don't process flow ctl err chars */
+ 0, /* disable LNext option */
+ 0, /* don't strip 8 bit on input */
+ },
+ 0, 0, 0, 0, 0, 0, 0, /* clear schr1-4, scrl, scrh, lnxt */
+};
+
+cx_opt_hdlc_t opt_hdlc_dflt = { /* default hdlc options */
+ { /* cor1 */
+ 2, /* 2 inter-frame flags */
+ 0, /* no-address mode */
+ CLRDET_DISABLE, /* disable clear detect */
+ AFLO_1OCT, /* 1-byte address field length */
+ },
+ { /* cor2 */
+ 0, /* disable automatic DSR */
+ 0, /* disable automatic CTS */
+ 0, /* disable automatic RTS */
+ 0,
+ CRC_INVERT, /* use CRC V.41 */
+ 0,
+ FCS_NOTPASS, /* don't pass received CRC to the host */
+ 0,
+ },
+ { /* cor3 */
+ 0, /* 0 pad characters sent */
+ IDLE_FLAG, /* idle in flag */
+ 0, /* enable FCS */
+ FCSP_ONES, /* FCS preset to all ones (V.41) */
+ SYNC_AA, /* use AAh as sync char */
+ 0, /* disable pad characters */
+ },
+ 0, 0, 0, 0, /* clear rfar1-4 */
+ POLY_V41, /* use V.41 CRC polynomial */
+};
+
+cx_opt_bisync_t opt_bisync_dflt = { /* default bisync options */
+ { /* cor1 */
+ 8-1, /* 8-bit char length */
+ 0, /* don't ignore parity */
+ PARM_NOPAR, /* no parity */
+ PAR_EVEN, /* even parity */
+ },
+ { /* cor2 */
+ 3-2, /* send three SYN chars */
+ CRC_DONT_INVERT,/* don't invert CRC (CRC-16) */
+ 0, /* use ASCII, not EBCDIC */
+ 0, /* disable bcc append */
+ BCC_CRC16, /* user CRC16, not LRC */
+ },
+ { /* cor3 */
+ 0, /* send 0 pad chars */
+ IDLE_FLAG, /* idle in SYN */
+ 0, /* enable FCS */
+ FCSP_ZEROS, /* FCS preset to all zeros (CRC-16) */
+ PAD_AA, /* use AAh as pad char */
+ 0, /* disable pad characters */
+ },
+ { /* cor6 */
+ 10, /* DLE - disable special termination char */
+ },
+ POLY_16, /* use CRC-16 polynomial */
+};
+
+cx_opt_x21_t opt_x21_dflt = { /* default x21 options */
+ { /* cor1 */
+ 8-1, /* 8-bit char length */
+ 0, /* don't ignore parity */
+ PARM_NOPAR, /* no parity */
+ PAR_EVEN, /* even parity */
+ },
+ { /* cor2 */
+ 0,
+ 0, /* disable embedded transmitter cmds */
+ 0,
+ },
+ { /* cor3 */
+ 0,
+ 0, /* disable special character detect */
+ 0, /* don't treat SYN as special condition */
+ 0, /* disable steady state detect */
+ X21SYN_2, /* 2 SYN chars on receive are required */
+ },
+ { /* cor6 */
+ 16, /* SYN - standard SYN character */
+ },
+ 0, 0, 0, /* clear schr1-3 */
+};
diff --git a/sys/i386/isa/cx.c b/sys/i386/isa/cx.c
new file mode 100644
index 0000000..80ecaa7
--- /dev/null
+++ b/sys/i386/isa/cx.c
@@ -0,0 +1,898 @@
+/*
+ * Cronyx-Sigma adapter driver for FreeBSD.
+ * Supports PPP/HDLC protocol in synchronous mode,
+ * and asyncronous channels with full modem control.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.2, Tue Nov 22 18:57:27 MSK 1994
+ */
+#undef DEBUG
+
+#include "cx.h"
+#if NCX > 0
+
+#include <sys/param.h>
+#include <systm.h>
+#include <kernel.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef __FreeBSD__
+# if __FreeBSD__ < 2
+# include <i386/include/pio.h>
+# define RB_GETC(q) getc(q)
+# else /* BSD 4.4 Lite */
+# include <i386/include/cpufunc.h>
+# include <sys/devconf.h>
+# endif
+# define oproc_func_t void(*)(struct tty*)
+#endif
+#ifdef __bsdi__
+# include <sys/ttystats.h>
+# include <i386/include/inline.h>
+# define tsleep(tp,pri,msg,x) ((tp)->t_state |= TS_WOPEN,\
+ ttysleep (tp, (caddr_t)&tp->t_rawq, pri, msg, x))
+# define oproc_func_t int(*)()
+# define timeout_func_t void(*)()
+#endif
+#if !defined (__FreeBSD__) || __FreeBSD__ >= 2
+# define t_out t_outq
+# define RB_LEN(q) ((q).c_cc)
+# define RB_GETC(q) getc(&q)
+# define TSA_CARR_ON(tp) tp
+# define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out)
+#endif
+
+#include <sys/cronyx.h>
+#include <i386/isa/cxreg.h>
+
+#ifdef DEBUG
+# define print(s) printf s
+#else
+# define print(s) /*void*/
+#endif
+
+#define DMABUFSZ (6*256) /* buffer size */
+#define BYTE *(unsigned char*)&
+#define UNIT(u) ((u) & 077)
+#define UNIT_CTL 077
+
+extern cx_board_t cxboard [NCX]; /* adapter state structures */
+extern cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */
+#if __FreeBSD__ >= 2
+extern struct kern_devconf kdc_cx [NCX];
+struct tty cx_tty [NCX*NCHAN]; /* tty data */
+#else
+struct tty *cx_tty [NCX*NCHAN]; /* tty data */
+#endif
+
+void cxoproc (struct tty *tp);
+int cxparam (struct tty *tp, struct termios *t);
+void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
+
+int cxopen (dev_t dev, int flag, int mode, struct proc *p)
+{
+ int unit = UNIT (dev);
+ cx_chan_t *c = cxchan[unit];
+ unsigned short port;
+ struct tty *tp;
+ int error = 0;
+
+ if (unit == UNIT_CTL) {
+ print (("cx: cxopen /dev/cronyx\n"));
+ return (0);
+ }
+ if (unit >= NCX*NCHAN || !c || c->type==T_NONE)
+ return (ENXIO);
+ port = c->chip->port;
+ print (("cx%d.%d: cxopen unit=%d\n", c->board->num, c->num, unit));
+ if (c->mode != M_ASYNC)
+ return (EBUSY);
+ if (! c->ttyp) {
+#if __FreeBSD__ >= 2
+ c->ttyp = &cx_tty[unit];
+#else
+ MALLOC (cx_tty[unit], struct tty*, sizeof (struct tty), M_DEVBUF, M_WAITOK);
+ bzero (cx_tty[unit], sizeof (*cx_tty[unit]));
+ c->ttyp = cx_tty[unit];
+#endif
+ c->ttyp->t_oproc = (oproc_func_t) cxoproc;
+ c->ttyp->t_param = cxparam;
+ }
+#ifdef __bsdi__
+ if (! c->ttydev) {
+ MALLOC (c->ttydev, struct ttydevice_tmp*,
+ sizeof (struct ttydevice_tmp), M_DEVBUF, M_WAITOK);
+ bzero (c->ttydev, sizeof (*c->ttydev));
+ strcpy (c->ttydev->tty_name, "cx");
+ c->ttydev->tty_unit = unit;
+ c->ttydev->tty_base = unit;
+ c->ttydev->tty_count = 1;
+ c->ttydev->tty_ttys = c->ttyp;
+ tty_attach (c->ttydev);
+ }
+#endif
+ tp = c->ttyp;
+ tp->t_dev = dev;
+ if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) &&
+ p->p_ucred->cr_uid != 0)
+ return (EBUSY);
+ if (! (tp->t_state & TS_ISOPEN)) {
+ ttychars (tp);
+ if (tp->t_ispeed == 0) {
+#ifdef __bsdi__
+ tp->t_termios = deftermios;
+#else
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_lflag = 0;
+ tp->t_cflag = CREAD | CS8 | HUPCL;
+ tp->t_ispeed = c->rxbaud;
+ tp->t_ospeed = c->txbaud;
+#endif
+ }
+ cxparam (tp, &tp->t_termios);
+ ttsetwater (tp);
+ }
+
+ spltty ();
+ if (! (tp->t_state & TS_ISOPEN)) {
+ /*
+ * Compute optimal receiver buffer length.
+ * The best choice is rxbaud/400.
+ * Make it even, to avoid byte-wide DMA transfers.
+ * --------------------------
+ * Baud rate Buffer length
+ * --------------------------
+ * 300 4
+ * 1200 4
+ * 9600 24
+ * 19200 48
+ * 38400 96
+ * 57600 192
+ * 115200 288
+ * --------------------------
+ */
+ int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
+ if (rbsz < 4)
+ rbsz = 4;
+ else if (rbsz > DMABUFSZ)
+ rbsz = DMABUFSZ;
+
+ /* Initialize channel, enable receiver. */
+ cx_cmd (port, CCR_INITCH | CCR_ENRX);
+ cx_cmd (port, CCR_INITCH | CCR_ENRX);
+
+ /* Start receiver. */
+ outw (ARBCNT(port), rbsz);
+ outw (BRBCNT(port), rbsz);
+ outw (ARBSTS(port), BSTS_OWN24);
+ outw (BRBSTS(port), BSTS_OWN24);
+
+ /* Enable interrupts. */
+ outb (IER(port), IER_RXD | IER_RET | IER_TXD | IER_MDM);
+
+ cx_chan_dtr (c, 1);
+ cx_chan_rts (c, 1);
+ }
+ if (cx_chan_cd (c))
+ tp->t_state |= TS_CARR_ON;
+ if (! (flag & O_NONBLOCK)) {
+ /* Lock the channel against cxconfig while we are
+ * waiting for carrier. */
+ c->sopt.lock = 1;
+ while (!(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON))
+ if ((error = tsleep (TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "cxdcd", 0)))
+ break;
+ c->sopt.lock = 0; /* Unlock the channel. */
+ }
+ print (("cx%d.%d: cxopen done csr=%b\n", c->board->num, c->num,
+ inb(CSR(c->chip->port)), CSRA_BITS));
+ spl0 ();
+ if (error)
+ return (error);
+#if __FreeBSD__ >= 2
+ error = (*linesw[tp->t_line].l_open) (dev, tp);
+ if (tp->t_state & TS_ISOPEN)
+ /* Mark the board busy on the first startup.
+ * Never goes idle. */
+ kdc_cx[c->board->num].kdc_state = DC_BUSY;
+#else
+ error = (*linesw[tp->t_line].l_open) (dev, tp, 0);
+#endif
+ return (error);
+}
+
+int cxclose (dev_t dev, int flag, int mode, struct proc *p)
+{
+ int unit = UNIT (dev);
+ cx_chan_t *c = cxchan[unit];
+ struct tty *tp;
+ int s;
+
+ if (unit == UNIT_CTL)
+ return (0);
+ tp = c->ttyp;
+ (*linesw[tp->t_line].l_close) (tp, flag);
+
+ /* Disable receiver.
+ * Transmitter continues sending the queued data. */
+ s = spltty ();
+ outb (CAR(c->chip->port), c->num & 3);
+ outb (IER(c->chip->port), IER_TXD | IER_MDM);
+ cx_cmd (c->chip->port, CCR_DISRX);
+
+ /* Clear DTR and RTS. */
+ if ((tp->t_cflag & HUPCL) || ! (tp->t_state & TS_ISOPEN)) {
+ cx_chan_dtr (c, 0);
+ cx_chan_rts (c, 0);
+ }
+
+ /* Stop sending break. */
+ if (c->brk == BRK_SEND) {
+ c->brk = BRK_STOP;
+ if (! (tp->t_state & TS_BUSY))
+ cxoproc (tp);
+ }
+ splx (s);
+ ttyclose (tp);
+ return (0);
+}
+
+int cxread (dev_t dev, struct uio *uio, int flag)
+{
+ int unit = UNIT (dev);
+ struct tty *tp;
+
+ if (unit == UNIT_CTL)
+ return (EIO);
+ tp = cxchan[unit]->ttyp;
+ return ((*linesw[tp->t_line].l_read) (tp, uio, flag));
+}
+
+int cxwrite (dev_t dev, struct uio *uio, int flag)
+{
+ int unit = UNIT (dev);
+ struct tty *tp;
+
+ if (unit == UNIT_CTL)
+ return (EIO);
+ tp = cxchan[unit]->ttyp;
+ return ((*linesw[tp->t_line].l_write) (tp, uio, flag));
+}
+
+int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ int unit = UNIT (dev);
+ cx_chan_t *c;
+ struct tty *tp;
+ int error, s;
+ unsigned char msv;
+
+ if (unit == UNIT_CTL) {
+ /* Process an ioctl request on /dev/cronyx */
+ cx_options_t *o = (cx_options_t*) data;
+
+ if (o->board >= NCX || o->channel >= NCHAN)
+ return (EINVAL);
+ c = &cxboard[o->board].chan[o->channel];
+ if (c->type == T_NONE)
+ return (ENXIO);
+ switch (cmd) {
+ default:
+ return (EINVAL);
+
+ case CXIOCSETMODE:
+ print (("cx%d.%d: CXIOCSETMODE\n", o->board, o->channel));
+ if (c->type == T_NONE)
+ return (EINVAL);
+ if (c->type == T_ASYNC && o->mode != M_ASYNC)
+ return (EINVAL);
+ if (o->mode == M_ASYNC)
+ switch (c->type) {
+ case T_SYNC_RS232:
+ case T_SYNC_V35:
+ case T_SYNC_RS449:
+ return (EINVAL);
+ }
+ /* Somebody is waiting for carrier? */
+ if (c->sopt.lock)
+ return (EBUSY);
+ /* /dev/ttyXX is already opened by someone? */
+ if (c->mode == M_ASYNC && c->ttyp &&
+ (c->ttyp->t_state & TS_ISOPEN))
+ return (EBUSY);
+ /* Network interface is up? */
+ if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP))
+ return (EBUSY);
+ c->mode = o->mode;
+ c->rxbaud = o->rxbaud;
+ c->txbaud = o->txbaud;
+ c->opt = o->opt;
+ c->aopt = o->aopt;
+ c->hopt = o->hopt;
+ c->bopt = o->bopt;
+ c->xopt = o->xopt;
+ switch (c->num) {
+ case 0: c->board->if0type = o->iftype; break;
+ case 8: c->board->if8type = o->iftype; break;
+ }
+ cxswitch (c, o->sopt);
+ s = spltty ();
+ cx_setup_chan (c);
+ outb (IER(c->chip->port), 0);
+ splx (s);
+ break;
+
+ case CXIOCGETMODE:
+ print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel));
+ o->type = c->type;
+ o->mode = c->mode;
+ o->rxbaud = c->rxbaud;
+ o->txbaud = c->txbaud;
+ o->opt = c->opt;
+ o->aopt = c->aopt;
+ o->hopt = c->hopt;
+ o->bopt = c->bopt;
+ o->xopt = c->xopt;
+ o->sopt = c->sopt;
+ switch (c->num) {
+ case 0: o->iftype = c->board->if0type; break;
+ case 8: o->iftype = c->board->if8type; break;
+ }
+ break;
+ }
+ return (0);
+ }
+
+ c = cxchan[unit];
+ tp = c->ttyp;
+ if (! tp)
+ return (EINVAL);
+#if __FreeBSD__ >= 2
+ error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, p);
+#else
+ error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag);
+#endif
+ if (error >= 0)
+ return (error);
+ error = ttioctl (tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+
+ s = spltty ();
+ switch (cmd) {
+ default:
+ splx (s);
+ return (ENOTTY);
+ case TIOCSBRK: /* Start sending line break */
+ c->brk = BRK_SEND;
+ if (! (tp->t_state & TS_BUSY))
+ cxoproc (tp);
+ break;
+ case TIOCCBRK: /* Stop sending line break */
+ c->brk = BRK_STOP;
+ if (! (tp->t_state & TS_BUSY))
+ cxoproc (tp);
+ break;
+ case TIOCSDTR: /* Set DTR */
+ cx_chan_dtr (c, 1);
+ break;
+ case TIOCCDTR: /* Clear DTR */
+ cx_chan_dtr (c, 0);
+ break;
+ case TIOCMSET: /* Set DTR/RTS */
+ cx_chan_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
+ cx_chan_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
+ break;
+ case TIOCMBIS: /* Add DTR/RTS */
+ if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 1);
+ if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 1);
+ break;
+ case TIOCMBIC: /* Clear DTR/RTS */
+ if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 0);
+ if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 0);
+ break;
+ case TIOCMGET: /* Get modem status */
+ msv = inb (MSVR(c->chip->port));
+ *(int*)data = TIOCM_LE; /* always enabled while open */
+ if (msv & MSV_DSR) *(int*)data |= TIOCM_DSR;
+ if (msv & MSV_CTS) *(int*)data |= TIOCM_CTS;
+ if (msv & MSV_CD) *(int*)data |= TIOCM_CD;
+ if (c->dtr) *(int*)data |= TIOCM_DTR;
+ if (c->rts) *(int*)data |= TIOCM_RTS;
+ break;
+ }
+ splx (s);
+ return (0);
+}
+
+/*
+ * Fill transmitter buffer with data.
+ */
+void cxout (cx_chan_t *c, char b)
+{
+ unsigned char *buf, *p, sym;
+ unsigned short port = c->chip->port, len = 0, cnt_port, sts_port;
+ struct tty *tp = c->ttyp;
+ int i;
+
+ if (! tp)
+ return;
+
+ /* Choose the buffer. */
+ if (b == 'A') {
+ buf = c->atbuf;
+ cnt_port = ATBCNT(port);
+ sts_port = ATBSTS(port);
+ } else {
+ buf = c->btbuf;
+ cnt_port = BTBCNT(port);
+ sts_port = BTBSTS(port);
+ }
+
+ /* Is it busy? */
+ if (inb (sts_port) & BSTS_OWN24) {
+ tp->t_state |= TS_BUSY;
+ return;
+ }
+
+ switch (c->brk) {
+ case BRK_SEND:
+ *buf++ = 0; /* extended transmit command */
+ *buf++ = 0x81; /* send break */
+ *buf++ = 0; /* extended transmit command */
+ *buf++ = 0x82; /* insert delay */
+ *buf++ = 250; /* 1/4 of second */
+ *buf++ = 0; /* extended transmit command */
+ *buf++ = 0x82; /* insert delay */
+ *buf++ = 250; /* + 1/4 of second */
+ len = 8;
+ c->brk = BRK_IDLE;
+ break;
+ case BRK_STOP:
+ *buf++ = 0; /* extended transmit command */
+ *buf++ = 0x83; /* stop break */
+ len = 2;
+ c->brk = BRK_IDLE;
+ break;
+ case BRK_IDLE:
+ len = RB_LEN (tp->t_out);
+ if (tp->t_iflag & IXOFF)
+ for (i=0, p=buf; i<len && p<buf+DMABUFSZ-1; ++i) {
+ sym = RB_GETC (tp->t_out);
+ /* Send XON/XOFF out of band. */
+ if (sym == tp->t_cc[VSTOP]) {
+ outb (STCR(port), STC_SNDSPC|STC_SSPC_2);
+ continue;
+ }
+ if (sym == tp->t_cc[VSTART]) {
+ outb (STCR(port), STC_SNDSPC|STC_SSPC_1);
+ continue;
+ }
+ /* Duplicate NULLs in ETC mode. */
+ if (! sym)
+ *p++ = 0;
+ *p++ = sym;
+ }
+ else
+ for (i=0, p=buf; i<len && p<buf+DMABUFSZ-1; ++i) {
+ sym = RB_GETC (tp->t_out);
+ /* Duplicate NULLs in ETC mode. */
+ if (! sym)
+ *p++ = 0;
+ *p++ = sym;
+ }
+ len = p - buf;
+ break;
+ }
+
+ /* Start transmitter. */
+ if (len) {
+ outw (cnt_port, len);
+ outb (sts_port, BSTS_INTR | BSTS_OWN24);
+ tp->t_state |= TS_BUSY;
+ print (("cx%d.%d: out %d bytes to %c\n",
+ c->board->num, c->num, len, b));
+ }
+}
+
+void cxoproc (struct tty *tp)
+{
+ int unit = UNIT (tp->t_dev);
+ cx_chan_t *c = cxchan[unit];
+ unsigned short port = c->chip->port;
+ int s = spltty ();
+
+ /* Set current channel number */
+ outb (CAR(port), c->num & 3);
+
+ if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
+ /* Start transmitter. */
+ if (! (inb (CSR(port)) & CSRA_TXEN))
+ cx_cmd (port, CCR_ENTX);
+
+ /* Determine the buffer order. */
+ if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
+ cxout (c, 'B');
+ cxout (c, 'A');
+ } else {
+ cxout (c, 'A');
+ cxout (c, 'B');
+ }
+ }
+#if defined (__FreeBSD__) && __FreeBSD__ < 2
+ if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel)
+ ttwwakeup (tp);
+#else /* FreeBSD 2.x and BSDI */
+ if (RB_LEN (tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup(TSA_OLOWAT(tp));
+ }
+ selwakeup(&tp->t_wsel);
+ }
+#endif
+ /*
+ * Enable TXMPTY interrupt,
+ * to catch the case when the second buffer is empty.
+ */
+ if ((inb (ATBSTS(port)) & BSTS_OWN24) &&
+ (inb (BTBSTS(port)) & BSTS_OWN24)) {
+ outb (IER(port), IER_RXD|IER_RET|IER_TXD|IER_TXMPTY|IER_MDM);
+ } else
+ outb (IER(port), IER_RXD|IER_RET|IER_TXD|IER_MDM);
+ splx (s);
+}
+
+int cxparam (struct tty *tp, struct termios *t)
+{
+ int unit = UNIT (tp->t_dev);
+ cx_chan_t *c = cxchan[unit];
+ unsigned short port = c->chip->port;
+ int clock, period, s;
+ cx_cor1_async_t cor1;
+
+ if (t->c_ospeed == 0) {
+ /* Clear DTR and RTS. */
+ s = spltty ();
+ cx_chan_dtr (c, 0);
+ cx_chan_rts (c, 0);
+ splx (s);
+ print (("cx%d.%d: cxparam (hangup)\n", c->board->num, c->num));
+ return (0);
+ }
+ print (("cx%d.%d: cxparam\n", c->board->num, c->num));
+
+ /* Check requested parameters. */
+ if (t->c_ospeed < 300 || t->c_ospeed > 256*1024)
+ return(EINVAL);
+ if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024))
+ return(EINVAL);
+
+#ifdef __bsdi__
+ /* CLOCAL flag set -- wakeup everybody who waits for CD. */
+ /* FreeBSD does this themselves. */
+ if (! (tp->t_cflag & CLOCAL) && (t->c_cflag & CLOCAL))
+ wakeup ((caddr_t) &tp->t_rawq);
+#endif
+ /* And copy them to tty and channel structures. */
+ c->rxbaud = tp->t_ispeed = t->c_ispeed;
+ c->txbaud = tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+
+ /* Set character length and parity mode. */
+ BYTE cor1 = 0;
+ switch (t->c_cflag & CSIZE) {
+ default:
+ case CS8: cor1.charlen = 7; break;
+ case CS7: cor1.charlen = 6; break;
+ case CS6: cor1.charlen = 5; break;
+ case CS5: cor1.charlen = 4; break;
+ }
+ if (t->c_cflag & PARENB) {
+ cor1.parmode = PARM_NORMAL;
+ cor1.ignpar = 0;
+ cor1.parity = (t->c_cflag & PARODD) ? PAR_ODD : PAR_EVEN;
+ } else {
+ cor1.parmode = PARM_NOPAR;
+ cor1.ignpar = 1;
+ }
+
+ /* Enable/disable hardware CTS. */
+ c->aopt.cor2.ctsae = (t->c_cflag & CRTSCTS) ? 1 : 0;
+ /* Handle DSR as CTS. */
+ c->aopt.cor2.dsrae = (t->c_cflag & CRTSCTS) ? 1 : 0;
+ /* Enable extended transmit command mode.
+ * Unfortunately, there is no other method for sending break. */
+ c->aopt.cor2.etc = 1;
+ /* Enable/disable hardware XON/XOFF. */
+ c->aopt.cor2.ixon = (t->c_iflag & IXON) ? 1 : 0;
+ c->aopt.cor2.ixany = (t->c_iflag & IXANY) ? 1 : 0;
+
+ /* Set the number of stop bits. */
+ if (t->c_cflag & CSTOPB)
+ c->aopt.cor3.stopb = STOPB_2;
+ else
+ c->aopt.cor3.stopb = STOPB_1;
+ /* Disable/enable passing XON/XOFF chars to the host. */
+ c->aopt.cor3.scde = (t->c_iflag & IXON) ? 1 : 0;
+ c->aopt.cor3.flowct = (t->c_iflag & IXON) ? FLOWCC_NOTPASS : FLOWCC_PASS;
+
+ c->aopt.schr1 = t->c_cc[VSTART]; /* XON */
+ c->aopt.schr2 = t->c_cc[VSTOP]; /* XOFF */
+
+ /* Set current channel number. */
+ s = spltty ();
+ outb (CAR(port), c->num & 3);
+
+ /* Set up receiver clock values. */
+ cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period);
+ c->opt.rcor.clk = clock;
+ outb (RCOR(port), BYTE c->opt.rcor);
+ outb (RBPR(port), period);
+
+ /* Set up transmitter clock values. */
+ cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period);
+ c->opt.tcor.clk = clock;
+ c->opt.tcor.ext1x = 0;
+ outb (TCOR(port), BYTE c->opt.tcor);
+ outb (TBPR(port), period);
+
+ outb (COR2(port), BYTE c->aopt.cor2);
+ outb (COR3(port), BYTE c->aopt.cor3);
+ outb (SCHR1(port), c->aopt.schr1);
+ outb (SCHR2(port), c->aopt.schr2);
+
+ if (BYTE c->aopt.cor1 != BYTE cor1) {
+ BYTE c->aopt.cor1 = BYTE cor1;
+ outb (COR1(port), BYTE c->aopt.cor1);
+ /* Any change to COR1 require reinitialization. */
+ /* Unfortunately, it may cause transmitter glitches... */
+ cx_cmd (port, CCR_INITCH);
+ }
+ splx (s);
+ return (0);
+}
+
+int cxselect (dev_t dev, int flag, struct proc *p)
+{
+ int unit = UNIT (dev);
+
+ if (unit == UNIT_CTL)
+ return (0);
+#ifdef __FreeBSD__
+ return (ttselect (dev, flag, p));
+#endif
+#ifdef __bsdi__
+ return (ttyselect (cxchan[unit]->ttyp, flag, p));
+#endif
+}
+
+/*
+ * Stop output on a line
+ */
+void cxstop (struct tty *tp, int flag)
+{
+ cx_chan_t *c = cxchan[UNIT(tp->t_dev)];
+ unsigned short port = c->chip->port;
+ int s = spltty ();
+
+ if (tp->t_state & TS_BUSY) {
+ print (("cx%d.%d: cxstop\n", c->board->num, c->num));
+
+ /* Set current channel number */
+ outb (CAR(port), c->num & 3);
+
+ /* Stop transmitter */
+ cx_cmd (port, CCR_DISTX);
+ }
+ splx (s);
+}
+
+/*
+ * Handle receive interrupts, including receive errors and
+ * receive timeout interrupt.
+ */
+int cxrinta (cx_chan_t *c)
+{
+ unsigned short port = c->chip->port;
+ unsigned short len = 0, risr = inw (RISR(port)), reoir = 0;
+ struct tty *tp = c->ttyp;
+
+ /* Compute optimal receiver buffer length. */
+ int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
+ if (rbsz < 4)
+ rbsz = 4;
+ else if (rbsz > DMABUFSZ)
+ rbsz = DMABUFSZ;
+
+ if (risr & RISA_TIMEOUT) {
+ unsigned long rcbadr = (unsigned short) inw (RCBADRL(port)) |
+ (long) inw (RCBADRU(port)) << 16;
+ unsigned char *buf = 0;
+ unsigned short cnt_port = 0, sts_port = 0;
+ if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) {
+ buf = c->brbuf;
+ len = rcbadr - c->brphys;
+ cnt_port = BRBCNT(port);
+ sts_port = BRBSTS(port);
+ } else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) {
+ buf = c->arbuf;
+ len = rcbadr - c->arphys;
+ cnt_port = ARBCNT(port);
+ sts_port = ARBSTS(port);
+ } else
+ printf ("cx%d.%d: timeout: invalid buffer address\n",
+ c->board->num, c->num);
+
+ if (len) {
+ print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n",
+ c->board->num, c->num, len, risr, RISA_BITS,
+ inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
+ if (tp && (tp->t_state & TS_ISOPEN)) {
+ int i;
+ void (*rint)() = (void(*)())
+ linesw[tp->t_line].l_rint;
+
+ for (i=0; i<len; ++i)
+ (*rint) (buf[i], tp);
+ }
+
+ /* Restart receiver. */
+ outw (cnt_port, rbsz);
+ outb (sts_port, BSTS_OWN24);
+ }
+ return (REOI_TERMBUFF);
+ }
+
+ print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
+ c->board->num, c->num, risr, RISA_BITS,
+ inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
+
+ if (risr & RIS_BUSERR)
+ printf ("cx%d.%d: receive bus error\n", c->board->num, c->num);
+
+ if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR)) {
+ print (("cx%d.%d: receive error\n", c->board->num, c->num));
+ if (tp && (tp->t_state & TS_ISOPEN))
+ (*linesw[tp->t_line].l_rint) (' ' |
+ (risr & RISA_FRERR) ? TTY_FE : TTY_PE, tp);
+ }
+
+ /* Handle line break condition. */
+ if ((risr & RISA_BREAK) && tp && (tp->t_state & TS_ISOPEN))
+ (*linesw[tp->t_line].l_rint) (TTY_FE, tp);
+
+ /* Discard exception characters. */
+ if ((risr & RISA_SCMASK) && (tp->t_iflag & IXON))
+ reoir |= REOI_DISCEXC;
+
+ /* Handle received data. */
+ if ((risr & RIS_EOBUF) && tp && (tp->t_state & TS_ISOPEN)) {
+ void (*rint)() = (void(*)()) linesw[tp->t_line].l_rint;
+ unsigned char *buf;
+ int i;
+
+ len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
+
+ print (("cx%d.%d: async: %d bytes received\n",
+ c->board->num, c->num, len));
+
+ buf = (risr & RIS_BB) ? c->brbuf : c->arbuf;
+ for (i=0; i<len; ++i)
+ (*rint) (buf[i], tp);
+ }
+
+ /* Restart receiver. */
+ if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
+ outw (ARBCNT(port), rbsz);
+ outb (ARBSTS(port), BSTS_OWN24);
+ }
+ if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
+ outw (BRBCNT(port), rbsz);
+ outb (BRBSTS(port), BSTS_OWN24);
+ }
+ return (reoir);
+}
+
+/*
+ * Handle transmit interrupt.
+ */
+void cxtinta (cx_chan_t *c)
+{
+ struct tty *tp = c->ttyp;
+ unsigned short port = c->chip->port;
+ unsigned char tisr = inb (TISR(port));
+
+ print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
+ c->board->num, c->num, tisr, TIS_BITS,
+ inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS));
+
+ if (tisr & TIS_BUSERR)
+ printf ("cx%d.%d: transmit bus error\n",
+ c->board->num, c->num);
+ else if (tisr & TIS_UNDERRUN)
+ printf ("cx%d.%d: transmit underrun error\n",
+ c->board->num, c->num);
+
+ if (tp) {
+ tp->t_state &= ~(TS_BUSY | TS_FLUSH);
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start) (tp);
+ else
+ cxoproc (tp);
+ }
+}
+
+/*
+ * Handle modem interrupt.
+ */
+void cxmint (cx_chan_t *c)
+{
+ unsigned short port = c->chip->port;
+ unsigned char misr = inb (MISR(port));
+ unsigned char msvr = inb (MSVR(port));
+ struct tty *tp = c->ttyp;
+
+ if (c->mode != M_ASYNC) {
+ printf ("cx%d.%d: unexpected modem interrupt, misr=%b, msvr=%b\n",
+ c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS);
+ return;
+ }
+ print (("cx%d.%d: modem interrupt, misr=%b, msvr=%b\n",
+ c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS));
+
+ /* Ignore DSR events. */
+ /* Ignore RTC/CTS events, handled by hardware. */
+ /* Handle carrier detect/loss. */
+ if (tp && (misr & MIS_CCD))
+ (*linesw[tp->t_line].l_modem) (tp, (msvr & MSV_CD) != 0);
+}
+
+/*
+ * Recover after lost transmit interrupts.
+ */
+void cxtimeout (caddr_t a)
+{
+ cx_board_t *b;
+ cx_chan_t *c;
+ struct tty *tp;
+ int s;
+
+ for (b=cxboard; b<cxboard+NCX; ++b)
+ for (c=b->chan; c<b->chan+NCHAN; ++c) {
+ tp = c->ttyp;
+ if (c->type==T_NONE || c->mode!=M_ASYNC || !tp)
+ continue;
+ s = spltty ();
+ if (tp->t_state & TS_BUSY) {
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start) (tp);
+ else
+ cxoproc (tp);
+ }
+ splx (s);
+ }
+ timeout ((timeout_func_t) cxtimeout, 0, hz*5);
+}
+#endif /* NCX */
diff --git a/sys/i386/isa/cxreg.h b/sys/i386/isa/cxreg.h
new file mode 100644
index 0000000..491c7fb
--- /dev/null
+++ b/sys/i386/isa/cxreg.h
@@ -0,0 +1,429 @@
+/*
+ * Defines for Cronyx-Sigma adapter, based on Cirrus Logic multiprotocol
+ * controller RISC processor CL-CD2400/2401.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.0, Fri Oct 7 19:34:06 MSD 1994
+ */
+#define NBRD 3 /* the maximum number of installed boards */
+#define NPORT 16 /* the number of i/o ports per board */
+
+#define REVCL_MIN 7 /* CD2400 min. revision number G */
+#define REVCL_MAX 11 /* CD2400 max. revision number K */
+
+#define BRD_INTR_LEVEL 0x5a /* interrupt level (arbitrary PILR value) */
+
+#define CS0(p) ((p) | 0x8000) /* chip select 0 */
+#define CS1(p) ((p) | 0xc000) /* chip select 1 */
+#define BSR(p) (p) /* board status register, read only */
+#define BCR0(p) (p) /* board command register 0, write only */
+#define BCR1(p) ((p) | 0x2000) /* board command register 1, write only */
+
+/*
+ * Chip register address, B is chip base port, R is chip register number.
+ */
+#define R(b,r) ((b) | (((r)<<6 & 0x3c00) | ((r) & 0xf)))
+
+/*
+ * Interrupt acknowledge register, P is board port, L is interrupt level,
+ * as prodrammed in PILR.
+ */
+#define IACK(p,l) (R(p,l) | 0x4000)
+
+/*
+ * Global registers.
+ */
+#define GFRCR(b) R(b,0x82) /* global firmware revision code register */
+#define CAR(b) R(b,0xec) /* channel access register */
+
+/*
+ * Option registers.
+ */
+#define CMR(b) R(b,0x18) /* channel mode register */
+#define COR1(b) R(b,0x13) /* channel option register 1 */
+#define COR2(b) R(b,0x14) /* channel option register 2 */
+#define COR3(b) R(b,0x15) /* channel option register 3 */
+#define COR4(b) R(b,0x16) /* channel option register 4 */
+#define COR5(b) R(b,0x17) /* channel option register 5 */
+#define COR6(b) R(b,0x1b) /* channel option register 6 */
+#define COR7(b) R(b,0x04) /* channel option register 7 */
+#define SCHR1(b) R(b,0x1c) /* special character register 1 */
+#define SCHR2(b) R(b,0x1d) /* special character register 2 */
+#define SCHR3(b) R(b,0x1e) /* special character register 3 */
+#define SCHR4(b) R(b,0x1f) /* special character register 4 */
+#define SCRL(b) R(b,0x20) /* special character range low */
+#define SCRH(b) R(b,0x21) /* special character range high */
+#define LNXT(b) R(b,0x2d) /* LNext character */
+#define RFAR1(b) R(b,0x1c) /* receive frame address register 1 */
+#define RFAR2(b) R(b,0x1d) /* receive frame address register 2 */
+#define RFAR3(b) R(b,0x1e) /* receive frame address register 3 */
+#define RFAR4(b) R(b,0x1f) /* receive frame address register 4 */
+#define CPSR(b) R(b,0xd4) /* CRC polynomial select register */
+
+/*
+ * Bit rate and clock option registers.
+ */
+#define RBPR(b) R(b,0xc9) /* receive baud rate period register */
+#define RCOR(b) R(b,0xca) /* receive clock option register */
+#define TBPR(b) R(b,0xc1) /* transmit baud rate period register */
+#define TCOR(b) R(b,0xc2) /* receive clock option register */
+
+/*
+ * Channel command and status registers.
+ */
+#define CCR(b) R(b,0x10) /* channel command register */
+#define STCR(b) R(b,0x11) /* special transmit command register */
+#define CSR(b) R(b,0x19) /* channel status register */
+#define MSVR(b) R(b,0xdc) /* modem signal value register */
+#define MSVR_RTS(b) R(b,0xdc) /* modem RTS setup register */
+#define MSVR_DTR(b) R(b,0xdd) /* modem DTR setup register */
+
+/*
+ * Interrupt registers.
+ */
+#define LIVR(b) R(b,0x0a) /* local interrupt vector register */
+#define IER(b) R(b,0x12) /* interrupt enable register */
+#define LICR(b) R(b,0x25) /* local interrupting channel register */
+#define STK(b) R(b,0xe0) /* stack register */
+
+/*
+ * Receive interrupt registers.
+ */
+#define RPILR(b) R(b,0xe3) /* receive priority interrupt level register */
+#define RIR(b) R(b,0xef) /* receive interrupt register */
+#define RISR(b) R(b,0x8a) /* receive interrupt status register */
+#define RISRL(b) R(b,0x8a) /* receive interrupt status register low */
+#define RISRH(b) R(b,0x8b) /* receive interrupt status register high */
+#define RFOC(b) R(b,0x33) /* receive FIFO output count */
+#define RDR(b) R(b,0xf8) /* receive data register */
+#define REOIR(b) R(b,0x87) /* receive end of interrupt register */
+
+/*
+ * Transmit interrupt registers.
+ */
+#define TPILR(b) R(b,0xe2) /* transmit priority interrupt level reg */
+#define TIR(b) R(b,0xee) /* transmit interrupt register */
+#define TISR(b) R(b,0x89) /* transmit interrupt status register */
+#define TFTC(b) R(b,0x83) /* transmit FIFO transfer count */
+#define TDR(b) R(b,0xf8) /* transmit data register */
+#define TEOIR(b) R(b,0x86) /* transmit end of interrupt register */
+
+/*
+ * Modem interrupt registers.
+ */
+#define MPILR(b) R(b,0xe1) /* modem priority interrupt level register */
+#define MIR(b) R(b,0xed) /* modem interrupt register */
+#define MISR(b) R(b,0x88) /* modem/timer interrupt status register */
+#define MEOIR(b) R(b,0x85) /* modem end of interrupt register */
+
+/*
+ * DMA registers.
+ */
+#define DMR(b) R(b,0xf4) /* DMA mode register */
+#define BERCNT(b) R(b,0x8d) /* bus error retry count */
+#define DMABSTS(b) R(b,0x1a) /* DMA buffer status */
+
+/*
+ * DMA receive registers.
+ */
+#define ARBADRL(b) R(b,0x40) /* A receive buffer address lower */
+#define ARBADRU(b) R(b,0x42) /* A receive buffer address upper */
+#define BRBADRL(b) R(b,0x44) /* B receive buffer address lower */
+#define BRBADRU(b) R(b,0x46) /* B receive buffer address upper */
+#define ARBCNT(b) R(b,0x48) /* A receive buffer byte count */
+#define BRBCNT(b) R(b,0x4a) /* B receive buffer byte count */
+#define ARBSTS(b) R(b,0x4c) /* A receive buffer status */
+#define BRBSTS(b) R(b,0x4d) /* B receive buffer status */
+#define RCBADRL(b) R(b,0x3c) /* receive current buffer address lower */
+#define RCBADRU(b) R(b,0x3e) /* receive current buffer address upper */
+
+/*
+ * DMA transmit registers.
+ */
+#define ATBADRL(b) R(b,0x50) /* A transmit buffer address lower */
+#define ATBADRU(b) R(b,0x52) /* A transmit buffer address upper */
+#define BTBADRL(b) R(b,0x54) /* B transmit buffer address lower */
+#define BTBADRU(b) R(b,0x56) /* B transmit buffer address upper */
+#define ATBCNT(b) R(b,0x58) /* A transmit buffer byte count */
+#define BTBCNT(b) R(b,0x5a) /* B transmit buffer byte count */
+#define ATBSTS(b) R(b,0x5c) /* A transmit buffer status */
+#define BTBSTS(b) R(b,0x5d) /* B transmit buffer status */
+#define TCBADRL(b) R(b,0x38) /* transmit current buffer address lower */
+#define TCBADRU(b) R(b,0x3a) /* transmit current buffer address upper */
+
+/*
+ * Timer registers.
+ */
+#define TPR(b) R(b,0xd8) /* timer period register */
+#define RTPR(b) R(b,0x26) /* receive timeout period register */
+#define RTPRL(b) R(b,0x26) /* receive timeout period register low */
+#define RTPTH(b) R(b,0x27) /* receive timeout period register high */
+#define GT1(b) R(b,0x28) /* general timer 1 */
+#define GT1L(b) R(b,0x28) /* general timer 1 low */
+#define GT1H(b) R(b,0x29) /* general timer 1 high */
+#define GT2(b) R(b,0x2a) /* general timer 2 */
+#define TTR(b) R(b,0x2a) /* transmit timer register */
+
+/*
+ * Board status register bits.
+ */
+#define BSR_NOINTR 0x01 /* no interrupt pending flag */
+
+#define BSR_VAR_MASK 0x66 /* adapter variant mask */
+
+#define BSR_OSC_MASK 0x18 /* oscillator frequency mask */
+#define BSR_OSC_20 0x18 /* 20 MHz */
+#define BSR_OSC_18432 0x10 /* 18.432 MHz */
+
+#define BSR_NOCHAIN 0x80 /* no daisy chained board */
+
+#define BSR_NODSR(n) (0x100 << (n)) /* DSR from channels 0-3, inverted */
+#define BSR_NOCD(n) (0x1000 << (n)) /* CD from channels 0-3, inverted */
+
+/*
+ * Board revision mask.
+ */
+#define BSR_REV_MASK (BSR_OSC_MASK|BSR_VAR_MASK|BSR_NOCHAIN)
+
+/*
+ * Board control register 0 bits.
+ */
+#define BCR0_IRQ_DIS 0x00 /* no interrupt generated */
+#define BCR0_IRQ_3 0x01 /* select IRQ number 3 */
+#define BCR0_IRQ_5 0x02 /* select IRQ number 5 */
+#define BCR0_IRQ_7 0x03 /* select IRQ number 7 */
+#define BCR0_IRQ_10 0x04 /* select IRQ number 10 */
+#define BCR0_IRQ_11 0x05 /* select IRQ number 11 */
+#define BCR0_IRQ_12 0x06 /* select IRQ number 12 */
+#define BCR0_IRQ_15 0x07 /* select IRQ number 15 */
+
+#define BCR0_NORESET 0x08 /* CD2400 reset flag (inverted) */
+
+#define BCR0_DMA_DIS 0x00 /* no interrupt generated */
+#define BCR0_DMA_5 0x10 /* select DMA channel 5 */
+#define BCR0_DMA_6 0x20 /* select DMA channel 6 */
+#define BCR0_DMA_7 0x30 /* select DMA channel 7 */
+
+#define BCR0_UM_ASYNC 0x00 /* channel 0 mode - async */
+#define BCR0_UM_SYNC 0x80 /* channel 0 mode - sync */
+#define BCR0_UI_RS232 0x00 /* channel 0 interface - RS-232 */
+#define BCR0_UI_RS449 0x40 /* channel 0 interface - RS-449/V.35 */
+#define BCR0_UMASK 0xc0 /* channel 0 interface mask */
+
+/*
+ * Board control register 1 bits.
+ */
+#define BCR1_DTR(n) (0x100 << (n)) /* DTR for channels 0-3 sync */
+
+/*
+ * Cronyx board variants.
+ */
+#define CRONYX_100 0x64
+#define CRONYX_400 0x62
+#define CRONYX_500 0x60
+#define CRONYX_410 0x24
+#define CRONYX_810 0x20
+#define CRONYX_410s 0x04
+#define CRONYX_810s 0x00
+#define CRONYX_440 0x44
+#define CRONYX_840 0x40
+#define CRONYX_401 0x26
+#define CRONYX_801 0x22
+#define CRONYX_401s 0x06
+#define CRONYX_801s 0x02
+#define CRONYX_404 0x46
+#define CRONYX_703 0x42
+
+/*
+ * Channel commands (CCR).
+ */
+#define CCR_CLRCH 0x40 /* clear channel */
+#define CCR_INITCH 0x20 /* initialize channel */
+#define CCR_RSTALL 0x10 /* reset all channels */
+#define CCR_ENTX 0x08 /* enable transmitter */
+#define CCR_DISTX 0x04 /* disable transmitter */
+#define CCR_ENRX 0x02 /* enable receiver */
+#define CCR_DISRX 0x01 /* disable receiver */
+#define CCR_CLRT1 0xc0 /* clear timer 1 */
+#define CCR_CLRT2 0xa0 /* clear timer 2 */
+#define CCR_CLRRCV 0x90 /* clear receiver */
+
+/*
+ * Interrupt enable register (IER) bits.
+ */
+#define IER_MDM 0x80 /* modem status changed */
+#define IER_RET 0x20 /* receive exception timeout */
+#define IER_RXD 0x08 /* data received */
+#define IER_TIMER 0x04 /* timer expired */
+#define IER_TXMPTY 0x02 /* transmitter empty */
+#define IER_TXD 0x01 /* data transmitted */
+
+/*
+ * Modem signal values register bits (MSVR).
+ */
+#define MSV_DSR 0x80 /* state of Data Set Ready input */
+#define MSV_CD 0x40 /* state of Carrier Detect input */
+#define MSV_CTS 0x20 /* state of Clear to Send input */
+#define MSV_TXCOUT 0x10 /* TXCout/DTR pin output flag */
+#define MSV_PORTID 0x04 /* device is CL-CD2401 (not 2400) */
+#define MSV_DTR 0x02 /* state of Data Terminal Ready output */
+#define MSV_RTS 0x01 /* state of Request to Send output */
+#define MSV_BITS "\20\1rts\2dtr\3cd2400\5txcout\6cts\7cd\10dsr"
+
+/*
+ * DMA buffer status register bits (DMABSTS).
+ */
+#define DMABSTS_TDALIGN 0x80 /* internal data alignment in transmit FIFO */
+#define DMABSTS_RSTAPD 0x40 /* reset append mode */
+#define DMABSTS_CRTTBUF 0x20 /* internal current transmit buffer in use */
+#define DMABSTS_APPEND 0x10 /* append buffer is in use */
+#define DMABSTS_NTBUF 0x08 /* next transmit buffer is B (not A) */
+#define DMABSTS_TBUSY 0x04 /* current transmit buffer is in use */
+#define DMABSTS_NRBUF 0x02 /* next receive buffer is B (not A) */
+#define DMABSTS_RBUSY 0x01 /* current receive buffer is in use */
+
+/*
+ * Buffer status register bits ([AB][RT]BSTS).
+ */
+#define BSTS_BUSERR 0x80 /* bus error */
+#define BSTS_EOFR 0x40 /* end of frame */
+#define BSTS_EOBUF 0x20 /* end of buffer */
+#define BSTS_APPEND 0x08 /* append mode */
+#define BSTS_INTR 0x02 /* interrupt required */
+#define BSTS_OWN24 0x01 /* buffer is (free to be) used by CD2400 */
+#define BSTS_BITS "\20\1own24\2intr\4append\6eobuf\7eofr\10buserr"
+
+/*
+ * Receive interrupt status register (RISR) bits.
+ */
+#define RIS_OVERRUN 0x0008 /* overrun error */
+#define RIS_BB 0x0800 /* buffer B status (not A) */
+#define RIS_EOBUF 0x2000 /* end of buffer reached */
+#define RIS_EOFR 0x4000 /* frame reception complete */
+#define RIS_BUSERR 0x8000 /* bus error */
+
+#define RISH_CLRDCT 0x0001 /* X.21 clear detect */
+#define RISH_RESIND 0x0004 /* residual indication */
+#define RISH_CRCERR 0x0010 /* CRC error */
+#define RISH_RXABORT 0x0020 /* abort sequence received */
+#define RISH_EOFR 0x0040 /* complete frame received */
+#define RISH_BITS "\20\1clrdct\3resind\4overrun\5crcerr\6rxabort\7eofr\14bb\16eobuf\17eofr\20buserr"
+
+#define RISA_BREAK 0x0001 /* break signal detected */
+#define RISA_FRERR 0x0002 /* frame error (bad stop bits) */
+#define RISA_PARERR 0x0004 /* parity error */
+#define RISA_SCMASK 0x0070 /* special character detect mask */
+#define RISA_SCHR1 0x0010 /* special character 1 detected */
+#define RISA_SCHR2 0x0020 /* special character 2 detected */
+#define RISA_SCHR3 0x0030 /* special character 3 detected */
+#define RISA_SCHR4 0x0040 /* special character 4 detected */
+#define RISA_SCRANGE 0x0070 /* special character in range detected */
+#define RISA_TIMEOUT 0x0080 /* receive timeout, no data */
+#define RISA_BITS "\20\1break\2frerr\3parerr\4overrun\5schr1\6schr2\7schr4\10timeout\14bb\16eobuf\17eofr\20buserr"
+
+#define RISB_CRCERR 0x0010 /* CRC error */
+#define RISB_RXABORT 0x0020 /* abort sequence received */
+#define RISB_EOFR 0x0040 /* complete frame received */
+
+#define RISX_LEADCHG 0x0001 /* CTS lead change */
+#define RISX_PARERR 0x0004 /* parity error */
+#define RISX_SCMASK 0x0070 /* special character detect mask */
+#define RISX_SCHR1 0x0010 /* special character 1 detected */
+#define RISX_SCHR2 0x0020 /* special character 2 detected */
+#define RISX_SCHR3 0x0030 /* special character 3 detected */
+#define RISX_ALLZERO 0x0040 /* all 0 condition detected */
+#define RISX_ALLONE 0x0050 /* all 1 condition detected */
+#define RISX_ALTOZ 0x0060 /* alternating 1 0 condition detected */
+#define RISX_SYN 0x0070 /* SYN detected */
+#define RISX_LEAD 0x0080 /* leading value */
+
+/*
+ * Channel mode register (CMR) bits.
+ */
+#define CMR_RXDMA 0x80 /* DMA receive transfer mode */
+#define CMR_TXDMA 0x40 /* DMA transmit transfer mode */
+#define CMR_HDLC 0x00 /* HDLC protocol mode */
+#define CMR_BISYNC 0x01 /* BISYNC protocol mode */
+#define CMR_ASYNC 0x02 /* ASYNC protocol mode */
+#define CMR_X21 0x03 /* X.21 protocol mode */
+
+/*
+ * Modem interrupt status register (MISR) bits.
+ */
+#define MIS_CDSR 0x80 /* DSR changed */
+#define MIS_CCD 0x40 /* CD changed */
+#define MIS_CCTS 0x20 /* CTS changed */
+#define MIS_CGT2 0x02 /* GT2 timer expired */
+#define MIS_CGT1 0x01 /* GT1 timer expired */
+#define MIS_BITS "\20\1gt1\2gt2\6ccts\7ccd\10cdsr"
+
+/*
+ * Transmit interrupt status register (TISR) bits.
+ */
+#define TIS_BUSERR 0x80 /* Bus error */
+#define TIS_EOFR 0x40 /* End of frame */
+#define TIS_EOBUF 0x20 /* end of transmit buffer reached */
+#define TIS_UNDERRUN 0x10 /* transmit underrun */
+#define TIS_BB 0x08 /* buffer B status (not A) */
+#define TIS_TXEMPTY 0x02 /* transmitter empty */
+#define TIS_TXDATA 0x01 /* transmit data below threshold */
+#define TIS_BITS "\20\1txdata\2txempty\4bb\5underrun\6eobuf\7eofr\10buserr"
+
+/*
+ * Local interrupt vector register (LIVR) bits.
+ */
+#define LIV_EXCEP 0
+#define LIV_MODEM 1
+#define LIV_TXDATA 2
+#define LIV_RXDATA 3
+
+/*
+ * Transmit end of interrupt registers (TEOIR) bits.
+ */
+#define TEOI_TERMBUFF 0x80 /* force current buffer to be discarded */
+#define TEOI_EOFR 0x40 /* end of frame in interrupt mode */
+#define TEOI_SETTM2 0x20 /* set general timer 2 in sync mode */
+#define TEOI_SETTM1 0x10 /* set general timer 1 in sync mode */
+#define TEOI_NOTRANSF 0x08 /* no transfer of data on this interrupt */
+
+/*
+ * Receive end of interrupt registers (REOIR) bits.
+ */
+#define REOI_TERMBUFF 0x80 /* force current buffer to be terminated */
+#define REOI_DISCEXC 0x40 /* discard exception character */
+#define REOI_SETTM2 0x20 /* set general timer 2 */
+#define REOI_SETTM1 0x10 /* set general timer 1 */
+#define REOI_NOTRANSF 0x08 /* no transfer of data */
+#define REOI_GAP_MASK 0x07 /* optional gap size to leave in buffer */
+
+/*
+ * Special transmit command register (STCR) bits.
+ */
+#define STC_ABORTTX 0x40 /* abort transmission (HDLC mode) */
+#define STC_APPDCMP 0x20 /* append complete (async DMA mode) */
+#define STC_SNDSPC 0x08 /* send special characters (async mode) */
+#define STC_SSPC_MASK 0x07 /* special character select */
+#define STC_SSPC_1 0x01 /* send special character #1 */
+#define STC_SSPC_2 0x02 /* send special character #2 */
+#define STC_SSPC_3 0x03 /* send special character #3 */
+#define STC_SSPC_4 0x04 /* send special character #4 */
+
+/*
+ * Channel status register (CSR) bits, asynchronous mode.
+ */
+#define CSRA_RXEN 0x80 /* receiver enable */
+#define CSRA_RXFLOFF 0x40 /* receiver flow off */
+#define CSRA_RXFLON 0x20 /* receiver flow on */
+#define CSRA_TXEN 0x08 /* transmitter enable */
+#define CSRA_TXFLOFF 0x04 /* transmitter flow off */
+#define CSRA_TXFLON 0x02 /* transmitter flow on */
+#define CSRA_BITS "\20\2txflon\3txfloff\4txen\6rxflon\7rxfloff\10rxen"
diff --git a/sys/i386/isa/if_cx.c b/sys/i386/isa/if_cx.c
new file mode 100644
index 0000000..d6c0367
--- /dev/null
+++ b/sys/i386/isa/if_cx.c
@@ -0,0 +1,818 @@
+/*
+ * Cronyx-Sigma adapter driver for FreeBSD.
+ * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
+ * and asyncronous channels with full modem control.
+ * Keepalive protocol implemented in both Cisco and PPP modes.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.2, Tue Nov 22 18:57:27 MSK 1994
+ */
+#undef DEBUG
+
+#include "cx.h"
+#if NCX > 0
+#include <bpfilter.h>
+
+#include <sys/param.h>
+#include <systm.h>
+#include <kernel.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/conf.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#ifdef __FreeBSD__
+# include <i386/isa/isa_device.h>
+# if __FreeBSD__ < 2
+# include <i386/include/pio.h>
+# else
+# include <i386/include/cpufunc.h>
+# include <sys/devconf.h>
+# endif
+# define init_func_t void(*)(int)
+# define watchdog_func_t void(*)(int)
+# define start_func_t void(*)(struct ifnet*)
+#endif
+
+#ifdef __bsdi__
+# if INET
+# include <netinet/in.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# endif
+# include <sys/device.h>
+# include <i386/isa/isavar.h>
+# include <i386/isa/icu.h>
+# include <i386/include/inline.h>
+# include <net/if_slvar.h>
+# include <net/if_p2p.h>
+# define timeout_func_t void(*)()
+# define init_func_t int(*)()
+# define watchdog_func_t int(*)()
+# define start_func_t int(*)()
+struct cxsoftc {
+ struct device dev; /* base device */
+ struct isadev isadev; /* ISA device */
+ struct intrhand intr; /* interrupt vectoring */
+};
+#endif
+
+#include <net/if_sppp.h>
+#include <sys/cronyx.h>
+#include <i386/isa/cxreg.h>
+
+#ifdef DEBUG
+# define print(s) printf s
+#else
+# define print(s) /*void*/
+#endif
+
+#define TXTIMEOUT 2 /* transmit timeout in seconds */
+#define DMABUFSZ (6*256) /* buffer size */
+#define PPP_HEADER_LEN 4 /* size of PPP header */
+
+/*
+ * Under BSDI it's possible to use general p2p protocol scheme,
+ * as well as our own one. Switching is done via IFF_ALTPHYS flag.
+ * Our ifnet pointer holds the buffer large enough to contain
+ * any of sppp and p2p structures.
+ */
+#ifdef __bsdi__
+# define SPPPSZ (sizeof (struct sppp))
+# define P2PSZ (sizeof (struct p2pcom))
+# define IFSTRUCTSZ (SPPPSZ>P2PSZ ? SPPPSZ : P2PSZ)
+#else
+# define IFSTRUCTSZ (sizeof (struct sppp))
+#endif
+#define IFNETSZ (sizeof (struct ifnet))
+
+int cxoutput (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt);
+int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data);
+void cxinit (int unit);
+void cxstart (struct ifnet *ifp);
+void cxwatchdog (int unit);
+void cxinput (cx_chan_t *c, void *buf, unsigned len);
+int cxrinta (cx_chan_t *c);
+void cxtinta (cx_chan_t *c);
+void cxmint (cx_chan_t *c);
+void cxtimeout (caddr_t a);
+
+cx_board_t cxboard [NCX]; /* adapter state structures */
+cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */
+
+static unsigned short irq_valid_values [] = { 3, 5, 7, 10, 11, 12, 15, 0 };
+static unsigned short drq_valid_values [] = { 5, 6, 7, 0 };
+static unsigned short port_valid_values [] = {
+ 0x240, 0x260, 0x280, 0x300, 0x320, 0x380, 0x3a0, 0,
+};
+
+#if __FreeBSD__ >= 2
+static char cxdescription [80];
+struct kern_devconf kdc_cx [NCX] = { {
+ 0, 0, 0, "cx", 0, { MDDT_ISA, 0, "net" },
+ isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, &kdc_isa0, 0,
+ DC_IDLE, cxdescription,
+} };
+#endif
+
+/*
+ * Check that the value is contained in the list of correct values.
+ */
+static int valid (unsigned short value, unsigned short *list)
+{
+ while (*list)
+ if (value == *list++)
+ return (1);
+ return (0);
+}
+
+/*
+ * Print the mbuf chain, for debug purposes only.
+ */
+static void printmbuf (struct mbuf *m)
+{
+ printf ("mbuf:");
+ for (; m; m=m->m_next) {
+ if (m->m_flags & M_PKTHDR)
+ printf (" HDR %d:", m->m_pkthdr.len);
+ if (m->m_flags & M_EXT)
+ printf (" EXT:");
+ printf (" %d", m->m_len);
+ }
+ printf ("\n");
+}
+
+/*
+ * Make an mbuf from data.
+ */
+static struct mbuf *makembuf (void *buf, unsigned len)
+{
+ struct mbuf *m, *o, *p;
+
+ MGETHDR (m, M_DONTWAIT, MT_DATA);
+ if (! m)
+ return (0);
+ if (len >= MINCLSIZE)
+ MCLGET (m, M_DONTWAIT);
+ m->m_pkthdr.len = len;
+ m->m_len = 0;
+
+ p = m;
+ while (len) {
+ unsigned n = M_TRAILINGSPACE (p);
+ if (n > len)
+ n = len;
+
+ if (! n) {
+ /* Allocate new mbuf. */
+ o = p;
+ MGET (p, M_DONTWAIT, MT_DATA);
+ if (! p) {
+ m_freem (m);
+ return (0);
+ }
+ if (len >= MINCLSIZE)
+ MCLGET (p, M_DONTWAIT);
+ p->m_len = 0;
+ o->m_next = p;
+
+ n = M_TRAILINGSPACE (p);
+ if (n > len)
+ n = len;
+ }
+
+ bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
+
+ p->m_len += n;
+ buf += n;
+ len -= n;
+ }
+ return (m);
+}
+
+/*
+ * Test the presence of the adapter on the given i/o port.
+ */
+#ifdef __FreeBSD__
+int cxprobe (struct isa_device *id)
+{
+ int unit = id->id_unit;
+ int iobase = id->id_iobase;
+ int irq = id->id_irq;
+ int drq = id->id_drq;
+ int irqnum;
+#endif
+#ifdef __bsdi__
+int cxprobe (struct device *parent, struct cfdata *cf, void *aux)
+{
+ int unit = cf->cf_unit;
+ int iobase = ((struct isa_attach_args*)aux)->ia_iobase;
+ int irq = ((struct isa_attach_args*)aux)->ia_irq;
+ int drq = ((struct isa_attach_args*)aux)->ia_drq;
+ int irqnum, i;
+
+ for (i=0; i<NCX; ++i)
+ if (i != unit && cxboard[i].port == iobase)
+ return (0);
+ if (irq == IRQUNK) {
+ irq = isa_irqalloc (IRQ3|IRQ5|IRQ7|IRQ10|IRQ11|IRQ12|IRQ15);
+ if (! irq)
+ return (0);
+ ((struct isa_attach_args*)aux)->ia_irq = irq;
+ }
+#endif
+ irqnum = ffs (irq) - 1;
+
+ print (("cx%d: probe iobase=0x%x irq=%d drq=%d\n",
+ unit, iobase, irqnum, drq));
+ if (! valid (irqnum, irq_valid_values)) {
+ printf ("cx%d: Incorrect IRQ: %d\n", unit, irqnum);
+ return (0);
+ }
+ if (! valid (iobase, port_valid_values)) {
+ printf ("cx%d: Incorrect port address: 0x%x\n", unit, iobase);
+ return (0);
+ }
+ if (! valid (drq, drq_valid_values)) {
+ printf ("cx%d: Incorrect DMA channel: %d\n", unit, drq);
+ return (0);
+ }
+ if (! cx_probe_board (iobase))
+ return (0);
+ return (1);
+}
+
+/*
+ * The adapter is present, initialize the driver structures.
+ */
+#ifdef __FreeBSD__
+int cxattach (struct isa_device *id)
+{
+ int unit = id->id_unit;
+ int iobase = id->id_iobase;
+ int irq = id->id_irq;
+ int drq = id->id_drq;
+#endif
+#ifdef __bsdi__
+void cxattach (struct device *parent, struct device *self, void *aux)
+{
+ int unit = self->dv_unit;
+ int iobase = ((struct isa_attach_args*)aux)->ia_iobase;
+ int irq = ((struct isa_attach_args*)aux)->ia_irq;
+ int drq = ((struct isa_attach_args*)aux)->ia_drq;
+ struct cxsoftc *sc = (struct cxsoftc*) self;
+ void cxintr (cx_board_t *b);
+#endif
+ cx_board_t *b = cxboard + unit;
+ int i;
+
+ /* Initialize the board structure. */
+ cx_init (b, unit, iobase, ffs(irq)-1, drq);
+
+ for (i=0; i<NCHAN; ++i) {
+ cx_chan_t *c = b->chan + i;
+ int u = b->num*NCHAN + i;
+ cxchan[u] = c;
+
+ if (c->type == T_NONE)
+ continue;
+
+ /* Allocate the buffer memory. */
+ c->arbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
+ c->brbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
+ c->atbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
+ c->btbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
+
+ /* All buffers should be located in lower 16M of memory! */
+ if (!c->arbuf || !c->brbuf || !c->atbuf || !c->btbuf) {
+ printf ("cx%d.%d: No memory for channel buffers\n",
+ c->board->num, c->num);
+ c->type = T_NONE;
+ }
+
+ switch (c->type) {
+ case T_SYNC_RS232:
+ case T_SYNC_V35:
+ case T_SYNC_RS449:
+ case T_UNIV_RS232:
+ case T_UNIV_RS449:
+ case T_UNIV_V35:
+ c->ifp = malloc (IFSTRUCTSZ, M_DEVBUF, M_NOWAIT);
+ if (! c->ifp) {
+ printf ("cx%d.%d: No memory for ifnet buffer\n",
+ c->board->num, c->num);
+ c->type = T_NONE;
+ continue;
+ }
+ c->ifp->if_unit = u;
+ c->ifp->if_name = "cx";
+ c->ifp->if_mtu = PP_MTU;
+ c->ifp->if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
+ c->ifp->if_ioctl = cxsioctl;
+ c->ifp->if_start = (start_func_t) cxstart;
+ c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog;
+ /* Init routine is never called by upper level? */
+ c->ifp->if_init = (init_func_t) cxinit;
+ sppp_attach (c->ifp);
+ if_attach (c->ifp);
+#if NBPFILTER > 0
+ /* If BPF is in the kernel, call the attach for it. */
+ bpfattach (&c->bpf, c->ifp, DLT_PPP, PPP_HEADER_LEN);
+#endif
+ }
+ }
+
+ /* Reset the adapter. */
+ cx_setup_board (b);
+
+ /* Activate the timeout routine. */
+ if (unit == 0)
+ timeout ((timeout_func_t) cxtimeout, 0, hz*5);
+
+#if __FreeBSD__ >= 2
+ if (unit != 0)
+ kdc_cx[unit] = kdc_cx[0];
+ kdc_cx[unit].kdc_unit = unit;
+ kdc_cx[unit].kdc_isa = id;
+ sprintf (cxdescription, "Cronyx-Sigma-%s sync/async serial adapter",
+ b->name);
+ dev_attach (&kdc_cx[unit]);
+#endif
+#ifdef __FreeBSD__
+ printf ("cx%d: <Cronyx-%s>\n", unit, b->name);
+ return (1);
+#endif
+#ifdef __bsdi__
+ printf (": <Cronyx-%s>\n", b->name);
+ isa_establish (&sc->isadev, &sc->dev);
+ sc->intr.ih_fun = (int(*)()) cxintr;
+ sc->intr.ih_arg = (void*) b;
+ intr_establish (irq, &sc->intr, DV_NET);
+#endif
+}
+
+#ifdef __FreeBSD__
+struct isa_driver cxdriver = { cxprobe, cxattach, "cx" };
+#endif
+#ifdef __bsdi__
+struct cfdriver cxcd = { 0, "cx", cxprobe, cxattach, sizeof (struct cxsoftc) };
+#endif
+
+/*
+ * Process an ioctl request.
+ */
+int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data)
+{
+ cx_chan_t *c = cxchan[ifp->if_unit];
+ int error, s;
+
+ if (c->type==T_NONE || c->mode==M_ASYNC)
+ return (EINVAL);
+#ifdef __bsdi__
+ if (c->sopt.ext) {
+ /* Save RUNNING flag. */
+ int running = (ifp->if_flags & IFF_RUNNING);
+ error = p2p_ioctl (ifp, cmd, data);
+ ifp->if_flags &= ~IFF_RUNNING;
+ ifp->if_flags |= running;
+ } else
+#endif
+ error = sppp_ioctl (ifp, cmd, data);
+ if (error)
+ return (error);
+ if (cmd != SIOCSIFFLAGS)
+ return (0);
+
+ s = splimp ();
+ if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING))
+ /* Interface is down and running -- stop it. */
+ cxinit (ifp->if_unit);
+ else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING))
+ /* Interface is up and not running -- start it. */
+ cxinit (ifp->if_unit);
+ splx (s);
+ return (0);
+}
+
+/*
+ * Initialization of interface.
+ */
+void cxinit (int unit)
+{
+ cx_chan_t *c = cxchan[unit];
+ unsigned short port = c->chip->port;
+ int s;
+
+ print (("cx%d.%d: cxinit\n", c->board->num, c->num));
+
+ /* Disable interrupts */
+ s = splimp();
+
+ /* Reset the channel (for sync modes only) */
+ if (c->ifp->if_flags & IFF_OACTIVE) {
+ outb (CAR(port), c->num & 3);
+ outb (STCR(port), STC_ABORTTX | STC_SNDSPC);
+ }
+ cx_setup_chan (c);
+ c->ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+ if (c->ifp->if_flags & IFF_UP) {
+ /* The interface is up, start it */
+ c->ifp->if_flags |= IFF_RUNNING;
+
+#if __FreeBSD__ >= 2
+ /* Mark the board busy on the first startup.
+ * Never goes idle. */
+ kdc_cx[c->board->num].kdc_state = DC_BUSY;
+#endif
+ /* Initialize channel, enable receiver and transmitter */
+ cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
+ /* Repeat the command, to avoid the rev.H bug */
+ cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
+
+ /* Start receiver */
+ outw (ARBCNT(port), DMABUFSZ);
+ outb (ARBSTS(port), BSTS_OWN24);
+ outw (BRBCNT(port), DMABUFSZ);
+ outb (BRBSTS(port), BSTS_OWN24);
+
+ /* Raise DTR and RTS */
+ cx_chan_dtr (c, 1);
+ cx_chan_rts (c, 1);
+
+ /* Enable interrupts */
+ outb (IER(port), IER_RXD | IER_TXD);
+
+ cxstart (c->ifp);
+
+ } else if (! c->sopt.ext)
+ /* Flush the interface output queue, if it is down */
+ sppp_flush (c->ifp);
+
+ splx (s);
+}
+
+/*
+ * Fill transmitter buffer with data.
+ */
+void cxput (cx_chan_t *c, char b)
+{
+ struct mbuf *m;
+ unsigned char *buf;
+ unsigned short port = c->chip->port, len, cnt_port, sts_port;
+
+ /* Choose the buffer. */
+ if (b == 'A') {
+ buf = c->atbuf;
+ cnt_port = ATBCNT(port);
+ sts_port = ATBSTS(port);
+ } else {
+ buf = c->btbuf;
+ cnt_port = BTBCNT(port);
+ sts_port = BTBSTS(port);
+ }
+
+ /* Is it busy? */
+ if (inb (sts_port) & BSTS_OWN24) {
+ c->ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ /* Get the packet to send. */
+#ifdef __bsdi__
+ if (c->sopt.ext) {
+ struct p2pcom *p = (struct p2pcom*) c->ifp;
+ int s = splimp ();
+
+ IF_DEQUEUE (&p->p2p_isnd, m)
+ if (! m)
+ IF_DEQUEUE (&c->ifp->if_snd, m)
+ splx (s);
+ } else
+#endif
+ m = sppp_dequeue (c->ifp);
+ if (! m)
+ return;
+ len = m->m_pkthdr.len;
+ if (len >= DMABUFSZ) {
+ printf ("cx%d.%d: too long packet: %d bytes\n",
+ c->board->num, c->num, len);
+ printmbuf (m);
+ m_freem (m);
+ return;
+ }
+ m_copydata (m, 0, len, buf);
+#if NBPFILTER > 0
+ if (c->bpf)
+ bpf_mtap (c->bpf, m);
+#endif
+ m_freem (m);
+
+ /* Start transmitter. */
+ outw (cnt_port, len);
+ outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24);
+#ifdef DEBUG
+ if (c->ifp->if_flags & IFF_DEBUG)
+ printf ("cx%d.%d: enqueue %d bytes to %c\n",
+ c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B');
+#endif
+ c->ifp->if_flags |= IFF_OACTIVE;
+}
+
+/*
+ * Start output on interface. Get another datagram to send
+ * off of the interface queue, and copy it to the interface
+ * before starting the output.
+ */
+void cxstart (struct ifnet *ifp)
+{
+ cx_chan_t *c = cxchan[ifp->if_unit];
+ unsigned short port = c->chip->port;
+
+ /* No output if the interface is down. */
+ if (! (ifp->if_flags & IFF_RUNNING))
+ return;
+
+ /* Set the current channel number. */
+ outb (CAR(port), c->num & 3);
+
+ /* Determine the buffer order. */
+ if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
+ cxput (c, 'B');
+ cxput (c, 'A');
+ } else {
+ cxput (c, 'A');
+ cxput (c, 'B');
+ }
+
+ /* Set up transmit timeout. */
+ if (c->ifp->if_flags & IFF_OACTIVE)
+ c->ifp->if_timer = TXTIMEOUT;
+
+ /*
+ * Enable TXMPTY interrupt,
+ * to catch the case when the second buffer is empty.
+ */
+ if ((inb (ATBSTS(port)) & BSTS_OWN24) &&
+ (inb (BTBSTS(port)) & BSTS_OWN24)) {
+ outb (IER(port), IER_RXD | IER_TXD | IER_TXMPTY);
+ } else
+ outb (IER(port), IER_RXD | IER_TXD);
+}
+
+/*
+ * Handle transmit timeouts.
+ * Recover after lost transmit interrupts.
+ */
+void cxwatchdog (int unit)
+{
+ cx_chan_t *c = cxchan[unit];
+
+ if (c->ifp->if_flags & IFF_OACTIVE) {
+ c->ifp->if_flags &= ~IFF_OACTIVE;
+ cxstart (c->ifp);
+ }
+}
+
+/*
+ * Handle receive interrupts, including receive errors and
+ * receive timeout interrupt.
+ */
+void cxrinth (cx_chan_t *c)
+{
+ unsigned short port = c->chip->port;
+ unsigned short len, risr = inw (RISR(port));
+
+ print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
+ c->board->num, c->num, risr, RISH_BITS,
+ inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
+
+ /* Receive errors. */
+ if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) {
+ if (c->ifp->if_flags & IFF_DEBUG)
+ printf ("cx%d.%d: receive error, risr=%b\n",
+ c->board->num, c->num, risr, RISH_BITS);
+ ++c->ifp->if_ierrors;
+ if (risr & RIS_OVERRUN)
+ ++c->ifp->if_collisions;
+ } else if (risr & RIS_EOBUF) {
+ /* Handle received data. */
+ len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
+ if (len > DMABUFSZ) {
+ /* Fatal error: actual DMA transfer size
+ * exceeds our buffer size. It could be caused
+ * by incorrectly programmed DMA register or
+ * hardware fault. Possibly, should panic here. */
+ printf ("cx%d.%d: panic! DMA buffer overflow: %d bytes\n",
+ c->board->num, c->num, len);
+ ++c->ifp->if_ierrors;
+ } else if (! (risr & RIS_EOFR)) {
+ /* The received frame does not fit in the DMA buffer.
+ * It could be caused by serial lie noise,
+ * or if the peer has too big MTU. */
+ if (c->ifp->if_flags & IFF_DEBUG)
+ printf ("cx%d.%d: received frame length exceeds MTU, risr=%b\n",
+ c->board->num, c->num, risr, RISH_BITS);
+ ++c->ifp->if_ierrors;
+ } else {
+ /* Valid frame received. */
+ print (("cx%d.%d: HDLC: %d bytes received\n",
+ c->board->num, c->num, len));
+ cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len);
+ ++c->ifp->if_ipackets;
+ }
+ }
+
+ /* Restart receiver. */
+ if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
+ outw (ARBCNT(port), DMABUFSZ);
+ outb (ARBSTS(port), BSTS_OWN24);
+ }
+ if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
+ outw (BRBCNT(port), DMABUFSZ);
+ outb (BRBSTS(port), BSTS_OWN24);
+ }
+}
+
+/*
+ * Handle transmit interrupt.
+ */
+int cxtinth (cx_chan_t *c)
+{
+ unsigned short port = c->chip->port;
+ unsigned char tisr = inb (TISR(port));
+ unsigned char teoir = 0;
+
+ print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
+ c->board->num, c->num, tisr, TIS_BITS,
+ inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS));
+
+ if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) {
+ if (c->ifp->if_flags & IFF_DEBUG)
+ printf ("cx%d.%d: transmit error, tisr=%b\n",
+ c->board->num, c->num, tisr, TIS_BITS);
+ ++c->ifp->if_oerrors;
+ /* Terminate the failed buffer. */
+ teoir |= TEOI_TERMBUFF;
+ } else if (tisr & (TIS_EOFR))
+ ++c->ifp->if_opackets;
+
+ c->ifp->if_flags &= ~IFF_OACTIVE;
+ cxstart (c->ifp);
+ return (teoir);
+}
+
+#ifdef __FreeBSD__
+void cxintr (int bnum)
+{
+ cx_board_t *b = cxboard + bnum;
+#endif
+#ifdef __bsdi__
+void cxintr (cx_board_t *b)
+{
+#endif
+ while (! (inw (BSR(b->port)) & BSR_NOINTR)) {
+ /* Acknowledge the interrupt to enter the interrupt context. */
+ /* Read the local interrupt vector register. */
+ unsigned char livr = inb (IACK(b->port, BRD_INTR_LEVEL));
+ cx_chan_t *c = b->chan + (livr>>2 & 0xf);
+ unsigned short port = c->chip->port;
+ unsigned short eoiport = REOIR(port);
+ unsigned char eoi = 0;
+
+ if (c->type == T_NONE) {
+ printf ("cx%d.%d: unexpected interrupt, livr=0x%x\n",
+ c->board->num, c->num, livr);
+ continue; /* incorrect channel number? */
+ }
+ /* print (("cx%d.%d: interrupt, livr=0x%x\n",
+ c->board->num, c->num, livr)); */
+
+ /* Clear RTS to stop receiver data flow while we are busy
+ * processing the interrupt, thus avoiding underruns. */
+ if (! c->sopt.norts) {
+ outb (MSVR_RTS(port), 0);
+ c->rts = 0;
+ }
+
+ switch (livr & 3) {
+ case LIV_EXCEP: /* receive exception */
+ case LIV_RXDATA: /* receive interrupt */
+ switch (c->mode) {
+ case M_ASYNC: eoi = cxrinta (c); break;
+ case M_HDLC: cxrinth (c); break;
+ default:; /* No bisync and X.21 yet */
+ }
+ break;
+ case LIV_TXDATA: /* transmit interrupt */
+ eoiport = TEOIR(port);
+ switch (c->mode) {
+ case M_ASYNC: cxtinta (c); break;
+ case M_HDLC: eoi = cxtinth (c); break;
+ default:; /* No bisync and X.21 yet */
+ }
+ break;
+ case LIV_MODEM: /* modem/timer interrupt */
+ eoiport = MEOIR(port);
+ cxmint (c);
+ break;
+ }
+
+ /* Raise RTS for this channel if and only if
+ * both receive buffers are empty. */
+ if (! c->sopt.norts && (inb (CSR(port)) & CSRA_RXEN) &&
+ (inb (ARBSTS(port)) & BSTS_OWN24) &&
+ (inb (BRBSTS(port)) & BSTS_OWN24)) {
+ outb (MSVR_RTS(port), MSV_RTS);
+ c->rts = 1;
+ }
+
+ /* Exit from interrupt context. */
+ outb (eoiport, eoi);
+ }
+}
+
+/*
+ * Process the received packet.
+ */
+void cxinput (cx_chan_t *c, void *buf, unsigned len)
+{
+ /* Make an mbuf. */
+ struct mbuf *m = makembuf (buf, len);
+ if (! m) {
+ if (c->ifp->if_flags & IFF_DEBUG)
+ printf ("cx%d.%d: no memory for packet\n",
+ c->board->num, c->num);
+ ++c->ifp->if_iqdrops;
+ return;
+ }
+ m->m_pkthdr.rcvif = c->ifp;
+#ifdef DEBUG
+ printmbuf (m);
+#endif
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (c->bpf)
+ bpf_tap (c->bpf, buf, len);
+#endif
+#ifdef __bsdi__
+ if (c->sopt.ext) {
+ struct p2pcom *p = (struct p2pcom*) c->ifp;
+ (*p->p2p_input) (p, m);
+ } else
+#endif
+ sppp_input (c->ifp, m);
+}
+
+void cxswitch (cx_chan_t *c, cx_soft_opt_t new)
+{
+#ifdef __bsdi__
+ if (new.ext && ! c->sopt.ext) {
+ /* Switch to external ppp implementation (BSDI) */
+ sppp_detach (c->ifp);
+ bzero ((void*) c->ifp + IFNETSZ, IFSTRUCTSZ-IFNETSZ);
+ } else if (! new.ext && c->sopt.ext) {
+ /* Switch to built-in ppp implementation */
+ bzero ((void*) c->ifp + IFNETSZ, IFSTRUCTSZ-IFNETSZ);
+ sppp_attach (c->ifp);
+ }
+#else
+ new.ext = 0;
+#endif
+ if (! new.ext) {
+ struct sppp *sp = (struct sppp*) c->ifp;
+
+ if (new.cisco)
+ sp->pp_flags |= PP_CISCO;
+ else
+ sp->pp_flags &= ~PP_CISCO;
+ if (new.keepalive)
+ sp->pp_flags |= PP_KEEPALIVE;
+ else
+ sp->pp_flags &= ~PP_KEEPALIVE;
+ }
+ c->sopt = new;
+}
+#endif /* NCX */
diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h
new file mode 100644
index 0000000..c915977
--- /dev/null
+++ b/sys/net/if_sppp.h
@@ -0,0 +1,70 @@
+/*
+ * Defines for synchronous PPP/Cisco link level subroutines.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.1, Thu Oct 27 21:15:02 MSK 1994
+ */
+
+#ifndef _NET_IF_HDLC_H_
+#define _NET_IF_HDLC_H_ 1
+
+struct slcp {
+ u_short state; /* state machine */
+ u_long magic; /* local magic number */
+ u_long rmagic; /* remote magic number */
+ u_char lastid; /* id of last keepalive echo request */
+};
+
+struct sipcp {
+ u_short state; /* state machine */
+};
+
+struct sppp {
+ struct ifnet pp_if; /* network interface data */
+ struct ifqueue pp_fastq; /* fast output queue */
+ struct sppp *pp_next; /* next interface in keepalive list */
+ u_int pp_flags; /* use Cisco protocol instead of PPP */
+ u_short pp_alivecnt; /* keepalive packets counter */
+ u_short pp_loopcnt; /* loopback detection counter */
+ u_long pp_seq; /* local sequence number */
+ u_long pp_rseq; /* remote sequence number */
+ struct slcp lcp; /* LCP params */
+ struct sipcp ipcp; /* IPCP params */
+};
+
+#define PP_KEEPALIVE 0x01 /* use keepalive protocol */
+#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */
+
+#define PP_MTU 1500 /* max. transmit unit */
+
+#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */
+#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */
+#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */
+#define LCP_STATE_OPENED 3 /* LCP state: opened */
+
+#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */
+#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */
+#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */
+#define IPCP_STATE_OPENED 3 /* IPCP state: opened */
+
+#ifdef KERNEL
+void sppp_attach (struct ifnet *ifp);
+void sppp_detach (struct ifnet *ifp);
+void sppp_input (struct ifnet *ifp, struct mbuf *m);
+int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+ struct rtentry *rt);
+int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data);
+struct mbuf *sppp_dequeue (struct ifnet *ifp);
+void sppp_flush (struct ifnet *ifp);
+#endif
+
+#endif /* _NET_IF_HDLC_H_ */
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
new file mode 100644
index 0000000..8c97231
--- /dev/null
+++ b/sys/net/if_spppsubr.c
@@ -0,0 +1,1219 @@
+/*
+ * Synchronous PPP/Cisco link level subroutines.
+ * Keepalive protocol implemented in both Cisco and PPP modes.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.1, Thu Oct 27 21:13:59 MSK 1994
+ */
+#undef DEBUG
+
+#include <sys/param.h>
+#include <systm.h>
+#include <kernel.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#ifdef ISO
+#include <netiso/argo_debug.h>
+#include <netiso/iso.h>
+#include <netiso/iso_var.h>
+#include <netiso/iso_snpac.h>
+#endif
+
+#include <net/if_sppp.h>
+
+#ifdef DEBUG
+#define print(s) printf s
+#else
+#define print(s) /*void*/
+#endif
+
+#define MAXALIVECNT 3 /* max. alive packets */
+
+#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */
+#define PPP_UI 0x03 /* Unnumbered Information */
+#define PPP_IP 0x0021 /* Internet Protocol */
+#define PPP_ISO 0x0023 /* ISO OSI Protocol */
+#define PPP_XNS 0x0025 /* Xerox NS Protocol */
+#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */
+
+#define LCP_CONF_REQ 1 /* PPP LCP configure request */
+#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */
+#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */
+#define LCP_CONF_REJ 4 /* PPP LCP configure reject */
+#define LCP_TERM_REQ 5 /* PPP LCP terminate request */
+#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */
+#define LCP_CODE_REJ 7 /* PPP LCP code reject */
+#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */
+#define LCP_ECHO_REQ 9 /* PPP LCP echo request */
+#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */
+#define LCP_DISC_REQ 11 /* PPP LCP discard request */
+
+#define LCP_OPT_MRU 1 /* maximum receive unit */
+#define LCP_OPT_ASYNC_MAP 2 /* async control character map */
+#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */
+#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */
+#define LCP_OPT_MAGIC 5 /* magic number */
+#define LCP_OPT_RESERVED 6 /* reserved */
+#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */
+#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */
+
+#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */
+#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */
+#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */
+#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */
+#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */
+#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */
+#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */
+
+#define CISCO_MULTICAST 0x8f /* Cisco multicast address */
+#define CISCO_UNICAST 0x0f /* Cisco unicast address */
+#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */
+#define CISCO_ADDR_REQ 0 /* Cisco address request */
+#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+
+struct ppp_header {
+ unsigned char address;
+ unsigned char control;
+ unsigned short protocol;
+};
+#define PPP_HEADER_LEN sizeof (struct ppp_header)
+
+struct lcp_header {
+ unsigned char type;
+ unsigned char ident;
+ unsigned short len;
+};
+#define LCP_HEADER_LEN sizeof (struct lcp_header)
+
+struct cisco_packet {
+ unsigned long type;
+ unsigned long par1;
+ unsigned long par2;
+ unsigned short rel;
+ unsigned short time0;
+ unsigned short time1;
+};
+#define CISCO_PACKET_LEN 18
+
+struct sppp *spppq;
+
+extern void if_down (struct ifnet *ifp);
+
+/*
+ * The following disgusting hack gets around the problem that IP TOS
+ * can't be set yet. We want to put "interactive" traffic on a high
+ * priority queue. To decide if traffic is interactive, we check that
+ * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
+ */
+static unsigned short interactive_ports[8] = {
+ 0, 513, 0, 0,
+ 0, 21, 0, 23,
+};
+#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
+
+void sppp_keepalive (caddr_t dummy1, int dummy2);
+void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type,
+ unsigned char ident, unsigned short len, void *data);
+void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2);
+void sppp_lcp_input (struct sppp *sp, struct mbuf *m);
+void sppp_cisco_input (struct sppp *sp, struct mbuf *m);
+void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h);
+void sppp_ipcp_input (struct sppp *sp, struct mbuf *m);
+void sppp_lcp_open (struct sppp *sp);
+void sppp_ipcp_open (struct sppp *sp);
+int sppp_lcp_conf_unknown_options (int len, unsigned char *p);
+void sppp_cp_timeout (caddr_t arg, int dummy);
+char *sppp_lcp_type_name (unsigned char type);
+char *sppp_ipcp_type_name (unsigned char type);
+void sppp_print_bytes (unsigned char *p, unsigned short len);
+
+/*
+ * Flush interface queue.
+ */
+static void qflush (struct ifqueue *ifq)
+{
+ struct mbuf *m, *n;
+
+ n = ifq->ifq_head;
+ while ((m = n)) {
+ n = m->m_act;
+ m_freem (m);
+ }
+ ifq->ifq_head = 0;
+ ifq->ifq_tail = 0;
+ ifq->ifq_len = 0;
+}
+
+/*
+ * Process the received packet.
+ */
+void sppp_input (struct ifnet *ifp, struct mbuf *m)
+{
+ struct ppp_header *h;
+ struct sppp *sp;
+ struct ifqueue *inq = 0;
+
+ ifp->if_lastchange = time;
+ if (ifp->if_flags & IFF_UP)
+ /* Count received bytes, add FCS and one flag */
+ ifp->if_ibytes += m->m_pkthdr.len + 3;
+
+ if (m->m_pkthdr.len <= PPP_HEADER_LEN) {
+ /* Too small packet, drop it. */
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: input packet is too small, %d bytes\n",
+ ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
+drop: ++ifp->if_iqdrops;
+ m_freem (m);
+ return;
+ }
+
+ /* Get PPP header. */
+ h = mtod (m, struct ppp_header*);
+ m_adj (m, PPP_HEADER_LEN);
+
+ switch (h->address) {
+ default: /* Invalid PPP packet. */
+invalid: if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid input packet <0x%x 0x%x 0x%x>\n",
+ ifp->if_name, ifp->if_unit,
+ h->address, h->control, ntohs (h->protocol));
+ goto drop;
+ case PPP_ALLSTATIONS:
+ if (h->control != PPP_UI)
+ goto invalid;
+ sp = (struct sppp*) ifp;
+ switch (ntohs (h->protocol)) {
+ default:
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ,
+ ++sp->pp_seq, m->m_pkthdr.len - 2,
+ &h->protocol);
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n",
+ ifp->if_name, ifp->if_unit,
+ h->address, h->control, ntohs (h->protocol));
+ ++ifp->if_noproto;
+ goto drop;
+ case PPP_LCP:
+ sppp_lcp_input ((struct sppp*) ifp, m);
+ m_freem (m);
+ return;
+#ifdef INET
+ case PPP_IPCP:
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ sppp_ipcp_input ((struct sppp*) ifp, m);
+ m_freem (m);
+ return;
+ case PPP_IP:
+ if (sp->ipcp.state == IPCP_STATE_OPENED) {
+ schednetisr (NETISR_IP);
+ inq = &ipintrq;
+ }
+ break;
+#endif
+#ifdef NS
+ case PPP_XNS:
+ /* XNS IDPCP not implemented yet */
+ if (sp->lcp.state == LCP_STATE_OPENED) {
+ schednetisr (NETISR_NS);
+ inq = &nsintrq;
+ }
+ break;
+#endif
+#ifdef ISO
+ case PPP_ISO:
+ /* OSI NLCP not implemented yet */
+ if (sp->lcp.state == LCP_STATE_OPENED) {
+ schednetisr (NETISR_ISO);
+ inq = &clnlintrq;
+ }
+ break;
+#endif
+ }
+ break;
+ case CISCO_MULTICAST:
+ case CISCO_UNICAST:
+ /* Don't check the control field here (RFC 1547). */
+ switch (ntohs (h->protocol)) {
+ default:
+ ++ifp->if_noproto;
+ goto invalid;
+ case CISCO_KEEPALIVE:
+ sppp_cisco_input ((struct sppp*) ifp, m);
+ m_freem (m);
+ return;
+#ifdef INET
+ case ETHERTYPE_IP:
+ schednetisr (NETISR_IP);
+ inq = &ipintrq;
+ break;
+#endif
+#ifdef NS
+ case ETHERTYPE_NS:
+ schednetisr (NETISR_NS);
+ inq = &nsintrq;
+ break;
+#endif
+ }
+ break;
+ }
+
+ if (! (ifp->if_flags & IFF_UP) || ! inq)
+ goto drop;
+
+ /* Check queue. */
+ if (IF_QFULL (inq)) {
+ /* Queue overflow. */
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: protocol queue overflow\n",
+ ifp->if_name, ifp->if_unit);
+ IF_DROP (inq);
+ goto drop;
+ }
+ IF_ENQUEUE (inq, m);
+}
+
+/*
+ * Enqueue transmit packet.
+ */
+int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)
+{
+ struct sppp *sp = (struct sppp*) ifp;
+ struct ppp_header *h;
+ struct ifqueue *ifq;
+ int s = splimp ();
+
+ if (! (ifp->if_flags & IFF_UP) || ! (ifp->if_flags & IFF_RUNNING)) {
+ m_freem (m);
+ splx (s);
+ return (ENETDOWN);
+ }
+
+ ifq = &ifp->if_snd;
+#ifdef INET
+ /*
+ * Put low delay, telnet, rlogin and ftp control packets
+ * in front of the queue.
+ */
+ {
+ struct ip *ip = mtod (m, struct ip*);
+ struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
+
+ if (! IF_QFULL (&sp->pp_fastq) && ((ip->ip_tos & IPTOS_LOWDELAY) ||
+ ip->ip_p == IPPROTO_TCP &&
+ m->m_len >= sizeof (struct ip) + sizeof (struct tcphdr) &&
+ (INTERACTIVE (ntohs (tcp->th_sport)) ||
+ INTERACTIVE (ntohs (tcp->th_dport)))))
+ ifq = &sp->pp_fastq;
+ }
+#endif
+
+ /*
+ * Prepend general data packet PPP header. For now, IP only.
+ */
+ M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT);
+ if (! m) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: no memory for transmit header\n",
+ ifp->if_name, ifp->if_unit);
+ splx (s);
+ return (ENOBUFS);
+ }
+ h = mtod (m, struct ppp_header*);
+ if (sp->pp_flags & PP_CISCO) {
+ h->address = CISCO_MULTICAST; /* broadcast address */
+ h->control = 0;
+ } else {
+ h->address = PPP_ALLSTATIONS; /* broadcast address */
+ h->control = PPP_UI; /* Unnumbered Info */
+ }
+
+ switch (dst->sa_family) {
+#ifdef INET
+ case AF_INET: /* Internet Protocol */
+ h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
+ ETHERTYPE_IP : PPP_IP);
+ break;
+#endif
+#ifdef NS
+ case AF_NS: /* Xerox NS Protocol */
+ h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
+ ETHERTYPE_NS : PPP_XNS);
+ break;
+#endif
+#ifdef ISO
+ case AF_ISO: /* ISO OSI Protocol */
+ if (sp->pp_flags & PP_CISCO)
+ goto nosupport;
+ h->protocol = htons (PPP_ISO);
+ break;
+#endif
+ default:
+ m_freem (m);
+ splx (s);
+ return (EAFNOSUPPORT);
+ }
+
+ /*
+ * Queue message on interface, and start output if interface
+ * not yet active.
+ */
+ if (IF_QFULL (ifq)) {
+ IF_DROP (&ifp->if_snd);
+ m_freem (m);
+ splx (s);
+ return (ENOBUFS);
+ }
+ IF_ENQUEUE (ifq, m);
+ if (! (ifp->if_flags & IFF_OACTIVE))
+ (*ifp->if_start) (ifp);
+
+ /*
+ * Count output packets and bytes.
+ * The packet length includes header, FCS and 1 flag,
+ * according to RFC 1333.
+ */
+ ifp->if_obytes += m->m_pkthdr.len + 3;
+ ifp->if_lastchange = time;
+ splx (s);
+ return (0);
+}
+
+void sppp_attach (struct ifnet *ifp)
+{
+ struct sppp *sp = (struct sppp*) ifp;
+
+ /* Initialize keepalive handler. */
+ if (! spppq)
+ timeout (sppp_keepalive, 0, hz * 10);
+
+ /* Insert new entry into the keepalive list. */
+ sp->pp_next = spppq;
+ spppq = sp;
+
+ sp->pp_if.if_type = IFT_PPP;
+ sp->pp_if.if_output = sppp_output;
+ sp->pp_fastq.ifq_maxlen = 32;
+ sp->pp_loopcnt = 0;
+ sp->pp_alivecnt = 0;
+ sp->lcp.magic = time.tv_sec + time.tv_usec;
+ sp->lcp.rmagic = 0;
+ sp->pp_seq = sp->lcp.magic;
+ sp->pp_rseq = 0;
+}
+
+void sppp_detach (struct ifnet *ifp)
+{
+ struct sppp **q, *p, *sp = (struct sppp*) ifp;
+
+ /* Remove the entry from the keepalive list. */
+ for (q = &spppq; (p = *q); q = &p->pp_next)
+ if (p == sp) {
+ *q = p->pp_next;
+ break;
+ }
+
+ /* Stop keepalive handler. */
+ if (! spppq)
+ untimeout (sppp_keepalive, 0);
+ untimeout (sppp_cp_timeout, (caddr_t) sp);
+}
+
+/*
+ * Flush the interface output queue.
+ */
+void sppp_flush (struct ifnet *ifp)
+{
+ struct sppp *sp = (struct sppp*) ifp;
+
+ qflush (&sp->pp_if.if_snd);
+ qflush (&sp->pp_fastq);
+}
+
+/*
+ * Get next packet to send.
+ */
+struct mbuf *sppp_dequeue (struct ifnet *ifp)
+{
+ struct sppp *sp = (struct sppp*) ifp;
+ struct mbuf *m;
+ int s = splimp ();
+
+ IF_DEQUEUE (&sp->pp_fastq, m);
+ if (! m)
+ IF_DEQUEUE (&sp->pp_if.if_snd, m);
+ splx (s);
+ return (m);
+}
+
+/*
+ * Send keepalive packets, every 10 seconds.
+ */
+void sppp_keepalive (caddr_t dummy1, int dummy2)
+{
+ struct sppp *sp;
+ int s = splimp ();
+
+ for (sp=spppq; sp; sp=sp->pp_next) {
+ struct ifnet *ifp = &sp->pp_if;
+
+ if (! (sp->pp_flags & PP_KEEPALIVE) ||
+ ! (ifp->if_flags & IFF_RUNNING) ||
+ sp->lcp.state != LCP_STATE_OPENED)
+ continue;
+
+ if (sp->pp_alivecnt == MAXALIVECNT) {
+ /* No keepalive packets got. Stop the interface. */
+ printf ("%s%d: down\n", ifp->if_name, ifp->if_unit);
+ if_down (ifp);
+ qflush (&sp->pp_fastq);
+ }
+ if (sp->pp_loopcnt >= MAXALIVECNT)
+ printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit);
+
+ if (sp->pp_alivecnt <= MAXALIVECNT)
+ ++sp->pp_alivecnt;
+ if (sp->pp_flags & PP_CISCO)
+ sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq,
+ sp->pp_rseq);
+ else if (sp->lcp.state == LCP_STATE_OPENED) {
+ long nmagic = htonl (sp->lcp.magic);
+ sp->lcp.lastid = ++sp->pp_seq;
+ sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ,
+ sp->lcp.lastid, 4, &nmagic);
+ }
+ }
+ splx (s);
+ timeout (sppp_keepalive, 0, hz * 10);
+}
+
+/*
+ * Handle incoming PPP Link Control Protocol packets.
+ */
+void sppp_lcp_input (struct sppp *sp, struct mbuf *m)
+{
+ struct lcp_header *h;
+ struct ifnet *ifp = &sp->pp_if;
+ int len = m->m_pkthdr.len;
+ unsigned char *p;
+
+ if (len < 4) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid lcp packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ return;
+ }
+ h = mtod (m, struct lcp_header*);
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf ("%s%d: lcp input: %d bytes <%s id=%xh len=%xh",
+ ifp->if_name, ifp->if_unit, len,
+ sppp_lcp_type_name (h->type), h->ident, ntohs (h->len));
+ if (len > 4)
+ sppp_print_bytes ((unsigned char*) (h+1), len-4);
+ printf (">\n");
+ }
+ if (len > ntohs (h->len))
+ len = ntohs (h->len);
+ switch (h->type) {
+ default:
+ /* Unknown packet type -- send Code-Reject packet. */
+ sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, len, h);
+ break;
+ case LCP_CONF_REQ:
+ if (len < 4) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid lcp configure request packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ return;
+ }
+ if (len>4 && sppp_lcp_conf_unknown_options (len-4, (unsigned char*) (h+1))) {
+ sppp_lcp_conf_rej (sp, h);
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ if (sp->lcp.state != LCP_STATE_ACK_RCVD) {
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ } else {
+ /* Extract remote magic number. */
+ p = (unsigned char*) (h+1);
+ if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4)
+ sp->lcp.rmagic = (unsigned long)p[2] << 24 |
+ (unsigned long)p[3] << 16 |
+ p[4] << 8 | p[5];
+ if (sp->lcp.rmagic == sp->lcp.magic) {
+ /* Local and remote magics are equal -- loop? */
+ sp->lcp.rmagic = ~sp->lcp.magic;
+ /* Send Configure-Nack packet. */
+ p[2] = sp->lcp.rmagic >> 24;
+ p[3] = sp->lcp.rmagic >> 16;
+ p[4] = sp->lcp.rmagic >> 8;
+ p[5] = sp->lcp.rmagic;
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK,
+ h->ident, len-4, h+1);
+ if (sp->lcp.state != LCP_STATE_ACK_RCVD) {
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ } else {
+ /* Send Configure-Ack packet. */
+ sp->pp_loopcnt = 0;
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+ h->ident, len-4, h+1);
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ /* Change the state. */
+ if (sp->lcp.state == LCP_STATE_ACK_RCVD) {
+ sp->lcp.state = LCP_STATE_OPENED;
+ sppp_ipcp_open (sp);
+ } else
+ sp->lcp.state = LCP_STATE_ACK_SENT;
+ }
+ }
+ break;
+ case LCP_CONF_ACK:
+ if (h->ident != sp->pp_seq)
+ return;
+ untimeout (sppp_cp_timeout, (caddr_t) sp);
+ switch (sp->lcp.state) {
+ case LCP_STATE_CLOSED:
+ sp->lcp.state = LCP_STATE_ACK_RCVD;
+ break;
+ case LCP_STATE_ACK_SENT:
+ sp->lcp.state = LCP_STATE_OPENED;
+ sppp_ipcp_open (sp);
+ break;
+ case LCP_STATE_ACK_RCVD:
+ case LCP_STATE_OPENED:
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ }
+ break;
+ case LCP_CONF_NAK:
+ if (h->ident != sp->pp_seq)
+ return;
+ p = (unsigned char*) (h+1);
+ if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) {
+ sp->lcp.rmagic = (unsigned long)p[2] << 24 |
+ (unsigned long)p[3] << 16 |
+ p[4] << 8 | p[5];
+ if (sp->lcp.rmagic == ~sp->lcp.magic) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: conf nak: magic glitch\n",
+ ifp->if_name, ifp->if_unit);
+ ++sp->pp_loopcnt;
+ sp->lcp.magic = time.tv_sec + time.tv_usec;
+ }
+ }
+ /* Fall through. */
+ case LCP_CONF_REJ:
+ if (h->ident != sp->pp_seq)
+ return;
+ untimeout (sppp_cp_timeout, (caddr_t) sp);
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ break;
+ case LCP_TERM_REQ:
+ /* Send Terminate-Ack packet. */
+ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0);
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case LCP_TERM_ACK:
+ if (h->ident != sp->pp_seq)
+ return;
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_lcp_open (sp);
+ if (sp->lcp.state != LCP_STATE_ACK_SENT) {
+ /* Go to closed state. */
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ }
+ break;
+ case LCP_CODE_REJ:
+ case LCP_PROTO_REJ:
+ /* Ignore for now. */
+ break;
+ case LCP_DISC_REQ:
+ /* Discard the packet. */
+ break;
+ case LCP_ECHO_REQ:
+ if (len < 8) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid lcp echo request packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ return;
+ }
+ if (ntohl (*(long*)(h+1)) == sp->lcp.magic) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: echo reply: magic glitch\n",
+ ifp->if_name, ifp->if_unit);
+ ++sp->pp_loopcnt;
+ }
+ *(long*)(h+1) = htonl (sp->lcp.magic);
+ sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1);
+ break;
+ case LCP_ECHO_REPLY:
+ if (h->ident != sp->lcp.lastid)
+ return;
+ if (len < 8) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ return;
+ }
+ if (ntohl (*(long*)(h+1)) == sp->lcp.magic)
+ return;
+ if (! (ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags |= IFF_UP;
+ printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
+ }
+ sp->pp_alivecnt = 0;
+ break;
+ }
+}
+
+/*
+ * Handle incoming Cisco keepalive protocol packets.
+ */
+void sppp_cisco_input (struct sppp *sp, struct mbuf *m)
+{
+ struct cisco_packet *h;
+ struct ifaddr *ifa;
+ struct ifnet *ifp = &sp->pp_if;
+
+ if (m->m_pkthdr.len != CISCO_PACKET_LEN) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid cisco packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, m->m_pkthdr.len);
+ return;
+ }
+ h = mtod (m, struct cisco_packet*);
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n",
+ ifp->if_name, ifp->if_unit, m->m_pkthdr.len,
+ ntohl (h->type), h->par1, h->par2, h->rel,
+ h->time0, h->time1);
+ switch (ntohl (h->type)) {
+ default:
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: unknown cisco packet type: 0x%x\n",
+ ifp->if_name, ifp->if_unit, ntohl (h->type));
+ break;
+ case CISCO_ADDR_REPLY:
+ /* Reply on address request, ignore */
+ break;
+ case CISCO_KEEPALIVE_REQ:
+ if (! (ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags |= IFF_UP;
+ printf ("%s%d: up\n", ifp->if_name, ifp->if_unit);
+ }
+ sp->pp_alivecnt = 0;
+ sp->pp_rseq = ntohl (h->par1);
+ if (sp->pp_seq == sp->pp_rseq) {
+ /* Local and remote sequence numbers are equal.
+ * Probably, the line is in loopback mode. */
+ ++sp->pp_loopcnt;
+
+ /* Generate new local sequence number */
+ sp->pp_seq ^= time.tv_sec ^ time.tv_usec;
+ } else
+ sp->pp_loopcnt = 0;
+ break;
+ case CISCO_ADDR_REQ:
+ for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ break;
+ if (! ifa) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: unknown address for cisco request\n",
+ ifp->if_name, ifp->if_unit);
+ return;
+ }
+ sppp_cisco_send (sp, CISCO_ADDR_REPLY,
+ ntohl (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr),
+ ntohl (((struct sockaddr_in*)ifa->ifa_netmask)->sin_addr.s_addr));
+ break;
+ }
+}
+
+/*
+ * Send PPP LCP packet.
+ */
+void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type,
+ unsigned char ident, unsigned short len, void *data)
+{
+ struct ppp_header *h;
+ struct lcp_header *lh;
+ struct mbuf *m;
+ struct ifnet *ifp = &sp->pp_if;
+
+ if (len > MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN)
+ len = MHLEN - PPP_HEADER_LEN - LCP_HEADER_LEN;
+ MGETHDR (m, M_DONTWAIT, MT_DATA);
+ if (! m)
+ return;
+ m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + LCP_HEADER_LEN + len;
+ m->m_pkthdr.rcvif = 0;
+
+ h = mtod (m, struct ppp_header*);
+ h->address = PPP_ALLSTATIONS; /* broadcast address */
+ h->control = PPP_UI; /* Unnumbered Info */
+ h->protocol = htons (proto); /* Link Control Protocol */
+
+ lh = (struct lcp_header*) (h + 1);
+ lh->type = type;
+ lh->ident = ident;
+ lh->len = htons (LCP_HEADER_LEN + len);
+ if (len)
+ bcopy (data, lh+1, len);
+
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf ("%s%d: %s output <%s id=%xh len=%xh",
+ ifp->if_name, ifp->if_unit,
+ proto==PPP_LCP ? "lcp" : "ipcp",
+ proto==PPP_LCP ? sppp_lcp_type_name (lh->type) :
+ sppp_ipcp_type_name (lh->type), lh->ident,
+ ntohs (lh->len));
+ if (len)
+ sppp_print_bytes ((unsigned char*) (lh+1), len);
+ printf (">\n");
+ }
+ if (IF_QFULL (&sp->pp_fastq)) {
+ IF_DROP (&ifp->if_snd);
+ m_freem (m);
+ } else
+ IF_ENQUEUE (&sp->pp_fastq, m);
+ if (! (ifp->if_flags & IFF_OACTIVE))
+ (*ifp->if_start) (ifp);
+ ifp->if_obytes += m->m_pkthdr.len + 3;
+}
+
+/*
+ * Send Cisco keepalive packet.
+ */
+void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2)
+{
+ struct ppp_header *h;
+ struct cisco_packet *ch;
+ struct mbuf *m;
+ struct ifnet *ifp = &sp->pp_if;
+ unsigned long t = (time.tv_sec - boottime.tv_sec) * 1000;
+
+ MGETHDR (m, M_DONTWAIT, MT_DATA);
+ if (! m)
+ return;
+ m->m_pkthdr.len = m->m_len = PPP_HEADER_LEN + CISCO_PACKET_LEN;
+ m->m_pkthdr.rcvif = 0;
+
+ h = mtod (m, struct ppp_header*);
+ h->address = CISCO_MULTICAST;
+ h->control = 0;
+ h->protocol = htons (CISCO_KEEPALIVE);
+
+ ch = (struct cisco_packet*) (h + 1);
+ ch->type = htonl (type);
+ ch->par1 = htonl (par1);
+ ch->par2 = htonl (par2);
+ ch->rel = -1;
+ ch->time0 = htons ((unsigned short) (t >> 16));
+ ch->time1 = htons ((unsigned short) t);
+
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: cisco output: <%xh %xh %xh %xh %xh-%xh>\n",
+ ifp->if_name, ifp->if_unit, ntohl (ch->type), ch->par1,
+ ch->par2, ch->rel, ch->time0, ch->time1);
+
+ if (IF_QFULL (&sp->pp_fastq)) {
+ IF_DROP (&ifp->if_snd);
+ m_freem (m);
+ } else
+ IF_ENQUEUE (&sp->pp_fastq, m);
+ if (! (ifp->if_flags & IFF_OACTIVE))
+ (*ifp->if_start) (ifp);
+ ifp->if_obytes += m->m_pkthdr.len + 3;
+}
+
+/*
+ * Process an ioctl request. Called on low priority level.
+ */
+int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data)
+{
+ struct ifreq *ifr = (struct ifreq*) data;
+ struct sppp *sp;
+ int s;
+
+ switch (cmd) {
+ default:
+ return (EINVAL);
+
+ case SIOCSIFADDR:
+ case SIOCAIFADDR:
+ case SIOCSIFDSTADDR:
+ break;
+
+ case SIOCSIFFLAGS:
+ s = splimp ();
+ if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) {
+ /* Interface is stopping. */
+ sp = (struct sppp*) ifp;
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ sppp_cp_send (sp, PPP_LCP, LCP_TERM_REQ, ++sp->pp_seq,
+ 0, 0);
+ } else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING)) {
+ /* Interface is starting. */
+ sp = (struct sppp*) ifp;
+ sp->lcp.state = LCP_STATE_CLOSED;
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ sppp_lcp_open (sp);
+ }
+ splx (s);
+ break;
+
+#ifdef SIOCSIFMTU
+#ifndef ifr_mtu
+#define ifr_mtu ifr_metric
+#endif
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu < 128 || ifr->ifr_mtu > PP_MTU)
+ return (EINVAL);
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+#endif
+#ifdef SLIOCSETMTU
+ case SLIOCSETMTU:
+ if (*(short*)data < 128 || *(short*)data > PP_MTU)
+ return (EINVAL);
+ ifp->if_mtu = *(short*)data;
+ break;
+#endif
+#ifdef SIOCGIFMTU
+ case SIOCGIFMTU:
+ ifr->ifr_mtu = ifp->if_mtu;
+ break;
+#endif
+#ifdef SLIOCGETMTU
+ case SLIOCGETMTU:
+ *(short*)data = ifp->if_mtu;
+ break;
+#endif
+#ifdef MULTICAST
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ break;
+#endif
+ }
+ return (0);
+}
+
+int sppp_lcp_conf_unknown_options (int len, unsigned char *p)
+{
+ /* Analyze the LCP Configure-Request options list
+ * for the presence of unknown options. */
+ while (len > 0) {
+ if (*p != LCP_OPT_MAGIC)
+ return (1);
+ len -= p[1];
+ p += p[1];
+ }
+ return (0);
+}
+
+void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h)
+{
+ /* The LCP Configure-Request contains unknown options.
+ * Send Configure-reject packet, containing only unknown options. */
+ unsigned char buf [PP_MTU], *r = buf, *p = (void*) (h+1);
+ unsigned rlen = 0, len = h->len - 4;
+
+ while (len > 0) {
+ if (*p != LCP_OPT_MAGIC) {
+ bcopy (p, r, p[1]);
+ r += p[1];
+ }
+ len -= p[1];
+ p += p[1];
+ }
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf);
+}
+
+void sppp_ipcp_input (struct sppp *sp, struct mbuf *m)
+{
+ struct lcp_header *h;
+ struct ifnet *ifp = &sp->pp_if;
+ int len = m->m_pkthdr.len;
+
+ if (len < 4) {
+ /* if (ifp->if_flags & IFF_DEBUG) */
+ printf ("%s%d: invalid ipcp packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ return;
+ }
+ h = mtod (m, struct lcp_header*);
+ if (ifp->if_flags & IFF_DEBUG) {
+ printf ("%s%d: ipcp input: %d bytes <%s id=%xh len=%xh",
+ ifp->if_name, ifp->if_unit, len,
+ sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len));
+ if (len > 4)
+ sppp_print_bytes ((unsigned char*) (h+1), len-4);
+ printf (">\n");
+ }
+ if (len > ntohs (h->len))
+ len = ntohs (h->len);
+ switch (h->type) {
+ default:
+ /* Unknown packet type -- send Code-Reject packet. */
+ sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h);
+ break;
+ case IPCP_CONF_REQ:
+ if (len < 4) {
+ if (ifp->if_flags & IFF_DEBUG)
+ printf ("%s%d: invalid ipcp configure request packet length: %d bytes\n",
+ ifp->if_name, ifp->if_unit, len);
+ return;
+ }
+ if (len > 4) {
+ sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident,
+ len-4, h+1);
+ if (sp->lcp.state == LCP_STATE_OPENED &&
+ sp->ipcp.state == IPCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ if (sp->ipcp.state != IPCP_STATE_ACK_RCVD)
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ } else {
+ /* Send Configure-Ack packet. */
+ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident,
+ 0, 0);
+ if (sp->lcp.state == LCP_STATE_OPENED &&
+ sp->ipcp.state == IPCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ /* Change the state. */
+ sp->ipcp.state = (sp->ipcp.state == IPCP_STATE_ACK_RCVD) ?
+ IPCP_STATE_OPENED : IPCP_STATE_ACK_SENT;
+ }
+ break;
+ case IPCP_CONF_ACK:
+ untimeout (sppp_cp_timeout, (caddr_t) sp);
+ switch (sp->ipcp.state) {
+ case IPCP_STATE_CLOSED:
+ sp->ipcp.state = IPCP_STATE_ACK_RCVD;
+ break;
+ case IPCP_STATE_ACK_SENT:
+ sp->ipcp.state = IPCP_STATE_OPENED;
+ break;
+ case IPCP_STATE_ACK_RCVD:
+ case IPCP_STATE_OPENED:
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ }
+ break;
+ case IPCP_CONF_NAK:
+ case IPCP_CONF_REJ:
+ untimeout (sppp_cp_timeout, (caddr_t) sp);
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ if (sp->lcp.state == LCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case IPCP_TERM_REQ:
+ /* Send Terminate-Ack packet. */
+ sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0);
+ if (sp->lcp.state == LCP_STATE_OPENED &&
+ sp->ipcp.state == IPCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case IPCP_TERM_ACK:
+ if (sp->lcp.state == LCP_STATE_OPENED &&
+ sp->ipcp.state == IPCP_STATE_OPENED)
+ /* Initiate renegotiation. */
+ sppp_ipcp_open (sp);
+ if (sp->ipcp.state != IPCP_STATE_ACK_SENT)
+ /* Go to closed state. */
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case IPCP_CODE_REJ:
+ /* Ignore for now. */
+ break;
+ }
+}
+
+void sppp_lcp_open (struct sppp *sp)
+{
+ char opt[6];
+
+ /* Make new magic number. */
+ sp->lcp.magic = time.tv_sec + time.tv_usec;
+ opt[0] = LCP_OPT_MAGIC;
+ opt[1] = sizeof (opt);
+ opt[2] = sp->lcp.magic >> 24;
+ opt[3] = sp->lcp.magic >> 16;
+ opt[4] = sp->lcp.magic >> 8;
+ opt[5] = sp->lcp.magic;
+ sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, ++sp->pp_seq,
+ sizeof (opt), &opt);
+ timeout (sppp_cp_timeout, (caddr_t) sp, hz * 5);
+}
+
+void sppp_ipcp_open (struct sppp *sp)
+{
+ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, ++sp->pp_seq, 0, 0);
+ timeout (sppp_cp_timeout, (caddr_t) sp, hz * 5);
+}
+
+/*
+ * Process PPP control protocol timeouts.
+ */
+void sppp_cp_timeout (caddr_t arg, int dummy)
+{
+ struct sppp *sp = (struct sppp*) arg;
+ struct ifnet *ifp = &sp->pp_if;
+ int s = splimp ();
+
+ switch (sp->lcp.state) {
+ case LCP_STATE_CLOSED:
+ /* No ACK for Configure-Request, retry. */
+ sppp_lcp_open (sp);
+ break;
+ case LCP_STATE_ACK_RCVD:
+ /* ACK got, but no Configure-Request for peer, retry. */
+ sppp_lcp_open (sp);
+ sp->lcp.state = LCP_STATE_CLOSED;
+ break;
+ case LCP_STATE_ACK_SENT:
+ /* ACK sent but no ACK for Configure-Request, retry. */
+ sppp_lcp_open (sp);
+ break;
+ case LCP_STATE_OPENED:
+ /* LCP is already OK, try IPCP. */
+ switch (sp->ipcp.state) {
+ case IPCP_STATE_CLOSED:
+ /* No ACK for Configure-Request, retry. */
+ sppp_ipcp_open (sp);
+ break;
+ case IPCP_STATE_ACK_RCVD:
+ /* ACK got, but no Configure-Request for peer, retry. */
+ sppp_ipcp_open (sp);
+ sp->ipcp.state = IPCP_STATE_CLOSED;
+ break;
+ case IPCP_STATE_ACK_SENT:
+ /* ACK sent but no ACK for Configure-Request, retry. */
+ sppp_ipcp_open (sp);
+ break;
+ case IPCP_STATE_OPENED:
+ /* IPCP is OK. */
+ break;
+ }
+ break;
+ }
+ splx (s);
+}
+
+char *sppp_lcp_type_name (unsigned char type)
+{
+ static char buf [8];
+ switch (type) {
+ case LCP_CONF_REQ: return ("conf-req");
+ case LCP_CONF_ACK: return ("conf-ack");
+ case LCP_CONF_NAK: return ("conf-nack");
+ case LCP_CONF_REJ: return ("conf-rej");
+ case LCP_TERM_REQ: return ("term-req");
+ case LCP_TERM_ACK: return ("term-ack");
+ case LCP_CODE_REJ: return ("code-rej");
+ case LCP_PROTO_REJ: return ("proto-rej");
+ case LCP_ECHO_REQ: return ("echo-req");
+ case LCP_ECHO_REPLY: return ("echo-reply");
+ case LCP_DISC_REQ: return ("discard-req");
+ }
+ sprintf (buf, "%xh", type);
+ return (buf);
+}
+
+char *sppp_ipcp_type_name (unsigned char type)
+{
+ static char buf [8];
+ switch (type) {
+ case IPCP_CONF_REQ: return ("conf-req");
+ case IPCP_CONF_ACK: return ("conf-ack");
+ case IPCP_CONF_NAK: return ("conf-nack");
+ case IPCP_CONF_REJ: return ("conf-rej");
+ case IPCP_TERM_REQ: return ("term-req");
+ case IPCP_TERM_ACK: return ("term-ack");
+ case IPCP_CODE_REJ: return ("code-rej");
+ }
+ sprintf (buf, "%xh", type);
+ return (buf);
+}
+
+void sppp_print_bytes (unsigned char *p, unsigned short len)
+{
+ printf (" %x", *p++);
+ while (--len > 0)
+ printf ("-%x", *p++);
+}
OpenPOWER on IntegriCloud