Leaked source code of windows server 2003
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.

1345 lines
41 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include <ncxbase.h>
  4. #include "hwres.h"
  5. #include "kkcwinf.h"
  6. #include "ncreg.h"
  7. extern const WCHAR c_szAfIoAddr[];
  8. extern const WCHAR c_szAfIrq[];
  9. extern const WCHAR c_szAfDma[];
  10. extern const WCHAR c_szAfMem[];
  11. extern const WCHAR c_szBusType[];
  12. //+---------------------------------------------------------------------------
  13. //
  14. // Member: CHwRes::CHwRes
  15. //
  16. // Purpose: Class constructor. (Variable initialization)
  17. //
  18. // Author: t-nabilr 07 Apr 1997
  19. //
  20. // Notes: Doesn't do much. Just some member variable initialization.
  21. // Bulk of the init work is done in HrInit().
  22. //
  23. CHwRes::CHwRes()
  24. : m_DevNode(NULL),
  25. m_pnccItem(NULL),
  26. m_fInitialized(FALSE),
  27. m_fHrInitCalled(FALSE),
  28. m_fDirty(FALSE)
  29. {
  30. m_vAfDma.InitNotPresent(VALUETYPE_DWORD);
  31. m_vAfIrq.InitNotPresent(VALUETYPE_DWORD);
  32. m_vAfMem.InitNotPresent(VALUETYPE_DWORD);
  33. m_vAfMemEnd.InitNotPresent(VALUETYPE_DWORD);
  34. m_vAfIo.InitNotPresent(VALUETYPE_DWORD);
  35. m_vAfIoEnd.InitNotPresent(VALUETYPE_DWORD);
  36. }
  37. //+---------------------------------------------------------------------------
  38. //
  39. // Member: CHwRes::HrInit
  40. //
  41. // Purpose: Initialize class
  42. //
  43. // Arguments:
  44. // hInst [in] Handle to our instance.
  45. // pnccItem [in] Our INetCfgComponent.
  46. //
  47. // Returns: S_OK - init successfull;
  48. // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) - no config
  49. // info for device; E_FAIL - other failure (device not found,etc)
  50. //
  51. // Author: t-nabilr 07 Apr 1997
  52. //
  53. // Notes: - should initialize all non-ui stuff
  54. // - initialize configuration and resource lists.
  55. //
  56. HRESULT CHwRes::HrInit(const DEVNODE& devnode)
  57. {
  58. HRESULT hr = E_FAIL;
  59. m_fHrInitCalled = TRUE;
  60. // use the config manager to get devnode
  61. // Since the devnode might have a problem, e.g. resources not set
  62. // correctly, we need to retrieve possible phantoms
  63. //
  64. CONFIGRET crRet = ERROR_SUCCESS;
  65. HKEY hkey;
  66. // We only do work on Isa adapters so we need to get the bustype
  67. // value from the driver (software) key
  68. crRet = CM_Open_DevNode_Key(devnode, KEY_READ, 0,
  69. RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE);
  70. if (CR_SUCCESS == crRet)
  71. {
  72. // Get BusType
  73. ULONG ulBusType;
  74. hr = HrRegQueryStringAsUlong(hkey, c_szBusType, c_nBase10,
  75. &ulBusType);
  76. RegCloseKey(hkey);
  77. // If Isa, than we can continue
  78. if (SUCCEEDED(hr) && (Isa == ulBusType))
  79. {
  80. m_DevNode = devnode;
  81. // read configuration current config info
  82. hr = HrInitConfigList();
  83. }
  84. else
  85. {
  86. hr = S_FALSE;
  87. }
  88. }
  89. if (S_OK == hr)
  90. {
  91. m_fInitialized = TRUE;
  92. }
  93. TraceError("CHwRes::HrInit",
  94. (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr ||
  95. S_FALSE == hr) ? S_OK : hr);
  96. return hr;
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Member: CHwRes::GetNextElement
  101. //
  102. // Purpose: Gets the next (or prev) element in a resource list
  103. //
  104. // Arguments:
  105. // pResource [in] resource list to traverse.
  106. // ppeList [out] the "next" element is returned.
  107. // fNext [in] TRUE - moving fwd in list; FALSE - move bkwrds.
  108. //
  109. // Author: t-nabilr 07 Apr 1997
  110. //
  111. // Notes:
  112. //
  113. VOID CHwRes::GetNextElement(PRESOURCE pResource, PVOID *ppeList, BOOL fNext)
  114. {
  115. UINT size = 0;
  116. AssertSz(m_fInitialized,
  117. "GetNextElement called before CHwRes is HrInit'ed");
  118. Assert(pResource != NULL);
  119. // get the vector size (dependant on resource type)
  120. switch (pResource->ResourceType) {
  121. case ResType_IRQ:
  122. size = pResource->pIRQList->size();
  123. break;
  124. case ResType_DMA:
  125. size = pResource->pDMAList->size();
  126. break;
  127. case ResType_IO:
  128. size = pResource->pIOList->size();
  129. break;
  130. case ResType_Mem:
  131. size = pResource->pMEMList->size();
  132. break;
  133. default:
  134. Assert(FALSE);
  135. break;
  136. }
  137. // increment/decrement current position within vector
  138. if (fNext)
  139. {
  140. pResource->pos++;
  141. }
  142. else
  143. {
  144. pResource->pos--;
  145. }
  146. // Check for wrapping
  147. if ((int)(pResource->pos) < 0)
  148. {
  149. Assert(pResource->pos == -1);
  150. Assert(!fNext); // we're going backwards
  151. pResource->pos = size-1;
  152. }
  153. else if (pResource->pos >= size)
  154. {
  155. Assert(pResource->pos == size);
  156. Assert(fNext);
  157. pResource->pos = 0;
  158. }
  159. // return the current vector element (dependant on res type)
  160. // REVIEW: do we ever use the element that's gathered below?
  161. switch (pResource->ResourceType) {
  162. case ResType_IRQ:
  163. *ppeList = (*pResource->pIRQList)[pResource->pos];
  164. break;
  165. case ResType_DMA:
  166. *ppeList = (*pResource->pDMAList)[pResource->pos];
  167. break;
  168. case ResType_IO:
  169. *ppeList = (*pResource->pIOList)[pResource->pos];
  170. break;
  171. case ResType_Mem:
  172. *ppeList = (*pResource->pMEMList)[pResource->pos];
  173. break;
  174. default:
  175. Assert(FALSE);
  176. break;
  177. }
  178. }
  179. //+---------------------------------------------------------------------------
  180. //
  181. // Member: CHwRes::HrInitConfigList
  182. //
  183. // Purpose: Initialize m_ConfigList (the internal vector of
  184. // configurations.)
  185. //
  186. // Returns: S_OK - init successful;
  187. // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if no device configs
  188. // found; E_FAIL otherwise (invalid device, etc.)
  189. //
  190. // Author: t-nabilr 07 Apr 1997
  191. //
  192. // Notes: "Lists" are actually implemented as STL vectors.
  193. //
  194. HRESULT CHwRes::HrInitConfigList() {
  195. HRESULT hr = S_OK;
  196. PCONFIGURATION pConfiguration;
  197. CONFIGRET ConfigRet;
  198. LOG_CONF lcCurrent, lcNext;
  199. UINT iBasicConfig;
  200. BOOL fFoundConfig = FALSE;
  201. Assert(NULL != m_DevNode);
  202. // erase all elements
  203. m_ConfigList.erase(m_ConfigList.begin(), m_ConfigList.end());
  204. // Boot Configuration
  205. if (CM_Get_First_Log_Conf(&lcCurrent, m_DevNode, BOOT_LOG_CONF)
  206. == CR_SUCCESS)
  207. {
  208. TraceTag(ttidNetComm, "Boot config already exists");
  209. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  210. }
  211. if (SUCCEEDED(hr))
  212. {
  213. // Basic Configurations (may be more than one)
  214. iBasicConfig = 0;
  215. ConfigRet = CM_Get_First_Log_Conf(&lcCurrent, m_DevNode, BASIC_LOG_CONF);
  216. #ifdef ENABLETRACE
  217. if (CR_SUCCESS != ConfigRet)
  218. {
  219. TraceTag(ttidNetComm, "CM_Get_First_Log_conf returned %lX", ConfigRet);
  220. }
  221. #endif // ENABLETRACE
  222. while (CR_SUCCESS == ConfigRet)
  223. {
  224. pConfiguration = new CONFIGURATION;
  225. if (pConfiguration == NULL)
  226. {
  227. TraceError("pConfiguration == NULL", E_FAIL);
  228. goto error;
  229. }
  230. pConfiguration->LogConf = lcCurrent;
  231. pConfiguration->fBoot = FALSE;
  232. pConfiguration->fAlloc = FALSE;
  233. if (!FInitResourceList(pConfiguration))
  234. {
  235. hr = E_FAIL;
  236. TraceError("CHwRes::FInitResourceList",hr);
  237. goto error;
  238. }
  239. m_ConfigList.push_back(pConfiguration);
  240. // Move on to the next basic config
  241. iBasicConfig++;
  242. ConfigRet = CM_Get_Next_Log_Conf(&lcNext, lcCurrent, 0);
  243. lcCurrent = lcNext;
  244. fFoundConfig = TRUE;
  245. }
  246. if (!fFoundConfig)
  247. {
  248. TraceTag(ttidNetComm, "No basic configs");
  249. // if no config entries found, return ERROR_FILE_NOT_FOUND.
  250. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  251. }
  252. }
  253. error:
  254. // ERROR_FILE_NOT_FOUND is an okay error message.
  255. TraceError("CHwRes::HrInitConfigList",
  256. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr ||
  257. HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr ) ? S_OK : hr);
  258. return hr;
  259. }
  260. //+---------------------------------------------------------------------------
  261. //
  262. // Member: CHwRes::FInitResourceList
  263. //
  264. // Purpose: Initializes the resource list for a given logical config.
  265. //
  266. // Arguments:
  267. // pConfiguration [in] configuration who's resource list is to
  268. // be initialized.
  269. //
  270. // Returns: TRUE if init sucessful; FALSE otherwise.
  271. //
  272. // Author: t-nabilr 07 Apr 1997
  273. //
  274. // Notes: Requires pConfiguration->LogConf to be initialized.
  275. //
  276. BOOL CHwRes::FInitResourceList(PCONFIGURATION pConfiguration)
  277. {
  278. RES_DES rdCurrent;
  279. RES_DES rdNext;
  280. RESOURCEID ResType;
  281. UINT iResource;
  282. #define RESOURCE_BUFFER_SIZE 4096
  283. BYTE Buffer[RESOURCE_BUFFER_SIZE];
  284. ULONG ulDataSize;
  285. RESOURCE * pRes;
  286. CONFIGRET cr;
  287. Assert(pConfiguration->LogConf);
  288. rdCurrent = (RES_DES) pConfiguration->LogConf;
  289. iResource = 0;
  290. while ((cr = CM_Get_Next_Res_Des(&rdNext, rdCurrent,
  291. ResType_All, &ResType, 0)) == CR_SUCCESS)
  292. {
  293. rdCurrent = rdNext;
  294. // Only process this resource if the ignore bit is not set
  295. if (ResType_Ignored_Bit != ResType)
  296. {
  297. pRes = &(pConfiguration->aResource[iResource]);
  298. pRes->ResDes = rdCurrent;
  299. pRes->ResourceType = ResType;
  300. cr = CM_Get_Res_Des_Data_Size(&ulDataSize, rdCurrent, 0);
  301. if (CR_SUCCESS != cr)
  302. {
  303. TraceTag (ttidDefault, "CM_Get_Res_Des_Data_Size returned 0x%08x", cr);
  304. goto error;
  305. }
  306. AssertSz (ulDataSize, "CM_Get_Res_Des_Data_Size returned 0!");
  307. AssertSz (ulDataSize <= sizeof(Buffer), "CHwRes::FInitResourceList: buffer is too small.");;
  308. cr = CM_Get_Res_Des_Data(rdCurrent, Buffer, sizeof(Buffer), 0);
  309. if (CR_SUCCESS != cr)
  310. {
  311. TraceTag (ttidDefault, "CM_Get_Res_Des_Data returned 0x%08x", cr);
  312. goto error;
  313. }
  314. // Depending on the ResType, we have to initialize our resource list.
  315. switch (ResType)
  316. {
  317. case ResType_Mem:
  318. InitMEMList(&(pRes->pMEMList), (PMEM_RESOURCE)Buffer);
  319. break;
  320. case ResType_IO:
  321. InitIOList(&(pRes->pIOList), (PIO_RESOURCE)Buffer);
  322. break;
  323. case ResType_DMA:
  324. InitDMAList(&(pRes->pDMAList), (PDMA_RESOURCE)Buffer);
  325. break;
  326. case ResType_IRQ:
  327. InitIRQList(&(pRes->pIRQList), (PIRQ_RESOURCE)Buffer);
  328. break;
  329. default:
  330. AssertSz (ResType_None != ResType, "ResType_None hit caught in CHwRes::FInitResourceList.");
  331. break;
  332. }
  333. // set the list position to the first element;
  334. // applied_pos will get copied to pos when dialog box is created.
  335. pRes->applied_pos = 0;
  336. iResource++;
  337. pConfiguration->cResource = iResource;
  338. if (iResource >= c_nMaxResCtls)
  339. {
  340. break; // we're done.
  341. }
  342. }
  343. } //while
  344. if ((CR_SUCCESS != cr) && (CR_NO_MORE_RES_DES != cr))
  345. {
  346. TraceTag (ttidDefault, "CM_Get_Next_Res_Des returned 0x%08x", cr);
  347. goto error;
  348. }
  349. return TRUE;
  350. error:
  351. return FALSE;
  352. }
  353. //+---------------------------------------------------------------------------
  354. //
  355. // Member: CHwRes::InitIRQList
  356. //
  357. // Purpose: Initialize an IRQ resource vector given a config manager
  358. // resource structure.
  359. //
  360. // Arguments:
  361. // ppIRQList [out] returns IRQ_LIST that will be created.
  362. // pIRQResource [in] IRQ_RESOURCE structure from config manager.
  363. //
  364. // Author: t-nabilr 07 Apr 1997
  365. //
  366. // Notes:
  367. //
  368. VOID CHwRes::InitIRQList(PIRQ_LIST* ppIRQList, PIRQ_RESOURCE pIRQResource) {
  369. PIRQ_DES pIRQHeader;
  370. PIRQ_RANGE pIRQData;
  371. PIRQ_LIST_ELEMENT pIRQListElement;
  372. pIRQHeader = &(pIRQResource->IRQ_Header);
  373. pIRQData = &(pIRQResource->IRQ_Data[0]);
  374. // Create a new list.
  375. *ppIRQList = new IRQ_LIST;
  376. if (*ppIRQList == NULL)
  377. {
  378. return;
  379. }
  380. ULONG iData;
  381. ULONG iIRQ;
  382. for (iData = 0; iData < pIRQHeader->IRQD_Count; iData++)
  383. {
  384. for (iIRQ = pIRQData[iData].IRQR_Min;
  385. iIRQ <= pIRQData[iData].IRQR_Max;
  386. iIRQ++)
  387. {
  388. // For each IRQ that falls within the given range,
  389. // create new IRQ List Element, populate its fields and insert
  390. // it into the m_IRQList.
  391. pIRQListElement = new IRQ_LIST_ELEMENT;
  392. if (pIRQListElement == NULL)
  393. {
  394. continue;
  395. }
  396. pIRQListElement->dwIRQ = iIRQ;
  397. pIRQListElement->fConflict = FALSE;
  398. pIRQListElement->fAllocated = FALSE;
  399. (*ppIRQList)->push_back(pIRQListElement);
  400. }
  401. }
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // Member: CHwRes::InitDMAList
  406. //
  407. // Purpose: Initialize a DMA resource vector given a config manager
  408. // resource structure.
  409. //
  410. // Arguments:
  411. // ppDMAList [out] returns DMA_LIST that will be created.
  412. // pDMAResource [in] DMA_RESOURCE structure from config manager.
  413. //
  414. // Author: t-nabilr 07 Apr 1997
  415. //
  416. // Notes:
  417. //
  418. VOID CHwRes::InitDMAList(PDMA_LIST* ppDMAList, PDMA_RESOURCE pDMAResource) {
  419. PDMA_DES pDMAHeader;
  420. PDMA_RANGE pDMAData;
  421. PDMA_LIST_ELEMENT peDMAList;
  422. pDMAHeader = &(pDMAResource->DMA_Header);
  423. pDMAData = &(pDMAResource->DMA_Data[0]);
  424. // Create a new list.
  425. *ppDMAList = new DMA_LIST;
  426. if (*ppDMAList == NULL)
  427. {
  428. return;
  429. }
  430. ULONG iData; // index of DMA_Range structure we're looking at.
  431. ULONG iDMA; // current DMA number we're adding to the list.
  432. // Go through all the DMA_Range structures, and all DMAs in the
  433. // specified range to the list.
  434. for (iData = 0; iData < pDMAHeader->DD_Count; iData++)
  435. {
  436. for (iDMA = pDMAData[iData].DR_Min;
  437. iDMA <= pDMAData[iData].DR_Max;
  438. iDMA++)
  439. {
  440. // For each DMA that falls within the given range,
  441. // create new DMA List Element, populate its fields and insert
  442. // it into the DMAList.
  443. peDMAList = new DMA_LIST_ELEMENT;
  444. if (peDMAList == NULL)
  445. {
  446. continue;
  447. }
  448. peDMAList->dwDMA = iDMA;
  449. peDMAList->fConflict = FALSE;
  450. peDMAList->fAllocated = FALSE;
  451. (*ppDMAList)->push_back(peDMAList);
  452. }
  453. }
  454. }
  455. //+---------------------------------------------------------------------------
  456. //
  457. // Member: CHwRes::InitMEMList
  458. //
  459. // Purpose: Initialize a MEM resource vector given a config manager
  460. // resource structure.
  461. //
  462. // Arguments:
  463. // ppMEMList [out] returns MEM_LIST that will be created.
  464. // pMEMResource [in] MEM_RESOURCE structure from config manager.
  465. //
  466. // Author: t-nabilr 07 Apr 1997
  467. //
  468. // Notes:
  469. //
  470. VOID CHwRes::InitMEMList(PMEM_LIST* ppMEMList, PMEM_RESOURCE pMEMResource)
  471. {
  472. PMEM_DES pMEMHeader;
  473. PMEM_RANGE pMEMData;
  474. PMEM_LIST_ELEMENT peMEMList;
  475. // For easy access
  476. pMEMHeader = &(pMEMResource->MEM_Header);
  477. pMEMData = pMEMResource->MEM_Data;
  478. // Create a new list.
  479. *ppMEMList = new MEM_LIST;
  480. if (*ppMEMList == NULL)
  481. {
  482. return;
  483. }
  484. ULONG iData; // index of MEM_Range structure we're looking at.
  485. DWORDLONG MEMBase; // current MEM Base we're adding to the list.
  486. ULONG cMEMBytes; // number of bytes required.
  487. DWORDLONG MEMAlign;
  488. // Go through all the MEM_Range structures, and all MEMs in the
  489. // specified range to the list.
  490. for (iData = 0; iData < pMEMHeader->MD_Count; iData++)
  491. {
  492. MEMAlign = pMEMData[iData].MR_Align;
  493. cMEMBytes = pMEMData[iData].MR_nBytes;
  494. // do sanity checks
  495. if (0 == MEMAlign)
  496. {
  497. TraceTag(ttidNetComm, "CHwRes::InitMEMList() - Bogus alignment "
  498. "field while processing info from Config Manager.");
  499. break;
  500. }
  501. if (0 == cMEMBytes)
  502. {
  503. TraceTag(ttidNetComm, "CHwRes::InitMEMList() - Bogus membytes "
  504. "field while processing info from Config Manager.");
  505. break;
  506. }
  507. for (MEMBase = pMEMData[iData].MR_Min;
  508. MEMBase+cMEMBytes-1 <= pMEMData[iData].MR_Max;
  509. MEMBase += ~MEMAlign + 1)
  510. {
  511. // For each MEM that falls within the given range,
  512. // create new MEM List Element, populate its fields and insert
  513. // it into the MEMList.
  514. peMEMList = new MEM_LIST_ELEMENT;
  515. if (peMEMList == NULL)
  516. {
  517. continue;
  518. }
  519. //
  520. // BUGBUG (forrestf) dwMEM_Base and dwMEM_End are 32-bit fields.
  521. // It appears that they contain physical memory addresses, which
  522. // should be 64-bit (even on 32-bit machines), no?
  523. //
  524. peMEMList->dwMEM_Base = (DWORD)MEMBase;
  525. peMEMList->dwMEM_End = (DWORD)(MEMBase + cMEMBytes - 1);
  526. peMEMList->fConflict = FALSE;
  527. peMEMList->fAllocated = FALSE;
  528. (*ppMEMList)->push_back(peMEMList);
  529. // Check for wrapping.
  530. if (MEMBase >= MEMBase + ~MEMAlign + 1)
  531. {
  532. TraceTag(ttidError, "Memory base is greater than Memory "
  533. "end!!!");
  534. break;
  535. }
  536. }
  537. }
  538. }
  539. //+---------------------------------------------------------------------------
  540. //
  541. // Member: CHwRes::InitIOList
  542. //
  543. // Purpose: Initialize an IO resource vector given a config manager
  544. // resource structure.
  545. //
  546. // Arguments:
  547. // ppIOList [out] returns IO_LIST that will be created.
  548. // pIOResource [in] IO_RESOURCE structure from config manager.
  549. //
  550. // Author: t-nabilr 07 Apr 1997
  551. //
  552. // Notes:
  553. //
  554. VOID CHwRes::InitIOList(PIO_LIST* ppIOList, PIO_RESOURCE pIOResource)
  555. {
  556. PIO_DES pIOHeader;
  557. PIO_RANGE pIOData;
  558. PIO_LIST_ELEMENT peIOList;
  559. // For easy access
  560. pIOHeader = &(pIOResource->IO_Header);
  561. pIOData = pIOResource->IO_Data;
  562. // Create a new list.
  563. *ppIOList = new IO_LIST;
  564. if (*ppIOList == NULL)
  565. {
  566. return;
  567. }
  568. ULONG iData; // index of IO_Range structure we're looking at.
  569. DWORDLONG IOBase; // current IO Base we're adding to the list.
  570. ULONG cIOBytes; // number of bytes required.
  571. DWORDLONG IOAlign;
  572. // Go through all the IO_Range structures, and all IOs in the
  573. // specified range to the list.
  574. for (iData = 0; iData < pIOHeader->IOD_Count; iData++)
  575. {
  576. IOAlign = pIOData[iData].IOR_Align;
  577. cIOBytes = pIOData[iData].IOR_nPorts;
  578. // Perform sanity checks.
  579. if (0 == IOAlign)
  580. {
  581. TraceTag(ttidError, "CHwRes::InitIOList - Bogus alignment field "
  582. "while processing data from Config Manager.");
  583. break;
  584. }
  585. if (0 == cIOBytes)
  586. {
  587. TraceTag(ttidError, "CHwRes::InitIOList - Bogus IObytes field "
  588. "while processing data from Config Manager.");
  589. break;
  590. }
  591. for (IOBase = pIOData[iData].IOR_Min;
  592. IOBase+cIOBytes-1 <= pIOData[iData].IOR_Max;
  593. IOBase += ~IOAlign + 1)
  594. {
  595. // For each IO that falls within the given range,
  596. // create new IO List Element, populate its fields and insert
  597. // it into the IOList.
  598. peIOList = new IO_LIST_ELEMENT;
  599. if (peIOList == NULL)
  600. {
  601. continue;
  602. }
  603. peIOList->dwIO_Base = (DWORD)IOBase;
  604. peIOList->dwIO_End = (DWORD)(IOBase + cIOBytes-1);
  605. peIOList->fConflict = FALSE;
  606. peIOList->fAllocated = FALSE;
  607. (*ppIOList)->push_back(peIOList);
  608. // Check for wrapping.
  609. if (IOBase >= IOBase + ~IOAlign+1)
  610. {
  611. TraceTag(ttidError, "IO base is greater than IO end!!!");
  612. break;
  613. }
  614. }
  615. }
  616. }
  617. //+---------------------------------------------------------------------------
  618. //
  619. // Member: CHwRes::UseAnswerFile
  620. //
  621. // Purpose: Reads in settings from answerfile and puts them into m_vAf*
  622. // member variables.
  623. //
  624. // Arguments:
  625. // szAnswerFile [in] Path to answerfile.
  626. // szSection [in] Section to read within answerfile
  627. //
  628. // Author: t-nabilr 07 Apr 1997
  629. //
  630. // Notes:
  631. //
  632. VOID CHwRes::UseAnswerFile(const WCHAR * const szAnswerFile, const WCHAR * const szSection) {
  633. CWInfFile AnswerFile;
  634. PCWInfSection pSection;
  635. DWORD dw;
  636. AssertSz(m_fInitialized,
  637. "UseAnswerFile called before CHwRes class HrInit'ed");
  638. // initialize answer file class
  639. if (AnswerFile.Init() == FALSE)
  640. {
  641. AssertSz(FALSE,"CHwRes::UseAnswerFile - Failed to initialize CWInfFile");
  642. return;
  643. }
  644. // Open the answerfile and find the desired section.
  645. AnswerFile.Open(szAnswerFile);
  646. pSection = AnswerFile.FindSection(szSection);
  647. // If the answer file section specified is missing
  648. // we should skip trying to read
  649. //
  650. if (pSection)
  651. {
  652. // Get the hardware resource keys
  653. if (pSection->GetIntValue(c_szAfIoAddr, &dw))
  654. {
  655. // set this only if the value isn't obviously wrong (i.e. <= 0)
  656. if (dw > 0)
  657. {
  658. m_vAfIo.SetDword(dw);
  659. m_vAfIo.SetPresent(TRUE);
  660. }
  661. }
  662. if (pSection->GetIntValue(c_szAfIrq, &dw))
  663. {
  664. // set this only if the value isn't obviously wrong (i.e. <= 0)
  665. if (dw > 0)
  666. {
  667. m_vAfIrq.SetDword(dw);
  668. m_vAfIrq.SetPresent(TRUE);
  669. }
  670. }
  671. if (pSection->GetIntValue(c_szAfDma, &dw))
  672. {
  673. // set this only if the value isn't obviously wrong (i.e. <= 0)
  674. if (dw > 0)
  675. {
  676. m_vAfDma.SetDword(dw);
  677. m_vAfDma.SetPresent(TRUE);
  678. }
  679. }
  680. if (pSection->GetIntValue(c_szAfMem, &dw))
  681. {
  682. // set this only if the value isn't obviously wrong (i.e. <= 0)
  683. if (dw > 0)
  684. {
  685. m_vAfMem.SetDword(dw);
  686. m_vAfMem.SetPresent(TRUE);
  687. }
  688. }
  689. }
  690. }
  691. //+---------------------------------------------------------------------------
  692. //
  693. // Member: CHwRes::FValidateAnswerfileSettings
  694. //
  695. // Purpose:
  696. // Ensures that the hw resource settings read in from the answerfile
  697. // are valid. It will, optionally, raise UI if the properties
  698. // are invalid.
  699. //
  700. // Arguments:
  701. // fDisplayUI [in] TRUE, if an error UI is to be displayed if the
  702. // answerfile settings are invalid
  703. //
  704. // Returns: HRESULT. S_OK if the answerfile settings are valid, S_FALSE if there
  705. // are no resources to set, an error code otherwise
  706. //
  707. // Author: t-nabilr 07 Apr 1997
  708. //
  709. // Notes:
  710. // Will set the m_vAfMemEnd and m_vAfIoEnd to correspond to
  711. // m_vAfMem and m_vAfIo.
  712. //
  713. HRESULT
  714. CHwRes::HrValidateAnswerfileSettings(BOOL fDisplayUI)
  715. {
  716. HRESULT hr = S_OK;
  717. AssertSz(m_fInitialized, "FValidateAnswerfileSettings called before "
  718. "CHwRes class HrInit'ed");
  719. // override current resource settings
  720. if (!m_vAfDma.IsPresent() &&
  721. !m_vAfIrq.IsPresent() &&
  722. !m_vAfIo.IsPresent() &&
  723. !m_vAfMem.IsPresent())
  724. {
  725. // no resources found...
  726. TraceTag(ttidNetComm, "No Hardware Resources found in answerfile.");
  727. hr = S_FALSE;
  728. }
  729. else
  730. {
  731. if (!FValidateAnswerfileResources())
  732. {
  733. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  734. TraceError("Error setting adapter resources from "
  735. "answerfile.", hr);
  736. }
  737. else
  738. {
  739. // m_vAfMemEnd and m_vAfIoEnd were set by
  740. // FValidateAnswerfileResources()
  741. Assert(FImplies(m_vAfMem.IsPresent(), m_vAfMemEnd.IsPresent()));
  742. Assert(FImplies(m_vAfIo.IsPresent(), m_vAfIoEnd.IsPresent()));
  743. }
  744. }
  745. TraceError("CHwRes::HrValidateAnswerfileSettings",
  746. (S_FALSE == hr) ? S_OK : hr);
  747. return hr;
  748. }
  749. //+---------------------------------------------------------------------------
  750. //
  751. // Member: CHwRes::FCommitAnswerfileSettings
  752. //
  753. // Purpose:
  754. // Commits (to the config manager) the hw resource settings read
  755. // in from the Answerfile.
  756. //
  757. // Returns: FALSE if there were problems writing the BootConfig entry.
  758. //
  759. // Author: t-nabilr 07 Apr 1997
  760. //
  761. // Notes:
  762. //
  763. BOOL CHwRes::FCommitAnswerfileSettings()
  764. {
  765. AssertSz(m_fInitialized, "FCommitAnswerfileSettings called before "
  766. "CHwRes class HrInit'ed");
  767. Assert(FImplies(m_vAfIo.IsPresent(), m_vAfIoEnd.IsPresent()));
  768. Assert(FImplies(m_vAfMem.IsPresent(), m_vAfMemEnd.IsPresent()));
  769. // write out forced config entry to the config manager
  770. BOOL f;
  771. f = FCreateBootConfig(&m_vAfMem, &m_vAfMemEnd,
  772. &m_vAfIo, &m_vAfIo,
  773. &m_vAfDma,
  774. &m_vAfIrq);
  775. return f;
  776. }
  777. //+---------------------------------------------------------------------------
  778. //
  779. // Member: CHwRes::FValidateAnswerfileResources
  780. //
  781. // Purpose: Validates the resource requirements read in from Answerfile.
  782. //
  783. // Arguments:
  784. // nID [out] ID of thingy.
  785. // fInstall [in] TRUE if installing, FALSE otherwise.
  786. // ppv [in,out] Old value is freed and this returns new value.
  787. //
  788. // Returns: TRUE, if resource requirement are valid.
  789. //
  790. // Author: t-nabilr 07 Apr 1997
  791. //
  792. // Notes:
  793. // Implementation note: We have a set of resource requirements from
  794. // the answerfile (stored in m_vAf*). This method iterates through
  795. // every logical config (execept alloc or boot ones) and tests to see
  796. // if the resource requirements are valid in the logical config.
  797. // If they are, then we can use the resource requirements. If they're
  798. // not all valid in any logical config, then we return FALSE.
  799. //
  800. BOOL CHwRes::FValidateAnswerfileResources()
  801. {
  802. DWORD dwMemEnd;
  803. DWORD dwIoEnd;
  804. BOOL fResourceValid;
  805. AssertSz(m_fInitialized, "FValidateAnswerfileResources called before "
  806. "CHwRes class HrInit'ed");
  807. // Configuration List should be initialized
  808. Assert(0 != m_ConfigList.size());
  809. PRESOURCE pResource;
  810. for (size_t iConfig = 0; iConfig < m_ConfigList.size(); iConfig++)
  811. {
  812. // we only want Basic configurations, so skip alloc or boot.
  813. if (m_ConfigList[iConfig]->fBoot || m_ConfigList[iConfig]->fAlloc)
  814. {
  815. continue;
  816. }
  817. fResourceValid = TRUE;
  818. if (m_vAfDma.IsPresent())
  819. {
  820. if (!FValidateDMA(m_ConfigList[iConfig], m_vAfDma.GetDword()))
  821. {
  822. fResourceValid = FALSE;
  823. }
  824. }
  825. if (m_vAfIrq.IsPresent())
  826. {
  827. if (!FValidateIRQ(m_ConfigList[iConfig], m_vAfIrq.GetDword()))
  828. {
  829. fResourceValid = FALSE;
  830. }
  831. }
  832. if (m_vAfIo.IsPresent())
  833. {
  834. if (!FGetIOEndPortGivenBasePort(m_ConfigList[iConfig],
  835. m_vAfIo.GetDword(), &dwIoEnd))
  836. {
  837. m_vAfIoEnd.SetPresent(FALSE);
  838. fResourceValid = FALSE;
  839. }
  840. else
  841. {
  842. m_vAfIoEnd.SetDword(dwIoEnd);
  843. m_vAfIoEnd.SetPresent(TRUE);
  844. }
  845. }
  846. if (m_vAfMem.IsPresent())
  847. {
  848. if (!FGetMEMEndGivenBase(m_ConfigList[iConfig],
  849. m_vAfMem.GetDword(), &dwMemEnd))
  850. {
  851. m_vAfMemEnd.SetPresent(FALSE);
  852. fResourceValid = FALSE;
  853. }
  854. else
  855. {
  856. m_vAfMemEnd.SetDword(dwMemEnd);
  857. m_vAfMemEnd.SetPresent(TRUE);
  858. }
  859. }
  860. if (fResourceValid) break; // found valid one.
  861. }
  862. // something has to be present (otherwise don't call this function!)
  863. Assert(m_vAfIo.IsPresent() || m_vAfIrq.IsPresent() ||
  864. m_vAfDma.IsPresent() || m_vAfMem.IsPresent());
  865. return fResourceValid;
  866. }
  867. //+---------------------------------------------------------------------------
  868. //
  869. // Member: CHwRes::FCreateBootConfig
  870. //
  871. // Purpose: Create and insert a Boot Config entry into the Config
  872. // Manager.
  873. //
  874. // Arguments:
  875. // pvMem [in] Memory range base
  876. // pvMemEnd [in] Memory range end
  877. // pvIo [in] Io range base
  878. // pvIoEnd [in] Io range end
  879. // pvDma [in] Dma resource required.
  880. // pvIrq [in] Irq resource required.
  881. //
  882. // Returns: TRUE if creation of forced config was successful.
  883. //
  884. // Author: t-nabilr 07 Apr 1997
  885. //
  886. // Notes:
  887. //
  888. BOOL CHwRes::FCreateBootConfig(
  889. CValue * pvMem,
  890. CValue * pvMemEnd,
  891. CValue * pvIo,
  892. CValue * pvIoEnd,
  893. CValue * pvDma,
  894. CValue * pvIrq)
  895. {
  896. DMA_RESOURCE DMARes;
  897. IO_RESOURCE IORes;
  898. MEM_RESOURCE MEMRes;
  899. IRQ_RESOURCE IRQRes;
  900. LOG_CONF lcLogConf = NULL;
  901. AssertSz(pvMem && pvMemEnd && pvIo && pvIoEnd && pvDma && pvIrq,
  902. "One of the pointer parameters passed to CHwRes::FCreate"
  903. "BootConfig() is null.");
  904. AssertSz(m_fInitialized, "FCreateBootConfig called before "
  905. "CHwRes class HrInit'ed");
  906. TraceTag(ttidNetComm, "In FCreateBootConfig");
  907. // Create a boot config
  908. //
  909. if (CM_Add_Empty_Log_Conf(&lcLogConf, m_DevNode, LCPRI_BOOTCONFIG,
  910. BOOT_LOG_CONF)
  911. != CR_SUCCESS)
  912. {
  913. TraceTag(ttidNetComm, "Unable to create BOOT_LOG_CONF");
  914. return FALSE;
  915. }
  916. if (pvDma->IsPresent())
  917. {
  918. Assert(pvDma->GetDword() > 0);
  919. // fill out DMAResource structure's header
  920. ZeroMemory(&DMARes, sizeof(DMARes));
  921. DMARes.DMA_Header.DD_Count = 0;
  922. DMARes.DMA_Header.DD_Type = DType_Range;
  923. DMARes.DMA_Header.DD_Flags = 0;
  924. DMARes.DMA_Header.DD_Alloc_Chan = pvDma->GetDword();
  925. // add to boot conf
  926. CM_Add_Res_Des(NULL, lcLogConf, ResType_DMA, &DMARes,
  927. sizeof(DMARes), 0);
  928. TraceTag(ttidNetComm, "added Dma resource %lX", pvDma->GetDword());
  929. }
  930. if (pvIrq->IsPresent())
  931. {
  932. Assert(pvIrq->GetDword() > 0);
  933. // IRQResource structure
  934. ZeroMemory(&IRQRes, sizeof(IRQRes));
  935. IRQRes.IRQ_Header.IRQD_Count = 0;
  936. IRQRes.IRQ_Header.IRQD_Type = IRQType_Range;
  937. IRQRes.IRQ_Header.IRQD_Flags |= fIRQD_Edge;
  938. IRQRes.IRQ_Header.IRQD_Alloc_Num = pvIrq->GetDword();
  939. IRQRes.IRQ_Header.IRQD_Affinity = 0;
  940. // add to boot conf
  941. CM_Add_Res_Des(NULL, lcLogConf, ResType_IRQ, &IRQRes,
  942. sizeof(IRQRes), 0);
  943. TraceTag(ttidNetComm, "added IRQ resource %lX", pvIrq->GetDword());
  944. }
  945. if (pvIo->IsPresent()) {
  946. Assert(pvIo->GetDword() > 0);
  947. Assert(pvIoEnd->GetDword() > 0);
  948. ZeroMemory(&IORes, sizeof(IORes));
  949. IORes.IO_Header.IOD_Count = 0;
  950. IORes.IO_Header.IOD_Type = IOType_Range;
  951. IORes.IO_Header.IOD_Alloc_Base = pvIo->GetDword();
  952. IORes.IO_Header.IOD_Alloc_End = pvIoEnd->GetDword();
  953. IORes.IO_Header.IOD_DesFlags = fIOD_10_BIT_DECODE;
  954. // add to boot conf
  955. CM_Add_Res_Des(NULL, lcLogConf, ResType_IO, &IORes, sizeof(IORes), 0);
  956. TraceTag(ttidNetComm, "added IO resource %lX-%lX", pvIo->GetDword(),
  957. pvIoEnd->GetDword());
  958. }
  959. if (pvMem->IsPresent()) {
  960. Assert(pvMem->GetDword() > 0);
  961. Assert(pvMemEnd->GetDword() > 0);
  962. ZeroMemory(&MEMRes, sizeof(MEMRes));
  963. MEMRes.MEM_Header.MD_Count = 0;
  964. MEMRes.MEM_Header.MD_Type = MType_Range;
  965. MEMRes.MEM_Header.MD_Alloc_Base = pvMem->GetDword();
  966. MEMRes.MEM_Header.MD_Alloc_End = pvMemEnd->GetDword();
  967. MEMRes.MEM_Header.MD_Flags = 0;
  968. // add to boot conf
  969. CM_Add_Res_Des(NULL, lcLogConf, ResType_Mem, &MEMRes,
  970. sizeof(MEMRes), 0);
  971. TraceTag(ttidNetComm, "added Memory resource %lX - %lX",
  972. pvMem->GetDword(), pvMemEnd->GetDword());
  973. }
  974. CM_Free_Log_Conf_Handle(lcLogConf);
  975. return TRUE;
  976. }
  977. //+---------------------------------------------------------------------------
  978. //
  979. // Member: CHwRes::FValidateIRQ
  980. //
  981. // Purpose: Validates that the IRQ given is valid in the given config.
  982. //
  983. // Arguments:
  984. // pConfig [in] Config to use.
  985. // dwIRQ [in] irq setting to validate.
  986. //
  987. // Returns: TRUE if irq setting is valid.
  988. //
  989. // Author: t-nabilr 07 Apr 1997
  990. //
  991. // Notes:
  992. //
  993. BOOL CHwRes::FValidateIRQ(PCONFIGURATION pConfig, ULONG dwIRQ)
  994. {
  995. PIRQ_LIST pIRQList;
  996. AssertSz(m_fInitialized, "FValidateIRQ called before "
  997. "CHwRes class HrInit'ed");
  998. Assert(pConfig != NULL);
  999. Assert(dwIRQ > 0);
  1000. // For each IRQ resource in the given config
  1001. // go through list of valid IRQ looking for given one
  1002. // if found, return TRUE
  1003. for (size_t iRes = 0; iRes < pConfig->cResource; iRes++)
  1004. {
  1005. if (pConfig->aResource[iRes].ResourceType != ResType_IRQ)
  1006. continue;
  1007. pIRQList = pConfig->aResource[iRes].pIRQList; // for easy access
  1008. for (size_t iIRQ = 0; iIRQ < pIRQList->size(); iIRQ++)
  1009. {
  1010. if ((*pIRQList)[iIRQ]->dwIRQ == dwIRQ)
  1011. {
  1012. return TRUE; // found it.
  1013. }
  1014. }
  1015. }
  1016. TraceTag(ttidNetComm, "IRQ %lX is not valid for this device", dwIRQ);
  1017. return FALSE;
  1018. }
  1019. //+---------------------------------------------------------------------------
  1020. //
  1021. // Member: CHwRes::FValidateDMA
  1022. //
  1023. // Purpose: Validate that given DMA is valid in given config.
  1024. //
  1025. // Arguments:
  1026. // pConfig [in] configuration to use
  1027. // dwDMA [in] dma setting to validate
  1028. //
  1029. // Returns: TRUE if dma setting is valid
  1030. //
  1031. // Author: t-nabilr 07 Apr 1997
  1032. //
  1033. // Notes:
  1034. //
  1035. BOOL CHwRes::FValidateDMA(PCONFIGURATION pConfig, ULONG dwDMA)
  1036. {
  1037. PDMA_LIST pDMAList;
  1038. AssertSz(m_fInitialized, "FValidateDMA called before "
  1039. "CHwRes class HrInit'ed");
  1040. Assert(pConfig != NULL);
  1041. Assert(dwDMA > 0);
  1042. // For each dma resource in the given config
  1043. // go through list of valid dma looking for given one
  1044. // if found, return TRUE
  1045. for (size_t iRes = 0; iRes < pConfig->cResource; iRes++)
  1046. {
  1047. if (pConfig->aResource[iRes].ResourceType != ResType_DMA)
  1048. continue;
  1049. pDMAList = pConfig->aResource[iRes].pDMAList; // for easy access
  1050. for (size_t iDMA = 0; iDMA < pDMAList->size(); iDMA++)
  1051. {
  1052. if ((*pDMAList)[iDMA]->dwDMA == dwDMA)
  1053. {
  1054. return TRUE;
  1055. }
  1056. }
  1057. }
  1058. TraceTag(ttidNetComm, "DMA %lX is not valid for this device", dwDMA);
  1059. return FALSE;
  1060. }
  1061. //+---------------------------------------------------------------------------
  1062. //
  1063. // Member: CHwRes::FGetIOEndPortGivenBasePort
  1064. //
  1065. // Purpose: Get an IO Range given only the BasePort
  1066. //
  1067. // Arguments:
  1068. // pConfig [in] configuration to use.
  1069. // dwBase [in] Io base
  1070. // pdwEnd [out] Io end is returned
  1071. //
  1072. // Returns: TRUE if Io base is valid in given config.
  1073. //
  1074. // Author: t-nabilr 07 Apr 1997
  1075. //
  1076. // Notes:
  1077. //
  1078. BOOL CHwRes::FGetIOEndPortGivenBasePort(PCONFIGURATION pConfig, DWORD dwBase,
  1079. DWORD * pdwEnd)
  1080. {
  1081. PIO_LIST pIOList;
  1082. AssertSz(m_fInitialized, "FGetIOEndPortGivenBasePort called before "
  1083. "CHwRes class HrInit'ed");
  1084. Assert(pConfig != NULL);
  1085. Assert(dwBase > 0);
  1086. // For each resource in the given configuration
  1087. // if it's an IO Resource
  1088. // Go through the list of valid IO resources looking for
  1089. // a matching base port
  1090. // if found, then set the corresponding end port, return TRUE;
  1091. for (size_t iRes = 0; iRes < pConfig->cResource; iRes++)
  1092. {
  1093. // ensure we're looking at an IO type
  1094. if (pConfig->aResource[iRes].ResourceType != ResType_IO)
  1095. continue;
  1096. pIOList = pConfig->aResource[iRes].pIOList; // for easy access
  1097. // go through all IO Elements in this list
  1098. for (size_t iIO = 0; iIO < pIOList->size(); iIO++)
  1099. {
  1100. if ((*pIOList)[iIO]->dwIO_Base == dwBase)
  1101. {
  1102. // found matching IO base port
  1103. *pdwEnd = (*pIOList)[iIO]->dwIO_End;
  1104. return TRUE;
  1105. }
  1106. }
  1107. }
  1108. TraceTag(ttidNetComm, "IO %lX is not valid for this device", dwBase);
  1109. return FALSE; // not found
  1110. }
  1111. //+---------------------------------------------------------------------------
  1112. //
  1113. // Member: CHwRes::FGetMEMEndGivenBase
  1114. //
  1115. // Purpose: Get a MEM range given the Mem base and config.
  1116. //
  1117. // Arguments:
  1118. // pConfig [in] configuration to use
  1119. // dwBase [in] mem base
  1120. // pdwEnd [out] mem end is returned.
  1121. //
  1122. // Returns: TRUE if the dwBase is a valid mem setting.
  1123. //
  1124. // Author: t-nabilr 07 Apr 1997
  1125. //
  1126. // Notes:
  1127. //
  1128. BOOL CHwRes::FGetMEMEndGivenBase(PCONFIGURATION pConfig, DWORD dwBase,
  1129. DWORD * pdwEnd)
  1130. {
  1131. PMEM_LIST pMEMList;
  1132. AssertSz(m_fInitialized, "FGetMEMEndGivenBase called before "
  1133. "CHwRes class HrInit'ed");
  1134. Assert(pConfig != NULL);
  1135. Assert(dwBase > 0);
  1136. // For each resource in the given configuration
  1137. // if it's an MEM Resource
  1138. // Go through the list of valid MEM resources looking for
  1139. // a matching base port
  1140. // if found, then set the corresponding end port,return TRUE;
  1141. for (size_t iRes = 0; iRes < pConfig->cResource; iRes++)
  1142. {
  1143. // ensure we're looking at an MEM type
  1144. if (pConfig->aResource[iRes].ResourceType != ResType_Mem)
  1145. continue;
  1146. pMEMList = pConfig->aResource[iRes].pMEMList; // for easy access
  1147. // go through all MEM Elements in this list
  1148. for (size_t iMEM = 0; iMEM < pMEMList->size(); iMEM++)
  1149. {
  1150. if ((*pMEMList)[iMEM]->dwMEM_Base == dwBase)
  1151. {
  1152. // found matching MEM base addr
  1153. *pdwEnd = (*pMEMList)[iMEM]->dwMEM_End;
  1154. return TRUE;
  1155. }
  1156. }
  1157. }
  1158. TraceTag(ttidNetComm, "Memory %lX is not valid for this device", dwBase);
  1159. return FALSE; // not found
  1160. }
  1161. //$REVIEW (t-pkoch) this function isn't yet in our custom STL...
  1162. // it can be removed later (when it causes errors)
  1163. template<class T> void os_release(vector<T> & v)
  1164. {
  1165. for(vector<T>::iterator iterDelete = v.begin() ; iterDelete != v.end() ;
  1166. ++iterDelete)
  1167. delete *iterDelete;
  1168. }
  1169. CHwRes::~CHwRes()
  1170. {
  1171. AssertSz(m_fHrInitCalled, "CHwRes destructor called before "
  1172. "CHwRes::HrInit() called");
  1173. vector<CONFIGURATION *>::iterator ppConfig;
  1174. RESOURCE * pRes;
  1175. // Delete everything from m_ConfigList.
  1176. for (ppConfig = m_ConfigList.begin(); ppConfig != m_ConfigList.end();
  1177. ppConfig++)
  1178. {
  1179. for (size_t iRes = 0; iRes < (*ppConfig)->cResource; iRes++)
  1180. {
  1181. pRes = &((*ppConfig)->aResource[iRes]);
  1182. switch(pRes->ResourceType)
  1183. {
  1184. case ResType_IRQ:
  1185. os_release(*(pRes->pIRQList));
  1186. delete pRes->pIRQList;
  1187. break;
  1188. case ResType_DMA:
  1189. os_release(*(pRes->pDMAList));
  1190. delete pRes->pDMAList;
  1191. break;
  1192. case ResType_IO:
  1193. os_release(*(pRes->pIOList));
  1194. delete pRes->pIOList;
  1195. break;
  1196. case ResType_Mem:
  1197. os_release(*(pRes->pMEMList));
  1198. delete pRes->pMEMList;
  1199. break;
  1200. }
  1201. }
  1202. delete *ppConfig;
  1203. }
  1204. ReleaseObj(m_pnccItem);
  1205. }