| /** \file vp880_fxs_control.c |
| * vp880_fxs_control.c |
| * |
| * This file contains the control functions for the FXS lines of the VP880 |
| * device. |
| * |
| * Copyright (c) 2011, Microsemi |
| * |
| * $Revision: 1.1.2.1.8.3 $ |
| * $LastChangedDate: 2010-03-23 14:01:46 -0500 (Tue, 23 Mar 2010) $ |
| */ |
| |
| #include "../includes/vp_api_cfg.h" |
| |
| #if defined (VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT) |
| |
| /* INCLUDES */ |
| #include "../../arch/uvb/vp_api_types.h" |
| #include "../../arch/uvb/vp_hal.h" |
| #include "../includes/vp_api_int.h" |
| #include "../includes/vp880_api.h" |
| #include "../vp880_api/vp880_api_int.h" |
| #include "../../arch/uvb/sys_service.h" |
| |
| /**< Functions called by Set Line State to abstract device states used for ABS |
| * and non ABS devices (if they are different). Set line state then operates |
| * on device state only (abstracted from API-II line state). |
| */ |
| static void |
| Vp880ApplyInternalTestTerm( |
| VpLineCtxType *pLineCtx); |
| |
| static void |
| Vp880RemoveInternalTestTerm( |
| VpLineCtxType *pLineCtx); |
| |
| /** |
| * Vp880ProcessFxsLine() |
| * This function should only be called by Vp880ApiTick on FXS lines. It |
| * performs all line processing for operations that are Tick based |
| * |
| * Preconditions: |
| * Conditions defined by purpose of Api Tick. |
| * |
| * Postconditions: |
| * The Api variables and events (as appropriate) for the line passed have been |
| * updated. |
| */ |
| VpStatusType |
| Vp880ProcessFxsLine( |
| Vp880DeviceObjectType *pDevObj, |
| VpLineCtxType *pLineCtx) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| uint8 channelId = pLineObj->channelId; |
| bool dpStatus[2] = {FALSE, FALSE}; |
| VpOptionEventMaskType lineEvents1; |
| VpOptionEventMaskType lineEvents2; |
| VpDialPulseDetectStatesType beforeState, afterState; |
| uint8 hookStatus = 0, i, validSamples; |
| uint8 hookIncrement; |
| bool dp2Valid; |
| |
| #ifdef VP880_INCLUDE_TESTLINE_CODE |
| /* Skip processing during line test */ |
| if (Vp880IsChnlUndrTst(pDevObj, channelId) == TRUE) { |
| return VP_STATUS_SUCCESS; |
| } |
| #endif |
| |
| lineEvents1.signaling = 0; |
| lineEvents2.signaling = 0; |
| |
| /* If the secondary pulse params are all 0 (default), mark them as invalid |
| * so that they will not be used. */ |
| if (pDevObj->pulseSpecs2.breakMin == 0 && |
| pDevObj->pulseSpecs2.breakMax == 0 && |
| pDevObj->pulseSpecs2.makeMin == 0 && |
| pDevObj->pulseSpecs2.makeMax == 0 && |
| #ifdef EXTENDED_FLASH_HOOK |
| pDevObj->pulseSpecs2.onHookMin == 0 && |
| #endif |
| pDevObj->pulseSpecs2.interDigitMin == 0 && |
| pDevObj->pulseSpecs2.flashMin == 0 && |
| pDevObj->pulseSpecs2.flashMax == 0) { |
| |
| dp2Valid = FALSE; |
| |
| } else { |
| dp2Valid = TRUE; |
| } |
| |
| /* |
| * If the line is configured for Dial Pulse Detection, run the Dial Pulse |
| * detection code. Dial Pulse detection code will generate the appropriate |
| * events |
| */ |
| if((pLineObj->pulseMode == VP_OPTION_PULSE_DECODE_ON) &&
|
| (!(pLineObj->lineState.condition & VP_CSLAC_LINE_LEAK_TEST))) {
|
| /* |
| * Based on the following (vp880_api_int.h): |
| * |
| * #define VP880_CC_500HZ_RATE 0x40 |
| * #define VP880_CC_1KHZ_RATE 0x30 |
| * #define VP880_CC_2KHZ_RATE 0x20 |
| * #define VP880_CC_4KHZ_RATE 0x10 |
| * #define VP880_CC_8KHZ_RATE 0x00 |
| */
|
|
|
| /*
|
| * Get the incremental steps sizes in 125us increments used to apply to the on/off-hook
|
| * times below, which is also the same scale as the Dial Pulse Detection Parameters.
|
| */ |
| uint8 shiftAmt = ((pDevObj->txBufferDataRate >> 4) & 0x7); |
| hookIncrement = (1 << shiftAmt); |
| |
| validSamples = ((pDevObj->txBuffer[VP880_TX_BUF_HOOK_MSB_INDEX] |
| & VP880_TX_BUF_LEN_MASK) >> 4); |
| |
| if (validSamples == 7) { |
| validSamples = 6; |
| } |
| |
| if (channelId == 0) { |
| hookStatus = pDevObj->txBuffer[VP880_TX_BUF_HOOK_LSB_INDEX]
|
| & VP880_TX_BUF_HOOK_CHAN1_MASK; |
| } else { |
| hookStatus = (pDevObj->txBuffer[VP880_TX_BUF_HOOK_MSB_INDEX] |
| & VP880_TX_BUF_HOOK_MSB_MASK) << 2; |
| hookStatus |= ((pDevObj->txBuffer[VP880_TX_BUF_HOOK_LSB_INDEX] |
| & VP880_TX_BUF_HOOK_CHAN2_MASK) >> 6); |
| } |
| /*
|
| * If the line is currently in Low Power Mode, the meaning applied to the hook detector is
|
| * inverted from it's normal meaning. A "high" signal level into the hook detector, which
|
| * normally measures current, will cause the hook bit to be set = '1'. The SW has to
|
| * understand that the hook detector is being fed line voltage when in LPM and interpret
|
| * that to mean the customer phone is on-hook. In normal detection mode where the
|
| * hook detector is being fed current, a "high" signal level means high current = phone is
|
| * off-hook.
|
| */ |
| if (pLineObj->status & VP880_LOW_POWER_EN) { |
| hookStatus = ~hookStatus; |
| } |
| |
| beforeState = pLineObj->dpStruct.state; |
| |
| /*
|
| * This flag is set when the Test Buffer (more specifically, the Hook-Bit buffer) has been
|
| * read this tick. It could happen when a hook interrupt occurs or not (i.e., there are a
|
| * few reasons for reading the test buffer). It should ONLY be set on silicon > VC, but it
|
| * isn't too much effort to check for both Hook-Bit Buffer read AND > VC silicon before
|
| * processing the data.
|
| */
|
| if ((pDevObj->state & VP_DEV_TEST_BUFFER_READ) &&
|
| (pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION] > VP880_REV_VC)) { |
| /*
|
| * Loop Open and Loop Close times are only at the accuracy of the tickrate now. We
|
| * want to improve that by looking for the point the hook status changed in the hook-bit
|
| * buffer and adjust based on the hook bit buffer sample rate (i.e., hook increment set
|
| * above).
|
| */
|
| VP_HOOK(VpLineCtxType, pLineCtx,
|
| ("CH%d Validsamples %d, buffer %02X %02X %d%d%d%d%d%d at time %d",
|
| channelId,
|
| ((pDevObj->txBuffer[VP880_TX_BUF_HOOK_MSB_INDEX] & VP880_TX_BUF_LEN_MASK) >> 4),
|
| pDevObj->txBuffer[0], pDevObj->txBuffer[1],
|
| (hookStatus & 0x20) == 0x20,
|
| (hookStatus & 0x10) == 0x10,
|
| (hookStatus & 0x08) == 0x08,
|
| (hookStatus & 0x04) == 0x04,
|
| (hookStatus & 0x02) == 0x02,
|
| (hookStatus & 0x01) == 0x01,
|
| pDevObj->timeStamp));
|
| |
| for (i = 1; i < (1 << validSamples); i <<= 1) { |
| if (beforeState == VP_DP_DETECT_STATE_LOOP_CLOSE) { |
| if (!(hookStatus & i)) {
|
| VP_HOOK(VpLineCtxType, pLineCtx,
|
| ("CH%d - Loop Close Time (%d) at time (%d) Hook Increment (%d)",
|
| channelId, pLineObj->dpStruct.lc_time, pDevObj->timeStamp,
|
| hookIncrement)); |
| |
| if (pLineObj->dpStruct.lc_time > hookIncrement) { |
| pLineObj->dpStruct.lc_time -= hookIncrement;
|
| } |
| if (pLineObj->dpStruct2.lc_time > hookIncrement) { |
| pLineObj->dpStruct2.lc_time -= hookIncrement; |
| } |
| } else { |
| break; |
| } |
| } else if (beforeState == VP_DP_DETECT_STATE_LOOP_OPEN) { |
| if (hookStatus & i) {
|
| VP_HOOK(VpLineCtxType, pLineCtx,
|
| ("CH%d - Loop Open Time (%d) at time (%d) Hook Increment (%d)",
|
| channelId, pLineObj->dpStruct.lo_time, pDevObj->timeStamp,
|
| hookIncrement)); |
| |
| if (pLineObj->dpStruct.lo_time > hookIncrement) { |
| pLineObj->dpStruct.lo_time -= hookIncrement; |
| } |
| if (pLineObj->dpStruct2.lo_time > hookIncrement) { |
| pLineObj->dpStruct2.lo_time -= hookIncrement; |
| } |
| } else { |
| break; |
| } |
| } |
| }
|
| |
| VP_HOOK(VpLineCtxType, pLineCtx,
|
| ("CH%d Fine Measurement Loop Open Time (%d) Loop Close Time (%d) at time %d",
|
| channelId, pLineObj->dpStruct.lo_time, pLineObj->dpStruct.lc_time,
|
| pDevObj->timeStamp)); |
| } |
|
|
| if ((!(pDevObj->stateInt & VP880_IS_ABS)) &&
|
| (pDevObj->swParamsCache[VP880_REGULATOR_TRACK_INDEX] & VP880_REGULATOR_FIXED_RING)) {
|
| /* Compensate for slow onhook detection with Fixed Mode Tracking Designs */ |
| if (beforeState == VP_DP_DETECT_STATE_LOOP_CLOSE && !(pLineObj->dpStruct.hookSt)) { |
| if (pLineObj->dpStruct.lc_time > VP880_PULSE_DETECT_ADJUSTMENT_LONG) { |
| pLineObj->dpStruct.lc_time -= VP880_PULSE_DETECT_ADJUSTMENT_LONG;
|
| VP_HOOK(VpLineCtxType, pLineCtx,
|
| ("CH%d Long Compensation to Loop Close Time (%d) at time (%d)",
|
| channelId, pLineObj->dpStruct.lc_time, pDevObj->timeStamp));
|
| } |
| } |
| if (beforeState == VP_DP_DETECT_STATE_LOOP_CLOSE && !(pLineObj->dpStruct2.hookSt)) { |
| if (pLineObj->dpStruct2.lc_time > VP880_PULSE_DETECT_ADJUSTMENT_LONG) { |
| pLineObj->dpStruct2.lc_time -= VP880_PULSE_DETECT_ADJUSTMENT_LONG; |
| } |
| }
|
| } else {
|
| /* Compensate just for the silicon */ |
| if (beforeState == VP_DP_DETECT_STATE_LOOP_CLOSE && !(pLineObj->dpStruct.hookSt)) { |
| if (pLineObj->dpStruct.lc_time > VP880_PULSE_DETECT_ADJUSTMENT_SHORT) { |
| pLineObj->dpStruct.lc_time -= VP880_PULSE_DETECT_ADJUSTMENT_SHORT;
|
| VP_HOOK(VpLineCtxType, pLineCtx,
|
| ("CH%d Short Compensation to Loop Close Time (%d) at time (%d)",
|
| channelId, pLineObj->dpStruct.lc_time, pDevObj->timeStamp));
|
| } |
| } |
| if (beforeState == VP_DP_DETECT_STATE_LOOP_CLOSE && !(pLineObj->dpStruct2.hookSt)) { |
| if (pLineObj->dpStruct2.lc_time > VP880_PULSE_DETECT_ADJUSTMENT_SHORT) { |
| pLineObj->dpStruct2.lc_time -= VP880_PULSE_DETECT_ADJUSTMENT_SHORT; |
| } |
| }
|
| }
|
| |
| dpStatus[0] = VpUpdateDP(pDevObj->devProfileData.tickRate, |
| &pDevObj->pulseSpecs, &pLineObj->dpStruct, &lineEvents1); |
| if (dp2Valid == TRUE) { |
| dpStatus[1] = VpUpdateDP(pDevObj->devProfileData.tickRate, |
| &pDevObj->pulseSpecs2, &pLineObj->dpStruct2, &lineEvents2); |
| } |
| afterState = pLineObj->dpStruct.state; |
| /* Update the loop open and close times according to the hook change |
| * within a tick */ |
| |
| /* If the state changed, adjust the hook timings */ |
| if (beforeState != afterState) { |
| if (pDevObj->state & VP_DEV_TEST_BUFFER_READ) { |
| for (i = 1; i < (1 << validSamples); i <<= 1) { |
| if (afterState == VP_DP_DETECT_STATE_LOOP_CLOSE) { |
| if (hookStatus & i) { |
| pLineObj->dpStruct.lc_time += hookIncrement; |
| pLineObj->dpStruct2.lc_time += hookIncrement; |
| } else { |
| break; |
| } |
| } else if (afterState == VP_DP_DETECT_STATE_LOOP_OPEN) { |
| if (!(hookStatus & i)) { |
| pLineObj->dpStruct.lo_time += hookIncrement; |
| pLineObj->dpStruct2.lo_time += hookIncrement; |
| } else { |
| break; |
| } |
| } |
| } |
| } |
| if (afterState == VP_DP_DETECT_STATE_LOOP_OPEN) {
|
| if ((!(pDevObj->stateInt & VP880_IS_ABS)) &&
|
| (pDevObj->swParamsCache[VP880_REGULATOR_TRACK_INDEX] & VP880_REGULATOR_FIXED_RING)) {
|
| /* Compensate for slow onhook detection with Fixed Mode Tracking Designs */
|
| pLineObj->dpStruct.lo_time += VP880_PULSE_DETECT_ADJUSTMENT_LONG; |
| pLineObj->dpStruct2.lo_time += VP880_PULSE_DETECT_ADJUSTMENT_LONG;
|
| } else {
|
| /* Compensate for silicon only */
|
| pLineObj->dpStruct.lo_time += VP880_PULSE_DETECT_ADJUSTMENT_SHORT; |
| pLineObj->dpStruct2.lo_time += VP880_PULSE_DETECT_ADJUSTMENT_SHORT;
|
| } |
| } |
| } |
| |
| /* |
| * The state machines will not necessarily complete at the same time, so |
| * keep track of each and when both are done, report a passing digit if |
| * one exists, or invalid if no criteria was met. |
| */ |
| if (dpStatus[0] == TRUE) { |
| pLineObj->signaling1 = lineEvents1.signaling; |
| pLineObj->lineEventHandle = pDevObj->timeStamp; |
| |
| if (!(pLineObj->lineEvents.signaling & VP_LINE_EVID_BREAK_MAX)) { |
| pLineObj->status |= VP880_DP_SET1_DONE; |
| } |
| } |
| |
| if (dpStatus[1] == TRUE && dp2Valid == TRUE) { |
| pLineObj->signaling2 = lineEvents2.signaling; |
| pLineObj->lineEventHandle = pDevObj->timeStamp; |
| |
| if (!(pLineObj->lineEvents.signaling & VP_LINE_EVID_BREAK_MAX)) { |
| pLineObj->status |= VP880_DP_SET2_DONE; |
| } |
| } |
| |
| /* Report events if: |
| * Both DP sets are done, OR |
| * Set 1 is done and set 2 is invalid */ |
| if ((pLineObj->status & VP880_DP_SET1_DONE) && |
| ((pLineObj->status & VP880_DP_SET2_DONE) || |
| dp2Valid == FALSE)) |
| { |
| /* Use the results of DP set 1 if it detected a valid digit, or |
| * if DP set 2 detected an invalid digit, or if set 2 is disabled */ |
| if (pLineObj->dpStruct.digits != -1 || |
| pLineObj->dpStruct2.digits == -1 || |
| dp2Valid == FALSE) |
| { |
| pLineObj->signalingData = pLineObj->dpStruct.digits; |
| pLineObj->lineEvents.signaling |= pLineObj->signaling1; |
| pLineObj->lineEventHandle = VP_DP_PARAM1; |
| } else { |
| pLineObj->signalingData = pLineObj->dpStruct2.digits; |
| pLineObj->lineEvents.signaling |= pLineObj->signaling2; |
| pLineObj->lineEventHandle = VP_DP_PARAM2; |
| } |
| |
| if (pLineObj->signalingData == 0) { |
| pLineObj->signalingData = pLineObj->lineEventHandle; |
| pLineObj->lineEventHandle = pDevObj->timeStamp; |
| } |
| |
| pLineObj->status &= ~(VP880_DP_SET1_DONE | VP880_DP_SET2_DONE); |
| pLineObj->signaling1 = 0; |
| pLineObj->signaling2 = 0; |
| } |
| } |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| /* |
| * If Caller ID sequencer is in progress, update unless it's in a state of |
| * suspension. If suspended, re-enable if device is in underrun (no more |
| * data to transmit). |
| */ |
| if ((pLineObj->callerId.status & VP_CID_IN_PROGRESS) |
| || (pLineObj->suspendCid == TRUE)) { |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| uint8 ecVal = pLineObj->ecVal; |
| |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880ProcessFxsLine()+")); |
| |
| /* First read of the CID State Machine this tick. */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_CID_PARAM_RD, |
| VP880_CID_PARAM_LEN, pLineObj->tickBeginState); |
| pLineObj->delayConsumed = FALSE; |
| |
| if (pLineObj->suspendCid == TRUE) { |
| /* |
| * Check to see if the Device Buffer is empty. If it is, continue |
| * with CID. |
| */ |
| uint8 cidState = (pLineObj->tickBeginState[0] & VP880_CID_STATE_MASK); |
| |
| if ((cidState == VP880_CID_STATE_URUN) |
| || (cidState == VP880_CID_STATE_IDLE)) { |
| uint8 cidParam = pLineObj->tickBeginState[0]; |
| |
| pLineObj->suspendCid = FALSE; |
| cidParam &= ~(VP880_CID_FRAME_BITS); |
| cidParam |= VP880_CID_DIS; |
| |
| Vp880MuteChannel(pLineCtx, FALSE); |
| if (cidParam != pLineObj->tickBeginState[0]) { |
| pLineObj->tickBeginState[0] = cidParam; |
| VP_CID(VpLineCtxType, pLineCtx, |
| ("Stopping FSK Generator with 0x%02X to CID Params at time %d", |
| pLineObj->tickBeginState[0], pDevObj->timeStamp)); |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_CID_PARAM_WRT, |
| VP880_CID_PARAM_LEN, pLineObj->tickBeginState); |
| pLineObj->callerId.status &= ~VP_CID_FSK_ACTIVE; |
| } |
| } |
| } |
| |
| if (pLineObj->callerId.status & VP_CID_IN_PROGRESS) { |
| VpCidSeq(pLineCtx); |
| } |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880ProcessFxsLine()-")); |
| } |
| #endif |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /** |
| * Vp880SetRelayState() |
| * This function controls the state of controlled relays for the VP880 device. |
| * |
| * Preconditions: |
| * Device/Line context should be created and initialized. For applicable |
| * devices bootload should be performed before calling the function. |
| * |
| * Postconditions: |
| * The indicated relay state is set for the given line. |
| */ |
| VpStatusType |
| Vp880SetRelayState( |
| VpLineCtxType *pLineCtx, |
| VpRelayControlType rState) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| uint8 ecVal = pLineObj->ecVal; |
| VpTermType termType = pLineObj->termType; |
| |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| uint8 pcn = pDevObj->staticInfo.rcnPcn[VP880_PCN_LOCATION]; |
| uint8 revCode = pDevObj->staticInfo.rcnPcn[VP880_RCN_LOCATION]; |
| |
| uint8 ioDirection[VP880_IODIR_REG_LEN]; |
| uint8 ioData[VP880_IODATA_REG_LEN]; |
| |
| uint8 mpiBuffer[3 + VP880_IODIR_REG_LEN + VP880_IODATA_REG_LEN + VP880_ICR1_LEN]; |
| uint8 mpiIndex = 0; |
| |
| /* |
| * In case this function fails, make sure the line object is unchanged by |
| * pre-saving it's current value. First step prior to 100% verifiying if |
| * this function will be success is to pre-clear the relay control bits. |
| */ |
| uint8 preIcr1Values = pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION]; |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState+")); |
| |
| /* Proceed if device state is either in progress or complete */ |
| if (pDevObj->state & (VP_DEV_INIT_CMP | VP_DEV_INIT_IN_PROGRESS)) { |
| } else { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_DEV_NOT_INITIALIZED; |
| } |
| |
| /* |
| * Do not proceed if the device calibration is in progress. This could |
| * damage the device. |
| */ |
| if (pDevObj->state & VP_DEV_IN_CAL) { |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_DEV_NOT_INITIALIZED; |
| } |
| |
| /* |
| * Handle the VP_RELAY_BRIDGED_TEST case for devices that do not have a |
| * physical test load. Use the internal test termination algorithm instead. |
| * If the VP880_ALWAYS_USE_INTERNAL_TEST_TERMINATION option is defined in |
| * vp_api_cfg.h the HAS_TEST_LOAD_SWITCH flag will always be cleared at |
| * initialization so that this method will always be used. The internal |
| * test termination is only supported for revisions newer than VC. |
| */ |
| if (rState == VP_RELAY_BRIDGED_TEST && |
| !(pDevObj->stateInt & VP880_HAS_TEST_LOAD_SWITCH) && |
| revCode > VP880_REV_VC) { |
| Vp880ApplyInternalTestTerm(pLineCtx); |
| |
| pLineObj->relayState = VP_RELAY_BRIDGED_TEST; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /* If the internal test termination is currently applied and we're going |
| * to a state other than BRIDGED_TEST, restore the internal settings */ |
| if (pLineObj->internalTestTermApplied == TRUE && |
| rState != VP_RELAY_BRIDGED_TEST) { |
| Vp880RemoveInternalTestTerm(pLineCtx); |
| } |
| |
| /* Read registers that may have partial modifications */ |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_IODIR_REG_RD, VP880_IODIR_REG_LEN, |
| ioDirection); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_IODATA_REG_RD, VP880_IODATA_REG_LEN, |
| ioData); |
| |
| /* Always set the value for Test Load Control. */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION-1] |= |
| VP880_ICR1_TEST_LOAD_MASK; |
| |
| /* Preclear test load bits */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] |
| &= ~(VP880_ICR1_TEST_LOAD_MASK); |
| |
| switch (pLineObj->termType) { |
| case VP_TERM_FXS_GENERIC: |
| case VP_TERM_FXS_LOW_PWR: |
| switch (rState) { |
| case VP_RELAY_BRIDGED_TEST: |
| if (!(pDevObj->stateInt & VP880_HAS_TEST_LOAD_SWITCH)) { |
| |
| /* Restore values prior to caling this function. */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] = preIcr1Values; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] |
| |= VP880_ICR1_TEST_LOAD_METALLIC; |
| |
| /* Test Load bits pre-cleared. Can pick up at Normal */ |
| |
| case VP_RELAY_NORMAL: |
| break; |
| |
| default: |
| /* Restore values prior to caling this function. */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] = preIcr1Values; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| break; |
| |
| case VP_TERM_FXS_ISOLATE: |
| case VP_TERM_FXS_ISOLATE_LP: |
| case VP_TERM_FXS_SPLITTER: |
| case VP_TERM_FXS_SPLITTER_LP: |
| ioDirection[0] &= ~VP880_IODIR_IO1_MASK; |
| ioData[0] &= ~(VP880_IODATA_IO1); |
| |
| switch (rState) { |
| case VP_RELAY_BRIDGED_TEST: |
| if (!(pDevObj->stateInt & VP880_HAS_TEST_LOAD_SWITCH)) { |
| /* Restore values prior to caling this function. */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] = preIcr1Values; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] |
| |= VP880_ICR1_TEST_LOAD_METALLIC; |
| |
| /* Test Load bits pre-cleared. Can pick up at Normal */ |
| |
| case VP_RELAY_NORMAL: |
| if (revCode <= VP880_REV_VC) { |
| ioDirection[0] |= VP880_IODIR_IO1_OPEN_DRAIN; |
| |
| if ((termType == VP_TERM_FXS_ISOLATE) || |
| (termType == VP_TERM_FXS_ISOLATE_LP)) { |
| /* |
| * Dir = open drain, Set Data = 0 |
| * This causes the output to go high. |
| */ |
| ioData[0] &= ~VP880_IODATA_IO1; |
| } else { |
| /* |
| * Dir = open drain, Set Data = 1 |
| * This causes the output to go low. |
| */ |
| ioData[0] |= VP880_IODATA_IO1; |
| } |
| } else { |
| /* |
| * Devices VP880_DEV_PCN_88536 and VP880_DEV_PCN_88264 |
| * are affected here because the VP-API-II forces the |
| * revision code to >= JA |
| */ |
| if ((termType == VP_TERM_FXS_ISOLATE) || |
| (termType == VP_TERM_FXS_ISOLATE_LP)) { |
| /* |
| * Dir = output, Set Data = 1 |
| * This causes the output to go high. |
| */ |
| ioDirection[0] |= VP880_IODIR_IO1_OUTPUT; |
| ioData[0] |= VP880_IODATA_IO1; |
| } else { |
| if ((pcn == VP880_DEV_PCN_88536) || |
| (pcn == VP880_DEV_PCN_88264)) { |
| /* |
| * Dir = output, Set Data = 0 |
| * This causes the output to go low. |
| */ |
| ioDirection[0] |= VP880_IODIR_IO1_OUTPUT; |
| ioData[0] &= ~VP880_IODATA_IO1; |
| } else { |
| /* |
| * Dir = open drain, Set Data = 1 |
| * This causes the output to go low. |
| */ |
| ioDirection[0] |= VP880_IODIR_IO1_OPEN_DRAIN; |
| ioData[0] |= VP880_IODATA_IO1; |
| } |
| } |
| } |
| break; |
| |
| case VP_RELAY_RESET: |
| if (revCode <= VP880_REV_VC) { |
| ioDirection[0] |= VP880_IODIR_IO1_OPEN_DRAIN; |
| if ((termType == VP_TERM_FXS_ISOLATE) || |
| (termType == VP_TERM_FXS_ISOLATE_LP)) { |
| /* |
| * Dir = open drain, Set Data = 1. |
| * This causes the output to go low |
| */ |
| ioData[0] |= VP880_IODATA_IO1; |
| } else { |
| /* |
| * Dir = open drain, Set Data = 0 |
| * This causes the output to go high. |
| */ |
| ioData[0] &= ~VP880_IODATA_IO1; |
| } |
| } else { |
| /* |
| * Devices VP880_DEV_PCN_88536 and VP880_DEV_PCN_88264 |
| * are affected here because the VP-API-II forces the |
| * revision code to >= JA |
| */ |
| if ((termType == VP_TERM_FXS_ISOLATE) || |
| (termType == VP_TERM_FXS_ISOLATE_LP)) { |
| if ((pcn == VP880_DEV_PCN_88536) || |
| (pcn == VP880_DEV_PCN_88264)) { |
| /* |
| * Dir = output, Set Data = 0. |
| * This causes the output to go low |
| */ |
| ioDirection[0] |= VP880_IODIR_IO1_OUTPUT; |
| ioData[0] &= ~VP880_IODATA_IO1; |
| } else { |
| /* |
| * Dir = open drain, Set Data = 1. |
| * This causes the output to go low |
| */ |
| ioDirection[0] |= VP880_IODIR_IO1_OPEN_DRAIN; |
| ioData[0] |= VP880_IODATA_IO1; |
| } |
| } else { |
| /* |
| * Dir = output, Set Data = 1 |
| * This causes the output to go high. |
| */ |
| ioDirection[0] |= VP880_IODIR_IO1_OUTPUT; |
| ioData[0] |= VP880_IODATA_IO1; |
| } |
| } |
| break; |
| |
| default: |
| /* Restore values prior to caling this function. */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] = preIcr1Values; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| break; |
| |
| default: |
| /* Restore values prior to caling this function. */ |
| pLineObj->icr1Values[VP880_ICR1_TEST_LOAD_LOCATION] = preIcr1Values; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("1. Write IODATA 0x%02X on Ch %d", |
| ioData[0], pLineObj->channelId)); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("2. Write IODIR 0x%02X on Channel %d", |
| ioDirection[0], pLineObj->channelId)); |
| |
| /* |
| * Note in this ONE VP-API-II case for ICR1 Write, we don't go through |
| * protected write because that's handled above in this function. |
| */ |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR1_WRT, |
| VP880_ICR1_LEN, pLineObj->icr1Values); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Vp880SetRelayState(): Write ICR1 0x%02X 0x%02X 0x%02X 0x%02X Ch %d", |
| pLineObj->icr1Values[0], pLineObj->icr1Values[1], |
| pLineObj->icr1Values[2], pLineObj->icr1Values[3], pLineObj->channelId)); |
| |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_IODATA_REG_WRT, |
| VP880_IODATA_REG_LEN, ioData); |
| |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_IODIR_REG_WRT, |
| VP880_IODIR_REG_LEN, ioDirection); |
| |
| /* send down the mpi commands */ |
| VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]); |
| |
| pLineObj->relayState = rState; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| VP_API_FUNC_INT(VpLineCtxType, pLineCtx, ("Vp880SetRelayState-")); |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /** |
| * Vp880ApplyInternalTestTerm() |
| * Configures ICR settings for the internal test termination algorithm, which |
| * is used instead of a physical test load for devices which do not have one. |
| * The internal test termination works by internally shorting tip and ring. |
| */ |
| static void |
| Vp880ApplyInternalTestTerm( |
| VpLineCtxType *pLineCtx) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| uint8 ecVal = pLineObj->ecVal; |
| uint16 timerDelay; |
| uint8 icr1Reg[VP880_ICR1_LEN]; |
| |
| uint8 mpiBuffer[3 + VP880_ICR6_LEN + VP880_ICR4_LEN + VP880_ICR1_LEN]; |
| uint8 mpiIndex = 0; |
| |
| if (pLineObj->internalTestTermApplied == TRUE) { |
| return; |
| } |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| /* Disconnect VAB sensing */ |
| pLineObj->icr6Values[VP880_DC_CAL_CUT_INDEX] |= VP880_C_TIP_SNS_CUT; |
| pLineObj->icr6Values[VP880_DC_CAL_CUT_INDEX] |= VP880_C_RING_SNS_CUT; |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR6_WRT, |
| VP880_ICR6_LEN, pLineObj->icr6Values); |
| |
| /* Reverse the polarity of the ground key detector to disable ground |
| * key event */ |
| pLineObj->icr4Values[VP880_ICR4_GKEY_DET_LOCATION] |= VP880_ICR4_GKEY_POL; |
| pLineObj->icr4Values[VP880_ICR4_GKEY_DET_LOCATION+1] |= VP880_ICR4_GKEY_POL; |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR4_WRT, |
| VP880_ICR4_LEN, pLineObj->icr4Values); |
| |
| /*
|
| * Forcing the SLIC DC bias for 200ms helps collapse the battery voltage, especially for fixed
|
| * tracking designs. We're taking over ICR1 completely here. Other parts of the code will set |
| * pLineObj->icr1Values but will not actually write to the register while this relay state is
|
| * active. See Vp880ProtectedWriteICR1(). When we leave this relay state, we will restore
|
| * pLineObj->icr1Values
|
| */ |
| icr1Reg[0] = 0xFF; |
| icr1Reg[2] = 0xFF; |
| if (pDevObj->stateInt & VP880_IS_ABS) { |
| #ifdef VP880_ABS_SUPPORT |
| icr1Reg[1] = 0x68; |
| icr1Reg[3] = 0x06; |
| #endif |
| } else {
|
| #ifdef VP880_TRACKER_SUPPORT |
| icr1Reg[1] = 0xFF; |
| icr1Reg[3] = 0x0F;
|
| #endif |
| } |
| VP_LINE_STATE(VpLineCtxType, pLineCtx,
|
| ("Vp880ApplyInternalTestTerm(): Write ICR1 0x%02X 0x%02X 0x%02X 0x%02X Ch %d",
|
| icr1Reg[0], icr1Reg[1], icr1Reg[2], icr1Reg[3], pLineObj->channelId)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR1_WRT, VP880_ICR1_LEN, icr1Reg); |
| |
| /* send down the mpi commands */ |
| VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]); |
| |
| /* Start a timer to change the ICR1 settings later to make tip and ring |
| * outputs high impedance so that they tend to pull to battery. */ |
| if ((pDevObj->stateInt & VP880_IS_ABS) || |
| !(pDevObj->swParams[VP880_REGULATOR_TRACK_INDEX] |
| & VP880_REGULATOR_FIXED_RING_SWY)) { |
| /* Use a short delay for ABS and non-fixed tracking devices */ |
| timerDelay = VP880_INTERNAL_TESTTERM_SETTLING_TIME_SHORT; |
| } else { |
| /* Use a longer delay for fixed tracking devices */ |
| timerDelay = VP880_INTERNAL_TESTTERM_SETTLING_TIME_LONG; |
| } |
| pLineObj->lineTimers.timers.timer[VP_LINE_INTERNAL_TESTTERM_TIMER] = |
| (MS_TO_TICKRATE(timerDelay, pDevObj->devProfileData.tickRate)) | VP_ACTIVATE_TIMER; |
|
|
| pLineObj->internalTestTermApplied = TRUE; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| } /* Vp880ApplyInternalTestTerm() */ |
| |
| /** |
| * Vp880RemoveInternalTestTerm() |
| * This function reverts the settings that control the internal test |
| * termination. |
| */ |
| static void |
| Vp880RemoveInternalTestTerm( |
| VpLineCtxType *pLineCtx) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| uint8 ecVal = pLineObj->ecVal; |
| |
| uint8 mpiBuffer[3 + VP880_ICR6_LEN + VP880_ICR4_LEN + VP880_ICR1_LEN]; |
| uint8 mpiIndex = 0; |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| /* Restore VAB sensing */ |
| pLineObj->icr6Values[VP880_DC_CAL_CUT_INDEX] &= ~VP880_C_TIP_SNS_CUT; |
| pLineObj->icr6Values[VP880_DC_CAL_CUT_INDEX] &= ~VP880_C_RING_SNS_CUT; |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR6_WRT, |
| VP880_ICR6_LEN, pLineObj->icr6Values); |
| |
| /* Restore ground key polarity setting */ |
| pLineObj->icr4Values[VP880_ICR4_GKEY_DET_LOCATION] &= ~VP880_ICR4_GKEY_POL; |
| pLineObj->icr4Values[VP880_ICR4_GKEY_DET_LOCATION+1] &= ~VP880_ICR4_GKEY_POL; |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR4_WRT, |
| VP880_ICR4_LEN, pLineObj->icr4Values); |
| |
| /* Restore ICR1 to the cached value in pLineObj->icr1Values */ |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Vp880RemoveInternalTestTerm(): Write ICR1 0x%02X 0x%02X 0x%02X 0x%02X Ch %d", |
| pLineObj->icr1Values[0], pLineObj->icr1Values[1], |
| pLineObj->icr1Values[2], pLineObj->icr1Values[3], pLineObj->channelId)); |
| |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR1_WRT, |
| VP880_ICR1_LEN, pLineObj->icr1Values); |
| |
| /* send down the mpi commands */ |
| VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]); |
| |
| /* Deactivate the timer in case it is still running */ |
| pLineObj->lineTimers.timers.timer[VP_LINE_INTERNAL_TESTTERM_TIMER] |
| &= ~VP_ACTIVATE_TIMER; |
| |
| pLineObj->internalTestTermApplied = FALSE; |
| |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| } /* Vp880RemoveInternalTestTerm() */ |
| |
| /** |
| * Vp880OffHookMgmt() |
| * This function manages the device and API behavior when an off-hook is |
| * detected from the device AFTER all normal debounce timers have expired. |
| * |
| * Preconditions: |
| * This function is called internally by the API-II only. |
| * |
| * Postconditions: |
| * Device and API is updated accordingly. Returns TRUE if an event is posted. |
| */ |
| bool |
| Vp880OffHookMgmt( |
| Vp880DeviceObjectType *pDevObj, |
| VpLineCtxType *pLineCtx, |
| uint8 ecVal) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| bool retFlag = FALSE; |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| VpProfilePtrType pCadence; |
| #endif |
| |
| VP_HOOK(VpLineCtxType, pLineCtx, ("Off-Hook on Line %d at Time %d Low Power 0x%02X", |
| pLineObj->channelId, pDevObj->timeStamp, (pLineObj->status & VP880_LOW_POWER_EN))); |
| |
| pLineObj->dpStruct.hookSt = TRUE; |
| pLineObj->dpStruct2.hookSt = TRUE; |
| |
| pLineObj->leakyLineCnt = 0; |
| pLineObj->status &= ~VP880_LINE_LEAK; |
| |
| if(pLineObj->pulseMode == VP_OPTION_PULSE_DECODE_OFF) { |
| pLineObj->lineEvents.signaling |= VP_LINE_EVID_HOOK_OFF;
|
| pLineObj->lineEventHandle = pDevObj->timeStamp;
|
| retFlag = TRUE; |
| } |
| |
| #ifdef VP_CSLAC_SEQ_EN |
| /* |
| * If an off-hook is detected when the active cadence is a Message Waiting |
| * Pulse on the line, restore the line state. |
| */ |
| pCadence = pLineObj->cadence.pActiveCadence; |
| if (pCadence != VP_PTABLE_NULL) { |
| if (pCadence[VP_PROFILE_TYPE_LSB] == VP_PRFWZ_PROFILE_MSG_WAIT_PULSE_INT) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Stopping Active Message Waiting Pulse")); |
| Vp880SetLineState(pLineCtx, pLineObj->lineState.currentState); |
| } |
| } |
| #endif |
| return retFlag; |
| } |
| |
| /** |
| * Vp880OnHookMgmt() |
| * This function manages the device and API behavior when an on-hook is |
| * detected from the device AFTER all normal debounce timers have expired. |
| * |
| * Preconditions: |
| * This function is called internally by the API-II only. |
| * |
| * Postconditions: |
| * Device and API is updated accordingly. |
| */ |
| bool |
| Vp880OnHookMgmt( |
| Vp880DeviceObjectType *pDevObj, |
| VpLineCtxType *pLineCtx, |
| uint8 ecVal) |
| { |
| Vp880LineObjectType *pLineObj = pLineCtx->pLineObj; |
| VpDeviceIdType deviceId = pDevObj->deviceId; |
| bool retFlag = FALSE; |
| |
| #ifdef VP880_ABS_SUPPORT |
| uint8 slacState; |
| #endif |
| |
| VP_HOOK(VpLineCtxType, pLineCtx, ("On-Hook on Line %d at Time %d", |
| pLineObj->channelId, pDevObj->timeStamp)); |
| |
| /* Restore the initial threshold */ |
| if (pLineObj->hookHysteresis != 0) { |
| VpMpiCmdWrapper(deviceId, ecVal, VP880_LOOP_SUP_WRT, VP880_LOOP_SUP_LEN, |
| pLineObj->loopSup); |
| } |
| |
| pLineObj->dpStruct.hookSt = FALSE; |
| pLineObj->dpStruct2.hookSt = FALSE; |
| |
| if ((pLineObj->pulseMode == VP_OPTION_PULSE_DECODE_OFF) &&
|
| (!(pLineObj->status & VP880_LINE_LEAK))) {
|
| /* |
| * If this is the first time after initialization that we are checking |
| * for on-hook and it is on-hook, don't generate an interrupt |
| */ |
| VP_HOOK(VpLineCtxType, pLineCtx, |
| ("Dial Pulse Detect Disabled - checking initial on-hook..")); |
| |
| if (!(pLineObj->lineState.condition & VP_CSLAC_STATUS_VALID)) { |
| VP_HOOK(VpLineCtxType, pLineCtx, |
| ("Line Previously Initialized - Generating On-Hook Event")); |
| |
| pLineObj->lineEvents.signaling |= VP_LINE_EVID_HOOK_ON; |
| pLineObj->lineEventHandle = pDevObj->timeStamp; |
| retFlag = TRUE; |
| } |
| } else { |
| VP_HOOK(VpLineCtxType, pLineCtx, |
| ("Dial Pulse Detect Enabled. On-Hook from Dial Pulse State Machine.")); |
| } |
| if (VpIsLowPowerTermType(pLineObj->termType)) { |
| VP_HOOK(VpLineCtxType, pLineCtx, ("User State %d Current State %d", |
| pLineObj->lineState.usrCurrent, pLineObj->lineState.currentState)); |
| |
| if (pLineObj->lineState.usrCurrent == VP_LINE_STANDBY) { |
| pLineObj->lineState.currentState = VP_LINE_STANDBY; |
| Vp880LLSetSysState(deviceId, pLineCtx, 0x00, FALSE); |
| } |
| } |
| |
| #ifdef VP880_ABS_SUPPORT |
| slacState = pLineObj->slicValueCache; |
| |
| if (pDevObj->stateInt & VP880_IS_ABS) { |
| switch(slacState & VP880_SS_LINE_FEED_MASK) { |
| /* |
| * Feed states where the SLIC needs to be put into high battery mode |
| * to optimize feed conditions and transient response. |
| */ |
| case (VP880_SS_ACTIVE & VP880_SS_LINE_FEED_MASK): |
| case (VP880_SS_IDLE & VP880_SS_LINE_FEED_MASK): |
| case (VP880_SS_ACTIVE_MID_BAT & VP880_SS_LINE_FEED_MASK): |
| slacState &= ~VP880_SS_LINE_FEED_MASK; |
| if(pLineObj->lineState.usrCurrent == VP_LINE_STANDBY) { |
| slacState |= VP880_SS_IDLE; |
| } else { |
| slacState |= VP880_SS_ACTIVE_MID_BAT; |
| } |
| Vp880LLSetSysState(deviceId, pLineCtx, slacState, TRUE); |
| break; |
| |
| default: |
| /* |
| * Another state that either should not cause off-hook detection, |
| * or state that is handled by API-II functionality (e.g., |
| * Ring Trip). |
| */ |
| break; |
| } |
| } |
| #endif |
| |
| return retFlag; |
| } |
| |
| /* |
| * Vp880ProtectedWriteICR1() |
| * This function is a wrapper for writing to ICR1. If the internal test |
| * termination is applied, ICR1 must not be changed, so this function copies |
| * the data into the line object cache and returns without writing anything to |
| * the device. If the internal test termination is not applied, the write |
| * is performed. |
| * |
| * Note: This function must be called from within a critical section. |
| */ |
| #ifdef VP880_FXS_SUPPORT |
| uint8 |
| Vp880ProtectedWriteICR1( |
| Vp880LineObjectType *pLineObj, |
| uint8 mpiIndex, |
| uint8 *mpiBuffer) |
| { |
| if (pLineObj->internalTestTermApplied == FALSE) { |
| VP_LINE_STATE(None, VP_NULL, ("Vp880ProtectedWriteICR1(): Channel %d Writing ICR1 0x%02X 0x%02X 0x%02X 0x%02X", |
| pLineObj->channelId, |
| pLineObj->icr1Values[0], pLineObj->icr1Values[1], |
| pLineObj->icr1Values[2], pLineObj->icr1Values[3])); |
| |
| return VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR1_WRT, |
| VP880_ICR1_LEN, pLineObj->icr1Values); |
| } |
| return mpiIndex; |
| } |
| #endif /* VP880_FXS_SUPPORT */ |
| #endif |