📄 ohcdpdd.c
字号:
WRITE_BITFIELD(struct resetBITS,&v_pDCUSBReg->Reset,pwrCtrlPolLow,1); // Need to invert the signal from the SA-1111 for the USB power controller
WRITE_BITFIELD(struct resetBITS,&v_pDCUSBReg->Reset,pwrSensePolLow,1);
WRITE_BITFIELD(struct skpcrBITS,&v_pDCPLLReg->skpcr,DCLKEn,1); //Enable DMA Clocks
#endif
#ifndef PLAT_LUBBOCK
RETAILMSG(1,(TEXT("OHCI_Reset: Resetting Bulverde OHCI.\r\n")));
// Do the reset for the Bulverde part.
// Two levels of reset need to be initiated:
// The OHCI core needs to be reset via the FHR bit,
// then the OHCI system bus interface needs to be reset via the FSBIR bit.
// reset the OHC core and all OHC blocks driven by the 12 MHz clock, eg. write fifo, etc.
v_pDCUSBOHCIReg->uhchr |= XLLP_USBOHCI_UHCHR_FHR;
usWait( 10 ); // ten micro second wait called for by spec.
v_pDCUSBOHCIReg->uhchr &= ~XLLP_USBOHCI_UHCHR_FHR;
// reset the OHC system bus interface, eg. SBI, DMA blocks, fifos, etc.
v_pDCUSBOHCIReg->uhchr |= XLLP_USBOHCI_UHCHR_FSBIR;
while( v_pDCUSBOHCIReg->uhchr & XLLP_USBOHCI_UHCHR_FSBIR ); // auto clears in 3 system bus clocks
// now set the polarity fields so the OHCI knows to:
// assert or deassert the power control signals to power or shutdown a port, and
// detect overcurrent indication from assertion or de-assertion of the power sense signals.
// note: the correcting settings for these values are determined by the board layout and the
// external voltage regulators in use. In the case of the Mainstone, the external voltage
// regulator is a MAX1693EUB USB Power Switch, which uses negative polarity for power enable
// and for fault notification.
v_pDCUSBOHCIReg->uhchr |= XLLP_USBOHCI_UHCHR_PCPL; // bit = 1 means power control polarity is active low
v_pDCUSBOHCIReg->uhchr |= XLLP_USBOHCI_UHCHR_PSPL; // bit = 1 means power (ie. over-current) sense polarity is active low
// v_pDCUSBOHCIReg->uhchr |= XLLP_USBOHCI_UHCHR_SSEP1; // keep port 1 in sleep/standby (eg. disable port 1)
v_pDCUSBOHCIReg->uhchr &= ~XLLP_USBOHCI_UHCHR_SSEP1; // for port 1, enable power to the single ended receivers and the port (DevMan says to do this)
v_pDCUSBOHCIReg->uhchr &= ~XLLP_USBOHCI_UHCHR_SSEP0; // for port 0, enable power to the single ended receivers and the port
v_pDCUSBOHCIReg->uhchr &= ~XLLP_USBOHCI_UHCHR_SSE; // allow the values of SSEP1 and SSPE0 to control the power.
#endif
RETAILMSG(1,(TEXT("OHCI_Reset: done.\r\n")));
}
// a thread for debugging....
INT WINAPI OHCIPDDDebugThread(LPVOID lpvParam)
{
// this thread will enable and disable the
// usb ohci port every fifteen seconds to
// do an automated plug / unplug stress test.
while(1)
{
// disable the usb ohci port
RETAILMSG(1,(TEXT("OHCIPDDDebugThread: disabling USB OHCI port 0.\r\n")));
v_pDCUSBOHCIReg->uhchr |= XLLP_USBOHCI_UHCHR_SSEP0; // port 0 standby: enabled
Sleep( 15 * 1000 ); // fifteen second delay
// enable the usb ohci port
RETAILMSG(1,(TEXT("OHCIPDDDebugThread: enabling USB OHCI port 0.\r\n")));
v_pDCUSBOHCIReg->uhchr &= ~XLLP_USBOHCI_UHCHR_SSEP0; // port 0 standby: disabled.
Sleep( 15 * 1000 );
}
}
// handle PDD interrupts
INT WINAPI OHCIPDDIntrThread(LPVOID lpvParam)
{
BOOL fKnownInterrupt;
UnusedParameter(lpvParam);
RETAILMSG(1,(TEXT("OHCIPDD INTR Thread: Started.\r\n")));
while (1) {
WaitForSingleObject(gOHCIPDDIntrEvent, INFINITE);
#ifdef PLAT_LUBBOCK
//See which SA-1111 non-OHCI Controller interrupt we got
RETAILMSG(1, (TEXT("OHCIPDD INTR Thread Interrupt Event\r\n")));
fKnownInterrupt = FALSE;
if (v_pDCUSBReg->ussr[0].irqHciRmtWkp) {
RETAILMSG(1, (TEXT("OHCIPdd Int Thread Remote Wakeup Event\r\n")));
fKnownInterrupt = TRUE;
}
if (v_pDCUSBReg->ussr[0].irqHciBuffAcc) {
RETAILMSG(1, (TEXT("OHCIPdd Int Thread Buffer Active Event\r\n")));
fKnownInterrupt = TRUE;
}
if (v_pDCUSBReg->ussr[0].nIrqHciM) {
RETAILMSG(1, (TEXT("OHCIPdd Int Thread Normal HC Interrupt Event\r\n")));
fKnownInterrupt = TRUE;
}
if (v_pDCUSBReg->ussr[0].nHciMFCir) {
RETAILMSG(1, (TEXT("OHCIPdd Int Thread Clear Signals Event\r\n")));
fKnownInterrupt = TRUE;
}
if (v_pDCUSBReg->ussr[0].usbPwrSense) {
RETAILMSG(1, (TEXT("OHCIPdd Int Thread Power Sense Event\r\n")));
fKnownInterrupt = TRUE;
}
#endif
#ifndef PLAT_LUBBOCK
if( v_pDCUSBOHCIReg->uhcstat )
{
RETAILMSG(1,(TEXT("OHCIPdd Int Thread uhcstat: %08x.\r\n"), v_pDCUSBOHCIReg->uhcstat ));
// clear the interrupt:
v_pDCUSBOHCIReg->uhcstat = v_pDCUSBOHCIReg->uhcstat;
RETAILMSG(1,(TEXT("OHCIPdd Int Thread new uhcstat: %08x.\r\n"), v_pDCUSBOHCIReg->uhcstat ));
fKnownInterrupt = TRUE;
}
#endif
if(!fKnownInterrupt) {
RETAILMSG(1, (TEXT("OHCIPdd Int Thread No known Event\r\n")));
}
#if 0 // allow HcdPdd_ResumeThread() to handle resume notifications
//if the USB clock is on go through reset sequence to start up the USB
// otherwise let normal HC int process
//Right now only Port Resume interrupts are enabled
if (!v_pDCPLLReg->skpcrBits[0].UCLKEn) {
RETAILMSG(1, (TEXT("OHCIPdd Int Port Resume, reseting Sense Event\r\n")));
OHCI_Reset();
}
#endif // boolean
//DEBUGMSG(ZONE_INIT, (TEXT("OHCI PDD INTR Thread called P\r\n")));
InterruptDone(dwSysIntrOhciPdd/*SYSINTR_OHCI_PDD*/);
}
RETAILMSG(1,(TEXT("OHCIPDD INTR Thread: Ended.\r\n")));
}
// This PDD will set up two interrupt service threads,
// first we create a thread to service the SA-1111 non-OHCI host controller interrupts
// Then in InitializeOHCI we hook the SA-1111 OHCI host controller interrupt in to the MDD
BOOL InitPddInterrupts(void)
{
gOHCIPDDIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!(InterruptInitialize(dwSysIntrOhciPdd/*SYSINTR_OHCI_PDD*/, gOHCIPDDIntrEvent, NULL, 0))) {
DEBUGMSG(ZONE_INIT, (TEXT("OHCI PDD INTR INIT Failed\r\n")));
DEBUGMSG(ZONE_INIT, (TEXT("OHCI PDD INTR INIT ERR: 0x%x\r\r"), GetLastError()));
//return NULL;
return FALSE;
}
// gOHCIPDDIntrThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) OHCIPDDIntrThread, NULL, 0, NULL);
// if ( gOHCIPDDIntrThread == NULL ) {
// ERRORMSG(1, (TEXT("Fatal Error! Failed to create OHCIPDD interrupt thread.\r\n")));
// //return (NULL);
// return (FALSE);
// } else {
// DEBUGMSG(ZONE_INIT, (TEXT("-OHCIPDD Init\r\n")));
// //return TRUE;
// }
RETAILMSG(1, (TEXT("InitPddInterrupts RhPortStatus: 0x%x.\r\n"), v_pDCUSBReg->RhPortStatus[0]));
return TRUE;
}
/* HcdPdd_DllMain
*
* DLL Entry point.
*
* Return Value:
*/
extern BOOL HcdPdd_DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
UnusedParameter(hinstDLL);
UnusedParameter(dwReason);
UnusedParameter(lpvReserved);
RETAILMSG(1, (TEXT("Modified File: ohcd.c.\r\n")));
return TRUE;
}
/* GetRegistryConfig
*
* Note: Will need to be changed to support multiple instances.
*
* Return Value:
* TRUE for success, FALSE for error
*/
static BOOL
GetRegistryConfig(
LPCWSTR RegKeyPath, // IN - driver registry key path
DWORD * lpdwBaseAddr, // OUT - base address
DWORD * lpdwAddrLen, // OUT - address range
DWORD * lpdwIOSpace, // OUT - 1 if base address describes I/O port, 0 otherwise
DWORD * lpdwSysIntr, // OUT - system interrupt number
PINTERFACE_TYPE lpIfcType, // OUT - interface type (PCIbus, ISAbus, etc)
DWORD * lpdwBusNumber, // OUT - bus number, depends on interface type
BOOL * bInstallIsr, // OUT - TRUE if ISR Handler found in registry
LPWSTR IsrDll, // OUT - Name of ISR Handler dll
LPWSTR IsrHandler, // OUT - Name of ISR Handler routine
DWORD * Irq // OUT - IRQ number, used to hook ISR handler
)
{
HKEY hKey = NULL;
BOOL fRet=FALSE;
DWORD dwRet;
// initialize with default values
*lpdwBaseAddr = (DWORD) v_pDCUSBReg->Revision;
*lpdwAddrLen = SK_USB_HCI_SPACE;
*lpdwIOSpace = 0;
*lpdwSysIntr = dwSysIntrOhciMdd;
*lpIfcType = Isa;
*bInstallIsr = FALSE;
*lpdwBusNumber = 0;
IsrDll[0] = 0;
IsrHandler[0] = 0;
*Irq = 0;
// Open key
dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,RegKeyPath,0,0,&hKey);
if (dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR,(TEXT("!UHCD:GetRegistryConfig RegOpenKeyEx(%s) failed %d\r\n"),
RegKeyPath, dwRet));
} else {
DWORD dwData;
DWORD dwSize;
DWORD dwType;
// read registry data
dwSize = sizeof(dwData);
dwRet = RegQueryValueEx(hKey,IRQ_VALUE_NAME,0,&dwType,(PUCHAR)&dwData,&dwSize);
if (dwRet == ERROR_SUCCESS) {
*lpdwSysIntr = dwData;
}
dwSize = sizeof(dwData);
dwRet = RegQueryValueEx(hKey,IOBASE_VALUE_NAME,0,&dwType,(PUCHAR)&dwData,&dwSize);
if (dwRet == ERROR_SUCCESS) {
*lpdwBaseAddr = dwData;
}
}
fRet = TRUE;
if(hKey != NULL) RegCloseKey(hKey);
return fRet;
} // GetRegistryConfig
/* ConfigureUHCICard
*
*/
BOOL
ConfigureUHCICard(
PUCHAR *pioPortBase, // IN - contains physical address of register base
// OUT- contains virtual address of register base
DWORD dwAddrLen,
DWORD dwIOSpace,
INTERFACE_TYPE IfcType,
DWORD dwBusNumber
)
{
#ifdef TRANSLATE_ADDRESSES
ULONG inIoSpace = dwIOSpace;
ULONG portBase;
PHYSICAL_ADDRESS ioPhysicalBase = {0, 0};
portBase = (ULONG)*pioPortBase;
ioPhysicalBase.LowPart = portBase;
if (!TransBusAddrToVirtual(IfcType, dwBusNumber, ioPhysicalBase, dwAddrLen, &inIoSpace, (PPVOID)pioPortBase)) {
DEBUGMSG(ZONE_ERROR, (L"UHCD: Failed TransBusAddrToVirtual\r\n"));
return FALSE;
}
DEBUGMSG(ZONE_INIT,
(TEXT("UHCD: ioPhysicalBase 0x%X, IoSpace 0x%X\r\n"),
ioPhysicalBase.LowPart, inIoSpace));
DEBUGMSG(ZONE_INIT,
(TEXT("UHCD: ioPortBase 0x%X, portBase 0x%X\r\n"),
*pioPortBase, portBase));
#else
UnusedParameter(pioPortBase);
UnusedParameter(dwAddrLen);
UnusedParameter(dwIOSpace);
UnusedParameter(IfcType);
UnusedParameter(dwBusNumber);
#endif
return TRUE;
}
/* InitializeUHCI
*
* Configure and initialize UHCI card
*
* Return Value:
* Return TRUE if card could be located and configured, otherwise FALSE
*/
static BOOL
InitializeUHCI(
SUhcdPdd * pPddObject, // IN - Pointer to PDD structure
LPCWSTR szDriverRegKey) // IN - Pointer to active registry key string
{
PUCHAR ioPortBase = NULL;
DWORD dwAddrLen;
DWORD dwIOSpace;
DWORD dwSysIntr;
INTERFACE_TYPE IfcType;
DWORD dwBusNumber;
BOOL InstallIsr = FALSE;
WCHAR IsrDll[DEVDLL_LEN];
WCHAR IsrHandler[DEVENTRY_LEN];
DWORD Irq = -1;
BOOL fResult = FALSE;
LPVOID pobMem = NULL;
LPVOID pobUhcd = NULL;
DWORD PhysAddr;
// reset the host controller and enable its clocks
OHCI_Reset();
if (!GetRegistryConfig(szDriverRegKey, &PhysAddr, &dwAddrLen, &dwIOSpace, &dwSysIntr, &IfcType, &dwBusNumber, &InstallIsr, IsrDll, IsrHandler, &Irq)) {
RETAILMSG(1,(TEXT("!UHCD: Error reading registry settings\r\n")));
return FALSE;
}
DEBUGMSG(ZONE_INIT,(TEXT("InitializeUHCI: Read config from registry: Base Address: 0x%X, Length: 0x%X, I/O Port: %s, SysIntr: 0x%X, Interface Type: %u, Bus Number: %u\r\n"),
PhysAddr, dwAddrLen, dwIOSpace ? L"YES" : L"NO", dwSysIntr, IfcType, dwBusNumber));
ioPortBase = (PUCHAR)PhysAddr;
if (!(fResult = ConfigureUHCICard(&ioPortBase, dwAddrLen, dwIOSpace, IfcType, dwBusNumber))) {
goto InitializeUHCI_Error;
}
#ifndef OSV_LOCAL_MERLIN
// The following is only supported in Jameson, but this
// code is for a Merlin build
if (InstallIsr) {
// Install ISR handler
g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);
if (!g_IsrHandle) {
DEBUGMSG(ZONE_ERROR, (L"UHCD: Couldn't install ISR handler\r\n"));
} else {
GIISR_INFO Info;
PHYSICAL_ADDRESS PortAddress = {PhysAddr, 0};
DEBUGMSG(ZONE_INIT, (L"UHCD: Installed ISR handler, Dll = '%s', Handler = '%s', Irq = %d\r\n",
IsrDll, IsrHandler, Irq));
if (!TransBusAddrToStatic(IfcType, dwBusNumber, PortAddress, dwAddrLen, &dwIOSpace, &(PVOID)PhysAddr)) {
DEBUGMSG(ZONE_ERROR, (L"UHCD: Failed TransBusAddrToStatic\r\n"));
return FALSE;
}
// Set up ISR handler
Info.SysIntr = dwSysIntr;
Info.CheckPort = TRUE;
Info.PortIsIO = (dwIOSpace) ? TRUE : FALSE;
Info.UseMaskReg = TRUE;
Info.PortAddr = PhysAddr + 0x0C;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -