⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trans.cpp

📁 嵌入式操作系统WINCE5.0下的USB驱动程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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 + -