|
|
/*++
Copyright (C) Microsoft Corporation
Module Name:
cnode.cpp
Abstract:
This module implements CDevice, CClass, CResource and CComputer classes.
Author:
William Hsieh (williamh) created
Revision History:
--*/ #include "devmgr.h"
#include "cdriver.h"
#include "hwprof.h"
#include "sysinfo.h"
#include <initguid.h>
#include <mountmgr.h>
#include <devguid.h>
#include <wdmguid.h>
//
// CClass implementation
//
CClass::CClass( CMachine* pMachine, GUID* pGuid ) { m_Guid = *pGuid; ASSERT(pMachine); ASSERT(pGuid);
m_NoDisplay = FALSE; m_pMachine = pMachine; m_TotalDevices = 0; m_TotalHiddenDevices = 0; m_pDevInfoList = NULL; m_pos = NULL;
if (!m_pMachine->DiGetClassFriendlyNameString(pGuid, m_strDisplayName)) { m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN); } m_pMachine->DiGetClassImageIndex(pGuid, &m_iImage);
HKEY hKey = m_pMachine->DiOpenClassRegKey(pGuid, KEY_READ, DIOCR_INSTALLER);
if (INVALID_HANDLE_VALUE != hKey) { if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL)) { m_NoDisplay = TRUE; } RegCloseKey(hKey); } }
CDevInfoList* CClass::GetDevInfoList( HWND hwndParent ) { if (!m_pDevInfoList) { HDEVINFO hDevInfo = m_pMachine->DiCreateDeviceInfoList(&m_Guid, hwndParent);
if (hDevInfo && INVALID_HANDLE_VALUE != hDevInfo) { m_pDevInfoList = new CDevInfoList(hDevInfo, hwndParent); } } return m_pDevInfoList; }
inline CItemIdentifier* CClass::CreateIdentifier() { return new CClassIdentifier(*this); }
CClass::~CClass() { m_listDevice.RemoveAll();
if (m_pDevInfoList) { delete m_pDevInfoList; } }
HICON CClass::LoadIcon() { HICON hClassIcon;
if (!m_pMachine->DiLoadClassIcon(&m_Guid, &hClassIcon, NULL)) { return NULL; } return hClassIcon; }
void CClass::AddDevice(CDevice* pDevice) { ASSERT(pDevice);
m_listDevice.AddTail(pDevice); m_TotalDevices++;
if (pDevice->IsHidden()) { m_TotalHiddenDevices++; } }
BOOL CClass::GetFirstDevice( CDevice** ppDevice, PVOID& Context ) { ASSERT(ppDevice);
if (!m_listDevice.IsEmpty()) { POSITION pos;
pos = m_listDevice.GetHeadPosition(); *ppDevice = m_listDevice.GetNext(pos); Context = pos;
return TRUE; } *ppDevice = NULL;
return FALSE; }
BOOL CClass::GetNextDevice( CDevice** ppDevice, PVOID& Context ) { ASSERT(ppDevice);
POSITION pos = (POSITION)(Context);
if(NULL != pos) { *ppDevice = m_listDevice.GetNext(pos); Context = pos; return TRUE; } *ppDevice = NULL;
return FALSE; }
void CClass::PropertyChanged() { if (!m_pMachine->DiGetClassFriendlyNameString(&m_Guid, m_strDisplayName)) { m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN); } m_pMachine->DiGetClassImageIndex(&m_Guid, &m_iImage);
if (m_pDevInfoList) { delete m_pDevInfoList; m_pDevInfoList = NULL; } HKEY hKey = m_pMachine->DiOpenClassRegKey(&m_Guid, KEY_READ, DIOCR_INSTALLER);
if (INVALID_HANDLE_VALUE != hKey) { if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGSTR_VAL_NODISPLAYCLASS, NULL, NULL, NULL, NULL)) { m_NoDisplay = TRUE; } RegCloseKey(hKey); } }
// CDevice implementation
//
CDevice::CDevice( CMachine* pMachine, CClass* pClass, PSP_DEVINFO_DATA pDevData ) { ASSERT(pMachine && pDevData && pClass); m_DevData = *pDevData; m_pClass = pClass; m_pMachine = pMachine; m_pSibling = NULL; m_pParent = NULL; m_pChild = NULL;
if (!m_pMachine->CmGetDescriptionString(m_DevData.DevInst, m_strDisplayName)) { m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN_DEVICE); } m_pMachine->CmGetDeviceIDString(m_DevData.DevInst, m_strDeviceID); m_iImage = m_pClass->GetImageIndex(); }
inline CItemIdentifier* CDevice::CreateIdentifier() { return new CDeviceIdentifier(*this); }
void CDevice::PropertyChanged() { if (!m_pMachine->CmGetDescriptionString(m_DevData.DevInst, m_strDisplayName)) { m_strDisplayName.LoadString(g_hInstance, IDS_UNKNOWN_DEVICE); } m_pMachine->CmGetDeviceIDString(m_DevData.DevInst, m_strDeviceID); m_iImage = m_pClass->GetImageIndex(); }
HICON CDevice::LoadClassIcon() { HICON hClassIcon; hClassIcon = NULL;
if (m_pMachine->DiLoadClassIcon(&m_DevData.ClassGuid, &hClassIcon, NULL)) { return hClassIcon; }
return NULL; }
BOOL CDevice::GetStatus( DWORD* pStatus, DWORD* pProblem ) { return m_pMachine->CmGetStatus(m_DevData.DevInst, pProblem, pStatus); }
BOOL CDevice::GetCapabilities( DWORD* pCapabilities ) { return m_pMachine->CmGetCapabilities(m_DevData.DevInst, pCapabilities); }
BOOL CDevice::GetPowerCapabilities( DWORD* pCapabilities ) { CM_POWER_DATA CmPowerData; ULONG Size;
Size = sizeof(CmPowerData); if (m_pMachine->CmGetRegistryProperty(m_DevData.DevInst, CM_DRP_DEVICE_POWER_DATA, &CmPowerData, &Size ) == CR_SUCCESS) {
*pCapabilities = CmPowerData.PD_Capabilities; return TRUE; }
*pCapabilities = 0; return FALSE; }
BOOL CDevice::IsRAW() { DWORD Capabilities; return (m_pMachine->CmGetCapabilities(m_DevData.DevInst, &Capabilities) && (CM_DEVCAP_RAWDEVICEOK & Capabilities)); }
BOOL CDevice::IsHidden() { CClass *pClass = GetClass();
//
// A device is hidden if one of the following are TRUE:
//
// - It's class is a NoDisplayClass
// - It has the DN_NO_SHOW_IN_DM Status flag set
// - It is a Phantom devnode
//
return (NoShowInDM() || IsPhantom() || pClass->NoDisplay()); }
BOOL CDevice::IsPhantom() { DWORD Status, Problem;
return !m_pMachine->CmGetStatus(m_DevData.DevInst, &Problem, &Status) && (CR_NO_SUCH_VALUE == m_pMachine->GetLastCR() || CR_NO_SUCH_DEVINST == m_pMachine->GetLastCR()); }
BOOL CDevice::NoShowInDM() { DWORD Status, Problem; Status = 0; if (GetStatus(&Status, &Problem) && (Status & DN_NO_SHOW_IN_DM)) {
return TRUE; }
return FALSE; }
BOOL CDevice::IsUninstallable( ) /*++
This function determins whether a device can be uninstalled. A device cannot be uninstalled if it is a ROOT device and it does not have the DN_DISABLEABLE DevNode status bit set. Return Value: TRUE if the device can be uninstalled. FALSE if the device cannot be uninstalled. --*/ { DWORD Status, Problem;
if (GetStatus(&Status, &Problem) && !(Status & DN_DISABLEABLE) && (Status & DN_ROOT_ENUMERATED)) {
return FALSE; } return TRUE; }
BOOL CDevice::IsDisableable( ) /*++
This function determins whether a device can be disabled or not by checking the DN_DISABLEABLE DevNode status bit. A device that is currently Hardware Disabled cannot be software disabled. Return Value: TRUE if the device can be disabled. FALSE if the device cannot be disabled.
--*/ { DWORD Status, Problem;
if (GetStatus(&Status, &Problem) && (Status & DN_DISABLEABLE) && (CM_PROB_HARDWARE_DISABLED != Problem)) {
return TRUE; }
return FALSE; }
BOOL CDevice::IsDisabled( ) /*++
A device is disabled if it has the problem CM_PROB_DISABLED. Return Value: TRUE if device is disabled. FALSE if device is NOT disabled. --*/ { DWORD Status, Problem;
if (GetStatus(&Status, &Problem)) { return ((Status & DN_HAS_PROBLEM) && (CM_PROB_DISABLED == Problem)); }
return FALSE; }
BOOL CDevice::IsStateDisabled( ) /*++
A device state is disabled if it has the CONFIGFLAG_DISABLED ConfigFlag set or the CSCONFIGFLAG_DISABLED Config Specific ConfigFlag disabled in the current profile. Note that a device disabled State has nothing to do with whether the device is currently physically disabled or not. The disabled state is just a registry flag that tells Plug and Play what to do with the device the next time it is started. Return Value: TRUE if device's state is disabled. FALSE if device's state is NOT disabled. --*/ { ULONG hwpfCurrent; DWORD Flags;
//
// Check if the device state is globally disabled by checking it's ConfigFlags
//
GetConfigFlags(&Flags); if (Flags & CONFIGFLAG_DISABLED) { return TRUE; }
//
// Check if the device state is disabled in the current hardware profile by
// checking it's Config Specific ConfigFlags.
//
if (m_pMachine->CmGetCurrentHwProfile(&hwpfCurrent) && m_pMachine->CmGetHwProfileFlags(m_DevData.DevInst, hwpfCurrent, &Flags) && (Flags & CSCONFIGFLAG_DISABLED)) { return TRUE; }
return FALSE; }
BOOL CDevice::IsStarted() { DWORD Status, Problem; //
// Check to see if the DN_STARTED devnode status flag is set.
//
if (GetStatus(&Status, &Problem) && (Status & DN_STARTED)) { return TRUE; } return FALSE; }
BOOL CDevice::HasProblem( ) /*++
This function returns whether a device has a problem or not. Return Value: TRUE if device has a problem. FALSE if device does not have a problem. --*/ { DWORD Status, Problem; if (GetStatus(&Status, &Problem)) { //
// If the DN_HAS_PROBLEM or DN_PRIVATE_PROBLEM status bits are set
// then this device has a problem, unless the problem is CM_PROB_MOVED.
//
if ((Status & DN_PRIVATE_PROBLEM) || ((Status & DN_HAS_PROBLEM) && (Problem != CM_PROB_MOVED))) { return TRUE; }
//
// If the device is not started and RAW capable then it also has a problem
//
if (!(Status & DN_STARTED) && IsRAW()) { return TRUE; } }
return FALSE; }
BOOL CDevice::NeedsRestart( ) /*++
This function returns whether a device needs a restart or not. It checks the DN_NEED_RESTART Status flag. Return Value: TRUE if device needs the computer to be restarted for it to work properly. FALSE if device does not need the computer to be restarted. --*/ { DWORD Status, Problem;
if (GetStatus(&Status, &Problem)) { return (Status & DN_NEED_RESTART); }
return FALSE; }
BOOL CDevice::IsPCIDevice() { GUID BusGuid;
if (m_pMachine->CmGetBusGuid(GetDevNode(), &BusGuid) && IsEqualGUID(BusGuid, GUID_BUS_TYPE_PCI)) {
return TRUE; }
return FALSE; }
BOOL CDevice::GetConfigFlags( DWORD* pFlags ) { return m_pMachine->CmGetConfigFlags(m_DevData.DevInst, pFlags); }
BOOL CDevice::GetConfigSpecificConfigFlags( DWORD* pCSStatus ) { ULONG hwpfCurrent;
if (m_pMachine->CmGetCurrentHwProfile(&hwpfCurrent) && m_pMachine->CmGetHwProfileFlags(m_DevData.DevInst, hwpfCurrent, pCSStatus)) { return TRUE; }
return FALSE; }
BOOL CDevice::GetKnownLogConf(LOG_CONF* plc, DWORD* plcType) { return m_pMachine->CmGetKnownLogConf(m_DevData.DevInst, plc, plcType); }
BOOL CDevice::HasResources() { return m_pMachine->CmHasResources(m_DevData.DevInst); }
void CDevice::GetMFGString( String& strMFG ) { m_pMachine->CmGetMFGString(m_DevData.DevInst, strMFG);
if (strMFG.IsEmpty()) { strMFG.LoadString(g_hInstance, IDS_UNKNOWN); } }
void CDevice::GetProviderString( String& strProvider ) { m_pMachine->CmGetProviderString(m_DevData.DevInst, strProvider); if (strProvider.IsEmpty()) { strProvider.LoadString(g_hInstance, IDS_UNKNOWN); } }
void CDevice::GetDriverDateString( String& strDriverDate ) { FILETIME ft;
strDriverDate.Empty();
//
// First try to get the driver date FileTime data from the registry,
// this way we can localize the date.
//
if (m_pMachine->CmGetDriverDateData(m_DevData.DevInst, &ft)) {
SYSTEMTIME SystemTime; TCHAR DriverDate[MAX_PATH];
DriverDate[0] = TEXT('\0');
if (FileTimeToSystemTime(&ft, &SystemTime)) {
if (GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &SystemTime, NULL, DriverDate, ARRAYLEN(DriverDate) ) != 0) {
strDriverDate = DriverDate; } }
} else { //
// We couldn't get the FileTime data so just get the DriverDate string
// from the registry.
//
m_pMachine->CmGetDriverDateString(m_DevData.DevInst, strDriverDate); }
if (strDriverDate.IsEmpty()) { strDriverDate.LoadString(g_hInstance, IDS_NOT_AVAILABLE); } }
void CDevice::GetDriverVersionString( String& strDriverVersion ) { m_pMachine->CmGetDriverVersionString(m_DevData.DevInst, strDriverVersion);
if (strDriverVersion.IsEmpty()) { strDriverVersion.LoadString(g_hInstance, IDS_NOT_AVAILABLE); } }
LPCTSTR CDevice::GetClassDisplayName() { if (m_pClass) { return m_pClass->GetDisplayName(); } else { return NULL; } }
BOOL CDevice::NoChangeUsage() { SP_DEVINSTALL_PARAMS dip; dip.cbSize = sizeof(dip);
if (m_pMachine->DiGetDeviceInstallParams(&m_DevData, &dip)) { return (dip.Flags & DI_PROPS_NOCHANGEUSAGE); } else { return TRUE; } }
CDriver* CDevice::CreateDriver() { CDriver* pDriver = NULL;
pDriver = new CDriver();
if (!pDriver) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); return NULL; }
pDriver->Create(this);
return pDriver; }
DWORD CDevice::EnableDisableDevice( HWND hDlg, BOOL Enabling ) { BOOL Disabling = !Enabling; BOOL Canceled; Canceled = FALSE; DWORD RestartFlags = 0; DWORD ConfigFlags; HCURSOR hCursorOld = NULL; BOOL Refresh = FALSE;
//
// Disable refreshing the TREE while we are enabling/disabling this device
//
m_pMachine->EnableRefresh(FALSE);
if (!GetConfigFlags(&ConfigFlags)) { ConfigFlags = 0; }
//
// Only want the disabled bit
//
ConfigFlags &= CONFIGFLAG_DISABLED;
CHwProfileList* pHwProfileList = new CHwProfileList(); if (!pHwProfileList) { goto clean0; }
pHwProfileList->Create(this, ConfigFlags);
//
// Get the current profile
//
CHwProfile* phwpf;
if (!(pHwProfileList->GetCurrentHwProfile(&phwpf))) { goto clean0; }
//
// Can only enable a device that is currently disabled
//
if (IsStateDisabled() && Enabling) { phwpf->SetEnablePending(); }
//
// Can only disable a device that is currently enabled
//
else if (!IsStateDisabled() && Disabling) { phwpf->SetDisablePending(); }
//
// If we don't have a valid enable or disable then exit
//
if (!(phwpf->IsEnablePending()) && !(phwpf->IsDisablePending())) { goto clean0; }
//
// This device is not a boot device so just display the normal disable
// warning to the user.
//
if (Disabling) { int MsgBoxResult; TCHAR szText[MAX_PATH]; LoadResourceString(IDS_WARN_NORMAL_DISABLE, szText, ARRAYLEN(szText)); MsgBoxResult = MessageBox(hDlg, szText, GetDisplayName(), MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2 );
if (IDYES != MsgBoxResult) { goto clean0; } }
hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// If this isn't a live devnode then we need to do a manual refresh if we
// are diabling the device.
//
Refresh = (!Enabling && (IsPhantom() || HasProblem() || !IsStarted()));
m_pMachine->DiTurnOnDiFlags(*this, DI_NODI_DEFAULTACTION);
SP_PROPCHANGE_PARAMS pcp; pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
//
// Now ask the class installer if the device can be specifically enabled/disabled
//
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.StateChange = DICS_DISABLE; if (phwpf->IsEnablePending()) { pcp.StateChange = DICS_ENABLE; } pcp.HwProfile = phwpf->GetHwProfile();
m_pMachine->DiSetClassInstallParams(*this, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pMachine->DiCallClassInstaller(DIF_PROPERTYCHANGE, *this); Canceled = (ERROR_CANCELLED == GetLastError()); //
// class installer has not objection of our enabling/disabling,
// do real enabling/disabling.
//
if (!Canceled) { if (phwpf->IsDisablePending()) { pcp.StateChange = DICS_DISABLE; pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = phwpf->GetHwProfile(); m_pMachine->DiSetClassInstallParams(*this, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pMachine->DiChangeState(*this); } else { //
// We are enabling the device,
// do a specific enabling then a globally enabling.
// the globally enabling will start the device
// The implementation here is different from
// Win9x which does a global enabling, a config
// specific enabling and then a start.
//
pcp.Scope = DICS_FLAG_CONFIGSPECIFIC; pcp.HwProfile = phwpf->GetHwProfile(); m_pMachine->DiSetClassInstallParams(*this, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pMachine->DiChangeState(*this);
//
// This call will start the device is it not started.
//
pcp.Scope = DICS_FLAG_GLOBAL; m_pMachine->DiSetClassInstallParams(*this, &pcp.ClassInstallHeader, sizeof(pcp) ); m_pMachine->DiChangeState(*this); } if (phwpf->IsEnablePending()) { phwpf->ResetEnablePending(); } else if (phwpf->IsDisablePending()) { phwpf->ResetDisablePending(); }
//
// signal that the property of the device is changed.
//
m_pMachine->DiTurnOnDiFlags(*this, DI_PROPERTIES_CHANGE);
//
// See if we need a restart.
//
RestartFlags |= (m_pMachine->DiGetFlags(*this)) & (DI_NEEDRESTART | DI_NEEDREBOOT);
if (NeedsRestart()) { RestartFlags |= DI_NEEDRESTART; } }
//
// Remove class install parameters, this also reset
// DI_CLASSINATLLPARAMS
//
m_pMachine->DiSetClassInstallParams(*this, NULL, 0);
m_pMachine->DiTurnOffDiFlags(*this, DI_NODI_DEFAULTACTION);
clean0: if (pHwProfileList) { delete pHwProfileList; }
//
// Enable the tree for refreshing.
// We will only schedule a refresh ourselves if the device was not started
// before we tried to disable it, and we are not going to prompt for a reboot.
// In all other cases we should get a WM_DEVICECHANGE which will cause us
// to refresh our tree.
//
if (Refresh && !NeedsRestart()) { m_pMachine->ScheduleRefresh(); }
m_pMachine->EnableRefresh(TRUE);
if (hCursorOld != NULL) { SetCursor(hCursorOld); }
return RestartFlags; }
//
// CComputer implementation
//
CComputer::CComputer( CMachine* pMachine, DEVNODE dnRoot ) { ASSERT(pMachine); ASSERT(!GetChild() && !GetParent() && !GetSibling()); m_pMachine = pMachine; m_strDisplayName.Empty(); m_strDisplayName = pMachine->GetMachineDisplayName(); m_iImage = pMachine->GetComputerIconIndex(); m_dnRoot = dnRoot; }
inline CItemIdentifier* CComputer::CreateIdentifier() { return new CComputerIdentifier(*this); }
CResource::CResource( CDevice* pDevice, RESOURCEID ResType, DWORDLONG dlBase, DWORDLONG dlLen, BOOL Forced, BOOL Free ) { m_pChild = NULL; m_pSibling = NULL; m_pParent = NULL; m_ResType = ResType; m_dlBase = dlBase; m_dlLen = dlLen; m_Forced = Forced; m_dlEnd = m_dlBase + m_dlLen - 1; m_Allocated = !Free; ASSERT(pDevice); m_pDevice = pDevice; m_iImage = pDevice->GetImageIndex(); ASSERT(ResType >= ResType_Mem && ResType <= ResType_IRQ);
m_strDisplayName.Empty(); m_strDisplayName = pDevice->GetDisplayName();
if (ResType_IRQ == m_ResType) { String strBus;
strBus.LoadString(g_hInstance, pDevice->IsPCIDevice() ? IDS_PCI : IDS_ISA );
m_strViewName.Format(TEXT("%2d "), m_dlBase); m_strViewName = strBus + m_strViewName; } else if (ResType_DMA == m_ResType) { m_strViewName.Format(TEXT("%2d " ), m_dlBase); } else { #ifdef _WIN64
m_strViewName.Format(TEXT("[%016I64X - %016I64X] "), m_dlBase, m_dlEnd); #else
m_strViewName.Format(TEXT("[%08lX - %08lX] "), (ULONG)m_dlBase, (ULONG)m_dlEnd); #endif
} if (m_Allocated) { m_strViewName += pDevice->GetDisplayName(); } }
BOOL CResource::operator <=( const CResource& resSrc ) { DWORDLONG dlBase, dlLen;
resSrc.GetValue(&dlBase, &dlLen);
if (m_dlBase < dlBase) return TRUE; //
// If this resource contain the given resource,
// we are smaller!
//
if (m_dlBase == dlBase) return (m_dlBase + m_dlLen > dlBase + dlLen); return FALSE; }
BOOL CResource::EnclosedBy( const CResource& resSrc ) { DWORDLONG dlBase, dlLen; resSrc.GetValue(&dlBase, &dlLen); return m_dlBase >= dlBase && m_dlBase + m_dlLen <= dlBase + dlLen; }
CResourceType::CResourceType( CMachine* pMachine, RESOURCEID ResType ) { int iStringID;
m_ResType = ResType; m_pChild = NULL; m_pSibling = NULL; m_pParent = NULL; m_pMachine = pMachine; ASSERT(ResType >= ResType_Mem && ResType <= ResType_IRQ);
switch (ResType) { case ResType_IRQ: iStringID = IDS_VIEW_RESOURCE_IRQ; break; case ResType_IO: iStringID = IDS_VIEW_RESOURCE_IO; break; case ResType_DMA: iStringID = IDS_VIEW_RESOURCE_DMA; break; case ResType_Mem: iStringID = IDS_VIEW_RESOURCE_MEM; break; default: iStringID = IDS_UNKNOWN; break; }
m_strDisplayName.Empty(); m_strDisplayName.LoadString(g_hInstance, iStringID); m_iImage = pMachine->GetResourceIconIndex(); }
inline CItemIdentifier* CResourceType::CreateIdentifier() { return new CResourceTypeIdentifier(*this); }
// This function creates CResourceList object to contain the designated
// resources for the given device.
// INPUT:
// pDevice -- the device
// ResType -- what type of resource
// LogConfType -- what type of logconf
// OUTPUT:
// NONE.
//
// This function may throw CMemoryException
//
CResourceList::CResourceList( CDevice* pDevice, RESOURCEID ResType, ULONG LogConfType, ULONG AltLogConfType ) { ASSERT(ResType_All != ResType); ASSERT(BOOT_LOG_CONF == LogConfType || FORCED_LOG_CONF == LogConfType || ALLOC_LOG_CONF == LogConfType); ASSERT(pDevice);
UNREFERENCED_PARAMETER(AltLogConfType);
LOG_CONF lc; RES_DES rd, rdPrev; rdPrev; RESOURCEID ResId; BOOL Forced; CMachine* pMachine = pDevice->m_pMachine; ASSERT(pMachine);
rdPrev = 0;
//
// Even though we have a valid logconf, it does not mean
// GetNextResDes would succeed because the ResType is not
// ResType_All.
//
if (pMachine->CmGetFirstLogConf(pDevice->GetDevNode(), &lc, LogConfType)) { if (pMachine->CmGetNextResDes(&rd, lc, ResType, &ResId)) { ULONG DataSize; DWORDLONG dlBase, dlLen; do { DataSize = pMachine->CmGetResDesDataSize(rd);
if (DataSize) { BufferPtr<BYTE> DataPtr(DataSize);
if (pMachine->CmGetResDesData(rd, DataPtr, DataSize)) { //
// Need this to use a different image overlay for
// forced allocated resource
//
Forced = pMachine->CmGetFirstLogConf(pDevice->GetDevNode(), NULL, FORCED_LOG_CONF); if (ExtractResourceValue(ResType, DataPtr, &dlBase, &dlLen)) { SafePtr<CResource> ResPtr; CResource* pRes; pRes = new CResource(pDevice, ResType, dlBase, dlLen, Forced, FALSE); if (pRes) { ResPtr.Attach(pRes); InsertResourceToList(pRes); ResPtr.Detach(); } } } } if (rdPrev) { pMachine->CmFreeResDesHandle(rdPrev); } rdPrev = rd;
} while (pMachine->CmGetNextResDes(&rd, rdPrev, ResType, &ResId)); //
// free the last resource descriptor handle
//
pMachine->CmFreeResDesHandle(rd); }
pMachine->CmFreeLogConfHandle(lc); } }
// This function creates CResourceList object to contain the designated
// resources for the given machine.
// INPUT:
// pMachine -- the machine
// ResType -- what type of resource
// LogConfType -- what type of logconf
// OUTPUT:
// NONE.
//
// This function may throw CMemoryException
//
CResourceList::CResourceList( CMachine* pMachine, RESOURCEID ResType, ULONG LogConfType, ULONG AltLogConfType ) { ASSERT(ResType_All != ResType); ASSERT(BOOT_LOG_CONF == LogConfType || FORCED_LOG_CONF == LogConfType || ALLOC_LOG_CONF == LogConfType || ALL_LOG_CONF == LogConfType);
ASSERT(pMachine);
if (pMachine->GetNumberOfDevices()) { ASSERT(pMachine->m_pComputer && pMachine->m_pComputer->GetChild());
CDevice* pFirstDevice;
pFirstDevice = pMachine->m_pComputer->GetChild(); CreateSubtreeResourceList(pFirstDevice, ResType, LogConfType, AltLogConfType); } }
//
// This function extracts resource value from the provided buffer
//
// INPUT:
// ResType -- resource type the data contain
// pData -- the raw data
// pdlBase -- buffer to hold the base of the value
// pdlLen -- buffer to hold the length of the value
//
// OUTPUT:
// TRUE if this is a valid resource descriptor or FALSE if we should ignore it.
//
// NOTE:
// If the return value is FALSE then pdlBase and pdlLen are not filled in.
//
BOOL CResourceList::ExtractResourceValue( RESOURCEID ResType, PVOID pData, DWORDLONG* pdlBase, DWORDLONG* pdlLen ) { BOOL bValidResDes = TRUE;
ASSERT(pData && pdlBase && pdlLen);
switch (ResType) { case ResType_Mem: if (pMemResData(pData)->MEM_Header.MD_Alloc_Base <= pMemResData(pData)->MEM_Header.MD_Alloc_End) { *pdlBase = pMemResData(pData)->MEM_Header.MD_Alloc_Base; *pdlLen = pMemResData(pData)->MEM_Header.MD_Alloc_End - *pdlBase + 1; } else { //
// If base > end then ignore this resource descriptor
//
*pdlBase = 0; *pdlLen = 0; bValidResDes = FALSE; } break; case ResType_IRQ: *pdlBase = pIRQResData(pData)->IRQ_Header.IRQD_Alloc_Num; // IRQ len is always 1
*pdlLen = 1; break; case ResType_DMA: *pdlBase = pDMAResData(pData)->DMA_Header.DD_Alloc_Chan; // DMA len is always 1
*pdlLen = 1; break; case ResType_IO: if (pIOResData(pData)->IO_Header.IOD_Alloc_Base <= pIOResData(pData)->IO_Header.IOD_Alloc_End) { *pdlBase = pIOResData(pData)->IO_Header.IOD_Alloc_Base; *pdlLen = pIOResData(pData)->IO_Header.IOD_Alloc_End - *pdlBase + 1; } else { //
// If base > end then ignore this resource descriptor
//
*pdlBase = 0; *pdlLen = 0; bValidResDes = FALSE; } break; default: ASSERT(FALSE); *pdlBase = 0; *pdlLen = 0; break; }
return bValidResDes; }
//
//This function creates resources for the given subtree rooted at
//the given device
//
//INPUT:
// pDevice -- the root device of the subtree
// ResType -- resource type to be created
// LogConfType -- logconf type to be created from
//
//OUTPUT:
// NONE
//
// This function may throw CMemoryException
//
void CResourceList::CreateSubtreeResourceList( CDevice* pDeviceStart, RESOURCEID ResType, ULONG LogConfType, ULONG AltLogConfType ) { LOG_CONF lc; RES_DES rd, rdPrev; RESOURCEID ResId; BOOL Forced; CMachine* pMachine = pDeviceStart->m_pMachine; ASSERT(pMachine);
while (pDeviceStart) { //
// We will try to get a LogConf for either the LogConfType (which defaults to
// ALLOC_LOG_CONF) or the AltLogConfType (which defaults to BOOT_LOG_CONF).
// We need to do this because on Win2000 a device that only has a BOOT_LOG_CONF
// will still consume those resources, even if it does not have an ALLOC_LOG_CONF.
// So we need to first check the ALLOC_LOG_CONF and if that fails check the
// BOOT_LOG_CONF.
//
if (pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), &lc, LogConfType) || pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), &lc, AltLogConfType)) { rdPrev = 0;
if (pMachine->CmGetNextResDes(&rd, lc, ResType, &ResId)) { ULONG DataSize; DWORDLONG dlBase, dlLen;
do { DataSize = pMachine->CmGetResDesDataSize(rd);
if (DataSize) { //
// Need this to use a different image overlay for
// forced allocated resource
//
Forced = pMachine->CmGetFirstLogConf(pDeviceStart->GetDevNode(), NULL, FORCED_LOG_CONF); BufferPtr<BYTE> DataPtr(DataSize); if (pMachine->CmGetResDesData(rd, DataPtr, DataSize)) { if (ExtractResourceValue(ResType, DataPtr, &dlBase, &dlLen)) { SafePtr<CResource> ResPtr; CResource* pRes; pRes = new CResource(pDeviceStart, ResType, dlBase, dlLen, Forced, FALSE); ResPtr.Attach(pRes); InsertResourceToList(pRes); ResPtr.Detach(); } } } if (rdPrev) pMachine->CmFreeResDesHandle(rdPrev); rdPrev = rd; }while (pMachine->CmGetNextResDes(&rd, rdPrev, ResType, &ResId)); //
// Free the last resource descriptor handle
//
pMachine->CmFreeResDesHandle(rd); } pMachine->CmFreeLogConfHandle(lc); } if (pDeviceStart->GetChild()) CreateSubtreeResourceList(pDeviceStart->GetChild(), ResType, LogConfType, AltLogConfType); pDeviceStart = pDeviceStart->GetSibling(); } }
// This function creates a resource tree
// INPUT:
// ppResRoot -- buffer to receive the tree root
//
BOOL CResourceList::CreateResourceTree( CResource** ppResRoot ) { ASSERT(ppResRoot);
*ppResRoot = NULL;
if (!m_listRes.IsEmpty()) { POSITION pos = m_listRes.GetHeadPosition(); CResource* pResFirst;
pResFirst = m_listRes.GetNext(pos); *ppResRoot = pResFirst;
while (NULL != pos) { CResource* pRes = m_listRes.GetNext(pos); InsertResourceToTree(pRes, pResFirst, TRUE); } } return TRUE; }
BOOL CResourceList::InsertResourceToTree( CResource* pRes, CResource* pResRoot, BOOL ForcedInsert ) { CResource* pResLast = NULL;
while (pResRoot) { if (pRes->EnclosedBy(*pResRoot)) { //
// This resource is either the pResRoot child or grand child
// figure out which one it is
//
if (!pResRoot->GetChild()) { pResRoot->SetChild(pRes); pRes->SetParent(pResRoot); } else if (!InsertResourceToTree(pRes, pResRoot->GetChild(), FALSE)) { //
// The Resource is not a grand child of pResRoot.
// search for the last child of pResRoot
//
CResource* pResSibling; pResSibling = pResRoot->GetChild();
while (pResSibling->GetSibling()) pResSibling = pResSibling->GetSibling(); pResSibling->SetSibling(pRes); pRes->SetParent(pResRoot); } return TRUE; } pResLast = pResRoot; pResRoot = pResRoot->GetSibling(); } if (ForcedInsert) { if (pResLast) { // when we reach here, pResLast is the last child
pResLast->SetSibling(pRes); pRes->SetParent(pResLast->GetParent()); }
return TRUE; } return FALSE; }
CResourceList::~CResourceList() { if (!m_listRes.IsEmpty()) { POSITION pos = m_listRes.GetHeadPosition();
while (NULL != pos) { delete m_listRes.GetNext(pos); } m_listRes.RemoveAll(); } }
BOOL CResourceList::GetFirst( CResource** ppRes, PVOID& Context ) { ASSERT(ppRes);
if (!m_listRes.IsEmpty()) { POSITION pos = m_listRes.GetHeadPosition(); *ppRes = m_listRes.GetNext(pos); Context = pos; return TRUE; } Context = NULL; *ppRes = NULL;
return FALSE; }
BOOL CResourceList::GetNext( CResource** ppRes, PVOID& Context ) { ASSERT(ppRes);
POSITION pos = (POSITION)Context;
if (NULL != pos) { *ppRes = m_listRes.GetNext(pos); Context = pos; return TRUE; } *ppRes = NULL; return FALSE; }
//
// This function inserts the given resource to class's resource list
// The resources are kept in accending sorted order
void CResourceList::InsertResourceToList( CResource* pRes ) { POSITION pos; CResource* pSrc; DWORDLONG dlBase, dlLen; pRes->GetValue(&dlBase, &dlLen);
pos = m_listRes.GetHeadPosition();
while (NULL != pos) { POSITION posSave = pos; pSrc = m_listRes.GetNext(pos);
if (*pRes <= *pSrc) { m_listRes.InsertBefore(posSave, pRes); return; } } m_listRes.AddTail(pRes); }
inline CItemIdentifier* CResource::CreateIdentifier() { return new CResourceIdentifier(*this); }
|