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

📄 pdd.c

📁 基于AU1200的CPLD的wince下的驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	UARTPDD *pPdd = (UARTPDD *)pContext;
	INTERRUPT_TYPE type;
	UCHAR intCause;

	DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWGetInterruptType 0x%x\r\n", pContext));

	//intCause = INP32(&pPdd->pPortBase->intcause);
	////intCause = INP32(&pPdd->pPortBase->uartStatus);
	intCause = (pPdd->pPortBase->uartStatus & (RX_STATUS_BIT | TX_STATUS_BIT));
	#if 0
	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;
		}
	}
	#endif
	if( !(intCause & RX_STATUS_BIT) ) {
        type = INTR_RX;
	}
	//else if( !(intCause & TX_STATUS_BIT) ) {
	//else if( (intCause & TX_STATUS_BIT)) {
	else if( (intCause & TX_STATUS_BIT) && bTxIntEn) {
        type = INTR_TX;
	}
	else {
        type = INTR_NONE;
	}

	// Add software TX interrupt to resume send
	if (pPdd->addTxIntr) {
		type |= INTR_TX;
		pPdd->addTxIntr = FALSE;
	}

	DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWGetInterruptType %d %02x %02x\r\n", type, intCause, pPdd->pPortBase->uartIntEnable ));

	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"+cplduart::HWRxIntr 0x%x 0x%x %d\r\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;
		if (lineStat & RX_STATUS_BIT){
			//DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWRxIntr over ch %c\r\n", pPdd->pPortBase->uartRxData));
			break;  // there is no data in fifo, exit while loop
		}

		// Get received char
		////rxChar = INP32(&pPdd->pPortBase->rxdata);
		rxChar = pPdd->pPortBase->uartRxData;
		//while( !(pPdd->pPortBase->uartStatus & 0x01) );  // if send fifo is empty
        //pPdd->pPortBase->uartTxData = rxChar;
		//DEBUGMSG(ZONE_THREAD, (L"%c\r\n",rxChar));   // 通过Au1200自带的com debug这个驱动

		// 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"-cplduart::HWRxIntr %d (%d)\r\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"+cplduart::HWTxIntr 0x%x 0x%x %d\r\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);
		////DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWTxIntr TX_OFF\r\n")); 
		////pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_OFF; 
		DISABLE_TX_INT(pPdd->pPortBase);
		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);
			////pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_OFF; 
			DISABLE_TX_INT(pPdd->pPortBase);
			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);
			////pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_OFF; 
			DISABLE_TX_INT(pPdd->pPortBase);
			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) {
	if ((lineStat&TX_STATUS_BIT)) {
		////count = pPdd->txFifoLength;
		count = 15;                    // cpld serial fifo is 16 depth,但不能一次写满,一定要留一个空字节
	////} 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) {
		while(!(ReadLineStat(pPdd) & TX_STATUS_BIT));
		////OUT32(&pPdd->pPortBase->txdata, *pTxBuffer++);
		pPdd->pPortBase->uartTxData = *pTxBuffer++;
		(*pLength)++;
		count--;
	}

	// Enable TX interrupt
	////OUT32(&pPdd->pPortBase->inten, UART_INTEN_TX_ON);
	pPdd->pPortBase->uartIntEnable = UART_INTEN_TX_ON; 
	ENABLE_TX_INT(pPdd->pPortBase);

	LeaveCriticalSection(&pPdd->hwCS);

cleanUp:
	DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWTxIntr (%d)\r\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)
{
#if 0
	UARTPDD *pPdd = (UARTPDD*)pContext;
	UCHAR modemStat;

	DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWModemIntr 0x%x\r\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);
#endif	
	DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWModemIntr\r\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)
{
#if 0
	UARTPDD *pPdd = (UARTPDD *)pContext;
	UCHAR fifoCtrl;

	DEBUGMSG(ZONE_THREAD, (L"+cplduart::HWLineIntr 0x%x\r\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);
#endif
	DEBUGMSG(ZONE_THREAD, (L"-cplduart::HWLineIntr\r\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)
{
	return 0;
}

//------------------------------------------------------------------------------

static BOOL HWPowerOff(PVOID pContext)
{

	UARTPDD *pPdd = (UARTPDD *)pContext;
#if 0
	// Save registers to be able power on
	pPdd->fifoCtrl = INP32(&pPdd->pPortBase->fifoctrl);
	pPdd->lineCtrl = INP32(&pPdd->pPortBase->linectrl);
	pPdd->mdmCtrl  = INP32(&pPdd->pPortBase->mdmctrl);
	pPdd->clkDiv   = INP32(&pPdd->pPortBase->clkdiv);

	// Disable device and clock
	OUT32(&pPdd->pPortBase->enable, 0);
#endif
	// Set flag
	pPdd->powerOff = TRUE;

	// We are done 
	return TRUE;
}

//------------------------------------------------------------------------------

static BOOL HWPowerOn(PVOID pContext)
{

	UARTPDD *pPdd = (UARTPDD *)pContext;

	// Do power-on only if there was power-off
	if (pPdd->powerOff) {
#if 0
		// Allow device clock
		OUT32(&pPdd->pPortBase->enable, UART_ENABLE_CE);

		// Then device itself
		OUT32(&pPdd->pPortBase->enable, UART_ENABLE_CE|UART_ENABLE_E);

		// Restore any registers that we need
		OUT32(&pPdd->pPortBase->fifoctrl, pPdd->fifoCtrl);
		OUT32(&pPdd->pPortBase->linectrl, pPdd->lineCtrl);
		OUT32(&pPdd->pPortBase->mdmctrl,  pPdd->mdmCtrl);
		OUT32(&pPdd->pPortBase->clkdiv,   pPdd->clkDiv);
#endif
		// Reset flag   
		pPdd->powerOff = FALSE;
	}
	
	return TRUE;
}

//------------------------------------------------------------------------------
//
// Function:     HWClearDTR
//
// Description:  This function clears DTR.
//

static VOID HWClearDTR(PVOID pContext)
{
#if 0
	UARTPDD *pPdd = (UARTPDD*)pContext;
	UCHAR mdmCtrl;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -