diff options
author | mattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-07-20 19:14:09 +0000 |
---|---|---|
committer | mattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-07-20 19:14:09 +0000 |
commit | 3c9433e21c91042d90622c37ae45fa55ed2e563a (patch) | |
tree | 9ea6272aa8389e5ddd30ab5d6c2521cf4f1860ba | |
parent | 54047ea02884d1029d5f3dfecfe1c43791e677c8 (diff) |
Merged revisions 2762 via svnmerge from
https://origsvn.digium.com/svn/zaptel/branches/1.4
................
r2762 | mattf | 2007-07-20 13:54:20 -0500 (Fri, 20 Jul 2007) | 9 lines
Merged revisions 2761 via svnmerge from
https://origsvn.digium.com/svn/zaptel/branches/1.2
........
r2761 | mattf | 2007-07-20 11:19:47 -0500 (Fri, 20 Jul 2007) | 1 line
New product support, new echo canceler and new boards
........
................
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2763 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | wctdm24xxp/GpakApi.c | 1609 | ||||
-rw-r--r-- | wctdm24xxp/GpakApi.h | 619 | ||||
-rw-r--r-- | wctdm24xxp/GpakCust.c | 388 | ||||
-rw-r--r-- | wctdm24xxp/GpakCust.h | 161 | ||||
-rw-r--r-- | wctdm24xxp/GpakHpi.h | 63 | ||||
-rw-r--r-- | wctdm24xxp/Makefile | 22 | ||||
-rw-r--r-- | wctdm24xxp/Makefile.kernel26 | 12 | ||||
-rw-r--r-- | wctdm24xxp/VPMADT032.bin | bin | 0 -> 60980 bytes | |||
-rw-r--r-- | wctdm24xxp/base.c (renamed from wctdm24xxp.c) | 1258 | ||||
-rw-r--r-- | wctdm24xxp/gpakErrs.h | 139 | ||||
-rw-r--r-- | wctdm24xxp/gpakenum.h | 175 | ||||
-rw-r--r-- | wctdm24xxp/wctdm24xxp.h | 237 |
13 files changed, 4364 insertions, 328 deletions
@@ -125,7 +125,7 @@ ifeq ($(strip $(foreach var,clean distclean dist-clean update,$(findstring $(var endif endif -MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wctdm24xxp wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode +MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode MODULES:=$(filter-out $(MENUSELECT_MODULES),$(MODULES)) MODULE_ALIASES=wcfxs wctdm8xxp wct2xxp @@ -160,6 +160,11 @@ obj-m+=xpp/ MODULES+=xpp endif +ifeq ($(findstring wctdm24xxp,$(MENUSELECT_MODULES)),) +obj-m+=wctdm24xxp/ +MODULES+=wctdm24xxp +endif + # Set this to override hotplug firmware loading and revert to classic header #HOTPLUG_FIRMWARE=no ifeq ($(HOTPLUG_FIRMWARE),yes) @@ -220,8 +225,6 @@ wcfxsusb.o: wcfxsusb.h wctdm.o: wctdm.h -wctdm24xxp.o: wctdm.h - pciradio.o: radfw.h ztdummy.o: ztdummy.h diff --git a/wctdm24xxp/GpakApi.c b/wctdm24xxp/GpakApi.c new file mode 100644 index 0000000..2abb67a --- /dev/null +++ b/wctdm24xxp/GpakApi.c @@ -0,0 +1,1609 @@ +/* + * 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 "GpakHpi.h" +#include "GpakCust.h" +#include "GpakApi.h" +#include "gpakenum.h" + +/* 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 100 /* 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]; /* Dowload byte buf */ +static DSP_WORD DlWordBufr[DOWNLOAD_BLOCK_SIZE]; /* Dowload 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( + 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(DspId, DSP_IFBLK_ADDRESS, 2, Temp); + RECONSTRUCT_LONGWORD(IfBlockPntr, Temp); + + /* 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(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus); + + /* If status indicates the DSP was reset, read the DSP's interface + parameters and calculate DSP addresses. */ + 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(DspId, IfBlockPntr + MAX_CMD_MSG_LEN_OFFSET, 1, + &(MaxCmdMsgLen[DspId])); + + /* read the number of configured DSP channels */ + gpakReadDspMemory(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(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(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(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 + + /* read the pointer to the event fifo info struct */ + gpakReadDspMemory(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(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( + 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(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(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + if (CmdMsgLength != 0) + return (0); + + /* Purge any previous Reply message that wasn't read. */ + gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1, + &CmdMsgLength); + + /* Copy the Command message into DSP memory. */ + gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakWriteDspMemory(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(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( + 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(DspId) == -1) + return (-1); + + /* Check if a Reply message is ready. */ + gpakReadDspMemory(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(DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp); + RECONSTRUCT_LONGWORD(BufferPointer, Temp); + gpakReadDspMemory(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(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( + 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(DspId, *TakeAddress, WordsTillEnd, pWordBuffer); + gpakReadDspMemory(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(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( + 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(DspId); + + /* Attempt to write the command message to the DSP. */ + LoopCount = 0; + while ((FuncStatus = WriteDspCmdMessage(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(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(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( + 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->SerialWordSize1 & 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)); + + 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(DspId, MsgBuffer, 62, 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( + 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)); + + 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) + ); + + 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(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( + 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(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( + 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(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( + 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) { +#if 0 + printk("Invalid DSP\n"); +#endif + return (RefInvalidDsp); + } + + /* Lock access to the DSP. */ + gpakLockAccess(DspId); + +#if 1 + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(DspId) == -1) + { + gpakUnlockAccess(DspId); +#if 0 + printk("CheckDspReset failed (DspId %d)\n", DspId); +#endif + return (RefDspCommFailure); + } +#endif + + /* Check if an event message is ready in the DSP. */ + EventInfoAddress = pEventFifoAddress[DspId]; + gpakReadDspMemory(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(DspId); + return (RefNoEventAvail); + } + + /* Read the event header from the DSP's Event FIFO. */ + TakeAddress = BufrBaseAddress + TakeIndex; + BufrLastAddress = BufrBaseAddress + BufrSize - 1; + ReadCircBuffer(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(DspId); +#if 0 + printk("EventDataLength > WORD_BUFFER_SIZE (%d)\n", EventDataLength); +#endif + return (RefInvalidEvent); + } + ReadCircBuffer(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) { +#if 0 + printk("EventDataLength != 4 it's %d\n", EventDataLength); +#endif + EventError = 1; + } + break; + + default: +#if 0 + printk("Event Code not in switch\n"); +#endif + EventError = 1; + break; + }; + + /* Update the Take index in the DSP's Packet Out buffer information. */ + gpakWriteDspMemory(DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1, + &TakeIndex); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(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( + 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 */ + + /* 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(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( + 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(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( + 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(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( + 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(DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(DspId) == -1) + return (RcuDspCommFailure); + + /* Read the CPU Usage statistics from the DSP. */ + gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(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( + 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(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( + 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(DspId); + + /* Check if the DSP was reset and is ready. */ + if (CheckDspReset(DspId) == -1) + return (RfsDspCommFailure); + + /* Read the framing interrupt statistics from the DSP. */ + gpakReadDspMemory(DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10, + ReadBuffer); + + /* Unlock access to the DSP. */ + gpakUnlockAccess(DspId); + + /* Store the framing statistics in the specified variables. */ + *pFramingError1Count = ReadBuffer[0]; + *pFramingError2Count = ReadBuffer[1]; + *pFramingError3Count = ReadBuffer[2]; + *pDmaStopErrorCount = ReadBuffer[3]; + + if(pDmaSlipStatsBuffer != 0) + // 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( + 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(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( + 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(DspId); + + RetStatus = GdlSuccess; + while (RetStatus == GdlSuccess) + { + + /* Read a record header from the file. */ + NumRead = gpakReadFile(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(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(DspId, Address, NumWords, DlWordBufr); + Address += ((DSP_ADDRESS) NumWords); + } + } + + /* Unlock access to the DSP. */ + gpakUnlockAccess(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( + 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(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); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakAccessGPIO - change Direction/read/write the GPIO on DSP + * + * FUNCTION + * This function read/write GPIO and change the GPIO direction + * + * + * RETURNS + * Status code indicating success or a specific error. + */ +gpakAccessGPIOStat_t gpakAccessGPIO( + unsigned short int DspId, // DSP identifier + GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read + unsigned short int *pGPIOValue // DSP software version + ) +{ + 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 (GPIOInvalidDsp); + + /* send value of 1, DSP increments it */ + MsgBuffer[0] = (MSG_ACCESSGPIO << 8); + MsgBuffer[1] = (DSP_WORD) ((gpakControlGPIO << 8) | (*pGPIOValue & 0xFF) ); + /* Attempt to send the ping message to the DSP and receive it's + reply. */ + if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ACCESSGPIO_REPLY, 6, 0, 0)) + return (GPIODspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + { + *pGPIOValue = MsgBuffer[2]; + return (GPIOSuccess); + } + else + return (GPIODspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakWriteSystemParms - Write a DSP's System Parameters. + * + * FUNCTION + * This function writes a DSP's System Parameters information. + * + * Note: + * Or-together the desired bit-mask #defines that are listed below. Only + * those algorithm parameters whose bit-mask is selected in the UpdateBits + * function parameter will be updated. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ + +gpakWriteSysParmsStatus_t gpakWriteSystemParms( + unsigned short int DspId, // DSP identifier + GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */ + unsigned short int UpdateBits, /* input: flags indicating which parms to update */ + GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */ + ) +{ + 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 (WspInvalidDsp); + + /* Build the Write System Parameters message. */ + MsgBuffer[0] = MSG_WRITE_SYS_PARMS << 8; + + if (UpdateBits & DTMF_UPDATE_MASK) + { + MsgBuffer[1] |= DTMF_UPDATE_MASK; + MsgBuffer[8] = (DSP_WORD) pSysParms->MinSigLevel; + MsgBuffer[9] = (DSP_WORD) (pSysParms->FreqDeviation & 0xff); + if (pSysParms->SNRFlag) + MsgBuffer[9] |= (1<<8); + } + + MsgBuffer[10] = (DSP_WORD) 0; + if (UpdateBits & DTMF_TWIST_UPDATE_MASK) + { + MsgBuffer[1] |= DTMF_TWIST_UPDATE_MASK; + MsgBuffer[10] |= (DSP_WORD) (pSysParms->DtmfFwdTwist & 0x000f); + MsgBuffer[10] |= (DSP_WORD) ((pSysParms->DtmfRevTwist << 4) & 0x00f0); + } + + + if (UpdateBits & DTMF_VALID_MASK) + { + MsgBuffer[1] |= DTMF_VALID_MASK; + MsgBuffer[11] = (DSP_WORD) (pSysParms->DtmfValidityMask & 0x00ff); + } + + /* Attempt to send the ping message to the DSP and receive it's + reply. */ + if (!TransactCmd(DspId, MsgBuffer, 24, MSG_WRITE_SYS_PARMS_REPLY, 6, 0, 0)) + return (WspDspCommFailure); + + /* Return with an indication of success or failure based on the return + status in the reply message. */ + *pStatus = (GPAK_SysParmsStat_t) (MsgBuffer[2] ); + + DspStatus = (MsgBuffer[1] & 0xFF); + if (DspStatus == 0) + return (WspSuccess); + else + return (WspDspCommFailure); +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakReadSystemParms - Read a DSP's System Parameters. + * + * FUNCTION + * This function reads a DSP's System Parameters information. + * + * RETURNS + * Status code indicating success or a specific error. + * + */ +gpakReadSysParmsStatus_t gpakReadSystemParms( + unsigned short int DspId, // DSP identifier + GpakSystemParms_t *pSysParms /* pointer to System Parms info var */ + ) +{ + + DSP_WORD MsgBuffer[MSG_BUFFER_SIZE]; /* message buffer */ + + /* Make sure the DSP Id is valid. */ + if (DspId >= MAX_DSP_CORES) + return (RspInvalidDsp); + + /* Build the Read System Parameters message. */ + MsgBuffer[0] = MSG_READ_SYS_PARMS << 8; + + /* Attempt to send the ping message to the DSP and receive it's + reply. */ + if (!TransactCmd(DspId, MsgBuffer, 2, MSG_READ_SYS_PARMS_REPLY, 22, 0, 0)) + return (RspDspCommFailure); + + /* Extract the System Parameters information from the message. */ + pSysParms->DtmfValidityMask = (short int)(MsgBuffer[7]) ; + + pSysParms->MinSigLevel = (short int)MsgBuffer[8]; + pSysParms->SNRFlag = (short int)((MsgBuffer[9]>>8) & 0x1); + pSysParms->FreqDeviation = (short int)(MsgBuffer[9] & 0xff); + pSysParms->DtmfFwdTwist = (short int)MsgBuffer[10] & 0x000f; + pSysParms->DtmfRevTwist = (short int)(MsgBuffer[10] >> 4) & 0x000f; + + /* Return with an indication that System Parameters info was obtained. */ + return (RspSuccess); +} diff --git a/wctdm24xxp/GpakApi.h b/wctdm24xxp/GpakApi.h new file mode 100644 index 0000000..8138430 --- /dev/null +++ b/wctdm24xxp/GpakApi.h @@ -0,0 +1,619 @@ +/* + * 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" + +// Bit masks to select which algorithm's parameters to update: Or-together the +// desired masks into the UpdateBits function parameter. +#define DTMF_UPDATE_MASK 0x0010 // update DTMF params, MinLevel, SNRFlag and Freq +#define DTMF_TWIST_UPDATE_MASK 0x0020 // update DTMF TWIST system params +#define DTMF_VALID_MASK 0x0080 // update DTMF ValidMask params + +#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( + 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( + 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( + 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( + 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 */ +} gpakDownloadStatus_t; + +/* + * 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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 + ); + +typedef enum +{ + GPIOSuccess =0, + GPIOInvalidDsp = 1, + GPIODspCommFailure = 2 +}gpakAccessGPIOStat_t; + +extern gpakAccessGPIOStat_t gpakAccessGPIO( + unsigned short int DspId, // DSP identifier + GpakGPIOCotrol_t gpakControlGPIO,// select oeration, changeDIR/write/read + unsigned short int *pGPIOValue // pointer for the read/write value or DIR mask + ); + +/* gpakWriteSystemParms return status. */ +typedef enum +{ + WspSuccess = 0, /* System Parameters written successfully */ + WspParmError = 1, /* Write System Parms's Parameter error */ + WspInvalidDsp = 2, /* invalid DSP */ + WspDspCommFailure = 3 /* failed to communicate with DSP */ +} gpakWriteSysParmsStatus_t; + +/* Definition of a System Parameters information structure. */ +typedef struct +{ + /* DTMF Parameters */ + short int MinSigLevel; /* 0 = Disabled, Min Sig Power Level for detection */ + short int SNRFlag; /* 0 = Disabled, relax SNR tolerances */ + short int FreqDeviation; /* 0 = Disabled, X Percent Deviation times 10 (e.g. 1.7% is entered as 17) */ + short int DtmfFwdTwist; /* 0 to 8 db */ + short int DtmfRevTwist; /* 0 to 8 db */ + + short int DtmfValidityMask; /* This flag allows users to relax the trailing conditions of the tone */ + +} GpakSystemParms_t; +/* gpakReadSystemParms return status. */ +typedef enum +{ + RspSuccess = 0, /* System Parameters read successfully */ + RspInvalidDsp = 1, /* invalid DSP */ + RspDspCommFailure = 2 /* failed to communicate with DSP */ +} gpakReadSysParmsStatus_t; + +extern gpakReadSysParmsStatus_t gpakReadSystemParms( + unsigned short int DspId, // DSP identifier + GpakSystemParms_t *pSysParms /* pointer to System Parms info var */ + ); + +extern gpakWriteSysParmsStatus_t gpakWriteSystemParms( + unsigned short int DspId, // DSP identifier + GpakSystemParms_t *pSysParms, /* pointer to System Parms info var */ + unsigned short int UpdateBits, /* input: flags indicating which parms to update */ + GPAK_SysParmsStat_t *pStatus /* pointer to Write System Parms Status */ + ); + +#endif // end multiple inclusion + diff --git a/wctdm24xxp/GpakCust.c b/wctdm24xxp/GpakCust.c new file mode 100644 index 0000000..bdce428 --- /dev/null +++ b/wctdm24xxp/GpakCust.c @@ -0,0 +1,388 @@ +/* + * 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 "wctdm24xxp.h" +#include <linux/delay.h> +#include <asm/semaphore.h> + +char vpm150mtone_to_zaptone(GpakToneCodes_t tone) +{ + switch (tone) { + case DtmfDigit0: + return '0'; + case DtmfDigit1: + return '1'; + case DtmfDigit2: + return '2'; + case DtmfDigit3: + return '3'; + case DtmfDigit4: + return '4'; + case DtmfDigit5: + return '5'; + case DtmfDigit6: + return '6'; + case DtmfDigit7: + return '7'; + case DtmfDigit8: + return '8'; + case DtmfDigit9: + return '9'; + case DtmfDigitPnd: + return '#'; + case DtmfDigitSt: + return '*'; + case DtmfDigitA: + return 'A'; + case DtmfDigitB: + return 'B'; + case DtmfDigitC: + return 'C'; + case DtmfDigitD: + return 'D'; + case EndofCngDigit: + return 'f'; + default: + return 0; + } +} + +static inline struct wctdm * wc_find_iface(unsigned short dspid) +{ + int i; + struct wctdm *ret = NULL; + unsigned long flags; + + spin_lock_irqsave(&ifacelock, flags); + for (i = 0; i < WC_MAX_IFACES; i++) + if (ifaces[i] && ifaces[i]->vpm150m && (ifaces[i]->vpm150m->dspid == dspid)) + ret = ifaces[i]; + spin_unlock_irqrestore(&ifacelock, flags); + + return ret; +} + +static inline struct vpm150m_cmd * vpm150m_empty_slot(struct wctdm *wc) +{ + int x; + + for (x = 0; x < VPM150M_MAX_COMMANDS; x++) + if (!wc->vpm150m->cmdq[x].desc) + return &wc->vpm150m->cmdq[x]; + return NULL; +} + + +unsigned short wctdm_vpm150m_getreg_full(struct wctdm *wc, int pagechange, unsigned int len, unsigned short addr, unsigned short *outbuf) +{ + unsigned long flags; + volatile struct vpm150m_cmd *hit; + unsigned short ret = 0; + int i; + do { + spin_lock_irqsave(&wc->reglock, flags); + hit = vpm150m_empty_slot(wc); + if (hit) { + hit->desc = __VPM150M_RD; + if (pagechange) { + hit->desc |= __VPM150M_RWPAGE; + } + hit->datalen = len; + hit->addr = addr; + for (i = 0; i < hit->datalen; i++) + hit->data[i] = 0x0000; + } + spin_unlock_irqrestore(&wc->reglock, flags); + if (!hit) { + if ((ret = schluffen(&wc->regq))) + return ret; + } + } while (!hit); + do { + spin_lock_irqsave(&wc->reglock, flags); + if (hit->desc & __VPM150M_FIN) { + for (i = 0; i < hit->datalen; i++) + outbuf[i] = hit->data[i]; + hit->desc = 0; + hit = NULL; + } + spin_unlock_irqrestore(&wc->reglock, flags); + if (hit) { + if ((ret = schluffen(&wc->regq))) + return ret; + } + } while (hit); + return ret; +} + +int wctdm_vpm150m_setreg_full(struct wctdm *wc, int pagechange, unsigned int len, unsigned int addr, unsigned short *data) +{ + unsigned long flags; + struct vpm150m_cmd *hit; + int ret, i; + do { + spin_lock_irqsave(&wc->reglock, flags); + hit = vpm150m_empty_slot(wc); + if (hit) { + hit->desc = __VPM150M_WR; + if (pagechange) + hit->desc |= __VPM150M_RWPAGE; + hit->addr = addr; + hit->datalen = len; + for (i = 0; i < len; i++) + hit->data[i] = data[i]; + } + spin_unlock_irqrestore(&wc->reglock, flags); + if (!hit) { + if ((ret = schluffen(&wc->regq))) + return ret; + } + } while (!hit); + return (hit) ? 0 : -1; +} + +int wctdm_vpm150m_setpage(struct wctdm *wc, unsigned short addr) +{ + addr &= 0xf; + /* Let's optimize this a little bit */ + if (wc->vpm150m->curpage == addr) + return 0; + else { + wc->vpm150m->curpage = addr; + } + + return wctdm_vpm150m_setreg_full(wc, 1, 1, 0, &addr); +} + +unsigned char wctdm_vpm150m_getpage(struct wctdm *wc) +{ + unsigned short res; + wctdm_vpm150m_getreg_full(wc, 1, 1, 0, &res); + return res; +} + +unsigned short wctdm_vpm150m_getreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data) +{ + unsigned short res; + wctdm_vpm150m_setpage(wc, addr >> 16); + if ((addr >> 16) != ((addr + len) >> 16)) + printk("getreg: You found it!\n"); + res = wctdm_vpm150m_getreg_full(wc, 0, len, addr & 0xffff, data); + return res; +} + +int wctdm_vpm150m_setreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data) +{ + int res; + wctdm_vpm150m_setpage(wc, addr >> 16); + if ((addr >> 16) != ((addr + len) >> 16)) + printk("getreg: You found it!\n"); + res = wctdm_vpm150m_setreg_full(wc, 0, len, addr & 0xffff, data); + return res; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * 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( + 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 */ + ) +{ + struct wctdm *wc = wc_find_iface(DspId); + int i; + int transcount; + + //printk("Reading %d words from memory\n"); + if (wc && wc->vpm150m) { + for (i = 0; i < NumWords;) { + if ((NumWords - i) > VPM150M_MAX_DATA) + transcount = VPM150M_MAX_DATA; + else + transcount = NumWords - i; + wctdm_vpm150m_getreg(wc, transcount, DspAddress + i, &pWordValues[i]); + i += transcount; + } + } + 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( + 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 */ + ) +{ + + struct wctdm *wc = wc_find_iface(DspId); + int i; + int transcount; + + //printk("Writing %d words to memory\n", NumWords); + if (wc && wc->vpm150m) { + for (i = 0; i < NumWords;) { + if ((NumWords - i) > VPM150M_MAX_DATA) + transcount = VPM150M_MAX_DATA; + else + transcount = NumWords - i; + + wctdm_vpm150m_setreg(wc, transcount, DspAddress + i, &pWordValues[i]); + i += transcount; + } +#if 0 + for (i = 0; i < NumWords; i++) { + if (wctdm_vpm150m_getreg(wc, DspAddress + i) != pWordValues[i]) { + printk("Error in write. Address %x is not %x\n", DspAddress + i, pWordValues[i]); + } + } +#endif + } + 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) +{ +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakLockAccess - Lock access to the specified DSP. + * + * FUNCTION + * This function aquires exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakLockAccess(unsigned short DspId) +{ + struct wctdm *wc; + + wc = wc_find_iface(DspId); + + if (wc) { + struct vpm150m *vpm = wc->vpm150m; + + if (vpm) + down_interruptible(&vpm->sem); + } +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * gpakUnlockAccess - Unlock access to the specified DSP. + * + * FUNCTION + * This function releases exclusive access to the specified DSP. + * + * RETURNS + * nothing + * + */ +void gpakUnlockAccess(unsigned short DspId) +{ + struct wctdm *wc; + + wc = wc_find_iface(DspId); + + if (wc) { + struct vpm150m *vpm = wc->vpm150m; + + if (vpm) + up(&vpm->sem); + } +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * 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( + 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 */ + ) +{ + struct wctdm_firmware *fw = FileId; + unsigned int i, count; + + if (!fw || !fw->fw) + return -1; + + if (NumBytes > (fw->fw->size - fw->offset)) + count = fw->fw->size - fw->offset; + else + count = NumBytes; + + for (i = 0; i < count; i++) + pBuffer[i] = fw->fw->data[fw->offset + i]; + + fw->offset += count; + + return count; +} diff --git a/wctdm24xxp/GpakCust.h b/wctdm24xxp/GpakCust.h new file mode 100644 index 0000000..dfb6103 --- /dev/null +++ b/wctdm24xxp/GpakCust.h @@ -0,0 +1,161 @@ +/* + * 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 "wctdm24xxp.h" +#include <linux/firmware.h> +#include "gpakenum.h" + + +struct wctdm_firmware { + const struct firmware *fw; + unsigned int offset; +}; + +/* Host and DSP system dependent related definitions. */ +#define MAX_DSP_CORES 128 /* maximum number of DSP cores */ +//#define MAX_CONFS 1 /* maximum number of conferences */ +//#define MAX_PKT_CHANNELS 8 /* maximum number of packet channels */ +#define MAX_CHANNELS 32 /* 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 MAX_CIDPAYLOAD_BYTES 512 /* max size of a CID payload (octets) */ +typedef unsigned short DSP_WORD; /* 16 bit DSP word */ +typedef unsigned int DSP_ADDRESS; /* 32 bit DSP address */ +typedef struct wctdm_firmware* GPAK_FILE_ID; /* G.PAK Download file identifier */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * 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( + 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( + 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( + 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( + 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( + 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 */ + ); + + +unsigned char wctdm_vpm150m_getpage(struct wctdm *wc); + +int wctdm_vpm150m_setpage(struct wctdm *wc, unsigned short addr); + +int wctdm_vpm150m_setreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data); + +unsigned short wctdm_vpm150m_getreg(struct wctdm *wc, unsigned int len, unsigned int addr, unsigned short *data); + +char vpm150mtone_to_zaptone(GpakToneCodes_t tone); + +#endif /* prevent multiple inclusion */ + + diff --git a/wctdm24xxp/GpakHpi.h b/wctdm24xxp/GpakHpi.h new file mode 100644 index 0000000..9dbf67a --- /dev/null +++ b/wctdm24xxp/GpakHpi.h @@ -0,0 +1,63 @@ +/* + * 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 */ + +#define MSG_ACCESSGPIO 51 +#define MSG_ACCESSGPIO_REPLY 52 +#endif /* prevent multiple inclusion */ diff --git a/wctdm24xxp/Makefile b/wctdm24xxp/Makefile new file mode 100644 index 0000000..9927928 --- /dev/null +++ b/wctdm24xxp/Makefile @@ -0,0 +1,22 @@ +ifneq ($(KBUILD_EXTMOD),) + +include $(src)/Makefile.kernel26 + +else + +all: wctdm24xxp.o + +%.o: %.c + $(CC) $(KFLAGS) -o $@ -c $< + +base.o: ../zaptel.h GpakCust.h ../wctdm.h + +GpakCust.o: GpakCust.h + +wctdm24xxp.o: base.o GpakCust.o GpakApi.o + $(LD) -r -o $@ $^ + +clean: + rm -f *.o + +endif diff --git a/wctdm24xxp/Makefile.kernel26 b/wctdm24xxp/Makefile.kernel26 new file mode 100644 index 0000000..f9fbf0c --- /dev/null +++ b/wctdm24xxp/Makefile.kernel26 @@ -0,0 +1,12 @@ +obj-m += wctdm24xxp.o + +EXTRA_CFLAGS := -I$(src)/.. -Wno-undef + +wctdm24xxp-objs := base.o GpakCust.o GpakApi.o + +$(obj)/base.o: $(src)/GpakCust.h $(src)/wctdm24xxp.h +$(obj)/base.o: $(src)/../zaptel.h + +$(obj)/GpakCust.o: $(src)/GpakCust.h + +$(obj)/GpakApi.o: $(src)/GpakApi.h diff --git a/wctdm24xxp/VPMADT032.bin b/wctdm24xxp/VPMADT032.bin Binary files differnew file mode 100644 index 0000000..e882060 --- /dev/null +++ b/wctdm24xxp/VPMADT032.bin diff --git a/wctdm24xxp.c b/wctdm24xxp/base.c index a330bb5..a1abe1d 100644 --- a/wctdm24xxp.c +++ b/wctdm24xxp/base.c @@ -2,7 +2,7 @@ * Wilcard TDM2400P TDM FXS/FXO Interface Driver for Zapata Telephony interface * * Written by Mark Spencer <markster@digium.com> - * Further modified to add support for the TDM800P by Matthew Fredrickson <creslin@digium.com> + * Support for TDM800P and VPM150M by Matthew Fredrickson <creslin@digium.com> * * Copyright (C) 2005,2006, Digium, Inc. * All rights reserved. @@ -34,6 +34,7 @@ Tx Gain - No Pre-Emphasis: -35.99 to 12.00 db Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db */ +#include <linux/version.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/module.h> @@ -41,18 +42,19 @@ Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db #include <linux/errno.h> #include <linux/pci.h> #include <linux/interrupt.h> -#include "proslic.h" -#include "wctdm.h" +#include <linux/firmware.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <asm/semaphore.h> +#include "../proslic.h" +#include "../wctdm.h" -/* Comment to disable VPM support */ -#define VPM_SUPPORT - -#ifdef VPM_SUPPORT +#include "GpakCust.h" +#include "GpakApi.h" -/* Define to get more attention-grabbing but slightly more CPU using echocan status */ -#define FANCY_ECHOCAN +/* Comment to disable VPM support */ -#endif +#include "wctdm24xxp.h" /* Experimental max loop current limit for the proslic @@ -240,176 +242,9 @@ static struct fxo_mode { #include <linux/moduleparam.h> #endif -#define NUM_FXO_REGS 60 - -#define WC_MAX_IFACES 128 - -#define FLAG_EMPTY 0 -#define FLAG_WRITE 1 -#define FLAG_READ 2 - -#define RING_DEBOUNCE 128 /* Ringer Debounce (in ms) */ -#define DEFAULT_BATT_DEBOUNCE 64 /* Battery debounce (in ms) */ -#define POLARITY_DEBOUNCE 64 /* Polarity debounce (in ms) */ -#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ - -#define OHT_TIMER 6000 /* How long after RING to retain OHT */ - -#define FLAG_3215 (1 << 0) - -#define NUM_CARDS 24 -#define NUM_EC 4 -#define NUM_SLOTS 6 -#define MAX_TDM_CHAN 31 - -#define EFRAME_SIZE 108 -#define ERING_SIZE 16 /* Maximum ring size */ -#define EFRAME_GAP 20 -#define SFRAME_SIZE ((EFRAME_SIZE * ZT_CHUNKSIZE) + (EFRAME_GAP * (ZT_CHUNKSIZE - 1))) - -#define MAX_ALARMS 10 - -#define MOD_TYPE_NONE 0 -#define MOD_TYPE_FXS 1 -#define MOD_TYPE_FXO 2 -#define MOD_TYPE_FXSINIT 3 -#define MOD_TYPE_VPM 4 -#define MOD_TYPE_QRV 5 - -#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ -#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ -#define PEGCOUNT 5 /* 5 cycles of pegging means RING */ - -#define SDI_CLK (0x00010000) -#define SDI_DOUT (0x00020000) -#define SDI_DREAD (0x00040000) -#define SDI_DIN (0x00080000) - -#define NUM_CAL_REGS 12 - -#define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4)) - -#define USER_COMMANDS 8 -#define ISR_COMMANDS 2 -#define QRV_DEBOUNCETIME 20 - -#define MAX_COMMANDS (USER_COMMANDS + ISR_COMMANDS) - -#define __CMD_RD (1 << 20) /* Read Operation */ -#define __CMD_WR (1 << 21) /* Write Operation */ -#define __CMD_FIN (1 << 22) /* Has finished receive */ -#define __CMD_TX (1 << 23) /* Has been transmitted */ - -#define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR) -#define CMD_RD(a) (((a) << 8) | __CMD_RD) - -#define CMD_BYTE(card,bit,altcs) (((((card) & 0x3) * 3 + (bit)) * 7) \ - + ((card) >> 2) + (altcs) + ((altcs) ? -21 : 0)) - -struct calregs { - unsigned char vals[NUM_CAL_REGS]; -}; - -struct cmdq { - unsigned int cmds[MAX_COMMANDS]; - unsigned char isrshadow[ISR_COMMANDS]; -}; - -struct wctdm { - struct pci_dev *dev; - char *variety; - struct zt_span span; - unsigned char ios; - unsigned int sdi; - int usecount; - unsigned int intcount; - unsigned int rxints; - unsigned int txints; - unsigned int intmask; - unsigned char txident; - unsigned char rxident; - int dead; - int pos; - int flags[NUM_CARDS]; - int freeregion; - int alt; - int rdbl; - int tdbl; - int curcard; - unsigned char ctlreg; - int cards; - int cardflag; /* Bit-map of present cards */ - int altcs[NUM_CARDS + NUM_EC]; - char qrvhook[NUM_CARDS]; - unsigned short qrvdebtime[NUM_CARDS]; - int radmode[NUM_CARDS]; -#define RADMODE_INVERTCOR 1 -#define RADMODE_IGNORECOR 2 -#define RADMODE_EXTTONE 4 -#define RADMODE_EXTINVERT 8 -#define RADMODE_IGNORECT 16 -#define RADMODE_PREEMP 32 -#define RADMODE_DEEMP 64 - unsigned short debouncetime[NUM_CARDS]; - signed short rxgain[NUM_CARDS]; - signed short txgain[NUM_CARDS]; - spinlock_t reglock; - wait_queue_head_t regq; - /* FXO Stuff */ - union { - struct { - int wasringing; - int ringdebounce; - int offhook; - int battdebounce; - int nobatttimer; - int battery; - int lastpol; - int polarity; - int polaritydebounce; - } fxo; - struct { - int oldrxhook; - int debouncehook; - int lastrxhook; - int debounce; - int ohttimer; - int idletxhookstate; /* IDLE changing hook state */ - int lasttxhook; - int palarms; - struct calregs calregs; - } fxs; - } mods[NUM_CARDS]; - struct cmdq cmdq[NUM_CARDS + NUM_EC]; - /* Receive hook state and debouncing */ - int modtype[NUM_CARDS + NUM_EC]; - /* Set hook */ - int sethook[NUM_CARDS + NUM_EC]; - int dacssrc[NUM_CARDS]; - int type; - -#ifdef VPM_SUPPORT - int vpm; - unsigned int dtmfactive; - unsigned int dtmfmask; - unsigned int dtmfmutemask; - short dtmfenergy[NUM_CARDS]; - short dtmfdigit[NUM_CARDS]; -#ifdef FANCY_ECHOCAN - int echocanpos; - int blinktimer; -#endif -#endif - unsigned long iobase; - dma_addr_t readdma; - dma_addr_t writedma; - dma_addr_t descripdma; - volatile unsigned int *writechunk; /* Double-word aligned write memory */ - volatile unsigned int *readchunk; /* Double-word aligned read memory */ - volatile unsigned int *descripchunk; /* Descriptors */ - struct zt_chan chans[NUM_CARDS]; -}; +#define DEBUG_CARD (1 << 0) +#define DEBUG_ECHOCAN (1 << 1) struct wctdm_desc { char *name; @@ -419,9 +254,13 @@ struct wctdm_desc { static struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 }; static struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 }; +static struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", 0, 24 }; +static struct wctdm_desc wcaex800 = { "Wildcard AEX800", 0, 8 }; + static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; -static struct wctdm *ifaces[WC_MAX_IFACES]; +struct wctdm *ifaces[WC_MAX_IFACES]; +spinlock_t ifacelock = SPIN_LOCK_UNLOCKED; static void wctdm_release(struct wctdm *wc); @@ -447,12 +286,14 @@ static int vpmsupport = 1; static int vpmdtmfsupport = 0; #define VPM_DEFAULT_DTMFTHRESHOLD 1250 static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD; + +static const char *vpm150m_firmware = "VPMADT032.bin"; #endif static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane); /* sleep in user space until woken up. Equivilant of tsleep() in BSD */ -static int schluffen(wait_queue_head_t *q) +int schluffen(wait_queue_head_t *q) { DECLARE_WAITQUEUE(wait, current); add_wait_queue(q, &wait); @@ -474,6 +315,163 @@ static inline int empty_slot(struct wctdm *wc, int card) return -1; } +#ifdef VPM_SUPPORT +static inline void cmd_dequeue_vpm150m(struct wctdm *wc, volatile unsigned char *writechunk, int whichframe) +{ + unsigned long flags; + struct vpm150m_cmd *curcmd = NULL; + struct vpm150m *vpm150m = wc->vpm150m; + int x; + unsigned char leds = ~((wc->intcount / 1000) % 8) & 0x7; + + /* Skip audio */ + writechunk += 24; + + spin_lock_irqsave(&wc->reglock, flags); + + if (test_bit(VPM150M_SPIRESET, &vpm150m->control) || test_bit(VPM150M_HPIRESET, &vpm150m->control)) { + if (debug & DEBUG_ECHOCAN) + printk("HW Resetting VPMADT032...\n"); + for (x = 24; x < 28; x++) { + if (x == 24) { + if (test_and_clear_bit(VPM150M_SPIRESET, &vpm150m->control)) + writechunk[CMD_BYTE(x, 0, 0)] = 0x08; + else if (test_and_clear_bit(VPM150M_HPIRESET, &vpm150m->control)) + writechunk[CMD_BYTE(x, 0, 0)] = 0x0b; + } else + writechunk[CMD_BYTE(x, 0, 0)] = 0x00 | leds; + writechunk[CMD_BYTE(x, 1, 0)] = 0; + writechunk[CMD_BYTE(x, 2, 0)] = 0x00; + } + spin_unlock_irqrestore(&wc->reglock, flags); + return; + } + + + /* Search for something waiting to transmit */ + for (x = 0; x < VPM150M_MAX_COMMANDS; x++) { + if ((vpm150m->cmdq[x].desc & (__VPM150M_RD | __VPM150M_WR)) && + !(vpm150m->cmdq[x].desc & (__VPM150M_FIN | __VPM150M_TX))) { + curcmd = &vpm150m->cmdq[x]; + curcmd->txident = wc->txident; + curcmd->desc |= __VPM150M_TX; + break; + } + } + if (curcmd) { +#if 0 + printk("Found command txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", curcmd->txident, curcmd->desc, curcmd->addr, curcmd->data); +#endif + if (curcmd->desc & __VPM150M_RWPAGE) { + /* Set CTRL access to page*/ + writechunk[CMD_BYTE(24, 0, 0)] = (0x8 << 4); + writechunk[CMD_BYTE(24, 1, 0)] = 0; + writechunk[CMD_BYTE(24, 2, 0)] = 0x20; + + /* Do a page write */ + if (curcmd->desc & __VPM150M_WR) + writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | 0x4) << 4); + else + writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | 0x4 | 0x1) << 4); + writechunk[CMD_BYTE(25, 1, 0)] = 0; + if (curcmd->desc & __VPM150M_WR) + writechunk[CMD_BYTE(25, 2, 0)] = curcmd->data[0] & 0xf; + else + writechunk[CMD_BYTE(25, 2, 0)] = 0; + + /* Clear XADD */ + writechunk[CMD_BYTE(26, 0, 0)] = (0x8 << 4); + writechunk[CMD_BYTE(26, 1, 0)] = 0; + writechunk[CMD_BYTE(26, 2, 0)] = 0; + + /* Fill in to buffer to size */ + writechunk[CMD_BYTE(27, 0, 0)] = 0; + writechunk[CMD_BYTE(27, 1, 0)] = 0; + writechunk[CMD_BYTE(27, 2, 0)] = 0; + + } else { + /* Set address */ + writechunk[CMD_BYTE(24, 0, 0)] = ((0x8 | 0x4) << 4); + writechunk[CMD_BYTE(24, 1, 0)] = (curcmd->addr >> 8) & 0xff; + writechunk[CMD_BYTE(24, 2, 0)] = curcmd->addr & 0xff; + + /* Send/Get our data */ + if (curcmd->desc & __VPM150M_WR) { + if (curcmd->datalen > 1) + writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x1 << 1)) << 4); + else + writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x3 << 1)) << 4); + } else + if (curcmd->datalen > 1) + writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x1 << 1) | 0x1) << 4); + else + writechunk[CMD_BYTE(25, 0, 0)] = ((0x8 | (0x3 << 1) | 0x1) << 4); + writechunk[CMD_BYTE(25, 1, 0)] = (curcmd->data[0] >> 8) & 0xff; + writechunk[CMD_BYTE(25, 2, 0)] = curcmd->data[0] & 0xff; + + if (curcmd->datalen > 1) { + if (curcmd->desc & __VPM150M_WR) + writechunk[CMD_BYTE(26, 0, 0)] = ((0x8 | (0x1 << 1)) << 4); + else + writechunk[CMD_BYTE(26, 0, 0)] = ((0x8 | (0x1 << 1) | 0x1) << 4); + writechunk[CMD_BYTE(26, 1, 0)] = (curcmd->data[1] >> 8) & 0xff; + writechunk[CMD_BYTE(26, 2, 0)] = curcmd->data[1] & 0xff; + } else { + /* Fill in the rest */ + writechunk[CMD_BYTE(26, 0, 0)] = 0; + writechunk[CMD_BYTE(26, 1, 0)] = 0; + writechunk[CMD_BYTE(26, 2, 0)] = 0; + } + + if (curcmd->datalen > 2) { + if (curcmd->desc & __VPM150M_WR) + writechunk[CMD_BYTE(27, 0, 0)] = ((0x8 | (0x1 << 1)) << 4); + else + writechunk[CMD_BYTE(27, 0, 0)] = ((0x8 | (0x1 << 1) | 0x1) << 4); + writechunk[CMD_BYTE(27, 1, 0)] = (curcmd->data[2] >> 8) & 0xff; + writechunk[CMD_BYTE(27, 2, 0)] = curcmd->data[2] & 0xff; + } else { + /* Fill in the rest */ + writechunk[CMD_BYTE(27, 0, 0)] = 0; + writechunk[CMD_BYTE(27, 1, 0)] = 0; + writechunk[CMD_BYTE(27, 2, 0)] = 0; + } + + + } + } else if (test_and_clear_bit(VPM150M_SWRESET, &vpm150m->control)) { + printk("Booting VPMADT032\n"); + for (x = 24; x < 28; x++) { + if (x == 24) + writechunk[CMD_BYTE(x, 0, 0)] = (0x8 << 4); + else + writechunk[CMD_BYTE(x, 0, 0)] = 0x00; + writechunk[CMD_BYTE(x, 1, 0)] = 0; + if (x == 24) + writechunk[CMD_BYTE(x, 2, 0)] = 0x01; + else + writechunk[CMD_BYTE(x, 2, 0)] = 0x00; + } + } else { + for (x = 24; x < 28; x++) { + writechunk[CMD_BYTE(x, 0, 0)] = 0x00; + writechunk[CMD_BYTE(x, 1, 0)] = 0x00; + writechunk[CMD_BYTE(x, 2, 0)] = 0x00; + } + } + + /* Add our leds in */ + for (x = 24; x < 28; x++) + writechunk[CMD_BYTE(x, 0, 0)] |= leds; + + /* Now let's figure out if we need to check for DTMF */ + if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 100)) + queue_work(vpm150m->wq, &vpm150m->work); + + spin_unlock_irqrestore(&wc->reglock, flags); +} +#endif /* VPM_SUPPORT */ + static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writechunk, int card, int pos) { unsigned long flags; @@ -487,14 +485,16 @@ static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writech ecval = ecval % EC_SIZE; #endif - /* if a QRV card, map it to its first channel */ - if ((wc->modtype[card] == MOD_TYPE_QRV) && (card & 3)) - { - return; - } - if (wc->altcs[card]) - subaddr = 0; + /* if a QRV card, map it to its first channel */ + if ((wc->modtype[card] == MOD_TYPE_QRV) && (card & 3)) + { + return; + } + if (wc->altcs[card]) + subaddr = 0; + + /* Skip audio */ writechunk += 24; spin_lock_irqsave(&wc->reglock, flags); @@ -532,59 +532,60 @@ static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writech } } if (wc->modtype[card] == MOD_TYPE_FXS) { - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = (1 << (subaddr)); + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = (1 << (subaddr)); if (curcmd & __CMD_WR) - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0x7f; + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0x7f; else - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x80 | ((curcmd >> 8) & 0x7f); - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x80 | ((curcmd >> 8) & 0x7f); + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; } else if (wc->modtype[card] == MOD_TYPE_FXO) { if (curcmd & __CMD_WR) - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x20 | fxo_addrs[subaddr]; + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x20 | fxo_addrs[subaddr]; else - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x60 | fxo_addrs[subaddr]; - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff; - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x60 | fxo_addrs[subaddr]; + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff; + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; } else if (wc->modtype[card] == MOD_TYPE_FXSINIT) { /* Special case, we initialize the FXS's into the three-byte command mode then switch to the regular mode. To send it into thee byte mode, treat the path as 6 two-byte commands and in the last one we initialize register 0 to 0x80. All modules read this as the command to switch to daisy chain mode and we're done. */ - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00; - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00; if ((card & 0x1) == 0x1) - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x80; + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x80; else - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00; #ifdef VPM_SUPPORT } else if (wc->modtype[card] == MOD_TYPE_VPM) { if (curcmd & __CMD_WR) - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xc | ((curcmd >> 16) & 0x1); + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xc | ((curcmd >> 16) & 0x1); else - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xa | ((curcmd >> 16) & 0x1); - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff; - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = ((card & 0x3) << 4) | 0xa | ((curcmd >> 16) & 0x1); + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = (curcmd >> 8) & 0xff; + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; + } else if (wc->modtype[card] == MOD_TYPE_VPM150M) { #endif - } else if (wc->modtype[card] == MOD_TYPE_QRV) { - - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00; - if (!curcmd) - { - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00; - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00; - } - else - { - if (curcmd & __CMD_WR) - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x40 | ((curcmd >> 8) & 0x3f); - else - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0xc0 | ((curcmd >> 8) & 0x3f); - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; - } + } else if (wc->modtype[card] == MOD_TYPE_QRV) { + + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00; + if (!curcmd) + { + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00; + } + else + { + if (curcmd & __CMD_WR) + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x40 | ((curcmd >> 8) & 0x3f); + else + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0xc0 | ((curcmd >> 8) & 0x3f); + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff; + } } else if (wc->modtype[card] == MOD_TYPE_NONE) { - writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00; - writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00; - writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00; + writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00; } #if 0 /* XXX */ @@ -598,6 +599,41 @@ static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writech #endif } +#ifdef VPM_SUPPORT +static inline void cmd_decifer_vpm150m(struct wctdm *wc, volatile unsigned char *readchunk) +{ + unsigned long flags; + unsigned char ident; + int x, i; + + /* Skip audio */ + readchunk += 24; + spin_lock_irqsave(&wc->reglock, flags); + /* Search for any pending results */ + for (x = 0; x < VPM150M_MAX_COMMANDS; x++) { + if ((wc->vpm150m->cmdq[x].desc & (__VPM150M_RD | __VPM150M_WR)) && + (wc->vpm150m->cmdq[x].desc & (__VPM150M_TX)) && + !(wc->vpm150m->cmdq[x].desc & (__VPM150M_FIN))) { + ident = wc->vpm150m->cmdq[x].txident; + if (ident == wc->rxident) { + /* Store result */ + for (i = 0; i < wc->vpm150m->cmdq[x].datalen; i++) { + wc->vpm150m->cmdq[x].data[i] = (0xff & readchunk[CMD_BYTE((25 + i), 1, 0)]) << 8; + wc->vpm150m->cmdq[x].data[i] |= readchunk[CMD_BYTE((25 + i), 2, 0)]; + } + if (wc->vpm150m->cmdq[x].desc & __VPM150M_WR) { + /* Go ahead and clear out writes since they need no acknowledgement */ + wc->vpm150m->cmdq[x].desc = 0; + } else + wc->vpm150m->cmdq[x].desc |= __VPM150M_FIN; + break; + } + } + } + spin_unlock_irqrestore(&wc->reglock, flags); +} +#endif /* VPM_SUPPORT */ + static inline void cmd_decifer(struct wctdm *wc, volatile unsigned char *readchunk, int card) { unsigned long flags; @@ -705,26 +741,24 @@ static inline void wctdm_transmitprep(struct wctdm *wc, int dbl) cmd_dequeue(wc, writechunk, y, x); } #ifdef VPM_SUPPORT + if (!x) + wc->blinktimer++; if (wc->vpm) { - if (!x) - wc->blinktimer++; for (y=24;y<28;y++) { if (!x) cmd_checkisr(wc, y); cmd_dequeue(wc, writechunk, y, x); } #ifdef FANCY_ECHOCAN - if (wc->blinktimer >= 0xf) { + if (wc->vpm && wc->blinktimer >= 0xf) { wc->blinktimer = -1; wc->echocanpos++; } #endif + } else if (wc->vpm150m) { + cmd_dequeue_vpm150m(wc, writechunk, x); } #endif -#if 0 - if (cmddesc < 1024) - printk("TC Result: %02x\n", wc->txident); -#endif if (x < ZT_CHUNKSIZE - 1) { writechunk[EFRAME_SIZE] = wc->ctlreg; writechunk[EFRAME_SIZE + 1] = wc->txident++; @@ -916,6 +950,7 @@ static inline unsigned short wctdm_getsdi(struct wctdm *wc, unsigned char addr) spin_unlock_irqrestore(&wc->reglock, flags); return val; } + #ifdef VPM_SUPPORT static inline unsigned char wctdm_vpm_in(struct wctdm *wc, int unit, const unsigned int addr) { @@ -926,6 +961,22 @@ static inline void wctdm_vpm_out(struct wctdm *wc, int unit, const unsigned int { wctdm_setreg(wc, unit + NUM_CARDS, addr, val); } + +static inline void cmd_vpm150m_retransmit(struct wctdm *wc) +{ + unsigned long flags; + int x; + + spin_lock_irqsave(&wc->reglock, flags); + for (x = 0; x < VPM150M_MAX_COMMANDS; x++) { + if (!(wc->vpm150m->cmdq[x].desc & __VPM150M_FIN)) { + //printk("Retransmit!\n"); + wc->vpm150m->cmdq[x].desc &= ~(__VPM150M_TX); + } + } + spin_unlock_irqrestore(&wc->reglock, flags); + +} #endif static inline void cmd_retransmit(struct wctdm *wc) @@ -941,6 +992,10 @@ static inline void cmd_retransmit(struct wctdm *wc) } } spin_unlock_irqrestore(&wc->reglock, flags); +#ifdef VPM_SUPPORT + if (wc->vpm150m) + cmd_vpm150m_retransmit(wc); +#endif } static inline void wctdm_receiveprep(struct wctdm *wc, int dbl) @@ -964,15 +1019,17 @@ static inline void wctdm_receiveprep(struct wctdm *wc, int dbl) } } for (y=0;y < wc->cards;y++) { - if (y < wc->type) + if (y < wc->type) { wc->chans[y].readchunk[x] = readchunk[y]; + } cmd_decifer(wc, readchunk, y); } #ifdef VPM_SUPPORT if (wc->vpm) { for (y=NUM_CARDS;y < NUM_CARDS + NUM_EC; y++) cmd_decifer(wc, readchunk, y); - } + } else if (wc->vpm150m) + cmd_decifer_vpm150m(wc, readchunk); #endif #if 0 if (cmddesc < 1024) { @@ -1111,7 +1168,7 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card) } if (passed) { - if (debug) + if (debug & DEBUG_CARD) printk("Init Indirect Registers completed successfully.\n"); } else { printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); @@ -1243,7 +1300,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) if (!wc->mods[card].fxo.wasringing) { wc->mods[card].fxo.wasringing = 1; zt_hooksig(&wc->chans[card], ZT_RXSIG_RING); - if (debug) + if (debug & DEBUG_CARD) printk("RING on %d/%d!\n", wc->span.spanno, card + 1); } wc->mods[card].fxo.ringdebounce = ZT_CHUNKSIZE * RING_DEBOUNCE; @@ -1254,7 +1311,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) if (wc->mods[card].fxo.wasringing) { wc->mods[card].fxo.wasringing = 0; zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); - if (debug) + if (debug & DEBUG_CARD) printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1); } wc->mods[card].fxo.ringdebounce = 0; @@ -1270,13 +1327,13 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) printk("Battery loss: %d (%d debounce)\n", b, wc->mods[card].fxo.battdebounce); #endif if (wc->mods[card].fxo.battery && !wc->mods[card].fxo.battdebounce) { - if (debug) + if (debug & DEBUG_CARD) printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1); wc->mods[card].fxo.battery = 0; #ifdef JAPAN if ((!wc->ohdebounce) && wc->offhook) { zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); - if (debug) + if (debug & DEBUG_CARD) printk("Signalled On Hook\n"); #ifdef ZERO_BATT_RING wc->onhook++; @@ -1290,14 +1347,14 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) wc->mods[card].fxo.battdebounce = battdebounce; } else if (abs(b) > battthresh) { if (!wc->mods[card].fxo.battery && !wc->mods[card].fxo.battdebounce) { - if (debug) + if (debug & DEBUG_CARD) printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1, (b < 0) ? "-" : "+"); #ifdef ZERO_BATT_RING if (wc->onhook) { wc->onhook = 0; zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); - if (debug) + if (debug & DEBUG_CARD) printk("Signalled Off Hook\n"); } #else @@ -1331,7 +1388,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) wc->mods[card].fxo.polaritydebounce--; if (wc->mods[card].fxo.polaritydebounce < 1) { if (wc->mods[card].fxo.lastpol != wc->mods[card].fxo.polarity) { - if (debug) + if (debug & DEBUG_CARD) printk("%lu Polarity reversed (%d -> %d)\n", jiffies, wc->mods[card].fxo.polarity, wc->mods[card].fxo.lastpol); @@ -1374,7 +1431,7 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card) } if (!wc->mods[card].fxs.oldrxhook && wc->mods[card].fxs.debouncehook) { /* Off hook */ - if (debug) + if (debug & DEBUG_CARD) printk("wctdm: Card %d Going off hook\n", card); zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); if (robust) @@ -1383,7 +1440,7 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card) } else if (wc->mods[card].fxs.oldrxhook && !wc->mods[card].fxs.debouncehook) { /* On hook */ - if (debug) + if (debug & DEBUG_CARD) printk("wctdm: Card %d Going on hook\n", card); zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); wc->mods[card].fxs.oldrxhook = 0; @@ -1407,14 +1464,14 @@ static inline void wctdm_reinit_descriptor(struct wctdm *wc, int tx, int dbl, ch static inline void wctdm_vpm_check(struct wctdm *wc, int x) { if (wc->cmdq[x].isrshadow[0]) { - if (debug) + if (debug & DEBUG_ECHOCAN) printk("VPM: Detected dtmf ON channel %02x on chip %d!\n", wc->cmdq[x].isrshadow[0], x - NUM_CARDS); wc->sethook[x] = CMD_WR(0xb9, wc->cmdq[x].isrshadow[0]); wc->cmdq[x].isrshadow[0] = 0; /* Cancel most recent lookup, if there is one */ wc->cmdq[x].cmds[USER_COMMANDS+0] = 0x00000000; } else if (wc->cmdq[x].isrshadow[1]) { - if (debug) + if (debug & DEBUG_ECHOCAN) printk("VPM: Detected dtmf OFF channel %02x on chip %d!\n", wc->cmdq[x].isrshadow[1], x - NUM_CARDS); wc->sethook[x] = CMD_WR(0xbd, wc->cmdq[x].isrshadow[1]); wc->cmdq[x].isrshadow[1] = 0; @@ -1426,25 +1483,42 @@ static inline void wctdm_vpm_check(struct wctdm *wc, int x) static int wctdm_echocan(struct zt_chan *chan, int eclen) { struct wctdm *wc = chan->pvt; - int channel; - int unit; - if (!wc->vpm) + if (wc->vpm) { + int channel; + int unit; + + channel = (chan->chanpos - 1); + unit = (chan->chanpos - 1) & 0x3; + if (wc->vpm < 2) + channel >>= 2; + + if(debug & DEBUG_ECHOCAN) + printk("echocan: Unit is %d, Channel is %d length %d\n", + unit, channel, eclen); + if (eclen) + wctdm_vpm_out(wc,unit,channel,0x3e); + else + wctdm_vpm_out(wc,unit,channel,0x01); + + return 0; + } else if (wc->vpm150m) { + struct vpm150m *vpm150m = wc->vpm150m; + + if (eclen) { + set_bit(chan->chanpos - 1, &vpm150m->desiredecstate); + if (test_bit(VPM150M_ACTIVE, &vpm150m->control)) + queue_work(vpm150m->wq, &vpm150m->work); + } else { + clear_bit(chan->chanpos - 1, &vpm150m->desiredecstate); + if (test_bit(VPM150M_ACTIVE, &vpm150m->control)) + queue_work(vpm150m->wq, &vpm150m->work); + } + return 0; + } else return -ENODEV; - channel = (chan->chanpos - 1); - unit = (chan->chanpos - 1) & 0x3; - if (wc->vpm < 2) - channel >>= 2; - - if(debug) - printk("echocan: Unit is %d, Channel is %d length %d\n", - unit, channel, eclen); - if (eclen) - wctdm_vpm_out(wc,unit,channel,0x3e); - else - wctdm_vpm_out(wc,unit,channel,0x01); - return 0; } #endif + static inline void wctdm_isr_misc(struct wctdm *wc) { int x; @@ -1610,7 +1684,7 @@ static int wctdm_voicedaa_insane(struct wctdm *wc, int card) if (blah != 0x3) return -2; blah = wctdm_getreg(wc, card, 11); - if (debug) + if (debug & DEBUG_CARD) printk("VoiceDAA System: %02x\n", blah & 0xf); return 0; } @@ -1621,7 +1695,7 @@ static int wctdm_proslic_insane(struct wctdm *wc, int card) insane_report=0; blah = wctdm_getreg(wc, card, 0); - if (debug) + if (debug & DEBUG_CARD) printk("ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf)); #if 0 @@ -1666,7 +1740,7 @@ static int wctdm_proslic_insane(struct wctdm *wc, int card) /* Just be sure it's setup right. */ wctdm_setreg(wc, card, 30, 0); - if (debug) + if (debug & DEBUG_CARD) printk("ProSLIC on module %d seems sane.\n", card); return 0; } @@ -1694,7 +1768,7 @@ static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card) printk("Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card, 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ)); return -1; - } else if (debug) { + } else if (debug & DEBUG_CARD) { printk("Post-leakage voltage: %d volts\n", 376 * vbat / 1000); } return 0; @@ -1731,7 +1805,7 @@ static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast) card, (int)(((jiffies - origjiffies) * 1000 / HZ)), vbat * 375); return -1; - } else if (debug) { + } else if (debug & DEBUG_CARD) { printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ))); } @@ -1741,10 +1815,10 @@ static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast) lim = (loopcurrent - 20) / 3; if ( loopcurrent > 41 ) { lim = 0; - if (debug) + if (debug & DEBUG_CARD) printk("Loop current out of range! Setting to default 20mA!\n"); } - else if (debug) + else if (debug & DEBUG_CARD) printk("Loop current set to %dmA!\n",(lim*3)+20); wctdm_setreg(wc,card,LOOP_I_LIMIT,lim); @@ -1867,7 +1941,7 @@ static int wctdm_proslic_calibrate(struct wctdm *wc, int card) } } - if (debug) { + if (debug & DEBUG_CARD) { /* Print calibration parameters */ printk("Calibration Vector Regs 98 - 107: \n"); for (x=98;x<108;x++) { @@ -1954,7 +2028,7 @@ static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, printk("VoiceDAA did not bring up ISO link properly!\n"); return -1; } - if (debug) + if (debug & DEBUG_CARD) printk("ISO-Cap is now up, line side: %02x rev %02x\n", wctdm_getreg(wc, card, 11) >> 4, (wctdm_getreg(wc, card, 13) >> 2) & 0xf); @@ -2245,8 +2319,8 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, static int wctdm_init_qrvdri(struct wctdm *wc, int card) { -unsigned char x,y; -unsigned long endjif; + unsigned char x,y; + unsigned long endjif; /* have to set this, at least for now */ wc->modtype[card] = MOD_TYPE_QRV; @@ -2507,18 +2581,24 @@ static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat case ZT_TONEDETECT: if (get_user(x, (int *) data)) return -EFAULT; - if (!wc->vpm) + if (!wc->vpm && !wc->vpm150m) return -ENOSYS; - if (x && !vpmdtmfsupport) + if ((wc->vpm || wc->vpm150m) && (x && !vpmdtmfsupport)) return -ENOSYS; - if (x & ZT_TONEDETECT_ON) - wc->dtmfmask |= (1 << (chan->chanpos - 1)); - else - wc->dtmfmask &= ~(1 << (chan->chanpos - 1)); - if (x & ZT_TONEDETECT_MUTE) - wc->dtmfmutemask |= (1 << (chan->chanpos - 1)); - else - wc->dtmfmutemask &= ~(1 << (chan->chanpos - 1)); + if (x & ZT_TONEDETECT_ON) { + set_bit(chan->chanpos - 1, &wc->dtmfmask); + } else { + clear_bit(chan->chanpos - 1, &wc->dtmfmask); + } + if (x & ZT_TONEDETECT_MUTE) { + if (wc->vpm150m) { + set_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate); + } + } else { + if (wc->vpm150m) { + clear_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate); + } + } return 0; #endif case ZT_RADIO_GETPARAM: @@ -2797,7 +2877,7 @@ static int wctdm_hooksig(struct zt_chan *chan, zt_txsig_t txsig) default: printk("wctdm24xxp: Can't set tx state to %d\n", txsig); } - if (debug) + if (debug & DEBUG_CARD) printk("Setting FXS hook state to %d (%02x)\n", txsig, reg); @@ -3068,8 +3148,502 @@ static void wctdm_disable_interrupts(struct wctdm *wc) wctdm_setctl(wc, 0x0084, 0x00000000); } - #ifdef VPM_SUPPORT +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void vpm150m_bh(void *data) +{ + struct vpm150m *vpm150m = data; +#else +static void vpm150m_bh(struct work_struct *data) +{ + struct vpm150m *vpm150m = container_of(data, struct vpm150m, work); +#endif + struct wctdm *wc = vpm150m->wc; + int i; + + for (i = 0; i < wc->type; i++) { + int enable = -1; + if (test_bit(i, &vpm150m->desireddtmfmutestate)) { + if (!test_bit(i, &vpm150m->curdtmfmutestate)) { + enable = 1; + } + } else { + if (test_bit(i, &vpm150m->curdtmfmutestate)) { + enable = 0; + } + } + if (enable > -1) { + unsigned int start = wc->intcount; + GPAK_AlgControlStat_t pstatus; + int res; + + if (enable) { + res = gpakAlgControl(vpm150m->dspid, i, EnableDTMFMuteA, &pstatus); + if (debug & DEBUG_ECHOCAN) + printk("DTMF mute enable took %d ms\n", wc->intcount - start); + } else { + res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &pstatus); + if (debug & DEBUG_ECHOCAN) + printk("DTMF mute disable took %d ms\n", wc->intcount - start); + } + if (!res) + change_bit(i, &vpm150m->curdtmfmutestate); + } + } + + if (test_bit(VPM150M_DTMFDETECT, &vpm150m->control)) { + unsigned short channel; + GpakAsyncEventCode_t eventcode; + GpakAsyncEventData_t eventdata; + gpakReadEventFIFOMessageStat_t res; +#if 1 + unsigned int start = wc->intcount; +#endif + + do { + res = gpakReadEventFIFOMessage(vpm150m->dspid, &channel, &eventcode, &eventdata); + +#if 1 + if (debug & DEBUG_ECHOCAN) + printk("ReadEventFIFOMessage took %d ms\n", wc->intcount - start); +#endif + + if (res == RefInvalidEvent || res == RefDspCommFailure) { + printk("Uh oh (%d)\n", res); + continue; + } + + if (eventcode == EventToneDetect) { + GpakToneCodes_t tone = eventdata.toneEvent.ToneCode; + int duration = eventdata.toneEvent.ToneDuration; + char zaptone = vpm150mtone_to_zaptone(tone); + + if (debug & DEBUG_ECHOCAN) + printk("Channel %d: Detected DTMF tone %d of duration %d!!!\n", channel + 1, tone, duration); + + if (test_bit(channel, &wc->dtmfmask) && (eventdata.toneEvent.ToneDuration > 0)) { + struct zt_chan *chan = &wc->chans[channel]; + + if ((tone != EndofMFDigit) && (zaptone != 0)) { + vpm150m->curtone[channel] = tone; + + if (test_bit(channel, &vpm150m->curdtmfmutestate)) { + unsigned long flags; + int y; + + /* Mute the audio data buffers */ + spin_lock_irqsave(&chan->lock, flags); + for (y = 0; y < chan->numbufs; y++) { + if ((chan->inreadbuf > -1) && (chan->readidx[y])) + memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]); + } + spin_unlock_irqrestore(&chan->lock, flags); + } + if (!test_bit(channel, &wc->dtmfactive)) { + if (debug & DEBUG_ECHOCAN) + printk("Queuing DTMFDOWN %c\n", zaptone); + set_bit(channel, &wc->dtmfactive); + zt_qevent_lock(chan, (ZT_EVENT_DTMFDOWN | zaptone)); + } + } else if ((tone == EndofMFDigit) && test_bit(channel, &wc->dtmfactive)) { + if (debug & DEBUG_ECHOCAN) + printk("Queuing DTMFUP %c\n", vpm150mtone_to_zaptone(vpm150m->curtone[channel])); + zt_qevent_lock(chan, (ZT_EVENT_DTMFUP | vpm150mtone_to_zaptone(vpm150m->curtone[channel]))); + clear_bit(channel, &wc->dtmfactive); + } + } + } + } while ((res != RefNoEventAvail) && (res != RefInvalidEvent) && (res != RefDspCommFailure)); + } + + for (i = 0; i < wc->type; i++) { + int enable = -1; + if (test_bit(i, &vpm150m->desiredecstate)) { + if (!test_bit(i, &vpm150m->curecstate)) { + enable = 1; + } + } else { + if (test_bit(i, &vpm150m->curecstate)) { + enable = 0; + } + } + if (enable > -1) { + unsigned int start = wc->intcount; + GPAK_AlgControlStat_t pstatus; + int res; + + if (enable) { + res = gpakAlgControl(vpm150m->dspid, i, EnableEcanA, &pstatus); + if (debug & DEBUG_ECHOCAN) + printk("Echocan enable took %d ms\n", wc->intcount - start); + } else { + res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &pstatus); + if (debug & DEBUG_ECHOCAN) + printk("Echocan disable took %d ms\n", wc->intcount - start); + } + if (!res) + change_bit(i, &vpm150m->curecstate); + } + } + + return; +} + +static int vpm150m_config_hw(struct wctdm *wc) +{ + struct vpm150m *vpm150m = wc->vpm150m; + gpakConfigPortStatus_t configportstatus; + GpakPortConfig_t portconfig; + GPAK_PortConfigStat_t pstatus; + GpakChannelConfig_t chanconfig; + GPAK_ChannelConfigStat_t cstatus; + GPAK_AlgControlStat_t algstatus; + + int res, i; + + memset(&portconfig, 0, sizeof(GpakPortConfig_t)); + + /* First Serial Port config */ + portconfig.SlotsSelect1 = SlotCfgNone; + portconfig.FirstBlockNum1 = 0; + portconfig.FirstSlotMask1 = 0x0000; + portconfig.SecBlockNum1 = 1; + portconfig.SecSlotMask1 = 0x0000; + portconfig.SerialWordSize1 = SerWordSize8; + portconfig.CompandingMode1 = cmpNone; + portconfig.TxFrameSyncPolarity1 = FrameSyncActHigh; + portconfig.RxFrameSyncPolarity1 = FrameSyncActHigh; + portconfig.TxClockPolarity1 = SerClockActHigh; + portconfig.RxClockPolarity1 = SerClockActHigh; + portconfig.TxDataDelay1 = DataDelay0; + portconfig.RxDataDelay1 = DataDelay0; + portconfig.DxDelay1 = Disabled; + portconfig.ThirdSlotMask1 = 0x0000; + portconfig.FouthSlotMask1 = 0x0000; + portconfig.FifthSlotMask1 = 0x0000; + portconfig.SixthSlotMask1 = 0x0000; + portconfig.SevenSlotMask1 = 0x0000; + portconfig.EightSlotMask1 = 0x0000; + + /* Second Serial Port config */ + portconfig.SlotsSelect2 = SlotCfg2Groups; + portconfig.FirstBlockNum2 = 0; + portconfig.FirstSlotMask2 = 0xffff; + portconfig.SecBlockNum2 = 1; + portconfig.SecSlotMask2 = 0xffff; + portconfig.SerialWordSize2 = SerWordSize8; + portconfig.CompandingMode2 = cmpNone; + portconfig.TxFrameSyncPolarity2 = FrameSyncActHigh; + portconfig.RxFrameSyncPolarity2 = FrameSyncActHigh; + portconfig.TxClockPolarity2 = SerClockActHigh; + portconfig.RxClockPolarity2 = SerClockActHigh; + portconfig.TxDataDelay2 = DataDelay0; + portconfig.RxDataDelay2 = DataDelay0; + portconfig.DxDelay2 = Disabled; + portconfig.ThirdSlotMask2 = 0x0000; + portconfig.FouthSlotMask2 = 0x0000; + portconfig.FifthSlotMask2 = 0x0000; + portconfig.SixthSlotMask2 = 0x0000; + portconfig.SevenSlotMask2 = 0x0000; + portconfig.EightSlotMask2 = 0x0000; + + /* Third Serial Port Config */ + portconfig.SlotsSelect3 = SlotCfg2Groups; + portconfig.FirstBlockNum3 = 0; + portconfig.FirstSlotMask3 = 0xffff; + portconfig.SecBlockNum3 = 1; + portconfig.SecSlotMask3 = 0xffff; + portconfig.SerialWordSize3 = SerWordSize8; + portconfig.CompandingMode3 = cmpNone; + portconfig.TxFrameSyncPolarity3 = FrameSyncActHigh; + portconfig.RxFrameSyncPolarity3 = FrameSyncActHigh; + portconfig.TxClockPolarity3 = SerClockActHigh; + portconfig.RxClockPolarity3 = SerClockActHigh; + portconfig.TxDataDelay3 = DataDelay0; + portconfig.RxDataDelay3 = DataDelay0; + portconfig.DxDelay3 = Disabled; + portconfig.ThirdSlotMask3 = 0x0000; + portconfig.FouthSlotMask3 = 0x0000; + portconfig.FifthSlotMask3 = 0x0000; + portconfig.SixthSlotMask3 = 0x0000; + portconfig.SevenSlotMask3 = 0x0000; + portconfig.EightSlotMask3 = 0x0000; + + if ((configportstatus = gpakConfigurePorts(vpm150m->dspid, &portconfig, &pstatus))) { + printk("Configuration of ports failed (%d)!\n", configportstatus); + return -1; + } else { + if (debug & DEBUG_ECHOCAN) + printk("Configured McBSP ports successfully\n"); + } + + if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) { + printk("Error pinging DSP (%d)\n", res); + return -1; + } + + for (i = 0; i < wc->type; i++) { + /* Let's configure a channel */ + chanconfig.PcmInPortA = 3; + chanconfig.PcmInSlotA = i; + chanconfig.PcmOutPortA = SerialPortNull; + chanconfig.PcmOutSlotA = i; + chanconfig.PcmInPortB = 2; + chanconfig.PcmInSlotB = i; + chanconfig.PcmOutPortB = 3; + chanconfig.PcmOutSlotB = i; + if (vpmdtmfsupport) { + chanconfig.ToneTypesA = DTMF_tone; + chanconfig.MuteToneA = Enabled; + chanconfig.FaxCngDetA = Enabled; + } else { + chanconfig.ToneTypesA = Null_tone; + chanconfig.MuteToneA = Disabled; + chanconfig.FaxCngDetA = Disabled; + } + chanconfig.ToneTypesB = Null_tone; + chanconfig.EcanEnableA = Enabled; + chanconfig.EcanEnableB = Disabled; + chanconfig.MuteToneB = Disabled; + chanconfig.FaxCngDetB = Disabled; + + if (alawoverride) + chanconfig.SoftwareCompand = cmpPCMA; + else + chanconfig.SoftwareCompand = cmpPCMU; + + chanconfig.FrameRate = rate2ms; + + chanconfig.EcanParametersA.EcanTapLength = 1024; + chanconfig.EcanParametersA.EcanNlpType = 1; + chanconfig.EcanParametersA.EcanAdaptEnable = 1; + chanconfig.EcanParametersA.EcanG165DetEnable = 0; + chanconfig.EcanParametersA.EcanDblTalkThresh = 6; + chanconfig.EcanParametersA.EcanNlpThreshold = 24; + chanconfig.EcanParametersA.EcanNlpConv = 0; + chanconfig.EcanParametersA.EcanNlpUnConv = 0; + chanconfig.EcanParametersA.EcanNlpMaxSuppress = 0; + chanconfig.EcanParametersA.EcanCngThreshold = 43; + chanconfig.EcanParametersA.EcanAdaptLimit = 50; + chanconfig.EcanParametersA.EcanCrossCorrLimit = 15; + chanconfig.EcanParametersA.EcanNumFirSegments = 3; + chanconfig.EcanParametersA.EcanFirSegmentLen = 64; + + chanconfig.EcanParametersB.EcanTapLength = 1024; + chanconfig.EcanParametersB.EcanNlpType = 1; + chanconfig.EcanParametersB.EcanAdaptEnable = 1; + chanconfig.EcanParametersB.EcanG165DetEnable = 0; + chanconfig.EcanParametersB.EcanDblTalkThresh = 6; + chanconfig.EcanParametersB.EcanNlpThreshold = 24; + chanconfig.EcanParametersB.EcanNlpConv = 0; + chanconfig.EcanParametersB.EcanNlpUnConv = 0; + chanconfig.EcanParametersB.EcanNlpMaxSuppress = 0; + chanconfig.EcanParametersB.EcanCngThreshold = 43; + chanconfig.EcanParametersB.EcanAdaptLimit = 50; + chanconfig.EcanParametersB.EcanCrossCorrLimit = 15; + chanconfig.EcanParametersB.EcanNumFirSegments = 3; + chanconfig.EcanParametersB.EcanFirSegmentLen = 64; + + if ((res = gpakConfigureChannel(vpm150m->dspid, i, tdmToTdm, &chanconfig, &cstatus))) { + printk("Unable to configure channel (%d)\n", res); + if (res == 1) { + printk("Reason %d\n", cstatus); + } + + return -1; + } + + if ((res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &algstatus))) { + printk("Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus); + return -1; + } + + if (vpmdtmfsupport) { + if ((res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &algstatus))) { + printk("Unable to disable dtmf muting on channel %d (reason %d:%d)\n", i + 1, res, algstatus); + return -1; + } + } + } + + if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) { + printk("Error pinging DSP (%d)\n", res); + return -1; + } + + vpm150m->wq = create_singlethread_workqueue("wctdm24xxp"); + vpm150m->wc = wc; + + if (!vpm150m->wq) { + printk("Unable to create work queue!\n"); + return -1; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&vpm150m->work, vpm150m_bh, vpm150m); +#else + INIT_WORK(&vpm150m->work, vpm150m_bh); +#endif + + /* Turn on DTMF detection */ + if (vpmdtmfsupport) + set_bit(VPM150M_DTMFDETECT, &vpm150m->control); + + set_bit(VPM150M_ACTIVE, &vpm150m->control); + + return 0; +} + +static void wctdm_vpm150m_init(struct wctdm *wc) +{ + unsigned short i; + struct vpm150m *vpm150m; + unsigned short reg; + struct wctdm_firmware fw; + gpakDownloadStatus_t downloadstatus; + gpakPingDspStat_t pingstatus; + unsigned long flags; + + if (!vpmsupport) { + printk("VPM: Support Disabled\n"); + wc->vpm150m = NULL; + return; + } + + vpm150m = kmalloc(sizeof(struct vpm150m), GFP_KERNEL); + + if (!vpm150m) { + printk("Unable to allocate VPM150M!\n"); + return; + } + + memset(vpm150m, 0, sizeof(struct vpm150m)); + + /* Init our vpm150m struct */ + sema_init(&vpm150m->sem, 1); + vpm150m->curpage = 0x80; + + for (i = 0; i < WC_MAX_IFACES; i++) { + if (ifaces[i] == wc) + vpm150m->dspid = i; + } + + printk("Checking for VPMADT032...\n"); + + if (debug & DEBUG_ECHOCAN) + printk("Setting VPMADT032 DSP ID to %d\n", vpm150m->dspid); + + spin_lock_irqsave(&wc->reglock, flags); + wc->vpm150m = vpm150m; + spin_unlock_irqrestore(&wc->reglock, flags); + + for (i = 0; i < 10; i++) + schluffen(&wc->regq); + + if (debug & DEBUG_ECHOCAN) + printk("VPMADT032 Testing page access: "); + for (i = 0; i < 0xf; i++) { + int x; + for (x = 0; x < 3; x++) { + wctdm_vpm150m_setpage(wc, i); + reg = wctdm_vpm150m_getpage(wc); + if (reg != i) { + if (debug & DEBUG_ECHOCAN) + printk("Failed: Sent %x != %x VPMADT032 Failed HI page test\n", i, reg); + goto failed_exit; + } + } + } + if (debug & DEBUG_ECHOCAN) + printk("Passed\n"); + + /* Set us up to page 0 */ + wctdm_vpm150m_setpage(wc, 0); + if (debug & DEBUG_ECHOCAN) + printk("VPMADT032 now doing address test: "); + for (i = 0; i < 16; i++) { + int x; + for (x = 0; x < 2; x++) { + wctdm_vpm150m_setreg(wc, 1, 0x1000, &i); + wctdm_vpm150m_getreg(wc, 1, 0x1000, ®); + if (reg != i) { + printk("VPMADT032 Failed address test\n"); + goto failed_exit; + } + + } + } + if (debug & DEBUG_ECHOCAN) + printk("Passed\n"); + +#if 0 + /* Load the firmware */ + set_bit(VPM150M_SPIRESET, &vpm150m->control); + + /* Wait for it to boot */ + msleep(7000); + + pingstatus = gpakPingDsp(vpm150m->dspid, &version); + + if (pingstatus || (version != 0x106)) { +#endif + fw.offset = 0; + if (request_firmware(&fw.fw, vpm150m_firmware, &wc->dev->dev)) { + printk("Unable to locate VPMADT032.bin firmware!\n"); + } + + set_bit(VPM150M_HPIRESET, &vpm150m->control); + + while (test_bit(VPM150M_HPIRESET, &vpm150m->control)) + schluffen(&wc->regq); + + printk("VPMADT032 Loading firwmare... "); + downloadstatus = gpakDownloadDsp(vpm150m->dspid, &fw); + + release_firmware(fw.fw); + + if (downloadstatus != 0) { + printk("Unable to download firmware to VPMADT032 with cause %d\n", downloadstatus); + goto failed_exit; + } else { + printk("Success\n"); + } + + set_bit(VPM150M_SWRESET, &vpm150m->control); + + while (test_bit(VPM150M_SWRESET, &vpm150m->control)) + schluffen(&wc->regq); + + msleep(700); +#if 0 + } +#endif + + pingstatus = gpakPingDsp(vpm150m->dspid, &vpm150m->version); + + if (!pingstatus) { + if (debug & DEBUG_ECHOCAN) + printk("Version of DSP is %x\n", vpm150m->version); + } else { + printk("VPMADT032 Failed! Unable to ping the DSP (%d)!\n", pingstatus); + goto failed_exit; + } + + if (vpm150m_config_hw(wc)) { + goto failed_exit; + } + + return; + +failed_exit: + spin_lock_irqsave(&wc->reglock, flags); + wc->vpm150m = NULL; + spin_unlock_irqrestore(&wc->reglock, flags); + kfree(vpm150m); + + return; +} + static void wctdm_vpm_set_dtmf_threshold(struct wctdm *wc, unsigned int threshold) { unsigned int x; @@ -3097,10 +3671,10 @@ static void wctdm_vpm_init(struct wctdm *wc) for (x=0;x<NUM_EC;x++) { ver = wctdm_vpm_in(wc, x, 0x1a0); /* revision */ - if (debug) - printk("VPM: Chip %d: ver %02x\n", x, ver); + if (debug & DEBUG_ECHOCAN) + printk("VPM100: Chip %d: ver %02x\n", x, ver); if (ver != 0x33) { - printk("VPM: %s\n", x ? "Inoperable" : "Not Present"); + printk("VPM100: %s\n", x ? "Inoperable" : "Not Present"); wc->vpm = 0; return; } @@ -3231,7 +3805,7 @@ static void wctdm_locate_modules(struct wctdm *wc) wc->modtype[x] = MOD_TYPE_FXSINIT; #ifdef VPM_SUPPORT wc->vpm = -1; - for (x=wc->cards;x<wc->cards+NUM_EC;x++) + for (x = wc->cards; x < wc->cards+NUM_EC; x++) wc->modtype[x] = MOD_TYPE_VPM; #endif spin_unlock_irqrestore(&wc->reglock, flags); @@ -3259,7 +3833,7 @@ retry: /* Init with Auto Calibration */ if (!(ret = wctdm_init_proslic(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); - if (debug) { + if (debug & DEBUG_CARD) { readi = wctdm_getreg(wc,x,LOOP_I_LIMIT); printk("Proslic module %d loop current is %dmA\n",x, ((readi*3)+20)); @@ -3271,7 +3845,7 @@ retry: /* Init with Manual Calibration */ if (!wctdm_init_proslic(wc, x, 0, 1, sane)) { wc->cardflag |= (1 << x); - if (debug) { + if (debug & DEBUG_CARD) { readi = wctdm_getreg(wc,x,LOOP_I_LIMIT); printk("Proslic module %d loop current is %dmA\n",x, ((readi*3)+20)); @@ -3283,27 +3857,27 @@ retry: } else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); printk("Port %d: Installed -- AUTO FXO (%s mode)\n",x + 1, fxo_modes[_opermode].name); - } else if (!wctdm_init_qrvdri(wc,x)) { - wc->cardflag |= 1 << x; - printk("Port %d: Installed -- QRV DRI card\n",x + 1); + } else if (!wctdm_init_qrvdri(wc,x)) { + wc->cardflag |= 1 << x; + printk("Port %d: Installed -- QRV DRI card\n",x + 1); } else { - if ((wc->type == 8) && ((x & 0x3) == 1) && !wc->altcs[x]) { - spin_lock_irqsave(&wc->reglock, flags); - wc->modtype[x] = MOD_TYPE_FXSINIT; - wc->altcs[x] = 2; - spin_unlock_irqrestore(&wc->reglock, flags); - schluffen(&wc->regq); - spin_lock_irqsave(&wc->reglock, flags); - wc->modtype[x] = MOD_TYPE_FXS; - spin_unlock_irqrestore(&wc->reglock, flags); - if (debug) - printk("Trying port %d with alternate chip select\n", x + 1); - goto retry; - } else { - printk("Port %d: Not installed\n", x + 1); - wc->modtype[x] = MOD_TYPE_NONE; - wc->cardflag |= (1 << x); - } + if ((wc->type == 8) && ((x & 0x3) == 1) && !wc->altcs[x]) { + spin_lock_irqsave(&wc->reglock, flags); + wc->modtype[x] = MOD_TYPE_FXSINIT; + wc->altcs[x] = 2; + spin_unlock_irqrestore(&wc->reglock, flags); + schluffen(&wc->regq); + spin_lock_irqsave(&wc->reglock, flags); + wc->modtype[x] = MOD_TYPE_FXS; + spin_unlock_irqrestore(&wc->reglock, flags); + if (debug & DEBUG_CARD) + printk("Trying port %d with alternate chip select\n", x + 1); + goto retry; + } else { + printk("Port %d: Not installed\n", x + 1); + wc->modtype[x] = MOD_TYPE_NONE; + wc->cardflag |= (1 << x); + } } } } @@ -3312,6 +3886,16 @@ retry: if (wc->vpm) { printk("VPM: Present and operational (Rev %c)\n", 'A' + wc->vpm - 1); wc->ctlreg |= 0x10; + } else { + spin_lock_irqsave(&wc->reglock, flags); + for (x = wc->cards; x < wc->cards+NUM_EC; x++) + wc->modtype[x] = MOD_TYPE_NONE; + spin_unlock_irqrestore(&wc->reglock, flags); + wctdm_vpm150m_init(wc); + if (wc->vpm150m) { + printk("VPMADT032: Present and operational (Firmware version %x)\n", wc->vpm150m->version); + wc->ctlreg |= 0x10; + } } #endif } @@ -3323,25 +3907,19 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data; int x; int y; - static int initd_ifaces=0; - if(initd_ifaces){ - memset((void *)ifaces,0,(sizeof(struct wctdm *))*WC_MAX_IFACES); - initd_ifaces=1; - } - for (x=0;x<WC_MAX_IFACES;x++) - if (!ifaces[x]) break; - if (x >= WC_MAX_IFACES) { - printk("Too many interfaces\n"); - return -EIO; - } - if (pci_enable_device(pdev)) { res = -EIO; } else { wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL); if (wc) { + spin_lock(&ifacelock); + for (x = 0; x < WC_MAX_IFACES; x++) + if (!ifaces[x]) break; + ifaces[x] = wc; + spin_unlock(&ifacelock); + memset(wc, 0, sizeof(struct wctdm)); spin_lock_init(&wc->reglock); wc->curcard = -1; @@ -3449,18 +4027,47 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic static void wctdm_release(struct wctdm *wc) { + int i; + zt_unregister(&wc->span); + if (wc->freeregion) release_region(wc->iobase, 0xff); + + spin_lock(&ifacelock); + + for (i = 0; i < WC_MAX_IFACES; i++) + if (ifaces[i] == wc) + break; + + ifaces[i] = NULL; + + spin_unlock(&ifacelock); + kfree(wc); printk("Freed a Wildcard\n"); } static void __devexit wctdm_remove_one(struct pci_dev *pdev) { + unsigned long flags; struct wctdm *wc = pci_get_drvdata(pdev); - if (wc) { + struct vpm150m *vpm150m = wc->vpm150m; + if (wc) { + if (vpm150m) { + clear_bit(VPM150M_DTMFDETECT, &vpm150m->control); + clear_bit(VPM150M_ACTIVE, &vpm150m->control); + flush_workqueue(vpm150m->wq); + destroy_workqueue(vpm150m->wq); + + spin_lock_irqsave(&wc->reglock, flags); + wc->vpm150m = NULL; + vpm150m->wc = NULL; + spin_unlock_irqrestore(&wc->reglock, flags); + + kfree(wc->vpm150m); + } /* Stop any DMA */ wctdm_stop_dma(wc); @@ -3482,6 +4089,8 @@ static void __devexit wctdm_remove_one(struct pci_dev *pdev) static struct pci_device_id wctdm_pci_tbl[] = { { 0xd161, 0x2400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm2400 }, { 0xd161, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm800 }, + { 0xd161, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex800 }, + { 0xd161, 0x8003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex2400 }, { 0 } }; @@ -3519,6 +4128,8 @@ static int __init wctdm_init(void) return -ENODEV; } + memset((void *)ifaces,0,(sizeof(struct wctdm *))*WC_MAX_IFACES); + res = pci_module_init(&wctdm_driver); if (res) return -ENODEV; @@ -3588,6 +4199,3 @@ MODULE_LICENSE("GPL"); module_init(wctdm_init); module_exit(wctdm_cleanup); - - - diff --git a/wctdm24xxp/gpakErrs.h b/wctdm24xxp/gpakErrs.h new file mode 100644 index 0000000..73d3666 --- /dev/null +++ b/wctdm24xxp/gpakErrs.h @@ -0,0 +1,139 @@ +/* + * 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 */ + + Cc_InvalidMuteToneA = 51, /* invalid MuteToneA set, no detector */ + Cc_InvalidMuteToneB = 52, /* invalid MuteToneB set, no detector */ + Cc_InsuffFaxCngDetResources = 53 /* insufficient tdm block resources avail. */ + +} 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 */ + Ac_InvalidDTMFMuteA = 5, /* A side invalid Mute, since no dtmf detector */ + Ac_InvalidDTMFMuteB = 6, /* B side invalid Mute, since no dtmf detector */ + Ac_InvalidFaxCngA = 7, /* A side FAXCNG detector not available */ + Ac_InvalidFaxCngB = 8, /* B side FAXCNG detector not available */ + Ac_InvalidSysConfig = 9 /* No new system parameters (DTMF config) wrriten yet */ +} GPAK_AlgControlStat_t; + +/* Write System Parameters reply status codes. */ +typedef enum +{ + Sp_Success = 0, /* System Parameters written successfully */ + Sp_BadTwistThresh = 29 /* invalid twist threshold */ + +} GPAK_SysParmsStat_t; + +#endif /* prevent multiple inclusion */ + + + + + + + + + + + + + + + + + + + diff --git a/wctdm24xxp/gpakenum.h b/wctdm24xxp/gpakenum.h new file mode 100644 index 0000000..b278159 --- /dev/null +++ b/wctdm24xxp/gpakenum.h @@ -0,0 +1,175 @@ +/* + * 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 + EnableDTMFMuteA = 9, // Mute A side Dtmf digit after tone detected + DisableDTMFMuteA = 10, // Do not mute A side Dtmf digit once tone detected + EnableDTMFMuteB = 11, // Mute B side Dtmf digit after tone detected + DisableDTMFMuteB = 12, // Do not mute B side Dtmf digit once tone detected + EnableFaxCngDetectA = 13, // Enable A side Fax CNG detector, channel must be configed already + DisableFaxCngDetectA = 14, // Disable A side Fax CNG detector, channel must be configed already + EnableFaxCngDetectB = 15, // Enable B side Fax CNG detector, channel must be configed already + DisableFaxCngDetectB = 16 // Disable B side Fax CNG detector, channel must be configed already +} 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 + + FaxCngDigit = 90, // Fax Calling Tone (1100 Hz) + + EndofMFDigit = 100, // End of MF digit + EndofCngDigit = 101 // End of Cng Digit +} GpakToneCodes_t; + +/* GPIO control code*/ +typedef enum +{ + GPIO_READ = 0, + GPIO_WRITE = 1, + GPIO_DIR = 2 +} GpakGPIOCotrol_t; + + +#endif // end multiple inclusion diff --git a/wctdm24xxp/wctdm24xxp.h b/wctdm24xxp/wctdm24xxp.h new file mode 100644 index 0000000..1b32103 --- /dev/null +++ b/wctdm24xxp/wctdm24xxp.h @@ -0,0 +1,237 @@ +#ifndef _WCTDM24XXP_H +#define _WCTDM24XXP_H + +#include "../zaptel.h" +#include <asm/semaphore.h> + +#define NUM_FXO_REGS 60 + +#define WC_MAX_IFACES 128 + +#define RING_DEBOUNCE 128 /* Ringer Debounce (in ms) */ +#define DEFAULT_BATT_DEBOUNCE 64 /* Battery debounce (in ms) */ +#define POLARITY_DEBOUNCE 64 /* Polarity debounce (in ms) */ +#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ + +#define OHT_TIMER 6000 /* How long after RING to retain OHT */ + +#define FLAG_3215 (1 << 0) + +#define EFRAME_SIZE 108 +#define ERING_SIZE 16 /* Maximum ring size */ +#define EFRAME_GAP 20 +#define SFRAME_SIZE ((EFRAME_SIZE * ZT_CHUNKSIZE) + (EFRAME_GAP * (ZT_CHUNKSIZE - 1))) + +#define MAX_ALARMS 10 + +#define MOD_TYPE_NONE 0 +#define MOD_TYPE_FXS 1 +#define MOD_TYPE_FXO 2 +#define MOD_TYPE_FXSINIT 3 +#define MOD_TYPE_VPM 4 +#define MOD_TYPE_QRV 5 +#define MOD_TYPE_VPM150M 6 + +#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ +#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ +#define PEGCOUNT 5 /* 5 cycles of pegging means RING */ + +#define SDI_CLK (0x00010000) +#define SDI_DOUT (0x00020000) +#define SDI_DREAD (0x00040000) +#define SDI_DIN (0x00080000) + +#define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4)) + +#define __CMD_RD (1 << 20) /* Read Operation */ +#define __CMD_WR (1 << 21) /* Write Operation */ +#define __CMD_FIN (1 << 22) /* Has finished receive */ +#define __CMD_TX (1 << 23) /* Has been transmitted */ + +#define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR) +#define CMD_RD(a) (((a) << 8) | __CMD_RD) + +#define CMD_BYTE(card,bit,altcs) (((((card) & 0x3) * 3 + (bit)) * 7) \ + + ((card) >> 2) + (altcs) + ((altcs) ? -21 : 0)) +#define NUM_CARDS 24 +#define NUM_EC 4 +#define NUM_SLOTS 6 +#define MAX_TDM_CHAN 31 + +#define NUM_CAL_REGS 12 + +#define USER_COMMANDS 8 +#define ISR_COMMANDS 2 +#define QRV_DEBOUNCETIME 20 + +#define MAX_COMMANDS (USER_COMMANDS + ISR_COMMANDS) + +#define __VPM150M_RWPAGE (1 << 4) +#define __VPM150M_RD (1 << 3) +#define __VPM150M_WR (1 << 2) +#define __VPM150M_FIN (1 << 1) +#define __VPM150M_TX (1 << 0) + +#define VPM150M_HPI_CONTROL 0x00 +#define VPM150M_HPI_ADDRESS 0x02 +#define VPM150M_HPI_DATA 0x03 + +#define VPM150M_MAX_COMMANDS 8 + +/* Some Bit ops for different operations */ +#define VPM150M_SPIRESET 0 +#define VPM150M_HPIRESET 1 +#define VPM150M_SWRESET 2 +#define VPM150M_DTMFDETECT 3 +#define VPM150M_ACTIVE 4 + +#define VPM150M_MAX_DATA 3 + +#define VPM_SUPPORT + +#ifdef VPM_SUPPORT + +/* Define to get more attention-grabbing but slightly more CPU using echocan status */ +#define FANCY_ECHOCAN + +#endif + +struct vpm150m_cmd { + unsigned int addr; + unsigned char datalen; + unsigned char desc; + unsigned char txident; + unsigned short data[VPM150M_MAX_DATA]; +}; + +struct vpm150m { + struct workqueue_struct *wq; + struct work_struct work; + struct wctdm *wc; + + int dspid; + struct semaphore sem; + unsigned long control; + unsigned char curpage; + unsigned short version; + unsigned long curecstate; + unsigned long desiredecstate; + unsigned long curdtmfmutestate; + unsigned long desireddtmfmutestate; + struct vpm150m_cmd cmdq[MAX_COMMANDS]; + unsigned char curtone[24]; +}; + +struct calregs { + unsigned char vals[NUM_CAL_REGS]; +}; + +struct cmdq { + unsigned int cmds[MAX_COMMANDS]; + unsigned char isrshadow[ISR_COMMANDS]; +}; + +struct wctdm { + struct pci_dev *dev; + char *variety; + struct zt_span span; + unsigned char ios; + unsigned int sdi; + int usecount; + unsigned int intcount; + unsigned int rxints; + unsigned int txints; + unsigned int intmask; + unsigned char txident; + unsigned char rxident; + int dead; + int pos; + int flags[NUM_CARDS]; + int freeregion; + int alt; + int rdbl; + int tdbl; + int curcard; + unsigned char ctlreg; + int cards; + int cardflag; /* Bit-map of present cards */ + int altcs[NUM_CARDS + NUM_EC]; + char qrvhook[NUM_CARDS]; + unsigned short qrvdebtime[NUM_CARDS]; + int radmode[NUM_CARDS]; +#define RADMODE_INVERTCOR 1 +#define RADMODE_IGNORECOR 2 +#define RADMODE_EXTTONE 4 +#define RADMODE_EXTINVERT 8 +#define RADMODE_IGNORECT 16 +#define RADMODE_PREEMP 32 +#define RADMODE_DEEMP 64 + unsigned short debouncetime[NUM_CARDS]; + signed short rxgain[NUM_CARDS]; + signed short txgain[NUM_CARDS]; + spinlock_t reglock; + wait_queue_head_t regq; + /* FXO Stuff */ + union { + struct { + int wasringing; + int ringdebounce; + int offhook; + int battdebounce; + int nobatttimer; + int battery; + int lastpol; + int polarity; + int polaritydebounce; + } fxo; + struct { + int oldrxhook; + int debouncehook; + int lastrxhook; + int debounce; + int ohttimer; + int idletxhookstate; /* IDLE changing hook state */ + int lasttxhook; + int palarms; + struct calregs calregs; + } fxs; + } mods[NUM_CARDS]; + struct cmdq cmdq[NUM_CARDS + NUM_EC]; + /* Receive hook state and debouncing */ + int modtype[NUM_CARDS + NUM_EC]; + /* Set hook */ + int sethook[NUM_CARDS + NUM_EC]; + int dacssrc[NUM_CARDS]; + int type; + +#ifdef VPM_SUPPORT + int vpm; + unsigned long dtmfactive; + unsigned long dtmfmask; + unsigned long dtmfmutemask; + short dtmfenergy[NUM_CARDS]; + short dtmfdigit[NUM_CARDS]; + + struct vpm150m *vpm150m; +#ifdef FANCY_ECHOCAN + int echocanpos; + int blinktimer; +#endif +#endif + unsigned long iobase; + dma_addr_t readdma; + dma_addr_t writedma; + dma_addr_t descripdma; + volatile unsigned int *writechunk; /* Double-word aligned write memory */ + volatile unsigned int *readchunk; /* Double-word aligned read memory */ + volatile unsigned int *descripchunk; /* Descriptors */ + struct zt_chan chans[NUM_CARDS]; +}; + + +int schluffen(wait_queue_head_t *q); + +extern spinlock_t ifacelock; +extern struct wctdm *ifaces[WC_MAX_IFACES]; + +#endif |