You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
630 lines
18 KiB
630 lines
18 KiB
//====================================================================
|
|
|
|
//
|
|
|
|
// chwres.cpp -- Hardware resource access wrapper class implementation
|
|
|
|
//
|
|
|
|
// Copyright (c) 1996-2001 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
// Revisions: 02/25/97 a-jmoon Adapted from original horrible
|
|
// code -- only comments remain.
|
|
//
|
|
//====================================================================
|
|
#include "precomp.h"
|
|
#include <cregcls.h>
|
|
#include "chwres.h"
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : CHWResource::CHWResource
|
|
*
|
|
* DESCRIPTION : Constructor
|
|
*
|
|
* INPUTS : none
|
|
*
|
|
* OUTPUTS : none
|
|
*
|
|
* RETURNS : nothing
|
|
*
|
|
* COMMENTS : Initialization
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifdef NTONLY
|
|
CHWResource::CHWResource()
|
|
{
|
|
// Zero out public structure
|
|
//==========================
|
|
|
|
memset(&_SystemResourceList, 0, sizeof(_SystemResourceList)) ;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : CHWResource::~CHWResource
|
|
*
|
|
* DESCRIPTION : Destructor
|
|
*
|
|
* INPUTS : none
|
|
*
|
|
* OUTPUTS : none
|
|
*
|
|
* RETURNS : nothing
|
|
*
|
|
* COMMENTS : Cleanup
|
|
*
|
|
*****************************************************************************/
|
|
|
|
CHWResource::~CHWResource()
|
|
{
|
|
// Make sure we've destroyed everything
|
|
//=====================================
|
|
|
|
DestroySystemResourceLists() ;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : CHWResource::DestroySystemResourceLists
|
|
*
|
|
* DESCRIPTION : Walks list of devices & frees associated resource records
|
|
*
|
|
* INPUTS : none
|
|
*
|
|
* OUTPUTS : none
|
|
*
|
|
* RETURNS : nothing
|
|
*
|
|
* COMMENTS :
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void CHWResource::DestroySystemResourceLists()
|
|
{
|
|
LPDEVICE pDevice ;
|
|
LPRESOURCE_DESCRIPTOR pResource ;
|
|
|
|
while(_SystemResourceList.DeviceHead != NULL)
|
|
{
|
|
pDevice = _SystemResourceList.DeviceHead ;
|
|
_SystemResourceList.DeviceHead = pDevice->Next ;
|
|
|
|
delete pDevice->Name ;
|
|
delete pDevice->KeyName ;
|
|
|
|
while(pDevice->ResourceDescriptorHead != NULL)
|
|
{
|
|
pResource = pDevice->ResourceDescriptorHead ;
|
|
pDevice->ResourceDescriptorHead = pResource->NextDiff ;
|
|
|
|
delete pResource ;
|
|
}
|
|
|
|
delete pDevice ;
|
|
}
|
|
|
|
memset(&_SystemResourceList, 0, sizeof(_SystemResourceList)) ;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : CHWResource::CreateSystemResourceLists
|
|
* CHWResource::EnumerateResources
|
|
* CHWResource::CreateResourceList
|
|
* CHWResource::CreateResourceRecord
|
|
*
|
|
* DESCRIPTION : These four routines recursively enumerate device records
|
|
* under HKEY_LOCAL_MACHINE\Hardware\ResourceMap and its
|
|
* subkeys, creating a linked list of discovered devices.
|
|
* Under each device, a linked list of resources owned by
|
|
* the device is also created. Resource records are also
|
|
* linked into chains specific to the type of resource.
|
|
*
|
|
* INPUTS : none
|
|
*
|
|
* OUTPUTS : none
|
|
*
|
|
* RETURNS : nothing
|
|
*
|
|
* COMMENTS : Initialization
|
|
*
|
|
*****************************************************************************/
|
|
|
|
void CHWResource::CreateSystemResourceLists()
|
|
{
|
|
// Start w/clean slate
|
|
//====================
|
|
|
|
DestroySystemResourceLists() ;
|
|
|
|
// Begin device enumeration at HKLM\Hardware\ResourceMap
|
|
//======================================================
|
|
|
|
EnumerateResources(_T("Hardware\\ResourceMap")) ;
|
|
}
|
|
|
|
void CHWResource::EnumerateResources(CHString sKeyName)
|
|
{
|
|
CRegistry Reg ;
|
|
CHString sSubKeyName, sDeviceName ;
|
|
int iFirst ;
|
|
DWORD i, dwCount, dwValueType, dwValueNameSize, dwValueDataSize ;
|
|
TCHAR *pValueName ;
|
|
unsigned char *pValueData ;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor ;
|
|
|
|
// Open target key
|
|
//================
|
|
|
|
if(Reg.Open(HKEY_LOCAL_MACHINE, (LPCTSTR) sKeyName, KEY_READ) != ERROR_SUCCESS)
|
|
{
|
|
return ;
|
|
}
|
|
|
|
// First, enumerate subkeys
|
|
//=========================
|
|
|
|
for( ; ; )
|
|
{
|
|
if(Reg.GetCurrentSubKeyName(sSubKeyName) == ERROR_SUCCESS)
|
|
{
|
|
EnumerateResources(sKeyName + "\\" + sSubKeyName) ;
|
|
}
|
|
|
|
if(Reg.NextSubKey() != ERROR_SUCCESS)
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// Extract this subkey's name
|
|
//===========================
|
|
|
|
iFirst = sKeyName.ReverseFind('\\') ;
|
|
sSubKeyName = sKeyName.Mid(iFirst + 1, sKeyName.GetLength() - iFirst) ;
|
|
|
|
// Create name & data buffers
|
|
//===========================
|
|
|
|
pValueName = new TCHAR[Reg.GetLongestValueName() + 2] ;
|
|
pValueData = new unsigned char[Reg.GetLongestValueData() + 2] ;
|
|
|
|
if(pValueName == NULL || pValueData == NULL)
|
|
{
|
|
|
|
delete [] pValueName ;
|
|
delete [] pValueData ;
|
|
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
// Enumerate subkeys
|
|
//==================
|
|
|
|
try
|
|
{
|
|
for(i = 0 ; i < Reg.GetValueCount() ; i++)
|
|
{
|
|
|
|
// We need type data, so can't use the CRegistry wrapper
|
|
//======================================================
|
|
|
|
dwValueNameSize = Reg.GetLongestValueName() + 2 ;
|
|
dwValueDataSize = Reg.GetLongestValueData() + 2 ;
|
|
|
|
if(RegEnumValue(Reg.GethKey(), i, pValueName, &dwValueNameSize,
|
|
NULL, &dwValueType, pValueData, &dwValueDataSize) != ERROR_SUCCESS)
|
|
{
|
|
continue ;
|
|
}
|
|
|
|
// Only deal w/'Raw' data
|
|
//=======================
|
|
|
|
sDeviceName = pValueName ;
|
|
if(sDeviceName.Right(4) != _T(".Raw")) {
|
|
|
|
continue ;
|
|
}
|
|
|
|
// We've found some resource records -- extract device name
|
|
//=========================================================
|
|
|
|
iFirst = sDeviceName.ReverseFind('\\') ;
|
|
if(iFirst == -1)
|
|
{
|
|
// No device in value name -- device is subkey
|
|
//============================================
|
|
|
|
sDeviceName = sSubKeyName ;
|
|
}
|
|
else
|
|
{
|
|
sDeviceName = sDeviceName.Mid(iFirst + 1, sDeviceName.GetLength() - 5 - iFirst) ;
|
|
}
|
|
|
|
if(sDeviceName.IsEmpty())
|
|
{
|
|
continue ;
|
|
}
|
|
|
|
// Based on returned type, set up for resource enumeration
|
|
//========================================================
|
|
|
|
if(dwValueType == REG_FULL_RESOURCE_DESCRIPTOR)
|
|
{
|
|
dwCount = 1 ;
|
|
pFullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) pValueData ;
|
|
}
|
|
else if(dwValueType == REG_RESOURCE_LIST)
|
|
{
|
|
dwCount = ((PCM_RESOURCE_LIST) pValueData)->Count ;
|
|
pFullDescriptor = ((PCM_RESOURCE_LIST) pValueData)->List ;
|
|
}
|
|
else
|
|
{
|
|
continue ;
|
|
}
|
|
|
|
// Add the device & resources to system lists
|
|
//===========================================
|
|
|
|
CreateResourceList(sDeviceName, dwCount, pFullDescriptor, sKeyName) ;
|
|
}
|
|
}
|
|
catch ( ... )
|
|
{
|
|
delete [] pValueName ;
|
|
delete [] pValueData ;
|
|
|
|
throw;
|
|
}
|
|
|
|
delete [] pValueName ;
|
|
delete [] pValueData ;
|
|
|
|
Reg.Close() ;
|
|
}
|
|
|
|
void CHWResource::CreateResourceList(CHString sDeviceName, DWORD dwFullResourceCount,
|
|
PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor, CHString sKeyName)
|
|
{
|
|
LPDEVICE pDevice ;
|
|
DWORD i, j ;
|
|
PCM_PARTIAL_RESOURCE_LIST pPartialList ;
|
|
|
|
// Locate/create record for device
|
|
//================================
|
|
|
|
pDevice = _SystemResourceList.DeviceHead ;
|
|
while(pDevice != NULL)
|
|
{
|
|
|
|
if(sDeviceName == pDevice->Name)
|
|
{
|
|
|
|
break ;
|
|
}
|
|
|
|
pDevice = pDevice->Next ;
|
|
}
|
|
|
|
if(pDevice == NULL)
|
|
{
|
|
|
|
// Device not found -- create new device record
|
|
//=============================================
|
|
|
|
pDevice = new DEVICE ;
|
|
if(pDevice == NULL)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
memset(pDevice, 0, sizeof(DEVICE)) ;
|
|
|
|
pDevice->Name = new TCHAR[sDeviceName.GetLength() + 2] ;
|
|
if(pDevice->Name == NULL)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
try
|
|
{
|
|
_tcscpy(pDevice->Name, LPCTSTR(sDeviceName)) ;
|
|
|
|
pDevice->KeyName = new TCHAR [sKeyName.GetLength() + 2] ;
|
|
if(pDevice->KeyName == NULL)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
_tcscpy(pDevice->KeyName, LPCTSTR(sKeyName)) ;
|
|
|
|
if(_SystemResourceList.DeviceHead == NULL)
|
|
{
|
|
_SystemResourceList.DeviceHead = pDevice ;
|
|
}
|
|
else
|
|
{
|
|
_SystemResourceList.DeviceTail->Next = pDevice ;
|
|
}
|
|
|
|
_SystemResourceList.DeviceTail = pDevice ;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
delete pDevice;
|
|
throw ;
|
|
}
|
|
}
|
|
|
|
// Create record for each owned resource
|
|
//======================================
|
|
|
|
for(i = 0 ; i < dwFullResourceCount ; i++)
|
|
{
|
|
pPartialList = &pFullDescriptor->PartialResourceList ;
|
|
|
|
for(j = 0 ; j < pPartialList->Count; j++)
|
|
{
|
|
CreateResourceRecord(pDevice, pFullDescriptor->InterfaceType, pFullDescriptor->BusNumber, &pPartialList->PartialDescriptors[j]) ;
|
|
}
|
|
|
|
// Point to next full descriptor
|
|
//==============================
|
|
|
|
pFullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) &pPartialList->PartialDescriptors[pPartialList->Count] ;
|
|
}
|
|
}
|
|
|
|
void CHWResource::CreateResourceRecord(LPDEVICE pDevice, INTERFACE_TYPE InterfaceType, ULONG Bus, PCM_PARTIAL_RESOURCE_DESCRIPTOR pResource)
|
|
{
|
|
LPRESOURCE_DESCRIPTOR pNewResource, *pHead, *pTail, pCurrent, pLast ;
|
|
|
|
// Only deal w/'known' resource types
|
|
//===================================
|
|
|
|
if(pResource->Type != CmResourceTypePort &&
|
|
pResource->Type != CmResourceTypeInterrupt &&
|
|
pResource->Type != CmResourceTypeMemory &&
|
|
pResource->Type != CmResourceTypeDma )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
// Create new record for resource & add to device's list
|
|
//======================================================
|
|
|
|
pNewResource = new RESOURCE_DESCRIPTOR ;
|
|
if(pNewResource == NULL)
|
|
{
|
|
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
|
|
}
|
|
|
|
try
|
|
{
|
|
memset(pNewResource, 0, sizeof(RESOURCE_DESCRIPTOR)) ;
|
|
|
|
memcpy(&pNewResource->CmResourceDescriptor, pResource, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)) ;
|
|
|
|
pNewResource->Owner = pDevice ;
|
|
pNewResource->Bus = Bus;
|
|
pNewResource->InterfaceType = InterfaceType;
|
|
|
|
if(pDevice->ResourceDescriptorHead == NULL)
|
|
{
|
|
|
|
pDevice->ResourceDescriptorHead = pNewResource ;
|
|
}
|
|
else
|
|
{
|
|
|
|
pDevice->ResourceDescriptorTail->NextDiff = pNewResource ;
|
|
}
|
|
|
|
pDevice->ResourceDescriptorTail = pNewResource ;
|
|
}
|
|
catch ( ... )
|
|
{
|
|
delete pNewResource;
|
|
throw ;
|
|
}
|
|
|
|
// Locate insertion point into sorted type-specific list
|
|
//======================================================
|
|
|
|
switch(pResource->Type)
|
|
{
|
|
case CmResourceTypePort :
|
|
|
|
pHead = &_SystemResourceList.PortHead ;
|
|
pTail = &_SystemResourceList.PortTail ;
|
|
|
|
pCurrent = *pHead ;
|
|
pLast = NULL ;
|
|
|
|
LARGE_INTEGER liTemp; // Used to avoid 64bit alignment problems
|
|
|
|
liTemp.HighPart = pResource->u.Port.Start.HighPart;
|
|
liTemp.LowPart = pResource->u.Port.Start.LowPart;
|
|
|
|
while(pCurrent != NULL)
|
|
{
|
|
LARGE_INTEGER liTemp2; // Used to avoid 64bit alignment problems
|
|
|
|
liTemp2.HighPart = pCurrent->CmResourceDescriptor.u.Port.Start.HighPart;
|
|
liTemp2.LowPart = pCurrent->CmResourceDescriptor.u.Port.Start.LowPart;
|
|
|
|
if (liTemp2.QuadPart < liTemp.QuadPart)
|
|
{
|
|
pLast = pCurrent ;
|
|
pCurrent = pCurrent->NextSame ;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt :
|
|
{
|
|
pHead = &_SystemResourceList.InterruptHead ;
|
|
pTail = &_SystemResourceList.InterruptTail ;
|
|
|
|
pCurrent = *pHead ;
|
|
pLast = NULL ;
|
|
|
|
ULONGLONG iIRQ = pResource->u.Interrupt.Level;
|
|
|
|
// If the IRQ to add is less than the current IRQ, OR
|
|
// if the IRQ to add is the same as the current IRQ and the current
|
|
// IRQ is not an internal one, put it after the current one. This
|
|
// will make sure that internal IRQs are listed last in the list.
|
|
while (pCurrent != NULL &&
|
|
( (pCurrent->CmResourceDescriptor.u.Interrupt.Level < iIRQ) ||
|
|
((pCurrent->CmResourceDescriptor.u.Interrupt.Level == iIRQ) &&
|
|
(pCurrent->InterfaceType != Internal))
|
|
))
|
|
{
|
|
pLast = pCurrent ;
|
|
pCurrent = pCurrent->NextSame ;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeMemory :
|
|
{
|
|
|
|
pHead = &_SystemResourceList.MemoryHead ;
|
|
pTail = &_SystemResourceList.MemoryTail ;
|
|
|
|
pCurrent = *pHead ;
|
|
pLast = NULL ;
|
|
|
|
LARGE_INTEGER liTemp; // Used to avoid 64bit alignment problems
|
|
|
|
liTemp.HighPart = pResource->u.Memory.Start.HighPart;
|
|
liTemp.LowPart = pResource->u.Memory.Start.LowPart;
|
|
|
|
while(pCurrent != NULL)
|
|
{
|
|
LARGE_INTEGER liTemp2; // Used to avoid 64bit alignment problems
|
|
|
|
liTemp2.HighPart = pCurrent->CmResourceDescriptor.u.Memory.Start.HighPart;
|
|
liTemp2.LowPart = pCurrent->CmResourceDescriptor.u.Memory.Start.LowPart;
|
|
|
|
if (liTemp2.QuadPart < liTemp.QuadPart)
|
|
{
|
|
pLast = pCurrent ;
|
|
pCurrent = pCurrent->NextSame ;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case CmResourceTypeDma :
|
|
|
|
pHead = &_SystemResourceList.DmaHead ;
|
|
pTail = &_SystemResourceList.DmaTail ;
|
|
|
|
pCurrent = *pHead ;
|
|
pLast = NULL ;
|
|
|
|
while(pCurrent != NULL &&
|
|
pCurrent->CmResourceDescriptor.u.Dma.Channel < pResource->u.Dma.Channel)
|
|
{
|
|
pLast = pCurrent ;
|
|
pCurrent = pCurrent->NextSame ;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Insert into...
|
|
//===============
|
|
|
|
if(*pHead == NULL)
|
|
{
|
|
|
|
// ...empty list
|
|
//==========================
|
|
|
|
(*pHead) = pNewResource ;
|
|
(*pTail) = pNewResource ;
|
|
}
|
|
else if(pLast == NULL)
|
|
{
|
|
|
|
// ...beginning of list
|
|
//=================================
|
|
|
|
pNewResource->NextSame = pCurrent ;
|
|
(*pHead) = pNewResource ;
|
|
}
|
|
else if(pCurrent == NULL)
|
|
{
|
|
// ...end of list
|
|
//=========================
|
|
|
|
pLast->NextSame = pNewResource ;
|
|
(*pTail) = pNewResource ;
|
|
}
|
|
else
|
|
{
|
|
// ...middle of list
|
|
//==============================
|
|
|
|
pLast->NextSame = pNewResource ;
|
|
pNewResource->NextSame = pCurrent ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Helper function for converting strings to resource types
|
|
BOOL WINAPI StringFromInterfaceType( INTERFACE_TYPE it, CHString& strVal )
|
|
{
|
|
//BOOL fReturn = TRUE;
|
|
|
|
//switch ( it )
|
|
//{
|
|
// case Internal: strVal = "INTERNAL"; break;
|
|
// case Isa: strVal = "ISA"; break;
|
|
// case Eisa: strVal = "EISA"; break;
|
|
// case MicroChannel: strVal = "MICROCHANNEL"; break;
|
|
// case TurboChannel: strVal = "TURBOCHANNEL"; break;
|
|
// case PCIBus: strVal = "PCI"; break;
|
|
// case VMEBus: strVal = "VME"; break;
|
|
// case NuBus: strVal = "NU"; break;
|
|
// case PCMCIABus: strVal = "PCMCIA"; break;
|
|
// case CBus: strVal = "INTERNAL"; break;
|
|
// case MPIBus: strVal = "INTERNAL"; break;
|
|
// case MPSABus: strVal = "MPSA"; break;
|
|
// case ProcessorInternal: strVal = "PROCESSORINTERNAL"; break;
|
|
// case InternalPowerBus: strVal = "INTERNALPOWER"; break;
|
|
// case PNPISABus: strVal = "PNPISA"; break;
|
|
// case PNPBus: strVal = "PNP"; break;
|
|
// default: fReturn = FALSE;
|
|
//}
|
|
|
|
if(it > InterfaceTypeUndefined && it < MaximumInterfaceType)
|
|
{
|
|
strVal = szBusType[it];
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|