⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdd.c.bak

📁 基于WinCE 5.0 下的MIPS 32 内核的Au1200(AMD)的UART驱动
💻 BAK
📖 第 1 页 / 共 3 页
字号:

	// 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 + -