📄 pl011pdd.c
字号:
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here, setting our return code to show a failure
fRC = FALSE;
}
fail_point:
LeaveCriticalSection(&pPDDContext->cs);
exit_point:
DEBUGMSG(ZONE_OPEN | ZONE_FUNCTION,
(TAIL_TEXT("PDD_Open() %s"), SUCCEEDED_OR_FAILED(fRC)));
return fRC;
}
ULONG PDD_Close(PDD_CONTEXT *pPDDContext)
{
BOOL fRC = FALSE;
DEBUGMSG(ZONE_CLOSE | ZONE_FUNCTION,
(HEAD_TEXT("PDD_Close(%#08x)"), pPDDContext));
if (pPDDContext == NULL)
goto exit_point;
// Check that we're not already closed
//
if (pPDDContext->nOpenCount == 0)
{
DEBUGMSG(ZONE_CLOSE | ZONE_ERROR,
(BODY_TEXT("PDD_Close: Not open")));
goto exit_point;
}
EnterCriticalSection(&pPDDContext->cs);
try
{
// Allow time for the UART transmitter to empty (one second is very generous)
//
VERIFY(PL011WaitTxEmpty(pPDDContext->pPL011, 1000));
// Deactivate modem control lines
//
PDD_ClearDTR(pPDDContext);
PDD_ClearRTS(pPDDContext);
// Power-down PL011
//
DEBUGMSG(ZONE_CLOSE,
(BODY_TEXT("PDD_Close: Powering down PL011")));
pPDDContext->fIRMode = FALSE;
VERIFY(PL011SetOutputMode(pPDDContext->pPL011, FALSE, FALSE));
VERIFY(PL011DisableAllInterrupts(pPDDContext->pPL011));
VERIFY(PL011ClearPendingInterrupts(pPDDContext->pPL011));
// Decrement the open count
//
pPDDContext->nOpenCount--;
DEBUGMSG(ZONE_CLOSE,
(BODY_TEXT("PDD_Close: Open count = %u"), pPDDContext->nOpenCount));
if (pPDDContext->DMA_Enable)
DMA_Close(&(pPDDContext->uart_DMA_Info));
// Although the return value isn't used by the MDD, we're still interested in failure. If we
// get this far, we'll call it a success.
//
fRC = TRUE;
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
fRC = FALSE;
}
LeaveCriticalSection(&pPDDContext->cs);
exit_point:
DEBUGMSG(ZONE_CLOSE | ZONE_FUNCTION,
(TAIL_TEXT("PDD_Close() %s"), SUCCEEDED_OR_FAILED(fRC)));
// As per other BSP serial drivers the return value is 0
return 0;
}
INTERRUPT_TYPE PDD_GetIntrType(PDD_CONTEXT *pPDDContext)
{
INTERRUPT_TYPE fInterruptType = INTR_NONE;
ULONG fInterrupts = 0;
DEBUGMSG(ZONE_THREAD | ZONE_FUNCTION,
(HEAD_TEXT("PDD_GetIntrType(%#08x)"), pPDDContext));
if (pPDDContext == NULL)
goto exit_point;
VERIFY(PL011GetInterrupts(pPDDContext->pPL011, &fInterrupts));
// Set the appropriate flags, according to the interrupts (the 16550 library, and all samples
// based on it return individual flags instead of combining them).
if ((fInterrupts & (PL011_INT_OE | PL011_INT_BE | PL011_INT_PE | PL011_INT_FE)) != 0)
fInterruptType |= INTR_LINE;
if ((fInterrupts & (PL011_INT_RT | PL011_INT_RX)) != 0)
{
//Rx time out, so disable DMA in RxIntHandler
if((fInterrupts & PL011_INT_RT)!=0) pPDDContext->No_DMA_timeout=TRUE;
fInterruptType |= INTR_RX;
}
if ((fInterrupts & (PL011_INT_TX)) != 0)
fInterruptType |= INTR_TX;
/*
if ((fInterrupts & (PL011_INT_DSR | PL011_INT_DCD | PL011_INT_CTS | PL011_INT_RI)) != 0)
fInterruptType |= INTR_MODEM;
*/
// Fake a transmit interrupt, if required (when ending flowed-off state, for example)
//
if (InterlockedExchange(&pPDDContext->fAddTxIntr, FALSE) == TRUE)
fInterruptType |= INTR_TX;
// Save the current interrupt flags for use by the Rx, Tx, Line and Modem interrupt handlers
//
pPDDContext->fInterrupts = fInterrupts;
exit_point:
DEBUGMSG(ZONE_THREAD | ZONE_FUNCTION,
(TAIL_TEXT("PDD_GetIntrType() %#08x"), fInterruptType));
return fInterruptType;
}
ULONG PDD_RxIntrHandler(PDD_CONTEXT *pPDDContext, PUCHAR pRxBuffer, ULONG *pBuffLen)
{
ULONG nDroppedBytes = 0;
ULONG cbTargetRoom;
BOOL fRXFlag;
BOOL fRXReady;
UCHAR bRXChar;
ULONG fRXStatus;
BOOL fDsrSensitivity;
BOOL fNull;
BOOL fErrorChar;
BOOL fParity;
BOOL fReplaceParityErrors;
UCHAR bEvtChar;
DEBUGMSG(ZONE_READ | ZONE_FUNCTION,
(HEAD_TEXT("PDD_RxIntrHandler(%#08x, %#08x, %#08x)"), pPDDContext, pRxBuffer, pBuffLen));
if ((pPDDContext == NULL) || (pRxBuffer == NULL) || (pBuffLen == NULL))
goto exit_point;
cbTargetRoom = *pBuffLen;
DEBUGCHK(cbTargetRoom != 0);
// Initialise count of received bytes [out] parameter (as early as possible)
//
*pBuffLen = 0;
fRXFlag = FALSE;
fRXReady = FALSE;
fDsrSensitivity = pPDDContext->dcb.fDsrSensitivity;
fNull = pPDDContext->dcb.fNull;
fErrorChar = pPDDContext->dcb.fErrorChar;
fParity = pPDDContext->dcb.fParity;
fReplaceParityErrors = (fParity && fErrorChar);
bEvtChar = pPDDContext->dcb.EvtChar;
//UART DMA - PDD_RxIntrHandler
if (pPDDContext->DMA_Enable && !fDsrSensitivity && !fNull &&
!fReplaceParityErrors && pPDDContext->No_DMA_timeout!=TRUE
&& cbTargetRoom >= UART_FIFO_Rx_LEVEL){
PUART_DMA_INFO pUDma = (PUART_DMA_INFO)(&(pPDDContext->uart_DMA_Info));
INITIALIZE_DMA_PARAMS InitializeDMAParams;
INITIALIZE_DMA_RESULT InitializeDMAResult;
START_DMA_PARAMS StartDMAParams;
START_DMA_RESULT StartDMAResult;
PUCHAR pvDestBuffer = pUDma->pvRxDestBuffer;
DWORD dwRet, Dest;
//UART Rx Channel Init.
InitializeDMAParams.ucChannelNumber = pUDma->ucRxDMAChannel;
InitializeDMAParams.ucSourceWidth = TRANSFER_WIDTH_BYTE; //UART Rx - 8 bits
InitializeDMAParams.ucDestWidth = TRANSFER_WIDTH_DWORD; //Mem - DWORD
InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_4;
InitializeDMAParams.ucDestBurstSize = BURST_SIZE_1;
//Per->Mem, DMA as flow controller
InitializeDMAParams.ucFlowControl = FLOW_PER_MEM_DMAC;
InitializeDMAParams.fIncrementSource = FALSE; //UART - constant
InitializeDMAParams.fIncrementDest = TRUE; //Mem - auto increment
if(!KernelIoControl(IOCTL_HAL_INITIALIZE_DMA_CHANNEL,
&InitializeDMAParams, sizeof(InitializeDMAParams),
&InitializeDMAResult, sizeof(InitializeDMAResult), &dwRet))
{
DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR,
(TEXT("PDD: Error - Rx, Cannot initialize DMA channel\r\n")));
*pBuffLen = 0;
return 0;
}
// It is certain that at least UART_FIFO_Rx_LEVEL bytes are in the Rx FIFO at this point
*pBuffLen = UART_FIFO_Rx_LEVEL;
// because we need to use DMA API.
pUDma->pdwRxDestPageList = (PDWORD)malloc(sizeof(DWORD));
if (pUDma->pdwRxDestPageList == NULL){
DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot allocate for pdwRxDestPageList\r\n")));
*pBuffLen = 0;
return 0;
}
// Lock the virtual pages to find the physical addresses
if(!LockPages(pvDestBuffer, PAGE_SIZE, pUDma->pdwRxDestPageList, LOCKFLAG_WRITE))
{
DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot lock pages\r\n")));
free(pUDma->pdwRxDestPageList);
*pBuffLen = 0;
return 0;
}
// Just double check page alignment
pUDma->pdwRxDestPageList[0] &= ~(DWORD)(PAGE_SIZE - 1);
pUDma->dwRxDestSize = *pBuffLen;
StartDMAParams.ucChannelNumber = pUDma->ucRxDMAChannel;
if(pPDDContext->ComId)
Dest = (DWORD)PHYS_UART1_BASE; // UART1 Physical address
else
Dest = (DWORD)PHYS_UART0_BASE; // UART0 Physical address
StartDMAParams.pdwSourceBuffer = &Dest;
StartDMAParams.pdwDestBuffer = pUDma->pdwRxDestPageList;
StartDMAParams.dwTransferSize = *pBuffLen;
if(!KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
&StartDMAParams, sizeof(StartDMAParams),
&StartDMAResult, sizeof(StartDMAResult), &dwRet))
{
DEBUGMSG (ZONE_ERROR,
(TEXT("PDD: Error - Cannot start DMA transfer\r\n")));
// Unlock the virtual pages so that they can be paged out
UnlockPages(pvDestBuffer, PAGE_SIZE);
free(pUDma->pdwRxDestPageList);
*pBuffLen = 0;
return 0;
}
dwRet=WaitForSingleObject(pUDma->hRxUDmaISTEvent, INFINITE);
UnlockPages(pvDestBuffer, PAGE_SIZE);
free(pUDma->pdwRxDestPageList);
InterruptDone(pUDma->dwRxDMASysIntr);
memcpy(pRxBuffer, pvDestBuffer, *pBuffLen);
}
//End of UART DMA - PDD_RxIntrHandler
else{
// Whilst there is free room in the supplied destination buffer, if there is a byte to read, we
// read it. If DSR is asserted, and we are configured to discard received data when DSR is
// asserted, then we discard the received byte. If the byte is NUL and we are configured to
// discard NUL bytes, then we discard it. If there was a parity error receiving the byte and
// we are configured to replace erroneous data with a specified 'error' character, then we do
// so. If we are configured to generate an event when we receive a specified character and the
// received byte is that character, then we generate the appropriate event. Otherwise, the
// received byte should be added to the supplied buffer and the count of received bytes should
// be incremented. We repeat this until either there is no more data to read, or there is no
// more room in the supplied destination buffer to add received data to.
//
while (cbTargetRoom != 0)
{
VERIFY(PL011ReadReceivedData(pPDDContext->pPL011, &fRXReady, &bRXChar, &fRXStatus));
if (!fRXReady)
break;
if (fDsrSensitivity && ((pPDDContext->fModemStatus & MS_DSR_ON) == 0))
{
DEBUGMSG(ZONE_FLOW | ZONE_WARN,
(BODY_TEXT("PDD_RxIntrHandler: Discarding byte [DCB.fDsrSensitivity]")));
}
else if (fNull && (bRXChar == 0))
{
DEBUGMSG(ZONE_WARN,
(BODY_TEXT("PDD_RxIntrHandler: Discarding NULL byte [DCB.fNull]")));
}
else
{
if (fReplaceParityErrors && ((fRXStatus & PL011_RSR_PE) != 0))
{
DEBUGMSG(ZONE_WARN,
(BODY_TEXT("PDD_RxIntrHandler: Replacing erroneous byte [DCB.ErrorChar]")));
bRXChar = pPDDContext->dcb.ErrorChar;
}
else
{
if (bRXChar == bEvtChar)
{
DEBUGMSG(ZONE_EVENTS,
(BODY_TEXT("PDD_RxIntrHandler: Received event character [DCB.EvtChar]")));
fRXFlag = TRUE;
}
}
*pRxBuffer++ = bRXChar; // Save the received byte and advance the destination pointer
(*pBuffLen)++; // Increment the count of received bytes [out] parameter
cbTargetRoom--; // Now we have one byte less free space in the destination buffer
}
}
if (fRXFlag)
EvaluateEventFlag(pPDDContext->pMDDContext, EV_RXFLAG);
nDroppedBytes = InterlockedExchange(&pPDDContext->nDroppedBytes, 0);
if(pPDDContext->No_DMA_timeout==TRUE) // did no-dma Rx read because time-out.
pPDDContext->No_DMA_timeout=FALSE; // do dma Rx read next time
// this has no effect when dma is disabled
}
exit_point:
DEBUGMSG(ZONE_READ | ZONE_FUNCTION,
(TAIL_TEXT("PDD_RxIntrHandler() %u"), nDroppedBytes));
return nDroppedBytes;
}
VOID PDD_TxIntrHandler(PDD_CONTEXT *pPDDContext, PUCHAR pTxBuffer, ULONG *pBuffLen)
{
ULONG cbInOut;
DEBUGMSG(ZONE_WRITE | ZONE_FUNCTION,
(HEAD_TEXT("PDD_TxIntrHandler(%#08x, %#08x, %#08x)"), pPDDContext, pTxBuffer, pBuffLen));
if ((pPDDContext == NULL) || (pBuffLen == NULL))
goto exit_point;
DEBUGMSG(ZONE_WRITE,
(BODY_TEXT("PDD_TxIntrHandler: Number of bytes = %u"), *pBuffLen));
// When there is no more to send, just disable the TX interrupts and return to the MDD.
//
if ((*pBuffLen == 0) || (pTxBuffer == NULL))
{
DEBUGMSG(ZONE_WRITE,
(BODY_TEXT("PDD_TxIntrHandler: Disable transmit interrupts")));
VERIFY(PL011DisableTxInterrupts(pPDDContext->pPL011));
goto exit_point;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -