📄 pl011pdd.c
字号:
pPDDContext->CommProp.dwServiceMask = SP_SERIALCOMM;
pPDDContext->CommProp.dwReserved1 = 0;
pPDDContext->CommProp.dwMaxTxQueue = 16;
pPDDContext->CommProp.dwMaxRxQueue = 16;
pPDDContext->CommProp.dwMaxBaud = BAUD_USER;
pPDDContext->CommProp.dwProvSubType = PST_RS232;
pPDDContext->CommProp.dwProvCapabilities = PCF_DTRDSR |
PCF_INTTIMEOUTS |
PCF_PARITY_CHECK |
PCF_RLSD |
PCF_RTSCTS |
PCF_SETXCHAR |
PCF_SPECIALCHARS |
PCF_TOTALTIMEOUTS |
PCF_XONXOFF;
pPDDContext->CommProp.dwSettableParams = SP_BAUD |
SP_DATABITS |
SP_HANDSHAKING |
SP_PARITY |
SP_PARITY_CHECK |
SP_RLSD |
SP_STOPBITS;
pPDDContext->CommProp.dwSettableBaud = BAUD_075 | BAUD_110 | BAUD_150 | BAUD_300 |
BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 |
BAUD_4800 | BAUD_7200 | BAUD_9600 | BAUD_14400 |
BAUD_19200 | BAUD_38400 | BAUD_56K | BAUD_128K |
BAUD_115200 | BAUD_57600 | BAUD_USER;
pPDDContext->CommProp.wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8;
pPDDContext->CommProp.wSettableStopParity = PARITY_NONE | PARITY_EVEN | PARITY_ODD |
PARITY_MARK | PARITY_SPACE |
STOPBITS_10 | STOPBITS_20;
pPDDContext->CommProp.dwCurrentTxQueue = 0;
pPDDContext->CommProp.dwCurrentTxQueue = 0;
pPDDContext->CommProp.dwProvSpec1 = 0;
pPDDContext->CommProp.dwProvSpec2 = 0;
pPDDContext->CommProp.wcProvChar[0] = 0;
// We don't have to initialise the following members; the entire PDD context was initialised
// with zero by the allocation.
//
pPDDContext->dcb; // MDD will call HWSetDCB() later
pPDDContext->fCommErrors; // 0x00000000
pPDDContext->fInterrupts; // 0x00000000
pPDDContext->fModemStatus; // 0x00000000
pPDDContext->nDroppedBytes; // 0
pPDDContext->fCTSFlowOff; // FALSE (not flowed-off yet)
pPDDContext->fDSRFlowOff; // FALSE (not flowed-off yet)
pPDDContext->fAddTxIntr; // FALSE
//UART DMA Init.
if (pPDDContext->DMA_Enable){
pPDDContext->No_DMA_timeout=FALSE; //by default, use DMA for Rx
PL011DMACtrl(pPDDContext->pPL011, PL011_DMACR_TXDMAE|PL011_DMACR_RXDMAE); //Enable UART Rx & Tx DMA
}
//End of DMA Init.
// Don't allow any interrupts until PostInit
//
VERIFY(PL011DisableAllInterrupts(pPDDContext->pPL011));
// Clear any pending interrupts (following a warm-start/soft-reset, for example)
//
VERIFY(PL011ClearPendingInterrupts(pPDDContext->pPL011));
// Power-down PL011
//
DEBUGMSG(ZONE_INIT,
(BODY_TEXT("PDD_Init: Powering-down UART")));
VERIFY(PL011SetOutputMode(pPDDContext->pPL011, FALSE, FALSE));
goto exit_point;
fail_point:
// TODO: We can't use PDD_Deinit to cleanup here. The MDD will use the HW_VTBL in the HWOBJ
// that we returned from GetSerialObject to call HWDeinit; the HWOBJ and HW_VTBL will
// have to be cleaned-up last of all.
//
PDD_Deinit(pPDDContext);
pPDDContext = NULL;
exit_point:
DEBUGMSG(ZONE_INIT | ZONE_FUNCTION,
(TAIL_TEXT("PDD_Init() %s"), SUCCEEDED_OR_FAILED(pPDDContext != NULL)));
return pPDDContext;
}
BOOL PDD_PostInit(PDD_CONTEXT *pPDDContext)
{
BOOL fRC = FALSE;
DEBUGMSG(ZONE_INIT | ZONE_FUNCTION,
(HEAD_TEXT("PDD_PostInit(%#08x)"), pPDDContext));
if (pPDDContext == NULL)
goto exit_point;
// Since we are just a library which might get used for built-in ports which Init() at boot,
// or by PCMCIA ports which Init() at Open, we can't do anything too fancy. Let's just make
// sure we cancel any pending interrupts so that if we are being used with an edge triggered
// PIC, it will see an edge after the MDD hooks the interrupt.
//
VERIFY(fRC = PL011ClearPendingInterrupts(pPDDContext->pPL011));
exit_point:
DEBUGMSG(ZONE_INIT | ZONE_FUNCTION,
(TAIL_TEXT("PDD_PostInit() %s"), SUCCEEDED_OR_FAILED(fRC)));
return fRC;
}
BOOL PDD_Deinit(PDD_CONTEXT *pPDDContext)
{
DEBUGMSG(ZONE_INIT | ZONE_CLOSE | ZONE_FUNCTION,
(HEAD_TEXT("PDD_Deinit(%#08x)"), pPDDContext));
RETAILMSG( TRUE, (TEXT("PDD_Deinit ( )\r\n")) );
if (pPDDContext == NULL)
goto exit_point;
// Make sure device is closed before doing DeInit
//
if (pPDDContext->nOpenCount != 0)
PDD_Close(pPDDContext);
// Free the PL011 context
//
pPDDContext->pPL011 = PL011Delete(pPDDContext->pPL011);
DEBUGMSG((ZONE_INIT | ZONE_CLOSE | ZONE_ERROR) && (pPDDContext->pPL011 != NULL),
(BODY_TEXT("PDD_Deinit: Failed to free PL011 context")));
// Free the critical section
//
DeleteCriticalSection(&pPDDContext->cs);
// Free the Win32 event object
if ((pPDDContext->hevTxReady != NULL) && (CloseHandle(pPDDContext->hevTxReady)))
pPDDContext->hevTxReady = NULL;
DEBUGMSG((ZONE_INIT | ZONE_CLOSE | ZONE_ERROR) && (pPDDContext->hevTxReady != NULL),
(BODY_TEXT("PDD_Deinit: Failed to free Win32 event object")));
// Free the HWOBJ
//
if (pPDDContext->pHWObj != NULL)
pPDDContext->pHWObj = LocalFree(pPDDContext->pHWObj);
// Free the mapped memory
if (pPDDContext->pBaseAddress)
{
VirtualFree (pPDDContext->pBaseAddress, 0, MEM_RELEASE);
}
DEBUGMSG((ZONE_INIT | ZONE_CLOSE | ZONE_ERROR) && (pPDDContext->pHWObj != NULL),
(BODY_TEXT("PDD_Deinit: Failed to free HWOBJ")));
// Now, free the PDD context
//
pPDDContext = LocalFree(pPDDContext);
DEBUGMSG((ZONE_INIT | ZONE_CLOSE | ZONE_ERROR) && (pPDDContext != NULL),
(BODY_TEXT("PDD_Deinit: Failed to free PDD context")));
exit_point:
DEBUGMSG(ZONE_INIT | ZONE_CLOSE | ZONE_FUNCTION,
(TAIL_TEXT("PDD_Deinit() %s"), SUCCEEDED_OR_FAILED(pPDDContext == NULL)));
return (pPDDContext == NULL);
}
BOOL PDD_Open(PDD_CONTEXT *pPDDContext)
{
BOOL fRC = FALSE;
DEBUGMSG(ZONE_OPEN | ZONE_FUNCTION,
(HEAD_TEXT("PDD_Open(%#08x)"), pPDDContext));
if (pPDDContext == NULL)
goto exit_point;
// Disallow multiple, simultaneous opens
//
if (pPDDContext->nOpenCount != 0)
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(BODY_TEXT("PDD_Open: Already open")));
SetLastError(ERROR_OPEN_FAILED);
goto exit_point;
}
pPDDContext->fCommErrors = 0; // 0x00000000
pPDDContext->fInterrupts = 0; // 0x00000000
pPDDContext->fModemStatus = 0; // 0x00000000
pPDDContext->nDroppedBytes = 0; // 0
pPDDContext->fCTSFlowOff = FALSE; // FALSE (not flowed-off yet)
pPDDContext->fDSRFlowOff = FALSE; // FALSE (not flowed-off yet)
pPDDContext->fAddTxIntr = FALSE;
EnterCriticalSection(&pPDDContext->cs);
try
{
//UART DMA - PDD_Open
if (pPDDContext->DMA_Enable)
{
PUART_DMA_INFO pUDma = &(pPDDContext->uart_DMA_Info);
ALLOCATE_DMA_PARAMS AllocateDMAParams;
ALLOCATE_DMA_RESULT AllocateDMAResult;
DWORD dwRet;
++(pUDma->OpenCnt);
// Allocate some virtual space (in page alignment) so we can do DMA transfer
// between it and Rx/Tx. We can not use MDD buffer address to configure DMA because
// the buffer is allocated from heap, which we can not get physical address.
pUDma->pvRxDestBuffer = (PUCHAR)VirtualAlloc
(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE);
if(pUDma->pvRxDestBuffer == NULL)
{
RETAILMSG(1, (TEXT("Error - unable to allocate buffer\r\n")));
return FALSE;
}
pUDma->pvTxSourceBuffer = (PUCHAR)VirtualAlloc
(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE);
if(pUDma->pvTxSourceBuffer == NULL)
{
RETAILMSG(1, (TEXT("Error - unable to allocate buffer\r\n")));
return FALSE;
}
//UART Rx Channel Alloc.
if (pPDDContext->ComId)
AllocateDMAParams.ucSourceDevice = UART1_Rx_ID; // UART1 Rx
else
AllocateDMAParams.ucSourceDevice = UART0_Rx_ID; // UART0 Rx
AllocateDMAParams.ucDestDevice = 0; // Memory, so could be any value
AllocateDMAParams.ucPreferedPriority = 0xff; // no preference
if(!KernelIoControl(IOCTL_HAL_ALLOCATE_DMA_CHANNEL,
&AllocateDMAParams, sizeof(AllocateDMAParams),
&AllocateDMAResult, sizeof(AllocateDMAResult), &dwRet))
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(TEXT("PDD_Open: Error - DMA channel(Rx) allocation failed\r\n")));
// No channels available
SetLastError(ERROR_ALREADY_ASSIGNED);
DMA_Close(&(pPDDContext->uart_DMA_Info));
return FALSE;
}
// Save the channel number and interrupt id
pUDma->ucRxDMAChannel = AllocateDMAResult.ucChannelNumber;
pUDma->dwRxDMASysIntr = AllocateDMAResult.dwInterruptID;
// Create the DMA interrupt event for Rx
pUDma->hRxUDmaISTEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(pUDma->hRxUDmaISTEvent == NULL)
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(TEXT("PDD_Open: Error creating Rx DMA Interrupt event\r\n")));
DMA_Close(pUDma);
return FALSE;
}
// Enable the DMA interrupt for Rx
if(!InterruptInitialize(pUDma->dwRxDMASysIntr, pUDma->hRxUDmaISTEvent, NULL, 0))
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(TEXT("PDD_Open: Error enabling Rx DMA interrupt (%d)\r\n"),
GetLastError()));
DMA_Close(pUDma);
return FALSE;
}
// UART Tx Channel Alloc.
AllocateDMAParams.ucSourceDevice = 0; // Memory
if(pPDDContext->ComId)
AllocateDMAParams.ucDestDevice = UART1_Tx_ID; // UART1 Tx
else
AllocateDMAParams.ucDestDevice = UART0_Tx_ID; // UART0 Tx
AllocateDMAParams.ucPreferedPriority = 0xff; // no preference
if(!KernelIoControl(IOCTL_HAL_ALLOCATE_DMA_CHANNEL,
&AllocateDMAParams, sizeof(AllocateDMAParams),
&AllocateDMAResult, sizeof(AllocateDMAResult), &dwRet))
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(TEXT("PDD_Open: Error - DMA channel(Tx) allocation failed\r\n")));
// No channels available
SetLastError(ERROR_ALREADY_ASSIGNED);
DMA_Close(pUDma);
return FALSE;
}
// Save the channel number and interrupt id
pUDma->ucTxDMAChannel = AllocateDMAResult.ucChannelNumber;
pUDma->dwTxDMASysIntr = AllocateDMAResult.dwInterruptID;
// Create the DMA interrupt event for the Tx
pUDma->hTxUDmaISTEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(pUDma->hTxUDmaISTEvent == NULL)
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(TEXT("PDD_Open: Error creating Tx DMA Interrupt event\r\n")));
DMA_Close(pUDma);
return FALSE;
}
// Enable the DMA interrupt for Tx
if(!InterruptInitialize(pUDma->dwTxDMASysIntr, pUDma->hTxUDmaISTEvent, NULL, 0))
{
DEBUGMSG(ZONE_OPEN | ZONE_ERROR,
(TEXT("PDD_Open: Error enabling Tx DMA interrupt (%d)\r\n"),
GetLastError()));
DMA_Close(pUDma);
return FALSE;
}
}
//End of UART DMA - PDD_Open
// Increment the open count
//
pPDDContext->nOpenCount++;
DEBUGMSG(ZONE_OPEN,
(BODY_TEXT("PDD_Open: Open count = %u"), pPDDContext->nOpenCount));
// Set FIFO settings (enabled, Rx >= 3/4, Tx <= 1/4)
//
if (!PL011EnableFIFO(pPDDContext->pPL011, PL011_FLSEL_3_4, PL011_FLSEL_1_4))
{
fRC = FALSE;
goto fail_point;
}
// Select wired by default
//
pPDDContext->fIRMode = FALSE;
if (!PL011SetOutputMode(pPDDContext->pPL011, pPDDContext->fIRMode, !pPDDContext->fIRMode))
{
fRC = FALSE;
goto fail_point;
}
DEBUGMSG(ZONE_OPEN,
(BODY_TEXT("PDD_Open: %s"), (pPDDContext->fIRMode) ? TEXT("IR mode") :
TEXT("Non IR mode")));
// Set baud rate, data size, parity and stop bits
//
fRC = PL011SetLineFormat(pPDDContext->pPL011, pPDDContext->dcb.BaudRate,
pPDDContext->dcb.ByteSize,
pPDDContext->dcb.Parity,
pPDDContext->dcb.StopBits);
// Enable interrupts, for the first time
//
VERIFY(PL011EnableAllInterrupts(pPDDContext->pPL011));
#ifdef DEBUG
if (ZONE_OPEN)
PL011DumpRegisters(pPDDContext->pPL011);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -