📄 trans.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.
//
//
// 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:
// Trans.cpp
//
// Abstract: Provides interface to UHCI host controller
//
// Notes:
//
#include <windows.h>
#include <Cphysmem.hpp>
#include "trans.h"
#include "cpipe.h"
#include "chw.h"
#include "cehcd.h"
#ifndef _PREFAST_
#pragma warning(disable: 4068) // Disable pragma warnings
#endif
DWORD CTransfer::m_dwGlobalTransferID=0;
CTransfer::CTransfer(IN CPipe * const pCPipe, IN CPhysMem * const pCPhysMem,STransfer sTransfer)
: m_sTransfer( sTransfer)
, m_pCPipe(pCPipe)
, m_pCPhysMem(pCPhysMem)
{
m_pNextTransfer=NULL;
m_paControlHeader=0;
m_pAllocatedForControl=NULL;
m_pAllocatedForClient=NULL;
memcpy(&m_sTransfer, &sTransfer,sizeof(STransfer));
m_DataTransferred =0 ;
m_dwCurrentPermissions = GetCurrentPermissions();
m_dwTransferID = m_dwGlobalTransferID++;
}
CTransfer::~CTransfer()
{
if (m_pAllocatedForControl!=NULL)
m_pCPhysMem->FreeMemory( PUCHAR(m_pAllocatedForControl),m_paControlHeader, CPHYSMEM_FLAG_NOBLOCK );
if (m_pAllocatedForClient!=NULL)
m_pCPhysMem->FreeMemory( PUCHAR(m_pAllocatedForClient), m_sTransfer.paBuffer, CPHYSMEM_FLAG_NOBLOCK );
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE , (TEXT("CTransfer::~CTransfer() (this=0x%x,m_pAllocatedForControl=0x%x,m_pAllocatedForClient=0x%x)\r\n"),
this,m_pAllocatedForControl,m_pAllocatedForClient));
}
BOOL CTransfer::Init(void)
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CTransfer::Init (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
// We must allocate the control header memory here so that cleanup works later.
if (m_sTransfer.lpvControlHeader != NULL && m_pAllocatedForControl == NULL ) {
// This must be a control transfer. It is asserted elsewhere,
// but the worst case is we needlessly allocate some physmem.
if ( !m_pCPhysMem->AllocateMemory(
DEBUG_PARAM( TEXT("IssueTransfer SETUP Buffer") )
sizeof(USB_DEVICE_REQUEST),
&m_pAllocatedForControl,
CPHYSMEM_FLAG_NOBLOCK ) ) {
DEBUGMSG( ZONE_WARNING, (TEXT("CPipe(%s)::IssueTransfer - no memory for SETUP buffer\n"), m_pCPipe->GetPipeType() ) );
m_pAllocatedForControl=NULL;
return FALSE;
}
m_paControlHeader = m_pCPhysMem->VaToPa( m_pAllocatedForControl );
DEBUGCHK( m_pAllocatedForControl != NULL && m_paControlHeader != 0 );
__try {
memcpy(m_pAllocatedForControl,m_sTransfer.lpvControlHeader,sizeof(USB_DEVICE_REQUEST));
} __except( EXCEPTION_EXECUTE_HANDLER ) {
// bad lpvControlHeader
return FALSE;
}
}
#ifdef DEBUG
if ( m_sTransfer.dwFlags & USB_IN_TRANSFER ) {
// I am leaving this in for two reasons:
// 1. The memset ought to work even on zero bytes to NULL.
// 2. Why would anyone really want to do a zero length IN?
DEBUGCHK( m_sTransfer.dwBufferSize > 0 &&
m_sTransfer.lpvBuffer != NULL );
__try { // IN buffer, trash it
memset( PUCHAR( m_sTransfer.lpvBuffer ), GARBAGE, m_sTransfer.dwBufferSize );
} __except( EXCEPTION_EXECUTE_HANDLER ) {
}
}
#endif // DEBUG
if ( m_sTransfer.dwBufferSize > 0 && m_sTransfer.paBuffer == 0 ) {
// ok, there's data on this transfer and the client
// did not specify a physical address for the
// buffer. So, we need to allocate our own.
if ( !m_pCPhysMem->AllocateMemory(
DEBUG_PARAM( TEXT("IssueTransfer Buffer") )
m_sTransfer.dwBufferSize,
&m_pAllocatedForClient,
CPHYSMEM_FLAG_NOBLOCK ) ) {
DEBUGMSG( ZONE_WARNING, (TEXT("CPipe(%s)::IssueTransfer - no memory for TD buffer\n"), m_pCPipe->GetPipeType() ) );
m_pAllocatedForClient = NULL;
return FALSE;
}
m_sTransfer.paBuffer = m_pCPhysMem->VaToPa( m_pAllocatedForClient );
PREFAST_DEBUGCHK( m_pAllocatedForClient != NULL);
PREFAST_DEBUGCHK( m_sTransfer.lpvBuffer!=NULL);
DEBUGCHK(m_sTransfer.paBuffer != 0 );
if ( !(m_sTransfer.dwFlags & USB_IN_TRANSFER) ) {
__try { // copying client buffer for OUT transfer
memcpy( m_pAllocatedForClient, m_sTransfer.lpvBuffer, m_sTransfer.dwBufferSize );
} __except( EXCEPTION_EXECUTE_HANDLER ) {
// bad lpvClientBuffer
return FALSE;
}
}
}
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE , (TEXT("CQTransfer::Init (this=0x%x,id=0x%x),m_pAllocatedForControl=0x%x,m_pAllocatedForClient=0x%x\r\n"),
this,m_dwTransferID,m_pAllocatedForControl,m_pAllocatedForClient));
return AddTransfer();
}
CQTransfer::~CQTransfer()
{
CQTD * pCurTD = m_pCQTDList;
while (pCurTD!=NULL) {
CQTD * pNextTD = pCurTD->GetNextTD();
pCurTD->~CQTD();
m_pCPhysMem->FreeMemory((PBYTE)pCurTD,m_pCPhysMem->VaToPa((PBYTE)pCurTD), CPHYSMEM_FLAG_HIGHPRIORITY |CPHYSMEM_FLAG_NOBLOCK );
pCurTD = pNextTD;
}
}
BOOL CQTransfer::AddTransfer()
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CQTransfer::AddTransfer (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
if (m_pCQTDList) { // Has been created. Somthing wrong.
ASSERT(FALSE);
return FALSE;
}
BOOL bDataToggle1= FALSE;
CQTD * pStatusTD = NULL;
if (m_paControlHeader!=NULL && m_sTransfer.lpvControlHeader!=NULL) {
// This is setup packet.
if (m_pCQTDList = new(m_pCPhysMem) CQTD(this, ((CQueuedPipe * const)m_pCPipe)->GetQHead())) {
PhysBufferArray bufferArray;
bufferArray.dwNumOfBlock=1;
bufferArray.dwStartOffset=m_paControlHeader & EHCI_PAGE_OFFSET_MASK;
bufferArray.dwBlockSize=min(bufferArray.dwStartOffset + sizeof(USB_DEVICE_REQUEST),EHCI_PAGE_SIZE );
bufferArray.dwArrayBlockAddr[0]=(m_paControlHeader & EHCI_PAGE_ADDR_MASK);
bufferArray.dwArrayBlockAddr[1]=((m_paControlHeader+sizeof(USB_DEVICE_REQUEST)) & EHCI_PAGE_ADDR_MASK ); // Terminate
m_pCQTDList->IssueTransfer( TD_SETUP_PID, bDataToggle1, sizeof(USB_DEVICE_REQUEST),&bufferArray,TRUE);
bDataToggle1 = !bDataToggle1;
}
else
return FALSE;
// Status Packet
pStatusTD = new(m_pCPhysMem) CQTD(this, ((CQueuedPipe * const)m_pCPipe)->GetQHead());
if (pStatusTD) {
PhysBufferArray bufferArray;
bufferArray.dwNumOfBlock=0;
bufferArray.dwBlockSize=0;
bufferArray.dwStartOffset=0;
bufferArray.dwArrayBlockAddr[0]=0;
bufferArray.dwArrayBlockAddr[1]=0;// Terminate
pStatusTD->IssueTransfer( (m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0?TD_OUT_PID:TD_IN_PID,
TRUE, 0 ,&bufferArray,TRUE);
}
else
return FALSE;
};
CQTD * pPrevTD=m_pCQTDList;
if (m_sTransfer.lpvBuffer && m_sTransfer.paBuffer && m_sTransfer.dwBufferSize) {
DWORD dwCurPos=0;
while ( dwCurPos< m_sTransfer.dwBufferSize) {
CQTD * pCurTD = new( m_pCPhysMem) CQTD(this, ((CQueuedPipe * const)m_pCPipe)->GetQHead());
ASSERT(pCurTD!=NULL);
if (pCurTD==NULL) {
// delete pStatusTD;
if ( pStatusTD) {
pStatusTD->~CQTD();
m_pCPhysMem->FreeMemory((PBYTE)pStatusTD,m_pCPhysMem->VaToPa((PBYTE)pStatusTD), CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK );
}
return FALSE;
}
DWORD dwCurPhysAddr= m_sTransfer.paBuffer + dwCurPos;
// We only can queue maximun 4 page for one TD and Align with Packet Size.
DWORD dwPacketSize= (m_pCPipe->GetEndptDescriptor()).wMaxPacketSize & 0x7ff;
ASSERT(dwPacketSize!=0);
DWORD dwCurLength = ((EHCI_PAGE_SIZE * MAX_QTD_PAGE_SIZE)/dwPacketSize)*dwPacketSize;
dwCurLength = min( m_sTransfer.dwBufferSize- dwCurPos,dwCurLength);
PhysBufferArray bufferArray;
bufferArray.dwNumOfBlock= (dwCurLength + EHCI_PAGE_SIZE -1 ) /EHCI_PAGE_SIZE;
ASSERT(bufferArray.dwNumOfBlock<=MAX_QTD_PAGE_SIZE && bufferArray.dwNumOfBlock!=0);
bufferArray.dwStartOffset= dwCurPhysAddr & EHCI_PAGE_OFFSET_MASK;
bufferArray.dwBlockSize = min (bufferArray.dwStartOffset + m_sTransfer.dwBufferSize- dwCurPos,EHCI_PAGE_SIZE);
for (DWORD dwIndex=0;dwIndex<bufferArray.dwNumOfBlock+1 && dwIndex<5;dwIndex++) {
bufferArray.dwArrayBlockAddr[dwIndex] = (dwCurPhysAddr & EHCI_PAGE_ADDR_MASK);
dwCurPhysAddr += EHCI_PAGE_SIZE;
}
DWORD dwReturnLength = pCurTD->IssueTransfer( (m_sTransfer.dwFlags & USB_IN_TRANSFER)!=0?TD_IN_PID:TD_OUT_PID,
bDataToggle1, dwCurLength,&bufferArray,TRUE);
ASSERT(dwReturnLength == dwCurLength);
// Setup for Short Packet
if ( pStatusTD) {
pCurTD->SetAltNextQTDPointer(pStatusTD->GetPhysAddr());
}
DWORD dwNumOfPacket = (dwReturnLength + dwPacketSize-1)/dwPacketSize;
dwCurPos += dwReturnLength;
if (pPrevTD) {
pPrevTD->QueueNextTD(pCurTD);
pPrevTD=pCurTD;
}
else { // THis is First. So update m_pQTDList
pPrevTD= m_pCQTDList = pCurTD;
}
if ((dwNumOfPacket & 1)!=0) // if it is odd packet number. Toggle the data toggle.
bDataToggle1 = !bDataToggle1;
}
}
// We have to append Status TD here.
if (pStatusTD) { // This is setup packet.
if (pPrevTD) {
pPrevTD->QueueNextTD(pStatusTD);
pPrevTD=pStatusTD;
}
else { // Something Wrong.
ASSERT(FALSE);
//delete pCurTD;
pStatusTD->~CQTD();
m_pCPhysMem->FreeMemory((PBYTE)pStatusTD,m_pCPhysMem->VaToPa((PBYTE)pStatusTD), CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK );
return FALSE;
}
};
return TRUE;
}
BOOL CQTransfer::DoneTransfer()
{
DEBUGMSG( ZONE_TRANSFER && ZONE_VERBOSE, (TEXT("CQTransfer::DoneTransfer (this=0x%x,id=0x%x)\r\n"),this,m_dwTransferID));
BOOL bIsTransDone = IsTransferDone();
ASSERT(bIsTransDone == TRUE);
if (bIsTransDone) {
DWORD dwUsbError = USB_NO_ERROR;
DWORD dwDataNotTransferred = 0;
CQTD * pCurTD = m_pCQTDList;
BOOL bReturn=TRUE;
while ( pCurTD!=NULL) {
pCurTD->CheckStructure();
if ( pCurTD->qTD_Token.qTD_TContext.PID != 2) // Do not count Setup TD
dwDataNotTransferred += pCurTD ->qTD_Token.qTD_TContext.BytesToTransfer ;
if (pCurTD->qTD_Token.qTD_TContext.Halted==1) { // This Transfer Has been halted due to error.
// This is error. We do not have error code for EHCI so generically we set STALL error.
if (dwUsbError == USB_NO_ERROR)
dwUsbError = USB_STALL_ERROR;
}
else
if (pCurTD->qTD_Token.qTD_TContext.Active ==1) {
if (dwUsbError == USB_NO_ERROR)
dwUsbError = USB_NOT_COMPLETE_ERROR;
break;
}
pCurTD = pCurTD->GetNextTD();
}
ASSERT(dwDataNotTransferred <= m_sTransfer.dwBufferSize);
if (dwDataNotTransferred >= m_sTransfer.dwBufferSize)
dwDataNotTransferred = m_sTransfer.dwBufferSize;
m_DataTransferred = m_sTransfer.dwBufferSize - dwDataNotTransferred ;
DWORD dwOldPermissions = SetProcPermissions(m_dwCurrentPermissions);
// We have to update the buffer when this is IN Transfer.
if ((m_sTransfer.dwFlags & USB_IN_TRANSFER)!=NULL && m_pAllocatedForClient!=NULL && m_sTransfer.dwBufferSize!=0) {
__try { // copying client buffer for OUT transfer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -