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

📄 pdd.c

📁 Windows CE 6.0 BSP for the Beagle Board.
💻 C
📖 第 1 页 / 共 5 页
字号:
            // Put the device in the D2 state.
            // Note that putting the device in D4 causes an endless loop if
            // no USB cable is currently plugged in. The suspend bit is set
            // when we get a suspend interrupt; if we turn the power off,
            // the suspend bit gets cleared, triggering a resume interrupt.
            // If no USB cable is plugged in, then a suspend interrupt gets
            // generated since no USB device is present. The suspend interrupt
            // then triggers the power off, which clears the suspend bit,
            // which triggers the resume interrupt, and we enter an infinite
            // loop from which there is no escape.
            pPdd->m_NewPowerState = D2;
            UpdateDevicePower(pPdd);

#ifndef USE_OLD_CABLE_DETECT_METHOD

            // This is a work-around for what is fundamentally a hardware design flaw.
            // We can't use the ATT bit in the DEV_STAT register to determine when
            // a cable is removed since the ATT bit is always set since we set the
            // BSESSVLD bit in the InitializeHardware() function. We are supposed to
            // be able to check to see whether a cable is connected to the device
            // and set BSESSVLD as appropriate, but the hardware design for the H4
            // lacks this functionality.
            // As a result, we treat SUSPEND interrupts as if they indicate both a
            // suspend and a cable removal.

            DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
                L"Detected Cable Removal Event!\r\n"));

            // We are not configured anymore
            OUTREG32(&pUSBDRegs->SYSCON2, USBD_SYSCON2_CLR_CFG);

            // TODO: Call bus driver (OTG?) to move HW to deep sleep
            // Let MDD process change
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);

            // Don't process other changes (we are disconnected)
            goto DevStatClean;

#endif // ! USE_OLD_CABLE_DETECT_METHOD
        }
        else
        {
            DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
                L"Detected Device Resume Event!\r\n"));

            pPdd->m_NewPowerState = D0;
            UpdateDevicePower(pPdd);

            // Let MDD process change
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_RESUME);

#ifndef USE_OLD_CABLE_DETECT_METHOD

            // This is a work-around for what is fundamentally a hardware design flaw.
            // We can't use the ATT bit in the DEV_STAT register to determine when
            // a cable is inserted since the ATT bit is always set since we set the
            // BSESSVLD bit in the InitializeHardware() function. We are supposed to
            // be able to check to see whether a cable is connected to the device
            // and set BSESSVLD as appropriate, but the hardware design for the H4
            // lacks this functionality.
            // As a result, we treat RESUME interrupts as if they indicate both a
            // resume and a cable insertion.

            DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
                L"Detected Cable Insertion Event!\r\n"));

            // Let MDD process change
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_SPEED,  BS_FULL_SPEED);

#endif // ! USE_OLD_CABLE_DETECT_METHOD
        }
    }

    // Configured
    // if ((change & USBD_DEVSTAT_CFG) != 0)
    // {
    // }

    // Addressed
    if ((change & USBD_DEVSTAT_ADD) != 0)
    {
        DEBUGMSG(ZONE_PDD, (L"USBD DevStatEvent() - "
            L"Detected Device Address Event!\r\n"));

        if ((state & USBD_DEVSTAT_ADD) != 0)
        {
            // Let MDD process change
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_SET_ADDRESS, 1);
        }
        else
        {
            // Let MDD process change
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_CONFIGURED,  0);
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_SET_ADDRESS, 0);
        }
    }

DevStatClean:
    // Save device state for next interrupt
    pPdd->devState = state;

    DEBUGMSG(ZONE_FUNCTION, (L"USBD DevStatEvent() - END\r\n"));
}

//------------------------------------------------------------------------------
//
//  Function:  InterruptThread
//
//  This is interrupt thread. It controls responsed to hardware interrupt. To
//  reduce code length it calls interrupt specific functions.
//
static DWORD WINAPI InterruptThread(VOID *pPddContext)
{
    USBFN_PDD *pPdd = pPddContext;
    OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    DWORD code;
    DWORD source;
    DWORD ep;

    DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - START\r\n"));

    while (!pPdd->exitIntrThread)
    {
        // Wait for interrupt
        code = WaitForSingleObject(pPdd->hIntrEvent, INFINITE);

        DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
            L"Interrupt Event Signalled!\r\n"));

        if (code != WAIT_OBJECT_0)
        {
            break;
        }

        // Exit thread when we are told to do so...
        if (pPdd->exitIntrThread)
        {
            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Exiting Thread\r\n"));
            break;
        }

        if ((pPdd->m_CurrentPowerState == D3) || (pPdd->m_CurrentPowerState == D4))
        {
            pPdd->m_NewPowerState = D2;
            UpdateDevicePower(pPdd);
        }

        // Get interrupt source
        source = INREG32(&pUSBDRegs->IRQ_SRC);

        DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
            L"Interrupt Source: 0x%04X\r\n", (source & 0x07BF)));

        // Device state
        if ((source & USBD_INT_DS_CHG) != 0 || pPdd->fakeDsChange)
        {
            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Processing Device Status Change Interrupt\r\n"));

            // Handle device state change
            DevStatEvent(pPdd);

            // Clear fake DsChange flag
            pPdd->fakeDsChange = FALSE;

            if ((source & USBD_INT_DS_CHG) != 0)
            {
                OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_DS_CHG);
            }
        }

        // EP0 RX interrupt
        if ((source & USBD_INT_EP0_RX) != 0)
        {
            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Processing Endpoint 0 RX Interrupt\r\n"));

            // Clear source bit
            OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP0_RX);

            // Issue next Rx transfer
            IssueRxTransfer(pPdd, 0);
        }

        // EP0 TX interrupt
        if ((source & USBD_INT_EP0_TX) != 0)
        {
            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Processing Endpoint 0 TX Interrupt\r\n"));

            // Clear source bit
            OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP0_TX);

            // Issue next Tx transfer
            IssueTxTransfer(pPdd, 0);
        }

        // EPn RX interrupt
        if ((source & USBD_INT_EP_RX) != 0)
        {
            // Get EP number
            ep = (INREG32(&pUSBDRegs->EP_STAT) >> 8) & USBD_EP_NUM;

            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Processing Endpoint %d RX Interrupt\r\n", ep));

            // Clear source bit
            OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP_RX);

            // Handle event
            IssueRxTransfer(pPdd, ep);
        }

        // EPn TX interrupt
        if ((source & USBD_INT_EP_TX) != 0)
        {
            // Get EP number
            ep = INREG32(&pUSBDRegs->EP_STAT) & USBD_EP_NUM;

            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Processing Endpoint %d RX Interrupt\r\n", ep));

            // Clear source bit
            OUTREG32(&pUSBDRegs->IRQ_SRC, USBD_INT_EP_TX);

            // Handle event
            IssueTxTransfer(pPdd, ep);
        }

        // Setup Packet
        if ((source & USBD_INT_SETUP) != 0)
        {
            DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - "
                L"Processing Setup Interrupt\r\n"));

            // Reading setup FIFO clears interrupt
            SetupEvent(pPdd);
        }

        // Finish interrupt
        InterruptDone(pPdd->sysIntr);
    }

    DEBUGMSG(ZONE_INTERRUPTS, (L"USBD InterruptThread() - END\r\n"));

    return ERROR_SUCCESS;
}

//------------------------------------------------------------------------------
//
//  Function:  UfnPdd_IssueTransfer
//
DWORD WINAPI UfnPdd_IssueTransfer(VOID      * pPddContext,
                                  DWORD       endPoint,
                                  STransfer * pTransfer)
{
    USBFN_PDD *pPdd = pPddContext;
    OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    DWORD epNum;


    // Save transfer for interrupt thread
    pPdd->ep[endPoint].pTransfer = pTransfer;

    if (pTransfer->pvBuffer == NULL)
    {
        // Sync Length with buffer.
        pTransfer->cbBuffer = 0;
    }

    DEBUGCHK(pTransfer->dwUsbError == UFN_NOT_COMPLETE_ERROR);

    // Depending on direction
    if (TRANSFER_IS_IN(pTransfer))
    {
        pPdd->ep[endPoint].fZeroLengthNeeded = (pTransfer->cbBuffer==0);
        IssueTxTransfer(pPdd, endPoint);
    }
    else
    {
        pPdd->ep[endPoint].fZeroLengthNeeded  = FALSE;

        // Select EP
        epNum = USBD_EP_NUM & endPoint;
        SelectEp(pPdd, epNum);

        // Enable EP FIFO
        OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_FIFO_EN);

        // Deselect EP
        DeselectEp(pPdd, epNum);
    }

    return ERROR_SUCCESS;
}

//------------------------------------------------------------------------------
//
//  Function:  UfnPdd_AbortTransfer
//
DWORD WINAPI UfnPdd_AbortTransfer(VOID *pPddContext, DWORD endPoint, STransfer *pTransfer)
{
    USBFN_PDD *pPdd = pPddContext;
    OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    DWORD epNum;

    // Select EP
    epNum = USBD_EP_NUM & endPoint;

    if (TRANSFER_IS_IN(pTransfer))
    {
        epNum |= USBD_EP_NUM_DIRIN;
    }

    SelectEp(pPdd, epNum);

    // Clear EP
    OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_CLR_EP);

    // Deselect EP
    DeselectEp(pPdd, epNum);

    // Finish transfer
    pPdd->ep[endPoint].pTransfer = NULL;
    pTransfer->dwUsbError = UFN_CANCELED_ERROR;
    pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_TRANSFER_COMPLETE, (DWORD)pTransfer);

    // Done
    return ERROR_SUCCESS;
}

//------------------------------------------------------------------------------
//
//  Function:  UfnPdd_StallEndpoint
//
//  This function is called by MDD to set end point to stall mode (halted).
//
DWORD WINAPI UfnPdd_StallEndpoint(VOID *pPddContext, DWORD endPoint)
{
    USBFN_PDD *pPdd = pPddContext;
    OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    DWORD epNum;

    DEBUGMSG(ZONE_PDD, (L"UsbFnPdd_StallEndpoint %d\r\n", endPoint));

    if (endPoint == 0)
    {
        // Stall next EP0 transaction
        OUTREG32(&pUSBDRegs->SYSCON2, USBD_SYSCON2_STALL_CMD);

    }
    else
    {
        // Select EP
        epNum = USBD_EP_NUM & endPoint;

        if (!pPdd->ep[endPoint].dirRx)
        {
            epNum |= USBD_EP_NUM_DIRIN;
        }

        SelectEp(pPdd, epNum);

        // Halt EP
        OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_SET_HALT);

        // Deselect EP
        DeselectEp(pPdd, epNum);
    }

    // Done
    return ERROR_SUCCESS;
}

//------------------------------------------------------------------------------
//
//  Function:  UfnPdd_ClearEndpointStall
//
//  This function is called by MDD to clear end point stall mode (halted).
//
DWORD WINAPI UfnPdd_ClearEndpointStall(VOID *pPddContext, DWORD endPoint)
{
    DWORD rc = ERROR_INVALID_FUNCTION;
    USBFN_PDD *pPdd = pPddContext;
    OMAP2420_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    DWORD epNum;

    DEBUGMSG(ZONE_PDD, (L"UsbFnPdd_ClearEndpoint %d\r\n", endPoint));

    // Endpoint can't be zero
    if (endPoint != 0)
    {
        // Select EP
        epNum = USBD_EP_NUM & endPoint;

        if (!pPdd->ep[endPoint].dirRx)
        {
            epNum |= USBD_EP_NUM_DIRIN;
        }

        SelectEp(pPdd, epNum);

        // Clear suspend, Clear data toggle
        OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_CLR_HALT | USBD_CTRL_CLR_DATA_TOGGLE);

        // Deselect EP
        DeselectEp(pPdd, epNum);

        // Done
        rc = ERROR_SUCCESS;
    }

    return rc;
}

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

⌨️ 快捷键说明

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