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

📄 pdd.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  File:  newpdd.c
//
//  This file contains USB function PDD implementation. Actual implementation
//  doesn't use DMA transfers and it doesn't support ISO endpoints.
//
#include <windows.h>
#include <omap730.h>
#include <usbfntypes.h>
#include <usbfn.h>
#include <oal.h>

#pragma optimize ( "g", on )

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

#ifdef DEBUG
DBGPARAM dpCurSettings;
#endif

//------------------------------------------------------------------------------
//
//  Define:  USBD_IRQ_MASK
//
//  This is composite interrupt mask used in driver.
//
#define USBD_IRQ_MASK   \
    (USBD_IRQ_EN_EP_RX|USBD_IRQ_EN_EP_TX|USBD_IRQ_EN_DS_CHG|USBD_IRQ_EN_EP0)

//------------------------------------------------------------------------------
//
//  Type:  USBFN_EP
//
//  Internal PDD structure which holds info about endpoint direction, max packet
//  size and active transfer.
//
typedef struct {
    WORD maxPacketSize;
    BOOL dirRx;
    BOOL zeroLength;
    STransfer *pTransfer;
} USBFN_EP;

//------------------------------------------------------------------------------
//
//  Type:  USBFN_PDD
//
//  Internal PDD context structure.
//
typedef struct {

    VOID *pMddContext;
    PFN_UFN_MDD_NOTIFY pfnNotify;

    OMAP730_USBD_REGS *pUSBDRegs;

    HANDLE hClk;

    DWORD devState;
    BOOL selfPowered;

    BOOL setupDirRx;
    WORD setupCount;
    HANDLE hSetupEvent;

    USBFN_EP ep[USBD_EP_COUNT];

    BOOL fakeDsChange;                  // To workaround MDD problem

} USBFN_PDD;

USBFN_PDD g_usbfnpdd;

#ifdef DEBUG

#define ZONE_INTERRUPTS         DEBUGZONE(8)
#define ZONE_POWER              DEBUGZONE(9)
#define ZONE_PDD                DEBUGZONE(15)

#endif

void ConnectHardware();
void DisconnectHardware();

//------------------------------------------------------------------------------
//
//  Function:  Log2
//
//  Trivial log with base 2 function used in EP configuration.
//
static DWORD Log2(DWORD value)
{
    DWORD rc = 0;
    while (value != 0) {
        value >>= 1;
        rc++;
    }
    if (rc > 0) rc--;
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function:  SetupInterrupt
//
//  This function handles setup packet interrupts.
//
static VOID SetupEvent(USBFN_PDD *pPdd)
{
    OMAP730_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    WORD data[4];
    USB_DEVICE_REQUEST *pSetup = (USB_DEVICE_REQUEST*)data;

    do {

        // Select setup FIFO (this clears USBD_INT_SETUP flag)
        OUTREG32(&pUSBDRegs->EP_NUM, USBD_EP_NUM_SETUP);

        // Read setup data
        data[0] = (WORD)INREG32(&pUSBDRegs->DATA);
        data[1] = (WORD)INREG32(&pUSBDRegs->DATA);
        data[2] = (WORD)INREG32(&pUSBDRegs->DATA);
        data[3] = (WORD)INREG32(&pUSBDRegs->DATA);

        // Deselect setup FIFO
        OUTREG32(&pUSBDRegs->EP_NUM, 0);

    } while ((INREG32(&pUSBDRegs->IRQ_SRC) & USBD_INT_SETUP) != 0);

    // Save setup packet direction & size for later use
    pPdd->setupDirRx = (pSetup->bmRequestType & 0x80) == 0;
    pPdd->setupCount = pSetup->wLength;

    // MDD doesn't call PDD back on configure message
    if (
        pSetup->bmRequestType == 0 &&
        pSetup->bRequest == USB_REQUEST_SET_CONFIGURATION
    ) {
        if (pSetup->wValue != 0) {
            // Move device to configured state
            OUTREG32(&pUSBDRegs->SYSCON2, USBD_SYSCON2_DEV_CFG);
            // Set self powered flag
            if (pPdd->selfPowered) {
                SETREG32(&pUSBDRegs->SYSCON1, USBD_SYSCON1_SELF_PWR);
            } else {
                CLRREG32(&pUSBDRegs->SYSCON1, USBD_SYSCON1_SELF_PWR);
            }
        } else {
            OUTREG32(&pUSBDRegs->SYSCON2, USBD_SYSCON2_CLR_CFG);
        }
    }

    // Let MDD process message
    pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_SETUP_PACKET, (DWORD)data);

}

//------------------------------------------------------------------------------
//
//  Function:  IssueTxTransfer
//
//  This function sends next packet from transaction buffer. It is called from
//  interrupt thread and UfnPdd_IssueTransfer.
//
static VOID IssueTxTransfer(USBFN_PDD *pPdd, DWORD endPoint)
{
    OMAP730_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    STransfer *pTransfer;
    BOOL complete = FALSE;
    DWORD epNum, stat, space, count, remain;
    UCHAR *pBuffer;
    WORD data;

    // Get active transfer
    pTransfer = pPdd->ep[endPoint].pTransfer;

    OALMSG(OAL_ETHER&&OAL_FUNC, (
        L"UsbFnPdd!IssueTxTransfer: EP %d pTransfer 0x%x (%d, %d, %d)\r\n",
        endPoint, pTransfer, pTransfer != NULL ? pTransfer->cbBuffer : 0,
        pTransfer != NULL ? pTransfer->cbTransferred : 0,
        pTransfer != NULL ? pTransfer->dwUsbError : -1
    ));

    // Select EP
    epNum = (USBD_EP_NUM & endPoint) | USBD_EP_NUM_DIRIN;
    OUTREG32(&pUSBDRegs->EP_NUM, USBD_EP_NUM_SEL | epNum);

    // Get EP status
    stat = INREG32(&pUSBDRegs->STAT_FLG);

    // Depending on EP status
    if ((stat & USBD_STAT_STALL) != 0) {
        // We issued stall, remove it...
        OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_CLR_HALT);
        // We are done
        goto clean;
    }

    // When transfer is NULL it is handshake ACK
    if (pTransfer == NULL) goto clean;

    // Is this final interrupt of transfer? 
    if (
        pTransfer->cbTransferred == pTransfer->cbBuffer && 
        !pPdd->ep[endPoint].zeroLength
    ) {
        pTransfer->dwUsbError = UFN_NO_ERROR;
        complete = TRUE;
        goto clean;
    }

    pBuffer = (UCHAR*)pTransfer->pvBuffer + pTransfer->cbTransferred;
    space = pTransfer->cbBuffer - pTransfer->cbTransferred;

    if (endPoint != 0) {
        // Non Zero Endpoint: No zero length padding needed.
        pPdd->ep[endPoint].zeroLength = FALSE;
    } else {
        // Zero endpoint: Zero length padding needed if last
        // packet is maxPacketSize.
        pPdd->ep[endPoint].zeroLength = (
            space == pPdd->ep[endPoint].maxPacketSize && 
            pPdd->setupCount > pTransfer->cbBuffer
        );
    }        

    // How many bytes we can send just now?
    count = pPdd->ep[endPoint].maxPacketSize;
    if (count > space) count = space;

    // Write data to FIFO
    remain = count;
    while (remain > 1) {
        data = (pBuffer[1] << 8) | pBuffer[0];
        OUTREG16((UINT16*)&pUSBDRegs->DATA, data);
        pBuffer += 2;
        space -= 2;
        remain -= 2;
    }
    if (remain > 0) {
        OUTREG8((UINT8*)&pUSBDRegs->DATA, *pBuffer);
        pBuffer += 1;
        space -= 1;
        remain -= 1;
    }

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

    // We transfered some data
    pTransfer->cbTransferred = pTransfer->cbBuffer - space;

clean:

    // Deselect EP
    OUTREG32(&pUSBDRegs->EP_NUM, epNum);

    // If transaction is complete we should tell MDD
    if (complete) {
        pPdd->ep[endPoint].pTransfer = NULL;
        pPdd->pfnNotify(
            pPdd->pMddContext, UFN_MSG_TRANSFER_COMPLETE, (DWORD)pTransfer
        );
    }
}

//------------------------------------------------------------------------------
//
//  Function:  IssueRxTransfer
//
//  This function receives packet to transaction buffer. It is called from
//  interrupt thread.
//
static VOID IssueRxTransfer(USBFN_PDD *pPdd, DWORD endPoint)
{
    OMAP730_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    STransfer *pTransfer;
    BOOL complete = FALSE;
    DWORD epNum, stat, space, count, remain, maxSize;
    UCHAR *pBuffer;
    WORD data;

    // Get active transfer
    pTransfer = pPdd->ep[endPoint].pTransfer;

    OALMSG(OAL_ETHER&&OAL_FUNC, (
        L"UsbFnPdd!IssueRxTransfer: EP %d pTransfer 0x%x (%d, %d, %d)\r\n",
        endPoint, pTransfer, pTransfer != NULL ? pTransfer->cbBuffer : 0,
        pTransfer != NULL ? pTransfer->cbTransferred : 0,
        pTransfer != NULL ? pTransfer->dwUsbError : -1
    ));

    // Select EP
    epNum = USBD_EP_NUM & endPoint;
    OUTREG32(&pUSBDRegs->EP_NUM, USBD_EP_NUM_SEL | epNum);

    // Get EP status
    stat = INREG32(&pUSBDRegs->STAT_FLG);

    // Depending on EP status
    if ((stat & USBD_STAT_STALL) != 0) {
        // We issued stall, remove it...
        OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_CLR_HALT);
        // We are done
        goto clean;
    }

    // When transfer is NULL it is handshake ACK
    if (pTransfer == NULL) goto clean;

    // Get maxPacketSize
    maxSize = pPdd->ep[endPoint].maxPacketSize;

        pBuffer = (UCHAR*)pTransfer->pvBuffer + pTransfer->cbTransferred;
        space = pTransfer->cbBuffer - pTransfer->cbTransferred;

        // Get EP status flag
        stat = INREG32(&pUSBDRegs->STAT_FLG);

        // Get number of bytes in FIFO
        if ((stat & USBD_STAT_FIFO_EMPTY) != 0) {
            count = 0;
        } else if ((stat & USBD_STAT_FIFO_FULL) != 0) {
            count = maxSize;
        } else {
            count = INREG32(&pUSBDRegs->RXFSTAT) & USBD_RFXSTAT_COUNT;
        }

        // Read data
        remain = count;
        while (remain > 1) {
            data = (WORD)INREG32(&pUSBDRegs->DATA);
            if (space > 1) {
                pBuffer[0] = (UCHAR)data;
                pBuffer[1] = (UCHAR)(data >> 8);
                pBuffer += 2;
                space -= 2;
            }
            remain -= 2;
        }
        if (remain > 0) {
            data = (WORD)INREG32(&pUSBDRegs->DATA);
            if (space > 0) {
                *pBuffer = (UCHAR)data;
                pBuffer += 1;
                space -= 1;
            }
            remain -= 1;
        }

        // We transfered some data
        pTransfer->cbTransferred = pTransfer->cbBuffer - space;

        // Is this end of transfer?
        if (
            pTransfer->cbTransferred == pTransfer->cbBuffer || count < maxSize
        ) {
            // Yes, set return code
            pTransfer->dwUsbError = UFN_NO_ERROR;
            // And complete flag
            complete = TRUE;
        } else {
            // No, enable FIFO for next packet
            OUTREG32(&pUSBDRegs->CTRL, USBD_CTRL_FIFO_EN);
        }

clean:

    // Deselect EP
    OUTREG32(&pUSBDRegs->EP_NUM, epNum);

    // If transaction is complete we should tell MDD
    if (complete) {
        pPdd->ep[endPoint].pTransfer = NULL;
        pPdd->pfnNotify(
            pPdd->pMddContext, UFN_MSG_TRANSFER_COMPLETE, (DWORD)pTransfer
        );
    }
}

//------------------------------------------------------------------------------
//
//  Function:  DevStatEvent
//
//  This function handles device state change interrupts.
//
static VOID DevStatEvent(USBFN_PDD *pPdd)
{
    OMAP730_USBD_REGS *pUSBDRegs = pPdd->pUSBDRegs;
    DWORD state, change;

    // Get device state & change
    state = INREG32(&pUSBDRegs->DEVSTAT);
    change = state ^ pPdd->devState;

    OALMSG(OAL_ETHER&&OAL_FUNC, (
        L"UsbFnPdd!DevStatEvent: Device state %x, change %x\r\n",
        state, change
    ));

    // Attach/deattach
    if ((change & USBD_DEVSTAT_ATT) != 0) {
        if ((state & USBD_DEVSTAT_ATT) != 0) {
            // TODO: Call bus driver (OTG?) to move HW from deep sleep
            // 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);
        } else {
            // Clear source bit
            // 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 clean;
        }
    }

    // Reset
    if ((change & (USBD_DEVSTAT_USB_RESET|USBD_DEVSTAT_DEF)) != 0) {
        if ((state & USBD_DEVSTAT_USB_RESET) == 0) {
            // OTG may not detect attach/detach events correctly on some platforms
            // Simulate a attach/detach event to clear any previous state on reset
            // Let MDD process change
            pPdd->pfnNotify(pPdd->pMddContext, UFN_MSG_BUS_EVENTS, UFN_DETACH);

⌨️ 快捷键说明

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