📄 serialhw.c
字号:
}
}
else {
// We read all chars, so we're done
break;
}
}
}
else
{
*pByteNumber = 0;
RetVal = 0;
while (TargetRoom > 0)
{
if (pSerHead->availRxByteCount == 0)
{
DDKSdmaGetBufDescStatus(pSerHead->SerialDmaChanRx, pSerHead->currRxDmaBufId, &Status);
if ((Status & DDK_DMA_FLAGS_BUSY) == 0)
{
pSerHead->availRxByteCount = Status & 0xFFFF;
pSerHead->dmaRxStartIdx = 0;
}
else
break;
}
discardCount = 0;
if (pHWHead->UseIrDA && pHWHead->ulDiscard)
{
discardCount = (pHWHead->ulDiscard > pSerHead->availRxByteCount) ? pSerHead->availRxByteCount : pHWHead->ulDiscard;
pHWHead->ulDiscard -= discardCount;
pSerHead->dmaRxStartIdx += discardCount;
pSerHead->availRxByteCount -= discardCount;
}
copyCount = (pSerHead->availRxByteCount > TargetRoom) ? TargetRoom : pSerHead->availRxByteCount;
if (copyCount)
{
LPBYTE pBuffer = (LPBYTE)MapCallerPtr(pTargetBuffer + *pByteNumber, copyCount);
memcpy(pBuffer, pSerHead->pSerialVirtRxDMABufferAddr +
pSerHead->currRxDmaBufId * pSerHead->rxDMABufSize + pSerHead->dmaRxStartIdx, copyCount);
*pByteNumber += copyCount;
TargetRoom -= copyCount;
pSerHead->availRxByteCount -= copyCount;
pSerHead->dmaRxStartIdx += copyCount;
}
//RETAILMSG(1, (TEXT("SL_RxIntrHandler: *pBytes: %d, TargetRoom: %d, availRxByteCount: %d, dmaRxStartIdx: %d CurBufId=%d, discardCount: %d\r\n"), *pByteNumber, TargetRoom, pSerHead->availRxByteCount, pSerHead->dmaRxStartIdx, pSerHead->currRxDmaBufId, discardCount));
if (pSerHead->availRxByteCount == 0)
{
DDKSdmaClearBufDescStatus(pSerHead->SerialDmaChanRx, pSerHead->currRxDmaBufId);
Mode = (pSerHead->currRxDmaBufId == (SERIAL_MAX_DESC_COUNT_RX - 1)) ?
DDK_DMA_FLAGS_WRAP : DDK_DMA_FLAGS_CONT;
DDKSdmaSetBufDesc(pSerHead->SerialDmaChanRx,
pSerHead->currRxDmaBufId,
(DDK_DMA_FLAGS_INTR | Mode),
pSerHead->SerialPhysRxDMABufferAddr.LowPart + pSerHead->currRxDmaBufId * pSerHead->rxDMABufSize,
0,
DDK_DMA_ACCESS_8BIT,
pSerHead->rxDMABufSize);
pSerHead->currRxDmaBufId = (pSerHead->currRxDmaBufId + 1) % SERIAL_MAX_DESC_COUNT_RX;
DDKSdmaStartChan(pSerHead->SerialDmaChanRx);
}
}
pHWHead->DroppedBytes = RetVal;
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
}
if (pSerHead->useDMA == FALSE)
{
// if we saw one (or more) EVT chars, then generate an event
if (fRXFlag) {
pHWHead->EventCallback(pHWHead->pMDDContext, EV_RXFLAG);
DEBUGMSG(ZONE_READ, (TEXT("EV_RXFLAG set\r\n")));
}
else {
DEBUGMSG(ZONE_READ, (TEXT("EV_RXFLAG not set\r\n")));
}
if (pHWHead->DroppedBytes)
DEBUGMSG(ZONE_READ, (TEXT("Rx drop %d.\r\n"), pHWHead->DroppedBytes));
DEBUGMSG(ZONE_READ, (TEXT("SL_RxIntrHandler - rx'ed %d, dropped %d.\r\n"), *pByteNumber, pHWHead->DroppedBytes));
RetVal = pHWHead->DroppedBytes;
pHWHead->DroppedBytes = 0;
}
return(RetVal);
}
//-----------------------------------------------------------------------------
//
// Function: SL_TxIntrHandler
//
// This function is called when the driver
// detects a transmit interrupt (INTR_TX), as set by
// the SL_GetInterruptType function. It sends several
// characters to the hardware transmission buffer.
//
// Parameters:
// pContext
// [in] Pointer to device head.
// pSourceBuffer
// [in] Pointer to the source buffer that contains data to be sent.
// pByteNumber
// [in] When SL_TxIntrEx is called,
// pByteNumber points to the maximum number of bytes
// to send. When SL_TxIntrEx returns, pByteNumber
// points to the actual number of bytes sent..
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
VOID SL_TxIntrHandler( PVOID pContext, PUCHAR pSourceBuffer, ULONG *pByteNumber )
{
PUART_INFO pHWHead = (PUART_INFO)pContext;
PSER_INFO pSerHead = (PSER_INFO)pContext;
UCHAR byteCount;
ULONG NumberOfBytes = *pByteNumber;
// SDMA
UINT32 Status = 0, Mode;
UINT32 curByteCount;
LPBYTE pBuffer;
int bufId;
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler+\r\n")));
DEBUGMSG(ZONE_WRITE, (TEXT("Transmit Event 0x%X, Len %d\r\n"), pContext, *pByteNumber));
SL_ReadModemStatus(pHWHead);
// We may be done sending. If so, just disable the TX interrupts
// and return to the MDD.
if (! *pByteNumber) {
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - Disable INTR_TX.\r\n")));
OUTREG32(&pHWHead->pUartReg->USR2,CSP_BITFVAL(UART_USR2_TXDC, UART_USR2_TXDC_SET));
//Disable the TX interrupts
OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );
return;
}
*pByteNumber = 0; // In case we don't send anything below.
// Disable xmit intr. Most 16550s will keep hammering
// us with xmit interrupts if we don't turn them off
// Whoever gets the FlushDone will then need to turn
// TX Ints back on if needed.
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
// Need to signal FlushDone for XmitComChar
PulseEvent(pHWHead->FlushDone);
pHWHead->CommErrors &= ~CE_TXFULL;
// If CTS flow control is desired, check cts. If clear, don't send,
// but loop. When CTS comes back on, the OtherInt routine will
// detect this and re-enable TX interrupts (causing Flushdone).
// For finest granularity, we would check this in the loop below,
// but for speed, I check it here (up to 8 xmit characters before
// we actually flow off.
if (pHWHead->dcb.fOutxCtsFlow) {
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - fOutxCtsFlow true\r\n")));
// We don't need to explicitly read the MSR, since we always enable
// IER_MS, which ensures that we will get an interrupt and read
// the MSR whenever CTS, DSR, TERI, or DCD change.
//Check CTS (RTS), 1:low, 0:high;
if (!(pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_RTSS, UART_USR1_RTSS_SET))) {
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - fOutxCtsFlow true 0x%x, 0x%x\r\n"),pHWHead->sUSR1,pHWHead->pUartReg->USR1));
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
// disable TX interrupts while flowed off
OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );
// We could return a positive value here, which would
// cause the MDD to periodically check the flow control
// status. However, we don't need to since we know that
// the DCTS interrupt will cause the MDD to call us, and we
// will subsequently fake a TX interrupt to the MDD, causing
// him to call back into PutBytes.
LeaveCriticalSection(&(pHWHead->RegCritSec));
return;
}
}
// Same thing applies for DSR
if (pHWHead->dcb.fOutxDsrFlow) {
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - fOutxDsrFlow true\r\n")));
// We don't need to explicitly read the register, since we always enable
// interrupt, which ensures that we will get an interrupt and read
// the register whenever CTS, DSR, TERI, or DCD change.
//Check shadow bDSR, 1:low, 0:high
if (!pHWHead->bDSR) {
pHWHead->DSRFlowOff = TRUE; // Record flowed off state
// disable TX interrupts while flowed off
OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );
// See the comment above above positive return codes.
LeaveCriticalSection(&(pHWHead->RegCritSec));
return;
}
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Do nothing. The worst case is that this was a fluke,
// and a TX Intr will come right back at us and we will
// resume transmission.
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
// OK, now lets actually transmit some data.
EnterCriticalSection(&(pHWHead->TransmitCritSec));
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
// Enable xmit intr. We need to do this no matter what,
// since the MDD relies on one final interrupt before
// returning to the application.
OUTREG32(&pHWHead->pUartReg->USR2,CSP_BITFVAL(UART_USR2_TXDC, UART_USR2_TXDC_SET));
SL_ReadLineStatus(pHWHead);
if (pSerHead->useDMA == FALSE)
{
if (pHWHead->sUSR2 & CSP_BITFVAL(UART_USR2_TXFE, UART_USR2_TXFE_SET)) {
//always enable FIFO
byteCount = SER_FIFO_DEPTH-SER_FIFO_TXTL;
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - Write max of %d bytes to 0x%x\r\n"), byteCount, &pHWHead->pUartReg->UTXD));
// Wait until there is room in the FIFO
while(INREG32(&pHWHead->pUartReg->UTS) & CSP_BITFMASK(UART_UTS_TXFULL));
for (*pByteNumber=0; NumberOfBytes && byteCount; NumberOfBytes--, byteCount--) {
OUTREG32(&pHWHead->pUartReg->UTXD,*pSourceBuffer);
DEBUGMSG(ZONE_WRITE, (TEXT("Write x%x\r\n"), *pSourceBuffer));
//We need to discard the echo char for irda
if (pHWHead->UseIrDA)
pHWHead->ulDiscard++;
++pSourceBuffer;
(*pByteNumber)++;
}
}
INSREG32BF(&pHWHead->pUartReg->UCR4, UART_UCR4_TCEN, UART_UCR4_TCEN_ENABLE);
}
else
{
bufId = 0;
while ((NumberOfBytes > 0) && (bufId < SERIAL_MAX_DESC_COUNT_TX))
{
DDKSdmaGetBufDescStatus(pSerHead->SerialDmaChanTx, bufId, &Status);
DEBUGMSG(ZONE_FLOW, (TEXT("SL_TxIntrHandler: Status before Tx = 0x%x\r\n"), Status));
if (((Status & DDK_DMA_FLAGS_BUSY) == 0) ||
(pSerHead->dmaBufFirstUseBmp & (1 << bufId)))
{
if (pSerHead->dmaBufFirstUseBmp & (1 << bufId))
{
pSerHead->dmaBufFirstUseBmp &= ~(1 << bufId);
}
DEBUGMSG(ZONE_FLOW, (TEXT("SL_TxIntrHandler: NumberOfBytes = 0x%x\r\n"), NumberOfBytes));
if (NumberOfBytes > pSerHead->txDMABufSize)
curByteCount = pSerHead->txDMABufSize;
else
curByteCount = NumberOfBytes;
NumberOfBytes -= curByteCount;
Mode = ((bufId == (SERIAL_MAX_DESC_COUNT_TX - 1)) || (NumberOfBytes == 0))
? DDK_DMA_FLAGS_WRAP : DDK_DMA_FLAGS_CONT;
DDKSdmaClearBufDescStatus(pSerHead->SerialDmaChanTx, bufId);
DDKSdmaSetBufDesc(pSerHead->SerialDmaChanTx, bufId,
DDK_DMA_FLAGS_INTR | Mode,
pSerHead->SerialPhysTxDMABufferAddr.LowPart + bufId * pSerHead->txDMABufSize,
0, DDK_DMA_ACCESS_8BIT, (WORD)curByteCount);
pBuffer = (LPBYTE)MapCallerPtr(pSourceBuffer + *pByteNumber, curByteCount);
memcpy(pSerHead->pSerialVirtTxDMABufferAddr + bufId * pSerHead->txDMABufSize,
pBuffer, curByteCount);
*pByteNumber += curByteCount;
pSerHead->awaitingTxDMACompBmp |= (1 << bufId);
bufId++;
} // Status
}
if (*pByteNumber > 0) {
DDKSdmaStartChan(pSerHead->SerialDmaChanTx);
//RETAILMSG(1, (TEXT("Write DMA started size %d"),*pByteNumber ));
if (pHWHead->UseIrDA)
pHWHead->ulDiscard += *pByteNumber;
}
}
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler: Enable INTR_TX.\r\n")));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
DEBUGMSG(1, (TEXT("Exception caught \n")));
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
LeaveCriticalSection(&(pHWHead->TransmitCritSec));
DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler- sent %d.\r\n"), *pByteNumber));
return;
}
//-----------------------------------------------------------------------------
//
// Function: SL_ModemIntrHandler
//
// This function handles the modem interrupt. It
// collects the modem status of the serial port, and
// updates internal driver status information.
// In the new serial port upper layer implementation
// available in Microsoft Windows CE 3.0 and later,
// this function replaces the HWOtherIntrHandler
// function.
//
// Parameters:
// pContext
// [in] Pointer to device head.
//
// Returns:
// None.
//
//-----------------------------------------------------------------------------
VOID SL_ModemIntrHandler( PVOID pContext )
{
PUART_INFO pHWHead = (PUART_INFO)pContext;
DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_ModemIntrHandler+\r\n")));
SL_ReadModemStatus( pHWHead );
if (!((PSER_INFO)pContext)->cOpenCount) {
// We want to indicate a cable event.
if (!pHWHead->UseIrDA) {
if ((pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_RTSS, UART_USR1_RTSS_SET)))
if (IsAPIReady(SH_WMGR))
CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED,NULL);
}
else {
if (IsAPIReady(SH_WMGR))
CeEventHasOccurred (NOTIFICATION_EVENT_IR_DISCOVERED,NULL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -