summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorhm <hm@FreeBSD.org>2001-01-11 14:35:45 +0000
committerhm <hm@FreeBSD.org>2001-01-11 14:35:45 +0000
commitd1aa54787886163037633da6a38c68c51eb73c7e (patch)
treedd64bb0f1a80ed41a13886b981e869713dfd33b6 /sys
parentd60e64a0cf8549645127fc90e0751a4dfaea372b (diff)
downloadFreeBSD-src-d1aa54787886163037633da6a38c68c51eb73c7e.zip
FreeBSD-src-d1aa54787886163037633da6a38c68c51eb73c7e.tar.gz
Add the ISDN itjc hardware driver. This driver supports the NETJet-S cards
from Traverse Technology and also the Teles PCI-TJ cards both based on the chipset combination of the Siemens ISAC and the TJNet Tiger300/320 chips. The itjc/i4b_hdlc.h file will hopefully soon be merged with the file /usr/src/sys/i4b/layer1/i4b_hdlc.h. Submitted by: Sergio de Souza Prallon <prallon@tmp.com.br>
Diffstat (limited to 'sys')
-rw-r--r--sys/i4b/layer1/i4b_l1.h8
-rw-r--r--sys/i4b/layer1/i4b_l1dmux.c23
-rw-r--r--sys/i4b/layer1/itjc/i4b_hdlc.h412
-rw-r--r--sys/i4b/layer1/itjc/i4b_itjc_ext.h59
-rw-r--r--sys/i4b/layer1/itjc/i4b_itjc_isac.c552
-rw-r--r--sys/i4b/layer1/itjc/i4b_itjc_l1.c243
-rw-r--r--sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c520
-rw-r--r--sys/i4b/layer1/itjc/i4b_itjc_pci.c2134
8 files changed, 3942 insertions, 9 deletions
diff --git a/sys/i4b/layer1/i4b_l1.h b/sys/i4b/layer1/i4b_l1.h
index 55d6860..50360db 100644
--- a/sys/i4b/layer1/i4b_l1.h
+++ b/sys/i4b/layer1/i4b_l1.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 2000, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,9 @@
* i4b_l1.h - isdn4bsd layer 1 header file
* ---------------------------------------
*
- * $Id: i4b_l1.h,v 1.15 2000/06/02 16:14:36 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Thu Oct 26 08:42:44 2000]
+ * last edit-date: [Wed Jan 10 16:42:27 2001]
*
*---------------------------------------------------------------------------*/
@@ -71,6 +69,7 @@
#define FLAG_ACER_P10 26
#define FLAG_TELEINT_NO_1 27
#define FLAG_CCD_HFCS_PCI 28
+#define FLAG_NETJET_S 29
#define SEC_DELAY 1000000 /* one second DELAY for DELAY*/
@@ -91,6 +90,7 @@
#define L0IHFCUNIT(u) ( (((L1DRVR_IHFC) << 8) & 0xff00) | ((u) & 0xff))
#define L0IFPNPUNIT(u) ( (((L1DRVR_IFPNP) << 8) & 0xff00) | ((u) & 0xff))
#define L0ICCHPUNIT(u) ( (((L1DRVR_ICCHP) << 8) & 0xff00) | ((u) & 0xff))
+#define L0ITJCUNIT(u) ( (((L1DRVR_ITJC) << 8) & 0xff00) | ((u) & 0xff))
/* jump table for the multiplex functions */
struct i4b_l1mux_func {
diff --git a/sys/i4b/layer1/i4b_l1dmux.c b/sys/i4b/layer1/i4b_l1dmux.c
index c65bb8c..9df32b5 100644
--- a/sys/i4b/layer1/i4b_l1dmux.c
+++ b/sys/i4b/layer1/i4b_l1dmux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000 Hellmuth Michaelis. All rights reserved.
+ * Copyright (c) 2000, 2001 Hellmuth Michaelis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,11 +27,9 @@
* i4b_l1dmux.c - isdn4bsd layer 1 driver multiplexer
* --------------------------------------------------
*
- * $Id: i4b_l1dmux.c,v 1.12 2000/06/02 16:14:36 hm Exp $
- *
* $FreeBSD$
*
- * last edit-date: [Fri Jun 2 14:37:39 2000]
+ * last edit-date: [Wed Jan 10 16:43:24 2001]
*
*---------------------------------------------------------------------------*/
@@ -40,11 +38,11 @@
#include "ifpi.h"
#include "ifpnp.h"
#include "ihfc.h"
+#include "itjc.h"
#include <sys/param.h>
#include <sys/systm.h>
-
#include <machine/i4b_debug.h>
#include <machine/i4b_ioctl.h>
#include <machine/i4b_trace.h>
@@ -105,6 +103,10 @@ static int l1ihfcunittab[MAXL1UNITS];
static int l1ifpnpunittab[MAXL1UNITS];
#endif
+#if NITJC > 0
+static int l1itjcunittab[MAXL1UNITS];
+#endif
+
static int numl1units = 0;
static int l1drvunittab[MAXL1UNITS];
@@ -185,6 +187,11 @@ getl1tab(int drv)
return(l1ifpnpunittab);
break;
#endif
+#if NITJC > 0
+ case L1DRVR_ITJC:
+ return(l1itjcunittab);
+ break;
+#endif
default:
return(NULL);
break;
@@ -316,6 +323,12 @@ i4b_l1_mph_status_ind(int drv_unit, int status, int parm, struct i4b_l1mux_func
#if NIHFC > 0
case L1DRVR_IHFC:
printf("ihfc%d: passive stack unit %d\n", L0UNIT(drv_unit), numl1units);
+ break;
+#endif
+#if NITJC > 0
+ case L1DRVR_ITJC:
+ printf("itjc%d: passive stack unit %d\n", L0UNIT(drv_unit), numl1units);
+ break;
#endif
}
diff --git a/sys/i4b/layer1/itjc/i4b_hdlc.h b/sys/i4b/layer1/itjc/i4b_hdlc.h
new file mode 100644
index 0000000..ccc60ca
--- /dev/null
+++ b/sys/i4b/layer1/itjc/i4b_hdlc.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2000 Hans Petter Selasky. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_hdlc.h - software-HDLC header file
+ * --------------------------------------
+ *
+ * $Id: i4b_hdlc.h,v 1.5 2000/08/28 07:41:19 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Thu Jan 11 11:31:01 2001]
+ *
+ * Please conform "ihfc/i4b_ihfc_drv.c" (ihfc_hdlc_Bxxxx)
+ * for correct usage! (-hp)
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _I4B_HDLC_H_
+#define _I4B_HDLC_H_
+
+/*---------------------------------------------------------------------------*
+ * HDLC CRC table
+ *
+ * Usage:
+ * crc = (HDLC_FCS_TAB[(u_char)(crc ^ byte of data)] ^ (u_char)(crc >> 8));
+ *
+ * For more information see RFC 1662 (p. 10)
+ *---------------------------------------------------------------------------*/
+static const u_short HDLC_FCS_TAB[256] = { 0x0000,
+ 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48,
+ 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081,
+ 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9,
+ 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102,
+ 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a,
+ 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183,
+ 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb,
+ 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204,
+ 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c,
+ 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285,
+ 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd,
+ 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306,
+ 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e,
+ 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387,
+ 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf,
+ 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408,
+ 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840,
+ 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489,
+ 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1,
+ 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a,
+ 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942,
+ 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b,
+ 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3,
+ 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c,
+ 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44,
+ 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d,
+ 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5,
+ 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e,
+ 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46,
+ 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f,
+ 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7,
+ 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*---------------------------------------------------------------------------*
+ * HDLC bit table
+ * ==============
+ *
+ * bits[0..3]: A value which tells how many set bits there are at the
+ * beginning of the byte.
+ *
+ * bits[4..7]: Special bytes like 0x7e, 0x7d, 0xfd ... are flagged here
+ * NOTE: Special bytes also means 'abort' bytes (7 or more
+ * continuous set bits)
+ *
+ * bits[8..11]: A copy of bits[0..3] but only incremented by one.
+ * NOTE: 0x7e has value '8' instead of '0'. Internal reasons.
+ *
+ * bits[12..15]: A value which tells how many set bits there are at the
+ * end of the byte.
+ * NOTE: 0xff has both '8' incoming and '8' outgoing bits.
+ *
+ *---------------------------------------------------------------------------*/
+static const u_short HDLC_BIT_TAB[256] = { 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0605, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0160, 0x0706, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0605, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0504, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x0100, 0x0201, 0x0100, 0x0403, 0x0100,
+ 0x0201, 0x0100, 0x0302, 0x01a0, 0x02a1, 0x0860, 0x0807, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1504, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1605, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1504, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1100, 0x1403, 0x1100,
+ 0x1201, 0x1100, 0x1302, 0x1100, 0x1201, 0x1160, 0x1706, 0x2100,
+ 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2403, 0x2100,
+ 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2504, 0x2100,
+ 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2403, 0x2100,
+ 0x2201, 0x2100, 0x2302, 0x2100, 0x2201, 0x2100, 0x2605, 0x3100,
+ 0x3201, 0x3100, 0x3302, 0x3100, 0x3201, 0x3100, 0x3403, 0x3100,
+ 0x3201, 0x3100, 0x3302, 0x3100, 0x3201, 0x3100, 0x3504, 0x4100,
+ 0x4201, 0x4100, 0x4302, 0x4100, 0x4201, 0x4100, 0x4403, 0x5100,
+ 0x5201, 0x5100, 0x5302, 0x6180, 0x6281, 0x7150, 0x8908
+};
+
+/*---------------------------------------------------------------------------*
+ * HDLC_DECODE
+ * ===========
+ *
+ * u_char: flag, blevel
+ * u_short: crc, ib, tmp, tmp2, len
+ *
+ * next: 'continue' or 'goto xxx'
+ *
+ * cfr: complete frame
+ * nfr: new frame
+ * NOTE: must setup 'len' and 'dst', so that 'dst' may be written
+ * at most 'len' times.
+ *
+ * rab: abort
+ * rdd: read data (read byte is stored in 'tmp2')
+ * rdo: overflow
+ *
+ * d: dummy
+ *
+ * NOTE: setting flag to '0' and len to '0' => recover from rdu
+ * NOTE: bits[8 .. ] of tmp2 may be used to store custom data/flags
+ * NOTE: these variables have to be 'suspended' / 'resumed' somehow:
+ * flag, blevel, crc, ib, tmp, len
+ * NOTE: zero is default value for all variables.
+ * NOTE: each time 'dst' is written, 'len' is decreased by one.
+ *---------------------------------------------------------------------------*/
+
+#define HDLC_DECODE(dst, len, tmp, tmp2, blevel, ib, crc, flag, rddcmd, nfrcmd, \
+ cfrcmd, rabcmd, rdocmd, nextcmd, d) \
+ \
+ rddcmd; \
+ \
+ ib += HDLC_BIT_TAB[(u_char)tmp2]; \
+ \
+ if ((u_char)ib >= 5) \
+ { \
+ if (ib & 0x20) /* de-stuff (msb) */ \
+ { \
+ if ((u_char)tmp2 == 0x7e) goto j0##d; \
+ tmp2 += tmp2 & 0x7f; \
+ blevel--; \
+ \
+ if ((ib += 0x100) & 0xc) tmp2 |= 1; /* */ \
+ } \
+ \
+ ib &= ~0xe0; \
+ \
+ if ((u_char)ib == 6) /* flag seq (lsb) */ \
+ { \
+ j0##d: if (flag >= 2) \
+ { \
+ len += (4 - flag) & 3; /* remove CRC bytes */ \
+ crc ^= 0xf0b8; \
+ cfrcmd; \
+ len = 0; \
+ } \
+ \
+ flag = 1; \
+ \
+ blevel = (ib >> 8) & 0xf; \
+ tmp = ((u_char)tmp2) >> blevel; \
+ blevel = 8 - blevel; \
+ \
+ ib >>= 12; \
+ \
+ nextcmd; \
+ } \
+ if ((u_char)ib >= 7) /* abort (msb & lsb) */ \
+ { \
+ if (flag >= 2) \
+ { \
+ rabcmd; \
+ len = 0; \
+ } \
+ \
+ flag = 0; \
+ \
+ ib >>= 12; \
+ \
+ nextcmd; \
+ } \
+ if ((u_char)ib == 5) /* de-stuff (lsb) */ \
+ { \
+ tmp2 = (tmp2 | (tmp2 + 1)) & ~0x1; \
+ blevel--; \
+ } \
+ if (blevel > 7) /* EO - bits */ \
+ { \
+ tmp |= (u_char)tmp2 >> (8 - (blevel &= 7)); \
+ \
+ ib >>= 12; \
+ \
+ nextcmd; \
+ } \
+ } \
+ \
+ tmp |= (u_char)tmp2 << blevel; \
+ \
+ if (!len--) \
+ { \
+ len++; \
+ \
+ if (!flag++) { flag--; goto j5##d;} /* hunt mode */ \
+ \
+ switch (flag) \
+ { case 2: /* new frame */ \
+ nfrcmd; \
+ crc = -1; \
+ if (!len--) { len++; flag++; goto j4##d; } \
+ goto j3##d; \
+ case 3: /* CRC (lsb's) */ \
+ case 4: /* CRC (msb's) */ \
+ goto j4##d; \
+ case 5: /* RDO */ \
+ rdocmd; \
+ flag = 0; \
+ break; \
+ } \
+ } \
+ else \
+ { \
+ j3##d: dst = (u_char)tmp; \
+ j4##d: crc = (HDLC_FCS_TAB[(u_char)(tmp ^ crc)] ^ (u_char)(crc >> 8)); \
+ } \
+ \
+ j5##d: ib >>= 12; \
+ tmp >>= 8; \
+
+/*------ end of HDLC_DECODE -------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*
+ * HDLC_ENCODE
+ * ===========
+ *
+ * u_char: flag, src
+ * u_short: tmp2, blevel, ib, crc, len
+ * u_int: tmp
+ *
+ * gfr: This is the place where you free the last [mbuf] chain, and get
+ * the next one. If a mbuf is available the code should setup 'len'
+ * and 'src' so that 'src' may be read 'len' times. If no mbuf is
+ * available leave 'len' and 'src' untouched.
+ *
+ * nmb: If your implementation accept/use chained mbufs, this is the
+ * place where you update 'len' and 'src' to the next mbuf of
+ * the chain that makes up a frame. If no further mbuf is
+ * available leave 'len' and 'src' untouched. This is not the
+ * place where you free the mbuf. Leave the block empty if your
+ * implementation does not accept/use chained mbufs.
+ *
+ * wrd: write data (output = (u_char)tmp)
+ *
+ * d: dummy
+ *
+ * NOTE: setting flag to '-2' and len to '0' => abort bytes will be sent
+ * NOTE: these variables have to be 'suspended' / 'resumed' somehow:
+ * flag, blevel, crc, ib, tmp, len
+ * NOTE: zero is default value for all variables.
+ * NOTE: each time 'src' is read, 'len' is decreased by one.
+ * NOTE: neither cmd's should exit through 'goto' or 'break' statements.
+ *---------------------------------------------------------------------------*/
+
+#define HDLC_ENCODE(src, len, tmp, tmp2, blevel, ib, crc, flag, gfrcmd, nmbcmd, wrdcmd, d) \
+ \
+ if (blevel >= 0x800) { blevel -= 0x800; goto j4##d; } \
+ \
+ if (!len--) \
+ { \
+ len++; \
+ \
+ switch(++flag) \
+ { default: /* abort */ \
+ tmp = blevel = 0; /* zero is default */ \
+ tmp2 = 0xff; \
+ goto j3##d; \
+ case 1: /* 1st time FS */ \
+ case 2: /* 2nd time FS */ \
+ tmp2 = 0x7e; \
+ goto j3##d; \
+ case 3: \
+ gfrcmd; /* get new frame */ \
+ if (!len--) \
+ { \
+ len++; \
+ flag--; /* don't proceed */ \
+ tmp2 = 0x7e; \
+ goto j3##d; /* final FS */ \
+ } \
+ else \
+ { \
+ crc = -1; \
+ ib = 0; \
+ goto j1##d; /* first byte */ \
+ } \
+ case 4: \
+ nmbcmd; /* get next mbuf in chain */ \
+ if (!len--) \
+ { \
+ len++; \
+ crc ^= -1; \
+ tmp2 = (u_char)crc; \
+ goto j2##d; /* CRC (lsb's) */ \
+ } \
+ else \
+ { \
+ flag--; \
+ goto j1##d; /* proceed with the frame */ \
+ } \
+ case 5: \
+ tmp2 = (u_char)(crc >> 8); \
+ flag = 1; \
+ goto j2##d; /* CRC (msb's) */ \
+ } \
+ } \
+ else \
+ { j1##d : \
+ tmp2 = (u_char)src; \
+ crc =(HDLC_FCS_TAB[(u_char)(crc ^ tmp2)] ^ (u_char)(crc >> 8)); \
+ j2##d: \
+ \
+ ib >>= 12; \
+ ib += HDLC_BIT_TAB[(u_char)tmp2]; \
+ \
+ if ((u_char)ib >= 5) /* stuffing */ \
+ { \
+ blevel &= ~0xff; \
+ \
+ if (ib & 0xc0) /* bit stuff (msb) */ \
+ { \
+ tmp2 += tmp2 & (0xff * (ib & 0xc0)); \
+ ib %= 0x5000; \
+ blevel++; \
+ } \
+ \
+ ib &= ~0xf0; \
+ \
+ if ((u_char)ib >= 5) /* bit stuff (lsb) */ \
+ { \
+ tmp2 += tmp2 & ~0x1f >> ((ib - (ib >> 8) + 1) \
+ & 7); \
+ blevel++; \
+ \
+ if ((u_char)ib >= 10) /* bit stuff (msb) */ \
+ { \
+ tmp2 += tmp2 & ~0x7ff >> ((ib - \
+ (ib >> 8) + 1) & 7); \
+ blevel++; \
+ } \
+ if (ib & 0x8000) /* bit walk */ \
+ { \
+ ib = ((u_char)ib % 5) << 12; \
+ } \
+ } \
+ \
+ tmp |= tmp2 << (u_char)(blevel >> 8); \
+ blevel += (u_char)blevel << 8; \
+ } \
+ else /* no stuffing */ \
+ { \
+ j3##d:tmp |= tmp2 << (u_char)(blevel >> 8); \
+ } \
+ } \
+ \
+ j4##d: wrdcmd; \
+ tmp >>= 8; \
+
+/*------ end of HDLC_ENCODE -------------------------------------------------*/
+
+
+#endif /* _I4B_HDLC_H_ */
diff --git a/sys/i4b/layer1/itjc/i4b_itjc_ext.h b/sys/i4b/layer1/itjc/i4b_itjc_ext.h
new file mode 100644
index 0000000..72631e5
--- /dev/null
+++ b/sys/i4b/layer1/itjc/i4b_itjc_ext.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2000, 2001 Sergio Prallon. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_itjc - NetJet PCI for split layers
+ * ------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Wed Jan 10 17:15:31 2001]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _I4B_ITJC_EXT_H_
+#define _I4B_ITJC_EXT_H_
+
+#include <i4b/include/i4b_l3l4.h>
+
+void itjc_set_linktab(int unit, int channel, drvr_link_t * dlt);
+isdn_link_t *itjc_ret_linktab(int unit, int channel);
+
+int itjc_ph_data_req(int unit, struct mbuf *m, int freeflag);
+int itjc_ph_activate_req(int unit);
+int itjc_mph_command_req(int unit, int command, void *parm);
+
+void itjc_isac_irq(struct l1_softc *sc, int ista);
+void itjc_isac_l1_cmd(struct l1_softc *sc, int command);
+int itjc_isac_init(struct l1_softc *sc);
+
+void itjc_recover(struct l1_softc *sc);
+char * itjc_printstate(struct l1_softc *sc);
+void itjc_next_state(struct l1_softc *sc, int event);
+
+#define ITJC_MAXUNIT 4
+extern struct l1_softc *itjc_scp[ITJC_MAXUNIT];
+
+#endif /* _I4B_ITJC_EXT_H_ */
diff --git a/sys/i4b/layer1/itjc/i4b_itjc_isac.c b/sys/i4b/layer1/itjc/i4b_itjc_isac.c
new file mode 100644
index 0000000..d0d80c6
--- /dev/null
+++ b/sys/i4b/layer1/itjc/i4b_itjc_isac.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_itjc_isac.c - i4b NetJet-S ISAC handler
+ * --------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Wed Jan 10 17:15:54 2001]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "itjc.h"
+#include "pci.h"
+
+#if (NITJC > 0)
+
+#include "opt_i4b.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#include <machine/stdarg.h>
+#include <machine/clock.h>
+
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/layer1/i4b_l1.h>
+
+#include <i4b/layer1/isic/i4b_isic.h>
+#include <i4b/layer1/isic/i4b_isac.h>
+
+#include <i4b/layer1/itjc/i4b_itjc_ext.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+
+static u_char itjc_isac_exir_hdlr(register struct l1_softc *sc, u_char exir);
+static void itjc_isac_ind_hdlr(register struct l1_softc *sc, int ind);
+
+/*---------------------------------------------------------------------------*
+ * ISAC interrupt service routine
+ *---------------------------------------------------------------------------*/
+void
+itjc_isac_irq(struct l1_softc *sc, int ista)
+{
+ register u_char c = 0;
+ NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista);
+
+ if(ista & ISAC_ISTA_EXI) /* extended interrupt */
+ {
+ c |= itjc_isac_exir_hdlr(sc, ISAC_READ(I_EXIR));
+ }
+
+ if(ista & ISAC_ISTA_RME) /* receive message end */
+ {
+ register int rest;
+ u_char rsta;
+
+ /* get rx status register */
+
+ rsta = ISAC_READ(I_RSTA);
+
+ if((rsta & ISAC_RSTA_MASK) != 0x20)
+ {
+ int error = 0;
+
+ if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */
+ {
+ error++;
+ NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit);
+ }
+
+ if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */
+ {
+ error++;
+ NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit);
+ }
+
+ if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */
+ {
+ error++;
+ NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit);
+ }
+
+ if(error == 0)
+ NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta);
+
+ i4b_Dfreembuf(sc->sc_ibuf);
+
+ c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
+
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+
+ ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES);
+ ISACCMDRWRDELAY();
+
+ return;
+ }
+
+ rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1));
+
+ if(rest == 0)
+ rest = ISAC_FIFO_LEN;
+
+ if(sc->sc_ibuf == NULL)
+ {
+ if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL)
+ sc->sc_ib = sc->sc_ibuf->m_data;
+ else
+ panic("itjc_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n");
+ sc->sc_ilen = 0;
+ }
+
+ if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest))
+ {
+ ISAC_RDFIFO(sc->sc_ib, rest);
+ sc->sc_ilen += rest;
+
+ sc->sc_ibuf->m_pkthdr.len =
+ sc->sc_ibuf->m_len = sc->sc_ilen;
+
+ if(sc->sc_trace & TRACE_D_RX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_D;
+ hdr.dir = FROM_NT;
+ hdr.count = ++sc->sc_trace_dcount;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data);
+ }
+
+ c |= ISAC_CMDR_RMC;
+
+ if(sc->sc_enabled &&
+ (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S))
+ {
+ i4b_l1_ph_data_ind(L0ITJCUNIT(sc->sc_unit), sc->sc_ibuf);
+ }
+ else
+ {
+ i4b_Dfreembuf(sc->sc_ibuf);
+ }
+ }
+ else
+ {
+ NDBGL1(L1_I_ERR, "RME, input buffer overflow!");
+ i4b_Dfreembuf(sc->sc_ibuf);
+ c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
+ }
+
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+ }
+
+ if(ista & ISAC_ISTA_RPF) /* receive fifo full */
+ {
+ if(sc->sc_ibuf == NULL)
+ {
+ if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL)
+ sc->sc_ib= sc->sc_ibuf->m_data;
+ else
+ panic("itjc_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n");
+ sc->sc_ilen = 0;
+ }
+
+ if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN))
+ {
+ ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN);
+ sc->sc_ilen += ISAC_FIFO_LEN;
+ sc->sc_ib += ISAC_FIFO_LEN;
+ c |= ISAC_CMDR_RMC;
+ }
+ else
+ {
+ NDBGL1(L1_I_ERR, "RPF, input buffer overflow!");
+ i4b_Dfreembuf(sc->sc_ibuf);
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+ c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
+ }
+ }
+
+ if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */
+ {
+ if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL))
+ {
+ sc->sc_freeflag = sc->sc_freeflag2;
+ sc->sc_obuf = sc->sc_obuf2;
+ sc->sc_op = sc->sc_obuf->m_data;
+ sc->sc_ol = sc->sc_obuf->m_len;
+ sc->sc_obuf2 = NULL;
+ }
+
+ if(sc->sc_obuf)
+ {
+ ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN));
+
+ if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */
+ {
+ sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */
+ sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */
+ c |= ISAC_CMDR_XTF; /* set XTF bit */
+ }
+ else
+ {
+ if(sc->sc_freeflag)
+ {
+ i4b_Dfreembuf(sc->sc_obuf);
+ sc->sc_freeflag = 0;
+ }
+ sc->sc_obuf = NULL;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+
+ c |= ISAC_CMDR_XTF | ISAC_CMDR_XME;
+ }
+ }
+ else
+ {
+ sc->sc_state &= ~ISAC_TX_ACTIVE;
+ }
+ }
+
+ if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */
+ {
+ register u_char ci;
+
+ /* get command/indication rx register*/
+
+ ci = ISAC_READ(I_CIRR);
+
+ /* if S/Q IRQ, read SQC reg to clr SQC IRQ */
+
+ if(ci & ISAC_CIRR_SQC)
+ (void) ISAC_READ(I_SQRR);
+
+ /* C/I code change IRQ (flag already cleared by CIRR read) */
+
+ if(ci & ISAC_CIRR_CIC0)
+ itjc_isac_ind_hdlr(sc, (ci >> 2) & 0xf);
+ }
+
+ if(c)
+ {
+ ISAC_WRITE(I_CMDR, c);
+ ISACCMDRWRDELAY();
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * ISAC L1 Extended IRQ handler
+ *---------------------------------------------------------------------------*/
+static u_char
+itjc_isac_exir_hdlr(register struct l1_softc *sc, u_char exir)
+{
+ u_char c = 0;
+
+ if(exir & ISAC_EXIR_XMR)
+ {
+ NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat");
+
+ c |= ISAC_CMDR_XRES;
+ }
+
+ if(exir & ISAC_EXIR_XDU)
+ {
+ NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun");
+
+ c |= ISAC_CMDR_XRES;
+ }
+
+ if(exir & ISAC_EXIR_PCE)
+ {
+ NDBGL1(L1_I_ERR, "EXIRQ Protocol Error");
+ }
+
+ if(exir & ISAC_EXIR_RFO)
+ {
+ NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow");
+
+ c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES;
+ }
+
+ if(exir & ISAC_EXIR_SOV)
+ {
+ NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow");
+ }
+
+ if(exir & ISAC_EXIR_MOS)
+ {
+ NDBGL1(L1_I_ERR, "EXIRQ Monitor Status");
+ }
+
+ if(exir & ISAC_EXIR_SAW)
+ {
+ /* cannot happen, STCR:TSF is set to 0 */
+
+ NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake");
+ }
+
+ if(exir & ISAC_EXIR_WOV)
+ {
+ /* cannot happen, STCR:TSF is set to 0 */
+
+ NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow");
+ }
+
+ return(c);
+}
+
+/*---------------------------------------------------------------------------*
+ * ISAC L1 Indication handler
+ *---------------------------------------------------------------------------*/
+static void
+itjc_isac_ind_hdlr(register struct l1_softc *sc, int ind)
+{
+ register int event;
+
+ switch(ind)
+ {
+ case ISAC_CIRR_IAI8:
+ NDBGL1(L1_I_CICO, "rx AI8 in state %s", itjc_printstate(sc));
+ itjc_isac_l1_cmd(sc, CMD_AR8);
+ event = EV_INFO48;
+ i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
+ break;
+
+ case ISAC_CIRR_IAI10:
+ NDBGL1(L1_I_CICO, "rx AI10 in state %s", itjc_printstate(sc));
+ itjc_isac_l1_cmd(sc, CMD_AR10);
+ event = EV_INFO410;
+ i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
+ break;
+
+ case ISAC_CIRR_IRSY:
+ NDBGL1(L1_I_CICO, "rx RSY in state %s", itjc_printstate(sc));
+ event = EV_RSY;
+ break;
+
+ case ISAC_CIRR_IPU:
+ NDBGL1(L1_I_CICO, "rx PU in state %s", itjc_printstate(sc));
+ event = EV_PU;
+ break;
+
+ case ISAC_CIRR_IDR:
+ NDBGL1(L1_I_CICO, "rx DR in state %s", itjc_printstate(sc));
+ itjc_isac_l1_cmd(sc, CMD_DIU);
+ event = EV_DR;
+ break;
+
+ case ISAC_CIRR_IDID:
+ NDBGL1(L1_I_CICO, "rx DID in state %s", itjc_printstate(sc));
+ event = EV_INFO0;
+ i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL);
+ break;
+
+ case ISAC_CIRR_IDIS:
+ NDBGL1(L1_I_CICO, "rx DIS in state %s", itjc_printstate(sc));
+ event = EV_DIS;
+ break;
+
+ case ISAC_CIRR_IEI:
+ NDBGL1(L1_I_CICO, "rx EI in state %s", itjc_printstate(sc));
+ itjc_isac_l1_cmd(sc, CMD_DIU);
+ event = EV_EI;
+ break;
+
+ case ISAC_CIRR_IARD:
+ NDBGL1(L1_I_CICO, "rx ARD in state %s", itjc_printstate(sc));
+ event = EV_INFO2;
+ break;
+
+ case ISAC_CIRR_ITI:
+ NDBGL1(L1_I_CICO, "rx TI in state %s", itjc_printstate(sc));
+ event = EV_INFO0;
+ break;
+
+ case ISAC_CIRR_IATI:
+ NDBGL1(L1_I_CICO, "rx ATI in state %s", itjc_printstate(sc));
+ event = EV_INFO0;
+ break;
+
+ case ISAC_CIRR_ISD:
+ NDBGL1(L1_I_CICO, "rx SD in state %s", itjc_printstate(sc));
+ event = EV_INFO0;
+ break;
+
+ default:
+ NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, itjc_printstate(sc));
+ event = EV_INFO0;
+ break;
+ }
+ itjc_next_state(sc, event);
+}
+
+/*---------------------------------------------------------------------------*
+ * execute a layer 1 command
+ *---------------------------------------------------------------------------*/
+void
+itjc_isac_l1_cmd(struct l1_softc *sc, int command)
+{
+ u_char cmd;
+
+ if(command < 0 || command > CMD_ILL)
+ {
+ NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, itjc_printstate(sc));
+ return;
+ }
+
+ cmd = ISAC_CIX0_LOW;
+
+ switch(command)
+ {
+ case CMD_TIM:
+ NDBGL1(L1_I_CICO, "tx TIM in state %s", itjc_printstate(sc));
+ cmd |= (ISAC_CIXR_CTIM << 2);
+ break;
+
+ case CMD_RS:
+ NDBGL1(L1_I_CICO, "tx RS in state %s", itjc_printstate(sc));
+ cmd |= (ISAC_CIXR_CRS << 2);
+ break;
+
+ case CMD_AR8:
+ NDBGL1(L1_I_CICO, "tx AR8 in state %s", itjc_printstate(sc));
+ cmd |= (ISAC_CIXR_CAR8 << 2);
+ break;
+
+ case CMD_AR10:
+ NDBGL1(L1_I_CICO, "tx AR10 in state %s", itjc_printstate(sc));
+ cmd |= (ISAC_CIXR_CAR10 << 2);
+ break;
+
+ case CMD_DIU:
+ NDBGL1(L1_I_CICO, "tx DIU in state %s", itjc_printstate(sc));
+ cmd |= (ISAC_CIXR_CDIU << 2);
+ break;
+ }
+ ISAC_WRITE(I_CIXR, cmd);
+}
+
+/*---------------------------------------------------------------------------*
+ * L1 ISAC initialization
+ *---------------------------------------------------------------------------*/
+int
+itjc_isac_init(struct l1_softc *sc)
+{
+ ISAC_IMASK = 0xff; /* disable all irqs */
+
+ ISAC_WRITE(I_MASK, ISAC_IMASK);
+
+ NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode");
+
+ /* ADF2: Select mode IOM-2 */
+ ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS);
+
+ /* SPCR: serial port control register:
+ * SPU - software power up = 0
+ * SPM - timing mode 0
+ * TLP - test loop = 0
+ * C1C, C2C - B1 + C1 and B2 + IC2 monitoring
+ */
+ ISAC_WRITE(I_SPCR, 0x00);
+
+ /* SQXR: S/Q channel xmit register:
+ * IDC - IOM direction = 0 (master)
+ * CFS - Config Select = 0 (clock always active)
+ * CI1E - C/I channel 1 IRQ enable = 0
+ * SQIE - S/Q IRQ enable = 0
+ * SQX1-4 - Fa bits = 1
+ */
+ ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4);
+
+ /* ADF1: additional feature reg 1:
+ * WTC - watchdog = 0
+ * TEM - test mode = 0
+ * PFS - pre-filter = 0
+ * IOF - IOM i/f off = 0
+ * ITF - interframe fill = idle
+ */
+ ISAC_WRITE(I_ADF1, 0x00);
+
+ /* STCR: sync transfer control reg:
+ * TSF - terminal secific functions = 0
+ * TBA - TIC bus address = 7
+ * STx/SCx = 0
+ */
+ ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0);
+
+ /* MODE: Mode Register:
+ * MDSx - transparent mode 2
+ * TMD - timer mode = external
+ * RAC - Receiver enabled
+ * DIMx - digital i/f mode
+ */
+ ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0);
+
+ /* enabled interrupts:
+ * ===================
+ * RME - receive message end
+ * RPF - receive pool full
+ * XPR - transmit pool ready
+ * CISQ - CI or S/Q channel change
+ * EXI - extended interrupt
+ */
+
+ ISAC_IMASK = ISAC_MASK_RSC | /* auto mode only */
+ ISAC_MASK_TIN | /* timer irq */
+ ISAC_MASK_SIN; /* sync xfer irq */
+
+ ISAC_WRITE(I_MASK, ISAC_IMASK);
+
+ return(0);
+}
+
+#endif /* NITJC > 0 */
diff --git a/sys/i4b/layer1/itjc/i4b_itjc_l1.c b/sys/i4b/layer1/itjc/i4b_itjc_l1.c
new file mode 100644
index 0000000..6952caf
--- /dev/null
+++ b/sys/i4b/layer1/itjc/i4b_itjc_l1.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_itjc_l1.c - NetJet-S layer 1 handler
+ * ---------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Wed Jan 10 17:16:19 2001]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "itjc.h"
+#include "pci.h"
+
+#if (NITJC > 0) && (NPCI > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#include <machine/stdarg.h>
+#include <machine/clock.h>
+
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/layer1/isic/i4b_isic.h>
+#include <i4b/layer1/isic/i4b_isac.h>
+
+#include <i4b/layer1/itjc/i4b_itjc_ext.h>
+
+#include <i4b/layer1/i4b_l1.h>
+
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+
+/*---------------------------------------------------------------------------*
+ *
+ * L2 -> L1: PH-DATA-REQUEST
+ * =========================
+ *
+ * parms:
+ * unit physical interface unit number
+ * m mbuf containing L2 frame to be sent out
+ * freeflag MBUF_FREE: free mbuf here after having sent
+ * it out
+ * MBUF_DONTFREE: mbuf is freed by Layer 2
+ * returns:
+ * ==0 fail, nothing sent out
+ * !=0 ok, frame sent out
+ *
+ *---------------------------------------------------------------------------*/
+int
+itjc_ph_data_req(int unit, struct mbuf *m, int freeflag)
+{
+ u_char cmd;
+ int s;
+ struct l1_softc *sc = itjc_scp[unit];
+
+ NDBGL1(L1_PRIM, "PH-DATA-REQ, unit %d, freeflag=%d", unit, freeflag);
+
+ if(m == NULL) /* failsafe */
+ return (0);
+
+ s = SPLI4B();
+
+ if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */
+ {
+ NDBGL1(L1_I_ERR, "still in state F3!");
+ itjc_ph_activate_req(unit);
+ }
+
+ if(sc->sc_state & ISAC_TX_ACTIVE)
+ {
+ if(sc->sc_obuf2 == NULL)
+ {
+ sc->sc_obuf2 = m; /* save mbuf ptr */
+
+ if(freeflag)
+ sc->sc_freeflag2 = 1; /* IRQ must mfree */
+ else
+ sc->sc_freeflag2 = 0; /* IRQ must not mfree */
+
+ NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", itjc_printstate(sc));
+
+ if(sc->sc_trace & TRACE_D_TX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = L0ITJCUNIT(unit);
+ hdr.type = TRC_CH_D;
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_dcount;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
+ }
+ splx(s);
+ return(1);
+ }
+
+ NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", itjc_printstate(sc));
+
+ if(freeflag == MBUF_FREE)
+ i4b_Dfreembuf(m);
+
+ splx(s);
+ return (0);
+ }
+
+ if(sc->sc_trace & TRACE_D_TX)
+ {
+ i4b_trace_hdr_t hdr;
+ hdr.unit = L0ITJCUNIT(unit);
+ hdr.type = TRC_CH_D;
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_dcount;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
+ }
+
+ sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */
+
+ NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set");
+
+ sc->sc_freeflag = 0; /* IRQ must NOT mfree */
+
+ ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */
+
+ if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */
+ {
+ sc->sc_obuf = m; /* save mbuf ptr */
+ sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */
+ sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */
+
+ if(freeflag)
+ sc->sc_freeflag = 1; /* IRQ must mfree */
+
+ cmd = ISAC_CMDR_XTF;
+ }
+ else
+ {
+ sc->sc_obuf = NULL;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+
+ if(freeflag)
+ i4b_Dfreembuf(m);
+
+ cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
+ }
+
+ ISAC_WRITE(I_CMDR, cmd);
+ ISACCMDRWRDELAY();
+
+ splx(s);
+
+ return(1);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ * L2 -> L1: PH-ACTIVATE-REQUEST
+ * =============================
+ *
+ * parms:
+ * unit physical interface unit number
+ *
+ * returns:
+ * ==0
+ * !=0
+ *
+ *---------------------------------------------------------------------------*/
+int
+itjc_ph_activate_req(int unit)
+{
+ struct l1_softc *sc = itjc_scp[unit];
+ NDBGL1(L1_PRIM, "PH-ACTIVATE-REQ, unit %d", unit);
+ itjc_next_state(sc, EV_PHAR);
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * command from the upper layers
+ *---------------------------------------------------------------------------*/
+int
+itjc_mph_command_req(int unit, int command, void *parm)
+{
+ struct l1_softc *sc = itjc_scp[unit];
+
+ switch(command)
+ {
+ case CMR_DOPEN: /* daemon running */
+ NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit);
+ sc->sc_enabled = 1;
+ break;
+
+ case CMR_DCLOSE: /* daemon not running */
+ NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit);
+ sc->sc_enabled = 0;
+ break;
+
+ case CMR_SETTRACE:
+ NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm);
+ sc->sc_trace = (unsigned int)parm;
+ break;
+
+ default:
+ NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm);
+ break;
+ }
+
+ return(0);
+}
+
+#endif /* NITJC > 0 */
diff --git a/sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c b/sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c
new file mode 100644
index 0000000..2bc902a
--- /dev/null
+++ b/sys/i4b/layer1/itjc/i4b_itjc_l1fsm.c
@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_itjc_l1fsm.c - NetJet-S layer 1 I.430 state machine
+ * ------------------------------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Wed Jan 10 17:16:33 2001]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "itjc.h"
+#include "pci.h"
+
+#if (NITJC > 0) && (NPCI > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+
+#include <machine/stdarg.h>
+#include <machine/clock.h>
+
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/layer1/isic/i4b_isic.h>
+#include <i4b/layer1/isic/i4b_isac.h>
+#include <i4b/layer1/isic/i4b_hscx.h>
+
+#include <i4b/layer1/i4b_l1.h>
+
+#include <i4b/include/i4b_global.h>
+
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer1/itjc/i4b_itjc_ext.h>
+
+#if DO_I4B_DEBUG
+static char *state_text[N_STATES] = {
+ "F3 Deactivated",
+ "F4 Awaiting Signal",
+ "F5 Identifying Input",
+ "F6 Synchronized",
+ "F7 Activated",
+ "F8 Lost Framing",
+ "Illegal State"
+};
+
+static char *event_text[N_EVENTS] = {
+ "EV_PHAR PH_ACT_REQ",
+ "EV_T3 Timer 3 expired",
+ "EV_INFO0 INFO0 received",
+ "EV_RSY Level Detected",
+ "EV_INFO2 INFO2 received",
+ "EV_INFO48 INFO4 received",
+ "EV_INFO410 INFO4 received",
+ "EV_DR Deactivate Req",
+ "EV_PU Power UP",
+ "EV_DIS Disconnected",
+ "EV_EI Error Ind",
+ "Illegal Event"
+};
+#endif
+
+/* Function prototypes */
+
+static void timer3_expired (struct l1_softc *sc);
+static void T3_start (struct l1_softc *sc);
+static void T3_stop (struct l1_softc *sc);
+static void F_T3ex (struct l1_softc *sc);
+static void timer4_expired (struct l1_softc *sc);
+static void T4_start (struct l1_softc *sc);
+static void T4_stop (struct l1_softc *sc);
+static void F_AI8 (struct l1_softc *sc);
+static void F_AI10 (struct l1_softc *sc);
+static void F_I01 (struct l1_softc *sc);
+static void F_I02 (struct l1_softc *sc);
+static void F_I03 (struct l1_softc *sc);
+static void F_I2 (struct l1_softc *sc);
+static void F_ill (struct l1_softc *sc);
+static void F_NULL (struct l1_softc *sc);
+
+/*---------------------------------------------------------------------------*
+ * I.430 Timer T3 expire function
+ *---------------------------------------------------------------------------*/
+static void
+timer3_expired(struct l1_softc *sc)
+{
+ if(sc->sc_I430T3)
+ {
+ NDBGL1(L1_T_ERR, "state = %s", itjc_printstate(sc));
+ sc->sc_I430T3 = 0;
+
+ /* XXX try some recovery here XXX */
+
+ itjc_recover(sc);
+
+ sc->sc_init_tries++; /* increment retry count */
+
+/*XXX*/ if(sc->sc_init_tries > 4)
+ {
+ int s = SPLI4B();
+
+ sc->sc_init_tries = 0;
+
+ if(sc->sc_obuf2 != NULL)
+ {
+ i4b_Dfreembuf(sc->sc_obuf2);
+ sc->sc_obuf2 = NULL;
+ }
+ if(sc->sc_obuf != NULL)
+ {
+ i4b_Dfreembuf(sc->sc_obuf);
+ sc->sc_obuf = NULL;
+ sc->sc_freeflag = 0;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+ }
+
+ splx(s);
+
+ i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL);
+ }
+
+ itjc_next_state(sc, EV_T3);
+ }
+ else
+ {
+ NDBGL1(L1_T_ERR, "expired without starting it ....");
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * I.430 Timer T3 start
+ *---------------------------------------------------------------------------*/
+static void
+T3_start(struct l1_softc *sc)
+{
+ NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc));
+ sc->sc_I430T3 = 1;
+ sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz);
+}
+
+/*---------------------------------------------------------------------------*
+ * I.430 Timer T3 stop
+ *---------------------------------------------------------------------------*/
+static void
+T3_stop(struct l1_softc *sc)
+{
+ NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc));
+
+ sc->sc_init_tries = 0; /* init connect retry count */
+
+ if(sc->sc_I430T3)
+ {
+ sc->sc_I430T3 = 0;
+ untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * I.430 Timer T3 expiry
+ *---------------------------------------------------------------------------*/
+static void
+F_T3ex(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_T3ex executing");
+ if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)
+ i4b_l1_ph_deactivate_ind(L0ITJCUNIT(sc->sc_unit));
+}
+
+/*---------------------------------------------------------------------------*
+ * Timer T4 expire function
+ *---------------------------------------------------------------------------*/
+static void
+timer4_expired(struct l1_softc *sc)
+{
+ if(sc->sc_I430T4)
+ {
+ NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc));
+ sc->sc_I430T4 = 0;
+ i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_PDEACT, 0, NULL);
+ }
+ else
+ {
+ NDBGL1(L1_T_ERR, "expired without starting it ....");
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Timer T4 start
+ *---------------------------------------------------------------------------*/
+static void
+T4_start(struct l1_softc *sc)
+{
+ NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc));
+ sc->sc_I430T4 = 1;
+ sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz);
+}
+
+/*---------------------------------------------------------------------------*
+ * Timer T4 stop
+ *---------------------------------------------------------------------------*/
+static void
+T4_stop(struct l1_softc *sc)
+{
+ NDBGL1(L1_T_MSG, "state = %s", itjc_printstate(sc));
+
+ if(sc->sc_I430T4)
+ {
+ sc->sc_I430T4 = 0;
+ untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: received AI8
+ *---------------------------------------------------------------------------*/
+static void
+F_AI8(struct l1_softc *sc)
+{
+ T4_stop(sc);
+
+ NDBGL1(L1_F_MSG, "FSM function F_AI8 executing");
+
+ if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)
+ i4b_l1_ph_activate_ind(L0ITJCUNIT(sc->sc_unit));
+
+ T3_stop(sc);
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO4_8;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_NT;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: received AI10
+ *---------------------------------------------------------------------------*/
+static void
+F_AI10(struct l1_softc *sc)
+{
+ T4_stop(sc);
+
+ NDBGL1(L1_F_MSG, "FSM function F_AI10 executing");
+
+ if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)
+ i4b_l1_ph_activate_ind(L0ITJCUNIT(sc->sc_unit));
+
+ T3_stop(sc);
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO4_10;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_NT;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: received INFO 0 in states F3 .. F5
+ *---------------------------------------------------------------------------*/
+static void
+F_I01(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_I01 executing");
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO0;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_NT;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: received INFO 0 in state F6
+ *---------------------------------------------------------------------------*/
+static void
+F_I02(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_I02 executing");
+
+ if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)
+ i4b_l1_ph_deactivate_ind(L0ITJCUNIT(sc->sc_unit));
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO0;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_NT;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: received INFO 0 in state F7 or F8
+ *---------------------------------------------------------------------------*/
+static void
+F_I03(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_I03 executing");
+
+ if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)
+ i4b_l1_ph_deactivate_ind(L0ITJCUNIT(sc->sc_unit));
+
+ T4_start(sc);
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO0;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_NT;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: activate request
+ *---------------------------------------------------------------------------*/
+static void
+F_AR(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_AR executing");
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO1_8;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_TE;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+
+ itjc_isac_l1_cmd(sc, CMD_AR8);
+
+ T3_start(sc);
+}
+
+/*---------------------------------------------------------------------------*
+ * FSM function: received INFO2
+ *---------------------------------------------------------------------------*/
+static void
+F_I2(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_I2 executing");
+
+ if(sc->sc_trace & TRACE_I)
+ {
+ i4b_trace_hdr_t hdr;
+ char info = INFO2;
+
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = TRC_CH_I;
+ hdr.dir = FROM_NT;
+ hdr.count = 0;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, 1, &info);
+ }
+
+}
+
+/*---------------------------------------------------------------------------*
+ * illegal state default action
+ *---------------------------------------------------------------------------*/
+static void
+F_ill(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_ERR, "FSM function F_ill executing");
+}
+
+/*---------------------------------------------------------------------------*
+ * No action
+ *---------------------------------------------------------------------------*/
+static void
+F_NULL(struct l1_softc *sc)
+{
+ NDBGL1(L1_F_MSG, "FSM function F_NULL executing");
+}
+
+
+/*---------------------------------------------------------------------------*
+ * layer 1 state transition table
+ *---------------------------------------------------------------------------*/
+struct itjc_state_tab {
+ void (*func) (struct l1_softc *sc); /* function to execute */
+ int newstate; /* next state */
+} itjc_state_tab[N_EVENTS][N_STATES] = {
+
+/* STATE: F3 F4 F5 F6 F7 F8 ILLEGAL STATE */
+/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/* EV_PHAR x*/ {{F_AR, ST_F4}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_ill, ST_ILL}, {F_NULL, ST_F8}, {F_ill, ST_ILL}},
+/* EV_T3 x*/ {{F_NULL, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}},
+/* EV_INFO0 */ {{F_I01, ST_F3}, {F_I01, ST_F4}, {F_I01, ST_F5}, {F_I02, ST_F3}, {F_I03, ST_F3}, {F_I03, ST_F3}, {F_ill, ST_ILL}},
+/* EV_RSY x*/ {{F_NULL, ST_F3}, {F_NULL, ST_F5}, {F_NULL, ST_F5}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_ill, ST_ILL}},
+/* EV_INFO2 */ {{F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_ill, ST_ILL}},
+/* EV_INFO48*/ {{F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_NULL, ST_F7}, {F_AI8, ST_F7}, {F_ill, ST_ILL}},
+/* EV_INFO41*/ {{F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_NULL, ST_F7}, {F_AI10, ST_F7}, {F_ill, ST_ILL}},
+/* EV_DR */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}},
+/* EV_PU */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}},
+/* EV_DIS */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+/* EV_EI */ {{F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_ill, ST_ILL}},
+/* EV_ILL */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}
+};
+
+/*---------------------------------------------------------------------------*
+ * event handler
+ *---------------------------------------------------------------------------*/
+void
+itjc_next_state(struct l1_softc *sc, int event)
+{
+ int currstate, newstate;
+
+ if(event >= N_EVENTS)
+ panic("i4b_l1fsm.c: event >= N_EVENTS\n");
+
+ currstate = sc->sc_I430state;
+
+ if(currstate >= N_STATES)
+ panic("i4b_l1fsm.c: currstate >= N_STATES\n");
+
+ newstate = itjc_state_tab[event][currstate].newstate;
+
+ if(newstate >= N_STATES)
+ panic("i4b_l1fsm.c: newstate >= N_STATES\n");
+
+ NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event],
+ state_text[currstate],
+ state_text[newstate]);
+
+ (*itjc_state_tab[event][currstate].func)(sc);
+
+ if(newstate == ST_ILL)
+ {
+ newstate = ST_F3;
+ NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!",
+ state_text[currstate],
+ state_text[newstate],
+ event_text[event]);
+ }
+
+ sc->sc_I430state = newstate;
+}
+
+#if DO_I4B_DEBUG
+/*---------------------------------------------------------------------------*
+ * return pointer to current state description
+ *---------------------------------------------------------------------------*/
+char *
+itjc_printstate(struct l1_softc *sc)
+{
+ return((char *) state_text[sc->sc_I430state]);
+}
+#endif
+
+#endif /* NITJC > 0 */
diff --git a/sys/i4b/layer1/itjc/i4b_itjc_pci.c b/sys/i4b/layer1/itjc/i4b_itjc_pci.c
new file mode 100644
index 0000000..28bea90
--- /dev/null
+++ b/sys/i4b/layer1/itjc/i4b_itjc_pci.c
@@ -0,0 +1,2134 @@
+/*
+ * Copyright (c) 2000, 2001 Sergio Prallon. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b_itjc_pci.c: NetJet-S hardware driver
+ * ----------------------------------------
+ *
+ * $FreeBSD$
+ *
+ * last edit-date: [Thu Jan 11 11:29:38 2001]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "itjc.h"
+#include "opt_i4b.h"
+#include "pci.h"
+
+#if (NITJC > 0)
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+
+#include <machine/clock.h>
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+
+#include <i4b/layer1/i4b_l1.h>
+
+#include <i4b/layer1/itjc/i4b_hdlc.h> /* XXXXXXXXXXXXXXXXXXXXXXXX */
+
+#include <i4b/layer1/isic/i4b_isic.h>
+#include <i4b/layer1/isic/i4b_isac.h>
+
+#include <i4b/layer1/itjc/i4b_itjc_ext.h>
+
+#define PCI_TJNET_VID (0xe159)
+#define PCI_TJ300_DID (0x0001)
+
+
+/*
+ * Function prototypes
+ */
+
+static int itjc_probe(device_t dev);
+static int itjc_attach(device_t dev);
+static void itjc_shutdown(device_t dev);
+static void itjc_intr(void *xsc);
+static int itjc_dma_start(struct l1_softc *sc);
+static void itjc_dma_stop(struct l1_softc *sc);
+static void itjc_isac_intr(struct l1_softc *sc);
+static void itjc_init_linktab(struct l1_softc *sc);
+static void itjc_bchannel_setup(int unit, int h_chan, int bprot,
+ int activate);
+static void itjc_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp);
+
+
+/*
+ * Shorter names to bus resource manager routines.
+ */
+
+#define itjc_bus_setup(sc) \
+ bus_space_handle_t h = \
+ rman_get_bushandle((sc)->sc_resources.io_base[0]); \
+ bus_space_tag_t t = \
+ rman_get_bustag((sc)->sc_resources.io_base[0]);
+
+#define itjc_read_1(port) (bus_space_read_1(t, h, (port)))
+#define itjc_read_4(port) (bus_space_read_4(t, h, (port)))
+#define itjc_write_1(port, data) (bus_space_write_1(t, h, (port), (data)))
+#define itjc_write_4(port, data) (bus_space_write_4(t, h, (port), (data)))
+#define itjc_read_multi_1(port, buf, size) \
+ (bus_space_read_multi_1(t, h, (port), (buf), (size)))
+#define itjc_write_multi_1(port, buf, size) \
+ (bus_space_write_multi_1(t, h, (port), (buf), (size)))
+
+
+/*---------------------------------------------------------------------------*
+ * Glue data to register ourselves as a PCI device driver.
+ *---------------------------------------------------------------------------*/
+
+static device_method_t itjc_pci_methods[] =
+{
+ /* Device interface */
+ DEVMETHOD(device_probe, itjc_probe),
+ DEVMETHOD(device_attach, itjc_attach),
+ DEVMETHOD(device_shutdown, itjc_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ { 0, 0 }
+};
+
+static driver_t itjc_pci_driver =
+{
+ "itjc",
+ itjc_pci_methods,
+ sizeof(struct l1_softc)
+};
+
+static devclass_t itjc_pci_devclass;
+
+DRIVER_MODULE(netjet, pci, itjc_pci_driver, itjc_pci_devclass, 0, 0);
+
+/*
+ * Jump table for multiplex routines.
+ */
+
+struct i4b_l1mux_func itjc_l1mux_func =
+{
+ itjc_ret_linktab,
+ itjc_set_linktab,
+ itjc_mph_command_req,
+ itjc_ph_data_req,
+ itjc_ph_activate_req,
+};
+
+struct l1_softc *itjc_scp[ITJC_MAXUNIT];
+
+
+/*---------------------------------------------------------------------------*
+ * Tiger300/320 PCI ASIC registers.
+ *---------------------------------------------------------------------------*/
+
+/*
+ * Register offsets from i/o base.
+ */
+enum tiger_regs
+{
+ TIGER_RESET_PIB_CL_TIME = 0x00,
+ TIGER_DMA_OPER = 0x01,
+ TIGER_AUX_PORT_CNTL = 0x02,
+ TIGER_AUX_PORT_DATA = 0x03,
+ TIGER_INT0_MASK = 0x04,
+ TIGER_INT1_MASK = 0x05,
+ TIGER_INT0_STATUS = 0x06,
+ TIGER_INT1_STATUS = 0x07,
+ TIGER_DMA_WR_START_ADDR = 0x08,
+ TIGER_DMA_WR_INT_ADDR = 0x0C,
+ TIGER_DMA_WR_END_ADDR = 0x10,
+ TIGER_DMA_WR_CURR_ADDR = 0x14,
+ TIGER_DMA_RD_START_ADDR = 0x18,
+ TIGER_DMA_RD_INT_ADDR = 0x1C,
+ TIGER_DMA_RD_END_ADDR = 0x20,
+ TIGER_DMA_RD_CURR_ADDR = 0x24,
+ TIGER_PULSE_COUNTER = 0x28,
+};
+
+/*
+ * Bits on the above registers.
+ */
+
+enum tiger_reg_bits
+{
+/* Reset and PIB Cycle Timing */
+
+ TIGER_DMA_OP_MODE_MASK = 0x80,
+ TIGER_SELF_ADDR_DMA = 0x00, /* Wrap around ending addr */
+ TIGER_NORMAL_DMA = 0x80, /* Stop at ending addr */
+
+ TIGER_DMA_INT_MODE_MASK = 0x40,
+ TIGER_DONT_LATCH_DMA_INT= 0x00, /* Bits on int0 status will be
+ set only while curr addr
+ equals int or end addr */
+ TIGER_LATCH_DMA_INT = 0x40, /* Bits on int0 status remain
+ set until cleared by CPU */
+
+ TIGER_PIB_CYCLE_TIMING_MASK = 0x30,
+ TIGER_PIB_3_CYCLES = 0x00,
+ TIGER_PIB_5_CYCLES = 0x01,
+ TIGER_PIB_12_CYCLES = 0x10,
+
+ TIGER_RESET_MASK = 0x0F,
+ TIGER_RESET_PULSE_COUNT = 0x08,
+ TIGER_RESET_SERIAL_PORT = 0x04,
+ TIGER_RESET_DMA_LOGIC = 0x02,
+ TIGER_RESET_EXTERNAL = 0x01,
+ TIGER_RESET_ALL = 0x0F,
+
+/* DMA Operation */
+ TIGER_DMA_RESTART_MASK = 0x02,
+ TIGER_HOLD_DMA = 0x00,
+ TIGER_RESTART_DMA = 0x00,
+
+ TIGER_DMA_ENABLE_MASK = 0x01,
+ TIGER_ENABLE_DMA = 0x01,
+ TIGER_DISABLE_DMA = 0x00,
+
+/* AUX Port Control & Data plus Interrupt 1 Mask & Status */
+ TIGER_AUX_7_MASK = 0x80,
+ TIGER_AUX_6_MASK = 0x40,
+ TIGER_AUX_5_MASK = 0x20,
+ TIGER_AUX_4_MASK = 0x10,
+ TIGER_ISAC_INT_MASK = 0x10,
+ TIGER_AUX_3_MASK = 0x08,
+ TIGER_AUX_2_MASK = 0x04,
+ TIGER_AUX_1_MASK = 0x02,
+ TIGER_AUX_0_MASK = 0x01,
+
+/* AUX Port Control */
+ TIGER_AUX_7_IS_INPUT = 0x00,
+ TIGER_AUX_7_IS_OUTPUT = 0x80,
+ TIGER_AUX_6_IS_INPUT = 0x00,
+ TIGER_AUX_6_IS_OUTPUT = 0x40,
+ TIGER_AUX_5_IS_INPUT = 0x00,
+ TIGER_AUX_5_IS_OUTPUT = 0x20,
+ TIGER_AUX_4_IS_INPUT = 0x00,
+ TIGER_AUX_4_IS_OUTPUT = 0x10,
+ TIGER_AUX_3_IS_INPUT = 0x00,
+ TIGER_AUX_3_IS_OUTPUT = 0x80,
+ TIGER_AUX_2_IS_INPUT = 0x00,
+ TIGER_AUX_2_IS_OUTPUT = 0x40,
+ TIGER_AUX_1_IS_INPUT = 0x00,
+ TIGER_AUX_1_IS_OUTPUT = 0x20,
+ TIGER_AUX_0_IS_INPUT = 0x00,
+ TIGER_AUX_0_IS_OUTPUT = 0x10,
+ TIGER_AUX_NJ_DEFAULT = 0xEF, /* All but ISAC int is output */
+
+/* Interrupt 0 Mask & Status */
+ TIGER_PCI_TARGET_ABORT_INT_MASK = 0x20,
+ TIGER_NO_TGT_ABORT_INT = 0x00,
+ TIGER_TARGET_ABORT_INT = 0x20,
+ TIGER_PCI_MASTER_ABORT_INT_MASK = 0x10,
+ TIGER_NO_MST_ABORT_INT = 0x00,
+ TIGER_MASTER_ABORT_INT = 0x10,
+ TIGER_DMA_RD_END_INT_MASK = 0x08,
+ TIGER_NO_RD_END_INT = 0x00,
+ TIGER_RD_END_INT = 0x08,
+ TIGER_DMA_RD_INT_INT_MASK = 0x04,
+ TIGER_NO_RD_INT_INT = 0x00,
+ TIGER_RD_INT_INT = 0x04,
+ TIGER_DMA_WR_END_INT_MASK = 0x02,
+ TIGER_NO_WR_END_INT = 0x00,
+ TIGER_WR_END_INT = 0x02,
+ TIGER_DMA_WR_INT_INT_MASK = 0x01,
+ TIGER_NO_WR_INT_INT = 0x00,
+ TIGER_WR_INT_INT = 0x01,
+
+/* Interrupt 1 Mask & Status */
+ TIGER_NO_AUX_7_INT = 0x00,
+ TIGER_AUX_7_INT = 0x80,
+ TIGER_NO_AUX_6_INT = 0x00,
+ TIGER_AUX_6_INT = 0x40,
+ TIGER_NO_AUX_5_INT = 0x00,
+ TIGER_AUX_5_INT = 0x20,
+ TIGER_NO_AUX_4_INT = 0x00,
+ TIGER_AUX_4_INT = 0x10,
+ TIGER_NO_ISAC_INT = 0x00,
+ TIGER_ISAC_INT = 0x10,
+ TIGER_NO_AUX_3_INT = 0x00,
+ TIGER_AUX_3_INT = 0x08,
+ TIGER_NO_AUX_2_INT = 0x00,
+ TIGER_AUX_2_INT = 0x04,
+ TIGER_NO_AUX_1_INT = 0x00,
+ TIGER_AUX_1_INT = 0x02,
+ TIGER_NO_AUX_0_INT = 0x00,
+ TIGER_AUX_0_INT = 0x01
+};
+
+/*
+ * Peripheral Interface Bus definitions. This is an ISA like bus
+ * created by the Tiger ASIC to keep ISA chips like the ISAC happy
+ * on a PCI environment.
+ *
+ * Since the PIB only supplies 4 addressing lines, the 2 higher bits
+ * (A4 & A5) of the ISAC register addresses are wired on the 2 lower
+ * AUX lines. Another restriction is that all I/O to the PIB (8bit
+ * wide) is mapped on the PCI side as 32bit data. So the PCI address
+ * of a given ISAC register has to be multiplied by 4 before being
+ * added to the PIB base offset.
+ */
+enum tiger_pib_regs_defs
+{
+ /* Offset from the I/O base to the ISAC registers. */
+ PIB_OFFSET = 0xC0,
+ PIB_LO_ADDR_MASK = 0x0F,
+ PIB_HI_ADDR_MASK = 0x30,
+ PIB_LO_ADDR_SHIFT = 2, /* Align on dword boundary */
+ PIB_HI_ADDR_SHIFT = 4 /* Right shift to AUX_1 & AUX_0 */
+};
+
+
+#define itjc_set_pib_addr_msb(a) \
+( \
+ itjc_write_1(TIGER_AUX_PORT_DATA, \
+ ((a) & PIB_HI_ADDR_MASK) >> PIB_HI_ADDR_SHIFT) \
+)
+
+#define itjc_pib_2_pci(a) \
+( \
+ (((a) & PIB_LO_ADDR_MASK) << PIB_LO_ADDR_SHIFT) + PIB_OFFSET \
+)
+
+#define itjc_get_dma_offset(ctx,reg) \
+( \
+ (u_int16_t)((bus_addr_t)itjc_read_4((reg)) - (ctx)->bus_addr) \
+)
+
+
+/*
+ * IOM-2 serial channel 0 DMA data ring buffers.
+ *
+ * The Tiger300/320 ASIC do not nothing more than transfer via DMA the
+ * first 32 bits of every IOM-2 frame on the serial interface to the
+ * ISAC. So we have no framing/deframing facilities like we would have
+ * with an HSCX, having to do the job with CPU cycles. On the plus side
+ * we are able to specify large rings which can limit the occurrence of
+ * over/underruns.
+ */
+
+enum
+{
+ ITJC_RING_SLOT_WORDS = 64,
+ ITJC_RING_WORDS = 3 * ITJC_RING_SLOT_WORDS,
+ ITJC_RING_SLOT_BYTES = 4 * ITJC_RING_SLOT_WORDS,
+ ITJC_RING_BYTES = 4 * ITJC_RING_WORDS,
+ ITJC_DMA_POOL_WORDS = 2 * ITJC_RING_WORDS,
+ ITJC_DMA_POOL_BYTES = 4 * ITJC_DMA_POOL_WORDS
+};
+
+#define itjc_ring_add(x, d) (((x) + 4 * (d)) % ITJC_RING_BYTES)
+#define itjc_ring_sub(x, d) (((x) + ITJC_RING_BYTES - 4 * (d)) \
+ % ITJC_RING_BYTES)
+
+
+enum
+{
+ TIGER_CH_A = 0,
+ TIGER_CH_B = 1,
+
+ HSCX_CH_A = 0, /* For compatibility reasons. */
+ HSCX_CH_B = 1,
+};
+
+enum
+{
+ ITJC_TEL_SILENCE_BYTE = 0x00,
+ ITJC_HDLC_FLAG_BYTE = 0x7E,
+ ITJC_HDLC_ABORT_BYTE = 0xFF
+};
+
+/*
+ * Hardware DMA control block (one per card).
+ */
+typedef enum
+{
+ ITJC_DS_LOAD_FAILED = -1,
+ ITJC_DS_FREE = 0,
+ ITJC_DS_LOADING,
+ ITJC_DS_STOPPED,
+ ITJC_DS_RUNNING
+}
+ dma_state_t;
+
+typedef struct
+{
+ dma_state_t state;
+ u_int8_t *pool;
+ bus_addr_t bus_addr;
+ bus_dma_tag_t tag;
+ bus_dmamap_t map;
+ int error;
+}
+ dma_context_t;
+
+dma_context_t
+ dma_context [ ITJC_MAXUNIT ];
+
+/*
+ * B-channel DMA control blocks (4 per card -- 1 RX & 1 TX per channel).
+ */
+typedef enum
+{
+ ITJC_RS_IDLE = 0,
+ ITJC_RS_ACTIVE
+}
+ dma_rx_state_t;
+
+typedef enum
+{
+ ITJC_TS_IDLE = 0,
+ ITJC_TS_ACTIVE,
+ ITJC_TS_AFTER_XDU
+}
+ dma_tx_state_t;
+
+typedef struct
+{
+ u_int8_t *ring;
+ bus_addr_t bus_addr;
+ u_int16_t next_read;
+ u_int16_t hdlc_len;
+ u_int16_t hdlc_tmp;
+ u_int16_t hdlc_crc;
+ u_int16_t hdlc_ib;
+ u_int8_t hdlc_blevel;
+ u_int8_t hdlc_flag;
+ dma_rx_state_t state;
+}
+ dma_rx_context_t;
+
+typedef struct
+{
+ u_int8_t *ring;
+ bus_addr_t bus_addr;
+ u_int16_t next_write;
+ u_int32_t hdlc_tmp;
+ u_int16_t hdlc_blevel;
+ u_int16_t hdlc_crc;
+ u_int16_t hdlc_ib;
+ u_int16_t next_frame;
+ u_int16_t filled;
+ u_int8_t hdlc_flag;
+ dma_tx_state_t state;
+}
+ dma_tx_context_t;
+
+dma_rx_context_t
+ dma_rx_context [ ITJC_MAXUNIT ] [ 2 ];
+
+dma_tx_context_t
+ dma_tx_context [ ITJC_MAXUNIT ] [ 2 ];
+
+/*
+ * Used by the mbuf handling functions.
+ */
+typedef enum
+{
+ ITJC_MB_CURR = 0,
+ ITJC_MB_NEXT = 1,
+ ITJC_MB_NEW = 2
+}
+ which_mb_t;
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_map_callback - get DMA bus address from resource mgr.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_map_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ dma_context_t *ctx = (dma_context_t *)arg;
+
+ if (error)
+ {
+ ctx->error = error;
+ ctx->state = ITJC_DS_LOAD_FAILED;
+ return;
+ }
+
+ ctx->bus_addr = segs->ds_addr;
+ ctx->state = ITJC_DS_STOPPED;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_dma_start - Complete DMA setup & start the Tiger DMA engine.
+ *---------------------------------------------------------------------------*/
+static int
+itjc_dma_start(struct l1_softc *sc)
+{
+ int unit = sc->sc_unit;
+ dma_context_t *ctx = &dma_context[unit];
+ dma_rx_context_t *rxc = &dma_rx_context[unit][0];
+ dma_tx_context_t *txc = &dma_tx_context[unit][0];
+ bus_addr_t ba;
+ u_int8_t i;
+ u_int32_t *pool_end,
+ *ip;
+
+ itjc_bus_setup(sc);
+
+ /* See if it is already running. */
+
+ if (ctx->state == ITJC_DS_RUNNING)
+ return 0;
+
+ if (ctx->state == ITJC_DS_LOAD_FAILED)
+ {
+ NDBGL1(L1_ERROR, "itjc%d: dma_start: DMA map loading "
+ "failed (error=%d).\n", unit, ctx->error);
+ return 1;
+ }
+
+ if (ctx->state != ITJC_DS_STOPPED)
+ {
+ NDBGL1(L1_ERROR, "itjc%d: dma_start: Unexpected DMA "
+ "state (%d).\n", unit, ctx->state);
+ return 1;
+ }
+
+ /*
+ * Initialize the DMA control structures (hardware & B-channel).
+ */
+ ba = ctx->bus_addr;
+
+ txc->ring = ctx->pool + TIGER_CH_A;
+ rxc->ring = ctx->pool + TIGER_CH_A + ITJC_RING_BYTES;
+
+ txc->bus_addr = ba;
+ rxc->bus_addr = ba + ITJC_RING_BYTES;
+
+ ++rxc; ++txc;
+
+ txc->ring = ctx->pool + TIGER_CH_B;
+ rxc->ring = ctx->pool + TIGER_CH_B + ITJC_RING_BYTES;
+
+ txc->bus_addr = ba;
+ rxc->bus_addr = ba + ITJC_RING_BYTES;
+
+ /*
+ * Fill the DMA ring buffers with IOM-2 channel 0 frames made of
+ * idle/abort sequences for the B & D channels and NOP for IOM-2
+ * cmd/ind, monitor handshake & data.
+ */
+ pool_end = (u_int32_t *)ctx->pool + ITJC_DMA_POOL_WORDS;
+ for (ip = (u_int32_t *)ctx->pool; ip < pool_end; ++ip)
+ *ip = 0xFFFFFFFF;
+
+ /*
+ * Program the Tiger DMA gears.
+ */
+
+ itjc_write_4(TIGER_DMA_WR_START_ADDR, ba);
+ itjc_write_4(TIGER_DMA_WR_INT_ADDR, ba + ITJC_RING_SLOT_BYTES - 4);
+ itjc_write_4(TIGER_DMA_WR_END_ADDR, ba + ITJC_RING_BYTES - 4);
+
+ ba += ITJC_RING_BYTES;
+
+ itjc_write_4(TIGER_DMA_RD_START_ADDR, ba);
+ itjc_write_4(TIGER_DMA_RD_INT_ADDR, ba + ITJC_RING_SLOT_BYTES * 2 - 4);
+ itjc_write_4(TIGER_DMA_RD_END_ADDR, ba + ITJC_RING_BYTES - 4);
+
+ itjc_write_1(TIGER_INT0_MASK,
+ TIGER_WR_END_INT | TIGER_WR_INT_INT | TIGER_RD_INT_INT);
+
+ itjc_write_1(TIGER_DMA_OPER, TIGER_ENABLE_DMA);
+
+ /*
+ * See if it really started.
+ */
+ ba = itjc_read_4(TIGER_DMA_RD_CURR_ADDR);
+ for (i = 0; i < 10; ++i)
+ {
+ DELAY(SEC_DELAY/1000);
+ if (ba != itjc_read_4(TIGER_DMA_RD_CURR_ADDR))
+ {
+ ctx->state = ITJC_DS_RUNNING;
+ return 0;
+ }
+ }
+
+ NDBGL1(L1_ERROR, "itjc%d: dma_start: DMA start failed.\n ", unit);
+ return 1;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_dma_stop - Stop the Tiger DMA engine.
+ *---------------------------------------------------------------------------*/
+void
+itjc_dma_stop(struct l1_softc *sc)
+{
+ dma_context_t *ctx = &dma_context[sc->sc_unit];
+
+ itjc_bus_setup(sc);
+
+ /* Only stop the DMA if it is running. */
+
+ if (ctx->state != ITJC_DS_RUNNING)
+ return;
+
+ itjc_write_1(TIGER_DMA_OPER, TIGER_DISABLE_DMA);
+ DELAY(SEC_DELAY/1000);
+
+ ctx->state = ITJC_DS_STOPPED;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_bchannel_dma_setup - The DMA side of itjc_bchannel_setup.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_bchannel_dma_setup(struct l1_softc *sc, int h_chan, int activate)
+{
+ dma_rx_context_t *rxc = &dma_rx_context[sc->sc_unit][h_chan];
+ dma_tx_context_t *txc = &dma_tx_context[sc->sc_unit][h_chan];
+
+ l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
+
+ u_int8_t fill_byte,
+ *ring_end,
+ *cp;
+
+ int s = SPLI4B();
+
+ itjc_bus_setup(sc);
+
+ if (activate)
+ {
+ /*
+ * Get the DMA engine going if it's not running already.
+ */
+ itjc_dma_start(sc);
+
+ rxc->hdlc_len = rxc->hdlc_tmp = rxc->hdlc_crc = 0;
+ rxc->hdlc_ib = rxc->hdlc_blevel = rxc->hdlc_flag = 0;
+
+ txc->hdlc_tmp = txc->hdlc_blevel = txc->hdlc_crc = 0;
+ txc->hdlc_ib = 0;
+ txc->hdlc_flag = 2;
+ txc->filled = 0;
+
+ if (chan->bprot == BPROT_NONE)
+ fill_byte = ITJC_TEL_SILENCE_BYTE;
+ else
+ fill_byte = ITJC_HDLC_ABORT_BYTE;
+
+ ring_end = rxc->ring + ITJC_RING_BYTES;
+ for (cp = rxc->ring; cp < ring_end; cp += 4)
+ *cp = fill_byte;
+
+ ring_end = txc->ring + ITJC_RING_BYTES;
+ for (cp = txc->ring; cp < ring_end; cp += 4)
+ *cp = fill_byte;
+
+ rxc->next_read =
+ itjc_get_dma_offset(rxc, TIGER_DMA_RD_CURR_ADDR);
+
+ txc->next_frame = txc->next_write =
+ itjc_get_dma_offset(txc, TIGER_DMA_WR_CURR_ADDR);
+
+ rxc->state = ITJC_RS_ACTIVE;
+ txc->state = ITJC_TS_AFTER_XDU;
+ }
+ else
+ {
+ dma_rx_context_t *rxc2;
+
+ txc->state = ITJC_TS_IDLE;
+ rxc->state = ITJC_RS_IDLE;
+
+ rxc2 = &dma_rx_context[sc->sc_unit][0];
+
+ if (rxc2->state == ITJC_RS_IDLE
+ && rxc2[1].state == ITJC_RS_IDLE)
+ itjc_dma_stop(sc);
+ }
+
+ splx(s);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * Mbuf & if_queues management routines.
+ *---------------------------------------------------------------------------*/
+
+static u_int8_t *
+itjc_get_rx_mbuf(l1_bchan_state_t *chan, u_int8_t **dst_end_p,
+which_mb_t which)
+{
+ struct mbuf *mbuf = chan->in_mbuf;
+
+ if (mbuf == NULL && which == ITJC_MB_NEW)
+ {
+ if ((mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL)
+ panic("itjc_get_rx_mbuf: cannot allocate mbuf!");
+
+ chan->in_mbuf = mbuf;
+ chan->in_cbptr = (u_int8_t *)mbuf->m_data;
+ chan->in_len = 0;
+ }
+
+ if (dst_end_p != NULL)
+ {
+ if (mbuf != NULL)
+ *dst_end_p = (u_int8_t *)(mbuf->m_data)
+ + BCH_MAX_DATALEN;
+ else
+ *dst_end_p = NULL;
+ }
+
+ return chan->in_cbptr;
+}
+
+
+static void
+itjc_save_rx_mbuf(l1_bchan_state_t *chan, u_int8_t * dst)
+{
+ struct mbuf *mbuf = chan->in_mbuf;
+
+ if (dst != NULL && mbuf != NULL)
+ {
+ chan->in_cbptr = dst;
+ chan->in_len = dst - (u_int8_t *)mbuf->m_data;
+ }
+ else if (dst == NULL && mbuf == NULL)
+ {
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+ }
+ else
+ panic("itjc_save_rx_mbuf: stale pointer dst=%p mbuf=%p "
+ "in_cbptr=%p in_len=%d", dst, mbuf,
+ chan->in_cbptr, chan->in_len);
+}
+
+
+static void
+itjc_free_rx_mbuf(l1_bchan_state_t *chan)
+{
+ struct mbuf *mbuf = chan->in_mbuf;
+
+ if (mbuf != NULL)
+ i4b_Bfreembuf(mbuf);
+
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+}
+
+
+static void
+itjc_put_rx_mbuf(struct l1_softc *sc, l1_bchan_state_t *chan, u_int16_t len)
+{
+ i4b_trace_hdr_t hdr;
+ struct mbuf *mbuf = chan->in_mbuf;
+ u_int8_t *data = mbuf->m_data;
+ int activity = 1;
+
+ mbuf->m_pkthdr.len = mbuf->m_len = len;
+
+ if (sc->sc_trace & TRACE_B_RX)
+ {
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_NT;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, len, data);
+ }
+
+ if (chan->bprot == BPROT_NONE)
+ {
+ activity = ! i4b_l1_bchan_tel_silence(data, len);
+
+ /* move rx'd data to rx queue */
+
+ if (! _IF_QFULL(&chan->rx_queue))
+ {
+ IF_ENQUEUE(&chan->rx_queue, mbuf);
+ }
+ else
+ {
+ i4b_Bfreembuf(mbuf);
+ len = 0;
+ }
+ }
+
+ if (len != 0)
+ {
+ chan->rxcount += len;
+
+ (*chan->isic_drvr_linktab->bch_rx_data_ready)
+ (chan->isic_drvr_linktab->unit);
+ }
+
+ if (activity)
+ (*chan->isic_drvr_linktab->bch_activity)
+ (chan->isic_drvr_linktab->unit, ACT_RX);
+
+ chan->in_mbuf = NULL;
+ chan->in_cbptr = NULL;
+ chan->in_len = 0;
+}
+
+
+#define itjc_free_tx_mbufs(chan) \
+{ \
+ i4b_Bfreembuf((chan)->out_mbuf_head); \
+ (chan)->out_mbuf_cur = (chan)->out_mbuf_head = NULL; \
+ (chan)->out_mbuf_cur_ptr = NULL; \
+ (chan)->out_mbuf_cur_len = 0; \
+}
+
+
+static u_int16_t
+itjc_get_tx_mbuf(struct l1_softc *sc, l1_bchan_state_t *chan,
+ u_int8_t **src_p, which_mb_t which)
+{
+ i4b_trace_hdr_t hdr;
+ struct mbuf *mbuf = chan->out_mbuf_cur;
+ u_int8_t activity = 1;
+ u_int16_t len;
+ void *data;
+
+ switch (which)
+ {
+ case ITJC_MB_CURR:
+ if (mbuf != NULL)
+ {
+ *src_p = chan->out_mbuf_cur_ptr;
+ return chan->out_mbuf_cur_len;
+ }
+
+ break;
+
+ case ITJC_MB_NEXT:
+ if (mbuf != NULL)
+ {
+ chan->txcount += mbuf->m_len;
+
+ mbuf = mbuf->m_next;
+
+ if (mbuf != NULL)
+ goto new_mbuf;
+ }
+
+ chan->out_mbuf_cur_ptr = *src_p = NULL;
+ chan->out_mbuf_cur_len = 0;
+
+ if (chan->out_mbuf_head != NULL)
+ {
+ i4b_Bfreembuf(chan->out_mbuf_head);
+ chan->out_mbuf_head = NULL;
+ }
+
+ return 0;
+
+ case ITJC_MB_NEW:
+ if (mbuf != NULL)
+ chan->txcount += mbuf->m_len;
+ }
+
+ if (chan->out_mbuf_head != NULL)
+ i4b_Bfreembuf(chan->out_mbuf_head);
+
+ IF_DEQUEUE(&chan->tx_queue, mbuf);
+
+ if (mbuf == NULL)
+ {
+ chan->out_mbuf_cur = chan->out_mbuf_head = NULL;
+ chan->out_mbuf_cur_ptr = *src_p = NULL;
+ chan->out_mbuf_cur_len = 0;
+
+ chan->state &= ~(HSCX_TX_ACTIVE);
+
+ (*chan->isic_drvr_linktab->bch_tx_queue_empty)
+ (chan->isic_drvr_linktab->unit);
+
+ return 0;
+ }
+
+ chan->out_mbuf_head = mbuf;
+
+new_mbuf:
+ chan->out_mbuf_cur = mbuf;
+ chan->out_mbuf_cur_ptr = data = mbuf->m_data;
+ chan->out_mbuf_cur_len = len = mbuf->m_len;
+
+ chan->state |= HSCX_TX_ACTIVE;
+
+ if (sc->sc_trace & TRACE_B_TX)
+ {
+ hdr.unit = L0ITJCUNIT(sc->sc_unit);
+ hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
+ hdr.dir = FROM_TE;
+ hdr.count = ++sc->sc_trace_bcount;
+ MICROTIME(hdr.time);
+ i4b_l1_trace_ind(&hdr, len, data);
+ }
+
+ if (chan->bprot == BPROT_NONE)
+ activity = ! i4b_l1_bchan_tel_silence(data, len);
+
+ if (activity)
+ (*chan->isic_drvr_linktab->bch_activity)
+ (chan->isic_drvr_linktab->unit, ACT_TX);
+
+ *src_p = data;
+ return len;
+}
+
+
+#define itjc_save_tx_mbuf(chan, src, dst) \
+( \
+ (chan)->out_mbuf_cur != NULL ? \
+ ( \
+ (chan)->out_mbuf_cur_ptr = (src), \
+ (chan)->out_mbuf_cur_len = (len) \
+ ) \
+ : \
+ 0 \
+)
+
+
+/*---------------------------------------------------------------------------*
+ * B-channel interrupt service routines.
+ *---------------------------------------------------------------------------*/
+
+/*
+ * Since the Tiger ASIC doesn't produce a XMIT underflow indication,
+ * we need to deduce it ourselves. This is somewhat tricky because we
+ * are dealing with modulo m arithmetic. The idea here is to have a
+ * "XDU zone" ahead of the writing pointer sized 1/3 of total ring
+ * length (a ring slot). If the hardware DMA pointer is found there we
+ * consider that a XDU has occurred. To complete the scheme, we never
+ * let the ring have more than 2 slots of (unsent) data and adjust the
+ * interrupt registers to cause an interrupt at every slot.
+ */
+static u_int8_t
+itjc_xdu(struct l1_softc *sc, l1_bchan_state_t *chan, dma_tx_context_t *ctx,
+u_int16_t *dst_p, u_int16_t *dst_end_p, u_int8_t tx_restart)
+{
+ u_int8_t xdu;
+
+ u_int16_t dst_end,
+ dst,
+ dma,
+ dma_l,
+ dma_h,
+ xdu_l,
+ xdu_h;
+
+ itjc_bus_setup(sc);
+
+ /*
+ * Since the hardware is running, be conservative and assume
+ * the pointer location has a `fuzy' error factor.
+ */
+ dma = itjc_get_dma_offset(ctx, TIGER_DMA_WR_CURR_ADDR);
+ dma_l = dma;
+ dma_h = itjc_ring_add(dma, 1);
+
+ dst_end = itjc_ring_sub(dma_l, ITJC_RING_SLOT_WORDS);
+
+ if (ctx->state != ITJC_TS_ACTIVE)
+ {
+ xdu = (ctx->state == ITJC_TS_AFTER_XDU);
+ dst = itjc_ring_add(dma_h, 4);
+ goto done;
+ }
+
+ /*
+ * Check for xmit underruns.
+ */
+ xdu_l = dst = ctx->next_write;
+ xdu_h = itjc_ring_add(dst, ITJC_RING_SLOT_WORDS);
+
+ if (xdu_l < xdu_h)
+ xdu = (xdu_l <= dma_l && dma_l < xdu_h)
+ || (xdu_l <= dma_h && dma_h < xdu_h);
+ else
+ xdu = (xdu_l <= dma_l || dma_l < xdu_h)
+ || (xdu_l <= dma_h || dma_h < xdu_h);
+
+ if (xdu)
+ {
+ ctx->state = ITJC_TS_AFTER_XDU;
+
+ dst = itjc_ring_add(dma_h, 4);
+ }
+ else if (tx_restart)
+ {
+ /*
+ * See if we still can restart from immediately
+ * after the last frame sent. It's a XDU test but
+ * using the real data end on the comparsions. We
+ * don't consider XDU an error here because we were
+ * just trying to avoid send a filling gap between
+ * frames. If it's already sent no harm is done.
+ */
+ xdu_l = dst = ctx->next_frame;
+ xdu_h = itjc_ring_add(dst, ITJC_RING_SLOT_WORDS);
+
+ if (xdu_l < xdu_h)
+ xdu = (xdu_l <= dma_l && dma_l < xdu_h)
+ || (xdu_l <= dma_h && dma_h < xdu_h);
+ else
+ xdu = (xdu_l <= dma_l || dma_l < xdu_h)
+ || (xdu_l <= dma_h || dma_h < xdu_h);
+
+ if (xdu)
+ dst = itjc_ring_add(dma_h, 4);
+
+ xdu = 0;
+ }
+
+done:
+ if (dst_p != NULL)
+ *dst_p = dst;
+
+ if (dst_end_p != NULL)
+ *dst_end_p = dst_end;
+
+ ctx->next_write = dst_end;
+
+ return xdu;
+}
+
+
+#define itjc_rotate_hdlc_flag(blevel) \
+ ((u_int8_t)(0x7E7E >> (8 - (u_int8_t)((blevel) >> 8))))
+
+
+static void
+itjc_dma_rx_intr(struct l1_softc *sc, l1_bchan_state_t *chan,
+dma_rx_context_t *ctx)
+{
+ u_int8_t *ring,
+ *dst,
+ *dst_end,
+ flag,
+ blevel;
+
+ u_int16_t dma,
+ src,
+ tmp2,
+ tmp,
+ len,
+ crc,
+ ib;
+
+ itjc_bus_setup(sc);
+
+
+ if (ctx->state == ITJC_RS_IDLE)
+ return;
+
+ ring = ctx->ring;
+ dma = itjc_get_dma_offset(ctx, TIGER_DMA_RD_CURR_ADDR);
+ dma = itjc_ring_sub(dma, 1);
+ src = ctx->next_read;
+
+ if (chan->bprot == BPROT_NONE)
+ {
+ dst = itjc_get_rx_mbuf(chan, &dst_end, ITJC_MB_CURR);
+
+ while (src != dma)
+ {
+ if (dst == NULL)
+ dst = itjc_get_rx_mbuf(chan, &dst_end,
+ ITJC_MB_NEW);
+
+ *dst++ = ring[src];
+ src = itjc_ring_add(src, 1);
+
+ if (dst >= dst_end)
+ {
+ itjc_put_rx_mbuf(sc, chan, BCH_MAX_DATALEN);
+ dst = dst_end = NULL;
+ }
+ }
+ ctx->next_read = src;
+ itjc_save_rx_mbuf(chan, dst);
+ return;
+ }
+
+ blevel = ctx->hdlc_blevel;
+ flag = ctx->hdlc_flag;
+ len = ctx->hdlc_len;
+ tmp = ctx->hdlc_tmp;
+ crc = ctx->hdlc_crc;
+ ib = ctx->hdlc_ib;
+
+ dst = itjc_get_rx_mbuf(chan, NULL, ITJC_MB_CURR);
+
+ while (src != dma)
+ {
+ HDLC_DECODE(*dst++, len, tmp, tmp2, blevel, ib, crc, flag,
+ {/* rdd */
+ tmp2 = ring[src];
+ src = itjc_ring_add(src, 1);
+ },
+ {/* nfr */
+ if (dst != NULL)
+ panic("itjc_dma_rx_intr: nfrcmd with "
+ "valid current frame");
+
+ dst = itjc_get_rx_mbuf(chan, &dst_end, ITJC_MB_NEW);
+ len = dst_end - dst;
+ },
+ {/* cfr */
+ len = BCH_MAX_DATALEN - len;
+
+ if ((!len) || (len > BCH_MAX_DATALEN))
+ {
+ /*
+ * NOTE: frames without any data, only crc
+ * field, should be silently discared.
+ */
+ NDBGL1(L1_S_MSG, "itjc_dma_rx_intr: "
+ "bad frame (len=%d, unit=%d)",
+ len, sc->sc_unit);
+
+ itjc_free_rx_mbuf(chan);
+
+ goto s0;
+ }
+
+ if (crc)
+ {
+ NDBGL1(L1_S_ERR,
+ "CRC (crc=0x%04x, len=%d, unit=%d)",
+ crc, len, sc->sc_unit);
+
+ itjc_free_rx_mbuf(chan);
+
+ goto s0;
+ }
+
+ itjc_put_rx_mbuf(sc, chan, len);
+
+ s0:
+ dst = NULL;
+ len = 0;
+ },
+ {/* rab */
+ NDBGL1(L1_S_ERR, "Read Abort (unit=%d)", sc->sc_unit);
+
+ itjc_free_rx_mbuf(chan);
+ dst = NULL;
+ len = 0;
+ },
+ {/* rdo */
+ NDBGL1(L1_S_ERR, "RDO (unit=%d) dma=%d src=%d",
+ sc->sc_unit, dma, src);
+
+ itjc_free_rx_mbuf(chan);
+ dst = NULL;
+ len = 0;
+ },
+ continue,
+ d);
+ }
+
+ itjc_save_rx_mbuf(chan, dst);
+
+ ctx->next_read = src;
+ ctx->hdlc_blevel= blevel;
+ ctx->hdlc_flag = flag;
+ ctx->hdlc_len = len;
+ ctx->hdlc_tmp = tmp;
+ ctx->hdlc_crc = crc;
+ ctx->hdlc_ib = ib;
+}
+
+
+/*
+ * The HDLC side of itjc_dma_tx_intr. We made a separate function
+ * to improve readability and (perhaps) help the compiler with
+ * register allocation.
+ */
+static void
+itjc_hdlc_encode(struct l1_softc *sc, l1_bchan_state_t *chan,
+dma_tx_context_t * ctx)
+{
+ u_int8_t *ring,
+ *src,
+ xdu,
+ flag,
+ flag_byte,
+ tx_restart;
+
+ u_int16_t saved_len,
+ dst_end,
+ dst_end1,
+ dst,
+ filled,
+ blevel,
+ tmp2,
+ len,
+ crc,
+ ib;
+
+ u_int32_t tmp;
+
+
+ saved_len = len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_CURR);
+
+ filled = ctx->filled;
+ flag = ctx->hdlc_flag;
+
+ if (src == NULL && flag == 2 && filled >= ITJC_RING_WORDS)
+ return;
+
+ tx_restart = (flag == 2 && src != NULL);
+ xdu = itjc_xdu(sc, chan, ctx, &dst, &dst_end, tx_restart);
+
+ ring = ctx->ring;
+
+ ib = ctx->hdlc_ib;
+ crc = ctx->hdlc_crc;
+ tmp = ctx->hdlc_tmp;
+ blevel = ctx->hdlc_blevel;
+
+ if (xdu)
+ {
+ if (flag != 2)
+ {
+ NDBGL1(L1_H_XFRERR, "XDU");
+ ++chan->stat_XDU;
+
+ /*
+ * Abort the current frame and
+ * prepare for a full restart.
+ */
+ itjc_free_tx_mbufs(chan);
+ saved_len = len = filled = 0;
+ flag = (u_int8_t)-2;
+ }
+ else if (filled < ITJC_RING_SLOT_WORDS)
+ {
+ /*
+ * A little garbage may have been retransmitted.
+ * Send an abort before any new data.
+ */
+ filled = 0;
+ flag = (u_int8_t)-2;
+ }
+ }
+
+ if (flag != 3)
+ len = 0;
+
+ while (dst != dst_end)
+ {
+ HDLC_ENCODE(
+ *src++, len, tmp, tmp2, blevel, ib, crc, flag,
+ {/* gfr */
+ if ((len = saved_len) == 0)
+ len = itjc_get_tx_mbuf(sc, chan, &src,
+ ITJC_MB_NEW);
+
+ if (len == 0)
+ {
+ ctx->next_frame = dst;
+
+ flag_byte = itjc_rotate_hdlc_flag(blevel);
+
+ for (dst_end1 = itjc_ring_sub(dst_end, 1);
+ dst != dst_end1;
+ dst = itjc_ring_add(dst, 1))
+ {
+ ring[dst] = flag_byte;
+ ++filled;
+ }
+ }
+ else
+ filled = 0;
+
+ ctx->state = ITJC_TS_ACTIVE;
+ },
+ {/* nmb */
+ saved_len = 0;
+ len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_NEXT);
+ },
+ {/* wrd */
+ ring[dst] = (u_int8_t)tmp;
+ dst = itjc_ring_add(dst, 1);
+ },
+ d1);
+ }
+
+ ctx->hdlc_blevel = blevel;
+ ctx->hdlc_flag = flag;
+ ctx->hdlc_tmp = tmp;
+ ctx->hdlc_crc = crc;
+ ctx->hdlc_ib = ib;
+
+ ctx->filled = filled;
+ ctx->next_write = dst;
+
+ itjc_save_tx_mbuf(chan, src, len);
+}
+
+
+static void
+itjc_dma_tx_intr(struct l1_softc *sc, l1_bchan_state_t *chan,
+dma_tx_context_t * ctx)
+{
+ u_int8_t *data_end,
+ *ring,
+ *src,
+ xdu;
+
+ u_int16_t dst,
+ dst_end,
+ filled,
+ len;
+
+
+ if (ctx->state == ITJC_TS_IDLE)
+ goto done;
+
+ if (chan->bprot != BPROT_NONE)
+ {
+ itjc_hdlc_encode(sc, chan, ctx);
+ goto done;
+ }
+
+ ring = ctx->ring;
+ filled = ctx->filled;
+
+ len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_CURR);
+
+ if (len == 0 && filled >= ITJC_RING_WORDS)
+ goto done;
+
+ xdu = itjc_xdu(sc, chan, ctx, &dst, &dst_end, len != 0);
+
+ if (xdu && filled < ITJC_RING_WORDS)
+ {
+ NDBGL1(L1_H_XFRERR, "XDU");
+ ++chan->stat_XDU;
+ filled = 0;
+ }
+
+ if (len == 0)
+ goto fill_ring;
+
+ ctx->state = ITJC_TS_ACTIVE;
+
+ data_end = src + len;
+ while (dst != dst_end)
+ {
+ ring[dst] = *src++; --len;
+
+ dst = itjc_ring_add(dst, 1);
+
+ if (src >= data_end)
+ {
+ len = itjc_get_tx_mbuf(sc, chan, &src, ITJC_MB_NEXT);
+ if (len == 0)
+ len = itjc_get_tx_mbuf(sc, chan,
+ &src, ITJC_MB_NEW);
+
+ if (len == 0)
+ {
+ data_end = NULL;
+ break;
+ }
+ data_end = src + len;
+ }
+ }
+
+ itjc_save_tx_mbuf(chan, src, len);
+
+ filled = 0;
+
+fill_ring:
+ ctx->next_frame = dst;
+
+ for (; dst != dst_end; dst = itjc_ring_add(dst, 1))
+ {
+ ring[dst] = ITJC_TEL_SILENCE_BYTE;
+ ++filled;
+ }
+
+ ctx->next_write = dst;
+ ctx->filled = filled;
+
+done:
+}
+
+
+/*---------------------------------------------------------------------------*
+ * NetJet fifo read/write routines.
+ *---------------------------------------------------------------------------*/
+
+static void
+itjc_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
+{
+ itjc_bus_setup(sc);
+
+ if (what != ISIC_WHAT_ISAC)
+ panic("itjc_write_fifo: Trying to read from HSCX fifo.\n");
+
+ itjc_set_pib_addr_msb(0);
+ itjc_read_multi_1(PIB_OFFSET, buf, size);
+}
+
+
+static void
+itjc_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size)
+{
+ itjc_bus_setup(sc);
+
+ if (what != ISIC_WHAT_ISAC)
+ panic("itjc_write_fifo: Trying to write to HSCX fifo.\n");
+
+ itjc_set_pib_addr_msb(0);
+ itjc_write_multi_1(PIB_OFFSET, buf, size);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * Read an ISAC register.
+ *---------------------------------------------------------------------------*/
+static u_int8_t
+itjc_read_reg(struct l1_softc *sc, int what, bus_size_t offs)
+{
+ itjc_bus_setup(sc);
+
+ if (what != ISIC_WHAT_ISAC)
+ {
+ panic("itjc_read_reg: what(%d) != ISIC_WHAT_ISAC\n",
+ what);
+ return 0;
+ }
+
+ itjc_set_pib_addr_msb(offs);
+ return itjc_read_1(itjc_pib_2_pci(offs));
+}
+
+
+/*---------------------------------------------------------------------------*
+ * Write an ISAC register.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data)
+{
+ itjc_bus_setup(sc);
+
+ if (what != ISIC_WHAT_ISAC)
+ {
+ panic("itjc_write_reg: what(%d) != ISIC_WHAT_ISAC\n",
+ what);
+ return;
+ }
+
+ itjc_set_pib_addr_msb(offs);
+ itjc_write_1(itjc_pib_2_pci(offs), data);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_probe - probe for a card.
+ *---------------------------------------------------------------------------*/
+static int itjc_probe(device_t dev)
+{
+ u_int16_t vid = pci_get_vendor(dev),
+ did = pci_get_device(dev);
+
+ if ((vid == PCI_TJNET_VID) && (did == PCI_TJ300_DID))
+ {
+ device_set_desc(dev, "NetJet-S");
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_attach - attach a (previously probed) card.
+ *---------------------------------------------------------------------------*/
+int
+itjc_attach(device_t dev)
+{
+ bus_space_handle_t h;
+ bus_space_tag_t t;
+
+ struct l1_softc *sc = device_get_softc(dev);
+
+ u_int16_t vid = pci_get_vendor(dev),
+ did = pci_get_device(dev);
+
+ int unit = device_get_unit(dev),
+ s = splimp(),
+ res_init_level = 0,
+ error = 0;
+
+ void *ih = 0;
+
+ dma_context_t *ctx = &dma_context[unit];
+
+ bzero(sc, sizeof(struct l1_softc));
+
+ /* Probably not really required. */
+ if (unit > ITJC_MAXUNIT)
+ {
+ printf("itjc%d: Error, unit > ITJC_MAXUNIT!\n", unit);
+ splx(s);
+ return ENXIO;
+ }
+
+ if (!(vid == PCI_TJNET_VID && did == PCI_TJ300_DID))
+ {
+ printf("itjc%d: unknown device (%04X,%04X)!\n", unit, vid, did);
+ goto fail;
+ }
+
+ itjc_scp[unit] = sc;
+
+ sc->sc_resources.io_rid[0] = PCIR_MAPS+0;
+ sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT,
+ &sc->sc_resources.io_rid[0], 0, ~0, 1, RF_ACTIVE);
+
+ if (sc->sc_resources.io_base[0] == NULL)
+ {
+ printf("itjc%d: couldn't map IO port\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ h = rman_get_bushandle(sc->sc_resources.io_base[0]);
+ t = rman_get_bustag(sc->sc_resources.io_base[0]);
+
+ ++res_init_level;
+
+ /* Allocate interrupt. */
+ sc->sc_resources.irq_rid = 0;
+ sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ,
+ &sc->sc_resources.irq_rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->sc_resources.irq == NULL)
+ {
+ printf("itjc%d: couldn't map interrupt\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ ++res_init_level;
+
+ error = bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET,
+ itjc_intr, sc, &ih);
+
+ if (error)
+ {
+ printf("itjc%d: couldn't set up irq handler\n", unit);
+ error = ENXIO;
+ goto fail;
+ }
+
+ /*
+ * Reset the ASIC & the ISAC.
+ */
+ itjc_write_1(TIGER_RESET_PIB_CL_TIME, TIGER_RESET_ALL);
+
+ DELAY(SEC_DELAY/100); /* Give it 10 ms to reset ...*/
+
+ itjc_write_1(TIGER_RESET_PIB_CL_TIME,
+ TIGER_SELF_ADDR_DMA | TIGER_PIB_3_CYCLES);
+
+ DELAY(SEC_DELAY/100); /* ... and more 10 to recover. */
+
+ /*
+ * First part of DMA initialization. Create & map the memory
+ * pool that will be used to bear the rx & tx ring buffers.
+ */
+ ctx->state = ITJC_DS_LOADING;
+
+ error = bus_dma_tag_create(
+ NULL, /* parent */
+ 4, /* alignment*/
+ 0, /* boundary*/
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr*/
+ BUS_SPACE_MAXADDR, /* highaddr*/
+ NULL, /* filter*/
+ NULL, /* filterarg*/
+ ITJC_DMA_POOL_BYTES, /* maxsize*/
+ 1, /* nsegments*/
+ ITJC_DMA_POOL_BYTES, /* maxsegsz*/
+ BUS_DMA_ALLOCNOW | BUS_DMAMEM_NOSYNC, /* flags*/
+ &ctx->tag);
+
+ if (error)
+ {
+ printf("itjc%d: couldn't create bus DMA tag.\n", unit);
+ goto fail;
+ }
+
+ ++res_init_level;
+
+ error = bus_dmamem_alloc(
+ ctx->tag, /* DMA tag */
+ (void **)&ctx->pool, /* KV addr of the allocated memory */
+ BUS_DMA_NOWAIT | BUS_DMAMEM_NOSYNC, /* flags */
+ &ctx->map); /* KV <-> PCI map */
+
+ if (error)
+ goto fail;
+
+ /*
+ * Load the KV <-> PCI map so the device sees the same
+ * memory segment as pointed by pool. Note: since the
+ * load may happen assyncronously (completion indicated by
+ * the execution of the callback function) we have to
+ * delay the initialization of the DMA engine to a moment we
+ * actually have the proper bus addresses to feed the Tiger
+ * and our DMA control blocks. This will be done in
+ * itjc_bchannel_setup via a call to itjc_dma_start.
+ */
+ bus_dmamap_load(
+ ctx->tag, /* DMA tag */
+ ctx->map, /* DMA map */
+ ctx->pool, /* KV addr of buffer */
+ ITJC_DMA_POOL_BYTES, /* buffer size */
+ itjc_map_callback, /* this receive the bus addr/error */
+ ctx, /* callback aux arg */
+ 0); /* flags */
+
+ ++res_init_level;
+
+ /*
+ * Setup the AUX port so we can talk to the ISAC.
+ */
+ itjc_write_1(TIGER_AUX_PORT_CNTL, TIGER_AUX_NJ_DEFAULT);
+ itjc_write_1(TIGER_INT1_MASK, TIGER_ISAC_INT);
+
+ /*
+ * From now on, almost like a `normal' ISIC driver.
+ */
+
+ sc->sc_unit = unit;
+
+ ISAC_BASE = (caddr_t)ISIC_WHAT_ISAC;
+
+ HSCX_A_BASE = (caddr_t)ISIC_WHAT_HSCXA;
+ HSCX_B_BASE = (caddr_t)ISIC_WHAT_HSCXB;
+
+ /* setup access routines */
+
+ sc->clearirq = NULL;
+ sc->readreg = itjc_read_reg;
+ sc->writereg = itjc_write_reg;
+
+ sc->readfifo = itjc_read_fifo;
+ sc->writefifo = itjc_write_fifo;
+
+ /* setup card type */
+
+ sc->sc_cardtyp = CARD_TYPEP_NETJET_S;
+
+ /* setup IOM bus type */
+
+ sc->sc_bustyp = BUS_TYPE_IOM2;
+
+ /* set up some other miscellaneous things */
+ sc->sc_ipac = 0;
+ sc->sc_bfifolen = 2 * ITJC_RING_SLOT_WORDS;
+
+ printf("itjc%d: ISAC 2186 Version 1.1 (IOM-2)\n", unit);
+
+ /* init the ISAC */
+ itjc_isac_init(sc);
+
+ /* init the "HSCX" */
+ itjc_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0);
+
+ itjc_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0);
+
+ /* can't use the normal B-Channel stuff */
+ itjc_init_linktab(sc);
+
+ /* set trace level */
+
+ sc->sc_trace = TRACE_OFF;
+
+ sc->sc_state = ISAC_IDLE;
+
+ sc->sc_ibuf = NULL;
+ sc->sc_ib = NULL;
+ sc->sc_ilen = 0;
+
+ sc->sc_obuf = NULL;
+ sc->sc_op = NULL;
+ sc->sc_ol = 0;
+ sc->sc_freeflag = 0;
+
+ sc->sc_obuf2 = NULL;
+ sc->sc_freeflag2 = 0;
+
+#if defined(__FreeBSD__) && __FreeBSD__ >=3
+ callout_handle_init(&sc->sc_T3_callout);
+ callout_handle_init(&sc->sc_T4_callout);
+#endif
+
+ /* init higher protocol layers */
+
+ i4b_l1_mph_status_ind(L0ITJCUNIT(sc->sc_unit), STI_ATTACH,
+ sc->sc_cardtyp, &itjc_l1mux_func);
+
+ splx(s);
+ return 0;
+
+ fail:
+ switch (res_init_level)
+ {
+ case 5:
+ bus_dmamap_unload(ctx->tag, ctx->map);
+ /* FALL TRHU */
+
+ case 4:
+ bus_dmamem_free(ctx->tag, ctx->pool, ctx->map);
+ bus_dmamap_destroy(ctx->tag, ctx->map);
+ /* FALL TRHU */
+
+ case 3:
+ bus_dma_tag_destroy(ctx->tag);
+ /* FALL TRHU */
+
+ case 2:
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_resources.irq);
+ /* FALL TRHU */
+
+ case 1:
+ bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS+0,
+ sc->sc_resources.io_base[0]);
+ /* FALL TRHU */
+
+ case 0:
+ }
+
+ itjc_scp[unit] = NULL;
+
+ splx(s);
+ return error;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_intr - main interrupt service routine.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_intr(void *xsc)
+{
+ struct l1_softc *sc = xsc;
+ l1_bchan_state_t *chan = &sc->sc_chan[0];
+ dma_context_t *dma = &dma_context[sc->sc_unit];
+ dma_rx_context_t *rxc = &dma_rx_context[sc->sc_unit][0];
+ dma_tx_context_t *txc = &dma_tx_context[sc->sc_unit][0];
+
+ itjc_bus_setup(sc);
+
+ /* Honor interrupts from successfully configured cards only. */
+ if (dma->state < ITJC_DS_STOPPED)
+ return;
+
+ /* First, we check the ISAC... */
+ if (! (itjc_read_1(TIGER_AUX_PORT_DATA) & TIGER_ISAC_INT_MASK))
+ {
+ itjc_write_1(TIGER_INT1_STATUS, TIGER_ISAC_INT);
+ NDBGL1(L1_H_IRQ, "ISAC");
+ itjc_isac_intr(sc);
+ }
+
+ /* ... after what we always have a look at the DMA rings. */
+
+ NDBGL1(L1_H_IRQ, "Tiger");
+
+ itjc_read_1(TIGER_INT0_STATUS);
+ itjc_write_1(TIGER_INT0_STATUS, TIGER_TARGET_ABORT_INT
+ | TIGER_MASTER_ABORT_INT | TIGER_RD_END_INT
+ | TIGER_RD_INT_INT | TIGER_WR_END_INT | TIGER_WR_INT_INT);
+
+ itjc_dma_rx_intr(sc, chan, rxc);
+ itjc_dma_tx_intr(sc, chan, txc);
+
+ ++chan; ++rxc; ++txc;
+
+ itjc_dma_rx_intr(sc, chan, rxc);
+ itjc_dma_tx_intr(sc, chan, txc);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_bchannel_setup - (Re)initialize and start/stop a Bchannel.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_bchannel_setup(int unit, int h_chan, int bprot, int activate)
+{
+#ifdef __FreeBSD__
+ struct l1_softc *sc = itjc_scp[unit];
+#else
+ struct l1_softc *sc = isic_find_sc(unit);
+#endif
+ l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
+ int s = SPLI4B();
+
+ NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s",
+ unit, h_chan, activate ? "activate" : "deactivate");
+
+ /*
+ * If we are deactivating the channel, we have to stop
+ * the DMA before we reset the channel control structures.
+ */
+ if (! activate)
+ itjc_bchannel_dma_setup(sc, h_chan, activate);
+
+ /* general part */
+
+ chan->state = HSCX_IDLE;
+
+ chan->unit = sc->sc_unit; /* unit number */
+ chan->channel = h_chan; /* B channel */
+ chan->bprot = bprot; /* B channel protocol */
+
+ /* receiver part */
+
+ i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */
+
+ chan->rx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+ chan->rxcount = 0; /* reset rx counter */
+
+ i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */
+
+ chan->in_mbuf = NULL; /* reset mbuf ptr */
+ chan->in_cbptr = NULL; /* reset mbuf curr ptr */
+ chan->in_len = 0; /* reset mbuf data len */
+
+ /* transmitter part */
+
+ i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */
+
+ chan->tx_queue.ifq_maxlen = IFQ_MAXLEN;
+
+ chan->txcount = 0; /* reset tx counter */
+
+ i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */
+
+ chan->out_mbuf_head = NULL; /* reset head mbuf ptr */
+ chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */
+ chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */
+ chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */
+
+ /*
+ * Only setup & start the DMA after all other channel
+ * control structures are in place.
+ */
+ if (activate)
+ itjc_bchannel_dma_setup(sc, h_chan, activate);
+
+ splx(s);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_bchannel_start - Signal us we have more data to send.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_bchannel_start(int unit, int h_chan)
+{
+#if Buggy_code
+ /*
+ * I disabled this routine because it was causing crashes when
+ * this driver was used with the ISP (kernel SPPP) protocol driver.
+ * The scenario is reproductible:
+ * Use the -link1 (dial on demand) ifconfig option.
+ * Start an interactive TCP connection to somewhere.
+ * Wait until the PPP connection times out and is dropped.
+ * Try to send something on the TCP connection.
+ * The machine will print some garbage and halt or reboot
+ * (no panic messages).
+ *
+ * I've nailed down the problem to the fact that this routine
+ * was being called before the B channel had been setup again.
+ *
+ * For now, I don't have a good solution other than this one.
+ * But, don't despair. The impact of it is unnoticeable.
+ */
+
+#ifdef __FreeBSD__
+ struct l1_softc *sc = itjc_scp[unit];
+#else
+ struct l1_softc *sc = isic_find_sc(unit);
+#endif
+ l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
+
+ int s = SPLI4B();
+
+ dma_tx_context_t *txc = &dma_tx_context[unit][h_chan];
+
+ if (chan->state & HSCX_TX_ACTIVE)
+ {
+ splx(s);
+ return;
+ }
+
+ itjc_dma_tx_intr(sc, chan, txc);
+
+ splx(s);
+#endif
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_shutdown - Stop the driver and reset the card.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_shutdown(device_t dev)
+{
+ struct l1_softc *sc = device_get_softc(dev);
+
+ itjc_bus_setup(sc);
+
+ /*
+ * Stop the DMA the nice and easy way.
+ */
+ itjc_bchannel_setup(sc->sc_unit, 0, BPROT_NONE, 0);
+ itjc_bchannel_setup(sc->sc_unit, 1, BPROT_NONE, 0);
+
+ /*
+ * Reset the card.
+ */
+ itjc_write_1(TIGER_RESET_PIB_CL_TIME, TIGER_RESET_ALL);
+
+ DELAY(SEC_DELAY/100); /* Give it 10 ms to reset ...*/
+
+ itjc_write_1(TIGER_RESET_PIB_CL_TIME,
+ TIGER_SELF_ADDR_DMA | TIGER_LATCH_DMA_INT | TIGER_PIB_3_CYCLES);
+
+ DELAY(SEC_DELAY/100); /* ... and more 10 to recover */
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_ret_linktab - Return the address of itjc drivers linktab.
+ *---------------------------------------------------------------------------*/
+isdn_link_t *
+itjc_ret_linktab(int unit, int channel)
+{
+#ifdef __FreeBSD__
+ struct l1_softc *sc = itjc_scp[unit];
+#else
+ struct l1_softc *sc = isic_find_sc(unit);
+#endif
+ l1_bchan_state_t *chan = &sc->sc_chan[channel];
+
+ return(&chan->isic_isdn_linktab);
+}
+
+/*---------------------------------------------------------------------------*
+ * itjc_set_linktab - Set the driver linktab in the b channel softc.
+ *---------------------------------------------------------------------------*/
+void
+itjc_set_linktab(int unit, int channel, drvr_link_t *dlt)
+{
+#ifdef __FreeBSD__
+ struct l1_softc *sc = itjc_scp[unit];
+#else
+ struct l1_softc *sc = isic_find_sc(unit);
+#endif
+ l1_bchan_state_t *chan = &sc->sc_chan[channel];
+
+ chan->isic_drvr_linktab = dlt;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_init_linktab - Initialize our local linktab.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_init_linktab(struct l1_softc *sc)
+{
+ l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A];
+ isdn_link_t *lt = &chan->isic_isdn_linktab;
+
+ /* make sure the hardware driver is known to layer 4 */
+ /* avoid overwriting if already set */
+ if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL)
+ {
+ ctrl_types[CTRL_PASSIVE].set_linktab = itjc_set_linktab;
+ ctrl_types[CTRL_PASSIVE].get_linktab = itjc_ret_linktab;
+ }
+
+ /* local setup */
+ lt->unit = sc->sc_unit;
+ lt->channel = HSCX_CH_A;
+ lt->bch_config = itjc_bchannel_setup;
+ lt->bch_tx_start = itjc_bchannel_start;
+ lt->bch_stat = itjc_bchannel_stat;
+ lt->tx_queue = &chan->tx_queue;
+
+ /* used by non-HDLC data transfers, i.e. telephony drivers */
+ lt->rx_queue = &chan->rx_queue;
+
+ /* used by HDLC data transfers, i.e. ipr and isp drivers */
+ lt->rx_mbuf = &chan->in_mbuf;
+
+ chan = &sc->sc_chan[HSCX_CH_B];
+ lt = &chan->isic_isdn_linktab;
+
+ lt->unit = sc->sc_unit;
+ lt->channel = HSCX_CH_B;
+ lt->bch_config = itjc_bchannel_setup;
+ lt->bch_tx_start = itjc_bchannel_start;
+ lt->bch_stat = itjc_bchannel_stat;
+ lt->tx_queue = &chan->tx_queue;
+
+ /* used by non-HDLC data transfers, i.e. telephony drivers */
+ lt->rx_queue = &chan->rx_queue;
+
+ /* used by HDLC data transfers, i.e. ipr and isp drivers */
+ lt->rx_mbuf = &chan->in_mbuf;
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_bchannel_stat - Collect link statistics for a given B channel.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp)
+{
+#ifdef __FreeBSD__
+ struct l1_softc *sc = itjc_scp[unit];
+#else
+ struct l1_softc *sc = isic_find_sc(unit);
+#endif
+ l1_bchan_state_t *chan = &sc->sc_chan[h_chan];
+ int s;
+
+ s = SPLI4B();
+
+ bsp->outbytes = chan->txcount;
+ bsp->inbytes = chan->rxcount;
+
+ chan->txcount = 0;
+ chan->rxcount = 0;
+
+ splx(s);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * Netjet - ISAC interrupt routine.
+ *---------------------------------------------------------------------------*/
+static void
+itjc_isac_intr(struct l1_softc *sc)
+{
+ register u_char irq_stat;
+
+ do
+ {
+ /* get isac irq status */
+ irq_stat = ISAC_READ(I_ISTA);
+
+ if(irq_stat)
+ itjc_isac_irq(sc, irq_stat); /* isac handler */
+ }
+ while(irq_stat);
+
+ ISAC_WRITE(I_MASK, 0xff);
+
+ DELAY(100);
+
+ ISAC_WRITE(I_MASK, ISAC_IMASK);
+}
+
+
+/*---------------------------------------------------------------------------*
+ * itjc_recover - Try to recover from ISAC irq lockup.
+ *---------------------------------------------------------------------------*/
+void
+itjc_recover(struct l1_softc *sc)
+{
+ u_char byte;
+
+ /* get isac irq status */
+
+ byte = ISAC_READ(I_ISTA);
+
+ NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte);
+
+ if(byte & ISAC_ISTA_EXI)
+ NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR));
+
+ if(byte & ISAC_ISTA_CISQ)
+ {
+ byte = ISAC_READ(I_CIRR);
+
+ NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte);
+
+ if(byte & ISAC_CIRR_SQC)
+ NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR));
+ }
+
+ NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK);
+
+ ISAC_WRITE(I_MASK, 0xff);
+ DELAY(100);
+ ISAC_WRITE(I_MASK, ISAC_IMASK);
+}
+
+#endif /* NITJC > 0 */
OpenPOWER on IntegriCloud