📄 ac97.c
字号:
// Ac97StartFifo actually touches the hardware. It assumes (verifies)
// that Ac97OpenFifo has been performed.
// All Fifo-related interrupts are assumed to be inactive when this routine
// is called. That is a responsibility of Ac97StopFifo().
// @@@ Note: May need to zero all buffers before (re)use.
UINT32 Ac97StartFifo (Ac97FifoProcessingInfoT* fifoInfoP)
{
UINT32 status = ERR_NONE;
UINT32 errLoc = 0; // Assume no errors
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Ac97StartFifo: Fifo, ID = %d; Addr = %08X; Name = %s \n",
fifoInfoP->fifoId, (UINT32) fifoInfoP, fifoInfoP->fifoNameStrP);
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Fifo status word: %X\n",fifoInfoP->fifoStatus);
// First, check various error conditions
if (!(fifoInfoP->fifoStatus & AC97_FIFO_ST_OPEN))
{
status = ERR_T_WRONG_STATE;
errLoc = 1;
}
else if (fifoInfoP->fifoStatus & AC97_FIFO_ST_ACTIVE)
{
status = ERR_T_ALREADY_IN_USE;
errLoc = 2;
}
/*
***************************************************************************
Now, perform various software-only operations
***************************************************************************
*/
if (!status)
{
// Fresh start. No errors. Init for new operations.
// We have a DMA channel and maybe a descriptor-buffer chain.
///@@@ // Obtain needed descriptors and descriptor-buffer chains from DMA and
// memalloc module. Configure descriptor chains to our needs (closed
// loop, bidirectional).
// getting DMA buffers?
// First, make sure that this FIFO has the descriptor/buffer chain it needs
//@@@ // for standard model
// if (!(fifoInfoP->fifoStatus & AC97_FIFO_ST_DMA_LP_MODE))
// {
// Ac97SetUpDescriptors (fifoInfoP);
// }
// Then, set up descriptor chains for DMA loop mode if appropriate
// For first pass, just set up for DMA loop
if (fifoInfoP->fifoStatus & AC97_FIFO_ST_DMA_LP_ABLE)
{
status = Ac97SetUpDmaLoopDescriptors (fifoInfoP);
}
// Early development. The "else" will go away.
else
{
// Need to work out details of normal mode buffering.
// Do we need new/current link counts to look for changes?
// If so, how do we handle changes in the link count?
// Maybe two versions of "normal" to test just double buffering
// versus longer, glitch-protected chains.
status = ERR_T_NOT_IMPLEMENTED;
errLoc = 3;
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Error: %s FIFO not DMA Loopable, FifoStatus = %X\n",
fifoInfoP->fifoNameStrP ,fifoInfoP->fifoStatus);
}
// Now set up the descriptor chain to use
if (!status)
{
if (fifoInfoP->fifoStatus & AC97_FIFO_ST_DMA_LP_MODE)
{
// Make DMA loop chain current.
fifoInfoP->activeDescriptorRootP =
fifoInfoP->dmaLoopDescriptorRootP;
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Installing %08X as active descriptor\n",
fifoInfoP->dmaLoopDescriptorRootP);
}
else
{
// Make normal chain current. First make sure that we have
// one. (To be done earlier in this function)
// @@@ fifoInfoP->activeDescriptorRootP =
// fifoInfoP->standardModeDescriptorRootP;
}
}
}
/*
***************************************************************************
More software-only operations
***************************************************************************
*/
if (!status)
{
// Register appropriate ISRs
// Activate interrupts for registered types.
Ac97ClearFifoStatus (fifoInfoP);
// Next four lines might be superflous, probably handled in fifo_close.
fifoInfoP->clientBufP = 0;
fifoInfoP->dmaDescriptorHwPaddrNextTmp = 0;
fifoInfoP->samplesProcessed = 0;
// Install FIFO error ISR if desired and needed.
if ( (fifoInfoP->fifoStatus &
(AC97_FIFO_ST_FIFO_ISR_MODE | AC97_FIFO_ST_FIFO_ISR_REG))
== (AC97_FIFO_ST_FIFO_ISR_MODE ))
{
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Registering ISR with AC97 Controller\n");
status = XsAc97CtrlRegisterHandler (fifoInfoP->fifoInterruptId,
Ac97FifoInterruptHandler,
(void *) fifoInfoP);
if (status)
{
// Bad interrupt type ID or handler already registered.
// Log the bug and don't cover it up. Get it fixed.
// However, make sure that we clean up.
errLoc = 4;
// Already caught the error.
(void) XsAc97CtrlUnRegisterHandler (fifoInfoP->fifoInterruptId);
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_FIFO_ISR_REG,
AC97_CLEAR);
}
else
{
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_FIFO_ISR_REG,
AC97_SET);
}
} // if (installing FIFO error ISR)
} // if (!status): preliminary error checks passed
if (!status)
{
// Now, make sure that we have the specified buffer and DMA
// configuration in place. (buffers already allocated).
// This includes having an appropriate
// set of interrupt handlers registered.
// Register DMA status ISR if desired and needed.
// Then activate it. Assume that DMA is stopped; that's a condition
// for calling this function.
// For now, just use default that reports events in FIFO structure
if ( !status
&& (fifoInfoP->fifoStatus & AC97_FIFO_ST_DMA_ISR_MODE)
&& !(fifoInfoP->fifoStatus & AC97_FIFO_ST_DMA_ISR_REG))
{
status = XsDmaRegisterHandler (fifoInfoP->dmaChannel,
Ac97DefaultDmaInterruptHandler,
fifoInfoP);
if (status)
{
errLoc = 5;
}
else
{
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_DMA_ISR_REG,
AC97_SET);
}
}
/*
***********************************************************************
Finally, begin the actual DMA operation
***********************************************************************
*/
if (!status)
{
// Now, enable the DMA interrupts and wait for the
// "stopped" interrupt to occur.
fifoInfoP->ac97DcsrStopIntrs = 0; // Set up for ready-wait
// (void): Just passed all error checks immediately above.
(void) XsDmaIntReasonEnable(fifoInfoP->dmaChannel,
(DCSR_BUSERRINTR |
DCSR_STARTINTR |
DCSR_ENDINTR |
DCSR_STOPINTR ));
(void) XsDmaLoadFirstDescriptorAddr(fifoInfoP->dmaChannel,
fifoInfoP->activeDescriptorRootP);
(void) XsDmaStart (fifoInfoP->dmaChannel);
status = Ac97WaitForDmaStart (fifoInfoP);
if (status)
{
errLoc = 6;
}
else
{
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_DMA_RUNNING,
AC97_SET);
} // else (:successfully registered handler for DMA interrupt)
} // if (need to install DMA status ISR)
} // if (!status): succeeded in installing FIFO error ISR
if (status)
{
LOGERROR (fifoInfoP->parentAc97ctxP->loggedError,
ERR_L_AC97,
ERR_S_AC97_START_FIFO,
status,
fifoInfoP->fifoId,
errLoc,
0)
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Error Code: %X\n", fifoInfoP->parentAc97ctxP->loggedError);
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Error loc: %X\n", errLoc);
}
else
{
// Don't declare active until all operations performed successfully.
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_ACTIVE,
AC97_SET);
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Success activating FIFO\n");
}
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"End of Ac97StartFifo: FifoName = %s, Status word: %X \n",
fifoInfoP->fifoNameStrP, fifoInfoP->fifoStatus);
return(status);
} // Ac97StartFifo ()
// Graceful termination of DDMA, not instantaneous. Operates by setting the
// Stop bits in the nextPhysicalAddr fields of all descriptors in current
// chain. Minimum delay is 1 buffer time; maximum is 2 buffer times.
UINT32 Ac97StopFifo (Ac97FifoProcessingInfoT* fifoInfoP)
{
UINT32 status = ERR_NONE;
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Begin Ac97StopFifo(). Fifo status word: %X, Active mask: %X",
fifoInfoP->fifoStatus,AC97_FIFO_ST_ACTIVE);
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Fifo IDs: %d, %s,",
fifoInfoP->fifoId,
fifoInfoP->fifoNameStrP);
// No-op gracefuly if inactive.
if (fifoInfoP->fifoStatus & AC97_FIFO_ST_ACTIVE)
{
// Prepare Stop bit to become active after next descriptor load.
(void) XsDmaOperateOnChain (fifoInfoP->dmaLoopDescriptorRootP,
XsDmaDescrSetStopBit);
XsDmaDumpDescriptor (fifoInfoP->dmaLoopDescriptorRootP,
DM_ControlWordsDebugPrintGetBit(DM_CW_AC97_CODEC));
XsDmaDumpDescriptor(fifoInfoP->dmaLoopDescriptorRootP->nextVirtualAddr,
DM_ControlWordsDebugPrintGetBit(DM_CW_AC97_CODEC));
// @@@
// Wait with standard 100 ms timeout for channel to stop.
// This assumes knowledge of the timeout and that two buffer
// times is less than
status = XsDmaWaitUntilStopped (fifoInfoP->dmaChannel);
// Don't declare inactive until everything has stopped.
Ac97WriteFifoStatus (fifoInfoP,
(AC97_FIFO_ST_ACTIVE |
AC97_FIFO_ST_DMA_RUNNING),
AC97_CLEAR);
}
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"End Ac97StopFifo(). Fifo status word: %X, Active mask: %X",
fifoInfoP->fifoStatus,AC97_FIFO_ST_ACTIVE);
return (status);
} // Ac97StopFifo ()
// Slightly faster, still graceful DMA termination. Write a dummy descriptor
// with 0 length and the stop bit set to the DDADR.
// Minimum delay is almost immediate; maximum is 1 buffer time.
UINT32 Ac97StopFifoQuick (Ac97FifoProcessingInfoT* fifoInfoP)
{
UINT32 status = ERR_NONE;
// No-op gracefuly if inactive.
if (fifoInfoP->fifoStatus & AC97_FIFO_ST_ACTIVE)
{
(void) XsDmaLoadFirstDescriptorAddr(fifoInfoP->dmaChannel,
fifoInfoP->stopDescriptorRootP);
// Wait with standard timeout for channel to stop.
status = XsDmaWaitUntilStopped (fifoInfoP->dmaChannel);
// Don't declare inactive until everything has stopped.
Ac97WriteFifoStatus (fifoInfoP,
(AC97_FIFO_ST_ACTIVE |
AC97_FIFO_ST_DMA_RUNNING),
AC97_CLEAR);
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"End Ac97StopFifoQuick(). Fifo status word: %X, Active mask: %X",
fifoInfoP->fifoStatus,AC97_FIFO_ST_ACTIVE);
}
return (status);
} // Ac97StopFifoQuick ()
UINT32 Ac97OpenFifo (Ac97ContextT* ctxP,
Ac97FifoProcessingInfoT** fifoInfoAddrP,
XsAc97CtrlFifoIdT fifoId)
{
UINT32 status = ERR_NONE;
UINT32 errLoc = 0; // Assume no errors
Ac97FifoProcessingInfoT* fifoInfoP =
&ctxP->fifoProcessingInfoRecords[fifoId];
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Ac97OpenFifo: Fifo, ID = %d; Addr = %08X; Name = %s \n",
fifoId, (UINT32) fifoInfoP, fifoInfoP->fifoNameStrP);
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Fifo status word: %X\n",fifoInfoP->fifoStatus);
// First, check various error conditions
if (!fifoInfoP->isSupported)
{
status = ERR_T_NOT_IMPLEMENTED;
errLoc = 1;
}
else if (fifoInfoP->fifoStatus & AC97_FIFO_ST_OPEN)
{
status = ERR_T_ALREADY_IN_USE;
errLoc = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -