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

📄 pl011pdd.c

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

    // Save [in] parameter (number of bytes to send) and initialise [out] parameter (number of
    //  bytes actually sent)
    //
    cbInOut = *pBuffLen;
    *pBuffLen = 0;

    EnterCriticalSection(&pPDDContext->cs);

    try
    {
        if ((pPDDContext->dcb.fOutxCtsFlow) && ((pPDDContext->fModemStatus & MS_CTS_ON) == 0))
        {
            // Record flowed-off state
            //
            pPDDContext->fCTSFlowOff = TRUE;
            DEBUGMSG(ZONE_WRITE | ZONE_FLOW,
                (BODY_TEXT("PDD_TxIntrHandler: Flowed-off via CTS")));

            // Disable TX interrupts while flowed-off
            //
            VERIFY(PL011DisableTxInterrupts(pPDDContext->pPL011));
            LeaveCriticalSection(&pPDDContext->cs);
            return;
        }

        if ((pPDDContext->dcb.fOutxDsrFlow) && ((pPDDContext->fModemStatus & MS_DSR_ON) == 0))
        {
            // Record flowed-off state
            //
            pPDDContext->fDSRFlowOff = TRUE;
            DEBUGMSG(ZONE_WRITE | ZONE_FLOW,
                (BODY_TEXT("PDD_TxIntrHandler: Flowed-off via DSR")));

            // Disable TX interrupts while flowed-off
            //
            VERIFY(PL011DisableTxInterrupts(pPDDContext->pPL011));
            LeaveCriticalSection(&pPDDContext->cs);
            return;
        }

        // If we get this far, then we're not flowed off, and the transmitter is running, so we can
        //  clear the 'transmitter full' error flag (the MDD is in a better position to control this
        //  flag  than we are... but it doesn't).
        //
        pPDDContext->fCommErrors &= ~CE_TXFULL;
    }
    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(&pPDDContext->cs);
        return;
    }
    
    LeaveCriticalSection(&pPDDContext->cs);

    // Signal XmitComChar() that the transmitter is ready (not full and not flowed-off).
    //
    PulseEvent(pPDDContext->hevTxReady);

    //UART DMA - PDD_TxIntrHandler  
    if (pPDDContext->DMA_Enable && cbInOut >= sizeof(DWORD))
    {
    
        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;
        PVOID   pvSourceBuffer = pUDma->pvTxSourceBuffer;
        DWORD   dwRet, Source;
        
        //UART Tx Channel Init.

        InitializeDMAParams.ucChannelNumber = pUDma->ucTxDMAChannel;
        InitializeDMAParams.ucSourceWidth = TRANSFER_WIDTH_DWORD; // Mem - DWORD
        InitializeDMAParams.ucDestWidth = TRANSFER_WIDTH_BYTE; // UART Tx 8 bit

        InitializeDMAParams.ucSourceBurstSize = BURST_SIZE_1;
        InitializeDMAParams.ucDestBurstSize = BURST_SIZE_4;

        //Mem->Per, DMA as flow controller
        InitializeDMAParams.ucFlowControl = FLOW_MEM_PER_DMAC;

        // Increment source and keep destination constant
        InitializeDMAParams.fIncrementSource = TRUE;
        InitializeDMAParams.fIncrementDest = FALSE;

        if(!KernelIoControl(IOCTL_HAL_INITIALIZE_DMA_CHANNEL,
            &InitializeDMAParams, sizeof(InitializeDMAParams),
            &InitializeDMAResult, sizeof(InitializeDMAResult), &dwRet))
        {
            DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR, 
                (TEXT("PDD: Tx, Error - Cannot initialize DMA channel\r\n")));
            *pBuffLen = 0;
            return;
        }
        
        //Only transfer DWORD aligned size
        *pBuffLen = (cbInOut >> 2) << 2;

        //transfer maximum PAGE_SIZE data in one go
        *pBuffLen = MIN((DWORD)PAGE_SIZE, *pBuffLen);

        //we need to use DMA API
        pUDma->pdwTxSourcePageList = (PDWORD)malloc(sizeof(DWORD));
        if (pUDma->pdwTxSourcePageList == NULL){
            DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot allocate for pdwTxSourcePageList\r\n")));
            *pBuffLen = 0;
            return;
        }

        
        // give the data in MDD buffer to the DMA buffer
        memcpy(pvSourceBuffer, pTxBuffer, *pBuffLen);

        if(!LockPages(pvSourceBuffer, PAGE_SIZE, pUDma->pdwTxSourcePageList, LOCKFLAG_WRITE))
        {
            DEBUGMSG (ZONE_ERROR, (TEXT("PDD: Error - Cannot lock pages\r\n")));
            free(pUDma->pdwTxSourcePageList);
            *pBuffLen = 0;
            return;
        }

        // Just double check page alignment
        pUDma->pdwTxSourcePageList[0] &= ~(DWORD)(PAGE_SIZE - 1);

        pUDma->dwTxSourceSize = *pBuffLen;
        
        StartDMAParams.ucChannelNumber = pUDma->ucTxDMAChannel;
        
        if(pPDDContext->ComId)
            Source = (DWORD)PHYS_UART1_BASE;    // UART1 Physical address
        else
            Source = (DWORD)PHYS_UART0_BASE;    // UART0 Physical address
        
        StartDMAParams.pdwDestBuffer = &Source;
        StartDMAParams.pdwSourceBuffer = pUDma->pdwTxSourcePageList;
        StartDMAParams.dwTransferSize = *pBuffLen;
        if(!KernelIoControl(IOCTL_HAL_START_DMA_TRANSFER,
            &StartDMAParams, sizeof(StartDMAParams),
            &StartDMAResult, sizeof(StartDMAResult), &dwRet))
        {
            DEBUGMSG (ZONE_FUNCTION | ZONE_ERROR, 
                (TEXT("PDD: Error - Cannot start DMA transfer\r\n")));
            // Unlock the virtual pages so that they can be paged out
            UnlockPages(pvSourceBuffer, PAGE_SIZE);
            free(pUDma->pdwTxSourcePageList);
            *pBuffLen = 0;
            return;
        }
        dwRet = WaitForSingleObject(pUDma->hTxUDmaISTEvent, INFINITE);
        
        UnlockPages(pvSourceBuffer, PAGE_SIZE);
        free(pUDma->pdwTxSourcePageList);

        InterruptDone(pUDma->dwTxDMASysIntr);

    }
    // End of UART DMA - PDD_TxIntrHandler

    else
    {
        //  We're not flowed-off so let's send as many bytes as possible, from the supplied buffer
        //
        VERIFY(PL011SendBytes(pPDDContext->pPL011, pTxBuffer, &cbInOut));
        DEBUGMSG(ZONE_WRITE | ZONE_THREAD,
            (BODY_TEXT("PDD_TxIntrHandler: Sent %u bytes"), cbInOut));

        *pBuffLen = cbInOut;
    }

    // Enable transmit interrupts. We need to do this no matter what, since the MDD relies on one
    //  final interrupt before returning to the application.
    //
    VERIFY(PL011EnableTxInterrupts(pPDDContext->pPL011));
    DEBUGMSG(ZONE_WRITE,
        (BODY_TEXT("PDD_TxIntrHandler: Transmit interrupts enabled")));

exit_point:

    DEBUGMSG(ZONE_WRITE | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_TxIntrHandler()")));
}


VOID PDD_ModemIntrHandler(PDD_CONTEXT *pPDDContext)
{
    ULONG fModemInterrupts;
    ULONG fModemEvents;

    DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
        (HEAD_TEXT("PDD_ModemIntrHandler(%#08x)"), pPDDContext));

    if (pPDDContext == NULL)
        goto exit_point;

    // First, see if there were changes in the modem lines, then notify the MDD of these events
    //
    fModemInterrupts = pPDDContext->fInterrupts & (PL011_INT_DSR |
                                                   PL011_INT_DCD |
                                                   PL011_INT_CTS |
                                                   PL011_INT_RI);

    if (fModemInterrupts == 0)
        goto exit_point;

    fModemEvents = 0;

    if (fModemInterrupts & PL011_INT_DSR )
        fModemEvents |= EV_DSR;

    if (fModemInterrupts & PL011_INT_DCD )
        fModemEvents |= EV_RLSD;

    if (fModemInterrupts & PL011_INT_CTS)
        fModemEvents |= EV_CTS;

    if (fModemInterrupts & PL011_INT_RI )
        fModemEvents |= EV_RING;

    // Pass any events to the callback in the MDD
    //
    EvaluateEventFlag(pPDDContext->pMDDContext, fModemEvents);

    // Now update the modem status flags stored in the PDD context
    //
    VERIFY(PL011GetModemStatus(pPDDContext->pPL011, &pPDDContext->fModemStatus));

    EnterCriticalSection(&pPDDContext->cs);

    try
    {
        if (pPDDContext->fDSRFlowOff && ((pPDDContext->fModemStatus & MS_DSR_ON) != 0))
        {
            // Record end of flowed-off state
            //
            pPDDContext->fDSRFlowOff = FALSE;
            DEBUGMSG(ZONE_FLOW,
                (BODY_TEXT("PDD_ModemIntrHandler: Flowed-on via DSR")));

            // Re-enable TX interrupts now no longer flowed-off, then simulate a TX interrupt to get
            //  things moving
            //
            VERIFY(PL011EnableTxInterrupts(pPDDContext->pPL011));
            pPDDContext->fAddTxIntr = TRUE;
        }

        if (pPDDContext->fCTSFlowOff && ((pPDDContext->fModemStatus & MS_CTS_ON) != 0))
        {
            // Record end of flowed-off state
            //
            pPDDContext->fCTSFlowOff = FALSE;
            DEBUGMSG(ZONE_FLOW,
                (BODY_TEXT("PDD_ModemIntrHandler: Flowed-on via CTS")));

            // Re-enable TX interrupts now no longer flowed-off, then simulate a TX interrupt to get
            //  things moving
            //
            VERIFY(PL011EnableTxInterrupts(pPDDContext->pPL011));
            pPDDContext->fAddTxIntr = TRUE;
        }
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    {
        // Do nothing
    }   

    LeaveCriticalSection(&pPDDContext->cs);

exit_point:

    DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_ModemIntrHandler()")));
}


VOID PDD_LineIntrHandler(PDD_CONTEXT *pPDDContext)
{
    ULONG fLineInterrupts;
    ULONG fLineStatus;

    DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
        (HEAD_TEXT("PDD_LineIntrHandler(%#08x)"), pPDDContext));

    if (pPDDContext == NULL)
        goto exit_point;

    fLineInterrupts = pPDDContext->fInterrupts & (PL011_INT_OE |
                                                  PL011_INT_BE |
                                                  PL011_INT_PE |
                                                  PL011_INT_FE);

    if (fLineInterrupts == 0)
        goto exit_point;

    fLineStatus = 0;

    if ((fLineInterrupts & PL011_INT_OE) != 0)
        fLineStatus |= PL011_RSR_OE;

    if ((fLineInterrupts & PL011_INT_BE) != 0)
        fLineStatus |= PL011_RSR_BE;

    if ((fLineInterrupts & PL011_INT_PE) != 0)
        fLineStatus |= PL011_RSR_PE;

    if ((fLineInterrupts & PL011_INT_FE) != 0)
        fLineStatus |= PL011_RSR_FE;

    VERIFY(ProcessLineStatus(pPDDContext, fLineStatus));

exit_point:

    DEBUGMSG(ZONE_EVENTS | ZONE_FUNCTION,
        (TAIL_TEXT("PDD_LineIntrHandler()")));
}


ULONG PDD_GetRxBufferSize(PDD_CONTEXT *pPDDContext)
{
    DEBUGMSG(ZONE_FUNCTION,
        (HEAD_TEXT("PDD_GetRxBufferSize(%#08x)"), pPDDContext));

    DEBUGMSG(ZONE_FUNCTION,
        (TAIL_TEXT("PDD_GetRxBufferSize() 0")));

    // By returning zero, we are leaving the MDD to set the size its receive buffer
    //
    return 0;
}

BOOL PDD_PowerOff(PDD_CONTEXT *pPDDContext)
{
    if (pPDDContext == NULL)
        return FALSE;

    // Note: We could try and shutdown the DMA transfer from here (like the following code) 
    //  But we are not allowed to call a system IOCTL during power down, so we will leave it 
    //  to the kernel.
/*
    if (pPDDContext->DMA_Enable)
    {
        PUART_DMA_INFO pUDma = &(pPDDContext->uart_DMA_Info);
        
        if( pUDma->OpenCnt)
        {
            HALT_DMA_PARAMS HaltDMAParams;
            HALT_DMA_RESULT HaltDMAResult;
            STOP_DMA_PARAMS StopDMAParams;
            STOP_DMA_RESULT StopDMAResult;
            DWORD   dwRet;
            
            // First halt the channels to make sure no activity is going on or is starting
            HaltDMAParams.ucChannelNumber = pUDma->ucRxDMAChannel;
            if(!KernelIoControl(IOCTL_HAL_HALT_DMA_TRANSFER,
                &HaltDMAParams, sizeof(HaltDMAParams),
                &HaltDMAResult, sizeof(HaltDMAResult), &dwRet))
            {
                DEBUGMSG( ZONE_ERROR, 
                    (TEXT("PDD_PowerOff: Error - DMA channel(Rx) halt failed\r\n")));
                //return FALSE; - Carry on regardless
            }
            HaltDMAParams.ucChannelNumber = pUDma->ucTxDMAChannel;
            if(!KernelIoControl(IOCTL_HAL_HALT_DMA_TRANSFER,
                &HaltDMAParams, sizeof(HaltDMAParams),
                &HaltDMAResult, sizeof(HaltDMAResult), &dwRet))
            {
                DEBUGMSG( ZONE_ERROR, 
                    (TEXT("PDD_PowerOff: Error - DMA channel(Tx) halt failed\r\n")));
                //return FALSE; - Carry on regardless
            }

⌨️ 快捷键说明

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