📄 ac97.c
字号:
}
if (!status)
{
// Fresh start. No errors. Init for new operations.
// Many init operations are performed in Ac97StartFifo() because
// logical FIFO configuration can only be done by clients on
// open FIFOs. No advantage to setting up for defaults that won't
// be used.
// Don't change the current settings for the sample rate.
// Clear all error and status indications; fresh start.
Ac97ClearFifoStatus (fifoInfoP);
}
if (!status)
{
if (!(fifoInfoP->fifoStatus & AC97_FIFO_ST_DMA_CHAN_ACQ))
{ // Need to get DMA channel
// Get DMA channel and record the results.
// Parameter values for XsDmaGetFreeChannel()
// intialized in Ac97SWInit()
fifoInfoP->dmaChannel = XsDmaGetFreeChannel (
fifoInfoP->dmaChannelPrioReq,
fifoInfoP->dmaDeviceName,
fifoInfoP->fifoStatus & AC97_FIFO_ST_DIR_TX,
&fifoInfoP->dmaChannelPrioCmp);
if (-1 == fifoInfoP->dmaChannel)
{ // No channel available. Record fact and clean up.
// The convention is 0s for most uninitialized members
fifoInfoP->dmaChannel = 0;
fifoInfoP->dmaChannelPrioReq = 0;
fifoInfoP->dmaChannelPrioCmp = 0;
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_DMA_CHAN_NA,
AC97_SET);
status = ERR_T_NOT_AVAIL;
errLoc = 4;
}
else
{
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_DMA_CHAN_ACQ,
AC97_SET);
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_DMA_CHAN_NA,
AC97_CLEAR);
}
} // if (need to get DMA channel)
if (!status )
{
if (!(fifoInfoP->stopDescriptorRootP))
{
// 0-length descriptor, points to self. Needs no buffer.
fifoInfoP->stopDescriptorRootP =
XsDmaCreateBareDescChain (fifoInfoP->dmaChannel, 1, 0);
} // Get stopDMA descriptor, if needed.
if (!fifoInfoP->stopDescriptorRootP)
{
status = ERR_T_NOT_AVAIL;
errLoc = 5;
}
else
{
// Don't declare open until all operations performed.
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_OPEN,
AC97_SET);
// Give our caller the address of the info structure.
// It will be needed for client operations on this FIFO.
*fifoInfoAddrP = fifoInfoP;
} // else: Have stopDMA descriptor.
} // if (Acquired DMA channel OK)
} // else (no configuration error conditions)
if (status)
{
LOGERROR (fifoInfoP->parentAc97ctxP->loggedError,
ERR_L_AC97,
ERR_S_AC97_OPEN_FIFO,
status,
fifoInfoP->fifoId,
errLoc,
0)
}
return(status);
} // Ac97OpenFifo
UINT32 Ac97OpenFifoPcmIn (Ac97ContextT* ctxP,
Ac97FifoProcessingInfoT** fifoInfoPP)
{
return (Ac97OpenFifo(ctxP, fifoInfoPP, XS_AC97CTRL_FIFO_AUDIO_IN));
}
UINT32 Ac97OpenFifoPcmOut (Ac97ContextT* ctxP,
Ac97FifoProcessingInfoT** fifoInfoPP)
{
return (Ac97OpenFifo(ctxP, fifoInfoPP, XS_AC97CTRL_FIFO_AUDIO_OUT));
}
UINT32 Ac97OpenFifoMicIn (Ac97ContextT* ctxP,
Ac97FifoProcessingInfoT** fifoInfoPP)
{
return (Ac97OpenFifo(ctxP, fifoInfoPP, XS_AC97CTRL_FIFO_MIC_IN));
}
UINT32 Ac97OpenFifoModemIn (Ac97ContextT* ctxP,
Ac97FifoProcessingInfoT** fifoInfoPP)
{
return (Ac97OpenFifo(ctxP, fifoInfoPP, XS_AC97CTRL_FIFO_MODEM_IN));
}
UINT32 Ac97OpenFifoModemOut (Ac97ContextT* ctxP,
Ac97FifoProcessingInfoT** fifoInfoPP)
{
return (Ac97OpenFifo(ctxP, fifoInfoPP, XS_AC97CTRL_FIFO_MODEM_OUT));
}
// Record first error condition, but continue closing down as much as possible
UINT32 Ac97CloseFifo (Ac97FifoProcessingInfoT* fifoInfoP)
{
UINT32 status = ERR_NONE;
UINT32 statusTmp = ERR_NONE;
int errloc = 0;
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Ac97CloseFifo: 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);
// No-op gracefuly if null or not open.
if (fifoInfoP)
{
if (fifoInfoP->fifoStatus & AC97_FIFO_ST_OPEN)
{
// Graceful termination of any current operations.
// Includes disabling of interrupts
status = Ac97StopFifo (fifoInfoP);
if (status && !statusTmp)
{
statusTmp = status;
errloc = 1;
}
// Do the close here!
// Close includes disposing of all resources but not changing
// configuration settings.
fifoInfoP->clientBufP = 0;
fifoInfoP->dmaDescriptorHwPaddrNextTmp = 0;
fifoInfoP->samplesProcessed = 0;
// Mark as closed now. Buffers really can't be used at this point.
// In a pre-emptive multitasking environment, a "closing" flag or
// more effective mutex would be needed to bracket this entire
// function.
fifoInfoP->fifoStatus &= AC97_FIFO_ST_OPEN_MSK;
// Return DMA channel: This also unregisters DMA handler, disables
// DMA interrupts for the channel and generally cleans up
// the DMA interface.
status = XsDmaFreeChannel(fifoInfoP->dmaChannel);
if (status && !statusTmp)
{
statusTmp = status;
errloc = 2;
}
// Unregister FIFO interrupt handler. Also disables this
// FIFO interrupt.
status = XsAc97CtrlUnRegisterHandler (fifoInfoP->fifoInterruptId);
if (status && !statusTmp)
{
statusTmp = status;
errloc = 3;
}
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_FIFO_ISR_REG,
AC97_CLEAR);
// Return all descriptors and buffers to pool. Chain may be either
// closed or open.
if (fifoInfoP->standardModeDescriptorRootP)
{
status = XsDmaDestroyChain (fifoInfoP->
standardModeDescriptorRootP);
fifoInfoP->standardModeDescriptorRootP = NULL;
if (status && !statusTmp)
{
statusTmp = status;
errloc = 4;
}
}
// Special handling for DMA loop mode. The subroutine knows all.
status = Ac97FreeDmaLoopDescriptors (fifoInfoP);
if (status && !statusTmp)
{
statusTmp = status;
errloc = 5;
}
// Now all descriptor chains are gone, so clear the active pointer
fifoInfoP->activeDescriptorRootP = NULL;
Ac97WriteFifoStatus (fifoInfoP,
(AC97_FIFO_ST_DMA_CHAN_ACQ |
AC97_FIFO_ST_DMA_ISR_REG),
AC97_CLEAR);
if (statusTmp)
{
LOGERROR (fifoInfoP->parentAc97ctxP->loggedError,
ERR_L_AC97, ERR_S_AC97_CLOSE_FIFO, statusTmp,errloc,0,0)
}
// @@@ This probably should be inside an "else"
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_OPEN,
AC97_CLEAR);
} // if (fifoInfoP->fifoStatus & AC97_FIFO_ST_OPEN)
} // if (fifoInfoP)
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"End Ac97CloseFifo\n");
DM_CwDbgPrintf(DM_CW_AC97_CODEC,
"Fifo status word: %X\n",fifoInfoP->fifoStatus);
return (status);
} // Ac97CloseFifo()
// Returns the number of samples read into client buffer. 4 bytes / sample.
// -1 indicates no bytes available and an error condition. Use Ac97CheckFifoStatus
// and Ac97ClearFifoStatus
// Must be read from an open, readable Fifo
INT Ac97ReadBuf (Ac97FifoProcessingInfoT* fifoInfoP, PUINT32 inbufP, INT numSamples)
{
UINT32 status = ERR_NONE;
INT numRead = 0;
// @@@
if (!(fifoInfoP->fifoStatus & AC97_FIFO_ST_OPEN))
{
status = ERR_T_WRONG_STATE;
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_INVALID_OP,
AC97_SET);
}
else if (fifoInfoP->fifoStatus & AC97_FIFO_ST_DIR_TX)
{
status = ERR_T_NORECEIVE; // Can't read from a Tx FIFO
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_INVALID_OP,
AC97_SET);
}
else if (fifoInfoP->fifoStatus &0 /*@@@*/)
{
}
//@@@ // try to do the read here!
if (status)
{
numRead = -1;
LOGERROR (fifoInfoP->parentAc97ctxP->loggedError,
ERR_L_AC97,
ERR_S_AC97_READ_BUF,
status,
fifoInfoP->fifoId,
(UINT32)&fifoInfoP->parentAc97ctxP,
0)
}
return (numRead);
} // Ac97ReadBuf()
// Returns the number of samples read from client buffer into driver buffer.
// 4 bytes / sample.
// -1 indicates no bytes transferred and an error condition. Use
// Ac97CheckFifoStatus and Ac97ClearFifoStatus.
// Must be written to an open, writable Fifo
INT Ac97WriteBuf (Ac97FifoProcessingInfoT* fifoInfoP, PUINT32 outbufP, INT numSamples)
{
UINT32 status = ERR_NONE;
INT numWritten = 0;
// @@@
fifoInfoP->fifoStatus = AC97_FIFO_ST_INVALID_OP;
if (!(fifoInfoP->fifoStatus & AC97_FIFO_ST_OPEN))
{
status = ERR_T_WRONG_STATE;
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_INVALID_OP,
AC97_SET);
}
else if (fifoInfoP->fifoStatus & AC97_FIFO_ST_DIR_TX)
{
status = ERR_T_NOTRANSMIT; // Can't write to a Rx FIFO
Ac97WriteFifoStatus (fifoInfoP,
AC97_FIFO_ST_INVALID_OP,
AC97_SET);
}
//@@@ // try to do the write here!
if (status)
{
numWritten = -1;
LOGERROR (fifoInfoP->parentAc97ctxP->loggedError,
ERR_L_AC97,
ERR_S_AC97_WRITE_BUF,
status,
fifoInfoP->fifoId,
(UINT32)&fifoInfoP->parentAc97ctxP,
0)
}
return (numWritten);
} // Ac97WriteBuf()
// Gets the fifoStatus word from the target Ac97FifoProcessingInfoT struct
// Should be interpreted with the "AC97_FIFO_ST_" constants
// Clears AC97_FIFO_ST_INVALID_OP status on read.
UINT32 Ac97CheckFifoStatus (Ac97FifoProcessingInfoT* fifoInfoP)
{
return (fifoInfoP->fifoStatus);
}
// Clears error indications in the fifoStatus word and also supporting data
// such as the current number of DMA restarts.
void Ac97ClearFifoStatus (Ac97FifoProcessingInfoT* fifoInfoP)
{
// Clear all error indications from this FIFO's record.
fifoInfoP->dmaRestarts = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -