e2c42aeaa8
the generic layer 4 and layer 3 management system. This should make the layer 4 driver API LKM clean - finaly. Make the Fritz!PCI driver work again after resent changes (oops!), noted by Frank Kardel (PR 15948) and Matthias Scheeler.
675 lines
17 KiB
C
675 lines
17 KiB
C
/*
|
|
* 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: hscx.c,v 1.5 2002/03/17 20:54:04 martin Exp $
|
|
*
|
|
* last edit-date: [Fri Jan 5 11:36:10 2001]
|
|
*
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: hscx.c,v 1.5 2002/03/17 20:54:04 martin Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#if defined(__FreeBSD_version) && __FreeBSD_version >= 300001
|
|
#include <sys/ioccom.h>
|
|
#else
|
|
#include <sys/ioctl.h>
|
|
#endif
|
|
#include <sys/kernel.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/mbuf.h>
|
|
#include <machine/stdarg.h>
|
|
|
|
#ifdef __FreeBSD__
|
|
#include <machine/clock.h>
|
|
#include <i386/isa/isa_device.h>
|
|
#else
|
|
#ifndef __bsdi__
|
|
#include <machine/bus.h>
|
|
#endif
|
|
#include <sys/device.h>
|
|
#endif
|
|
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
|
|
#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
|
|
#include <sys/callout.h>
|
|
#endif
|
|
|
|
#ifdef __FreeBSD__
|
|
#include <machine/i4b_debug.h>
|
|
#include <machine/i4b_ioctl.h>
|
|
#include <machine/i4b_trace.h>
|
|
#else
|
|
#include <netisdn/i4b_debug.h>
|
|
#include <netisdn/i4b_ioctl.h>
|
|
#include <netisdn/i4b_trace.h>
|
|
#endif
|
|
|
|
#include <dev/ic/isic_l1.h>
|
|
#include <dev/ic/isac.h>
|
|
#include <dev/ic/hscx.h>
|
|
|
|
#include <netisdn/i4b_l1l2.h>
|
|
#include <netisdn/i4b_global.h>
|
|
#include <netisdn/i4b_mbuf.h>
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* 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 hdr;
|
|
hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
|
|
hdr.dir = FROM_NT;
|
|
hdr.count = ++sc->sc_trace_bcount;
|
|
isdn_layer2_trace_ind(sc->sc_l2, &hdr, chan->in_mbuf->m_len, chan->in_mbuf->m_data);
|
|
}
|
|
|
|
(*chan->l4_driver->bch_rx_data_ready)(chan->l4_driver_softc);
|
|
|
|
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 hdr;
|
|
hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
|
|
hdr.dir = FROM_NT;
|
|
hdr.count = ++sc->sc_trace_bcount;
|
|
isdn_layer2_trace_ind(sc->sc_l2, &hdr,chan->in_mbuf->m_len, chan->in_mbuf->m_data);
|
|
}
|
|
|
|
/* silence detection */
|
|
|
|
if(!(isic_hscx_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->l4_driver->bch_rx_data_ready)(chan->l4_driver_softc);
|
|
|
|
/* 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->l4_driver->bch_tx_queue_empty)(chan->l4_driver_softc);
|
|
}
|
|
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 hdr;
|
|
hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
|
|
hdr.dir = FROM_TE;
|
|
hdr.count = ++sc->sc_trace_bcount;
|
|
isdn_layer2_trace_ind(sc->sc_l2, &hdr, chan->out_mbuf_cur->m_len, chan->out_mbuf_cur->m_data);
|
|
}
|
|
|
|
if(chan->bprot == BPROT_NONE)
|
|
{
|
|
if(!(isic_hscx_silence(chan->out_mbuf_cur->m_data, chan->out_mbuf_cur->m_len)))
|
|
activity = ACT_TX;
|
|
}
|
|
else
|
|
{
|
|
activity = ACT_TX;
|
|
}
|
|
}
|
|
}
|
|
|
|
len = 0;
|
|
|
|
while(chan->out_mbuf_cur && len != sc->sc_bfifolen)
|
|
{
|
|
nextlen = min(chan->out_mbuf_cur_len, sc->sc_bfifolen - len);
|
|
|
|
#ifdef NOTDEF
|
|
printf("i:mh=%x, mc=%x, mcp=%x, mcl=%d l=%d nl=%d # ",
|
|
chan->out_mbuf_head,
|
|
chan->out_mbuf_cur,
|
|
chan->out_mbuf_cur_ptr,
|
|
chan->out_mbuf_cur_len,
|
|
len,
|
|
next_len);
|
|
#endif
|
|
|
|
isic_hscx_waitxfw(sc, h_chan); /* necessary !!! */
|
|
|
|
HSCX_WRFIFO(h_chan, chan->out_mbuf_cur_ptr, nextlen);
|
|
cmd |= HSCX_CMDR_XTF;
|
|
|
|
len += nextlen;
|
|
chan->txcount += nextlen;
|
|
|
|
chan->out_mbuf_cur_ptr += nextlen;
|
|
chan->out_mbuf_cur_len -= nextlen;
|
|
|
|
if(chan->out_mbuf_cur_len == 0)
|
|
{
|
|
if((chan->out_mbuf_cur = chan->out_mbuf_cur->m_next) != NULL)
|
|
{
|
|
chan->out_mbuf_cur_ptr = chan->out_mbuf_cur->m_data;
|
|
chan->out_mbuf_cur_len = chan->out_mbuf_cur->m_len;
|
|
|
|
if(sc->sc_trace & TRACE_B_TX)
|
|
{
|
|
i4b_trace_hdr hdr;
|
|
hdr.type = (h_chan == HSCX_CH_A ? TRC_CH_B1 : TRC_CH_B2);
|
|
hdr.dir = FROM_TE;
|
|
hdr.count = ++sc->sc_trace_bcount;
|
|
isdn_layer2_trace_ind(sc->sc_l2, &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->l4_driver->bch_activity)(chan->l4_driver_softc, 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);
|
|
}
|
|
|
|
isic_hscx_cmd(sc, h_chan, HSCX_CMDR_RHR|HSCX_CMDR_XRES);
|
|
}
|
|
else
|
|
{
|
|
/* TSAX: tx time slot */
|
|
HSCX_WRITE(h_chan, H_TSAX, 0xff);
|
|
|
|
/* TSAR: rx time slot */
|
|
HSCX_WRITE(h_chan, H_TSAR, 0xff);
|
|
|
|
/* Raw Telephony, extended transparent mode 1 */
|
|
HSCX_WRITE(h_chan, H_MODE,
|
|
HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS);
|
|
}
|
|
|
|
/* don't touch ICA, EXA and EXB bits, this could be HSCX_CH_B */
|
|
/* always disable RSC and TIN */
|
|
|
|
chan->hscx_mask |= HSCX_MASK_RSC | HSCX_MASK_TIN;
|
|
|
|
if(activate)
|
|
{
|
|
/* enable */
|
|
chan->hscx_mask &= ~(HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR);
|
|
}
|
|
else
|
|
{
|
|
/* disable */
|
|
chan->hscx_mask |= HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR;
|
|
}
|
|
|
|
/* handle ICA, EXA, and EXB via interrupt mask of channel b */
|
|
|
|
if (h_chan == HSCX_CH_A)
|
|
{
|
|
if (activate)
|
|
HSCX_B_IMASK &= ~(HSCX_MASK_EXA | HSCX_MASK_ICA);
|
|
else
|
|
HSCX_B_IMASK |= HSCX_MASK_EXA | HSCX_MASK_ICA;
|
|
HSCX_WRITE(HSCX_CH_A, H_MASK, HSCX_A_IMASK);
|
|
HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK);
|
|
}
|
|
else
|
|
{
|
|
if (activate)
|
|
HSCX_B_IMASK &= ~HSCX_MASK_EXB;
|
|
else
|
|
HSCX_B_IMASK |= HSCX_MASK_EXB;
|
|
HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK);
|
|
}
|
|
|
|
/* clear spurious interrupts left over */
|
|
|
|
if(h_chan == HSCX_CH_A)
|
|
{
|
|
HSCX_READ(h_chan, H_EXIR);
|
|
HSCX_READ(h_chan, H_ISTA);
|
|
}
|
|
else /* mask ICA, because it must not be cleared by reading ISTA */
|
|
{
|
|
HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK | HSCX_MASK_ICA);
|
|
HSCX_READ(h_chan, H_EXIR);
|
|
HSCX_READ(h_chan, H_ISTA);
|
|
HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* write command to HSCX command register
|
|
*---------------------------------------------------------------------------*/
|
|
void
|
|
isic_hscx_cmd(struct 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);
|
|
}
|
|
}
|
|
|