Source code of Windows XP (NT5)
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.

1453 lines
35 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name:
  4. devres2.c
  5. Abstract:
  6. Utility routines for resource matching
  7. Author:
  8. Jamie Hunter (jamiehun) 9-July-1998
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. PRDE_LIST
  13. pRDEList_Alloc()
  14. /*++
  15. Routine Description:
  16. Allocates a list-entry node
  17. Arguments:
  18. Return Value:
  19. PRDE_LIST entry
  20. --*/
  21. {
  22. PRDE_LIST Node;
  23. Node = (PRDE_LIST)MyMalloc(sizeof(RDE_LIST));
  24. if (Node == NULL) {
  25. return NULL;
  26. }
  27. Node->Prev = Node;
  28. Node->Next = Node;
  29. Node->Entry = NULL;
  30. return Node;
  31. }
  32. VOID
  33. pRDEList_AddHead(
  34. IN OUT PRDE_LIST pList,
  35. IN PRDE_LIST Node
  36. )
  37. /*++
  38. Routine Description:
  39. Adds a node to head of list
  40. Arguments:
  41. pList = pointer to list
  42. Node = node to add
  43. Return Value:
  44. none
  45. --*/
  46. {
  47. MYASSERT(Node);
  48. MYASSERT(Node->Prev == Node);
  49. MYASSERT(Node->Next == Node);
  50. MYASSERT(pList);
  51. Node->Prev = pList;
  52. Node->Next = pList->Next;
  53. Node->Next->Prev = Node;
  54. pList->Next = Node; // Head
  55. }
  56. VOID
  57. pRDEList_AddTail(
  58. IN OUT PRDE_LIST pList,
  59. IN PRDE_LIST Node
  60. )
  61. /*++
  62. Routine Description:
  63. Adds a node to tail of list
  64. Arguments:
  65. pList = pointer to list
  66. Node = node to add
  67. Return Value:
  68. none
  69. --*/
  70. {
  71. MYASSERT(Node);
  72. MYASSERT(Node->Prev == Node);
  73. MYASSERT(Node->Next == Node);
  74. MYASSERT(pList);
  75. Node->Next = pList;
  76. Node->Prev = pList->Prev;
  77. Node->Prev->Next = Node;
  78. pList->Prev = Node; // Tail
  79. }
  80. VOID
  81. pRDEList_Remove(
  82. IN PRDE_LIST Node
  83. )
  84. /*++
  85. Routine Description:
  86. Removes a node from list that node is member of
  87. Arguments:
  88. Node = node to remove
  89. Return Value:
  90. none
  91. --*/
  92. {
  93. MYASSERT(Node);
  94. if (Node->Prev == Node && Node->Next == Node) {
  95. //
  96. // already removed
  97. //
  98. return;
  99. }
  100. Node->Prev->Next = Node->Next;
  101. Node->Next->Prev = Node->Prev;
  102. Node->Next = Node;
  103. Node->Prev = Node;
  104. }
  105. PRDE_LIST
  106. pRDEList_Find(
  107. IN PRDE_LIST pList,
  108. IN PRESDES_ENTRY pItem
  109. )
  110. /*++
  111. Routine Description:
  112. Looks for pItem in pList
  113. Arguments:
  114. pList = list to search
  115. pItem = item to search for
  116. Return Value:
  117. Node entry, or NULL
  118. --*/
  119. {
  120. PRDE_LIST Node;
  121. MYASSERT(pList);
  122. MYASSERT(pItem);
  123. Node = pList->Next; // head
  124. while (Node != pList) {
  125. if (Node->Entry == pItem) {
  126. return Node;
  127. }
  128. Node = Node->Next;
  129. }
  130. return NULL;
  131. }
  132. VOID
  133. pRDEList_Destroy(
  134. IN PRDE_LIST pList
  135. )
  136. /*++
  137. Routine Description:
  138. Destroy pList and everything on pList
  139. Arguments:
  140. pList = list to destroy
  141. Return Value:
  142. Node entry, or NULL
  143. --*/
  144. {
  145. PRDE_LIST Node,Next;
  146. if (pList == NULL) {
  147. return;
  148. }
  149. Node = pList; // head
  150. do
  151. {
  152. Next = Node->Next;
  153. MyFree(Node); // this will free pList first, and then everything else on same list
  154. Node = Next;
  155. }
  156. while (Node != pList);
  157. }
  158. BOOL
  159. pGetMatchingRange(
  160. IN ULONG64 ulKnownValue,
  161. IN ULONG64 ulKnownLen,
  162. IN LPBYTE pData,
  163. IN RESOURCEID ResType,
  164. OUT PULONG pRange,
  165. OUT PBOOL pExact,
  166. OUT PULONG pFlags
  167. )
  168. /*++
  169. Routine Description:
  170. Finds range index for resource inside ResDes
  171. Arguments:
  172. ulKnownValue - base address
  173. ulKnownLen - length of resources
  174. pData/ResType - resource data we're comparing with
  175. pRange - output range index
  176. pExact - output true if there is only one range
  177. pFlags - output flags from matching range
  178. Return Value:
  179. BOOL if match
  180. --*/
  181. {
  182. PGENERIC_RESOURCE pGenRes = NULL;
  183. ULONG64 ulValue = 0, ulLen = 0, ulEnd = 0;
  184. ULONG ulFlags = 0, i;
  185. pGenRes = (PGENERIC_RESOURCE)pData;
  186. for (i = 0; i < pGenRes->GENERIC_Header.GENERIC_Count; i++) {
  187. pGetRangeValues(pData, ResType, i, &ulValue, &ulLen, &ulEnd, NULL, &ulFlags);
  188. if (ulLen != ulKnownLen) {
  189. continue;
  190. }
  191. if ((ulKnownValue >= ulValue) &&
  192. ((ulKnownValue + ulLen - 1) <= ulEnd)) {
  193. if (pRange != NULL) {
  194. *pRange = i;
  195. }
  196. //
  197. // consider exact case
  198. //
  199. if (pExact != NULL) {
  200. if (pGenRes->GENERIC_Header.GENERIC_Count==1 && ulValue == ulKnownValue && (ulKnownValue + ulLen - 1) == ulEnd) {
  201. *pExact = TRUE;
  202. }
  203. }
  204. if (pFlags != NULL) {
  205. //
  206. // want nearest flags
  207. //
  208. *pFlags = ulFlags;
  209. }
  210. return TRUE;
  211. }
  212. }
  213. if (pRange != NULL) {
  214. *pRange = 0;
  215. }
  216. return FALSE;
  217. }
  218. ULONG
  219. pTryMatch(
  220. IN OUT PRESDES_ENTRY pKnown,
  221. IN OUT PRDE_LIST pResList,
  222. IN OUT PULONG pDepth
  223. )
  224. /*++
  225. Routine Description:
  226. Looks for best match of remaining requirements in
  227. remaining available resources
  228. returns number of matched requirements
  229. Arguments:
  230. pKnown - requirements list (what is remaining)
  231. pResList - list of available resources
  232. Return Value:
  233. Node entry, or NULL
  234. --*/
  235. {
  236. ULONG ThisBest = 0;
  237. ULONG MyBest = 0;
  238. PRDE_LIST pIterator = NULL;
  239. PRESDES_ENTRY pRange;
  240. ULONG64 ulValue, ulLen, ulEnd;
  241. ULONG ulFlags;
  242. BOOL Exact = FALSE;
  243. ULONG Best = 0;
  244. PRDE_LIST pBestRes = NULL;
  245. BOOL BadMatch = FALSE;
  246. BOOL Prune = FALSE;
  247. BOOL NoRemaining = TRUE;
  248. MYASSERT(pDepth);
  249. *pDepth = 0;
  250. if (pKnown == NULL) {
  251. //
  252. // end recursion
  253. //
  254. return 0;
  255. }
  256. pKnown->CrossLink = NULL;
  257. //
  258. // we're looking for a match in pResList for pKnown
  259. // case (1) get a "Best" for if we decide not to match
  260. // case (2) get a "Best" for exact match, and chose between (1) and (2) if one exists
  261. // case (3) get a "Best" for each possible range match and choose best between (1) and all (3)
  262. //
  263. //
  264. // consider case(1) - what the results would be if we wasn't able to fit anything in
  265. //
  266. //Best = pTryMatch(pKnown->Next,pResList,pDepth);
  267. //pBestRes = NULL;
  268. pGetHdrValues(pKnown->ResDesData, pKnown->ResDesType, &ulValue, &ulLen, &ulEnd, &ulFlags);
  269. //
  270. // consider case(2) and (3) together
  271. //
  272. for(pIterator = pResList->Next;pIterator!=pResList;pIterator = pIterator->Next) {
  273. //
  274. // iterate through remaining resources
  275. //
  276. pRange = pIterator->Entry;
  277. if (pRange == NULL) {
  278. //
  279. // this has been used
  280. //
  281. continue;
  282. }
  283. if (pRange->ResDesType != pKnown->ResDesType) {
  284. //
  285. // not the kind of resource i'm looking for
  286. //
  287. continue;
  288. }
  289. NoRemaining = FALSE;
  290. if(pGetMatchingRange(ulValue, ulLen,pRange->ResDesData, pRange->ResDesType,NULL,&Exact,NULL)) {
  291. pIterator->Entry = NULL; // eliminate this range
  292. ThisBest = pTryMatch(pKnown->Next,pResList,pDepth); // match the rest, with us using this resource-range
  293. pIterator->Entry = pRange;
  294. if ((ThisBest > Best) || (pBestRes == NULL)) {
  295. //
  296. // the current best match (or first match if pBestRes == NULL)
  297. //
  298. pKnown->CrossLink = pRange;
  299. pBestRes = pIterator;
  300. Best = ThisBest;
  301. MyBest = 1;
  302. BadMatch = FALSE;
  303. } else {
  304. //
  305. // need to re-do best match
  306. //
  307. BadMatch = TRUE;
  308. }
  309. if (Exact || (*pDepth == ThisBest)) {
  310. //
  311. // prune - we're either exact, or got a perfect match
  312. //
  313. Prune = TRUE;
  314. goto Final;
  315. }
  316. }
  317. }
  318. if (NoRemaining) {
  319. //
  320. // I have no resources remaining I can use - consider this as good as a match
  321. // but we need to continue up the tree
  322. //
  323. Best = pTryMatch(pKnown->Next,pResList,pDepth); // match the rest, with us using this resource-range
  324. MyBest = TRUE;
  325. BadMatch = FALSE;
  326. goto Final;
  327. }
  328. //
  329. // if we get here we've:
  330. // (1) found a flexable match, but wasn't able to match everyone above us, or
  331. // (2) not found any match
  332. // note that if last best was n with us matching and this best is n+1 without
  333. // then we don't lose the best
  334. // consider if overall we'd do any better if we gave up our resources to someone else
  335. //
  336. if((pBestRes == NULL) || ((Best+MyBest) < *pDepth)) {
  337. //
  338. // if we had a match, only worth checking if we could increase best by more than MyBest
  339. // note that *pDepth is only valid if pBestRes != NULL
  340. //
  341. ThisBest = pTryMatch(pKnown->Next,pResList,pDepth);
  342. if ((ThisBest > (Best+MyBest)) || (pBestRes == NULL)) {
  343. //
  344. // the current best match
  345. //
  346. pKnown->CrossLink = NULL;
  347. pBestRes = NULL;
  348. Best = ThisBest;
  349. MyBest = 0;
  350. BadMatch = FALSE;
  351. } else {
  352. //
  353. // need to re-do best match
  354. //
  355. BadMatch = TRUE;
  356. }
  357. }
  358. Final:
  359. if (BadMatch) {
  360. //
  361. // We had a bad-match since our last good match
  362. //
  363. if (pBestRes) {
  364. pRange = pBestRes->Entry; // the range we determined was our best bet
  365. pBestRes->Entry = NULL; // eliminate this range
  366. Best = pTryMatch(pKnown->Next,pResList,pDepth); // match the rest, with us using this resource-range
  367. pBestRes->Entry = pRange;
  368. pKnown->CrossLink = pRange;
  369. MyBest = 1;
  370. } else {
  371. Best = pTryMatch(pKnown->Next,pResList,pDepth); // match the rest, with us not using this resource range
  372. pKnown->CrossLink = NULL;
  373. MyBest = 0;
  374. }
  375. }
  376. //
  377. // if we found a match, we've saved it in pKnown->CrossLink
  378. // return Best+0 if it's better we don't fit our resource in, Best+1 otherwise
  379. // returns *pDepth = Best+1 if everyone (me up) fit their resources in
  380. //
  381. (*pDepth)++; // increment to include me
  382. return Best+MyBest; // MyBest = 1 if I managed to match my resource (or no resources left), Best = everyone to the right of me
  383. }
  384. ULONG
  385. pMergeResDesDataLists(
  386. IN OUT PRESDES_ENTRY pKnown,
  387. IN OUT PRESDES_ENTRY pTest,
  388. OUT PULONG pMatchCount
  389. )
  390. /*++
  391. Routine Description:
  392. Map entries in pKnown into pTest
  393. as best as possible
  394. Arguments:
  395. pKnown - list of known values
  396. pTest - list of ranges
  397. pMatchCount - set to be number of resources matched
  398. Return Value:
  399. NO_LC_MATCH if no correlation (not a single known matches)
  400. LC_MATCH_SUPERSET if at least one known matches, but some known's don't
  401. LC_MATCH_SUBSET if all known matches, but there are some range-items unmatched
  402. LC_MATCH if all known matches and all range-items match
  403. ORDERED_LC_MATCH if match, and match is in order
  404. pKnown->CrossLink entries point to matching entries in pTest
  405. pTest->CrossLink entries point to matching entries in pKnown
  406. --*/
  407. {
  408. PRDE_LIST pResList = NULL;
  409. PRDE_LIST Node;
  410. PRESDES_ENTRY pKnownEntry;
  411. PRESDES_ENTRY pTestEntry;
  412. ULONG Success = NO_LC_MATCH;
  413. ULONG Depth = 0;
  414. BOOL SomeKnownMatched = FALSE;
  415. BOOL SomeKnownUnMatched = FALSE;
  416. BOOL SomeTestMatched = FALSE;
  417. BOOL SomeTestUnMatched = FALSE;
  418. BOOL Ordered = TRUE;
  419. ULONG MatchCount = 0;
  420. if (pKnown == NULL) {
  421. goto Final;
  422. }
  423. //
  424. // reset
  425. //
  426. for(pKnownEntry = pKnown; pKnownEntry != NULL ;pKnownEntry = pKnownEntry->Next) {
  427. pKnownEntry->CrossLink = NULL;
  428. }
  429. for(pTestEntry = pTest; pTestEntry != NULL ;pTestEntry = pTestEntry->Next) {
  430. pTestEntry->CrossLink = NULL;
  431. }
  432. pResList = pRDEList_Alloc();
  433. if (pResList == NULL) {
  434. goto Final;
  435. }
  436. //
  437. // make all resources available
  438. // this gives us a work list without destroying original list
  439. //
  440. for(pTestEntry = pTest; pTestEntry != NULL ;pTestEntry = pTestEntry->Next) {
  441. Node = pRDEList_Alloc();
  442. if (Node == NULL) {
  443. goto Final;
  444. }
  445. Node->Entry = pTestEntry;
  446. pRDEList_AddTail(pResList,Node);
  447. }
  448. MatchCount = pTryMatch(pKnown,pResList,&Depth);
  449. if (MatchCount ==0) {
  450. //
  451. // no match
  452. //
  453. goto Final;
  454. }
  455. //
  456. // pKnown now has it's Cross-Link's set to determine success of this match
  457. //
  458. // consider NO_LC_MATCH, LC_MATCH_SUPERSET and ORDERED_LC_MATCH cases
  459. //
  460. pKnownEntry = pKnown;
  461. pTestEntry = pTest;
  462. while (pKnownEntry) {
  463. if (pKnownEntry->CrossLink == NULL) {
  464. SomeKnownUnMatched = TRUE;
  465. } else {
  466. SomeKnownMatched = TRUE; // we have at least one matched
  467. pKnownEntry->CrossLink->CrossLink = pKnownEntry; // cross-link test entries
  468. if (pKnownEntry->CrossLink != pTestEntry) {
  469. Ordered = FALSE; // ordered compare lost
  470. } else {
  471. pTestEntry = pTestEntry->Next; // goto next test for ordered
  472. }
  473. }
  474. pKnownEntry = pKnownEntry->Next;
  475. }
  476. if (Ordered && pTestEntry != NULL) {
  477. Ordered = FALSE;
  478. }
  479. if (SomeKnownUnMatched) {
  480. if (SomeKnownMatched) {
  481. Success = LC_MATCH_SUPERSET;
  482. }
  483. goto Final;
  484. }
  485. if (Ordered) {
  486. Success = ORDERED_LC_MATCH;
  487. goto Final;
  488. }
  489. //
  490. // consider between LC_MATCH_SUBSET and LC_MATCH
  491. //
  492. pTestEntry = pTest;
  493. while (pTestEntry) {
  494. if (pTestEntry->CrossLink == NULL) {
  495. //
  496. // the first NULL CrossLink entry makes Known a Subset of Test
  497. Success = LC_MATCH_SUBSET;
  498. goto Final;
  499. }
  500. pTestEntry = pTestEntry->Next;
  501. }
  502. //
  503. // if we get here, there is an exact match
  504. //
  505. Success = LC_MATCH;
  506. Final:
  507. pRDEList_Destroy(pResList);
  508. if (pMatchCount != NULL) {
  509. *pMatchCount = MatchCount;
  510. }
  511. return Success;
  512. }
  513. ULONG
  514. pCompareLogConf(
  515. IN LOG_CONF KnownLogConf,
  516. IN LOG_CONF TestLogConf,
  517. IN HMACHINE hMachine,
  518. OUT PULONG pMatchCount
  519. )
  520. /*++
  521. Routine Description:
  522. This routine compares two log confs and returns info about how well
  523. they match.
  524. This simply uses the pMergeResDesDataLists function to get match status
  525. Arguments:
  526. KnownLogConf = First log conf to compare (fixed values)
  527. TestConfType = Second log conf to compare (range values)
  528. hMachine = Machine to compare on
  529. pMatchCount = number of resources matched
  530. Return Value:
  531. As pMergeResDesDataLists
  532. --*/
  533. {
  534. PRESDES_ENTRY pKnownResList = NULL, pTestResList = NULL;
  535. ULONG Status;
  536. //
  537. // Retrieve the resources for each log conf
  538. //
  539. if (!pGetResDesDataList(KnownLogConf, &pKnownResList, TRUE,hMachine)) {
  540. if (pMatchCount) {
  541. *pMatchCount = 0;
  542. }
  543. return NO_LC_MATCH;
  544. }
  545. if (!pGetResDesDataList(TestLogConf, &pTestResList, TRUE,hMachine)) {
  546. pDeleteResDesDataList(pKnownResList);
  547. if (pMatchCount) {
  548. *pMatchCount = 0;
  549. }
  550. return NO_LC_MATCH;
  551. }
  552. Status = pMergeResDesDataLists(pKnownResList,pTestResList,pMatchCount);
  553. pDeleteResDesDataList(pKnownResList);
  554. pDeleteResDesDataList(pTestResList);
  555. return Status;
  556. }
  557. BOOL
  558. pFindMatchingAllocConfig(
  559. IN LPDMPROP_DATA lpdmpd
  560. )
  561. {
  562. HWND hDlg = lpdmpd->hDlg;
  563. ULONG ulBasicLC = 0;
  564. ULONG ulBasicCount = 0;
  565. BOOL bFoundCorrectLC = FALSE;
  566. LOG_CONF LogConf;
  567. ULONG lastMatchStatus = NO_LC_MATCH, bestMatchStatus = NO_LC_MATCH;
  568. UINT lastMatchCount;
  569. UINT bestMatchCount = 0;
  570. HMACHINE hMachine;
  571. hMachine = pGetMachine(lpdmpd);
  572. lpdmpd->MatchingLC = (LOG_CONF)0;
  573. lpdmpd->MatchingLCType = BASIC_LOG_CONF;
  574. //
  575. // Load the values associated with the allocated config in the list box,
  576. // but associate each with the resource requirements descriptor that it
  577. // originated from. To do this, we have to match the allocated config
  578. // with the basic/filtered config it is based on.
  579. //
  580. // NOTE: if we got here, then we know that an known config of some kind
  581. // exists (passed in as param) and that at least one basic/filtered config
  582. // exists. Further more, we know that the combobox has already been
  583. // filled in with a list of any basic/filtered configs and the lc handle
  584. // associated with them.
  585. //
  586. ulBasicCount = (ULONG)SendDlgItemMessage(hDlg,IDC_DEVRES_LOGCONFIGLIST,CB_GETCOUNT,
  587. (WPARAM)0,(LPARAM)0);
  588. if (ulBasicCount == (ULONG)LB_ERR) {
  589. return FALSE;
  590. }
  591. for (ulBasicLC = 0 ; ulBasicLC < ulBasicCount; ulBasicLC++) {
  592. //
  593. // Retrieve the log conf handle
  594. //
  595. LogConf = (LOG_CONF)SendDlgItemMessage(hDlg, IDC_DEVRES_LOGCONFIGLIST,
  596. CB_GETITEMDATA, ulBasicLC, 0L);
  597. if (LogConf != 0) {
  598. //
  599. // Determine how good a match this requirements list is.
  600. //
  601. lastMatchStatus = pCompareLogConf(lpdmpd->CurrentLC, LogConf,hMachine,&lastMatchCount);
  602. if ((lastMatchStatus > bestMatchStatus)
  603. || ((bestMatchStatus == lastMatchStatus) && lastMatchCount > bestMatchCount)) {
  604. bestMatchCount = lastMatchCount;
  605. bestMatchStatus =lastMatchStatus;
  606. lpdmpd->MatchingLC = LogConf;
  607. }
  608. }
  609. }
  610. if (bestMatchStatus == NO_LC_MATCH || bestMatchStatus == LC_MATCH_SUBSET) {
  611. //
  612. // this doesn't follow any valid config
  613. //
  614. return FALSE;
  615. }
  616. lpdmpd->dwFlags &= ~(DMPROP_FLAG_PARTIAL_MATCH|DMPROP_FLAG_MATCH_OUT_OF_ORDER);
  617. if (bestMatchStatus != ORDERED_LC_MATCH) {
  618. //
  619. // If match status isn't ORDERED_LC_MATCH, then ordering of the resource descriptors
  620. // didn't match up. Set a flag to indicate this, so that later on we'll know to handle
  621. // this specially.
  622. //
  623. lpdmpd->dwFlags |= DMPROP_FLAG_MATCH_OUT_OF_ORDER;
  624. } else if (bestMatchStatus < LC_MATCH) {
  625. //
  626. // match is partial
  627. //
  628. lpdmpd->dwFlags |= DMPROP_FLAG_PARTIAL_MATCH;
  629. }
  630. return TRUE;
  631. } // LoadMatchingAllocConfig
  632. BOOL
  633. pGetMatchingResDes(
  634. IN ULONG64 ulKnownValue,
  635. IN ULONG64 ulKnownLen,
  636. IN ULONG64 ulKnownEnd,
  637. IN RESOURCEID ResType,
  638. IN LOG_CONF MatchingLogConf,
  639. OUT PRES_DES pMatchingResDes,
  640. IN HMACHINE hMachine
  641. )
  642. /*++
  643. Routine Description:
  644. This returns a res des that matches the specified values.
  645. used by pSaveCustomResSettings
  646. Arguments:
  647. ulKnownValue Starting resource value to match against
  648. ulKnownLen Length of resource to match against
  649. ResType Type of resource to match against
  650. MatchnigLogConf Log conf to retreive potential matching res des from
  651. pMatchingResDes Supplies a pointer that on return contains a matching
  652. res des if any.
  653. Return Value:
  654. None.
  655. --*/
  656. {
  657. CONFIGRET Status = CR_SUCCESS;
  658. RESOURCEID Res;
  659. RES_DES ResDes, ResDesTemp;
  660. ULONG64 ulValue = 0, ulLen = 0, ulEnd = 0;
  661. ULONG ulSize, ulFlags = 0, i;
  662. PGENERIC_RESOURCE pGenRes;
  663. BOOL bMatch = FALSE;
  664. LPBYTE pData = NULL;
  665. //
  666. // The MatchingLogConf is a requirements list. Loop through each res des
  667. // in the matching log conf until we find a res des that matches the
  668. // known res des values.
  669. //
  670. Status = CM_Get_Next_Res_Des_Ex(&ResDes, MatchingLogConf, ResType, &Res, 0,hMachine);
  671. while (Status == CR_SUCCESS) {
  672. //
  673. // Get res des data
  674. //
  675. if (CM_Get_Res_Des_Data_Size_Ex(&ulSize, ResDes, CM_RESDES_WIDTH_64,hMachine) != CR_SUCCESS) {
  676. CM_Free_Res_Des_Handle(ResDes);
  677. break;
  678. }
  679. pData = MyMalloc(ulSize);
  680. if (pData == NULL) {
  681. CM_Free_Res_Des_Handle(ResDes);
  682. break;
  683. }
  684. if (CM_Get_Res_Des_Data_Ex(ResDes, pData, ulSize, DEVRES_WIDTH_FLAGS,hMachine) != CR_SUCCESS) {
  685. CM_Free_Res_Des_Handle(ResDes);
  686. MyFree(pData);
  687. break;
  688. }
  689. if(pGetMatchingRange(ulKnownValue,ulKnownLen,pData,ResType,NULL,NULL,NULL)) {
  690. *pMatchingResDes = ResDes;
  691. bMatch = TRUE;
  692. MyFree(pData);
  693. goto MatchFound;
  694. }
  695. //
  696. // Get next res des in log conf
  697. //
  698. ResDesTemp = ResDes;
  699. Status = CM_Get_Next_Res_Des_Ex(&ResDes, ResDesTemp,
  700. ResType, &Res, 0,hMachine);
  701. CM_Free_Res_Des_Handle(ResDesTemp);
  702. MyFree(pData);
  703. }
  704. MatchFound:
  705. return bMatch;
  706. } // GetMatchingResDes
  707. //
  708. // NTRAID#166214-2000/08/19-JamieHun Conflict Supression Hack
  709. // this stuff needs to be fixed proper
  710. //
  711. PTSTR
  712. pGetRegString(
  713. IN HKEY hKey,
  714. IN PCTSTR regval
  715. )
  716. /*++
  717. Routine Description:
  718. Obtain and return a registry string allocated by MyMalloc
  719. return NULL if we couldn't retrieve string
  720. Arguments:
  721. hKey - key to retrieve string from
  722. regval - value to retrieve
  723. Return Value:
  724. copy of registry string, may be free'd with MyFree
  725. --*/
  726. {
  727. DWORD dwSize;
  728. DWORD dwType;
  729. PTSTR pSz;
  730. LONG res;
  731. dwType = 0;
  732. dwSize = 0;
  733. res = RegQueryValueEx(hKey,regval,NULL,&dwType,(PBYTE)NULL,&dwSize);
  734. if (res != ERROR_SUCCESS) {
  735. return NULL;
  736. }
  737. if (dwType != REG_SZ) {
  738. return NULL;
  739. }
  740. pSz = MyMalloc(dwSize);
  741. if (pSz == NULL) {
  742. return NULL;
  743. }
  744. res = RegQueryValueEx(hKey,regval,NULL,&dwType,(PBYTE)pSz,&dwSize);
  745. if (res != ERROR_SUCCESS) {
  746. MyFree(pSz);
  747. return NULL;
  748. }
  749. return pSz;
  750. }
  751. VOID
  752. pFillCETags(
  753. IN PCONFLICT_EXCEPTIONS pExceptions,
  754. IN PCE_TAGS pTags,
  755. PTSTR pSz
  756. )
  757. /*++
  758. Routine Description:
  759. parse a list of tags into CE_TAGS structure
  760. adding the strings into the string table en-route
  761. note that this structure will be flexable and allow ',' or ';' seperator
  762. however when used in Exceptions string, we've already eliminated any ';'
  763. format is:
  764. <tag>,<tag>,<tag> or <tag>;<tag>;<tag>
  765. Arguments:
  766. pExceptions - context information
  767. pTags - tag structure to fill in
  768. Return Value:
  769. none
  770. --*/
  771. {
  772. static CE_TAGS DummyEntry = { -1 }; // if we write a new string, negative size count means this isn't a devnode entry
  773. MYASSERT(pTags->nTags == 0);
  774. while(pSz[0] && pTags->nTags < MAX_CE_TAGS) {
  775. if(pSz[0]==TEXT(',')||pSz[0]==TEXT(';')||pSz[0]<=TEXT(' ')) {
  776. pSz++;
  777. } else {
  778. PTSTR pOldSz = pSz;
  779. PTSTR pLastSpace = NULL;
  780. LONG id;
  781. while (pSz[0] && pSz[0]!=TEXT(';')&& pSz[0]!=TEXT(',')) {
  782. if (pSz[0]<=TEXT(' ')) {
  783. if (pLastSpace==NULL) {
  784. pLastSpace = pSz;
  785. }
  786. } else {
  787. pLastSpace = NULL;
  788. }
  789. pSz++;
  790. }
  791. //
  792. // pSz points to '\0', ';' or ','
  793. // pLastSpace points to any trailing WS
  794. // pOldSz points to start of string
  795. //
  796. if(pLastSpace==NULL) {
  797. pLastSpace = pSz;
  798. }
  799. if (pSz[0]) {
  800. pSz++;
  801. }
  802. pLastSpace[0]=TEXT('\0');
  803. //
  804. // pSz points to next string, pOldSz points to this string
  805. // add string to string table, place in list of tags
  806. //
  807. id = pSetupStringTableAddStringEx(pExceptions->ceTagMap,pOldSz,STRTAB_CASE_INSENSITIVE|STRTAB_BUFFER_WRITEABLE,&DummyEntry,sizeof(DummyEntry));
  808. if (id>=0) {
  809. pTags->Tag[pTags->nTags++] = id;
  810. }
  811. }
  812. }
  813. }
  814. PCE_ENTRY
  815. pScanConflictExceptionEntry(
  816. IN PCONFLICT_EXCEPTIONS pExceptions,
  817. PTSTR pSz
  818. )
  819. /*++
  820. Routine Description:
  821. obtains conflict exception info from string
  822. format is:
  823. (1) <tags> - always ignore tag for any type of conflict
  824. (2) <rt>:<tags> - ignore tag for <rt> resource type
  825. (3) <rt>@x:<tags> - IRQ/DMA - specfic
  826. (4) <rt>@x-y:<tags> - IO/MEM - range
  827. <tags> are a comma-sep list of tags <tag>,<tag>,<tag>
  828. Arguments:
  829. pExceptions - context information
  830. pSz - string to parse
  831. Return Value:
  832. CE_ENTRY structure if this is a valid descriptor
  833. --*/
  834. {
  835. PTSTR brk;
  836. PCE_ENTRY pEntry;
  837. TCHAR rt[5];
  838. int c;
  839. while (pSz[0] && pSz[0]<=TEXT(' ')) {
  840. pSz++;
  841. }
  842. if (!pSz[0]) {
  843. return NULL;
  844. }
  845. pEntry = MyMalloc(sizeof(CE_ENTRY));
  846. if (pEntry == NULL) {
  847. return NULL;
  848. }
  849. ZeroMemory(pEntry,sizeof(CE_ENTRY));
  850. brk = _tcschr(pSz,TEXT(':'));
  851. if(!brk) {
  852. //
  853. // treat as tags only
  854. //
  855. pEntry->resType = ResType_None;
  856. } else {
  857. //
  858. // determine resource type
  859. //
  860. for(c=0;_istalpha(pSz[0]) && c<(sizeof(rt)/sizeof(TCHAR)-1);c++,pSz++) {
  861. rt[c] = (TCHAR)_totupper(pSz[0]);
  862. }
  863. rt[c] = 0;
  864. while (pSz[0] && pSz[0]<=TEXT(' ')) {
  865. pSz++;
  866. }
  867. if (pSz[0]!=TEXT(':') && pSz[0]!=TEXT('@')) {
  868. MyFree(pEntry);
  869. return NULL;
  870. } else if (lstrcmp(rt,CE_RES_IO)==0) {
  871. pEntry->resType = ResType_IO;
  872. } else if (lstrcmp(rt,CE_RES_MEM)==0) {
  873. pEntry->resType = ResType_Mem;
  874. } else if (lstrcmp(rt,CE_RES_IRQ)==0) {
  875. pEntry->resType = ResType_IRQ;
  876. } else if (lstrcmp(rt,CE_RES_DMA)==0) {
  877. pEntry->resType = ResType_DMA;
  878. } else {
  879. MyFree(pEntry);
  880. return NULL;
  881. }
  882. if (pSz[0]!=TEXT('@')) {
  883. //
  884. // no range follows
  885. //
  886. pEntry->resStart = (ULONG64)0;
  887. pEntry->resEnd = (ULONG64)(-1);
  888. } else {
  889. //
  890. // @x[-y]:
  891. //
  892. ULONG x;
  893. ULONG y;
  894. PTSTR i;
  895. pSz++; // past @
  896. while (pSz[0] && pSz[0]<=TEXT(' ')) {
  897. pSz++;
  898. }
  899. i = pSz;
  900. x = _tcstoul(pSz,&i,0);
  901. if (i==pSz) {
  902. MyFree(pEntry);
  903. return NULL;
  904. }
  905. pSz = i;
  906. while (pSz[0] && pSz[0]<=TEXT(' ')) {
  907. pSz++;
  908. }
  909. if (pSz[0]==TEXT('-')) {
  910. //
  911. // -y
  912. //
  913. pSz++;
  914. while (pSz[0] && pSz[0]<=TEXT(' ')) {
  915. pSz++;
  916. }
  917. i = pSz;
  918. y = _tcstoul(pSz,&i,0);
  919. if (i==pSz || y<x) {
  920. MyFree(pEntry);
  921. return NULL;
  922. }
  923. pSz = i;
  924. while (pSz[0] && pSz[0]<=TEXT(' ')) {
  925. pSz++;
  926. }
  927. } else {
  928. y = x;
  929. }
  930. pEntry->resStart = x;
  931. pEntry->resEnd = y;
  932. }
  933. if (pSz[0] != TEXT(':')) {
  934. MyFree(pEntry);
  935. return NULL;
  936. }
  937. pSz ++; // skip past colon
  938. }
  939. //
  940. // at this point, expect a list of tags
  941. // each tag terminated by a comma
  942. //
  943. pFillCETags(pExceptions,&pEntry->tags,pSz);
  944. if (!pEntry->tags.nTags) {
  945. MyFree(pEntry);
  946. return NULL;
  947. }
  948. return pEntry;
  949. }
  950. PCONFLICT_EXCEPTIONS pLoadConflictExceptions(
  951. IN LPDMPROP_DATA lpdmpd
  952. )
  953. /*++
  954. Routine Description:
  955. Load the string "ResourcePickerExceptions" if any
  956. create a context structure for eliminating false conflicts
  957. this is one huge hack.
  958. Arguments:
  959. lpdmpd - Context data
  960. Return Value:
  961. CONFLICT_EXCEPTIONS structure, if "active" contains a string table and a list of resource exceptions
  962. --*/
  963. {
  964. PCONFLICT_EXCEPTIONS pExceptions;
  965. PCE_ENTRY pEntry;
  966. BOOL bStatus;
  967. HKEY hDevRegKey;
  968. PTSTR pSz;
  969. PTSTR pScanSz;
  970. PTSTR pOldSz;
  971. PCE_TAGS pTags;
  972. //
  973. // we always create the structure, so we will avoid looking for registry info every time
  974. //
  975. pExceptions = MyMalloc(sizeof(CONFLICT_EXCEPTIONS));
  976. if (pExceptions == NULL) {
  977. return NULL;
  978. }
  979. ZeroMemory(pExceptions,sizeof(CONFLICT_EXCEPTIONS));
  980. hDevRegKey = SetupDiOpenDevRegKey(lpdmpd->hDevInfo,lpdmpd->lpdi,DICS_FLAG_GLOBAL,0,DIREG_DRV,KEY_READ);
  981. if (hDevRegKey == INVALID_HANDLE_VALUE) {
  982. //
  983. // can't find key, no conflict elimination
  984. //
  985. return pExceptions;
  986. }
  987. pSz = pGetRegString(hDevRegKey,REGSTR_VAL_RESOURCE_PICKER_EXCEPTIONS);
  988. RegCloseKey(hDevRegKey);
  989. if(pSz == NULL) {
  990. //
  991. // can't find key, no conflict elimination
  992. //
  993. return pExceptions;
  994. }
  995. //
  996. // now parse the string creating our context to eliminate false conflicts
  997. //
  998. pExceptions->ceTagMap = pSetupStringTableInitializeEx(sizeof(CE_TAGS),0);
  999. if (pExceptions->ceTagMap == NULL) {
  1000. MyFree(pSz);
  1001. return pExceptions;
  1002. }
  1003. pScanSz = pSz;
  1004. while (pScanSz[0]) {
  1005. if (pScanSz[0] == TEXT(';')) {
  1006. pScanSz ++;
  1007. } else {
  1008. pOldSz = pScanSz;
  1009. while (pScanSz[0] && pScanSz[0] != TEXT(';')) {
  1010. pScanSz++;
  1011. }
  1012. if (pScanSz[0]) {
  1013. pScanSz[0] = 0;
  1014. pScanSz++;
  1015. }
  1016. pEntry = pScanConflictExceptionEntry(pExceptions,pOldSz);
  1017. if (pEntry) {
  1018. pEntry->Next = pExceptions->exceptions;
  1019. pExceptions->exceptions = pEntry;
  1020. }
  1021. }
  1022. }
  1023. MyFree(pSz);
  1024. return pExceptions;
  1025. }
  1026. VOID pFreeConflictExceptions(
  1027. IN PCONFLICT_EXCEPTIONS pExceptions
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. Releases memory used by PCONFLICT_EXCEPTIONS
  1032. Arguments:
  1033. pExceptions structure to release
  1034. Return Value:
  1035. None.
  1036. --*/
  1037. {
  1038. //
  1039. // free the list
  1040. //
  1041. while (pExceptions->exceptions) {
  1042. PCE_ENTRY pEntry = pExceptions->exceptions;
  1043. pExceptions->exceptions = pEntry->Next;
  1044. MyFree(pEntry);
  1045. }
  1046. //
  1047. // free the string table
  1048. //
  1049. if (pExceptions->ceTagMap) {
  1050. pSetupStringTableDestroy(pExceptions->ceTagMap);
  1051. }
  1052. MyFree(pExceptions);
  1053. }
  1054. BOOL pIsConflictException(
  1055. IN LPDMPROP_DATA lpdmpd,
  1056. IN PCONFLICT_EXCEPTIONS pExceptions,
  1057. IN DEVINST devConflict,
  1058. IN PCTSTR resDesc,
  1059. IN RESOURCEID resType,
  1060. IN ULONG64 resValue,
  1061. IN ULONG64 resLength
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Load the string "ResourcePickerExceptions" if any
  1066. create a context structure for eliminating false conflicts
  1067. this is one huge hack.
  1068. Arguments:
  1069. lpdmpd - Context data
  1070. pExceptions - Cache of information
  1071. devConflict - DEVINST that's shown to be conflicting with us, -1 if "unavailable" (tag = *)
  1072. resType - type of resource that we tested
  1073. resValue - value of resource that we tested
  1074. resLength - length of resource that we tested
  1075. Return Value:
  1076. TRUE if this is an exception
  1077. --*/
  1078. {
  1079. HMACHINE hMachine;
  1080. TCHAR DevNodeName[MAX_DEVNODE_ID_LEN];
  1081. CE_TAGS tags;
  1082. PCE_ENTRY pEntry;
  1083. LONG tagent;
  1084. LONG n,m;
  1085. ULONG64 resEnd = resValue+(resLength-1);
  1086. PTSTR pSz;
  1087. HKEY hKey;
  1088. //
  1089. // if we're not doing any exceptions, get out ASAP
  1090. //
  1091. if (pExceptions->exceptions == NULL) {
  1092. return FALSE;
  1093. }
  1094. hMachine = pGetMachine(lpdmpd);
  1095. //
  1096. // handle "reserved" case first
  1097. //
  1098. if (devConflict != -1) {
  1099. //
  1100. // obtain device instance string
  1101. //
  1102. if(CM_Get_Device_ID_Ex(devConflict,DevNodeName,MAX_DEVNODE_ID_LEN,0,hMachine)!=CR_SUCCESS) {
  1103. devConflict = -1;
  1104. }
  1105. }
  1106. if (devConflict == -1) {
  1107. if (resDesc && resDesc[0]) {
  1108. lstrcpy(DevNodeName,resDesc);
  1109. } else {
  1110. lstrcpy(DevNodeName,CE_TAG_RESERVED);
  1111. }
  1112. } else {
  1113. }
  1114. //
  1115. // is this a brand-new devnodename ?
  1116. //
  1117. tags.nTags = 0;
  1118. tagent = pSetupStringTableLookUpStringEx(pExceptions->ceTagMap,DevNodeName,STRTAB_CASE_INSENSITIVE|STRTAB_BUFFER_WRITEABLE,&tags,sizeof(tags));
  1119. if(tagent<0 || tags.nTags<0) {
  1120. //
  1121. // this particular devnode hasn't been processed before, ouch time
  1122. //
  1123. ZeroMemory(&tags,sizeof(tags)); // default reserved case
  1124. if (devConflict != -1) {
  1125. //
  1126. // we need to get regkey for this devnode
  1127. // I could do this via setupapi, or cfgmgr
  1128. // for efficiency, I'm going latter route
  1129. //
  1130. if(CM_Open_DevNode_Key_Ex(devConflict,
  1131. KEY_READ,
  1132. 0,
  1133. RegDisposition_OpenExisting,
  1134. &hKey,
  1135. CM_REGISTRY_SOFTWARE,
  1136. hMachine) == CR_SUCCESS) {
  1137. pSz = pGetRegString(hKey,REGSTR_VAL_RESOURCE_PICKER_TAGS);
  1138. RegCloseKey(hKey);
  1139. if (pSz) {
  1140. //
  1141. // now fill in tags
  1142. //
  1143. pFillCETags(pExceptions,&tags,pSz);
  1144. MyFree(pSz);
  1145. }
  1146. }
  1147. }
  1148. //
  1149. // now write this back into the string table
  1150. // this time, non-negative nTags indicates we've processed this once
  1151. // we will re-write the extra-data
  1152. //
  1153. tagent = pSetupStringTableAddStringEx(pExceptions->ceTagMap,DevNodeName,STRTAB_CASE_INSENSITIVE|STRTAB_BUFFER_WRITEABLE|STRTAB_NEW_EXTRADATA,&tags,sizeof(tags));
  1154. }
  1155. if (tagent<0) {
  1156. //
  1157. // if this happens, we have other problems (out of memory)
  1158. //
  1159. return FALSE;
  1160. }
  1161. //
  1162. // go through our list of exceptions
  1163. // an exception that mentions tagent, or any of tags associated with tagent (in tags) is rejected
  1164. // the policy in this routine is make this an exception if we can
  1165. //
  1166. for(pEntry=pExceptions->exceptions;pEntry;pEntry=pEntry->Next) {
  1167. if (pEntry->resType != ResType_None) {
  1168. //
  1169. // we need to validate the resource
  1170. //
  1171. if (pEntry->resType != resType ||
  1172. pEntry->resStart > resValue ||
  1173. pEntry->resEnd < resEnd) {
  1174. continue;
  1175. }
  1176. }
  1177. for (n=0;n<pEntry->tags.nTags;n++) {
  1178. if (pEntry->tags.Tag[n] == tagent) {
  1179. MYTRACE((DPFLTR_ERROR_LEVEL, TEXT("Setup: Eliminated false conflict with %s type=%u, start=0x%08x, len=0x%08x\n"),DevNodeName,resType,resValue,resLength));
  1180. return TRUE; // hit (devnode itself, where devnode may also be "*")
  1181. }
  1182. for (m=0;m<tags.nTags;m++) {
  1183. if (pEntry->tags.Tag[n] == tags.Tag[m]) {
  1184. MYTRACE((DPFLTR_ERROR_LEVEL, TEXT("Setup: Eliminated false conflict with %s (via tag %s) type=%u, start=0x%08x, len=0x%08x\n"),DevNodeName,pStringTableStringFromId(pExceptions->ceTagMap,tags.Tag[m]),resType,resValue,resLength));
  1185. return TRUE; // hit on one of associated tags
  1186. }
  1187. }
  1188. }
  1189. }
  1190. return FALSE;
  1191. }