📄 ufnmdd.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.
//
/*****************************************************************************
* Copyright (C) 2005-2006, Freescale Semiconductor, Inc. All Rights Reserved.
* THIS SOURCE CODE IS CONFIDENTIAL AND PROPRIETARY AND MAY NOT
* BE USED OR DISTRIBUTED WITHOUT THE WRITTEN PERMISSION OF
* Freescale Semiconductor, Inc.
*******************************************************************************/
/*++
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:
UFNMDD.CPP
Abstract:
USB Function Controller Model Device Driver Implementation.
--*/
#include "mx31_ufnmdd.h"
#include <devload.h>
#include <creg.hxx>
#define VERIFY_RUNNING() \
if (!pContext->fRunning) { \
DEBUGMSG(ZONE_ERROR, (_T("%s Device is not running\r\n"), pszFname)); \
dwRet = ERROR_INVALID_HANDLE; \
goto EXIT; \
}
#ifdef DEBUG
// Validate a context object.
VOID
ValidateContext(
PUFN_MDD_CONTEXT pContext
)
{
PREFAST_DEBUGCHK(pContext);
DEBUGCHK(pContext->dwSig == UFN_MDD_SIG);
if (pContext->Speed != BS_UNKNOWN_SPEED) {
DEBUGCHK(pContext->Speed & pContext->PddInfo.dwCapabilities);
}
if (!pContext->fClientIsBeingAddedOrRemoved) {
if (pContext->pUfnBus->IsClientActive()) {
DEBUGCHK(pContext->pPipes != NULL);
DEBUGCHK(pContext->pFreeTransferList);
}
else {
DEBUGCHK(pContext->pPipes == NULL);
DEBUGCHK(pContext->pFreeTransferList == NULL);
}
}
else {
DEBUGCHK(pContext->pPipes);
DEBUGCHK(pContext->pFreeTransferList);
}
}
#endif
#ifndef SHIP_BUILD
static
LPCTSTR
GetSpeedString(
UFN_BUS_SPEED Speed
)
{
LPCTSTR pszSpeed = _T("unknown");
if (Speed == BS_FULL_SPEED) {
pszSpeed = _T("full");
}
else if (Speed == BS_HIGH_SPEED) {
pszSpeed = _T("high");
}
return pszSpeed;
}
#endif
// Reset the pipe status table to its default state.
static
VOID
ResetPipeStatusTable(
PUFN_MDD_CONTEXT pContext
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
PREFAST_DEBUGCHK(pContext);
DEBUGCHK(pContext->pPipes);
// the default endpoint is always endpoint 0
for (DWORD dwEp = 0; dwEp < pContext->PddInfo.dwEndpointCount; ++dwEp) {
PCPipe pPipe = &pContext->pPipes[dwEp];
pPipe->Reset();
}
FUNCTION_LEAVE_MSG();
}
static
VOID
InitializeEndpointZeroDescriptor(
PUFN_MDD_CONTEXT pContext,
BYTE bMaxPacketSize,
PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc
)
{
DEBUGCHK(pContext);
PREFAST_DEBUGCHK(pEndpointDesc);
pEndpointDesc->bEndpointAddress = 0;
pEndpointDesc->bmAttributes = USB_ENDPOINT_TYPE_CONTROL;
pEndpointDesc->wMaxPacketSize = bMaxPacketSize;
}
// Search for the target endpoint address. The endpoint address is
// stored in the endpoint descriptor.
PCPipe
FindPipe(
PUFN_MDD_CONTEXT pContext,
DWORD dwEndpointAddress
)
{
PCPipe pPipe = NULL;
PREFAST_DEBUGCHK(pContext);
PREFAST_DEBUGCHK(pContext->pPipes);
DEBUGCHK(dwEndpointAddress != -1);
for (DWORD dwPipe = 0; dwPipe < pContext->PddInfo.dwEndpointCount; ++dwPipe) {
if (pContext->pPipes[dwPipe].GetEndpointAddress() == dwEndpointAddress) {
pPipe = &pContext->pPipes[dwPipe];
break;
}
}
return pPipe;
}
static
DWORD
ReadRegDword(
HKEY hKey,
LPCTSTR pszKey,
BOOL fMustSucceed,
PDWORD pdwValue
)
{
SETFNAME();
PREFAST_DEBUGCHK(hKey);
DEBUGCHK(pszKey);
DEBUGCHK(pdwValue);
DWORD dwType;
DWORD cbData = sizeof(DWORD);
DWORD dwErr = RegQueryValueEx(hKey, pszKey, NULL,
&dwType, (PBYTE) pdwValue, &cbData);
if ( (dwErr == ERROR_SUCCESS) && (dwType != REG_DWORD) ) {
dwErr = ERROR_INVALID_DATA;
}
if ( fMustSucceed && (dwErr != ERROR_SUCCESS) ) {
DEBUGMSG(ZONE_ERROR, (_T("%s Failed to read %s. Error: %d\r\n"),
pszFname, pszKey, dwErr));
}
return dwErr;
}
// See if the packet size adheres to the USB standard for the speed and type.
static
BOOL
ValidatePacketSize(
UFN_BUS_SPEED Speed,
PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc
)
{
PREFAST_DEBUGCHK(pEndpointDesc);
BOOL fRet = TRUE;
WORD wPacketSize =
(pEndpointDesc->wMaxPacketSize & USB_ENDPOINT_MAX_PACKET_SIZE_MASK);
switch (pEndpointDesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) {
case USB_ENDPOINT_TYPE_CONTROL:
if ( (wPacketSize != 8) && (wPacketSize != 16) &&
(wPacketSize != 32) && (wPacketSize != 64) ) {
fRet = FALSE;
}
break;
case USB_ENDPOINT_TYPE_BULK:
if ( (wPacketSize != 8) && (wPacketSize != 16) &&
(wPacketSize != 32) && (wPacketSize != 64) &&
(wPacketSize != 512) ) {
fRet = FALSE;
}
else if ( (wPacketSize == 512) && (Speed != BS_HIGH_SPEED) ) {
fRet = FALSE;
}
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
if ( (Speed == BS_FULL_SPEED) && (wPacketSize > 64) ) {
fRet = FALSE;
}
else if (wPacketSize > 1024) {
DEBUGCHK(Speed == BS_HIGH_SPEED);
fRet = FALSE;
}
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
if ( (Speed == BS_FULL_SPEED) && (wPacketSize > 1023) ) {
fRet = FALSE;
}
else if (wPacketSize > 1024) {
DEBUGCHK(Speed == BS_HIGH_SPEED);
fRet = FALSE;
}
break;
default:
// We should net get here.
fRet = FALSE;
break;
}
return fRet;
}
// Append data to the config descriptor and advance pointers.
static
DWORD
FillConfigDescBuffer(
PBYTE *ppbDest,
PDWORD pcbDest,
PVOID pvSource,
DWORD cbSource
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
PREFAST_DEBUGCHK(ppbDest);
DEBUGCHK(*ppbDest);
PREFAST_DEBUGCHK(pcbDest);
PREFAST_DEBUGCHK(pvSource);
DEBUGCHK(cbSource);
DWORD dwRet = ERROR_SUCCESS;
if (cbSource > *pcbDest) {
DEBUGMSG(ZONE_ERROR, (_T("%s Config descriptor length is too short\r\n"), pszFname));
dwRet = ERROR_INVALID_PARAMETER;
}
else {
memcpy(*ppbDest, pvSource, cbSource);
*ppbDest += cbSource;
*pcbDest -= cbSource;
}
FUNCTION_LEAVE_MSG();
return dwRet;
}
// Creates the config descriptor from the descriptor tree.
static
DWORD
CreateConfigDesc(
PUSB_CONFIGURATION_DESCRIPTOR *ppConfigDesc,
PUFN_CONFIGURATION pConfig
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
PREFAST_DEBUGCHK(pConfig);
PREFAST_DEBUGCHK(ppConfigDesc);
DWORD dwRet;
DWORD cbConfig = pConfig->Descriptor.wTotalLength;
PBYTE pbBuffer = (PBYTE) LocalAlloc(0, cbConfig);
if (pbBuffer == NULL) {
dwRet = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("%s LocalAlloc failed. Error: %d\r\n"), pszFname,
dwRet));
goto EXIT;
}
PUSB_CONFIGURATION_DESCRIPTOR pConfigDesc = (PUSB_CONFIGURATION_DESCRIPTOR) pbBuffer;
DWORD cbBuffer = cbConfig;
// Copy configuration descriptor
dwRet = FillConfigDescBuffer(&pbBuffer, &cbBuffer, &pConfig->Descriptor,
sizeof(USB_CONFIGURATION_DESCRIPTOR));
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
if (pConfig->pvExtended) {
dwRet = FillConfigDescBuffer(&pbBuffer, &cbBuffer, pConfig->pvExtended,
pConfig->cbExtended);
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
}
for (DWORD dwInterface = 0; dwInterface < pConfigDesc->bNumInterfaces; ++dwInterface) {
// Copy interface descriptor
PUFN_INTERFACE pInterface = &pConfig->pInterfaces[dwInterface];
PREFAST_DEBUGCHK(pInterface);
dwRet = FillConfigDescBuffer(&pbBuffer, &cbBuffer, &pInterface->Descriptor,
sizeof(USB_INTERFACE_DESCRIPTOR));
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
if (pInterface->pvExtended) {
dwRet = FillConfigDescBuffer(&pbBuffer, &cbBuffer, pInterface->pvExtended,
pInterface->cbExtended);
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
}
DEBUGCHK( (pInterface->pEndpoints && pInterface->Descriptor.bNumEndpoints > 0) ||
(pInterface->pEndpoints == NULL && pInterface->Descriptor.bNumEndpoints == 0) );
// Copy endpoint descriptors
for (DWORD dwEndpoint = 0; dwEndpoint < pInterface->Descriptor.bNumEndpoints; ++dwEndpoint) {
PUFN_ENDPOINT pEndpoint = &pInterface->pEndpoints[dwEndpoint];
dwRet = FillConfigDescBuffer(&pbBuffer, &cbBuffer,
&pEndpoint->Descriptor, sizeof(USB_ENDPOINT_DESCRIPTOR));
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
if (pEndpoint->pvExtended) {
dwRet = FillConfigDescBuffer(&pbBuffer, &cbBuffer, pEndpoint->pvExtended,
pEndpoint->cbExtended);
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
}
}
}
if (cbBuffer != 0) {
DEBUGMSG(ZONE_ERROR, (_T("%s Config descriptor length is too long\r\n"), pszFname));
dwRet = ERROR_INVALID_PARAMETER;
goto EXIT;
}
*ppConfigDesc = pConfigDesc;
dwRet = ERROR_SUCCESS;
EXIT:
if (dwRet != ERROR_SUCCESS) {
if (pConfigDesc) LocalFree(pConfigDesc);
}
FUNCTION_LEAVE_MSG();
return dwRet;
}
// Allocates room and copies an extended descriptor if it exists.
static
DWORD
CopyExtendedDesc(
PVOID *ppvDest,
PDWORD pcbDest,
PVOID pvSource,
DWORD cbSource
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
PREFAST_DEBUGCHK(ppvDest);
PREFAST_DEBUGCHK(pcbDest);
DWORD dwRet = ERROR_SUCCESS;
if (pvSource) {
*ppvDest = LocalAlloc(0, cbSource);
if (*ppvDest == NULL) {
dwRet = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("%s LocalAlloc failed. Error: %d\r\n"), pszFname,
dwRet));
goto EXIT;
}
memcpy(*ppvDest, pvSource, cbSource);
*pcbDest = cbSource;
DEBUGMSG(ZONE_FUNCTION, (_T("%s Copied %d bytes of extended descriptor(s)\r\n"),
pszFname, cbSource));
}
EXIT:
FUNCTION_LEAVE_MSG();
return dwRet;
}
// Copies a config tree structure.
static
DWORD
CopyConfig(
PUFN_CONFIGURATION pConfigDest,
PUFN_CONFIGURATION pConfigSource
)
{
SETFNAME();
FUNCTION_ENTER_MSG();
DWORD dwRet;
memcpy(pConfigDest, pConfigSource, sizeof(UFN_CONFIGURATION));
// Clear out the configuration's pointers
pConfigDest->pInterfaces = NULL;
pConfigDest->pvExtended = NULL;
// Copy the config's extended descriptor
dwRet = CopyExtendedDesc(&pConfigDest->pvExtended, &pConfigDest->cbExtended,
pConfigSource->pvExtended, pConfigSource->cbExtended);
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
// Copy the interface structure
DEBUGCHK(pConfigSource->Descriptor.bNumInterfaces);
PREFAST_DEBUGCHK(pConfigSource->pInterfaces);
DWORD cbInterfaces =
pConfigDest->Descriptor.bNumInterfaces * sizeof(UFN_INTERFACE);
pConfigDest->pInterfaces = (PUFN_INTERFACE) LocalAlloc(0, cbInterfaces);
if (pConfigDest->pInterfaces == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -