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.

3130 lines
100 KiB

  1. /*++
  2. Copyright (c) 1994-2000 Microsoft Corporation
  3. Module Name:
  4. pnpmap.c
  5. Abstract:
  6. This module contains the code that translates the device info returned from
  7. the PnP BIOS into root enumerated devices.
  8. Author:
  9. Robert B. Nelson (RobertN) 22-Sep-1997
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "pnpmgrp.h"
  15. #pragma hdrstop
  16. #include "pnpcvrt.h"
  17. #include "pbios.h"
  18. #ifdef POOL_TAGGING
  19. #undef ExAllocatePool
  20. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'PpaM')
  21. #endif
  22. #if UMODETEST
  23. #define MULTIFUNCTION_KEY_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\TestSystem\\MultifunctionAdapter"
  24. #define ENUMROOT_KEY_NAME L"\\Registry\\Machine\\System\\TestControlSet\\Enum\\Root"
  25. #else
  26. #define MULTIFUNCTION_KEY_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
  27. #define ENUMROOT_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\Root"
  28. #endif
  29. #define BIOSINFO_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Biosinfo\\PNPBios"
  30. #define DISABLENODES_VALUE_NAME L"DisableNodes"
  31. #define DECODEINFO_VALUE_NAME L"FullDecodeChipsetOverride"
  32. #define INSTANCE_ID_PREFIX L"PnPBIOS_"
  33. #define DEFAULT_STRING_SIZE 80
  34. #define DEFAULT_VALUE_SIZE 80
  35. #define DEFAULT_DEVICE_DESCRIPTION L"Unknown device class"
  36. #define EXCLUSION_ENTRY(a) { a, sizeof(a) - sizeof(UNICODE_NULL) }
  37. typedef struct _EXCLUDED_PNPNODE {
  38. PWCHAR Id;
  39. ULONG IdLength;
  40. } EXCLUDED_PNPNODE, *PEXCLUDED_PNPNODE;
  41. #ifdef ALLOC_DATA_PRAGMA
  42. #pragma const_seg("INITCONST")
  43. #endif
  44. const EXCLUDED_PNPNODE ExcludedDevices[] = {
  45. EXCLUSION_ENTRY(L"*PNP03"), // Keyboards
  46. EXCLUSION_ENTRY(L"*PNP0A"), // PCI Busses
  47. EXCLUSION_ENTRY(L"*PNP0E"), // PCMCIA Busses
  48. EXCLUSION_ENTRY(L"*PNP0F"), // Mice
  49. EXCLUSION_ENTRY(L"*IBM3780"), // IBM Trackpoint Mouse
  50. EXCLUSION_ENTRY(L"*IBM3781") // IBM Trackpoint Mouse
  51. };
  52. #define EXCLUDED_DEVICES_COUNT (sizeof(ExcludedDevices) / sizeof(ExcludedDevices[0]))
  53. const EXCLUDED_PNPNODE ExcludeIfDisabled[] = {
  54. EXCLUSION_ENTRY(L"*PNP0C01"), // Motherboard resources
  55. EXCLUSION_ENTRY(L"*PNP0C02") // Motherboard resources
  56. };
  57. #define EXCLUDE_DISABLED_COUNT (sizeof(ExcludeIfDisabled) / sizeof(ExcludeIfDisabled[0]))
  58. typedef struct _CLASSDATA {
  59. ULONG Value;
  60. PWCHAR Description;
  61. } CLASSDATA;
  62. const CLASSDATA Class1Descriptions[] = {
  63. { 0x0000, L"SCSI Controller" },
  64. { 0x0100, L"IDE Controller" },
  65. { 0x0200, L"Floppy Controller" },
  66. { 0x0300, L"IPI Controller" },
  67. { 0x0400, L"RAID Controller" },
  68. { 0x8000, L"Other Mass Storage" }
  69. };
  70. const CLASSDATA Class2Descriptions[] = {
  71. { 0x0000, L"Ethernet" },
  72. { 0x0100, L"Token ring" },
  73. { 0x0200, L"FDDI" },
  74. { 0x0300, L"ATM" },
  75. { 0x8000, L"Other network" }
  76. };
  77. const CLASSDATA Class3Descriptions[] = {
  78. { 0x0000, L"VGA" },
  79. { 0x0001, L"SVGA" },
  80. { 0x0100, L"XGA" },
  81. { 0x8000, L"Other display" }
  82. };
  83. const CLASSDATA Class4Descriptions[] = {
  84. { 0x0000, L"Video device" },
  85. { 0x0100, L"Audio device" },
  86. { 0x8000, L"Other multimedia" }
  87. };
  88. const CLASSDATA Class5Descriptions[] = {
  89. { 0x0000, L"RAM memory" },
  90. { 0x0100, L"Flash memory" },
  91. { 0x8000, L"Other memory" }
  92. };
  93. const CLASSDATA Class6Descriptions[] = {
  94. { 0x0000, L"HOST / PCI" },
  95. { 0x0100, L"PCI / ISA" },
  96. { 0x0200, L"PCI / EISA" },
  97. { 0x0300, L"PCI / MCA" },
  98. { 0x0400, L"PCI / PCI" },
  99. { 0x0500, L"PCI / PCMCIA" },
  100. { 0x0600, L"NuBus" },
  101. { 0x0700, L"Cardbus" },
  102. { 0x8000, L"Other bridge" }
  103. };
  104. const CLASSDATA Class7Descriptions[] = {
  105. { 0x0000, L"XT Serial" },
  106. { 0x0001, L"16450" },
  107. { 0x0002, L"16550" },
  108. { 0x0100, L"Parallel output only" },
  109. { 0x0101, L"BiDi Parallel" },
  110. { 0x0102, L"ECP 1.x parallel" },
  111. { 0x8000, L"Other comm" }
  112. };
  113. const CLASSDATA Class8Descriptions[] = {
  114. { 0x0000, L"Generic 8259" },
  115. { 0x0001, L"ISA PIC" },
  116. { 0x0002, L"EISA PIC" },
  117. { 0x0100, L"Generic 8237" },
  118. { 0x0101, L"ISA DMA" },
  119. { 0x0102, L"EISA DMA" },
  120. { 0x0200, L"Generic 8254" },
  121. { 0x0201, L"ISA timer" },
  122. { 0x0202, L"EISA timer" },
  123. { 0x0300, L"Generic RTC" },
  124. { 0x0301, L"ISA RTC" },
  125. { 0x8000, L"Other system device" }
  126. };
  127. const CLASSDATA Class9Descriptions[] = {
  128. { 0x0000, L"Keyboard" },
  129. { 0x0100, L"Digitizer" },
  130. { 0x0200, L"Mouse" },
  131. { 0x8000, L"Other input" }
  132. };
  133. const CLASSDATA Class10Descriptions[] = {
  134. { 0x0000, L"Generic dock" },
  135. { 0x8000, L"Other dock" },
  136. };
  137. const CLASSDATA Class11Descriptions[] = {
  138. { 0x0000, L"386" },
  139. { 0x0100, L"486" },
  140. { 0x0200, L"Pentium" },
  141. { 0x1000, L"Alpha" },
  142. { 0x4000, L"Co-processor" }
  143. };
  144. const CLASSDATA Class12Descriptions[] = {
  145. { 0x0000, L"Firewire" },
  146. { 0x0100, L"Access bus" },
  147. { 0x0200, L"SSA" },
  148. { 0x8000, L"Other serial bus" }
  149. };
  150. #define CLASSLIST_ENTRY(a) { a, sizeof(a) / sizeof(a[0]) }
  151. struct _CLASS_DESCRIPTIONS_LIST {
  152. CLASSDATA const*Descriptions;
  153. ULONG Count;
  154. } const ClassDescriptionsList[] = {
  155. { NULL, 0 },
  156. CLASSLIST_ENTRY( Class1Descriptions ),
  157. CLASSLIST_ENTRY( Class2Descriptions ),
  158. CLASSLIST_ENTRY( Class3Descriptions ),
  159. CLASSLIST_ENTRY( Class4Descriptions ),
  160. CLASSLIST_ENTRY( Class5Descriptions ),
  161. CLASSLIST_ENTRY( Class6Descriptions ),
  162. CLASSLIST_ENTRY( Class7Descriptions ),
  163. CLASSLIST_ENTRY( Class8Descriptions ),
  164. CLASSLIST_ENTRY( Class9Descriptions ),
  165. CLASSLIST_ENTRY( Class10Descriptions ),
  166. CLASSLIST_ENTRY( Class11Descriptions ),
  167. CLASSLIST_ENTRY( Class12Descriptions )
  168. };
  169. #define CLASSLIST_COUNT ( sizeof(ClassDescriptionsList) / sizeof(ClassDescriptionsList[0]) )
  170. typedef struct _BIOS_DEVNODE_INFO {
  171. WCHAR ProductId[10]; // '*' + 7 char ID + NUL + NUL for REG_MULTI_SZ
  172. UCHAR Handle; // BIOS Node # / Handle
  173. UCHAR TypeCode[3];
  174. USHORT Attributes;
  175. PWSTR Replaces; // Instance ID of Root enumerated device being replaced
  176. PCM_RESOURCE_LIST BootConfig;
  177. ULONG BootConfigLength;
  178. PIO_RESOURCE_REQUIREMENTS_LIST BasicConfig;
  179. ULONG BasicConfigLength;
  180. PWSTR CompatibleIDs; // REG_MULTI_SZ list of compatible IDs (including ProductId)
  181. ULONG CompatibleIDsLength;
  182. BOOLEAN FirmwareDisabled; // determined that it's disabled by firmware
  183. } BIOS_DEVNODE_INFO, *PBIOS_DEVNODE_INFO;
  184. NTSTATUS
  185. PbBiosResourcesToNtResources (
  186. IN ULONG BusNumber,
  187. IN ULONG SlotNumber,
  188. IN OUT PUCHAR *BiosData,
  189. OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList,
  190. OUT PULONG ReturnedLength
  191. );
  192. VOID
  193. PnPBiosExpandProductId(
  194. PUCHAR CompressedId,
  195. PWCHAR ProductIDStr
  196. );
  197. NTSTATUS
  198. PnPBiosIoResourceListToCmResourceList(
  199. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
  200. OUT PCM_RESOURCE_LIST *CmResourceList,
  201. OUT ULONG *CmResourceListSize
  202. );
  203. NTSTATUS
  204. PnPBiosExtractCompatibleIDs(
  205. IN PUCHAR *DevNodeData,
  206. IN ULONG DevNodeDataLength,
  207. OUT PWSTR *CompatibleIDs,
  208. OUT ULONG *CompatibleIDsLength
  209. );
  210. NTSTATUS
  211. PnPBiosTranslateInfo(
  212. IN VOID *BiosInfo,
  213. IN ULONG BiosInfoLength,
  214. OUT PBIOS_DEVNODE_INFO *DevNodeInfoList,
  215. OUT ULONG *NumberNodes
  216. );
  217. LONG
  218. PnPBiosFindMatchingDevNode(
  219. IN PWCHAR MapperName,
  220. IN PCM_RESOURCE_LIST ResourceList,
  221. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  222. IN ULONG NumberNodes
  223. );
  224. NTSTATUS
  225. PnPBiosEliminateDupes(
  226. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  227. IN ULONG NumberNodes
  228. );
  229. PWCHAR
  230. PnPBiosGetDescription(
  231. IN PBIOS_DEVNODE_INFO DevNodeInfoEntry
  232. );
  233. NTSTATUS
  234. PnPBiosWriteInfo(
  235. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  236. IN ULONG NumberNodes
  237. );
  238. VOID
  239. PnPBiosCopyIoDecode(
  240. IN HANDLE EnumRootKey,
  241. IN PBIOS_DEVNODE_INFO DevNodeInfo
  242. );
  243. NTSTATUS
  244. PnPBiosFreeDevNodeInfo(
  245. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  246. IN ULONG NumberNodes
  247. );
  248. NTSTATUS
  249. PnPBiosCheckForHardwareDisabled(
  250. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
  251. IN OUT PBOOLEAN Disabled
  252. );
  253. BOOLEAN
  254. PnPBiosCheckForExclusion(
  255. IN EXCLUDED_PNPNODE const* ExclusionArray,
  256. IN ULONG ExclusionCount,
  257. IN PWCHAR PnpDeviceName,
  258. IN PWCHAR PnpCompatIds
  259. );
  260. NTSTATUS
  261. PnPBiosMapper(
  262. VOID
  263. );
  264. VOID
  265. PpFilterNtResource (
  266. IN PWCHAR PnpDeviceName,
  267. PIO_RESOURCE_REQUIREMENTS_LIST ResReqList
  268. );
  269. NTSTATUS
  270. ComPortDBAdd(
  271. IN HANDLE DeviceParamKey,
  272. IN PWSTR PortName
  273. );
  274. #ifdef ALLOC_PRAGMA
  275. BOOLEAN
  276. PnPBiosIgnoreNode (
  277. PWCHAR PnpID,
  278. PWCHAR excludeNodes
  279. );
  280. PKEY_VALUE_FULL_INFORMATION
  281. PnPGetBiosInfoValue(
  282. PWCHAR ValueName
  283. );
  284. NTSTATUS
  285. PnPBiosCopyDeviceParamKey(
  286. IN HANDLE EnumRootKey,
  287. IN PWCHAR SourcePath,
  288. IN PWCHAR DestinationPath
  289. );
  290. #pragma alloc_text(INIT, PnPBiosExpandProductId)
  291. #pragma alloc_text(INIT, PnPBiosIgnoreNode)
  292. #pragma alloc_text(INIT, PnPGetBiosInfoValue)
  293. #pragma alloc_text(INIT, PnPBiosIoResourceListToCmResourceList)
  294. #pragma alloc_text(INIT, PnPBiosExtractCompatibleIDs)
  295. #pragma alloc_text(INIT, PnPBiosTranslateInfo)
  296. #pragma alloc_text(INIT, PnPBiosFindMatchingDevNode)
  297. #pragma alloc_text(INIT, PnPBiosEliminateDupes)
  298. #pragma alloc_text(INIT, PnPBiosGetDescription)
  299. #pragma alloc_text(INIT, PnPBiosCopyDeviceParamKey)
  300. #pragma alloc_text(INIT, PnPBiosWriteInfo)
  301. #pragma alloc_text(INIT, PnPBiosCopyIoDecode)
  302. #pragma alloc_text(INIT, PnPBiosFreeDevNodeInfo)
  303. #pragma alloc_text(INIT, PnPBiosCheckForHardwareDisabled)
  304. #pragma alloc_text(INIT, PnPBiosCheckForExclusion)
  305. #pragma alloc_text(INIT, PnPBiosMapper)
  306. #pragma alloc_text(INIT, PpFilterNtResource)
  307. #pragma alloc_text(PAGE, PnPBiosGetBiosInfo)
  308. #endif
  309. NTSTATUS
  310. PnPBiosGetBiosInfo(
  311. OUT PVOID *BiosInfo,
  312. OUT ULONG *BiosInfoLength
  313. )
  314. /*++
  315. Routine Description:
  316. This function retrieves the PnP BIOS info accumulated by NTDETECT.COM and
  317. placed in the registry.
  318. Arguments:
  319. BiosInfo - Set to a dynamically allocated block of information retrieved
  320. from the PnP BIOS by NTDETECT. This block should be freed using
  321. ExFreePool. The contents of the block are the PnP BIOS
  322. Installation Check Structure followed by the DevNode Structures reported
  323. by the BIOS. The detailed format is documented in the PnP BIOS spec.
  324. BiosInfoLength - Length of the block whose address is stored in BiosInfo.
  325. Return Value:
  326. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  327. --*/
  328. {
  329. UNICODE_STRING multifunctionKeyName, biosKeyName, valueName;
  330. HANDLE multifunctionKey = NULL, biosKey = NULL;
  331. PKEY_BASIC_INFORMATION keyBasicInfo = NULL;
  332. ULONG keyBasicInfoLength;
  333. PKEY_VALUE_PARTIAL_INFORMATION valueInfo = NULL;
  334. ULONG valueInfoLength;
  335. ULONG returnedLength;
  336. PCM_FULL_RESOURCE_DESCRIPTOR biosValue;
  337. ULONG index;
  338. NTSTATUS status = STATUS_UNSUCCESSFUL;
  339. //
  340. // The PnP BIOS info is written to one of the subkeys under
  341. // MULTIFUNCTION_KEY_NAME. The appropriate key is determined by
  342. // enumerating the subkeys and using the first one which has a value named
  343. // "Identifier" that is "PNP BIOS".
  344. //
  345. PiWstrToUnicodeString(&multifunctionKeyName, MULTIFUNCTION_KEY_NAME);
  346. status = IopOpenRegistryKeyEx( &multifunctionKey,
  347. NULL,
  348. &multifunctionKeyName,
  349. KEY_READ
  350. );
  351. if (!NT_SUCCESS(status)) {
  352. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  353. "Could not open %S, status = %8.8X\n",
  354. MULTIFUNCTION_KEY_NAME,
  355. status) );
  356. return STATUS_UNSUCCESSFUL;
  357. }
  358. //
  359. // Allocate memory for key names returned from ZwEnumerateKey and values
  360. // returned from ZwQueryValueKey.
  361. //
  362. keyBasicInfoLength = sizeof(KEY_BASIC_INFORMATION) + DEFAULT_STRING_SIZE;
  363. keyBasicInfo = ExAllocatePool(PagedPool, keyBasicInfoLength + sizeof(UNICODE_NULL));
  364. if (keyBasicInfo == NULL) {
  365. ZwClose( multifunctionKey );
  366. return STATUS_NO_MEMORY;
  367. }
  368. valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + DEFAULT_STRING_SIZE;
  369. valueInfo = ExAllocatePool(PagedPool, valueInfoLength);
  370. if (valueInfo == NULL) {
  371. ExFreePool( keyBasicInfo );
  372. ZwClose( multifunctionKey );
  373. return STATUS_NO_MEMORY;
  374. }
  375. //
  376. // Enumerate each key under HKLM\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter
  377. // to locate the one representing the PnP BIOS information.
  378. //
  379. for (index = 0; ; index++) {
  380. status = ZwEnumerateKey( multifunctionKey, // handle of key to enumerate
  381. index, // index of subkey to enumerate
  382. KeyBasicInformation,
  383. keyBasicInfo,
  384. keyBasicInfoLength,
  385. &returnedLength);
  386. if (!NT_SUCCESS(status)) {
  387. if (status != STATUS_NO_MORE_ENTRIES) {
  388. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  389. "Could not enumerate under key %S, status = %8.8X\n",
  390. MULTIFUNCTION_KEY_NAME,
  391. status) );
  392. }
  393. break;
  394. }
  395. //
  396. // We found a subkey, NUL terminate the name and open the subkey.
  397. //
  398. keyBasicInfo->Name[ keyBasicInfo->NameLength / 2 ] = L'\0';
  399. RtlInitUnicodeString(&biosKeyName, keyBasicInfo->Name);
  400. status = IopOpenRegistryKeyEx( &biosKey,
  401. multifunctionKey,
  402. &biosKeyName,
  403. KEY_READ
  404. );
  405. if (!NT_SUCCESS(status)) {
  406. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  407. "Could not open registry key %S\\%S, status = %8.8X\n",
  408. MULTIFUNCTION_KEY_NAME,
  409. keyBasicInfo->Name,
  410. status) );
  411. break;
  412. }
  413. //
  414. // Now we need to check the Identifier value in the subkey to see if
  415. // it is PNP BIOS.
  416. //
  417. PiWstrToUnicodeString(&valueName, L"Identifier");
  418. status = ZwQueryValueKey( biosKey,
  419. &valueName,
  420. KeyValuePartialInformation,
  421. valueInfo,
  422. valueInfoLength,
  423. &returnedLength);
  424. // lets see if its the PNP BIOS identifier
  425. if (NT_SUCCESS(status)) {
  426. if (wcscmp((PWSTR)valueInfo->Data, L"PNP BIOS") == 0) {
  427. //
  428. // We found the PnP BIOS subkey, retrieve the BIOS info which
  429. // is stored in the "Configuration Data" value.
  430. //
  431. // We'll start off with our default value buffer and increase
  432. // its size if necessary.
  433. //
  434. PiWstrToUnicodeString(&valueName, L"Configuration Data");
  435. status = ZwQueryValueKey( biosKey,
  436. &valueName,
  437. KeyValuePartialInformation,
  438. valueInfo,
  439. valueInfoLength,
  440. &returnedLength);
  441. if (!NT_SUCCESS(status)) {
  442. if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW) {
  443. //
  444. // The default buffer was too small, free it and reallocate
  445. // it to the required size.
  446. //
  447. ExFreePool( valueInfo );
  448. valueInfoLength = returnedLength;
  449. valueInfo = ExAllocatePool( PagedPool, valueInfoLength );
  450. if (valueInfo != NULL) {
  451. status = ZwQueryValueKey( biosKey,
  452. &valueName,
  453. KeyValuePartialInformation,
  454. valueInfo,
  455. valueInfoLength,
  456. &returnedLength );
  457. } else {
  458. status = STATUS_NO_MEMORY;
  459. }
  460. }
  461. }
  462. if (NT_SUCCESS(status)) {
  463. //
  464. // We now have the PnP BIOS data but it is buried inside
  465. // the resource structures. Do some consistency checks and
  466. // then extract it into its own buffer.
  467. //
  468. ASSERT(valueInfo->Type == REG_FULL_RESOURCE_DESCRIPTOR);
  469. biosValue = (PCM_FULL_RESOURCE_DESCRIPTOR)valueInfo->Data;
  470. //
  471. // The WMI folks added another list so we should search for
  472. // the PnPBIOS one, but for now the BIOS one is always
  473. // first.
  474. //
  475. *BiosInfoLength = biosValue->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
  476. *BiosInfo = ExAllocatePool(PagedPool, *BiosInfoLength);
  477. if (*BiosInfo != NULL) {
  478. RtlCopyMemory( *BiosInfo,
  479. &biosValue->PartialResourceList.PartialDescriptors[1],
  480. *BiosInfoLength );
  481. status = STATUS_SUCCESS;
  482. } else {
  483. *BiosInfoLength = 0;
  484. status = STATUS_NO_MEMORY;
  485. }
  486. } else {
  487. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  488. "Error retrieving %S\\%S\\Configuration Data, status = %8.8X\n",
  489. MULTIFUNCTION_KEY_NAME,
  490. keyBasicInfo->Name,
  491. status) );
  492. }
  493. //
  494. // We found the PnP BIOS entry, so close the key handle and
  495. // return.
  496. //
  497. ZwClose(biosKey);
  498. break;
  499. }
  500. }
  501. //
  502. // That wasn't it so close this handle and try the next subkey.
  503. //
  504. ZwClose(biosKey);
  505. }
  506. //
  507. // Cleanup the dynamically allocated temporary buffers.
  508. //
  509. if (valueInfo != NULL) {
  510. ExFreePool(valueInfo);
  511. }
  512. if (keyBasicInfo != NULL) {
  513. ExFreePool(keyBasicInfo);
  514. }
  515. ZwClose(multifunctionKey);
  516. return status;
  517. }
  518. VOID
  519. PnPBiosExpandProductId(
  520. PUCHAR CompressedId,
  521. PWCHAR ProductIDStr
  522. )
  523. /*++
  524. Routine Description:
  525. This function expands a PnP Device ID from the 4 byte compressed form into
  526. an 7 character unicode string. The string is then NUL terminated.
  527. Arguments:
  528. CompressedId - Pointer to the 4 byte compressed Device ID as defined in the
  529. PnP Specification.
  530. ProductIDStr - Pointer to the 16 byte buffer in which the unicode string
  531. version of the ID is placed.
  532. Return Value:
  533. NONE.
  534. --*/
  535. {
  536. static const CHAR HexDigits[16] = "0123456789ABCDEF";
  537. ProductIDStr[0] = (CompressedId[0] >> 2) + 0x40;
  538. ProductIDStr[1] = (((CompressedId[0] & 0x03) << 3) | (CompressedId[1] >> 5)) + 0x40;
  539. ProductIDStr[2] = (CompressedId[1] & 0x1f) + 0x40;
  540. ProductIDStr[3] = HexDigits[CompressedId[2] >> 4];
  541. ProductIDStr[4] = HexDigits[CompressedId[2] & 0x0F];
  542. ProductIDStr[5] = HexDigits[CompressedId[3] >> 4];
  543. ProductIDStr[6] = HexDigits[CompressedId[3] & 0x0F];
  544. ProductIDStr[7] = 0x00;
  545. }
  546. BOOLEAN
  547. PnPBiosIgnoreNode (
  548. PWCHAR PnpID,
  549. PWCHAR excludeNodes
  550. )
  551. {
  552. BOOLEAN bRet=FALSE;
  553. ULONG keyLen;
  554. PWCHAR pTmp;
  555. ASSERT(excludeNodes);
  556. //
  557. //excludeNodes is multi-sz, so walk through each one and check it.
  558. //
  559. pTmp=excludeNodes;
  560. while (*pTmp != '\0') {
  561. keyLen = (ULONG)wcslen(pTmp);
  562. if (RtlCompareMemory(PnpID,pTmp,keyLen*sizeof (WCHAR)) == keyLen*sizeof (WCHAR)) {
  563. bRet=TRUE;
  564. break;
  565. }
  566. pTmp = pTmp + keyLen + 1;
  567. }
  568. return bRet;
  569. }
  570. PKEY_VALUE_FULL_INFORMATION
  571. PnPGetBiosInfoValue(
  572. PWCHAR ValueName
  573. )
  574. {
  575. UNICODE_STRING biosKeyName;
  576. HANDLE biosKey;
  577. NTSTATUS status;
  578. PKEY_VALUE_FULL_INFORMATION info;
  579. info = NULL;
  580. PiWstrToUnicodeString(&biosKeyName, BIOSINFO_KEY_NAME);
  581. status = IopOpenRegistryKeyEx( &biosKey,
  582. NULL,
  583. &biosKeyName,
  584. KEY_READ
  585. );
  586. if (NT_SUCCESS(status)) {
  587. IopGetRegistryValue (biosKey, ValueName, &info);
  588. ZwClose (biosKey);
  589. }
  590. return info;
  591. }
  592. BOOLEAN
  593. PnPBiosCheckForExclusion(
  594. IN EXCLUDED_PNPNODE const*Exclusions,
  595. IN ULONG ExclusionCount,
  596. IN PWCHAR PnpDeviceName,
  597. IN PWCHAR PnpCompatIds
  598. )
  599. {
  600. PWCHAR idPtr;
  601. ULONG exclusionIndex;
  602. for (exclusionIndex = 0; exclusionIndex < ExclusionCount; exclusionIndex++) {
  603. idPtr = PnpDeviceName;
  604. if (RtlCompareMemory( idPtr,
  605. Exclusions[ exclusionIndex ].Id,
  606. Exclusions[ exclusionIndex ].IdLength) != Exclusions[ exclusionIndex ].IdLength ) {
  607. idPtr = PnpCompatIds;
  608. if (idPtr != NULL) {
  609. while (*idPtr != '\0') {
  610. if (RtlCompareMemory( idPtr,
  611. Exclusions[ exclusionIndex ].Id,
  612. Exclusions[ exclusionIndex ].IdLength) == Exclusions[ exclusionIndex ].IdLength ) {
  613. break;
  614. }
  615. idPtr += 9;
  616. }
  617. if (*idPtr == '\0') {
  618. idPtr = NULL;
  619. }
  620. }
  621. }
  622. if (idPtr != NULL) {
  623. break;
  624. }
  625. }
  626. if (exclusionIndex < ExclusionCount) {
  627. return TRUE;
  628. }
  629. return FALSE;
  630. }
  631. NTSTATUS
  632. PnPBiosIoResourceListToCmResourceList(
  633. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
  634. OUT PCM_RESOURCE_LIST *CmResourceList,
  635. OUT ULONG *CmResourceListSize
  636. )
  637. /*++
  638. Routine Description:
  639. Converts an IO_RESOURCE_REQUIREMENTS_LIST into a CM_RESOURCE_LIST. This
  640. routine is used to convert the list of resources currently being used by a
  641. device into a form suitable for writing to the BootConfig registry value.
  642. Arguments:
  643. IoResourceList - Pointer to the input list.
  644. CmResourceList - Pointer to a PCM_RESOURCE_LIST which is set to the
  645. dynamically allocated and filled in using the data from IoResourceList.
  646. CmResourceListSize - Pointer to a variable which is set to the size in bytes
  647. of the dynamically allocated *CmResourceList.
  648. Return Value:
  649. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  650. --*/
  651. {
  652. PCM_PARTIAL_RESOURCE_LIST partialList;
  653. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  654. PIO_RESOURCE_DESCRIPTOR ioDescriptor;
  655. ULONG descIndex;
  656. //
  657. // Since this routine is only used to translate the allocated resources
  658. // returned by the PnP BIOS, we can assume that there is only 1 alternative
  659. // list
  660. //
  661. ASSERT(IoResourceList->AlternativeLists == 1);
  662. //
  663. // Calculate the size of the translated list and allocate memory for it.
  664. //
  665. *CmResourceListSize = sizeof(CM_RESOURCE_LIST) +
  666. (IoResourceList->AlternativeLists - 1) * sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
  667. (IoResourceList->List[0].Count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  668. *CmResourceList = ExAllocatePool( PagedPool, *CmResourceListSize );
  669. if (*CmResourceList == NULL) {
  670. *CmResourceListSize = 0;
  671. return STATUS_NO_MEMORY;
  672. }
  673. //
  674. // Copy the header info from the requirements list to the resource list.
  675. //
  676. (*CmResourceList)->Count = 1;
  677. (*CmResourceList)->List[ 0 ].InterfaceType = IoResourceList->InterfaceType;
  678. (*CmResourceList)->List[ 0 ].BusNumber = IoResourceList->BusNumber;
  679. partialList = &(*CmResourceList)->List[ 0 ].PartialResourceList;
  680. partialList->Version = IoResourceList->List[ 0 ].Version;
  681. partialList->Revision = IoResourceList->List[ 0 ].Revision;
  682. partialList->Count = 0;
  683. //
  684. // Translate each resource descriptor, currently we only handle ports,
  685. // memory, interrupts, and dma. The current implementation of the routine
  686. // which converts from ISA PnP Resource data to IO_RESOURCE_REQUIREMENTS
  687. // won't generate any other descriptor types given the data returned from
  688. // the BIOS.
  689. //
  690. partialDescriptor = &partialList->PartialDescriptors[ 0 ];
  691. for (descIndex = 0; descIndex < IoResourceList->List[ 0 ].Count; descIndex++) {
  692. ioDescriptor = &IoResourceList->List[ 0 ].Descriptors[ descIndex ];
  693. switch (ioDescriptor->Type) {
  694. case CmResourceTypePort:
  695. partialDescriptor->u.Port.Start = ioDescriptor->u.Port.MinimumAddress;
  696. partialDescriptor->u.Port.Length = ioDescriptor->u.Port.Length;
  697. break;
  698. case CmResourceTypeInterrupt:
  699. if (ioDescriptor->u.Interrupt.MinimumVector == (ULONG)2 ) {
  700. *CmResourceListSize -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  701. continue;
  702. }
  703. partialDescriptor->u.Interrupt.Level = ioDescriptor->u.Interrupt.MinimumVector;
  704. partialDescriptor->u.Interrupt.Vector = ioDescriptor->u.Interrupt.MinimumVector;
  705. partialDescriptor->u.Interrupt.Affinity = ~0ul;
  706. break;
  707. case CmResourceTypeMemory:
  708. partialDescriptor->u.Memory.Start = ioDescriptor->u.Memory.MinimumAddress;
  709. partialDescriptor->u.Memory.Length = ioDescriptor->u.Memory.Length;
  710. break;
  711. case CmResourceTypeDma:
  712. partialDescriptor->u.Dma.Channel = ioDescriptor->u.Dma.MinimumChannel;
  713. partialDescriptor->u.Dma.Port = 0;
  714. partialDescriptor->u.Dma.Reserved1 = 0;
  715. break;
  716. default:
  717. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  718. "Unexpected ResourceType (%d) in I/O Descriptor\n",
  719. ioDescriptor->Type) );
  720. #if DBG
  721. // DbgBreakPoint();
  722. #endif
  723. break;
  724. }
  725. partialDescriptor->Type = ioDescriptor->Type;
  726. partialDescriptor->ShareDisposition = ioDescriptor->ShareDisposition;
  727. partialDescriptor->Flags = ioDescriptor->Flags;
  728. partialDescriptor++;
  729. partialList->Count++;
  730. }
  731. return STATUS_SUCCESS;
  732. }
  733. NTSTATUS
  734. PnPBiosExtractCompatibleIDs(
  735. IN PUCHAR *DevNodeData,
  736. IN ULONG DevNodeDataLength,
  737. OUT PWSTR *CompatibleIDs,
  738. OUT ULONG *CompatibleIDsLength
  739. )
  740. {
  741. PWCHAR idPtr;
  742. PUCHAR currentPtr, endPtr;
  743. UCHAR tagName;
  744. ULONG increment;
  745. ULONG compatibleCount;
  746. endPtr = &(*DevNodeData)[DevNodeDataLength];
  747. compatibleCount = 0;
  748. for (currentPtr = *DevNodeData; currentPtr < endPtr; currentPtr += increment) {
  749. tagName = *currentPtr;
  750. if (tagName == TAG_COMPLETE_END) {
  751. break;
  752. }
  753. //
  754. // Determine the size of the BIOS resource descriptor
  755. //
  756. if (!(tagName & LARGE_RESOURCE_TAG)) {
  757. increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK);
  758. increment++; // length of small tag
  759. tagName &= SMALL_TAG_MASK;
  760. } else {
  761. increment = *(USHORT UNALIGNED *)(&currentPtr[1]);
  762. increment += 3; // length of large tag
  763. }
  764. if (tagName == TAG_COMPATIBLE_ID) {
  765. compatibleCount++;
  766. }
  767. }
  768. if (compatibleCount == 0) {
  769. *CompatibleIDs = NULL;
  770. *CompatibleIDsLength = 0;
  771. return STATUS_SUCCESS;
  772. }
  773. *CompatibleIDsLength = (compatibleCount * 9 + 1) * sizeof(WCHAR);
  774. *CompatibleIDs = ExAllocatePool(PagedPool, *CompatibleIDsLength);
  775. if (*CompatibleIDs == NULL) {
  776. *CompatibleIDsLength = 0;
  777. return STATUS_NO_MEMORY;
  778. }
  779. idPtr = *CompatibleIDs;
  780. for (currentPtr = *DevNodeData; currentPtr < endPtr; currentPtr += increment) {
  781. tagName = *currentPtr;
  782. if (tagName == TAG_COMPLETE_END) {
  783. break;
  784. }
  785. //
  786. // Determine the size of the BIOS resource descriptor
  787. //
  788. if (!(tagName & LARGE_RESOURCE_TAG)) {
  789. increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK);
  790. increment++; // length of small tag
  791. tagName &= SMALL_TAG_MASK;
  792. } else {
  793. increment = *(USHORT UNALIGNED *)(&currentPtr[1]);
  794. increment += 3; // length of large tag
  795. }
  796. if (tagName == TAG_COMPATIBLE_ID) {
  797. *idPtr = '*';
  798. PnPBiosExpandProductId(&currentPtr[1], &idPtr[1]);
  799. idPtr += 9;
  800. }
  801. }
  802. *idPtr++ = '\0'; // Extra NUL for REG_MULTI_SZ
  803. *CompatibleIDsLength = (ULONG)(idPtr - *CompatibleIDs) * sizeof(WCHAR);
  804. return STATUS_SUCCESS;
  805. }
  806. NTSTATUS
  807. PnPBiosTranslateInfo(
  808. IN VOID *BiosInfo,
  809. IN ULONG BiosInfoLength,
  810. OUT PBIOS_DEVNODE_INFO *DevNodeInfoList,
  811. OUT ULONG *NumberNodes
  812. )
  813. /*++
  814. Routine Description:
  815. Translates the devnode info retrieved from the BIOS.
  816. Arguments:
  817. BiosInfo - The PnP BIOS Installation Check Structure followed by the
  818. DevNode Structures reported by the BIOS. The detailed format is
  819. documented in the PnP BIOS spec.
  820. BiosInfoLength - Length in bytes of the block whose address is stored in
  821. BiosInfo.
  822. DevNodeInfoList - Dynamically allocated array of BIOS_DEVNODE_INFO
  823. structures, one for each device reported by the BIOS. The information
  824. supplied by the BIOS: device ID, type, current resources, and supported
  825. configurations is converted into a more useful format. For example the
  826. current resource allocation is converted from ISA PnP descriptors into
  827. an IO_RESOURCE_REQUIREMENTS_LIST and then into a CM_RESOURCE_LIST for
  828. storing into the BootConfig registry value.
  829. NumberNodes - Number of BIOS_DEVNODE_INFO elements pointed to by
  830. DevNodeInfoList.
  831. Return Value:
  832. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  833. --*/
  834. {
  835. PCM_PNP_BIOS_INSTALLATION_CHECK biosInstallCheck;
  836. PCM_PNP_BIOS_DEVICE_NODE devNodeHeader;
  837. PBIOS_DEVNODE_INFO devNodeInfo;
  838. PIO_RESOURCE_REQUIREMENTS_LIST tempResReqList;
  839. PUCHAR currentPtr;
  840. LONG lengthRemaining;
  841. LONG remainingNodeLength;
  842. ULONG numNodes;
  843. ULONG nodeIndex;
  844. PUCHAR configPtr;
  845. ULONG configListLength;
  846. NTSTATUS status;
  847. ULONG convertFlags = 0;
  848. PKEY_VALUE_FULL_INFORMATION fullValueInfo;
  849. //
  850. // Make sure the data is at least large enough to hold the BIOS Installation
  851. // Check structure and check that the PnP signature is correct.
  852. //
  853. if (BiosInfoLength < sizeof(CM_PNP_BIOS_INSTALLATION_CHECK)) {
  854. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  855. "BiosInfoLength (%d) is smaller than sizeof(PNPBIOS_INSTALLATION_CHECK) (%d)\n",
  856. BiosInfoLength,
  857. sizeof(CM_PNP_BIOS_INSTALLATION_CHECK)) );
  858. return STATUS_UNSUCCESSFUL;
  859. }
  860. biosInstallCheck = (PCM_PNP_BIOS_INSTALLATION_CHECK)BiosInfo;
  861. if (biosInstallCheck->Signature[0] != '$' ||
  862. biosInstallCheck->Signature[1] != 'P' ||
  863. biosInstallCheck->Signature[2] != 'n' ||
  864. biosInstallCheck->Signature[3] != 'P') {
  865. return STATUS_UNSUCCESSFUL;
  866. }
  867. //
  868. // First scan the data and count the devnodes to determine the size of our
  869. // allocated data structures.
  870. //
  871. currentPtr = (PUCHAR)BiosInfo + biosInstallCheck->Length;
  872. lengthRemaining = BiosInfoLength - biosInstallCheck->Length;
  873. for (numNodes = 0; lengthRemaining > sizeof(CM_PNP_BIOS_DEVICE_NODE); numNodes++) {
  874. devNodeHeader = (PCM_PNP_BIOS_DEVICE_NODE)currentPtr;
  875. if (devNodeHeader->Size > lengthRemaining) {
  876. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  877. "Node # %d, invalid size (%d), length remaining (%d)\n",
  878. devNodeHeader->Node,
  879. devNodeHeader->Size,
  880. lengthRemaining) );
  881. return STATUS_UNSUCCESSFUL;
  882. }
  883. currentPtr += devNodeHeader->Size;
  884. lengthRemaining -= devNodeHeader->Size;
  885. }
  886. //
  887. // Allocate the list of translated devnodes.
  888. //
  889. devNodeInfo = ExAllocatePool( PagedPool, numNodes * sizeof(BIOS_DEVNODE_INFO) );
  890. if (devNodeInfo == NULL) {
  891. return STATUS_NO_MEMORY;
  892. }
  893. //
  894. // Should we force all fixed IO decodes to 16bit?
  895. //
  896. fullValueInfo = PnPGetBiosInfoValue(DECODEINFO_VALUE_NAME);
  897. if (fullValueInfo) {
  898. if (fullValueInfo->Type == REG_DWORD &&
  899. fullValueInfo->DataLength == sizeof(ULONG) &&
  900. *(PULONG)((PUCHAR)fullValueInfo + fullValueInfo->DataOffset)) {
  901. convertFlags |= PPCONVERTFLAG_FORCE_FIXED_IO_16BIT_DECODE;
  902. }
  903. ExFreePool(fullValueInfo);
  904. }
  905. //
  906. // Now scan the data translating the info for each devnode into an entry in
  907. // our devNodeInfo array.
  908. //
  909. currentPtr = (PUCHAR)BiosInfo + biosInstallCheck->Length;
  910. lengthRemaining = BiosInfoLength - biosInstallCheck->Length;
  911. for (nodeIndex = 0; nodeIndex < numNodes; nodeIndex++) {
  912. devNodeHeader = (PCM_PNP_BIOS_DEVICE_NODE)currentPtr;
  913. if (devNodeHeader->Size > lengthRemaining) {
  914. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  915. "Node # %d, invalid size (%d), length remaining (%d)\n",
  916. devNodeHeader->Node,
  917. devNodeHeader->Size,
  918. lengthRemaining) );
  919. break;
  920. }
  921. //
  922. // We use the Product ID field as the DeviceID key name. So we insert
  923. // an initial asterisk so we don't have to copy and mangle it later.
  924. //
  925. devNodeInfo[nodeIndex].ProductId[0] = '*';
  926. PnPBiosExpandProductId((PUCHAR)&devNodeHeader->ProductId, &devNodeInfo[nodeIndex].ProductId[1]);
  927. devNodeInfo[nodeIndex].ProductId[9] = '\0'; // Extra NUL for REG_MULTI_SZ
  928. //
  929. // The handle is used as part of the Instance ID
  930. devNodeInfo[nodeIndex].Handle = devNodeHeader->Node;
  931. //
  932. // The type code and attributes aren't currently used but are copied
  933. // for completeness.
  934. //
  935. RtlCopyMemory( &devNodeInfo[nodeIndex].TypeCode,
  936. devNodeHeader->DeviceType,
  937. sizeof(devNodeInfo[nodeIndex].TypeCode) );
  938. devNodeInfo[nodeIndex].Attributes = devNodeHeader->DeviceAttributes;
  939. //
  940. // Replaces will eventually be set to the path of the Firmware
  941. // Enumerated devnode which duplicates this one (if a duplicate exists).
  942. //
  943. devNodeInfo[nodeIndex].Replaces = NULL;
  944. //
  945. // CompatibleIDs will be set to the list of compatible IDs.
  946. //
  947. devNodeInfo[nodeIndex].CompatibleIDs = NULL;
  948. //
  949. // Convert the allocated resources from ISA PnP resource descriptor
  950. // format to an IO_RESOURCE_REQUIREMENTS_LIST.
  951. //
  952. configPtr = currentPtr + sizeof(*devNodeHeader);
  953. remainingNodeLength = devNodeHeader->Size - sizeof(*devNodeHeader);
  954. devNodeInfo[nodeIndex].BootConfig = NULL;
  955. devNodeInfo[nodeIndex].FirmwareDisabled = FALSE;
  956. status = PpBiosResourcesToNtResources( 0, /* BusNumber */
  957. 0, /* SlotNumber */
  958. &configPtr, /* BiosData */
  959. convertFlags, /* ConvertFlags */
  960. &tempResReqList, /* ReturnedList */
  961. &configListLength); /* ReturnedLength */
  962. remainingNodeLength = devNodeHeader->Size - (LONG)(configPtr - (PUCHAR)devNodeHeader);
  963. if (NT_SUCCESS( status )) {
  964. if (tempResReqList != NULL) {
  965. PpFilterNtResource (
  966. devNodeInfo[nodeIndex].ProductId,
  967. tempResReqList
  968. );
  969. //
  970. // Now we need to convert from a IO_RESOURCE_REQUIREMENTS_LIST to a
  971. // CM_RESOURCE_LIST.
  972. //
  973. status = PnPBiosIoResourceListToCmResourceList( tempResReqList,
  974. &devNodeInfo[nodeIndex].BootConfig,
  975. &devNodeInfo[nodeIndex].BootConfigLength);
  976. status = PnPBiosCheckForHardwareDisabled(tempResReqList,&devNodeInfo[nodeIndex].FirmwareDisabled);
  977. ExFreePool( tempResReqList );
  978. }
  979. } else {
  980. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  981. "Error converting allocated resources for devnode # %d, status = %8.8X\n",
  982. devNodeInfo[nodeIndex].Handle,
  983. status) );
  984. }
  985. //
  986. // Convert the supported resource configurations from ISA PnP resource
  987. // descriptor format to an IO_RESOURCE_REQUIREMENTS_LIST.
  988. //
  989. status = PpBiosResourcesToNtResources( 0, /* BusNumber */
  990. 0, /* SlotNumber */
  991. &configPtr, /* BiosData */
  992. convertFlags | PPCONVERTFLAG_SET_RESTART_LCPRI, /* ConvertFlags */
  993. &devNodeInfo[nodeIndex].BasicConfig, /* ReturnedList */
  994. &devNodeInfo[nodeIndex].BasicConfigLength ); /* ReturnedLength */
  995. remainingNodeLength = devNodeHeader->Size - (LONG)(configPtr - (PUCHAR)devNodeHeader);
  996. if (!NT_SUCCESS( status )) {
  997. devNodeInfo[nodeIndex].BasicConfig = NULL;
  998. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  999. "Error converting allowed resources for devnode # %d, status = %8.8X\n",
  1000. devNodeInfo[nodeIndex].Handle,
  1001. status) );
  1002. } else {
  1003. PpFilterNtResource (
  1004. devNodeInfo[nodeIndex].ProductId,
  1005. devNodeInfo[nodeIndex].BasicConfig
  1006. );
  1007. }
  1008. //
  1009. // Convert the list of compatible IDs if present
  1010. //
  1011. ASSERT(remainingNodeLength >= 0);
  1012. status = PnPBiosExtractCompatibleIDs( &configPtr, // BiosData
  1013. (ULONG)remainingNodeLength,
  1014. &devNodeInfo[nodeIndex].CompatibleIDs,
  1015. &devNodeInfo[nodeIndex].CompatibleIDsLength );
  1016. currentPtr += devNodeHeader->Size;
  1017. lengthRemaining -= devNodeHeader->Size;
  1018. }
  1019. *DevNodeInfoList = devNodeInfo;
  1020. *NumberNodes = numNodes;
  1021. return STATUS_SUCCESS;
  1022. }
  1023. LONG
  1024. PnPBiosFindMatchingDevNode(
  1025. IN PWCHAR MapperName,
  1026. IN PCM_RESOURCE_LIST ResourceList,
  1027. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  1028. IN ULONG NumberNodes
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. Given a list of resources this routine finds an entry in the
  1033. DevNodeInfoList whose BootConfig resources match. A match is defined as
  1034. having at least overlapping I/O Ports or Memory Ranges. If ResourceList doesn't
  1035. include any I/O Ports or Memory Ranges then a match is defined as exactly
  1036. the same interrupts and/or DMA channels.
  1037. This routine is used to find PnP BIOS reported devices which match devices
  1038. created by the Firmware Mapper.
  1039. Arguments:
  1040. ResourceList - Pointer to CM_RESOURCE_LIST describing the resources
  1041. currently used by the device for which a match is being searched.
  1042. DevNodeInfoList - Array of BIOS_DEVNODE_INFO structures, one for each device
  1043. reported by the BIOS.
  1044. NumberNodes - Number of BIOS_DEVNODE_INFO elements pointed to by
  1045. DevNodeInfoList.
  1046. Return Value:
  1047. Index of the entry in DevNodeInfoList whose BootConfig matches the resources
  1048. listed in ResourceList. If no matching entry is found then -1 is returned.
  1049. --*/
  1050. {
  1051. PCM_PARTIAL_RESOURCE_LIST sourceList;
  1052. PCM_PARTIAL_RESOURCE_LIST targetList;
  1053. PCM_PARTIAL_RESOURCE_DESCRIPTOR sourceDescriptor;
  1054. PCM_PARTIAL_RESOURCE_DESCRIPTOR targetDescriptor;
  1055. ULONG nodeIndex, sourceIndex, targetIndex;
  1056. LONG firstMatch = -1;
  1057. LONG bestMatch = -1;
  1058. ULONG numResourcesMatch;
  1059. ULONG score, possibleScore, bestScore = 0;
  1060. PWCHAR idPtr;
  1061. BOOLEAN idsMatch;
  1062. BOOLEAN bestIdsMatch = FALSE;
  1063. #if DEBUG_DUP_MATCH
  1064. CHAR sourceMapping[256];
  1065. CHAR targetMapping[256];
  1066. #endif
  1067. //
  1068. // In order to simplify the problem we assume there is only one list. This
  1069. // assumption holds true in the BootConfig structures generated by the
  1070. // current firmware mapper.
  1071. //
  1072. ASSERT( ResourceList->Count == 1 );
  1073. sourceList = &ResourceList->List[0].PartialResourceList;
  1074. #if DEBUG_DUP_MATCH
  1075. //
  1076. // For debugging purposes we keep track of which resource entries map to
  1077. // each other. These relationships are stored in a fixed CHAR array, thus
  1078. // the restriction on the number of descriptors.
  1079. //
  1080. ASSERT( sourceList->Count < 255 );
  1081. #endif
  1082. //
  1083. // Loop through each devnode and try and match it to the source resource
  1084. // list.
  1085. //
  1086. for (nodeIndex = 0; nodeIndex < NumberNodes; nodeIndex++) {
  1087. if (DevNodeInfoList[ nodeIndex ].BootConfig == NULL) {
  1088. continue;
  1089. }
  1090. //
  1091. // We found at least one potential match. Let's double check if
  1092. // the PNP ids also match. We use a lack of ID match to disqualify
  1093. // entries which don't match at least I/O ports or memory.
  1094. //
  1095. idPtr = DevNodeInfoList[ nodeIndex ].ProductId;
  1096. if (RtlCompareMemory( idPtr, MapperName, 12 ) != 12) {
  1097. idPtr = DevNodeInfoList[ nodeIndex ].CompatibleIDs;
  1098. if (idPtr != NULL) {
  1099. while (*idPtr != '\0') {
  1100. if (RtlCompareMemory( idPtr, MapperName, 12 ) == 12) {
  1101. break;
  1102. }
  1103. idPtr += 9;
  1104. }
  1105. if (*idPtr == '\0') {
  1106. idPtr = NULL;
  1107. }
  1108. }
  1109. }
  1110. idsMatch = (BOOLEAN)(idPtr != NULL);
  1111. ASSERT( DevNodeInfoList[ nodeIndex ].BootConfig->Count == 1 );
  1112. targetList = &DevNodeInfoList[ nodeIndex ].BootConfig->List[0].PartialResourceList;
  1113. #if DEBUG_DUP_MATCH
  1114. RtlFillMemory( sourceMapping, sizeof(sourceMapping), -1 );
  1115. RtlFillMemory( targetMapping, sizeof(targetMapping), -1 );
  1116. #endif
  1117. numResourcesMatch = 0;
  1118. possibleScore = 0;
  1119. score = 0;
  1120. //
  1121. // Loop through each source descriptor (resource) and try and match it
  1122. // to one of this devnode's descriptors.
  1123. //
  1124. for (sourceIndex = 0; sourceIndex < sourceList->Count; sourceIndex++) {
  1125. sourceDescriptor = &sourceList->PartialDescriptors[sourceIndex];
  1126. //
  1127. // We are recalculating the possible score unnecessarily each time
  1128. // we process a devnode. We might save a small amount of time by
  1129. // looping through the source descriptors once at the beginning but
  1130. // its not clear it would make all that much difference given the
  1131. // few devices reported by the BIOS.
  1132. //
  1133. switch (sourceDescriptor->Type) {
  1134. case CmResourceTypePort:
  1135. possibleScore += 0x1100;
  1136. break;
  1137. case CmResourceTypeInterrupt:
  1138. possibleScore += 0x0001;
  1139. break;
  1140. case CmResourceTypeMemory:
  1141. possibleScore += 0x1100;
  1142. break;
  1143. case CmResourceTypeDma:
  1144. possibleScore += 0x0010;
  1145. break;
  1146. default:
  1147. continue;
  1148. }
  1149. //
  1150. // Try to find a resource in the target devnode which matches the
  1151. // current source resource.
  1152. //
  1153. for (targetIndex = 0; targetIndex < targetList->Count; targetIndex++) {
  1154. targetDescriptor = &targetList->PartialDescriptors[targetIndex];
  1155. if (sourceDescriptor->Type == targetDescriptor->Type) {
  1156. switch (sourceDescriptor->Type) {
  1157. case CmResourceTypePort:
  1158. if ((sourceDescriptor->u.Port.Start.LowPart + sourceDescriptor->u.Port.Length) <=
  1159. targetDescriptor->u.Port.Start.LowPart ||
  1160. (targetDescriptor->u.Port.Start.LowPart + targetDescriptor->u.Port.Length) <=
  1161. sourceDescriptor->u.Port.Start.LowPart) {
  1162. continue;
  1163. }
  1164. if (sourceDescriptor->u.Port.Start.LowPart ==
  1165. targetDescriptor->u.Port.Start.LowPart &&
  1166. sourceDescriptor->u.Port.Length ==
  1167. targetDescriptor->u.Port.Length) {
  1168. score += 0x1100;
  1169. } else {
  1170. IopDbgPrint( (IOP_MAPPER_INFO_LEVEL,
  1171. "Overlapping port resources, source = %4.4X-%4.4X, target = %4.4X-%4.4X\n",
  1172. sourceDescriptor->u.Port.Start.LowPart,
  1173. sourceDescriptor->u.Port.Start.LowPart + sourceDescriptor->u.Port.Length - 1,
  1174. targetDescriptor->u.Port.Start.LowPart,
  1175. targetDescriptor->u.Port.Start.LowPart + targetDescriptor->u.Port.Length - 1) );
  1176. score += 0x1000;
  1177. }
  1178. break;
  1179. case CmResourceTypeInterrupt:
  1180. if (sourceDescriptor->u.Interrupt.Level !=
  1181. targetDescriptor->u.Interrupt.Level) {
  1182. continue;
  1183. }
  1184. score += 0x0001;
  1185. break;
  1186. case CmResourceTypeMemory:
  1187. if ((sourceDescriptor->u.Memory.Start.LowPart + sourceDescriptor->u.Memory.Length) <=
  1188. targetDescriptor->u.Memory.Start.LowPart ||
  1189. (targetDescriptor->u.Memory.Start.LowPart + targetDescriptor->u.Memory.Length) <=
  1190. sourceDescriptor->u.Memory.Start.LowPart) {
  1191. continue;
  1192. }
  1193. if (sourceDescriptor->u.Memory.Start.LowPart ==
  1194. targetDescriptor->u.Memory.Start.LowPart &&
  1195. sourceDescriptor->u.Memory.Length ==
  1196. targetDescriptor->u.Memory.Length) {
  1197. score += 0x1100;
  1198. } else {
  1199. score += 0x1000;
  1200. }
  1201. break;
  1202. case CmResourceTypeDma:
  1203. if (sourceDescriptor->u.Dma.Channel !=
  1204. targetDescriptor->u.Dma.Channel) {
  1205. continue;
  1206. }
  1207. score += 0x0010;
  1208. break;
  1209. }
  1210. break;
  1211. }
  1212. }
  1213. if (targetIndex < targetList->Count) {
  1214. #if DEBUG_DUP_MATCH
  1215. sourceMapping[sourceIndex] = (CHAR)targetIndex;
  1216. targetMapping[targetIndex] = (CHAR)sourceIndex;
  1217. #endif
  1218. numResourcesMatch++;
  1219. }
  1220. }
  1221. if (numResourcesMatch != 0) {
  1222. if (firstMatch == -1) {
  1223. firstMatch = nodeIndex;
  1224. }
  1225. if ((score > bestScore) || (score == bestScore && !bestIdsMatch && idsMatch)) {
  1226. bestScore = score;
  1227. bestMatch = nodeIndex;
  1228. bestIdsMatch = idsMatch;
  1229. }
  1230. }
  1231. }
  1232. if (bestMatch != -1) {
  1233. if (bestScore == possibleScore) {
  1234. IopDbgPrint( (IOP_MAPPER_INFO_LEVEL,
  1235. "Perfect match, score = %4.4X, possible = %4.4X, index = %d\n",
  1236. bestScore,
  1237. possibleScore,
  1238. bestMatch) );
  1239. if (possibleScore < 0x1000 && !bestIdsMatch) {
  1240. bestMatch = -1;
  1241. }
  1242. } else if (possibleScore > 0x1000 && bestScore >= 0x1000) {
  1243. IopDbgPrint( (IOP_MAPPER_INFO_LEVEL,
  1244. "Best match is close enough, score = %4.4X, possible = %4.4X, index = %d\n",
  1245. bestScore,
  1246. possibleScore,
  1247. bestMatch) );
  1248. } else {
  1249. IopDbgPrint( (IOP_MAPPER_INFO_LEVEL,
  1250. "Best match is less than threshold, score = %4.4X, possible = %4.4X, index = %d\n",
  1251. bestScore,
  1252. possibleScore,
  1253. bestMatch) );
  1254. bestMatch = -1;
  1255. }
  1256. }
  1257. return bestMatch;
  1258. }
  1259. NTSTATUS
  1260. PnPBiosEliminateDupes(
  1261. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  1262. IN ULONG NumberNodes
  1263. )
  1264. /*++
  1265. Routine Description:
  1266. This routine enumerates the Firmware Mapper generated devices under
  1267. Enum\Root. Those that match entries in DevNodeInfoList have their registry
  1268. key name stored in the DevNodeInfoList entry so that the Firmare Mapper
  1269. instance may be removed later.
  1270. Arguments:
  1271. DevNodeInfoList - Array of BIOS_DEVNODE_INFO structures, one for each device
  1272. reported by the BIOS.
  1273. NumberNodes - Number of BIOS_DEVNODE_INFO elements pointed to by
  1274. DevNodeInfoList.
  1275. Return Value:
  1276. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  1277. --*/
  1278. {
  1279. UNICODE_STRING enumRootKeyName, valueName;
  1280. HANDLE enumRootKey;
  1281. PKEY_BASIC_INFORMATION deviceBasicInfo = NULL;
  1282. ULONG deviceBasicInfoLength;
  1283. UNICODE_STRING deviceKeyName;
  1284. HANDLE deviceKey = NULL;
  1285. PKEY_BASIC_INFORMATION instanceBasicInfo = NULL;
  1286. ULONG instanceBasicInfoLength;
  1287. WCHAR logConfStr[DEFAULT_STRING_SIZE];
  1288. UNICODE_STRING logConfKeyName;
  1289. HANDLE logConfKey = NULL;
  1290. PKEY_VALUE_PARTIAL_INFORMATION valueInfo = NULL;
  1291. ULONG valueInfoLength;
  1292. ULONG returnedLength;
  1293. ULONG deviceIndex, instanceIndex;
  1294. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1295. PiWstrToUnicodeString(&enumRootKeyName, ENUMROOT_KEY_NAME);
  1296. status = IopOpenRegistryKeyEx( &enumRootKey,
  1297. NULL,
  1298. &enumRootKeyName,
  1299. KEY_READ
  1300. );
  1301. if (!NT_SUCCESS(status)) {
  1302. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1303. "Could not open registry key %S, status = %8.8X\n",
  1304. ENUMROOT_KEY_NAME,
  1305. status) );
  1306. return STATUS_UNSUCCESSFUL;
  1307. }
  1308. deviceBasicInfoLength = sizeof(KEY_BASIC_INFORMATION) + DEFAULT_STRING_SIZE;
  1309. deviceBasicInfo = ExAllocatePool(PagedPool, deviceBasicInfoLength);
  1310. instanceBasicInfoLength = sizeof(KEY_BASIC_INFORMATION) + DEFAULT_STRING_SIZE;
  1311. instanceBasicInfo = ExAllocatePool(PagedPool, instanceBasicInfoLength);
  1312. valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + DEFAULT_STRING_SIZE;
  1313. valueInfo = ExAllocatePool(PagedPool, valueInfoLength);
  1314. if (deviceBasicInfo != NULL && instanceBasicInfo != NULL && valueInfo != NULL) {
  1315. for (deviceIndex = 0; ; deviceIndex++) {
  1316. status = ZwEnumerateKey( enumRootKey,
  1317. deviceIndex,
  1318. KeyBasicInformation,
  1319. deviceBasicInfo,
  1320. deviceBasicInfoLength,
  1321. &returnedLength);
  1322. if (!NT_SUCCESS(status)) {
  1323. if (status == STATUS_BUFFER_TOO_SMALL ||
  1324. status == STATUS_BUFFER_OVERFLOW) {
  1325. continue;
  1326. } else if (status != STATUS_NO_MORE_ENTRIES) {
  1327. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1328. "Could not enumerate under key %S, status = %8.8X\n",
  1329. ENUMROOT_KEY_NAME,
  1330. status) );
  1331. } else {
  1332. status = STATUS_SUCCESS;
  1333. }
  1334. break;
  1335. }
  1336. if (deviceBasicInfo->Name[0] != '*') {
  1337. continue;
  1338. }
  1339. deviceBasicInfo->Name[ deviceBasicInfo->NameLength / 2 ] = L'\0';
  1340. RtlInitUnicodeString(&deviceKeyName, deviceBasicInfo->Name);
  1341. status = IopOpenRegistryKeyEx( &deviceKey,
  1342. enumRootKey,
  1343. &deviceKeyName,
  1344. KEY_READ
  1345. );
  1346. if (!NT_SUCCESS(status)) {
  1347. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1348. "Could not open registry key %S\\%S, status = %8.8X\n",
  1349. ENUMROOT_KEY_NAME,
  1350. deviceBasicInfo->Name,
  1351. status) );
  1352. break;
  1353. }
  1354. for (instanceIndex = 0; ; instanceIndex++) {
  1355. status = ZwEnumerateKey( deviceKey,
  1356. instanceIndex,
  1357. KeyBasicInformation,
  1358. instanceBasicInfo,
  1359. instanceBasicInfoLength,
  1360. &returnedLength);
  1361. if (!NT_SUCCESS(status)) {
  1362. if (status == STATUS_BUFFER_TOO_SMALL ||
  1363. status == STATUS_BUFFER_OVERFLOW) {
  1364. continue;
  1365. } else if (status != STATUS_NO_MORE_ENTRIES) {
  1366. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1367. "Could not enumerate under key %S\\%S, status = %8.8X\n",
  1368. ENUMROOT_KEY_NAME,
  1369. deviceBasicInfo->Name,
  1370. status) );
  1371. } else {
  1372. status = STATUS_SUCCESS;
  1373. }
  1374. break;
  1375. }
  1376. if (RtlCompareMemory( instanceBasicInfo->Name,
  1377. INSTANCE_ID_PREFIX,
  1378. sizeof(INSTANCE_ID_PREFIX) - sizeof(UNICODE_NULL)
  1379. ) == (sizeof(INSTANCE_ID_PREFIX) - sizeof(UNICODE_NULL))) {
  1380. continue;
  1381. }
  1382. instanceBasicInfo->Name[ instanceBasicInfo->NameLength / 2 ] = L'\0';
  1383. RtlCopyMemory( logConfStr,
  1384. instanceBasicInfo->Name,
  1385. instanceBasicInfo->NameLength );
  1386. logConfStr[ instanceBasicInfo->NameLength / 2 ] = L'\\';
  1387. RtlCopyMemory( &logConfStr[ instanceBasicInfo->NameLength / 2 + 1 ],
  1388. REGSTR_KEY_LOGCONF,
  1389. sizeof(REGSTR_KEY_LOGCONF) );
  1390. RtlInitUnicodeString( &logConfKeyName, logConfStr );
  1391. status = IopOpenRegistryKeyEx( &logConfKey,
  1392. deviceKey,
  1393. &logConfKeyName,
  1394. KEY_READ
  1395. );
  1396. if (!NT_SUCCESS(status)) {
  1397. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1398. "Could not open registry key %S\\%S\\%S, status = %8.8X\n",
  1399. ENUMROOT_KEY_NAME,
  1400. deviceBasicInfo->Name,
  1401. logConfStr,
  1402. status) );
  1403. continue;
  1404. }
  1405. PiWstrToUnicodeString( &valueName, REGSTR_VAL_BOOTCONFIG );
  1406. status = ZwQueryValueKey( logConfKey,
  1407. &valueName,
  1408. KeyValuePartialInformation,
  1409. valueInfo,
  1410. valueInfoLength,
  1411. &returnedLength );
  1412. if (!NT_SUCCESS(status)) {
  1413. if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW) {
  1414. ExFreePool( valueInfo );
  1415. valueInfoLength = returnedLength;
  1416. valueInfo = ExAllocatePool( PagedPool, valueInfoLength );
  1417. if (valueInfo != NULL) {
  1418. status = ZwQueryValueKey( logConfKey,
  1419. &valueName,
  1420. KeyValuePartialInformation,
  1421. valueInfo,
  1422. valueInfoLength,
  1423. &returnedLength );
  1424. } else {
  1425. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1426. "Error allocating memory for %S\\%S\\LogConf\\BootConfig value\n",
  1427. ENUMROOT_KEY_NAME,
  1428. deviceBasicInfo->Name) );
  1429. valueInfoLength = 0;
  1430. status = STATUS_NO_MEMORY;
  1431. break;
  1432. }
  1433. } else {
  1434. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1435. "Error retrieving %S\\%S\\LogConf\\BootConfig size, status = %8.8X\n",
  1436. ENUMROOT_KEY_NAME,
  1437. deviceBasicInfo->Name,
  1438. status) );
  1439. status = STATUS_UNSUCCESSFUL;
  1440. }
  1441. }
  1442. if (NT_SUCCESS( status )) {
  1443. PCM_RESOURCE_LIST resourceList;
  1444. LONG matchingIndex;
  1445. resourceList = (PCM_RESOURCE_LIST)valueInfo->Data;
  1446. matchingIndex = PnPBiosFindMatchingDevNode( deviceBasicInfo->Name,
  1447. resourceList,
  1448. DevNodeInfoList,
  1449. NumberNodes );
  1450. if (matchingIndex != -1) {
  1451. DevNodeInfoList[ matchingIndex ].Replaces = ExAllocatePool( PagedPool,
  1452. deviceBasicInfo->NameLength + instanceBasicInfo->NameLength + 2 * sizeof(UNICODE_NULL));
  1453. if (DevNodeInfoList[ matchingIndex ].Replaces != NULL) {
  1454. RtlCopyMemory( DevNodeInfoList[ matchingIndex ].Replaces,
  1455. deviceBasicInfo->Name,
  1456. deviceBasicInfo->NameLength );
  1457. DevNodeInfoList[ matchingIndex ].Replaces[ deviceBasicInfo->NameLength / 2 ] = '\\';
  1458. RtlCopyMemory( &DevNodeInfoList[ matchingIndex ].Replaces[ deviceBasicInfo->NameLength / 2 + 1 ],
  1459. instanceBasicInfo->Name,
  1460. instanceBasicInfo->NameLength );
  1461. DevNodeInfoList[ matchingIndex ].Replaces[ (deviceBasicInfo->NameLength + instanceBasicInfo->NameLength) / 2 + 1 ] = '\0';
  1462. IopDbgPrint( (IOP_MAPPER_INFO_LEVEL,
  1463. "Match found: %S\\%S%d replaces %S\n",
  1464. DevNodeInfoList[ matchingIndex ].ProductId,
  1465. INSTANCE_ID_PREFIX,
  1466. DevNodeInfoList[ matchingIndex ].Handle,
  1467. DevNodeInfoList[ matchingIndex ].Replaces) );
  1468. } else {
  1469. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1470. "Error allocating memory for %S\\%S%d\\Replaces\n",
  1471. DevNodeInfoList[ matchingIndex ].ProductId,
  1472. INSTANCE_ID_PREFIX,
  1473. DevNodeInfoList[ matchingIndex ].Handle) );
  1474. }
  1475. } else {
  1476. IopDbgPrint( (IOP_MAPPER_INFO_LEVEL,
  1477. "No matching PnP Bios DevNode found for FW Enumerated device %S\\%S\n",
  1478. deviceBasicInfo->Name,
  1479. instanceBasicInfo->Name) );
  1480. }
  1481. } else {
  1482. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1483. "Error retrieving %S\\%S\\%S\\BootConfig, status = %8.8X\n",
  1484. ENUMROOT_KEY_NAME,
  1485. deviceBasicInfo->Name,
  1486. logConfStr,
  1487. status) );
  1488. }
  1489. ZwClose(logConfKey);
  1490. logConfKey = NULL;
  1491. }
  1492. ZwClose(deviceKey);
  1493. deviceKey = NULL;
  1494. }
  1495. } else {
  1496. status = STATUS_NO_MEMORY;
  1497. }
  1498. if (valueInfo != NULL) {
  1499. ExFreePool(valueInfo);
  1500. }
  1501. if (instanceBasicInfo != NULL) {
  1502. ExFreePool(instanceBasicInfo);
  1503. }
  1504. if (deviceBasicInfo != NULL) {
  1505. ExFreePool(deviceBasicInfo);
  1506. }
  1507. if (logConfKey != NULL) {
  1508. ZwClose(logConfKey);
  1509. }
  1510. if (deviceKey != NULL) {
  1511. ZwClose(deviceKey);
  1512. }
  1513. ZwClose(enumRootKey);
  1514. return status;
  1515. }
  1516. PWCHAR
  1517. PnPBiosGetDescription(
  1518. IN PBIOS_DEVNODE_INFO DevNodeInfoEntry
  1519. )
  1520. {
  1521. ULONG class, subClass;
  1522. LONG index;
  1523. CLASSDATA const*classDescriptions;
  1524. LONG descriptionCount;
  1525. class = DevNodeInfoEntry->TypeCode[0];
  1526. subClass = (DevNodeInfoEntry->TypeCode[1] << 8) | DevNodeInfoEntry->TypeCode[2];
  1527. if (class > 0 && class < CLASSLIST_COUNT) {
  1528. classDescriptions = ClassDescriptionsList[ class ].Descriptions;
  1529. descriptionCount = ClassDescriptionsList[ class ].Count;
  1530. //
  1531. // The last description entry is the default so there is no use
  1532. // comparing it, if we get that far just use it.
  1533. //
  1534. for (index = 0; index < (descriptionCount - 1); index++) {
  1535. if (subClass == classDescriptions[ index ].Value) {
  1536. break;
  1537. }
  1538. }
  1539. return classDescriptions[ index ].Description;
  1540. }
  1541. return DEFAULT_DEVICE_DESCRIPTION;
  1542. }
  1543. NTSTATUS
  1544. PnPBiosCopyDeviceParamKey(
  1545. IN HANDLE EnumRootKey,
  1546. IN PWCHAR SourcePath,
  1547. IN PWCHAR DestinationPath
  1548. )
  1549. /*++
  1550. Routine Description:
  1551. Copy the Device Parameters key from the firmware mapper node in
  1552. DevNodeInfo->Replaces to the BIOS mapper node represented by DevNodeInfo.
  1553. Arguments:
  1554. EnumRootKey - Handle to Enum\Root.
  1555. SourcePath - Instance path of FW Mapper node relative to Enum\Root.
  1556. DestinationKey - Handle to destination instance key.
  1557. Return Value:
  1558. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  1559. --*/
  1560. {
  1561. NTSTATUS status;
  1562. UNICODE_STRING sourceInstanceKeyName;
  1563. HANDLE sourceInstanceKey = NULL;
  1564. UNICODE_STRING deviceParamKeyName;
  1565. HANDLE sourceDeviceParamKey = NULL;
  1566. HANDLE destinationDeviceParamKey = NULL;
  1567. UNICODE_STRING destinationInstanceKeyName;
  1568. PKEY_VALUE_FULL_INFORMATION valueFullInfo = NULL;
  1569. ULONG valueFullInfoLength;
  1570. ULONG resultLength;
  1571. UNICODE_STRING valueName;
  1572. ULONG index;
  1573. RtlInitUnicodeString( &sourceInstanceKeyName, SourcePath );
  1574. status = IopOpenRegistryKeyEx( &sourceInstanceKey,
  1575. EnumRootKey,
  1576. &sourceInstanceKeyName,
  1577. KEY_ALL_ACCESS
  1578. );
  1579. if (!NT_SUCCESS(status)) {
  1580. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1581. "PnPBiosCopyDeviceParamKey() - Could not open source instance key %S, status = %8.8X\n",
  1582. SourcePath,
  1583. status) );
  1584. return status;
  1585. }
  1586. PiWstrToUnicodeString(&deviceParamKeyName, REGSTR_KEY_DEVICEPARAMETERS);
  1587. status = IopOpenRegistryKeyEx( &sourceDeviceParamKey,
  1588. sourceInstanceKey,
  1589. &deviceParamKeyName,
  1590. KEY_ALL_ACCESS
  1591. );
  1592. if (!NT_SUCCESS(status)) {
  1593. if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
  1594. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1595. "PnPBiosCopyDeviceParamKey() - Could not open source device parameter key %S\\%S, status = %8.8X\n",
  1596. SourcePath,
  1597. deviceParamKeyName.Buffer,
  1598. status) );
  1599. }
  1600. goto Cleanup;
  1601. }
  1602. RtlInitUnicodeString(&destinationInstanceKeyName, DestinationPath);
  1603. status = IopOpenDeviceParametersSubkey( &destinationDeviceParamKey,
  1604. EnumRootKey,
  1605. &destinationInstanceKeyName,
  1606. KEY_ALL_ACCESS );
  1607. if (!NT_SUCCESS(status)) {
  1608. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1609. "PnPBiosCopyDeviceParamKey() - Could not open destination device parameter key %S\\%S, status = %8.8X\n",
  1610. DestinationPath,
  1611. REGSTR_KEY_DEVICEPARAMETERS,
  1612. status) );
  1613. goto Cleanup;
  1614. }
  1615. valueFullInfoLength = sizeof(KEY_VALUE_FULL_INFORMATION) + DEFAULT_STRING_SIZE + DEFAULT_VALUE_SIZE;
  1616. valueFullInfo = ExAllocatePool(PagedPool, valueFullInfoLength);
  1617. if (valueFullInfo == NULL) {
  1618. goto Cleanup;
  1619. }
  1620. for (index = 0; ; index++) {
  1621. status = ZwEnumerateValueKey( sourceDeviceParamKey,
  1622. index,
  1623. KeyValueFullInformation,
  1624. valueFullInfo,
  1625. valueFullInfoLength,
  1626. &resultLength );
  1627. if (NT_SUCCESS(status)) {
  1628. UNICODE_STRING sourcePathString;
  1629. UNICODE_STRING serialPrefixString;
  1630. UNICODE_STRING portNameString;
  1631. valueName.Length = (USHORT)valueFullInfo->NameLength;
  1632. valueName.MaximumLength = valueName.Length;
  1633. valueName.Buffer = valueFullInfo->Name;
  1634. RtlInitUnicodeString(&sourcePathString, SourcePath);
  1635. PiWstrToUnicodeString(&serialPrefixString, L"*PNP0501");
  1636. if (sourcePathString.Length > serialPrefixString.Length) {
  1637. sourcePathString.Length = serialPrefixString.Length;
  1638. }
  1639. if (RtlCompareUnicodeString(&sourcePathString, &serialPrefixString, TRUE) == 0) {
  1640. PiWstrToUnicodeString(&portNameString, L"DosDeviceName");
  1641. if (valueName.Length == 16 &&
  1642. RtlCompareUnicodeString(&valueName, &portNameString, TRUE) == 0) {
  1643. // ComPortDBRemove(SourcePath, &unicodeValue);
  1644. ComPortDBAdd(destinationDeviceParamKey, (PWSTR)((PUCHAR)valueFullInfo + valueFullInfo->DataOffset));
  1645. continue;
  1646. }
  1647. }
  1648. status = ZwSetValueKey( destinationDeviceParamKey,
  1649. &valueName,
  1650. valueFullInfo->TitleIndex,
  1651. valueFullInfo->Type,
  1652. (PUCHAR)valueFullInfo + valueFullInfo->DataOffset,
  1653. valueFullInfo->DataLength );
  1654. } else {
  1655. if (status == STATUS_BUFFER_OVERFLOW) {
  1656. ExFreePool( valueFullInfo );
  1657. valueFullInfoLength = resultLength;
  1658. valueFullInfo = ExAllocatePool(PagedPool, valueFullInfoLength);
  1659. if (valueFullInfo == NULL) {
  1660. status = STATUS_NO_MEMORY;
  1661. } else {
  1662. index--;
  1663. continue;
  1664. }
  1665. } else if (status != STATUS_NO_MORE_ENTRIES) {
  1666. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1667. "Could not enumerate under key %S\\%S, status = %8.8X\n",
  1668. SourcePath,
  1669. deviceParamKeyName.Buffer,
  1670. status) );
  1671. } else {
  1672. status = STATUS_SUCCESS;
  1673. }
  1674. break;
  1675. }
  1676. }
  1677. Cleanup:
  1678. if (sourceInstanceKey != NULL) {
  1679. ZwClose( sourceInstanceKey );
  1680. }
  1681. if (sourceDeviceParamKey != NULL) {
  1682. ZwClose( sourceDeviceParamKey );
  1683. }
  1684. if (destinationDeviceParamKey != NULL) {
  1685. ZwClose( destinationDeviceParamKey );
  1686. }
  1687. if (valueFullInfo != NULL) {
  1688. ExFreePool( valueFullInfo );
  1689. }
  1690. return status;
  1691. }
  1692. NTSTATUS
  1693. PnPBiosWriteInfo(
  1694. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  1695. IN ULONG NumberNodes
  1696. )
  1697. /*++
  1698. Routine Description:
  1699. Creates an entry under Enum\Root for each DevNodeInfoList element. Also
  1700. removes any duplicate entries which were created by the Firmware Mapper.
  1701. Note: Currently entries for the Keyboard, Mouse, and PCI bus are ignored.
  1702. Arguments:
  1703. DevNodeInfoList - Array of BIOS_DEVNODE_INFO structures, one for each device
  1704. reported by the BIOS.
  1705. NumberNodes - Number of BIOS_DEVNODE_INFO elements pointed to by
  1706. DevNodeInfoList.
  1707. Return Value:
  1708. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  1709. --*/
  1710. {
  1711. PKEY_VALUE_FULL_INFORMATION excludeList=NULL;
  1712. UNICODE_STRING enumRootKeyName;
  1713. HANDLE enumRootKey;
  1714. WCHAR instanceNameStr[DEFAULT_STRING_SIZE];
  1715. UNICODE_STRING instanceKeyName;
  1716. HANDLE instanceKey;
  1717. UNICODE_STRING controlKeyName;
  1718. HANDLE controlKey;
  1719. UNICODE_STRING logConfKeyName;
  1720. HANDLE logConfKey;
  1721. UNICODE_STRING valueName;
  1722. ULONG dwordValue;
  1723. ULONG disposition;
  1724. PWCHAR descriptionStr;
  1725. ULONG descriptionStrLength;
  1726. ULONG nodeIndex;
  1727. NTSTATUS status;
  1728. BOOLEAN isNewDevice;
  1729. PCHAR ids;
  1730. PiWstrToUnicodeString(&enumRootKeyName, ENUMROOT_KEY_NAME);
  1731. status = IopOpenRegistryKeyEx( &enumRootKey,
  1732. NULL,
  1733. &enumRootKeyName,
  1734. KEY_ALL_ACCESS
  1735. );
  1736. if (!NT_SUCCESS(status)) {
  1737. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1738. "Could not open registry key %S, status = %8.8X\n",
  1739. ENUMROOT_KEY_NAME,
  1740. status) );
  1741. return STATUS_UNSUCCESSFUL;
  1742. }
  1743. //
  1744. // Reasons why a node might be excluded (i.e not enumerated)
  1745. // * included in ExcludedDevices array (non-conditional)
  1746. // * included in CCS\Control\BiosInfo\PnpBios\DisableNodes via biosinfo.inf
  1747. // * resources are disabled and device is included in the
  1748. // ExcludeIfDisabled array
  1749. excludeList = PnPGetBiosInfoValue(DISABLENODES_VALUE_NAME);
  1750. for (nodeIndex = 0; nodeIndex < NumberNodes; nodeIndex++) {
  1751. //
  1752. // Check if this node is in the 'ignore on this machine' list.
  1753. //
  1754. if ( excludeList &&
  1755. PnPBiosIgnoreNode( &DevNodeInfoList[ nodeIndex ].ProductId[1],
  1756. (PWCHAR)((PUCHAR)excludeList+excludeList->DataOffset))) {
  1757. continue;
  1758. }
  1759. // Checking for nodes we always exclude
  1760. if ( PnPBiosCheckForExclusion( ExcludedDevices,
  1761. EXCLUDED_DEVICES_COUNT,
  1762. DevNodeInfoList[ nodeIndex ].ProductId,
  1763. DevNodeInfoList[ nodeIndex ].CompatibleIDs)) {
  1764. //
  1765. // If we are skipping the device, we need to first copy the decode
  1766. // info that the BIOS supplied to the ntdetected device's Boot
  1767. // Config which was generated by the FW mapper.
  1768. //
  1769. PnPBiosCopyIoDecode( enumRootKey, &DevNodeInfoList[ nodeIndex ] );
  1770. //
  1771. // Skip excluded devices, ie busses, mice and keyboards for now.
  1772. //
  1773. continue;
  1774. }
  1775. // Checking for nodes we exclude if disabled
  1776. if ( DevNodeInfoList[ nodeIndex ].FirmwareDisabled &&
  1777. PnPBiosCheckForExclusion( ExcludeIfDisabled,
  1778. EXCLUDE_DISABLED_COUNT,
  1779. DevNodeInfoList[ nodeIndex ].ProductId,
  1780. NULL)) {
  1781. continue;
  1782. }
  1783. swprintf( instanceNameStr,
  1784. L"%s\\%s%d",
  1785. DevNodeInfoList[ nodeIndex ].ProductId,
  1786. INSTANCE_ID_PREFIX,
  1787. DevNodeInfoList[ nodeIndex ].Handle );
  1788. RtlInitUnicodeString( &instanceKeyName, instanceNameStr );
  1789. status = IopCreateRegistryKeyEx( &instanceKey,
  1790. enumRootKey,
  1791. &instanceKeyName,
  1792. KEY_ALL_ACCESS,
  1793. REG_OPTION_NON_VOLATILE,
  1794. &disposition
  1795. );
  1796. if (NT_SUCCESS(status)) {
  1797. //
  1798. // If the key already exists because it was explicitly migrated
  1799. // during textmode setup, we should still consider it a "new key".
  1800. //
  1801. if (disposition != REG_CREATED_NEW_KEY) {
  1802. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1803. UNICODE_STRING unicodeString;
  1804. status = IopGetRegistryValue(instanceKey,
  1805. REGSTR_VALUE_MIGRATED,
  1806. &keyValueInformation);
  1807. if (NT_SUCCESS(status)) {
  1808. if ((keyValueInformation->Type == REG_DWORD) &&
  1809. (keyValueInformation->DataLength == sizeof(ULONG)) &&
  1810. ((*(PULONG)KEY_VALUE_DATA(keyValueInformation)) != 0)) {
  1811. disposition = REG_CREATED_NEW_KEY;
  1812. }
  1813. ExFreePool(keyValueInformation);
  1814. PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_MIGRATED);
  1815. ZwDeleteValueKey(instanceKey, &unicodeString);
  1816. }
  1817. }
  1818. isNewDevice = (BOOLEAN)(disposition == REG_CREATED_NEW_KEY);
  1819. if (isNewDevice) {
  1820. PiWstrToUnicodeString( &valueName, L"DeviceDesc" );
  1821. descriptionStr = PnPBiosGetDescription( &DevNodeInfoList[ nodeIndex ] );
  1822. descriptionStrLength = (ULONG)(wcslen(descriptionStr) * 2 + sizeof(UNICODE_NULL));
  1823. status = ZwSetValueKey( instanceKey,
  1824. &valueName,
  1825. 0,
  1826. REG_SZ,
  1827. descriptionStr,
  1828. descriptionStrLength );
  1829. }
  1830. PiWstrToUnicodeString( &valueName, REGSTR_VAL_FIRMWAREIDENTIFIED );
  1831. dwordValue = 1;
  1832. status = ZwSetValueKey( instanceKey,
  1833. &valueName,
  1834. 0,
  1835. REG_DWORD,
  1836. &dwordValue,
  1837. sizeof(dwordValue) );
  1838. if (isNewDevice) {
  1839. PiWstrToUnicodeString( &valueName, REGSTR_VALUE_HARDWAREID);
  1840. status = ZwSetValueKey( instanceKey,
  1841. &valueName,
  1842. 0,
  1843. REG_MULTI_SZ,
  1844. DevNodeInfoList[ nodeIndex ].ProductId,
  1845. sizeof(DevNodeInfoList[nodeIndex].ProductId));
  1846. if (DevNodeInfoList[ nodeIndex ].CompatibleIDs != NULL) {
  1847. PiWstrToUnicodeString( &valueName, REGSTR_VALUE_COMPATIBLEIDS);
  1848. status = ZwSetValueKey( instanceKey,
  1849. &valueName,
  1850. 0,
  1851. REG_MULTI_SZ,
  1852. DevNodeInfoList[ nodeIndex ].CompatibleIDs,
  1853. DevNodeInfoList[ nodeIndex ].CompatibleIDsLength);
  1854. }
  1855. }
  1856. PiWstrToUnicodeString( &valueName, L"Replaces" );
  1857. if (DevNodeInfoList[ nodeIndex ].Replaces != NULL) {
  1858. status = ZwSetValueKey( instanceKey,
  1859. &valueName,
  1860. 0,
  1861. REG_SZ,
  1862. DevNodeInfoList[ nodeIndex ].Replaces,
  1863. (ULONG)(wcslen(DevNodeInfoList[ nodeIndex ].Replaces) * 2 + sizeof(UNICODE_NULL)) );
  1864. } else if (!isNewDevice) {
  1865. status = ZwDeleteValueKey( instanceKey,
  1866. &valueName );
  1867. }
  1868. PiWstrToUnicodeString( &controlKeyName, REGSTR_KEY_DEVICECONTROL );
  1869. status = IopCreateRegistryKeyEx( &controlKey,
  1870. instanceKey,
  1871. &controlKeyName,
  1872. KEY_ALL_ACCESS,
  1873. REG_OPTION_VOLATILE,
  1874. NULL
  1875. );
  1876. if (NT_SUCCESS(status)) {
  1877. PiWstrToUnicodeString( &valueName, REGSTR_VAL_FIRMWAREMEMBER );
  1878. dwordValue = 1;
  1879. status = ZwSetValueKey( controlKey,
  1880. &valueName,
  1881. 0,
  1882. REG_DWORD,
  1883. &dwordValue,
  1884. sizeof(dwordValue) );
  1885. PiWstrToUnicodeString( &valueName, L"PnpBiosDeviceHandle" );
  1886. dwordValue = DevNodeInfoList[ nodeIndex ].Handle;
  1887. status = ZwSetValueKey( controlKey,
  1888. &valueName,
  1889. 0,
  1890. REG_DWORD,
  1891. &dwordValue,
  1892. sizeof(dwordValue) );
  1893. PiWstrToUnicodeString( &valueName, REGSTR_VAL_FIRMWAREDISABLED );
  1894. dwordValue = DevNodeInfoList[ nodeIndex ].FirmwareDisabled;
  1895. status = ZwSetValueKey( controlKey,
  1896. &valueName,
  1897. 0,
  1898. REG_DWORD,
  1899. &dwordValue,
  1900. sizeof(dwordValue) );
  1901. PiWstrToUnicodeString( &valueName, L"PnpBiosDeviceHandle" );
  1902. dwordValue = DevNodeInfoList[ nodeIndex ].Handle;
  1903. ZwClose( controlKey );
  1904. } else {
  1905. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1906. "Could not open registry key %S\\%S\\%S\\Control, status = %8.8X\n",
  1907. ENUMROOT_KEY_NAME,
  1908. DevNodeInfoList[ nodeIndex ].ProductId,
  1909. instanceNameStr,
  1910. status) );
  1911. ZwClose( instanceKey );
  1912. status = STATUS_UNSUCCESSFUL;
  1913. goto Cleanup;
  1914. }
  1915. PiWstrToUnicodeString( &logConfKeyName, REGSTR_KEY_LOGCONF );
  1916. status = IopCreateRegistryKeyEx( &logConfKey,
  1917. instanceKey,
  1918. &logConfKeyName,
  1919. KEY_ALL_ACCESS,
  1920. REG_OPTION_NON_VOLATILE,
  1921. NULL
  1922. );
  1923. if (NT_SUCCESS(status)) {
  1924. if (DevNodeInfoList[ nodeIndex ].BootConfig != NULL) {
  1925. PiWstrToUnicodeString(&valueName, REGSTR_VAL_BOOTCONFIG);
  1926. status = ZwSetValueKey( logConfKey,
  1927. &valueName,
  1928. 0,
  1929. REG_RESOURCE_LIST,
  1930. DevNodeInfoList[ nodeIndex ].BootConfig,
  1931. DevNodeInfoList[ nodeIndex ].BootConfigLength );
  1932. }
  1933. if (DevNodeInfoList[ nodeIndex ].BasicConfig != NULL) {
  1934. PiWstrToUnicodeString( &valueName, REGSTR_VAL_BASICCONFIGVECTOR );
  1935. status = ZwSetValueKey( logConfKey,
  1936. &valueName,
  1937. 0,
  1938. REG_RESOURCE_REQUIREMENTS_LIST,
  1939. DevNodeInfoList[ nodeIndex ].BasicConfig,
  1940. DevNodeInfoList[ nodeIndex ].BasicConfigLength );
  1941. }
  1942. ZwClose( logConfKey );
  1943. } else {
  1944. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1945. "Could not open registry key %S\\%S\\%S\\LogConf, status = %8.8X\n",
  1946. ENUMROOT_KEY_NAME,
  1947. DevNodeInfoList[ nodeIndex ].ProductId,
  1948. instanceNameStr,
  1949. status) );
  1950. ZwClose( instanceKey );
  1951. status = STATUS_UNSUCCESSFUL;
  1952. goto Cleanup;
  1953. }
  1954. //
  1955. // If we are replacing a FW Mapper devnode we need to copy the
  1956. // Device Parameters subkey.
  1957. //
  1958. if (isNewDevice && DevNodeInfoList[ nodeIndex ].Replaces != NULL) {
  1959. status = PnPBiosCopyDeviceParamKey( enumRootKey,
  1960. DevNodeInfoList[ nodeIndex ].Replaces,
  1961. instanceNameStr );
  1962. }
  1963. ZwClose( instanceKey );
  1964. } else {
  1965. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  1966. "Could not open registry key %S\\%S\\%S, status = %8.8X\n",
  1967. ENUMROOT_KEY_NAME,
  1968. DevNodeInfoList[ nodeIndex ].ProductId,
  1969. instanceNameStr,
  1970. status) );
  1971. ZwClose( instanceKey );
  1972. status = STATUS_UNSUCCESSFUL;
  1973. goto Cleanup;
  1974. }
  1975. //
  1976. // Now check if the entry just written duplicates one written by the
  1977. // Firmware Mapper. If it does then remove the Firmware Mapper entry.
  1978. //
  1979. if (DevNodeInfoList[ nodeIndex ].Replaces != NULL) {
  1980. IopDeleteKeyRecursive( enumRootKey, DevNodeInfoList[ nodeIndex ].Replaces );
  1981. }
  1982. }
  1983. status = STATUS_SUCCESS;
  1984. Cleanup:
  1985. ZwClose( enumRootKey );
  1986. if (excludeList) {
  1987. ExFreePool (excludeList);
  1988. }
  1989. return status;
  1990. }
  1991. VOID
  1992. PnPBiosCopyIoDecode(
  1993. IN HANDLE EnumRootKey,
  1994. IN PBIOS_DEVNODE_INFO DevNodeInfo
  1995. )
  1996. {
  1997. WCHAR logConfKeyNameStr[DEFAULT_STRING_SIZE];
  1998. UNICODE_STRING logConfKeyName;
  1999. HANDLE logConfKey;
  2000. UNICODE_STRING valueName;
  2001. PKEY_VALUE_PARTIAL_INFORMATION valueInfo = NULL;
  2002. ULONG valueInfoLength;
  2003. ULONG returnedLength;
  2004. NTSTATUS status;
  2005. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  2006. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  2007. ULONG index;
  2008. USHORT flags;
  2009. if (DevNodeInfo->Replaces == NULL || DevNodeInfo->BootConfig == NULL) {
  2010. //
  2011. // If we didn't find a FW Mapper created devnode then there is nothing
  2012. // to do.
  2013. //
  2014. return;
  2015. }
  2016. //
  2017. // Search through the Boot Config and see if the device's I/O ports are
  2018. // 16 bit decode.
  2019. //
  2020. ASSERT(DevNodeInfo->BootConfig->Count == 1);
  2021. partialResourceList = &DevNodeInfo->BootConfig->List[0].PartialResourceList;
  2022. partialDescriptor = &partialResourceList->PartialDescriptors[0];
  2023. flags = (USHORT)~0;
  2024. #define DECODE_FLAGS ( CM_RESOURCE_PORT_10_BIT_DECODE | \
  2025. CM_RESOURCE_PORT_12_BIT_DECODE | \
  2026. CM_RESOURCE_PORT_16_BIT_DECODE | \
  2027. CM_RESOURCE_PORT_POSITIVE_DECODE )
  2028. for ( index = 0; index < partialResourceList->Count; index++ ) {
  2029. if (partialDescriptor->Type == CmResourceTypePort) {
  2030. if (flags == (USHORT)~0) {
  2031. flags = partialDescriptor->Flags & DECODE_FLAGS;
  2032. } else {
  2033. ASSERT(flags == (partialDescriptor->Flags & DECODE_FLAGS));
  2034. }
  2035. }
  2036. partialDescriptor++;
  2037. }
  2038. if (!(flags & (CM_RESOURCE_PORT_16_BIT_DECODE | CM_RESOURCE_PORT_POSITIVE_DECODE))) {
  2039. return;
  2040. }
  2041. swprintf( logConfKeyNameStr,
  2042. L"%s\\%s",
  2043. DevNodeInfo->Replaces,
  2044. REGSTR_KEY_LOGCONF
  2045. );
  2046. RtlInitUnicodeString( &logConfKeyName, logConfKeyNameStr );
  2047. status = IopCreateRegistryKeyEx( &logConfKey,
  2048. EnumRootKey,
  2049. &logConfKeyName,
  2050. KEY_ALL_ACCESS,
  2051. REG_OPTION_NON_VOLATILE,
  2052. NULL
  2053. );
  2054. if (!NT_SUCCESS(status)) {
  2055. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  2056. "Could not open registry key %S\\%S\\%S, status = %8.8X\n",
  2057. ENUMROOT_KEY_NAME,
  2058. DevNodeInfo->Replaces,
  2059. REGSTR_KEY_LOGCONF,
  2060. status) );
  2061. return;
  2062. }
  2063. valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + DEFAULT_STRING_SIZE;
  2064. valueInfo = ExAllocatePool(PagedPool, valueInfoLength);
  2065. if (valueInfo == NULL) {
  2066. ZwClose( logConfKey );
  2067. return;
  2068. }
  2069. PiWstrToUnicodeString( &valueName, REGSTR_VAL_BOOTCONFIG );
  2070. status = ZwQueryValueKey( logConfKey,
  2071. &valueName,
  2072. KeyValuePartialInformation,
  2073. valueInfo,
  2074. valueInfoLength,
  2075. &returnedLength);
  2076. if (!NT_SUCCESS(status)) {
  2077. if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_BUFFER_OVERFLOW) {
  2078. //
  2079. // The default buffer was too small, free it and reallocate
  2080. // it to the required size.
  2081. //
  2082. ExFreePool( valueInfo );
  2083. valueInfoLength = returnedLength;
  2084. valueInfo = ExAllocatePool( PagedPool, valueInfoLength );
  2085. if (valueInfo != NULL) {
  2086. status = ZwQueryValueKey( logConfKey,
  2087. &valueName,
  2088. KeyValuePartialInformation,
  2089. valueInfo,
  2090. valueInfoLength,
  2091. &returnedLength );
  2092. if (!NT_SUCCESS(status)) {
  2093. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  2094. "Could not query registry value %S\\%S\\LogConf\\BootConfig, status = %8.8X\n",
  2095. ENUMROOT_KEY_NAME,
  2096. DevNodeInfo->Replaces,
  2097. status) );
  2098. ExFreePool( valueInfo );
  2099. ZwClose( logConfKey );
  2100. return;
  2101. }
  2102. } else {
  2103. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  2104. "Could not allocate memory for BootConfig value\n"
  2105. ) );
  2106. ZwClose( logConfKey );
  2107. return;
  2108. }
  2109. }
  2110. }
  2111. partialResourceList = &((PCM_RESOURCE_LIST)valueInfo->Data)->List[0].PartialResourceList;
  2112. partialDescriptor = &partialResourceList->PartialDescriptors[0];
  2113. for ( index = 0; index < partialResourceList->Count; index++ ) {
  2114. if (partialDescriptor->Type == CmResourceTypePort) {
  2115. partialDescriptor->Flags &= ~DECODE_FLAGS;
  2116. partialDescriptor->Flags |= flags;
  2117. }
  2118. partialDescriptor++;
  2119. }
  2120. status = ZwSetValueKey( logConfKey,
  2121. &valueName,
  2122. 0,
  2123. REG_RESOURCE_LIST,
  2124. valueInfo->Data,
  2125. valueInfo->DataLength );
  2126. if (!NT_SUCCESS(status)) {
  2127. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  2128. "Could not set registry value %S\\%S\\LogConf\\BootConfig, status = %8.8X\n",
  2129. ENUMROOT_KEY_NAME,
  2130. DevNodeInfo->Replaces,
  2131. status) );
  2132. }
  2133. ExFreePool(valueInfo);
  2134. ZwClose(logConfKey);
  2135. }
  2136. NTSTATUS
  2137. PnPBiosCheckForHardwareDisabled(
  2138. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
  2139. IN OUT PBOOLEAN Disabled
  2140. )
  2141. /*++
  2142. Routine Description:
  2143. If this device has been assigned one or more resources, and each resource has a length of zero, then it is
  2144. hardware disabled.
  2145. Arguments:
  2146. IoResourceList - Resource obtained from BIOS that we're about to map to a CmResourceList
  2147. Disabled - Set to TRUE if the device is deemed to be disabled
  2148. Return Value:
  2149. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  2150. --*/
  2151. {
  2152. BOOLEAN ParsedResource = FALSE;
  2153. PIO_RESOURCE_DESCRIPTOR ioDescriptor;
  2154. ULONG descIndex;
  2155. //
  2156. // Since this routine is only used to translate the allocated resources
  2157. // returned by the PnP BIOS, we can assume that there is only 1 alternative
  2158. // list
  2159. //
  2160. ASSERT(IoResourceList->AlternativeLists == 1);
  2161. ASSERT(Disabled != NULL);
  2162. *Disabled = FALSE;
  2163. //
  2164. // Translate each resource descriptor, currently we only handle ports,
  2165. // memory, interrupts, and dma. The current implementation of the routine
  2166. // which converts from ISA PnP Resource data to IO_RESOURCE_REQUIREMENTS
  2167. // won't generate any other descriptor types given the data returned from
  2168. // the BIOS.
  2169. //
  2170. for (descIndex = 0; descIndex < IoResourceList->List[ 0 ].Count; descIndex++) {
  2171. ioDescriptor = &IoResourceList->List[ 0 ].Descriptors[ descIndex ];
  2172. switch (ioDescriptor->Type) {
  2173. case CmResourceTypePort:
  2174. if (ioDescriptor->u.Port.Length) {
  2175. return STATUS_SUCCESS;
  2176. }
  2177. ParsedResource = TRUE;
  2178. break;
  2179. case CmResourceTypeInterrupt:
  2180. if (ioDescriptor->u.Interrupt.MinimumVector != (ULONG)(-1)) {
  2181. return STATUS_SUCCESS;
  2182. }
  2183. ParsedResource = TRUE;
  2184. break;
  2185. case CmResourceTypeMemory:
  2186. if (ioDescriptor->u.Memory.Length) {
  2187. return STATUS_SUCCESS;
  2188. }
  2189. ParsedResource = TRUE;
  2190. break;
  2191. case CmResourceTypeDma:
  2192. if (ioDescriptor->u.Dma.MinimumChannel != (ULONG)(-1)) {
  2193. return STATUS_SUCCESS;
  2194. }
  2195. ParsedResource = TRUE;
  2196. break;
  2197. default:
  2198. IopDbgPrint( (IOP_MAPPER_ERROR_LEVEL,
  2199. "Unexpected ResourceType (%d) in I/O Descriptor\n",
  2200. ioDescriptor->Type) );
  2201. #if DBG
  2202. // DbgBreakPoint();
  2203. #endif
  2204. break;
  2205. }
  2206. }
  2207. if (ParsedResource) {
  2208. //
  2209. // at least one empty resource, no non-empty resources
  2210. //
  2211. *Disabled = TRUE;
  2212. }
  2213. return STATUS_SUCCESS;
  2214. }
  2215. NTSTATUS
  2216. PnPBiosFreeDevNodeInfo(
  2217. IN PBIOS_DEVNODE_INFO DevNodeInfoList,
  2218. IN ULONG NumberNodes
  2219. )
  2220. /*++
  2221. Routine Description:
  2222. Free the dynamically allocated DevNodeInfoList as well as any dynamically
  2223. allocated dependent structures.
  2224. Arguments:
  2225. DevNodeInfoList - Array of BIOS_DEVNODE_INFO structures, one for each device
  2226. reported by the BIOS.
  2227. NumberNodes - Number of BIOS_DEVNODE_INFO elements pointed to by
  2228. DevNodeInfoList.
  2229. Return Value:
  2230. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  2231. --*/
  2232. {
  2233. ULONG nodeIndex;
  2234. for (nodeIndex = 0; nodeIndex < NumberNodes; nodeIndex++) {
  2235. if (DevNodeInfoList[nodeIndex].Replaces != NULL) {
  2236. ExFreePool( DevNodeInfoList[nodeIndex].Replaces );
  2237. }
  2238. if (DevNodeInfoList[nodeIndex].CompatibleIDs != NULL) {
  2239. ExFreePool( DevNodeInfoList[nodeIndex].CompatibleIDs );
  2240. }
  2241. if (DevNodeInfoList[nodeIndex].BootConfig != NULL) {
  2242. ExFreePool( DevNodeInfoList[nodeIndex].BootConfig );
  2243. }
  2244. if (DevNodeInfoList[nodeIndex].BasicConfig != NULL) {
  2245. ExFreePool( DevNodeInfoList[nodeIndex].BasicConfig );
  2246. }
  2247. }
  2248. ExFreePool( DevNodeInfoList );
  2249. return STATUS_SUCCESS;
  2250. }
  2251. NTSTATUS
  2252. PnPBiosMapper()
  2253. /*++
  2254. Routine Description:
  2255. Map the information provided from the PnP BIOS and stored in the registry by
  2256. NTDETECT into root enumerated devices.
  2257. Arguments:
  2258. NONE
  2259. Return Value:
  2260. STATUS_SUCCESS if no errors, otherwise the appropriate error.
  2261. --*/
  2262. {
  2263. PCM_RESOURCE_LIST biosInfo;
  2264. ULONG length;
  2265. NTSTATUS status;
  2266. PBIOS_DEVNODE_INFO devNodeInfoList;
  2267. ULONG numberNodes;
  2268. status = PnPBiosGetBiosInfo( &biosInfo, &length );
  2269. if (!NT_SUCCESS( status )) {
  2270. return status;
  2271. }
  2272. status = PnPBiosTranslateInfo( biosInfo,
  2273. length,
  2274. &devNodeInfoList,
  2275. &numberNodes );
  2276. ExFreePool( biosInfo );
  2277. if (!NT_SUCCESS( status )) {
  2278. return status;
  2279. }
  2280. status = PnPBiosEliminateDupes( devNodeInfoList, numberNodes );
  2281. if (NT_SUCCESS( status )) {
  2282. status = PnPBiosWriteInfo( devNodeInfoList, numberNodes );
  2283. }
  2284. PnPBiosFreeDevNodeInfo( devNodeInfoList, numberNodes );
  2285. return status;
  2286. }
  2287. VOID
  2288. PpFilterNtResource (
  2289. IN PWCHAR PnpDeviceName,
  2290. PIO_RESOURCE_REQUIREMENTS_LIST ResReqList
  2291. )
  2292. {
  2293. PIO_RESOURCE_LIST ioResourceList;
  2294. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptors;
  2295. if (ResReqList == NULL) {
  2296. return;
  2297. }
  2298. #if 0 //_X86_
  2299. if (KeI386MachineType == MACHINE_TYPE_EISA) {
  2300. PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
  2301. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  2302. PUCHAR nextDescriptor;
  2303. ULONG j;
  2304. ULONG lastResourceIndex;
  2305. fullDescriptor = &ResourceList->List[0];
  2306. for (i = 0; i < ResourceList->Count; i++) {
  2307. partialResourceList = &fullDescriptor->PartialResourceList;
  2308. for (j = 0; j < partialResourceList->Count; j++) {
  2309. partialDescriptor = &partialResourceList->PartialDescriptors[j];
  2310. if (partialDescriptor->Type == CmResourceTypePort) {
  2311. if (partialDescriptor->u.Port.Start.HighPart == 0 &&
  2312. (partialDescriptor->u.Port.Start.LowPart & 0x00000300) == 0) {
  2313. partialDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
  2314. }
  2315. }
  2316. }
  2317. nextDescriptor = (PUCHAR)fullDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  2318. //
  2319. // account for any resource descriptors in addition to the single
  2320. // imbedded one I've already accounted for (if there aren't any,
  2321. // then I'll end up subtracting off the extra imbedded descriptor
  2322. // from the previous step)
  2323. //
  2324. //
  2325. // finally, account for any extra device specific data at the end of
  2326. // the last partial resource descriptor (if any)
  2327. //
  2328. if (partialResourceList->Count > 0) {
  2329. nextDescriptor += (partialResourceList->Count - 1) *
  2330. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  2331. lastResourceIndex = partialResourceList->Count - 1;
  2332. if (partialResourceList->PartialDescriptors[lastResourceIndex].Type ==
  2333. CmResourceTypeDeviceSpecific) {
  2334. nextDescriptor += partialResourceList->PartialDescriptors[lastResourceIndex].
  2335. u.DeviceSpecificData.DataSize;
  2336. }
  2337. }
  2338. fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)nextDescriptor;
  2339. }
  2340. }
  2341. #endif
  2342. if (RtlCompareMemory(PnpDeviceName,
  2343. L"*PNP06",
  2344. sizeof(L"*PNP06") - sizeof(WCHAR)) ==
  2345. sizeof(L"*PNP06") - sizeof(WCHAR)) {
  2346. ULONG i, j;
  2347. ioResourceList = ResReqList->List;
  2348. for (j = 0; j < ResReqList->AlternativeLists; j++) {
  2349. ioResourceDescriptors = ioResourceList->Descriptors;
  2350. for (i = 0; i < ioResourceList->Count; i++) {
  2351. if (ioResourceDescriptors[i].Type == CmResourceTypePort) {
  2352. //
  2353. // some bios asks for 1 too many io port for ide channel
  2354. //
  2355. if ((ioResourceDescriptors[i].u.Port.Length == 2) &&
  2356. (ioResourceDescriptors[i].u.Port.MaximumAddress.QuadPart ==
  2357. (ioResourceDescriptors[i].u.Port.MinimumAddress.QuadPart + 1))) {
  2358. ioResourceDescriptors[i].u.Port.Length = 1;
  2359. ioResourceDescriptors[i].u.Port.MaximumAddress =
  2360. ioResourceDescriptors[i].u.Port.MinimumAddress;
  2361. }
  2362. }
  2363. }
  2364. ioResourceList = (PIO_RESOURCE_LIST) (ioResourceDescriptors + ioResourceList->Count);
  2365. }
  2366. }
  2367. }