📄 sc2450pdd.cpp
字号:
/**
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2006 Samsung Electronics, co. ltd All rights reserved.
Module Name:
SC2450PDD.CPP
Abstract:
S3C2450 USB2.0 function device driver
rev:
2006.9.4 : First release (Woosuk Chung)
**/
#include <windows.h>
#include <nkintr.h>
#include <ddkreg.h>
#include <S3C2450.h>
#include "sc2450pdd.h"
#include <S3C2450REF_GPIO.h>
#include <bsp.h>
static volatile BSP_ARGS *v_gBspArgs;
#define CARD_INSERTED 1
#define CARD_REMOVED 2
#define UDC_REG_PRIORITY_VAL _T("Priority256")
#define DBG 0
#define TEST_MODE_SUPPORT 1
#define INVALID_HANDLE (HANDLE)-1
#if TEST_MODE_SUPPORT
#define USB_TEST_J 0x01
#define USB_TEST_K 0x02
#define USB_TEST_SE0_NAK 0x03
#define USB_TEST_PACKET 0x04
#define USB_TEST_FORCE_ENABLE 0x05
#define USB_FEATURE_TEST_MODE 2
#define TEST_PKT_SIZE 53
#define TEST_ARR_SIZE 27
WORD ahwTestPkt [TEST_ARR_SIZE] = {
0x0000, 0x0000, 0x0000,
0xAA00, 0xAAAA, 0xAAAA, 0xAAAA,
0xEEAA, 0xEEEE, 0xEEEE, 0xEEEE,
0xFEEE, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0x7FFF, 0xDFBF,
0xF7EF, 0xFDFB, 0x7EFC, 0xDFBF,
0xF7EF, 0xFDFB, 0x007E, 0x0000
};
#endif
enum EP0_STATE {
EP0_STATE_IDLE = 0,
EP0_STATE_IN_DATA_PHASE,
EP0_STATE_OUT_DATA_PHASE
};
#define IN_TRANSFER 1
#define OUT_TRANSFER 2
typedef struct EP_STATUS {
DWORD dwEndpointNumber;
DWORD dwDirectionAssigned;
DWORD dwPacketSizeAssigned;
BOOL fInitialized;
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 0x40 // usb2.0
#define ENDPOINT_COUNT 9
#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;
EP0_STATE Ep0State;
// registry
DWORD dwIOBase;
DWORD dwSysIntr;
DWORD dwIrq;
DWORD dwIOLen;
DWORD dwISTPriority;
USB_DEVICE_REQUEST udr;
EP_STATUS rgEpStatus[ENDPOINT_COUNT];
PFN_UFN_MDD_NOTIFY pfnNotify;
HANDLE hBusAccess;
CEDEVICE_POWER_STATE cpsCurrent;
} *PCTRLR_PDD_CONTEXT;
#define SC2450_SIG '2450' // "SC2450" signature
#define IS_VALID_SC2450_CONTEXT(ptr) \
( (ptr != NULL) && (ptr->dwSig == SC2450_SIG) )
#ifdef DEBUG
#define ZONE_POWER DEBUGZONE(8)
UFN_GENERATE_DPCURSETTINGS(UFN_DEFAULT_DPCURSETTINGS_NAME,
_T("Power"), _T(""), _T(""), _T(""),
DBG_ERROR | DBG_INIT);
// Caution: Turning on more debug zones can cause STALLs due
// to corrupted setup packets.
// Validate the context.
static
VOID
ValidateContext(
PCTRLR_PDD_CONTEXT pContext
)
{
PREFAST_DEBUGCHK(pContext);
DEBUGCHK(pContext->dwSig == SC2450_SIG);
DEBUGCHK(!pContext->hevInterrupt || pContext->hIST);
DEBUGCHK(VALID_DX(pContext->cpsCurrent));
DEBUGCHK(pContext->pfnNotify);
}
#else
#define ValidateContext(ptr)
#endif
volatile BYTE *g_pUDCBase;
static BYTE USBClassInfo;
#define USB_RNDIS 0
#define USB_Serial 1
#define USB_MSF 2
#define SET TRUE
#define CLEAR FALSE
#define CTRLR_BASE_REG_ADDR(offset) ((volatile ULONG*) ( (g_pUDCBase) + (offset)))
#define DRIVER_USB_KEY TEXT("Drivers\\USB\\FunctionDrivers")
#define DRIVER_USB_VALUE TEXT("DefaultClientDriver")
#define DRIVER_USB_MSF_CARD_KEY TEXT("Drivers\\USB\\FunctionDrivers\\Mass_Storage_Class")
#define DRIVER_USB_MSF_CARD_VALUE TEXT("DeviceName")
#define DRIVER_USB_MSF_MMC_KEY TEXT("Drivers\\SDCARD\\ClientDrivers\\Class\\MMC_Class")
#define DRIVER_USB_MSF_MMC_VALUE TEXT("Index")
#define DRIVER_USB_MSF_SD_KEY TEXT("Drivers\\SDCARD\\ClientDrivers\\Class\\SDMemory_Class")
#define DRIVER_USB_MSF_SD_VALUE TEXT("Index")
#define DRIVER_USB_MSF_FLASH_KEY TEXT("Drivers\\BuiltIn\\SMFLASH")
#define DRIVER_USB_MSF_FLASH_VALUE TEXT("Index")
#define CLKCON_USBD (1<<7)
volatile S3C2450_CLKPWR_REG *pCLKPWR = NULL; // Clock power registers (needed to enable I2S and SPI clocks)
volatile S3C2450_IOPORT_REG *pIOPregs = NULL;
// EINT2 Test Code by woo
UINT32 g_PlugIrq = IRQ_EINT2; // Determined by SMDK2450 board layout.
UINT32 g_PlugSysIntr = SYSINTR_UNDEFINED;
HANDLE g_PlugThread;
HANDLE g_PlugEvent;
HANDLE g_SdCardDetectThread;
static DWORD PLUG_IST();
static DWORD SDCARD_DetectIST();
BOOL HW_USBClocks(CEDEVICE_POWER_STATE cpsNew);
DWORD bSDMMCMSF = FALSE;
#define HIGH 1
#define FULL 0
#define POWER_THREAD_PRIORITY 101
// end woo
// Read a register.
inline
WORD
ReadReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwOffset
)
{
DEBUGCHK(IS_VALID_SC2450_CONTEXT(pContext));
volatile ULONG *pbReg = CTRLR_BASE_REG_ADDR(dwOffset);
WORD bValue = (WORD) *pbReg;
return bValue;
}
// Write a register.
inline
VOID
WriteReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwOffset,
DWORD bValue
)
{
DEBUGCHK(IS_VALID_SC2450_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,
WORD dwMask,
BOOL bSet
)
{
DEBUGCHK(IS_VALID_SC2450_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,
WORD dwMask,
BOOL bSet
)
{
DEBUGCHK(IS_VALID_SC2450_CONTEXT(pContext));
BYTE bValue = 0;
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Write the EP number to the index reg
WriteReg(pContext, IR, (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;
}
// Read an indexed register.
inline
WORD
ReadIndexedReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint,
DWORD regOffset
)
{
DEBUGCHK(IS_VALID_SC2450_CONTEXT(pContext));
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Write the EP number to the index reg
WriteReg(pContext, IR, (BYTE) dwEndpoint);
// Now Read the Register associated with this Endpoint for a given offset
WORD bValue = ReadReg(pContext, regOffset);
LeaveCriticalSection(&pContext->csIndexedRegisterAccess);
return bValue;
}
// Write an indexed register.
inline
VOID
WriteIndexedReg(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint,
DWORD regOffset,
DWORD bValue
)
{
DEBUGCHK(IS_VALID_SC2450_CONTEXT(pContext));
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Write the EP number to the index reg
WriteReg(pContext, IR, (BYTE) dwEndpoint);
// 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(EP0BR); break;
case 1: pulDataReg = CTRLR_BASE_REG_ADDR(EP1BR); break;
case 2: pulDataReg = CTRLR_BASE_REG_ADDR(EP2BR); break;
case 3: pulDataReg = CTRLR_BASE_REG_ADDR(EP3BR); break;
case 4: pulDataReg = CTRLR_BASE_REG_ADDR(EP4BR); break;
case 5: pulDataReg = CTRLR_BASE_REG_ADDR(EP5BR); break;
case 6: pulDataReg = CTRLR_BASE_REG_ADDR(EP6BR); break;
case 7: pulDataReg = CTRLR_BASE_REG_ADDR(EP7BR); break;
case 8: pulDataReg = CTRLR_BASE_REG_ADDR(EP8BR); 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
EnableDisableEndpointInterrupt(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint,
BOOL fEnable
)
{
// TODO: Make new cs or rename this one
EnterCriticalSection(&pContext->csIndexedRegisterAccess);
// Disable the Endpoint Interrupt
WORD bEpIntReg = ReadReg(pContext, EIER);
BYTE bIrqEnBit = EpToIrqStatBit(dwEndpoint);
if (fEnable) {
bEpIntReg |= bIrqEnBit;
}
else {
bEpIntReg &= ~bIrqEnBit;
}
WriteReg(pContext, EIER, bEpIntReg);
LeaveCriticalSection(&pContext->csIndexedRegisterAccess);
}
static
inline
VOID
EnableEndpointInterrupt(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
EnableDisableEndpointInterrupt(pContext, dwEndpoint, TRUE);
FUNCTION_LEAVE_MSG();
}
static
inline
VOID
DisableEndpointInterrupt(
PCTRLR_PDD_CONTEXT pContext,
DWORD dwEndpoint
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -