📄 ohcdpdd.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.
//
/*++
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.
Module Name:
system.c
Abstract:
Device dependant part of the USB Universal Host Controller Driver (UHCD).
Notes:
--*/
#ifdef USBOHCI_DMA_IN_SRAM
#pragma message ("OHCI using Internal SRAM")
#else
#pragma message ("OHCI using SDRAM")
#endif
#ifdef OSV_LOCAL_MERLIN
#pragma message ("build is for MERLIN")
#else
#pragma message ("build is not for MERLIN")
#endif
#ifdef TRANSLATE_ADDRESSES
#pragma message ("build is for TRANSLATE_ADDRESSES")
#else
#pragma message ("build is not for TRANSLATE_ADDRESSES")
#endif
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <devload.h>
#include <uhcdddsi.h>
#include "bvd1.h"
// Bulverde will use XLLP library to
// access GPIOs and Clocks.
#include "xllp_gpio.h"
#include "xllp_clkmgr.h"
#include "xllp_usbohci.h"
// Registry key and value names
#define OHCI_DRIVER_KEY TEXT("Drivers\\BuiltIn\\OHCI")
#define IRQ_VALUE_NAME TEXT("Irq")
#define IOBASE_VALUE_NAME TEXT("MemBase")
extern void msWait(unsigned msVal);
extern void usWait(unsigned msVal);
extern PVOID VirtualAllocCopy(unsigned size,char *str,PVOID pVirtualAddress);
void TurnOnSRAMClocks();
// Amount of memory to use for HCD buffer
extern DWORD gcTotalAvailablePhysicalMemory;// = OHCI_DMA_BUFFER_SIZE; //28672; // 28K
extern DWORD gcHighPriorityPhysicalMemory;// = OHCI_DMA_BUFFER_HIGHPRI_SIZE; //0x5000; // 20K
extern DWORD dwSysIntrOhciMdd;//=SYSINTR_OHCI_MDD;
extern DWORD dwSysIntrOhciPdd;//=SYSINTR_OHCI_PDD
//Dma Buffer
extern DWORD dwOhciDmaBufferPhysical;//=OHCI_DMA_BUFFER_PHYSICAL
extern PVOID pOhciDmaBufferVirtual;//=OHCI_DMA_BUFFER_U_VIRTUAL
extern DWORD dwOhciDmaBufferSize;//=OHCI_DMA_BUFFER_SIZE
volatile XLLP_CLKMGR_T *v_pDCCLKReg;
XLLP_GPIO_T *v_pDCGPIOReg;
volatile XLLP_USBOHCI_T *v_pDCUSBOHCIReg;
PVOID v_pOHCIDMABuffer;
volatile MEMC_STRUCT *v_pDCMEMCReg; // on the cotulla, xsc1.h
// Interrupt Service Thread Globals
VOID *gOHCIPDDIntrEvent;
VOID *gOHCIPDDIntrThread;
static HANDLE g_IsrHandle = NULL;
typedef struct _SUhcdPdd
{
LPVOID lpvMemoryObject;
LPVOID lpvUhcdMddObject;
PVOID pvVirtualAddress; // DMA buffers as seen by the CPU
PHYSICAL_ADDRESS LogicalAddress; // DMA buffers as seen by the DMA controller and bus interfaces
DMA_ADAPTER_OBJECT AdapterObject;
TCHAR szDriverRegKey[MAX_PATH];
PUCHAR ioPortBase;
DWORD dwSysIntr;
CRITICAL_SECTION csPdd; // serializes access to the PDD object
} SUhcdPdd;
#define UnusedParameter(x) x = x
// set up virtual addresses for registers on the sa11x1
BOOL
OhcdPddInitializeAddresses(void)
{
// the bulverde needs access to the clkmgr to enable the USBHOST clock
v_pDCCLKReg = (volatile XLLP_CLKMGR_T*)
VirtualAllocCopy(sizeof(XLLP_CLKMGR_T), "OHCI v_pDCCLKReg", (PVOID)(CLK_BASE_U_VIRTUAL));
if( v_pDCCLKReg == NULL ) {
goto error_return;
}
// the bulverde needs access to the gpio regs to set up the gpios that
// are tied to the external MAX1693EUB USB Power Switch
v_pDCGPIOReg = (/*volatile*/ XLLP_GPIO_T*)
VirtualAllocCopy(sizeof(XLLP_GPIO_T), "OHCI v_pDCGPIOReg", (PVOID)(GPIO_BASE_U_VIRTUAL));
if( v_pDCCLKReg == NULL ) {
goto error_return;
}
// map the usb ohci register block.
// use the old cotulla global pointer for now.
// later, during code clean up, consolidate the two pointers into one
// and reconcile their usage differences.
v_pDCUSBOHCIReg = (volatile XLLP_USBOHCI_T*)
VirtualAllocCopy(sizeof(XLLP_USBOHCI_T),"OHCI v_pDCUSBOHCIReg: ",(PVOID)(USBH_BASE_U_VIRTUAL));
if (v_pDCUSBOHCIReg == NULL) {
goto error_return;
}
#ifdef USBOHCI_DMA_IN_SRAM
// initialize the sram here.
{
volatile unsigned long *v_pDCIMReg = NULL;
// map the memory
v_pDCIMReg = (volatile unsigned long*)VirtualAllocCopy(
sizeof( 64 * sizeof( volatile unsigned long ) ),
"OHCI v_pDCIMReg: ",
(PVOID)(IM_CONTROL_BASE_U_VIRTUAL)
);
if( v_pDCIMReg == NULL )
{
// error
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: failed mapping v_pDCIMReg to %08x.\r\n"), IM_CONTROL_BASE_U_VIRTUAL));
}
else
{
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCIMReg: %08x = %08x.\r\n"), v_pDCIMReg,IM_CONTROL_BASE_U_VIRTUAL));
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCIMReg: impmr %08x.\r\n"), v_pDCIMReg[0] ));
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCIMReg: impsr %08x.\r\n"), v_pDCIMReg[2] ));
// I don't think the imrmr register really exists
//RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCIMReg: imrmr %08x.\r\n"), v_pDCIMReg[4] ));
// test access to this memory
v_pDCIMReg[0] = 188; // the control register, 0 enables all internal sram banks, disables auto-wake and disables entry to standby
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCIMReg:Mimpmr %08x.\r\n"), v_pDCIMReg[0] ));
// set the bank power control, auto wake enable, and DST fields
v_pDCIMReg[0] = 0; // the control register, 0 enables all internal sram banks, disables auto-wake and disables entry to standby
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCIMReg:Fimpmr %08x.\r\n"), v_pDCIMReg[0] ));
// free the mapped memory
VirtualFree((PVOID)v_pDCIMReg,0,MEM_RELEASE);
}
}
v_pOHCIDMABuffer =
// VirtualAllocCopy(OHCI_DMA_BUFFER_SIZE,"OHCI v_pOHCIDMABuffer", (PVOID) OHCI_DMA_BUFFER_U_VIRTUAL);
VirtualAllocCopy(dwOhciDmaBufferSize,"OHCI v_pOHCIDMABuffer", (PVOID)(IM_STORAGE_BASE_U_VIRTUAL +0x30000));
if (v_pOHCIDMABuffer == NULL) {
goto error_return;
}
{
// Test access to the OHCIDMABuffer:
volatile unsigned long *pulTemp = (volatile unsigned long*)v_pOHCIDMABuffer;
// the SRAM needs to be clocked, just like other memory and peripherals.
TurnOnSRAMClocks();
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: testing access to OHCIDMABuffer %08x mapped to %08x.\r\n"), IM_STORAGE_BASE_U_VIRTUAL+0x30000, pulTemp ));
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: 00-0f: %08x %08x %08x %08x\r\n"), pulTemp[0], pulTemp[1], pulTemp[2], pulTemp[3] ));
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: 10-1f: %08x %08x %08x %08x\r\n"), pulTemp[4], pulTemp[5], pulTemp[6], pulTemp[7] ));
pulTemp[0] = 188;
pulTemp[1] = 189;
pulTemp[2] = 190;
pulTemp[3] = 191;
pulTemp[4] = 192;
pulTemp[5] = 193;
pulTemp[6] = 194;
pulTemp[7] = 195;
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses:M00-0f: %08x %08x %08x %08x\r\n"), pulTemp[0], pulTemp[1], pulTemp[2], pulTemp[3] ));
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses:M10-1f: %08x %08x %08x %08x\r\n"), pulTemp[4], pulTemp[5], pulTemp[6], pulTemp[7] ));
}
// change the value of a global pointer that contains the uncached virtual address
// of the memory buffer used to hold the usb structures. usb structures are built
// in this area, and the USB OHCI reads and writes to this area, also.
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: dwohciBPhy: old %08x.\r\n"), dwOhciDmaBufferPhysical));
dwOhciDmaBufferPhysical = (IM_STORAGE_BASE_PHYSICAL+0x30000);
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: dwohciBPhy: new %08x.\r\n"), dwOhciDmaBufferPhysical));
#else
v_pOHCIDMABuffer =
// VirtualAllocCopy(OHCI_DMA_BUFFER_SIZE,"OHCI v_pOHCIDMABuffer", (PVOID) OHCI_DMA_BUFFER_U_VIRTUAL);
VirtualAllocCopy(dwOhciDmaBufferSize,"OHCI v_pOHCIDMABuffer", pOhciDmaBufferVirtual);
if (v_pOHCIDMABuffer == NULL) {
goto error_return;
}
#endif
// RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCCLKReg: %08x = %08x.\r\n"), v_pDCCLKReg,CLK_BASE_U_VIRTUAL));
// RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCGPIOReg: %08x = %08x.\r\n"), v_pDCGPIOReg,GPIO_BASE_U_VIRTUAL));
#ifdef USBOHCI_DMA_IN_SRAM
RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pOHCIDMABuffer: %08x = %08x.\r\n"), v_pOHCIDMABuffer,IM_STORAGE_BASE_U_VIRTUAL+0x30000));
#else
// RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pOHCIDMABuffer: %08x = %08x.\r\n"), v_pOHCIDMABuffer,pOhciDmaBufferVirtual));
#endif
// RETAILMSG(ZONE_INIT,(TEXT("OhcdPddInitializeAddresses: v_pDCUSBOHCIReg: %08x = %08x.\r\n"), v_pDCUSBOHCIReg,USBH_BASE_U_VIRTUAL));
return TRUE;
error_return:
ERRORMSG(1,(TEXT("OHCI Driver InitializeAddresses: Failed!.\r\n")));
if (v_pDCCLKReg) VirtualFree((PVOID)v_pDCCLKReg,0,MEM_RELEASE);
if (v_pDCGPIOReg) VirtualFree((PVOID)v_pDCGPIOReg,0,MEM_RELEASE);
if (v_pDCUSBOHCIReg) VirtualFree((PVOID)v_pDCUSBOHCIReg,0,MEM_RELEASE);
if (v_pOHCIDMABuffer) VirtualFree((PVOID)v_pOHCIDMABuffer,0,MEM_RELEASE);
v_pDCCLKReg = 0;
v_pDCGPIOReg = 0;
v_pDCUSBOHCIReg = 0;
v_pOHCIDMABuffer = 0;
return 0;
}
VOID OHCI_Reset()
{
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;
msWait( 1 ); // 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.
RETAILMSG(1,(TEXT("OHCI_Reset: done.\r\n")));
}
// 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);
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;
}
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 (FALSE);
} else {
DEBUGMSG(ZONE_INIT, (TEXT("-OHCIPDD Init\r\n")));
//return TRUE;
}
*/
RETAILMSG(1, (TEXT("InitPddInterrupts RhPortStatus: 0x%x.\r\n"), v_pDCUSBOHCIReg->uhcrhs));
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -