Index: head/sys/i4b/driver/i4b_isppp.c =================================================================== --- head/sys/i4b/driver/i4b_isppp.c (revision 67972) +++ head/sys/i4b/driver/i4b_isppp.c (revision 67973) @@ -1,825 +1,824 @@ /* * Copyright (c) 1997 Joerg Wunsch. All rights reserved. * * Copyright (c) 1997, 2000 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.44 2000/08/31 07:07:26 hm Exp $ * * $FreeBSD$ * * last edit-date: [Thu Aug 31 09:02:27 2000] * *---------------------------------------------------------------------------*/ #ifndef __NetBSD__ #define USE_ISPPP #endif #include "i4bisppp.h" #ifndef USE_ISPPP #ifdef __FreeBSD__ #include "sppp.h" #endif #ifndef __NetBSD__ #if NI4BISPPP == 0 # error "You need to define `pseudo-device sppp ' with options ISPPP" #endif #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(__OpenBSD__) #ifndef USE_ISPPP #include #else #include #endif /* USE_ISPPP */ #else #include #endif #if defined(__FreeBSD_version) && __FreeBSD_version >= 400008 #include "bpf.h" #else #include "bpfilter.h" #endif #if NBPFILTER > 0 || NBPF > 0 #include #include #endif #ifdef __FreeBSD__ #include -#include #include #else #include #include #include #endif #include #include #include #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(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); time_t i4bisppp_idletime(int unit); /* 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() #endif { struct i4bisppp_softc *sc = i4bisppp_softc; int i; #ifndef HACK_NO_PSEUDO_ATTACH_MSG #ifdef SPPP_VJ printf("i4bisppp: %d ISDN SyncPPP device(s) attached (VJ header compression)\n", NI4BISPPP); #else printf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", NI4BISPPP); #endif #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; #ifdef __NetBSD__ sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; #else sc->sc_if.if_flags = IFF_SIMPLEX | IFF_POINTOPOINT; #endif 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; #ifndef USE_ISPPP sppp_attach(&sc->sc_if); #else isppp_attach(&sc->sc_if); #endif #if defined(__FreeBSD_version) && ((__FreeBSD_version >= 500009) || (410000 <= __FreeBSD_version && __FreeBSD_version < 500000)) /* do not call bpfattach in ether_ifattach */ ether_ifattach(&sc->sc_if, 0); #else if_attach(&sc->sc_if); #endif #if NBPFILTER > 0 || NBPF > 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; #ifndef USE_ISPPP error = sppp_ioctl(&sc->sc_if, cmd, data); #else error = isppp_ioctl(&sc->sc_if, cmd, data); #endif 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); #ifndef USE_ISPPP if (sppp_isempty(ifp)) #else if (isppp_isempty(ifp)) #endif return; if(sc->sc_state != ST_CONNECTED) return; /* * s = splimp(); * ifp->if_flags |= IFF_OACTIVE; // - need to clear this somewhere * splx(s); */ #ifndef USE_ISPPP while ((m = sppp_dequeue(&sc->sc_if)) != NULL) #else while ((m = isppp_dequeue(&sc->sc_if)) != NULL) #endif { #if NBPFILTER > 0 || NBPF > 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 || NBPF > 0 */ microtime(&ifp->if_lastchange); if(IF_QFULL(isdn_linktab[unit]->tx_queue)) { NDBGL4(L4_ISPDBG, "isp%d, tx queue full!", unit); m_freem(m); } else { IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m); #if 0 sc->sc_if.if_obytes += m->m_pkthdr.len; #endif 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 */ #ifndef __NetBSD__ sp->pp_last_sent = sp->pp_last_recv = SECOND; #endif 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) { NDBGL4(L4_ISPDBG, "isp%d, channel%d not active!", unit, cd->channelid); 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, cause_t cause) { struct i4bisppp_softc *sc = &i4bisppp_softc[unit]; NDBGL4(L4_ISPDBG, "isp%d: status=%d, cause=%d", unit, status, cause); if(status != DSTAT_NONE) { struct mbuf *m; NDBGL4(L4_ISPDBG, "isp%d: clearing queues", unit); #ifndef USE_ISPPP if(!(sppp_isempty(&sc->sc_if))) #else if(!(isppp_isempty(&sc->sc_if))) #endif { #ifndef USE_ISPPP while((m = sppp_dequeue(&sc->sc_if)) != NULL) #else while((m = isppp_dequeue(&sc->sc_if)) != NULL) #endif m_freem(m); } } } /*---------------------------------------------------------------------------* * 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++; #if 0 sc->sc_if.if_ibytes += m->m_pkthdr.len; #endif #if I4BISPPPACCT sc->sc_inb += m->m_pkthdr.len; #endif #ifdef I4BISPPPDEBUG printf("i4bisppp_rx_data_ready: received packet!\n"); #endif #if NBPFILTER > 0 || NBPF > 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 || NBPF > 0 */ s = splimp(); #ifndef USE_ISPPP sppp_input(&sc->sc_if, m); #else isppp_input(&sc->sc_if, m); #endif 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 should be used instead of last_active_time to implement * an activity timeout mechanism. * * Sending back the time difference unneccessarily complicates the * idletime checks in i4b_l4.c. Return the largest time instead. * That way the code in i4b_l4.c needs only minimal changes. *---------------------------------------------------------------------------*/ time_t i4bisppp_idletime(int unit) { #ifdef __NetBSD__ return(i4bisppp_softc[unit].sc_cdp->last_active_time); #else struct sppp *sp; sp = (struct sppp *) &i4bisppp_softc[unit]; return((sp->pp_last_recv < sp->pp_last_sent) ? sp->pp_last_sent : sp->pp_last_recv); #endif } /*---------------------------------------------------------------------------* * 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; } /*===========================================================================*/ Index: head/sys/i4b/driver/i4b_tel.c =================================================================== --- head/sys/i4b/driver/i4b_tel.c (revision 67972) +++ head/sys/i4b/driver/i4b_tel.c (revision 67973) @@ -1,1898 +1,1897 @@ /* * Copyright (c) 1997, 2000 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.51 2000/10/06 08:37:43 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon Oct 2 10:06:32 2000] * *---------------------------------------------------------------------------*/ #include "i4btel.h" #if NI4BTEL > 0 #undef I4BTELDEBUG #include #include #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) #include #include #else #include #include #endif #include #include #include #include #include #include #include #ifdef __FreeBSD__ #if defined(__FreeBSD__) && __FreeBSD__ == 3 #include "opt_devfs.h" #endif #ifdef DEVFS #include #endif #endif /* __FreeBSD__ */ #ifdef __bsdi__ #include #endif #ifdef __FreeBSD__ #include #include #include #else #include #include #include #endif #include #include #include #include /* minor number: lower 6 bits = unit number */ -#include #define UNITBITS 6 #define UNITMASK 0x3f #define UNIT(n) (minor(n) & UNITMASK) /* minor number: upper 2 bits = function number */ #define FUNCMASK 0x03 #define FUNC(n) (((minor(n)) >> UNITBITS) & FUNCMASK) #define FUNCTEL 0 /* 0 = normal i4btel device */ #define FUNCDIAL 1 /* 1 = i4bteld dialout device */ #define NOFUNCS 2 /* number of device classes */ typedef struct { /* used only in func = FUNCTEL */ drvr_link_t drvr_linktab; /* driver linktab */ isdn_link_t *isdn_linktab; /* isdn linktab */ int audiofmt; /* audio format conversion */ u_char *rcvttab; /* conversion table on read */ u_char *wcvttab; /* conversion table on write */ call_desc_t *cdp; /* call descriptor pointer */ /* used only in func = FUNCDIAL */ char result; /* result code for dial dev */ /* used in func = FUNCDIAL and func = FUNCTEL*/ 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 */ #define ST_TONE 0x10 /* tone generator */ struct selinfo selp; /* select / poll */ #if defined(__FreeBSD__) && __FreeBSD__ == 3 #ifdef DEVFS void *devfs_token; /* token for DEVFS */ #endif #endif struct i4b_tel_tones tones; int toneidx; int toneomega; int tonefreq; } tel_sc_t; static tel_sc_t tel_sc[NI4BTEL][NOFUNCS]; /* 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 void tel_tone(tel_sc_t *sc); /* audio format conversion tables */ static unsigned char a2u_tab[]; static unsigned char u2a_tab[]; static unsigned char bitreverse[]; static u_char sinetab[]; #ifndef __FreeBSD__ #define PDEVSTATIC /* - not static - */ PDEVSTATIC void i4btelattach __P((void)); #ifdef __bsdi__ PDEVSTATIC int i4btelioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)); #else PDEVSTATIC int i4btelioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); #endif 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)); #ifdef OS_USES_POLL int i4btelpoll __P((dev_t dev, int events, struct proc *p)); #else int i4btelsel __P((dev_t dev, int rw, struct proc *p)); #endif #endif /* __FreeBSD__ */ #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; #ifdef OS_USES_POLL PDEVSTATIC d_poll_t i4btelpoll; #define POLLFIELD i4btelpoll #else PDEVSTATIC d_select_t i4btelsel; #define POLLFIELD i4btelsel #endif #define CDEV_MAJOR 56 #if defined(__FreeBSD__) && __FreeBSD__ >= 4 static struct cdevsw i4btel_cdevsw = { /* open */ i4btelopen, /* close */ i4btelclose, /* read */ i4btelread, /* write */ i4btelwrite, /* ioctl */ i4btelioctl, /* poll */ POLLFIELD, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "i4btel", /* maj */ CDEV_MAJOR, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, /* bmaj */ -1 }; #else static struct cdevsw i4btel_cdevsw = { i4btelopen, i4btelclose, i4btelread, i4btelwrite, i4btelioctl, nostop, noreset, nodevtotty, POLLFIELD, 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) { #if defined(__FreeBSD__) && __FreeBSD__ >= 4 cdevsw_add(&i4btel_cdevsw); #else dev_t dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev, &i4btel_cdevsw, NULL); #endif } SYSINIT(i4bteldev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btelinit, NULL); #endif /* BSD > 199306 && defined(__FreeBSD__) */ #ifdef __bsdi__ int i4btelsel(dev_t dev, int rw, struct proc *p); int i4btelmatch(struct device *parent, struct cfdata *cf, void *aux); void dummy_i4btelattach(struct device*, struct device *, void *); #define CDEV_MAJOR 62 static struct cfdriver i4btelcd = { NULL, "i4btel", i4btelmatch, dummy_i4btelattach, DV_DULL, sizeof(struct cfdriver) }; struct devsw i4btelsw = { &i4btelcd, i4btelopen, i4btelclose, i4btelread, i4btelwrite, i4btelioctl, i4btelsel, nommap, nostrat, nodump, nopsize, 0, nostop }; int i4btelmatch(struct device *parent, struct cfdata *cf, void *aux) { NDBGL4(L4_TELDBG, "aux=0x%x", aux); return 1; } void dummy_i4btelattach(struct device *parent, struct device *self, void *aux) { NDBGL4(L4_TELDBG, "aux=0x%x", aux); } #endif /* __bsdi__ */ /*---------------------------------------------------------------------------* * interface attach routine *---------------------------------------------------------------------------*/ PDEVSTATIC void #ifdef __FreeBSD__ i4btelattach(void *dummy) #else i4btelattach() #endif { int i, j; #ifndef HACK_NO_PSEUDO_ATTACH_MSG printf("i4btel: %d ISDN telephony interface device(s) attached\n", NI4BTEL); #endif for(i=0; i < NI4BTEL; i++) { for(j=0; j < NOFUNCS; j++) { tel_sc[i][j].devstate = ST_IDLE; tel_sc[i][j].audiofmt = CVT_NONE; tel_sc[i][j].rcvttab = 0; tel_sc[i][j].wcvttab = 0; tel_sc[i][j].result = 0; #if defined(__FreeBSD__) #if __FreeBSD__ == 3 #ifdef DEVFS /* XXX */ tel_sc[i][j].devfs_token = devfs_add_devswf(&i4btel_cdevsw, i, DV_CHR, UID_ROOT, GID_WHEEL, 0600, "i4btel%d", i); #endif #else switch(j) { case FUNCTEL: /* normal i4btel device */ make_dev(&i4btel_cdevsw, i, UID_ROOT, GID_WHEEL, 0600, "i4btel%d", i); break; case FUNCDIAL: /* i4bteld dialout device */ make_dev(&i4btel_cdevsw, i+(1<= NI4BTEL) return(ENXIO); sc = &tel_sc[unit][func]; if(sc->devstate & ST_ISOPEN) return(EBUSY); sc->devstate |= ST_ISOPEN; if(func == FUNCDIAL) { sc->result = 0; } return(0); } /*---------------------------------------------------------------------------* * close tel device *---------------------------------------------------------------------------*/ PDEVSTATIC int i4btelclose(dev_t dev, int flag, int fmt, struct proc *p) { int unit = UNIT(dev); int func = FUNC(dev); tel_sc_t *sc; int error = 0; int x; if(unit > NI4BTEL) return(ENXIO); sc = &tel_sc[unit][func]; x = splimp(); sc->devstate &= ~ST_TONE; if((func == FUNCTEL) && (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; splx(x); wakeup((caddr_t) &sc->tones); 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) #elif defined(__bsdi__) 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 unit = UNIT(dev); int func = FUNC(dev); int error = 0; struct mbuf *m; int s; tel_sc_t *sc = &tel_sc[unit][func]; if(func == FUNCTEL) { switch(cmd) { case I4B_TEL_GETAUDIOFMT: *(int *)data = sc->audiofmt; break; case I4B_TEL_SETAUDIOFMT: switch (*(int *)data) { case CVT_NONE: sc->rcvttab = 0; sc->wcvttab = 0; break; case CVT_ALAW2ULAW: /* ISDN: a-law */ /* user: u-law */ sc->rcvttab = a2u_tab; sc->wcvttab = u2a_tab; break; case CVT_ULAW2ALAW: /* ISDN: u-law */ /* user: a-law */ sc->rcvttab = u2a_tab; sc->wcvttab = a2u_tab; break; default: error = ENODEV; break; } if(error == 0) 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; case I4B_TEL_VR_REQ: { msg_vr_req_t *mvr; mvr = (msg_vr_req_t *)data; mvr->version = VERSION; mvr->release = REL; mvr->step = STEP; break; } case I4B_TEL_TONES: { struct i4b_tel_tones *tt; tt = (struct i4b_tel_tones *)data; s = splimp(); while ((sc->devstate & ST_TONE) && sc->tones.duration[sc->toneidx] != 0) { if((error = tsleep((caddr_t) &sc->tones, TTIPRI | PCATCH, "rtone", 0 )) != 0) { splx(s); return(error); } } if(!(sc->devstate & ST_ISOPEN)) { splx(s); return (EIO); } if(!(sc->devstate & ST_CONNECTED)) { splx(s); return (EIO); } sc->tones = *tt; sc->toneidx = 0; sc->tonefreq = tt->frequency[0]; sc->devstate |= ST_TONE; splx(s); tel_tone(sc); break; } default: error = ENOTTY; break; } } else if(func == FUNCDIAL) { switch(cmd) { default: error = ENOTTY; break; } } return(error); } /*---------------------------------------------------------------------------* * read from tel device *---------------------------------------------------------------------------*/ PDEVSTATIC int i4btelread(dev_t dev, struct uio *uio, int ioflag) { int unit = UNIT(dev); int func = FUNC(dev); struct mbuf *m; int s; int error = 0; tel_sc_t *sc = &tel_sc[unit][func]; if(!(sc->devstate & ST_ISOPEN)) return(EIO); if(func == FUNCTEL) { s = splimp(); while(IF_QEMPTY(sc->isdn_linktab->rx_queue) && (sc->devstate & ST_ISOPEN) && (sc->devstate & ST_CONNECTED)) { sc->devstate |= ST_RDWAITDATA; NDBGL4(L4_TELDBG, "i4btel%d, queue empty!", unit); if((error = tsleep((caddr_t) &sc->isdn_linktab->rx_queue, TTIPRI | PCATCH, "rtel", 0 )) != 0) { sc->devstate &= ~ST_RDWAITDATA; splx(s); return(error); } } if(!(sc->devstate & ST_ISOPEN)) { splx(s); return(EIO); } if(!(sc->devstate & ST_CONNECTED)) { splx(s); return(EIO); } IF_DEQUEUE(sc->isdn_linktab->rx_queue, m); if(m && m->m_len > 0) { register int i; for(i = 0; i < m->m_len; i++) { /* always reverse bit order from line */ mtod(m,u_char *)[i] = bitreverse[mtod(m,u_char *)[i]]; /* convert if necessary */ if(sc->rcvttab) mtod(m,u_char *)[i] = sc->rcvttab[mtod(m,u_char *)[i]]; } error = uiomove(m->m_data, m->m_len, uio); NDBGL4(L4_TELDBG, "i4btel%d, mbuf (%d bytes), uiomove %d!", unit, m->m_len, error); } else { NDBGL4(L4_TELDBG, "i4btel%d, empty mbuf from queue!", unit); error = EIO; } if(m) i4b_Bfreembuf(m); splx(s); } else if(func == FUNCDIAL) { s = splimp(); while((sc->result == 0) && (sc->devstate & ST_ISOPEN)) { sc->devstate |= ST_RDWAITDATA; if((error = tsleep((caddr_t) &sc->result, TTIPRI | PCATCH, "rtel1", 0 )) != 0) { sc->devstate &= ~ST_RDWAITDATA; splx(s); return(error); } } if(!(sc->devstate & ST_ISOPEN)) { splx(s); return(EIO); } if(sc->result != 0) { error = uiomove(&sc->result, 1, uio); sc->result = 0; } else { error = EIO; } splx(s); } return(error); } /*---------------------------------------------------------------------------* * write to tel device *---------------------------------------------------------------------------*/ PDEVSTATIC int i4btelwrite(dev_t dev, struct uio * uio, int ioflag) { int unit = UNIT(dev); int func = FUNC(dev); struct mbuf *m; int s; int error = 0; tel_sc_t *sc = &tel_sc[unit][func]; if(!(sc->devstate & ST_ISOPEN)) { return(EIO); } if(func == FUNCTEL) { s = splimp(); if(!(sc->devstate & ST_CONNECTED)) { splx(s); return(EIO); } sc->devstate &= ~ST_TONE; 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; splx(s); return(error); } } if(!(sc->devstate & ST_ISOPEN)) { splx(s); return(EIO); } if(!(sc->devstate & ST_CONNECTED)) { splx(s); return(EIO); } if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL) { register int i; m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid); error = uiomove(m->m_data, m->m_len, uio); for(i = 0; i < m->m_len; i++) { /* convert if necessary */ if(sc->wcvttab) mtod(m,u_char *)[i] = sc->wcvttab[mtod(m,u_char *)[i]]; /* always reverse bitorder to line */ mtod(m,u_char *)[i] = bitreverse[mtod(m,u_char *)[i]]; } if(IF_QFULL(sc->isdn_linktab->tx_queue)) { m_freem(m); } else { IF_ENQUEUE(sc->isdn_linktab->tx_queue, m); } (*sc->isdn_linktab->bch_tx_start)(sc->isdn_linktab->unit, sc->isdn_linktab->channel); } splx(s); } else if(func == FUNCDIAL) { #define CMDBUFSIZ 80 char cmdbuf[CMDBUFSIZ]; int len = min(CMDBUFSIZ-1, uio->uio_resid); error = uiomove(cmdbuf, len, uio); if(cmdbuf[0] == CMD_DIAL) { i4b_l4_dialoutnumber(BDRV_TEL, unit, len-1, &cmdbuf[1]); } else if(cmdbuf[0] == CMD_HUP) { i4b_l4_drvrdisc(BDRV_TEL, unit); } } else { error = EIO; } return(error); } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ #define NTONESAMP 32 static void tel_tone(tel_sc_t *sc) { struct mbuf *m; u_char *p; int i; if((m = i4b_Bgetmbuf(NTONESAMP)) == NULL) { printf("no mbuf in tel_tone\n"); return; } p = m->m_data; m->m_len = 0; for (i = 0; i < NTONESAMP && (sc->devstate & ST_TONE); i++) { if (sc->tones.duration[sc->toneidx] > 0) { if (--sc->tones.duration[sc->toneidx] == 0) { sc->toneidx++; if (sc->toneidx == I4B_TEL_MAXTONES) { sc->devstate &= ~ST_TONE; sc->toneomega = 0; sc->tonefreq = 0; } else if (sc->tones.frequency[sc->toneidx] == 0 && sc->tones.duration[sc->toneidx] == 0) { sc->devstate &= ~ST_TONE; sc->toneomega = 0; sc->tonefreq = 0; } else { sc->tonefreq = sc->tones.frequency[sc->toneidx]; } if (sc->tones.duration[sc->toneidx] == 0) { wakeup((caddr_t) &sc->tones); } } } sc->toneomega += sc->tonefreq; if (sc->toneomega >= 8000) sc->toneomega -= 8000; *p++ = bitreverse[sinetab[sc->toneomega]]; m->m_len++; } IF_ENQUEUE(sc->isdn_linktab->tx_queue, m); (*sc->isdn_linktab->bch_tx_start)(sc->isdn_linktab->unit, sc->isdn_linktab->channel); } #ifdef OS_USES_POLL /*---------------------------------------------------------------------------* * device driver poll *---------------------------------------------------------------------------*/ PDEVSTATIC int i4btelpoll(dev_t dev, int events, struct proc *p) { int revents = 0; /* Events we found */ int s; int unit = UNIT(dev); int func = FUNC(dev); tel_sc_t *sc = &tel_sc[unit][func]; s = splhigh(); if(!(sc->devstate & ST_ISOPEN)) { NDBGL4(L4_TELDBG, "i4btel%d, !ST_ISOPEN", unit); splx(s); return(0); } if(func == FUNCTEL) { /* * Writes are OK if we are connected and the * transmit queue can take them */ if((events & (POLLOUT|POLLWRNORM)) && (sc->devstate & ST_CONNECTED) && (sc->isdn_linktab != NULL) && (!IF_QFULL(sc->isdn_linktab->tx_queue))) { NDBGL4(L4_TELDBG, "i4btel%d, POLLOUT", unit); revents |= (events & (POLLOUT|POLLWRNORM)); } /* ... while reads are OK if we have any data */ if((events & (POLLIN|POLLRDNORM)) && (sc->devstate & ST_CONNECTED) && (sc->isdn_linktab != NULL) && (!IF_QEMPTY(sc->isdn_linktab->rx_queue))) { NDBGL4(L4_TELDBG, "i4btel%d, POLLIN", unit); revents |= (events & (POLLIN|POLLRDNORM)); } if(revents == 0) { NDBGL4(L4_TELDBG, "i4btel%d, selrecord", unit); selrecord(p, &sc->selp); } } else if(func == FUNCDIAL) { if(events & (POLLOUT|POLLWRNORM)) { NDBGL4(L4_TELDBG, "i4bteld%d, POLLOUT", unit); revents |= (events & (POLLOUT|POLLWRNORM)); } if(events & (POLLIN|POLLRDNORM)) { NDBGL4(L4_TELDBG, "i4bteld%d, POLLIN, result = %d", unit, sc->result); if(sc->result != 0) revents |= (events & (POLLIN|POLLRDNORM)); } if(revents == 0) { NDBGL4(L4_TELDBG, "i4bteld%d, selrecord", unit); selrecord(p, &sc->selp); } } splx(s); return(revents); } #else /* OS_USES_POLL */ /*---------------------------------------------------------------------------* * device driver select *---------------------------------------------------------------------------*/ PDEVSTATIC int i4btelsel(dev_t dev, int rw, struct proc *p) { int s; int unit = UNIT(dev); int func = FUNC(dev); tel_sc_t *sc = &tel_sc[unit][func]; s = splhigh(); if (!(sc->devstate & ST_ISOPEN)) { NDBGL4(L4_TELDBG, "i4btel%d, !ST_ISOPEN", unit); splx(s); return(0); } if (func == FUNCTEL) { /* Don't even bother if we're not connected */ if (!(sc->devstate & ST_CONNECTED) || sc->isdn_linktab == NULL) { splx(s); return 0; } if (rw == FREAD) { if (!IF_QEMPTY(sc->isdn_linktab->rx_queue)) { NDBGL4(L4_TELDBG, "i4btel%d, FREAD", unit); splx(s); return 1; } } else if (rw == FWRITE) { if (!IF_QFULL(sc->isdn_linktab->tx_queue)) { NDBGL4(L4_TELDBG, "i4btel%d, FWRITE", unit); splx(s); return 1; } } } else if (func == FUNCDIAL) { if (rw == FWRITE) { NDBGL4(L4_TELDBG, "i4bteld%d, FWRITE", unit); splx(s); return 1; } if (rw == FREAD) { NDBGL4(L4_TELDBG, "i4bteld%d, FREAD, result = %d", unit, sc->result); if (sc->result != 0) { splx(s); return 1; } } } NDBGL4(L4_TELDBG, "i4bteld%d, selrecord", unit); selrecord(p, &sc->selp); splx(s); return 0; } #endif /* OS_USES_POLL */ /*===========================================================================* * 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][FUNCTEL]; /* audio device */ sc->cdp = (call_desc_t *)cdp; sc->devstate |= ST_CONNECTED; /* dialer device */ sc = &tel_sc[unit][FUNCDIAL]; if(sc->devstate == ST_ISOPEN) { sc->result = RSP_CONN; if(sc->devstate & ST_RDWAITDATA) { sc->devstate &= ~ST_RDWAITDATA; wakeup((caddr_t) &sc->result); } selwakeup(&sc->selp); } } /*---------------------------------------------------------------------------* * 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][FUNCTEL]; /* audio device */ 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); } /* dialer device */ sc = &tel_sc[unit][FUNCDIAL]; if(sc->devstate & ST_ISOPEN) { sc->result = RSP_HUP; if(sc->devstate & ST_RDWAITDATA) { sc->devstate &= ~ST_RDWAITDATA; wakeup((caddr_t) &sc->result); } selwakeup(&sc->selp); if (sc->devstate & ST_TONE) { sc->devstate &= ~ST_TONE; wakeup((caddr_t) &sc->tones); } } } /*---------------------------------------------------------------------------* * feedback from daemon in case of dial problems *---------------------------------------------------------------------------*/ static void tel_dialresponse(int unit, int status, cause_t cause) { tel_sc_t *sc = &tel_sc[unit][FUNCDIAL]; NDBGL4(L4_TELDBG, "i4btel%d, status=%d, cause=0x%4x", unit, status, cause); if((sc->devstate == ST_ISOPEN) && status) { sc->result = RSP_NOA; if(sc->devstate & ST_RDWAITDATA) { sc->devstate &= ~ST_RDWAITDATA; wakeup((caddr_t) &sc->result); } selwakeup(&sc->selp); } } /*---------------------------------------------------------------------------* * 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][FUNCTEL]; if(sc->devstate & ST_RDWAITDATA) { sc->devstate &= ~ST_RDWAITDATA; wakeup((caddr_t) &sc->isdn_linktab->rx_queue); } selwakeup(&sc->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 tel_tx_queue_empty(int unit) { tel_sc_t *sc = &tel_sc[unit][FUNCTEL]; if(sc->devstate & ST_WRWAITEMPTY) { sc->devstate &= ~ST_WRWAITEMPTY; wakeup((caddr_t) &sc->isdn_linktab->tx_queue); } if(sc->devstate & ST_TONE) { tel_tone(sc); } else { selwakeup(&sc->selp); } } /*---------------------------------------------------------------------------* * 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) { if(tel_sc[unit][FUNCTEL].cdp) tel_sc[unit][FUNCTEL].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][FUNCTEL]; 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][FUNCTEL]; sc->isdn_linktab = ilt; } /*---------------------------------------------------------------------------* * initialize this drivers linktab *---------------------------------------------------------------------------*/ static void tel_init_linktab(int unit) { tel_sc_t *sc = &tel_sc[unit][FUNCTEL]; 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 (produced by running g711conv) *===========================================================================*/ /*---------------------------------------------------------------------------* * A-law to u-law conversion *---------------------------------------------------------------------------*/ static unsigned char a2u_tab[256] = { /* 00 */ 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, /* 08 */ 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, /* 10 */ 0x39, 0x3a, 0x37, 0x38, 0x3d, 0x3e, 0x3b, 0x3c, /* 18 */ 0x31, 0x32, 0x30, 0x30, 0x35, 0x36, 0x33, 0x34, /* 20 */ 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, /* 28 */ 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, /* 30 */ 0x1a, 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, /* 38 */ 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, /* 40 */ 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, /* 48 */ 0x5d, 0x5d, 0x5c, 0x5c, 0x5f, 0x5f, 0x5e, 0x5e, /* 50 */ 0x74, 0x76, 0x70, 0x72, 0x7c, 0x7e, 0x78, 0x7a, /* 58 */ 0x6a, 0x6b, 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, /* 60 */ 0x48, 0x49, 0x46, 0x47, 0x4c, 0x4d, 0x4a, 0x4b, /* 68 */ 0x40, 0x41, 0x3f, 0x3f, 0x44, 0x45, 0x42, 0x43, /* 70 */ 0x56, 0x57, 0x54, 0x55, 0x5a, 0x5b, 0x58, 0x59, /* 78 */ 0x4f, 0x4f, 0x4e, 0x4e, 0x52, 0x53, 0x50, 0x51, /* 80 */ 0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad, /* 88 */ 0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5, /* 90 */ 0xb9, 0xba, 0xb7, 0xb8, 0xbd, 0xbe, 0xbb, 0xbc, /* 98 */ 0xb1, 0xb2, 0xb0, 0xb0, 0xb5, 0xb6, 0xb3, 0xb4, /* a0 */ 0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, /* a8 */ 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, /* b0 */ 0x9a, 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, /* b8 */ 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, /* c0 */ 0xe2, 0xe3, 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, /* c8 */ 0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde, /* d0 */ 0xf4, 0xf6, 0xf0, 0xf2, 0xfc, 0xfe, 0xf8, 0xfa, /* d8 */ 0xea, 0xeb, 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, /* e0 */ 0xc8, 0xc9, 0xc6, 0xc7, 0xcc, 0xcd, 0xca, 0xcb, /* e8 */ 0xc0, 0xc1, 0xbf, 0xbf, 0xc4, 0xc5, 0xc2, 0xc3, /* f0 */ 0xd6, 0xd7, 0xd4, 0xd5, 0xda, 0xdb, 0xd8, 0xd9, /* f8 */ 0xcf, 0xcf, 0xce, 0xce, 0xd2, 0xd3, 0xd0, 0xd1 }; /*---------------------------------------------------------------------------* * u-law to A-law conversion *---------------------------------------------------------------------------*/ static unsigned char u2a_tab[256] = { /* 00 */ 0x2a, 0x2b, 0x28, 0x29, 0x2e, 0x2f, 0x2c, 0x2d, /* 08 */ 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25, /* 10 */ 0x3a, 0x3b, 0x38, 0x39, 0x3e, 0x3f, 0x3c, 0x3d, /* 18 */ 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35, /* 20 */ 0x0a, 0x0b, 0x08, 0x09, 0x0e, 0x0f, 0x0c, 0x0d, /* 28 */ 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, /* 30 */ 0x1b, 0x18, 0x19, 0x1e, 0x1f, 0x1c, 0x1d, 0x12, /* 38 */ 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6a, /* 40 */ 0x68, 0x69, 0x6e, 0x6f, 0x6c, 0x6d, 0x62, 0x63, /* 48 */ 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7a, 0x78, /* 50 */ 0x7e, 0x7f, 0x7c, 0x7d, 0x72, 0x73, 0x70, 0x71, /* 58 */ 0x76, 0x77, 0x74, 0x75, 0x4b, 0x49, 0x4f, 0x4d, /* 60 */ 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45, /* 68 */ 0x5a, 0x5b, 0x58, 0x59, 0x5e, 0x5f, 0x5c, 0x5d, /* 70 */ 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, /* 78 */ 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0x55, /* 80 */ 0xaa, 0xab, 0xa8, 0xa9, 0xae, 0xaf, 0xac, 0xad, /* 88 */ 0xa2, 0xa3, 0xa0, 0xa1, 0xa6, 0xa7, 0xa4, 0xa5, /* 90 */ 0xba, 0xbb, 0xb8, 0xb9, 0xbe, 0xbf, 0xbc, 0xbd, /* 98 */ 0xb2, 0xb3, 0xb0, 0xb1, 0xb6, 0xb7, 0xb4, 0xb5, /* a0 */ 0x8a, 0x8b, 0x88, 0x89, 0x8e, 0x8f, 0x8c, 0x8d, /* a8 */ 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, /* b0 */ 0x9b, 0x98, 0x99, 0x9e, 0x9f, 0x9c, 0x9d, 0x92, /* b8 */ 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xea, /* c0 */ 0xe8, 0xe9, 0xee, 0xef, 0xec, 0xed, 0xe2, 0xe3, /* c8 */ 0xe0, 0xe1, 0xe6, 0xe7, 0xe4, 0xe5, 0xfa, 0xf8, /* d0 */ 0xfe, 0xff, 0xfc, 0xfd, 0xf2, 0xf3, 0xf0, 0xf1, /* d8 */ 0xf6, 0xf7, 0xf4, 0xf5, 0xcb, 0xc9, 0xcf, 0xcd, /* e0 */ 0xc2, 0xc3, 0xc0, 0xc1, 0xc6, 0xc7, 0xc4, 0xc5, /* e8 */ 0xda, 0xdb, 0xd8, 0xd9, 0xde, 0xdf, 0xdc, 0xdd, /* f0 */ 0xd2, 0xd2, 0xd3, 0xd3, 0xd0, 0xd0, 0xd1, 0xd1, /* f8 */ 0xd6, 0xd6, 0xd7, 0xd7, 0xd4, 0xd4, 0xd5, 0xd5 }; /*---------------------------------------------------------------------------* * reverse bits in a byte *---------------------------------------------------------------------------*/ static unsigned char bitreverse[256] = { /* 00 */ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, /* 08 */ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, /* 10 */ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, /* 18 */ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, /* 20 */ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, /* 28 */ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, /* 30 */ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, /* 38 */ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, /* 40 */ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, /* 48 */ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, /* 50 */ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, /* 58 */ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, /* 60 */ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, /* 68 */ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, /* 70 */ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, /* 78 */ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, /* 80 */ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, /* 88 */ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, /* 90 */ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, /* 98 */ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, /* a0 */ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, /* a8 */ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, /* b0 */ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, /* b8 */ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, /* c0 */ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, /* c8 */ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, /* d0 */ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, /* d8 */ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, /* e0 */ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, /* e8 */ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, /* f0 */ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, /* f8 */ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; static u_char sinetab[8000] = { 213, 213, 213, 213, 213, 213, 213, 212, 212, 212, 212, 212, 212, 215, 215, 215, 215, 215, 215, 214, 214, 214, 214, 214, 214, 209, 209, 209, 209, 209, 209, 209, 208, 208, 208, 208, 208, 208, 211, 211, 211, 211, 211, 211, 210, 210, 210, 210, 210, 210, 221, 221, 221, 221, 221, 221, 220, 220, 220, 220, 220, 220, 220, 223, 223, 223, 223, 223, 223, 222, 222, 222, 222, 222, 222, 217, 217, 217, 217, 217, 217, 216, 216, 216, 216, 216, 216, 216, 219, 219, 219, 219, 219, 219, 218, 218, 218, 218, 218, 218, 197, 197, 197, 197, 197, 197, 196, 196, 196, 196, 196, 196, 196, 199, 199, 199, 199, 199, 199, 198, 198, 198, 198, 198, 198, 193, 193, 193, 193, 193, 193, 192, 192, 192, 192, 192, 192, 192, 195, 195, 195, 195, 195, 195, 194, 194, 194, 194, 194, 194, 205, 205, 205, 205, 205, 205, 204, 204, 204, 204, 204, 204, 204, 207, 207, 207, 207, 207, 207, 206, 206, 206, 206, 206, 206, 201, 201, 201, 201, 201, 201, 200, 200, 200, 200, 200, 200, 200, 203, 203, 203, 203, 203, 203, 202, 202, 202, 202, 202, 202, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 202, 202, 202, 202, 202, 202, 203, 203, 203, 203, 203, 203, 200, 200, 200, 200, 200, 200, 200, 201, 201, 201, 201, 201, 201, 206, 206, 206, 206, 206, 206, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 204, 204, 204, 205, 205, 205, 205, 205, 205, 194, 194, 194, 194, 194, 194, 195, 195, 195, 195, 195, 195, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, 193, 198, 198, 198, 198, 198, 198, 199, 199, 199, 199, 199, 199, 196, 196, 196, 196, 196, 196, 196, 197, 197, 197, 197, 197, 197, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 216, 216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 222, 222, 222, 222, 222, 222, 223, 223, 223, 223, 223, 223, 220, 220, 220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 208, 208, 208, 208, 208, 208, 209, 209, 209, 209, 209, 209, 209, 214, 214, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 212, 212, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 90, 90, 90, 85, 85, 85, 85, 85, 85, 84, 84, 84, 84, 84, 84, 87, 87, 87, 87, 87, 87, 86, 86, 86, 86, 86, 86, 81, 81, 81, 81, 81, 81, 81, 80, 80, 80, 80, 80, 80, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 93, 93, 93, 93, 93, 93, 93, 92, 92, 92, 92, 92, 92, 95, 95, 95, 95, 95, 95, 94, 94, 94, 94, 94, 94, 89, 89, 89, 89, 89, 89, 88, 88, 88, 88, 88, 88, 88, 91, 91, 91, 91, 91, 91, 90, 90, 90, 90, 90, 90, 69, 69, 69, 69, 69, 69, 68, 68, 68, 68, 68, 68, 68, 71, 71, 71, 71, 71, 71, 70, 70, 70, 70, 70, 70, 65, 65, 65, 65, 65, 65, 64, 64, 64, 64, 64, 64, 64, 67, 67, 67, 67, 67, 67, 66, 66, 66, 66, 66, 66, 77, 77, 77, 77, 77, 77, 76, 76, 76, 76, 76, 76, 76, 79, 79, 79, 79, 79, 79, 78, 78, 78, 78, 78, 78, 73, 73, 73, 73, 73, 73, 73, 72, 72, 72, 72, 72, 72, 75, 75, 75, 75, 75, 75, 74, 74, 74, 74, 74, 74, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 68, 68, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, 92, 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 80, 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 90, 90, 90 }; /*===========================================================================*/ #endif /* NI4BTEL > 0 */ Index: head/sys/i4b/layer1/i4b_l1lib.c =================================================================== --- head/sys/i4b/layer1/i4b_l1lib.c (revision 67972) +++ head/sys/i4b/layer1/i4b_l1lib.c (revision 67973) @@ -1,77 +1,76 @@ /* * Copyright (c) 2000 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_l1lib.c - general useful L1 procedures * ------------------------------------------ * * $Id: i4b_l1lib.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 15:24:21 2000] * *---------------------------------------------------------------------------*/ #include #include -#include #include #include #include #define TEL_IDLE_MIN (BCH_MAX_DATALEN/2) /*---------------------------------------------------------------------------* * telephony silence detection *---------------------------------------------------------------------------*/ int i4b_l1_bchan_tel_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("i4b_l1_bchan_tel_silence: got %d silence bytes in frame\n", j); #endif if(j < (TEL_IDLE_MIN)) return(0); else return(1); } Index: head/sys/i4b/layer1/ifpi/i4b_ifpi_isac.c =================================================================== --- head/sys/i4b/layer1/ifpi/i4b_ifpi_isac.c (revision 67972) +++ head/sys/i4b/layer1/ifpi/i4b_ifpi_isac.c (revision 67973) @@ -1,667 +1,666 @@ /* * Copyright (c) 1997, 2000 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_ifpi_isac.c - i4b Fritz PCI ISAC handler * -------------------------------------------- * * $Id: i4b_ifpi_isac.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 15:22:52 2000] * *---------------------------------------------------------------------------*/ #include "ifpi.h" #include "pci.h" #if (NIFPI > 0) && (NPCI > 0) #include "opt_i4b.h" #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include static u_char ifpi_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); static void ifpi_isac_ind_hdlr(register struct l1_softc *sc, int ind); /*---------------------------------------------------------------------------* * ISAC interrupt service routine *---------------------------------------------------------------------------*/ void ifpi_isac_irq(struct l1_softc *sc, int ista) { register u_char c = 0; NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); if(ista & ISAC_ISTA_EXI) /* extended interrupt */ { c |= ifpi_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); } if(ista & ISAC_ISTA_RME) /* receive message end */ { register int rest; u_char rsta; /* get rx status register */ rsta = ISAC_READ(I_RSTA); if((rsta & ISAC_RSTA_MASK) != 0x20) { int error = 0; if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ { error++; NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); } if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ { error++; NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); } if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ { error++; NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); } if(error == 0) NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); ISACCMDRWRDELAY(); return; } rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); if(rest == 0) rest = ISAC_FIFO_LEN; if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) sc->sc_ib = sc->sc_ibuf->m_data; else panic("ifpi_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 = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_D; hdr.dir = FROM_NT; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); } c |= ISAC_CMDR_RMC; if(sc->sc_enabled && (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) { i4b_l1_ph_data_ind(L0IFPIUNIT(sc->sc_unit), sc->sc_ibuf); } else { i4b_Dfreembuf(sc->sc_ibuf); } } else { NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; } if(ista & ISAC_ISTA_RPF) /* receive fifo full */ { if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) sc->sc_ib= sc->sc_ibuf->m_data; else panic("ifpi_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) { ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); sc->sc_ilen += ISAC_FIFO_LEN; sc->sc_ib += ISAC_FIFO_LEN; c |= ISAC_CMDR_RMC; } else { NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } } if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ { if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) { sc->sc_freeflag = sc->sc_freeflag2; sc->sc_obuf = sc->sc_obuf2; sc->sc_op = sc->sc_obuf->m_data; sc->sc_ol = sc->sc_obuf->m_len; sc->sc_obuf2 = NULL; #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) ifpi_isac_ind_hdlr(sc, (ci >> 2) & 0xf); } if(c) { ISAC_WRITE(I_CMDR, c); ISACCMDRWRDELAY(); } } /*---------------------------------------------------------------------------* * ISAC L1 Extended IRQ handler *---------------------------------------------------------------------------*/ static u_char ifpi_isac_exir_hdlr(register struct l1_softc *sc, u_char exir) { u_char c = 0; if(exir & ISAC_EXIR_XMR) { NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); c |= ISAC_CMDR_XRES; } if(exir & ISAC_EXIR_XDU) { NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); c |= ISAC_CMDR_XRES; } if(exir & ISAC_EXIR_PCE) { NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); } if(exir & ISAC_EXIR_RFO) { NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } if(exir & ISAC_EXIR_SOV) { NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); } if(exir & ISAC_EXIR_MOS) { NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); } if(exir & ISAC_EXIR_SAW) { /* cannot happen, STCR:TSF is set to 0 */ NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); } if(exir & ISAC_EXIR_WOV) { /* cannot happen, STCR:TSF is set to 0 */ NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); } return(c); } /*---------------------------------------------------------------------------* * ISAC L1 Indication handler *---------------------------------------------------------------------------*/ static void ifpi_isac_ind_hdlr(register struct l1_softc *sc, int ind) { register int event; switch(ind) { case ISAC_CIRR_IAI8: NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpi_printstate(sc)); if(sc->sc_bustyp == BUS_TYPE_IOM2) ifpi_isac_l1_cmd(sc, CMD_AR8); event = EV_INFO48; i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); break; case ISAC_CIRR_IAI10: NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpi_printstate(sc)); if(sc->sc_bustyp == BUS_TYPE_IOM2) ifpi_isac_l1_cmd(sc, CMD_AR10); event = EV_INFO410; i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); break; case ISAC_CIRR_IRSY: NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpi_printstate(sc)); event = EV_RSY; break; case ISAC_CIRR_IPU: NDBGL1(L1_I_CICO, "rx PU in state %s", ifpi_printstate(sc)); event = EV_PU; break; case ISAC_CIRR_IDR: NDBGL1(L1_I_CICO, "rx DR in state %s", ifpi_printstate(sc)); ifpi_isac_l1_cmd(sc, CMD_DIU); event = EV_DR; break; case ISAC_CIRR_IDID: NDBGL1(L1_I_CICO, "rx DID in state %s", ifpi_printstate(sc)); event = EV_INFO0; i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL); break; case ISAC_CIRR_IDIS: NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpi_printstate(sc)); event = EV_DIS; break; case ISAC_CIRR_IEI: NDBGL1(L1_I_CICO, "rx EI in state %s", ifpi_printstate(sc)); ifpi_isac_l1_cmd(sc, CMD_DIU); event = EV_EI; break; case ISAC_CIRR_IARD: NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpi_printstate(sc)); event = EV_INFO2; break; case ISAC_CIRR_ITI: NDBGL1(L1_I_CICO, "rx TI in state %s", ifpi_printstate(sc)); event = EV_INFO0; break; case ISAC_CIRR_IATI: NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpi_printstate(sc)); event = EV_INFO0; break; case ISAC_CIRR_ISD: NDBGL1(L1_I_CICO, "rx SD in state %s", ifpi_printstate(sc)); event = EV_INFO0; break; default: NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpi_printstate(sc)); event = EV_INFO0; break; } ifpi_next_state(sc, event); } /*---------------------------------------------------------------------------* * execute a layer 1 command *---------------------------------------------------------------------------*/ void ifpi_isac_l1_cmd(struct l1_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) { NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpi_printstate(sc)); return; } if(sc->sc_bustyp == BUS_TYPE_IOM2) cmd = ISAC_CIX0_LOW; else cmd = 0; switch(command) { case CMD_TIM: NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpi_printstate(sc)); cmd |= (ISAC_CIXR_CTIM << 2); break; case CMD_RS: NDBGL1(L1_I_CICO, "tx RS in state %s", ifpi_printstate(sc)); cmd |= (ISAC_CIXR_CRS << 2); break; case CMD_AR8: NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpi_printstate(sc)); cmd |= (ISAC_CIXR_CAR8 << 2); break; case CMD_AR10: NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpi_printstate(sc)); cmd |= (ISAC_CIXR_CAR10 << 2); break; case CMD_DIU: NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpi_printstate(sc)); cmd |= (ISAC_CIXR_CDIU << 2); break; } ISAC_WRITE(I_CIXR, cmd); } /*---------------------------------------------------------------------------* * L1 ISAC initialization *---------------------------------------------------------------------------*/ int ifpi_isac_init(struct l1_softc *sc) { ISAC_IMASK = 0xff; /* disable all irqs */ ISAC_WRITE(I_MASK, ISAC_IMASK); if(sc->sc_bustyp != BUS_TYPE_IOM2) { NDBGL1(L1_I_SETUP, "configuring for IOM-1 mode"); /* 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 { NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); /* ADF2: Select mode IOM-2 */ ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); /* SPCR: serial port control register: * SPU - software power up = 0 * SPM - timing mode 0 * TLP - test loop = 0 * C1C, C2C - B1 + C1 and B2 + IC2 monitoring */ ISAC_WRITE(I_SPCR, 0x00); /* SQXR: S/Q channel xmit register: * IDC - IOM direction = 0 (master) * CFS - Config Select = 0 (clock always active) * CI1E - C/I channel 1 IRQ enable = 0 * SQIE - S/Q IRQ enable = 0 * SQX1-4 - Fa bits = 1 */ ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); /* ADF1: additional feature reg 1: * WTC - watchdog = 0 * TEM - test mode = 0 * PFS - pre-filter = 0 * IOF - IOM i/f off = 0 * ITF - interframe fill = idle */ ISAC_WRITE(I_ADF1, 0x00); /* STCR: sync transfer control reg: * TSF - terminal secific functions = 0 * TBA - TIC bus address = 7 * STx/SCx = 0 */ ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); /* MODE: Mode Register: * MDSx - transparent mode 2 * TMD - timer mode = external * RAC - Receiver enabled * DIMx - digital i/f mode */ ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); } #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 /* NIFPI > 0 */ Index: head/sys/i4b/layer1/ifpi/i4b_ifpi_l1.c =================================================================== --- head/sys/i4b/layer1/ifpi/i4b_ifpi_l1.c (revision 67972) +++ head/sys/i4b/layer1/ifpi/i4b_ifpi_l1.c (revision 67973) @@ -1,246 +1,244 @@ /* * Copyright (c) 1997, 2000 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_ifpi_l1.c - AVM Fritz PCI layer 1 handler * --------------------------------------------- * * $Id: i4b_ifpi_l1.c,v 1.4 2000/06/02 16:14:36 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Jun 2 14:54:30 2000] * *---------------------------------------------------------------------------*/ #include "ifpi.h" #include "pci.h" #if (NIFPI > 0) && (NPCI > 0) #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include #include /*---------------------------------------------------------------------------* * * L2 -> L1: PH-DATA-REQUEST * ========================= * * parms: * unit physical interface unit number * m mbuf containing L2 frame to be sent out * freeflag MBUF_FREE: free mbuf here after having sent * it out * MBUF_DONTFREE: mbuf is freed by Layer 2 * returns: * ==0 fail, nothing sent out * !=0 ok, frame sent out * *---------------------------------------------------------------------------*/ int ifpi_ph_data_req(int unit, struct mbuf *m, int freeflag) { u_char cmd; int s; struct l1_softc *sc = ifpi_scp[unit]; #ifdef NOTDEF NDBGL1(L1_PRIM, "PH-DATA-REQ, unit %d, freeflag=%d", unit, freeflag); #endif if(m == NULL) /* failsafe */ return (0); s = SPLI4B(); if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ { NDBGL1(L1_I_ERR, "still in state F3!"); ifpi_ph_activate_req(unit); } if(sc->sc_state & ISAC_TX_ACTIVE) { if(sc->sc_obuf2 == NULL) { sc->sc_obuf2 = m; /* save mbuf ptr */ if(freeflag) sc->sc_freeflag2 = 1; /* IRQ must mfree */ else sc->sc_freeflag2 = 0; /* IRQ must not mfree */ NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", ifpi_printstate(sc)); if(sc->sc_trace & TRACE_D_TX) { i4b_trace_hdr_t hdr; hdr.unit = L0IFPIUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } splx(s); return(1); } NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", ifpi_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 = L0IFPIUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); sc->sc_freeflag = 0; /* IRQ must NOT mfree */ ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ { sc->sc_obuf = m; /* save mbuf ptr */ sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ if(freeflag) sc->sc_freeflag = 1; /* IRQ must mfree */ cmd = ISAC_CMDR_XTF; } else { sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; if(freeflag) i4b_Dfreembuf(m); cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; } ISAC_WRITE(I_CMDR, cmd); ISACCMDRWRDELAY(); splx(s); return(1); } /*---------------------------------------------------------------------------* * * L2 -> L1: PH-ACTIVATE-REQUEST * ============================= * * parms: * unit physical interface unit number * * returns: * ==0 * !=0 * *---------------------------------------------------------------------------*/ int ifpi_ph_activate_req(int unit) { struct l1_softc *sc = ifpi_scp[unit]; NDBGL1(L1_PRIM, "PH-ACTIVATE-REQ, unit %d", unit); ifpi_next_state(sc, EV_PHAR); return(0); } /*---------------------------------------------------------------------------* * command from the upper layers *---------------------------------------------------------------------------*/ int ifpi_mph_command_req(int unit, int command, void *parm) { struct l1_softc *sc = ifpi_scp[unit]; switch(command) { case CMR_DOPEN: /* daemon running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); sc->sc_enabled = 1; break; case CMR_DCLOSE: /* daemon not running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); sc->sc_enabled = 0; break; case CMR_SETTRACE: NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); sc->sc_trace = (unsigned int)parm; break; default: NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); break; } return(0); } #endif /* NIFPI > 0 */ Index: head/sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c =================================================================== --- head/sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c (revision 67972) +++ head/sys/i4b/layer1/ifpi/i4b_ifpi_l1fsm.c (revision 67973) @@ -1,520 +1,517 @@ /* * Copyright (c) 1997, 2000 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_ifpi_l1fsm.c - AVM Fritz PCI layer 1 I.430 state machine * ------------------------------------------------------------ * * $Id: i4b_ifpi_l1fsm.c,v 1.4 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 15:23:15 2000] * *---------------------------------------------------------------------------*/ #include "ifpi.h" #include "pci.h" #if (NIFPI > 0) && (NPCI > 0) #include #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include #include #if DO_I4B_DEBUG static char *state_text[N_STATES] = { "F3 Deactivated", "F4 Awaiting Signal", "F5 Identifying Input", "F6 Synchronized", "F7 Activated", "F8 Lost Framing", "Illegal State" }; static char *event_text[N_EVENTS] = { "EV_PHAR PH_ACT_REQ", "EV_T3 Timer 3 expired", "EV_INFO0 INFO0 received", "EV_RSY Level Detected", "EV_INFO2 INFO2 received", "EV_INFO48 INFO4 received", "EV_INFO410 INFO4 received", "EV_DR Deactivate Req", "EV_PU Power UP", "EV_DIS Disconnected", "EV_EI Error Ind", "Illegal Event" }; #endif /* Function prototypes */ static void timer3_expired (struct l1_softc *sc); static void T3_start (struct l1_softc *sc); static void T3_stop (struct l1_softc *sc); static void F_T3ex (struct l1_softc *sc); static void timer4_expired (struct l1_softc *sc); static void T4_start (struct l1_softc *sc); static void T4_stop (struct l1_softc *sc); static void F_AI8 (struct l1_softc *sc); static void F_AI10 (struct l1_softc *sc); static void F_I01 (struct l1_softc *sc); static void F_I02 (struct l1_softc *sc); static void F_I03 (struct l1_softc *sc); static void F_I2 (struct l1_softc *sc); static void F_ill (struct l1_softc *sc); static void F_NULL (struct l1_softc *sc); /*---------------------------------------------------------------------------* * I.430 Timer T3 expire function *---------------------------------------------------------------------------*/ static void timer3_expired(struct l1_softc *sc) { if(sc->sc_I430T3) { NDBGL1(L1_T_ERR, "state = %s", ifpi_printstate(sc)); sc->sc_I430T3 = 0; /* XXX try some recovery here XXX */ ifpi_recover(sc); sc->sc_init_tries++; /* increment retry count */ /*XXX*/ if(sc->sc_init_tries > 4) { int s = SPLI4B(); sc->sc_init_tries = 0; if(sc->sc_obuf2 != NULL) { i4b_Dfreembuf(sc->sc_obuf2); sc->sc_obuf2 = NULL; } if(sc->sc_obuf != NULL) { i4b_Dfreembuf(sc->sc_obuf); sc->sc_obuf = NULL; sc->sc_freeflag = 0; sc->sc_op = NULL; sc->sc_ol = 0; } splx(s); i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL); } ifpi_next_state(sc, EV_T3); } else { NDBGL1(L1_T_ERR, "expired without starting it ...."); } } /*---------------------------------------------------------------------------* * I.430 Timer T3 start *---------------------------------------------------------------------------*/ static void T3_start(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); sc->sc_I430T3 = 1; sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz); } /*---------------------------------------------------------------------------* * I.430 Timer T3 stop *---------------------------------------------------------------------------*/ static void T3_stop(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); sc->sc_init_tries = 0; /* init connect retry count */ if(sc->sc_I430T3) { sc->sc_I430T3 = 0; untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout); } } /*---------------------------------------------------------------------------* * I.430 Timer T3 expiry *---------------------------------------------------------------------------*/ static void F_T3ex(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0IFPIUNIT(sc->sc_unit)); } /*---------------------------------------------------------------------------* * Timer T4 expire function *---------------------------------------------------------------------------*/ static void timer4_expired(struct l1_softc *sc) { if(sc->sc_I430T4) { NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); sc->sc_I430T4 = 0; i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_PDEACT, 0, NULL); } else { NDBGL1(L1_T_ERR, "expired without starting it ...."); } } /*---------------------------------------------------------------------------* * Timer T4 start *---------------------------------------------------------------------------*/ static void T4_start(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); sc->sc_I430T4 = 1; sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz); } /*---------------------------------------------------------------------------* * Timer T4 stop *---------------------------------------------------------------------------*/ static void T4_stop(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpi_printstate(sc)); if(sc->sc_I430T4) { sc->sc_I430T4 = 0; untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout); } } /*---------------------------------------------------------------------------* * FSM function: received AI8 *---------------------------------------------------------------------------*/ static void F_AI8(struct l1_softc *sc) { T4_stop(sc); NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_activate_ind(L0IFPIUNIT(sc->sc_unit)); T3_stop(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO4_8; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received AI10 *---------------------------------------------------------------------------*/ static void F_AI10(struct l1_softc *sc) { T4_stop(sc); NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_activate_ind(L0IFPIUNIT(sc->sc_unit)); T3_stop(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO4_10; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in states F3 .. F5 *---------------------------------------------------------------------------*/ static void F_I01(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in state F6 *---------------------------------------------------------------------------*/ static void F_I02(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0IFPIUNIT(sc->sc_unit)); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in state F7 or F8 *---------------------------------------------------------------------------*/ static void F_I03(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0IFPIUNIT(sc->sc_unit)); T4_start(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: activate request *---------------------------------------------------------------------------*/ static void F_AR(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_AR executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO1_8; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_TE; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } ifpi_isac_l1_cmd(sc, CMD_AR8); T3_start(sc); } /*---------------------------------------------------------------------------* * FSM function: received INFO2 *---------------------------------------------------------------------------*/ static void F_I2(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO2; hdr.unit = L0IFPIUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * illegal state default action *---------------------------------------------------------------------------*/ static void F_ill(struct l1_softc *sc) { NDBGL1(L1_F_ERR, "FSM function F_ill executing"); } /*---------------------------------------------------------------------------* * No action *---------------------------------------------------------------------------*/ static void F_NULL(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); } /*---------------------------------------------------------------------------* * layer 1 state transition table *---------------------------------------------------------------------------*/ struct ifpi_state_tab { void (*func) (struct l1_softc *sc); /* function to execute */ int newstate; /* next state */ } ifpi_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 ifpi_next_state(struct l1_softc *sc, int event) { int currstate, newstate; if(event >= N_EVENTS) panic("i4b_l1fsm.c: event >= N_EVENTS\n"); currstate = sc->sc_I430state; if(currstate >= N_STATES) panic("i4b_l1fsm.c: currstate >= N_STATES\n"); newstate = ifpi_state_tab[event][currstate].newstate; if(newstate >= N_STATES) panic("i4b_l1fsm.c: newstate >= N_STATES\n"); NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], state_text[currstate], state_text[newstate]); (*ifpi_state_tab[event][currstate].func)(sc); if(newstate == ST_ILL) { newstate = ST_F3; NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", state_text[currstate], state_text[newstate], event_text[event]); } sc->sc_I430state = newstate; } #if DO_I4B_DEBUG /*---------------------------------------------------------------------------* * return pointer to current state description *---------------------------------------------------------------------------*/ char * ifpi_printstate(struct l1_softc *sc) { return((char *) state_text[sc->sc_I430state]); } #endif #endif /* NIFPI > 0 */ Index: head/sys/i4b/layer1/ifpi/i4b_ifpi_pci.c =================================================================== --- head/sys/i4b/layer1/ifpi/i4b_ifpi_pci.c (revision 67972) +++ head/sys/i4b/layer1/ifpi/i4b_ifpi_pci.c (revision 67973) @@ -1,1486 +1,1484 @@ /* * Copyright (c) 1999, 2000 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. * *--------------------------------------------------------------------------- * * i4b_ifpi_pci.c: AVM Fritz!Card PCI hardware driver * -------------------------------------------------- * * $Id: i4b_ifpi_pci.c,v 1.4 2000/06/02 11:58:56 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Jun 2 13:58:02 2000] * *---------------------------------------------------------------------------*/ #include "ifpi.h" #include "opt_i4b.h" #include "pci.h" #if (NIFPI > 0) && (NPCI > 0) #include #include #include #include -#include /* this device uses port accesses only */ #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PCI_AVMA1_VID 0x1244 #define PCI_AVMA1_DID 0x0a00 /* prototypes */ static void avma1pp_disable(device_t); static void avma1pp_intr(void *); static void hscx_write_reg(int, u_int, u_int, struct l1_softc *); static u_char hscx_read_reg(int, u_int, struct l1_softc *); static u_int hscx_read_reg_int(int, u_int, struct l1_softc *); static void hscx_read_fifo(int, void *, size_t, struct l1_softc *); static void hscx_write_fifo(int, void *, size_t, struct l1_softc *); static void avma1pp_hscx_int_handler(struct l1_softc *); static void avma1pp_hscx_intr(int, u_int, struct l1_softc *); static void avma1pp_init_linktab(struct l1_softc *); static void avma1pp_bchannel_setup(int, int, int, int); static void avma1pp_bchannel_start(int, int); static void avma1pp_hscx_init(struct l1_softc *, int, int); static void avma1pp_bchannel_stat(int, int, bchan_statistics_t *); static void avma1pp_set_linktab(int, int, drvr_link_t *); static isdn_link_t * avma1pp_ret_linktab(int, int); static int avma1pp_pci_probe(device_t); static int avma1pp_hscx_fifo(l1_bchan_state_t *, struct l1_softc *); int avma1pp_attach_avma1pp(device_t); static void ifpi_isac_intr(struct l1_softc *sc); static device_method_t avma1pp_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, avma1pp_pci_probe), DEVMETHOD(device_attach, avma1pp_attach_avma1pp), DEVMETHOD(device_shutdown, avma1pp_disable), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), { 0, 0 } }; #if 0 /* use what's in l1_softc */ /* a minimal softc for the Fritz!Card PCI */ struct avma1pp_softc { bus_space_handle_t avma1pp_bhandle; bus_space_tag_t avma1pp_btag; void *avma1pp_intrhand; struct resource *avma1pp_irq; struct resource *avma1pp_res; /* pointer to ifpi_sc */ struct l1_softc *avma1pp_isc; }; #endif static driver_t avma1pp_pci_driver = { "ifpi", avma1pp_pci_methods, sizeof(struct l1_softc) }; static devclass_t avma1pp_pci_devclass; DRIVER_MODULE(avma1pp, pci, avma1pp_pci_driver, avma1pp_pci_devclass, 0, 0); /* jump table for multiplex routines */ struct i4b_l1mux_func avma1pp_l1mux_func = { avma1pp_ret_linktab, avma1pp_set_linktab, ifpi_mph_command_req, ifpi_ph_data_req, ifpi_ph_activate_req, }; struct l1_softc *ifpi_scp[IFPI_MAXUNIT]; /*---------------------------------------------------------------------------* * AVM PCI Fritz!Card special registers *---------------------------------------------------------------------------*/ /* * register offsets from i/o base */ #define STAT0_OFFSET 0x02 #define STAT1_OFFSET 0x03 #define ADDR_REG_OFFSET 0x04 /*#define MODREG_OFFSET 0x06 #define VERREG_OFFSET 0x07*/ /* these 2 are used to select an ISAC register set */ #define ISAC_LO_REG_OFFSET 0x04 #define ISAC_HI_REG_OFFSET 0x06 /* offset higher than this goes to the HI register set */ #define MAX_LO_REG_OFFSET 0x2f /* mask for the offset */ #define ISAC_REGSET_MASK 0x0f /* the offset from the base to the ISAC registers */ #define ISAC_REG_OFFSET 0x10 /* the offset from the base to the ISAC FIFO */ #define ISAC_FIFO 0x02 /* not really the HSCX, but sort of */ #define HSCX_FIFO 0x00 #define HSCX_STAT 0x04 /* * AVM PCI Status Latch 0 read only bits */ #define ASL_IRQ_ISAC 0x01 /* ISAC interrupt, active low */ #define ASL_IRQ_HSCX 0x02 /* HSX interrupt, active low */ #define ASL_IRQ_TIMER 0x04 /* Timer interrupt, active low */ #define ASL_IRQ_BCHAN ASL_IRQ_HSCX /* actually active LOW */ #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 */ #define ASL_TESTBIT 0x10 /* active high */ /* * AVM Status Latch 1 write only bits */ #define ASL1_INTSEL 0x0f /* active high */ #define ASL1_ENABLE_IOM 0x80 /* active high */ /* * "HSCX" mode bits */ #define HSCX_MODE_ITF_FLG 0x01 #define HSCX_MODE_TRANS 0x02 #define HSCX_MODE_CCR_7 0x04 #define HSCX_MODE_CCR_16 0x08 #define HSCX_MODE_TESTLOOP 0x80 /* * "HSCX" status bits */ #define HSCX_STAT_RME 0x01 #define HSCX_STAT_RDO 0x10 #define HSCX_STAT_CRCVFRRAB 0x0E #define HSCX_STAT_CRCVFR 0x06 #define HSCX_STAT_RML_MASK 0x3f00 /* * "HSCX" interrupt bits */ #define HSCX_INT_XPR 0x80 #define HSCX_INT_XDU 0x40 #define HSCX_INT_RPR 0x20 #define HSCX_INT_MASK 0xE0 /* * "HSCX" command bits */ #define HSCX_CMD_XRS 0x80 #define HSCX_CMD_XME 0x01 #define HSCX_CMD_RRS 0x20 #define HSCX_CMD_XML_MASK 0x3f00 /* * Commands and parameters are sent to the "HSCX" as a long, but the * fields are handled as bytes. * * The long contains: * (prot << 16)|(txl << 8)|cmd * * where: * prot = protocol to use * txl = transmit length * cmd = the command to be executed * * The fields are defined as u_char in struct l1_softc. * * Macro to coalesce the byte fields into a u_int */ #define AVMA1PPSETCMDLONG(f) (f) = ((sc->avma1pp_cmd) | (sc->avma1pp_txl << 8) \ | (sc->avma1pp_prot << 16)) /* * to prevent deactivating the "HSCX" when both channels are active we * define an HSCX_ACTIVE flag which is or'd into the channel's state * flag in avma1pp_bchannel_setup upon active and cleared upon deactivation. * It is set high to allow room for new flags. */ #define HSCX_AVMA1PP_ACTIVE 0x1000 /*---------------------------------------------------------------------------* * AVM read fifo routines *---------------------------------------------------------------------------*/ static void avma1pp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, ISAC_FIFO); bus_space_read_multi_1(btag, bhandle, ISAC_REG_OFFSET, buf, size); break; case ISIC_WHAT_HSCXA: hscx_read_fifo(0, buf, size, sc); break; case ISIC_WHAT_HSCXB: hscx_read_fifo(1, buf, size, sc); break; } } static void hscx_read_fifo(int chan, void *buf, size_t len, struct l1_softc *sc) { u_int32_t *ip; size_t cnt; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_write_4(btag, bhandle, ADDR_REG_OFFSET, chan); ip = (u_int32_t *)buf; cnt = 0; /* what if len isn't a multiple of sizeof(int) and buf is */ /* too small ???? */ while (cnt < len) { *ip++ = bus_space_read_4(btag, bhandle, ISAC_REG_OFFSET); cnt += 4; } } /*---------------------------------------------------------------------------* * AVM write fifo routines *---------------------------------------------------------------------------*/ static void avma1pp_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, ISAC_FIFO); bus_space_write_multi_1(btag, bhandle, ISAC_REG_OFFSET, (u_int8_t*)buf, size); break; case ISIC_WHAT_HSCXA: hscx_write_fifo(0, buf, size, sc); break; case ISIC_WHAT_HSCXB: hscx_write_fifo(1, buf, size, sc); break; } } static void hscx_write_fifo(int chan, void *buf, size_t len, struct l1_softc *sc) { u_int32_t *ip; size_t cnt; l1_bchan_state_t *Bchan = &sc->sc_chan[chan]; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); sc->avma1pp_cmd &= ~HSCX_CMD_XME; sc->avma1pp_txl = 0; if (Bchan->out_mbuf_cur == NULL) { if (Bchan->bprot != BPROT_NONE) sc->avma1pp_cmd |= HSCX_CMD_XME; } if (len != sc->sc_bfifolen) sc->avma1pp_txl = len; cnt = 0; /* borrow cnt */ AVMA1PPSETCMDLONG(cnt); hscx_write_reg(chan, HSCX_STAT, cnt, sc); ip = (u_int32_t *)buf; cnt = 0; while (cnt < len) { bus_space_write_4(btag, bhandle, ISAC_REG_OFFSET, *ip); ip++; cnt += 4; } } /*---------------------------------------------------------------------------* * AVM write register routines *---------------------------------------------------------------------------*/ static void avma1pp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { u_char reg_bank; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; #ifdef AVMA1PCI_DEBUG printf("write_reg bank %d off %ld.. ", (int)reg_bank, (long)offs); #endif /* set the register bank */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, reg_bank); bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET + (offs & ISAC_REGSET_MASK), data); break; case ISIC_WHAT_HSCXA: hscx_write_reg(0, offs, data, sc); break; case ISIC_WHAT_HSCXB: hscx_write_reg(1, offs, data, sc); break; } } static void hscx_write_reg(int chan, u_int off, u_int val, struct l1_softc *sc) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* point at the correct channel */ bus_space_write_4(btag, bhandle, ADDR_REG_OFFSET, chan); bus_space_write_4(btag, bhandle, ISAC_REG_OFFSET + off, val); } /*---------------------------------------------------------------------------* * AVM read register routines *---------------------------------------------------------------------------*/ static u_int8_t avma1pp_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { u_char reg_bank; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; #ifdef AVMA1PCI_DEBUG printf("read_reg bank %d off %ld.. ", (int)reg_bank, (long)offs); #endif /* set the register bank */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, reg_bank); return(bus_space_read_1(btag, bhandle, ISAC_REG_OFFSET + (offs & ISAC_REGSET_MASK))); case ISIC_WHAT_HSCXA: return hscx_read_reg(0, offs, sc); case ISIC_WHAT_HSCXB: return hscx_read_reg(1, offs, sc); } return 0; } static u_char hscx_read_reg(int chan, u_int off, struct l1_softc *sc) { return(hscx_read_reg_int(chan, off, sc) & 0xff); } /* * need to be able to return an int because the RBCH is in the 2nd * byte. */ static u_int hscx_read_reg_int(int chan, u_int off, struct l1_softc *sc) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* point at the correct channel */ bus_space_write_4(btag, bhandle, ADDR_REG_OFFSET, chan); return(bus_space_read_4(btag, bhandle, ISAC_REG_OFFSET + off)); } /*---------------------------------------------------------------------------* * avma1pp_probe - probe for a card *---------------------------------------------------------------------------*/ static int avma1pp_pci_probe(dev) device_t dev; { u_int16_t did, vid; vid = pci_get_vendor(dev); did = pci_get_device(dev); if ((vid == PCI_AVMA1_VID) && (did == PCI_AVMA1_DID)) { device_set_desc(dev, "AVM Fritz!Card PCI"); return(0); } return(ENXIO); } /*---------------------------------------------------------------------------* * avma1pp_attach_avma1pp - attach Fritz!Card PCI *---------------------------------------------------------------------------*/ int avma1pp_attach_avma1pp(device_t dev) { struct l1_softc *sc; u_int v; int unit, error = 0; int s; u_int16_t did, vid; void *ih = 0; bus_space_handle_t bhandle; bus_space_tag_t btag; s = splimp(); vid = pci_get_vendor(dev); did = pci_get_device(dev); sc = device_get_softc(dev); unit = device_get_unit(dev); bzero(sc, sizeof(struct l1_softc)); /* probably not really required */ if(unit > IFPI_MAXUNIT) { printf("avma1pp%d: Error, unit > IFPI_MAXUNIT!\n", unit); splx(s); return(ENXIO); } if ((vid != PCI_AVMA1_VID) && (did != PCI_AVMA1_DID)) { printf("avma1pp%d: unknown device!?\n", unit); goto fail; } ifpi_scp[unit] = sc; sc->sc_resources.io_rid[0] = PCIR_MAPS+4; sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0, ~0, 1, RF_ACTIVE); if (sc->sc_resources.io_base[0] == NULL) { printf("avma1pp%d: couldn't map IO port\n", unit); error = ENXIO; goto fail; } bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* Allocate interrupt */ sc->sc_resources.irq_rid = 0; sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_resources.irq == NULL) { bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS+4, sc->sc_resources.io_base[0]); printf("avma1pp%d: couldn't map interrupt\n", unit); error = ENXIO; goto fail; } error = bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, avma1pp_intr, sc, &ih); if (error) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_resources.irq); bus_release_resource(dev, SYS_RES_IOPORT, PCIR_MAPS+4, sc->sc_resources.io_base[0]); printf("avma1pp%d: couldn't set up irq\n", unit); goto fail; } sc->sc_unit = unit; /* end of new-bus stuff */ ISAC_BASE = (caddr_t)ISIC_WHAT_ISAC; HSCX_A_BASE = (caddr_t)ISIC_WHAT_HSCXA; HSCX_B_BASE = (caddr_t)ISIC_WHAT_HSCXB; /* setup access routines */ sc->clearirq = NULL; sc->readreg = avma1pp_read_reg; sc->writereg = avma1pp_write_reg; sc->readfifo = avma1pp_read_fifo; sc->writefifo = avma1pp_write_fifo; /* setup card type */ sc->sc_cardtyp = CARD_TYPEP_AVMA1PCI; /* setup IOM bus type */ sc->sc_bustyp = BUS_TYPE_IOM2; /* set up some other miscellaneous things */ sc->sc_ipac = 0; sc->sc_bfifolen = HSCX_FIFO_LEN; /* reset the card */ /* the Linux driver does this to clear any pending ISAC interrupts */ v = 0; v = ISAC_READ(I_STAR); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: I_STAR %x...", v); #endif v = ISAC_READ(I_MODE); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: I_MODE %x...", v); #endif v = ISAC_READ(I_ADF2); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: I_ADF2 %x...", v); #endif v = ISAC_READ(I_ISTA); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: I_ISTA %x...", v); #endif if (v & ISAC_ISTA_EXI) { v = ISAC_READ(I_EXIR); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: I_EXIR %x...", v); #endif } v = ISAC_READ(I_CIRR); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: I_CIRR %x...", v); #endif ISAC_WRITE(I_MASK, 0xff); /* the Linux driver does this to clear any pending HSCX interrupts */ v = hscx_read_reg_int(0, HSCX_STAT, sc); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: 0 HSCX_STAT %x...", v); #endif v = hscx_read_reg_int(1, HSCX_STAT, sc); #ifdef AVMA1PCI_DEBUG printf("avma1pp_attach: 1 HSCX_STAT %x\n", v); #endif bus_space_write_1(btag, bhandle, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); DELAY(SEC_DELAY/100); /* 10 ms */ bus_space_write_1(btag, bhandle, STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE); DELAY(SEC_DELAY/100); /* 10 ms */ #ifdef AVMA1PCI_DEBUG bus_space_write_1(btag, bhandle, STAT1_OFFSET, ASL1_ENABLE_IOM|sc->sc_irq); DELAY(SEC_DELAY/100); /* 10 ms */ v = bus_space_read_1(btag, bhandle, STAT1_OFFSET); printf("after reset: S1 %#x\n", v); v = bus_space_read_4(btag, bhandle, 0); printf("avma1pp_attach_avma1pp: v %#x\n", v); #endif /* from here to the end would normally be done in isic_pciattach */ printf("ifpi%d: ISAC %s (IOM-%c)\n", unit, "2085 Version A1/A2 or 2086/2186 Version 1.1", sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); /* init the ISAC */ ifpi_isac_init(sc); /* init the "HSCX" */ avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); avma1pp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); /* can't use the normal B-Channel stuff */ avma1pp_init_linktab(sc); /* set trace level */ sc->sc_trace = TRACE_OFF; sc->sc_state = ISAC_IDLE; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; sc->sc_freeflag = 0; sc->sc_obuf2 = NULL; sc->sc_freeflag2 = 0; #if defined(__FreeBSD__) && __FreeBSD__ >=3 callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); #endif /* init higher protocol layers */ i4b_l1_mph_status_ind(L0IFPIUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &avma1pp_l1mux_func); fail: splx(s); return(error); } /* * this is the real interrupt routine */ static void avma1pp_hscx_intr(int h_chan, u_int stat, struct l1_softc *sc) { register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int activity = -1; u_int param = 0; NDBGL1(L1_H_IRQ, "%#x", stat); if((stat & HSCX_INT_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */ { chan->stat_XDU++; NDBGL1(L1_H_XFRERR, "xmit data underrun"); /* abort the transmission */ sc->avma1pp_txl = 0; sc->avma1pp_cmd |= HSCX_CMD_XRS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); sc->avma1pp_cmd &= ~HSCX_CMD_XRS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); 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; } } /* * The following is based on examination of the Linux driver. * * The logic here is different than with a "real" HSCX; all kinds * of information (interrupt/status bits) are in stat. * HSCX_INT_RPR indicates a receive interrupt * HSCX_STAT_RDO indicates an overrun condition, abort - * otherwise read the bytes ((stat & HSCX_STZT_RML_MASK) >> 8) * HSCX_STAT_RME indicates end-of-frame and apparently any * CRC/framing errors are only reported in this state. * if ((stat & HSCX_STAT_CRCVFRRAB) != HSCX_STAT_CRCVFR) * CRC/framing error */ if(stat & HSCX_INT_RPR) { register int fifo_data_len; int error = 0; /* always have to read the FIFO, so use a scratch buffer */ u_char scrbuf[HSCX_FIFO_LEN]; if(stat & HSCX_STAT_RDO) { chan->stat_RDO++; NDBGL1(L1_H_XFRERR, "receive data overflow"); error++; } /* * check whether we're receiving data for an inactive B-channel * and discard it. This appears to happen for telephony when * both B-channels are active and one is deactivated. Since * it is not really possible to deactivate the channel in that * case (the ASIC seems to deactivate _both_ channels), the * "deactivated" channel keeps receiving data which can lead * to exhaustion of mbufs and a kernel panic. * * This is a hack, but it's the only solution I can think of * without having the documentation for the ASIC. * GJ - 28 Nov 1999 */ if (chan->state == HSCX_IDLE) { NDBGL1(L1_H_XFRERR, "toss data from %d", h_chan); error++; } fifo_data_len = ((stat & HSCX_STAT_RML_MASK) >> 8); if(fifo_data_len == 0) fifo_data_len = sc->sc_bfifolen; /* ALWAYS read data from HSCX fifo */ HSCX_RDFIFO(h_chan, scrbuf, fifo_data_len); chan->rxcount += fifo_data_len; /* 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 avma1pp_hscx_intr: RME, cannot allocate mbuf!\n"); chan->in_cbptr = chan->in_mbuf->m_data; chan->in_len = 0; } if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN) { /* OK to copy the data */ bcopy(scrbuf, chan->in_cbptr, fifo_data_len); chan->in_cbptr += fifo_data_len; chan->in_len += 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 = L0IFPIUNIT(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); i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); } if (stat & HSCX_STAT_RME) { if((stat & HSCX_STAT_CRCVFRRAB) == HSCX_STAT_CRCVFR) { (*chan->isic_drvr_linktab->bch_rx_data_ready)(chan->isic_drvr_linktab->unit); activity = ACT_RX; /* mark buffer ptr as unused */ chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } else { chan->stat_CRC++; NDBGL1(L1_H_XFRERR, "CRC/RAB"); if (chan->in_mbuf != NULL) { i4b_Bfreembuf(chan->in_mbuf); chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } } } } /* END enough space in mbuf */ 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 = L0IFPIUNIT(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); i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); } if(!(i4b_l1_bchan_tel_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len))) activity = ACT_RX; /* move rx'd data to rx queue */ if (!(IF_QFULL(&chan->rx_queue))) { IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf); } else { i4b_Bfreembuf(chan->in_mbuf); } /* signal upper layer that data are available */ (*chan->isic_drvr_linktab->bch_rx_data_ready)(chan->isic_drvr_linktab->unit); /* alloc new buffer */ if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) panic("L1 avma1pp_hscx_intr: RPF, cannot allocate new mbuf!\n"); /* setup new data ptr */ chan->in_cbptr = chan->in_mbuf->m_data; /* OK to copy the data */ bcopy(scrbuf, chan->in_cbptr, fifo_data_len); chan->in_cbptr += fifo_data_len; chan->in_len = fifo_data_len; chan->rxcount += fifo_data_len; } else { NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len); chan->in_cbptr = chan->in_mbuf->m_data; chan->in_len = 0; } } } /* if(error == 0) */ else { /* land here for RDO */ if (chan->in_mbuf != NULL) { i4b_Bfreembuf(chan->in_mbuf); chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } sc->avma1pp_txl = 0; sc->avma1pp_cmd |= HSCX_CMD_RRS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); sc->avma1pp_cmd &= ~HSCX_CMD_RRS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); } } /* transmit fifo empty, new data can be written to fifo */ if(stat & HSCX_INT_XPR) { /* * for a description what is going on here, please have * a look at isic_bchannel_start() in i4b_bchan.c ! */ NDBGL1(L1_H_IRQ, "unit %d, chan %d - XPR, Tx Fifo Empty!", 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->isic_drvr_linktab->bch_tx_queue_empty)(chan->isic_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 = L0IFPIUNIT(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); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } if(chan->bprot == BPROT_NONE) { if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) activity = ACT_TX; } else { activity = ACT_TX; } } } avma1pp_hscx_fifo(chan, sc); } /* call timeout handling routine */ if(activity == ACT_RX || activity == ACT_TX) (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity); } /* * this is the main routine which checks each channel and then calls * the real interrupt routine as appropriate */ static void avma1pp_hscx_int_handler(struct l1_softc *sc) { u_int stat; /* has to be a u_int because the byte count is in the 2nd byte */ stat = hscx_read_reg_int(0, HSCX_STAT, sc); if (stat & HSCX_INT_MASK) avma1pp_hscx_intr(0, stat, sc); stat = hscx_read_reg_int(1, HSCX_STAT, sc); if (stat & HSCX_INT_MASK) avma1pp_hscx_intr(1, stat, sc); } static void avma1pp_disable(device_t dev) { struct l1_softc *sc = device_get_softc(dev); bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_write_1(btag, bhandle, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); } static void avma1pp_intr(void *xsc) { u_char stat; struct l1_softc *sc; bus_space_handle_t bhandle; bus_space_tag_t btag; sc = xsc; bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); btag = rman_get_bustag(sc->sc_resources.io_base[0]); stat = bus_space_read_1(btag, bhandle, STAT0_OFFSET); NDBGL1(L1_H_IRQ, "stat %x", stat); /* was there an interrupt from this card ? */ if ((stat & ASL_IRQ_Pending) == ASL_IRQ_Pending) return; /* no */ /* interrupts are low active */ if (!(stat & ASL_IRQ_TIMER)) NDBGL1(L1_H_IRQ, "timer interrupt ???"); if (!(stat & ASL_IRQ_HSCX)) { NDBGL1(L1_H_IRQ, "HSCX"); avma1pp_hscx_int_handler(sc); } if (!(stat & ASL_IRQ_ISAC)) { NDBGL1(L1_H_IRQ, "ISAC"); ifpi_isac_intr(sc); } } static void avma1pp_hscx_init(struct l1_softc *sc, int h_chan, int activate) { l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; u_int param = 0; NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", sc->sc_unit, h_chan, activate ? "activate" : "deactivate"); if (activate == 0) { /* only deactivate if both channels are idle */ if (sc->sc_chan[HSCX_CH_A].state != HSCX_IDLE || sc->sc_chan[HSCX_CH_B].state != HSCX_IDLE) { return; } sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; sc->avma1pp_prot = HSCX_MODE_TRANS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); return; } if(chan->bprot == BPROT_RHDLC) { NDBGL1(L1_BCHAN, "BPROT_RHDLC"); /* HDLC Frames, transparent mode 0 */ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; sc->avma1pp_prot = HSCX_MODE_ITF_FLG; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); sc->avma1pp_cmd = HSCX_CMD_XRS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); sc->avma1pp_cmd = 0; } else { NDBGL1(L1_BCHAN, "BPROT_NONE??"); /* Raw Telephony, extended transparent mode 1 */ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; sc->avma1pp_prot = HSCX_MODE_TRANS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); sc->avma1pp_cmd = HSCX_CMD_XRS; AVMA1PPSETCMDLONG(param); hscx_write_reg(h_chan, HSCX_STAT, param, sc); sc->avma1pp_cmd = 0; } } static void avma1pp_bchannel_setup(int unit, int h_chan, int bprot, int activate) { #ifdef __FreeBSD__ struct l1_softc *sc = ifpi_scp[unit]; #else struct l1_softc *sc = isic_find_sc(unit); #endif l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s = SPLI4B(); if(activate == 0) { /* deactivation */ chan->state = HSCX_IDLE; avma1pp_hscx_init(sc, h_chan, activate); } NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", 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 */ avma1pp_hscx_init(sc, h_chan, activate); chan->state |= HSCX_AVMA1PP_ACTIVE; } splx(s); } static void avma1pp_bchannel_start(int unit, int h_chan) { #ifdef __FreeBSD__ struct l1_softc *sc = ifpi_scp[unit]; #else struct l1_softc *sc = isic_find_sc(unit); #endif register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s; int activity = -1; 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(!(i4b_l1_bchan_tel_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 = L0IFPIUNIT(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); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } avma1pp_hscx_fifo(chan, sc); /* call timeout handling routine */ if(activity == ACT_RX || activity == ACT_TX) (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity); splx(s); } /*---------------------------------------------------------------------------* * return the address of isic drivers linktab *---------------------------------------------------------------------------*/ static isdn_link_t * avma1pp_ret_linktab(int unit, int channel) { #ifdef __FreeBSD__ struct l1_softc *sc = ifpi_scp[unit]; #else struct l1_softc *sc = isic_find_sc(unit); #endif l1_bchan_state_t *chan = &sc->sc_chan[channel]; return(&chan->isic_isdn_linktab); } /*---------------------------------------------------------------------------* * set the driver linktab in the b channel softc *---------------------------------------------------------------------------*/ static void avma1pp_set_linktab(int unit, int channel, drvr_link_t *dlt) { #ifdef __FreeBSD__ struct l1_softc *sc = ifpi_scp[unit]; #else struct l1_softc *sc = isic_find_sc(unit); #endif l1_bchan_state_t *chan = &sc->sc_chan[channel]; chan->isic_drvr_linktab = dlt; } /*---------------------------------------------------------------------------* * initialize our local linktab *---------------------------------------------------------------------------*/ static void avma1pp_init_linktab(struct l1_softc *sc) { l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A]; isdn_link_t *lt = &chan->isic_isdn_linktab; /* make sure the hardware driver is known to layer 4 */ /* avoid overwriting if already set */ if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL) { ctrl_types[CTRL_PASSIVE].set_linktab = avma1pp_set_linktab; ctrl_types[CTRL_PASSIVE].get_linktab = avma1pp_ret_linktab; } /* local setup */ lt->unit = sc->sc_unit; lt->channel = HSCX_CH_A; lt->bch_config = avma1pp_bchannel_setup; lt->bch_tx_start = avma1pp_bchannel_start; lt->bch_stat = avma1pp_bchannel_stat; lt->tx_queue = &chan->tx_queue; /* used by non-HDLC data transfers, i.e. telephony drivers */ lt->rx_queue = &chan->rx_queue; /* used by HDLC data transfers, i.e. ipr and isp drivers */ lt->rx_mbuf = &chan->in_mbuf; chan = &sc->sc_chan[HSCX_CH_B]; lt = &chan->isic_isdn_linktab; lt->unit = sc->sc_unit; lt->channel = HSCX_CH_B; lt->bch_config = avma1pp_bchannel_setup; lt->bch_tx_start = avma1pp_bchannel_start; lt->bch_stat = avma1pp_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; } /* * use this instead of isic_bchannel_stat in i4b_bchan.c because it's static */ static void avma1pp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp) { #ifdef __FreeBSD__ struct l1_softc *sc = ifpi_scp[unit]; #else struct l1_softc *sc = isic_find_sc(unit); #endif l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s; s = SPLI4B(); bsp->outbytes = chan->txcount; bsp->inbytes = chan->rxcount; chan->txcount = 0; chan->rxcount = 0; splx(s); } /*---------------------------------------------------------------------------* * fill HSCX fifo with data from the current mbuf * Put this here until it can go into i4b_hscx.c *---------------------------------------------------------------------------*/ static int avma1pp_hscx_fifo(l1_bchan_state_t *chan, struct l1_softc *sc) { int len; int nextlen; int i; int cmd = 0; /* using a scratch buffer simplifies writing to the FIFO */ u_char scrbuf[HSCX_FIFO_LEN]; len = 0; /* * 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(chan->out_mbuf_cur && len != sc->sc_bfifolen) { nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len); #ifdef NOTDEF printf("i:mh=%p, mc=%p, mcp=%p, 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, nextlen); #endif cmd |= HSCX_CMDR_XTF; /* collect the data in the scratch buffer */ for (i = 0; i < nextlen; i++) scrbuf[i + len] = chan->out_mbuf_cur_ptr[i]; 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 = L0IFPIUNIT(sc->sc_unit); hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_bcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 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; } } } /* write what we have from the scratch buf to the HSCX fifo */ if (len != 0) HSCX_WRFIFO(chan->channel, scrbuf, len); return(cmd); } /*---------------------------------------------------------------------------* * ifpi - ISAC interrupt routine *---------------------------------------------------------------------------*/ static void ifpi_isac_intr(struct l1_softc *sc) { register u_char isac_irq_stat; for(;;) { /* get isac irq status */ isac_irq_stat = ISAC_READ(I_ISTA); if(isac_irq_stat) ifpi_isac_irq(sc, isac_irq_stat); /* isac handler */ else break; } ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASK, ISAC_IMASK); } /*---------------------------------------------------------------------------* * ifpi_recover - try to recover from irq lockup *---------------------------------------------------------------------------*/ void ifpi_recover(struct l1_softc *sc) { u_char byte; /* get isac irq status */ byte = ISAC_READ(I_ISTA); NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte); if(byte & ISAC_ISTA_EXI) NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR)); if(byte & ISAC_ISTA_CISQ) { byte = ISAC_READ(I_CIRR); NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte); if(byte & ISAC_CIRR_SQC) NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR)); } NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK); ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASK, ISAC_IMASK); } #endif /* NIFPI > 0 */ Index: head/sys/i4b/layer1/ifpnp/i4b_ifpnp_avm.c =================================================================== --- head/sys/i4b/layer1/ifpnp/i4b_ifpnp_avm.c (revision 67972) +++ head/sys/i4b/layer1/ifpnp/i4b_ifpnp_avm.c (revision 67973) @@ -1,1389 +1,1387 @@ /* * Copyright (c) 1999, 2000 Udo Schweigert. 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_ifpnp_avm.c: AVM Fritz!Card PnP hardware driver * --------------------------------------------------- * * $Id: i4b_ifpnp_avm.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_avm.c,v 1.6 2000/04/18 08:32:32 ust Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 15:24:43 2000] * *---------------------------------------------------------------------------*/ #include "ifpnp.h" #include "opt_i4b.h" #if (NIFPNP > 0) #include #include #include #include -#include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* prototypes */ static void avm_pnp_intr(void *); static void hscx_write_reg(int, u_int, struct l1_softc *, u_int); static void hscx_write_reg_val(int, u_int, u_int8_t, struct l1_softc *); static u_int hscx_read_reg(int, u_int, struct l1_softc *); static void hscx_read_fifo(int, void *, size_t, struct l1_softc *); static void hscx_write_fifo(int, void *, size_t, struct l1_softc *); static void avm_pnp_hscx_int_handler(struct l1_softc *); static void avm_pnp_hscx_intr(int, u_int, u_int, struct l1_softc *); static void avm_pnp_init_linktab(struct l1_softc *); static void avm_pnp_bchannel_setup(int, int, int, int); static void avm_pnp_bchannel_start(int, int); static void avm_pnp_hscx_init(struct l1_softc *, int, int); static void avm_pnp_bchannel_stat(int, int, bchan_statistics_t *); static void avm_pnp_set_linktab(int, int, drvr_link_t *); static isdn_link_t * avm_pnp_ret_linktab(int, int); static int avm_pnp_probe(device_t); static int avm_pnp_hscx_fifo(l1_bchan_state_t *, struct l1_softc *); int avm_pnp_attach(device_t); static void ifpnp_isac_intr(struct l1_softc *sc); static device_method_t avm_pnp_methods[] = { /* Device interface */ DEVMETHOD(device_probe, avm_pnp_probe), DEVMETHOD(device_attach, avm_pnp_attach), { 0, 0 } }; static driver_t avm_pnp_driver = { "ifpnp", avm_pnp_methods, sizeof(struct l1_softc) }; static devclass_t avm_pnp_devclass; DRIVER_MODULE(avm_pnp, isa, avm_pnp_driver, avm_pnp_devclass, 0, 0); /* jump table for multiplex routines */ struct i4b_l1mux_func avm_pnp_l1mux_func = { avm_pnp_ret_linktab, avm_pnp_set_linktab, ifpnp_mph_command_req, ifpnp_ph_data_req, ifpnp_ph_activate_req, }; struct l1_softc *ifpnp_scp[IFPNP_MAXUNIT]; /*---------------------------------------------------------------------------* * AVM PnP Fritz!Card special registers *---------------------------------------------------------------------------*/ /* * register offsets from i/o base */ #define CLASS_OFFSET 0x00 #define REVISION_OFFSET 0x01 #define STAT0_OFFSET 0x02 #define STAT1_OFFSET 0x03 #define ADDR_REG_OFFSET 0x04 /*#define MODREG_OFFSET 0x06 #define VERREG_OFFSET 0x07*/ /* these 2 are used to select an ISAC register set */ #define ISAC_LO_REG_OFFSET 0x04 #define ISAC_HI_REG_OFFSET 0x06 /* offset higher than this goes to the HI register set */ #define MAX_LO_REG_OFFSET 0x2f /* mask for the offset */ #define ISAC_REGSET_MASK 0x0f /* the offset from the base to the ISAC registers */ #define ISAC_REG_OFFSET 0x10 /* the offset from the base to the ISAC FIFO */ #define ISAC_FIFO 0x02 /* not really the HSCX, but sort of */ #define HSCX_FIFO 0x00 #define HSCX_STAT 0x04 /* * AVM PnP Status Latch 0 read only bits */ #define ASL_IRQ_ISAC 0x01 /* ISAC interrupt, active low */ #define ASL_IRQ_HSCX 0x02 /* HSX interrupt, active low */ #define ASL_IRQ_TIMER 0x04 /* Timer interrupt, active low */ #define ASL_IRQ_BCHAN ASL_IRQ_HSCX /* actually active LOW */ #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 */ #define ASL_TESTBIT 0x10 /* active high */ /* * AVM Status Latch 1 write only bits */ #define ASL1_INTSEL 0x0f /* active high */ #define ASL1_ENABLE_IOM 0x80 /* active high */ /* * "HSCX" mode bits */ #define HSCX_MODE_ITF_FLG 0x01 #define HSCX_MODE_TRANS 0x02 #define HSCX_MODE_CCR_7 0x04 #define HSCX_MODE_CCR_16 0x08 #define HSCX_MODE_TESTLOOP 0x80 /* * "HSCX" status bits */ #define HSCX_STAT_RME 0x01 #define HSCX_STAT_RDO 0x10 #define HSCX_STAT_CRCVFRRAB 0x0E #define HSCX_STAT_CRCVFR 0x06 #define HSCX_STAT_RML_MASK 0x3f00 /* * "HSCX" interrupt bits */ #define HSCX_INT_XPR 0x80 #define HSCX_INT_XDU 0x40 #define HSCX_INT_RPR 0x20 #define HSCX_INT_MASK 0xE0 /* * "HSCX" command bits */ #define HSCX_CMD_XRS 0x80 #define HSCX_CMD_XME 0x01 #define HSCX_CMD_RRS 0x20 #define HSCX_CMD_XML_MASK 0x3f00 /* * to prevent deactivating the "HSCX" when both channels are active we * define an HSCX_ACTIVE flag which is or'd into the channel's state * flag in avm_pnp_bchannel_setup upon active and cleared upon deactivation. * It is set high to allow room for new flags. */ #define HSCX_AVMA1PP_ACTIVE 0x1000 /*---------------------------------------------------------------------------* * AVM read fifo routines *---------------------------------------------------------------------------*/ static void avm_pnp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, ISAC_FIFO); bus_space_read_multi_1(btag, bhandle, ISAC_REG_OFFSET, buf, size); break; case ISIC_WHAT_HSCXA: hscx_read_fifo(0, buf, size, sc); break; case ISIC_WHAT_HSCXB: hscx_read_fifo(1, buf, size, sc); break; } } static void hscx_read_fifo(int chan, void *buf, size_t len, struct l1_softc *sc) { u_int8_t *ip; size_t cnt; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, chan); ip = (u_int8_t *)buf; cnt = 0; while (cnt++ < len) { *ip++ = bus_space_read_1(btag, bhandle, ISAC_REG_OFFSET); } } /*---------------------------------------------------------------------------* * AVM write fifo routines *---------------------------------------------------------------------------*/ static void avm_pnp_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, ISAC_FIFO); bus_space_write_multi_1(btag, bhandle, ISAC_REG_OFFSET, (u_int8_t*)buf, size); break; case ISIC_WHAT_HSCXA: hscx_write_fifo(0, buf, size, sc); break; case ISIC_WHAT_HSCXB: hscx_write_fifo(1, buf, size, sc); break; } } static void hscx_write_fifo(int chan, void *buf, size_t len, struct l1_softc *sc) { u_int8_t *ip; size_t cnt; l1_bchan_state_t *Bchan = &sc->sc_chan[chan]; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); sc->avma1pp_cmd &= ~HSCX_CMD_XME; sc->avma1pp_txl = 0; if (Bchan->out_mbuf_cur == NULL) { if (Bchan->bprot != BPROT_NONE) sc->avma1pp_cmd |= HSCX_CMD_XME; } if (len != sc->sc_bfifolen) sc->avma1pp_txl = len; hscx_write_reg(chan, HSCX_STAT, sc, 3); ip = (u_int8_t *)buf; cnt = 0; while (cnt++ < len) { bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET, *ip++); } } /*---------------------------------------------------------------------------* * AVM write register routines *---------------------------------------------------------------------------*/ static void avm_pnp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { u_char reg_bank; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; /* set the register bank */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, reg_bank); bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET + (offs & ISAC_REGSET_MASK), data); break; case ISIC_WHAT_HSCXA: hscx_write_reg_val(0, offs, data, sc); break; case ISIC_WHAT_HSCXB: hscx_write_reg_val(1, offs, data, sc); break; } } static void hscx_write_reg(int chan, u_int off, struct l1_softc *sc, u_int which) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* point at the correct channel */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, chan); if (which & 4) bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET + off + 2, sc->avma1pp_prot); if (which & 2) bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET + off + 1, sc->avma1pp_txl); if (which & 1) bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET + off, sc->avma1pp_cmd); } static void hscx_write_reg_val(int chan, u_int off, u_int8_t val, struct l1_softc *sc) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* point at the correct channel */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, chan); bus_space_write_1(btag, bhandle, ISAC_REG_OFFSET + off, val); } /*---------------------------------------------------------------------------* * AVM read register routines *---------------------------------------------------------------------------*/ static u_int8_t avm_pnp_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { u_char reg_bank; bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: reg_bank = (offs > MAX_LO_REG_OFFSET) ? ISAC_HI_REG_OFFSET:ISAC_LO_REG_OFFSET; /* set the register bank */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, reg_bank); return(bus_space_read_1(btag, bhandle, ISAC_REG_OFFSET + (offs & ISAC_REGSET_MASK))); case ISIC_WHAT_HSCXA: return hscx_read_reg(0, offs, sc); case ISIC_WHAT_HSCXB: return hscx_read_reg(1, offs, sc); } return 0; } static u_int hscx_read_reg(int chan, u_int off, struct l1_softc *sc) { bus_space_handle_t bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_tag_t btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* point at the correct channel */ bus_space_write_1(btag, bhandle, ADDR_REG_OFFSET, chan); return(bus_space_read_1(btag, bhandle, ISAC_REG_OFFSET + off)); } static struct ifpnp_ids { u_long vend_id; char *id_str; } ifpnp_ids[] = { { 0x0009cd06, "AVM Fritz!Card PnP" }, { 0, 0 } }; /*---------------------------------------------------------------------------* * avm_pnp_probe - probe for a card *---------------------------------------------------------------------------*/ static int avm_pnp_probe(dev) device_t dev; { struct ifpnp_ids *ids; /* pnp id's */ char *string = NULL; /* the name */ u_int32_t vend_id = isa_get_vendorid(dev); /* vendor id */ /* search table of knowd id's */ for(ids = ifpnp_ids; ids->vend_id != 0; ids++) { if(vend_id == ids->vend_id) { string = ids->id_str; break; } } if(string) /* set name if we have one */ { device_set_desc(dev, string); /* set description */ return 0; } else { return ENXIO; } } /*---------------------------------------------------------------------------* * avm_pnp_attach - attach Fritz!Card PnP *---------------------------------------------------------------------------*/ int avm_pnp_attach(device_t dev) { struct l1_softc *sc; u_int v; int unit, error = 0; int s; u_int16_t vid; void *ih = 0; bus_space_handle_t bhandle; bus_space_tag_t btag; s = splimp(); vid = isa_get_vendorid(dev); sc = device_get_softc(dev); unit = device_get_unit(dev); bzero(sc, sizeof(struct l1_softc)); /* probably not really required */ if(unit > IFPNP_MAXUNIT) { printf("avm_pnp%d: Error, unit > IFPNP_MAXUNIT!\n", unit); splx(s); return(ENXIO); } ifpnp_scp[unit] = sc; /* get io_base */ if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0UL, ~0UL, 1, RF_ACTIVE ) )) { printf("avm_pnp_attach: Couldn't get my io_base.\n"); return ENXIO; } if (sc->sc_resources.io_base[0] == NULL) { printf("avm_pnp%d: couldn't map IO port\n", unit); error = ENXIO; goto fail; } bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); btag = rman_get_bustag(sc->sc_resources.io_base[0]); /* will not be used for pnp devices */ sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); /* get irq, release io_base if we don't get it */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0UL, ~0UL, 1, RF_ACTIVE))) { printf("avm_pnp%d: Could not get irq.\n",unit); error = ENXIO; goto fail; } /* not needed */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); bus_setup_intr(dev,sc->sc_resources.irq,INTR_TYPE_NET, (void(*)(void*))avm_pnp_intr, sc,&ih); sc->sc_unit = unit; /* end of new-bus stuff */ ISAC_BASE = (caddr_t)ISIC_WHAT_ISAC; HSCX_A_BASE = (caddr_t)ISIC_WHAT_HSCXA; HSCX_B_BASE = (caddr_t)ISIC_WHAT_HSCXB; /* setup access routines */ sc->clearirq = NULL; sc->readreg = avm_pnp_read_reg; sc->writereg = avm_pnp_write_reg; sc->readfifo = avm_pnp_read_fifo; sc->writefifo = avm_pnp_write_fifo; /* setup card type */ sc->sc_cardtyp = CARD_TYPEP_AVM_PNP; /* setup IOM bus type */ sc->sc_bustyp = BUS_TYPE_IOM2; /* set up some other miscellaneous things */ sc->sc_ipac = 0; sc->sc_bfifolen = HSCX_FIFO_LEN; /* reset the card */ /* the Linux driver does this to clear any pending ISAC interrupts */ v = 0; v = ISAC_READ(I_STAR); v = ISAC_READ(I_MODE); v = ISAC_READ(I_ADF2); v = ISAC_READ(I_ISTA); if (v & ISAC_ISTA_EXI) { v = ISAC_READ(I_EXIR); } v = ISAC_READ(I_CIRR); ISAC_WRITE(I_MASK, 0xff); /* the Linux driver does this to clear any pending HSCX interrupts */ v = hscx_read_reg(0, HSCX_STAT, sc); v = hscx_read_reg(1, HSCX_STAT, sc); bus_space_write_1(btag, bhandle, STAT0_OFFSET, ASL_RESET_ALL|ASL_TIMERDISABLE); DELAY(SEC_DELAY/100); /* 10 ms */ bus_space_write_1(btag, bhandle, STAT1_OFFSET, ASL1_ENABLE_IOM|sc->sc_irq); DELAY(SEC_DELAY/100); /* 10 ms */ bus_space_write_1(btag, bhandle, STAT0_OFFSET, ASL_TIMERRESET|ASL_ENABLE_INT|ASL_TIMERDISABLE); DELAY(SEC_DELAY/100); /* 10 ms */ printf("ifpnp%d: AVM Fritz!Card PnP Class %#x Revision %d \n", unit, bus_space_read_1(btag, bhandle, CLASS_OFFSET), bus_space_read_1(btag, bhandle, REVISION_OFFSET)); printf("ifpnp%d: ISAC %s (IOM-%c)\n", unit, "2085 Version A1/A2 or 2086/2186 Version 1.1", sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2'); /* init the ISAC */ ifpnp_isac_init(sc); /* init the "HSCX" */ avm_pnp_bchannel_setup(sc->sc_unit, HSCX_CH_A, BPROT_NONE, 0); avm_pnp_bchannel_setup(sc->sc_unit, HSCX_CH_B, BPROT_NONE, 0); /* can't use the normal B-Channel stuff */ avm_pnp_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; callout_handle_init(&sc->sc_T3_callout); callout_handle_init(&sc->sc_T4_callout); /* init higher protocol layers */ i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &avm_pnp_l1mux_func); fail: splx(s); return(error); } /* * this is the real interrupt routine */ static void avm_pnp_hscx_intr(int h_chan, u_int stat, u_int cnt, struct l1_softc *sc) { register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int activity = -1; NDBGL1(L1_H_IRQ, "%#x", stat); if((stat & HSCX_INT_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */ { chan->stat_XDU++; NDBGL1(L1_H_XFRERR, "xmit data underrun"); /* abort the transmission */ sc->avma1pp_txl = 0; sc->avma1pp_cmd |= HSCX_CMD_XRS; hscx_write_reg(h_chan, HSCX_STAT, sc, 1); sc->avma1pp_cmd &= ~HSCX_CMD_XRS; hscx_write_reg(h_chan, HSCX_STAT, sc, 1); 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; } } /* * The following is based on examination of the Linux driver. * * The logic here is different than with a "real" HSCX; all kinds * of information (interrupt/status bits) are in stat. * HSCX_INT_RPR indicates a receive interrupt * HSCX_STAT_RDO indicates an overrun condition, abort - * otherwise read the bytes ((stat & HSCX_STZT_RML_MASK) >> 8) * HSCX_STAT_RME indicates end-of-frame and apparently any * CRC/framing errors are only reported in this state. * if ((stat & HSCX_STAT_CRCVFRRAB) != HSCX_STAT_CRCVFR) * CRC/framing error */ if(stat & HSCX_INT_RPR) { register int fifo_data_len; int error = 0; /* always have to read the FIFO, so use a scratch buffer */ u_char scrbuf[HSCX_FIFO_LEN]; if(stat & HSCX_STAT_RDO) { chan->stat_RDO++; NDBGL1(L1_H_XFRERR, "receive data overflow"); error++; } /* * check whether we're receiving data for an inactive B-channel * and discard it. This appears to happen for telephony when * both B-channels are active and one is deactivated. Since * it is not really possible to deactivate the channel in that * case (the ASIC seems to deactivate _both_ channels), the * "deactivated" channel keeps receiving data which can lead * to exhaustion of mbufs and a kernel panic. * * This is a hack, but it's the only solution I can think of * without having the documentation for the ASIC. * GJ - 28 Nov 1999 */ if (chan->state == HSCX_IDLE) { NDBGL1(L1_H_XFRERR, "toss data from %d", h_chan); error++; } fifo_data_len = cnt; if(fifo_data_len == 0) fifo_data_len = sc->sc_bfifolen; /* ALWAYS read data from HSCX fifo */ HSCX_RDFIFO(h_chan, scrbuf, fifo_data_len); chan->rxcount += fifo_data_len; /* 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 avm_pnp_hscx_intr: RME, cannot allocate mbuf!\n"); chan->in_cbptr = chan->in_mbuf->m_data; chan->in_len = 0; } if((chan->in_len + fifo_data_len) <= BCH_MAX_DATALEN) { /* OK to copy the data */ bcopy(scrbuf, chan->in_cbptr, fifo_data_len); chan->in_cbptr += fifo_data_len; chan->in_len += 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 = L0IFPNPUNIT(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); i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); } if (stat & HSCX_STAT_RME) { if((stat & HSCX_STAT_CRCVFRRAB) == HSCX_STAT_CRCVFR) { (*chan->isic_drvr_linktab->bch_rx_data_ready)(chan->isic_drvr_linktab->unit); activity = ACT_RX; /* mark buffer ptr as unused */ chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } else { chan->stat_CRC++; NDBGL1(L1_H_XFRERR, "CRC/RAB"); if (chan->in_mbuf != NULL) { i4b_Bfreembuf(chan->in_mbuf); chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } } } } /* END enough space in mbuf */ 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 = L0IFPNPUNIT(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); i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); } if(!(i4b_l1_bchan_tel_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len))) activity = ACT_RX; /* move rx'd data to rx queue */ if (!(IF_QFULL(&chan->rx_queue))) { IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf); } else { i4b_Bfreembuf(chan->in_mbuf); } /* signal upper layer that data are available */ (*chan->isic_drvr_linktab->bch_rx_data_ready)(chan->isic_drvr_linktab->unit); /* alloc new buffer */ if((chan->in_mbuf = i4b_Bgetmbuf(BCH_MAX_DATALEN)) == NULL) panic("L1 avm_pnp_hscx_intr: RPF, cannot allocate new mbuf!\n"); /* setup new data ptr */ chan->in_cbptr = chan->in_mbuf->m_data; /* OK to copy the data */ bcopy(scrbuf, chan->in_cbptr, fifo_data_len); chan->in_cbptr += fifo_data_len; chan->in_len = fifo_data_len; chan->rxcount += fifo_data_len; } else { NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", chan->in_len); chan->in_cbptr = chan->in_mbuf->m_data; chan->in_len = 0; } } } /* if(error == 0) */ else { /* land here for RDO */ if (chan->in_mbuf != NULL) { i4b_Bfreembuf(chan->in_mbuf); chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } sc->avma1pp_txl = 0; sc->avma1pp_cmd |= HSCX_CMD_RRS; hscx_write_reg(h_chan, HSCX_STAT, sc, 1); sc->avma1pp_cmd &= ~HSCX_CMD_RRS; hscx_write_reg(h_chan, HSCX_STAT, sc, 1); } } /* transmit fifo empty, new data can be written to fifo */ if(stat & HSCX_INT_XPR) { /* * for a description what is going on here, please have * a look at isic_bchannel_start() in i4b_bchan.c ! */ NDBGL1(L1_H_IRQ, "unit %d, chan %d - XPR, Tx Fifo Empty!", 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->isic_drvr_linktab->bch_tx_queue_empty)(chan->isic_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 = L0IFPNPUNIT(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); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } if(chan->bprot == BPROT_NONE) { if(!(i4b_l1_bchan_tel_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len))) activity = ACT_TX; } else { activity = ACT_TX; } } } avm_pnp_hscx_fifo(chan, sc); } /* call timeout handling routine */ if(activity == ACT_RX || activity == ACT_TX) (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity); } /* * this is the main routine which checks each channel and then calls * the real interrupt routine as appropriate */ static void avm_pnp_hscx_int_handler(struct l1_softc *sc) { u_char stat = 0; u_char cnt = 0; stat = hscx_read_reg(0, HSCX_STAT, sc); if (stat & HSCX_INT_RPR) cnt = hscx_read_reg(0, HSCX_STAT+1, sc); if (stat & HSCX_INT_MASK) avm_pnp_hscx_intr(0, stat, cnt, sc); cnt = 0; stat = hscx_read_reg(1, HSCX_STAT, sc); if (stat & HSCX_INT_RPR) cnt = hscx_read_reg(1, HSCX_STAT+1, sc); if (stat & HSCX_INT_MASK) avm_pnp_hscx_intr(1, stat, cnt, sc); } static void avm_pnp_intr(void *xsc) { u_char stat; struct l1_softc *sc; bus_space_handle_t bhandle; bus_space_tag_t btag; sc = xsc; bhandle = rman_get_bushandle(sc->sc_resources.io_base[0]); btag = rman_get_bustag(sc->sc_resources.io_base[0]); stat = bus_space_read_1(btag, bhandle, STAT0_OFFSET); NDBGL1(L1_H_IRQ, "stat %x", stat); /* was there an interrupt from this card ? */ if ((stat & ASL_IRQ_Pending) == ASL_IRQ_Pending) return; /* no */ /* interrupts are low active */ if (!(stat & ASL_IRQ_TIMER)) NDBGL1(L1_H_IRQ, "timer interrupt ???"); if (!(stat & ASL_IRQ_HSCX)) { NDBGL1(L1_H_IRQ, "HSCX"); avm_pnp_hscx_int_handler(sc); } if (!(stat & ASL_IRQ_ISAC)) { NDBGL1(L1_H_IRQ, "ISAC"); ifpnp_isac_intr(sc); } } static void avm_pnp_hscx_init(struct l1_softc *sc, int h_chan, int activate) { l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", sc->sc_unit, h_chan, activate ? "activate" : "deactivate"); if (activate == 0) { /* only deactivate if both channels are idle */ if (sc->sc_chan[HSCX_CH_A].state != HSCX_IDLE || sc->sc_chan[HSCX_CH_B].state != HSCX_IDLE) { return; } sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; sc->avma1pp_prot = HSCX_MODE_TRANS; hscx_write_reg(h_chan, HSCX_STAT, sc, 5); return; } if(chan->bprot == BPROT_RHDLC) { NDBGL1(L1_BCHAN, "BPROT_RHDLC"); /* HDLC Frames, transparent mode 0 */ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; sc->avma1pp_prot = HSCX_MODE_ITF_FLG; hscx_write_reg(h_chan, HSCX_STAT, sc, 5); sc->avma1pp_cmd = HSCX_CMD_XRS; hscx_write_reg(h_chan, HSCX_STAT, sc, 1); sc->avma1pp_cmd = 0; } else { NDBGL1(L1_BCHAN, "BPROT_NONE??"); /* Raw Telephony, extended transparent mode 1 */ sc->avma1pp_cmd = HSCX_CMD_XRS|HSCX_CMD_RRS; sc->avma1pp_prot = HSCX_MODE_TRANS; hscx_write_reg(h_chan, HSCX_STAT, sc, 5); sc->avma1pp_cmd = HSCX_CMD_XRS; hscx_write_reg(h_chan, HSCX_STAT, sc, 1); sc->avma1pp_cmd = 0; } } static void avm_pnp_bchannel_setup(int unit, int h_chan, int bprot, int activate) { struct l1_softc *sc = ifpnp_scp[unit]; l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s = SPLI4B(); if(activate == 0) { /* deactivation */ chan->state = HSCX_IDLE; avm_pnp_hscx_init(sc, h_chan, activate); } NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", 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 */ avm_pnp_hscx_init(sc, h_chan, activate); chan->state |= HSCX_AVMA1PP_ACTIVE; } splx(s); } static void avm_pnp_bchannel_start(int unit, int h_chan) { struct l1_softc *sc = ifpnp_scp[unit]; register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s; int activity = -1; 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(!(i4b_l1_bchan_tel_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 = L0IFPNPUNIT(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); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } avm_pnp_hscx_fifo(chan, sc); /* call timeout handling routine */ if(activity == ACT_RX || activity == ACT_TX) (*chan->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity); splx(s); } /*---------------------------------------------------------------------------* * return the address of isic drivers linktab *---------------------------------------------------------------------------*/ static isdn_link_t * avm_pnp_ret_linktab(int unit, int channel) { struct l1_softc *sc = ifpnp_scp[unit]; l1_bchan_state_t *chan = &sc->sc_chan[channel]; return(&chan->isic_isdn_linktab); } /*---------------------------------------------------------------------------* * set the driver linktab in the b channel softc *---------------------------------------------------------------------------*/ static void avm_pnp_set_linktab(int unit, int channel, drvr_link_t *dlt) { struct l1_softc *sc = ifpnp_scp[unit]; l1_bchan_state_t *chan = &sc->sc_chan[channel]; chan->isic_drvr_linktab = dlt; } /*---------------------------------------------------------------------------* * initialize our local linktab *---------------------------------------------------------------------------*/ static void avm_pnp_init_linktab(struct l1_softc *sc) { l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A]; isdn_link_t *lt = &chan->isic_isdn_linktab; /* make sure the hardware driver is known to layer 4 */ /* avoid overwriting if already set */ if (ctrl_types[CTRL_PASSIVE].set_linktab == NULL) { ctrl_types[CTRL_PASSIVE].set_linktab = avm_pnp_set_linktab; ctrl_types[CTRL_PASSIVE].get_linktab = avm_pnp_ret_linktab; } /* local setup */ lt->unit = sc->sc_unit; lt->channel = HSCX_CH_A; lt->bch_config = avm_pnp_bchannel_setup; lt->bch_tx_start = avm_pnp_bchannel_start; lt->bch_stat = avm_pnp_bchannel_stat; lt->tx_queue = &chan->tx_queue; /* used by non-HDLC data transfers, i.e. telephony drivers */ lt->rx_queue = &chan->rx_queue; /* used by HDLC data transfers, i.e. ipr and isp drivers */ lt->rx_mbuf = &chan->in_mbuf; chan = &sc->sc_chan[HSCX_CH_B]; lt = &chan->isic_isdn_linktab; lt->unit = sc->sc_unit; lt->channel = HSCX_CH_B; lt->bch_config = avm_pnp_bchannel_setup; lt->bch_tx_start = avm_pnp_bchannel_start; lt->bch_stat = avm_pnp_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; } /* * use this instead of isic_bchannel_stat in i4b_bchan.c because it's static */ static void avm_pnp_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp) { struct l1_softc *sc = ifpnp_scp[unit]; l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s; s = SPLI4B(); bsp->outbytes = chan->txcount; bsp->inbytes = chan->rxcount; chan->txcount = 0; chan->rxcount = 0; splx(s); } /*---------------------------------------------------------------------------* * fill HSCX fifo with data from the current mbuf * Put this here until it can go into i4b_hscx.c *---------------------------------------------------------------------------*/ static int avm_pnp_hscx_fifo(l1_bchan_state_t *chan, struct l1_softc *sc) { int len; int nextlen; int i; int cmd = 0; /* using a scratch buffer simplifies writing to the FIFO */ u_char scrbuf[HSCX_FIFO_LEN]; len = 0; /* * 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(chan->out_mbuf_cur && len != sc->sc_bfifolen) { nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len); #ifdef NOTDEF printf("i:mh=%p, mc=%p, mcp=%p, 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, nextlen); #endif cmd |= HSCX_CMDR_XTF; /* collect the data in the scratch buffer */ for (i = 0; i < nextlen; i++) scrbuf[i + len] = chan->out_mbuf_cur_ptr[i]; 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 = L0IFPNPUNIT(sc->sc_unit); hdr.type = (chan->channel == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2); hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_bcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 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; } } } /* write what we have from the scratch buf to the HSCX fifo */ if (len != 0) HSCX_WRFIFO(chan->channel, scrbuf, len); return(cmd); } /*---------------------------------------------------------------------------* * ifpnp - ISAC interrupt routine *---------------------------------------------------------------------------*/ static void ifpnp_isac_intr(struct l1_softc *sc) { register u_char isac_irq_stat; for(;;) { /* get isac irq status */ isac_irq_stat = ISAC_READ(I_ISTA); if(isac_irq_stat) ifpnp_isac_irq(sc, isac_irq_stat); /* isac handler */ else break; } ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASK, ISAC_IMASK); } /*---------------------------------------------------------------------------* * ifpnp_recover - try to recover from irq lockup *---------------------------------------------------------------------------*/ void ifpnp_recover(struct l1_softc *sc) { u_char byte; /* get isac irq status */ byte = ISAC_READ(I_ISTA); NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte); if(byte & ISAC_ISTA_EXI) NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR)); if(byte & ISAC_ISTA_CISQ) { byte = ISAC_READ(I_CIRR); NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte); if(byte & ISAC_CIRR_SQC) NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR)); } NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK); ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASK, ISAC_IMASK); } #endif /* NIFPNP > 0 */ Index: head/sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c =================================================================== --- head/sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c (revision 67972) +++ head/sys/i4b/layer1/ifpnp/i4b_ifpnp_isac.c (revision 67973) @@ -1,667 +1,666 @@ /* * Copyright (c) 1997, 2000 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_ifpnp_isac.c - i4b Fritz PnP ISAC handler * --------------------------------------------- * * $Id: i4b_ifpnp_isac.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_isac.c,v 1.4 2000/04/18 08:03:05 ust Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 15:24:49 2000] * *---------------------------------------------------------------------------*/ #include "ifpnp.h" #if (NIFPNP > 0) #include "opt_i4b.h" #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include static u_char ifpnp_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); static void ifpnp_isac_ind_hdlr(register struct l1_softc *sc, int ind); /*---------------------------------------------------------------------------* * ISAC interrupt service routine *---------------------------------------------------------------------------*/ void ifpnp_isac_irq(struct l1_softc *sc, int ista) { register u_char c = 0; NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); if(ista & ISAC_ISTA_EXI) /* extended interrupt */ { c |= ifpnp_isac_exir_hdlr(sc, ISAC_READ(I_EXIR)); } if(ista & ISAC_ISTA_RME) /* receive message end */ { register int rest; u_char rsta; /* get rx status register */ rsta = ISAC_READ(I_RSTA); if((rsta & ISAC_RSTA_MASK) != 0x20) { int error = 0; if(!(rsta & ISAC_RSTA_CRC)) /* CRC error */ { error++; NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); } if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ { error++; NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); } if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ { error++; NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); } if(error == 0) NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); ISACCMDRWRDELAY(); return; } rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); if(rest == 0) rest = ISAC_FIFO_LEN; if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) sc->sc_ib = sc->sc_ibuf->m_data; else panic("ifpnp_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 = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_D; hdr.dir = FROM_NT; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); } c |= ISAC_CMDR_RMC; if(sc->sc_enabled && (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) { i4b_l1_ph_data_ind(L0IFPNPUNIT(sc->sc_unit), sc->sc_ibuf); } else { i4b_Dfreembuf(sc->sc_ibuf); } } else { NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; } if(ista & ISAC_ISTA_RPF) /* receive fifo full */ { if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) sc->sc_ib= sc->sc_ibuf->m_data; else panic("ifpnp_isac_irq: RPF, i4b_Dgetmbuf returns NULL!\n"); sc->sc_ilen = 0; } if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISAC_FIFO_LEN)) { ISAC_RDFIFO(sc->sc_ib, ISAC_FIFO_LEN); sc->sc_ilen += ISAC_FIFO_LEN; sc->sc_ib += ISAC_FIFO_LEN; c |= ISAC_CMDR_RMC; } else { NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } } if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ { if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) { sc->sc_freeflag = sc->sc_freeflag2; sc->sc_obuf = sc->sc_obuf2; sc->sc_op = sc->sc_obuf->m_data; sc->sc_ol = sc->sc_obuf->m_len; sc->sc_obuf2 = NULL; #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) ifpnp_isac_ind_hdlr(sc, (ci >> 2) & 0xf); } if(c) { ISAC_WRITE(I_CMDR, c); ISACCMDRWRDELAY(); } } /*---------------------------------------------------------------------------* * ISAC L1 Extended IRQ handler *---------------------------------------------------------------------------*/ static u_char ifpnp_isac_exir_hdlr(register struct l1_softc *sc, u_char exir) { u_char c = 0; if(exir & ISAC_EXIR_XMR) { NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); c |= ISAC_CMDR_XRES; } if(exir & ISAC_EXIR_XDU) { NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); c |= ISAC_CMDR_XRES; } if(exir & ISAC_EXIR_PCE) { NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); } if(exir & ISAC_EXIR_RFO) { NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } if(exir & ISAC_EXIR_SOV) { NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); } if(exir & ISAC_EXIR_MOS) { NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); } if(exir & ISAC_EXIR_SAW) { /* cannot happen, STCR:TSF is set to 0 */ NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); } if(exir & ISAC_EXIR_WOV) { /* cannot happen, STCR:TSF is set to 0 */ NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); } return(c); } /*---------------------------------------------------------------------------* * ISAC L1 Indication handler *---------------------------------------------------------------------------*/ static void ifpnp_isac_ind_hdlr(register struct l1_softc *sc, int ind) { register int event; switch(ind) { case ISAC_CIRR_IAI8: NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpnp_printstate(sc)); if(sc->sc_bustyp == BUS_TYPE_IOM2) ifpnp_isac_l1_cmd(sc, CMD_AR8); event = EV_INFO48; i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); break; case ISAC_CIRR_IAI10: NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpnp_printstate(sc)); if(sc->sc_bustyp == BUS_TYPE_IOM2) ifpnp_isac_l1_cmd(sc, CMD_AR10); event = EV_INFO410; i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); break; case ISAC_CIRR_IRSY: NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpnp_printstate(sc)); event = EV_RSY; break; case ISAC_CIRR_IPU: NDBGL1(L1_I_CICO, "rx PU in state %s", ifpnp_printstate(sc)); event = EV_PU; break; case ISAC_CIRR_IDR: NDBGL1(L1_I_CICO, "rx DR in state %s", ifpnp_printstate(sc)); ifpnp_isac_l1_cmd(sc, CMD_DIU); event = EV_DR; break; case ISAC_CIRR_IDID: NDBGL1(L1_I_CICO, "rx DID in state %s", ifpnp_printstate(sc)); event = EV_INFO0; i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL); break; case ISAC_CIRR_IDIS: NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpnp_printstate(sc)); event = EV_DIS; break; case ISAC_CIRR_IEI: NDBGL1(L1_I_CICO, "rx EI in state %s", ifpnp_printstate(sc)); ifpnp_isac_l1_cmd(sc, CMD_DIU); event = EV_EI; break; case ISAC_CIRR_IARD: NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpnp_printstate(sc)); event = EV_INFO2; break; case ISAC_CIRR_ITI: NDBGL1(L1_I_CICO, "rx TI in state %s", ifpnp_printstate(sc)); event = EV_INFO0; break; case ISAC_CIRR_IATI: NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpnp_printstate(sc)); event = EV_INFO0; break; case ISAC_CIRR_ISD: NDBGL1(L1_I_CICO, "rx SD in state %s", ifpnp_printstate(sc)); event = EV_INFO0; break; default: NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpnp_printstate(sc)); event = EV_INFO0; break; } ifpnp_next_state(sc, event); } /*---------------------------------------------------------------------------* * execute a layer 1 command *---------------------------------------------------------------------------*/ void ifpnp_isac_l1_cmd(struct l1_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) { NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpnp_printstate(sc)); return; } if(sc->sc_bustyp == BUS_TYPE_IOM2) cmd = ISAC_CIX0_LOW; else cmd = 0; switch(command) { case CMD_TIM: NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpnp_printstate(sc)); cmd |= (ISAC_CIXR_CTIM << 2); break; case CMD_RS: NDBGL1(L1_I_CICO, "tx RS in state %s", ifpnp_printstate(sc)); cmd |= (ISAC_CIXR_CRS << 2); break; case CMD_AR8: NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpnp_printstate(sc)); cmd |= (ISAC_CIXR_CAR8 << 2); break; case CMD_AR10: NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpnp_printstate(sc)); cmd |= (ISAC_CIXR_CAR10 << 2); break; case CMD_DIU: NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpnp_printstate(sc)); cmd |= (ISAC_CIXR_CDIU << 2); break; } ISAC_WRITE(I_CIXR, cmd); } /*---------------------------------------------------------------------------* * L1 ISAC initialization *---------------------------------------------------------------------------*/ int ifpnp_isac_init(struct l1_softc *sc) { ISAC_IMASK = 0xff; /* disable all irqs */ ISAC_WRITE(I_MASK, ISAC_IMASK); if(sc->sc_bustyp != BUS_TYPE_IOM2) { NDBGL1(L1_I_SETUP, "configuring for IOM-1 mode"); /* 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 { NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); /* ADF2: Select mode IOM-2 */ ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); /* SPCR: serial port control register: * SPU - software power up = 0 * SPM - timing mode 0 * TLP - test loop = 0 * C1C, C2C - B1 + C1 and B2 + IC2 monitoring */ ISAC_WRITE(I_SPCR, 0x00); /* SQXR: S/Q channel xmit register: * IDC - IOM direction = 0 (master) * CFS - Config Select = 0 (clock always active) * CI1E - C/I channel 1 IRQ enable = 0 * SQIE - S/Q IRQ enable = 0 * SQX1-4 - Fa bits = 1 */ ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); /* ADF1: additional feature reg 1: * WTC - watchdog = 0 * TEM - test mode = 0 * PFS - pre-filter = 0 * IOF - IOM i/f off = 0 * ITF - interframe fill = idle */ ISAC_WRITE(I_ADF1, 0x00); /* STCR: sync transfer control reg: * TSF - terminal secific functions = 0 * TBA - TIC bus address = 7 * STx/SCx = 0 */ ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); /* MODE: Mode Register: * MDSx - transparent mode 2 * TMD - timer mode = external * RAC - Receiver enabled * DIMx - digital i/f mode */ ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); } #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 /* NIFPNP > 0 */ Index: head/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c =================================================================== --- head/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c (revision 67972) +++ head/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1.c (revision 67973) @@ -1,246 +1,244 @@ /* * Copyright (c) 1997, 2000 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_ifpnp_l1.c - AVM Fritz PnP layer 1 handler * ---------------------------------------------- * * $Id: i4b_ifpnp_l1.c,v 1.4 2000/06/02 16:14:36 hm Exp $ * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_l1.c,v 1.4 2000/04/18 08:03:05 ust Exp $ * * $FreeBSD$ * * last edit-date: [Fri Jun 2 14:55:49 2000] * *---------------------------------------------------------------------------*/ #include "ifpnp.h" #if (NIFPNP > 0) #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include #include /*---------------------------------------------------------------------------* * * L2 -> L1: PH-DATA-REQUEST * ========================= * * parms: * unit physical interface unit number * m mbuf containing L2 frame to be sent out * freeflag MBUF_FREE: free mbuf here after having sent * it out * MBUF_DONTFREE: mbuf is freed by Layer 2 * returns: * ==0 fail, nothing sent out * !=0 ok, frame sent out * *---------------------------------------------------------------------------*/ int ifpnp_ph_data_req(int unit, struct mbuf *m, int freeflag) { u_char cmd; int s; struct l1_softc *sc = ifpnp_scp[unit]; #ifdef NOTDEF NDBGL1(L1_PRIM, "PH-DATA-REQ, unit %d, freeflag=%d", unit, freeflag); #endif if(m == NULL) /* failsafe */ return (0); s = SPLI4B(); if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ { NDBGL1(L1_I_ERR, "still in state F3!"); ifpnp_ph_activate_req(unit); } if(sc->sc_state & ISAC_TX_ACTIVE) { if(sc->sc_obuf2 == NULL) { sc->sc_obuf2 = m; /* save mbuf ptr */ if(freeflag) sc->sc_freeflag2 = 1; /* IRQ must mfree */ else sc->sc_freeflag2 = 0; /* IRQ must not mfree */ NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", ifpnp_printstate(sc)); if(sc->sc_trace & TRACE_D_TX) { i4b_trace_hdr_t hdr; hdr.unit = L0IFPNPUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } splx(s); return(1); } NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", ifpnp_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 = L0IFPNPUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); sc->sc_freeflag = 0; /* IRQ must NOT mfree */ ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ { sc->sc_obuf = m; /* save mbuf ptr */ sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ if(freeflag) sc->sc_freeflag = 1; /* IRQ must mfree */ cmd = ISAC_CMDR_XTF; } else { sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; if(freeflag) i4b_Dfreembuf(m); cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; } ISAC_WRITE(I_CMDR, cmd); ISACCMDRWRDELAY(); splx(s); return(1); } /*---------------------------------------------------------------------------* * * L2 -> L1: PH-ACTIVATE-REQUEST * ============================= * * parms: * unit physical interface unit number * * returns: * ==0 * !=0 * *---------------------------------------------------------------------------*/ int ifpnp_ph_activate_req(int unit) { struct l1_softc *sc = ifpnp_scp[unit]; NDBGL1(L1_PRIM, "PH-ACTIVATE-REQ, unit %d\n", unit); ifpnp_next_state(sc, EV_PHAR); return(0); } /*---------------------------------------------------------------------------* * command from the upper layers *---------------------------------------------------------------------------*/ int ifpnp_mph_command_req(int unit, int command, void *parm) { struct l1_softc *sc = ifpnp_scp[unit]; switch(command) { case CMR_DOPEN: /* daemon running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); sc->sc_enabled = 1; break; case CMR_DCLOSE: /* daemon not running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); sc->sc_enabled = 0; break; case CMR_SETTRACE: NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); sc->sc_trace = (unsigned int)parm; break; default: NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); break; } return(0); } #endif /* NIFPNP > 0 */ Index: head/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c =================================================================== --- head/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c (revision 67972) +++ head/sys/i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c (revision 67973) @@ -1,520 +1,517 @@ /* * Copyright (c) 1997, 2000 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_ifpnp_l1fsm.c - AVM Fritz PnP layer 1 I.430 state machine * ------------------------------------------------------------- * * $Id: i4b_ifpnp_l1fsm.c,v 1.4 2000/05/29 15:41:41 hm Exp $ * $Ust: src/i4b/layer1-nb/ifpnp/i4b_ifpnp_l1fsm.c,v 1.4 2000/04/18 08:03:05 ust Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 15:25:04 2000] * *---------------------------------------------------------------------------*/ #include "ifpnp.h" #if (NIFPNP > 0) #include #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include #include #if DO_I4B_DEBUG static char *state_text[N_STATES] = { "F3 Deactivated", "F4 Awaiting Signal", "F5 Identifying Input", "F6 Synchronized", "F7 Activated", "F8 Lost Framing", "Illegal State" }; static char *event_text[N_EVENTS] = { "EV_PHAR PH_ACT_REQ", "EV_T3 Timer 3 expired", "EV_INFO0 INFO0 received", "EV_RSY Level Detected", "EV_INFO2 INFO2 received", "EV_INFO48 INFO4 received", "EV_INFO410 INFO4 received", "EV_DR Deactivate Req", "EV_PU Power UP", "EV_DIS Disconnected", "EV_EI Error Ind", "Illegal Event" }; #endif /* Function prototypes */ static void timer3_expired (struct l1_softc *sc); static void T3_start (struct l1_softc *sc); static void T3_stop (struct l1_softc *sc); static void F_T3ex (struct l1_softc *sc); static void timer4_expired (struct l1_softc *sc); static void T4_start (struct l1_softc *sc); static void T4_stop (struct l1_softc *sc); static void F_AI8 (struct l1_softc *sc); static void F_AI10 (struct l1_softc *sc); static void F_I01 (struct l1_softc *sc); static void F_I02 (struct l1_softc *sc); static void F_I03 (struct l1_softc *sc); static void F_I2 (struct l1_softc *sc); static void F_ill (struct l1_softc *sc); static void F_NULL (struct l1_softc *sc); /*---------------------------------------------------------------------------* * I.430 Timer T3 expire function *---------------------------------------------------------------------------*/ static void timer3_expired(struct l1_softc *sc) { if(sc->sc_I430T3) { NDBGL1(L1_T_ERR, "state = %s", ifpnp_printstate(sc)); sc->sc_I430T3 = 0; /* XXX try some recovery here XXX */ ifpnp_recover(sc); sc->sc_init_tries++; /* increment retry count */ /*XXX*/ if(sc->sc_init_tries > 4) { int s = SPLI4B(); sc->sc_init_tries = 0; if(sc->sc_obuf2 != NULL) { i4b_Dfreembuf(sc->sc_obuf2); sc->sc_obuf2 = NULL; } if(sc->sc_obuf != NULL) { i4b_Dfreembuf(sc->sc_obuf); sc->sc_obuf = NULL; sc->sc_freeflag = 0; sc->sc_op = NULL; sc->sc_ol = 0; } splx(s); i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL); } ifpnp_next_state(sc, EV_T3); } else { NDBGL1(L1_T_ERR, "expired without starting it ...."); } } /*---------------------------------------------------------------------------* * I.430 Timer T3 start *---------------------------------------------------------------------------*/ static void T3_start(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); sc->sc_I430T3 = 1; sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz); } /*---------------------------------------------------------------------------* * I.430 Timer T3 stop *---------------------------------------------------------------------------*/ static void T3_stop(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); sc->sc_init_tries = 0; /* init connect retry count */ if(sc->sc_I430T3) { sc->sc_I430T3 = 0; untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout); } } /*---------------------------------------------------------------------------* * I.430 Timer T3 expiry *---------------------------------------------------------------------------*/ static void F_T3ex(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0IFPNPUNIT(sc->sc_unit)); } /*---------------------------------------------------------------------------* * Timer T4 expire function *---------------------------------------------------------------------------*/ static void timer4_expired(struct l1_softc *sc) { if(sc->sc_I430T4) { NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); sc->sc_I430T4 = 0; i4b_l1_mph_status_ind(L0IFPNPUNIT(sc->sc_unit), STI_PDEACT, 0, NULL); } else { NDBGL1(L1_T_ERR, "expired without starting it ...."); } } /*---------------------------------------------------------------------------* * Timer T4 start *---------------------------------------------------------------------------*/ static void T4_start(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); sc->sc_I430T4 = 1; sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz); } /*---------------------------------------------------------------------------* * Timer T4 stop *---------------------------------------------------------------------------*/ static void T4_stop(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", ifpnp_printstate(sc)); if(sc->sc_I430T4) { sc->sc_I430T4 = 0; untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout); } } /*---------------------------------------------------------------------------* * FSM function: received AI8 *---------------------------------------------------------------------------*/ static void F_AI8(struct l1_softc *sc) { T4_stop(sc); NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_activate_ind(L0IFPNPUNIT(sc->sc_unit)); T3_stop(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO4_8; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received AI10 *---------------------------------------------------------------------------*/ static void F_AI10(struct l1_softc *sc) { T4_stop(sc); NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_activate_ind(L0IFPNPUNIT(sc->sc_unit)); T3_stop(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO4_10; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in states F3 .. F5 *---------------------------------------------------------------------------*/ static void F_I01(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in state F6 *---------------------------------------------------------------------------*/ static void F_I02(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0IFPNPUNIT(sc->sc_unit)); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in state F7 or F8 *---------------------------------------------------------------------------*/ static void F_I03(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0IFPNPUNIT(sc->sc_unit)); T4_start(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: activate request *---------------------------------------------------------------------------*/ static void F_AR(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_AR executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO1_8; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_TE; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } ifpnp_isac_l1_cmd(sc, CMD_AR8); T3_start(sc); } /*---------------------------------------------------------------------------* * FSM function: received INFO2 *---------------------------------------------------------------------------*/ static void F_I2(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO2; hdr.unit = L0IFPNPUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * illegal state default action *---------------------------------------------------------------------------*/ static void F_ill(struct l1_softc *sc) { NDBGL1(L1_F_ERR, "FSM function F_ill executing"); } /*---------------------------------------------------------------------------* * No action *---------------------------------------------------------------------------*/ static void F_NULL(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); } /*---------------------------------------------------------------------------* * layer 1 state transition table *---------------------------------------------------------------------------*/ struct ifpnp_state_tab { void (*func) (struct l1_softc *sc); /* function to execute */ int newstate; /* next state */ } ifpnp_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 ifpnp_next_state(struct l1_softc *sc, int event) { int currstate, newstate; if(event >= N_EVENTS) panic("i4b_l1fsm.c: event >= N_EVENTS\n"); currstate = sc->sc_I430state; if(currstate >= N_STATES) panic("i4b_l1fsm.c: currstate >= N_STATES\n"); newstate = ifpnp_state_tab[event][currstate].newstate; if(newstate >= N_STATES) panic("i4b_l1fsm.c: newstate >= N_STATES\n"); NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], state_text[currstate], state_text[newstate]); (*ifpnp_state_tab[event][currstate].func)(sc); if(newstate == ST_ILL) { newstate = ST_F3; NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", state_text[currstate], state_text[newstate], event_text[event]); } sc->sc_I430state = newstate; } #if DO_I4B_DEBUG /*---------------------------------------------------------------------------* * return pointer to current state description *---------------------------------------------------------------------------*/ char * ifpnp_printstate(struct l1_softc *sc) { return((char *) state_text[sc->sc_I430state]); } #endif #endif /* NIFPNP > 0 */ Index: head/sys/i4b/layer1/ihfc/i4b_ihfc_drv.c =================================================================== --- head/sys/i4b/layer1/ihfc/i4b_ihfc_drv.c (revision 67972) +++ head/sys/i4b/layer1/ihfc/i4b_ihfc_drv.c (revision 67973) @@ -1,1745 +1,1744 @@ /* * Copyright (c) 2000 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *--------------------------------------------------------------------------- * * i4b_ihfc_drv.c - ihfc ISA PnP-bus interface * ------------------------------------------- * * Everything which has got anything to do with the * HFC-1/S/SP chips has been put here. * * last edit-date: [Wed Jul 19 09:39:42 2000] * * $Id: i4b_ihfc_drv.c,v 1.11 2000/09/19 13:50:36 hm Exp $ * * $FreeBSD$ * *---------------------------------------------------------------------------*/ #include "ihfc.h" #if (NIHFC > 0) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include /*---------------------------------------------------------------------------* * Local prototypes *---------------------------------------------------------------------------*/ void ihfc_loadconfig (ihfc_sc_t *sc); static void ihfc_trans_Bread (ihfc_sc_t *sc, u_char chan); static void ihfc_trans_Bwrite (ihfc_sc_t *sc, u_char chan); static void ihfc_hdlc_Bread (ihfc_sc_t *sc, u_char chan); static void ihfc_hdlc_Bwrite (ihfc_sc_t *sc, u_char chan); static void ihfc_hdlc_Dread (ihfc_sc_t *sc, u_char chan); static void ihfc_hdlc_Dwrite (ihfc_sc_t *sc, u_char chan); static void ihfc_isac_Dread (ihfc_sc_t *sc, u_char chan); static void ihfc_isac_Dwrite (ihfc_sc_t *sc, u_char chan); void ihfc_cmdr_hdlr (ihfc_sc_t *sc, u_char cmdr); void ihfc_exir_hdlr (ihfc_sc_t *sc, u_char exir); void ihfc_sq (ihfc_sc_t *sc); static void ihfc_test_Bread (ihfc_sc_t *sc, u_char chan); static void ihfc_test_Bwrite (ihfc_sc_t *sc, u_char chan); u_short ihfc_Bsel_fifo (ihfc_sc_t *sc, u_char chan, u_char flag); u_int32_t ihfc_Dsel_fifo (ihfc_sc_t *sc, u_char chan, u_char flag); /*---------------------------------------------------------------------------* * Commonly used ISA bus commands *---------------------------------------------------------------------------*/ #define IHFC_DATA_OFFSET 0 #define IHFC_REG_OFFSET 1 #define BUS_VAR bus_space_handle_t h = rman_get_bushandle(S_IOBASE[0]); \ bus_space_tag_t t = rman_get_bustag (S_IOBASE[0]) #define SET_REG(reg) bus_space_write_1(t,h, IHFC_REG_OFFSET, reg) #define GET_STAT bus_space_read_1 (t,h, IHFC_REG_OFFSET) #define READ_DATA_1 bus_space_read_1 (t,h, IHFC_DATA_OFFSET) #define READ_BOTH_2 bus_space_read_2 (t,h, IHFC_DATA_OFFSET) #define WRITE_DATA_1(data) bus_space_write_1(t,h, IHFC_DATA_OFFSET, data) #define WRITE_BOTH_2(data) bus_space_write_2(t,h, IHFC_DATA_OFFSET, data) #define DISBUSY(okcmd, tocmd) \ { \ if (GET_STAT & 1) \ { \ register u_char a; \ register u_int to = IHFC_DISBUSYTO; \ \ while(((a = GET_STAT) & 1) && --to); \ \ if (!to) \ { \ NDBGL1(L1_ERROR, "DISBUSY-TIMEOUT! (a=%04x, " \ "unit=%d)", a, S_UNIT); \ tocmd; \ } \ else \ { \ okcmd; \ } \ } \ else \ { \ okcmd; \ } \ } #define WAITBUSY_2(okcmd, tocmd) \ { \ register u_short a; \ register u_int to = IHFC_NONBUSYTO; \ \ while((~(a = READ_BOTH_2) & 0x100) && --to); \ \ if (!to) \ { \ NDBGL1(L1_ERROR, "NONBUSY-TIMEOUT! (a=%04x, " \ "unit=%d)", a, S_UNIT); \ tocmd; \ } \ else \ { \ okcmd; \ } \ } /*---------------------------------------------------------------------------* * Control function (HFC-1/S/SP) * * Flag: * 1: reset and unlock chip (at boot only) * 2: prepare for shutdown (at shutdown only) * 3: reset and resume * 4: select TE-mode (boot default) * 5: select NT-mode (only HFC-S/SP/PCI) * * Returns != 0 on errornous chip *---------------------------------------------------------------------------*/ int ihfc_control(ihfc_sc_t *sc, int flag) { BUS_VAR; if (flag == 3) goto reset0; if (flag == 4) { S_NTMODE = 0; goto mode0; } if (flag == 5) { S_NTMODE = 1; goto mode0; } if (flag == 1) { WRITE_BOTH_2(0x5400 | S_IIO); /* enable IO (HFC-1/S) */ S_LAST_CHAN = -1; /* HFC-S/SP configuration */ S_CIRM = S_IIRQ|0x10; /* IRQ, 8K fifo mode */ S_CLKDEL = 0x00; /* 12.288mhz */ S_CTMT = 0x03; /* transperant mode */ S_CONNECT = 0x00; /* B channel data flow */ S_INT_M1 = 0x40; /* interrupt mask */ S_INT_M2 = 0x08; /* enable interrupt output */ S_MST_MODE = 0x01; /* master mode */ S_SCTRL = 0x50; /* S/Q on, non cap. line mode */ S_SCTRL_R = 0x00; /* B channel receive disable */ S_TEST = 0x00; /* no need for awake enable */ if (S_HFC & (HFC_1 | HFC_S)) /* configure timer (50ms) */ { S_CTMT |= 0x08; } else { S_CTMT |= 0x14; } /* HFC-1 ISAC configuration (IOM-2 mode) */ S_ADF1 = 0x00; /* */ S_ADF2 = 0x80; /* select mode IOM-2 */ S_SPCR = 0x00; /* B channel send disable (0x10 for test loop) */ S_MASK = 0xfb; /* enable CISQ */ S_MODE = 0xc9; /* receiver enabled */ S_SQXR = 0x0f; /* master, clock always active */ S_STCR = 0x70; /* TIC bus address = 7 */ S_STAR2 = 0x04; /* enable S/Q */ mode0: if (S_NTMODE) /* configure NT- or TE-mode */ { S_SCTRL |= 0x04; /* NT mode */ S_CLKDEL &= ~0x7f; /* clear delay */ S_CLKDEL |= 0x6c; /* set delay */ } else { S_SCTRL &= ~0x04; /* TE mode */ S_STDEL &= 0x7f; /* use mask! */ S_CLKDEL &= ~0x7f; /* clear delay */ S_CLKDEL |= S_STDEL; /* set delay */ } if (S_DLP) /* configure D-priority */ { S_SCTRL |= 0x08; /* (10/11) */ } else { S_SCTRL &= ~0x08; /* (8/9) */ } reset0: /* chip reset (HFC-1/S/SP) */ if (S_HFC & HFC_1) { SET_REG((S_CIRM | 0xc8) & 0xdf); DELAY(10); /* HFC-2B manual recommends a 4 * * clock cycle delay after CIRM * * write with reset=1. A 1us * * delay, should do for 7.68mhz,* * but just in case I make that * * 10us. */ SET_REG((S_CIRM | 0xc0) & 0xdf); DELAY(250); /* ISAC manual says reset pulse * * length is 125us. Accessing * * ISAC before those 125us, we * * may risk chip corruption and * * irq failure. The HFC-2B also * * needs some delay to recover, * * so we add some us. */ } else { SET_REG(0x18); WRITE_DATA_1(S_CIRM | 8); DELAY(10); /* HFC-2BDS0 manual recommends * * a 4 clock cycle delay after * * CIRM write with reset=1. * * A 1us delay, should do for * * 12.288mhz, but just in case * * I make that 10us. */ WRITE_DATA_1(S_CIRM); DELAY(25); /* HFC-2BDS0 needs some time to * * recover after CIRM write * * with reset=0. Experiments * * show this delay should be * * 8-9us. Just in case we make * * that 25us. */ } { /* HFC-1/S/SP chip test * * * * NOTE: after reset the HFC-1/S/SP should be * * in a mode where it is always non-busy/non- * * processing, and bit[0] of STATUS/DISBUSY * * register, should always return binary '0' * * until we configure the chips for normal * * operation. */ #ifdef IHFC_DEBUG printf("ihfc: GET_STAT value is: 0x%x\n", GET_STAT); #endif SET_REG(0x30); if ((GET_STAT & 1) || (READ_DATA_1 & 0xf)) goto f0; } ihfc_loadconfig(sc); if (S_HFC & HFC_1) ihfc_cmdr_hdlr(sc, 0x41); /* rres, xres */ S_PHSTATE = 0; HFC_FSM(sc, 0); } if (flag == 2) { if (S_HFC & HFC_1) S_CIRM &= ~0x03; /* disable interrupt */ S_SQXR |= 0x40; /* power down */ S_SPCR &= ~0x0f; /* send 1's only */ S_SCTRL &= ~0x83; /* send 1's only + enable oscillator */ ihfc_loadconfig(sc); } return(0); /* success */ f0: return(1); /* failure */ } /*---------------------------------------------------------------------------* * Softc initializer and hardware setup (HFC-1/S/SP) * * Returns: 0 on success * 1 on failure *---------------------------------------------------------------------------*/ int ihfc_init (ihfc_sc_t *sc, u_char chan, int prot, int activate) { if (chan > 5) goto f0; chan &= ~1; do { if (chan < 2) /* D-Channel */ { i4b_Dfreembuf(S_MBUF); i4b_Dcleanifq(&S_IFQUEUE); RESET_SOFT_CHAN(sc, chan); S_IFQUEUE.ifq_maxlen = IFQ_MAXLEN; if (!activate) continue; if (S_HFC & HFC_1) { S_FILTER = (chan & 1) ? ihfc_isac_Dread : ihfc_isac_Dwrite; } else { S_FILTER = (chan & 1) ? ihfc_hdlc_Dread : ihfc_hdlc_Dwrite; } } else /* B-Channel */ { i4b_Bfreembuf(S_MBUF); i4b_Bcleanifq(&S_IFQUEUE); RESET_SOFT_CHAN(sc, chan); S_PROT = prot; S_IFQUEUE.ifq_maxlen = IFQ_MAXLEN; if (!activate) continue; switch(prot) { case(BPROT_NONE): S_FILTER = (chan & 1) ? ihfc_trans_Bread : ihfc_trans_Bwrite; break; case(BPROT_RHDLC): S_FILTER = (chan & 1) ? ihfc_hdlc_Bread : ihfc_hdlc_Bwrite; break; case(5): S_FILTER = (chan & 1) ? ihfc_test_Bread : ihfc_test_Bwrite; break; } } } while (++chan & 1); S_MASK |= 0xfb; /* disable all, but CISQ interrupt (ISAC) */ S_INT_M1 &= 0x40; /* disable all, but TE/NT state machine (HFC) */ S_SCTRL &= ~0x03; /* B1/B2 send disable (HFC) */ S_SPCR &= ~0x0f; /* B1/B2 send disable (ISAC) */ S_SCTRL_R &= ~0x03; /* B1/B2 receive disable (HFC) */ chan = 0; if (S_FILTER) /* D-Channel active */ { S_MASK &= 0x2e; /* enable RME, RPF, XPR, EXI */ S_INT_M1 |= 0x24; /* enable D-receive, D-transmit */ } chan = 2; if (S_FILTER) /* B1-Channel active */ { S_SCTRL |= 1; /* send enable (HFC) */ S_SPCR |= 8; /* send enable (ISAC) */ S_SCTRL_R |= 1; /* receive enable (HFC) */ S_INT_M1 |= 0x80; /* timer enable (HFC) */ S_INT_M1 &= ~0x04; /* let D-channel use timer too */ } chan = 4; if (S_FILTER) /* B2-Channel active */ { S_SCTRL |= 2; /* send enable (HFC) */ S_SPCR |= 2; /* send enable (ISAC) */ S_SCTRL_R |= 2; /* receive enable (HFC) */ S_INT_M1 |= 0x80; /* timer enable (HFC) */ S_INT_M1 &= ~0x04; /* let D-channel use timer too */ } ihfc_loadconfig(sc); /* XXX reset timer? */ return 0; /* success */ f0: return 1; /* failure */ } /*---------------------------------------------------------------------------* * Load configuration data (HFC-1/S/SP) *---------------------------------------------------------------------------*/ void ihfc_loadconfig(ihfc_sc_t *sc) { BUS_VAR; if (S_HFC & HFC_1) { /* HFC-1 chips w/ISAC: */ const u_char *src = (void *)&S_ISAC_CONFIG; const u_char *dst = (void *)&isac_configtable; SET_REG((S_CIRM | 0xc0) & 0xdf); S_CTMT = (S_CTMT & ~0x14) | ((S_INT_M1 >> 5) & 0x4); SET_REG((S_CTMT | 0xe0) & 0xff); while(*dst) { SET_REG(*dst++); /* set register */ /* write configuration */ DISBUSY(WRITE_DATA_1(*src++), break); } } else { /* HFC-S/SP chips: */ const u_char *src = (void *)&S_HFC_CONFIG; const u_char *dst = (void *)&ihfc_configtable; while(*dst) { SET_REG(*dst++); /* set register */ WRITE_DATA_1(*src++); /* write configuration */ } } } /*---------------------------------------------------------------------------* * Function State Machine handler (PH layer) (HFC-1/S/SP) * * Flag: 0 = Refresh softc S_PHSTATE + take hints * 1 = Activate * 2 = Deactivate * * NOTE: HFC-1 only supports TE mode. *---------------------------------------------------------------------------*/ void ihfc_fsm(ihfc_sc_t *sc, int flag) { const struct ihfc_FSMtable *fsmtab; u_char ihfc_cmd = 0; u_char isac_cmd = 0; u_char tmp; BUS_VAR; /* get current state (rx/downstream) */ if (S_HFC & HFC_1) { SET_REG(0x31); DISBUSY(tmp = (READ_DATA_1 >> 2) & 0xf, return); fsmtab = (S_NTMODE) ? &ihfc_TEtable2[tmp]: &ihfc_TEtable2[tmp]; } else { SET_REG(0x30); tmp = READ_DATA_1 & 0xf; fsmtab = (S_NTMODE) ? &ihfc_NTtable[tmp]: &ihfc_TEtable[tmp]; } if (fsmtab->string) { NDBGL1(L1_I_CICO, "%s (ind=0x%x, flag=%d, unit=%d).", fsmtab->string, tmp, flag, S_UNIT); } else { NDBGL1(L1_I_ERR, "Illegal indicatation (ind=0x%x, " "flag=%d, unit=%d).", tmp, flag, S_UNIT); } /* indication machine / state change * * * * Whenever the state of the S0-line changes, we check to see in which * * direction the change went. Generally upwards means activate, and * * downwards means deactivate. * * The test signal is used to ensure proper syncronization. */ if (fsmtab->state == 0) /* deactivated indication */ { if (S_PHSTATE != 0) { isac_cmd = 0x3c; /* deactivate DUI */ i4b_l1_ph_deactivate_ind(S_I4BUNIT); } } if (fsmtab->state == 2) /* syncronized indication */ { if (S_PHSTATE != 2) { if (S_NTMODE) ihfc_cmd = 0x80; } } if (fsmtab->state == 3) /* activated indication */ { if (S_PHSTATE != 3) { isac_cmd = (S_DLP) ? 0x24 /* activate AR10 */ : 0x20; /* activate AR8 */ i4b_l1_ph_activate_ind(S_I4BUNIT); } } if (fsmtab->state == 4) /* error indication */ { if (S_PHSTATE < 4) { isac_cmd = 0x3c; /* deactivate DUI */ } } S_PHSTATE = fsmtab->state; if ((flag == 1) && (fsmtab->state != 3)) { isac_cmd = (S_DLP) ? 0x24 : 0x20; ihfc_cmd = 0x60; } if ((flag == 2) && (fsmtab->state != 0)) { isac_cmd = 0x3c; ihfc_cmd = 0x40; } /* set new state (tx / upstream) * * * * NOTE: HFC-S/SP and ISAC transmitters are always active when * * activated state is reached. The bytes sent to the S0-bus are all * * high impedance, so they do not disturb. * * The HFC-1 has a seperate SIEMENS S0-device. */ if (S_HFC & HFC_1) { if (isac_cmd) { if (S_IOM2) isac_cmd |= 3; SET_REG(0x31); DISBUSY(WRITE_DATA_1(isac_cmd), ); NDBGL1(L1_I_CICO, "(isac_cmd=0x%x, unit=%d).", isac_cmd, S_UNIT); } } else { if (ihfc_cmd || (fsmtab->state == 5)) { SET_REG(0x30); WRITE_DATA_1(ihfc_cmd); NDBGL1(L1_I_CICO, "(ihfc_cmd=0x%x, unit=%d).", ihfc_cmd, S_UNIT); } } } /*---------------------------------------------------------------------------* * S/Q - channel handler (read) (HFC-S/SP) *---------------------------------------------------------------------------*/ void ihfc_sq (ihfc_sc_t *sc) { const struct ihfc_SQtable *SQtab; register u_char a = 0; BUS_VAR; if (S_HFC & HFC_1) { SET_REG(0x31); DISBUSY(a = READ_DATA_1, a = 0); if (a & 0x80) { SET_REG(0x3b); DISBUSY(a = READ_DATA_1, a = 0); } } else { SET_REG(0x34); a = READ_DATA_1; } SQtab = (S_NTMODE) ? &ihfc_Qtable[a & 7]: &ihfc_Stable[a & 7]; if (a & 0x10) { if (SQtab->string) { NDBGL1(L1_I_CICO, "%s (unit=%d, int=%x)", SQtab->string, S_UNIT, S_INT_S1); } else { NDBGL1(L1_ERROR, "Unknown indication = %x (unit=%d)", a & 7, S_UNIT); } } } /*---------------------------------------------------------------------------* * Interrupt handler (HFC-1) *---------------------------------------------------------------------------*/ void ihfc_intr1 (ihfc_sc_t *sc) { u_char chan; u_char tmp; BUS_VAR; HFC_VAR; HFC_BEG; SET_REG(0x20); tmp = GET_STAT; DISBUSY(S_ISTA |= READ_DATA_1, ); if (S_ISTA & 0x04) /* CIRQ */ { HFC_FSM(sc, 0); ihfc_sq(sc); } S_INTR_ACTIVE = 1; if (S_ISTA & 0xc0) /* RPF or RME */ { chan = 1; if (S_FILTER) S_FILTER(sc, chan); } if (S_ISTA & 0x10) /* XPR */ { chan = 0; if (S_FILTER) S_FILTER(sc, chan); } if (tmp & 0x04) /* Timer elapsed (50ms) */ { SET_REG((S_CTMT | 0xf0) & 0xff); chan = 6; while(chan--) { if (chan == 1) break; if (S_FILTER) S_FILTER(sc, chan); } } S_INTR_ACTIVE = 0; if (S_ISTA & 0x01) /* EXIR */ { SET_REG(0x24); DISBUSY(ihfc_exir_hdlr(sc, READ_DATA_1), ); } S_ISTA &= ~(0x1 | 0x4); HFC_END; } /*---------------------------------------------------------------------------* * Interrupt handler (HFC-S/SP) *---------------------------------------------------------------------------*/ void ihfc_intr2 (ihfc_sc_t *sc) { u_char chan; BUS_VAR; HFC_VAR; HFC_BEG; SET_REG(0x1e); S_INT_S1 = READ_DATA_1; /* this will enable new interrupts! */ if (S_INT_S1 & 0x40) { HFC_FSM(sc, 0); /* statemachine changed */ ihfc_sq(sc); } S_INTR_ACTIVE = 1; if (S_INT_S1 & 0x20) /* D-Channel frame (rx) */ { chan = 1; if (S_FILTER) S_FILTER(sc, chan); } if (S_INT_S1 & 0x04) /* D-Channel frame (tx) */ { chan = 0; if (S_FILTER && (~S_INT_S1 & 0x80)) S_FILTER(sc, chan); } if (S_INT_S1 & 0x80) /* Timer elapsed (50ms) */ { chan = 6; while(chan--) { if (chan == 1) continue; if (S_FILTER) S_FILTER(sc, chan); } } S_INTR_ACTIVE = 0; HFC_END; } /*---------------------------------------------------------------------------* * Select a Bfifo (HFC-1/S/SP) * and return bytes in FIFO * * (this code is optimized) *---------------------------------------------------------------------------*/ u_short ihfc_Bsel_fifo(ihfc_sc_t *sc, u_char chan, u_char flag) { register u_char reg = 0x7e + chan; register u_short tmp = 0x100; register u_short z1; register u_short z2; BUS_VAR; if (S_HFC & (HFC_1 | HFC_S)) { if (S_LAST_CHAN != chan) { SET_REG(reg); DISBUSY(WAITBUSY_2( , return 0), return 0); S_LAST_CHAN = chan; } } else { SET_REG(0x10); WRITE_DATA_1(chan - 2); DISBUSY( , return 0); } #define FAST_READ (u_char)(tmp = READ_BOTH_2) #define FAST_STAT if (tmp & 0x100) DISBUSY( , return 0); SET_REG(reg ); FAST_STAT; z1 = FAST_READ; SET_REG(reg += 4); FAST_STAT; z1 |= FAST_READ << 8; SET_REG(reg += 4); FAST_STAT; z2 = FAST_READ; SET_REG(reg += 4); FAST_STAT; z2 |= READ_DATA_1 << 8; #undef FAST_READ #undef FAST_STAT z1 &= 0x1fff; z2 &= 0x1fff; z1 = 0x5ff - (z2 = z1 - z2 + ((z2 <= z1) ? 0 : 0x600)); if (chan & 1) return(z2); /* receive channel */ else return(z1); /* transmit channel */ } /*---------------------------------------------------------------------------* * Select a Dfifo (HFC-S/SP) * and return bytes, and frames in FIFO * * Flag values: * 0x00: select new fifo + update counters * 0x10: increment f1 + update counters * 0x20: increment f2 + update counters * * NOTE: The upper 16bits holds the number of frames in the FIFO. * NOTE: FIFO has to be selected before you can use flags 0x10/0x20. *---------------------------------------------------------------------------*/ u_int32_t ihfc_Dsel_fifo(ihfc_sc_t *sc, u_char chan, u_char flag) { register u_char reg = 0x90 + chan; register u_short tmp = 0x100; register u_char f1; register u_char f2; register u_short z1; register u_short z2; BUS_VAR; if (S_HFC & (HFC_1 | HFC_S)) { switch(flag) { case(0x10): case(0x20): SET_REG(reg); if (~GET_STAT & 1) WAITBUSY_2( , return 0); SET_REG(0xa2 - (flag & 0x10) + chan); DISBUSY(READ_DATA_1, return 0); SET_REG(reg); if (~GET_STAT & 1) WAITBUSY_2( , return 0); break; default: if (S_LAST_CHAN != chan) { SET_REG(reg); DISBUSY(WAITBUSY_2( , return 0), return 0); S_LAST_CHAN = chan; } break; } } else { switch(flag) { case(0x10): case(0x20): SET_REG(0xb8 - (flag & 0x10) + chan); READ_DATA_1; DISBUSY( , return 0); if (chan & 1) { /* Before reading a FIFO a change * * FIFO operation must be done. * * (see HFC-SP manual p.38) */ SET_REG(0x10); WRITE_DATA_1(chan | 4); DISBUSY( , return 0); } break; default: SET_REG(0x10); WRITE_DATA_1(chan | 4); DISBUSY( , return 0); break; } } #define FAST_READ (u_char)(tmp = READ_BOTH_2) #define FAST_STAT if (tmp & 0x100) DISBUSY( , return 0); if (S_HFC & HFC_SP) reg = 0x80 + chan; SET_REG(reg ); FAST_STAT; z1 = FAST_READ; SET_REG(reg += 4); FAST_STAT; z1 |= FAST_READ << 8; SET_REG(reg += 4); FAST_STAT; z2 = FAST_READ; SET_REG(reg += 4); FAST_STAT; z2 |= FAST_READ << 8; if (S_HFC & HFC_SP) reg += 0x26; SET_REG(reg -= 2); FAST_STAT; f1 = FAST_READ; SET_REG(reg += 4); FAST_STAT; f2 = READ_DATA_1; #undef FAST_READ #undef FAST_STAT if (~chan & 1) { /* XXX was Z1 */ S_HDLC_DZ_TAB[f1 & 0xf] = z2; /* We keep track of the 'Z' * * values for D-channel (tx),* * so we may calculate the # * * of FIFO bytes free when * * f1 != f2. */ z2 = S_HDLC_DZ_TAB[f2 & 0xf]; } z1 = 0x1ff - (z2 = (z1 - z2) & 0x1ff); f1 = 0xf - (f2 = (f1 - f2) & 0xf); if (chan & 1) return(z2 | (f2 << 16)); /* receive channel */ else return(z1 | (f1 << 16)); /* transmit channel */ } /*---------------------------------------------------------------------------* * Data handler for D channel(write) - chan 0 (HFC-S/SP) *---------------------------------------------------------------------------*/ void ihfc_hdlc_Dwrite (ihfc_sc_t *sc, u_char chan) { register u_int32_t sendlen; register u_short len; register u_char * src; BUS_VAR; if (!S_MBUF && IF_QEMPTY(&S_IFQUEUE)) return; sendlen = ihfc_Dsel_fifo(sc, chan, 0); /* select new fifo * * NOTE: the 16 higher bits * * contain the # of frame- * * etries free in the FIFO */ while (sendlen & ~0xffff) { if (!S_MBUF) { if (!(S_MBUF = ihfc_getmbuf(sc, chan))) goto j1; } src = S_MBUFDATA; len = S_MBUFLEN; if (len >= 0x1ff) goto j0; /* frame is too big: skip! */ sendlen &= 0xffff; /* only keep # of * * bytes free */ SET_REG((S_HFC & HFC_SP) ? 0xac : 0x96); while (sendlen--) { if (!len--) break; DISBUSY(WRITE_DATA_1(*src++), sendlen = -1; len++; break); } if (!++sendlen) /* out of fifo: suspend */ { S_MBUFDATA = src; S_MBUFLEN = len; break; } sendlen = ihfc_Dsel_fifo(sc, chan, 0x10); /* inc F1 */ j0: i4b_Dfreembuf(S_MBUF); S_MBUF = NULL; } j1: } /*---------------------------------------------------------------------------* * Data handler for D channel(read) - chan 1 (HFC-S/SP) * * NOTE: Max framelength is (511 - 3) = 508 bytes, when only one frame * is received at a time. *---------------------------------------------------------------------------*/ void ihfc_hdlc_Dread (ihfc_sc_t *sc, u_char chan) { register u_char tmp = -1; register u_char to = 15; register u_int32_t reclen; register u_short crc; register u_short len; register u_char * dst; BUS_VAR; reclen = ihfc_Dsel_fifo(sc, chan, 0); /* select new fifo * * NOTE: the higher 16 bits * * contain the # of frames * * to receive. */ while ((reclen & ~0xffff) && to--) { reclen &= 0xffff; /* only keep # of * * bytes to receive */ if (!(S_MBUF = i4b_Dgetmbuf(DCH_MAX_LEN))) panic("ihfc_hdlc_Dread: No mbufs(unit=%d)!\n", S_UNIT); SET_REG((S_HFC & HFC_SP) ? 0xbd : 0xa7); if ((reclen > 2) && (reclen <= (DCH_MAX_LEN+2))) { dst = S_MBUFDATA; len = S_MBUFLEN = (reclen += 1) - 3; } else { len = 0; dst = NULL; } crc = -1; /* NOTE: after a "F1" or "Z1" hardware overflow * * it appears not to be necessary to reset the * * HFC-1/S or SP chips to continue proper * * operation, only and only, if we always read * * "Z1-Z2+1" bytes when F1!=F2 followed by a * * F2-counter increment. The bi-effect of doing * * this is the "STAT" field may say frame is ok * * when the frame is actually bad. * * The simple solution is to re-CRC the frame * * including "STAT" field to see if we get * * CRC == 0x3933. Then we're 99% sure all * * frames received are good. */ while(reclen--) { DISBUSY(tmp = READ_DATA_1, break); if (len) { len--; *dst++ = tmp; } crc = (HDLC_FCS_TAB[(u_char)(tmp ^ crc)] ^ (u_char)(crc >> 8)); } crc ^= 0x3933; if (!tmp && !crc) { ihfc_putmbuf(sc, chan, S_MBUF); S_MBUF = NULL; } else { NDBGL1(L1_ERROR, "Frame error (len=%d, stat=0x%x, " "crc=0x%x, unit=%d)", S_MBUFLEN, (u_char)tmp, crc, S_UNIT); i4b_Dfreembuf(S_MBUF); S_MBUF = NULL; } reclen = ihfc_Dsel_fifo(sc, chan, 0x20); } } /*---------------------------------------------------------------------------* * EXIR error handler - ISAC (D - channel) (HFC-1) *---------------------------------------------------------------------------*/ void ihfc_exir_hdlr (ihfc_sc_t *sc, u_char exir) { register u_char a; register u_char cmd; for (a = 0, cmd = 0; exir; a++, exir >>= 1) { if (exir & 1) { NDBGL1(L1_I_ERR, "%s. (unit=%d)", ihfc_EXIRtable[a].string, S_UNIT); cmd |= ihfc_EXIRtable[a].cmd; } } if (cmd) ihfc_cmdr_hdlr(sc, cmd); } /*---------------------------------------------------------------------------* * CMDR handler - ISAC (D - channel) (HFC-1) *---------------------------------------------------------------------------*/ void ihfc_cmdr_hdlr (ihfc_sc_t *sc, u_char cmdr) { BUS_VAR; SET_REG(0x21); DISBUSY(WRITE_DATA_1(cmdr); DELAY(30), ); } /*---------------------------------------------------------------------------* * Data handler for D channel(write) - chan 0 (HFC-1) *---------------------------------------------------------------------------*/ void ihfc_isac_Dwrite (ihfc_sc_t *sc, u_char chan) { register u_char sendlen = 32; register u_char cmd = 0; register u_short len; register u_char * src; BUS_VAR; if (~S_ISTA & 0x10) goto j0; if (!S_MBUF) if (!(S_MBUF = ihfc_getmbuf(sc, chan))) goto j0; len = S_MBUFLEN; src = S_MBUFDATA; SET_REG(0x00); while(sendlen--) /* write data */ { if (!len--) break; DISBUSY(WRITE_DATA_1(*src++), goto a0); } cmd |= 0x08; if (!++sendlen) /* suspend */ { S_MBUFLEN = len; S_MBUFDATA = src; } else { a0: i4b_Dfreembuf(S_MBUF); S_MBUF = NULL; cmd |= 0x02; } if (cmd) ihfc_cmdr_hdlr(sc, cmd); S_ISTA &= ~0x10; j0: } /*---------------------------------------------------------------------------* * Data handler for D channel(read) - chan 1 (HFC-1) *---------------------------------------------------------------------------*/ void ihfc_isac_Dread (ihfc_sc_t *sc, u_char chan) { register u_char cmd = 0; register u_char reclen; register u_short tmp; register u_short len; register u_char * dst; BUS_VAR; if (!(S_ISTA & 0xc0)) goto j1; /* only receive data * * on interrupt */ if (!S_MBUF) { if (!(S_MBUF = i4b_Dgetmbuf(DCH_MAX_LEN))) panic("ihfc%d: (D) Out of mbufs!\n", S_UNIT); } len = S_MBUFLEN; dst = S_MBUFDATA + (DCH_MAX_LEN - len); if (S_ISTA & 0x80) /* RME */ { SET_REG(0x27); DISBUSY(tmp = (READ_DATA_1 ^ 0x20), goto j0); if (tmp & 0x70) goto j0; /* error */ SET_REG(0x25); DISBUSY(tmp = (READ_DATA_1 & 0x1f), goto j0); reclen = (tmp) ? tmp : 32; } else /* RPF */ { reclen = 32; } if ((len -= reclen) <= DCH_MAX_LEN) /* get data */ { SET_REG(0x00); while(reclen--) { DISBUSY(*dst++ = READ_DATA_1, goto j0); } } else /* soft rdo or error */ { j0: i4b_Dfreembuf(S_MBUF); S_MBUF = NULL; cmd |= 0x40; NDBGL1(L1_I_ERR, "Frame error (unit=%d)", S_UNIT); } if (S_ISTA & 0x80) /* frame complete */ { if (S_MBUF) { S_MBUFLEN = (DCH_MAX_LEN - len); ihfc_putmbuf(sc, chan, S_MBUF); S_MBUF = NULL; } } if (S_MBUF) /* suspend */ { S_MBUFLEN = len; } ihfc_cmdr_hdlr(sc, cmd | 0x80); S_ISTA &= ~0xc0; j1: } /*---------------------------------------------------------------------------* * Data handler for B channel(write) - chan 2 and 4 (HFC-1/S/SP) * * NOTE: No XDU checking! *---------------------------------------------------------------------------*/ void ihfc_trans_Bwrite (ihfc_sc_t *sc, u_char chan) { register u_short sendlen; register u_short len; register u_char * src; BUS_VAR; if (!S_MBUF && IF_QEMPTY(&S_IFQUEUE)) return; sendlen = (u_short)ihfc_Bsel_fifo(sc, chan, 0); SET_REG(0xaa + chan); while (1) { if (!S_MBUF) { S_MBUF = ihfc_getmbuf(sc, chan); if (!S_MBUF) break; } src = S_MBUFDATA; len = S_MBUFLEN; while (sendlen--) { if (!len--) break; DISBUSY(WRITE_DATA_1(*src++), sendlen = -1; len++; break); } if (!++sendlen) /* out of fifo: Suspend */ { S_MBUFDATA = src; S_MBUFLEN = len; break; } i4b_Dfreembuf(S_MBUF); S_MBUF = NULL; } } /*---------------------------------------------------------------------------* * Data handler for B channel(read) - chan 3 and 5 (HFC-1/S/SP) * (this code is optimized) *---------------------------------------------------------------------------*/ void ihfc_trans_Bread (ihfc_sc_t *sc, u_char chan) { register u_short reclen; register u_short tmp; register u_short len; register u_char * dst; BUS_VAR; reclen = (u_short)ihfc_Bsel_fifo(sc, chan, 0); while (1) { SET_REG(0xba + chan); tmp = 0x100; if (!S_MBUF) if (!(S_MBUF = i4b_Bgetmbuf(BCH_MAX_DATALEN))) panic("ihfc%d: (B) Out of mbufs!\n", S_UNIT); len = S_MBUFLEN; dst = S_MBUFDATA + (BCH_MAX_DATALEN - len); while (reclen--) { if (!len--) break; if (tmp & 0x100) DISBUSY( , reclen = -1; len++; break); *dst++ = (u_char)(tmp = READ_BOTH_2); } if (~tmp & 0x100) { SET_REG(0x30); READ_DATA_1; /* a read to the data port * * will disable the internal * * disbusy signal for HFC-1/S * * chips. This is neccessary * * to avvoid data loss. */ } if (!++reclen) /* out of fifo: suspend */ { S_MBUFLEN = len; break; } S_MBUFLEN = (BCH_MAX_DATALEN - ++len); ihfc_putmbuf(sc, chan, S_MBUF); S_MBUF = NULL; } } /*---------------------------------------------------------------------------* * Data handler for B channel(write) - chan 2 and 4 (HFC-1/S/SP) * * NOTE: Software HDLC encoding! *---------------------------------------------------------------------------*/ void ihfc_hdlc_Bwrite (ihfc_sc_t *sc, u_char chan) { register u_short blevel = S_HDLC_BLEVEL; register u_char flag = S_HDLC_FLAG; register u_int tmp = S_HDLC_TMP; register u_short crc = S_HDLC_CRC; register u_short ib = S_HDLC_IB; register u_char * src = NULL; register u_short len = 0; register u_short sendlen; register u_short tmp2; BUS_VAR; if (!S_MBUF && IF_QEMPTY(&S_IFQUEUE) && (flag == 2)) return; sendlen = (u_short)ihfc_Bsel_fifo(sc, chan, 0); SET_REG(0xaa + chan); if (S_MBUF) { /* resume */ src = S_MBUFDATA; len = S_MBUFLEN; if (sendlen == 0x5ff) { /* XDU */ flag = -1; len = 0; NDBGL1(L1_S_ERR, "XDU (unit=%d)", S_UNIT); } } while (sendlen--) { HDLC_ENCODE(*src++, len, tmp, tmp2, blevel, ib, crc, flag, {/* gfr */ i4b_Bfreembuf(S_MBUF); S_MBUF = ihfc_getmbuf(sc, chan); if (S_MBUF) { src = S_MBUFDATA; len = S_MBUFLEN; } else { sendlen = 0; /* Exit after final FS, * * else the buffer will * * only be filled with * * "0x7e"-bytes! */ } }, {/* wrd */ DISBUSY(WRITE_DATA_1((u_char)tmp), sendlen = 0); }, d ); } if (S_MBUF) /* suspend */ { S_MBUFDATA = src; S_MBUFLEN = len; } S_HDLC_IB = ib; S_HDLC_BLEVEL = blevel; S_HDLC_TMP = tmp; S_HDLC_FLAG = flag; S_HDLC_CRC = crc; } /*---------------------------------------------------------------------------* * Data handler for B channel(read) - chan 3 and 5 (HFC-1/S/SP) * * NOTE: Software HDLC decoding! *---------------------------------------------------------------------------*/ void ihfc_hdlc_Bread (ihfc_sc_t *sc, u_char chan) { register u_char blevel = S_HDLC_BLEVEL; u_char flag = S_HDLC_FLAG; register u_short crc = S_HDLC_CRC; register u_int tmp = S_HDLC_TMP; register u_short ib = S_HDLC_IB; register u_char * dst = NULL; register u_short tmp2 = 0x100; register u_short len = 0; register u_short reclen; BUS_VAR; if (S_MBUF) { /* resume */ len = S_MBUFLEN; dst = S_MBUFDATA + (BCH_MAX_DATALEN - len); } reclen = (u_short)ihfc_Bsel_fifo(sc, chan, 0); SET_REG(0xba + chan); while (reclen--) { HDLC_DECODE(*dst++, len, tmp, tmp2, blevel, ib, crc, flag, {/* rdd */ /* if (tmp2 & 0x100) while (GET_STAT & 1); * tmp2 = READ_BOTH_2; */ DISBUSY(tmp2 = READ_DATA_1, reclen = 0; tmp2 = 0); }, {/* nfr */ if (!(S_MBUF = i4b_Bgetmbuf(BCH_MAX_DATALEN))) panic("ihfc:(B) Out of mbufs!\n"); dst = S_MBUFDATA; len = BCH_MAX_DATALEN; }, {/* cfr */ len = (BCH_MAX_DATALEN - len); if ((!len) || (len > BCH_MAX_DATALEN)) { /* NOTE: frames without any data, * * only crc field, should be silently discared. */ i4b_Bfreembuf(S_MBUF); NDBGL1(L1_S_MSG, "Bad frame (len=%d, unit=%d)", len, S_UNIT); goto s0; } if (crc) { i4b_Bfreembuf(S_MBUF); NDBGL1(L1_S_ERR, "CRC (crc=0x%04x, len=%d, unit=%d)", crc, len, S_UNIT); goto s0; } S_MBUFLEN = len; ihfc_putmbuf(sc, chan, S_MBUF); s0: S_MBUF = NULL; }, {/* rab */ i4b_Bfreembuf(S_MBUF); S_MBUF = NULL; NDBGL1(L1_S_MSG, "Read Abort (unit=%d)", S_UNIT); }, {/* rdo */ i4b_Bfreembuf(S_MBUF); S_MBUF = NULL; NDBGL1(L1_S_ERR, "RDO (unit=%d)", S_UNIT); }, continue, d); } /* SET_REG(0x30); * if (~tmp2 & 0x100) READ_DATA_1; kill disbusy signal */ if (S_MBUF) S_MBUFLEN = len; /* suspend */ S_HDLC_IB = ib; S_HDLC_CRC = crc; S_HDLC_TMP = tmp; S_HDLC_FLAG = flag; S_HDLC_BLEVEL = blevel; } /*---------------------------------------------------------------------------* * Data handler for B channel(write) - chan 2 and 4 (HFC-1/S/SP) * * This filter generates a pattern which is recognized * and examinated and verified by ihfc_test_Bread. * * NOTE: This filter is only for testing purpose. *---------------------------------------------------------------------------*/ void ihfc_test_Bwrite (ihfc_sc_t *sc, u_char chan) { struct mbuf *m; register u_char fb; register u_short sendlen, tlen; register u_short xlen = S_HDLC_IB; BUS_VAR; goto j0; while((m = ihfc_getmbuf(sc, chan))) /* internal loop */ { if (chan == 2) ihfc_putmbuf(sc, 5, m); else ihfc_putmbuf(sc, 3, m); } j0: sendlen = (u_short)ihfc_Bsel_fifo(sc, chan, 0); if (sendlen == 0x5ff) printf("(send empty)"); SET_REG(0xaa + chan); S_BYTES += sendlen; tlen = S_HDLC_CRC; if (sendlen > 0x400) printf("(slow: %d)", sendlen); fb = 0x80; while (sendlen--) { if (!tlen--) fb |= 0x20; if (!xlen--) { while(GET_STAT & 1); WRITE_DATA_1(0x3e); xlen = 200; } else { while(GET_STAT & 1); WRITE_DATA_1((xlen + 1) & 0xef); } fb = 0; } S_HDLC_IB = xlen; } /*---------------------------------------------------------------------------* * Data handler for B channel(read) - chan 3 and 5 (HFC-1/S/SP) * * This filter examins and verifies the pattern * generated by ihfc_test_Bwrite. * * NOTE: This filter is only for testing purpose. *---------------------------------------------------------------------------*/ void ihfc_test_Bread (ihfc_sc_t *sc, u_char chan) { static u_short toterrors = 0; register u_short reclen, len, tlen; register u_char fb, tmp; register u_short xlen = S_HDLC_IB; register u_char *dst = NULL; register u_char error = S_HDLC_TMP; register u_char ecount = S_HDLC_FLAG; BUS_VAR; if (S_UNIT != 0) return; reclen = (u_short)ihfc_Bsel_fifo(sc, chan, 0); S_BYTES += reclen; tlen = S_HDLC_CRC; fb = 0x40; if (S_MBUF) { len = S_MBUFLEN; dst = S_MBUFDATA + (BCH_MAX_DATALEN - len); } else { len = 0; } SET_REG(0xba + chan); while (reclen--) { /* if (tmp2 & 0x100) while(GET_STAT & 1); * tmp = (u_char)(tmp2 = READ_BOTH_2); */ if (GET_STAT & 1) { /* if (!(++busy % 4)) reclen++; */ while(GET_STAT & 1); } tmp = READ_DATA_1; if ((tmp & 0x3f) == 0x3e) { if ((BCH_MAX_DATALEN - len) != 201) error |= 4; if ((S_MBUF) && (error)) { if (len) { len--; *dst++ = error; } if (len) { len--; *dst++ = xlen+1; } if (len) { len--; *dst++ = ecount; } S_MBUFLEN = BCH_MAX_DATALEN - len; if (S_TRACE & TRACE_B_RX) ihfc_putmbuf(sc, chan, S_MBUF); else i4b_Bfreembuf(S_MBUF); S_MBUF = NULL; printf("(error%d, %d, %d)", S_UNIT, ecount, toterrors++); } i4b_Bfreembuf(S_MBUF); S_MBUF = i4b_Bgetmbuf(BCH_MAX_DATALEN); dst = S_MBUFDATA; len = BCH_MAX_DATALEN; xlen = 200; error = 0; ecount = 0; /* SET_REG(0xba + chan); */ } else { if (!xlen) error |= 2; if ((tmp ^ xlen--) & 0xef) { error |= 1; ecount++; } } if (!tlen--) fb |= 0x20; if (len--) { *dst++ = (tmp | fb); } else { len++; } fb = 0; } if (S_MBUF) { S_MBUFLEN = len; } S_HDLC_IB = xlen; S_HDLC_TMP = error; S_HDLC_FLAG = ecount; } #endif /* NIHFC > 0 */ Index: head/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c =================================================================== --- head/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c (revision 67972) +++ head/sys/i4b/layer1/ihfc/i4b_ihfc_l1if.c (revision 67973) @@ -1,515 +1,514 @@ /* * Copyright (c) 2000 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *--------------------------------------------------------------------------- * * i4b_ihfc_l1.c - hfc layer 1 handler * ----------------------------------- * * The idea of this file is to seperate hfcs/sp/pci data/signal * handling and the I4B data/signal handling. * * Everything which has got anything to do with I4B has been put here! * * last edit-date: [Wed Jul 19 09:41:03 2000] * * $Id: i4b_ihfc_l1if.c,v 1.10 2000/09/19 13:50:36 hm Exp $ * * $FreeBSD$ * *---------------------------------------------------------------------------*/ #include "ihfc.h" #if (NIHFC > 0) #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------* * Local prototypes * * NOTE: The prototypes for get/putmbuf and B_linkinit * have been put in i4b_hfc_ext.h for global hfc use. * * NOTE: channel != chan *---------------------------------------------------------------------------*/ static isdn_link_t * ihfc_B_ret_linktab (int unit, int channel); static void ihfc_B_set_linktab (int unit, int channel, drvr_link_t *B_linktab); static void ihfc_B_start (int unit, int chan); static void ihfc_B_stat (int unit, int chan, bchan_statistics_t *bsp); void ihfc_B_setup (int unit, int chan, int bprot, int activate); static int ihfc_mph_command_req (int unit, int command, void *parm); static int ihfc_ph_activate_req (int unit); static int ihfc_ph_data_req (int unit, struct mbuf *m, int freeflag); static void ihfc_T3_expired (ihfc_sc_t *sc); /*---------------------------------------------------------------------------* * Our I4B L1 mulitplexer link *---------------------------------------------------------------------------*/ struct i4b_l1mux_func ihfc_l1mux_func = { ihfc_B_ret_linktab, ihfc_B_set_linktab, ihfc_mph_command_req, ihfc_ph_data_req, ihfc_ph_activate_req, }; /*---------------------------------------------------------------------------* * L2 -> L1: PH-DATA-REQUEST (D-Channel) * * NOTE: We may get called here from ihfc_hdlc_Dread or isac_hdlc_Dread * via the upper layers. *---------------------------------------------------------------------------*/ int ihfc_ph_data_req(int unit, struct mbuf *m, int freeflag) { ihfc_sc_t *sc = &ihfc_softc[unit]; u_char chan = 0; HFC_VAR; if (!m) return 0; HFC_BEG; if(S_PHSTATE != 3) { NDBGL1(L1_PRIM, "L1 was not running: " "ihfc_ph_activate_req(unit = %d)!", unit); ihfc_ph_activate_req(unit); } /* "Allow" I-frames (-hp) */ if (freeflag == MBUF_DONTFREE) m = m_copypacket(m, M_DONTWAIT); if (!IF_QFULL(&S_IFQUEUE) && m) { IF_ENQUEUE(&S_IFQUEUE, m); ihfc_B_start(unit, chan); /* (recycling) */ } else { NDBGL1(L1_ERROR, "No frame out (unit = %d)", unit); i4b_Dfreembuf(m); } if (S_INTR_ACTIVE) S_INT_S1 |= 0x04; HFC_END; return 1; } /*---------------------------------------------------------------------------* * L2 -> L1: PH-ACTIVATE-REQUEST (B-channel and D-channel) *---------------------------------------------------------------------------*/ int ihfc_ph_activate_req(int unit) { ihfc_sc_t *sc = &ihfc_softc[unit]; HFC_VAR; HFC_BEG; if ((!S_STM_T3) && (S_PHSTATE != 3)) { HFC_FSM(sc, 1); S_STM_T3 = 1; S_STM_T3CALLOUT = timeout((TIMEOUT_FUNC_T) ihfc_T3_expired, (ihfc_sc_t *)sc, IHFC_ACTIVATION_TIMEOUT); } HFC_END; return 0; } /*---------------------------------------------------------------------------* * T3 timeout - persistant deactivation *---------------------------------------------------------------------------*/ void ihfc_T3_expired(ihfc_sc_t *sc) { u_char chan = 0; HFC_VAR; HFC_BEG; S_STM_T3 = 0; if (S_PHSTATE != 3) /* line was not activated */ { i4b_Dcleanifq(&S_IFQUEUE); i4b_l1_ph_deactivate_ind(S_I4BUNIT); i4b_l1_mph_status_ind(S_I4BUNIT, STI_PDEACT, 0, 0); HFC_FSM(sc, 2); /* L1 deactivate */ } HFC_END; } /*---------------------------------------------------------------------------* * Command from the upper layers (B-channel and D-channel) *---------------------------------------------------------------------------*/ int ihfc_mph_command_req(int unit, int command, void *parm) { ihfc_sc_t *sc = &ihfc_softc[unit]; switch(command) { case CMR_DOPEN: /* daemon running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); S_ENABLED = 1; break; case CMR_DCLOSE: /* daemon not running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); S_ENABLED = 0; break; case CMR_SETTRACE: /* set new trace mask */ NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); S_TRACE = (unsigned int)parm; break; case CMR_GCST: /* get chip statistic */ NDBGL1(L1_PRIM, "unit %d, command = CMR_GCST, parm = %d", unit, (unsigned int)parm); #define CST ((struct chipstat *)parm) CST->driver_type = L1DRVR_IHFC; /* XXX CST->xxxx_stat = xxx; */ #undef CST break; default: NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); break; } return 0; } /*---------------------------------------------------------------------------* * Data source switch for Read channels - 1, 3 and 5 (B and D-Channel) *---------------------------------------------------------------------------*/ void ihfc_putmbuf (ihfc_sc_t *sc, u_char chan, struct mbuf *m) { i4b_trace_hdr_t hdr; if (chan < 2) { if(S_TRACE & TRACE_D_RX) { hdr.count = ++S_DTRACECOUNT; hdr.dir = FROM_NT; hdr.type = TRC_CH_D; hdr.unit = S_I4BUNIT; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } if (!S_ENABLED) { i4b_Dfreembuf(m); return; } m->m_pkthdr.len = m->m_len; i4b_l1_ph_data_ind(S_I4BUNIT, m); } else { if(S_TRACE & TRACE_B_RX) { hdr.count = ++S_BTRACECOUNT; hdr.dir = FROM_NT; hdr.type = (chan < 4) ? TRC_CH_B1 : TRC_CH_B2; hdr.unit = S_I4BUNIT; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } if (!S_ENABLED) { i4b_Bfreembuf(m); return; } if (S_PROT == BPROT_NONE) { if(!i4b_l1_bchan_tel_silence(m->m_data, m->m_len)) { S_BDRVLINK->bch_activity(S_BDRVLINK->unit, ACT_RX); } if (!IF_QFULL(&S_IFQUEUE)) { S_BYTES += m->m_len; IF_ENQUEUE(&S_IFQUEUE, m); S_BDRVLINK->bch_rx_data_ready(S_BDRVLINK->unit); } return; } if (S_PROT == BPROT_RHDLC) { S_MBUFDUMMY = m; S_BYTES += m->m_pkthdr.len = m->m_len; S_BDRVLINK->bch_rx_data_ready(S_BDRVLINK->unit); S_MBUFDUMMY = NULL; return; } NDBGL1(L1_ERROR, "Unknown protocol: %d", S_PROT); } } /*---------------------------------------------------------------------------* * Data destinator switch for write channels - 0, 2 and 4 *---------------------------------------------------------------------------*/ struct mbuf * ihfc_getmbuf (ihfc_sc_t *sc, u_char chan) { register struct mbuf *m; i4b_trace_hdr_t hdr; if (chan < 2) { IF_DEQUEUE(&S_IFQUEUE, m); if((S_TRACE & TRACE_D_TX) && m) { hdr.count = ++S_DTRACECOUNT; hdr.dir = FROM_TE; hdr.type = TRC_CH_D; hdr.unit = S_I4BUNIT; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } } else { IF_DEQUEUE(&S_IFQUEUE, m); if (!m) { S_BDRVLINK->bch_tx_queue_empty(S_BDRVLINK->unit); IF_DEQUEUE(&S_IFQUEUE, m); } if (m) { if(!i4b_l1_bchan_tel_silence(m->m_data, m->m_len)) { S_BDRVLINK->bch_activity(S_BDRVLINK->unit, ACT_TX); } S_BYTES += m->m_len; if(S_TRACE & TRACE_B_TX) { hdr.count = ++S_BTRACECOUNT; hdr.dir = FROM_TE; hdr.type = (chan < 4) ? TRC_CH_B1 : TRC_CH_B2; hdr.unit = S_I4BUNIT; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } } } return(m); } /*---------------------------------------------------------------------------* * Initialize rx/tx data structures (B-channel) *---------------------------------------------------------------------------*/ void ihfc_B_setup(int unit, int chan, int bprot, int activate) { ihfc_sc_t *sc = &ihfc_softc[unit]; HFC_VAR; if (((u_int)chan > 5) || ((u_int)chan < 2)) return; HFC_BEG; HFC_INIT(sc, chan, bprot, activate); HFC_END; } /*---------------------------------------------------------------------------* * Start transmission (B-channel or D-channel tx) * NOTE: if "chan" variable is corrupted, it will not cause any harm, * but data may be lost and there may be software sync. errors. *---------------------------------------------------------------------------*/ void ihfc_B_start(int unit, int chan) { ihfc_sc_t *sc = &ihfc_softc[unit]; HFC_VAR; if ((u_int)chan > 5) return; HFC_BEG; if (S_FILTER && !S_MBUF && !S_INTR_ACTIVE) { S_INTR_ACTIVE |= 2; /* never know what * * they put in the * * L2 code */ S_FILTER(sc, chan); /* quick tx */ S_INTR_ACTIVE &= ~2; } HFC_END; } /*---------------------------------------------------------------------------* * Fill statistics struct (B-channel) *---------------------------------------------------------------------------*/ void ihfc_B_stat(int unit, int chan, bchan_statistics_t *bsp) { ihfc_sc_t *sc = &ihfc_softc[unit]; HFC_VAR; if ((u_int)chan > 5) return; chan &= ~1; HFC_BEG; bsp->inbytes = S_BYTES; S_BYTES = 0; chan++; bsp->outbytes = S_BYTES; S_BYTES = 0; HFC_END; } /*---------------------------------------------------------------------------* * Return the address of IHFC linktab to I4B (B-channel) *---------------------------------------------------------------------------*/ isdn_link_t * ihfc_B_ret_linktab(int unit, int channel) { ihfc_sc_t *sc = &ihfc_softc[unit]; if (channel < 2) return(&sc->sc_blinktab[channel]); else return 0; } /*---------------------------------------------------------------------------* * Set the I4B driver linktab for IHFC use (B-channel) *---------------------------------------------------------------------------*/ void ihfc_B_set_linktab(int unit, int channel, drvr_link_t *B_linktab) { ihfc_sc_t *sc = &ihfc_softc[unit]; if (channel < 2) sc->sc_bdrvlinktab[channel] = B_linktab; } /*---------------------------------------------------------------------------* * Initialize linktab for I4B use (B-channel) *---------------------------------------------------------------------------*/ void ihfc_B_linkinit(ihfc_sc_t *sc) { u_char chan; /* make sure the hardware driver is known to layer 4 */ ctrl_types[CTRL_PASSIVE].set_linktab = i4b_l1_set_linktab; ctrl_types[CTRL_PASSIVE].get_linktab = i4b_l1_ret_linktab; for (chan = 2; chan < 6; chan++) { S_BLINK.unit = S_UNIT; S_BLINK.channel = chan; /* point to tx-chan */ S_BLINK.bch_config = ihfc_B_setup; S_BLINK.bch_tx_start = ihfc_B_start; S_BLINK.bch_stat = ihfc_B_stat; /* This is a transmit channel (even) */ S_BLINK.tx_queue = &S_IFQUEUE; chan++; /* This is a receive channel (odd) */ S_BLINK.rx_queue = &S_IFQUEUE; S_BLINK.rx_mbuf = &S_MBUFDUMMY; } } #endif /* NIHFC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_asuscom_ipac.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_asuscom_ipac.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_asuscom_ipac.c (revision 67973) @@ -1,241 +1,238 @@ /* * Copyright (c) 1999 Ari Suutari. All rights reserved. * * Copyright (c) 1997, 2000 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 Asuscom ISDNlink 128K PnP * ===================================================================== * * This driver works with Asuscom ISDNlink 128K PnP ISA adapter, * which is based on Siemens IPAC chip (my card probes as ASU1690). * Older Asuscom ISA cards are based on different chipset * (containing two chips) - for those cards, one might want * to try the Dynalink driver. * * This driver is heavily based on ELSA Quickstep 1000pro PCI * driver written by Hellmuth Michaelis. Card initialization * code is modeled after Linux i4l driver written by Karsten * Keil. * * $Id: i4b_asuscom_ipac.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 15:59:33 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if (NISIC > 0) && defined (ASUSCOM_IPAC) #include #include #include #include -#include #include #include #include -#include -#include /* masks for register encoded in base addr */ #define ASI_BASE_MASK 0x0ffff #define ASI_OFF_MASK 0xf0000 /* register id's to be encoded in base addr */ #define ASI_IDISAC 0x00000 #define ASI_IDHSCXA 0x10000 #define ASI_IDHSCXB 0x20000 #define ASI_IDIPAC 0x40000 /* offsets from base address */ #define ASI_OFF_ALE 0x00 #define ASI_OFF_RW 0x01 /*---------------------------------------------------------------------------* * Asuscom ISDNlink 128K ISAC get fifo routine *---------------------------------------------------------------------------*/ static void asi_read_fifo(struct l1_softc *sc,int what,void *buf,size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,ASI_OFF_ALE,IPAC_ISAC_OFF); bus_space_read_multi_1(t,h,ASI_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,ASI_OFF_ALE,IPAC_HSCXA_OFF); bus_space_read_multi_1(t,h,ASI_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,ASI_OFF_ALE,IPAC_HSCXB_OFF); bus_space_read_multi_1(t,h,ASI_OFF_RW,buf,size); break; } } /*---------------------------------------------------------------------------* * Asuscom ISDNlink 128K ISAC put fifo routine *---------------------------------------------------------------------------*/ static void asi_write_fifo(struct l1_softc *sc,int what,void *buf,size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,ASI_OFF_ALE,IPAC_ISAC_OFF); bus_space_write_multi_1(t,h,ASI_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,ASI_OFF_ALE,IPAC_HSCXA_OFF); bus_space_write_multi_1(t,h,ASI_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,ASI_OFF_ALE,IPAC_HSCXB_OFF); bus_space_write_multi_1(t,h,ASI_OFF_RW,buf,size); break; } } /*---------------------------------------------------------------------------* * Asuscom ISDNlink 128K ISAC put register routine *---------------------------------------------------------------------------*/ static void asi_write_reg(struct l1_softc *sc,int what,bus_size_t reg,u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_ISAC_OFF); bus_space_write_1(t,h,ASI_OFF_RW,data); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_HSCXA_OFF); bus_space_write_1(t,h,ASI_OFF_RW,data); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_HSCXB_OFF); bus_space_write_1(t,h,ASI_OFF_RW,data); break; case ISIC_WHAT_IPAC: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_IPAC_OFF); bus_space_write_1(t,h,ASI_OFF_RW,data); break; } } /*---------------------------------------------------------------------------* * Asuscom ISDNlink 128K ISAC get register routine *---------------------------------------------------------------------------*/ static u_int8_t asi_read_reg(struct l1_softc *sc,int what,bus_size_t reg) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_ISAC_OFF); return bus_space_read_1(t,h,ASI_OFF_RW); case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_HSCXA_OFF); return bus_space_read_1(t,h,ASI_OFF_RW); case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_HSCXB_OFF); return bus_space_read_1(t,h,ASI_OFF_RW); case ISIC_WHAT_IPAC: bus_space_write_1(t,h,ASI_OFF_ALE,reg+IPAC_IPAC_OFF); return bus_space_read_1(t,h,ASI_OFF_RW); default: return 0; } } /*---------------------------------------------------------------------------* * isic_attach_siemens_isurf - attach for Asuscom ISDNlink 128K *---------------------------------------------------------------------------*/ int isic_attach_asi(device_t dev) { int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; /* setup access routines */ sc->clearirq = NULL; sc->readreg = asi_read_reg; sc->writereg = asi_write_reg; sc->readfifo = asi_read_fifo; sc->writefifo = asi_write_fifo; /* setup card type */ sc->sc_cardtyp = CARD_TYPEP_ASUSCOMIPAC; /* 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 */ /* * This has been taken from Linux driver. * (Removed initialization that was not applicaple to * this board or was already register default setting.) */ IPAC_WRITE (IPAC_ACFG, 0xff); /* Setup AUX pin modes */ IPAC_WRITE (IPAC_AOE, 0x0); /* Setup AUX pin modes */ IPAC_WRITE (IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0)); return(0); } #endif /* (NISIC > 0) && defined (ASUSCOM_IPAC) */ Index: head/sys/i4b/layer1/isic/i4b_avm_a1.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_avm_a1.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_avm_a1.c (revision 67973) @@ -1,416 +1,414 @@ /* * Copyright (c) 1996 Andrew Gordon. All rights reserved. * * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:42:06 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 && defined(AVM_A1) #include #include #include #include -#include #include #include -#include #include /*---------------------------------------------------------------------------* * 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 */ #define AVM_ISAC_R_OFFS (0x1400-0x20) #define AVM_HSCXA_R_OFFS (0x400-0x20) #define AVM_HSCXB_R_OFFS (0xc00-0x20) #define AVM_ISAC_F_OFFS (0x1400-0x20-0x3e0) #define AVM_HSCXA_F_OFFS (0x400-0x20-0x3e0) #define AVM_HSCXB_F_OFFS (0xc00-0x20-0x3e0) /*---------------------------------------------------------------------------* * AVM read fifo routine *---------------------------------------------------------------------------*/ static void avma1_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+4]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+4]); bus_space_read_multi_1(t, h, 0, buf, size); } /*---------------------------------------------------------------------------* * AVM write fifo routine *---------------------------------------------------------------------------*/ static void avma1_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+4]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+4]); bus_space_write_multi_1(t, h, 0, (u_int8_t*)buf, size); } /*---------------------------------------------------------------------------* * AVM write register routine *---------------------------------------------------------------------------*/ static void avma1_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+1]); bus_space_write_1(t, h, offs, data); } /*---------------------------------------------------------------------------* * AVM read register routine *---------------------------------------------------------------------------*/ static u_int8_t avma1_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+1]); return bus_space_read_1(t, h, offs); } /*---------------------------------------------------------------------------* * allocate an io port *---------------------------------------------------------------------------*/ static int isic_alloc_port(device_t dev, int rid, u_int base, u_int len) { size_t unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; sc->sc_resources.io_rid[rid] = rid; bus_set_resource(dev, SYS_RES_IOPORT, rid, base, len); if(!(sc->sc_resources.io_base[rid] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[rid], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Error, failed to reserve io #%d!\n", unit, rid); isic_detach_common(dev); return(ENXIO); } return(0); } /*---------------------------------------------------------------------------* * isic_probe_avma1 - probe for AVM A1 and compatibles *---------------------------------------------------------------------------*/ int isic_probe_avma1(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* pointer to softc */ void *ih = 0; /* dummy */ bus_space_tag_t t; /* bus things */ bus_space_handle_t h; u_char savebyte; u_char byte; /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for AVM A1/Fritz!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_AVM_A1; /* set flags */ /* see if an io base was supplied */ if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get iobase for AVM A1/Fritz!\n", unit); return(ENXIO); } /* set io base */ sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); /* release io base */ bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); switch(sc->sc_port) { case 0x200: case 0x240: case 0x300: case 0x340: break; default: printf("isic%d: Error, invalid iobase 0x%x specified for AVM A1/Fritz!\n", unit, sc->sc_port); return(ENXIO); break; } if(isic_alloc_port(dev, 0, sc->sc_port+AVM_CONF_REG, 0x20)) return(ENXIO); if(isic_alloc_port(dev, 1, sc->sc_port+AVM_ISAC_R_OFFS, 0x20)) return(ENXIO); if(isic_alloc_port(dev, 2, sc->sc_port+AVM_HSCXA_R_OFFS, 0x20)) return(ENXIO); if(isic_alloc_port(dev, 3, sc->sc_port+AVM_HSCXB_R_OFFS, 0x20)) return(ENXIO); if(isic_alloc_port(dev, 4, sc->sc_port+AVM_ISAC_F_OFFS, 0x20)) return(ENXIO); if(isic_alloc_port(dev, 5, sc->sc_port+AVM_HSCXA_F_OFFS, 0x20)) return(ENXIO); if(isic_alloc_port(dev, 6, sc->sc_port+AVM_HSCXB_F_OFFS, 0x20)) return(ENXIO); /* get our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get an irq for AVM A1/Fritz!\n",unit); isic_detach_common(dev); return ENXIO; } /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); /* register interupt routine */ bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void *))(isicintr), sc, &ih); /* check IRQ validity */ switch(sc->sc_irq) { 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", unit, sc->sc_irq); isic_detach_common(dev); return(ENXIO); break; } 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; /* * 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", unit); printf("isic%d: HSC0: VSTR: %#x\n", unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", unit, HSCX_READ(1, H_VSTR)); return(ENXIO); } /* 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 ..... */ t = rman_get_bustag(sc->sc_resources.io_base[0]); h = rman_get_bushandle(sc->sc_resources.io_base[0]); savebyte = bus_space_read_1(t, h, 0); /* write low to test bit */ bus_space_write_1(t, h, 0, 0x00); /* test bit and next higher and lower bit must be 0 */ if((byte = bus_space_read_1(t, h, 0) & 0x38) != 0x00) { printf("isic%d: Error, probe-1 failed, 0x%02x should be 0x00 for AVM A1/Fritz!\n", unit, byte); bus_space_write_1(t, h, 0, savebyte); return(ENXIO); } /* write high to test bit */ bus_space_write_1(t, h, 0, 0x10); /* test bit must be high, next higher and lower bit must be 0 */ if((byte = bus_space_read_1(t, h, 0) & 0x38) != 0x10) { printf("isic%d: Error, probe-2 failed, 0x%02x should be 0x10 for AVM A1/Fritz!\n", unit, byte); bus_space_write_1(t, h, 0, savebyte); return(ENXIO); } return(0); } /*---------------------------------------------------------------------------* * isic_attach_avma1 - attach AVM A1 and compatibles *---------------------------------------------------------------------------*/ int isic_attach_avma1(device_t dev) { size_t unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); /* reset ISAC/HSCX */ 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(0); } #endif /* NISIC > 0 && defined(AVM_A1) */ Index: head/sys/i4b/layer1/isic/i4b_bchan.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_bchan.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_bchan.c (revision 67973) @@ -1,403 +1,401 @@ /* * Copyright (c) 1997, 2000 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.6 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:42:26 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #if NISIC > 0 #include #include #include -#include #include #include #include #include #include #include #include -#include #include #include #include static void isic_bchannel_start(int unit, int h_chan); static void isic_bchannel_stat(int unit, int h_chan, bchan_statistics_t *bsp); /*---------------------------------------------------------------------------* * 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) { struct l1_softc *sc = &l1_sc[unit]; l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s = SPLI4B(); if(activate == 0) { /* deactivation */ isic_hscx_init(sc, h_chan, activate); } NDBGL1(L1_BCHAN, "unit=%d, channel=%d, %s", 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) { struct l1_softc *sc = &l1_sc[unit]; register l1_bchan_state_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(!(i4b_l1_bchan_tel_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 = L0ISICUNIT(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); i4b_l1_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 = L0ISICUNIT(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); i4b_l1_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->isic_drvr_linktab->bch_activity)(chan->isic_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) { struct l1_softc *sc = &l1_sc[unit]; l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; int s; s = SPLI4B(); bsp->outbytes = chan->txcount; bsp->inbytes = chan->rxcount; chan->txcount = 0; chan->rxcount = 0; splx(s); } /*---------------------------------------------------------------------------* * return the address of isic drivers linktab *---------------------------------------------------------------------------*/ isdn_link_t * isic_ret_linktab(int unit, int channel) { struct l1_softc *sc = &l1_sc[unit]; l1_bchan_state_t *chan = &sc->sc_chan[channel]; return(&chan->isic_isdn_linktab); } /*---------------------------------------------------------------------------* * set the driver linktab in the b channel softc *---------------------------------------------------------------------------*/ void isic_set_linktab(int unit, int channel, drvr_link_t *dlt) { struct l1_softc *sc = &l1_sc[unit]; l1_bchan_state_t *chan = &sc->sc_chan[channel]; chan->isic_drvr_linktab = dlt; } /*---------------------------------------------------------------------------* * initialize our local linktab *---------------------------------------------------------------------------*/ void isic_init_linktab(struct l1_softc *sc) { l1_bchan_state_t *chan = &sc->sc_chan[HSCX_CH_A]; isdn_link_t *lt = &chan->isic_isdn_linktab; /* make sure the hardware driver is known to layer 4 */ ctrl_types[CTRL_PASSIVE].set_linktab = i4b_l1_set_linktab; ctrl_types[CTRL_PASSIVE].get_linktab = i4b_l1_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->isic_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; } #endif /* NISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_ctx_s0P.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_ctx_s0P.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_ctx_s0P.c (revision 67973) @@ -1,254 +1,252 @@ /* * Copyright (c) 1997, 2000 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/Teles PnP * ============================================================ * * $Id: i4b_ctx_s0P.c,v 1.4 2000/08/22 11:30:04 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 15:59:45 2000] * * Note: this driver works for the Creatix ISDN S0-16 P+P and * for the Teles S0/16.3 PnP card. Although they are not * the same hardware and don't share the same PnP config * information, once the base addresses are set, the * offsets are same and therefore they can use the same * driver. * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if (NISIC > 0) && (defined(CRTX_S0_P) || defined(TEL_S0_16_3_P)) #include #include #include #include -#include #include #include -#include #include /*---------------------------------------------------------------------------* * Creatix / Teles PnP ISAC get fifo routine *---------------------------------------------------------------------------*/ static void ctxs0P_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+2]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+2]); bus_space_read_multi_1(t,h,0x3e,buf,size); } /*---------------------------------------------------------------------------* * Creatix / Teles PnP ISAC put fifo routine *---------------------------------------------------------------------------*/ static void ctxs0P_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+2]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+2]); bus_space_write_multi_1(t,h,0x3e,buf,size); } /*---------------------------------------------------------------------------* * Creatix / Teles PnP ISAC put register routine *---------------------------------------------------------------------------*/ static void ctxs0P_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+2]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+2]); bus_space_write_1(t,h,offs,data); } /*---------------------------------------------------------------------------* * Creatix / Teles PnP ISAC get register routine *---------------------------------------------------------------------------*/ static u_int8_t ctxs0P_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+2]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+2]); return bus_space_read_1(t,h,offs); } /*---------------------------------------------------------------------------* * isic_attach_Cs0P - attach Creatix / Teles PnP *---------------------------------------------------------------------------*/ int isic_attach_Cs0P(device_t dev) { u_int32_t iobase1; u_int32_t iobase2; int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; bus_space_tag_t t; bus_space_handle_t h; /* * this card needs a second io_base, * free resources if we don't get it */ sc->sc_resources.io_rid[1] = 1; if(!(sc->sc_resources.io_base[1] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[1], 0UL, ~0UL, 1, RF_ACTIVE))) { printf("isic%d: Could not get io area 1 for Creatix / Teles PnP!\n", unit); isic_detach_common(dev); return ENXIO; } /* remember the io base addresses */ iobase1 = rman_get_start(sc->sc_resources.io_base[0]); iobase2 = rman_get_start(sc->sc_resources.io_base[1]); /* * because overlapping resources are invalid, * release the first io port resource */ bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); /* set and allocate a base io address for the ISAC chip */ sc->sc_resources.io_rid[2] = 2; bus_set_resource(dev, SYS_RES_IOPORT, 2, iobase1-0x20, 0x40); if(!(sc->sc_resources.io_base[2] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[2], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get io area 2 for Creatix / Teles PnP!\n", unit); isic_detach_common(dev); return ENXIO; } /* * because overlapping resources are invalid, * release the second io port resource */ bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_resources.io_rid[1], sc->sc_resources.io_base[1]); /* set and allocate a resource for the HSCX channel A */ sc->sc_resources.io_rid[3] = 3; /*XXX*/ /* FIXME !!!! * the width of the resource is too small, there are accesses * to it with an offset of 0x3e into the next resource. anyway, * it seems to work and i have no idea how to do 2 resources * overlapping each other. */ #if 0 bus_set_resource(dev, SYS_RES_IOPORT, 3, iobase2-0x20, 0x20); #else bus_set_resource(dev, SYS_RES_IOPORT, 3, iobase2-0x20, 0x10); #endif if(!(sc->sc_resources.io_base[3] = bus_alloc_resource(dev,SYS_RES_IOPORT, &sc->sc_resources.io_rid[3], 0ul,~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get io area 3 for Creatix / Teles PnP!\n", unit); isic_detach_common(dev); return ENXIO; } /* set and allocate a resources for the HSCX channel B */ sc->sc_resources.io_rid[4] = 4; bus_set_resource(dev, SYS_RES_IOPORT, 4, iobase2, 0x40); if(!(sc->sc_resources.io_base[4] = bus_alloc_resource(dev,SYS_RES_IOPORT, &sc->sc_resources.io_rid[4], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get io area 4 for Creatix / Teles PnP!\n", unit); isic_detach_common(dev); return ENXIO; } /* 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; /* enable the card */ t = rman_get_bustag(sc->sc_resources.io_base[2]); h = rman_get_bushandle(sc->sc_resources.io_base[2]); bus_space_write_1(t, h, 0x3c, 0); DELAY(SEC_DELAY / 10); bus_space_write_1(t, h, 0x3c, 1); DELAY(SEC_DELAY / 10); return 0; } #endif /* (NISIC > 0) && (defined(CRTX_S0_P) || defined(TEL_S0_16_3_P)) */ Index: head/sys/i4b/layer1/isic/i4b_drn_ngo.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_drn_ngo.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_drn_ngo.c (revision 67973) @@ -1,267 +1,265 @@ /* * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:43:21 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if (NISIC > 0) && defined(DRN_NGO) #include #include #include #include -#include #include #include -#include #include /*---------------------------------------------------------------------------* * 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 */ #define ISAC_DATA 0 #define HSCX_DATA 1 #define ISAC_ADDR 0 #define HSCX_ADDR 1 /*---------------------------------------------------------------------------* * Dr. Neuhaus Niccy GO@ read fifo routine *---------------------------------------------------------------------------*/ static void drnngo_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t tdata, tadr; bus_space_handle_t hdata, hadr; tdata = rman_get_bustag(sc->sc_resources.io_base[0]); hdata = rman_get_bushandle(sc->sc_resources.io_base[0]); tadr = rman_get_bustag(sc->sc_resources.io_base[1]); hadr = rman_get_bushandle(sc->sc_resources.io_base[1]); switch(what) { case ISIC_WHAT_ISAC: bus_space_write_1 (tadr ,hadr, ISAC_ADDR,0x0); bus_space_read_multi_1(tdata,hdata,ISAC_DATA,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1 (tadr ,hadr ,HSCX_ADDR,0x0); bus_space_read_multi_1(tdata,hdata,HSCX_DATA,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1 (tadr ,hadr ,HSCX_ADDR,HSCX_BOFF); bus_space_read_multi_1(tdata,hdata,HSCX_DATA,buf,size); break; } } /*---------------------------------------------------------------------------* * Dr. Neuhaus Niccy GO@ write fifo routine *---------------------------------------------------------------------------*/ static void drnngo_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t tdata, tadr; bus_space_handle_t hdata, hadr; tdata = rman_get_bustag(sc->sc_resources.io_base[0]); hdata = rman_get_bushandle(sc->sc_resources.io_base[0]); tadr = rman_get_bustag(sc->sc_resources.io_base[1]); hadr = rman_get_bushandle(sc->sc_resources.io_base[1]); switch(what) { case ISIC_WHAT_ISAC: bus_space_write_1 (tadr ,hadr, ISAC_ADDR,0x0); bus_space_write_multi_1(tdata,hdata,ISAC_DATA,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1 (tadr ,hadr ,HSCX_ADDR,0x0); bus_space_write_multi_1(tdata,hdata,HSCX_DATA,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1 (tadr ,hadr ,HSCX_ADDR,HSCX_BOFF); bus_space_write_multi_1(tdata,hdata,HSCX_DATA,buf,size); break; } } /*---------------------------------------------------------------------------* * Dr. Neuhaus Niccy GO@ write register routine *---------------------------------------------------------------------------*/ static void drnngo_write_reg(struct l1_softc *sc, int what, bus_size_t reg, u_int8_t data) { bus_space_tag_t tdata, tadr; bus_space_handle_t hdata, hadr; tdata = rman_get_bustag(sc->sc_resources.io_base[0]); hdata = rman_get_bushandle(sc->sc_resources.io_base[0]); tadr = rman_get_bustag(sc->sc_resources.io_base[1]); hadr = rman_get_bushandle(sc->sc_resources.io_base[1]); switch(what) { case ISIC_WHAT_ISAC: bus_space_write_1(tadr ,hadr, ISAC_ADDR,reg); bus_space_write_1(tdata,hdata,ISAC_DATA,data); break; case ISIC_WHAT_HSCXA: bus_space_write_1(tadr ,hadr ,HSCX_ADDR,reg); bus_space_write_1(tdata,hdata,HSCX_DATA,data); break; case ISIC_WHAT_HSCXB: bus_space_write_1(tadr ,hadr ,HSCX_ADDR,reg+HSCX_BOFF); bus_space_write_1(tdata,hdata,HSCX_DATA,data); break; } } /*---------------------------------------------------------------------------* * Dr. Neuhaus Niccy GO@ read register routine *---------------------------------------------------------------------------*/ static u_int8_t drnngo_read_reg(struct l1_softc *sc, int what, bus_size_t reg) { bus_space_tag_t tdata, tadr; bus_space_handle_t hdata, hadr; tdata = rman_get_bustag(sc->sc_resources.io_base[0]); hdata = rman_get_bushandle(sc->sc_resources.io_base[0]); tadr = rman_get_bustag(sc->sc_resources.io_base[1]); hadr = rman_get_bushandle(sc->sc_resources.io_base[1]); switch(what) { case ISIC_WHAT_ISAC: bus_space_write_1(tadr ,hadr, ISAC_ADDR,reg); return bus_space_read_1(tdata,hdata,ISAC_DATA); case ISIC_WHAT_HSCXA: bus_space_write_1(tadr ,hadr ,HSCX_ADDR,reg); return bus_space_read_1(tdata,hdata,HSCX_DATA); case ISIC_WHAT_HSCXB: bus_space_write_1(tadr ,hadr ,HSCX_ADDR,reg+HSCX_BOFF); return bus_space_read_1(tdata,hdata,HSCX_DATA); default: return 0; } } /*---------------------------------------------------------------------------* * probe for ISA PnP cards *---------------------------------------------------------------------------*/ int isic_attach_drnngo(device_t dev) { int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; sc->sc_resources.io_rid[1] = 1; /* * this card needs a second io_base, * free resources if we don't get it */ if(!(sc->sc_resources.io_base[1] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[1], 0UL, ~0UL, 1, RF_ACTIVE))) { printf("isic%d: Failed to get second io base.\n", unit); isic_detach_common(dev); return ENXIO; } /* 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; return (0); } #endif /* (NISIC > 0) && defined(DRN_NGO) */ Index: head/sys/i4b/layer1/isic/i4b_dynalink.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_dynalink.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_dynalink.c (revision 67973) @@ -1,237 +1,235 @@ /* * 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.1 2000/09/04 09:17:26 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon Sep 4 09:47:18 2000] * *---------------------------------------------------------------------------*/ /* 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. */ #include "isic.h" #include "opt_i4b.h" #if (NISIC > 0) && defined(DYNALINK) #include #include #include #include -#include #include #include -#include #include /* 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 /* LOW-LEVEL DEVICE ACCESS */ static void dynalink_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } static void dynalink_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } static void dynalink_write_reg(struct l1_softc *sc, int what, bus_size_t reg, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: bus_space_write_1(t, h, ADDR, reg); bus_space_write_1(t, h, ISAC, data); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t, h, ADDR, HSCXA+reg); bus_space_write_1(t, h, HSCX, data); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t, h, ADDR, HSCXB+reg); bus_space_write_1(t, h, HSCX, data); break; } } static u_int8_t dynalink_read_reg(struct l1_softc *sc, int what, bus_size_t reg) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch (what) { case ISIC_WHAT_ISAC: bus_space_write_1(t, h, ADDR, reg); return bus_space_read_1(t, h, ISAC); case ISIC_WHAT_HSCXA: bus_space_write_1(t, h, ADDR, HSCXA+reg); return bus_space_read_1(t, h, HSCX); case ISIC_WHAT_HSCXB: bus_space_write_1(t, h, ADDR, HSCXB+reg); return bus_space_read_1(t, h, HSCX); } return 0; } /* attach callback routine */ int isic_attach_Dyn(device_t dev) { int unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = &l1_sc[unit]; /* pointer to softc */ struct i4b_info * info = &(sc->sc_resources); bus_space_tag_t t = rman_get_bustag(info->io_base[0]); bus_space_handle_t h = rman_get_bushandle(info->io_base[0]); /* fill in l1_softc structure */ sc->readreg = dynalink_read_reg; sc->writereg = dynalink_write_reg; sc->readfifo = dynalink_read_fifo; sc->writefifo = dynalink_write_fifo; sc->clearirq = NULL; sc->sc_cardtyp = CARD_TYPEP_DYNALINK; 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("isic%d: HSCX VSTR test failed for Dynalink\n", sc->sc_unit); printf("isic%d: HSC0: VSTR: %#x\n", sc->sc_unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", sc->sc_unit, HSCX_READ(1, H_VSTR)); return ENXIO; } /* reset card */ bus_space_write_1(t,h,ADDR,RESET); DELAY(SEC_DELAY / 10); bus_space_write_1(t,h,ADDR,0); DELAY(SEC_DELAY / 10); return 0; } #endif /* (NISIC > 0) && defined(DYNALINK) */ Index: head/sys/i4b/layer1/isic/i4b_elsa_pcc16.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_elsa_pcc16.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_elsa_pcc16.c (revision 67973) @@ -1,401 +1,399 @@ /* * Copyright (c) 1999, 2000 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 MicroLink ISDN/PCC-16 * ===================================================================== * * This should now also work for an ELSA PCFpro. * * $Id: i4b_elsa_pcc16.c,v 1.4 2000/07/19 07:51:22 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:00:01 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if (NISIC > 0) && defined(ELSA_PCC16) #include #include #include #include -#include #include #include -#include #include static void i4b_epcc16_clrirq(struct l1_softc *sc); /* 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 MicroLink ISDN/PCC-16 clear IRQ routine *---------------------------------------------------------------------------*/ static void i4b_epcc16_clrirq(struct l1_softc *sc) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_write_1(t, h, ELSA_OFF_IRQ, 0); } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCC-16 ISAC get fifo routine *---------------------------------------------------------------------------*/ static void epcc16_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCC-16 ISAC put fifo routine *---------------------------------------------------------------------------*/ static void epcc16_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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, 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, 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, buf, size); break; } } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCC-16 ISAC put register routine *---------------------------------------------------------------------------*/ static void epcc16_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCC-16 ISAC get register routine *---------------------------------------------------------------------------*/ static u_int8_t epcc16_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } /*---------------------------------------------------------------------------* * isic_detach_Epcc16 - detach for ELSA MicroLink ISDN/PCC-16 *---------------------------------------------------------------------------*/ static void isic_detach_Epcc16(device_t dev) { struct l1_softc *sc = &l1_sc[device_get_unit(dev)]; if ( sc->sc_resources.irq ) { bus_teardown_intr(dev,sc->sc_resources.irq, (void(*)(void *))isicintr); bus_release_resource(dev,SYS_RES_IRQ, sc->sc_resources.irq_rid, sc->sc_resources.irq); sc->sc_resources.irq = 0; } if ( sc->sc_resources.io_base[0] ) { bus_release_resource(dev,SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); sc->sc_resources.io_base[0] = 0; } } /*---------------------------------------------------------------------------* * isic_probe_Epcc16 - probe for ELSA MicroLink ISDN/PCC-16 *---------------------------------------------------------------------------*/ int isic_probe_Epcc16(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* pointer to softc */ void *ih = 0; /* dummy */ /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA PCC-16!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_ELSA_PCC16; /* set flags */ /* see if an io base was supplied */ if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get iobase for ELSA PCC-16.\n", unit); return(ENXIO); } /* check if we got an iobase */ sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); switch(sc->sc_port) { case 0x160: case 0x170: case 0x260: case 0x360: break; default: printf("isic%d: Error, invalid iobase 0x%x specified for ELSA MicroLink ISDN/PCC-16!\n", unit, sc->sc_port); isic_detach_Epcc16(dev); return(ENXIO); break; } /* setup access routines */ sc->clearirq = i4b_epcc16_clrirq; sc->readreg = epcc16_read_reg; sc->writereg = epcc16_write_reg; sc->readfifo = epcc16_read_fifo; sc->writefifo = epcc16_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; /* * Read HSCX A/B VSTR. Expected value for the ELSA PCC-16 * 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) ) { /* patch from "Doobee R . Tzeck" : * I own an ELSA PCFpro. To my knowledge, the ELSA PCC16 is * a stripped down Version on the PCFpro. By patching the * card detection routine for the PPC16 I was able to use * the PPC16 driver for the PCFpro. */ if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x85) || ((HSCX_READ(1, H_VSTR) & 0xf) != 0x85) ) { printf("isic%d: HSCX VSTR test failed for ELSA MicroLink ISDN/PCC-16\n", unit); isic_detach_Epcc16(dev); printf("isic%d: HSC0: VSTR: %#x\n", unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", unit, HSCX_READ(1, H_VSTR)); return (ENXIO); } else { printf("isic%d: ELSA MicroLink ISDN/PCFpro found, going to tread it as PCC-16\n", unit); } } /* get our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get an irq.\n",unit); isic_detach_Epcc16(dev); return ENXIO; } /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); /* check IRQ validity */ switch(sc->sc_irq) { case 2: case 9: case 3: case 5: case 10: case 11: case 15: break; default: printf("isic%d: Error, invalid IRQ [%d] specified for ELSA MicroLink ISDN/PCC-16!\n", unit, sc->sc_irq); isic_detach_Epcc16(dev); return(ENXIO); break; } /* register interupt routine */ bus_setup_intr(dev,sc->sc_resources.irq,INTR_TYPE_NET, (void(*)(void *))(isicintr), sc,&ih); return (0); } /*---------------------------------------------------------------------------* * isic_attach_Epcc16 - attach for ELSA MicroLink ISDN/PCC-16 *---------------------------------------------------------------------------*/ int isic_attach_Epcc16(device_t dev) { int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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); return 0; } #endif /* (NISIC > 0) && defined(ELSA_PCC16) */ Index: head/sys/i4b/layer1/isic/i4b_elsa_qs1i.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_elsa_qs1i.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_elsa_qs1i.c (revision 67973) @@ -1,242 +1,240 @@ /* * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:00:15 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if (NISIC > 0) && defined(ELSA_QS1ISA) #include #include #include #include -#include #include #include -#include #include static void i4b_eq1i_clrirq(struct l1_softc *sc); /* 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 *---------------------------------------------------------------------------*/ static void i4b_eq1i_clrirq(struct l1_softc *sc) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_write_1(t, h, ELSA_OFF_IRQ, 0); } /*---------------------------------------------------------------------------* * ELSA QuickStep 1000pro/ISA ISAC get fifo routine *---------------------------------------------------------------------------*/ static void eqs1pi_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } /*---------------------------------------------------------------------------* * ELSA QuickStep 1000pro/ISA ISAC put fifo routine *---------------------------------------------------------------------------*/ static void eqs1pi_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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, 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, 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, buf, size); break; } } /*---------------------------------------------------------------------------* * ELSA QuickStep 1000pro/ISA ISAC put register routine *---------------------------------------------------------------------------*/ static void eqs1pi_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } /*---------------------------------------------------------------------------* * ELSA QuickStep 1000pro/ISA ISAC get register routine *---------------------------------------------------------------------------*/ static u_int8_t eqs1pi_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } /*---------------------------------------------------------------------------* * isic_attach_Eqs1pi - attach for ELSA QuickStep 1000pro/ISA *---------------------------------------------------------------------------*/ int isic_attach_Eqs1pi(device_t dev) { int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); u_char byte = ELSA_CTRL_SECRET; /* 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; /* enable the card */ 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); return 0; } #endif /* (NISIC > 0) && defined(ELSA_QS1ISA) */ Index: head/sys/i4b/layer1/isic/i4b_elsa_qs1p.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_elsa_qs1p.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_elsa_qs1p.c (revision 67973) @@ -1,359 +1,355 @@ /* * Copyright (c) 1997, 2000 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 MicroLink ISDN/PCI * ================================================================== * * $Id: i4b_elsa_qs1p.c,v 1.4 2000/06/02 11:58:56 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:00:24 2000] * * Note: ELSA Quickstep 1000pro PCI = ELSA MicroLink ISDN/PCI * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #include "pci.h" #if (NISIC > 0) && (NPCI > 0) && defined(ELSA_QS1PCI) #include #include #include #include #include #include -#include #include #include #include #include -#include #include #include -#include -#include #include #define MEM0_MAPOFF 0 #define PORT0_MAPOFF 4 #define PORT1_MAPOFF 12 #define ELSA_PORT0_MAPOFF (PCIR_MAPS+PORT0_MAPOFF) #define ELSA_PORT1_MAPOFF (PCIR_MAPS+PORT1_MAPOFF) #define PCI_QS1000_DID 0x1000 #define PCI_QS1000_VID 0x1048 /* 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 static int eqs1p_pci_probe(device_t dev); static int eqs1p_pci_attach(device_t dev); static device_method_t eqs1p_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, eqs1p_pci_probe), DEVMETHOD(device_attach, eqs1p_pci_attach), { 0, 0 } }; static driver_t eqs1p_pci_driver = { "isic", eqs1p_pci_methods, 0 }; static devclass_t eqs1p_pci_devclass; DRIVER_MODULE(eqs1p, pci, eqs1p_pci_driver, eqs1p_pci_devclass, 0, 0); /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCI fifo read routine *---------------------------------------------------------------------------*/ static void eqs1pp_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]); 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; } } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCI fifo write routine *---------------------------------------------------------------------------*/ static void eqs1pp_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]); 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; } } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCI register write routine *---------------------------------------------------------------------------*/ static void eqs1pp_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]); 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; } } /*---------------------------------------------------------------------------* * ELSA MicroLink ISDN/PCI register read routine *---------------------------------------------------------------------------*/ static u_int8_t eqs1pp_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[1]); 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; } /*---------------------------------------------------------------------------* * avma1pp_probe - probe for a card *---------------------------------------------------------------------------*/ static int eqs1p_pci_probe(device_t dev) { if((pci_get_vendor(dev) == PCI_QS1000_VID) && (pci_get_device(dev) == PCI_QS1000_DID)) { device_set_desc(dev, "ELSA MicroLink ISDN/PCI"); return(0); } return(ENXIO); } /*---------------------------------------------------------------------------* * isic_attach_Eqs1pp - attach for ELSA MicroLink ISDN/PCI *---------------------------------------------------------------------------*/ static int eqs1p_pci_attach(device_t dev) { bus_space_tag_t t; bus_space_handle_t h; struct l1_softc *sc; void *ih = 0; int unit = device_get_unit(dev); /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ELSA MicroLink ISDN/PCI!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get softc */ sc->sc_unit = unit; /* get io_base */ sc->sc_resources.io_rid[0] = ELSA_PORT0_MAPOFF; if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0UL, ~0UL, 1, RF_ACTIVE))) { printf("isic%d: Couldn't get first iobase for ELSA MicroLink ISDN/PCI!\n", unit); return(ENXIO); } sc->sc_resources.io_rid[1] = ELSA_PORT1_MAPOFF; if(!(sc->sc_resources.io_base[1] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[1], 0UL, ~0UL, 1, RF_ACTIVE))) { printf("isic%d: Couldn't get second iobase for ELSA MicroLink ISDN/PCI!\n", unit); isic_detach_common(dev); return(ENXIO); } sc->sc_port = rman_get_start(sc->sc_resources.io_base[1]); if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0UL, ~0UL, 1, RF_ACTIVE))) { printf("isic%d: Could not get irq for ELSA MicroLink ISDN/PCI!\n",unit); isic_detach_common(dev); return(ENXIO); } sc->sc_irq = rman_get_start(sc->sc_resources.irq); /* 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; if(isic_attach_common(dev)) { isic_detach_common(dev); return(ENXIO); } if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void*))isicintr, sc, &ih)) { printf("isic%d: Couldn't set up irq for ELSA MicroLink ISDN/PCI!\n", unit); isic_detach_common(dev); return(ENXIO); } /* 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 */ t = rman_get_bustag(sc->sc_resources.io_base[0]); h = rman_get_bushandle(sc->sc_resources.io_base[0]); bus_space_write_1(t, h, 0x4c, 0x41); /* enable card interrupt */ return(0); } #endif /* (NISIC > 0) && (NPCI > 0) && defined(ELSA_QS1PCI) */ Index: head/sys/i4b/layer1/isic/i4b_hscx.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_hscx.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_hscx.c (revision 67973) @@ -1,665 +1,663 @@ /* * Copyright (c) 1997, 2000 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.7 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:44:50 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #if NISIC > 0 #include #include #include #include -#include #include #include #include #include #include -#include #include #include #include #include /*---------------------------------------------------------------------------* * HSCX IRQ Handler *---------------------------------------------------------------------------*/ void isic_hscx_irq(register struct l1_softc *sc, u_char ista, int h_chan, u_char ex_irq) { register l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; u_char exir = 0; int activity = -1; u_char cmd = 0; NDBGL1(L1_H_IRQ, "%#x", ista); if(ex_irq) { /* get channel extended irq reg */ exir = HSCX_READ(h_chan, H_EXIR); if(exir & HSCX_EXIR_RFO) { chan->stat_RFO++; NDBGL1(L1_H_XFRERR, "ex_irq: receive data overflow"); } if((exir & HSCX_EXIR_XDU) && (chan->bprot != BPROT_NONE))/* xmit data underrun */ { chan->stat_XDU++; NDBGL1(L1_H_XFRERR, "ex_irq: xmit data underrun"); 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); NDBGL1(L1_H_XFRERR, "received invalid Frame"); error++; } if(rsta & HSCX_RSTA_RDO) { chan->stat_RDO++; NDBGL1(L1_H_XFRERR, "receive data overflow"); error++; } if((rsta & HSCX_RSTA_CRC) == 0) { chan->stat_CRC++; cmd |= (HSCX_CMDR_RHR); NDBGL1(L1_H_XFRERR, "CRC check failed"); error++; } if(rsta & HSCX_RSTA_RAB) { chan->stat_RAB++; NDBGL1(L1_H_XFRERR, "Receive message aborted"); 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 = L0ISICUNIT(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); i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); } (*chan->isic_drvr_linktab->bch_rx_data_ready)(chan->isic_drvr_linktab->unit); activity = ACT_RX; /* mark buffer ptr as unused */ chan->in_mbuf = NULL; chan->in_cbptr = NULL; chan->in_len = 0; } else { NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RME, in_len=%d, fifolen=%d", 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 = L0ISICUNIT(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); i4b_l1_trace_ind(&hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data); } /* silence detection */ if(!(i4b_l1_bchan_tel_silence(chan->in_mbuf->m_data, chan->in_mbuf->m_len))) activity = ACT_RX; if(!(IF_QFULL(&chan->rx_queue))) { IF_ENQUEUE(&chan->rx_queue, chan->in_mbuf); } else { i4b_Bfreembuf(chan->in_mbuf); } /* signal upper driver that data is available */ (*chan->isic_drvr_linktab->bch_rx_data_ready)(chan->isic_drvr_linktab->unit); /* 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 { NDBGL1(L1_H_XFRERR, "RAWHDLC rx buffer overflow in RPF, in_len=%d", 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; NDBGL1(L1_H_IRQ, "unit %d, chan %d - XPR, Tx Fifo Empty!", 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->isic_drvr_linktab->bch_tx_queue_empty)(chan->isic_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 = L0ISICUNIT(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); i4b_l1_trace_ind(&hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data); } if(chan->bprot == BPROT_NONE) { if(!(i4b_l1_bchan_tel_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 = L0ISICUNIT(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); i4b_l1_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->isic_drvr_linktab->bch_activity)(chan->isic_drvr_linktab->unit, activity); } /*---------------------------------------------------------------------------* * HSCX initialization * * for telephony: extended transparent mode 1 * for raw hdlc: transparent mode 0 *---------------------------------------------------------------------------*/ void isic_hscx_init(struct l1_softc *sc, int h_chan, int activate) { l1_bchan_state_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); } #if 0 isic_hscx_cmd(sc, h_chan, HSCX_CMDR_RHR|HSCX_CMDR_XRES); #else isic_hscx_cmd(sc, h_chan, HSCX_CMDR_RHR); #endif } 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 l1_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) { NDBGL1(L1_H_ERR, "HSCX wait for CEC timeout!"); } HSCX_WRITE(h_chan, H_CMDR, cmd); } /*---------------------------------------------------------------------------* * wait for HSCX transmit FIFO write enable *---------------------------------------------------------------------------*/ void isic_hscx_waitxfw(struct l1_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) { NDBGL1(L1_H_ERR, "HSCX wait for XFW timeout!"); } else if (timeout != WAITTO) { NDBGL1(L1_H_XFRERR, "HSCX wait for XFW time: %d uS", (WAITTO-timeout)*50); } } #endif /* NISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_isac.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_isac.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_isac.c (revision 67973) @@ -1,664 +1,663 @@ /* * Copyright (c) 1997, 2000 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.7 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:45:08 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #if NISIC > 0 #include "opt_i4b.h" #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include static u_char isic_isac_exir_hdlr(register struct l1_softc *sc, u_char exir); static void isic_isac_ind_hdlr(register struct l1_softc *sc, int ind); /*---------------------------------------------------------------------------* * ISAC interrupt service routine *---------------------------------------------------------------------------*/ void isic_isac_irq(struct l1_softc *sc, int ista) { register u_char c = 0; NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista); if(ista & ISAC_ISTA_EXI) /* extended interrupt */ { c |= 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++; NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit); } if(rsta & ISAC_RSTA_RDO) /* ReceiveDataOverflow */ { error++; NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit); } if(rsta & ISAC_RSTA_RAB) /* ReceiveABorted */ { error++; NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit); } if(error == 0) NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTA = 0x%02x!", sc->sc_unit, rsta); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; ISAC_WRITE(I_CMDR, ISAC_CMDR_RMC|ISAC_CMDR_RRES); ISACCMDRWRDELAY(); return; } rest = (ISAC_READ(I_RBCL) & (ISAC_FIFO_LEN-1)); if(rest == 0) rest = ISAC_FIFO_LEN; if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL) sc->sc_ib = sc->sc_ibuf->m_data; else panic("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 = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_D; hdr.dir = FROM_NT; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data); } c |= ISAC_CMDR_RMC; if(sc->sc_enabled && (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S)) { i4b_l1_ph_data_ind(L0ISICUNIT(sc->sc_unit), sc->sc_ibuf); } else { i4b_Dfreembuf(sc->sc_ibuf); } } else { NDBGL1(L1_I_ERR, "RME, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; } if(ista & ISAC_ISTA_RPF) /* receive fifo full */ { if(sc->sc_ibuf == NULL) { if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL) sc->sc_ib= sc->sc_ibuf->m_data; else panic("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 { NDBGL1(L1_I_ERR, "RPF, input buffer overflow!"); i4b_Dfreembuf(sc->sc_ibuf); sc->sc_ibuf = NULL; sc->sc_ib = NULL; sc->sc_ilen = 0; c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } } if(ista & ISAC_ISTA_XPR) /* transmit fifo empty (XPR bit set) */ { if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL)) { sc->sc_freeflag = sc->sc_freeflag2; sc->sc_obuf = sc->sc_obuf2; sc->sc_op = sc->sc_obuf->m_data; sc->sc_ol = sc->sc_obuf->m_len; sc->sc_obuf2 = NULL; #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 l1_softc *sc, u_char exir) { u_char c = 0; if(exir & ISAC_EXIR_XMR) { NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat"); c |= ISAC_CMDR_XRES; } if(exir & ISAC_EXIR_XDU) { NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun"); c |= ISAC_CMDR_XRES; } if(exir & ISAC_EXIR_PCE) { NDBGL1(L1_I_ERR, "EXIRQ Protocol Error"); } if(exir & ISAC_EXIR_RFO) { NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow"); c |= ISAC_CMDR_RMC|ISAC_CMDR_RRES; } if(exir & ISAC_EXIR_SOV) { NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow"); } if(exir & ISAC_EXIR_MOS) { NDBGL1(L1_I_ERR, "EXIRQ Monitor Status"); } if(exir & ISAC_EXIR_SAW) { /* cannot happen, STCR:TSF is set to 0 */ NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake"); } if(exir & ISAC_EXIR_WOV) { /* cannot happen, STCR:TSF is set to 0 */ NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow"); } return(c); } /*---------------------------------------------------------------------------* * ISAC L1 Indication handler *---------------------------------------------------------------------------*/ static void isic_isac_ind_hdlr(register struct l1_softc *sc, int ind) { register int event; switch(ind) { case ISAC_CIRR_IAI8: NDBGL1(L1_I_CICO, "rx AI8 in state %s", isic_printstate(sc)); if(sc->sc_bustyp == BUS_TYPE_IOM2) isic_isac_l1_cmd(sc, CMD_AR8); event = EV_INFO48; i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); break; case ISAC_CIRR_IAI10: NDBGL1(L1_I_CICO, "rx AI10 in state %s", isic_printstate(sc)); if(sc->sc_bustyp == BUS_TYPE_IOM2) isic_isac_l1_cmd(sc, CMD_AR10); event = EV_INFO410; i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL); break; case ISAC_CIRR_IRSY: NDBGL1(L1_I_CICO, "rx RSY in state %s", isic_printstate(sc)); event = EV_RSY; break; case ISAC_CIRR_IPU: NDBGL1(L1_I_CICO, "rx PU in state %s", isic_printstate(sc)); event = EV_PU; break; case ISAC_CIRR_IDR: NDBGL1(L1_I_CICO, "rx DR in state %s", isic_printstate(sc)); isic_isac_l1_cmd(sc, CMD_DIU); event = EV_DR; break; case ISAC_CIRR_IDID: NDBGL1(L1_I_CICO, "rx DID in state %s", isic_printstate(sc)); event = EV_INFO0; i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL); break; case ISAC_CIRR_IDIS: NDBGL1(L1_I_CICO, "rx DIS in state %s", isic_printstate(sc)); event = EV_DIS; break; case ISAC_CIRR_IEI: NDBGL1(L1_I_CICO, "rx EI in state %s", isic_printstate(sc)); isic_isac_l1_cmd(sc, CMD_DIU); event = EV_EI; break; case ISAC_CIRR_IARD: NDBGL1(L1_I_CICO, "rx ARD in state %s", isic_printstate(sc)); event = EV_INFO2; break; case ISAC_CIRR_ITI: NDBGL1(L1_I_CICO, "rx TI in state %s", isic_printstate(sc)); event = EV_INFO0; break; case ISAC_CIRR_IATI: NDBGL1(L1_I_CICO, "rx ATI in state %s", isic_printstate(sc)); event = EV_INFO0; break; case ISAC_CIRR_ISD: NDBGL1(L1_I_CICO, "rx SD in state %s", isic_printstate(sc)); event = EV_INFO0; break; default: NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, isic_printstate(sc)); event = EV_INFO0; break; } isic_next_state(sc, event); } /*---------------------------------------------------------------------------* * execute a layer 1 command *---------------------------------------------------------------------------*/ void isic_isac_l1_cmd(struct l1_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) { NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, isic_printstate(sc)); return; } if(sc->sc_bustyp == BUS_TYPE_IOM2) cmd = ISAC_CIX0_LOW; else cmd = 0; switch(command) { case CMD_TIM: NDBGL1(L1_I_CICO, "tx TIM in state %s", isic_printstate(sc)); cmd |= (ISAC_CIXR_CTIM << 2); break; case CMD_RS: NDBGL1(L1_I_CICO, "tx RS in state %s", isic_printstate(sc)); cmd |= (ISAC_CIXR_CRS << 2); break; case CMD_AR8: NDBGL1(L1_I_CICO, "tx AR8 in state %s", isic_printstate(sc)); cmd |= (ISAC_CIXR_CAR8 << 2); break; case CMD_AR10: NDBGL1(L1_I_CICO, "tx AR10 in state %s", isic_printstate(sc)); cmd |= (ISAC_CIXR_CAR10 << 2); break; case CMD_DIU: NDBGL1(L1_I_CICO, "tx DIU in state %s", isic_printstate(sc)); cmd |= (ISAC_CIXR_CDIU << 2); break; } ISAC_WRITE(I_CIXR, cmd); } /*---------------------------------------------------------------------------* * L1 ISAC initialization *---------------------------------------------------------------------------*/ int isic_isac_init(struct l1_softc *sc) { ISAC_IMASK = 0xff; /* disable all irqs */ ISAC_WRITE(I_MASK, ISAC_IMASK); if(sc->sc_bustyp != BUS_TYPE_IOM2) { NDBGL1(L1_I_SETUP, "configuring for IOM-1 mode"); /* 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 { NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode"); /* ADF2: Select mode IOM-2 */ ISAC_WRITE(I_ADF2, ISAC_ADF2_IMS); /* SPCR: serial port control register: * SPU - software power up = 0 * SPM - timing mode 0 * TLP - test loop = 0 * C1C, C2C - B1 + C1 and B2 + IC2 monitoring */ ISAC_WRITE(I_SPCR, 0x00); /* SQXR: S/Q channel xmit register: * IDC - IOM direction = 0 (master) * CFS - Config Select = 0 (clock always active) * CI1E - C/I channel 1 IRQ enable = 0 * SQIE - S/Q IRQ enable = 0 * SQX1-4 - Fa bits = 1 */ ISAC_WRITE(I_SQXR, ISAC_SQXR_SQX1|ISAC_SQXR_SQX2|ISAC_SQXR_SQX3|ISAC_SQXR_SQX4); /* ADF1: additional feature reg 1: * WTC - watchdog = 0 * TEM - test mode = 0 * PFS - pre-filter = 0 * IOF - IOM i/f off = 0 * ITF - interframe fill = idle */ ISAC_WRITE(I_ADF1, 0x00); /* STCR: sync transfer control reg: * TSF - terminal secific functions = 0 * TBA - TIC bus address = 7 * STx/SCx = 0 */ ISAC_WRITE(I_STCR, ISAC_STCR_TBA2|ISAC_STCR_TBA1|ISAC_STCR_TBA0); /* MODE: Mode Register: * MDSx - transparent mode 2 * TMD - timer mode = external * RAC - Receiver enabled * DIMx - digital i/f mode */ ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_RAC|ISAC_MODE_DIM0); } #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 */ Index: head/sys/i4b/layer1/isic/i4b_isic_isa.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_isic_isa.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_isic_isa.c (revision 67973) @@ -1,217 +1,212 @@ /* * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:00:46 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 #include #include #include #include #include -#include #include -#include #include -#include -#include -#include #include #include struct l1_softc l1_sc[ISIC_MAXUNIT]; static int isic_isa_probe(device_t dev); static int isic_isa_attach(device_t dev); static device_method_t isic_methods[] = { DEVMETHOD(device_probe, isic_isa_probe), DEVMETHOD(device_attach, isic_isa_attach), { 0, 0 } }; static driver_t isic_driver = { "isic", isic_methods, 0 }; static devclass_t isic_devclass; DRIVER_MODULE(isic, isa, isic_driver, isic_devclass, 0, 0); /*---------------------------------------------------------------------------* * probe for ISA non-PnP cards *---------------------------------------------------------------------------*/ static int isic_isa_probe(device_t dev) { int ret = ENXIO; if(isa_get_vendorid(dev)) /* no PnP probes here */ return ENXIO; switch(device_get_flags(dev)) { #ifdef TEL_S0_16 case FLAG_TELES_S0_16: ret = isic_probe_s016(dev); break; #endif #ifdef TEL_S0_8 case FLAG_TELES_S0_8: ret = isic_probe_s08(dev); break; #endif #ifdef ELSA_PCC16 case FLAG_ELSA_PCC16: ret = isic_probe_Epcc16(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: printf("isic%d: probe, unknown flag: %d\n", device_get_unit(dev), device_get_flags(dev)); break; } return(ret); } /*---------------------------------------------------------------------------* * attach for ISA non-PnP cards *---------------------------------------------------------------------------*/ static int isic_isa_attach(device_t dev) { int ret = ENXIO; struct l1_softc *sc = &l1_sc[device_get_unit(dev)]; sc->sc_unit = device_get_unit(dev); /* card dependent setup */ switch(sc->sc_flags) { #ifdef TEL_S0_16 case FLAG_TELES_S0_16: ret = isic_attach_s016(dev); break; #endif #ifdef TEL_S0_8 case FLAG_TELES_S0_8: ret = isic_attach_s08(dev); break; #endif #ifdef ELSA_PCC16 case FLAG_ELSA_PCC16: ret = isic_attach_Epcc16(dev); break; #endif #ifdef TEL_S0_16_3 case FLAG_TELES_S0_163: ret = isic_attach_s0163(dev); break; #endif #ifdef AVM_A1 case FLAG_AVM_A1: ret = isic_attach_avma1(dev); break; #endif #ifdef USR_STI case FLAG_USR_ISDN_TA_INT: ret = isic_attach_usrtai(dev); break; #endif #ifdef ITKIX1 case FLAG_ITK_IX1: ret = isic_attach_itkix1(dev); break; #endif default: printf("isic%d: attach, unknown flag: %d\n", device_get_unit(dev), device_get_flags(dev)); break; } if(ret) return(ret); ret = isic_attach_common(dev); return(ret); } #endif /* NISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_itk_ix1.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_itk_ix1.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_itk_ix1.c (revision 67973) @@ -1,404 +1,402 @@ /* * Copyright (c) 1998, 1999 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. 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 2000/08/24 14:08:41 hm Exp $ * * last edit-date: [Thu Aug 24 15:44:33 2000] * * $FreeBSD$ * *--------------------------------------------------------------------------- * * 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). * * The probe routine was derived by trial and error from a representative * sample of two cards ;-) The standard way (checking HSCX versions) * was extended by reading a zero from a non existant HSCX register (register * 0xff). Reading the config register gives varying results, so this doesn't * seem to be used as an id register (like the Teles S0/16.3). * * If the probe fails for your card use "options ITK_PROBE_DEBUG" to get * additional debug output. * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 && defined(ITKIX1) #include #include #include #include -#include #include #include -#include #include /* Register offsets */ #define ITK_ISAC_DATA 0 #define ITK_HSCX_DATA 1 #define ITK_ALE 2 #define ITK_CONFIG 3 /* Size of IO range to allocate for this card */ #define ITK_IO_SIZE 4 /* Register offsets for the two HSCX channels */ #define HSCXA 0 #define HSCXB 0x40 static void itkix1_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } static void itkix1_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } static void itkix1_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } } static u_int8_t itkix1_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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; } /* * Probe for card */ int isic_probe_itkix1(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* softc */ void *ih = 0; /* dummy */ bus_space_tag_t t; /* bus things */ bus_space_handle_t h; u_int8_t hd, hv1, hv2, saveale; int ret; #if defined(ITK_PROBE_DEBUG) printf("Checking unit %u\n", unit); #endif /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for ITK IX1!\n", unit, unit); return ENXIO; } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_ITK_IX1; /* set flags */ #if defined(ITK_PROBE_DEBUG) printf("Allocating io base..."); #endif if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not allocate i/o port for ITK IX1.\n", unit); return ENXIO; } #if defined(ITK_PROBE_DEBUG) printf("done.\n"); #endif sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); t = rman_get_bustag(sc->sc_resources.io_base[0]); h = rman_get_bushandle(sc->sc_resources.io_base[0]); #if defined(ITK_PROBE_DEBUG) printf("Allocating irq..."); #endif /* get our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not allocate irq for ITK IX1.\n", unit); bus_release_resource(dev,SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); return ENXIO; } #if defined(ITK_PROBE_DEBUG) printf("done.\n"); #endif /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); #if defined(ITK_PROBE_DEBUG) printf("Setting up access routines..."); #endif /* 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; #if defined(ITK_PROBE_DEBUG) printf("done.\n"); #endif /* register interupt routine */ #if defined(ITK_PROBE_DEBUG) printf("Setting up access interupt..."); #endif bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void *))(isicintr), sc, &ih); #if defined(ITK_PROBE_DEBUG) printf("done.\n"); printf("Doing probe stuff..."); #endif /* save old value of this port, we're stomping over it */ saveale = bus_space_read_1(t, h, ITK_ALE); /* select invalid register */ bus_space_write_1(t, h, ITK_ALE, 0xff); /* get HSCX data for this non existent register */ hd = bus_space_read_1(t, h, ITK_HSCX_DATA); /* get HSCX version info */ bus_space_write_1(t, h, ITK_ALE, HSCXA + H_VSTR); hv1 = bus_space_read_1(t, h, ITK_HSCX_DATA); bus_space_write_1(t, h, ITK_ALE, HSCXB + H_VSTR); hv2 = bus_space_read_1(t, h, ITK_HSCX_DATA); ret = (hd == 0) && ((hv1 & 0x0f) == 0x05) && ((hv2 & 0x0f) == 0x05); /* succeed if version bits are OK and we got a zero from the * non existent register. we found verison 0x05 and 0x04 * out there... */ ret = (hd == 0) && (((hv1 & 0x0f) == 0x05) || ((hv1 & 0x0f) == 0x04)) && (((hv2 & 0x0f) == 0x05) || ((hv2 & 0x0f) == 0x04)); /* retstore save value if we fail (if we succeed the old value * has no meaning) */ if (!ret) bus_space_write_1(t, h, ITK_ALE, saveale); #if defined(ITK_PROBE_DEBUG) printf("done.\n"); printf("Doing second probe stuff..."); #endif hv1 = HSCX_READ(0, H_VSTR) & 0xf; hv2 = HSCX_READ(1, H_VSTR) & 0xf; /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */ if((hv1 != 0x05 && hv1 != 0x04) || (hv2 != 0x05 && hv2 != 0x04)) { printf("isic%d: HSCX VSTR test failed for ITK ix1 micro\n", unit); printf("isic%d: HSC0: VSTR: %#x\n", unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", unit, HSCX_READ(1, H_VSTR)); isic_detach_common(dev); return ENXIO; } #if defined(ITK_PROBE_DEBUG) printf("done.\n"); #endif #if defined(ITK_PROBE_DEBUG) printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n", hd, hv1, hv2, ret ? "succeeded" : "failed"); isic_detach_common(dev); return ENXIO; #else if ( ret ) { return 0; } else { isic_detach_common(dev); return ENXIO; } #endif } /* * Attach card */ int isic_attach_itkix1(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = &l1_sc[unit]; bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); /* 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; bus_space_write_1(t, h, ITK_CONFIG, 1); DELAY(SEC_DELAY / 10); bus_space_write_1(t, h, ITK_CONFIG, 0); DELAY(SEC_DELAY / 10); return 0; } #endif /* ITKIX1 */ Index: head/sys/i4b/layer1/isic/i4b_l1.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_l1.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_l1.c (revision 67973) @@ -1,259 +1,257 @@ /* * Copyright (c) 1997, 2000 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.7 2000/06/02 16:14:36 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Jun 2 18:09:53 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #if NISIC > 0 #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include /*---------------------------------------------------------------------------* * * L2 -> L1: PH-DATA-REQUEST * ========================= * * parms: * unit physical interface unit number * m mbuf containing L2 frame to be sent out * freeflag MBUF_FREE: free mbuf here after having sent * it out * MBUF_DONTFREE: mbuf is freed by Layer 2 * returns: * ==0 fail, nothing sent out * !=0 ok, frame sent out * *---------------------------------------------------------------------------*/ int isic_ph_data_req(int unit, struct mbuf *m, int freeflag) { u_char cmd; int s; struct l1_softc *sc = &l1_sc[unit]; #ifdef NOTDEF NDBGL1(L1_PRIM, "unit %d, freeflag=%d", unit, freeflag); #endif if(m == NULL) /* failsafe */ return (0); s = SPLI4B(); if(sc->sc_I430state == ST_F3) /* layer 1 not running ? */ { NDBGL1(L1_I_ERR, "still in state F3!"); isic_ph_activate_req(unit); } if(sc->sc_state & ISAC_TX_ACTIVE) { if(sc->sc_obuf2 == NULL) { sc->sc_obuf2 = m; /* save mbuf ptr */ if(freeflag) sc->sc_freeflag2 = 1; /* IRQ must mfree */ else sc->sc_freeflag2 = 0; /* IRQ must not mfree */ NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", isic_printstate(sc)); if(sc->sc_trace & TRACE_D_TX) { i4b_trace_hdr_t hdr; hdr.unit = L0ISICUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } splx(s); return(1); } NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", 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 = L0ISICUNIT(unit); hdr.type = TRC_CH_D; hdr.dir = FROM_TE; hdr.count = ++sc->sc_trace_dcount; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, m->m_len, m->m_data); } sc->sc_state |= ISAC_TX_ACTIVE; /* set transmitter busy flag */ NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set"); sc->sc_freeflag = 0; /* IRQ must NOT mfree */ ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */ if(m->m_len > ISAC_FIFO_LEN) /* message > 32 bytes ? */ { sc->sc_obuf = m; /* save mbuf ptr */ sc->sc_op = m->m_data + ISAC_FIFO_LEN; /* ptr for irq hdl */ sc->sc_ol = m->m_len - ISAC_FIFO_LEN; /* length for irq hdl */ if(freeflag) sc->sc_freeflag = 1; /* IRQ must mfree */ cmd = ISAC_CMDR_XTF; } else { sc->sc_obuf = NULL; sc->sc_op = NULL; sc->sc_ol = 0; if(freeflag) i4b_Dfreembuf(m); cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; } ISAC_WRITE(I_CMDR, cmd); ISACCMDRWRDELAY(); splx(s); return(1); } /*---------------------------------------------------------------------------* * * L2 -> L1: PH-ACTIVATE-REQUEST * ============================= * * parms: * unit physical interface unit number * * returns: * ==0 * !=0 * *---------------------------------------------------------------------------*/ int isic_ph_activate_req(int unit) { struct l1_softc *sc = &l1_sc[unit]; NDBGL1(L1_PRIM, "unit %d", unit); isic_next_state(sc, EV_PHAR); return(0); } /*---------------------------------------------------------------------------* * command from the upper layers *---------------------------------------------------------------------------*/ int isic_mph_command_req(int unit, int command, void *parm) { struct l1_softc *sc = &l1_sc[unit]; switch(command) { case CMR_DOPEN: /* daemon running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DOPEN", unit); sc->sc_enabled = 1; break; case CMR_DCLOSE: /* daemon not running */ NDBGL1(L1_PRIM, "unit %d, command = CMR_DCLOSE", unit); sc->sc_enabled = 0; break; case CMR_SETTRACE: NDBGL1(L1_PRIM, "unit %d, command = CMR_SETTRACE, parm = %d", unit, (unsigned int)parm); sc->sc_trace = (unsigned int)parm; break; case CMR_GCST: { struct chipstat *cst; NDBGL1(L1_PRIM, "unit %d, command = CMR_GCST, parm = %d", unit, (unsigned int)parm); cst = (struct chipstat *)parm; cst->driver_type = L1DRVR_ISIC; cst->stats.hscxstat.unit = sc->sc_unit; cst->stats.hscxstat.chan = cst->driver_bchannel; cst->stats.hscxstat.vfr = sc->sc_chan[cst->driver_bchannel].stat_VFR; cst->stats.hscxstat.rdo = sc->sc_chan[cst->driver_bchannel].stat_RDO; cst->stats.hscxstat.crc = sc->sc_chan[cst->driver_bchannel].stat_CRC; cst->stats.hscxstat.rab = sc->sc_chan[cst->driver_bchannel].stat_RAB; cst->stats.hscxstat.xdu = sc->sc_chan[cst->driver_bchannel].stat_XDU; cst->stats.hscxstat.rfo = sc->sc_chan[cst->driver_bchannel].stat_RFO; break; } default: NDBGL1(L1_ERROR, "ERROR, unknown command = %d, unit = %d, parm = %d", command, unit, (unsigned int)parm); break; } return(0); } #endif /* NISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_l1fsm.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_l1fsm.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_l1fsm.c (revision 67973) @@ -1,518 +1,515 @@ /* * Copyright (c) 1997, 2000 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.8 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:46:03 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #if NISIC > 0 #include #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include #if DO_I4B_DEBUG static char *state_text[N_STATES] = { "F3 Deactivated", "F4 Awaiting Signal", "F5 Identifying Input", "F6 Synchronized", "F7 Activated", "F8 Lost Framing", "Illegal State" }; static char *event_text[N_EVENTS] = { "EV_PHAR PH_ACT_REQ", "EV_T3 Timer 3 expired", "EV_INFO0 INFO0 received", "EV_RSY Level Detected", "EV_INFO2 INFO2 received", "EV_INFO48 INFO4 received", "EV_INFO410 INFO4 received", "EV_DR Deactivate Req", "EV_PU Power UP", "EV_DIS Disconnected", "EV_EI Error Ind", "Illegal Event" }; #endif /* Function prototypes */ static void timer3_expired (struct l1_softc *sc); static void T3_start (struct l1_softc *sc); static void T3_stop (struct l1_softc *sc); static void F_T3ex (struct l1_softc *sc); static void timer4_expired (struct l1_softc *sc); static void T4_start (struct l1_softc *sc); static void T4_stop (struct l1_softc *sc); static void F_AI8 (struct l1_softc *sc); static void F_AI10 (struct l1_softc *sc); static void F_I01 (struct l1_softc *sc); static void F_I02 (struct l1_softc *sc); static void F_I03 (struct l1_softc *sc); static void F_I2 (struct l1_softc *sc); static void F_ill (struct l1_softc *sc); static void F_NULL (struct l1_softc *sc); /*---------------------------------------------------------------------------* * I.430 Timer T3 expire function *---------------------------------------------------------------------------*/ static void timer3_expired(struct l1_softc *sc) { if(sc->sc_I430T3) { NDBGL1(L1_T_ERR, "state = %s", 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); i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_NOL1ACC, 0, NULL); } isic_next_state(sc, EV_T3); } else { NDBGL1(L1_T_ERR, "expired without starting it ...."); } } /*---------------------------------------------------------------------------* * I.430 Timer T3 start *---------------------------------------------------------------------------*/ static void T3_start(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); sc->sc_I430T3 = 1; sc->sc_T3_callout = timeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, 2*hz); } /*---------------------------------------------------------------------------* * I.430 Timer T3 stop *---------------------------------------------------------------------------*/ static void T3_stop(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); sc->sc_init_tries = 0; /* init connect retry count */ if(sc->sc_I430T3) { sc->sc_I430T3 = 0; untimeout((TIMEOUT_FUNC_T)timer3_expired,(struct l1_softc *)sc, sc->sc_T3_callout); } } /*---------------------------------------------------------------------------* * I.430 Timer T3 expiry *---------------------------------------------------------------------------*/ static void F_T3ex(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_T3ex executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0ISICUNIT(sc->sc_unit)); } /*---------------------------------------------------------------------------* * Timer T4 expire function *---------------------------------------------------------------------------*/ static void timer4_expired(struct l1_softc *sc) { if(sc->sc_I430T4) { NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); sc->sc_I430T4 = 0; i4b_l1_mph_status_ind(L0ISICUNIT(sc->sc_unit), STI_PDEACT, 0, NULL); } else { NDBGL1(L1_T_ERR, "expired without starting it ...."); } } /*---------------------------------------------------------------------------* * Timer T4 start *---------------------------------------------------------------------------*/ static void T4_start(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); sc->sc_I430T4 = 1; sc->sc_T4_callout = timeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, hz); } /*---------------------------------------------------------------------------* * Timer T4 stop *---------------------------------------------------------------------------*/ static void T4_stop(struct l1_softc *sc) { NDBGL1(L1_T_MSG, "state = %s", isic_printstate(sc)); if(sc->sc_I430T4) { sc->sc_I430T4 = 0; untimeout((TIMEOUT_FUNC_T)timer4_expired,(struct l1_softc *)sc, sc->sc_T4_callout); } } /*---------------------------------------------------------------------------* * FSM function: received AI8 *---------------------------------------------------------------------------*/ static void F_AI8(struct l1_softc *sc) { T4_stop(sc); NDBGL1(L1_F_MSG, "FSM function F_AI8 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_activate_ind(L0ISICUNIT(sc->sc_unit)); T3_stop(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO4_8; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received AI10 *---------------------------------------------------------------------------*/ static void F_AI10(struct l1_softc *sc) { T4_stop(sc); NDBGL1(L1_F_MSG, "FSM function F_AI10 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_activate_ind(L0ISICUNIT(sc->sc_unit)); T3_stop(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO4_10; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in states F3 .. F5 *---------------------------------------------------------------------------*/ static void F_I01(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I01 executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in state F6 *---------------------------------------------------------------------------*/ static void F_I02(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I02 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0ISICUNIT(sc->sc_unit)); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: received INFO 0 in state F7 or F8 *---------------------------------------------------------------------------*/ static void F_I03(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I03 executing"); if(ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S) i4b_l1_ph_deactivate_ind(L0ISICUNIT(sc->sc_unit)); T4_start(sc); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO0; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * FSM function: activate request *---------------------------------------------------------------------------*/ static void F_AR(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_AR executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO1_8; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_TE; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } isic_isac_l1_cmd(sc, CMD_AR8); T3_start(sc); } /*---------------------------------------------------------------------------* * FSM function: received INFO2 *---------------------------------------------------------------------------*/ static void F_I2(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_I2 executing"); if(sc->sc_trace & TRACE_I) { i4b_trace_hdr_t hdr; char info = INFO2; hdr.unit = L0ISICUNIT(sc->sc_unit); hdr.type = TRC_CH_I; hdr.dir = FROM_NT; hdr.count = 0; MICROTIME(hdr.time); i4b_l1_trace_ind(&hdr, 1, &info); } } /*---------------------------------------------------------------------------* * illegal state default action *---------------------------------------------------------------------------*/ static void F_ill(struct l1_softc *sc) { NDBGL1(L1_F_ERR, "FSM function F_ill executing"); } /*---------------------------------------------------------------------------* * No action *---------------------------------------------------------------------------*/ static void F_NULL(struct l1_softc *sc) { NDBGL1(L1_F_MSG, "FSM function F_NULL executing"); } /*---------------------------------------------------------------------------* * layer 1 state transition table *---------------------------------------------------------------------------*/ struct isic_state_tab { void (*func) (struct l1_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 l1_softc *sc, int event) { int currstate, newstate; if(event >= N_EVENTS) panic("i4b_l1fsm.c: event >= N_EVENTS\n"); currstate = sc->sc_I430state; if(currstate >= N_STATES) panic("i4b_l1fsm.c: currstate >= N_STATES\n"); newstate = isic_state_tab[event][currstate].newstate; if(newstate >= N_STATES) panic("i4b_l1fsm.c: newstate >= N_STATES\n"); NDBGL1(L1_F_MSG, "FSM event [%s]: [%s => %s]", event_text[event], state_text[currstate], state_text[newstate]); (*isic_state_tab[event][currstate].func)(sc); if(newstate == ST_ILL) { newstate = ST_F3; NDBGL1(L1_F_ERR, "FSM Illegal State ERROR, oldstate = %s, newstate = %s, event = %s!", state_text[currstate], state_text[newstate], event_text[event]); } sc->sc_I430state = newstate; } #if DO_I4B_DEBUG /*---------------------------------------------------------------------------* * return pointer to current state description *---------------------------------------------------------------------------*/ char * isic_printstate(struct l1_softc *sc) { return((char *) state_text[sc->sc_I430state]); } #endif #endif /* NISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_siemens_isurf.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_siemens_isurf.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_siemens_isurf.c (revision 67973) @@ -1,237 +1,234 @@ /* * Copyright (c) 1999, 2000 Udo Schweigert. 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. * *--------------------------------------------------------------------------- * Based on ELSA Quickstep 1000pro PCI driver (i4b_elsa_qs1p.c) *--------------------------------------------------------------------------- * In case of trouble please contact Udo Schweigert *--------------------------------------------------------------------------- * * Siemens I-Surf 2.0 PnP specific routines for isic driver * -------------------------------------------------------- * * $Id: i4b_siemens_isurf.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:00:57 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 && defined(SIEMENS_ISURF2) #include #include #include #include -#include #include #include #include -#include -#include /* masks for register encoded in base addr */ #define SIE_ISURF_BASE_MASK 0x0ffff #define SIE_ISURF_OFF_MASK 0xf0000 /* register id's to be encoded in base addr */ #define SIE_ISURF_IDISAC 0x00000 #define SIE_ISURF_IDHSCXA 0x10000 #define SIE_ISURF_IDHSCXB 0x20000 #define SIE_ISURF_IDIPAC 0x40000 /* offsets from base address */ #define SIE_ISURF_OFF_ALE 0x00 #define SIE_ISURF_OFF_RW 0x01 /*---------------------------------------------------------------------------* * Siemens I-Surf 2.0 PnP ISAC get fifo routine *---------------------------------------------------------------------------*/ static void siemens_isurf_read_fifo(struct l1_softc *sc,int what,void *buf,size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,IPAC_ISAC_OFF); bus_space_read_multi_1(t,h,SIE_ISURF_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,IPAC_HSCXA_OFF); bus_space_read_multi_1(t,h,SIE_ISURF_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,IPAC_HSCXB_OFF); bus_space_read_multi_1(t,h,SIE_ISURF_OFF_RW,buf,size); break; } } /*---------------------------------------------------------------------------* * Siemens I-Surf 2.0 PnP ISAC put fifo routine *---------------------------------------------------------------------------*/ static void siemens_isurf_write_fifo(struct l1_softc *sc,int what,void *buf,size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,IPAC_ISAC_OFF); bus_space_write_multi_1(t,h,SIE_ISURF_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,IPAC_HSCXA_OFF); bus_space_write_multi_1(t,h,SIE_ISURF_OFF_RW,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,IPAC_HSCXB_OFF); bus_space_write_multi_1(t,h,SIE_ISURF_OFF_RW,buf,size); break; } } /*---------------------------------------------------------------------------* * Siemens I-Surf 2.0 PnP ISAC put register routine *---------------------------------------------------------------------------*/ static void siemens_isurf_write_reg(struct l1_softc *sc,int what,bus_size_t reg,u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_ISAC_OFF); bus_space_write_1(t,h,SIE_ISURF_OFF_RW,data); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_HSCXA_OFF); bus_space_write_1(t,h,SIE_ISURF_OFF_RW,data); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_HSCXB_OFF); bus_space_write_1(t,h,SIE_ISURF_OFF_RW,data); break; case ISIC_WHAT_IPAC: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_IPAC_OFF); bus_space_write_1(t,h,SIE_ISURF_OFF_RW,data); break; } } /*---------------------------------------------------------------------------* * Siemens I-Surf 2.0 PnP ISAC get register routine *---------------------------------------------------------------------------*/ static u_int8_t siemens_isurf_read_reg(struct l1_softc *sc,int what,bus_size_t reg) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_ISAC_OFF); return bus_space_read_1(t,h,SIE_ISURF_OFF_RW); case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_HSCXA_OFF); return bus_space_read_1(t,h,SIE_ISURF_OFF_RW); case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_HSCXB_OFF); return bus_space_read_1(t,h,SIE_ISURF_OFF_RW); case ISIC_WHAT_IPAC: bus_space_write_1(t,h,SIE_ISURF_OFF_ALE,reg+IPAC_IPAC_OFF); return bus_space_read_1(t,h,SIE_ISURF_OFF_RW); default: return 0; } } /*---------------------------------------------------------------------------* * isic_attach_siemens_isurf - attach for Siemens I-Surf 2.0 PnP *---------------------------------------------------------------------------*/ int isic_attach_siemens_isurf(device_t dev) { int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; /* setup access routines */ sc->clearirq = NULL; sc->readreg = siemens_isurf_read_reg; sc->writereg = siemens_isurf_write_reg; sc->readfifo = siemens_isurf_read_fifo; sc->writefifo = siemens_isurf_write_fifo; /* setup card type */ sc->sc_cardtyp = CARD_TYPEP_SIE_ISURF2; /* 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 */ return(0); } #endif /* NISIC > 0 && defined(SIEMENS_ISURF2) */ Index: head/sys/i4b/layer1/isic/i4b_sws.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_sws.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_sws.c (revision 67973) @@ -1,217 +1,215 @@ /* * Copyright (c) 1998, 2000 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 * ==================================================== * * $Id: i4b_sws.c,v 1.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:01:10 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #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 */ #include #include #include #include -#include #include #include -#include #include /*---------------------------------------------------------------------------* * SWS P&P ISAC get fifo routine *---------------------------------------------------------------------------*/ static void sws_read_fifo(struct l1_softc *sc,int what,void *buf,size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SWS_RW,0x0); bus_space_read_multi_1(t,h,SWS_ISAC,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SWS_RW,0x0); bus_space_read_multi_1(t,h,SWS_HSCX0,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SWS_RW,0x0+0x40); bus_space_read_multi_1(t,h,SWS_HSCX0,buf,size); break; } } static void sws_write_fifo(struct l1_softc *sc,int what,void *buf,size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SWS_RW,0x0); bus_space_write_multi_1(t,h,SWS_ISAC,buf,size); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SWS_RW,0x0); bus_space_write_multi_1(t,h,SWS_HSCX0,buf,size); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SWS_RW,0x0+0x40); bus_space_write_multi_1(t,h,SWS_HSCX0,buf,size); break; } } static void sws_write_reg(struct l1_softc *sc,int what,bus_size_t reg,u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SWS_RW,reg); bus_space_write_1(t,h,SWS_ISAC,data); break; case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SWS_RW,reg); bus_space_write_1(t,h,SWS_HSCX0,data); break; case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SWS_RW,reg+0x40); bus_space_write_1(t,h,SWS_HSCX0,data); break; } } static u_char sws_read_reg (struct l1_softc *sc,int what,bus_size_t reg) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); switch ( what ) { case ISIC_WHAT_ISAC: bus_space_write_1(t,h,SWS_RW,reg); return bus_space_read_1(t,h,SWS_ISAC); case ISIC_WHAT_HSCXA: bus_space_write_1(t,h,SWS_RW,reg); return bus_space_read_1(t,h,SWS_HSCX0); case ISIC_WHAT_HSCXB: bus_space_write_1(t,h,SWS_RW,reg+0x40); return bus_space_read_1(t,h,SWS_HSCX0); default: return 0; } } /* attach callback routine */ int isic_attach_sws(device_t dev) { int unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; struct i4b_info * info = &(sc->sc_resources); bus_space_tag_t t = rman_get_bustag(info->io_base[0]); bus_space_handle_t h = rman_get_bushandle(info->io_base[0]); /* fill in l1_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_cardtyp = CARD_TYPEP_SWS; 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("isic%d: HSCX VSTR test failed for SWS PnP\n", sc->sc_unit); printf("isic%d: HSC0: VSTR: %#x\n", sc->sc_unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", sc->sc_unit, HSCX_READ(1, H_VSTR)); return (ENXIO); } /* reset card */ bus_space_write_1(t,h,SWS_RESON,0x3); DELAY(SEC_DELAY / 5); bus_space_write_1(t,h,SWS_RESOFF,0x0); DELAY(SEC_DELAY / 5); return(0); } #endif /* defined(SEDLBAUER) && NISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_tel_s016.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_tel_s016.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_tel_s016.c (revision 67973) @@ -1,377 +1,375 @@ /* * Copyright (c) 1996 Arne Helme. All rights reserved. * * Copyright (c) 1996 Gary Jennejohn. All rights reserved. * * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:01:20 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 && defined(TEL_S0_16) #include #include #include #include #include -#include #include #include -#include #include #define TELES_S016_MEMSIZE 0x1000 static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 }; static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 }; /*---------------------------------------------------------------------------* * Teles S0/16 write register routine *---------------------------------------------------------------------------*/ static void tels016_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); offs += offset[what]; if (offs & 0x01) offs |= 0x200; bus_space_write_1(t, h, offs, data); } /*---------------------------------------------------------------------------* * Teles S0/16 read register routine *---------------------------------------------------------------------------*/ static u_int8_t tels016_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); offs += offset[what]; if(offs & 0x01) offs |= 0x200; return bus_space_read_1(t, h, offs); } /*---------------------------------------------------------------------------* * Teles S0/16 fifo write routine *---------------------------------------------------------------------------*/ static void tels016_write_fifo(struct l1_softc *sc, int what, void *data, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); bus_space_write_region_1(t, h, offset[what], data, size); } /*---------------------------------------------------------------------------* * Teles S0/16 fifo read routine *---------------------------------------------------------------------------*/ static void tels016_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); bus_space_read_region_1(t, h, offset[what], buf, size); } /*---------------------------------------------------------------------------* * isic_probe_s016 - probe for Teles S0/16 and compatibles *---------------------------------------------------------------------------*/ int isic_probe_s016(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* softc */ void *ih = 0; /* dummy */ u_int8_t b0,b1,b2; /* for signature */ bus_space_tag_t t; /* bus things */ bus_space_handle_t h; /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/16!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_TELES_S0_16; /* set flags */ /* see if an io base was supplied */ if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not allocate i/o port for Teles S0/16.\n", unit); return(ENXIO); } sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); /* * check if the provided io port is valid */ switch(sc->sc_port) { case 0xd80: case 0xe80: case 0xf80: break; default: printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16!\n", unit, sc->sc_port); isic_detach_common(dev); return(ENXIO); break; } /* allocate memory resource */ if(!(sc->sc_resources.mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_resources.mem_rid, 0ul, ~0ul, TELES_S016_MEMSIZE, RF_ACTIVE))) { printf("isic%d: Could not allocate memory for Teles S0/16.\n", unit); isic_detach_common(dev); return(ENXIO); } /* * get virtual addr. */ sc->sc_vmem_addr = rman_get_virtual(sc->sc_resources.mem); /* * check for valid adresses */ switch(kvtop(sc->sc_vmem_addr)) { 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 memory address 0x%lx for Teles S0/16!\n", unit, kvtop(sc->sc_vmem_addr)); isic_detach_common(dev); return(ENXIO); break; } /* setup ISAC 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; /* setup ISAC base addr, though we don't really need it */ ISAC_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x100); /* setup HSCX base addr */ HSCX_A_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x180); HSCX_B_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x1c0); t = rman_get_bustag(sc->sc_resources.io_base[0]); h = rman_get_bushandle(sc->sc_resources.io_base[0]); /* get signature bytes */ b0 = bus_space_read_1(t, h, 0); b1 = bus_space_read_1(t, h, 1); b2 = bus_space_read_1(t, h, 2); /* check signature bytes */ if(b0 != 0x51) { printf("isic%d: Error, signature 1 0x%x != 0x51 for Teles S0/16!\n", unit, b0); isic_detach_common(dev); return(ENXIO); } if(b1 != 0x93) { printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16!\n", unit, b1); isic_detach_common(dev); return(ENXIO); } if((b2 != 0x1e) && (b2 != 0x1f)) { printf("isic%d: Error, signature 3 0x%x != 0x1e or 0x1f for Teles S0/16!\n", unit, b2); isic_detach_common(dev); return(ENXIO); } /* get our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not allocate irq for Teles S0/16.\n", unit); isic_detach_common(dev); return ENXIO; } /* register interupt routine */ bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void *))(isicintr), sc, &ih); /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); /* check IRQ validity */ if((intr_no[sc->sc_irq]) == 1) { printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16!\n", unit, sc->sc_irq); isic_detach_common(dev); return(ENXIO); } return (0); } /*---------------------------------------------------------------------------* * isic_attach_s016 - attach Teles S0/16 and compatibles *---------------------------------------------------------------------------*/ int isic_attach_s016(device_t dev) { struct l1_softc *sc = &l1_sc[device_get_unit(dev)]; u_long irq; bus_space_tag_t ta = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t ha = rman_get_bushandle(sc->sc_resources.mem); bus_space_tag_t tb = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t hb = rman_get_bushandle(sc->sc_resources.io_base[0]); /* is this right for FreeBSD or off by one ? */ irq = intr_no[sc->sc_irq]; /* configure IRQ */ irq |= ((u_long) sc->sc_vmem_addr) >> 9; DELAY(SEC_DELAY / 10); bus_space_write_1(tb, hb, 4, irq); DELAY(SEC_DELAY / 10); bus_space_write_1(tb, hb, 4, irq | 0x01); DELAY(SEC_DELAY / 5); /* set card bit off */ bus_space_write_1(ta, ha, 0x80, 0); DELAY(SEC_DELAY / 5); /* set card bit on */ bus_space_write_1(ta, ha, 0x80, 1); DELAY(SEC_DELAY / 5); return 0; } #endif /* ISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_tel_s0163.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_tel_s0163.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_tel_s0163.c (revision 67973) @@ -1,380 +1,378 @@ /* * Copyright (c) 1996 Arne Helme. All rights reserved. * * Copyright (c) 1996 Gary Jennejohn. All rights reserved. * * Copyright (c) 1997, 2000 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.4 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:01:29 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 && defined(TEL_S0_16_3) #include #include #include #include -#include #include #include -#include #include static u_char intr_no[] = { 1, 1, 0, 2, 4, 6, 1, 1, 1, 0, 8, 10, 12, 1, 1, 14 }; #define ISAC_OFFS 0x400 #define HSCXA_OFFS 0xc00 #define HSCXB_OFFS 0x800 /*---------------------------------------------------------------------------* * Teles S0/16.3 read fifo routine *---------------------------------------------------------------------------*/ static void tels0163_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+1]); bus_space_read_multi_1(t,h,0x1e,buf,size); } /*---------------------------------------------------------------------------* * Teles S0/16.3 write fifo routine *---------------------------------------------------------------------------*/ static void tels0163_write_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+1]); bus_space_write_multi_1(t,h,0x1e,buf,size); } /*---------------------------------------------------------------------------* * Teles S0/16.3 ISAC put register routine *---------------------------------------------------------------------------*/ static void tels0163_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+1]); bus_space_write_1(t,h,offs - 0x20,data); } /*---------------------------------------------------------------------------* * Teles S0/16.3 ISAC get register routine *---------------------------------------------------------------------------*/ static u_int8_t tels0163_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[what+1]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[what+1]); return bus_space_read_1(t,h,offs - 0x20); } /*---------------------------------------------------------------------------* * isic_probe_s0163 - probe routine for Teles S0/16.3 *---------------------------------------------------------------------------*/ int isic_probe_s0163(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* pointer to softc */ void *ih = 0; /* dummy */ bus_space_tag_t t; /* bus things */ bus_space_handle_t h; u_int8_t b0,b1,b2; /* signature */ /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles 16.3!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_TELES_S0_163; /* set flags */ /* see if an io base was supplied */ if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get iobase for Teles S0/16.3.\n", unit); return(ENXIO); } /* set io base */ sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); /* Release the resource - re-allocate later with correct size */ bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); switch(sc->sc_port) { case 0xd80: case 0xe80: case 0xf80: break; case 0x180: case 0x280: case 0x380: printf("isic%d: Error, instead of using iobase 0x%x for your Teles S0/16.3,\n", unit, sc->sc_port); printf("isic%d: please use 0x%x in the kernel configuration file!\n", unit, sc->sc_port+0xc00); isic_detach_common(dev); return(ENXIO); break; default: printf("isic%d: Error, invalid iobase 0x%x specified for Teles S0/16.3!\n", unit, sc->sc_port); isic_detach_common(dev); return(ENXIO); break; } /* set io port resources */ sc->sc_resources.io_rid[0] = 0; bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port, 0x20); sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE); if(!sc->sc_resources.io_base[0]) { printf("isic%d: Error allocating io at 0x%x for Teles S0/16.3!\n", unit, sc->sc_port); isic_detach_common(dev); return ENXIO; } sc->sc_resources.io_rid[1] = 1; bus_set_resource(dev, SYS_RES_IOPORT, 1, sc->sc_port-ISAC_OFFS, 0x20); sc->sc_resources.io_base[1] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[1], 0ul, ~0ul, 1, RF_ACTIVE); if(!sc->sc_resources.io_base[1]) { printf("isic%d: Error allocating io at 0x%x for Teles S0/16.3!\n", unit, sc->sc_port-ISAC_OFFS); isic_detach_common(dev); return ENXIO; } sc->sc_resources.io_rid[2] = 2; bus_set_resource(dev, SYS_RES_IOPORT, 2, sc->sc_port-HSCXA_OFFS, 0x20); sc->sc_resources.io_base[2] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[2], 0ul, ~0ul, 1, RF_ACTIVE); if(!sc->sc_resources.io_base[2]) { printf("isic%d: Error allocating io at 0x%x for Teles S0/16.3!\n", unit, sc->sc_port-HSCXA_OFFS); isic_detach_common(dev); return ENXIO; } sc->sc_resources.io_rid[3] = 3; bus_set_resource(dev, SYS_RES_IOPORT, 3, sc->sc_port-HSCXB_OFFS, 0x20); sc->sc_resources.io_base[3] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[3], 0ul, ~0ul, 1, RF_ACTIVE); if(!sc->sc_resources.io_base[3]) { printf("isic%d: Error allocating io at 0x%x for Teles S0/16.3!\n", unit, sc->sc_port-HSCXB_OFFS); isic_detach_common(dev); return ENXIO; } /* 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; t = rman_get_bustag(sc->sc_resources.io_base[0]); h = rman_get_bushandle(sc->sc_resources.io_base[0]); 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 && b0 != 0x10 ) { printf("isic%d: Error, signature 1 0x%x != 0x51 or 0x10 for Teles S0/16.3!\n", unit, b0); isic_detach_common(dev); return ENXIO; } if ( b1 != 0x93 ) { printf("isic%d: Error, signature 2 0x%x != 0x93 for Teles S0/16.3!\n", unit, b1); isic_detach_common(dev); return ENXIO; } if (( b2 != 0x1c ) && ( b2 != 0x1f )) { printf("isic%d: Error, signature 3 0x%x != (0x1c || 0x1f) for Teles S0/16.3!\n", unit, b2); isic_detach_common(dev); return ENXIO; } /* * 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", unit); printf("isic%d: HSC0: VSTR: %#x\n", unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", unit, HSCX_READ(1, H_VSTR)); isic_detach_common(dev); return (ENXIO); } /* get our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get IRQ for Teles S0/16.3.\n",unit); isic_detach_common(dev); return ENXIO; } /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); switch(sc->sc_irq) { case 2: case 9: case 5: case 10: case 12: case 15: break; default: printf("isic%d: Error, invalid IRQ [%d] specified for Teles S0/16.3!\n", unit, sc->sc_irq); isic_detach_common(dev); return(ENXIO); break; } /* register interupt routine */ bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void *))(isicintr), sc, &ih); return (0); } /*---------------------------------------------------------------------------* * isic_attach_s0163 - attach Teles S0/16.3 and compatibles *---------------------------------------------------------------------------*/ int isic_attach_s0163(device_t dev) { unsigned int unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = &l1_sc[unit]; bus_space_tag_t t = rman_get_bustag(sc->sc_resources.io_base[0]); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.io_base[0]); /* configure IRQ */ DELAY(SEC_DELAY / 10); bus_space_write_1(t, h, 4, intr_no[sc->sc_irq]); DELAY(SEC_DELAY / 10); bus_space_write_1(t, h, 4, intr_no[sc->sc_irq] | 0x01); return (0); } #endif /* ISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_tel_s08.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_tel_s08.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_tel_s08.c (revision 67973) @@ -1,310 +1,308 @@ /* * Copyright (c) 1996 Arne Helme. All rights reserved. * * Copyright (c) 1996 Gary Jennejohn. All rights reserved. * * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:41 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 16:01:42 2000] * *---------------------------------------------------------------------------*/ #include "isic.h" #include "opt_i4b.h" #if NISIC > 0 && defined(TEL_S0_8) #include #include #include #include #include -#include #include #include -#include #include #define TELES_S08_MEMSIZE 0x1000 static const bus_size_t offset[] = { 0x100, 0x180, 0x1c0 }; /*---------------------------------------------------------------------------* * Teles S0/8 write register routine *---------------------------------------------------------------------------*/ static void tels08_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); offs += offset[what]; if (offs & 0x01) offs |= 0x200; bus_space_write_1(t, h, offs, data); } /*---------------------------------------------------------------------------* * Teles S0/8 read register routine *---------------------------------------------------------------------------*/ static u_int8_t tels08_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); offs += offset[what]; if (offs & 0x01) offs |= 0x200; return bus_space_read_1(t, h, offs); } /*---------------------------------------------------------------------------* * Teles S0/8 fifo write access *---------------------------------------------------------------------------*/ static void tels08_write_fifo(struct l1_softc *sc, int what, void *data, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); bus_space_write_region_1(t, h, offset[what], data, size); } /*---------------------------------------------------------------------------* * Teles S0/8 fifo read access *---------------------------------------------------------------------------*/ static void tels08_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); bus_space_read_region_1(t, h, offset[what], buf, size); } /*---------------------------------------------------------------------------* * isic_probe_s08 - probe for Teles S0/8 and compatibles *---------------------------------------------------------------------------*/ int isic_probe_s08(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* pointer to softc */ void *ih = 0; /* dummy */ /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Teles S0/8!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_TELES_S0_8; /* set flags */ /* see if an io base was supplied */ if((sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { /* the S0/8 is completely memory mapped ! */ bus_release_resource(dev,SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); printf("isic%d: Error, iobase specified for Teles S0/8!\n", unit); return(ENXIO); } /* allocate memory */ if(!(sc->sc_resources.mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_resources.mem_rid, 0ul, ~0ul, TELES_S08_MEMSIZE, RF_ACTIVE))) { printf("isic%d: Could not allocate memory for Teles S0/8!\n", unit); return(ENXIO); } /* * get virtual addr. it's just needed to see if it is in * the valid range */ sc->sc_vmem_addr = rman_get_virtual(sc->sc_resources.mem); /* check if inside memory range of 0xA0000 .. 0xDF000 */ if((kvtop(sc->sc_vmem_addr) < 0xa0000) || (kvtop(sc->sc_vmem_addr) > 0xdf000)) { printf("isic%d: Error, mem addr 0x%lx outside 0xA0000-0xDF000 for Teles S0/8!\n", unit, kvtop(sc->sc_vmem_addr)); bus_release_resource(dev,SYS_RES_MEMORY, sc->sc_resources.mem_rid, sc->sc_resources.mem); sc->sc_resources.mem = 0; return(ENXIO); } /* 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; sc->sc_cardtyp = CARD_TYPEP_8; /* setup card type */ sc->sc_bustyp = BUS_TYPE_IOM1; /* setup IOM bus type */ sc->sc_ipac = 0; sc->sc_bfifolen = HSCX_FIFO_LEN; /* setup ISAC base addr, though we don't really need it */ ISAC_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x100); /* setup HSCX base addr */ HSCX_A_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x180); HSCX_B_BASE = (caddr_t)((sc->sc_vmem_addr) + 0x1c0); /* allocate our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not allocate irq for Teles S0/8!\n",unit); bus_release_resource(dev,SYS_RES_MEMORY, sc->sc_resources.mem_rid, sc->sc_resources.mem); sc->sc_resources.mem = 0; return ENXIO; } /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); /* check IRQ validity */ switch(sc->sc_irq) { 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", unit, sc->sc_irq); bus_release_resource(dev,SYS_RES_IRQ, sc->sc_resources.irq_rid, sc->sc_resources.irq); sc->sc_resources.irq = 0; bus_release_resource(dev,SYS_RES_MEMORY, sc->sc_resources.mem_rid, sc->sc_resources.mem); sc->sc_resources.mem = 0; return(ENXIO); break; } /* register interupt routine */ bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void *))(isicintr), sc, &ih); return (0); } /*---------------------------------------------------------------------------* * isic_attach_s08 - attach Teles S0/8 and compatibles *---------------------------------------------------------------------------*/ int isic_attach_s08(device_t dev) { struct l1_softc *sc = &l1_sc[device_get_unit(dev)]; bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); /* set card off */ bus_space_write_1(t, h, 0x80, 0); DELAY(SEC_DELAY / 5); /* set card on */ bus_space_write_1(t, h, 0x80, 1); DELAY(SEC_DELAY / 5); return 0; } #endif /* ISIC > 0 */ Index: head/sys/i4b/layer1/isic/i4b_usr_sti.c =================================================================== --- head/sys/i4b/layer1/isic/i4b_usr_sti.c (revision 67972) +++ head/sys/i4b/layer1/isic/i4b_usr_sti.c (revision 67973) @@ -1,673 +1,670 @@ /* * Copyright (c) 1997, 2000 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.3 2000/05/29 15:41:42 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:47:26 2000] * *---------------------------------------------------------------------------*/ #if defined(__FreeBSD__) #include "isic.h" #include "opt_i4b.h" #else #define NISIC 1 #endif #if (NISIC > 0) && defined(USR_STI) #include #include #ifdef __FreeBSD__ #include -#include #include #include #else #include #include #endif #include #include #ifdef __FreeBSD__ -#include #include #else #include #include #endif #include -#include #include /*---------------------------------------------------------------------------* * 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)) #ifdef USRTA_DEBUG_PORTACCESS int debugcntr; #define USRTA_DEBUG(fmt) \ if (++debugcntr < 1000) printf fmt; #else #define USRTA_DEBUG(fmt) #endif /*---------------------------------------------------------------------------* * USRobotics read fifo routine *---------------------------------------------------------------------------*/ static void usrtai_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { register int offset = 0; register unsigned int base = 0; USRTA_DEBUG(("usrtai_read_fifo: what %d size %d\n", what, size)) switch (what) { case ISIC_WHAT_ISAC: base = (unsigned int)ISAC_BASE; break; case ISIC_WHAT_HSCXA: base = (unsigned int)HSCX_A_BASE; break; case ISIC_WHAT_HSCXB: base = (unsigned int)HSCX_B_BASE; break; default: printf("usrtai_read_fifo: invalid what %d\n", what); return; } for(;size > 0; size--, offset++) { *((u_char *)buf + offset) = inb(base + ADDR(offset)); } } /*---------------------------------------------------------------------------* * USRobotics write fifo routine *---------------------------------------------------------------------------*/ static void usrtai_write_fifo(struct l1_softc *sc, int what, void *data, size_t size) { register int offset = 0; register unsigned int base = 0; USRTA_DEBUG(("usrtai_write_fifo: what %d size %d\n", what, size)) switch (what) { case ISIC_WHAT_ISAC: base = (unsigned int)ISAC_BASE; break; case ISIC_WHAT_HSCXA: base = (unsigned int)HSCX_A_BASE; break; case ISIC_WHAT_HSCXB: base = (unsigned int)HSCX_B_BASE; break; default: printf("usrtai_write_fifo: invalid what %d\n", what); return; } for(;size > 0; size--, offset++) { outb(base + ADDR(offset), *((u_char *)data + offset)); } } /*---------------------------------------------------------------------------* * USRobotics write register routine *---------------------------------------------------------------------------*/ static void usrtai_write_reg(struct l1_softc *sc, int what, bus_size_t offs, u_int8_t data) { register unsigned int base = 0; USRTA_DEBUG(("usrtai_write_reg: what %d ADDR(%d) %d data %#x\n", what, offs, ADDR(offs), data)) switch (what) { case ISIC_WHAT_ISAC: base = (unsigned int)ISAC_BASE; break; case ISIC_WHAT_HSCXA: base = (unsigned int)HSCX_A_BASE; break; case ISIC_WHAT_HSCXB: base = (unsigned int)HSCX_B_BASE; break; default: printf("usrtai_write_reg invalid what %d\n", what); return; } outb(base + ADDR(offs), (u_char)data); } /*---------------------------------------------------------------------------* * USRobotics read register routine *---------------------------------------------------------------------------*/ static u_int8_t usrtai_read_reg(struct l1_softc *sc, int what, bus_size_t offs) { register unsigned int base = 0; u_int8_t byte; USRTA_DEBUG(("usrtai_read_reg: what %d ADDR(%d) %d..", what, offs, ADDR(offs))) switch (what) { case ISIC_WHAT_ISAC: base = (unsigned int)ISAC_BASE; break; case ISIC_WHAT_HSCXA: base = (unsigned int)HSCX_A_BASE; break; case ISIC_WHAT_HSCXB: base = (unsigned int)HSCX_B_BASE; break; default: printf("usrtai_read_reg: invalid what %d\n", what); return(0); } byte = inb(base + ADDR(offs)); USRTA_DEBUG(("usrtai_read_reg: got %#x\n", byte)) return(byte); } /*---------------------------------------------------------------------------* * allocate an io port - based on code in isa_isic.c *---------------------------------------------------------------------------*/ static int usrtai_alloc_port(device_t dev) { size_t unit = device_get_unit(dev); struct l1_softc *sc = &l1_sc[unit]; int i, num = 0; bus_size_t base; /* 49 io mappings: 1 config and 48x8 registers */ /* config at offset 0x8000 */ base = sc->sc_port + 0x8000; if (base < 0 || base > 0x0ffff) return 1; sc->sc_resources.io_rid[num] = num; bus_set_resource(dev, SYS_RES_IOPORT, num, base, 1); if(!(sc->sc_resources.io_base[num] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[num], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Error, failed to reserve io #%dport %#x!\n", unit, num, base); isic_detach_common(dev); return(ENXIO); } num++; /* HSCX A at offset 0 */ base = sc->sc_port; for (i = 0; i < 16; i++) { if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) return 1; sc->sc_resources.io_rid[num] = num; bus_set_resource(dev, SYS_RES_IOPORT, num, base+i*1024, 8); if(!(sc->sc_resources.io_base[num] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[num], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Error, failed to reserve io #%d port %#x!\n", unit, num, base+i*1024); isic_detach_common(dev); return(ENXIO); } ++num; } /* HSCX B at offset 0x4000 */ base = sc->sc_port + 0x4000; for (i = 0; i < 16; i++) { if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) return 1; sc->sc_resources.io_rid[num] = num; bus_set_resource(dev, SYS_RES_IOPORT, num, base+i*1024, 8); if(!(sc->sc_resources.io_base[num] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[num], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Error, failed to reserve io #%d port %#x!\n", unit, num, base+i*1024); isic_detach_common(dev); return(ENXIO); } ++num; } /* ISAC at offset 0xc000 */ base = sc->sc_port + 0xc000; for (i = 0; i < 16; i++) { if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff) return 1; sc->sc_resources.io_rid[num] = num; bus_set_resource(dev, SYS_RES_IOPORT, num, base+i*1024, 8); if(!(sc->sc_resources.io_base[num] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[num], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Error, failed to reserve io #%d port %#x!\n", unit, num, base+i*1024); isic_detach_common(dev); return(ENXIO); } ++num; } return(0); } /*---------------------------------------------------------------------------* * isic_probe_usrtai - probe for USR *---------------------------------------------------------------------------*/ int isic_probe_usrtai(device_t dev) { size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* pointer to softc */ void *ih = 0; /* dummy */ /* check max unit range */ if(unit >= ISIC_MAXUNIT) { printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for USR Sportster TA!\n", unit, unit); return(ENXIO); } sc = &l1_sc[unit]; /* get pointer to softc */ sc->sc_unit = unit; /* set unit */ sc->sc_flags = FLAG_USR_ISDN_TA_INT; /* set flags */ /* see if an io base was supplied */ if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get iobase for USR Sportster TA!\n", unit); return(ENXIO); } /* set io base */ sc->sc_port = rman_get_start(sc->sc_resources.io_base[0]); /* release io base */ bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_resources.io_rid[0], sc->sc_resources.io_base[0]); /* check if we got an iobase */ switch(sc->sc_port) { 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", unit, sc->sc_port); return(0); break; } /* allocate all the ports needed */ if(usrtai_alloc_port(dev)) { printf("isic%d: Could not get the ports for USR Sportster TA!\n", unit); isic_detach_common(dev); return(ENXIO); } /* get our irq */ if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0ul, ~0ul, 1, RF_ACTIVE))) { printf("isic%d: Could not get an irq for USR Sportster TA!\n",unit); isic_detach_common(dev); return ENXIO; } /* get the irq number */ sc->sc_irq = rman_get_start(sc->sc_resources.irq); /* register interrupt routine */ bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void *))(isicintr), sc, &ih); /* check IRQ validity */ if(intr_no[sc->sc_irq] == 0) { printf("isic%d: Error, invalid IRQ [%d] specified for USR Sportster TA!\n", unit, sc->sc_irq); return(1); } /* 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)sc->sc_port + USR_ISAC_OFF; HSCX_A_BASE = (caddr_t)sc->sc_port + USR_HSCXA_OFF; HSCX_B_BASE = (caddr_t)sc->sc_port + 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", unit); printf("isic%d: HSC0: VSTR: %#x\n", unit, HSCX_READ(0, H_VSTR)); printf("isic%d: HSC1: VSTR: %#x\n", unit, HSCX_READ(1, H_VSTR)); return (1); } return (0); } /*---------------------------------------------------------------------------* * isic_attach_usrtai - attach USR *---------------------------------------------------------------------------*/ int isic_attach_usrtai(device_t dev) { u_char irq = 0; size_t unit = device_get_unit(dev); /* get unit */ struct l1_softc *sc = 0; /* pointer to softc */ sc = &l1_sc[unit]; /* get pointer to softc */ /* reset the HSCX and ISAC chips */ outb(sc->sc_port + USR_INTL_OFF, USR_RES_BIT); DELAY(SEC_DELAY / 10); outb(sc->sc_port + USR_INTL_OFF, 0x00); DELAY(SEC_DELAY / 10); /* setup IRQ */ if((irq = intr_no[sc->sc_irq]) == 0) { printf("isic%d: Attach error, invalid IRQ [%d] specified for USR Sportster TA!\n", unit, sc->sc_irq); return(1); } /* configure and enable irq */ outb(sc->sc_port + USR_INTL_OFF, irq | USR_INTE_BIT); DELAY(SEC_DELAY / 10); return (0); } #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 */ Index: head/sys/i4b/layer1/iwic/i4b_iwic_l1if.c =================================================================== --- head/sys/i4b/layer1/iwic/i4b_iwic_l1if.c (revision 67972) +++ head/sys/i4b/layer1/iwic/i4b_iwic_l1if.c (revision 67973) @@ -1,158 +1,155 @@ /* * Copyright (c) 1999, 2000 Dave Boyce. 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_iwic - isdn4bsd Winbond W6692 driver * ---------------------------------------- * * $Id: i4b_iwic_l1if.c,v 1.3 2000/06/02 16:14:36 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Jun 2 14:52:39 2000] * *---------------------------------------------------------------------------*/ #include "iwic.h" #include "opt_i4b.h" #include "pci.h" #if (NIWIC > 0) && (NPCI > 0) #include #include #include #include -#include -#include #include #include #include #include #include #include #include #include -#include /* jump table for multiplex routines */ struct i4b_l1mux_func iwic_l1mux_func = { iwic_ret_linktab, iwic_set_linktab, iwic_mph_command_req, iwic_ph_data_req, iwic_ph_activate_req, }; /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ int iwic_ph_data_req(int unit, struct mbuf *m, int freeflag) { struct iwic_softc *sc = iwic_find_sc(unit); return iwic_dchan_data_req(sc, m, freeflag); } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ int iwic_ph_activate_req(int unit) { struct iwic_softc *sc = iwic_find_sc(unit); iwic_next_state(sc, EV_PHAR); return 0; } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ int iwic_mph_command_req(int unit, int command, void *parm) { struct iwic_softc *sc = iwic_find_sc(unit); switch (command) { case CMR_DOPEN: /* Daemon running */ NDBGL1(L1_PRIM, "CMR_DOPEN"); sc->enabled = TRUE; break; case CMR_DCLOSE: /* Daemon not running */ NDBGL1(L1_PRIM, "CMR_DCLOSE"); sc->enabled = FALSE; break; case CMR_SETTRACE: NDBGL1(L1_PRIM, "CMR_SETTRACE, parm = %d", (unsigned int)parm); sc->sc_trace = (unsigned int)parm; break; default: NDBGL1(L1_PRIM, "unknown command = %d", command); break; } return 0; } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ isdn_link_t * iwic_ret_linktab(int unit, int channel) { struct iwic_softc *sc = iwic_find_sc(unit); struct iwic_bchan *bchan = &sc->sc_bchan[channel]; return &bchan->iwic_isdn_linktab; } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ void iwic_set_linktab (int unit, int channel, drvr_link_t *dlt) { struct iwic_softc *sc = iwic_find_sc(unit); struct iwic_bchan *bchan = &sc->sc_bchan[channel]; bchan->iwic_drvr_linktab = dlt; } #endif Index: head/sys/i4b/layer1/iwic/i4b_iwic_pci.c =================================================================== --- head/sys/i4b/layer1/iwic/i4b_iwic_pci.c (revision 67972) +++ head/sys/i4b/layer1/iwic/i4b_iwic_pci.c (revision 67973) @@ -1,314 +1,312 @@ /* * Copyright (c) 1999, 2000 Dave Boyce. 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_iwic - isdn4bsd Winbond W6692 driver * ---------------------------------------- * * $Id: i4b_iwic_pci.c,v 1.14 2000/09/04 09:08:45 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon Sep 4 09:49:03 2000] * *---------------------------------------------------------------------------*/ #include "iwic.h" #include "opt_i4b.h" #include "pci.h" #if (NIWIC > 0) && (NPCI > 0) #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include extern struct i4b_l1mux_func iwic_l1mux_func; /* Winbond PCI Configuration Space */ #define BASEREG0_MAPOFF 0x00 #define BASEREG1_MAPOFF 0x04 #define BADDR0 (PCIR_MAPS + BASEREG0_MAPOFF) #define BADDR1 (PCIR_MAPS + BASEREG1_MAPOFF) static void iwic_pci_intr(struct iwic_softc *sc); static int iwic_pci_probe(device_t dev); static int iwic_pci_attach(device_t dev); static device_method_t iwic_pci_methods[] = { DEVMETHOD(device_probe, iwic_pci_probe), DEVMETHOD(device_attach, iwic_pci_attach), { 0, 0 } }; static driver_t iwic_pci_driver = { "iwic", iwic_pci_methods, 0 }; static devclass_t iwic_pci_devclass; DRIVER_MODULE(iwic, pci, iwic_pci_driver, iwic_pci_devclass, 0, 0); #define IWIC_MAXUNIT 4 struct iwic_softc iwic_sc[IWIC_MAXUNIT]; /*---------------------------------------------------------------------------* * PCI ID list for ASUSCOM card got from Asuscom in March 2000: * * Vendor ID: 0675 Device ID: 1702 * Vendor ID: 0675 Device ID: 1703 * Vendor ID: 0675 Device ID: 1707 * Vendor ID: 10CF Device ID: 105E * Vendor ID: 1043 Device ID: 0675 SubVendor: 144F SubDevice ID: 2000 * Vendor ID: 1043 Device ID: 0675 SubVendor: 144F SubDevice ID: 1702 * Vendor ID: 1043 Device ID: 0675 SubVendor: 144F SubDevice ID: 1707 * Vendor ID: 1043 Device ID: 0675 SubVendor: 1043 SubDevice ID: 1702 * Vendor ID: 1043 Device ID: 0675 SubVendor: 1043 SubDevice ID: 1707 * Vendor ID: 1050 Device ID: 6692 SubVendor: 0675 SubDevice ID: 1702 *---------------------------------------------------------------------------*/ static struct winids { u_int32_t type; int sv; int sd; const char *desc; } win_ids[] = { { 0x66921050, -1, -1, "Generic Winbond W6692 ISDN PCI (0x66921050)" }, { 0x17020675, -1, -1, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x17020675)" }, { 0x17030675, -1, -1, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x17030675)" }, { 0x17070675, -1, -1, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x17070675)" }, { 0x105e10cf, -1, -1, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x105e10cf)" }, { 0x06751043, 0x144F, 0x2000, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x144F, 0x1702, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x144F, 0x1707, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x1443, 0x1702, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x1443, 0x1707, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x144F, 0x2000, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x144F, 0x2000, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x06751043, 0x144F, 0x2000, "ASUSCOM P-IN100-ST-D (Winbond W6692, 0x06751043)" }, { 0x00000000, 0, 0, NULL } }; /*---------------------------------------------------------------------------* * iwic PCI probe *---------------------------------------------------------------------------*/ static int iwic_pci_probe(device_t dev) { u_int32_t type = pci_get_devid(dev); u_int32_t sv = pci_get_subvendor(dev); u_int32_t sd = pci_get_subdevice(dev); struct winids *wip = win_ids; while(wip->type) { if(wip->type == type) { if(((wip->sv == -1) && (wip->sd == -1)) || ((wip->sv == sv) && (wip->sd == sd))) break; } ++wip; } if(wip->desc) { if(bootverbose) { printf("iwic_pci_probe: vendor = 0x%x, device = 0x%x\n", pci_get_vendor(dev), pci_get_device(dev)); printf("iwic_pci_probe: subvendor = 0x%x, subdevice = 0x%x\n", sv, sd); } device_set_desc(dev, wip->desc); return(0); } else { return(ENXIO); } } /*---------------------------------------------------------------------------* * PCI attach *---------------------------------------------------------------------------*/ static int iwic_pci_attach(device_t dev) { unsigned short iobase; struct iwic_softc *sc; void *ih = 0; int unit = device_get_unit(dev); struct iwic_bchan *bchan; /* check max unit range */ if(unit >= IWIC_MAXUNIT) { printf("iwic%d: Error, unit %d >= IWIC_MAXUNIT!\n", unit, unit); return(ENXIO); } sc = iwic_find_sc(unit); /* get softc */ sc->sc_unit = unit; /* use the i/o mapped base address */ sc->sc_resources.io_rid[0] = BADDR1; if(!(sc->sc_resources.io_base[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_resources.io_rid[0], 0UL, ~0UL, 1, RF_ACTIVE))) { printf("iwic%d: Couldn't alloc io port!\n", unit); return(ENXIO); } iobase = rman_get_start(sc->sc_resources.io_base[0]); if(!(sc->sc_resources.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_resources.irq_rid, 0UL, ~0UL, 1, RF_SHAREABLE|RF_ACTIVE))) { printf("iwic%d: Couldn't alloc irq!\n",unit); return(ENXIO); } /* setup card type */ sc->sc_cardtyp = CARD_TYPEP_WINB6692; sc->sc_iobase = (u_int32_t) iobase; sc->sc_trace = TRACE_OFF; sc->sc_I430state = ST_F3N; /* Deactivated */ sc->enabled = FALSE; if(bus_setup_intr(dev, sc->sc_resources.irq, INTR_TYPE_NET, (void(*)(void*))iwic_pci_intr, sc, &ih)) { printf("iwic%d: Couldn't set up irq!\n", unit); return(ENXIO); } /* disable interrupts */ IWIC_WRITE(sc, IMASK, 0xff); iwic_dchan_init(sc); bchan = &sc->sc_bchan[IWIC_BCH_A]; bchan->unit = unit; bchan->offset = B1_CHAN_OFFSET; bchan->channel = IWIC_BCH_A; bchan->state = ST_IDLE; iwic_bchannel_setup(unit, IWIC_BCH_A, BPROT_NONE, 0); bchan = &sc->sc_bchan[IWIC_BCH_B]; bchan->unit = unit; bchan->offset = B2_CHAN_OFFSET; bchan->channel = IWIC_BCH_B; bchan->state = ST_IDLE; iwic_bchannel_setup(unit, IWIC_BCH_B, BPROT_NONE, 0); iwic_init_linktab(sc); i4b_l1_mph_status_ind(L0IWICUNIT(sc->sc_unit), STI_ATTACH, sc->sc_cardtyp, &iwic_l1mux_func); IWIC_READ(sc, ISTA); /* Enable interrupts */ IWIC_WRITE(sc, IMASK, IMASK_XINT0 | IMASK_XINT1); return(0); } /*---------------------------------------------------------------------------* * IRQ handler *---------------------------------------------------------------------------*/ static void iwic_pci_intr(struct iwic_softc *sc) { while (1) { int irq_stat = IWIC_READ(sc, ISTA); if (irq_stat == 0) break; if (irq_stat & (ISTA_D_RME | ISTA_D_RMR | ISTA_D_XFR)) { iwic_dchan_xfer_irq(sc, irq_stat); } if (irq_stat & ISTA_D_EXI) { iwic_dchan_xirq(sc); } if (irq_stat & ISTA_B1_EXI) { iwic_bchan_xirq(sc, 0); } if (irq_stat & ISTA_B2_EXI) { iwic_bchan_xirq(sc, 1); } } } #endif Index: head/sys/i4b/layer2/i4b_iframe.c =================================================================== --- head/sys/i4b/layer2/i4b_iframe.c (revision 67972) +++ head/sys/i4b/layer2/i4b_iframe.c (revision 67973) @@ -1,291 +1,290 @@ /* * Copyright (c) 1997, 2000 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.25 2000/08/24 11:48:57 hm Exp $ * * $FreeBSD$ * * last edit-date: [Thu Aug 24 12:49:18 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #include #else #include #include #include #endif #include #include #include #include #include #include /*---------------------------------------------------------------------------* * process i frame * implements the routine "I COMMAND" Q.921 03/93 pp 68 and 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; CRIT_VAR; 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); NDBGL2(L2_I_ERR, "ERROR, state != (MF || TR)!"); return; } CRIT_BEG; l2sc->stat.rx_i++; /* update frame count */ 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; CRIT_END; 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; } CRIT_END; } /*---------------------------------------------------------------------------* * internal I FRAME QUEUED UP routine (Q.921 03/93 p 61) *---------------------------------------------------------------------------*/ void i4b_i_frame_queued_up(l2_softc_t *l2sc) { struct mbuf *m; u_char *ptr; CRIT_VAR; CRIT_BEG; if((l2sc->peer_busy) || (l2sc->vs == ((l2sc->va + MAX_K_VALUE) & 127))) { if(l2sc->peer_busy) { NDBGL2(L2_I_MSG, "regen IFQUP, cause: peer busy!"); } if(l2sc->vs == ((l2sc->va + MAX_K_VALUE) & 127)) { NDBGL2(L2_I_MSG, "regen IFQUP, cause: vs=va+k!"); } /* * XXX see: Q.921, page 36, 5.6.1 ".. may retransmit an I * frame ...", shall we retransmit the last i frame ? */ if(!(IF_QEMPTY(&l2sc->i_queue))) { NDBGL2(L2_I_MSG, "re-scheduling IFQU call!"); START_TIMER(l2sc->IFQU_callout, i4b_i_frame_queued_up, l2sc, IFQU_DLY); } CRIT_END; return; } IF_DEQUEUE(&l2sc->i_queue, m); /* fetch next frame to tx */ if(!m) { NDBGL2(L2_I_ERR, "ERROR, mbuf NULL after IF_DEQUEUE"); CRIT_END; 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 */ l2sc->stat.tx_i++; /* update frame counter */ 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 */ { NDBGL2(L2_I_ERR, "ERROR, l2sc->ua_num: %d != UA_EMPTY", 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; CRIT_END; if(l2sc->T200 == TIMER_IDLE) { i4b_T203_stop(l2sc); i4b_T200_start(l2sc); } } #endif /* NI4BQ921 > 0 */ Index: head/sys/i4b/layer2/i4b_l2.c =================================================================== --- head/sys/i4b/layer2/i4b_l2.c (revision 67972) +++ head/sys/i4b/layer2/i4b_l2.c (revision 67973) @@ -1,410 +1,409 @@ /* * Copyright (c) 1997, 2000 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.35 2000/08/24 11:48:57 hm Exp $ * * $FreeBSD$ * * last edit-date: [Thu Aug 24 13:40:35 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include #include #include #include #include #include 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, void *); /* from layer 2 */ 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, void *)) i4b_mdl_command_req }; /*---------------------------------------------------------------------------* * DL_ESTABLISH_REQ from layer 3 *---------------------------------------------------------------------------*/ int i4b_dl_establish_req(int unit) { l2_softc_t *l2sc = &l2_softc[unit]; NDBGL2(L2_PRIM, "unit %d",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]; NDBGL2(L2_PRIM, "unit %d",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 NDBGL2(L2_PRIM, "unit %d",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]; #ifdef NOTDEF NDBGL2(L2_PRIM, "unit %d",unit); #endif switch(l2sc->Q921_state) { case ST_AW_EST: case ST_MULTIFR: case ST_TIMREC: if(IF_QFULL(&l2sc->i_queue)) { NDBGL2(L2_ERROR, "i_queue full!!"); i4b_Dfreembuf(m); } else { CRIT_VAR; CRIT_BEG; IF_ENQUEUE(&l2sc->i_queue, m); CRIT_END; i4b_i_frame_queued_up(l2sc); } break; default: NDBGL2(L2_ERROR, "unit %d ERROR in state [%s], freeing mbuf", 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]; NDBGL1(L1_PRIM, "unit %d",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]; NDBGL1(L1_PRIM, "unit %d",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]; CRIT_VAR; CRIT_BEG; 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); CRIT_END; } /*---------------------------------------------------------------------------* * 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]; CRIT_VAR; int sendup = 1; CRIT_BEG; NDBGL1(L1_PRIM, "unit %d, status=%d, parm=%d", unit, status, parm); switch(status) { case STI_ATTACH: l2sc->unit = unit; l2sc->i_queue.ifq_maxlen = IQUEUE_MAXLEN; l2sc->ua_frame = NULL; bzero(&l2sc->stat, sizeof(lapdstat_t)); i4b_l2_unit_init(unit); #if defined(__FreeBSD__) /* 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); callout_handle_init(&l2sc->IFQU_callout); #endif #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 /* initialize the callout handles for timeout routines */ callout_init(&l2sc->T200_callout); callout_init(&l2sc->T202_callout); callout_init(&l2sc->T203_callout); callout_init(&l2sc->IFQU_callout); #endif break; case STI_L1STAT: /* state of layer 1 */ break; case STI_PDEACT: /* Timer 4 expired */ /*XXX*/ if((l2sc->Q921_state >= ST_AW_EST) && (l2sc->Q921_state <= ST_TIMREC)) { NDBGL2(L2_ERROR, "unit %d, persistent deactivation!", unit); i4b_l2_unit_init(unit); } else { sendup = 0; } break; case STI_NOL1ACC: i4b_l2_unit_init(unit); NDBGL2(L2_ERROR, "unit %d, cannot access S0 bus!", unit); break; default: NDBGL2(L2_ERROR, "ERROR, unit %d, unknown status message!", unit); break; } if(sendup) MDL_Status_Ind(unit, status, parm); /* send up to layer 3 */ CRIT_END; return(0); } /*---------------------------------------------------------------------------* * MDL_COMMAND_REQ from layer 3 *---------------------------------------------------------------------------*/ int i4b_mdl_command_req(int unit, int command, void * parm) { NDBGL2(L2_PRIM, "unit %d, command=%d, parm=%d", unit, command, (unsigned int)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) { l2_softc_t *l2sc = &l2_softc[unit]; #ifdef NOTDEF NDBGL1(L1_PRIM, "unit %d", unit); #endif u_char *ptr = m->m_data; if ( (*(ptr + OFF_CNTL) & 0x01) == 0 ) { if(m->m_len < 4) /* 6 oct - 2 chksum oct */ { l2sc->stat.err_rx_len++; NDBGL2(L2_ERROR, "ERROR, I-frame < 6 octetts!"); 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 */ { l2sc->stat.err_rx_len++; NDBGL2(L2_ERROR, "ERROR, S-frame < 6 octetts!"); 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 */ { l2sc->stat.err_rx_len++; NDBGL2(L2_ERROR, "ERROR, U-frame < 5 octetts!"); i4b_Dfreembuf(m); return(0); } i4b_rxd_u_frame(unit, m); } else { l2sc->stat.err_rx_badf++; NDBGL2(L2_ERROR, "ERROR, bad frame rx'd - "); i4b_print_frame(m->m_len, m->m_data); i4b_Dfreembuf(m); } return(0); } #endif /* NI4BQ921 > 0 */ Index: head/sys/i4b/layer2/i4b_l2timer.c =================================================================== --- head/sys/i4b/layer2/i4b_l2timer.c (revision 67972) +++ head/sys/i4b/layer2/i4b_l2timer.c (revision 67973) @@ -1,252 +1,251 @@ /* * Copyright (c) 1997, 2000 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.20 2000/08/24 11:48:58 hm Exp $ * * $FreeBSD$ * * last edit-date: [Thu Aug 24 12:48:52 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include #include #include /*---------------------------------------------------------------------------* * Q.921 timer T200 timeout function *---------------------------------------------------------------------------*/ static void i4b_T200_timeout(l2_softc_t *l2sc) { NDBGL2(L2_T_ERR, "unit %d, RC = %d", l2sc->unit, l2sc->RC); i4b_next_l2state(l2sc, EV_T200EXP); } /*---------------------------------------------------------------------------* * Q.921 timer T200 start *---------------------------------------------------------------------------*/ void i4b_T200_start(l2_softc_t *l2sc) { if(l2sc->T200 == TIMER_ACTIVE) return; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); l2sc->T200 = TIMER_ACTIVE; START_TIMER(l2sc->T200_callout, i4b_T200_timeout, l2sc, T200DEF); } /*---------------------------------------------------------------------------* * Q.921 timer T200 stop *---------------------------------------------------------------------------*/ void i4b_T200_stop(l2_softc_t *l2sc) { CRIT_VAR; CRIT_BEG; if(l2sc->T200 != TIMER_IDLE) { STOP_TIMER(l2sc->T200_callout, i4b_T200_timeout, l2sc); l2sc->T200 = TIMER_IDLE; } CRIT_END; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); } /*---------------------------------------------------------------------------* * Q.921 timer T200 restart *---------------------------------------------------------------------------*/ void i4b_T200_restart(l2_softc_t *l2sc) { CRIT_VAR; CRIT_BEG; if(l2sc->T200 != TIMER_IDLE) { STOP_TIMER(l2sc->T200_callout, i4b_T200_timeout, l2sc); } else { l2sc->T200 = TIMER_ACTIVE; } START_TIMER(l2sc->T200_callout, i4b_T200_timeout, l2sc, T200DEF); CRIT_END; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); } /*---------------------------------------------------------------------------* * Q.921 timer T202 timeout function *---------------------------------------------------------------------------*/ static void i4b_T202_timeout(l2_softc_t *l2sc) { NDBGL2(L2_T_ERR, "unit %d, N202 = %d", l2sc->unit, l2sc->N202); if(--(l2sc->N202)) { (*l2sc->T202func)(l2sc); } } /*---------------------------------------------------------------------------* * Q.921 timer T202 start *---------------------------------------------------------------------------*/ void i4b_T202_start(l2_softc_t *l2sc) { if (l2sc->N202 == TIMER_ACTIVE) return; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); l2sc->N202 = N202DEF; l2sc->T202 = TIMER_ACTIVE; START_TIMER(l2sc->T202_callout, i4b_T202_timeout, l2sc, T202DEF); } /*---------------------------------------------------------------------------* * Q.921 timer T202 stop *---------------------------------------------------------------------------*/ void i4b_T202_stop(l2_softc_t *l2sc) { CRIT_VAR; CRIT_BEG; if(l2sc->T202 != TIMER_IDLE) { STOP_TIMER(l2sc->T202_callout, i4b_T202_timeout, l2sc); l2sc->T202 = TIMER_IDLE; } CRIT_END; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); } /*---------------------------------------------------------------------------* * Q.921 timer T203 timeout function *---------------------------------------------------------------------------*/ #if I4B_T203_ACTIVE static void i4b_T203_timeout(l2_softc_t *l2sc) { NDBGL2(L2_T_ERR, "unit %d", 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 if (l2sc->T203 == TIMER_ACTIVE) return; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); l2sc->T203 = TIMER_ACTIVE; START_TIMER(l2sc->T203_callout, i4b_T203_timeout, l2sc, T203DEF); #endif } /*---------------------------------------------------------------------------* * Q.921 timer T203 stop *---------------------------------------------------------------------------*/ void i4b_T203_stop(l2_softc_t *l2sc) { #if I4B_T203_ACTIVE CRIT_VAR; CRIT_BEG; if(l2sc->T203 != TIMER_IDLE) { STOP_TIMER(l2sc->T203_callout, i4b_T203_timeout, l2sc); l2sc->T203 = TIMER_IDLE; } CRIT_END; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); #endif } /*---------------------------------------------------------------------------* * Q.921 timer T203 restart *---------------------------------------------------------------------------*/ void i4b_T203_restart(l2_softc_t *l2sc) { #if I4B_T203_ACTIVE CRIT_VAR; CRIT_BEG; if(l2sc->T203 != TIMER_IDLE) { STOP_TIMER(l2sc->T203_callout, i4b_T203_timerout, l2sc); } else { l2sc->T203 = TIMER_ACTIVE; } START_TIMER(l2sc->T203_callout, i4b_T203_timerout, l2sc, T203DEF); CRIT_END; NDBGL2(L2_T_MSG, "unit %d", l2sc->unit); #endif } #endif /* NI4BQ921 > 0 */ Index: head/sys/i4b/layer2/i4b_lme.c =================================================================== --- head/sys/i4b/layer2/i4b_lme.c (revision 67972) +++ head/sys/i4b/layer2/i4b_lme.c (revision 67973) @@ -1,156 +1,155 @@ /* * Copyright (c) 1997, 2000 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.15 2000/08/24 11:48:58 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:55:12 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include /*---------------------------------------------------------------------------* * mdl assign indication handler *---------------------------------------------------------------------------*/ void i4b_mdl_assign_ind(l2_softc_t *l2sc) { NDBGL2(L2_PRIM, "unit %d", 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) { #if DO_I4B_DEBUG 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!!!" }; #endif if(errorcode > MDL_ERR_MAX) errorcode = MDL_ERR_MAX; NDBGL2(L2_ERROR, "unit = %d, location = %s", l2sc->unit, where); NDBGL2(L2_ERROR, "error = %s", 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 */ Index: head/sys/i4b/layer2/i4b_sframe.c =================================================================== --- head/sys/i4b/layer2/i4b_sframe.c (revision 67972) +++ head/sys/i4b/layer2/i4b_sframe.c (revision 67973) @@ -1,227 +1,226 @@ /* * Copyright (c) 1997, 2000 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.15 2000/08/24 11:48:58 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:55:23 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include #include #include #include /*---------------------------------------------------------------------------* * 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: l2sc->stat.rx_rr++; /* update statistics */ NDBGL2(L2_S_MSG, "rx'd RR, N(R) = %d", l2sc->rxd_NR); i4b_next_l2state(l2sc, EV_RXRR); break; case RNR: l2sc->stat.rx_rnr++; /* update statistics */ NDBGL2(L2_S_MSG, "rx'd RNR, N(R) = %d", l2sc->rxd_NR); i4b_next_l2state(l2sc, EV_RXRNR); break; case REJ: l2sc->stat.rx_rej++; /* update statistics */ NDBGL2(L2_S_MSG, "rx'd REJ, N(R) = %d", l2sc->rxd_NR); i4b_next_l2state(l2sc, EV_RXREJ); break; default: l2sc->stat.err_rx_bads++; /* update statistics */ NDBGL2(L2_S_ERR, "ERROR, unknown code, frame = "); 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; NDBGL2(L2_S_MSG, "tx RR, unit = %d", l2sc->unit); m = i4b_build_s_frame(l2sc, CR_CMD_TO_NT, pbit, RR); PH_Data_Req(l2sc->unit, m, MBUF_FREE); l2sc->stat.tx_rr++; /* update statistics */ } /*---------------------------------------------------------------------------* * transmit RR response *---------------------------------------------------------------------------*/ void i4b_tx_rr_response(l2_softc_t *l2sc, fbit_t fbit) { struct mbuf *m; NDBGL2(L2_S_MSG, "tx RR, unit = %d", l2sc->unit); m = i4b_build_s_frame(l2sc, CR_RSP_TO_NT, fbit, RR); PH_Data_Req(l2sc->unit, m, MBUF_FREE); l2sc->stat.tx_rr++; /* update statistics */ } /*---------------------------------------------------------------------------* * transmit RNR command *---------------------------------------------------------------------------*/ void i4b_tx_rnr_command(l2_softc_t *l2sc, pbit_t pbit) { struct mbuf *m; NDBGL2(L2_S_MSG, "tx RNR, unit = %d", l2sc->unit); m = i4b_build_s_frame(l2sc, CR_CMD_TO_NT, pbit, RNR); PH_Data_Req(l2sc->unit, m, MBUF_FREE); l2sc->stat.tx_rnr++; /* update statistics */ } /*---------------------------------------------------------------------------* * transmit RNR response *---------------------------------------------------------------------------*/ void i4b_tx_rnr_response(l2_softc_t *l2sc, fbit_t fbit) { struct mbuf *m; NDBGL2(L2_S_MSG, "tx RNR, unit = %d", l2sc->unit); m = i4b_build_s_frame(l2sc, CR_RSP_TO_NT, fbit, RNR); PH_Data_Req(l2sc->unit, m, MBUF_FREE); l2sc->stat.tx_rnr++; /* update statistics */ } /*---------------------------------------------------------------------------* * transmit REJ response *---------------------------------------------------------------------------*/ void i4b_tx_rej_response(l2_softc_t *l2sc, fbit_t fbit) { struct mbuf *m; NDBGL2(L2_S_MSG, "tx REJ, unit = %d", l2sc->unit); m = i4b_build_s_frame(l2sc, CR_RSP_TO_NT, fbit, REJ); PH_Data_Req(l2sc->unit, m, MBUF_FREE); l2sc->stat.tx_rej++; /* update statistics */ } /*---------------------------------------------------------------------------* * 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 */ Index: head/sys/i4b/layer2/i4b_tei.c =================================================================== --- head/sys/i4b/layer2/i4b_tei.c (revision 67972) +++ head/sys/i4b/layer2/i4b_tei.c (revision 67973) @@ -1,323 +1,322 @@ /* * Copyright (c) 1997, 2000 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.25 2000/09/01 14:11:51 hm Exp $ * * $FreeBSD$ * * last edit-date: [Fri Oct 13 15:56:35 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include #include #include #include #include #include /*---------------------------------------------------------------------------* * 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); NDBGL2(L2_TEI_MSG, "TEI ID Assign - TEI = %d", 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); NDBGL2(L2_TEI_ERR, "TEI ID Denied, No TEI values available from exchange!"); } else { log(LOG_WARNING, "i4b: unit %d, denied TEI = %d = 0x%02x\n", l2sc->unit, l2sc->tei, l2sc->tei); NDBGL2(L2_TEI_ERR, "TEI ID Denied - TEI = %d", 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) { NDBGL2(L2_TEI_MSG, "TEI ID Check Req - TEI = %d", 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); NDBGL2(L2_TEI_MSG, "TEI ID Remove - TEI = %d", l2sc->tei); MDL_Status_Ind(l2sc->unit, STI_TEIASG, -1); i4b_next_l2state(l2sc, EV_MDREMRQ); } break; default: NDBGL2(L2_TEI_ERR, "UNKNOWN TEI MGMT Frame, type = 0x%x", *(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; } l2sc->stat.tx_tei++; 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; NDBGL2(L2_TEI_MSG, "tx TEI ID_Request"); 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; NDBGL2(L2_TEI_MSG, "tx TEI ID_Verify"); 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; NDBGL2(L2_TEI_MSG, "tx TEI ID_Check_Response"); } 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__) u_short val; #ifdef RANDOMDEV read_random((char *)&val, sizeof(val)); #else val = (u_short)random(); #endif /* RANDOMDEV */ #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 */ Index: head/sys/i4b/layer2/i4b_uframe.c =================================================================== --- head/sys/i4b/layer2/i4b_uframe.c (revision 67972) +++ head/sys/i4b/layer2/i4b_uframe.c (revision 67973) @@ -1,297 +1,296 @@ /* * Copyright (c) 1997, 2000 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.13 2000/08/24 11:48:58 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:55:30 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include #include #include #include #include /*---------------------------------------------------------------------------* * 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)))) { l2sc->stat.rx_sabme++; NDBGL2(L2_U_MSG, "SABME, sapi = %d, tei = %d", 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) */ l2sc->stat.rx_tei++; i4b_tei_rxframe(unit, m); } else if(sapi == SAPI_CCP && tei == GROUP_TEI) { /* call control (SAPI = 0) */ l2sc->stat.rx_ui++; /* strip ui header */ m_adj(m, UI_HDR_LEN); /* to upper layer */ DL_Unit_Data_Ind(unit, m); } else { l2sc->stat.err_rx_badui++; NDBGL2(L2_U_ERR, "unknown UI frame!"); i4b_Dfreembuf(m); } break; case DISC: if((l2sc->tei_valid == TEI_VALID) && (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) { l2sc->stat.rx_disc++; NDBGL2(L2_U_MSG, "DISC, sapi = %d, tei = %d", 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)))) { l2sc->stat.rx_xid++; NDBGL2(L2_U_MSG, "XID, sapi = %d, tei = %d", sapi, tei); } i4b_Dfreembuf(m); break; /* responses */ case DM: if((l2sc->tei_valid == TEI_VALID) && (l2sc->tei == GETTEI(*(ptr+OFF_TEI)))) { l2sc->stat.rx_dm++; NDBGL2(L2_U_MSG, "DM, sapi = %d, tei = %d", 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)))) { l2sc->stat.rx_ua++; NDBGL2(L2_U_MSG, "UA, sapi = %d, tei = %d", 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)))) { l2sc->stat.rx_frmr++; NDBGL2(L2_U_MSG, "FRMR, sapi = %d, tei = %d", 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)))) { NDBGL2(L2_U_ERR, "UNKNOWN TYPE ERROR, sapi = %d, tei = %d, frame = ", sapi, tei); i4b_print_frame(m->m_len, m->m_data); } else { NDBGL2(L2_U_ERR, "not mine - UNKNOWN TYPE ERROR, sapi = %d, tei = %d, frame = ", sapi, tei); i4b_print_frame(m->m_len, m->m_data); } l2sc->stat.err_rx_badui++; 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; l2sc->stat.tx_sabme++; NDBGL2(L2_U_MSG, "tx SABME, tei = %d", 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; l2sc->stat.tx_dm++; NDBGL2(L2_U_MSG, "tx DM, tei = %d", 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; l2sc->stat.tx_disc++; NDBGL2(L2_U_MSG, "tx DISC, tei = %d", 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; l2sc->stat.tx_ua++; NDBGL2(L2_U_MSG, "tx UA, tei = %d", 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; l2sc->stat.tx_frmr++; NDBGL2(L2_U_MSG, "tx FRMR, tei = %d", 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 */ Index: head/sys/i4b/layer2/i4b_util.c =================================================================== --- head/sys/i4b/layer2/i4b_util.c (revision 67972) +++ head/sys/i4b/layer2/i4b_util.c (revision 67973) @@ -1,326 +1,325 @@ /* * Copyright (c) 1997, 2000 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.26 2000/08/24 11:48:58 hm Exp $ * * $FreeBSD$ * * last edit-date: [Mon May 29 16:55:35 2000] * *---------------------------------------------------------------------------*/ #ifdef __FreeBSD__ #include "i4bq921.h" #else #define NI4BQ921 1 #endif #if NI4BQ921 > 0 #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include -#include #else #include #include #endif #include #include #include #include /*---------------------------------------------------------------------------* * 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) { CRIT_VAR; CRIT_BEG; /*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; CRIT_END; } /*---------------------------------------------------------------------------* * 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) { CRIT_VAR; CRIT_BEG; NDBGL2(L2_ERROR, "nr = %d", nr ); while(l2sc->vs != nr) { NDBGL2(L2_ERROR, "nr(%d) != vs(%d)", nr, l2sc->vs); M128DEC(l2sc->vs); /* XXXXXXXXXXXXXXXXX */ if((l2sc->ua_num != UA_EMPTY) && (l2sc->vs == l2sc->ua_num)) { if(IF_QFULL(&l2sc->i_queue)) { NDBGL2(L2_ERROR, "ERROR, I-queue full!"); } else { IF_ENQUEUE(&l2sc->i_queue, l2sc->ua_frame); l2sc->ua_num = UA_EMPTY; } } else { NDBGL2(L2_ERROR, "ERROR, l2sc->vs = %d, l2sc->ua_num = %d ",l2sc->vs, l2sc->ua_num); } /* XXXXXXXXXXXXXXXXX */ i4b_i_frame_queued_up(l2sc); } CRIT_END; } /*---------------------------------------------------------------------------* * 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) { #if 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) { NDBGL2(L2_ERROR, "unit%d V(R)=%d, V(S)=%d, V(A)=%d,ACKP=%d,PBSY=%d,OBSY=%d", 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 NDBGL2(L2_ERROR, "N(R)=%d, UA=%d, V(R)=%d, V(S)=%d, V(A)=%d", nr, l2sc->ua_num, l2sc->vr, l2sc->vs, l2sc->va); #endif if(l2sc->ua_num != UA_EMPTY) { CRIT_VAR; CRIT_BEG; M128DEC(nr); if(l2sc->ua_num != nr) NDBGL2(L2_ERROR, "((N(R)-1)=%d) != (UA=%d) !!!", nr, l2sc->ua_num); i4b_Dfreembuf(l2sc->ua_frame); l2sc->ua_num = UA_EMPTY; CRIT_END; } } /*---------------------------------------------------------------------------* * 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))) { NDBGL2(L2_ERROR, "ERROR, va = %d, nr = %d, vs = %d [1]", va, nr, vs); return 0; /* fail */ } if((nr > vs) && ((vs != 0) || (nr != 127))) { NDBGL2(L2_ERROR, "ERROR, va = %d, nr = %d, vs = %d [2]", va, nr, vs); return 0; /* fail */ } return 1; /* good */ } #endif /* NI4BQ921 > 0 */