diff --git drivers/dahdi/Kbuild drivers/dahdi/Kbuild index 3fe2e28..ce5788b 100644 --- drivers/dahdi/Kbuild +++ drivers/dahdi/Kbuild @@ -22,6 +22,7 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_TOR2) += tor2.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_PCIRADIO) += pciradio.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPP) += xpp/ +obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_RHINO) += rhino/ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_JPAH) += dahdi_echocan_jpah.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE) += dahdi_echocan_sec.o diff --git drivers/dahdi/Kconfig drivers/dahdi/Kconfig index 6952c6a..cae6633 100644 --- drivers/dahdi/Kconfig +++ drivers/dahdi/Kconfig @@ -292,3 +292,4 @@ config DAHDI_WCTE11XP If unsure, say Y. source "drivers/dahdi/xpp/Kconfig" +source "drivers/dahdi/rhino/Kconfig" diff --git drivers/dahdi/rhino/Kbuild drivers/dahdi/rhino/Kbuild new file mode 100644 index 0000000..7c7d286 --- /dev/null +++ drivers/dahdi/rhino/Kbuild @@ -0,0 +1,36 @@ +EXTRA_CFLAGS+=-Drw_lock_t=rwlock_t + +obj-m += r1t1/ +obj-m += rcbfx/ +obj-m += rxt1/ + +ifdef DEBUG + $(info Kernel BUILDVER=$(BUILDVER)) + $(info Kernel SUBLEVEL=$(SUBLEVEL)) +endif + +#Include the config telling us what to compile +KCONFIG:=$(KSRC)/.config +MYCONFIG:=$(PWD)/.config +ifneq (,$(wildcard $(KCONFIG))) + include $(KCONFIG) +endif +ifneq (,$(wildcard $(MYCONFIG))) + include $(MYCONFIG) +endif + + +all: modules + +modules: + $(KMAKE) modules + +clean: + $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) clean + +install: all + $(KMAKE) INSTALL_MOD_PATH=$(INSTALL_PREFIX) INSTALL_MOD_DIR=rhino modules_install + [ `id -u` = 0 ] && /sbin/depmod -a $(KVER) || : + +.PHONY: clean install modules + diff --git drivers/dahdi/rhino/Kconfig drivers/dahdi/rhino/Kconfig new file mode 100644 index 0000000..36522d2 --- /dev/null +++ drivers/dahdi/rhino/Kconfig @@ -0,0 +1,62 @@ +# +# Rhino configuration +# + +menuconfig RHINO + tristate "Rhino support" + select DAHDI + default m + ---help--- + Rhino DAHDI drivers. + + To compile the Rhino PCI drivers as modules, choose M here. + + If unsure, say Y. + +config RHINO_R1T1 + tristate "Rhino R1T1 T1-E1-J1 Support" + depends on DAHDI && PCI && RHINO + default RHINO + ---help--- + This driver provides support for the following Rhino + Equipment products: + + * R1T1 (PCI/PCIe) + + To compile this driver as a module, choose M here: the + module will be called r1t1. + + If unsure, say Y. + +config RHINO_RCBFX + tristate "Rhino Equipment Modular Analog Interface Support" + depends on DAHDI && PCI && RHINO + default RHINO + ---help--- + This driver provides support for the following Rhino + Equipment products: + + * RCB4FXO (PCI/PCIe) + * RCB8FXX (PCI/PCIe) + * RCB24FXX/FXO/FXS (PCI/PCIe) + + To compile this driver as a module, choose M here: the + module will be called rcbfx. + + If unsure, say Y. + +config RHINO_RXT1 + tristate "Rhino Equipment 1-2-4 Span T1-E1-J1 PCI Support" + depends on DAHDI && PCI && RHINO + default RHINO + ---help--- + This driver provides support for the following Rhino + Equipment products: + + * R2T1 (PCI/PCIe) + * R4T1 (PCI/PCIe) + + To compile this driver as a module, choose M here: the + module will be called rxt1. + + If unsure, say Y. diff --git drivers/dahdi/rhino/Makefile drivers/dahdi/rhino/Makefile new file mode 100644 index 0000000..00fc5ee --- /dev/null +++ drivers/dahdi/rhino/Makefile @@ -0,0 +1,7 @@ +# We only get here on kernels 2.6.0-2.6.9 . +# For newer kernels, Kbuild will be included directly by the kernel +# build system. +-include $(src)/Kbuild + +ctags: + ctags *.[ch] diff --git drivers/dahdi/rhino/r1t1/GpakApi.c drivers/dahdi/rhino/r1t1/GpakApi.c new file mode 100644 index 0000000..885bfe5 --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakApi.c @@ -0,0 +1,1450 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakApi.c + * + * Description: + * This file contains user API functions to communicate with DSPs executing + * G.PAK software. The file is integrated into the host processor connected + * to C55X G.PAK DSPs via a Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * 11/15/2006 - 24 TDM-TDM Channels EC release + */ + +#include "r1t1.h" +#include "GpakHpi.h" +#include "GpakCust.h" +#include "GpakApi.h" +#include "gpakenum.h" + +/* Boot load interface related definitions. */ +/* only word(16bit) address below 0x4000 could be accessed by Host */ +/* bootloader loaded first, then help host load real application */ +#define BL_DSP_STATUS 0x3800 /* DSP status (non zero = ready), word address */ +#define BL_HOST_CMD (BL_DSP_STATUS + 1) /* Host cmd (1=Prog, 2=Data, 3=Run) */ +#define BL_ADDRESS (BL_DSP_STATUS + 2) /* destination address */ /* Huafeng ; 2word address for C55X */ +#define BL_LENGTH (BL_DSP_STATUS + 4) /* length (words) to write */ +#define BL_BUFFER 0x3900 /* memory image buffer (source), word adress */ +#define BL_BUFFER_SIZE 0x0700 /* size of memory image buffer */ + +/* DSP to Host interface block offsets. */ +#define REPLY_MSG_PNTR_OFFSET 0 /* I/F blk offset to Reply Msg Pointer */ +#define CMD_MSG_PNTR_OFFSET 2 /* I/F blk offset to Command Msg Pointer */ +#define EVENT_MSG_PNTR_OFFSET 4 /* I/F blk offset to Event Msg Pointer */ +#define PKT_BUFR_MEM_OFFSET 6 /* I/F blk offset to Packet Buffer memory */ +#define DSP_STATUS_OFFSET 8 /* I/F blk offset to DSP Status */ +#define VERSION_ID_OFFSET 9 /* I/F blk offset to G.PAK Version Id */ +#define MAX_CMD_MSG_LEN_OFFSET 10 /* I/F blk offset to Max Cmd Msg Length */ +#define CMD_MSG_LEN_OFFSET 11 /* I/F blk offset to Command Msg Length */ +#define REPLY_MSG_LEN_OFFSET 12 /* I/F blk offset to Reply Msg Length */ +#define NUM_CHANNELS_OFFSET 13 /* I/F blk offset to Num Built Channels */ +#define NUM_PKT_CHANNELS_OFFSET 14 /* I/F blk offset to Num Pkt Channels */ +#define NUM_CONFERENCES_OFFSET 15 /* I/F blk offset to Num Conferences */ +//#define CPU_USAGE_OFFSET_1MS 16 /* I/F blk offset to CPU Usage statistics */ +#define CPU_USAGE_OFFSET 18 /* I/F blk offset to CPU Usage statistics */ +//#define CPU_USAGE_OFFSET_10MS 20 /* I/F blk offset to CPU Usage statistics */ +#define FRAMING_STATS_OFFSET 22 /* I/F blk offset to Framing statistics */ + +//#define GPAK_RELEASE_Rate rate10ms +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +// Macro to reconstruct a 32-bit value from two 16-bit values. +// Parameter p32: 32-bit-wide destination +// Parameter p16: 16-bit-wide source array of length 2 words +#define RECONSTRUCT_LONGWORD(p32, p16) p32 = (DSP_ADDRESS)p16[0]<<16; \ + p32 |= (unsigned long)p16[1] +// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +/* DSP Status value definitions. */ +#define DSP_INIT_STATUS 0x5555 /* DSP Initialized status value */ +#define HOST_INIT_STATUS 0xAAAA /* Host Initialized status value */ + +/* Circular packet buffer information structure offsets. */ +#define CB_BUFR_BASE 0 /* pointer to base of circular buffer */ +#define CB_BUFR_SIZE 2 /* size of buffer (words) */ +#define CB_BUFR_PUT_INDEX 3 /* offset in buffer for next write */ +#define CB_BUFR_TAKE_INDEX 4 /* offset in buffer for next read */ +#define CIRC_BUFFER_INFO_STRUCT_SIZE 6 + +/* Miscellaneous definitions. */ +//#define MSG_BUFFER_SIZE 1000 /* size (words) of Host msg buffer */ +// Why the hell not +#define MSG_BUFFER_SIZE 1000 /* size (words) of Host msg buffer */ +#define WORD_BUFFER_SIZE 84 /* size of DSP Word buffer (words) */ + +#ifdef __TMS320C55XX__ // debug sections if not on host +#pragma DATA_SECTION(pDspIfBlk,"GPAKAPIDEBUG_SECT") +#pragma DATA_SECTION(MaxCmdMsgLen,"GPAKAPIDEBUG_SECT") +#pragma DATA_SECTION(MaxChannels,"GPAKAPIDEBUG_SECT") +#pragma DATA_SECTION(DlByteBufr,"GPAKAPIDEBUG_SECT") +#pragma DATA_SECTION(DlWordBufr,"GPAKAPIDEBUG_SECT") +#pragma DATA_SECTION(pEventFifoAddress,"GPAKAPIDEBUG_SECT") +#endif + +/* Host variables related to Host to DSP interface. */ +static DSP_ADDRESS pDspIfBlk[MAX_DSP_CORES]; /* DSP address of I/F block */ +static DSP_WORD MaxCmdMsgLen[MAX_DSP_CORES]; /* max Cmd msg length (octets) */ +static unsigned short int MaxChannels[MAX_DSP_CORES]; /* max num channels */ + +//static unsigned short int MaxPktChannels[MAX_DSP_CORES]; /* max num pkt channels */ +//static unsigned short int MaxConfs[MAX_DSP_CORES]; /* max num conferences */ +//static DSP_ADDRESS pPktInBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt In buffer */ +//static DSP_ADDRESS pPktOutBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt Out buffer */ +static DSP_ADDRESS pEventFifoAddress[MAX_DSP_CORES]; /* event fifo */ + +static unsigned char DlByteBufr[DOWNLOAD_BLOCK_SIZE * 2]; /* Download byte buf */ +static DSP_WORD DlWordBufr[DOWNLOAD_BLOCK_SIZE]; /* Download word buffer */ +static DSP_WORD DlWordChek[DOWNLOAD_BLOCK_SIZE]; /* Check word buffer */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * CheckDspReset - Check if the DSP was reset. + * + * FUNCTION + * This function determines if the DSP was reset and is ready. If reset + * occurred, it reads interface parameters and calculates DSP addresses. + * + * RETURNS + * -1 = DSP is not ready. + * 0 = Reset did not occur. + * 1 = Reset occurred. + * + */ +static int CheckDspReset(struct r1t1 *rh, /* Card containing the DSP */ + int DspId /* DSP Identifier (0 to MaxDSPCores-1) */ + ) +{ + DSP_ADDRESS IfBlockPntr; /* Interface Block pointer */ + DSP_WORD DspStatus; /* DSP Status */ + DSP_WORD DspChannels; /* number of DSP channels */ +// DSP_WORD DspConfs; /* number of DSP conferences */ +// DSP_ADDRESS PktBufrMem; /* address of Packet Buffer */ + DSP_WORD Temp[2]; +// unsigned short int i; /* loop index / counter */ + + /* Read the pointer to the Interface Block. */ + gpakReadDspMemory(rh, DspId, DSP_IFBLK_ADDRESS, 2, Temp); + RECONSTRUCT_LONGWORD(IfBlockPntr, Temp); +// printk("IfBlockPntr %x\n", IfBlockPntr); + /* If the pointer is zero, return with an indication the DSP is not + ready. */ + if (IfBlockPntr == 0) + return (-1); + + /* Read the DSP's Status. */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus); + + /* If status indicates the DSP was reset, read the DSP's interface + parameters and calculate DSP addresses. */ +// printk("if DspStatus %x DSP_INIT_STATUS %x or pDspIfBlk[DspId] %x HOST_INIT_STATUS %x\n", +// DspStatus, DSP_INIT_STATUS, pDspIfBlk[DspId], HOST_INIT_STATUS); + if (DspStatus == DSP_INIT_STATUS || + ((DspStatus == HOST_INIT_STATUS) && (pDspIfBlk[DspId] == 0))) { + /* Save the address of the DSP's Interface Block. */ + pDspIfBlk[DspId] = IfBlockPntr; + + /* Read the DSP's interface parameters. */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + MAX_CMD_MSG_LEN_OFFSET, 1, + &(MaxCmdMsgLen[DspId])); + + /* read the number of configured DSP channels */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + NUM_CHANNELS_OFFSET, 1, &DspChannels); + if (DspChannels > MAX_CHANNELS) + MaxChannels[DspId] = MAX_CHANNELS; + else + MaxChannels[DspId] = (unsigned short int) DspChannels; +#if 0 + /* read the number of configured DSP conferences */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + NUM_CONFERENCES_OFFSET, 1, &DspConfs); + if (DspConfs > MAX_CONFS) + MaxConfs[DspId] = MAX_CONFS; + else + MaxConfs[DspId] = (unsigned short int) DspConfs; + + + /* read the number of configured DSP packet channels */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + NUM_PKT_CHANNELS_OFFSET, 1, + &DspChannels); + if (DspChannels > MAX_PKT_CHANNELS) + MaxPktChannels[DspId] = MAX_PKT_CHANNELS; + else + MaxPktChannels[DspId] = (unsigned short int) DspChannels; + + + /* read the pointer to the circular buffer infor struct table */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + PKT_BUFR_MEM_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(PktBufrMem, Temp); + + + /* Determine the addresses of each channel's Packet buffers. */ + for (i = 0; i < MaxPktChannels[DspId]; i++) { + pPktInBufr[DspId][i] = PktBufrMem; + pPktOutBufr[DspId][i] = PktBufrMem + CIRC_BUFFER_INFO_STRUCT_SIZE; + PktBufrMem += (CIRC_BUFFER_INFO_STRUCT_SIZE * 2); + } +#endif + + if (rh->dsp_type == DSP_5510) { + /* read the pointer to the event fifo info struct */ + gpakReadDspMemory(rh, DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp); + } + + /* Set the DSP Status to indicate the host recognized the reset. */ + DspStatus = HOST_INIT_STATUS; + gpakWriteDspMemory(rh, DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus); + + /* Return with an indication that a reset occurred. */ + return (1); + } + + /* If status doesn't indicate the host recognized a reset, return with an + indication the DSP is not ready. */ + if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0)) + return (-1); + + /* Return with an indication that a reset did not occur. */ + return (0); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * WriteDspCmdMessage - Write a Host Command/Request message to DSP. + * + * FUNCTION + * This function writes a Host Command/Request message into DSP memory and + * informs the DSP of the presence of the message. + * + * RETURNS + * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) + * 0 = Temporarily unable to write message (previous Cmd Msg busy) + * 1 = Message written successfully + * + */ +static int WriteDspCmdMessage(struct r1t1 *rh, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMessage, /* pointer to Command message */ + DSP_WORD MsgLength /* length of message (octets) */ + ) +{ + DSP_WORD CmdMsgLength; /* current Cmd message length */ + DSP_WORD Temp[2]; + DSP_ADDRESS BufferPointer; /* message buffer pointer */ + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rh, DspId) == -1) + return (-1); + + /* Make sure the message length is valid. */ + if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId])) + return (-1); + + /* Make sure a previous Command message is not in use by the DSP. */ + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, &CmdMsgLength); + if (CmdMsgLength != 0) + return (0); + + /* Purge any previous Reply message that wasn't read. */ + gpakWriteDspMemory(rh, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Copy the Command message into DSP memory. */ + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakWriteDspMemory(rh, DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); + + /* Store the message length in DSP's Command message length (flags DSP that + a Command message is ready). */ + CmdMsgLength = MsgLength; + gpakWriteDspMemory(rh, DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Return with an indication the message was written. */ + return (1); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ReadDspReplyMessage - Read a DSP Reply message from DSP. + * + * FUNCTION + * This function reads a DSP Reply message from DSP memory. + * + * RETURNS + * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) + * 0 = No message available (DSP Reply message empty) + * 1 = Message read successfully (message and length stored in variables) + * + */ +static int ReadDspReplyMessage(struct r1t1 *rh, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMessage, /* pointer to Reply message buffer */ + DSP_WORD * pMsgLength /* pointer to msg length var (octets) */ + ) +{ + DSP_WORD MsgLength; /* message length */ + DSP_ADDRESS BufferPointer; /* message buffer pointer */ + DSP_WORD Temp[2]; + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rh, DspId) == -1) + return (-1); + + /* Check if a Reply message is ready. */ + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, &MsgLength); + if (MsgLength == 0) + return (0); + + /* Make sure the message length is valid. */ + if (MsgLength > *pMsgLength) + return (-1); + + /* Copy the Reply message from DSP memory. */ + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakReadDspMemory(rh, DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); + + /* Store the message length in the message length variable. */ + *pMsgLength = MsgLength; + + /* Indicate a Reply message is not ready. */ + MsgLength = 0; + gpakWriteDspMemory(rh, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, &MsgLength); + + /* Return with an indication the message was read. */ + return (1); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ReadCircBuffer - Read from a DSP circular buffer. + * + * FUNCTION + * This function reads a block of words from a DSP circular buffer. The Take + * address is incremented by the number of words read adjusting for buffer + * wrap. + * + * RETURNS + * nothing + * + */ +static void ReadCircBuffer(struct r1t1 *rh, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_ADDRESS BufrBaseAddress, /* address of base of circular buffer */ + DSP_ADDRESS BufrLastAddress, /* address of last word in buffer */ + DSP_ADDRESS * TakeAddress, /* pointer to address in buffer for read */ + DSP_WORD * pWordBuffer, /* pointer to buffer for words read */ + DSP_WORD NumWords /* number of words to read */ + ) +{ + DSP_WORD WordsTillEnd; /* number of words until end of buffer */ + + /* Determine the number of words from the start address until the end of the + buffer. */ + WordsTillEnd = BufrLastAddress - *TakeAddress + 1; + + /* If a buffer wrap will occur, read the first part at the end of the + buffer followed by the second part at the beginning of the buffer. */ + if (NumWords > WordsTillEnd) { + gpakReadDspMemory(rh, DspId, *TakeAddress, WordsTillEnd, pWordBuffer); + gpakReadDspMemory(rh, DspId, BufrBaseAddress, NumWords - WordsTillEnd, + &(pWordBuffer[WordsTillEnd])); + *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd; + } + + /* If a buffer wrap will not occur, read all words starting at the current + take address in the buffer. */ + else { + gpakReadDspMemory(rh, DspId, *TakeAddress, NumWords, pWordBuffer); + if (NumWords == WordsTillEnd) + *TakeAddress = BufrBaseAddress; + else + *TakeAddress = *TakeAddress + NumWords; + } + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * VerifyReply - Verify the reply message is correct for the command sent. + * + * FUNCTION + * This function verifies correct reply message content for the command that + * was just sent. + * + * RETURNS + * 0 = Incorrect + * 1 = Correct + * + */ +static int VerifyReply(DSP_WORD * pMsgBufr, /* pointer to Reply message buffer */ + int CheckType, /* reply check type */ + DSP_WORD CheckValue /* reply check value */ + ) +{ + + /* Verify Channel or Conference Id. */ + if (CheckType == 1) { + if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue) + return (0); + } + + /* Verify Test Mode Id. */ + else if (CheckType == 2) { + if (pMsgBufr[1] != CheckValue) + return (0); + } + + /* Return with an indication of correct reply. */ + return (1); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * TransactCmd - Send a command to the DSP and receive it's reply. + * + * FUNCTION + * This function sends the specified command to the DSP and receives the DSP's + * reply. + * + * RETURNS + * Length of reply message (0 = Failure) + * + */ +static unsigned int TransactCmd(struct r1t1 *rh, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMsgBufr, /* pointer to Cmd/Reply message buffer */ + DSP_WORD CmdLength, /* length of command message (octets) */ + DSP_WORD ReplyType, /* required type of reply message */ + DSP_WORD ReplyLength, /* required length of reply message (octets) */ + int ReplyCheckType, /* reply check type */ + DSP_WORD ReplyCheckValue /* reply check value */ + ) +{ + int FuncStatus; /* function status */ + int LoopCount; /* wait loop counter */ + DSP_WORD RcvReplyLength; /* received Reply message length */ + DSP_WORD RcvReplyType; /* received Reply message type code */ + DSP_WORD RetValue; /* return value */ + + /* Default the return value to indicate a failure. */ + RetValue = 0; + + /* Lock access to the DSP. */ + gpakLockAccess(rh, DspId); + + + /* Attempt to write the command message to the DSP. */ + LoopCount = 0; + while ((FuncStatus = WriteDspCmdMessage(rh, DspId, pMsgBufr, CmdLength)) != 1) { + if (FuncStatus == -1) + break; + if (++LoopCount > MAX_WAIT_LOOPS) + break; + gpakHostDelay(); + } + + /* Attempt to read the reply message from the DSP if the command message was + sent successfully. */ + if (FuncStatus == 1) { + for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++) { + RcvReplyLength = MSG_BUFFER_SIZE * 2; + FuncStatus = ReadDspReplyMessage(rh, DspId, pMsgBufr, &RcvReplyLength); + if (FuncStatus == 1) { + RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF; + if ((RcvReplyLength >= ReplyLength) && + (RcvReplyType == ReplyType) && + VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue)) { + RetValue = RcvReplyLength; + break; + } else if (RcvReplyType == MSG_NULL_REPLY) + break; + } else if (FuncStatus == -1) + break; + gpakHostDelay(); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rh, DspId); + + /* Return the length of the reply message (0 = failure). */ + return (RetValue); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakConfigurePorts - Configure a DSP's serial ports. + * + * FUNCTION + * This function configures a DSP's serial ports. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakConfigPortStatus_t gpakConfigurePorts(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + GpakPortConfig_t * pPortConfig, /* pointer to Port Config info */ + GPAK_PortConfigStat_t * pStatus /* pointer to Port Config Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (CpsInvalidDsp); + + /* Build the Configure Serial Ports message. */ + MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8; + MsgBuffer[1] = (DSP_WORD) + ((pPortConfig->SlotsSelect1 << 12) | + ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum1 << 4) & 0x00F0)); + MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1; + MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1; + MsgBuffer[4] = (DSP_WORD) + ((pPortConfig->SlotsSelect2 << 12) | + ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum2 << 4) & 0x00F0)); + MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2; + MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2; + MsgBuffer[7] = (DSP_WORD) + ((pPortConfig->SlotsSelect3 << 12) | + ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum3 << 4) & 0x00F0)); + MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3; + MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3; + + MsgBuffer[10] = (DSP_WORD) + (((pPortConfig->DxDelay1 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay1 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay1 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) | + ((pPortConfig->CompandingMode1 << 1) & 0x0006) | + (pPortConfig->SerialWordSize1 & 0x0001)); + + MsgBuffer[11] = (DSP_WORD) + (((pPortConfig->DxDelay2 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay2 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay2 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) | + ((pPortConfig->CompandingMode2 << 1) & 0x0006) | + (pPortConfig->SerialWordSize2 & 0x0001)); + + MsgBuffer[12] = (DSP_WORD) + (((pPortConfig->DxDelay3 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay3 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay3 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) | + ((pPortConfig->CompandingMode3 << 1) & 0x0006) | + (pPortConfig->SerialWordSize3 & 0x0001)); + + if (rh->dsp_type == DSP_5510) { + MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1; + MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1; + MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1; + MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1; + MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1; + MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1; + + MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;; + MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2; + MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;; + MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2; + MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;; + MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2; + + MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;; + MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3; + MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;; + MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3; + MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;; + MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3; + + /* Attempt to send the Configure Serial Ports message to the DSP and receive + it's reply. */ + if (!TransactCmd(rh, DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) + return (CpsDspCommFailure); + } + + else { + /* Attempt to send the Configure Serial Ports message to the DSP and receive + it's reply. */ + if (!TransactCmd(rh, DspId, MsgBuffer, 26, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) + return (CpsDspCommFailure); + } + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Pc_Success) + return (CpsSuccess); + else + return (CpsParmError); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakConfigureChannel - Configure a DSP's Channel. + * + * FUNCTION + * This function configures a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakConfigChanStatus_t gpakConfigureChannel(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ + GpakChanType ChannelType, /* Channel Type */ + GpakChannelConfig_t * pChanConfig, /* pointer to Channel Config info */ + GPAK_ChannelConfigStat_t * pStatus /* pointer to Channel Config Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD MsgLength; /* message length */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (CcsInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (CcsInvalidChannel); + + /* Build the Configure Channel message based on the Channel Type. */ + switch (ChannelType) { + + /* PCM to Packet channel type. */ + case tdmToTdm: + + MsgBuffer[2] = (DSP_WORD) + ((pChanConfig->PcmInPortA << 8) | (pChanConfig->PcmInSlotA & 0xFF)); + MsgBuffer[3] = (DSP_WORD) + ((pChanConfig->PcmOutPortA << 8) | (pChanConfig->PcmOutSlotA & 0xFF)); + + MsgBuffer[4] = (DSP_WORD) + ((pChanConfig->PcmInPortB << 8) | (pChanConfig->PcmInSlotB & 0xFF)); + MsgBuffer[5] = (DSP_WORD) + ((pChanConfig->PcmOutPortB << 8) | (pChanConfig->PcmOutSlotB & 0xFF)); + + if (rh->dsp_type == DSP_5510) { + MsgBuffer[6] = (DSP_WORD) + (((pChanConfig->FaxCngDetB << 11) & 0x0800) | + ((pChanConfig->FaxCngDetA << 10) & 0x0400) | + ((pChanConfig->MuteToneB << 9) & 0x0200) | + ((pChanConfig->MuteToneA << 8) & 0x0100) | + ((pChanConfig->FrameRate << 6) & 0x00C0) | + ((pChanConfig->ToneTypesB << 5) & 0x0020) | + ((pChanConfig->ToneTypesA << 4) & 0x0010) | + ((pChanConfig->SoftwareCompand & 3) << 2) | + (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1) + ); + } else { + MsgBuffer[6] = (DSP_WORD) + ((pChanConfig->FrameRate << 6) | + //((pChanConfig->ToneTypesB << 5) & 0x0020) | + //((pChanConfig->ToneTypesA << 4) & 0x0010) | + ((pChanConfig->SoftwareCompand & 3) << 2) | + (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1)); + } + + MsgBuffer[7] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanTapLength; + MsgBuffer[8] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpType; + MsgBuffer[9] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanAdaptEnable; + MsgBuffer[10] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanG165DetEnable; + MsgBuffer[11] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanDblTalkThresh; + MsgBuffer[12] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpThreshold; + MsgBuffer[13] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpConv; + MsgBuffer[14] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpUnConv; + MsgBuffer[15] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpMaxSuppress; + + MsgBuffer[16] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanCngThreshold; + MsgBuffer[17] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanAdaptLimit; + MsgBuffer[18] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanCrossCorrLimit; + MsgBuffer[19] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNumFirSegments; + MsgBuffer[20] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanFirSegmentLen; + + MsgBuffer[21] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanTapLength; + MsgBuffer[22] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpType; + MsgBuffer[23] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanAdaptEnable; + MsgBuffer[24] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanG165DetEnable; + MsgBuffer[25] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanDblTalkThresh; + MsgBuffer[26] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpThreshold; + MsgBuffer[27] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpConv; + MsgBuffer[28] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpUnConv; + MsgBuffer[29] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpMaxSuppress; + MsgBuffer[30] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanCngThreshold; + MsgBuffer[31] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanAdaptLimit; + MsgBuffer[32] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanCrossCorrLimit; + MsgBuffer[33] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNumFirSegments; + MsgBuffer[34] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanFirSegmentLen; + + MsgLength = 70; // byte number == 35*2 + break; + + + /* Unknown (invalid) channel type. */ + default: + *pStatus = Cc_InvalidChannelType; + return (CcsParmError); + } + + MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF)); + + /* Attempt to send the Configure Channel message to the DSP and receive it's + reply. */ + if (!TransactCmd(rh, DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (CcsDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Cc_Success) + return (CcsSuccess); + else + return (CcsParmError); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakTearDownChannel - Tear Down a DSP's Channel. + * + * FUNCTION + * This function tears down a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakTearDownStatus_t gpakTearDownChannel(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ + GPAK_TearDownChanStat_t * pStatus /* pointer to Tear Down Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (TdsInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (TdsInvalidChannel); + + /* Build the Tear Down Channel message. */ + MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8; + MsgBuffer[1] = (DSP_WORD) (ChannelId << 8); + + /* Attempt to send the Tear Down Channel message to the DSP and receive it's + reply. */ + if (!TransactCmd(rh, DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (TdsDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Td_Success) + return (TdsSuccess); + else + return (TdsError); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAlgControl - Control an Algorithm. + * + * FUNCTION + * This function controls an Algorithm + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakAlgControlStat_t gpakAlgControl(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakAlgCtrl_t ControlCode, // algorithm control code + GPAK_AlgControlStat_t * pStatus // pointer to return status + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (AcInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (AcInvalidChannel); + + MsgBuffer[0] = MSG_ALG_CONTROL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF)); + +// printk("R1T1 %d: Alg control Chan %d Control code %d\n", rh->num+1 , ChannelId, ControlCode); + + /* Attempt to send the Tear Down Channel message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rh, DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (AcDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Ac_Success) + return (AcSuccess); + else + return (AcParmError); + +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadEventFIFOMessage - read from the event fifo + * + * FUNCTION + * This function reads a single event from the event fifo if one is available + * + * RETURNS + * Status code indicating success or a specific error. + * + * Notes: This function should be called in a loop until the return status + * indicates that the fifo is empty. + * + * If the event code equals "EventLoopbackTeardownComplete", then the + * contents of *pChannelId hold the coderBlockId that was assigned to + * the loopback coder that was torn down. + */ +gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(struct r1t1 * rh, // Card containing the DSP + unsigned short int DspId, // DSP identifier + unsigned short int *pChannelId, // pointer to channel identifier + GpakAsyncEventCode_t * pEventCode, // pointer to Event Code + GpakAsyncEventData_t * pEventData // pointer to Event Data Struct + ) +{ + DSP_WORD WordBuffer[WORD_BUFFER_SIZE]; /* DSP words buffer */ + GpakAsyncEventCode_t EventCode; /* DSP's event code */ + DSP_WORD EventDataLength; /* Length of event to read */ + DSP_WORD ChannelId; /* DSP's channel Id */ + DSP_ADDRESS EventInfoAddress; /* address of EventFIFO info structure */ + DSP_ADDRESS BufrBaseAddress; /* base address of EventFIFO buffer */ + DSP_ADDRESS BufrLastAddress; /* last address of EventFIFO buffer */ + DSP_ADDRESS TakeAddress; /* current take address in fifo buffer */ + DSP_WORD BufrSize; /* size (in words) of event FIFO buffer */ + DSP_WORD PutIndex; /* event fifo put index */ + DSP_WORD TakeIndex; /* event fifo take index */ + DSP_WORD WordsReady; /* number words ready for read out of event fifo */ + DSP_WORD EventError; /* flag indicating error with event fifo msg */ +// DSP_WORD *pDebugData; /* debug data buffer pointer in event data struct */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RefInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rh, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rh, DspId) == -1) { + gpakUnlockAccess(rh, DspId); + return (RefDspCommFailure); + } + + /* Check if an event message is ready in the DSP. */ + EventInfoAddress = pEventFifoAddress[DspId]; + gpakReadDspMemory(rh, DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE, + WordBuffer); + RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *) & WordBuffer[CB_BUFR_BASE])); + BufrSize = WordBuffer[CB_BUFR_SIZE]; + PutIndex = WordBuffer[CB_BUFR_PUT_INDEX]; + TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX]; + if (PutIndex >= TakeIndex) + WordsReady = PutIndex - TakeIndex; + else + WordsReady = PutIndex + BufrSize - TakeIndex; + + if (WordsReady < 2) { + gpakUnlockAccess(rh, DspId); + return (RefNoEventAvail); + } + + /* Read the event header from the DSP's Event FIFO. */ + TakeAddress = BufrBaseAddress + TakeIndex; + BufrLastAddress = BufrBaseAddress + BufrSize - 1; + ReadCircBuffer(rh, DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, + WordBuffer, 2); + TakeIndex += 2; + if (TakeIndex >= BufrSize) + TakeIndex -= BufrSize; + + ChannelId = (WordBuffer[0] >> 8) & 0xFF; + EventCode = (GpakAsyncEventCode_t) (WordBuffer[0] & 0xFF); + EventDataLength = WordBuffer[1]; + EventError = 0; + + switch (EventCode) { + case EventToneDetect: + if (EventDataLength > WORD_BUFFER_SIZE) { + gpakUnlockAccess(rh, DspId); + return (RefInvalidEvent); + } + ReadCircBuffer(rh, DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, + WordBuffer, EventDataLength); + pEventData->toneEvent.ToneCode = (GpakToneCodes_t) + (WordBuffer[0] & 0xFF); + pEventData->toneEvent.ToneDuration = WordBuffer[1]; + pEventData->toneEvent.Direction = WordBuffer[2]; + pEventData->toneEvent.DebugToneStatus = WordBuffer[3]; + TakeIndex += EventDataLength; + if (TakeIndex >= BufrSize) + TakeIndex -= BufrSize; + if (EventDataLength != 4) + EventError = 1; + break; + + default: + EventError = 1; + break; + }; + + /* Update the Take index in the DSP's Packet Out buffer information. */ + gpakWriteDspMemory(rh, DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1, &TakeIndex); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rh, DspId); + + if (EventError) + return (RefInvalidEvent); + + *pChannelId = ChannelId; + *pEventCode = EventCode; + return (RefEventAvail); + +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakPingDsp - ping the DSP to see if it's alive + * + * FUNCTION + * This function checks if the DSP is still communicating with the host + * and returns the DSP SW version + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakPingDspStat_t gpakPingDsp(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pDspSwVersion // DSP software version + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + //printk("pDspIfBlk = %x, MaxCmdMsgLen = %x, MaxChannels = %x\n",pDspIfBlk[0], MaxCmdMsgLen[0], MaxChannels[0]); + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (PngInvalidDsp); + + /* send value of 1, DSP increments it */ + MsgBuffer[0] = (MSG_PING << 8); + + /* Attempt to send the ping message to the DSP and receive it's + reply. */ + if (!TransactCmd(rh, DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0)) + return (PngDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) { + *pDspSwVersion = MsgBuffer[2]; + return (PngSuccess); + } else + return (PngDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakSerialTxFixedValue - transmit a fixed value on a timeslot + * + * FUNCTION + * This function controls transmission of a fixed value out onto a serial + * port's timeslot. + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id + unsigned short int PcmOutSlot, // PCM Output Time Slot + unsigned short int Value, // 16-bit value + GpakActivation State // activation state + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (TfvInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (TfvInvalidChannel); + + + /* Build the message. */ + MsgBuffer[0] = MSG_SERIAL_TXVAL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF)); + MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF)); + MsgBuffer[3] = (DSP_WORD) Value; + + /* Attempt to send the message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rh, DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4, 1, ChannelId)) + return (TfvDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (TfvSuccess); + else + return (TfvDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakControlTdmLoopBack - control a serial port's loopback state + * + * FUNCTION + * This function enables/disables the tdm input to output looback mode on a + * serial port + * + * RETURNS + * Status code indicating success or a specific error. + */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakSerialPort_t SerialPort, // Serial Port Id + GpakActivation LoopBackState // Loopback State + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (ClbInvalidDsp); + + /* Build the message. */ + MsgBuffer[0] = MSG_TDM_LOOPBACK << 8; + MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF)); + + /* Attempt to send the message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rh, DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0)) + return (ClbDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (ClbSuccess); + else + return (ClbDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - Read CPU usage statistics from a DSP. + * + * FUNCTION + * This function reads the CPU usage statistics from a DSP's memory. The + * average CPU usage in units of .1 percent are obtained for each of the frame + * rates. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadCpuUsageStat_t gpakReadCpuUsage(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, // Dsp Identifier + unsigned short int *pPeakUsage, // pointer to peak usage variable + unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second + ) +{ + DSP_WORD ReadBuffer[2]; /* DSP read buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RcuInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rh, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rh, DspId) == -1) + return (RcuDspCommFailure); + + /* Read the CPU Usage statistics from the DSP. */ + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2, ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rh, DspId); + + /* Store the usage statistics in the specified variables. */ + *pPrev1SecPeakUsage = ReadBuffer[0]; + *pPeakUsage = ReadBuffer[1]; + + /* Return with an indication the usage staistics were read successfully. */ + return (RcuSuccess); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetCpuUsageStats - reset the cpu usage statistics + * + * FUNCTION + * This function resets the cpu utilization statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakResetCpuUsageStat_t gpakResetCpuUsageStats(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RstcInvalidDsp); + + MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8); + + /* Attempt to send the message to the DSP and receive it's reply. */ + //need_reply_len; + if (!TransactCmd(rh, DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0)) + return (RstcDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (RstcSuccess); + else + return (RstcDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFramingStats + * + * FUNCTION + * This function reads a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakReadFramingStatsStatus_t gpakReadFramingStats(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pFramingError1Count, // port 1 Framing error count + unsigned short int *pFramingError2Count, // port 2 Framing error count + unsigned short int *pFramingError3Count, // port 3 Framing error count + unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count + unsigned short int *pDmaSlipStatsBuffer // DMA slips count + ) +{ + DSP_WORD ReadBuffer[10]; /* DSP read buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RfsInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rh, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rh, DspId) == -1) + return (RfsDspCommFailure); + + /* Read the framing interrupt statistics from the DSP. */ + if (rh->dsp_type == DSP_5510) + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10, + ReadBuffer); + else + gpakReadDspMemory(rh, DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 4, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rh, DspId); + + /* Store the framing statistics in the specified variables. */ + *pFramingError1Count = ReadBuffer[0]; + *pFramingError2Count = ReadBuffer[1]; + *pFramingError3Count = ReadBuffer[2]; + *pDmaStopErrorCount = ReadBuffer[3]; + + if ((pDmaSlipStatsBuffer != 0) && (rh->dsp_type == DSP_5510)) + // If users want to get the DMA slips count + { + pDmaSlipStatsBuffer[0] = ReadBuffer[4]; + pDmaSlipStatsBuffer[1] = ReadBuffer[5]; + pDmaSlipStatsBuffer[2] = ReadBuffer[6]; + pDmaSlipStatsBuffer[3] = ReadBuffer[7]; + pDmaSlipStatsBuffer[4] = ReadBuffer[8]; + pDmaSlipStatsBuffer[5] = ReadBuffer[9]; + + } + + /* Return with an indication the statistics were read successfully. */ + return (RfsSuccess); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - reset a DSP's framing interrupt statistics + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakResetFramingStatsStatus_t gpakResetFramingStats(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RstfInvalidDsp); + + MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8); + + /* Attempt to send the message to the DSP and receive it's reply. */ + //need_reply_len; + if (!TransactCmd(rh, DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0)) + return (RstfDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (RstfSuccess); + else + return (RstfDspCommFailure); +} + +/* + * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. + * + * FUNCTION + * This function reads a DSP's Program and Data memory image from the + * specified file and writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakDownloadStatus_t gpakDownloadDsp_5510(struct r1t1 * rh, /* Card containing the DSP */ + unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Download File Identifier */ + ) +{ + gpakDownloadStatus_t RetStatus; /* function return status */ + int NumRead; /* number of file bytes read */ + DSP_ADDRESS Address; /* DSP address */ + unsigned int WordCount; /* number of words in record */ + unsigned int NumWords; /* number of words to read/write */ + unsigned int i; /* loop index / counter */ + unsigned int j; /* loop index */ + unsigned int check_count; /* # of failed checks */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (GdlInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rh, DspId); + + RetStatus = GdlSuccess; + while (RetStatus == GdlSuccess) { + + /* Read a record header from the file. */ + NumRead = gpakReadFile_5510(rh, FileId, DlByteBufr, 6); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != 6) { + RetStatus = GdlInvalidFile; + break; + } + Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) | + (((DSP_ADDRESS) DlByteBufr[2]) << 8) | ((DSP_ADDRESS) DlByteBufr[3]); + WordCount = (((unsigned int) DlByteBufr[4]) << 8) | + ((unsigned int) DlByteBufr[5]); + + /* Check for the End Of File record. */ + if (DlByteBufr[0] == 0xFF) + break; + + /* Verify the record is for a valid memory type. */ + if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01)) { + RetStatus = GdlInvalidFile; + break; + } + + /* Read a block of words at a time from the file and write to the + DSP's memory . */ + while (WordCount != 0) { + if (WordCount < DOWNLOAD_BLOCK_SIZE) + NumWords = WordCount; + else + NumWords = DOWNLOAD_BLOCK_SIZE; + WordCount -= NumWords; + NumRead = gpakReadFile_5510(rh, FileId, DlByteBufr, NumWords * 2); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != (NumWords * 2)) { + RetStatus = GdlInvalidFile; + break; + } + for (i = 0, j = 0; i < NumWords; i++, j += 2) + DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) | + ((DSP_WORD) DlByteBufr[j + 1]); + + check_count = 0; + + while (check_count < 4) { + gpakWriteDspMemory(rh, DspId, Address, NumWords, DlWordBufr); + gpakReadDspMemory(rh, DspId, Address, NumWords, DlWordChek); + + if (memcmp(DlWordBufr, DlWordChek, NumWords) == 0) + break; + else + check_count++; + } + + if (check_count) { + if (check_count == 4) { + RetStatus = GdlDspCommFailure; + printk("Failure to load DSP @ Address 0x%08x\n", Address); + } + } + + Address += ((DSP_ADDRESS) NumWords); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rh, DspId); + + /* Return with an indication of success or failure. */ + return (RetStatus); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - Read CPU usage statistics from a DSP. + * + * FUNCTION + * This function reads the memory map register section of DSP memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(struct r1t1 * rh, // Card containing the DSP + unsigned short int DspId, // Dsp Identifier + unsigned short int *pDest, // Buffer on host to hold DSP memory map + DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out + unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP reply's status */ + int i; /* loop index / counter */ + + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RmmInvalidDsp); + + /* Verify the message buffer is large enough */ + if (MSG_BUFFER_SIZE < MemoryLength_Word16) + return (RmmSizeTooBig); + + MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8; + MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF); + MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF); + MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16; + + /* Attempt to send the Read memory section message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rh, DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY, + (MemoryLength_Word16 + 2) * 2, 0, 0)) + return (RmmInvalidAddress); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus != 0) + return (RmmFailure); + + for (i = 0; i < MemoryLength_Word16; i++) + pDest[i] = (short int) MsgBuffer[2 + i]; + + + return (RmmSuccess); +} diff --git drivers/dahdi/rhino/r1t1/GpakApi.h drivers/dahdi/rhino/r1t1/GpakApi.h new file mode 100644 index 0000000..1aa515d --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakApi.h @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2005 , Adaptive Digital Technologies, Inc. + * + * File Name: GpakApi.h + * + * Description: + * This file contains the function prototypes and data types for the user + * API functions that communicate with DSPs executing G.PAK software. The + * file is used by application software in the host processor connected to + * C55X G.PAK DSPs via a Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * 11/15/2006 - 24 TDM-TDM Channels EC release + */ + +#ifndef _GPAKAPI_H /* prevent multiple inclusion */ +#define _GPAKAPI_H +#include "GpakErrs.h" +#include "gpakenum.h" +#include "r1t1.h" + +typedef unsigned long int GPAK_FILE_ID; /* G.PAK Download file identifier */ + +#define BL_DSP_BOOTLOADER_ENTRY 0x7020 /* DSP bootloader entry-point, */ + /* HOST have to put this address in 0x60-61 */ + /* after DSP bootloader bin file downloaded */ + +typedef unsigned short int DSP_WORD; /* 16 bit DSP word */ +typedef unsigned int DSP_ADDRESS; /* 32 bit DSP address */ +//typedef unsigned long int DSP_ADDRESS; /* 32 bit DSP address */ + +#define DSP_DEBUG_BUFF_SIZE 42 // units of 16-bit words + +/* Definition of an Asynchronous Event Data Structure */ + +typedef union { + struct { + GpakToneCodes_t ToneCode; // detected tone code + unsigned short int ToneDuration; // tone duration + GpakTdmDirection Direction; // detected on A r B side + short int DebugToneStatus; // reserved for debug info + } toneEvent; + +} GpakAsyncEventData_t; + +/* Definition of an Echo Canceller Parameters information structure. */ + +typedef struct { + short int EcanTapLength; // Echo Can Num Taps (tail length) + short int EcanNlpType; // Echo Can NLP Type + short int EcanAdaptEnable; // Echo Can Adapt Enable flag + short int EcanG165DetEnable; // Echo Can G165 Detect Enable flag + short int EcanDblTalkThresh; // Echo Can Double Talk threshold + short int EcanNlpThreshold; // Echo Can NLP threshold + short int EcanNlpConv; // Dynamic NLP control, NLP limit when EC about to converged + short int EcanNlpUnConv; // Dynamic NLP control, NLP limit when EC not converged yet + short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode + short int EcanCngThreshold; // Echo Can CNG Noise threshold + short int EcanAdaptLimit; // Echo Can Max Adapts per frame + short int EcanCrossCorrLimit; // Echo Can Cross Correlation limit + short int EcanNumFirSegments; // Echo Can Num FIR Segments + short int EcanFirSegmentLen; // Echo Can FIR Segment Length +} GpakEcanParms_t; + +/* Definition of a Channel Configuration information structure. */ + +typedef struct { + GpakSerialPort_t PcmInPortA; // A side PCM Input Serial Port Id + unsigned short int PcmInSlotA; // A side PCM Input Time Slot + GpakSerialPort_t PcmOutPortA; // A side PCM Output Serial Port Id + unsigned short int PcmOutSlotA; // A side PCM Output Time Slot + GpakSerialPort_t PcmInPortB; // B side PCM Input Serial Port Id + unsigned short int PcmInSlotB; // B side PCM Input Time Slot + GpakSerialPort_t PcmOutPortB; // B side PCM Output Serial Port Id + unsigned short int PcmOutSlotB; // B side PCM Output Time Slot + GpakToneTypes ToneTypesA; // A side Tone Detect Types + GpakToneTypes ToneTypesB; // B side Tone Detect Types + GpakActivation EcanEnableA; // Echo Cancel A Enabled + GpakActivation EcanEnableB; // Echo Cancel B Enabled + GpakEcanParms_t EcanParametersA; // Echo Cancel parameters + GpakEcanParms_t EcanParametersB; // Echo Cancel parameters + GpakCompandModes SoftwareCompand; // software companding + GpakRate_t FrameRate; // Gpak Frame Rate + GpakActivation MuteToneA; // A side mute DTMF Enabled + GpakActivation MuteToneB; // B side mute DTMF Enabled + GpakActivation FaxCngDetA; // A side FaxCng Tone Detector Enabled + GpakActivation FaxCngDetB; // B side FaxCng Tone Detector Enabled + +} GpakChannelConfig_t; + + +/* Definition of a Serial Port Configuration Structure */ +typedef struct { + GpakSlotCfg_t SlotsSelect1; // port 1 Slot selection + unsigned short int FirstBlockNum1; // port 1 first group Block Number + unsigned short int FirstSlotMask1; // port 1 first group Slot Mask + unsigned short int SecBlockNum1; // port 1 second group Block Number + unsigned short int SecSlotMask1; // port 1 second group Slot Mask + + GpakSerWordSize_t SerialWordSize1; // port 1 serial word size + GpakCompandModes CompandingMode1; // port 1 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity1; // port 1 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity1; // port 1 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay1; // port 1 Tx data delay + GpakSerDataDelay_t RxDataDelay1; // port 1 Rx data delay + GpakActivation DxDelay1; // port 1 DX Delay + + unsigned short int ThirdSlotMask1; // port 1 3rd group Slot Mask + unsigned short int FouthSlotMask1; // port 1 4th group Slot Mask + unsigned short int FifthSlotMask1; // port 1 5th group Slot Mask + unsigned short int SixthSlotMask1; // port 1 6th group Slot Mask + unsigned short int SevenSlotMask1; // port 1 7th group Slot Mask + unsigned short int EightSlotMask1; // port 1 8th group Slot Mask + + + GpakSlotCfg_t SlotsSelect2; // port 2 Slot selection + unsigned short int FirstBlockNum2; // port 2 first group Block Number + unsigned short int FirstSlotMask2; // port 2 first group Slot Mask + unsigned short int SecBlockNum2; // port 2 second group Block Number + unsigned short int SecSlotMask2; // port 2 second group Slot Mask + GpakSerWordSize_t SerialWordSize2; // port 2 serial word size + GpakCompandModes CompandingMode2; // port 2 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity2; // port 2 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity2; // port 2 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay2; // port 2 Tx data delay + GpakSerDataDelay_t RxDataDelay2; // port 2 Rx data delay + GpakActivation DxDelay2; // port 2 DX Delay + + unsigned short int ThirdSlotMask2; // port 2 3rd group Slot Mask + unsigned short int FouthSlotMask2; // port 2 4th group Slot Mask + unsigned short int FifthSlotMask2; // port 2 5th group Slot Mask + unsigned short int SixthSlotMask2; // port 2 6th group Slot Mask + unsigned short int SevenSlotMask2; // port 2 7th group Slot Mask + unsigned short int EightSlotMask2; // port 2 8th group Slot Mask + + GpakSlotCfg_t SlotsSelect3; // port 3 Slot selection + unsigned short int FirstBlockNum3; // port 3 first group Block Number + unsigned short int FirstSlotMask3; // port 3 first group Slot Mask + unsigned short int SecBlockNum3; // port 3 second group Block Number + unsigned short int SecSlotMask3; // port 3 second group Slot Mask + GpakSerWordSize_t SerialWordSize3; // port 3 serial word size + GpakCompandModes CompandingMode3; // port 3 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity3; // port 3 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity3; // port 3 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay3; // port 3 Tx data delay + GpakSerDataDelay_t RxDataDelay3; // port 3 Rx data delay + GpakActivation DxDelay3; // port 3 DX Delay + + unsigned short int ThirdSlotMask3; // port 3 3rd group Slot Mask + unsigned short int FouthSlotMask3; // port 3 4th group Slot Mask + unsigned short int FifthSlotMask3; // port 3 5th group Slot Mask + unsigned short int SixthSlotMask3; // port 3 6th group Slot Mask + unsigned short int SevenSlotMask3; // port 3 7th group Slot Mask + unsigned short int EightSlotMask3; // port 3 8th group Slot Mask + +} GpakPortConfig_t; + +/* Definition of a Tone Generation Parameter Structure */ +/* +typedef struct +{ + GpakToneGenType_t ToneType; // Tone Type + unsigned short int Frequency[4]; // Frequency (Hz) + short int Level[4]; // Frequency's Level (1 dBm) + unsigned short int OnTime[4]; // On Times (msecs) + unsigned short int OffTime[4]; // Off Times (msecs) +} GpakToneGenParms_t; +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakConfigureChannel return status. */ +typedef enum { + CcsSuccess = 0, /* Channel Configured successfully */ + CcsParmError = 1, /* Channel Config Parameter error */ + CcsInvalidChannel = 2, /* invalid channel */ + CcsInvalidDsp = 3, /* invalid DSP */ + CcsDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakConfigChanStatus_t; + +/* + * gpakConfigureChannel - Configure a DSP's Channel. + * + * FUNCTION + * This function configures a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakConfigChanStatus_t gpakConfigureChannel(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakChanType ChannelType, // channel type + GpakChannelConfig_t * pChanConfig, // pointer to channel config info + GPAK_ChannelConfigStat_t * pStatus // pointer to Channel Config Status + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakTearDownChannel return status. */ +typedef enum { + TdsSuccess = 0, /* Channel Tear Down successful */ + TdsError = 1, /* Channel Tear Down error */ + TdsInvalidChannel = 2, /* invalid channel */ + TdsInvalidDsp = 3, /* invalid DSP */ + TdsDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakTearDownStatus_t; + +/* + * gpakTearDownChannel - Tear Down a DSP's Channel. + * + * FUNCTION + * This function tears down a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +extern gpakTearDownStatus_t gpakTearDownChannel(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GPAK_TearDownChanStat_t * pStatus // pointer to Tear Down Status + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakAlgControl return status. */ +typedef enum { + AcSuccess = 0, /* control successful */ + AcInvalidChannel = 1, /* invalid channel identifier */ + AcInvalidDsp = 2, /* invalid DSP */ + AcParmError = 3, /* invalid control parameter */ + AcDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakAlgControlStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAlgControl - Control an Algorithm. + * + * FUNCTION + * This function controls an Algorithm + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakAlgControlStat_t gpakAlgControl(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakAlgCtrl_t ControlCode, // algorithm control code + GPAK_AlgControlStat_t * pStatus // pointer to return status + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakConfigurePorts return status. */ +typedef enum { + CpsSuccess = 0, /* Serial Ports configured successfully */ + CpsParmError = 1, /* Configure Ports Parameter error */ + CpsInvalidDsp = 2, /* invalid DSP */ + CpsDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakConfigPortStatus_t; + +/* + * gpakConfigurePorts - Configure a DSP's serial ports. + * + * FUNCTION + * This function configures a DSP's serial ports. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakConfigPortStatus_t gpakConfigurePorts(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakPortConfig_t * pPortConfig, // pointer to Port Config info + GPAK_PortConfigStat_t * pStatus // pointer to Port Config Status + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakDownloadDsp return status. */ +typedef enum { + GdlSuccess = 0, /* DSP download successful */ + GdlFileReadError = 1, /* error reading Download file */ + GdlInvalidFile = 2, /* invalid Download file content */ + GdlInvalidDsp = 3, /* invalid DSP */ + GdlDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakDownloadStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakDownloadLoader - Download the DSP's Loader program. + * + * FUNCTION + * This function reads the DSP's Loader program from the specified file and + * writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +extern gpakDownloadStatus_t gpakDownloadLoader(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Loader program File Identifier */ + ); + +/* + * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. + * + * FUNCTION + * This function reads a DSP's Program and Data memory image from the + * specified file and writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakDownloadStatus_t gpakDownloadDsp_5510(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GPAK_FILE_ID FileId // G.PAK download file identifier + ); + +extern gpakDownloadStatus_t gpakDownloadDsp_5507(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GPAK_FILE_ID FileId // G.PAK download file identifier + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakReadEventFIFOMessage return status */ +typedef enum { + RefEventAvail = 0, /* an event was successfully read from the fifo */ + RefNoEventAvail = 1, /* no event was in the fifo */ + RefInvalidDsp = 2, /* invalid DSP identifier */ + RefInvalidEvent = 3, /* invalid event */ + RefDspCommFailure = 4 /* error communicating with DSP */ +} gpakReadEventFIFOMessageStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadEventFIFOMessage - read from the event fifo + * + * FUNCTION + * This function reads a single event from the event fifo if one is available + * + * RETURNS + * Status code indicating success or a specific error. + * + * Note: This function should be called in a loop until the return status + * indicates that the fifo is empty. + */ +extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(struct r1t1 *rh, // Card containing the DSP + unsigned short int DspId, // DSP identifier + unsigned short int *pChannelId, // pointer to channel identifier + GpakAsyncEventCode_t * pEventCode, // pointer to Event Code + GpakAsyncEventData_t * pEventData // pointer to Event Data Struct + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakPingDsp return status values */ +typedef enum { + PngSuccess = 0, /* DSP responded successfully */ + PngInvalidDsp = 1, /* invalid DSP identifier */ + PngDspCommFailure = 2 /* error communicating with DSP */ +} gpakPingDspStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakPingDsp - ping the DSP to see if it's alive + * + * FUNCTION + * This function checks if the DSP is still communicating with the host + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakPingDspStat_t gpakPingDsp(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pDspSwVersion // DSP software version + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakSerialTxFixedValue return status values */ +typedef enum { + TfvSuccess = 0, /* operation successful */ + TfvInvalidChannel = 1, /* invalid channel identifier */ + TfvInvalidDsp = 2, /* invalid DSP identifier */ + TfvDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakSerialTxFixedValueStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakSerialTxFixedValue - transmit a fixed value on a timeslot + * + * FUNCTION + * This function controls transmission of a fixed value out onto a serial + * port's timeslot. + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id + unsigned short int PcmOutSlot, // PCM Output Time Slot + unsigned short int Value, // 16-bit value + GpakActivation State // activation state + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakControlTdmLoopBack return status values */ +typedef enum { + ClbSuccess = 0, /* operation successful */ + ClbSerPortInactive = 1, /* serial port is inactive */ + ClbInvalidDsp = 2, /* invalid DSP identifier */ + ClbDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakControlTdmLoopBackStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakControlTdmLoopBack - control a serial port's loopback state + * + * FUNCTION + * This function enables/disables the tdm input to output looback mode on a + * serial port + * + * RETURNS + * Status code indicating success or a specific error. + */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakSerialPort_t SerialPort, // Serial Port Id + GpakActivation LoopBackState // Loopback State + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakReadCpuUsage return status values */ +typedef enum { + RcuSuccess = 0, /* operation successful */ + RcuInvalidDsp = 1, /* invalid DSP identifier */ + RcuDspCommFailure = 2 /* communication failure */ +} gpakReadCpuUsageStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - read the cpu usage statistics + * + * FUNCTION + * This function reads cpu utilization from the DSP. + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakReadCpuUsageStat_t gpakReadCpuUsage(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pPeakUsage, // pointer to peak usage variable + unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakResetCpuUsageStats return status values */ +typedef enum { + RstcSuccess = 0, /* operation successful */ + RstcInvalidDsp = 1, /* invalid DSP identifier */ + RstcDspCommFailure = 2 /* communication failure */ +} gpakResetCpuUsageStat_t; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetCpuUsageStats - reset the cpu usage statistics + * + * FUNCTION + * This function resets the cpu utilization statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakReadFramingStats return status values */ +typedef enum { + RfsSuccess = 0, /* operation successful */ + RfsInvalidDsp = 1, /* invalid DSP identifier */ + RfsDspCommFailure = 2 /* communication failure */ +} gpakReadFramingStatsStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFramingStats + * + * FUNCTION + * This function reads a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakReadFramingStatsStatus_t gpakReadFramingStats(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pFramingError1Count, // port 1 Framing error count + unsigned short int *pFramingError2Count, // port 2 Framing error count + unsigned short int *pFramingError3Count, // port 3 Framing error count + unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count + unsigned short int *pDmaSlipStatsBuffer // DMA slips count + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakResetFramingStats return values */ +typedef enum { + RstfSuccess = 0, /* operation successful */ + RstfInvalidDsp = 1, /* invalid DSP identifier */ + RstfDspCommFailure = 2 /* communication failure */ +} gpakResetFramingStatsStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - reset a DSP's framing interrupt statistics + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakResetFramingStatsStatus_t gpakResetFramingStats(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ); + + +typedef enum { + RmmSuccess = 0, + RmmInvalidDsp = 1, + RmmSizeTooBig = 2, + RmmFailure = 3, + RmmInvalidAddress = 4 +} gpakReadDSPMemoryStat_t; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - read a section of DSP memory + * to get access DSP registers, since 0x00--0x60 not HPI-accessable + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ + +extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(struct r1t1 *rh, // Card containing the DSP + unsigned short int DspId, // Dsp Identifier + unsigned short int *pDest, // Buffer on host to hold DSP memory map + DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out + unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word + ); + +#endif // end multiple inclusion diff --git drivers/dahdi/rhino/r1t1/GpakCust.c drivers/dahdi/rhino/r1t1/GpakCust.c new file mode 100644 index 0000000..d206303 --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakCust.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakCust.c + * + * Description: + * This file contains host system dependent functions to support generic + * G.PAK API functions. The file is integrated into the host processor + * connected to C55x G.PAK DSPs via a Host Port Interface. + * + * Note: This file needs to be modified by the G.PAK system integrator. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + +#include "GpakCust.h" +#include "r1t1.h" +#include + +void __r1t1_card_wait_hpi(struct r1t1 *rh, __u8 flags) +{ + __u8 temp; + int loops; + int bus_sel; + + bus_sel = (HPI_SEL | DSP_RST) & __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC); + if (bus_sel != (HPI_SEL | DSP_RST)) + printk("r1t1: Locking Error %x\n", bus_sel); + + if (!(rh->hpi_fast)) { + temp = (__u8) (__r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIRDX_STAT) >> 16); + for (loops = 0; loops < 200; loops++) { + temp = (__u8) (__r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIRDX_STAT) >> 16); + + if ((temp & flags) == flags) { + return; + } + } + } + return; +} + +void __r1t1_card_hpic_set(struct r1t1 *rh, __u16 hpic_data) +{ + __r1t1_card_pci_out(rh, R1T1_DSP_HPIC + TARG_REGS, (__u32) (hpic_data)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); +} + +void r1t1_card_hpic_set(struct r1t1 *rh, __u16 hpic_data) +{ + unsigned int hpi_lock; + hpi_lock = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, + ((hpi_lock & ~0x1F) | HPI_SEL | DSP_RST)); + __r1t1_card_hpic_set(rh, hpic_data); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, hpi_lock); +} + +void r1t1_card_dsp_set(struct r1t1 *rh, __u32 dsp_address, __u16 dsp_data) +{ + __u32 u_nib; + unsigned int hpi_lock; + unsigned long flags; + + spin_lock_irqsave(&rh->lock, flags); + hpi_lock = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, + ((hpi_lock & ~0x1F) | HPI_SEL | DSP_RST)); + + if (rh->dsp_type == DSP_5510) { + u_nib = ((dsp_address & 0xf0000) >> 16); + if (!(rh->hpi_xadd == u_nib)) { + + rh->hpi_xadd = u_nib; + + __r1t1_card_pci_out(rh, R1T1_DSP_HPIC + TARG_REGS, (__u32) (R1T1_XADD)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + __r1t1_card_pci_out(rh, R1T1_HPIA + TARG_REGS, (__u32) (u_nib)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + __r1t1_card_pci_out(rh, R1T1_DSP_HPIC + TARG_REGS, (__u32) (0)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + + } + } + + __r1t1_card_pci_out(rh, R1T1_HPIA + TARG_REGS, (__u32) (dsp_address)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + + __r1t1_card_pci_out(rh, R1T1_HPID + TARG_REGS, (__u32) (dsp_data)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, hpi_lock); + + spin_unlock_irqrestore(&rh->lock, flags); + + return; +} + +__u16 r1t1_card_dsp_get(struct r1t1 * rh, __u32 dsp_address) +{ + __u32 dsp_data; + __u32 u_nib; + unsigned int hpi_lock; + unsigned long flags; + + spin_lock_irqsave(&rh->lock, flags); + + hpi_lock = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, + ((hpi_lock & ~0x1F) | HPI_SEL | DSP_RST)); + + if (rh->dsp_type == DSP_5510) { + + u_nib = ((dsp_address & 0xf0000) >> 16); + + if (!(rh->hpi_xadd == u_nib)) { + rh->hpi_xadd = u_nib; + + __r1t1_card_pci_out(rh, R1T1_DSP_HPIC + TARG_REGS, (__u32) (R1T1_XADD)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + __r1t1_card_pci_out(rh, R1T1_HPIA + TARG_REGS, (__u32) (u_nib)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + __r1t1_card_pci_out(rh, R1T1_DSP_HPIC + TARG_REGS, (__u32) (0)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + + } + } + + __r1t1_card_pci_out(rh, R1T1_HPIA + TARG_REGS, (__u32) (dsp_address)); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + dsp_data = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPID); + __r1t1_card_wait_hpi(rh, R1T1_HRDY); + dsp_data = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIRDX); + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, hpi_lock); + + spin_unlock_irqrestore(&rh->lock, flags); + + return (__u16) dsp_data; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadDspMemory - Read DSP memory. + * + * FUNCTION + * This function reads a contiguous block of words from DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +void gpakReadDspMemory(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to read */ + DSP_WORD * pWordValues /* pointer to array of word values variable */ + ) +{ + + unsigned int word_num; + + if (!rh) { + printk("r1t1: gpakReadDspMemory: No iface exists for DSP number %d\n", DspId); + return; + } + + /* read NumWords from auto increment data register */ + for (word_num = 0; word_num < NumWords; word_num++) { + pWordValues[word_num] = r1t1_card_dsp_get(rh, DspAddress + word_num); + } + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteDspMemory - Write DSP memory. + * + * FUNCTION + * This function writes a contiguous block of words to DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +void gpakWriteDspMemory(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to write */ + DSP_WORD * pWordValues /* pointer to array of word values to write */ + ) +{ + + unsigned int word_num; + + if (!rh) { + printk("r1t1: gpakWriteDspMemory: No iface exists for DSP number %d\n", DspId); + return; + } + + /* read NumWords from auto increment data register */ + for (word_num = 0; word_num < NumWords; word_num++) { + r1t1_card_dsp_set(rh, DspAddress + word_num, pWordValues[word_num]); + } + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakHostDelay - Delay for a fixed time interval. + * + * FUNCTION + * This function delays for a fixed time interval before returning. The time + * interval is the Host Port Interface sampling period when polling a DSP for + * replies to command messages. + * + * RETURNS + * nothing + * + */ +void gpakHostDelay(void) +{ + msleep(5); + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakLockAccess(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ) +{ + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakUnlockAccess(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ) +{ + return; +} + +extern const unsigned char _binary_GpakDsp_fw_start[]; +extern const unsigned int _binary_GpakDsp_fw_size; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFile - Read a block of bytes from a G.PAK Download file. + * + * FUNCTION + * This function reads a contiguous block of bytes from a G.PAK Download file + * starting at the current file position. + * + * RETURNS + * The number of bytes read from the file. + * -1 indicates an error occurred. + * 0 indicates all bytes have been read (end of file) + * + */ + + +int gpakReadFile_5510(struct r1t1 *rh, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ) +{ + static int stats = 0; + int core_num; + int byte_num = -1; + int DspId; + static unsigned int file_pos[MAX_DSP_CORES]; + static unsigned int file_size; + if (!(stats)) { + stats++; + for (core_num = 0; core_num < MAX_DSP_CORES; core_num++) { + file_pos[core_num] = 0; + } + + file_size = (unsigned int) &_binary_GpakDsp_fw_size; + + printk("r1t1: %d G168 DSP App file size = %d %x\n", rh->num + 1, + (unsigned int) &_binary_GpakDsp_fw_size, + (unsigned int) &_binary_GpakDsp_fw_size); + } + + DspId = rh->num; + + for (byte_num = 0; byte_num < NumBytes; byte_num++) { + if ((file_size - 1) >= file_pos[DspId]) { + pBuffer[byte_num] = _binary_GpakDsp_fw_start[file_pos[DspId]++]; + } + } + + return byte_num; +} diff --git drivers/dahdi/rhino/r1t1/GpakCust.h drivers/dahdi/rhino/r1t1/GpakCust.h new file mode 100644 index 0000000..92dbdea --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakCust.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakCust.h + * + * Description: + * This file contains host system dependent definitions and prototypes of + * functions to support generic G.PAK API functions. The file is used when + * integrating G.PAK API functions in a specific host processor environment. + * + * Note: This file may need to be modified by the G.PAK system integrator. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + + +#ifndef _GPAKCUST_H /* prevent multiple inclusion */ +#define _GPAKCUST_H + +#include "GpakApi.h" + + +/* Host and DSP system dependent related definitions. */ +#define MAX_DSP_CORES 16 /* maximum number of DSP cores */ +#define MAX_CHANNELS 48 /* maximum number of channels */ +#define MAX_WAIT_LOOPS 50 /* max number of wait delay loops */ +#define DSP_IFBLK_ADDRESS 0x0100 /* DSP address of I/F block pointer */ +#define DOWNLOAD_BLOCK_SIZE 512 /* download block size (DSP words) */ + +#define loader_file 0 /* GPAK_FILE_ID for bootloader */ +#define app_file 1 /* GPAK_FILE_ID for application */ +#define num_files 2 + +extern void r1t1_card_wait_hpi(struct r1t1 *rh, __u8 flags); + +extern void r1t1_card_dsp_set(struct r1t1 *rh, __u32 dsp_address, __u16 dsp_data); + +extern __u16 r1t1_card_dsp_get(struct r1t1 *rh, __u32 dsp_address); + +extern void r1t1_card_hpic_set(struct r1t1 *rh, __u16 hpic_data); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadDspMemory - Read DSP memory. + * + * FUNCTION + * This function reads a contiguous block of words from DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +extern void gpakReadDspMemory(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to read */ + DSP_WORD * pWordValues /* pointer to array of word values variable */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteDspMemory - Write DSP memory. + * + * FUNCTION + * This function writes a contiguous block of words to DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +extern void gpakWriteDspMemory(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to write */ + DSP_WORD * pWordValues /* pointer to array of word values to write */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakHostDelay - Delay for a fixed time interval. + * + * FUNCTION + * This function delays for a fixed time interval before returning. The time + * interval is the Host Port Interface sampling period when polling a DSP for + * replies to command messages. + * + * RETURNS + * nothing + * + */ +extern void gpakHostDelay(void); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +extern void gpakLockAccess(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +extern void gpakUnlockAccess(struct r1t1 *rh, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFile - Read a block of bytes from a G.PAK Download file. + * + * FUNCTION + * This function reads a contiguous block of bytes from a G.PAK Download file + * starting at the current file position. + * + * RETURNS + * The number of bytes read from the file. + * -1 indicates an error occurred. + * 0 indicates all bytes have been read (end of file) + * + */ +extern int gpakReadFile_5510(struct r1t1 *rh, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ); + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/r1t1/GpakErrs.h drivers/dahdi/rhino/r1t1/GpakErrs.h new file mode 100644 index 0000000..c60ba12 --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakErrs.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc. + * + * File Name: GpakErrs.h + * + * Description: + * This file contains DSP reply status codes used by G.PAK API functions to + * indicate specific errors. + * + * Version: 1.0 + * + * Revision History: + * 10/17/01 - Initial release. + * 07/03/02 - Updates for conferencing. + * 06/15/04 - Tone type updates. + * + */ + +#ifndef _GPAKERRS_H /* prevent multiple inclusion */ +#define _GPAKERRS_H + +/* Configure Serial Ports reply status codes. */ +typedef enum { + Pc_Success = 0, /* serial ports configured successfully */ + Pc_ChannelsActive = 1, /* unable to configure while channels active */ + Pc_TooManySlots1 = 2, /* too many slots selected for port 1 */ + Pc_InvalidBlockCombo1 = 3, /* invalid combination of blocks for port 1 */ + Pc_NoSlots1 = 4, /* no slots selected for port 1 */ + Pc_InvalidSlots1 = 5, /* invalid slot (> max) selected for port 1 */ + Pc_TooManySlots2 = 6, /* too many slots selected for port 2 */ + Pc_InvalidBlockCombo2 = 7, /* invalid combination of blocks for port 2 */ + Pc_NoSlots2 = 8, /* no slots selected for port 2 */ + Pc_InvalidSlots2 = 9, /* invalid slot (> max) selected for port 2 */ + Pc_TooManySlots3 = 10, /* too many slots selected for port 3 */ + Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */ + Pc_NoSlots3 = 12, /* no slots selected for port 3 */ + Pc_InvalidSlots3 = 13 /* invalid slot (> max) selected for port 3 */ +} GPAK_PortConfigStat_t; + +/* Configure Channel reply status codes. */ +typedef enum { + Cc_Success = 0, /* channel configured successfully */ + Cc_InvalidChannelType = 1, /* invalid Channel Type */ + Cc_InvalidChannel = 2, /* invalid Channel A Id */ + Cc_ChannelActiveA = 3, /* Channel A is currently active */ + Cc_InvalidInputPortA = 4, /* invalid Input A Port */ + Cc_InvalidInputSlotA = 5, /* invalid Input A Slot */ + Cc_BusyInputSlotA = 6, /* busy Input A Slot */ + Cc_InvalidOutputPortA = 7, /* invalid Output A Port */ + Cc_InvalidOutputSlotA = 8, /* invalid Output A Slot */ + Cc_BusyOutputSlotA = 9, /* busy Output A Slot */ + Cc_InvalidInputPortB = 10, /* invalid Input B Port */ + Cc_InvalidInputSlotB = 11, /* invalid Input B Slot */ + Cc_BusyInputSlotB = 12, /* busy Input B Slot */ + Cc_InvalidPktInCodingA = 13, /* invalid Packet In A Coding */ + Cc_InvalidPktOutCodingA = 14, /* invalid Packet Out A Coding */ + Cc_InvalidPktInSizeA = 15, /* invalid Packet In A Frame Size */ + Cc_InvalidPktOutSizeA = 16, /* invalid Packet Out A Frame Size */ + + Cc_ChanTypeNotConfigured = 21, /* channel type was not configured */ + Cc_InsuffECResources = 22, /* insufficient ecan resources avail. */ + Cc_InsuffTDMResources = 23, /* insufficient tdm block resources avail. */ + + Cc_InsuffPktBufResources = 25, /* insufficient pkt buffer resources avail. */ + Cc_InsuffPcmBufResources = 26, /* insufficient pcm buffer resources avail. */ + + Cc_BadPcmEcNlpType = 30, /* invalid EC Nlp type */ + Cc_BadPcmEcTapLength = 31, /* invalid EC tap length */ + Cc_BadPcmEcDblTalkThresh = 32, /* invalid EC double-talk threshold */ + Cc_BadPcmEcNlpThreshold = 33, /* invalid EC Nlp threshold */ + Cc_BadPcmEcCngThreshold = 34, /* invalid EC Cng threshold */ + Cc_BadPcmEcAdaptLimit = 35, /* invalid EC Adapt Limit */ + Cc_BadPcmEcCrossCorrLim = 36, /* invalid EC Cross Correlation Limit */ + Cc_BadPcmEcNumFirSegs = 37, /* invalid EC Number of FirSegments */ + Cc_BadPcmEcFirSegLen = 38, /* invalid EC Fir Segment Length */ + + //Cc_InvalidNumEcsEnabled = 48, /* more than 1 Ec enabled on channel */ + Cc_InvalidFrameRate = 49, /* invalid gpak frame rate */ + Cc_InvalidSoftCompand = 50 /* invalid softCompanding type */ +} GPAK_ChannelConfigStat_t; + +/* Tear Down Channel reply status codes. */ +typedef enum { + Td_Success = 0, /* channel torn down successfully */ + Td_InvalidChannel = 1, /* invalid Channel Id */ + Td_ChannelNotActive = 2 /* channel is not active */ +} GPAK_TearDownChanStat_t; + + +typedef enum { + Ac_Success = 0, /* algorithm control is successfull */ + Ac_InvalidChannel = 1, /* invalid channel identifier */ + Ac_InvalidCode = 2, /* invalid algorithm control code */ + Ac_ECNotEnabled = 3, /* echo canceller was not allocated */ + Ac_InvalidSoftComp = 4 /* invalid softcompanding, 'cause serial port not in companding mode */ +} GPAK_AlgControlStat_t; + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/r1t1/GpakExts.h drivers/dahdi/rhino/r1t1/GpakExts.h new file mode 100644 index 0000000..ece1703 --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakExts.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2001, Adaptive Digital Technologies, Inc. + * + * File Name: GpakExts.h + * + * Description: + * This file contains G.PAK external data and function declarations. + * + * Version: 1.0 + * + * Revision History: + * 11/13/01 - Initial release. + * + */ + +#ifndef _GPAKEXTS_H /* prevent multiple inclusion */ +#define _GPAKEXTS_H + +#include "GpakEnum.h" +#include "sysconfig.h" + + +// Definition of System Configuration related constants and variables. +extern sysConfig_t sysConfig; // System Configuration Info +extern struct chanInfo *chanTable[]; // pointers to Channel structures + +// work input/output buffers +extern USHORT inWork_10msec[]; +extern USHORT outWork_10msec[]; +extern USHORT ECFarWork_10msec[]; + +extern USHORT inWork_2msec[]; +extern USHORT outWork_2msec[]; +extern USHORT ECFarWork_2msec[]; + +extern USHORT inWork_1msec[]; +extern USHORT outWork_1msec[]; +extern USHORT ECFarWork_1msec[]; + +// Echo Canceller scratch memory. +extern USHORT G168SAscratch_10ms[]; // G.168 SARAM scratch for 10 msec task +extern USHORT G168DAscratch_10ms[]; // G.168 DARAM scratch for 10 msec task + +extern USHORT G168SAscratch_2ms[]; // G.168 SARAM scratch for 2 msec task +extern USHORT G168DAscratch_2ms[]; // G.168 DARAM scratch for 2 msec task + +extern USHORT G168SAscratch_1ms[]; // G.168 SARAM scratch for 1 msec task +extern USHORT G168DAscratch_1ms[]; // G.168 DARAM scratch for 1 msec task + + +// Pointers to Echo Canceller data structures. +extern USHORT *pPcmEcDaState[]; // pntr to PCM EC DA States +extern USHORT *pPcmEcSaState[]; // pntr to PCM EC SA States +extern USHORT *pPcmEcEchoPath[]; // pntr to PCM EC Echo Paths +extern USHORT *pPcmEcBackEp[]; // pntr to PCM EC Background Echo Paths +extern USHORT *pPcmEcBackFar[]; // pntr to PCM EC Background Nears +extern USHORT *pPcmEcBackNear[]; // pntr to PCM EC Background Fars +extern USHORT *pPktEcDaState[]; // pntr to Pkt EC DA States +extern USHORT *pPktEcSaState[]; // pntr to Pkt EC SA States +extern USHORT *pPktEcEchoPath[]; // pntr to Pkt EC Echo Paths +extern USHORT *pPktEcBackEp[]; // pntr to Pkt EC Background Echo Paths +extern USHORT *pPktEcBackFar[]; // pntr to Pkt EC Background Nears +extern USHORT *pPktEcBackNear[]; // pntr to Pkt EC Background Fars + +extern sysConfig_t sysConfig; +extern struct chanInfo *chanTable[]; + +extern USHORT DmaLoopback[]; // DMA Loopback flag for each port +extern USHORT NumCfgSlots[]; // num time slots configured on McBSP +extern USHORT McRcvChanEnabA[]; // McBSP's Rcv Chan Enable A reg val +extern USHORT McRcvChanEnabB[]; // McBSP's Rcv Chan Enable B reg val +extern USHORT McXmtChanEnabA[]; // McBSP's Xmt Chan Enable A reg val +extern USHORT McXmtChanEnabB[]; // McBSP's Xmt Chan Enable B reg val + + +extern USHORT BSP0DMA_TxBuffer[]; // DMA Transmit buffer for McBSP0 +extern USHORT BSP0DMA_RxBuffer[]; // DMA Receive buffer for McBSP0 +extern USHORT BSP1DMA_TxBuffer[]; // DMA Transmit buffer for McBSP1 +extern USHORT BSP1DMA_RxBuffer[]; // DMA Receive buffer for McBSP1 +extern USHORT BSP2DMA_TxBuffer[]; // DMA Transmit buffer for McBSP2 +extern USHORT BSP2DMA_RxBuffer[]; // DMA Receive buffer for McBSP2 +extern chanInfo_t GpakChanInstance[]; + + + + +extern USHORT PcmInBufferPool[]; +extern USHORT PcmOutBufferPool[]; +extern USHORT PcmBInBufferPool[]; +extern USHORT PcmBOutBufferPool[]; +extern CircBufInfo_t PcmBOutCircInfo[]; +extern CircBufInfo_t PcmBInCircInfo[]; + +// System status variables. +extern USHORT NumActiveChannels; // number of active channels +// Echo Canceller management variables. +extern USHORT NumPcmEcansUsed; // number of PCM Echo Cancellers in use +extern USHORT PcmEcInUse[]; // flag indicating PCM Echo Canceller in use + +// Echo Canceller management variables. +extern USHORT *pPcmEcChan[]; // pointer to PCM Echo Canceller channels +extern USHORT *pPktEcChan[]; // pointer to Packet Echo Canceller channels + +extern chanInfo_t GpakChanInstance[]; +extern CPG_Instance_t ToneGenInstance[]; +extern CPG_Params_t CPGParms[]; +extern G168Params_t EcParmsA[]; +extern G168Params_t EcParmsB[]; + +// Definition of function prototypes and their return values. + +// Initialize G.PAK interface with host processor. +extern void InitGpakInterface(void); + +// Initialize G.PAK PCM I/O. +extern void InitGpakPcm(void); + +// Initialize G.PAK Framing task data. +extern void InitFrameTasks(void); + +// Initialize a G.PAK channel's Channel structure. +extern struct chanInfo *initChanStruct(USHORT * saramBlock, // pointer to channel's SARAM memory block + USHORT * daramBlock, // pointer to channel's DARAM memory block + USHORT channelId // channels Id + ); + +// ConfigureGpakPcm return status. +typedef enum { + SPCSuccess, // serial ports configured successfully + SPCTooManySlots1, // too many slots selected for port 1 + SPCInvalidBlockCombo1, // invalid combination of blocks for port 1 + SPCNoSlots1, // no slots selected for port 1 + SPCInvalidSlots1, // invalid slot (exceeds max) selected for port 1 + SPCTooManySlots2, // too many slots selected for port 2 + SPCInvalidBlockCombo2, // invalid combination of blocks for port 2 + SPCNoSlots2, // no slots selected for port 2 + SPCInvalidSlots2, // invalid slot (exceeds max) selected for port 2 + SPCTooManySlots3, // too many slots selected for port 3 + SPCInvalidBlockCombo3, // invalid combination of blocks for port 3 + SPCNoSlots3, // no slots selected for port 3 + SPCInvalidSlots3 // invalid slot (exceeds max) selected for port 3 +} SPCStatus_t; + +// Configure G.PAK PCM I/O. +extern SPCStatus_t ConfigureGpakPcm(GpakSlotCfg_t SlotsSelect[], // port's Slot selection + USHORT BlockNumber1[], // port's first group Block Number + USHORT SlotMask1[], // port's first group Slot Mask + USHORT BlockNumber2[], // port's second group Block Number + USHORT SlotMask2[] // port's second group Slot Mask + ); + +// Get the address of PCM to Pkt framing rate queue head. +extern chanInfo_t **GetPcmToPktQueueHead(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Get the address of Pkt to PCM framing rate queue head. +extern chanInfo_t **GetPktToPcmQueueHead(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Determine the address of a framing rate phase counter. +extern USHORT *FrameRatePhaseCount(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Adjust Far Echo and Bulk Delay buffer indices. +extern void AdjustFarBulkIndices(int WriteFrameSize, // Bulk writer's frame size (samples per frame) + int ReadFrameSize, // Far reader's frame size (samples per frame) + USHORT * pWrtPhaseCnt, // pointer to Bulk writer's DMA phase count + USHORT * pReadPhaseCnt, // pointer to Far reader's DMA phase count + USHORT BulkDelaySize, // size of Bulk Delay buffer (samples) + USHORT * pBulkPutIndex, // pointer to Bulk Delay buffer's Put index var + USHORT * pFarTakeIndex // pointer to Far Echo buffer's Take index var + ); + +// Enqueue a channel to it's framing rate or conference queues. +extern void EnqueueChannel(chanInfo_t * pChanInfo, // pointer to channel's Channel Info + chanInfo_t ** pPcm2PktHead, // pointer to PCM to Packet queue head + chanInfo_t ** pPkt2PcmHead // pointer to Packet to PCM queue head + ); + +// Dequeue a channel from it's framing rate/conference queues. +extern void DequeueChannel(chanInfo_t * pChanInfo, // pointer to channel's Channel Info + chanInfo_t ** pPcm2PktHead, // pointer to PCM to Packet queue head + chanInfo_t ** pPkt2PcmHead // pointer to Packet to PCM queue head + ); + +// ActivateGpakChannel return status. +typedef enum { + ACSuccess, // channel activated successfully + ACInvalidInputPort1, // invalid Input Port 1 + ACInvalidInputSlot1, // invalid Input Slot 1 + ACBusyInputSlot1, // busy Input Slot 1 + ACInvalidOutputPort1, // invalid Output Port 1 + ACInvalidOutputSlot1, // invalid Output Slot 1 + ACBusyOutputSlot1, // busy Output Slot 1 + ACInvalidInputPort2, // invalid Input Port 2 + ACInvalidInputSlot2, // invalid Input Slot 2 + ACBusyInputSlot2, // busy Input Slot 2 + ACInvalidOutputPort2, // invalid Output Port 2 + ACInvalidOutputSlot2, // invalid Output Slot 2 + ACBusyOutputSlot2 // busy Output Slot 2 +} ACStatus_t; + +// Activate a G.PAK Channel. +extern ACStatus_t ActivateGpakChannel(chanInfo_t * pChanInfo // pointer to Channel Info + ); + +// Deactivate a G.PAK Channel. +extern void DeactivateGpakChannel(chanInfo_t * pChanInfo // pointer to Channel Info + ); + +// Determine if the frame size is valid. +extern int ValidFrameSize(int FrameSize // Frame Size + ); + + +// Copy linear buffer to circular buffer. +extern void copyLinearToCirc(USHORT * src, CircBufInfo_t * dest, USHORT len); + +// Copy circular buffer to linear buffer. +extern void copyCircToLinear(CircBufInfo_t * src, USHORT * dest, USHORT len); + +// Perform VAD, Tone Detect, and Encode functions. +extern void ProcessVadToneEncode(chanInfo_t * pChanInfo, // pointer to Channel Info + USHORT * pInWork, // pointer to input work buffer (contains data) + USHORT * pOutWork // pointer to output work buffer + ); + +// Initialize an Echo Canceller. +extern G168ChannelInstance_t *InitEchoCanceller(USHORT FrameSize, // number of samples per frame + G168Params_t * EcInitParms, // Echo Canceller initialization parameters + short int EcanIndex // variable that stores ecan index + ); + +/* +extern void ToneGenerate( + short int *pToneActive, + short int *pToneUpdate, + CPG_Instance_t *pToneGenPtr, + CPG_Params_t *pToneParms, + short int *pToneData, + GpakToneGenCmd_t ToneCmd, + short int FrameSize + ); +*/ + +extern void algorithmControl(chanInfo_t * pChan // pointer to Channel structure + ); + + +extern void writeTransmitEnables(USHORT McBspId, // McBSP Id + USHORT MaskA, // A Block mask bits to be written + USHORT MaskB // B Block mask bits to be written + ); + +void ResetCpuUsageStats(); + +int validFrameRate(chanInfo_t * pChan, GpakRate_t frameRate); + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/r1t1/GpakHpi.h drivers/dahdi/rhino/r1t1/GpakHpi.h new file mode 100644 index 0000000..abe731b --- /dev/null +++ drivers/dahdi/rhino/r1t1/GpakHpi.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2001, Adaptive Digital Technologies, Inc. + * + * File Name: GpakHpi.h + * + * Description: + * This file contains common definitions related to the G.PAK interface + * between a host processor and a DSP processor via the Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 10/17/01 - Initial release. + * + */ + +#ifndef _GPAKHPI_H /* prevent multiple inclusion */ +#define _GPAKHPI_H + + +/* Definition of G.PAK Command/Reply message type codes. */ +#define MSG_NULL_REPLY 0 /* Null Reply (unsupported Command) */ +#define MSG_SYS_CONFIG_RQST 1 /* System Configuration Request */ +#define MSG_SYS_CONFIG_REPLY 2 /* System Configuration Reply */ +#define MSG_READ_SYS_PARMS 3 /* Read System Parameters */ +#define MSG_READ_SYS_PARMS_REPLY 4 /* Read System Parameters Reply */ +#define MSG_WRITE_SYS_PARMS 5 /* Write System Parameters */ +#define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */ +#define MSG_CONFIGURE_PORTS 7 /* Configure Serial Ports */ +#define MSG_CONFIG_PORTS_REPLY 8 /* Configure Serial Ports Reply */ +#define MSG_CONFIGURE_CHANNEL 9 /* Configure Channel */ +#define MSG_CONFIG_CHAN_REPLY 10 /* Configure Channel Reply */ +#define MSG_TEAR_DOWN_CHANNEL 11 /* Tear Down Channel */ +#define MSG_TEAR_DOWN_REPLY 12 /* Tear Down Channel Reply */ +#define MSG_CHAN_STATUS_RQST 13 /* Channel Status Request */ +#define MSG_CHAN_STATUS_REPLY 14 /* Channel Status Reply */ + +#define MSG_TEST_MODE 17 /* Configure/Perform Test Mode */ +#define MSG_TEST_REPLY 18 /* Configure/Perform Test Mode Reply */ + +#define MSG_ALG_CONTROL 27 /* algorithm control */ +#define MSG_ALG_CONTROL_REPLY 28 /* algorithm control reply */ +#define MSG_GET_TXCID_ADDRESS 29 /* get tx cid buffer start address */ +#define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */ + +#define MSG_PING 35 /* ping command */ +#define MSG_PING_REPLY 36 /* ping command reply */ +#define MSG_SERIAL_TXVAL 37 /* transmit serial fixed value */ +#define MSG_SERIAL_TXVAL_REPLY 38 /* transmit serial fixed value reply */ +#define MSG_TDM_LOOPBACK 39 /* tdm loopback control */ +#define MSG_TDM_LOOPBACK_REPLY 40 /* tdm loopback control reply */ +#define MSG_RESET_USAGE_STATS 41 /* reset cpu usage stats */ +#define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */ + +#define MSG_RESET_FRAME_STATS 47 /* reset framing stats */ +#define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */ + +#define MSG_READ_DSP_MEMORY 49 /* read small section of DSP's memory */ +#define MSG_READ_DSP_MEMORY_REPLY 50 /* read memory reply */ +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/r1t1/Makefile drivers/dahdi/rhino/r1t1/Makefile new file mode 100644 index 0000000..a4f1bda --- /dev/null +++ drivers/dahdi/rhino/r1t1/Makefile @@ -0,0 +1,14 @@ +obj-m += r1t1.o + +r1t1-objs := r1t1_base.o + +$(obj)/r1t1_base.o: $(src)/r1t1.h $(src)/GpakApi.h $(src)/GpakCust.h + + +clean: + @rm -f *.o + @rm -f *.cmd *.o *.ko + @rm -f .*.cmd .*.o + @rm -rf .tmp_versions Module.symvers + @rm -f core + diff --git drivers/dahdi/rhino/r1t1/gpakenum.h drivers/dahdi/rhino/r1t1/gpakenum.h new file mode 100644 index 0000000..bb10517 --- /dev/null +++ drivers/dahdi/rhino/r1t1/gpakenum.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: gpakenum.h + * + * Description: + * This file contains common enumerations related to G.PAK application + * software. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + +#ifndef _GPAKENUM_H /* prevent multiple inclusion */ +#define _GPAKENUM_H + +/* G.PAK Serial Port Word Size */ +typedef enum { + SerWordSize8 = 0, // 8-bit seial word + SerWordSize16 = 1 // 16-bit serial word +} GpakSerWordSize_t; + +/* G.PAK Serial Port FrameSync Polarity */ +typedef enum { + FrameSyncActLow = 0, // active low frame sync signal + FrameSyncActHigh = 1 // active high frame sync signal +} GpakSerFrameSyncPol_t; + +/* G.PAK Serial Port Clock Polarity */ +typedef enum { + SerClockActLow = 0, // active low serial clock + SerClockActHigh = 1 // active high serial clock +} GpakSerClockPol_t; + +/* G.PAK Serial Port Data Delay */ +typedef enum { + DataDelay0 = 0, // no data delay + DataDelay1 = 1, // 1-bit data delay + DataDelay2 = 2 // 2-bit data delay +} GpakSerDataDelay_t; + +/* G.PAK Serial Port Ids. */ +typedef enum { + SerialPortNull = 0, // null serial port + SerialPort1 = 1, // first PCM serial stream port (McBSP0) + SerialPort2 = 2, // second PCM serial stream port (McBSP1) + SerialPort3 = 3 // third PCM serial stream port (McBSP2) +} GpakSerialPort_t; + +/* G.PAK serial port Slot Configuration selection codes. */ +typedef enum { + SlotCfgNone = 0, // no time slots used + SlotCfg2Groups = 2, // 2 groups of 16 time slots used, 32 Channels system + SlotCfg8Groups = 8 // 8-partition mode for 128-channel system +} GpakSlotCfg_t; + +/* G.PAK serial port Companding Mode codes. */ +typedef enum { + cmpPCMU = 0, // u-Law + cmpPCMA = 1, // A-Law + cmpNone = 2 // none +} GpakCompandModes; + +/* G.PAK Active/Inactive selection codes. */ +typedef enum { + Disabled = 0, // Inactive + Enabled = 1 // Active +} GpakActivation; + +/* G.PAK Channel Type codes. */ +typedef enum { + inactive = 0, // channel inactive + tdmToTdm = 1 // tdmToTdm +} GpakChanType; + +/* G.PAK Algorithm control commands */ +typedef enum { + EnableEcanA = 0, // Enable A side echo canceller + BypassEcanA = 1, // Bypass A side echo canceller + ResetEcanA = 2, // Reset A side echo canceller + EnableEcanB = 3, // Enable B side echo canceller + BypassEcanB = 4, // Bypass B side echo canceller + ResetEcanB = 5, // Reset B side echo canceller + + EnableMuLawSwCompanding = 6, // Enable Mu-law Software companding + EnableALawSwCompanding = 7, // Enable Mu-law Software companding + BypassSwCompanding = 8 // Bypass Software companding +} GpakAlgCtrl_t; + +/* G.PAK Tone types. */ +typedef enum { + Null_tone = 0, // no tone detection + DTMF_tone = 1 // DTMF tone +} GpakToneTypes; + +/* G.PAK direction. */ +typedef enum { + TDMAToB = 0, // A to B + TDMBToA = 1 // B to A +} GpakTdmDirection; + + +typedef enum { + rate1ms = 0, + rate2ms = 1, + rate10ms = 2 +} GpakRate_t; + +/* G.PAK Asynchronous Event Codes */ +typedef enum { + EventToneDetect = 0, // Tone detection event + EventDSPDebug = 7 // DSP debug data event +} GpakAsyncEventCode_t; + +/* G.PAK MF Tone Code Indices */ +typedef enum { + DtmfDigit1 = 0, // DTMF Digit 1 + DtmfDigit2 = 1, // DTMF Digit 2 + DtmfDigit3 = 2, // DTMF Digit 3 + DtmfDigitA = 3, // DTMF Digit A + DtmfDigit4 = 4, // DTMF Digit 4 + DtmfDigit5 = 5, // DTMF Digit 5 + DtmfDigit6 = 6, // DTMF Digit 6 + DtmfDigitB = 7, // DTMF Digit B + DtmfDigit7 = 8, // DTMF Digit 7 + DtmfDigit8 = 9, // DTMF Digit 8 + DtmfDigit9 = 10, // DTMF Digit 9 + DtmfDigitC = 11, // DTMF Digit C + DtmfDigitSt = 12, // DTMF Digit * + DtmfDigit0 = 13, // DTMF Digit 0 + DtmfDigitPnd = 14, // DTMF Digit # + DtmfDigitD = 15, // DTMF Digit D + + EndofMFDigit = 100, // End of MF digit + EndofCngDigit = 101 // End of Cng Digit +} GpakToneCodes_t; + +#endif // end multiple inclusion diff --git drivers/dahdi/rhino/r1t1/r1t1.h drivers/dahdi/rhino/r1t1/r1t1.h new file mode 100644 index 0000000..37ec4b0 --- /dev/null +++ drivers/dahdi/rhino/r1t1/r1t1.h @@ -0,0 +1,261 @@ +/* + * Rhino Equipment Corp. Rhino R1T1 Card Driver + * + * Release version 10/10/10 + * + * Written by + * Lee Reeves + * Bob Conklin + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's wct1xxp module + * and Zapata Telephony's Zaptel Telephony Interface + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * * * * * * * * * * * * * NO WARRANTY * * * * * * * * * * * * * * * * * + * + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + * + * * * * * * * * * * * * DISCLAIMER OF LIABILITY * * * * * * * * * * * * + * + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _R1T1_H +#define _R1T1_H + +#include + +#include +#include +#include +#include + +#define PCI_VENDOR_RHINO 0xb0b +#define PCI_DEVICE_R1T1 0x0105 + +#define RH_MAX_CARDS 32 + +#define R1T1_SIZE 0x820 + +#define E1_DRIVER 1 +#define SUPPORT_E1 1 + +#define DELAY 0x0 /* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */ + +#define RH_CNTL (0x00 << 2) /* loop back, led Al, led A0 */ +#define RH_OPER (0x01 << 2) /* buff length, int ack, enable */ +#define RH_AUXC (0x02 << 2) +#define RH_AUXD (0x03 << 2) +#define RH_MASK0 (0x04 << 2) +#define RH_MASK1 (0x05 << 2) +#define RH_INTSTAT (0x06 << 2) + +#define RH_DMAWS (0x08 << 2) +#define RH_DMAWI (0x0c << 2) +#define RH_DMAWE (0x10 << 2) +#define RH_DMARS (0x18 << 2) +#define RH_DMARI (0x1c << 2) +#define RH_DMARE (0x20 << 2) +#define RH_CURPOS (0x24 << 2) + +#define RH_SERC (0x2d << 2) +#define RH_FSCDELAY (0x2f << 2) + +#define RH_CLOCK 0x0 +#define RH_LEDTEST 0x1 +#define RH_VERSION 0x2 + +#define R1T1_STATE 0x800 +#define R1T1_VERSION 0x802 +#define R1T1_CONTROL 0x804 +#define R1T1_BUFLEN 0x806 +#define R1T1_RXBUFSTART 0x808 +#define R1T1_TXBUFSTART 0x80C + +/* Offset between transmit and receive - I'm not sure what this is actually used for */ +#define RH_OFFSET 4 + +#define BIT_CS (1 << 7) +#define BIT_ADDR (0xf << 3) + +#define BIT_LED0 (1 << 0) +#define BIT_LED1 (1 << 1) +#define BIT_TEST (1 << 2) + +#define NORM_OP 0x90 +#define YEL_ALM 0xa0 +#define NO_CARR 0x70 +#define NO_SYNC 0x80 +#define RECOVER 0xe0 + +#define DS2155_MSTRREG 0x00 +#define DS2155_IOCR1 0x01 +#define DS2155_IOCR2 0x02 +#define DS2155_T1RCR1 0x03 +#define DS2155_T1RCR2 0x04 +#define DS2155_T1TCR1 0x05 +#define DS2155_T1TCR2 0x06 +#define DS2155_T1CCR1 0x07 +#define DS2155_SSIE 0x08 +#define DS2155_SR2 0x18 +#define DS2155_SR3 0x1A +#define DS2155_E1RCR1 0x33 +#define DS2155_E1RCR2 0x34 +#define DS2155_E1TCR1 0x35 +#define DS2155_E1TCR2 0x36 +#define DS2155_SIGCR 0x40 +#define DS2155_LBCR 0x4a +#define DS2155_ESCR 0x4f +#define DS2155_TSR1 0x50 +#define DS2155_CCR1 0x70 +#define DS2155_CCR2 0x71 +#define DS2155_CCR3 0x72 +#define DS2155_CCR4 0x73 +#define DS2155_LIC1 0x78 +#define DS2155_LIC2 0x79 +#define DS2155_LIC4 0x7b +#define DS2155_TLBC 0x7d +#define DS2155_IBCC 0xb6 +#define DS2155_TCD1 0xb7 +#define DS2155_TCD2 0xb8 +#define DS2155_RUPCD1 0xb9 +#define DS2155_RUPCD2 0xba +#define DS2155_RDNCD1 0xbb +#define DS2155_RDNCD2 0xbc +#define DS2155_TAF 0xd0 +#define DS2155_TNAF 0xd1 +#define DS2155_TFDL 0xc1 +#define DS2155_IBOC 0xc5 + +#define TARG_REGS 0x200 + +#define R1T1_HPIC 0x7 /* 0x81c */ + +#define R1T1_ECA1 0x8 +#define R1T1_ECB1 0x9 +#define R1T1_XLATE_EN 0xa /* 0x828 */ + +#define HPI_SEL 1 << 4 +#define EC_ON 1 << 5 +#define DSP_RST 1 << 6 +#define XLATE 1 << 7 + +#define R1T1_DSP_HPIC 0x10 /* 0x840 */ +#define R1T1_HPIDAI 0x11 /* 0x844 */ +#define R1T1_HPIA 0x12 /* 0x848 */ +#define R1T1_HPID 0x13 /* 0x84C */ + +#define R1T1_HPIRD 0x14 /* 0x850 */ +#define R1T1_HPIRD_STAT 0x14 /* 0x852 */ + +#define R1T1_HRDY 1 << 0 +#define R1T1_BUSY_N 2 << 1 +#define R1T1_D_NEW 4 << 2 + +#define R1T1_HPIRDX 0x15 /* 0x854 */ +#define R1T1_HPIRDX_STAT 0x15 /* 0x856 */ + +#define R1T1_HCS_REG 0x16 + +#define R1T1_BL_GO 1 << 0 +#define R1T1_XADD 1 << 5 + +#define DSP_5510 2 + + +struct r1t1 { + struct pci_dev *dev; + spinlock_t lock; + int ise1; + int num; + int version; + /* Our offset for finding channel 1 */ + int offset; + char *variety; + unsigned int intcount; + int usecount; + int clocktimeout; + int sync; + int dead; + int blinktimer; + int alarmtimer; + int loopupcnt; + int loopdowncnt; + int miss; + int misslast; + int dsp_up; + int hpi_fast; + int hpi_xadd; + int dsp_sel; + int dsp_type; + int *chanmap; + unsigned int nextec; + unsigned int currec; + + wait_queue_head_t regq; + + struct workqueue_struct *wq; + struct work_struct work; + + unsigned char ledtestreg; + unsigned char outbyte; + unsigned long pciaddr; + void *ioaddr; + volatile unsigned int *membase; /* Base address of card */ + unsigned short canary; + /* T1 signalling */ + unsigned char txsig[12]; + dma_addr_t readdma; + dma_addr_t writedma; + volatile unsigned char *writechunk; /* Double-word aligned write memory */ + volatile unsigned char *readchunk; /* Double-word aligned read memory */ + unsigned char ec_chunk1[31][DAHDI_CHUNKSIZE]; + unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; + int nextbuf; + struct dahdi_span span; /* Span */ + struct dahdi_chan *chans[31]; /* Channels */ + struct dahdi_echocan_state *ec[31]; /* echocan state for each channel */ +}; + +extern unsigned int __r1t1_card_dsp_in(struct r1t1 *rh, const unsigned int addr); +extern void __r1t1_card_dsp_out(struct r1t1 *rh, const unsigned int addr, + const unsigned int value); + +extern unsigned int __r1t1_card_pci_in(struct r1t1 *rh, const unsigned int addr); +extern void __r1t1_card_pci_out(struct r1t1 *rh, const unsigned int addr, + const unsigned int value); + +#endif /* _R1T1_H */ diff --git drivers/dahdi/rhino/r1t1/r1t1_base.c drivers/dahdi/rhino/r1t1/r1t1_base.c new file mode 100644 index 0000000..5e23e64 --- /dev/null +++ drivers/dahdi/rhino/r1t1/r1t1_base.c @@ -0,0 +1,2289 @@ +/* + * Rhino Equipment Corp. Rhino R1T1 Card Driver + * + * Release version 10/10/10 + * + * Written by + * Lee Reeves + * Bob Conklin + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's wct1xxp module + * and Zapata Telephony's Zaptel Telephony Interface + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "r1t1.h" +#include "GpakCust.h" +#include "GpakApi.h" + +static int chanmap_t1[] = { 1, 2, 3, + 5, 6, 7, + 9, 10, 11, + 13, 14, 15, + 17, 18, 19, + 21, 22, 23, + 25, 26, 27, + 29, 30, 31 +}; + +static int chanmap_e1[] = { 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + 16, 17, 18, 19, + 20, 21, 22, 23, + 24, 25, 26, 27, + 28, 29, 30, 31 +}; + +#define USE_G168_DSP + +#define CANARY 0xca1e +#define addr_t (__u32)(dma_addr_t) +#define DEBUG_MAIN (1 << 0) +#define DEBUG_DSP (1 << 7) + +static int debug = 0; /* Start out with no debugging enabled */ +static int e1 = 0; /* Defines whether or not the card is set to e1 mode */ +static int no_ec = 0; +static int ec_disable = 0; /* Mask defining where the ec should be disabled */ +static int ec_sw = 0xffffffff; /* Mask defining where the ec should be enabled */ +static int nlp_type = 3; + +static struct r1t1 *cards[RH_MAX_CARDS]; + +static int r1t1_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, + struct dahdi_echocan_state **ec); +static void r1t1_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); + +static const struct dahdi_echocan_features my_ec_features = { + .NLP_automatic = 1, + .CED_tx_detect = 1, + .CED_rx_detect = 1, +}; + +static const struct dahdi_echocan_ops my_ec_ops = { + .name = "R1T1_HWEC", + .echocan_free = r1t1_echocan_free, +}; + +#ifndef __GENERIC_IO_H + +unsigned int fastcall ioread8(void __iomem *); +{ + return *(volatile __u8 *) (__iomem); +} + +unsigned int fastcall ioread16(void __iomem *); +{ + return *(volatile __u16 *) (__iomem); +} + +unsigned int fastcall ioread32(void __iomem *); +{ + return *(volatile __u32 *) (__iomem); +} + +void fastcall iowrite8(u8, void __iomem *); +{ + *(volatile __u8 *) (__iomem) = u8; + return 0; +} + +void fastcall iowrite16(u16, void __iomem *); +{ + *(volatile __u16 *) (__iomem) = u16; + return 0; +} + +void fastcall iowrite32(u32, void __iomem *); +{ + *(volatile __u32 *) (__iomem) = u32; + return 0; +} + +#endif + +static int r1t1_open(struct dahdi_chan *chan) +{ + struct dahdi_span *span = chan->span; + struct r1t1 *rh = container_of(span, struct r1t1, span); + + if (rh->dead) + return -ENODEV; + rh->usecount++; + try_module_get(THIS_MODULE); + + if (debug) + printk("R1T1: use count %d\n", rh->usecount); + return 0; +} + +static int __r1t1_get_reg(struct r1t1 *rh, int reg) +{ + unsigned char res; + res = ioread8(rh->ioaddr + (reg << 2)); + return res; +} + +static int __r1t1_set_reg(struct r1t1 *rh, int reg, unsigned char val) +{ + iowrite8(val, rh->ioaddr + (reg << 2)); + /* an extra read to prevent back-to-back burst writes */ + ioread8(rh->ioaddr + (reg << 2)); + return 0; +} + + +static void __r1t1_stop_framer(struct r1t1 *rh) +{ + __r1t1_set_reg(rh, R1T1_CONTROL / 4, 0x00); +} + + +static int r1t1_framer_hard_reset(struct r1t1 *rh) +{ + int i; + unsigned long flags; + unsigned long endjiffies; + + spin_lock_irqsave(&rh->lock, flags); + if (debug) + printk("R1T1: is e1 %i\n", rh->ise1); + + /* Soft reset */ + __r1t1_set_reg(rh, DS2155_MSTRREG, 0x01); /* Sets *ALL* regs to default values */ + __r1t1_set_reg(rh, DS2155_IOCR2, 0x03); /* 2.048 Mhz Pll clock for all */ + /* 2 TCLK from TCLK pin if alive, or RCLK 6 TCLK from RCLK 4 TCLK from MCLK (Master) */ + __r1t1_set_reg(rh, DS2155_CCR1, 0x06); /* 0 TCLK pin = RCLK from Rhino Chip */ + __r1t1_set_reg(rh, DS2155_CCR2, 0x03); /* Enable BPCLK 8.019 Mhz */ + __r1t1_set_reg(rh, DS2155_IBOC, 0x28); /* Set as #1 on 4 wide bus */ + + + if (rh->ise1) { + __r1t1_set_reg(rh, DS2155_MSTRREG, 0x02); /* Sets E1 Mode */ + __r1t1_set_reg(rh, DS2155_E1TCR1, 0x10); /* International Si */ + __r1t1_set_reg(rh, DS2155_SIGCR, 0x80); /* Sig reinsertion en */ + __r1t1_set_reg(rh, DS2155_LIC1, 0x21); /* TPD turn off Power Down default 120 LBO */ + __r1t1_set_reg(rh, DS2155_LIC4, 0x0f); /* 120 transmit term */ + __r1t1_set_reg(rh, DS2155_LIC2, 0xd8); /* LIRST Line Intf Reset (takes 40ms) */ + __r1t1_set_reg(rh, DS2155_LIC2, 0x98); /* Sets E1 mode JAMUX, Stops TA1 */ + __r1t1_set_reg(rh, DS2155_TAF, 0x1b); /* Tx Align Frame Sa and Si Pattern */ + __r1t1_set_reg(rh, DS2155_TNAF, 0x5f); /* Tx Non Align Frame Sa and Si Pattern */ + __r1t1_set_reg(rh, DS2155_TSR1, 0x50); /* CH-0 clear */ + for (i = 0x51; i <= 0x5f; i++) + __r1t1_set_reg(rh, i, 0x55); /* TSR2 - TSR16 = 55 */ + for (i = 0x8c; i <= 0x8f; i++) + __r1t1_set_reg(rh, i, 0xff); /* TCBR1 - TCBR4 = ff */ + } else { + __r1t1_set_reg(rh, DS2155_T1RCR1, 0x0C); /* Sync Time & Criteria */ + __r1t1_set_reg(rh, DS2155_T1TCR1, 0x10); /* SW Sig Insertion */ + __r1t1_set_reg(rh, DS2155_IBCC, 0x22); /* Enable Loop Up and Down */ + __r1t1_set_reg(rh, DS2155_RUPCD1, 0x80); /* Set the Code Values */ + __r1t1_set_reg(rh, DS2155_RUPCD2, 0x00); + __r1t1_set_reg(rh, DS2155_RDNCD1, 0x80); + __r1t1_set_reg(rh, DS2155_RDNCD2, 0x00); + __r1t1_set_reg(rh, DS2155_LIC1, 0x01); /* TPD(0) turn off Power Down default LBO */ + __r1t1_set_reg(rh, DS2155_LIC4, 0x05); /* 75 transmit term */ + __r1t1_set_reg(rh, DS2155_LIC2, 0x58); /* LIRST(6) Line Intf Reset (takes 40ms) */ + __r1t1_set_reg(rh, DS2155_LIC2, 0x18); /* Sets T1 mode JAMUX, Stops TA1 */ + } + /* Wait 100ms to give plenty of time for reset */ + endjiffies = jiffies + 10; + while (endjiffies < jiffies); + + __r1t1_set_reg(rh, DS2155_ESCR, 0x55); /* Re-align elastic stores */ + __r1t1_set_reg(rh, DS2155_ESCR, 0x11); /* TX & RX elastic (TSYSCLK IN) */ + + spin_unlock_irqrestore(&rh->lock, flags); + return 0; +} + +static int r1t1_shutdown(struct dahdi_span *span) +{ + if (span) { + struct r1t1 *rh = container_of(span, struct r1t1, span); + span->flags &= ~DAHDI_FLAG_RUNNING; + + if (rh) { + __r1t1_stop_framer(rh); + r1t1_framer_hard_reset(rh); + } + } + + return 0; +} + + +static void r1t1_release(struct r1t1 *rh) +{ + + r1t1_shutdown(&rh->span); + + dahdi_unregister(&rh->span); + + /* Free resources */ + free_irq(rh->dev->irq, rh); + pci_free_consistent(rh->dev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 + 8, + (void *) rh->writechunk, rh->writedma); + iounmap(rh->ioaddr); + release_mem_region(rh->pciaddr, R1T1_SIZE); + /* recall that rc->chans[0] == chan_block from r1t1_init_one, + * and that rc->ec[0] == ec_block from r1t1_init_one. */ + kfree(rh->chans[0]); + kfree(rh->ec[0]); + kfree(rh); + printk("Released a Rhino r1t1\n"); +} + +static int r1t1_close(struct dahdi_chan *chan) +{ + struct dahdi_span *span = chan->span; + struct r1t1 *rh = container_of(span, struct r1t1, span); + rh->usecount--; + module_put(THIS_MODULE); + if (debug) + printk("R1T1: use count %d\n", rh->usecount); + /* If we're dead, release us now */ + if (!rh->usecount && rh->dead) + r1t1_release(rh); + return 0; +} + +static void r1t1_enable_interrupts(struct r1t1 *rh) +{ +} + +static void r1t1_start_dma(struct r1t1 *rh) +{ + /* Reset Master and TDM */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + __r1t1_set_reg(rh, R1T1_CONTROL / 4, 0x01); + if (debug) + printk("R1T1: Started DMA\n"); +} + +static void __r1t1_set_clear(struct r1t1 *rh) +{ + /* Setup registers */ + int x, z; + unsigned char b; + + /* No such thing under E1 */ + if (rh->ise1) { + printk("R1T1: Can't set clear mode on an E1!\n"); + return; + } + + for (x = 0; x < 3; x++) { + b = 0; + for (z = 0; z < 8; z++) { + /* Enable software signaling unless the channel is "clear" */ + if (!(rh->span.chans[x * 8 + z]->flags & DAHDI_FLAG_CLEAR)) + b |= (1 << z); + } + __r1t1_set_reg(rh, DS2155_SSIE + x, b); + } +} + +static void r1t1_t1_framer_start(struct r1t1 *rh) +{ + char *coding, *framing; + int alreadyrunning = rh->span.flags & DAHDI_FLAG_RUNNING; + unsigned long flags; + + spin_lock_irqsave(&rh->lock, flags); + + if (rh->span.lineconfig & DAHDI_CONFIG_ESF) { + /* CCR1(2) TFM = 1 */ + __r1t1_set_reg(rh, DS2155_T1CCR1, + (__r1t1_get_reg(rh, DS2155_T1CCR1) & 0xfb) | 0x04); + /* RCR2(6) RFM = 1 */ + __r1t1_set_reg(rh, DS2155_T1RCR2, + (__r1t1_get_reg(rh, DS2155_T1RCR2) & 0xbf) | 0x40); + /* Fs bit insertion TCR2 TSLC96 = 0 */ + __r1t1_set_reg(rh, DS2155_T1TCR2, + (__r1t1_get_reg(rh, DS2155_T1TCR2) & 0xbf) & ~0x40); + __r1t1_set_reg(rh, DS2155_TFDL, 0x00); /* FDL data */ + framing = "ESF"; + } else { + /* CCR1(2) TFM = 0 */ + __r1t1_set_reg(rh, DS2155_T1CCR1, + (__r1t1_get_reg(rh, DS2155_T1CCR1) & 0xfb) & ~0x04); + /* RCR2(6) RFM = 0 */ + __r1t1_set_reg(rh, DS2155_T1RCR2, + (__r1t1_get_reg(rh, DS2155_T1RCR2) & 0xbf) & ~0x40); + /* Fs bit insertion TCR2(6) TSLC96 = 1 and TCR1(2) TFDLS = 0 (*default*) */ + __r1t1_set_reg(rh, DS2155_T1TCR2, + (__r1t1_get_reg(rh, DS2155_T1TCR2) & 0xbf) | 0x40); + __r1t1_set_reg(rh, DS2155_TFDL, 0x1c); /* FDL data */ + framing = "D4"; + } + if (rh->span.lineconfig & DAHDI_CONFIG_B8ZS) { + /* TCR2(7) TB8ZS = 1 */ + __r1t1_set_reg(rh, DS2155_T1TCR2, + (__r1t1_get_reg(rh, DS2155_T1TCR2) & 0x7f) | 0x80); + /* RCR2(5) RB8ZS = 1 */ + __r1t1_set_reg(rh, DS2155_T1RCR2, + (__r1t1_get_reg(rh, DS2155_T1RCR2) & 0xdf) | 0x20); + coding = "B8ZS"; + } else { + /* TCR2(7) TB8ZS = 0 */ + __r1t1_set_reg(rh, DS2155_T1TCR2, + (__r1t1_get_reg(rh, DS2155_T1TCR2) & 0x7f) & ~0x80); + /* RCR2(5) RB8ZS = 0 */ + __r1t1_set_reg(rh, DS2155_T1RCR2, + (__r1t1_get_reg(rh, DS2155_T1RCR2) & 0xdf) & ~0x20); + coding = "AMI"; + + } + + /* Force re-sync */ + __r1t1_set_reg(rh, DS2155_T1RCR1, (__r1t1_get_reg(rh, DS2155_T1RCR1) & 0xfe) | 0x01); + __r1t1_set_reg(rh, DS2155_T1RCR1, (__r1t1_get_reg(rh, DS2155_T1RCR1) & 0xfe) & ~0x01); + + /* Set outgoing LBO */ + __r1t1_set_reg(rh, DS2155_LIC1, + (__r1t1_get_reg(rh, DS2155_LIC1) & 0x1f) | (rh->span.txlevel << 5)); + __r1t1_set_clear(rh); + + printk("R1T1: Using %s/%s coding/framing\n", coding, framing); + if (!alreadyrunning) { + rh->span.flags |= DAHDI_FLAG_RUNNING; + } + spin_unlock_irqrestore(&rh->lock, flags); +} + +static void r1t1_e1_framer_start(struct r1t1 *rh) +{ + char *coding, *framing; + int alreadyrunning = rh->span.flags & DAHDI_FLAG_RUNNING; + unsigned long flags; + char *crcing = ""; + + spin_lock_irqsave(&rh->lock, flags); + if (debug) + printk("R1T1: E1 framer start configuration\n"); + + if (rh->span.lineconfig & DAHDI_CONFIG_CCS) { + /* SIGCR GRSRE(7) = 0 CCS */ + __r1t1_set_reg(rh, DS2155_SIGCR, + (__r1t1_get_reg(rh, DS2155_SIGCR) & 0x7f) & ~0x80); + /* SIGCR TCCS(1) RCCS(2) = 1 CCS */ + __r1t1_set_reg(rh, DS2155_SIGCR, + (__r1t1_get_reg(rh, DS2155_SIGCR) & 0xfb) | 0x04); + /* E1RCR1 RSIGM(6) = 1 CCS */ + __r1t1_set_reg(rh, DS2155_E1RCR1, + (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xbf) | 0x40); + /* E1TCR1 T16S(6) = 0 TS16 from SSIE and TSHCS */ + __r1t1_set_reg(rh, DS2155_E1TCR1, + (__r1t1_get_reg(rh, DS2155_E1TCR1) & 0xbf) & ~0x40); + framing = "CCS"; /* Receive CCS */ + } else { + /* SIGCR GRSRE(7) = 1 CAS */ + __r1t1_set_reg(rh, DS2155_SIGCR, + (__r1t1_get_reg(rh, DS2155_SIGCR) & 0x7f) | 0x80); + /* SIGCR TCCS(1) RCCS(2) = 0 CAS */ + __r1t1_set_reg(rh, DS2155_SIGCR, + (__r1t1_get_reg(rh, DS2155_SIGCR) & 0xfb) & ~0x04); + /* E1RCR1 RSIGM(6) = 0 CAS */ + __r1t1_set_reg(rh, DS2155_E1RCR1, + (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xbf) & ~0x40); + /* E1TCR1 T16S(6) = 1 TS16 from TS1-TS16 */ + __r1t1_set_reg(rh, DS2155_E1TCR1, + (__r1t1_get_reg(rh, DS2155_E1TCR1) & 0xbf) | 0x40); + framing = "CAS"; + } + if (rh->span.lineconfig & DAHDI_CONFIG_HDB3) { + /* E1RCR1 RHDB3(5) = 1 HDB3 */ + __r1t1_set_reg(rh, DS2155_E1RCR1, + (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xdf) | 0x20); + /* E1TCR1 THDB3(2) = 1 HDB3 */ + __r1t1_set_reg(rh, DS2155_E1TCR1, + (__r1t1_get_reg(rh, DS2155_E1TCR1) & 0xfb) | 0x04); + coding = "HDB3"; + } else { + /* E1RCR1 RHDB3(5) = 0 HDB3 */ + __r1t1_set_reg(rh, DS2155_E1RCR1, + (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xdf) & ~0x20); + /* E1TCR1 THDB3(2) = 0 HDB3 */ + __r1t1_set_reg(rh, DS2155_E1TCR1, + (__r1t1_get_reg(rh, DS2155_E1TCR1) & 0xfb) & ~0x04); + coding = "AMI"; + } + if (rh->span.lineconfig & DAHDI_CONFIG_CRC4) { + /* E1RCR1 RCRC4(3) = 1 */ + __r1t1_set_reg(rh, DS2155_E1RCR1, + (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xf7) | 0x08); + /* E1TCR1 TCRC4(0) = 1 */ + __r1t1_set_reg(rh, DS2155_E1TCR1, + (__r1t1_get_reg(rh, DS2155_E1TCR1) & 0xfe) | 0x01); + /* E1TCR2 AEBE(2) = 1 */ + __r1t1_set_reg(rh, DS2155_E1TCR2, + (__r1t1_get_reg(rh, DS2155_E1TCR2) & 0xfb) | 0x04); + crcing = " with CRC4"; + } else { + /* E1RCR1 RCRC4(3) = 0 */ + __r1t1_set_reg(rh, DS2155_E1RCR1, + (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xf7) & ~0x08); + /* E1TCR1 TCRC4(0) = 0 */ + __r1t1_set_reg(rh, DS2155_E1TCR1, + (__r1t1_get_reg(rh, DS2155_E1TCR1) & 0xfe) & ~0x01); + /* E1TCR2 AEBE(2) = 0 */ + __r1t1_set_reg(rh, DS2155_E1TCR2, + (__r1t1_get_reg(rh, DS2155_E1TCR2) & 0xfb) & ~0x04); + crcing = ""; + } + + /* Set outgoing LBO */ + __r1t1_set_reg(rh, DS2155_LIC1, + (__r1t1_get_reg(rh, DS2155_LIC1) & 0x1f) | (rh->span.txlevel << 5)); + + /* Force re-sync E1RCR1 RESYNC(0) = 1 - 0 */ + __r1t1_set_reg(rh, DS2155_E1RCR1, (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xfe) | 0x01); + __r1t1_set_reg(rh, DS2155_E1RCR1, (__r1t1_get_reg(rh, DS2155_E1RCR1) & 0xfe) & ~0x01); + + + printk("R1T1: Using %s/%s coding/signaling%s 120 Ohms\n", coding, framing, crcing); + if (!alreadyrunning) { + rh->span.flags |= DAHDI_FLAG_RUNNING; + } + spin_unlock_irqrestore(&rh->lock, flags); +} + +static int r1t1_rbsbits(struct dahdi_chan *chan, int bits) +{ + struct dahdi_span *span = chan->span; + struct r1t1 *rh = container_of(span, struct r1t1, span); + unsigned long flags; + int b, o; + unsigned char mask; + + /* Byte offset */ + spin_lock_irqsave(&rh->lock, flags); + + if (rh->ise1) { + if (chan->chanpos % 2) { + mask = (bits | (rh->chans[chan->chanpos - 1 + 1]->txsig << 4)); + } else { + mask = ((bits << 4) | rh->chans[chan->chanpos - 1 - 1]->txsig); + } + __r1t1_set_reg(rh, 0x51 + (chan->chanpos - 1) / 2, mask); + rh->chans[chan->chanpos - 1]->txsig = bits; + if (debug) + printk("R1T1: Register %x, Addr %x, mask %x\n", + __r1t1_get_reg(rh, 0x51 + (chan->chanpos - 1) / 2), mask, + (0x51 + (chan->chanpos - 1) / 2)); + + } else { + b = (chan->chanpos - 1) / 2; + o = (chan->chanpos - 1) % 2; + + mask = o ? 0x80 : 0x08; + + if (bits & DAHDI_ABIT) { + /* Set A-bit */ + rh->txsig[b] |= mask; + } else { + /* Clear A-bit */ + rh->txsig[b] &= ~mask; + } + if (bits & DAHDI_BBIT) { + /* Set B-bit */ + rh->txsig[b] |= (mask >> 1); + } else { + rh->txsig[b] &= ~(mask >> 1); + } + if (bits & DAHDI_CBIT) { + /* Set C-bit */ + rh->txsig[b] |= (mask >> 2); + } else { + rh->txsig[b] &= ~(mask >> 2); + } + if (bits & DAHDI_DBIT) { + /* Set D-bit */ + rh->txsig[b] |= (mask >> 3); + } else { + rh->txsig[b] &= ~(mask >> 3); + } + /* Output new values */ + __r1t1_set_reg(rh, 0x50 + b, rh->txsig[b]); + + } + spin_unlock_irqrestore(&rh->lock, flags); + return 0; +} + +static int r1t1_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) +{ + switch (cmd) { + default: + return -ENOTTY; + } +} + +static int r1t1_startup(struct dahdi_span *span) +{ + struct r1t1 *rh = container_of(span, struct r1t1, span); + + int i, alreadyrunning = span->flags & DAHDI_FLAG_RUNNING; + + /* initialize the start value for the entire chunk of last ec buffer */ + for (i = 0; i < span->channels; i++) { + memset(rh->ec_chunk1[i], DAHDI_LIN2X(0, span->chans[i]), DAHDI_CHUNKSIZE); + memset(rh->ec_chunk2[i], DAHDI_LIN2X(0, span->chans[i]), DAHDI_CHUNKSIZE); + } + + /* Reset framer with proper parameters and start */ + if (rh->ise1) { + r1t1_e1_framer_start(rh); + } else { + r1t1_t1_framer_start(rh); + } + printk("R1T1: Calling startup (flags is %x)\n", (__u32) (span->flags)); + + if (!alreadyrunning) { + /* Only if we're not already going */ + r1t1_enable_interrupts(rh); + r1t1_start_dma(rh); + span->flags |= DAHDI_FLAG_RUNNING; + } + return 0; +} + +static int r1t1_maint(struct dahdi_span *span, int cmd) +{ + struct r1t1 *rh = container_of(span, struct r1t1, span); + int res = 0; + unsigned long flags; + spin_lock_irqsave(&rh->lock, flags); + if (rh->ise1) { + switch (cmd) { + case DAHDI_MAINT_NONE: + __r1t1_set_reg(rh, DS2155_LBCR, 0); /* no loop */ + break; + case DAHDI_MAINT_LOCALLOOP: + __r1t1_set_reg(rh, DS2155_LBCR, 0x08); /* local loop */ + break; + case DAHDI_MAINT_REMOTELOOP: + __r1t1_set_reg(rh, DS2155_LBCR, 0x04); /* remote loop */ + break; + case DAHDI_MAINT_LOOPUP: + case DAHDI_MAINT_LOOPDOWN: + case DAHDI_MAINT_LOOPSTOP: + res = -ENOSYS; + break; + default: + printk("R1T1: Unknown maint command: %d\n", cmd); + res = -EINVAL; + break; + } + } else { + switch (cmd) { + case DAHDI_MAINT_NONE: + __r1t1_set_reg(rh, DS2155_LBCR, 0); /* no loop */ + break; + case DAHDI_MAINT_LOCALLOOP: + __r1t1_set_reg(rh, DS2155_LBCR, 0x08); /* local loop */ + break; + case DAHDI_MAINT_REMOTELOOP: + __r1t1_set_reg(rh, DS2155_LBCR, 0x04); /* remote loop */ + break; + case DAHDI_MAINT_LOOPUP: + __r1t1_set_reg(rh, DS2155_T1CCR1, (__r1t1_get_reg(rh, DS2155_T1CCR1) & 0xfe) | 1); /* send loopup code */ + __r1t1_set_reg(rh, DS2155_IBCC, 0x22); /* send loopup code */ + __r1t1_set_reg(rh, DS2155_TCD1, 0x80); /* send loopup code */ + __r1t1_set_reg(rh, DS2155_TCD2, 0x00); /* send loopup code */ + break; + case DAHDI_MAINT_LOOPDOWN: + __r1t1_set_reg(rh, DS2155_T1CCR1, (__r1t1_get_reg(rh, DS2155_T1CCR1) & 0xfe) | 1); /* send loopdown code */ + __r1t1_set_reg(rh, DS2155_IBCC, 0x62); /* send loopdown code */ + __r1t1_set_reg(rh, DS2155_TCD1, 0x90); /* send loopdown code */ + __r1t1_set_reg(rh, DS2155_TCD1, 0x00); /* send loopdown code */ + break; + case DAHDI_MAINT_LOOPSTOP: + __r1t1_set_reg(rh, DS2155_T1CCR1, (__r1t1_get_reg(rh, DS2155_T1CCR1) & 0xfe)); /* stop sending loopup code */ + break; + default: + printk("R1T1: Unknown maint command: %d\n", cmd); + res = -EINVAL; + } + } + spin_unlock_irqrestore(&rh->lock, flags); + return res; +} + +static int r1t1_chanconfig(struct dahdi_chan *chan, int sigtype) +{ + if (chan) { + struct dahdi_span *span = chan->span; + struct r1t1 *rh = container_of(span, struct r1t1, span); + unsigned long flags; + int alreadyrunning = chan->span->flags & DAHDI_FLAG_RUNNING; + + spin_lock_irqsave(&rh->lock, flags); + + if (alreadyrunning && !rh->ise1) + __r1t1_set_clear(rh); + + spin_unlock_irqrestore(&rh->lock, flags); + } + return 0; +} + +static int r1t1_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) +{ + if (span) { + struct r1t1 *rh = container_of(span, struct r1t1, span); + span->lineconfig = lc->lineconfig; + span->txlevel = lc->lbo; + span->rxlevel = 0; + /* Do we want to SYNC on receive or not */ + rh->sync = lc->sync; + /* If already running, apply changes immediately */ + if (span->flags & DAHDI_FLAG_RUNNING) + return r1t1_startup(span); + } + return 0; +} + +static int r1t1_software_init(struct r1t1 *rh) +{ +static struct dahdi_span_ops ops = { + .spanconfig = r1t1_spanconfig, + .chanconfig = r1t1_chanconfig, + .startup = r1t1_startup, + .shutdown = r1t1_shutdown, + .rbsbits = r1t1_rbsbits, + .maint = r1t1_maint, + .open = r1t1_open, + .close = r1t1_close, + .ioctl = r1t1_ioctl, +#ifdef USE_G168_DSP + .echocan_create = r1t1_echocan_create, +#endif + .owner = THIS_MODULE + }; + + int x; + + +rh->span.ops = &ops; + + sprintf(rh->span.name, "R1T1/%d", rh->num); + snprintf(rh->span.desc, sizeof(rh->span.desc) - 1, "%s Card %d", rh->variety, + rh->num); + dahdi_copy_string(rh->span.devicetype, rh->variety, sizeof(rh->span.devicetype)); + snprintf(rh->span.location, sizeof(rh->span.location) - 1, + "PCI Bus %02d Slot %02d", rh->dev->bus->number, + PCI_SLOT(rh->dev->devfn) + 1); + rh->span.manufacturer = "Rhino Equipment"; + + rh->span.chans = rh->chans; + rh->span.flags = DAHDI_FLAG_RBS; + + if (rh->ise1) { + rh->span.channels = 31; + rh->span.spantype = "E1"; + rh->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3 | + DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4; + rh->span.deflaw = DAHDI_LAW_ALAW; + } else { + rh->span.channels = 24; + rh->span.spantype = "T1"; + rh->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | + DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; + rh->span.deflaw = DAHDI_LAW_MULAW; + } + + init_waitqueue_head(&rh->span.maintq); + for (x = 0; x < rh->span.channels; x++) { + + + if (rh->ise1) { + rh->chans[x]->writechunk = (u_char *) (rh->writechunk + + (chanmap_e1[x] * DAHDI_CHUNKSIZE)); + rh->chans[x]->readchunk = (u_char *) (rh->readchunk + + (chanmap_e1[x] * DAHDI_CHUNKSIZE)); + } else { + rh->chans[x]->writechunk = (u_char *) (rh->writechunk + + (chanmap_t1[x] * DAHDI_CHUNKSIZE)); + rh->chans[x]->readchunk = (u_char *) (rh->readchunk + + (chanmap_t1[x] * DAHDI_CHUNKSIZE)); + } + + sprintf(rh->chans[x]->name, "R1T1/%d/%d", rh->num, x + 1); + rh->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 | + DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | + DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS | +#ifdef DAHDI_SIG_FXONS + DAHDI_SIG_FXONS | +#endif + DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_SF; + rh->chans[x]->chanpos = x + 1; + } + + if (dahdi_register(&rh->span, 0)) { + printk("R1T1: Unable to register span with DAHDI\n"); + return -1; + } + return 0; +} + +static void r1t1_transmitprep(struct r1t1 *rh, int nextbuf) +{ + dahdi_transmit(&rh->span); +} + +static void r1t1_receiveprep(struct r1t1 *rh, int nextbuf) +{ + if (!rh->dsp_up) + dahdi_ec_span(&rh->span); + dahdi_receive(&rh->span); +} + +static void __r1t1_check_sigbits(struct r1t1 *rh, int x) +{ + int a, i, y, rxs; + + if (rh->ise1) { + for (y = 0; y < 10; y += 2) { + i = x * 10 + y; + a = __r1t1_get_reg(rh, 0x61 + (i / 2)); + rxs = (a & 0xf); + if (!(rh->chans[i]->sig & DAHDI_SIG_CLEAR)) { + if (rh->chans[i]->rxsig != rxs) + dahdi_rbsbits(rh->chans[i], rxs); + } + i++; + rxs = (a >> 4) & 0xf; + if (!(rh->chans[i]->sig & DAHDI_SIG_CLEAR)) { + if (rh->chans[i]->rxsig != rxs) + dahdi_rbsbits(rh->chans[i], rxs); + } + } + } else { + for (y = 0; y < 8; y += 2) { + i = x * 8 + y; + a = __r1t1_get_reg(rh, 0x60 + (i / 2)); + rxs = a & 0x0f; + if (!(rh->chans[i]->sig & DAHDI_SIG_CLEAR)) { + if (rh->chans[i]->rxsig != rxs) + dahdi_rbsbits(rh->chans[i], rxs); + } + i++; + rxs = (a >> 4) & 0x0f; + if (!(rh->chans[i]->sig & DAHDI_SIG_CLEAR)) { + if (rh->chans[i]->rxsig != rxs) + dahdi_rbsbits(rh->chans[i], rxs); + } + } + } +} + +static void __r1t1_check_alarms(struct r1t1 *rh) +{ + unsigned char c, led_state; + int alarms; + int x, j; + + /* Get RIR2 */ + __r1t1_set_reg(rh, DS2155_SR2, 0x00); + c = __r1t1_get_reg(rh, DS2155_SR2); + /* RLOSC FRCLC */ + rh->span.rxlevel = (((c >> 4) & 1) << 1) || ((c >> 5) & 1); + + /* Get status register s */ + __r1t1_set_reg(rh, DS2155_SR3, 0x60); + c = __r1t1_get_reg(rh, DS2155_SR3); + + /* Assume no alarms */ + led_state = NORM_OP; + alarms = 0; + + /* And consider only carrier alarms */ + rh->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); + +#if SUPPORT_E1 + if (rh->ise1) { + /* XXX Implement me XXX */ + } else { +#endif + /* Detect loopup code if we're not sending one */ + if ((!rh->span.mainttimer) && (c & 0x20)) { + /* Loop-up code detected */ + led_state = 0xd0; + if (debug) + printk("R1T1: SR3 20 LOOP UP\n"); + if ((rh->loopupcnt++ > 80) && (rh->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { + __r1t1_set_reg(rh, DS2155_LBCR, 0x04); /* Remote Loop */ + rh->span.maintstat = DAHDI_MAINT_REMOTELOOP; + } + } else { + rh->loopupcnt = 0; + } + /* Same for loopdown code */ + if ((!rh->span.mainttimer) && (c & 0x40)) { + /* Loop-down code detected */ + if (debug) + printk("R1T1: SR3 04 LOOP DOWN\n"); + led_state = NORM_OP; + if ((rh->loopdowncnt++ > 80) && + (rh->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { + __r1t1_set_reg(rh, DS2155_LBCR, 0x0); /* No remote Loop */ + rh->span.maintstat = DAHDI_MAINT_NONE; + } + } else + rh->loopdowncnt = 0; +#if SUPPORT_E1 + } +#endif + + if (rh->span.lineconfig & DAHDI_CONFIG_NOTOPEN) { + for (x = 0, j = 0; x < rh->span.channels; x++) + /* + if ((rh->chans[x]->flags & DAHDI_FLAG_OPEN) || + (rh->chans[x]->flags & DAHDI_FLAG_NETDEV)) + */ + if ((rh->chans[x]->flags & DAHDI_FLAG_OPEN) ) + j++; + if (!j) + alarms |= DAHDI_ALARM_NOTOPEN; + } + + /* Check actual alarm status */ + __r1t1_set_reg(rh, DS2155_SR2, 0xff); + c = __r1t1_get_reg(rh, DS2155_SR2); + if (c & 0x4) { + led_state = YEL_ALM; + if (debug) + printk("R1T1: SR2 04 BLUE ALARM\n"); + alarms |= DAHDI_ALARM_BLUE; + } + if (c & 0x2) { + led_state = NO_CARR; + if (debug) + printk("R1T1: SR2 02 RED NO CARRIER\n"); + alarms |= DAHDI_ALARM_RED; + } + if (c & 0x1) { + led_state = NO_SYNC; + if (debug) + printk("R1T1: SR2 01 RED NO SYNC\n"); + alarms |= DAHDI_ALARM_RED; + } + + /* Keep track of recovering */ + if ((!alarms) && rh->span.alarms) + rh->alarmtimer = DAHDI_ALARMSETTLE_TIME; + + /* If receiving alarms, go into Yellow alarm state */ + if (alarms && (!rh->span.alarms)) { + if (rh->ise1) + __r1t1_set_reg(rh, DS2155_TNAF, 0x7f); + else + __r1t1_set_reg(rh, DS2155_T1TCR1, 0x11); + } + + if (rh->span.alarms != alarms) { + if (!(alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK)) && + rh->sync) { + /* Use the recieve signalling */ + rh->span.syncsrc = rh->span.spanno; + } else { + rh->span.syncsrc = 0; + } + } + if (rh->alarmtimer) { + alarms |= DAHDI_ALARM_RECOVER; + if (debug) + printk("R1T1: alarmtimer %x alarm clearing\n", rh->alarmtimer); + led_state = RECOVER; + } + if ((c & 0x8) && !(rh->ise1)) { + alarms |= DAHDI_ALARM_YELLOW; + if (debug) + printk("R1T1: SR2 08 YELLOW ALARM\n"); + led_state = YEL_ALM; + } + + rh->span.alarms = alarms; + c = __r1t1_get_reg(rh, R1T1_STATE / 4); + if (c != led_state) { + if (debug) + printk("R1T1: State was %x, Now setting to %x \n", c, led_state); + __r1t1_set_reg(rh, R1T1_STATE / 4, led_state); + } + dahdi_alarm_notify(&rh->span); +} + +static void __r1t1_do_counters(struct r1t1 *rh) +{ + if (rh->alarmtimer) { + if (!--rh->alarmtimer) { + rh->span.alarms &= ~(DAHDI_ALARM_RECOVER); + /* Clear yellow alarm */ + if (rh->ise1) + __r1t1_set_reg(rh, DS2155_TNAF, 0x5f); + else + __r1t1_set_reg(rh, DS2155_T1TCR1, 0x10); + dahdi_alarm_notify(&rh->span); + } + } +} + +DAHDI_IRQ_HANDLER(r1t1_interrupt) +{ + struct r1t1 *rh = dev_id; + unsigned long flags; + unsigned int x, nextbuf; + + nextbuf = ioread8(rh->ioaddr + 0x805) & 0x3; + + if (!(nextbuf & 2)) + return IRQ_NONE; + + nextbuf &= 1; + + rh->intcount++; + + --rh->clocktimeout; + + r1t1_receiveprep(rh, rh->nextbuf); + r1t1_transmitprep(rh, rh->nextbuf); + + spin_lock_irqsave(&rh->lock, flags); + + /* Acknowledge the interrupt */ + __r1t1_set_reg(rh, R1T1_CONTROL / 4, 0x03); + __r1t1_set_reg(rh, R1T1_CONTROL / 4, 0x01); + + /* Count down timers */ + __r1t1_do_counters(rh); + + /* Do some things that we don't have to do very often */ + x = rh->intcount & 15 /* 63 */ ; + switch (x) { + case 0: + case 1: + case 2: + __r1t1_check_sigbits(rh, x); + break; + case 4: + /* Check alarms 1/4 as frequently */ + if (!(rh->intcount & 0x30)) + __r1t1_check_alarms(rh); + break; + } + + rh->nextbuf = (rh->nextbuf + 1) & 0x01; + + spin_unlock_irqrestore(&rh->lock, flags); + + return IRQ_RETVAL(1); +} + + +#ifdef USE_G168_DSP + +inline void __r1t1_card_pci_out(struct r1t1 *rh, const unsigned int addr, + const unsigned int value) +{ + writel(value, &rh->membase[addr]); +} + +inline unsigned int __r1t1_card_pci_in(struct r1t1 *rh, const unsigned int addr) +{ + unsigned int value; + value = readl(&rh->membase[addr]); + return value; +} + +static void r1t1_card_reset_dsp(struct r1t1 *rh) +{ + unsigned long flags; + unsigned int hpi_c; + + spin_lock_irqsave(&rh->lock, flags); + hpi_c = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC); + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, (hpi_c & ~DSP_RST)); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, (hpi_c & ~DSP_RST)); + mdelay(100); + + rh->hpi_fast = 0; + rh->hpi_xadd = 0; + rh->dsp_sel = 0; + + __r1t1_card_pci_out(rh, R1T1_HCS_REG + TARG_REGS, 0); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, (hpi_c | DSP_RST)); + + spin_unlock_irqrestore(&rh->lock, flags); +} + + +int try_select_dsp(struct r1t1 *rh) +{ + int sel = __r1t1_card_pci_in(rh, R1T1_HCS_REG + TARG_REGS); + + if (sel == 0) { + + __r1t1_card_pci_out(rh, R1T1_HCS_REG + TARG_REGS, 1); + + rh->dsp_sel = 1; + return (0); + } + return (1); +} + +void r1t1_card_select_dsp(struct r1t1 *rh) +{ + int ridiculous = 0; + + while (try_select_dsp(rh)) { + ridiculous++; + if (ridiculous > 100000) { + printk("R1T1: Waited 10 seconds ... nothing happened. Quitting.\n"); + return; + } + } + return; +} + +void r1t1_card_unselect_dsp(struct r1t1 *rh) +{ + __r1t1_card_pci_out(rh, R1T1_HCS_REG + TARG_REGS, 0); + return; +} + +static unsigned short int r1t1_card_dsp_ping(struct r1t1 *rh) +{ + + gpakPingDspStat_t ping_stat; + unsigned short int dsp_ver; + + r1t1_card_select_dsp(rh); + + ping_stat = gpakPingDsp(rh, rh->num, &dsp_ver); + + if (debug & DEBUG_DSP) { + if (ping_stat == PngSuccess) + printk("R1T1: %d %d: G168 DSP Ping DSP Version %x\n", rh->num + 1, + rh->dsp_sel, dsp_ver); + else + printk("R1T1: %d %d: G168 DSP Ping Error %d\n", rh->num + 1, rh->dsp_sel, + ping_stat); + } + + r1t1_card_unselect_dsp(rh); + + if (ping_stat == PngSuccess) + return dsp_ver; + else + return 0; +} + +static int __devinit r1t1_span_download_dsp(struct r1t1 *rh) +{ + unsigned short int DspId; + gpakDownloadStatus_t dl_res = 0; + + r1t1_card_select_dsp(rh); + DspId = rh->num; + if ((dl_res = gpakDownloadDsp_5510(rh, DspId, app_file))) + printk("R1T1: %d DSP %d: G168 DSP App Loader Failed %d\n", rh->num + 1, 1, + dl_res); + else + printk("R1T1: %d DSP %d: G168 DSP App Loader Success %d\n", rh->num + 1, 1, + dl_res); + + r1t1_card_dsp_set(rh, DSP_IFBLK_ADDRESS, 0); + r1t1_card_dsp_set(rh, DSP_IFBLK_ADDRESS + 1, 0); + + r1t1_card_unselect_dsp(rh); + + if (dl_res) + return -1; + else + return 0; +} + +static void __devinit r1t1_span_run_dsp(struct r1t1 *rh) +{ + r1t1_card_select_dsp(rh); + r1t1_card_hpic_set(rh, R1T1_BL_GO); + r1t1_card_unselect_dsp(rh); + return; +} + +static GpakPortConfig_t Gpak_32_chan_port_config = { + + /* GpakSlotCfg_t SlotsSelect1 port 1 Slot selection */ + SlotCfgNone, + /* unsigned short int FirstBlockNum1 port 1 first group Block Number */ + 0x0000, + /* unsigned short int FirstSlotMask1 port 1 first group Slot Mask */ + 0x0000, + /* unsigned short int SecBlockNum1 port 1 second group Block Number */ + 0x0000, + /* unsigned short int SecSlotMask1 port 1 second group Slot Mask */ + 0x0000, + /* GpakSerWordSize_t SerialWordSize1 port 1 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode1 port 1 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity1 port 1 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity1 port 1 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity1 port 1 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity1 port 1 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay1 port 1 Tx data delay */ + DataDelay1, + /* GpakSerDataDelay_t RxDataDelay1 port 1 Rx data delay */ + DataDelay1, + /* GpakActivation DxDelay1 port 1 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask1 port 1 3rd group Slot Mask */ + 0x0000, + /* unsigned short int FouthSlotMask1 port 1 4th group Slot Mask */ + 0x0000, + /* unsigned short int FifthSlotMask1 port 1 5th group Slot Mask */ + 0x0000, + /* unsigned short int SixthSlotMask1 port 1 6th group Slot Mask */ + 0x0000, + /* unsigned short int SevenSlotMask1 port 1 7th group Slot Mask */ + 0x0000, + /* unsigned short int EightSlotMask1 port 1 8th group Slot Mask */ + 0x0000, + + /* GpakSlotCfg_t SlotsSelect2 port 2 Slot selection */ + SlotCfg8Groups, + /* unsigned short int FirstBlockNum2 port 2 first group Block Number */ + 0, + /* unsigned short int FirstSlotMask2 port 2 first group Slot Mask */ + 0x1110, + /* unsigned short int SecBlockNum2 port 2 second group Block Number */ + 1, + /* unsigned short int SecSlotMask2 port 2 second group Slot Mask */ + 0x1111, + /* GpakSerWordSize_t SerialWordSize2 port 2 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode2 port 2 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity2 port 2 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity2 port 2 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity2 port 2 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity2 port 2 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay2 port 2 Tx data delay */ + DataDelay1, + /* GpakSerDataDelay_t RxDataDelay2 port 2 Rx data delay */ + DataDelay1, + /* GpakActivation DxDelay2 port 2 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask2 port 2 3rd group Slot Mask */ + 0x1111, + /* unsigned short int FouthSlotMask2 port 2 4th group Slot Mask */ + 0x1111, + /* unsigned short int FifthSlotMask2 port 2 5th group Slot Mask */ + 0x1111, + /* unsigned short int SixthSlotMask2 port 2 6th group Slot Mask */ + 0x1111, + /* unsigned short int SevenSlotMask2 port 2 7th group Slot Mask */ + 0x1111, + /* unsigned short int EightSlotMask2 port 2 8th group Slot Mask */ + 0x1111, + + /* GpakSlotCfg_t SlotsSelect3 port 3 Slot selection */ + SlotCfg8Groups, + /* unsigned short int FirstBlockNum3 port 3 first group Block Number */ + 0, + /* unsigned short int FirstSlotMask3 port 3 first group Slot Mask */ + 0x1110, + /* unsigned short int SecBlockNum3 port 3 second group Block Number */ + 1, + /* unsigned short int SecSlotMask3 port 3 second group Slot Mask */ + 0x1111, + /* GpakSerWordSize_t SerialWordSize3 port 3 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode3 port 3 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity3 port 3 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity3 port 3 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity3 port 3 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity3 port 3 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay3 port 3 Tx data delay */ + DataDelay1, + /* GpakSerDataDelay_t RxDataDelay3 port 3 Rx data delay */ + DataDelay1, + /* GpakActivation DxDelay3 port 3 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask3 port 3 3rd group Slot Mask */ + 0x1111, + /* unsigned short int FouthSlotMask3 port 3 4th group Slot Mask */ + 0x1111, + /* unsigned short int FifthSlotMask3 port 3 5th group Slot Mask */ + 0x1111, + /* unsigned short int SixthSlotMask3 port 3 6th group Slot Mask */ + 0x1111, + /* unsigned short int SevenSlotMask3 port 3 7th group Slot Mask */ + 0x1111, + /* unsigned short int EightSlotMask3 port 3 8th group Slot Mask */ + 0x1111, +}; + + +static void r1t1_card_dsp_show_portconfig(GpakPortConfig_t PortConfig) +{ + if (debug & DEBUG_DSP) { + printk("%x = %s\n", PortConfig.SlotsSelect1, "SlotsSelect1"); + printk("%x = %s\n", PortConfig.FirstBlockNum1, "FirstBlockNum1"); + printk("%x = %s\n", PortConfig.FirstSlotMask1, "FirstSlotMask1"); + printk("%x = %s\n", PortConfig.SecBlockNum1, "SecBlockNum1"); + printk("%x = %s\n", PortConfig.SecSlotMask1, "SecSlotMask1"); + printk("%x = %s\n", PortConfig.SerialWordSize1, "SerialWordSize1"); + printk("%x = %s\n", PortConfig.CompandingMode1, "CompandingMode1"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity1, "TxFrameSyncPolarity1"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity1, "RxFrameSyncPolarity1"); + printk("%x = %s\n", PortConfig.TxClockPolarity1, "TxClockPolarity1"); + printk("%x = %s\n", PortConfig.RxClockPolarity1, "RxClockPolarity1"); + printk("%x = %s\n", PortConfig.TxDataDelay1, "TxDataDelay1"); + printk("%x = %s\n", PortConfig.RxDataDelay1, "RxDataDelay1"); + printk("%x = %s\n", PortConfig.DxDelay1, "DxDelay1"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask1, "ThirdSlotMask1"); + printk("%x = %s\n", PortConfig.FouthSlotMask1, "FouthSlotMask1"); + printk("%x = %s\n", PortConfig.FifthSlotMask1, "FifthSlotMask1"); + printk("%x = %s\n", PortConfig.SixthSlotMask1, "SixthSlotMask1"); + printk("%x = %s\n", PortConfig.SevenSlotMask1, "SevenSlotMask1"); + printk("%x = %s\n", PortConfig.EightSlotMask1, "EightSlotMask1"); + + printk("%x = %s\n", PortConfig.SlotsSelect2, "SlotsSelect2"); + printk("%x = %s\n", PortConfig.FirstBlockNum2, "FirstBlockNum2"); + printk("%x = %s\n", PortConfig.FirstSlotMask2, "FirstSlotMask2"); + printk("%x = %s\n", PortConfig.SecBlockNum2, "SecBlockNum2"); + printk("%x = %s\n", PortConfig.SecSlotMask2, "SecSlotMask2"); + printk("%x = %s\n", PortConfig.SerialWordSize2, "SerialWordSize2"); + printk("%x = %s\n", PortConfig.CompandingMode2, "CompandingMode2"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity2, "TxFrameSyncPolarity2"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity2, "RxFrameSyncPolarity2"); + printk("%x = %s\n", PortConfig.TxClockPolarity2, "TxClockPolarity2"); + printk("%x = %s\n", PortConfig.RxClockPolarity2, "RxClockPolarity2"); + printk("%x = %s\n", PortConfig.TxDataDelay2, "TxDataDelay2"); + printk("%x = %s\n", PortConfig.RxDataDelay2, "RxDataDelay2"); + printk("%x = %s\n", PortConfig.DxDelay2, "DxDelay2"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask2, "ThirdSlotMask2"); + printk("%x = %s\n", PortConfig.FouthSlotMask2, "FouthSlotMask2"); + printk("%x = %s\n", PortConfig.FifthSlotMask2, "FifthSlotMask2"); + printk("%x = %s\n", PortConfig.SixthSlotMask2, "SixthSlotMask2"); + printk("%x = %s\n", PortConfig.SevenSlotMask2, "SevenSlotMask2"); + printk("%x = %s\n", PortConfig.EightSlotMask2, "EightSlotMask2"); + + printk("%x = %s\n", PortConfig.SlotsSelect3, "SlotsSelect3"); + printk("%x = %s\n", PortConfig.FirstBlockNum3, "FirstBlockNum3"); + printk("%x = %s\n", PortConfig.FirstSlotMask3, "FirstSlotMask3"); + printk("%x = %s\n", PortConfig.SecBlockNum3, "SecBlockNum3"); + printk("%x = %s\n", PortConfig.SecSlotMask3, "SecSlotMask3"); + printk("%x = %s\n", PortConfig.SerialWordSize3, "SerialWordSize3"); + printk("%x = %s\n", PortConfig.CompandingMode3, "CompandingMode3"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity3, "TxFrameSyncPolarity3"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity3, "RxFrameSyncPolarity3"); + printk("%x = %s\n", PortConfig.TxClockPolarity3, "TxClockPolarity3"); + printk("%x = %s\n", PortConfig.RxClockPolarity3, "RxClockPolarity3"); + printk("%x = %s\n", PortConfig.TxDataDelay3, "TxDataDelay3"); + printk("%x = %s\n", PortConfig.RxDataDelay3, "RxDataDelay3"); + printk("%x = %s\n", PortConfig.DxDelay3, "DxDelay3"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask3, "ThirdSlotMask3"); + printk("%x = %s\n", PortConfig.FouthSlotMask3, "FouthSlotMask3"); + printk("%x = %s\n", PortConfig.FifthSlotMask3, "FifthSlotMask3"); + printk("%x = %s\n", PortConfig.SixthSlotMask3, "SixthSlotMask3"); + printk("%x = %s\n", PortConfig.SevenSlotMask3, "SevenSlotMask3"); + printk("%x = %s\n", PortConfig.EightSlotMask3, "EightSlotMask3"); + + } + return; +} + +static int __devinit r1t1_span_dsp_configureports(struct r1t1 *rh, + GpakPortConfig_t PortConfig) +{ + gpakConfigPortStatus_t cp_res; + GPAK_PortConfigStat_t cp_error; + unsigned short int DspId; + + r1t1_card_dsp_show_portconfig(PortConfig); + + r1t1_card_select_dsp(rh); + DspId = rh->num; + + if ((cp_res = gpakConfigurePorts(rh, DspId, &PortConfig, &cp_error))) + printk("R1T1: %d DSP %d: G168 DSP Port Config failed res = %d error = %d\n", + rh->num + 1, 1, cp_res, cp_error); + else if (debug & DEBUG_DSP) { + printk("R1T1: %d DSP %d: G168 DSP Port Config success %d\n", rh->num + 1, 1, + cp_res); + } + + r1t1_card_unselect_dsp(rh); + + if (cp_res) + return -1; + else + return 0; +} + +static GpakChannelConfig_t Gpak_chan_config = { + + /* GpakSerialPort_t PCM Input Serial Port A Id */ + SerialPort2, + /* unsigned short int PCM Input Time Slot */ + 0, + /* GpakSerialPort_t PCM Output Serial Port A Id */ + SerialPort3, + /* unsigned short int PCM Output Time Slot */ + 0, + /* GpakSerialPort_t PCM Input Serial Port B Id */ + SerialPort3, + /* unsigned short int PCM Input Time Slot */ + 0, + /* GpakSerialPort_t PCM Output Serial Port B Id */ + SerialPortNull, + /* unsigned short int PCM Output Time Slot */ + 0, + /* GpakToneTypes ToneTypesA A side Tone Detect Types */ + Null_tone, + /* GpakToneTypes ToneTypesB B side Tone Detect Types */ + Null_tone, + /* GpakActivation Echo Cancel A Enabled */ + Disabled, + /* GpakActivation Echo Cancel B Enabled */ + Disabled, + + { + /* short int Echo Can Num Taps (tail length) 64 = 512 32 = 256 */ + 1024, + /* short int Echo Can NLP Type */ + 3, + /* short int Echo Can Adapt Enable flag */ + 1, + /* short int Echo Can G165 Detect Enable flag */ + 1, + /* short int Echo Can Double Talk threshold */ + 4, + /* short int Echo Can NLP threshold */ + 21, + /* short int Dynamic NLP control, NLP limit when EC about to converged */ + 17, + /* short int Dynamic NLP control, NLP limit when EC not converged yet */ + 12, + /* short int suppression level for NLP_SUPP mode */ + 0, + /* short int Echo Can CNG Noise threshold */ + 50, + /* short int Echo Can Max Adapts per frame */ + 40, + /* short int Echo Can Cross Correlation limit */ + 20, + /* short int Echo Can Num FIR Segments */ + 3, + /* short int Echo Can FIR Segment Length */ + 64, + }, + + { + /* short int Echo Can Num Taps (tail length) */ + 1024, + /* short int Echo Can NLP Type */ + 3, + /* short int Echo Can Adapt Enable flag */ + 1, + /* short int Echo Can G165 Detect Enable flag */ + 1, + /* short int Echo Can Double Talk threshold */ + 4, + /* short int Echo Can NLP threshold */ + 21, + /* short int Dynamic NLP control, NLP limit when EC about to converged */ + 17, + /* short int Dynamic NLP control, NLP limit when EC not converged yet */ + 12, + /* short int suppression level for NLP_SUPP mode */ + 0, + /* short int Echo Can CNG Noise threshold */ + 50, + /* short int Echo Can Max Adapts per frame */ + 40, + /* short int Echo Can Cross Correlation limit */ + 20, + /* short int Echo Can Num FIR Segments */ + 3, + /* short int Echo Can FIR Segment Length */ + 64, + }, + + /* GpakCompandModes software companding */ + cmpNone, + /* GpakRate_t Gpak Frame Rate */ + rate2ms, + Disabled, + Disabled, + Disabled, + Disabled +}; + +static void r1t1_card_dsp_show_chanconfig(GpakChannelConfig_t ChanConfig) +{ + if (debug & DEBUG_DSP) { + printk("%d = %s\n", ChanConfig.PcmInPortA, "PcmInPortA"); + printk("%d = %s\n", ChanConfig.PcmInSlotA, "PcmInSlotA"); + printk("%d = %s\n", ChanConfig.PcmOutPortA, "PcmOutPortA"); + printk("%d = %s\n", ChanConfig.PcmOutSlotA, "PcmOutSlotA"); + printk("%d = %s\n", ChanConfig.PcmInPortB, "PcmInPortB"); + printk("%d = %s\n", ChanConfig.PcmInSlotB, "PcmInSlotB"); + printk("%d = %s\n", ChanConfig.PcmOutPortB, "PcmOutPortB"); + printk("%d = %s\n", ChanConfig.PcmOutSlotB, "PcmOutSlotB"); + + printk("%d = %s\n", ChanConfig.ToneTypesA, "ToneTypesA"); + printk("%d = %s\n", ChanConfig.ToneTypesB, "ToneTypesB"); + + printk("%d = %s\n", ChanConfig.EcanEnableA, "EcanEnableA"); + printk("%d = %s\n", ChanConfig.EcanEnableB, "EcanEnableB"); + + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanTapLength, + "EcanParametersA.EcanTapLength"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpType, + "EcanParametersA.EcanNlpType"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanAdaptEnable, + "EcanParametersA.EcanAdaptEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanG165DetEnable, + "EcanParametersA.EcanG165DetEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanDblTalkThresh, + "EcanParametersA.EcanDblTalkThresh"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpThreshold, + "EcanParametersA.EcanNlpThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpConv, + "EcanParametersA.EcanNlpConv"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpUnConv, + "EcanParametersA.EcanNlpUnConv"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpMaxSuppress, + "EcanParametersA.EcanNlpMaxSuppress"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanCngThreshold, + "EcanParametersA.EcanCngThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanAdaptLimit, + "EcanParametersA.EcanAdaptLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanCrossCorrLimit, + "EcanParametersA.EcanCrossCorrLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNumFirSegments, + "EcanParametersA.EcanNumFirSegments"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanFirSegmentLen, + "EcanParametersA.EcanFirSegmentLen"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanTapLength, + "EcanParametersB.EcanTapLength"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpType, + "EcanParametersB.EcanNlpType"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanAdaptEnable, + "EcanParametersB.EcanAdaptEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanG165DetEnable, + "EcanParametersB.EcanG165DetEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanDblTalkThresh, + "EcanParametersB.EcanDblTalkThresh"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpThreshold, + "EcanParametersB.EcanNlpThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpConv, + "EcanParametersB.EcanNlpConv"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpUnConv, + "EcanParametersB.EcanNlpUnConv"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpMaxSuppress, + "EcanParametersB.EcanNlpMaxSuppress"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanCngThreshold, + "EcanParametersB.EcanCngThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanAdaptLimit, + "EcanParametersB.EcanAdaptLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanCrossCorrLimit, + "EcanParametersB.EcanCrossCorrLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNumFirSegments, + "EcanParametersB.EcanNumFirSegments"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanFirSegmentLen, + "EcanParametersB.EcanFirSegmentLen"); + + printk("%d = %s\n", ChanConfig.SoftwareCompand, "SoftwareCompand"); + + printk("%d = %s\n", ChanConfig.FrameRate, "FrameRate"); + + printk("%d = %s\n", ChanConfig.MuteToneA, "MuteToneA"); + printk("%d = %s\n", ChanConfig.MuteToneB, "MuteToneB"); + printk("%d = %s\n", ChanConfig.FaxCngDetA, "FaxCngDetA"); + printk("%d = %s\n", ChanConfig.FaxCngDetB, "FaxCngDetB"); + + } + return; +} + +static int __devinit r1t1_span_dsp_configurechannel(struct r1t1 *rh, + GpakChannelConfig_t ChanConfig, + int chan_num) +{ + GPAK_ChannelConfigStat_t chan_config_err; + gpakConfigChanStatus_t chan_conf_stat; + unsigned short int DspId; + + r1t1_card_dsp_show_chanconfig(ChanConfig); + + r1t1_card_select_dsp(rh); + DspId = rh->num; + + if ((chan_conf_stat = + gpakConfigureChannel(rh, DspId, chan_num, tdmToTdm, &Gpak_chan_config, + &chan_config_err))) + printk("R1T1: %d DSP %d: Chan %d G168 DSP Chan Config failed error = %d %d\n", + rh->num + 1, 1, chan_num, chan_config_err, chan_conf_stat); + else if (debug & DEBUG_DSP) { + printk("R1T1: %d DSP %d: G168 DSP Chan %d Config success %d\n", rh->num + 1, 1, + chan_num, chan_conf_stat); + } + + r1t1_card_unselect_dsp(rh); + + if (chan_conf_stat) + return -1; + else + return 0; +} + +static void r1t1_card_dsp_framestats(struct r1t1 *rh) +{ + gpakReadFramingStatsStatus_t framing_status_status; + unsigned short int ec1, ec2, ec3, dmaec, slips[6]; + unsigned short int DspId; + + r1t1_card_select_dsp(rh); + DspId = rh->num; + + if (debug & DEBUG_DSP) { + framing_status_status = + gpakReadFramingStats(rh, DspId, &ec1, &ec2, &ec3, &dmaec, &slips[0]); + if (framing_status_status == RfsSuccess) { + printk("R1T1: %d DSP %d: G168 DSP Framing Status Success %d\n", rh->num + 1, + 1, framing_status_status); + if (ec1 + ec2 + ec3 + dmaec + slips[0] + slips[1] + slips[2] + slips[3] + + slips[4] + slips[5]) { + printk + ("R1T1: %d DSP %d: G168 DSP Framing Status p1 %2d p2 %2d p3 %2d stop %2d\n", + rh->num + 1, 1, ec1, ec2, ec3, dmaec); + printk + ("R1T1: %d DSP %d: G168 DSP Framing Status slip0 %2d slip1 %2d slip2 %2d slip3 %2d slip4 %2d slip5 %2d\n", + 1, 1, slips[0], slips[1], slips[2], slips[3], slips[4], slips[5]); + } else + printk("R1T1: %d DSP %d: G168 DSP Framing Status GOOD!!\n", rh->num + 1, + 1); + } else { + printk("R1T1: %d DSP %d: G168 DSP Framing Status Failed %d\n", rh->num + 1, 1, + framing_status_status); + printk("R1T1: %d DSP %d: G168 DSP Framing Status %d %d %d %d %d\n", + rh->num + 1, 1, ec1, ec2, ec3, dmaec, slips[0]); + } + } + + r1t1_card_unselect_dsp(rh); + return; +} + +static void r1t1_card_dsp_reetframestats(struct r1t1 *rh) +{ + gpakResetFramingStatsStatus_t framing_reset_status; + unsigned short int DspId; + + r1t1_card_select_dsp(rh); + DspId = rh->num; + + if ((framing_reset_status = gpakResetFramingStats(rh, DspId))) + printk("R1T1: %d DSP %d: G168 DSP Reset Framing Stats Failed %d\n", rh->num + 1, + 1, framing_reset_status); + else + printk("R1T1: %d DSP %d: G168 DSP Reset Framing Stats Success %d\n", rh->num + 1, + 1, framing_reset_status); + + r1t1_card_unselect_dsp(rh); + return; +} + +static void r1t1_card_dsp_cpustats(struct r1t1 *rh) +{ + gpakReadCpuUsageStat_t cpu_status_status; + unsigned short int pPeakUsage, pPrev1SecPeakUsage; + unsigned short int DspId; + + r1t1_card_select_dsp(rh); + DspId = rh->num; + + cpu_status_status = gpakReadCpuUsage(rh, DspId, &pPeakUsage, &pPrev1SecPeakUsage); + if (cpu_status_status) + printk("R1T1: %d DSP %d: G168 DSP CPU Status Failed %d\n", rh->num + 1, 1, + cpu_status_status); + else + printk("R1T1: %d DSP %d: G168 DSP CPU Status peek %2d 1 S %2d\n", rh->num + 1, 1, + pPeakUsage, pPrev1SecPeakUsage); + + + r1t1_card_unselect_dsp(rh); + return; +} + +static void r1t1_chan_ec_enable(struct r1t1 *rh, int chan_num) +{ + gpakAlgControlStat_t a_c_stat; + GPAK_AlgControlStat_t a_c_err; + unsigned short int DspId; + unsigned int mask, slot_num; + + if (ec_disable & (1 << chan_num)) { + if (debug & DEBUG_DSP) + printk("r1t1 %d: Echo Can NOT enable DSP EC Chan %d\n", rh->num + 1, + chan_num); + return; + } + + DspId = rh->num; + + if (rh->ise1) + slot_num = chanmap_e1[chan_num]; + else + slot_num = chanmap_t1[chan_num]; + + if (debug & DEBUG_DSP) + printk("R1T1: %d: Echo Can enable DSP %d EC Chan %d\n", rh->num + 1, 1, chan_num); + + r1t1_card_select_dsp(rh); + + if ((a_c_stat = gpakAlgControl(rh, DspId, chan_num, EnableEcanB, &a_c_err))) { + if ((a_c_stat = gpakAlgControl(rh, DspId, chan_num, EnableEcanB, &a_c_err))) { + if ((a_c_stat = gpakAlgControl(rh, DspId, chan_num, EnableEcanB, &a_c_err))) { + printk + ("R1T1: %d: G168 DSP Enable Alg Control failed res = %d error = %d\n", + rh->num + 1, a_c_stat, a_c_err); + } + } + } + + mask = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_ECA1); + mask |= (1 << slot_num); + + r1t1_card_unselect_dsp(rh); + + return; +} + +static void r1t1_chan_ec_disable(struct r1t1 *rh, int chan_num) +{ + gpakAlgControlStat_t a_c_stat; + GPAK_AlgControlStat_t a_c_err; + unsigned short int DspId; + unsigned int mask, slot_num; + + DspId = rh->num; + + if (rh->ise1) + slot_num = chanmap_e1[chan_num]; + else + slot_num = chanmap_t1[chan_num]; + + if (debug & DEBUG_DSP) + printk("R1T1: %d: Echo Can disable DSP %d EC Chan %d\n", rh->num + 1, 1, + chan_num); + + r1t1_card_select_dsp(rh); + + if ((a_c_stat = gpakAlgControl(rh, DspId, chan_num, BypassEcanB, &a_c_err))) { + if ((a_c_stat = gpakAlgControl(rh, DspId, chan_num, BypassEcanB, &a_c_err))) { + if ((a_c_stat = gpakAlgControl(rh, DspId, chan_num, BypassEcanB, &a_c_err))) { + printk + ("R1T1: %d: G168 DSP Disable Alg Control failed res = %d error = %d\n", + rh->num + 1, a_c_stat, a_c_err); + } + } + } + + mask = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_ECA1); + mask &= ~(1 << slot_num); + + r1t1_card_unselect_dsp(rh); + + return; +} + + +static int r1t1_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, + struct dahdi_echocan_state **ec) +{ + struct dahdi_span *span = chan->span; + struct r1t1 *rh = container_of(span, struct r1t1, span); + int chan_num; + + chan_num = chan->chanpos - 1; + + if (ecp->param_count > 0) { + printk(KERN_WARNING + "R1T1 echo canceller does not support parameters; failing request\n"); + return -EINVAL; + } + + if (debug & DEBUG_DSP) { + printk("R1T1: %d Echo Can control Span %d Chan %d dahdi_chan %d\n", rh->num + 1, + 1, chan_num, chan->channo); + printk("DSP up %x\n", rh->dsp_up); + } + if (rh->dsp_up == 1) { + *ec = rh->ec[chan_num]; + (*ec)->ops = &my_ec_ops; + (*ec)->features = my_ec_features; + rh->nextec |= (1 << chan_num); + queue_work(rh->wq, &rh->work); + } + return 0; +} + +static void r1t1_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) +{ + struct dahdi_span *span = chan->span; + struct r1t1 *rh = container_of(span, struct r1t1, span); + int chan_num; + + memset(ec, 0, sizeof(*ec)); + chan_num = chan->chanpos - 1; + + if (debug & DEBUG_DSP) { + printk("R1T1: %d Echo Can control Span %d Chan %d dahdi_chan %d\n", rh->num + 1, + 1, chan_num, chan->channo); + printk("DSP up %x\n", rh->dsp_up); + } + + if (rh->dsp_up == 1) { + rh->nextec &= ~(1 << chan_num); + queue_work(rh->wq, &rh->work); + } +} + + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void echocan_bh(void *data) +{ + struct r1t1 *rh = data; +#else +static void echocan_bh(struct work_struct *data) +{ + struct r1t1 *rh = container_of(data, struct r1t1, work); +#endif + unsigned int todo, chan_num; + + todo = rh->nextec ^ rh->currec; + if (debug & DEBUG_DSP) { + printk("R1T1: %d Echo Can control bh change %x to %x\n", rh->num + 1, todo, + (rh->nextec & todo)); + printk("nextec %x currec %x\n", rh->nextec, rh->currec); + printk("span.channels = %d\n", rh->span.channels); + } + for (chan_num = 0; chan_num < rh->span.channels; chan_num++) { + if (todo & (1 << chan_num)) { + if (rh->nextec & (1 << chan_num)) { + r1t1_chan_ec_enable(rh, chan_num); + rh->currec |= (1 << chan_num); + schedule(); + } else { + r1t1_chan_ec_disable(rh, chan_num); + rh->currec &= ~(1 << chan_num); + schedule(); + } + } + } +} + + +static int __devinit r1t1_card_init_dsp(struct r1t1 *rh) +{ + int loops = 0; + __u16 high, low; + int chan_num, chan_count, slot_num; + int ifb_z = 4; + + if (debug & DEBUG_DSP) + printk("R1T1: Reset DSP\n"); + + r1t1_card_reset_dsp(rh); + + if (debug & DEBUG_DSP) + printk("R1T1: Un-Reset DSP\n"); + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_ECB1, 0x00000000); /* use ec b */ + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_ECA1, 0x00000000); /* use ec a */ + + if (no_ec) + return -1; + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, + (~EC_ON & __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC))); + + if (r1t1_span_download_dsp(rh)) { + return -1; + } + + r1t1_span_run_dsp(rh); + if (debug & DEBUG_DSP) + printk("R1T1: %d DSP %d: GO!!\n", rh->num + 1, 1); + + while (ifb_z != 0) { + ifb_z = 0; + msleep(1); + r1t1_card_select_dsp(rh); + high = r1t1_card_dsp_get(rh, DSP_IFBLK_ADDRESS); + low = r1t1_card_dsp_get(rh, DSP_IFBLK_ADDRESS + 1); + + if (debug & DEBUG_DSP) + printk("R1T1: %d DSP %d: IfBlockPntr %x\n", rh->num + 1, 1, + ((high << 16) + low)); + + if ((high == 0) && (low == 0)) + ifb_z++; + + r1t1_card_unselect_dsp(rh); + schedule(); + + if ((loops++) > 2) { + printk("R1T1: DSP not responding...is EC installed?\n"); + return -1; + } + } + + rh->hpi_fast = 0; + + r1t1_card_dsp_ping(rh); + + if (r1t1_span_dsp_configureports(rh, Gpak_32_chan_port_config)) + return -1; + + Gpak_chan_config.EcanParametersA.EcanNlpType = nlp_type; + Gpak_chan_config.EcanParametersB.EcanNlpType = nlp_type; + + Gpak_chan_config.EcanEnableB = Enabled; + + Gpak_chan_config.EcanEnableA = Disabled; + Gpak_chan_config.SoftwareCompand = cmpNone; + + r1t1_card_dsp_ping(rh); + chan_count = 0; + + for (chan_num = 0; chan_num < rh->span.channels; chan_num++) { + chan_count++; + + if (rh->ise1) { + unsigned int hpi_c; + hpi_c = __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, (hpi_c | XLATE)); + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_XLATE_EN, 0xffff7fff); + slot_num = chanmap_e1[chan_num]; + if (chan_num != 15) + Gpak_chan_config.SoftwareCompand = cmpPCMU; + else + Gpak_chan_config.SoftwareCompand = cmpNone; + } else { + slot_num = chanmap_t1[chan_num]; + Gpak_chan_config.SoftwareCompand = cmpPCMU; + } + + Gpak_chan_config.PcmInSlotA = slot_num * 4; + Gpak_chan_config.PcmOutSlotA = slot_num * 4; + Gpak_chan_config.PcmInSlotB = slot_num * 4; + Gpak_chan_config.PcmOutSlotB = slot_num * 4; + + if (r1t1_span_dsp_configurechannel(rh, Gpak_chan_config, chan_num)) + return -1; + + r1t1_chan_ec_disable(rh, chan_num); + } + + printk("R1T1: %d DSP %d: %d channels configured\n", rh->num + 1, 1, chan_count); + + rh->dsp_up = 1; + + if (debug & DEBUG_DSP) { + + r1t1_card_dsp_cpustats(rh); + r1t1_card_dsp_framestats(rh); + r1t1_card_dsp_reetframestats(rh); + + msleep(400); + + r1t1_card_dsp_cpustats(rh); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_cpustats(rh); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + msleep(400); + r1t1_card_dsp_framestats(rh); + } + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_HPIC, + (EC_ON | __r1t1_card_pci_in(rh, TARG_REGS + R1T1_HPIC))); + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_ECB1, 0x00000000); /* use ec b */ + + __r1t1_card_pci_out(rh, TARG_REGS + R1T1_ECA1, ec_sw); /* use ec a */ + + r1t1_card_dsp_ping(rh); + + rh->wq = create_singlethread_workqueue("r1t1_ec"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&rh->work, echocan_bh, rh); +#else + INIT_WORK(&rh->work, echocan_bh); +#endif + + return (0); +} + +#endif /* USE_G168_DSP */ + +static int r1t1_hardware_init(struct r1t1 *rh) +{ + /* Setup DMA Addresses */ + /* Start at writedma */ + iowrite32(rh->writedma, rh->ioaddr + R1T1_TXBUFSTART); /* Write start */ + ioread32(rh->ioaddr + R1T1_TXBUFSTART); + iowrite32(rh->readdma, rh->ioaddr + R1T1_RXBUFSTART); /* Read start */ + ioread32(rh->ioaddr + R1T1_RXBUFSTART); + iowrite16((DAHDI_CHUNKSIZE * 32 * 2) >> 2, rh->ioaddr + R1T1_BUFLEN); + ioread16(rh->ioaddr + R1T1_BUFLEN); + + if (rh->ise1) { + rh->chanmap = chanmap_e1; + } else + rh->chanmap = chanmap_t1; + + rh->clocktimeout = 100; + + /* Reset the T1 and report */ + r1t1_framer_hard_reset(rh); + + return 0; + +} + +static int __devinit r1t1_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct r1t1 *rh; + unsigned int *canary; + int x; + struct dahdi_chan *chan_block; + struct dahdi_echocan_state *ec_block; + int chan_count; + + if (debug) + printk("R1T1: init_one debug=%x e1=%d\n", debug, e1); + + if (pci_enable_device(pdev)) { + printk("R1T1: No Rhino spotted\n"); + return -EIO; + } + + /* Find position */ + for (x = 0; x < RH_MAX_CARDS; x++) { + if (!cards[x]) { + break; + } + } + + if (x >= RH_MAX_CARDS) + return -1; + + rh = kmalloc(sizeof *rh, GFP_KERNEL); + + if (rh == NULL) { + printk("R1T1: No memory available for card\n"); + return -ENOMEM; + } + + memset(rh, 0x0, sizeof *rh); + rh->num = x; + cards[rh->num] = rh; + spin_lock_init(&rh->lock); + rh->dev = pdev; + rh->pciaddr = pci_resource_start(pdev, 0); + + if (e1 & (1 << rh->num)) { + rh->ise1 = 1; + rh->variety = "Rhino R1T1 E1/PRA"; + printk("R1T1: %x configured E1 by module_param\n", rh->num); + } else { + rh->ise1 = 0; + rh->variety = "Rhino R1T1 T1/PRI"; + printk("R1T1: %x configured as T1\n", rh->num); + } + + chan_count = rh->ise1 ? 31 : 24; + chan_block = kmalloc(chan_count * sizeof *chan_block, GFP_KERNEL); + ec_block = kmalloc(chan_count * sizeof *ec_block, GFP_KERNEL); + + if (chan_block == NULL || ec_block == NULL) { + if (chan_block) + kfree(chan_block); + + if (ec_block) + kfree(ec_block); + + kfree(rh); + + printk("R1T1: No memory available for chans/ec\n"); + return -ENOMEM; + } + + memset(chan_block, 0, chan_count * sizeof *chan_block); + memset(ec_block, 0, chan_count * sizeof *ec_block); + + for (x = 0; x < chan_count; x++) { + rh->chans[x] = chan_block + x; + rh->ec[x] = ec_block + x; + } + + printk("R1T1: pciaddr = %x \n", (__u32) rh->pciaddr); + + if (!request_mem_region(rh->pciaddr, R1T1_SIZE, "R1T1")) { + printk("R1T1: Unable to claim R1T1 PCI space\n"); + kfree(chan_block); + kfree(ec_block); + cards[rh->num] = NULL; + kfree(rh); + return -ENOMEM; + } + + printk("R1T1: claimed R1T1 PCI space\n"); + + rh->ioaddr = ioremap_nocache((dma_addr_t) rh->pciaddr, R1T1_SIZE); + rh->membase = rh->ioaddr; + printk("R1T1: mapped R1T1 PCI space to %x\n", (__u32) (dma_addr_t) rh->ioaddr); + + rh->writechunk = + /* 32 channels, Double-buffer, Read/Write */ + (unsigned char *) pci_alloc_consistent(pdev, + DAHDI_MAX_CHUNKSIZE * 32 * 2 * 2 + + 8, &rh->writedma); + if (!rh->writechunk) { + printk("R1T1: Unable to allocate DMA-able memory\n"); + kfree(chan_block); + kfree(ec_block); + iounmap(rh->ioaddr); + cards[rh->num] = NULL; + kfree(rh); + return -ENOMEM; + } + + /* Read is after the whole write piece (in bytes) */ + rh->readchunk = rh->writechunk + DAHDI_CHUNKSIZE * 32 * 2; + + /* Same thing... */ + rh->readdma = rh->writedma + DAHDI_CHUNKSIZE * 32 * 2; + + /* Initialize Write/Buffers to all blank data */ + memset((void *) rh->writechunk, 0x00, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32); + /* Initialize canary */ + canary = (unsigned int *) (rh->readchunk + DAHDI_CHUNKSIZE * 64 - 4); + *canary = (CANARY << 16) | (0xffff); + + rh->nextbuf = 0; + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* Keep track of which device we are */ + pci_set_drvdata(pdev, rh); + + /* Disable interrupts on the board before enabling them in Linux */ + __r1t1_set_reg(rh, R1T1_CONTROL / 4, 0x00); + + if (request_irq(pdev->irq, r1t1_interrupt, DAHDI_IRQ_SHARED, "r1t1", rh)) { + printk("R1T1: Unable to request IRQ %d\n", pdev->irq); + iounmap(rh->ioaddr); + release_mem_region(rh->pciaddr, R1T1_SIZE); + pci_free_consistent(rh->dev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 + 8, + (void *) rh->writechunk, rh->writedma); + kfree(chan_block); + kfree(ec_block); + cards[rh->num] = NULL; + kfree(rh); + return -EIO; + } + + rh->version = ioread16(rh->ioaddr + R1T1_VERSION); + + printk("R1T1: Version %d\n", rh->version); + + if (rh->version < 36) { + printk("R1T1: Found HW version less than 36, need to upgrade your hardware!\n"); + iounmap(rh->ioaddr); + release_mem_region(rh->pciaddr, R1T1_SIZE); + pci_free_consistent(rh->dev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 + 8, + (void *) rh->writechunk, rh->writedma); + free_irq(pdev->irq, rh); + kfree(chan_block); + kfree(ec_block); + cards[rh->num] = NULL; + kfree(rh); + return -1; + } + + /* Initialize hardware */ + r1t1_hardware_init(rh); + + /* Misc. software stuff */ + r1t1_software_init(rh); + +#ifdef USE_G168_DSP + rh->dsp_type = DSP_5510; + r1t1_card_init_dsp(rh); +#endif /* USE_G168_DSP */ + + printk("R1T1: Spotted a Rhino: %s version %d. Module Version " DAHDI_VERSION + "\n", rh->variety, rh->version); + + return 0; +} + +static void __devexit r1t1_remove_one(struct pci_dev *pdev) +{ + struct r1t1 *rh = pci_get_drvdata(pdev); + if (rh) { +#ifdef USE_G168_DSP + if (rh->dsp_up) { + flush_workqueue(rh->wq); + destroy_workqueue(rh->wq); + } +#endif /* USE_G168_DSP */ + + r1t1_shutdown(&rh->span); + + /* Release span, possibly delayed */ + if (!rh->usecount) + r1t1_release(rh); + else + rh->dead = 1; + } +} + +static struct pci_device_id r1t1_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_RHINO, PCI_DEVICE_R1T1)}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, r1t1_pci_tbl); + +static struct pci_driver r1t1_driver = { + name:"r1t1", + probe:r1t1_init_one, + remove:__devexit_p(r1t1_remove_one), + suspend:NULL, + resume:NULL, + id_table:r1t1_pci_tbl, +}; + +static int __init r1t1_init(void) +{ + return pci_register_driver(&r1t1_driver); +} + +static void __exit r1t1_cleanup(void) +{ + pci_unregister_driver(&r1t1_driver); +} + + +module_param(debug, int, 0600); +MODULE_PARM_DESC(debug, "1 for debugging messages"); +module_param(e1, int, 0600); +MODULE_PARM_DESC(e1, "1 for E1 mode set from module_param"); +module_param(ec_disable, int, 0600); +module_param(ec_sw, int, 0600); +module_param(no_ec, int, 0600); +module_param(nlp_type, int, 0600); +MODULE_PARM_DESC(nlp_type, "0 - off, 1 - mute, 2 - rand, 3 - hoth, 4 - supp"); + +MODULE_DESCRIPTION("Rhino R1T1 T1-E1-J1 Driver " DAHDI_VERSION); +MODULE_AUTHOR + ("Lee Reeves \n\tBob Conklin \n\tBryce Chidester \n\tMatthew Gessner MAX_CHANNELS) + MaxChannels[DspId] = MAX_CHANNELS; + else + MaxChannels[DspId] = (unsigned short int) DspChannels; +#if 0 + /* read the number of configured DSP conferences */ + gpakReadDspMemory(rcb_card, DspId, IfBlockPntr + NUM_CONFERENCES_OFFSET, 1, + &DspConfs); + if (DspConfs > MAX_CONFS) + MaxConfs[DspId] = MAX_CONFS; + else + MaxConfs[DspId] = (unsigned short int) DspConfs; + + + /* read the number of configured DSP packet channels */ + gpakReadDspMemory(rcb_card, DspId, IfBlockPntr + NUM_PKT_CHANNELS_OFFSET, 1, + &DspChannels); + if (DspChannels > MAX_PKT_CHANNELS) + MaxPktChannels[DspId] = MAX_PKT_CHANNELS; + else + MaxPktChannels[DspId] = (unsigned short int) DspChannels; + + + /* read the pointer to the circular buffer infor struct table */ + gpakReadDspMemory(rcb_card, DspId, IfBlockPntr + PKT_BUFR_MEM_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(PktBufrMem, Temp); + + + /* Determine the addresses of each channel's Packet buffers. */ + for (i = 0; i < MaxPktChannels[DspId]; i++) { + pPktInBufr[DspId][i] = PktBufrMem; + pPktOutBufr[DspId][i] = PktBufrMem + CIRC_BUFFER_INFO_STRUCT_SIZE; + PktBufrMem += (CIRC_BUFFER_INFO_STRUCT_SIZE * 2); + } +#endif + + if (rcb_card->dsp_type == DSP_5510) { + /* read the pointer to the event fifo info struct */ + gpakReadDspMemory(rcb_card, DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, + Temp); + RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp); + } + + /* Set the DSP Status to indicate the host recognized the reset. */ + DspStatus = HOST_INIT_STATUS; + gpakWriteDspMemory(rcb_card, DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, + &DspStatus); + + /* Return with an indication that a reset occurred. */ + return (1); + } + + /* If status doesn't indicate the host recognized a reset, return with an + indication the DSP is not ready. */ + if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0)) + return (-1); + + /* Return with an indication that a reset did not occur. */ + return (0); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * WriteDspCmdMessage - Write a Host Command/Request message to DSP. + * + * FUNCTION + * This function writes a Host Command/Request message into DSP memory and + * informs the DSP of the presence of the message. + * + * RETURNS + * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) + * 0 = Temporarily unable to write message (previous Cmd Msg busy) + * 1 = Message written successfully + * + */ +static int WriteDspCmdMessage(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMessage, /* pointer to Command message */ + DSP_WORD MsgLength /* length of message (octets) */ + ) +{ + DSP_WORD CmdMsgLength; /* current Cmd message length */ + DSP_WORD Temp[2]; + DSP_ADDRESS BufferPointer; /* message buffer pointer */ + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rcb_card, DspId) == -1) + return (-1); + + /* Make sure the message length is valid. */ + if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId])) + return (-1); + + /* Make sure a previous Command message is not in use by the DSP. */ + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + if (CmdMsgLength != 0) + return (0); + + /* Purge any previous Reply message that wasn't read. */ + gpakWriteDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Copy the Command message into DSP memory. */ + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakWriteDspMemory(rcb_card, DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); + + /* Store the message length in DSP's Command message length (flags DSP that + a Command message is ready). */ + CmdMsgLength = MsgLength; + gpakWriteDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Return with an indication the message was written. */ + return (1); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ReadDspReplyMessage - Read a DSP Reply message from DSP. + * + * FUNCTION + * This function reads a DSP Reply message from DSP memory. + * + * RETURNS + * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) + * 0 = No message available (DSP Reply message empty) + * 1 = Message read successfully (message and length stored in variables) + * + */ +static int ReadDspReplyMessage(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMessage, /* pointer to Reply message buffer */ + DSP_WORD * pMsgLength /* pointer to msg length var (octets) */ + ) +{ + DSP_WORD MsgLength; /* message length */ + DSP_ADDRESS BufferPointer; /* message buffer pointer */ + DSP_WORD Temp[2]; + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rcb_card, DspId) == -1) + return (-1); + + /* Check if a Reply message is ready. */ + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &MsgLength); + if (MsgLength == 0) + return (0); + + /* Make sure the message length is valid. */ + if (MsgLength > *pMsgLength) + return (-1); + + /* Copy the Reply message from DSP memory. */ + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakReadDspMemory(rcb_card, DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); + + /* Store the message length in the message length variable. */ + *pMsgLength = MsgLength; + + /* Indicate a Reply message is not ready. */ + MsgLength = 0; + gpakWriteDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &MsgLength); + + /* Return with an indication the message was read. */ + return (1); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ReadCircBuffer - Read from a DSP circular buffer. + * + * FUNCTION + * This function reads a block of words from a DSP circular buffer. The Take + * address is incremented by the number of words read adjusting for buffer + * wrap. + * + * RETURNS + * nothing + * + */ +static void ReadCircBuffer(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_ADDRESS BufrBaseAddress, /* address of base of circular buffer */ + DSP_ADDRESS BufrLastAddress, /* address of last word in buffer */ + DSP_ADDRESS * TakeAddress, /* pointer to address in buffer for read */ + DSP_WORD * pWordBuffer, /* pointer to buffer for words read */ + DSP_WORD NumWords /* number of words to read */ + ) +{ + DSP_WORD WordsTillEnd; /* number of words until end of buffer */ + + /* Determine the number of words from the start address until the end of the + buffer. */ + WordsTillEnd = BufrLastAddress - *TakeAddress + 1; + + /* If a buffer wrap will occur, read the first part at the end of the + buffer followed by the second part at the beginning of the buffer. */ + if (NumWords > WordsTillEnd) { + gpakReadDspMemory(rcb_card, DspId, *TakeAddress, WordsTillEnd, pWordBuffer); + gpakReadDspMemory(rcb_card, DspId, BufrBaseAddress, NumWords - WordsTillEnd, + &(pWordBuffer[WordsTillEnd])); + *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd; + } + + /* If a buffer wrap will not occur, read all words starting at the current + take address in the buffer. */ + else { + gpakReadDspMemory(rcb_card, DspId, *TakeAddress, NumWords, pWordBuffer); + if (NumWords == WordsTillEnd) + *TakeAddress = BufrBaseAddress; + else + *TakeAddress = *TakeAddress + NumWords; + } + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * VerifyReply - Verify the reply message is correct for the command sent. + * + * FUNCTION + * This function verifies correct reply message content for the command that + * was just sent. + * + * RETURNS + * 0 = Incorrect + * 1 = Correct + * + */ +static int VerifyReply(DSP_WORD * pMsgBufr, /* pointer to Reply message buffer */ + int CheckType, /* reply check type */ + DSP_WORD CheckValue /* reply check value */ + ) +{ + + /* Verify Channel or Conference Id. */ + if (CheckType == 1) { + if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue) + return (0); + } + + /* Verify Test Mode Id. */ + else if (CheckType == 2) { + if (pMsgBufr[1] != CheckValue) + return (0); + } + + /* Return with an indication of correct reply. */ + return (1); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * TransactCmd - Send a command to the DSP and receive it's reply. + * + * FUNCTION + * This function sends the specified command to the DSP and receives the DSP's + * reply. + * + * RETURNS + * Length of reply message (0 = Failure) + * + */ +static unsigned int TransactCmd(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMsgBufr, /* pointer to Cmd/Reply message buffer */ + DSP_WORD CmdLength, /* length of command message (octets) */ + DSP_WORD ReplyType, /* required type of reply message */ + DSP_WORD ReplyLength, /* required length of reply message (octets) */ + int ReplyCheckType, /* reply check type */ + DSP_WORD ReplyCheckValue /* reply check value */ + ) +{ + int FuncStatus; /* function status */ + int LoopCount; /* wait loop counter */ + DSP_WORD RcvReplyLength; /* received Reply message length */ + DSP_WORD RcvReplyType; /* received Reply message type code */ + DSP_WORD RetValue; /* return value */ + + /* Default the return value to indicate a failure. */ + RetValue = 0; + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + + /* Attempt to write the command message to the DSP. */ + LoopCount = 0; + while ((FuncStatus = WriteDspCmdMessage(rcb_card, DspId, pMsgBufr, CmdLength)) != 1) { + if (FuncStatus == -1) + break; + if (++LoopCount > MAX_WAIT_LOOPS) + break; + gpakHostDelay(); + } + + /* Attempt to read the reply message from the DSP if the command message was + sent successfully. */ + if (FuncStatus == 1) { + for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++) { + RcvReplyLength = MSG_BUFFER_SIZE * 2; + FuncStatus = ReadDspReplyMessage(rcb_card, DspId, pMsgBufr, &RcvReplyLength); + if (FuncStatus == 1) { + RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF; + if ((RcvReplyLength >= ReplyLength) && + (RcvReplyType == ReplyType) && + VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue)) { + RetValue = RcvReplyLength; + break; + } else if (RcvReplyType == MSG_NULL_REPLY) + break; + } else if (FuncStatus == -1) + break; + gpakHostDelay(); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + /* Return the length of the reply message (0 = failure). */ + return (RetValue); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakConfigurePorts - Configure a DSP's serial ports. + * + * FUNCTION + * This function configures a DSP's serial ports. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakConfigPortStatus_t gpakConfigurePorts(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + GpakPortConfig_t * pPortConfig, /* pointer to Port Config info */ + GPAK_PortConfigStat_t * pStatus /* pointer to Port Config Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (CpsInvalidDsp); + + /* Build the Configure Serial Ports message. */ + MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8; + MsgBuffer[1] = (DSP_WORD) + ((pPortConfig->SlotsSelect1 << 12) | + ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum1 << 4) & 0x00F0)); + MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1; + MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1; + MsgBuffer[4] = (DSP_WORD) + ((pPortConfig->SlotsSelect2 << 12) | + ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum2 << 4) & 0x00F0)); + MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2; + MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2; + MsgBuffer[7] = (DSP_WORD) + ((pPortConfig->SlotsSelect3 << 12) | + ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum3 << 4) & 0x00F0)); + MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3; + MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3; + + MsgBuffer[10] = (DSP_WORD) + (((pPortConfig->DxDelay1 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay1 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay1 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) | + ((pPortConfig->CompandingMode1 << 1) & 0x0006) | + (pPortConfig->SerialWordSize1 & 0x0001)); + + MsgBuffer[11] = (DSP_WORD) + (((pPortConfig->DxDelay2 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay2 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay2 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) | + ((pPortConfig->CompandingMode2 << 1) & 0x0006) | + (pPortConfig->SerialWordSize2 & 0x0001)); + + MsgBuffer[12] = (DSP_WORD) + (((pPortConfig->DxDelay3 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay3 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay3 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) | + ((pPortConfig->CompandingMode3 << 1) & 0x0006) | + (pPortConfig->SerialWordSize3 & 0x0001)); + + if (rcb_card->dsp_type == DSP_5510) { + MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1; + MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1; + MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1; + MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1; + MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1; + MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1; + + MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;; + MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2; + MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;; + MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2; + MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;; + MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2; + + MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;; + MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3; + MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;; + MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3; + MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;; + MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3; + + /* Attempt to send the Configure Serial Ports message to the DSP and receive + it's reply. */ + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) + return (CpsDspCommFailure); + } + + else { + /* Attempt to send the Configure Serial Ports message to the DSP and receive + it's reply. */ + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 26, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) + return (CpsDspCommFailure); + } + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Pc_Success) + return (CpsSuccess); + else + return (CpsParmError); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakConfigureChannel - Configure a DSP's Channel. + * + * FUNCTION + * This function configures a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakConfigChanStatus_t gpakConfigureChannel(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ + GpakChanType ChannelType, /* Channel Type */ + GpakChannelConfig_t * pChanConfig, /* pointer to Channel Config info */ + GPAK_ChannelConfigStat_t * pStatus /* pointer to Channel Config Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD MsgLength; /* message length */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (CcsInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (CcsInvalidChannel); + + /* Build the Configure Channel message based on the Channel Type. */ + switch (ChannelType) { + + /* PCM to Packet channel type. */ + case tdmToTdm: + + MsgBuffer[2] = (DSP_WORD) + ((pChanConfig->PcmInPortA << 8) | (pChanConfig->PcmInSlotA & 0xFF)); + MsgBuffer[3] = (DSP_WORD) + ((pChanConfig->PcmOutPortA << 8) | (pChanConfig->PcmOutSlotA & 0xFF)); + + MsgBuffer[4] = (DSP_WORD) + ((pChanConfig->PcmInPortB << 8) | (pChanConfig->PcmInSlotB & 0xFF)); + MsgBuffer[5] = (DSP_WORD) + ((pChanConfig->PcmOutPortB << 8) | (pChanConfig->PcmOutSlotB & 0xFF)); + + if (rcb_card->dsp_type == DSP_5510) { + MsgBuffer[6] = (DSP_WORD) + ((pChanConfig->FrameRate << 6) | + ((pChanConfig->ToneTypesB << 5) & 0x0020) | + ((pChanConfig->ToneTypesA << 4) & 0x0010) | + ((pChanConfig->SoftwareCompand & 3) << 2) | + (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1)); + } else { + MsgBuffer[6] = (DSP_WORD) + ((pChanConfig->FrameRate << 6) | + //((pChanConfig->ToneTypesB << 5) & 0x0020) | + //((pChanConfig->ToneTypesA << 4) & 0x0010) | + ((pChanConfig->SoftwareCompand & 3) << 2) | + (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1)); + } + + MsgBuffer[7] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanTapLength; + MsgBuffer[8] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpType; + MsgBuffer[9] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanAdaptEnable; + MsgBuffer[10] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanG165DetEnable; + MsgBuffer[11] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanDblTalkThresh; + MsgBuffer[12] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpThreshold; + MsgBuffer[13] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpConv; + MsgBuffer[14] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpUnConv; + MsgBuffer[15] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpMaxSuppress; + + MsgBuffer[16] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanCngThreshold; + MsgBuffer[17] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanAdaptLimit; + MsgBuffer[18] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanCrossCorrLimit; + MsgBuffer[19] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNumFirSegments; + MsgBuffer[20] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanFirSegmentLen; + + MsgBuffer[21] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanTapLength; + MsgBuffer[22] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpType; + MsgBuffer[23] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanAdaptEnable; + MsgBuffer[24] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanG165DetEnable; + MsgBuffer[25] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanDblTalkThresh; + MsgBuffer[26] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpThreshold; + MsgBuffer[27] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpConv; + MsgBuffer[28] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpUnConv; + MsgBuffer[29] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpMaxSuppress; + MsgBuffer[30] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanCngThreshold; + MsgBuffer[31] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanAdaptLimit; + MsgBuffer[32] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanCrossCorrLimit; + MsgBuffer[33] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNumFirSegments; + MsgBuffer[34] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanFirSegmentLen; + + MsgLength = 70; // byte number == 35*2 + break; + + + /* Unknown (invalid) channel type. */ + default: + *pStatus = Cc_InvalidChannelType; + return (CcsParmError); + } + + MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF)); + + /* Attempt to send the Configure Channel message to the DSP and receive it's + reply. */ + if (!TransactCmd(rcb_card, DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (CcsDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Cc_Success) + return (CcsSuccess); + else + return (CcsParmError); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakTearDownChannel - Tear Down a DSP's Channel. + * + * FUNCTION + * This function tears down a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakTearDownStatus_t gpakTearDownChannel(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ + GPAK_TearDownChanStat_t * pStatus /* pointer to Tear Down Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (TdsInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (TdsInvalidChannel); + + /* Build the Tear Down Channel message. */ + MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8; + MsgBuffer[1] = (DSP_WORD) (ChannelId << 8); + + /* Attempt to send the Tear Down Channel message to the DSP and receive it's + reply. */ + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (TdsDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Td_Success) + return (TdsSuccess); + else + return (TdsError); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAlgControl - Control an Algorithm. + * + * FUNCTION + * This function controls an Algorithm + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakAlgControlStat_t gpakAlgControl(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakAlgCtrl_t ControlCode, // algorithm control code + GPAK_AlgControlStat_t * pStatus // pointer to return status + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (AcInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (AcInvalidChannel); + + MsgBuffer[0] = MSG_ALG_CONTROL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF)); + + /* Attempt to send the Tear Down Channel message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (AcDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Ac_Success) + return (AcSuccess); + else + return (AcParmError); + +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadEventFIFOMessage - read from the event fifo + * + * FUNCTION + * This function reads a single event from the event fifo if one is available + * + * RETURNS + * Status code indicating success or a specific error. + * + * Notes: This function should be called in a loop until the return status + * indicates that the fifo is empty. + * + * If the event code equals "EventLoopbackTeardownComplete", then the + * contents of *pChannelId hold the coderBlockId that was assigned to + * the loopback coder that was torn down. + */ +gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(struct rcb_card_t * rcb_card, // Card containing the DSP + unsigned short int DspId, // DSP identifier + unsigned short int *pChannelId, // pointer to channel identifier + GpakAsyncEventCode_t * pEventCode, // pointer to Event Code + GpakAsyncEventData_t * pEventData // pointer to Event Data Struct + ) +{ + DSP_WORD WordBuffer[WORD_BUFFER_SIZE]; /* DSP words buffer */ + GpakAsyncEventCode_t EventCode; /* DSP's event code */ + DSP_WORD EventDataLength; /* Length of event to read */ + DSP_WORD ChannelId; /* DSP's channel Id */ + DSP_ADDRESS EventInfoAddress; /* address of EventFIFO info structure */ + DSP_ADDRESS BufrBaseAddress; /* base address of EventFIFO buffer */ + DSP_ADDRESS BufrLastAddress; /* last address of EventFIFO buffer */ + DSP_ADDRESS TakeAddress; /* current take address in fifo buffer */ + DSP_WORD BufrSize; /* size (in words) of event FIFO buffer */ + DSP_WORD PutIndex; /* event fifo put index */ + DSP_WORD TakeIndex; /* event fifo take index */ + DSP_WORD WordsReady; /* number words ready for read out of event fifo */ + DSP_WORD EventError; /* flag indicating error with event fifo msg */ +// DSP_WORD *pDebugData; /* debug data buffer pointer in event data struct */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RefInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rcb_card, DspId) == -1) { + gpakUnlockAccess(rcb_card, DspId); + return (RefDspCommFailure); + } + + /* Check if an event message is ready in the DSP. */ + EventInfoAddress = pEventFifoAddress[DspId]; + gpakReadDspMemory(rcb_card, DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE, + WordBuffer); + RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *) & WordBuffer[CB_BUFR_BASE])); + BufrSize = WordBuffer[CB_BUFR_SIZE]; + PutIndex = WordBuffer[CB_BUFR_PUT_INDEX]; + TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX]; + if (PutIndex >= TakeIndex) + WordsReady = PutIndex - TakeIndex; + else + WordsReady = PutIndex + BufrSize - TakeIndex; + + if (WordsReady < 2) { + gpakUnlockAccess(rcb_card, DspId); + return (RefNoEventAvail); + } + + /* Read the event header from the DSP's Event FIFO. */ + TakeAddress = BufrBaseAddress + TakeIndex; + BufrLastAddress = BufrBaseAddress + BufrSize - 1; + ReadCircBuffer(rcb_card, DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, + WordBuffer, 2); + TakeIndex += 2; + if (TakeIndex >= BufrSize) + TakeIndex -= BufrSize; + + ChannelId = (WordBuffer[0] >> 8) & 0xFF; + EventCode = (GpakAsyncEventCode_t) (WordBuffer[0] & 0xFF); + EventDataLength = WordBuffer[1]; + EventError = 0; + + switch (EventCode) { + case EventToneDetect: + if (EventDataLength > WORD_BUFFER_SIZE) { + gpakUnlockAccess(rcb_card, DspId); + return (RefInvalidEvent); + } + ReadCircBuffer(rcb_card, DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, + WordBuffer, EventDataLength); + pEventData->toneEvent.ToneCode = (GpakToneCodes_t) + (WordBuffer[0] & 0xFF); + pEventData->toneEvent.ToneDuration = WordBuffer[1]; + pEventData->toneEvent.Direction = WordBuffer[2]; + pEventData->toneEvent.DebugToneStatus = WordBuffer[3]; + TakeIndex += EventDataLength; + if (TakeIndex >= BufrSize) + TakeIndex -= BufrSize; + if (EventDataLength != 4) + EventError = 1; + break; + + default: + EventError = 1; + break; + }; + + /* Update the Take index in the DSP's Packet Out buffer information. */ + gpakWriteDspMemory(rcb_card, DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1, + &TakeIndex); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + if (EventError) + return (RefInvalidEvent); + + *pChannelId = ChannelId; + *pEventCode = EventCode; + return (RefEventAvail); + +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakPingDsp - ping the DSP to see if it's alive + * + * FUNCTION + * This function checks if the DSP is still communicating with the host + * and returns the DSP SW version + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakPingDspStat_t gpakPingDsp(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pDspSwVersion // DSP software version + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + //printk("pDspIfBlk = %x, MaxCmdMsgLen = %x, MaxChannels = %x\n",pDspIfBlk[0], MaxCmdMsgLen[0], MaxChannels[0]); + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (PngInvalidDsp); + + /* send value of 1, DSP increments it */ + MsgBuffer[0] = (MSG_PING << 8); + + /* Attempt to send the ping message to the DSP and receive it's + reply. */ + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0)) + return (PngDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) { + *pDspSwVersion = MsgBuffer[2]; + return (PngSuccess); + } else + return (PngDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakSerialTxFixedValue - transmit a fixed value on a timeslot + * + * FUNCTION + * This function controls transmission of a fixed value out onto a serial + * port's timeslot. + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id + unsigned short int PcmOutSlot, // PCM Output Time Slot + unsigned short int Value, // 16-bit value + GpakActivation State // activation state + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (TfvInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (TfvInvalidChannel); + + + /* Build the message. */ + MsgBuffer[0] = MSG_SERIAL_TXVAL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF)); + MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF)); + MsgBuffer[3] = (DSP_WORD) Value; + + /* Attempt to send the message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4, + 1, ChannelId)) + return (TfvDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (TfvSuccess); + else + return (TfvDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakControlTdmLoopBack - control a serial port's loopback state + * + * FUNCTION + * This function enables/disables the tdm input to output looback mode on a + * serial port + * + * RETURNS + * Status code indicating success or a specific error. + */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakSerialPort_t SerialPort, // Serial Port Id + GpakActivation LoopBackState // Loopback State + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (ClbInvalidDsp); + + /* Build the message. */ + MsgBuffer[0] = MSG_TDM_LOOPBACK << 8; + MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF)); + + /* Attempt to send the message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0)) + return (ClbDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (ClbSuccess); + else + return (ClbDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - Read CPU usage statistics from a DSP. + * + * FUNCTION + * This function reads the CPU usage statistics from a DSP's memory. The + * average CPU usage in units of .1 percent are obtained for each of the frame + * rates. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadCpuUsageStat_t gpakReadCpuUsage(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // Dsp Identifier + unsigned short int *pPeakUsage, // pointer to peak usage variable + unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second + ) +{ + DSP_WORD ReadBuffer[2]; /* DSP read buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RcuInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rcb_card, DspId) == -1) + return (RcuDspCommFailure); + + /* Read the CPU Usage statistics from the DSP. */ + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + /* Store the usage statistics in the specified variables. */ + *pPrev1SecPeakUsage = ReadBuffer[0]; + *pPeakUsage = ReadBuffer[1]; + + /* Return with an indication the usage staistics were read successfully. */ + return (RcuSuccess); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetCpuUsageStats - reset the cpu usage statistics + * + * FUNCTION + * This function resets the cpu utilization statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakResetCpuUsageStat_t gpakResetCpuUsageStats(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RstcInvalidDsp); + + MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8); + + /* Attempt to send the message to the DSP and receive it's reply. */ + //need_reply_len; + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0)) + return (RstcDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (RstcSuccess); + else + return (RstcDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFramingStats + * + * FUNCTION + * This function reads a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakReadFramingStatsStatus_t gpakReadFramingStats(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pFramingError1Count, // port 1 Framing error count + unsigned short int *pFramingError2Count, // port 2 Framing error count + unsigned short int *pFramingError3Count, // port 3 Framing error count + unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count + unsigned short int *pDmaSlipStatsBuffer // DMA slips count + ) +{ + DSP_WORD ReadBuffer[10]; /* DSP read buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RfsInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rcb_card, DspId) == -1) + return (RfsDspCommFailure); + + /* Read the framing interrupt statistics from the DSP. */ + if (rcb_card->dsp_type == DSP_5510) + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10, + ReadBuffer); + else + gpakReadDspMemory(rcb_card, DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 4, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + /* Store the framing statistics in the specified variables. */ + *pFramingError1Count = ReadBuffer[0]; + *pFramingError2Count = ReadBuffer[1]; + *pFramingError3Count = ReadBuffer[2]; + *pDmaStopErrorCount = ReadBuffer[3]; +/* + if((pDmaSlipStatsBuffer != 0) && (rcb_card->dsp_type == DSP_5510)) + // If users want to get the DMA slips count + { + pDmaSlipStatsBuffer[0] = ReadBuffer[4]; + pDmaSlipStatsBuffer[1] = ReadBuffer[5]; + pDmaSlipStatsBuffer[2] = ReadBuffer[6]; + pDmaSlipStatsBuffer[3] = ReadBuffer[7]; + pDmaSlipStatsBuffer[4] = ReadBuffer[8]; + pDmaSlipStatsBuffer[5] = ReadBuffer[9]; + + } +*/ + /* Return with an indication the statistics were read successfully. */ + return (RfsSuccess); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - reset a DSP's framing interrupt statistics + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakResetFramingStatsStatus_t gpakResetFramingStats(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RstfInvalidDsp); + + MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8); + + /* Attempt to send the message to the DSP and receive it's reply. */ + //need_reply_len; + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0)) + return (RstfDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (RstfSuccess); + else + return (RstfDspCommFailure); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakDownloadLoader - Download the DSP's Loader program. + * + * FUNCTION + * This function reads the DSP's Loader program from the specified file and + * writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakDownloadStatus_t gpakDownloadLoader(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Loader program File Identifier */ + ) +{ + gpakDownloadStatus_t RetStatus; /* function return status */ + int NumRead; /* number of file bytes read */ + DSP_ADDRESS Address; /* DSP address */ + unsigned int WordCount; /* number of words in record */ + unsigned int NumWords; /* number of words to read/write */ + unsigned int i; /* loop index / counter */ + unsigned int j; /* loop index */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (GdlInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + RetStatus = GdlSuccess; + while (RetStatus == GdlSuccess) { + + /* Read a record header from the file. */ + NumRead = gpakReadFile_5507(rcb_card, FileId, DlByteBufr, 6); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != 6) { + RetStatus = GdlInvalidFile; + break; + } + Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) | + (((DSP_ADDRESS) DlByteBufr[2]) << 8) | ((DSP_ADDRESS) DlByteBufr[3]); + WordCount = (((unsigned int) DlByteBufr[4]) << 8) | + ((unsigned int) DlByteBufr[5]); + + /* Check for the End Of File record. */ + if (DlByteBufr[0] == 0xFF) + break; + + /* Verify the record is for a valid memory type. */ + if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01)) { + RetStatus = GdlInvalidFile; + break; + } + + /* Read a block of words at a time from the file and write to the + DSP's memory . */ + while (WordCount != 0) { + if (WordCount < DOWNLOAD_BLOCK_SIZE) + NumWords = WordCount; + else + NumWords = DOWNLOAD_BLOCK_SIZE; + WordCount -= NumWords; + NumRead = gpakReadFile_5507(rcb_card, FileId, DlByteBufr, NumWords * 2); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != (NumWords * 2)) { + RetStatus = GdlInvalidFile; + break; + } + for (i = 0, j = 0; i < NumWords; i++, j += 2) + DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) | + ((DSP_WORD) DlByteBufr[j + 1]); + gpakWriteDspMemory(rcb_card, DspId, Address, NumWords, DlWordBufr); + Address += ((DSP_ADDRESS) NumWords); + } + } + + /* If the download was succesful, clear the DSP Loader's status variable and + set the host's command to null. */ + if (RetStatus == GdlSuccess) { + DlWordBufr[0] = 0; + gpakWriteDspMemory(rcb_card, DspId, BL_DSP_STATUS, 1, DlWordBufr); + gpakWriteDspMemory(rcb_card, DspId, BL_HOST_CMD, 1, DlWordBufr); + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + /* Return with an indication of success or failure. */ + return (RetStatus); +} + + +/* + * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. + * + * FUNCTION + * This function reads a DSP's Program and Data memory image from the + * specified file and writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakDownloadStatus_t gpakDownloadDsp_5510(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Download File Identifier */ + ) +{ + gpakDownloadStatus_t RetStatus; /* function return status */ + int NumRead; /* number of file bytes read */ + DSP_ADDRESS Address; /* DSP address */ + unsigned int WordCount; /* number of words in record */ + unsigned int NumWords; /* number of words to read/write */ + unsigned int i; /* loop index / counter */ + unsigned int j; /* loop index */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (GdlInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + RetStatus = GdlSuccess; + while (RetStatus == GdlSuccess) { + + /* Read a record header from the file. */ + NumRead = gpakReadFile_5510(rcb_card, FileId, DlByteBufr, 6); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != 6) { + RetStatus = GdlInvalidFile; + break; + } + Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) | + (((DSP_ADDRESS) DlByteBufr[2]) << 8) | ((DSP_ADDRESS) DlByteBufr[3]); + WordCount = (((unsigned int) DlByteBufr[4]) << 8) | + ((unsigned int) DlByteBufr[5]); + + /* Check for the End Of File record. */ + if (DlByteBufr[0] == 0xFF) + break; + + /* Verify the record is for a valid memory type. */ + if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01)) { + RetStatus = GdlInvalidFile; + break; + } + + /* Read a block of words at a time from the file and write to the + DSP's memory . */ + while (WordCount != 0) { + if (WordCount < DOWNLOAD_BLOCK_SIZE) + NumWords = WordCount; + else + NumWords = DOWNLOAD_BLOCK_SIZE; + WordCount -= NumWords; + NumRead = gpakReadFile_5510(rcb_card, FileId, DlByteBufr, NumWords * 2); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != (NumWords * 2)) { + RetStatus = GdlInvalidFile; + break; + } + for (i = 0, j = 0; i < NumWords; i++, j += 2) + DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) | + ((DSP_WORD) DlByteBufr[j + 1]); + gpakWriteDspMemory(rcb_card, DspId, Address, NumWords, DlWordBufr); + Address += ((DSP_ADDRESS) NumWords); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + /* Return with an indication of success or failure. */ + return (RetStatus); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakDownloadDsp - Download the DSP's Application program and data memory. + * + * FUNCTION + * This function reads the DSP's Application program and data memory image from + * the specified file and interacts with the DSP's Loader program to write the + * image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakDownloadStatus_t gpakDownloadDsp_5507(struct rcb_card_t * rcb_card, /* Card containing the DSP */ + unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Application program File Identifier */ + ) +{ + gpakDownloadStatus_t RetStatus; /* function return status */ + int NumRead; /* number of file bytes read */ + DSP_ADDRESS Address; /* DSP address */ + DSP_WORD AddressBuffer[2]; /* DSP address buffer, 5509: 24bits address */ + unsigned int WordCount; /* number of words in record */ + unsigned int NumWords; /* number of words to read/write */ + unsigned int i; /* loop index / counter */ + unsigned int j; /* loop index */ + unsigned int MaxBlockSize; /* max words to transfer per block */ + DSP_WORD MemoryType; /* DSP memory type */ + DSP_WORD DspTemp; /* temporary DSP memory word */ + int LoopCount; /* wait loop counter */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (GdlInvalidDsp); + + /* Determine the maximum number of words to transfer at a time. */ + if (BL_BUFFER_SIZE < DOWNLOAD_BLOCK_SIZE) + MaxBlockSize = BL_BUFFER_SIZE; + else + MaxBlockSize = DOWNLOAD_BLOCK_SIZE; + + /* Lock access to the DSP. */ + gpakLockAccess(rcb_card, DspId); + + /* Wait for the DSP Loader to indicate it's ready. */ + LoopCount = 0; + while (1) { + gpakReadDspMemory(rcb_card, DspId, BL_DSP_STATUS, 1, &DspTemp); + if (DspTemp != 0) + break; + if (++LoopCount > MAX_WAIT_LOOPS) { + gpakUnlockAccess(rcb_card, DspId); + return (GdlDspCommFailure); + } + gpakHostDelay(); + } + + RetStatus = GdlSuccess; + while (RetStatus == GdlSuccess) { + + /* Read a record header from the file. */ + NumRead = gpakReadFile_5507(rcb_card, FileId, DlByteBufr, 6); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != 6) { + RetStatus = GdlInvalidFile; + break; + } + Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) | + (((DSP_ADDRESS) DlByteBufr[2]) << 8) | ((DSP_ADDRESS) DlByteBufr[3]); + + AddressBuffer[0] = (DSP_WORD) ((Address >> 16) & 0xFFFF); + AddressBuffer[1] = (DSP_WORD) (Address & 0xFFFF); + + WordCount = (((unsigned int) DlByteBufr[4]) << 8) | + ((unsigned int) DlByteBufr[5]); + + /* Check for the End Of File record. */ + if (DlByteBufr[0] == 0xFF) + break; + + /* Verify the record is for a valid memory type. */ + if (DlByteBufr[0] == 0x00) + MemoryType = 1; + else if (DlByteBufr[0] == 0x01) + MemoryType = 2; + else { + RetStatus = GdlInvalidFile; + break; + } + + /* Read a block of words at a time from the file and write to the + DSP's memory . */ + while (WordCount != 0) { + if (WordCount < MaxBlockSize) + NumWords = WordCount; + else + NumWords = MaxBlockSize; + WordCount -= NumWords; + NumRead = gpakReadFile_5507(rcb_card, FileId, DlByteBufr, NumWords * 2); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != (NumWords * 2)) { + RetStatus = GdlInvalidFile; + break; + } + + /* Wait for the DSP Loader to complete the previous command. */ + LoopCount = 0; + while (1) { + gpakReadDspMemory(rcb_card, DspId, BL_HOST_CMD, 1, &DspTemp); + if (DspTemp == 0) + break; + if (++LoopCount > MAX_WAIT_LOOPS) { + gpakUnlockAccess(rcb_card, DspId); + return (GdlDspCommFailure); + } + gpakHostDelay(); + } + + /* Command the DSP Loader to store the block in memory. */ + for (i = 0, j = 0; i < NumWords; i++, j += 2) + DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) | + ((DSP_WORD) DlByteBufr[j + 1]); + gpakWriteDspMemory(rcb_card, DspId, BL_BUFFER, NumWords, DlWordBufr); + + AddressBuffer[0] = (DSP_WORD) (Address >> 16); + AddressBuffer[1] = (DSP_WORD) (Address & 0xFFFF); + + //DspTemp = Address; + gpakWriteDspMemory(rcb_card, DspId, BL_ADDRESS, 2, AddressBuffer); //&DspTemp); + DspTemp = NumWords; + gpakWriteDspMemory(rcb_card, DspId, BL_LENGTH, 1, &DspTemp); + gpakWriteDspMemory(rcb_card, DspId, BL_HOST_CMD, 1, &MemoryType); + + /* Increment the address for the next block. */ + Address += ((DSP_ADDRESS) NumWords); + + AddressBuffer[0] = (DSP_WORD) ((Address >> 16) & 0xFFFF); + AddressBuffer[1] = (DSP_WORD) (Address & 0xFFFF); + + } + } + + /* If the download was succesful, command the DSP Loader to restart. */ + if (RetStatus == GdlSuccess) { + + /* Wait for the DSP Loader to complete the previous command. */ + LoopCount = 0; + while (1) { + gpakReadDspMemory(rcb_card, DspId, BL_HOST_CMD, 1, &DspTemp); + if (DspTemp == 0) + break; + if (++LoopCount > MAX_WAIT_LOOPS) { + gpakUnlockAccess(rcb_card, DspId); + return (GdlDspCommFailure); + } + gpakHostDelay(); + } + + DspTemp = 3; + gpakWriteDspMemory(rcb_card, DspId, BL_HOST_CMD, 1, &DspTemp); + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rcb_card, DspId); + + /* Return with an indication of success or failure. */ + return (RetStatus); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - Read CPU usage statistics from a DSP. + * + * FUNCTION + * This function reads the memory map register section of DSP memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(struct rcb_card_t * rcb_card, // Card containing the DSP + unsigned short int DspId, // Dsp Identifier + unsigned short int *pDest, // Buffer on host to hold DSP memory map + DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out + unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP reply's status */ + int i; /* loop index / counter */ + + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RmmInvalidDsp); + + /* Verify the message buffer is large enough */ + if (MSG_BUFFER_SIZE < MemoryLength_Word16) + return (RmmSizeTooBig); + + MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8; + MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF); + MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF); + MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16; + + /* Attempt to send the Read memory section message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rcb_card, DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY, + (MemoryLength_Word16 + 2) * 2, 0, 0)) + return (RmmInvalidAddress); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus != 0) + return (RmmFailure); + + for (i = 0; i < MemoryLength_Word16; i++) + pDest[i] = (short int) MsgBuffer[2 + i]; + + + return (RmmSuccess); +} diff --git drivers/dahdi/rhino/rcbfx/GpakApi.h drivers/dahdi/rhino/rcbfx/GpakApi.h new file mode 100644 index 0000000..eb32759 --- /dev/null +++ drivers/dahdi/rhino/rcbfx/GpakApi.h @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2005 , Adaptive Digital Technologies, Inc. + * + * File Name: GpakApi.h + * + * Description: + * This file contains the function prototypes and data types for the user + * API functions that communicate with DSPs executing G.PAK software. The + * file is used by application software in the host processor connected to + * C55X G.PAK DSPs via a Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * 11/15/2006 - 24 TDM-TDM Channels EC release + */ + +#ifndef _GPAKAPI_H /* prevent multiple inclusion */ +#define _GPAKAPI_H +#include "GpakErrs.h" +#include "gpakenum.h" +#include "rcbfx.h" + +typedef unsigned long int GPAK_FILE_ID; /* G.PAK Download file identifier */ + +#define BL_DSP_BOOTLOADER_ENTRY 0x7020 /* DSP bootloader entry-point, */ + /* HOST have to put this address in 0x60-61 */ + /* after DSP bootloader bin file downloaded */ + +typedef unsigned short int DSP_WORD; /* 16 bit DSP word */ +typedef unsigned int DSP_ADDRESS; /* 32 bit DSP address */ +//typedef unsigned long int DSP_ADDRESS; /* 32 bit DSP address */ + +#define DSP_DEBUG_BUFF_SIZE 42 // units of 16-bit words + +/* Definition of an Asynchronous Event Data Structure */ + +typedef union { + struct { + GpakToneCodes_t ToneCode; // detected tone code + unsigned short int ToneDuration; // tone duration + GpakTdmDirection Direction; // detected on A r B side + short int DebugToneStatus; // reserved for debug info + } toneEvent; + +} GpakAsyncEventData_t; + +/* Definition of an Echo Canceller Parameters information structure. */ + +typedef struct { + short int EcanTapLength; // Echo Can Num Taps (tail length) + short int EcanNlpType; // Echo Can NLP Type + short int EcanAdaptEnable; // Echo Can Adapt Enable flag + short int EcanG165DetEnable; // Echo Can G165 Detect Enable flag + short int EcanDblTalkThresh; // Echo Can Double Talk threshold + short int EcanNlpThreshold; // Echo Can NLP threshold + short int EcanNlpConv; // Dynamic NLP control, NLP limit when EC about to converged + short int EcanNlpUnConv; // Dynamic NLP control, NLP limit when EC not converged yet + short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode + short int EcanCngThreshold; // Echo Can CNG Noise threshold + short int EcanAdaptLimit; // Echo Can Max Adapts per frame + short int EcanCrossCorrLimit; // Echo Can Cross Correlation limit + short int EcanNumFirSegments; // Echo Can Num FIR Segments + short int EcanFirSegmentLen; // Echo Can FIR Segment Length +} GpakEcanParms_t; + +/* Definition of a Channel Configuration information structure. */ + +typedef struct { + GpakSerialPort_t PcmInPortA; // A side PCM Input Serial Port Id + unsigned short int PcmInSlotA; // A side PCM Input Time Slot + GpakSerialPort_t PcmOutPortA; // A side PCM Output Serial Port Id + unsigned short int PcmOutSlotA; // A side PCM Output Time Slot + GpakSerialPort_t PcmInPortB; // B side PCM Input Serial Port Id + unsigned short int PcmInSlotB; // B side PCM Input Time Slot + GpakSerialPort_t PcmOutPortB; // B side PCM Output Serial Port Id + unsigned short int PcmOutSlotB; // B side PCM Output Time Slot + GpakToneTypes ToneTypesA; // A side Tone Detect Types + GpakToneTypes ToneTypesB; // B side Tone Detect Types + GpakActivation EcanEnableA; // Echo Cancel A Enabled + GpakActivation EcanEnableB; // Echo Cancel B Enabled + GpakEcanParms_t EcanParametersA; // Echo Cancel parameters + GpakEcanParms_t EcanParametersB; // Echo Cancel parameters + GpakCompandModes SoftwareCompand; // software companding + GpakRate_t FrameRate; // Gpak Frame Rate + +} GpakChannelConfig_t; + + +/* Definition of a Serial Port Configuration Structure */ +typedef struct { + GpakSlotCfg_t SlotsSelect1; // port 1 Slot selection + unsigned short int FirstBlockNum1; // port 1 first group Block Number + unsigned short int FirstSlotMask1; // port 1 first group Slot Mask + unsigned short int SecBlockNum1; // port 1 second group Block Number + unsigned short int SecSlotMask1; // port 1 second group Slot Mask + + GpakSerWordSize_t SerialWordSize1; // port 1 serial word size + GpakCompandModes CompandingMode1; // port 1 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity1; // port 1 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity1; // port 1 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay1; // port 1 Tx data delay + GpakSerDataDelay_t RxDataDelay1; // port 1 Rx data delay + GpakActivation DxDelay1; // port 1 DX Delay + + unsigned short int ThirdSlotMask1; // port 1 3rd group Slot Mask + unsigned short int FouthSlotMask1; // port 1 4th group Slot Mask + unsigned short int FifthSlotMask1; // port 1 5th group Slot Mask + unsigned short int SixthSlotMask1; // port 1 6th group Slot Mask + unsigned short int SevenSlotMask1; // port 1 7th group Slot Mask + unsigned short int EightSlotMask1; // port 1 8th group Slot Mask + + + GpakSlotCfg_t SlotsSelect2; // port 2 Slot selection + unsigned short int FirstBlockNum2; // port 2 first group Block Number + unsigned short int FirstSlotMask2; // port 2 first group Slot Mask + unsigned short int SecBlockNum2; // port 2 second group Block Number + unsigned short int SecSlotMask2; // port 2 second group Slot Mask + GpakSerWordSize_t SerialWordSize2; // port 2 serial word size + GpakCompandModes CompandingMode2; // port 2 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity2; // port 2 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity2; // port 2 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay2; // port 2 Tx data delay + GpakSerDataDelay_t RxDataDelay2; // port 2 Rx data delay + GpakActivation DxDelay2; // port 2 DX Delay + + unsigned short int ThirdSlotMask2; // port 2 3rd group Slot Mask + unsigned short int FouthSlotMask2; // port 2 4th group Slot Mask + unsigned short int FifthSlotMask2; // port 2 5th group Slot Mask + unsigned short int SixthSlotMask2; // port 2 6th group Slot Mask + unsigned short int SevenSlotMask2; // port 2 7th group Slot Mask + unsigned short int EightSlotMask2; // port 2 8th group Slot Mask + + GpakSlotCfg_t SlotsSelect3; // port 3 Slot selection + unsigned short int FirstBlockNum3; // port 3 first group Block Number + unsigned short int FirstSlotMask3; // port 3 first group Slot Mask + unsigned short int SecBlockNum3; // port 3 second group Block Number + unsigned short int SecSlotMask3; // port 3 second group Slot Mask + GpakSerWordSize_t SerialWordSize3; // port 3 serial word size + GpakCompandModes CompandingMode3; // port 3 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity3; // port 3 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity3; // port 3 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay3; // port 3 Tx data delay + GpakSerDataDelay_t RxDataDelay3; // port 3 Rx data delay + GpakActivation DxDelay3; // port 3 DX Delay + + unsigned short int ThirdSlotMask3; // port 3 3rd group Slot Mask + unsigned short int FouthSlotMask3; // port 3 4th group Slot Mask + unsigned short int FifthSlotMask3; // port 3 5th group Slot Mask + unsigned short int SixthSlotMask3; // port 3 6th group Slot Mask + unsigned short int SevenSlotMask3; // port 3 7th group Slot Mask + unsigned short int EightSlotMask3; // port 3 8th group Slot Mask + +} GpakPortConfig_t; + +/* Definition of a Tone Generation Parameter Structure */ +/* +typedef struct +{ + GpakToneGenType_t ToneType; // Tone Type + unsigned short int Frequency[4]; // Frequency (Hz) + short int Level[4]; // Frequency's Level (1 dBm) + unsigned short int OnTime[4]; // On Times (msecs) + unsigned short int OffTime[4]; // Off Times (msecs) +} GpakToneGenParms_t; +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakConfigureChannel return status. */ +typedef enum { + CcsSuccess = 0, /* Channel Configured successfully */ + CcsParmError = 1, /* Channel Config Parameter error */ + CcsInvalidChannel = 2, /* invalid channel */ + CcsInvalidDsp = 3, /* invalid DSP */ + CcsDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakConfigChanStatus_t; + +/* + * gpakConfigureChannel - Configure a DSP's Channel. + * + * FUNCTION + * This function configures a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakConfigChanStatus_t gpakConfigureChannel(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakChanType ChannelType, // channel type + GpakChannelConfig_t * pChanConfig, // pointer to channel config info + GPAK_ChannelConfigStat_t * pStatus // pointer to Channel Config Status + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakTearDownChannel return status. */ +typedef enum { + TdsSuccess = 0, /* Channel Tear Down successful */ + TdsError = 1, /* Channel Tear Down error */ + TdsInvalidChannel = 2, /* invalid channel */ + TdsInvalidDsp = 3, /* invalid DSP */ + TdsDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakTearDownStatus_t; + +/* + * gpakTearDownChannel - Tear Down a DSP's Channel. + * + * FUNCTION + * This function tears down a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +extern gpakTearDownStatus_t gpakTearDownChannel(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GPAK_TearDownChanStat_t * pStatus // pointer to Tear Down Status + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakAlgControl return status. */ +typedef enum { + AcSuccess = 0, /* control successful */ + AcInvalidChannel = 1, /* invalid channel identifier */ + AcInvalidDsp = 2, /* invalid DSP */ + AcParmError = 3, /* invalid control parameter */ + AcDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakAlgControlStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAlgControl - Control an Algorithm. + * + * FUNCTION + * This function controls an Algorithm + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakAlgControlStat_t gpakAlgControl(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakAlgCtrl_t ControlCode, // algorithm control code + GPAK_AlgControlStat_t * pStatus // pointer to return status + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakConfigurePorts return status. */ +typedef enum { + CpsSuccess = 0, /* Serial Ports configured successfully */ + CpsParmError = 1, /* Configure Ports Parameter error */ + CpsInvalidDsp = 2, /* invalid DSP */ + CpsDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakConfigPortStatus_t; + +/* + * gpakConfigurePorts - Configure a DSP's serial ports. + * + * FUNCTION + * This function configures a DSP's serial ports. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakConfigPortStatus_t gpakConfigurePorts(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakPortConfig_t * pPortConfig, // pointer to Port Config info + GPAK_PortConfigStat_t * pStatus // pointer to Port Config Status + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakDownloadDsp return status. */ +typedef enum { + GdlSuccess = 0, /* DSP download successful */ + GdlFileReadError = 1, /* error reading Download file */ + GdlInvalidFile = 2, /* invalid Download file content */ + GdlInvalidDsp = 3, /* invalid DSP */ + GdlDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakDownloadStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakDownloadLoader - Download the DSP's Loader program. + * + * FUNCTION + * This function reads the DSP's Loader program from the specified file and + * writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +extern gpakDownloadStatus_t gpakDownloadLoader(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Loader program File Identifier */ + ); + +/* + * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. + * + * FUNCTION + * This function reads a DSP's Program and Data memory image from the + * specified file and writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakDownloadStatus_t gpakDownloadDsp_5510(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GPAK_FILE_ID FileId // G.PAK download file identifier + ); + +extern gpakDownloadStatus_t gpakDownloadDsp_5507(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GPAK_FILE_ID FileId // G.PAK download file identifier + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakReadEventFIFOMessage return status */ +typedef enum { + RefEventAvail = 0, /* an event was successfully read from the fifo */ + RefNoEventAvail = 1, /* no event was in the fifo */ + RefInvalidDsp = 2, /* invalid DSP identifier */ + RefInvalidEvent = 3, /* invalid event */ + RefDspCommFailure = 4 /* error communicating with DSP */ +} gpakReadEventFIFOMessageStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadEventFIFOMessage - read from the event fifo + * + * FUNCTION + * This function reads a single event from the event fifo if one is available + * + * RETURNS + * Status code indicating success or a specific error. + * + * Note: This function should be called in a loop until the return status + * indicates that the fifo is empty. + */ +extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(struct rcb_card_t *rcb_card, // Card containing the DSP + unsigned short int DspId, // DSP identifier + unsigned short int *pChannelId, // pointer to channel identifier + GpakAsyncEventCode_t * pEventCode, // pointer to Event Code + GpakAsyncEventData_t * pEventData // pointer to Event Data Struct + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakPingDsp return status values */ +typedef enum { + PngSuccess = 0, /* DSP responded successfully */ + PngInvalidDsp = 1, /* invalid DSP identifier */ + PngDspCommFailure = 2 /* error communicating with DSP */ +} gpakPingDspStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakPingDsp - ping the DSP to see if it's alive + * + * FUNCTION + * This function checks if the DSP is still communicating with the host + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakPingDspStat_t gpakPingDsp(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pDspSwVersion // DSP software version + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakSerialTxFixedValue return status values */ +typedef enum { + TfvSuccess = 0, /* operation successful */ + TfvInvalidChannel = 1, /* invalid channel identifier */ + TfvInvalidDsp = 2, /* invalid DSP identifier */ + TfvDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakSerialTxFixedValueStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakSerialTxFixedValue - transmit a fixed value on a timeslot + * + * FUNCTION + * This function controls transmission of a fixed value out onto a serial + * port's timeslot. + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id + unsigned short int PcmOutSlot, // PCM Output Time Slot + unsigned short int Value, // 16-bit value + GpakActivation State // activation state + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakControlTdmLoopBack return status values */ +typedef enum { + ClbSuccess = 0, /* operation successful */ + ClbSerPortInactive = 1, /* serial port is inactive */ + ClbInvalidDsp = 2, /* invalid DSP identifier */ + ClbDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakControlTdmLoopBackStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakControlTdmLoopBack - control a serial port's loopback state + * + * FUNCTION + * This function enables/disables the tdm input to output looback mode on a + * serial port + * + * RETURNS + * Status code indicating success or a specific error. + */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakSerialPort_t SerialPort, // Serial Port Id + GpakActivation LoopBackState // Loopback State + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakReadCpuUsage return status values */ +typedef enum { + RcuSuccess = 0, /* operation successful */ + RcuInvalidDsp = 1, /* invalid DSP identifier */ + RcuDspCommFailure = 2 /* communication failure */ +} gpakReadCpuUsageStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - read the cpu usage statistics + * + * FUNCTION + * This function reads cpu utilization from the DSP. + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakReadCpuUsageStat_t gpakReadCpuUsage(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pPeakUsage, // pointer to peak usage variable + unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakResetCpuUsageStats return status values */ +typedef enum { + RstcSuccess = 0, /* operation successful */ + RstcInvalidDsp = 1, /* invalid DSP identifier */ + RstcDspCommFailure = 2 /* communication failure */ +} gpakResetCpuUsageStat_t; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetCpuUsageStats - reset the cpu usage statistics + * + * FUNCTION + * This function resets the cpu utilization statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakReadFramingStats return status values */ +typedef enum { + RfsSuccess = 0, /* operation successful */ + RfsInvalidDsp = 1, /* invalid DSP identifier */ + RfsDspCommFailure = 2 /* communication failure */ +} gpakReadFramingStatsStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFramingStats + * + * FUNCTION + * This function reads a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakReadFramingStatsStatus_t gpakReadFramingStats(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pFramingError1Count, // port 1 Framing error count + unsigned short int *pFramingError2Count, // port 2 Framing error count + unsigned short int *pFramingError3Count, // port 3 Framing error count + unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count + unsigned short int *pDmaSlipStatsBuffer // DMA slips count + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakResetFramingStats return values */ +typedef enum { + RstfSuccess = 0, /* operation successful */ + RstfInvalidDsp = 1, /* invalid DSP identifier */ + RstfDspCommFailure = 2 /* communication failure */ +} gpakResetFramingStatsStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - reset a DSP's framing interrupt statistics + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakResetFramingStatsStatus_t gpakResetFramingStats(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ); + + +typedef enum { + RmmSuccess = 0, + RmmInvalidDsp = 1, + RmmSizeTooBig = 2, + RmmFailure = 3, + RmmInvalidAddress = 4 +} gpakReadDSPMemoryStat_t; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - read a section of DSP memory + * to get access DSP registers, since 0x00--0x60 not HPI-accessable + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ + +extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(struct rcb_card_t *rcb_card, // Card containing the DSP + unsigned short int DspId, // Dsp Identifier + unsigned short int *pDest, // Buffer on host to hold DSP memory map + DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out + unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word + ); + +#endif // end multiple inclusion diff --git drivers/dahdi/rhino/rcbfx/GpakCust.c drivers/dahdi/rhino/rcbfx/GpakCust.c new file mode 100644 index 0000000..b0036e1 --- /dev/null +++ drivers/dahdi/rhino/rcbfx/GpakCust.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakCust.c + * + * Description: + * This file contains host system dependent functions to support generic + * G.PAK API functions. The file is integrated into the host processor + * connected to C55x G.PAK DSPs via a Host Port Interface. + * + * Note: This file needs to be modified by the G.PAK system integrator. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + +#include "GpakCust.h" +#include "rcbfx.h" +#include + +void rcb_card_wait_hpi(struct rcb_card_t *rcb_card, __u8 flags) +{ + volatile __u8 temp; + int loops; + + if (!(rcb_card->hpi_fast)) { + + temp = (*(volatile __u8 *) (rcb_card->memaddr + RCB_HPIRDX_STAT)); + + for (loops = 0; loops < 20; loops++) { + + temp = (*(volatile __u8 *) (rcb_card->memaddr + RCB_HPIRDX_STAT)); + if ((temp & flags) == flags) { + return; + } + } + } + return; +} + +void rcb_card_dsp_set(struct rcb_card_t *rcb_card, __u32 dsp_address, __u16 dsp_data) +{ + __u32 u_nib; + + if (rcb_card->dsp_type == DSP_5510) { + u_nib = ((dsp_address & 0xf0000) >> 16); + if (!(rcb_card->hpi_xadd == u_nib)) { + rcb_card->hpi_xadd = u_nib; + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIC) = (__u32) (RCB_XADD); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIA) = (__u32) (u_nib); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIC) = (__u32) (0); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + } + } + + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIA) = (__u32) (dsp_address); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPID) = (__u32) (dsp_data); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + + return; +} + +__u16 rcb_card_dsp_get(struct rcb_card_t * rcb_card, __u32 dsp_address) +{ + __u32 dsp_data; + __u32 u_nib; + + if (rcb_card->dsp_type == DSP_5510) { + + u_nib = ((dsp_address & 0xf0000) >> 16); + + if (!(rcb_card->hpi_xadd == u_nib)) { + rcb_card->hpi_xadd = u_nib; + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIC) = (__u32) (RCB_XADD); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIA) = (__u32) (u_nib); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIC) = (__u32) (0); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + } + } + + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIA) = (__u32) (dsp_address); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + + dsp_data = (0xFFFF & *(volatile __u32 *) (rcb_card->memaddr + RCB_HPID)); + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + + dsp_data = (0xFFFF & *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIRDX)); + + return (__u16) dsp_data; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadDspMemory - Read DSP memory. + * + * FUNCTION + * This function reads a contiguous block of words from DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +void gpakReadDspMemory(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to read */ + DSP_WORD * pWordValues /* pointer to array of word values variable */ + ) +{ + + unsigned int word_num; + + if (!rcb_card) { + printk("rcbfx: gpakReadDspMemory: No iface exists for DSP number %d\n", DspId); + return; + } + + /* read NumWords from auto increment data register */ + for (word_num = 0; word_num < NumWords; word_num++) { + pWordValues[word_num] = rcb_card_dsp_get(rcb_card, DspAddress + word_num); + } + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteDspMemory - Write DSP memory. + * + * FUNCTION + * This function writes a contiguous block of words to DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +void gpakWriteDspMemory(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to write */ + DSP_WORD * pWordValues /* pointer to array of word values to write */ + ) +{ + + unsigned int word_num; + + if (!rcb_card) { + printk("rcbfx: gpakWriteDspMemory: No iface exists for DSP number %d\n", DspId); + return; + } + + /* read NumWords from auto increment data register */ + for (word_num = 0; word_num < NumWords; word_num++) { + rcb_card_dsp_set(rcb_card, DspAddress + word_num, pWordValues[word_num]); + } + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakHostDelay - Delay for a fixed time interval. + * + * FUNCTION + * This function delays for a fixed time interval before returning. The time + * interval is the Host Port Interface sampling period when polling a DSP for + * replies to command messages. + * + * RETURNS + * nothing + * + */ +void gpakHostDelay(void) +{ + msleep(5); + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ + +void gpakLockAccess(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ) +{ + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakUnlockAccess(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ) +{ + return; +} + +extern const unsigned char _binary_DspLoader_fw_start[]; +extern const unsigned int _binary_DspLoader_fw_size; +extern const unsigned char _binary_GpakDsp10_fw_start[]; +extern const unsigned int _binary_GpakDsp10_fw_size; +extern const unsigned char _binary_GpakDsp0708_fw_start[]; +extern const unsigned int _binary_GpakDsp0708_fw_size; +extern const unsigned char _binary_GpakDsp0704_fw_start[]; +extern const unsigned int _binary_GpakDsp0704_fw_size; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFile - Read a block of bytes from a G.PAK Download file. + * + * FUNCTION + * This function reads a contiguous block of bytes from a G.PAK Download file + * starting at the current file position. + * + * RETURNS + * The number of bytes read from the file. + * -1 indicates an error occurred. + * 0 indicates all bytes have been read (end of file) + * + */ + + +int gpakReadFile_5510(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ) +{ + static int stats = 0; + int core_num; + int byte_num = -1; + int DspId; + static unsigned int file_pos[MAX_DSP_CORES]; + static unsigned int file_size; + if (!(stats)) { + stats++; + for (core_num = 0; core_num < MAX_DSP_CORES; core_num++) { + file_pos[core_num] = 0; + } + + file_size = (unsigned int) &_binary_GpakDsp10_fw_size; + + printk("rcbfx %d: G168 DSP App file size = %d %x\n", rcb_card->pos + 1, + (unsigned int) &_binary_GpakDsp10_fw_size, + (unsigned int) &_binary_GpakDsp10_fw_size); + } + + DspId = rcb_card->pos; + + for (byte_num = 0; byte_num < NumBytes; byte_num++) { + if ((file_size - 1) >= file_pos[DspId]) { + pBuffer[byte_num] = _binary_GpakDsp10_fw_start[file_pos[DspId]++]; + } + } + + return byte_num; +} + +int gpakReadFile_5507(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ) +{ + static int stats = 0; + int core_num; + int byte_num = -1; + int DspId; + static unsigned int file_pos[num_files][MAX_DSP_CORES]; + static unsigned int file_size[num_files]; + if (!(stats)) { + stats++; + for (core_num = 0; core_num < MAX_DSP_CORES; core_num++) { + file_pos[loader_file][core_num] = 0; + file_pos[app_file][core_num] = 0; + } + + file_size[loader_file] = (unsigned int) &_binary_DspLoader_fw_size; + + if (rcb_card->num_chans > 4) + file_size[app_file] = (unsigned int) &_binary_GpakDsp0708_fw_size; + else + file_size[app_file] = (unsigned int) &_binary_GpakDsp0704_fw_size; + + if (rcb_card->num_chans > 4) + printk("rcbfx %d: G168 07 08 DSP Loader file size = %d App file size = %d\n", + rcb_card->pos + 1, (unsigned int) &_binary_DspLoader_fw_size, + (unsigned int) &_binary_GpakDsp0708_fw_size); + else + printk("rcbfx %d: G168 07 04 DSP Loader file size = %d App file size = %d\n", + rcb_card->pos + 1, (unsigned int) &_binary_DspLoader_fw_size, + (unsigned int) &_binary_GpakDsp0704_fw_size); + } + + DspId = rcb_card->pos; + + + if (FileId == loader_file) { + for (byte_num = 0; byte_num < NumBytes; byte_num++) { + if ((file_size[loader_file] - 1) >= file_pos[loader_file][DspId]) { + pBuffer[byte_num] = + _binary_DspLoader_fw_start[file_pos[loader_file][DspId]++]; + } + } + } + + if (FileId == app_file) { + for (byte_num = 0; byte_num < NumBytes; byte_num++) { + if ((file_size[app_file] - 1) >= file_pos[app_file][DspId]) { + if (rcb_card->num_chans > 4) + pBuffer[byte_num] = + _binary_GpakDsp0708_fw_start[file_pos[app_file][DspId]++]; + else + pBuffer[byte_num] = + _binary_GpakDsp0704_fw_start[file_pos[app_file][DspId]++]; + } + } + } + + return byte_num; +} diff --git drivers/dahdi/rhino/rcbfx/GpakCust.h drivers/dahdi/rhino/rcbfx/GpakCust.h new file mode 100644 index 0000000..a82dc0f --- /dev/null +++ drivers/dahdi/rhino/rcbfx/GpakCust.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakCust.h + * + * Description: + * This file contains host system dependent definitions and prototypes of + * functions to support generic G.PAK API functions. The file is used when + * integrating G.PAK API functions in a specific host processor environment. + * + * Note: This file may need to be modified by the G.PAK system integrator. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + + +#ifndef _GPAKCUST_H /* prevent multiple inclusion */ +#define _GPAKCUST_H + +#include "GpakApi.h" + + +/* Host and DSP system dependent related definitions. */ +#define MAX_DSP_CORES 16 /* maximum number of DSP cores */ +#define MAX_CHANNELS 48 /* maximum number of channels */ +#define MAX_WAIT_LOOPS 50 /* max number of wait delay loops */ +#define DSP_IFBLK_ADDRESS 0x0100 /* DSP address of I/F block pointer */ +#define DOWNLOAD_BLOCK_SIZE 512 /* download block size (DSP words) */ + +#define loader_file 0 /* GPAK_FILE_ID for bootloader */ +#define app_file 1 /* GPAK_FILE_ID for application */ +#define num_files 2 + +extern void rcb_card_wait_hpi(struct rcb_card_t *rcb_card, __u8 flags); + +extern void rcb_card_dsp_set(struct rcb_card_t *rcb_card, __u32 dsp_address, + __u16 dsp_data); + +extern __u16 rcb_card_dsp_get(struct rcb_card_t *rcb_card, __u32 dsp_address); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadDspMemory - Read DSP memory. + * + * FUNCTION + * This function reads a contiguous block of words from DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +extern void gpakReadDspMemory(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to read */ + DSP_WORD * pWordValues /* pointer to array of word values variable */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteDspMemory - Write DSP memory. + * + * FUNCTION + * This function writes a contiguous block of words to DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +extern void gpakWriteDspMemory(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to write */ + DSP_WORD * pWordValues /* pointer to array of word values to write */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakHostDelay - Delay for a fixed time interval. + * + * FUNCTION + * This function delays for a fixed time interval before returning. The time + * interval is the Host Port Interface sampling period when polling a DSP for + * replies to command messages. + * + * RETURNS + * nothing + * + */ +extern void gpakHostDelay(void); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +extern void gpakLockAccess(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +extern void gpakUnlockAccess(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFile - Read a block of bytes from a G.PAK Download file. + * + * FUNCTION + * This function reads a contiguous block of bytes from a G.PAK Download file + * starting at the current file position. + * + * RETURNS + * The number of bytes read from the file. + * -1 indicates an error occurred. + * 0 indicates all bytes have been read (end of file) + * + */ +extern int gpakReadFile_5510(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ); + +extern int gpakReadFile_5507(struct rcb_card_t *rcb_card, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ); + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rcbfx/GpakErrs.h drivers/dahdi/rhino/rcbfx/GpakErrs.h new file mode 100644 index 0000000..c60ba12 --- /dev/null +++ drivers/dahdi/rhino/rcbfx/GpakErrs.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc. + * + * File Name: GpakErrs.h + * + * Description: + * This file contains DSP reply status codes used by G.PAK API functions to + * indicate specific errors. + * + * Version: 1.0 + * + * Revision History: + * 10/17/01 - Initial release. + * 07/03/02 - Updates for conferencing. + * 06/15/04 - Tone type updates. + * + */ + +#ifndef _GPAKERRS_H /* prevent multiple inclusion */ +#define _GPAKERRS_H + +/* Configure Serial Ports reply status codes. */ +typedef enum { + Pc_Success = 0, /* serial ports configured successfully */ + Pc_ChannelsActive = 1, /* unable to configure while channels active */ + Pc_TooManySlots1 = 2, /* too many slots selected for port 1 */ + Pc_InvalidBlockCombo1 = 3, /* invalid combination of blocks for port 1 */ + Pc_NoSlots1 = 4, /* no slots selected for port 1 */ + Pc_InvalidSlots1 = 5, /* invalid slot (> max) selected for port 1 */ + Pc_TooManySlots2 = 6, /* too many slots selected for port 2 */ + Pc_InvalidBlockCombo2 = 7, /* invalid combination of blocks for port 2 */ + Pc_NoSlots2 = 8, /* no slots selected for port 2 */ + Pc_InvalidSlots2 = 9, /* invalid slot (> max) selected for port 2 */ + Pc_TooManySlots3 = 10, /* too many slots selected for port 3 */ + Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */ + Pc_NoSlots3 = 12, /* no slots selected for port 3 */ + Pc_InvalidSlots3 = 13 /* invalid slot (> max) selected for port 3 */ +} GPAK_PortConfigStat_t; + +/* Configure Channel reply status codes. */ +typedef enum { + Cc_Success = 0, /* channel configured successfully */ + Cc_InvalidChannelType = 1, /* invalid Channel Type */ + Cc_InvalidChannel = 2, /* invalid Channel A Id */ + Cc_ChannelActiveA = 3, /* Channel A is currently active */ + Cc_InvalidInputPortA = 4, /* invalid Input A Port */ + Cc_InvalidInputSlotA = 5, /* invalid Input A Slot */ + Cc_BusyInputSlotA = 6, /* busy Input A Slot */ + Cc_InvalidOutputPortA = 7, /* invalid Output A Port */ + Cc_InvalidOutputSlotA = 8, /* invalid Output A Slot */ + Cc_BusyOutputSlotA = 9, /* busy Output A Slot */ + Cc_InvalidInputPortB = 10, /* invalid Input B Port */ + Cc_InvalidInputSlotB = 11, /* invalid Input B Slot */ + Cc_BusyInputSlotB = 12, /* busy Input B Slot */ + Cc_InvalidPktInCodingA = 13, /* invalid Packet In A Coding */ + Cc_InvalidPktOutCodingA = 14, /* invalid Packet Out A Coding */ + Cc_InvalidPktInSizeA = 15, /* invalid Packet In A Frame Size */ + Cc_InvalidPktOutSizeA = 16, /* invalid Packet Out A Frame Size */ + + Cc_ChanTypeNotConfigured = 21, /* channel type was not configured */ + Cc_InsuffECResources = 22, /* insufficient ecan resources avail. */ + Cc_InsuffTDMResources = 23, /* insufficient tdm block resources avail. */ + + Cc_InsuffPktBufResources = 25, /* insufficient pkt buffer resources avail. */ + Cc_InsuffPcmBufResources = 26, /* insufficient pcm buffer resources avail. */ + + Cc_BadPcmEcNlpType = 30, /* invalid EC Nlp type */ + Cc_BadPcmEcTapLength = 31, /* invalid EC tap length */ + Cc_BadPcmEcDblTalkThresh = 32, /* invalid EC double-talk threshold */ + Cc_BadPcmEcNlpThreshold = 33, /* invalid EC Nlp threshold */ + Cc_BadPcmEcCngThreshold = 34, /* invalid EC Cng threshold */ + Cc_BadPcmEcAdaptLimit = 35, /* invalid EC Adapt Limit */ + Cc_BadPcmEcCrossCorrLim = 36, /* invalid EC Cross Correlation Limit */ + Cc_BadPcmEcNumFirSegs = 37, /* invalid EC Number of FirSegments */ + Cc_BadPcmEcFirSegLen = 38, /* invalid EC Fir Segment Length */ + + //Cc_InvalidNumEcsEnabled = 48, /* more than 1 Ec enabled on channel */ + Cc_InvalidFrameRate = 49, /* invalid gpak frame rate */ + Cc_InvalidSoftCompand = 50 /* invalid softCompanding type */ +} GPAK_ChannelConfigStat_t; + +/* Tear Down Channel reply status codes. */ +typedef enum { + Td_Success = 0, /* channel torn down successfully */ + Td_InvalidChannel = 1, /* invalid Channel Id */ + Td_ChannelNotActive = 2 /* channel is not active */ +} GPAK_TearDownChanStat_t; + + +typedef enum { + Ac_Success = 0, /* algorithm control is successfull */ + Ac_InvalidChannel = 1, /* invalid channel identifier */ + Ac_InvalidCode = 2, /* invalid algorithm control code */ + Ac_ECNotEnabled = 3, /* echo canceller was not allocated */ + Ac_InvalidSoftComp = 4 /* invalid softcompanding, 'cause serial port not in companding mode */ +} GPAK_AlgControlStat_t; + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rcbfx/GpakExts.h drivers/dahdi/rhino/rcbfx/GpakExts.h new file mode 100644 index 0000000..ece1703 --- /dev/null +++ drivers/dahdi/rhino/rcbfx/GpakExts.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2001, Adaptive Digital Technologies, Inc. + * + * File Name: GpakExts.h + * + * Description: + * This file contains G.PAK external data and function declarations. + * + * Version: 1.0 + * + * Revision History: + * 11/13/01 - Initial release. + * + */ + +#ifndef _GPAKEXTS_H /* prevent multiple inclusion */ +#define _GPAKEXTS_H + +#include "GpakEnum.h" +#include "sysconfig.h" + + +// Definition of System Configuration related constants and variables. +extern sysConfig_t sysConfig; // System Configuration Info +extern struct chanInfo *chanTable[]; // pointers to Channel structures + +// work input/output buffers +extern USHORT inWork_10msec[]; +extern USHORT outWork_10msec[]; +extern USHORT ECFarWork_10msec[]; + +extern USHORT inWork_2msec[]; +extern USHORT outWork_2msec[]; +extern USHORT ECFarWork_2msec[]; + +extern USHORT inWork_1msec[]; +extern USHORT outWork_1msec[]; +extern USHORT ECFarWork_1msec[]; + +// Echo Canceller scratch memory. +extern USHORT G168SAscratch_10ms[]; // G.168 SARAM scratch for 10 msec task +extern USHORT G168DAscratch_10ms[]; // G.168 DARAM scratch for 10 msec task + +extern USHORT G168SAscratch_2ms[]; // G.168 SARAM scratch for 2 msec task +extern USHORT G168DAscratch_2ms[]; // G.168 DARAM scratch for 2 msec task + +extern USHORT G168SAscratch_1ms[]; // G.168 SARAM scratch for 1 msec task +extern USHORT G168DAscratch_1ms[]; // G.168 DARAM scratch for 1 msec task + + +// Pointers to Echo Canceller data structures. +extern USHORT *pPcmEcDaState[]; // pntr to PCM EC DA States +extern USHORT *pPcmEcSaState[]; // pntr to PCM EC SA States +extern USHORT *pPcmEcEchoPath[]; // pntr to PCM EC Echo Paths +extern USHORT *pPcmEcBackEp[]; // pntr to PCM EC Background Echo Paths +extern USHORT *pPcmEcBackFar[]; // pntr to PCM EC Background Nears +extern USHORT *pPcmEcBackNear[]; // pntr to PCM EC Background Fars +extern USHORT *pPktEcDaState[]; // pntr to Pkt EC DA States +extern USHORT *pPktEcSaState[]; // pntr to Pkt EC SA States +extern USHORT *pPktEcEchoPath[]; // pntr to Pkt EC Echo Paths +extern USHORT *pPktEcBackEp[]; // pntr to Pkt EC Background Echo Paths +extern USHORT *pPktEcBackFar[]; // pntr to Pkt EC Background Nears +extern USHORT *pPktEcBackNear[]; // pntr to Pkt EC Background Fars + +extern sysConfig_t sysConfig; +extern struct chanInfo *chanTable[]; + +extern USHORT DmaLoopback[]; // DMA Loopback flag for each port +extern USHORT NumCfgSlots[]; // num time slots configured on McBSP +extern USHORT McRcvChanEnabA[]; // McBSP's Rcv Chan Enable A reg val +extern USHORT McRcvChanEnabB[]; // McBSP's Rcv Chan Enable B reg val +extern USHORT McXmtChanEnabA[]; // McBSP's Xmt Chan Enable A reg val +extern USHORT McXmtChanEnabB[]; // McBSP's Xmt Chan Enable B reg val + + +extern USHORT BSP0DMA_TxBuffer[]; // DMA Transmit buffer for McBSP0 +extern USHORT BSP0DMA_RxBuffer[]; // DMA Receive buffer for McBSP0 +extern USHORT BSP1DMA_TxBuffer[]; // DMA Transmit buffer for McBSP1 +extern USHORT BSP1DMA_RxBuffer[]; // DMA Receive buffer for McBSP1 +extern USHORT BSP2DMA_TxBuffer[]; // DMA Transmit buffer for McBSP2 +extern USHORT BSP2DMA_RxBuffer[]; // DMA Receive buffer for McBSP2 +extern chanInfo_t GpakChanInstance[]; + + + + +extern USHORT PcmInBufferPool[]; +extern USHORT PcmOutBufferPool[]; +extern USHORT PcmBInBufferPool[]; +extern USHORT PcmBOutBufferPool[]; +extern CircBufInfo_t PcmBOutCircInfo[]; +extern CircBufInfo_t PcmBInCircInfo[]; + +// System status variables. +extern USHORT NumActiveChannels; // number of active channels +// Echo Canceller management variables. +extern USHORT NumPcmEcansUsed; // number of PCM Echo Cancellers in use +extern USHORT PcmEcInUse[]; // flag indicating PCM Echo Canceller in use + +// Echo Canceller management variables. +extern USHORT *pPcmEcChan[]; // pointer to PCM Echo Canceller channels +extern USHORT *pPktEcChan[]; // pointer to Packet Echo Canceller channels + +extern chanInfo_t GpakChanInstance[]; +extern CPG_Instance_t ToneGenInstance[]; +extern CPG_Params_t CPGParms[]; +extern G168Params_t EcParmsA[]; +extern G168Params_t EcParmsB[]; + +// Definition of function prototypes and their return values. + +// Initialize G.PAK interface with host processor. +extern void InitGpakInterface(void); + +// Initialize G.PAK PCM I/O. +extern void InitGpakPcm(void); + +// Initialize G.PAK Framing task data. +extern void InitFrameTasks(void); + +// Initialize a G.PAK channel's Channel structure. +extern struct chanInfo *initChanStruct(USHORT * saramBlock, // pointer to channel's SARAM memory block + USHORT * daramBlock, // pointer to channel's DARAM memory block + USHORT channelId // channels Id + ); + +// ConfigureGpakPcm return status. +typedef enum { + SPCSuccess, // serial ports configured successfully + SPCTooManySlots1, // too many slots selected for port 1 + SPCInvalidBlockCombo1, // invalid combination of blocks for port 1 + SPCNoSlots1, // no slots selected for port 1 + SPCInvalidSlots1, // invalid slot (exceeds max) selected for port 1 + SPCTooManySlots2, // too many slots selected for port 2 + SPCInvalidBlockCombo2, // invalid combination of blocks for port 2 + SPCNoSlots2, // no slots selected for port 2 + SPCInvalidSlots2, // invalid slot (exceeds max) selected for port 2 + SPCTooManySlots3, // too many slots selected for port 3 + SPCInvalidBlockCombo3, // invalid combination of blocks for port 3 + SPCNoSlots3, // no slots selected for port 3 + SPCInvalidSlots3 // invalid slot (exceeds max) selected for port 3 +} SPCStatus_t; + +// Configure G.PAK PCM I/O. +extern SPCStatus_t ConfigureGpakPcm(GpakSlotCfg_t SlotsSelect[], // port's Slot selection + USHORT BlockNumber1[], // port's first group Block Number + USHORT SlotMask1[], // port's first group Slot Mask + USHORT BlockNumber2[], // port's second group Block Number + USHORT SlotMask2[] // port's second group Slot Mask + ); + +// Get the address of PCM to Pkt framing rate queue head. +extern chanInfo_t **GetPcmToPktQueueHead(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Get the address of Pkt to PCM framing rate queue head. +extern chanInfo_t **GetPktToPcmQueueHead(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Determine the address of a framing rate phase counter. +extern USHORT *FrameRatePhaseCount(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Adjust Far Echo and Bulk Delay buffer indices. +extern void AdjustFarBulkIndices(int WriteFrameSize, // Bulk writer's frame size (samples per frame) + int ReadFrameSize, // Far reader's frame size (samples per frame) + USHORT * pWrtPhaseCnt, // pointer to Bulk writer's DMA phase count + USHORT * pReadPhaseCnt, // pointer to Far reader's DMA phase count + USHORT BulkDelaySize, // size of Bulk Delay buffer (samples) + USHORT * pBulkPutIndex, // pointer to Bulk Delay buffer's Put index var + USHORT * pFarTakeIndex // pointer to Far Echo buffer's Take index var + ); + +// Enqueue a channel to it's framing rate or conference queues. +extern void EnqueueChannel(chanInfo_t * pChanInfo, // pointer to channel's Channel Info + chanInfo_t ** pPcm2PktHead, // pointer to PCM to Packet queue head + chanInfo_t ** pPkt2PcmHead // pointer to Packet to PCM queue head + ); + +// Dequeue a channel from it's framing rate/conference queues. +extern void DequeueChannel(chanInfo_t * pChanInfo, // pointer to channel's Channel Info + chanInfo_t ** pPcm2PktHead, // pointer to PCM to Packet queue head + chanInfo_t ** pPkt2PcmHead // pointer to Packet to PCM queue head + ); + +// ActivateGpakChannel return status. +typedef enum { + ACSuccess, // channel activated successfully + ACInvalidInputPort1, // invalid Input Port 1 + ACInvalidInputSlot1, // invalid Input Slot 1 + ACBusyInputSlot1, // busy Input Slot 1 + ACInvalidOutputPort1, // invalid Output Port 1 + ACInvalidOutputSlot1, // invalid Output Slot 1 + ACBusyOutputSlot1, // busy Output Slot 1 + ACInvalidInputPort2, // invalid Input Port 2 + ACInvalidInputSlot2, // invalid Input Slot 2 + ACBusyInputSlot2, // busy Input Slot 2 + ACInvalidOutputPort2, // invalid Output Port 2 + ACInvalidOutputSlot2, // invalid Output Slot 2 + ACBusyOutputSlot2 // busy Output Slot 2 +} ACStatus_t; + +// Activate a G.PAK Channel. +extern ACStatus_t ActivateGpakChannel(chanInfo_t * pChanInfo // pointer to Channel Info + ); + +// Deactivate a G.PAK Channel. +extern void DeactivateGpakChannel(chanInfo_t * pChanInfo // pointer to Channel Info + ); + +// Determine if the frame size is valid. +extern int ValidFrameSize(int FrameSize // Frame Size + ); + + +// Copy linear buffer to circular buffer. +extern void copyLinearToCirc(USHORT * src, CircBufInfo_t * dest, USHORT len); + +// Copy circular buffer to linear buffer. +extern void copyCircToLinear(CircBufInfo_t * src, USHORT * dest, USHORT len); + +// Perform VAD, Tone Detect, and Encode functions. +extern void ProcessVadToneEncode(chanInfo_t * pChanInfo, // pointer to Channel Info + USHORT * pInWork, // pointer to input work buffer (contains data) + USHORT * pOutWork // pointer to output work buffer + ); + +// Initialize an Echo Canceller. +extern G168ChannelInstance_t *InitEchoCanceller(USHORT FrameSize, // number of samples per frame + G168Params_t * EcInitParms, // Echo Canceller initialization parameters + short int EcanIndex // variable that stores ecan index + ); + +/* +extern void ToneGenerate( + short int *pToneActive, + short int *pToneUpdate, + CPG_Instance_t *pToneGenPtr, + CPG_Params_t *pToneParms, + short int *pToneData, + GpakToneGenCmd_t ToneCmd, + short int FrameSize + ); +*/ + +extern void algorithmControl(chanInfo_t * pChan // pointer to Channel structure + ); + + +extern void writeTransmitEnables(USHORT McBspId, // McBSP Id + USHORT MaskA, // A Block mask bits to be written + USHORT MaskB // B Block mask bits to be written + ); + +void ResetCpuUsageStats(); + +int validFrameRate(chanInfo_t * pChan, GpakRate_t frameRate); + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rcbfx/GpakHpi.h drivers/dahdi/rhino/rcbfx/GpakHpi.h new file mode 100644 index 0000000..abe731b --- /dev/null +++ drivers/dahdi/rhino/rcbfx/GpakHpi.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2001, Adaptive Digital Technologies, Inc. + * + * File Name: GpakHpi.h + * + * Description: + * This file contains common definitions related to the G.PAK interface + * between a host processor and a DSP processor via the Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 10/17/01 - Initial release. + * + */ + +#ifndef _GPAKHPI_H /* prevent multiple inclusion */ +#define _GPAKHPI_H + + +/* Definition of G.PAK Command/Reply message type codes. */ +#define MSG_NULL_REPLY 0 /* Null Reply (unsupported Command) */ +#define MSG_SYS_CONFIG_RQST 1 /* System Configuration Request */ +#define MSG_SYS_CONFIG_REPLY 2 /* System Configuration Reply */ +#define MSG_READ_SYS_PARMS 3 /* Read System Parameters */ +#define MSG_READ_SYS_PARMS_REPLY 4 /* Read System Parameters Reply */ +#define MSG_WRITE_SYS_PARMS 5 /* Write System Parameters */ +#define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */ +#define MSG_CONFIGURE_PORTS 7 /* Configure Serial Ports */ +#define MSG_CONFIG_PORTS_REPLY 8 /* Configure Serial Ports Reply */ +#define MSG_CONFIGURE_CHANNEL 9 /* Configure Channel */ +#define MSG_CONFIG_CHAN_REPLY 10 /* Configure Channel Reply */ +#define MSG_TEAR_DOWN_CHANNEL 11 /* Tear Down Channel */ +#define MSG_TEAR_DOWN_REPLY 12 /* Tear Down Channel Reply */ +#define MSG_CHAN_STATUS_RQST 13 /* Channel Status Request */ +#define MSG_CHAN_STATUS_REPLY 14 /* Channel Status Reply */ + +#define MSG_TEST_MODE 17 /* Configure/Perform Test Mode */ +#define MSG_TEST_REPLY 18 /* Configure/Perform Test Mode Reply */ + +#define MSG_ALG_CONTROL 27 /* algorithm control */ +#define MSG_ALG_CONTROL_REPLY 28 /* algorithm control reply */ +#define MSG_GET_TXCID_ADDRESS 29 /* get tx cid buffer start address */ +#define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */ + +#define MSG_PING 35 /* ping command */ +#define MSG_PING_REPLY 36 /* ping command reply */ +#define MSG_SERIAL_TXVAL 37 /* transmit serial fixed value */ +#define MSG_SERIAL_TXVAL_REPLY 38 /* transmit serial fixed value reply */ +#define MSG_TDM_LOOPBACK 39 /* tdm loopback control */ +#define MSG_TDM_LOOPBACK_REPLY 40 /* tdm loopback control reply */ +#define MSG_RESET_USAGE_STATS 41 /* reset cpu usage stats */ +#define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */ + +#define MSG_RESET_FRAME_STATS 47 /* reset framing stats */ +#define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */ + +#define MSG_READ_DSP_MEMORY 49 /* read small section of DSP's memory */ +#define MSG_READ_DSP_MEMORY_REPLY 50 /* read memory reply */ +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rcbfx/Makefile drivers/dahdi/rhino/rcbfx/Makefile new file mode 100644 index 0000000..46ecdab --- /dev/null +++ drivers/dahdi/rhino/rcbfx/Makefile @@ -0,0 +1,13 @@ +obj-m += rcbfx.o + +rcbfx-objs := rcbfx_base.o + +$(obj)/rcbfx_base.o: $(src)/rcbfx.h $(src)/GpakApi.h $(src)/GpakCust.h + +clean: + @rm -f *.o + @rm -f *.cmd *.o *.ko + @rm -f .*.cmd .*.o + @rm -rf .tmp_versions Module.symvers + @rm -f core + diff --git drivers/dahdi/rhino/rcbfx/gpakenum.h drivers/dahdi/rhino/rcbfx/gpakenum.h new file mode 100644 index 0000000..bb10517 --- /dev/null +++ drivers/dahdi/rhino/rcbfx/gpakenum.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: gpakenum.h + * + * Description: + * This file contains common enumerations related to G.PAK application + * software. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + +#ifndef _GPAKENUM_H /* prevent multiple inclusion */ +#define _GPAKENUM_H + +/* G.PAK Serial Port Word Size */ +typedef enum { + SerWordSize8 = 0, // 8-bit seial word + SerWordSize16 = 1 // 16-bit serial word +} GpakSerWordSize_t; + +/* G.PAK Serial Port FrameSync Polarity */ +typedef enum { + FrameSyncActLow = 0, // active low frame sync signal + FrameSyncActHigh = 1 // active high frame sync signal +} GpakSerFrameSyncPol_t; + +/* G.PAK Serial Port Clock Polarity */ +typedef enum { + SerClockActLow = 0, // active low serial clock + SerClockActHigh = 1 // active high serial clock +} GpakSerClockPol_t; + +/* G.PAK Serial Port Data Delay */ +typedef enum { + DataDelay0 = 0, // no data delay + DataDelay1 = 1, // 1-bit data delay + DataDelay2 = 2 // 2-bit data delay +} GpakSerDataDelay_t; + +/* G.PAK Serial Port Ids. */ +typedef enum { + SerialPortNull = 0, // null serial port + SerialPort1 = 1, // first PCM serial stream port (McBSP0) + SerialPort2 = 2, // second PCM serial stream port (McBSP1) + SerialPort3 = 3 // third PCM serial stream port (McBSP2) +} GpakSerialPort_t; + +/* G.PAK serial port Slot Configuration selection codes. */ +typedef enum { + SlotCfgNone = 0, // no time slots used + SlotCfg2Groups = 2, // 2 groups of 16 time slots used, 32 Channels system + SlotCfg8Groups = 8 // 8-partition mode for 128-channel system +} GpakSlotCfg_t; + +/* G.PAK serial port Companding Mode codes. */ +typedef enum { + cmpPCMU = 0, // u-Law + cmpPCMA = 1, // A-Law + cmpNone = 2 // none +} GpakCompandModes; + +/* G.PAK Active/Inactive selection codes. */ +typedef enum { + Disabled = 0, // Inactive + Enabled = 1 // Active +} GpakActivation; + +/* G.PAK Channel Type codes. */ +typedef enum { + inactive = 0, // channel inactive + tdmToTdm = 1 // tdmToTdm +} GpakChanType; + +/* G.PAK Algorithm control commands */ +typedef enum { + EnableEcanA = 0, // Enable A side echo canceller + BypassEcanA = 1, // Bypass A side echo canceller + ResetEcanA = 2, // Reset A side echo canceller + EnableEcanB = 3, // Enable B side echo canceller + BypassEcanB = 4, // Bypass B side echo canceller + ResetEcanB = 5, // Reset B side echo canceller + + EnableMuLawSwCompanding = 6, // Enable Mu-law Software companding + EnableALawSwCompanding = 7, // Enable Mu-law Software companding + BypassSwCompanding = 8 // Bypass Software companding +} GpakAlgCtrl_t; + +/* G.PAK Tone types. */ +typedef enum { + Null_tone = 0, // no tone detection + DTMF_tone = 1 // DTMF tone +} GpakToneTypes; + +/* G.PAK direction. */ +typedef enum { + TDMAToB = 0, // A to B + TDMBToA = 1 // B to A +} GpakTdmDirection; + + +typedef enum { + rate1ms = 0, + rate2ms = 1, + rate10ms = 2 +} GpakRate_t; + +/* G.PAK Asynchronous Event Codes */ +typedef enum { + EventToneDetect = 0, // Tone detection event + EventDSPDebug = 7 // DSP debug data event +} GpakAsyncEventCode_t; + +/* G.PAK MF Tone Code Indices */ +typedef enum { + DtmfDigit1 = 0, // DTMF Digit 1 + DtmfDigit2 = 1, // DTMF Digit 2 + DtmfDigit3 = 2, // DTMF Digit 3 + DtmfDigitA = 3, // DTMF Digit A + DtmfDigit4 = 4, // DTMF Digit 4 + DtmfDigit5 = 5, // DTMF Digit 5 + DtmfDigit6 = 6, // DTMF Digit 6 + DtmfDigitB = 7, // DTMF Digit B + DtmfDigit7 = 8, // DTMF Digit 7 + DtmfDigit8 = 9, // DTMF Digit 8 + DtmfDigit9 = 10, // DTMF Digit 9 + DtmfDigitC = 11, // DTMF Digit C + DtmfDigitSt = 12, // DTMF Digit * + DtmfDigit0 = 13, // DTMF Digit 0 + DtmfDigitPnd = 14, // DTMF Digit # + DtmfDigitD = 15, // DTMF Digit D + + EndofMFDigit = 100, // End of MF digit + EndofCngDigit = 101 // End of Cng Digit +} GpakToneCodes_t; + +#endif // end multiple inclusion diff --git drivers/dahdi/rhino/rcbfx/rcbfx.h drivers/dahdi/rhino/rcbfx/rcbfx.h new file mode 100644 index 0000000..39015c1 --- /dev/null +++ drivers/dahdi/rhino/rcbfx/rcbfx.h @@ -0,0 +1,269 @@ +/* + * Rhino RCB FXO / FXS Interface Driver + * + * Release version 10/10/10 + * + * Written by + * Bob Conklin + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's TDM400P TDM FXS/FXO + * and Zapata Telephony's Zaptel Telephony Interface + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * Copyright (C) 2001-2005, Digium, Inc. + * Copyright (C) 2001 Jim Dixon / Zapata Telephony. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * * * * * * * * * * * * * NO WARRANTY * * * * * * * * * * * * * * * * * + * + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + * + * * * * * * * * * * * * DISCLAIMER OF LIABILITY * * * * * * * * * * * * + * + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _RCBFX_H +#define _RCBFX_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define NUM_FXO_REGS 60 + +#define RH_MAX_IFACES 128 +#define PCI_VENDOR_RHINO 0xb0b +#define PCI_DEVICE_RCB8FXX 0x406 +#define PCI_DEVICE_RCB24FXS 0x506 +#define PCI_DEVICE_RCB24FXX 0x906 +#define PCI_DEVICE_RCB24FXO 0x706 +#define PCI_DEVICE_RCB4FXO 0x206 + +#define RCB_STATE 0x800 +#define RCB_VERSION 0x802 +#define RCB_CONTROL 0x804 +#define RCB_INTSTAT 0x805 +#define RCB_BUFLEN 0x806 +#define RCB_RXBUFSTART 0x808 +#define RCB_TXBUFSTART 0x80C +#define RCB_JTAG 0x810 +#define RCB_TXSIG0 0x820 +#define RCB_RXSIG0 0x830 +#define RCB_RXSIGSTAT 0x83C +#define RCB_TXSIGSTAT 0x82C +#define RCB_CHANPRES 0x840 +#define RCB_CHANTYPE 0x844 +#define RH_SPI_DIV 0x811 +#define RH_OLDSPI 0x814 +#define RH_SPI 0x814 +#define RH_CSR 0x815 +#define SPI_WR 0x818 +#define SPI_RD 0x81C +#define FW_DATA 0x854 +#define FW_COMOUT 0x855 +#define FW_VER 0x856 +#define FW_COMIN 0x858 +#define FW_BOOT 0x859 +#define FW_BOOT_LOAD 2 +#define FW_BOOT_RST 1 +#define DSP_RST 4 +#define FW_SUM 0x85A +#define EC_CNTL 0x85B +#define EC_ON 1 +#define RCB_STATOUT 0x854 +#define RCB_TDM_PTR 0x85C +#define RCB_HPIC 0x860 +#define RCB_XADD (1 << 5) +#define RCB_BL_GO (1 << 0) +#define RCB_HPIDAI 0x864 +#define RCB_HPIA 0x868 +#define RCB_HPID 0x86C + +#define RCB_HPIRD 0x870 +#define RCB_HPIRD_STAT 0x872 + +#define RCB_HRDY 1 +#define RCB_BUSY_N 2 +#define RCB_D_NEW 4 + +#define RCB_HPIRDX 0x874 +#define RCB_HPIRDX_STAT 0x876 + +#define RCB_EC_ENA 0x878 +#define RCB_EC_ENB 0x87C + +#define RCB_LVSSAMP 0x3ff /* 1.024 sec */ +#define RCB_LVSTAB 0x880 +#define RCB_REGTAB 0x898 +#define RCB_REGADDR 0x8b1 +#define RCB_BATTTIME 0x8b0 +#define RCB_REGTIME 1500 /* 1.5 sec */ + +#define RCB_SIZE 0x8b4 + +#define DSP_ENTRY_ADDR_LO 0x0061 +#define DSP_ENTRY_ADDR_HI 0x0060 + +#define RH_SYNC 0x0 +#define RH_TEST 0x1 +#define RH_CS 0x2 +#define RH_VER 0x3 + +#define BIT_CS (1 << 2) +#define BIT_SCLK (1 << 3) +#define BIT_SDI (1 << 4) +#define BIT_SDO (1 << 5) +#define BIT_RST (1 << 6) +#define BIT_DMAGO (1 << 0) +#define INT_ACK (1 << 1) + +#define DEBUG_MAIN (1 << 0) +#define DEBUG_INTS (1 << 1) +#define DEBUG_DSP (1 << 2) +#define DEBUG_SIG (1 << 3) + +#define STOP_DMA (1 << 0) +#define FREE_DMA (1 << 1) +#define IOUNMAP (1 << 2) +#define ZUNREG (1 << 3) +#define FREE_INT (1 << 4) +#define RH_KFREE (1 << 5) +#define PCI_FREE (1 << 6) +#define RST_SLAB (1 << 7) + +#define FLAG_EMPTY 0 +#define FLAG_WRITE 1 +#define FLAG_READ 2 + +/* the constants below control the 'debounce' periods enforced by the + check_hook routines; these routines are called once every 4 interrupts + (the interrupt cycles around the four modules), so the periods are + specified in _4 millisecond_ increments +*/ +#define RING_DEBOUNCE 4 /* Ringer Debounce (64 ms) */ +#define DEFAULT_BATT_DEBOUNCE 4 /* 4 = Battery debounce (64 ms) */ +#define POLARITY_DEBOUNCE 8 /* 4 = Polarity debounce (64 ms) */ +#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ + +#define OHT_TIMER 6000 /* How long after RING to retain OHT */ + +#define MAX_CHANS 32 + +#define MAX_ALARMS 10 + +#define MOD_TYPE_UNK 0 +#define MOD_TYPE_FXS 1 +#define MOD_TYPE_FXO 2 + +#define DSP_NONE 0 +#define DSP_5507 1 +#define DSP_5510 2 + +#define PCMEN (1 << 4) +#define ALAW 0x00 +#define ULAW 0x01 +#define LCR (1 << 0) +#define CAL (1 << 7) + +#define RCB_CHAN_REG 72 + + +struct rcb_card_t { + struct pci_dev *dev; + struct dahdi_span span; + unsigned char ios; + int usecount; + unsigned int intcount; + unsigned int tdm_ptr; + unsigned int nextbuf; + long unsigned int last_jiffie; + long unsigned int buf_int_diff; + int dead; + int pos; + int freeregion; + int alt; + int hpi_fast; + int hpi_xadd; + int dsp_up; + int dsp_type; + int curcard; + int oldreg_addr; + int read_on_int; + int num_chans; + int num_slots; + int chanflag; /* Bit-map of present cards */ + spinlock_t lock; + + /* Receive hook state and debouncing */ + int modtype[MAX_CHANS]; + int fxs_chanmap; + int fxo_chanmap; + int chans_configed; + int param_upd_state; + int comerr[MAX_CHANS]; + int retry[MAX_CHANS]; + int lastcomerr[MAX_CHANS]; + long unsigned int baseaddr; + int currec; + int nextec; + wait_queue_head_t regq; + struct workqueue_struct *wq; + struct work_struct work; + int memlen; + int hw_ver_min; + void *memaddr; + dma_addr_t readdma; + dma_addr_t writedma; + volatile unsigned char *writechunk; /* Double-word aligned write memory */ + volatile unsigned char *readchunk; /* Double-word aligned read memory */ + struct dahdi_chan *chans[MAX_CHANS]; + char *variety; + struct dahdi_echocan_state *ec[MAX_CHANS]; /* echocan state for each channel */ +}; + +#endif /* _RCBFX_H */ diff --git drivers/dahdi/rhino/rcbfx/rcbfx_base.c drivers/dahdi/rhino/rcbfx/rcbfx_base.c new file mode 100644 index 0000000..6b701ce --- /dev/null +++ drivers/dahdi/rhino/rcbfx/rcbfx_base.c @@ -0,0 +1,1909 @@ +/* + * Rhino RCB FXO / FXS Interface Driver + * + * Release version 10/10/10 + * + * Written by + * Bob Conklin + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's TDM400P TDM FXS/FXO + * and Zapata Telephony's Zaptel Telephony Interface + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * Copyright (C) 2001-2005, Digium, Inc. + * Copyright (C) 2001 Jim Dixon / Zapata Telephony. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * * * * * * * * * * * * * NO WARRANTY * * * * * * * * * * * * * * * * * + * + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + * + * * * * * * * * * * * * DISCLAIMER OF LIABILITY * * * * * * * * * * * * + * + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#define USE_G168_DSP + +/* /include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "rcbfx.h" +#include + +#ifdef USE_G168_DSP +#include "GpakCust.h" +#include "GpakApi.h" +#endif + +struct rcb_card_desc { + char *name; + unsigned int type_idx; + unsigned int num_chans; + unsigned int num_slots; + unsigned int hw_ver_min; +}; + +#define FLAG_2CHAN_SPI (1 << 0) + +static struct rcb_card_desc rcb8fxx = { "Rhino RCB8FXX", FLAG_2CHAN_SPI, 8, 8, 8 }; +static struct rcb_card_desc rcb24fxs = { "Rhino RCB24FXS", FLAG_2CHAN_SPI, 24, 32, 8 }; +static struct rcb_card_desc rcb24fxx = { "Rhino RCB24FXX", FLAG_2CHAN_SPI, 24, 32, 8 }; +static struct rcb_card_desc rcb24fxo = { "Rhino RCB24FXO", FLAG_2CHAN_SPI, 24, 32, 8 }; +static struct rcb_card_desc rcb4fxo = { "Rhino RCB4FXO", FLAG_2CHAN_SPI, 4, 4, 7 }; + +static struct rcb_card_t *ifaces[RH_MAX_IFACES]; + +static int show_pointers = 0; +static int debug = 0; +/* static int debug = (DEBUG_MAIN | DEBUG_INTS | DEBUG_DSP); */ +/* static int debug = (DEBUG_MAIN | DEBUG_INTS | DEBUG_DSP | DEBUG_SIG); */ +static int ec_fxo_alg = 0; /* B side on */ +static int ec_fxs_alg = 0xffffff; /* A side on */ +static int use_ec_fxo = 0; /* B side from alg */ +static int use_ec_fxs = 0xffffff; /* A side from alg */ +static int use_ec_zap = -1; /* Enable zaptel echo can */ +static int use_ec = -1; /* Switch in DSP's TDM bus */ +static int force_fw = 0; +static int no_ec = 0; +static int nlp_type = 3; +/* Internal results of calculations */ +static int zt_ec_chanmap = 0; +static int fxs_alg_chanmap = 0; +static int fxo_alg_chanmap = 0; +static int use_fxs_chanmap = 0; +static int use_fxo_chanmap = 0; +static int lvs[24]; +static int reg_val[24]; +static int battime = 100; +static int reg_addr = 0; +static int arr_argc = 24; + +void *mmap(void *, size_t, int, int, int, off_t); +int open(const char *path, int oflags); + +static const char *rcbfx_firmware = "rcbfx.fw"; + +static int rcbfx_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, + struct dahdi_echocan_state **ec); +static void rcbfx_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); + +static const struct dahdi_echocan_features my_ec_features = { + .NLP_automatic = 1, + .CED_tx_detect = 1, + .CED_rx_detect = 1, +}; + +static const struct dahdi_echocan_ops my_ec_ops = { + .name = "RCBFX_HWEC", + .echocan_free = rcbfx_echocan_free, +}; + +static inline void rcb_card_transmit(struct rcb_card_t *rcb_card, unsigned char ints) +{ + dahdi_transmit(&rcb_card->span); +} + +static inline void rcb_card_receive(struct rcb_card_t *rcb_card, unsigned char ints) +{ + if (!rcb_card->dsp_up) + dahdi_ec_span(&rcb_card->span); + dahdi_receive(&rcb_card->span); +} + +static int rcb_dahdi_chan_rbsbits(struct dahdi_chan *chan, int bits) +{ + int channum, high_nib, regnum; + struct dahdi_span *span = chan->span; + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + unsigned long flags; + + if (debug & DEBUG_SIG) + printk("rcbfx %d: RBS bits Setting bits to %d on channel %s\n", rcb_card->pos + 1, + bits, chan->name); + + spin_lock_irqsave(&rcb_card->lock, flags); + + channum = chan->chanpos - 1; /* Zero base */ + high_nib = 4 * (channum & 1); + regnum = channum >> 1; + + *(volatile __u8 *) (rcb_card->memaddr + RCB_TXSIG0 + regnum) &= ~(0xF << high_nib); + *(volatile __u8 *) (rcb_card->memaddr + RCB_TXSIG0 + regnum) |= bits << high_nib; + if (debug & DEBUG_SIG) + printk("rcbfx %d: txsig0 = %x\n", rcb_card->pos + 1, + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIG0)); + + spin_unlock_irqrestore(&rcb_card->lock, flags); + + return 0; +} + +static void rcb_card_check_sigbits(struct rcb_card_t *rcb_card, int status) +{ + int rxs, regnum; + + if (debug & DEBUG_SIG) + printk("rcbfx %d: Checking sigbits %x configged %x\n", rcb_card->pos + 1, status, + rcb_card->chans_configed); + + if (rcb_card->chans_configed) { + for (regnum = 0; regnum < 12; regnum++) { /* 12 bytes of sig data to check */ + if (status & (1 << regnum)) { + rxs = *(volatile __u8 *) (rcb_card->memaddr + RCB_RXSIG0 + regnum); + if (rcb_card->num_chans > (regnum * 2)) { /* make sure the chan exists */ + if (debug & DEBUG_SIG) + printk("rcbfx %d: rbsbits channel: %x, bits: %x\n", + rcb_card->pos + 1, regnum * 2, (rxs & 0xf)); + dahdi_rbsbits(rcb_card->span.chans[regnum * 2], (rxs & 0xf)); + } else if (debug & DEBUG_SIG) + printk + ("rcbfx %d: invalid signaling data recieved channel: %d, bits: %x\n", + rcb_card->pos + 1, regnum * 2, (rxs & 0xf)); + + if (rcb_card->num_chans > (regnum * 2 + 1)) { /* make sure the chan exists */ + if (debug & DEBUG_SIG) + printk("rcbfx %d: rbsbits channel: %x, bits: %x\n", + rcb_card->pos + 1, regnum * 2 + 1, ((rxs & 0xf0) >> 4)); + dahdi_rbsbits(rcb_card->span.chans[regnum * 2 + 1], + (rxs & 0xf0) >> 4); + } else if (debug & DEBUG_SIG) + printk + ("rcbfx %d: invalid signaling data recieved channel: %d, bits: %x\n", + rcb_card->pos + 1, regnum * 2 + 1, ((rxs & 0xf0) >> 4)); + } + } + } else if (debug & DEBUG_SIG) + printk("rcbfx %d: Channels not configured for signaling yet !!\n", + rcb_card->pos + 1); + +} + +static unsigned short int rcb_card_dsp_ping(struct rcb_card_t *rcb_card); + +DAHDI_IRQ_HANDLER(rcb_card_interrupt) +{ + struct rcb_card_t *rcb_card = dev_id; + int status, upd_state, regnum; + __u8 ints, regval; + + /* read flancter */ + status = *(volatile __u16 *) (rcb_card->memaddr + RCB_RXSIGSTAT); + + if (status) { + if (debug & DEBUG_SIG) + printk("RXCHANGE flags = %x\n", status); + /* reset flancter */ + *(volatile __u16 *) (rcb_card->memaddr + RCB_RXSIGSTAT) = status; + if (debug & DEBUG_SIG) + printk("RXCHANGE flags = %x\n", + *(volatile __u16 *) (rcb_card->memaddr + RCB_RXSIGSTAT)); + + rcb_card_check_sigbits(rcb_card, status); + } + + else if (*(volatile __u8 *) (rcb_card->memaddr + RCB_INTSTAT) & 0x02) { + /* int acknowledge */ + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) |= INT_ACK; + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) &= ~INT_ACK; + + /* read DMA address pointer MSB */ + ints = *(volatile __u8 *) (rcb_card->memaddr + RCB_INTSTAT) & 0x01; + + if ((rcb_card->intcount < 10) && (debug)) + printk("rcbfx %d: INT count %d PTR %x\n", rcb_card->pos + 1, + rcb_card->intcount, + *(volatile __u32 *) (rcb_card->memaddr + RCB_TDM_PTR)); + + rcb_card->intcount++; + rcb_card_receive(rcb_card, ints); + rcb_card_transmit(rcb_card, ints); + + + if ((rcb_card->intcount & RCB_LVSSAMP) == 0) { + for (regnum = 0; regnum < 24; regnum++) { + regval = *(volatile __u8 *) (rcb_card->memaddr + RCB_LVSTAB + regnum); + if (regval & 0x80) { /* negative */ + regval &= 0x7f; + lvs[regnum] = -(0x80 - regval); + } else + lvs[regnum] = regval; + } + } + + if (reg_addr != rcb_card->oldreg_addr) { + if (debug) + printk("New reg_addr = %x\n", reg_addr); + rcb_card->oldreg_addr = reg_addr; + *(volatile __u8 *) (rcb_card->memaddr + RCB_REGADDR) = reg_addr; + rcb_card->read_on_int = rcb_card->intcount + RCB_REGTIME; + } + + if (rcb_card->intcount == rcb_card->read_on_int) { + if (debug) + printk("updating valuesfor reg %x\n", reg_addr); + for (regnum = 0; regnum < 24; regnum++) { + reg_val[regnum] = + *(volatile __u8 *) (rcb_card->memaddr + RCB_REGTAB + regnum); + } + } + + } + + else + return IRQ_NONE; + + upd_state = (*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & 0x08000); + if ((!upd_state) && (rcb_card->param_upd_state)) { + printk("parameters accepted and set\n"); + rcb_card->param_upd_state = 0; + } + if ((upd_state) && (!rcb_card->param_upd_state)) { + printk("parameters loaded to card\n"); + rcb_card->param_upd_state = 1; + } + + return IRQ_RETVAL(1); +} + +static int rcb_dahdi_chan_ioctl(struct dahdi_chan *chan, unsigned int cmd, + unsigned long data) +{ + int regnum; + struct rcb_card_params_t rcb_card_params; + struct dahdi_span *span = chan->span; + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + int num_chans = rcb_card->num_chans; + struct rcb_chan_echo_coefs coefs; + + switch (cmd) { + case DAHDI_ONHOOKTRANSFER: + return -EINVAL; + break; + case DAHDI_SETPOLARITY: + return -EINVAL; + break; + case RCB_CHAN_SET_CBPARAMS: + if (debug) + printk("rcbfx %d: Setting cbfx parameters: \n", rcb_card->pos + 1); + if (*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & 0x09000) { + printk("rcbfx %d: Board not ready for params -- not setting\n", + rcb_card->pos + 1); + return -EFAULT; + break; + } + if (copy_from_user + (&rcb_card_params, (struct rcb_card_params_t *) data, + sizeof(rcb_card_params))) + return -EFAULT; + + printk("rcbfx %d: Recieved cbfx parameters: \n", rcb_card->pos + 1); + + for (regnum = 0; regnum < P_TBL_CNT; regnum++) { + if (debug) + printk("rcbfx %d: IO Address: %x, Regnum: %x, Data: %x \n", + rcb_card->pos + 1, PARAM_TBL + regnum, regnum, + (__u8) (rcb_card_params.settings[regnum])); + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + regnum) = + (__u8) (rcb_card_params.settings[regnum]); + } + /* notify of parameter update */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) = 0x08000; + break; + case RCB_CHAN_GET_BDINFO: + if (debug) + printk("rcbfx %d: ioctl RCB_CHAN_GET_BDINFO sending %d\n", rcb_card->pos + 1, + num_chans); + if (copy_to_user((int *) data, &num_chans, sizeof(num_chans))) + return -EFAULT; + break; + + case RCB_CHAN_SET_ECHOTUNE: + if (debug) { + printk("rcbfx %d: ioctl RCB_CHAN_SET_ECHOTUNE sending\n", rcb_card->pos + 1); + printk("chan %x, ac %x, 1 %x, 2 %x, 3 %x, 4 %x, 5 %x, 6 %x, 7 %x, 8 %x,\n", + chan->chanpos, coefs.acim, coefs.coef1, coefs.coef2, coefs.coef3, + coefs.coef4, coefs.coef5, coefs.coef6, coefs.coef7, coefs.coef8); + } + if (*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & 0x05000) { + printk("rcbfx %d: Board not ready for params -- not setting %x\n", + rcb_card->pos + 1, + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT)); + return -EFAULT; + break; + } + + if (copy_from_user(&coefs, (struct rcb_chan_echo_coefs *) data, sizeof(coefs))) + return -EFAULT; + + if (rcb_card->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG) = + chan->chanpos; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 1) = + coefs.acim; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 2) = + coefs.coef1; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 3) = + coefs.coef2; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 4) = + coefs.coef3; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 5) = + coefs.coef4; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 6) = + coefs.coef5; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 7) = + coefs.coef6; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 8) = + coefs.coef7; + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + RCB_CHAN_REG + 9) = + coefs.coef8; + } else { + return -EINVAL; + } + + /* notify of parameter update */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) = 0x04000; + msleep(100); + break; + + default: + return -ENOTTY; + break; + } + return 0; +} + +static int rcb_card_update_fw(struct rcb_card_t *rcb_card, + const struct firmware *firmware) +{ + long end_jiffies; + unsigned int block_count = 0; + unsigned int total_blocks, frac_block, char_count, zeros = 0; + unsigned char block_sum; + + total_blocks = (firmware->size - 2) >> 8; /* 256 char blocks */ + frac_block = (firmware->size - 2) & 0xff; + + printk("rcbfx %d: New Firmware is %xh bytes - loading into 800h to %xh\n", + rcb_card->pos + 1, (unsigned int) (firmware->size - 2), + (unsigned int) (firmware->size - 2) + 0x800); + printk("Firmware Size is %d blocks plus %d more bytes\n", total_blocks, frac_block); + if ((firmware->size - 2) > 0x7600) { + printk("rcbfx %d: Firmware file to large %x GT %x\n", rcb_card->pos + 1, + (unsigned int) (firmware->size - 2), 0x7600); + return -2; + } + if ((firmware->size - 2) < 0x5000) { + printk("rcbfx %d: Firmware file too small %x\n", rcb_card->pos + 1, + (unsigned int) (firmware->size - 2)); + return -2; + } + for (char_count = 2; char_count < firmware->size; char_count++) { + if (firmware->data[char_count] == 0) + zeros++; + else + break; + } + if (zeros > 20) { + printk("rcbfx %d: %d too many leading zeros\n", rcb_card->pos + 1, zeros); + return -2; + } + /* reset and set boot code to bootloader */ + *(volatile __u8 *) (rcb_card->memaddr + FW_BOOT) = FW_BOOT_LOAD | FW_BOOT_RST; + end_jiffies = jiffies + 50; + while (end_jiffies > jiffies); + *(volatile __u8 *) (rcb_card->memaddr + FW_BOOT) = FW_BOOT_LOAD; /* release reset */ + end_jiffies = jiffies + 50; + while (end_jiffies > jiffies); /* wait for reset */ + if (debug) + printk("rcbfx %d: Starting to send firmware\n", rcb_card->pos + 1); + for (block_count = 1; block_count <= total_blocks; block_count++) { + schedule(); + /* send block */ + block_sum = 0; + for (char_count = 0; char_count < 0x100; char_count++) { + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + char_count) = + firmware->data[char_count + 2 + ((block_count - 1) << 8)]; + block_sum = + (unsigned char) (block_sum + firmware->data[char_count + 2 + + ((block_count - 1) << 8)]); + } + /* update block counter */ + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = block_count; + *(volatile __u8 *) (rcb_card->memaddr + FW_SUM) = block_sum; + + end_jiffies = jiffies + 2000; + /* wait for block to take */ + while ((*(volatile __u8 *) (rcb_card->memaddr + FW_COMIN) != block_count) && + (end_jiffies > jiffies)); + if (*(volatile __u8 *) (rcb_card->memaddr + FW_COMIN) != block_count) { + printk("rcbfx %d: Time out!!!! %d blocks transfered %d blocks taken\n", + rcb_card->pos + 1, block_count, + *(volatile __u8 *) (rcb_card->memaddr + FW_COMIN)); + return -1; + } + if (debug) + printk("rcbfx %d: Acked block %x of %x ", rcb_card->pos + 1, block_count, + total_blocks); + } + /* clear block for checksum purposes */ + for (char_count = 0; char_count < 0x100; char_count++) + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + char_count) = 0; + /* send the partial block */ + block_sum = 0; + for (char_count = 0; char_count < frac_block; char_count++) { + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + char_count) = + firmware->data[char_count + 2 + ((block_count - 1) << 8)]; + block_sum = (unsigned char) (block_sum + firmware->data[char_count + 2 + + ((block_count - + 1) << 8)]); + } + /* update block counter */ + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = block_count; + *(volatile __u8 *) (rcb_card->memaddr + FW_SUM) = block_sum; + if (debug) + printk("rcbfx %d: Sent partial block %x\n", rcb_card->pos + 1, block_count); + + end_jiffies = jiffies + 2000; + /* wait for block to take */ + while ((*(volatile __u8 *) (rcb_card->memaddr + FW_COMIN) != block_count) && + (end_jiffies > jiffies)); + if (*(volatile __u8 *) (rcb_card->memaddr + FW_COMIN) != block_count) { + printk("rcbfx %d: Time out!!!! %d blocks transfered %d blocks taken\n", + rcb_card->pos + 1, block_count, + *(volatile __u8 *) (rcb_card->memaddr + FW_COMIN)); + return -1; + } + if (debug) + printk("rcbfx %d: Acked partial block %x\n", rcb_card->pos + 1, block_count); + /* say done */ + *(volatile __u8 *) (rcb_card->memaddr + FW_BOOT) = 0; + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = 0xff; + /* wait for it */ + end_jiffies = jiffies + 100; + while ((*(volatile __u8 *) (rcb_card->memaddr + FW_COMIN) != 0xff) || + (end_jiffies > jiffies)); + + if (*(volatile __u8 *) (rcb_card->memaddr + FW_COMIN) != 0xff) { + printk("rcbfx %d: All blocks transfered no ACK\n", rcb_card->pos + 1); + return -1; + } else + printk("rcbfx %d: All blocks transfered and acked\n", rcb_card->pos + 1); + + *(volatile __u8 *) (rcb_card->memaddr + FW_DATA) = 0x00; + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = 0x00; + + return 0; +} + +static int rcb_dahdi_chan_open(struct dahdi_chan *chan) +{ + struct dahdi_span *span = chan->span; + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + if (rcb_card->num_chans < (chan->chanpos - 1)) /* make sure the chan exists */ + return -ENODEV; + if (rcb_card->dead) + return -ENODEV; + rcb_card->usecount++; + if (debug) + printk("rcbfx %d: Use Count %x\n", rcb_card->pos + 1, rcb_card->usecount); + try_module_get(THIS_MODULE); + return 0; +} + +static void rcb_card_restart_dma(struct rcb_card_t *rcb_card) +{ + if (debug) + printk("rcbfx %d: Restarting DMA\n", rcb_card->pos + 1); + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) &= ~BIT_DMAGO; + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) |= BIT_DMAGO; + return; +} + +static int rcb_dahdi_span_watchdog(struct dahdi_span *span, int event) +{ + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + rcb_card_restart_dma(rcb_card); + return 0; +} + +static void rcb_card_release(struct rcb_card_t *rcb_card) +{ + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT) &= ~0x00; + if (debug) + printk("rcbfx %d: Statout = %x\n", rcb_card->pos + 1, + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT)); + dahdi_unregister(&rcb_card->span); + if (rcb_card->freeregion) + release_region(rcb_card->baseaddr, rcb_card->memlen); + printk("rcbfx %d: Released a Rhino\n", rcb_card->pos + 1); + kfree(rcb_card); +} + +static int rcb_dahdi_chan_close(struct dahdi_chan *chan) +{ + struct dahdi_span *span = chan->span; + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + rcb_card->usecount--; + if (debug) + printk("rcbfx %d: Use Count %d\n", rcb_card->pos + 1, rcb_card->usecount); + module_put(THIS_MODULE); + /* If we're dead, release us now */ + if (!rcb_card->usecount && rcb_card->dead) + rcb_card_release(rcb_card); + return 0; +} + +static int rcb_card_initialize(struct rcb_card_t *rcb_card) +{ +static struct dahdi_span_ops ops = { + .rbsbits = rcb_dahdi_chan_rbsbits, + .open = rcb_dahdi_chan_open, + .close = rcb_dahdi_chan_close, + .ioctl = rcb_dahdi_chan_ioctl, + .watchdog = rcb_dahdi_span_watchdog, + .echocan_create = rcbfx_echocan_create, + .owner = THIS_MODULE, + }; + + int chan_num; + /* dahdi stuff */ + + sprintf(rcb_card->span.name, "%s/%d", rcb_card->variety, rcb_card->pos + 1); + sprintf(rcb_card->span.desc, "%s/%d", rcb_card->variety, rcb_card->pos + 1); + rcb_card->span.deflaw = DAHDI_LAW_MULAW; + + for (chan_num = 0; chan_num < rcb_card->num_chans; chan_num++) { + + rcb_card->chans[chan_num]->writechunk = + (u_char *) (rcb_card->writechunk + (chan_num * DAHDI_CHUNKSIZE)); + rcb_card->chans[chan_num]->readchunk = + (u_char *) (rcb_card->readchunk + (chan_num * DAHDI_CHUNKSIZE)); + if (show_pointers) + printk("rcbfx %d: Chan %d writechunk %lx readchunk %lx\n", + rcb_card->pos + 1, chan_num, + (long unsigned int) rcb_card->chans[chan_num]->writechunk, + (long unsigned int) rcb_card->chans[chan_num]->readchunk); + + if (rcb_card->chanflag & (1 << chan_num)) { + if (rcb_card->modtype[chan_num] == MOD_TYPE_FXO) { + sprintf(rcb_card->chans[chan_num]->name, "FXO/%d/%d", + rcb_card->pos + 1, chan_num); + rcb_card->chans[chan_num]->sigcap = + DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF | DAHDI_SIG_CLEAR; + } else { + sprintf(rcb_card->chans[chan_num]->name, "FXS/%d/%d", + rcb_card->pos + 1, chan_num); + rcb_card->chans[chan_num]->sigcap = + DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | + DAHDI_SIG_EM | DAHDI_SIG_CLEAR; + } + } else { + sprintf(rcb_card->chans[chan_num]->name, "---/%d/%d", + rcb_card->pos + 1, chan_num); + rcb_card->chans[chan_num]->sigcap = + DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | + DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS; + } + + rcb_card->chans[chan_num]->chanpos = chan_num + 1; + rcb_card->chans[chan_num]->pvt = rcb_card; + } + + rcb_card->span.manufacturer = "Rhino Equipment Corp."; + rcb_card->span.channels = rcb_card->num_chans; + rcb_card->span.chans = rcb_card->chans; + rcb_card->span.flags = DAHDI_FLAG_RBS; + init_waitqueue_head(&rcb_card->span.maintq); + + rcb_card->span.ops = &ops; + + if (dahdi_register(&rcb_card->span, 0)) { + printk("rcbfx %d: Unable to register span with Parent\n", rcb_card->pos + 1); + return -1; + } + + rcb_card->chans_configed = 1; + return 0; +} + +static int rcb_card_hardware_init(struct rcb_card_t *rcb_card) +{ + /* Hardware stuff */ + __u16 bd_pres; + __u32 is_fxo; + long end_jiffies; + int chan_num, time_out, res, tries = 0; + int fwv_register, fwv_file; + int done = 0; + static const struct firmware *firmware_rcb; + + /* reset DSP */ + *(volatile __u8 *) (rcb_card->memaddr + FW_BOOT) = DSP_RST; + end_jiffies = jiffies + 30000; + time_out = 0; + + /* ping!! */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) = 0x02000; + /* check sign of life and move on */ + if (*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & 0x02000) { + printk("rcbfx %d: Waiting for response from card ......... \n", + rcb_card->pos + 1); + while ((*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & 0x02000) && + (time_out == 0)) { + if (jiffies > end_jiffies) + time_out = 1; + } + } + + /* release DSP reset */ + *(volatile __u8 *) (rcb_card->memaddr + FW_BOOT) = 0x00; + + fwv_register = *(volatile __u16 *) (rcb_card->memaddr + FW_VER); + printk("rcbfx %d: Firmware Version %x.%x\n", rcb_card->pos + 1, + (fwv_register & 0xff00) >> 8, (fwv_register & 0xff)); + + if ((request_firmware(&firmware_rcb, rcbfx_firmware, &rcb_card->dev->dev) != 0) || + !firmware_rcb) { + printk("rcbfx %d: firmware %s not available from userspace\n", rcb_card->pos + 1, + rcbfx_firmware); + } else { + fwv_file = ((firmware_rcb->data[0] << 8) | (firmware_rcb->data[1])); + printk("rcbfx %d: Firmware File Version is %x.%x\n", rcb_card->pos + 1, + (fwv_file & 0xff00) >> 8, fwv_file & 0xff); + if ((fwv_file > fwv_register) || (force_fw)) { + if (force_fw) + printk("rcbfx %d: Firmware Upgrade beeing forced\n", rcb_card->pos + 1); + printk(KERN_ALERT + "rcbfx %d: Firmware Uprgrade In Progress -- Do Not Interrupt!!\n", + rcb_card->pos + 1); + while (!done) { + res = rcb_card_update_fw(rcb_card, firmware_rcb); + tries++; + if ((res == 0) || (res == -2)) + done = 1; + else if ((res == -1) && (tries > 3)) + done = 1; + } + } + + release_firmware(firmware_rcb); + *(volatile __u8 *) (rcb_card->memaddr + FW_DATA) = 0x00; + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = 0x00; + } + + *(volatile __u8 *) (rcb_card->memaddr + RCB_BATTTIME) = battime; + + printk("rcbfx %d: Hardware version %d\n", rcb_card->pos + 1, + *(volatile __u16 *) (rcb_card->memaddr + RCB_VERSION)); + if (*(volatile __u16 *) (rcb_card->memaddr + RCB_VERSION) < rcb_card->hw_ver_min) { + if (debug) + printk("rcbfx %d: YOU ARE NOT USING THE LATEST HARDWARE VERSION\n", + rcb_card->pos + 1); + } + if (done) { /* updated */ + end_jiffies = jiffies + 30000; + time_out = 0; + /* ping!! */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) = 0x02000; + + /* check sign of life and move on */ + if (*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & 0x02000) { + printk("Waiting for response from card ......... \n"); + while ((*(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) & + (__u32) (0x02000)) && (time_out == 0)) { + schedule(); + if (jiffies > end_jiffies) + time_out = 1; + } + } + } + + if ((time_out == 0) && (debug)) + printk("rcbfx %d: Got response from card\n", rcb_card->pos + 1); + if (time_out == 1) { + printk("rcbfx %d: Not responding !!!!\n", rcb_card->pos + 1); + } + + bd_pres = *(volatile __u16 *) (rcb_card->memaddr + RCB_CHANPRES); + is_fxo = *(volatile __u32 *) (rcb_card->memaddr + RCB_CHANTYPE); + if (debug) { + printk("rcbfx %d: Channels Present: %x, Channel Type: %x\n", rcb_card->pos + 1, + bd_pres, is_fxo); + printk("rcbfx %d: num_chans: %d\n", rcb_card->pos + 1, rcb_card->num_chans); + } + + rcb_card->fxs_chanmap = 0; + rcb_card->fxo_chanmap = 0; + + for (chan_num = 0; chan_num < rcb_card->num_chans; chan_num++) { + if ((1 << (chan_num >> 1)) & bd_pres) { + rcb_card->chanflag |= (1 << chan_num); + + if ((1 << chan_num) & is_fxo) { + rcb_card->modtype[chan_num] = MOD_TYPE_FXO; + rcb_card->fxo_chanmap |= (1 << chan_num); + } else { + rcb_card->modtype[chan_num] = MOD_TYPE_FXS; + rcb_card->fxs_chanmap |= (1 << chan_num); + } + } + } + +#ifdef USE_G168_DSP + /* Set the global variables here */ + if ((ec_fxo_alg > 0) || (ec_fxo_alg == 0)) /* forced value */ + fxo_alg_chanmap = ec_fxo_alg; + else + fxo_alg_chanmap = rcb_card->fxo_chanmap; /* On in B diraction */ + + if ((ec_fxs_alg > 0) || (ec_fxs_alg == 0)) /* forced value */ + fxs_alg_chanmap = ec_fxs_alg; + else + fxs_alg_chanmap = rcb_card->fxs_chanmap; /* On in A diraction */ + + if ((use_ec_fxo > 0) || (use_ec_fxo == 0)) /* forced value */ + use_fxo_chanmap = use_ec_fxo; + else + use_fxo_chanmap = rcb_card->fxo_chanmap; /* Off for fxs */ + + if ((use_ec_fxs > 0) || (use_ec_fxs == 0)) /* forced value */ + use_fxs_chanmap = use_ec_fxs; + else + use_fxs_chanmap = rcb_card->fxs_chanmap; /* off for fxo */ +#endif + + /* Setup DMA Addresses */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXBUFSTART) = (__u32) rcb_card->writedma; + *(volatile __u32 *) (rcb_card->memaddr + RCB_RXBUFSTART) = (__u32) rcb_card->readdma; + *(volatile __u16 *) (rcb_card->memaddr + RCB_BUFLEN) = + ((__u16) (DAHDI_CHUNKSIZE * rcb_card->num_chans * 2) >> 2); + + return 0; +} + +static void rcb_card_start_dma(struct rcb_card_t *rcb_card) +{ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) |= BIT_DMAGO; +} + + +static void rcb_card_stop_dma(struct rcb_card_t *rcb_card) +{ + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) &= ~BIT_DMAGO; + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT) &= ~0x00; + if (debug) + printk("rcbfx %d: Statout = %x\n", rcb_card->pos + 1, + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT)); + *(volatile __u8 *) (rcb_card->memaddr + FW_DATA) = 0x00; + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = 0x00; +} + +static void rcb_card_cleaner(struct rcb_card_t *rcb_card, int flags) +{ + if (rcb_card) { + + if (flags & STOP_DMA) { + *(volatile __u8 *) (rcb_card->memaddr + RCB_CONTROL) &= ~BIT_DMAGO; + } + if (flags & FREE_DMA) { + if (rcb_card->writechunk) { + pci_free_consistent(rcb_card->dev, + DAHDI_MAX_CHUNKSIZE * rcb_card->num_chans * 2 * 2, + (void *) rcb_card->writechunk, rcb_card->writedma); + rcb_card->writechunk = NULL; + } + } + if (flags & IOUNMAP) { + if (rcb_card->freeregion) { + rcb_card->freeregion = -1; + release_region(rcb_card->baseaddr, rcb_card->memlen); + } + iounmap(rcb_card->memaddr); + } + if (flags & ZUNREG) { + if (!rcb_card->usecount) + dahdi_unregister(&rcb_card->span); + else + rcb_card->dead = 1; + } + if (flags & FREE_INT) + free_irq(rcb_card->dev->irq, rcb_card); + if (flags & RH_KFREE) + kfree(rcb_card); + if (flags & PCI_FREE) + pci_set_drvdata(rcb_card->dev, NULL); + } +} + +#ifdef USE_G168_DSP + +static GpakPortConfig_t Gpak_24_chan_port_config = { + + /* GpakSlotCfg_t SlotsSelect1 port 1 Slot selection */ + SlotCfg2Groups, + /* unsigned short int FirstBlockNum1 port 1 first group Block Number */ + 0x0000, + /* unsigned short int FirstSlotMask1 port 1 first group Slot Mask */ + 0xffff, + /* unsigned short int SecBlockNum1 port 1 second group Block Number */ + 0x0001, + /* unsigned short int SecSlotMask1 port 1 second group Slot Mask */ + 0x00ff, + /* GpakSerWordSize_t SerialWordSize1 port 1 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode1 port 1 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity1 port 1 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity1 port 1 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity1 port 1 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity1 port 1 Rx Clock Polarity */ + SerClockActLow, + /* GpakSerDataDelay_t TxDataDelay1 port 1 Tx data delay */ + DataDelay0, + /* GpakSerDataDelay_t RxDataDelay1 port 1 Rx data delay */ + DataDelay0, + /* GpakActivation DxDelay1 port 1 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask1 port 1 3rd group Slot Mask */ + 0x0000, + /* unsigned short int FouthSlotMask1 port 1 4th group Slot Mask */ + 0x0000, + /* unsigned short int FifthSlotMask1 port 1 5th group Slot Mask */ + 0x0000, + /* unsigned short int SixthSlotMask1 port 1 6th group Slot Mask */ + 0x0000, + /* unsigned short int SevenSlotMask1 port 1 7th group Slot Mask */ + 0x0000, + /* unsigned short int EightSlotMask1 port 1 8th group Slot Mask */ + 0x0000, + /* GpakSlotCfg_t SlotsSelect2 port 2 Slot selection */ + SlotCfg2Groups, + /* unsigned short int FirstBlockNum2 port 2 first group Block Number */ + 0x0000, + /* unsigned short int FirstSlotMask2 port 2 first group Slot Mask */ + 0xffff, + /* unsigned short int SecBlockNum2 port 2 second group Block Number */ + 0x0001, + /* unsigned short int SecSlotMask2 port 2 second group Slot Mask */ + 0x00ff, + /* GpakSerWordSize_t SerialWordSize2 port 2 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode2 port 2 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity2 port 2 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity2 port 2 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity2 port 2 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity2 port 2 Rx Clock Polarity */ + SerClockActLow, + /* GpakSerDataDelay_t TxDataDelay2 port 2 Tx data delay */ + DataDelay0, + /* GpakSerDataDelay_t RxDataDelay2 port 2 Rx data delay */ + DataDelay0, + /* GpakActivation DxDelay2 port 2 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask2 port 2 3rd group Slot Mask */ + 0x0000, + /* unsigned short int FouthSlotMask2 port 2 4th group Slot Mask */ + 0x0000, + /* unsigned short int FifthSlotMask2 port 2 5th group Slot Mask */ + 0x0000, + /* unsigned short int SixthSlotMask2 port 2 6th group Slot Mask */ + 0x0000, + /* unsigned short int SevenSlotMask2 port 2 7th group Slot Mask */ + 0x0000, + /* unsigned short int EightSlotMask2 port 2 8th group Slot Mask */ + 0x0000, + /* GpakSlotCfg_t SlotsSelect3 port 3 Slot selection */ + SlotCfgNone, + /* unsigned short int FirstBlockNum3 port 3 first group Block Number */ + 0x0000, + /* unsigned short int FirstSlotMask3 port 3 first group Slot Mask */ + 0x0000, + /* unsigned short int SecBlockNum3 port 3 second group Block Number */ + 0x0000, + /* unsigned short int SecSlotMask3 port 3 second group Slot Mask */ + 0x0000, + /* GpakSerWordSize_t SerialWordSize3 port 3 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode3 port 3 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity3 port 3 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity3 port 3 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity3 port 3 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity3 port 3 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay3 port 3 Tx data delay */ + DataDelay0, + /* GpakSerDataDelay_t RxDataDelay3 port 3 Rx data delay */ + DataDelay0, + /* GpakActivation DxDelay3 port 3 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask3 port 3 3rd group Slot Mask */ + 0x0000, + /* unsigned short int FouthSlotMask3 port 3 4th group Slot Mask */ + 0x0000, + /* unsigned short int FifthSlotMask3 port 3 5th group Slot Mask */ + 0x0000, + /* unsigned short int SixthSlotMask3 port 3 6th group Slot Mask */ + 0x0000, + /* unsigned short int SevenSlotMask3 port 3 7th group Slot Mask */ + 0x0000, + /* unsigned short int EightSlotMask3 port 3 8th group Slot Mask */ + 0x0000, +}; + +static GpakChannelConfig_t Gpak_chan_config = { + + /* GpakSerialPort_t PCM Input Serial Port A Id */ + SerialPort1, + /* unsigned short int PCM Input Time Slot */ + 0, + /* GpakSerialPort_t PCM Output Serial Port A Id */ + SerialPortNull, + /* unsigned short int PCM Output Time Slot */ + 0, + /* GpakSerialPort_t PCM Input Serial Port B Id */ + SerialPort2, + /* unsigned short int PCM Input Time Slot */ + 0, + /* GpakSerialPort_t PCM Output Serial Port B Id */ + SerialPort1, + /* unsigned short int PCM Output Time Slot */ + 0, + /* GpakToneTypes ToneTypesA A side Tone Detect Types */ + Null_tone, + /* GpakToneTypes ToneTypesB B side Tone Detect Types */ + Null_tone, + /* GpakActivation Echo Cancel A Enabled */ + Disabled, + /* GpakActivation Echo Cancel B Enabled */ + Disabled, + + { + /* short int Echo Can Num Taps (tail length) 64 = 512 32 = 256 */ + 1024, + /* short int Echo Can NLP Type */ + 3, + /* short int Echo Can Adapt Enable flag */ + 1, + /* short int Echo Can G165 Detect Enable flag */ + 1, + /* short int Echo Can Double Talk threshold */ + 4, + /* short int Echo Can NLP threshold */ + 21, + /* short int Dynamic NLP control, NLP limit when EC about to converged */ + 18, + /* short int Dynamic NLP control, NLP limit when EC not converged yet */ + 12, + /* short int suppression level for NLP_SUPP mode */ + 0, + /* short int Echo Can CNG Noise threshold */ + 50, + /* short int Echo Can Max Adapts per frame */ + 50, + /* short int Echo Can Cross Correlation limit */ + 20, + /* short int Echo Can Num FIR Segments */ + 3, + /* short int Echo Can FIR Segment Length */ + 64, + }, + + { + /* short int Echo Can Num Taps (tail length) */ + 1024, + /* short int Echo Can NLP Type */ + 3, + /* short int Echo Can Adapt Enable flag */ + 1, + /* short int Echo Can G165 Detect Enable flag */ + 1, + /* short int Echo Can Double Talk threshold */ + 4, + /* short int Echo Can NLP threshold */ + 21, + /* short int Dynamic NLP control, NLP limit when EC about to converged */ + 18, + /* short int Dynamic NLP control, NLP limit when EC not converged yet */ + 12, + /* short int suppression level for NLP_SUPP mode */ + 0, + /* short int Echo Can CNG Noise threshold */ + 50, + /* short int Echo Can Max Adapts per frame */ + 50, + /* short int Echo Can Cross Correlation limit */ + 20, + /* short int Echo Can Num FIR Segments */ + 3, + /* short int Echo Can FIR Segment Length */ + 64, + }, + + /* GpakCompandModes software companding */ + cmpNone, + /* GpakRate_t Gpak Frame Rate */ + rate2ms, + +}; + +static void rcb_card_dsp_show_portconfig(GpakPortConfig_t PortConfig) +{ + if (debug & DEBUG_DSP) { + printk("%x = %s\n", PortConfig.SlotsSelect1, "SlotsSelect1"); + printk("%x = %s\n", PortConfig.FirstBlockNum1, "FirstBlockNum1"); + printk("%x = %s\n", PortConfig.FirstSlotMask1, "FirstSlotMask1"); + printk("%x = %s\n", PortConfig.SecBlockNum1, "SecBlockNum1"); + printk("%x = %s\n", PortConfig.SecSlotMask1, "SecSlotMask1"); + printk("%x = %s\n", PortConfig.SerialWordSize1, "SerialWordSize1"); + printk("%x = %s\n", PortConfig.CompandingMode1, "CompandingMode1"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity1, "TxFrameSyncPolarity1"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity1, "RxFrameSyncPolarity1"); + printk("%x = %s\n", PortConfig.TxClockPolarity1, "TxClockPolarity1"); + printk("%x = %s\n", PortConfig.RxClockPolarity1, "RxClockPolarity1"); + printk("%x = %s\n", PortConfig.TxDataDelay1, "TxDataDelay1"); + printk("%x = %s\n", PortConfig.RxDataDelay1, "RxDataDelay1"); + printk("%x = %s\n", PortConfig.DxDelay1, "DxDelay1"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask1, "ThirdSlotMask1"); + printk("%x = %s\n", PortConfig.FouthSlotMask1, "FouthSlotMask1"); + printk("%x = %s\n", PortConfig.FifthSlotMask1, "FifthSlotMask1"); + printk("%x = %s\n", PortConfig.SixthSlotMask1, "SixthSlotMask1"); + printk("%x = %s\n", PortConfig.SevenSlotMask1, "SevenSlotMask1"); + printk("%x = %s\n", PortConfig.EightSlotMask1, "EightSlotMask1"); + + printk("%x = %s\n", PortConfig.SlotsSelect2, "SlotsSelect2"); + printk("%x = %s\n", PortConfig.FirstBlockNum2, "FirstBlockNum2"); + printk("%x = %s\n", PortConfig.FirstSlotMask2, "FirstSlotMask2"); + printk("%x = %s\n", PortConfig.SecBlockNum2, "SecBlockNum2"); + printk("%x = %s\n", PortConfig.SecSlotMask2, "SecSlotMask2"); + printk("%x = %s\n", PortConfig.SerialWordSize2, "SerialWordSize2"); + printk("%x = %s\n", PortConfig.CompandingMode2, "CompandingMode2"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity2, "TxFrameSyncPolarity2"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity2, "RxFrameSyncPolarity2"); + printk("%x = %s\n", PortConfig.TxClockPolarity2, "TxClockPolarity2"); + printk("%x = %s\n", PortConfig.RxClockPolarity2, "RxClockPolarity2"); + printk("%x = %s\n", PortConfig.TxDataDelay2, "TxDataDelay2"); + printk("%x = %s\n", PortConfig.RxDataDelay2, "RxDataDelay2"); + printk("%x = %s\n", PortConfig.DxDelay2, "DxDelay2"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask2, "ThirdSlotMask2"); + printk("%x = %s\n", PortConfig.FouthSlotMask2, "FouthSlotMask2"); + printk("%x = %s\n", PortConfig.FifthSlotMask2, "FifthSlotMask2"); + printk("%x = %s\n", PortConfig.SixthSlotMask2, "SixthSlotMask2"); + printk("%x = %s\n", PortConfig.SevenSlotMask2, "SevenSlotMask2"); + printk("%x = %s\n", PortConfig.EightSlotMask2, "EightSlotMask2"); + + printk("%x = %s\n", PortConfig.SlotsSelect3, "SlotsSelect3"); + printk("%x = %s\n", PortConfig.FirstBlockNum3, "FirstBlockNum3"); + printk("%x = %s\n", PortConfig.FirstSlotMask3, "FirstSlotMask3"); + printk("%x = %s\n", PortConfig.SecBlockNum3, "SecBlockNum3"); + printk("%x = %s\n", PortConfig.SecSlotMask3, "SecSlotMask3"); + printk("%x = %s\n", PortConfig.SerialWordSize3, "SerialWordSize3"); + printk("%x = %s\n", PortConfig.CompandingMode3, "CompandingMode3"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity3, "TxFrameSyncPolarity3"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity3, "RxFrameSyncPolarity3"); + printk("%x = %s\n", PortConfig.TxClockPolarity3, "TxClockPolarity3"); + printk("%x = %s\n", PortConfig.RxClockPolarity3, "RxClockPolarity3"); + printk("%x = %s\n", PortConfig.TxDataDelay3, "TxDataDelay3"); + printk("%x = %s\n", PortConfig.RxDataDelay3, "RxDataDelay3"); + printk("%x = %s\n", PortConfig.DxDelay3, "DxDelay3"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask3, "ThirdSlotMask3"); + printk("%x = %s\n", PortConfig.FouthSlotMask3, "FouthSlotMask3"); + printk("%x = %s\n", PortConfig.FifthSlotMask3, "FifthSlotMask3"); + printk("%x = %s\n", PortConfig.SixthSlotMask3, "SixthSlotMask3"); + printk("%x = %s\n", PortConfig.SevenSlotMask3, "SevenSlotMask3"); + printk("%x = %s\n", PortConfig.EightSlotMask3, "EightSlotMask3"); + + } + return; +} + +static void rcb_card_dsp_show_chanconfig(GpakChannelConfig_t ChanConfig) +{ + if (debug & DEBUG_DSP) { + printk("%x = %s\n", ChanConfig.PcmInPortA, "PcmInPortA"); + printk("%x = %s\n", ChanConfig.PcmInSlotA, "PcmInSlotA"); + printk("%x = %s\n", ChanConfig.PcmOutPortA, "PcmOutPortA"); + printk("%x = %s\n", ChanConfig.PcmOutSlotA, "PcmOutSlotA"); + printk("%x = %s\n", ChanConfig.PcmInPortB, "PcmInPortB"); + printk("%x = %s\n", ChanConfig.PcmInSlotB, "PcmInSlotB"); + printk("%x = %s\n", ChanConfig.PcmOutPortB, "PcmOutPortB"); + printk("%x = %s\n", ChanConfig.PcmOutSlotB, "PcmOutSlotB"); + + printk("%x = %s\n", ChanConfig.ToneTypesA, "ToneTypesA"); + printk("%x = %s\n", ChanConfig.ToneTypesB, "ToneTypesB"); + + printk("%x = %s\n", ChanConfig.EcanEnableA, "EcanEnableA"); + printk("%x = %s\n", ChanConfig.EcanEnableB, "EcanEnableB"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanTapLength, + "EcanParametersA.EcanTapLength"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanNlpType, + "EcanParametersA.EcanNlpType"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanAdaptEnable, + "EcanParametersA.EcanAdaptEnable"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanG165DetEnable, + "EcanParametersA.EcanG165DetEnable"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanDblTalkThresh, + "EcanParametersA.EcanDblTalkThresh"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanNlpThreshold, + "EcanParametersA.EcanNlpThreshold"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanNlpConv, + "EcanParametersA.EcanNlpConv"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanNlpUnConv, + "EcanParametersA.EcanNlpUnConv"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanNlpMaxSuppress, + "EcanParametersA.EcanNlpMaxSuppress"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanCngThreshold, + "EcanParametersA.EcanCngThreshold"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanAdaptLimit, + "EcanParametersA.EcanAdaptLimit"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanCrossCorrLimit, + "EcanParametersA.EcanCrossCorrLimit"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanNumFirSegments, + "EcanParametersA.EcanNumFirSegments"); + printk("%x = %s\n", ChanConfig.EcanParametersA.EcanFirSegmentLen, + "EcanParametersA.EcanFirSegmentLen"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanTapLength, + "EcanParametersB.EcanTapLength"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanNlpType, + "EcanParametersB.EcanNlpType"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanAdaptEnable, + "EcanParametersB.EcanAdaptEnable"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanG165DetEnable, + "EcanParametersB.EcanG165DetEnable"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanDblTalkThresh, + "EcanParametersB.EcanDblTalkThresh"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanNlpThreshold, + "EcanParametersB.EcanNlpThreshold"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanNlpConv, + "EcanParametersB.EcanNlpConv"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanNlpUnConv, + "EcanParametersB.EcanNlpUnConv"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanNlpMaxSuppress, + "EcanParametersB.EcanNlpMaxSuppress"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanCngThreshold, + "EcanParametersB.EcanCngThreshold"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanAdaptLimit, + "EcanParametersB.EcanAdaptLimit"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanCrossCorrLimit, + "EcanParametersB.EcanCrossCorrLimit"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanNumFirSegments, + "EcanParametersB.EcanNumFirSegments"); + printk("%x = %s\n", ChanConfig.EcanParametersB.EcanFirSegmentLen, + "EcanParametersB.EcanFirSegmentLen"); + printk("%x = %s\n", ChanConfig.SoftwareCompand, "SoftwareCompand"); + printk("%x = %s\n", ChanConfig.FrameRate, "FrameRate"); + + } + return; +} + +static unsigned short int rcb_card_dsp_ping(struct rcb_card_t *rcb_card) +{ + + gpakPingDspStat_t ping_stat; + unsigned short int dsp_ver; + + ping_stat = gpakPingDsp(rcb_card, rcb_card->pos, &dsp_ver); + + if (debug & DEBUG_DSP) { + if (ping_stat == PngSuccess) + printk("rcbfx %d: G168 DSP Ping DSP Version %x\n", rcb_card->pos + 1, + dsp_ver); + else + printk("rcbfx %d: G168 DSP Ping Error %d\n", rcb_card->pos + 1, ping_stat); + } + + if (ping_stat == PngSuccess) + return dsp_ver; + else + return 0; +} + +static void rcbfx_chan_ec_enable(struct rcb_card_t *rcb_card, int chan_num) +{ + gpakAlgControlStat_t a_c_stat; + GPAK_AlgControlStat_t a_c_err; + unsigned short int DspId = rcb_card->pos; + + if (debug & DEBUG_DSP) + printk("rcbfx: %d: Echo Can enable DSP %d EC Chan %d\n", rcb_card->pos + 1, 1, + chan_num - 1); + + if ((a_c_stat = gpakAlgControl(rcb_card, DspId, chan_num, EnableEcanB, &a_c_err))) + printk("rcbfx: %d: G168 DSP Enable Alg Control failed res = %d error = %d\n", + rcb_card->pos + 1, a_c_stat, a_c_err); + + return; +} + +static void rcbfx_chan_ec_disable(struct rcb_card_t *rcb_card, int chan_num) +{ + gpakAlgControlStat_t a_c_stat; + GPAK_AlgControlStat_t a_c_err; + unsigned short int DspId = rcb_card->pos; + + if (debug & DEBUG_DSP) + printk("rcbfx: %d: Echo Can disable DSP %d EC Chan %d\n", rcb_card->pos + 1, 1, + chan_num); + + if ((a_c_stat = gpakAlgControl(rcb_card, DspId, chan_num, BypassEcanB, &a_c_err))) + printk("rcbfx: %d: G168 DSP Enable Alg Control failed res = %d error = %d\n", + rcb_card->pos + 1, a_c_stat, a_c_err); + + return; +} + +/*static int rcbfx_dahdi_chan_echocan(struct dahdi_chan *chan, int eclen)*/ +static int rcbfx_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, + struct dahdi_echocan_state **ec) +{ + struct dahdi_span *span = chan->span; + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + int chan_num; + + chan_num = chan->chanpos - 1; + + if (ecp->param_count > 0) { + printk(KERN_WARNING + "rcbfx: echo canceller does not support parameters; failing request\n"); + return -EINVAL; + } + + if (debug & DEBUG_DSP) { + printk("rcbfx: %d Echo Can control Span %d Chan %d daddy chan %d\n", + rcb_card->pos + 1, 1, chan_num, chan->channo); + printk("DSP up %x\n", rcb_card->dsp_up); + } + if (rcb_card->dsp_up == 1) { + *ec = rcb_card->ec[chan_num]; + (*ec)->ops = &my_ec_ops; + (*ec)->features = my_ec_features; + rcb_card->nextec |= (1 << chan_num); + queue_work(rcb_card->wq, &rcb_card->work); + } + return 0; +} + +static void rcbfx_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) +{ + struct dahdi_span *span = chan->span; + struct rcb_card_t *rcb_card = container_of(span, struct rcb_card_t, span); + int chan_num; + + memset(ec, 0, sizeof(*ec)); + chan_num = chan->chanpos - 1; + + if (debug & DEBUG_DSP) { + printk("rcbfx: %d Echo Can control Span %d Chan %d daddy chan %d\n", + rcb_card->pos + 1, 1, chan_num, chan->channo); + printk("DSP up %x\n", rcb_card->dsp_up); + } + + if (rcb_card->dsp_up == 1) { + rcb_card->nextec &= ~(1 << chan_num); + queue_work(rcb_card->wq, &rcb_card->work); + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void echocan_bh(void *data) +{ + struct rcb_card_t *rcb_card = data; +#else +static void echocan_bh(struct work_struct *data) +{ + struct rcb_card_t *rcb_card = container_of(data, struct rcb_card_t, work); +#endif + unsigned int todo, chan_num; + + todo = rcb_card->nextec ^ rcb_card->currec; + if (debug & DEBUG_DSP) { + printk("rcbfx %d Echo Can control bh change %x to %x\n", rcb_card->pos + 1, todo, + (rcb_card->nextec & todo)); + printk("nextec %x currec %x\n", rcb_card->nextec, rcb_card->currec); + } + + for (chan_num = 0; chan_num < rcb_card->num_chans; chan_num++) { + + if (todo & (1 << chan_num)) { + if (rcb_card->nextec & (1 << chan_num)) { + rcbfx_chan_ec_enable(rcb_card, chan_num); + rcb_card->currec |= (1 << chan_num); + schedule(); + } else { + rcb_card->currec &= ~(1 << chan_num); + schedule(); + } + } + } +} + + +static int rcb_card_dsp_init(struct rcb_card_t *rcb_card) +{ + gpakDownloadStatus_t dl_res = 0; + gpakConfigPortStatus_t cp_res; + GPAK_PortConfigStat_t cp_error; + GPAK_ChannelConfigStat_t chan_config_err; + int chan_num; + gpakConfigChanStatus_t chan_conf_stat; + int dsp_chans = 0; + int dsp_in_use = 0; + gpakReadFramingStatsStatus_t framing_status_status; + unsigned short int ec1, ec2, ec3, dmaec, slips; + + *(volatile __u32 *) (rcb_card->memaddr + RCB_EC_ENA) = 0; + *(volatile __u32 *) (rcb_card->memaddr + RCB_EC_ENB) = 0; + + if (no_ec) + return 0; + + rcb_card->hpi_fast = 0; + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIC) = 0; + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + rcb_card->hpi_xadd = 0; + + /* quit here if no dsp channels on */ + if (!(dsp_chans = rcb_card->chanflag)) { + printk("rcbfx %d: G168 DSP Disabled\n", rcb_card->pos + 1); + return 0; + } + + if (rcb_card->dsp_type == DSP_5507) { + + /* Load the loader file */ + if ((dl_res = gpakDownloadLoader(rcb_card, rcb_card->pos, loader_file))) { + printk("rcbfx %d: G168 DSP Loader Loader Failed %d\n", rcb_card->pos + 1, + dl_res); + return -1; + } + if (debug & DEBUG_DSP) + printk("rcbfx %d: G168 DSP Loader Loader Sucess\n", rcb_card->pos + 1); + + /* execute the loader */ + rcb_card_dsp_set(rcb_card, DSP_ENTRY_ADDR_LO, (0xFFFF & BL_DSP_BOOTLOADER_ENTRY)); + rcb_card_dsp_set(rcb_card, DSP_ENTRY_ADDR_HI, + (0xFF00 | (0xFF & (BL_DSP_BOOTLOADER_ENTRY >> 16)))); + + if (debug & DEBUG_DSP) { + printk("HPIA 0x0061 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x0061)); + printk("HPIA 0x0060 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x0060)); + printk("HPIA 0x3800 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x3800)); + printk("HPIA 0x3801 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x3801)); + printk("HPIA 0x3802 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x3802)); + printk("HPIA 0x3803 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x3803)); + printk("HPIA 0x3804 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x3804)); + printk("HPIA 0x3805 HPID %x\n", rcb_card_dsp_get(rcb_card, 0x3805)); + } + + } + + if (rcb_card->dsp_type == DSP_5507) { + if ((dl_res = gpakDownloadDsp_5507(rcb_card, rcb_card->pos, app_file))) { + printk("rcbfx %d: G168 DSP App Loader Failed %d\n", rcb_card->pos + 1, + dl_res); + return -1; + } + } + + if (rcb_card->dsp_type == DSP_5510) { + if ((dl_res = gpakDownloadDsp_5510(rcb_card, rcb_card->pos, app_file))) { + printk("rcbfx %d: G168 DSP App Loader Failed %d\n", rcb_card->pos + 1, + dl_res); + return -1; + } + } + + if (debug & DEBUG_DSP) + printk("rcbfx %d: G168 DSP App Loader Sucess %d\n", rcb_card->pos + 1, dl_res); + + if (rcb_card->dsp_type == DSP_5510) { + *(volatile __u32 *) (rcb_card->memaddr + RCB_HPIC) = RCB_BL_GO; + rcb_card_wait_hpi(rcb_card, RCB_HRDY); + } + + { + long end_jiffies; + end_jiffies = jiffies + 10; + while (end_jiffies > jiffies); + } + + rcb_card_dsp_ping(rcb_card); + rcb_card_dsp_ping(rcb_card); + rcb_card_dsp_ping(rcb_card); + printk("rcbfx %d: G168 DSP Ping DSP Version %x\n", rcb_card->pos + 1, + rcb_card_dsp_ping(rcb_card)); + + if (debug & DEBUG_DSP) { + framing_status_status = + gpakReadFramingStats(rcb_card, rcb_card->pos, &ec1, &ec2, &ec3, &dmaec, + &slips); + if (framing_status_status == RfsSuccess) { + printk("rcbfx %d: G168 DSP Framing Status Sucess %d\n", rcb_card->pos + 1, + framing_status_status); + printk("rcbfx %d: G168 DSP Framing Status %d %d %d %d %d\n", + rcb_card->pos + 1, ec1, ec2, ec3, dmaec, slips); + } else { + printk("rcbfx %d: G168 DSP Framing Status Failed %d\n", rcb_card->pos + 1, + framing_status_status); + printk("rcbfx %d: G168 DSP Framing Status %d %d %d %d %d\n", + rcb_card->pos + 1, ec1, ec2, ec3, dmaec, slips); + } + } + + Gpak_24_chan_port_config.FirstSlotMask1 = (rcb_card->chanflag & 0xffff); + Gpak_24_chan_port_config.SecSlotMask1 = ((rcb_card->chanflag >> 16) & 0xffff); + + Gpak_24_chan_port_config.FirstSlotMask2 = (rcb_card->chanflag & 0xffff); + Gpak_24_chan_port_config.SecSlotMask2 = ((rcb_card->chanflag >> 16) & 0xffff); + + rcb_card_dsp_show_portconfig(Gpak_24_chan_port_config); + + + if ((cp_res = + gpakConfigurePorts(rcb_card, rcb_card->pos, &Gpak_24_chan_port_config, + &cp_error))) { + printk("rcbfx %d: G168 DSP Port Config failed res = %d error = %d\n", + rcb_card->pos + 1, cp_res, cp_error); + return -1; + } + + + if (debug & DEBUG_DSP) + printk("rcbfx %d: G168 DSP Port Config success %d\n", rcb_card->pos + 1, cp_res); + + rcb_card_dsp_ping(rcb_card); + + if (debug & DEBUG_DSP) { + framing_status_status = + gpakReadFramingStats(rcb_card, rcb_card->pos, &ec1, &ec1, &ec3, &dmaec, + &slips); + if (framing_status_status == RfsSuccess) { + printk("rcbfx %d: G168 DSP Framing Status Sucess %d\n", rcb_card->pos + 1, + framing_status_status); + printk("rcbfx %d: G168 DSP Framing Status %d %d %d %d %d\n", + rcb_card->pos + 1, ec1, ec2, ec3, dmaec, slips); + } else { + printk("rcbfx %d: G168 DSP Framing Status Failed %d\n", rcb_card->pos + 1, + framing_status_status); + printk("rcbfx %d: G168 DSP Framing Status %d %d %d %d %d\n", + rcb_card->pos + 1, ec1, ec2, ec3, dmaec, slips); + } + } + + Gpak_chan_config.EcanParametersA.EcanNlpType = nlp_type; + Gpak_chan_config.EcanParametersB.EcanNlpType = nlp_type; + + for (chan_num = 0; chan_num < rcb_card->num_chans; chan_num++) { + + if (rcb_card->chanflag & (1 << chan_num)) { + + dsp_in_use++; + Gpak_chan_config.EcanEnableA = Enabled; + Gpak_chan_config.SoftwareCompand = cmpPCMU; + + Gpak_chan_config.PcmInSlotA = chan_num; + Gpak_chan_config.PcmOutSlotA = chan_num; + Gpak_chan_config.PcmInSlotB = chan_num; + Gpak_chan_config.PcmOutSlotB = chan_num; + + rcb_card_dsp_show_chanconfig(Gpak_chan_config); + + if ((chan_conf_stat = + gpakConfigureChannel(rcb_card, rcb_card->pos, chan_num, tdmToTdm, + &Gpak_chan_config, &chan_config_err))) { + printk("rcbfx %d: Chan %d G168 DSP Chan Config failed error = %d %d\n", + rcb_card->pos + 1, chan_num + 1, chan_config_err, chan_conf_stat); + return -1; + } + + else if (debug & DEBUG_DSP) + printk("rcbfx %d: G168 DSP Chan %d Config success %d\n", + rcb_card->pos + 1, chan_num, chan_conf_stat); + + rcb_card_dsp_ping(rcb_card); + + rcbfx_chan_ec_disable(rcb_card, chan_num); + + } + } + + /* switch to dsp audio stream */ + if ((use_ec == -1) || (use_ec == 1)) + *(volatile __u8 *) (rcb_card->memaddr + EC_CNTL) |= EC_ON; + + rcb_card->dsp_up = 1; + + *(volatile __u32 *) (rcb_card->memaddr + RCB_EC_ENA) = 0xffffffff; + *(volatile __u32 *) (rcb_card->memaddr + RCB_EC_ENB) = 0; + + rcb_card->wq = create_singlethread_workqueue("rcbfx_ec"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&rcb_card->work, echocan_bh, rcb_card); +#else + INIT_WORK(&rcb_card->work, echocan_bh); +#endif + + + printk("rcbfx %d: G168 DSP Active and Servicing %d Channels - %x\n", + rcb_card->pos + 1, dsp_in_use, dsp_chans); + + return dsp_chans; +} + +#endif + +static int __devinit rcb_card_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int res, regnum; + static struct rcb_card_t *rcb_card; + struct rcb_card_desc *d = (struct rcb_card_desc *) ent->driver_data; + int x, i; + static int initd_ifaces = 0; + + if (initd_ifaces) { + memset((void *) ifaces, 0, (sizeof(struct rcb_card_t *)) * RH_MAX_IFACES); + initd_ifaces = 1; + } + for (x = 0; x < RH_MAX_IFACES; x++) + if (!ifaces[x]) + break; + if (x >= RH_MAX_IFACES) { + /* had some chickens EI */ + printk("Too many interfaces\n"); + return -EIO; + } + + if (pci_enable_device(pdev)) { + /* had some cows EI */ + printk("No Rhino spotted\n"); + res = -EIO; + } else { + rcb_card = kmalloc(sizeof(struct rcb_card_t), GFP_KERNEL); + if (rcb_card) { + int cardcount = 0; + ifaces[x] = rcb_card; + memset(rcb_card, 0, sizeof(struct rcb_card_t)); + + for (i = 0; i < d->num_chans; i++) { + printk("alloc chan %x ec %x\n", i, i); + if (! + (rcb_card->chans[i] = + kmalloc(sizeof(*rcb_card->chans[i]), GFP_KERNEL))) { + return -ENOMEM; + } + memset(rcb_card->chans[i], 0, sizeof(*rcb_card->chans[i])); + + if (!(rcb_card->ec[i] = kmalloc(sizeof(*rcb_card->ec[i]), GFP_KERNEL))) { + return -ENOMEM; + } + memset(rcb_card->ec[i], 0, sizeof(*rcb_card->ec[i])); + + } + + spin_lock_init(&rcb_card->lock); + rcb_card->curcard = -1; + rcb_card->baseaddr = pci_resource_start(pdev, 0); + rcb_card->memlen = pci_resource_len(pdev, 0); + rcb_card->chans_configed = 0; + rcb_card->dev = pdev; + rcb_card->pos = x; + + rcb_card->num_chans = d->num_chans; + rcb_card->num_slots = d->num_slots; + rcb_card->variety = d->name; + rcb_card->hw_ver_min = d->hw_ver_min; + if (rcb_card->num_chans > 8) + rcb_card->dsp_type = DSP_5510; + else + rcb_card->dsp_type = DSP_5507; + + if (request_region(rcb_card->baseaddr, rcb_card->memlen, rcb_card->variety)) + rcb_card->freeregion = 1; + + rcb_card->memaddr = ioremap_nocache(rcb_card->baseaddr, rcb_card->memlen); + printk("rcbfx %d: Rhino PCI BAR0 %lx IOMem mapped at %lx\n", + rcb_card->pos + 1, (long unsigned int) rcb_card->baseaddr, + (long unsigned int) rcb_card->memaddr); + + /* chunksize * num channels * 2 swap buffers * 2 read and write */ + rcb_card->writechunk = + (unsigned char *) pci_alloc_consistent(pdev, + DAHDI_MAX_CHUNKSIZE * + rcb_card->num_slots * 2 * 2, + &rcb_card->writedma); + + if (!rcb_card->writechunk) { + printk("rcbfx %d: Unable to allocate DMA-able memory\n", + rcb_card->pos + 1); + rcb_card_cleaner(rcb_card, IOUNMAP); + return -ENOMEM; + } + /* read starts @ write + 8 samples * 4 channels * 2 buffers later = 0x40 bytes */ + rcb_card->readchunk = rcb_card->writechunk + (DAHDI_MAX_CHUNKSIZE * rcb_card->num_slots * 2); /* half the total */ + rcb_card->readdma = rcb_card->writedma + (DAHDI_MAX_CHUNKSIZE * rcb_card->num_slots * 2); /* in bytes */ + + pci_set_master(pdev); + + pci_set_drvdata(pdev, rcb_card); + + if (request_irq + (pdev->irq, rcb_card_interrupt, DAHDI_IRQ_SHARED, rcb_card->variety, + rcb_card)) { + printk("rcbfx %d: Unable to request IRQ %d\n", rcb_card->pos + 1, + pdev->irq); + rcb_card_cleaner(rcb_card, + RH_KFREE | PCI_FREE | IOUNMAP | FREE_DMA | STOP_DMA | + FREE_INT | ZUNREG); + return -EIO; /* had some pigs EI */ + } + + /* sticks in here without up */ + if (rcb_card_hardware_init(rcb_card)) { + printk("rcbfx %d: Unable to initialize hardware\n", rcb_card->pos + 1); + rcb_card_cleaner(rcb_card, + RH_KFREE | PCI_FREE | IOUNMAP | FREE_DMA | STOP_DMA | + FREE_INT | ZUNREG); + return -EIO; /* had some ducks EI */ + } + + rcb_card->dsp_up = 0; + +#ifdef USE_G168_DSP + if (rcb_card_dsp_init(rcb_card) < 0) + printk("rcbfx %d: Unable to initialize G168 DSP\n", rcb_card->pos + 1); +#endif + + if ((use_ec_zap > 0) || (use_ec_zap == 0)) /* forced value */ + zt_ec_chanmap = use_ec_zap; + else if (rcb_card->dsp_up == 0) /* Switch on if there is no DSP */ + zt_ec_chanmap = -1; + else + zt_ec_chanmap = 0; + + + if (use_ec == 1) + *(volatile __u8 *) (rcb_card->memaddr + EC_CNTL) |= EC_ON; + + if (use_ec == 0) + *(volatile __u8 *) (rcb_card->memaddr + EC_CNTL) &= ~EC_ON; + + if (rcb_card_initialize(rcb_card)) { + /* set up and register span and channels */ + printk("rcbfx %d: Unable to initialize \n", rcb_card->pos + 1); + rcb_card_cleaner(rcb_card, + RH_KFREE | IOUNMAP | FREE_DMA | STOP_DMA | FREE_INT); + return -EIO; /* had some goats EI */ + } + + printk("rcbfx %d: Starting DMA\n", rcb_card->pos + 1); + + rcb_card_start_dma(rcb_card); + + for (regnum = 0; regnum < P_TBL_CNT; regnum++) { + + *(volatile __u8 *) (rcb_card->memaddr + PARAM_TBL + regnum) = + rcb_settings_default[regnum]; + } + + /* notify changes */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) = 0x01000; + + for (x = 0; x < rcb_card->num_chans; x++) { + if (rcb_card->chanflag & (1 << x)) + cardcount++; + } + /* let board run signaling data now */ + /* notify changes */ + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT) |= 0x01; + if (debug) + printk("rcbfx %d: Statout = %x\n", rcb_card->pos + 1, + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT)); + /* notify changes */ + *(volatile __u32 *) (rcb_card->memaddr + RCB_TXSIGSTAT) = 0x04000; + + if ((rcb_card->dev->device == PCI_DEVICE_RCB4FXO) || + (rcb_card->dev->device == PCI_DEVICE_RCB24FXO) || + (rcb_card->dev->device == PCI_DEVICE_RCB24FXS)) + + printk("rcbfx %d: Spotted a Rhino: %s (%d channels)\n", rcb_card->pos + 1, + rcb_card->variety, cardcount); + else + printk("rcbfx %d: Spotted a Rhino: %s (%d modules)\n", rcb_card->pos + 1, + rcb_card->variety, cardcount / 2); + + res = 0; + + } else /* if (!rcb_card) */ + res = -ENOMEM; + } + return res; +} + +static void __devexit rcb_card_remove_one(struct pci_dev *pdev) +{ + struct rcb_card_t *rcb_card = pci_get_drvdata(pdev); + if (rcb_card) { + if (rcb_card->dsp_up) { + flush_workqueue(rcb_card->wq); + destroy_workqueue(rcb_card->wq); + } + + /* reset DSP */ + *(volatile __u8 *) (rcb_card->memaddr + FW_BOOT) = 0x00 | DSP_RST; + rcb_card_stop_dma(rcb_card); + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT) &= ~0x00; + if (debug) + printk("rcbfx %d: Statout = %x\n", rcb_card->pos + 1, + *(volatile __u8 *) (rcb_card->memaddr + RCB_STATOUT)); + *(volatile __u8 *) (rcb_card->memaddr + FW_DATA) = 0x00; + *(volatile __u8 *) (rcb_card->memaddr + FW_COMOUT) = 0x00; + pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * rcb_card->num_chans, + (void *) rcb_card->writechunk, rcb_card->writedma); + free_irq(pdev->irq, rcb_card); + if (!rcb_card->usecount) + rcb_card_release(rcb_card); + else + rcb_card->dead = 1; + } +} + +static struct pci_device_id rcb_card_pci_tbl[] = { +/* vendor subvendor class driver_data */ +/* device subdevice class_mask */ + {PCI_VENDOR_RHINO, PCI_DEVICE_RCB4FXO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) &rcb4fxo}, + {PCI_VENDOR_RHINO, PCI_DEVICE_RCB8FXX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) &rcb8fxx}, + {PCI_VENDOR_RHINO, PCI_DEVICE_RCB24FXS, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) &rcb24fxs}, + {PCI_VENDOR_RHINO, PCI_DEVICE_RCB24FXX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) &rcb24fxx}, + {PCI_VENDOR_RHINO, PCI_DEVICE_RCB24FXO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + (unsigned long) &rcb24fxo}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, rcb_card_pci_tbl); + +static struct pci_driver rcb_driver = { + name:"rcbfx", + probe:rcb_card_init_one, + remove:__devexit_p(rcb_card_remove_one), + suspend:NULL, + resume:NULL, + id_table:rcb_card_pci_tbl, +}; + +static int __init rcb_card_init(void) +{ + int res; + res = dahdi_pci_module(&rcb_driver); + if (res) + return -ENODEV; + return 0; +} + +static void __exit rcb_card_cleanup(void) +{ + pci_unregister_driver(&rcb_driver); +} + +module_param(force_fw, int, 0600); +MODULE_PARM_DESC(force_fw, "Reprogram firmware regardless of version"); +module_param(debug, int, 0600); +MODULE_PARM_DESC(debug, "1 for debugging messages"); +module_param(nlp_type, int, 0600); +MODULE_PARM_DESC(nlp_type, "0 - off, 1 - mute, 2 - rand, 3 - hoth, 4 - supp"); + +module_param(zt_ec_chanmap, int, 0600); +module_param(fxs_alg_chanmap, int, 0600); +module_param(fxo_alg_chanmap, int, 0600); +module_param(use_fxs_chanmap, int, 0600); +module_param(use_fxo_chanmap, int, 0600); +#if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) +module_param_array(lvs, int, &arr_argc, 0600); +module_param_array(reg_val, int, &arr_argc, 0600); +#endif /* param arrays */ +module_param(battime, int, 0600); +module_param(reg_addr, int, 0600); +module_param(no_ec, int, 0600); + +MODULE_DESCRIPTION("Rhino Equipment Modular Analog Interface Driver " DAHDI_VERSION); +MODULE_AUTHOR + ("Bob Conklin \n\tBryce Chidester \n\tMatthew Gessner MAX_CHANNELS) + MaxChannels[DspId] = MAX_CHANNELS; + else + MaxChannels[DspId] = (unsigned short int) DspChannels; +#if 0 + /* read the number of configured DSP conferences */ + gpakReadDspMemory(rxt1_card, DspId, IfBlockPntr + NUM_CONFERENCES_OFFSET, 1, + &DspConfs); + if (DspConfs > MAX_CONFS) + MaxConfs[DspId] = MAX_CONFS; + else + MaxConfs[DspId] = (unsigned short int) DspConfs; + + + /* read the number of configured DSP packet channels */ + gpakReadDspMemory(rxt1_card, DspId, IfBlockPntr + NUM_PKT_CHANNELS_OFFSET, 1, + &DspChannels); + if (DspChannels > MAX_PKT_CHANNELS) + MaxPktChannels[DspId] = MAX_PKT_CHANNELS; + else + MaxPktChannels[DspId] = (unsigned short int) DspChannels; + + + /* read the pointer to the circular buffer infor struct table */ + gpakReadDspMemory(rxt1_card, DspId, IfBlockPntr + PKT_BUFR_MEM_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(PktBufrMem, Temp); + + + /* Determine the addresses of each channel's Packet buffers. */ + for (i = 0; i < MaxPktChannels[DspId]; i++) { + pPktInBufr[DspId][i] = PktBufrMem; + pPktOutBufr[DspId][i] = PktBufrMem + CIRC_BUFFER_INFO_STRUCT_SIZE; + PktBufrMem += (CIRC_BUFFER_INFO_STRUCT_SIZE * 2); + } +#endif + + if (rxt1_card->dsp_type == DSP_5510) { + /* read the pointer to the event fifo info struct */ + gpakReadDspMemory(rxt1_card, DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, + Temp); + RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp); + } + + /* Set the DSP Status to indicate the host recognized the reset. */ + DspStatus = HOST_INIT_STATUS; + gpakWriteDspMemory(rxt1_card, DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, + &DspStatus); + + /* Return with an indication that a reset occurred. */ + return (1); + } + + /* If status doesn't indicate the host recognized a reset, return with an + indication the DSP is not ready. */ + if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0)) + return (-1); + + /* Return with an indication that a reset did not occur. */ + return (0); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * WriteDspCmdMessage - Write a Host Command/Request message to DSP. + * + * FUNCTION + * This function writes a Host Command/Request message into DSP memory and + * informs the DSP of the presence of the message. + * + * RETURNS + * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) + * 0 = Temporarily unable to write message (previous Cmd Msg busy) + * 1 = Message written successfully + * + */ +static int WriteDspCmdMessage(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMessage, /* pointer to Command message */ + DSP_WORD MsgLength /* length of message (octets) */ + ) +{ + DSP_WORD CmdMsgLength; /* current Cmd message length */ + DSP_WORD Temp[2]; + DSP_ADDRESS BufferPointer; /* message buffer pointer */ + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rxt1_card, DspId) == -1) + return (-1); + + /* Make sure the message length is valid. */ + if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId])) + return (-1); + + /* Make sure a previous Command message is not in use by the DSP. */ + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + if (CmdMsgLength != 0) + return (0); + + /* Purge any previous Reply message that wasn't read. */ + gpakWriteDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Copy the Command message into DSP memory. */ + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakWriteDspMemory(rxt1_card, DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); + + /* Store the message length in DSP's Command message length (flags DSP that + a Command message is ready). */ + CmdMsgLength = MsgLength; + gpakWriteDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Return with an indication the message was written. */ + return (1); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ReadDspReplyMessage - Read a DSP Reply message from DSP. + * + * FUNCTION + * This function reads a DSP Reply message from DSP memory. + * + * RETURNS + * -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready) + * 0 = No message available (DSP Reply message empty) + * 1 = Message read successfully (message and length stored in variables) + * + */ +static int ReadDspReplyMessage(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMessage, /* pointer to Reply message buffer */ + DSP_WORD * pMsgLength /* pointer to msg length var (octets) */ + ) +{ + DSP_WORD MsgLength; /* message length */ + DSP_ADDRESS BufferPointer; /* message buffer pointer */ + DSP_WORD Temp[2]; + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rxt1_card, DspId) == -1) + return (-1); + + /* Check if a Reply message is ready. */ + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &MsgLength); + if (MsgLength == 0) + return (0); + + /* Make sure the message length is valid. */ + if (MsgLength > *pMsgLength) + return (-1); + + /* Copy the Reply message from DSP memory. */ + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, + Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakReadDspMemory(rxt1_card, DspId, BufferPointer, (MsgLength + 1) / 2, pMessage); + + /* Store the message length in the message length variable. */ + *pMsgLength = MsgLength; + + /* Indicate a Reply message is not ready. */ + MsgLength = 0; + gpakWriteDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &MsgLength); + + /* Return with an indication the message was read. */ + return (1); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ReadCircBuffer - Read from a DSP circular buffer. + * + * FUNCTION + * This function reads a block of words from a DSP circular buffer. The Take + * address is incremented by the number of words read adjusting for buffer + * wrap. + * + * RETURNS + * nothing + * + */ +static void ReadCircBuffer(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_ADDRESS BufrBaseAddress, /* address of base of circular buffer */ + DSP_ADDRESS BufrLastAddress, /* address of last word in buffer */ + DSP_ADDRESS * TakeAddress, /* pointer to address in buffer for read */ + DSP_WORD * pWordBuffer, /* pointer to buffer for words read */ + DSP_WORD NumWords /* number of words to read */ + ) +{ + DSP_WORD WordsTillEnd; /* number of words until end of buffer */ + + /* Determine the number of words from the start address until the end of the + buffer. */ + WordsTillEnd = BufrLastAddress - *TakeAddress + 1; + + /* If a buffer wrap will occur, read the first part at the end of the + buffer followed by the second part at the beginning of the buffer. */ + if (NumWords > WordsTillEnd) { + gpakReadDspMemory(rxt1_card, DspId, *TakeAddress, WordsTillEnd, pWordBuffer); + gpakReadDspMemory(rxt1_card, DspId, BufrBaseAddress, NumWords - WordsTillEnd, + &(pWordBuffer[WordsTillEnd])); + *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd; + } + + /* If a buffer wrap will not occur, read all words starting at the current + take address in the buffer. */ + else { + gpakReadDspMemory(rxt1_card, DspId, *TakeAddress, NumWords, pWordBuffer); + if (NumWords == WordsTillEnd) + *TakeAddress = BufrBaseAddress; + else + *TakeAddress = *TakeAddress + NumWords; + } + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * VerifyReply - Verify the reply message is correct for the command sent. + * + * FUNCTION + * This function verifies correct reply message content for the command that + * was just sent. + * + * RETURNS + * 0 = Incorrect + * 1 = Correct + * + */ +static int VerifyReply(DSP_WORD * pMsgBufr, /* pointer to Reply message buffer */ + int CheckType, /* reply check type */ + DSP_WORD CheckValue /* reply check value */ + ) +{ + + /* Verify Channel or Conference Id. */ + if (CheckType == 1) { + if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue) + return (0); + } + + /* Verify Test Mode Id. */ + else if (CheckType == 2) { + if (pMsgBufr[1] != CheckValue) + return (0); + } + + /* Return with an indication of correct reply. */ + return (1); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * TransactCmd - Send a command to the DSP and receive it's reply. + * + * FUNCTION + * This function sends the specified command to the DSP and receives the DSP's + * reply. + * + * RETURNS + * Length of reply message (0 = Failure) + * + */ +static unsigned int TransactCmd(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + DSP_WORD * pMsgBufr, /* pointer to Cmd/Reply message buffer */ + DSP_WORD CmdLength, /* length of command message (octets) */ + DSP_WORD ReplyType, /* required type of reply message */ + DSP_WORD ReplyLength, /* required length of reply message (octets) */ + int ReplyCheckType, /* reply check type */ + DSP_WORD ReplyCheckValue /* reply check value */ + ) +{ + int FuncStatus; /* function status */ + int LoopCount; /* wait loop counter */ + DSP_WORD RcvReplyLength; /* received Reply message length */ + DSP_WORD RcvReplyType; /* received Reply message type code */ + DSP_WORD RetValue; /* return value */ + + /* Default the return value to indicate a failure. */ + RetValue = 0; + + /* Lock access to the DSP. */ + gpakLockAccess(rxt1_card, DspId); + + + /* Attempt to write the command message to the DSP. */ + LoopCount = 0; + while ((FuncStatus = WriteDspCmdMessage(rxt1_card, DspId, pMsgBufr, CmdLength)) != 1) { + if (FuncStatus == -1) + break; + if (++LoopCount > MAX_WAIT_LOOPS) + break; + gpakHostDelay(); + } + + /* Attempt to read the reply message from the DSP if the command message was + sent successfully. */ + if (FuncStatus == 1) { + for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++) { + RcvReplyLength = MSG_BUFFER_SIZE * 2; + FuncStatus = ReadDspReplyMessage(rxt1_card, DspId, pMsgBufr, &RcvReplyLength); + if (FuncStatus == 1) { + RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF; + if ((RcvReplyLength >= ReplyLength) && + (RcvReplyType == ReplyType) && + VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue)) { + RetValue = RcvReplyLength; + break; + } else if (RcvReplyType == MSG_NULL_REPLY) + break; + } else if (FuncStatus == -1) + break; + gpakHostDelay(); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rxt1_card, DspId); + + /* Return the length of the reply message (0 = failure). */ + return (RetValue); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakConfigurePorts - Configure a DSP's serial ports. + * + * FUNCTION + * This function configures a DSP's serial ports. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakConfigPortStatus_t gpakConfigurePorts(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + GpakPortConfig_t * pPortConfig, /* pointer to Port Config info */ + GPAK_PortConfigStat_t * pStatus /* pointer to Port Config Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (CpsInvalidDsp); + + /* Build the Configure Serial Ports message. */ + MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8; + MsgBuffer[1] = (DSP_WORD) + ((pPortConfig->SlotsSelect1 << 12) | + ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum1 << 4) & 0x00F0)); + MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1; + MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1; + MsgBuffer[4] = (DSP_WORD) + ((pPortConfig->SlotsSelect2 << 12) | + ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum2 << 4) & 0x00F0)); + MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2; + MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2; + MsgBuffer[7] = (DSP_WORD) + ((pPortConfig->SlotsSelect3 << 12) | + ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) | + ((pPortConfig->SecBlockNum3 << 4) & 0x00F0)); + MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3; + MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3; + + MsgBuffer[10] = (DSP_WORD) + (((pPortConfig->DxDelay1 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay1 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay1 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) | + ((pPortConfig->CompandingMode1 << 1) & 0x0006) | + (pPortConfig->SerialWordSize1 & 0x0001)); + + MsgBuffer[11] = (DSP_WORD) + (((pPortConfig->DxDelay2 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay2 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay2 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) | + ((pPortConfig->CompandingMode2 << 1) & 0x0006) | + (pPortConfig->SerialWordSize2 & 0x0001)); + + MsgBuffer[12] = (DSP_WORD) + (((pPortConfig->DxDelay3 << 11) & 0x0800) | + ((pPortConfig->RxDataDelay3 << 9) & 0x0600) | + ((pPortConfig->TxDataDelay3 << 7) & 0x0180) | + ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) | + ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) | + ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) | + ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) | + ((pPortConfig->CompandingMode3 << 1) & 0x0006) | + (pPortConfig->SerialWordSize3 & 0x0001)); + + if (rxt1_card->dsp_type == DSP_5510) { + MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1; + MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1; + MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1; + MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1; + MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1; + MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1; + + MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;; + MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2; + MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;; + MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2; + MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;; + MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2; + + MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;; + MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3; + MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;; + MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3; + MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;; + MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3; + + /* Attempt to send the Configure Serial Ports message to the DSP and receive + it's reply. */ + if (!TransactCmd + (rxt1_card, DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) + return (CpsDspCommFailure); + } + + else { + /* Attempt to send the Configure Serial Ports message to the DSP and receive + it's reply. */ + if (!TransactCmd + (rxt1_card, DspId, MsgBuffer, 26, MSG_CONFIG_PORTS_REPLY, 4, 0, 0)) + return (CpsDspCommFailure); + } + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Pc_Success) + return (CpsSuccess); + else + return (CpsParmError); +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakConfigureChannel - Configure a DSP's Channel. + * + * FUNCTION + * This function configures a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakConfigChanStatus_t gpakConfigureChannel(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ + GpakChanType ChannelType, /* Channel Type */ + GpakChannelConfig_t * pChanConfig, /* pointer to Channel Config info */ + GPAK_ChannelConfigStat_t * pStatus /* pointer to Channel Config Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD MsgLength; /* message length */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (CcsInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (CcsInvalidChannel); + + /* Build the Configure Channel message based on the Channel Type. */ + switch (ChannelType) { + + /* PCM to Packet channel type. */ + case tdmToTdm: + + MsgBuffer[2] = (DSP_WORD) + ((pChanConfig->PcmInPortA << 8) | (pChanConfig->PcmInSlotA & 0xFF)); + MsgBuffer[3] = (DSP_WORD) + ((pChanConfig->PcmOutPortA << 8) | (pChanConfig->PcmOutSlotA & 0xFF)); + + MsgBuffer[4] = (DSP_WORD) + ((pChanConfig->PcmInPortB << 8) | (pChanConfig->PcmInSlotB & 0xFF)); + MsgBuffer[5] = (DSP_WORD) + ((pChanConfig->PcmOutPortB << 8) | (pChanConfig->PcmOutSlotB & 0xFF)); + + if (rxt1_card->dsp_type == DSP_5510) { + MsgBuffer[6] = (DSP_WORD) + (((pChanConfig->FaxCngDetB << 11) & 0x0800) | + ((pChanConfig->FaxCngDetA << 10) & 0x0400) | + ((pChanConfig->MuteToneB << 9) & 0x0200) | + ((pChanConfig->MuteToneA << 8) & 0x0100) | + ((pChanConfig->FrameRate << 6) & 0x00C0) | + ((pChanConfig->ToneTypesB << 5) & 0x0020) | + ((pChanConfig->ToneTypesA << 4) & 0x0010) | + ((pChanConfig->SoftwareCompand & 3) << 2) | + (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1) + ); + } else { + MsgBuffer[6] = (DSP_WORD) + ((pChanConfig->FrameRate << 6) | + //((pChanConfig->ToneTypesB << 5) & 0x0020) | + //((pChanConfig->ToneTypesA << 4) & 0x0010) | + ((pChanConfig->SoftwareCompand & 3) << 2) | + (pChanConfig->EcanEnableB << 1) | (pChanConfig->EcanEnableA & 1)); + } + + MsgBuffer[7] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanTapLength; + MsgBuffer[8] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpType; + MsgBuffer[9] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanAdaptEnable; + MsgBuffer[10] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanG165DetEnable; + MsgBuffer[11] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanDblTalkThresh; + MsgBuffer[12] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpThreshold; + MsgBuffer[13] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpConv; + MsgBuffer[14] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpUnConv; + MsgBuffer[15] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNlpMaxSuppress; + + MsgBuffer[16] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanCngThreshold; + MsgBuffer[17] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanAdaptLimit; + MsgBuffer[18] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanCrossCorrLimit; + MsgBuffer[19] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanNumFirSegments; + MsgBuffer[20] = (DSP_WORD) + pChanConfig->EcanParametersA.EcanFirSegmentLen; + + MsgBuffer[21] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanTapLength; + MsgBuffer[22] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpType; + MsgBuffer[23] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanAdaptEnable; + MsgBuffer[24] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanG165DetEnable; + MsgBuffer[25] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanDblTalkThresh; + MsgBuffer[26] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpThreshold; + MsgBuffer[27] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpConv; + MsgBuffer[28] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpUnConv; + MsgBuffer[29] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNlpMaxSuppress; + MsgBuffer[30] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanCngThreshold; + MsgBuffer[31] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanAdaptLimit; + MsgBuffer[32] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanCrossCorrLimit; + MsgBuffer[33] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanNumFirSegments; + MsgBuffer[34] = (DSP_WORD) + pChanConfig->EcanParametersB.EcanFirSegmentLen; + + MsgLength = 70; // byte number == 35*2 + break; + + + /* Unknown (invalid) channel type. */ + default: + *pStatus = Cc_InvalidChannelType; + return (CcsParmError); + } + + MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF)); + + /* Attempt to send the Configure Channel message to the DSP and receive it's + reply. */ + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (CcsDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Cc_Success) + return (CcsSuccess); + else + return (CcsParmError); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakTearDownChannel - Tear Down a DSP's Channel. + * + * FUNCTION + * This function tears down a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakTearDownStatus_t gpakTearDownChannel(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Id (0 to MaxDSPCores-1) */ + unsigned short int ChannelId, /* Channel Id (0 to MaxChannels-1) */ + GPAK_TearDownChanStat_t * pStatus /* pointer to Tear Down Status */ + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (TdsInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (TdsInvalidChannel); + + /* Build the Tear Down Channel message. */ + MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8; + MsgBuffer[1] = (DSP_WORD) (ChannelId << 8); + + /* Attempt to send the Tear Down Channel message to the DSP and receive it's + reply. */ + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (TdsDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Td_Success) + return (TdsSuccess); + else + return (TdsError); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAlgControl - Control an Algorithm. + * + * FUNCTION + * This function controls an Algorithm + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakAlgControlStat_t gpakAlgControl(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakAlgCtrl_t ControlCode, // algorithm control code + GPAK_AlgControlStat_t * pStatus // pointer to return status + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (AcInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (AcInvalidChannel); + + MsgBuffer[0] = MSG_ALG_CONTROL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF)); + +#if 0 + printk("r%dt1 %d: Alg control Chan %d Control code %d\n", rxt1_card->numspans, + rxt1_card->num + 1, ChannelId, ControlCode); +#endif + + /* Attempt to send the Tear Down Channel message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1, + (DSP_WORD) ChannelId)) + return (AcDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF); + if (*pStatus == Ac_Success) + return (AcSuccess); + else + return (AcParmError); + +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadEventFIFOMessage - read from the event fifo + * + * FUNCTION + * This function reads a single event from the event fifo if one is available + * + * RETURNS + * Status code indicating success or a specific error. + * + * Notes: This function should be called in a loop until the return status + * indicates that the fifo is empty. + * + * If the event code equals "EventLoopbackTeardownComplete", then the + * contents of *pChannelId hold the coderBlockId that was assigned to + * the loopback coder that was torn down. + */ +gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(struct rxt1_card_t * rxt1_card, // Card containing the DSP + unsigned short int DspId, // DSP identifier + unsigned short int *pChannelId, // pointer to channel identifier + GpakAsyncEventCode_t * pEventCode, // pointer to Event Code + GpakAsyncEventData_t * pEventData // pointer to Event Data Struct + ) +{ + DSP_WORD WordBuffer[WORD_BUFFER_SIZE]; /* DSP words buffer */ + GpakAsyncEventCode_t EventCode; /* DSP's event code */ + DSP_WORD EventDataLength; /* Length of event to read */ + DSP_WORD ChannelId; /* DSP's channel Id */ + DSP_ADDRESS EventInfoAddress; /* address of EventFIFO info structure */ + DSP_ADDRESS BufrBaseAddress; /* base address of EventFIFO buffer */ + DSP_ADDRESS BufrLastAddress; /* last address of EventFIFO buffer */ + DSP_ADDRESS TakeAddress; /* current take address in fifo buffer */ + DSP_WORD BufrSize; /* size (in words) of event FIFO buffer */ + DSP_WORD PutIndex; /* event fifo put index */ + DSP_WORD TakeIndex; /* event fifo take index */ + DSP_WORD WordsReady; /* number words ready for read out of event fifo */ + DSP_WORD EventError; /* flag indicating error with event fifo msg */ +// DSP_WORD *pDebugData; /* debug data buffer pointer in event data struct */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RefInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rxt1_card, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rxt1_card, DspId) == -1) { + gpakUnlockAccess(rxt1_card, DspId); + return (RefDspCommFailure); + } + + /* Check if an event message is ready in the DSP. */ + EventInfoAddress = pEventFifoAddress[DspId]; + gpakReadDspMemory(rxt1_card, DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE, + WordBuffer); + RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *) & WordBuffer[CB_BUFR_BASE])); + BufrSize = WordBuffer[CB_BUFR_SIZE]; + PutIndex = WordBuffer[CB_BUFR_PUT_INDEX]; + TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX]; + if (PutIndex >= TakeIndex) + WordsReady = PutIndex - TakeIndex; + else + WordsReady = PutIndex + BufrSize - TakeIndex; + + if (WordsReady < 2) { + gpakUnlockAccess(rxt1_card, DspId); + return (RefNoEventAvail); + } + + /* Read the event header from the DSP's Event FIFO. */ + TakeAddress = BufrBaseAddress + TakeIndex; + BufrLastAddress = BufrBaseAddress + BufrSize - 1; + ReadCircBuffer(rxt1_card, DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, + WordBuffer, 2); + TakeIndex += 2; + if (TakeIndex >= BufrSize) + TakeIndex -= BufrSize; + + ChannelId = (WordBuffer[0] >> 8) & 0xFF; + EventCode = (GpakAsyncEventCode_t) (WordBuffer[0] & 0xFF); + EventDataLength = WordBuffer[1]; + EventError = 0; + + switch (EventCode) { + case EventToneDetect: + if (EventDataLength > WORD_BUFFER_SIZE) { + gpakUnlockAccess(rxt1_card, DspId); + return (RefInvalidEvent); + } + ReadCircBuffer(rxt1_card, DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress, + WordBuffer, EventDataLength); + pEventData->toneEvent.ToneCode = (GpakToneCodes_t) + (WordBuffer[0] & 0xFF); + pEventData->toneEvent.ToneDuration = WordBuffer[1]; + pEventData->toneEvent.Direction = WordBuffer[2]; + pEventData->toneEvent.DebugToneStatus = WordBuffer[3]; + TakeIndex += EventDataLength; + if (TakeIndex >= BufrSize) + TakeIndex -= BufrSize; + if (EventDataLength != 4) + EventError = 1; + break; + + default: + EventError = 1; + break; + }; + + /* Update the Take index in the DSP's Packet Out buffer information. */ + gpakWriteDspMemory(rxt1_card, DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1, + &TakeIndex); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rxt1_card, DspId); + + if (EventError) + return (RefInvalidEvent); + + *pChannelId = ChannelId; + *pEventCode = EventCode; + return (RefEventAvail); + +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakPingDsp - ping the DSP to see if it's alive + * + * FUNCTION + * This function checks if the DSP is still communicating with the host + * and returns the DSP SW version + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakPingDspStat_t gpakPingDsp(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pDspSwVersion // DSP software version + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + //printk("pDspIfBlk = %x, MaxCmdMsgLen = %x, MaxChannels = %x\n",pDspIfBlk[0], MaxCmdMsgLen[0], MaxChannels[0]); + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (PngInvalidDsp); + + /* send value of 1, DSP increments it */ + MsgBuffer[0] = (MSG_PING << 8); + + /* Attempt to send the ping message to the DSP and receive it's + reply. */ + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0)) + return (PngDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) { + *pDspSwVersion = MsgBuffer[2]; + return (PngSuccess); + } else + return (PngDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakSerialTxFixedValue - transmit a fixed value on a timeslot + * + * FUNCTION + * This function controls transmission of a fixed value out onto a serial + * port's timeslot. + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id + unsigned short int PcmOutSlot, // PCM Output Time Slot + unsigned short int Value, // 16-bit value + GpakActivation State // activation state + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (TfvInvalidDsp); + + /* Make sure the Channel Id is valid. */ + if (ChannelId >= MaxChannels[DspId]) + return (TfvInvalidChannel); + + + /* Build the message. */ + MsgBuffer[0] = MSG_SERIAL_TXVAL << 8; + MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF)); + MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF)); + MsgBuffer[3] = (DSP_WORD) Value; + + /* Attempt to send the message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4, + 1, ChannelId)) + return (TfvDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (TfvSuccess); + else + return (TfvDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakControlTdmLoopBack - control a serial port's loopback state + * + * FUNCTION + * This function enables/disables the tdm input to output looback mode on a + * serial port + * + * RETURNS + * Status code indicating success or a specific error. + */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakSerialPort_t SerialPort, // Serial Port Id + GpakActivation LoopBackState // Loopback State + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (ClbInvalidDsp); + + /* Build the message. */ + MsgBuffer[0] = MSG_TDM_LOOPBACK << 8; + MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF)); + + /* Attempt to send the message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0)) + return (ClbDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (ClbSuccess); + else + return (ClbDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - Read CPU usage statistics from a DSP. + * + * FUNCTION + * This function reads the CPU usage statistics from a DSP's memory. The + * average CPU usage in units of .1 percent are obtained for each of the frame + * rates. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadCpuUsageStat_t gpakReadCpuUsage(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // Dsp Identifier + unsigned short int *pPeakUsage, // pointer to peak usage variable + unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second + ) +{ + DSP_WORD ReadBuffer[2]; /* DSP read buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RcuInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rxt1_card, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rxt1_card, DspId) == -1) + return (RcuDspCommFailure); + + /* Read the CPU Usage statistics from the DSP. */ + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rxt1_card, DspId); + + /* Store the usage statistics in the specified variables. */ + *pPrev1SecPeakUsage = ReadBuffer[0]; + *pPeakUsage = ReadBuffer[1]; + + /* Return with an indication the usage staistics were read successfully. */ + return (RcuSuccess); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetCpuUsageStats - reset the cpu usage statistics + * + * FUNCTION + * This function resets the cpu utilization statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakResetCpuUsageStat_t gpakResetCpuUsageStats(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RstcInvalidDsp); + + MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8); + + /* Attempt to send the message to the DSP and receive it's reply. */ + //need_reply_len; + if (!TransactCmd + (rxt1_card, DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0)) + return (RstcDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (RstcSuccess); + else + return (RstcDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFramingStats + * + * FUNCTION + * This function reads a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakReadFramingStatsStatus_t gpakReadFramingStats(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pFramingError1Count, // port 1 Framing error count + unsigned short int *pFramingError2Count, // port 2 Framing error count + unsigned short int *pFramingError3Count, // port 3 Framing error count + unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count + unsigned short int *pDmaSlipStatsBuffer // DMA slips count + ) +{ + DSP_WORD ReadBuffer[10]; /* DSP read buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RfsInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rxt1_card, DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(rxt1_card, DspId) == -1) + return (RfsDspCommFailure); + + /* Read the framing interrupt statistics from the DSP. */ + if (rxt1_card->dsp_type == DSP_5510) + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10, + ReadBuffer); + else + gpakReadDspMemory(rxt1_card, DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 4, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rxt1_card, DspId); + + /* Store the framing statistics in the specified variables. */ + *pFramingError1Count = ReadBuffer[0]; + *pFramingError2Count = ReadBuffer[1]; + *pFramingError3Count = ReadBuffer[2]; + *pDmaStopErrorCount = ReadBuffer[3]; + + if ((pDmaSlipStatsBuffer != 0) && (rxt1_card->dsp_type == DSP_5510)) + // If users want to get the DMA slips count + { + pDmaSlipStatsBuffer[0] = ReadBuffer[4]; + pDmaSlipStatsBuffer[1] = ReadBuffer[5]; + pDmaSlipStatsBuffer[2] = ReadBuffer[6]; + pDmaSlipStatsBuffer[3] = ReadBuffer[7]; + pDmaSlipStatsBuffer[4] = ReadBuffer[8]; + pDmaSlipStatsBuffer[5] = ReadBuffer[9]; + + } + + /* Return with an indication the statistics were read successfully. */ + return (RfsSuccess); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - reset a DSP's framing interrupt statistics + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakResetFramingStatsStatus_t gpakResetFramingStats(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP's reply status */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RstfInvalidDsp); + + MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8); + + /* Attempt to send the message to the DSP and receive it's reply. */ + //need_reply_len; + if (!TransactCmd + (rxt1_card, DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0)) + return (RstfDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (RstfSuccess); + else + return (RstfDspCommFailure); +} + +/* + * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. + * + * FUNCTION + * This function reads a DSP's Program and Data memory image from the + * specified file and writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakDownloadStatus_t gpakDownloadDsp_5510(struct rxt1_card_t * rxt1_card, /* Card containing the DSP */ + unsigned short DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Download File Identifier */ + ) +{ + gpakDownloadStatus_t RetStatus; /* function return status */ + int NumRead; /* number of file bytes read */ + DSP_ADDRESS Address; /* DSP address */ + unsigned int WordCount; /* number of words in record */ + unsigned int NumWords; /* number of words to read/write */ + unsigned int i; /* loop index / counter */ + unsigned int j; /* loop index */ + unsigned int check_count; /* # of attempts to load block */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (GdlInvalidDsp); + + /* Lock access to the DSP. */ + gpakLockAccess(rxt1_card, DspId); + + RetStatus = GdlSuccess; + while (RetStatus == GdlSuccess) { + + /* Read a record header from the file. */ + NumRead = gpakReadFile_5510(rxt1_card, FileId, DlByteBufr, 6); + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + if (NumRead != 6) { + RetStatus = GdlInvalidFile; + break; + } + Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) | + (((DSP_ADDRESS) DlByteBufr[2]) << 8) | ((DSP_ADDRESS) DlByteBufr[3]); + WordCount = (((unsigned int) DlByteBufr[4]) << 8) | + ((unsigned int) DlByteBufr[5]); + + /* printk("Load 0x%x words into address 0x%x\n", WordCount, Address); */ + + /* Check for the End Of File record. */ + if (DlByteBufr[0] == 0xFF) + break; + + /* Verify the record is for a valid memory type. */ + if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01)) { + RetStatus = GdlInvalidFile; + break; + } + + /* Read a block of words at a time from the file and write to the + DSP's memory . */ + while (WordCount != 0) { + if (WordCount < DOWNLOAD_BLOCK_SIZE) + NumWords = WordCount; + else + NumWords = DOWNLOAD_BLOCK_SIZE; + + WordCount -= NumWords; + NumRead = gpakReadFile_5510(rxt1_card, FileId, DlByteBufr, NumWords * 2); + + if (NumRead == -1) { + RetStatus = GdlFileReadError; + break; + } + + if (NumRead != (NumWords * 2)) { + RetStatus = GdlInvalidFile; + break; + } + + for (i = 0, j = 0; i < NumWords; i++, j += 2) + DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) | + ((DSP_WORD) DlByteBufr[j + 1]); + + check_count = 0; + + while (check_count < 4) { + gpakWriteDspMemory(rxt1_card, DspId, Address, NumWords, DlWordBufr); + gpakReadDspMemory(rxt1_card, DspId, Address, NumWords, DlWordChek); + + if (memcmp(DlWordBufr, DlWordChek, NumWords * 2) == 0) + break; + else + check_count++; + } + + if (check_count) { + if (check_count == 4) { + RetStatus = GdlDspCommFailure; + printk("Failure to load DSP @ Address 0x%08x\n", Address); + } + } + + Address += ((DSP_ADDRESS) NumWords); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(rxt1_card, DspId); + + /* Return with an indication of success or failure. */ + return (RetStatus); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - Read CPU usage statistics from a DSP. + * + * FUNCTION + * This function reads the memory map register section of DSP memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(struct rxt1_card_t * rxt1_card, // Card containing the DSP + unsigned short int DspId, // Dsp Identifier + unsigned short int *pDest, // Buffer on host to hold DSP memory map + DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out + unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word + ) +{ + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + DSP_WORD DspStatus; /* DSP reply's status */ + int i; /* loop index / counter */ + + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RmmInvalidDsp); + + /* Verify the message buffer is large enough */ + if (MSG_BUFFER_SIZE < MemoryLength_Word16) + return (RmmSizeTooBig); + + MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8; + MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF); + MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF); + MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16; + + /* Attempt to send the Read memory section message to the DSP and receive it's + reply. */ + //need_reply_len; + if (!TransactCmd(rxt1_card, DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY, + (MemoryLength_Word16 + 2) * 2, 0, 0)) + return (RmmInvalidAddress); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus != 0) + return (RmmFailure); + + for (i = 0; i < MemoryLength_Word16; i++) + pDest[i] = (short int) MsgBuffer[2 + i]; + + + return (RmmSuccess); +} diff --git drivers/dahdi/rhino/rxt1/GpakApi.h drivers/dahdi/rhino/rxt1/GpakApi.h new file mode 100644 index 0000000..1af1a83 --- /dev/null +++ drivers/dahdi/rhino/rxt1/GpakApi.h @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2005 , Adaptive Digital Technologies, Inc. + * + * File Name: GpakApi.h + * + * Description: + * This file contains the function prototypes and data types for the user + * API functions that communicate with DSPs executing G.PAK software. The + * file is used by application software in the host processor connected to + * C55X G.PAK DSPs via a Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * 11/15/2006 - 24 TDM-TDM Channels EC release + */ + +#ifndef _GPAKAPI_H /* prevent multiple inclusion */ +#define _GPAKAPI_H +#include "GpakErrs.h" +#include "gpakenum.h" +#include "rxt1.h" + +typedef unsigned long int GPAK_FILE_ID; /* G.PAK Download file identifier */ + +#define BL_DSP_BOOTLOADER_ENTRY 0x7020 /* DSP bootloader entry-point, */ + /* HOST have to put this address in 0x60-61 */ + /* after DSP bootloader bin file downloaded */ + +typedef unsigned short int DSP_WORD; /* 16 bit DSP word */ +typedef unsigned int DSP_ADDRESS; /* 32 bit DSP address */ +//typedef unsigned long int DSP_ADDRESS; /* 32 bit DSP address */ + +#define DSP_DEBUG_BUFF_SIZE 42 // units of 16-bit words + +/* Definition of an Asynchronous Event Data Structure */ + +typedef union { + struct { + GpakToneCodes_t ToneCode; // detected tone code + unsigned short int ToneDuration; // tone duration + GpakTdmDirection Direction; // detected on A r B side + short int DebugToneStatus; // reserved for debug info + } toneEvent; + +} GpakAsyncEventData_t; + +/* Definition of an Echo Canceller Parameters information structure. */ + +typedef struct { + short int EcanTapLength; // Echo Can Num Taps (tail length) + short int EcanNlpType; // Echo Can NLP Type + short int EcanAdaptEnable; // Echo Can Adapt Enable flag + short int EcanG165DetEnable; // Echo Can G165 Detect Enable flag + short int EcanDblTalkThresh; // Echo Can Double Talk threshold + short int EcanNlpThreshold; // Echo Can NLP threshold + short int EcanNlpConv; // Dynamic NLP control, NLP limit when EC about to converged + short int EcanNlpUnConv; // Dynamic NLP control, NLP limit when EC not converged yet + short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode + short int EcanCngThreshold; // Echo Can CNG Noise threshold + short int EcanAdaptLimit; // Echo Can Max Adapts per frame + short int EcanCrossCorrLimit; // Echo Can Cross Correlation limit + short int EcanNumFirSegments; // Echo Can Num FIR Segments + short int EcanFirSegmentLen; // Echo Can FIR Segment Length +} GpakEcanParms_t; + +/* Definition of a Channel Configuration information structure. */ + +typedef struct { + GpakSerialPort_t PcmInPortA; // A side PCM Input Serial Port Id + unsigned short int PcmInSlotA; // A side PCM Input Time Slot + GpakSerialPort_t PcmOutPortA; // A side PCM Output Serial Port Id + unsigned short int PcmOutSlotA; // A side PCM Output Time Slot + GpakSerialPort_t PcmInPortB; // B side PCM Input Serial Port Id + unsigned short int PcmInSlotB; // B side PCM Input Time Slot + GpakSerialPort_t PcmOutPortB; // B side PCM Output Serial Port Id + unsigned short int PcmOutSlotB; // B side PCM Output Time Slot + GpakToneTypes ToneTypesA; // A side Tone Detect Types + GpakToneTypes ToneTypesB; // B side Tone Detect Types + GpakActivation EcanEnableA; // Echo Cancel A Enabled + GpakActivation EcanEnableB; // Echo Cancel B Enabled + GpakEcanParms_t EcanParametersA; // Echo Cancel parameters + GpakEcanParms_t EcanParametersB; // Echo Cancel parameters + GpakCompandModes SoftwareCompand; // software companding + GpakRate_t FrameRate; // Gpak Frame Rate + GpakActivation MuteToneA; // A side mute DTMF Enabled + GpakActivation MuteToneB; // B side mute DTMF Enabled + GpakActivation FaxCngDetA; // A side FaxCng Tone Detector Enabled + GpakActivation FaxCngDetB; // B side FaxCng Tone Detector Enabled + +} GpakChannelConfig_t; + + +/* Definition of a Serial Port Configuration Structure */ +typedef struct { + GpakSlotCfg_t SlotsSelect1; // port 1 Slot selection + unsigned short int FirstBlockNum1; // port 1 first group Block Number + unsigned short int FirstSlotMask1; // port 1 first group Slot Mask + unsigned short int SecBlockNum1; // port 1 second group Block Number + unsigned short int SecSlotMask1; // port 1 second group Slot Mask + + GpakSerWordSize_t SerialWordSize1; // port 1 serial word size + GpakCompandModes CompandingMode1; // port 1 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity1; // port 1 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity1; // port 1 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay1; // port 1 Tx data delay + GpakSerDataDelay_t RxDataDelay1; // port 1 Rx data delay + GpakActivation DxDelay1; // port 1 DX Delay + + unsigned short int ThirdSlotMask1; // port 1 3rd group Slot Mask + unsigned short int FouthSlotMask1; // port 1 4th group Slot Mask + unsigned short int FifthSlotMask1; // port 1 5th group Slot Mask + unsigned short int SixthSlotMask1; // port 1 6th group Slot Mask + unsigned short int SevenSlotMask1; // port 1 7th group Slot Mask + unsigned short int EightSlotMask1; // port 1 8th group Slot Mask + + + GpakSlotCfg_t SlotsSelect2; // port 2 Slot selection + unsigned short int FirstBlockNum2; // port 2 first group Block Number + unsigned short int FirstSlotMask2; // port 2 first group Slot Mask + unsigned short int SecBlockNum2; // port 2 second group Block Number + unsigned short int SecSlotMask2; // port 2 second group Slot Mask + GpakSerWordSize_t SerialWordSize2; // port 2 serial word size + GpakCompandModes CompandingMode2; // port 2 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity2; // port 2 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity2; // port 2 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay2; // port 2 Tx data delay + GpakSerDataDelay_t RxDataDelay2; // port 2 Rx data delay + GpakActivation DxDelay2; // port 2 DX Delay + + unsigned short int ThirdSlotMask2; // port 2 3rd group Slot Mask + unsigned short int FouthSlotMask2; // port 2 4th group Slot Mask + unsigned short int FifthSlotMask2; // port 2 5th group Slot Mask + unsigned short int SixthSlotMask2; // port 2 6th group Slot Mask + unsigned short int SevenSlotMask2; // port 2 7th group Slot Mask + unsigned short int EightSlotMask2; // port 2 8th group Slot Mask + + GpakSlotCfg_t SlotsSelect3; // port 3 Slot selection + unsigned short int FirstBlockNum3; // port 3 first group Block Number + unsigned short int FirstSlotMask3; // port 3 first group Slot Mask + unsigned short int SecBlockNum3; // port 3 second group Block Number + unsigned short int SecSlotMask3; // port 3 second group Slot Mask + GpakSerWordSize_t SerialWordSize3; // port 3 serial word size + GpakCompandModes CompandingMode3; // port 3 companding mode + GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity + GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity + GpakSerClockPol_t TxClockPolarity3; // port 3 Tx Clock Polarity + GpakSerClockPol_t RxClockPolarity3; // port 3 Rx Clock Polarity + GpakSerDataDelay_t TxDataDelay3; // port 3 Tx data delay + GpakSerDataDelay_t RxDataDelay3; // port 3 Rx data delay + GpakActivation DxDelay3; // port 3 DX Delay + + unsigned short int ThirdSlotMask3; // port 3 3rd group Slot Mask + unsigned short int FouthSlotMask3; // port 3 4th group Slot Mask + unsigned short int FifthSlotMask3; // port 3 5th group Slot Mask + unsigned short int SixthSlotMask3; // port 3 6th group Slot Mask + unsigned short int SevenSlotMask3; // port 3 7th group Slot Mask + unsigned short int EightSlotMask3; // port 3 8th group Slot Mask + +} GpakPortConfig_t; + +/* Definition of a Tone Generation Parameter Structure */ +/* +typedef struct +{ + GpakToneGenType_t ToneType; // Tone Type + unsigned short int Frequency[4]; // Frequency (Hz) + short int Level[4]; // Frequency's Level (1 dBm) + unsigned short int OnTime[4]; // On Times (msecs) + unsigned short int OffTime[4]; // Off Times (msecs) +} GpakToneGenParms_t; +*/ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakConfigureChannel return status. */ +typedef enum { + CcsSuccess = 0, /* Channel Configured successfully */ + CcsParmError = 1, /* Channel Config Parameter error */ + CcsInvalidChannel = 2, /* invalid channel */ + CcsInvalidDsp = 3, /* invalid DSP */ + CcsDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakConfigChanStatus_t; + +/* + * gpakConfigureChannel - Configure a DSP's Channel. + * + * FUNCTION + * This function configures a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakConfigChanStatus_t gpakConfigureChannel(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakChanType ChannelType, // channel type + GpakChannelConfig_t * pChanConfig, // pointer to channel config info + GPAK_ChannelConfigStat_t * pStatus // pointer to Channel Config Status + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakTearDownChannel return status. */ +typedef enum { + TdsSuccess = 0, /* Channel Tear Down successful */ + TdsError = 1, /* Channel Tear Down error */ + TdsInvalidChannel = 2, /* invalid channel */ + TdsInvalidDsp = 3, /* invalid DSP */ + TdsDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakTearDownStatus_t; + +/* + * gpakTearDownChannel - Tear Down a DSP's Channel. + * + * FUNCTION + * This function tears down a DSP's Channel. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +extern gpakTearDownStatus_t gpakTearDownChannel(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GPAK_TearDownChanStat_t * pStatus // pointer to Tear Down Status + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakAlgControl return status. */ +typedef enum { + AcSuccess = 0, /* control successful */ + AcInvalidChannel = 1, /* invalid channel identifier */ + AcInvalidDsp = 2, /* invalid DSP */ + AcParmError = 3, /* invalid control parameter */ + AcDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakAlgControlStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAlgControl - Control an Algorithm. + * + * FUNCTION + * This function controls an Algorithm + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakAlgControlStat_t gpakAlgControl(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakAlgCtrl_t ControlCode, // algorithm control code + GPAK_AlgControlStat_t * pStatus // pointer to return status + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakConfigurePorts return status. */ +typedef enum { + CpsSuccess = 0, /* Serial Ports configured successfully */ + CpsParmError = 1, /* Configure Ports Parameter error */ + CpsInvalidDsp = 2, /* invalid DSP */ + CpsDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakConfigPortStatus_t; + +/* + * gpakConfigurePorts - Configure a DSP's serial ports. + * + * FUNCTION + * This function configures a DSP's serial ports. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakConfigPortStatus_t gpakConfigurePorts(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakPortConfig_t * pPortConfig, // pointer to Port Config info + GPAK_PortConfigStat_t * pStatus // pointer to Port Config Status + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakDownloadDsp return status. */ +typedef enum { + GdlSuccess = 0, /* DSP download successful */ + GdlFileReadError = 1, /* error reading Download file */ + GdlInvalidFile = 2, /* invalid Download file content */ + GdlInvalidDsp = 3, /* invalid DSP */ + GdlDspCommFailure = 4 /* failed to communicate with DSP */ +} gpakDownloadStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakDownloadLoader - Download the DSP's Loader program. + * + * FUNCTION + * This function reads the DSP's Loader program from the specified file and + * writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +extern gpakDownloadStatus_t gpakDownloadLoader(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MaxDSPCores-1) */ + GPAK_FILE_ID FileId /* G.PAK Loader program File Identifier */ + ); + +/* + * gpakDownloadDsp - Download a DSP's Program and initialized Data memory. + * + * FUNCTION + * This function reads a DSP's Program and Data memory image from the + * specified file and writes the image to the DSP's memory. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +extern gpakDownloadStatus_t gpakDownloadDsp_5510(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GPAK_FILE_ID FileId // G.PAK download file identifier + ); + +extern gpakDownloadStatus_t gpakDownloadDsp_5507(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GPAK_FILE_ID FileId // G.PAK download file identifier + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* gpakReadEventFIFOMessage return status */ +typedef enum { + RefEventAvail = 0, /* an event was successfully read from the fifo */ + RefNoEventAvail = 1, /* no event was in the fifo */ + RefInvalidDsp = 2, /* invalid DSP identifier */ + RefInvalidEvent = 3, /* invalid event */ + RefDspCommFailure = 4 /* error communicating with DSP */ +} gpakReadEventFIFOMessageStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadEventFIFOMessage - read from the event fifo + * + * FUNCTION + * This function reads a single event from the event fifo if one is available + * + * RETURNS + * Status code indicating success or a specific error. + * + * Note: This function should be called in a loop until the return status + * indicates that the fifo is empty. + */ +extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(struct rxt1_card_t *rxt1_card, // Card containing the DSP + unsigned short int DspId, // DSP identifier + unsigned short int *pChannelId, // pointer to channel identifier + GpakAsyncEventCode_t * pEventCode, // pointer to Event Code + GpakAsyncEventData_t * pEventData // pointer to Event Data Struct + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakPingDsp return status values */ +typedef enum { + PngSuccess = 0, /* DSP responded successfully */ + PngInvalidDsp = 1, /* invalid DSP identifier */ + PngDspCommFailure = 2 /* error communicating with DSP */ +} gpakPingDspStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakPingDsp - ping the DSP to see if it's alive + * + * FUNCTION + * This function checks if the DSP is still communicating with the host + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakPingDspStat_t gpakPingDsp(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pDspSwVersion // DSP software version + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakSerialTxFixedValue return status values */ +typedef enum { + TfvSuccess = 0, /* operation successful */ + TfvInvalidChannel = 1, /* invalid channel identifier */ + TfvInvalidDsp = 2, /* invalid DSP identifier */ + TfvDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakSerialTxFixedValueStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakSerialTxFixedValue - transmit a fixed value on a timeslot + * + * FUNCTION + * This function controls transmission of a fixed value out onto a serial + * port's timeslot. + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int ChannelId, // channel identifier + GpakSerialPort_t PcmOutPort, // PCM Output Serial Port Id + unsigned short int PcmOutSlot, // PCM Output Time Slot + unsigned short int Value, // 16-bit value + GpakActivation State // activation state + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakControlTdmLoopBack return status values */ +typedef enum { + ClbSuccess = 0, /* operation successful */ + ClbSerPortInactive = 1, /* serial port is inactive */ + ClbInvalidDsp = 2, /* invalid DSP identifier */ + ClbDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakControlTdmLoopBackStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakControlTdmLoopBack - control a serial port's loopback state + * + * FUNCTION + * This function enables/disables the tdm input to output looback mode on a + * serial port + * + * RETURNS + * Status code indicating success or a specific error. + */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + GpakSerialPort_t SerialPort, // Serial Port Id + GpakActivation LoopBackState // Loopback State + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakReadCpuUsage return status values */ +typedef enum { + RcuSuccess = 0, /* operation successful */ + RcuInvalidDsp = 1, /* invalid DSP identifier */ + RcuDspCommFailure = 2 /* communication failure */ +} gpakReadCpuUsageStat_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadCpuUsage - read the cpu usage statistics + * + * FUNCTION + * This function reads cpu utilization from the DSP. + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakReadCpuUsageStat_t gpakReadCpuUsage(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pPeakUsage, // pointer to peak usage variable + unsigned short int *pPrev1SecPeakUsage // peak usage over previous 1 second + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakResetCpuUsageStats return status values */ +typedef enum { + RstcSuccess = 0, /* operation successful */ + RstcInvalidDsp = 1, /* invalid DSP identifier */ + RstcDspCommFailure = 2 /* communication failure */ +} gpakResetCpuUsageStat_t; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetCpuUsageStats - reset the cpu usage statistics + * + * FUNCTION + * This function resets the cpu utilization statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakReadFramingStats return status values */ +typedef enum { + RfsSuccess = 0, /* operation successful */ + RfsInvalidDsp = 1, /* invalid DSP identifier */ + RfsDspCommFailure = 2 /* communication failure */ +} gpakReadFramingStatsStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFramingStats + * + * FUNCTION + * This function reads a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakReadFramingStatsStatus_t gpakReadFramingStats(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, // DSP identifier + unsigned short int *pFramingError1Count, // port 1 Framing error count + unsigned short int *pFramingError2Count, // port 2 Framing error count + unsigned short int *pFramingError3Count, // port 3 Framing error count + unsigned short int *pDmaStopErrorCount, // DMA-stoppage error count + unsigned short int *pDmaSlipStatsBuffer // DMA slips count + ); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + +/* gpakResetFramingStats return values */ +typedef enum { + RstfSuccess = 0, /* operation successful */ + RstfInvalidDsp = 1, /* invalid DSP identifier */ + RstfDspCommFailure = 2 /* communication failure */ +} gpakResetFramingStatsStatus_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - reset a DSP's framing interrupt statistics + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ +extern gpakResetFramingStatsStatus_t gpakResetFramingStats(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId // DSP identifier + ); + + +typedef enum { + RmmSuccess = 0, + RmmInvalidDsp = 1, + RmmSizeTooBig = 2, + RmmFailure = 3, + RmmInvalidAddress = 4 +} gpakReadDSPMemoryStat_t; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakResetFramingStats - read a section of DSP memory + * to get access DSP registers, since 0x00--0x60 not HPI-accessable + * + * FUNCTION + * This function resets a DSP's framing interrupt statistics + * + * RETURNS + * Status code indicating success or a specific error. + */ + +extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(struct rxt1_card_t *rxt1_card, // Card containing the DSP + unsigned short int DspId, // Dsp Identifier + unsigned short int *pDest, // Buffer on host to hold DSP memory map + DSP_ADDRESS BufrBaseAddress, // DSP memory users want to read out + unsigned short int MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word + ); + +#endif // end multiple inclusion diff --git drivers/dahdi/rhino/rxt1/GpakCust.c drivers/dahdi/rhino/rxt1/GpakCust.c new file mode 100644 index 0000000..1c9e21f --- /dev/null +++ drivers/dahdi/rhino/rxt1/GpakCust.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakCust.c + * + * Description: + * This file contains host system dependent functions to support generic + * G.PAK API functions. The file is integrated into the host processor + * connected to C55x G.PAK DSPs via a Host Port Interface. + * + * Note: This file needs to be modified by the G.PAK system integrator. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + +#include "GpakCust.h" +#include "rxt1.h" +#include + +void __rxt1_card_wait_hpi(struct rxt1_card_t *rxt1_card, __u8 flags) +{ + __u8 temp; + int loops; + int bus_sel; + static int debug_limit = 0; + + bus_sel = (HPI_SEL | DSP_RST) & __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC); + if (bus_sel != (HPI_SEL | DSP_RST)) + printk("r%dt1: Locking Error %x\n", rxt1_card->numspans, bus_sel); + + if (!(rxt1_card->hpi_fast)) { + temp = (__u8) (__rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIRDX_STAT) >> 16); + if (debug_limit < 100) { + debug_limit++; + } + for (loops = 0; loops < 200; loops++) { + temp = + (__u8) (__rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIRDX_STAT) >> + 16); + + if ((temp & flags) == flags) { + return; + } + } + } + return; +} + +void __rxt1_card_hpic_set(struct rxt1_card_t *rxt1_card, __u16 hpic_data) +{ + __rxt1_card_pci_out(rxt1_card, RXT1_DSP_HPIC + TARG_REGS, (__u32) (hpic_data), 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); +} + +void rxt1_card_hpic_set(struct rxt1_card_t *rxt1_card, __u16 hpic_data) +{ + unsigned int hpi_lock; + hpi_lock = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, + ((hpi_lock & ~0x1F) | HPI_SEL | DSP_RST), 0); + __rxt1_card_hpic_set(rxt1_card, hpic_data); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, hpi_lock, 0); +} + +void rxt1_card_dsp_set(struct rxt1_card_t *rxt1_card, __u32 dsp_address, __u16 dsp_data) +{ + __u32 u_nib; + unsigned int hpi_lock; + unsigned long flags; + __u32 hcs; + + spin_lock_irqsave(&rxt1_card->reglock, flags); + hcs = 1 << rxt1_card->dsp_sel; + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, hcs, 0); + + hpi_lock = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, + ((hpi_lock & ~0x1F) | HPI_SEL | DSP_RST), 0); + + if (rxt1_card->dsp_type == DSP_5510) { + u_nib = ((dsp_address & 0xf0000) >> 16); + if (!(rxt1_card->hpi_xadd[rxt1_card->dsp_sel] == u_nib)) { + + rxt1_card->hpi_xadd[rxt1_card->dsp_sel] = u_nib; + + __rxt1_card_pci_out(rxt1_card, RXT1_DSP_HPIC + TARG_REGS, RXT1_XADD, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + __rxt1_card_pci_out(rxt1_card, RXT1_HPIA + TARG_REGS, u_nib, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + __rxt1_card_pci_out(rxt1_card, RXT1_DSP_HPIC + TARG_REGS, 0, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + + } + } + + __rxt1_card_pci_out(rxt1_card, RXT1_HPIA + TARG_REGS, dsp_address, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + + __rxt1_card_pci_out(rxt1_card, RXT1_HPID + TARG_REGS, dsp_data, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, hpi_lock, 0); + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, 0, 0); + + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + + return; +} + +__u16 rxt1_card_dsp_get(struct rxt1_card_t * rxt1_card, __u32 dsp_address) +{ + __u32 dsp_data; + __u32 u_nib; + unsigned int hpi_lock; + unsigned long flags; + __u32 hcs; + + spin_lock_irqsave(&rxt1_card->reglock, flags); + hcs = 1 << rxt1_card->dsp_sel; + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, hcs, 0); + + hpi_lock = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, + ((hpi_lock & ~0x1F) | HPI_SEL | DSP_RST), 0); + + if (rxt1_card->dsp_type == DSP_5510) { + + u_nib = ((dsp_address & 0xf0000) >> 16); + + if (!(rxt1_card->hpi_xadd[rxt1_card->dsp_sel] == u_nib)) { + rxt1_card->hpi_xadd[rxt1_card->dsp_sel] = u_nib; + + __rxt1_card_pci_out(rxt1_card, RXT1_DSP_HPIC + TARG_REGS, RXT1_XADD, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + __rxt1_card_pci_out(rxt1_card, RXT1_HPIA + TARG_REGS, u_nib, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + __rxt1_card_pci_out(rxt1_card, RXT1_DSP_HPIC + TARG_REGS, 0, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + + } + } + + __rxt1_card_pci_out(rxt1_card, RXT1_HPIA + TARG_REGS, dsp_address, 0); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + dsp_data = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPID); + __rxt1_card_wait_hpi(rxt1_card, RXT1_HRDY); + dsp_data = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIRDX); + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, hpi_lock, 0); + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, 0, 0); + + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + + return dsp_data & 0xFFFF; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadDspMemory - Read DSP memory. + * + * FUNCTION + * This function reads a contiguous block of words from DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +void gpakReadDspMemory(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to read */ + DSP_WORD * pWordValues /* pointer to array of word values variable */ + ) +{ + + unsigned int word_num; + + if (!rxt1_card) { + printk("r%dt1: gpakReadDspMemory: No iface exists for DSP number %d\n", + rxt1_card->numspans, DspId); + return; + } + + /* read NumWords from auto increment data register */ + for (word_num = 0; word_num < NumWords; word_num++) { + pWordValues[word_num] = rxt1_card_dsp_get(rxt1_card, DspAddress + word_num); + } + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteDspMemory - Write DSP memory. + * + * FUNCTION + * This function writes a contiguous block of words to DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +void gpakWriteDspMemory(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to write */ + DSP_WORD * pWordValues /* pointer to array of word values to write */ + ) +{ + + unsigned int word_num; + + if (!rxt1_card) { + printk("r%dt1: gpakWriteDspMemory: No iface exists for DSP number %d\n", + rxt1_card->numspans, DspId); + return; + } + + /* read NumWords from auto increment data register */ + for (word_num = 0; word_num < NumWords; word_num++) { + rxt1_card_dsp_set(rxt1_card, DspAddress + word_num, pWordValues[word_num]); + } + + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakHostDelay - Delay for a fixed time interval. + * + * FUNCTION + * This function delays for a fixed time interval before returning. The time + * interval is the Host Port Interface sampling period when polling a DSP for + * replies to command messages. + * + * RETURNS + * nothing + * + */ +void gpakHostDelay(void) +{ + msleep(5); + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakLockAccess(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ) +{ + return; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakUnlockAccess(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ) +{ + return; +} + +extern const unsigned char _binary_GpakDsp_fw_start[]; +extern const unsigned int _binary_GpakDsp_fw_size; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFile - Read a block of bytes from a G.PAK Download file. + * + * FUNCTION + * This function reads a contiguous block of bytes from a G.PAK Download file + * starting at the current file position. + * + * RETURNS + * The number of bytes read from the file. + * -1 indicates an error occurred. + * 0 indicates all bytes have been read (end of file) + * + */ + + +int gpakReadFile_5510(struct rxt1_card_t *rxt1_card, /* Card containing the DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ) +{ + static int stats = 0; + int core_num; + int byte_num = -1; + int DspId; + static unsigned int file_pos[MAX_DSP_CORES]; + static unsigned int file_size; + + if (!(stats)) { + stats++; + for (core_num = 0; core_num < MAX_DSP_CORES; core_num++) { + file_pos[core_num] = 0; + } + + file_size = (unsigned int) &_binary_GpakDsp_fw_size; + + printk("r%dt1 %d: G168 DSP App file size = %d %x\n", rxt1_card->numspans, + rxt1_card->num + 1, file_size, file_size); + } + + DspId = rxt1_card->dsp_sel + rxt1_card->num * 4; + + for (byte_num = 0; byte_num < NumBytes; byte_num++) { + if ((file_size - 1) >= file_pos[DspId]) { + pBuffer[byte_num] = _binary_GpakDsp_fw_start[file_pos[DspId]++]; + } + } + + return byte_num; +} diff --git drivers/dahdi/rhino/rxt1/GpakCust.h drivers/dahdi/rhino/rxt1/GpakCust.h new file mode 100644 index 0000000..589a2da --- /dev/null +++ drivers/dahdi/rhino/rxt1/GpakCust.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: GpakCust.h + * + * Description: + * This file contains host system dependent definitions and prototypes of + * functions to support generic G.PAK API functions. The file is used when + * integrating G.PAK API functions in a specific host processor environment. + * + * Note: This file may need to be modified by the G.PAK system integrator. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + + +#ifndef _GPAKCUST_H /* prevent multiple inclusion */ +#define _GPAKCUST_H + +#include "GpakApi.h" + + +/* Host and DSP system dependent related definitions. */ +#define MAX_DSP_CORES 16 /* maximum number of DSP cores */ +#define MAX_CHANNELS 48 /* maximum number of channels */ +#define MAX_WAIT_LOOPS 50 /* max number of wait delay loops */ +#define DSP_IFBLK_ADDRESS 0x0100 /* DSP address of I/F block pointer */ +#define DOWNLOAD_BLOCK_SIZE 512 /* download block size (DSP words) */ + +#define loader_file 0 /* GPAK_FILE_ID for bootloader */ +#define app_file 1 /* GPAK_FILE_ID for application */ +#define num_files 2 + +extern void rxt1_card_wait_hpi(struct rxt1_card_t *rxt1_card, __u8 flags); + +extern void rxt1_card_dsp_set(struct rxt1_card_t *rxt1_card, __u32 dsp_address, + __u16 dsp_data); + +extern __u16 rxt1_card_dsp_get(struct rxt1_card_t *rxt1_card, __u32 dsp_address); + +extern void rxt1_card_hpic_set(struct rxt1_card_t *rxt1_card, __u16 hpic_data); + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadDspMemory - Read DSP memory. + * + * FUNCTION + * This function reads a contiguous block of words from DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +extern void gpakReadDspMemory(struct rxt1_card_t *rxt1_card, /* Card containing DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to read */ + DSP_WORD * pWordValues /* pointer to array of word values variable */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteDspMemory - Write DSP memory. + * + * FUNCTION + * This function writes a contiguous block of words to DSP memory starting at + * the specified address. + * + * RETURNS + * nothing + * + */ +extern void gpakWriteDspMemory(struct rxt1_card_t *rxt1_card, /* Card containing DSP */ + unsigned short int DspId, /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + DSP_ADDRESS DspAddress, /* DSP's memory address of first word */ + unsigned int NumWords, /* number of contiguous words to write */ + DSP_WORD * pWordValues /* pointer to array of word values to write */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakHostDelay - Delay for a fixed time interval. + * + * FUNCTION + * This function delays for a fixed time interval before returning. The time + * interval is the Host Port Interface sampling period when polling a DSP for + * replies to command messages. + * + * RETURNS + * nothing + * + */ +extern void gpakHostDelay(void); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +extern void gpakLockAccess(struct rxt1_card_t *rxt1_card, /* Card containing DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +extern void gpakUnlockAccess(struct rxt1_card_t *rxt1_card, /* Card containing DSP */ + unsigned short int DspId /* DSP Identifier (0 to MAX_DSP_CORES-1) */ + ); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadFile - Read a block of bytes from a G.PAK Download file. + * + * FUNCTION + * This function reads a contiguous block of bytes from a G.PAK Download file + * starting at the current file position. + * + * RETURNS + * The number of bytes read from the file. + * -1 indicates an error occurred. + * 0 indicates all bytes have been read (end of file) + * + */ +extern int gpakReadFile_5510(struct rxt1_card_t *rxt1_card, /* Card containing DSP */ + GPAK_FILE_ID FileId, /* G.PAK Download File Identifier */ + unsigned char *pBuffer, /* pointer to buffer for storing bytes */ + unsigned int NumBytes /* number of bytes to read */ + ); + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rxt1/GpakErrs.h drivers/dahdi/rhino/rxt1/GpakErrs.h new file mode 100644 index 0000000..c60ba12 --- /dev/null +++ drivers/dahdi/rhino/rxt1/GpakErrs.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc. + * + * File Name: GpakErrs.h + * + * Description: + * This file contains DSP reply status codes used by G.PAK API functions to + * indicate specific errors. + * + * Version: 1.0 + * + * Revision History: + * 10/17/01 - Initial release. + * 07/03/02 - Updates for conferencing. + * 06/15/04 - Tone type updates. + * + */ + +#ifndef _GPAKERRS_H /* prevent multiple inclusion */ +#define _GPAKERRS_H + +/* Configure Serial Ports reply status codes. */ +typedef enum { + Pc_Success = 0, /* serial ports configured successfully */ + Pc_ChannelsActive = 1, /* unable to configure while channels active */ + Pc_TooManySlots1 = 2, /* too many slots selected for port 1 */ + Pc_InvalidBlockCombo1 = 3, /* invalid combination of blocks for port 1 */ + Pc_NoSlots1 = 4, /* no slots selected for port 1 */ + Pc_InvalidSlots1 = 5, /* invalid slot (> max) selected for port 1 */ + Pc_TooManySlots2 = 6, /* too many slots selected for port 2 */ + Pc_InvalidBlockCombo2 = 7, /* invalid combination of blocks for port 2 */ + Pc_NoSlots2 = 8, /* no slots selected for port 2 */ + Pc_InvalidSlots2 = 9, /* invalid slot (> max) selected for port 2 */ + Pc_TooManySlots3 = 10, /* too many slots selected for port 3 */ + Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */ + Pc_NoSlots3 = 12, /* no slots selected for port 3 */ + Pc_InvalidSlots3 = 13 /* invalid slot (> max) selected for port 3 */ +} GPAK_PortConfigStat_t; + +/* Configure Channel reply status codes. */ +typedef enum { + Cc_Success = 0, /* channel configured successfully */ + Cc_InvalidChannelType = 1, /* invalid Channel Type */ + Cc_InvalidChannel = 2, /* invalid Channel A Id */ + Cc_ChannelActiveA = 3, /* Channel A is currently active */ + Cc_InvalidInputPortA = 4, /* invalid Input A Port */ + Cc_InvalidInputSlotA = 5, /* invalid Input A Slot */ + Cc_BusyInputSlotA = 6, /* busy Input A Slot */ + Cc_InvalidOutputPortA = 7, /* invalid Output A Port */ + Cc_InvalidOutputSlotA = 8, /* invalid Output A Slot */ + Cc_BusyOutputSlotA = 9, /* busy Output A Slot */ + Cc_InvalidInputPortB = 10, /* invalid Input B Port */ + Cc_InvalidInputSlotB = 11, /* invalid Input B Slot */ + Cc_BusyInputSlotB = 12, /* busy Input B Slot */ + Cc_InvalidPktInCodingA = 13, /* invalid Packet In A Coding */ + Cc_InvalidPktOutCodingA = 14, /* invalid Packet Out A Coding */ + Cc_InvalidPktInSizeA = 15, /* invalid Packet In A Frame Size */ + Cc_InvalidPktOutSizeA = 16, /* invalid Packet Out A Frame Size */ + + Cc_ChanTypeNotConfigured = 21, /* channel type was not configured */ + Cc_InsuffECResources = 22, /* insufficient ecan resources avail. */ + Cc_InsuffTDMResources = 23, /* insufficient tdm block resources avail. */ + + Cc_InsuffPktBufResources = 25, /* insufficient pkt buffer resources avail. */ + Cc_InsuffPcmBufResources = 26, /* insufficient pcm buffer resources avail. */ + + Cc_BadPcmEcNlpType = 30, /* invalid EC Nlp type */ + Cc_BadPcmEcTapLength = 31, /* invalid EC tap length */ + Cc_BadPcmEcDblTalkThresh = 32, /* invalid EC double-talk threshold */ + Cc_BadPcmEcNlpThreshold = 33, /* invalid EC Nlp threshold */ + Cc_BadPcmEcCngThreshold = 34, /* invalid EC Cng threshold */ + Cc_BadPcmEcAdaptLimit = 35, /* invalid EC Adapt Limit */ + Cc_BadPcmEcCrossCorrLim = 36, /* invalid EC Cross Correlation Limit */ + Cc_BadPcmEcNumFirSegs = 37, /* invalid EC Number of FirSegments */ + Cc_BadPcmEcFirSegLen = 38, /* invalid EC Fir Segment Length */ + + //Cc_InvalidNumEcsEnabled = 48, /* more than 1 Ec enabled on channel */ + Cc_InvalidFrameRate = 49, /* invalid gpak frame rate */ + Cc_InvalidSoftCompand = 50 /* invalid softCompanding type */ +} GPAK_ChannelConfigStat_t; + +/* Tear Down Channel reply status codes. */ +typedef enum { + Td_Success = 0, /* channel torn down successfully */ + Td_InvalidChannel = 1, /* invalid Channel Id */ + Td_ChannelNotActive = 2 /* channel is not active */ +} GPAK_TearDownChanStat_t; + + +typedef enum { + Ac_Success = 0, /* algorithm control is successfull */ + Ac_InvalidChannel = 1, /* invalid channel identifier */ + Ac_InvalidCode = 2, /* invalid algorithm control code */ + Ac_ECNotEnabled = 3, /* echo canceller was not allocated */ + Ac_InvalidSoftComp = 4 /* invalid softcompanding, 'cause serial port not in companding mode */ +} GPAK_AlgControlStat_t; + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rxt1/GpakExts.h drivers/dahdi/rhino/rxt1/GpakExts.h new file mode 100644 index 0000000..ece1703 --- /dev/null +++ drivers/dahdi/rhino/rxt1/GpakExts.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2001, Adaptive Digital Technologies, Inc. + * + * File Name: GpakExts.h + * + * Description: + * This file contains G.PAK external data and function declarations. + * + * Version: 1.0 + * + * Revision History: + * 11/13/01 - Initial release. + * + */ + +#ifndef _GPAKEXTS_H /* prevent multiple inclusion */ +#define _GPAKEXTS_H + +#include "GpakEnum.h" +#include "sysconfig.h" + + +// Definition of System Configuration related constants and variables. +extern sysConfig_t sysConfig; // System Configuration Info +extern struct chanInfo *chanTable[]; // pointers to Channel structures + +// work input/output buffers +extern USHORT inWork_10msec[]; +extern USHORT outWork_10msec[]; +extern USHORT ECFarWork_10msec[]; + +extern USHORT inWork_2msec[]; +extern USHORT outWork_2msec[]; +extern USHORT ECFarWork_2msec[]; + +extern USHORT inWork_1msec[]; +extern USHORT outWork_1msec[]; +extern USHORT ECFarWork_1msec[]; + +// Echo Canceller scratch memory. +extern USHORT G168SAscratch_10ms[]; // G.168 SARAM scratch for 10 msec task +extern USHORT G168DAscratch_10ms[]; // G.168 DARAM scratch for 10 msec task + +extern USHORT G168SAscratch_2ms[]; // G.168 SARAM scratch for 2 msec task +extern USHORT G168DAscratch_2ms[]; // G.168 DARAM scratch for 2 msec task + +extern USHORT G168SAscratch_1ms[]; // G.168 SARAM scratch for 1 msec task +extern USHORT G168DAscratch_1ms[]; // G.168 DARAM scratch for 1 msec task + + +// Pointers to Echo Canceller data structures. +extern USHORT *pPcmEcDaState[]; // pntr to PCM EC DA States +extern USHORT *pPcmEcSaState[]; // pntr to PCM EC SA States +extern USHORT *pPcmEcEchoPath[]; // pntr to PCM EC Echo Paths +extern USHORT *pPcmEcBackEp[]; // pntr to PCM EC Background Echo Paths +extern USHORT *pPcmEcBackFar[]; // pntr to PCM EC Background Nears +extern USHORT *pPcmEcBackNear[]; // pntr to PCM EC Background Fars +extern USHORT *pPktEcDaState[]; // pntr to Pkt EC DA States +extern USHORT *pPktEcSaState[]; // pntr to Pkt EC SA States +extern USHORT *pPktEcEchoPath[]; // pntr to Pkt EC Echo Paths +extern USHORT *pPktEcBackEp[]; // pntr to Pkt EC Background Echo Paths +extern USHORT *pPktEcBackFar[]; // pntr to Pkt EC Background Nears +extern USHORT *pPktEcBackNear[]; // pntr to Pkt EC Background Fars + +extern sysConfig_t sysConfig; +extern struct chanInfo *chanTable[]; + +extern USHORT DmaLoopback[]; // DMA Loopback flag for each port +extern USHORT NumCfgSlots[]; // num time slots configured on McBSP +extern USHORT McRcvChanEnabA[]; // McBSP's Rcv Chan Enable A reg val +extern USHORT McRcvChanEnabB[]; // McBSP's Rcv Chan Enable B reg val +extern USHORT McXmtChanEnabA[]; // McBSP's Xmt Chan Enable A reg val +extern USHORT McXmtChanEnabB[]; // McBSP's Xmt Chan Enable B reg val + + +extern USHORT BSP0DMA_TxBuffer[]; // DMA Transmit buffer for McBSP0 +extern USHORT BSP0DMA_RxBuffer[]; // DMA Receive buffer for McBSP0 +extern USHORT BSP1DMA_TxBuffer[]; // DMA Transmit buffer for McBSP1 +extern USHORT BSP1DMA_RxBuffer[]; // DMA Receive buffer for McBSP1 +extern USHORT BSP2DMA_TxBuffer[]; // DMA Transmit buffer for McBSP2 +extern USHORT BSP2DMA_RxBuffer[]; // DMA Receive buffer for McBSP2 +extern chanInfo_t GpakChanInstance[]; + + + + +extern USHORT PcmInBufferPool[]; +extern USHORT PcmOutBufferPool[]; +extern USHORT PcmBInBufferPool[]; +extern USHORT PcmBOutBufferPool[]; +extern CircBufInfo_t PcmBOutCircInfo[]; +extern CircBufInfo_t PcmBInCircInfo[]; + +// System status variables. +extern USHORT NumActiveChannels; // number of active channels +// Echo Canceller management variables. +extern USHORT NumPcmEcansUsed; // number of PCM Echo Cancellers in use +extern USHORT PcmEcInUse[]; // flag indicating PCM Echo Canceller in use + +// Echo Canceller management variables. +extern USHORT *pPcmEcChan[]; // pointer to PCM Echo Canceller channels +extern USHORT *pPktEcChan[]; // pointer to Packet Echo Canceller channels + +extern chanInfo_t GpakChanInstance[]; +extern CPG_Instance_t ToneGenInstance[]; +extern CPG_Params_t CPGParms[]; +extern G168Params_t EcParmsA[]; +extern G168Params_t EcParmsB[]; + +// Definition of function prototypes and their return values. + +// Initialize G.PAK interface with host processor. +extern void InitGpakInterface(void); + +// Initialize G.PAK PCM I/O. +extern void InitGpakPcm(void); + +// Initialize G.PAK Framing task data. +extern void InitFrameTasks(void); + +// Initialize a G.PAK channel's Channel structure. +extern struct chanInfo *initChanStruct(USHORT * saramBlock, // pointer to channel's SARAM memory block + USHORT * daramBlock, // pointer to channel's DARAM memory block + USHORT channelId // channels Id + ); + +// ConfigureGpakPcm return status. +typedef enum { + SPCSuccess, // serial ports configured successfully + SPCTooManySlots1, // too many slots selected for port 1 + SPCInvalidBlockCombo1, // invalid combination of blocks for port 1 + SPCNoSlots1, // no slots selected for port 1 + SPCInvalidSlots1, // invalid slot (exceeds max) selected for port 1 + SPCTooManySlots2, // too many slots selected for port 2 + SPCInvalidBlockCombo2, // invalid combination of blocks for port 2 + SPCNoSlots2, // no slots selected for port 2 + SPCInvalidSlots2, // invalid slot (exceeds max) selected for port 2 + SPCTooManySlots3, // too many slots selected for port 3 + SPCInvalidBlockCombo3, // invalid combination of blocks for port 3 + SPCNoSlots3, // no slots selected for port 3 + SPCInvalidSlots3 // invalid slot (exceeds max) selected for port 3 +} SPCStatus_t; + +// Configure G.PAK PCM I/O. +extern SPCStatus_t ConfigureGpakPcm(GpakSlotCfg_t SlotsSelect[], // port's Slot selection + USHORT BlockNumber1[], // port's first group Block Number + USHORT SlotMask1[], // port's first group Slot Mask + USHORT BlockNumber2[], // port's second group Block Number + USHORT SlotMask2[] // port's second group Slot Mask + ); + +// Get the address of PCM to Pkt framing rate queue head. +extern chanInfo_t **GetPcmToPktQueueHead(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Get the address of Pkt to PCM framing rate queue head. +extern chanInfo_t **GetPktToPcmQueueHead(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Determine the address of a framing rate phase counter. +extern USHORT *FrameRatePhaseCount(int SamplesPerFrame // samples per frame (framing rate) + ); + +// Adjust Far Echo and Bulk Delay buffer indices. +extern void AdjustFarBulkIndices(int WriteFrameSize, // Bulk writer's frame size (samples per frame) + int ReadFrameSize, // Far reader's frame size (samples per frame) + USHORT * pWrtPhaseCnt, // pointer to Bulk writer's DMA phase count + USHORT * pReadPhaseCnt, // pointer to Far reader's DMA phase count + USHORT BulkDelaySize, // size of Bulk Delay buffer (samples) + USHORT * pBulkPutIndex, // pointer to Bulk Delay buffer's Put index var + USHORT * pFarTakeIndex // pointer to Far Echo buffer's Take index var + ); + +// Enqueue a channel to it's framing rate or conference queues. +extern void EnqueueChannel(chanInfo_t * pChanInfo, // pointer to channel's Channel Info + chanInfo_t ** pPcm2PktHead, // pointer to PCM to Packet queue head + chanInfo_t ** pPkt2PcmHead // pointer to Packet to PCM queue head + ); + +// Dequeue a channel from it's framing rate/conference queues. +extern void DequeueChannel(chanInfo_t * pChanInfo, // pointer to channel's Channel Info + chanInfo_t ** pPcm2PktHead, // pointer to PCM to Packet queue head + chanInfo_t ** pPkt2PcmHead // pointer to Packet to PCM queue head + ); + +// ActivateGpakChannel return status. +typedef enum { + ACSuccess, // channel activated successfully + ACInvalidInputPort1, // invalid Input Port 1 + ACInvalidInputSlot1, // invalid Input Slot 1 + ACBusyInputSlot1, // busy Input Slot 1 + ACInvalidOutputPort1, // invalid Output Port 1 + ACInvalidOutputSlot1, // invalid Output Slot 1 + ACBusyOutputSlot1, // busy Output Slot 1 + ACInvalidInputPort2, // invalid Input Port 2 + ACInvalidInputSlot2, // invalid Input Slot 2 + ACBusyInputSlot2, // busy Input Slot 2 + ACInvalidOutputPort2, // invalid Output Port 2 + ACInvalidOutputSlot2, // invalid Output Slot 2 + ACBusyOutputSlot2 // busy Output Slot 2 +} ACStatus_t; + +// Activate a G.PAK Channel. +extern ACStatus_t ActivateGpakChannel(chanInfo_t * pChanInfo // pointer to Channel Info + ); + +// Deactivate a G.PAK Channel. +extern void DeactivateGpakChannel(chanInfo_t * pChanInfo // pointer to Channel Info + ); + +// Determine if the frame size is valid. +extern int ValidFrameSize(int FrameSize // Frame Size + ); + + +// Copy linear buffer to circular buffer. +extern void copyLinearToCirc(USHORT * src, CircBufInfo_t * dest, USHORT len); + +// Copy circular buffer to linear buffer. +extern void copyCircToLinear(CircBufInfo_t * src, USHORT * dest, USHORT len); + +// Perform VAD, Tone Detect, and Encode functions. +extern void ProcessVadToneEncode(chanInfo_t * pChanInfo, // pointer to Channel Info + USHORT * pInWork, // pointer to input work buffer (contains data) + USHORT * pOutWork // pointer to output work buffer + ); + +// Initialize an Echo Canceller. +extern G168ChannelInstance_t *InitEchoCanceller(USHORT FrameSize, // number of samples per frame + G168Params_t * EcInitParms, // Echo Canceller initialization parameters + short int EcanIndex // variable that stores ecan index + ); + +/* +extern void ToneGenerate( + short int *pToneActive, + short int *pToneUpdate, + CPG_Instance_t *pToneGenPtr, + CPG_Params_t *pToneParms, + short int *pToneData, + GpakToneGenCmd_t ToneCmd, + short int FrameSize + ); +*/ + +extern void algorithmControl(chanInfo_t * pChan // pointer to Channel structure + ); + + +extern void writeTransmitEnables(USHORT McBspId, // McBSP Id + USHORT MaskA, // A Block mask bits to be written + USHORT MaskB // B Block mask bits to be written + ); + +void ResetCpuUsageStats(); + +int validFrameRate(chanInfo_t * pChan, GpakRate_t frameRate); + +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rxt1/GpakHpi.h drivers/dahdi/rhino/rxt1/GpakHpi.h new file mode 100644 index 0000000..abe731b --- /dev/null +++ drivers/dahdi/rhino/rxt1/GpakHpi.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2001, Adaptive Digital Technologies, Inc. + * + * File Name: GpakHpi.h + * + * Description: + * This file contains common definitions related to the G.PAK interface + * between a host processor and a DSP processor via the Host Port Interface. + * + * Version: 1.0 + * + * Revision History: + * 10/17/01 - Initial release. + * + */ + +#ifndef _GPAKHPI_H /* prevent multiple inclusion */ +#define _GPAKHPI_H + + +/* Definition of G.PAK Command/Reply message type codes. */ +#define MSG_NULL_REPLY 0 /* Null Reply (unsupported Command) */ +#define MSG_SYS_CONFIG_RQST 1 /* System Configuration Request */ +#define MSG_SYS_CONFIG_REPLY 2 /* System Configuration Reply */ +#define MSG_READ_SYS_PARMS 3 /* Read System Parameters */ +#define MSG_READ_SYS_PARMS_REPLY 4 /* Read System Parameters Reply */ +#define MSG_WRITE_SYS_PARMS 5 /* Write System Parameters */ +#define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */ +#define MSG_CONFIGURE_PORTS 7 /* Configure Serial Ports */ +#define MSG_CONFIG_PORTS_REPLY 8 /* Configure Serial Ports Reply */ +#define MSG_CONFIGURE_CHANNEL 9 /* Configure Channel */ +#define MSG_CONFIG_CHAN_REPLY 10 /* Configure Channel Reply */ +#define MSG_TEAR_DOWN_CHANNEL 11 /* Tear Down Channel */ +#define MSG_TEAR_DOWN_REPLY 12 /* Tear Down Channel Reply */ +#define MSG_CHAN_STATUS_RQST 13 /* Channel Status Request */ +#define MSG_CHAN_STATUS_REPLY 14 /* Channel Status Reply */ + +#define MSG_TEST_MODE 17 /* Configure/Perform Test Mode */ +#define MSG_TEST_REPLY 18 /* Configure/Perform Test Mode Reply */ + +#define MSG_ALG_CONTROL 27 /* algorithm control */ +#define MSG_ALG_CONTROL_REPLY 28 /* algorithm control reply */ +#define MSG_GET_TXCID_ADDRESS 29 /* get tx cid buffer start address */ +#define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */ + +#define MSG_PING 35 /* ping command */ +#define MSG_PING_REPLY 36 /* ping command reply */ +#define MSG_SERIAL_TXVAL 37 /* transmit serial fixed value */ +#define MSG_SERIAL_TXVAL_REPLY 38 /* transmit serial fixed value reply */ +#define MSG_TDM_LOOPBACK 39 /* tdm loopback control */ +#define MSG_TDM_LOOPBACK_REPLY 40 /* tdm loopback control reply */ +#define MSG_RESET_USAGE_STATS 41 /* reset cpu usage stats */ +#define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */ + +#define MSG_RESET_FRAME_STATS 47 /* reset framing stats */ +#define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */ + +#define MSG_READ_DSP_MEMORY 49 /* read small section of DSP's memory */ +#define MSG_READ_DSP_MEMORY_REPLY 50 /* read memory reply */ +#endif /* prevent multiple inclusion */ diff --git drivers/dahdi/rhino/rxt1/Makefile drivers/dahdi/rhino/rxt1/Makefile new file mode 100644 index 0000000..490983e --- /dev/null +++ drivers/dahdi/rhino/rxt1/Makefile @@ -0,0 +1,12 @@ +obj-m += rxt1.o + +rxt1-objs := rxt1_base.o + +$(obj)/rxt1_base.o: $(src)/rxt1.h $(src)/GpakApi.h $(src)/GpakCust.h + +clean: + @rm -f *.o + @rm -f *.cmd *.o *.ko + @rm -f .*.cmd .*.o + @rm -rf .tmp_versions Module.symvers + @rm -f core diff --git drivers/dahdi/rhino/rxt1/gpakenum.h drivers/dahdi/rhino/rxt1/gpakenum.h new file mode 100644 index 0000000..bb10517 --- /dev/null +++ drivers/dahdi/rhino/rxt1/gpakenum.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2005, Adaptive Digital Technologies, Inc. + * + * File Name: gpakenum.h + * + * Description: + * This file contains common enumerations related to G.PAK application + * software. + * + * Version: 1.0 + * + * Revision History: + * 06/15/05 - Initial release. + * + */ + +#ifndef _GPAKENUM_H /* prevent multiple inclusion */ +#define _GPAKENUM_H + +/* G.PAK Serial Port Word Size */ +typedef enum { + SerWordSize8 = 0, // 8-bit seial word + SerWordSize16 = 1 // 16-bit serial word +} GpakSerWordSize_t; + +/* G.PAK Serial Port FrameSync Polarity */ +typedef enum { + FrameSyncActLow = 0, // active low frame sync signal + FrameSyncActHigh = 1 // active high frame sync signal +} GpakSerFrameSyncPol_t; + +/* G.PAK Serial Port Clock Polarity */ +typedef enum { + SerClockActLow = 0, // active low serial clock + SerClockActHigh = 1 // active high serial clock +} GpakSerClockPol_t; + +/* G.PAK Serial Port Data Delay */ +typedef enum { + DataDelay0 = 0, // no data delay + DataDelay1 = 1, // 1-bit data delay + DataDelay2 = 2 // 2-bit data delay +} GpakSerDataDelay_t; + +/* G.PAK Serial Port Ids. */ +typedef enum { + SerialPortNull = 0, // null serial port + SerialPort1 = 1, // first PCM serial stream port (McBSP0) + SerialPort2 = 2, // second PCM serial stream port (McBSP1) + SerialPort3 = 3 // third PCM serial stream port (McBSP2) +} GpakSerialPort_t; + +/* G.PAK serial port Slot Configuration selection codes. */ +typedef enum { + SlotCfgNone = 0, // no time slots used + SlotCfg2Groups = 2, // 2 groups of 16 time slots used, 32 Channels system + SlotCfg8Groups = 8 // 8-partition mode for 128-channel system +} GpakSlotCfg_t; + +/* G.PAK serial port Companding Mode codes. */ +typedef enum { + cmpPCMU = 0, // u-Law + cmpPCMA = 1, // A-Law + cmpNone = 2 // none +} GpakCompandModes; + +/* G.PAK Active/Inactive selection codes. */ +typedef enum { + Disabled = 0, // Inactive + Enabled = 1 // Active +} GpakActivation; + +/* G.PAK Channel Type codes. */ +typedef enum { + inactive = 0, // channel inactive + tdmToTdm = 1 // tdmToTdm +} GpakChanType; + +/* G.PAK Algorithm control commands */ +typedef enum { + EnableEcanA = 0, // Enable A side echo canceller + BypassEcanA = 1, // Bypass A side echo canceller + ResetEcanA = 2, // Reset A side echo canceller + EnableEcanB = 3, // Enable B side echo canceller + BypassEcanB = 4, // Bypass B side echo canceller + ResetEcanB = 5, // Reset B side echo canceller + + EnableMuLawSwCompanding = 6, // Enable Mu-law Software companding + EnableALawSwCompanding = 7, // Enable Mu-law Software companding + BypassSwCompanding = 8 // Bypass Software companding +} GpakAlgCtrl_t; + +/* G.PAK Tone types. */ +typedef enum { + Null_tone = 0, // no tone detection + DTMF_tone = 1 // DTMF tone +} GpakToneTypes; + +/* G.PAK direction. */ +typedef enum { + TDMAToB = 0, // A to B + TDMBToA = 1 // B to A +} GpakTdmDirection; + + +typedef enum { + rate1ms = 0, + rate2ms = 1, + rate10ms = 2 +} GpakRate_t; + +/* G.PAK Asynchronous Event Codes */ +typedef enum { + EventToneDetect = 0, // Tone detection event + EventDSPDebug = 7 // DSP debug data event +} GpakAsyncEventCode_t; + +/* G.PAK MF Tone Code Indices */ +typedef enum { + DtmfDigit1 = 0, // DTMF Digit 1 + DtmfDigit2 = 1, // DTMF Digit 2 + DtmfDigit3 = 2, // DTMF Digit 3 + DtmfDigitA = 3, // DTMF Digit A + DtmfDigit4 = 4, // DTMF Digit 4 + DtmfDigit5 = 5, // DTMF Digit 5 + DtmfDigit6 = 6, // DTMF Digit 6 + DtmfDigitB = 7, // DTMF Digit B + DtmfDigit7 = 8, // DTMF Digit 7 + DtmfDigit8 = 9, // DTMF Digit 8 + DtmfDigit9 = 10, // DTMF Digit 9 + DtmfDigitC = 11, // DTMF Digit C + DtmfDigitSt = 12, // DTMF Digit * + DtmfDigit0 = 13, // DTMF Digit 0 + DtmfDigitPnd = 14, // DTMF Digit # + DtmfDigitD = 15, // DTMF Digit D + + EndofMFDigit = 100, // End of MF digit + EndofCngDigit = 101 // End of Cng Digit +} GpakToneCodes_t; + +#endif // end multiple inclusion diff --git drivers/dahdi/rhino/rxt1/rxt1.h drivers/dahdi/rhino/rxt1/rxt1.h new file mode 100644 index 0000000..67fdd44 --- /dev/null +++ drivers/dahdi/rhino/rxt1/rxt1.h @@ -0,0 +1,406 @@ +/* + * Rhino RXT1 DUAL - QUAD T1 E1 J1 Interface Driver + * + * Release version 10/10/10 + * + * Written by + * Bob Conklin + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's TE410P Quad-T1/E1 PCI Driver + * Based on previous works, designs, and archetectures conceived and + * written by Jim Dixon , + * and Mark Spencer + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * Copyright (C) 2001-2005, Digium, Inc. + * Copyright (C) 2001 Jim Dixon / Zapata Telephony. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * * * * * * * * * * * * * NO WARRANTY * * * * * * * * * * * * * * * * * + * + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + * + * * * * * * * * * * * * DISCLAIMER OF LIABILITY * * * * * * * * * * * * + * + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _RXT1_H +#define _RXT1_H + +#include + +#include +#include +#include +#include + +#include +#include + +#define addr_t (__u32)(dma_addr_t) + +#define FRMR_TTR_BASE 0x10 +#define FRMR_RTR_BASE 0x0c +#define FRMR_TSEO 0xa0 +#define FRMR_TSBS1 0xa1 +#define FRMR_CCR1 0x09 +#define FRMR_CCR1_ITF 0x08 +#define FRMR_CCR1_EITS 0x10 +#define FRMR_CCR2 0x0a +#define FRMR_CCR2_RCRC 0x04 +#define FRMR_CCR2_RADD 0x10 +#define FRMR_MODE 0x03 +#define FRMR_MODE_NO_ADDR_CMP 0x80 +#define FRMR_MODE_SS7 0x20 +#define FRMR_MODE_HRAC 0x08 +#define FRMR_IMR0 0x14 +#define FRMR_IMR0_RME 0x80 +#define FRMR_IMR0_RPF 0x01 +#define FRMR_IMR1 0x15 +#define FRMR_IMR1_ALLS 0x20 +#define FRMR_IMR1_XDU 0x10 +#define FRMR_IMR1_XPR 0x01 + +#define FRMR_FMR2 0x1e +#define FRMR_XSP 0x21 + +#define FRMR_XC0 0x22 +#define FRMR_XC1 0x23 +#define FRMR_RC0 0x24 +#define FRMR_RC1 0x25 +#define FRMR_IDLE 0x2b + +#define FRMR_ICB1 0x32 +#define FRMR_ICB2 0x33 +#define FRMR_ICB3 0x34 +#define FRMR_ICB4 0x35 +#define FRMR_LIM0 0x36 +#define FRMR_LIM1 0x37 + +#define FRMR_SIC1 0x3e +#define FRMR_SIC2 0x3f +#define FRMR_SIC3 0x40 +#define FRMR_CMR1 0x44 +#define FRMR_CMR2 0x45 +#define FRMR_GCR 0x46 + +#define FRMR_FRS0 0x4c + +#define FRMR_FRS0_LOS 0x80 /* loss of signal */ +#define FRMR_FRS0_AIS 0x40 /* Blue alarma pattern */ +#define FRMR_FRS0_LFA 0x20 /* loss of frame */ +#define FRMR_FRS0_RRA 0x10 /* recieve remote alarm */ + +#define FRMR_FRS0_NMF 0x04 +#define FRMR_FRS0_LMFA 0x02 /* loss of multiframe */ +#define FRMR_FRS0_FSRF 0x01 /* frame search restart */ + +#define FRMR_FRS1 0x4d + +#define FRMR_FRS1_EXZD 0x80 /* excessive zeros */ +#define FRMR_FRS1_PDEN 0x40 /* T1 ** pulse density violation */ +#define FRMR_FRS1_LLBDD 0x10 /* loop down code recieved */ +#define FRMR_FRS1_LLBAD 0x08 /* loop up code recieved */ +#define FRMR_FRS1_XLS 0x02 /* Line shorted -- over current */ +#define FRMR_FRS1_XLO 0x01 /* Line open -- zero current */ + +#define FRMR_FRS1_TS16RA 0x40 /* E1 ** */ +#define FRMR_FRS1_TS16LOS 0x20 /* E1 ** */ +#define FRMR_FRS1_TS16AIS 0x10 /* E1 ** */ +#define FRMR_FRS1_TS16LFA 0x08 /* E1 ** */ + +#define FRMR_ISR0 0x68 +#define FRMR_ISR0_RME 0x80 +#define FRMR_ISR0_RPF 0x01 +#define FRMR_ISR1 0x69 +#define FRMR_ISR1_ALLS 0x20 +#define FRMR_ISR1_XDU 0x10 +#define FRMR_ISR1_XPR 0x01 +#define FRMR_ISR2 0x6a +#define FRMR_ISR3 0x6b +#define FRMR_ISR4 0x6c +#define FRMR_ISR5 0x6d +#define FRMR_ISR6 0xac +#define FRMR_ISR7 0xd8 +#define FRMR_GIS 0x6e +#define FRMR_GIS_ISR0 0x01 +#define FRMR_GIS_ISR1 0x02 +#define FRMR_GIS_ISR2 0x04 +#define FRMR_GIS_ISR3 0x08 +#define FRMR_GIS_ISR4 0x10 +#define FRMR_GIS_ISR5 0x20 +#define FRMR_GIS_ISR6 0x40 +#define FRMR_GIS_ISR7 0x80 +#define FRMR_CIS 0x6f +#define FRMR_CIS_GIS1 0x01 +#define FRMR_CIS_GIS2 0x02 +#define FRMR_CIS_GIS3 0x04 +#define FRMR_CIS_GIS4 0x08 +#define FRMR_CMDR 0x02 +#define FRMR_CMDR_SRES 0x01 +#define FRMR_CMDR_XRES 0x10 +#define FRMR_CMDR_RMC 0x80 +#define FRMR_CMDR_XTF 0x04 +#define FRMR_CMDR_XHF 0x08 +#define FRMR_CMDR_XME 0x02 +#define FRMR_RSIS 0x65 +#define FRMR_RSIS_VFR 0x80 +#define FRMR_RSIS_RDO 0x40 +#define FRMR_RSIS_CRC16 0x20 +#define FRMR_RSIS_RAB 0x10 +#define FRMR_RBCL 0x66 +#define FRMR_RBCL_MAX_SIZE 0x1f +#define FRMR_RBCH 0x67 +#define FRMR_RXFIFO 0x00 +#define FRMR_SIS 0x64 +#define FRMR_SIS_XFW 0x40 +#define FRMR_TXFIFO 0x00 + +#define FRMR_PC1 0x80 +#define FRMR_PC2 0x81 +#define FRMR_PC3 0x82 +#define FRMR_PC4 0x83 +#define FRMR_PC5 0x84 + +#define NUM_REGS 0xa9 +#define NUM_PCI 5 + + +struct rxt1_regs { + unsigned int pci[NUM_PCI]; + unsigned char regs[NUM_REGS]; +}; + +#define RXT1_GET_REGS _IOW (DAHDI_CODE, 60, struct rxt1_regs) + +#define RXT1_REGSTARTB 0x1000 +#define RXT1_REGSTARTW 0x400 +#define TARG_REGS 0x400 +#define RXT1_VERSION 0x0 /* 0x1000 */ +#define RH_VERMASK 0xffff << 16 +#define RXT1_DMA 0x1 /* 0x1004 */ +#define DMA_GO 1 << 0 +#define DMA_ACK 1 << 1 +#define DMA_IMSK 1 << 2 +#define FRMR_IEN 1 << 3 +#define FRMR_ISTAT 1 << 4 +#define FRMR_ACK 1 << 5 +#define FRMR_IMSK 1 << 6 +#define BUFF_PTR 1 << 8 +#define DMA_INT 1 << 9 +#define FRAME_MA 1 << 10 +#define DMA_OVFL 1 << 11 +#define OVFL_FLGS 0xf << 12 +#define DMA_LEN 0xffff << 16 +#define RXT1_RXBUFSTART 0x2 /* 0x1008 */ +#define RXT1_TXBUFSTART 0x3 /* 0x100C */ +#define RXT1_STAT 0x4 /* 0x1010 */ + +#define RXT1_HPIC 0x7 /* 0x101c */ + +#define RXT1_ECA1 0x8 /* 0x1020 */ +#define RXT1_ECB1 0x9 /* 0x1024 */ +#define RXT1_ECA2 0xa /* 0x1028 */ +#define RXT1_ECB2 0xb /* 0x102C */ +#define RXT1_ECA3 0xc /* 0x1030 */ +#define RXT1_ECB3 0xd /* 0x1034 */ +#define RXT1_ECA4 0xe /* 0x1038 */ +#define RXT1_ECB4 0xf /* 0x103c */ + +#define HPI_SEL 1 << 4 +#define EC_ON 1 << 5 +#define DSP_RST 1 << 6 + +#define RXT1_DSP_HPIC 0x10 /* 0x1040 */ +#define RXT1_HPIDAI 0x11 /* 0x1044 */ +#define RXT1_HPIA 0x12 /* 0x1048 */ +#define RXT1_HPID 0x13 /* 0x104C */ + +#define RXT1_HPIRD 0x14 /* 0x1050 */ +#define RXT1_HPIRD_STAT 0x14 /* 0x1052 */ + +#define RXT1_HRDY 1 << 0 +#define RXT1_BUSY_N 2 << 1 +#define RXT1_D_NEW 4 << 2 + +#define RXT1_HPIRDX 0x15 /* 0x1054 */ +#define RXT1_HPIRDX_STAT 0x15 /* 0x1056 */ + +#define RXT1_HCS_REG 0x16 /* 0x1058 */ + +#define RXT1_XLATE1 0x17 /* 0x105c */ +#define RXT1_XLATE2 0x18 /* 0x1060 */ +#define RXT1_XLATE3 0x19 /* 0x1064 */ +#define RXT1_XLATE4 0x1a /* 0x1068 */ + +#define RXT1_BL_GO 1 << 0 +#define RXT1_XADD 1 << 5 + +#define JTAG_TDI 1 << 0 +#define JTAG_TCK 1 << 1 +#define JTAG_TMS 1 << 2 +#define JTAG_ENS 7 << 3 /* 3,4,5 */ +#define JTAG_TDO 1 << 6 +#define STATINIT 0x00777710 +#define FRMR1_STAT 0xf << 8 /* << (8 + span * 4) */ +#define FRMR2_STAT 0xf << 12 +#define FRMR3_STAT 0xf << 16 +#define FRMR4_STAT 0xf << 20 + +#define NORM_OP 0x9 +#define YEL_ALM 0xa +#define NO_CARR 0x7 +#define NO_SYNC 0x8 +#define RECOVER 0xe +#define RLOOP 0xd +#define SPAN_OFF 0xc + +#define RXT1_SIZE 0x14 +#define DSP_5510 1 + +#define MAX_RXT1_CARDS 64 + +struct rxt1_card_t; + +struct rxt1_span_t { + struct rxt1_card_t *owner; + unsigned int *writechunk; /* Double-word aligned write memory */ + unsigned int *readchunk; /* Double-word aligned read memory */ + int spantype; /* card type, T1 or E1 or J1 */ + int sync; + int psync; + int alarmtimer; + int redalarms; + int notclear; + int alarmcount; + int dsp_up; + int spanflags; + int syncpos; + int e1check; /* E1 check */ + struct dahdi_span span; + unsigned char txsigs[16]; /* Transmit sigs */ + int loopupcnt; + int loopdowncnt; + unsigned int ec_chan_id[31]; + unsigned char ec_chunk1[31][DAHDI_CHUNKSIZE]; /* first EC chunk buffer */ + unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; /* second EC chunk buffer */ + int irqmisses; + + /* HDLC controller fields */ + struct dahdi_chan *sigchan; + unsigned char sigmode; + int sigactive; + int frames_out; + int frames_in; + +#ifdef ENABLE_WORKQUEUES + struct work_struct swork; +#endif + struct dahdi_chan *chans[31]; /* Individual channels */ + struct dahdi_echocan_state *ec[31]; /* echocan state for each channel */ +}; + +struct rxt1_card_t { + /* This structure exists one per card */ + struct pci_dev *dev; /* Pointer to PCI device */ + unsigned int intcount; + int num; /* Which card we are */ + int t1e1; /* T1/E1 select pins */ + int globalconfig; /* Whether global setup has been done */ + int syncsrc; /* active sync source */ + struct rxt1_span_t *rxt1_spans[4]; /* Individual spans */ + int numspans; /* Number of spans on the card */ + int hpi_fast; + int hpi_xadd[4]; + int dsp_sel; + int dsp_type; + struct workqueue_struct *dspwq; + struct work_struct dspwork; + unsigned int nextec[4]; + unsigned int currec[4]; + int blinktimer; + int irq; /* IRQ used by device */ + int order; /* Order */ + int flags; /* Device flags */ + int master; /* Are we master */ + int ledreg; /* LED Register */ + int version; /* LED Register */ + unsigned int gpio; + unsigned int gpioctl; + int stopdma; /* Set to stop DMA */ + unsigned int dmactrl; + int e1recover; /* E1 recovery timer */ + dma_addr_t readdma; + dma_addr_t writedma; + unsigned long memaddr; /* Base address of card */ + unsigned long memlen; + volatile unsigned int *membase; /* Base address of card */ + int spansstarted; /* number of spans started */ + spinlock_t reglock; /* lock register access */ + volatile unsigned int *writechunk; /* Double-word aligned write memory */ + volatile unsigned int *readchunk; /* Double-word aligned read memory */ + unsigned short canary; +#ifdef ENABLE_WORKQUEUES + atomic_t worklist; + struct workqueue_struct *workq; +#else +#ifdef ENABLE_TASKLETS + int taskletrun; + int taskletsched; + int taskletpending; + int taskletexec; + int txerrors; + struct tasklet_struct rxt1_tlet; +#endif +#endif + unsigned int passno; /* number of interrupt passes */ + char *variety; + int nextbuf; + int last_jiffie; + int last0; /* for detecting double-missed IRQ */ + int checktiming; /* Set >0 to cause the timing source to be checked */ +}; + +extern unsigned int __rxt1_card_dsp_in(struct rxt1_card_t *rxt1_card, + const unsigned int addr); +extern void __rxt1_card_dsp_out(struct rxt1_card_t *rxt1_card, const unsigned int addr, + const unsigned int value); + +extern unsigned int __rxt1_card_pci_in(struct rxt1_card_t *rxt1_card, + const unsigned int addr); +extern void __rxt1_card_pci_out(struct rxt1_card_t *rxt1_card, const unsigned int addr, + const unsigned int value, const unsigned int mask); + +#endif /* _RXT1_H */ diff --git drivers/dahdi/rhino/rxt1/rxt1_base.c drivers/dahdi/rhino/rxt1/rxt1_base.c new file mode 100644 index 0000000..f209f5e --- /dev/null +++ drivers/dahdi/rhino/rxt1/rxt1_base.c @@ -0,0 +1,4798 @@ +/* + * Rhino RXT1 DUAL - QUAD T1 E1 J1 Interface Driver + * + * Release version 10/10/10 + * + * Written by + * Bob Conklin + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's TE410P Quad-T1/E1 PCI Driver + * Based on previous works, designs, and archetectures conceived and + * written by Jim Dixon , + * and Mark Spencer + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * Copyright (C) 2001-2005, Digium, Inc. + * Copyright (C) 2001 Jim Dixon / Zapata Telephony. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * * * * * * * * * * * * * NO WARRANTY * * * * * * * * * * * * * * * * * + * + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + * + * * * * * * * * * * * * DISCLAIMER OF LIABILITY * * * * * * * * * * * * + * + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LINUX26 +#include +#ifdef HOTPLUG_FIRMWARE +#ifndef CONFIG_FW_LOADER +#undef HOTPLUG_FIRMWARE +#else +#include +#endif +#endif +#endif +#include "rxt1.h" +#include "GpakCust.h" +#include "GpakApi.h" + +/* + * Tasklets provide better system interactive response at the cost of the + * possibility of losing a frame of data at very infrequent intervals. If + * you are more concerned with the performance of your machine, enable the + * tasklets. If you are strict about absolutely no drops, then do not enable + * tasklets. + */ + +/* #define ENABLE_TASKLETS */ + + +/* Work queues are a way to better distribute load on SMP systems */ +#if defined(LINUX26) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) +/* + * Work queues can significantly improve performance and scalability + * on multi-processor machines, but requires bypassing some kernel + * API's, so it's not guaranteed to be compatible with all kernels. + */ +/* #define ENABLE_WORKQUEUES */ +#endif + +/* Enable prefetching may help performance */ +#define ENABLE_PREFETCH + +#define DEBUG_MAIN (1 << 0) +#define DEBUG_DTMF (1 << 1) +#define DEBUG_REGS (1 << 2) +#define DEBUG_TSI (1 << 3) +#define DEBUG_ECHOCAN (1 << 4) +#define DEBUG_RBS (1 << 5) +#define DEBUG_FRAMER (1 << 6) +#define DEBUG_DSP (1 << 7) + +#define assert(expr) \ + if (unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s, %s, %s, line=%d\n",\ + #expr, __FILE__, __FUNCTION__, __LINE__); \ + } + +#ifdef ENABLE_WORKQUEUES +#include + +/* XXX UGLY!!!! XXX We have to access the direct structures of the workqueue which + are only defined within workqueue.c because they don't give us a routine to allow us + to nail a work to a particular thread of the CPU. Nailing to threads gives us + substantially higher scalability in multi-CPU environments though! */ + +/* + * The per-CPU workqueue (if single thread, we always use cpu 0's). + * + * The sequence counters are for flush_scheduled_work(). It wants to wait + * until until all currently-scheduled works are completed, but it doesn't + * want to be livelocked by new, incoming ones. So it waits until + * remove_sequence is >= the insert_sequence which pertained when + * flush_scheduled_work() was called. + */ + +struct cpu_workqueue_struct { + + spinlock_t lock; + + long remove_sequence; /* Least-recently added (next to run) */ + long insert_sequence; /* Next to add */ + + struct list_head worklist; + wait_queue_head_t more_work; + wait_queue_head_t work_done; + + struct workqueue_struct *wq; + task_t *thread; + + int run_depth; /* Detect run_workqueue() recursion depth */ +} ____cacheline_aligned; + +/* + * The externally visible workqueue abstraction is an array of + * per-CPU workqueues: + */ +struct workqueue_struct { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) + struct cpu_workqueue_struct *cpu_wq; +#else + struct cpu_workqueue_struct cpu_wq[NR_CPUS]; +#endif + const char *name; + struct list_head list; /* Empty if single thread */ +}; + +/* Preempt must be disabled. */ +static void __rxt1_queue_work(struct cpu_workqueue_struct *cwq, struct work_struct *work) +{ + unsigned long flags; + + spin_lock_irqsave(&cwq->lock, flags); + work->wq_data = cwq; + list_add_tail(&work->entry, &cwq->worklist); + cwq->insert_sequence++; + wake_up(&cwq->more_work); + spin_unlock_irqrestore(&cwq->lock, flags); +} + +/* + * Queue work on a workqueue. Return non-zero if it was successfully + * added. + * + * We queue the work to the CPU it was submitted, but there is no + * guarantee that it will be processed by that CPU. + */ +static inline int rxt1_queue_work(struct workqueue_struct *wq, struct work_struct *work, + int cpu) +{ + int ret = 0; + get_cpu(); + + if (!test_and_set_bit(0, &work->pending)) { + BUG_ON(!list_empty(&work->entry)); + __rxt1_queue_work(wq->cpu_wq + cpu, work); + ret = 1; + } + put_cpu(); + return ret; +} + +#endif + +static int debug = 0; +/* static int debug = (DEBUG_MAIN | DEBUG_DTMF | DEBUG_REGS | DEBUG_TSI | + * DEBUG_ECHOCAN | DEBUG_RBS | DEBUG_FRAMER); */ +/* static int debug = (DEBUG_MAIN | DEBUG_DSP); */ +/* static int debug = (DEBUG_MAIN | DEBUG_DTMF | DEBUG_REGS | DEBUG_TSI | + * DEBUG_ECHOCAN); */ +static int monitor_mode = 0; +static int timingcable = 0; +/* static int recq_off = 5; */ +static int recq_off = 1; +static int recd_off = 1; +static int xmit_off = 0; +static int sic3_set = 0x0c; +/* static int sic3_set = 0; */ +static int ec_disable_1 = 0; +static int ec_disable_2 = 0; +static int ec_disable_3 = 0; +static int ec_disable_4 = 0; +static int no_ec = 0; +static int nlp_type = 3; +static int porboot = 0; +static int memloop = 0; +static int test_pat = 0; +static int regdump = 0; +static int regdumped = 0; +static int insert_idle = 0; +static int local_loop = 0; +static int double_buffer = 0; +static int show_pointers = 0; +static int highestorder; +static int t1e1override = 0x00; /* -1 = jumper; 0xFF = E1 */ +static int j1mode = 0; +static int sigmode = FRMR_MODE_NO_ADDR_CMP; +static int loopback = 0; +static int alarmdebounce = 0; +/* Enabling bursting can more efficiently utilize PCI bus bandwidth, but + can also cause PCI bus starvation, especially in combination with other + aggressive cards. Please note that burst mode has no effect on CPU + utilization / max number of calls / etc. */ +static int noburst = 1; +static int debugslips = 0; +static int polling = 0; +static int gen_clk = 0; + +#define MAX_SPANS 16 + +#define FLAG_STARTED (1 << 0) +#define FLAG_NMF (1 << 1) +#define FLAG_SENDINGYELLOW (1 << 2) + +typedef struct { + __u32 offsetw; + __u32 offsetb; + char *name; + __u32 initial; + __u32 iomask; +} pciregs; + +static pciregs target_regs[] = { +/* offset name initial mask */ + {0, 0x400, "VERSION", 0x00000000, 0x0000000c}, /* 0x1000 */ + {1, 0x404, "DMA_CONT", 0x00000000, 0xffff004d}, /* 0x1004 */ + {2, 0x408, "RX_ADDR", 0x00000000, 0xffffffff}, /* 0x1008 */ + {3, 0x412, "TX_ADDR", 0x00000000, 0xffffffff}, /* 0x100c */ + {4, 0x416, "STATUS", 0x00000000, 0x00ffff00}, /* 0x1010 */ + {5, 0x405, "HPI_W", 0x00000000, 0xffffffff}, /* 0x1014 */ + {6, 0x406, "HPI_R", 0x00000000, 0x00000000}, /* 0x1018 */ + {7, 0x407, "HPI_C", 0x00000000, 0x00000050}, /* 0x1018 */ + +}; + +static pciregs framer_regs[] = { +/* offset name initial mask */ + /* 0x00, Transmission FIFO */ + {0x00, (0x00 << 2), "FRMR_FIFOL", 0x00, 0x00}, + /* 0x01, Transmission FIFO */ + {0x01, (0x01 << 2), "FRMR_FIFOH", 0x00, 0x00}, + /* 0x02, Command Register */ + {0x02, (0x02 << 2), "FRMR_CMDR", 0x00, 0x00}, + /* 0x03, Mode Register */ + {0x03, (0x03 << 2), "FRMR_MODE", 0x00, 0xff}, + /* 0x04, Receive Address High 1 */ + {0x04, (0x04 << 2), "FRMR_RAH1", 0x00, 0xff}, + /* 0x05, Receive Address High 2 */ + {0x05, (0x05 << 2), "FRMR_RAH2", 0x00, 0xff}, + /* 0x06, Receive Address Low 1 */ + {0x06, (0x06 << 2), "FRMR_RAL1", 0x00, 0xff}, + /* 0x07, Receive Address Low 2 */ + {0x07, (0x07 << 2), "FRMR_RAL2", 0x00, 0xff}, + /* 0x08, Interrupt Port Configuration */ + {0x08, (0x08 << 2), "FRMR_IPC", 0x00, 0xff}, + /* 0x09, Common Configuration Register 1 */ + {0x09, (0x09 << 2), "FRMR_CCR1", 0x00, 0xff}, + /* 0x0A, Common Configuration Register 3 */ + {0x0A, (0x0A << 2), "FRMR_CCR2", 0x00, 0xff}, + /* 0x0B, Preamble Register */ + {0x0B, (0x0B << 2), "FRMR_PRE", 0x00, 0xff}, + /* 0x0C, Receive Timeslot Register 1 */ + {0x0C, (0x0C << 2), "FRMR_RTR1", 0x00, 0xff}, + /* 0x0D, Receive Timeslot Register 2 */ + {0x0D, (0x0D << 2), "FRMR_RTR2", 0x00, 0xff}, + /* 0x0E, Receive Timeslot Register 3 */ + {0x0E, (0x0E << 2), "FRMR_RTR3", 0x00, 0xff}, + /* 0x0F, Receive Timeslot Register 4 */ + {0x0F, (0x0F << 2), "FRMR_RTR4", 0x00, 0xff}, + /* 0x10, Transmit Timeslot Register 1 */ + {0x10, (0x10 << 2), "FRMR_TTR1", 0x00, 0xff}, + /* 0x11, Transmit Timeslot Register 2 */ + {0x11, (0x11 << 2), "FRMR_TTR2", 0x00, 0xff}, + /* 0x12, Transmit Timeslot Register 3 */ + {0x12, (0x12 << 2), "FRMR_TTR3", 0x00, 0xff}, + /* 0x13, Transmit Timeslot Register 4 */ + {0x13, (0x13 << 2), "FRMR_TTR4", 0x00, 0xff}, + /* 0x14, Interrupt Mask Register 0 */ + {0x14, (0x14 << 2), "FRMR_IMR0", 0x00, 0xff}, + /* 0x15, Interrupt Mask Register 1 */ + {0x15, (0x15 << 2), "FRMR_IMR1", 0x00, 0xff}, + /* 0x16, Interrupt Mask Register 2 */ + {0x16, (0x16 << 2), "FRMR_IMR2", 0x00, 0xff}, + /* 0x17, Interrupt Mask Register 3 */ + {0x17, (0x17 << 2), "FRMR_IMR3", 0x00, 0xff}, + /* 0x18, Interrupt Mask Register 4 */ + {0x18, (0x18 << 2), "FRMR_IMR4", 0x00, 0xff}, + /* 0x19, Gap within address range no.1 */ + {0x19, (0x19 << 2), "FRMR_RESERVED_19", 0x00, 0x00}, + /* 0x1A, Gap within address range no.1 */ + {0x1A, (0x1A << 2), "FRMR_RESERVED_2A", 0x00, 0x00}, + /* 0x1B, Single Bit Insertion Register */ + {0x1B, (0x1B << 2), "FRMR_IERR", 0x00, 0xff}, + /* 0x1C, Framer Mode Register 0 */ + {0x1C, (0x1C << 2), "FRMR_FMR0", 0x00, 0xff}, + /* 0x1D, Framer Mode Register 1 */ + {0x1D, (0x1D << 2), "FRMR_FMR1", 0x00, 0xff}, + /* 0x1E, Framer Mode Register 2 */ + {0x1E, (0x1E << 2), "FRMR_FMR2", 0x00, 0xff}, + /* 0x1F, Channel Loop Back */ + {0x1F, (0x1F << 2), "FRMR_LOOP", 0x00, 0xff}, + /* 0x20, Transmit Service Word Framer Mode Reigster 4 */ + {0x20, (0x20 << 2), "FRMR_XSW_FMR4", 0x00, 0xff}, + /* 0x21, Transmit Spare Bits Framer Mode Reigster 5 */ + {0x21, (0x21 << 2), "FRMR_XSP_FMR5", 0x00, 0xff}, + /* 0x22, Transmit Control 0 */ + {0x22, (0x22 << 2), "FRMR_XC0", 0x00, 0xff}, + /* 0x23, Transmit Control 1 */ + {0x23, (0x23 << 2), "FRMR_XC1", 0x00, 0xff}, + /* 0x24, Receive Control 0 */ + {0x24, (0x24 << 2), "FRMR_RC0", 0x00, 0xff}, + /* 0x25, Receive Control 1 */ + {0x25, (0x25 << 2), "FRMR_RC1", 0x00, 0xff}, + /* 0x26, Transmit Pulse Mask 0 */ + {0x26, (0x26 << 2), "FRMR_XPM0", 0x00, 0xff}, + /* 0x27, Transmit Pulse Mask 1 */ + {0x27, (0x27 << 2), "FRMR_XPM1", 0x00, 0xff}, + /* 0x28, Transmit Pulse Mask 2 */ + {0x28, (0x28 << 2), "FRMR_XPM2", 0x00, 0xff}, + /* 0x29, Transparent Service Word Mask */ + {0x29, (0x29 << 2), "FRMR_TSWM", 0x00, 0xff}, + /* 0x2A, Unused Byte No.2 */ + {0x2A, (0x2A << 2), "FRMR_RESERVED_2A", 0x00, 0x00}, + /* 0x2B, Idle Channel Code */ + {0x2B, (0x2B << 2), "FRMR_IDLE", 0x00, 0xff}, + /* 0x2C, Transmit SA4 Bit Register Fransmit DL-Bit Register 1 */ + {0x2C, (0x2C << 2), "FRMR_XSA4_XDL1", 0x00, 0xff}, + /* 0x2D, Transmit SA5 Bit Register Fransmit DL-Bit Register 2 */ + {0x2D, (0x2D << 2), "FRMR_XSA5_XDL2", 0x00, 0xff}, + /* 0x2E, Transmit SA6 Bit Register Fransmit DL-Bit Register 3 */ + {0x2E, (0x2E << 2), "FRMR_XSA6_XDL3", 0x00, 0xff}, + /* 0x2F, Transmit SA7 Bit Register Clear Channel Register 1 */ + {0x2F, (0x2F << 2), "FRMR_XSA7_CCB1", 0x00, 0xff}, + /* 0x30, Transmit SA8 Bit Register Clear Channel Register 2 */ + {0x30, (0x30 << 2), "FRMR_XSA8_CCB2", 0x00, 0xff}, + /* 0x31, Framer Mode Reg. 3 Clear Channel Register 3 */ + {0x31, (0x31 << 2), "FRMR_FMR3_CCB3", 0x00, 0xff}, + /* 0x32, Idle Channel Register 1 */ + {0x32, (0x32 << 2), "FRMR_ICB1", 0x00, 0xff}, + /* 0x33, Idle Channel Register 2 */ + {0x33, (0x33 << 2), "FRMR_ICB2", 0x00, 0xff}, + /* 0x34, Idle Channel Register 3 */ + {0x34, (0x34 << 2), "FRMR_ICB3", 0x00, 0xff}, + /* 0x35, Idle Channel Register 4 */ + {0x35, (0x35 << 2), "FRMR_ICB4", 0x00, 0xff}, + /* 0x36, Line Interface Mode 0 EQ bit is gone */ + {0x36, (0x36 << 2), "FRMR_LIM0", 0x00, 0xf7}, + /* 0x37, Line Interface Mode 1 */ + {0x37, (0x37 << 2), "FRMR_LIM1", 0x00, 0xff}, + /* 0x38, Pulse Count Detection */ + {0x38, (0x38 << 2), "FRMR_PCD", 0x00, 0xff}, + /* 0x39, Pulse Count Recovery */ + {0x39, (0x39 << 2), "FRMR_PCR", 0x00, 0xff}, + /* 0x3A, Line Interface Mode Register 2 */ + {0x3A, (0x3A << 2), "FRMR_LIM2", 0x00, 0xff}, + /* 0x3B, Line Code Register 1 */ + {0x3B, (0x3B << 2), "FRMR_LCR1", 0x00, 0xff}, + /* 0x3C, Line Code Register 2 */ + {0x3C, (0x3C << 2), "FRMR_LCR2", 0x00, 0xff}, + /* 0x3D, Line Code Register 3 */ + {0x3D, (0x3D << 2), "FRMR_LCR3", 0x00, 0xff}, + /* 0x3E, System Interface Control 1 */ + {0x3E, (0x3E << 2), "FRMR_SIC1", 0x00, 0xff}, + /* 0x3F, System Interface Control 2 */ + {0x3F, (0x3F << 2), "FRMR_SIC2", 0x00, 0xff}, + /* 0x40, System Interface Control 3 */ + {0x40, (0x40 << 2), "FRMR_SIC3", 0x00, 0xff}, + /* 0x41, Gap within address range no.1 */ + {0x41, (0x41 << 2), "FRMR_RESERVED_41", 0x00, 0x00}, + /* 0x42, Gap within address range no.1 */ + {0x42, (0x42 << 2), "FRMR_RESERVED_42", 0x00, 0x00}, + /* 0x43, Gap within address range no.1 */ + {0x43, (0x43 << 2), "FRMR_RESERVED_43", 0x00, 0x00}, + /* 0x44, Clock Mode Register 1 */ + {0x44, (0x44 << 2), "FRMR_CMR1", 0x00, 0xff}, + /* 0x45, Clock Mode Register 2 */ + {0x45, (0x45 << 2), "FRMR_CMR2", 0x00, 0xff}, + /* 0x46, Global Configuration Register */ + {0x46, (0x46 << 2), "FRMR_GCR", 0x00, 0xff}, + /* 0x47, Errored Second Mask */ + {0x47, (0x47 << 2), "FRMR_ESM", 0x00, 0xff}, + /* 0x48, Gap within address range no.1 */ + {0x48, (0x48 << 2), "FRMR_RESERVED_48", 0x00, 0x00}, + /* 0x49, Receive Buffer Delay */ + {0x49, (0x49 << 2), "FRMR_RBD", 0x00, 0xff}, + /* 0x4A, Version Status */ + {0x4A, (0x4A << 2), "FRMR_VSTR", 0x00, 0x00}, + /* 0x4B, Receive Equilizer Status */ + {0x4B, (0x4B << 2), "FRMR_RES", 0x00, 0xff}, + /* 0x4C, Framer Receive Status 0 */ + {0x4C, (0x4C << 2), "FRMR_FRS0", 0x00, 0xff}, + /* 0x4D, Framer Receive Status 1 */ + {0x4D, (0x4D << 2), "FRMR_FRS1", 0x00, 0xff}, + /* 0x4E, Receive Service Word Framer Receive Status 2 */ + {0x4E, (0x4E << 2), "FRMR_RSW_FRS2", 0x00, 0xff}, + /* 0x4F, Receive Spare Bits Framer Receive Status 3 */ + {0x4F, (0x4F << 2), "FRMR_RSP_FRS3", 0x00, 0xff}, + /* 0x50, Framing Error Counter */ + {0x50, (0x50 << 2), "FRMR_FECL", 0x00, 0xff}, + /* 0x51, Framing Error Counter */ + {0x51, (0x51 << 2), "FRMR_FECH", 0x00, 0xff}, + /* 0x52, Code Violation Counter */ + {0x52, (0x52 << 2), "FRMR_CVCL", 0x00, 0xff}, + /* 0x53, Code Violation Counter */ + {0x53, (0x53 << 2), "FRMR_CVCH", 0x00, 0xff}, + /* 0x54, CRC Error Counter 1 */ + {0x54, (0x54 << 2), "FRMR_CEC1L", 0x00, 0xff}, + /* 0x55, CRC Error Counter 1 */ + {0x55, (0x55 << 2), "FRMR_CEC1H", 0x00, 0xff}, + /* 0x56, E-Bit Error Counter */ + {0x56, (0x56 << 2), "FRMR_EBCL", 0x00, 0xff}, + /* 0x57, E-Bit Error Counter */ + {0x57, (0x57 << 2), "FRMR_EBCH", 0x00, 0xff}, + /* 0x58, CRC Error Counter 2 (E1) */ + {0x58, (0x58 << 2), "FRMR_CEC2_BECL", 0x00, 0xff}, + /* 0x59, CRC Error Counter 2 (E1) */ + {0x59, (0x59 << 2), "FRMR_CEC2_BECH", 0x00, 0xff}, + /* 0x5A, CRC Error Counter 3 (E1) */ + {0x5A, (0x5A << 2), "FRMR_CEC3_COFAL", 0x00, 0xff}, + /* 0x5B, CRC Error Counter 3 (E1) */ + {0x5B, (0x5B << 2), "FRMR_CEC3_COFAH", 0x00, 0xff}, + /* 0x5C, Receive SA4 Bit Register Receive DL-Bit Register 1 */ + {0x5C, (0x5C << 2), "FRMR_RSA4_RDL1", 0x00, 0xff}, + /* 0x5D, Receive SA5 Bit Register Receive DL-Bit Register 2 */ + {0x5D, (0x5D << 2), "FRMR_RSA5_RDL2", 0x00, 0xff}, + /* 0x5E, Receive SA6 Bit Register Receive DL-Bit Register 3 */ + {0x5E, (0x5E << 2), "FRMR_RSA6_RDL3", 0x00, 0xff}, + /* 0x5F, Receive SA7 Bit Register */ + {0x5F, (0x5F << 2), "FRMR_RSA7", 0x00, 0xff}, + /* 0x60, Receive SA8 Bit Register */ + {0x60, (0x60 << 2), "FRMR_RSA8_DEC", 0x00, 0x00}, + /* 0x61, Receive Sa6 Bit Status Register */ + {0x61, (0x61 << 2), "FRMR_RSA6S", 0x00, 0xff}, + /* 0x62, Manufacturer Test Register 0 */ + {0x62, (0x62 << 2), "FRMR_RSP1_TEST2", 0x00, 0x00}, + /* 0x63, Manufacturer Test Register 1 */ + {0x63, (0x63 << 2), "FRMR_RSP2", 0x00, 0xff}, + /* 0x64, Signaling Status Register */ + {0x64, (0x64 << 2), "FRMR_SIS", 0x00, 0xff}, + /* 0x65, Receive Signaling Status Register */ + {0x65, (0x65 << 2), "FRMR_RSIS", 0x00, 0xff}, + /* 0x66, Receive Byte Control */ + {0x66, (0x66 << 2), "FRMR_RBCL", 0x00, 0xff}, + /* 0x67, Receive Byte Control */ + {0x67, (0x67 << 2), "FRMR_RBCH", 0x00, 0xff}, + /* 0x68, Interrupt Status Register 0 */ + {0x68, (0x68 << 2), "FRMR_ISR0", 0x00, 0xff}, + /* 0x69, Interrupt Status Register 1 */ + {0x69, (0x69 << 2), "FRMR_ISR1", 0x00, 0xff}, + /* 0x6A, Interrupt Status Register 2 */ + {0x6A, (0x6A << 2), "FRMR_ISR2", 0x00, 0xff}, + /* 0x6B, Interrupt Status Register 3 */ + {0x6B, (0x6B << 2), "FRMR_ISR3", 0x00, 0xff}, + /* 0x6C, Interrupt Status Register 4 */ + {0x6C, (0x6C << 2), "FRMR_ISR4", 0x00, 0xff}, + /* 0x6D, Unused Byte No.3 */ + {0x6D, (0x6D << 2), "FRMR_RESERVED_6D", 0x00, 0xff}, + /* 0x6E, Global Interrupt Status */ + {0x6E, (0x6E << 2), "FRMR_GIS", 0x00, 0xff}, + /* 0x6F, Channel Interrupt Status */ + {0x6F, (0x6F << 2), "FRMR_CIS", 0x00, 0xff}, + /* 0x70, Receive CAS Register 1...16 */ + {0x70, (0x70 << 2), "FRMR_XS_RS_1", 0x00, 0x00}, + /* 0x71, Receive CAS Register 1...16 */ + {0x71, (0x71 << 2), "FRMR_XS_RS_2", 0x00, 0x00}, + /* 0x72, Receive CAS Register 1...16 */ + {0x72, (0x72 << 2), "FRMR_XS_RS_3", 0x00, 0x00}, + /* 0x73, Receive CAS Register 1...16 */ + {0x73, (0x73 << 2), "FRMR_XS_RS_4", 0x00, 0x00}, + /* 0x74, Receive CAS Register 1...16 */ + {0x74, (0x74 << 2), "FRMR_XS_RS_5", 0x00, 0x00}, + /* 0x75, Receive CAS Register 1...16 */ + {0x75, (0x75 << 2), "FRMR_XS_RS_6", 0x00, 0x00}, + /* 0x76, Receive CAS Register 1...16 */ + {0x76, (0x76 << 2), "FRMR_XS_RS_7", 0x00, 0x00}, + /* 0x77, Receive CAS Register 1...16 */ + {0x77, (0x77 << 2), "FRMR_XS_RS_8", 0x00, 0x00}, + /* 0x78, Receive CAS Register 1...16 */ + {0x78, (0x78 << 2), "FRMR_XS_RS_9", 0x00, 0x00}, + /* 0x79, Receive CAS Register 1...16 */ + {0x79, (0x79 << 2), "FRMR_XS_RS_10", 0x00, 0x00}, + /* 0x7a, Receive CAS Register 1...16 */ + {0x7a, (0x7a << 2), "FRMR_XS_RS_11", 0x00, 0x00}, + /* 0x7b, Receive CAS Register 1...16 */ + {0x7b, (0x7b << 2), "FRMR_XS_RS_12", 0x00, 0x00}, + /* 0x7c, Receive CAS Register 1...16 */ + {0x7c, (0x7c << 2), "FRMR_XS_RS_13", 0x00, 0x00}, + /* 0x7d, Receive CAS Register 1...16 */ + {0x7d, (0x7d << 2), "FRMR_XS_RS_14", 0x00, 0x00}, + /* 0x7e, Receive CAS Register 1...16 */ + {0x7e, (0x7e << 2), "FRMR_XS_RS_15", 0x00, 0x00}, + /* 0x7f, Receive CAS Register 1...16 */ + {0x7f, (0x7f << 2), "FRMR_XS_RS_16", 0x00, 0x00}, + /* 0x80, Port Configuration 1 */ + {0x80, (0x80 << 2), "FRMR_PC1", 0x00, 0xff}, + /* 0x81, Port Configuration 2 */ + {0x81, (0x81 << 2), "FRMR_PC2", 0x00, 0xff}, + /* 0x82, Port Configuration 3 */ + {0x82, (0x82 << 2), "FRMR_PC3", 0x00, 0xff}, + /* 0x83, Port Configuration 4 */ + {0x83, (0x83 << 2), "FRMR_PC4", 0x00, 0xff}, + /* 0x84, Port Configuration 5 */ + {0x84, (0x84 << 2), "FRMR_PC5", 0x00, 0xff}, + /* 0x85, Global Port Configuration 1 */ + {0x85, (0x85 << 2), "FRMR_GPC1", 0x00, 0xff}, + /* 0x86, Unused Byte 3 */ + {0x86, (0x86 << 2), "FRMR_RESERVED_86", 0x00, 0xff}, + /* 0x87, Command Register no.2 */ + {0x87, (0x87 << 2), "FRMR_CMDR2", 0x00, 0x00}, + /* 0x88, Gap within address range */ + {0x88, (0x88 << 2), "FRMR_RESERVED_88", 0x00, 0x00}, + /* 0x89, Gap within address range */ + {0x89, (0x89 << 2), "FRMR_RESERVED_89", 0x00, 0x00}, + /* 0x8a, Gap within address range */ + {0x8a, (0x8a << 2), "FRMR_RESERVED_8A", 0x00, 0x00}, + /* 0x8b, Gap within address range */ + {0x8b, (0x8b << 2), "FRMR_RESERVED_8B", 0x00, 0x00}, + /* 0x8c, Gap within address range */ + {0x8c, (0x8c << 2), "FRMR_RESERVED_8C", 0x00, 0x00}, + /* 0x8D, Common Configuration Register 5 */ + {0x8D, (0x8D << 2), "FRMR_CCR5", 0x00, 0xff}, + /* 0x8E, Gap within address range */ + {0x8E, (0x8E << 2), "FRMR_RESERVED_8E", 0x00, 0x00}, + /* 0x8f, Gap within address range */ + {0x8f, (0x8f << 2), "FRMR_RESERVED_8F", 0x00, 0x00}, + /* 0x90, Gap within address range */ + {0x90, (0x90 << 2), "FRMR_RESERVED_90", 0x00, 0x00}, + /* 0x91, Gap within address range */ + {0x91, (0x91 << 2), "FRMR_RESERVED_91", 0x00, 0x00}, + /* 0x92, Global Clocking Modes */ + {0x92, (0x92 << 2), "FRMR_GCM1", 0x00, 0xff}, + /* 0x93, Channel Interrupt Status */ + {0x93, (0x93 << 2), "FRMR_GCM2", 0x00, 0xff}, + /* 0x94, Global Clocking Modes */ + {0x94, (0x94 << 2), "FRMR_GCM3", 0x00, 0xff}, + /* 0x95, Channel Interrupt Status */ + {0x95, (0x95 << 2), "FRMR_GCM4", 0x00, 0xff}, + /* 0x96, Global Clocking Modes */ + {0x96, (0x96 << 2), "FRMR_GCM5", 0x00, 0xff}, + /* 0x97, Global Clocking Modes */ + {0x97, (0x97 << 2), "FRMR_GCM6", 0x00, 0xff}, + /* 0x98, Gap within address range */ + {0x98, (0x98 << 2), "FRMR_RESERVED_98", 0x00, 0x00}, + /* 0x99, Gap within address range */ + {0x99, (0x99 << 2), "FRMR_RESERVED_99", 0x00, 0x00}, + /* 0x9a, Gap within address range */ + {0x9a, (0x9a << 2), "FRMR_RESERVED_9A", 0x00, 0x00}, + /* 0x9b, Gap within address range */ + {0x9b, (0x9b << 2), "FRMR_RESERVED_9B", 0x00, 0x00}, + /* 0x9c, Gap within address range */ + {0x9c, (0x9c << 2), "FRMR_RESERVED_9C", 0x00, 0x00}, + /* 0x9d, Gap within address range */ + {0x9d, (0x9d << 2), "FRMR_RESERVED_9D", 0x00, 0x00}, + /* 0x9f, Gap within address range */ + {0x9f, (0x9f << 2), "FRMR_RESERVED_9F", 0x00, 0x00}, + /* 0xA0, Time Slot Even/Odd Select */ + {0xA0, (0xA0 << 2), "FRMR_TSEO", 0x00, 0xff}, + /* 0xA1, Time Slot Bit Select 1 */ + {0xA1, (0xA1 << 2), "FRMR_TSBS1", 0x00, 0xff}, + /* 0xA2, Gap within address range */ + {0xA2, (0xA2 << 2), "FRMR_RESERVED_A2", 0x00, 0x00}, + /* 0xA3, Gap within address range */ + {0xA3, (0xA3 << 2), "FRMR_RESERVED_A3", 0x00, 0x00}, + /* 0xA4, Gap within address range */ + {0xA4, (0xA4 << 2), "FRMR_RESERVED_A4", 0x00, 0x00}, + /* 0xA5, Gap within address range */ + {0xA5, (0xA5 << 2), "FRMR_RESERVED_A5", 0x00, 0x00}, + /* 0xA6, Gap within address range */ + {0xA6, (0xA6 << 2), "FRMR_RESERVED_A6", 0x00, 0x00}, + /* 0xA7, Gap within address range */ + {0xA7, (0xA7 << 2), "FRMR_RESERVED_A7", 0x00, 0x00}, + /* 0xA8, Test Pattern Control 0 */ + {0xA8, (0xA8 << 2), "FRMR_TPC0", 0x00, 0xff}, + /* 0xA9, Gap within address range */ + {0xA9, (0xA9 << 2), "FRMR_RESERVED_A9", 0x00, 0x00}, + /* 0xAA, Gap within address range */ + {0xAA, (0xAA << 2), "FRMR_RESERVED_AA", 0x00, 0x00}, + /* 0xAB, Gap within address range */ + {0xAB, (0xAB << 2), "FRMR_RESERVED_AB", 0x00, 0x00}, + /* 0xAC, Gap within address range */ + {0xAC, (0xAC << 2), "FRMR_RESERVED_AC", 0x00, 0x00}, + /* 0xAD, Gap within address range */ + {0xAD, (0xAD << 2), "FRMR_RESERVED_AD", 0x00, 0x00}, + /* 0xAE, Gap within address range */ + {0xAE, (0xAE << 2), "FRMR_RESERVED_AE", 0x00, 0x00}, + /* 0xAF, Gap within address range */ + {0xAF, (0xAF << 2), "FRMR_RESERVED_AF", 0x00, 0x00}, + /* 0xB0 Gap within address range */ + {0xB0, (0xB0 << 2), "FRMR_RESERVED_B0", 0x00, 0x00}, + /* 0xB1 Gap within address range */ + {0xB1, (0xB1 << 2), "FRMR_RESERVED_B1", 0x00, 0x00}, + /* 0xB2 Gap within address range */ + {0xB2, (0xB2 << 2), "FRMR_RESERVED_B2", 0x00, 0x00}, + /* 0xB3 Gap within address range */ + {0xB3, (0xB3 << 2), "FRMR_RESERVED_B3", 0x00, 0x00}, + /* 0xB4 Gap within address range */ + {0xB4, (0xB4 << 2), "FRMR_RESERVED_B4", 0x00, 0x00}, + /* 0xB5 Gap within address range */ + {0xB5, (0xB5 << 2), "FRMR_RESERVED_B5", 0x00, 0x00}, + /* 0xB6 Gap within address range */ + {0xB6, (0xB6 << 2), "FRMR_RESERVED_B6", 0x00, 0x00}, + /* 0xB7 Gap within address range */ + {0xB7, (0xB7 << 2), "FRMR_RESERVED_B7", 0x00, 0x00}, + /* 0xB8 Gap within address range */ + {0xB8, (0xB8 << 2), "FRMR_RESERVED_B8", 0x00, 0x00}, + /* 0xB9 Gap within address range */ + {0xB9, (0xB9 << 2), "FRMR_RESERVED_B9", 0x00, 0x00}, + /* 0xBA Gap within address range */ + {0xBA, (0xBA << 2), "FRMR_RESERVED_BA", 0x00, 0x00}, + /* 0xBB */ + {0xBB, (0xBB << 2), "FRMR_REGFP", 0x00, 0xff}, + /* 0xBC */ + {0xBC, (0xBC << 2), "FRMR_REGFD", 0x00, 0x00}, +}; + + +#define TYPE_T1 1 /* is a T1 card */ +#define TYPE_E1 2 /* is an E1 card */ +#define TYPE_J1 3 /* is a running J1 */ + +#define FLAG_2PORT (1 << 4) +#define FLAG_OCTOPT (1 << 6) + +#define CANARY 0xc0de + +struct devtype { + char *desc; + unsigned int flags; +}; + +static struct devtype r4t1 = { "Rhino Equipment R4T1", 0 }; +static struct devtype r2t1 = { "Rhino Equipment R2T1", FLAG_2PORT }; + +static int inirq = 0; + +static void __rxt1_span_set_clear(struct rxt1_card_t *rxt1_card, int span); +static int rxt1_span_startup(struct dahdi_span *zap_span); +static int rxt1_span_shutdown(struct dahdi_span *zap_span); +static int rxt1_zap_chan_rbsbits(struct dahdi_chan *zap_chan, int bits); +static int rxt1_span_maint(struct dahdi_span *zap_span, int cmd); +#ifdef DAHDI_SIG_HARDHDLC +static void rxt1_zap_chan_hdlc_hard_xmit(struct dahdi_chan *zap_chan); +#endif +static int rxt1_zap_chan_ioctl(struct dahdi_chan *zap_chan, unsigned int cmd, + unsigned long data); +static void rxt1_card_tsi_assign(struct rxt1_card_t *rxt1_card, int fromspan, + int fromchan, int tospan, int tochan); +static void rxt1_card_tsi_unassign(struct rxt1_card_t *rxt1_card, int tospan, int tochan); +static void __rxt1_card_set_timing_source(struct rxt1_card_t *rxt1_card, int unit, + int master, int slave); +static void rxt1_span_check_alarms(struct rxt1_card_t *rxt1_card, int span); +static void rxt1_span_check_sigbits(struct rxt1_card_t *rxt1_card, int span); + +static int rxt1_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, + struct dahdi_echocan_state **ec); +static void rxt1_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); + +static const struct dahdi_echocan_features my_ec_features = { + .NLP_automatic = 1, + .CED_tx_detect = 1, + .CED_rx_detect = 1, +}; + +static const struct dahdi_echocan_ops my_ec_ops = { + .name = "RXT1_HWEC", + .echocan_free = rxt1_echocan_free, +}; + + +#ifdef ENABLE_TASKLETS +static void rxt1_tasklet(unsigned long data); +#endif + +static struct rxt1_card_t *rxt1_cards[MAX_RXT1_CARDS]; + +#define MAX_TDM_CHAN 32 +#define MAX_DTMF_DET 16 + +#define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF) +#define HDLC_IMR1_MASK (FRMR_IMR1_XDU | FRMR_IMR1_XPR) + +/* read __u32 from BAR 0 indexed by DWORDS */ +/* word 401 = bus address 1004 + BAR 0 = Framer address */ +inline unsigned int __rxt1_card_pci_in(struct rxt1_card_t *rxt1_card, + const unsigned int addr) +{ + unsigned int res = readl(&rxt1_card->membase[addr]); + return res; +} + +/* write __u32 to BAR 0 indexed by DWORDS */ +/* and test with mask word 401 = bus address 1004 */ +inline void __rxt1_card_pci_out(struct rxt1_card_t *rxt1_card, const unsigned int addr, + const unsigned int value, const unsigned int mask) +{ + /* &rxt1_case->membase[addr] CANNOT BE less than rxt1_card->membase + * but it was being tested before, so we'll leave this here */ + if (&rxt1_card->membase[addr] < rxt1_card->membase) { + printk + ("PCI out writing %x to addr %p OUCH base is %p and Last Reg is %p OUCH (1)\n", + value, &rxt1_card->membase[addr], rxt1_card->membase, + &rxt1_card->membase[0x1068]); + return; + } else if (addr < 0x400 && value > 255) { + printk("PCI out writing %x to addr %p OUCH too big for register OUCH\n", + value, &rxt1_card->membase[addr]); + } + + writel(value, &rxt1_card->membase[addr]); +} + +static inline void rxt1_card_pci_out(struct rxt1_card_t *rxt1_card, + const unsigned int addr, const unsigned int value, + const unsigned int mask) +{ + unsigned long flags; + spin_lock_irqsave(&rxt1_card->reglock, flags); + __rxt1_card_pci_out(rxt1_card, addr, value, mask); + spin_unlock_irqrestore(&rxt1_card->reglock, flags); +} + +static inline void __rxt1_card_set_led(struct rxt1_card_t *rxt1_card, int span, int state) +{ + int retry = 0; + int oldreg = rxt1_card->ledreg; + int mask = target_regs[RXT1_STAT].iomask; + rxt1_card->ledreg &= ~(0xf << (8 + (span << 2))); + rxt1_card->ledreg |= (state << (8 + (span << 2))); + if (oldreg != rxt1_card->ledreg) { + printk("Status Change on Span %d from %x to %x\n", span, oldreg, + rxt1_card->ledreg); + __rxt1_card_pci_out(rxt1_card, RXT1_STAT + TARG_REGS, rxt1_card->ledreg, mask); + while (((__rxt1_card_pci_in(rxt1_card, RXT1_STAT + TARG_REGS) & mask) != + (rxt1_card->ledreg & mask)) && ((retry++) < 10)) + __rxt1_card_pci_out(rxt1_card, RXT1_STAT + TARG_REGS, rxt1_card->ledreg, + mask); + } +} + +static inline void rxt1_card_activate(struct rxt1_card_t *rxt1_card) +{ + rxt1_card->ledreg = STATINIT | 0x40; /* keep JTAG locked and tri-state */ + rxt1_card_pci_out(rxt1_card, RXT1_STAT + TARG_REGS, rxt1_card->ledreg, + target_regs[RXT1_STAT].iomask); +} + +static inline unsigned int rxt1_card_pci_in(struct rxt1_card_t *rxt1_card, + const unsigned int addr) +{ + unsigned int ret; + unsigned long flags; + + spin_lock_irqsave(&rxt1_card->reglock, flags); + ret = __rxt1_card_pci_in(rxt1_card, addr); + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + return ret; +} + +unsigned long flags; + +int try_select_framer(struct rxt1_card_t *rxt1_card) +{ + int hpi_lock; + + int sel; + spin_lock_irqsave(&rxt1_card->reglock, flags); + sel = __rxt1_card_pci_in(rxt1_card, RXT1_HCS_REG + TARG_REGS); + if (sel == 0) { + hpi_lock = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, hpi_lock & ~HPI_SEL, + target_regs[RXT1_HPIC].iomask); + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, (__u32) (0x10), 0); + return (0); + } + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + return (1); +} + +void rxt1_card_select_framer(struct rxt1_card_t *rxt1_card) +{ + int ridiculous = 0; + + while (try_select_framer(rxt1_card)) { + mdelay(1); + ridiculous++; + if (ridiculous > 100000) { + printk + ("I'm Broken. I waited 10 seconds .... and nothing happened. I quit. " + "I'm outta here.\n"); + BUG(); + return; + } + } + return; +} + +void rxt1_card_unselect_framer(struct rxt1_card_t *rxt1_card) +{ + int sel = __rxt1_card_pci_in(rxt1_card, RXT1_HCS_REG + TARG_REGS); + if (sel != (0x10)) + printk("R%dT1: Framer un-select Wrong DSP Selected: Should be %x is %x\n", + rxt1_card->numspans, 0x10, sel); + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, (__u32) (0), 0); + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + + return; +} + +static inline unsigned int __rxt1_span_framer_in(struct rxt1_card_t *rxt1_card, int span, + const unsigned int addr) +{ + unsigned int ret, adj_addr; + span &= 0x3; + + rxt1_card_select_framer(rxt1_card); + + /* Dual card span 1 is actually at span 2 */ + if ((rxt1_card->numspans == 2) && (span == 1)) + span = 2; + else if ((rxt1_card->numspans == 2) && (span == 2)) + span = 1; + + adj_addr = (((span << 8) | (addr & 0xff))); + ret = __rxt1_card_pci_in(rxt1_card, adj_addr); + + rxt1_card_unselect_framer(rxt1_card); + + return (ret & 0xff); +} + +static inline unsigned int rxt1_span_framer_in(struct rxt1_card_t *rxt1_card, int span, + const unsigned int addr) +{ + return __rxt1_span_framer_in(rxt1_card, span, addr); +} + +static inline void __rxt1_span_framer_out(struct rxt1_card_t *rxt1_card, int span, + const unsigned int addr, + const unsigned int value) +{ + unsigned int adj_addr; + span &= 0x3; + + rxt1_card_select_framer(rxt1_card); + + /* Dual card span 2 is actually at span 3 */ + if ((rxt1_card->numspans == 2) && (span == 1)) + span = 2; + else if ((rxt1_card->numspans == 2) && (span == 2)) + span = 1; + + adj_addr = (((span << 8) | (addr & 0xff))); + if (debug & DEBUG_REGS) + printk("Writing %02x to address %02x of span %d adj_addr %x\n", value, addr, span, + adj_addr); + __rxt1_card_pci_out(rxt1_card, adj_addr, value, framer_regs[addr].iomask); + + rxt1_card_unselect_framer(rxt1_card); +} + +static inline void rxt1_span_framer_out(struct rxt1_card_t *rxt1_card, int span, + const unsigned int addr, const unsigned int value) +{ + __rxt1_span_framer_out(rxt1_card, span, addr, value); +} + +static void __rxt1_span_hdlc_stop(struct rxt1_card_t *rxt1_card, unsigned int span) +{ + /* used in one place below */ + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span]; + unsigned char imr0, imr1, mode; + int i = 0; + + if (debug & DEBUG_FRAMER) + printk("Stopping HDLC controller on span %d\n", span + 1); + + /* Clear receive and transmit timeslots */ + for (i = 0; i < 4; i++) { + __rxt1_span_framer_out(rxt1_card, span, FRMR_RTR_BASE + i, 0x00); + __rxt1_span_framer_out(rxt1_card, span, FRMR_TTR_BASE + i, 0x00); + } + + imr0 = __rxt1_span_framer_in(rxt1_card, span, FRMR_IMR0); + imr1 = __rxt1_span_framer_in(rxt1_card, span, FRMR_IMR1); + + /* Disable HDLC interrupts */ + imr0 |= HDLC_IMR0_MASK; + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR0, imr0); + + imr1 |= HDLC_IMR1_MASK; + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR1, imr1); + + mode = __rxt1_span_framer_in(rxt1_card, span, FRMR_MODE); + mode &= ~FRMR_MODE_HRAC; + __rxt1_span_framer_out(rxt1_card, span, FRMR_MODE, mode); + + rxt1_span->sigactive = 0; +} + +static inline void __rxt1_span_framer_cmd(struct rxt1_card_t *rxt1_card, + unsigned int span, int cmd) +{ + __rxt1_span_framer_out(rxt1_card, span, FRMR_CMDR, cmd); +} + +static inline void __rxt1_span_framer_cmd_wait(struct rxt1_card_t *rxt1_card, + unsigned int span, int cmd) +{ + int sis; + int loops = 0; + + /* XXX could be time consuming XXX */ + for (;;) { + sis = __rxt1_span_framer_in(rxt1_card, span, FRMR_SIS); + if (!(sis & 0x04)) + break; + if (!loops++) { + printk("!!!SIS Waiting before cmd %02x\n", cmd); + } + } + if (loops) + printk("!!!SIS waited %d loops\n", loops); + + __rxt1_span_framer_out(rxt1_card, span, FRMR_CMDR, cmd); +} + +static int __rxt1_hdlc_start_chan(struct rxt1_card_t *rxt1_card, unsigned int span, + struct dahdi_chan *zap_chan, unsigned char mode) +{ + /* used in 2 places below */ + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span]; + + unsigned char imr0, imr1; + int offset = zap_chan->chanpos; + + if (debug & DEBUG_FRAMER) + printk("Starting HDLC controller for channel %d span %d\n", offset, span + 1); + + if (mode != FRMR_MODE_NO_ADDR_CMP) + return -1; + + mode |= FRMR_MODE_HRAC; + + /* Make sure we're in the right mode */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_MODE, mode); + __rxt1_span_framer_out(rxt1_card, span, FRMR_TSEO, 0x00); + __rxt1_span_framer_out(rxt1_card, span, FRMR_TSBS1, 0xff); + + /* Set the interframe gaps, etc */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_CCR1, FRMR_CCR1_ITF | FRMR_CCR1_EITS); + + __rxt1_span_framer_out(rxt1_card, span, FRMR_CCR2, FRMR_CCR2_RCRC); + + /* Set up the time slot that we want to tx/rx on */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_TTR_BASE + (offset / 8), + (0x80 >> (offset % 8))); + __rxt1_span_framer_out(rxt1_card, span, FRMR_RTR_BASE + (offset / 8), + (0x80 >> (offset % 8))); + + imr0 = __rxt1_span_framer_in(rxt1_card, span, FRMR_IMR0); + imr1 = __rxt1_span_framer_in(rxt1_card, span, FRMR_IMR1); + + /* Enable our interrupts again */ + imr0 &= ~HDLC_IMR0_MASK; + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR0, imr0); + + imr1 &= ~HDLC_IMR1_MASK; + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR1, imr1); + + /* Reset the signaling controller */ + __rxt1_span_framer_cmd_wait(rxt1_card, span, FRMR_CMDR_SRES); + + rxt1_span->sigchan = zap_chan; + rxt1_span->sigactive = 0; + + return 0; +} + +static void __rxt1_span_set_clear(struct rxt1_card_t *rxt1_card, int span) +{ + int i, j; + int oldnotclear; + unsigned short val = 0; + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span]; + + oldnotclear = rxt1_span->notclear; + if (rxt1_span->spantype == TYPE_T1) { + for (i = 0; i < 24; i++) { + j = (i / 8); + if (rxt1_span->span.chans[i]->flags & DAHDI_FLAG_CLEAR) { + val |= 1 << (7 - (i % 8)); + rxt1_span->notclear &= ~(1 << i); + } else + rxt1_span->notclear |= (1 << i); + if ((i % 8) == 7) { + if (debug & DEBUG_REGS) + printk("SET CLEAR Putting %d in register %02x on span %d\n", + val, 0x2f + j, span + 1); + __rxt1_span_framer_out(rxt1_card, span, 0x2f + j, val); + val = 0; + } + } + } else { + for (i = 0; i < 31; i++) { + if (rxt1_span->span.chans[i]->flags & DAHDI_FLAG_CLEAR) + rxt1_span->notclear &= ~(1 << i); + else + rxt1_span->notclear |= (1 << i); + } + } + if (rxt1_span->notclear != oldnotclear) { + unsigned char reg; + reg = __rxt1_span_framer_in(rxt1_card, span, FRMR_IMR0); + if (rxt1_span->notclear) + reg &= ~0x08; + else + reg |= 0x08; + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR0, reg); + } +} + +static int rxt1_zap_chan_dacs(struct dahdi_chan *zap_chan_dst, + struct dahdi_chan *zap_chan_src) +{ + struct dahdi_span *span_dst = zap_chan_dst->span; + struct rxt1_span_t *rxt1_span_dst = container_of(span_dst, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card_dst = rxt1_span_dst->owner; + + if (zap_chan_src) { + struct dahdi_span *span_src = zap_chan_src->span; + struct rxt1_span_t *rxt1_span_src = + container_of(span_src, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card_src = rxt1_span_src->owner; + + if (rxt1_card_src != rxt1_card_dst) { + rxt1_card_tsi_unassign(rxt1_card_dst, + zap_chan_dst->span->offset, zap_chan_dst->chanpos); + rxt1_card_tsi_unassign(rxt1_card_src, + zap_chan_src->span->offset, zap_chan_src->chanpos); + return -1; + } + /* channels reside on same card, this card. */ + rxt1_card_tsi_assign(rxt1_card_dst, + zap_chan_src->span->offset, + zap_chan_src->chanpos, + zap_chan_dst->span->offset, zap_chan_dst->chanpos); + if (debug) + printk("Assigning channel %d/%d -> %d/%d!\n", + zap_chan_src->span->offset, zap_chan_src->chanpos, + zap_chan_dst->span->offset, zap_chan_dst->chanpos); + + } else { /* called with bad source channel */ + rxt1_card_tsi_unassign(rxt1_card_dst, + zap_chan_dst->span->offset, zap_chan_dst->chanpos); + } + + return 0; +} + +static int rxt1_zap_chan_ioctl(struct dahdi_chan *zap_chan, unsigned int cmd, + unsigned long data) +{ + struct rxt1_regs regs; + int x; + size_t regs_size; + struct dahdi_span *span = zap_chan->span; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + regs_size = sizeof(regs); + switch (cmd) { + case RXT1_GET_REGS: + for (x = 0; x < NUM_PCI; x++) + regs.pci[x] = rxt1_card_pci_in(rxt1_card, x); + for (x = 0; x < NUM_REGS; x++) + regs.regs[x] = rxt1_span_framer_in(rxt1_card, zap_chan->span->offset, x); + if (copy_to_user((struct rxt1_regs *) data, ®s, regs_size)) + return -EFAULT; + break; + default: + return -ENOTTY; + } + return 0; +} + +static void inline __rxt1_span_hdlc_xmit_fifo(struct rxt1_card_t *rxt1_card, + unsigned int span, + struct rxt1_span_t *rxt1_span) +{ + int res = 0; + int i, size = 32; + unsigned char buf[32]; + +#ifdef DAHDI_SIG_HARDHDLC + res = dahdi_hdlc_getbuf(rxt1_span->sigchan, buf, &size); +#endif + if (debug & DEBUG_FRAMER) + printk("Got buffer sized %d and res %d for %d\n", size, res, span); + if (size > 0) { + rxt1_span->sigactive = 1; + + if (debug & DEBUG_FRAMER) { + printk("TX("); + for (i = 0; i < size; i++) + printk((i ? " %02x" : "%02x"), buf[i]); + printk(")\n"); + } + + for (i = 0; i < size; i++) + __rxt1_span_framer_out(rxt1_card, span, FRMR_TXFIFO, buf[i]); + + if (res) { /* End of message */ + if (debug & DEBUG_FRAMER) + printk("transmiting XHF|XME\n"); + __rxt1_span_framer_cmd_wait(rxt1_card, span, FRMR_CMDR_XHF | FRMR_CMDR_XME); +#if 0 + rxt1_span->sigactive = + (__rxt1_span_framer_in(rxt1_card, span, FRMR_SIS) & FRMR_SIS_XFW) ? 0 : 1; +#endif + ++rxt1_span->frames_out; + if ((debug & DEBUG_FRAMER) && !(rxt1_span->frames_out & 0x0f)) + printk("Transmitted %d frames on span %d\n", rxt1_span->frames_out, span); + } else { /* Still more to transmit */ + if (debug & DEBUG_FRAMER) + printk("transmiting XHF\n"); + __rxt1_span_framer_cmd_wait(rxt1_card, span, FRMR_CMDR_XHF); + } + } else if (res < 0) + rxt1_span->sigactive = 0; +} + +#ifdef DAHDI_SIG_HARDHDLC +static void rxt1_zap_chan_hdlc_hard_xmit(struct dahdi_chan *zap_chan) +{ + struct dahdi_span *span = zap_chan->span; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + unsigned long flags; + + spin_lock_irqsave(&rxt1_card->reglock, flags); + if (!rxt1_span->sigchan) { + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + return; + } + if ((rxt1_span->sigchan == zap_chan) && !rxt1_span->sigactive) + __rxt1_span_hdlc_xmit_fifo(rxt1_card, zap_chan->span->offset, rxt1_span); + spin_unlock_irqrestore(&rxt1_card->reglock, flags); +} +#endif + +static int rxt1_span_maint(struct dahdi_span *span, int cmd) +{ + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + if (rxt1_span->spantype == TYPE_E1) { + switch (cmd) { + case DAHDI_MAINT_NONE: + printk("XXX Turn off local and remote loops E1 XXX\n"); + break; + case DAHDI_MAINT_LOCALLOOP: + printk("XXX Turn on local loopback E1 XXX\n"); + break; + case DAHDI_MAINT_REMOTELOOP: + printk("XXX Turn on remote loopback E1 XXX\n"); + break; + case DAHDI_MAINT_LOOPUP: + printk("XXX Send loopup code E1 XXX\n"); + break; + case DAHDI_MAINT_LOOPDOWN: + printk("XXX Send loopdown code E1 XXX\n"); + break; + case DAHDI_MAINT_LOOPSTOP: + printk("XXX Stop sending loop codes E1 XXX\n"); + break; + default: + printk("R%dT1: Unknown E1 maint command: %d\n", rxt1_card->numspans, cmd); + break; + } + } else { + switch (cmd) { + case DAHDI_MAINT_NONE: + printk("XXX Turn off local and remote loops T1 XXX\n"); + break; + case DAHDI_MAINT_LOCALLOOP: + printk("XXX Turn on local loop and no remote loop XXX\n"); + break; + case DAHDI_MAINT_REMOTELOOP: + printk("XXX Turn on remote loopup XXX\n"); + break; + case DAHDI_MAINT_LOOPUP: + /* FMR5: Nothing but RBS mode */ + rxt1_span_framer_out(rxt1_card, span->offset, 0x21, 0x50); + break; + case DAHDI_MAINT_LOOPDOWN: + /* FMR5: Nothing but RBS mode */ + rxt1_span_framer_out(rxt1_card, span->offset, 0x21, 0x60); + break; + case DAHDI_MAINT_LOOPSTOP: + rxt1_span_framer_out(rxt1_card, span->offset, 0x21, 0x40); /* FMR5: Nothing but RBS mode */ + break; + default: + printk("R%dT1: Unknown T1 maint command: %d\n", rxt1_card->numspans, cmd); + break; + } + } + return 0; +} + +static int rxt1_zap_chan_rbsbits(struct dahdi_chan *zap_chan, int bits) +{ + u_char m, c; + int k, n, b; + struct dahdi_span *span = zap_chan->span; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + k = zap_chan->span->offset; + if (rxt1_span->spantype == TYPE_E1) { /* do it E1 way */ + if (zap_chan->chanpos == 16) { + return 0; + } + n = zap_chan->chanpos - 1; + if (zap_chan->chanpos > 15) + n--; + b = (n % 15); + c = rxt1_span->txsigs[b]; + m = (n / 15) << 2; /* nibble selector */ + c &= (0xf << m); /* keep the other nibble */ + c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ + rxt1_span->txsigs[b] = c; + + /* output them to the chip */ + __rxt1_span_framer_out(rxt1_card, k, 0x71 + b, c); + + } else if (rxt1_span->span.lineconfig & DAHDI_CONFIG_D4) { + n = zap_chan->chanpos - 1; + b = (n / 4); + c = rxt1_span->txsigs[b]; + m = ((3 - (n % 4)) << 1); /* nibble selector */ + c &= ~(0x3 << m); /* keep the other nibble */ + c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */ + rxt1_span->txsigs[b] = c; + + /* output them to the chip */ + __rxt1_span_framer_out(rxt1_card, k, 0x70 + b, c); + __rxt1_span_framer_out(rxt1_card, k, 0x70 + b + 6, c); + + } else if (rxt1_span->span.lineconfig & DAHDI_CONFIG_ESF) { + n = zap_chan->chanpos - 1; + b = (n / 2); + c = rxt1_span->txsigs[b]; + m = ((n % 2) << 2); /* nibble selector */ + c &= (0xf << m); /* keep the other nibble */ + c |= (bits & 0xf) << (4 - m); /* put our new nibble here */ + rxt1_span->txsigs[b] = c; + /* output them to the chip */ + __rxt1_span_framer_out(rxt1_card, k, 0x70 + b, c); + } + + return 0; +} + +static int rxt1_span_shutdown(struct dahdi_span *span) +{ + int span_num; + int wasrunning; + unsigned long flags; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + span_num = span->offset + 1; + if (span_num < 0) { + printk("R%dT1: Span '%d' isn't us?\n", rxt1_card->numspans, span->spanno); + return -1; + } + + if (debug & DEBUG_MAIN) + printk("Shutting down span %d (%s)\n", span->spanno, span->name); + + /* Stop HDLC controller if runned */ + if (rxt1_span->sigchan) + __rxt1_span_hdlc_stop(rxt1_card, span->offset); + + spin_lock_irqsave(&rxt1_card->reglock, flags); + wasrunning = span->flags & DAHDI_FLAG_RUNNING; + + span->flags &= ~DAHDI_FLAG_RUNNING; + + __rxt1_card_set_led(rxt1_card, span->offset, SPAN_OFF); + + if (((rxt1_card->numspans == 4) && + (!(rxt1_card->rxt1_spans[0]->span.flags & DAHDI_FLAG_RUNNING)) && + (!(rxt1_card->rxt1_spans[1]->span.flags & DAHDI_FLAG_RUNNING)) && + (!(rxt1_card->rxt1_spans[2]->span.flags & DAHDI_FLAG_RUNNING)) && + (!(rxt1_card->rxt1_spans[3]->span.flags & DAHDI_FLAG_RUNNING))) + || + ((rxt1_card->numspans == 2) && + (!(rxt1_card->rxt1_spans[0]->span.flags & DAHDI_FLAG_RUNNING)) && + (!(rxt1_card->rxt1_spans[1]->span.flags & DAHDI_FLAG_RUNNING)))) { + /* No longer in use, disable interrupts */ + printk("R%dT1: Disabling interrupts since there are no active spans\n", + rxt1_card->numspans); + rxt1_card->stopdma = 1; + } else + rxt1_card->checktiming = 1; + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + + /* Wait for interrupt routine to shut itself down */ + msleep(10); + if (wasrunning) + rxt1_card->spansstarted--; + + if (debug & DEBUG_MAIN) + printk("DAHDI Span %d (%s) shutdown\n", span->spanno, span->name); + return 0; +} + +static int rxt1_span_startup(struct dahdi_span *span); + +static int rxt1_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *spanconfig) +{ + int i; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + printk("About to enter DAHDI spanconfig!\n"); + if (debug & DEBUG_MAIN) { + printk("R%dT1: Configuring DAHDI span %d\n", rxt1_card->numspans, span->spanno); + printk("lineconfig %x , lbo %x , sync %x\n", spanconfig->lineconfig, + spanconfig->lbo, spanconfig->sync); + + } + + /* XXX We assume lineconfig is okay and shouldn't XXX */ + span->lineconfig = spanconfig->lineconfig; + span->txlevel = spanconfig->lbo; + span->rxlevel = 0; + if (spanconfig->sync < 0) + spanconfig->sync = 0; + if (spanconfig->sync > 4) + spanconfig->sync = 0; + + /* remove this span number from the current sync sources, if there */ + for (i = 0; i < rxt1_card->numspans; i++) { + if (rxt1_card->rxt1_spans[i]->sync == span->spanno) { + rxt1_card->rxt1_spans[i]->sync = 0; + rxt1_card->rxt1_spans[i]->psync = 0; + } + } + rxt1_card->rxt1_spans[span->offset]->syncpos = spanconfig->sync; + /* if a sync src, put it in proper place */ + if (spanconfig->sync) { + rxt1_card->rxt1_spans[spanconfig->sync - 1]->sync = span->spanno; + rxt1_card->rxt1_spans[spanconfig->sync - 1]->psync = span->offset + 1; + } + rxt1_card->checktiming = 1; + + /* If we're already running, then go ahead and apply the changes */ + if (span->flags & DAHDI_FLAG_RUNNING) + return rxt1_span_startup(span); + printk("Done with spanconfig!\n"); + return 0; +} + +static int rxt1_zap_chanconfig(struct dahdi_chan *zap_chan, int sigtype) +{ + int alreadyrunning; + + struct dahdi_span *span = zap_chan->span; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + alreadyrunning = rxt1_span->span.flags & DAHDI_FLAG_RUNNING; + if (debug & DEBUG_MAIN) { + if (alreadyrunning) + printk("R%dT1: Reconfigured channel %d (%s) sigtype %d\n", + rxt1_card->numspans, zap_chan->channo, zap_chan->name, sigtype); + else + printk("R%dT1: Configured channel %d (%s) sigtype %d\n", rxt1_card->numspans, + zap_chan->channo, zap_chan->name, sigtype); + } + + if (alreadyrunning) + __rxt1_span_set_clear(rxt1_card, zap_chan->span->offset); + + /* (re)configure signalling channel */ +#ifdef DAHDI_SIG_HARDHDLC + if ((sigtype == DAHDI_SIG_HARDHDLC) || (rxt1_span->sigchan == zap_chan)) { +#else + if (rxt1_span->sigchan == zap_chan) { +#endif +#ifdef DAHDI_SIG_HARDHDLC + if (debug & DEBUG_FRAMER) + printk("%sonfiguring hardware HDLC on %s\n", + ((sigtype == DAHDI_SIG_HARDHDLC) ? "C" : "Unc"), zap_chan->name); +#endif + if (alreadyrunning) { + if (rxt1_span->sigchan) + __rxt1_span_hdlc_stop(rxt1_card, rxt1_span->sigchan->span->offset); +#ifdef DAHDI_SIG_HARDHDLC + if (sigtype == DAHDI_SIG_HARDHDLC) { + if (__rxt1_hdlc_start_chan + (rxt1_card, zap_chan->span->offset, zap_chan, rxt1_span->sigmode)) { + printk("Error initializing signalling controller\n"); + return -1; + } + } else +#endif + rxt1_span->sigchan = NULL; + } else { +#ifdef DAHDI_SIG_HARDHDLC + rxt1_span->sigchan = (sigtype == DAHDI_SIG_HARDHDLC) ? zap_chan : NULL; +#else + rxt1_span->sigchan = NULL; +#endif + + rxt1_span->sigactive = 0; + } + } + return 0; +} + +static int rxt1_zap_chan_open(struct dahdi_chan *zap_chan) +{ + try_module_get(THIS_MODULE); + return 0; +} + +static int rxt1_zap_chan_close(struct dahdi_chan *zap_chan) +{ + module_put(THIS_MODULE); + return 0; +} + +static struct dahdi_span_ops ops_with_echocan = { + .spanconfig = rxt1_spanconfig, + .chanconfig = rxt1_zap_chanconfig, + .startup = rxt1_span_startup, + .shutdown = rxt1_span_shutdown, + .rbsbits = rxt1_zap_chan_rbsbits, + .maint = rxt1_span_maint, + .open = rxt1_zap_chan_open, + .close = rxt1_zap_chan_close, + .ioctl = rxt1_zap_chan_ioctl, + .dacs = rxt1_zap_chan_dacs, + .echocan_create = rxt1_echocan_create, +#ifdef DAHDI_SIG_HARDHDLC + .hdlc_hard_xmit = rxt1_zap_chan_hdlc_hard_xmit, +#endif + .owner = THIS_MODULE, +}; + +static struct dahdi_span_ops ops_without_echocan = { + .spanconfig = rxt1_spanconfig, + .chanconfig = rxt1_zap_chanconfig, + .startup = rxt1_span_startup, + .shutdown = rxt1_span_shutdown, + .rbsbits = rxt1_zap_chan_rbsbits, + .maint = rxt1_span_maint, + .open = rxt1_zap_chan_open, + .close = rxt1_zap_chan_close, + .ioctl = rxt1_zap_chan_ioctl, + .dacs = rxt1_zap_chan_dacs, +#ifdef DAHDI_SIG_HARDHDLC + .hdlc_hard_xmit = rxt1_zap_chan_hdlc_hard_xmit, +#endif + .owner = THIS_MODULE, +}; + +static void rxt1_card_init_spans(struct rxt1_card_t *rxt1_card) +{ + int span_num, chan_num /*,c */ ; + int offset = 1; + struct rxt1_span_t *rxt1_span; + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_span = rxt1_card->rxt1_spans[span_num]; + sprintf(rxt1_span->span.name, "R%dT1/%d/%d", rxt1_card->numspans, + rxt1_card->num, span_num + 1); + sprintf(rxt1_span->span.desc, "R%dT1 (PCI) Card %d Span %d", rxt1_card->numspans, + rxt1_card->num, span_num + 1); + rxt1_span->span.manufacturer = "Rhino Equipment"; + + + /* HDLC Specific init */ + rxt1_span->sigchan = NULL; + rxt1_span->sigmode = sigmode; + rxt1_span->sigactive = 0; + + if (rxt1_span->spantype == TYPE_T1 || rxt1_span->spantype == TYPE_J1) { + rxt1_span->span.channels = 24; + rxt1_span->span.deflaw = DAHDI_LAW_MULAW; + } else { + rxt1_span->span.channels = 31; + rxt1_span->span.deflaw = DAHDI_LAW_ALAW; + } + +#ifdef DAHDI_GT_1471 + switch (rxt1_span->spantype) { + case TYPE_T1: + rxt1_span->span.spantype = "T1"; + + break; + case TYPE_E1: + rxt1_span->span.spantype = "E1"; + + break; + case TYPE_J1: + rxt1_span->span.spantype = "J1"; + + break; + } +#endif + + switch (rxt1_span->spantype) { + case TYPE_T1: + rxt1_span->span.linecompat = + DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; + break; + case TYPE_E1: + rxt1_span->span.linecompat = + DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | + DAHDI_CONFIG_CRC4; + break; + case TYPE_J1: + rxt1_span->span.linecompat = + DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; + break; + } + + rxt1_span->span.chans = rxt1_span->chans; + rxt1_span->span.flags = DAHDI_FLAG_RBS; + + + rxt1_span->owner = rxt1_card; + rxt1_span->span.offset = span_num; + rxt1_span->writechunk = (void *) (rxt1_card->writechunk + span_num * 32 * 2); + rxt1_span->readchunk = (void *) (rxt1_card->readchunk + span_num * 32 * 2); + if (show_pointers == 1) + printk("Span %d writechunk %x readchunk %x\n", span_num, + (__u32) rxt1_span->writechunk, (__u32) rxt1_span->readchunk); + init_waitqueue_head(&rxt1_span->span.maintq); + for (chan_num = 0; chan_num < rxt1_card->rxt1_spans[span_num]->span.channels; + chan_num++) { + sprintf(rxt1_span->chans[chan_num]->name, "R%dT1/%d/%d/%d", + rxt1_card->numspans, rxt1_card->num, span_num + 1, chan_num + 1); + rxt1_span->chans[chan_num]->sigcap = + DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | + DAHDI_SIG_FXSKS | +#ifdef DAHDI_SIG_HARDHDLC + DAHDI_SIG_HARDHDLC | +#endif +#ifdef DAHDI_SIG_FXONS + DAHDI_SIG_FXONS | +#endif + DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | + DAHDI_SIG_EM_E1 | DAHDI_SIG_DACS_RBS; + + rxt1_span->chans[chan_num]->pvt = rxt1_card; + rxt1_span->chans[chan_num]->chanpos = chan_num + 1; + rxt1_span->chans[chan_num]->writechunk = + (void *) (rxt1_card->writechunk + + (span_num * 32 + chan_num + offset) * 2); + rxt1_span->chans[chan_num]->readchunk = + (void *) (rxt1_card->readchunk + (span_num * 32 + chan_num + offset) * 2); + rxt1_span->chans[chan_num]->span = &rxt1_span->span; + + if (show_pointers) + printk("R%dT1: Span %d Chan %d writechunk %p readchunk %p\n", + rxt1_card->numspans, span_num, chan_num, + rxt1_span->chans[chan_num]->writechunk, + rxt1_span->chans[chan_num]->readchunk); + } + } +} + +static void rxt1_span_serial_setup(struct rxt1_card_t *rxt1_card, int span) +{ + unsigned char lim0 = 8; + lim0 |= (__rxt1_span_framer_in(rxt1_card, span, 0x36) & 1); + if (!rxt1_card->globalconfig) { /* just do glabal section once */ + rxt1_card->globalconfig = 1; + printk("R%dT1: Setting up global serial parameters on Span %d\n", + rxt1_card->numspans, span); + /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */ + rxt1_span_framer_out(rxt1_card, 0, 0x85, 0xe0); + /* IPC: Interrupt push/pull active low */ + rxt1_span_framer_out(rxt1_card, 0, 0x08, 0x01); + + /* Global clocks (8.192 Mhz CLK) */ + rxt1_span_framer_out(rxt1_card, 0, 0x92, 0x00); + rxt1_span_framer_out(rxt1_card, 0, 0x93, 0x18); + rxt1_span_framer_out(rxt1_card, 0, 0x94, 0xfb); + rxt1_span_framer_out(rxt1_card, 0, 0x95, 0x0b); + rxt1_span_framer_out(rxt1_card, 0, 0x96, 0x00); + rxt1_span_framer_out(rxt1_card, 0, 0x97, 0x0b); + rxt1_span_framer_out(rxt1_card, 0, 0x98, 0xdb); + rxt1_span_framer_out(rxt1_card, 0, 0x99, 0xdf); + + if (rxt1_card->numspans == 2) { + rxt1_span_framer_out(rxt1_card, 2, FRMR_LIM1, 0x09); /* 137 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_LIM0, 0x02); /* 136 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_XSP, 0x20); /* 121 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_FMR2, 0x10); /* 11e */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_IDLE, 0x00); /* 12b */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_ICB1, 0xff); /* 132 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_ICB2, 0xff); /* 133 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_ICB3, 0xff); /* 134 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_ICB4, 0xff); /* 135 */ + rxt1_span_framer_out(rxt1_card, 2, FRMR_CMR2, 0x0c); /* 145 */ + + rxt1_span_framer_out(rxt1_card, 2, FRMR_SIC2, 0x20 | (2 << 1)); + rxt1_span_framer_out(rxt1_card, 2, FRMR_XC0, 0x00); + rxt1_span_framer_out(rxt1_card, 2, FRMR_XC1, xmit_off); + rxt1_span_framer_out(rxt1_card, 2, FRMR_RC0, 0x00); + rxt1_span_framer_out(rxt1_card, 2, FRMR_RC1, recd_off); + + rxt1_span_framer_out(rxt1_card, 3, FRMR_LIM1, 0x09); /* 337 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_LIM0, 0x02); /* 336 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_XSP, 0x20); /* 321 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_FMR2, 0x10); /* 31e */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_IDLE, 0x00); /* 32b */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_ICB1, 0xff); /* 332 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_ICB2, 0xff); /* 333 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_ICB3, 0xff); /* 334 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_ICB4, 0xff); /* 335 */ + rxt1_span_framer_out(rxt1_card, 3, FRMR_CMR2, 0x0c); /* 345 */ + + rxt1_span_framer_out(rxt1_card, 3, FRMR_SIC2, 0x20 | (3 << 1)); + rxt1_span_framer_out(rxt1_card, 3, FRMR_XC0, 0x00); + rxt1_span_framer_out(rxt1_card, 3, FRMR_XC1, xmit_off); + rxt1_span_framer_out(rxt1_card, 3, FRMR_RC0, 0x00); + rxt1_span_framer_out(rxt1_card, 3, FRMR_RC1, recd_off); + } + } + + /* Configure interrupts */ + /* GCR: Interrupt on Activation/Deactivation of each */ + rxt1_span_framer_out(rxt1_card, span, FRMR_GCR, 0x00); + + if (local_loop == 1) + lim0 |= 2; + if (monitor_mode & (1 << span)) + lim0 |= 4; + if (gen_clk & (1 << span)) + lim0 |= 1; + + if (debug & DEBUG_FRAMER) + printk("Span %x LIM0 %X\n", span, lim0); + /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ + rxt1_span_framer_out(rxt1_card, span, 0x36, lim0); + + if (insert_idle == 1) { + if (span == 0) { + rxt1_span_framer_out(rxt1_card, span, FRMR_IDLE, 0x00); /* IDLE code */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB1, 0x00); /* IDLE enable slot 7-0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB2, 0xff); /* ... 15-8 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB3, 0xff); /* ... 23-16 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB4, 0xff); /* ... 31-24 */ + } + if (span == 1) { + rxt1_span_framer_out(rxt1_card, span, FRMR_IDLE, 0xff); /* IDLE code for test */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB1, 0xff); /* IDLE enable slot 7-0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB2, 0xff); /* ... 15-8 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB3, 0xff); /* ... 23-16 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB4, 0xff); /* ... 31-24 */ + } + if (span == 2) { + rxt1_span_framer_out(rxt1_card, span, FRMR_IDLE, 0xff); /* IDLE code for test */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB1, 0xff); /* IDLE enable slot 7-0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB2, 0xff); /* ... 15-8 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB3, 0xff); /* ... 23-16 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB4, 0xff); /* ... 31-24 */ + } + if (span == 3) { + rxt1_span_framer_out(rxt1_card, span, FRMR_IDLE, 0xff); /* IDLE code for test */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB1, 0xff); /* IDLE enable slot 7-0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB2, 0xff); /* ... 15-8 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB3, 0xff); /* ... 23-16 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB4, 0xff); /* ... 31-24 */ + } + } else { + rxt1_span_framer_out(rxt1_card, span, FRMR_IDLE, 0xff); /* IDLE code */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB1, 0x00); /* IDLE enable slot 7-0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB2, 0x00); /* ... 15-8 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB3, 0x00); /* ... 23-16 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_ICB4, 0x00); /* ... 31-24 */ + } + + /* Configure system interface */ + /* SIC1: 8.192 Mhz clock/bus, double buffer receive / transmit, byte interleaved */ + rxt1_span_framer_out(rxt1_card, span, FRMR_SIC1, 0xc2); + /* SIC2: No FFS, no center receive eliastic buffer, phase */ + rxt1_span_framer_out(rxt1_card, span, FRMR_SIC2, 0x20 | ((span + 0) << 1)); + /* SIC3: Edges for capture */ + rxt1_span_framer_out(rxt1_card, span, FRMR_SIC3, sic3_set); + /* CMR2: We provide sync and clock for tx and rx. */ + rxt1_span_framer_out(rxt1_card, span, FRMR_CMR2, 0x00); + if (!rxt1_card->t1e1) { /* T1 mode */ + /* XC0: Normal operation of Sa-bits */ + rxt1_span_framer_out(rxt1_card, span, FRMR_XC0, 0x00); + /* XC1: 0 offset */ + rxt1_span_framer_out(rxt1_card, span, FRMR_XC1, xmit_off); + if (rxt1_card->rxt1_spans[span]->spantype == TYPE_J1) + /* RC0: Just shy of 1023 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC0, 0x80); + else + /* RC0: Just shy of 1023 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC0, 0x00); + + if (rxt1_card->numspans == 2) + /* RC1: The rest of RC0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC1, recd_off); + else + /* RC1: The rest of RC0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC1, recq_off); + } else { /* E1 mode */ + /* XC0: Normal operation of Sa-bits */ + rxt1_span_framer_out(rxt1_card, span, FRMR_XC0, 0x00); + /* XC1: 0 offset */ + rxt1_span_framer_out(rxt1_card, span, FRMR_XC1, xmit_off); + /* RC0: Just shy of 1023 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC0, 0x00); + if (rxt1_card->numspans == 2) + /* RC1: The rest of RC0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC1, recd_off); + else + /* RC1: The rest of RC0 */ + rxt1_span_framer_out(rxt1_card, span, FRMR_RC1, recq_off); + } + + /* Configure ports */ + /* PC1: SPYR/SPYX input on RPA/XPA */ + rxt1_span_framer_out(rxt1_card, span, 0x80, 0x00); + /* PC2: RMFB/XSIG output/input on RPB/XPB */ + rxt1_span_framer_out(rxt1_card, span, 0x81, 0xf7); + /* PC3: Some unused stuff */ + rxt1_span_framer_out(rxt1_card, span, 0x82, 0xf7); + /* PC4: Some more unused stuff */ + rxt1_span_framer_out(rxt1_card, span, 0x83, 0xf7); + /* PC5: XMFS active low, SCLKR is input, RCLK is output */ + rxt1_span_framer_out(rxt1_card, span, 0x84, 0x01); + if (debug & DEBUG_MAIN) + printk("Successfully initialized serial bus for span %d\n", span); +} + +static int syncsrc = 3; /* Zaptel span number */ +static int syncnum = 0 /* -1 */ ; /* rxt1 card number */ +static int syncspan = 0; /* span on given rxt1 card */ +#ifdef DEFINE_SPINLOCK +static DEFINE_SPINLOCK(synclock); +#else +static spinlock_t synclock = SPIN_LOCK_UNLOCKED; +#endif + +static void __rxt1_card_set_timing_source(struct rxt1_card_t *rxt1_card, int src_span, + int master, int slave) +{ + unsigned int timing; + int span_num; + if (src_span != rxt1_card->syncsrc) { + /* CMR1: RCLK src_span, 8.192 Mhz TCLK, RCLK is 8.192 Mhz */ + timing = 0x34; + if ((src_span > -1) && (src_span < 4)) { + if (rxt1_card->numspans == 4) + timing |= (src_span << 6); + else + timing |= (src_span << 7); + + /* set all 4 receive reference clocks to src_span */ + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) + __rxt1_span_framer_out(rxt1_card, span_num, 0x44, timing); + } else { + /* set each receive reference clock to itself */ + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + if (rxt1_card->numspans == 4) + __rxt1_span_framer_out(rxt1_card, span_num, 0x44, + timing | (span_num << 6)); + else + __rxt1_span_framer_out(rxt1_card, span_num, 0x44, + timing | (span_num << 7)); + } + } + + if (!master && !slave) + rxt1_card->syncsrc = src_span; + if ((src_span < 0) || (src_span > 3)) + src_span = 0; + else + src_span++; + if (!master && !slave) { + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) + rxt1_card->rxt1_spans[span_num]->span.syncsrc = src_span; + } + } else { + /* already set */ + if (debug & DEBUG_MAIN) + printk("r%d11: Set Timing source already set to %d\n", rxt1_card->numspans, + src_span); + } + if (debug && DEBUG_MAIN) { + printk("R%dT1_card: Set Timing source set to %d master %d slave %d\n", + rxt1_card->numspans, src_span, master, slave); + printk("R%dT1_card: Zap Span Timing Src %d on Card %d Span %d\n", + rxt1_card->numspans, syncsrc, syncnum, syncspan); + } +} + +static inline void __rxt1_card_update_timing(struct rxt1_card_t *rxt1_card) +{ + int span_num; + /* update sync src info */ + if (debug && DEBUG_MAIN) { + printk("R%dT1_card: Update Timing source set to %d\n", rxt1_card->numspans, + rxt1_card->syncsrc); + printk("R%dT1_card: Zap Span Timing Src %d on Card %d Span %d\n", + rxt1_card->numspans, syncsrc, syncnum, syncspan); + } + + if (rxt1_card->syncsrc != syncsrc) { + printk("R%dT1: Swapping card %d from %d to %d\n", rxt1_card->numspans, + rxt1_card->num, rxt1_card->syncsrc, syncsrc); + rxt1_card->syncsrc = syncsrc; + /* Update sync sources */ + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card->rxt1_spans[span_num]->span.syncsrc = rxt1_card->syncsrc; + } + if (syncnum == rxt1_card->num) { /* M S */ + __rxt1_card_set_timing_source(rxt1_card, syncspan - 1, 1, 0); + if (debug) + printk("R%dT1 card %d, using sync span %d, master\n", rxt1_card->numspans, + rxt1_card->num, syncspan); + } else { /* M S */ + __rxt1_card_set_timing_source(rxt1_card, syncspan - 1, 0, 1); + if (debug) + printk("R%dT1 card %d, using Timing Bus, NOT master\n", + rxt1_card->numspans, rxt1_card->num); + } + } +} + +static int __rxt1_card_findsync(struct rxt1_card_t *rxt1_card) +{ + int i; + int x; + unsigned long flags; + int p; + int nonzero; + int newsyncsrc = 0; /* Zaptel span number */ + int newsyncnum = 0; /* rxt1 card number */ + int newsyncspan = 0; /* span on given rxt1 card */ + spin_lock_irqsave(&synclock, flags); + + if (!rxt1_card->num) { + /* If we're the first card, go through all the motions, up to 8 levels + of sync source */ + p = 1; + while (p < 8) { + nonzero = 0; + for (x = 0; rxt1_cards[x]; x++) { + for (i = 0; i < rxt1_card->numspans; i++) { + if (rxt1_cards[x]->rxt1_spans[i]->syncpos) { + nonzero = 1; + if ((rxt1_cards[x]->rxt1_spans[i]->syncpos == p) && + !(rxt1_cards[x]->rxt1_spans[i]-> + span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | + DAHDI_ALARM_LOOPBACK)) && + (rxt1_cards[x]->rxt1_spans[i]-> + span.flags & DAHDI_FLAG_RUNNING)) { + /* This makes a good sync source */ + newsyncsrc = rxt1_cards[x]->rxt1_spans[i]->span.spanno; + newsyncnum = x; + newsyncspan = i + 1; + /* Jump out */ + goto found; + } + } + } + } + if (nonzero) + p++; + else + break; + } + found: + if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || + (newsyncspan != syncspan)) { + syncnum = newsyncnum; + syncsrc = newsyncsrc; + syncspan = newsyncspan; + for (x = 0; rxt1_cards[x]; x++) { + __rxt1_card_update_timing(rxt1_cards[x]); + } + } + } else + rxt1_cards[0]->checktiming = 1; + + spin_unlock_irqrestore(&synclock, flags); + + if (debug && DEBUG_MAIN) { + printk("R%dT1_card: Find Timing source set to %d\n", rxt1_card->numspans, + rxt1_card->syncsrc); + printk("R%dT1_card: Zap Span Timing Src %d on Card %d Span %d\n", + rxt1_card->numspans, syncsrc, syncnum, syncspan); + } + + return 0; +} + +static void __rxt1_card_set_timing_source_auto(struct rxt1_card_t *rxt1_card) +{ + int span_num; + if (debug && DEBUG_MAIN) + printk("R%dT1: Timing source auto card %d!\n", rxt1_card->numspans, + rxt1_card->num); + + rxt1_card->checktiming = 0; + if (timingcable) { + __rxt1_card_findsync(rxt1_card); + } else { + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + if (rxt1_card->rxt1_spans[span_num]->sync) { + if ((rxt1_card->rxt1_spans[rxt1_card->rxt1_spans[span_num]->psync - + 1]->span.flags & DAHDI_FLAG_RUNNING) && + !(rxt1_card->rxt1_spans[rxt1_card->rxt1_spans[span_num]->psync - + 1]->span. + alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE))) { + /* Valid timing source *//* M S */ + __rxt1_card_set_timing_source(rxt1_card, + rxt1_card->rxt1_spans[span_num]->psync - + 1, 0, 0); + return; + } + } + } /* X M S */ + __rxt1_card_set_timing_source(rxt1_card, 4, 0, 0); + } + if (debug && DEBUG_MAIN) { + printk("R%dT1_card: Set auto Timing source set to %d\n", rxt1_card->numspans, + rxt1_card->syncsrc); + printk("R%dT1_card: Zap Span Timing Src %d on Card %d Span %d\n", + rxt1_card->numspans, syncsrc, syncnum, syncspan); + } +} + +static void __rxt1_span_configure_t1(struct rxt1_card_t *rxt1_card, int span, + int lineconfig, int txlevel) +{ + unsigned int fmr4, fmr2, fmr1, fmr0, lim2, lim0; + char *framing, *line; + int mytxlevel; + if ((txlevel > 7) || (txlevel < 4)) + mytxlevel = 0; + else + mytxlevel = txlevel - 4; + /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */ + fmr1 = 0x9c; + /* FMR2: no payload loopback, auto send yellow alarm */ + fmr2 = 0x22; + if (loopback) + fmr2 |= 0x4; + /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */ + fmr4 = 0x0c; + /* LIM2: 50% peak is a "1", Advanced Loss recovery */ + lim2 = 0x21; + /* LIM2: Add line buildout */ + lim2 |= (mytxlevel << 6); + __rxt1_span_framer_out(rxt1_card, span, 0x1d, fmr1); + __rxt1_span_framer_out(rxt1_card, span, 0x1e, fmr2); + + /* Configure line interface */ + if (lineconfig & DAHDI_CONFIG_AMI) { + line = "AMI"; + fmr0 = 0xf0; + } else { + line = "B8ZS"; + fmr0 = 0xf0; + } + if (lineconfig & DAHDI_CONFIG_D4) { + framing = "D4"; + } else { + framing = "ESF"; + fmr4 |= 0x2; + fmr2 |= 0xc0; + } + lim0 = 8 | (__rxt1_span_framer_in(rxt1_card, span, 0x36) & 1); + if (local_loop == 1) + lim0 |= 2; + if (monitor_mode & (1 << span)) + lim0 |= 4; + __rxt1_span_framer_out(rxt1_card, span, 0x1c, fmr0); + __rxt1_span_framer_out(rxt1_card, span, 0x20, fmr4); + /* FMR5: Enable RBS mode */ + __rxt1_span_framer_out(rxt1_card, span, 0x21, 0x40); + + /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), + * No remote loop, no DRS */ + __rxt1_span_framer_out(rxt1_card, span, 0x37, 0xf8); + /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ + __rxt1_span_framer_out(rxt1_card, span, 0x36, lim0); + + /* CMDR: Reset the receiver and transmitter line interface */ + __rxt1_span_framer_out(rxt1_card, span, 0x02, 0x50); + /* CMDR: Reset the receiver and transmitter line interface */ + __rxt1_span_framer_out(rxt1_card, span, 0x02, 0x00); + + /* LIM2: 50% peak amplitude is a "1" */ + __rxt1_span_framer_out(rxt1_card, span, 0x3a, lim2); + /* PCD: LOS after 176 consecutive "zeros" */ + __rxt1_span_framer_out(rxt1_card, span, 0x38, 0x0a); + /* PCR: 22 "ones" clear LOS */ + __rxt1_span_framer_out(rxt1_card, span, 0x39, 0x15); + + /* Generate pulse mask for T1 */ + switch (mytxlevel) { + case 3: + __rxt1_span_framer_out(rxt1_card, span, 0x26, 0x07); /* XPM0 */ + __rxt1_span_framer_out(rxt1_card, span, 0x27, 0x01); /* XPM1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x28, 0x00); /* XPM2 */ + break; + case 2: + __rxt1_span_framer_out(rxt1_card, span, 0x26, 0x8c); /* XPM0 */ + __rxt1_span_framer_out(rxt1_card, span, 0x27, 0x11); /* XPM1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x28, 0x01); /* XPM2 */ + break; + case 1: + __rxt1_span_framer_out(rxt1_card, span, 0x26, 0x8c); /* XPM0 */ + __rxt1_span_framer_out(rxt1_card, span, 0x27, 0x01); /* XPM1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x28, 0x00); /* XPM2 */ + break; + case 0: + default: + __rxt1_span_framer_out(rxt1_card, span, 0x26, 0xd7); /* XPM0 */ + __rxt1_span_framer_out(rxt1_card, span, 0x27, 0x22); /* XPM1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x28, 0x01); /* XPM2 */ + break; + } + + /* Don't mask framer interrupts if hardware HDLC is in use */ + /* IMR0: We care about CAS changes, etc */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR0, + 0xff & ~((rxt1_card->rxt1_spans[span]->sigchan) ? + HDLC_IMR0_MASK : 0)); + /* IMR1: We care about nothing */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR1, + 0xff & ~((rxt1_card->rxt1_spans[span]->sigchan) ? + HDLC_IMR1_MASK : 0)); + /* IMR2: We care about all the alarm stuff! */ + __rxt1_span_framer_out(rxt1_card, span, 0x16, 0x00); + if (debugslips) { + /* IMR3: We care about AIS and friends */ + __rxt1_span_framer_out(rxt1_card, span, 0x17, 0xf4); + /* IMR4: We care about slips on transmit */ + __rxt1_span_framer_out(rxt1_card, span, 0x18, 0x3f); + } else { + /* IMR3: We care about AIS and friends */ + __rxt1_span_framer_out(rxt1_card, span, 0x17, 0xf7); + /* IMR4: We don't care about slips on transmit */ + __rxt1_span_framer_out(rxt1_card, span, 0x18, 0xff); + } + + if (!polling) { + rxt1_span_check_alarms(rxt1_card, span); + rxt1_span_check_sigbits(rxt1_card, span); + } + + if (debug & DEBUG_MAIN) + printk("R%dT1: Span %d configured for %s/%s\n", rxt1_card->numspans, span + 1, + framing, line); +} + +static void __rxt1_span_configure_e1(struct rxt1_card_t *rxt1_card, int span, + int lineconfig) +{ + unsigned int fmr2, fmr1, fmr0; + unsigned int cas = 0; + unsigned int imr3extra = 0; + char *crc4 = ""; + char *framing, *line; + /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */ + fmr1 = 0x44; + /* FMR2: Auto transmit remote alarm, auto loss of multiframe recovery, + * no payload loopback */ + fmr2 = 0x03; + if (loopback) + fmr2 |= 0x4; + if (lineconfig & DAHDI_CONFIG_CRC4) { + /* CRC4 transmit */ + fmr1 |= 0x08; + /* CRC4 receive */ + fmr2 |= 0xc0; + crc4 = "/CRC4"; + } + __rxt1_span_framer_out(rxt1_card, span, 0x1d, fmr1); + __rxt1_span_framer_out(rxt1_card, span, 0x1e, fmr2); + + /* Configure line interface */ + if (lineconfig & DAHDI_CONFIG_AMI) { + line = "AMI"; + fmr0 = 0xa0; + } else { + line = "HDB3"; + fmr0 = 0xf0; + } + if (lineconfig & DAHDI_CONFIG_CCS) { + framing = "CCS"; + imr3extra = 0x28; + } else { + framing = "CAS"; + cas = 0x40; + } + __rxt1_span_framer_out(rxt1_card, span, 0x1c, fmr0); + + /* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), + * No remote loop, no DRS */ + __rxt1_span_framer_out(rxt1_card, span, 0x37, 0xf8); + /* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */ + __rxt1_span_framer_out(rxt1_card, span, 0x36, 0x08); + + /* CMDR: Reset the receiver and transmitter line interface */ + __rxt1_span_framer_out(rxt1_card, span, 0x02, 0x50); + /* CMDR: Reset the receiver and transmitter line interface */ + __rxt1_span_framer_out(rxt1_card, span, 0x02, 0x00); + + /* Condition receive line interface for E1 after reset */ + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x17); + __rxt1_span_framer_out(rxt1_card, span, 0xbc, 0x55); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x97); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x11); + __rxt1_span_framer_out(rxt1_card, span, 0xbc, 0xaa); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x91); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x12); + __rxt1_span_framer_out(rxt1_card, span, 0xbc, 0x55); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x92); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x0c); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x00); + __rxt1_span_framer_out(rxt1_card, span, 0xbb, 0x8c); + + /* LIM2: 50% peak amplitude is a "1" */ + __rxt1_span_framer_out(rxt1_card, span, 0x3a, 0x20); + /* PCD: LOS after 176 consecutive "zeros" */ + __rxt1_span_framer_out(rxt1_card, span, 0x38, 0x0a); + /* PCR: 22 "ones" clear LOS */ + __rxt1_span_framer_out(rxt1_card, span, 0x39, 0x15); + + /* XSW: Spare bits all to 1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x20, 0x9f); + /* XSP: E-bit set when async. AXS auto, XSIF to 1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x21, 0x1c | cas); + + + /* Generate pulse mask for E1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x26, 0x54); /* XPM0 */ + __rxt1_span_framer_out(rxt1_card, span, 0x27, 0x02); /* XPM1 */ + __rxt1_span_framer_out(rxt1_card, span, 0x28, 0x00); /* XPM2 */ + + /* Don't mask framer interrupts if hardware HDLC is in use */ + /* IMR0: We care about CRC errors, CAS changes, etc */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR0, + 0xff & ~((rxt1_card->rxt1_spans[span]->sigchan) ? + HDLC_IMR0_MASK : 0)); + /* IMR1: We care about loopup / loopdown */ + __rxt1_span_framer_out(rxt1_card, span, FRMR_IMR1, + 0x3f & ~((rxt1_card->rxt1_spans[span]->sigchan) ? + HDLC_IMR1_MASK : 0)); + /* IMR2: We care about all the alarm stuff! */ + __rxt1_span_framer_out(rxt1_card, span, 0x16, 0x00); + if (debugslips) { + /* IMR3: We care about AIS and friends */ + __rxt1_span_framer_out(rxt1_card, span, 0x17, 0xc4 | imr3extra); + /* IMR4: We care about slips on transmit */ + __rxt1_span_framer_out(rxt1_card, span, 0x18, 0x3f); + } else { + /* IMR3: We care about AIS and friends */ + __rxt1_span_framer_out(rxt1_card, span, 0x17, 0xc7 | imr3extra); + /* IMR4: We don't care about slips on transmit */ + __rxt1_span_framer_out(rxt1_card, span, 0x18, 0xff); + } + if (!polling) { + rxt1_span_check_alarms(rxt1_card, span); + rxt1_span_check_sigbits(rxt1_card, span); + } + + if (debug & DEBUG_MAIN) + printk("R%dT1: Span %d configured for %s/%s%s\n", rxt1_card->numspans, span + 1, + framing, line, crc4); +} + +static int rxt1_span_startup(struct dahdi_span *span) +{ + int chan_num; + int tspan; + int alreadyrunning; + + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + if (debug & DEBUG_MAIN) + printk("R%dT1: About to enter startup!\n", rxt1_card->numspans); + tspan = span->offset + 1; + if (tspan < 0) { + printk("R%dT1: Span '%d' isn't us?\n", rxt1_card->numspans, span->spanno); + return -1; + } + + alreadyrunning = span->flags & DAHDI_FLAG_RUNNING; + + /* initialize the start value for the entire chunk of last ec buffer */ + for (chan_num = 0; chan_num < span->channels; chan_num++) { + memset(rxt1_span->ec_chunk1[chan_num], + DAHDI_LIN2X(0, span->chans[chan_num]), DAHDI_CHUNKSIZE); + memset(rxt1_span->ec_chunk2[chan_num], + DAHDI_LIN2X(0, span->chans[chan_num]), DAHDI_CHUNKSIZE); + } + + /* Force re-evaluation fo timing source */ + if (timingcable) + rxt1_card->syncsrc = -1; + + if (rxt1_span->spantype == TYPE_E1) { /* if this is an E1 card */ + __rxt1_span_configure_e1(rxt1_card, span->offset, span->lineconfig); + } else { /* is a T1 card */ + __rxt1_span_configure_t1(rxt1_card, span->offset, span->lineconfig, + span->txlevel); + } + + /* Note clear channel status */ + rxt1_card->rxt1_spans[span->offset]->notclear = 0; + __rxt1_span_set_clear(rxt1_card, span->offset); + + if (!alreadyrunning) { + span->flags |= DAHDI_FLAG_RUNNING; + rxt1_card->spansstarted++; + + /* enable interrupts */ + /* Start DMA, enabling DMA interrupts on read only */ + rxt1_card->nextbuf = 0; + + /* this is for test -- remove */ + rxt1_card->dmactrl |= FRMR_IMSK; + rxt1_card->dmactrl &= ~(DMA_IMSK); + rxt1_card->dmactrl |= (DMA_GO | FRMR_IEN); + __rxt1_card_pci_out(rxt1_card, RXT1_DMA + TARG_REGS, rxt1_card->dmactrl, + target_regs[RXT1_DMA].iomask); + + /* Startup HDLC controller too */ + if (rxt1_span->sigchan) { + if (__rxt1_hdlc_start_chan + (rxt1_card, span->offset, rxt1_span->sigchan, rxt1_span->sigmode)) { + printk("R%dT1: Error initializing signalling controller\n", + rxt1_card->numspans); + return -1; + } + } + + if (!polling) { + rxt1_span_check_alarms(rxt1_card, span->offset); + rxt1_span_check_sigbits(rxt1_card, span->offset); + } + } + + if (rxt1_card->rxt1_spans[0]->sync == span->spanno) + printk("R%dT1: SPAN %d: Primary Sync Source\n", rxt1_card->numspans, + span->spanno); + if (rxt1_card->rxt1_spans[1]->sync == span->spanno) + printk("R%dT1: SPAN %d: Secondary Sync Source\n", rxt1_card->numspans, + span->spanno); + if (rxt1_card->numspans == 4) { + if (rxt1_card->rxt1_spans[2]->sync == span->spanno) + printk("R%dT1: SPAN %d: Tertiary Sync Source\n", rxt1_card->numspans, + span->spanno); + if (rxt1_card->rxt1_spans[3]->sync == span->spanno) + printk("R%dT1: SPAN %d: Quaternary Sync Source\n", rxt1_card->numspans, + span->spanno); + } + + if (debug & DEBUG_MAIN) + printk("R%dT1: Completed Span %d startup!\n", rxt1_card->numspans, tspan); + + return 0; +} + + +#if (DAHDI_CHUNKSIZE != 8) +#error Sorry, rxt1 does not support chunksize != 8 +#endif + +static inline void __rxt1_receive_span(struct rxt1_span_t *rxt1_span) +{ + int chan_num, samp_num; + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + if (show_pointers == 1) { + + if ((rxt1_card->intcount > 100) && (rxt1_card->intcount < 104)) { + + printk("R%dT1: Span %d writechunk %p readchunk %p int %d\n", + rxt1_card->numspans, rxt1_span->span.offset, rxt1_span->writechunk, + rxt1_span->readchunk, rxt1_card->intcount); + + for (chan_num = 0; chan_num < rxt1_span->span.channels; chan_num++) { + struct dahdi_chan *mychans = rxt1_span->chans[chan_num]; + printk("R%dT1: Span %d Chan %d writechunk %p readchunk %p\n", + rxt1_card->numspans, rxt1_span->span.offset, chan_num, + mychans->writechunk, mychans->readchunk); + } + } + } +#ifdef ENABLE_PREFETCH + prefetch((void *) (rxt1_span->readchunk)); + prefetch((void *) (rxt1_span->writechunk)); + prefetch((void *) (rxt1_span->readchunk + 8)); + prefetch((void *) (rxt1_span->writechunk + 8)); + prefetch((void *) (rxt1_span->readchunk + 16)); + prefetch((void *) (rxt1_span->writechunk + 16)); + prefetch((void *) (rxt1_span->readchunk + 24)); + prefetch((void *) (rxt1_span->writechunk + 24)); + prefetch((void *) (rxt1_span->readchunk + 32)); + prefetch((void *) (rxt1_span->writechunk + 32)); + prefetch((void *) (rxt1_span->readchunk + 40)); + prefetch((void *) (rxt1_span->writechunk + 40)); + prefetch((void *) (rxt1_span->readchunk + 48)); + prefetch((void *) (rxt1_span->writechunk + 48)); + prefetch((void *) (rxt1_span->readchunk + 56)); + prefetch((void *) (rxt1_span->writechunk + 56)); +#endif + + if ((test_pat == 1) && + ((rxt1_card->intcount > 10000) && (rxt1_card->intcount < 10003))) { + for (chan_num = 0; chan_num < rxt1_span->span.channels; chan_num++) { + for (samp_num = 0; samp_num < DAHDI_CHUNKSIZE; samp_num++) { + + printk("Sp %02x Sa %02x Ch %02d = %x ", + rxt1_span->span.offset, samp_num, + chan_num, rxt1_span->span.chans[chan_num]->readchunk[samp_num] + ); + printk("Sa %02x Ch %02d Addr %p\n", + rxt1_span->span.chans[chan_num]->readchunk[samp_num] & 0x7, + (rxt1_span->span.chans[chan_num]->readchunk[samp_num] & 0xf8) >> 3, + &rxt1_span->span.chans[chan_num]->readchunk[samp_num]); + } + } + } + + dahdi_ec_span(&rxt1_span->span); + dahdi_receive(&rxt1_span->span); +} + +static inline void __rxt1_transmit_span(struct rxt1_span_t *rxt1_span) +{ + int chan_num, samp_num; + + dahdi_transmit(&rxt1_span->span); + + if (test_pat == 1) { + for (chan_num = 0; chan_num < rxt1_span->span.channels; chan_num++) { + for (samp_num = 0; samp_num < DAHDI_CHUNKSIZE; samp_num++) { + if ((rxt1_span->span.offset == 0) && (chan_num == 1)) { + rxt1_span->span.chans[chan_num]->writechunk[samp_num] = 0x81; + } else { + rxt1_span->span.chans[chan_num]->writechunk[samp_num] = 0x00; + } + } + } + } +} + +#ifdef ENABLE_WORKQUEUES +static void workq_handlespan(void *data) +{ + struct rxt1_span_t *rxt1_span = data; + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + __rxt1_receive_span(rxt1_span); + __rxt1_transmit_span(rxt1_span); + atomic_dec(&rxt1_card->worklist); +} +#else +static void rxt1_card_prep_gen2(struct rxt1_card_t *rxt1_card) +{ + int offset = 1; + int span_num; + int chan_num; + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span_num]; + + if (rxt1_span->span.flags & DAHDI_FLAG_RUNNING) { + + if (double_buffer == 1) { + rxt1_span->writechunk = + (void *) (rxt1_card->writechunk + span_num * 32 * 2 + + (rxt1_card->nextbuf * 8 * 32)); + rxt1_span->readchunk = + (void *) (rxt1_card->readchunk + span_num * 32 * 2 + + (rxt1_card->nextbuf * 8 * 32)); + + for (chan_num = 0; chan_num < rxt1_span->span.channels; chan_num++) { + struct dahdi_chan *mychans = rxt1_span->chans[chan_num]; + + mychans->writechunk = + (void *) (rxt1_card->writechunk + + (span_num * 32 + chan_num + offset) * 2 + + (rxt1_card->nextbuf * 8 * 32)); + mychans->readchunk = + (void *) (rxt1_card->readchunk + + (span_num * 32 + chan_num + offset) * 2 + + (rxt1_card->nextbuf * 8 * 32)); + } + } + + __rxt1_receive_span(rxt1_span); + __rxt1_transmit_span(rxt1_span); + } + } +} + +#endif + + +static void rxt1_span_check_sigbits(struct rxt1_card_t *rxt1_card, int span) +{ + int a, i, rxs; + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span]; + + if (debug & DEBUG_RBS) + printk("Checking sigbits on span %d\n", span + 1); + + if (!(rxt1_span->span.flags & DAHDI_FLAG_RUNNING)) + return; + if (rxt1_span->spantype == TYPE_E1) { + for (i = 0; i < 15; i++) { + a = __rxt1_span_framer_in(rxt1_card, span, 0x71 + i); + /* Get high channel in low bits */ + rxs = (a & 0xf); + if (!(rxt1_span->chans[i + 16]->sig & DAHDI_SIG_CLEAR)) { + if (rxt1_span->chans[i + 16]->rxsig != rxs) + dahdi_rbsbits(rxt1_span->chans[i + 16], rxs); + } + rxs = (a >> 4) & 0xf; + if (!(rxt1_span->chans[i]->sig & DAHDI_SIG_CLEAR)) { + if (rxt1_span->chans[i]->rxsig != rxs) + dahdi_rbsbits(rxt1_span->chans[i], rxs); + } + } + } else if (rxt1_span->span.lineconfig & DAHDI_CONFIG_D4) { + for (i = 0; i < 24; i += 4) { + a = __rxt1_span_framer_in(rxt1_card, span, 0x70 + (i >> 2)); + /* Get high channel in low bits */ + rxs = (a & 0x3) << 2; + if (!(rxt1_span->chans[i + 3]->sig & DAHDI_SIG_CLEAR)) { + if (rxt1_span->chans[i + 3]->rxsig != rxs) + dahdi_rbsbits(rxt1_span->chans[i + 3], rxs); + } + rxs = (a & 0xc); + if (!(rxt1_span->chans[i + 2]->sig & DAHDI_SIG_CLEAR)) { + if (rxt1_span->chans[i + 2]->rxsig != rxs) + dahdi_rbsbits(rxt1_span->chans[i + 2], rxs); + } + rxs = (a >> 2) & 0xc; + if (!(rxt1_span->chans[i + 1]->sig & DAHDI_SIG_CLEAR)) { + if (rxt1_span->chans[i + 1]->rxsig != rxs) + dahdi_rbsbits(rxt1_span->chans[i + 1], rxs); + } + rxs = (a >> 4) & 0xc; + if (!(rxt1_span->chans[i]->sig & DAHDI_SIG_CLEAR)) { + if (rxt1_span->chans[i]->rxsig != rxs) + dahdi_rbsbits(rxt1_span->chans[i], rxs); + } + } + } else { + for (i = 0; i < 24; i += 2) { + a = __rxt1_span_framer_in(rxt1_card, span, 0x70 + (i >> 1)); + /* Get high channel in low bits */ + rxs = (a & 0xf); + if (!(rxt1_span->chans[i + 1]->sig & DAHDI_SIG_CLEAR)) { + /* XXX Not really reset on every trans! XXX */ + if (rxt1_span->chans[i + 1]->rxsig != rxs) { + dahdi_rbsbits(rxt1_span->chans[i + 1], rxs); + } + } + rxs = (a >> 4) & 0xf; + if (!(rxt1_span->chans[i]->sig & DAHDI_SIG_CLEAR)) { + /* XXX Not really reset on every trans! XXX */ + if (rxt1_span->chans[i]->rxsig != rxs) { + dahdi_rbsbits(rxt1_span->chans[i], rxs); + } + } + } + } +} + +static void rxt1_span_check_alarms(struct rxt1_card_t *rxt1_card, int span) +{ + unsigned char c, d, led_state; + int alarms; + int x, j; + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span]; + + if (!(rxt1_span->span.flags & DAHDI_FLAG_RUNNING)) + return; + + c = __rxt1_span_framer_in(rxt1_card, span, 0x4c); + d = __rxt1_span_framer_in(rxt1_card, span, 0x4d); + + if (debug && DEBUG_FRAMER) { + printk("check alarms: intcount %x\n", rxt1_card->intcount); + if (c) + printk("SPAN %d FRMR_FRS0 = %x ", span, c); + if (c & FRMR_FRS0_FSRF) + printk("FRMR_FRS0_FSRF "); /* 0 0x01 */ + if (c & FRMR_FRS0_LMFA) + printk("FRMR_FRS0_LMFA "); /* 1 0x02 */ + if (c & FRMR_FRS0_NMF) + printk("FRMR_FRS0_WTFNMF "); /* 2 0x04 */ + if (c & FRMR_FRS0_RRA) + printk("FRMR_FRS0_RRA "); /* 4 0x10 */ + if (c & FRMR_FRS0_LFA) + printk("FRMR_FRS0_LFA "); /* 5 0x20 */ + if (c & FRMR_FRS0_AIS) + printk("FRMR_FRS0_AIS "); /* 6 0x40 */ + if (c & FRMR_FRS0_LOS) + printk("FRMR_FRS0_LOS"); /* 7 0x80 */ + if (c) + printk("\n"); + + if (d) + printk("SPAN %d FRMR_FRS1 = %x ", span, d); + if (d & FRMR_FRS1_EXZD) + printk("FRMR_FRS1_EXZD "); /* 7 0x80 */ + if (d & FRMR_FRS1_PDEN) + printk("FRMR_FRS1_PDEN "); /* 6 0x40 */ + if (d & FRMR_FRS1_LLBDD) + printk("FRMR_FRS1_LLBDD "); /* 4 0x10 */ + if (d & FRMR_FRS1_LLBAD) + printk("FRMR_FRS1_LLBAD "); /* 3 0x08 */ + if (d & FRMR_FRS1_XLS) + printk("FRMR_FRS1_XLS "); /* 1 0x02 */ + if (d & FRMR_FRS1_XLO) + printk("FRMR_FRS1_XLO"); /* 0 0x01 */ + if (d) + printk("\n"); + } + + /* Assume no alarms */ + alarms = 0; + led_state = NORM_OP; + + /* And consider only carrier alarms */ + rxt1_span->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); + + if (rxt1_span->spantype == TYPE_E1) { + if (c & 0x04) { + /* No multiframe found, force RAI high after 400ms only if + we haven't found a multiframe since last loss of frame */ + if (!(rxt1_span->spanflags & FLAG_NMF)) { + __rxt1_span_framer_out(rxt1_card, span, 0x20, 0x9f | 0x20); /* LIM0: Force RAI High */ + rxt1_span->spanflags |= FLAG_NMF; + led_state = YEL_ALM; + printk("NMF workaround on!\n"); + } + __rxt1_span_framer_out(rxt1_card, span, 0x1e, 0xc3); /* Reset to CRC4 mode */ + __rxt1_span_framer_out(rxt1_card, span, 0x1c, 0xf2); /* Force Resync */ + __rxt1_span_framer_out(rxt1_card, span, 0x1c, 0xf0); /* Force Resync */ + } else if (!(c & 0x02)) { + if ((rxt1_span->spanflags & FLAG_NMF)) { + /* LIM0: Clear forced RAI */ + __rxt1_span_framer_out(rxt1_card, span, 0x20, 0x9f); + rxt1_span->spanflags &= ~FLAG_NMF; + led_state = NORM_OP; + printk("NMF workaround off!\n"); + } + } + } else { /* T1 */ + /* Detect loopup code if we're not sending one */ + /* Line Loop Back Activate Detected */ + if ((!rxt1_span->span.mainttimer) && (d & FRMR_FRS1_LLBAD)) { + /* Loop-up code detected */ + if ((rxt1_span->loopupcnt++ > 80) && + (rxt1_span->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { + /* LIM0: Disable any local loop */ + __rxt1_span_framer_out(rxt1_card, span, 0x36, 0x08); + /* LIM1: Enable remote loop */ + __rxt1_span_framer_out(rxt1_card, span, 0x37, 0xf6); + rxt1_span->span.maintstat = DAHDI_MAINT_REMOTELOOP; + led_state = RLOOP; + } + } else + rxt1_span->loopupcnt = 0; + /* Same for loopdown code */ + /* Line Loop Back De-activate Detected */ + if ((!rxt1_span->span.mainttimer) && (d & FRMR_FRS1_LLBDD)) { + /* Loop-down code detected */ + if ((rxt1_span->loopdowncnt++ > 80) && + (rxt1_span->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { + /* LIM0: Disable any local loop */ + __rxt1_span_framer_out(rxt1_card, span, 0x36, 0x08); + /* LIM1: Disable remote loop */ + __rxt1_span_framer_out(rxt1_card, span, 0x37, 0xf0); + rxt1_span->span.maintstat = DAHDI_MAINT_NONE; + led_state = NORM_OP; + } + } else + rxt1_span->loopdowncnt = 0; + } + + if (rxt1_span->span.lineconfig & DAHDI_CONFIG_NOTOPEN) { + for (x = 0, j = 0; x < rxt1_span->span.channels; x++) + /* + if ((rxt1_span->span.chans[x]->flags & DAHDI_FLAG_OPEN) || + (rxt1_span->span.chans[x]->flags & DAHDI_FLAG_NETDEV)) + */ + if ((rxt1_span->span.chans[x]->flags & DAHDI_FLAG_OPEN)) + j++; + if (!j) + alarms |= DAHDI_ALARM_NOTOPEN; + } + + if (c & (FRMR_FRS0_LFA | FRMR_FRS0_LOS)) { + if (rxt1_span->alarmcount >= alarmdebounce) { + alarms |= DAHDI_ALARM_RED; + led_state = NO_SYNC; + } else + rxt1_span->alarmcount++; + } else + rxt1_span->alarmcount = 0; + if (c & FRMR_FRS0_NMF) { + alarms |= DAHDI_ALARM_BLUE; + led_state = NO_SYNC; + } + + if (((!rxt1_span->span.alarms) && alarms) || (rxt1_span->span.alarms && (!alarms))) + rxt1_card->checktiming = 1; + + /* Keep track of recovering */ + if ((!alarms) && rxt1_span->span.alarms) + rxt1_span->alarmtimer = DAHDI_ALARMSETTLE_TIME; + if (rxt1_span->alarmtimer) { + alarms |= DAHDI_ALARM_RECOVER; + led_state = RECOVER; + } + /* If receiving alarms, go into Yellow alarm state */ + if (alarms && !(rxt1_span->spanflags & FLAG_SENDINGYELLOW)) { + unsigned char fmr4; + printk("R%dT1: Setting yellow alarm on span %d\n", rxt1_card->numspans, span + 1); + /* We manually do yellow alarm to handle RECOVER and NOTOPEN, + * otherwise it's auto anyway */ + fmr4 = __rxt1_span_framer_in(rxt1_card, span, 0x20); + __rxt1_span_framer_out(rxt1_card, span, 0x20, fmr4 | 0x20); + rxt1_span->spanflags |= FLAG_SENDINGYELLOW; + led_state = YEL_ALM; + } else if ((!alarms) && (rxt1_span->spanflags & FLAG_SENDINGYELLOW)) { + unsigned char fmr4; + printk("R%dT1: Clearing yellow alarm on span %d\n", rxt1_card->numspans, + span + 1); + /* We manually do yellow alarm to handle RECOVER */ + fmr4 = __rxt1_span_framer_in(rxt1_card, span, 0x20); + __rxt1_span_framer_out(rxt1_card, span, 0x20, fmr4 & ~0x20); + rxt1_span->spanflags &= ~FLAG_SENDINGYELLOW; + } + + /* Re-check the timing source when we enter/leave alarm, + * not withstanding yellow alarm */ + if (c & FRMR_FRS0_RRA) + alarms |= DAHDI_ALARM_YELLOW; + if (rxt1_span->span.mainttimer || rxt1_span->span.maintstat) + alarms |= DAHDI_ALARM_LOOPBACK; + rxt1_span->span.alarms = alarms; + + __rxt1_card_set_led(rxt1_card, span, led_state); + + dahdi_alarm_notify(&rxt1_span->span); +} + +static void rxt1_card_do_counters(struct rxt1_card_t *rxt1_card) +{ + int span_num; + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span_num]; + int docheck = 0; + + spin_lock(&rxt1_card->reglock); + if (rxt1_span->loopupcnt || rxt1_span->loopdowncnt) + docheck++; + if (rxt1_span->alarmtimer) { + if (!--rxt1_span->alarmtimer) { + docheck++; + rxt1_span->span.alarms &= ~(DAHDI_ALARM_RECOVER); + + __rxt1_card_set_led(rxt1_card, span_num, NORM_OP); + } + } + spin_unlock(&rxt1_card->reglock); + if (docheck) { + if (!polling) + rxt1_span_check_alarms(rxt1_card, span_num); + dahdi_alarm_notify(&rxt1_span->span); + } + } +} + + +static inline void rxt1_span_framer_interrupt(struct rxt1_card_t *rxt1_card, int span) +{ + /* Check interrupts for a given span */ + unsigned char cis, gis, isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7; + int readsize = -1; + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span]; + struct dahdi_chan *sigchan; + unsigned long flags; + + if (debug & DEBUG_FRAMER) + printk("Framer interrupt span %d:%d!\n", rxt1_card->num, span + 1); + + /* 1st gen cards isn't used interrupts */ + cis = __rxt1_span_framer_in(rxt1_card, 0, FRMR_CIS); + gis = __rxt1_span_framer_in(rxt1_card, span, FRMR_GIS); + isr0 = (gis & FRMR_GIS_ISR0) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR0) : 0; + isr1 = (gis & FRMR_GIS_ISR1) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR1) : 0; + isr2 = (gis & FRMR_GIS_ISR2) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR2) : 0; + isr3 = (gis & FRMR_GIS_ISR3) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR3) : 0; + isr4 = (gis & FRMR_GIS_ISR4) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR4) : 0; + isr5 = (gis & FRMR_GIS_ISR5) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR5) : 0; + isr6 = (gis & FRMR_GIS_ISR6) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR6) : 0; + isr7 = (gis & FRMR_GIS_ISR7) ? __rxt1_span_framer_in(rxt1_card, span, FRMR_ISR7) : 0; + + if (debug & DEBUG_FRAMER) + printk + ("cis: %02x, gis: %02x, cnt: %d\nisr0: %02x, isr1: %02x, isr2: %02x,isr3: %02x, \nisr4: %02x, isr5: %02x, isr6: %02x, isr7: %02x\n", + cis, gis, rxt1_card->intcount, isr0, isr1, isr2, isr3, isr4, isr5, isr6, + isr7); + + if (isr0) + rxt1_span_check_sigbits(rxt1_card, span); + + if (rxt1_span->spantype == TYPE_E1) { + /* E1 checks */ + if ((isr3 & 0x38) || isr2 || isr1) + rxt1_span_check_alarms(rxt1_card, span); + } else { + /* T1 checks */ + if (isr2 || (isr3 & 0x08)) + rxt1_span_check_alarms(rxt1_card, span); + } + + if (!rxt1_span->span.alarms) { + if ((isr3 & 0x3) || (isr4 & 0xc0)) + if (debug & DEBUG_MAIN) { + if (isr3 & 0x02) + printk("R%dT1: RECEIVE slip NEGATIVE on span %d\n", + rxt1_card->numspans, span + 1); + if (isr3 & 0x01) + printk("R%dT1: RECEIVE slip POSITIVE on span %d\n", + rxt1_card->numspans, span + 1); + if (isr4 & 0x80) + printk("R%dT1: TRANSMIT slip POSITIVE on span %d\n", + rxt1_card->numspans, span + 1); + if (isr4 & 0x40) + printk("R%dT1: TRANSMIT slip NEGATIVE on span %d\n", + rxt1_card->numspans, span + 1); + } + } + + spin_lock_irqsave(&rxt1_card->reglock, flags); + + /* HDLC controller checks - receive side */ + if (!rxt1_span->sigchan) { + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + return; + } + + sigchan = rxt1_span->sigchan; + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + + if (isr0 & FRMR_ISR0_RME) { + readsize = + (__rxt1_span_framer_in(rxt1_card, span, FRMR_RBCH) << 8) | + __rxt1_span_framer_in(rxt1_card, span, FRMR_RBCL); + if (debug & DEBUG_FRAMER) + printk("Received data length is %d (%d)\n", readsize, + readsize & FRMR_RBCL_MAX_SIZE); + /* RPF isn't set on last part of frame */ + if ((readsize > 0) && ((readsize &= FRMR_RBCL_MAX_SIZE) == 0)) + readsize = 32; + } else if (isr0 & FRMR_ISR0_RPF) + readsize = 32; + + if (readsize > 0) { + struct dahdi_chan *sigchan = rxt1_span->sigchan; + int i; + unsigned char readbuf[FRMR_RBCL_MAX_SIZE]; + + if (debug & DEBUG_FRAMER) + printk("Framer %d: Got RPF/RME! readsize is %d\n", sigchan->span->offset, + readsize); + + for (i = 0; i < readsize; i++) + readbuf[i] = __rxt1_span_framer_in(rxt1_card, span, FRMR_RXFIFO); + + /* Tell the framer to clear the RFIFO */ + __rxt1_span_framer_cmd_wait(rxt1_card, span, FRMR_CMDR_RMC); + + if (debug & DEBUG_FRAMER) { + printk("RX("); + for (i = 0; i < readsize; i++) + printk((i ? " %02x" : "%02x"), readbuf[i]); + printk(")\n"); + } +#ifdef DAHDI_SIG_HARDHDLC + if (isr0 & FRMR_ISR0_RME) { + /* Do checks for HDLC problems */ + unsigned char rsis = readbuf[readsize - 1]; + unsigned int olddebug = debug; + unsigned char rsis_reg = __rxt1_span_framer_in(rxt1_card, span, FRMR_RSIS); + + ++rxt1_span->frames_in; + if ((debug & DEBUG_FRAMER) && !(rxt1_span->frames_in & 0x0f)) + printk("Received %d frames on span %d\n", rxt1_span->frames_in, span); + if (debug & DEBUG_FRAMER) + printk("Received HDLC frame %d. RSIS = 0x%x (%x)\n", + rxt1_span->frames_in, rsis, rsis_reg); + if (!(rsis & FRMR_RSIS_CRC16)) { + if (debug & DEBUG_FRAMER) + printk("CRC check failed %d\n", span); + dahdi_hdlc_abort(sigchan, DAHDI_EVENT_BADFCS); + } else if (rsis & FRMR_RSIS_RAB) { + if (debug & DEBUG_FRAMER) + printk("ABORT of current frame due to overflow %d\n", span); + dahdi_hdlc_abort(sigchan, DAHDI_EVENT_ABORT); + } else if (rsis & FRMR_RSIS_RDO) { + if (debug & DEBUG_FRAMER) + printk("HDLC overflow occured %d\n", span); + dahdi_hdlc_abort(sigchan, DAHDI_EVENT_OVERRUN); + } else if (!(rsis & FRMR_RSIS_VFR)) { + if (debug & DEBUG_FRAMER) + printk("Valid Frame check failed on span %d\n", span); + dahdi_hdlc_abort(sigchan, DAHDI_EVENT_ABORT); + } else { + dahdi_hdlc_putbuf(sigchan, readbuf, readsize - 1); + dahdi_hdlc_finish(sigchan); + if (debug & DEBUG_FRAMER) + printk("Received valid HDLC frame on span %d\n", span); + } + debug = olddebug; + } else if (isr0 & FRMR_ISR0_RPF) + dahdi_hdlc_putbuf(sigchan, readbuf, readsize); +#endif /* HARDHDLC */ + } + + /* Transmit side */ + if (isr1 & FRMR_ISR1_XDU) { + if (debug & DEBUG_FRAMER) + printk("XDU: Resetting signal controler!\n"); + __rxt1_span_framer_cmd_wait(rxt1_card, span, FRMR_CMDR_SRES); + } else if (isr1 & FRMR_ISR1_XPR) { + struct dahdi_chan *sigchan = rxt1_span->sigchan; + + if (debug & DEBUG_FRAMER) + printk("Sigchan %d is %p\n", sigchan->chanpos, sigchan); + + if (debug & DEBUG_FRAMER) + printk("Framer %d: Got XPR!\n", sigchan->span->offset); + __rxt1_span_hdlc_xmit_fifo(rxt1_card, span, rxt1_span); + } + + if (isr1 & FRMR_ISR1_ALLS) { + if (debug & DEBUG_FRAMER) + printk("ALLS received\n"); + } + +} + +DAHDI_IRQ_HANDLER(rxt1_card_interrupt_gen2) +{ + struct rxt1_card_t *rxt1_card = dev_id; + unsigned char cis; + int x, span_num, reg_num; + + unsigned int status; + inirq = 1; + + /* Make sure it's really for us */ + status = rxt1_card_pci_in(rxt1_card, RXT1_DMA + TARG_REGS); + + /* Ignore if it's not for us */ + if (!(status & (FRMR_ISTAT | DMA_INT))) { + if (unlikely(debug)) + printk("Int called with no INT status high!\n"); + return IRQ_NONE; + } + + if (unlikely(!rxt1_card->spansstarted)) { + if (status & DMA_INT) + __rxt1_card_pci_out(rxt1_card, RXT1_DMA + TARG_REGS, + rxt1_card->dmactrl | DMA_ACK, + target_regs[RXT1_DMA].iomask); + if (debug) + printk("Not prepped yet!\n"); + return IRQ_NONE; + } + + if (unlikely((rxt1_card->intcount < 20) && debug)) + printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, + __rxt1_span_framer_in(rxt1_card, 0, FRMR_CIS)); + + if (status & DMA_INT) { + rxt1_card->intcount++; + + __rxt1_card_pci_out(rxt1_card, RXT1_DMA + TARG_REGS, rxt1_card->dmactrl | DMA_ACK, + target_regs[RXT1_DMA].iomask); + + if (status & BUFF_PTR) { + if (unlikely((rxt1_card->nextbuf == 1) && debug)) + printk("Miss %d PTR was 1 twice\n", rxt1_card->intcount); + rxt1_card->nextbuf = 1; + } else { + if (unlikely((rxt1_card->nextbuf == 0) && debug)) + printk("Miss %d PTR was 0 twice\n", rxt1_card->intcount); + rxt1_card->nextbuf = 0; + } + + if (unlikely((rxt1_card->intcount % 10000) == 0)) { + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + struct rxt1_span_t *rxt1_span = rxt1_card->rxt1_spans[span_num]; + if (rxt1_span->span.flags & DAHDI_FLAG_RUNNING) { + if (__rxt1_span_framer_in(rxt1_card, span_num, 0x4c) & + (FRMR_FRS0_LFA | FRMR_FRS0_LOS)) { + printk("RESYNC Card %d Span %d\n", rxt1_card->num + 1, + span_num + 1); + rxt1_span_startup(&rxt1_span->span); + } + } + } + } + + if (unlikely((rxt1_card->intcount > 8500) && (regdump == 1) && (regdumped == 0))) { + for (span_num = 0; span_num < 4; span_num++) { + for (reg_num = 0; reg_num < 0xba; reg_num++) + printk("Span %d Reg 0x%x: %s 0x%02x\n", span_num, reg_num, + framer_regs[reg_num].name, + __rxt1_span_framer_in(rxt1_card, span_num, reg_num)); + } + regdumped = 1; + } +#ifdef ENABLE_WORKQUEUES + int cpus = num_online_cpus(); + atomic_set(&rxt1_card->worklist, rxt1_card->numspans); + if (rxt1_card->rxt1_spans[0]->span.flags & DAHDI_FLAG_RUNNING) + t4_queue_work(rxt1_card->workq, &rxt1_card->rxt1_spans[0]->swork, 0); + else + atomic_dec(&rxt1_card->worklist); + if (rxt1_card->rxt1_spans[1]->span.flags & DAHDI_FLAG_RUNNING) + t4_queue_work(rxt1_card->workq, &rxt1_card->rxt1_spans[1]->swork, 1 % cpus); + else + atomic_dec(&rxt1_card->worklist); + if (rxt1_card->numspans == 4) { + if (rxt1_card->rxt1_spans[2]->span.flags & DAHDI_FLAG_RUNNING) + t4_queue_work(rxt1_card->workq, &rxt1_card->rxt1_spans[2]->swork, + 2 % cpus); + else + atomic_dec(&rxt1_card->worklist); + if (rxt1_card->rxt1_spans[3]->span.flags & DAHDI_FLAG_RUNNING) + t4_queue_work(rxt1_card->workq, &rxt1_card->rxt1_spans[3]->swork, + 3 % cpus); + else + atomic_dec(&rxt1_card->worklist); + } +#else + rxt1_card_prep_gen2(rxt1_card); +#endif + } + + + if (status & DMA_INT) + rxt1_card_do_counters(rxt1_card); + + /* This should be something like : + * x = (intcount & (7 << shift)) >> shift + * not 8 polling and then 8 idle ints + * then case even : sigbits(x >> 1) + * case odd : alarms(x >> 1) + * + * Look up the required response time for shift + */ + if (polling && (status & DMA_INT)) { + x = rxt1_card->intcount & 15 /* 63 */ ; + switch (x) { + case 0: + case 1: + case 2: + case 3: + rxt1_span_check_sigbits(rxt1_card, x); + break; + case 4: + case 5: + case 6: + case 7: + rxt1_span_check_alarms(rxt1_card, x - 4); + break; + } + } else if (status & FRMR_ISTAT) { + cis = __rxt1_span_framer_in(rxt1_card, 0, FRMR_CIS); + /* all cards have span 0 */ + if (cis & FRMR_CIS_GIS1) + rxt1_span_framer_interrupt(rxt1_card, 0); + /* dual card GIS2 is in GIS3 bit position */ + if ((rxt1_card->numspans == 2) && (cis & FRMR_CIS_GIS3)) { + rxt1_span_framer_interrupt(rxt1_card, 1); + } + /* other 3 on quad only */ + if (rxt1_card->numspans == 4) { + if (cis & FRMR_CIS_GIS2) + rxt1_span_framer_interrupt(rxt1_card, 1); + if (cis & FRMR_CIS_GIS3) + rxt1_span_framer_interrupt(rxt1_card, 2); + if (cis & FRMR_CIS_GIS4) + rxt1_span_framer_interrupt(rxt1_card, 3); + } + } + + if (rxt1_card->checktiming > 0) + __rxt1_card_set_timing_source_auto(rxt1_card); + if (rxt1_card->stopdma) { + + rxt1_card->dmactrl &= ~(DMA_GO | FRMR_IEN); + __rxt1_card_pci_out(rxt1_card, RXT1_DMA + TARG_REGS, rxt1_card->dmactrl, + target_regs[RXT1_DMA].iomask); + __rxt1_card_set_timing_source(rxt1_card, 4, 0, 0); + rxt1_card->stopdma = 0x0; + + } + + return IRQ_RETVAL(1); +} + +static void rxt1_card_tsi_reset(struct rxt1_card_t *rxt1_card) +{ + int x; + for (x = 0; x < 128; x++) { + } +} + +/* Note that channels here start from 1 */ +static void rxt1_card_tsi_assign(struct rxt1_card_t *rxt1_card, int fromspan, + int fromchan, int tospan, int tochan) +{ + int fromts, tots; + + fromts = (fromspan << 5) | (fromchan); + tots = (tospan << 5) | (tochan); + + if (!rxt1_card->t1e1) { + fromts += 4; + tots += 4; + } +} + +static void rxt1_card_tsi_unassign(struct rxt1_card_t *rxt1_card, int tospan, int tochan) +{ + int tots; + + tots = (tospan << 5) | (tochan); + + if (!rxt1_card->t1e1) + tots += 4; +} + +static int rxt1_card_hardware_init_1(struct rxt1_card_t *rxt1_card, int gen2) +{ + rxt1_card->version = (rxt1_card_pci_in(rxt1_card, RXT1_VERSION + TARG_REGS) >> 16); + + printk("R%dT1 version %08x\n", rxt1_card->numspans, rxt1_card->version); + + if (debug & DEBUG_MAIN) { + printk("burst %s, slip debug: %s\n", noburst ? "OFF" : "ON", + debugslips ? "ON" : "OFF"); + printk("test pattern: %s, register dump: %s, idle codes: %s\n", + test_pat ? "ON" : "OFF", regdump ? "ON" : "OFF", + insert_idle ? "ON" : "OFF"); + printk("receive quad offset: %d, receive dual offset: %d, transmit offset: %d,\n", + recq_off, recd_off, xmit_off); + } +#ifdef ENABLE_WORKQUEUES + printk("R%dT1 running with work queues.\n", rxt1_card->numspans); +#endif +#ifdef ENABLE_PREFETCH + printk("R%dT1 running with prefetch enabled.\n", rxt1_card->numspans); +#endif + /* Make sure DMA engine is not running and interrupts are acknowledged */ + rxt1_card->dmactrl = 0x0; + __rxt1_card_pci_out(rxt1_card, RXT1_DMA + TARG_REGS, rxt1_card->dmactrl, + target_regs[RXT1_DMA].iomask); + + /* Set DMA addresses */ + __rxt1_card_pci_out(rxt1_card, RXT1_RXBUFSTART + TARG_REGS, rxt1_card->readdma, + target_regs[RXT1_RXBUFSTART].iomask); + __rxt1_card_pci_out(rxt1_card, RXT1_TXBUFSTART + TARG_REGS, rxt1_card->writedma, + target_regs[RXT1_TXBUFSTART].iomask); + + rxt1_card_tsi_reset(rxt1_card); + + /* Setup counter */ + rxt1_card->dmactrl = + ((DAHDI_MAX_CHUNKSIZE * 2 * 32) << 16) | (rxt1_card->dmactrl & ~DMA_LEN); + if (double_buffer != 1) + rxt1_card->dmactrl |= 0x80; + __rxt1_card_pci_out(rxt1_card, RXT1_DMA + TARG_REGS, rxt1_card->dmactrl, + target_regs[RXT1_DMA].iomask); + + rxt1_card->order = 0x0; + + return 0; +} + +static int rxt1_card_hardware_init_2(struct rxt1_card_t *rxt1_card) +{ + int x; + unsigned int falcver; + + rxt1_span_framer_out(rxt1_card, 0, 0x4a, 0xaa); + falcver = rxt1_span_framer_in(rxt1_card, 0, 0x4a); + printk("R%dT1: FALC version: %08x, Board ID: %02x\n", rxt1_card->numspans, falcver, + rxt1_card->order); + + if (debug & DEBUG_MAIN) { + for (x = 0; x < 5; x++) + printk("R%dT1: Reg %d: %s 0x%08x\n", rxt1_card->numspans, x, + target_regs[x].name, rxt1_card_pci_in(rxt1_card, x + TARG_REGS)); + } + + return 0; +} + +static inline void rxt1_card_reset_dsp(struct rxt1_card_t *rxt1_card) +{ + unsigned long flags; + unsigned int hpi_c; + + spin_lock_irqsave(&rxt1_card->reglock, flags); + hpi_c = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC); + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, (hpi_c & ~DSP_RST), + target_regs[RXT1_HPIC].iomask); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, (hpi_c & ~DSP_RST), + target_regs[RXT1_HPIC].iomask); + + rxt1_card->hpi_fast = 0; + rxt1_card->hpi_xadd[0] = 0; + rxt1_card->hpi_xadd[1] = 0; + rxt1_card->hpi_xadd[2] = 0; + rxt1_card->hpi_xadd[3] = 0; + rxt1_card->dsp_sel = 0; + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, (hpi_c | DSP_RST), + target_regs[RXT1_HPIC].iomask); + + spin_unlock_irqrestore(&rxt1_card->reglock, flags); +} + + +int try_select_dsp(struct rxt1_card_t *rxt1_card, int span_num, int bc) +{ + int hcs; + int sel; + + sel = __rxt1_card_pci_in(rxt1_card, RXT1_HCS_REG + TARG_REGS); + + if (sel == 0) { + if (bc == 0) { + hcs = (1 << span_num); + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, (__u32) (hcs), 0); + } else + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, (__u32) 0xf, 0); + + return 0; + } + return 1; +} + +void rxt1_card_select_dsp(struct rxt1_card_t *rxt1_card, int span_num, int bc) +{ + rxt1_card->dsp_sel = span_num; +} + +void rxt1_card_unselect_dsp(struct rxt1_card_t *rxt1_card, int span_num) +{ + rxt1_card->dsp_sel = 0; +} + +static unsigned short int rxt1_card_dsp_ping(struct rxt1_card_t *rxt1_card, int span_num) +{ + gpakPingDspStat_t ping_stat; + unsigned short int dsp_ver; + unsigned short int DspId; + + DspId = (rxt1_card->num * 4) + span_num; + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + + ping_stat = gpakPingDsp(rxt1_card, DspId, &dsp_ver); + + if (debug & DEBUG_DSP) { + if (ping_stat == PngSuccess) + printk("R%dT1 %d %d: G168 DSP Ping DSP Version %x\n", rxt1_card->numspans, + rxt1_card->num + 1, DspId + 1, dsp_ver); + else + printk("R%dT1 %d %d: G168 DSP Ping Error %d\n", rxt1_card->numspans, + rxt1_card->num + 1, DspId + 1, ping_stat); + } + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + if (ping_stat == PngSuccess) + return dsp_ver; + else + return 0; +} + +static int __devinit rxt1_span_download_dsp(struct rxt1_card_t *rxt1_card, int span_num) +{ + unsigned short int DspId; + gpakDownloadStatus_t dl_res = 0; + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + DspId = (rxt1_card->num * 4) + span_num; + if ((dl_res = gpakDownloadDsp_5510(rxt1_card, DspId, app_file))) + printk("R%dT1 %d DSP %d: G168 DSP App Loader Failed %d\n", rxt1_card->numspans, + rxt1_card->num + 1, DspId + 1, dl_res); + else + printk("R%dT1 %d DSP %d: G168 DSP App Loader Success %d\n", rxt1_card->numspans, + rxt1_card->num + 1, DspId + 1, dl_res); + + rxt1_card_dsp_set(rxt1_card, DSP_IFBLK_ADDRESS, 0); + rxt1_card_dsp_set(rxt1_card, DSP_IFBLK_ADDRESS + 1, 0); + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + if (dl_res) + return -1; + else + return 0; +} + +static void __devinit rxt1_span_run_dsp(struct rxt1_card_t *rxt1_card, int span_num) +{ + unsigned long flags; + unsigned long hcs; + + spin_lock_irqsave(&rxt1_card->reglock, flags); + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + + hcs = 1 << rxt1_card->dsp_sel; + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, hcs, 0); + + rxt1_card_hpic_set(rxt1_card, RXT1_BL_GO); + + __rxt1_card_pci_out(rxt1_card, RXT1_HCS_REG + TARG_REGS, 0, 0); + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + spin_unlock_irqrestore(&rxt1_card->reglock, flags); + + return; +} + +static GpakPortConfig_t Gpak_32_chan_port_config = { + + /* GpakSlotCfg_t SlotsSelect1 port 1 Slot selection */ + SlotCfgNone, + /* unsigned short int FirstBlockNum1 port 1 first group Block Number */ + 0x0000, + /* unsigned short int FirstSlotMask1 port 1 first group Slot Mask */ + 0x0000, + /* unsigned short int SecBlockNum1 port 1 second group Block Number */ + 0x0000, + /* unsigned short int SecSlotMask1 port 1 second group Slot Mask */ + 0x0000, + /* GpakSerWordSize_t SerialWordSize1 port 1 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode1 port 1 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity1 port 1 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity1 port 1 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity1 port 1 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t TxClockPolarity1 port 1 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay1 port 1 Tx data delay */ + DataDelay1, + /* GpakSerDataDelay_t RxDataDelay1 port 1 Rx data delay */ + DataDelay1, + /* GpakActivation DxDelay1 port 1 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask1 port 1 3rd group Slot Mask */ + 0x0000, + /* unsigned short int FouthSlotMask1 port 1 4th group Slot Mask */ + 0x0000, + /* unsigned short int FifthSlotMask1 port 1 5th group Slot Mask */ + 0x0000, + /* unsigned short int SixthSlotMask1 port 1 6th group Slot Mask */ + 0x0000, + /* unsigned short int SevenSlotMask1 port 1 7th group Slot Mask */ + 0x0000, + /* unsigned short int EightSlotMask1 port 1 8th group Slot Mask */ + 0x0000, + + /* GpakSlotCfg_t SlotsSelect2 port 2 Slot selection */ + SlotCfg8Groups, + /* unsigned short int FirstBlockNum2 port 2 first group Block Number */ + 0, + /* unsigned short int FirstSlotMask2 port 2 first group Slot Mask */ + 0x1110, + /* unsigned short int SecBlockNum2 port 2 second group Block Number */ + 1, + /* unsigned short int SecSlotMask2 port 2 second group Slot Mask */ + 0x1111, + /* GpakSerWordSize_t SerialWordSize2 port 2 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode2 port 2 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity2 port 2 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity2 port 2 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity2 port 2 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity2 port 2 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay2 port 2 Tx data delay */ + DataDelay1, + /* GpakSerDataDelay_t RxDataDelay2 port 2 Rx data delay */ + DataDelay1, + /* GpakActivation DxDelay2 port 2 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask2 port 2 3rd group Slot Mask */ + 0x1111, + /* unsigned short int FouthSlotMask2 port 2 4th group Slot Mask */ + 0x1111, + /* unsigned short int FifthSlotMask2 port 2 5th group Slot Mask */ + 0x1111, + /* unsigned short int SixthSlotMask2 port 2 6th group Slot Mask */ + 0x1111, + /* unsigned short int SevenSlotMask2 port 2 7th group Slot Mask */ + 0x1111, + /* unsigned short int EightSlotMask2 port 2 8th group Slot Mask */ + 0x1111, + + /* GpakSlotCfg_t SlotsSelect3 port 3 Slot selection */ + SlotCfg8Groups, + /* unsigned short int FirstBlockNum3 port 3 first group Block Number */ + 0, + /* unsigned short int FirstSlotMask3 port 3 first group Slot Mask */ + 0x1110, + /* unsigned short int SecBlockNum3 port 3 second group Block Number */ + 1, + /* unsigned short int SecSlotMask3 port 3 second group Slot Mask */ + 0x1111, + /* GpakSerWordSize_t SerialWordSize3 port 3 serial word size */ + SerWordSize8, + /* GpakCompandModes CompandingMode3 port 3 companding mode */ + cmpNone, + /* GpakSerFrameSyncPol_t TxFrameSyncPolarity3 port 3 Tx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerFrameSyncPol_t RxFrameSyncPolarity3 port 3 Rx Frame Sync Polarity */ + FrameSyncActHigh, + /* GpakSerClockPol_t TxClockPolarity3 port 3 Tx Clock Polarity */ + SerClockActHigh, + /* GpakSerClockPol_t RxClockPolarity3 port 3 Rx Clock Polarity */ + SerClockActHigh, + /* GpakSerDataDelay_t TxDataDelay3 port 3 Tx data delay */ + DataDelay1, + /* GpakSerDataDelay_t RxDataDelay3 port 3 Rx data delay */ + DataDelay1, + /* GpakActivation DxDelay3 port 3 DX Delay */ + Disabled, + /* unsigned short int ThirdSlotMask3 port 3 3rd group Slot Mask */ + 0x1111, + /* unsigned short int FouthSlotMask3 port 3 4th group Slot Mask */ + 0x1111, + /* unsigned short int FifthSlotMask3 port 3 5th group Slot Mask */ + 0x1111, + /* unsigned short int SixthSlotMask3 port 3 6th group Slot Mask */ + 0x1111, + /* unsigned short int SevenSlotMask3 port 3 7th group Slot Mask */ + 0x1111, + /* unsigned short int EightSlotMask3 port 3 8th group Slot Mask */ + 0x1111, +}; + +static void rxt1_card_dsp_show_portconfig(GpakPortConfig_t PortConfig) +{ + if (debug & DEBUG_DSP) { + printk("%x = %s\n", PortConfig.SlotsSelect1, "SlotsSelect1"); + printk("%x = %s\n", PortConfig.FirstBlockNum1, "FirstBlockNum1"); + printk("%x = %s\n", PortConfig.FirstSlotMask1, "FirstSlotMask1"); + printk("%x = %s\n", PortConfig.SecBlockNum1, "SecBlockNum1"); + printk("%x = %s\n", PortConfig.SecSlotMask1, "SecSlotMask1"); + printk("%x = %s\n", PortConfig.SerialWordSize1, "SerialWordSize1"); + printk("%x = %s\n", PortConfig.CompandingMode1, "CompandingMode1"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity1, "TxFrameSyncPolarity1"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity1, "RxFrameSyncPolarity1"); + printk("%x = %s\n", PortConfig.TxClockPolarity1, "TxClockPolarity1"); + printk("%x = %s\n", PortConfig.RxClockPolarity1, "RxClockPolarity1"); + printk("%x = %s\n", PortConfig.TxDataDelay1, "TxDataDelay1"); + printk("%x = %s\n", PortConfig.RxDataDelay1, "RxDataDelay1"); + printk("%x = %s\n", PortConfig.DxDelay1, "DxDelay1"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask1, "ThirdSlotMask1"); + printk("%x = %s\n", PortConfig.FouthSlotMask1, "FouthSlotMask1"); + printk("%x = %s\n", PortConfig.FifthSlotMask1, "FifthSlotMask1"); + printk("%x = %s\n", PortConfig.SixthSlotMask1, "SixthSlotMask1"); + printk("%x = %s\n", PortConfig.SevenSlotMask1, "SevenSlotMask1"); + printk("%x = %s\n", PortConfig.EightSlotMask1, "EightSlotMask1"); + + printk("%x = %s\n", PortConfig.SlotsSelect2, "SlotsSelect2"); + printk("%x = %s\n", PortConfig.FirstBlockNum2, "FirstBlockNum2"); + printk("%x = %s\n", PortConfig.FirstSlotMask2, "FirstSlotMask2"); + printk("%x = %s\n", PortConfig.SecBlockNum2, "SecBlockNum2"); + printk("%x = %s\n", PortConfig.SecSlotMask2, "SecSlotMask2"); + printk("%x = %s\n", PortConfig.SerialWordSize2, "SerialWordSize2"); + printk("%x = %s\n", PortConfig.CompandingMode2, "CompandingMode2"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity2, "TxFrameSyncPolarity2"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity2, "RxFrameSyncPolarity2"); + printk("%x = %s\n", PortConfig.TxClockPolarity2, "TxClockPolarity2"); + printk("%x = %s\n", PortConfig.RxClockPolarity2, "RxClockPolarity2"); + printk("%x = %s\n", PortConfig.TxDataDelay2, "TxDataDelay2"); + printk("%x = %s\n", PortConfig.RxDataDelay2, "RxDataDelay2"); + printk("%x = %s\n", PortConfig.DxDelay2, "DxDelay2"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask2, "ThirdSlotMask2"); + printk("%x = %s\n", PortConfig.FouthSlotMask2, "FouthSlotMask2"); + printk("%x = %s\n", PortConfig.FifthSlotMask2, "FifthSlotMask2"); + printk("%x = %s\n", PortConfig.SixthSlotMask2, "SixthSlotMask2"); + printk("%x = %s\n", PortConfig.SevenSlotMask2, "SevenSlotMask2"); + printk("%x = %s\n", PortConfig.EightSlotMask2, "EightSlotMask2"); + + printk("%x = %s\n", PortConfig.SlotsSelect3, "SlotsSelect3"); + printk("%x = %s\n", PortConfig.FirstBlockNum3, "FirstBlockNum3"); + printk("%x = %s\n", PortConfig.FirstSlotMask3, "FirstSlotMask3"); + printk("%x = %s\n", PortConfig.SecBlockNum3, "SecBlockNum3"); + printk("%x = %s\n", PortConfig.SecSlotMask3, "SecSlotMask3"); + printk("%x = %s\n", PortConfig.SerialWordSize3, "SerialWordSize3"); + printk("%x = %s\n", PortConfig.CompandingMode3, "CompandingMode3"); + printk("%x = %s\n", PortConfig.TxFrameSyncPolarity3, "TxFrameSyncPolarity3"); + printk("%x = %s\n", PortConfig.RxFrameSyncPolarity3, "RxFrameSyncPolarity3"); + printk("%x = %s\n", PortConfig.TxClockPolarity3, "TxClockPolarity3"); + printk("%x = %s\n", PortConfig.RxClockPolarity3, "RxClockPolarity3"); + printk("%x = %s\n", PortConfig.TxDataDelay3, "TxDataDelay3"); + printk("%x = %s\n", PortConfig.RxDataDelay3, "RxDataDelay3"); + printk("%x = %s\n", PortConfig.DxDelay3, "DxDelay3"); + + printk("%x = %s\n", PortConfig.ThirdSlotMask3, "ThirdSlotMask3"); + printk("%x = %s\n", PortConfig.FouthSlotMask3, "FouthSlotMask3"); + printk("%x = %s\n", PortConfig.FifthSlotMask3, "FifthSlotMask3"); + printk("%x = %s\n", PortConfig.SixthSlotMask3, "SixthSlotMask3"); + printk("%x = %s\n", PortConfig.SevenSlotMask3, "SevenSlotMask3"); + printk("%x = %s\n", PortConfig.EightSlotMask3, "EightSlotMask3"); + + } + return; +} + +static int __devinit rxt1_span_dsp_configureports(struct rxt1_card_t *rxt1_card, + GpakPortConfig_t PortConfig, + int span_num) +{ + gpakConfigPortStatus_t cp_res; + GPAK_PortConfigStat_t cp_error; + unsigned short int DspId; + + rxt1_card_dsp_show_portconfig(PortConfig); + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + DspId = (rxt1_card->num * 4) + span_num; + + if ((cp_res = gpakConfigurePorts(rxt1_card, DspId, &PortConfig, &cp_error))) + printk("R%dT1 %d DSP %d: G168 DSP Port Config failed res = %d error = %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, cp_res, cp_error); + else if (debug & DEBUG_DSP) { + printk("R%dT1 %d DSP %d: G168 DSP Port Config success %d\n", rxt1_card->numspans, + rxt1_card->num + 1, DspId + 1, cp_res); + } + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + if (cp_res) + return -1; + else + return 0; +} + +static GpakChannelConfig_t Gpak_chan_config = { + + /* GpakSerialPort_t PCM Input Serial Port A Id */ + SerialPort2, + /* unsigned short int PCM Input Time Slot */ + 0, + /* GpakSerialPort_t PCM Output Serial Port A Id */ + SerialPort3, + /* unsigned short int PCM Output Time Slot */ + 0, + /* GpakSerialPort_t PCM Input Serial Port B Id */ + SerialPort3, + /* unsigned short int PCM Input Time Slot */ + 0, + /* GpakSerialPort_t PCM Output Serial Port B Id */ + SerialPortNull, + /* unsigned short int PCM Output Time Slot */ + 0, + /* GpakToneTypes ToneTypesA A side Tone Detect Types */ + Null_tone, + /* GpakToneTypes ToneTypesB B side Tone Detect Types */ + Null_tone, + /* GpakActivation Echo Cancel A Enabled */ + Disabled, + /* GpakActivation Echo Cancel B Enabled */ + Disabled, + + { + /* short int Echo Can Num Taps (tail length) 64 = 512 32 = 256 */ + 1024, + /* short int Echo Can NLP Type */ + 3, + /* short int Echo Can Adapt Enable flag */ + 1, + /* short int Echo Can G165 Detect Enable flag */ + 1, + /* short int Echo Can Double Talk threshold */ + 4, + /* short int Echo Can NLP threshold */ + 21, + /* short int Dynamic NLP control, NLP limit when EC about to converged */ + 17, + /* short int Dynamic NLP control, NLP limit when EC not converged yet */ + 12, + /* short int suppression level for NLP_SUPP mode */ + 0, + /* short int Echo Can CNG Noise threshold */ + 50, + /* short int Echo Can Max Adapts per frame */ + 40, + /* short int Echo Can Cross Correlation limit */ + 20, + /* short int Echo Can Num FIR Segments */ + 3, + /* short int Echo Can FIR Segment Length */ + 64, + }, + + { + /* short int Echo Can Num Taps (tail length) */ + 1024, + /* short int Echo Can NLP Type */ + 3, + /* short int Echo Can Adapt Enable flag */ + 1, + /* short int Echo Can G165 Detect Enable flag */ + 1, + /* short int Echo Can Double Talk threshold */ + 4, + /* short int Echo Can NLP threshold */ + 21, + /* short int Dynamic NLP control, NLP limit when EC about to converged */ + 17, + /* short int Dynamic NLP control, NLP limit when EC not converged yet */ + 12, + /* short int suppression level for NLP_SUPP mode */ + 0, + /* short int Echo Can CNG Noise threshold */ + 50, + /* short int Echo Can Max Adapts per frame */ + 40, + /* short int Echo Can Cross Correlation limit */ + 20, + /* short int Echo Can Num FIR Segments */ + 3, + /* short int Echo Can FIR Segment Length */ + 64, + }, + + /* GpakCompandModes software companding */ + cmpNone, + /* GpakRate_t Gpak Frame Rate */ + rate2ms, + Disabled, + Disabled, + Disabled, + Disabled +}; + +static void rxt1_card_dsp_show_chanconfig(GpakChannelConfig_t ChanConfig) +{ + if (debug & DEBUG_DSP) { + printk("%d = %s\n", ChanConfig.PcmInPortA, "PcmInPortA"); + printk("%d = %s\n", ChanConfig.PcmInSlotA, "PcmInSlotA"); + printk("%d = %s\n", ChanConfig.PcmOutPortA, "PcmOutPortA"); + printk("%d = %s\n", ChanConfig.PcmOutSlotA, "PcmOutSlotA"); + printk("%d = %s\n", ChanConfig.PcmInPortB, "PcmInPortB"); + printk("%d = %s\n", ChanConfig.PcmInSlotB, "PcmInSlotB"); + printk("%d = %s\n", ChanConfig.PcmOutPortB, "PcmOutPortB"); + printk("%d = %s\n", ChanConfig.PcmOutSlotB, "PcmOutSlotB"); + + printk("%d = %s\n", ChanConfig.ToneTypesA, "ToneTypesA"); + printk("%d = %s\n", ChanConfig.ToneTypesB, "ToneTypesB"); + + printk("%d = %s\n", ChanConfig.EcanEnableA, "EcanEnableA"); + printk("%d = %s\n", ChanConfig.EcanEnableB, "EcanEnableB"); + + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanTapLength, + "EcanParametersA.EcanTapLength"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpType, + "EcanParametersA.EcanNlpType"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanAdaptEnable, + "EcanParametersA.EcanAdaptEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanG165DetEnable, + "EcanParametersA.EcanG165DetEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanDblTalkThresh, + "EcanParametersA.EcanDblTalkThresh"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpThreshold, + "EcanParametersA.EcanNlpThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpConv, + "EcanParametersA.EcanNlpConv"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpUnConv, + "EcanParametersA.EcanNlpUnConv"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNlpMaxSuppress, + "EcanParametersA.EcanNlpMaxSuppress"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanCngThreshold, + "EcanParametersA.EcanCngThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanAdaptLimit, + "EcanParametersA.EcanAdaptLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanCrossCorrLimit, + "EcanParametersA.EcanCrossCorrLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanNumFirSegments, + "EcanParametersA.EcanNumFirSegments"); + printk("%d = %s\n", ChanConfig.EcanParametersA.EcanFirSegmentLen, + "EcanParametersA.EcanFirSegmentLen"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanTapLength, + "EcanParametersB.EcanTapLength"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpType, + "EcanParametersB.EcanNlpType"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanAdaptEnable, + "EcanParametersB.EcanAdaptEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanG165DetEnable, + "EcanParametersB.EcanG165DetEnable"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanDblTalkThresh, + "EcanParametersB.EcanDblTalkThresh"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpThreshold, + "EcanParametersB.EcanNlpThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpConv, + "EcanParametersB.EcanNlpConv"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpUnConv, + "EcanParametersB.EcanNlpUnConv"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNlpMaxSuppress, + "EcanParametersB.EcanNlpMaxSuppress"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanCngThreshold, + "EcanParametersB.EcanCngThreshold"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanAdaptLimit, + "EcanParametersB.EcanAdaptLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanCrossCorrLimit, + "EcanParametersB.EcanCrossCorrLimit"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanNumFirSegments, + "EcanParametersB.EcanNumFirSegments"); + printk("%d = %s\n", ChanConfig.EcanParametersB.EcanFirSegmentLen, + "EcanParametersB.EcanFirSegmentLen"); + + printk("%d = %s\n", ChanConfig.SoftwareCompand, "SoftwareCompand"); + + printk("%d = %s\n", ChanConfig.FrameRate, "FrameRate"); + + printk("%d = %s\n", ChanConfig.MuteToneA, "MuteToneA"); + printk("%d = %s\n", ChanConfig.MuteToneB, "MuteToneB"); + printk("%d = %s\n", ChanConfig.FaxCngDetA, "FaxCngDetA"); + printk("%d = %s\n", ChanConfig.FaxCngDetB, "FaxCngDetB"); + + } + return; +} + +static int __devinit rxt1_span_dsp_configurechannel(struct rxt1_card_t *rxt1_card, + GpakChannelConfig_t ChanConfig, + int chan_num, int span_num) +{ + GPAK_ChannelConfigStat_t chan_config_err; + gpakConfigChanStatus_t chan_conf_stat; + unsigned short int DspId; + + rxt1_card_dsp_show_chanconfig(ChanConfig); + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + DspId = (rxt1_card->num * 4) + span_num; + + if ((chan_conf_stat = + gpakConfigureChannel(rxt1_card, DspId, chan_num, tdmToTdm, &Gpak_chan_config, + &chan_config_err))) + printk("R%dT1 %d DSP %d: Chan %d G168 DSP Chan Config failed error = %d %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, chan_num, + chan_config_err, chan_conf_stat); + else if (debug & DEBUG_DSP) { + printk("R%dT1 %d DSP %d: G168 DSP Chan %d Config success %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, chan_num, + chan_conf_stat); + } + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + if (chan_conf_stat) + return -1; + else + return 0; +} + +static void rxt1_card_dsp_framestats(struct rxt1_card_t *rxt1_card, int span_num) +{ + gpakReadFramingStatsStatus_t framing_status_status; + unsigned short int ec1, ec2, ec3, dmaec, slips[6]; + unsigned short int DspId; + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + DspId = (rxt1_card->num * 4) + span_num; + + if (debug & DEBUG_DSP) { + framing_status_status = + gpakReadFramingStats(rxt1_card, DspId, &ec1, &ec2, &ec3, &dmaec, &slips[0]); + if (framing_status_status == RfsSuccess) { + printk("R%dT1 %d DSP %d: G168 DSP Framing Status Success %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, + framing_status_status); + if (ec1 + ec2 + ec3 + dmaec + slips[0] + slips[1] + slips[2] + slips[3] + + slips[4] + slips[5]) { + printk + ("R%dT1 %d DSP %d: G168 DSP Framing Status p1 %2d p2 %2d p3 %2d stop %2d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, ec1, ec2, ec3, + dmaec); + printk + ("R%dT1 %d DSP %d: G168 DSP Framing Status slip0 %2d slip1 %2d slip2 %2d " + "slip3 %2d slip4 %2d slip5 %2d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, slips[0], + slips[1], slips[2], slips[3], slips[4], slips[5]); + } else + printk("R%dT1 %d DSP %d: G168 DSP Framing Status GOOD!!\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1); + } else { + printk("R%dT1 %d DSP %d: G168 DSP Framing Status Failed %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, + framing_status_status); + printk("R%dT1 %d DSP %d: G168 DSP Framing Status %d %d %d %d %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, ec1, ec2, ec3, + dmaec, slips[0]); + } + } + + rxt1_card_unselect_dsp(rxt1_card, span_num); + return; +} + +static void rxt1_card_dsp_reetframestats(struct rxt1_card_t *rxt1_card, int span_num) +{ + gpakResetFramingStatsStatus_t framing_reset_status; + unsigned short int DspId; + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + DspId = (rxt1_card->num * 4) + span_num; + + if ((framing_reset_status = gpakResetFramingStats(rxt1_card, DspId))) + printk("R%dT1 %d DSP %d: G168 DSP Reset Framing Stats Failed %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, framing_reset_status); + else + printk("R%dT1 %d DSP %d: G168 DSP Reset Framing Stats Success %d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, framing_reset_status); + + rxt1_card_unselect_dsp(rxt1_card, span_num); + return; +} + +static void rxt1_card_dsp_cpustats(struct rxt1_card_t *rxt1_card, int span_num) +{ + gpakReadCpuUsageStat_t cpu_status_status; + unsigned short int pPeakUsage, pPrev1SecPeakUsage; + unsigned short int DspId; + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + DspId = (rxt1_card->num * 4) + span_num; + + cpu_status_status = + gpakReadCpuUsage(rxt1_card, DspId, &pPeakUsage, &pPrev1SecPeakUsage); + if (cpu_status_status) + printk("R%dT1 %d DSP %d: G168 DSP CPU Status Failed %d\n", rxt1_card->numspans, + rxt1_card->num + 1, DspId + 1, cpu_status_status); + else + printk("R%dT1 %d DSP %d: G168 DSP CPU Status peek %2d 1 S %2d\n", + rxt1_card->numspans, rxt1_card->num + 1, DspId + 1, pPeakUsage, + pPrev1SecPeakUsage); + + rxt1_card_unselect_dsp(rxt1_card, span_num); + return; +} + +static void rxt1_chan_ec_enable(struct rxt1_card_t *rxt1_card, int span_num, int chan_num) +{ + gpakAlgControlStat_t a_c_stat; + GPAK_AlgControlStat_t a_c_err; + unsigned short int DspId; + unsigned int en_mask = ec_disable_1; + unsigned int mask; + + if (span_num == 1) + en_mask = ec_disable_2; + if (span_num == 2) + en_mask = ec_disable_3; + if (span_num == 3) + en_mask = ec_disable_4; + + if (en_mask & (1 << chan_num)) { + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Can NOT enable DSP %d EC Chan %d\n", rxt1_card->num + 1, + span_num, chan_num); + return; + } + + DspId = (rxt1_card->num * 4) + span_num; + + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Can enable DSP %d EC Chan %d\n", rxt1_card->num + 1, + span_num, chan_num); + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + + if ((a_c_stat = gpakAlgControl(rxt1_card, DspId, chan_num, EnableEcanB, &a_c_err))) { + if ((a_c_stat = + gpakAlgControl(rxt1_card, DspId, chan_num, EnableEcanB, &a_c_err))) { + if ((a_c_stat = + gpakAlgControl(rxt1_card, DspId, chan_num, EnableEcanB, &a_c_err))) { + printk + ("R%dT1 %d: G168 DSP Enable Alg Control failed res = %d error = %d\n", + rxt1_card->numspans, rxt1_card->num + 1, a_c_stat, a_c_err); + } + } + } + + msleep(1); + + mask = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_ECA1 + (span_num * 2)); + mask |= (1 << chan_num); + + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Mask %x\n", rxt1_card->num + 1, mask); + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + return; +} + +static void rxt1_chan_ec_disable(struct rxt1_card_t *rxt1_card, int span_num, + int chan_num) +{ + gpakAlgControlStat_t a_c_stat; + GPAK_AlgControlStat_t a_c_err; + unsigned short int DspId; + unsigned int mask; + + DspId = (rxt1_card->num * 4) + span_num; + + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Can disable DSP %d EC Chan %d\n", rxt1_card->num + 1, + span_num, chan_num); + + rxt1_card_select_dsp(rxt1_card, span_num, 0); + + if ((a_c_stat = gpakAlgControl(rxt1_card, DspId, chan_num, BypassEcanB, &a_c_err))) { + if ((a_c_stat = + gpakAlgControl(rxt1_card, DspId, chan_num, BypassEcanB, &a_c_err))) { + if ((a_c_stat = + gpakAlgControl(rxt1_card, DspId, chan_num, BypassEcanB, &a_c_err))) { + printk + ("R%dT1 %d: G168 DSP Disable Alg Control failed res = %d error = %d\n", + rxt1_card->numspans, rxt1_card->num + 1, a_c_stat, a_c_err); + } + } + } + + msleep(1); + + mask = __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_ECA1 + (span_num * 2)); + mask &= ~(1 << chan_num); + + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Mask %x\n", rxt1_card->num + 1, mask); + + rxt1_card_unselect_dsp(rxt1_card, span_num); + + return; +} + +static int rxt1_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, + struct dahdi_echocanparam *p, + struct dahdi_echocan_state **ec) +{ + struct dahdi_span *span = chan->span; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + + int span_num, chan_num; + const struct dahdi_echocan_ops *ops; + const struct dahdi_echocan_features *features; + ops = &my_ec_ops; + features = &my_ec_features; + + if (ecp->param_count > 0) { + printk(KERN_WARNING + "RXT1 echo canceller does not support parameters; failing request\n"); + return -EINVAL; + } + + span_num = chan->span->offset; + chan_num = chan->chanpos - 1; + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Can control Span %d Chan %d dahdi_chan %d\n", + rxt1_card->num + 1, span_num + 1, chan_num, chan->channo); + + if (rxt1_span->dsp_up == 1) { + *ec = rxt1_span->ec[chan_num]; + printk("ec %x\n", (__u32) (ec)); + + (*ec)->ops = ops; + (*ec)->features = *features; + rxt1_card->nextec[span_num] |= (1 << chan_num); + printk("rxt1 echo can create nextec %x\n", rxt1_card->nextec[span_num]); + queue_work(rxt1_card->dspwq, &rxt1_card->dspwork); + } + + return 0; +} + +static void rxt1_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) +{ + struct dahdi_span *span = chan->span; + struct rxt1_span_t *rxt1_span = container_of(span, struct rxt1_span_t, span); + struct rxt1_card_t *rxt1_card = rxt1_span->owner; + int span_num, chan_num; + + memset(ec, 0, sizeof(*ec)); + chan_num = chan->chanpos - 1; + + span_num = chan->span->offset; + chan_num = chan->chanpos - 1; + if (debug & DEBUG_DSP) + printk("rxt1 %d: Echo Can control Span %d Chan %d dahdi_chan %d\n", + rxt1_card->num + 1, span_num + 1, chan_num, chan->channo); + + if (rxt1_span->dsp_up == 1) { + printk("rxt1 echo can free nextec %x\n", rxt1_card->nextec[span_num]); + rxt1_card->nextec[span_num] &= ~(1 << chan_num); + queue_work(rxt1_card->dspwq, &rxt1_card->dspwork); + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void echocan_bh(void *data) +{ + struct rxt1_card_t *rxt1_card = data; +#else +static void echocan_bh(struct work_struct *data) +{ + struct rxt1_card_t *rxt1_card = container_of(data, struct rxt1_card_t, dspwork); +#endif + unsigned int todo[4], chan_num, span_num; + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + todo[span_num] = rxt1_card->nextec[span_num] ^ rxt1_card->currec[span_num]; + if (debug & DEBUG_DSP) { + printk("rxt1: %d Span %d Echo Can control bh change %x to %x\n", + rxt1_card->num + 1, span_num, todo[span_num], + (rxt1_card->nextec[span_num] & todo[span_num])); + printk("nextec %x currec %x\n", rxt1_card->nextec[span_num], + rxt1_card->currec[span_num]); + } + + for (chan_num = 0; chan_num < rxt1_card->rxt1_spans[span_num]->span.channels; + chan_num++) { + if (todo[span_num] & (1 << chan_num)) { + if (rxt1_card->nextec[span_num] & (1 << chan_num)) { + rxt1_chan_ec_enable(rxt1_card, span_num, chan_num); + rxt1_card->currec[span_num] |= (1 << chan_num); + } else { + rxt1_chan_ec_disable(rxt1_card, span_num, chan_num); + rxt1_card->currec[span_num] &= ~(1 << chan_num); + } + } + } + } +} + +static int __devinit rxt1_card_init_dsp(struct rxt1_card_t *rxt1_card) +{ + int loops = 0; + __u16 high, low; + int span_num, chan_num, chan_count; + int ifb_z = 4; + int strt = 4; + int skip = 4; + + if (debug & DEBUG_DSP) + printk("Reset DSP\n"); + rxt1_card_reset_dsp(rxt1_card); + if (debug & DEBUG_DSP) + printk("Un-Reset DSP\n"); + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB1, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB2, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB3, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB4, 0, 0); + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA1, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA2, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA3, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA4, 0, 0); + + if (no_ec) + return 0; + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, + (~EC_ON & __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC)), + target_regs[RXT1_HPIC].iomask); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + if (rxt1_span_download_dsp(rxt1_card, span_num)) { + return -1; + } + } + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_span_run_dsp(rxt1_card, span_num); + if (debug & DEBUG_DSP) + printk("R%dT1 %d DSP %d: GO!!\n", rxt1_card->numspans, rxt1_card->num + 1, + (rxt1_card->num * 4) + span_num + 1); + } + + while (ifb_z != 0) { + ifb_z = 0; + msleep(100); + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_select_dsp(rxt1_card, span_num, 0); + high = rxt1_card_dsp_get(rxt1_card, DSP_IFBLK_ADDRESS); + low = rxt1_card_dsp_get(rxt1_card, DSP_IFBLK_ADDRESS + 1); + if (debug & DEBUG_DSP) + printk("R%dT1 %d DSP %d: IfBlockPntr %x\n", rxt1_card->numspans, + rxt1_card->num + 1, (rxt1_card->num * 4) + span_num + 1, + ((high << 16) + low)); + if ((high == 0) && (low == 0)) + ifb_z++; + rxt1_card_unselect_dsp(rxt1_card, span_num); + } + schedule(); + if ((loops++) > 2) { + printk("R%dT1 %d at least one DSP did not respond No EC configured\n", + rxt1_card->numspans, rxt1_card->num + 1); + return -1; + } + } + + rxt1_card->hpi_fast = 0; + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_ping(rxt1_card, span_num); + } + + Gpak_32_chan_port_config.FirstSlotMask2 = 0x1111; + Gpak_32_chan_port_config.SecSlotMask2 = 0x1111; + Gpak_32_chan_port_config.ThirdSlotMask2 = 0x1111; + Gpak_32_chan_port_config.FouthSlotMask2 = 0x1111; + Gpak_32_chan_port_config.FifthSlotMask2 = 0x1111; + Gpak_32_chan_port_config.SixthSlotMask2 = 0x1111; + Gpak_32_chan_port_config.SevenSlotMask2 = 0x1111; + Gpak_32_chan_port_config.EightSlotMask2 = 0x1111; + Gpak_32_chan_port_config.FirstSlotMask3 = 0x1111; + Gpak_32_chan_port_config.SecSlotMask3 = 0x1111; + Gpak_32_chan_port_config.ThirdSlotMask3 = 0x1111; + Gpak_32_chan_port_config.FouthSlotMask3 = 0x1111; + Gpak_32_chan_port_config.FifthSlotMask3 = 0x1111; + Gpak_32_chan_port_config.SixthSlotMask3 = 0x1111; + Gpak_32_chan_port_config.SevenSlotMask3 = 0x1111; + Gpak_32_chan_port_config.EightSlotMask3 = 0x1111; + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + + if (rxt1_span_dsp_configureports(rxt1_card, Gpak_32_chan_port_config, span_num)) + return -1; + + Gpak_32_chan_port_config.FirstSlotMask2 <<= 1; + Gpak_32_chan_port_config.SecSlotMask2 <<= 1; + Gpak_32_chan_port_config.ThirdSlotMask2 <<= 1; + Gpak_32_chan_port_config.FouthSlotMask2 <<= 1; + Gpak_32_chan_port_config.FifthSlotMask2 <<= 1; + Gpak_32_chan_port_config.SixthSlotMask2 <<= 1; + Gpak_32_chan_port_config.SevenSlotMask2 <<= 1; + Gpak_32_chan_port_config.EightSlotMask2 <<= 1; + Gpak_32_chan_port_config.FirstSlotMask3 <<= 1; + Gpak_32_chan_port_config.SecSlotMask3 <<= 1; + Gpak_32_chan_port_config.ThirdSlotMask3 <<= 1; + Gpak_32_chan_port_config.FouthSlotMask3 <<= 1; + Gpak_32_chan_port_config.FifthSlotMask3 <<= 1; + Gpak_32_chan_port_config.SixthSlotMask3 <<= 1; + Gpak_32_chan_port_config.SevenSlotMask3 <<= 1; + Gpak_32_chan_port_config.EightSlotMask3 <<= 1; + } + + Gpak_chan_config.EcanParametersA.EcanNlpType = nlp_type; + Gpak_chan_config.EcanParametersB.EcanNlpType = nlp_type; + + Gpak_chan_config.EcanEnableB = Enabled; + + Gpak_chan_config.EcanEnableA = Disabled; + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_ping(rxt1_card, span_num); + } + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + chan_count = 0; + + for (chan_num = 0; chan_num < rxt1_card->rxt1_spans[span_num]->span.channels; + chan_num++) { + + if (rxt1_card->rxt1_spans[span_num]->spantype == TYPE_E1) { + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_XLATE1 + span_num, + 0xffff7fff, 0); + if (chan_num != 15) + Gpak_chan_config.SoftwareCompand = cmpPCMU; + else + Gpak_chan_config.SoftwareCompand = cmpNone; + } else + Gpak_chan_config.SoftwareCompand = cmpPCMU; + + + msleep(1); + chan_count++; + Gpak_chan_config.PcmInSlotA = (span_num + strt) + (chan_num * skip); + Gpak_chan_config.PcmOutSlotA = (span_num + strt) + (chan_num * skip); + Gpak_chan_config.PcmInSlotB = (span_num + strt) + (chan_num * skip); + Gpak_chan_config.PcmOutSlotB = (span_num + strt) + (chan_num * skip); + + if (rxt1_span_dsp_configurechannel + (rxt1_card, Gpak_chan_config, chan_num, span_num)) + return -1; + + rxt1_chan_ec_disable(rxt1_card, span_num, chan_num); + + } + printk("R%dT1 %d DSP %d: %d channels configured\n", rxt1_card->numspans, + rxt1_card->num + 1, (rxt1_card->num * 4) + span_num + 1, chan_count); + + } + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card->rxt1_spans[span_num]->dsp_up = 1; + /* we have to coerce the ops pointer to remove the const, because we + * don't necessarily know what this pointer was supposed to be until now. */ + ((struct dahdi_span_ops *) + rxt1_card->rxt1_spans[span_num]->span.ops)->echocan_create = rxt1_echocan_create; + } + + if (debug & DEBUG_DSP) { + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_cpustats(rxt1_card, span_num); + rxt1_card_dsp_framestats(rxt1_card, span_num); + rxt1_card_dsp_reetframestats(rxt1_card, span_num); + + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_cpustats(rxt1_card, span_num); + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_cpustats(rxt1_card, span_num); + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + + msleep(100); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_framestats(rxt1_card, span_num); + } + } +#if 1 + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, + (EC_ON | __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC)), + target_regs[RXT1_HPIC].iomask); +#else + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_HPIC, + (~EC_ON & __rxt1_card_pci_in(rxt1_card, TARG_REGS + RXT1_HPIC)), + target_regs[RXT1_HPIC].iomask); + +#endif + + /* this is selecting the A EC (route around the B) */ + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB1, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB2, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB3, 0, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECB4, 0, 0); + + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA1, 0xffffffff, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA2, 0xffffffff, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA3, 0xffffffff, 0); + __rxt1_card_pci_out(rxt1_card, TARG_REGS + RXT1_ECA4, 0xffffffff, 0); + + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) { + rxt1_card_dsp_ping(rxt1_card, span_num); + } + + rxt1_card->dspwq = create_singlethread_workqueue("rxt1_ec"); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&rxt1_card->dspwork, echocan_bh, rxt1_card); +#else + INIT_WORK(&rxt1_card->dspwork, echocan_bh); +#endif + + printk("R%dT1: G168 DSP configured successfully\n", rxt1_card->numspans); + + return (0); +} + + + +static int __devinit rxt1_card_launch(struct rxt1_card_t *rxt1_card) +{ + int span_num; + if (rxt1_card->rxt1_spans[0]->span.flags & DAHDI_FLAG_REGISTERED) + return 0; + printk("R%dT1: Launching card: %d\n", rxt1_card->numspans, rxt1_card->order); + + /* Setup serial parameters and system interface */ + for (span_num = 0; span_num < rxt1_card->numspans; span_num++) + rxt1_span_serial_setup(rxt1_card, span_num); + + if (dahdi_register(&rxt1_card->rxt1_spans[0]->span, 0)) { + printk(KERN_ERR "Unable to register span %s\n", + rxt1_card->rxt1_spans[0]->span.name); + return -1; + } + if (dahdi_register(&rxt1_card->rxt1_spans[1]->span, 0)) { + printk(KERN_ERR "Unable to register span %s\n", + rxt1_card->rxt1_spans[1]->span.name); + dahdi_unregister(&rxt1_card->rxt1_spans[0]->span); + return -1; + } + + if (rxt1_card->numspans == 4) { + if (dahdi_register(&rxt1_card->rxt1_spans[2]->span, 0)) { + printk(KERN_ERR "Unable to register span %s\n", + rxt1_card->rxt1_spans[2]->span.name); + dahdi_unregister(&rxt1_card->rxt1_spans[0]->span); + dahdi_unregister(&rxt1_card->rxt1_spans[1]->span); + return -1; + } + if (dahdi_register(&rxt1_card->rxt1_spans[3]->span, 0)) { + printk(KERN_ERR "Unable to register span %s\n", + rxt1_card->rxt1_spans[3]->span.name); + dahdi_unregister(&rxt1_card->rxt1_spans[0]->span); + dahdi_unregister(&rxt1_card->rxt1_spans[1]->span); + dahdi_unregister(&rxt1_card->rxt1_spans[2]->span); + return -1; + } + } + rxt1_card->checktiming = 1; + __rxt1_card_set_timing_source(rxt1_card, 4, 0, 0); +#ifdef ENABLE_TASKLETS + tasklet_init(&rxt1_card->t4_tlet, t4_tasklet, (unsigned long) rxt1_card); +#endif + + /* check to see if the hardware version is compativle with this driver version */ + if (rxt1_card->version > 35) + rxt1_card_init_dsp(rxt1_card); + else + printk("R%dT1: Found HW version less than 36, need to upgrade your hardware! \n", + rxt1_card->numspans); + + return 0; +} + +static int __devinit rxt1_driver_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct rxt1_card_t *rxt1_card; + struct devtype *dt; + int x, f; + int basesize; + /* used for kmalloc'ing large blocks */ + struct rxt1_span_t *span_block; + struct dahdi_chan *chan_block; + struct dahdi_echocan_state *ec_block; + int chan_count; + + if (pci_enable_device(pdev)) + return -EIO; + + for (x = 0; x < MAX_RXT1_CARDS; x++) { + if (!rxt1_cards[x]) + break; + } + + if (x >= MAX_RXT1_CARDS) { + printk("rxt1: No cards[] slot available!!\n"); + return -ENOMEM; + } + + rxt1_card = kmalloc(sizeof *rxt1_card, GFP_KERNEL); + if (rxt1_card == NULL) + return -ENOMEM; + + memset(rxt1_card, 0x0, sizeof *rxt1_card); + + dt = (struct devtype *) (ent->driver_data); + if (dt->flags & FLAG_2PORT) + rxt1_card->numspans = 2; + else + rxt1_card->numspans = 4; + + span_block = kmalloc(rxt1_card->numspans * sizeof *span_block, GFP_KERNEL); + + if (span_block == NULL) { + kfree(rxt1_card); + return -ENOMEM; + } + + memset(span_block, 0, rxt1_card->numspans * sizeof *span_block); + + /* Read T1/E1 status or something */ + if (t1e1override > -1) + rxt1_card->t1e1 = t1e1override; + else + rxt1_card->t1e1 = 0x0; + + rxt1_cards[x] = rxt1_card; + rxt1_card->num = x; + spin_lock_init(&rxt1_card->reglock); + basesize = DAHDI_MAX_CHUNKSIZE * 32 * 2 * 4; + + rxt1_card->variety = dt->desc; + + rxt1_card->memaddr = pci_resource_start(pdev, 0); + rxt1_card->memlen = pci_resource_len(pdev, 0); + rxt1_card->membase = ioremap(rxt1_card->memaddr, rxt1_card->memlen); + + /* This rids of the Double missed interrupt message after loading */ + rxt1_card->last0 = 1; + + if (pci_request_regions(pdev, rxt1_card->variety)) + printk("R%dT1: Unable to request regions\n", rxt1_card->numspans); + + printk("Found R%dT1 at base address %08lx, remapped to %p\n", + rxt1_card->numspans, rxt1_card->memaddr, rxt1_card->membase); + + rxt1_card->dev = pdev; + rxt1_card->dsp_type = DSP_5510; + rxt1_card->writechunk = /* 32 channels, Double-buffer, Read/Write, 4 spans */ + pci_alloc_consistent(pdev, basesize * 2, &rxt1_card->writedma); + + if (!rxt1_card->writechunk) { + printk("R%dT1: Unable to allocate DMA-able memory\n", rxt1_card->numspans); + kfree(span_block); + iounmap(rxt1_card->membase); + pci_release_regions(pdev); + rxt1_cards[rxt1_card->num] = NULL; + kfree(rxt1_card); + return -ENOMEM; + } + + /* Read is after the whole write piece (in words) */ + if (memloop == 0) + rxt1_card->readchunk = rxt1_card->writechunk + basesize / 4; + else + rxt1_card->readchunk = rxt1_card->writechunk; // PC memory loop back + + /* Same thing but in bytes... */ + rxt1_card->readdma = rxt1_card->writedma + basesize; + + printk("R%dT1: writechunk %p readchunk %p writedma %x readdma %x basesize %x\n", + rxt1_card->numspans, rxt1_card->writechunk, rxt1_card->readchunk, + rxt1_card->writedma, rxt1_card->readdma, basesize); + + /* Initialize Write/Buffers to all blank data */ + memset((void *) rxt1_card->writechunk, 0x00, basesize); + if (memloop == 0) + memset((void *) rxt1_card->readchunk, 0xff, basesize); + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* Keep track of which device we are */ + pci_set_drvdata(pdev, rxt1_card); + + /* Initialize hardware */ + rxt1_card_hardware_init_1(rxt1_card, 1); + +#ifdef ENABLE_WORKQUEUES + char tmp[20]; + sprintf(tmp, "R%dT1[%d]", rxt1_card->numspans, rxt1_card->num); + rxt1_card->workq = create_workqueue(tmp); +#endif + + /* Allocate pieces we need here */ + for (x = 0; x < rxt1_card->numspans; x++) { + rxt1_card->rxt1_spans[x] = span_block + x; + + if (rxt1_card->t1e1 & (1 << x)) { + rxt1_card->rxt1_spans[x]->spantype = TYPE_E1; + } else if (j1mode) { + rxt1_card->rxt1_spans[x]->spantype = TYPE_J1; + } else { + rxt1_card->rxt1_spans[x]->spantype = TYPE_T1; + } + + chan_count = rxt1_card->rxt1_spans[x]->spantype == TYPE_E1 ? 31 : 24; + chan_block = kmalloc(chan_count * sizeof *chan_block, GFP_KERNEL); + ec_block = kmalloc(chan_count * sizeof *ec_block, GFP_KERNEL); + + if (chan_block == NULL || ec_block == NULL) { + if (chan_block) + kfree(chan_block); + + if (ec_block) + kfree(ec_block); + + /* free all the preceding chans, and all of the ecs. + * note that rxt1_card->rxt1_spans[x]->chans[0] is the block kmalloc'd previously. + * note that rxt1_card->rxt1_spans[x]->ec[0] is the block kmalloc'd previously. + */ + while (--x >= 0) { + kfree(rxt1_card->rxt1_spans[x]->chans[0]); + kfree(rxt1_card->rxt1_spans[x]->ec[0]); + } + + kfree(span_block); + iounmap(rxt1_card->membase); + pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, + (void *) rxt1_card->writechunk, rxt1_card->writedma); + pci_release_regions(pdev); + rxt1_cards[rxt1_card->num] = NULL; + kfree(rxt1_card); + return -ENOMEM; + } + + memset(chan_block, 0, chan_count * sizeof *chan_block); + memset(ec_block, 0, chan_count * sizeof *ec_block); + + for (f = 0; f < chan_count; f++) { + rxt1_card->rxt1_spans[x]->chans[f] = chan_block + f; + rxt1_card->rxt1_spans[x]->ec[f] = ec_block + f; + } + +#ifdef ENABLE_WORKQUEUES + INIT_WORK(&rxt1_card->rxt1_spans[x]->swork, workq_handlespan, + rxt1_card->rxt1_spans[x]); +#endif + rxt1_card->rxt1_spans[x]->spanflags |= dt->flags; + } + + /* Continue hardware intiialization */ + rxt1_card_hardware_init_2(rxt1_card); + + if (request_irq + (pdev->irq, rxt1_card_interrupt_gen2, DAHDI_IRQ_SHARED, "rxt1", rxt1_card)) { + printk("R%dT1: Unable to request IRQ %d\n", rxt1_card->numspans, pdev->irq); + for (x = 0; x < rxt1_card->numspans; x++) { + kfree(rxt1_card->rxt1_spans[x]->chans[0]); + kfree(rxt1_card->rxt1_spans[x]->ec[0]); + } + + kfree(span_block); + iounmap(rxt1_card->membase); + + pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, + (void *) rxt1_card->writechunk, rxt1_card->writedma); + + kfree(rxt1_card); + pci_release_regions(pdev); + rxt1_cards[rxt1_card->num] = NULL; + return -EIO; + } + + rxt1_card_init_spans(rxt1_card); + + /* Launch cards as appropriate */ + x = 0; + for (;;) { + /* Find a card to activate */ + f = 0; + for (x = 0; rxt1_cards[x]; x++) { + if (rxt1_cards[x]->order <= highestorder) { + rxt1_card_launch(rxt1_cards[x]); + if (rxt1_cards[x]->order == highestorder) + f = 1; + } + } + + /* If we found at least one, increment the highest order and search again, + * otherwise stop */ + if (f) + highestorder++; + else + break; + } + + printk("rxt1: Found a Rhino: %s\n", rxt1_card->variety); + + return 0; +} + +static int rxt1_card_hardware_stop(struct rxt1_card_t *rxt1_card) +{ + + /* Turn off DMA, leave interrupts enabled */ + rxt1_card->stopdma = 1; + + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout((25 * HZ) / 1000); + + /* Turn off counter, address, etc */ + rxt1_card_tsi_reset(rxt1_card); + printk("\nStopped R%dT1, Turned off DMA\n", rxt1_card->numspans); + return 0; +} + +static void __devexit rxt1_driver_remove_one(struct pci_dev *pdev) +{ + struct rxt1_card_t *rxt1_card = pci_get_drvdata(pdev); + int x; + + if (rxt1_card) { + /* Stop hardware */ + rxt1_card_hardware_stop(rxt1_card); + + /* Unregister spans */ + if (rxt1_card->rxt1_spans[0]->span.flags & DAHDI_FLAG_REGISTERED) + dahdi_unregister(&rxt1_card->rxt1_spans[0]->span); + if (rxt1_card->rxt1_spans[1]->span.flags & DAHDI_FLAG_REGISTERED) + dahdi_unregister(&rxt1_card->rxt1_spans[1]->span); + if (rxt1_card->numspans == 4) { + if (rxt1_card->rxt1_spans[2]->span.flags & DAHDI_FLAG_REGISTERED) + dahdi_unregister(&rxt1_card->rxt1_spans[2]->span); + if (rxt1_card->rxt1_spans[3]->span.flags & DAHDI_FLAG_REGISTERED) + dahdi_unregister(&rxt1_card->rxt1_spans[3]->span); + } +#ifdef ENABLE_WORKQUEUES + if (rxt1_card->workq) { + flush_workqueue(rxt1_card->workq); + destroy_workqueue(rxt1_card->workq); + } +#endif + + if (rxt1_card->membase) + iounmap(rxt1_card->membase); + + pci_release_regions(pdev); + + if (rxt1_card->memaddr) + release_mem_region(rxt1_card->memaddr, rxt1_card->memlen); + + /* Immediately free resources */ + pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, + (void *) rxt1_card->writechunk, rxt1_card->writedma); + + free_irq(pdev->irq, rxt1_card); + + rxt1_cards[rxt1_card->num] = NULL; + pci_set_drvdata(pdev, NULL); + + for (x = 0; x < rxt1_card->numspans; x++) { + /* + * recall that from init_one, a large block is allocated, one + * each for the chans and ec blocks. + */ + kfree(rxt1_card->rxt1_spans[x]->chans[0]); + kfree(rxt1_card->rxt1_spans[x]->ec[0]); + } + + /* + * recall that from init_one, a large block is allocated for all + * the spans for the rxt1_card. + */ + kfree(rxt1_card->rxt1_spans[0]); + + kfree(rxt1_card); + } +} + +static struct pci_device_id rxt1_pci_tbl[] __devinitdata = { + /* vendor device */ + {0x0b0b, 0x0305, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &r4t1}, + {0x0b0b, 0x0605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &r2t1}, + {0,} +}; + +static struct pci_driver rxt1_driver = { + name:"Rhino Equipment 1-2-4 Span T1-E1-J1 PCI Driver", + probe:rxt1_driver_init_one, + remove:__devexit_p(rxt1_driver_remove_one), + suspend:NULL, + resume:NULL, + id_table:rxt1_pci_tbl, +}; + +static int __init rxt1_driver_init(void) +{ + int res; + res = dahdi_pci_module(&rxt1_driver); + if (res) + return -ENODEV; + return 0; +} + +static void __exit rxt1_cleanup(void) +{ + pci_unregister_driver(&rxt1_driver); +} + + +MODULE_AUTHOR + ("Bob Conklin \n\tBryce Chidester \n\tMatthew Gessner + * Bryce Chidester + * Matthew Gessner + * + * Based on Digium's TDM400P TDM FXS/FXO + * and Zapata Telephony's Zaptel Telephony Interface + * + * Copyright (C) 2005-2010, Rhino Equipment Corp. + * Copyright (C) 2001-2005, Digium, Inc. + * Copyright (C) 2001 Jim Dixon / Zapata Telephony. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * * * * * * * * * * * * * NO WARRANTY * * * * * * * * * * * * * * * * * + * + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + * + * * * * * * * * * * * * DISCLAIMER OF LIABILITY * * * * * * * * * * * * + * + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _RCBFX_IOCTL_H +#define _RCBFX_IOCTL_H + +#include + +#define PARAM_TBL 0x900 +#define P_TBL_CNT 424 + +struct rcb_card_params_t { + unsigned char settings[P_TBL_CNT]; +}; + + +static unsigned char rcb_settings_default[P_TBL_CNT] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // signaling + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // transmit gain + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // receive gain + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // power down + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // analog mode + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hybrid + 70, // country + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VOX base + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // high trigger + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, // low trigger + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // on settle time + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, // off settle time + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + // Default USA parameters + 0x45, 0x60, 0xD4, 0x2A, 0xAA, 0x2B, 0xBD, 0x33, 0xA2, 0x00, // IM-Filter part 1 + 0x45, 0x68, 0xAC, 0x01, 0x29, 0x8D, 0x0E, 0x77, 0x09, 0x00, // IM-Filter part 2 + 0x45, 0x18, 0x08, 0xA0, 0xCA, 0x23, 0x66, 0xFA, 0x9E, 0x07, // FRR-Filter + 0x45, 0x28, 0x2B, 0xAB, 0x46, 0xA5, 0x88, 0x00, 0x00, 0x00, // AR-Filter + 0x45, 0x48, 0x96, 0x38, 0x29, 0x96, 0xC9, 0x2B, 0x8B, 0x00, // LPR-Filter + 0x45, 0x20, 0x08, 0x50, 0xF9, 0x87, 0x72, 0x48, 0x8F, 0x02, // FRX-Filter + 0x45, 0x30, 0xB2, 0x10, 0xC5, 0x0D, 0x85, 0x50, 0xC0, 0x1A, // AX-Filter + 0x45, 0x50, 0x96, 0x38, 0x29, 0xF5, 0xFA, 0x2B, 0x8B, 0x00, // LPX-Filter + 0x45, 0x00, 0x00, 0x08, 0x08, 0x81, 0x00, 0x80, 0x00, 0x08, // TH-Filter part 1 + 0x45, 0x08, 0x81, 0x00, 0x6A, 0xE8, 0xB0, 0x33, 0xAA, 0x01, // TH-Filter part 2 + 0x45, 0x10, 0x87, 0x32, 0xCA, 0x9C, 0xC4, 0xF2, 0x88, 0x00, // TH-Filter part 3 + 0x45, 0x80, 0xCB, 0x49, 0xA2, 0x5A, 0x22, 0xC3, 0x21, 0x22, // DC-Parameter + 0x45, 0x70, 0x90, 0x30, 0x1B, 0xC0, 0x33, 0x12, 0xAC, 0x02, // Ringing + 0x45, 0x90, 0x3E, 0xE5, 0x2E, 0x29, 0x86, 0xB4, 0x29, 0x83, // LP-Filters + 0x45, 0x88, 0xC0, 0x04, 0x2C, 0x7B, 0xB3, 0x47, 0x7B, 0x01, // Hook Levels + 0x45, 0x78, 0x00, 0xC0, 0x6D, 0xA5, 0xB2, 0x48, 0x08, 0x00, // Ramp Generator + 0x45, 0x58, 0x90, 0x40, 0x34, 0xDB, 0x0E, 0xA2, 0x2A, 0x00, // TTX + 0x45, 0x38, 0x08, 0x00, 0xA3, 0x05, 0xB3, 0x01, 0x00, 0x00, // TG1 + 0x45, 0x40, 0x09, 0x00, 0xA3, 0x05, 0x08, 0x00, 0x00, 0x00, // TG2 + 0x45, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved + 0x44, 0x15, 0x00, 0x20, 0x93, 0x00 // SOP,BCR1,...BCR4 +}; // 218 base stuff + 206 for country = 424 + +// unsigned char rcb_card_params[214] +// int num_chans; + +struct rcb_chan_echo_coefs { + unsigned char acim; + unsigned char coef1; + unsigned char coef2; + unsigned char coef3; + unsigned char coef4; + unsigned char coef5; + unsigned char coef6; + unsigned char coef7; + unsigned char coef8; +}; + +#define RCB_CHAN_SET_ECHOTUNE _IOW (DAHDI_CODE, 63, struct rcb_chan_echo_coefs) +#define RCB_CHAN_SET_CBPARAMS _IOW (DAHDI_CODE, 64, struct rcb_card_params_t) +#define RCB_CHAN_GET_BDINFO _IOR (DAHDI_CODE, 65, int) + +#endif /* _RCBFX_IOCTL_H */