📄 pdd.c.bak
字号:
// Initialization succeeded
ok = TRUE;
cleanUp:
if (hKey != NULL) RegCloseKey(hKey);
if (!ok && pPdd != NULL) {
HWDeinit(pPdd);
pPdd = NULL;
}
DEBUGMSG(ZONE_OPEN, (L"-au1uart::HWInit 0x%08x\n", pPdd));
return pPdd;
}
//------------------------------------------------------------------------------
//
// Function: HWPostInit
//
// Description: This function is called by the upper layer after hardware
// independent initialization is done (at end of COM_Init).
//
static BOOL HWPostInit(PVOID pContext)
{
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: HWDeinit
//
// Description: This function is called by the upper layer to de-initialize
// the hardware when a device driver is unloaded.
static BOOL HWDeinit(PVOID pContext)
{
UARTPDD *pPdd = (UARTPDD*)pContext;
DEBUGMSG(ZONE_CLOSE, (L"+au1uart::HWDeinit 0x%08x\n", pContext));
// Disable device
if (pPdd->pPortBase != NULL) {
OUT32(&pPdd->pPortBase->enable, 0);
MmUnmapIoSpace((PVOID)pPdd->pPortBase, 0x1000);
}
// Disconnect the interrupt
InterruptDisconnect(pPdd->sysIntr);
// Delete sync objects
DeleteCriticalSection(&pPdd->hwCS);
DeleteCriticalSection(&pPdd->txCS);
if (pPdd->txEvent != NULL) CloseHandle(pPdd->txEvent);
// Free driver object
free(pPdd);
DEBUGMSG(ZONE_CLOSE, (L"-au1uart::HWDeinit\n"));
return TRUE;
}
//------------------------------------------------------------------------------
static BOOL HWOpen(PVOID pContext)
{
BOOL ok = FALSE;
UARTPDD *pPdd = (UARTPDD*)pContext;
UCHAR fifoCtrl;
DEBUGMSG(ZONE_OPEN, (L"+au1uart::HWOpen 0x%x\n", pContext));
if (pPdd->open) goto cleanUp;
pPdd->commErrors = 0;
pPdd->overrunCount = 0;
pPdd->flowOffCTS = FALSE;
pPdd->flowOffDSR = FALSE;
pPdd->addTxIntr = FALSE;
pPdd->powerOff = FALSE;
pPdd->open = TRUE;
// Initialize FIFO constant
pPdd->txFifoLength = 16;
pPdd->txFifoThresh = 8;
pPdd->rxFifoLength = 16;
pPdd->rxFifoThresh = 1;
EnterCriticalSection(&pPdd->hwCS);
// Set line control register
OUT32(&pPdd->pPortBase->linectrl, 0);
SetBaudRate(pPdd, pPdd->dcb.BaudRate);
SetWordLength(pPdd, pPdd->dcb.ByteSize);
SetStopBits(pPdd, pPdd->dcb.StopBits);
SetParity(pPdd, pPdd->dcb.Parity);
// Set modem control register
OUT32(&pPdd->pPortBase->mdmctrl, 0);
// Set FIFO values & enable flags
//fifoCtrl = UART_FIFOCTRL_FE | UART_FIFOCTRL_MS | (0 << 6) | (2 << 4);
fifoCtrl = UART_FIFOCTRL_FE | (0 << 6) | (2 << 4);
// Set reset TX & RX flags
fifoCtrl |= UART_FIFOCTRL_RR | UART_FIFOCTRL_TR;
// Set fifo control register
OUT32(&pPdd->pPortBase->fifoctrl, fifoCtrl);
// Enable interrupts (no TX interrupt)
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
ReadLineStat(pPdd);
ReadModemStat(pPdd);
LeaveCriticalSection(&pPdd->hwCS);
ok = TRUE;
cleanUp:
DEBUGMSG(ZONE_OPEN, (L"-au1uart::HWOpen %s\n", ok ? L"TRUE" : L"FALSE"));
return ok;
}
//------------------------------------------------------------------------------
static ULONG HWClose(PVOID pContext)
{
ULONG rc = -1;
UARTPDD *pPdd = (UARTPDD*)pContext;
DEBUGMSG(ZONE_CLOSE, (L"+au1uart::HWClose 0x%x\n", pContext));
if (!pPdd->open) goto cleanUp;
EnterCriticalSection(&pPdd->hwCS);
// Disable all interrupts and clear modem control register
OUT32(&pPdd->pPortBase->inten, 0);
OUT32(&pPdd->pPortBase->mdmctrl, 0);
LeaveCriticalSection(&pPdd->hwCS);
pPdd->open = FALSE;
cleanUp:
DEBUGMSG(ZONE_CLOSE, (L"-au1uart::HWClose %d\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: HWGetInterruptType
//
// Description: This function is called by the upper layer whenever an
// interrupt occurs. The return code is then checked by the MDD
// to determine which of the four interrupt handling routines are
// to be called.
//
static INTERRUPT_TYPE HWGetInterruptType(PVOID pContext)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
INTERRUPT_TYPE type;
UCHAR intCause;
DEBUGMSG(ZONE_THREAD, (L"+au1uart::HWGetInterruptType 0x%x\n", pContext));
intCause = INP32(&pPdd->pPortBase->intcause);
if ((intCause & UART_INTCAUSE_IP) != 0) {
type = INTR_NONE;
} else {
switch (intCause & UART_INTCAUSE_IID) {
case UART_INTCAUSE_IID_MS:
type = INTR_MODEM;
break;
case UART_INTCAUSE_IID_TBA:
type = INTR_TX;
break;
case UART_INTCAUSE_IID_RDA:
case UART_INTCAUSE_IID_CTO:
type = INTR_RX;
break;
case UART_INTCAUSE_IID_RLS:
type = INTR_LINE;
break;
default:
type = INTR_NONE;
}
}
// Add software TX interrupt to resume send
if (pPdd->addTxIntr) {
type |= INTR_TX;
pPdd->addTxIntr = FALSE;
}
DEBUGMSG(ZONE_THREAD, (L"-au1uart::HWGetInterruptType %d %02x\n", type, intCause));
return type;
}
//------------------------------------------------------------------------------
//
// Function: HWRxIntr
//
// Description: This function gets several characters from the hardware
// receive buffer and puts them in a buffer provided via
// the second argument. It returns the number of bytes lost to
// overrun.
//
static ULONG HWRxIntr(PVOID pContext, PUCHAR pRxBuffer, ULONG *pLength)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
ULONG count = *pLength;
UCHAR lineStat, rxChar;
BOOL rxFlag, replaceParityError;
DEBUGMSG(ZONE_THREAD, (L"+au1uart::HWRxIntr 0x%x 0x%x %d\n", pContext, pRxBuffer, *pLength));
*pLength = 0;
rxFlag = FALSE;
replaceParityError = (pPdd->dcb.fErrorChar != '\0') && pPdd->dcb.fParity;
while (count > 0) {
// Get line status register
lineStat = ReadLineStat(pPdd);
// If there isn't more chars exit loop
if ((lineStat & UART_LINESTAT_DR) == 0) break;
// Get received char
rxChar = INP32(&pPdd->pPortBase->rxdata);
// Ignore char in DSR is low and we care about it
if (
pPdd->dcb.fDsrSensitivity &&
(ReadModemStat(pPdd) & UART_MDMSTAT_DS) == 0
) continue;
// Ignore NUL char if requested
if (rxChar == '\0' && pPdd->dcb.fNull) continue;
// Replace char with parity error
if (replaceParityError && (lineStat & UART_LINESTAT_PE) != 0) {
rxChar = pPdd->dcb.ErrorChar;
}
// See if we need to generate an EV_RXFLAG
if (rxChar == pPdd->dcb.EvtChar) rxFlag = TRUE;
// Store it to buffer
*pRxBuffer++ = rxChar;
(*pLength)++;
count--;
}
// Send event to MDD
if (rxFlag) EvaluateEventFlag(pPdd->pMdd, EV_RXFLAG);
// Clear overrun counter and use this value as return code
count = pPdd->overrunCount;
pPdd->overrunCount = 0;
// So we are done
DEBUGMSG(ZONE_THREAD, (L"-au1uart::HWRxIntr %d (%d)\n", count, *pLength));
return count;
}
//------------------------------------------------------------------------------
//
// Function: HWTxIntr
//
// Description: This function is called from the MDD whenever INTR_TX is
// returned by HWGetInterruptType which indicate empty place in
// transmitter FIFO.
//
static VOID HWTxIntr(PVOID pContext, PUCHAR pTxBuffer, ULONG *pLength)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
ULONG count;
UCHAR lineStat, modemStat;
DEBUGMSG(ZONE_THREAD, (L"+au1uart::HWTxIntr 0x%x 0x%x %d\n", pContext, pTxBuffer, *pLength));
EnterCriticalSection(&pPdd->hwCS);
// There can be nothing to send - then disable TX interrupt
if (*pLength == 0) {
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
LeaveCriticalSection(&pPdd->hwCS);
goto cleanUp;
}
// Set event to fire HWXmitComChar
PulseEvent(pPdd->txEvent);
// If CTS flow control is desired, check it. 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 (pPdd->dcb.fOutxCtsFlow) {
modemStat = ReadModemStat(pPdd);
if ((modemStat & UART_MDMSTAT_CT) == 0) {
// Set flag
pPdd->flowOffCTS = TRUE;
// Disable TX interrupt
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
LeaveCriticalSection(&pPdd->hwCS);
*pLength = 0;
goto cleanUp;
}
}
// Same thing applies for DSR
if (pPdd->dcb.fOutxDsrFlow) {
modemStat = ReadModemStat(pPdd);
if ((modemStat & UART_MDMSTAT_DS) == 0) {
// Set flag
pPdd->flowOffDSR = TRUE;
// Disable TX interrupt
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_OFF);
LeaveCriticalSection(&pPdd->hwCS);
*pLength = 0;
goto cleanUp;
}
}
LeaveCriticalSection(&pPdd->hwCS);
// Give chance to HWXmitComChar there
EnterCriticalSection(&pPdd->hwCS);
// Read line status
lineStat = ReadLineStat(pPdd);
if ((lineStat&UART_LINESTAT_TE) != 0) {
count = pPdd->txFifoLength;
} else if ((lineStat&UART_LINESTAT_TT) != 0) {
count = pPdd->txFifoLength - pPdd->txFifoThresh;
} else {
count = 0;
}
// We can't send more data then avaiable
if (count > *pLength) count = *pLength;
// Ok, so send data
*pLength = 0;
while (count > 0) {
OUT32(&pPdd->pPortBase->txdata, *pTxBuffer++);
(*pLength)++;
count--;
}
// Enable TX interrupt
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
LeaveCriticalSection(&pPdd->hwCS);
cleanUp:
DEBUGMSG(ZONE_THREAD, (L"-au1uart::HWTxIntr (%d)\n", *pLength));
}
//------------------------------------------------------------------------------
//
// Function: HWModemIntr
//
// Description: This function is called from the MDD whenever INTR_MODEM is
// returned by HWGetInterruptType which indicate change in
// modem registry.
//
static VOID HWModemIntr(PVOID pContext)
{
UARTPDD *pPdd = (UARTPDD*)pContext;
UCHAR modemStat;
DEBUGMSG(ZONE_THREAD, (L"+au1uart::HWModemIntr 0x%x\n", pContext));
// Get actual modem status
modemStat = ReadModemStat(pPdd);
// If we are currently flowed off via CTS or DSR, then
// we better signal the TX thread when one of them changes
// so that TX can resume sending.
EnterCriticalSection(&pPdd->hwCS);
if (pPdd->flowOffDSR && (modemStat & UART_MDMSTAT_DS) != 0) {
// Clear flag
pPdd->flowOffDSR = FALSE;
// DSR is set, so go ahead and resume sending
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
// Then simulate a TX intr to get things moving
pPdd->addTxIntr = TRUE;
}
if (pPdd->flowOffCTS && (modemStat & UART_MDMSTAT_CT) != 0) {
pPdd->flowOffCTS = FALSE;
// CTS is set, so go ahead and resume sending
OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
// Then simulate a TX intr to get things moving
pPdd->addTxIntr = TRUE;
}
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_THREAD, (L"-au1uart::HWModemIntr\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWLineIntr
//
// Description: This function is called from the MDD whenever INTR_LINE is
// returned by HWGetInterruptType which indicate change in
// line status registry.
//
static VOID HWLineIntr(PVOID pContext)
{
UARTPDD *pPdd = (UARTPDD *)pContext;
UCHAR fifoCtrl;
DEBUGMSG(ZONE_THREAD, (L"+au1uart::HWLineIntr 0x%x\n", pContext));
ReadLineStat(pPdd);
EnterCriticalSection(&pPdd->hwCS);
// Reset receiver
fifoCtrl = INP32(&pPdd->pPortBase->fifoctrl);
OUT32(&pPdd->pPortBase->fifoctrl, fifoCtrl|UART_FIFOCTRL_RR);
// Read all character in fifo
while (ReadLineStat(pPdd) & UART_LINESTAT_DR) {
INP32(&pPdd->pPortBase->rxdata);
}
LeaveCriticalSection(&pPdd->hwCS);
DEBUGMSG(ZONE_THREAD, (L"-au1uart::HWLineIntr\n"));
}
//------------------------------------------------------------------------------
//
// Function: HWGetRxBufferSize
//
// Description: This function returns the size of the hardware buffer passed
// to the interrupt initialize function. It would be used only
// for devices which share a buffer between the MDD/PDD and
// an ISR. It always returns 0 for 16550 type UARTS.
//
static ULONG HWGetRxBufferSize(PVOID pContext)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -