diff options
author | hm <hm@FreeBSD.org> | 2000-10-09 13:29:00 +0000 |
---|---|---|
committer | hm <hm@FreeBSD.org> | 2000-10-09 13:29:00 +0000 |
commit | 6a1e8c89a39e745792906a17cdf08fc5bdd384f4 (patch) | |
tree | 082a43cf60a2a80e84ca74e4339fda393b01ec06 /sys/i4b/layer1/ihfc | |
parent | 9fc2bc8a46f4f09ca71eaf59e5c203b5d61533fb (diff) | |
download | FreeBSD-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.h | 337 | ||||
-rw-r--r-- | sys/i4b/layer1/ihfc/i4b_ihfc_drv.c | 1743 | ||||
-rw-r--r-- | sys/i4b/layer1/ihfc/i4b_ihfc_drv.h | 230 | ||||
-rw-r--r-- | sys/i4b/layer1/ihfc/i4b_ihfc_ext.h | 62 | ||||
-rw-r--r-- | sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c | 517 | ||||
-rw-r--r-- | sys/i4b/layer1/ihfc/i4b_ihfc_pnp.c | 421 |
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 */ |