📄 sc2440pdd.cpp
字号:
//
// 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.
//
//
//
// 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.
//
#include <windows.h>
#include <nkintr.h>
#include <ddkreg.h>
#include "sc2440pdd.h"
#define UDC_REG_PRIORITY_VAL _T("Priority256")
#define EP_STATE_IDLE 0
#define EP0_STATE_IN_DATA_PHASE 1
#define EP0_STATE_END_XFER_PHASE 2
#define EP0_STATE_OUT_DATA_PHASE 3
#define IN_TRANSFER 1
#define OUT_TRANSFER 2
typedef struct EP_STATUS {
DWORD dwEndPointNumber;
DWORD dwDirectionAssigned;
DWORD dwPacketSizeAssigned;
BOOL fInitialized;
DWORD dwEpState;
DWORD dwEndpointType;
PSTransfer pTransfer;
CRITICAL_SECTION cs;
} *PEP_STATUS;
#define LOCK_ENDPOINT(peps) EnterCriticalSection(&peps->cs)
#define UNLOCK_ENDPOINT(peps) LeaveCriticalSection(&peps->cs)
#define EP_0_PACKET_SIZE 0x8 // Could also be 16 but they recommend 8
static const EP_STATUS g_rgEpStatus[] = {
{
0x0,
},
{
0x1,
},
{
0x2,
},
{
0x3,
},
{
0x4,
}
};
#define ENDPOINT_COUNT dim(g_rgEpStatus)
#define EP_VALID(x) ((x) < ENDPOINT_COUNT)
#define DEFAULT_PRIORITY 100
typedef struct CTRL_PDD_CONTEXT {
PVOID pvMddContext;
DWORD dwSig;
HANDLE hIST;
HANDLE hevInterrupt;
BOOL fRunning;
CRITICAL_SECTION csIndexedRegisterAccess;
BOOL fSpeedReported;
BOOL fRestartIST;
BOOL fExitIST;
BOOL attachedState;
BOOL sendDataEnd;
// registry
DWORD dwIOBase;
DWORD dwSysIntr;
DWORD dwIrq;
DWORD dwIOLen;
DWORD dwISTPriority;
EP_STATUS rgEpStatus[ENDPOINT_COUNT];
PFN_UFN_MDD_NOTIFY pfnNotify;
HANDLE hBusAccess;
CEDEVICE_POWER_STATE cpsCurrent;
} *PCTRLR_PDD_CONTEXT;
#define SC2440_SIG '2440' // "SC2440" signature
#define IS_VALID_SC2440_CONTEXT(ptr) \
( (ptr != NULL) && (ptr->dwSig == SC2440_SIG) )
#ifdef DEBUG
#define ZONE_POWER DEBUGZONE(8)
UFN_GENERATE_DPCURSETTINGS(UFN_DEFAULT_DPCURSETTINGS_NAME,
_T("Power"), _T(""), _T(""), _T(""),
DBG_ERROR | DBG_INIT);
// Validate the context.
static
VOID
ValidateContext(
PCTRLR_PDD_CONTEXT pContext
)
{
PREFAST_DEBUGCHK(pContext);
DEBUGCHK(pContext->dwSig == SC2440_SIG);
DEBUGCHK(!pContext->hevInterrupt || pContext->hIST);
DEBUGCHK(VALID_DX(pContext->cpsCurrent));
DEBUGCHK(pContext->pfnNotify);
}
#else
#define ValidateContext(ptr)
#endif
volatile BYTE *g_pUDCBase;
#define CTRLR_BASE_REG_ADDR(offset) ((volatile ULONG*) ( (g_pUDCBase) + (offset)))
// Read a register.
inline
BYTE
ReadReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwOffset
)
{
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
BYTE bValue = (BYTE) *pbReg;
return bValue;
}
// Write a register.
inline
VOID
WriteReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwOffset,
BYTE bValue
)
{
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
*pbReg = (ULONG) bValue;
}
// Calling with dwMask = 0 and SET reads and writes the contents unchanged.
inline
BYTE
SetClearReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwOffset,
BYTE dwMask,
BOOL bSet
)
{
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
BYTE bValue = (BYTE) *pbReg;
if (bSet) {
bValue |= dwMask;
}
else {
bValue &= ~dwMask;
}
*pbReg = bValue;
return bValue;
}
// Calling with dwMask = 0 and SET reads and writes the contents unchanged.
inline
BYTE
SetClearIndexedReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint,
DWORD dwOffset,
BYTE dwMask,
BOOL bSet
)
{
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
BYTE bValue = 0;
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Write the EP number to the index reg
WriteReg(pContext, IDXADDR_REG_OFFSET, (BYTE) dwEndpoint);
// Now Write the Register associated with this Endpoint for a given offset
bValue = SetClearReg(pContext, dwOffset, dwMask, bSet);
LeaveCriticalSection(&pContext->csIndexedRegisterAccess);
return bValue;
}
#define SET TRUE
#define CLEAR FALSE
// Read an indexed register.
inline
BYTE
ReadIndexedReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint,
DWORD regOffset
)
{
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Write the EP number to the index reg
WriteReg(pContext, IDXADDR_REG_OFFSET, (BYTE) dwEndpoint);
// Now Read the Register associated with this Endpoint for a given offset
BYTE bValue = ReadReg(pContext, regOffset);
LeaveCriticalSection(&pContext->csIndexedRegisterAccess);
return bValue;
}
// Write an indexed register.
inline
VOID
WriteIndexedReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwIndex,
DWORD regOffset,
BYTE bValue
)
{
DEBUGCHK(IS_VALID_SC2440_CONTEXT(pContext));
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Write the EP number to the index reg
WriteReg(pContext, IDXADDR_REG_OFFSET, (BYTE) dwIndex);
// Now Write the Register associated with this Endpoint for a given offset
WriteReg(pContext, regOffset, bValue);
LeaveCriticalSection(&pContext->csIndexedRegisterAccess);
}
/*++
Routine Description:
Return the data register of an endpoint.
Arguments:
dwEndpoint - the target endpoint
Return Value:
The data register of the target endpoint.
--*/
static
volatile ULONG*
_GetDataRegister(
DWORD dwEndpoint
)
{
volatile ULONG *pulDataReg = NULL;
//
// find the data register (non-uniform offset)
//
switch (dwEndpoint) {
case 0: pulDataReg = CTRLR_BASE_REG_ADDR(EP0_FIFO_REG_OFFSET); break;
case 1: pulDataReg = CTRLR_BASE_REG_ADDR(EP1_FIFO_REG_OFFSET); break;
case 2: pulDataReg = CTRLR_BASE_REG_ADDR(EP2_FIFO_REG_OFFSET); break;
case 3: pulDataReg = CTRLR_BASE_REG_ADDR(EP3_FIFO_REG_OFFSET); break;
case 4: pulDataReg = CTRLR_BASE_REG_ADDR(EP4_FIFO_REG_OFFSET); break;
default:
DEBUGCHK(FALSE);
break;
}
return pulDataReg;
} // _GetDataRegister
// Retrieve the endpoint status structure.
inline
static
PEP_STATUS
GetEpStatus(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint
)
{
ValidateContext(pContext);
DEBUGCHK(EP_VALID(dwEndpoint));
PEP_STATUS peps = &pContext->rgEpStatus[dwEndpoint];
return peps;
}
// Return the irq bit for this endpoint.
inline
static
BYTE
EpToIrqStatBit(
DWORD dwEndpoint
)
{
DEBUGCHK(EP_VALID(dwEndpoint));
return (1 << (BYTE)dwEndpoint);
}
/*++
Routine Description:
Enable the interrupt of an endpoint.
Arguments:
dwEndpoint - the target endpoint
Return Value:
None.
--*/
static
VOID
EnableEndpointInterrupt(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
// End Point Zero is always enabled (after Run)
if (dwEndpoint == 0) {
FUNCTION_LEAVE_MSG();
return;
}
// Disable the Endpoint Interrupt
BYTE irqEnBit = EpToIrqStatBit(dwEndpoint);
SetClearReg(pContext, EP_INT_EN_REG_OFFSET, irqEnBit, SET);
FUNCTION_LEAVE_MSG();
} // _EnableEpInterrupt
/*++
Routine Description:
Disable the interrupt of an endpoint.
Arguments:
dwEndpoint - the target endpoint
Return Value:
None.
--*/
static
VOID
DisableEndpointInterrupt(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
// End Point Zero is always enabled (after Run)
if (dwEndpoint == 0) {
FUNCTION_LEAVE_MSG();
return;
}
// Enable the Endpoint Interrupt
BYTE irqEnBit = EpToIrqStatBit(dwEndpoint);
SetClearReg(pContext, EP_INT_EN_REG_OFFSET, irqEnBit, CLEAR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -