summaryrefslogtreecommitdiffstats
path: root/sys/i4b/layer1/ihfc
diff options
context:
space:
mode:
authorhm <hm@FreeBSD.org>2000-10-09 13:29:00 +0000
committerhm <hm@FreeBSD.org>2000-10-09 13:29:00 +0000
commit6a1e8c89a39e745792906a17cdf08fc5bdd384f4 (patch)
tree082a43cf60a2a80e84ca74e4339fda393b01ec06 /sys/i4b/layer1/ihfc
parent9fc2bc8a46f4f09ca71eaf59e5c203b5d61533fb (diff)
downloadFreeBSD-src-6a1e8c89a39e745792906a17cdf08fc5bdd384f4.zip
FreeBSD-src-6a1e8c89a39e745792906a17cdf08fc5bdd384f4.tar.gz
update to i4b version 0.95.04
Diffstat (limited to 'sys/i4b/layer1/ihfc')
-rw-r--r--sys/i4b/layer1/ihfc/i4b_ihfc.h337
-rw-r--r--sys/i4b/layer1/ihfc/i4b_ihfc_drv.c1743
-rw-r--r--sys/i4b/layer1/ihfc/i4b_ihfc_drv.h230
-rw-r--r--sys/i4b/layer1/ihfc/i4b_ihfc_ext.h62
-rw-r--r--sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c517
-rw-r--r--sys/i4b/layer1/ihfc/i4b_ihfc_pnp.c421
6 files changed, 3310 insertions, 0 deletions
diff --git a/sys/i4b/layer1/ihfc/i4b_ihfc.h b/sys/i4b/layer1/ihfc/i4b_ihfc.h
new file mode 100644
index 0000000..1036636
--- /dev/null
+++ b/sys/i4b/layer1/ihfc/i4b_ihfc.h
@@ -0,0 +1,337 @@
+/*
+ * 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_ihfc.h - ihfc common header file
+ * ------------------------------------
+ *
+ * last edit-date: [Wed Jul 19 09:40:45 2000]
+ *
+ * $Id: i4b_ihfc.h,v 1.9 2000/09/19 13:50:36 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _I4B_IHFC_H_
+#define _I4B_IHFC_H_
+
+#include <i4b/include/i4b_l3l4.h>
+
+/*---------------------------------------------------------------------------*
+ * global stuff (HFC-1/S/SP)
+ *---------------------------------------------------------------------------*/
+#define DCH_MAX_LEN 264 /* max length of a D frame */
+
+#define IHFC_ACTIVATION_TIMEOUT 3*hz /* S0-bus must activate before this time */
+
+#define IHFC_IO_BASES 1
+
+#define IHFC_DISBUSYTO 500 /* do at least 500 inb's before giving up */
+#define IHFC_NONBUSYTO 8000 /* do at least 8000 inb's before giving up */
+
+#define IHFC_NTMODE 0 /* use TE-mode as default */
+#define IHFC_DLP 0 /* use (8/9) priority as default */
+
+#define IHFC_MAXUNIT 4
+
+/* #define IHFC_DEBUG internal debugging enabled *
+ * #undef IHFC_DEBUG internal debugging disabled */
+
+/* chan: *
+ * 0 - D1 (tx) *
+ * 1 - D1 (rx) *
+ * 2 - B1 (tx) *
+ * 3 - B1 (rx) *
+ * 4 - B2 (tx) *
+ * 5 - B2 (rx) */
+
+#define HFC_1 0x01 /* HFC 2B */
+#define HFC_S 0x02 /* HFC - S 2BDS0 */
+#define HFC_SP 0x04 /* HFC - SP 2BDS0 */
+#define HFC_SPCI 0x08 /* HFC - SPCI 2BDS0 X */
+#define HFC_S2M 0x10 /* HFC - S2M 2BDS0 X */
+#define HFC_USB 0x20 /* HFC - USB 2BDS0 X */
+
+/*---------------------------------------------------------------------------*
+ * "Help Fix Corruption" macros (HFC-1/S/SP)
+ *
+ * NOTE: If the code does not run at splhigh, we will sporadically
+ * lose bytes. On fast PC's (200 Mhz), this is very little noticable.
+ *---------------------------------------------------------------------------*/
+#define HFC_VAR int _s_ /* declare variable */
+#define HFC_BEG _s_ = splhigh() /* save spl */
+#define HFC_END splx(_s_) /* restore spl */
+
+/*---------------------------------------------------------------------------*
+ * macros related to i4b linking (HFC-1/S/SP)
+ *---------------------------------------------------------------------------*/
+#define S_BLINK sc->sc_blinktab[(chan > 3) ? 1 : 0]
+#define S_BDRVLINK sc->sc_bdrvlinktab[(chan > 3) ? 1 : 0]
+
+/*---------------------------------------------------------------------------*
+ * macros related to ihfc_sc (HFC-1/S/SP)
+ *---------------------------------------------------------------------------*/
+
+/* statemachine */
+
+#define S_IOM2 (sc->sc_config.i_adf2 & 0x80)
+ /* 0x80: IOM2 mode selected */
+
+#define S_DLP (sc->sc_config.dlp)
+#define S_NTMODE (sc->sc_config.ntmode)
+#define S_STDEL (sc->sc_config.stdel)
+
+#define S_PHSTATE sc->sc_statemachine.state
+#define S_STM_T3 sc->sc_statemachine.T3
+#define S_STM_T3CALLOUT sc->sc_statemachine.T3callout
+
+/* unitnumbers */
+
+#define S_UNIT sc->sc_unit
+#define S_FLAG sc->sc_flag
+#define S_I4BUNIT sc->sc_i4bunit
+#define S_I4BFLAG sc->sc_i4bflag
+
+/* ISA bus setup */
+
+#define S_IOBASE sc->sc_resources.io_base
+#define S_IORID sc->sc_resources.io_rid
+#define S_IRQ sc->sc_resources.irq
+#define S_IRQRID sc->sc_resources.irq_rid
+
+/* hardware setup */
+
+#define S_HFC sc->sc_config.chiptype
+#define S_IIO sc->sc_config.iio
+#define S_IIRQ sc->sc_config.iirq
+
+/* registers of the HFC-S/SP (write only) */
+
+#define S_HFC_CONFIG sc->sc_config.cirm
+
+#define S_CIRM sc->sc_config.cirm
+#define S_CTMT sc->sc_config.ctmt
+#define S_TEST sc->sc_config.test
+#define S_SCTRL sc->sc_config.sctrl
+#define S_CLKDEL sc->sc_config.clkdel
+#define S_INT_M1 sc->sc_config.int_m1
+#define S_INT_M2 sc->sc_config.int_m2
+#define S_CONNECT sc->sc_config.connect
+#define S_SCTRL_R sc->sc_config.sctrl_r
+#define S_MST_MODE sc->sc_config.mst_mode
+
+/* registers of the HFC-S/SP (read only) */
+
+#define S_INT_S1 sc->sc_config.int_s1
+
+/* registers of the ISAC (write only) */
+
+#define S_ISAC_CONFIG sc->sc_config.i_adf2
+
+#define S_ADF1 sc->sc_config.i_adf1
+#define S_ADF2 sc->sc_config.i_adf2
+#define S_MASK sc->sc_config.i_mask
+#define S_MODE sc->sc_config.i_mode
+#define S_SPCR sc->sc_config.i_spcr
+#define S_SQXR sc->sc_config.i_sqxr
+#define S_STCR sc->sc_config.i_stcr
+#define S_STAR2 sc->sc_config.i_star2
+
+/* registers of the ISAC (read only) */
+
+#define S_ISTA sc->sc_config.i_ista
+
+/* state of the softc */
+
+#define S_ENABLED sc->sc_enabled
+#define S_INTR_ACTIVE sc->sc_intr_active
+
+/* SOFT-HDLC */
+
+#define S_HDLC_IB sc->sc_fifo.chan[chan].hdlc.ib /* u_short */
+#define S_HDLC_CRC sc->sc_fifo.chan[chan].hdlc.crc /* u_short */
+#define S_HDLC_TMP sc->sc_fifo.chan[chan].hdlc.tmp /* u_int */
+#define S_HDLC_FLAG sc->sc_fifo.chan[chan].hdlc.flag /* u_char */
+#define S_HDLC_BLEVEL sc->sc_fifo.chan[chan].hdlc.blevel /* u_short */
+
+/* stats */
+
+#define S_BYTES sc->sc_fifo.chan[chan].bytes
+
+/* "Z"-values */
+
+#define S_HDLC_DZ_TAB sc->sc_fifo.dztable
+
+/* filters */
+
+#define S_PROT sc->sc_fifo.chan[chan].prot
+#define S_FILTER sc->sc_fifo.chan[chan].filter
+#define S_ACTIVITY sc->sc_fifo.chan[chan].activity
+#define S_LAST_CHAN sc->sc_fifo.last_chan
+
+/* soft reset */
+
+#define RESET_SOFT_CHAN(sc, chan) bzero(&sc->sc_fifo.chan[chan], sizeof(sc->sc_fifo.chan[0]))
+
+/* trace */
+
+#define S_TRACE sc->sc_trace
+#define S_DTRACECOUNT sc->sc_Dtracecount
+#define S_BTRACECOUNT sc->sc_Btracecount
+
+/* mbuf */
+
+#define S_MBUF sc->sc_fifo.chan[chan].buffer.mbuf
+#define S_MBUFDUMMY sc->sc_fifo.chan[chan].buffer.mbufdummy
+#define S_MBUFLEN sc->sc_fifo.chan[chan].buffer.mbuf->m_len
+#define S_MBUFPKTHDR sc->sc_fifo.chan[chan].buffer.mbuf->m_pkthdr
+#define S_MBUFDATA sc->sc_fifo.chan[chan].buffer.mbuf->m_data
+#define S_MBUFDAT sc->sc_fifo.chan[chan].buffer.mbuf->m_dat
+
+#define S_IFQUEUE sc->sc_fifo.chan[chan].buffer.ifqueue
+
+/* hfc control */
+
+#define HFC_INIT ihfc_init
+#define HFC_INTR ((S_HFC & HFC_1) ? ihfc_intr1 : ihfc_intr2)
+#define HFC_FSM ihfc_fsm
+#define HFC_CONTROL ihfc_control
+
+/* softc parts */
+
+struct ihfc_sc;
+
+struct sc_resources {
+ struct resource * io_base[IHFC_IO_BASES];
+ int io_rid [IHFC_IO_BASES];
+ struct resource * irq;
+ int irq_rid;
+};
+
+struct hdlc {
+ u_char flag;
+ u_short blevel;
+ u_short crc;
+ u_short ib;
+ u_int tmp;
+};
+
+struct buffer {
+ struct ifqueue ifqueue; /* data queue */
+ struct mbuf *mbuf; /* current mbuf */
+ struct mbuf *mbufdummy; /* temporary */
+};
+
+struct chan {
+ struct hdlc hdlc;
+ u_int bytes;
+ u_int prot;
+ struct buffer buffer;
+ void (*filter)(struct ihfc_sc *sc, u_char chan);
+};
+
+struct sc_fifo {
+ struct chan chan[6];
+ u_short dztable[16];
+ u_char last_chan;
+};
+
+struct sc_config {
+ /* software only: */
+
+ u_short chiptype; /* chiptype (eg. HFC_1) */
+ u_char dlp; /* D-priority */
+ u_short iio; /* internal IO */
+ u_char iirq; /* internal IRQ */
+ u_char ntmode; /* mode */
+ u_char stdel; /* S/T delay */
+
+ /* write only: */
+ u_char cirm;
+ u_char ctmt;
+ u_char int_m1;
+ u_char int_m2;
+ u_char mst_mode;
+ u_char clkdel;
+ u_char sctrl;
+ u_char connect;
+ u_char test;
+ u_char sctrl_r;
+
+ /* isac write only - hfc-1: */
+ u_char i_adf2;
+ u_char i_spcr;
+ u_char i_sqxr;
+ u_char i_adf1;
+ u_char i_stcr;
+ u_char i_mode;
+ u_char i_mask;
+ u_char i_star2;
+
+ /* read only: */
+ u_char int_s1;
+
+ /* isac read only - hfc-1: */
+ u_char i_ista;
+};
+
+struct sc_statemachine {
+ u_char state; /* see i4b_ihfc_drv.h */
+ u_char usync;
+ u_char T3; /* T3 running */
+ struct callout_handle T3callout;
+};
+
+/*---------------------------------------------------------------------------*
+ * HFC softc
+ *---------------------------------------------------------------------------*/
+typedef struct ihfc_sc
+{ int sc_unit;
+ int sc_flag;
+
+ int sc_i4bunit; /* L0IHFCUNIT(sc_unit) */
+ int sc_i4bflag; /* FLAG_TEL_S0_16_3C .. */
+
+ u_char sc_enabled; /* daemon running if set */
+ u_char sc_intr_active; /* interrupt is active */
+
+ int sc_trace;
+ u_int sc_Btracecount;
+ u_int sc_Dtracecount;
+
+ struct sc_config sc_config;
+ struct sc_resources sc_resources;
+ struct sc_statemachine sc_statemachine;
+
+ isdn_link_t sc_blinktab[2];
+ drvr_link_t *sc_bdrvlinktab[2];
+
+ struct sc_fifo sc_fifo;
+} ihfc_sc_t;
+
+extern ihfc_sc_t ihfc_softc[];
+
+#endif /* _I4B_IHFC_H_ */
diff --git a/sys/i4b/layer1/ihfc/i4b_ihfc_drv.c b/sys/i4b/layer1/ihfc/i4b_ihfc_drv.c
new file mode 100644
index 0000000..bd56be2
--- /dev/null
+++ b/sys/i4b/layer1/ihfc/i4b_ihfc_drv.c
@@ -0,0 +1,1743 @@
+/*
+ * 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_ihfc_drv.c - ihfc ISA PnP-bus interface
+ * -------------------------------------------
+ *
+ * Everything which has got anything to do with the
+ * HFC-1/S/SP chips has been put here.
+ *
+ * last edit-date: [Wed Jul 19 09:39:42 2000]
+ *
+ * $Id: i4b_ihfc_drv.c,v 1.11 2000/09/19 13:50:36 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "ihfc.h"
+
+#if (NIHFC > 0)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <sys/mbuf.h>
+#include <machine/clock.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l1l2.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/i4b_hdlc.h>
+#include <i4b/layer1/ihfc/i4b_ihfc.h>
+#include <i4b/layer1/ihfc/i4b_ihfc_ext.h>
+#include <i4b/layer1/ihfc/i4b_ihfc_drv.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <isa/isavar.h>
+
+/*---------------------------------------------------------------------------*
+ * Local prototypes
+ *---------------------------------------------------------------------------*/
+ void ihfc_loadconfig (ihfc_sc_t *sc);
+
+static void ihfc_trans_Bread (ihfc_sc_t *sc, u_char chan);
+static void ihfc_trans_Bwrite (ihfc_sc_t *sc, u_char chan);
+static void ihfc_hdlc_Bread (ihfc_sc_t *sc, u_char chan);
+static void ihfc_hdlc_Bwrite (ihfc_sc_t *sc, u_char chan);
+static void ihfc_hdlc_Dread (ihfc_sc_t *sc, u_char chan);
+static void ihfc_hdlc_Dwrite (ihfc_sc_t *sc, u_char chan);
+
+static void ihfc_isac_Dread (ihfc_sc_t *sc, u_char chan);
+static void ihfc_isac_Dwrite (ihfc_sc_t *sc, u_char chan);
+
+ void ihfc_cmdr_hdlr (ihfc_sc_t *sc, u_char cmdr);
+ void ihfc_exir_hdlr (ihfc_sc_t *sc, u_char exir);
+
+ void ihfc_sq (ihfc_sc_t *sc);
+
+static void ihfc_test_Bread (ihfc_sc_t *sc, u_char chan);
+static void ihfc_test_Bwrite (ihfc_sc_t *sc, u_char chan);
+
+u_short ihfc_Bsel_fifo (ihfc_sc_t *sc, u_char chan, u_char flag);
+u_int32_t ihfc_Dsel_fifo (ihfc_sc_t *sc, u_char chan, u_char flag);
+
+
+/*---------------------------------------------------------------------------*
+ * Commonly used ISA bus commands
+ *---------------------------------------------------------------------------*/
+#define IHFC_DATA_OFFSET 0
+#define IHFC_REG_OFFSET 1
+
+#define BUS_VAR bus_space_handle_t h = rman_get_bushandle(S_IOBASE[0]); \
+ bus_space_tag_t t = rman_get_bustag (S_IOBASE[0])
+
+#define SET_REG(reg) bus_space_write_1(t,h, IHFC_REG_OFFSET, reg)
+#define GET_STAT bus_space_read_1 (t,h, IHFC_REG_OFFSET)
+
+#define READ_DATA_1 bus_space_read_1 (t,h, IHFC_DATA_OFFSET)
+#define READ_BOTH_2 bus_space_read_2 (t,h, IHFC_DATA_OFFSET)
+
+#define WRITE_DATA_1(data) bus_space_write_1(t,h, IHFC_DATA_OFFSET, data)
+#define WRITE_BOTH_2(data) bus_space_write_2(t,h, IHFC_DATA_OFFSET, data)
+
+#define DISBUSY(okcmd, tocmd) \
+{ \
+ if (GET_STAT & 1) \
+ { \
+ register u_char a; \
+ register u_int to = IHFC_DISBUSYTO; \
+ \
+ while(((a = GET_STAT) & 1) && --to); \
+ \
+ if (!to) \
+ { \
+ NDBGL1(L1_ERROR, "DISBUSY-TIMEOUT! (a=%04x, " \
+ "unit=%d)", a, S_UNIT); \
+ tocmd; \
+ } \
+ else \
+ { \
+ okcmd; \
+ } \
+ } \
+ else \
+ { \
+ okcmd; \
+ } \
+}
+
+#define WAITBUSY_2(okcmd, tocmd) \
+ { \
+ register u_short a; \
+ register u_int to = IHFC_NONBUSYTO; \
+ \
+ while((~(a = READ_BOTH_2) & 0x100) && --to); \
+ \
+ if (!to) \
+ { \
+ NDBGL1(L1_ERROR, "NONBUSY-TIMEOUT! (a=%04x, " \
+ "unit=%d)", a, S_UNIT); \
+ tocmd; \
+ } \
+ else \
+ { \
+ okcmd; \
+ } \
+ }
+
+/*---------------------------------------------------------------------------*
+ * Control function (HFC-1/S/SP)
+ *
+ * Flag:
+ * 1: reset and unlock chip (at boot only)
+ * 2: prepare for shutdown (at shutdown only)
+ * 3: reset and resume
+ * 4: select TE-mode (boot default)
+ * 5: select NT-mode (only HFC-S/SP/PCI)
+ *
+ * Returns != 0 on errornous chip
+ *---------------------------------------------------------------------------*/
+int
+ihfc_control(ihfc_sc_t *sc, int flag)
+{
+ BUS_VAR;
+
+ if (flag == 3) goto reset0;
+ if (flag == 4)
+ {
+ S_NTMODE = 0;
+ goto mode0;
+ }
+ if (flag == 5)
+ {
+ S_NTMODE = 1;
+ goto mode0;
+ }
+ if (flag == 1)
+ {
+ WRITE_BOTH_2(0x5400 | S_IIO); /* enable IO (HFC-1/S) */
+
+ S_LAST_CHAN = -1;
+
+ /* HFC-S/SP configuration */
+
+ S_CIRM = S_IIRQ|0x10; /* IRQ, 8K fifo mode */
+ S_CLKDEL = 0x00; /* 12.288mhz */
+ S_CTMT = 0x03; /* transperant mode */
+ S_CONNECT = 0x00; /* B channel data flow */
+ S_INT_M1 = 0x40; /* interrupt mask */
+ S_INT_M2 = 0x08; /* enable interrupt output */
+ S_MST_MODE = 0x01; /* master mode */
+ S_SCTRL = 0x50; /* S/Q on, non cap. line mode */
+ S_SCTRL_R = 0x00; /* B channel receive disable */
+ S_TEST = 0x00; /* no need for awake enable */
+
+ if (S_HFC & (HFC_1 | HFC_S)) /* configure timer (50ms) */
+ {
+ S_CTMT |= 0x08;
+ }
+ else
+ {
+ S_CTMT |= 0x14;
+ }
+
+ /* HFC-1 ISAC configuration (IOM-2 mode) */
+
+ S_ADF1 = 0x00; /* */
+ S_ADF2 = 0x80; /* select mode IOM-2 */
+ S_SPCR = 0x00; /* B channel send disable (0x10 for test loop) */
+ S_MASK = 0xfb; /* enable CISQ */
+ S_MODE = 0xc9; /* receiver enabled */
+ S_SQXR = 0x0f; /* master, clock always active */
+ S_STCR = 0x70; /* TIC bus address = 7 */
+ S_STAR2 = 0x04; /* enable S/Q */
+
+ mode0:
+ if (S_NTMODE) /* configure NT- or TE-mode */
+ {
+ S_SCTRL |= 0x04; /* NT mode */
+ S_CLKDEL &= ~0x7f; /* clear delay */
+ S_CLKDEL |= 0x6c; /* set delay */
+ }
+ else
+ {
+ S_SCTRL &= ~0x04; /* TE mode */
+ S_CLKDEL &= ~0x7f; /* clear delay */
+ S_CLKDEL |= S_STDEL; /* set delay */
+ }
+ if (S_DLP) /* configure D-priority */
+ {
+ S_SCTRL |= 0x08; /* (10/11) */
+ }
+ else
+ {
+ S_SCTRL &= ~0x08; /* (8/9) */
+ }
+
+ reset0:
+ /* chip reset (HFC-1/S/SP) */
+
+ if (S_HFC & HFC_1)
+ {
+ SET_REG((S_CIRM | 0xc8) & 0xdf);
+
+ DELAY(10); /* HFC-2B manual recommends a 4 *
+ * clock cycle delay after CIRM *
+ * write with reset=1. A 1us *
+ * delay, should do for 7.68mhz,*
+ * but just in case I make that *
+ * 10us. */
+
+ SET_REG((S_CIRM | 0xc0) & 0xdf);
+
+ DELAY(250); /* ISAC manual says reset pulse *
+ * length is 125us. Accessing *
+ * ISAC before those 125us, we *
+ * may risk chip corruption and *
+ * irq failure. The HFC-2B also *
+ * needs some delay to recover, *
+ * so we add some us. */
+ }
+ else
+ {
+ SET_REG(0x18);
+
+ WRITE_DATA_1(S_CIRM | 8);
+
+ DELAY(10); /* HFC-2BDS0 manual recommends *
+ * a 4 clock cycle delay after *
+ * CIRM write with reset=1. *
+ * A 1us delay, should do for *
+ * 12.288mhz, but just in case *
+ * I make that 10us. */
+
+ WRITE_DATA_1(S_CIRM);
+
+ DELAY(25); /* HFC-2BDS0 needs some time to *
+ * recover after CIRM write *
+ * with reset=0. Experiments *
+ * show this delay should be *
+ * 8-9us. Just in case we make *
+ * that 25us. */
+ }
+
+ {
+ /* HFC-1/S/SP chip test *
+ * *
+ * NOTE: after reset the HFC-1/S/SP should be *
+ * in a mode where it is always non-busy/non- *
+ * processing, and bit[0] of STATUS/DISBUSY *
+ * register, should always return binary '0' *
+ * until we configure the chips for normal *
+ * operation. */
+#ifdef IHFC_DEBUG
+ printf("ihfc: GET_STAT value is: 0x%x\n", GET_STAT);
+#endif
+ SET_REG(0x30);
+
+ if ((GET_STAT & 1) || (READ_DATA_1 & 0xf)) goto f0;
+ }
+
+ ihfc_loadconfig(sc);
+
+ if (S_HFC & HFC_1) ihfc_cmdr_hdlr(sc, 0x41); /* rres, xres */
+
+ S_PHSTATE = 0;
+ HFC_FSM(sc, 0);
+ }
+
+ if (flag == 2)
+ {
+ if (S_HFC & HFC_1) S_CIRM &= ~0x03; /* disable interrupt */
+
+ S_SQXR |= 0x40; /* power down */
+
+ S_SPCR &= ~0x0f; /* send 1's only */
+ S_SCTRL &= ~0x83; /* send 1's only + enable oscillator */
+
+ ihfc_loadconfig(sc);
+ }
+
+ return(0); /* success */
+
+ f0:
+ return(1); /* failure */
+}
+
+/*---------------------------------------------------------------------------*
+ * Softc initializer and hardware setup (HFC-1/S/SP)
+ *
+ * Returns: 0 on success
+ * 1 on failure
+ *---------------------------------------------------------------------------*/
+int
+ihfc_init (ihfc_sc_t *sc, u_char chan, int prot, int activate)
+{
+ if (chan > 5) goto f0;
+
+ chan &= ~1;
+
+ do
+ { if (chan < 2) /* D-Channel */
+ {
+ i4b_Dfreembuf(S_MBUF);
+ i4b_Dcleanifq(&S_IFQUEUE);
+
+ RESET_SOFT_CHAN(sc, chan);
+
+ S_IFQUEUE.ifq_maxlen = IFQ_MAXLEN;
+
+ if (!activate) continue;
+
+ if (S_HFC & HFC_1)
+ {
+ S_FILTER = (chan & 1) ? ihfc_isac_Dread :
+ ihfc_isac_Dwrite;
+ }
+ else
+ {
+ S_FILTER = (chan & 1) ? ihfc_hdlc_Dread :
+ ihfc_hdlc_Dwrite;
+ }
+ }
+ else /* B-Channel */
+ {
+ i4b_Bfreembuf(S_MBUF);
+ i4b_Bcleanifq(&S_IFQUEUE);
+
+ RESET_SOFT_CHAN(sc, chan);
+
+ S_PROT = prot;
+ S_IFQUEUE.ifq_maxlen = IFQ_MAXLEN;
+
+ if (!activate) continue;
+
+ switch(prot)
+ { case(BPROT_NONE):
+ S_FILTER = (chan & 1) ?
+ ihfc_trans_Bread :
+ ihfc_trans_Bwrite;
+ break;
+ case(BPROT_RHDLC):
+ S_FILTER = (chan & 1) ?
+ ihfc_hdlc_Bread :
+ ihfc_hdlc_Bwrite;
+ break;
+ case(5):
+ S_FILTER = (chan & 1) ?
+ ihfc_test_Bread :
+ ihfc_test_Bwrite;
+ break;
+ }
+ }
+ } while (++chan & 1);
+
+ S_MASK |= 0xfb; /* disable all, but CISQ interrupt (ISAC) */
+ S_INT_M1 &= 0x40; /* disable all, but TE/NT state machine (HFC) */
+ S_SCTRL &= ~0x03; /* B1/B2 send disable (HFC) */
+ S_SPCR &= ~0x0f; /* B1/B2 send disable (ISAC) */
+ S_SCTRL_R &= ~0x03; /* B1/B2 receive disable (HFC) */
+
+ chan = 0;
+ if (S_FILTER) /* D-Channel active */
+ {
+ S_MASK &= 0x2e; /* enable RME, RPF, XPR, EXI */
+ S_INT_M1 |= 0x24; /* enable D-receive, D-transmit */
+ }
+
+ chan = 2;
+ if (S_FILTER) /* B1-Channel active */
+ {
+ S_SCTRL |= 1; /* send enable (HFC) */
+ S_SPCR |= 8; /* send enable (ISAC) */
+ S_SCTRL_R |= 1; /* receive enable (HFC) */
+ S_INT_M1 |= 0x80; /* timer enable (HFC) */
+ S_INT_M1 &= ~0x04; /* let D-channel use timer too */
+ }
+
+ chan = 4;
+ if (S_FILTER) /* B2-Channel active */
+ {
+ S_SCTRL |= 2; /* send enable (HFC) */
+ S_SPCR |= 2; /* send enable (ISAC) */
+ S_SCTRL_R |= 2; /* receive enable (HFC) */
+ S_INT_M1 |= 0x80; /* timer enable (HFC) */
+ S_INT_M1 &= ~0x04; /* let D-channel use timer too */
+ }
+
+ ihfc_loadconfig(sc);
+
+ /* XXX reset timer? */
+
+ return 0; /* success */
+ f0:
+ return 1; /* failure */
+}
+
+/*---------------------------------------------------------------------------*
+ * Load configuration data (HFC-1/S/SP)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_loadconfig(ihfc_sc_t *sc)
+{
+ BUS_VAR;
+
+ if (S_HFC & HFC_1)
+ {
+ /* HFC-1 chips w/ISAC: */
+
+ const u_char *src = (void *)&S_ISAC_CONFIG;
+ const u_char *dst = (void *)&isac_configtable;
+
+ SET_REG((S_CIRM | 0xc0) & 0xdf);
+
+ S_CTMT = (S_CTMT & ~0x14) | ((S_INT_M1 >> 5) & 0x4);
+
+ SET_REG((S_CTMT | 0xe0) & 0xff);
+
+ while(*dst)
+ {
+ SET_REG(*dst++); /* set register */
+
+ /* write configuration */
+ DISBUSY(WRITE_DATA_1(*src++), break);
+ }
+ }
+ else
+ {
+ /* HFC-S/SP chips: */
+
+ const u_char *src = (void *)&S_HFC_CONFIG;
+ const u_char *dst = (void *)&ihfc_configtable;
+
+ while(*dst)
+ {
+ SET_REG(*dst++); /* set register */
+ WRITE_DATA_1(*src++); /* write configuration */
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Function State Machine handler (PH layer) (HFC-1/S/SP)
+ *
+ * Flag: 0 = Refresh softc S_PHSTATE + take hints
+ * 1 = Activate
+ * 2 = Deactivate
+ *
+ * NOTE: HFC-1 only supports TE mode.
+ *---------------------------------------------------------------------------*/
+void
+ihfc_fsm(ihfc_sc_t *sc, int flag)
+{
+ const struct ihfc_FSMtable *fsmtab;
+ u_char ihfc_cmd = 0;
+ u_char isac_cmd = 0;
+ u_char tmp;
+ BUS_VAR;
+
+ /* get current state (rx/downstream) */
+
+ if (S_HFC & HFC_1)
+ {
+ SET_REG(0x31); DISBUSY(tmp = (READ_DATA_1 >> 2) & 0xf, return);
+
+ fsmtab = (S_NTMODE) ? &ihfc_TEtable2[tmp]:
+ &ihfc_TEtable2[tmp];
+ }
+ else
+ {
+ SET_REG(0x30); tmp = READ_DATA_1 & 0xf;
+
+ fsmtab = (S_NTMODE) ? &ihfc_NTtable[tmp]:
+ &ihfc_TEtable[tmp];
+ }
+
+ if (fsmtab->string)
+ {
+ NDBGL1(L1_I_CICO, "%s (ind=0x%x, flag=%d, unit=%d).",
+ fsmtab->string, tmp, flag, S_UNIT);
+ }
+ else
+ {
+ NDBGL1(L1_I_ERR, "Illegal indicatation (ind=0x%x, "
+ "flag=%d, unit=%d).", tmp, flag, S_UNIT);
+ }
+
+ /* indication machine / state change *
+ * *
+ * Whenever the state of the S0-line changes, we check to see in which *
+ * direction the change went. Generally upwards means activate, and *
+ * downwards means deactivate. *
+ * The test signal is used to ensure proper syncronization. */
+
+ if (fsmtab->state == 0) /* deactivated indication */
+ {
+ if (S_PHSTATE != 0)
+ {
+ isac_cmd = 0x3c; /* deactivate DUI */
+
+ i4b_l1_ph_deactivate_ind(S_I4BUNIT);
+ }
+ }
+ if (fsmtab->state == 2) /* syncronized indication */
+ {
+ if (S_PHSTATE != 2)
+ {
+ if (S_NTMODE) ihfc_cmd = 0x80;
+ }
+ }
+ if (fsmtab->state == 3) /* activated indication */
+ {
+ if (S_PHSTATE != 3)
+ {
+ isac_cmd = (S_DLP) ? 0x24 /* activate AR10 */
+ : 0x20; /* activate AR8 */
+
+ i4b_l1_ph_activate_ind(S_I4BUNIT);
+ }
+ }
+ if (fsmtab->state == 4) /* error indication */
+ {
+ if (S_PHSTATE < 4)
+ {
+ isac_cmd = 0x3c; /* deactivate DUI */
+ }
+ }
+
+ S_PHSTATE = fsmtab->state;
+
+ if ((flag == 1) && (fsmtab->state != 3))
+ {
+ isac_cmd = (S_DLP) ? 0x24 : 0x20;
+ ihfc_cmd = 0x60;
+ }
+ if ((flag == 2) && (fsmtab->state != 0))
+ {
+ isac_cmd = 0x3c;
+ ihfc_cmd = 0x40;
+ }
+
+ /* set new state (tx / upstream) *
+ * *
+ * NOTE: HFC-S/SP and ISAC transmitters are always active when *
+ * activated state is reached. The bytes sent to the S0-bus are all *
+ * high impedance, so they do not disturb. *
+ * The HFC-1 has a seperate SIEMENS S0-device. */
+
+ if (S_HFC & HFC_1)
+ {
+ if (isac_cmd)
+ {
+ if (S_IOM2) isac_cmd |= 3;
+
+ SET_REG(0x31); DISBUSY(WRITE_DATA_1(isac_cmd), );
+
+ NDBGL1(L1_I_CICO, "(isac_cmd=0x%x, unit=%d).",
+ isac_cmd, S_UNIT);
+ }
+ }
+ else
+ {
+ if (ihfc_cmd || (fsmtab->state == 5))
+ {
+ SET_REG(0x30); WRITE_DATA_1(ihfc_cmd);
+
+ NDBGL1(L1_I_CICO, "(ihfc_cmd=0x%x, unit=%d).",
+ ihfc_cmd, S_UNIT);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * S/Q - channel handler (read) (HFC-S/SP)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_sq (ihfc_sc_t *sc)
+{
+ const struct ihfc_SQtable *SQtab;
+ register u_char a = 0;
+ BUS_VAR;
+
+ if (S_HFC & HFC_1)
+ {
+ SET_REG(0x31);
+ DISBUSY(a = READ_DATA_1, a = 0);
+
+ if (a & 0x80)
+ {
+ SET_REG(0x3b);
+ DISBUSY(a = READ_DATA_1, a = 0);
+ }
+ }
+ else
+ {
+ SET_REG(0x34);
+ a = READ_DATA_1;
+ }
+
+ SQtab = (S_NTMODE) ? &ihfc_Qtable[a & 7]:
+ &ihfc_Stable[a & 7];
+
+ if (a & 0x10)
+ {
+ if (SQtab->string)
+ {
+ NDBGL1(L1_I_CICO, "%s (unit=%d, int=%x)",
+ SQtab->string, S_UNIT, S_INT_S1);
+ }
+ else
+ {
+ NDBGL1(L1_ERROR, "Unknown indication = %x (unit=%d)",
+ a & 7, S_UNIT);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Interrupt handler (HFC-1)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_intr1 (ihfc_sc_t *sc)
+{
+ u_char chan;
+ u_char tmp;
+ BUS_VAR;
+ HFC_VAR;
+
+ HFC_BEG;
+
+ SET_REG(0x20); tmp = GET_STAT; DISBUSY(S_ISTA |= READ_DATA_1, );
+
+ if (S_ISTA & 0x04) /* CIRQ */
+ {
+ HFC_FSM(sc, 0);
+
+ ihfc_sq(sc);
+ }
+
+ S_INTR_ACTIVE = 1;
+
+ if (S_ISTA & 0xc0) /* RPF or RME */
+ {
+ chan = 1;
+ if (S_FILTER) S_FILTER(sc, chan);
+ }
+ if (S_ISTA & 0x10) /* XPR */
+ {
+ chan = 0;
+ if (S_FILTER) S_FILTER(sc, chan);
+ }
+ if (tmp & 0x04) /* Timer elapsed (50ms) */
+ {
+ SET_REG((S_CTMT | 0xf0) & 0xff);
+
+ chan = 6;
+ while(chan--)
+ {
+ if (chan == 1) break;
+ if (S_FILTER) S_FILTER(sc, chan);
+ }
+ }
+
+ S_INTR_ACTIVE = 0;
+
+ if (S_ISTA & 0x01) /* EXIR */
+ {
+ SET_REG(0x24); DISBUSY(ihfc_exir_hdlr(sc, READ_DATA_1), );
+ }
+
+ S_ISTA &= ~(0x1 | 0x4);
+
+ HFC_END;
+}
+
+/*---------------------------------------------------------------------------*
+ * Interrupt handler (HFC-S/SP)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_intr2 (ihfc_sc_t *sc)
+{
+ u_char chan;
+ BUS_VAR;
+ HFC_VAR;
+
+ HFC_BEG;
+
+ SET_REG(0x1e); S_INT_S1 = READ_DATA_1; /* this will enable new interrupts! */
+
+ if (S_INT_S1 & 0x40)
+ {
+ HFC_FSM(sc, 0); /* statemachine changed */
+
+ ihfc_sq(sc);
+ }
+
+ S_INTR_ACTIVE = 1;
+
+ if (S_INT_S1 & 0x20) /* D-Channel frame (rx) */
+ {
+ chan = 1;
+ if (S_FILTER) S_FILTER(sc, chan);
+ }
+ if (S_INT_S1 & 0x04) /* D-Channel frame (tx) */
+ {
+ chan = 0;
+ if (S_FILTER && (~S_INT_S1 & 0x80)) S_FILTER(sc, chan);
+ }
+ if (S_INT_S1 & 0x80) /* Timer elapsed (50ms) */
+ {
+ chan = 6;
+ while(chan--)
+ {
+ if (chan == 1) continue;
+ if (S_FILTER) S_FILTER(sc, chan);
+ }
+ }
+
+ S_INTR_ACTIVE = 0;
+
+ HFC_END;
+}
+
+/*---------------------------------------------------------------------------*
+ * Select a Bfifo (HFC-1/S/SP)
+ * and return bytes in FIFO
+ *
+ * (this code is optimized)
+ *---------------------------------------------------------------------------*/
+u_short
+ihfc_Bsel_fifo(ihfc_sc_t *sc, u_char chan, u_char flag)
+{
+ register u_char reg = 0x7e + chan;
+ register u_short tmp = 0x100;
+ register u_short z1;
+ register u_short z2;
+
+ BUS_VAR;
+
+ if (S_HFC & (HFC_1 | HFC_S))
+ {
+ if (S_LAST_CHAN != chan)
+ {
+ SET_REG(reg);
+ DISBUSY(WAITBUSY_2( , return 0), return 0);
+
+ S_LAST_CHAN = chan;
+ }
+ }
+ else
+ {
+ SET_REG(0x10);
+ WRITE_DATA_1(chan - 2);
+ DISBUSY( , return 0);
+ }
+
+#define FAST_READ (u_char)(tmp = READ_BOTH_2)
+#define FAST_STAT if (tmp & 0x100) DISBUSY( , return 0);
+
+ SET_REG(reg ); FAST_STAT; z1 = FAST_READ;
+ SET_REG(reg += 4); FAST_STAT; z1 |= FAST_READ << 8;
+ SET_REG(reg += 4); FAST_STAT; z2 = FAST_READ;
+ SET_REG(reg += 4); FAST_STAT; z2 |= READ_DATA_1 << 8;
+
+#undef FAST_READ
+#undef FAST_STAT
+
+ z1 &= 0x1fff;
+ z2 &= 0x1fff;
+
+ z1 = 0x5ff - (z2 = z1 - z2 + ((z2 <= z1) ? 0 : 0x600));
+
+ if (chan & 1)
+ return(z2); /* receive channel */
+ else
+ return(z1); /* transmit channel */
+}
+
+/*---------------------------------------------------------------------------*
+ * Select a Dfifo (HFC-S/SP)
+ * and return bytes, and frames in FIFO
+ *
+ * Flag values:
+ * 0x00: select new fifo + update counters
+ * 0x10: increment f1 + update counters
+ * 0x20: increment f2 + update counters
+ *
+ * NOTE: The upper 16bits holds the number of frames in the FIFO.
+ * NOTE: FIFO has to be selected before you can use flags 0x10/0x20.
+ *---------------------------------------------------------------------------*/
+u_int32_t
+ihfc_Dsel_fifo(ihfc_sc_t *sc, u_char chan, u_char flag)
+{
+ register u_char reg = 0x90 + chan;
+ register u_short tmp = 0x100;
+ register u_char f1;
+ register u_char f2;
+ register u_short z1;
+ register u_short z2;
+
+ BUS_VAR;
+
+ if (S_HFC & (HFC_1 | HFC_S))
+ {
+ switch(flag)
+ {
+ case(0x10):
+ case(0x20):
+ SET_REG(reg);
+ if (~GET_STAT & 1)
+ WAITBUSY_2( , return 0);
+
+ SET_REG(0xa2 - (flag & 0x10) + chan);
+ DISBUSY(READ_DATA_1, return 0);
+
+ SET_REG(reg);
+ if (~GET_STAT & 1)
+ WAITBUSY_2( , return 0);
+ break;
+
+ default:
+ if (S_LAST_CHAN != chan)
+ {
+ SET_REG(reg);
+ DISBUSY(WAITBUSY_2( , return 0), return 0);
+
+ S_LAST_CHAN = chan;
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch(flag)
+ {
+ case(0x10):
+ case(0x20):
+ SET_REG(0xb8 - (flag & 0x10) + chan);
+ READ_DATA_1;
+
+ DISBUSY( , return 0);
+
+ if (chan & 1)
+ {
+ /* Before reading a FIFO a change *
+ * FIFO operation must be done. *
+ * (see HFC-SP manual p.38) */
+
+ SET_REG(0x10);
+ WRITE_DATA_1(chan | 4);
+
+ DISBUSY( , return 0);
+ }
+ break;
+
+ default:
+ SET_REG(0x10);
+ WRITE_DATA_1(chan | 4);
+
+ DISBUSY( , return 0);
+ break;
+ }
+ }
+
+#define FAST_READ (u_char)(tmp = READ_BOTH_2)
+#define FAST_STAT if (tmp & 0x100) DISBUSY( , return 0);
+
+ if (S_HFC & HFC_SP) reg = 0x80 + chan;
+
+ SET_REG(reg ); FAST_STAT; z1 = FAST_READ;
+ SET_REG(reg += 4); FAST_STAT; z1 |= FAST_READ << 8;
+ SET_REG(reg += 4); FAST_STAT; z2 = FAST_READ;
+ SET_REG(reg += 4); FAST_STAT; z2 |= FAST_READ << 8;
+
+ if (S_HFC & HFC_SP) reg += 0x26;
+
+ SET_REG(reg -= 2); FAST_STAT; f1 = FAST_READ;
+ SET_REG(reg += 4); FAST_STAT; f2 = READ_DATA_1;
+
+#undef FAST_READ
+#undef FAST_STAT
+
+ if (~chan & 1)
+ { /* XXX was Z1 */
+ S_HDLC_DZ_TAB[f1 & 0xf] = z2; /* We keep track of the 'Z' *
+ * values for D-channel (tx),*
+ * so we may calculate the # *
+ * of FIFO bytes free when *
+ * f1 != f2. */
+ z2 = S_HDLC_DZ_TAB[f2 & 0xf];
+ }
+
+ z1 = 0x1ff - (z2 = (z1 - z2) & 0x1ff);
+ f1 = 0xf - (f2 = (f1 - f2) & 0xf);
+
+ if (chan & 1)
+ return(z2 | (f2 << 16)); /* receive channel */
+ else
+ return(z1 | (f1 << 16)); /* transmit channel */
+}
+
+
+/*---------------------------------------------------------------------------*
+ * Data handler for D channel(write) - chan 0 (HFC-S/SP)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_hdlc_Dwrite (ihfc_sc_t *sc, u_char chan)
+{
+ register u_int32_t sendlen;
+ register u_short len;
+ register u_char * src;
+
+ BUS_VAR;
+
+ if (!S_MBUF && IF_QEMPTY(&S_IFQUEUE)) return;
+
+ sendlen = ihfc_Dsel_fifo(sc, chan, 0); /* select new fifo *
+ * NOTE: the 16 higher bits *
+ * contain the # of frame- *
+ * etries free in the FIFO */
+ while (sendlen & ~0xffff)
+ {
+ if (!S_MBUF)
+ {
+ if (!(S_MBUF = ihfc_getmbuf(sc, chan))) goto j1;
+ }
+
+ src = S_MBUFDATA;
+ len = S_MBUFLEN;
+
+ if (len >= 0x1ff) goto j0; /* frame is too big: skip! */
+
+ sendlen &= 0xffff; /* only keep # of *
+ * bytes free */
+
+ SET_REG((S_HFC & HFC_SP) ? 0xac : 0x96);
+
+ while (sendlen--)
+ {
+ if (!len--) break;
+
+ DISBUSY(WRITE_DATA_1(*src++), sendlen = -1; len++; break);
+ }
+
+ if (!++sendlen) /* out of fifo: suspend */
+ {
+ S_MBUFDATA = src;
+ S_MBUFLEN = len;
+ break;
+ }
+
+ sendlen = ihfc_Dsel_fifo(sc, chan, 0x10); /* inc F1 */
+ j0:
+ i4b_Dfreembuf(S_MBUF);
+ S_MBUF = NULL;
+ }
+ j1:
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for D channel(read) - chan 1 (HFC-S/SP)
+ *
+ * NOTE: Max framelength is (511 - 3) = 508 bytes, when only one frame
+ * is received at a time.
+ *---------------------------------------------------------------------------*/
+void
+ihfc_hdlc_Dread (ihfc_sc_t *sc, u_char chan)
+{
+ register u_char tmp = -1;
+ register u_char to = 15;
+ register u_int32_t reclen;
+ register u_short crc;
+ register u_short len;
+ register u_char * dst;
+
+ BUS_VAR;
+
+ reclen = ihfc_Dsel_fifo(sc, chan, 0); /* select new fifo *
+ * NOTE: the higher 16 bits *
+ * contain the # of frames *
+ * to receive. */
+ while ((reclen & ~0xffff) && to--)
+ {
+ reclen &= 0xffff; /* only keep # of *
+ * bytes to receive */
+
+ if (!(S_MBUF = i4b_Dgetmbuf(DCH_MAX_LEN)))
+ panic("ihfc_hdlc_Dread: No mbufs(unit=%d)!\n", S_UNIT);
+
+ SET_REG((S_HFC & HFC_SP) ? 0xbd : 0xa7);
+
+ if ((reclen > 2) && (reclen <= (DCH_MAX_LEN+2)))
+ {
+ dst = S_MBUFDATA;
+ len = S_MBUFLEN = (reclen += 1) - 3;
+ }
+ else
+ {
+ len = 0;
+ dst = NULL;
+ }
+
+ crc = -1; /* NOTE: after a "F1" or "Z1" hardware overflow *
+ * it appears not to be necessary to reset the *
+ * HFC-1/S or SP chips to continue proper *
+ * operation, only and only, if we always read *
+ * "Z1-Z2+1" bytes when F1!=F2 followed by a *
+ * F2-counter increment. The bi-effect of doing *
+ * this is the "STAT" field may say frame is ok *
+ * when the frame is actually bad. *
+ * The simple solution is to re-CRC the frame *
+ * including "STAT" field to see if we get *
+ * CRC == 0x3933. Then we're 99% sure all *
+ * frames received are good. */
+
+ while(reclen--)
+ {
+ DISBUSY(tmp = READ_DATA_1, break);
+ if (len) { len--; *dst++ = tmp; }
+
+ crc = (HDLC_FCS_TAB[(u_char)(tmp ^ crc)] ^ (u_char)(crc >> 8));
+ }
+
+ crc ^= 0x3933;
+
+ if (!tmp && !crc)
+ {
+ ihfc_putmbuf(sc, chan, S_MBUF);
+ S_MBUF = NULL;
+ }
+ else
+ {
+ NDBGL1(L1_ERROR, "Frame error (len=%d, stat=0x%x, "
+ "crc=0x%x, unit=%d)", S_MBUFLEN, (u_char)tmp, crc,
+ S_UNIT);
+
+ i4b_Dfreembuf(S_MBUF);
+ S_MBUF = NULL;
+ }
+
+ reclen = ihfc_Dsel_fifo(sc, chan, 0x20);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * EXIR error handler - ISAC (D - channel) (HFC-1)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_exir_hdlr (ihfc_sc_t *sc, u_char exir)
+{
+ register u_char a;
+ register u_char cmd;
+
+ for (a = 0, cmd = 0; exir; a++, exir >>= 1)
+ {
+ if (exir & 1)
+ {
+ NDBGL1(L1_I_ERR, "%s. (unit=%d)",
+ ihfc_EXIRtable[a].string, S_UNIT);
+ cmd |= ihfc_EXIRtable[a].cmd;
+ }
+ }
+
+ if (cmd) ihfc_cmdr_hdlr(sc, cmd);
+}
+
+/*---------------------------------------------------------------------------*
+ * CMDR handler - ISAC (D - channel) (HFC-1)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_cmdr_hdlr (ihfc_sc_t *sc, u_char cmdr)
+{
+ BUS_VAR;
+
+ SET_REG(0x21); DISBUSY(WRITE_DATA_1(cmdr); DELAY(30), );
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for D channel(write) - chan 0 (HFC-1)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_isac_Dwrite (ihfc_sc_t *sc, u_char chan)
+{
+ register u_char sendlen = 32;
+ register u_char cmd = 0;
+ register u_short len;
+ register u_char * src;
+
+ BUS_VAR;
+
+ if (~S_ISTA & 0x10) goto j0;
+
+ if (!S_MBUF)
+ if (!(S_MBUF = ihfc_getmbuf(sc, chan))) goto j0;
+
+ len = S_MBUFLEN;
+ src = S_MBUFDATA;
+
+ SET_REG(0x00);
+
+ while(sendlen--) /* write data */
+ {
+ if (!len--) break;
+ DISBUSY(WRITE_DATA_1(*src++), goto a0);
+ }
+
+ cmd |= 0x08;
+
+ if (!++sendlen) /* suspend */
+ {
+ S_MBUFLEN = len;
+ S_MBUFDATA = src;
+ }
+ else
+ {
+ a0:
+ i4b_Dfreembuf(S_MBUF);
+ S_MBUF = NULL;
+
+ cmd |= 0x02;
+ }
+
+ if (cmd) ihfc_cmdr_hdlr(sc, cmd);
+
+ S_ISTA &= ~0x10;
+ j0:
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for D channel(read) - chan 1 (HFC-1)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_isac_Dread (ihfc_sc_t *sc, u_char chan)
+{
+ register u_char cmd = 0;
+ register u_char reclen;
+ register u_short tmp;
+ register u_short len;
+ register u_char * dst;
+
+ BUS_VAR;
+
+ if (!(S_ISTA & 0xc0)) goto j1; /* only receive data *
+ * on interrupt */
+
+ if (!S_MBUF)
+ {
+ if (!(S_MBUF = i4b_Dgetmbuf(DCH_MAX_LEN)))
+ panic("ihfc%d: (D) Out of mbufs!\n", S_UNIT);
+ }
+
+ len = S_MBUFLEN;
+ dst = S_MBUFDATA + (DCH_MAX_LEN - len);
+
+ if (S_ISTA & 0x80) /* RME */
+ {
+ SET_REG(0x27); DISBUSY(tmp = (READ_DATA_1 ^ 0x20), goto j0);
+
+ if (tmp & 0x70) goto j0; /* error */
+
+ SET_REG(0x25); DISBUSY(tmp = (READ_DATA_1 & 0x1f), goto j0);
+
+ reclen = (tmp) ? tmp : 32;
+ }
+ else /* RPF */
+ {
+ reclen = 32;
+ }
+
+ if ((len -= reclen) <= DCH_MAX_LEN) /* get data */
+ {
+ SET_REG(0x00);
+
+ while(reclen--)
+ {
+ DISBUSY(*dst++ = READ_DATA_1, goto j0);
+ }
+ }
+ else /* soft rdo or error */
+ {
+ j0: i4b_Dfreembuf(S_MBUF);
+ S_MBUF = NULL;
+
+ cmd |= 0x40;
+
+ NDBGL1(L1_I_ERR, "Frame error (unit=%d)", S_UNIT);
+ }
+
+ if (S_ISTA & 0x80) /* frame complete */
+ {
+ if (S_MBUF)
+ {
+ S_MBUFLEN = (DCH_MAX_LEN - len);
+ ihfc_putmbuf(sc, chan, S_MBUF);
+ S_MBUF = NULL;
+ }
+ }
+
+ if (S_MBUF) /* suspend */
+ {
+ S_MBUFLEN = len;
+ }
+
+ ihfc_cmdr_hdlr(sc, cmd | 0x80);
+
+ S_ISTA &= ~0xc0;
+ j1:
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for B channel(write) - chan 2 and 4 (HFC-1/S/SP)
+ *
+ * NOTE: No XDU checking!
+ *---------------------------------------------------------------------------*/
+void
+ihfc_trans_Bwrite (ihfc_sc_t *sc, u_char chan)
+{
+ register u_short sendlen;
+ register u_short len;
+ register u_char * src;
+
+ BUS_VAR;
+
+ if (!S_MBUF && IF_QEMPTY(&S_IFQUEUE)) return;
+
+ sendlen = (u_short)ihfc_Bsel_fifo(sc, chan, 0);
+
+ SET_REG(0xaa + chan);
+
+ while (1)
+ {
+ if (!S_MBUF)
+ {
+ S_MBUF = ihfc_getmbuf(sc, chan);
+ if (!S_MBUF) break;
+ }
+
+ src = S_MBUFDATA;
+ len = S_MBUFLEN;
+
+ while (sendlen--)
+ {
+ if (!len--) break;
+
+ DISBUSY(WRITE_DATA_1(*src++), sendlen = -1; len++; break);
+ }
+
+ if (!++sendlen) /* out of fifo: Suspend */
+ {
+ S_MBUFDATA = src;
+ S_MBUFLEN = len;
+ break;
+ }
+
+ i4b_Dfreembuf(S_MBUF);
+ S_MBUF = NULL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for B channel(read) - chan 3 and 5 (HFC-1/S/SP)
+ * (this code is optimized)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_trans_Bread (ihfc_sc_t *sc, u_char chan)
+{
+ register u_short reclen;
+ register u_short tmp;
+ register u_short len;
+ register u_char * dst;
+
+ BUS_VAR;
+
+ reclen = (u_short)ihfc_Bsel_fifo(sc, chan, 0);
+
+ while (1)
+ {
+ SET_REG(0xba + chan);
+
+ tmp = 0x100;
+
+ if (!S_MBUF)
+ if (!(S_MBUF = i4b_Bgetmbuf(BCH_MAX_DATALEN)))
+ panic("ihfc%d: (B) Out of mbufs!\n", S_UNIT);
+
+ len = S_MBUFLEN;
+ dst = S_MBUFDATA + (BCH_MAX_DATALEN - len);
+
+ while (reclen--)
+ {
+ if (!len--) break;
+
+ if (tmp & 0x100) DISBUSY( , reclen = -1; len++; break);
+ *dst++ = (u_char)(tmp = READ_BOTH_2);
+ }
+
+ if (~tmp & 0x100)
+ {
+ SET_REG(0x30);
+ READ_DATA_1; /* a read to the data port *
+ * will disable the internal *
+ * disbusy signal for HFC-1/S *
+ * chips. This is neccessary *
+ * to avvoid data loss. */
+ }
+
+ if (!++reclen) /* out of fifo: suspend */
+ {
+ S_MBUFLEN = len;
+ break;
+ }
+
+ S_MBUFLEN = (BCH_MAX_DATALEN - ++len);
+
+ ihfc_putmbuf(sc, chan, S_MBUF);
+
+ S_MBUF = NULL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for B channel(write) - chan 2 and 4 (HFC-1/S/SP)
+ *
+ * NOTE: Software HDLC encoding!
+ *---------------------------------------------------------------------------*/
+void
+ihfc_hdlc_Bwrite (ihfc_sc_t *sc, u_char chan)
+{
+ register u_short blevel = S_HDLC_BLEVEL;
+ register u_char flag = S_HDLC_FLAG;
+ register u_int tmp = S_HDLC_TMP;
+ register u_short crc = S_HDLC_CRC;
+ register u_short ib = S_HDLC_IB;
+ register u_char * src = NULL;
+ register u_short len = 0;
+ register u_short sendlen;
+ register u_short tmp2;
+
+ BUS_VAR;
+
+ if (!S_MBUF && IF_QEMPTY(&S_IFQUEUE) && (flag == 2)) return;
+
+ sendlen = (u_short)ihfc_Bsel_fifo(sc, chan, 0);
+
+ SET_REG(0xaa + chan);
+
+ if (S_MBUF)
+ {
+ /* resume */
+
+ src = S_MBUFDATA;
+ len = S_MBUFLEN;
+
+ if (sendlen == 0x5ff)
+ {
+ /* XDU */
+
+ flag = -1;
+ len = 0;
+
+ NDBGL1(L1_S_ERR, "XDU (unit=%d)", S_UNIT);
+ }
+ }
+
+ while (sendlen--)
+ {
+ HDLC_ENCODE(*src++, len, tmp, tmp2, blevel, ib, crc, flag,
+ {/* gfr */
+ i4b_Bfreembuf(S_MBUF);
+ S_MBUF = ihfc_getmbuf(sc, chan);
+
+ if (!S_MBUF) goto d0;
+
+ src = S_MBUFDATA;
+ len = S_MBUFLEN;
+ },
+ {/* wrd */
+
+ DISBUSY(WRITE_DATA_1((u_char)tmp), sendlen = 0);
+ },
+ d );
+ }
+
+ if (S_MBUF) /* suspend */
+ {
+ S_MBUFDATA = src;
+ S_MBUFLEN = len;
+ }
+
+ d0:
+ S_HDLC_IB = ib;
+ S_HDLC_BLEVEL = blevel;
+ S_HDLC_TMP = tmp;
+ S_HDLC_FLAG = flag;
+ S_HDLC_CRC = crc;
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for B channel(read) - chan 3 and 5 (HFC-1/S/SP)
+ *
+ * NOTE: Software HDLC decoding!
+ *---------------------------------------------------------------------------*/
+void
+ihfc_hdlc_Bread (ihfc_sc_t *sc, u_char chan)
+{
+ register u_char blevel = S_HDLC_BLEVEL;
+ u_char flag = S_HDLC_FLAG;
+ register u_short crc = S_HDLC_CRC;
+ register u_int tmp = S_HDLC_TMP;
+ register u_short ib = S_HDLC_IB;
+ register u_char * dst = NULL;
+ register u_short tmp2 = 0x100;
+ register u_short len = 0;
+ register u_short reclen;
+
+ BUS_VAR;
+
+ if (S_MBUF)
+ {
+ /* resume */
+
+ len = S_MBUFLEN;
+ dst = S_MBUFDATA + (BCH_MAX_DATALEN - len);
+ }
+
+ reclen = (u_short)ihfc_Bsel_fifo(sc, chan, 0);
+
+ SET_REG(0xba + chan);
+
+ while (reclen--)
+ {
+ HDLC_DECODE(*dst++, len, tmp, tmp2, blevel, ib, crc, flag,
+ {/* rdd */
+ /* if (tmp2 & 0x100) while (GET_STAT & 1);
+ * tmp2 = READ_BOTH_2;
+ */
+
+ DISBUSY(tmp2 = READ_DATA_1, reclen = 0; tmp2 = 0);
+ },
+ {/* nfr */
+ if (!(S_MBUF = i4b_Bgetmbuf(BCH_MAX_DATALEN)))
+ panic("ihfc:(B) Out of mbufs!\n");
+
+ dst = S_MBUFDATA;
+ len = BCH_MAX_DATALEN;
+ },
+ {/* cfr */
+ len = (BCH_MAX_DATALEN - len);
+
+ if ((!len) || (len > BCH_MAX_DATALEN))
+ {
+ /* NOTE: frames without any data, *
+ * only crc field, should be silently discared. */
+
+ i4b_Bfreembuf(S_MBUF);
+ NDBGL1(L1_S_MSG, "Bad frame (len=%d, unit=%d)", len, S_UNIT);
+ goto s0;
+ }
+
+ if (crc)
+ { i4b_Bfreembuf(S_MBUF);
+ NDBGL1(L1_S_ERR, "CRC (crc=0x%04x, len=%d, unit=%d)", crc, len, S_UNIT);
+ goto s0;
+ }
+
+ S_MBUFLEN = len;
+
+ ihfc_putmbuf(sc, chan, S_MBUF);
+ s0:
+ S_MBUF = NULL;
+ },
+ {/* rab */
+ i4b_Bfreembuf(S_MBUF);
+ S_MBUF = NULL;
+
+ NDBGL1(L1_S_MSG, "Read Abort (unit=%d)", S_UNIT);
+ },
+ {/* rdo */
+ i4b_Bfreembuf(S_MBUF);
+ S_MBUF = NULL;
+
+ NDBGL1(L1_S_ERR, "RDO (unit=%d)", S_UNIT);
+ },
+ continue,
+ d);
+ }
+
+ /* SET_REG(0x30);
+ * if (~tmp2 & 0x100) READ_DATA_1; kill disbusy signal
+ */
+
+ if (S_MBUF) S_MBUFLEN = len; /* suspend */
+
+ S_HDLC_IB = ib;
+ S_HDLC_CRC = crc;
+ S_HDLC_TMP = tmp;
+ S_HDLC_FLAG = flag;
+ S_HDLC_BLEVEL = blevel;
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for B channel(write) - chan 2 and 4 (HFC-1/S/SP)
+ *
+ * This filter generates a pattern which is recognized
+ * and examinated and verified by ihfc_test_Bread.
+ *
+ * NOTE: This filter is only for testing purpose.
+ *---------------------------------------------------------------------------*/
+void
+ihfc_test_Bwrite (ihfc_sc_t *sc, u_char chan)
+{
+ struct mbuf *m;
+
+ register u_char fb;
+ register u_short sendlen, tlen;
+ register u_short xlen = S_HDLC_IB;
+ BUS_VAR;
+
+ goto j0;
+
+ while((m = ihfc_getmbuf(sc, chan))) /* internal loop */
+ {
+ if (chan == 2)
+ ihfc_putmbuf(sc, 5, m);
+ else
+ ihfc_putmbuf(sc, 3, m);
+ }
+
+ j0:
+
+ sendlen = (u_short)ihfc_Bsel_fifo(sc, chan, 0);
+
+ if (sendlen == 0x5ff) printf("(send empty)");
+
+ SET_REG(0xaa + chan);
+
+ S_BYTES += sendlen;
+
+ tlen = S_HDLC_CRC;
+
+ if (sendlen > 0x400) printf("(slow: %d)", sendlen);
+
+ fb = 0x80;
+
+ while (sendlen--)
+ {
+ if (!tlen--) fb |= 0x20;
+
+ if (!xlen--)
+ {
+ while(GET_STAT & 1);
+ WRITE_DATA_1(0x3e);
+ xlen = 200;
+ }
+ else
+ {
+ while(GET_STAT & 1);
+ WRITE_DATA_1((xlen + 1) & 0xef);
+ }
+
+ fb = 0;
+ }
+
+ S_HDLC_IB = xlen;
+}
+
+/*---------------------------------------------------------------------------*
+ * Data handler for B channel(read) - chan 3 and 5 (HFC-1/S/SP)
+ *
+ * This filter examins and verifies the pattern
+ * generated by ihfc_test_Bwrite.
+ *
+ * NOTE: This filter is only for testing purpose.
+ *---------------------------------------------------------------------------*/
+void
+ihfc_test_Bread (ihfc_sc_t *sc, u_char chan)
+{
+ static u_short toterrors = 0;
+
+ register u_short reclen, len, tlen;
+ register u_char fb, tmp;
+
+ register u_short xlen = S_HDLC_IB;
+ register u_char *dst = NULL;
+ register u_char error = S_HDLC_TMP;
+ register u_char ecount = S_HDLC_FLAG;
+
+ BUS_VAR;
+
+ if (S_UNIT != 0) return;
+
+ reclen = (u_short)ihfc_Bsel_fifo(sc, chan, 0);
+
+ S_BYTES += reclen;
+
+ tlen = S_HDLC_CRC;
+
+ fb = 0x40;
+
+ if (S_MBUF)
+ {
+ len = S_MBUFLEN;
+ dst = S_MBUFDATA + (BCH_MAX_DATALEN - len);
+ }
+ else
+ {
+ len = 0;
+ }
+
+ SET_REG(0xba + chan);
+
+ while (reclen--)
+ {
+/* if (tmp2 & 0x100) while(GET_STAT & 1);
+ * tmp = (u_char)(tmp2 = READ_BOTH_2);
+ */
+ if (GET_STAT & 1)
+ {
+ /* if (!(++busy % 4)) reclen++; */
+ while(GET_STAT & 1);
+ }
+
+ tmp = READ_DATA_1;
+
+ if ((tmp & 0x3f) == 0x3e)
+ {
+ if ((BCH_MAX_DATALEN - len) != 201) error |= 4;
+
+ if ((S_MBUF) && (error))
+ {
+ if (len) { len--; *dst++ = error; }
+ if (len) { len--; *dst++ = xlen+1; }
+ if (len) { len--; *dst++ = ecount; }
+
+ S_MBUFLEN = BCH_MAX_DATALEN - len;
+
+ if (S_TRACE & TRACE_B_RX)
+ ihfc_putmbuf(sc, chan, S_MBUF);
+ else
+ i4b_Bfreembuf(S_MBUF);
+
+ S_MBUF = NULL;
+ printf("(error%d, %d, %d)", S_UNIT, ecount, toterrors++);
+ }
+
+ i4b_Bfreembuf(S_MBUF);
+ S_MBUF = i4b_Bgetmbuf(BCH_MAX_DATALEN);
+
+ dst = S_MBUFDATA;
+ len = BCH_MAX_DATALEN;
+
+ xlen = 200;
+ error = 0;
+ ecount = 0;
+
+ /* SET_REG(0xba + chan); */
+ }
+ else
+ {
+ if (!xlen) error |= 2;
+ if ((tmp ^ xlen--) & 0xef) { error |= 1; ecount++; }
+ }
+ if (!tlen--) fb |= 0x20;
+
+ if (len--)
+ {
+ *dst++ = (tmp | fb);
+ }
+ else
+ {
+ len++;
+ }
+
+ fb = 0;
+ }
+
+ if (S_MBUF)
+ {
+ S_MBUFLEN = len;
+ }
+
+ S_HDLC_IB = xlen;
+ S_HDLC_TMP = error;
+ S_HDLC_FLAG = ecount;
+}
+
+#endif /* NIHFC > 0 */
diff --git a/sys/i4b/layer1/ihfc/i4b_ihfc_drv.h b/sys/i4b/layer1/ihfc/i4b_ihfc_drv.h
new file mode 100644
index 0000000..d0456ad
--- /dev/null
+++ b/sys/i4b/layer1/ihfc/i4b_ihfc_drv.h
@@ -0,0 +1,230 @@
+/*
+ * 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_ihfc_drv.h - include file for the HFC-1/S/SP driver
+ * -------------------------------------------------------
+ *
+ * last edit-date: [Wed Jul 19 09:40:55 2000]
+ *
+ * $Id: i4b_ihfc_drv.h,v 1.7 2000/09/19 13:50:36 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+#ifndef I4B_IHFC_DRV_H_
+#define I4B_IHFC_DRV_H_
+
+/*---------------------------------------------------------------------------*
+ * Ramptables related fifo (HFC-1/S/SP)
+ *
+ * The HFC-SP chip only uses ihfc_xxx[2] values for D-channel!
+ * NOTE: These tables are not used anymore.
+ *---------------------------------------------------------------------------*
+ *
+ * w - write, r - read: D1_w D1_r B1_w B1_r B2_w B2_r
+ * const u_char ihfc_readtable[6] = {0xa6, 0xa7, 0xbc, 0xbd, 0xbe, 0xbf};
+ * const u_char ihfc_writetable[6] = {0x96, 0x97, 0xac, 0xad, 0xae, 0xaf};
+ * const u_char ihfc_f1inctable[6] = {0x92, 0x93, 0xa8, 0xa9, 0xaa, 0xab};
+ * const u_char ihfc_f2inctable[6] = {0xa2, 0xa3, 0xb8, 0xb9, 0xba, 0xbb};
+ *
+ * const struct { u_char z1L, z1H, z2L, z2H, f1, f2, dummy; }
+ * ihfc_countertable[6] = {
+ * {0x90, 0x94, 0x98, 0x9c, 0x9a, 0x9e, 0x00}, D1_w
+ * {0x91, 0x95, 0x99, 0x9d, 0x9b, 0x9f, 0x00}, D1_r
+ * {0x80, 0x84, 0x88, 0x8c, 0xb0, 0xb4, 0x00}, B1_w
+ * {0x81, 0x85, 0x89, 0x8d, 0xb1, 0xb5, 0x00}, B1_r
+ * {0x82, 0x86, 0x8a, 0x8e, 0xb2, 0xb6, 0x00}, B2_w
+ * {0x83, 0x87, 0x8b, 0x8f, 0xb3, 0xb7, 0x00} B2_r
+ * };
+ *---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*
+ * Ramptables related to configuration (HFC-1/S/SP)
+ *
+ * NOTE: Write registers only
+ *---------------------------------------------------------------------------*/
+const u_char ihfc_configtable[11] =
+{
+ 0x18, 0x19, 0x1a, /* cirm, ctmt, int_m1 */
+ 0x1b, 0x2e, 0x37, /* int_m2, mst_mode, clkdel */
+ 0x31, 0x2f, 0x32, /* sctrl, connect, test/sctrl_e */
+ 0x33, 0x00 /* sctrl_r */
+};
+const u_char isac_configtable[9] =
+{
+ 0x39, 0x30, 0x3b, /* adf2, spcr, sqxr */
+ 0x38, 0x37, 0x22, /* adf1, stcr, mode */
+ 0x20, 0x2b, 0x00 /* mask, star2 */
+};
+
+/*---------------------------------------------------------------------------*
+ * Ramptables related to statemachine (HFC-1/S/SP)
+ *
+ * state:
+ * 0 = deactivated
+ * 1 = pending
+ * 2 = syncronized
+ * 3 = activated
+ * 4 = error
+ * 5 = reset
+ * -1 = illegal
+ *---------------------------------------------------------------------------*/
+
+const struct ihfc_FSMtable { u_char state, *string; }
+
+ ihfc_TEtable[16] = /* HFC-S/SP - TE */
+{
+ { 0x05 ,"Reset" },
+ { 0xff , 0 },
+ { 0x01 ,"Sensing" },
+ { 0x00 ,"Deactivated" },
+ { 0x01 ,"Awaiting signal" },
+ { 0x01 ,"Identifying input" },
+ { 0x02 ,"Syncronized" },
+ { 0x03 ,"Activated" },
+ { 0x04 ,"Lost framing" },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 }
+},
+ ihfc_NTtable[16] = /* HFC-S/SP - NT */
+{
+ { 0x05 ,"Reset" },
+ { 0x00 ,"Deactive" },
+ { 0x02 ,"Pending activation" },
+ { 0x03 ,"Active" },
+ { 0x01 ,"Pending deactivation" },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 }
+},
+ ihfc_TEtable2[16] = /* HFC-1/ISAC - TE */
+{
+ { 0x00 ,"Deactivate request" },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0xff , 0 },
+ { 0x01 ,"Level detected" },
+ { 0xff , 0 },
+ { 0x04 ,"Error indication" },
+ { 0x00 ,"Power-up" },
+ { 0x02 ,"Activate request downstream" },
+ { 0xff , 0 },
+ { 0x00 ,"Test indication" },
+ { 0x00 ,"Awake test indication" },
+ { 0x03 ,"Activate ind. with priority class 8" },
+ { 0x03 ,"Activate ind. with priority class 10" },
+ { 0xff , 0 },
+ { 0x00 ,"Deactivate indication downstream" }
+};
+
+/*---------------------------------------------------------------------------*
+ * Ramptable related to ISAC EXIR (HFC-1)
+ *
+ * cmd: command to execute, if any.
+ *
+ *---------------------------------------------------------------------------*/
+const struct ihfc_EXIRtable { u_char cmd, *string; }
+
+ ihfc_EXIRtable[8] =
+{
+ { 0x00 ,"Watchdog Timer Overflow" },
+ { 0x00 ,"Subscriber Awake" },
+ { 0x00 ,"Monitor Status" },
+ { 0x00 ,"Rx Sync Xfer Overflow" },
+ { 0xc0 ,"Rx Frame Overflow" }, /* RMC + RRES */
+ { 0x00 ,"Protocol Error" },
+ { 0x01 ,"Tx Data Underrun" }, /* XRES */
+ { 0x01 ,"Tx Message Repeat" }, /* XRES */
+};
+
+/*---------------------------------------------------------------------------*
+ * Ramptables related to S/Q - channel (HFC-1/S/SP)
+ *
+ * From TE's viewpoint:
+ * Q: commands to NT
+ * S: indications from NT
+ *
+ * From NT's viewpoint:
+ * Q: indications from TE
+ * S: commands to TE
+ *
+ * cmd: not used
+ *---------------------------------------------------------------------------*/
+const struct ihfc_SQtable { u_char cmd, *string; }
+
+ ihfc_Qtable[16] =
+{
+ { 0x00, "Loss of Power indication" },
+ { 0x00, "ST request" },
+ { 0x00, 0 },
+ { 0x00, "LoopBack request (B1/B2)" },
+ { 0x00, 0 },
+ { 0x00, 0 },
+ { 0x00, 0 },
+ { 0x00, "LoopBack request (B1)" },
+ { 0x00, 0 },
+ { 0x00, 0 },
+ { 0x00, 0 },
+ { 0x00, "LoopBack request (B2)" },
+ { 0x00, "V-DCE slave mode" },
+ { 0x00, "V-DTE slave mode" },
+ { 0x00, 0 },
+ { 0x00, "Idle" }
+},
+ ihfc_Stable[16] =
+{
+ { 0x00, "Idle" },
+ { 0x00, "ST Fail" },
+ { 0x00, "ST Pass" },
+ { 0x00, "Disruptive Operation Indication" },
+ { 0x00, "DTSE-OUT" },
+ { 0x00, "V-DCE master mode" },
+ { 0x00, "ST Indication" },
+ { 0x00, "DTSE-IN" },
+ { 0x00, "LoopBack indication (B1/B2)" },
+ { 0x00, "Loss of Received Signal indication" },
+ { 0x00, "LoopBack indication (B2)" },
+ { 0x00, "DTSE-IN and OUT" },
+ { 0x00, "LoopBack indication (B1)" },
+ { 0x00, "Loss of power indication" }
+};
+
+
+#endif /* I4B_IHFC_DRV_H_ */
+
diff --git a/sys/i4b/layer1/ihfc/i4b_ihfc_ext.h b/sys/i4b/layer1/ihfc/i4b_ihfc_ext.h
new file mode 100644
index 0000000..0d1ee44
--- /dev/null
+++ b/sys/i4b/layer1/ihfc/i4b_ihfc_ext.h
@@ -0,0 +1,62 @@
+/*
+ * 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_ihfc_ext.h - ihfc common prototypes
+ * ---------------------------------------
+ *
+ * last edit-date: [Wed Jul 19 09:40:59 2000]
+ *
+ * $Id: i4b_ihfc_ext.h,v 1.6 2000/08/20 07:14:08 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef I4B_IHFC_EXT_H_
+#define I4B_IHFC_EXT_H_
+
+#include <i4b/include/i4b_l3l4.h>
+
+
+/* prototypes from i4b_ihfc_l1if.c */
+
+extern struct i4b_l1mux_func ihfc_l1mux_func;
+
+void ihfc_B_linkinit (ihfc_sc_t *sc);
+struct mbuf * ihfc_getmbuf (ihfc_sc_t *sc, u_char chan);
+void ihfc_putmbuf (ihfc_sc_t *sc, u_char chan, struct mbuf *m);
+
+
+/* prototypes from i4b_ihfc_drv.c */
+
+void ihfc_intr1 (ihfc_sc_t *sc);
+void ihfc_intr2 (ihfc_sc_t *sc);
+
+int ihfc_control (ihfc_sc_t *sc, int flag);
+void ihfc_fsm (ihfc_sc_t *sc, int flag);
+int ihfc_init (ihfc_sc_t *sc, u_char chan, int prot, int activate);
+
+#endif /* I4B_IHFC_EXT_H_ */
diff --git a/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c b/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c
new file mode 100644
index 0000000..4f9f4e9
--- /dev/null
+++ b/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c
@@ -0,0 +1,517 @@
+/*
+ * 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_ihfc_l1.c - hfc layer 1 handler
+ * -----------------------------------
+ *
+ * The idea of this file is to seperate hfcs/sp/pci data/signal
+ * handling and the I4B data/signal handling.
+ *
+ * Everything which has got anything to do with I4B has been put here!
+ *
+ * last edit-date: [Wed Jul 19 09:41:03 2000]
+ *
+ * $Id: i4b_ihfc_l1if.c,v 1.10 2000/09/19 13:50:36 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "ihfc.h"
+
+#if (NIHFC > 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/include/i4b_mbuf.h>
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_l1l2.h>
+
+#include <i4b/layer1/i4b_l1.h>
+#include <i4b/layer1/ihfc/i4b_ihfc.h>
+#include <i4b/layer1/ihfc/i4b_ihfc_ext.h>
+
+/*---------------------------------------------------------------------------*
+ * Local prototypes
+ *
+ * NOTE: The prototypes for get/putmbuf and B_linkinit
+ * have been put in i4b_hfc_ext.h for global hfc use.
+ *
+ * NOTE: channel != chan
+ *---------------------------------------------------------------------------*/
+static
+isdn_link_t * ihfc_B_ret_linktab (int unit, int channel);
+static void ihfc_B_set_linktab (int unit, int channel, drvr_link_t *B_linktab);
+
+static void ihfc_B_start (int unit, int chan);
+static void ihfc_B_stat (int unit, int chan, bchan_statistics_t *bsp);
+ void ihfc_B_setup (int unit, int chan, int bprot, int activate);
+
+static int ihfc_mph_command_req (int unit, int command, void *parm);
+
+static int ihfc_ph_activate_req (int unit);
+static int ihfc_ph_data_req (int unit, struct mbuf *m, int freeflag);
+
+static void ihfc_T3_expired (ihfc_sc_t *sc);
+
+/*---------------------------------------------------------------------------*
+ * Our I4B L1 mulitplexer link
+ *---------------------------------------------------------------------------*/
+struct i4b_l1mux_func ihfc_l1mux_func = {
+ ihfc_B_ret_linktab,
+ ihfc_B_set_linktab,
+ ihfc_mph_command_req,
+ ihfc_ph_data_req,
+ ihfc_ph_activate_req,
+};
+
+/*---------------------------------------------------------------------------*
+ * L2 -> L1: PH-DATA-REQUEST (D-Channel)
+ *
+ * NOTE: We may get called here from ihfc_hdlc_Dread or isac_hdlc_Dread
+ * via the upper layers.
+ *---------------------------------------------------------------------------*/
+int
+ihfc_ph_data_req(int unit, struct mbuf *m, int freeflag)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+ u_char chan = 0;
+ HFC_VAR;
+
+ if (!m) return 0;
+
+ HFC_BEG;
+
+ if(S_PHSTATE != 3)
+ {
+ NDBGL1(L1_PRIM, "L1 was not running: "
+ "ihfc_ph_activate_req(unit = %d)!", unit);
+
+ ihfc_ph_activate_req(unit);
+ }
+
+ /* "Allow" I-frames (-hp) */
+
+ if (freeflag == MBUF_DONTFREE) m = m_copypacket(m, M_DONTWAIT);
+
+ if (!IF_QFULL(&S_IFQUEUE) && m)
+ {
+ IF_ENQUEUE(&S_IFQUEUE, m);
+
+ ihfc_B_start(unit, chan); /* (recycling) */
+ }
+ else
+ {
+ NDBGL1(L1_ERROR, "No frame out (unit = %d)", unit);
+ i4b_Dfreembuf(m);
+ }
+
+ if (S_INTR_ACTIVE) S_INT_S1 |= 0x04;
+
+ HFC_END;
+
+ return 1;
+}
+
+/*---------------------------------------------------------------------------*
+ * L2 -> L1: PH-ACTIVATE-REQUEST (B-channel and D-channel)
+ *---------------------------------------------------------------------------*/
+int
+ihfc_ph_activate_req(int unit)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+ HFC_VAR;
+
+ HFC_BEG;
+
+ if ((!S_STM_T3) && (S_PHSTATE != 3))
+ {
+ HFC_FSM(sc, 1);
+
+ S_STM_T3 = 1;
+ S_STM_T3CALLOUT = timeout((TIMEOUT_FUNC_T)
+ ihfc_T3_expired, (ihfc_sc_t *)sc,
+ IHFC_ACTIVATION_TIMEOUT);
+ }
+
+ HFC_END;
+ return 0;
+}
+/*---------------------------------------------------------------------------*
+ * T3 timeout - persistant deactivation
+ *---------------------------------------------------------------------------*/
+void
+ihfc_T3_expired(ihfc_sc_t *sc)
+{
+ u_char chan = 0;
+ HFC_VAR;
+
+ HFC_BEG;
+
+ S_STM_T3 = 0;
+
+ if (S_PHSTATE != 3) /* line was not activated */
+ {
+ i4b_Dcleanifq(&S_IFQUEUE);
+ i4b_l1_ph_deactivate_ind(S_I4BUNIT);
+
+ i4b_l1_mph_status_ind(S_I4BUNIT, STI_PDEACT, 0, 0);
+
+ HFC_FSM(sc, 2); /* L1 deactivate */
+ }
+
+ HFC_END;
+}
+
+/*---------------------------------------------------------------------------*
+ * Command from the upper layers (B-channel and D-channel)
+ *---------------------------------------------------------------------------*/
+int
+ihfc_mph_command_req(int unit, int command, void *parm)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+
+ switch(command)
+ {
+ case CMR_DOPEN: /* daemon running */
+ NDBGL1(L1_PRIM,
+ "unit %d, command = CMR_DOPEN", unit);
+ S_ENABLED = 1;
+ break;
+
+ case CMR_DCLOSE: /* daemon not running */
+ NDBGL1(L1_PRIM,
+ "unit %d, command = CMR_DCLOSE", unit);
+ S_ENABLED = 0;
+ break;
+
+ case CMR_SETTRACE: /* set new trace mask */
+ NDBGL1(L1_PRIM,
+ "unit %d, command = CMR_SETTRACE, parm = %d",
+ unit, (unsigned int)parm);
+ S_TRACE = (unsigned int)parm;
+ break;
+
+ case CMR_GCST: /* get chip statistic */
+ NDBGL1(L1_PRIM,
+ "unit %d, command = CMR_GCST, parm = %d",
+ unit, (unsigned int)parm);
+
+ #define CST ((struct chipstat *)parm)
+
+ CST->driver_type = L1DRVR_IHFC;
+
+ /* XXX CST->xxxx_stat = xxx; */
+
+ #undef CST
+ break;
+
+ default:
+ NDBGL1(L1_ERROR,
+ "ERROR, unknown command = %d, unit = %d, parm = %d",
+ command, unit, (unsigned int)parm);
+ break;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * Data source switch for Read channels - 1, 3 and 5 (B and D-Channel)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_putmbuf (ihfc_sc_t *sc, u_char chan, struct mbuf *m)
+{
+ i4b_trace_hdr_t hdr;
+
+ if (chan < 2)
+ {
+ if(S_TRACE & TRACE_D_RX)
+ {
+ hdr.count = ++S_DTRACECOUNT;
+ hdr.dir = FROM_NT;
+ hdr.type = TRC_CH_D;
+ hdr.unit = S_I4BUNIT;
+
+ MICROTIME(hdr.time);
+
+ i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
+ }
+
+ if (!S_ENABLED) { i4b_Dfreembuf(m); return; }
+
+ m->m_pkthdr.len = m->m_len;
+
+ i4b_l1_ph_data_ind(S_I4BUNIT, m);
+ }
+ else
+ {
+ if(S_TRACE & TRACE_B_RX)
+ {
+ hdr.count = ++S_BTRACECOUNT;
+ hdr.dir = FROM_NT;
+ hdr.type = (chan < 4) ? TRC_CH_B1 : TRC_CH_B2;
+ hdr.unit = S_I4BUNIT;
+
+ MICROTIME(hdr.time);
+
+ i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
+ }
+
+ if (!S_ENABLED) { i4b_Bfreembuf(m); return; }
+
+ if (S_PROT == BPROT_NONE)
+ {
+ if(!i4b_l1_bchan_tel_silence(m->m_data, m->m_len))
+ {
+ S_BDRVLINK->bch_activity(S_BDRVLINK->unit, ACT_RX);
+ }
+
+ if (!IF_QFULL(&S_IFQUEUE))
+ {
+ S_BYTES += m->m_len;
+ IF_ENQUEUE(&S_IFQUEUE, m);
+ S_BDRVLINK->bch_rx_data_ready(S_BDRVLINK->unit);
+ }
+
+ return;
+ }
+
+ if (S_PROT == BPROT_RHDLC)
+ {
+ S_MBUFDUMMY = m;
+ S_BYTES += m->m_pkthdr.len = m->m_len;
+ S_BDRVLINK->bch_rx_data_ready(S_BDRVLINK->unit);
+ S_MBUFDUMMY = NULL;
+
+ return;
+ }
+
+ NDBGL1(L1_ERROR, "Unknown protocol: %d", S_PROT);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * Data destinator switch for write channels - 0, 2 and 4
+ *---------------------------------------------------------------------------*/
+struct mbuf *
+ihfc_getmbuf (ihfc_sc_t *sc, u_char chan)
+{
+ register struct mbuf *m;
+ i4b_trace_hdr_t hdr;
+
+ if (chan < 2)
+ {
+ IF_DEQUEUE(&S_IFQUEUE, m);
+
+ if((S_TRACE & TRACE_D_TX) && m)
+ {
+ hdr.count = ++S_DTRACECOUNT;
+ hdr.dir = FROM_TE;
+ hdr.type = TRC_CH_D;
+ hdr.unit = S_I4BUNIT;
+
+ MICROTIME(hdr.time);
+
+ i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
+ }
+ }
+ else
+ {
+ IF_DEQUEUE(&S_IFQUEUE, m);
+
+ if (!m)
+ {
+ S_BDRVLINK->bch_tx_queue_empty(S_BDRVLINK->unit);
+
+ IF_DEQUEUE(&S_IFQUEUE, m);
+ }
+ if (m)
+ {
+ if(!i4b_l1_bchan_tel_silence(m->m_data, m->m_len))
+ {
+ S_BDRVLINK->bch_activity(S_BDRVLINK->unit, ACT_TX);
+ }
+
+ S_BYTES += m->m_len;
+
+ if(S_TRACE & TRACE_B_TX)
+ {
+ hdr.count = ++S_BTRACECOUNT;
+ hdr.dir = FROM_TE;
+ hdr.type = (chan < 4) ? TRC_CH_B1 : TRC_CH_B2;
+ hdr.unit = S_I4BUNIT;
+
+ MICROTIME(hdr.time);
+
+ i4b_l1_trace_ind(&hdr, m->m_len, m->m_data);
+ }
+ }
+ }
+
+ return(m);
+}
+
+/*---------------------------------------------------------------------------*
+ * Initialize rx/tx data structures (B-channel)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_B_setup(int unit, int chan, int bprot, int activate)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+ HFC_VAR;
+
+ if (((u_int)chan > 5) || ((u_int)chan < 2)) return;
+
+ HFC_BEG;
+
+ HFC_INIT(sc, chan, bprot, activate);
+
+ HFC_END;
+}
+
+/*---------------------------------------------------------------------------*
+ * Start transmission (B-channel or D-channel tx)
+ * NOTE: if "chan" variable is corrupted, it will not cause any harm,
+ * but data may be lost and there may be software sync. errors.
+ *---------------------------------------------------------------------------*/
+void
+ihfc_B_start(int unit, int chan)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+ HFC_VAR;
+
+ if ((u_int)chan > 5) return;
+
+ HFC_BEG;
+
+ if (S_FILTER && !S_MBUF && !S_INTR_ACTIVE)
+ {
+ S_INTR_ACTIVE |= 2; /* never know what *
+ * they put in the *
+ * L2 code */
+
+ S_FILTER(sc, chan); /* quick tx */
+
+ S_INTR_ACTIVE &= ~2;
+ }
+
+ HFC_END;
+}
+
+/*---------------------------------------------------------------------------*
+ * Fill statistics struct (B-channel)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_B_stat(int unit, int chan, bchan_statistics_t *bsp)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+ HFC_VAR;
+
+ if ((u_int)chan > 5) return;
+
+ chan &= ~1;
+
+ HFC_BEG;
+
+ bsp->inbytes = S_BYTES; S_BYTES = 0;
+
+ chan++;
+
+ bsp->outbytes = S_BYTES; S_BYTES = 0;
+
+ HFC_END;
+}
+
+/*---------------------------------------------------------------------------*
+ * Return the address of IHFC linktab to I4B (B-channel)
+ *---------------------------------------------------------------------------*/
+isdn_link_t *
+ihfc_B_ret_linktab(int unit, int channel)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+
+ if (channel < 2)
+ return(&sc->sc_blinktab[channel]);
+ else
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * Set the I4B driver linktab for IHFC use (B-channel)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_B_set_linktab(int unit, int channel, drvr_link_t *B_linktab)
+{
+ ihfc_sc_t *sc = &ihfc_softc[unit];
+
+ if (channel < 2)
+ sc->sc_bdrvlinktab[channel] = B_linktab;
+}
+
+/*---------------------------------------------------------------------------*
+ * Initialize linktab for I4B use (B-channel)
+ *---------------------------------------------------------------------------*/
+void
+ihfc_B_linkinit(ihfc_sc_t *sc)
+{
+ u_char chan;
+
+ /* make sure the hardware driver is known to layer 4 */
+ ctrl_types[CTRL_PASSIVE].set_linktab = i4b_l1_set_linktab;
+ ctrl_types[CTRL_PASSIVE].get_linktab = i4b_l1_ret_linktab;
+
+ for (chan = 2; chan < 6; chan++)
+ {
+ S_BLINK.unit = S_UNIT;
+ S_BLINK.channel = chan; /* point to tx-chan */
+ S_BLINK.bch_config = ihfc_B_setup;
+ S_BLINK.bch_tx_start = ihfc_B_start;
+ S_BLINK.bch_stat = ihfc_B_stat;
+
+ /* This is a transmit channel (even) */
+ S_BLINK.tx_queue = &S_IFQUEUE;
+ chan++;
+ /* This is a receive channel (odd) */
+ S_BLINK.rx_queue = &S_IFQUEUE;
+ S_BLINK.rx_mbuf = &S_MBUFDUMMY;
+ }
+}
+
+#endif /* NIHFC > 0 */
diff --git a/sys/i4b/layer1/ihfc/i4b_ihfc_pnp.c b/sys/i4b/layer1/ihfc/i4b_ihfc_pnp.c
new file mode 100644
index 0000000..f8fb9af
--- /dev/null
+++ b/sys/i4b/layer1/ihfc/i4b_ihfc_pnp.c
@@ -0,0 +1,421 @@
+/*
+ * 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_ihfc_pnp.c - common hfc ISA PnP-bus interface
+ * -------------------------------------------------
+ *
+ * - Everything which has got anything to to with "PnP" bus setup has
+ * been put here.
+ *
+ *
+ * last edit-date: [Wed Jul 19 09:41:07 2000]
+ *
+ * $Id: i4b_ihfc_pnp.c,v 1.9 2000/09/19 13:50:36 hm Exp $
+ *
+ * $FreeBSD$
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "ihfc.h"
+
+#if (NIHFC > 0)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <sys/mbuf.h>
+#include <machine/clock.h>
+
+#include <i4b/include/i4b_global.h>
+#include <i4b/include/i4b_mbuf.h>
+#include <i4b/include/i4b_l1l2.h>
+
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include <i4b/layer1/i4b_l1.h>
+#include <i4b/layer1/ihfc/i4b_ihfc.h>
+#include <i4b/layer1/ihfc/i4b_ihfc_ext.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <isa/isavar.h>
+
+/*---------------------------------------------------------------------------*
+ * Softc
+ *---------------------------------------------------------------------------*/
+ihfc_sc_t ihfc_softc[IHFC_MAXUNIT];
+
+/*---------------------------------------------------------------------------*
+ * Prototypes
+ *---------------------------------------------------------------------------*/
+static int ihfc_isa_probe (device_t dev);
+static int ihfc_pnp_probe (device_t dev);
+static int ihfc_pnp_attach (device_t dev);
+static int ihfc_pnp_detach (device_t dev, u_int flag);
+static int ihfc_pnp_shutdown (device_t dev);
+
+const struct ihfc_pnp_ids
+{
+ u_long vid; /* vendor id */
+ int flag; /* */
+ u_char hfc; /* chip type */
+ u_char iirq; /* internal irq */
+ u_short iio; /* internal io-address */
+ u_char stdel; /* S/T delay compensation */
+}
+ ihfc_pnp_ids[] =
+{
+ { 0x10262750, FLAG_TELES_S0_163C, HFC_S , 2, 0x200 , 0xd},
+ { 0x20262750, FLAG_TELES_S0_163C, HFC_SP, 0, 0x000 , 0xf},
+ { 0x1411d805, FLAG_ACER_P10 , HFC_S , 1, 0x300 , 0xe},
+ { 0 }
+};
+
+typedef const struct ihfc_pnp_ids ihfc_id_t;
+
+/*---------------------------------------------------------------------------*
+ * PCB layout
+ *
+ * IIRQx: Internal IRQ cross reference for a card
+ * IRQx : Supported IRQ's for a card
+ * IOx : Supported IO-bases for a card
+ *
+ * IO0, IRQ0, IIRQ0: TELEINT ISDN SPEED No. 1
+ * IIRQ3: Teles 16.3c PnP (B version)
+ *---------------------------------------------------------------------------*/
+ /* IRQ -> 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+#define IIRQ0 ((const u_char []){ 0, 0, 0, 1, 2, 3, 0, 4, 0, 0, 5, 6, 0, 0, 0, 0 })
+#define IRQ0 ((const u_char []){ 3, 4, 5, 7, 0xa, 0xb, 0 })
+
+#define IO0 ((const u_long []){ 0x300, 0x330, 0x278, 0x2e8, 0 })
+
+#define IIRQ3 ((const u_char []){ 0, 0, 0, 7, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 0, 6 })
+
+/*---------------------------------------------------------------------------*
+ * ISA PnP setup
+ *---------------------------------------------------------------------------*/
+static device_method_t ihfc_pnp_methods[] =
+{
+ DEVMETHOD(device_probe, ihfc_pnp_probe),
+ DEVMETHOD(device_attach, ihfc_pnp_attach),
+ DEVMETHOD(device_shutdown, ihfc_pnp_shutdown),
+ { 0, 0 }
+};
+
+static driver_t ihfc_pnp_driver =
+{
+ "ihfc",
+ ihfc_pnp_methods,
+ 0,
+};
+
+static devclass_t ihfc_devclass;
+
+DRIVER_MODULE(ihfcpnp, isa, ihfc_pnp_driver, ihfc_devclass, 0, 0);
+
+/*---------------------------------------------------------------------------*
+ * probe for ISA "PnP" card
+ *---------------------------------------------------------------------------*/
+int
+ihfc_pnp_probe(device_t dev)
+{
+ u_int unit = device_get_unit(dev); /* get unit */
+ u_int32_t vid = isa_get_vendorid(dev); /* vendor id */
+ ihfc_id_t *ids = &ihfc_pnp_ids[0]; /* ids ptr */
+ ihfc_sc_t *sc = &ihfc_softc[unit]; /* softc */
+
+ HFC_VAR;
+
+ if (unit >= IHFC_MAXUNIT)
+ {
+ printf("ihfc%d: Error, unit %d >= IHFC_MAXUNIT", unit, unit);
+ return ENXIO;
+ }
+
+ if (!vid) return ihfc_isa_probe(dev);
+
+ HFC_BEG;
+
+ for ( ;(ids->vid); ids++)
+ {
+ if (ids->vid == vid)
+ {
+ bzero(sc, sizeof(ihfc_sc_t)); /* reset data structure */
+
+ S_IOBASE[0] = bus_alloc_resource(
+ dev, SYS_RES_IOPORT, &S_IORID[0],
+ 0UL, ~0UL, 2, RF_ACTIVE
+ );
+
+ S_IRQ = bus_alloc_resource(
+ dev, SYS_RES_IRQ, &S_IRQRID,
+ 0UL, ~0UL, 1, RF_ACTIVE
+ );
+
+ S_DLP = IHFC_DLP; /* set D-priority */
+ S_HFC = ids->hfc; /* set chip type */
+ S_I4BFLAG = ids->flag; /* set flag */
+ S_NTMODE = IHFC_NTMODE; /* set mode */
+ S_STDEL = ids->stdel; /* set delay */
+
+ S_I4BUNIT = L0IHFCUNIT(unit); /* set "i4b" unit */
+ S_TRACE = TRACE_OFF; /* set trace mask */
+ S_UNIT = unit; /* set up unit numbers */
+
+ if (S_IOBASE[0] && S_IRQ)
+ {
+ if (ids->iio)
+ {
+ S_IIO = ids->iio;
+ S_IIRQ = ids->iirq;
+ }
+ else
+ {
+ S_IIO = rman_get_start(S_IOBASE[0]) & 0x3ff;
+ S_IIRQ = IIRQ3[rman_get_start(S_IRQ) & 0xf];
+ }
+
+ if (!HFC_CONTROL(sc, 1))
+ {
+ HFC_END;
+ return 0; /* success */
+ }
+ else
+ {
+ printf("ihfc%d: Chip seems corrupted. "
+ "Please hard reboot your computer!\n",
+ unit);
+ }
+ }
+
+ ihfc_pnp_detach(dev, 0);
+ }
+ }
+
+ HFC_END;
+ return ENXIO; /* failure */
+}
+
+/*---------------------------------------------------------------------------*
+ * probe for "ISA" cards
+ *---------------------------------------------------------------------------*/
+int
+ihfc_isa_probe(device_t dev)
+{
+ u_int unit = device_get_unit(dev); /* get unit */
+ ihfc_sc_t *sc = &ihfc_softc[unit]; /* softc */
+ const u_char *irq = &IRQ0[0]; /* irq's to try */
+ const u_long *iobase = &IO0[0]; /* iobases to try */
+
+ HFC_VAR;
+
+ bzero(sc, sizeof(ihfc_sc_t)); /* reset data structure *
+ * We must reset the *
+ * datastructure here, *
+ * else we risk zero-out *
+ * our gotten resources. */
+ HFC_BEG;
+
+ j0: while(*irq) /* get supported IRQ */
+ {
+ if ((S_IRQ = bus_alloc_resource(
+ dev, SYS_RES_IRQ, &S_IRQRID,
+ *irq, *irq, 1, RF_ACTIVE
+ )
+ ))
+ break;
+ else
+ irq++;
+ }
+
+ while(*iobase) /* get supported IO-PORT */
+ {
+ if ((S_IOBASE[0] = bus_alloc_resource(
+ dev, SYS_RES_IOPORT, &S_IORID[0],
+ *iobase, *iobase, 2, RF_ACTIVE
+ )
+ ))
+ break;
+ else
+ iobase++;
+ }
+
+ if (*irq && *iobase) /* we got our resources, now test chip */
+ {
+ S_DLP = IHFC_DLP; /* set D-priority */
+ S_HFC = HFC_1; /* set chip type */
+ S_I4BFLAG = FLAG_TELEINT_NO_1; /* set flag */
+ S_NTMODE = IHFC_NTMODE; /* set mode */
+ S_STDEL = 0x00; /* set delay (not used) */
+
+ S_I4BUNIT = L0IHFCUNIT(unit); /* set "i4b" unit */
+ S_TRACE = TRACE_OFF; /* set trace mask */
+ S_UNIT = unit; /* set up unit numbers */
+
+ S_IIRQ = IIRQ0[*irq]; /* set internal irq */
+ S_IIO = *iobase; /* set internal iobase */
+
+ if (!HFC_CONTROL(sc, 1))
+ {
+ device_set_desc(dev, "TELEINT ISDN SPEED No. 1");
+
+ HFC_END;
+ return 0; /* success */
+ }
+ }
+
+ ihfc_pnp_detach(dev, 0);
+
+ if (*irq && *++iobase) goto j0; /* try again */
+
+ HFC_END;
+
+ printf("ihfc%d: Chip not found. "
+ "A hard reboot may help!\n", unit);
+
+ return ENXIO; /* failure */
+}
+
+/*---------------------------------------------------------------------------*
+ * attach ISA "PnP" card
+ *---------------------------------------------------------------------------*/
+int
+ihfc_pnp_attach(device_t dev)
+{
+ u_int unit = device_get_unit(dev); /* get unit */
+ ihfc_sc_t *sc = &ihfc_softc[unit]; /* softc */
+ void *dummy = 0; /* a dummy */
+ HFC_VAR;
+
+ HFC_BEG;
+
+ ihfc_B_linkinit(sc); /* Setup B-Channel linktabs */
+
+ i4b_l1_mph_status_ind(S_I4BUNIT, STI_ATTACH, S_I4BFLAG, &ihfc_l1mux_func);
+
+ HFC_INIT(sc, 0, 0, 1); /* Setup D - Channel */
+
+ HFC_INIT(sc, 2, 0, 0); /* Init B1 - Channel */
+ HFC_INIT(sc, 4, 0, 0); /* Init B2 - Channel */
+
+ bus_setup_intr(dev, S_IRQ, INTR_TYPE_NET, (void(*)(void*))
+ HFC_INTR, sc, &dummy);
+
+ HFC_END;
+ return 0; /* success */
+
+ HFC_END;
+ return ENXIO; /* failure */
+}
+
+/*---------------------------------------------------------------------------*
+ * shutdown for our ISA PnP card
+ *---------------------------------------------------------------------------*/
+int
+ihfc_pnp_shutdown(device_t dev)
+{
+ u_int unit = device_get_unit(dev); /* get unit */
+ ihfc_sc_t *sc = &ihfc_softc[unit]; /* softc */
+ HFC_VAR;
+
+ HFC_BEG;
+
+ if (unit >= IHFC_MAXUNIT)
+ {
+ printf("ihfc%d: Error, unit %d >= IHFC_MAXUNIT", unit, unit);
+ goto f0;
+ }
+
+ HFC_CONTROL(sc, 2); /* shutdown chip */
+
+ HFC_END;
+ return 0;
+ f0:
+ HFC_END;
+ return ENXIO;
+
+}
+
+/*---------------------------------------------------------------------------*
+ * detach for our ISA PnP card
+ *
+ * flag: bit[0] set: teardown interrupt handler too
+ *---------------------------------------------------------------------------*/
+int
+ihfc_pnp_detach (device_t dev, u_int flag)
+{
+ u_int unit = device_get_unit(dev); /* get unit */
+ ihfc_sc_t *sc = &ihfc_softc[unit]; /* softc */
+ u_char i;
+
+ if (unit >= IHFC_MAXUNIT)
+ {
+ printf("ihfc%d: Error, unit %d >= IHFC_MAXUNIT", unit, unit);
+ return 0;
+ }
+
+ /* free interrupt resources */
+
+ if(S_IRQ)
+ {
+ if (flag & 1)
+ {
+ /* tear down interrupt handler */
+ bus_teardown_intr(dev, S_IRQ, (void(*)(void *))HFC_INTR);
+ }
+
+ /* free irq */
+ bus_release_resource(dev, SYS_RES_IRQ, S_IRQRID, S_IRQ);
+
+ S_IRQRID = 0;
+ S_IRQ = 0;
+ }
+
+
+ /* free iobases */
+
+ for (i = IHFC_IO_BASES; i--;)
+ {
+ if(S_IOBASE[i])
+ {
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ S_IORID[i], S_IOBASE[i]);
+ S_IORID[i] = 0;
+ S_IOBASE[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+#endif /* NIHFC > 0 */
OpenPOWER on IntegriCloud