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

📄 pl011pdd.c

📁 ARM9基于WINDOWSCE的BSP源代码
💻 C
📖 第 1 页 / 共 5 页
字号:

    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    {
        // Just get out of here, setting our return code to show a failure
        fRC = FALSE;
    }

fail_point:

    LeaveCriticalSection(&pPDDContext->cs);

exit_point:

    DEBUGMSG(ZONE_OPEN | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_Open() %s"), SUCCEEDED_OR_FAILED(fRC)));

    return fRC;
}


ULONG PDD_Close(PDD_CONTEXT *pPDDContext)
{
    BOOL fRC = FALSE;

    DEBUGMSG(ZONE_CLOSE | ZONE_FUNCTION,
        (HEAD_TEXT("PDD_Close(%#08x)"), pPDDContext));

    if (pPDDContext == NULL)
        goto exit_point;

    // Check that we're not already closed
    //
    if (pPDDContext->nOpenCount == 0)
    {
        DEBUGMSG(ZONE_CLOSE | ZONE_ERROR,
            (BODY_TEXT("PDD_Close: Not open")));
        goto exit_point;
    }

    EnterCriticalSection(&pPDDContext->cs);

    try
    {
        // Allow time for the UART transmitter to empty (one second is very generous)
        //
        VERIFY(PL011WaitTxEmpty(pPDDContext->pPL011, 1000));

        // Deactivate modem control lines
        //
        PDD_ClearDTR(pPDDContext);
        PDD_ClearRTS(pPDDContext);

        // Power-down PL011
        //
        DEBUGMSG(ZONE_CLOSE,
            (BODY_TEXT("PDD_Close: Powering down PL011")));

        pPDDContext->fIRMode = FALSE;  
        VERIFY(PL011SetOutputMode(pPDDContext->pPL011, FALSE, FALSE));

        VERIFY(PL011DisableAllInterrupts(pPDDContext->pPL011));
        VERIFY(PL011ClearPendingInterrupts(pPDDContext->pPL011));

        // Decrement the open count
        //
        pPDDContext->nOpenCount--;
        DEBUGMSG(ZONE_CLOSE,
            (BODY_TEXT("PDD_Close: Open count = %u"), pPDDContext->nOpenCount));

        if (pPDDContext->DMA_Enable)
            DMA_Close(&(pPDDContext->uart_DMA_Info));
        // Although the return value isn't used by the MDD, we're still interested in failure. If we
        //  get this far, we'll call it a success.
        //
        fRC = TRUE;
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    {
        fRC = FALSE;
    }
    
    
    LeaveCriticalSection(&pPDDContext->cs);

exit_point:

    DEBUGMSG(ZONE_CLOSE | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_Close() %s"), SUCCEEDED_OR_FAILED(fRC)));

    // As per other BSP serial drivers the return value is 0
    return 0;
}


INTERRUPT_TYPE PDD_GetIntrType(PDD_CONTEXT *pPDDContext)
{
    INTERRUPT_TYPE fInterruptType = INTR_NONE;
    ULONG fInterrupts = 0;

    DEBUGMSG(ZONE_THREAD | ZONE_FUNCTION,
        (HEAD_TEXT("PDD_GetIntrType(%#08x)"), pPDDContext));

    if (pPDDContext == NULL)
        goto exit_point;

    VERIFY(PL011GetInterrupts(pPDDContext->pPL011, &fInterrupts));

    // Set the appropriate flags, according to the interrupts (the 16550 library, and all samples
    //  based on it return individual flags instead of combining them).

    if ((fInterrupts & (PL011_INT_OE | PL011_INT_BE | PL011_INT_PE | PL011_INT_FE)) != 0)
        fInterruptType |= INTR_LINE;

    if ((fInterrupts & (PL011_INT_RT | PL011_INT_RX)) != 0)
    {
        //Rx time out, so disable DMA in RxIntHandler
        if((fInterrupts & PL011_INT_RT)!=0) pPDDContext->No_DMA_timeout=TRUE; 
        fInterruptType |= INTR_RX;
    }

    if ((fInterrupts & (PL011_INT_TX)) != 0)
        fInterruptType |= INTR_TX;
/*
    if ((fInterrupts & (PL011_INT_DSR | PL011_INT_DCD | PL011_INT_CTS | PL011_INT_RI)) != 0)
        fInterruptType |= INTR_MODEM;
*/
    // Fake a transmit interrupt, if required (when ending flowed-off state, for example)
    //
    if (InterlockedExchange(&pPDDContext->fAddTxIntr, FALSE) == TRUE)
        fInterruptType |= INTR_TX;

    // Save the current interrupt flags for use by the Rx, Tx, Line and Modem interrupt handlers
    //
    pPDDContext->fInterrupts = fInterrupts;

exit_point:

    DEBUGMSG(ZONE_THREAD | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_GetIntrType() %#08x"), fInterruptType));

    return fInterruptType;
}


ULONG PDD_RxIntrHandler(PDD_CONTEXT *pPDDContext, PUCHAR pRxBuffer, ULONG *pBuffLen)
{
    ULONG nDroppedBytes = 0;

    ULONG cbTargetRoom;
    BOOL  fRXFlag;

    BOOL  fRXReady;
    UCHAR bRXChar;
    ULONG fRXStatus;

    BOOL  fDsrSensitivity;
    BOOL  fNull;
    BOOL  fErrorChar;
    BOOL  fParity;
    BOOL  fReplaceParityErrors;
    UCHAR bEvtChar;

    DEBUGMSG(ZONE_READ | ZONE_FUNCTION,
        (HEAD_TEXT("PDD_RxIntrHandler(%#08x, %#08x, %#08x)"), pPDDContext, pRxBuffer, pBuffLen));

    if ((pPDDContext == NULL) || (pRxBuffer == NULL) || (pBuffLen == NULL))
        goto exit_point;

    cbTargetRoom = *pBuffLen;
    DEBUGCHK(cbTargetRoom != 0);

    // Initialise count of received bytes [out] parameter (as early as possible)
    //
    *pBuffLen = 0;

    fRXFlag = FALSE;
    fRXReady = FALSE;

    fDsrSensitivity      = pPDDContext->dcb.fDsrSensitivity;
    fNull                = pPDDContext->dcb.fNull;
    fErrorChar           = pPDDContext->dcb.fErrorChar;
    fParity              = pPDDContext->dcb.fParity;
    fReplaceParityErrors = (fParity && fErrorChar);
    bEvtChar             = pPDDContext->dcb.EvtChar;
//UART DMA - PDD_RxIntrHandler
    if (pPDDContext->DMA_Enable && !fDsrSensitivity && !fNull && 
            !fReplaceParityErrors && pPDDContext->No_DMA_timeout!=TRUE 
            && cbTargetRoom >= UART_FIFO_Rx_LEVEL){
        
        PUART_DMA_INFO pUDma = (PUART_DMA_INFO)(&(pPDDContext->uart_DMA_Info));
        INITIALIZE_DMA_PARAMS   InitializeDMAParams;
        INITIALIZE_DMA_RESULT   InitializeDMAResult;
        START_DMA_PARAMS    StartDMAParams;
        START_DMA_RESULT    StartDMAResult;
        PUCHAR  pvDestBuffer = pUDma->pvRxDestBuffer;
        DWORD   dwRet,  Dest;

    //UART Rx Channel Init.

        InitializeDMAParams.ucChannelNumber = pUDma->ucRxDMAChannel;
        InitializeDMAParams.ucSourceWidth = TRANSFER_WIDTH_BYTE; //UART Rx - 8 bits
        InitializeDMAParams.ucDestWidth = TRANSFER_WIDTH_DWORD; //Mem - DWORD

        InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_4; 
        InitializeDMAParams.ucDestBurstSize = BURST_SIZE_1;
        
        //Per->Mem, DMA as flow controller
        InitializeDMAParams.ucFlowControl = FLOW_PER_MEM_DMAC; 

        InitializeDMAParams.fIncrementSource = FALSE; //UART - constant
        InitializeDMAParams.fIncrementDest = TRUE; //Mem - auto increment
        if(!KernelIoControl(IOCTL_HAL_INITIALIZE_DMA_CHANNEL,
            &InitializeDMAParams, sizeof(InitializeDMAParams),
            &InitializeDMAResult, sizeof(InitializeDMAResult), &dwRet))
        {
            DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR, 
                (TEXT("PDD: Error - Rx, Cannot initialize DMA channel\r\n")));
            *pBuffLen = 0;
            return 0;
        }
        
        // It is certain that at least UART_FIFO_Rx_LEVEL bytes are in the Rx FIFO at this point
        *pBuffLen = UART_FIFO_Rx_LEVEL; 
        
        // because we need to use DMA API.
        pUDma->pdwRxDestPageList = (PDWORD)malloc(sizeof(DWORD));
        if (pUDma->pdwRxDestPageList == NULL){
            DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot allocate for pdwRxDestPageList\r\n")));
            *pBuffLen = 0;
            return 0;
        }

        // Lock the virtual pages to find the physical addresses
        if(!LockPages(pvDestBuffer, PAGE_SIZE, pUDma->pdwRxDestPageList, LOCKFLAG_WRITE))
        {
            DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot lock pages\r\n")));
            free(pUDma->pdwRxDestPageList);
            *pBuffLen = 0;
            return 0;
        }
        
        // Just double check page alignment
        pUDma->pdwRxDestPageList[0] &= ~(DWORD)(PAGE_SIZE - 1);
    
        pUDma->dwRxDestSize = *pBuffLen;

        StartDMAParams.ucChannelNumber = pUDma->ucRxDMAChannel;

        if(pPDDContext->ComId)
            Dest = (DWORD)PHYS_UART1_BASE;  // UART1 Physical address
        else
            Dest = (DWORD)PHYS_UART0_BASE;  // UART0 Physical address

        StartDMAParams.pdwSourceBuffer = &Dest;
        StartDMAParams.pdwDestBuffer = pUDma->pdwRxDestPageList;
        StartDMAParams.dwTransferSize = *pBuffLen;
        if(!KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
            &StartDMAParams, sizeof(StartDMAParams),
            &StartDMAResult, sizeof(StartDMAResult), &dwRet))
        {
            DEBUGMSG (ZONE_ERROR, 
                (TEXT("PDD: Error - Cannot start DMA transfer\r\n")));
            // Unlock the virtual pages so that they can be paged out
            UnlockPages(pvDestBuffer, PAGE_SIZE);
            free(pUDma->pdwRxDestPageList);
            *pBuffLen = 0;
            return 0;
        }

        dwRet=WaitForSingleObject(pUDma->hRxUDmaISTEvent, INFINITE);

        UnlockPages(pvDestBuffer, PAGE_SIZE);
        free(pUDma->pdwRxDestPageList);

        InterruptDone(pUDma->dwRxDMASysIntr);
        memcpy(pRxBuffer, pvDestBuffer, *pBuffLen);
    }
//End of UART DMA - PDD_RxIntrHandler
    else{
    // Whilst there is free room in the supplied destination buffer, if there is a byte to read, we
    //  read it. If DSR is asserted, and we are configured to discard received data when DSR is
    //  asserted, then we discard the received byte. If the byte is NUL and we are configured to
    //  discard NUL bytes, then we discard it. If there was a parity error receiving the byte and
    //  we are configured to replace erroneous data with a specified 'error' character, then we do
    //  so. If we are configured to generate an event when we receive a specified character and the
    //  received byte is that character, then we generate the appropriate event. Otherwise, the
    //  received byte should be added to the supplied buffer and the count of received bytes should
    //  be incremented. We repeat this until either there is no more data to read, or there is no
    //  more room in the supplied destination buffer to add received data to.
    //
    while (cbTargetRoom != 0)
    {
        VERIFY(PL011ReadReceivedData(pPDDContext->pPL011, &fRXReady, &bRXChar, &fRXStatus));
        if (!fRXReady)
            break;

        if (fDsrSensitivity && ((pPDDContext->fModemStatus & MS_DSR_ON) == 0))
        {
            DEBUGMSG(ZONE_FLOW | ZONE_WARN,
                (BODY_TEXT("PDD_RxIntrHandler: Discarding byte [DCB.fDsrSensitivity]")));
        }
        else if (fNull && (bRXChar == 0))
        {
            DEBUGMSG(ZONE_WARN,
                (BODY_TEXT("PDD_RxIntrHandler: Discarding NULL byte [DCB.fNull]")));
        }
        else
        {
            if (fReplaceParityErrors && ((fRXStatus & PL011_RSR_PE) != 0))
            {
                DEBUGMSG(ZONE_WARN,
                    (BODY_TEXT("PDD_RxIntrHandler: Replacing erroneous byte [DCB.ErrorChar]")));

                bRXChar = pPDDContext->dcb.ErrorChar;
            }
            else
            {
                if (bRXChar == bEvtChar)
                {
                    DEBUGMSG(ZONE_EVENTS,
                        (BODY_TEXT("PDD_RxIntrHandler: Received event character [DCB.EvtChar]")));

                    fRXFlag = TRUE;
                }
            }

            *pRxBuffer++ = bRXChar; // Save the received byte and advance the destination pointer
            (*pBuffLen)++;          // Increment the count of received bytes [out] parameter
            cbTargetRoom--;         // Now we have one byte less free space in the destination buffer
        }
    }

    if (fRXFlag)
        EvaluateEventFlag(pPDDContext->pMDDContext, EV_RXFLAG);

    nDroppedBytes = InterlockedExchange(&pPDDContext->nDroppedBytes, 0);

        if(pPDDContext->No_DMA_timeout==TRUE) // did no-dma Rx read because time-out.
            pPDDContext->No_DMA_timeout=FALSE;  // do dma Rx read next time
                                                // this has no effect when dma is disabled 
    }

exit_point:

    DEBUGMSG(ZONE_READ | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_RxIntrHandler() %u"), nDroppedBytes));

    return nDroppedBytes;
}


VOID PDD_TxIntrHandler(PDD_CONTEXT *pPDDContext, PUCHAR pTxBuffer, ULONG *pBuffLen)
{
    ULONG cbInOut;

    DEBUGMSG(ZONE_WRITE | ZONE_FUNCTION,
        (HEAD_TEXT("PDD_TxIntrHandler(%#08x, %#08x, %#08x)"), pPDDContext, pTxBuffer, pBuffLen));

    if ((pPDDContext == NULL) || (pBuffLen == NULL))
        goto exit_point;

    DEBUGMSG(ZONE_WRITE,
        (BODY_TEXT("PDD_TxIntrHandler: Number of bytes = %u"), *pBuffLen));

    // When there is no more to send, just disable the TX interrupts and return to the MDD.
    //
    if ((*pBuffLen == 0) || (pTxBuffer == NULL))
    {
        DEBUGMSG(ZONE_WRITE,
            (BODY_TEXT("PDD_TxIntrHandler: Disable transmit interrupts")));
        VERIFY(PL011DisableTxInterrupts(pPDDContext->pPL011));
        goto exit_point;
    }

⌨️ 快捷键说明

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