diff options
| author | Poul-Henning Kamp <phk@FreeBSD.org> | 1998-12-27 21:47:14 +0000 |
|---|---|---|
| committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1998-12-27 21:47:14 +0000 |
| commit | 19c749625fd37f8c5e890077c1d4bb1f82fbf726 (patch) | |
| tree | 4b7a53adb1b0254fa926016dad9d614a0399e80a /sys/i4b | |
| parent | 587c729bb366182252ca16e660b5b13fe69e304d (diff) | |
Notes
Diffstat (limited to 'sys/i4b')
83 files changed, 32435 insertions, 0 deletions
diff --git a/sys/i4b/driver/i4b_ctl.c b/sys/i4b/driver/i4b_ctl.c new file mode 100644 index 000000000000..56bcb02c2651 --- /dev/null +++ b/sys/i4b/driver/i4b_ctl.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_ctl.c - i4b system control port driver + * ------------------------------------------ + * + * $Id: i4b_ctl.c,v 1.17 1998/12/05 18:02:39 hm Exp $ + * + * last edit-date: [Sat Dec 5 17:59:15 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4bctl.h" + +#if NI4BCTL > 1 +#error "only 1 (one) i4bctl device allowed!" +#endif + +#if NI4BCTL > 0 + +#include <sys/param.h> + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#include <i386/isa/isa_device.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include "opt_devfs.h" +#endif + +#ifdef DEVFS +#include <sys/devfsext.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/layer1/i4b_l1.h> + +static int openflag = 0; + +#if BSD > 199306 && defined(__FreeBSD__) +static d_open_t i4bctlopen; +static d_close_t i4bctlclose; +static d_ioctl_t i4bctlioctl; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +static d_poll_t i4bctlpoll; +#endif + +#define CDEV_MAJOR 55 +static struct cdevsw i4bctl_cdevsw = + { i4bctlopen, i4bctlclose, noread, nowrite, + i4bctlioctl, nostop, nullreset, nodevtotty, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + i4bctlpoll, nommap, NULL, "i4bctl", NULL, -1 }; +#else + noselect, nommap, NULL, "i4bctl", NULL, -1 }; +#endif + +static void i4bctlattach(void *); +PSEUDO_SET(i4bctlattach, i4b_i4bctldrv); + +#define PDEVSTATIC static +#endif /* __FreeBSD__ */ + +#ifdef DEVFS +static void *devfs_token; +#endif + +#ifndef __FreeBSD__ +#define PDEVSTATIC /* */ +void i4bctlattach __P((void)); +int i4bctlopen __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4bctlclose __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4bctlioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +#endif /* !FreeBSD */ + +#if BSD > 199306 && defined(__FreeBSD__) +/*---------------------------------------------------------------------------* + * initialization at kernel load time + *---------------------------------------------------------------------------*/ +static void +i4bctlinit(void *unused) +{ + dev_t dev; + + dev = makedev(CDEV_MAJOR, 0); + + cdevsw_add(&dev, &i4bctl_cdevsw, NULL); +} + +SYSINIT(i4bctldev, SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, &i4bctlinit, NULL); + +#endif /* BSD > 199306 && defined(__FreeBSD__) */ + +/*---------------------------------------------------------------------------* + * interface attach routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4bctlattach(void *dummy) +#else +i4bctlattach() +#endif +{ +#ifndef HACK_NO_PSEUDO_ATTACH_MSG + printf("i4bctl: ISDN system control port attached\n"); +#endif +#ifdef DEVFS + devfs_token = devfs_add_devswf(&i4bctl_cdevsw, 0, DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "i4bctl", 0); +#endif +} + +/*---------------------------------------------------------------------------* + * i4bctlopen - device driver open routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bctlopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + if(minor(dev)) + return (ENXIO); + + if(openflag) + return (EBUSY); + + openflag = 1; + + return (0); +} + +/*---------------------------------------------------------------------------* + * i4bctlclose - device driver close routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bctlclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + openflag = 0; + return (0); +} + +/*---------------------------------------------------------------------------* + * i4bctlioctl - device driver ioctl routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003 +i4bctlioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +#else +i4bctlioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +#endif +{ + ctl_debug_t *cdbg; + int error = 0; + +#ifndef DO_I4B_DEBUG + return(ENODEV); +#else + if(minor(dev)) + return(ENODEV); + + switch(cmd) + { + case I4B_CTL_GET_DEBUG: + cdbg = (ctl_debug_t *)data; + cdbg->l1 = i4b_l1_debug; + cdbg->l2 = i4b_l2_debug; + cdbg->l3 = i4b_l3_debug; + cdbg->l4 = i4b_l4_debug; + break; + + case I4B_CTL_SET_DEBUG: + cdbg = (ctl_debug_t *)data; + i4b_l1_debug = cdbg->l1; + i4b_l2_debug = cdbg->l2; + i4b_l3_debug = cdbg->l3; + i4b_l4_debug = cdbg->l4; + break; + + case I4B_CTL_GET_HSCXSTAT: + { + hscxstat_t *hst; + struct isic_softc *sc; + hst = (hscxstat_t *)data; + + if( hst->unit < 0 || + hst->unit > ISIC_MAXUNIT || + hst->chan < 0 || + hst->chan > 1 ) + { + error = EINVAL; + break; + } + +#ifndef __FreeBSD__ + sc = isic_find_sc(hst->unit); +#else + sc = &isic_sc[hst->unit]; +#endif + hst->vfr = sc->sc_chan[hst->chan].stat_VFR; + hst->rdo = sc->sc_chan[hst->chan].stat_RDO; + hst->crc = sc->sc_chan[hst->chan].stat_CRC; + hst->rab = sc->sc_chan[hst->chan].stat_RAB; + hst->xdu = sc->sc_chan[hst->chan].stat_XDU; + hst->rfo = sc->sc_chan[hst->chan].stat_RFO; + break; + } + + case I4B_CTL_CLR_HSCXSTAT: + { + hscxstat_t *hst; + struct isic_softc *sc; + hst = (hscxstat_t *)data; + + if( hst->unit < 0 || + hst->unit > ISIC_MAXUNIT || + hst->chan < 0 || + hst->chan > 1 ) + { + error = EINVAL; + break; + } + +#ifndef __FreeBSD__ + sc = isic_find_sc(hst->unit); +#else + sc = &isic_sc[hst->unit]; +#endif + + sc->sc_chan[hst->chan].stat_VFR = 0; + sc->sc_chan[hst->chan].stat_RDO = 0; + sc->sc_chan[hst->chan].stat_CRC = 0; + sc->sc_chan[hst->chan].stat_RAB = 0; + sc->sc_chan[hst->chan].stat_XDU = 0; + sc->sc_chan[hst->chan].stat_RFO = 0; + + break; + } + + default: + error = ENOTTY; + break; + } + return(error); +#endif DO_I4B_DEBUG +} + +/*---------------------------------------------------------------------------* + * i4bctlpoll - device driver poll routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static int +i4bctlpoll (dev_t dev, int events, struct proc *p) +{ + return (ENODEV); +} +#endif + +#endif /* NI4BCTL > 0 */ diff --git a/sys/i4b/driver/i4b_ipr.c b/sys/i4b/driver/i4b_ipr.c new file mode 100644 index 000000000000..df3977cb72af --- /dev/null +++ b/sys/i4b/driver/i4b_ipr.c @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_ipr.c - isdn4bsd IP over raw HDLC ISDN network driver + * --------------------------------------------------------- + * + * $Id: i4b_ipr.c,v 1.42 1998/12/18 14:20:44 hm Exp $ + * + * last edit-date: [Fri Dec 18 11:50:47 1998] + * + *---------------------------------------------------------------------------* + * + * statistics counter usage (interface lifetime): + * ---------------------------------------------- + * sc->sc_if.if_ipackets # of received packets + * sc->sc_if.if_ierrors # of error packets not going to upper layers + * sc->sc_if.if_opackets # of transmitted packets + * sc->sc_if.if_oerrors # of error packets not being transmitted + * sc->sc_if.if_collisions # of invalid ip packets after VJ decompression + * sc->sc_if.if_ibytes # of bytes coming in from the line (before VJ) + * sc->sc_if.if_obytes # of bytes going out to the line (after VJ) + * sc->sc_if.if_imcasts (currently unused) + * sc->sc_if.if_omcasts # of frames sent out of the fastqueue + * sc->sc_if.if_iqdrops # of frames dropped on input because queue full + * sc->sc_if.if_noproto # of frames dropped on output because !AF_INET + * + * statistics counter usage (connection lifetime): + * ----------------------------------------------- + * sc->sc_iinb # of ISDN incoming bytes from HSCX + * sc->sc_ioutb # of ISDN outgoing bytes from HSCX + * sc->sc_inb # of incoming bytes after decompression + * sc->sc_outb # of outgoing bytes before compression + * + *---------------------------------------------------------------------------*/ + +#include "i4bipr.h" + +#if NI4BIPR > 0 + +#ifdef __FreeBSD__ +#include "opt_i4b.h" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/errno.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#include <sys/sockio.h> +#ifdef IPR_VJ +#include <sys/malloc.h> +#endif +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> + +#ifdef IPR_VJ +#include <net/slcompress.h> +#define IPR_COMPRESS IFF_LINK0 /* compress TCP traffic */ +#define IPR_AUTOCOMP IFF_LINK1 /* auto-enable TCP compression */ + +/*--------------------------------------------------------------------------- + * NOTICE: using NO separate buffer relies on the assumption, that the HSCX + * IRQ handler _always_ allocates a single, continuous mbuf cluster large + * enough to hold the maximum MTU size if the ipr interface ! + * + * CAUTION: i have re-defined IPR_VJ_USEBUFFER because it makes problems + * with 2 i4b's back to back running cvs over ssh, cvs simply + * aborts because it gets bad data. Everything else (telnet/ftp?etc) + * functions fine. + *---------------------------------------------------------------------------*/ +#define IPR_VJ_USEBUFFER /* define to use an allocated separate buffer*/ + /* undef to uncompress in the mbuf itself */ +#endif /* IPR_VJ */ + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include <sys/time.h> +#include <net/bpf.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_debug.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_l3l4.h> + +#include <i4b/layer4/i4b_l4.h> + +#ifndef __FreeBSD__ +#include <machine/cpu.h> /* For softnet */ +#endif + +#ifdef __FreeBSD__ +#define IPR_FMT "ipr%d: " +#define IPR_ARG(sc) ((sc)->sc_if.if_unit) +#define PDEVSTATIC static +#else +#define IPR_FMT "%s: " +#define IPR_ARG(sc) ((sc)->sc_if.if_xname) +#define PDEVSTATIC /* not static */ +#endif + +#define I4BIPRMTU 1500 /* regular MTU */ +#define I4BIPRMAXMTU 2000 /* max MTU */ +#define I4BIPRMINMTU 500 /* min MTU */ + +#define I4BIPRMAXQLEN 50 /* max queue length */ + +#define I4BIPRACCT 1 /* enable accounting messages */ +#define I4BIPRACCTINTVL 2 /* accounting msg interval in secs */ +#define I4BIPRADJFRXP 1 /* adjust 1st rxd packet */ + +/* initialized by L4 */ + +static drvr_link_t ipr_drvr_linktab[NI4BIPR]; +static isdn_link_t *isdn_linktab[NI4BIPR]; + +struct ipr_softc { + struct ifnet sc_if; /* network-visible interface */ + int sc_state; /* state of the interface */ + +#ifndef __FreeBSD__ + int sc_unit; /* unit number for Net/OpenBSD */ +#endif + + call_desc_t *sc_cdp; /* ptr to call descriptor */ + int sc_updown; /* soft state of interface */ + struct ifqueue sc_fastq; /* interactive traffic */ + int sc_dialresp; /* dialresponse */ + int sc_lastdialresp;/* last dialresponse */ + +#if I4BIPRACCT + int sc_iinb; /* isdn driver # of inbytes */ + int sc_ioutb; /* isdn driver # of outbytes */ + int sc_inb; /* # of bytes rx'd */ + int sc_outb; /* # of bytes tx'd */ + int sc_linb; /* last # of bytes rx'd */ + int sc_loutb; /* last # of bytes tx'd */ + int sc_fn; /* flag, first null acct */ +#endif + +#ifdef I4BIPRADJFRXP + int sc_first_pkt; /* flag, first rxd packet */ +#endif + +#ifdef IPR_VJ + struct slcompress sc_compr; /* tcp compression data */ +#ifdef IPR_VJ_USEBUFFER + u_char *sc_cbuf; /* tcp decompression buffer */ +#endif +#endif + +} ipr_softc[NI4BIPR]; + +enum ipr_states { + ST_IDLE, /* initialized, ready, idle */ + ST_DIALING, /* dialling out to remote */ + ST_CONNECTED_W, /* connected to remote */ + ST_CONNECTED_A, /* connected to remote */ +}; + +#ifdef __FreeBSD__ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +# define IOCTL_CMD_T u_long +#else +# define IOCTL_CMD_T int +#endif +PDEVSTATIC void i4biprattach(void *); +PSEUDO_SET(i4biprattach, i4b_ipr); +static int i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data); +#else +PDEVSTATIC void i4biprattach __P((void)); +static int i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data); +#endif + +static void iprwatchdog(struct ifnet *ifp); +static void ipr_init_linktab(int unit); +static void ipr_tx_queue_empty(int unit); +static int i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rtp); +static void iprclearqueues(struct ipr_softc *sc); + +/*===========================================================================* + * DEVICE DRIVER ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * interface attach routine at kernel boot time + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4biprattach(void *dummy) +#else +i4biprattach() +#endif +{ + struct ipr_softc *sc = ipr_softc; + int i; + +#ifndef HACK_NO_PSEUDO_ATTACH_MSG +#ifdef IPR_VJ + printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached (VJ header compression)\n", NI4BIPR); +#else + printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached\n", NI4BIPR); +#endif +#endif + + for(i=0; i < NI4BIPR; sc++, i++) + { + ipr_init_linktab(i); + + DBGL4(L4_DIALST, "i4biprattach", ("setting dial state to ST_IDLE\n")); + + sc->sc_state = ST_IDLE; + +#ifdef __FreeBSD__ + sc->sc_if.if_name = "ipr"; +#if __FreeBSD__ < 3 + sc->sc_if.if_next = NULL; +#endif + sc->sc_if.if_unit = i; +#else + sprintf(sc->sc_if.if_xname, "ipr%d", i); + sc->sc_if.if_softc = sc; + sc->sc_unit = i; +#endif + +#ifdef IPR_VJ + sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX | IPR_AUTOCOMP; +#else + sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX; +#endif + + sc->sc_if.if_mtu = I4BIPRMTU; + sc->sc_if.if_type = IFT_ISDNBASIC; + sc->sc_if.if_ioctl = i4biprioctl; + sc->sc_if.if_output = i4biproutput; + + sc->sc_if.if_snd.ifq_maxlen = I4BIPRMAXQLEN; + sc->sc_fastq.ifq_maxlen = I4BIPRMAXQLEN; + + sc->sc_if.if_ipackets = 0; + sc->sc_if.if_ierrors = 0; + sc->sc_if.if_opackets = 0; + sc->sc_if.if_oerrors = 0; + sc->sc_if.if_collisions = 0; + sc->sc_if.if_ibytes = 0; + sc->sc_if.if_obytes = 0; + sc->sc_if.if_imcasts = 0; + sc->sc_if.if_omcasts = 0; + sc->sc_if.if_iqdrops = 0; + sc->sc_if.if_noproto = 0; + +#if I4BIPRACCT + sc->sc_if.if_timer = 0; + sc->sc_if.if_watchdog = iprwatchdog; + sc->sc_iinb = 0; + sc->sc_ioutb = 0; + sc->sc_inb = 0; + sc->sc_outb = 0; + sc->sc_linb = 0; + sc->sc_loutb = 0; + sc->sc_fn = 1; +#endif + +#ifdef IPR_VJ +#ifdef __FreeBSD__ + sl_compress_init(&sc->sc_compr, -1); +#else + sl_compress_init(&sc->sc_compr); +#endif + +#ifdef IPR_VJ_USEBUFFER + if(!((sc->sc_cbuf = + (u_char *)malloc(I4BIPRMAXMTU+128, M_DEVBUF, M_WAITOK)))) + { + panic("if_ipr.c, ipr_attach: VJ malloc failed"); + } +#endif +#endif + + sc->sc_updown = SOFT_ENA; /* soft enabled */ + + sc->sc_dialresp = DSTAT_NONE; /* no response */ + sc->sc_lastdialresp = DSTAT_NONE; + + if_attach(&sc->sc_if); + +#if NBPFILTER > 0 +#ifdef __FreeBSD__ + bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int)); +#else + bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int)); +#endif +#endif + } +} + +/*---------------------------------------------------------------------------* + * output a packet to the ISDN B-channel + *---------------------------------------------------------------------------*/ +static int +i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rtp) +{ + struct ipr_softc *sc; + int unit; + int s; + struct ifqueue *ifq; + struct ip *ip; + + s = SPLI4B(); + +#ifdef __FreeBSD__ + unit = ifp->if_unit; + sc = &ipr_softc[unit]; +#else + sc = ifp->if_softc; + unit = sc->sc_unit; +#endif + + /* check for IP */ + + if(dst->sa_family != AF_INET) + { + printf(IPR_FMT "af%d not supported\n", IPR_ARG(sc), dst->sa_family); + m_freem(m); + splx(s); + sc->sc_if.if_noproto++; + sc->sc_if.if_oerrors++; + return(EAFNOSUPPORT); + } + + /* check interface state = UP */ + + if(!(ifp->if_flags & IFF_UP)) + { + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: interface is DOWN!\n", unit)); + m_freem(m); + splx(s); + sc->sc_if.if_oerrors++; + return(ENETDOWN); + } + + /* dial if necessary */ + + if(sc->sc_state == ST_IDLE || sc->sc_state == ST_DIALING) + { + +#ifdef NOTDEF + switch(sc->sc_dialresp) + { + case DSTAT_TFAIL: /* transient failure */ + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: transient dial failure!\n", unit)); + m_freem(m); + iprclearqueues(sc); + sc->sc_dialresp = DSTAT_NONE; + splx(s); + sc->sc_if.if_oerrors++; + return(ENETUNREACH); + break; + + case DSTAT_PFAIL: /* permanent failure */ + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: permanent dial failure!\n", unit)); + m_freem(m); + iprclearqueues(sc); + sc->sc_dialresp = DSTAT_NONE; + splx(s); + sc->sc_if.if_oerrors++; + return(EHOSTUNREACH); + break; + + case DSTAT_INONLY: /* no dialout allowed*/ + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: dialout not allowed failure!\n", unit)); + m_freem(m); + iprclearqueues(sc); + sc->sc_dialresp = DSTAT_NONE; + splx(s); + sc->sc_if.if_oerrors++; + return(EHOSTUNREACH); + break; + } +#endif + + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: send dial request message!\n", unit)); + DBGL4(L4_DIALST, "i4biproutput", ("ipr%d: setting dial state to ST_DIALING\n", unit)); + i4b_l4_dialout(BDRV_IPR, unit); + sc->sc_state = ST_DIALING; + } + + /* update access time */ + + microtime(&sc->sc_if.if_lastchange); + + /* + * check, if type of service indicates interactive, i.e. telnet, + * traffic. in case it is interactive, put it into the fast queue, + * else (i.e. ftp traffic) put it into the "normal" queue + */ + + ip = mtod(m, struct ip *); /* get ptr to ip header */ + + if(ip->ip_tos & IPTOS_LOWDELAY) + ifq = &sc->sc_fastq; + else + ifq = &sc->sc_if.if_snd; + + /* check for space in choosen send queue */ + + if(IF_QFULL(ifq)) + { + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: send queue full!\n", unit)); + IF_DROP(ifq); + m_freem(m); + splx(s); + sc->sc_if.if_oerrors++; + return(ENOBUFS); + } + + DBGL4(L4_IPRDBG, "i4biproutput", ("ipr%d: add packet to send queue!\n", unit)); + + IF_ENQUEUE(ifq, m); + + ipr_tx_queue_empty(unit); + + splx(s); + + return (0); +} + +/*---------------------------------------------------------------------------* + * process ioctl + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static int +i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data) +#else +static int +i4biprioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +#endif +{ +#ifdef __FreeBSD__ + struct ipr_softc *sc = &ipr_softc[ifp->if_unit]; +#else + struct ipr_softc *sc = ifp->if_softc; +#endif + + struct ifreq *ifr = (struct ifreq *)data; + struct ifaddr *ifa = (struct ifaddr *)data; + int s; + int error = 0; + + s = SPLI4B(); + + switch (cmd) + { + case SIOCAIFADDR: /* add interface address */ + case SIOCSIFADDR: /* set interface address */ + case SIOCSIFDSTADDR: /* set interface destination address */ + if(ifa->ifa_addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + else + sc->sc_if.if_flags |= IFF_UP; + microtime(&sc->sc_if.if_lastchange); + break; + + case SIOCSIFFLAGS: /* set interface flags */ + if(!(ifr->ifr_flags & IFF_UP)) + { + if(sc->sc_if.if_flags & IFF_RUNNING) + { + /* disconnect ISDN line */ +#ifdef __FreeBSD__ + i4b_l4_drvrdisc(BDRV_IPR, ifp->if_unit); +#else + i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit); +#endif + sc->sc_if.if_flags &= ~IFF_RUNNING; + } + + sc->sc_state = ST_IDLE; + + /* empty queues */ + + iprclearqueues(sc); + } + + if(ifr->ifr_flags & IFF_DEBUG) + { + /* enable debug messages */ + } + + microtime(&sc->sc_if.if_lastchange); + break; + +#if !defined(__OpenBSD__) + case SIOCSIFMTU: /* set interface MTU */ + if(ifr->ifr_mtu > I4BIPRMAXMTU) + error = EINVAL; + else if(ifr->ifr_mtu < I4BIPRMINMTU) + error = EINVAL; + else + { + ifp->if_mtu = ifr->ifr_mtu; + microtime(&sc->sc_if.if_lastchange); + } + break; +#endif /* __OPENBSD__ */ + +#if 0 + /* not needed for FreeBSD, done in sl_compress_init() (-hm) */ + + /* need to add an ioctl: set VJ max slot ID + * #define IPRIOCSMAXCID _IOW('I', XXX, int) + */ +#ifdef IPR_VJ + case IPRIOCSMAXCID: + { + struct proc *p = curproc; /* XXX */ + if((error = suser(p->p_ucred, &p->p_acflag)) != 0) + return (error); + sl_compress_setup(sc->sc_compr, *(int *)data); + } + break; +#endif +#endif + default: + error = EINVAL; + break; + } + + splx(s); + + return(error); +} + +/*---------------------------------------------------------------------------* + * clear the interface's send queues + *---------------------------------------------------------------------------*/ +static void +iprclearqueues(struct ipr_softc *sc) +{ + int x; + struct mbuf *m; + + for(;;) + { + x = splimp(); + IF_DEQUEUE(&sc->sc_fastq, m); + splx(x); + + if(m) + m_freem(m); + else + break; + } + + for(;;) + { + x = splimp(); + IF_DEQUEUE(&sc->sc_if.if_snd, m); + splx(x); + + if(m) + m_freem(m); + else + break; + } +} + +#if I4BIPRACCT +/*---------------------------------------------------------------------------* + * watchdog routine + *---------------------------------------------------------------------------*/ +static void +iprwatchdog(struct ifnet *ifp) +{ +#ifdef __FreeBSD__ + int unit = ifp->if_unit; + struct ipr_softc *sc = &ipr_softc[unit]; +#else + struct ipr_softc *sc = ifp->if_softc; + int unit = sc->sc_unit; +#endif + bchan_statistics_t bs; + + /* get # of bytes in and out from the HSCX driver */ + + (*isdn_linktab[unit]->bch_stat) + (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs); + + sc->sc_ioutb += bs.outbytes; + sc->sc_iinb += bs.inbytes; + + if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) + { + int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL; + int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL; + + if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb)) + sc->sc_fn = 0; + else + sc->sc_fn = 1; + + sc->sc_linb = sc->sc_iinb; + sc->sc_loutb = sc->sc_ioutb; + + i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING, + sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb); + } + sc->sc_if.if_timer = I4BIPRACCTINTVL; +} +#endif /* I4BIPRACCT */ + +/*===========================================================================* + * ISDN INTERFACE ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * start transmitting after connect + *---------------------------------------------------------------------------*/ +static void +i4bipr_connect_startio(int unit) +{ + struct ipr_softc *sc = &ipr_softc[unit]; + int s = SPLI4B(); + + if(sc->sc_state == ST_CONNECTED_W) + { + sc->sc_state = ST_CONNECTED_A; + ipr_tx_queue_empty(unit); + } + + splx(s); +} + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at connect time + *---------------------------------------------------------------------------*/ +static void +ipr_connect(int unit, void *cdp) +{ + struct ipr_softc *sc = &ipr_softc[unit]; + int s; + + sc->sc_cdp = (call_desc_t *)cdp; + + s = SPLI4B(); + + DBGL4(L4_DIALST, "ipr_connect", ("ipr%d: setting dial state to ST_CONNECTED\n", unit)); + + sc->sc_if.if_flags |= IFF_RUNNING; + sc->sc_state = ST_CONNECTED_W; + + sc->sc_dialresp = DSTAT_NONE; + sc->sc_lastdialresp = DSTAT_NONE; + +#if I4BIPRACCT + sc->sc_iinb = 0; + sc->sc_ioutb = 0; + sc->sc_inb = 0; + sc->sc_outb = 0; + sc->sc_linb = 0; + sc->sc_loutb = 0; + sc->sc_if.if_timer = I4BIPRACCTINTVL; +#endif + +#ifdef I4BIPRADJFRXP + sc->sc_first_pkt = 1; +#endif + + /* + * Sometimes ISDN B-channels are switched thru asymmetic. This + * means that under such circumstances B-channel data (the first + * three packets of a TCP connection in my case) may get lost, + * causing a large delay until the connection is started. + * When the sending of the very first packet of a TCP connection + * is delayed for a to be empirically determined delay (close + * to a second in my case) those packets go thru and the TCP + * connection comes up "almost" immediately (-hm). + */ + + if(sc->sc_cdp->isdntxdelay > 0) + { + timeout((TIMEOUT_FUNC_T)i4bipr_connect_startio, (void *)unit, sc->sc_cdp->isdntxdelay /* hz*1 */); + } + else + { + sc->sc_state = ST_CONNECTED_A; + ipr_tx_queue_empty(unit); + } + + splx(s); + + /* we don't need any negotiation - pass event back right now */ + i4b_l4_negcomplete(sc->sc_cdp); +} + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at disconnect time + *---------------------------------------------------------------------------*/ +static void +ipr_disconnect(int unit, void *cdp) +{ + call_desc_t *cd = (call_desc_t *)cdp; + struct ipr_softc *sc = &ipr_softc[unit]; + + /* new stuff to check that the active channel is being closed */ + + if (cd != sc->sc_cdp) + { + DBGL4(L4_IPRDBG, "ipr_disconnect", ("ipr%d: channel %d not active\n", + cd->driver_unit, cd->channelid)); + return; + } + +#if I4BIPRACCT + sc->sc_if.if_timer = 0; +#endif + + i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL, + sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb); + + sc->sc_cdp = (call_desc_t *)0; + + DBGL4(L4_DIALST, "ipr_disconnect", ("setting dial state to ST_IDLE\n")); + + sc->sc_dialresp = DSTAT_NONE; + sc->sc_lastdialresp = DSTAT_NONE; + + sc->sc_if.if_flags &= ~IFF_RUNNING; + sc->sc_state = ST_IDLE; +} + +/*---------------------------------------------------------------------------* + * this routine is used to give a feedback from userland daemon + * in case of dial problems + *---------------------------------------------------------------------------*/ +static void +ipr_dialresponse(int unit, int status) +{ + struct ipr_softc *sc = &ipr_softc[unit]; + sc->sc_dialresp = status; + + DBGL4(L4_IPRDBG, "ipr_dialresponse", ("ipr%d: last=%d, this=%d\n", + unit, sc->sc_lastdialresp, sc->sc_dialresp)); +} + +/*---------------------------------------------------------------------------* + * interface soft up/down + *---------------------------------------------------------------------------*/ +static void +ipr_updown(int unit, int updown) +{ + struct ipr_softc *sc = &ipr_softc[unit]; + sc->sc_updown = updown; +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when a new frame (mbuf) has been received and was put on + * the rx queue. It is assumed that this routines runs at + * pri level splimp() ! Keep it short ! + *---------------------------------------------------------------------------*/ +static void +ipr_rx_data_rdy(int unit) +{ + register struct ipr_softc *sc = &ipr_softc[unit]; + register struct mbuf *m; +#ifdef IPR_VJ +#ifdef IPR_VJ_USEBUFFER + u_char *cp = sc->sc_cbuf; +#endif + int len, c; +#endif + + if((m = *isdn_linktab[unit]->rx_mbuf) == NULL) + return; + + m->m_pkthdr.rcvif = &sc->sc_if; + + m->m_pkthdr.len = m->m_len; + + microtime(&sc->sc_if.if_lastchange); + +#ifdef I4BIPRADJFRXP + + /* + * The very first packet after the B channel is switched thru + * has very often several bytes of random data prepended. This + * routine looks where the IP header starts and removes the + * the bad data. + */ + + if(sc->sc_first_pkt) + { + unsigned char *mp = m->m_data; + int i; + + sc->sc_first_pkt = 0; + + for(i = 0; i < m->m_len; i++, mp++) + { + if( ((*mp & 0xf0) == 0x40) && + ((*mp & 0x0f) >= 0x05) ) + { + m->m_data = mp; + m->m_pkthdr.len -= i; + break; + } + } + } +#endif + + sc->sc_if.if_ipackets++; + sc->sc_if.if_ibytes += m->m_pkthdr.len; + +#ifdef IPR_VJ + if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4)) + { + /* copy data to buffer */ + + len = m->m_len; + +#ifdef IPR_VJ_USEBUFFER +/* XXX */ m_copydata(m, 0, len, cp); +#endif + + if(c & 0x80) + { + c = TYPE_COMPRESSED_TCP; + } + else if(c == TYPE_UNCOMPRESSED_TCP) + { +#ifdef IPR_VJ_USEBUFFER + *cp &= 0x4f; /* XXX */ +#else + *(mtod(m, u_char *)) &= 0x4f; +#endif + } + + /* + * We've got something that's not an IP packet. + * If compression is enabled, try to decompress it. + * Otherwise, if `auto-enable' compression is on and + * it's a reasonable packet, decompress it and then + * enable compression. Otherwise, drop it. + */ + if(sc->sc_if.if_flags & IPR_COMPRESS) + { +#ifdef IPR_VJ_USEBUFFER + len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr); +#else + len = sl_uncompress_tcp((u_char **)&m->m_data, len, + (u_int)c, &sc->sc_compr); +#endif + + if(len <= 0) + { +#ifdef DEBUG_IPR_VJ + printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n"); +#endif + goto error; + } + } + else if((sc->sc_if.if_flags & IPR_AUTOCOMP) && + (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40)) + { +#ifdef IPR_VJ_USEBUFFER + len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr); +#else + len = sl_uncompress_tcp((u_char **)&m->m_data, len, + (u_int)c, &sc->sc_compr); +#endif + + if(len <= 0) + { +#ifdef DEBUG_IPR_VJ + printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n"); +#endif + goto error; + } + + sc->sc_if.if_flags |= IPR_COMPRESS; + } + else + { +#ifdef DEBUG_IPR_VJ + printf("i4b_ipr, ipr_input: invalid ip packet!\n"); +#endif + +error: + sc->sc_if.if_ierrors++; + sc->sc_if.if_collisions++; + m_freem(m); + return; + } +#ifdef IPR_VJ_USEBUFFER +/* XXX */ m_copyback(m, 0, len, cp); +#else + m->m_len = m->m_pkthdr.len = len; +#endif + } +#endif + +#if I4BIPRACCT + /* NB. do the accounting after decompression! */ + sc->sc_inb += m->m_pkthdr.len; +#endif + +#if NBPFILTER > 0 + if(sc->sc_if.if_bpf) + { + /* prepend the address family as a four byte field */ + struct mbuf mm; + u_int af = AF_INET; + mm.m_next = m; + mm.m_len = 4; + mm.m_data = (char *)⁡ + +#ifdef __FreeBSD__ + bpf_mtap(&sc->sc_if, &mm); +#else + bpf_mtap(sc->sc_if.if_bpf, &mm); +#endif + } +#endif /* NBPFILTER > 0 */ + + if(IF_QFULL(&ipintrq)) + { + DBGL4(L4_IPRDBG, "ipr_rx_data_rdy", ("ipr%d: ipintrq full!\n", unit)); + + IF_DROP(&ipintrq); + sc->sc_if.if_ierrors++; + sc->sc_if.if_iqdrops++; + m_freem(m); + } + else + { + IF_ENQUEUE(&ipintrq, m); + schednetisr(NETISR_IP); + } +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when the last frame has been sent out and there is no + * further frame (mbuf) in the tx queue. + *---------------------------------------------------------------------------*/ +static void +ipr_tx_queue_empty(int unit) +{ + register struct ipr_softc *sc = &ipr_softc[unit]; + register struct mbuf *m; +#ifdef IPR_VJ + struct ip *ip; +#endif + int x = 0; + + if(sc->sc_state != ST_CONNECTED_A) + return; + + for(;;) + { + IF_DEQUEUE(&sc->sc_fastq, m); + if(m) + { + sc->sc_if.if_omcasts++; + } + else + { + IF_DEQUEUE(&sc->sc_if.if_snd, m); + if(m == NULL) + break; + } + + microtime(&sc->sc_if.if_lastchange); + +#if NBPFILTER > 0 + if(sc->sc_if.if_bpf) + { + /* prepend the address family as a four byte field */ + + struct mbuf mm; + u_int af = AF_INET; + mm.m_next = m; + mm.m_len = 4; + mm.m_data = (char *)⁡ + +#ifdef __FreeBSD__ + bpf_mtap(&sc->sc_if, &mm); +#else + bpf_mtap(sc->sc_if.if_bpf, &mm); +#endif + } +#endif /* NBPFILTER */ + +#if I4BIPRACCT + sc->sc_outb += m->m_pkthdr.len; /* size before compression */ +#endif + +#ifdef IPR_VJ + if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) + { + if(sc->sc_if.if_flags & IPR_COMPRESS) + { + *mtod(m, u_char *) |= sl_compress_tcp(m, ip, + &sc->sc_compr, 1); + } + } +#endif + x = 1; + + IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m); + + sc->sc_if.if_obytes += m->m_pkthdr.len; + + sc->sc_if.if_opackets++; + } + + if(x) + (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel); +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * each time a packet is received or transmitted. It should + * be used to implement an activity timeout mechanism. + *---------------------------------------------------------------------------*/ +static void +ipr_activity(int unit, int rxtx) +{ + ipr_softc[unit].sc_cdp->last_active_time = SECOND; +} + +/*---------------------------------------------------------------------------* + * return this drivers linktab address + *---------------------------------------------------------------------------*/ +drvr_link_t * +ipr_ret_linktab(int unit) +{ + return(&ipr_drvr_linktab[unit]); +} + +/*---------------------------------------------------------------------------* + * setup the isdn_linktab for this driver + *---------------------------------------------------------------------------*/ +void +ipr_set_linktab(int unit, isdn_link_t *ilt) +{ + isdn_linktab[unit] = ilt; +} + +/*---------------------------------------------------------------------------* + * initialize this drivers linktab + *---------------------------------------------------------------------------*/ +static void +ipr_init_linktab(int unit) +{ + ipr_drvr_linktab[unit].unit = unit; + ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy; + ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty; + ipr_drvr_linktab[unit].bch_activity = ipr_activity; + ipr_drvr_linktab[unit].line_connected = ipr_connect; + ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect; + ipr_drvr_linktab[unit].dial_response = ipr_dialresponse; + ipr_drvr_linktab[unit].updown_ind = ipr_updown; +} + +/*===========================================================================*/ + +#endif /* NI4BIPR > 0 */ diff --git a/sys/i4b/driver/i4b_isppp.c b/sys/i4b/driver/i4b_isppp.c new file mode 100644 index 000000000000..b1cb2cf9df5b --- /dev/null +++ b/sys/i4b/driver/i4b_isppp.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 1997 Joerg Wunsch. All rights reserved. + * + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isppp.c - isdn4bsd kernel SyncPPP driver + * -------------------------------------------- + * + * Uses Serge Vakulenko's sppp backend (originally contributed with + * the "cx" driver for Cronyx's HDLC-in-hardware device). This driver + * is only the glue between sppp and i4b. + * + * $Id: i4b_isppp.c,v 1.20 1998/12/18 14:20:44 hm Exp $ + * + * last edit-date: [Fri Dec 18 11:47:58 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4bisppp.h" +#ifdef __FreeBSD__ +#include "sppp.h" +#endif + +#if NI4BISPPP == 0 +# error "You need to define `pseudo-device sppp <N>' with options ISPPP" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/ioccom.h> +#include <sys/sockio.h> +#include <sys/kernel.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#ifdef __FreeBSD__ +#include <net/if_sppp.h> +#else +#include <i4b/sppp/if_sppp.h> +#endif + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include <sys/time.h> +#include <net/bpf.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_l3l4.h> + +#include <i4b/layer4/i4b_l4.h> + +#ifdef __FreeBSD__ +#define ISPPP_FMT "isp%d: " +#define ISPPP_ARG(sc) ((sc)->sc_if.if_unit) +#define PDEVSTATIC static +#define IFP2UNIT(ifp) (ifp)->if_unit + +# if __FreeBSD_version >= 300001 +# define CALLOUT_INIT(chan) callout_handle_init(chan) +# define TIMEOUT(fun, arg, chan, tick) chan = timeout(fun, arg, tick) +# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg, chan) +# define IOCTL_CMD_T u_long +# else +# define CALLOUT_INIT(chan) do {} while(0) +# define TIMEOUT(fun, arg, chan, tick) timeout(fun, arg, tick) +# define UNTIMEOUT(fun, arg, chan) untimeout(fun, arg) +# define IOCTL_CMD_T int +# endif + +#elif defined __NetBSD__ || defined __OpenBSD__ +#define ISPPP_FMT "%s: " +#define ISPPP_ARG(sc) ((sc)->sc_if.if_xname) +#define PDEVSTATIC /* not static */ +#define IOCTL_CMD_T u_long +#define IFP2UNIT(ifp) ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit +#else +# error "What system are you using?" +#endif + +#ifdef __FreeBSD__ +PDEVSTATIC void i4bispppattach(void *); +PSEUDO_SET(i4bispppattach, i4b_isppp); +#else +PDEVSTATIC void i4bispppattach __P((void)); +#endif + +#define I4BISPPPACCT 1 /* enable accounting messages */ +#define I4BISPPPACCTINTVL 2 /* accounting msg interval in secs */ +#define I4BISPPPDISCDEBUG 1 + +#define PPP_HDRLEN 4 /* 4 octetts PPP header length */ + +struct i4bisppp_softc { + /* + * struct sppp starts with a struct ifnet, but we gotta allocate + * more space for it. NB: do not relocate this union, it must + * be first in isppp_softc. The tls and tlf hooks below want to + * convert a ``struct sppp *'' into a ``struct isppp_softc *''. + */ + union { + struct ifnet scu_if; + struct sppp scu_sp; + } sc_if_un; +#define sc_if sc_if_un.scu_if + + int sc_state; /* state of the interface */ + +#ifndef __FreeBSD__ + int sc_unit; /* unit number for Net/OpenBSD */ +#endif + + call_desc_t *sc_cdp; /* ptr to call descriptor */ + +#ifdef I4BISPPPACCT + int sc_iinb; /* isdn driver # of inbytes */ + int sc_ioutb; /* isdn driver # of outbytes */ + int sc_inb; /* # of bytes rx'd */ + int sc_outb; /* # of bytes tx'd */ + int sc_linb; /* last # of bytes rx'd */ + int sc_loutb; /* last # of bytes tx'd */ + int sc_fn; /* flag, first null acct */ +#endif + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + struct callout_handle sc_ch; +#endif + +} i4bisppp_softc[NI4BISPPP]; + +static void i4bisppp_init_linktab(int unit); +static int i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data); + +#if 0 +static void i4bisppp_send(struct ifnet *ifp); +#endif + +static void i4bisppp_start(struct ifnet *ifp); + +#if 0 /* never used ??? */ +static void i4bisppp_timeout(void *cookie); +#endif + +static void i4bisppp_tls(struct sppp *sp); +static void i4bisppp_tlf(struct sppp *sp); +static void i4bisppp_state_changed(struct sppp *sp, int new_state); +static void i4bisppp_negotiation_complete(struct sppp *sp); +static void i4bisppp_watchdog(struct ifnet *ifp); + +/* initialized by L4 */ + +static drvr_link_t i4bisppp_drvr_linktab[NI4BISPPP]; +static isdn_link_t *isdn_linktab[NI4BISPPP]; + +enum i4bisppp_states { + ST_IDLE, /* initialized, ready, idle */ + ST_DIALING, /* dialling out to remote */ + ST_CONNECTED, /* connected to remote */ +}; + +/*===========================================================================* + * DEVICE DRIVER ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * interface attach routine at kernel boot time + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4bispppattach(void *dummy) +#else +i4bispppattach(void) +#endif +{ + struct i4bisppp_softc *sc = i4bisppp_softc; + int i; + +#ifndef HACK_NO_PSEUDO_ATTACH_MSG + printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", + NI4BISPPP); +#endif + + for(i = 0; i < NI4BISPPP; sc++, i++) { + i4bisppp_init_linktab(i); + + sc->sc_if.if_softc = sc; + +#ifdef __FreeBSD__ + sc->sc_if.if_name = "isp"; +#if defined(__FreeBSD_version) && __FreeBSD_version < 300001 + sc->sc_if.if_next = NULL; +#endif + sc->sc_if.if_unit = i; +#else + sprintf(sc->sc_if.if_xname, "isp%d", i); + sc->sc_unit = i; +#endif + + sc->sc_if.if_mtu = PP_MTU; + sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT; + sc->sc_if.if_type = IFT_ISDNBASIC; + sc->sc_state = ST_IDLE; + + sc->sc_if.if_ioctl = i4bisppp_ioctl; + + /* actually initialized by sppp_attach() */ + /* sc->sc_if.if_output = sppp_output; */ + + sc->sc_if.if_start = i4bisppp_start; + + sc->sc_if.if_hdrlen = 0; + sc->sc_if.if_addrlen = 0; + sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; + + sc->sc_if.if_ipackets = 0; + sc->sc_if.if_ierrors = 0; + sc->sc_if.if_opackets = 0; + sc->sc_if.if_oerrors = 0; + sc->sc_if.if_collisions = 0; + sc->sc_if.if_ibytes = 0; + sc->sc_if.if_obytes = 0; + sc->sc_if.if_imcasts = 0; + sc->sc_if.if_omcasts = 0; + sc->sc_if.if_iqdrops = 0; + sc->sc_if.if_noproto = 0; + +#if I4BISPPPACCT + sc->sc_if.if_timer = 0; + sc->sc_if.if_watchdog = i4bisppp_watchdog; + sc->sc_iinb = 0; + sc->sc_ioutb = 0; + sc->sc_inb = 0; + sc->sc_outb = 0; + sc->sc_linb = 0; + sc->sc_loutb = 0; + sc->sc_fn = 1; +#endif + + sc->sc_if_un.scu_sp.pp_tls = i4bisppp_tls; + sc->sc_if_un.scu_sp.pp_tlf = i4bisppp_tlf; + sc->sc_if_un.scu_sp.pp_con = i4bisppp_negotiation_complete; + sc->sc_if_un.scu_sp.pp_chg = i4bisppp_state_changed; + + sppp_attach(&sc->sc_if); + if_attach(&sc->sc_if); + +#if NBPFILTER > 0 +#ifdef __FreeBSD__ + bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN); + CALLOUT_INIT(&sc->sc_ch); +#endif /* __FreeBSD__ */ +#ifdef __NetBSD__ + bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_PPP, sizeof(u_int)); +#endif +#endif + } +} + +/*---------------------------------------------------------------------------* + * process ioctl + *---------------------------------------------------------------------------*/ +static int +i4bisppp_ioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data) +{ + struct i4bisppp_softc *sc = ifp->if_softc; +#if 0 + struct sppp *sp = (struct sppp *)sc; + struct ifaddr *ifa = (struct ifaddr *) data; + struct ifreq *ifr = (struct ifreq *) data; +#endif + + int error; + + error = sppp_ioctl(&sc->sc_if, cmd, data); + if (error) + return error; + + switch(cmd) { + case SIOCSIFFLAGS: +#if 0 /* never used ??? */ + x = splimp(); + if ((ifp->if_flags & IFF_UP) == 0) + UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); + splx(x); +#endif + break; + } + + return 0; +} + +/*---------------------------------------------------------------------------* + * start output to ISDN B-channel + *---------------------------------------------------------------------------*/ +static void +i4bisppp_start(struct ifnet *ifp) +{ + struct i4bisppp_softc *sc = ifp->if_softc; + struct mbuf *m; + int s; + int unit = IFP2UNIT(ifp); + + if (sppp_isempty(ifp)) + return; + + if(sc->sc_state != ST_CONNECTED) + return; + + s = splimp(); + /*ifp->if_flags |= IFF_OACTIVE; - need to clear this somewhere */ + splx(s); + + while ((m = sppp_dequeue(&sc->sc_if)) != NULL) + { + +#if NBPFILTER > 0 +#ifdef __FreeBSD__ + if (ifp->if_bpf) + bpf_mtap(ifp, m); +#endif /* __FreeBSD__ */ + +#ifdef __NetBSD__ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m); +#endif +#endif /* NBPFILTER > 0 */ + + microtime(&ifp->if_lastchange); + + IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m); + + sc->sc_if.if_obytes += m->m_pkthdr.len; + sc->sc_outb += m->m_pkthdr.len; + sc->sc_if.if_opackets++; + } + isdn_linktab[unit]->bch_tx_start(isdn_linktab[unit]->unit, + isdn_linktab[unit]->channel); +} + +#ifdef I4BISPPPACCT +/*---------------------------------------------------------------------------* + * watchdog routine + *---------------------------------------------------------------------------*/ +static void +i4bisppp_watchdog(struct ifnet *ifp) +{ + struct i4bisppp_softc *sc = ifp->if_softc; + int unit = IFP2UNIT(ifp); + bchan_statistics_t bs; + + (*isdn_linktab[unit]->bch_stat) + (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs); + + sc->sc_ioutb += bs.outbytes; + sc->sc_iinb += bs.inbytes; + + if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn) + { + int ri = (sc->sc_iinb - sc->sc_linb)/I4BISPPPACCTINTVL; + int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BISPPPACCTINTVL; + + if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb)) + sc->sc_fn = 0; + else + sc->sc_fn = 1; + + sc->sc_linb = sc->sc_iinb; + sc->sc_loutb = sc->sc_ioutb; + + i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_DURING, + sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb); + } + sc->sc_if.if_timer = I4BISPPPACCTINTVL; + +#if 0 /* old stuff, keep it around */ + printf(ISPPP_FMT "transmit timeout\n", ISPPP_ARG(sc)); + i4bisppp_start(ifp); +#endif +} +#endif /* I4BISPPPACCT */ + +/* + *===========================================================================* + * SyncPPP layer interface routines + *===========================================================================* + */ + +#if 0 /* never used ??? */ +/*---------------------------------------------------------------------------* + * just an alias for i4bisppp_tls, but of type timeout_t + *---------------------------------------------------------------------------*/ +static void +i4bisppp_timeout(void *cookie) +{ + i4bisppp_tls((struct sppp *)cookie); +} +#endif + +/*---------------------------------------------------------------------------* + * PPP this-layer-started action + *---------------------------------------------------------------------------* + */ +static void +i4bisppp_tls(struct sppp *sp) +{ + struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; + struct ifnet *ifp = (struct ifnet *)sp; + + if(sc->sc_state == ST_CONNECTED) + return; + + i4b_l4_dialout(BDRV_ISPPP, IFP2UNIT(ifp)); +} + +/*---------------------------------------------------------------------------* + * PPP this-layer-finished action + *---------------------------------------------------------------------------* + */ +static void +i4bisppp_tlf(struct sppp *sp) +{ + struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; +/* call_desc_t *cd = sc->sc_cdp; */ + struct ifnet *ifp = (struct ifnet *)sp; + + if(sc->sc_state != ST_CONNECTED) + return; + +#if 0 /* never used ??? */ + UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); +#endif + + i4b_l4_drvrdisc(BDRV_ISPPP, IFP2UNIT(ifp)); +} +/*---------------------------------------------------------------------------* + * PPP interface phase change + *---------------------------------------------------------------------------* + */ +static void +i4bisppp_state_changed(struct sppp *sp, int new_state) +{ + struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; + + i4b_l4_ifstate_changed(sc->sc_cdp, new_state); +} + +/*---------------------------------------------------------------------------* + * PPP control protocol negotiation complete (run ip-up script now) + *---------------------------------------------------------------------------* + */ +static void +i4bisppp_negotiation_complete(struct sppp *sp) +{ + struct i4bisppp_softc *sc = (struct i4bisppp_softc *)sp; + + i4b_l4_negcomplete(sc->sc_cdp); +} + +/*===========================================================================* + * ISDN INTERFACE ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at connect time + *---------------------------------------------------------------------------*/ +static void +i4bisppp_connect(int unit, void *cdp) +{ + struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; + struct sppp *sp = &sc->sc_if_un.scu_sp; + int s = splimp(); + + sc->sc_cdp = (call_desc_t *)cdp; + sc->sc_state = ST_CONNECTED; + +#if I4BISPPPACCT + sc->sc_iinb = 0; + sc->sc_ioutb = 0; + sc->sc_inb = 0; + sc->sc_outb = 0; + sc->sc_linb = 0; + sc->sc_loutb = 0; + sc->sc_if.if_timer = I4BISPPPACCTINTVL; +#endif + +#if 0 /* never used ??? */ + UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); +#endif + + sp->pp_up(sp); /* tell PPP we are ready */ + + splx(s); +} + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at disconnect time + *---------------------------------------------------------------------------*/ +static void +i4bisppp_disconnect(int unit, void *cdp) +{ + call_desc_t *cd = (call_desc_t *)cdp; + struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; + struct sppp *sp = &sc->sc_if_un.scu_sp; + + int s = splimp(); + + /* new stuff to check that the active channel is being closed */ + if (cd != sc->sc_cdp) + { +#ifdef I4BISPPPDISCDEBUG + printf("i4bisppp_disconnect: isppp%d channel%d not active\n", + cd->driver_unit, cd->channelid); +#endif + splx(s); + return; + } + +#if I4BISPPPACCT + sc->sc_if.if_timer = 0; +#endif + + i4b_l4_accounting(BDRV_ISPPP, unit, ACCT_FINAL, + sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb); + + if (sc->sc_state == ST_CONNECTED) + { +#if 0 /* never used ??? */ + UNTIMEOUT(i4bisppp_timeout, (void *)sp, sc->sc_ch); +#endif + sc->sc_cdp = (call_desc_t *)0; + /* do thhis here because pp_down calls i4bisppp_tlf */ + sc->sc_state = ST_IDLE; + sp->pp_down(sp); /* tell PPP we have hung up */ + } + + splx(s); +} + +/*---------------------------------------------------------------------------* + * this routine is used to give a feedback from userland demon + * in case of dial problems + *---------------------------------------------------------------------------*/ +static void +i4bisppp_dialresponse(int unit, int status) +{ +/* struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; */ +} + +/*---------------------------------------------------------------------------* + * interface up/down + *---------------------------------------------------------------------------*/ +static void +i4bisppp_updown(int unit, int updown) +{ + /* could probably do something useful here */ +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when a new frame (mbuf) has been received and was put on + * the rx queue. + *---------------------------------------------------------------------------*/ +static void +i4bisppp_rx_data_rdy(int unit) +{ + struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; + struct mbuf *m; + int s; + + if((m = *isdn_linktab[unit]->rx_mbuf) == NULL) + return; + + m->m_pkthdr.rcvif = &sc->sc_if; + m->m_pkthdr.len = m->m_len; + + microtime(&sc->sc_if.if_lastchange); + + sc->sc_if.if_ipackets++; + sc->sc_if.if_ibytes += m->m_pkthdr.len; + +#if I4BISPPPACCT + sc->sc_inb += m->m_pkthdr.len; +#endif + +#ifdef I4BISPPPDEBUG + printf("i4bisppp_rx_data_ready: received packet!\n"); +#endif + +#if NBPFILTER > 0 + +#ifdef __FreeBSD__ + if(sc->sc_if.if_bpf) + bpf_mtap(&sc->sc_if, m); +#endif /* __FreeBSD__ */ + +#ifdef __NetBSD__ + if(sc->sc_if.if_bpf) + bpf_mtap(sc->sc_if.if_bpf, m); +#endif + +#endif /* NBPFILTER > 0 */ + + s = splimp(); + + sppp_input(&sc->sc_if, m); + + splx(s); +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when the last frame has been sent out and there is no + * further frame (mbuf) in the tx queue. + *---------------------------------------------------------------------------*/ +static void +i4bisppp_tx_queue_empty(int unit) +{ + i4bisppp_start(&i4bisppp_softc[unit].sc_if); +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * each time a packet is received or transmitted. It should + * be used to implement an activity timeout mechanism. + *---------------------------------------------------------------------------*/ +static void +i4bisppp_activity(int unit, int rxtx) +{ + i4bisppp_softc[unit].sc_cdp->last_active_time = SECOND; +} + +/*---------------------------------------------------------------------------* + * return this drivers linktab address + *---------------------------------------------------------------------------*/ +drvr_link_t * +i4bisppp_ret_linktab(int unit) +{ + return(&i4bisppp_drvr_linktab[unit]); +} + +/*---------------------------------------------------------------------------* + * setup the isdn_linktab for this driver + *---------------------------------------------------------------------------*/ +void +i4bisppp_set_linktab(int unit, isdn_link_t *ilt) +{ + isdn_linktab[unit] = ilt; +} + +/*---------------------------------------------------------------------------* + * initialize this drivers linktab + *---------------------------------------------------------------------------*/ +static void +i4bisppp_init_linktab(int unit) +{ + i4bisppp_drvr_linktab[unit].unit = unit; + i4bisppp_drvr_linktab[unit].bch_rx_data_ready = i4bisppp_rx_data_rdy; + i4bisppp_drvr_linktab[unit].bch_tx_queue_empty = i4bisppp_tx_queue_empty; + i4bisppp_drvr_linktab[unit].bch_activity = i4bisppp_activity; + i4bisppp_drvr_linktab[unit].line_connected = i4bisppp_connect; + i4bisppp_drvr_linktab[unit].line_disconnected = i4bisppp_disconnect; + i4bisppp_drvr_linktab[unit].dial_response = i4bisppp_dialresponse; + i4bisppp_drvr_linktab[unit].updown_ind = i4bisppp_updown; +} + +/*===========================================================================*/ diff --git a/sys/i4b/driver/i4b_rbch.c b/sys/i4b/driver/i4b_rbch.c new file mode 100644 index 000000000000..9cf432c98f29 --- /dev/null +++ b/sys/i4b/driver/i4b_rbch.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_rbch.c - device driver for raw B channel data + * --------------------------------------------------- + * + * $Id: i4b_rbch.c,v 1.23 1998/12/14 09:39:10 hm Exp $ + * + * last edit-date: [Sun Dec 13 10:19:08 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4brbch.h" + +#if NI4BRBCH > 0 + +#include <sys/param.h> +#include <sys/systm.h> + +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || !defined(__FreeBSD__) +#include <sys/ioccom.h> +#include <sys/poll.h> +#else +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#endif + +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) +#include <sys/filio.h> +#endif + +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/proc.h> +#include <sys/tty.h> + +#ifdef __NetBSD__ +extern cc_t ttydefchars; +#define termioschars(t) memcpy((t)->c_cc, &ttydefchars, sizeof((t)->c_cc)) +#endif + +#ifdef __FreeBSD__ +#include "opt_devfs.h" +#endif + +#ifdef DEVFS +#include <sys/devfsext.h> +#endif + +#ifdef __NetBSD__ +#include <sys/filio.h> +#define bootverbose 0 +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_debug.h> +#else +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_debug.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_l3l4.h> + +#include <i4b/layer4/i4b_l4.h> +/* initialized by L4 */ + +static drvr_link_t rbch_drvr_linktab[NI4BRBCH]; +static isdn_link_t *isdn_linktab[NI4BRBCH]; + +static struct rbch_softc { + int sc_devstate; /* state of driver */ +#define ST_IDLE 0x00 +#define ST_CONNECTED 0x01 +#define ST_ISOPEN 0x02 +#define ST_RDWAITDATA 0x04 +#define ST_WRWAITEMPTY 0x08 +#define ST_NOBLOCK 0x10 + + int sc_bprot; /* B-ch protocol used */ + + call_desc_t *cd; /* Call Descriptor */ + struct termios it_in; + + struct ifqueue sc_hdlcq; /* hdlc read queue */ +#define I4BRBCHMAXQLEN 10 + + struct selinfo selp; /* select / poll */ + +#ifdef DEVFS + void *devfs_token; /* device filesystem */ +#endif +} rbch_softc[NI4BRBCH]; + +static void rbch_rx_data_rdy(int unit); +static void rbch_tx_queue_empty(int unit); +static void rbch_connect(int unit, void *cdp); +static void rbch_disconnect(int unit, void *cdp); +static void rbch_init_linktab(int unit); +static void rbch_clrq(int unit); + +#ifndef __FreeBSD__ +#define PDEVSTATIC /* - not static - */ +#define IOCTL_CMD_T u_long +void i4brbchattach __P((void)); +int i4brbchopen __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4brbchclose __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4brbchread __P((dev_t dev, struct uio *uio, int ioflag)); +int i4brbchwrite __P((dev_t dev, struct uio *uio, int ioflag)); +int i4brbchioctl __P((dev_t dev, IOCTL_CMD_T cmd, caddr_t arg, int flag, struct proc* pr)); +int i4brbchpoll __P((dev_t dev, int events, struct proc *p)); +#endif + +#if BSD > 199306 && defined(__FreeBSD__) +#define PDEVSTATIC static +#if !defined(__FreeBSD_version) || __FreeBSD_version < 300003 +#define IOCTL_CMD_T int +#else +#define IOCTL_CMD_T u_long +#endif + +PDEVSTATIC d_open_t i4brbchopen; +PDEVSTATIC d_close_t i4brbchclose; +PDEVSTATIC d_read_t i4brbchread; +PDEVSTATIC d_read_t i4brbchwrite; +PDEVSTATIC d_ioctl_t i4brbchioctl; + +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || !defined(__FreeBSD__) +PDEVSTATIC d_poll_t i4brbchpoll; +#else +PDEVSTATIC d_select_t i4brbchselect; +#endif + +#define CDEV_MAJOR 57 +static struct cdevsw i4brbch_cdevsw = { + i4brbchopen, i4brbchclose, i4brbchread, i4brbchwrite, + i4brbchioctl, nostop, noreset, nodevtotty, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + i4brbchpoll, nommap, NULL, "i4brbch", NULL, -1 +#else + i4brbchselect, nommap, NULL, "i4brbch", NULL, -1 +#endif +}; + +static void i4brbchattach(void *); +PSEUDO_SET(i4brbchattach, i4b_rbch); + +/*===========================================================================* + * DEVICE DRIVER ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * initialization at kernel load time + *---------------------------------------------------------------------------*/ +static void +i4brbchinit(void *unused) +{ + dev_t dev; + + dev = makedev(CDEV_MAJOR, 0); + + cdevsw_add(&dev, &i4brbch_cdevsw, NULL); +} + +SYSINIT(i4brbchdev, SI_SUB_DRIVERS, + SI_ORDER_MIDDLE+CDEV_MAJOR, &i4brbchinit, NULL); + +#endif /* BSD > 199306 && defined(__FreeBSD__) */ + +/*---------------------------------------------------------------------------* + * interface attach routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4brbchattach(void *dummy) +#else +i4brbchattach() +#endif +{ + int i; + +#ifndef HACK_NO_PSEUDO_ATTACH_MSG + printf("i4brbch: %d raw B channel access device(s) attached\n", NI4BRBCH); +#endif + + for(i=0; i < NI4BRBCH; i++) + { +#ifdef DEVFS + rbch_softc[i].devfs_token = + devfs_add_devswf(&i4brbch_cdevsw, i, DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "i4brbch%d", i); +#endif + rbch_softc[i].sc_devstate = ST_IDLE; + rbch_softc[i].sc_hdlcq.ifq_maxlen = I4BRBCHMAXQLEN; + rbch_softc[i].it_in.c_ispeed = rbch_softc[i].it_in.c_ospeed = 64000; + termioschars(&rbch_softc[i].it_in); + rbch_init_linktab(i); + } +} + +/*---------------------------------------------------------------------------* + * open rbch device + *---------------------------------------------------------------------------*/ +int +i4brbchopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + int unit = minor(dev); + + if(unit > NI4BRBCH) + return(ENXIO); + + if(rbch_softc[unit].sc_devstate & ST_ISOPEN) + return(EBUSY); + + rbch_clrq(unit); + + rbch_softc[unit].sc_devstate |= ST_ISOPEN; + + DBGL4(L4_RBCHDBG, "i4brbchopen", ("unit %d, open\n", unit)); + + return(0); +} + +/*---------------------------------------------------------------------------* + * close rbch device + *---------------------------------------------------------------------------*/ +int +i4brbchclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + int unit = minor(dev); + + if (rbch_softc[unit].cd) { + i4b_l4_disconnect_ind(rbch_softc[unit].cd); + rbch_softc[unit].cd = NULL; + } + rbch_softc[unit].sc_devstate &= ~ST_ISOPEN; + + rbch_clrq(unit); + + DBGL4(L4_RBCHDBG, "i4brbclose", ("unit %d, close\n", unit)); + + return(0); +} + +/*---------------------------------------------------------------------------* + * read from rbch device + *---------------------------------------------------------------------------*/ +int +i4brbchread(dev_t dev, struct uio *uio, int ioflag) +{ + struct mbuf *m; + int s; + int error = 0; + int unit = minor(dev); + struct ifqueue *iqp; + + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, enter read\n", unit)); + + if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, read while not open\n", unit)); + return(EIO); + } + + if((rbch_softc[unit].sc_devstate & ST_NOBLOCK)) { + if(!(rbch_softc[unit].sc_devstate & ST_CONNECTED)) + return(EWOULDBLOCK); + + if(rbch_softc[unit].sc_bprot == BPROT_RHDLC) + iqp = &rbch_softc[unit].sc_hdlcq; + else + iqp = isdn_linktab[unit]->rx_queue; + + if(IF_QEMPTY(iqp) && (rbch_softc[unit].sc_devstate & ST_ISOPEN)) + return(EWOULDBLOCK); + } else { + while(!(rbch_softc[unit].sc_devstate & ST_CONNECTED)) + { + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, wait read init\n", unit)); + + if((error = tsleep((caddr_t) &rbch_softc[unit], + TTIPRI | PCATCH, + "rrrbch", 0 )) != 0) + { + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, error %d tsleep\n", unit, error)); + return(error); + } + } + + if(rbch_softc[unit].sc_bprot == BPROT_RHDLC) + iqp = &rbch_softc[unit].sc_hdlcq; + else + iqp = isdn_linktab[unit]->rx_queue; + + while(IF_QEMPTY(iqp) && (rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + s = splimp(); + rbch_softc[unit].sc_devstate |= ST_RDWAITDATA; + splx(s); + + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, wait read data\n", unit)); + + if((error = tsleep((caddr_t) &isdn_linktab[unit]->rx_queue, + TTIPRI | PCATCH, + "rrbch", 0 )) != 0) + { + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, error %d tsleep read\n", unit, error)); + rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA; + return(error); + } + } + } + + s = splimp(); + + IF_DEQUEUE(iqp, m); + + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, read %d bytes\n", unit, m->m_len)); + + if(m && m->m_len) + { + error = uiomove(m->m_data, m->m_len, uio); + } + else + { + DBGL4(L4_RBCHDBG, "i4brbchread", ("unit %d, error %d uiomove\n", unit, error)); + error = EIO; + } + + if(m) + i4b_Bfreembuf(m); + + splx(s); + + return(error); +} + +/*---------------------------------------------------------------------------* + * write to rbch device + *---------------------------------------------------------------------------*/ +int +i4brbchwrite(dev_t dev, struct uio * uio, int ioflag) +{ + struct mbuf *m; + int s; + int error = 0; + int unit = minor(dev); + + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write\n", unit)); + + if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write while not open\n", unit)); + return(EIO); + } + + if((rbch_softc[unit].sc_devstate & ST_NOBLOCK)) { + if(!(rbch_softc[unit].sc_devstate & ST_CONNECTED)) + return(EWOULDBLOCK); + if(IF_QFULL(isdn_linktab[unit]->tx_queue) && (rbch_softc[unit].sc_devstate & ST_ISOPEN)) + return(EWOULDBLOCK); + } else { + while(!(rbch_softc[unit].sc_devstate & ST_CONNECTED)) + { + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write wait init\n", unit)); + + error = tsleep((caddr_t) &rbch_softc[unit], + TTIPRI | PCATCH, + "wrrbch", 0 ); + if(error == ERESTART) + return (ERESTART); + else if(error == EINTR) { + printf("\n ========= i4brbchwrite, EINTR during wait init ======== \n"); + return(EINTR); + } else if(error) { + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, error %d tsleep init\n", unit, error)); + return(error); + } +/*XXX*/ tsleep((caddr_t) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1)); + } + + while(IF_QFULL(isdn_linktab[unit]->tx_queue) && (rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + s = splimp(); + rbch_softc[unit].sc_devstate |= ST_WRWAITEMPTY; + splx(s); + + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write queue full\n", unit)); + + if ((error = tsleep((caddr_t) &isdn_linktab[unit]->tx_queue, + TTIPRI | PCATCH, + "wrbch", 0)) != 0) { + rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY; + if(error == ERESTART) { + return(ERESTART); + } else if(error == EINTR) { + printf("\n ========= i4brbchwrite, EINTR during wait write ======== \n"); + return(error); + } else if(error) { + DBGL4(L4_RBCHDBG, "i4brbchwrite", + ("unit %d, error %d tsleep write\n", unit, error)); + return(error); + } + } + } + } + + s = splimp(); + + if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, not open anymore\n", unit)); + splx(s); + return(EIO); + } + + if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL) + { + m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid); + + DBGL4(L4_RBCHDBG, "i4brbchwrite", ("unit %d, write %d bytes\n", unit, m->m_len)); + + error = uiomove(m->m_data, m->m_len, uio); + + IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m); + + (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel); + } + + splx(s); + + return(error); +} + +PDEVSTATIC int +i4brbchioctl(dev_t dev, IOCTL_CMD_T cmd, caddr_t data, int flag, struct proc* p) { + int error = 0; + int unit = minor(dev); + + switch(cmd) + { +#if 0 + case I4B_RBCH_DIALOUT: +if(bootverbose)printf("EE-rbch%d: attempting dialout (ioctl)\n", unit); + i4b_l4_dialout(BDRV_RBCH, unit); + break; +#endif + + case FIOASYNC: /* Set async mode */ + if (*(int *)data) { +if(bootverbose)printf("EE-rbch%d: setting async mode\n", unit); + } else { +if(bootverbose)printf("EE-rbch%d: clearing async mode\n", unit); + } + break; + case FIONBIO: + if (*(int *)data) { +if(bootverbose)printf("EE-rbch%d: setting non-blocking mode\n", unit); + rbch_softc[unit].sc_devstate |= ST_NOBLOCK; + } else { +if(bootverbose)printf("EE-rbch%d: clearing non-blocking mode\n", unit); + rbch_softc[unit].sc_devstate &= ~ST_NOBLOCK; + } + break; + case TIOCCDTR: /* Clear DTR */ + if(rbch_softc[unit].sc_devstate & ST_CONNECTED) { +if(bootverbose)printf("EE-rbch%d: disconnecting for DTR down\n", unit); + i4b_l4_disconnect_ind(rbch_softc[unit].cd); + } + break; + case TIOCSDTR: /* Set DTR */ +if(bootverbose)printf("EE-rbch%d: attempting dialout (DTR)\n", unit); + i4b_l4_dialout(BDRV_RBCH, unit); + break; + case TIOCSETA: /* Set termios struct */ + break; + case TIOCGETA: /* Get termios struct */ + *(struct termios *)data = rbch_softc[unit].it_in; + break; + case TIOCMGET: + *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR; + if (rbch_softc[unit].sc_devstate & ST_CONNECTED) + *(int *)data |= TIOCM_CD; + break; + default: /* Unknown stuff */ + printf("\n ========= i4brbch%d - ioctl, unknown cmd %lx ==================== \n", + unit, + (u_long)cmd); + error = EINVAL; + break; + } + return(error); +} + +/*---------------------------------------------------------------------------* + * device driver poll + *---------------------------------------------------------------------------*/ +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || !defined(__FreeBSD__) + +PDEVSTATIC int +i4brbchpoll(dev_t dev, int events, struct proc *p) +{ + int revents = 0; /* Events we found */ + int s; + int unit = minor(dev); + + /* We can't check for anything but IN or OUT */ + + if((events & (POLLIN|POLLOUT)) == 0) + return(POLLNVAL); + + s = splhigh(); + + if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + splx(s); + return(POLLNVAL); + } + + /* + * Writes are OK if we are connected and the + * transmit queue can take them + */ + + if((events & POLLOUT) && + (rbch_softc[unit].sc_devstate & ST_CONNECTED) && + !IF_QFULL(isdn_linktab[unit]->tx_queue)) + { + revents |= POLLOUT; + } + + /* ... while reads are OK if we have any data */ + + if((events & POLLIN) && + (rbch_softc[unit].sc_devstate & ST_CONNECTED)) + { + struct ifqueue *iqp; + + if(rbch_softc[unit].sc_bprot == BPROT_RHDLC) + iqp = &rbch_softc[unit].sc_hdlcq; + else + iqp = isdn_linktab[unit]->rx_queue; + + if(!IF_QEMPTY(iqp)) + revents |= POLLIN; + } + + if(revents == 0) + selrecord(p, &rbch_softc[unit].selp); + + splx(s); + return(revents); +} + +#else + +/*---------------------------------------------------------------------------* + * device driver select + *---------------------------------------------------------------------------*/ +static int +i4brbchselect(dev_t dev, int rw, struct proc *p) +{ + int unit = minor(dev); + int s; + + s = splhigh(); + + if(!(rbch_softc[unit].sc_devstate & ST_ISOPEN)) + { + splx(s); + DBGL4(L4_RBCHDBG, "i4brbchselect", ("unit %d, not open anymore\n", unit)); + return(1); + } + + if(rbch_softc[unit].sc_devstate & ST_CONNECTED) + { + struct ifqueue *iqp; + + switch(rw) + { + case FREAD: + if(rbch_softc[unit].sc_bprot == BPROT_RHDLC) + iqp = &rbch_softc[unit].sc_hdlcq; + else + iqp = isdn_linktab[unit]->rx_queue; + + if(!IF_QEMPTY(iqp)) + return(1); + break; + + case FWRITE: + if(!IF_QFULL(isdn_linktab[unit]->rx_queue)) + return(1); + break; + + default: + return 0; + } + } + selrecord(p, &rbch_softc[unit].selp); + return(0); +} + +#endif /* defined(__FreeBSD_version) && __FreeBSD_version >= 300001 */ + +/*===========================================================================* + * ISDN INTERFACE ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at connect time + *---------------------------------------------------------------------------*/ +static void +rbch_connect(int unit, void *cdp) +{ + call_desc_t *cd = (call_desc_t *)cdp; + + rbch_softc[unit].sc_bprot = cd->bprot; + + if(!(rbch_softc[unit].sc_devstate & ST_CONNECTED)) + { + DBGL4(L4_RBCHDBG, "rbch_connect", ("unit %d, wakeup\n", unit)); + rbch_softc[unit].sc_devstate |= ST_CONNECTED; + rbch_softc[unit].cd = cdp; + wakeup((caddr_t) &rbch_softc[unit]); + } +} + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at disconnect time + *---------------------------------------------------------------------------*/ +static void +rbch_disconnect(int unit, void *cdp) +{ + /* call_desc_t *cd = (call_desc_t *)cdp; */ + + DBGL4(L4_RBCHDBG, "rbch_disconnect", ("unit %d, deinit\n", unit)); + rbch_softc[unit].sc_devstate &= ~ST_CONNECTED; + rbch_softc[unit].cd = NULL; +} + +/*---------------------------------------------------------------------------* + * feedback from daemon in case of dial problems + *---------------------------------------------------------------------------*/ +static void +rbch_dialresponse(int unit, int status) +{ +} + +/*---------------------------------------------------------------------------* + * interface up/down + *---------------------------------------------------------------------------*/ +static void +rbch_updown(int unit, int updown) +{ +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when a new frame (mbuf) has been received and is to be put on + * the rx queue. + *---------------------------------------------------------------------------*/ +static void +rbch_rx_data_rdy(int unit) +{ + if(rbch_softc[unit].sc_bprot == BPROT_RHDLC) + { + register struct mbuf *m; + + if((m = *isdn_linktab[unit]->rx_mbuf) == NULL) + return; + + m->m_pkthdr.len = m->m_len; + + if(IF_QFULL(&(rbch_softc[unit].sc_hdlcq))) + { + DBGL4(L4_RBCHDBG, "rbch_rx_data_rdy", ("unit %d: hdlc rx queue full!\n", unit)); + m_freem(m); + } + else + { + IF_ENQUEUE(&(rbch_softc[unit].sc_hdlcq), m); + } + } + + if(rbch_softc[unit].sc_devstate & ST_RDWAITDATA) + { + DBGL4(L4_RBCHDBG, "rbch_rx_data_rdy", ("unit %d, wakeup\n", unit)); + rbch_softc[unit].sc_devstate &= ~ST_RDWAITDATA; + wakeup((caddr_t) &isdn_linktab[unit]->rx_queue); + } + else + { + DBGL4(L4_RBCHDBG, "rbch_rx_data_rdy", ("unit %d, NO wakeup\n", unit)); + } + selwakeup(&rbch_softc[unit].selp); +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when the last frame has been sent out and there is no + * further frame (mbuf) in the tx queue. + *---------------------------------------------------------------------------*/ +static void +rbch_tx_queue_empty(int unit) +{ + if(rbch_softc[unit].sc_devstate & ST_WRWAITEMPTY) + { + DBGL4(L4_RBCHDBG, "rbch_tx_queue_empty", ("unit %d, wakeup\n", unit)); + rbch_softc[unit].sc_devstate &= ~ST_WRWAITEMPTY; + wakeup((caddr_t) &isdn_linktab[unit]->tx_queue); + } + else + { + DBGL4(L4_RBCHDBG, "rbch_tx_queue_empty", ("unit %d, NO wakeup\n", unit)); + } + selwakeup(&rbch_softc[unit].selp); +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * each time a packet is received or transmitted + *---------------------------------------------------------------------------*/ +static void +rbch_activity(int unit, int rxtx) +{ + if (rbch_softc[unit].cd) + rbch_softc[unit].cd->last_active_time = SECOND; + selwakeup(&rbch_softc[unit].selp); +} + +/*---------------------------------------------------------------------------* + * clear an hdlc rx queue for a rbch unit + *---------------------------------------------------------------------------*/ +static void +rbch_clrq(int unit) +{ + int x; + struct mbuf *m; + + for(;;) + { + x = splimp(); + IF_DEQUEUE(&rbch_softc[unit].sc_hdlcq, m); + splx(x); + if(m) + m_freem(m); + else + break; + } +} + +/*---------------------------------------------------------------------------* + * return this drivers linktab address + *---------------------------------------------------------------------------*/ +drvr_link_t * +rbch_ret_linktab(int unit) +{ + rbch_init_linktab(unit); + return(&rbch_drvr_linktab[unit]); +} + +/*---------------------------------------------------------------------------* + * setup the isdn_linktab for this driver + *---------------------------------------------------------------------------*/ +void +rbch_set_linktab(int unit, isdn_link_t *ilt) +{ + isdn_linktab[unit] = ilt; +} + +/*---------------------------------------------------------------------------* + * initialize this drivers linktab + *---------------------------------------------------------------------------*/ +static void +rbch_init_linktab(int unit) +{ + rbch_drvr_linktab[unit].unit = unit; + rbch_drvr_linktab[unit].bch_rx_data_ready = rbch_rx_data_rdy; + rbch_drvr_linktab[unit].bch_tx_queue_empty = rbch_tx_queue_empty; + rbch_drvr_linktab[unit].bch_activity = rbch_activity; + rbch_drvr_linktab[unit].line_connected = rbch_connect; + rbch_drvr_linktab[unit].line_disconnected = rbch_disconnect; + rbch_drvr_linktab[unit].dial_response = rbch_dialresponse; + rbch_drvr_linktab[unit].updown_ind = rbch_updown; +} + +/*===========================================================================*/ + +#endif /* NI4BRBCH > 0 */ diff --git a/sys/i4b/driver/i4b_tel.c b/sys/i4b/driver/i4b_tel.c new file mode 100644 index 000000000000..81b38a614b06 --- /dev/null +++ b/sys/i4b/driver/i4b_tel.c @@ -0,0 +1,713 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_tel.c - device driver for ISDN telephony + * -------------------------------------------- + * + * $Id: i4b_tel.c,v 1.18 1998/12/14 10:31:53 hm Exp $ + * + * last edit-date: [Mon Dec 14 11:32:06 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4btel.h" + +#if NI4BTEL > 0 + +#undef I4BTELDEBUG + +#include <sys/param.h> +#include <sys/systm.h> + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/proc.h> +#include <sys/tty.h> + +#ifdef __FreeBSD__ +#include "opt_devfs.h" +#endif + +#ifdef DEVFS +#include <sys/devfsext.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_tel_ioctl.h> +#else +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_tel_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_l3l4.h> + +typedef struct { + drvr_link_t drvr_linktab; /* driver linktab */ + isdn_link_t *isdn_linktab; /* isdn linktab */ + int devstate; /* state of this unit */ +#define ST_IDLE 0x00 /* idle */ +#define ST_CONNECTED 0x01 /* isdn connected state */ +#define ST_ISOPEN 0x02 /* userland opened */ +#define ST_RDWAITDATA 0x04 /* userland read waiting */ +#define ST_WRWAITEMPTY 0x08 /* userland write waiting */ + int audiofmt; /* audio format conversion */ + call_desc_t *cdp; /* call descriptor pointer */ +#ifdef DEVFS + void *devfs_token; /* token for DEVFS */ +#endif +} tel_sc_t; + +static tel_sc_t tel_sc[NI4BTEL]; + +/* forward decl */ + +static void tel_rx_data_rdy(int unit); +static void tel_tx_queue_empty(int unit); +static void tel_init_linktab(int unit); +static void tel_connect(int unit, void *cdp); +static void tel_disconnect(int unit, void *cdp); + +static unsigned char alaw_ulaw[]; +static unsigned char ulaw_alaw[]; + +#ifndef __FreeBSD__ +#define PDEVSTATIC /* - not static - */ +PDEVSTATIC void i4btelattach __P((void)); +PDEVSTATIC int i4btelioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +int i4btelopen __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4btelclose __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4btelread __P((dev_t dev, struct uio *uio, int ioflag)); +int i4btelwrite __P((dev_t dev, struct uio * uio, int ioflag)); +#endif +#if BSD > 199306 && defined(__FreeBSD__) +#define PDEVSTATIC static +PDEVSTATIC d_open_t i4btelopen; +PDEVSTATIC d_close_t i4btelclose; +PDEVSTATIC d_read_t i4btelread; +PDEVSTATIC d_read_t i4btelwrite; +PDEVSTATIC d_ioctl_t i4btelioctl; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +PDEVSTATIC d_poll_t i4btelpoll; +#endif + +#define CDEV_MAJOR 56 +static struct cdevsw i4btel_cdevsw = { + i4btelopen, i4btelclose, i4btelread, i4btelwrite, + i4btelioctl, nostop, noreset, nodevtotty, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + i4btelpoll, nommap, NULL, "i4btel", NULL, -1 +#else + noselect, nommap, NULL, "i4btel", NULL, -1 +#endif +}; + +PDEVSTATIC void i4btelinit(void *unused); + +PDEVSTATIC void i4btelattach(void *); +PSEUDO_SET(i4btelattach, i4b_tel); + +/*===========================================================================* + * DEVICE DRIVER ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * initialization at kernel load time + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +i4btelinit(void *unused) +{ + dev_t dev; + + dev = makedev(CDEV_MAJOR, 0); + + cdevsw_add(&dev, &i4btel_cdevsw, NULL); +} + +SYSINIT(i4bteldev, SI_SUB_DRIVERS, + SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btelinit, NULL); + +#endif /* BSD > 199306 && defined(__FreeBSD__) */ + +/*---------------------------------------------------------------------------* + * interface attach routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4btelattach(void *dummy) +#else +i4btelattach() +#endif +{ + int i; + +#ifndef HACK_NO_PSEUDO_ATTACH_MSG + printf("i4btel: %d ISDN telephony interface device(s) attached\n", NI4BTEL); +#endif + + for(i=0; i < NI4BTEL; i++) + { + tel_sc[i].devstate = ST_IDLE; + tel_sc[i].audiofmt = CVT_NONE; + tel_init_linktab(i); +#ifdef DEVFS + tel_sc[i].devfs_token + = devfs_add_devswf(&i4btel_cdevsw, i, DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "i4btel%d", i); +#endif + } +} + +/*---------------------------------------------------------------------------* + * open tel device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btelopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + int unit = minor(dev); + tel_sc_t *sc; + + if(unit > NI4BTEL) + return(ENXIO); + + sc = &tel_sc[unit]; + + if(!(sc->devstate & ST_CONNECTED)) + return(EIO); + + if(sc->devstate & ST_ISOPEN) + return(EBUSY); + + sc->devstate |= ST_ISOPEN; + + return(0); +} + +/*---------------------------------------------------------------------------* + * close tel device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btelclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + int unit = minor(dev); + tel_sc_t *sc; + int error = 0; + + if(unit > NI4BTEL) + return(ENXIO); + + sc = &tel_sc[unit]; + + if(sc->isdn_linktab != NULL && sc->isdn_linktab->tx_queue != NULL) + { + while(!(IF_QEMPTY(sc->isdn_linktab->tx_queue))) + { + sc->devstate |= ST_WRWAITEMPTY; + + if((error = tsleep((caddr_t) &sc->isdn_linktab->tx_queue, + TTIPRI | PCATCH, "wtcl", 0)) != 0) + { + break; + } + } + sc->devstate &= ~ST_WRWAITEMPTY; + } + sc->devstate &= ~ST_ISOPEN; + return(error); +} + +/*---------------------------------------------------------------------------* + * i4btelioctl - device driver ioctl routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300003 +i4btelioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +#else +i4btelioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +#endif +{ + int error = 0; + struct mbuf *m; + int s; + tel_sc_t *sc = &tel_sc[minor(dev)]; + + switch(cmd) + { + case I4B_TEL_GETAUDIOFMT: + *(int *)data = sc->audiofmt; + break; + + case I4B_TEL_SETAUDIOFMT: + sc->audiofmt = *(int *)data; + break; + + case I4B_TEL_EMPTYINPUTQUEUE: + s = splimp(); + while((sc->devstate & ST_CONNECTED) && + (sc->devstate & ST_ISOPEN) && + !IF_QEMPTY(sc->isdn_linktab->rx_queue)) + { + IF_DEQUEUE(sc->isdn_linktab->rx_queue, m); + if(m) + i4b_Bfreembuf(m); + } + splx(s); + break; + + default: + error = ENOTTY; + break; + } + return(error); +} + +/*---------------------------------------------------------------------------* + * read from tel device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btelread(dev_t dev, struct uio *uio, int ioflag) +{ + struct mbuf *m; + int s; + int error = 0; + tel_sc_t *sc = &tel_sc[minor(dev)]; + + if(!(sc->devstate & ST_CONNECTED)) + return(EIO); + + if(!(sc->devstate & ST_ISOPEN)) + return(EIO); + +#ifdef NOTDEF + while(!(sc->devstate & ST_CONNECTED)) + { + if((error = tsleep((caddr_t) &sc->devstate, + TTIPRI | PCATCH, + "rrtel", 0 )) != 0) + { + return(error); + } + } +#endif + + while(IF_QEMPTY(sc->isdn_linktab->rx_queue) && + (sc->devstate & ST_ISOPEN) && + (sc->devstate & ST_CONNECTED)) + { + sc->devstate |= ST_RDWAITDATA; + + if((error = tsleep((caddr_t) &sc->isdn_linktab->rx_queue, + TTIPRI | PCATCH, + "rtel", 0 )) != 0) + { + sc->devstate &= ~ST_RDWAITDATA; + return(error); + } + } + + if(!(sc->devstate & ST_ISOPEN)) + { + return(EIO); + } + + if(!(sc->devstate & ST_CONNECTED)) + { + return(EIO); + } + + s = splimp(); + + IF_DEQUEUE(sc->isdn_linktab->rx_queue, m); + + if(m && m->m_len) + { + if(sc->audiofmt == CVT_ALAW2ULAW) + { + int i; + for(i = 0; i < m->m_len; i++) + m->m_data[i] = alaw_ulaw[(int)m->m_data[i]]; + } + error = uiomove(m->m_data, m->m_len, uio); + } + else + { + error = EIO; + } + + if(m) + i4b_Bfreembuf(m); + + splx(s); + + return(error); +} + +/*---------------------------------------------------------------------------* + * write to tel device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btelwrite(dev_t dev, struct uio * uio, int ioflag) +{ + struct mbuf *m; + int s; + int error = 0; + tel_sc_t *sc = &tel_sc[minor(dev)]; + + if(!(sc->devstate & ST_CONNECTED)) + return(EIO); + + if(!(sc->devstate & ST_ISOPEN)) + { + return(EIO); + } + +#ifdef NOTDEF + while(!(sc->devstate & ST_CONNECTED)) + { + if((error = tsleep((caddr_t) &sc->devstate, + TTIPRI | PCATCH, + "wrtel", 0 )) != 0) + { + return(error); + } + + /* + * XXX the originations B channel gets much earlier + * switched thru than the destinations B channel, so + * if the origination starts to send at once, some + * 200 bytes (at my site) or so get lost, so i delay + * a bit before sending. (-hm) + */ + + tsleep((caddr_t) &sc->devstate, TTIPRI | PCATCH, "xtel", (hz*1)); + } +#endif + + while((IF_QFULL(sc->isdn_linktab->tx_queue)) && + (sc->devstate & ST_ISOPEN)) + { + sc->devstate |= ST_WRWAITEMPTY; + + if((error = tsleep((caddr_t) &sc->isdn_linktab->tx_queue, + TTIPRI | PCATCH, "wtel", 0)) != 0) + { + sc->devstate &= ~ST_WRWAITEMPTY; + return(error); + } + } + + if(!(sc->devstate & ST_ISOPEN)) + { + return(EIO); + } + + if(!(sc->devstate & ST_CONNECTED)) + { + return(EIO); + } + + s = splimp(); + + if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL) + { + m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid); + + error = uiomove(m->m_data, m->m_len, uio); + + if(sc->audiofmt == CVT_ALAW2ULAW) + { + int i; + for(i = 0; i < m->m_len; i++) + m->m_data[i] = ulaw_alaw[(int)m->m_data[i]]; + } + + IF_ENQUEUE(sc->isdn_linktab->tx_queue, m); + + (*sc->isdn_linktab->bch_tx_start)(sc->isdn_linktab->unit, sc->isdn_linktab->channel); + } + + splx(s); + + return(error); +} + +/*---------------------------------------------------------------------------* + * poll + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +PDEVSTATIC int +i4btelpoll (dev_t dev, int events, struct proc *p) +{ + return (ENODEV); +} +#endif + +/*===========================================================================* + * ISDN INTERFACE ROUTINES + *===========================================================================*/ + +/*---------------------------------------------------------------------------* +* this routine is called from L4 handler at connect time + *---------------------------------------------------------------------------*/ +static void +tel_connect(int unit, void *cdp) +{ + tel_sc_t *sc = &tel_sc[unit]; + + sc->cdp = (call_desc_t *)cdp; + +#ifdef NOTDEF + if(!(sc->devstate & ST_CONNECTED)) + { + sc->devstate |= ST_CONNECTED; + wakeup((caddr_t) &sc->devstate); + } +#else + sc->devstate |= ST_CONNECTED; +#endif +} + +/*---------------------------------------------------------------------------* + * this routine is called from L4 handler at disconnect time + *---------------------------------------------------------------------------*/ +static void +tel_disconnect(int unit, void *cdp) +{ +/* call_desc_t *cd = (call_desc_t *)cdp; */ + + tel_sc_t *sc = &tel_sc[unit]; + + sc->devstate &= ~ST_CONNECTED; + + if(sc->devstate & ST_RDWAITDATA) + { + sc->devstate &= ~ST_RDWAITDATA; + wakeup((caddr_t) &sc->isdn_linktab->rx_queue); + } + + if(sc->devstate & ST_WRWAITEMPTY) + { + sc->devstate &= ~ST_WRWAITEMPTY; + wakeup((caddr_t) &sc->isdn_linktab->tx_queue); + } +} + +/*---------------------------------------------------------------------------* + * feedback from daemon in case of dial problems + *---------------------------------------------------------------------------*/ +static void +tel_dialresponse(int unit, int status) +{ +} + +/*---------------------------------------------------------------------------* + * interface up/down + *---------------------------------------------------------------------------*/ +static void +tel_updown(int unit, int updown) +{ +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when a new frame (mbuf) has been received and was put on + * the rx queue. + *---------------------------------------------------------------------------*/ +static void +tel_rx_data_rdy(int unit) +{ + tel_sc_t *sc = &tel_sc[unit]; + + if(sc->devstate & ST_RDWAITDATA) + { + sc->devstate &= ~ST_RDWAITDATA; + wakeup((caddr_t) &sc->isdn_linktab->rx_queue); + } +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * when the last frame has been sent out and there is no + * further frame (mbuf) in the tx queue. + *---------------------------------------------------------------------------*/ +static void +tel_tx_queue_empty(int unit) +{ + tel_sc_t *sc = &tel_sc[unit]; + + if(sc->devstate & ST_WRWAITEMPTY) + { + sc->devstate &= ~ST_WRWAITEMPTY; + wakeup((caddr_t) &sc->isdn_linktab->tx_queue); + } +} + +/*---------------------------------------------------------------------------* + * this routine is called from the HSCX interrupt handler + * each time a packet is received or transmitted. + *---------------------------------------------------------------------------*/ +static void +tel_activity(int unit, int rxtx) +{ + tel_sc[unit].cdp->last_active_time = SECOND; +} + +/*---------------------------------------------------------------------------* + * return this drivers linktab address + *---------------------------------------------------------------------------*/ +drvr_link_t * +tel_ret_linktab(int unit) +{ + tel_sc_t *sc = &tel_sc[unit]; + + tel_init_linktab(unit); + return(&sc->drvr_linktab); +} + +/*---------------------------------------------------------------------------* + * setup the isdn_linktab for this driver + *---------------------------------------------------------------------------*/ +void +tel_set_linktab(int unit, isdn_link_t *ilt) +{ + tel_sc_t *sc = &tel_sc[unit]; + sc->isdn_linktab = ilt; +} + +/*---------------------------------------------------------------------------* + * initialize this drivers linktab + *---------------------------------------------------------------------------*/ +static void +tel_init_linktab(int unit) +{ + tel_sc_t *sc = &tel_sc[unit]; + + sc->drvr_linktab.unit = unit; + sc->drvr_linktab.bch_rx_data_ready = tel_rx_data_rdy; + sc->drvr_linktab.bch_tx_queue_empty = tel_tx_queue_empty; + sc->drvr_linktab.bch_activity = tel_activity; + sc->drvr_linktab.line_connected = tel_connect; + sc->drvr_linktab.line_disconnected = tel_disconnect; + sc->drvr_linktab.dial_response = tel_dialresponse; + sc->drvr_linktab.updown_ind = tel_updown; +} + +/*===========================================================================* + * AUDIO FORMAT CONVERSION + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * A-law to mu-law conversion + *---------------------------------------------------------------------------*/ +static unsigned char alaw_ulaw[] = { + 0x002a, 0x00a9, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0048, 0x00c8, + 0x0039, 0x00b9, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0055, 0x00d7, + 0x0022, 0x00a1, 0x005b, 0x00dd, 0x001f, 0x009f, 0x0040, 0x00c0, + 0x0031, 0x00b1, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004e, 0x00cf, + 0x002e, 0x00ad, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004c, 0x00cc, + 0x003d, 0x00bd, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0059, 0x00db, + 0x0026, 0x00a5, 0x005d, 0x00df, 0x001f, 0x009f, 0x0044, 0x00c4, + 0x0035, 0x00b5, 0x006b, 0x00ef, 0x001f, 0x009f, 0x0051, 0x00d3, + 0x0028, 0x00a7, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0046, 0x00c6, + 0x0037, 0x00b7, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0053, 0x00d5, + 0x0020, 0x009f, 0x005b, 0x00dd, 0x001f, 0x009f, 0x003f, 0x00bf, + 0x002f, 0x00af, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004d, 0x00ce, + 0x002c, 0x00ab, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004a, 0x00ca, + 0x003b, 0x00bb, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0057, 0x00d9, + 0x0024, 0x00a3, 0x005d, 0x00df, 0x001f, 0x009f, 0x0042, 0x00c2, + 0x0033, 0x00b3, 0x006b, 0x00ef, 0x001f, 0x009f, 0x004f, 0x00d1, + 0x002b, 0x00aa, 0x0063, 0x00e3, 0x001f, 0x009f, 0x0049, 0x00c9, + 0x003a, 0x00ba, 0x0077, 0x00f7, 0x001f, 0x009f, 0x0057, 0x00d7, + 0x0023, 0x00a2, 0x005d, 0x00dd, 0x001f, 0x009f, 0x0041, 0x00c1, + 0x0032, 0x00b2, 0x006b, 0x00eb, 0x001f, 0x009f, 0x004f, 0x00cf, + 0x002f, 0x00ae, 0x0067, 0x00e7, 0x001f, 0x009f, 0x004d, 0x00cd, + 0x003e, 0x00be, 0x00ff, 0x00ff, 0x001f, 0x009f, 0x005b, 0x00db, + 0x0027, 0x00a6, 0x005f, 0x00df, 0x001f, 0x009f, 0x0045, 0x00c5, + 0x0036, 0x00b6, 0x006f, 0x00ef, 0x001f, 0x009f, 0x0053, 0x00d3, + 0x0029, 0x00a8, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0047, 0x00c7, + 0x0038, 0x00b8, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0055, 0x00d5, + 0x0021, 0x00a0, 0x005b, 0x00dd, 0x001f, 0x009f, 0x003f, 0x00bf, + 0x0030, 0x00b0, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004e, 0x00ce, + 0x002d, 0x00ac, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004b, 0x00cb, + 0x003c, 0x00bc, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0059, 0x00d9, + 0x0025, 0x00a4, 0x005d, 0x00df, 0x001f, 0x009f, 0x0043, 0x00c3, + 0x0034, 0x00b4, 0x006b, 0x00ef, 0x001f, 0x009f, 0x0051, 0x00d1 +}; + +/*---------------------------------------------------------------------------* + * mu-law to A-law conversion + *---------------------------------------------------------------------------*/ +static unsigned char ulaw_alaw[] = { + 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, + 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, + 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, + 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00ac, + 0x0050, 0x00d0, 0x0010, 0x0090, 0x0070, 0x00f0, 0x0030, 0x00b0, + 0x0040, 0x00c0, 0x0000, 0x0080, 0x0060, 0x00e0, 0x0020, 0x00a0, + 0x00d8, 0x0018, 0x0098, 0x0078, 0x00f8, 0x0038, 0x00b8, 0x0048, + 0x00c8, 0x0008, 0x0088, 0x0068, 0x00e8, 0x0028, 0x00a8, 0x00d6, + 0x0096, 0x0076, 0x00f6, 0x0036, 0x00b6, 0x0046, 0x00c6, 0x0006, + 0x0086, 0x0066, 0x00e6, 0x0026, 0x00a6, 0x00de, 0x009e, 0x00fe, + 0x00fe, 0x00be, 0x00be, 0x00ce, 0x00ce, 0x008e, 0x008e, 0x00ee, + 0x00ee, 0x00d2, 0x00d2, 0x00f2, 0x00f2, 0x00c2, 0x00c2, 0x00e2, + 0x00e2, 0x00e2, 0x00da, 0x00da, 0x00da, 0x00da, 0x00fa, 0x00fa, + 0x00fa, 0x00fa, 0x00ca, 0x00ca, 0x00ca, 0x00ca, 0x00ea, 0x00ea, + 0x00ea, 0x00ea, 0x00ea, 0x00ea, 0x00eb, 0x00eb, 0x00eb, 0x00eb, + 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, + 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, + 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, + 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, + 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, + 0x00d1, 0x0011, 0x0091, 0x0071, 0x00f1, 0x0031, 0x00b1, 0x0041, + 0x00c1, 0x0001, 0x0081, 0x0061, 0x00e1, 0x0021, 0x00a1, 0x0059, + 0x00d9, 0x0019, 0x0099, 0x0079, 0x00f9, 0x0039, 0x00b9, 0x0049, + 0x00c9, 0x0009, 0x0089, 0x0069, 0x00e9, 0x0029, 0x00a9, 0x0057, + 0x0017, 0x0097, 0x0077, 0x00f7, 0x0037, 0x00b7, 0x0047, 0x00c7, + 0x0007, 0x0087, 0x0067, 0x00e7, 0x0027, 0x00a7, 0x00df, 0x009f, + 0x009f, 0x00ff, 0x00ff, 0x00bf, 0x00bf, 0x00cf, 0x00cf, 0x008f, + 0x008f, 0x00ef, 0x00ef, 0x00af, 0x00af, 0x00d3, 0x00d3, 0x00f3, + 0x00f3, 0x00f3, 0x00c3, 0x00c3, 0x00c3, 0x00c3, 0x00e3, 0x00e3, + 0x00e3, 0x00e3, 0x00db, 0x00db, 0x00db, 0x00db, 0x00fb, 0x00fb, + 0x00fb, 0x00fb, 0x00fb, 0x00fb, 0x00cb, 0x00cb, 0x00cb, 0x00cb, + 0x00cb, 0x00cb, 0x00cb, 0x00cb, 0x00eb, 0x00eb, 0x00eb, 0x00eb +}; + +/*===========================================================================*/ + +#endif /* NI4BTEL > 0 */ diff --git a/sys/i4b/driver/i4b_trace.c b/sys/i4b/driver/i4b_trace.c new file mode 100644 index 000000000000..f64e35d622fd --- /dev/null +++ b/sys/i4b/driver/i4b_trace.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4btrc - device driver for trace data read device + * --------------------------------------------------- + * + * $Id: i4b_trace.c,v 1.14 1998/12/05 18:02:51 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:01:53 1998] + * + * NOTE: the code assumes that SPLI4B >= splimp ! + * + *---------------------------------------------------------------------------*/ + +#include "i4btrc.h" + +#if NI4BTRC > 0 + +#ifdef __FreeBSD__ +#include "isic.h" /* 'isic' is no pseudo-device on non FreeBSD - + * so we just can't count it at compile time, + * we're doing an attach-time check instead. */ + +#if NI4BTRC < NISIC +#error "number of trace devices != number of passive ISDN controllers !" +#error "change number of i4btrc to be equal to number of isic devices !" +#endif +#endif /* __FreeBSD__ */ + +#include <sys/param.h> +#include <sys/systm.h> + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/proc.h> +#include <sys/tty.h> + +#ifdef __FreeBSD__ +#include "opt_devfs.h" +#endif + +#ifdef DEVFS +#include <sys/devfsext.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_trace.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_trace.h> +#include <i4b/i4b_ioctl.h> +#endif + +#ifndef __FreeBSD__ +#define memcpy(d,s,l) bcopy(s,d,l) +#endif + +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l3l4.h> + +static struct ifqueue trace_queue[NI4BTRC]; +static int device_state[NI4BTRC]; +#define ST_IDLE 0x00 +#define ST_ISOPEN 0x01 +#define ST_WAITDATA 0x02 +#ifdef DEVFS +static void *devfs_token[NI4BTRC]; +#endif + +static int analyzemode = 0; +static int rxunit = -1; +static int txunit = -1; +static int outunit = -1; + +#ifndef __FreeBSD__ +#define PDEVSTATIC /* - not static - */ +void i4btrcattach __P((void)); +int i4btrcopen __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4btrcclose __P((dev_t dev, int flag, int fmt, struct proc *p)); +int i4btrcread __P((dev_t dev, struct uio * uio, int ioflag)); +int i4btrcioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +#endif + +#if BSD > 199306 && defined(__FreeBSD__) +#define PDEVSTATIC static +static d_open_t i4btrcopen; +static d_close_t i4btrcclose; +static d_read_t i4btrcread; +static d_ioctl_t i4btrcioctl; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +static d_poll_t i4btrcpoll; +#endif + +#define CDEV_MAJOR 59 +static struct cdevsw i4btrc_cdevsw = { + i4btrcopen, i4btrcclose, i4btrcread, nowrite, + i4btrcioctl, nostop, noreset, nodevtotty, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + i4btrcpoll, nommap, NULL, "i4btrc", NULL, -1 +#else + noselect, nommap, NULL, "i4btrc", NULL, -1 +#endif +}; + +/*---------------------------------------------------------------------------* + * interface init routine + *---------------------------------------------------------------------------*/ +static +void i4btrcinit(void *unused) +{ + dev_t dev; + + dev = makedev(CDEV_MAJOR, 0); + + cdevsw_add(&dev, &i4btrc_cdevsw, NULL); +} + +SYSINIT(i4btrcdev, SI_SUB_DRIVERS, + SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btrcinit, NULL); + +static void i4btrcattach(void *); +PSEUDO_SET(i4btrcattach, i4b_trace); + +#endif /* BSD > 199306 && defined(__FreeBSD__) */ + +int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf); + +/*---------------------------------------------------------------------------* + * interface attach routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4btrcattach(void *dummy) +#else +i4btrcattach() +#endif +{ + int i; + +#ifndef HACK_NO_PSEUDO_ATTACH_MSG + printf("i4btrc: %d ISDN trace device(s) attached\n", NI4BTRC); +#endif + + for(i=0; i < NI4BTRC; i++) + { +#ifdef DEVFS + devfs_token[i] + = devfs_add_devswf(&i4btrc_cdevsw, i, DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "i4btrc%d", i); +#endif + trace_queue[i].ifq_maxlen = IFQ_MAXLEN; + device_state[i] = ST_IDLE; + } +} + +/*---------------------------------------------------------------------------* + * get_trace_data_from_l1() + * ------------------------ + * is called from layer 1, adds timestamp to trace data and puts + * it into a queue, from which it can be read from the i4btrc + * device. The unit number in the trace header selects the minor + * device's queue the data is put into. + *---------------------------------------------------------------------------*/ +int +get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf) +{ + struct mbuf *m; + int x; + int unit; + int trunc = 0; + int totlen = len + sizeof(i4b_trace_hdr_t); + + /* + * for telephony (or better non-HDLC HSCX mode) we get + * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets + * to put into the queue to userland. because of this + * we detect this situation, strip the length to MCLBYTES + * max size, and infor the userland program of this fact + * by putting the no of truncated bytes into hdr->trunc. + */ + + if(totlen > MCLBYTES) + { + trunc = 1; + hdr->trunc = totlen - MCLBYTES; + totlen = MCLBYTES; + } + else + { + hdr->trunc = 0; + } + + /* set length of trace record */ + + hdr->length = totlen; + + /* check valid unit no */ + + if((unit = hdr->unit) > NI4BTRC) + { + printf("i4b_trace: get_trace_data_from_l1 - unit > NI4BTRC!\n"); + return(0); + } + + /* get mbuf */ + + if(!(m = i4b_Bgetmbuf(totlen))) + { + printf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n"); + return(0); + } + + /* check if we are in analyzemode */ + + if(analyzemode && (unit == rxunit || unit == txunit)) + { + if(unit == rxunit) + hdr->dir = FROM_NT; + else + hdr->dir = FROM_TE; + unit = outunit; + } + + if(IF_QFULL(&trace_queue[unit])) + { + struct mbuf *m1; + + x = SPLI4B(); + IF_DEQUEUE(&trace_queue[unit], m1); + splx(x); + + i4b_Bfreembuf(m1); + } + + /* copy trace header */ + memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr_t)); + + /* copy trace data */ + if(trunc) + memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, totlen-sizeof(i4b_trace_hdr_t)); + else + memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, len); + + x = SPLI4B(); + + IF_ENQUEUE(&trace_queue[unit], m); + + if(device_state[unit] & ST_WAITDATA) + { + device_state[unit] &= ~ST_WAITDATA; + wakeup((caddr_t) &trace_queue[unit]); + } + + splx(x); + + return(1); +} + +/*---------------------------------------------------------------------------* + * open trace device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btrcopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + int x; + int unit = minor(dev); + + if(unit > NI4BTRC) + return(ENXIO); + + if(device_state[unit] & ST_ISOPEN) + return(EBUSY); + + if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit)) + return(EBUSY); + + x = SPLI4B(); + + device_state[unit] = ST_ISOPEN; + + splx(x); + + return(0); +} + +/*---------------------------------------------------------------------------* + * close trace device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btrcclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + int unit = minor(dev); + int i, x, cno = -1; + + for(i = 0; i < nctrl; i++) + { + if(ctrl_desc[i].N_SET_TRACE) + { + cno = i; + break; + } + } + + if(analyzemode && (unit == outunit)) + { + analyzemode = 0; + outunit = -1; + + if(cno >= 0) + { + ctrl_desc[cno].N_SET_TRACE(rxunit, TRACE_OFF); + ctrl_desc[cno].N_SET_TRACE(txunit, TRACE_OFF); + } + rxunit = -1; + txunit = -1; + } + + if(cno >= 0) + { + ctrl_desc[cno].N_SET_TRACE(unit, TRACE_OFF); + } + + x = SPLI4B(); + device_state[unit] = ST_IDLE; + splx(x); + + return(0); +} + +/*---------------------------------------------------------------------------* + * read from trace device + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4btrcread(dev_t dev, struct uio * uio, int ioflag) +{ + struct mbuf *m; + int x; + int error = 0; + int unit = minor(dev); + + if(!(device_state[unit] & ST_ISOPEN)) + return(EIO); + + x = SPLI4B(); + + while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN)) + { + device_state[unit] |= ST_WAITDATA; + + if((error = tsleep((caddr_t) &trace_queue[unit], + TTIPRI | PCATCH, + "bitrc", 0 )) != 0) + { + device_state[unit] &= ~ST_WAITDATA; + splx(x); + return(error); + } + } + + IF_DEQUEUE(&trace_queue[unit], m); + + if(m && m->m_len) + error = uiomove(m->m_data, m->m_len, uio); + else + error = EIO; + + if(m) + i4b_Bfreembuf(m); + + splx(x); + + return(error); +} + +/*---------------------------------------------------------------------------* + * poll device + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +PDEVSTATIC int +i4btrcpoll(dev_t dev, int events, struct proc *p) +{ + return(ENODEV); +} +#endif + +/*---------------------------------------------------------------------------* + * device driver ioctl routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003 +i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +#else +i4btrcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +#endif +{ + int error = 0; + int unit = minor(dev); + i4b_trace_setupa_t *tsa; + int i, cno = -1; + + /* find the first passive controller to get at the set/get function + pointers. Would be better if we had the controller class virtual + function table separate from the port registry... */ + + for(i=0; i < nctrl; i++) + { + if(ctrl_desc[i].N_SET_TRACE) + { + cno = i; /* one suitable controller, might not */ + break; /* be related to the trace unit at all, but */ + } /* has the right function pointers */ + } + + switch(cmd) + { + case I4B_TRC_GET: + if(cno < 0) + return ENOTTY; + *(int *)data = ctrl_desc[cno].N_GET_TRACE(unit); + break; + + case I4B_TRC_SET: + if(cno < 0) + return ENOTTY; + ctrl_desc[cno].N_SET_TRACE(unit, *(int *)data); + break; + + case I4B_TRC_SETA: + tsa = (i4b_trace_setupa_t *)data; + + if(tsa->rxunit >= 0 && tsa->rxunit < NI4BTRC) + rxunit = tsa->rxunit; + else + error = EINVAL; + + if(tsa->txunit >= 0 && tsa->txunit < NI4BTRC) + txunit = tsa->txunit; + else + error = EINVAL; + + if(error) + { + outunit = -1; + rxunit = -1; + txunit = -1; + } + else + { + if(cno < 0) + return ENOTTY; + + outunit = unit; + analyzemode = 1; + ctrl_desc[cno].N_SET_TRACE(rxunit, tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)); + ctrl_desc[cno].N_SET_TRACE(txunit, tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)); + } + break; + + case I4B_TRC_RESETA: + analyzemode = 0; + outunit = -1; + rxunit = -1; + txunit = -1; + break; + + default: + error = ENOTTY; + break; + } + return(error); +} + +#endif /* NI4BTRC > 0 */ diff --git a/sys/i4b/include/i4b_cause.h b/sys/i4b/include/i4b_cause.h new file mode 100644 index 000000000000..439db4e2bcc4 --- /dev/null +++ b/sys/i4b/include/i4b_cause.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_cause.h - causes and cause handling for i4b + * ----------------------------------------------- + * + * $Id: i4b_cause.h,v 1.8 1998/12/05 18:05:55 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:36:30 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_CAUSE_H_ +#define _I4B_CAUSE_H_ + +/*---------------------------------------------------------------------------* + * ISDN4BSD internal causes specification + *---------------------------------------------------------------------------*/ + +#define CAUSE_VAL 0x000000ff /* cause value */ +#define CAUSE_TYPE 0x0000ff00 /* cause type */ +#define CAUSET_Q850 0 /* value coded according to Q.850 */ +#define CAUSET_I4B 1 /* i4b protocol independent causes*/ + +#define GET_CAUSE_VAL(cause) ((cause) & 0xff) +#define SET_CAUSE_VAL(dest, val) ((dest) = ((dest & 0xffffff00) | \ + (val & 0x000000ff))) + +#define GET_CAUSE_TYPE(cause) (((cause) >> 8) & 0xff) +#define SET_CAUSE_TYPE(dest, type) ((dest) = ((dest & 0xffff00ff) | \ + ((type << 8) & 0x0000ff00))) + +#define SET_CAUSE_TV(dest, type, val) ((dest) = ((val & 0x000000ff) | \ + ((type << 8) & 0x0000ff00))) + +/* CAUSET_I4B - protocol independent cause values */ + +#define CAUSE_I4B_NORMAL 0 /* normal call clearing */ +#define CAUSE_I4B_BUSY 1 /* user busy */ +#define CAUSE_I4B_NOCHAN 2 /* circuit/channel not available*/ +#define CAUSE_I4B_INCOMP 3 /* incompatible source/dest */ +#define CAUSE_I4B_REJECT 4 /* call rejected */ +#define CAUSE_I4B_OOO 5 /* destination out of order */ +#define CAUSE_I4B_TMPFAIL 6 /* temporary failure */ +#define CAUSE_I4B_L1ERROR 7 /* L1 error / persistent deact */ +#define CAUSE_I4B_MAX 8 + +/* CAUSET_Q850 - causes defined in Q.850 */ + +#define CAUSE_Q850_SHUTDN 0x00 /* normal D-channel shutdown */ +#define CAUSE_Q850_NUNALLC 0x01 /* Unallocated (unassigned) number */ +#define CAUSE_Q850_NRTTN 0x02 /* No route to specified transit network */ +#define CAUSE_Q850_NRTDST 0x03 /* No route to destination */ +#define CAUSE_Q850_SSINFTN 0x04 /* Send special information tone */ +#define CAUSE_Q850_MDIALTP 0x05 /* Misdialled trunk prefix */ +#define CAUSE_Q850_CHUNACC 0x06 /* Channel unacceptable */ +#define CAUSE_Q850_CALLAWD 0x07 /* Call awarded and being delivered in an established channel */ +#define CAUSE_Q850_PREEMPT 0x08 /* Preemption */ +#define CAUSE_Q850_PREECRR 0x09 /* Preemption - circuit reserved for reuse */ +#define CAUSE_Q850_NCCLR 0x10 /* Normal call clearing */ +#define CAUSE_Q850_USRBSY 0x11 /* User busy */ +#define CAUSE_Q850_NOUSRRSP 0x12 /* No user responding */ +#define CAUSE_Q850_NOANSWR 0x13 /* No answer from user (user alerted) */ +#define CAUSE_Q850_SUBSABS 0x14 /* Subscriber absent */ +#define CAUSE_Q850_CALLREJ 0x15 /* Call rejected */ +#define CAUSE_Q850_NUCHNG 0x16 /* Number changed */ +#define CAUSE_Q850_NONSELUC 0x1A /* Non-selected user clearing */ +#define CAUSE_Q850_DSTOOORDR 0x1B /* Destination out of order */ +#define CAUSE_Q850_INVNUFMT 0x1C /* Invalid number format */ +#define CAUSE_Q850_FACREJ 0x1D /* Facility rejected */ +#define CAUSE_Q850_STENQRSP 0x1E /* Response to STATUS ENQUIRY */ +#define CAUSE_Q850_NORMUNSP 0x1F /* Normal, unspecified */ +#define CAUSE_Q850_NOCAVAIL 0x22 /* No circuit / channel available */ +#define CAUSE_Q850_NETOOORDR 0x26 /* Network out of order */ +#define CAUSE_Q850_PFMCDOOSERV 0x27 /* Permanent frame mode connection out of service */ +#define CAUSE_Q850_PFMCOPER 0x28 /* Permanent frame mode connection operational */ +#define CAUSE_Q850_TMPFAIL 0x29 /* Temporary failure */ +#define CAUSE_Q850_SWEQCONG 0x2A /* Switching equipment congestion */ +#define CAUSE_Q850_ACCINFDIS 0x2B /* Access information discarded */ +#define CAUSE_Q850_REQCNOTAV 0x2C /* Requested circuit/channel not available */ +#define CAUSE_Q850_PRECALBLK 0x2E /* Precedence call blocked */ +#define CAUSE_Q850_RESUNAVAIL 0x2F /* Resources unavailable, unspecified */ +#define CAUSE_Q850_QOSUNAVAIL 0x31 /* Quality of service unavailable */ +#define CAUSE_Q850_REQSERVNS 0x32 /* Requested facility not subscribed */ +#define CAUSE_Q850_OCBARRCUG 0x35 /* Outgoing calls barred within CUG */ +#define CAUSE_Q850_ICBARRCUG 0x36 /* Incoming calls barred within CUG */ +#define CAUSE_Q850_BCAPNAUTH 0x39 /* Bearer capability not authorized */ +#define CAUSE_Q850_BCAPNAVAIL 0x3A /* Bearer capability not presently available */ +#define CAUSE_Q850_INCSTOACISC 0x3E /* Inconsistenciy in designated outgoing access information and subscriber class */ +#define CAUSE_Q850_SOONOTAVAIL 0x3F /* Service or option not available, unspecified */ +#define CAUSE_Q850_BCAPNOTIMPL 0x41 /* Bearer capability not implemented */ +#define CAUSE_Q850_CHTYPNIMPL 0x42 /* Channel type not implemented */ +#define CAUSE_Q850_REQFACNIMPL 0x45 /* Requested facility not implemented */ +#define CAUSE_Q850_ORDINBCAVL 0x46 /* Only restricted digital information bearer capability is available */ +#define CAUSE_Q850_SOONOTIMPL 0x4F /* Service or option not implemented, unspecified */ +#define CAUSE_Q850_INVCLRFVAL 0x51 /* Invalid call reference value */ +#define CAUSE_Q850_IDCHDNOEX 0x52 /* Identified channel does not exist */ +#define CAUSE_Q850_SUSCAEXIN 0x53 /* A suspended call exists, but this call identity does not */ +#define CAUSE_Q850_CLIDINUSE 0x54 /* Call identity in use */ +#define CAUSE_Q850_NOCLSUSP 0x55 /* No call suspended */ +#define CAUSE_Q850_CLIDCLRD 0x56 /* Call having the requested call identity has been cleared */ +#define CAUSE_Q850_UNOTMEMCUG 0x57 /* User not member of CUG */ +#define CAUSE_Q850_INCDEST 0x58 /* Incompatible destination */ +#define CAUSE_Q850_NONEXCUG 0x5A /* Non-existent CUG */ +#define CAUSE_Q850_INVNTWSEL 0x5B /* Invalid transit network selection */ +#define CAUSE_Q850_INVMSG 0x5F /* Invalid message, unspecified */ +#define CAUSE_Q850_MIEMISS 0x60 /* Mandatory information element is missing */ +#define CAUSE_Q850_MSGTNI 0x61 /* Message type non-existent or not implemented */ +#define CAUSE_Q850_MSGNCMPT 0x62 /* Message not compatible with call state or message type non-existent or not implemented */ +#define CAUSE_Q850_IENENI 0x63 /* Information element/parameter non-existent or not implemented */ +#define CAUSE_Q850_INVIEC 0x64 /* Invalid information element contents */ +#define CAUSE_Q850_MSGNCWCS 0x65 /* Message not compatible with call state */ +#define CAUSE_Q850_RECOTIMEXP 0x66 /* Recovery on timer expiry */ +#define CAUSE_Q850_PARMNENIPO 0x67 /* Parameter non-existent or not implemented, passed on */ +#define CAUSE_Q850_MSGUNRDPRM 0x6E /* Message with unrecognized parameter, discarded */ +#define CAUSE_Q850_PROTERR 0x6F /* Protocol error, unspecified */ +#define CAUSE_Q850_INTWRKU 0x7F /* Interworking, unspecified */ + +#define CAUSE_Q850_MAX 128 + +#endif /* _I4B_CAUSE_H_ */ diff --git a/sys/i4b/include/i4b_debug.h b/sys/i4b/include/i4b_debug.h new file mode 100644 index 000000000000..33e6315ba285 --- /dev/null +++ b/sys/i4b/include/i4b_debug.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_debug.h - i4b debug header file + * ----------------------------------- + * + * $Id: i4b_debug.h,v 1.14 1998/12/05 18:05:57 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:36:47 1998] + * + *---------------------------------------------------------------------------*/ + +#define DO_I4B_DEBUG /* enable debugging code inclusion */ + +#undef DO_I4B_MAXDEBUG /* enable ALL debug messages by default */ + +#ifdef DO_I4B_DEBUG + +extern unsigned int i4b_l1_debug; +extern unsigned int i4b_l2_debug; +extern unsigned int i4b_l3_debug; +extern unsigned int i4b_l4_debug; + +#define DBGL1(bits, routine, what) \ + if(bits & i4b_l1_debug) \ + { \ + printf("i4b-L1-%s: ", routine); \ + printf what ; \ + } + +#define DBGL2(bits, routine, what) \ + if(bits & i4b_l2_debug) \ + { \ + printf("i4b-L2-%s: ", routine); \ + printf what ; \ + } + +#define DBGL3(bits, routine, what) \ + if(bits & i4b_l3_debug) \ + { \ + printf("i4b-L3-%s: ", routine); \ + printf what ; \ + } + +#define DBGL4(bits, routine, what) \ + if(bits & i4b_l4_debug) \ + { \ + printf("i4b-L4-%s: ", routine); \ + printf what ; \ + } +#else /* !DO_I4B_DEBUG */ + +#define DBGL1(bits, routine, what); +#define DBGL2(bits, routine, what); +#define DBGL3(bits, routine, what); +#define DBGL4(bits, routine, what); + +#endif /* DO_I4B_DEBUG */ + +/* Layer 1 */ + +#define L1_ERROR 0x0001 /* general error message*/ +#define L1_PRIM 0x0002 /* interlayer primitives*/ +#define L1_BCHAN 0x0004 /* B channel action */ +#define L1_H_ERR 0x0008 /* HSCX errors */ +#define L1_H_IRQ 0x0010 /* HSCX IRQ messages */ +#define L1_I_ERR 0x0020 /* ISAC errors */ +#define L1_I_MSG 0x0040 /* ISAC messages */ +#define L1_I_SETUP 0x0080 /* ISAC setup messages */ +#define L1_F_MSG 0x0100 /* FSM messages */ +#define L1_F_ERR 0x0200 /* FSM error messages */ +#define L1_T_MSG 0x0400 /* Timer messages */ +#define L1_T_ERR 0x0800 /* Timer error messages */ +#define L1_H_XFRERR 0x1000 /* HSCX data xfer error */ +#define L1_I_CICO 0x2000 /* ISAC command in/out */ + +#define L1_DEBUG_MAX 0x3fef /* all messages on except IRQ! */ +#define L1_DEBUG_ERR (L1_H_ERR | L1_I_ERR | L1_F_ERR | L1_T_ERR | L1_ERROR) + +#ifndef L1_DEBUG_DEFAULT +#ifdef DO_I4B_MAXDEBUG +#define L1_DEBUG_DEFAULT L1_DEBUG_MAX +#else +#define L1_DEBUG_DEFAULT L1_DEBUG_ERR +#endif +#endif + +/* Layer 2 */ + +#define L2_ERROR 0x0001 /* general error message */ +#define L2_PRIM 0x0002 /* interlayer primitives */ +#define L2_U_MSG 0x0004 /* U frame messages */ +#define L2_U_ERR 0x0008 /* U frame error messages */ +#define L2_S_MSG 0x0010 /* S frame messages */ +#define L2_S_ERR 0x0020 /* S frame error messages */ +#define L2_I_MSG 0x0040 /* I frame messages */ +#define L2_I_ERR 0x0080 /* I frame error messages */ +#define L2_F_MSG 0x0100 /* FSM messages */ +#define L2_F_ERR 0x0200 /* FSM error messages */ +#define L2_T_MSG 0x0400 /* timer messages */ +#define L2_T_ERR 0x0800 /* timer error messages */ +#define L2_TEI_MSG 0x1000 /* TEI messages */ +#define L2_TEI_ERR 0x2000 /* TEI error messages */ + +#define L2_DEBUG_MAX 0x3fff /* all messages on */ +#define L2_DEBUG_ERR (L2_ERROR | L2_I_ERR | L2_F_ERR | L2_T_ERR | L2_S_ERR | L2_TEI_ERR | L2_U_ERR ) + +#ifndef L2_DEBUG_DEFAULT +#ifdef DO_I4B_MAXDEBUG +#define L2_DEBUG_DEFAULT L2_DEBUG_MAX +#else +#define L2_DEBUG_DEFAULT L2_DEBUG_ERR +#endif +#endif + +/* Layer 3 */ + +#define L3_ERR 0x0001 /* general error message */ +#define L3_MSG 0x0002 /* general message */ +#define L3_F_MSG 0x0004 /* FSM messages */ +#define L3_F_ERR 0x0008 /* FSM error messages */ +#define L3_T_MSG 0x0010 /* timer messages */ +#define L3_T_ERR 0x0020 /* timer error messages */ +#define L3_P_MSG 0x0040 /* protocol messages */ +#define L3_P_ERR 0x0080 /* protocol error messages */ +#define L3_A_MSG 0x0100 /* AOC messages */ +#define L3_A_ERR 0x0200 /* AOC error messages */ +#define L3_PRIM 0x0400 /* messages exchanged */ + +#define L3_DEBUG_MAX 0x07ff /* all messages on */ +#define L3_DEBUG_ERR (L3_ERR | L3_F_ERR | L3_T_ERR | L3_P_ERR | L3_A_ERR) + +#ifndef L3_DEBUG_DEFAULT +#ifdef DO_I4B_MAXDEBUG +#define L3_DEBUG_DEFAULT L3_DEBUG_MAX +#else +#define L3_DEBUG_DEFAULT L3_DEBUG_ERR +#endif +#endif + +/* Layer 4 */ + +#define L4_ERR 0x0001 /* general error message */ +#define L4_MSG 0x0002 /* general message */ +#define L4_TIMO 0x0004 /* b channel idle timeout msgs */ +#define L4_DIALST 0x0008 /* network driver dial states */ +#define L4_IPRDBG 0x0010 /* ipr driver debug messages */ +#define L4_RBCHDBG 0x0020 /* rbch driver debug messages */ + +#define L4_DEBUG_MAX 0x003f /* all messages on */ +#define L4_DEBUG_ERR (L4_ERR) + +#ifndef L4_DEBUG_DEFAULT +#ifdef DO_I4B_MAXDEBUG +#define L4_DEBUG_DEFAULT L4_DEBUG_MAX +#else +#define L4_DEBUG_DEFAULT L4_DEBUG_ERR +#endif +#endif + +/*---------------------------------------------------------------------------* + * ioctl via /dev/i4bctl: + * get/set current debug bits settings + *---------------------------------------------------------------------------*/ + +typedef struct { + unsigned int l1; + unsigned int l2; + unsigned int l3; + unsigned int l4; +} ctl_debug_t; + +#define I4B_CTL_GET_DEBUG _IOR('C', 0, ctl_debug_t) + +#define I4B_CTL_SET_DEBUG _IOW('C', 1, ctl_debug_t) + +/*---------------------------------------------------------------------------* + * get hscx statistics + *---------------------------------------------------------------------------*/ + +typedef struct { + int unit; /* controller number */ + int chan; /* channel number */ + int vfr; + int rdo; + int crc; + int rab; + int xdu; + int rfo; +} hscxstat_t; + +#define I4B_CTL_GET_HSCXSTAT _IOWR('C', 2, hscxstat_t) + +#define I4B_CTL_CLR_HSCXSTAT _IOW('C', 3, hscxstat_t) + +/* EOF */ diff --git a/sys/i4b/include/i4b_global.h b/sys/i4b/include/i4b_global.h new file mode 100644 index 000000000000..739d78d6b3ed --- /dev/null +++ b/sys/i4b/include/i4b_global.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_global.h - i4b global include file + * -------------------------------------- + * + * $Id: i4b_global.h,v 1.17 1998/12/05 18:02:53 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:03:41 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_GLOBAL_H_ +#define _I4B_GLOBAL_H_ + +#define SPLI4B() splimp() /* spl for i4b */ + +#define TIMER_IDLE 1 /* a timer is running */ +#define TIMER_ACTIVE 2 /* a timer is idle */ + +#ifdef __FreeBSD__ +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + +#define TIMEOUT_FUNC_T timeout_t * +#define SECOND time_second +#define MICROTIME(x) getmicrotime(&(x)) + +#else /* FreeBSD < 3 */ + +#define TIMEOUT_FUNC_T timeout_func_t +#define SECOND time.tv_sec +#define MICROTIME(x) microtime(&(x)) + +#endif /* >= 3 */ +#endif /* __FreeBSD__ */ + +#if defined(__NetBSD__) || defined (__OpenBSD__) + +#define TIMEOUT_FUNC_T void * +#define SECOND time.tv_sec +#define MICROTIME(x) (x) = time + +#endif /* __NetBSD__ */ + +/* definitions for the STATUS indications L1 -> L2 -> L3 */ + +#define STI_ATTACH 0 /* attach at boot time */ +#define STI_L1STAT 1 /* layer 1 status */ +#define STI_L2STAT 2 /* layer 2 status */ +#define STI_TEIASG 3 /* TEI assignments */ +#define STI_PDEACT 4 /* Layer 1 T4 expired = persistent deactivation */ +#define STI_NOL1ACC 5 /* no outgoing L1 access possible */ + +/* definitions for the COMMAND requests L3 -> L2 -> L1 */ + +#define CMR_DOPEN 0 /* daemon opened /dev/i4b */ +#define CMR_DCLOSE 1 /* daemon closed /dev/i4b */ + +/*--------------------------------------------------------------------------- + * + * Number of max supported passive card units + * + * Teles/Creatix/Neuhaus cards have a hardware limitation + * as one is able to set 3 (sometimes 4) different configurations by + * jumpers so a maximum of 3 (4) cards per ISA bus is possible. + * (Note: there are multiple ISA buses on some architectures) + * + *---------------------------------------------------------------------------*/ +#define ISIC_MAXUNIT 3 /* max no of supported units 0..3 */ + +#endif /* _I4B_GLOBAL_H_ */ diff --git a/sys/i4b/include/i4b_ioctl.h b/sys/i4b/include/i4b_ioctl.h new file mode 100644 index 000000000000..17e945f173ef --- /dev/null +++ b/sys/i4b/include/i4b_ioctl.h @@ -0,0 +1,606 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_ioctl.h - messages kernel <--> userland + * ------------------------------------------- + * + * $Id: i4b_ioctl.h,v 1.58 1998/12/22 19:48:24 hm Exp $ + * + * last edit-date: [Tue Dec 22 20:33:46 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_IOCTL_H_ +#define _I4B_IOCTL_H_ + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#ifndef _MACHINE_TYPES_H_ +#include <machine/types.h> +#endif /* _MACHINE_TYPES_H_ */ +#endif /* __FreeBSD__ */ + +/*---------------------------------------------------------------------------* + * version and release number for isdn4bsd package + *---------------------------------------------------------------------------*/ +#define VERSION 0 /* version number */ +#define REL 70 /* release number */ +#define STEP 00 /* release step */ + +/*---------------------------------------------------------------------------* + * date/time format in i4b log messages + * ------------------------------------ + * Being year 2000 clean is not easy with the current state of the + * ANSI C library standard and it's implementation for some locales. + * You might like to use the "%c" format of "strftime" sometimes, + * but this breaks Y2K in some locales. Also the old standard logfile + * format "%d.%m.%y %H:%M:%S" is non compliant. + * NetBSD's current toolset warns about this problems, and we compile + * with -Werror, so this problems need to be resolved. + *---------------------------------------------------------------------------*/ +#define I4B_TIME_FORMAT "%d.%m.%Y %H:%M:%S" + +/*---------------------------------------------------------------------------* + * max number of controllers in system + *---------------------------------------------------------------------------*/ +#define MAX_CONTROLLERS 8 /* max number of controllers */ + +/*---------------------------------------------------------------------------* + * controller types + *---------------------------------------------------------------------------*/ +#define CTRL_INVALID (-1) /* invalid, error */ +#define CTRL_UNKNOWN 0 /* unknown controller type */ +#define CTRL_PASSIVE 1 /* passive ISDN controller cards*/ +#define CTRL_DAIC 2 /* Diehl active controller cards*/ +#define CTRL_NUMTYPES 3 /* number of controller types */ + +/*---------------------------------------------------------------------------* + * card types for CTRL_PASSIVE + *---------------------------------------------------------------------------*/ +#define CARD_TYPEP_INVAL (-1) /* invalid, error */ +#define CARD_TYPEP_UNK 0 /* unknown */ +#define CARD_TYPEP_8 1 /* Teles, S0/8 */ +#define CARD_TYPEP_16 2 /* Teles, S0/16 */ +#define CARD_TYPEP_16_3 3 /* Teles, S0/16.3 */ +#define CARD_TYPEP_AVMA1 4 /* AVM A1 or AVM Fritz!Card */ +#define CARD_TYPEP_163P 5 /* Teles, S0/16.3 PnP */ +#define CARD_TYPEP_CS0P 6 /* Creatix, S0 PnP */ +#define CARD_TYPEP_USRTA 7 /* US Robotics ISDN TA internal */ +#define CARD_TYPEP_DRNNGO 8 /* Dr. Neuhaus Niccy GO@ */ +#define CARD_TYPEP_SWS 9 /* Sedlbauer Win Speed */ +#define CARD_TYPEP_DYNALINK 10 /* Dynalink IS64PH */ +#define CARD_TYPEP_BLMASTER 11 /* ISDN Blaster / ISDN Master */ +#define CARD_TYPEP_PCFRITZ 12 /* AVM PCMCIA Fritz!Card */ +#define CARD_TYPEP_ELSAQS1ISA 13 /* ELSA QuickStep 1000pro ISA */ +#define CARD_TYPEP_ELSAQS1PCI 14 /* ELSA QuickStep 1000pro PCI */ +#define CARD_TYPEP_SIEMENSITALK 15 /* Siemens I-Talk */ +#define CARD_TYPEP_ELSAMLIMC 16 /* ELSA MicroLink ISDN/MC */ +#define CARD_TYPEP_ELSAMLMCALL 17 /* ELSA MicroLink MCall */ +#define CARD_TYPEP_ITKIX1 18 /* ITK ix1 micro */ + +/* + * in case you add support for more cards, please update: + * + * isdnd: support.c, name_of_controller() + * diehl/diehlctl: main.c, listall() + * + * and adjust CARD_TYPEP_MAX below. + */ + +#define CARD_TYPEP_MAX 18 /* max type */ + +/*---------------------------------------------------------------------------* + * card types for CTRL_DAIC + *---------------------------------------------------------------------------*/ +#define CARD_TYPEA_DAIC_UNK 0 +#define CARD_TYPEA_DAIC_S 1 +#define CARD_TYPEA_DAIC_SX 2 +#define CARD_TYPEA_DAIC_SCOM 3 +#define CARD_TYPEA_DAIC_QUAD 4 + +/*---------------------------------------------------------------------------* + * max length of some strings + *---------------------------------------------------------------------------*/ +#define TELNO_MAX 41 /* max length of a telephone number (+ '\0') */ +#define DISPLAY_MAX 91 /* max length of display information (+ '\0') */ +#define DATETIME_MAX 21 /* max length of datetime information (+ '\0')*/ + +/*---------------------------------------------------------------------------* + * in case the src or dst telephone number is empty + *---------------------------------------------------------------------------*/ +#define TELNO_EMPTY "NotAvailable" + +/*---------------------------------------------------------------------------* + * B channel parameters + *---------------------------------------------------------------------------*/ +#define BCH_MAX_DATALEN 2048 /* max length of a B channel frame */ + +/*---------------------------------------------------------------------------* + * userland driver types + * --------------------- + * a "driver" is defined here as a piece of software interfacing an + * ISDN B channel with a userland service, such as IP, Telephony etc. + *---------------------------------------------------------------------------*/ +#define BDRV_RBCH 0 /* raw b-channel interface driver */ +#define BDRV_TEL 1 /* telephone (speech) interface driver */ +#define BDRV_IPR 2 /* IP over raw HDLC interface driver */ +#define BDRV_ISPPP 3 /* sync Kernel PPP interface driver */ + +/*---------------------------------------------------------------------------* + * B channel protocol + *---------------------------------------------------------------------------*/ +#define BPROT_NONE 0 /* no protocol at all, raw data */ +#define BPROT_RHDLC 1 /* raw HDLC: flag, data, crc, flag */ + +/*---------------------------------------------------------------------------* + * causes data type + *---------------------------------------------------------------------------*/ +typedef unsigned int cause_t; /* 32 bit unsigned int */ + +/*---------------------------------------------------------------------------* + * call descriptor id (cdid) definitions + *---------------------------------------------------------------------------*/ +#define CDID_UNUSED 0 /* cdid is invalid and unused */ +#define CDID_MAX 99999 /* highest valid cdid, wraparound to 1 */ + + +/**************************************************************************** + + outgoing call: + -------------- + + userland kernel + -------- ------ + + CDID_REQ -----------------> + + <------------------ cdid + + CONNECT_REQ --------------> + + <------------------ PROCEEDING_IND (if connect req ok) + + <------------------ CONNECT_ACTIVE_IND (if connection ok) + + or + + <------------------ DISCONNECT_IND (if connection failed) + + + + incoming call: + -------------- + + userland kernel + -------- ------ + + <------------------ CONNECT_IND + + CONNECT_RESP -------------> + + <------------------ CONNECT_ACTIVE_IND (if accepted) + + + + active disconnect: + ------------------ + + userland kernel + -------- ------ + + DISCONNECT_REQ ------------> + + <------------------ DISCONNECT_IND + + + passive disconnect: + ------------------- + + userland kernel + -------- ------ + + <------------------ DISCONNECT_IND + + +****************************************************************************/ + + +/*===========================================================================* + *===========================================================================* + * "read" messages from kernel -> userland + *===========================================================================* + *===========================================================================*/ + + +/*---------------------------------------------------------------------------* + * message header, included in every message + *---------------------------------------------------------------------------*/ +typedef struct { + char type; /* message identifier */ +#define MSG_CONNECT_IND 'a' +#define MSG_CONNECT_ACTIVE_IND 'b' +#define MSG_DISCONNECT_IND 'c' +#define MSG_DIALOUT_IND 'd' +#define MSG_IDLE_TIMEOUT_IND 'e' +#define MSG_ACCT_IND 'f' +#define MSG_CHARGING_IND 'g' +#define MSG_PROCEEDING_IND 'h' +#define MSG_ALERT_IND 'i' +#define MSG_DRVRDISC_REQ 'j' +#define MSG_L12STAT_IND 'k' +#define MSG_TEIASG_IND 'l' +#define MSG_PDEACT_IND 'm' +#define MSG_NEGCOMP_IND 'n' +#define MSG_IFSTATE_CHANGED_IND 'o' + int cdid; /* call descriptor id */ +} msg_hdr_t; + +/*---------------------------------------------------------------------------* + * connect indication + * indicates incoming connection + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int controller; /* controller number */ + int channel; /* channel number */ +#define CHAN_B1 0 /* this _must_ be 0, HSCX B1 is also 0 */ +#define CHAN_B2 1 /* this _must_ be 1, HSCX B2 is also 1 */ +#define CHAN_ANY (-1) /* outgoing, not possible for incoming */ +#define CHAN_NO (-2) /* call waiting (CW) for incoming */ + int bprot; /* b channel protocot, see BPROT_XXX */ + char dst_telno[TELNO_MAX]; /* destination telno */ + char src_telno[TELNO_MAX]; /* source telno */ + int scr_ind;/* screening indicator */ +#define SCR_NONE 0 /* no screening indicator transmitted */ +#define SCR_USR_NOSC 1 /* screening user provided, not screened*/ +#define SCR_USR_PASS 2 /* screening user provided, verified & passed */ +#define SCR_USR_FAIL 3 /* screening user provided, verified & failed */ +#define SCR_NET 4 /* screening network provided */ + char display[DISPLAY_MAX]; /* content of display IE*/ +} msg_connect_ind_t; + +/*---------------------------------------------------------------------------* + * connect active indication + * indicates active connection + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int controller; /* controller number actually used */ + int channel; /* channel number actually used */ + char datetime[DATETIME_MAX]; /* content of date/time IE */ +} msg_connect_active_ind_t; + +/*---------------------------------------------------------------------------* + * disconnect indication + * indicates a disconnect + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + cause_t cause; /* cause code */ +} msg_disconnect_ind_t; + +/*---------------------------------------------------------------------------* + * negotiation complete + * indicates an interface is completely up & running + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ +} msg_negcomplete_ind_t; + +/*---------------------------------------------------------------------------* + * interface changes internal state + * indicates an interface has somehow switched its FSM + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int state; /* new interface state */ +} msg_ifstatechg_ind_t; + +/*---------------------------------------------------------------------------* + * initiate a call to a remote site + * i.e. the IP driver got a packet and wants a connection + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int driver; /* driver type */ + int driver_unit; /* driver unit number */ +} msg_dialout_ind_t; + +/*---------------------------------------------------------------------------* + * idle timeout disconnect sent indication + * kernel has sent disconnect request because of b-ch idle + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ +} msg_idle_timeout_ind_t; + +/*---------------------------------------------------------------------------* + * accounting information from userland interface driver to daemon + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int accttype; /* accounting type */ +#define ACCT_DURING 0 +#define ACCT_FINAL 1 + int driver; /* driver type */ + int driver_unit; /* driver unit number */ + int ioutbytes; /* ISDN # of bytes sent */ + int iinbytes; /* ISDN # of bytes received */ + int outbps; /* bytes per sec out */ + int inbps; /* bytes per sec in */ + int outbytes; /* driver # of bytes sent */ + int inbytes; /* driver # of bytes received */ +} msg_accounting_ind_t; + +/*---------------------------------------------------------------------------* + * charging information from isdn driver to daemon + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int units; /* number of units */ + int units_type; /* type of units info */ +#define CHARGE_INVALID 0 /* invalid, unknown */ +#define CHARGE_AOCD 1 /* advice of charge during call */ +#define CHARGE_AOCE 2 /* advice of charge at end of call */ +#define CHARGE_CALC 3 /* locally calculated from rates information */ +} msg_charging_ind_t; + +/*---------------------------------------------------------------------------* + * call proceeding indication + * indicates outgoing SETUP has been acknowleged + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int controller; /* controller number actually used */ + int channel; /* channel number actually used */ +} msg_proceeding_ind_t; + +/*---------------------------------------------------------------------------* + * alert indication + * indicates remote user side "rings" + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ +} msg_alert_ind_t; + +/*---------------------------------------------------------------------------* + * driver requests to disconnect line + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int driver; /* driver type */ + int driver_unit; /* driver unit number */ +} msg_drvrdisc_req_t; + +/*---------------------------------------------------------------------------* + * state of layer 1/2 + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int controller; /* controller unit */ + int layer; /* layer number (1/2) */ +#define LAYER_ONE 1 +#define LAYER_TWO 2 + int state; /* state info */ +#define LAYER_IDLE 0 +#define LAYER_ACTIVE 1 +} msg_l12stat_ind_t; + +/*---------------------------------------------------------------------------* + * TEI assignment messages + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int controller; /* controller unit */ + int tei; /* TEI or -1 if invalid */ +} msg_teiasg_ind_t; + +/*---------------------------------------------------------------------------* + * persistent deactivation state of stack + *---------------------------------------------------------------------------*/ +typedef struct { + msg_hdr_t header; /* common header */ + int controller; /* controller unit */ + int numactive; /* number of active connections */ +} msg_pdeact_ind_t; + + +/*===========================================================================* + *===========================================================================* + * "ioctl" messages from userland -> kernel + *===========================================================================* + *===========================================================================*/ + + +/*---------------------------------------------------------------------------* + * request a unique cdid (to setup an outgoing call) + *---------------------------------------------------------------------------*/ +typedef struct { + int cdid; /* call descriptor id */ +} msg_cdid_req_t; + +#define I4B_CDID_REQ _IOWR('4', 0, int) + +/*---------------------------------------------------------------------------* + * connect request + * requests an outgoing connection + *---------------------------------------------------------------------------*/ +typedef struct { + int cdid; /* call descriptor id */ + int controller; /* controller to use */ + int channel; /* channel to use */ + int txdelay; /* tx delay after connect */ + int bprot; /* b channel protocol */ + int driver; /* driver to route b channel data to */ + int driver_unit; /* unit number for above driver */ + int unitlen_time; /* length of a charging unit */ + int idle_time; /* time without activity on b ch */ + int earlyhup_time; /* safety area at end of unit */ + int unitlen_method; /* how to calculate the unitlength */ +#define ULEN_METHOD_STATIC 0 /* use unitlen_time value (see above) */ +#define ULEN_METHOD_DYNAMIC 1 /* use AOCD */ + char dst_telno[TELNO_MAX]; /* destination telephone no */ + char src_telno[TELNO_MAX]; /* source telephone number */ +} msg_connect_req_t; + +#define I4B_CONNECT_REQ _IOW('4', 1, msg_connect_req_t) + +/*---------------------------------------------------------------------------* + * connect response + * this is the answer to an incoming connect indication + *---------------------------------------------------------------------------*/ +typedef struct { + int cdid; /* call descriptor id */ + int response; /* what to do with incoming call */ +#define SETUP_RESP_DNTCRE 0 /* dont care, call is not for me */ +#define SETUP_RESP_REJECT 1 /* reject call */ +#define SETUP_RESP_ACCEPT 2 /* accept call */ + cause_t cause; /* cause for case SETUP_RESP_REJECT */ + /* the following are only used for SETUP_RESP_ACCEPT !! */ + int txdelay; /* tx delay after connect */ + int bprot; /* B chan protocol */ + int driver; /* driver to route b channel data to */ + int driver_unit; /* unit number for above driver */ + int max_idle_time; /* max time without activity on b ch */ +} msg_connect_resp_t; + +#define I4B_CONNECT_RESP _IOW('4', 2, msg_connect_resp_t) + +/*---------------------------------------------------------------------------* + * disconnect request + * active disconnect request + *---------------------------------------------------------------------------*/ +typedef struct { + int cdid; /* call descriptor id */ + cause_t cause; /* protocol independent cause */ +} msg_discon_req_t; + +#define I4B_DISCONNECT_REQ _IOW('4', 3, msg_discon_req_t) + +/*---------------------------------------------------------------------------* + * controller info request + *---------------------------------------------------------------------------*/ +typedef struct { + int controller; /* controller number */ + int ncontroller; /* number of controllers in system */ + int ctrl_type; /* controller type passive/active */ + int card_type; /* brand / version */ + int tei; /* tei controller probably has */ +} msg_ctrl_info_req_t; + +#define I4B_CTRL_INFO_REQ _IOWR('4', 4, msg_ctrl_info_req_t) + +/*---------------------------------------------------------------------------* + * dialout response + * status report to driver who requested a dialout + *---------------------------------------------------------------------------*/ +typedef struct { + int driver; /* driver to route b channel data to */ + int driver_unit; /* unit number for above driver */ + int stat; /* state of dialout request */ +#define DSTAT_NONE 0 +#define DSTAT_TFAIL 1 /* transient failure */ +#define DSTAT_PFAIL 2 /* permanent failure */ +#define DSTAT_INONLY 3 /* no outgoing dials allowed */ +} msg_dialout_resp_t; + +#define I4B_DIALOUT_RESP _IOW('4', 5, msg_dialout_resp_t) + +/*---------------------------------------------------------------------------* + * timeout value update + *---------------------------------------------------------------------------*/ +typedef struct { + int cdid; /* call descriptor id */ + int unitlen_time; /* length of a charging unit */ + int idle_time; /* time without activity on b ch */ + int earlyhup_time; /* safety area at end of unit */ +} msg_timeout_upd_t; + +#define I4B_TIMEOUT_UPD _IOW('4', 6, msg_timeout_upd_t) + +/*---------------------------------------------------------------------------* + * soft enable/disable + *---------------------------------------------------------------------------*/ +typedef struct { + int driver; /* driver to route b channel data to */ + int driver_unit; /* unit number for above driver */ + int updown; /* what to do */ +#define SOFT_ENA 0 /* enable interface */ +#define SOFT_DIS 1 /* disable interface */ +} msg_updown_ind_t; + +#define I4B_UPDOWN_IND _IOW('4', 7, msg_updown_ind_t) + +/*---------------------------------------------------------------------------* + * send alert request + *---------------------------------------------------------------------------*/ +typedef struct { + int cdid; /* call descriptor id */ +} msg_alert_req_t; + +#define I4B_ALERT_REQ _IOW('4', 8, msg_alert_req_t) + +/*---------------------------------------------------------------------------* + * request version and release info from kernel part + *---------------------------------------------------------------------------*/ +typedef struct { + int version; /* version number */ + int release; /* release number */ + int step; /* release step number */ +} msg_vr_req_t; + +#define I4B_VR_REQ _IOR('4', 9, msg_vr_req_t) + +/*---------------------------------------------------------------------------* + * Protocol download to active cards + *---------------------------------------------------------------------------*/ +struct isdn_dr_prot { + size_t bytecount; /* length of code */ + u_int8_t *microcode; /* pointer to microcode */ +}; + +struct isdn_download_request { + int controller; /* controller number */ + int numprotos; /* number of protocols in 'protocols' */ + struct isdn_dr_prot *protocols; +}; + +#define I4B_CTRL_DOWNLOAD _IOW('4', 100, struct isdn_download_request) + +/*---------------------------------------------------------------------------* + * Generic diagnostic interface for active cards + *---------------------------------------------------------------------------*/ +struct isdn_diagnostic_request { + int controller; /* controller number */ + u_int32_t cmd; /* diagnostic command to execute */ + size_t in_param_len; /* length of additional input parameter */ + void *in_param; /* optional input parameter */ + size_t out_param_len; /* available output space */ + void *out_param; /* output data goes here */ +}; + +#define I4B_ACTIVE_DIAGNOSTIC _IOW('4', 102, struct isdn_diagnostic_request) + +#endif /* _I4B_IOCTL_H_ */ diff --git a/sys/i4b/include/i4b_isdnq931.h b/sys/i4b/include/i4b_isdnq931.h new file mode 100644 index 000000000000..bdc77f08c660 --- /dev/null +++ b/sys/i4b/include/i4b_isdnq931.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isdnq931.h - DSS1 layer 3 message types + * ------------------------------------------- + * + * $Id: i4b_isdnq931.h,v 1.4 1998/12/05 18:02:54 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:04:01 1998] + * + *---------------------------------------------------------------------------*/ + +/* protocol discriminators */ + +#define PD_Q931 0x08 /* Q.931/I.451 */ + +/* Q.931 single octett information element identifiers */ + +#define IEI_SENDCOMPL 0xa1 /* sending complete */ + +/* Q.931 variable length information element identifiers */ + +#define IEI_SEGMMSG 0x00 /* segmented message */ +#define IEI_BEARERCAP 0x04 /* bearer capabilities */ +#define IEI_CAUSE 0x08 /* cause */ +#define IEI_CALLID 0x10 /* call identity */ +#define IEI_CALLSTATE 0x14 /* call state */ +#define IEI_CHANNELID 0x18 /* channel identification */ +#define IEI_PROGRESSI 0x1e /* progress indicator */ +#define IEI_NETSPCFAC 0x20 /* network specific facilities */ +#define IEI_NOTIFIND 0x27 /* notification indicator */ +#define IEI_DISPLAY 0x28 /* display */ +#define IEI_DATETIME 0x29 /* date/time */ +#define IEI_KEYPAD 0x2c /* keypad facility */ +#define IEI_SIGNAL 0x34 /* signal */ +#define IEI_INFRATE 0x40 /* information rate */ +#define IEI_ETETDEL 0x42 /* end to end transit delay */ +#define IEI_TDELSELIND 0x43 /* transit delay selection and indication */ +#define IEI_PLBPARMS 0x44 /* packet layer binary parameters */ +#define IEI_PLWSIZE 0x45 /* packet layer window size */ +#define IEI_PSIZE 0x46 /* packet size */ +#define IEI_CUG 0x47 /* closed user group */ +#define IEI_REVCHRGI 0x4a /* reverse charge indication */ +#define IEI_CALLINGPN 0x6c /* calling party number */ +#define IEI_CALLINGPS 0x6d /* calling party subaddress */ +#define IEI_CALLEDPN 0x70 /* called party number */ +#define IEI_CALLEDPS 0x71 /* called party subaddress */ +#define IEI_REDIRNO 0x74 /* redirecting number */ +#define IEI_TRNSEL 0x78 /* transit network selection */ +#define IEI_RESTARTI 0x79 /* restart indicator */ +#define IEI_LLCOMPAT 0x7c /* low layer compatibility */ +#define IEI_HLCOMPAT 0x7d /* high layer compatibility */ +#define IEI_USERUSER 0x7e /* user-user */ +#define IEI_ESACPE 0x7f /* escape for extension */ + +/* Q.932 variable length information element identifiers */ + +#define IEI_EXTFAC 0x0d /* extended facility */ +#define IEI_FACILITY 0x1c /* facility */ +#define IEI_INFOREQ 0x32 /* information request */ +#define IEI_FEATACT 0x38 /* feature activation */ +#define IEI_FEATIND 0x39 /* feature indication */ +#define IEI_SERVPID 0x3a /* service profile identification */ +#define IEI_ENDPTID 0x3b /* endpoint identifier */ + +/* Q.933 variable length information element identifiers */ + +#define IEI_DATALCID 0x19 /* data link connection identifier */ +#define IEI_LLCOREP 0x48 /* link layer core parameters */ +#define IEI_LLPROTP 0x49 /* link layer protocol parameters */ +#define IEI_X213PRI 0x50 /* X.213 priority */ +#define IEI_REPORTT 0x51 /* report type */ +#define IEI_LNKITYVERF 0x53 /* link integrity verification */ +#define IEI_PVCSTAT 0x57 /* PVC status */ + +/* Q.95x variable length information element identifiers */ + +#define IEI_PRECLEV 0x41 /* precedence level */ +#define IEI_CONCTDNO 0x4c /* connected number */ +#define IEI_CONCTDSA 0x4d /* connected subaddress */ +#define IEI_REDICNNO 0x76 /* redirection number */ + +/* single octett information elements */ + +#define SOIE_SHIFT 0x90 /* shift codeset */ +#define SHIFT_LOCK 0x08 /* shift codeset, locking shift bit */ +#define SOIE_MDSC 0xa0 /* more data AND/OR sending complete */ +#define SOIE_SENDC 0xa1 /* sending complete */ +#define SOIE_CONGL 0xb0 /* congestion level */ +#define SOIE_REPTI 0xd0 /* repeat indicator */ + +/* codesets */ + +#define CODESET_0 0 /* codeset 0, normal DSS1 codeset */ + +/* Q.931/Q.932 message types (see Q.931 03/93 p10 and p311) */ + +/* call establishment messages */ + +#define ALERT 0x01 +#define CALL_PROCEEDING 0x02 +#define PROGRESS 0x03 +#define SETUP 0x05 +#define CONNECT 0x07 +#define SETUP_ACKNOWLEDGE 0x0d +#define CONNECT_ACKNOWLEDGE 0x0f + +/* call information phase messages */ + +#define USER_INFORMATION 0x20 +#define SUSPEND_REJECT 0x21 +#define RESUME_REJECT 0x22 +#define HOLD 0x24 +#define SUSPEND 0x25 +#define RESUME 0x26 +#define HOLD_ACKNOWLEDGE 0x28 +#define SUSPEND_ACKNOWLEDGE 0x2d +#define RESUME_ACKNOWLEDGE 0x2e +#define HOLD_REJECT 0x30 +#define RETRIEVE 0x31 +#define RETRIEVE_ACKNOWLEDGE 0x32 +#define RETRIEVE_REJECT 0x37 + +/* call clearing */ + +#define DISCONNECT 0x45 +#define RESTART 0x46 +#define RELEASE 0x4d +#define RESTART_ACKNOWLEDGE 0x4e +#define RELEASE_COMPLETE 0x5a + +/* misc messages */ + +#define SEGMENT 0x60 +#define FACILITY 0x62 +#define REGISTER 0x64 +#define NOTIFY 0x6e +#define STATUS_ENQUIRY 0x75 +#define CONGESTION_CONTROL 0x79 +#define INFORMATION 0x7b +#define STATUS 0x7d + +/* EOF */ diff --git a/sys/i4b/include/i4b_l1l2.h b/sys/i4b/include/i4b_l1l2.h new file mode 100644 index 000000000000..782ca68a97a3 --- /dev/null +++ b/sys/i4b/include/i4b_l1l2.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l1l2.h - i4b layer 1 / layer 2 interactions + * --------------------------------------------------- + * + * $Id: i4b_l1l2.h,v 1.7 1998/12/05 18:02:56 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:04:25 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L1L2_H_ +#define _I4B_L1L2_H_ + +#ifdef __FreeBSD__ +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_trace.h> +#endif + +extern struct i4b_l1l2_func i4b_l1l2_func; + +struct i4b_l1l2_func +{ + /* Layer 1 --> Layer 2 */ + /* =================== */ + + int (*PH_DATA_IND) (int, struct mbuf *); + int (*PH_ACTIVATE_IND) (int); + int (*PH_DEACTIVATE_IND) (int); + +#define PH_Data_Ind(unit, data) \ + ((*i4b_l1l2_func.PH_DATA_IND)(unit, data)) +#define PH_Act_Ind(unit) \ + ((*i4b_l1l2_func.PH_ACTIVATE_IND)(unit)) +#define PH_Deact_Ind(unit) \ + ((*i4b_l1l2_func.PH_DEACTIVATE_IND)(unit)) + + + /* Layer 2 --> Layer 1 */ + /* =================== */ + + int (*PH_DATA_REQ) (int, struct mbuf *, int); + + /* 3rd ph_data_req parameter */ +#define MBUF_DONTFREE 0 +#define MBUF_FREE 1 + + int (*PH_ACTIVATE_REQ) (int); + +#define PH_Data_Req(unit, data, freeflag) \ + ((*i4b_l1l2_func.PH_DATA_REQ)(unit, data, freeflag)) +#define PH_Act_Req(unit) \ + ((*i4b_l1l2_func.PH_ACTIVATE_REQ)(unit)) + + /* Layer 1 --> upstream, ISDN trace data */ + /* ===================================== */ + int (*MPH_TRACE_IND) (i4b_trace_hdr_t *, int, unsigned char *); + +#define MPH_Trace_Ind(header, length, pointer) \ + ((*i4b_l1l2_func.MPH_TRACE_IND)(header, length, pointer)) + + /* L1/L2 management command and status information */ + /* =============================================== */ + int (*MPH_STATUS_IND) (int, int, int); + int (*MPH_COMMAND_REQ) (int, int, int); + +#define MPH_Status_Ind(unit, status, parm) \ + ((*i4b_l1l2_func.MPH_STATUS_IND)(unit, status, parm)) +#define MPH_Command_Req(unit, command, parm) \ + ((*i4b_l1l2_func.MPH_COMMAND_REQ)(unit, command, parm)) +}; + +#endif /* _I4B_L1L2_H_ */ + diff --git a/sys/i4b/include/i4b_l2l3.h b/sys/i4b/include/i4b_l2l3.h new file mode 100644 index 000000000000..81ab1829ebc9 --- /dev/null +++ b/sys/i4b/include/i4b_l2l3.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2l3.h - i4b layer 2 / layer 3 interactions + * ----------------------------------------------- + * + * $Id: i4b_l2l3.h,v 1.5 1998/12/05 18:02:57 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:04:44 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L2L3_H_ +#define _I4B_L2L3_H_ + +extern struct i4b_l2l3_func i4b_l2l3_func; + +struct i4b_l2l3_func +{ + /* Layer 2 --> Layer 3 */ + /* =================== */ + + int (*DL_ESTABLISH_IND) (int); + int (*DL_ESTABLISH_CNF) (int); + + int (*DL_RELEASE_IND) (int); + int (*DL_RELEASE_CNF) (int); + + int (*DL_DATA_IND) (int, struct mbuf *); + + int (*DL_UNIT_DATA_IND) (int, struct mbuf *); + +#define DL_Est_Ind(unit) \ + ((*i4b_l2l3_func.DL_ESTABLISH_IND)(unit)) +#define DL_Est_Cnf(unit) \ + ((*i4b_l2l3_func.DL_ESTABLISH_CNF)(unit)) +#define DL_Rel_Ind(unit) \ + ((*i4b_l2l3_func.DL_RELEASE_IND)(unit)) +#define DL_Rel_Cnf(unit) \ + ((*i4b_l2l3_func.DL_RELEASE_CNF)(unit)) +#define DL_Data_Ind(unit, data) \ + ((*i4b_l2l3_func.DL_DATA_IND)(unit, data)) +#define DL_Unit_Data_Ind(unit, data) \ + ((*i4b_l2l3_func.DL_UNIT_DATA_IND)(unit, data)) + +#define DL_Est_Ind_A \ + (i4b_l2l3_func.DL_ESTABLISH_IND) +#define DL_Est_Cnf_A \ + (i4b_l2l3_func.DL_ESTABLISH_CNF) +#define DL_Rel_Ind_A \ + (i4b_l2l3_func.DL_RELEASE_IND) +#define DL_Rel_Cnf_A \ + (i4b_l2l3_func.DL_RELEASE_CNF) + + /* Layer 3 --> Layer 2 */ + /* =================== */ + + int (*DL_ESTABLISH_REQ) (int); + + int (*DL_RELEASE_REQ) (int); + + int (*DL_DATA_REQ) (int, struct mbuf *); + + int (*DL_UNIT_DATA_REQ) (int, struct mbuf *); + +#define DL_Est_Req(unit) \ + ((*i4b_l2l3_func.DL_ESTABLISH_REQ)(unit)) +#define DL_Rel_Req(unit) \ + ((*i4b_l2l3_func.DL_RELEASE_REQ)(unit)) +#define DL_Data_Req(unit, data) \ + ((*i4b_l2l3_func.DL_DATA_REQ)(unit, data)) +#define DL_Unit_Data_Req(unit, data) \ + ((*i4b_l2l3_func.DL_UNIT_DATA_REQ)(unit, data)) + + /* Layer 2 --> Layer 3 management */ + /* ============================== */ + + int (*MDL_STATUS_IND) (int, int, int); /* L2 --> L3 status */ + +#define MDL_Status_Ind(unit, status, parm) \ + ((*i4b_l2l3_func.MDL_STATUS_IND)(unit, status, parm)) + + /* Layer 3 --> Layer 2 management */ + /* ============================== */ + + int (*MDL_COMMAND_REQ) (int, int, int); /* L3 --> L2 command */ + +#define MDL_Command_Req(unit, command, parm) \ + ((*i4b_l2l3_func.MDL_COMMAND_REQ)(unit, command, parm)) +}; + +#endif /* _I4B_L2L3_H_ */ + diff --git a/sys/i4b/include/i4b_l3l4.h b/sys/i4b/include/i4b_l3l4.h new file mode 100644 index 000000000000..642777c04d67 --- /dev/null +++ b/sys/i4b/include/i4b_l3l4.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l3l4.h - layer 3 / layer 4 interface + * ------------------------------------------ + * + * $Id: i4b_l3l4.h,v 1.21 1998/12/05 18:02:59 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:04:58 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L3L4_H_ +#define _I4B_L3L4_H_ + +#define T303VAL (hz*4) /* 4 seconds timeout */ +#define T305VAL (hz*30) /* 30 seconds timeout */ +#define T308VAL (hz*4) /* 4 seconds timeout */ +#define T309VAL (hz*90) /* 90 seconds timeout */ +#define T310VAL (hz*60) /* 30-120 seconds timeout */ +#define T313VAL (hz*4) /* 4 seconds timeout */ +#define T400DEF (hz*10) /* 10 seconds timeout */ + +#define N_CALL_DESC (MAX_CONTROLLERS*2) /* no of call descriptors */ + +extern int nctrl; /* number of controllers detected in system */ + +typedef struct bchan_statistics { + int outbytes; + int inbytes; +} bchan_statistics_t; + +/*---------------------------------------------------------------------------* + * table of things the driver needs to know about the b channel + * it is connected to for data transfer + *---------------------------------------------------------------------------*/ +typedef struct i4l_isdn_bchan_linktab { + int unit; + int channel; + void (*bch_config)(int unit, int channel, int bprot, int updown); + void (*bch_tx_start)(int unit, int channel); + void (*bch_stat)(int unit, int channel, bchan_statistics_t *bsp); + struct ifqueue *tx_queue; + struct ifqueue *rx_queue; /* data xfer for NON-HDLC traffic */ + struct mbuf **rx_mbuf; /* data xfer for HDLC based traffic */ +} isdn_link_t; + +/*---------------------------------------------------------------------------* + * table of things the b channel handler needs to know about + * the driver it is connected to for data transfer + *---------------------------------------------------------------------------*/ +typedef struct i4l_driver_bchan_linktab { + int unit; + void (*bch_rx_data_ready)(int unit); + void (*bch_tx_queue_empty)(int unit); + void (*bch_activity)(int unit, int rxtx); +#define ACT_RX 0 +#define ACT_TX 1 + void (*line_connected)(int unit, void *cde); + void (*line_disconnected)(int unit, void *cde); + void (*dial_response)(int unit, int stat); + void (*updown_ind)(int unit, int updown); +} drvr_link_t; + +/* global linktab functions for controller types (aka hardware drivers) */ +struct ctrl_type_desc { + isdn_link_t* (*get_linktab)(int unit, int channel); + void (*set_linktab)(int unit, int channel, drvr_link_t *dlt); +}; +extern struct ctrl_type_desc ctrl_types[]; + +/* global linktab functions for RBCH userland driver */ + +drvr_link_t *rbch_ret_linktab(int unit); +void rbch_set_linktab(int unit, isdn_link_t *ilt); + +/* global linktab functions for IPR network driver */ + +drvr_link_t *ipr_ret_linktab(int unit); +void ipr_set_linktab(int unit, isdn_link_t *ilt); + +/* global linktab functions for TEL userland driver */ + +drvr_link_t *tel_ret_linktab(int unit); +void tel_set_linktab(int unit, isdn_link_t *ilt); + +/* global linktab functions for ISPPP userland driver */ + +drvr_link_t *i4bisppp_ret_linktab(int unit); +void i4bisppp_set_linktab(int unit, isdn_link_t *ilt); + +/*---------------------------------------------------------------------------* + * this structure describes one call/connection on one B-channel + * and all its parameters + *---------------------------------------------------------------------------*/ +typedef struct +{ + u_int cdid; /* call descriptor id */ + int controller; /* isdn controller number */ + int cr; /* call reference value */ + + int crflag; /* call reference flag */ +#define CRF_ORIG 0 /* originating side */ +#define CRF_DEST 1 /* destinating side */ + + int channelid; /* channel id value */ + int channelexcl; /* channel exclusive */ + + int bprot; /* B channel protocol BPROT_XXX */ + + int driver; /* driver to use for B channel */ + int driver_unit; /* unit for above driver number */ + + cause_t cause_in; /* cause value from NT */ + cause_t cause_out; /* cause value to NT */ + + int call_state; /* from incoming SETUP */ + + u_char dst_telno[TELNO_MAX]; /* destination number */ + u_char src_telno[TELNO_MAX]; /* source number */ + int scr_ind; /* screening ind for incoming call */ + + int Q931state; /* Q.931 state for call */ + int event; /* event to be processed */ + + int response; /* setup response type */ + + int T303; /* SETUP sent response timeout */ + int T303_first_to; /* first timeout flag */ + + int T305; /* DISC without PROG IND */ + + int T308; /* RELEASE sent response timeout*/ + int T308_first_to; /* first timeout flag */ + + int T309; /* data link disconnect timeout */ + + int T310; /* CALL PROC received */ + + int T313; /* CONNECT sent timeout */ + + int T400; /* L4 timeout */ + + isdn_link_t *ilt; /* isdn B channel linktab */ + drvr_link_t *dlt; /* driver linktab */ + + int dir; /* outgoing or incoming call */ +#define DIR_OUTGOING 0 +#define DIR_INCOMING 1 + + int timeout_active; /* idle timeout() active flag */ + +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300001) || \ + (!defined(__FreeBSD_version) && defined(__FreeBSD__) && __FreeBSD__ >= 3) + struct callout_handle idle_timeout_handle; + struct callout_handle T303_callout; + struct callout_handle T305_callout; + struct callout_handle T308_callout; + struct callout_handle T309_callout; + struct callout_handle T310_callout; + struct callout_handle T313_callout; + struct callout_handle T400_callout; + int callouts_inited; /* must init before use */ +#endif + + int idletime_state; /* wait for idle_time begin */ +#define IST_IDLE 0 /* shorthold mode disabled */ +#define IST_NONCHK 1 /* in non-checked window */ +#define IST_CHECK 2 /* in idle check window */ +#define IST_SAFE 3 /* in safety zone */ + + time_t idletimechk_start; /* check idletime window start */ + time_t connect_time; /* time connect was made */ + time_t last_active_time; /* last time with activity */ + + /* for incoming connections: */ + time_t max_idle_time; /* max time without activity */ + + /* for outgoing connections: */ + time_t unitlen_time; /* length of a charging unit */ + time_t idle_time; /* idle time before end of unit */ + time_t earlyhup_time; /* safety time zone at end of unit */ + + int aocd_flag; /* AOCD used for unitlength calc*/ + time_t last_aocd_time; /* last time AOCD received */ + int units; /* number of AOCD charging units*/ + int units_type; /* units type: AOCD, AOCE */ + int cunits; /* calculated units */ + + int isdntxdelay; /* isdn tx delay after connect */ + + u_char display[DISPLAY_MAX]; /* display information element */ + char datetime[DATETIME_MAX]; /* date/time information element*/ +} call_desc_t; + +extern call_desc_t call_desc[N_CALL_DESC]; + +/* forward decl. */ +struct isdn_diagnostic_request; +struct isdn_dr_prot; + +/*---------------------------------------------------------------------------* + * this structure "describes" one controller + *---------------------------------------------------------------------------*/ +typedef struct +{ + int unit; /* unit number of this contr. */ + int ctrl_type; /* controller type (CTRL_XXX) */ + int card_type; /* card manufacturer (CARD_XXX) */ + + int dl_est; /* layer 2 established */ +#define DL_DOWN 0 +#define DL_UP 1 + + int bch_state[2]; /* states of the b channels */ +#define BCH_ST_FREE 0 /* free to be used, idle */ +#define BCH_ST_RSVD 1 /* reserved, may become free or used */ +#define BCH_ST_USED 2 /* in use for data transfer */ + + int tei; /* current tei or -1 if invalid */ + + /* pointers to functions to be called from L4 */ + + void (*N_CONNECT_REQUEST) (unsigned int); + void (*N_CONNECT_RESPONSE) (unsigned int, int, int); + void (*N_DISCONNECT_REQUEST) (unsigned int, int); + void (*N_ALERT_REQUEST) (unsigned int); + void (*N_SET_TRACE) (int unit, int val); + int (*N_GET_TRACE) (int unit); + int (*N_DOWNLOAD) (int unit, int numprotos, struct isdn_dr_prot *protocols); + int (*N_DIAGNOSTICS) (int unit, struct isdn_diagnostic_request*); + void (*N_MGMT_COMMAND) (int unit, int cmd, int parm); +} ctrl_desc_t; + +extern ctrl_desc_t ctrl_desc[MAX_CONTROLLERS]; + +#endif /* _I4B_Q931_H_ */ diff --git a/sys/i4b/include/i4b_mbuf.h b/sys/i4b/include/i4b_mbuf.h new file mode 100644 index 000000000000..49ee26d6162d --- /dev/null +++ b/sys/i4b/include/i4b_mbuf.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b - mbuf handling support routines + * -------------------------------------- + * + * $Id: i4b_mbuf.h,v 1.6 1998/12/05 18:03:00 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:05:12 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_MBUF_H_ +#define _I4B_MBUF_H_ + +#define IF_QEMPTY(ifq) ((ifq)->ifq_len == 0) + +struct mbuf *i4b_Dgetmbuf( int ); +void i4b_Dfreembuf( struct mbuf *m ); +void i4b_Dcleanifq( struct ifqueue * ); + +struct mbuf *i4b_Bgetmbuf( int ); +void i4b_Bfreembuf( struct mbuf *m ); +void i4b_Bcleanifq( struct ifqueue * ); + +#endif /* _I4B_MBUF_H_ */ + +/* EOF */ diff --git a/sys/i4b/include/i4b_tel_ioctl.h b/sys/i4b/include/i4b_tel_ioctl.h new file mode 100644 index 000000000000..b7f0f73cd92a --- /dev/null +++ b/sys/i4b/include/i4b_tel_ioctl.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_tel_ioctl.h telephony interface ioctls + * ------------------------------------------ + * + * $Id: i4b_tel_ioctl.h,v 1.5 1998/12/14 10:31:58 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:37:36 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_TEL_IOCTL_H_ +#define _I4B_TEL_IOCTL_H_ + +/* supported audio format conversions for /dev/i4btelXX devices */ + +#define CVT_NONE 0 /* no format conversion */ +#define CVT_ALAW2ULAW 1 /* kernel A-law, userland mu-law */ + +/*---------------------------------------------------------------------------* + * get / set audio format + *---------------------------------------------------------------------------*/ + +#define I4B_TEL_GETAUDIOFMT _IOR('A', 0, int) +#define I4B_TEL_SETAUDIOFMT _IOW('A', 1, int) +#define I4B_TEL_EMPTYINPUTQUEUE _IOW('A', 2, int) + +#endif /* _I4B_TEL_IOCTL_H_ */ diff --git a/sys/i4b/include/i4b_trace.h b/sys/i4b/include/i4b_trace.h new file mode 100644 index 000000000000..07e08daa075c --- /dev/null +++ b/sys/i4b/include/i4b_trace.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_trace.h - header file for trace data read device + * ---------------------------------------------------- + * + * $Id: i4b_trace.h,v 1.5 1998/12/05 18:06:01 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:37:49 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_TRACE_H_ +#define _I4B_TRACE_H_ + +/*---------------------------------------------------------------------------* + * structure of the header at the beginning of every trace mbuf + *---------------------------------------------------------------------------*/ +typedef struct { + int length; /* length of the following mbuf */ + int unit; /* controller unit number */ + int type; /* type of channel */ +#define TRC_CH_I 0 /* Layer 1 INFO's */ +#define TRC_CH_D 1 /* D channel */ +#define TRC_CH_B1 2 /* B1 channel */ +#define TRC_CH_B2 3 /* B2 channel */ + int dir; /* direction */ +#define FROM_TE 0 /* user -> network */ +#define FROM_NT 1 /* network -> user */ + int trunc; /* # of truncated bytes (frame > MCLBYTES) */ + unsigned int count; /* frame count for this unit/type */ + struct timeval time; /* timestamp for this frame */ +} i4b_trace_hdr_t; + +#define INFO0 0 /* layer 1 */ +#define INFO1_8 1 +#define INFO1_10 2 +#define INFO2 3 +#define INFO3 4 +#define INFO4_8 5 +#define INFO4_10 6 + +/*---------------------------------------------------------------------------* + * ioctl via /dev/i4btrc device(s): + * get/set current trace flag settings + *---------------------------------------------------------------------------*/ + +#define I4B_TRC_GET _IOR('T', 0, int) /* get trace settings */ +#define I4B_TRC_SET _IOW('T', 1, int) /* set trace settings */ + +#define TRACE_OFF 0x00 /* tracing off */ +#define TRACE_I 0x01 /* trace L1 INFO's on */ +#define TRACE_D_TX 0x02 /* trace D channel on */ +#define TRACE_D_RX 0x04 /* trace D channel on */ +#define TRACE_B_TX 0x08 /* trace B channel on */ +#define TRACE_B_RX 0x10 /* trace B channel on */ + +typedef struct { + int rxunit; /* unit # for rx frames */ + int rxflags; /* d and/or b channel */ + int txunit; /* unit # for tx frames */ + int txflags; /* d and/or b channel */ +} i4b_trace_setupa_t; + +#define I4B_TRC_SETA _IOW('T', 2, i4b_trace_setupa_t) /* set analyze mode */ +#define I4B_TRC_RESETA _IOW('T', 3, int) /* reset analyze mode */ + +#endif /* _I4B_TRACE_H_ */ diff --git a/sys/i4b/layer1/i4b_avm_a1.c b/sys/i4b/layer1/i4b_avm_a1.c new file mode 100644 index 000000000000..bb55979e3638 --- /dev/null +++ b/sys/i4b/layer1/i4b_avm_a1.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 1996 Andrew Gordon. All rights reserved. + * + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_avm_a1.c - AVM A1/Fritz passive card driver for isdn4bsd + * ------------------------------------------------------------ + * + * $Id: i4b_avm_a1.c,v 1.20 1998/12/16 13:57:21 hm Exp $ + * + * last edit-date: [Wed Dec 16 14:59:59 1998] + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(AVM_A1) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#ifndef __FreeBSD__ +static u_int8_t avma1_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void avma1_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void avma1_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void avma1_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * AVM A1 and AVM Fritz! Card special registers + *---------------------------------------------------------------------------*/ + +#define AVM_CONF_REG 0x1800 /* base offset for config register */ +#define AVM_CONF_IRQ 0x1801 /* base offset for IRQ register */ + /* config register write */ +#define AVM_CONF_WR_RESET 0x01 /* 1 = RESET ISAC and HSCX */ +#define AVM_CONF_WR_CCL 0x02 /* 1 = clear counter low nibble */ +#define AVM_CONF_WR_CCH 0x04 /* 1 = clear counter high nibble */ +#define AVM_CONF_WR_IRQEN 0x08 /* 1 = enable IRQ */ +#define AVM_CONF_WR_TEST 0x10 /* test bit */ + /* config register read */ +#define AVM_CONF_RD_IIRQ 0x01 /* 0 = ISAC IRQ active */ +#define AVM_CONF_RD_HIRQ 0x02 /* 0 = HSCX IRQ active */ +#define AVM_CONF_RD_CIRQ 0x04 /* 0 = counter IRQ active */ +#define AVM_CONF_RD_ZER1 0x08 /* unused, always read 0 */ +#define AVM_CONF_RD_TEST 0x10 /* test bit read back */ +#define AVM_CONF_RD_ZER2 0x20 /* unused, always read 0 */ + +/*---------------------------------------------------------------------------* + * AVM read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base - 0x3e0, (u_char *)buf, (u_int)len); +} +#else +static void +avma1_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+4].t; + bus_space_handle_t h = sc->sc_maps[what+4].h; + bus_space_read_multi_1(t, h, 0, buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base - 0x3e0, (u_char *)buf, (u_int)len); +} +#else +static void +avma1_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+4].t; + bus_space_handle_t h = sc->sc_maps[what+4].h; + bus_space_write_multi_1(t, h, 0, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} +#else +static void +avma1_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_space_write_1(t, h, offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +avma1_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} +#else +static u_int8_t +avma1_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + return bus_space_read_1(t, h, offs); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_avma1 - probe for AVM A1 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_avma1(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + u_char savebyte; + u_char byte; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for AVM A1/Fritz!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq)-1) + { + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for AVM A1/Fritz!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for AVM A1/Fritz!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x200: + case 0x240: + case 0x300: + case 0x340: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for AVM A1/Fritz!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + sc->clearirq = NULL; + sc->readreg = avma1_read_reg; + sc->writereg = avma1_write_reg; + + sc->readfifo = avma1_read_fifo; + sc->writefifo = avma1_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_AVMA1; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t)dev->id_iobase + 0x1400 - 0x20; + + HSCX_A_BASE = (caddr_t)dev->id_iobase + 0x400 - 0x20; + HSCX_B_BASE = (caddr_t)dev->id_iobase + 0xc00 - 0x20; + + /* + * Read HSCX A/B VSTR. + * Expected value for AVM A1 is 0x04 or 0x05 and for the + * AVM Fritz!Card is 0x05 in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for AVM A1/Fritz\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + /* AVM A1 or Fritz! control register bits: */ + /* read write */ + /* 0x01 hscx irq* RESET */ + /* 0x02 isac irq* clear counter1 */ + /* 0x04 counter irq* clear counter2 */ + /* 0x08 always 0 irq enable */ + /* 0x10 read test bit set test bit */ + /* 0x20 always 0 unused */ + + /* + * XXX the following test may be destructive, to prevent the + * worst case, we save the byte first, and in case the test + * fails, we write back the saved byte ..... + */ + + savebyte = inb(dev->id_iobase + AVM_CONF_REG); + + /* write low to test bit */ + + outb(dev->id_iobase + AVM_CONF_REG, 0x00); + + /* test bit and next higher and lower bit must be 0 */ + + if((byte = inb(dev->id_iobase + AVM_CONF_REG) & 0x38) != 0x00) + { + printf("isic%d: Error, probe-1 failed, 0x%02x should be 0x00 for AVM A1/Fritz!\n", + dev->id_unit, byte); + outb(dev->id_iobase + AVM_CONF_REG, savebyte); + return (0); + } + + /* write high to test bit */ + + outb(dev->id_iobase + AVM_CONF_REG, 0x10); + + /* test bit must be high, next higher and lower bit must be 0 */ + + if((byte = inb(dev->id_iobase + AVM_CONF_REG) & 0x38) != 0x10) + { + printf("isic%d: Error, probe-2 failed, 0x%02x should be 0x10 for AVM A1/Fritz!\n", + dev->id_unit, byte); + outb(dev->id_iobase + AVM_CONF_REG, savebyte); + return (0); + } + + return (1); +} + +#else + +int +isic_probe_avma1(struct isic_attach_args *ia) +{ + u_int8_t savebyte, v1, v2; + + /* + * Read HSCX A/B VSTR. + * Expected value for AVM A1 is 0x04 or 0x05 and for the + * AVM Fritz!Card is 0x05 in the least significant bits. + */ + + v1 = bus_space_read_1(ia->ia_maps[ISIC_WHAT_HSCXA+1].t, ia->ia_maps[ISIC_WHAT_HSCXA+1].h, H_VSTR) & 0x0f; + v2 = bus_space_read_1(ia->ia_maps[ISIC_WHAT_HSCXB+1].t, ia->ia_maps[ISIC_WHAT_HSCXB+1].h, H_VSTR) & 0x0f; + if (v1 != v2 || (v1 != 0x05 && v1 != 0x04)) + return 0; + + /* AVM A1 or Fritz! control register bits: */ + /* read write */ + /* 0x01 hscx irq* RESET */ + /* 0x02 isac irq* clear counter1 */ + /* 0x04 counter irq* clear counter2 */ + /* 0x08 always 0 irq enable */ + /* 0x10 read test bit set test bit */ + /* 0x20 always 0 unused */ + + /* + * XXX the following test may be destructive, to prevent the + * worst case, we save the byte first, and in case the test + * fails, we write back the saved byte ..... + */ + + savebyte = bus_space_read_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0); + + /* write low to test bit */ + + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, 0); + + /* test bit and next higher and lower bit must be 0 */ + + if((bus_space_read_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0) & 0x38) != 0x00) + { + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, savebyte); + return 0; + } + + /* write high to test bit */ + + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, 0x10); + + /* test bit must be high, next higher and lower bit must be 0 */ + + if((bus_space_read_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0) & 0x38) != 0x10) + { + bus_space_write_1(ia->ia_maps[0].t, ia->ia_maps[0].h, 0, savebyte); + return 0; + } + + return (1); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_avma1 - attach AVM A1 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_avma1(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* reset the HSCX and ISAC chips */ + + outb(dev->id_iobase + AVM_CONF_REG, 0x00); + DELAY(SEC_DELAY / 10); + + outb(dev->id_iobase + AVM_CONF_REG, AVM_CONF_WR_RESET); + DELAY(SEC_DELAY / 10); + + outb(dev->id_iobase + AVM_CONF_REG, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + outb(dev->id_iobase + AVM_CONF_IRQ, (ffs(sc->sc_irq)) - 1); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + outb(dev->id_iobase + AVM_CONF_REG, AVM_CONF_WR_IRQEN | + AVM_CONF_WR_CCH | AVM_CONF_WR_CCL); + DELAY(SEC_DELAY / 10); + + return (1); +} + +#else + +int +isic_attach_avma1(struct isic_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = avma1_read_reg; + sc->writereg = avma1_write_reg; + + sc->readfifo = avma1_read_fifo; + sc->writefifo = avma1_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_AVMA1; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* reset the HSCX and ISAC chips */ + + bus_space_write_1(t, h, 0, 0x00); + DELAY(SEC_DELAY / 10); + + bus_space_write_1(t, h, 0, AVM_CONF_WR_RESET); + DELAY(SEC_DELAY / 10); + + bus_space_write_1(t, h, 0, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + bus_space_write_1(t, h, 1, sc->sc_irq); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + bus_space_write_1(t, h, 0, AVM_CONF_WR_IRQEN | + AVM_CONF_WR_CCH | AVM_CONF_WR_CCL); + DELAY(SEC_DELAY / 10); + + return (1); +} +#endif + +#endif /* ISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_avm_fritz_pcmcia.c b/sys/i4b/layer1/i4b_avm_fritz_pcmcia.c new file mode 100644 index 000000000000..483eb660a828 --- /dev/null +++ b/sys/i4b/layer1/i4b_avm_fritz_pcmcia.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 1998 Matthias Apitz. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * Fritz!Card pcmcia specific routines for isic driver + * --------------------------------------------------- + * + * $Id: i4b_avm_fritz_pcmcia.c,v 1.7 1998/12/01 21:25:53 hm Exp $ + * + * last edit-date: [Tue Dec 1 22:03:51 1998] + * + * -ap added support for AVM PCMCIA Fritz!Card + * -mh split into separate file + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif + +#if NISIC > 0 && defined(AVM_PCMCIA) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/layer1/pcmcia_isic.h> + +#ifndef __FreeBSD__ +/* PCMCIA support routines */ +static u_int8_t avma1_pcmcia_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void avma1_pcmcia_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void avma1_pcmcia_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void avma1_pcmcia_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * AVM PCMCIA Fritz!Card special registers + *---------------------------------------------------------------------------*/ + +/* + * register offsets from i/o base 0x140 or 0x300 + */ +#define ADDR_REG_OFFSET 0x02 +#define DATA_REG_OFFSET 0x03 +#define STAT0_OFFSET 0x04 +#define STAT1_OFFSET 0x05 +#define MODREG_OFFSET 0x06 +#define VERREG_OFFSET 0x07 +/* + * AVM PCMCIA Status Latch 0 read only bits + */ +#define ASL_IRQ_TIMER 0x10 /* Timer interrupt, active low */ +#define ASL_IRQ_ISAC 0x20 /* ISAC interrupt, active low */ +#define ASL_IRQ_HSCX 0x40 /* HSX interrupt, active low */ +#define ASL_IRQ_BCHAN ASL_IRQ_HSCX +#define ASL_IRQ_Pending (ASL_IRQ_ISAC | ASL_IRQ_HSCX | ASL_IRQ_TIMER) +/* + * AVM Status Latch 0 write only bits + */ +#define ASL_RESET_ALL 0x01 /* reset siemens IC's, active 1 */ +#define ASL_TIMERDISABLE 0x02 /* active high */ +#define ASL_TIMERRESET 0x04 /* active high */ +#define ASL_ENABLE_INT 0x08 /* active high */ +/* + * AVM Status Latch 1 write only bits + */ +#define ASL1_LED0 0x10 /* active high */ +#define ASL1_LED1 0x20 /* active high */ + +#define ASL1_ENABLE_S0 0xc0 /* enable active S0 I/F */ + +/*----- EEpromless controller -----*/ +/* + * AVM Status Latch read/write bit + */ + +#define ASL_TESTBIT 0x80 + + +/*---------------------------------------------------------------------------* + * AVM read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static int PCMCIA_IO_BASE = 0; /* ap: XXX hack */ +static void +avma1_pcmcia_read_fifo(void *buf, const void *base, size_t len) +{ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base - 0x20); + insb(PCMCIA_IO_BASE + DATA_REG_OFFSET, (u_char *)buf, (u_int)len); +} +#else +/* offsets of the different 'what' arguments */ +static u_int8_t what_map[] = { + 0x20-0x20, /* ISIC_WHAT_ISAC */ + 0xA0-0x20, /* ISIC_WHAT_HSCXA */ + 0xE0-0x20 /* ISIC_WHAT_HSCXB */ +}; +static void +avma1_pcmcia_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]); + bus_space_read_multi_1(t, h, DATA_REG_OFFSET, buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_pcmcia_write_fifo(void *base, const void *buf, size_t len) +{ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base - 0x20); + outsb(PCMCIA_IO_BASE + DATA_REG_OFFSET, (u_char *)buf, (u_int)len); +} +#else +static void +avma1_pcmcia_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]); + bus_space_write_multi_1(t, h, DATA_REG_OFFSET, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +avma1_pcmcia_write_reg(u_char *base, u_int offset, u_int v) +{ + /* offset includes 0x20 FIFO ! */ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base+offset-0x20); + outb(PCMCIA_IO_BASE + DATA_REG_OFFSET, (u_char)v); +} +#else +static void +avma1_pcmcia_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]+offs); + bus_space_write_1(t, h, DATA_REG_OFFSET, data); +} +#endif + +/*---------------------------------------------------------------------------* + * AVM read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +avma1_pcmcia_read_reg(u_char *base, u_int offset) +{ + /* offset includes 0x20 FIFO ! */ + outb(PCMCIA_IO_BASE + ADDR_REG_OFFSET, (int)base+offset-0x20); + return (inb(PCMCIA_IO_BASE + DATA_REG_OFFSET)); +} +#else +static u_int8_t +avma1_pcmcia_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ADDR_REG_OFFSET, what_map[what]+offs); + return bus_space_read_1(t, h, DATA_REG_OFFSET); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_avma1_pcmcia - probe for AVM PCMCIA Fritz!Card + * This is in the bus attachemnt part on NetBSD (pcmcia_isic.c), no + * card specicfic probe is needed on direct config buses like pcmcia. + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_avma1_pcmcia(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + u_char byte; + int i; + u_int cardinfo; + + /* check max unit range */ + + if(dev->id_unit > 1) + { + printf("isic%d: Error, unit %d > MAXUNIT for AVM PCMCIA Fritz!Card\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* + * we trust the IRQ we got from PCCARD service + */ + sc->sc_irq = dev->id_irq; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x140: + case 0x300: + break; + default: + printf("isic%d: Error, invalid iobase 0x%x specified for AVM PCMCIA Fritz!Card.\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* ResetController */ + + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 20); + outb(dev->id_iobase + STAT0_OFFSET, 0x01); + DELAY(SEC_DELAY / 20); + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + + /* + * CheckController + * The logic to check for the PCMCIA was adapted as + * described by AVM. + */ + + outb(dev->id_iobase + ADDR_REG_OFFSET, 0x21); /* ISAC STAR */ + if ( (byte=inb(dev->id_iobase + DATA_REG_OFFSET) & 0xfd) != 0x48 ) + { + printf("isic%d: Error, ISAC STAR for AVM PCMCIA is 0x%0x (should be 0x48)\n", + dev->id_unit, byte); + return(0); + } + + outb(dev->id_iobase + ADDR_REG_OFFSET, 0xa1); /* HSCX STAR */ + if ( (byte=inb(dev->id_iobase + DATA_REG_OFFSET) & 0xfd) != 0x48 ) + { + printf("isic%d: Error, HSCX STAR for AVM PCMCIA is 0x%0x (should be 0x48)\n", + dev->id_unit, byte); + return(0); + } + + byte = ASL_TESTBIT; + for (i=0; i<256; i++) { + byte = byte ? 0 : ASL_TESTBIT; + outb(dev->id_iobase + STAT0_OFFSET, byte); + if ((inb(dev->id_iobase+STAT0_OFFSET)&ASL_TESTBIT)!=byte) { + printf("isic%d: Error during toggle of AVM PCMCIA Status Latch0\n", + dev->id_unit); + return(0); + } + } + + sc->clearirq = NULL; + sc->readreg = avma1_pcmcia_read_reg; + sc->writereg = avma1_pcmcia_write_reg; + + sc->readfifo = avma1_pcmcia_read_fifo; + sc->writefifo = avma1_pcmcia_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_PCFRITZ; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; /* ap: XXX ??? */ + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + /* + * NOTE: for PCMCIA these are no real addrs; they are + * offsets to be written into the base+ADDR_REG_OFFSET register + * to pick up the values of the bytes fro base+DATA_REG_OFFSET + * + * see also the logic in the avma1_pcmcia_* routines; + * therefore we also must have the base addr in some static + * space or struct; XXX better solution? + */ + + PCMCIA_IO_BASE = dev->id_iobase; + ISAC_BASE = (caddr_t)0x20; + + HSCX_A_BASE = (caddr_t)0xA0; + HSCX_B_BASE = (caddr_t)0xE0; + + /* + * Read HSCX A/B VSTR. + * Expected value for AVM A1 is 0x04 or 0x05 and for the + * AVM Fritz!Card is 0x05 in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for AVM PCMCIA Fritz!Card\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: 0x%0x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: 0x%0x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + /* + * seems we really have an AVM PCMCIA Fritz!Card controller + */ + cardinfo = inb(dev->id_iobase + VERREG_OFFSET)<<8 | inb(dev->id_iobase + MODREG_OFFSET); + printf("isic%d: successfully detect AVM PCMCIA cardinfo = 0x%0x\n", + dev->id_unit, cardinfo); + dev->id_flags = FLAG_AVM_A1_PCMCIA; + return (1); +} +#endif /* __FreeBSD__ */ + + + +/*---------------------------------------------------------------------------* + * isic_attach_fritzpcmcia - attach Fritz!Card + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_fritzpcmica(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* ResetController again just to make sure... */ + + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + STAT0_OFFSET, 0x01); + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + outb(dev->id_iobase + STAT0_OFFSET, ASL_TIMERDISABLE | + ASL_TIMERRESET | ASL_ENABLE_INT); + /* DELAY(SEC_DELAY / 10); */ + + return(1); +} + +#else + +/* + * XXX - one time only! Some of this has to go into an enable + * function, with apropriate counterpart in disable, so a card + * could be removed an inserted again. But never mind for now, + * this won't work anyway for several reasons (both in NetBSD + * and in I4B). + */ +int +isic_attach_fritzpcmcia(struct pcmcia_isic_softc *psc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa) +{ + struct isic_softc *sc = &psc->sc_isic; + bus_space_tag_t t; + bus_space_handle_t h; + + /* Validate config info */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of memory spaces %d should be 1\n", + cfe->num_iospace); + + /* Allocate pcmcia space - exactly as dictated by the card */ + if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, cfe->iospace[0].length, + 0, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + + /* map them */ + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, + cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return 0; + } + + /* Setup bus space maps */ + sc->sc_num_mappings = 1; + sc->sc_cardtyp = CARD_TYPEP_PCFRITZ; + MALLOC_MAPS(sc); + + /* Copy our handles/tags to the MI maps */ + sc->sc_maps[0].t = psc->sc_pcioh.iot; + sc->sc_maps[0].h = psc->sc_pcioh.ioh; + sc->sc_maps[0].offset = 0; + sc->sc_maps[0].size = 0; /* not our mapping */ + + t = sc->sc_maps[0].t; + h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = avma1_pcmcia_read_reg; + sc->writereg = avma1_pcmcia_write_reg; + + sc->readfifo = avma1_pcmcia_read_fifo; + sc->writefifo = avma1_pcmcia_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_PCFRITZ; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* Reset controller again just to make sure... */ + + bus_space_write_1(t, h, STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, STAT0_OFFSET, 0x01); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, STAT0_OFFSET, 0x00); + DELAY(SEC_DELAY / 10); + + /* enable IRQ, disable counter IRQ */ + + bus_space_write_1(t, h, STAT0_OFFSET, ASL_TIMERDISABLE | + ASL_TIMERRESET | ASL_ENABLE_INT); + + return 1; +} +#endif + +#endif /* NISIC > 0 && defined(AVM_PCMCIA) */ diff --git a/sys/i4b/layer1/i4b_bchan.c b/sys/i4b/layer1/i4b_bchan.c new file mode 100644 index 000000000000..17ee27364777 --- /dev/null +++ b/sys/i4b/layer1/i4b_bchan.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_bchan.c - B channel handling L1 procedures + * ---------------------------------------------- + * + * $Id: i4b_bchan.c,v 1.28 1998/12/05 18:04:28 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:21:57 1998] + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#else +#define NISIC 1 +#endif + +#if NISIC > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#ifdef __FreeBSD__ +static void isic_bchannel_start(int unit, int h_chan); +static void isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp); +#else +static void isic_bchannel_start __P((int unit, int h_chan)); +static void isic_bchannel_stat __P((int unit, int h_chan, bchan_statistics_t *bsp)); +#endif + +static void isic_set_linktab(int unit, int channel, drvr_link_t *dlt); +static isdn_link_t *isic_ret_linktab(int unit, int channel); + +/*---------------------------------------------------------------------------* + * initialize one B channels rx/tx data structures and init/deinit HSCX + *---------------------------------------------------------------------------*/ +void +isic_bchannel_setup(int unit, int h_chan, int bprot, int activate) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + isic_Bchan_t *chan = &sc->sc_chan[h_chan]; + + int s = SPLI4B(); + + if(activate == 0) + { + /* deactivation */ + isic_hscx_init(sc, h_chan, activate); + } + + DBGL1(L1_BCHAN, "isic_bchannel_setup", ("unit=%d, channel=%d, %s\n", + sc->sc_unit, h_chan, activate ? "activate" : "deactivate")); + + /* general part */ + + chan->unit = sc->sc_unit; /* unit number */ + chan->channel = h_chan; /* B channel */ + chan->bprot = bprot; /* B channel protocol */ + chan->state = HSCX_IDLE; /* B channel state */ + + /* receiver part */ + + i4b_Bcleanifq(&chan->rx_queue); /* clean rx queue */ + + chan->rx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->rxcount = 0; /* reset rx counter */ + + i4b_Bfreembuf(chan->in_mbuf); /* clean rx mbuf */ + + chan->in_mbuf = NULL; /* reset mbuf ptr */ + chan->in_cbptr = NULL; /* reset mbuf curr ptr */ + chan->in_len = 0; /* reset mbuf data len */ + + /* transmitter part */ + + i4b_Bcleanifq(&chan->tx_queue); /* clean tx queue */ + + chan->tx_queue.ifq_maxlen = IFQ_MAXLEN; + + chan->txcount = 0; /* reset tx counter */ + + i4b_Bfreembuf(chan->out_mbuf_head); /* clean tx mbuf */ + + chan->out_mbuf_head = NULL; /* reset head mbuf ptr */ + chan->out_mbuf_cur = NULL; /* reset current mbuf ptr */ + chan->out_mbuf_cur_ptr = NULL; /* reset current mbuf data ptr */ + chan->out_mbuf_cur_len = 0; /* reset current mbuf data cnt */ + + if(activate != 0) + { + /* activation */ + isic_hscx_init(sc, h_chan, activate); + } + + splx(s); +} + +/*---------------------------------------------------------------------------* + * start transmission on a b channel + *---------------------------------------------------------------------------*/ +static void +isic_bchannel_start(int unit, int h_chan) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + + register isic_Bchan_t *chan = &sc->sc_chan[h_chan]; + register int next_len; + register int len; + + int s; + int activity = -1; + int cmd = 0; + + s = SPLI4B(); /* enter critical section */ + if(chan->state & HSCX_TX_ACTIVE) /* already running ? */ + { + splx(s); + return; /* yes, leave */ + } + + /* get next mbuf from queue */ + + IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); + + if(chan->out_mbuf_head == NULL) /* queue empty ? */ + { + splx(s); /* leave critical section */ + return; /* yes, exit */ + } + + /* init current mbuf values */ + + chan->out_mbuf_cur = chan->out_mbuf_head; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + + /* activity indicator for timeout handling */ + + if(chan->bprot == BPROT_NONE) + { + if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) + activity = ACT_TX; + } + else + { + activity = ACT_TX; + } + + chan->state |= HSCX_TX_ACTIVE; /* we start transmitting */ + + if(sc->sc_trace & TRACE_B_TX) /* if trace, send mbuf to trace dev */ + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + + len = 0; /* # of chars put into HSCX tx fifo this time */ + + /* + * fill the HSCX tx fifo with data from the current mbuf. if + * current mbuf holds less data than HSCX fifo length, try to + * get the next mbuf from (a possible) mbuf chain. if there is + * not enough data in a single mbuf or in a chain, then this + * is the last mbuf and we tell the HSCX that it has to send + * CRC and closing flag + */ + + while((len < sc->sc_bfifolen) && chan->out_mbuf_cur) + { + /* + * put as much data into the HSCX fifo as is + * available from the current mbuf + */ + + if((len + chan->out_mbuf_cur_len) >= sc->sc_bfifolen) + next_len = sc->sc_bfifolen - len; + else + next_len = chan->out_mbuf_cur_len; + +#ifdef NOTDEF + printf("b:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ", + chan->out_mbuf_head, + chan->out_mbuf_cur, + chan->out_mbuf_cur_ptr, + chan->out_mbuf_cur_len, + len, + next_len); +#endif + + /* wait for tx fifo write enabled */ + + isic_hscx_waitxfw(sc, h_chan); + + /* write what we have from current mbuf to HSCX fifo */ + + HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, next_len); + + len += next_len; /* update # of bytes written */ + chan->txcount += next_len; /* statistics */ + chan->out_mbuf_cur_ptr += next_len; /* data ptr */ + chan->out_mbuf_cur_len -= next_len; /* data len */ + + /* + * in case the current mbuf (of a possible chain) data + * has been put into the fifo, check if there is a next + * mbuf in the chain. If there is one, get ptr to it + * and update the data ptr and the length + */ + + if((chan->out_mbuf_cur_len <= 0) && + ((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)) + { + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + } + } + + /* + * if there is either still data in the current mbuf and/or + * there is a successor on the chain available issue just + * a XTF (transmit) command to HSCX. if ther is no more + * data available from the current mbuf (-chain), issue + * an XTF and an XME (message end) command which will then + * send the CRC and the closing HDLC flag sequence + */ + + if(chan->out_mbuf_cur && (chan->out_mbuf_cur_len > 0)) + { + /* + * more data available, send current fifo out. + * next xfer to HSCX tx fifo is done in the + * HSCX interrupt routine. + */ + + cmd |= HSCX_CMDR_XTF; + } + else + { + /* end of mbuf chain */ + + if(chan->bprot == BPROT_NONE) + cmd |= HSCX_CMDR_XTF; + else + cmd |= HSCX_CMDR_XTF | HSCX_CMDR_XME; + + i4b_Bfreembuf(chan->out_mbuf_head); /* free mbuf chain */ + + chan->out_mbuf_head = NULL; + chan->out_mbuf_cur = NULL; + chan->out_mbuf_cur_ptr = NULL; + chan->out_mbuf_cur_len = 0; + } + + /* call timeout handling routine */ + + if(activity == ACT_RX || activity == ACT_TX) + (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity); + + if(cmd) + isic_hscx_cmd(sc, h_chan, cmd); + + splx(s); +} + +/*---------------------------------------------------------------------------* + * fill statistics struct + *---------------------------------------------------------------------------*/ +static void +isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + isic_Bchan_t *chan = &sc->sc_chan[h_chan]; + int s; + + s = SPLI4B(); + + bsp->outbytes = chan->txcount; + bsp->inbytes = chan->rxcount; + + chan->txcount = 0; + chan->rxcount = 0; + + splx(s); +} + +/*---------------------------------------------------------------------------* + * return the address of isic drivers linktab + *---------------------------------------------------------------------------*/ +static isdn_link_t * +isic_ret_linktab(int unit, int channel) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + isic_Bchan_t *chan = &sc->sc_chan[channel]; + + return(&chan->isdn_linktab); +} + +/*---------------------------------------------------------------------------* + * set the driver linktab in the b channel softc + *---------------------------------------------------------------------------*/ +static void +isic_set_linktab(int unit, int channel, drvr_link_t *dlt) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + isic_Bchan_t *chan = &sc->sc_chan[channel]; + + chan->drvr_linktab = dlt; +} + +/*---------------------------------------------------------------------------* + * initialize our local linktab + *---------------------------------------------------------------------------*/ +void +isic_init_linktab(struct isic_softc *sc) +{ + isic_Bchan_t *chan = &sc->sc_chan[HSCX_CH_A]; + isdn_link_t *lt = &chan->isdn_linktab; + + /* make sure the hardware driver is known to layer 4 */ + ctrl_types[CTRL_PASSIVE].set_linktab = isic_set_linktab; + ctrl_types[CTRL_PASSIVE].get_linktab = isic_ret_linktab; + + /* local setup */ + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_A; + lt->bch_config = isic_bchannel_setup; + lt->bch_tx_start = isic_bchannel_start; + lt->bch_stat = isic_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; + + chan = &sc->sc_chan[HSCX_CH_B]; + lt = &chan->isdn_linktab; + + lt->unit = sc->sc_unit; + lt->channel = HSCX_CH_B; + lt->bch_config = isic_bchannel_setup; + lt->bch_tx_start = isic_bchannel_start; + lt->bch_stat = isic_bchannel_stat; + lt->tx_queue = &chan->tx_queue; + + /* used by non-HDLC data transfers, i.e. telephony drivers */ + lt->rx_queue = &chan->rx_queue; + + /* used by HDLC data transfers, i.e. ipr and isp drivers */ + lt->rx_mbuf = &chan->in_mbuf; +} + +/*---------------------------------------------------------------------------* + * telephony silence detection + *---------------------------------------------------------------------------*/ + +#define TEL_IDLE_MIN (BCH_MAX_DATALEN/2) + +int +isic_hscx_silence(unsigned char *data, int len) +{ + register int i = 0; + register int j = 0; + + /* count idle bytes */ + + for(;i < len; i++) + { + if((*data >= 0xaa) && (*data <= 0xac)) + j++; + data++; + } + +#ifdef NOTDEF + printf("isic_hscx_silence: got %d silence bytes in frame\n", j); +#endif + + if(j < (TEL_IDLE_MIN)) + return(0); + else + return(1); + +} + +#endif /* NISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_ctx_s0P.c b/sys/i4b/layer1/i4b_ctx_s0P.c new file mode 100644 index 000000000000..f9e6b7f03eed --- /dev/null +++ b/sys/i4b/layer1/i4b_ctx_s0P.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Creatix PnP cards + * ============================================================ + * + * $Id: i4b_ctx_s0P.c,v 1.17 1998/12/16 09:32:50 hm Exp $ + * + * last edit-date: [Mon Dec 14 17:26:30 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +#include "isic.h" +#include "opt_i4b.h" +#include "pnp.h" + +#else + +#define NISIC 1 +#define NPNP 1 + +#endif + +#if (NISIC > 0) && (NPNP > 0) && defined(CRTX_S0_P) + +#include <sys/param.h> + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t ctxs0P_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void ctxs0P_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void ctxs0P_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void ctxs0P_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +void isic_attach_Cs0P(struct isic_softc *sc); +#endif + +#ifdef __FreeBSD__ +#include <i386/isa/pnp.h> +extern void isicintr ( int unit ); +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +ctxs0P_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +ctxs0P_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_read_multi_1(t, h, o + 0x3e, buf, size); +} + +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +ctxs0P_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +ctxs0P_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_multi_1(t, h, o + 0x3e, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +ctxs0P_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} + +#else + +static void +ctxs0P_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_1(t, h, o + offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Creatix ISDN-S0 P&P ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +ctxs0P_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} + +#else + +static u_int8_t +ctxs0P_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + return bus_space_read_1(t, h, o + offs); +} + +#endif + +#ifdef __FreeBSD__ + +/*---------------------------------------------------------------------------* + * isic_probe_Cs0P - probe for Creatix ISDN-S0 P&P and compatibles + *---------------------------------------------------------------------------*/ +int +isic_probe_Cs0P(struct isa_device *dev, unsigned int iobase2) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Creatix ISDN-S0 P&P!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 5: + case 7: + case 10: + case 11: + case 12: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Creatix ISDN-S0 P&P!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Creatix ISDN-S0 P&P!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + if(iobase2 == 0) + { + printf("isic%d: Error, iobase2 is 0 for Creatix ISDN-S0 P&P!\n", + dev->id_unit); + return(0); + } + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x120: + case 0x180: +/*XXX*/ break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Creatix ISDN-S0 P&P!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = ctxs0P_read_reg; + sc->writereg = ctxs0P_write_reg; + + sc->readfifo = ctxs0P_read_fifo; + sc->writefifo = ctxs0P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_CS0P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) dev->id_iobase - 0x20; + HSCX_A_BASE = (caddr_t) iobase2 - 0x20; + HSCX_B_BASE = (caddr_t) iobase2; + + /* + * Read HSCX A/B VSTR. Expected value for the Creatix PnP card is + * 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Creatix PnP\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_s0163P - attach Creatix ISDN-S0 P&P + *---------------------------------------------------------------------------*/ +int +isic_attach_Cs0P(struct isa_device *dev, unsigned int iobase2) +{ + outb((dev->id_iobase) + 0x1c, 0); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase) + 0x1c, 1); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else /* !__FreeBSD__ */ + +void +isic_attach_Cs0P(struct isic_softc *sc) +{ + /* init card */ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, 0x1c, 0); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 0x1c, 1); + DELAY(SEC_DELAY / 10); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = ctxs0P_read_reg; + sc->writereg = ctxs0P_write_reg; + + sc->readfifo = ctxs0P_read_fifo; + sc->writefifo = ctxs0P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_CS0P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} +#endif + +#endif /* (NISIC > 0) && (NPNP > 0) && defined(CRTX_S0_P) */ + diff --git a/sys/i4b/layer1/i4b_drn_ngo.c b/sys/i4b/layer1/i4b_drn_ngo.c new file mode 100644 index 000000000000..a5f3d6941923 --- /dev/null +++ b/sys/i4b/layer1/i4b_drn_ngo.c @@ -0,0 +1,542 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_drn_ngo.c - Dr. Neuhaus Niccy GO@ and SAGEM Cybermod + * -------------------------------------------------------- + * + * $Id: i4b_drn_ngo.c,v 1.19 1998/12/16 09:32:50 hm Exp $ + * + * last edit-date: [Mon Dec 14 17:26:03 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +#include "isic.h" +#include "opt_i4b.h" +#include "pnp.h" + +#else + +#define NISIC 1 +#define NPNP 1 + +#endif + +#if (NISIC > 0) && (NPNP > 0) && defined(DRN_NGO) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +/*---------------------------------------------------------------------------* + * Niccy GO@ definitions + * + * the card uses 2 i/o addressranges each using 2 bytes + * + * addressrange 0: + * offset 0 - ISAC dataregister + * offset 1 - HSCX dataregister + * addressrange 1: + * offset 0 - ISAC addressregister + * offset 1 - HSCX addressregister + * + * to access an ISAC/HSCX register, you have to write the register + * number into the ISAC or HSCX addressregister and then read/write + * data for the ISAC/HSCX register into/from the corresponding + * dataregister. + * + * Thanks to Klaus Muehle of Dr. Neuhaus Telekommunikation for giving + * out this information! + * + *---------------------------------------------------------------------------*/ +#define NICCY_PORT_MIN 0x200 +#define NICCY_PORT_MAX 0x3e0 + +#define HSCX_ABIT 0x1000 /* flag, HSCX A is meant */ +#define HSCX_BBIT 0x2000 /* flag, HSCX B is meant */ + +#define HSCX_BOFF 0x40 + +#define ADDR_OFF 2 /* address register range offset XXX */ + +#define ISAC_DATA 0 +#define HSCX_DATA 1 + +#define ISAC_ADDR 0 +#define HSCX_ADDR 1 + +#ifdef __FreeBSD__ + +#if 0 +#define HSCXADEBUG +#define HSCXBDEBUG +#define ISACDEBUG +#else +#undef HSCXADEBUG +#undef HSCXBDEBUG +#undef ISACDEBUG +#endif + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ read fifo routine + *---------------------------------------------------------------------------*/ +static void +drnngo_read_fifo(void *buf, const void *base, size_t len) +{ + register int offset; + register u_int data; + + int x = SPLI4B(); + + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = 0; +#ifdef HSCXADEBUG +printf("GO/A/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = HSCX_BOFF; +#ifdef HSCXBDEBUG +printf("GO/B/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else + { + (u_int)data = ((u_int)base + ISAC_DATA); + (u_int)base += (ADDR_OFF + ISAC_ADDR); + offset = 0; +#ifdef ISACDEBUG +printf("GO/I/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + + for(;len > 0; len--, offset++) + { + outb((int)base, (u_char)offset); + *((u_char *)buf + offset) = inb((int)data); + } + + splx(x); +} + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ write fifo routine + *---------------------------------------------------------------------------*/ +static void +drnngo_write_fifo(void *base, const void *buf, size_t len) +{ + register int offset; + register u_int data; + + int x = SPLI4B(); + + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = 0; +#ifdef HSCXADEBUG +printf("GO/A/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + (u_int)data = ((u_int)base + HSCX_DATA); + (u_int)base += (ADDR_OFF + HSCX_ADDR); + offset = HSCX_BOFF; +#ifdef HSCXBDEBUG +printf("GO/B/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + else + { + (u_int)data = ((u_int)base + ISAC_DATA); + (u_int)base += (ADDR_OFF + ISAC_ADDR); + offset = 0; +#ifdef ISACDEBUG +printf("GO/I/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len); +#endif + } + + for(;len > 0; len--, offset++) + { + outb((int)base, (u_char)offset); + outb((int)data, *((u_char *)buf + offset)); + } + + splx(x); +} + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ write register routine + *---------------------------------------------------------------------------*/ +static void +drnngo_write_reg(u_char *base, u_int offset, u_int v) +{ + int x = SPLI4B(); + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)offset); + outb((int)base + HSCX_DATA, (u_char)v); +#ifdef HSCXADEBUG +printf("GO/A/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)offset, (u_char)v); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)(offset + HSCX_BOFF)); + outb((int)base + HSCX_DATA, (u_char)v); +#ifdef HSCXBDEBUG +printf("GO/B/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)(offset + HSCX_BOFF), (u_char)v); +#endif + } + else + { + outb((int)base + ADDR_OFF + ISAC_ADDR, (u_char)offset); + outb((int)base + ISAC_DATA, (u_char)v); +#ifdef ISACDEBUG +printf("GO/I/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + ISAC_ADDR, (int)base + ISAC_DATA, + (u_char)offset, (u_char)v); +#endif + } + splx(x); +} + +/*---------------------------------------------------------------------------* + * Dr. Neuhaus Niccy GO@ read register routine + *---------------------------------------------------------------------------*/ +static u_char +drnngo_read_reg(u_char *base, u_int offset) +{ + u_char val; + int x = SPLI4B(); + + if((u_int)base & HSCX_ABIT) + { + (u_int)base &= ~HSCX_ABIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)offset); + val = inb((int)base + HSCX_DATA); +#ifdef HSCXADEBUG +printf("GO/A/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)offset, (u_char)val); +#endif + } + else if((u_int)base & HSCX_BBIT) + { + (u_int)base &= ~HSCX_BBIT; + outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)(offset + HSCX_BOFF)); + val = inb((int)base + HSCX_DATA); +#ifdef HSCXBDEBUG +printf("GO/B/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA, + (u_char)(offset + HSCX_BOFF), (u_char)val); +#endif + } + else + { + outb((int)base + ADDR_OFF + ISAC_ADDR, (u_char)offset); + val = inb((int)base + ISAC_DATA); +#ifdef ISACDEBUG +printf("GO/I/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n", + (int)base + ADDR_OFF + ISAC_ADDR, (int)base + ISAC_DATA, + (u_char)offset, (u_char)val); +#endif + } + splx(x); + return(val); +} + +/*---------------------------------------------------------------------------* + * isic_probe_drnngo - probe for Dr. Neuhaus Niccy GO@ + *---------------------------------------------------------------------------*/ +int +isic_probe_drnngo(struct isa_device *dev, unsigned int iobase2) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq)-1) + { + case 3: + case 4: + case 5: + case 9: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + if(dev->id_iobase < NICCY_PORT_MIN || dev->id_iobase > NICCY_PORT_MAX) + { + printf("isic%d: Error, invalid iobase 0x%x specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + if(iobase2 == 0) + { + printf("isic%d: Error, iobase2 is 0 for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit); + return(0); + } + + if(iobase2 < NICCY_PORT_MIN || iobase2 > NICCY_PORT_MAX) + { + printf("isic%d: Error, invalid port1 0x%x specified for Dr. Neuhaus Niccy GO@!\n", + dev->id_unit, iobase2); + return(0); + } + +/*XXX*/ if((dev->id_iobase + 2) != iobase2) + { + printf("isic%d: Error, port1 must be (port0+2) for Dr.Neuhaus Niccy GO@!\n", + dev->id_unit); + return(0); + } + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = drnngo_read_reg; + sc->writereg = drnngo_write_reg; + + sc->readfifo = drnngo_read_fifo; + sc->writefifo = drnngo_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_DRNNGO; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t)dev->id_iobase; + HSCX_A_BASE = (caddr_t)(((u_int)dev->id_iobase) | HSCX_ABIT); + HSCX_B_BASE = (caddr_t)(((u_int)dev->id_iobase) | HSCX_BBIT); + + /* + * Read HSCX A/B VSTR. Expected value for Dr. Neuhaus Niccy GO@ based + * boards is 0x05 in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Dr. Neuhaus Niccy GO@\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_drnngo - attach Dr. Neuhaus Niccy GO@ + *---------------------------------------------------------------------------*/ +int +isic_attach_drnngo(struct isa_device *dev, unsigned int iobase2) +{ + return (1); +} + +#else + +static u_int8_t drnngo_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void drnngo_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void drnngo_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void drnngo_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +void isic_attach_drnngo __P((struct isic_softc *sc)); + +/* + * Mapping from "what" parameter to offsets into the io map + */ +static struct { + bus_size_t oa, /* address register offset */ + od, /* data register offset */ + or; /* additional chip register offset */ +} offset[] = +{ + { ISAC_ADDR, ISAC_DATA, 0 }, /* ISAC access */ + { HSCX_ADDR, HSCX_DATA, 0 }, /* HSCX A access */ + { HSCX_ADDR, HSCX_DATA, HSCX_BOFF } /* HSCX B access */ +}; + +static void +drnngo_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offset[what].or); + bus_space_read_multi_1(t, hd, offset[what].od, buf, size); +} + +static void +drnngo_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offset[what].or); + bus_space_write_multi_1(t, hd, offset[what].od, (u_int8_t*)buf, size); +} + +static void +drnngo_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offs+offset[what].or); + bus_space_write_1(t, hd, offset[what].od, data); +} + +static u_int8_t +drnngo_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h; + bus_space_write_1(t, ha, offset[what].oa, offs+offset[what].or); + return bus_space_read_1(t, hd, offset[what].od); +} + +void +isic_attach_drnngo(struct isic_softc *sc) +{ + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = drnngo_read_reg; + sc->writereg = drnngo_write_reg; + + sc->readfifo = drnngo_read_fifo; + sc->writefifo = drnngo_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_DRNNGO; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} + +#endif + +#endif /* (NISIC > 0) && (NPNP > 0) && defined(DRN_NGO) */ diff --git a/sys/i4b/layer1/i4b_dynalink.c b/sys/i4b/layer1/i4b_dynalink.c new file mode 100644 index 000000000000..846e79ae6da1 --- /dev/null +++ b/sys/i4b/layer1/i4b_dynalink.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 1998 Martijn Plak. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isdn4bsd layer1 driver for Dynalink IS64PH isdn TA + * ================================================== + * + * $Id: i4b_dynalink.c,v 1.8 1998/12/17 04:55:38 hm Exp $ + * + * last edit-date: [Thu Dec 17 05:50:39 1998] + * + * written by Martijn Plak <tigrfhur@xs4all.nl> + * + * -mp 11 jun 1998 first try, code borrowed from Creatix driver + * -mp 18 jun 1998 cleaned up code + * -hm FreeBSD PnP + * -mp 17 dec 1998 made it compile again + * + *---------------------------------------------------------------------------*/ + +/* NOTES: + + This driver was written for the Dynalink IS64PH ISDN TA, based on two + Siemens chips (HSCX 21525 and ISAC 2186). It is sold in the Netherlands. + + model numbers found on (my) card: + IS64PH, TAS100H-N, P/N:89590555, TA200S100045521 + + chips: + Siemens PSB 21525N, HSCX TE V2.1 + Siemens PSB 2186N, ISAC-S TE V1.1 + 95MS14, PNP + + plug-and-play info: + device id "ASU1688" + vendor id 0x88167506 + serial 0x00000044 + i/o port 4 byte alignment, 4 bytes requested, + 10 bit i/o decoding, 0x100-0x3f8 (?) + irq 3,4,5,9,10,11,12,15, high true, edge sensitive + + At the moment I'm writing this Dynalink is replacing this card with + one based on a single Siemens chip (IPAC). It will apparently be sold + under the same model name. + + This driver might also work for Asuscom cards. +*/ + +#ifdef __FreeBSD__ + +#include "isic.h" +#include "opt_i4b.h" +#include "pnp.h" + +#else + +#define NISIC 1 +#define NPNP 1 + +#endif + +#if (NISIC > 0) && (NPNP > 0) && defined(DYNALINK) + +/* HEADERS +*/ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <i386/isa/pnp.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#ifdef __FreeBSD__ +static void dynalink_read_fifo(void *buf, const void *base, size_t len); +static void dynalink_write_fifo(void *base, const void *buf, size_t len); +static void dynalink_write_reg(u_char *base, u_int offset, u_int v); +static u_char dynalink_read_reg(u_char *base, u_int offset); + +extern struct isa_driver isicdriver; + +#else +static void dynalink_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size); +static void dynalink_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size); +static void dynalink_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data); +static u_int8_t dynalink_read_reg(struct isic_softc *sc, int what, bus_size_t offs); +void isic_attach_Dyn(struct isic_softc *sc); +#endif + +/* io address mapping */ +#define ISAC 0 +#define HSCX 1 +#define ADDR 2 + +/* ADDR bits */ +#define ADDRMASK 0x7F +#define RESET 0x80 + +/* HSCX register offsets */ +#define HSCXA 0x00 +#define HSCXB 0x40 + +#ifdef __FreeBSD__ +/* base address juggling */ +#define HSCXB_HACK 0x400 +#define IOBASE(addr) (((int)addr)&0x3FC) +#define IOADDR(addr) (((int)addr)&0x3FF) +#define IS_HSCXB_HACK(addr) ((((int)addr)&HSCXB_HACK)?HSCXB:HSCXA) + +/* ISIC probe and attach +*/ + +int +isic_probe_Dyn(struct isa_device *dev, unsigned int iobase2) +{ + + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Dynalink IS64PH.\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 4: + case 5: + case 9: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Dynalink IS64PH.\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Dynalink IS64PH.\n", + dev->id_unit, (u_long)dev->id_maddr); + return (0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + if ( (dev->id_iobase < 0x100) || + (dev->id_iobase > 0x3f8) || + (dev->id_iobase & 3) ) + { + printf("isic%d: Error, invalid iobase 0x%x specified for Dynalink!\n", dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = dynalink_read_reg; + sc->writereg = dynalink_write_reg; + sc->readfifo = dynalink_read_fifo; + sc->writefifo = dynalink_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_DYNALINK; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + ISAC_BASE = (caddr_t) sc->sc_port; + HSCX_A_BASE = (caddr_t) sc->sc_port + 1; + HSCX_B_BASE = (caddr_t) sc->sc_port + 1 + HSCXB_HACK; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Dynalink\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +int +isic_attach_Dyn(struct isa_device *dev, unsigned int iobase2) +{ + outb((dev->id_iobase)+ADDR, RESET); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase)+ADDR, 0); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else + +void isic_attach_Dyn(struct isic_softc *sc) +{ + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = dynalink_read_reg; + sc->writereg = dynalink_write_reg; + sc->readfifo = dynalink_read_fifo; + sc->writefifo = dynalink_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_DYNALINK; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("%s: HSCX VSTR test failed for Dynalink PnP\n", + sc->sc_dev.dv_xname); + printf("%s: HSC0: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR)); + printf("%s: HSC1: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR)); + return; + } + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR, RESET); + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR, 0); + DELAY(SEC_DELAY / 10); +} + +#endif /* ISIC>0 && NPNP>0 && defined(DYNALINK) */ + +/* LOW-LEVEL DEVICE ACCESS + + NOTE: The isdn4bsd code expects the two HSCX channels at different + base addresses. I'm faking this, and remap them to the same address + in the low-level routines. Search for HSCXB_HACK and IS_HSCXB_HACK. + + REM: this is only true for the FreeBSD version of I4B! +*/ + +#ifdef __FreeBSD__ +static void +dynalink_read_fifo(void *buf, const void *base, size_t len) +{ + outb(IOBASE(base)+ADDR, 0+IS_HSCXB_HACK(base)); + insb(IOADDR(base), (u_char *)buf, (u_int)len); +} +#else +static void +dynalink_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, 0); + bus_space_read_multi_1(t, h, ISAC, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA); + bus_space_read_multi_1(t, h, HSCX, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB); + bus_space_read_multi_1(t, h, HSCX, buf, size); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static void +dynalink_write_fifo(void *base, const void *buf, size_t len) +{ + outb(IOBASE(base)+ADDR, 0+IS_HSCXB_HACK(base)); + outsb(IOADDR(base), (u_char *)buf, (u_int)len); +} +#else +static void dynalink_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, 0); + bus_space_write_multi_1(t, h, ISAC, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA); + bus_space_write_multi_1(t, h, HSCX, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB); + bus_space_write_multi_1(t, h, HSCX, (u_int8_t*)buf, size); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static void +dynalink_write_reg(u_char *base, u_int offset, u_int v) +{ + outb(IOBASE(base)+ADDR, (offset+IS_HSCXB_HACK(base))&ADDRMASK); + outb(IOADDR(base), (u_char)v); +} +#else +static void dynalink_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, offs); + bus_space_write_1(t, h, ISAC, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA+offs); + bus_space_write_1(t, h, HSCX, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB+offs); + bus_space_write_1(t, h, HSCX, data); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static u_char +dynalink_read_reg(u_char *base, u_int offset) +{ + outb(IOBASE(base)+ADDR, (offset+IS_HSCXB_HACK(base))&ADDRMASK); + return (inb(IOADDR(base))); +} +#else +static u_int8_t dynalink_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR, offs); + return bus_space_read_1(t, h, ISAC); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR, HSCXA+offs); + return bus_space_read_1(t, h, HSCX); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR, HSCXB+offs); + return bus_space_read_1(t, h, HSCX); + } + return 0; +} +#endif + +#endif /* (NISIC > 0) && (NPNP > 0) && defined(DYNALINK) */ diff --git a/sys/i4b/layer1/i4b_elsa_isdnmc.c b/sys/i4b/layer1/i4b_elsa_isdnmc.c new file mode 100644 index 000000000000..c6987f55adb2 --- /dev/null +++ b/sys/i4b/layer1/i4b_elsa_isdnmc.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * ELSA MicroLink ISDN/MC card specific routines + * --------------------------------------------- + * + * $Id: i4b_elsa_isdnmc.c,v 1.2 1998/12/05 18:04:33 hm Exp $ + * + * last edit-date: [Tue Dec 1 07:45:53 1998] + * + * -mh added support for elsa ISDN/mc + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif + +#if NISIC > 0 && defined(ELSA_ISDNMC) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/layer1/pcmcia_isic.h> + +#ifndef __FreeBSD__ +/* PCMCIA support routines */ +static u_int8_t elsa_isdnmc_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void elsa_isdnmc_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void elsa_isdnmc_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void elsa_isdnmc_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +#endif + +/* + * The ELSA MicroLink ISDN/MC uses one contigous IO region, + * mapped by the pcmcia code. + * The chip access is via three ports: + */ +#define ISAC_DATA 1 /* ISAC dataport at offset 1 */ +#define HSCX_DATA 2 /* HSCX dataport at offset 2 */ +#define ADDR_LATCH 4 /* address latch at offset 4 */ + +/* This is very similar to the ELSA QuickStep 1000 (ISA) card */ + +/*---------------------------------------------------------------------------* + * read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_isdnmc_read_fifo(void *buf, const void *base, size_t len) +{ +} +#else +static void +elsa_isdnmc_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_read_multi_1(t, h, ISAC_DATA, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_read_multi_1(t, h, HSCX_DATA, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40); + bus_space_read_multi_1(t, h, HSCX_DATA, buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_isdnmc_write_fifo(void *base, const void *buf, size_t len) +{ +} +#else +static void +elsa_isdnmc_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_write_multi_1(t, h, ISAC_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, 0); + bus_space_write_multi_1(t, h, HSCX_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40); + bus_space_write_multi_1(t, h, HSCX_DATA, (u_int8_t*)buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_isdnmc_write_reg(u_char *base, u_int offset, u_int v) +{ +} +#else +static void +elsa_isdnmc_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, offs); + bus_space_write_1(t, h, ISAC_DATA, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, offs); + bus_space_write_1(t, h, HSCX_DATA, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40+offs); + bus_space_write_1(t, h, HSCX_DATA, data); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +elsa_isdnmc_read_reg(u_char *base, u_int offset) +{ + return 0; +} +#else +static u_int8_t +elsa_isdnmc_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ADDR_LATCH, offs); + return bus_space_read_1(t, h, ISAC_DATA); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ADDR_LATCH, offs); + return bus_space_read_1(t, h, HSCX_DATA); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ADDR_LATCH, 0x40+offs); + return bus_space_read_1(t, h, HSCX_DATA); + } + return 0; +} +#endif + +#ifdef __FreeBSD__ +#else + +/* + * XXX - one time only! Some of this has to go into an enable + * function, with apropriate counterpart in disable, so a card + * could be removed an inserted again. But never mind for now, + * this won't work anyway for several reasons (both in NetBSD + * and in I4B). + */ +int +isic_attach_elsaisdnmc(struct pcmcia_isic_softc *psc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa) +{ + struct isic_softc *sc = &psc->sc_isic; + bus_space_tag_t t; + bus_space_handle_t h; + + /* Validate config info */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of memory spaces %d should be 1\n", + cfe->num_iospace); + + /* Allocate pcmcia space */ + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + + /* map them */ + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, + cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return 0; + } + + /* OK, this will work! */ + sc->sc_cardtyp = CARD_TYPEP_ELSAMLIMC; + + /* Setup bus space maps */ + sc->sc_num_mappings = 1; + MALLOC_MAPS(sc); + + /* Copy our handles/tags to the MI maps */ + sc->sc_maps[0].t = psc->sc_pcioh.iot; + sc->sc_maps[0].h = psc->sc_pcioh.ioh; + sc->sc_maps[0].offset = 0; + sc->sc_maps[0].size = 0; /* not our mapping */ + + t = sc->sc_maps[0].t; + h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = elsa_isdnmc_read_reg; + sc->writereg = elsa_isdnmc_write_reg; + + sc->readfifo = elsa_isdnmc_read_fifo; + sc->writefifo = elsa_isdnmc_write_fifo; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + return 1; +} +#endif + +#endif /* ISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_elsa_mcall.c b/sys/i4b/layer1/i4b_elsa_mcall.c new file mode 100644 index 000000000000..36882e912809 --- /dev/null +++ b/sys/i4b/layer1/i4b_elsa_mcall.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * ELSA MicroLink MC/all card specific routines + * -------------------------------------------- + * + * $Id: i4b_elsa_mcall.c,v 1.1 1998/12/02 06:44:27 hm Exp $ + * + * last edit-date: [Tue Dec 1 07:45:53 1998] + * + * -mh started support for ELSA MC/all + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif + +#if NISIC > 0 && defined(ELSA_MCALL) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> +#include <i4b/layer1/i4b_ipac.h> + +#include <i4b/layer1/pcmcia_isic.h> + +#ifndef __FreeBSD__ +/* PCMCIA support routines */ +static u_int8_t elsa_mcall_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void elsa_mcall_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void elsa_mcall_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void elsa_mcall_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * read fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static int PCMCIA_IO_BASE = 0; /* ap: XXX hack */ +static void +elsa_mcall_read_fifo(void *buf, const void *base, size_t len) +{ +} +#else +static void +elsa_mcall_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ +} +#endif + +/*---------------------------------------------------------------------------* + * write fifo routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_mcall_write_fifo(void *base, const void *buf, size_t len) +{ +} +#else +static void +elsa_mcall_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ +} +#endif + +/*---------------------------------------------------------------------------* + * write register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +elsa_mcall_write_reg(u_char *base, u_int offset, u_int v) +{ +} +#else +static void +elsa_mcall_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ +} +#endif + +/*---------------------------------------------------------------------------* + * read register routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static u_char +elsa_mcall_read_reg(u_char *base, u_int offset) +{ + return 0; +} +#else +static u_int8_t +elsa_mcall_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + /* + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + */ + return 0; +} +#endif + +#ifdef __FreeBSD__ +#else + +/* + * XXX - one time only! Some of this has to go into an enable + * function, with apropriate counterpart in disable, so a card + * could be removed an inserted again. But never mind for now, + * this won't work anyway for several reasons (both in NetBSD + * and in I4B). + */ +int +isic_attach_elsamcall(struct pcmcia_isic_softc *psc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa) +{ + struct isic_softc *sc = &psc->sc_isic; + bus_space_tag_t t; + bus_space_handle_t h; + + /* Validate config info */ + if (cfe->num_memspace != 0) + printf(": unexpected number of memory spaces %d should be 0\n", + cfe->num_memspace); + if (cfe->num_iospace != 1) + printf(": unexpected number of memory spaces %d should be 1\n", + cfe->num_iospace); + + /* Allocate pcmcia space */ + if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length, + cfe->iospace[0].length, &psc->sc_pcioh)) + printf(": can't allocate i/o space\n"); + + /* map them */ + if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ? + PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, + cfe->iospace[0].length, &psc->sc_pcioh, &psc->sc_io_window)) { + printf(": can't map i/o space\n"); + return 0; + } + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_ELSAMLMCALL; + + /* Setup bus space maps */ + sc->sc_num_mappings = 1; + MALLOC_MAPS(sc); + + /* Copy our handles/tags to the MI maps */ + sc->sc_maps[0].t = psc->sc_pcioh.iot; + sc->sc_maps[0].h = psc->sc_pcioh.ioh; + sc->sc_maps[0].offset = 0; + sc->sc_maps[0].size = 0; /* not our mapping */ + + t = sc->sc_maps[0].t; + h = sc->sc_maps[0].h; + + sc->clearirq = NULL; + sc->readreg = elsa_mcall_read_reg; + sc->writereg = elsa_mcall_write_reg; + + sc->readfifo = elsa_mcall_read_fifo; + sc->writefifo = elsa_mcall_write_fifo; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + return 1; +} +#endif + +#endif /* NISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_elsa_qs1i.c b/sys/i4b/layer1/i4b_elsa_qs1i.c new file mode 100644 index 000000000000..a3c8ddc27afe --- /dev/null +++ b/sys/i4b/layer1/i4b_elsa_qs1i.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for ELSA Quickstep 1000pro ISA + * ===================================================================== + * + * $Id: i4b_elsa_qs1i.c,v 1.12 1998/12/16 09:32:50 hm Exp $ + * + * last edit-date: [Mon Dec 14 17:27:08 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +#include "isic.h" +#include "opt_i4b.h" +#include "pnp.h" + +#else + +#define NISIC 1 +#define NPNP 1 + +#endif + +#if (NISIC > 0) && (NPNP > 0) && defined(ELSA_QS1ISA) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <i386/isa/pnp.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#ifdef __FreeBSD__ +static void i4b_eq1i_clrirq(void* base); +#else +static void i4b_eq1i_clrirq(struct isic_softc *sc); +void isic_attach_Eqs1pi __P((struct isic_softc *sc)); +#endif + +/* masks for register encoded in base addr */ + +#define ELSA_BASE_MASK 0x0ffff +#define ELSA_OFF_MASK 0xf0000 + +/* register id's to be encoded in base addr */ + +#define ELSA_IDISAC 0x00000 +#define ELSA_IDHSCXA 0x10000 +#define ELSA_IDHSCXB 0x20000 + +/* offsets from base address */ + +#define ELSA_OFF_ISAC 0x00 +#define ELSA_OFF_HSCX 0x02 +#define ELSA_OFF_OFF 0x03 +#define ELSA_OFF_CTRL 0x04 +#define ELSA_OFF_CFG 0x05 +#define ELSA_OFF_TIMR 0x06 +#define ELSA_OFF_IRQ 0x07 + +/* control register (write access) */ + +#define ELSA_CTRL_LED_YELLOW 0x02 +#define ELSA_CTRL_LED_GREEN 0x08 +#define ELSA_CTRL_RESET 0x20 +#define ELSA_CTRL_TIMEREN 0x80 +#define ELSA_CTRL_SECRET 0x50 + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA clear IRQ routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +static void +i4b_eq1i_clrirq(void* base) +{ + outb((u_int)base + ELSA_OFF_IRQ, 0); +} + +#else +static void +i4b_eq1i_clrirq(struct isic_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, ELSA_OFF_IRQ, 0); +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pi_read_fifo(void *buf, const void *base, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0x40); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pi_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_read_multi_1(t, h, ELSA_OFF_ISAC, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_read_multi_1(t, h, ELSA_OFF_HSCX, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40); + bus_space_read_multi_1(t, h, ELSA_OFF_HSCX, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pi_write_fifo(void *base, const void *buf, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0x40); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, 0); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pi_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_write_multi_1(t, h, ELSA_OFF_ISAC, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0); + bus_space_write_multi_1(t, h, ELSA_OFF_HSCX, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40); + bus_space_write_multi_1(t, h, ELSA_OFF_HSCX, (u_int8_t*)buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pi_write_reg(u_char *base, u_int offset, u_int v) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)(offset+0x40)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX, (u_char)v); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX, (u_char)v); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC, (u_char)v); + } +} + +#else + +static void +eqs1pi_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + bus_space_write_1(t, h, ELSA_OFF_ISAC, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + bus_space_write_1(t, h, ELSA_OFF_HSCX, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40+offs); + bus_space_write_1(t, h, ELSA_OFF_HSCX, data); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/ISA ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +eqs1pi_read_reg(u_char *base, u_int offset) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)(offset+0x40)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX)); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_HSCX)); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_OFF, (u_char)offset); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ISAC)); + } +} + +#else + +static u_int8_t +eqs1pi_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + return bus_space_read_1(t, h, ELSA_OFF_ISAC); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_OFF, offs); + return bus_space_read_1(t, h, ELSA_OFF_HSCX); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_OFF, 0x40+offs); + return bus_space_read_1(t, h, ELSA_OFF_HSCX); + } + return 0; +} + +#endif + +#ifdef __FreeBSD__ + +/*---------------------------------------------------------------------------* + * isic_probe_Eqs1pi - probe for ELSA QuickStep 1000pro/ISA and compatibles + *---------------------------------------------------------------------------*/ +int +isic_probe_Eqs1pi(struct isa_device *dev, unsigned int iobase2) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 4: + case 5: + case 7: + case 10: + case 11: + case 12: + case 15: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + if(!((dev->id_iobase >= 0x160) && (dev->id_iobase <= 0x360))) + { + printf("isic%d: Error, invalid iobase 0x%x specified for ELSA QuickStep 1000pro/ISA!\n", + dev->id_unit, dev->id_iobase); + return(0); + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + +/* XXX no "sc_clearirq" in sight... /phk + sc->sc_clearirq = i4b_eq1i_clrirq; +*/ + sc->readreg = eqs1pi_read_reg; + sc->writereg = eqs1pi_write_reg; + + sc->readfifo = eqs1pi_read_fifo; + sc->writefifo = eqs1pi_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1ISA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) ((u_int)dev->id_iobase | ELSA_IDISAC); + HSCX_A_BASE = (caddr_t) ((u_int)dev->id_iobase | ELSA_IDHSCXA); + HSCX_B_BASE = (caddr_t) ((u_int)dev->id_iobase | ELSA_IDHSCXB); + + /* + * Read HSCX A/B VSTR. Expected value for the ELSA QuickStep 1000pro + * ISA card is 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for ELSA QuickStep 1000pro/ISA\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_s0163P - attach ELSA QuickStep 1000pro/ISA + *---------------------------------------------------------------------------*/ +int +isic_attach_Eqs1pi(struct isa_device *dev, unsigned int iobase2) +{ + u_char byte = ELSA_CTRL_SECRET; + + byte &= ~ELSA_CTRL_RESET; + outb(dev->id_iobase + ELSA_OFF_CTRL, byte); + DELAY(20); + byte |= ELSA_CTRL_RESET; + outb(dev->id_iobase + ELSA_OFF_CTRL, byte); + + DELAY(20); + outb(dev->id_iobase + ELSA_OFF_IRQ, 0xff); + + return(1); +} + +#else /* !__FreeBSD__ */ + +void +isic_attach_Eqs1pi(struct isic_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + u_char byte = ELSA_CTRL_SECRET; + + byte &= ~ELSA_CTRL_RESET; + bus_space_write_1(t, h, ELSA_OFF_CTRL, byte); + DELAY(20); + byte |= ELSA_CTRL_RESET; + bus_space_write_1(t, h, ELSA_OFF_CTRL, byte); + + DELAY(20); + bus_space_write_1(t, h, ELSA_OFF_IRQ, 0xff); + + /* setup access routines */ + + sc->clearirq = i4b_eq1i_clrirq; + sc->readreg = eqs1pi_read_reg; + sc->writereg = eqs1pi_write_reg; + + sc->readfifo = eqs1pi_read_fifo; + sc->writefifo = eqs1pi_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1ISA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} + +#endif + +#endif /* (NISIC > 0) && (NPNP > 0) && defined(ELSA_QS1ISA) */ diff --git a/sys/i4b/layer1/i4b_elsa_qs1p.c b/sys/i4b/layer1/i4b_elsa_qs1p.c new file mode 100644 index 000000000000..b2b35d03fc34 --- /dev/null +++ b/sys/i4b/layer1/i4b_elsa_qs1p.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for ELSA Quickstep 1000pro PCI + * ===================================================================== + * + * $Id: i4b_elsa_qs1p.c,v 1.4 1998/12/05 18:04:36 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:22:41 1998] + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#include "pci.h" +#else +#define NISIC 1 +#endif + +#if (NISIC > 0) && /* (NPCI > 0) && */ defined(ELSA_QS1PCI) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> +#include <i4b/layer1/i4b_ipac.h> + +#ifndef __FreeBSD__ +/* we don't have the function prototypes in the global i4b_l1.h any more */ +void isic_attach_Eqs1pp __P((struct isic_softc *sc, struct pci_attach_args *pa)); +#endif + +/* masks for register encoded in base addr */ + +#define ELSA_BASE_MASK 0x0ffff +#define ELSA_OFF_MASK 0xf0000 + +/* register id's to be encoded in base addr */ + +#define ELSA_IDISAC 0x00000 +#define ELSA_IDHSCXA 0x10000 +#define ELSA_IDHSCXB 0x20000 +#define ELSA_IDIPAC 0x40000 + +/* offsets from base address */ + +#define ELSA_OFF_ALE 0x00 +#define ELSA_OFF_RW 0x01 + +#define ELSA_PORT0_MAPOFF PCI_MAPREG_START+4 +#define ELSA_PORT1_MAPOFF PCI_MAPREG_START+12 + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC get fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pp_read_fifo(void *buf, const void *base, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXB_OFF); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXA_OFF); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_ISAC_OFF); + insb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pp_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF); + bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF); + bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF); + bus_space_read_multi_1(t, h, ELSA_OFF_RW, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC put fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pp_write_fifo(void *base, const void *buf, size_t len) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXB_OFF); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_HSCXA_OFF); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } + else /* if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, IPAC_ISAC_OFF); + outsb((((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW), (u_char *)buf, (u_int)len); + } +} + +#else + +static void +eqs1pp_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF); + bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF); + bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF); + bus_space_write_multi_1(t, h, ELSA_OFF_RW, (u_int8_t*)buf, size); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +eqs1pp_write_reg(u_char *base, u_int offset, u_int v) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } + else /* IPAC */ + { + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF)); + outb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW, (u_char)v); + } +} + +#else + +static void +eqs1pp_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + case ISIC_WHAT_IPAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs); + bus_space_write_1(t, h, ELSA_OFF_RW, data); + break; + } +} +#endif + +/*---------------------------------------------------------------------------* + * ELSA QuickStep 1000pro/PCI ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +eqs1pp_read_reg(u_char *base, u_int offset) +{ + if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXB) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDHSCXA) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } + else if(((u_int)base & ELSA_OFF_MASK) == ELSA_IDISAC) + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } + else /* IPAC */ + { + outb((u_int)((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF)); + return(inb(((u_int)base & ELSA_BASE_MASK) + ELSA_OFF_RW)); + } +} + +#else + +static u_int8_t +eqs1pp_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_ISAC_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXA_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_HSCXB_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + case ISIC_WHAT_IPAC: + { + bus_space_write_1(t, h, ELSA_OFF_ALE, IPAC_IPAC_OFF+offs); + return bus_space_read_1(t, h, ELSA_OFF_RW); + } + } + + return 0; +} + +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_Eqs1pp - attach for ELSA QuickStep 1000pro/PCI + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_Eqs1pp(int unit, unsigned int iobase1, unsigned int iobase2) +{ + struct isic_softc *sc = &isic_sc[unit]; + + /* check max unit range */ + + if(unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA QuickStep 1000pro/PCI!\n", + unit, unit); + return(0); + } + sc->sc_unit = unit; + + /* setup iobase */ + + if((iobase2 <= 0) || (iobase2 > 0xffff)) + { + printf("isic%d: Error, invalid iobase 0x%x specified for ELSA QuickStep 1000pro/PCI!\n", + unit, iobase2); + return(0); + } + sc->sc_port = iobase2; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = eqs1pp_read_reg; + sc->writereg = eqs1pp_write_reg; + + sc->readfifo = eqs1pp_read_fifo; + sc->writefifo = eqs1pp_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* setup chip type = IPAC ! */ + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDISAC); + HSCX_A_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDHSCXA); + HSCX_B_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDHSCXB); + IPAC_BASE = (caddr_t) ((u_int)iobase2 | ELSA_IDIPAC); + + /* enable hscx/isac irq's */ + IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); + + IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */ + IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */ + (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2)); + IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */ + + outb(iobase1 + 0x4c, 0x41); /* enable card interrupt */ + + return (1); +} + +#else /* !FreeBSD */ + +void +isic_attach_Eqs1pp(sc, pa) + struct isic_softc *sc; + struct pci_attach_args *pa; +{ + /* setup io mappings */ + sc->sc_num_mappings = 2; + MALLOC_MAPS(sc); + sc->sc_maps[0].size = 0; + if (pci_mapreg_map(pa, ELSA_PORT0_MAPOFF, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_maps[0].t, &sc->sc_maps[0].h, NULL, NULL)) { + printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); + return; + } + sc->sc_maps[1].size = 0; + if (pci_mapreg_map(pa, ELSA_PORT1_MAPOFF, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_maps[1].t, &sc->sc_maps[1].h, NULL, NULL)) { + printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); + return; + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = eqs1pp_read_reg; + sc->writereg = eqs1pp_write_reg; + + sc->readfifo = eqs1pp_read_fifo; + sc->writefifo = eqs1pp_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_ELSAQS1PCI; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + /* setup chip type = IPAC ! */ + + sc->sc_ipac = 1; + sc->sc_bfifolen = IPAC_BFIFO_LEN; + + /* enable hscx/isac irq's */ + IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); + + IPAC_WRITE(IPAC_ACFG, 0); /* outputs are open drain */ + IPAC_WRITE(IPAC_AOE, /* aux 5..2 are inputs, 7, 6 outputs */ + (IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2)); + IPAC_WRITE(IPAC_ATX, 0xff); /* set all output lines high */ + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 0x4c, 0x41); /* enable card interrupt */ +} + +#endif + +#endif /* (NISIC > 0) && defined(ELSA_QS1PCI) */ diff --git a/sys/i4b/layer1/i4b_hscx.c b/sys/i4b/layer1/i4b_hscx.c new file mode 100644 index 000000000000..ed80a51c5731 --- /dev/null +++ b/sys/i4b/layer1/i4b_hscx.c @@ -0,0 +1,672 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b - Siemens HSCX chip (B-channel) handling + * -------------------------------------------- + * + * $Id: i4b_hscx.c,v 1.37 1998/12/05 18:04:38 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:23:36 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#else +#define NISIC 1 /* doesn't matter in non-FreeBSD, config(8) d.t.r.t. */ +#endif +#if NISIC > 0 + +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_mbuf.h> + +/*---------------------------------------------------------------------------* + * HSCX IRQ Handler + *---------------------------------------------------------------------------*/ +void +isic_hscx_irq(register struct isic_softc *sc, u_char ista, int h_chan, u_char ex_irq) +{ + register isic_Bchan_t *chan = &sc->sc_chan[h_chan]; + u_char exir = 0; + int activity = -1; + u_char cmd = 0; + + DBGL1(L1_H_IRQ, "isic_hscx_irq", ("%#x\n", ista)); + + if(ex_irq) + { + /* get channel extended irq reg */ + + exir = HSCX_READ(h_chan, H_EXIR); + + if(exir & HSCX_EXIR_RFO) + { + chan->stat_RFO++; + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("ex_irq: receive data overflow\n")); + } + + if((exir & HSCX_EXIR_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */ + { + chan->stat_XDU++; + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("ex_irq: xmit data underrun\n")); + isic_hscx_cmd(sc, h_chan, HSCX_CMDR_XRES); + + if (chan->out_mbuf_head != NULL) /* don't continue to transmit this buffer */ + { + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_cur = chan->out_mbuf_head = NULL; + } + } + + } + + /* rx message end, end of frame */ + + if(ista & HSCX_ISTA_RME) + { + register int fifo_data_len; + u_char rsta; + int error = 0; + + rsta = HSCX_READ(h_chan, H_RSTA); + + if((rsta & 0xf0) != 0xa0) + { + if((rsta & HSCX_RSTA_VFR) == 0) + { + chan->stat_VFR++; + cmd |= (HSCX_CMDR_RHR); + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("received invalid Frame\n")); + error++; + } + + if(rsta & HSCX_RSTA_RDO) + { + chan->stat_RDO++; + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("receive data overflow\n")); + error++; + } + + if((rsta & HSCX_RSTA_CRC) == 0) + { + chan->stat_CRC++; + cmd |= (HSCX_CMDR_RHR); + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("CRC check failed\n")); + error++; + } + + if(rsta & HSCX_RSTA_RAB) + { + chan->stat_RAB++; + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("Receive message aborted\n")); + error++; + } + } + + fifo_data_len = ((HSCX_READ(h_chan, H_RBCL)) & + ((sc->sc_bfifolen)-1)); + + if(fifo_data_len == 0) + fifo_data_len = sc->sc_bfifolen; + + /* all error conditions checked, now decide and take action */ + + if(error == 0) + { + if(chan->in_mbuf == NULL) + { + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 isic_hscx_irq: RME, cannot allocate mbuf!\n"); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + } + + fifo_data_len -= 1; /* last byte in fifo is RSTA ! */ + + if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN) + { + /* read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, chan->in_cbptr, fifo_data_len); + + cmd |= (HSCX_CMDR_RMC); + isic_hscx_cmd(sc, h_chan, cmd); + cmd = 0; + + chan->in_len += fifo_data_len; + chan->rxcount += fifo_data_len; + + /* setup mbuf data length */ + + chan->in_mbuf->m_len = chan->in_len; + chan->in_mbuf->m_pkthdr.len = chan->in_len; + + if(sc->sc_trace & TRACE_B_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); + } + + (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit); + + activity = ACT_RX; + + /* mark buffer ptr as unused */ + + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + else + { + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d\n", chan->in_len, fifo_data_len)); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + cmd |= (HSCX_CMDR_RHR | HSCX_CMDR_RMC); + } + } + else + { + if (chan->in_mbuf != NULL) + { + i4b_Bfreembuf(chan->in_mbuf); + chan->in_mbuf = NULL; + chan->in_cbptr = NULL; + chan->in_len = 0; + } + cmd |= (HSCX_CMDR_RMC); + } + } + + /* rx fifo full */ + + if(ista & HSCX_ISTA_RPF) + { + if(chan->in_mbuf == NULL) + { + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 isic_hscx_irq: RPF, cannot allocate mbuf!\n"); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + } + + chan->rxcount += sc->sc_bfifolen; + + if((chan->in_len + sc->sc_bfifolen) <= BCH_MAX_DATALEN) + { + /* read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, chan->in_cbptr, sc->sc_bfifolen); + + chan->in_cbptr += sc->sc_bfifolen; + chan->in_len += sc->sc_bfifolen; + } + else + { + if(chan->bprot == BPROT_NONE) + { + /* setup mbuf data length */ + + chan->in_mbuf->m_len = chan->in_len; + chan->in_mbuf->m_pkthdr.len = chan->in_len; + + if(sc->sc_trace & TRACE_B_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); + } + + /* move rx'd data to rx queue */ + + IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf); + + (*chan->drvr_linktab->bch_rx_data_ready)(chan->drvr_linktab->unit); + + if(!(isic_hscx_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len))) + activity = ACT_RX; + + /* alloc new buffer */ + + if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) + panic("L1 isic_hscx_irq: RPF, cannot allocate new mbuf!\n"); + + /* setup new data ptr */ + + chan->in_cbptr = chan->in_mbuf->m_data; + + /* read data from HSCX fifo */ + + HSCX_RDFIFO(h_chan, chan->in_cbptr, sc->sc_bfifolen); + + chan->in_cbptr += sc->sc_bfifolen; + chan->in_len = sc->sc_bfifolen; + + chan->rxcount += sc->sc_bfifolen; + } + else + { + DBGL1(L1_H_XFRERR, "isic_hscx_irq", ("RAWHDLC rx buffer overflow in RPF, in_len=%d\n", chan->in_len)); + chan->in_cbptr = chan->in_mbuf->m_data; + chan->in_len = 0; + cmd |= (HSCX_CMDR_RHR); + } + } + + /* command to release fifo space */ + + cmd |= HSCX_CMDR_RMC; + } + + /* transmit fifo empty, new data can be written to fifo */ + + if(ista & HSCX_ISTA_XPR) + { + /* + * for a description what is going on here, please have + * a look at isic_bchannel_start() in i4b_bchan.c ! + */ + + int activity = -1; + int len; + int nextlen; + + DBGL1(L1_H_IRQ, "isic_hscx_irq", ("unit %d, chan %d - XPR, Tx Fifo Empty!\n", sc->sc_unit, h_chan)); + + if(chan->out_mbuf_cur == NULL) /* last frame is transmitted */ + { + IF_DEQUEUE(&chan->tx_queue, chan->out_mbuf_head); + + if(chan->out_mbuf_head == NULL) + { + chan->state &= ~HSCX_TX_ACTIVE; + (*chan->drvr_linktab->bch_tx_queue_empty)(chan->drvr_linktab->unit); + } + else + { + chan->state |= HSCX_TX_ACTIVE; + chan->out_mbuf_cur = chan->out_mbuf_head; + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + + if(chan->bprot == BPROT_NONE) + { + if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) + activity = ACT_TX; + } + else + { + activity = ACT_TX; + } + } + } + + len = 0; + + while(chan->out_mbuf_cur && len != sc->sc_bfifolen) + { + nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len); + +#ifdef NOTDEF + printf("i:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ", + chan->out_mbuf_head, + chan->out_mbuf_cur, + chan->out_mbuf_cur_ptr, + chan->out_mbuf_cur_len, + len, + next_len); +#endif + + isic_hscx_waitxfw(sc, h_chan); /* necessary !!! */ + + HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, nextlen); + cmd |= HSCX_CMDR_XTF; + + len += nextlen; + chan->txcount += nextlen; + + chan->out_mbuf_cur_ptr += nextlen; + chan->out_mbuf_cur_len -= nextlen; + + if(chan->out_mbuf_cur_len == 0) + { + if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL) + { + chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data; + chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len; + + if(sc->sc_trace & TRACE_B_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_bcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); + } + } + else + { + if (chan->bprot != BPROT_NONE) + cmd |= HSCX_CMDR_XME; + i4b_Bfreembuf(chan->out_mbuf_head); + chan->out_mbuf_head = NULL; + } + + } + } + } + + if(cmd) /* is there a command for the HSCX ? */ + { + isic_hscx_cmd(sc, h_chan, cmd); /* yes, to HSCX */ + } + + /* call timeout handling routine */ + + if(activity == ACT_RX || activity == ACT_TX) + (*chan->drvr_linktab->bch_activity)(chan->drvr_linktab->unit, activity); +} + +/*---------------------------------------------------------------------------* + * HSCX initialization + * + * for telephony: extended transparent mode 1 + * for raw hdlc: transparent mode 0 + *---------------------------------------------------------------------------*/ +void +isic_hscx_init(struct isic_softc *sc, int h_chan, int activate) +{ + isic_Bchan_t *chan = &sc->sc_chan[h_chan]; + + HSCX_WRITE(h_chan, H_MASK, 0xff); /* mask irq's */ + + if(sc->sc_ipac) + { + /* CCR1: Power Up, Clock Mode 5 */ + HSCX_WRITE(h_chan, H_CCR1, HSCX_CCR1_PU | /* power up */ + HSCX_CCR1_CM1); /* IPAC clock mode 5 */ + } + else + { + /* CCR1: Power Up, Clock Mode 5 */ + HSCX_WRITE(h_chan, H_CCR1, HSCX_CCR1_PU | /* power up */ + HSCX_CCR1_CM2 | /* HSCX clock mode 5 */ + HSCX_CCR1_CM0); + } + + /* XAD1: Transmit Address Byte 1 */ + HSCX_WRITE(h_chan, H_XAD1, 0xff); + + /* XAD2: Transmit Address Byte 2 */ + HSCX_WRITE(h_chan, H_XAD2, 0xff); + + /* RAH2: Receive Address Byte High Reg. 2 */ + HSCX_WRITE(h_chan, H_RAH2, 0xff); + + /* XBCH: reset Transmit Byte Count High */ + HSCX_WRITE(h_chan, H_XBCH, 0x00); + + /* RLCR: reset Receive Length Check Register */ + HSCX_WRITE(h_chan, H_RLCR, 0x00); + + /* CCR2: set tx/rx clock shift bit 0 */ + /* disable CTS irq, disable RIE irq*/ + HSCX_WRITE(h_chan, H_CCR2, HSCX_CCR2_XCS0|HSCX_CCR2_RCS0); + + /* XCCR: tx bit count per time slot */ + HSCX_WRITE(h_chan, H_XCCR, 0x07); + + /* RCCR: rx bit count per time slot */ + HSCX_WRITE(h_chan, H_RCCR, 0x07); + + if(sc->sc_bustyp == BUS_TYPE_IOM2) + { + switch(h_chan) + { + case HSCX_CH_A: /* Prepare HSCX channel A */ + /* TSAX: tx clock shift bits 1 & 2 */ + /* tx time slot number */ + HSCX_WRITE(h_chan, H_TSAX, 0x2f); + + /* TSAR: rx clock shift bits 1 & 2 */ + /* rx time slot number */ + HSCX_WRITE(h_chan, H_TSAR, 0x2f); + break; + + case HSCX_CH_B: /* Prepare HSCX channel B */ + /* TSAX: tx clock shift bits 1 & 2 */ + /* tx time slot number */ + HSCX_WRITE(h_chan, H_TSAX, 0x03); + + /* TSAR: rx clock shift bits 1 & 2 */ + /* rx time slot number */ + HSCX_WRITE(h_chan, H_TSAR, 0x03); + break; + } + } + else /* IOM 1 setup */ + { + /* TSAX: tx clock shift bits 1 & 2 */ + /* tx time slot number */ + HSCX_WRITE(h_chan, H_TSAX, 0x07); + + /* TSAR: rx clock shift bits 1 & 2 */ + /* rx time slot number */ + HSCX_WRITE(h_chan, H_TSAR, 0x07); + } + + if(activate) + { + if(chan->bprot == BPROT_RHDLC) + { + /* HDLC Frames, transparent mode 0 */ + HSCX_WRITE(h_chan, H_MODE, + HSCX_MODE_MDS1|HSCX_MODE_RAC|HSCX_MODE_RTS); + } + else + { + /* Raw Telephony, extended transparent mode 1 */ + HSCX_WRITE(h_chan, H_MODE, + HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS); + } + + isic_hscx_cmd(sc, h_chan, HSCX_CMDR_RHR|HSCX_CMDR_XRES); + } + else + { + /* TSAX: tx time slot */ + HSCX_WRITE(h_chan, H_TSAX, 0xff); + + /* TSAR: rx time slot */ + HSCX_WRITE(h_chan, H_TSAR, 0xff); + + /* Raw Telephony, extended transparent mode 1 */ + HSCX_WRITE(h_chan, H_MODE, + HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS); + } + + /* don't touch ICA, EXA and EXB bits, this could be HSCX_CH_B */ + /* always disable RSC and TIN */ + + chan->hscx_mask |= HSCX_MASK_RSC | HSCX_MASK_TIN; + + if(activate) + { + /* enable */ + chan->hscx_mask &= ~(HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR); + } + else + { + /* disable */ + chan->hscx_mask |= HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR; + } + + /* handle ICA, EXA, and EXB via interrupt mask of channel b */ + + if (h_chan == HSCX_CH_A) + { + if (activate) + HSCX_B_IMASK &= ~(HSCX_MASK_EXA | HSCX_MASK_ICA); + else + HSCX_B_IMASK |= HSCX_MASK_EXA | HSCX_MASK_ICA; + HSCX_WRITE(HSCX_CH_A, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); + } + else + { + if (activate) + HSCX_B_IMASK &= ~HSCX_MASK_EXB; + else + HSCX_B_IMASK |= HSCX_MASK_EXB; + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); + } + + /* clear spurious interrupts left over */ + + if(h_chan == HSCX_CH_A) + { + HSCX_READ(h_chan, H_EXIR); + HSCX_READ(h_chan, H_ISTA); + } + else /* mask ICA, because it must not be cleared by reading ISTA */ + { + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK | HSCX_MASK_ICA); + HSCX_READ(h_chan, H_EXIR); + HSCX_READ(h_chan, H_ISTA); + HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); + } +} + +/*---------------------------------------------------------------------------* + * write command to HSCX command register + *---------------------------------------------------------------------------*/ +void +isic_hscx_cmd(struct isic_softc *sc, int h_chan, unsigned char cmd) +{ + int timeout = 20; + + while(((HSCX_READ(h_chan, H_STAR)) & HSCX_STAR_CEC) && timeout) + { + DELAY(10); + timeout--; + } + + if(timeout == 0) + { + DBGL1(L1_H_ERR, "isic_hscx_cmd", ("HSCX wait for CEC timeout!\n")); + } + + HSCX_WRITE(h_chan, H_CMDR, cmd); +} + +/*---------------------------------------------------------------------------* + * wait for HSCX transmit FIFO write enable + *---------------------------------------------------------------------------*/ +void +isic_hscx_waitxfw(struct isic_softc *sc, int h_chan) +{ +#define WAITVAL 50 +#define WAITTO 200 + + int timeout = WAITTO; + + while((!(((HSCX_READ(h_chan, H_STAR)) & + (HSCX_STAR_CEC | HSCX_STAR_XFW)) == HSCX_STAR_XFW)) && timeout) + { + DELAY(WAITVAL); + timeout--; + } + + if(timeout == 0) + { + DBGL1(L1_H_ERR, "isic_hscx_waitxfw", ("HSCX wait for XFW timeout!\n")); + } + else if (timeout != WAITTO) + { + DBGL1(L1_H_XFRERR, "isic_hscx_waitxfw", ("HSCX wait for XFW time: %d uS\n", (WAITTO-timeout)*50)); + } +} + +#endif /* NISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_hscx.h b/sys/i4b/layer1/i4b_hscx.h new file mode 100644 index 000000000000..1b1640de2282 --- /dev/null +++ b/sys/i4b/layer1/i4b_hscx.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 1996, 1998 Gary Jennejohn. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * $Id: i4b_hscx.h,v 1.3 1998/02/13 17:00:31 hm Exp $ + * + * last edit-date: [Thu Feb 5 13:38:50 1998] + * + * -hm added AVM config register defs + * -hm split up for rewrite of Siemens chipset driver + * + *--------------------------------------------------------------------------- + */ + +#ifndef I4B_HSCX_H_ +#define I4B_HSCX_H_ + +enum HSCX_VERSIONS { + HSCX_VA1, /* 82525 A1 */ + HSCX_UNKN1, /* unknown 1 */ + HSCX_VA2, /* 82525 A2 */ + HSCX_UNKN3, /* unknown 3 */ + HSCX_VA3, /* 82525 A3 */ + HSCX_V21, /* 82525 2.1 */ + HSCX_UNKN /* unknown version */ +}; + +#define HSCX_CH_A 0 /* channel A */ +#define HSCX_CH_B 1 /* channel B */ + +#define HSCX_FIFO_LEN 32 /* 32 bytes FIFO on chip */ + +/* + * definitions of registers and bits for the HSCX ISDN chip. + */ + +typedef struct hscx_reg { + + /* 32 byte deep FIFO always first */ + + unsigned char hscx_fifo [HSCX_FIFO_LEN]; + + /* most registers can be read/written, but have different names */ + /* so define a union with read/write names to make that clear */ + + union { + struct { + unsigned char hscx_ista; + unsigned char hscx_star; + unsigned char hscx_mode; + unsigned char hscx_timr; + unsigned char hscx_exir; + unsigned char hscx_rbcl; + unsigned char dummy_26; + unsigned char hscx_rsta; + unsigned char hscx_ral1; + unsigned char hscx_rhcr; + unsigned char dummy_2a; + unsigned char dummy_2b; + unsigned char hscx_ccr2; + unsigned char hscx_rbch; + unsigned char hscx_vstr; + unsigned char hscx_ccr; + unsigned char dummy_30; + unsigned char dummy_31; + unsigned char dummy_32; + unsigned char dummy_33; + } hscx_r; + struct { + unsigned char hscx_mask; + unsigned char hscx_cmdr; + unsigned char hscx_mode; + unsigned char hscx_timr; + unsigned char hscx_xad1; + unsigned char hscx_xad2; + unsigned char hscx_rah1; + unsigned char hscx_rah2; + unsigned char hscx_ral1; + unsigned char hscx_ral2; + unsigned char hscx_xbcl; + unsigned char hscx_bgr; + unsigned char hscx_ccr2; + unsigned char hscx_xbch; + unsigned char hscx_rlcr; + unsigned char hscx_ccr1; + unsigned char hscx_tsax; + unsigned char hscx_tsar; + unsigned char hscx_xccr; + unsigned char hscx_rccr; + } hscx_w; + } hscx_rw; +} hscx_reg_t; + +#define REG_OFFSET(type, field) (int)(&(((type *)0)->field)) + +/* HSCX read registers */ + +#define h_ista hscx_rw.hscx_r.hscx_ista +#define H_ISTA REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ista) +#define h_star hscx_rw.hscx_r.hscx_star +#define H_STAR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_star) +#define h_mode hscx_rw.hscx_r.hscx_mode +#define H_MODE REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_mode) +#define h_timr hscx_rw.hscx_r.hscx_timr +#define H_TIMR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_timr) +#define h_exir hscx_rw.hscx_r.hscx_exir +#define H_EXIR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_exir) +#define h_rbcl hscx_rw.hscx_r.hscx_rbcl +#define H_RBCL REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rbcl) +#define h_rsta hscx_rw.hscx_r.hscx_rsta +#define H_RSTA REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rsta) +#define h_ral1 hscx_rw.hscx_r.hscx_ral1 +#define H_RAL1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ral1) +#define h_rhcr hscx_rw.hscx_r.hscx_rhcr +#define H_RHCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rhcr) +#define h_ccr2 hscx_rw.hscx_r.hscx_ccr2 +#define H_CCR2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ccr2) +#define h_rbch hscx_rw.hscx_r.hscx_rbch +#define H_RBCH REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_rbch) +#define h_vstr hscx_rw.hscx_r.hscx_vstr +#define H_VSTR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_vstr) +#define h_ccr hscx_rw.hscx_r.hscx_ccr +#define H_CCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_r.hscx_ccr) + +/* HSCX write registers - for hscx_mode, hscx_timr, hscx_ral1, hscx_ccr2 */ +/* see read registers */ + +#define h_mask hscx_rw.hscx_w.hscx_mask +#define H_MASK REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_mask) +#define h_cmdr hscx_rw.hscx_w.hscx_cmdr +#define H_CMDR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_cmdr) +#define h_xad1 hscx_rw.hscx_w.hscx_xad1 +#define H_XAD1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xad1) +#define h_xad2 hscx_rw.hscx_w.hscx_xad2 +#define H_XAD2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xad2) +#define h_rah1 hscx_rw.hscx_w.hscx_rah1 +#define H_RAH1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rah1) +#define h_rah2 hscx_rw.hscx_w.hscx_rah2 +#define H_RAH2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rah2) +#define h_ral2 hscx_rw.hscx_w.hscx_ral2 +#define H_RAL2 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_ral2) +#define h_xbcl hscx_rw.hscx_w.hscx_xbcl +#define H_XBCL REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xbcl) +#define h_bgr hscx_rw.hscx_w.hscx_bgr +#define H_BGR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_bgr) +#define h_xbch hscx_rw.hscx_w.hscx_xbch +#define H_XBCH REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xbch) +#define h_rlcr hscx_rw.hscx_w.hscx_rlcr +#define H_RLCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rlcr) +#define h_ccr1 hscx_rw.hscx_w.hscx_ccr1 +#define H_CCR1 REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_ccr1) +#define h_tsax hscx_rw.hscx_w.hscx_tsax +#define H_TSAX REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_tsax) +#define h_tsar hscx_rw.hscx_w.hscx_tsar +#define H_TSAR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_tsar) +#define h_xccr hscx_rw.hscx_w.hscx_xccr +#define H_XCCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_xccr) +#define h_rccr hscx_rw.hscx_w.hscx_rccr +#define H_RCCR REG_OFFSET(hscx_reg_t, hscx_rw.hscx_w.hscx_rccr) + +#define HSCX_ISTA_RME 0x80 +#define HSCX_ISTA_RPF 0x40 +#define HSCX_ISTA_RSC 0x20 +#define HSCX_ISTA_XPR 0x10 +#define HSCX_ISTA_TIN 0x08 +#define HSCX_ISTA_ICA 0x04 +#define HSCX_ISTA_EXA 0x02 +#define HSCX_ISTA_EXB 0x01 + +#define HSCX_MASK_RME 0x80 +#define HSCX_MASK_RPF 0x40 +#define HSCX_MASK_RSC 0x20 +#define HSCX_MASK_XPR 0x10 +#define HSCX_MASK_TIN 0x08 +#define HSCX_MASK_ICA 0x04 +#define HSCX_MASK_EXA 0x02 +#define HSCX_MASK_EXB 0x01 + +#define HSCX_EXIR_XMR 0x80 +#define HSCX_EXIR_XDU 0x40 +#define HSCX_EXIR_PCE 0x20 +#define HSCX_EXIR_RFO 0x10 +#define HSCX_EXIR_CSC 0x08 +#define HSCX_EXIR_RFS 0x04 + +/* the other bits are always 0 */ + +#define HSCX_STAR_XDOV 0x80 +#define HSCX_STAR_XFW 0x40 +#define HSCX_STAR_XRNR 0x20 +#define HSCX_STAR_RRNR 0x10 +#define HSCX_STAR_RLI 0x08 +#define HSCX_STAR_CEC 0x04 +#define HSCX_STAR_CTS 0x02 +#define HSCX_STAR_WFA 0x01 + +#define HSCX_CMDR_RMC 0x80 +#define HSCX_CMDR_RHR 0x40 +/* also known as XREP in transparent mode */ +#define HSCX_CMDR_RNR 0x20 +#define HSCX_CMDR_STI 0x10 +#define HSCX_CMDR_XTF 0x08 +#define HSCX_CMDR_XIF 0x04 +#define HSCX_CMDR_XME 0x02 +#define HSCX_CMDR_XRES 0x01 + +#define HSCX_MODE_MDS1 0x80 +#define HSCX_MODE_MDS0 0x40 +#define HSCX_MODE_ADM 0x20 +#define HSCX_MODE_TMD 0x10 +#define HSCX_MODE_RAC 0x08 +#define HSCX_MODE_RTS 0x04 +#define HSCX_MODE_TRS 0x02 +#define HSCX_MODE_TLP 0x01 + +#define HSCX_RSTA_VFR 0x80 +#define HSCX_RSTA_RDO 0x40 +#define HSCX_RSTA_CRC 0x20 +#define HSCX_RSTA_RAB 0x10 +#define HSCX_RSTA_HA1 0x08 +#define HSCX_RSTA_HA0 0x04 +#define HSCX_RSTA_CR 0x02 +#define HSCX_RSTA_LA 0x01 + +#define HSCX_RSTA_MASK 0xf0 /* the interesting ones */ + +/* only used in DMA mode */ +#define HSCX_XBCH_DMA 0x80 +#define HSCX_XBCH_NRM 0x40 +#define HSCX_XBCH_CAS 0x20 +#define HSCX_XBCH_XC 0x10 +/* the rest are bits 11 thru 8 of the byte count */ + +#define HSCX_RBCH_DMA 0x80 +#define HSCX_RBCH_NRM 0x40 +#define HSCX_RBCH_CAS 0x20 +#define HSCX_RBCH_OV 0x10 +/* the rest are bits 11 thru 8 of the byte count */ + +#define HSCX_VSTR_CD 0x80 +/* bits 6 thru 4 are 0 */ +/* bits 3 thru 0 are the version number */ + +#define HSCX_RLCR_RC 0x80 +/* the rest of the bits are used to set the received length */ + +#define HSCX_CCR1_PU 0x80 +/* bits 6 and 5 are SC1 SC0 */ +#define HSCX_CCR1_ODS 0x10 +#define HSCX_CCR1_ITF 0x08 +#define HSCX_CCR1_CM2 0x04 +#define HSCX_CCR1_CM1 0x02 +#define HSCX_CCR1_CM0 0x01 + +/* for clock mode 5 */ +#define HSCX_CCR2_SOC2 0x80 +#define HSCX_CCR2_SOC1 0x40 +#define HSCX_CCR2_XCS0 0x20 +#define HSCX_CCR2_RCS0 0x10 +#define HSCX_CCR2_TIO 0x08 +#define HSCX_CCR2_CIE 0x04 +#define HSCX_CCR2_RIE 0x02 +#define HSCX_CCR2_DIV 0x01 + +/* bits 7 thru 2 are TSNX */ +#define HSCX_TSAX_XCS2 0x02 +#define HSCX_TSAX_XCS1 0x01 + +/* bits 7 thru 2 are TSNR */ +#define HSCX_TSAR_RCS2 0x02 +#define HSCX_TSAR_RCS1 0x01 + +#endif /* I4B_HSCX_H_ */ diff --git a/sys/i4b/layer1/i4b_ipac.h b/sys/i4b/layer1/i4b_ipac.h new file mode 100644 index 000000000000..79d8bc9656bd --- /dev/null +++ b/sys/i4b/layer1/i4b_ipac.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_ipac.h - definitions for the Siemens IPAC PSB2115 chip + * ========================================================== + * + * $Id: i4b_ipac.h,v 1.4 1998/12/05 18:04:39 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:23:50 1998] + * + *--------------------------------------------------------------------------- + */ + +#ifndef _I4B_IPAC_H_ +#define _I4B_IPAC_H_ + +#define IPAC_BFIFO_LEN 64 /* 64 bytes B-channel FIFO on chip */ + +#define IPAC_HSCXA_OFF 0x00 +#define IPAC_HSCXB_OFF 0x40 +#define IPAC_ISAC_OFF 0x80 +#define IPAC_IPAC_OFF 0xc0 + +/* + * definitions of registers and bits for the IPAC ISDN chip. + */ + +typedef struct ipac_reg { + + /* most registers can be read/written, but have different names */ + /* so define a union with read/write names to make that clear */ + + union { + struct { + unsigned char ipac_conf; + unsigned char ipac_ista; + unsigned char ipac_id; + unsigned char ipac_acfg; + unsigned char ipac_aoe; + unsigned char ipac_arx; + unsigned char ipac_pita1; + unsigned char ipac_pita2; + unsigned char ipac_pota1; + unsigned char ipac_pota2; + unsigned char ipac_pcfg; + unsigned char ipac_scfg; + unsigned char ipac_timr2; + } ipac_r; + struct { + unsigned char ipac_conf; + unsigned char ipac_mask; + unsigned char ipac_dummy; + unsigned char ipac_acfg; + unsigned char ipac_aoe; + unsigned char ipac_atx; + unsigned char ipac_pita1; + unsigned char ipac_pita2; + unsigned char ipac_pota1; + unsigned char ipac_pota2; + unsigned char ipac_pcfg; + unsigned char ipac_scfg; + unsigned char ipac_timr2; + } ipac_w; + } ipac_rw; +} ipac_reg_t; + +#define REG_OFFSET(type, field) (int)(&(((type *)0)->field)) + +/* IPAC read registers */ + +#define IPAC_CONF REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_conf) +#define IPAC_ISTA REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_ista) +#define IPAC_ID REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_id) +#define IPAC_ACFG REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_acfg) +#define IPAC_AOE REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_aoe) +#define IPAC_ARX REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_arx) +#define IPAC_PITA1 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pita1) +#define IPAC_PITA2 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pita2) +#define IPAC_POTA1 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pota1) +#define IPAC_POTA2 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pota2) +#define IPAC_PCFG REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_pcfg) +#define IPAC_SCFG REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_scfg) +#define IPAC_TIMR2 REG_OFFSET(ipac_reg_t, ipac_rw.ipac_r.ipac_timr2) + +/* IPAC write registers */ + +#define IPAC_MASK REG_OFFSET(ipac_reg_t, ipac_rw.ipac_w.ipac_mask) +#define IPAC_ATX REG_OFFSET(ipac_reg_t, ipac_rw.ipac_w.ipac_atx) + +/* register bits */ + +#define IPAC_CONF_AMP 0x80 +#define IPAC_CONF_CFS 0x40 +#define IPAC_CONF_TEM 0x20 +#define IPAC_CONF_PDS 0x10 +#define IPAC_CONF_IDH 0x08 +#define IPAC_CONF_SGO 0x04 +#define IPAC_CONF_ODS 0x02 +#define IPAC_CONF_IOF 0x01 + +#define IPAC_ISTA_INT1 0x80 +#define IPAC_ISTA_INT0 0x40 +#define IPAC_ISTA_ICD 0x20 +#define IPAC_ISTA_EXD 0x10 +#define IPAC_ISTA_ICA 0x08 +#define IPAC_ISTA_EXA 0x04 +#define IPAC_ISTA_ICB 0x02 +#define IPAC_ISTA_EXB 0x01 + +#define IPAC_MASK_INT1 0x80 +#define IPAC_MASK_INT0 0x40 +#define IPAC_MASK_ICD 0x20 +#define IPAC_MASK_EXD 0x10 +#define IPAC_MASK_ICA 0x08 +#define IPAC_MASK_EXA 0x04 +#define IPAC_MASK_ICB 0x02 +#define IPAC_MASK_EXB 0x01 + +#define IPAC_ACFG_OD7 0x80 +#define IPAC_ACFG_OD6 0x40 +#define IPAC_ACFG_OD5 0x20 +#define IPAC_ACFG_OD4 0x10 +#define IPAC_ACFG_OD3 0x08 +#define IPAC_ACFG_OD2 0x04 +#define IPAC_ACFG_EL1 0x02 +#define IPAC_ACFG_EL2 0x01 + +#define IPAC_AOE_OE7 0x80 +#define IPAC_AOE_OE6 0x40 +#define IPAC_AOE_OE5 0x20 +#define IPAC_AOE_OE4 0x10 +#define IPAC_AOE_OE3 0x08 +#define IPAC_AOE_OE2 0x04 + +#define IPAC_ARX_AR7 0x80 +#define IPAC_ARX_AR6 0x40 +#define IPAC_ARX_AR5 0x20 +#define IPAC_ARX_AR4 0x10 +#define IPAC_ARX_AR3 0x08 +#define IPAC_ARX_AR2 0x04 + +#define IPAC_ATX_AT7 0x80 +#define IPAC_ATX_AT6 0x40 +#define IPAC_ATX_AT5 0x20 +#define IPAC_ATX_AT4 0x10 +#define IPAC_ATX_AT3 0x08 +#define IPAC_ATX_AT2 0x04 + +#define IPAC_PITA1_ENA 0x80 +#define IPAC_PITA1_DUDD 0x40 + +#define IPAC_PITA2_ENA 0x80 +#define IPAC_PITA2_DUDD 0x40 + +#define IPAC_POTA1_ENA 0x80 +#define IPAC_POTA1_DUDD 0x40 + +#define IPAC_POTA2_ENA 0x80 +#define IPAC_POTA2_DUDD 0x40 + +#define IPAC_PCFG_DPS 0x80 +#define IPAC_PCFG_ACL 0x40 +#define IPAC_PCFG_LED 0x20 +#define IPAC_PCFG_PLD 0x10 +#define IPAC_PCFG_FBS 0x08 +#define IPAC_PCFG_CSL2 0x04 +#define IPAC_PCFG_CSL1 0x02 +#define IPAC_PCFG_CSL0 0x01 + +#define IPAC_SCFG_PRI 0x80 +#define IPAC_SCFG_TXD 0x40 +#define IPAC_SCFG_TLEN 0x20 + +#define IPAC_TIMR2_TMD 0x80 + +#endif /* _I4B_IPAC_H_ */ diff --git a/sys/i4b/layer1/i4b_isac.c b/sys/i4b/layer1/i4b_isac.c new file mode 100644 index 000000000000..4065c9a575b9 --- /dev/null +++ b/sys/i4b/layer1/i4b_isac.c @@ -0,0 +1,679 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isac.c - i4b siemens isdn chipset driver ISAC handler + * --------------------------------------------------------- + * + * $Id: i4b_isac.c,v 1.28 1998/12/05 18:04:41 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:23:59 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#else +#define NISIC 1 /* non-FreeBSD handles this via config(8) */ +#endif +#if NISIC > 0 + +#ifdef __FreeBSD__ +#include "opt_i4b.h" +#endif +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +static u_char isic_isac_exir_hdlr(register struct isic_softc *sc, u_char exir); +static void isic_isac_ind_hdlr(register struct isic_softc *sc, int ind); + +/*---------------------------------------------------------------------------* + * ISAC interrupt service routine + *---------------------------------------------------------------------------*/ +void +isic_isac_irq(struct isic_softc *sc, int ista) +{ + register u_char c = 0; + DBGL1(L1_F_MSG, "isic_isac_irq", ("unit %d: ista = 0x%02x\n", sc->sc_unit, ista)); + + if(ista & ISAC_ISTA_EXI) /* extended interrupt */ + { + c |= isic_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); + } + + if(ista & ISAC_ISTA_RME) /* receive message end */ + { + register int rest; + u_char rsta; + + /* get rx status register */ + + rsta = ISAC_READ(I_RSTA); + + if((rsta & ISAC_RSTA_MASK) != 0x20) + { + int error = 0; + + if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ + { + error++; + DBGL1(L1_I_ERR, "isic_isac_irq", ("unit %d: CRC error\n", sc->sc_unit)); + } + + if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ + { + error++; + DBGL1(L1_I_ERR, "isic_isac_irq", ("unit %d: Data Overrun error\n", sc->sc_unit)); + } + + if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ + { + error++; + DBGL1(L1_I_ERR, "isic_isac_irq", ("unit %d: Receive Aborted error\n", sc->sc_unit)); + } + + if(error == 0) + DBGL1(L1_I_ERR, "isic_isac_irq", ("unit %d: RME unknown error, RSTA = 0x%02x!\n", sc->sc_unit, rsta)); + + i4b_Dfreembuf(sc->sc_ibuf); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); + ISACCMDRWRDELAY(); + + return; + } + + rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); + + if(rest == 0) + rest = ISAC_FIFO_LEN; + + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) + sc->sc_ib = sc->sc_ibuf->m_data; + else + panic("isic_isac_irq: RME, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest)) + { + ISAC_RDFIFO(sc->sc_ib, rest); + sc->sc_ilen += rest; + + sc->sc_ibuf->m_pkthdr.len = + sc->sc_ibuf->m_len = sc->sc_ilen; + + if(sc->sc_trace & TRACE_D_RX) + { + i4b_trace_hdr_t hdr; + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_D; + hdr.dir = FROM_NT; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); + } + + c |= ISAC_CMDR_RMC; + + if(sc->sc_enabled) + PH_Data_Ind(sc->sc_unit, sc->sc_ibuf); + else + i4b_Dfreembuf(sc->sc_ibuf); + } + else + { + DBGL1(L1_I_ERR, "isic_isac_irq", ("RME, input buffer overflow!\n")); + i4b_Dfreembuf(sc->sc_ibuf); + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + } + + if(ista & ISAC_ISTA_RPF) /* receive fifo full */ + { + if(sc->sc_ibuf == NULL) + { + if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) + sc->sc_ib= sc->sc_ibuf->m_data; + else + panic("isic_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); + sc->sc_ilen = 0; + } + + if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) + { + ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); + sc->sc_ilen += ISAC_FIFO_LEN; + sc->sc_ib += ISAC_FIFO_LEN; + c |= ISAC_CMDR_RMC; + } + else + { + DBGL1(L1_I_ERR, "isic_isac_irq", ("RPF, input buffer overflow!\n")); + i4b_Dfreembuf(sc->sc_ibuf); + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + } + + if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ + { + if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) + { + sc->sc_freeflag = sc->sc_freeflag2; + sc->sc_obuf = sc->sc_obuf2; + sc->sc_op = sc->sc_obuf->m_data; + sc->sc_ol = sc->sc_obuf->m_len; + sc->sc_obuf2 = NULL; +#ifdef NOTDEF + printf("ob2=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + else + { +#ifdef NOTDEF + printf("ob=%x, op=%x, ol=%d, f=%d #", + sc->sc_obuf, + sc->sc_op, + sc->sc_ol, + sc->sc_state); +#endif + } + + if(sc->sc_obuf) + { + ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISAC_FIFO_LEN)); + + if(sc->sc_ol > ISAC_FIFO_LEN) /* length > 32 ? */ + { + sc->sc_op += ISAC_FIFO_LEN; /* bufferptr+32 */ + sc->sc_ol -= ISAC_FIFO_LEN; /* length - 32 */ + c |= ISAC_CMDR_XTF; /* set XTF bit */ + } + else + { + if(sc->sc_freeflag) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_freeflag = 0; + } + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + c |= ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + } + else + { + sc->sc_state &= ~ISAC_TX_ACTIVE; + } + } + + if(ista & ISAC_ISTA_CISQ) /* channel status change CISQ */ + { + register u_char ci; + + /* get command/indication rx register*/ + + ci = ISAC_READ(I_CIRR); + + /* if S/Q IRQ, read SQC reg to clr SQC IRQ */ + + if(ci & ISAC_CIRR_SQC) + (void) ISAC_READ(I_SQRR); + + /* C/I code change IRQ (flag already cleared by CIRR read) */ + + if(ci & ISAC_CIRR_CIC0) + isic_isac_ind_hdlr(sc, (ci >> 2) & 0xf); + } + + if(c) + { + ISAC_WRITE(I_CMDR, c); + ISACCMDRWRDELAY(); + } +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Extended IRQ handler + *---------------------------------------------------------------------------*/ +static u_char +isic_isac_exir_hdlr(register struct isic_softc *sc, u_char exir) +{ + u_char c = 0; + + if(exir & ISAC_EXIR_XMR) + { + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Tx Message Repeat\n")); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_XDU) + { + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Tx Data Underrun\n")); + + c |= ISAC_CMDR_XRES; + } + + if(exir & ISAC_EXIR_PCE) + { + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Protocol Error\n")); + } + + if(exir & ISAC_EXIR_RFO) + { + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Rx Frame Overflow\n")); + + c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; + } + + if(exir & ISAC_EXIR_SOV) + { + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Sync Xfer Overflow\n")); + } + + if(exir & ISAC_EXIR_MOS) + { + DBGL1(L1_I_ERR, "L1 isic_isac_exir_hdlr", ("EXIRQ Monitor Status\n")); + } + + if(exir & ISAC_EXIR_SAW) + { + /* cannot happen, STCR:TSF is set to 0 */ + + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Subscriber Awake\n")); + } + + if(exir & ISAC_EXIR_WOV) + { + /* cannot happen, STCR:TSF is set to 0 */ + + DBGL1(L1_I_ERR, "isic_isac_exir_hdlr", ("EXIRQ Watchdog Timer Overflow\n")); + } + + return(c); +} + +/*---------------------------------------------------------------------------* + * ISAC L1 Indication handler + *---------------------------------------------------------------------------*/ +static void +isic_isac_ind_hdlr(register struct isic_softc *sc, int ind) +{ + register int event; + + switch(ind) + { + case ISAC_CIRR_IAI8: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx AI8 in state %s\n", isic_printstate(sc))); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + isic_isac_l1_cmd(sc, CMD_AR8); + event = EV_INFO48; + MPH_Status_Ind(sc->sc_unit, STI_L1STAT, LAYER_ACTIVE); + break; + + case ISAC_CIRR_IAI10: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx AI10 in state %s\n", isic_printstate(sc))); + if(sc->sc_bustyp == BUS_TYPE_IOM2) + isic_isac_l1_cmd(sc, CMD_AR10); + event = EV_INFO410; + MPH_Status_Ind(sc->sc_unit, STI_L1STAT, LAYER_ACTIVE); + break; + + case ISAC_CIRR_IRSY: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx RSY in state %s\n", isic_printstate(sc))); + event = EV_RSY; + break; + + case ISAC_CIRR_IPU: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx PU in state %s\n", isic_printstate(sc))); + event = EV_PU; + break; + + case ISAC_CIRR_IDR: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx DR in state %s\n", isic_printstate(sc))); + isic_isac_l1_cmd(sc, CMD_DIU); + event = EV_DR; + break; + + case ISAC_CIRR_IDID: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx DID in state %s\n", isic_printstate(sc))); + event = EV_INFO0; + MPH_Status_Ind(sc->sc_unit, STI_L1STAT, LAYER_IDLE); + break; + + case ISAC_CIRR_IDIS: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx DIS in state %s\n", isic_printstate(sc))); + event = EV_DIS; + break; + + case ISAC_CIRR_IEI: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx EI in state %s\n", isic_printstate(sc))); + isic_isac_l1_cmd(sc, CMD_DIU); + event = EV_EI; + break; + + case ISAC_CIRR_IARD: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx ARD in state %s\n", isic_printstate(sc))); + event = EV_INFO2; + break; + + case ISAC_CIRR_ITI: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx TI in state %s\n", isic_printstate(sc))); + event = EV_INFO0; + break; + + case ISAC_CIRR_IATI: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx ATI in state %s\n", isic_printstate(sc))); + event = EV_INFO0; + break; + + case ISAC_CIRR_ISD: + DBGL1(L1_I_CICO, "isic_isac_ind_hdlr", ("rx SD in state %s\n", isic_printstate(sc))); + event = EV_INFO0; + break; + + default: + DBGL1(L1_I_ERR, "isic_isac_ind_hdlr", ("UNKNOWN Indication 0x%x in state %s\n", ind, isic_printstate(sc))); + event = EV_INFO0; + break; + } + isic_next_state(sc, event); +} + +/*---------------------------------------------------------------------------* + * execute a layer 1 command + *---------------------------------------------------------------------------*/ +void +isic_isac_l1_cmd(struct isic_softc *sc, int command) +{ + u_char cmd; + +#ifdef I4B_SMP_WORKAROUND + + /* XXXXXXXXXXXXXXXXXXX */ + + /* + * patch from Wolfgang Helbig: + * + * Here is a patch that makes i4b work on an SMP: + * The card (TELES 16.3) didn't interrupt on an SMP machine. + * This is a gross workaround, but anyway it works *and* provides + * some information as how to finally fix this problem. + */ + + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + + /* XXXXXXXXXXXXXXXXXXX */ + +#endif /* I4B_SMP_WORKAROUND */ + + if(command < 0 || command > CMD_ILL) + { + DBGL1(L1_I_ERR, "isic_isac_l1_cmd", ("illegal cmd 0x%x in state %s\n", command, isic_printstate(sc))); + return; + } + + if(sc->sc_bustyp == BUS_TYPE_IOM2) + cmd = ISAC_CIX0_LOW; + else + cmd = 0; + + switch(command) + { + case CMD_TIM: + DBGL1(L1_I_CICO, "isic_isac_l1_cmd", ("tx TIM in state %s\n", isic_printstate(sc))); + cmd |= (ISAC_CIXR_CTIM << 2); + break; + + case CMD_RS: + DBGL1(L1_I_CICO, "isic_isac_l1_cmd", ("tx RS in state %s\n", isic_printstate(sc))); + cmd |= (ISAC_CIXR_CRS << 2); + break; + + case CMD_AR8: + DBGL1(L1_I_CICO, "isic_isac_l1_cmd", ("tx AR8 in state %s\n", isic_printstate(sc))); + cmd |= (ISAC_CIXR_CAR8 << 2); + break; + + case CMD_AR10: + DBGL1(L1_I_CICO, "isic_isac_l1_cmd", ("tx AR10 in state %s\n", isic_printstate(sc))); + cmd |= (ISAC_CIXR_CAR10 << 2); + break; + + case CMD_DIU: + DBGL1(L1_I_CICO, "isic_isac_l1_cmd", ("tx DIU in state %s\n", isic_printstate(sc))); + cmd |= (ISAC_CIXR_CDIU << 2); + break; + } + ISAC_WRITE(I_CIXR, cmd); +} + +/*---------------------------------------------------------------------------* + * L1 ISAC initialization + *---------------------------------------------------------------------------*/ +int +isic_isac_init(struct isic_softc *sc) +{ + ISAC_IMASK = 0xff; /* disable all irqs */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + if(sc->sc_bustyp != BUS_TYPE_IOM2) + { + DBGL1(L1_I_SETUP, "isic_isac_setup", ("configuring for IOM-1 mode\n")); + + /* ADF2: Select mode IOM-1 */ + ISAC_WRITE(I_ADF2, 0x00); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SAC - SIP port high Z + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 and B2 switched to/from SPa + */ + ISAC_WRITE(I_SPCR, ISAC_SPCR_C1C1|ISAC_SPCR_C2C1); + + /* SQXR: S/Q channel xmit register: + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * CFS - IOM clock/frame always active + * FSC1/2 - polarity of 8kHz strobe + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, ISAC_ADF1_FC2); /* ADF1 */ + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + else + { + DBGL1(L1_I_SETUP, "isic_isac_setup", ("configuring for IOM-2 mode\n")); + + /* ADF2: Select mode IOM-2 */ + ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); + + /* SPCR: serial port control register: + * SPU - software power up = 0 + * SPM - timing mode 0 + * TLP - test loop = 0 + * C1C, C2C - B1 + C1 and B2 + IC2 monitoring + */ + ISAC_WRITE(I_SPCR, 0x00); + + /* SQXR: S/Q channel xmit register: + * IDC - IOM direction = 0 (master) + * CFS - Config Select = 0 (clock always active) + * CI1E - C/I channel 1 IRQ enable = 0 + * SQIE - S/Q IRQ enable = 0 + * SQX1-4 - Fa bits = 1 + */ + ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); + + /* ADF1: additional feature reg 1: + * WTC - watchdog = 0 + * TEM - test mode = 0 + * PFS - pre-filter = 0 + * IOF - IOM i/f off = 0 + * ITF - interframe fill = idle + */ + ISAC_WRITE(I_ADF1, 0x00); + + /* STCR: sync transfer control reg: + * TSF - terminal secific functions = 0 + * TBA - TIC bus address = 7 + * STx/SCx = 0 + */ + ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); + + /* MODE: Mode Register: + * MDSx - transparent mode 2 + * TMD - timer mode = external + * RAC - Receiver enabled + * DIMx - digital i/f mode + */ + ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); + } + +#ifdef NOTDEF + /* + * XXX a transmitter reset causes an ISAC tx IRQ which will not + * be serviced at attach time under some circumstances leaving + * the associated IRQ line on the ISA bus active. This prevents + * any further interrupts to be serviced because no low -> high + * transition can take place anymore. (-hm) + */ + + /* command register: + * RRES - HDLC receiver reset + * XRES - transmitter reset + */ + ISAC_WRITE(I_CMDR, ISAC_CMDR_RRES|ISAC_CMDR_XRES); + ISACCMDRWRDELAY(); +#endif + + /* enabled interrupts: + * =================== + * RME - receive message end + * RPF - receive pool full + * XPR - transmit pool ready + * CISQ - CI or S/Q channel change + * EXI - extended interrupt + */ + + ISAC_IMASK = ISAC_MASK_RSC | /* auto mode only */ + ISAC_MASK_TIN | /* timer irq */ + ISAC_MASK_SIN; /* sync xfer irq */ + + ISAC_WRITE(I_MASK, ISAC_IMASK); + + return(0); +} + +#endif /* NISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_isac.h b/sys/i4b/layer1/i4b_isac.h new file mode 100644 index 000000000000..56a4241564fe --- /dev/null +++ b/sys/i4b/layer1/i4b_isac.h @@ -0,0 +1,391 @@ +/* + * Copyright (c) 1996, 1998 Gary Jennejohn. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * $Id: i4b_isac.h,v 1.5 1998/03/28 15:11:03 hm Exp $ + * + * last edit-date: [Fri Mar 27 15:52:40 1998] + * + * -hm split up for rewrite of Siemens chipset driver + * + *--------------------------------------------------------------------------- + */ + +#ifndef I4B_ISAC_H_ +#define I4B_ISAC_H_ + +/* + * The ISAC databook specifies a delay of 2.5 DCL clock cycles between + * writes to the ISAC command register CMDR. This is the delay used to + * satisfy this requirement. + */ + +#define I4B_ISAC_CMDRWRDELAY 30 + +#if (I4B_ISAC_CMDRWRDELAY > 0) +#define ISACCMDRWRDELAY() DELAY(I4B_ISAC_CMDRWRDELAY) +#else +#warning "I4B_ISAC_CMDRWRDELAY set to 0!" +#define ISACCMDRWRDELAY() +#endif + +enum ISAC_VERSIONS { + ISAC_VA, /* 2085 A1 or A2, 2086/2186 V1.1 */ + ISAC_VB1, /* 2085 B1 */ + ISAC_VB2, /* 2085 B2 */ + ISAC_VB3, /* 2085 B3/V2.3 */ + ISAC_UNKN /* unknown version */ +}; + +#define ISAC_FIFO_LEN 32 /* 32 bytes FIFO on chip */ + +/* + * definitions of registers and bits for the ISAC ISDN chip. + */ + +typedef struct isac_reg { + + /* 32 byte deep FIFO always first */ + + unsigned char isac_fifo [ISAC_FIFO_LEN]; + + /* most registers can be read/written, but have different names */ + /* so define a union with read/write names to make that clear */ + + union { + struct { + unsigned char isac_ista; + unsigned char isac_star; + unsigned char isac_mode; + unsigned char isac_timr; + unsigned char isac_exir; + unsigned char isac_rbcl; + unsigned char isac_sapr; + unsigned char isac_rsta; + unsigned char dummy_28; + unsigned char isac_rhcr; + unsigned char isac_rbch; + unsigned char isac_star2; + unsigned char dummy_2c; + unsigned char dummy_2d; + unsigned char dummy_2e; + unsigned char dummt_2f; + unsigned char isac_spcr; + unsigned char isac_cirr; + unsigned char isac_mor; + unsigned char isac_sscr; + unsigned char isac_sfcr; + unsigned char isac_c1r; + unsigned char isac_c2r; + unsigned char isac_b1cr; + unsigned char isac_b2cr; + unsigned char isac_adf2; + unsigned char isac_mosr; + unsigned char isac_sqrr; + } isac_r; + struct { + unsigned char isac_mask; + unsigned char isac_cmdr; + unsigned char isac_mode; + unsigned char isac_timr; + unsigned char isac_xad1; + unsigned char isac_xad2; + unsigned char isac_sap1; + unsigned char isac_sap2; + unsigned char isac_tei1; + unsigned char isac_tei2; + unsigned char dummy_2a; + unsigned char isac_star2; + unsigned char dummy_2c; + unsigned char dummy_2d; + unsigned char dummy_2e; + unsigned char dummt_2f; + unsigned char isac_spcr; + unsigned char isac_cixr; + unsigned char isac_mox; + unsigned char isac_sscx; + unsigned char isac_sfcw; + unsigned char isac_c1r; + unsigned char isac_c2r; + unsigned char isac_stcr; + unsigned char isac_adf1; + unsigned char isac_adf2; + unsigned char isac_mocr; + unsigned char isac_sqxr; + } isac_w; + } isac_rw; +} isac_reg_t; + +#define REG_OFFSET(type, field) (int)(&(((type *)0)->field)) + +/* ISAC read registers */ + +#define i_ista isac_rw.isac_r.isac_ista +#define I_ISTA REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_ista) +#define i_star isac_rw.isac_r.isac_star +#define I_STAR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_star) +#define i_mode isac_rw.isac_r.isac_mode +#define I_MODE REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_mode) +#define i_timr isac_rw.isac_r.isac_timr +#define I_TIMR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_timr) +#define i_exir isac_rw.isac_r.isac_exir +#define I_EXIR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_exir) +#define i_rbcl isac_rw.isac_r.isac_rbcl +#define I_RBCL REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rbcl) +#define i_sapr isac_rw.isac_r.isac_sapr +#define I_SAPR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sapr) +#define i_rsta isac_rw.isac_r.isac_rsta +#define I_RSTA REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rsta) +#define i_rhcr isac_rw.isac_r.isac_rhcr +#define I_RHCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rhcr) +#define i_rbch isac_rw.isac_r.isac_rbch +#define I_RBCH REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_rbch) +#define i_star2 isac_rw.isac_r.isac_star2 +#define I_STAR2 REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_star2) +#define i_spcr isac_rw.isac_r.isac_spcr +#define I_SPCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_spcr) +#define i_cirr isac_rw.isac_r.isac_cirr +#define I_CIRR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_cirr) +#define i_mor isac_rw.isac_r.isac_mor +#define I_MOR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_mor) +#define i_sscr isac_rw.isac_r.isac_sscr +#define I_SSCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sscr) +#define i_sfcr isac_rw.isac_r.isac_sfcr +#define I_SFCR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sfcr) +#define i_c1r isac_rw.isac_r.isac_c1r +#define I_C1R REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_c1r) +#define i_c2r isac_rw.isac_r.isac_c2r +#define I_C2R REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_c2r) +#define i_b1cr isac_rw.isac_r.isac_b1cr +#define I_B1CR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_b1cr) +#define i_b2cr isac_rw.isac_r.isac_b2cr +#define I_B2CR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_b2cr) +#define i_adf2 isac_rw.isac_r.isac_adf2 +#define I_ADF2 REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_adf2) +#define i_mosr isac_rw.isac_r.isac_mosr +#define I_MOSR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_mosr) +#define i_sqrr isac_rw.isac_r.isac_sqrr +#define I_SQRR REG_OFFSET(isac_reg_t, isac_rw.isac_r.isac_sqrr) + +/* ISAC write registers - isac_mode, isac_timr, isac_star2, isac_spcr, */ +/* isac_c1r, isac_c2r, isac_adf2 see read registers */ + +#define i_mask isac_rw.isac_w.isac_mask +#define I_MASK REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_mask) +#define i_cmdr isac_rw.isac_w.isac_cmdr +#define I_CMDR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_cmdr) +#define i_xad1 isac_rw.isac_w.isac_xad1 +#define I_XAD1 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_xad1) +#define i_xad2 isac_rw.isac_w.isac_xad2 +#define I_XAD2 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_xad2) +#define i_sap1 isac_rw.isac_w.isac_sap1 +#define I_SAP1 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sap1) +#define i_sap2 isac_rw.isac_w.isac_sap2 +#define I_SAP2 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sap2) +#define i_tei1 isac_rw.isac_w.isac_tei1 +#define i_tei2 isac_rw.isac_w.isac_tei2 +#define i_cixr isac_rw.isac_w.isac_cixr +#define I_CIXR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_cixr) +#define I_CIX0 I_CIXR +#define i_mox isac_rw.isac_w.isac_mox +#define I_MOX REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_mox) +#define i_sscx isac_rw.isac_w.isac_sscx +#define I_SSCX REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sscx) +#define i_sfcw isac_rw.isac_w.isac_sfcw +#define I_SFCW REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sfcw) +#define i_stcr isac_rw.isac_w.isac_stcr +#define I_STCR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_stcr) +#define i_adf1 isac_rw.isac_w.isac_adf1 +#define I_ADF1 REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_adf1) +#define i_mocr isac_rw.isac_w.isac_mocr +#define I_MOCR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_mocr) +#define i_sqxr isac_rw.isac_w.isac_sqxr +#define I_SQXR REG_OFFSET(isac_reg_t, isac_rw.isac_w.isac_sqxr) + +#define ISAC_ISTA_RME 0x80 +#define ISAC_ISTA_RPF 0x40 +#define ISAC_ISTA_RSC 0x20 +#define ISAC_ISTA_XPR 0x10 +#define ISAC_ISTA_TIN 0x08 +#define ISAC_ISTA_CISQ 0x04 +#define ISAC_ISTA_SIN 0x02 +#define ISAC_ISTA_EXI 0x01 + +#define ISAC_MASK_RME 0x80 +#define ISAC_MASL_RPF 0x40 +#define ISAC_MASK_RSC 0x20 +#define ISAC_MASK_XPR 0x10 +#define ISAC_MASK_TIN 0x08 +#define ISAC_MASK_CISQ 0x04 +#define ISAC_MASK_SIN 0x02 +#define ISAC_MASK_EXI 0x01 +#define ISAC_MASK_ALL 0xff + +#define ISAC_STAR_XDOV 0x80 +#define ISAC_STAR_XFW 0x40 +#define ISAC_STAR_XRNR 0x20 +#define ISAC_STAR_RRNR 0x10 +#define ISAC_STAR_MBR 0x08 +#define ISAC_STAR_MAC1 0x04 +#define ISAC_STAR_BVS 0x02 +#define ISAC_STAR_MAC0 0x01 + +#define ISAC_CMDR_RMC 0x80 +#define ISAC_CMDR_RRES 0x40 +#define ISAC_CMDR_RNR 0x20 +#define ISAC_CMDR_STI 0x10 +#define ISAC_CMDR_XTF 0x08 +#define ISAC_CMDR_XIF 0x04 +#define ISAC_CMDR_XME 0x02 +#define ISAC_CMDR_XRES 0x01 + +#define ISAC_MODE_MDS2 0x80 +#define ISAC_MODE_MDS1 0x40 +#define ISAC_MODE_MDS0 0x20 +#define ISAC_MODE_TMD 0x10 +#define ISAC_MODE_RAC 0x08 +#define ISAC_MODE_DIM2 0x04 +#define ISAC_MODE_DIM1 0x02 +#define ISAC_MODE_DIM0 0x01 + +#define ISAC_EXIR_XMR 0x80 +#define ISAC_EXIR_XDU 0x40 +#define ISAC_EXIR_PCE 0x20 +#define ISAC_EXIR_RFO 0x10 +#define ISAC_EXIR_SOV 0x08 +#define ISAC_EXIR_MOS 0x04 +#define ISAC_EXIR_SAW 0x02 +#define ISAC_EXIR_WOV 0x01 + +#define ISAC_RSTA_RDA 0x80 +#define ISAC_RSTA_RDO 0x40 +#define ISAC_RSTA_CRC 0x20 +#define ISAC_RSTA_RAB 0x10 +#define ISAC_RSTA_SA1 0x08 +#define ISAC_RSTA_SA0 0x04 +#define ISAC_RSTA_CR 0x02 +#define ISAC_RSTA_TA 0x01 + +#define ISAC_RSTA_MASK 0x70 /* the interesting bits */ + +#define ISAC_RBCH_XAC 0x80 +#define ISAC_RBCH_VN1 0x40 +#define ISAC_RBCH_VN0 0x20 +#define ISAC_RBCH_OV 0x10 +/* the other 4 bits are the high bits of the receive byte count */ + +#define ISAC_SPCR_SPU 0x80 +#define ISAC_SPCR_SAC 0x40 +#define ISAC_SPCR_SPM 0x20 +#define ISAC_SPCR_TLP 0x10 +#define ISAC_SPCR_C1C1 0x08 +#define ISAC_SPCR_C1C0 0x04 +#define ISAC_SPCR_C2C1 0x02 +#define ISAC_SPCR_C2C0 0x01 + +#define ISAC_CIRR_SQC 0x80 +#define ISAC_CIRR_BAS 0x40 +/* bits 5-2 CODR */ +#define ISAC_CIRR_CIC0 0x02 +/* bit 0 is always 0 */ +/* C/I codes from bits 5-2 (>> 2 & 0xf) */ +/* the indications */ +#define ISAC_CIRR_IPU 0x07 +#define ISAC_CIRR_IDR 0x00 +#define ISAC_CIRR_ISD 0x02 +#define ISAC_CIRR_IDIS 0x03 +#define ISAC_CIRR_IEI 0x06 +#define ISAC_CIRR_IRSY 0x04 +#define ISAC_CIRR_IARD 0x08 +#define ISAC_CIRR_ITI 0x0a +#define ISAC_CIRR_IATI 0x0b +#define ISAC_CIRR_IAI8 0x0c +#define ISAC_CIRR_IAI10 0x0d +#define ISAC_CIRR_IDID 0x0f + +#define ISAC_CI_MASK 0x0f + +#define ISAC_CIXR_RSS 0x80 +#define ISAC_CIXR_BAC 0x40 +/* bits 5-2 CODX */ +#define ISAC_CIXR_TCX 0x02 +#define ISAC_CIXR_ECX 0x01 +/* in IOM-2 mode the low bits are always 1 */ +#define ISAC_CIX0_LOW 0x03 +/* C/I codes from bits 5-2 (>> 2 & 0xf) */ +/* the commands */ +#define ISAC_CIXR_CTIM 0 +#define ISAC_CIXR_CRS 0x01 +#define ISAC_CIXR_CSCZ 0x04 +#define ISAC_CIXR_CSSZ 0x02 +#define ISAC_CIXR_CAR8 0x08 +#define ISAC_CIXR_CAR10 0x09 +#define ISAC_CIXR_CARL 0x0a +#define ISAC_CIXR_CDIU 0x0f + +#define ISAC_STCR_TSF 0x80 +#define ISAC_STCR_TBA2 0x40 +#define ISAC_STCR_TBA1 0x20 +#define ISAC_STCR_TBA0 0x10 +#define ISAC_STCR_ST1 0x08 +#define ISAC_STCR_ST0 0x04 +#define ISAC_STCR_SC1 0x02 +#define ISAC_STCR_SC0 0x01 + +#define ISAC_ADF1_WTC1 0x80 +#define ISAC_ADF1_WTC2 0x40 +#define ISAC_ADF1_TEM 0x20 +#define ISAC_ADF1_PFS 0x10 +#define ISAC_ADF1_CFS 0x08 +#define ISAC_ADF1_FC2 0x04 +#define ISAC_ADF1_FC1 0x02 +#define ISAC_ADF1_ITF 0x01 + +#define ISAC_ADF2_IMS 0x80 +/* all other bits are 0 */ + +/* bits 7-5 are always 0 */ +#define ISAC_SQRR_SYN 0x10 +#define ISAC_SQRR_SQR1 0x08 +#define ISAC_SQRR_SQR2 0x04 +#define ISAC_SQRR_SQR3 0x02 +#define ISAC_SQRR_SQR4 0x01 + +#define ISAC_SQXR_IDC 0x80 +#define ISAC_SQXR_CFS 0x40 +#define ISAC_SQXR_CI1E 0x20 +#define ISAC_SQXR_SQIE 0x10 +#define ISAC_SQXR_SQX1 0x08 +#define ISAC_SQXR_SQX2 0x04 +#define ISAC_SQXR_SQX3 0x02 +#define ISAC_SQXR_SQX4 0x01 + +#endif /* I4B_ISAC_H_ */ diff --git a/sys/i4b/layer1/i4b_isic.c b/sys/i4b/layer1/i4b_isic.c new file mode 100644 index 000000000000..922df793c07a --- /dev/null +++ b/sys/i4b/layer1/i4b_isic.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isic.c - global isic stuff + * ============================== + * + * $Id: i4b_isic.c,v 1.44 1998/12/20 11:07:59 hm Exp $ + * + * last edit-date: [Fri Dec 18 12:14:07 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <sys/device.h> +#if defined(__NetBSD__) && defined(amiga) +#include <machine/bus.h> +#else +#include <dev/isa/isavar.h> +#endif +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_ipac.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +void isic_settrace(int unit, int val); +int isic_gettrace(int unit); + +#ifdef __FreeBSD__ +void isicintr_sc(struct isic_softc *sc); +#if !(defined(__FreeBSD_version)) || (defined(__FreeBSD_version) && __FreeBSD_version >= 300006) +void isicintr(int unit); +#endif +#else +/* XXX - hack, going away soon! */ +struct isic_softc *isic_sc[ISIC_MAXUNIT]; +#endif + +/*---------------------------------------------------------------------------* + * isic - device driver interrupt routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +void +isicintr_sc(struct isic_softc *sc) +{ + isicintr(sc->sc_unit); +} + +void +isicintr(int unit) +{ + register struct isic_softc *sc = &isic_sc[unit]; +#else +int +isicintr(void *arg) +{ + struct isic_softc *sc = arg; +#endif + + if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ + { + u_char was_hscx_irq = 0; + u_char was_isac_irq = 0; + + register u_char hscx_irq_stat; + register u_char isac_irq_stat; + + for(;;) + { + /* get hscx irq status from hscx b ista */ + hscx_irq_stat = + HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; + + /* get isac irq status */ + isac_irq_stat = ISAC_READ(I_ISTA); + + /* do as long as there are pending irqs in the chips */ + if(!hscx_irq_stat && !isac_irq_stat) + break; + + if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | + HSCX_ISTA_RSC | HSCX_ISTA_XPR | + HSCX_ISTA_TIN | HSCX_ISTA_EXB)) + { + isic_hscx_irq(sc, hscx_irq_stat, + HSCX_CH_B, + hscx_irq_stat & HSCX_ISTA_EXB); + was_hscx_irq = 1; + } + + if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) + { + isic_hscx_irq(sc, + HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, + HSCX_CH_A, + hscx_irq_stat & HSCX_ISTA_EXA); + was_hscx_irq = 1; + } + + if(isac_irq_stat) + { + isic_isac_irq(sc, isac_irq_stat); /* isac handler */ + was_isac_irq = 1; + } + } +#ifndef amiga /* XXX should be: #if INTERUPTS_ARE_SHARED */ +#ifdef ELSA_QS1ISA + if(sc->sc_cardtyp != CARD_TYPEP_ELSAQS1ISA) + { +#endif + if((was_hscx_irq == 0) && (was_isac_irq == 0)) + DBGL1(L1_ERROR, "isicintr", ("WARNING: unit %d, No IRQ from HSCX/ISAC!\n", sc->sc_unit)); +#ifdef ELSA_QS1ISA + } +#endif +#endif /* AMIGA */ + + HSCX_WRITE(0, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + +#ifdef ELSA_QS1ISA + DELAY(80); + + if(sc->sc_cardtyp == CARD_TYPEP_ELSAQS1ISA) + if (sc->clearirq) + { + sc->clearirq(sc); + } +#else + DELAY(100); +#endif + + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); +#ifndef __FreeBSD__ + return(was_hscx_irq || was_isac_irq); +#endif + } + else /* IPAC interrupt routine */ + { + register u_char ipac_irq_stat; + register u_char was_ipac_irq = 0; + + for(;;) + { + /* get global irq status */ + + ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; + + /* check hscx a */ + + if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) + { + /* HSCX A interrupt */ + isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), + HSCX_CH_A, + ipac_irq_stat & IPAC_ISTA_EXA); + was_ipac_irq = 1; + } + if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) + { + /* HSCX B interrupt */ + isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), + HSCX_CH_B, + ipac_irq_stat & IPAC_ISTA_EXB); + was_ipac_irq = 1; + } + if(ipac_irq_stat & (IPAC_ISTA_ICD | IPAC_ISTA_EXD)) + { + /* ISAC interrupt */ + isic_isac_irq(sc, ISAC_READ(I_ISTA)); + was_ipac_irq = 1; + } + + /* do as long as there are pending irqs in the chip */ + if(!ipac_irq_stat) + break; + } + + if(was_ipac_irq == 0) + DBGL1(L1_ERROR, "isicintr", ("WARNING: unit %d, No IRQ from IPAC!\n", sc->sc_unit)); + + IPAC_WRITE(IPAC_MASK, 0xff); + DELAY(50); + IPAC_WRITE(IPAC_MASK, 0xc0); + +#ifndef __FreeBSD__ + return(was_ipac_irq); +#endif + } +} + +/*---------------------------------------------------------------------------* + * isic_settrace + *---------------------------------------------------------------------------*/ +void +isic_settrace(int unit, int val) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + sc->sc_trace = val; +} + +/*---------------------------------------------------------------------------* + * isic_gettrace + *---------------------------------------------------------------------------*/ +int +isic_gettrace(int unit) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + return(sc->sc_trace); +} + +/*---------------------------------------------------------------------------* + * isic_recovery - try to recover from irq lockup + *---------------------------------------------------------------------------*/ +void +isic_recover(struct isic_softc *sc) +{ + u_char byte; + + /* get hscx irq status from hscx b ista */ + + byte = HSCX_READ(HSCX_CH_B, H_ISTA); + + DBGL1(L1_ERROR, "isic_recover", ("HSCX B: ISTA = 0x%x\n", byte)); + + if(byte & HSCX_ISTA_ICA) + DBGL1(L1_ERROR, "isic_recover", ("HSCX A: ISTA = 0x%x\n", (u_char)HSCX_READ(HSCX_CH_A, H_ISTA))); + + if(byte & HSCX_ISTA_EXB) + DBGL1(L1_ERROR, "isic_recover", ("HSCX B: EXIR = 0x%x\n", (u_char)HSCX_READ(HSCX_CH_B, H_EXIR))); + + if(byte & HSCX_ISTA_EXA) + DBGL1(L1_ERROR, "isic_recover", ("HSCX A: EXIR = 0x%x\n", (u_char)HSCX_READ(HSCX_CH_A, H_EXIR))); + + /* get isac irq status */ + + byte = ISAC_READ(I_ISTA); + + DBGL1(L1_ERROR, "isic_recover", (" ISAC: ISTA = 0x%x\n", byte)); + + if(byte & ISAC_ISTA_EXI) + DBGL1(L1_ERROR, "isic_recover", (" ISAC: EXIR = 0x%x\n", (u_char)ISAC_READ(I_EXIR))); + + if(byte & ISAC_ISTA_CISQ) + { + byte = ISAC_READ(I_CIRR); + + DBGL1(L1_ERROR, "isic_recover", (" ISAC: CISQ = 0x%x\n", byte)); + + if(byte & ISAC_CIRR_SQC) + DBGL1(L1_ERROR, "isic_recover", (" ISAC: SQRR = 0x%x\n", (u_char)ISAC_READ(I_SQRR))); + } + + DBGL1(L1_ERROR, "isic_recover", ("HSCX B: IMASK = 0x%x\n", HSCX_B_IMASK)); + DBGL1(L1_ERROR, "isic_recover", ("HSCX A: IMASK = 0x%x\n", HSCX_A_IMASK)); + + HSCX_WRITE(0, H_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + DELAY(100); + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + DELAY(100); + + DBGL1(L1_ERROR, "isic_recover", (" ISAC: IMASK = 0x%x\n", ISAC_IMASK)); + + ISAC_WRITE(I_MASK, 0xff); + DELAY(100); + ISAC_WRITE(I_MASK, ISAC_IMASK); +} + +#endif /* NISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_isic_isa.c b/sys/i4b/layer1/i4b_isic_isa.c new file mode 100644 index 000000000000..c0e11b9a044f --- /dev/null +++ b/sys/i4b/layer1/i4b_isic_isa.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isic_isa.c - ISA bus interface + * ================================== + * + * $Id: i4b_isic_isa.c,v 1.14 1998/12/20 11:07:59 hm Exp $ + * + * last edit-date: [Fri Dec 18 12:00:26 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <sys/device.h> +#if defined(__NetBSD__) && defined(amiga) +#include <machine/bus.h> +#else +#include <dev/isa/isavar.h> +#endif +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_ipac.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#ifdef __FreeBSD__ + +#if !(defined(__FreeBSD_version)) || (defined(__FreeBSD_version) && __FreeBSD_version >= 300006) +void isicintr ( int unit ); +#endif + +void isicintr_sc(struct isic_softc *sc); + +static int isicprobe(struct isa_device *dev); +int isicattach(struct isa_device *dev); + +struct isa_driver isicdriver = { + isicprobe, + isicattach, + "isic", + 0 +}; + +int next_isic_unit = 0; +struct isic_softc isic_sc[ISIC_MAXUNIT]; + +#else + +#ifdef NetBSD1_3 +#if NetBSD1_3 < 2 +struct cfdriver isic_cd = { + NULL, "isic", DV_DULL +}; +#endif +#endif + +#if defined (__OpenBSD__) +struct cfdriver isic_cd = { + NULL, "isic", DV_DULL +}; +#endif + +#endif + +/* parameter and format for message producing e.g. "isic0: " */ + +#ifdef __FreeBSD__ +#define ISIC_FMT "isic%d: " +#define ISIC_PARM dev->id_unit +#define TERMFMT " " +#else +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" +#endif + +extern void isic_settrace(int unit, int val); /*XXX*/ +extern int isic_gettrace(int unit); /*XXX*/ + +#ifdef __FreeBSD__ +/*---------------------------------------------------------------------------* + * isic - non-pnp device driver probe routine + *---------------------------------------------------------------------------*/ +static int +isicprobe(struct isa_device *dev) +{ + int ret = 0; + + if(dev->id_unit != next_isic_unit) + { + printf("isicprobe: Error: new unit (%d) != next_isic_unit (%d)!\n", dev->id_unit, next_isic_unit); + return(0); + } + + switch(dev->id_flags) + { +#ifdef TEL_S0_8 + case FLAG_TELES_S0_8: + ret = isic_probe_s08(dev); + break; +#endif + +#ifdef TEL_S0_16 + case FLAG_TELES_S0_16: + ret = isic_probe_s016(dev); + break; +#endif + +#ifdef TEL_S0_16_3 + case FLAG_TELES_S0_163: + ret = isic_probe_s0163(dev); + break; +#endif + +#ifdef AVM_A1 + case FLAG_AVM_A1: + ret = isic_probe_avma1(dev); + break; +#endif + +#ifdef USR_STI + case FLAG_USR_ISDN_TA_INT: + ret = isic_probe_usrtai(dev); + break; +#endif + +#ifdef ITKIX1 + case FLAG_ITK_IX1: + ret = isic_probe_itkix1(dev); + break; +#endif + + default: + break; + } + return(ret); +} + +#else + +/*---------------------------------------------------------------------------* + * isic - device driver probe routine, dummy for NetBSD/OpenBSD + *---------------------------------------------------------------------------*/ +int +isicprobe(struct isic_attach_args *args) +{ + return 1; +} + +#endif /* __FreeBSD__ */ + +#ifdef __FreeBSD__ + +/*---------------------------------------------------------------------------* + * isic - non-pnp device driver attach routine + *---------------------------------------------------------------------------*/ +int +isicattach(struct isa_device *dev) +{ + return(isic_realattach(dev, 0)); +} + +/*---------------------------------------------------------------------------* + * isic - non-pnp and pnp device driver attach routine + *---------------------------------------------------------------------------*/ +int +isic_realattach(struct isa_device *dev, unsigned int iobase2) + +#else /* ! __FreeBSD__ */ + +int +isicattach(int flags, struct isic_softc *sc) + +#endif /* __FreeBSD__ */ +{ + int ret = 0; + char *drvid; + +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[dev->id_unit]; +#define PARM dev +#define PARM2 dev, iobase2 +#define FLAGS dev->id_flags +#else +#define PARM sc +#define PARM2 sc +#define FLAGS flags +#endif + + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + /* done in bus specific attach code for other OS */ + +#ifdef __FreeBSD__ + if(dev->id_unit != next_isic_unit) + { + printf("isicattach: Error: new unit (%d) != next_isic_unit (%d)!\n", dev->id_unit, next_isic_unit); + return(0); + } + + sc->sc_unit = dev->id_unit; +#else + isic_sc[sc->sc_unit] = sc; +#endif + + /* card dependent setup */ + switch(FLAGS) + { +#ifdef DYNALINK + case FLAG_DYNALINK: + ret = isic_attach_Dyn(PARM2); + break; +#endif + +#ifdef TEL_S0_8 + case FLAG_TELES_S0_8: + ret = isic_attach_s08(PARM); + break; +#endif + +#ifdef TEL_S0_16 + case FLAG_TELES_S0_16: + ret = isic_attach_s016(PARM); + break; +#endif + +#ifdef TEL_S0_16_3 + case FLAG_TELES_S0_163: + ret = isic_attach_s0163(PARM); + break; +#endif + +#ifdef AVM_A1 + case FLAG_AVM_A1: + ret = isic_attach_avma1(PARM); + break; +#endif + +#ifdef USR_STI + case FLAG_USR_ISDN_TA_INT: + ret = isic_attach_usrtai(PARM); + break; +#endif + +#ifdef ITKIX1 + case FLAG_ITK_IX1: + ret = isic_attach_itkix1(PARM); + break; +#endif + +/* ====================================================================== + * Only P&P cards follow below!!! + */ +#ifdef __FreeBSD__ /* we've already splitted all non-ISA stuff + out of this ISA specific part for the other + OS */ + +#ifdef AVM_PCMCIA + case FLAG_AVM_A1_PCMCIA: + ret = isic_attach_fritzpcmcia(PARM); + break; +#endif + +#ifndef __FreeBSD__ +#ifdef TEL_S0_16_3_P + case FLAG_TELES_S0_163_PnP: + ret = isic_attach_s0163P(PARM2); + break; +#endif +#endif + +#ifdef CRTX_S0_P + case FLAG_CREATIX_S0_PnP: + ret = isic_attach_Cs0P(PARM2); + break; +#endif + +#ifdef DRN_NGO + case FLAG_DRN_NGO: + ret = isic_attach_drnngo(PARM2); + break; +#endif + +#ifdef SEDLBAUER + case FLAG_SWS: + ret = isic_attach_sws(PARM); + break; +#endif + +#ifdef ELSA_QS1ISA + case FLAG_ELSA_QS1P_ISA: + ret = isic_attach_Eqs1pi(PARM2); + break; +#endif + +#endif /* __FreeBSD__ / P&P specific part */ + +/* --- XXX - don't know how to handle this - should be removed!!!! ---- */ +#ifdef amiga + case FLAG_BLMASTER: + ret = 1; /* full detection was done in caller */ + break; +#endif +/* ------------------------------------------------------------------- */ + + default: + break; + } + + if(ret == 0) + return(0); + + sc->sc_isac_version = 0; + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return(0); + break; + }; + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce manufacturer and card type */ + + switch(FLAGS) + { + case FLAG_TELES_S0_8: + drvid = "Teles S0/8 or Niccy 1008"; + break; + + case FLAG_TELES_S0_16: + drvid = "Teles S0/16, Creatix ISDN S0-16 or Niccy 1016"; + break; + + case FLAG_TELES_S0_163: + drvid = "Teles S0/16.3"; + break; + + case FLAG_AVM_A1: + drvid = "AVM A1 or AVM Fritz!Card"; + break; + + case FLAG_AVM_A1_PCMCIA: + drvid = "AVM PCMCIA Fritz!Card"; + break; + + case FLAG_TELES_S0_163_PnP: + drvid = "Teles S0/PnP"; + break; + + case FLAG_CREATIX_S0_PnP: + drvid = "Creatix ISDN S0-16 P&P"; + break; + + case FLAG_USR_ISDN_TA_INT: + drvid = "USRobotics Sportster ISDN TA intern"; + break; + + case FLAG_DRN_NGO: + drvid = "Dr. Neuhaus NICCY Go@"; + break; + + case FLAG_DYNALINK: + drvid = "Dynalink IS64PH"; + break; + + case FLAG_SWS: + drvid = "Sedlbauer WinSpeed"; + break; + + case FLAG_BLMASTER: + /* board announcement was done by caller */ + drvid = (char *)0; + break; + + case FLAG_ELSA_QS1P_ISA: + drvid = "ELSA QuickStep 1000pro (ISA)"; + break; + + case FLAG_ITK_IX1: + drvid = "ITK ix1 micro"; + break; + + default: + drvid = "ERROR, unknown flag used"; + break; + } +#ifndef __FreeBSD__ + printf("\n"); +#endif + if (drvid) + printf(ISIC_FMT "%s\n", ISIC_PARM, drvid); + + /* announce chip versions */ + + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + +#ifdef __FreeBSD__ + printf("(Addr=0x%lx)\n", (u_long)ISAC_BASE); +#endif + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } + +#ifdef __FreeBSD__ + printf("(AddrA=0x%lx, AddrB=0x%lx)\n", (u_long)HSCX_A_BASE, (u_long)HSCX_B_BASE); + + next_isic_unit++; + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300003 + + /* set the interrupt handler - no need to change isa_device.h */ + dev->id_intr = (inthand2_t *)isicintr; + +#endif + +#endif /* __FreeBSD__ */ + + return(1); +#undef PARM +#undef FLAGS +} + +#endif /* NISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_isic_pci.c b/sys/i4b/layer1/i4b_isic_pci.c new file mode 100644 index 000000000000..3aebf08c796e --- /dev/null +++ b/sys/i4b/layer1/i4b_isic_pci.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isic_pci.c - PCI bus interface + * ================================== + * + * $Id: i4b_isic_pci.c,v 1.9 1998/12/05 18:04:48 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:24:36 1998] + * + *---------------------------------------------------------------------------*/ + +#include "isic.h" + +#if defined(__FreeBSD__) +#include "opt_i4b.h" +#include "pci.h" +#endif + +#if (NISIC > 0) && (NPCI > 0) + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#if __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <pci/pcireg.h> +#include <pci/pcivar.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_ipac.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#define PCI_QS1000_ID 0x10001048 + +#define MEM0_MAPOFF 0 +#define PORT0_MAPOFF 4 +#define PORT1_MAPOFF 12 + +static char* i4b_pci_probe(pcici_t tag, pcidi_t type); +static void i4b_pci_attach(pcici_t config_id, int unit); +static int isic_pciattach(int unit, u_long type, u_int iobase1, u_int iobase2); + +static u_long i4b_pci_count = 0; + +static struct pci_device i4b_pci_driver = { + "isic", + i4b_pci_probe, + i4b_pci_attach, + &i4b_pci_count, + NULL +}; + +DATA_SET (pcidevice_set, i4b_pci_driver); + +static void isic_pci_intr_sc(struct isic_softc *sc); + + +/*---------------------------------------------------------------------------* + * PCI probe routine + *---------------------------------------------------------------------------*/ +static char * +i4b_pci_probe(pcici_t tag, pcidi_t type) +{ + switch(type) + { + case PCI_QS1000_ID: + return("ELSA QuickStep 1000pro PCI ISDN adaptor"); + break; + + default: + if(bootverbose) + printf("i4b_pci_probe: unknown PCI type %ul!\n", (u_int)type); + return(NULL); + } + return(NULL); +} + +/*---------------------------------------------------------------------------* + * PCI attach routine + *---------------------------------------------------------------------------*/ +static void +i4b_pci_attach(pcici_t config_id, int unit) +{ + unsigned short iobase1; + unsigned short iobase2; + unsigned long type; + struct isic_softc *sc = &isic_sc[unit]; + + if(unit != next_isic_unit) + { + printf("i4b_pci_attach: Error: new unit (%d) != next_isic_unit (%d)!\n", unit, next_isic_unit); + return; + } + + if(!(pci_map_port(config_id, PCI_MAP_REG_START+PORT0_MAPOFF, &iobase1))) + { + printf("i4b_pci_attach: pci_map_port 1 failed!\n"); + return; + } + + if(!(pci_map_port(config_id, PCI_MAP_REG_START+PORT1_MAPOFF, &iobase2))) + { + printf("i4b_pci_attach: pci_map_port 2 failed!\n"); + return; + } + + if(bootverbose) + printf("i4b_pci_attach: unit %d, port0 0x%x, port1 0x%x\n", unit, iobase1, iobase2); + + type = pci_conf_read(config_id, PCI_ID_REG); + + if((isic_pciattach(unit, type, iobase1, iobase2)) == 0) + return; + + if(!(pci_map_int(config_id, (void *)isic_pci_intr_sc, (void *)sc, &net_imask))) + return; +} + +/*---------------------------------------------------------------------------* + * isic - pci device driver attach routine + *---------------------------------------------------------------------------*/ +static int +isic_pciattach(int unit, u_long type, u_int iobase1, u_int iobase2) +{ + int ret = 0; + struct isic_softc *sc = &isic_sc[unit]; + + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + switch(type) + { +#ifdef ELSA_QS1PCI + case PCI_QS1000_ID: + ret = isic_attach_Eqs1pp(unit, iobase1, iobase2); + break; +#endif + default: + break; + } + + if(ret == 0) + return(ret); + + sc->sc_isac_version = 0; + sc->sc_hscx_version = 0; + + sc->sc_unit = unit; + + if(sc->sc_ipac) + { + ret = IPAC_READ(IPAC_ID); + + switch(ret) + { + case 0x01: + printf("isic%d: IPAC PSB2115 Version 1.1\n", unit); + break; + + default: + printf("isic%d: Error, IPAC version %d unknown!\n", + unit, ret); + return(0); + break; + } + } + else + { + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + printf("isic%d: ISAC %s (IOM-%c)\n", + unit, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + break; + + default: + printf("isic%d: Error, ISAC version %d unknown!\n", + unit, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + printf("isic%d: HSCX %s\n", + unit, + HSCXversion[sc->sc_hscx_version]); + break; + + default: + printf("isic%d: Error, HSCX version %d unknown!\n", + unit, sc->sc_hscx_version); + return(0); + break; + } + } + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + next_isic_unit++; + + return(1); +} + +/*---------------------------------------------------------------------------* + * isic - PCI device driver interrupt routine + *---------------------------------------------------------------------------*/ +static void +isic_pci_intr_sc(struct isic_softc *sc) +{ + if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ + { + register u_char hscx_irq_stat; + register u_char isac_irq_stat; + + for(;;) + { + /* get hscx irq status from hscx b ista */ + hscx_irq_stat = + HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; + + /* get isac irq status */ + isac_irq_stat = ISAC_READ(I_ISTA); + + /* do as long as there are pending irqs in the chips */ + if(!hscx_irq_stat && !isac_irq_stat) + break; + + if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | + HSCX_ISTA_RSC | HSCX_ISTA_XPR | + HSCX_ISTA_TIN | HSCX_ISTA_EXB)) + { + isic_hscx_irq(sc, hscx_irq_stat, + HSCX_CH_B, + hscx_irq_stat & HSCX_ISTA_EXB); + } + + if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) + { + isic_hscx_irq(sc, + HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, + HSCX_CH_A, + hscx_irq_stat & HSCX_ISTA_EXA); + } + + if(isac_irq_stat) + { /* isac handler */ + isic_isac_irq(sc, isac_irq_stat); + } + } + + HSCX_WRITE(0, H_MASK, 0xff); + ISAC_WRITE(I_MASK, 0xff); + HSCX_WRITE(1, H_MASK, 0xff); + + DELAY(100); + + HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); + ISAC_WRITE(I_MASK, ISAC_IMASK); + HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); + } + else /* IPAC interrupt routine */ + { + register u_char ipac_irq_stat; + + for(;;) + { + /* get global irq status */ + + ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; + + /* do as long as there are pending irqs in the chip */ + if(!ipac_irq_stat) + break; + + /* check hscx a */ + + if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) + { + /* HSCX A interrupt */ + isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), + HSCX_CH_A, + ipac_irq_stat & IPAC_ISTA_EXA); + } + if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) + { + /* HSCX B interrupt */ + isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), + HSCX_CH_B, + ipac_irq_stat & IPAC_ISTA_EXB); + } + if(ipac_irq_stat & (IPAC_ISTA_ICD | IPAC_ISTA_EXD)) + { + /* ISAC interrupt */ + isic_isac_irq(sc, ISAC_READ(I_ISTA)); + } + } + + IPAC_WRITE(IPAC_MASK, 0xff); + DELAY(50); + IPAC_WRITE(IPAC_MASK, 0xc0); + } +} + +#endif /* (NISIC > 0) && (NPCI > 0) */ + diff --git a/sys/i4b/layer1/i4b_isic_pcmcia.c b/sys/i4b/layer1/i4b_isic_pcmcia.c new file mode 100644 index 000000000000..a1fb22af6206 --- /dev/null +++ b/sys/i4b/layer1/i4b_isic_pcmcia.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 1998 Matthias Apitz. All rights reserved. + * + * Copyright (c) 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isic_pcmcia.c - i4b FreeBSD PCMCIA support + * ---------------------------------------------- + * + * $Id: i4b_isic_pcmcia.c,v 1.3 1998/12/16 09:32:50 hm Exp $ + * + * last edit-date: [Mon Dec 14 17:30:09 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +#include "isic.h" +#include "opt_i4b.h" +#include "card.h" + +#if (NISIC > 0) && (NCARD > 0) + +#include "apm.h" +#include <sys/param.h> +#include <sys/select.h> +#include <i386/isa/isa_device.h> + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <machine/clock.h> +#include <i386/isa/isa_device.h> + +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> + +#include <pccard/cardinfo.h> +#include <pccard/slot.h> +#include <pccard/driver.h> + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +/* + * PC-Card (PCMCIA) specific code. + */ +static int isic_pccard_init __P((struct pccard_devinfo *)); +static void isic_unload __P((struct pccard_devinfo *)); +static int isic_card_intr __P((struct pccard_devinfo *)); + +static struct pccard_device isic_info = { + "isic", + isic_pccard_init, + isic_unload, + isic_card_intr, + 0, /* Attributes - presently unused */ + &net_imask +}; + +DATA_SET(pccarddrv_set, isic_info); + +/* + * Initialize the device - called from Slot manager. + */ + +static int opened = 0; /* our cards status */ + +static int isic_pccard_init(devi) +struct pccard_devinfo *devi; +{ + struct isa_device *is = &devi->isahd; + struct isic_softc *sc = &isic_sc[is->id_unit]; + + if ((1 << is->id_unit) & opened) + return(EBUSY); + + opened |= 1 << is->id_unit; + printf("isic%d: PCMCIA init, irqmask = 0x%x (%d), iobase = 0x%x\n", + is->id_unit, is->id_irq, devi->slt->irq, is->id_iobase); + +#if 0 + /* XXX: problems resolving isic_probe_avma1_pcmcia() /phk */ + /* + * look if there is really an AVM PCMCIA Fritz!Card and + * setup the card specific stuff + */ + isic_probe_avma1_pcmcia(is); +#endif + + /* ap: + * XXX what's to do with the return value? + */ + + /* + * try to attach the PCMCIA card as a normal A1 card + */ + isicattach(is); + return(0); +} + +static void isic_unload(devi) +struct pccard_devinfo *devi; +{ + struct isa_device *is = &devi->isahd; + printf("isic%d: unloaded\n", is->id_unit); + opened &= ~(1 << is->id_unit); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int isic_card_intr(devi) +struct pccard_devinfo *devi; +{ + isicintr(devi->isahd.id_unit); + return(1); +} + +#endif /* (NISIC > 0) && (NCARD > 0) */ +#endif /* __FreeBSD__ */ diff --git a/sys/i4b/layer1/i4b_isic_pnp.c b/sys/i4b/layer1/i4b_isic_pnp.c new file mode 100644 index 000000000000..ed1892d9088f --- /dev/null +++ b/sys/i4b/layer1/i4b_isic_pnp.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 1998 Eivind Eklund. All rights reserved. + * + * Copyright (c) 1998 German Tischler. All rights reserved. + * + * Copyright (c) 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_isic_pnp.c - i4b pnp support + * -------------------------------- + * + * $Id: i4b_isic_pnp.c,v 1.15 1998/12/20 11:07:59 hm Exp $ + * + * last edit-date: [Fri Dec 18 20:54:56 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +#include "pnp.h" +#include "isic.h" +#include "opt_i4b.h" + +#if (NISIC > 0) && (NPNP > 0) + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <net/if.h> + +#if defined(__FreeBSD__) && __FreeBSD__ < 3 +#include "ioconf.h" +extern void isicintr(int unit); /* XXX this gives a compiler warning */ + /* on one 2.2.7 machine but no */ + /* warning on another one !? (-hm) */ +#endif + +#if (defined(__FreeBSD_version) && __FreeBSD_version >= 300006) +extern void isicintr(int unit); +#endif + +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#include <i386/isa/pnp.h> + +#include <i4b/include/i4b_global.h> +#include <machine/i4b_ioctl.h> +#include <i4b/layer1/i4b_l1.h> + +#define VID_TEL163PNP 0x10212750 /* Teles 16.3 PnP */ +#define VID_CREATIXPP 0x0000980e /* Creatix S0/16 P+P */ +#define VID_DYNALINK 0x88167506 /* Dynalink */ +#define VID_SEDLBAUER 0x0100274c /* Sedlbauer WinSpeed */ +#define VID_NICCYGO 0x5001814c /* Neuhaus Niccy GO@ */ +#define VID_ELSAQS1P 0x33019315 /* ELSA Quickstep1000pro*/ + +static struct i4b_pnp_ids { + u_long vend_id; + char *id_str; +} i4b_pnp_ids[] = { + { VID_TEL163PNP, "Teles 16.3 PnP" }, + { VID_CREATIXPP, "Creatix S0/16 P+P" }, + { VID_DYNALINK, "Dynalink IS64PH" }, + { VID_SEDLBAUER, "Sedlbauer WinSpeed" }, + { VID_NICCYGO, "Dr.Neuhaus Niccy Go@" }, + { VID_ELSAQS1P, "ELSA QuickStep 1000pro"}, + { 0 } +}; + +extern struct isa_driver isicdriver; + +static int isic_pnpprobe(struct isa_device *dev, unsigned int iobase2); +static char *i4b_pnp_probe(u_long csn, u_long vend_id); +static void i4b_pnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev); + +static u_long ni4b_pnp = 0; + +static struct pnp_device i4b_pnp = { + "i4b_pnp", + i4b_pnp_probe, + i4b_pnp_attach, + &ni4b_pnp, + &net_imask +}; + +DATA_SET(pnpdevice_set, i4b_pnp); + +/*---------------------------------------------------------------------------* + * PnP probe routine + *---------------------------------------------------------------------------*/ +static char * +i4b_pnp_probe(u_long csn, u_long vend_id) +{ + struct i4b_pnp_ids *ids; + char *string = NULL; + + /* search table of knowd id's */ + + for(ids = i4b_pnp_ids; ids->vend_id != 0; ids++) + { + if(vend_id == ids->vend_id) + { + string = ids->id_str; + break; + } + } + + if(string) + { + struct pnp_cinfo spci; + + read_pnp_parms(&spci, 0); + + if((spci.enable == 0) || (spci.flags & 0x01)) + { + printf("CSN %d (%s) is disabled.\n", (int)csn, string); + return (NULL); + } + } + return(string); +} + +/*---------------------------------------------------------------------------* + * PnP attach routine + *---------------------------------------------------------------------------*/ +static void +i4b_pnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev) +{ + struct pnp_cinfo spci; + struct isa_device *isa_devp; + + if(dev->id_unit != next_isic_unit) + { + printf("i4b_pnp_attach: Error: new unit (%d) != next_isic_unit (%d)!\n", dev->id_unit, next_isic_unit); + return; + } + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for %s\n", + dev->id_unit, dev->id_unit, name); + return; + } + + if(read_pnp_parms(&spci, 0) == 0) + { + printf("isic%d: read_pnp_parms error for %s\n", + dev->id_unit, name); + return; + } + + if(bootverbose) + { + printf("isic%d: vendorid = 0x%08x port0 = 0x%04x, port1 = 0x%04x, irq = %d\n", + dev->id_unit, spci.vendor_id, spci.port[0], spci.port[1], spci.irq[0]); + } + + dev->id_iobase = spci.port[0]; + dev->id_irq = (1 << spci.irq[0]); + dev->id_intr = (inthand2_t *) isicintr; + dev->id_drq = -1; + +/* XXX add dev->id_alive init here ! ?? */ + + switch(spci.vendor_id) + { + case VID_TEL163PNP: + dev->id_flags = FLAG_TELES_S0_163_PnP; + break; + case VID_CREATIXPP: + dev->id_flags = FLAG_CREATIX_S0_PnP; + break; + case VID_DYNALINK: + dev->id_flags = FLAG_DYNALINK; + break; + case VID_SEDLBAUER: + dev->id_flags = FLAG_SWS; + break; + case VID_NICCYGO: + dev->id_flags = FLAG_DRN_NGO; + break; + case VID_ELSAQS1P: + dev->id_flags = FLAG_ELSA_QS1P_ISA; + break; + } + + write_pnp_parms(&spci, 0); + enable_pnp_card(); + + if(dev->id_driver == NULL) + { + dev->id_driver = &isicdriver; + + isa_devp = find_isadev(isa_devtab_net, &isicdriver, 0); + + if(isa_devp != NULL) + { + dev->id_id = isa_devp->id_id; + } + } + + if((dev->id_alive = isic_pnpprobe(dev, spci.port[1])) != 0) + { +/* XXX dev->id_alive is the size of the port area used ! */ + isic_realattach(dev, spci.port[1]); + } + else + { + printf("isic%d: probe failed!\n", dev->id_unit); + } +} + +/*---------------------------------------------------------------------------* + * isic - pnp device driver probe routine + *---------------------------------------------------------------------------*/ +static int +isic_pnpprobe(struct isa_device *dev, unsigned int iobase2) +{ + int ret = 0; + + switch(dev->id_flags) + { +#ifndef __FreeBSD__ +#ifdef TEL_S0_16_3_P + case FLAG_TELES_S0_163_PnP: + ret = isic_probe_s0163P(dev, iobase2); + break; +#endif +#endif + +#ifdef CRTX_S0_P + case FLAG_CREATIX_S0_PnP: + ret = isic_probe_Cs0P(dev, iobase2); + break; +#endif + +#ifdef DRN_NGO + case FLAG_DRN_NGO: + ret = isic_probe_drnngo(dev, iobase2); + break; +#endif + +#ifdef SEDLBAUER + case FLAG_SWS: + ret = 8; /* pnp only, nothing to probe */ + break; +#endif + +#ifdef DYNALINK + case FLAG_DYNALINK: + ret = isic_probe_Dyn(dev, iobase2); + break; +#endif + +#ifdef ELSA_QS1ISA + case FLAG_ELSA_QS1P_ISA: + ret = isic_probe_Eqs1pi(dev, iobase2); + break; +#endif + default: + break; + } + return(ret); +} + +#endif /* (NISIC > 0) && (NPNP > 0) */ +#endif /* __FreeBSD__ */ diff --git a/sys/i4b/layer1/i4b_itk_ix1.c b/sys/i4b/layer1/i4b_itk_ix1.c new file mode 100644 index 000000000000..f7491cd0b62a --- /dev/null +++ b/sys/i4b/layer1/i4b_itk_ix1.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 1998 Martin Husemann <martin@rumolt.teuto.de> + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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_itk_ix1.c - ITK ix1 micro passive card driver for isdn4bsd + * -------------------------------------------------------------- + * + * $Id: i4b_itk_ix1.c,v 1.1 1998/12/16 13:43:20 hm Exp $ + * + * last edit-date: [Wed Dec 16 14:46:36 1998] + * + *--------------------------------------------------------------------------- + * + * The ITK ix1 micro ISDN card is an ISA card with one region + * of four io ports mapped and a fixed irq all jumpered on the card. + * Access to the board is straight forward and simmilar to + * the ELSA and DYNALINK cards. If a PCI version of this card + * exists all we need is probably a pci-bus attachment, all + * this low level routines should work imediately. + * + * To reset the card: + * - write 0x01 to ITK_CONFIG + * - wait >= 10 ms + * - write 0x00 to ITK_CONFIG + * + * To read or write data: + * - write address to ITK_ALE port + * - read data from or write data to ITK_ISAC_DATA port or ITK_HSCX_DATA port + * The two HSCX channel registers are offset by HSCXA (0x00) and HSCXB (0x40). + * + * XXX - A reasonable probe routine has to be written. + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(ITKIX1) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> + +#define ITK_ISAC_DATA 0 +#define ITK_HSCX_DATA 1 +#define ITK_ALE 2 +#define ITK_CONFIG 3 +#define ITK_IO_SIZE 4 + +#define HSCXA 0 +#define HSCXB 0x40 + +#ifndef __FreeBSD__ +static void itkix1_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size); +static void itkix1_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size); +static void itkix1_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data); +static u_int8_t itkix1_read_reg(struct isic_softc *sc, int what, bus_size_t offs); +#else +static u_char itkix1_read_reg(u_char *base, u_int offset); +static void itkix1_write_reg(u_char *base, u_int offset, u_int v); +static void itkix1_read_fifo(void *base, const void *buf, size_t len); +static void itkix1_write_fifo(void *base, const void *buf, size_t len); +#endif + +/* + * Probe for card + */ +#ifdef __FreeBSD__ +int +isic_probe_itkix1(struct isa_device *dev) +{ + u_int8_t hd, cd; + int ret; + + hd = inb(dev->id_iobase + ITK_HSCX_DATA); + cd = inb(dev->id_iobase + ITK_CONFIG); + + ret = (hd == 0 && cd == 0xfc); + +#define ITK_PROBE_DEBUG +#ifdef ITK_PROBE_DEBUG + printf("\nITK ix1 micro probe: hscx = 0x%02x, config = 0x%02x, would have %s\n", + hd, cd, ret ? "succeeded" : "failed"); + return 1; +#else + return ret; +#endif +} +#else +int +isic_probe_itkix1(struct isic_attach_args *ia) +{ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t hd, cd; + int ret; + + hd = bus_space_read_1(t, h, ITK_HSCX_DATA); + cd = bus_space_read_1(t, h, ITK_CONFIG); + + ret = (hd == 0 && cd == 0xfc); + +#define ITK_PROBE_DEBUG +#ifdef ITK_PROBE_DEBUG + printf("\nITK ix1 micro probe: hscx = 0x%02x, config = 0x%02x, would have %s\n", + hd, cd, ret ? "succeeded" : "failed"); + return 1; +#else + return ret; +#endif +} +#endif + +/* + * Attach card + */ +#ifdef __FreeBSD__ +int +isic_attach_itkix1(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + sc->sc_irq = dev->id_irq; + + dev->id_msize = 0; + + /* check if we got an iobase */ + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = itkix1_read_reg; + sc->writereg = itkix1_write_reg; + sc->readfifo = itkix1_read_fifo; + sc->writefifo = itkix1_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_ITKIX1; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + ISAC_BASE = (caddr_t) sc->sc_port; + HSCX_A_BASE = (caddr_t) sc->sc_port + 1; + HSCX_B_BASE = (caddr_t) sc->sc_port + 2; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for ITK ix1 micro\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + outb((dev->id_iobase)+ITK_CONFIG, 1); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase)+ITK_CONFIG, 0); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else + +int isic_attach_itkix1(struct isic_softc *sc) +{ + /* setup access routines */ + sc->clearirq = NULL; + sc->readreg = itkix1_read_reg; + sc->writereg = itkix1_write_reg; + sc->readfifo = itkix1_read_fifo; + sc->writefifo = itkix1_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_ITKIX1; + + /* setup IOM bus type */ + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */ + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("%s: HSCX VSTR test failed for ITK ix1 micro\n", + sc->sc_dev.dv_xname); + printf("%s: HSC0: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR)); + printf("%s: HSC1: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR)); + return 0; + } + + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ITK_CONFIG, 1); + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ITK_CONFIG, 0); + DELAY(SEC_DELAY / 10); + return 1; +} + +#endif + +#ifdef __FreeBSD__ +static void +itkix1_read_fifo(void *buf, const void *base, size_t len) +{ + int port = (u_long)base & ~0x0003; + switch ((u_long)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, 0); + insb(port+ITK_ISAC_DATA, (u_char *)buf, (u_int)len); + break; + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA); + insb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB); + insb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + } +} +#else +static void +itkix1_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, 0); + bus_space_read_multi_1(t, h, ITK_ISAC_DATA, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA); + bus_space_read_multi_1(t, h, ITK_HSCX_DATA, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB); + bus_space_read_multi_1(t, h, ITK_HSCX_DATA, buf, size); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static void +itkix1_write_fifo(void *base, const void *buf, size_t len) +{ + int port = (u_long)base & ~0x0003; + switch ((u_long)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, 0); + outsb(port+ITK_ISAC_DATA, (u_char *)buf, (u_int)len); + break; + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA); + outsb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB); + outsb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len); + break; + } +} +#else +static void itkix1_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, 0); + bus_space_write_multi_1(t, h, ITK_ISAC_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA); + bus_space_write_multi_1(t, h, ITK_HSCX_DATA, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB); + bus_space_write_multi_1(t, h, ITK_HSCX_DATA, (u_int8_t*)buf, size); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static void +itkix1_write_reg(u_char *base, u_int offset, u_int v) +{ + int port = (u_long)base & ~0x0003; + switch ((u_long)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, offset); + outb(port+ITK_ISAC_DATA, (u_char)v); + break; + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA+offset); + outb(port+ITK_HSCX_DATA, (u_char)v); + break; + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB+offset); + outb(port+ITK_HSCX_DATA, (u_char)v); + break; + } +} +#else +static void itkix1_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, offs); + bus_space_write_1(t, h, ITK_ISAC_DATA, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA+offs); + bus_space_write_1(t, h, ITK_HSCX_DATA, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB+offs); + bus_space_write_1(t, h, ITK_HSCX_DATA, data); + break; + } +} +#endif + +#ifdef __FreeBSD__ +static u_char +itkix1_read_reg(u_char *base, u_int offset) +{ + int port = (u_long)base & ~0x0003; + switch ((u_long)base & 3) { + case 0: /* ISAC */ + outb(port+ITK_ALE, offset); + return (inb(port+ITK_ISAC_DATA)); + case 1: /* HSCXA */ + outb(port+ITK_ALE, HSCXA+offset); + return (inb(port+ITK_HSCX_DATA)); + case 2: /* HSCXB */ + outb(port+ITK_ALE, HSCXB+offset); + return (inb(port+ITK_HSCX_DATA)); + } +} +#else +static u_int8_t itkix1_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, ITK_ALE, offs); + return bus_space_read_1(t, h, ITK_ISAC_DATA); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, ITK_ALE, HSCXA+offs); + return bus_space_read_1(t, h, ITK_HSCX_DATA); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, ITK_ALE, HSCXB+offs); + return bus_space_read_1(t, h, ITK_HSCX_DATA); + } + return 0; +} +#endif + +#endif /* ITKIX1 */ diff --git a/sys/i4b/layer1/i4b_l1.c b/sys/i4b/layer1/i4b_l1.c new file mode 100644 index 000000000000..96497c5df6a4 --- /dev/null +++ b/sys/i4b/layer1/i4b_l1.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l1.c - isdn4bsd layer 1 handler + * ----------------------------------- + * + * $Id: i4b_l1.c,v 1.27 1998/12/05 18:04:51 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:24:52 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "isic.h" +#else +#define NISIC 1 /* don't bother */ +#endif +#if NISIC > 0 + +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +unsigned int i4b_l1_debug = L1_DEBUG_DEFAULT; + +static int ph_data_req(int, struct mbuf *, int); +static int ph_activate_req(int); + +/* from i4btrc driver i4b_trace.c */ +extern int get_trace_data_from_l1(int unit, int what, int len, char *buf); + +/* from layer 2 */ +extern int i4b_ph_data_ind(int unit, struct mbuf *m); +extern int i4b_ph_activate_ind(int unit); +extern int i4b_ph_deactivate_ind(int unit); +extern int i4b_mph_attach_ind(int unit); +extern int i4b_mph_status_ind(int, int, int); + +/* layer 1 lme */ +static int i4b_mph_command_req(int, int, int); + +/* jump table */ +struct i4b_l1l2_func i4b_l1l2_func = { + + /* Layer 1 --> Layer 2 */ + + (int (*)(int, struct mbuf *)) i4b_ph_data_ind, + (int (*)(int)) i4b_ph_activate_ind, + (int (*)(int)) i4b_ph_deactivate_ind, + + /* Layer 2 --> Layer 1 */ + + (int (*)(int, struct mbuf *, int)) ph_data_req, + (int (*)(int)) ph_activate_req, + + /* Layer 1 --> upstream, ISDN trace data */ + + (int (*)(i4b_trace_hdr_t *, int, u_char *)) get_trace_data_from_l1, + + /* Driver control and status information */ + + (int (*)(int, int, int)) i4b_mph_status_ind, + (int (*)(int, int, int)) i4b_mph_command_req, +}; + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-DATA-REQUEST + * ========================= + * + * parms: + * unit physical interface unit number + * m mbuf containing L2 frame to be sent out + * freeflag MBUF_FREE: free mbuf here after having sent + * it out + * MBUF_DONTFREE: mbuf is freed by Layer 2 + * returns: + * ==0 fail, nothing sent out + * !=0 ok, frame sent out + * + *---------------------------------------------------------------------------*/ +static int +ph_data_req(int unit, struct mbuf *m, int freeflag) +{ + u_char cmd; + int s; + +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + +#ifdef NOTDEF + DBGL1(L1_PRIM, "PH-DATA-REQ", ("unit %d, freeflag=%d\n", unit, freeflag)); +#endif + + if(m == NULL) /* failsafe */ + return (0); + + s = SPLI4B(); + + if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ + { + DBGL1(L1_I_ERR, "ph_data_req", ("still in state F3!\n")); + ph_activate_req(unit); + } + + if(sc->sc_state & ISAC_TX_ACTIVE) + { + if(sc->sc_obuf2 == NULL) + { + sc->sc_obuf2 = m; /* save mbuf ptr */ + + if(freeflag) + sc->sc_freeflag2 = 1; /* IRQ must mfree */ + else + sc->sc_freeflag2 = 0; /* IRQ must not mfree */ + + DBGL1(L1_I_MSG, "ph_data_req", ("using 2nd ISAC TX buffer, state = %s\n", isic_printstate(sc))); + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, m->m_len, m->m_data); + } + splx(s); + return(1); + } + + DBGL1(L1_I_ERR, "ph_data_req", ("No Space in TX FIFO, state = %s\n", isic_printstate(sc))); + + if(freeflag == MBUF_FREE) + i4b_Dfreembuf(m); + + splx(s); + return (0); + } + + if(sc->sc_trace & TRACE_D_TX) + { + i4b_trace_hdr_t hdr; + hdr.unit = unit; + hdr.type = TRC_CH_D; + hdr.dir = FROM_TE; + hdr.count = ++sc->sc_trace_dcount; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, m->m_len, m->m_data); + } + + sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ + + DBGL1(L1_I_MSG, "ph_data_req", ("ISAC_TX_ACTIVE set\n")); + + sc->sc_freeflag = 0; /* IRQ must NOT mfree */ + + ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ + + if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ + { + sc->sc_obuf = m; /* save mbuf ptr */ + sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ + sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ + + if(freeflag) + sc->sc_freeflag = 1; /* IRQ must mfree */ + + cmd = ISAC_CMDR_XTF; + } + else + { + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + + if(freeflag) + i4b_Dfreembuf(m); + + cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; + } + + ISAC_WRITE(I_CMDR, cmd); + ISACCMDRWRDELAY(); + + splx(s); + + return(1); +} + +/*---------------------------------------------------------------------------* + * + * L2 -> L1: PH-ACTIVATE-REQUEST + * ============================= + * + * parms: + * unit physical interface unit number + * + * returns: + * ==0 + * !=0 + * + *---------------------------------------------------------------------------*/ +static int +ph_activate_req(int unit) +{ + +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + + DBGL1(L1_PRIM, "PH-ACTIVATE-REQ", ("unit %d\n", unit)); + isic_next_state(sc, EV_PHAR); + return(0); +} + +/*---------------------------------------------------------------------------* + * command from the upper layers + *---------------------------------------------------------------------------*/ +static int +i4b_mph_command_req(int unit, int command, int parm) +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[unit]; +#else + struct isic_softc *sc = isic_find_sc(unit); +#endif + + switch(command) + { + case CMR_DOPEN: /* daemon running */ + DBGL1(L1_PRIM, "MPH-COMMAND-REQ", ("unit %d, command = CMR_DOPEN\n", unit)); + sc->sc_enabled = 1; + break; + + case CMR_DCLOSE: /* daemon not running */ + DBGL1(L1_PRIM, "MPH-COMMAND-REQ", ("unit %d, command = CMR_DCLOSE\n", unit)); + sc->sc_enabled = 0; + break; + + default: + DBGL1(L1_ERROR, "i4b_mph_command_req", ("ERROR, unknown command = %d, unit = %d, parm = %d\n", command, unit, parm)); + break; + } + + return(0); +} + +#endif /* NISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_l1.h b/sys/i4b/layer1/i4b_l1.h new file mode 100644 index 000000000000..2b15ccc92983 --- /dev/null +++ b/sys/i4b/layer1/i4b_l1.h @@ -0,0 +1,438 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *---------------------------------------------------------------------------* + * + * i4b_l1.h - isdn4bsd layer 1 header file + * --------------------------------------- + * + * $Id: i4b_l1.h,v 1.54 1998/12/17 04:55:39 hm Exp $ + * + * last edit-date: [Mon Dec 14 10:41:36 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef I4B_L1_H_ +#define I4B_L1_H_ + +#include <i4b/include/i4b_l3l4.h> + +/*--------------------------------------------------------------------------- + * kernel config file flags definition + *---------------------------------------------------------------------------*/ + /* XXX: we do need these only for real ISA (not even ISAPNP cards), and only + * because we are not confident enough in the general ISA probe routine (as + * practiced by the NetBSD variant). *And* it is completely redundant to the + * various options enabling only a few card's support routines to be compiled + * in. Probably the current truth is: this is usefull for anybody with more + * than one supported real ISA card. It is not usefull in generic configs, + * nor in typical one-controller-only configurations. + * Further - it is identical to the CARD_TYPEP_xxx definitions in + * ../machine/i4b_ioctl.h. + */ +#define FLAG_TELES_S0_8 1 +#define FLAG_TELES_S0_16 2 +#define FLAG_TELES_S0_163 3 +#define FLAG_AVM_A1 4 +#define FLAG_TELES_S0_163_PnP 5 /* XXX - not needed, remove! */ +#define FLAG_CREATIX_S0_PnP 6 /* XXX - not needed, remove! */ +#define FLAG_USR_ISDN_TA_INT 7 +#define FLAG_DRN_NGO 8 /* XXX - not needed, remove! */ +#define FLAG_SWS 9 /* XXX - not needed, remove! */ +#define FLAG_AVM_A1_PCMCIA 10 /* XXX - not needed, remove! */ +#define FLAG_DYNALINK 11 /* XXX - not needed, remove! */ +#define FLAG_BLMASTER 12 +#define FLAG_ELSA_QS1P_ISA 13 /* XXX - not needed, remove! */ +#define FLAG_ELSA_QS1P_PCI 14 /* XXX - not needed, remove! */ +#define FLAG_SIEMENS_ITALK 15 +#define FLAG_ELSA_MLIMC 16 /* XXX - not needed, remove! */ +#define FLAG_ELSA_MLMCALL 17 /* XXX - not needed, remove! */ +#define FLAG_ITK_IX1 18 + +#define SEC_DELAY 1000000 /* one second DELAY for DELAY*/ + +#define MAX_DFRAME_LEN 264 /* max length of a D frame */ + +#define min(a,b) ((a)<(b)?(a):(b)) + +#ifndef __FreeBSD__ +/* We try to map as few as possible as small as possible io and/or + memory regions. Each card defines its own interpretation of this + mapping array. At probe time we have a fixed size array, later + (when the card type is known) we allocate a minimal array + dynamically. */ + +#define ISIC_MAX_IO_MAPS 49 /* no cardtype needs more yet */ + +/* one entry in mapping array */ +struct isic_io_map { + bus_space_tag_t t; /* which bus-space is this? */ + bus_space_handle_t h; /* handle of mapped bus space region */ + bus_size_t offset; /* offset into region */ + bus_size_t size; /* size of region, zero if not ours + (i.e.: don't ever unmap it!) */ +}; + +/* this is passed around at probe time (no struct isic_softc yet) */ +struct isic_attach_args { + int ia_flags; /* flags from config file */ + int ia_num_mappings; /* number of io mappings provided */ + struct isic_io_map ia_maps[ISIC_MAX_IO_MAPS]; +}; +#endif + +#ifdef __FreeBSD__ +extern int next_isic_unit; +#endif + +/*---------------------------------------------------------------------------* + * isic_Bchan: the state of one B channel + *---------------------------------------------------------------------------*/ +typedef struct +{ + int unit; /* cards unit number */ + int channel; /* which channel is this*/ + +#ifdef __FreeBSD__ + caddr_t hscx; /* HSCX address */ +#endif + + u_char hscx_mask; /* HSCX interrupt mask */ + + int bprot; /* B channel protocol */ + + int state; /* this channels state */ +#define HSCX_IDLE 0x00 /* channel idle */ +#define HSCX_TX_ACTIVE 0x01 /* tx running */ + + /* receive data from ISDN */ + + struct ifqueue rx_queue; /* receiver queue */ + + int rxcount; /* rx statistics counter*/ + + struct mbuf *in_mbuf; /* rx input buffer */ + u_char *in_cbptr; /* curr buffer pointer */ + int in_len; /* rx input buffer len */ + + /* transmit data to ISDN */ + + struct ifqueue tx_queue; /* transmitter queue */ + + int txcount; /* tx statistics counter*/ + + struct mbuf *out_mbuf_head; /* first mbuf in possible chain */ + struct mbuf *out_mbuf_cur; /* current mbuf in possbl chain */ + unsigned char *out_mbuf_cur_ptr; /* data pointer into mbuf */ + int out_mbuf_cur_len; /* remaining bytes in mbuf */ + + /* link between b channel and driver */ + + isdn_link_t isdn_linktab; /* b channel addresses */ + drvr_link_t *drvr_linktab; /* ptr to driver linktab*/ + + /* statistics */ + + /* RSTA */ + + int stat_VFR; /* HSCX RSTA Valid FRame */ + int stat_RDO; /* HSCX RSTA Rx Data Overflow */ + int stat_CRC; /* HSCX RSTA CRC */ + int stat_RAB; /* HSCX RSTA Rx message ABorted */ + + /* EXIR */ + + int stat_XDU; /* HSCX EXIR tx data underrun */ + int stat_RFO; /* HSCX EXIR rx frame overflow */ + +} isic_Bchan_t; + +/*---------------------------------------------------------------------------* + * isic_softc: the state of the layer 1 of the D channel + *---------------------------------------------------------------------------*/ +struct isic_softc +{ +#ifndef __FreeBSD__ + /* We are inherited from this class. All drivers must have this + as their first entry in struct softc. */ + struct device sc_dev; +#endif + + int sc_unit; /* unit number */ + int sc_irq; /* interrupt vector */ + +#ifdef __FreeBSD__ + int sc_port; /* port base address */ +#else + u_int sc_maddr; /* "memory address" for card config register */ + int sc_num_mappings; /* number of io mappings provided */ + struct isic_io_map *sc_maps; +#define MALLOC_MAPS(sc) \ + (sc)->sc_maps = (struct isic_io_map*)malloc(sizeof((sc)->sc_maps[0])*(sc)->sc_num_mappings, M_DEVBUF, 0) +#endif + + int sc_cardtyp; /* CARD_TYPEP_xxxx */ + + int sc_bustyp; /* IOM1 or IOM2 */ +#define BUS_TYPE_IOM1 0x01 +#define BUS_TYPE_IOM2 0x02 + + int sc_trace; /* output protocol data for tracing */ + unsigned int sc_trace_dcount;/* d channel trace frame counter */ + unsigned int sc_trace_bcount;/* b channel trace frame counter */ + + int sc_state; /* ISAC state flag */ +#define ISAC_IDLE 0x00 /* state = idle */ +#define ISAC_TX_ACTIVE 0x01 /* state = transmitter active */ + + int sc_init_tries; /* no of out tries to access S0 */ + +#ifdef __FreeBSD__ + caddr_t sc_vmem_addr; /* card RAM virtual memory base */ + caddr_t sc_isac; /* ISAC port base addr */ +#define ISAC_BASE (sc->sc_isac) + + caddr_t sc_ipacbase; /* IPAC port base addr */ +#define IPAC_BASE (sc->sc_ipacbase) +#endif + + u_char sc_isac_mask; /* ISAC IRQ mask */ +#define ISAC_IMASK (sc->sc_isac_mask) + + isic_Bchan_t sc_chan[2]; /* B-channel state */ +#define HSCX_A_BASE (sc->sc_chan[0].hscx) +#define HSCX_A_IMASK (sc->sc_chan[0].hscx_mask) +#define HSCX_B_BASE (sc->sc_chan[1].hscx) +#define HSCX_B_IMASK (sc->sc_chan[1].hscx_mask) + + struct mbuf *sc_ibuf; /* input buffer mgmt */ + u_short sc_ilen; + u_char *sc_ib; + /* this is for the irq TX routine */ + struct mbuf *sc_obuf; /* pointer to an mbuf with TX frame */ + u_char *sc_op; /* ptr to next chunk of frame to tx */ + int sc_ol; /* length of remaining frame to tx */ + int sc_freeflag; /* m_freem mbuf if set */ + + struct mbuf *sc_obuf2; /* pointer to an mbuf with TX frame */ + int sc_freeflag2; /* m_freem mbuf if set */ + + int sc_isac_version; /* version number of ISAC */ + int sc_hscx_version; /* version number of HSCX */ + + int sc_I430state; /* I.430 state F3 .... F8 */ + + int sc_I430T3; /* I.430 Timer T3 running */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + struct callout_handle sc_T3_callout; +#endif + + int sc_I430T4; /* Timer T4 running */ +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + struct callout_handle sc_T4_callout; +#endif + + int sc_enabled; /* daemon is running */ + + int sc_ipac; /* flag, running on ipac */ + int sc_bfifolen; /* length of b channel fifos */ + +#ifdef __FreeBSD__ + + u_char (*readreg)(u_char *, u_int); + void (*writereg)(u_char *, u_int, u_int); + void (*readfifo)(void *, const void *, size_t); + void (*writefifo)(void *, const void *, size_t); + void (*clearirq)(void *); + +#define ISAC_READ(r) (*sc->readreg)(ISAC_BASE, (r)) +#define ISAC_WRITE(r,v) (*sc->writereg)(ISAC_BASE, (r), (v)); +#define ISAC_RDFIFO(b,s) (*sc->readfifo)((b), ISAC_BASE, (s)) +#define ISAC_WRFIFO(b,s) (*sc->writefifo)(ISAC_BASE, (b), (s)) + +#define HSCX_READ(n,r) (*sc->readreg)(sc->sc_chan[(n)].hscx, (r)) +#define HSCX_WRITE(n,r,v) (*sc->writereg)(sc->sc_chan[(n)].hscx, (r), (v)) +#define HSCX_RDFIFO(n,b,s) (*sc->readfifo)((b), sc->sc_chan[(n)].hscx, (s)) +#define HSCX_WRFIFO(n,b,s) (*sc->writefifo)(sc->sc_chan[(n)].hscx, (b), (s)) + +#define IPAC_READ(r) (*sc->readreg)(IPAC_BASE, (r)) +#define IPAC_WRITE(r,v) (*sc->writereg)(IPAC_BASE, (r), (v)); + +#else /* ! __FreeBSD__ */ + +#define ISIC_WHAT_ISAC 0 +#define ISIC_WHAT_HSCXA 1 +#define ISIC_WHAT_HSCXB 2 +#define ISIC_WHAT_IPAC 3 + + u_int8_t (*readreg) __P((struct isic_softc *sc, int what, bus_size_t offs)); + void (*writereg) __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); + void (*readfifo) __P((struct isic_softc *sc, int what, void *buf, size_t size)); + void (*writefifo) __P((struct isic_softc *sc, int what, const void *data, size_t size)); + void (*clearirq) __P((struct isic_softc *sc)); + +#define ISAC_READ(r) (*sc->readreg)(sc, ISIC_WHAT_ISAC, (r)) +#define ISAC_WRITE(r,v) (*sc->writereg)(sc, ISIC_WHAT_ISAC, (r), (v)) +#define ISAC_RDFIFO(b,s) (*sc->readfifo)(sc, ISIC_WHAT_ISAC, (b), (s)) +#define ISAC_WRFIFO(b,s) (*sc->writefifo)(sc, ISIC_WHAT_ISAC, (b), (s)) + +#define HSCX_READ(n,r) (*sc->readreg)(sc, ISIC_WHAT_HSCXA+(n), (r)) +#define HSCX_WRITE(n,r,v) (*sc->writereg)(sc, ISIC_WHAT_HSCXA+(n), (r), (v)) +#define HSCX_RDFIFO(n,b,s) (*sc->readfifo)(sc, ISIC_WHAT_HSCXA+(n), (b), (s)) +#define HSCX_WRFIFO(n,b,s) (*sc->writefifo)(sc, ISIC_WHAT_HSCXA+(n), (b), (s)) + +#define IPAC_READ(r) (*sc->readreg)(sc, ISIC_WHAT_IPAC, (r)) +#define IPAC_WRITE(r, v) (*sc->writereg)(sc, ISIC_WHAT_IPAC, (r), (v)) + +#endif /* __FreeBSD__ */ +}; + +/*---------------------------------------------------------------------------* + * possible I.430/ISAC states + *---------------------------------------------------------------------------*/ +enum I430states { + ST_F3, /* F3 Deactivated */ + ST_F4, /* F4 Awaiting Signal */ + ST_F5, /* F5 Identifying Input */ + ST_F6, /* F6 Synchronized */ + ST_F7, /* F7 Activated */ + ST_F8, /* F8 Lost Framing */ + ST_ILL, /* Illegal State */ + N_STATES +}; + +/*---------------------------------------------------------------------------* + * possible I.430/ISAC events + *---------------------------------------------------------------------------*/ +enum I430events { + EV_PHAR, /* PH ACTIVATE REQUEST */ + EV_T3, /* Timer 3 expired */ + EV_INFO0, /* receiving INFO0 */ + EV_RSY, /* receiving any signal */ + EV_INFO2, /* receiving INFO2 */ + EV_INFO48, /* receiving INFO4 pri 8/9 */ + EV_INFO410, /* receiving INFO4 pri 10/11 */ + EV_DR, /* Deactivate Request */ + EV_PU, /* Power UP */ + EV_DIS, /* Disconnected (only 2085) */ + EV_EI, /* Error Indication */ + EV_ILL, /* Illegal Event */ + N_EVENTS +}; + +enum I430commands { + CMD_TIM, /* Timing */ + CMD_RS, /* Reset */ + CMD_AR8, /* Activation request pri 8 */ + CMD_AR10, /* Activation request pri 10 */ + CMD_DIU, /* Deactivate Indication Upstream */ + CMD_ILL /* Illegal command */ +}; + +#define N_COMMANDS CMD_ILL + +#ifdef __FreeBSD__ + +extern struct isic_softc isic_sc[]; + +extern void isic_recover(struct isic_softc *sc); +extern int isic_realattach(struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_avma1 ( struct isa_device *dev ); +extern int isic_attach_fritzpcmcia ( struct isa_device *dev ); +extern int isic_attach_Cs0P ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_Dyn ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_s016 ( struct isa_device *dev ); +extern int isic_attach_s0163 ( struct isa_device *dev ); +extern int isic_attach_s0163P ( struct isa_device *dev ); +extern int isic_attach_s08 ( struct isa_device *dev ); +extern int isic_attach_usrtai ( struct isa_device *dev ); +extern int isic_attach_itkix1 ( struct isa_device *dev ); +extern int isic_attach_drnngo ( struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_sws ( struct isa_device *dev ); +extern int isic_attach_Eqs1pi(struct isa_device *dev, unsigned int iobase2); +extern int isic_attach_Eqs1pp(int unit, unsigned int iobase1, unsigned int iobase2); +extern void isic_bchannel_setup (int unit, int hscx_channel, int bprot, int activate ); +extern void isic_hscx_init ( struct isic_softc *sc, int hscx_channel, int activate ); +extern void isic_hscx_irq ( struct isic_softc *sc, u_char ista, int hscx_channel, u_char ex_irq ); +extern int isic_hscx_silence ( unsigned char *data, int len ); +extern void isic_hscx_cmd( struct isic_softc *sc, int h_chan, unsigned char cmd ); +extern void isic_hscx_waitxfw( struct isic_softc *sc, int h_chan ); +extern void isic_init_linktab ( struct isic_softc *sc ); +extern int isic_isac_init ( struct isic_softc *sc ); +extern void isic_isac_irq ( struct isic_softc *sc, int r ); +extern void isic_isac_l1_cmd ( struct isic_softc *sc, int command ); +extern void isic_next_state ( struct isic_softc *sc, int event ); +extern char *isic_printstate ( struct isic_softc *sc ); +extern int isic_probe_avma1 ( struct isa_device *dev ); +extern int isic_probe_avma1_pcmcia ( struct isa_device *dev ); +extern int isic_probe_Cs0P ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_Dyn ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_s016 ( struct isa_device *dev ); +extern int isic_probe_s0163 ( struct isa_device *dev ); +extern int isic_probe_s0163P ( struct isa_device *dev ); +extern int isic_probe_s08 ( struct isa_device *dev ); +extern int isic_probe_usrtai ( struct isa_device *dev ); +extern int isic_probe_itkix1 ( struct isa_device *dev ); +extern int isic_probe_drnngo ( struct isa_device *dev, unsigned int iobase2); +extern int isic_probe_sws ( struct isa_device *dev ); +extern int isic_probe_Eqs1pi(struct isa_device *dev, unsigned int iobase2); + +#else /* not FreeBSD */ + +extern void isic_recover __P((struct isic_softc *sc)); +extern int isicattach __P((int flags, struct isic_softc *sc)); +extern int isicintr __P((void *)); +extern int isicprobe __P((struct isic_attach_args *ia)); +extern int isic_attach_avma1 __P((struct isic_softc *sc)); +extern int isic_attach_s016 __P((struct isic_softc *sc)); +extern int isic_attach_s0163 __P((struct isic_softc *sc)); +extern int isic_attach_s08 __P((struct isic_softc *sc)); +extern int isic_attach_usrtai __P((struct isic_softc *sc)); +extern int isic_attach_itkix1 __P((struct isic_softc *sc)); +extern void isic_bchannel_setup __P((int unit, int hscx_channel, int bprot, int activate)); +extern void isic_hscx_init __P((struct isic_softc *sc, int hscx_channel, int activate)); +extern void isic_hscx_irq __P((struct isic_softc *sc, u_char ista, int hscx_channel, u_char ex_irq)); +extern int isic_hscx_silence __P(( unsigned char *data, int len )); +extern void isic_hscx_cmd __P(( struct isic_softc *sc, int h_chan, unsigned char cmd )); +extern void isic_hscx_waitxfw __P(( struct isic_softc *sc, int h_chan )); +extern void isic_init_linktab __P((struct isic_softc *sc)); +extern int isic_isac_init __P((struct isic_softc *sc)); +extern void isic_isac_irq __P((struct isic_softc *sc, int r)); +extern void isic_isac_l1_cmd __P((struct isic_softc *sc, int command)); +extern void isic_next_state __P((struct isic_softc *sc, int event)); +extern char * isic_printstate __P((struct isic_softc *sc)); +extern int isic_probe_avma1 __P((struct isic_attach_args *ia)); +extern int isic_probe_s016 __P((struct isic_attach_args *ia)); +extern int isic_probe_s0163 __P((struct isic_attach_args *ia)); +extern int isic_probe_s08 __P((struct isic_attach_args *ia)); +extern int isic_probe_usrtai __P((struct isic_attach_args *ia)); +extern int isic_probe_itkix1 __P((struct isic_attach_args *ia)); + +extern struct isic_softc *isic_sc[]; + +#define isic_find_sc(unit) (isic_sc[(unit)]) + +#endif /* __FreeBSD__ */ + +#endif /* I4B_L1_H_ */ diff --git a/sys/i4b/layer1/i4b_l1fsm.c b/sys/i4b/layer1/i4b_l1fsm.c new file mode 100644 index 000000000000..397ce11f711c --- /dev/null +++ b/sys/i4b/layer1/i4b_l1fsm.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l1fsm.c - isdn4bsd layer 1 I.430 state machine + * -------------------------------------------------- + * + * $Id: i4b_l1fsm.c,v 1.26 1998/12/05 18:04:55 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:25:12 1998] + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#else +#define NISIC 1 +#endif + +#if NISIC > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#include <machine/stdarg.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + + +static char *state_text[N_STATES] = { + "F3 Deactivated", + "F4 Awaiting Signal", + "F5 Identifying Input", + "F6 Synchronized", + "F7 Activated", + "F8 Lost Framing", + "Illegal State" +}; + +static char *event_text[N_EVENTS] = { + "EV_PHAR PH_ACT_REQ", + "EV_T3 Timer 3 expired", + "EV_INFO0 INFO0 received", + "EV_RSY Level Detected", + "EV_INFO2 INFO2 received", + "EV_INFO48 INFO4 received", + "EV_INFO410 INFO4 received", + "EV_DR Deactivate Req", + "EV_PU Power UP", + "EV_DIS Disconnected", + "EV_EI Error Ind", + "Illegal Event" +}; + +/* Function prototypes */ + +static void timer3_expired (struct isic_softc *sc); +static void T3_start (struct isic_softc *sc); +static void T3_stop (struct isic_softc *sc); +static void F_T3ex (struct isic_softc *sc); +static void timer4_expired (struct isic_softc *sc); +static void T4_start (struct isic_softc *sc); +static void T4_stop (struct isic_softc *sc); +static void F_AI8 (struct isic_softc *sc); +static void F_AI10 (struct isic_softc *sc); +static void F_I01 (struct isic_softc *sc); +static void F_I02 (struct isic_softc *sc); +static void F_I03 (struct isic_softc *sc); +static void F_I2 (struct isic_softc *sc); +static void F_ill (struct isic_softc *sc); +static void F_NULL (struct isic_softc *sc); + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expire function + *---------------------------------------------------------------------------*/ +static void +timer3_expired(struct isic_softc *sc) +{ + if(sc->sc_I430T3) + { + DBGL1(L1_T_ERR, "timer3_expired", ("state = %s\n", isic_printstate(sc))); + sc->sc_I430T3 = 0; + + /* XXX try some recovery here XXX */ + + isic_recover(sc); + + sc->sc_init_tries++; /* increment retry count */ + +/*XXX*/ if(sc->sc_init_tries > 4) + { + int s = SPLI4B(); + + sc->sc_init_tries = 0; + + if(sc->sc_obuf2 != NULL) + { + i4b_Dfreembuf(sc->sc_obuf2); + sc->sc_obuf2 = NULL; + } + if(sc->sc_obuf != NULL) + { + i4b_Dfreembuf(sc->sc_obuf); + sc->sc_obuf = NULL; + sc->sc_freeflag = 0; + sc->sc_op = NULL; + sc->sc_ol = 0; + } + + splx(s); + + MPH_Status_Ind(sc->sc_unit, STI_NOL1ACC, 0); + } + + isic_next_state(sc, EV_T3); + } + else + { + DBGL1(L1_T_ERR, "timer3_expired", ("expired without starting it ....\n")); + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 start + *---------------------------------------------------------------------------*/ +static void +T3_start(struct isic_softc *sc) +{ + DBGL1(L1_T_MSG, "T3_start", ("state = %s\n", isic_printstate(sc))); + sc->sc_I430T3 = 1; + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct isic_softc *)sc, 2*hz); +#else + timeout((TIMEOUT_FUNC_T)timer3_expired,(struct isic_softc *)sc, 2*hz); +#endif +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 stop + *---------------------------------------------------------------------------*/ +static void +T3_stop(struct isic_softc *sc) +{ + DBGL1(L1_T_MSG, "T3_stop", ("state = %s\n", isic_printstate(sc))); + + sc->sc_init_tries = 0; /* init connect retry count */ + + if(sc->sc_I430T3) + { + sc->sc_I430T3 = 0; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct isic_softc *)sc, sc->sc_T3_callout); +#else + untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct isic_softc *)sc); +#endif + } +} + +/*---------------------------------------------------------------------------* + * I.430 Timer T3 expiry + *---------------------------------------------------------------------------*/ +static void +F_T3ex(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_T3ex", ("FSM function F_T3ex executing\n")); + PH_Deact_Ind(sc->sc_unit); +} + +/*---------------------------------------------------------------------------* + * Timer T4 expire function + *---------------------------------------------------------------------------*/ +static void +timer4_expired(struct isic_softc *sc) +{ + if(sc->sc_I430T4) + { + DBGL1(L1_T_ERR, "timer4_expired", ("state = %s\n", isic_printstate(sc))); + sc->sc_I430T4 = 0; + MPH_Status_Ind(sc->sc_unit, STI_PDEACT, 0); + } + else + { + DBGL1(L1_T_ERR, "timer4_expired", ("expired without starting it ....\n")); + } +} + +/*---------------------------------------------------------------------------* + * Timer T4 start + *---------------------------------------------------------------------------*/ +static void +T4_start(struct isic_softc *sc) +{ + DBGL1(L1_T_MSG, "T4_start", ("state = %s\n", isic_printstate(sc))); + sc->sc_I430T4 = 1; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct isic_softc *)sc, hz); +#else + timeout((TIMEOUT_FUNC_T)timer4_expired,(struct isic_softc *)sc, hz); +#endif +} + +/*---------------------------------------------------------------------------* + * Timer T4 stop + *---------------------------------------------------------------------------*/ +static void +T4_stop(struct isic_softc *sc) +{ + DBGL1(L1_T_MSG, "T4_stop", ("state = %s\n", isic_printstate(sc))); + + if(sc->sc_I430T4) + { + sc->sc_I430T4 = 0; +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct isic_softc *)sc, sc->sc_T4_callout); +#else + untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct isic_softc *)sc); +#endif + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI8 + *---------------------------------------------------------------------------*/ +static void +F_AI8(struct isic_softc *sc) +{ + T4_stop(sc); + + DBGL1(L1_F_MSG, "F_AI8", ("FSM function F_AI8 executing\n")); + + PH_Act_Ind(sc->sc_unit); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_8; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received AI10 + *---------------------------------------------------------------------------*/ +static void +F_AI10(struct isic_softc *sc) +{ + T4_stop(sc); + + DBGL1(L1_F_MSG, "F_AI10", ("FSM function F_AI10 executing\n")); + + PH_Act_Ind(sc->sc_unit); + + T3_stop(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO4_10; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in states F3 .. F5 + *---------------------------------------------------------------------------*/ +static void +F_I01(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_I01", ("FSM function F_I01 executing\n")); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F6 + *---------------------------------------------------------------------------*/ +static void +F_I02(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_I02", ("FSM function F_I02 executing\n")); + + PH_Deact_Ind(sc->sc_unit); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO 0 in state F7 or F8 + *---------------------------------------------------------------------------*/ +static void +F_I03(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_I03", ("FSM function F_I03 executing\n")); + + PH_Deact_Ind(sc->sc_unit); + + T4_start(sc); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO0; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } +} + +/*---------------------------------------------------------------------------* + * FSM function: activate request + *---------------------------------------------------------------------------*/ +static void +F_AR(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_AR", ("FSM function F_AR executing\n")); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO1_8; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_TE; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } + + isic_isac_l1_cmd(sc, CMD_AR8); + + T3_start(sc); +} + +/*---------------------------------------------------------------------------* + * FSM function: received INFO2 + *---------------------------------------------------------------------------*/ +static void +F_I2(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_I2", ("FSM function F_I2 executing\n")); + + if(sc->sc_trace & TRACE_I) + { + i4b_trace_hdr_t hdr; + char info = INFO2; + + hdr.unit = sc->sc_unit; + hdr.type = TRC_CH_I; + hdr.dir = FROM_NT; + hdr.count = 0; + MICROTIME(hdr.time); + MPH_Trace_Ind(&hdr, 1, &info); + } + +} + +/*---------------------------------------------------------------------------* + * illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ill(struct isic_softc *sc) +{ + DBGL1(L1_F_ERR, "F_ill", ("FSM function F_ill executing\n")); +} + +/*---------------------------------------------------------------------------* + * No action + *---------------------------------------------------------------------------*/ +static void +F_NULL(struct isic_softc *sc) +{ + DBGL1(L1_F_MSG, "F_NULL", ("FSM function F_NULL executing\n")); +} + + +/*---------------------------------------------------------------------------* + * layer 1 state transition table + *---------------------------------------------------------------------------*/ +struct isic_state_tab { + void (*func) (struct isic_softc *sc); /* function to execute */ + int newstate; /* next state */ +} isic_state_tab[N_EVENTS][N_STATES] = { + +/* STATE: F3 F4 F5 F6 F7 F8 ILLEGAL STATE */ +/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* EV_PHAR x*/ {{F_AR, ST_F4}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_ill, ST_ILL}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_T3 x*/ {{F_NULL, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_T3ex, ST_F3}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO0 */ {{F_I01, ST_F3}, {F_I01, ST_F4}, {F_I01, ST_F5}, {F_I02, ST_F3}, {F_I03, ST_F3}, {F_I03, ST_F3}, {F_ill, ST_ILL}}, +/* EV_RSY x*/ {{F_NULL, ST_F3}, {F_NULL, ST_F5}, {F_NULL, ST_F5}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_INFO2 */ {{F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_I2, ST_F6}, {F_ill, ST_ILL}}, +/* EV_INFO48*/ {{F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_AI8, ST_F7}, {F_NULL, ST_F7}, {F_AI8, ST_F7}, {F_ill, ST_ILL}}, +/* EV_INFO41*/ {{F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_AI10, ST_F7}, {F_NULL, ST_F7}, {F_AI10, ST_F7}, {F_ill, ST_ILL}}, +/* EV_DR */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_PU */ {{F_NULL, ST_F3}, {F_NULL, ST_F4}, {F_NULL, ST_F5}, {F_NULL, ST_F6}, {F_NULL, ST_F7}, {F_NULL, ST_F8}, {F_ill, ST_ILL}}, +/* EV_DIS */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}, +/* EV_EI */ {{F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_NULL, ST_F3}, {F_ill, ST_ILL}}, +/* EV_ILL */ {{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void +isic_next_state(struct isic_softc *sc, int event) +{ + int currstate, newstate; + + if(event >= N_EVENTS) + panic("i4b_l1fsm.c: event >= N_EVENTS\n"); + + currstate = sc->sc_I430state; + + if(currstate >= N_STATES) + panic("i4b_l1fsm.c: currstate >= N_STATES\n"); + + newstate = isic_state_tab[event][currstate].newstate; + + if(newstate >= N_STATES) + panic("i4b_l1fsm.c: newstate >= N_STATES\n"); + + DBGL1(L1_F_MSG, "isic_next_state", ("FSM event [%s]: [%s => %s]\n", event_text[event], + state_text[currstate], + state_text[newstate])); + + (*isic_state_tab[event][currstate].func)(sc); + + if(newstate == ST_ILL) + { + newstate = ST_F3; + DBGL1(L1_F_ERR, "isic_next_state", ("FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!\n", + state_text[currstate], + state_text[newstate], + event_text[event])); + } + + sc->sc_I430state = newstate; +} + +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char * +isic_printstate(struct isic_softc *sc) +{ + return((char *) state_text[sc->sc_I430state]); +} + +#endif /* NISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_sws.c b/sys/i4b/layer1/i4b_sws.c new file mode 100644 index 000000000000..c5182b49e3d7 --- /dev/null +++ b/sys/i4b/layer1/i4b_sws.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 1998 German Tischler. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * Card format: + * + * iobase + 0 : reset on (0x03) + * iobase + 1 : reset off (0x0) + * iobase + 2 : isac read/write + * iobase + 3 : hscx read/write ( offset 0-0x3f hscx0 , + * offset 0x40-0x7f hscx1 ) + * iobase + 4 : offset for indirect adressing + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for SWS cards + * ==================================================== + * + * EXPERIMENTAL !!!! + * ================= + * + * $Id: i4b_sws.c,v 1.12 1998/12/18 09:32:45 hm Exp $ + * + * last edit-date: [Sun Dec 13 10:49:25 1998] + * + * -hm adding driver to i4b + * -hm adjustments for FreeBSD < 2.2.6, no PnP support yet + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) + +#include "isic.h" +#include "opt_i4b.h" + +#else + +#define NISIC 1 + +#endif + +#if defined (SEDLBAUER) && NISIC > 0 + +#define SWS_RESON 0 /* reset on */ +#define SWS_RESOFF 1 /* reset off */ +#define SWS_ISAC 2 /* ISAC */ +#define SWS_HSCX0 3 /* HSCX0 */ +#define SWS_RW 4 /* indirect access register */ +#define SWS_HSCX1 5 /* this is for fakeing that we mean hscx1, though */ + /* access is done through hscx0 */ + +#define SWS_REGS 8 /* we use an area of 8 bytes for io */ + +#define SWS_BASE(X) ((unsigned int)X&~(SWS_REGS-1)) +#define SWS_PART(X) ((unsigned int)X& (SWS_REGS-1)) +#define SWS_ADDR(X) ((SWS_PART(X) == SWS_ISAC) ? (SWS_BASE(X)+SWS_ISAC) : (SWS_BASE(X)+SWS_HSCX0) ) +#define SWS_REG(X,Y) ((SWS_PART(X) != SWS_HSCX1) ? Y : (Y+0x40) ) +#define SWS_IDO(X) (SWS_BASE(X)+SWS_RW) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t sws_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void sws_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void sws_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void sws_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +void isic_attach_sws __P((struct isic_softc *sc)); +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC get fifo routine + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +static void +sws_read_fifo(void *buf, const void *base, size_t len) +{ + outb(SWS_IDO(base),SWS_REG(base,0)); + insb(SWS_ADDR(base),buf,len); +} + +#else + +static void +sws_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_read_multi_1(t, h, SWS_ISAC, buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_read_multi_1(t, h, SWS_HSCX0, buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40); + bus_space_read_multi_1(t, h, SWS_HSCX0, buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC put fifo routine + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +static void +sws_write_fifo(void *base, const void *buf, size_t len) +{ + outb (SWS_IDO(base),SWS_REG(base,0)); + outsb(SWS_ADDR(base),buf,len); +} + +#else + +static void +sws_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_write_multi_1(t, h, SWS_ISAC, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, 0); + bus_space_write_multi_1(t, h, SWS_HSCX0, (u_int8_t*)buf, size); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40); + bus_space_write_multi_1(t, h, SWS_HSCX0, (u_int8_t*)buf, size); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC put register routine + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ + +static void +sws_write_reg(u_char *base, u_int offset, u_int v) +{ + outb(SWS_IDO(base),SWS_REG(base,offset)); + outb(SWS_ADDR(base),v); +} + +#else + +static void +sws_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, offs); + bus_space_write_1(t, h, SWS_ISAC, data); + break; + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, offs); + bus_space_write_1(t, h, SWS_HSCX0, data); + break; + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40+offs); + bus_space_write_1(t, h, SWS_HSCX0, data); + break; + } +} + +#endif + +/*---------------------------------------------------------------------------* + * SWS P&P ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +sws_read_reg(u_char *base, u_int offset) +{ + outb(SWS_IDO(base),SWS_REG(base,offset)); + return inb(SWS_ADDR(base)); +} + +#else + +static u_int8_t +sws_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + switch (what) { + case ISIC_WHAT_ISAC: + bus_space_write_1(t, h, SWS_RW, offs); + return bus_space_read_1(t, h, SWS_ISAC); + case ISIC_WHAT_HSCXA: + bus_space_write_1(t, h, SWS_RW, offs); + return bus_space_read_1(t, h, SWS_HSCX0); + case ISIC_WHAT_HSCXB: + bus_space_write_1(t, h, SWS_RW, 0x40+offs); + return bus_space_read_1(t, h, SWS_HSCX0); + } + return 0; +} + +#endif + +#ifdef __FreeBSD__ + +/* attach callback routine */ + +int +isic_attach_sws(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* fill in isic_softc structure */ + + sc->readreg = sws_read_reg; + sc->writereg = sws_write_reg; + sc->readfifo = sws_read_fifo; + sc->writefifo = sws_write_fifo; + sc->clearirq = NULL; + sc->sc_unit = dev->id_unit; + sc->sc_irq = dev->id_irq; + sc->sc_port = dev->id_iobase; + sc->sc_cardtyp = CARD_TYPEP_SWS; + sc->sc_bustyp = BUS_TYPE_IOM2; + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + dev->id_msize = 0; + + ISAC_BASE = (caddr_t) (((u_int) sc->sc_port) + SWS_ISAC); + HSCX_A_BASE = (caddr_t) (((u_int) sc->sc_port) + SWS_HSCX0); + HSCX_B_BASE = (caddr_t) (((u_int) sc->sc_port) + SWS_HSCX1); + + /* + * Read HSCX A/B VSTR. Expected value for the SWS PnP card is + * 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for SWS PnP\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + /* reset card */ + + outb( ((u_int) sc->sc_port) + SWS_RESON , 0x3); + DELAY(SEC_DELAY / 5); + outb( ((u_int) sc->sc_port) + SWS_RESOFF, 0); + DELAY(SEC_DELAY / 5); + + return(1); +} + +#else /* !__FreeBSD__ */ + +void +isic_attach_sws(struct isic_softc *sc) +{ + /* setup access routines */ + + sc->readreg = sws_read_reg; + sc->writereg = sws_write_reg; + + sc->readfifo = sws_read_fifo; + sc->writefifo = sws_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_SWS; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* + * Read HSCX A/B VSTR. Expected value for the SWS PnP card is + * 0x05 ( = version 2.1 ) in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("%s: HSCX VSTR test failed for SWS PnP\n", + sc->sc_dev.dv_xname); + printf("%s: HSC0: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR)); + printf("%s: HSC1: VSTR: %#x\n", + sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR)); + return; + } + + /* reset card */ + { + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, SWS_RESON, 0x3); + DELAY(SEC_DELAY / 5); + bus_space_write_1(t, h, SWS_RESOFF, 0); + DELAY(SEC_DELAY / 5); + } +} + +#endif /* !__FreeBSD__ */ + +#endif /* defined(SEDLBAUER) && NISIC > 0 */ diff --git a/sys/i4b/layer1/i4b_tel_s016.c b/sys/i4b/layer1/i4b_tel_s016.c new file mode 100644 index 000000000000..f77a3c184241 --- /dev/null +++ b/sys/i4b/layer1/i4b_tel_s016.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1996 Arne Helme. All rights reserved. + * + * Copyright (c) 1996 Gary Jennejohn. All rights reserved. + * + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0/16 and clones + * ================================================================= + * + * $Id: i4b_tel_s016.c,v 1.12 1998/12/05 18:04:56 hm Exp $ + * + * last edit-date: [Fri Dec 4 10:40:17 1998] + * + * -hm clean up + * -hm checked with a Creatix ISDN-S0 (PCB version: mp 130.1) + * -hm more cleanup + * -hm NetBSD patches from Martin + * -hm converting asm -> C + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(TEL_S0_16) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <machine/md_var.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 }; + +#ifndef __FreeBSD__ +static u_int8_t tels016_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void tels016_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels016_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void tels016_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16 write register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels016_write_reg(u_char *base, u_int i, u_int v) +{ + if(i & 0x01) + i |= 0x200; + base[i] = v; +} + +#else + +static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 }; + +static void +tels016_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + + offs += offset[what]; + if (offs & 0x01) + offs |= 0x200; + + bus_space_write_1(t, h, offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16 read register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels016_read_reg(u_char *base, u_int i) +{ + if(i & 0x1) + i |= 0x200; + return(base[i]); +} + +#else + +static u_int8_t +tels016_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + + offs += offset[what]; + + if(offs & 0x01) + offs |= 0x200; + + return bus_space_read_1(t, h, offs); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16 fifo read/write routines + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels016_memcpyb(void *to, const void *from, size_t len) +{ + for(;len > 0; len--) + *((unsigned char *)to)++ = *((unsigned char *)from)++; +} + +#else + +static void +tels016_write_fifo(struct isic_softc *sc, int what, const void *data, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + bus_space_write_region_1(t, h, offset[what], data, size); +} + +static void +tels016_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[1].t; + bus_space_handle_t h = sc->sc_maps[1].h; + bus_space_read_region_1(t, h, offset[what], buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s016 - probe for Teles S0/16 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_s016(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + u_char byte; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + if((intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + sc->sc_irq = dev->id_irq; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0xd80: + case 0xe80: + case 0xf80: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* check if valid memory addr */ + + switch((unsigned int)kvtop(dev->id_maddr)) + { + case 0xc0000: + case 0xc2000: + case 0xc4000: + case 0xc6000: + case 0xc8000: + case 0xca000: + case 0xcc000: + case 0xce000: + case 0xd0000: + case 0xd2000: + case 0xd4000: + case 0xd6000: + case 0xd8000: + case 0xda000: + case 0xdc000: + case 0xde000: + break; + + default: + printf("isic%d: Error, invalid mem addr 0x%lx for Teles S0/16!\n", + dev->id_unit, kvtop(dev->id_maddr)); + return(0); + break; + } + sc->sc_vmem_addr = (caddr_t) dev->id_maddr; + dev->id_msize = 0x1000; + + /* check card signature */ + + if((byte = inb(sc->sc_port)) != 0x51) + { + printf("isic%d: Error, signature 1 0x%x != 0x51 for Teles S0/16!\n", + dev->id_unit, byte); + return(0); + } + + if((byte = inb(sc->sc_port + 1)) != 0x93) + { + printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16!\n", + dev->id_unit, byte); + return(0); + } + + byte = inb(sc->sc_port + 2); + + if((byte != 0x1e) && (byte != 0x1f)) + { + printf("isic%d: Error, signature 3 0x%x != 0x1e or 0x1f for Teles S0/16!\n", + dev->id_unit, byte); + return(0); + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels016_read_reg; + sc->writereg = tels016_write_reg; + + sc->readfifo = tels016_memcpyb; + sc->writefifo = tels016_memcpyb; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC base addr */ + + ISAC_BASE = (caddr_t) ((dev->id_maddr) + 0x100); + + /* setup HSCX base addr */ + + HSCX_A_BASE = (caddr_t) ((dev->id_maddr) + 0x180); + HSCX_B_BASE = (caddr_t) ((dev->id_maddr) + 0x1c0); + + return (1); +} + +#else + +int +isic_probe_s016(struct isic_attach_args *ia) +{ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t b0, b1, b2; + + b0 = bus_space_read_1(t, h, 0); + b1 = bus_space_read_1(t, h, 1); + b2 = bus_space_read_1(t, h, 2); + + if (b0 == 0x51 && b1 == 0x93 && (b2 == 0x1e || b2 == 0x1f)) + return 1; + + return 0; +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s016 - attach Teles S0/16 and compatibles + *---------------------------------------------------------------------------*/ +int +#ifdef __FreeBSD__ +isic_attach_s016(struct isa_device *dev) +#else +isic_attach_s016(struct isic_softc *sc) +#endif +{ + +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[dev->id_unit]; +#endif + + u_long irq; + +#ifndef __FreeBSD__ + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels016_read_reg; + sc->writereg = tels016_write_reg; + + sc->readfifo = tels016_read_fifo; + sc->writefifo = tels016_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + +#endif + +#ifdef __FreeBSD__ + if((irq = intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Attach error, invalid IRQ [%d] specified for Teles S0/16!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } +#else + irq = intr_no[sc->sc_irq]; +#endif + + /* configure IRQ */ + +#ifdef __FreeBSD__ + irq |= ((u_long) sc->sc_vmem_addr) >> 9; + + DELAY(SEC_DELAY / 10); + outb(sc->sc_port + 4, irq); + + DELAY(SEC_DELAY / 10); + outb(sc->sc_port + 4, irq | 0x01); + + DELAY(SEC_DELAY / 5); + + /* set card bit off */ + + sc->sc_vmem_addr[0x80] = 0; + DELAY(SEC_DELAY / 5); + + /* set card bit on */ + + sc->sc_vmem_addr[0x80] = 1; + DELAY(SEC_DELAY / 5); + +#else + + irq |= ((sc->sc_maddr >> 9) & 0x000000f0); + + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 4, irq); + + DELAY(SEC_DELAY / 10); + bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, 4, irq | 0x01); + + DELAY(SEC_DELAY / 5); + + /* set card bit off */ + + bus_space_write_1(sc->sc_maps[1].t, sc->sc_maps[1].h, 0x80, 0); + DELAY(SEC_DELAY / 5); + + /* set card bit on */ + + bus_space_write_1(sc->sc_maps[1].t, sc->sc_maps[1].h, 0x80, 1); + DELAY(SEC_DELAY / 5); +#endif + + return (1); +} + +#endif /* ISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_tel_s0163.c b/sys/i4b/layer1/i4b_tel_s0163.c new file mode 100644 index 000000000000..5fdd32961b73 --- /dev/null +++ b/sys/i4b/layer1/i4b_tel_s0163.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 1996 Arne Helme. All rights reserved. + * + * Copyright (c) 1996 Gary Jennejohn. All rights reserved. + * + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0/16.3 + * ======================================================== + * + * $Id: i4b_tel_s0163.c,v 1.15 1998/12/05 18:04:58 hm Exp $ + * + * last edit-date: [Fri Dec 4 10:40:58 1998] + * + * -hm clean up + * -hm more cleanup + * -hm NetBSD patches from Martin + * -hm VSTR detection for older 16.3 cards + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(TEL_S0_16_3) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 }; + +#ifndef __FreeBSD__ +static u_int8_t tels0163_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void tels0163_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels0163_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void tels0163_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 read fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_read_multi_1(t, h, o + 0x1e, buf, size); +} + +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 write fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_multi_1(t, h, o + 0x1e, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 ISAC put register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} + +#else + +static void +tels0163_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_1(t, h, o + offs - 0x20, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 ISAC get register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels0163_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} + +#else + +static u_int8_t +tels0163_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + return bus_space_read_1(t, h, o + offs - 0x20); +} + +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s0163 - probe for Teles S0/16.3 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_s0163(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + u_char byte; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16.3!", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + if((intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16.3!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Teles S0/16.3!", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0xd80: + case 0xe80: + case 0xf80: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16.3!", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + if((byte = inb(sc->sc_port)) != 0x51) + { + printf("isic%d: Error, signature 1 0x%x != 0x51 for Teles S0/16.3!", + dev->id_unit, byte); + return(0); + } + + if((byte = inb(sc->sc_port + 1)) != 0x93) + { + printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16.3!", + dev->id_unit, byte); + return(0); + } + + if((byte = inb(sc->sc_port + 2)) != 0x1c) + { + printf("isic%d: Error, signature 3 0x%x != 0x1c for Teles S0/16.3!", + dev->id_unit, byte); + return(0); + } + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163_read_reg; + sc->writereg = tels0163_write_reg; + + sc->readfifo = tels0163_read_fifo; + sc->writefifo = tels0163_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16_3; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + switch(dev->id_iobase) + { + case 0xd80: + ISAC_BASE = (caddr_t) 0x960; + HSCX_A_BASE = (caddr_t) 0x160; + HSCX_B_BASE = (caddr_t) 0x560; + break; + + case 0xe80: + ISAC_BASE = (caddr_t) 0xa60; + HSCX_A_BASE = (caddr_t) 0x260; + HSCX_B_BASE = (caddr_t) 0x660; + break; + + case 0xf80: + ISAC_BASE = (caddr_t) 0xb60; + HSCX_A_BASE = (caddr_t) 0x360; + HSCX_B_BASE = (caddr_t) 0x760; + break; + } + + /* + * Read HSCX A/B VSTR. Expected value for the S0/16.3 card is + * 0x05 or 0x04 (for older 16.3's) in the least significant bits. + */ + + if( (((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(0, H_VSTR) & 0xf) != 0x4)) || + (((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) && + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x4)) ) + { + printf("isic%d: HSCX VSTR test failed for Teles S0/16.3\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +#else + +int +isic_probe_s0163(struct isic_attach_args *ia) +{ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t b0, b1, b2; + + b0 = bus_space_read_1(t, h, 0); + b1 = bus_space_read_1(t, h, 1); + b2 = bus_space_read_1(t, h, 2); + + if (b0 == 0x51 && b1 == 0x93 && b2 == 0x1c) + return 1; + + return 0; +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s0163 - attach Teles S0/16.3 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_s0163(struct isa_device *dev) +{ + u_char irq; + + if((irq = intr_no[ffs(dev->id_irq) - 1]) == 1) + { + printf("isic%d: Attach error, invalid IRQ [%d] specified for Teles S0/16.3!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + + /* configure IRQ */ + + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + 4, irq); + + DELAY(SEC_DELAY / 10); + outb(dev->id_iobase + 4, irq | 0x01); + + return (1); +} + +#else + +int +isic_attach_s0163(struct isic_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + u_int8_t irq = intr_no[sc->sc_irq]; + + /* configure IRQ */ + + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 4, irq); + + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 4, irq | 0x01); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163_read_reg; + sc->writereg = tels0163_write_reg; + + sc->readfifo = tels0163_read_fifo; + sc->writefifo = tels0163_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp= CARD_TYPEP_16_3; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + return (1); +} +#endif + +#endif /* ISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_tel_s08.c b/sys/i4b/layer1/i4b_tel_s08.c new file mode 100644 index 000000000000..6115e12ab624 --- /dev/null +++ b/sys/i4b/layer1/i4b_tel_s08.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1996 Arne Helme. All rights reserved. + * + * Copyright (c) 1996 Gary Jennejohn. All rights reserved. + * + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0/8 and clones + * ================================================================ + * + * $Id: i4b_tel_s08.c,v 1.13 1998/12/05 18:04:59 hm Exp $ + * + * last edit-date: [Fri Dec 4 10:39:12 1998] + * + * -hm clean up + * -hm more cleanup + * -hm NetBSD patches from Martin + * -hm making it finally work (checked with board revision 1.2) + * -hm converting asm -> C + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(TEL_S0_8) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <machine/md_var.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t tels08_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void tels08_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels08_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +static void tels08_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/8 write register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels08_write_reg(u_char *base, u_int i, u_int v) +{ + if(i & 0x01) + i |= 0x200; + base[i] = v; +} + +#else + +static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 }; + +static void +tels08_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + + offs += offset[what]; + + if (offs & 0x01) + offs |= 0x200; + + bus_space_write_1(t, h, offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/8 read register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels08_read_reg(u_char *base, u_int i) +{ + if(i & 0x1) + i |= 0x200; + return(base[i]); +} + +#else + +static u_int8_t +tels08_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + + offs += offset[what]; + + if (offs & 0x01) + offs |= 0x200; + + return bus_space_read_1(t, h, offs); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/8 fifo read/write access + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels08_memcpyb(void *to, const void *from, size_t len) +{ + for(;len > 0; len--) + *((unsigned char *)to)++ = *((unsigned char *)from)++; +} + +#else + +static void +tels08_write_fifo(struct isic_softc *sc, int what, const void *data, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_region_1(t, h, offset[what], data, size); +} + +static void +tels08_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_read_region_1(t, h, offset[what], buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s08 - probe for Teles S0/8 and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +int +isic_probe_s08(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/8!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq)-1) + { + case 2: + case 9: /* XXX */ + case 3: + case 4: + case 5: + case 6: + case 7: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/8!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if we got an iobase */ + + if(dev->id_iobase > 0) + { + printf("isic%d: Error, iobase specified for Teles S0/8!\n", + dev->id_unit); + return(0); + } + + /* check if inside memory range of 0xA0000 .. 0xDF000 */ + + if( (kvtop(dev->id_maddr) < 0xa0000) || + (kvtop(dev->id_maddr) > 0xdf000) ) + { + printf("isic%d: Error, mem addr 0x%lx outside 0xA0000-0xDF000 for Teles S0/8!\n", + dev->id_unit, kvtop(dev->id_maddr)); + return(0); + } + + sc->sc_vmem_addr = (caddr_t) dev->id_maddr; + dev->id_msize = 0x1000; + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = tels08_read_reg; + sc->writereg = tels08_write_reg; + + sc->readfifo = tels08_memcpyb; + sc->writefifo = tels08_memcpyb; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_8; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC base addr */ + + ISAC_BASE = (caddr_t)((dev->id_maddr) + 0x100); + + /* setup HSCX base addr */ + + HSCX_A_BASE = (caddr_t)((dev->id_maddr) + 0x180); + HSCX_B_BASE = (caddr_t)((dev->id_maddr) + 0x1c0); + + return (1); +} + +#else + +int +isic_probe_s08(struct isic_attach_args *ia) +{ + /* no real sensible probe is easy - write to fifo memory + and read back to verify there is memory doesn't work, + because you talk to tx fifo and rcv fifo. So, just check + HSCX version, which at least fails if no card present + at the given location. */ + bus_space_tag_t t = ia->ia_maps[0].t; + bus_space_handle_t h = ia->ia_maps[0].h; + u_int8_t v1, v2; + + /* HSCX A VSTR */ + v1 = bus_space_read_1(t, h, offset[1] + H_VSTR) & 0x0f; + if (v1 != HSCX_VA1 && v1 != HSCX_VA2 && v1 != HSCX_VA3 && v1 != HSCX_V21) + return 0; + + /* HSCX B VSTR */ + v2 = bus_space_read_1(t, h, offset[2] + H_VSTR) & 0x0f; + if (v2 != HSCX_VA1 && v2 != HSCX_VA2 && v2 != HSCX_VA3 && v2 != HSCX_V21) + return 0; + + /* both HSCX channels should have the same version... */ + if (v1 != v2) + return 0; + + return 1; +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s08 - attach Teles S0/8 and compatibles + *---------------------------------------------------------------------------*/ +int +#ifdef __FreeBSD__ +isic_attach_s08(struct isa_device *dev) +#else +isic_attach_s08(struct isic_softc *sc) +#endif +{ +#ifdef __FreeBSD__ + struct isic_softc *sc = &isic_sc[dev->id_unit]; +#else + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; +#endif + + /* set card off */ + +#ifdef __FreeBSD__ + sc->sc_vmem_addr[0x80] = 0; +#else + bus_space_write_1(t, h, 0x80, 0); +#endif + + DELAY(SEC_DELAY / 5); + + /* set card on */ + +#ifdef __FreeBSD__ + sc->sc_vmem_addr[0x80] = 1; +#else + bus_space_write_1(t, h, 0x80, 1); +#endif + + DELAY(SEC_DELAY / 5); + +#ifndef __FreeBSD__ + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = tels08_read_reg; + sc->writereg = tels08_write_reg; + sc->readfifo = tels08_read_fifo; + sc->writefifo = tels08_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_8; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM1; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + +#endif + + return (1); +} + +#endif /* ISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_tel_s0P.c b/sys/i4b/layer1/i4b_tel_s0P.c new file mode 100644 index 000000000000..9bccd77b6fc9 --- /dev/null +++ b/sys/i4b/layer1/i4b_tel_s0P.c @@ -0,0 +1,378 @@ +/* + * Copyright (c) 1997 Andrew Gordon. All rights reserved. + * + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic - I4B Siemens ISDN Chipset Driver for Teles S0 PnP + * ======================================================= + * + * EXPERIMENTAL !!! + * ================ + * + * $Id: i4b_tel_s0P.c,v 1.12 1998/12/13 09:52:34 hm Exp $ + * + * last edit-date: [Thu Dec 10 07:11:15 1998] + * + * -hm rudimentary PnP support, hint from Andrew Gordon + * -hm more cleanup + * -hm NetBSD patches from Martin + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(TEL_S0_16_3_P) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_mbuf.h> + +#ifndef __FreeBSD__ +static u_int8_t tels0163P_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs)); +static void tels0163P_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)); +static void tels0163P_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size)); +static void tels0163P_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size)); +void isic_attach_s0163P __P((struct isic_softc *sc)); +#endif + + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP read fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163P_read_fifo(void *buf, const void *base, size_t len) +{ + insb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163P_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_read_multi_1(t, h, o + 0x3e, buf, size); +} + +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP write fifo routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163P_write_fifo(void *base, const void *buf, size_t len) +{ + outsb((int)base + 0x3e, (u_char *)buf, (u_int)len); +} + +#else + +static void +tels0163P_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_multi_1(t, h, o + 0x3e, (u_int8_t*)buf, size); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP write register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static void +tels0163P_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + offset, (u_char)v); +} + +#else + +static void +tels0163P_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + bus_space_write_1(t, h, o + offs, data); +} +#endif + +/*---------------------------------------------------------------------------* + * Teles S0/16.3 PnP read register routine + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ + +static u_char +tels0163P_read_reg(u_char *base, u_int offset) +{ + return (inb((int)base + offset)); +} + +#else + +static u_int8_t +tels0163P_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what+1].t; + bus_space_handle_t h = sc->sc_maps[what+1].h; + bus_size_t o = sc->sc_maps[what+1].offset; + return bus_space_read_1(t, h, o + offs); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_probe_s0163P - probe for Teles S0/16.3 PnP and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_probe_s0163P(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16.3 PnP!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + switch(ffs(dev->id_irq) - 1) + { + case 3: + case 5: + case 7: + case 10: + case 11: + case 12: + break; + + default: + printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16.3 PnP!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + break; + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for Teles S0/16.3 PnP!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x580: + case 0x500: + case 0x680: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16.3 PnP!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163P_read_reg; + sc->writereg = tels0163P_write_reg; + + sc->readfifo = tels0163P_read_fifo; + sc->writefifo = tels0163P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_163P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + switch(dev->id_iobase) + { + case 0x580: + ISAC_BASE = (caddr_t) 0x580 - 0x20; + HSCX_A_BASE = (caddr_t) 0x180 - 0x20; + HSCX_B_BASE = (caddr_t) 0x180; + break; + + case 0x500: + ISAC_BASE = (caddr_t) 0x500 - 0x20; + HSCX_A_BASE = (caddr_t) 0x100 - 0x20; + HSCX_B_BASE = (caddr_t) 0x100; + break; + + case 0x680: + ISAC_BASE = (caddr_t) 0x680 - 0x20; + HSCX_A_BASE = (caddr_t) 0x280 - 0x20; + HSCX_B_BASE = (caddr_t) 0x280; + break; + } + + /* + * Read HSCX A/B VSTR. Expected value for the S0/16.3 PnP card is + * 0x05 in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for Teles S0/16.3 PnP\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} +#endif + +/*---------------------------------------------------------------------------* + * isic_attach_s0163P - attach Teles S0/16.3 PnP and compatibles + *---------------------------------------------------------------------------*/ +#ifdef __FreeBSD__ +int +isic_attach_s0163P(struct isa_device *dev) +{ + outb((dev->id_iobase) + 0x1c, 0); + DELAY(SEC_DELAY / 10); + outb((dev->id_iobase) + 0x1c, 1); + DELAY(SEC_DELAY / 10); + return(1); +} + +#else + +void +isic_attach_s0163P(struct isic_softc *sc) +{ + /* init card */ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + bus_space_write_1(t, h, 0x1c, 0); + DELAY(SEC_DELAY / 10); + bus_space_write_1(t, h, 0x1c, 1); + DELAY(SEC_DELAY / 10); + + /* setup access routines */ + + sc->clearirq = NULL; + sc->readreg = tels0163P_read_reg; + sc->writereg = tels0163P_write_reg; + + sc->readfifo = tels0163P_read_fifo; + sc->writefifo = tels0163P_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_163P; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; +} +#endif + +#endif /* ISIC > 0 */ + diff --git a/sys/i4b/layer1/i4b_usr_sti.c b/sys/i4b/layer1/i4b_usr_sti.c new file mode 100644 index 000000000000..db89296160fa --- /dev/null +++ b/sys/i4b/layer1/i4b_usr_sti.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_usr_sti.c - USRobotics Sportster ISDN TA intern (Tina-pp) + * ------------------------------------------------------------- + * + * $Id: i4b_usr_sti.c,v 1.16 1998/12/05 18:05:02 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:25:34 1998] + * + *---------------------------------------------------------------------------*/ + +#if defined(__FreeBSD__) +#include "isic.h" +#include "opt_i4b.h" +#else +#define NISIC 1 +#endif +#if NISIC > 0 && defined(USR_STI) + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#endif + +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_global.h> + +/*---------------------------------------------------------------------------* + * USR Sportster TA intern special registers + *---------------------------------------------------------------------------*/ +#define USR_HSCXA_OFF 0x0000 +#define USR_HSCXB_OFF 0x4000 +#define USR_INTL_OFF 0x8000 +#define USR_ISAC_OFF 0xc000 + +#define USR_RES_BIT 0x80 /* 0 = normal, 1 = reset ISAC/HSCX */ +#define USR_INTE_BIT 0x40 /* 0 = IRQ disabled, 1 = IRQ's enabled */ +#define USR_IL_MASK 0x07 /* IRQ level config */ + +static u_char intr_no[] = { 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 3, 4, 5, 0, 6, 7 }; + +#ifdef __FreeBSD__ + +#define ADDR(reg) \ + (((reg/4) * 1024) + ((reg%4) * 2)) + +/*---------------------------------------------------------------------------* + * USRobotics read fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_read_fifo(void *buf, const void *base, size_t len) +{ + register int offset = 0; + + for(;len > 0; len--, offset++) + *((u_char *)buf + offset) = inb((int)base + ADDR(offset)); +} + +/*---------------------------------------------------------------------------* + * USRobotics write fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_fifo(void *base, const void *buf, size_t len) +{ + register int offset = 0; + + for(;len > 0; len--, offset++) + outb((int)base + ADDR(offset), *((u_char *)buf + offset)); +} + +/*---------------------------------------------------------------------------* + * USRobotics write register routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_reg(u_char *base, u_int offset, u_int v) +{ + outb((int)base + ADDR(offset), (u_char)v); +} + +/*---------------------------------------------------------------------------* + * USRobotics read register routine + *---------------------------------------------------------------------------*/ +static u_char +usrtai_read_reg(u_char *base, u_int offset) +{ + return(inb((int)base + ADDR(offset))); +} + +/*---------------------------------------------------------------------------* + * isic_probe_usrtai - probe for USR + *---------------------------------------------------------------------------*/ +int +isic_probe_usrtai(struct isa_device *dev) +{ + struct isic_softc *sc = &isic_sc[dev->id_unit]; + + /* check max unit range */ + + if(dev->id_unit >= ISIC_MAXUNIT) + { + printf("isic%d: Error, unit %d >= MAXUNIT for USR Sportster TA!\n", + dev->id_unit, dev->id_unit); + return(0); + } + sc->sc_unit = dev->id_unit; + + /* check IRQ validity */ + + if((intr_no[ffs(dev->id_irq) - 1]) == 0) + { + printf("isic%d: Error, invalid IRQ [%d] specified for USR Sportster TA!\n", + dev->id_unit, (ffs(dev->id_irq))-1); + return(0); + } + sc->sc_irq = dev->id_irq; + + /* check if memory addr specified */ + + if(dev->id_maddr) + { + printf("isic%d: Error, mem addr 0x%lx specified for USR Sportster TA!\n", + dev->id_unit, (u_long)dev->id_maddr); + return(0); + } + dev->id_msize = 0; + + /* check if we got an iobase */ + + switch(dev->id_iobase) + { + case 0x200: + case 0x208: + case 0x210: + case 0x218: + case 0x220: + case 0x228: + case 0x230: + case 0x238: + case 0x240: + case 0x248: + case 0x250: + case 0x258: + case 0x260: + case 0x268: + case 0x270: + case 0x278: + break; + + default: + printf("isic%d: Error, invalid iobase 0x%x specified for USR Sportster TA!\n", + dev->id_unit, dev->id_iobase); + return(0); + break; + } + sc->sc_port = dev->id_iobase; + + /* setup ISAC access routines */ + + sc->clearirq = NULL; + sc->readreg = usrtai_read_reg; + sc->writereg = usrtai_write_reg; + + sc->readfifo = usrtai_read_fifo; + sc->writefifo = usrtai_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_USRTA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* setup ISAC and HSCX base addr */ + + ISAC_BASE = (caddr_t)dev->id_iobase + USR_ISAC_OFF; + HSCX_A_BASE = (caddr_t)dev->id_iobase + USR_HSCXA_OFF; + HSCX_B_BASE = (caddr_t)dev->id_iobase + USR_HSCXB_OFF; + + /* + * Read HSCX A/B VSTR. Expected value for USR Sportster TA based + * boards is 0x05 in the least significant bits. + */ + + if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || + ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) ) + { + printf("isic%d: HSCX VSTR test failed for USR Sportster TA\n", + dev->id_unit); + printf("isic%d: HSC0: VSTR: %#x\n", + dev->id_unit, HSCX_READ(0, H_VSTR)); + printf("isic%d: HSC1: VSTR: %#x\n", + dev->id_unit, HSCX_READ(1, H_VSTR)); + return (0); + } + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_usrtai - attach USR + *---------------------------------------------------------------------------*/ +int +isic_attach_usrtai(struct isa_device *dev) +{ + u_char irq = 0; + + /* reset the HSCX and ISAC chips */ + + outb(dev->id_iobase + USR_INTL_OFF, USR_RES_BIT); + DELAY(SEC_DELAY / 10); + + outb(dev->id_iobase + USR_INTL_OFF, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + if((irq = intr_no[ffs(dev->id_irq) - 1]) == 0) + { + printf("isic%d: Attach error, invalid IRQ [%d] specified for USR Sportster TA!\n", + dev->id_unit, ffs(dev->id_irq)-1); + return(0); + } + + /* configure and enable irq */ + + outb(dev->id_iobase + USR_INTL_OFF, irq | USR_INTE_BIT); + DELAY(SEC_DELAY / 10); + + return (1); +} + +#else /* end of FreeBSD, start NetBSD */ + +/* + * Use of sc->sc_maps: + * 0 : config register + * 1 - 16 : HSCX A registers + * 17 - 32 : HSCX B registers + * 33 - 48 : ISAC registers + */ + +#define USR_REG_OFFS(reg) ((reg % 4) * 2) +#define USR_HSCXA_MAP(reg) ((reg / 4) + 1) +#define USR_HSCXB_MAP(reg) ((reg / 4) + 17) +#define USR_ISAC_MAP(reg) ((reg / 4) + 33) + +static int map_base[] = { 33, 1, 17, 0 }; /* ISAC, HSCX A, HSCX B */ + +/*---------------------------------------------------------------------------* + * USRobotics read fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + int map, off, offset; + u_char * p = buf; + bus_space_tag_t t; + bus_space_handle_t h; + + for (offset = 0; size > 0; size--, offset++) { + map = map_base[what] + (offset / 4); + t = sc->sc_maps[map].t; + h = sc->sc_maps[map].h; + off = USR_REG_OFFS(offset); + + *p++ = bus_space_read_1(t, h, off); + } +} + +/*---------------------------------------------------------------------------* + * USRobotics write fifo routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + int map, off, offset; + const u_char * p = buf; + bus_space_tag_t t; + bus_space_handle_t h; + u_char v; + + for (offset = 0; size > 0; size--, offset++) { + map = map_base[what] + (offset / 4); + t = sc->sc_maps[map].t; + h = sc->sc_maps[map].h; + off = USR_REG_OFFS(offset); + + v = *p++; + bus_space_write_1(t, h, off, v); + } +} + +/*---------------------------------------------------------------------------* + * USRobotics write register routine + *---------------------------------------------------------------------------*/ +static void +usrtai_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + int map = map_base[what] + (offs / 4), + off = USR_REG_OFFS(offs); + bus_space_tag_t t = sc->sc_maps[map].t; + bus_space_handle_t h = sc->sc_maps[map].h; + + bus_space_write_1(t, h, off, data); +} + +/*---------------------------------------------------------------------------* + * USRobotics read register routine + *---------------------------------------------------------------------------*/ +static u_char +usrtai_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + int map = map_base[what] + (offs / 4), + off = USR_REG_OFFS(offs); + bus_space_tag_t t = sc->sc_maps[map].t; + bus_space_handle_t h = sc->sc_maps[map].h; + + return bus_space_read_1(t, h, off); +} + +/*---------------------------------------------------------------------------* + * isic_probe_usrtai - probe for USR + *---------------------------------------------------------------------------*/ +int +isic_probe_usrtai(struct isic_attach_args *ia) +{ + /* + * Read HSCX A/B VSTR. Expected value for IOM2 based + * boards is 0x05 in the least significant bits. + */ + + if(((bus_space_read_1(ia->ia_maps[USR_HSCXA_MAP(H_VSTR)].t, ia->ia_maps[USR_HSCXA_MAP(H_VSTR)].h, USR_REG_OFFS(H_VSTR)) & 0x0f) != 0x05) || + ((bus_space_read_1(ia->ia_maps[USR_HSCXB_MAP(H_VSTR)].t, ia->ia_maps[USR_HSCXB_MAP(H_VSTR)].h, USR_REG_OFFS(H_VSTR)) & 0x0f) != 0x05)) + return 0; + + return (1); +} + +/*---------------------------------------------------------------------------* + * isic_attach_usrtai - attach USR + *---------------------------------------------------------------------------*/ +int +isic_attach_usrtai(struct isic_softc *sc) +{ + bus_space_tag_t t = sc->sc_maps[0].t; + bus_space_handle_t h = sc->sc_maps[0].h; + u_char irq = intr_no[sc->sc_irq]; + + sc->clearirq = NULL; + sc->readreg = usrtai_read_reg; + sc->writereg = usrtai_write_reg; + + sc->readfifo = usrtai_read_fifo; + sc->writefifo = usrtai_write_fifo; + + /* setup card type */ + + sc->sc_cardtyp = CARD_TYPEP_USRTA; + + /* setup IOM bus type */ + + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* reset the HSCX and ISAC chips */ + + bus_space_write_1(t, h, 0, USR_RES_BIT); + DELAY(SEC_DELAY / 10); + + bus_space_write_1(t, h, 0, 0x00); + DELAY(SEC_DELAY / 10); + + /* setup IRQ */ + + bus_space_write_1(t, h, 0, irq | USR_INTE_BIT); + DELAY(SEC_DELAY / 10); + + return (1); +} + +#endif /* __FreeBSD__ */ + +#endif /* ISIC > 0 */ diff --git a/sys/i4b/layer1/isa_isic.c b/sys/i4b/layer1/isa_isic.c new file mode 100644 index 000000000000..94e4bf7e4151 --- /dev/null +++ b/sys/i4b/layer1/isa_isic.c @@ -0,0 +1,828 @@ +/* + * Copyright (c) 1997, 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isa_isic.c - ISA bus frontend for i4b_isic driver + * -------------------------------------------------- + * + * $Id: isa_isic.c,v 1.18 1998/12/16 13:39:47 hm Exp $ + * + * last edit-date: [Mon Dec 14 10:53:16 1998] + * + * -mh original implementation + * -hm NetBSD patches from Martin + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/isa/isavar.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> + +#if defined(__OpenBSD__) +#define __BROKEN_INDIRECT_CONFIG +#endif + +/* local functions */ +#ifdef __BROKEN_INDIRECT_CONFIG +static int isa_isic_probe __P((struct device *, void *, void *)); +#else +static int isa_isic_probe __P((struct device *, struct cfdata *, void *)); +#endif + +static void isa_isic_attach __P((struct device *, struct device *, void *)); +static int setup_io_map __P((int flags, bus_space_tag_t iot, + bus_space_tag_t memt, bus_size_t iobase, bus_size_t maddr, + int *num_mappings, struct isic_io_map *maps, int *iosize, + int *msize)); +static void args_unmap __P((int *num_mappings, struct isic_io_map *maps)); + +struct cfattach isa_isic_ca = { + sizeof(struct isic_softc), isa_isic_probe, isa_isic_attach +}; + + +/* + * Probe card + */ +static int +#ifdef __BROKEN_INDIRECT_CONFIG +isa_isic_probe(parent, match, aux) +#else +isa_isic_probe(parent, cf, aux) +#endif + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *cf; +#endif + void *aux; +{ +#ifdef __BROKEN_INDIRECT_CONFIG + struct cfdata *cf = ((struct device*)match)->dv_cfdata; +#endif + struct isa_attach_args *ia = aux; + bus_space_tag_t memt = ia->ia_memt, iot = ia->ia_iot; + int flags = cf->cf_flags; + struct isic_attach_args args; + int ret = 0; + + /* check irq */ + if (ia->ia_irq == IRQUNK) { + printf("isic%d: config error: no IRQ specified\n", cf->cf_unit); + return 0; + } + + /* setup MI attach args */ + bzero(&args, sizeof(args)); + args.ia_flags = flags; + + /* if card type specified setup io map for that card */ + switch(flags) + { + case FLAG_TELES_S0_8: + case FLAG_TELES_S0_16: + case FLAG_TELES_S0_163: + case FLAG_AVM_A1: + case FLAG_USR_ISDN_TA_INT: + case FLAG_ITK_IX1: + if (setup_io_map(flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &ia->ia_msize)) { + ret = 0; + goto done; + } + break; + + default: + /* no io map now, will figure card type later */ + break; + } + + /* probe card */ + switch(flags) + { +#ifdef DYNALINK + case FLAG_DYNALINK: + ret = isic_probe_Dyn(&args); + break; +#endif + +#ifdef TEL_S0_8 + case FLAG_TELES_S0_8: + ret = isic_probe_s08(&args); + break; +#endif + +#ifdef TEL_S0_16 + case FLAG_TELES_S0_16: + ret = isic_probe_s016(&args); + break; +#endif + +#ifdef TEL_S0_16_3 + case FLAG_TELES_S0_163: + ret = isic_probe_s0163(&args); + break; +#endif + +#ifdef AVM_A1 + case FLAG_AVM_A1: + ret = isic_probe_avma1(&args); + break; +#endif + +#ifdef USR_STI + case FLAG_USR_ISDN_TA_INT: + ret = isic_probe_usrtai(&args); + break; +#endif + +#ifdef ITKIX1 + case FLAG_ITK_IX1: + ret = isic_probe_itkix1(&args); + break; +#endif + + default: + /* No card type given, try to figure ... */ + if (ia->ia_iobase == IOBASEUNK) { + ret = 0; +#ifdef TEL_S0_8 + /* only Teles S0/8 will work without IO */ + args.ia_flags = FLAG_TELES_S0_8; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s08(&args); + } +#endif /* TEL_S0_8 */ + } else if (ia->ia_maddr == MADDRUNK) { + ret = 0; +#ifdef TEL_S0_16_3 + /* no shared memory, only a 16.3 based card, + AVM A1, the usr sportster or an ITK would work */ + args.ia_flags = FLAG_TELES_S0_163; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s0163(&args); + if (ret) + break; + } +#endif /* TEL_S0_16_3 */ +#ifdef AVM_A1 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_AVM_A1; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_avma1(&args); + if (ret) + break; + } +#endif /* AVM_A1 */ +#ifdef USR_STI + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_USR_ISDN_TA_INT; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_usrtai(&args); + if (ret) + break; + } +#endif /* USR_STI */ + +#ifdef ITKIX1 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_ITK_IX1; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_itkix1(&args); + if (ret) + break; + } +#endif /* ITKIX1 */ + + } else { +#ifdef TEL_S0_16_3 + /* could be anything */ + args.ia_flags = FLAG_TELES_S0_163; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s0163(&args); + if (ret) + break; + } +#endif /* TEL_S0_16_3 */ +#ifdef TEL_S0_16 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_TELES_S0_16; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s016(&args); + if (ret) + break; + } +#endif /* TEL_S0_16 */ +#ifdef AVM_A1 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_AVM_A1; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_avma1(&args); + if (ret) + break; + } +#endif /* AVM_A1 */ +#ifdef TEL_S0_8 + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + args.ia_flags = FLAG_TELES_S0_8; + if (setup_io_map(args.ia_flags, iot, memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], + &(ia->ia_iosize), &(ia->ia_msize)) == 0) + { + ret = isic_probe_s08(&args); + } +#endif /* TEL_S0_8 */ + } + break; + } + +done: + /* unmap resources */ + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + + return ret; +} + +/* + * Attach the card + */ +static void +isa_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isic_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + int flags = sc->sc_dev.dv_cfdata->cf_flags; + int ret = 0; + struct isic_attach_args args; + + /* Setup parameters */ + sc->sc_unit = sc->sc_dev.dv_unit; + sc->sc_irq = ia->ia_irq; + sc->sc_maddr = ia->ia_maddr; + sc->sc_num_mappings = 0; + sc->sc_maps = NULL; + switch(flags) + { + case FLAG_TELES_S0_8: + case FLAG_TELES_S0_16: + case FLAG_TELES_S0_163: + case FLAG_AVM_A1: + case FLAG_USR_ISDN_TA_INT: + setup_io_map(flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &(sc->sc_num_mappings), NULL, NULL, NULL); + MALLOC_MAPS(sc); + setup_io_map(flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &(sc->sc_num_mappings), &(sc->sc_maps[0]), NULL, NULL); + break; + + default: + /* No card type given, try to figure ... */ + + /* setup MI attach args */ + bzero(&args, sizeof(args)); + args.ia_flags = flags; + + /* Probe cards */ + if (ia->ia_iobase == IOBASEUNK) { + ret = 0; +#ifdef TEL_S0_8 + /* only Teles S0/8 will work without IO */ + args.ia_flags = FLAG_TELES_S0_8; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s08(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* TEL_S0_8 */ + } else if (ia->ia_maddr == MADDRUNK) { + /* no shared memory, only a 16.3 based card, + AVM A1, the usr sportster or an ITK would work */ + ret = 0; +#ifdef TEL_S0_16_3 + args.ia_flags = FLAG_TELES_S0_163; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s0163(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* TEL_S0_16_3 */ +#ifdef AVM_A1 + args.ia_flags = FLAG_AVM_A1; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_avma1(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* AVM_A1 */ +#ifdef USR_STI + args.ia_flags = FLAG_USR_ISDN_TA_INT; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_usrtai(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* USR_STI */ +#ifdef ITKIX1 + args.ia_flags = FLAG_ITK_IX1; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_itkix1(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* ITKIX1 */ + } else { + /* could be anything */ + ret = 0; +#ifdef TEL_S0_16_3 + args.ia_flags = FLAG_TELES_S0_163; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s0163(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* TEL_S0_16_3 */ +#ifdef TEL_S0_16 + args.ia_flags = FLAG_TELES_S0_16; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s016(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* TEL_S0_16 */ +#ifdef AVM_A1 + args.ia_flags = FLAG_AVM_A1; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_avma1(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* AVM_A1 */ +#ifdef TEL_S0_8 + args.ia_flags = FLAG_TELES_S0_8; + setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL); + ret = isic_probe_s08(&args); + if (ret) + goto found; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); +#endif /* TEL_S0_8 */ + } + break; + + found: + flags = args.ia_flags; + sc->sc_num_mappings = args.ia_num_mappings; + args_unmap(&args.ia_num_mappings, &args.ia_maps[0]); + if (ret) { + MALLOC_MAPS(sc); + setup_io_map(flags, ia->ia_iot, ia->ia_memt, ia->ia_iobase, ia->ia_maddr, + &(sc->sc_num_mappings), &(sc->sc_maps[0]), NULL, NULL); + } else { + printf(": could not determine card type - not configured!\n"); + return; + } + break; + } + +#if defined(__OpenBSD__) + isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, isicintr, sc, sc->sc_dev.dv_xname); + + /* MI initialization of card */ + isicattach(flags, sc); + +#else + + /* MI initialization of card */ + isicattach(flags, sc); + + /* + * Try to get a level-triggered interrupt first. If that doesn't + * work (like on NetBSD/Atari, try to establish an edge triggered + * interrupt. + */ + if (isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_LEVEL, + IPL_NET, isicintr, sc) == NULL) { + if(isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, + IPL_NET, isicintr, sc) == NULL) { + args_unmap(&(sc->sc_num_mappings), &(sc->sc_maps[0])); + free((sc)->sc_maps, M_DEVBUF); + } + else { + /* + * XXX: This is a hack that probably needs to be + * solved by setting an interrupt type in the sc + * structure. I don't feel familiar enough with the + * code to do this currently. Feel free to contact + * me about it (leo@netbsd.org). + */ + isicintr(sc); + } + } +#endif +} + +/* + * Setup card specific io mapping. Return 0 on success, + * any other value on config error. + * Be prepared to get NULL as maps array. + * Make sure to keep *num_mappings in sync with the real + * mappings already setup when returning! + */ +static int +setup_io_map(flags, iot, memt, iobase, maddr, num_mappings, maps, iosize, msize) + int flags, *num_mappings, *iosize, *msize; + bus_size_t iobase, maddr; + bus_space_tag_t iot, memt; + struct isic_io_map *maps; +{ + /* nothing mapped yet */ + *num_mappings = 0; + + /* which resources do we need? */ + switch(flags) + { + case FLAG_TELES_S0_8: + if (maddr == MADDRUNK) { + printf("isic: config error: no shared memory specified for Teles S0/8!\n"); + return 1; + } + if (iosize) *iosize = 0; /* no i/o ports */ + if (msize) *msize = 0x1000; /* shared memory size */ + + /* this card uses a single memory mapping */ + if (maps == NULL) { + *num_mappings = 1; + return 0; + } + *num_mappings = 0; + maps[0].t = memt; + maps[0].offset = 0; + maps[0].size = 0x1000; + if (bus_space_map(maps[0].t, maddr, + maps[0].size, 0, &maps[0].h)) { + return 1; + } + (*num_mappings)++; + break; + + case FLAG_TELES_S0_16: + if (iobase == IOBASEUNK) { + printf("isic: config error: no i/o address specified for Teles S0/16!\n"); + return 1; + } + if (maddr == MADDRUNK) { + printf("isic: config error: no shared memory specified for Teles S0/16!\n"); + return 1; + } + if (iosize) *iosize = 8; /* i/o ports */ + if (msize) *msize = 0x1000; /* shared memory size */ + + /* one io and one memory mapping */ + if (maps == NULL) { + *num_mappings = 2; + return 0; + } + *num_mappings = 0; + maps[0].t = iot; + maps[0].offset = 0; + maps[0].size = 8; + if (bus_space_map(maps[0].t, iobase, + maps[0].size, 0, &maps[0].h)) { + return 1; + } + (*num_mappings)++; + maps[1].t = memt; + maps[1].offset = 0; + maps[1].size = 0x1000; + if (bus_space_map(maps[1].t, maddr, + maps[1].size, 0, &maps[1].h)) { + return 1; + } + (*num_mappings)++; + break; + + case FLAG_TELES_S0_163: + if (iobase == IOBASEUNK) { + printf("isic: config error: no i/o address specified for Teles S0/16!\n"); + return 1; + } + if (iosize) *iosize = 8; /* only some i/o ports shown */ + if (msize) *msize = 0; /* no shared memory */ + + /* Four io mappings: config, isac, 2 * hscx */ + if (maps == NULL) { + *num_mappings = 4; + return 0; + } + *num_mappings = 0; + maps[0].t = iot; + maps[0].offset = 0; + maps[0].size = 8; + if (bus_space_map(maps[0].t, iobase, + maps[0].size, 0, &maps[0].h)) { + return 1; + } + (*num_mappings)++; + maps[1].t = iot; + maps[1].offset = 0; + maps[1].size = 0x40; /* XXX - ??? */ + if ((iobase - 0xd80 + 0x980) < 0 || (iobase - 0xd80 + 0x980) > 0x0ffff) + return 1; + if (bus_space_map(maps[1].t, iobase - 0xd80 + 0x980, + maps[1].size, 0, &maps[1].h)) { + return 1; + } + (*num_mappings)++; + maps[2].t = iot; + maps[2].offset = 0; + maps[2].size = 0x40; /* XXX - ??? */ + if ((iobase - 0xd80 + 0x180) < 0 || (iobase - 0xd80 + 0x180) > 0x0ffff) + return 1; + if (bus_space_map(maps[2].t, iobase - 0xd80 + 0x180, + maps[2].size, 0, &maps[2].h)) { + return 1; + } + (*num_mappings)++; + maps[3].t = iot; + maps[3].offset = 0; + maps[3].size = 0x40; /* XXX - ??? */ + if ((iobase - 0xd80 + 0x580) < 0 || (iobase - 0xd80 + 0x580) > 0x0ffff) + return 1; + if (bus_space_map(maps[3].t, iobase - 0xd80 + 0x580, + maps[3].size, 0, &maps[3].h)) { + return 1; + } + (*num_mappings)++; + break; + + case FLAG_AVM_A1: + if (iobase == IOBASEUNK) { + printf("isic: config error: no i/o address specified for AVM A1/Fritz! card!\n"); + return 1; + } + if (iosize) *iosize = 8; /* only some i/o ports shown */ + if (msize) *msize = 0; /* no shared memory */ + + /* Seven io mappings: config, isac, 2 * hscx, + isac-fifo, 2 * hscx-fifo */ + if (maps == NULL) { + *num_mappings = 7; + return 0; + } + *num_mappings = 0; + maps[0].t = iot; /* config */ + maps[0].offset = 0; + maps[0].size = 8; + if ((iobase + 0x1800) < 0 || (iobase + 0x1800) > 0x0ffff) + return 1; + if (bus_space_map(maps[0].t, iobase + 0x1800, maps[0].size, 0, &maps[0].h)) + return 1; + (*num_mappings)++; + maps[1].t = iot; /* isac */ + maps[1].offset = 0; + maps[1].size = 0x80; /* XXX - ??? */ + if ((iobase + 0x1400 - 0x20) < 0 || (iobase + 0x1400 - 0x20) > 0x0ffff) + return 1; + if (bus_space_map(maps[1].t, iobase + 0x1400 - 0x20, maps[1].size, 0, &maps[1].h)) + return 1; + (*num_mappings)++; + maps[2].t = iot; /* hscx 0 */ + maps[2].offset = 0; + maps[2].size = 0x40; /* XXX - ??? */ + if ((iobase + 0x400 - 0x20) < 0 || (iobase + 0x400 - 0x20) > 0x0ffff) + return 1; + if (bus_space_map(maps[2].t, iobase + 0x400 - 0x20, maps[2].size, 0, &maps[2].h)) + return 1; + (*num_mappings)++; + maps[3].t = iot; /* hscx 1 */ + maps[3].offset = 0; + maps[3].size = 0x40; /* XXX - ??? */ + if ((iobase + 0xc00 - 0x20) < 0 || (iobase + 0xc00 - 0x20) > 0x0ffff) + return 1; + if (bus_space_map(maps[3].t, iobase + 0xc00 - 0x20, maps[3].size, 0, &maps[3].h)) + return 1; + (*num_mappings)++; + maps[4].t = iot; /* isac-fifo */ + maps[4].offset = 0; + maps[4].size = 1; + if ((iobase + 0x1400 - 0x20 -0x3e0) < 0 || (iobase + 0x1400 - 0x20 -0x3e0) > 0x0ffff) + return 1; + if (bus_space_map(maps[4].t, iobase + 0x1400 - 0x20 -0x3e0, maps[4].size, 0, &maps[4].h)) + return 1; + (*num_mappings)++; + maps[5].t = iot; /* hscx 0 fifo */ + maps[5].offset = 0; + maps[5].size = 1; + if ((iobase + 0x400 - 0x20 -0x3e0) < 0 || (iobase + 0x400 - 0x20 -0x3e0) > 0x0ffff) + return 1; + if (bus_space_map(maps[5].t, iobase + 0x400 - 0x20 -0x3e0, maps[5].size, 0, &maps[5].h)) + return 1; + (*num_mappings)++; + maps[6].t = iot; /* hscx 1 fifo */ + maps[6].offset = 0; + maps[6].size = 1; + if ((iobase + 0xc00 - 0x20 -0x3e0) < 0 || (iobase + 0xc00 - 0x20 -0x3e0) > 0x0ffff) + return 1; + if (bus_space_map(maps[6].t, iobase + 0xc00 - 0x20 -0x3e0, maps[6].size, 0, &maps[6].h)) + return 1; + (*num_mappings)++; + break; + + case FLAG_USR_ISDN_TA_INT: + if (iobase == IOBASEUNK) { + printf("isic: config error: no I/O base specified for USR Sportster TA intern!\n"); + return 1; + } + if (iosize) *iosize = 8; /* scattered ports, only some shown */ + if (msize) *msize = 0; /* no shared memory */ + + /* 49 io mappings: 1 config and 48x8 registers */ + if (maps == NULL) { + *num_mappings = 49; + return 0; + } + *num_mappings = 0; + { + int i, num; + bus_size_t base; + + /* config at offset 0x8000 */ + base = iobase + 0x8000; + maps[0].size = 1; + maps[0].t = iot; + maps[0].offset = 0; + if (base < 0 || base > 0x0ffff) + return 1; + if (bus_space_map(iot, base, 1, 0, &maps[0].h)) { + return 1; + } + *num_mappings = num = 1; + + /* HSCX A at offset 0 */ + base = iobase; + for (i = 0; i < 16; i++) { + maps[num].size = 8; + maps[num].offset = 0; + maps[num].t = iot; + if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) + return 1; + if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) { + return 1; + } + *num_mappings = ++num; + } + /* HSCX B at offset 0x4000 */ + base = iobase + 0x4000; + for (i = 0; i < 16; i++) { + maps[num].size = 8; + maps[num].offset = 0; + maps[num].t = iot; + if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) + return 1; + if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) { + return 1; + } + *num_mappings = ++num; + } + /* ISAC at offset 0xc000 */ + base = iobase + 0xc000; + for (i = 0; i < 16; i++) { + maps[num].size = 8; + maps[num].offset = 0; + maps[num].t = iot; + if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) + return 1; + if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) { + return 1; + } + *num_mappings = ++num; + } + } + break; + + case FLAG_ITK_IX1: + if (iobase == IOBASEUNK) { + printf("isic: config error: no I/O base specified for ITK ix1 micro!\n"); + return 1; + } + if (iosize) *iosize = 4; + if (msize) *msize = 0; + if (maps == NULL) { + *num_mappings = 1; + return 0; + } + *num_mappings = 0; + maps[0].size = 4; + maps[0].t = iot; + maps[0].offset = 0; + if (bus_space_map(iot, iobase, 4, 0, &maps[0].h)) { + return 1; + } + *num_mappings = 1; + break; + + default: + printf("isic: config error: flags do not specify any known card!\n"); + return 1; + break; + } + + return 0; +} + +static void +args_unmap(num_mappings, maps) + int *num_mappings; + struct isic_io_map *maps; +{ + int i, n; + for (i = 0, n = *num_mappings; i < n; i++) + if (maps[i].size) + bus_space_unmap(maps[i].t, maps[i].h, maps[i].size); + *num_mappings = 0; +} diff --git a/sys/i4b/layer1/isapnp_isic.c b/sys/i4b/layer1/isapnp_isic.c new file mode 100644 index 000000000000..9dfdf68c62b3 --- /dev/null +++ b/sys/i4b/layer1/isapnp_isic.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 1997, 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isapnp_isic.c - ISA-P&P bus frontend for i4b_isic driver + * -------------------------------------------------------- + * + * $Id: isapnp_isic.c,v 1.9 1998/12/16 13:39:47 hm Exp $ + * + * last edit-date: [Mon Dec 14 10:54:23 1998] + * + * -mh original implementation + * -hm NetBSD patches from Martin + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/isa/isavar.h> +#include <dev/isapnp/isapnpreg.h> +#include <dev/isapnp/isapnpvar.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_ipac.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_global.h> + +#ifdef __BROKEN_INDIRECT_CONFIG +static int isapnp_isic_probe __P((struct device *, void *, void *)); +#else +static int isapnp_isic_probe __P((struct device *, struct cfdata *, void *)); +#endif +static void isapnp_isic_attach __P((struct device *, struct device *, void *)); + +struct cfattach isapnp_isic_ca = { + sizeof(struct isic_softc), isapnp_isic_probe, isapnp_isic_attach +}; + +typedef void (*allocmaps_func)(struct isapnp_attach_args *ipa, struct isic_softc *sc); +typedef void (*attach_func)(struct isic_softc *sc); + +/* map allocators */ +static void generic_pnp_mapalloc(struct isapnp_attach_args *ipa, struct isic_softc *sc); +static void ngo_pnp_mapalloc(struct isapnp_attach_args *ipa, struct isic_softc *sc); +static void tls_pnp_mapalloc(struct isapnp_attach_args *ipa, struct isic_softc *sc); + +/* card attach functions */ +extern void isic_attach_Cs0P __P((struct isic_softc *sc)); +extern void isic_attach_Dyn __P((struct isic_softc *sc)); +extern void isic_attach_s0163P __P((struct isic_softc *sc)); +extern void isic_attach_drnngo __P((struct isic_softc *sc)); +extern void isic_attach_sws __P((struct isic_softc *sc)); +extern void isic_attach_Eqs1pi __P((struct isic_softc *sc)); + +struct isapnp_isic_card_desc { + char *devlogic; /* ISAPNP logical device ID */ + char *name; /* Name of the card */ + int card_type; /* isic card type identifier */ + allocmaps_func allocmaps; /* map allocator function */ + attach_func attach; /* card attach and init function */ +}; +static const struct isapnp_isic_card_desc +isapnp_isic_descriptions[] = +{ +#ifdef CRTX_S0_P + { "CTX0000", "Creatix ISDN S0-16 P&P", CARD_TYPEP_CS0P, + tls_pnp_mapalloc, isic_attach_Cs0P }, +#endif +#ifdef TEL_S0_16_3_P + { "TAG2110", "Teles S0/PnP", CARD_TYPEP_163P, + tls_pnp_mapalloc, isic_attach_s0163P }, +#endif +#ifdef DRN_NGO + { "SDA0150", "Dr. Neuhaus NICCY GO@", CARD_TYPEP_DRNNGO, + ngo_pnp_mapalloc, isic_attach_drnngo }, +#endif +#ifdef ELSA_QS1ISA + { "ELS0133", "Elsa QuickStep 1000 (ISA)", CARD_TYPEP_ELSAQS1ISA, + generic_pnp_mapalloc, isic_attach_Eqs1pi }, +#endif +#ifdef SEDLBAUER + { "SAG0001", "Sedlbauer WinSpeed", CARD_TYPEP_SWS, + generic_pnp_mapalloc, isic_attach_sws }, +#endif +#ifdef DYNALINK + { "ASU1688", "Dynalink IS64PH", CARD_TYPEP_DYNALINK, + generic_pnp_mapalloc, isic_attach_Dyn }, +#endif +}; +#define NUM_DESCRIPTIONS (sizeof(isapnp_isic_descriptions)/sizeof(isapnp_isic_descriptions[0])) + +/* + * Probe card + */ +static int +#ifdef __BROKEN_INDIRECT_CONFIG +isapnp_isic_probe(parent, match, aux) +#else +isapnp_isic_probe(parent, cf, aux) +#endif + struct device *parent; +#ifdef __BROKEN_INDIRECT_CONFIG + void *match; +#else + struct cfdata *cf; +#endif + void *aux; +{ + struct isapnp_attach_args *ipa = aux; + const struct isapnp_isic_card_desc *desc = isapnp_isic_descriptions; + int i; + + for (i = 0; i < NUM_DESCRIPTIONS; i++, desc++) + if (strcmp(ipa->ipa_devlogic, desc->devlogic) == 0) + return 1; + + return 0; +} + + +/*---------------------------------------------------------------------------* + * card independend attach for ISA P&P cards + *---------------------------------------------------------------------------*/ + +/* parameter and format for message producing e.g. "isic0: " */ + +#ifdef __FreeBSD__ +#define ISIC_FMT "isic%d: " +#define ISIC_PARM dev->id_unit +#define TERMFMT " " +#else +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" +#endif + +static void +isapnp_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + struct isic_softc *sc = (void *)self; + struct isapnp_attach_args *ipa = aux; + const struct isapnp_isic_card_desc *desc = isapnp_isic_descriptions; + int i; + + for (i = 0; i < NUM_DESCRIPTIONS; i++, desc++) + if (strcmp(ipa->ipa_devlogic, desc->devlogic) == 0) + break; + if (i >= NUM_DESCRIPTIONS) + panic("could not identify isic PnP device"); + + /* setup parameters */ + sc->sc_cardtyp = desc->card_type; + sc->sc_unit = sc->sc_dev.dv_unit; + sc->sc_irq = ipa->ipa_irq[0].num; + desc->allocmaps(ipa, sc); + + /* announce card name */ + printf(": %s\n", desc->name); + + /* establish interrupt handler */ + isa_intr_establish(ipa->ipa_ic, ipa->ipa_irq[0].num, IST_EDGE, + IPL_NET, isicintr, sc); + + /* init card */ + isic_sc[sc->sc_unit] = sc; + desc->attach(sc); + + /* announce chip versions */ + sc->sc_isac_version = 0; + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return; + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return; + break; + }; + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce chip versions */ + + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } +} + +static void +generic_pnp_mapalloc(struct isapnp_attach_args *ipa, struct isic_softc *sc) +{ + sc->sc_num_mappings = 1; /* most cards have just one mapping */ + MALLOC_MAPS(sc); /* malloc the maps */ + sc->sc_maps[0].t = ipa->ipa_iot; /* copy the access handles */ + sc->sc_maps[0].h = ipa->ipa_io[0].h; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ +} + +static void +ngo_pnp_mapalloc(struct isapnp_attach_args *ipa, struct isic_softc *sc) +{ + sc->sc_num_mappings = 2; /* one data, one address mapping */ + MALLOC_MAPS(sc); /* malloc the maps */ + sc->sc_maps[0].t = ipa->ipa_iot; /* copy the access handles */ + sc->sc_maps[0].h = ipa->ipa_io[0].h; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ + sc->sc_maps[1].t = ipa->ipa_iot; + sc->sc_maps[1].h = ipa->ipa_io[1].h; + sc->sc_maps[1].size = 0; +} + +static void +tls_pnp_mapalloc(struct isapnp_attach_args *ipa, struct isic_softc *sc) +{ + sc->sc_num_mappings = 4; /* config, isac, 2 * hscx */ + MALLOC_MAPS(sc); /* malloc the maps */ + sc->sc_maps[0].t = ipa->ipa_iot; /* copy the access handles */ + sc->sc_maps[0].h = ipa->ipa_io[0].h; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ + sc->sc_maps[1].t = ipa->ipa_iot; + sc->sc_maps[1].h = ipa->ipa_io[0].h; + sc->sc_maps[1].size = 0; + sc->sc_maps[1].offset = - 0x20; + sc->sc_maps[2].t = ipa->ipa_iot; + sc->sc_maps[2].offset = - 0x20; + sc->sc_maps[2].h = ipa->ipa_io[1].h; + sc->sc_maps[2].size = 0; + sc->sc_maps[3].t = ipa->ipa_iot; + sc->sc_maps[3].offset = 0; + sc->sc_maps[3].h = ipa->ipa_io[1].h; + sc->sc_maps[3].size = 0; +} diff --git a/sys/i4b/layer1/isic_supio.c b/sys/i4b/layer1/isic_supio.c new file mode 100644 index 000000000000..6c58ad218425 --- /dev/null +++ b/sys/i4b/layer1/isic_supio.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 1998 Ignatios Souvatzis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * isic_supio.c - Amiga supio pseudo bus frontend for i4b_isic driver + * supports: + * - ISDN Blaster 5001/1 + * - ISDN Master 2092/64 + * But we attach to the supio, so just see "isic". + * ----------------------------------------------- + * + * $Id: isic_supio.c,v 1.5 1998/12/19 12:07:55 hm Exp $ + * + * last edit-date: [Mon Nov 16 12:29:19 1998] + * + * -is original implementation + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <amiga/dev/supio.h> + +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_hscx.h> +#include <i4b/layer1/i4b_isac.h> + +/*static*/ int isic_supio_match __P((struct device *, struct cfdata *, void *)); +/*static*/ void isic_supio_attach __P((struct device *, struct device *, void *)); + +/*static*/ u_int8_t aster_read_reg __P((struct isic_softc *sc, int what, + bus_size_t offs)); +/*static*/ void aster_write_reg __P((struct isic_softc *sc, int what, + bus_size_t offs, u_int8_t data)); +/*static*/ void aster_read_fifo __P((struct isic_softc *sc, int what, + void *buf, size_t size)); +/*static*/ void aster_write_fifo __P((struct isic_softc *sc, int what, + const void *data, size_t size)); + +static int supio_isicattach __P((struct isic_softc *sc)); + +struct isic_supio_softc { + struct isic_softc sc_isic; + struct isr sc_isr; + struct bus_space_tag sc_bst; +}; + +struct cfattach isic_supio_ca = { + sizeof(struct isic_supio_softc), isic_supio_match, isic_supio_attach +}; + +/* + * Probe card + */ +/*static*/ int +isic_supio_match(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + struct supio_attach_args *sap = aux; + + /* ARGSUSED */ + return (!strcmp("isic", sap->supio_name)); +} + +int isic_supio_ipl = 2; +/* + * Attach the card + */ +/*static*/ void +isic_supio_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isic_supio_softc *ssc = (void *)self; + struct isic_softc *sc = &ssc->sc_isic; + struct supio_attach_args *sap = aux; + + bus_space_tag_t bst; + bus_space_handle_t h; + + /* setup parameters */ + sc->sc_cardtyp = CARD_TYPEP_BLMASTER; + sc->sc_num_mappings = 3; + sc->sc_unit = sc->sc_dev.dv_unit; /* XXX ??? */ + + /* create io mappings */ + MALLOC_MAPS(sc); + + bst = sap->supio_iot; + bus_space_map(bst, sap->supio_iobase, 0x400, 0, &h); + + /* ISAC */ + sc->sc_maps[0].t = bst; + sc->sc_maps[0].h = h; + sc->sc_maps[0].offset = 0x300/2; + sc->sc_maps[0].size = 0; /* foreign mapping, leave it alone */ + + /* HSCX A */ + sc->sc_maps[1].t = bst; + sc->sc_maps[1].h = h; + sc->sc_maps[1].offset = 0x100/2; + sc->sc_maps[1].size = 0; /* foreign mapping, leave it alone */ + + /* HSCX B */ + sc->sc_maps[2].t = bst; + sc->sc_maps[2].h = h; + sc->sc_maps[2].offset = 0x180/2; + sc->sc_maps[2].size = 0; /* foreign mapping, leave it alone */ + + sc->clearirq = NULL; + sc->readreg = aster_read_reg; + sc->writereg = aster_write_reg; + sc->readfifo = aster_read_fifo; + sc->writefifo = aster_write_fifo; + + /* setup card type */ + sc->sc_cardtyp = CARD_TYPEP_BLMASTER; + sc->sc_bustyp = BUS_TYPE_IOM2; + + sc->sc_ipac = 0; + sc->sc_bfifolen = HSCX_FIFO_LEN; + + /* enable RTS on HSCX A */ + aster_write_reg(sc, ISIC_WHAT_HSCXA, H_MODE, HSCX_MODE_RTS); + + /* MI initialization of card */ + + printf("\n"); + supio_isicattach(sc); + + ssc->sc_isr.isr_intr = isicintr; + ssc->sc_isr.isr_arg = sc; + ssc->sc_isr.isr_ipl = isic_supio_ipl; /* XXX */ + add_isr(&ssc->sc_isr); +} + +#if 0 +int +isic_supiointr(p) + void *p; +{ + /* XXX should test whether it is our interupt at all */ + add_sicallback((sifunc_t)isicintr, p, NULL); + return 1; +} +#endif + +/*static*/ void +aster_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what].t; + bus_space_handle_t h = sc->sc_maps[what].h; + bus_size_t o = sc->sc_maps[what].offset; + + bus_space_read_multi_1(t, h, o, buf, size); +} + +/*static*/ void +aster_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size) +{ + bus_space_tag_t t = sc->sc_maps[what].t; + bus_space_handle_t h = sc->sc_maps[what].h; + bus_size_t o = sc->sc_maps[what].offset; + + bus_space_write_multi_1(t, h, o, (u_int8_t*)buf, size); +} + +/*static*/ u_int8_t +aster_read_reg(struct isic_softc *sc, int what, bus_size_t offs) +{ + bus_space_tag_t t = sc->sc_maps[what].t; + bus_space_handle_t h = sc->sc_maps[what].h; + bus_size_t o = sc->sc_maps[what].offset; + + return bus_space_read_1(t, h, o + offs); +} + +/*static*/ void +aster_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data) +{ + bus_space_tag_t t = sc->sc_maps[what].t; + bus_space_handle_t h = sc->sc_maps[what].h; + bus_size_t o = sc->sc_maps[what].offset; + + bus_space_write_1(t, h, o + offs, data); +} + +/*---------------------------------------------------------------------------* + * card independend attach for pcmcia^Wsupio cards + * XXX this should be centralized! + *---------------------------------------------------------------------------*/ + +/* + * parameter and format for message producing e.g. "isic0: " + * there is no FreeBSD/Amiga, so just: + */ + +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" + +int +supio_isicattach(struct isic_softc *sc) +{ + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + isic_sc[sc->sc_unit] = sc; + sc->sc_isac_version = 0; + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return(0); + break; + }; + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce chip versions */ + + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } + + return(1); +} + diff --git a/sys/i4b/layer1/pci_isic.c b/sys/i4b/layer1/pci_isic.c new file mode 100644 index 000000000000..6f929e52cca6 --- /dev/null +++ b/sys/i4b/layer1/pci_isic.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * pci_isic.c - pcmcia bus frontend for i4b_isic driver + * ------------------------------------------------------- + * + * $Id: pci_isic.c,v 1.1 1998/12/16 13:39:47 hm Exp $ + * + * last edit-date: [Mon Nov 16 20:37:32 1998] + * + * -mh original implementation + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + + +#include <machine/bus.h> +#include <machine/intr.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_ipac.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> + +static int pci_isic_match __P((struct device *, struct cfdata *, void *)); +static void pci_isic_attach __P((struct device *, struct device *, void *)); +static const struct isic_pci_product * find_matching_card __P((struct pci_attach_args *pa)); + +extern void isic_attach_Eqs1pp __P((struct isic_softc *sc, struct pci_attach_args *pa)); +static int isic_pciattach __P((struct isic_softc *sc)); + +struct pci_isic_softc { + struct isic_softc sc_isic; /* parent class */ + + /* PCI-specific goo */ + void *sc_ih; /* interrupt handler */ +}; + +struct cfattach pci_isic_ca = { + sizeof(struct pci_isic_softc), pci_isic_match, pci_isic_attach +}; + + +static const struct isic_pci_product { + pci_vendor_id_t npp_vendor; + pci_product_id_t npp_product; + int cardtype; + int flag; + const char * name; + void (*attach)(struct isic_softc *sc, struct pci_attach_args *pa); +} isic_pci_products[] = { + { PCI_VENDOR_ELSA, 0x1000, + CARD_TYPEP_ELSAQS1PCI, FLAG_ELSA_QS1P_PCI, + "ELSA QuickStep 1000pro/PCI", + isic_attach_Eqs1pp }, + + { 0, 0, 0, 0, NULL, NULL }, +}; + +static const struct isic_pci_product * find_matching_card(pa) + struct pci_attach_args *pa; +{ + const struct isic_pci_product * pp = NULL; + + for (pp = isic_pci_products; pp->npp_vendor; pp++) + if (PCI_VENDOR(pa->pa_id) == pp->npp_vendor && + PCI_PRODUCT(pa->pa_id) == pp->npp_product) + return pp; + + return NULL; +} + +/* + * Match card + */ +static int +pci_isic_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pci_attach_args *pa = aux; + + if (!find_matching_card(pa)) + return 0; + + return 1; +} + +/* + * Attach the card + */ +static void +pci_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pci_isic_softc *psc = (void*) self; + struct isic_softc *sc = &psc->sc_isic; + struct pci_attach_args *pa = aux; + pci_chipset_tag_t pc = pa->pa_pc; + pci_intr_handle_t ih; + const struct isic_pci_product * prod; + const char *intrstr; + + /* Redo probe */ + prod = find_matching_card(pa); + if (prod == NULL) return; /* oops - not found?!? */ + + sc->sc_unit = sc->sc_dev.dv_unit; + printf(": %s\n", prod->name); + + /* card initilization and sc setup */ + prod->attach(sc, pa); + + /* generic setup */ + isic_pciattach(sc); + + /* Map and establish the interrupt. */ + if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &ih)) { + printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); + return; + } + intrstr = pci_intr_string(pc, ih); + psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, isicintr, sc); + if (psc->sc_ih == NULL) { + printf("%s: couldn't establish interrupt", + sc->sc_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); +} + +/*---------------------------------------------------------------------------* + * isic - pci device driver attach routine + *---------------------------------------------------------------------------*/ +static int +isic_pciattach(sc) + struct isic_softc *sc; +{ + int ret = 0; + + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + isic_sc[sc->sc_unit] = sc; /* XXX - hack! */ + + sc->sc_isac_version = 0; + sc->sc_hscx_version = 0; + + if(sc->sc_ipac) + { + ret = IPAC_READ(IPAC_ID); + + switch(ret) + { + case 0x01: + printf("%s: IPAC PSB2115 Version 1.1\n", sc->sc_dev.dv_xname); + break; + + default: + printf("%s: Error, IPAC version %d unknown!\n", + sc->sc_dev.dv_xname, ret); + return(0); + break; + } + } + else + { + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + printf("%s: ISAC %s (IOM-%c)\n", + sc->sc_dev.dv_xname, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + break; + + default: + printf("%s: Error, ISAC version %d unknown!\n", + sc->sc_dev.dv_xname, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + printf("%s: HSCX %s\n", + sc->sc_dev.dv_xname, + HSCXversion[sc->sc_hscx_version]); + break; + + default: + printf("%s: Error, HSCX version %d unknown!\n", + sc->sc_dev.dv_xname, sc->sc_hscx_version); + return(0); + break; + } + } + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + +#if defined(__FreeBSD__) && __FreeBSD__ >=3 + callout_handle_init(&sc->sc_T3_callout); + callout_handle_init(&sc->sc_T4_callout); +#endif + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + return(1); +} + diff --git a/sys/i4b/layer1/pcmcia_isic.c b/sys/i4b/layer1/pcmcia_isic.c new file mode 100644 index 000000000000..9d428a1b3cef --- /dev/null +++ b/sys/i4b/layer1/pcmcia_isic.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * pcmcia_isic.c - pcmcia bus frontend for i4b_isic driver + * ------------------------------------------------------- + * + * $Id: pcmcia_isic.c,v 1.3 1998/12/05 18:05:04 hm Exp $ + * + * last edit-date: [Fri Dec 4 10:38:43 1998] + * + * -mh original implementation + * + *---------------------------------------------------------------------------*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/systm.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/pcmcia/pcmciareg.h> +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciadevs.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/layer1/i4b_l1.h> +#include <i4b/layer1/i4b_ipac.h> +#include <i4b/layer1/i4b_isac.h> +#include <i4b/layer1/i4b_hscx.h> + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer1/pcmcia_isic.h> + +static int pcmcia_isic_match __P((struct device *, struct cfdata *, void *)); +static void pcmcia_isic_attach __P((struct device *, struct device *, void *)); +static const struct isic_pcmcia_card_entry * find_matching_card __P((struct pcmcia_attach_args *pa)); +static int pcmcia_isicattach __P((struct isic_softc *sc)); + +struct cfattach pcmcia_isic_ca = { + sizeof(struct pcmcia_isic_softc), pcmcia_isic_match, pcmcia_isic_attach +}; + +struct isic_pcmcia_card_entry { + int32_t vendor; /* vendor ID */ + int32_t product; /* product ID */ + char *cis1_info[4]; /* CIS info to match */ + char *name; /* name of controller */ + int function; /* expected PCMCIA function type */ + int card_type; /* card type found */ + isic_pcmcia_attach_func attach; /* card initialization */ +}; + +static const struct isic_pcmcia_card_entry card_list[] = { + +#ifdef AVM_PCMCIA + { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, + { "AVM", "ISDN A", NULL, NULL }, + "AVM Fritz!Card", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_PCFRITZ, isic_attach_fritzpcmcia }, +#endif + +#ifdef ELSA_ISDNMC + { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, + { "ELSA GmbH, Aachen", "MicroLink ISDN/MC ", NULL, NULL }, + "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc }, + { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, + { "ELSA AG, Aachen", "MicroLink ISDN/MC ", NULL, NULL }, + "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc }, +#endif + +#ifdef ELSA_MCALL + { 0x105, 0x410a, + { "ELSA", "MicroLink MC all", NULL, NULL }, + "ELSA MicroLink MCall", PCMCIA_FUNCTION_NETWORK, + CARD_TYPEP_ELSAMLMCALL, isic_attach_elsamcall }, +#endif + +}; +#define NUM_MATCH_ENTRIES (sizeof(card_list)/sizeof(card_list[0])) + +static const struct isic_pcmcia_card_entry * +find_matching_card(pa) + struct pcmcia_attach_args *pa; +{ + int i, j; + + for (i = 0; i < NUM_MATCH_ENTRIES; i++) { + if (card_list[i].vendor != PCMCIA_VENDOR_INVALID && pa->card->manufacturer != card_list[i].vendor) + continue; + if (card_list[i].product != PCMCIA_PRODUCT_INVALID && pa->card->product != card_list[i].product) + continue; + if (pa->pf->function != card_list[i].function) + continue; + for (j = 0; j < 4; j++) { + if (card_list[i].cis1_info[j] == NULL) + continue; /* wildcard */ + if (pa->card->cis1_info[j] == NULL) + break; /* not available */ + if (strcmp(pa->card->cis1_info[j], card_list[i].cis1_info[j]) != 0) + break; /* mismatch */ + } + if (j >= 4) + break; + } + if (i >= NUM_MATCH_ENTRIES) + return NULL; + + return &card_list[i]; +} + +/* + * Match card + */ +static int +pcmcia_isic_match(parent, match, aux) + struct device *parent; + struct cfdata *match; + void *aux; +{ + struct pcmcia_attach_args *pa = aux; + + if (!find_matching_card(pa)) + return 0; + + return 1; +} + +/* + * Attach the card + */ +static void +pcmcia_isic_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pcmcia_isic_softc *psc = (void*) self; + struct isic_softc *sc = &psc->sc_isic; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_config_entry *cfe; + const struct isic_pcmcia_card_entry * cde; + + /* Which card is it? */ + cde = find_matching_card(pa); + if (cde == NULL) return; /* oops - not found?!? */ + + psc->sc_pf = pa->pf; + cfe = pa->pf->cfe_head.sqh_first; + + /* Enable the card */ + pcmcia_function_init(pa->pf, cfe); + pcmcia_function_enable(pa->pf); + + if (!cde->attach(psc, cfe, pa)) + return; /* Ooops ? */ + + sc->sc_unit = sc->sc_dev.dv_unit; + + /* Announce card name */ + printf(": %s\n", cde->name); + + /* MI initilization */ + pcmcia_isicattach(sc); + + /* setup interrupt */ + psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, isicintr, sc); +} + +/*---------------------------------------------------------------------------* + * card independend attach for pcmicia cards + *---------------------------------------------------------------------------*/ + +/* parameter and format for message producing e.g. "isic0: " */ + +#ifdef __FreeBSD__ +#define ISIC_FMT "isic%d: " +#define ISIC_PARM dev->id_unit +#define TERMFMT " " +#else +#define ISIC_FMT "%s: " +#define ISIC_PARM sc->sc_dev.dv_xname +#define TERMFMT "\n" +#endif + +int +pcmcia_isicattach(struct isic_softc *sc) +{ + static char *ISACversion[] = { + "2085 Version A1/A2 or 2086/2186 Version 1.1", + "2085 Version B1", + "2085 Version B2", + "2085 Version V2.3 (B3)", + "Unknown Version" + }; + + static char *HSCXversion[] = { + "82525 Version A1", + "Unknown (0x01)", + "82525 Version A2", + "Unknown (0x03)", + "82525 Version A3", + "82525 or 21525 Version 2.1", + "Unknown Version" + }; + + isic_sc[sc->sc_unit] = sc; + sc->sc_isac_version = 0; + sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03; + + switch(sc->sc_isac_version) + { + case ISAC_VA: + case ISAC_VB1: + case ISAC_VB2: + case ISAC_VB3: + break; + + default: + printf(ISIC_FMT "Error, ISAC version %d unknown!\n", + ISIC_PARM, sc->sc_isac_version); + return(0); + break; + } + + sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf; + + switch(sc->sc_hscx_version) + { + case HSCX_VA1: + case HSCX_VA2: + case HSCX_VA3: + case HSCX_V21: + break; + + default: + printf(ISIC_FMT "Error, HSCX version %d unknown!\n", + ISIC_PARM, sc->sc_hscx_version); + return(0); + break; + }; + + /* ISAC setup */ + + isic_isac_init(sc); + + /* HSCX setup */ + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); + + isic_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); + + /* setup linktab */ + + isic_init_linktab(sc); + + /* set trace level */ + + sc->sc_trace = TRACE_OFF; + + sc->sc_state = ISAC_IDLE; + + sc->sc_ibuf = NULL; + sc->sc_ib = NULL; + sc->sc_ilen = 0; + + sc->sc_obuf = NULL; + sc->sc_op = NULL; + sc->sc_ol = 0; + sc->sc_freeflag = 0; + + sc->sc_obuf2 = NULL; + sc->sc_freeflag2 = 0; + + /* init higher protocol layers */ + + MPH_Status_Ind(sc->sc_unit, STI_ATTACH, sc->sc_cardtyp); + + /* announce chip versions */ + + if(sc->sc_isac_version >= ISAC_UNKN) + { + printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_isac_version); + sc->sc_isac_version = ISAC_UNKN; + } + else + { + printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT, + ISIC_PARM, + ISACversion[sc->sc_isac_version], + sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); + } + + if(sc->sc_hscx_version >= HSCX_UNKN) + { + printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT, + ISIC_PARM, + sc->sc_hscx_version); + sc->sc_hscx_version = HSCX_UNKN; + } + else + { + printf(ISIC_FMT "HSCX %s" TERMFMT, + ISIC_PARM, + HSCXversion[sc->sc_hscx_version]); + } + + return(1); +} + diff --git a/sys/i4b/layer1/pcmcia_isic.h b/sys/i4b/layer1/pcmcia_isic.h new file mode 100644 index 000000000000..73f52d693020 --- /dev/null +++ b/sys/i4b/layer1/pcmcia_isic.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1998 Martin Husemann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 4. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software and/or documentation. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * pcmcia_isic.h - common definitions for pcmcia isic cards + * -------------------------------------------------------- + * + * $Id: pcmcia_isic.h,v 1.1 1998/12/02 06:44:30 hm Exp $ + * + * last edit-date: [Mon Nov 30 21:19:14 1998] + * + * -mh original implementation + * + *---------------------------------------------------------------------------*/ + +struct pcmcia_isic_softc { + struct isic_softc sc_isic; /* parent class */ + + /* PCMCIA-specific goo */ + struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ + int sc_io_window; /* our i/o window */ + struct pcmcia_function *sc_pf; /* our PCMCIA function */ + void *sc_ih; /* interrupt handler */ +}; + +typedef int (*isic_pcmcia_attach_func)(struct pcmcia_isic_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); + +extern int isic_attach_fritzpcmcia(struct pcmcia_isic_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); +extern int isic_attach_elsaisdnmc(struct pcmcia_isic_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); +extern int isic_attach_elsamcall(struct pcmcia_isic_softc *sc, struct pcmcia_config_entry *cfe, struct pcmcia_attach_args *pa); + + diff --git a/sys/i4b/layer2/i4b_iframe.c b/sys/i4b/layer2/i4b_iframe.c new file mode 100644 index 000000000000..c5e38d80f8ec --- /dev/null +++ b/sys/i4b/layer2/i4b_iframe.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_iframe.c - i frame handling routines + * ------------------------------------------ + * + * $Id: i4b_iframe.c,v 1.15 1998/12/05 18:05:06 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:26:16 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_trace.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_trace.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * process i frame + * implements the routine "I COMMAND" Q.921 03/93 pp 77 + *---------------------------------------------------------------------------*/ +void +i4b_rxd_i_frame(int unit, struct mbuf *m) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + u_char *ptr = m->m_data; + int nr; + int ns; + int p; + int x; + + if(!((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI))))) + { + i4b_Dfreembuf(m); + return; + } + + if((l2sc->Q921_state != ST_MULTIFR) && (l2sc->Q921_state != ST_TIMREC)) + { + i4b_Dfreembuf(m); + DBGL2(L2_I_ERR, "i4b_rxd_i_frame", ("ERROR, state != (MF || TR)!\n")); + return; + } + + x = SPLI4B(); + + nr = GETINR(*(ptr + OFF_INR)); + ns = GETINS(*(ptr + OFF_INS)); + p = GETIP(*(ptr + OFF_INR)); + + i4b_rxd_ack(l2sc, nr); /* last packet ack */ + + if(l2sc->own_busy) /* own receiver busy ? */ + { + i4b_Dfreembuf(m); /* yes, discard information */ + + if(p == 1) /* P bit == 1 ? */ + { + i4b_tx_rnr_response(l2sc, p); /* yes, tx RNR */ + l2sc->ack_pend = 0; /* clear ACK pending */ + } + } + else /* own receiver ready */ + { + if(ns == l2sc->vr) /* expected sequence number ? */ + { + M128INC(l2sc->vr); /* yes, update */ + + l2sc->rej_excpt = 0; /* clr reject exception */ + + m_adj(m, I_HDR_LEN); /* strip i frame header */ + + l2sc->iframe_sent = 0; /* reset i acked already */ + + DL_Data_Ind(l2sc->unit, m); /* pass data up */ + + if(!l2sc->iframe_sent) + { + i4b_tx_rr_response(l2sc, p); /* yes, tx RR */ + l2sc->ack_pend = 0; /* clr ACK pending */ + } + } + else /* ERROR, sequence number NOT expected */ + { + i4b_Dfreembuf(m); /* discard information */ + + if(l2sc->rej_excpt == 1) /* already exception ? */ + { + if(p == 1) /* immediate response ? */ + { + i4b_tx_rr_response(l2sc, p); /* yes, tx RR */ + l2sc->ack_pend = 0; /* clr ack pend */ + } + } + else /* not in exception cond */ + { + l2sc->rej_excpt = 1; /* set exception */ + i4b_tx_rej_response(l2sc, p); /* tx REJ */ + l2sc->ack_pend = 0; /* clr ack pending */ + } + } + } + + /* sequence number ranges as expected ? */ + + if(i4b_l2_nr_ok(nr, l2sc->va, l2sc->vs)) + { + if(l2sc->Q921_state == ST_TIMREC) + { + l2sc->va = nr; + splx(x); + return; + } + + if(l2sc->peer_busy) /* yes, other side busy ? */ + { + l2sc->va = nr; /* yes, update ack count */ + } + else /* other side ready */ + { + if(nr == l2sc->vs) /* count expected ? */ + { + l2sc->va = nr; /* update ack */ + i4b_T200_stop(l2sc); + i4b_T203_restart(l2sc); + } + else + { + if(nr != l2sc->va) + { + l2sc->va = nr; + i4b_T200_restart(l2sc); + } + } + } + } + else + { + i4b_nr_error_recovery(l2sc); /* sequence error */ + l2sc->Q921_state = ST_AW_EST; + } + splx(x); +} + +/*---------------------------------------------------------------------------* + * internal I FRAME QUEUED UP routine (Q.921 03/93 p 61) + *---------------------------------------------------------------------------*/ +void +i4b_i_frame_queued_up(l2_softc_t *l2sc) +{ + int x; + struct mbuf *m; + u_char *ptr; + + x = SPLI4B(); + + if(l2sc->peer_busy) + { + DBGL2(L2_I_MSG, "i4b_i_frame_queued_up", ("peer busy!\n")); + i4b_print_l2var(l2sc); + splx(x); + return; + } + + if(l2sc->vs == ((l2sc->va + MAX_K_VALUE) & 127)) + { + DBGL2(L2_I_ERR, "i4b_i_frame_queued_up", ("V(S) == ((V(A) + k) & 127)!\n")); + DBGL2(L2_I_ERR, "i4b_i_frame_queued_up", ("state = %s\n", i4b_print_l2state(l2sc))); + i4b_print_l2var(l2sc); + splx(x); + return; + } + + IF_DEQUEUE(&l2sc->i_queue, m); /* fetch next frame to tx */ + + if(!m) + { + DBGL2(L2_I_ERR, "i4b_i_frame_queued_up", ("ERROR, mbuf NULL after IF_DEQUEUE\n")); + splx(x); + return; + } + + ptr = m->m_data; + + PUTSAPI(SAPI_CCP, CR_CMD_TO_NT, *(ptr + OFF_SAPI)); + PUTTEI(l2sc->tei, *(ptr + OFF_TEI)); + + *(ptr + OFF_INS) = (l2sc->vs << 1) & 0xfe; /* bit 0 = 0 */ + *(ptr + OFF_INR) = (l2sc->vr << 1) & 0xfe; /* P bit = 0 */ + + PH_Data_Req(l2sc->unit, m, MBUF_DONTFREE); /* free'd when ack'd ! */ + + l2sc->iframe_sent = 1; /* in case we ack an I frame with another I frame */ + + if(l2sc->ua_num != UA_EMPTY) /* failsafe */ + { + DBGL2(L2_I_ERR, "i4b_i_frame_queued_up", ("ERROR, l2sc->ua_num: %d != UA_EMPTY\n", l2sc->ua_num)); + i4b_print_l2var(l2sc); + i4b_Dfreembuf(l2sc->ua_frame); + } + + l2sc->ua_frame = m; /* save unacked frame */ + l2sc->ua_num = l2sc->vs; /* save frame number */ + + M128INC(l2sc->vs); + + l2sc->ack_pend = 0; + + splx(x); + + if(l2sc->T200 == TIMER_IDLE) + { + i4b_T203_stop(l2sc); + i4b_T200_start(l2sc); + } +} + +#endif /* NI4BQ921 > 0 */ diff --git a/sys/i4b/layer2/i4b_l2.c b/sys/i4b/layer2/i4b_l2.c new file mode 100644 index 000000000000..5cdc1c7cc582 --- /dev/null +++ b/sys/i4b/layer2/i4b_l2.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2.c - ISDN layer 2 (Q.921) + * ------------------------------- + * + * $Id: i4b_l2.c,v 1.23 1998/12/05 18:05:08 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:27:00 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +int i4b_dl_establish_ind(int); +int i4b_dl_establish_cnf(int); +int i4b_dl_release_ind(int); +int i4b_dl_release_cnf(int); +int i4b_dl_data_ind(int, struct mbuf *); +int i4b_dl_unit_data_ind(int, struct mbuf *); + +static int i4b_mdl_command_req(int, int, int); + +/* from layer 2 */ + +extern int i4b_mdl_attach_ind(int, int); +extern int i4b_mdl_status_ind(int, int, int); + +/* this layers debug level */ + +unsigned int i4b_l2_debug = L2_DEBUG_DEFAULT; + +struct i4b_l2l3_func i4b_l2l3_func = { + + /* Layer 2 --> Layer 3 */ + + (int (*)(int)) i4b_dl_establish_ind, + (int (*)(int)) i4b_dl_establish_cnf, + (int (*)(int)) i4b_dl_release_ind, + (int (*)(int)) i4b_dl_release_cnf, + (int (*)(int, struct mbuf *)) i4b_dl_data_ind, + (int (*)(int, struct mbuf *)) i4b_dl_unit_data_ind, + + /* Layer 3 --> Layer 2 */ + + (int (*)(int)) i4b_dl_establish_req, + (int (*)(int)) i4b_dl_release_req, + (int (*)(int, struct mbuf *)) i4b_dl_data_req, + (int (*)(int, struct mbuf *)) i4b_dl_unit_data_req, + + /* Layer 2 --> Layer 3 management */ + + (int (*)(int, int, int)) i4b_mdl_status_ind, + + /* Layer 3 --> Layer 2 management */ + + (int (*)(int, int, int)) i4b_mdl_command_req +}; + +/*---------------------------------------------------------------------------* + * DL_ESTABLISH_REQ from layer 3 + *---------------------------------------------------------------------------*/ +int i4b_dl_establish_req(int unit) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + + DBGL2(L2_PRIM, "DL-ESTABLISH-REQ", ("unit %d\n",unit)); + i4b_l1_activate(l2sc); + i4b_next_l2state(l2sc, EV_DLESTRQ); + return(0); +} + +/*---------------------------------------------------------------------------* + * DL_RELEASE_REQ from layer 3 + *---------------------------------------------------------------------------*/ +int i4b_dl_release_req(int unit) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + + DBGL2(L2_PRIM, "DL-RELEASE-REQ", ("unit %d\n",unit)); + i4b_next_l2state(l2sc, EV_DLRELRQ); + return(0); +} + +/*---------------------------------------------------------------------------* + * DL UNIT DATA REQUEST from Layer 3 + *---------------------------------------------------------------------------*/ +int i4b_dl_unit_data_req(int unit, struct mbuf *m) +{ +#ifdef NOTDEF + DBGL2(L2_PRIM, "DL-UNIT-DATA-REQ", ("unit %d\n",unit)); +#endif + return(0); +} + +/*---------------------------------------------------------------------------* + * DL DATA REQUEST from Layer 3 + *---------------------------------------------------------------------------*/ +int i4b_dl_data_req(int unit, struct mbuf *m) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + int x; +#ifdef NOTDEF + DBGL2(L2_PRIM, "DL-DATA-REQ", ("unit %d\n",unit)); +#endif + switch(l2sc->Q921_state) + { + case ST_AW_EST: + case ST_MULTIFR: + case ST_TIMREC: + + if(IF_QFULL(&l2sc->i_queue)) + { + DBGL2(L2_ERROR, "i4b_dl_data_req", ("i_queue full!!\n")); + i4b_Dfreembuf(m); + } + else + { + x = splimp(); + IF_ENQUEUE(&l2sc->i_queue, m); + splx(x); + i4b_i_frame_queued_up(l2sc); + } + break; + + default: + DBGL2(L2_ERROR, "i4b_dl_data_req", ("unit %d ERROR in state [%s], freeing mbuf\n", unit, i4b_print_l2state(l2sc))); + i4b_Dfreembuf(m); + break; + } + return(0); +} + +/*---------------------------------------------------------------------------* + * i4b_ph_activate_ind - link activation indication from layer 1 + *---------------------------------------------------------------------------*/ +int +i4b_ph_activate_ind(int unit) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + + DBGL1(L1_PRIM, "PH-ACTIVATE-IND", ("unit %d\n",unit)); + l2sc->ph_active = PH_ACTIVE; + return(0); +} + +/*---------------------------------------------------------------------------* + * i4b_ph_deactivate_ind - link deactivation indication from layer 1 + *---------------------------------------------------------------------------*/ +int +i4b_ph_deactivate_ind(int unit) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + + DBGL1(L1_PRIM, "PH-DEACTIVATE-IND", ("unit %d\n",unit)); + l2sc->ph_active = PH_INACTIVE; + return(0); +} + + +/*---------------------------------------------------------------------------* + * i4b_l2_unit_init - place layer 2 unit into known state + *---------------------------------------------------------------------------*/ +static void +i4b_l2_unit_init(int unit) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + + l2sc->Q921_state = ST_TEI_UNAS; + l2sc->tei_valid = TEI_INVALID; + l2sc->vr = 0; + l2sc->vs = 0; + l2sc->va = 0; + l2sc->ack_pend = 0; + l2sc->rej_excpt = 0; + l2sc->peer_busy = 0; + l2sc->own_busy = 0; + l2sc->l3initiated = 0; + + l2sc->rxd_CR = 0; + l2sc->rxd_PF = 0; + l2sc->rxd_NR = 0; + l2sc->RC = 0; + l2sc->iframe_sent = 0; + + l2sc->postfsmfunc = NULL; + + if(l2sc->ua_num != UA_EMPTY) + { + i4b_Dfreembuf(l2sc->ua_frame); + l2sc->ua_num = UA_EMPTY; + l2sc->ua_frame = NULL; + } + + i4b_T200_stop(l2sc); + i4b_T202_stop(l2sc); + i4b_T203_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * i4b_mph_status_ind - status indication upward + *---------------------------------------------------------------------------*/ +int +i4b_mph_status_ind(int unit, int status, int parm) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + int sendup = 1; + + int x = SPLI4B(); + + DBGL1(L1_PRIM, "MPH-STATUS-IND", ("unit %d, status=%d, parm=%d\n", unit, status, parm)); + + switch(status) + { + case STI_ATTACH: + l2sc->unit = unit; + l2sc->i_queue.ifq_maxlen = IQUEUE_MAXLEN; + l2sc->ua_frame = NULL; + i4b_l2_unit_init(unit); + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + /* initialize the callout handles for timeout routines */ + callout_handle_init(&l2sc->T200_callout); + callout_handle_init(&l2sc->T202_callout); + callout_handle_init(&l2sc->T203_callout); +#endif + break; + + case STI_L1STAT: /* state of layer 1 */ + break; + + case STI_PDEACT: /* Timer 4 expired */ + if((l2sc->Q921_state >= ST_AW_EST) && + (l2sc->Q921_state <= ST_TIMREC)) + { + DBGL2(L2_ERROR, "i4b_mph_status_ind", ("unit %d, persistent deactivation!\n", unit)); + i4b_l2_unit_init(unit); + } + else + { + sendup = 0; + } + break; + + case STI_NOL1ACC: + i4b_l2_unit_init(unit); + DBGL2(L2_ERROR, "i4b_mph_status_ind", ("unit %d, cannot access S0 bus!\n", unit)); + break; + + default: + DBGL2(L2_ERROR, "i4b_mph_status_ind", ("ERROR, unit %d, unknown status message!\n", unit)); + break; + } + + if(sendup) + MDL_Status_Ind(unit, status, parm); /* send up to layer 3 */ + + splx(x); + + return(0); +} + +/*---------------------------------------------------------------------------* + * MDL_COMMAND_REQ from layer 3 + *---------------------------------------------------------------------------*/ +int i4b_mdl_command_req(int unit, int command, int parm) +{ + DBGL2(L2_PRIM, "MDL-COMMAND-REQ", ("unit %d, command=%d, parm=%d\n", unit, command, parm)); + + switch(command) + { + case CMR_DOPEN: + i4b_l2_unit_init(unit); + break; + } + + MPH_Command_Req(unit, command, parm); + + return(0); +} + +/*---------------------------------------------------------------------------* + * i4b_ph_data_ind - process a rx'd frame got from layer 1 + *---------------------------------------------------------------------------*/ +int +i4b_ph_data_ind(int unit, struct mbuf *m) +{ +#ifdef NOTDEF + DBGL1(L1_PRIM, "PH-DATA-IND", ("unit %d\n", unit)); +#endif + u_char *ptr = m->m_data; + + if ( (*(ptr + OFF_CNTL) & 0x01) == 0 ) + { + if(m->m_len < 4) /* 6 oct - 2 chksum oct */ + { + DBGL2(L2_ERROR, "i4b_ph_data_ind", ("ERROR, I-frame < 6 octetts!\n")); + i4b_Dfreembuf(m); + return(0); + } + i4b_rxd_i_frame(unit, m); + } + else if ( (*(ptr + OFF_CNTL) & 0x03) == 0x01 ) + { + if(m->m_len < 4) /* 6 oct - 2 chksum oct */ + { + DBGL2(L2_ERROR, "i4b_ph_data_ind", ("ERROR, S-frame < 6 octetts!\n")); + i4b_Dfreembuf(m); + return(0); + } + i4b_rxd_s_frame(unit, m); + } + else if ( (*(ptr + OFF_CNTL) & 0x03) == 0x03 ) + { + if(m->m_len < 3) /* 5 oct - 2 chksum oct */ + { + DBGL2(L2_ERROR, "i4b_ph_data_ind", ("ERROR, U-frame < 5 octetts!\n")); + i4b_Dfreembuf(m); + return(0); + } + i4b_rxd_u_frame(unit, m); + } + else + { + DBGL2(L2_ERROR, "i4b_ph_data_ind", ("ERROR, bad frame rx'd - ")); + i4b_print_frame(m->m_len, m->m_data); + i4b_Dfreembuf(m); + } + return(0); +} + +#endif /* NI4BQ921 > 0 */ + diff --git a/sys/i4b/layer2/i4b_l2.h b/sys/i4b/layer2/i4b_l2.h new file mode 100644 index 000000000000..ab1dfd7cd549 --- /dev/null +++ b/sys/i4b/layer2/i4b_l2.h @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2.h - ISDN layer 2 (Q.921) definitions + * --------------------------------------------- + * + * $Id: i4b_l2.h,v 1.14 1998/12/05 18:05:09 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:27:13 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L2_H_ +#define _I4B_L2_H_ + +typedef struct { + int unit; /* unit number this entry is for */ + + int Q921_state; /* state according to Q.921 */ + + u_char last_ril; /* last reference number from TEI management */ + u_char last_rih; + + int tei_valid; /* tei is valid flag */ +#define TEI_INVALID 0 +#define TEI_VALID 1 + int tei; /* tei, if tei flag valid */ + + int ph_active; /* Layer 1 active flag */ +#define PH_INACTIVE 0 /* layer 1 inactive */ +#define PH_ACTIVEPEND 1 /* already tried to activate */ +#define PH_ACTIVE 2 /* layer 1 active */ + + int T200; /* Multiframe timeout timer */ + int T201; /* min time between TEI ID check */ + int T202; /* min time between TEI ID Req messages */ + int N202; /* TEI ID Req tx counter */ + void(*T202func)(void *);/* function to be called when T202 expires */ + int T203; /* max line idle time */ + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + struct callout_handle T200_callout; + struct callout_handle T202_callout; + struct callout_handle T203_callout; +#endif + + int vr; /* receive sequence frame counter */ + int vs; /* transmit sequence frame counter */ + int va; /* acknowledge sequence frame counter */ + + int ack_pend; /* acknowledge pending */ + int rej_excpt; /* reject exception */ + int peer_busy; /* peer receiver busy */ + int own_busy; /* own receiver busy */ + int l3initiated; /* layer 3 initiated */ + + struct ifqueue i_queue; /* queue of outgoing i frames */ +#define IQUEUE_MAXLEN 20 + + /* this implementation only supports a k-value of 1 !!! */ + struct mbuf *ua_frame; /* last unacked frame */ + int ua_num; /* last unacked frame number */ +#define UA_EMPTY (-1) /* ua_frame is unused */ + + int rxd_CR; /* received Command Response bit */ + int rxd_PF; /* received Poll/Final bit */ + int rxd_NR; /* received N(R) field */ + int RC; /* Retry Counter */ + + int iframe_sent; /* check if i frame acked by another i frame */ + + int (*postfsmfunc)(int);/* function to be called at fsm exit */ + int postfsmarg; /* argument for above function */ +} l2_softc_t; + +extern l2_softc_t l2_softc[]; + +/* Q.912 system parameters (Q.921 03/93 pp 43) */ + +#define MAX_K_VALUE 1 /* BRI - # of outstanding frames */ + +#define N200 3 /* max no of retransmissions */ +#define N201DEF 260 /* max no of octetts in information field */ +#define N202DEF 3 /* max no of TEI ID Request message transmissions */ + +#define T200DEF (hz*1) /* default T200 timer value = 1 second */ +#define T201DEF T200DEF /* default T201 timer value = T200DEF */ +#define T202DEF (hz*2) /* default T202 timer value = 2 seconds */ +#define T203DEF (hz*10) /* default T203 timer value = 10 seconds*/ + +/* modulo 128 operations */ + +#define M128INC(v) (v)++; \ + if((v)>127) \ + { \ + v = 0; \ + } + +#define M128DEC(v) (v)--; \ + if((v)<0) \ + { \ + v = 127;\ + } + +/* P-bit values */ + +typedef enum { + P0, + P1 +} pbit_t; + +/* F-bit values */ + +typedef enum { + F0, + F1 +} fbit_t; + +/* CR-bit values to NT */ + +typedef enum { + CR_CMD_TO_NT, + CR_RSP_TO_NT +} crbit_to_nt_t; + +/* CR-bit values from NT */ + +typedef enum { + CR_RSP_FROM_NT, + CR_CMD_FROM_NT +} crbit_from_nt_t; + +/* address field - octett 2 */ + +#define OFF_SAPI 0 /* SAPI offset, HDLC flag is eaten by L1 */ +#define SAPI_CCP 0 /* SAPI = 0 - call control procedures */ +#define SAPI_X25 16 /* SAPI = 16 - X.25 packet procedures */ +#define SAPI_L2M 63 /* SAPI = 63 - Layer 2 management procedures */ + +/* extract and insert macros for SAPI octett */ + +#define GETSAPI(octett) (((octett) >> 2) & 0x3f) +#define PUTSAPI(sapi,cr,octett) ((octett) = (((sapi << 2) & 0xfc) | ((cr & 0x01) << 1))) +#define GETCR(octett) (((octett) >> 1) & 0x01) +#define GETEA(octett) ((octett) & 0x01) + +/* address field - octett 3 */ + +#define OFF_TEI 1 /* TEI offset */ +#define GETTEI(octett) (((octett) >> 1) & 0x7f) +#define PUTTEI(tei, octett) ((octett) = ((((tei) << 1) & 0xfe)) | 0x01) +#define GROUP_TEI 127 /* broadcast TEI for LME */ + +/* control field - octett 4 */ + +#define OFF_CNTL 2 /* 1st byte of control field */ + +/* S frames */ + +#define S_FRAME_LEN 4 /* lenght of a U-frame */ +#define OFF_SRCR 2 /* 1st byte of control field, */ + /* R-commands and R-responses */ +#define OFF_SNR 3 /* 2nd byte of control field, N(R) and PF */ +#define SPFBIT 0x01 /* poll/final bit mask */ +#define SPBITSET SPFBIT +#define SFBITSET SPFBIT +#define GETSNR(octett) (((octett) >> 1) & 0x7f) +#define GETSPF(octett) ((octett) & SPFBIT) +#define RR 0x01 /* RR and bit 0 set */ +#define RNR 0x05 /* RNR and bit 0 set */ +#define REJ 0x09 /* REJ and bit 0 set */ + +/* U frames */ + +#define UI_HDR_LEN 3 /* length of UI header in front of L3 frame */ +#define U_FRAME_LEN 3 /* lenght of a U-frame */ +#define UPFBIT 0x10 /* poll/final bit mask */ +#define UPBITSET UPFBIT +#define UFBITSET UPFBIT +#define GETUPF(octett) (((octett) >> 4) & 0x01) + +/* commands/responses with pf bit set to 0 */ + +#define SABME 0x6f +#define DM 0x0f +#define UI 0x03 +#define DISC 0x43 +#define UA 0x63 +#define FRMR 0x87 +#define XID 0xaf + +/* control field - octett 3 */ + +#define OFF_MEI 3 /* 2nd byte of control field */ + +/* control field - octett 4,5 */ + +#define OFF_RIL 4 /* Ri low byte */ +#define OFF_RIH 5 /* Ri high byte */ + +/* control field - octett 6 */ + +#define OFF_MT 6 /* Message Type */ +#define OFF_AI 7 /* Action Indicator */ +#define GET_TEIFROMAI(octett) (((octett) >> 1) & 0x7f) + +/* I frame */ + +#define I_HDR_LEN 4 /* length of I header in front of L3 frame */ +#define OFF_INS 2 /* transmit sequence number */ +#define OFF_INR 3 /* receive sequence number */ +#define IPFBIT 0x01 /* poll/final bit mask */ +#define IPBITSET 0x01 +#define GETINR(octett) (((octett) >> 1) & 0x7f) +#define GETINS(octett) (((octett) >> 1) & 0x7f) +#define GETIP(octett) ((octett) & IPFBIT) + +/* structure of a TEI management frame */ + +#define TEI_MGMT_FRM_LEN 8 /* frame length */ +#define TEIM_SAPIO 0x00 /* SAPI, CR, EA */ +#define TEIM_TEIO 0x01 /* TEI, EA */ +#define TEIM_UIO 0x02 /* frame type = UI = 0x03 */ +#define TEIM_MEIO 0x03 /* management entity id = 0x0f */ +#define MEI 0x0f +#define TEIM_RILO 0x04 /* reference number, low */ +#define TEIM_RIHO 0x05 /* reference number, high */ +#define TEIM_MTO 0x06 /* message type */ +#define MT_ID_REQEST 0x01 +#define MT_ID_ASSIGN 0x02 +#define MT_ID_DENY 0x03 +#define MT_ID_CHK_REQ 0x04 +#define MT_ID_CHK_RSP 0x05 +#define MT_ID_REMOVE 0x06 +#define MT_ID_VERIFY 0x07 +#define TEIM_AIO 0x07 /* action indicator */ + +/* i4b_mdl_error_ind codes */ + +enum MDL_ERROR_CODES { + MDL_ERR_A, + MDL_ERR_B, + MDL_ERR_C, + MDL_ERR_D, + MDL_ERR_E, + MDL_ERR_F, + MDL_ERR_G, + MDL_ERR_H, + MDL_ERR_I, + MDL_ERR_J, + MDL_ERR_K, + MDL_ERR_L, + MDL_ERR_M, + MDL_ERR_N, + MDL_ERR_O, + MDL_ERR_MAX +}; + +/* forward decl */ + +extern void i4b_acknowledge_pending ( l2_softc_t *l2sc ); +extern struct mbuf * i4b_build_s_frame ( l2_softc_t *l2sc, crbit_to_nt_t crbit, pbit_t pbit, u_char type ); +extern struct mbuf * i4b_build_u_frame ( l2_softc_t *l2sc, crbit_to_nt_t crbit, pbit_t pbit, u_char type ); +extern void i4b_clear_exception_conditions ( l2_softc_t *l2sc ); +extern int i4b_dl_data_req ( int unit, struct mbuf *m ); +extern int i4b_dl_establish_req ( int unit ); +extern int i4b_dl_release_req ( int unit ); +extern int i4b_dl_unit_data_req ( int unit, struct mbuf *m ); +extern void i4b_enquiry_response ( l2_softc_t *l2sc ); +extern void i4b_establish_data_link ( l2_softc_t *l2sc ); +extern void i4b_invoke_retransmission ( l2_softc_t *l2sc, int nr ); +extern void i4b_i_frame_queued_up ( l2_softc_t *l2sc ); +extern void i4b_l1_activate ( l2_softc_t *l2sc ); +extern int i4b_l2_nr_ok ( int nr, int va, int vs ); +extern void i4b_make_rand_ri ( l2_softc_t *l2sc ); +extern void i4b_mdl_assign_ind ( l2_softc_t *l2sc ); +extern void i4b_mdl_error_ind ( l2_softc_t *l2sc, char *where, int errorcode ); +extern int i4b_mph_attach_ind ( int unit, int type ); +extern int i4b_mph_status_ind ( int unit, int status, int parm ); +extern void i4b_next_l2state ( l2_softc_t *l2sc, int event ); +extern void i4b_nr_error_recovery ( l2_softc_t *l2sc ); +extern int i4b_ph_activate_ind ( int unit ); +extern int i4b_ph_deactivate_ind ( int unit ); +extern int i4b_ph_data_ind ( int unit, struct mbuf *m ); +extern void i4b_print_frame ( int len, u_char *buf ); +extern char *i4b_print_l2state ( l2_softc_t *l2sc ); +extern void i4b_print_l2var ( l2_softc_t *l2sc ); +extern void i4b_rxd_ack(l2_softc_t *l2sc, int nr); +extern void i4b_rxd_i_frame ( int unit, struct mbuf *m ); +extern void i4b_rxd_s_frame ( int unit, struct mbuf *m ); +extern void i4b_rxd_u_frame ( int unit, struct mbuf *m ); +extern void i4b_T200_restart ( l2_softc_t *l2sc ); +extern void i4b_T200_start ( l2_softc_t *l2sc ); +extern void i4b_T200_stop ( l2_softc_t *l2sc ); +extern void i4b_T202_start ( l2_softc_t *l2sc ); +extern void i4b_T202_stop ( l2_softc_t *l2sc ); +extern void i4b_T203_restart ( l2_softc_t *l2sc ); +extern void i4b_T203_start ( l2_softc_t *l2sc ); +extern void i4b_T203_stop ( l2_softc_t *l2sc ); +extern void i4b_tei_assign ( l2_softc_t *l2sc ); +extern void i4b_tei_chkresp ( l2_softc_t *l2sc ); +extern void i4b_tei_rxframe ( int unit, struct mbuf *m ); +extern void i4b_tei_verify ( l2_softc_t *l2sc ); +extern void i4b_transmit_enquire ( l2_softc_t *l2sc ); +extern void i4b_tx_disc ( l2_softc_t *l2sc, pbit_t pbit ); +extern void i4b_tx_dm ( l2_softc_t *l2sc, fbit_t fbit ); +extern void i4b_tx_frmr ( l2_softc_t *l2sc, fbit_t fbit ); +extern void i4b_tx_rej_response ( l2_softc_t *l2sc, fbit_t fbit ); +extern void i4b_tx_rnr_command ( l2_softc_t *l2sc, pbit_t pbit ); +extern void i4b_tx_rnr_response ( l2_softc_t *l2sc, fbit_t fbit ); +extern void i4b_tx_rr_command ( l2_softc_t *l2sc, pbit_t pbit ); +extern void i4b_tx_rr_response ( l2_softc_t *l2sc, fbit_t fbit ); +extern void i4b_tx_sabme ( l2_softc_t *l2sc, pbit_t pbit ); +extern void i4b_tx_ua ( l2_softc_t *l2sc, fbit_t fbit ); + +#endif /* _I4B_L2_H_ */ diff --git a/sys/i4b/layer2/i4b_l2fsm.c b/sys/i4b/layer2/i4b_l2fsm.c new file mode 100644 index 000000000000..113167c11429 --- /dev/null +++ b/sys/i4b/layer2/i4b_l2fsm.c @@ -0,0 +1,1593 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2fsm.c - layer 2 FSM + * ------------------------- + * + * $Id: i4b_l2fsm.c,v 1.13 1998/12/05 18:05:11 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:28:15 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +l2_softc_t l2_softc[ISIC_MAXUNIT]; + +static char *l2state_text[N_STATES] = { + "ST_TEI_UNAS", + "ST_ASG_AW_TEI", + "ST_EST_AW_TEI", + "ST_TEI_ASGD", + + "ST_AW_EST", + "ST_AW_REL", + "ST_MULTIFR", + "ST_TIMREC", + + "ST_SUBSET", + "Illegal State" +}; + +static char *l2event_text[N_EVENTS] = { + "EV_DLESTRQ", + "EV_DLUDTRQ", + "EV_MDASGRQ", + "EV_MDERRRS", + "EV_PSDEACT", + "EV_MDREMRQ", + "EV_RXSABME", + "EV_RXDISC", + "EV_RXUA", + "EV_RXDM", + "EV_T200EXP", + "EV_DLDATRQ", + "EV_DLRELRQ", + "EV_T203EXP", + "EV_OWNBUSY", + "EV_OWNRDY", + "EV_RXRR", + "EV_RXREJ", + "EV_RXRNR", + "EV_RXFRMR", + "Illegal Event" +}; + +static void F_TU01 __P((l2_softc_t *)); +static void F_TU03 __P((l2_softc_t *)); + +static void F_TA03 __P((l2_softc_t *)); +static void F_TA04 __P((l2_softc_t *)); +static void F_TA05 __P((l2_softc_t *)); + +static void F_TE03 __P((l2_softc_t *)); +static void F_TE04 __P((l2_softc_t *)); +static void F_TE05 __P((l2_softc_t *)); + +static void F_T01 __P((l2_softc_t *)); +static void F_T05 __P((l2_softc_t *)); +static void F_T06 __P((l2_softc_t *)); +static void F_T07 __P((l2_softc_t *)); +static void F_T08 __P((l2_softc_t *)); +static void F_T09 __P((l2_softc_t *)); +static void F_T10 __P((l2_softc_t *)); +static void F_T13 __P((l2_softc_t *)); + +static void F_AE01 __P((l2_softc_t *)); +static void F_AE05 __P((l2_softc_t *)); +static void F_AE06 __P((l2_softc_t *)); +static void F_AE07 __P((l2_softc_t *)); +static void F_AE08 __P((l2_softc_t *)); +static void F_AE09 __P((l2_softc_t *)); +static void F_AE10 __P((l2_softc_t *)); +static void F_AE11 __P((l2_softc_t *)); +static void F_AE12 __P((l2_softc_t *)); + +static void F_AR05 __P((l2_softc_t *)); +static void F_AR06 __P((l2_softc_t *)); +static void F_AR07 __P((l2_softc_t *)); +static void F_AR08 __P((l2_softc_t *)); +static void F_AR09 __P((l2_softc_t *)); +static void F_AR10 __P((l2_softc_t *)); +static void F_AR11 __P((l2_softc_t *)); + +static void F_MF01 __P((l2_softc_t *)); +static void F_MF05 __P((l2_softc_t *)); +static void F_MF06 __P((l2_softc_t *)); +static void F_MF07 __P((l2_softc_t *)); +static void F_MF08 __P((l2_softc_t *)); +static void F_MF09 __P((l2_softc_t *)); +static void F_MF10 __P((l2_softc_t *)); +static void F_MF11 __P((l2_softc_t *)); +static void F_MF12 __P((l2_softc_t *)); +static void F_MF13 __P((l2_softc_t *)); +static void F_MF14 __P((l2_softc_t *)); +static void F_MF15 __P((l2_softc_t *)); +static void F_MF16 __P((l2_softc_t *)); +static void F_MF17 __P((l2_softc_t *)); +static void F_MF18 __P((l2_softc_t *)); +static void F_MF19 __P((l2_softc_t *)); +static void F_MF20 __P((l2_softc_t *)); + +static void F_TR01 __P((l2_softc_t *)); +static void F_TR05 __P((l2_softc_t *)); +static void F_TR06 __P((l2_softc_t *)); +static void F_TR07 __P((l2_softc_t *)); +static void F_TR08 __P((l2_softc_t *)); +static void F_TR09 __P((l2_softc_t *)); +static void F_TR10 __P((l2_softc_t *)); +static void F_TR11 __P((l2_softc_t *)); +static void F_TR12 __P((l2_softc_t *)); +static void F_TR13 __P((l2_softc_t *)); +static void F_TR15 __P((l2_softc_t *)); +static void F_TR16 __P((l2_softc_t *)); +static void F_TR17 __P((l2_softc_t *)); +static void F_TR18 __P((l2_softc_t *)); +static void F_TR19 __P((l2_softc_t *)); +static void F_TR20 __P((l2_softc_t *)); +static void F_ILL __P((l2_softc_t *)); +static void F_NCNA __P((l2_softc_t *)); + +/*---------------------------------------------------------------------------* + * FSM illegal state default action + *---------------------------------------------------------------------------*/ +static void +F_ILL(l2_softc_t *l2sc) +{ + DBGL2(L2_F_ERR, "F_ILL", ("FSM function F_ILL executing\n")); +} + +/*---------------------------------------------------------------------------* + * FSM No change, No action + *---------------------------------------------------------------------------*/ +static void +F_NCNA(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_NCNA", ("FSM function F_NCNA executing\n")); +} + +/*---------------------------------------------------------------------------* + * layer 2 state transition table + *---------------------------------------------------------------------------*/ +struct l2state_tab { + void (*func) __P((l2_softc_t *)); /* function to execute */ + int newstate; /* next state */ +} l2state_tab[N_EVENTS][N_STATES] = { + +/* STATE: ST_TEI_UNAS, ST_ASG_AW_TEI, ST_EST_AW_TEI, ST_TEI_ASGD, ST_AW_EST, ST_AW_REL, ST_MULTIFR, ST_TIMREC, ST_SUBSET, ILLEGAL STATE */ +/* -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/*EV_DLESTRQ*/{ {F_TU01, ST_EST_AW_TEI}, {F_NCNA, ST_EST_AW_TEI}, {F_ILL, ST_ILL}, {F_T01, ST_AW_EST}, {F_AE01, ST_AW_EST}, {F_ILL, ST_ILL}, {F_MF01, ST_AW_EST}, {F_TR01, ST_AW_EST}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_DLUDTRQ*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_MDASGRQ*/{ {F_TU03, ST_TEI_ASGD}, {F_TA03, ST_TEI_ASGD}, {F_TE03, ST_AW_EST}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_MDERRRS*/{ {F_ILL, ST_ILL}, {F_TA04, ST_TEI_UNAS}, {F_TE04, ST_TEI_UNAS}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_PSDEACT*/{ {F_ILL, ST_ILL}, {F_TA05, ST_TEI_UNAS}, {F_TE05, ST_TEI_UNAS}, {F_T05, ST_TEI_ASGD}, {F_AE05, ST_TEI_ASGD}, {F_AR05, ST_TEI_ASGD}, {F_MF05, ST_TEI_ASGD}, {F_TR05, ST_TEI_ASGD}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_MDREMRQ*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_T06, ST_TEI_UNAS}, {F_AE06, ST_TEI_UNAS}, {F_AR06, ST_TEI_UNAS}, {F_MF06, ST_TEI_UNAS}, {F_TR06, ST_TEI_UNAS}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXSABME*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_T07, ST_SUBSET}, {F_AE07, ST_AW_EST}, {F_AR07, ST_AW_REL}, {F_MF07, ST_MULTIFR}, {F_TR07, ST_MULTIFR}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXDISC */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_T08, ST_TEI_ASGD}, {F_AE08, ST_AW_EST}, {F_AR08, ST_AW_REL}, {F_MF08, ST_TEI_ASGD}, {F_TR08, ST_TEI_ASGD}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXUA */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_T09, ST_TEI_ASGD}, {F_AE09, ST_SUBSET}, {F_AR09, ST_SUBSET}, {F_MF09, ST_MULTIFR}, {F_TR09, ST_TIMREC}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXDM */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_T10, ST_SUBSET}, {F_AE10, ST_SUBSET}, {F_AR10, ST_SUBSET}, {F_MF10, ST_SUBSET}, {F_TR10, ST_AW_EST}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_T200EXP*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_AE11, ST_SUBSET}, {F_AR11, ST_SUBSET}, {F_MF11, ST_TIMREC}, {F_TR11, ST_SUBSET}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_DLDATRQ*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_AE12, ST_AW_EST}, {F_ILL, ST_ILL}, {F_MF12, ST_MULTIFR}, {F_TR12, ST_TIMREC}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_DLRELRQ*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_T13, ST_TEI_ASGD}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF13, ST_AW_REL}, {F_TR13, ST_AW_REL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_T203EXP*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF14, ST_TIMREC}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_OWNBUSY*/{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF15, ST_MULTIFR}, {F_TR15, ST_TIMREC}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_OWNRDY */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF16, ST_MULTIFR}, {F_TR16, ST_TIMREC}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXRR */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF17, ST_SUBSET}, {F_TR17, ST_SUBSET}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXREJ */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF18, ST_SUBSET}, {F_TR18, ST_SUBSET}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXRNR */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF19, ST_SUBSET}, {F_TR19, ST_SUBSET}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_RXFRMR */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_MF20, ST_AW_EST}, {F_TR20, ST_AW_EST}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} }, +/*EV_ILL */{ {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL} } +}; + +/*---------------------------------------------------------------------------* + * event handler, executes function and sets new state + *---------------------------------------------------------------------------*/ +void i4b_next_l2state(l2_softc_t *l2sc, int event) +{ + int currstate, newstate; + + /* check event number */ + if(event > N_EVENTS) + panic("i4b_l2fsm.c: event > N_EVENTS\n"); + + /* get current state and check it */ + if((currstate = l2sc->Q921_state) > N_STATES) /* failsafe */ + panic("i4b_l2fsm.c: currstate > N_STATES\n"); + + /* get new state and check it */ + if((newstate = l2state_tab[event][currstate].newstate) > N_STATES) + panic("i4b_l2fsm.c: newstate > N_STATES\n"); + + + if(newstate != ST_SUBSET) + { /* state function does NOT set new state */ + DBGL2(L2_F_MSG, "i4b_next_l2state", ("FSM event [%s]: [%s/%d => %s/%d]\n", + l2event_text[event], + l2state_text[currstate], currstate, + l2state_text[newstate], newstate)); + } + + /* execute state transition function */ + (*l2state_tab[event][currstate].func)(l2sc); + + if(newstate == ST_SUBSET) + { /* state function DOES set new state */ + DBGL2(L2_F_MSG, "i4b_next_l2state", ("FSM S-event [%s]: [%s => %s]\n", l2event_text[event], + l2state_text[currstate], + l2state_text[l2sc->Q921_state])); + } + + /* check for illegal new state */ + + if(newstate == ST_ILL) + { + newstate = currstate; + DBGL2(L2_F_ERR, "i4b_next_l2state", ("FSM illegal state, state = %s, event = %s!\n", + l2state_text[currstate], + l2event_text[event])); + } + + /* check if state machine function has to set new state */ + + if(newstate != ST_SUBSET) + l2sc->Q921_state = newstate; /* no, we set new state */ + + if(l2sc->postfsmfunc != NULL) + { + DBGL2(L2_F_MSG, "i4b_next_l2state", ("FSM executing postfsmfunc!\n")); + (*l2sc->postfsmfunc)(l2sc->postfsmarg); + l2sc->postfsmfunc = NULL; + } +} + +/*---------------------------------------------------------------------------* + * return pointer to current state description + *---------------------------------------------------------------------------*/ +char *i4b_print_l2state(l2_softc_t *l2sc) +{ + return((char *) l2state_text[l2sc->Q921_state]); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_UNAS event dl establish request + *---------------------------------------------------------------------------*/ +static void +F_TU01(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TU01", ("FSM function F_TU01 executing\n")); + i4b_mdl_assign_ind(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_UNAS event mdl assign request + *---------------------------------------------------------------------------*/ +static void +F_TU03(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TU03", ("FSM function F_TU03 executing\n")); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_ASG_AW_TEI event mdl assign request + *---------------------------------------------------------------------------*/ +static void +F_TA03(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TA03", ("FSM function F_TA03 executing\n")); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_ASG_AW_TEI event mdl error response + *---------------------------------------------------------------------------*/ +static void +F_TA04(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TA04", ("FSM function F_TA04 executing\n")); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_ASG_AW_TEI event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_TA05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TA05", ("FSM function F_TA05 executing\n")); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_EST_AW_TEI event mdl assign request + *---------------------------------------------------------------------------*/ +static void +F_TE03(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TE03", ("FSM function F_TE03 executing\n")); + i4b_establish_data_link(l2sc); + l2sc->l3initiated = 1; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_EST_AW_TEI event mdl error response + *---------------------------------------------------------------------------*/ +static void +F_TE04(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TE04", ("FSM function F_TE04 executing\n")); + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_EST_AW_TEI event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_TE05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TE05", ("FSM function F_TE05 executing\n")); + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event dl establish request + *---------------------------------------------------------------------------*/ +static void +F_T01(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T01", ("FSM function F_T01 executing\n")); + i4b_establish_data_link(l2sc); + l2sc->l3initiated = 1; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_T05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T05", ("FSM function F_T05 executing\n")); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event mdl remove request + *---------------------------------------------------------------------------*/ +static void +F_T06(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T06", ("FSM function F_T06 executing\n")); +/*XXX*/ i4b_mdl_assign_ind(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event rx'd SABME + *---------------------------------------------------------------------------*/ +static void +F_T07(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T07", ("FSM function F_T07 executing\n")); + +/* XXX */ +#ifdef NOTDEF + if(NOT able to establish) + { + i4b_tx_dm(l2sc, l2sc->rxd_PF); + l2sc->Q921_state = ST_TEI_ASGD; + return; + } +#endif + + i4b_clear_exception_conditions(l2sc); + + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_ACTIVE); + + i4b_tx_ua(l2sc, l2sc->rxd_PF); + + l2sc->vs = 0; + l2sc->va = 0; + l2sc->vr = 0; + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Est_Ind_A; + + i4b_T203_start(l2sc); + + l2sc->Q921_state = ST_MULTIFR; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event rx'd DISC + *---------------------------------------------------------------------------*/ +static void +F_T08(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T08", ("FSM function F_T08 executing\n")); + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_IDLE); + i4b_tx_ua(l2sc, l2sc->rxd_PF); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event rx'd UA + *---------------------------------------------------------------------------*/ +static void +F_T09(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T09", ("FSM function F_T09 executing\n")); + i4b_mdl_error_ind(l2sc, "F_T09", MDL_ERR_C); + i4b_mdl_error_ind(l2sc, "F_T09", MDL_ERR_D); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event rx'd DM + *---------------------------------------------------------------------------*/ +static void +F_T10(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T10", ("FSM function F_T10 executing\n")); + + if(l2sc->rxd_PF) + { + l2sc->Q921_state = ST_TEI_ASGD; + } + else + { +#ifdef NOTDEF + if(NOT able_to_etablish) + { + l2sc->Q921_state = ST_TEI_ASGD; + return; + } +#endif + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 1; + + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TEI_ASGD event dl release request + *---------------------------------------------------------------------------*/ +static void +F_T13(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_T13", ("FSM function F_T13 executing\n")); + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Cnf_A; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event dl establish request + *---------------------------------------------------------------------------*/ +static void +F_AE01(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE01", ("FSM function F_AE01 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->l3initiated = 1; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_AE05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE05", ("FSM function F_AE05 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event mdl remove request + *---------------------------------------------------------------------------*/ +static void +F_AE06(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE06", ("FSM function F_AE06 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); + +/*XXX*/ i4b_mdl_assign_ind(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event rx'd SABME + *---------------------------------------------------------------------------*/ +static void +F_AE07(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE07", ("FSM function F_AE07 executing\n")); + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_ACTIVE); + i4b_tx_ua(l2sc, l2sc->rxd_PF); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event rx'd DISC + *---------------------------------------------------------------------------*/ +static void +F_AE08(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE08", ("FSM function F_AE08 executing\n")); + i4b_tx_dm(l2sc, l2sc->rxd_PF); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event rx'd UA + *---------------------------------------------------------------------------*/ +static void +F_AE09(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE09", ("FSM function F_AE09 executing\n")); + + if(l2sc->rxd_PF == 0) + { + i4b_mdl_error_ind(l2sc, "F_AE09", MDL_ERR_D); + l2sc->Q921_state = ST_AW_EST; + } + else + { + if(l2sc->l3initiated) + { + l2sc->l3initiated = 0; + l2sc->vr = 0; + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Est_Cnf_A; + } + else + { + if(l2sc->vs != l2sc->va) + { + i4b_Dcleanifq(&l2sc->i_queue); + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Est_Ind_A; + } + } + + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_ACTIVE); + + i4b_T200_stop(l2sc); + i4b_T203_start(l2sc); + + l2sc->vs = 0; + l2sc->va = 0; + + l2sc->Q921_state = ST_MULTIFR; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event rx'd DM + *---------------------------------------------------------------------------*/ +static void +F_AE10(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE10", ("FSM function F_AE10 executing\n")); + + if(l2sc->rxd_PF == 0) + { + l2sc->Q921_state = ST_AW_EST; + } + else + { + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); + + l2sc->Q921_state = ST_TEI_ASGD; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event T200 expiry + *---------------------------------------------------------------------------*/ +static void +F_AE11(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE11", ("FSM function F_AE11 executing\n")); + + if(l2sc->RC >= N200) + { + i4b_Dcleanifq(&l2sc->i_queue); + + i4b_mdl_error_ind(l2sc, "F_AE11", MDL_ERR_G); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + l2sc->Q921_state = ST_TEI_ASGD; + } + else + { + l2sc->RC++; + + i4b_tx_sabme(l2sc, P1); + + i4b_T200_start(l2sc); + + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_EST event dl data request + *---------------------------------------------------------------------------*/ +static void +F_AE12(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AE12", ("FSM function F_AE12 executing\n")); + + if(l2sc->l3initiated == 0) + { + i4b_i_frame_queued_up(l2sc); + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_AR05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR05", ("FSM function F_AR05 executing\n")); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Cnf_A; + + i4b_T200_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event mdl remove request + *---------------------------------------------------------------------------*/ +static void +F_AR06(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR06", ("FSM function F_AR06 executing\n")); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Cnf_A; + + i4b_T200_stop(l2sc); + +/*XXX*/ i4b_mdl_assign_ind(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event rx'd SABME + *---------------------------------------------------------------------------*/ +static void +F_AR07(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR07", ("FSM function F_AR07 executing\n")); + i4b_tx_dm(l2sc, l2sc->rxd_PF); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event rx'd DISC + *---------------------------------------------------------------------------*/ +static void +F_AR08(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR08", ("FSM function F_AR08 executing\n")); + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_IDLE); + i4b_tx_ua(l2sc, l2sc->rxd_PF); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event rx'd UA + *---------------------------------------------------------------------------*/ +static void +F_AR09(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR09", ("FSM function F_AR09 executing\n")); + + if(l2sc->rxd_PF) + { + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Cnf_A; + + i4b_T200_stop(l2sc); + + l2sc->Q921_state = ST_TEI_ASGD; + } + else + { + i4b_mdl_error_ind(l2sc, "F_AR09", MDL_ERR_D); + + l2sc->Q921_state = ST_AW_REL; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event rx'd DM + *---------------------------------------------------------------------------*/ +static void +F_AR10(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR10", ("FSM function F_AR10 executing\n")); + + if(l2sc->rxd_PF) + { + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Cnf_A; + + i4b_T200_stop(l2sc); + + l2sc->Q921_state = ST_TEI_ASGD; + } + else + { + l2sc->Q921_state = ST_AW_REL; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_AW_REL event T200 expiry + *---------------------------------------------------------------------------*/ +static void +F_AR11(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_AR11", ("FSM function F_AR11 executing\n")); + + if(l2sc->RC >= N200) + { + i4b_mdl_error_ind(l2sc, "F_AR11", MDL_ERR_H); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Cnf_A; + + l2sc->Q921_state = ST_TEI_ASGD; + } + else + { + l2sc->RC++; + + i4b_tx_disc(l2sc, P1); + + i4b_T200_start(l2sc); + + l2sc->Q921_state = ST_AW_REL; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event dl establish request + *---------------------------------------------------------------------------*/ +static void +F_MF01(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF01", ("FSM function F_MF01 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 1; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_MF05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF05", ("FSM function F_MF05 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); + i4b_T203_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event mdl remove request + *---------------------------------------------------------------------------*/ +static void +F_MF06(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF06", ("FSM function F_MF06 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); + i4b_T203_stop(l2sc); + +/*XXX*/ i4b_mdl_assign_ind(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd SABME + *---------------------------------------------------------------------------*/ +static void +F_MF07(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF07", ("FSM function F_MF07 executing\n")); + + i4b_clear_exception_conditions(l2sc); + + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_ACTIVE); + + i4b_tx_ua(l2sc, l2sc->rxd_PF); + + i4b_mdl_error_ind(l2sc, "F_MF07", MDL_ERR_F); + + if(l2sc->vs != l2sc->va) + { + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Est_Ind_A; + } + + i4b_T200_stop(l2sc); + i4b_T203_start(l2sc); + + l2sc->vs = 0; + l2sc->va = 0; + l2sc->vr = 0; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd DISC + *---------------------------------------------------------------------------*/ +static void +F_MF08(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF08", ("FSM function F_MF08 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_IDLE); + i4b_tx_ua(l2sc, l2sc->rxd_PF); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); + i4b_T203_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd UA + *---------------------------------------------------------------------------*/ +static void +F_MF09(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF09", ("FSM function F_MF09 executing\n")); + if(l2sc->rxd_PF) + i4b_mdl_error_ind(l2sc, "F_MF09", MDL_ERR_C); + else + i4b_mdl_error_ind(l2sc, "F_MF09", MDL_ERR_D); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd DM + *---------------------------------------------------------------------------*/ +static void +F_MF10(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF10", ("FSM function F_MF10 executing\n")); + + if(l2sc->rxd_PF) + { + i4b_mdl_error_ind(l2sc, "F_MF10", MDL_ERR_B); + + l2sc->Q921_state = ST_MULTIFR; + } + else + { + i4b_mdl_error_ind(l2sc, "F_MF10", MDL_ERR_E); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 0; + + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event T200 expiry + *---------------------------------------------------------------------------*/ +static void +F_MF11(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF11", ("FSM function F_MF11 executing\n")); + + l2sc->RC = 0; + + i4b_transmit_enquire(l2sc); + + l2sc->RC++; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event dl data request + *---------------------------------------------------------------------------*/ +static void +F_MF12(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF12", ("FSM function F_MF12 executing\n")); + + i4b_i_frame_queued_up(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event dl release request + *---------------------------------------------------------------------------*/ +static void +F_MF13(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF13", ("FSM function F_MF13 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->RC = 0; + + i4b_tx_disc(l2sc, P1); + + i4b_T203_stop(l2sc); + i4b_T200_restart(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event T203 expiry + *---------------------------------------------------------------------------*/ +static void +F_MF14(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF14", ("FSM function F_MF14 executing\n")); + + i4b_transmit_enquire(l2sc); + + l2sc->RC = 0; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event set own rx busy + *---------------------------------------------------------------------------*/ +static void +F_MF15(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF15", ("FSM function F_MF15 executing\n")); + + if(l2sc->own_busy == 0) + { + l2sc->own_busy = 1; + + i4b_tx_rnr_response(l2sc, F0); /* wrong in Q.921 03/93 p 64 */ + + l2sc->ack_pend = 0; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event clear own rx busy + *---------------------------------------------------------------------------*/ +static void +F_MF16(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF16", ("FSM function F_MF16 executing\n")); + + if(l2sc->own_busy != 0) + { + l2sc->own_busy = 0; + + i4b_tx_rr_response(l2sc, F0); /* wrong in Q.921 03/93 p 64 */ + + l2sc->ack_pend = 0; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd RR + *---------------------------------------------------------------------------*/ +static void +F_MF17(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF17", ("FSM function F_MF17 executing\n")); + + l2sc->peer_busy = 0; + + if(l2sc->rxd_CR == CR_CMD_FROM_NT) + { + if(l2sc->rxd_PF == 1) + { + i4b_enquiry_response(l2sc); + } + } + else + { + if(l2sc->rxd_PF == 1) + { + i4b_mdl_error_ind(l2sc, "F_MF17", MDL_ERR_A); + } + } + + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + if(l2sc->rxd_NR == l2sc->vs) + { + l2sc->va = l2sc->rxd_NR; + i4b_T200_stop(l2sc); + i4b_T203_restart(l2sc); + } + else if(l2sc->rxd_NR != l2sc->va) + { + l2sc->va = l2sc->rxd_NR; + i4b_T200_restart(l2sc); + } + l2sc->Q921_state = ST_MULTIFR; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd REJ + *---------------------------------------------------------------------------*/ +static void +F_MF18(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF18", ("FSM function F_MF18 executing\n")); + + l2sc->peer_busy = 0; + + if(l2sc->rxd_CR == CR_CMD_FROM_NT) + { + if(l2sc->rxd_PF == 1) + { + i4b_enquiry_response(l2sc); + } + } + else + { + if(l2sc->rxd_PF == 1) + { + i4b_mdl_error_ind(l2sc, "F_MF18", MDL_ERR_A); + } + } + + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + i4b_T200_stop(l2sc); + i4b_T203_start(l2sc); + i4b_invoke_retransmission(l2sc, l2sc->rxd_NR); + l2sc->Q921_state = ST_MULTIFR; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd RNR + *---------------------------------------------------------------------------*/ +static void +F_MF19(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF19", ("FSM function F_MF19 executing\n")); + + l2sc->peer_busy = 1; + + if(l2sc->rxd_CR == CR_CMD_FROM_NT) + { + if(l2sc->rxd_PF == 1) + { + i4b_enquiry_response(l2sc); + } + } + else + { + if(l2sc->rxd_PF == 1) + { + i4b_mdl_error_ind(l2sc, "F_MF19", MDL_ERR_A); + } + } + + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + i4b_T203_stop(l2sc); + i4b_T200_restart(l2sc); + l2sc->Q921_state = ST_MULTIFR; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_MULTIFR event rx'd FRMR + *---------------------------------------------------------------------------*/ +static void +F_MF20(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_MF20", ("FSM function F_MF20 executing\n")); + + i4b_mdl_error_ind(l2sc, "F_MF20", MDL_ERR_K); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 0; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event dl establish request + *---------------------------------------------------------------------------*/ +static void +F_TR01(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR01", ("FSM function F_TR01 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 1; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event persistent deactivation + *---------------------------------------------------------------------------*/ +static void +F_TR05(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR05", ("FSM function F_TR05 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event mdl remove request + *---------------------------------------------------------------------------*/ +static void +F_TR06(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR06", ("FSM function F_TR06 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); + +/*XXX*/ i4b_mdl_assign_ind(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd SABME + *---------------------------------------------------------------------------*/ +static void +F_TR07(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR07", ("FSM function F_TR07 executing\n")); + + i4b_clear_exception_conditions(l2sc); + + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_ACTIVE); + + i4b_tx_ua(l2sc, l2sc->rxd_PF); + + i4b_mdl_error_ind(l2sc, "F_TR07", MDL_ERR_F); + + if(l2sc->vs != l2sc->va) + { + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Est_Ind_A; + } + + i4b_T200_stop(l2sc); + i4b_T203_start(l2sc); + + l2sc->vs = 0; + l2sc->va = 0; + l2sc->vr = 0; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd DISC + *---------------------------------------------------------------------------*/ +static void +F_TR08(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR08", ("FSM function F_TR08 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + MDL_Status_Ind(l2sc->unit, STI_L2STAT, LAYER_IDLE); + i4b_tx_ua(l2sc, l2sc->rxd_PF); + + l2sc->postfsmarg = l2sc->unit; + l2sc->postfsmfunc = DL_Rel_Ind_A; + + i4b_T200_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd UA + *---------------------------------------------------------------------------*/ +static void +F_TR09(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR09", ("FSM function F_TR09 executing\n")); + if(l2sc->rxd_PF) + i4b_mdl_error_ind(l2sc, "F_TR09", MDL_ERR_C); + else + i4b_mdl_error_ind(l2sc, "F_TR09", MDL_ERR_D); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd DM + *---------------------------------------------------------------------------*/ +static void +F_TR10(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR10", ("FSM function F_TR10 executing\n")); + + if(l2sc->rxd_PF) + { + i4b_mdl_error_ind(l2sc, "F_TR10", MDL_ERR_B); + } + else + { + i4b_mdl_error_ind(l2sc, "F_TR10", MDL_ERR_E); + } + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 0; +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event T200 expiry + *---------------------------------------------------------------------------*/ +static void +F_TR11(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR11", ("FSM function F_TR11 executing\n")); + + if(l2sc->RC >= N200) + { + i4b_mdl_error_ind(l2sc, "F_TR11", MDL_ERR_I); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 0; + + l2sc->Q921_state = ST_AW_EST; + } + else + { + i4b_transmit_enquire(l2sc); + + l2sc->RC++; + + l2sc->Q921_state = ST_TIMREC; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event dl data request + *---------------------------------------------------------------------------*/ +static void +F_TR12(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR12", ("FSM function F_TR12 executing\n")); + + i4b_i_frame_queued_up(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event dl release request + *---------------------------------------------------------------------------*/ +static void +F_TR13(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR13", ("FSM function F_TR13 executing\n")); + + i4b_Dcleanifq(&l2sc->i_queue); + + l2sc->RC = 0; + + i4b_tx_disc(l2sc, P1); + + i4b_T200_restart(l2sc); +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event set own rx busy + *---------------------------------------------------------------------------*/ +static void +F_TR15(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR15", ("FSM function F_TR15 executing\n")); + + if(l2sc->own_busy == 0) + { + l2sc->own_busy = 1; + + i4b_tx_rnr_response(l2sc, F0); + + l2sc->ack_pend = 0; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event clear own rx busy + *---------------------------------------------------------------------------*/ +static void +F_TR16(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR16", ("FSM function F_TR16 executing\n")); + + if(l2sc->own_busy != 0) + { + l2sc->own_busy = 0; + + i4b_tx_rr_response(l2sc, F0); /* this is wrong */ + /* in Q.921 03/93 p 74 ! */ + l2sc->ack_pend = 0; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd RR + *---------------------------------------------------------------------------*/ +static void +F_TR17(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR17", ("FSM function F_TR17 executing\n")); + + l2sc->peer_busy = 0; + + if(l2sc->rxd_CR == CR_CMD_FROM_NT) + { + if(l2sc->rxd_PF == 1) + { + i4b_enquiry_response(l2sc); + } + } + else + { + if(l2sc->rxd_PF == 1) + { + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + i4b_T200_stop(l2sc); + i4b_T203_start(l2sc); + i4b_invoke_retransmission(l2sc, l2sc->rxd_NR); + l2sc->Q921_state = ST_MULTIFR; + return; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + return; + } + } + } + + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + l2sc->Q921_state = ST_TIMREC; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event + *---------------------------------------------------------------------------*/ +static void +F_TR18(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR18", ("FSM function F_TR18 executing\n")); + + l2sc->peer_busy = 0; + + if(l2sc->rxd_CR == CR_CMD_FROM_NT) + { + if(l2sc->rxd_PF == 1) + { + i4b_enquiry_response(l2sc); + } + } + else + { + if(l2sc->rxd_PF == 1) + { + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + i4b_T200_stop(l2sc); + i4b_T203_start(l2sc); + i4b_invoke_retransmission(l2sc, l2sc->rxd_NR); + l2sc->Q921_state = ST_MULTIFR; + return; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + return; + } + } + } + + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + l2sc->Q921_state = ST_TIMREC; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd RNR + *---------------------------------------------------------------------------*/ +static void +F_TR19(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR19", ("FSM function F_TR19 executing\n")); + + l2sc->peer_busy = 0; + + if(l2sc->rxd_CR == CR_CMD_FROM_NT) + { + if(l2sc->rxd_PF == 1) + { + i4b_enquiry_response(l2sc); + } + } + else + { + if(l2sc->rxd_PF == 1) + { + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + i4b_T200_restart(l2sc); + i4b_invoke_retransmission(l2sc, l2sc->rxd_NR); + l2sc->Q921_state = ST_MULTIFR; + return; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + return; + } + } + } + + if(i4b_l2_nr_ok(l2sc->rxd_NR, l2sc->va, l2sc->vs)) + { + l2sc->va = l2sc->rxd_NR; + l2sc->Q921_state = ST_TIMREC; + } + else + { + i4b_nr_error_recovery(l2sc); + l2sc->Q921_state = ST_AW_EST; + } +} + +/*---------------------------------------------------------------------------* + * FSM state ST_TIMREC event rx'd FRMR + *---------------------------------------------------------------------------*/ +static void +F_TR20(l2_softc_t *l2sc) +{ + DBGL2(L2_F_MSG, "F_TR20", ("FSM function F_TR20 executing\n")); + + i4b_mdl_error_ind(l2sc, "F_TR20", MDL_ERR_K); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 0; +} + +#endif /* NI4BQ921 > 0 */ diff --git a/sys/i4b/layer2/i4b_l2fsm.h b/sys/i4b/layer2/i4b_l2fsm.h new file mode 100644 index 000000000000..8f510682bebf --- /dev/null +++ b/sys/i4b/layer2/i4b_l2fsm.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2fsm.h - layer 2 FSM + * ------------------------- + * + * $Id: i4b_l2fsm.h,v 1.3 1998/12/05 18:05:13 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:28:39 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L2FSM_H_ +#define _I4B_L2FSM_H_ + +enum Q921_states { + ST_TEI_UNAS, /* TEI unassigned */ + ST_ASG_AW_TEI, /* assign awaiting TEI */ + ST_EST_AW_TEI, /* establish awaiting TEI */ + ST_TEI_ASGD, /* TEI assigned */ + + ST_AW_EST, /* awaiting establishment */ + ST_AW_REL, /* awaiting release */ + ST_MULTIFR, /* multiple frame established */ + ST_TIMREC, /* timer recovery */ + + ST_SUBSET, /* SUBroutine SETs new state */ + ST_ILL, /* illegal state */ + N_STATES /* number of states */ +}; + +enum Q921_events { + EV_DLESTRQ, /* dl establish req */ + EV_DLUDTRQ, /* dl unit data req */ + EV_MDASGRQ, /* mdl assign req */ + EV_MDERRRS, /* mdl error response */ + EV_PSDEACT, /* persistent deactivation */ + EV_MDREMRQ, /* mdl remove req */ + EV_RXSABME, /* rx'd SABME */ + EV_RXDISC, /* rx'd DISC */ + EV_RXUA, /* rx'd UA */ + EV_RXDM, /* rx'd DM */ + EV_T200EXP, /* T200 expired */ + EV_DLDATRQ, /* dl data req */ + EV_DLRELRQ, /* dl release req */ + EV_T203EXP, /* T203 expired */ + EV_OWNBUSY, /* set own rx busy */ + EV_OWNRDY, /* clear own rx busy */ + EV_RXRR, /* rx'd RR */ + EV_RXREJ, /* rx'd REJ */ + EV_RXRNR, /* rx'd RNR */ + EV_RXFRMR, /* rx'd FRMR */ + + EV_ILL, /* Illegal */ + N_EVENTS +}; + +#endif /* _I4B_L2FSM_H_ */ + diff --git a/sys/i4b/layer2/i4b_l2timer.c b/sys/i4b/layer2/i4b_l2timer.c new file mode 100644 index 000000000000..3b45e807dcdb --- /dev/null +++ b/sys/i4b/layer2/i4b_l2timer.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2timer.c - layer 2 timer handling + * -------------------------------------- + * + * $Id: i4b_l2timer.c,v 1.12 1998/12/05 18:05:15 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:29:13 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * Q.921 timer T200 timeout function + *---------------------------------------------------------------------------*/ +static void +i4b_T200_timeout(l2_softc_t *l2sc) +{ + DBGL2(L2_T_ERR, "i4b_T200_timeout", ("unit %d, RC = %d\n", l2sc->unit, l2sc->RC)); + i4b_next_l2state(l2sc, EV_T200EXP); +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T200 start + *---------------------------------------------------------------------------*/ +void +i4b_T200_start(l2_softc_t *l2sc) +{ + DBGL2(L2_T_MSG, "i4b_T200_start", ("unit %d\n", l2sc->unit)); + l2sc->T200 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + l2sc->T200_callout = timeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc, T200DEF); +#else + timeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc, T200DEF); +#endif +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T200 stop + *---------------------------------------------------------------------------*/ +void +i4b_T200_stop(l2_softc_t *l2sc) +{ + if(l2sc->T200 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc, l2sc->T200_callout); +#else + untimeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc); +#endif + l2sc->T200 = TIMER_IDLE; + } + DBGL2(L2_T_MSG, "i4b_T200_stop", ("unit %d\n", l2sc->unit)); +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T200 restart + *---------------------------------------------------------------------------*/ +void +i4b_T200_restart(l2_softc_t *l2sc) +{ + if(l2sc->T200 != TIMER_IDLE) +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc, l2sc->T200_callout); +#else + untimeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc); +#endif + else + l2sc->T200 = TIMER_ACTIVE; + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + l2sc->T200_callout = timeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc, T200DEF); +#else + timeout((TIMEOUT_FUNC_T)i4b_T200_timeout, (void *)l2sc, T200DEF); +#endif + + DBGL2(L2_T_MSG, "i4b_T200_restart", ("unit %d\n", l2sc->unit)); +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T202 timeout function + *---------------------------------------------------------------------------*/ +static void +i4b_T202_timeout(l2_softc_t *l2sc) +{ + DBGL2(L2_T_ERR, "i4b_T202_timeout", ("unit %d, N202 = %d\n", l2sc->unit, l2sc->N202)); + + if(--(l2sc->N202)) + { + (*l2sc->T202func)(l2sc); + } +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T202 start + *---------------------------------------------------------------------------*/ +void +i4b_T202_start(l2_softc_t *l2sc) +{ + DBGL2(L2_T_MSG, "i4b_T202_start", ("unit %d\n", l2sc->unit)); + l2sc->N202 = N202DEF; + l2sc->T202 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + l2sc->T202_callout = timeout((TIMEOUT_FUNC_T)i4b_T202_timeout, (void *)l2sc, T202DEF); +#else + timeout((TIMEOUT_FUNC_T)i4b_T202_timeout, (void *)l2sc, T202DEF); +#endif +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T202 stop + *---------------------------------------------------------------------------*/ +void +i4b_T202_stop(l2_softc_t *l2sc) +{ + if(l2sc->T202 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)i4b_T202_timeout, (void *)l2sc, l2sc->T202_callout); +#else + untimeout((TIMEOUT_FUNC_T)i4b_T202_timeout, (void *)l2sc); +#endif + l2sc->T202 = TIMER_IDLE; + } + DBGL2(L2_T_MSG, "i4b_T202_stop", ("unit %d\n", l2sc->unit)); +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T203 timeout function + *---------------------------------------------------------------------------*/ +#if I4B_T203_ACTIVE +static void +i4b_T203_timeout(l2_softc_t *l2sc) +{ + DBGL2(L2_T_ERR, "i4b_T203_timeout", ("unit %d\n", l2sc->unit)); + i4b_next_l2state(l2sc, EV_T203EXP); +} +#endif + +/*---------------------------------------------------------------------------* + * Q.921 timer T203 start + *---------------------------------------------------------------------------*/ +void +i4b_T203_start(l2_softc_t *l2sc) +{ +#if I4B_T203_ACTIVE + DBGL2(L2_T_MSG, "i4b_T203_start", ("unit %d\n", l2sc->unit)); + l2sc->T203 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + l2sc->T203_callout = timeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc, T203DEF); +#else + timeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc, T203DEF); +#endif +#endif +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T203 stop + *---------------------------------------------------------------------------*/ +void +i4b_T203_stop(l2_softc_t *l2sc) +{ +#if I4B_T203_ACTIVE + if(l2sc->T203 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc, l2sc->T203_callout); +#else + untimeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc); +#endif + l2sc->T203 = TIMER_IDLE; + } + DBGL2(L2_T_MSG, "i4b_T203_stop", ("unit %d\n", l2sc->unit)); +#endif +} + +/*---------------------------------------------------------------------------* + * Q.921 timer T203 restart + *---------------------------------------------------------------------------*/ +void +i4b_T203_restart(l2_softc_t *l2sc) +{ +#if I4B_T203_ACTIVE + if(l2sc->T203 != TIMER_IDLE) +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc, l2sc->T203_callout); +#else + untimeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc); +#endif + else + l2sc->T203 = TIMER_ACTIVE; + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + l2sc->T203_callout = timeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc, T203DEF); +#else + timeout((TIMEOUT_FUNC_T)i4b_T203_timeout, (void *)l2sc, T203DEF); +#endif + + DBGL2(L2_T_MSG, "i4b_T203_restart", ("unit %d\n", l2sc->unit)); +#endif +} + +#endif /* NI4BQ921 > 0 */ + diff --git a/sys/i4b/layer2/i4b_lme.c b/sys/i4b/layer2/i4b_lme.c new file mode 100644 index 000000000000..b179e94bfe43 --- /dev/null +++ b/sys/i4b/layer2/i4b_lme.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_lme.c - layer management entity + * ------------------------------------- + * + * $Id: i4b_lme.c,v 1.8 1998/12/05 18:05:19 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:29:25 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * mdl assign indication handler + *---------------------------------------------------------------------------*/ +void +i4b_mdl_assign_ind(l2_softc_t *l2sc) +{ + DBGL2(L2_PRIM, "MDL-ASSIGN-IND", ("unit %d\n", l2sc->unit)); + + i4b_l1_activate(l2sc); + + if(l2sc->tei_valid == TEI_VALID) + { + l2sc->T202func = (void(*)(void*))i4b_tei_verify; + l2sc->N202 = N202DEF; + i4b_tei_verify(l2sc); + } + else + { + l2sc->T202func = (void(*)(void*))i4b_tei_assign; + l2sc->N202 = N202DEF; + i4b_tei_assign(l2sc); + } +} + +/*---------------------------------------------------------------------------* + * i4b_mdl_error_ind handler (Q.921 01/94 pp 156) + *---------------------------------------------------------------------------*/ +void +i4b_mdl_error_ind(l2_softc_t *l2sc, char *where, int errorcode) +{ + static char *error_text[] = { + "MDL_ERR_A: rx'd unsolicited response - supervisory (F=1)", + "MDL_ERR_B: rx'd unsolicited response - DM (F=1)", + "MDL_ERR_C: rx'd unsolicited response - UA (F=1)", + "MDL_ERR_D: rx'd unsolicited response - UA (F=0)", + "MDL_ERR_E: rx'd unsolicited response - DM (F=0)", + "MDL_ERR_F: peer initiated re-establishment - SABME", + "MDL_ERR_G: unsuccessful transmission N200times - SABME", + "MDL_ERR_H: unsuccessful transmission N200times - DIS", + "MDL_ERR_I: unsuccessful transmission N200times - Status ENQ", + "MDL_ERR_J: other error - N(R) error", + "MDL_ERR_K: other error - rx'd FRMR response", + "MDL_ERR_L: other error - rx'd undefined frame", + "MDL_ERR_M: other error - receipt of I field not permitted", + "MDL_ERR_N: other error - rx'd frame with wrong size", + "MDL_ERR_O: other error - N201 error", + "MDL_ERR_MAX: i4b_mdl_error_ind called with wrong parameter!!!" + }; + + if(errorcode > MDL_ERR_MAX) + errorcode = MDL_ERR_MAX; + + DBGL2(L2_ERROR, "i4b_mdl_error_ind", ("unit = %d, location = %s\n", l2sc->unit, where)); + DBGL2(L2_ERROR, "i4b_mdl_error_ind", ("error = %s\n", error_text[errorcode])); + + switch(errorcode) + { + case MDL_ERR_A: + case MDL_ERR_B: + break; + + case MDL_ERR_C: + case MDL_ERR_D: + i4b_tei_verify(l2sc); + break; + + case MDL_ERR_E: + case MDL_ERR_F: + break; + + case MDL_ERR_G: + case MDL_ERR_H: + i4b_tei_verify(l2sc); + break; + + case MDL_ERR_I: + case MDL_ERR_J: + case MDL_ERR_K: + case MDL_ERR_L: + case MDL_ERR_M: + case MDL_ERR_N: + case MDL_ERR_O: + break; + + default: + break; + } +} + +#endif /* NI4BQ921 > 0 */ diff --git a/sys/i4b/layer2/i4b_mbuf.c b/sys/i4b/layer2/i4b_mbuf.c new file mode 100644 index 000000000000..6d085c3e08c0 --- /dev/null +++ b/sys/i4b/layer2/i4b_mbuf.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b - mbuf handling support routines + * ------------------------------------ + * + * $Id: i4b_mbuf.c,v 1.10 1998/12/05 18:05:20 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:29:44 1998] + * + *---------------------------------------------------------------------------*/ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#define I4B_MBUF_DEBUG +#undef I4B_MBUF_TYPE_DEBUG + +#ifdef I4B_MBUF_TYPE_DEBUG + +#ifdef __FreeBSD__ + +#define MT_DCHAN 42 +#define MT_BCHAN 43 + +#else /* NetBSD */ + +#define MT_DCHAN MT_DATA +#define MT_BCHAN MT_DATA + +#endif + +#define MT_I4B_D MT_DCHAN +#define MT_I4B_B MT_BCHAN + +#else /* ! I4B_MBUF_TYPE_DEBUG */ + +#define MT_I4B_D MT_DATA +#define MT_I4B_B MT_DATA + +#endif /* I4B_MBUF_TYPE_DEBUG */ + +/*---------------------------------------------------------------------------* + * allocate D-channel mbuf space + *---------------------------------------------------------------------------*/ +struct mbuf* +i4b_Dgetmbuf(int len) +{ + struct mbuf *m; + + if(len > MCLBYTES) /* if length > max extension size */ + { + +#ifdef I4B_MBUF_DEBUG + printf("i4b_getmbuf: error - len(%d) > MCLBYTES(%d)\n", + len, MCLBYTES); +#endif + + return(NULL); + } + + MGETHDR(m, M_DONTWAIT, MT_I4B_D); /* get mbuf with pkthdr */ + + /* did we actually get the mbuf ? */ + + if(!m) + { + +#ifdef I4B_MBUF_DEBUG + printf("i4b_getbuf: error - MGETHDR failed!\n"); +#endif + + return(NULL); + } + + if(len >= MHLEN) + { + MCLGET(m, M_DONTWAIT); + + if(!(m->m_flags & M_EXT)) + { + m_freem(m); + +#ifdef I4B_MBUF_DEBUG + printf("i4b_getbuf: error - MCLGET failed, len(%d)\n", len); +#endif + + return (NULL); + } + } + + m->m_len = len; + + return(m); +} + +/*---------------------------------------------------------------------------* + * free a D-channel mbuf + *---------------------------------------------------------------------------*/ +void +i4b_Dfreembuf(struct mbuf *m) +{ + if(m) + m_freem(m); +} + +/*---------------------------------------------------------------------------* + * clear a D-channel ifqueue from data + *---------------------------------------------------------------------------*/ +void +i4b_Dcleanifq(struct ifqueue *ifq) +{ + struct mbuf *m; + int x = splimp(); + + while(!IF_QEMPTY(ifq)) + { + IF_DEQUEUE(ifq, m); + i4b_Dfreembuf(m); + } + + splx(x); +} + +/*---------------------------------------------------------------------------* + * allocate B-channel mbuf space + *---------------------------------------------------------------------------*/ +struct mbuf* +i4b_Bgetmbuf(int len) +{ + struct mbuf *m; + + if(len > MCLBYTES) /* if length > max extension size */ + { + +#ifdef I4B_MBUF_DEBUG + printf("i4b_getmbuf: error - len(%d) > MCLBYTES(%d)\n", + len, MCLBYTES); +#endif + + return(NULL); + } + + MGETHDR(m, M_DONTWAIT, MT_I4B_B); /* get mbuf with pkthdr */ + + /* did we actually get the mbuf ? */ + + if(!m) + { + +#ifdef I4B_MBUF_DEBUG + printf("i4b_getbuf: error - MGETHDR failed!\n"); +#endif + + return(NULL); + } + + if(len >= MHLEN) + { + MCLGET(m, M_DONTWAIT); + + if(!(m->m_flags & M_EXT)) + { + m_freem(m); + +#ifdef I4B_MBUF_DEBUG + printf("i4b_getbuf: error - MCLGET failed, len(%d)\n", len); +#endif + + return (NULL); + } + } + + m->m_len = len; + + return(m); +} + +/*---------------------------------------------------------------------------* + * free a B-channel mbuf + *---------------------------------------------------------------------------*/ +void +i4b_Bfreembuf(struct mbuf *m) +{ + if(m) + m_freem(m); +} + +/*---------------------------------------------------------------------------* + * clear a B-channel ifqueue from data + *---------------------------------------------------------------------------*/ +void +i4b_Bcleanifq(struct ifqueue *ifq) +{ + struct mbuf *m; + int x = splimp(); + + while(!IF_QEMPTY(ifq)) + { + IF_DEQUEUE(ifq, m); + i4b_Bfreembuf(m); + } + + splx(x); +} + +/* EOF */ diff --git a/sys/i4b/layer2/i4b_sframe.c b/sys/i4b/layer2/i4b_sframe.c new file mode 100644 index 000000000000..f8d14ba1a246 --- /dev/null +++ b/sys/i4b/layer2/i4b_sframe.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_sframe.c - s frame handling routines + * ---------------------------------------- + * + * $Id: i4b_sframe.c,v 1.8 1998/12/05 18:05:21 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:30:02 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * process s frame + *---------------------------------------------------------------------------*/ +void +i4b_rxd_s_frame(int unit, struct mbuf *m) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + u_char *ptr = m->m_data; + + if(!((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI))))) + { + i4b_Dfreembuf(m); + return; + } + + l2sc->rxd_CR = GETCR(*(ptr + OFF_SAPI)); + l2sc->rxd_PF = GETSPF(*(ptr + OFF_SNR)); + l2sc->rxd_NR = GETSNR(*(ptr + OFF_SNR)); + + i4b_rxd_ack(l2sc, l2sc->rxd_NR); + + switch(*(ptr + OFF_SRCR)) + { + case RR: + DBGL2(L2_S_MSG, "i4b_rxd_s_frame", ("rx'd RR, N(R) = %d\n", l2sc->rxd_NR)); + i4b_next_l2state(l2sc, EV_RXRR); + break; + + case RNR: + DBGL2(L2_S_MSG, "i4b_rxd_s_frame", ("rx'd RNR, N(R) = %d\n", l2sc->rxd_NR)); + i4b_next_l2state(l2sc, EV_RXRNR); + break; + + case REJ: + DBGL2(L2_S_MSG, "i4b_rxd_s_frame", ("rx'd REJ, N(R) = %d\n", l2sc->rxd_NR)); + i4b_next_l2state(l2sc, EV_RXREJ); + break; + + default: + DBGL2(L2_S_ERR, "i4b_rxd_s_frame", ("ERROR, unknown code, frame = \n")); + i4b_print_frame(m->m_len, m->m_data); + break; + } + i4b_Dfreembuf(m); +} + +/*---------------------------------------------------------------------------* + * transmit RR command + *---------------------------------------------------------------------------*/ +void +i4b_tx_rr_command(l2_softc_t *l2sc, pbit_t pbit) +{ + struct mbuf *m; + + DBGL2(L2_S_MSG, "i4b_tx_rr_command", ("tx RR, unit = %d\n", l2sc->unit)); + + m = i4b_build_s_frame(l2sc, CR_CMD_TO_NT, pbit, RR); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit RR response + *---------------------------------------------------------------------------*/ +void +i4b_tx_rr_response(l2_softc_t *l2sc, fbit_t fbit) +{ + struct mbuf *m; + + DBGL2(L2_S_MSG, "i4b_tx_rr_response", ("tx RR, unit = %d\n", l2sc->unit)); + + m = i4b_build_s_frame(l2sc, CR_RSP_TO_NT, fbit, RR); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit RNR command + *---------------------------------------------------------------------------*/ +void +i4b_tx_rnr_command(l2_softc_t *l2sc, pbit_t pbit) +{ + struct mbuf *m; + + DBGL2(L2_S_MSG, "i4b_tx_rnr_command", ("tx RNR, unit = %d\n", l2sc->unit)); + + m = i4b_build_s_frame(l2sc, CR_CMD_TO_NT, pbit, RNR); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit RNR response + *---------------------------------------------------------------------------*/ +void +i4b_tx_rnr_response(l2_softc_t *l2sc, fbit_t fbit) +{ + struct mbuf *m; + + DBGL2(L2_S_MSG, "i4b_tx_rnr_response", ("tx RNR, unit = %d\n", l2sc->unit)); + + m = i4b_build_s_frame(l2sc, CR_RSP_TO_NT, fbit, RNR); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit REJ response + *---------------------------------------------------------------------------*/ +void +i4b_tx_rej_response(l2_softc_t *l2sc, fbit_t fbit) +{ + struct mbuf *m; + + DBGL2(L2_S_MSG, "i4b_tx_rej_response", ("tx REJ, unit = %d\n", l2sc->unit)); + + m = i4b_build_s_frame(l2sc, CR_RSP_TO_NT, fbit, REJ); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * build S-frame for sending + *---------------------------------------------------------------------------*/ +struct mbuf * +i4b_build_s_frame(l2_softc_t *l2sc, crbit_to_nt_t crbit, pbit_t pbit, u_char type) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(S_FRAME_LEN)) == NULL) + return(NULL); + + PUTSAPI(SAPI_CCP, crbit, m->m_data[OFF_SAPI]); + + PUTTEI(l2sc->tei, m->m_data[OFF_TEI]); + + m->m_data[OFF_SRCR] = type; + + m->m_data[OFF_SNR] = (l2sc->vr << 1) | (pbit & 0x01); + + return(m); +} + +#endif /* NI4BQ921 > 0 */ diff --git a/sys/i4b/layer2/i4b_tei.c b/sys/i4b/layer2/i4b_tei.c new file mode 100644 index 000000000000..5c5b7b83fd87 --- /dev/null +++ b/sys/i4b/layer2/i4b_tei.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_tei.c - tei handling procedures + * ----------------------------------- + * + * $Id: i4b_tei.c,v 1.13 1998/12/05 18:05:23 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:30:20 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/syslog.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <machine/random.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * handle a received TEI management frame + *---------------------------------------------------------------------------*/ +void +i4b_tei_rxframe(int unit, struct mbuf *m) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + u_char *ptr = m->m_data; + + switch(*(ptr + OFF_MT)) + { + case MT_ID_ASSIGN: + if( (*(ptr + OFF_RIL) == l2sc->last_ril) && + (*(ptr + OFF_RIH) == l2sc->last_rih)) + { + l2sc->tei = GET_TEIFROMAI(*(ptr+OFF_AI)); + l2sc->tei_valid = TEI_VALID; + + if(l2sc->T202 == TIMER_ACTIVE) + i4b_T202_stop(l2sc); + + MDL_Status_Ind(l2sc->unit, STI_TEIASG, l2sc->tei); + + log(LOG_INFO, "i4b: unit %d, assigned TEI = %d = 0x%02x\n", l2sc->unit, l2sc->tei, l2sc->tei); + + DBGL2(L2_TEI_MSG, "i4b_tei_rx_frame", ("TEI ID Assign - TEI = %d\n", l2sc->tei)); + + i4b_next_l2state(l2sc, EV_MDASGRQ); + } + break; + + case MT_ID_DENY: + if( (*(ptr + OFF_RIL) == l2sc->last_ril) && + (*(ptr + OFF_RIH) == l2sc->last_rih)) + { + l2sc->tei_valid = TEI_INVALID; + l2sc->tei = GET_TEIFROMAI(*(ptr+OFF_AI)); + + if(l2sc->tei == GROUP_TEI) + { + log(LOG_WARNING, "i4b: unit %d, denied TEI, no TEI values available from exchange!\n", l2sc->unit); + DBGL2(L2_TEI_ERR, "i4b_tei_rx_frame", ("TEI ID Denied, No TEI values available from exchange!\n")); + } + else + { + log(LOG_WARNING, "i4b: unit %d, denied TEI = %d = 0x%02x\n", l2sc->unit, l2sc->tei, l2sc->tei); + DBGL2(L2_TEI_ERR, "i4b_tei_rx_frame", ("TEI ID Denied - TEI = %d\n", l2sc->tei)); + } + MDL_Status_Ind(l2sc->unit, STI_TEIASG, -1); + i4b_next_l2state(l2sc, EV_MDERRRS); + } + break; + + case MT_ID_CHK_REQ: + if( (l2sc->tei_valid == TEI_VALID) && + ( (l2sc->tei == GET_TEIFROMAI(*(ptr+OFF_AI))) || + (GROUP_TEI == GET_TEIFROMAI(*(ptr+OFF_AI))) )) + { + static int lasttei = -1; + + if(l2sc->tei != lasttei) + { + DBGL2(L2_TEI_MSG, "i4b_tei_rx_frame", ("TEI ID Check Req - TEI = %d\n", l2sc->tei)); + lasttei = l2sc->tei; + } + + if(l2sc->T202 == TIMER_ACTIVE) + i4b_T202_stop(l2sc); + i4b_tei_chkresp(l2sc); + } + break; + + case MT_ID_REMOVE: + if( (l2sc->tei_valid == TEI_VALID) && + ( (l2sc->tei == GET_TEIFROMAI(*(ptr+OFF_AI))) || + (l2sc->tei == GET_TEIFROMAI(*(ptr+OFF_AI))))) + { + l2sc->tei_valid = TEI_INVALID; + l2sc->tei = GET_TEIFROMAI(*(ptr+OFF_AI)); + + log(LOG_INFO, "i4b: unit %d, removed TEI = %d = 0x%02x\n", l2sc->unit, l2sc->tei, l2sc->tei); + DBGL2(L2_TEI_MSG, "i4b_tei_rx_frame", ("TEI ID Remove - TEI = %d\n", l2sc->tei)); + MDL_Status_Ind(l2sc->unit, STI_TEIASG, -1); + i4b_next_l2state(l2sc, EV_MDREMRQ); + } + break; + + default: + DBGL2(L2_TEI_ERR, "i4b_tei_rx_frame", ("UNKNOWN TEI MGMT Frame, type = 0x%x\n", *(ptr + OFF_MT))); + i4b_print_frame(m->m_len, m->m_data); + break; + } + i4b_Dfreembuf(m); +} + +/*---------------------------------------------------------------------------* + * allocate and fill up a TEI management frame for sending + *---------------------------------------------------------------------------*/ +static struct mbuf * +build_tei_mgmt_frame(l2_softc_t *l2sc, unsigned char type) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(TEI_MGMT_FRM_LEN)) == NULL) + return(NULL); + + m->m_data[TEIM_SAPIO] = 0xfc; /* SAPI = 63, CR = 0, EA = 0 */ + m->m_data[TEIM_TEIO] = 0xff; /* TEI = 127, EA = 1 */ + m->m_data[TEIM_UIO] = UI; /* UI */ + m->m_data[TEIM_MEIO] = MEI; /* MEI */ + m->m_data[TEIM_MTO] = type; /* message type */ + + switch(type) + { + case MT_ID_REQEST: + i4b_make_rand_ri(l2sc); + m->m_data[TEIM_RILO] = l2sc->last_ril; + m->m_data[TEIM_RIHO] = l2sc->last_rih; + m->m_data[TEIM_AIO] = (GROUP_TEI << 1) | 0x01; + break; + + case MT_ID_CHK_RSP: + i4b_make_rand_ri(l2sc); + m->m_data[TEIM_RILO] = l2sc->last_ril; + m->m_data[TEIM_RIHO] = l2sc->last_rih; + m->m_data[TEIM_AIO] = (l2sc->tei << 1) | 0x01; + break; + + case MT_ID_VERIFY: + m->m_data[TEIM_RILO] = 0; + m->m_data[TEIM_RIHO] = 0; + m->m_data[TEIM_AIO] = (l2sc->tei << 1) | 0x01; + break; + + default: + i4b_Dfreembuf(m); + panic("build_tei_mgmt_frame: invalid type"); + break; + } + return(m); +} + +/*---------------------------------------------------------------------------* + * i4b_tei_assign - TEI assignment procedure (Q.921, 5.3.2, pp 24) + * T202func and N202 _MUST_ be set prior to calling this function ! + *---------------------------------------------------------------------------*/ +void +i4b_tei_assign(l2_softc_t *l2sc) +{ + struct mbuf *m; + + DBGL2(L2_TEI_MSG, "i4b_tei_assign", ("tx TEI ID_Request\n")); + + m = build_tei_mgmt_frame(l2sc, MT_ID_REQEST); + + if(m == NULL) + panic("i4b_tei_assign: no mbuf"); + + i4b_T202_start(l2sc); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * i4b_tei_assign - TEI verify procedure (Q.921, 5.3.5, pp 29) + * T202func and N202 _MUST_ be set prior to calling this function ! + *---------------------------------------------------------------------------*/ +void +i4b_tei_verify(l2_softc_t *l2sc) +{ + struct mbuf *m; + + DBGL2(L2_TEI_MSG, "i4b_tei_verify", ("tx TEI ID_Verify\n")); + + m = build_tei_mgmt_frame(l2sc, MT_ID_VERIFY); + + if(m == NULL) + panic("i4b_tei_verify: no mbuf"); + + i4b_T202_start(l2sc); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * i4b_tei_chkresp - TEI check response procedure (Q.921, 5.3.5, pp 29) + *---------------------------------------------------------------------------*/ +void +i4b_tei_chkresp(l2_softc_t *l2sc) +{ + struct mbuf *m; + static int lasttei = 0; + + if(l2sc->tei != lasttei) + { + lasttei = l2sc->tei; + DBGL2(L2_TEI_MSG, "i4b_tei_chkresp", ("tx TEI ID_Check_Response\n")); + } + + m = build_tei_mgmt_frame(l2sc, MT_ID_CHK_RSP); + + if(m == NULL) + panic("i4b_tei_chkresp: no mbuf"); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * generate some 16 bit "random" number used for TEI mgmt Ri field + *---------------------------------------------------------------------------*/ +void +i4b_make_rand_ri(l2_softc_t *l2sc) +{ + +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + + u_short val; + read_random((char *)&val, sizeof(val)); + +#else + + register u_short val; + register int i; + static int called = 42; + + val = (l2sc->last_rih << 8) | l2sc->last_ril; + + val += ++called; + + for(i=0; i < 50 ; i++, val++) + { + val |= l2sc->unit+i; + val <<= i; + val ^= (time.tv_sec >> 16) ^ time.tv_usec; + val <<= i; + val ^= time.tv_sec ^ (time.tv_usec >> 16); + + if(val != 0 && val != 0xffff) + break; + } +#endif + l2sc->last_rih = (val >> 8) & 0x00ff; + l2sc->last_ril = val & 0x00ff; +} + +#endif /* NI4BQ921 > 0 */ diff --git a/sys/i4b/layer2/i4b_uframe.c b/sys/i4b/layer2/i4b_uframe.c new file mode 100644 index 000000000000..90e79124d29c --- /dev/null +++ b/sys/i4b/layer2/i4b_uframe.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_uframe.c - routines for handling U-frames + * ----------------------------------------------- + * + * $Id: i4b_uframe.c,v 1.6 1998/12/05 18:05:24 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:30:33 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * process a received U-frame + *---------------------------------------------------------------------------*/ +void +i4b_rxd_u_frame(int unit, struct mbuf *m) +{ + l2_softc_t *l2sc = &l2_softc[unit]; + u_char *ptr = m->m_data; + + int sapi = GETSAPI(*(ptr + OFF_SAPI)); + int tei = GETTEI(*(ptr + OFF_TEI)); + int pfbit = GETUPF(*(ptr + OFF_CNTL)); + + switch(*(ptr + OFF_CNTL) & ~UPFBIT) + { + /* commands */ + + case SABME: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_MSG, "i4b_rxd_u_frame", ("SABME, sapi = %d, tei = %d\n", sapi, tei)); + + l2sc->rxd_PF = pfbit; + + i4b_next_l2state(l2sc, EV_RXSABME); + } + i4b_Dfreembuf(m); + break; + + case UI: + if(sapi == SAPI_L2M && + tei == GROUP_TEI && + *(ptr + OFF_MEI) == MEI) + { + /* layer 2 management (SAPI = 63) */ + + i4b_tei_rxframe(unit, m); + } + else if(sapi == SAPI_CCP && tei == GROUP_TEI) + { + /* call control (SAPI = 0) */ + + /* strip ui header */ + m_adj(m, UI_HDR_LEN); + /* to upper layer */ + DL_Unit_Data_Ind(unit, m); + } + else + { + DBGL2(L2_U_ERR, "i4b_rxd_u_frame", ("unknown UI frame!\n")); + + i4b_Dfreembuf(m); + } + break; + + case DISC: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_MSG, "i4b_rxd_u_frame", ("DISC, sapi = %d, tei = %d\n", sapi, tei)); + + l2sc->rxd_PF = pfbit; + + i4b_next_l2state(l2sc, EV_RXDISC); + } + i4b_Dfreembuf(m); + break; + + case XID: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_MSG, "i4b_rxd_u_frame", ("XID, sapi = %d, tei = %d\n", sapi, tei)); + } + i4b_Dfreembuf(m); + break; + + /* responses */ + + case DM: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_MSG, "i4b_rxd_u_frame", ("DM, sapi = %d, tei = %d\n", sapi, tei)); + + i4b_print_frame(m->m_len, m->m_data); + + l2sc->rxd_PF = pfbit; + + i4b_next_l2state(l2sc, EV_RXDM); + } + i4b_Dfreembuf(m); + break; + + case UA: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_MSG, "i4b_rxd_u_frame", ("UA, sapi = %d, tei = %d\n", sapi, tei)); + + l2sc->rxd_PF = pfbit; + + i4b_next_l2state(l2sc, EV_RXUA); + } + i4b_Dfreembuf(m); + break; + + case FRMR: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_MSG, "i4b_rxd_u_frame", ("FRMR, sapi = %d, tei = %d\n", sapi, tei)); + + l2sc->rxd_PF = pfbit; + + i4b_next_l2state(l2sc, EV_RXFRMR); + } + i4b_Dfreembuf(m); + break; + + default: + if((l2sc->tei_valid == TEI_VALID) && + (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) + { + DBGL2(L2_U_ERR, "i4b_rxd_u_frame", ("UNKNOWN TYPE ERROR, sapi = %d, tei = %d, frame = ", sapi, tei)); + i4b_print_frame(m->m_len, m->m_data); + } + else + { + DBGL2(L2_U_ERR, "i4b_rxd_u_frame", ("not mine - UNKNOWN TYPE ERROR, sapi = %d, tei = %d, frame = ", sapi, tei)); + i4b_print_frame(m->m_len, m->m_data); + } + i4b_Dfreembuf(m); + break; + } +} + +/*---------------------------------------------------------------------------* + * build U-frame for sending + *---------------------------------------------------------------------------*/ +struct mbuf * +i4b_build_u_frame(l2_softc_t *l2sc, crbit_to_nt_t crbit, pbit_t pbit, u_char type) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(U_FRAME_LEN)) == NULL) + return(NULL); + + PUTSAPI(SAPI_CCP, crbit, m->m_data[OFF_SAPI]); + + PUTTEI(l2sc->tei, m->m_data[OFF_TEI]); + + if(pbit) + m->m_data[OFF_CNTL] = type | UPBITSET; + else + m->m_data[OFF_CNTL] = type & ~UPBITSET; + + return(m); +} + +/*---------------------------------------------------------------------------* + * transmit SABME command + *---------------------------------------------------------------------------*/ +void +i4b_tx_sabme(l2_softc_t *l2sc, pbit_t pbit) +{ + struct mbuf *m; + + DBGL2(L2_U_MSG, "i4b_tx_sabme", ("tx SABME, tei = %d\n", l2sc->tei)); + + m = i4b_build_u_frame(l2sc, CR_CMD_TO_NT, pbit, SABME); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit DM response + *---------------------------------------------------------------------------*/ +void +i4b_tx_dm(l2_softc_t *l2sc, fbit_t fbit) +{ + struct mbuf *m; + + DBGL2(L2_U_MSG, "i4b_tx_dm", ("tx DM, tei = %d\n", l2sc->tei)); + + m = i4b_build_u_frame(l2sc, CR_RSP_TO_NT, fbit, DM); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit DISC command + *---------------------------------------------------------------------------*/ +void +i4b_tx_disc(l2_softc_t *l2sc, pbit_t pbit) +{ + struct mbuf *m; + + DBGL2(L2_U_MSG, "i4b_tx_disc", ("tx DISC, tei = %d\n", l2sc->tei)); + + m = i4b_build_u_frame(l2sc, CR_CMD_TO_NT, pbit, DISC); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit UA response + *---------------------------------------------------------------------------*/ +void +i4b_tx_ua(l2_softc_t *l2sc, fbit_t fbit) +{ + struct mbuf *m; + + DBGL2(L2_U_MSG, "i4b_tx_ua", ("tx UA, tei = %d\n", l2sc->tei)); + + m = i4b_build_u_frame(l2sc, CR_RSP_TO_NT, fbit, UA); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + +/*---------------------------------------------------------------------------* + * transmit FRMR response + *---------------------------------------------------------------------------*/ +void +i4b_tx_frmr(l2_softc_t *l2sc, fbit_t fbit) +{ + struct mbuf *m; + + DBGL2(L2_U_MSG, "i4b_tx_frmr", ("tx FRMR, tei = %d\n", l2sc->tei)); + + m = i4b_build_u_frame(l2sc, CR_RSP_TO_NT, fbit, FRMR); + + PH_Data_Req(l2sc->unit, m, MBUF_FREE); +} + + +#endif /* NI4BQ921 > 0 */ diff --git a/sys/i4b/layer2/i4b_util.c b/sys/i4b/layer2/i4b_util.c new file mode 100644 index 000000000000..9f8fe196c56c --- /dev/null +++ b/sys/i4b/layer2/i4b_util.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_util.c - layer 2 utility routines + * ------------------------------------- + * + * $Id: i4b_util.c,v 1.15 1998/12/05 18:05:26 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:31:10 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq921.h" +#else +#define NI4BQ921 1 +#endif +#if NI4BQ921 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l1l2.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer2/i4b_l2.h> +#include <i4b/layer2/i4b_l2fsm.h> + +/*---------------------------------------------------------------------------* + * routine ESTABLISH DATA LINK (Q.921 03/93 page 83) + *---------------------------------------------------------------------------*/ +void +i4b_establish_data_link(l2_softc_t *l2sc) +{ + i4b_l1_activate(l2sc); + + i4b_clear_exception_conditions(l2sc); + + l2sc->RC = 0; + + i4b_tx_sabme(l2sc, P1); + + i4b_T200_restart(l2sc); + + i4b_T203_stop(l2sc); +} + +/*---------------------------------------------------------------------------* + * routine CLEAR EXCEPTION CONDITIONS (Q.921 03/93 page 83) + *---------------------------------------------------------------------------*/ +void +i4b_clear_exception_conditions(l2_softc_t *l2sc) +{ + +/*XXX -------------------------------------------------------------- */ +/*XXX is this really appropriate here or should it moved elsewhere ? */ + + i4b_Dcleanifq(&l2sc->i_queue); + + if(l2sc->ua_num != UA_EMPTY) + { + i4b_Dfreembuf(l2sc->ua_frame); + l2sc->ua_num = UA_EMPTY; + } +/*XXX -------------------------------------------------------------- */ + + l2sc->peer_busy = 0; + + l2sc->rej_excpt = 0; + + l2sc->own_busy = 0; + + l2sc->ack_pend = 0; +} + +/*---------------------------------------------------------------------------* + * routine TRANSMIT ENQUIRE (Q.921 03/93 page 83) + *---------------------------------------------------------------------------*/ +void +i4b_transmit_enquire(l2_softc_t *l2sc) +{ + if(l2sc->own_busy) + i4b_tx_rnr_command(l2sc, P1); + else + i4b_tx_rr_command(l2sc, P1); + + l2sc->ack_pend = 0; + + i4b_T200_start(l2sc); +} + +/*---------------------------------------------------------------------------* + * routine NR ERROR RECOVERY (Q.921 03/93 page 83) + *---------------------------------------------------------------------------*/ +void +i4b_nr_error_recovery(l2_softc_t *l2sc) +{ + i4b_mdl_error_ind(l2sc, "i4b_nr_error_recovery", MDL_ERR_J); + + i4b_establish_data_link(l2sc); + + l2sc->l3initiated = 0; +} + +/*---------------------------------------------------------------------------* + * routine ENQUIRY RESPONSE (Q.921 03/93 page 84) + *---------------------------------------------------------------------------*/ +void +i4b_enquiry_response(l2_softc_t *l2sc) +{ + if(l2sc->own_busy) + i4b_tx_rnr_response(l2sc, F1); + else + i4b_tx_rr_response(l2sc, F1); + + l2sc->ack_pend = 0; +} + +/*---------------------------------------------------------------------------* + * routine INVOKE RETRANSMISSION (Q.921 03/93 page 84) + *---------------------------------------------------------------------------*/ +void +i4b_invoke_retransmission(l2_softc_t *l2sc, int nr) +{ + DBGL2(L2_ERROR, "i4b_invoke_retransmission", ("nr = %d\n", nr )); + + while(l2sc->vs != nr) + { + DBGL2(L2_ERROR, "i4b_invoke_retransmission", ("nr != vs, nr = %d, vs = %d\n", nr, l2sc->vs)); + + M128DEC(l2sc->vs); + +/* XXXXXXXXXXXXXXXXX */ + + if((l2sc->ua_num != UA_EMPTY) && (l2sc->vs == l2sc->ua_num)) + { + IF_ENQUEUE(&l2sc->i_queue, l2sc->ua_frame); + l2sc->ua_num = UA_EMPTY; + } + else + { + DBGL2(L2_ERROR, "i4b_invoke_retransmission", ("ERROR, l2sc->vs = %d, l2sc->ua_num = %d \n",l2sc->vs, l2sc->ua_num)); + } + +/* XXXXXXXXXXXXXXXXX */ + + i4b_i_frame_queued_up(l2sc); + } +} + +/*---------------------------------------------------------------------------* + * routine ACKNOWLEDGE PENDING (Q.921 03/93 p 70) + *---------------------------------------------------------------------------*/ +void +i4b_acknowledge_pending(l2_softc_t *l2sc) +{ + if(l2sc->ack_pend) + { + l2sc->ack_pend = 0; + i4b_tx_rr_response(l2sc, F0); + } +} + +/*---------------------------------------------------------------------------* + * i4b_print_frame - just print the hex contents of a frame + *---------------------------------------------------------------------------*/ +void +i4b_print_frame(int len, u_char *buf) +{ +#ifdef DO_I4B_DEBUG + int i; + + if (!(i4b_l2_debug & L2_ERROR)) /* XXXXXXXXXXXXXXXXXXXXX */ + return; + + for(i = 0; i < len; i++) + printf(" 0x%x", buf[i]); + printf("\n"); +#endif +} + +/*---------------------------------------------------------------------------* + * i4b_print_l2var - print some l2softc vars + *---------------------------------------------------------------------------*/ +void +i4b_print_l2var(l2_softc_t *l2sc) +{ + DBGL2(L2_ERROR, "i4b_print_l2var", ("unit%d V(R)=%d, V(S)=%d, V(A)=%d,ACKP=%d,PBSY=%d,OBSY=%d\n", + l2sc->unit, + l2sc->vr, + l2sc->vs, + l2sc->va, + l2sc->ack_pend, + l2sc->peer_busy, + l2sc->own_busy)); +} + +/*---------------------------------------------------------------------------* + * got s or i frame, check if valid ack for last sent frame + *---------------------------------------------------------------------------*/ +void +i4b_rxd_ack(l2_softc_t *l2sc, int nr) +{ + +#ifdef NOTDEF + DBGL2(L2_ERROR, "i4b_rxd_ack", ("N(R)=%d, UA=%d, V(R)=%d, V(S)=%d, V(A)=%d\n", + nr, + l2sc->ua_num, + l2sc->vr, + l2sc->vs, + l2sc->va)); +#endif + + if(l2sc->ua_num != UA_EMPTY) + { + int s; + + M128DEC(nr); + + if(l2sc->ua_num != nr) + DBGL2(L2_ERROR, "i4b_rxd_ack", ("((N(R)-1)=%d) != (UA=%d) !!!\n", nr, l2sc->ua_num)); + + s = SPLI4B(); + + i4b_Dfreembuf(l2sc->ua_frame); + l2sc->ua_num = UA_EMPTY; + + splx(s); + } +} + +/*---------------------------------------------------------------------------* + * if not already active, activate layer 1 + *---------------------------------------------------------------------------*/ +void +i4b_l1_activate(l2_softc_t *l2sc) +{ + if(l2sc->ph_active == PH_INACTIVE) + { + l2sc->ph_active = PH_ACTIVEPEND; + PH_Act_Req(l2sc->unit); + } +}; + +/*---------------------------------------------------------------------------* + * check for v(a) <= n(r) <= v(s) + * nr = receive sequence frame counter, va = acknowledge sequence frame + * counter and vs = transmit sequence frame counter + *---------------------------------------------------------------------------*/ +int +i4b_l2_nr_ok(int nr, int va, int vs) +{ + if((va > nr) && ((nr != 0) || (va != 127))) + { + DBGL2(L2_ERROR, "i4b_l2_nr_ok", ("ERROR, va = %d, nr = %d, vs = %d [1]\n", va, nr, vs)); + return 0; /* fail */ + } + + if((nr > vs) && ((vs != 0) || (nr != 127))) + { + DBGL2(L2_ERROR, "i4b_l2_nr_ok", ("ERROR, va = %d, nr = %d, vs = %d [2]\n", va, nr, vs)); + return 0; /* fail */ + } + + return 1; /* good */ +} + +#endif /* NI4BQ921 > 0 */ + diff --git a/sys/i4b/layer3/i4b_l2if.c b/sys/i4b/layer3/i4b_l2if.c new file mode 100644 index 000000000000..33b1340738ec --- /dev/null +++ b/sys/i4b/layer3/i4b_l2if.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l2if.c - Layer 3 interface to Layer 2 + * ------------------------------------------- + * + * $Id: i4b_l2if.c,v 1.14 1998/12/05 18:05:28 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:31:26 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif +#if NI4BQ931 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> + +#include <i4b/layer4/i4b_l4.h> + +static unsigned char make_q931_cause(cause_t cause); + +/*---------------------------------------------------------------------------* + * this converts our internal state (number) to the number specified + * in Q.931 and is used for reporting our state in STATUS messages. + *---------------------------------------------------------------------------*/ +int i4b_status_tab[] = { + 0, /* ST_U0, */ + 1, /* ST_U1, */ + 3, /* ST_U3, */ + 4, /* ST_U4, */ + 6, /* ST_U6, */ + 7, /* ST_U7, */ + 8, /* ST_U8, */ + 9, /* ST_U9, */ + 10, /* ST_U10, */ + 11, /* ST_U11, */ + 12, /* ST_U12, */ + 19, /* ST_U19, */ + 6, /* ST_IWA, */ + 6, /* ST_IWR, */ + 1, /* ST_OW, */ + 6, /* ST_IWL, */ +}; + +/*---------------------------------------------------------------------------* + * return a valid q.931/q.850 cause from any of the internal causes + *---------------------------------------------------------------------------*/ +static unsigned char +make_q931_cause(cause_t cause) +{ + register unsigned char ret; + + switch(GET_CAUSE_TYPE(cause)) + { + case CAUSET_Q850: + ret = GET_CAUSE_VAL(cause); + break; + case CAUSET_I4B: + ret = cause_tab_q931[GET_CAUSE_VAL(cause)]; + break; + default: + panic("make_q931_cause: unknown cause type!"); + break; + } + ret |= EXT_LAST; + return(ret); +} + +/*---------------------------------------------------------------------------* + * return status of data link + *---------------------------------------------------------------------------*/ +int +i4b_get_dl_stat(call_desc_t *cd) +{ + return(ctrl_desc[cd->controller].dl_est); +} + +/*---------------------------------------------------------------------------* + * DL ESTABLISH INDICATION from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_establish_ind(int unit) +{ + int i; + int found = 0; + + DBGL2(L2_PRIM, "DL-ESTABLISH-IND", ("unit %d\n",unit)); + + /* first set DL up in controller descriptor */ + + for(i=0; i < nctrl; i++) + { + if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[i].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_establish_ind", ("unit=%d DL established!\n",unit)); + ctrl_desc[i].dl_est = DL_UP; + found = 1; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_establish_ind", ("ERROR, controller not found for unit=%d!\n",unit)); + return(-1); + } + + found = 0; + + /* second, inform all (!) active call of the event */ + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != 0) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_establish_ind", ("unit=%d, index=%d cdid=%u cr=%d\n", + unit, i, call_desc[i].cdid, call_desc[i].cr)); + next_l3state(&call_desc[i], EV_DLESTIN); + found++; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_establish_ind", ("ERROR, no cdid for unit %d found!\n", unit)); + return(-1); + } + else + { + return(0); + } +} + +/*---------------------------------------------------------------------------* + * DL ESTABLISH CONFIRM from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_establish_cnf(int unit) +{ + int i; + int found = 0; + + DBGL2(L2_PRIM, "DL-ESTABLISH-CONF", ("unit %d\n",unit)); + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != 0) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + ctrl_desc[call_desc[i].controller].dl_est = DL_UP; + + DBGL3(L3_MSG, "i4b_dl_establish_cnf", ("unit=%d, index=%d cdid=%u cr=%d\n", + unit, i, call_desc[i].cdid, call_desc[i].cr)); + + next_l3state(&call_desc[i], EV_DLESTCF); + found++; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_establish_cnf", ("ERROR, no cdid for unit %d found!\n", unit)); + return(-1); + } + else + { + return(0); + } +} + +/*---------------------------------------------------------------------------* + * DL RELEASE INDICATION from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_release_ind(int unit) +{ + int i; + int found = 0; + + DBGL2(L2_PRIM, "DL-RELEASE-IND", ("unit %d\n",unit)); + + /* first set controller to down */ + + for(i=0; i < nctrl; i++) + { + if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[i].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_release_ind", ("unit=%d DL released!\n",unit)); + ctrl_desc[i].dl_est = DL_DOWN; + found = 1; + } + } + + if(found == 0) + { + DBGL3(L3_ERR, "i4b_dl_release_ind", ("ERROR, controller not found for unit=%d!\n",unit)); + return(-1); + } + + found = 0; + + /* second, inform all (!) active calls of the event */ + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != 0) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_release_ind", ("unit=%d, index=%d cdid=%u cr=%d\n", + unit, i, call_desc[i].cdid, call_desc[i].cr)); + next_l3state(&call_desc[i], EV_DLRELIN); + found++; + } + } + + if(found == 0) + { + /* this is not an error since it might be a normal call end */ + DBGL3(L3_MSG, "i4b_dl_release_ind", ("no cdid for unit %d found\n", unit)); + } + return(0); +} + +/*---------------------------------------------------------------------------* + * DL RELEASE CONFIRM from Layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_release_cnf(int unit) +{ + int i; + + DBGL2(L2_PRIM, "DL-RELEASE-CONF", ("unit %d\n",unit)); + + for(i=0; i < nctrl; i++) + { + if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[i].unit == unit)) + { + DBGL3(L3_MSG, "i4b_dl_release_cnf", ("unit=%d DL released!\n",unit)); + ctrl_desc[i].dl_est = DL_DOWN; + return(0); + } + } + DBGL3(L3_ERR, "i4b_dl_release_cnf", ("ERROR, controller not found for unit=%d!\n",unit)); + return(-1); +} + +/*---------------------------------------------------------------------------* + * i4b_dl_data_ind - process a rx'd I-frame got from layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_data_ind(int unit, struct mbuf *m) +{ +#ifdef NOTDEF + DBGL2(L2_PRIM, "DL-DATA-IND", ("unit %d\n",unit)); +#endif + i4b_decode_q931(unit, m->m_len, m->m_data); + i4b_Dfreembuf(m); + return(0); +} + +/*---------------------------------------------------------------------------* + * dl_unit_data_ind - process a rx'd U-frame got from layer 2 + *---------------------------------------------------------------------------*/ +int +i4b_dl_unit_data_ind(int unit, struct mbuf *m) +{ +#ifdef NOTDEF + DBGL2(L2_PRIM, "DL-UNIT-DATA-IND", ("unit %d\n",unit)); +#endif + i4b_decode_q931(unit, m->m_len, m->m_data); + i4b_Dfreembuf(m); + return(0); +} + +/*---------------------------------------------------------------------------* + * send CONNECT message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_connect(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx CONNECT", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_CONNECT_LEN)) == NULL) + panic("i4b_l3_tx_connect: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = CONNECT; /* message type = connect */ + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send RELEASE COMPLETE message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_release_complete(call_desc_t *cd, int send_cause_flag) +{ + struct mbuf *m; + u_char *ptr; + int len = I_FRAME_HDRLEN + MSG_RELEASE_COMPLETE_LEN; + + DBGL3(L3_PRIM, "tx RELEASE-COMPLETE", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if(send_cause_flag == 0) + len -= 4; + + if((m = i4b_Dgetmbuf(len)) == NULL) + panic("i4b_l3_tx_release_complete: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = RELEASE_COMPLETE; /* message type = release complete */ + + if(send_cause_flag) + { + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = make_q931_cause(cd->cause_out); + } + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send DISCONNECT message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_disconnect(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx DISCONNECT", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_DISCONNECT_LEN)) == NULL) + panic("i4b_l3_tx_disconnect: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call ref length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = DISCONNECT; /* message type = disconnect */ + + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = make_q931_cause(cd->cause_out); + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send SETUP message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_setup(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + int slen = strlen(cd->src_telno); + int dlen = strlen(cd->dst_telno); + + /* + * there is one additional octet if cd->bprot == BPROT_NONE + * NOTE: the selection of a bearer capability by a B L1 + * protocol is highly questionable and a better + * mechanism should be used in future. (-hm) + */ + + DBGL3(L3_PRIM, "tx SETUP", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_SETUP_LEN + slen + dlen + + (cd->bprot == BPROT_NONE ? 1 : 0))) == NULL) + { + panic("i4b_l3_tx_setup: can't allocate mbuf\n"); + } + + cd->crflag = CRF_ORIG; /* we are the originating side */ + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call ref length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = SETUP; /* message type = setup */ + + *ptr++ = IEI_SENDCOMPL; /* sending complete */ + + *ptr++ = IEI_BEARERCAP; /* bearer capability */ + + /* XXX + * currently i have no idea if this should be switched by + * the choosen B channel protocol or if there should be a + * separate configuration item for the bearer capability. + * For now, it is switched by the choosen b protocol (-hm) + */ + + switch(cd->bprot) + { + case BPROT_NONE: /* telephony */ + *ptr++ = IEI_BEARERCAP_LEN+1; + *ptr++ = IT_CAP_SPEECH; + *ptr++ = IT_RATE_64K; + *ptr++ = IT_UL1_G711A; + break; + + case BPROT_RHDLC: /* raw HDLC */ + *ptr++ = IEI_BEARERCAP_LEN; + *ptr++ = IT_CAP_UNR_DIG_INFO; + *ptr++ = IT_RATE_64K; + break; + + default: + *ptr++ = IEI_BEARERCAP_LEN; + *ptr++ = IT_CAP_UNR_DIG_INFO; + *ptr++ = IT_RATE_64K; + break; + } + + *ptr++ = IEI_CHANNELID; /* channel id */ + *ptr++ = IEI_CHANNELID_LEN; /* channel id length */ + + switch(cd->channelid) + { + case CHAN_B1: + *ptr++ = CHANNELID_B1; + break; + case CHAN_B2: + *ptr++ = CHANNELID_B2; + break; + default: + *ptr++ = CHANNELID_ANY; + break; + } + + *ptr++ = IEI_CALLINGPN; /* calling party no */ + *ptr++ = IEI_CALLINGPN_LEN+slen;/* calling party no length */ + *ptr++ = NUMBER_TYPEPLAN; /* type of number, number plan id */ + strncpy(ptr, cd->src_telno, slen); + ptr += slen; + + *ptr++ = IEI_CALLEDPN; /* called party no */ + *ptr++ = IEI_CALLEDPN_LEN+dlen; /* called party no length */ + *ptr++ = NUMBER_TYPEPLAN; /* type of number, number plan id */ + strncpy(ptr, cd->dst_telno, dlen); + ptr += dlen; + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send CONNECT ACKNOWLEDGE message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_connect_ack(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx CONNECT-ACK", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_CONNECT_ACK_LEN)) == NULL) + panic("i4b_l3_tx_connect_ack: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = CONNECT_ACKNOWLEDGE; /* message type = connect ack */ + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send STATUS message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_status(call_desc_t *cd, u_char q850cause) +{ + struct mbuf *m; + u_char *ptr; + + DBGL3(L3_PRIM, "tx STATUS", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_STATUS_LEN)) == NULL) + panic("i4b_l3_tx_status: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = STATUS; /* message type = connect ack */ + + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = q850cause; + + *ptr++ = IEI_CALLSTATE; /* call state ie */ + *ptr++ = CALLSTATE_LEN; + *ptr++ = i4b_status_tab[cd->Q931state]; + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send RELEASE message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_release(call_desc_t *cd, int send_cause_flag) +{ + struct mbuf *m; + u_char *ptr; + int len = I_FRAME_HDRLEN + MSG_RELEASE_LEN; + + DBGL3(L3_PRIM, "tx RELEASE", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + if(send_cause_flag == 0) + len -= 4; + + if((m = i4b_Dgetmbuf(len)) == NULL) + panic("i4b_l3_tx_release: can't allocate mbuf\n"); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = RELEASE; /* message type = release complete */ + + if(send_cause_flag) + { + *ptr++ = IEI_CAUSE; /* cause ie */ + *ptr++ = CAUSE_LEN; + *ptr++ = CAUSE_STD_LOC_OUT; + *ptr++ = make_q931_cause(cd->cause_out); + } + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +/*---------------------------------------------------------------------------* + * send ALERTING message + *---------------------------------------------------------------------------*/ +void +i4b_l3_tx_alert(call_desc_t *cd) +{ + struct mbuf *m; + u_char *ptr; + + if((m = i4b_Dgetmbuf(I_FRAME_HDRLEN + MSG_ALERT_LEN)) == NULL) + panic("i4b_l3_tx_alert: can't allocate mbuf\n"); + + DBGL3(L3_PRIM, "tx ALERT", ("unit %d, cr = 0x%02x\n", ctrl_desc[cd->controller].unit, cd->cr)); + + ptr = m->m_data + I_FRAME_HDRLEN; + + *ptr++ = PD_Q931; /* protocol discriminator */ + *ptr++ = 0x01; /* call reference length */ + *ptr++ = setup_cr(cd, cd->cr); /* call reference value */ + *ptr++ = ALERT; /* message type = alert */ + + DL_Data_Req(ctrl_desc[cd->controller].unit, m); +} + +#endif /* NI4BQ931 > 0 */ diff --git a/sys/i4b/layer3/i4b_l3.h b/sys/i4b/layer3/i4b_l3.h new file mode 100644 index 000000000000..9d05055fc537 --- /dev/null +++ b/sys/i4b/layer3/i4b_l3.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l3.h - layer 3 header file + * ------------------------------ + * + * $Id: i4b_l3.h,v 1.8 1998/12/05 18:05:30 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:31:41 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L3_H_ +#define _I4B_L3_H_ + +extern int utoc_tab[]; +extern unsigned char cause_tab_q931[]; + +extern int i4b_aoc ( unsigned char *, call_desc_t *cd ); +extern void i4b_decode_q931 ( int unit, int msg_len, u_char *msg_ptr ); +extern int i4b_decode_q931_cs0_ie ( int unit, call_desc_t *cd, int msg_len, u_char *msg_ptr ); +extern void i4b_decode_q931_message ( int unit, call_desc_t *cd, u_char message_type ); +extern void i4b_l3_stop_all_timers ( call_desc_t *cd ); +extern void i4b_l3_tx_alert ( call_desc_t *cd ); +extern void i4b_l3_tx_connect ( call_desc_t *cd ); +extern void i4b_l3_tx_connect_ack ( call_desc_t *cd ); +extern void i4b_l3_tx_disconnect ( call_desc_t *cd ); +extern void i4b_l3_tx_release ( call_desc_t *cd, int send_cause_flag ); +extern void i4b_l3_tx_release_complete ( call_desc_t *cd, int send_cause_flag ); +extern void i4b_l3_tx_setup ( call_desc_t *cd ); +extern void i4b_l3_tx_status ( call_desc_t *cd, u_char q850cause ); +extern int i4b_dl_data_ind ( int unit, struct mbuf *m ); +extern int i4b_dl_establish_cnf ( int unit ); +extern int i4b_dl_establish_ind ( int unit ); +extern int i4b_dl_release_cnf ( int unit ); +extern int i4b_dl_release_ind ( int unit ); +extern int i4b_dl_unit_data_ind ( int unit, struct mbuf *m ); +extern int i4b_get_dl_stat( call_desc_t *cd ); +extern int i4b_mdl_status_ind ( int unit, int status, int parm); +extern void i4b_print_frame ( int len, u_char *buf ); +extern void next_l3state ( call_desc_t *cd, int event ); +extern char *print_l3state ( call_desc_t *cd ); +extern unsigned char setup_cr ( call_desc_t *cd, unsigned char cr ); +extern void T303_start ( call_desc_t *cd ); +extern void T303_stop ( call_desc_t *cd ); +extern void T305_start ( call_desc_t *cd ); +extern void T305_stop ( call_desc_t *cd ); +extern void T308_start ( call_desc_t *cd ); +extern void T308_stop ( call_desc_t *cd ); +extern void T309_start ( call_desc_t *cd ); +extern void T309_stop ( call_desc_t *cd ); +extern void T310_start ( call_desc_t *cd ); +extern void T310_stop ( call_desc_t *cd ); +extern void T313_start ( call_desc_t *cd ); +extern void T313_stop ( call_desc_t *cd ); + +#endif /* _I4B_L3_H_ */ diff --git a/sys/i4b/layer3/i4b_l3fsm.c b/sys/i4b/layer3/i4b_l3fsm.c new file mode 100644 index 000000000000..e45e1195e399 --- /dev/null +++ b/sys/i4b/layer3/i4b_l3fsm.c @@ -0,0 +1,1034 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l3fsm.c - layer 3 FSM + * ------------------------- + * + * $Id: i4b_l3fsm.c,v 1.13 1998/12/05 18:05:31 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:32:17 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif +#if NI4BQ931 > 0 +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> + +#include <i4b/layer4/i4b_l4.h> + + +static void F_00A(call_desc_t *cd), F_00H(call_desc_t *cd), F_00I(call_desc_t *cd); +static void F_00J(call_desc_t *cd); + +static void F_01B(call_desc_t *cd), F_01K(call_desc_t *cd), F_01L(call_desc_t *cd); +static void F_01M(call_desc_t *cd), F_01N(call_desc_t *cd), F_01U(call_desc_t *cd); +static void F_01O(call_desc_t *cd); + +static void F_03C(call_desc_t *cd), F_03N(call_desc_t *cd), F_03O(call_desc_t *cd); +static void F_03P(call_desc_t *cd), F_03Y(call_desc_t *cd); + +static void F_04O(call_desc_t *cd); + +static void F_06D(call_desc_t *cd), F_06E(call_desc_t *cd), F_06F(call_desc_t *cd); +static void F_06G(call_desc_t *cd), F_06J(call_desc_t *cd), F_06Q(call_desc_t *cd); + +static void F_07E(call_desc_t *cd), F_07F(call_desc_t *cd), F_07G(call_desc_t *cd); + +static void F_08R(call_desc_t *cd), F_08Z(call_desc_t *cd); + +static void F_09D(call_desc_t *cd), F_09E(call_desc_t *cd), F_09F(call_desc_t *cd); +static void F_09G(call_desc_t *cd); + +static void F_11J(call_desc_t *cd), F_11Q(call_desc_t *cd), F_11V(call_desc_t *cd); + +static void F_12C(call_desc_t *cd), F_12J(call_desc_t *cd); + +static void F_19I(call_desc_t *cd), F_19J(call_desc_t *cd), F_19K(call_desc_t *cd); +static void F_19W(call_desc_t *cd); + +static void F_NCNA(call_desc_t *cd), F_STENQ(call_desc_t *cd), F_STAT(call_desc_t *cd); +static void F_INFO(call_desc_t *cd), F_RELCP(call_desc_t *cd), F_REL(call_desc_t *cd); +static void F_DISC(call_desc_t *cd), F_DCRQ(call_desc_t *cd), F_UEM(call_desc_t *cd); +static void F_SIGN(call_desc_t *cd), F_DLEI(call_desc_t *cd), F_ILL(call_desc_t *cd); +static void F_309TO(call_desc_t *cd), F_DECF(call_desc_t *cd), F_FCTY(call_desc_t *cd); +static void F_DECF1(call_desc_t *cd), F_DECF2(call_desc_t *cd), F_DECF3(call_desc_t *cd); +static void F_DLRI(call_desc_t *cd), F_DLRIA(call_desc_t *cd), F_DECF4(call_desc_t *cd); + +static char *l3state_text[N_STATES] = { + "ST_U0 - Null", + "ST_U1 - Out Init", + "ST_U3 - Out Proc", + "ST_U4 - Out Delv", + "ST_U6 - In Pres", + "ST_U7 - In Rxd", + "ST_U8 - In ConReq", + "ST_U9 - In Proc", + "ST_U10 - Active", + "ST_U11 - Disc Req", + "ST_U12 - Disc Ind", + "ST_U19 - Rel Req", + + "ST_IWA - In Wait EST-Accept", + "ST_IWR - In Wait EST-Reject", + "ST_OW - Out Wait EST", + "ST_IWL - In Wait EST-Alert", + + "ST_SUSE - Subroutine sets state", + + "Illegal State" +}; + +static char *l3event_text[N_EVENTS] = { + "EV_SETUPRQ - L4 SETUP REQ", /* setup request from L4 */ + "EV_DISCRQ - L4 DISC REQ", /* disconnect request from L4 */ + "EV_RELRQ - L4 REL REQ", /* release request from L4 */ + "EV_ALERTRQ - L4 ALERT REQ", /* alerting request from L4 */ + "EV_SETACRS - L4 accept RSP", /* setup response accept from l4 */ + "EV_SETRJRS - L4 reject RSP", /* setup response reject from l4 */ + "EV_SETDCRS - L4 ignore RSP", /* setup response dontcare from l4 */ + + "EV_SETUP - rxd SETUP", /* incoming SETUP message from L2 */ + "EV_STATUS - rxd STATUS", /* incoming STATUS message from L2 */ + "EV_RELEASE - rxd REL", /* incoming RELEASE message from L2 */ + "EV_RELCOMP - rxd REL COMPL", /* incoming RELEASE COMPLETE from L2 */ + "EV_SETUPAK - rxd SETUP ACK", /* incoming SETUP ACK message from L2 */ + "EV_CALLPRC - rxd CALL PROC", /* incoming CALL PROCEEDING from L2 */ + "EV_ALERT - rxd ALERT", /* incoming ALERT message from L2 */ + "EV_CONNECT - rxd CONNECT", /* incoming CONNECT message from L2 */ + "EV_PROGIND - rxd PROG IND", /* incoming Progress IND from L2 */ + "EV_DISCONN - rxd DISC", /* incoming DISCONNECT message from L2 */ + "EV_CONACK - rxd CONN ACK", /* incoming CONNECT ACK message from L2 */ + "EV_STATENQ - rxd STAT ENQ", /* incoming STATUS ENQ message from L2 */ + "EV_INFO - rxd INFO", /* incoming INFO message from L2 */ + "EV_FACILITY - rxd FACILITY", /* incoming FACILITY message */ + + "EV_T303EXP - T303 timeout", /* Timer T303 expired */ + "EV_T305EXP - T305 timeout", /* Timer T305 expired */ + "EV_T308EXP - T308 timeout", /* Timer T308 expired */ + "EV_T309EXP - T309 timeout", /* Timer T309 expired */ + "EV_T310EXP - T310 timeout", /* Timer T310 expired */ + "EV_T313EXP - T313 timeout", /* Timer T313 expired */ + + "EV_DLESTIN - L2 DL_Est_Ind", /* dl establish indication from l2 */ + "EV_DLRELIN - L2 DL_Rel_Ind", /* dl release indication from l2 */ + "EV_DLESTCF - L2 DL_Est_Cnf", /* dl establish confirm from l2 */ + "EV_DLRELCF - L2 DL_Rel_Cnf", /* dl release confirm from l2 */ + + "EV_ILL - Illegal event!!" /* Illegal */ +}; + +/*---------------------------------------------------------------------------* + * layer 3 state transition table + *---------------------------------------------------------------------------*/ +struct l3state_tab { + void (*func) (call_desc_t *); /* function to execute */ + int newstate; /* next state */ +} l3state_tab[N_EVENTS][N_STATES] = { + +/* STATE: ST_U0 ST_U1 ST_U3 ST_U4 ST_U6 ST_U7 ST_U8 ST_U9 ST_U10 ST_U11 ST_U12 ST_U19 ST_IWA ST_IWR ST_OW ST_IWL ST_SUBSET ST_ILL */ +/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/*EV_SETUPRQ*/ {{F_00A, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_DISCRQ */ {{F_ILL, ST_ILL}, {F_01B, ST_U11}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_ILL, ST_ILL}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_ILL, ST_ILL}, {F_NCNA, ST_U12}, {F_ILL, ST_ILL}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_DCRQ, ST_U11}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_RELRQ */ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_03C, ST_U19}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_12C, ST_U19}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_ALERTRQ*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_06D, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_09D, ST_U7}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_SETACRS*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_06E, ST_SUSE}, {F_07E, ST_U8}, {F_ILL, ST_ILL}, {F_09E, ST_U8}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_SETRJRS*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_06F, ST_SUSE}, {F_07F, ST_U0}, {F_ILL, ST_ILL}, {F_09F, ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_SETDCRS*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_06G, ST_U0}, {F_07G, ST_U0}, {F_ILL, ST_ILL}, {F_09G, ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/* STATE: ST_U0 ST_U1 ST_U3 ST_U4 ST_U6 ST_U7 ST_U8 ST_U9 ST_U10 ST_U11 ST_U12 ST_U19 ST_IWA ST_IWR ST_OW ST_IWL ST_SUBSET ST_ILL */ +/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/*EV_SETUP */ {{F_00H, ST_U6}, {F_SIGN, ST_U1}, {F_SIGN, ST_U3}, {F_SIGN, ST_U4}, {F_SIGN, ST_U6}, {F_SIGN, ST_U7}, {F_SIGN, ST_U8}, {F_SIGN, ST_U9}, {F_SIGN, ST_U10}, {F_SIGN, ST_U11}, {F_SIGN, ST_U12}, {F_SIGN, ST_U19}, {F_SIGN, ST_IWA}, {F_SIGN, ST_IWR}, {F_SIGN, ST_OW}, {F_SIGN, ST_IWL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_STATUS */ {{F_00I, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_19I, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_STAT, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_RELEASE*/ {{F_00J, ST_U0}, {F_UEM, ST_SUSE}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_06J, ST_U0}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_11J, ST_U0}, {F_12J, ST_U0}, {F_19J, ST_U0}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_REL, ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_RELCOMP*/ {{F_NCNA, ST_U0}, {F_01K, ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_19K, ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_RELCP,ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_SETUPAK*/ {{F_UEM, ST_SUSE}, {F_01L, ST_U3}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_CALLPRC*/ {{F_UEM, ST_SUSE}, {F_01M, ST_U3}, {F_NCNA, ST_U3}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_ALERT */ {{F_UEM, ST_SUSE}, {F_01N, ST_U4}, {F_03N, ST_U4}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_CONNECT*/ {{F_UEM, ST_SUSE}, {F_01O, ST_U10}, {F_03O, ST_U10}, {F_04O, ST_U10}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_PROGIND*/ {{F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_03P, ST_U3}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_DISCONN*/ {{F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_06Q, ST_U12}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_11Q, ST_U19}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_DISC, ST_U12}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_CONACK */ {{F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_08R, ST_U10}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_STATENQ*/ {{F_STENQ,ST_U0}, {F_STENQ,ST_U1}, {F_STENQ,ST_U3}, {F_STENQ,ST_U4}, {F_STENQ,ST_U6}, {F_STENQ,ST_U7}, {F_STENQ,ST_U8}, {F_STENQ,ST_U9}, {F_STENQ,ST_U10}, {F_STENQ,ST_U11}, {F_STENQ,ST_U12}, {F_STENQ,ST_U19}, {F_STENQ,ST_IWA}, {F_STENQ,ST_IWR}, {F_STENQ,ST_OW}, {F_STENQ,ST_OW}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_INFO */ {{F_UEM, ST_SUSE}, {F_UEM, ST_SUSE}, {F_INFO, ST_U3}, {F_INFO, ST_U4}, {F_UEM, ST_SUSE}, {F_INFO, ST_U7}, {F_INFO, ST_U8}, {F_INFO, ST_U9}, {F_INFO, ST_U10}, {F_INFO, ST_U11}, {F_INFO, ST_U12}, {F_UEM, ST_SUSE}, {F_INFO, ST_IWA}, {F_INFO, ST_IWR}, {F_INFO, ST_OW}, {F_INFO, ST_OW}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_FACILITY*/ {{F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_FCTY, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/* STATE: ST_U0 ST_U1 ST_U3 ST_U4 ST_U6 ST_U7 ST_U8 ST_U9 ST_U10 ST_U11 ST_U12 ST_U19 ST_IWA ST_IWR ST_OW ST_IWL ST_SUBSET ST_ILL */ +/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/*EV_T303EXP*/ {{F_ILL, ST_ILL}, {F_01U, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_T305EXP*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_11V, ST_U19}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_T308EXP*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_19W, ST_SUSE}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_T309EXP*/ {{F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_309TO,ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_T310EXP*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_03Y, ST_U11}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_T313EXP*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_08Z, ST_U11}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/* STATE: ST_U0 ST_U1 ST_U3 ST_U4 ST_U6 ST_U7 ST_U8 ST_U9 ST_U10 ST_U11 ST_U12 ST_U19 ST_IWA ST_IWR ST_OW ST_IWL ST_SUBSET ST_ILL */ +/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/*EV_DLESTIN*/ {{F_ILL, ST_ILL}, {F_DLEI, ST_U1}, {F_DLEI, ST_U3}, {F_DLEI, ST_U4}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_DLEI, ST_U1}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_DLRELIN*/ {{F_NCNA, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRIA,ST_U10}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_DLRI, ST_U0}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_DLESTCF*/ {{F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF, ST_SUSE}, {F_DECF2,ST_U8}, {F_DECF3,ST_U0}, {F_DECF1,ST_U1}, {F_DECF4,ST_U7}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_DLRELCF*/ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}}, +/*EV_ILL */ {{F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}, {F_ILL, ST_ILL}} +}; + +/*---------------------------------------------------------------------------* + * event handler + *---------------------------------------------------------------------------*/ +void next_l3state(call_desc_t *cd, int event) +{ + int currstate, newstate; + + if(event > N_EVENTS) + panic("i4b_l3fsm.c: event > N_EVENTS\n"); + + currstate = cd->Q931state; + + if(currstate > N_STATES) + panic("i4b_l3fsm.c: currstate > N_STATES\n"); + + newstate = l3state_tab[event][currstate].newstate; + + if(newstate > N_STATES) + panic("i4b_l3fsm.c: newstate > N_STATES\n"); + + DBGL3(L3_F_MSG, "next_l3state", ("L3 FSM event [%s]: [%s => %s]\n", + l3event_text[event], + l3state_text[currstate], + l3state_text[newstate])); + + /* execute function */ + + (*l3state_tab[event][currstate].func)(cd); + + if(newstate == ST_ILL) + { + newstate = currstate; + DBGL3(L3_F_ERR, "next_l3state", ("FSM illegal state, state = %s, event = %s!\n", + l3state_text[newstate], + l3event_text[event])); + } + + if(newstate != ST_SUSE) + cd->Q931state = newstate; +} + +/*---------------------------------------------------------------------------* + * resturn pointer to current state description + *---------------------------------------------------------------------------*/ +char *print_l3state(call_desc_t *cd) +{ + return((char *) l3state_text[cd->Q931state]); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U0 event L4 setup req + *---------------------------------------------------------------------------*/ +static void F_00A(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_00A", ("FSM function F_00A executing\n")); + + if(i4b_get_dl_stat(cd) == DL_DOWN) + { + DL_Est_Req(ctrl_desc[cd->controller].unit); + cd->Q931state = ST_OW; + } + else + { + i4b_l3_tx_setup(cd); + cd->Q931state = ST_U1; + } + + cd->T303_first_to = 1; + T303_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U0 event SETUP from L2 + *---------------------------------------------------------------------------*/ +static void F_00H(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_00H", ("FSM function F_00H executing\n")); + i4b_l4_connect_ind(cd); /* tell l4 we have an incoming setup */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U0 event STATUS from L2 + *---------------------------------------------------------------------------*/ +static void F_00I(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_00I", ("FSM function F_00I executing\n")); + + if(cd->call_state != 0) + { + cd->cause_out = 101; + i4b_l3_tx_release_complete(cd, 1); /* 1 = send cause */ + } + cd->Q931state = ST_U0; +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U0 event RELEASE from L2 + *---------------------------------------------------------------------------*/ +static void F_00J(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_00J", ("FSM function F_00J executing\n")); + i4b_l3_tx_release_complete(cd, 0); /* 0 = don't send cause */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event disconnect req from L4 + *---------------------------------------------------------------------------*/ +static void F_01B(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01B", ("FSM function F_01B executing\n")); + /* cause from L4 */ + i4b_l3_tx_disconnect(cd); + T303_stop(cd); + T305_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event RELEASE COMPLETE from L2 + *---------------------------------------------------------------------------*/ +static void F_01K(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01K", ("FSM function F_01K executing\n")); + T303_stop(cd); + i4b_l4_disconnect_ind(cd); /* tell l4 we were rejected */ + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event SETUP ACK from L2 + *---------------------------------------------------------------------------*/ +static void F_01L(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01L", ("FSM function F_01L executing\n")); + T303_stop(cd); + + /* + * since this implementation does NOT support overlap sending, + * we react here as if we received a CALL PROCEEDING because + * several PBX's react with a SETUP ACK even if the called + * number is complete AND we sent a SENDING COMPLETE in the + * preceeding SETUP message. (-hm) + */ + + T310_start(cd); + i4b_l4_proceeding_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event CALL PROCEEDING from L2 + *---------------------------------------------------------------------------*/ +static void F_01M(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01M", ("FSM function F_01M executing\n")); + T303_stop(cd); + T310_start(cd); + i4b_l4_proceeding_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event ALERT from L2 (XXX !) + *---------------------------------------------------------------------------*/ +static void F_01N(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01N", ("FSM function F_01N executing\n")); + T303_stop(cd); + i4b_l4_alert_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event CONNECT from L2 (XXX !) + *---------------------------------------------------------------------------*/ +static void F_01O(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01O", ("FSM function F_01O executing\n")); + T303_stop(cd); + i4b_l3_tx_connect_ack(cd); + i4b_l4_connect_active_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U1 event T303 timeout + *---------------------------------------------------------------------------*/ +static void F_01U(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_01U", ("FSM function F_01U executing\n")); + if(cd->T303_first_to == 1) + { + cd->T303_first_to = 0; + i4b_l3_tx_setup(cd); + T303_start(cd); + cd->Q931state = ST_U1; + } + else + { + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + cd->Q931state = ST_U0; + } +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U3 event release req from L4 + *---------------------------------------------------------------------------*/ +static void F_03C(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_03C", ("FSM function F_03C executing\n")); + T310_stop(cd); + cd->cause_out = 6; + i4b_l3_tx_release(cd, 1); /* 0 = don't send cause */ + cd->T308_first_to = 1; + T308_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U3 event ALERT from L2 + *---------------------------------------------------------------------------*/ +static void F_03N(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_03N", ("FSM function F_03N executing\n")); + T310_stop(cd); + i4b_l4_alert_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U3 event CONNECT from L2 + *---------------------------------------------------------------------------*/ +static void F_03O(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_03O", ("FSM function F_03O executing\n")); + T310_stop(cd); + i4b_l3_tx_connect_ack(cd); /* CONNECT ACK to network */ + i4b_l4_connect_active_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U3 event PROGESS IND from L2 + *---------------------------------------------------------------------------*/ +static void F_03P(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_03P", ("FSM function F_03P executing\n")); + T310_stop(cd); +#ifdef NOTDEF + i4b_l4_progress_ind(cd); +#endif +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U3 event T310 timeout + *---------------------------------------------------------------------------*/ +static void F_03Y(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_03Y", ("FSM function F_03Y executing\n")); + cd->cause_out = 102; /* recovery on timer expiry */ + i4b_l3_tx_disconnect(cd); + T305_start(cd); + i4b_l4_disconnect_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U4 event CONNECT from L2 + *---------------------------------------------------------------------------*/ +static void F_04O(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_04O", ("FSM function F_04O executing\n")); + i4b_l3_tx_connect_ack(cd); /* CONNECT ACK to network */ + i4b_l4_connect_active_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U6 event alert req from L4 + *---------------------------------------------------------------------------*/ +static void F_06D(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_06D", ("FSM function F_06D executing\n")); + + if(i4b_get_dl_stat(cd) == DL_DOWN) + { + DL_Est_Req(ctrl_desc[cd->controller].unit); + cd->Q931state = ST_IWL; + } + else + { + i4b_l3_tx_alert(cd); + cd->Q931state = ST_U7; + } +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U6 event incoming setup accept from L4 + *---------------------------------------------------------------------------*/ +static void F_06E(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_06E", ("FSM function F_06E executing\n")); + + if(i4b_get_dl_stat(cd) == DL_DOWN) + { + DL_Est_Req(ctrl_desc[cd->controller].unit); + cd->Q931state = ST_IWA; + } + else + { + i4b_l3_tx_connect(cd); + cd->Q931state = ST_U8; + } + T313_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U6 event incoming setup reject from L4 + *---------------------------------------------------------------------------*/ +static void F_06F(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_06F", ("FSM function F_06F executing\n")); + + if(i4b_get_dl_stat(cd) == DL_DOWN) + { + DL_Est_Req(ctrl_desc[cd->controller].unit); + cd->Q931state = ST_IWR; + } + else + { + int s = SPLI4B(); + i4b_l3_tx_release_complete(cd, 1); + cd->Q931state = ST_U0; + freecd_by_cd(cd); + splx(s); + } +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U6 event incoming setup ignore from L4 + *---------------------------------------------------------------------------*/ +static void F_06G(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_06G", ("FSM function F_06G executing\n")); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U6 event RELEASE from L2 + *---------------------------------------------------------------------------*/ +static void F_06J(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_06J", ("FSM function F_06J executing\n")); + i4b_l3_tx_release_complete(cd, 0); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U6 event DISCONNECT from L2 + *---------------------------------------------------------------------------*/ +static void F_06Q(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_06Q", ("FSM function F_06Q executing\n")); + i4b_l4_disconnect_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U7 event setup response accept from L4 + *---------------------------------------------------------------------------*/ +static void F_07E(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_07E", ("FSM function F_07E executing\n")); + i4b_l3_tx_connect(cd); + T313_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U7 event setup response reject from L4 + *---------------------------------------------------------------------------*/ +static void F_07F(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_07F", ("FSM function F_07F executing\n")); + i4b_l3_tx_release_complete(cd, 1); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U7 event setup response ignore from L4 + *---------------------------------------------------------------------------*/ +static void F_07G(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_07G", ("FSM function F_07G executing\n")); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U8 event CONNECT ACK from L2 + *---------------------------------------------------------------------------*/ +static void F_08R(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_08R", ("FSM function F_08R executing\n")); + T313_stop(cd); + i4b_l4_connect_active_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U8 event T313 timeout + *---------------------------------------------------------------------------*/ +static void F_08Z(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_08Z", ("FSM function F_08Z executing\n")); + cd->cause_out = 102; /* recovery on timer expiry */ + i4b_l3_tx_disconnect(cd); + T305_start(cd); + i4b_l4_disconnect_ind(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U9 event alert req from L4 + *---------------------------------------------------------------------------*/ +static void F_09D(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_09D", ("FSM function F_09D executing\n")); + i4b_l3_tx_alert(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U9 event setup response accept from L4 + *---------------------------------------------------------------------------*/ +static void F_09E(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_09E", ("FSM function F_09E executing\n")); + i4b_l3_tx_connect(cd); + T313_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U9 event setup response reject from L4 + *---------------------------------------------------------------------------*/ +static void F_09F(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_09F", ("FSM function F_09F executing\n")); + i4b_l3_tx_release_complete(cd, 1); + freecd_by_cd(cd); +} +/*---------------------------------------------------------------------------* + * L3 FSM state U9 event setup response ignore from L4 + *---------------------------------------------------------------------------*/ +static void F_09G(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_09G", ("FSM function F_09G executing\n")); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U11 event RELEASE from L2 + *---------------------------------------------------------------------------*/ +static void F_11J(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_11J", ("FSM function F_11J executing\n")); + T305_stop(cd); + i4b_l3_tx_release_complete(cd, 0); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U11 event DISCONNECT from L2 + *---------------------------------------------------------------------------*/ +static void F_11Q(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_11Q", ("FSM function F_11Q executing\n")); + T305_stop(cd); + i4b_l3_tx_release(cd, 0); + cd->T308_first_to = 1; + T308_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U11 event T305 timeout + *---------------------------------------------------------------------------*/ +static void F_11V(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_11V", ("FSM function F_11V executing\n")); + cd->cause_out = 102; + i4b_l3_tx_release(cd, 1); + cd->T308_first_to = 1; + T308_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U12 event release req from L4 + *---------------------------------------------------------------------------*/ +static void F_12C(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_12C", ("FSM function F_12C executing\n")); + i4b_l3_tx_release(cd, 1); + cd->T308_first_to = 1; + T308_start(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U12 event RELEASE from L2 + *---------------------------------------------------------------------------*/ +static void F_12J(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_12J", ("FSM function F_12J executing\n")); + i4b_l3_tx_release_complete(cd, 0); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U19 event STATUS from L2 + *---------------------------------------------------------------------------*/ +static void F_19I(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_19I", ("FSM function F_19I executing\n")); + + if(cd->call_state == 0) + { + i4b_l4_status_ind(cd); + freecd_by_cd(cd); + cd->Q931state = ST_U0; + } + else + { + cd->Q931state = ST_U19; + } +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U19 event RELEASE from L2 + *---------------------------------------------------------------------------*/ +static void F_19J(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_19J", ("FSM function F_19J executing\n")); + T308_stop(cd); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U19 event RELEASE COMPLETE from L2 + *---------------------------------------------------------------------------*/ +static void F_19K(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_19K", ("FSM function F_19K executing\n")); + T308_stop(cd); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U19 event T308 timeout + *---------------------------------------------------------------------------*/ +static void F_19W(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_19W", ("FSM function F_19W executing\n")); + if(cd->T308_first_to == 0) + { + cd->T308_first_to = 1; + i4b_l3_tx_release(cd, 0); + T308_start(cd); + cd->Q931state = ST_U19; + } + else + { + cd->T308_first_to = 0; + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + cd->Q931state = ST_U0; + } +} + +/*---------------------------------------------------------------------------* + * L3 FSM routine no change no action + *---------------------------------------------------------------------------*/ +static void F_NCNA(call_desc_t *cd) +{ +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state event STATUS ENQ from L2 + *---------------------------------------------------------------------------*/ +static void F_STENQ(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_STENQ", ("FSM function F_STENQ executing\n")); + i4b_l3_tx_status(cd, CAUSE_Q850_STENQRSP); /* 30, resonse to stat enq */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state except 0 & 19 event STATUS from L2 + *---------------------------------------------------------------------------*/ +static void F_STAT(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_STAT", ("FSM function F_STAT executing\n")); + if(cd->call_state == 0) + { + i4b_l4_status_ind(cd); + cd->Q931state = ST_U0; + freecd_by_cd(cd); + } + else + { + /* XXX !!!!!!!!!!!!!!!!!! */ + + i4b_l4_status_ind(cd); + cd->cause_out = 101; /* message not compatible with call state */ + i4b_l3_tx_disconnect(cd); + T305_start(cd); + cd->Q931state = ST_U11; + } +} + +/*---------------------------------------------------------------------------* + * L3 FSM some states event INFORMATION from L2 + *---------------------------------------------------------------------------*/ +static void F_INFO(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_INFO", ("FSM function F_INFO executing\n")); + i4b_l4_info_ind(cd); + /* remain in current state */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM some states event RELEASE COMPLETE from L2 + *---------------------------------------------------------------------------*/ +static void F_RELCP(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_RELCP", ("FSM function F_RELCP executing\n")); + i4b_l3_stop_all_timers(cd); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM some states event RELEASE from L2 + *---------------------------------------------------------------------------*/ +static void F_REL(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_REL", ("FSM function F_REL executing\n")); + i4b_l3_stop_all_timers(cd); + i4b_l3_tx_release_complete(cd, 0); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM some states event DISCONNECT from L2 + *---------------------------------------------------------------------------*/ +static void F_DISC(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DISC", ("FSM function F_DISC executing\n")); + i4b_l3_stop_all_timers(cd); + + /* + * no disconnect ind to L4, no jump to state U12 + * instead we issue a RELEASE and jump to U19 + */ + + i4b_l3_tx_release(cd, 0); + cd->T308_first_to = 1; + T308_start(cd); + cd->Q931state = ST_U19; +} + +/*---------------------------------------------------------------------------* + * L3 FSM some states event disconnect request from L4 + *---------------------------------------------------------------------------*/ +static void F_DCRQ(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DCRQ", ("FSM function F_DCRQ executing\n")); + /* cause from L4 */ + i4b_l3_tx_disconnect(cd); + T305_start(cd); + cd->Q931state = ST_U11; +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state except 0 event unexpected message from L2 + *---------------------------------------------------------------------------*/ +static void F_UEM(call_desc_t *cd) +{ + DBGL3(L3_F_ERR, "F_UEM", ("FSM function F_UEM executing, state = %s\n", print_l3state(cd))); + i4b_l3_tx_status(cd, CAUSE_Q850_MSGNCWCS); /* 101, message not compatible with call state */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state except 0 event SETUP from L2 + *---------------------------------------------------------------------------*/ +static void F_SIGN(call_desc_t *cd) +{ + DBGL3(L3_F_ERR, "F_SIGN", ("FSM function F_SIGN executing\n")); + +/* XXX */ /* freecd_by_cd(cd); ?????????? XXX */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM relevant states event DL ESTABLISH IND from L2 + *---------------------------------------------------------------------------*/ +static void F_DLEI(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DLEI", ("FSM function F_DLEI executing\n")); + +/* XXX */ + + /* remain in current state */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state event illegal event occured + *---------------------------------------------------------------------------*/ +static void F_ILL(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_ILL", ("FSM function F_ILL executing\n")); +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state event T309 timeout + *---------------------------------------------------------------------------*/ +static void F_309TO(call_desc_t *cd) +{ + DBGL3(L3_F_ERR, "F_309TO", ("FSM function F_309TO executing\n")); + +/* XXX */ + +#ifdef NOTDEF + i4b_l4_dl_fail_ind(cd); +#endif + + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state event FACILITY message received + *---------------------------------------------------------------------------*/ +static void F_FCTY(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_FCTY", ("FSM function F_FCTY executing\n")); + /* ST_SUSE, no change in state ! */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM state ST_OW event DL ESTABLISH CONF from L2 + *---------------------------------------------------------------------------*/ +static void F_DECF1(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DECF1", ("FSM function F_DECF1 executing\n")); + i4b_l3_tx_setup(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state ST_IWA event DL ESTABLISH CONF from L2 + *---------------------------------------------------------------------------*/ +static void F_DECF2(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DECF2", ("FSM function F_DECF2 executing\n")); + i4b_l3_tx_connect(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state ST_IWR event DL ESTABLISH CONF from L2 + *---------------------------------------------------------------------------*/ +static void F_DECF3(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DECF3", ("FSM function F_DECF3 executing\n")); + i4b_l3_tx_release_complete(cd, 1); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state ST_IWL event DL ESTABLISH CONF from L2 + *---------------------------------------------------------------------------*/ +static void F_DECF4(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DECF4", ("FSM function F_DECF4 executing\n")); + i4b_l3_tx_alert(cd); +} + + +/*---------------------------------------------------------------------------* + * L3 FSM any state event DL ESTABLISH CONF from L2 + *---------------------------------------------------------------------------*/ +static void F_DECF(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DECF", ("FSM function F_DECF executing\n")); + T309_stop(cd); + i4b_l3_tx_status(cd, CAUSE_Q850_NORMUNSP); /* 31, normal unspecified */ +} + +/*---------------------------------------------------------------------------* + * L3 FSM any state except U10 event DL RELEASE IND from L2 + *---------------------------------------------------------------------------*/ +static void F_DLRI(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DLRI", ("FSM function F_DLRI executing\n")); + i4b_l3_stop_all_timers(cd); + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); +} + +/*---------------------------------------------------------------------------* + * L3 FSM state U10 event DL RELEASE IND from L2 + *---------------------------------------------------------------------------*/ +static void F_DLRIA(call_desc_t *cd) +{ + DBGL3(L3_F_MSG, "F_DLRIA", ("FSM function F_DLRIA executing\n")); + + if(cd->T309 == TIMER_IDLE) + T309_start(cd); + + DL_Est_Req(ctrl_desc[cd->controller].unit); +} + +#endif /* NI4BQ931 > 0 */ diff --git a/sys/i4b/layer3/i4b_l3fsm.h b/sys/i4b/layer3/i4b_l3fsm.h new file mode 100644 index 000000000000..d69b810b45ad --- /dev/null +++ b/sys/i4b/layer3/i4b_l3fsm.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l3fsm.c - layer 3 FSM + * ------------------------- + * + * $Id: i4b_l3fsm.h,v 1.5 1998/12/05 18:05:33 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:32:45 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L3FSM_H_ +#define _I4B_L3FSM_H_ + +enum Q931_states { + ST_U0, + ST_U1, + ST_U3, + ST_U4, + ST_U6, + ST_U7, + ST_U8, + ST_U9, + ST_U10, + ST_U11, + ST_U12, + ST_U19, + + ST_IWA, /* incoming call, wait establish, then accept */ + ST_IWR, /* incoming call, wait establish, then reject */ + ST_OW, /* outgoing call, wait establish */ + ST_IWL, /* incoming call, wait establish, then alert */ + + ST_SUSE, /* SUBroutine SETs new state on exit */ + ST_ILL, /* Illegal */ + + N_STATES /* number of states */ +}; + +enum Q931_events { + + EV_SETUPRQ, /* setup request from L4 */ + EV_DISCRQ, /* disconnect request from L4 */ + EV_RELRQ, /* release request from L4 */ + EV_ALERTRQ, /* alerting request from L4 */ + EV_SETACRS, /* setup response accept from l4 */ + EV_SETRJRS, /* setup response reject from l4 */ + EV_SETDCRS, /* setup response dontcare from l4 */ + + EV_SETUP, /* incoming SETUP message from L2 */ + EV_STATUS, /* incoming STATUS message from L2 */ + EV_RELEASE, /* incoming RELEASE message from L2 */ + EV_RELCOMP, /* incoming RELEASE COMPLETE from L2 */ + EV_SETUPAK, /* incoming SETUP ACK message from L2 */ + EV_CALLPRC, /* incoming CALL PROCEEDING from L2 */ + EV_ALERT, /* incoming ALERT message from L2 */ + EV_CONNECT, /* incoming CONNECT message from L2 */ + EV_PROGIND, /* incoming Progress IND from L2 */ + EV_DISCONN, /* incoming DISCONNECT message from L2 */ + EV_CONACK, /* incoming CONNECT ACK message from L2 */ + EV_STATENQ, /* incoming STATUS ENQ message from L2 */ + EV_INFO, /* incoming INFO message from L2 */ + EV_FACILITY, /* FACILITY message */ + + EV_T303EXP, /* Timer T303 expired */ + EV_T305EXP, /* Timer T305 expired */ + EV_T308EXP, /* Timer T308 expired */ + EV_T309EXP, /* Timer T309 expired */ + EV_T310EXP, /* Timer T310 expired */ + EV_T313EXP, /* Timer T313 expired */ + + EV_DLESTIN, /* dl establish indication from l2 */ + EV_DLRELIN, /* dl release indication from l2 */ + EV_DLESTCF, /* dl establish confirm from l2 */ + EV_DLRELCF, /* dl release indication from l2 */ + + EV_ILL, /* Illegal */ + N_EVENTS +}; + +#endif /* _I4B_L3FSM_H_ */ diff --git a/sys/i4b/layer3/i4b_l3timer.c b/sys/i4b/layer3/i4b_l3timer.c new file mode 100644 index 000000000000..6c1a2d30122b --- /dev/null +++ b/sys/i4b/layer3/i4b_l3timer.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l3timer.c - timer and timeout handling for layer 3 + * ------------------------------------------------------ + * + * $Id: i4b_l3timer.c,v 1.9 1998/12/05 18:05:35 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:33:00 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif +#if NI4BQ931 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> + +#include <i4b/layer4/i4b_l4.h> + +/*---------------------------------------------------------------------------* + * stop all layer 3 timers + *---------------------------------------------------------------------------*/ +void i4b_l3_stop_all_timers(call_desc_t *cd) +{ + T303_stop(cd); + T305_stop(cd); + T308_stop(cd); + T309_stop(cd); + T310_stop(cd); + T313_stop(cd); +} + +/*---------------------------------------------------------------------------* + * timer T303 timeout function + *---------------------------------------------------------------------------*/ +static void +T303_timeout(call_desc_t *cd) +{ + DBGL3(L3_T_ERR, "T303_timeout", ("SETUP not answered, cr = %d\n", cd->cr)); + next_l3state(cd, EV_T303EXP); +} + +/*---------------------------------------------------------------------------* + * timer T303 start + *---------------------------------------------------------------------------*/ +void +T303_start(call_desc_t *cd) +{ + DBGL3(L3_T_MSG, "T303_start", ("cr = %d\n", cd->cr)); + cd->T303 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T303_callout = timeout((TIMEOUT_FUNC_T)T303_timeout, (void *)cd, T303VAL); +#else + timeout((TIMEOUT_FUNC_T)T303_timeout, (void *)cd, T303VAL); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T303 stop + *---------------------------------------------------------------------------*/ +void +T303_stop(call_desc_t *cd) +{ + if(cd->T303 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T303_timeout, (void *)cd, cd->T303_callout); +#else + untimeout((TIMEOUT_FUNC_T)T303_timeout, (void *)cd); +#endif + cd->T303 = TIMER_IDLE; + } + DBGL3(L3_T_MSG, "T303_stop", ("cr = %d\n", cd->cr)); +} + +/*---------------------------------------------------------------------------* + * timer T305 timeout function + *---------------------------------------------------------------------------*/ +static void +T305_timeout(call_desc_t *cd) +{ + DBGL3(L3_T_ERR, "T305_timeout", ("DISC not answered, cr = %d\n", cd->cr)); + next_l3state(cd, EV_T305EXP); +} + +/*---------------------------------------------------------------------------* + * timer T305 start + *---------------------------------------------------------------------------*/ +void +T305_start(call_desc_t *cd) +{ + DBGL3(L3_T_MSG, "T305_start", ("cr = %d\n", cd->cr)); + cd->T305 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T305_callout = timeout((TIMEOUT_FUNC_T)T305_timeout, (void *)cd, T305VAL); +#else + timeout((TIMEOUT_FUNC_T)T305_timeout, (void *)cd, T305VAL); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T305 stop + *---------------------------------------------------------------------------*/ +void +T305_stop(call_desc_t *cd) +{ + if(cd->T305 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T305_timeout, (void *)cd, cd->T305_callout); +#else + untimeout((TIMEOUT_FUNC_T)T305_timeout, (void *)cd); +#endif + cd->T305 = TIMER_IDLE; + } + DBGL3(L3_T_MSG, "T305_stop", ("cr = %d\n", cd->cr)); +} + +/*---------------------------------------------------------------------------* + * timer T308 timeout function + *---------------------------------------------------------------------------*/ +static void +T308_timeout(call_desc_t *cd) +{ + DBGL3(L3_T_ERR, "T308_timeout", ("REL not answered, cr = %d\n", cd->cr)); + next_l3state(cd, EV_T308EXP); +} + +/*---------------------------------------------------------------------------* + * timer T308 start + *---------------------------------------------------------------------------*/ +void +T308_start(call_desc_t *cd) +{ + DBGL3(L3_T_MSG, "T308_start", ("cr = %d\n", cd->cr)); + cd->T308 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T308_callout = timeout((TIMEOUT_FUNC_T)T308_timeout, (void *)cd, T308VAL); +#else + timeout((TIMEOUT_FUNC_T)T308_timeout, (void *)cd, T308VAL); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T308 stop + *---------------------------------------------------------------------------*/ +void +T308_stop(call_desc_t *cd) +{ + if(cd->T308 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T308_timeout, (void *)cd, cd->T308_callout); +#else + untimeout((TIMEOUT_FUNC_T)T308_timeout, (void *)cd); +#endif + cd->T308 = TIMER_IDLE; + } + DBGL3(L3_T_MSG, "T308_stop", ("cr = %d\n", cd->cr)); +} + +/*---------------------------------------------------------------------------* + * timer T309 timeout function + *---------------------------------------------------------------------------*/ +static void +T309_timeout(call_desc_t *cd) +{ + DBGL3(L3_T_ERR, "T309_timeout", ("datalink not reconnected, cr = %d\n", cd->cr)); + next_l3state(cd, EV_T309EXP); +} + +/*---------------------------------------------------------------------------* + * timer T309 start + *---------------------------------------------------------------------------*/ +void +T309_start(call_desc_t *cd) +{ + DBGL3(L3_T_MSG, "T309_start", ("cr = %d\n", cd->cr)); + cd->T309 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T309_callout = timeout((TIMEOUT_FUNC_T)T309_timeout, (void *)cd, T309VAL); +#else + timeout((TIMEOUT_FUNC_T)T309_timeout, (void *)cd, T309VAL); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T309 stop + *---------------------------------------------------------------------------*/ +void +T309_stop(call_desc_t *cd) +{ + if(cd->T309 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T309_timeout, (void *)cd, cd->T309_callout); +#else + untimeout((TIMEOUT_FUNC_T)T309_timeout, (void *)cd); +#endif + cd->T309 = TIMER_IDLE; + } + DBGL3(L3_T_MSG, "T309_stop", ("cr = %d\n", cd->cr)); +} + +/*---------------------------------------------------------------------------* + * timer T310 timeout function + *---------------------------------------------------------------------------*/ +static void +T310_timeout(call_desc_t *cd) +{ + DBGL3(L3_T_ERR, "T310_timeout", ("CALL PROC timeout, cr = %d\n", cd->cr)); + next_l3state(cd, EV_T310EXP); +} + +/*---------------------------------------------------------------------------* + * timer T310 start + *---------------------------------------------------------------------------*/ +void +T310_start(call_desc_t *cd) +{ + DBGL3(L3_T_MSG, "T310_start", ("cr = %d\n", cd->cr)); + cd->T310 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T310_callout = timeout((TIMEOUT_FUNC_T)T310_timeout, (void *)cd, T310VAL); +#else + timeout((TIMEOUT_FUNC_T)T310_timeout, (void *)cd, T310VAL); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T310 stop + *---------------------------------------------------------------------------*/ +void +T310_stop(call_desc_t *cd) +{ + if(cd->T310 != TIMER_IDLE) + { +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T310_timeout, (void *)cd, cd->T310_callout); +#else + untimeout((TIMEOUT_FUNC_T)T310_timeout, (void *)cd); +#endif + cd->T310 = TIMER_IDLE; + } + DBGL3(L3_T_MSG, "T310_stop", ("cr = %d\n", cd->cr)); +} + +/*---------------------------------------------------------------------------* + * timer T313 timeout function + *---------------------------------------------------------------------------*/ +static void +T313_timeout(call_desc_t *cd) +{ + DBGL3(L3_T_ERR, "T313_timeout", ("CONN ACK not received, cr = %d\n", cd->cr)); + next_l3state(cd, EV_T313EXP); +} + +/*---------------------------------------------------------------------------* + * timer T313 start + *---------------------------------------------------------------------------*/ +void +T313_start(call_desc_t *cd) +{ + DBGL3(L3_T_MSG, "T313_start", ("cr = %d\n", cd->cr)); + cd->T313 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T313_callout = timeout((TIMEOUT_FUNC_T)T313_timeout, (void *)cd, T313VAL); +#else + timeout((TIMEOUT_FUNC_T)T313_timeout, (void *)cd, T313VAL); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T313 stop + *---------------------------------------------------------------------------*/ +void +T313_stop(call_desc_t *cd) +{ + if(cd->T313 != TIMER_IDLE) + { + cd->T313 = TIMER_IDLE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T313_timeout, (void *)cd, cd->T313_callout); +#else + untimeout((TIMEOUT_FUNC_T)T313_timeout, (void *)cd); +#endif + } + DBGL3(L3_T_MSG, "T313_stop", ("cr = %d\n", cd->cr)); +} + +#endif /* NI4BQ931 > 0 */ + diff --git a/sys/i4b/layer3/i4b_l4if.c b/sys/i4b/layer3/i4b_l4if.c new file mode 100644 index 000000000000..55d9bb9da445 --- /dev/null +++ b/sys/i4b/layer3/i4b_l4if.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l4if.c - Layer 3 interface to Layer 4 + * ------------------------------------------- + * + * $Id: i4b_l4if.c,v 1.17 1998/12/05 18:05:36 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:33:16 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif +#if NI4BQ931 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> + +#include <i4b/layer4/i4b_l4.h> + +extern void isic_settrace(int unit, int val); /*XXX*/ +extern int isic_gettrace(int unit); /*XXX*/ + +static void n_connect_request(u_int cdid); +static void n_connect_response(u_int cdid, int response, int cause); +static void n_disconnect_request(u_int cdid, int cause); +static void n_alert_request(u_int cdid); +static void n_mgmt_command(int unit, int cmd, int parm); + +/*---------------------------------------------------------------------------* + * i4b_mdl_status_ind - status indication from lower layers + *---------------------------------------------------------------------------*/ +int +i4b_mdl_status_ind(int unit, int status, int parm) +{ + int sendup; + int i; + + DBGL3(L3_MSG, "i4b_mdl_status_ind", ("unit = %d, status = %d, parm = %d\n", unit, status, parm)); + + switch(status) + { + case STI_ATTACH: + DBGL3(L3_MSG, "i4b_mdl_status_ind", ("STI_ATTACH: attaching unit %d to controller %d\n", unit, nctrl)); + + /* init function pointers */ + + ctrl_desc[nctrl].N_CONNECT_REQUEST = n_connect_request; + ctrl_desc[nctrl].N_CONNECT_RESPONSE = n_connect_response; + ctrl_desc[nctrl].N_DISCONNECT_REQUEST = n_disconnect_request; + ctrl_desc[nctrl].N_ALERT_REQUEST = n_alert_request; + ctrl_desc[nctrl].N_SET_TRACE = isic_settrace; + ctrl_desc[nctrl].N_GET_TRACE = isic_gettrace; + ctrl_desc[nctrl].N_DOWNLOAD = NULL; /* only used by active cards */ + ctrl_desc[nctrl].N_DIAGNOSTICS = NULL; /* only used by active cards */ + ctrl_desc[nctrl].N_MGMT_COMMAND = n_mgmt_command; + + /* init type and unit */ + + ctrl_desc[nctrl].unit = unit; + ctrl_desc[nctrl].ctrl_type = CTRL_PASSIVE; + ctrl_desc[nctrl].card_type = parm; + + /* state fields */ + + ctrl_desc[nctrl].dl_est = DL_DOWN; + ctrl_desc[nctrl].bch_state[CHAN_B1] = BCH_ST_FREE; + ctrl_desc[nctrl].bch_state[CHAN_B2] = BCH_ST_FREE; + ctrl_desc[nctrl].tei = -1; + + /* init unit to controller table */ + + utoc_tab[unit] = nctrl; + + /* increment no. of controllers */ + + nctrl++; + + break; + + case STI_L1STAT: + i4b_l4_l12stat(unit, 1, parm); + DBGL3(L3_MSG, "i4b_mdl_status_ind", ("STI_L1STAT: unit %d layer 1 = %s\n", unit, status ? "up" : "down")); + break; + + case STI_L2STAT: + i4b_l4_l12stat(unit, 2, parm); + DBGL3(L3_MSG, "i4b_mdl_status_ind", ("STI_L2STAT: unit %d layer 2 = %s\n", unit, status ? "up" : "down")); + break; + + case STI_TEIASG: + ctrl_desc[unit].tei = parm; + i4b_l4_teiasg(unit, parm); + DBGL3(L3_MSG, "i4b_mdl_status_ind", ("STI_TEIASG: unit %d TEI = %d = 0x%02x\n", unit, parm, parm)); + break; + + case STI_PDEACT: /* L1 T4 timeout */ + DBGL3(L3_ERR, "i4b_mdl_status_ind", ("STI_PDEACT: unit %d TEI = %d = 0x%02x\n", unit, parm, parm)); + + sendup = 0; + + for(i=0; i < N_CALL_DESC; i++) + { + if( (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + if(call_desc[i].cdid != CDID_UNUSED) + sendup++; + } + } + + ctrl_desc[utoc_tab[unit]].dl_est = DL_DOWN; + ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B1] = BCH_ST_FREE; + ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B2] = BCH_ST_FREE; + ctrl_desc[utoc_tab[unit]].tei = -1; + + if(sendup) + i4b_l4_pdeact(unit, sendup); + break; + + case STI_NOL1ACC: /* no outgoing access to S0 */ + DBGL3(L3_ERR, "i4b_mdl_status_ind", ("STI_NOL1ACC: unit %d no outgoing access to S0\n", unit)); + + for(i=0; i < N_CALL_DESC; i++) + { + if( (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + if(call_desc[i].cdid != CDID_UNUSED) + { + SET_CAUSE_TYPE(call_desc[i].cause_in, CAUSET_I4B); + SET_CAUSE_VAL(call_desc[i].cause_in, CAUSE_I4B_L1ERROR); + i4b_l4_disconnect_ind(&(call_desc[i])); + } + } + } + + ctrl_desc[utoc_tab[unit]].dl_est = DL_DOWN; + ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B1] = BCH_ST_FREE; + ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B2] = BCH_ST_FREE; + ctrl_desc[utoc_tab[unit]].tei = -1; + break; + + default: + DBGL3(L3_ERR, "i4b_mdl_status_ind", ("ERROR, unit %d, unknown status value %d!\n", unit, status)); + break; + } + return(0); +} + +/*---------------------------------------------------------------------------* + * send command to the lower layers + *---------------------------------------------------------------------------*/ +static void +n_mgmt_command(int unit, int cmd, int parm) +{ + int i; + + switch(cmd) + { + case CMR_DOPEN: + DBGL3(L3_MSG, "n_mgmt_command", ("CMR_DOPEN for unit %d\n", unit)); + + for(i=0; i < N_CALL_DESC; i++) + { + if( (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit)) + { + call_desc[i].cdid = CDID_UNUSED; + } + } + + ctrl_desc[utoc_tab[unit]].dl_est = DL_DOWN; + ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B1] = BCH_ST_FREE; + ctrl_desc[utoc_tab[unit]].bch_state[CHAN_B2] = BCH_ST_FREE; + ctrl_desc[utoc_tab[unit]].tei = -1; + break; + + case CMR_DCLOSE: + DBGL3(L3_MSG, "n_mgmt_command", ("CMR_DCLOSE for unit %d\n", unit)); + break; + + default: + break; + + } + + MDL_Command_Req(unit, cmd, parm); + +} + +/*---------------------------------------------------------------------------* + * handle connect request message from userland + *---------------------------------------------------------------------------*/ +static void +n_connect_request(u_int cdid) +{ + call_desc_t *cd; + + cd = cd_by_cdid(cdid); + + next_l3state(cd, EV_SETUPRQ); +} + +/*---------------------------------------------------------------------------* + * handle setup response message from userland + *---------------------------------------------------------------------------*/ +static void +n_connect_response(u_int cdid, int response, int cause) +{ + call_desc_t *cd; + int chstate; + + cd = cd_by_cdid(cdid); + + T400_stop(cd); + + cd->response = response; + cd->cause_out = cause; + + switch(response) + { + case SETUP_RESP_ACCEPT: + next_l3state(cd, EV_SETACRS); + chstate = BCH_ST_USED; + break; + + case SETUP_RESP_REJECT: + next_l3state(cd, EV_SETRJRS); + chstate = BCH_ST_FREE; + break; + + case SETUP_RESP_DNTCRE: + next_l3state(cd, EV_SETDCRS); + chstate = BCH_ST_FREE; + break; + + default: /* failsafe */ + next_l3state(cd, EV_SETDCRS); + chstate = BCH_ST_FREE; + DBGL3(L3_ERR, "n_connect_response", ("unknown response, doing SETUP_RESP_DNTCRE")); + break; + } + + if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) + { + ctrl_desc[cd->controller].bch_state[cd->channelid] = chstate; + } + else + { + DBGL3(L3_ERR, "n_connect_response", ("ERROR, invalid channel %d\n", cd->channelid)); + } +} + +/*---------------------------------------------------------------------------* + * handle disconnect request message from userland + *---------------------------------------------------------------------------*/ +static void +n_disconnect_request(u_int cdid, int cause) +{ + call_desc_t *cd; + + cd = cd_by_cdid(cdid); + + cd->cause_out = cause; + + next_l3state(cd, EV_DISCRQ); +} + +/*---------------------------------------------------------------------------* + * handle alert request message from userland + *---------------------------------------------------------------------------*/ +static void +n_alert_request(u_int cdid) +{ + call_desc_t *cd; + + cd = cd_by_cdid(cdid); + + next_l3state(cd, EV_ALERTRQ); +} + +#endif /* NI4BQ931 > 0 */ diff --git a/sys/i4b/layer3/i4b_q931.c b/sys/i4b/layer3/i4b_q931.c new file mode 100644 index 000000000000..6c111d101228 --- /dev/null +++ b/sys/i4b/layer3/i4b_q931.c @@ -0,0 +1,624 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_q931.c - Q931 received messages handling + * -------------------------------------------- + * + * $Id: i4b_q931.c,v 1.18 1998/12/05 18:05:38 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:33:36 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif + +#if NI4BQ931 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> + +#include <i4b/layer4/i4b_l4.h> + +#ifndef __FreeBSD__ +#define memcpy(d,s,l) bcopy(s,d,l) +#endif + +unsigned int i4b_l3_debug = L3_DEBUG_DEFAULT; + +call_desc_t call_desc[N_CALL_DESC]; /* call descriptor array */ +ctrl_desc_t ctrl_desc[MAX_CONTROLLERS]; /* controller description array */ +int utoc_tab[MAX_CONTROLLERS]; /* unit to controller conversion */ + +/* protocol independent causes -> Q.931 causes */ + +unsigned char cause_tab_q931[CAUSE_I4B_MAX] = { + CAUSE_Q850_NCCLR, /* CAUSE_I4B_NORMAL -> normal call clearing */ + CAUSE_Q850_USRBSY, /* CAUSE_I4B_BUSY -> user busy */ + CAUSE_Q850_NOCAVAIL, /* CAUSE_I4B_NOCHAN -> no circuit/channel available*/ + CAUSE_Q850_INCDEST, /* CAUSE_I4B_INCOMP -> incompatible destination */ + CAUSE_Q850_CALLREJ, /* CAUSE_I4B_REJECT -> call rejected */ + CAUSE_Q850_DSTOOORDR, /* CAUSE_I4B_OOO -> destination out of order */ + CAUSE_Q850_TMPFAIL, /* CAUSE_I4B_TMPFAIL -> temporary failure */ +}; + +/*---------------------------------------------------------------------------* + * setup cr ref flag according to direction + *---------------------------------------------------------------------------*/ +unsigned char +setup_cr(call_desc_t *cd, unsigned char cr) +{ + if(cd->crflag == CRF_ORIG) + return(cr & 0x7f); /* clear cr ref flag */ + else if(cd->crflag == CRF_DEST) + return(cr | 0x80); /* set cr ref flag */ + else + panic("setup_cr: invalid crflag!\n"); +} + +/*---------------------------------------------------------------------------* + * decode and process a Q.931 message + *---------------------------------------------------------------------------*/ +void +i4b_decode_q931(int unit, int msg_len, u_char *msg_ptr) +{ + call_desc_t *cd; + int codeset = CODESET_0; + int old_codeset = CODESET_0; + int shift_flag = UNSHIFTED; + int crlen = 0; + int crval = 0; + int crflag = 0; + int i; + int offset; + int s; + + /* check protocol discriminator */ + + if(*msg_ptr != PD_Q931) + { + DBGL3(L3_P_ERR, "i4b_decode_q931", ("protocol discriminator 0x%x != Q.931\n", *msg_ptr)); + return; + } + msg_ptr++; + msg_len--; + + s = SPLI4B(); /* this has to be protected ! */ + + /* extract call reference */ + + crlen = *msg_ptr & CRLENGTH_MASK; + msg_ptr++; + msg_len--; + + if(crlen != 0) + { + crval += *msg_ptr & 0x7f; + crflag = (*msg_ptr >> 7) & 0x01; + msg_ptr++; + msg_len--; + + for(i=1; i < crlen; i++) + { + crval += *msg_ptr; + msg_ptr++; + msg_len--; + } + } + else + { + crval = 0; + crflag = 0; + } + + DBGL3(L3_P_MSG, "i4b_decode_q931", ("Call Ref, len %d, val %d, flag %d\n", crlen, crval, crflag)); + + /* find or allocate calldescriptor */ + + if((cd = cd_by_unitcr(unit, crval, + crflag == CRF_DEST ? CRF_ORIG : CRF_DEST)) == NULL) + { + if(*msg_ptr == SETUP) + { + /* get and init new calldescriptor */ + + cd = reserve_cd(); /* cdid filled in */ + cd->controller = utoc_tab[unit]; + cd->cr = crval; + cd->crflag = CRF_DEST; /* we are the dest side */ + cd->ilt = NULL; /* reset link tab ptrs */ + cd->dlt = NULL; + } + else + { +/*XXX*/ if(crval != 0) /* ignore global call references */ + { + DBGL3(L3_P_ERR, "i4b_decode_q931", ("cannot find calldescriptor for cr = 0x%x, crflag = 0x%x, msg = 0x%x, frame = ", crval, crflag, *msg_ptr)); + i4b_print_frame(msg_len, msg_ptr); + } + splx(s); + return; + } + } + + splx(s); + + /* decode and handle message type */ + + i4b_decode_q931_message(unit, cd, *msg_ptr); + msg_ptr++; + msg_len--; + + /* process information elements */ + + while(msg_len > 0) + { + /* check for shift codeset IE */ + + if((*msg_ptr & 0x80) && ((*msg_ptr & 0xf0) == SOIE_SHIFT)) + { + if(!(*msg_ptr & SHIFT_LOCK)) + shift_flag = SHIFTED; + + old_codeset = codeset; + codeset = *msg_ptr & CODESET_MASK; + + if((shift_flag != SHIFTED) && + (codeset <= old_codeset)) + { + DBGL3(L3_P_ERR, "i4b_decode_q931", ("Q.931 lockingshift proc violation, shift %d -> %d\n", old_codeset, codeset)); + codeset = old_codeset; + } + msg_len--; + msg_ptr++; + } + + /* process one IE for selected codeset */ + + switch(codeset) + { + case CODESET_0: + offset = i4b_decode_q931_cs0_ie(unit, cd, msg_len, msg_ptr); + msg_len -= offset; + msg_ptr += offset; + break; + + default: + DBGL3(L3_P_ERR, "i4b_decode_q931", ("unknown codeset %d, ", codeset)); + i4b_print_frame(msg_len, msg_ptr); + msg_len = 0; + break; + } + + /* check for non-locking shifts */ + + if(shift_flag == SHIFTED) + { + shift_flag = UNSHIFTED; + codeset = old_codeset; + } + } + next_l3state(cd, cd->event); +} + +/*---------------------------------------------------------------------------* + * decode and process one Q.931 codeset 0 information element + *---------------------------------------------------------------------------*/ +int +i4b_decode_q931_cs0_ie(int unit, call_desc_t *cd, int msg_len, u_char *msg_ptr) +{ + int i, j; + char *p; + + switch(*msg_ptr) + { + /* single byte IE's */ + + case IEI_SENDCOMPL: + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_SENDCOMPL\n")); + return(1); + break; + + /* multi byte IE's */ + + case IEI_BEARERCAP: /* bearer capability */ + switch(msg_ptr[2]) + { + case 0x80: /* speech */ + case 0x89: /* restricted digital info */ + case 0x90: /* 3.1KHz audio */ +/* XXX */ cd->bprot = BPROT_NONE; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_BEARERCAP - Telephony\n")); + break; + + case 0x88: /* unrestricted digital info */ +/* XXX */ cd->bprot = BPROT_RHDLC; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_BEARERCAP - Raw HDLC\n")); + break; + + default: +/* XXX */ cd->bprot = BPROT_NONE; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_BEARERCAP - No Protocol\n")); + break; + } + break; + + case IEI_CAUSE: /* cause */ + if(msg_ptr[2] & 0x80) + { + cd->cause_in = msg_ptr[3] & 0x7f; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CAUSE = %d\n", msg_ptr[3] & 0x7f)); + } + else + { + cd->cause_in = msg_ptr[4] & 0x7f; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CAUSE = %d\n", msg_ptr[4] & 0x7f)); + } + break; + + case IEI_CHANNELID: /* channel id */ + if((msg_ptr[2] & 0xf4) != 0x80) + { + cd->channelid = CHAN_NO; + DBGL3(L3_P_ERR, "i4b_decode_q931_codeset0", ("IEI_CHANNELID, unsupported value 0x%x\n", msg_ptr[2])); + } + else + { + switch(msg_ptr[2] & 0x03) + { + case IE_CHAN_ID_NO: + cd->channelid = CHAN_NO; + break; + case IE_CHAN_ID_B1: + cd->channelid = CHAN_B1; + break; + case IE_CHAN_ID_B2: + cd->channelid = CHAN_B2; + break; + case IE_CHAN_ID_ANY: + cd->channelid = CHAN_ANY; + break; + } + cd->channelexcl = (msg_ptr[2] & 0x08) >> 3; + + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CHANNELID - channel %d, exclusive = %d\n", cd->channelid, cd->channelexcl)); + + /* if this is a setup message, reserve channel */ + + if(cd->event == EV_SETUP) + { + if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) + { + if(ctrl_desc[cd->controller].bch_state[cd->channelid] == BCH_ST_FREE) + ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_RSVD; + else + DBGL3(L3_P_ERR, "i4b_decode_q931_codeset0", ("IE ChannelID, Channel NOT free!!\n")); + } + else if(cd->channelid == CHAN_NO) + { + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IE ChannelID, SETUP with channel = No channel (CW)\n")); + } + else /* cd->channelid == CHAN_ANY */ + { + DBGL3(L3_P_ERR, "i4b_decode_q931_codeset0", ("ERROR: IE ChannelID, SETUP with channel = Any channel!\n")); + } + } + } + break; + + case IEI_CALLINGPN: /* calling party no */ + if(msg_ptr[2] & 0x80) /* no presentation/screening indicator ? */ + { + memcpy(cd->src_telno, &msg_ptr[3], min(TELNO_MAX, msg_ptr[1]-1)); + cd->src_telno[min(TELNO_MAX, msg_ptr[1] - 1)] = '\0'; + cd->scr_ind = SCR_NONE; + } + else + { + memcpy(cd->src_telno, &msg_ptr[4], min(TELNO_MAX, msg_ptr[1]-2)); + cd->src_telno[min(TELNO_MAX, msg_ptr[1] - 2)] = '\0'; + cd->scr_ind = (msg_ptr[3] & 0x03) + SCR_USR_NOSC; + } + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CALLINGPN = %s\n", cd->src_telno)); + break; + + case IEI_CALLEDPN: /* called party number */ + memcpy(cd->dst_telno, &msg_ptr[3], min(TELNO_MAX, msg_ptr[1]-1)); + cd->dst_telno[min(TELNO_MAX, msg_ptr [1] - 1)] = '\0'; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CALLED = %s\n", cd->dst_telno)); + break; + + case IEI_CALLSTATE: /* call state */ + cd->call_state = msg_ptr[2] & 0x3f; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CALLSTATE = %d\n", cd->call_state)); + break; + + case IEI_PROGRESSI: /* progress indicator */ + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_PROGRESSINDICATOR\n")); + break; + + case IEI_DISPLAY: /* display */ + /* CHANGED BY <chris@medis.de> */ + memcpy(cd->display, &msg_ptr[2], min(DISPLAY_MAX, msg_ptr[1])); + cd->display[min(DISPLAY_MAX, msg_ptr[1])] = '\0'; + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_DISPLAY = %s\n", cd->display)); + break; + + case IEI_DATETIME: /* date/time */ + i = 2; + j = msg_ptr[1]; + p = &(cd->datetime[0]); + *p = '\0'; + + for(j = msg_ptr[1]; j > 0; j--, i++) + sprintf(p+strlen(p), "%02d", msg_ptr[i]); + + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_DATETIME = %s\n", cd->datetime)); + break; + + case IEI_FACILITY: /* facility */ + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_FACILITY\n")); + if(i4b_aoc(msg_ptr, cd) > -1) + i4b_l4_charging_ind(cd); + break; + + case IEI_CONCTDNO: /* connected number */ + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_CONCTDNO\n")); + break; + + case IEI_NETSPCFAC: /* network specific fac */ + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_NETSPCFAC\n")); + break; + + case IEI_LLCOMPAT: /* low layer compat */ + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_LLCOMPAT\n")); + break; + + case IEI_HLCOMPAT: /* high layer compat */ + DBGL3(L3_P_MSG, "i4b_decode_q931_codeset0", ("IEI_HLCOMPAT\n")); + break; + + default: + DBGL3(L3_P_ERR, "i4b_decode_q931_codeset0", ("Unknown IE %d - ", *msg_ptr)); + i4b_print_frame(msg_ptr[1]+2, msg_ptr); + break; + } + return(msg_ptr[1] + 2); +} + +/*---------------------------------------------------------------------------* + * decode and process one Q.931 codeset 0 information element + *---------------------------------------------------------------------------*/ +void +i4b_decode_q931_message(int unit, call_desc_t *cd, u_char message_type) +{ + cd->event = EV_ILL; + + switch(message_type) + { + /* call establishment */ + + case ALERT: + cd->event = EV_ALERT; + DBGL3(L3_PRIM, "rx ALERT", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case CALL_PROCEEDING: + cd->event = EV_CALLPRC; + DBGL3(L3_PRIM, "rx CALL-PROC", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case PROGRESS: + cd->event = EV_PROGIND; + DBGL3(L3_PRIM, "rx PROGRESS", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case SETUP: + DBGL3(L3_PRIM, "rx SETUP", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->bprot = BPROT_NONE; + cd->cause_in = 0; + cd->cause_out = 0; + cd->dst_telno[0] = '\0'; + cd->src_telno[0] = '\0'; + cd->channelid = CHAN_NO; + cd->channelexcl = 0; + cd->display[0] = '\0'; + cd->datetime[0] = '\0'; + cd->event = EV_SETUP; + break; + + case CONNECT: + DBGL3(L3_PRIM, "rx CONNECT", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->datetime[0] = '\0'; + cd->event = EV_CONNECT; + break; + + case SETUP_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx SETUP-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_SETUPAK; + break; + + case CONNECT_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx CONNECT-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_CONACK; + break; + + /* call information */ + + case USER_INFORMATION: + DBGL3(L3_PRIM, "rx USER-INFO", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case SUSPEND_REJECT: + DBGL3(L3_PRIM, "rx SUSPEND-REJ", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RESUME_REJECT: + DBGL3(L3_PRIM, "rx RESUME-REJ", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case HOLD: + DBGL3(L3_PRIM, "rx HOLD", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case SUSPEND: + DBGL3(L3_PRIM, "rx SUSPEND", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RESUME: + DBGL3(L3_PRIM, "rx RESUME", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case HOLD_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx HOLD-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case SUSPEND_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx SUSPEND-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RESUME_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx RESUME-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case HOLD_REJECT: + DBGL3(L3_PRIM, "rx HOLD-REJ", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RETRIEVE: + DBGL3(L3_PRIM, "rx RETRIEVE", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RETRIEVE_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx RETRIEVE-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RETRIEVE_REJECT: + DBGL3(L3_PRIM, "rx RETRIEVE-REJ", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + /* call clearing */ + + case DISCONNECT: + DBGL3(L3_PRIM, "rx DISCONNECT", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_DISCONN; + break; + + case RESTART: + DBGL3(L3_PRIM, "rx RESTART", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RELEASE: + DBGL3(L3_PRIM, "rx RELEASE", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_RELEASE; + break; + + case RESTART_ACKNOWLEDGE: + DBGL3(L3_PRIM, "rx RESTART-ACK", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case RELEASE_COMPLETE: + DBGL3(L3_PRIM, "rx RELEASE-COMPLETE", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_RELCOMP; + break; + + /* misc messages */ + + case SEGMENT: + DBGL3(L3_PRIM, "rx SEGMENT", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case FACILITY: + DBGL3(L3_PRIM, "rx FACILITY", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_FACILITY; + break; + + case REGISTER: + DBGL3(L3_PRIM, "rx REGISTER", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case NOTIFY: + DBGL3(L3_PRIM, "rx NOTIFY", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case STATUS_ENQUIRY: + DBGL3(L3_PRIM, "rx STATUS-ENQ", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_STATENQ; + break; + + case CONGESTION_CONTROL: + DBGL3(L3_PRIM, "rx CONGESTION-CONTROL", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + break; + + case INFORMATION: + DBGL3(L3_PRIM, "rx INFORMATION", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_INFO; + break; + + case STATUS: + DBGL3(L3_PRIM, "rx STATUS", ("unit %d, cr = 0x%02x\n", unit, cd->cr)); + cd->event = EV_STATUS; + break; + + default: + DBGL3(L3_P_ERR, "rx UNKNOWN msg", ("unit %d, cr = 0x%02x, msg = 0x%02x\n", unit, cd->cr, message_type)); + break; + } +} + +#endif /* NI4BQ931 > 0 */ diff --git a/sys/i4b/layer3/i4b_q931.h b/sys/i4b/layer3/i4b_q931.h new file mode 100644 index 000000000000..cb916b045fd0 --- /dev/null +++ b/sys/i4b/layer3/i4b_q931.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_q931.h - Q931 handling header file + * -------------------------------------- + * + * $Id: i4b_q931.h,v 1.5 1998/12/05 18:05:39 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:33:53 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_Q931_H_ +#define _I4B_Q931_H_ + +/* extension bit */ + +#define EXT_LAST 0x80 /* last octett */ + +/* reserve space in mbuf */ + +#define I_FRAME_HDRLEN 4 /* to be added by layer 2 */ + +/* SHIFT */ + +#define CODESET_MASK 0x07 +#define UNSHIFTED 0 +#define SHIFTED 1 +#define CRLENGTH_MASK 0x0f + +/* CONNECT */ + +#define MSG_CONNECT_LEN 4 /* length of a connect message */ + +/* DISCONNECT */ + +#define MSG_DISCONNECT_LEN 8 /* length of a disconnect message */ + +/* RELEASE COMPLETE */ + +#define MSG_RELEASE_COMPLETE_LEN 8 /* length of release complete msg */ + +/* for outgoing causes */ + +#define CAUSE_LEN 2 +#define CAUSE_STD_LOC_OUT 0x80 /* std = CCITT, loc = user */ + +/* SETUP */ + +#define MSG_SETUP_LEN 18 /* without number strings ! */ + +#define IEI_BEARERCAP_LEN 2 /* 2 octetts lenght */ + +#define IT_CAP_SPEECH 0x80 /* BC: information xfer capability */ +#define IT_CAP_UNR_DIG_INFO 0x88 /* BC: information xfer capability */ + +#define IT_RATE_64K 0x90 /* BC: information xfer rate */ +#define IT_UL1_G711A 0xa3 /* layer1 proto G.711 A-law */ + +#define IEI_CHANNELID_LEN 0x01 /* length of channel id */ +#define CHANNELID_B1 0x81 /* channel = B1 (outgoing) */ +#define CHANNELID_B2 0x82 /* channel = B2 (outgoing) */ +#define CHANNELID_ANY 0x83 /* channel = any channel (outgoing) */ + +#define IE_CHAN_ID_NO 0x00 /* no channel (incoming) */ +#define IE_CHAN_ID_B1 0x01 /* B1 channel (incoming) */ +#define IE_CHAN_ID_B2 0x02 /* B2 channel (incoming) */ +#define IE_CHAN_ID_ANY 0x03 /* ANY channel (incoming) */ + +#define NUMBER_TYPEPLAN 0x81 /* type of number/numbering plan */ + +#define IEI_CALLINGPN_LEN 1 /* without number string ! */ + +#define IEI_CALLEDPN_LEN 1 /* without number string ! */ + +/* CONNECT_ACK */ + +#define MSG_CONNECT_ACK_LEN 4 /* length of a connect ack message */ + +/* STATUS */ + +#define MSG_STATUS_LEN 11 +#define CALLSTATE_LEN 1 + +/* RELEASE */ + +#define MSG_RELEASE_LEN 8 /* length of release msg */ + +/* ALERT */ + +#define MSG_ALERT_LEN 4 /* length of a alert message */ + +#endif /* _I4B_Q931_H_ */ diff --git a/sys/i4b/layer3/i4b_q932fac.c b/sys/i4b/layer3/i4b_q932fac.c new file mode 100644 index 000000000000..487ce004c144 --- /dev/null +++ b/sys/i4b/layer3/i4b_q932fac.c @@ -0,0 +1,569 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_q932fac.c - Q932 facility handling + * -------------------------------------- + * + * $Id: i4b_q932fac.c,v 1.5 1998/12/05 18:05:41 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:34:11 1998] + * + *---------------------------------------------------------------------------*/ + +#ifdef __FreeBSD__ +#include "i4bq931.h" +#else +#define NI4BQ931 1 +#endif +#if NI4BQ931 > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer3/i4b_l3fsm.h> +#include <i4b/layer3/i4b_q931.h> +#include <i4b/layer3/i4b_q932fac.h> + +#include <i4b/layer4/i4b_l4.h> + +static int do_component(int length); +static void next_state(int class, int form, int code, int val); + +static int byte_len; +static unsigned char *byte_buf; +static int state; + +static int units; +static int operation_value; + +/*---------------------------------------------------------------------------* + * decode Q.931/Q.932 facility info element + *---------------------------------------------------------------------------*/ +int +i4b_aoc(unsigned char *buf, call_desc_t *cd) +{ + int len; + + cd->units_type = CHARGE_INVALID; + cd->units = -1; + + buf++; /* length */ + + len = *buf; + + buf++; /* protocol profile */ + + switch(*buf & 0x1f) + { + case FAC_PROTO_ROP: + break; + + case FAC_PROTO_CMIP: + DBGL3(L3_A_MSG, "i4b_facility", ("CMIP Protocol (Q.941), UNSUPPORTED\n")); + return(-1); + break; + + case FAC_PROTO_ACSE: + DBGL3(L3_A_MSG, "i4b_facility", ("ACSE Protocol (X.217/X.227), UNSUPPORTED!\n")); + return(-1); + break; + + default: + DBGL3(L3_A_ERR, "i4b_facility", ("Unknown Protocol, UNSUPPORTED!\n")); + return(-1); + break; + } + + DBGL3(L3_A_MSG, "i4b_facility", ("Remote Operations Protocol\n")); + + /* next byte */ + + buf++; + len--; + + /* initialize variables for do_component */ + + byte_len = 0; + byte_buf = buf; + state = ST_EXP_COMP_TYP; + + /* decode facility */ + + do_component(len); + + switch(operation_value) + { + case FAC_OPVAL_AOC_D_CUR: + cd->units_type = CHARGE_AOCD; + cd->units = 0; + return(0); + break; + + case FAC_OPVAL_AOC_D_UNIT: + cd->units_type = CHARGE_AOCD; + cd->units = units; + return(0); + break; + + case FAC_OPVAL_AOC_E_CUR: + cd->units_type = CHARGE_AOCE; + cd->units = 0; + return(0); + break; + + case FAC_OPVAL_AOC_E_UNIT: + cd->units_type = CHARGE_AOCE; + cd->units = units; + return(0); + break; + + default: + cd->units_type = CHARGE_INVALID; + cd->units = -1; + return(-1); + break; + } + return(-1); +} + +/*---------------------------------------------------------------------------* + * handle a component recursively + *---------------------------------------------------------------------------*/ +static int +do_component(int length) +{ + int comp_tag_class; /* component tag class */ + int comp_tag_form; /* component form: constructor or primitive */ + int comp_tag_code; /* component code depending on class */ + int comp_length = 0; /* component length */ + +again: + + /*----------------------------------------*/ + /* first component element: component tag */ + /*----------------------------------------*/ + + /* tag class bits */ + + comp_tag_class = (*byte_buf & 0xc0) >> 6; + + switch(comp_tag_class) + { + case FAC_TAGCLASS_UNI: + break; + case FAC_TAGCLASS_APW: + break; + case FAC_TAGCLASS_COS: + break; + case FAC_TAGCLASS_PRU: + break; + } + + /* tag form bit */ + + comp_tag_form = (*byte_buf & 0x20) > 5; + + /* tag code bits */ + + comp_tag_code = *byte_buf & 0x1f; + + if(comp_tag_code == 0x1f) + { + comp_tag_code = 0; + + byte_buf++; + byte_len++; + + while(*byte_buf & 0x80) + { + comp_tag_code += (*byte_buf & 0x7f); + byte_buf++; + byte_len++; + } + comp_tag_code += (*byte_buf & 0x7f); + } + else + { + comp_tag_code = (*byte_buf & 0x1f); + } + + byte_buf++; + byte_len++; + + /*--------------------------------------------*/ + /* second component element: component length */ + /*--------------------------------------------*/ + + comp_length = 0; + + if(*byte_buf & 0x80) + { + int i = *byte_buf & 0x7f; + + byte_len += i; + + for(;i > 0;i++) + { + byte_buf++; + comp_length += (*byte_buf * (i*256)); + } + } + else + { + comp_length = *byte_buf & 0x7f; + } + + next_state(comp_tag_class, comp_tag_form, comp_tag_code, -1); + + byte_len++; + byte_buf++; + + /*---------------------------------------------*/ + /* third component element: component contents */ + /*---------------------------------------------*/ + + if(comp_tag_form) /* == constructor */ + { + do_component(comp_length); + } + else + { + int val = 0; + if(comp_tag_class == FAC_TAGCLASS_UNI) + { + switch(comp_tag_code) + { + case FAC_CODEUNI_INT: + case FAC_CODEUNI_ENUM: + case FAC_CODEUNI_BOOL: + if(comp_length) + { + int i; + + for(i = comp_length-1; i >= 0; i--) + { + val += (*byte_buf + (i*255)); + byte_buf++; + byte_len++; + } + } + break; + default: + if(comp_length) + { + int i; + + for(i = comp_length-1; i >= 0; i--) + { + byte_buf++; + byte_len++; + } + } + break; + } + } + + else /* comp_tag_class != FAC_TAGCLASS_UNI */ + { + if(comp_length) + { + int i; + + for(i = comp_length-1; i >= 0; i--) + { + val += (*byte_buf + (i*255)); + byte_buf++; + byte_len++; + } + } + } + next_state(comp_tag_class, comp_tag_form, comp_tag_code, val); + } + + if(byte_len < length) + goto again; + + return(byte_len); +} + +/*---------------------------------------------------------------------------* + * invoke component + *---------------------------------------------------------------------------*/ +static void +F_1_1(int val) +{ + if(val == -1) + { + state = ST_EXP_INV_ID; + } +} + +/*---------------------------------------------------------------------------* + * return result + *---------------------------------------------------------------------------*/ +static void +F_1_2(int val) +{ + if(val == -1) + state = ST_EXP_NIX; +} +/*---------------------------------------------------------------------------* + * return error + *---------------------------------------------------------------------------*/ +static void +F_1_3(int val) +{ + if(val == -1) + state = ST_EXP_NIX; +} +/*---------------------------------------------------------------------------* + * reject + *---------------------------------------------------------------------------*/ +static void +F_1_4(int val) +{ + if(val == -1) + state = ST_EXP_NIX; +} + +/*---------------------------------------------------------------------------* + * invoke id + *---------------------------------------------------------------------------*/ +static void +F_2(int val) +{ + if(val != -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Invoke ID = %d\n", val)); + state = ST_EXP_OP_VAL; + } +} + +/*---------------------------------------------------------------------------* + * operation value + *---------------------------------------------------------------------------*/ +static void +F_3(int val) +{ + if(val != -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Operation Value = %d\n", val)); + + operation_value = val; + + if((val == FAC_OPVAL_AOC_D_UNIT) || (val == FAC_OPVAL_AOC_E_UNIT)) + { + units = 0; + state = ST_EXP_INFO; + } + else + { + state = ST_EXP_NIX; + } + } +} + +/*---------------------------------------------------------------------------* + * specific charging units + *---------------------------------------------------------------------------*/ +static void +F_4(int val) +{ + if(val == -1) + state = ST_EXP_RUL; +} + +/*---------------------------------------------------------------------------* + * free of charge + *---------------------------------------------------------------------------*/ +static void +F_4_1(int val) +{ + if(val == -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Free of Charge\n")); + /* units = 0; XXXX */ + state = ST_EXP_NIX; + } +} + +/*---------------------------------------------------------------------------* + * charge not available + *---------------------------------------------------------------------------*/ +static void +F_4_2(int val) +{ + if(val == -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Charge not available\n")); + /* units = -1; XXXXXX ??? */ + state = ST_EXP_NIX; + } +} + +/*---------------------------------------------------------------------------* + * recorded units list + *---------------------------------------------------------------------------*/ +static void +F_5(int val) +{ + if(val == -1) + state = ST_EXP_RU; +} + +/*---------------------------------------------------------------------------* + * recorded units + *---------------------------------------------------------------------------*/ +static void +F_6(int val) +{ + if(val == -1) + state = ST_EXP_RNOU; +} + +/*---------------------------------------------------------------------------* + * number of units + *---------------------------------------------------------------------------*/ +static void +F_7(int val) +{ + if(val != -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Number of Units = %d\n", val)); + units = val; + state = ST_EXP_TOCI; + } +} + +/*---------------------------------------------------------------------------* + * subtotal/total + *---------------------------------------------------------------------------*/ +static void +F_8(int val) +{ + if(val != -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Subtotal/Total = %d\n", val)); + /* type_of_charge = val; */ + state = ST_EXP_DBID; + } +} + +/*---------------------------------------------------------------------------* + * billing_id + *---------------------------------------------------------------------------*/ +static void +F_9(int val) +{ + if(val != -1) + { + DBGL3(L3_A_MSG, "i4b_facility", ("Billing ID = %d\n", val)); + /* billing_id = val; */ + state = ST_EXP_NIX; + } +} + +/*---------------------------------------------------------------------------* + * + *---------------------------------------------------------------------------*/ +static struct statetab { + int currstate; /* input: current state we are in */ + int form; /* input: current tag form */ + int class; /* input: current tag class */ + int code; /* input: current tag code */ + void (*func)(int); /* output: func to exec */ +} statetab[] = { + +/* current state tag form tag class tag code function */ +/* --------------------- ---------------------- ---------------------- ---------------------- ----------------*/ + {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_1_1 }, + {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 2, F_1_2 }, + {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 3, F_1_3 }, + {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 4, F_1_4 }, + {ST_EXP_INV_ID, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_2 }, + {ST_EXP_OP_VAL, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_3 }, + {ST_EXP_INFO, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_4 }, + {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_NULL, F_4_1 }, + {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 1, F_4_2 }, + {ST_EXP_RUL, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_5 }, + {ST_EXP_RU, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_6 }, + {ST_EXP_RNOU, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_7 }, + {ST_EXP_TOCI, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 2, F_8 }, + {ST_EXP_DBID, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 3, F_9 }, + {-1, -1, -1, -1, NULL } +}; + +/*---------------------------------------------------------------------------* + * state decode for do_component + *---------------------------------------------------------------------------*/ +static void +next_state(int class, int form, int code, int val) +{ + int i; + + for(i=0; ; i++) + { + if((statetab[i].currstate > state) || + (statetab[i].currstate == -1)) + { + break; + } + + if((statetab[i].currstate == state) && + (statetab[i].form == form) && + (statetab[i].class == class) && + (statetab[i].code == code)) + { + (*statetab[i].func)(val); + break; + } + } +} + +#endif /* NI4BQ931 > 0 */ diff --git a/sys/i4b/layer3/i4b_q932fac.h b/sys/i4b/layer3/i4b_q932fac.h new file mode 100644 index 000000000000..d7544a86e020 --- /dev/null +++ b/sys/i4b/layer3/i4b_q932fac.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_q932fac.h - Q932 facility handling header file + * -------------------------------------------------- + * + * $Id: i4b_q932fac.h,v 1.5 1998/12/18 17:17:57 hm Exp $ + * + * last edit-date: [Fri Dec 18 18:17:23 1998] + * + *--------------------------------------------------------------------------- + * + * - Q.932 (03/93) Generic Procedures for the Control of + * ISDN Supplementaty Services + * - Q.950 (03/93) Supplementary Services Protocols, Structure and + * General Principles + * - ETS 300 179 (10/92) Advice Of Charge: charging information during + * the call (AOC-D) supplementary service Service description + * - ETS 300 180 (10/92) Advice Of Charge: charging information at the + * end of call (AOC-E) supplementary service Service description + * - ETS 300 181 (04/93) Advice Of Charge (AOC) supplementary service + * Functional capabilities and information flows + * - ETS 300 182 (04/93) Advice Of Charge (AOC) supplementary service + * Digital Subscriber Signalling System No. one (DSS1) protocol + * - X.208 Specification of Abstract Syntax Notation One (ASN.1) + * - X.209 Specification of Basic Encoding Rules for + * Abstract Syntax Notation One (ASN.1) + * - "ASN.1 Abstract Syntax Notation One", Walter Gora, DATACOM-Verlag + * 1992, 3rd Edition (ISBN 3-89238-062-7) (german !) + * + *---------------------------------------------------------------------------*/ + +/* protocols */ +#define FAC_PROTO_ROP 0x11 +#define FAC_PROTO_CMIP 0x12 +#define FAC_PROTO_ACSE 0x13 + +/* tag classes */ +#define FAC_TAGCLASS_UNI 0x00 +#define FAC_TAGCLASS_APW 0x01 +#define FAC_TAGCLASS_COS 0x02 +#define FAC_TAGCLASS_PRU 0x03 + +/* tag forms */ +#define FAC_TAGFORM_PRI 0x00 +#define FAC_TAGFORM_CON 0x01 + +/* class UNIVERSAL values */ +#define FAC_CODEUNI_BOOL 1 +#define FAC_CODEUNI_INT 2 +#define FAC_CODEUNI_BITS 3 +#define FAC_CODEUNI_OCTS 4 +#define FAC_CODEUNI_NULL 5 +#define FAC_CODEUNI_OBJI 6 +#define FAC_CODEUNI_OBJD 7 +#define FAC_CODEUNI_EXT 8 +#define FAC_CODEUNI_REAL 9 +#define FAC_CODEUNI_ENUM 10 +#define FAC_CODEUNI_R11 11 +#define FAC_CODEUNI_R12 12 +#define FAC_CODEUNI_R13 13 +#define FAC_CODEUNI_R14 14 +#define FAC_CODEUNI_R15 15 +#define FAC_CODEUNI_SEQ 16 +#define FAC_CODEUNI_SET 17 +#define FAC_CODEUNI_NSTR 18 +#define FAC_CODEUNI_PSTR 19 +#define FAC_CODEUNI_TSTR 20 +#define FAC_CODEUNI_VSTR 21 +#define FAC_CODEUNI_ISTR 22 +#define FAC_CODEUNI_UTIME 23 +#define FAC_CODEUNI_GTIME 24 +#define FAC_CODEUNI_GSTR 25 +#define FAC_CODEUNI_VISTR 26 +#define FAC_CODEUNI_GNSTR 27 + +/* operation values */ +#define FAC_OPVAL_UUS 1 +#define FAC_OPVAL_CUG 2 +#define FAC_OPVAL_MCID 3 +#define FAC_OPVAL_BTPY 4 +#define FAC_OPVAL_ETPY 5 +#define FAC_OPVAL_ECT 6 + +#define FAC_OPVAL_DIV_ACT 7 +#define FAC_OPVAL_DIV_DEACT 8 +#define FAC_OPVAL_DIV_ACTSN 9 +#define FAC_OPVAL_DIV_DEACTSN 10 +#define FAC_OPVAL_DIV_INTER 11 +#define FAC_OPVAL_DIV_INFO 12 +#define FAC_OPVAL_DIV_CALLDEF 13 +#define FAC_OPVAL_DIV_CALLRER 14 +#define FAC_OPVAL_DIV_LINF2 15 +#define FAC_OPVAL_DIV_INVS 16 +#define FAC_OPVAL_DIV_INTER1 17 +#define FAC_OPVAL_DIV_LINF1 18 +#define FAC_OPVAL_DIV_LINF3 19 + +#define FAC_OPVAL_ER_CRCO 20 +#define FAC_OPVAL_ER_MGMT 21 +#define FAC_OPVAL_ER_CANC 22 + +#define FAC_OPVAL_MLPP_QUERY 24 +#define FAC_OPVAL_MLPP_CALLR 25 +#define FAC_OPVAL_MLPP_CALLP 26 + +#define FAC_OPVAL_AOC_REQ 30 +#define FAC_OPVAL_AOC_S_CUR 31 +#define FAC_OPVAL_AOC_S_SPC 32 +#define FAC_OPVAL_AOC_D_CUR 33 +#define FAC_OPVAL_AOC_D_UNIT 34 +#define FAC_OPVAL_AOC_E_CUR 35 +#define FAC_OPVAL_AOC_E_UNIT 36 +#define FAC_OPVAL_AOC_IDOFCRG 37 + +#define FAC_OPVAL_CONF_BEG 40 +#define FAC_OPVAL_CONF_ADD 41 +#define FAC_OPVAL_CONF_SPLIT 42 +#define FAC_OPVAL_CONF_DROP 43 +#define FAC_OPVAL_CONF_ISOLATE 44 +#define FAC_OPVAL_CONF_REATT 45 +#define FAC_OPVAL_CONF_PDISC 46 +#define FAC_OPVAL_CONF_FCONF 47 +#define FAC_OPVAL_CONF_END 48 +#define FAC_OPVAL_CONF_IDCFE 49 + +#define FAC_OPVAL_REVC_REQ 60 + +enum states { + ST_EXP_COMP_TYP, + ST_EXP_INV_ID, + ST_EXP_OP_VAL, + ST_EXP_INFO, + ST_EXP_RUL, + ST_EXP_RU, + ST_EXP_RNOU, + ST_EXP_TOCI, + ST_EXP_DBID, + + ST_EXP_NIX +}; + +/* EOF */ + diff --git a/sys/i4b/layer4/i4b_i4bdrv.c b/sys/i4b/layer4/i4b_i4bdrv.c new file mode 100644 index 000000000000..0c21e8ef7c5a --- /dev/null +++ b/sys/i4b/layer4/i4b_i4bdrv.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_i4bdrv.c - i4b userland interface driver + * -------------------------------------------- + * + * $Id: i4b_i4bdrv.c,v 1.33 1998/12/12 19:44:36 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:35:02 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4b.h" +#include "i4bipr.h" + +#if NI4B > 1 +#error "only 1 (one) i4b device possible!" +#endif + +#if NI4B > 0 + +#include <sys/param.h> + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#include <sys/malloc.h> +#include <sys/uio.h> +#else +#include <sys/ioctl.h> +#endif + +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include "opt_devfs.h" +#endif + +#ifdef DEVFS +#include <sys/devfsext.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer4/i4b_l4.h> + +#if defined(__FreeBSD__) && (!defined(__FreeBSD_version) || __FreeBSD_version < 300001) +/* do nothing */ +#else +#include <sys/poll.h> +#endif + +struct selinfo select_rd_info; + +static struct ifqueue i4b_rdqueue; +static int openflag = 0; +static int selflag = 0; +static int readflag = 0; +#ifdef DEVFS +static void *devfs_token; +#endif + +#ifndef __FreeBSD__ +#define PDEVSTATIC /* - not static - */ +PDEVSTATIC void i4battach __P((void)); +PDEVSTATIC int i4bopen __P((dev_t dev, int flag, int fmt, struct proc *p)); +PDEVSTATIC int i4bclose __P((dev_t dev, int flag, int fmt, struct proc *p)); +PDEVSTATIC int i4bread __P((dev_t dev, struct uio *uio, int ioflag)); +PDEVSTATIC int i4bioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +PDEVSTATIC int i4bpoll __P((dev_t dev, int events, struct proc *p)); + +#if defined (__OpenBSD__) +PDEVSTATIC int i4bselect(dev_t dev, int rw, struct proc *p); +#endif + +#endif + +#if BSD > 199306 && defined(__FreeBSD__) +#define PDEVSTATIC static + +PDEVSTATIC d_open_t i4bopen; +PDEVSTATIC d_close_t i4bclose; +PDEVSTATIC d_read_t i4bread; +PDEVSTATIC d_ioctl_t i4bioctl; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +PDEVSTATIC d_poll_t i4bpoll; +#else +PDEVSTATIC d_select_t i4bselect; +#endif + +#define CDEV_MAJOR 60 +static struct cdevsw i4b_cdevsw = + { i4bopen, i4bclose, i4bread, nowrite, + i4bioctl, nostop, nullreset, nodevtotty, +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + i4bpoll, nommap, NULL, "i4b", NULL, -1 }; +#else + i4bselect, nommap, NULL, "i4b", NULL, -1 }; +#endif + +PDEVSTATIC void i4battach(void *); +PSEUDO_SET(i4battach, i4b_i4bdrv); + +#endif /* __FreeBSD__ */ + +/*---------------------------------------------------------------------------* + * interface attach routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC void +#ifdef __FreeBSD__ +i4battach(void *dummy) +#else +i4battach() +#endif +{ +#ifndef HACK_NO_PSEUDO_ATTACH_MSG + printf("i4b: ISDN call control device attached\n"); +#endif + i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN; +#ifdef DEVFS + devfs_token = devfs_add_devswf(&i4b_cdevsw, 0, DV_CHR, + UID_ROOT, GID_WHEEL, 0600, + "i4b", 0); +#endif +} + +/*---------------------------------------------------------------------------* + * i4bopen - device driver open routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + int x; + + if(minor(dev)) + return(ENXIO); + + if(openflag) + return(EBUSY); + + x = splimp(); + openflag = 1; + i4b_l4_daemon_attached(); + splx(x); + + return(0); +} + +/*---------------------------------------------------------------------------* + * i4bclose - device driver close routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + int x = splimp(); + openflag = 0; + i4b_l4_daemon_detached(); + i4b_Dcleanifq(&i4b_rdqueue); + splx(x); + return(0); +} + +/*---------------------------------------------------------------------------* + * i4bread - device driver read routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bread(dev_t dev, struct uio *uio, int ioflag) +{ + struct mbuf *m; + int x; + int error = 0; + + if(minor(dev)) + return(ENODEV); + + while(IF_QEMPTY(&i4b_rdqueue)) + { + x = splimp(); + readflag = 1; + splx(x); + tsleep((caddr_t) &i4b_rdqueue, (PZERO + 1) | PCATCH, "bird", 0); + } + + x = splimp(); + + IF_DEQUEUE(&i4b_rdqueue, m); + + splx(x); + + if(m && m->m_len) + error = uiomove(m->m_data, m->m_len, uio); + else + error = EIO; + + if(m) + i4b_Dfreembuf(m); + + return(error); +} + +/*---------------------------------------------------------------------------* + * i4bioctl - device driver ioctl routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +#if defined (__FreeBSD_version) && __FreeBSD_version >= 300003 +i4bioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +#else +i4bioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) +#endif +{ + call_desc_t *cd; + int error = 0; + + if(minor(dev)) + return(ENODEV); + + switch(cmd) + { + /* cdid request, reserve cd and return cdid */ + + case I4B_CDID_REQ: + { + msg_cdid_req_t *mir; + mir = (msg_cdid_req_t *)data; + cd = reserve_cd(); + mir->cdid = cd->cdid; + break; + } + + /* connect request, dial out to remote */ + + case I4B_CONNECT_REQ: + { + msg_connect_req_t *mcr; + mcr = (msg_connect_req_t *)data; /* setup ptr */ + + if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */ + { + DBGL4(L4_ERR, "i4bioctl", ("I4B_CONNECT_REQ ioctl, cdid not found!\n")); + error = EINVAL; + break; + } + + cd->controller = mcr->controller; /* fill cd */ + cd->bprot = mcr->bprot; + cd->driver = mcr->driver; + cd->driver_unit = mcr->driver_unit; + cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit); + + cd->unitlen_time = mcr->unitlen_time; + cd->idle_time = mcr->idle_time; + cd->earlyhup_time = mcr->earlyhup_time; + + cd->last_aocd_time = 0; + if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC) + cd->aocd_flag = 1; + else + cd->aocd_flag = 0; + + cd->cunits = 0; + + cd->max_idle_time = 0; /* this is outgoing */ + + cd->dir = DIR_OUTGOING; + + DBGL4(L4_TIMO, "i4bioctl", ("I4B_CONNECT_REQ times, unitlen=%ld idle=%ld earlyhup=%ld\n", + (long)cd->unitlen_time, (long)cd->idle_time, (long)cd->earlyhup_time)); + + strcpy(cd->dst_telno, mcr->dst_telno); + strcpy(cd->src_telno, mcr->src_telno); + cd->display[0] = '\0'; + + SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B); + SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL); + + switch(mcr->channel) + { + case CHAN_B1: + case CHAN_B2: + if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE) + SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); + break; + + case CHAN_ANY: + if((ctrl_desc[mcr->controller].bch_state[CHAN_B1] != BCH_ST_FREE) && + (ctrl_desc[mcr->controller].bch_state[CHAN_B2] != BCH_ST_FREE)) + SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); + break; + + default: + SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); + break; + } + + cd->channelid = mcr->channel; + + cd->isdntxdelay = mcr->txdelay; + + /* check whether we have a pointer. Seems like */ + /* this should be adequate. GJ 19.09.97 */ + if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL) +/*XXX*/ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); + + if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL) + { + i4b_l4_disconnect_ind(cd); + freecd_by_cd(cd); + } + else + { + (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid); + } + break; + } + + /* connect response, accept/reject/ignore incoming call */ + + case I4B_CONNECT_RESP: + { + msg_connect_resp_t *mcrsp; + + mcrsp = (msg_connect_resp_t *)data; + + if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */ + { + DBGL4(L4_ERR, "i4bioctl", ("I4B_CONNECT_RESP ioctl, cdid not found!\n")); + error = EINVAL; + break; + } + + T400_stop(cd); + + cd->driver = mcrsp->driver; + cd->driver_unit = mcrsp->driver_unit; + cd->max_idle_time = mcrsp->max_idle_time; + + cd->unitlen_time = 0; /* this is incoming */ + cd->idle_time = 0; + cd->earlyhup_time = 0; + + cd->isdntxdelay = mcrsp->txdelay; + + DBGL4(L4_TIMO, "i4bioctl", ("I4B_CONNECT_RESP max_idle_time set to %ld seconds\n", (long)cd->max_idle_time)); + + (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause); + break; + } + + /* disconnect request, actively terminate connection */ + + case I4B_DISCONNECT_REQ: + { + msg_discon_req_t *mdr; + + mdr = (msg_discon_req_t *)data; + + if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */ + { + DBGL4(L4_ERR, "i4bioctl", ("I4B_DISCONNECT_REQ ioctl, cdid not found!\n")); + error = EINVAL; + break; + } + + /* preset causes with our cause */ + cd->cause_in = cd->cause_out = mdr->cause; + + (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause); + break; + } + + /* controller info request */ + + case I4B_CTRL_INFO_REQ: + { + msg_ctrl_info_req_t *mcir; + + mcir = (msg_ctrl_info_req_t *)data; + mcir->ncontroller = nctrl; + + if(mcir->controller > nctrl) + { + mcir->ctrl_type = -1; + mcir->card_type = -1; + } + else + { + mcir->ctrl_type = + ctrl_desc[mcir->controller].ctrl_type; + mcir->card_type = + ctrl_desc[mcir->controller].card_type; + + if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE) + mcir->tei = ctrl_desc[mcir->controller].tei; + else + mcir->tei = -1; + } + break; + } + + /* dial response */ + + case I4B_DIALOUT_RESP: + { + msg_dialout_resp_t *mdrsp; + + mdrsp = (msg_dialout_resp_t *)data; + +#if NI4BIPR > 0 + if(mdrsp->driver == BDRV_IPR) + { + drvr_link_t *dlt; + dlt = ipr_ret_linktab(mdrsp->driver_unit); + (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat); + } +#endif + break; + } + + /* update timeout value */ + + case I4B_TIMEOUT_UPD: + { + msg_timeout_upd_t *mtu; + int x; + + mtu = (msg_timeout_upd_t *)data; + + if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */ + { + DBGL4(L4_ERR, "i4bioctl", ("I4B_TIMEOUT_UPD ioctl, cdid not found!\n")); + error = EINVAL; + break; + } + + x = SPLI4B(); + cd->unitlen_time = mtu->unitlen_time; + cd->idle_time = mtu->idle_time; + cd->earlyhup_time = mtu->earlyhup_time; + splx(x); + break; + } + + /* soft enable/disable interface */ + + case I4B_UPDOWN_IND: + { + msg_updown_ind_t *mui; + + mui = (msg_updown_ind_t *)data; + +#if NI4BIPR > 0 + if(mui->driver == BDRV_IPR) + { + drvr_link_t *dlt; + dlt = ipr_ret_linktab(mui->driver_unit); + (*dlt->updown_ind)(mui->driver_unit, mui->updown); + } +#endif + break; + } + + /* send ALERT request */ + + case I4B_ALERT_REQ: + { + msg_alert_req_t *mar; + + mar = (msg_alert_req_t *)data; + + if((cd = cd_by_cdid(mar->cdid)) == NULL) + { + DBGL4(L4_ERR, "i4bioctl", ("I4B_ALERT_REQ ioctl, cdid not found!\n")); + error = EINVAL; + break; + } + + T400_stop(cd); + + (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid); + + break; + } + + /* version/release number request */ + + case I4B_VR_REQ: + { + msg_vr_req_t *mvr; + + mvr = (msg_vr_req_t *)data; + + mvr->version = VERSION; + mvr->release = REL; + mvr->step = STEP; + break; + } + + /* Download request */ + + case I4B_CTRL_DOWNLOAD: + { + struct isdn_dr_prot *prots = NULL, *prots2 = NULL; + struct isdn_download_request *r = + (struct isdn_download_request*)data; + int i; + + if(!ctrl_desc[r->controller].N_DOWNLOAD) + { + error = ENODEV; + goto download_done; + } + + prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot), + M_DEVBUF, M_WAITOK); + + prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot), + M_DEVBUF, M_WAITOK); + + if(!prots || !prots2) + { + error = ENOMEM; + goto download_done; + } + + copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot)); + + for(i = 0; i < r->numprotos; i++) + { + prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK); + copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount); + prots2[i].bytecount = prots[i].bytecount; + } + + error = ctrl_desc[r->controller].N_DOWNLOAD( + ctrl_desc[r->controller].unit, + r->numprotos, prots2); + +download_done: + if(prots2) + { + for(i = 0; i < r->numprotos; i++) + { + if(prots2[i].microcode) + { + free(prots2[i].microcode, M_DEVBUF); + } + } + free(prots2, M_DEVBUF); + } + + if(prots) + { + free(prots, M_DEVBUF); + } + break; + } + + /* Diagnostic request */ + + case I4B_ACTIVE_DIAGNOSTIC: + { + struct isdn_diagnostic_request req, *r = + (struct isdn_diagnostic_request*)data; + + req.in_param = req.out_param = NULL; + + if(!ctrl_desc[r->controller].N_DIAGNOSTICS) + { + error = ENODEV; + goto diag_done; + } + + memcpy(&req, r, sizeof(req)); + + if(req.in_param_len) + { + req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK); + + if(!req.in_param) + { + error = ENOMEM; + goto diag_done; + } + copyin(r->in_param, req.in_param, req.in_param_len); + } + + if(req.out_param_len) + { + req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK); + + if(!req.out_param) + { + error = ENOMEM; + goto diag_done; + } + } + + error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req); + + if(!error && req.out_param_len) + copyout(req.out_param, r->out_param, req.out_param_len); + +diag_done: + if(req.in_param) + free(req.in_param, M_DEVBUF); + + if(req.out_param) + free(req.out_param, M_DEVBUF); + + break; + } + + /* default */ + + default: + error = ENOTTY; + break; + } + + return(error); +} + +#if (defined(__FreeBSD__) && \ + (!defined(__FreeBSD_version) || (__FreeBSD_version < 300001))) \ + || defined (__OpenBSD__) + +/*---------------------------------------------------------------------------* + * i4bselect - device driver select routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bselect(dev_t dev, int rw, struct proc *p) +{ + int x; + + if(minor(dev)) + return(ENODEV); + + switch(rw) + { + case FREAD: + if(!IF_QEMPTY(&i4b_rdqueue)) + return(1); + x = splimp(); + selrecord(p, &select_rd_info); + selflag = 1; + splx(x); + return(0); + break; + + case FWRITE: + return(1); + break; + } + return(0); +} + +#else /* NetBSD and FreeBSD -current */ + +/*---------------------------------------------------------------------------* + * i4bpoll - device driver poll routine + *---------------------------------------------------------------------------*/ +PDEVSTATIC int +i4bpoll(dev_t dev, int events, struct proc *p) +{ + int x; + + if(minor(dev)) + return(ENODEV); + + if((events & POLLIN) || (events & POLLRDNORM)) + { + if(!IF_QEMPTY(&i4b_rdqueue)) + return(1); + + x = splimp(); + selrecord(p, &select_rd_info); + selflag = 1; + splx(x); + return(0); + } + else if((events & POLLOUT) || (events & POLLWRNORM)) + { + return(1); + } + + return(0); +} + +#endif /* defined(__FreeBSD__) && __FreeBSD__ < 3 */ + +/*---------------------------------------------------------------------------* + * i4bputqueue - put message into queue to userland + *---------------------------------------------------------------------------*/ +void +i4bputqueue(struct mbuf *m) +{ + int x; + + if(!openflag) + { + i4b_Dfreembuf(m); + return; + } + + x = splimp(); + + if(IF_QFULL(&i4b_rdqueue)) + { + struct mbuf *m1; + IF_DEQUEUE(&i4b_rdqueue, m1); + i4b_Dfreembuf(m1); + DBGL4(L4_ERR, "i4bputqueue", ("ERROR, queue full, removing entry!\n")); + } + + IF_ENQUEUE(&i4b_rdqueue, m); + + splx(x); + + if(readflag) + { + readflag = 0; + wakeup((caddr_t) &i4b_rdqueue); + } + + if(selflag) + { + selflag = 0; + selwakeup(&select_rd_info); + } +} + +/*---------------------------------------------------------------------------* + * i4bputqueue_hipri - put message into front of queue to userland + *---------------------------------------------------------------------------*/ +void +i4bputqueue_hipri(struct mbuf *m) +{ + int x; + + if(!openflag) + { + i4b_Dfreembuf(m); + return; + } + + x = splimp(); + + if(IF_QFULL(&i4b_rdqueue)) + { + struct mbuf *m1; + IF_DEQUEUE(&i4b_rdqueue, m1); + i4b_Dfreembuf(m1); + DBGL4(L4_ERR, "i4bputqueue", ("ERROR, queue full, removing entry!\n")); + } + + IF_PREPEND(&i4b_rdqueue, m); + + splx(x); + + if(readflag) + { + readflag = 0; + wakeup((caddr_t) &i4b_rdqueue); + } + + if(selflag) + { + selflag = 0; + selwakeup(&select_rd_info); + } +} + +#if BSD > 199306 && defined(__FreeBSD__) +static i4b_devsw_installed = 0; + +static void +i4b_drvinit(void *unused) +{ + dev_t dev; + + if( ! i4b_devsw_installed ) { + dev = makedev(CDEV_MAJOR,0); + cdevsw_add(&dev,&i4b_cdevsw,NULL); + i4b_devsw_installed = 1; + } +} + +SYSINIT(i4bdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,i4b_drvinit,NULL) +#endif /* __FreeBSD__ */ +#endif /* NI4B > 0 */ diff --git a/sys/i4b/layer4/i4b_l4.c b/sys/i4b/layer4/i4b_l4.c new file mode 100644 index 000000000000..cecd5f4e2d66 --- /dev/null +++ b/sys/i4b/layer4/i4b_l4.c @@ -0,0 +1,897 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l4.c - kernel interface to userland + * ----------------------------------------- + * + * $Id: i4b_l4.c,v 1.33 1998/12/05 18:05:49 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:35:16 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4b.h" +#include "i4bipr.h" +#include "i4bisppp.h" +#include "i4brbch.h" +#include "i4btel.h" + +#if NI4B > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <machine/i4b_cause.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#include <i4b/i4b_cause.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/layer3/i4b_l3.h> +#include <i4b/layer4/i4b_l4.h> + +unsigned int i4b_l4_debug = L4_DEBUG_DEFAULT; + +struct ctrl_type_desc ctrl_types[CTRL_NUMTYPES] = { { NULL, NULL} }; + +static int i4b_link_bchandrvr(call_desc_t *cd); +static void i4b_unlink_bchandrvr(call_desc_t *cd); +static void i4b_l4_setup_timeout(call_desc_t *cd); + +/*---------------------------------------------------------------------------* + * send MSG_PDEACT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_pdeact(int controller, int numactive) +{ + struct mbuf *m; + int i; + call_desc_t *cd; + + for(i=0; i < N_CALL_DESC; i++) + { + if((call_desc[i].cdid != CDID_UNUSED) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == controller)) + { + cd = &call_desc[i]; + + if(cd->timeout_active) + { +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle); +#else + untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd); +#endif + } + + if(cd->dlt != NULL) + { + (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); + i4b_unlink_bchandrvr(cd); + } + + if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) + { + ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; + } + + cd->cdid = CDID_UNUSED; + } + } + + if((m = i4b_Dgetmbuf(sizeof(msg_pdeact_ind_t))) != NULL) + { + msg_pdeact_ind_t *md = (msg_pdeact_ind_t *)m->m_data; + + md->header.type = MSG_PDEACT_IND; + md->header.cdid = -1; + + md->controller = controller; + md->numactive = numactive; + + i4bputqueue_hipri(m); /* URGENT !!! */ + } +} + +/*---------------------------------------------------------------------------* + * send MSG_L12STAT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_l12stat(int controller, int layer, int state) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_l12stat_ind_t))) != NULL) + { + msg_l12stat_ind_t *md = (msg_l12stat_ind_t *)m->m_data; + + md->header.type = MSG_L12STAT_IND; + md->header.cdid = -1; + + md->controller = controller; + md->layer = layer; + md->state = state; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_TEIASG_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_teiasg(int controller, int tei) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_teiasg_ind_t))) != NULL) + { + msg_teiasg_ind_t *md = (msg_teiasg_ind_t *)m->m_data; + + md->header.type = MSG_TEIASG_IND; + md->header.cdid = -1; + + md->controller = controller; + md->tei = ctrl_desc[controller].tei; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_DIALOUT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_dialout(int driver, int driver_unit) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_dialout_ind_t))) != NULL) + { + msg_dialout_ind_t *md = (msg_dialout_ind_t *)m->m_data; + + md->header.type = MSG_DIALOUT_IND; + md->header.cdid = -1; + + md->driver = driver; + md->driver_unit = driver_unit; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_NEGOTIATION_COMPL message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_negcomplete(call_desc_t *cd) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_negcomplete_ind_t))) != NULL) + { + msg_negcomplete_ind_t *md = (msg_negcomplete_ind_t *)m->m_data; + + md->header.type = MSG_NEGCOMP_IND; + md->header.cdid = cd->cdid; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_IFSTATE_CHANGED_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_ifstate_changed(call_desc_t *cd, int new_state) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_ifstatechg_ind_t))) != NULL) + { + msg_ifstatechg_ind_t *md = (msg_ifstatechg_ind_t *)m->m_data; + + md->header.type = MSG_IFSTATE_CHANGED_IND; + md->header.cdid = cd->cdid; + md->state = new_state; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_DRVRDISC_REQ message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_drvrdisc(int driver, int driver_unit) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_drvrdisc_req_t))) != NULL) + { + msg_drvrdisc_req_t *md = (msg_drvrdisc_req_t *)m->m_data; + + md->header.type = MSG_DRVRDISC_REQ; + md->header.cdid = -1; + + md->driver = driver; + md->driver_unit = driver_unit; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_ACCT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_accounting(int driver, int driver_unit, int accttype, int ioutbytes, + int iinbytes, int ro, int ri, int outbytes, int inbytes) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_accounting_ind_t))) != NULL) + { + msg_accounting_ind_t *md = (msg_accounting_ind_t *)m->m_data; + + md->header.type = MSG_ACCT_IND; + md->header.cdid = -1; + + md->driver = driver; + md->driver_unit = driver_unit; + + md->accttype = accttype; + md->ioutbytes = ioutbytes; + md->iinbytes = iinbytes; + md->outbps = ro; + md->inbps = ri; + md->outbytes = outbytes; + md->inbytes = inbytes; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_CONNECT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_connect_ind(call_desc_t *cd) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_connect_ind_t))) != NULL) + { + msg_connect_ind_t *mp = (msg_connect_ind_t *)m->m_data; + + mp->header.type = MSG_CONNECT_IND; + mp->header.cdid = cd->cdid; + + mp->controller = cd->controller; + mp->channel = cd->channelid; + mp->bprot = cd->bprot; + + cd->dir = DIR_INCOMING; + + if(strlen(cd->dst_telno) > 0) + strcpy(mp->dst_telno, cd->dst_telno); + else + strcpy(mp->dst_telno, TELNO_EMPTY); + + if(strlen(cd->src_telno) > 0) + strcpy(mp->src_telno, cd->src_telno); + else + strcpy(mp->src_telno, TELNO_EMPTY); + + strcpy(mp->display, cd->display); + + mp->scr_ind = cd->scr_ind; + + T400_start(cd); + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_CONNECT_ACTIVE_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_connect_active_ind(call_desc_t *cd) +{ + int s; + struct mbuf *m; + + s = SPLI4B(); + + cd->last_active_time = cd->connect_time = SECOND; + + DBGL4(L4_TIMO, "i4b_l4_connect_active_ind", ("last_active/connect_time=%ld\n", (long)cd->connect_time)); + + i4b_link_bchandrvr(cd); + + (*cd->dlt->line_connected)(cd->driver_unit, (void *)cd); + + i4b_l4_setup_timeout(cd); + + splx(s); + + if((m = i4b_Dgetmbuf(sizeof(msg_connect_active_ind_t))) != NULL) + { + msg_connect_active_ind_t *mp = (msg_connect_active_ind_t *)m->m_data; + + mp->header.type = MSG_CONNECT_ACTIVE_IND; + mp->header.cdid = cd->cdid; + mp->controller = cd->controller; + mp->channel = cd->channelid; + if(cd->datetime[0] != '\0') + strcpy(mp->datetime, cd->datetime); + else + mp->datetime[0] = '\0'; + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_DISCONNECT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_disconnect_ind(call_desc_t *cd) +{ + struct mbuf *m; + + if(cd->timeout_active) +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, cd->idle_timeout_handle); +#else + untimeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd); +#endif + + if(cd->dlt != NULL) + { + (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); + i4b_unlink_bchandrvr(cd); + } + + if((cd->channelid == CHAN_B1) || (cd->channelid == CHAN_B2)) + { + ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; + } + else + { + /* no error, might be hunting call for callback */ + DBGL4(L4_MSG, "i4b_l4_disconnect_ind", ("channel free not B1/B2 but %d!\n", cd->channelid)); + } + + if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL) + { + msg_disconnect_ind_t *mp = (msg_disconnect_ind_t *)m->m_data; + + mp->header.type = MSG_DISCONNECT_IND; + mp->header.cdid = cd->cdid; + mp->cause = cd->cause_in; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_IDLE_TIMEOUT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_idle_timeout_ind(call_desc_t *cd) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_idle_timeout_ind_t))) != NULL) + { + msg_idle_timeout_ind_t *mp = (msg_idle_timeout_ind_t *)m->m_data; + + mp->header.type = MSG_IDLE_TIMEOUT_IND; + mp->header.cdid = cd->cdid; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_CHARGING_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_charging_ind(call_desc_t *cd) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_charging_ind_t))) != NULL) + { + msg_charging_ind_t *mp = (msg_charging_ind_t *)m->m_data; + + mp->header.type = MSG_CHARGING_IND; + mp->header.cdid = cd->cdid; + mp->units_type = cd->units_type; + +/*XXX*/ if(mp->units_type == CHARGE_CALC) + mp->units = cd->cunits; + else + mp->units = cd->units; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_STATUS_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_status_ind(call_desc_t *cd) +{ +} + +/*---------------------------------------------------------------------------* + * send MSG_ALERT_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_alert_ind(call_desc_t *cd) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_alert_ind_t))) != NULL) + { + msg_alert_ind_t *mp = (msg_alert_ind_t *)m->m_data; + + mp->header.type = MSG_ALERT_IND; + mp->header.cdid = cd->cdid; + + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * send MSG_INFO_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_info_ind(call_desc_t *cd) +{ +} + +/*---------------------------------------------------------------------------* + * send MSG_INFO_IND message to userland + *---------------------------------------------------------------------------*/ +void +i4b_l4_proceeding_ind(call_desc_t *cd) +{ + struct mbuf *m; + + if((m = i4b_Dgetmbuf(sizeof(msg_proceeding_ind_t))) != NULL) + { + msg_proceeding_ind_t *mp = (msg_proceeding_ind_t *)m->m_data; + + mp->header.type = MSG_PROCEEDING_IND; + mp->header.cdid = cd->cdid; + mp->controller = cd->controller; + mp->channel = cd->channelid; + i4bputqueue(m); + } +} + +/*---------------------------------------------------------------------------* + * link a driver(unit) to a B-channel(controller,unit,channel) + *---------------------------------------------------------------------------*/ +static int +i4b_link_bchandrvr(call_desc_t *cd) +{ + int t = ctrl_desc[cd->controller].ctrl_type; + + if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL) + { + cd->ilt = NULL; + } + else + { + cd->ilt = ctrl_types[t].get_linktab( + ctrl_desc[cd->controller].unit, + cd->channelid); + } + + switch(cd->driver) + { +#if NI4BRBCH > 0 + case BDRV_RBCH: + cd->dlt = rbch_ret_linktab(cd->driver_unit); + break; +#endif + +#if NI4BTEL > 0 + case BDRV_TEL: + cd->dlt = tel_ret_linktab(cd->driver_unit); + break; +#endif + +#if NI4BIPR > 0 + case BDRV_IPR: + cd->dlt = ipr_ret_linktab(cd->driver_unit); + break; +#endif + +#if NI4BISPPP > 0 + case BDRV_ISPPP: + cd->dlt = i4bisppp_ret_linktab(cd->driver_unit); + break; +#endif + + default: + cd->dlt = NULL; + break; + } + + if(cd->dlt == NULL || cd->ilt == NULL) + return(-1); + + if(t >= 0 && t < CTRL_NUMTYPES && ctrl_types[t].set_linktab != NULL) + { + ctrl_types[t].set_linktab( + ctrl_desc[cd->controller].unit, + cd->channelid, + cd->dlt); + } + + switch(cd->driver) + { +#if NI4BRBCH > 0 + case BDRV_RBCH: + rbch_set_linktab(cd->driver_unit, cd->ilt); + break; +#endif + +#if NI4BTEL > 0 + case BDRV_TEL: + tel_set_linktab(cd->driver_unit, cd->ilt); + break; +#endif + +#if NI4BIPR > 0 + case BDRV_IPR: + ipr_set_linktab(cd->driver_unit, cd->ilt); + break; +#endif + +#if NI4BISPPP > 0 + case BDRV_ISPPP: + i4bisppp_set_linktab(cd->driver_unit, cd->ilt); + break; +#endif + default: + return(0); + break; + } + + /* activate B channel */ + + (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit, + cd->channelid, cd->bprot, 1); + + return(0); +} + +/*---------------------------------------------------------------------------* + * unlink a driver(unit) from a B-channel(controller,unit,channel) + *---------------------------------------------------------------------------*/ +static void +i4b_unlink_bchandrvr(call_desc_t *cd) +{ + int t = ctrl_desc[cd->controller].ctrl_type; + + if(t < 0 || t >= CTRL_NUMTYPES || ctrl_types[t].get_linktab == NULL) + { + cd->ilt = NULL; + return; + } + else + { + cd->ilt = ctrl_types[t].get_linktab( + ctrl_desc[cd->controller].unit, + cd->channelid); + } + + /* deactivate B channel */ + + (*cd->ilt->bch_config)(ctrl_desc[cd->controller].unit, + cd->channelid, cd->bprot, 0); +} + +/*--------------------------------------------------------------------------- + + How shorthold mode works for OUTGOING connections + ================================================= + + |<---- unchecked-window ------->|<-checkwindow->|<-safetywindow>| + +idletime_state: IST_NONCHK IST_CHECK IST_SAFE + + | | | | + time>>+-------------------------------+---------------+---------------+-... + | | | | + | |<--idle_time-->|<--earlyhup--->| + |<-----------------------unitlen------------------------------->| + + + unitlen - specifies the time a charging unit lasts + idle_time - specifies the thime the line must be idle at the + end of the unit to be elected for hangup + earlyhup - is the beginning of a timing safety zone before the + next charging unit starts + + The algorithm works as follows: lets assume the unitlen is 100 + secons, idle_time is 40 seconds and earlyhup is 10 seconds. + The line then must be idle 50 seconds after the begin of the + current unit and it must then be quiet for 40 seconds. if it + has been quiet for this 40 seconds, the line is closed 10 + seconds before the next charging unit starts. In case there was + any traffic within the idle_time, the line is not closed. + It does not matter whether there was any traffic between second + 0 and second 50 or not. + + + How shorthold mode works for INCOMING connections + ================================================= + + it is just possible to specify a maximum idle time for incoming + connections, after this time of no activity on the line the line + is closed. + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------* + * B channel idle check timeout setup + *---------------------------------------------------------------------------*/ +static void +i4b_l4_setup_timeout(call_desc_t *cd) +{ + cd->timeout_active = 0; + cd->idletime_state = IST_IDLE; + + if((cd->dir == DIR_INCOMING) && (cd->max_idle_time > 0)) + { + /* incoming call: simple max idletime check */ + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); + cd->timeout_active = 1; + DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: incoming-call, setup max_idle_time to %ld\n", (long)SECOND, (long)cd->max_idle_time)); + } + else if((cd->dir == DIR_OUTGOING) && (cd->idle_time > 0)) + { + /* outgoing call */ + + if((cd->idle_time > 0) && (cd->unitlen_time == 0)) + { + /* outgoing call: simple max idletime check */ + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); + cd->timeout_active = 1; + DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, setup idle_time to %ld\n", (long)SECOND, (long)cd->idle_time)); + } + else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time))) + { + /* outgoing call: full shorthold mode check */ + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time))); + cd->timeout_active = 1; + cd->idletime_state = IST_NONCHK; + DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("%ld: outgoing-call, start %ld sec nocheck window\n", + (long)SECOND, (long)(cd->unitlen_time - (cd->idle_time + cd->earlyhup_time)))); + + if(cd->aocd_flag == 0) + { + cd->units_type = CHARGE_CALC; + cd->cunits++; + i4b_l4_charging_ind(cd); + } + } + else + { + /* parms somehow got wrong .. */ + + DBGL4(L4_ERR, "i4b_l4_setup_timeout", ("%ld: ERROR: idletime[%ld]+earlyhup[%ld] > unitlength[%ld]!\n", + (long)SECOND, (long)cd->idle_time, (long)cd->earlyhup_time, (long)cd->unitlen_time)); + } + } + else + { + DBGL4(L4_TIMO, "i4b_l4_setup_timeout", ("no idle_timeout configured\n")); + } +} + +/*---------------------------------------------------------------------------* + * B channel idle check timeout function + *---------------------------------------------------------------------------*/ +void +i4b_idle_check(call_desc_t *cd) +{ + int s; + + if(cd->cdid == CDID_UNUSED) + return; + + s = SPLI4B(); + + /* failsafe */ + + if(cd->timeout_active == 0) + { + DBGL4(L4_ERR, "i4b_idle_check", ("ERROR: timeout_active == 0 !!!\n")); + } + else + { + cd->timeout_active = 0; + } + + /* incoming connections, simple idletime check */ + + if(cd->dir == DIR_INCOMING) + { + if((cd->last_active_time + cd->max_idle_time) <= SECOND) + { + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, line idle timeout, disconnecting!\n", (long)SECOND)); + (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, + (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); + i4b_l4_idle_timeout_ind(cd); + } + else + { + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: incoming-call, activity, last_active=%ld, max_idle=%ld\n", (long)SECOND, (long)cd->last_active_time, (long)cd->max_idle_time)); +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); + cd->timeout_active = 1; + } + } + + /* outgoing connections */ + + else if(cd->dir == DIR_OUTGOING) + { + + /* simple idletime calculation */ + + if((cd->idle_time > 0) && (cd->unitlen_time == 0)) + { + if((cd->last_active_time + cd->idle_time) <= SECOND) + { + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, idle timeout, disconnecting!\n", (long)SECOND)); + (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, + (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); + i4b_l4_idle_timeout_ind(cd); + } + else + { + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call-st, activity, last_active=%ld, max_idle=%ld\n", + (long)SECOND, (long)cd->last_active_time, (long)cd->idle_time)); +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz/2); + cd->timeout_active = 1; + } + } + + /* full shorthold mode calculation */ + + else if((cd->unitlen_time > 0) && (cd->unitlen_time > (cd->idle_time + cd->earlyhup_time))) + { + switch(cd->idletime_state) + { + case IST_NONCHK: /* end of non-check time */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->idle_time)); + cd->idletimechk_start = SECOND; + cd->idletime_state = IST_CHECK; + cd->timeout_active = 1; + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idletime check window reached!\n", (long)SECOND)); + break; + + case IST_CHECK: /* end of idletime chk */ + if((cd->last_active_time > cd->idletimechk_start) && + (cd->last_active_time <= SECOND)) + { /* activity detected */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->earlyhup_time)); + cd->timeout_active = 1; + cd->idletime_state = IST_SAFE; + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, activity at %ld, wait earlyhup-end\n", (long)SECOND, (long)cd->last_active_time)); + } + else + { /* no activity, hangup */ + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, idle timeout, last activity at %ld\n", (long)SECOND, (long)cd->last_active_time)); + (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, + (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); + i4b_l4_idle_timeout_ind(cd); + cd->idletime_state = IST_IDLE; + } + break; + + case IST_SAFE: /* end of earlyhup time */ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->idle_timeout_handle = +#endif + timeout((TIMEOUT_FUNC_T)i4b_idle_check,(void *)cd, hz*(cd->unitlen_time - (cd->idle_time+cd->earlyhup_time))); + cd->timeout_active = 1; + cd->idletime_state = IST_NONCHK; + + if(cd->aocd_flag == 0) + { + cd->units_type = CHARGE_CALC; + cd->cunits++; + i4b_l4_charging_ind(cd); + } + + DBGL4(L4_TIMO, "i4b_idle_check", ("%ld: outgoing-call, earlyhup end, wait for idletime start\n", (long)SECOND)); + break; + + default: + DBGL4(L4_ERR, "i4b_idle_check", ("outgoing-call: invalid idletime_state value!\n")); + cd->idletime_state = IST_IDLE; + break; + } + } + } + splx(s); +} + +#endif /* NI4B > 0 */ diff --git a/sys/i4b/layer4/i4b_l4.h b/sys/i4b/layer4/i4b_l4.h new file mode 100644 index 000000000000..e4ed863f383a --- /dev/null +++ b/sys/i4b/layer4/i4b_l4.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l4.h - kernel interface to userland header file + * --------------------------------------------------- + * + * $Id: i4b_l4.h,v 1.13 1998/12/05 18:05:50 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:35:34 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_L4_H_ +#define _I4B_L4_H_ + +extern void i4bputqueue ( struct mbuf *m ); +extern void i4bputqueue_hipri(struct mbuf *m); +extern void i4b_l4_accounting(int, int, int, int, int, int, int, int, int); +extern void i4b_l4_alert_ind ( call_desc_t *cd ); +extern void i4b_l4_charging_ind( call_desc_t *cd ); +extern void i4b_l4_connect_active_ind ( call_desc_t *cd ); +extern void i4b_l4_connect_ind ( call_desc_t *cd ); +extern void i4b_l4_daemon_attached(void); +extern void i4b_l4_daemon_detached(void); +extern void i4b_l4_dialout( int driver, int driver_unit ); +extern void i4b_l4_disconnect_ind ( call_desc_t *cd ); +extern void i4b_l4_drvrdisc (int driver, int driver_unit ); +extern void i4b_l4_negcomplete( call_desc_t *cd ); +extern void i4b_l4_ifstate_changed( call_desc_t *cd, int new_state ); +extern void i4b_l4_idle_timeout_ind( call_desc_t *cd ); +extern void i4b_l4_info_ind ( call_desc_t *cd ); +extern void i4b_l4_l12stat(int controller, int layer, int state); +extern void i4b_l4_pdeact(int controller, int numactive); +extern void i4b_l4_teiasg(int controller, int tei); +extern void i4b_l4_status_ind ( call_desc_t *cd ); +extern void i4b_l4_proceeding_ind ( call_desc_t *cd ); +extern void i4b_idle_check(call_desc_t *cdp); +extern call_desc_t * cd_by_cdid ( unsigned int cdid ); +extern call_desc_t * cd_by_unitcr ( int unit, int cr, int crf ); +extern void freecd_by_cd ( call_desc_t *cd ); +extern unsigned char get_rand_cr ( int unit ); +extern call_desc_t * reserve_cd ( void ); +extern void T400_start ( call_desc_t *cd ); +extern void T400_stop ( call_desc_t *cd ); + +#endif /* _I4B_L4_H_ */ diff --git a/sys/i4b/layer4/i4b_l4mgmt.c b/sys/i4b/layer4/i4b_l4mgmt.c new file mode 100644 index 000000000000..e8e1a967a696 --- /dev/null +++ b/sys/i4b/layer4/i4b_l4mgmt.c @@ -0,0 +1,467 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l4mgmt.c - layer 4 calldescriptor management utilites + * ----------------------------------------------------------- + * + * $Id: i4b_l4mgmt.c,v 1.23 1998/12/05 18:05:52 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:35:50 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4b.h" + +#if NI4B > 0 + +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <machine/random.h> +#endif +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_l2l3.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> +#include <i4b/include/i4b_isdnq931.h> +#include <i4b/include/i4b_global.h> + +#include <i4b/layer4/i4b_l4.h> + +call_desc_t call_desc[N_CALL_DESC]; /* call descriptor array */ + +static unsigned int get_cdid(void); + +int nctrl; /* number of attached controllers */ + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +void init_callout(call_desc_t *); +#endif + +/*---------------------------------------------------------------------------* + * return a new unique call descriptor id + * -------------------------------------- + * returns a new calldescriptor id which is used to uniquely identyfy + * a single call in the communication between kernel and userland. + * this cdid is then used to associate a calldescriptor with an id. + *---------------------------------------------------------------------------*/ +static unsigned int +get_cdid(void) +{ + static unsigned int cdid_count = 0; + int i; + int x; + + x = SPLI4B(); + + /* get next id */ + + cdid_count++; + +again: + if(cdid_count == CDID_UNUSED) /* zero is invalid */ + cdid_count++; + else if(cdid_count > CDID_MAX) /* wraparound ? */ + cdid_count = 1; + + /* check if id already in use */ + + for(i=0; i < N_CALL_DESC; i++) + { + if(call_desc[i].cdid == cdid_count) + { + cdid_count++; + goto again; + } + } + + splx(x); + + return(cdid_count); +} + +/*---------------------------------------------------------------------------* + * reserve a calldescriptor for later usage + * ---------------------------------------- + * searches the calldescriptor array until an unused + * descriptor is found, gets a new calldescriptor id + * and reserves it by putting the id into the cdid field. + * returns pointer to the calldescriptor. + *---------------------------------------------------------------------------*/ +call_desc_t * +reserve_cd(void) +{ + call_desc_t *cd; + int x; + int i; + + x = SPLI4B(); + + cd = NULL; + + for(i=0; i < N_CALL_DESC; i++) + { + if(call_desc[i].cdid == CDID_UNUSED) + { + bzero(&call_desc[i], sizeof(call_desc_t)); /* clear it */ + call_desc[i].cdid = get_cdid(); /* fill in new cdid */ + cd = &(call_desc[i]); /* get pointer to descriptor */ + DBGL4(L4_MSG, "reserve_cd", ("found free cd - index=%d cdid=%u\n", + i, call_desc[i].cdid)); + break; + } + } + + splx(x); + + if(cd == NULL) + panic("reserve_cd: no free call descriptor available!"); + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + init_callout(cd); +#endif + + return(cd); +} + +/*---------------------------------------------------------------------------* + * free a calldescriptor + * --------------------- + * free a unused calldescriptor by giving address of calldescriptor + * and writing a 0 into the cdid field marking it as unused. + *---------------------------------------------------------------------------*/ +void +freecd_by_cd(call_desc_t *cd) +{ + int i; + int x = SPLI4B(); + + for(i=0; i < N_CALL_DESC; i++) + { + if( (call_desc[i].cdid != CDID_UNUSED) && + (&(call_desc[i]) == cd) ) + { + DBGL4(L4_MSG, "freecd_by_cd", ("releasing cd - index=%d cdid=%u cr=%d\n", + i, call_desc[i].cdid, cd->cr)); + call_desc[i].cdid = CDID_UNUSED; + break; + } + } + + if(i == N_CALL_DESC) + panic("freecd_by_cd: ERROR, cd not found, cr = %d\n", cd->cr); + + splx(x); +} + +/*---------------------------------------------------------------------------* + * return pointer to calldescriptor by giving the calldescriptor id + * ---------------------------------------------------------------- + * lookup a calldescriptor in the calldescriptor array by looking + * at the cdid field. return pointer to calldescriptor if found, + * else return NULL if not found. + *---------------------------------------------------------------------------*/ +call_desc_t * +cd_by_cdid(unsigned int cdid) +{ + int i; + + for(i=0; i < N_CALL_DESC; i++) + { + if(call_desc[i].cdid == cdid) + { + DBGL4(L4_MSG, "cd_by_cdid", ("found cdid - index=%d cdid=%u cr=%d\n", + i, call_desc[i].cdid, call_desc[i].cr)); +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + init_callout(&call_desc[i]); +#endif + return(&(call_desc[i])); + } + } + return(NULL); +} + +/*---------------------------------------------------------------------------* + * search calldescriptor + * --------------------- + * This routine searches for the calldescriptor for a passive controller + * given by unit number, callreference and callreference flag. + * It returns a pointer to the calldescriptor if found, else a NULL. + *---------------------------------------------------------------------------*/ +call_desc_t * +cd_by_unitcr(int unit, int cr, int crf) +{ + int i; + + for(i=0; i < N_CALL_DESC; i++) + { + if((call_desc[i].cdid != CDID_UNUSED) && + (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) && + (ctrl_desc[call_desc[i].controller].unit == unit) && + (call_desc[i].cr == cr) && + (call_desc[i].crflag == crf) ) + { + DBGL4(L4_MSG, "cd_by_unitcr", ("found cd, index=%d cdid=%u cr=%d\n", + i, call_desc[i].cdid, call_desc[i].cr)); +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + init_callout(&call_desc[i]); +#endif + return(&(call_desc[i])); + } + } + return(NULL); +} + +/*---------------------------------------------------------------------------* + * generate 7 bit "random" number used for outgoing Call Reference + *---------------------------------------------------------------------------*/ +unsigned char +get_rand_cr(int unit) +{ + register int i, j; + static u_char val, retval; + static int called = 42; + + val += ++called; + + for(i=0; i < 50 ; i++, val++) + { + int found = 1; + +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + read_random((char *)&val, sizeof(val)); +#else + val |= unit+i; + val <<= i; + val ^= (time.tv_sec >> 8) ^ time.tv_usec; + val <<= i; + val ^= time.tv_sec ^ (time.tv_usec >> 8); +#endif + + retval = val & 0x7f; + + if(retval == 0 || retval == 0x7f) + continue; + + for(j=0; j < N_CALL_DESC; j++) + { + if( (call_desc[j].cdid != CDID_UNUSED) && + (call_desc[j].cr == retval) ) + { + found = 0; + break; + } + } + + if(found) + return(retval); + } + return(0); /* XXX */ +} + +/*---------------------------------------------------------------------------* + * initialize the callout handles for FreeBSD-current 3.0 + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +void +init_callout(call_desc_t *cd) +{ + if(cd->callouts_inited == 0) + { + callout_handle_init(&cd->idle_timeout_handle); + callout_handle_init(&cd->T303_callout); + callout_handle_init(&cd->T305_callout); + callout_handle_init(&cd->T308_callout); + callout_handle_init(&cd->T309_callout); + callout_handle_init(&cd->T310_callout); + callout_handle_init(&cd->T313_callout); + callout_handle_init(&cd->T400_callout); + cd->callouts_inited = 1; + } +} +#endif + +/*---------------------------------------------------------------------------* + * daemon is attached + *---------------------------------------------------------------------------*/ +void +i4b_l4_daemon_attached(void) +{ + int i; + + int x = SPLI4B(); + + for(i=0; i < nctrl; i++) + { +/*XXX*/ if(ctrl_desc[i].ctrl_type == CTRL_PASSIVE) + { + DBGL4(L4_MSG, "i4b_l4_daemon_attached", ("CMR_DOPEN sent to unit %d\n", ctrl_desc[i].unit)); + + (*ctrl_desc[i].N_MGMT_COMMAND)(ctrl_desc[i].unit, CMR_DOPEN, 0); + } + } + splx(x); +} + +/*---------------------------------------------------------------------------* + * daemon is detached + *---------------------------------------------------------------------------*/ +void +i4b_l4_daemon_detached(void) +{ + int i; + + int x = SPLI4B(); + + for(i=0; i < nctrl; i++) + { +/*XXX*/ if(ctrl_desc[i].ctrl_type == CTRL_PASSIVE) + { + DBGL4(L4_MSG, "i4b_l4_daemon_detached", ("CMR_DCLOSE sent to unit %d\n", ctrl_desc[i].unit)); + + (*ctrl_desc[i].N_MGMT_COMMAND)(ctrl_desc[i].unit, CMR_DCLOSE, 0); + } + } + splx(x); +} + +#ifdef I4B_CD_DEBUG_PRINT + +extern char *print_l3state(call_desc_t *cd); + +void i4b_print_cdp(call_desc_t *cdp); +void i4b_print_cdx(int index); +void i4b_print_cda(void); +void i4b_print_cdaa(void); + +/*---------------------------------------------------------------------------* + * print a call descriptor by cd-pointer + *---------------------------------------------------------------------------*/ +void +i4b_print_cdp(call_desc_t *cdp) +{ + if((cdp > &(call_desc[N_CALL_DESC])) || (cdp < &(call_desc[0]))) + { + printf("i4b_print_cd: cdp out of range!\n"); + return; + } + + printf("i4b_print_cd: printing call descriptor %d at 0x%lx:\n", cdp - (&(call_desc[0])), (unsigned long)cdp); + + printf(" cdid = %d\n", cdp->cdid); + printf(" controller = %d (u=%d, dl=%d, b1=%d, b2=%d)\n", + cdp->controller, + ctrl_desc[cdp->controller].unit, + ctrl_desc[cdp->controller].dl_est, + ctrl_desc[cdp->controller].bch_state[CHAN_B1], + ctrl_desc[cdp->controller].bch_state[CHAN_B2]); + printf(" cr = 0x%02x\n", cdp->cr); + printf(" crflag = %d\n", cdp->crflag); + printf(" channelid = %d\n", cdp->channelid); + printf(" bprot = %d\n", cdp->bprot); + printf(" driver = %d\n", cdp->driver); + printf(" driver_unit = %d\n", cdp->driver_unit); + printf(" call_state = %d\n", cdp->call_state); + printf(" Q931state = %s\n", print_l3state(cdp)); + printf(" event = %d\n", cdp->event); + printf(" response = %d\n", cdp->response); + printf(" T303 = %d\n", cdp->T303); + printf("T303_first_to = %d\n", cdp->T303_first_to); + printf(" T305 = %d\n", cdp->T305); + printf(" T308 = %d\n", cdp->T308); + printf("T308_first_to = %d\n", cdp->T308_first_to); + printf(" T309 = %d\n", cdp->T309); + printf(" T310 = %d\n", cdp->T310); + printf(" T313 = %d\n", cdp->T313); + printf(" T400 = %d\n", cdp->T400); + printf(" dir = %s\n", cdp->dir == DIR_OUTGOING ? "out" : "in"); +} + +/*---------------------------------------------------------------------------* + * print a call descriptor by index + *---------------------------------------------------------------------------*/ +void +i4b_print_cdx(int index) +{ + if(index >= N_CALL_DESC) + { + printf("i4b_print_cdx: index %d >= N_CALL_DESC %d\n", index, N_CALL_DESC); + return; + } + i4b_print_cdp(&(call_desc[index])); +} + +/*---------------------------------------------------------------------------* + * print all call descriptors + *---------------------------------------------------------------------------*/ +void +i4b_print_cda(void) +{ + int i; + + for(i=0; i < N_CALL_DESC; i++) + { + i4b_print_cdp(&(call_desc[i])); + } +} + +/*---------------------------------------------------------------------------* + * print all active call descriptors + *---------------------------------------------------------------------------*/ +void +i4b_print_cdaa(void) +{ + int i; + + for(i=0; i < N_CALL_DESC; i++) + { + if(call_desc[i].cdid != CDID_UNUSED) + { + i4b_print_cdp(&(call_desc[i])); + } + } +} + +#endif /* I4B_CD_DEBUG_PRINT */ + +#endif /* NI4BQ931 > 0 */ diff --git a/sys/i4b/layer4/i4b_l4timer.c b/sys/i4b/layer4/i4b_l4timer.c new file mode 100644 index 000000000000..7a38e13904dd --- /dev/null +++ b/sys/i4b/layer4/i4b_l4timer.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_l4timer.c - timer and timeout handling for layer 4 + * -------------------------------------------------------- + * + * $Id: i4b_l4timer.c,v 1.10 1998/12/05 18:05:53 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:36:07 1998] + * + *---------------------------------------------------------------------------*/ + +#include "i4b.h" + +#if NI4B > 0 + +#include <sys/param.h> +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#else +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_global.h> +#include <i4b/include/i4b_l3l4.h> +#include <i4b/include/i4b_mbuf.h> + +#include <i4b/layer4/i4b_l4.h> + +/*---------------------------------------------------------------------------* + * timer T400 timeout function + *---------------------------------------------------------------------------*/ +static void +T400_timeout(call_desc_t *cd) +{ + DBGL4(L4_ERR, "T400_timeout", ("cr = %d\n", cd->cr)); +} + +/*---------------------------------------------------------------------------* + * timer T400 start + *---------------------------------------------------------------------------*/ +void +T400_start(call_desc_t *cd) +{ + DBGL4(L4_MSG, "T400_start", ("cr = %d\n", cd->cr)); + + cd->T400 = TIMER_ACTIVE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + cd->T400_callout = timeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd, T400DEF); +#else + timeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd, T400DEF); +#endif +} + +/*---------------------------------------------------------------------------* + * timer T400 stop + *---------------------------------------------------------------------------*/ +void +T400_stop(call_desc_t *cd) +{ + DBGL4(L4_MSG, "T400_stop", ("cr = %d\n", cd->cr)); + + if(cd->T400 == TIMER_ACTIVE) + { + cd->T400 = TIMER_IDLE; +#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001 + untimeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd, cd->T400_callout); +#else + untimeout((TIMEOUT_FUNC_T)T400_timeout, (void *)cd); +#endif + } +} + +#endif /* NI4B > 0 */ diff --git a/sys/i4b/tina-dd/README b/sys/i4b/tina-dd/README new file mode 100644 index 000000000000..6a2386f90bf4 --- /dev/null +++ b/sys/i4b/tina-dd/README @@ -0,0 +1,20 @@ + +THIS DRIVER IS NOT YET WORKING ! +================================ + +This adds support for the active ISDN card tina-dd manufactured by +Stollmann E+V GmbH in Hamburg, Germany. This card was also sold by +MIRO as the Miro P1. + +Christian Luehrs and Manfred Jung of Stollmann were very helpful +giving out docs and sources to support the development of a driver +for this card. + +The card supports many protocols. In order to make the card operable +you'll need the downloadable firmware which also can be found on the +www/ftp server, www.stollmann.de / ftp.stollmann.de. + +While developing this driver, i used fcdddss1.loc as of April 1994. + +The code is based in part on sources and header files written by +Stollmann for their driver development kit for the tina-dd. diff --git a/sys/i4b/tina-dd/i4b_tina_dd.c b/sys/i4b/tina-dd/i4b_tina_dd.c new file mode 100644 index 000000000000..7a5e010b8048 --- /dev/null +++ b/sys/i4b/tina-dd/i4b_tina_dd.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 1994, 1998 Hellmuth Michaelis. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * i4b_tina_dd.c - i4b Stollman Tina-dd control device driver + * ---------------------------------------------------------- + * + * $Id: i4b_tina_dd.c,v 1.3 1998/12/05 18:06:19 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:41:38 1998] + * + *---------------------------------------------------------------------------*/ + +#include "tina.h" + +#if NTINA > 0 + +#include <sys/param.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include <sys/ioccom.h> +#else +#include <sys/ioctl.h> +#endif +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/mbuf.h> +#include <sys/proc.h> +#include <sys/fcntl.h> +#include <sys/socket.h> +#include <net/if.h> + +#ifdef __FreeBSD__ +#include <machine/i4b_debug.h> +#include <machine/i4b_ioctl.h> +#include <i386/isa/isa_device.h> +#else +#include <machine/bus.h> +#include <sys/device.h> +#include <i4b/i4b_debug.h> +#include <i4b/i4b_ioctl.h> +#endif + +#include <i4b/include/i4b_mbuf.h> +#include <i4b/tina-dd/i4b_tina_ioctl.h> + +static int openflag = 0; + +int tinaprobe(struct isa_device *dev); +int tinaattach(struct isa_device *dev); + +struct isa_driver tinadriver = { + tinaprobe, + tinaattach, + "tina", + 0 +}; + +static struct tina_softc { + int sc_unit; + int sc_iobase; +} tina_sc[NTINA]; + +static d_open_t tinaopen; +static d_close_t tinaclose; +static d_ioctl_t tinaioctl; +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static d_poll_t tinapoll; +#endif + +#define CDEV_MAJOR 54 +static struct cdevsw tina_cdevsw = + { tinaopen, tinaclose, noread, nowrite, + tinaioctl, nostop, nullreset, nodevtotty, +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 + tinapoll, nommap, NULL, "tina", NULL, -1 }; +#else + noselect, nommap, NULL, "tina", NULL, -1 }; +#endif + +static void setupaddr(unsigned short iobase, unsigned int addr); +static void readblock(unsigned short iobase, unsigned int addr, + unsigned char *dst, unsigned int len); +static void writeblock(unsigned short iobase, unsigned char *src, + unsigned long addr, int len); + +/*---------------------------------------------------------------------------* + * tina - device driver probe routine + *---------------------------------------------------------------------------*/ +int +tinaprobe(struct isa_device *dev) +{ + struct tina_softc *sc = &tina_sc[dev->id_unit]; + u_char byte; + +#define SETLOW 0x55 +#define SETMID 0xaa +#define SETHIGH 0x06 + + outb((dev->id_iobase + ADDR_CNTL), SETLOW); + + if((byte = inb(dev->id_iobase + ADDR_CNTL)) != SETLOW) + { + printf("tina%d: probe low failed, 0x%x != 0x%x\n", + dev->id_unit, byte, SETLOW); + return(0); + } + + outb((dev->id_iobase + ADDR_CNTM), SETMID); + if((byte = inb(dev->id_iobase + ADDR_CNTM)) != SETMID) + { + printf("tina%d: probe mid failed, 0x%x != 0x%x\n", + dev->id_unit, byte, SETMID); + return(0); + } + + outb((dev->id_iobase + ADDR_CNTH), SETHIGH); + if(((byte = inb(dev->id_iobase + ADDR_CNTH)) & 0x0f) != SETHIGH) + { + printf("tina%d: probe high failed, 0x%x != 0x%x\n", + dev->id_unit, byte, SETHIGH); + return(0); + } + + printf("tina%d: status register = 0x%x\n", + dev->id_unit, inb(dev->id_iobase + CTRL_STAT)); + + return(1); /* board found */ +} +#undef SETLOW +#undef SETMID +#undef SETHIGH + +/*---------------------------------------------------------------------------* + * tina - device driver attach routine + *---------------------------------------------------------------------------*/ +int +tinaattach(struct isa_device *dev) +{ + struct tina_softc *sc = &tina_sc[dev->id_unit]; + + sc->sc_unit = dev->id_unit; + sc->sc_iobase = dev->id_iobase; + + printf("tina%d: attaching Tina-dd\n", dev->id_unit); + + return(1); +} + +/*---------------------------------------------------------------------------* + * tina - device driver interrupt routine + *---------------------------------------------------------------------------*/ +void +tinaintr(int unit) +{ + struct tina_softc *sc = &tina_sc[unit]; +} + +#if BSD > 199306 && defined(__FreeBSD__) +/*---------------------------------------------------------------------------* + * initialization at kernel load time + *---------------------------------------------------------------------------*/ +static void +tinainit(void *unused) +{ + dev_t dev; + + dev = makedev(CDEV_MAJOR, 0); + + cdevsw_add(&dev, &tina_cdevsw, NULL); +} + +SYSINIT(tinadev, SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR, &tinainit, NULL); + +#endif /* BSD > 199306 && defined(__FreeBSD__) */ + +/*---------------------------------------------------------------------------* + * tinaopen - device driver open routine + *---------------------------------------------------------------------------*/ +static int +tinaopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + if(minor(dev)) + return (ENXIO); + + if(openflag) + return (EBUSY); + + openflag = 1; + + return(0); +} + +/*---------------------------------------------------------------------------* + * tinaclose - device driver close routine + *---------------------------------------------------------------------------*/ +static int +tinaclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + openflag = 0; + return(0); +} + +/*---------------------------------------------------------------------------* + * tinaioctl - device driver ioctl routine + *---------------------------------------------------------------------------*/ +static int +tinaioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct tina_softc *sc = &tina_sc[minor(dev)]; + u_short iobase = sc->sc_iobase; + int error = 0; + char *ptr; + int s; + + if(minor(dev)) + return(ENODEV); + + s = splimp(); + + switch(cmd) + { + /* hardware layer - control & status register */ + + case ISDN_GETCSR: /* return control register */ + *(unsigned char *)data = inb(iobase + CTRL_STAT); + break; + + case ISDN_SETCSR: /* set status register */ + outb((iobase + CTRL_STAT), *(unsigned char *)data); + break; + + /* hardware layer - dual ported memory */ + + case ISDN_GETBLK: /* get block from dual port mem */ + readblock(iobase, (*(struct record *)data).addr, + (*(struct record *)data).data, + (*(struct record *)data).length); + break; + + case ISDN_SETBLK: /* write block to dual port mem */ + writeblock(iobase, (*(struct record *)data).data, + (*(struct record *)data).addr, + (*(struct record *)data).length); + break; + + default: + error = ENOTTY; + break; + } + return(error); +} + +/*---------------------------------------------------------------------------* + * tinapoll - device driver poll routine + *---------------------------------------------------------------------------*/ +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +static int +tinapoll (dev_t dev, int events, struct proc *p) +{ + return (ENODEV); +} +#endif + +/*===========================================================================* + * tina dual ported memory access + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * setup address for accessing tina-dd ram + *---------------------------------------------------------------------------*/ +static void +setupaddr(unsigned short iobase, unsigned int addr) +{ + outb((iobase + ADDR_CNTL), (unsigned char) addr & 0xff); + outb((iobase + ADDR_CNTM), (unsigned char) ((addr >> 8) & 0xff)); + outb((iobase + ADDR_CNTH), (unsigned char) ((addr >> 16) & 0xff)); +} + + +/*---------------------------------------------------------------------------* + * read block from tina-dd dual ported ram + *---------------------------------------------------------------------------*/ +static void +readblock(unsigned short iobase, unsigned int addr, + unsigned char *dst, unsigned int len) +{ + setupaddr(iobase, addr); /* setup start address */ + + while(len--) /* tina-dd mem -> pc mem */ + *dst++ = inb(iobase + DATA_LOW_INC); +} + +/*---------------------------------------------------------------------------* + * write block to tina-dd dual ported ram + *---------------------------------------------------------------------------*/ +static void +writeblock(unsigned short iobase, unsigned char *src, + unsigned long addr, int len) +{ + setupaddr(iobase, addr); /* setup start address */ + + while(len--) /* pc mem -> tina-dd mem */ + outb((iobase + DATA_LOW_INC), *src++); +} + +#endif /* NTINA > 0 */ diff --git a/sys/i4b/tina-dd/i4b_tina_ioctl.h b/sys/i4b/tina-dd/i4b_tina_ioctl.h new file mode 100644 index 000000000000..d51f16d731a4 --- /dev/null +++ b/sys/i4b/tina-dd/i4b_tina_ioctl.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1994, 1998 Hellmuth Michaelis. All rights reserved. + * + * Based on code written by Stollmann GmbH, Hamburg. Many thanks to + * Christian Luehrs and Manfred Jung for docs, sources and answers! + * + * 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_tina_ioctl.h - i4b Stollman Tina-dd ioctl header file + * --------------------------------------------------------- + * + * $Id: i4b_tina_ioctl.h,v 1.2 1998/12/05 18:06:20 hm Exp $ + * + * last edit-date: [Sat Dec 5 18:41:51 1998] + * + *---------------------------------------------------------------------------*/ + +#ifndef _I4B_TINA_IOCTL_H_ +#define _I4B_TINA_IOCTL_H_ + +#define TINA_IOSIZE 8 /* 8 byte wide iospace occupied */ + +/*---------------------------------------------------------------------------* + * register offsets in i/o address space + *---------------------------------------------------------------------------*/ + +#define CTRL_STAT 0 /* control & status */ + +#define ADDR_CNTL 1 /* address pointer low */ +#define ADDR_CNTM 2 /* address pointer mid */ +#define ADDR_CNTH 3 /* address pointer high */ + +#define DATA_LOW 4 /* data register low */ +#define DATA_HIGH 5 /* data register high */ + +#define DATA_LOW_INC 6 /* data register low, post inc */ +#define DATA_HIGH_INC 7 /* data register high, post inc */ + +/*---------------------------------------------------------------------------* + * status register (CTRL_STAT read access) + *---------------------------------------------------------------------------*/ + +#define CR_INTC 0x80 /* irq FROM tina-dd TO pc active */ +#define CR_INTP 0x40 /* irq FROM pc TO tina-dd active */ +#define CR_INTPA 0x20 /* irq FROM pc TO tina-dd active */ +#define CR_NMI 0x10 /* nmi FROM PC TO tina-dd active */ +#define CR_FLASHLD 0x08 /* read of the FLASHLD-bit (n/c) */ +#define CR_S2C 0x04 /* info bit */ +#define CR_S1C 0x02 /* info bit */ +#define CR_S0C 0x01 /* info bit */ + +/*---------------------------------------------------------------------------* + * control register (CTRL_STAT write access) + *---------------------------------------------------------------------------*/ + +#define CR_CLR_INTC 0x80 /* clear irq on tina-dd */ +#define CR_SET_INTP 0x40 /* trigger irq on tina-dd */ +#define CR_RESET 0x20 /* reset tina-dd */ +#define CR_SET_NMI 0x10 /* trigger nmi on tina-dd */ +#define CR_SET_FLASHLD 0x08 /* activates pin FLASHLD (n/c) */ +#define CR_S2P 0x04 /* info bit (not readable !) */ +#define CR_S1P 0x02 /* info bit (not readable !) */ +#define CR_S0P 0x01 /* info bit (not readable !) */ + +/*---------------------------------------------------------------------------* + * misc definitions in dual-ported mem on board of tina-dd + *---------------------------------------------------------------------------*/ + +#define FW_SYSCB 0x200 /* address of FW SYSCB / MJ 300392 */ +#define FW_SINFO_NAME 0x220 /* address of general info label */ + +#define FW_HW_TYPE 0x224 /* address of hardware type byte: */ +#define FW_HW_UNDEF 0x00 /* undefined .. */ +#define FW_HW_TINA_DD 0x10 /* TINA-dd */ +#define FW_HW_TINA_DS 0x20 /* TINA-ds (B channel/ser ?) */ +#define FW_HW_TINA_D 0x30 /* TINA-d (one B channel ?) */ +#define FW_HW_TINA_DDM 0x40 /* TINA-dd with fax module */ +#define FW_HW_TINA_DDS 0x50 /* TINA-dd with fax/voice module */ +#define FW_HW_SICCE 0x80 /* X.25 board */ +#define FW_HW_ASIC 0x01 /* ASIC version bit */ + +#define FW_STAT 0x228 /* address of firmware status byte */ +#define FW_READY 0x20 /* firmware ready bit */ +#define FW_BOOTPRM_RDY 0x02 /* boot PROM ready */ +#define FW_UNDEF_0 0x00 /* undefined */ +#define FW_UNDEF_1 0xFF /* undefined */ + +#define FW_SINFO_ID "SYSI" /* general info label for FW > 2.13*/ +#define FW_SINFO_ID_LEN 4 + +#define FW_ADDR_PROFPTR 0x260 /* addr of ptr to board profile */ + +/*===========================================================================* + * Layer 0 - Hardware layer + *===========================================================================*/ + +/* control and status register access */ + +#define ISDN_GETCSR _IOR('I', 1, unsigned char) /* get csr */ +#define ISDN_SETCSR _IOW('I', 2, unsigned char) /* set csr */ + +/* dual ported ram access */ + +#define ISDN_GETBLK _IOWR('I', 3, struct record) /* get dpr record */ +#define ISDN_SETBLK _IOW('I', 4, struct record) /* set dpr record */ + +/*---------------------------------------------------------------------------* + * record structure for dual ported ram block rd/wr + *---------------------------------------------------------------------------*/ +struct record { + unsigned int length; /* length of data block */ + unsigned int addr; /* address of mem on tina-dd board */ + unsigned char *data; /* pointer to the datablock itself */ +}; + +#endif /* _I4B_TINA_IOCTL_H_ */ |
