📄 pdd.c
字号:
//
// 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 + -