📄 pl011pdd.c
字号:
// Save [in] parameter (number of bytes to send) and initialise [out] parameter (number of
// bytes actually sent)
//
cbInOut = *pBuffLen;
*pBuffLen = 0;
EnterCriticalSection(&pPDDContext->cs);
try
{
if ((pPDDContext->dcb.fOutxCtsFlow) && ((pPDDContext->fModemStatus & MS_CTS_ON) == 0))
{
// Record flowed-off state
//
pPDDContext->fCTSFlowOff = TRUE;
DEBUGMSG(ZONE_WRITE | ZONE_FLOW,
(BODY_TEXT("PDD_TxIntrHandler: Flowed-off via CTS")));
// Disable TX interrupts while flowed-off
//
VERIFY(PL011DisableTxInterrupts(pPDDContext->pPL011));
LeaveCriticalSection(&pPDDContext->cs);
return;
}
if ((pPDDContext->dcb.fOutxDsrFlow) && ((pPDDContext->fModemStatus & MS_DSR_ON) == 0))
{
// Record flowed-off state
//
pPDDContext->fDSRFlowOff = TRUE;
DEBUGMSG(ZONE_WRITE | ZONE_FLOW,
(BODY_TEXT("PDD_TxIntrHandler: Flowed-off via DSR")));
// Disable TX interrupts while flowed-off
//
VERIFY(PL011DisableTxInterrupts(pPDDContext->pPL011));
LeaveCriticalSection(&pPDDContext->cs);
return;
}
// If we get this far, then we're not flowed off, and the transmitter is running, so we can
// clear the 'transmitter full' error flag (the MDD is in a better position to control this
// flag than we are... but it doesn't).
//
pPDDContext->fCommErrors &= ~CE_TXFULL;
}
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(&pPDDContext->cs);
return;
}
LeaveCriticalSection(&pPDDContext->cs);
// Signal XmitComChar() that the transmitter is ready (not full and not flowed-off).
//
PulseEvent(pPDDContext->hevTxReady);
//UART DMA - PDD_TxIntrHandler
if (pPDDContext->DMA_Enable && cbInOut >= sizeof(DWORD))
{
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;
PVOID pvSourceBuffer = pUDma->pvTxSourceBuffer;
DWORD dwRet, Source;
//UART Tx Channel Init.
InitializeDMAParams.ucChannelNumber = pUDma->ucTxDMAChannel;
InitializeDMAParams.ucSourceWidth = TRANSFER_WIDTH_DWORD; // Mem - DWORD
InitializeDMAParams.ucDestWidth = TRANSFER_WIDTH_BYTE; // UART Tx 8 bit
InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_1;
InitializeDMAParams.ucDestBurstSize = BURST_SIZE_4;
//Mem->Per, DMA as flow controller
InitializeDMAParams.ucFlowControl = FLOW_MEM_PER_DMAC;
// Increment source and keep destination constant
InitializeDMAParams.fIncrementSource = TRUE;
InitializeDMAParams.fIncrementDest = FALSE;
if(!KernelIoControl(IOCTL_HAL_INITIALIZE_DMA_CHANNEL,
&InitializeDMAParams, sizeof(InitializeDMAParams),
&InitializeDMAResult, sizeof(InitializeDMAResult), &dwRet))
{
DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR,
(TEXT("PDD: Tx, Error - Cannot initialize DMA channel\r\n")));
*pBuffLen = 0;
return;
}
//Only transfer DWORD aligned size
*pBuffLen = (cbInOut >> 2) << 2;
//transfer maximum PAGE_SIZE data in one go
*pBuffLen = MIN((DWORD)PAGE_SIZE, *pBuffLen);
//we need to use DMA API
pUDma->pdwTxSourcePageList = (PDWORD)malloc(sizeof(DWORD));
if (pUDma->pdwTxSourcePageList == NULL){
DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot allocate for pdwTxSourcePageList\r\n")));
*pBuffLen = 0;
return;
}
// give the data in MDD buffer to the DMA buffer
memcpy(pvSourceBuffer, pTxBuffer, *pBuffLen);
if(!LockPages(pvSourceBuffer, PAGE_SIZE, pUDma->pdwTxSourcePageList, LOCKFLAG_WRITE))
{
DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot lock pages\r\n")));
free(pUDma->pdwTxSourcePageList);
*pBuffLen = 0;
return;
}
// Just double check page alignment
pUDma->pdwTxSourcePageList[0] &= ~(DWORD)(PAGE_SIZE - 1);
pUDma->dwTxSourceSize = *pBuffLen;
StartDMAParams.ucChannelNumber = pUDma->ucTxDMAChannel;
if(pPDDContext->ComId)
Source = (DWORD)PHYS_UART1_BASE; // UART1 Physical address
else
Source = (DWORD)PHYS_UART0_BASE; // UART0 Physical address
StartDMAParams.pdwDestBuffer = &Source;
StartDMAParams.pdwSourceBuffer = pUDma->pdwTxSourcePageList;
StartDMAParams.dwTransferSize = *pBuffLen;
if(!KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
&StartDMAParams, sizeof(StartDMAParams),
&StartDMAResult, sizeof(StartDMAResult), &dwRet))
{
DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR,
(TEXT("PDD: Error - Cannot start DMA transfer\r\n")));
// Unlock the virtual pages so that they can be paged out
UnlockPages(pvSourceBuffer, PAGE_SIZE);
free(pUDma->pdwTxSourcePageList);
*pBuffLen = 0;
return;
}
dwRet = WaitForSingleObject(pUDma->hTxUDmaISTEvent, INFINITE);
UnlockPages(pvSourceBuffer, PAGE_SIZE);
free(pUDma->pdwTxSourcePageList);
InterruptDone(pUDma->dwTxDMASysIntr);
}
// End of UART DMA - PDD_TxIntrHandler
else
{
// We're not flowed-off so let's send as many bytes as possible, from the supplied buffer
//
VERIFY(PL011SendBytes(pPDDContext->pPL011, pTxBuffer, &cbInOut));
DEBUGMSG(ZONE_WRITE | ZONE_THREAD,
(BODY_TEXT("PDD_TxIntrHandler: Sent %u bytes"), cbInOut));
*pBuffLen = cbInOut;
}
// Enable transmit interrupts. We need to do this no matter what, since the MDD relies on one
// final interrupt before returning to the application.
//
VERIFY(PL011EnableTxInterrupts(pPDDContext->pPL011));
DEBUGMSG(ZONE_WRITE,
(BODY_TEXT("PDD_TxIntrHandler: Transmit interrupts enabled")));
exit_point:
DEBUGMSG(ZONE_WRITE | ZONE_FUNCTION,
(TAIL_TEXT("PDD_TxIntrHandler()")));
}
VOID PDD_ModemIntrHandler(PDD_CONTEXT *pPDDContext)
{
ULONG fModemInterrupts;
ULONG fModemEvents;
DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
(HEAD_TEXT("PDD_ModemIntrHandler(%#08x)"), pPDDContext));
if (pPDDContext == NULL)
goto exit_point;
// First, see if there were changes in the modem lines, then notify the MDD of these events
//
fModemInterrupts = pPDDContext->fInterrupts & (PL011_INT_DSR |
PL011_INT_DCD |
PL011_INT_CTS |
PL011_INT_RI);
if (fModemInterrupts == 0)
goto exit_point;
fModemEvents = 0;
if (fModemInterrupts & PL011_INT_DSR )
fModemEvents |= EV_DSR;
if (fModemInterrupts & PL011_INT_DCD )
fModemEvents |= EV_RLSD;
if (fModemInterrupts & PL011_INT_CTS)
fModemEvents |= EV_CTS;
if (fModemInterrupts & PL011_INT_RI )
fModemEvents |= EV_RING;
// Pass any events to the callback in the MDD
//
EvaluateEventFlag(pPDDContext->pMDDContext, fModemEvents);
// Now update the modem status flags stored in the PDD context
//
VERIFY(PL011GetModemStatus(pPDDContext->pPL011, &pPDDContext->fModemStatus));
EnterCriticalSection(&pPDDContext->cs);
try
{
if (pPDDContext->fDSRFlowOff && ((pPDDContext->fModemStatus & MS_DSR_ON) != 0))
{
// Record end of flowed-off state
//
pPDDContext->fDSRFlowOff = FALSE;
DEBUGMSG(ZONE_FLOW,
(BODY_TEXT("PDD_ModemIntrHandler: Flowed-on via DSR")));
// Re-enable TX interrupts now no longer flowed-off, then simulate a TX interrupt to get
// things moving
//
VERIFY(PL011EnableTxInterrupts(pPDDContext->pPL011));
pPDDContext->fAddTxIntr = TRUE;
}
if (pPDDContext->fCTSFlowOff && ((pPDDContext->fModemStatus & MS_CTS_ON) != 0))
{
// Record end of flowed-off state
//
pPDDContext->fCTSFlowOff = FALSE;
DEBUGMSG(ZONE_FLOW,
(BODY_TEXT("PDD_ModemIntrHandler: Flowed-on via CTS")));
// Re-enable TX interrupts now no longer flowed-off, then simulate a TX interrupt to get
// things moving
//
VERIFY(PL011EnableTxInterrupts(pPDDContext->pPL011));
pPDDContext->fAddTxIntr = TRUE;
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Do nothing
}
LeaveCriticalSection(&pPDDContext->cs);
exit_point:
DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
(TAIL_TEXT("PDD_ModemIntrHandler()")));
}
VOID PDD_LineIntrHandler(PDD_CONTEXT *pPDDContext)
{
ULONG fLineInterrupts;
ULONG fLineStatus;
DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
(HEAD_TEXT("PDD_LineIntrHandler(%#08x)"), pPDDContext));
if (pPDDContext == NULL)
goto exit_point;
fLineInterrupts = pPDDContext->fInterrupts & (PL011_INT_OE |
PL011_INT_BE |
PL011_INT_PE |
PL011_INT_FE);
if (fLineInterrupts == 0)
goto exit_point;
fLineStatus = 0;
if ((fLineInterrupts & PL011_INT_OE) != 0)
fLineStatus |= PL011_RSR_OE;
if ((fLineInterrupts & PL011_INT_BE) != 0)
fLineStatus |= PL011_RSR_BE;
if ((fLineInterrupts & PL011_INT_PE) != 0)
fLineStatus |= PL011_RSR_PE;
if ((fLineInterrupts & PL011_INT_FE) != 0)
fLineStatus |= PL011_RSR_FE;
VERIFY(ProcessLineStatus(pPDDContext, fLineStatus));
exit_point:
DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
(TAIL_TEXT("PDD_LineIntrHandler()")));
}
ULONG PDD_GetRxBufferSize(PDD_CONTEXT *pPDDContext)
{
DEBUGMSG(ZONE_FUNCTION,
(HEAD_TEXT("PDD_GetRxBufferSize(%#08x)"), pPDDContext));
DEBUGMSG(ZONE_FUNCTION,
(TAIL_TEXT("PDD_GetRxBufferSize() 0")));
// By returning zero, we are leaving the MDD to set the size its receive buffer
//
return 0;
}
BOOL PDD_PowerOff(PDD_CONTEXT *pPDDContext)
{
if (pPDDContext == NULL)
return FALSE;
// Note: We could try and shutdown the DMA transfer from here (like the following code)
// But we are not allowed to call a system IOCTL during power down, so we will leave it
// to the kernel.
/*
if (pPDDContext->DMA_Enable)
{
PUART_DMA_INFO pUDma = &(pPDDContext->uart_DMA_Info);
if( pUDma->OpenCnt)
{
HALT_DMA_PARAMS HaltDMAParams;
HALT_DMA_RESULT HaltDMAResult;
STOP_DMA_PARAMS StopDMAParams;
STOP_DMA_RESULT StopDMAResult;
DWORD dwRet;
// First halt the channels to make sure no activity is going on or is starting
HaltDMAParams.ucChannelNumber = pUDma->ucRxDMAChannel;
if(!KernelIoControl(IOCTL_HAL_HALT_DMA_TRANSFER,
&HaltDMAParams, sizeof(HaltDMAParams),
&HaltDMAResult, sizeof(HaltDMAResult), &dwRet))
{
DEBUGMSG( ZONE_ERROR,
(TEXT("PDD_PowerOff: Error - DMA channel(Rx) halt failed\r\n")));
//return FALSE; - Carry on regardless
}
HaltDMAParams.ucChannelNumber = pUDma->ucTxDMAChannel;
if(!KernelIoControl(IOCTL_HAL_HALT_DMA_TRANSFER,
&HaltDMAParams, sizeof(HaltDMAParams),
&HaltDMAResult, sizeof(HaltDMAResult), &dwRet))
{
DEBUGMSG( ZONE_ERROR,
(TEXT("PDD_PowerOff: Error - DMA channel(Tx) halt failed\r\n")));
//return FALSE; - Carry on regardless
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -