973 lines
26 KiB
C
973 lines
26 KiB
C
/*++
|
||
|
||
Copyright (c) 1995-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
conflist.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the API routines that manage conflict list reporting
|
||
|
||
CM_Query_Resource_Conflict_List
|
||
CM_Free_Resource_Conflict_Handle
|
||
CM_Get_Resource_Conflict_Count
|
||
CM_Get_Resource_Conflict_Details
|
||
|
||
Author:
|
||
|
||
Jamie Hunter (jamiehun) 4-14-1998
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
|
||
Revision History:
|
||
|
||
April-14-1998 jamiehun
|
||
|
||
Addition of NT extended resource-conflict functions
|
||
|
||
--*/
|
||
|
||
|
||
//
|
||
// includes
|
||
//
|
||
#include "precomp.h"
|
||
#include "cfgi.h"
|
||
#include "setupapi.h"
|
||
#include "spapip.h"
|
||
|
||
typedef struct _CONFLICT_LIST_HEADER {
|
||
HMACHINE Machine; // indicates relevent machine
|
||
PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictInfo; // data obtained via UMPNPMGR
|
||
ULONG Signature; // marks this structure as a handle
|
||
} CONFLICT_LIST_HEADER, *PCONFLICT_LIST_HEADER;
|
||
|
||
|
||
//
|
||
// Private prototypes
|
||
//
|
||
|
||
BOOL
|
||
ValidateConfListHandle(
|
||
PCONFLICT_LIST_HEADER pConfList
|
||
);
|
||
|
||
VOID
|
||
FreeConfListHandle(
|
||
PCONFLICT_LIST_HEADER pConfList
|
||
);
|
||
|
||
//
|
||
// private prototypes from resdes.c
|
||
//
|
||
|
||
CONFIGRET
|
||
CreateResDesHandle(
|
||
PRES_DES prdResDes,
|
||
DEVINST dnDevInst,
|
||
ULONG ulLogType,
|
||
ULONG ulLogTag,
|
||
ULONG ulResType,
|
||
ULONG ulResTag
|
||
);
|
||
|
||
BOOL
|
||
ValidateResDesHandle(
|
||
PPrivate_Res_Des_Handle pResDes
|
||
);
|
||
|
||
CONFIGRET
|
||
Get32bitResDesFrom64bitResDes(
|
||
IN RESOURCEID ResourceID,
|
||
IN PCVOID ResData64,
|
||
IN ULONG ResLen64,
|
||
OUT PVOID * ResData32,
|
||
OUT ULONG * ResLen32
|
||
);
|
||
|
||
|
||
//
|
||
// private prototypes from logconf.c
|
||
//
|
||
CONFIGRET
|
||
CreateLogConfHandle(
|
||
PLOG_CONF plcLogConf,
|
||
DEVINST dnDevInst,
|
||
ULONG ulLogType,
|
||
ULONG ulLogTag
|
||
);
|
||
|
||
BOOL
|
||
ValidateLogConfHandle(
|
||
PPrivate_Log_Conf_Handle pLogConf
|
||
);
|
||
|
||
|
||
|
||
//
|
||
// API functions
|
||
//
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Query_Resource_Conflict_List(
|
||
OUT PCONFLICT_LIST pclConflictList,
|
||
IN DEVINST dnDevInst,
|
||
IN RESOURCEID ResourceID,
|
||
IN PCVOID ResourceData,
|
||
IN ULONG ResourceLen,
|
||
IN ULONG ulFlags,
|
||
IN HMACHINE hMachine
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieves conflict list
|
||
returns a handle for list
|
||
|
||
Arguments:
|
||
|
||
pclConflictList - holds returned conflict list handle
|
||
dnDevInst Device we want to allocate a resource for
|
||
ResourceID Type of resource, ResType_xxxx
|
||
ResourceData Resource specific data
|
||
ResourceLen length of ResourceData
|
||
|
||
ulFlags Width of certain variable-size resource
|
||
descriptor structure fields, where applicable.
|
||
|
||
Currently, the following flags are defined:
|
||
|
||
CM_RESDES_WIDTH_32 or
|
||
CM_RESDES_WIDTH_64
|
||
|
||
If no flags are specified, the width of the variable-sized
|
||
resource data supplied is assumed to be that native to the
|
||
platform of the caller.
|
||
|
||
hMachine - optional machine to query
|
||
|
||
Return Value:
|
||
|
||
CM status value
|
||
|
||
--*/
|
||
{
|
||
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
WCHAR DeviceID[MAX_DEVICE_ID_LEN];
|
||
PVOID hStringTable = NULL;
|
||
handle_t hBinding = NULL;
|
||
PPLUGPLAY_CONTROL_CONFLICT_LIST pConfList1 = NULL;
|
||
PPLUGPLAY_CONTROL_CONFLICT_LIST pConfList2 = NULL;
|
||
PCONFLICT_LIST_HEADER pConfListHeader = NULL;
|
||
ULONG ConfListSize1;
|
||
ULONG ConfListSize2;
|
||
ULONG ulLen = MAX_DEVICE_ID_LEN;
|
||
BOOL Success;
|
||
PVOID ResourceData32 = NULL;
|
||
ULONG ResourceLen32 = 0;
|
||
|
||
try {
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (dnDevInst == 0) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(ulFlags, CM_RESDES_WIDTH_BITS)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if ((ulFlags & CM_RESDES_WIDTH_32) && (ulFlags & CM_RESDES_WIDTH_64)) {
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
#ifdef _WIN64
|
||
if ((ulFlags & CM_RESDES_WIDTH_BITS) == CM_RESDES_WIDTH_DEFAULT) {
|
||
ulFlags |= CM_RESDES_WIDTH_64;
|
||
}
|
||
#endif // _WIN64
|
||
|
||
if (ulFlags & CM_RESDES_WIDTH_32) {
|
||
ulFlags &= ~CM_RESDES_WIDTH_BITS;
|
||
}
|
||
|
||
if (pclConflictList == NULL) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (ResourceData == NULL || ResourceLen == 0) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
#if 0
|
||
if (ResourceID > ResType_MAX) { // ClassSpecific not allowed
|
||
Status = CR_INVALID_RESOURCEID;
|
||
goto Clean0;
|
||
}
|
||
#endif
|
||
if (ResourceID == ResType_All) {
|
||
Status = CR_INVALID_RESOURCEID; // can't specify All on a detect
|
||
goto Clean0;
|
||
}
|
||
//
|
||
// Initialize parameters
|
||
//
|
||
*pclConflictList = 0;
|
||
|
||
//
|
||
// setup rpc binding handle and string table handle
|
||
//
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// Make sure the server can support the client's 64-bit resdes request.
|
||
// Only server versions 0x0501 and greater support CM_RESDES_WIDTH_64.
|
||
//
|
||
if (ulFlags & CM_RESDES_WIDTH_64) {
|
||
if (!CM_Is_Version_Available_Ex((WORD)0x0501,
|
||
hMachine)) {
|
||
//
|
||
// Server can only support 32-bit resdes. Have the client
|
||
// convert the caller's 64-bit resdes to a 32-bit resdes for the
|
||
// server.
|
||
//
|
||
ulFlags &= ~CM_RESDES_WIDTH_BITS;
|
||
|
||
Status = Get32bitResDesFrom64bitResDes(ResourceID,ResourceData,ResourceLen,&ResourceData32,&ResourceLen32);
|
||
if(Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
if(ResourceData32) {
|
||
ResourceData = ResourceData32;
|
||
ResourceLen = ResourceLen32;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// retreive device instance string that corresponds to dnDevInst
|
||
//
|
||
Success = pSetupStringTableStringFromIdEx(hStringTable, dnDevInst,DeviceID,&ulLen);
|
||
if (Success == FALSE || INVALID_DEVINST(DeviceID)) {
|
||
Status = CR_INVALID_DEVINST;
|
||
goto Clean0;
|
||
}
|
||
|
||
pConfListHeader = (PCONFLICT_LIST_HEADER)pSetupMalloc(sizeof(CONFLICT_LIST_HEADER));
|
||
if (pConfListHeader == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// estimate size required to hold one conflict
|
||
//
|
||
ConfListSize1 = sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST)+ // header + one entry
|
||
sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS)+ // strings marker
|
||
(sizeof(WCHAR)*MAX_DEVICE_ID_LEN); // enough space for one string
|
||
|
||
pConfList1 = (PPLUGPLAY_CONTROL_CONFLICT_LIST)pSetupMalloc(ConfListSize1);
|
||
if (pConfList1 == NULL) {
|
||
Status = CR_OUT_OF_MEMORY;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// first try
|
||
//
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_QueryResConfList(
|
||
hBinding, // rpc binding handle
|
||
DeviceID, // device id string
|
||
ResourceID, // resource type
|
||
(LPBYTE)ResourceData, // actual res des data
|
||
ResourceLen, // size in bytes of ResourceData
|
||
(LPBYTE)pConfList1, // buffer
|
||
ConfListSize1, // size of buffer
|
||
ulFlags); // currently zero
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_QueryResConfList (first pass) caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0; // quit for any error
|
||
}
|
||
|
||
if (pConfList1->ConflictsCounted > pConfList1->ConflictsListed) {
|
||
//
|
||
// need more space, multiple conflict
|
||
//
|
||
ConfListSize2 = pConfList1->RequiredBufferSize;
|
||
pConfList2 = (PPLUGPLAY_CONTROL_CONFLICT_LIST)pSetupMalloc(ConfListSize2);
|
||
|
||
if (pConfList2 != NULL) {
|
||
//
|
||
// Try to use this instead
|
||
//
|
||
RpcTryExcept {
|
||
//
|
||
// call rpc service entry point
|
||
//
|
||
Status = PNP_QueryResConfList(
|
||
hBinding, // rpc binding handle
|
||
DeviceID, // device id string
|
||
ResourceID, // resource type
|
||
(LPBYTE)ResourceData, // actual res des data
|
||
ResourceLen, // size in bytes of ResourceData
|
||
(LPBYTE)pConfList2, // buffer
|
||
ConfListSize2, // size of buffer
|
||
ulFlags); // currently zero
|
||
}
|
||
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
||
KdPrintEx((DPFLTR_PNPMGR_ID,
|
||
DBGF_ERRORS,
|
||
"PNP_QueryResConfList (second pass) caused an exception (%d)\n",
|
||
RpcExceptionCode()));
|
||
|
||
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (Status != CR_SUCCESS) {
|
||
//
|
||
// if we got error second time, but first time success
|
||
// use what we got on first attempt
|
||
// (I can't see this happening, but Murphey says it can)
|
||
//
|
||
pSetupFree(pConfList2);
|
||
Status = CR_SUCCESS;
|
||
} else {
|
||
//
|
||
// use second attempt
|
||
//
|
||
pSetupFree(pConfList1);
|
||
pConfList1 = pConfList2;
|
||
ConfListSize1 = ConfListSize2;
|
||
}
|
||
//
|
||
// either way, we've deleted a buffer
|
||
//
|
||
pConfList2 = NULL;
|
||
}
|
||
}
|
||
|
||
if(ConfListSize1 > pConfList1->RequiredBufferSize) {
|
||
//
|
||
// we can release some of the buffer we requested
|
||
//
|
||
ConfListSize2 = pConfList1->RequiredBufferSize;
|
||
pConfList2 = (PPLUGPLAY_CONTROL_CONFLICT_LIST)pSetupRealloc(pConfList1,ConfListSize2);
|
||
if(pConfList2) {
|
||
//
|
||
// success, we managed to save space
|
||
//
|
||
pConfList1 = pConfList2;
|
||
ConfListSize1 = ConfListSize2;
|
||
pConfList2 = NULL;
|
||
}
|
||
}
|
||
//
|
||
// if we get here, we have a successfully valid handle
|
||
//
|
||
pConfListHeader->Signature = CM_PRIVATE_CONFLIST_SIGNATURE;
|
||
pConfListHeader->Machine = hMachine;
|
||
pConfListHeader->ConflictInfo = pConfList1;
|
||
*pclConflictList = (ULONG_PTR)pConfListHeader;
|
||
pConfList1 = NULL;
|
||
pConfListHeader = NULL;
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
//
|
||
// cleanup
|
||
//
|
||
if (pConfListHeader != NULL) {
|
||
pSetupFree(pConfListHeader);
|
||
}
|
||
if (pConfList1 != NULL) {
|
||
pSetupFree(pConfList1);
|
||
}
|
||
if (pConfList2 != NULL) {
|
||
pSetupFree(pConfList2);
|
||
}
|
||
|
||
if (ResourceData32) {
|
||
pSetupFree(ResourceData32);
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Query_Resource_Conflict_List
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Free_Resource_Conflict_Handle(
|
||
IN CONFLICT_LIST clConflictList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free's a conflict-list handle
|
||
|
||
Arguments:
|
||
clConflictList - handle of conflict list to free
|
||
|
||
Return Value:
|
||
|
||
CM status value
|
||
|
||
--*/
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PCONFLICT_LIST_HEADER pConfList = NULL;
|
||
|
||
try {
|
||
//
|
||
// Validate parameters
|
||
//
|
||
pConfList = (PCONFLICT_LIST_HEADER)clConflictList;
|
||
if (!ValidateConfListHandle(pConfList)) {
|
||
Status = CR_INVALID_CONFLICT_LIST;
|
||
goto Clean0;
|
||
}
|
||
|
||
FreeConfListHandle(pConfList);
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Resource_Conflict_Count(
|
||
IN CONFLICT_LIST clConflictList,
|
||
OUT PULONG pulCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieves number of conflicts from list
|
||
|
||
Arguments:
|
||
clConflictList - handle of conflict list
|
||
pulCount - filled with number of conflicts (0 if no conflicts)
|
||
|
||
Return Value:
|
||
|
||
CM status value
|
||
|
||
--*/
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PCONFLICT_LIST_HEADER pConfList;
|
||
|
||
try {
|
||
//
|
||
// Validate parameters
|
||
//
|
||
pConfList = (PCONFLICT_LIST_HEADER)clConflictList;
|
||
if (!ValidateConfListHandle(pConfList)) {
|
||
Status = CR_INVALID_CONFLICT_LIST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (pulCount == NULL) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// return count parameter
|
||
// that can be used to iterate conflicts
|
||
//
|
||
|
||
*pulCount = pConfList->ConflictInfo->ConflictsListed;
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Free_Resource_Conflict_Handle
|
||
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Resource_Conflict_DetailsW(
|
||
IN CONFLICT_LIST clConflictList,
|
||
IN ULONG ulIndex,
|
||
IN OUT PCONFLICT_DETAILS_W pConflictDetails
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Retrieves conflict details
|
||
for a specific conflict
|
||
|
||
Arguments:
|
||
clConflictList - handle of conflict list
|
||
ulIndex - index of conflict to query, 0 to count-1
|
||
where count is obtained from CM_Get_Resource_Conflict_Count
|
||
pConflictDetails - structure to be filled with conflict details
|
||
must have CD_ulSize & CD_ulFlags initialized before calling function
|
||
eg: pConflictDetails->CD_ulSize = sizeof(CONFLICT_DETAILS)
|
||
pConflictDetails->CD_ulFlags = CM_CDMASK_ALL
|
||
|
||
Return Value:
|
||
|
||
CM status value
|
||
|
||
--*/
|
||
{
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
PCONFLICT_LIST_HEADER pConfList;
|
||
PPLUGPLAY_CONTROL_CONFLICT_ENTRY pConfEntry;
|
||
PWCHAR pString;
|
||
ULONG ulFlags;
|
||
PPLUGPLAY_CONTROL_CONFLICT_STRINGS ConfStrings;
|
||
PVOID hStringTable = NULL;
|
||
handle_t hBinding = NULL;
|
||
HMACHINE hMachine = NULL;
|
||
DEVINST dnDevInst;
|
||
ULONG ulSize;
|
||
|
||
try {
|
||
//
|
||
// Validate parameters
|
||
//
|
||
pConfList = (PCONFLICT_LIST_HEADER)clConflictList;
|
||
if (!ValidateConfListHandle(pConfList)) {
|
||
Status = CR_INVALID_CONFLICT_LIST;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (pConflictDetails == NULL) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(pConflictDetails->CD_ulSize != sizeof(CONFLICT_DETAILS_W)) {
|
||
//
|
||
// currently only one structure size supported
|
||
//
|
||
Status = CR_INVALID_STRUCTURE_SIZE;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(pConflictDetails->CD_ulMask, CM_CDMASK_VALID)) {
|
||
//
|
||
// CM_CDMASK_VALID describes the bits that are supported
|
||
//
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (pConflictDetails->CD_ulMask == 0) {
|
||
//
|
||
// must want something
|
||
//
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(ulIndex >= pConfList->ConflictInfo->ConflictsListed) {
|
||
//
|
||
// validate index
|
||
//
|
||
Status = CR_INVALID_INDEX;
|
||
goto Clean0;
|
||
}
|
||
|
||
hMachine = (HMACHINE)(pConfList->Machine);
|
||
|
||
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
||
//
|
||
// handles
|
||
//
|
||
Status = CR_FAILURE;
|
||
goto Clean0;
|
||
}
|
||
|
||
|
||
ConfStrings = (PPLUGPLAY_CONTROL_CONFLICT_STRINGS)&(pConfList->ConflictInfo->ConflictEntry[pConfList->ConflictInfo->ConflictsListed]);
|
||
pConfEntry = pConfList->ConflictInfo->ConflictEntry + ulIndex;
|
||
pString = ConfStrings->DeviceInstanceStrings + pConfEntry->DeviceInstance; // the string for this entry
|
||
|
||
//
|
||
// init requested parameters
|
||
//
|
||
ulFlags = pConflictDetails->CD_ulMask;
|
||
pConflictDetails->CD_ulMask = 0;
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_DEVINST)) {
|
||
pConflictDetails->CD_dnDevInst = 0;
|
||
}
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_RESDES)) {
|
||
pConflictDetails->CD_rdResDes = 0;
|
||
}
|
||
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_FLAGS)) {
|
||
pConflictDetails->CD_ulFlags = 0;
|
||
}
|
||
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_DESCRIPTION)) {
|
||
pConflictDetails->CD_szDescription[0] = 0;
|
||
}
|
||
|
||
//
|
||
// fill in requested parameters
|
||
//
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_DEVINST)) {
|
||
|
||
if (pString[0] == 0 || IS_FLAG_SET(pConfEntry->DeviceFlags,PNP_CE_LEGACY_DRIVER)) {
|
||
//
|
||
// not a valid dev-instance
|
||
//
|
||
dnDevInst = -1;
|
||
} else {
|
||
//
|
||
// lookup DeviceID
|
||
//
|
||
ASSERT(pString && *pString && IsLegalDeviceId(pString));
|
||
|
||
dnDevInst = (DEVINST)pSetupStringTableAddString(hStringTable,
|
||
pString,
|
||
STRTAB_CASE_SENSITIVE);
|
||
if (dnDevInst == (DEVINST)(-1)) {
|
||
Status = CR_OUT_OF_MEMORY; // probably out of memory
|
||
goto Clean0;
|
||
}
|
||
}
|
||
pConflictDetails->CD_dnDevInst = dnDevInst;
|
||
pConflictDetails->CD_ulMask |= CM_CDMASK_DEVINST;
|
||
}
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_RESDES)) {
|
||
//
|
||
// not implemented yet
|
||
//
|
||
pConflictDetails->CD_rdResDes = 0;
|
||
}
|
||
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_FLAGS)) {
|
||
//
|
||
// convert flags
|
||
//
|
||
pConflictDetails->CD_ulFlags = 0;
|
||
if(IS_FLAG_SET(pConfEntry->DeviceFlags,PNP_CE_LEGACY_DRIVER)) {
|
||
//
|
||
// description describes a driver, not a device
|
||
//
|
||
pConflictDetails->CD_ulFlags |= CM_CDFLAGS_DRIVER;
|
||
}
|
||
if(IS_FLAG_SET(pConfEntry->DeviceFlags,PNP_CE_ROOT_OWNED)) {
|
||
//
|
||
// resource is owned by root device
|
||
//
|
||
pConflictDetails->CD_ulFlags |= CM_CDFLAGS_ROOT_OWNED;
|
||
}
|
||
if(IS_FLAG_SET(pConfEntry->DeviceFlags,PNP_CE_TRANSLATE_FAILED) || IS_FLAG_SET(pConfEntry->DeviceFlags,PNP_CE_ROOT_OWNED)) {
|
||
//
|
||
// resource cannot be allocated, but no descriptive text
|
||
//
|
||
pConflictDetails->CD_ulFlags |= CM_CDFLAGS_RESERVED;
|
||
}
|
||
}
|
||
|
||
if (IS_FLAG_SET(ulFlags , CM_CDMASK_DESCRIPTION)) {
|
||
if (pString[0] == 0 || IS_FLAG_SET(pConfEntry->DeviceFlags,PNP_CE_LEGACY_DRIVER)) {
|
||
//
|
||
// copy string directly, specifies legacy driver (or nothing for unavailable)
|
||
//
|
||
lstrcpynW(pConflictDetails->CD_szDescription,pString,MAX_PATH);
|
||
} else {
|
||
//
|
||
// copy a descriptive name for P&P device
|
||
//
|
||
ASSERT(pString && *pString && IsLegalDeviceId(pString));
|
||
|
||
dnDevInst = (DEVINST)pSetupStringTableAddString(hStringTable,
|
||
pString,
|
||
STRTAB_CASE_SENSITIVE);
|
||
if (dnDevInst == (DEVINST)(-1)) {
|
||
Status = CR_OUT_OF_MEMORY; // probably out of memory
|
||
goto Clean0;
|
||
}
|
||
|
||
ulSize = sizeof(pConflictDetails->CD_szDescription);
|
||
if (CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
CM_DRP_FRIENDLYNAME,
|
||
NULL, (LPBYTE)(pConflictDetails->CD_szDescription),
|
||
&ulSize, 0,hMachine) != CR_SUCCESS) {
|
||
|
||
ulSize = sizeof(pConflictDetails->CD_szDescription);
|
||
if (CM_Get_DevNode_Registry_Property_ExW(dnDevInst,
|
||
CM_DRP_DEVICEDESC,
|
||
NULL, (LPBYTE)(pConflictDetails->CD_szDescription),
|
||
&ulSize, 0,hMachine) != CR_SUCCESS) {
|
||
|
||
//
|
||
// unknown
|
||
//
|
||
pConflictDetails->CD_szDescription[0] = 0;
|
||
}
|
||
}
|
||
}
|
||
pConflictDetails->CD_ulMask |= CM_CDMASK_DESCRIPTION;
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Resource_Conflict_DetailsW
|
||
|
||
|
||
|
||
BOOL
|
||
ValidateConfListHandle(
|
||
PCONFLICT_LIST_HEADER pConfList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates a conflict-list handle
|
||
pConfList must not be null, and must
|
||
contain a valid signature
|
||
|
||
Arguments:
|
||
|
||
pConfList - handle to conflict list
|
||
|
||
Return Value:
|
||
|
||
TRUE if valid, FALSE if not valid
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// validate parameters
|
||
//
|
||
if (pConfList == NULL) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// check for the private conflict list signature
|
||
//
|
||
if (pConfList->Signature != CM_PRIVATE_CONFLIST_SIGNATURE) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
} // ValidateConfListHandle
|
||
|
||
|
||
|
||
VOID
|
||
FreeConfListHandle(
|
||
PCONFLICT_LIST_HEADER pConfList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Releases memory allocated for Conflict List
|
||
Makes sure Signature is invalid
|
||
|
||
Arguments:
|
||
|
||
pConfList - valid handle to conflict list
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
if(pConfList != NULL) {
|
||
pConfList->Signature = 0;
|
||
if(pConfList->ConflictInfo) {
|
||
pSetupFree(pConfList->ConflictInfo);
|
||
}
|
||
pSetupFree(pConfList);
|
||
}
|
||
|
||
return;
|
||
|
||
} // FreeConfListHandle
|
||
|
||
|
||
|
||
|
||
//-------------------------------------------------------------------
|
||
// ANSI STUBS
|
||
//-------------------------------------------------------------------
|
||
|
||
|
||
CMAPI
|
||
CONFIGRET
|
||
WINAPI
|
||
CM_Get_Resource_Conflict_DetailsA(
|
||
IN CONFLICT_LIST clConflictList,
|
||
IN ULONG ulIndex,
|
||
IN OUT PCONFLICT_DETAILS_A pConflictDetails
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Ansi version of CM_Get_Resource_Conflict_DetailsW
|
||
|
||
--*/
|
||
{
|
||
CONFLICT_DETAILS_W detailsW;
|
||
CONFIGRET Status = CR_SUCCESS;
|
||
ULONG ulAnsiLength;
|
||
|
||
try {
|
||
//
|
||
// Validate parameters we need for Ansi part
|
||
// further validation occurs in Wide-char part
|
||
//
|
||
if (pConflictDetails == NULL) {
|
||
Status = CR_INVALID_POINTER;
|
||
goto Clean0;
|
||
}
|
||
|
||
if(pConflictDetails->CD_ulSize != sizeof(CONFLICT_DETAILS_A)) {
|
||
//
|
||
// currently only one structure size supported
|
||
//
|
||
Status = CR_INVALID_STRUCTURE_SIZE;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (INVALID_FLAGS(pConflictDetails->CD_ulMask, CM_CDMASK_VALID)) {
|
||
//
|
||
// CM_CDMASK_VALID describes the bits that are supported
|
||
//
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
if (pConflictDetails->CD_ulMask == 0) {
|
||
//
|
||
// must want something
|
||
//
|
||
Status = CR_INVALID_FLAG;
|
||
goto Clean0;
|
||
}
|
||
|
||
ZeroMemory(&detailsW,sizeof(detailsW));
|
||
detailsW.CD_ulSize = sizeof(detailsW);
|
||
detailsW.CD_ulMask = pConflictDetails->CD_ulMask;
|
||
|
||
Status = CM_Get_Resource_Conflict_DetailsW(clConflictList,ulIndex,&detailsW);
|
||
if (Status != CR_SUCCESS) {
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// copy details
|
||
//
|
||
pConflictDetails->CD_ulMask = detailsW.CD_ulMask;
|
||
|
||
if (IS_FLAG_SET(detailsW.CD_ulMask , CM_CDMASK_DEVINST)) {
|
||
pConflictDetails->CD_dnDevInst = detailsW.CD_dnDevInst;
|
||
}
|
||
if (IS_FLAG_SET(detailsW.CD_ulMask , CM_CDMASK_RESDES)) {
|
||
pConflictDetails->CD_rdResDes = detailsW.CD_rdResDes;
|
||
}
|
||
|
||
if (IS_FLAG_SET(detailsW.CD_ulMask , CM_CDMASK_FLAGS)) {
|
||
pConflictDetails->CD_ulFlags = detailsW.CD_ulFlags;
|
||
}
|
||
|
||
if (IS_FLAG_SET(detailsW.CD_ulMask , CM_CDMASK_DESCRIPTION)) {
|
||
pConflictDetails->CD_szDescription[0] = 0;
|
||
//
|
||
// need to convery from UNICODE to ANSI
|
||
//
|
||
ulAnsiLength = MAX_PATH;
|
||
Status = PnPUnicodeToMultiByte(detailsW.CD_szDescription,
|
||
MAX_PATH*sizeof(WCHAR),
|
||
pConflictDetails->CD_szDescription,
|
||
&ulAnsiLength);
|
||
if (Status != CR_SUCCESS) {
|
||
//
|
||
// error occurred
|
||
//
|
||
Status = CR_FAILURE;
|
||
}
|
||
}
|
||
|
||
Clean0:
|
||
NOTHING;
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = CR_FAILURE;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // CM_Get_Resource_Conflict_DetailsA
|
||
|
||
|