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.

3039 lines
101 KiB

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