📄 ufnbus.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.
//
#include "ufnbus.h"
#include "ufnmdd.h"
#include "ufnclient.h"
#include <devload.h>
CUfnBusDevice::CUfnBusDevice(
LPCTSTR pszBusName,
LPCTSTR pszRegPath,
LPCTSTR pszDeviceBusName,
LPCTSTR pszChildName,
DWORD dwController,
HANDLE hParent
) :
DeviceFolder(pszBusName, pszRegPath, Internal, 0, dwController,
0, hParent, 0, pszDeviceBusName)
{
m_fValid = TRUE;
HRESULT hr = StringCchCopy(m_szUfnName, dim(m_szUfnName), pszChildName);
if (FAILED(hr)) {
m_fValid = FALSE;
}
DEBUGCHK(m_fValid);
}
static
BOOL
GetUfnDescription(
HKEY hkClient,
LPTSTR pszDescription,
DWORD cchDescription
)
{
SETFNAME();
DEBUGCHK(hkClient);
PREFAST_DEBUGCHK(pszDescription);
DWORD dwType;
DWORD cbValue = sizeof(TCHAR) * cchDescription;
DWORD dwError = RegQueryValueEx(hkClient, PSZ_REG_FRIENDLY_NAME,
NULL, &dwType, (PBYTE) pszDescription, &cbValue);
pszDescription[cchDescription - 1] = 0; // Null-terminate
if ( (dwError != ERROR_SUCCESS) || (dwType != REG_SZ) ) {
// No description. Still return success, though.
pszDescription[0] = 0;
DEBUGMSG(ZONE_WARNING, (_T("%s No friendly name given for client\r\n"),
pszFname));
}
return TRUE;
}
#define MAX_ENDPOINTS 0x1000 // arbitrary max endpoint count
static
DWORD
AllocEndpoints(
PUFN_MDD_CONTEXT pContext
)
{
SETFNAME();
DWORD dwRet = ERROR_SUCCESS;
// Set up our pipe table
DEBUGCHK(pContext->pPipes == NULL);
DEBUGCHK(pContext->pFreeTransferList);
// First guard against integer overflow
if (pContext->PddInfo.dwEndpointCount > MAX_ENDPOINTS) {
dwRet = ERROR_INVALID_PARAMETER;
DEBUGMSG(ZONE_ERROR, (_T("%s Too many endpoints: %u\r\n"), pszFname,
pContext->PddInfo.dwEndpointCount));
}
else {
pContext->pPipes = (PCPipe) LocalAlloc(LPTR,
sizeof(CPipe) * pContext->PddInfo.dwEndpointCount);
if (pContext->pPipes == NULL) {
dwRet = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("%s LocalAlloc failed. Error: %d\r\n"), pszFname,
dwRet));
}
else {
for (DWORD dwPipe = 0; dwPipe < pContext->PddInfo.dwEndpointCount; ++dwPipe) {
PVOID pv = &pContext->pPipes[dwPipe];
new (pv) CPipe(dwPipe, &pContext->PddInfo, pContext->pFreeTransferList);
}
}
}
return dwRet;
}
static
VOID
FreePipes(
PUFN_MDD_CONTEXT pContext
)
{
PREFAST_DEBUGCHK(pContext->pPipes);
for (DWORD dwPipe = 0; dwPipe < pContext->PddInfo.dwEndpointCount; ++dwPipe) {
PCPipe pPipe = &pContext->pPipes[dwPipe];
pPipe->~CPipe();
}
LocalFree(pContext->pPipes);
pContext->pPipes = NULL;
}
CUfnBus::CUfnBus(
LPCTSTR pszActivePath,
UFN_MDD_CONTEXT *pContext
) :
DefaultBusDriver(pszActivePath)
{
DEBUGCHK(pszActivePath);
DEBUGCHK(pContext);
m_pContext = pContext;
m_dwControllerNumber = 0xFFFFFFFF;
m_fIsChildPowerManaged = FALSE;
}
BOOL
CUfnBus::Init(
)
{
SETFNAME();
BOOL fRet = DefaultBusDriver::Init();
if (fRet) {
DEVMGR_DEVICE_INFORMATION ddi;
ddi.dwSize = sizeof(ddi);
if (!GetDeviceInformationByDeviceHandle(GetDeviceHandle(), &ddi)) {
DEBUGMSG(ZONE_ERROR, (_T("%s Could not get device information. Error = %d\r\n"),
pszFname, GetLastError()));
fRet = FALSE;
}
else {
m_dwControllerNumber = (ddi.szLegacyName[3] - L'0');
HRESULT hr = StringCchPrintf(m_szClientBusName, dim(m_szClientBusName),
TEXT("%s_%d_0"), UFN_BUS_PREFIX, m_dwControllerNumber);
DEBUGCHK(SUCCEEDED(hr));
fRet = TRUE;
}
}
return fRet;
}
CUfnBus::~CUfnBus(
)
{
if (IsClientActive()) {
DeactivateChild(m_szClientBusName);
}
}
DWORD
CUfnBus::CreateChild(
LPCTSTR pszChildName,
CUfnBusDevice **ppDevice
)
{
SETFNAME();
TCHAR szFullRegPath[MAX_PATH];
DWORD dwRet;
HRESULT hr = StringCchPrintf(szFullRegPath, dim(szFullRegPath), _T("%s\\%s"),
PSZ_REG_CLIENT_DRIVER_PATH, pszChildName);
if (FAILED(hr)) {
dwRet = HRESULT_CODE(hr);
RETAILMSG(1, (_T("%s Reg path too long for buffer. \"%s\\%s\"\r\n"),
pszFname, PSZ_REG_CLIENT_DRIVER_PATH, pszChildName));
goto EXIT;
}
DEBUGMSG(ZONE_INIT, (_T("%s Using client driver key \"%s\"\r\n"), pszFname,
szFullRegPath));
CUfnBusDevice *pDevice = new CUfnBusDevice(UFN_BUS_PREFIX, szFullRegPath,
m_szClientBusName, pszChildName, m_dwControllerNumber, GetDeviceHandle());
if (!pDevice || !pDevice->Init()) {
if (pDevice) {
delete pDevice;
}
dwRet = ERROR_GEN_FAILURE;
goto EXIT;
}
dwRet = ERROR_SUCCESS;
*ppDevice = pDevice;
EXIT:
return dwRet;
}
DWORD
CUfnBus::OpenFunctionKey(HKEY *phkFunctions)
{
SETFNAME();
DEBUGCHK(phkFunctions);
// Determine which client driver to load
DWORD dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, PSZ_REG_CLIENT_DRIVER_PATH, phkFunctions);
if (dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s Failed to open function client key \"%s\". Error = %d\r\n"),
pszFname, PSZ_REG_CLIENT_DRIVER_PATH, dwRet));
}
return dwRet;
}
BOOL
CUfnBus::PostInit(
)
{
SETFNAME();
BOOL fErr;
CUfnBusDevice *pDevice = NULL;
TCHAR szClientName[UFN_CLIENT_NAME_MAX_CHARS];
DWORD dwRet;
BOOL fInserted = FALSE;
DEBUGCHK(GetDeviceList() == NULL);
dwRet = GetDefaultClientName(szClientName, dim(szClientName));
if (dwRet != ERROR_SUCCESS) {
goto EXIT;
}
dwRet = CreateChild(szClientName, &pDevice);
if (dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s CreateChild failed.\r\n"), pszFname));
dwRet = ERROR_GEN_FAILURE;
goto EXIT;
}
fErr = InsertChild(pDevice);
if (!fErr) {
DEBUGMSG(ZONE_ERROR, (_T("%s InsertChild failed.\r\n"), pszFname));
dwRet = ERROR_GEN_FAILURE;
goto EXIT;
}
fInserted = TRUE;
fErr = ActivateChild(m_szClientBusName);
if (!fErr) {
DEBUGMSG(ZONE_ERROR, (_T("%s ActivateChild failed.\r\n"), pszFname));
dwRet = ERROR_GEN_FAILURE;
goto EXIT;
}
EXIT:
BOOL fRet = TRUE;
if (dwRet != ERROR_SUCCESS) {
if (pDevice) {
if (fInserted) {
RemoveChildByFolder(pDevice);
// This will take reference count to 0 and delete it.
}
else {
delete pDevice;
}
}
SetLastError(dwRet);
fRet = FALSE;
}
return fRet;
}
BOOL CUfnBus::ActivateChild(LPCTSTR pszChildBusName)
{
SETFNAME();
DWORD dwRet;
DEBUGCHK(m_fIsChildPowerManaged == FALSE);
// Allocate our free transfer list
DEBUGCHK(m_pContext->pFreeTransferList == NULL);
m_pContext->pFreeTransferList = new CFreeTransferList();
if (m_pContext->pFreeTransferList == NULL) {
dwRet = GetLastError();
DEBUGMSG(ZONE_ERROR, (_T("%s Failed to create free transfer list. Error %u\r\n"),
pszFname, dwRet));
goto EXIT;
}
#ifdef DEBUG
// Verify that a compact can occur on a free list where
// nothing has been allocated yet.
//
// Perform an initial compact to simulate the compact that will
// occur after a quick attach and detach when no transfers have
// been allocated yet.
m_pContext->pFreeTransferList->Compact();
#endif
dwRet = AllocEndpoints(m_pContext);
if (dwRet != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (_T("%s Failed to create pipes. Error %u\r\n"),
pszFname, dwRet));
goto EXIT;
}
// Load the client driver
DEBUGCHK(m_pContext->fClientIsBeingAddedOrRemoved == FALSE);
m_pContext->fClientIsBeingAddedOrRemoved = TRUE;
m_hInitThread = GetCurrentThread();
// ActivateChild will eventually call the PDD's Start routine. The Start
// routine will create the IST which could immediately send notifications
// to the MDD. Reset the event so that notifications will be stalled.
ResetEvent(m_pContext->hevReadyForNotifications);
BOOL fErr = DefaultBusDriver::ActivateChild(pszChildBusName);
m_hInitThread = NULL;
m_pContext->fClientIsBeingAddedOrRemoved = FALSE;
// Allow the stalled notification to continue now that the client is
// fully loaded.
SetEvent(m_pContext->hevReadyForNotifications);
if (fErr == FALSE) {
DEBUGMSG(ZONE_ERROR, (_T("%s ActivateChild failed.\r\n"), pszFname));
dwRet = ERROR_GEN_FAILURE;
goto EXIT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -