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

📄 serialhw.c

📁 freescale i.mx31 BSP CE5.0全部源码
💻 C
📖 第 1 页 / 共 5 页
字号:
					}
				}
				else {
					// We read all chars, so we're done
					break;
				}
			}
		}
		else
		{
			*pByteNumber = 0;
			RetVal = 0;
			while (TargetRoom > 0)
			{
				if (pSerHead->availRxByteCount == 0)
				{
					DDKSdmaGetBufDescStatus(pSerHead->SerialDmaChanRx, pSerHead->currRxDmaBufId, &Status);

					if ((Status & DDK_DMA_FLAGS_BUSY) == 0)
					{
						pSerHead->availRxByteCount = Status & 0xFFFF;
						pSerHead->dmaRxStartIdx = 0;
					}
					else
						break;
				}

				discardCount = 0;

				if (pHWHead->UseIrDA && pHWHead->ulDiscard)
				{
					discardCount = (pHWHead->ulDiscard > pSerHead->availRxByteCount) ? pSerHead->availRxByteCount : pHWHead->ulDiscard;
					pHWHead->ulDiscard -= discardCount;
					pSerHead->dmaRxStartIdx += discardCount;
					pSerHead->availRxByteCount -= discardCount;
				}

				copyCount = (pSerHead->availRxByteCount > TargetRoom) ? TargetRoom : pSerHead->availRxByteCount;

				if (copyCount)
				{
					LPBYTE pBuffer = (LPBYTE)MapCallerPtr(pTargetBuffer + *pByteNumber, copyCount);
					memcpy(pBuffer, pSerHead->pSerialVirtRxDMABufferAddr + 
						pSerHead->currRxDmaBufId * pSerHead->rxDMABufSize + pSerHead->dmaRxStartIdx, copyCount);
					*pByteNumber += copyCount;
					TargetRoom -= copyCount;
					pSerHead->availRxByteCount -= copyCount;
					pSerHead->dmaRxStartIdx += copyCount;
				}
				
				//RETAILMSG(1, (TEXT("SL_RxIntrHandler: *pBytes: %d, TargetRoom: %d, availRxByteCount: %d, dmaRxStartIdx: %d CurBufId=%d, discardCount: %d\r\n"), *pByteNumber, TargetRoom, pSerHead->availRxByteCount, pSerHead->dmaRxStartIdx, pSerHead->currRxDmaBufId, discardCount));

				if (pSerHead->availRxByteCount == 0)
				{
					DDKSdmaClearBufDescStatus(pSerHead->SerialDmaChanRx, pSerHead->currRxDmaBufId);

					Mode = (pSerHead->currRxDmaBufId == (SERIAL_MAX_DESC_COUNT_RX - 1)) ? 
							DDK_DMA_FLAGS_WRAP : DDK_DMA_FLAGS_CONT;

					DDKSdmaSetBufDesc(pSerHead->SerialDmaChanRx, 
						  pSerHead->currRxDmaBufId, 
						  (DDK_DMA_FLAGS_INTR | Mode),
						  pSerHead->SerialPhysRxDMABufferAddr.LowPart + pSerHead->currRxDmaBufId * pSerHead->rxDMABufSize,
						  0, 
						  DDK_DMA_ACCESS_8BIT, 
						  pSerHead->rxDMABufSize);

					pSerHead->currRxDmaBufId = (pSerHead->currRxDmaBufId + 1) % SERIAL_MAX_DESC_COUNT_RX;
					
					DDKSdmaStartChan(pSerHead->SerialDmaChanRx);
				}
			}
			pHWHead->DroppedBytes = RetVal;
		}
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
        EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
    }

	if (pSerHead->useDMA == FALSE)
	{
		// if we saw one (or more) EVT chars, then generate an event
		if (fRXFlag) {
			pHWHead->EventCallback(pHWHead->pMDDContext, EV_RXFLAG);
			DEBUGMSG(ZONE_READ, (TEXT("EV_RXFLAG set\r\n")));
		}
		else {
			DEBUGMSG(ZONE_READ, (TEXT("EV_RXFLAG not set\r\n")));
		}
		if (pHWHead->DroppedBytes)
			DEBUGMSG(ZONE_READ, (TEXT("Rx drop %d.\r\n"), pHWHead->DroppedBytes));

    DEBUGMSG(ZONE_READ, (TEXT("SL_RxIntrHandler - rx'ed %d, dropped %d.\r\n"), *pByteNumber, pHWHead->DroppedBytes));


    RetVal = pHWHead->DroppedBytes;
    pHWHead->DroppedBytes = 0;

	}

    return(RetVal);
}


//-----------------------------------------------------------------------------
//
// Function: SL_TxIntrHandler
//
// This function is called when the driver 
// detects a transmit interrupt (INTR_TX), as set by 
// the SL_GetInterruptType function. It sends several 
// characters to the hardware transmission buffer.
//
// Parameters:
//      pContext 
//          [in] Pointer to device head.
//      pSourceBuffer 
//          [in] Pointer to the source buffer that contains data to be sent.
//      pByteNumber 
//          [in] When SL_TxIntrEx is called, 
//                 pByteNumber points to the maximum number of bytes 
//                 to send. When SL_TxIntrEx returns, pByteNumber 
//                 points to the actual number of bytes sent..
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------
VOID SL_TxIntrHandler( PVOID pContext, PUCHAR pSourceBuffer, ULONG *pByteNumber )
{
    PUART_INFO pHWHead = (PUART_INFO)pContext;
 	PSER_INFO pSerHead = (PSER_INFO)pContext;
    UCHAR byteCount;
    ULONG NumberOfBytes = *pByteNumber;
	// SDMA
	UINT32 Status = 0, Mode;
	UINT32 curByteCount;
	LPBYTE pBuffer;
	int bufId;

	
	DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler+\r\n")));

    DEBUGMSG(ZONE_WRITE, (TEXT("Transmit Event 0x%X, Len %d\r\n"), pContext, *pByteNumber));

    SL_ReadModemStatus(pHWHead);
    // We may be done sending.  If so, just disable the TX interrupts
    // and return to the MDD.  
    if (! *pByteNumber) {
        DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - Disable INTR_TX.\r\n")));
        OUTREG32(&pHWHead->pUartReg->USR2,CSP_BITFVAL(UART_USR2_TXDC, UART_USR2_TXDC_SET)); 
        //Disable the TX interrupts
        OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );
        return;
    }

	*pByteNumber = 0;  // In case we don't send anything below.
    
    // Disable xmit intr.  Most 16550s will keep hammering
    // us with xmit interrupts if we don't turn them off
    // Whoever gets the FlushDone will then need to turn
    // TX Ints back on if needed.
    EnterCriticalSection(&(pHWHead->RegCritSec));
    try {
        // Need to signal FlushDone for XmitComChar
        PulseEvent(pHWHead->FlushDone);

        pHWHead->CommErrors &= ~CE_TXFULL;

        // If CTS flow control is desired, check cts. 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 (pHWHead->dcb.fOutxCtsFlow) {
            DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - fOutxCtsFlow true\r\n")));
            // We don't need to explicitly read the MSR, since we always enable
            // IER_MS, which ensures that we will get an interrupt and read
            // the MSR whenever CTS, DSR, TERI, or DCD change.
            //Check CTS (RTS), 1:low, 0:high;
            if (!(pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_RTSS, UART_USR1_RTSS_SET))) {
                DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - fOutxCtsFlow true 0x%x, 0x%x\r\n"),pHWHead->sUSR1,pHWHead->pUartReg->USR1));                
                DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler, flowed off via CTS\n") ) );
                pHWHead->CTSFlowOff = TRUE;  // Record flowed off state

                // disable TX interrupts while flowed off
                OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );

                // We could return a positive value here, which would
                // cause the MDD to periodically check the flow control
                // status.  However, we don't need to since we know that
                // the DCTS interrupt will cause the MDD to call us, and we
                // will subsequently fake a TX interrupt to the MDD, causing
                // him to call back into PutBytes.
                LeaveCriticalSection(&(pHWHead->RegCritSec));
                return;
            }
        }

        // Same thing applies for DSR
        if (pHWHead->dcb.fOutxDsrFlow) {
            DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - fOutxDsrFlow true\r\n")));
            // We don't need to explicitly read the register, since we always enable
            // interrupt, which ensures that we will get an interrupt and read
            // the register whenever CTS, DSR, TERI, or DCD change.
            //Check shadow bDSR, 1:low, 0:high
            if (!pHWHead->bDSR) {
                pHWHead->DSRFlowOff = TRUE;  // Record flowed off state
                // disable TX interrupts while flowed off

                OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );

                // See the comment above above positive return codes.
                LeaveCriticalSection(&(pHWHead->RegCritSec));
                return;
            }
        }
    }
    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(&(pHWHead->RegCritSec));

    //  OK, now lets actually transmit some data.
    EnterCriticalSection(&(pHWHead->TransmitCritSec));

    EnterCriticalSection(&(pHWHead->RegCritSec));
    try {
        // Enable xmit intr. We need to do this no matter what, 
        // since the MDD relies on one final interrupt before
        // returning to the application. 

        OUTREG32(&pHWHead->pUartReg->USR2,CSP_BITFVAL(UART_USR2_TXDC, UART_USR2_TXDC_SET)); 

        SL_ReadLineStatus(pHWHead);

		if (pSerHead->useDMA == FALSE)
		{
			if (pHWHead->sUSR2 & CSP_BITFVAL(UART_USR2_TXFE, UART_USR2_TXFE_SET)) {         
				//always enable FIFO
				byteCount = SER_FIFO_DEPTH-SER_FIFO_TXTL;
				DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler - Write max of %d bytes to 0x%x\r\n"), byteCount, &pHWHead->pUartReg->UTXD));
				
				
				// Wait until there is room in the FIFO
				while(INREG32(&pHWHead->pUartReg->UTS) & CSP_BITFMASK(UART_UTS_TXFULL));
				
				for (*pByteNumber=0; NumberOfBytes && byteCount; NumberOfBytes--, byteCount--) {

					OUTREG32(&pHWHead->pUartReg->UTXD,*pSourceBuffer);

					DEBUGMSG(ZONE_WRITE, (TEXT("Write x%x\r\n"), *pSourceBuffer));
					
					//We need to discard the echo char for irda
					if (pHWHead->UseIrDA)
						pHWHead->ulDiscard++;

					++pSourceBuffer;
					(*pByteNumber)++;
				}
			}
			INSREG32BF(&pHWHead->pUartReg->UCR4, UART_UCR4_TCEN, UART_UCR4_TCEN_ENABLE); 
		}
		else
		{
			bufId = 0;
			while ((NumberOfBytes > 0) && (bufId < SERIAL_MAX_DESC_COUNT_TX))
			{
				DDKSdmaGetBufDescStatus(pSerHead->SerialDmaChanTx, bufId, &Status); 
				DEBUGMSG(ZONE_FLOW, (TEXT("SL_TxIntrHandler: Status before Tx = 0x%x\r\n"), Status));

				if (((Status & DDK_DMA_FLAGS_BUSY) == 0) || 
					(pSerHead->dmaBufFirstUseBmp & (1 << bufId)))
				{
					if (pSerHead->dmaBufFirstUseBmp & (1 << bufId))
					{
						pSerHead->dmaBufFirstUseBmp &= ~(1 << bufId);
					}
					DEBUGMSG(ZONE_FLOW, (TEXT("SL_TxIntrHandler: NumberOfBytes = 0x%x\r\n"), NumberOfBytes));

					if (NumberOfBytes > pSerHead->txDMABufSize)
						curByteCount = pSerHead->txDMABufSize;
					else
						curByteCount = NumberOfBytes;

					NumberOfBytes -= curByteCount;

					Mode = ((bufId == (SERIAL_MAX_DESC_COUNT_TX - 1)) || (NumberOfBytes == 0))
						? DDK_DMA_FLAGS_WRAP : DDK_DMA_FLAGS_CONT;

					DDKSdmaClearBufDescStatus(pSerHead->SerialDmaChanTx, bufId);
					DDKSdmaSetBufDesc(pSerHead->SerialDmaChanTx, bufId,
						DDK_DMA_FLAGS_INTR | Mode,
						pSerHead->SerialPhysTxDMABufferAddr.LowPart + bufId * pSerHead->txDMABufSize,
						0, DDK_DMA_ACCESS_8BIT, (WORD)curByteCount);
					
					pBuffer = (LPBYTE)MapCallerPtr(pSourceBuffer + *pByteNumber, curByteCount);

					memcpy(pSerHead->pSerialVirtTxDMABufferAddr + bufId * pSerHead->txDMABufSize,
						pBuffer, curByteCount);

					*pByteNumber += curByteCount;
					pSerHead->awaitingTxDMACompBmp |= (1 << bufId);
					bufId++;
				} // Status
			}

			if (*pByteNumber > 0) {
				DDKSdmaStartChan(pSerHead->SerialDmaChanTx);
				//RETAILMSG(1, (TEXT("Write DMA started size %d"),*pByteNumber ));
				if (pHWHead->UseIrDA)
					pHWHead->ulDiscard += *pByteNumber;
			}
		}
		DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler: Enable INTR_TX.\r\n")));
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
        EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
		DEBUGMSG(1, (TEXT("Exception caught \n")));
    }
    LeaveCriticalSection(&(pHWHead->RegCritSec));
    LeaveCriticalSection(&(pHWHead->TransmitCritSec));

    DEBUGMSG(ZONE_WRITE, (TEXT("SL_TxIntrHandler- sent %d.\r\n"), *pByteNumber));

    return;
}


//-----------------------------------------------------------------------------
//
// Function: SL_ModemIntrHandler
//
// This function handles the modem interrupt. It
// collects the modem status of the serial port, and 
// updates internal driver status information. 
// In the new serial port upper layer implementation 
// available in Microsoft Windows CE 3.0 and later, 
// this function replaces the HWOtherIntrHandler 
// function.
//
// Parameters:
//      pContext 
//          [in] Pointer to device head.
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------
VOID SL_ModemIntrHandler( PVOID pContext )
{
    PUART_INFO pHWHead = (PUART_INFO)pContext;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_ModemIntrHandler+\r\n")));
    
    SL_ReadModemStatus( pHWHead );
    if (!((PSER_INFO)pContext)->cOpenCount) {
        // We want to indicate a cable event.
        if (!pHWHead->UseIrDA) {
            if ((pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_RTSS, UART_USR1_RTSS_SET)))
                if (IsAPIReady(SH_WMGR))
                    CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED,NULL);
        }
        else {
            if (IsAPIReady(SH_WMGR)) 
                CeEventHasOccurred (NOTIFICATION_EVENT_IR_DISCOVERED,NULL);
        }        

⌨️ 快捷键说明

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