?? phcd.cpp
字號:
TEXT("GET_DESCRIPTOR"),
TEXT("SET_DESCRIPTOR"),
TEXT("GET_CONFIGURATION"),
TEXT("SET_CONFIGURATION"),
TEXT("GET_INTERFACE"),
TEXT("SET_INTERFACE"),
TEXT("SYNC_FRAME")
};
static const TCHAR *aszPortFeatureStrings[] =
{
TEXT("PORT_CONNECTION"),
TEXT("PORT_ENABLE"),
TEXT("PORT_SUSPEND"),
TEXT("PORT_OVER_CURRENT"),
TEXT("PORT_RESET"),
TEXT("RSVD (5)"),
TEXT("RSVD (6)"),
TEXT("RSVD (7)"),
TEXT("PORT_POWER"),
TEXT("PORT_LOW_SPEED"),
TEXT("RSVD (10)"),
TEXT("RSVD (11)"),
TEXT("RSVD (12)"),
TEXT("RSVD (13)"),
TEXT("RSVD (14)"),
TEXT("RSVD (15)"),
TEXT("C_PORT_CONNECTION"),
TEXT("C_PORT_ENABLE"),
TEXT("C_PORT_SUSPEND"),
TEXT("C_PORT_OVER_CURRENT"),
TEXT("C_PORT_RESET"),
};
static const TCHAR *aszHubFeatureStrings[] =
{
TEXT("LOCAL_POWER"),
TEXT("OVER_CURRENT")
};
inline const TCHAR *DecodeRequestString(UCHAR bRequest)
{
return ((bRequest < NUM_ELEMENTS(aszRequestStrings)) ?
aszRequestStrings[bRequest] : TEXT("Invalid"));
}
inline const TCHAR *DecodePortFeatureString(USHORT wValue)
{
return ((wValue < NUM_ELEMENTS(aszPortFeatureStrings)) ?
aszPortFeatureStrings[wValue]:TEXT("Invalid"));
}
inline const TCHAR *DecodeHubFeatureString(USHORT wValue)
{
return ((wValue < NUM_ELEMENTS(aszHubFeatureStrings)) ?
aszHubFeatureStrings[wValue]:TEXT("Invalid"));
}
// Routine to decode control transfers - somewhat incomplete, add further decoding
// as necessary...
void
CPhcd::DecodeControlTransfer(SEndpoint * pEndpt, PUSB_DEVICE_REQUEST pDr)
{
SDevice *pDev;
EnterCriticalSection(&m_csDeviceListLock);
pDev = m_ppDevices[pEndpt->pEd->bfFunctionAddress];
LeaveCriticalSection(&m_csDeviceListLock);
if (!pDev)
return;
// We only care about EP 0 transfers
if (pEndpt->endptArrayNum == gcEndpoint0Addr)
{
if (pDr->bmRequestType & USB_REQUEST_CLASS)
{
if (pDev->pHubPorts)
{
// Treat this as a hub request
switch (pDr->bRequest) {
case USB_REQUEST_SET_FEATURE:
case USB_REQUEST_CLEAR_FEATURE:
// Port 0 == hub command, else port command
DEBUGMSG(ISPDBG,(TEXT("PHCD::Control (HUB %X): %s_FEATURE, %s, port:%u\r\n"),pDev,
(pDr->bRequest == USB_REQUEST_SET_FEATURE)? TEXT("SET") : TEXT("CLEAR"),
(pDr->wIndex == 0) ? DecodeHubFeatureString(pDr->wValue) : DecodePortFeatureString(pDr->wValue),
pDr->wIndex));
break;
default:
DEBUGMSG(ISPDBG,(TEXT("PHCD::Control (HUB %X): %s Val: %u, Idx: %u, Len: %u\r\n"),pDev,
DecodeRequestString(pDr->bRequest),pDr->wValue, pDr->wIndex,pDr->wLength));
break;
}
}
else
RETAILMSG(1,(TEXT("PHCD::Control (CLASS %X): %s Val: %u, Idx: %u, Len: %u\r\n"),pDev,
DecodeRequestString(pDr->bRequest),pDr->wValue, pDr->wIndex,pDr->wLength));
}
else
{
// Device request
RETAILMSG(1,(TEXT("PHCD:Control (DEV %X): %s Val: %u, Idx: %u, Len: %u\r\n"),pDev,
DecodeRequestString(pDr->bRequest),pDr->wValue, pDr->wIndex,pDr->wLength));
}
}
}
//#endif // DEBUG
EError CPhcd::InitializeSchedule(void)
PBYTE virtAddr;
ULONG physAddr;
EError errorCode;
UINT numTds;
UINT td;
ULONG paEd;
REGISTER regBase = m_regBase;
SGeneralTransferDescriptor *pTd;
SIsochTransferDescriptor *pITd;
SEndpointDescriptor *pEd, *pPrevEd;
SDevice *pDev;
SEndpoint *pEndpt;
PBYTE pSetupBuffer;
ULONG paSetupBuffer;
STransfer *pTransfer;
RETAILMSG(ISPDBG,(TEXT("+PHCD::InitializeSchedule\r\n")));
// We're going to first get a good page aligned chunk of memory and divy
// it up between the HCCA and some ED/TDs
errorCode = ALLOC_PHYS_MEM(m_pobMem, USBPAGESIZE, &virtAddr,
&physAddr, USBALLOCF_SPECIAL, NULL);
// errorCode = m_pobMem->AllocateMemory(USBPAGESIZE, &virtAddr,
// &physAddr, USBALLOCF_SPECIAL);
if (errorCode != successful)
{
DEBUGMSG(ZONE_ERROR,
(TEXT("PHCD: Couldn't allocate memory for the HCCA and TDs\r\n")));
return(errorCode);
}
m_pHcca = virtAddr;
virtAddr += gcHccaByteSize;
physAddr += gcHccaByteSize;
// This isn't strictly necessary as obviously no one has used the TD Lists
// yet. But grabbing an unheld CS is practically free, so this can't hurt.
EnterCriticalSection(&m_csTdListsLock);
// That's 256 bytes out of 4K. Split the remaining memory between EDs, TDs
// and Isoch TDs. EDs and TDs are the same size, which is half that of
// IsochTDs, so just split the remaining memory in half and allocate as
// many of both kinds of TDs as each will allow. Note that we can make
// Tds into Eds and vice versa, so we'll just make TDs, not both.
numTds = gcNumExtraGeneralTds + (USBPAGESIZE - gcHccaByteSize) /
(sizeof(SGeneralTransferDescriptor) * 2);
m_pFreeTdList = (SGeneralTransferDescriptor *)virtAddr;
for (td = 0; td < numTds - 1; td++)
{
pTd = (SGeneralTransferDescriptor *)(virtAddr +
td * sizeof(SGeneralTransferDescriptor));
pTd->paNextTd = physAddr +
(td + 1) * sizeof(SGeneralTransferDescriptor);
}
pTd = (SGeneralTransferDescriptor *)(virtAddr +
(numTds - 1) * sizeof(SGeneralTransferDescriptor));
pTd->paNextTd = 0;
virtAddr += numTds * sizeof(SGeneralTransferDescriptor);
physAddr += numTds * sizeof(SGeneralTransferDescriptor);
// That did the general tds, Now finish off the page with isoch ones.
numTds = (USBPAGESIZE - (virtAddr - m_pHcca)) /
sizeof(SIsochTransferDescriptor);
m_pFreeITdList = (SIsochTransferDescriptor *)virtAddr;
for (td = 0; td < numTds - 1; td++)
{
pITd = (SIsochTransferDescriptor *)(virtAddr +
td * sizeof(SIsochTransferDescriptor));
pITd->paNextTd = physAddr +
(td + 1) * sizeof(SIsochTransferDescriptor);
}
pITd = (SIsochTransferDescriptor *)(virtAddr +
(td + 1) * sizeof(SIsochTransferDescriptor));
pITd->paNextTd = 0;
// Now that we've got storage set aside for a bunch of descriptors, let's
// set up the necessary list heads.
errorCode = InitializeInterruptEds();
if (errorCode != successful)
{
DEBUGMSG(ZONE_ERROR, (TEXT("PHCD: Error setting up InterruptEds\r\n")));
return(errorCode);
}
// Our scheduling lives will be made considerably easier if we put dummy
// Eds at the start of the bulk and control Lists. I've also seen
// comments in the NT code that suggests this is necessary for CMD parts.
pEd = (SEndpointDescriptor *)m_pFreeTdList;
m_pFreeTdList = (SGeneralTransferDescriptor *)
(m_pobMem->PaToVa(m_pFreeTdList->paNextTd));
// In the static Eds, the tail pointer points to itself and the
// head points to null. This is illegal for PHCI, but since the
// SKIP bit is set, the HC will never notice.
pEd->paTdQueueTail = paEd = m_pobMem->VaToPa((PBYTE)pEd);
pEd->paTdQueueHead = gcStaticEdIdentifier;
pEd->bfSkip = TRUE;
pEd->paNextEd = 0;
WRITE_REGISTER_ULONG(HcBulkHeadEd(regBase), paEd);
WRITE_REGISTER_ULONG(HcBulkCurrentEd(regBase), paEd);
pEd = (SEndpointDescriptor *)m_pFreeTdList;
m_pFreeTdList = (SGeneralTransferDescriptor *)
(m_pobMem->PaToVa(m_pFreeTdList->paNextTd));
pEd->paTdQueueTail = paEd = m_pobMem->VaToPa((PBYTE)pEd);
pEd->paTdQueueHead = gcStaticEdIdentifier;
pEd->bfSkip = TRUE;
pEd->paNextEd = 0;
WRITE_REGISTER_ULONG(HcControlHeadEd(regBase), paEd);
WRITE_REGISTER_ULONG(HcControlCurrentEd(regBase), paEd);
pPrevEd = pEd;
LeaveCriticalSection(&m_csTdListsLock);
// Now set up the Addr0 device and control endpoint.
pDev = AddDevice(0, 0, TRUE);
if (pDev == NULL)
return(error);
pEndpt = pDev->ppEndpts[gcEndpoint0Addr];
errorCode = ALLOC_PHYS_MEM(m_pobMem, sizeof(USB_DEVICE_REQUEST),
&pSetupBuffer, &paSetupBuffer, 0, NULL);
// errorCode = m_pobMem->AllocateMemory(sizeof(USB_DEVICE_REQUEST),
// &pSetupBuffer, &paSetupBuffer);
if (errorCode != successful)
{
DEBUGMSG(ZONE_ERROR,
(TEXT("PHCD: Couldn't allocate memory for the control queue\r\n")));
return(errorCode);
}
EnterCriticalSection(&m_csOtherListsLock);
if (m_pFreeTransferHead != NULL)
{
pTransfer = m_pFreeTransferHead;
m_pFreeTransferHead = pTransfer->pNext;
}
else
{
pTransfer = new STransfer;
}
LeaveCriticalSection(&m_csOtherListsLock);
pTransfer->lpbClientBuffer = NULL;
pTransfer->dwClientBufferPerms = 0;
pTransfer->lpCompletionParameter = NULL;
pTransfer->lpCompletionStartAddress = NULL;
pTransfer->lpCancelParameter = NULL;
pTransfer->lpCancelStartAddress = NULL;
pTransfer->lpvCancelId = NULL;
pTransfer->pfComplete = NULL;
pTransfer->pdwBytesTransfered = NULL;
pTransfer->pdwError = NULL;
pTransfer->adwIsochErrors = NULL;
pTransfer->adwIsochLengths = NULL;
pTransfer->pSetupBuffer = pSetupBuffer;
pTransfer->cbBuffer1 = 0;
pTransfer->pDataBuffer1 = NULL;
pTransfer->paDataBuffer1 = 0;
pTransfer->cbBuffer2 = 0;
pTransfer->pDataBuffer2 = NULL;
pTransfer->paDataBuffer2 = 0;
pTransfer->aCopyLengths = NULL;
pTransfer->pCopyLength = NULL;
#ifdef USE_CRITICAL_THREAD
pTransfer->cCriticalTds = 0;
#endif
pTransfer->cNormalTds = 0;
pTransfer->fCanceled = FALSE;
pTransfer->fActiveCanceled = FALSE;
pTransfer->fIn = FALSE;
pTransfer->fCompress = FALSE;
pTransfer->bufType = gcBufTypeUnused;
pTransfer->paLastTD = 0;
pTransfer->pNext = NULL;
pEndpt->pTransferHead = pTransfer;
RETAILMSG(ISPDBG,(TEXT("-PHCD::InitializeSchedule\r\n")));
return(successful);
}
// Don't even try to understand this without first reading the portion of
// the PHCI spec that describes the Interrupt Ed structure.
EError CPhcd::InitializeInterruptEds(void)
{
SEndpointDescriptor * pEd;
SEndpointDescriptor * pStaticEds[gcIntrNumStaticEds];
PULONG pEdListHead;
UINT ed;
UINT balanceEd = 0;
UINT extra = 0;
UINT balance[] =
{ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
ASSERT(m_pHcca != NULL);
DEBUGMSG(ISPDBG,(TEXT("+PHCD::InitializeInterruptEds\r\n")));
for (ed = 0; ed < gcIntrNumStaticEds; ed++)
{
pEd = (SEndpointDescriptor *)m_pFreeTdList;
m_pFreeTdList = (SGeneralTransferDescriptor *)
(m_pobMem->PaToVa(m_pFreeTdList->paNextTd));
// In the static intr eds, the tail pointer points to itself and the
// head points to null. This is illegal for PHCI, but since the
// SKIP bit is set, the HC will never notice.
pEd->paTdQueueTail = m_pobMem->VaToPa((PBYTE)pEd);
pEd->paTdQueueHead = gcStaticEdIdentifier;
pEd->bfSkip = TRUE;
pStaticEds[ed] = pEd;
if (ed != 0)
{
// Remember, this sets pEd->paNextEd to the Phys Addr of
// pStaticEds[(ed - 1)/2];
pEd->paNextEd = pStaticEds[(ed - 1) / 2]->paTdQueueTail;
}
else
{
// This is the last Interrupt Descriptor. Isoch descriptors
// go after these.
pEd->paNextEd = 0;
m_paLastIntrEd = m_pobMem->VaToPa((PBYTE)pEd);
}
if (ed >= gcIntrNumStaticEds - gcIntrNumListHeads)
{
// The final 32 go in the HCCA in a wierd order as defined by
// the balance array above.
// To save space, I used a balance array that is 1/2 as big as
// necessary. The second set of 16 values are equal to the first
// set with each being + 1 bigger.
pEdListHead = (PULONG)(m_pHcca +
4 * (balance[balanceEd] + extra));
*pEdListHead = pEd->paTdQueueTail; //pEd's PhysAddr
balanceEd++;
if (balanceEd > 15)
{
balanceEd = 0;
extra = 1;
}
}
}
DEBUGMSG(ISPDBG,(TEXT("-PHCD::InitializeInterruptEds\r\n")));
return(successful);
}
// Reset and initialize the HC hardware. Will leave the HC in RESET state, call
// EnterOperationalState() to actually start sending SOFs.
// Note: This function may be called within the context of a power handler routine,
// so cannot make any system calls if m_bPoweredUpAfterPowerDown is set!
EError CPhcd::InitializeHardware(void)
{
REGISTER regBase = m_regBase;
ULONG physAddr;
ULONG ulValue;
// if there was a previous driver changing the frame length then
// we want to clear this condition when the device goes through
// a warm reboot.
DEBUGMSG(ZONE_INIT && !m_bPoweredUpAfterPowerDown,
(TEXT("+PHCD::InitializeHardware\r\n")));
m_nAdjustFrame = 0;
m_fAdjust = FALSE;
m_hAdjustmentEvent = NULL;
// These registers need to be saved before we reset the HC
// because a software reset will zero them.
// They were already saved by the PowerManagementCallback if this is a warm boot.
if (!m_bPoweredUpAfterPowerDown)
{
m_paHcBulkHeadEdSave = READ_REGISTER_ULONG(HcBulkHeadEd(regBase));
m_paHcControlHeadEdSave = READ_REGISTER_ULONG(HcControlHeadEd(regBase));
}
// Reset the chip
ulValue = READ_REGISTER_ULONG(HcCommandStatus(regBase));
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -