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.

2422 lines
61 KiB

  1. /*++
  2. Copyright (c) 1991-2000 Microsoft Corporation
  3. Module Name:
  4. misc.c
  5. Abstract:
  6. This file contains pnp isa bus extender support routines.
  7. Author:
  8. Shie-Lin Tzong (shielint) 27-July-1995
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "busp.h"
  14. #include "pnpisa.h"
  15. #ifdef ALLOC_PRAGMA
  16. //#pragma alloc_text(PAGE, PipLockDeviceDatabase)
  17. //#pragma alloc_text(PAGE, PipUnlockDeviceDatabase)
  18. #pragma alloc_text(PAGE, PipQueryDeviceRelations)
  19. //#pragma alloc_text(PAGE, PipIsCardEnumeratedAlready)
  20. #pragma alloc_text(PAGE, PipCleanupAcquiredResources)
  21. #pragma alloc_text(PAGE, PipMapReadDataPort)
  22. #pragma alloc_text(PAGE, PipGetMappedAddress)
  23. #pragma alloc_text(PAGE, PipDecompressEisaId)
  24. #pragma alloc_text(PAGE, PipLogError)
  25. #pragma alloc_text(PAGE, PipOpenRegistryKey)
  26. #pragma alloc_text(PAGE, PipGetRegistryValue)
  27. #pragma alloc_text(PAGE, PipOpenCurrentHwProfileDeviceInstanceKey)
  28. #pragma alloc_text(PAGE, PipGetDeviceInstanceCsConfigFlags)
  29. #pragma alloc_text(PAGE, PipDetermineResourceListSize)
  30. #pragma alloc_text(PAGE, PipResetGlobals)
  31. #pragma alloc_text(PAGE, PipMapAddressAndCmdPort)
  32. #pragma alloc_text(PAGE, PiNeedDeferISABridge)
  33. #pragma alloc_text(PAGE, PipReleaseDeviceResources)
  34. #if DBG
  35. //#pragma alloc_text(PAGE, PipDebugPrint)
  36. #pragma alloc_text(PAGE, PipDumpIoResourceDescriptor)
  37. #pragma alloc_text(PAGE, PipDumpIoResourceList)
  38. #pragma alloc_text(PAGE, PipDumpCmResourceDescriptor)
  39. #pragma alloc_text(PAGE, PipDumpCmResourceList)
  40. #endif
  41. #endif
  42. #define IRQFLAGS_VALUE_NAME L"IrqFlags"
  43. #define BOOTRESOURCES_VALUE_NAME L"BootRes"
  44. #if ISOLATE_CARDS
  45. UCHAR CurrentCsn = 0;
  46. UCHAR CurrentDev = 255;
  47. VOID
  48. PipWaitForKey(VOID)
  49. {
  50. ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep));
  51. PipWriteAddress(CONFIG_CONTROL_PORT);
  52. PipWriteData(CONTROL_WAIT_FOR_KEY);
  53. PipReportStateChange(PiSWaitForKey);
  54. CurrentCsn = 0;
  55. CurrentDev = 255;
  56. }
  57. VOID
  58. PipConfig(
  59. IN UCHAR Csn
  60. )
  61. {
  62. ASSERT(Csn);
  63. ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep));
  64. PipWriteAddress(WAKE_CSN_PORT);
  65. PipWriteData(Csn);
  66. DebugPrint((DEBUG_STATE, "Wake CSN %u\n", (ULONG) Csn));
  67. CurrentCsn = Csn;
  68. CurrentDev = 255;
  69. PipReportStateChange(PiSConfig);
  70. }
  71. VOID
  72. PipIsolation(
  73. VOID
  74. )
  75. {
  76. ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep));
  77. PipWriteAddress(WAKE_CSN_PORT);
  78. PipWriteData(0);
  79. CurrentCsn = 0;
  80. CurrentDev = 255;
  81. DebugPrint((DEBUG_STATE, "Isolate cards w/o CSN\n"));
  82. PipReportStateChange(PiSIsolation);
  83. }
  84. VOID
  85. PipSleep(
  86. VOID
  87. )
  88. {
  89. ASSERT((PipState == PiSConfig) || PipState == PiSIsolation);
  90. PipWriteAddress(WAKE_CSN_PORT);
  91. PipWriteData(0);
  92. CurrentCsn = 0;
  93. CurrentDev = 255;
  94. DebugPrint((DEBUG_STATE, "Putting all cards to sleep (we think)\n"));
  95. PipReportStateChange(PiSSleep);
  96. }
  97. VOID
  98. PipActivateDevice (
  99. )
  100. {
  101. UCHAR tmp;
  102. PipWriteAddress(IO_RANGE_CHECK_PORT);
  103. tmp = PipReadData();
  104. tmp &= ~2;
  105. PipWriteAddress(IO_RANGE_CHECK_PORT);
  106. PipWriteData(tmp);
  107. PipWriteAddress(ACTIVATE_PORT);
  108. PipWriteData(1);
  109. DebugPrint((DEBUG_STATE, "Activated card CSN %d/LDN %d\n",
  110. (ULONG) CurrentCsn,
  111. (ULONG) CurrentDev));
  112. }
  113. VOID
  114. PipDeactivateDevice (
  115. )
  116. {
  117. PipWriteAddress(ACTIVATE_PORT);
  118. PipWriteData(0);
  119. DebugPrint((DEBUG_STATE, "Deactivated card CSN %d/LDN %d\n",
  120. (ULONG) CurrentCsn,
  121. (ULONG) CurrentDev));
  122. }
  123. VOID
  124. PipSelectDevice(
  125. IN UCHAR Device
  126. )
  127. {
  128. ASSERT(PipState == PiSConfig);
  129. PipWriteAddress(LOGICAL_DEVICE_PORT);
  130. PipWriteData(Device);
  131. CurrentDev = Device;
  132. DebugPrint((DEBUG_STATE, "Selected CSN %d/LDN %d\n",
  133. (ULONG) CurrentCsn,
  134. (ULONG) Device));
  135. }
  136. VOID
  137. PipWakeAndSelectDevice(
  138. IN UCHAR Csn,
  139. IN UCHAR Device
  140. )
  141. {
  142. PipLFSRInitiation();
  143. PipConfig(Csn);
  144. PipSelectDevice(Device);
  145. }
  146. PDEVICE_INFORMATION
  147. PipReferenceDeviceInformation (
  148. IN PDEVICE_OBJECT DeviceObject,
  149. IN BOOLEAN ConfigHardware
  150. )
  151. /*++
  152. Routine Description:
  153. This function locks a device node so it won't go away.
  154. Note, this function does not lock the whole device node tree.
  155. Arguments:
  156. DeviceNode - Supplies a pointer to the device information node
  157. Return Value:
  158. None.
  159. --*/
  160. {
  161. PDEVICE_INFORMATION deviceInfo;
  162. deviceInfo = (PDEVICE_INFORMATION)DeviceObject->DeviceExtension;
  163. if (deviceInfo && !(deviceInfo->Flags & DF_DELETED)) {
  164. if ((deviceInfo->Flags & DF_NOT_FUNCTIONING) && ConfigHardware) {
  165. PipDereferenceDeviceInformation(NULL, FALSE);
  166. return NULL;
  167. }
  168. if (!(deviceInfo->Flags & DF_READ_DATA_PORT) && ConfigHardware) {
  169. PipWakeAndSelectDevice(
  170. deviceInfo->CardInformation->CardSelectNumber,
  171. deviceInfo->LogicalDeviceNumber);
  172. }
  173. return deviceInfo;
  174. } else {
  175. PipDereferenceDeviceInformation(NULL, FALSE);
  176. return NULL;
  177. }
  178. }
  179. VOID
  180. PipDereferenceDeviceInformation(
  181. IN PDEVICE_INFORMATION DeviceInformation, BOOLEAN ConfigedHardware
  182. )
  183. /*++
  184. Routine Description:
  185. This function releases the enumeration lock of the specified device node.
  186. Arguments:
  187. DeviceNode - Supplies a pointer to the device node whose lock is to be released.
  188. Return Value:
  189. None.
  190. --*/
  191. {
  192. //
  193. // Synchronize the dec and set event operations with IopAcquireEnumerationLock.
  194. //
  195. if (DeviceInformation) {
  196. if (!(DeviceInformation->Flags & DF_READ_DATA_PORT) && ConfigedHardware) {
  197. if (PipState != PiSWaitForKey) {
  198. PipWaitForKey();
  199. }
  200. }
  201. }
  202. }
  203. VOID
  204. PipLockDeviceDatabase(
  205. VOID
  206. )
  207. /*++
  208. Routine Description:
  209. This function locks the whole device node tree. Currently, eject operation
  210. needs to lock the whole device node tree.
  211. Arguments:
  212. None.
  213. Return Value:
  214. None.
  215. --*/
  216. {
  217. KeWaitForSingleObject( &PipDeviceTreeLock,
  218. Executive,
  219. KernelMode,
  220. FALSE,
  221. NULL );
  222. }
  223. VOID
  224. PipUnlockDeviceDatabase (
  225. VOID
  226. )
  227. /*++
  228. Routine Description:
  229. This function releases the lock of the whole device node tree.
  230. Arguments:
  231. None.
  232. Return Value:
  233. None.
  234. --*/
  235. {
  236. KeSetEvent( &PipDeviceTreeLock,
  237. 0,
  238. FALSE );
  239. }
  240. VOID
  241. PipDeleteDevice (
  242. PDEVICE_OBJECT DeviceObject
  243. )
  244. /*++
  245. Routine Description:
  246. This routine
  247. Parameters:
  248. P1 -
  249. Return Value:
  250. Status code that indicates whether or not the function was successful.
  251. --*/
  252. {
  253. PDEVICE_INFORMATION deviceInfo, devicex, devicep;
  254. PCARD_INFORMATION cardInfo, cardx, cardp;
  255. PSINGLE_LIST_ENTRY deviceLink, cardLink;
  256. NTSTATUS status = STATUS_SUCCESS;
  257. PPI_BUS_EXTENSION busExtension;
  258. deviceInfo = (PDEVICE_INFORMATION)DeviceObject->DeviceExtension;
  259. deviceInfo->Flags |= DF_DELETED;
  260. //
  261. // Free the pool
  262. //
  263. if (deviceInfo->ResourceRequirements) {
  264. ExFreePool(deviceInfo->ResourceRequirements);
  265. deviceInfo->ResourceRequirements = NULL;
  266. }
  267. if (deviceInfo->BootResources) {
  268. ExFreePool(deviceInfo->BootResources);
  269. deviceInfo->BootResources = NULL;
  270. }
  271. if (deviceInfo->AllocatedResources) {
  272. ExFreePool(deviceInfo->AllocatedResources);
  273. deviceInfo->AllocatedResources = NULL;
  274. }
  275. if (deviceInfo->LogConfHandle) {
  276. ZwClose(deviceInfo->LogConfHandle);
  277. deviceInfo->LogConfHandle = NULL;
  278. }
  279. busExtension = deviceInfo->ParentDeviceExtension;
  280. cardInfo = deviceInfo->CardInformation;
  281. PipLockDeviceDatabase();
  282. //
  283. // Remove the device from device list.
  284. //
  285. deviceLink = busExtension->DeviceList.Next;
  286. devicep = NULL;
  287. devicex = NULL;
  288. while (deviceLink) {
  289. devicex = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
  290. if (devicex == deviceInfo) {
  291. break;
  292. }
  293. devicep = devicex;
  294. deviceLink = devicex->DeviceList.Next;
  295. }
  296. ASSERT(devicex == deviceInfo);
  297. if (devicep == NULL) {
  298. busExtension->DeviceList.Next = deviceInfo->DeviceList.Next;
  299. } else {
  300. devicep->DeviceList.Next = deviceInfo->DeviceList.Next;
  301. }
  302. //
  303. // Remove the device from logical device list of the card
  304. //
  305. deviceLink = cardInfo->LogicalDeviceList.Next;
  306. devicep = NULL;
  307. devicex = NULL;
  308. while (deviceLink) {
  309. devicex = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
  310. if (devicex == deviceInfo) {
  311. break;
  312. }
  313. devicep = devicex;
  314. deviceLink = devicex->LogicalDeviceList.Next;
  315. }
  316. ASSERT(devicex == deviceInfo);
  317. if (devicep == NULL) {
  318. cardInfo->LogicalDeviceList.Next = deviceInfo->LogicalDeviceList.Next;
  319. } else {
  320. devicep->LogicalDeviceList.Next = deviceInfo->LogicalDeviceList.Next;
  321. }
  322. cardInfo->NumberLogicalDevices--;
  323. //
  324. // All the devices are gone. That means the card is removed.
  325. // Next remove the isapnp card structure.
  326. //
  327. if (cardInfo->NumberLogicalDevices == 0) {
  328. ASSERT(cardInfo->LogicalDeviceList.Next == NULL);
  329. cardLink = busExtension->CardList.Next;
  330. cardp = NULL;
  331. cardx = NULL;
  332. while (cardLink) {
  333. cardx = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
  334. if (cardx == cardInfo) {
  335. break;
  336. }
  337. cardp = cardx;
  338. cardLink = cardx->CardList.Next;
  339. }
  340. ASSERT(cardx == cardInfo);
  341. if (cardp == NULL) {
  342. busExtension->CardList.Next = cardInfo->CardList.Next;
  343. } else {
  344. cardp->CardList.Next = cardInfo->CardList.Next;
  345. }
  346. }
  347. PipUnlockDeviceDatabase();
  348. //
  349. // Remove the card information structure after releasing spin lock.
  350. //
  351. if (cardInfo->NumberLogicalDevices == 0) {
  352. if (cardInfo->CardData) {
  353. ExFreePool(cardInfo->CardData);
  354. }
  355. ExFreePool(cardInfo);
  356. deviceInfo->CardInformation = NULL;
  357. }
  358. IoDeleteDevice(DeviceObject);
  359. }
  360. NTSTATUS
  361. PipQueryDeviceRelations (
  362. PPI_BUS_EXTENSION BusExtension,
  363. PDEVICE_RELATIONS *DeviceRelations,
  364. BOOLEAN Removal
  365. )
  366. /*++
  367. Routine Description:
  368. This routine
  369. Parameters:
  370. P1 -
  371. Return Value:
  372. Status code that indicates whether or not the function was successful.
  373. --*/
  374. {
  375. PDEVICE_INFORMATION deviceInfo;
  376. PSINGLE_LIST_ENTRY deviceLink;
  377. NTSTATUS status = STATUS_SUCCESS;
  378. PDEVICE_OBJECT *devicePtr;
  379. ULONG count = 0;
  380. PDEVICE_RELATIONS deviceRelations;
  381. PAGED_CODE();
  382. *DeviceRelations = NULL;
  383. //
  384. // Go through the card link list to match the card data
  385. //
  386. deviceLink = BusExtension->DeviceList.Next;
  387. while (deviceLink) {
  388. deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
  389. //
  390. // if it's the RDP ignore it for removal relations
  391. //
  392. if ((deviceInfo->Flags & DF_ENUMERATED) &&
  393. (!(deviceInfo->Flags & DF_READ_DATA_PORT) || !Removal)) {
  394. count++;
  395. } else {
  396. DebugPrint((DEBUG_PNP, "PipQueryDeviceRelations skipping a node, Flags: %x\n",deviceInfo->Flags));
  397. }
  398. deviceLink = deviceInfo->DeviceList.Next;
  399. }
  400. if (count != 0) {
  401. deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool(
  402. PagedPool,
  403. sizeof(DEVICE_RELATIONS) + (count - 1) * sizeof(PDEVICE_OBJECT));
  404. if (deviceRelations) {
  405. deviceRelations->Count = count;
  406. deviceLink = BusExtension->DeviceList.Next;
  407. devicePtr = deviceRelations->Objects;
  408. while (deviceLink) {
  409. deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
  410. if ((deviceInfo->Flags & DF_ENUMERATED) &&
  411. (!(deviceInfo->Flags & DF_READ_DATA_PORT) || !(Removal))) {
  412. ObReferenceObject(deviceInfo->PhysicalDeviceObject);
  413. *devicePtr = deviceInfo->PhysicalDeviceObject;
  414. devicePtr++;
  415. }
  416. deviceLink = deviceInfo->DeviceList.Next;
  417. }
  418. *DeviceRelations = deviceRelations;
  419. } else {
  420. status = STATUS_INSUFFICIENT_RESOURCES;
  421. }
  422. }
  423. return status;
  424. }
  425. PCARD_INFORMATION
  426. PipIsCardEnumeratedAlready(
  427. IN PPI_BUS_EXTENSION BusExtension,
  428. IN PUCHAR CardData,
  429. IN ULONG DataLength
  430. )
  431. /*++
  432. Routine Description:
  433. This routine finds the card information structure which contains the same CardData.
  434. Parameters:
  435. CardData - Supplies a pointer to the CardData
  436. DataLength - The length of the CardData
  437. Return Value:
  438. A pointer to the CARD_INFORMATION structure if found.
  439. --*/
  440. {
  441. PCARD_INFORMATION cardInfo;
  442. PSINGLE_LIST_ENTRY cardLink;
  443. PSERIAL_IDENTIFIER serialId1, serialId2 = (PSERIAL_IDENTIFIER)CardData;
  444. //
  445. // Go through the card link list to match the card data
  446. //
  447. cardLink = BusExtension->CardList.Next;
  448. while (cardLink) {
  449. cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
  450. if (cardInfo->CardSelectNumber != 0) { // if == 0, card is no longer present
  451. serialId1 = (PSERIAL_IDENTIFIER)cardInfo->CardData;
  452. ASSERT(serialId1 && serialId2);
  453. if (serialId1->VenderId == serialId2->VenderId &&
  454. serialId1->SerialNumber == serialId2->SerialNumber) {
  455. return cardInfo;
  456. }
  457. }
  458. cardLink = cardInfo->CardList.Next; // Get the next addr before releasing pool
  459. }
  460. return NULL;
  461. }
  462. VOID
  463. PipCleanupAcquiredResources (
  464. PPI_BUS_EXTENSION BusExtension
  465. )
  466. /*++
  467. Routine Description:
  468. This routine cleans up the resources assigned to the readdata, command and address
  469. ports.
  470. Parameters:
  471. BusExtension - specifies the isapnp bus to be cleaned up.
  472. Return Value:
  473. None.
  474. --*/
  475. {
  476. PAGED_CODE();
  477. //
  478. // Release address, command and read data port resources.
  479. //
  480. if (BusExtension->CommandPort && BusExtension->CmdPortMapped) {
  481. MmUnmapIoSpace(BusExtension->CommandPort, 1);
  482. BusExtension->CmdPortMapped = FALSE;
  483. }
  484. BusExtension->CommandPort = NULL;
  485. if (BusExtension->AddressPort && BusExtension->AddrPortMapped) {
  486. MmUnmapIoSpace(BusExtension->AddressPort, 1);
  487. BusExtension->AddrPortMapped = FALSE;
  488. }
  489. BusExtension->AddressPort = NULL;
  490. if (BusExtension->ReadDataPort) {
  491. PipReadDataPort = PipCommandPort = PipAddressPort = NULL;
  492. }
  493. if (BusExtension->ReadDataPort && BusExtension->DataPortMapped) {
  494. MmUnmapIoSpace(BusExtension->ReadDataPort - 3, 4);
  495. BusExtension->DataPortMapped = FALSE;
  496. }
  497. BusExtension->ReadDataPort = NULL;
  498. }
  499. NTSTATUS
  500. PipMapReadDataPort (
  501. IN PPI_BUS_EXTENSION BusExtension,
  502. IN PHYSICAL_ADDRESS Start,
  503. IN ULONG Length
  504. )
  505. /*++
  506. Routine Description:
  507. This routine maps specified port resources.
  508. Arguments:
  509. BusExtension - Supplies a pointer to the pnp bus extension.
  510. BaseAddressLow,
  511. BaseAddressHi - Supplies the read data port base address range to be mapped.
  512. Return Value:
  513. NTSTATUS code.
  514. --*/
  515. {
  516. NTSTATUS status;
  517. ULONG size;
  518. PHYSICAL_ADDRESS physicalAddress;
  519. ULONG dumpData[3];
  520. BOOLEAN conflictDetected;
  521. PAGED_CODE();
  522. if (BusExtension->ReadDataPort && BusExtension->DataPortMapped) {
  523. MmUnmapIoSpace(PipReadDataPort - 3, 4);
  524. PipReadDataPort = BusExtension->ReadDataPort = NULL;
  525. BusExtension->DataPortMapped = FALSE;
  526. }
  527. PipReadDataPort = PipGetMappedAddress(
  528. Isa, // InterfaceType
  529. 0, // BusNumber,
  530. Start,
  531. Length,
  532. CM_RESOURCE_PORT_IO,
  533. &BusExtension->DataPortMapped
  534. );
  535. DebugPrint((DEBUG_RDP, "PnpIsa:ReadDataPort is at %x\n",PipReadDataPort+3));
  536. if (PipReadDataPort) {
  537. PipReadDataPort += 3;
  538. BusExtension->ReadDataPort = PipReadDataPort;
  539. status = STATUS_SUCCESS;
  540. } else {
  541. status = STATUS_INSUFFICIENT_RESOURCES;
  542. }
  543. return status;
  544. }
  545. PVOID
  546. PipGetMappedAddress(
  547. IN INTERFACE_TYPE BusType,
  548. IN ULONG BusNumber,
  549. IN PHYSICAL_ADDRESS IoAddress,
  550. IN ULONG NumberOfBytes,
  551. IN ULONG AddressSpace,
  552. OUT PBOOLEAN MappedAddress
  553. )
  554. /*++
  555. Routine Description:
  556. This routine maps an IO address to system address space.
  557. Arguments:
  558. BusType - Supplies the type of bus - eisa, mca, isa...
  559. IoBusNumber - Supplies the bus number.
  560. IoAddress - Supplies the base device address to be mapped.
  561. NumberOfBytes - Supplies the number of bytes for which the address is
  562. valid.
  563. AddressSpace - Supplies whether the address is in io space or memory.
  564. MappedAddress - Supplies whether the address was mapped. This only has
  565. meaning if the address returned is non-null.
  566. Return Value:
  567. The mapped address.
  568. --*/
  569. {
  570. PHYSICAL_ADDRESS cardAddress;
  571. PVOID address;
  572. BOOLEAN returnVal;
  573. PAGED_CODE();
  574. returnVal = HalTranslateBusAddress(BusType, BusNumber, IoAddress, &AddressSpace,
  575. &cardAddress);
  576. if (returnVal == FALSE) {
  577. *MappedAddress = FALSE;
  578. return NULL;
  579. }
  580. //
  581. // Map the device base address into the virtual address space
  582. // if the address is in memory space.
  583. //
  584. if (!AddressSpace) {
  585. address = MmMapIoSpace(cardAddress, NumberOfBytes, FALSE);
  586. *MappedAddress = (address ? TRUE : FALSE);
  587. } else {
  588. address = (PVOID) cardAddress.LowPart;
  589. *MappedAddress = FALSE;
  590. }
  591. return address;
  592. }
  593. VOID
  594. PipDecompressEisaId(
  595. IN ULONG CompressedId,
  596. OUT PWCHAR EisaId
  597. )
  598. /*++
  599. Routine Description:
  600. This routine decompressed compressed Eisa Id and returns the Id to caller
  601. specified character buffer.
  602. Arguments:
  603. CompressedId - supplies the compressed Eisa Id.
  604. EisaId - supplies a 8-wchar buffer to receive the decompressed Eisa Id.
  605. Return Value:
  606. None.
  607. --*/
  608. {
  609. USHORT c1, c2;
  610. LONG i;
  611. PAGED_CODE();
  612. CompressedId &= 0xffffff7f; // remove the reserved bit (bit 7 of byte 0)
  613. c1 = c2 = (USHORT)CompressedId;
  614. c1 = (c1 & 0xff) << 8;
  615. c2 = (c2 & 0xff00) >> 8;
  616. c1 |= c2;
  617. for (i = 2; i >= 0; i--) {
  618. *(EisaId + i) = (WCHAR)(c1 & 0x1f) + 0x40;
  619. c1 >>= 5;
  620. }
  621. EisaId += 3;
  622. c1 = c2 = (USHORT)(CompressedId >> 16);
  623. c1 = (c1 & 0xff) << 8;
  624. c2 = (c2 & 0xff00) >> 8;
  625. c1 |= c2;
  626. StringCchPrintf(EisaId,
  627. 5,
  628. L"%04x",
  629. c1
  630. );
  631. }
  632. VOID
  633. PipLogError(
  634. IN NTSTATUS ErrorCode,
  635. IN ULONG UniqueErrorValue,
  636. IN NTSTATUS FinalStatus,
  637. IN PULONG DumpData,
  638. IN ULONG DumpCount,
  639. IN USHORT StringLength,
  640. IN PWCHAR String
  641. )
  642. /*++
  643. Routine Description:
  644. This routine contains common code to write an error log entry. It is
  645. called from other routines to avoid duplication of code. This routine
  646. only allows caller to supply one insertion string to the error log.
  647. Arguments:
  648. ErrorCode - The error code for the error log packet.
  649. UniqueErrorValue - The unique error value for the error log packet.
  650. FinalStatus - The final status of the operation for the error log packet.
  651. DumpData - Pointer to an array of dump data for the error log packet.
  652. DumpCount - The number of entries in the dump data array.
  653. StringLength - The length of insertion string *NOT* including the NULL terminater.
  654. String - The pointer to the insertion string
  655. Return Value:
  656. None.
  657. --*/
  658. {
  659. PIO_ERROR_LOG_PACKET errorLogEntry;
  660. ULONG i, size;
  661. PUCHAR p;
  662. size = sizeof(IO_ERROR_LOG_PACKET) + DumpCount * sizeof(ULONG) +
  663. StringLength + sizeof(UNICODE_NULL) - sizeof(ULONG);
  664. ASSERT(size <= MAXUCHAR);
  665. if (size > MAXUCHAR) {
  666. return;
  667. }
  668. errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
  669. PipDriverObject,
  670. (UCHAR) size
  671. );
  672. if (errorLogEntry != NULL) {
  673. RtlZeroMemory(errorLogEntry, size);
  674. errorLogEntry->ErrorCode = ErrorCode;
  675. errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
  676. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  677. errorLogEntry->FinalStatus = FinalStatus;
  678. for (i = 0; i < DumpCount; i++)
  679. errorLogEntry->DumpData[i] = DumpData[i];
  680. if (String) {
  681. errorLogEntry->NumberOfStrings = 1;
  682. errorLogEntry->StringOffset = (USHORT)(sizeof(IO_ERROR_LOG_PACKET) +
  683. DumpCount * sizeof(ULONG) - sizeof(ULONG));
  684. p= (PUCHAR)errorLogEntry + errorLogEntry->StringOffset;
  685. StringCbCopy((PWCHAR)p,
  686. StringLength + sizeof(UNICODE_NULL),
  687. String
  688. );
  689. }
  690. IoWriteErrorLogEntry(errorLogEntry);
  691. }
  692. }
  693. NTSTATUS
  694. PipOpenCurrentHwProfileDeviceInstanceKey(
  695. OUT PHANDLE Handle,
  696. IN PUNICODE_STRING DeviceInstanceName,
  697. IN ACCESS_MASK DesiredAccess
  698. )
  699. /*++
  700. Routine Description:
  701. This routine sets the csconfig flags for the specified device
  702. which is specified by the instance number under ServiceKeyName\Enum.
  703. Arguments:
  704. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  705. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  706. that caused the driver to load. This is the RegistryPath parameter
  707. to the DriverEntry routine.
  708. Instance - Supplies the instance value under ServiceKeyName\Enum key
  709. DesiredAccess - Specifies the desired access that the caller needs to
  710. the key.
  711. Create - Determines if the key is to be created if it does not exist.
  712. Return Value:
  713. status
  714. --*/
  715. {
  716. NTSTATUS status;
  717. UNICODE_STRING unicodeString;
  718. HANDLE profileEnumHandle;
  719. //
  720. // See if we can open the device instance key of current hardware profile
  721. //
  722. RtlInitUnicodeString (
  723. &unicodeString,
  724. L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT\\SYSTEM\\CURRENTCONTROLSET\\ENUM"
  725. );
  726. status = PipOpenRegistryKey(&profileEnumHandle,
  727. NULL,
  728. &unicodeString,
  729. KEY_READ,
  730. FALSE
  731. );
  732. if (NT_SUCCESS(status)) {
  733. status = PipOpenRegistryKey(Handle,
  734. profileEnumHandle,
  735. DeviceInstanceName,
  736. DesiredAccess,
  737. FALSE
  738. );
  739. ZwClose(profileEnumHandle);
  740. }
  741. return status;
  742. }
  743. NTSTATUS
  744. PipGetDeviceInstanceCsConfigFlags(
  745. IN PUNICODE_STRING DeviceInstance,
  746. OUT PULONG CsConfigFlags
  747. )
  748. /*++
  749. Routine Description:
  750. This routine retrieves the csconfig flags for the specified device
  751. which is specified by the instance number under ServiceKeyName\Enum.
  752. Arguments:
  753. ServiceKeyName - Supplies a pointer to the name of the subkey in the
  754. system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
  755. that caused the driver to load.
  756. // Instance - Supplies the instance value under ServiceKeyName\Enum key
  757. //
  758. CsConfigFlags - Supplies a variable to receive the device's CsConfigFlags
  759. Return Value:
  760. status
  761. --*/
  762. {
  763. NTSTATUS status;
  764. HANDLE handle;
  765. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  766. *CsConfigFlags = 0;
  767. status = PipOpenCurrentHwProfileDeviceInstanceKey(&handle,
  768. DeviceInstance,
  769. KEY_READ
  770. );
  771. if(NT_SUCCESS(status)) {
  772. status = PipGetRegistryValue(handle,
  773. L"CsConfigFlags",
  774. &keyValueInformation
  775. );
  776. if(NT_SUCCESS(status)) {
  777. if((keyValueInformation->Type == REG_DWORD) &&
  778. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  779. *CsConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  780. }
  781. ExFreePool(keyValueInformation);
  782. }
  783. ZwClose(handle);
  784. }
  785. return status;
  786. }
  787. ULONG
  788. PipDetermineResourceListSize(
  789. IN PCM_RESOURCE_LIST ResourceList
  790. )
  791. /*++
  792. Routine Description:
  793. This routine determines size of the passed in ResourceList
  794. structure.
  795. Arguments:
  796. Configuration1 - Supplies a pointer to the resource list.
  797. Return Value:
  798. size of the resource list structure.
  799. --*/
  800. {
  801. ULONG totalSize, listSize, descriptorSize, i, j;
  802. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  803. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  804. if (!ResourceList) {
  805. totalSize = 0;
  806. } else {
  807. totalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
  808. fullResourceDesc = &ResourceList->List[0];
  809. for (i = 0; i < ResourceList->Count; i++) {
  810. listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  811. PartialResourceList) +
  812. FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
  813. PartialDescriptors);
  814. partialDescriptor = &fullResourceDesc->PartialResourceList.PartialDescriptors[0];
  815. for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
  816. descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  817. if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
  818. descriptorSize += partialDescriptor->u.DeviceSpecificData.DataSize;
  819. }
  820. listSize += descriptorSize;
  821. partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  822. ((PUCHAR)partialDescriptor + descriptorSize);
  823. }
  824. totalSize += listSize;
  825. fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
  826. ((PUCHAR)fullResourceDesc + listSize);
  827. }
  828. }
  829. return totalSize;
  830. }
  831. NTSTATUS
  832. PipMapAddressAndCmdPort (
  833. IN PPI_BUS_EXTENSION BusExtension
  834. )
  835. {
  836. NTSTATUS status = STATUS_SUCCESS;
  837. ULONG dumpData[3];
  838. PHYSICAL_ADDRESS physicalAddress;
  839. //
  840. // Map port addr to memory addr if necessary.
  841. //
  842. if (PipAddressPort == NULL) {
  843. physicalAddress.LowPart = ADDRESS_PORT;
  844. physicalAddress.HighPart = 0;
  845. BusExtension->AddressPort =
  846. PipAddressPort = PipGetMappedAddress(
  847. Isa, // InterfaceType
  848. 0, // BusNumber,
  849. physicalAddress,
  850. 1,
  851. CM_RESOURCE_PORT_IO,
  852. &BusExtension->AddrPortMapped
  853. );
  854. if (PipAddressPort == NULL) {
  855. dumpData[0] = ADDRESS_PORT;
  856. dumpData[1] = 1;
  857. dumpData[2] = CM_RESOURCE_PORT_IO;
  858. PipLogError(PNPISA_REGISTER_NOT_MAPPED,
  859. PNPISA_ACQUIREPORTRESOURCE_1,
  860. STATUS_INSUFFICIENT_RESOURCES,
  861. dumpData,
  862. 3,
  863. 0,
  864. NULL
  865. );
  866. status = STATUS_UNSUCCESSFUL;
  867. }
  868. }
  869. if (PipCommandPort == NULL) {
  870. physicalAddress.LowPart = COMMAND_PORT;
  871. physicalAddress.HighPart = 0;
  872. BusExtension->CommandPort =
  873. PipCommandPort = PipGetMappedAddress(
  874. Isa, // InterfaceType
  875. 0, // BusNumber,
  876. physicalAddress,
  877. 1,
  878. CM_RESOURCE_PORT_IO,
  879. &BusExtension->CmdPortMapped
  880. );
  881. if (PipCommandPort == NULL) {
  882. dumpData[0] = COMMAND_PORT;
  883. dumpData[1] = 1;
  884. dumpData[2] = CM_RESOURCE_PORT_IO;
  885. PipLogError(PNPISA_REGISTER_NOT_MAPPED,
  886. PNPISA_ACQUIREPORTRESOURCE_2,
  887. STATUS_INSUFFICIENT_RESOURCES,
  888. dumpData,
  889. 3,
  890. 0,
  891. NULL
  892. );
  893. status = STATUS_UNSUCCESSFUL;
  894. }
  895. }
  896. return status;
  897. }
  898. VOID
  899. PipReleaseDeviceResources (
  900. PDEVICE_INFORMATION DeviceInfo
  901. )
  902. {
  903. UNICODE_STRING unicodeString;
  904. // This code is here rather than in the following conditional as
  905. // this best reflects how the code used to work before this code
  906. // was moved here from PDO stop/remove/surprise remove.
  907. if (DeviceInfo->LogConfHandle) {
  908. RtlInitUnicodeString(&unicodeString, L"AllocConfig");
  909. ZwDeleteValueKey (DeviceInfo->LogConfHandle, &unicodeString);
  910. }
  911. if (DeviceInfo->AllocatedResources) {
  912. ExFreePool (DeviceInfo->AllocatedResources);
  913. DeviceInfo->AllocatedResources=NULL;
  914. if (DeviceInfo->LogConfHandle) {
  915. // As it stands now it we will close the logconf handle if
  916. // the device gets removed, surprise removed, or stopped.
  917. // When we get started, we'll try to re-create the
  918. // AllocConfig value but fail because of the lack of the
  919. // logconf handle. This is not a change in behavior.
  920. //
  921. // The ZwDeleteKey() was definitely bogus though.
  922. ZwClose(DeviceInfo->LogConfHandle);
  923. DeviceInfo->LogConfHandle=NULL;
  924. }
  925. }
  926. }
  927. VOID
  928. PipReportStateChange(
  929. PNPISA_STATE State
  930. )
  931. {
  932. DebugPrint((DEBUG_STATE, "State transition: %d to %d\n",
  933. PipState, State));
  934. PipState = State;
  935. }
  936. ULONG
  937. PipGetCardFlags(
  938. PCARD_INFORMATION CardInfo
  939. )
  940. /*++
  941. Description:
  942. Look in the registry for any flags for this CardId
  943. Arguments:
  944. CardId First 4 bytes of ISAPNP config space
  945. Return Value:
  946. 32 bit flags value from registry or 0 if not found.
  947. --*/
  948. {
  949. HANDLE serviceHandle, paramHandle;
  950. NTSTATUS status;
  951. ULONG flags, returnedLength;
  952. UNICODE_STRING nameString;
  953. WCHAR nameBuffer[9];
  954. WCHAR eisaId[8];
  955. const PWCHAR paramKey = L"Parameters";
  956. struct {
  957. KEY_VALUE_PARTIAL_INFORMATION Header;
  958. //
  959. // The header contains enough space for one UCHAR, pad
  960. // it out by a ULONG, this will ensure the structure
  961. // is large enough for at lease the ULONG we need.
  962. //
  963. // N.B. Natural alignment will get it out far enough that
  964. // this ULONG is 4 bytes to many.
  965. //
  966. ULONG Pad;
  967. } returnedData;
  968. status = PipOpenRegistryKey(&serviceHandle,
  969. NULL,
  970. &PipRegistryPath,
  971. KEY_READ,
  972. FALSE);
  973. if (!NT_SUCCESS(status)) {
  974. return 0;
  975. }
  976. RtlInitUnicodeString(&nameString, paramKey);
  977. status = PipOpenRegistryKey(&paramHandle,
  978. serviceHandle,
  979. &nameString,
  980. KEY_READ,
  981. FALSE);
  982. if (!NT_SUCCESS(status)) {
  983. ZwClose(serviceHandle);
  984. return 0;
  985. }
  986. PipDecompressEisaId(
  987. ((PSERIAL_IDENTIFIER) (CardInfo->CardData))->VenderId,
  988. eisaId
  989. );
  990. RtlInitUnicodeString(&nameString, eisaId);
  991. //
  992. // Get the "value" of this value.
  993. //
  994. status = ZwQueryValueKey(
  995. paramHandle,
  996. &nameString,
  997. KeyValuePartialInformation,
  998. &returnedData,
  999. sizeof(returnedData),
  1000. &returnedLength
  1001. );
  1002. ZwClose(paramHandle);
  1003. ZwClose(serviceHandle);
  1004. if (NT_SUCCESS(status) && (returnedData.Header.Type == REG_DWORD) &&
  1005. (returnedData.Header.DataLength == sizeof(ULONG))) {
  1006. flags = *(PULONG)(returnedData.Header.Data);
  1007. DebugPrint((DEBUG_WARN, "Retrieving card flags for %ws: %x\n",
  1008. nameString.Buffer, flags));
  1009. } else {
  1010. flags = 0;
  1011. }
  1012. return flags;
  1013. }
  1014. NTSTATUS
  1015. PipBuildValueName(
  1016. IN PDEVICE_INFORMATION DeviceInfo,
  1017. IN PWSTR Suffix,
  1018. OUT PWSTR *ValuePath
  1019. )
  1020. /*++
  1021. Description:
  1022. Builds a name describing the device via the device id and unique
  1023. id. Used to store per-device info in our parent's BiosConfig key
  1024. Arguments:
  1025. DeviceInfo Pointer to the PDO Extension for this device.
  1026. Suffix Suffix for value name
  1027. IrqFlags The edge or level setting of the boot config
  1028. Return Value:
  1029. Status
  1030. --*/
  1031. {
  1032. NTSTATUS status;
  1033. PWSTR DeviceId = NULL, Instance = NULL;
  1034. PWSTR Buffer, Current;
  1035. ULONG length, deviceIdLength, instanceIdLength;
  1036. status = PipQueryDeviceId(DeviceInfo, &DeviceId, &deviceIdLength, 0);
  1037. if (!NT_SUCCESS(status)) {
  1038. goto cleanup;
  1039. }
  1040. status = PipQueryDeviceUniqueId(DeviceInfo, &Instance, &instanceIdLength);
  1041. if (!NT_SUCCESS(status)) {
  1042. goto cleanup;
  1043. }
  1044. length = deviceIdLength + instanceIdLength + (wcslen(Suffix) + 1) * sizeof(WCHAR);
  1045. Buffer = ExAllocatePool(PagedPool, length);
  1046. if (Buffer == NULL) {
  1047. status = STATUS_INSUFFICIENT_RESOURCES;
  1048. goto cleanup;
  1049. }
  1050. StringCbCopy(Buffer,
  1051. length,
  1052. DeviceId
  1053. );
  1054. StringCbCat(Buffer,
  1055. length,
  1056. Instance
  1057. );
  1058. StringCbCat(Buffer,
  1059. length,
  1060. Suffix
  1061. );
  1062. Current = Buffer;
  1063. while (*Current != UNICODE_NULL) {
  1064. if (*Current == L'\\') {
  1065. *Current = L'_';
  1066. }
  1067. Current++;
  1068. }
  1069. cleanup:
  1070. if (Instance) {
  1071. ExFreePool(Instance);
  1072. }
  1073. if (DeviceId) {
  1074. ExFreePool(DeviceId);
  1075. }
  1076. if (NT_SUCCESS(status)) {
  1077. *ValuePath = Buffer;
  1078. } else {
  1079. *ValuePath = NULL;
  1080. }
  1081. return status;
  1082. }
  1083. NTSTATUS
  1084. PipSaveBootResources(
  1085. IN PDEVICE_INFORMATION DeviceInfo
  1086. )
  1087. /*++
  1088. Description:
  1089. This saves the per-boot configuration of a device in the registry
  1090. Arguments:
  1091. DeviceInfo Pointer to the PDO Extension for this device.
  1092. Return Value:
  1093. Status
  1094. --*/
  1095. {
  1096. NTSTATUS status;
  1097. OBJECT_ATTRIBUTES attributes;
  1098. UNICODE_STRING unicodeString;
  1099. HANDLE deviceHandle, configHandle;
  1100. PWSTR Buffer = NULL;
  1101. ULONG Flags;
  1102. PAGED_CODE();
  1103. status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
  1104. PLUGPLAY_REGKEY_DEVICE,
  1105. KEY_WRITE,
  1106. &deviceHandle
  1107. );
  1108. if (!NT_SUCCESS(status)) {
  1109. goto cleanup;
  1110. }
  1111. RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
  1112. InitializeObjectAttributes(&attributes,
  1113. &unicodeString,
  1114. OBJ_KERNEL_HANDLE,
  1115. deviceHandle,
  1116. NULL
  1117. );
  1118. status = ZwCreateKey(&configHandle,
  1119. KEY_WRITE,
  1120. &attributes,
  1121. 0,
  1122. NULL,
  1123. REG_OPTION_VOLATILE,
  1124. NULL
  1125. );
  1126. ZwClose(deviceHandle);
  1127. if (!NT_SUCCESS(status)) {
  1128. goto cleanup;
  1129. }
  1130. status = PipBuildValueName(DeviceInfo, BOOTRESOURCES_VALUE_NAME,
  1131. &Buffer);
  1132. if (!NT_SUCCESS(status)) {
  1133. Buffer = NULL;
  1134. goto cleanup;
  1135. }
  1136. RtlInitUnicodeString(&unicodeString, Buffer);
  1137. status = ZwSetValueKey(configHandle,
  1138. &unicodeString,
  1139. 0,
  1140. REG_BINARY,
  1141. DeviceInfo->BootResources,
  1142. DeviceInfo->BootResourcesLength
  1143. );
  1144. ZwClose(configHandle);
  1145. cleanup:
  1146. if (Buffer != NULL) {
  1147. ExFreePool(Buffer);
  1148. }
  1149. return status;
  1150. }
  1151. NTSTATUS
  1152. PipSaveBootIrqFlags(
  1153. IN PDEVICE_INFORMATION DeviceInfo,
  1154. IN USHORT IrqFlags
  1155. )
  1156. /*++
  1157. Description:
  1158. This saves the per-boot irq configuration of a device in the registry
  1159. Arguments:
  1160. DeviceInfo Pointer to the PDO Extension for this device.
  1161. IrqFlags The edge or level setting of the boot config
  1162. Return Value:
  1163. Status
  1164. --*/
  1165. {
  1166. NTSTATUS status;
  1167. OBJECT_ATTRIBUTES attributes;
  1168. UNICODE_STRING unicodeString;
  1169. HANDLE deviceHandle, configHandle;
  1170. PWSTR Buffer = NULL;
  1171. ULONG Flags;
  1172. PAGED_CODE();
  1173. Flags = (ULONG) IrqFlags;
  1174. status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
  1175. PLUGPLAY_REGKEY_DEVICE,
  1176. KEY_WRITE,
  1177. &deviceHandle
  1178. );
  1179. if (!NT_SUCCESS(status)) {
  1180. goto cleanup;
  1181. }
  1182. RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
  1183. InitializeObjectAttributes(&attributes,
  1184. &unicodeString,
  1185. OBJ_KERNEL_HANDLE,
  1186. deviceHandle,
  1187. NULL
  1188. );
  1189. status = ZwCreateKey(&configHandle,
  1190. KEY_WRITE,
  1191. &attributes,
  1192. 0,
  1193. NULL,
  1194. REG_OPTION_VOLATILE,
  1195. NULL
  1196. );
  1197. ZwClose(deviceHandle);
  1198. if (!NT_SUCCESS(status)) {
  1199. goto cleanup;
  1200. }
  1201. status = PipBuildValueName(DeviceInfo, IRQFLAGS_VALUE_NAME, &Buffer);
  1202. if (!NT_SUCCESS(status)) {
  1203. Buffer = NULL;
  1204. goto cleanup;
  1205. }
  1206. RtlInitUnicodeString(&unicodeString, Buffer);
  1207. status = ZwSetValueKey(configHandle,
  1208. &unicodeString,
  1209. 0,
  1210. REG_DWORD,
  1211. &Flags,
  1212. sizeof(ULONG)
  1213. );
  1214. ZwClose(configHandle);
  1215. cleanup:
  1216. if (Buffer != NULL) {
  1217. ExFreePool(Buffer);
  1218. }
  1219. return status;
  1220. }
  1221. NTSTATUS
  1222. PipGetSavedBootResources(
  1223. IN PDEVICE_INFORMATION DeviceInfo,
  1224. OUT PCM_RESOURCE_LIST *BootResources
  1225. )
  1226. /*
  1227. Description:
  1228. This retrieves the saved boot resources
  1229. Arguments:
  1230. DeviceInfo Pointer to the PDO Extension for this device.
  1231. Return Value:
  1232. Status
  1233. --*/
  1234. {
  1235. UNICODE_STRING unicodeString;
  1236. NTSTATUS status;
  1237. OBJECT_ATTRIBUTES attributes;
  1238. HANDLE deviceHandle, configHandle;
  1239. PWSTR Buffer = NULL;
  1240. PKEY_VALUE_PARTIAL_INFORMATION info = NULL;
  1241. ULONG resultLength;
  1242. PAGED_CODE();
  1243. *BootResources = NULL;
  1244. status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
  1245. PLUGPLAY_REGKEY_DEVICE,
  1246. KEY_READ | KEY_WRITE,
  1247. &deviceHandle
  1248. );
  1249. if (!NT_SUCCESS(status)) {
  1250. goto cleanup;
  1251. }
  1252. RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
  1253. InitializeObjectAttributes(&attributes,
  1254. &unicodeString,
  1255. OBJ_KERNEL_HANDLE,
  1256. deviceHandle,
  1257. NULL
  1258. );
  1259. status = ZwOpenKey(&configHandle,
  1260. KEY_READ,
  1261. &attributes
  1262. );
  1263. ZwClose(deviceHandle);
  1264. if (!NT_SUCCESS(status)) {
  1265. goto cleanup;
  1266. }
  1267. status = PipBuildValueName(DeviceInfo, BOOTRESOURCES_VALUE_NAME, &Buffer);
  1268. if (!NT_SUCCESS(status)) {
  1269. ZwClose(configHandle);
  1270. Buffer = NULL;
  1271. goto cleanup;
  1272. }
  1273. RtlInitUnicodeString(&unicodeString,Buffer);
  1274. status = ZwQueryValueKey(configHandle,
  1275. &unicodeString,
  1276. KeyValuePartialInformation,
  1277. NULL,
  1278. 0,
  1279. &resultLength
  1280. );
  1281. if (status != STATUS_BUFFER_OVERFLOW &&
  1282. status != STATUS_BUFFER_TOO_SMALL) {
  1283. ZwClose(configHandle);
  1284. goto cleanup;
  1285. }
  1286. info = ExAllocatePool(PagedPool, resultLength);
  1287. if (info == NULL) {
  1288. ZwClose(configHandle);
  1289. status = STATUS_INSUFFICIENT_RESOURCES;
  1290. goto cleanup;
  1291. }
  1292. status = ZwQueryValueKey(configHandle,
  1293. &unicodeString,
  1294. KeyValuePartialInformation,
  1295. info,
  1296. resultLength,
  1297. &resultLength
  1298. );
  1299. ZwClose(configHandle);
  1300. if (!NT_SUCCESS(status)) {
  1301. DebugPrint((DEBUG_PNP, "Failed to get boot resources from registry for %ws\n", Buffer));
  1302. goto cleanup;
  1303. }
  1304. status = PipValidateResourceList((PCM_RESOURCE_LIST)info->Data, info->DataLength);
  1305. if (!NT_SUCCESS(status)) {
  1306. *BootResources = NULL;
  1307. goto cleanup;
  1308. }
  1309. *BootResources = ExAllocatePool(PagedPool, info->DataLength);
  1310. if (*BootResources) {
  1311. RtlCopyMemory(*BootResources, info->Data, info->DataLength);
  1312. DebugPrint((DEBUG_PNP, "Got boot resources from registry for %ws\n", Buffer));
  1313. } else {
  1314. status = STATUS_INSUFFICIENT_RESOURCES;
  1315. }
  1316. cleanup:
  1317. if (info != NULL) {
  1318. ExFreePool(info);
  1319. }
  1320. if (Buffer != NULL) {
  1321. ExFreePool(Buffer);
  1322. }
  1323. return status;
  1324. }
  1325. NTSTATUS
  1326. PipGetBootIrqFlags(
  1327. IN PDEVICE_INFORMATION DeviceInfo,
  1328. OUT PUSHORT IrqFlags
  1329. )
  1330. /*
  1331. Description:
  1332. This retrieves the per-boot irq configuration of a device from the registry
  1333. Arguments:
  1334. DeviceInfo Pointer to the PDO Extension for this device.
  1335. IrqFlags - flags we originally derived from the device's boot
  1336. config on this boot
  1337. Return Value:
  1338. Status
  1339. --*/
  1340. {
  1341. NTSTATUS status;
  1342. OBJECT_ATTRIBUTES attributes;
  1343. UNICODE_STRING unicodeString;
  1344. HANDLE deviceHandle, configHandle;
  1345. PWSTR Buffer = NULL;
  1346. CHAR returnBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1];
  1347. PKEY_VALUE_PARTIAL_INFORMATION info;
  1348. ULONG resultLength;
  1349. PAGED_CODE();
  1350. status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
  1351. PLUGPLAY_REGKEY_DEVICE,
  1352. KEY_READ,
  1353. &deviceHandle
  1354. );
  1355. if (!NT_SUCCESS(status)) {
  1356. goto cleanup;
  1357. }
  1358. RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
  1359. InitializeObjectAttributes(&attributes,
  1360. &unicodeString,
  1361. OBJ_KERNEL_HANDLE,
  1362. deviceHandle,
  1363. NULL
  1364. );
  1365. status = ZwOpenKey(&configHandle,
  1366. KEY_READ,
  1367. &attributes
  1368. );
  1369. ZwClose(deviceHandle);
  1370. if (!NT_SUCCESS(status)) {
  1371. goto cleanup;
  1372. }
  1373. status = PipBuildValueName(DeviceInfo, IRQFLAGS_VALUE_NAME, &Buffer);
  1374. if (!NT_SUCCESS(status)) {
  1375. ZwClose(configHandle);
  1376. Buffer = NULL;
  1377. goto cleanup;
  1378. }
  1379. RtlInitUnicodeString(&unicodeString,Buffer);
  1380. status = ZwQueryValueKey(configHandle,
  1381. &unicodeString,
  1382. KeyValuePartialInformation,
  1383. returnBuffer,
  1384. sizeof(returnBuffer),
  1385. &resultLength
  1386. );
  1387. ZwClose(configHandle);
  1388. if (NT_SUCCESS(status)) {
  1389. ULONG Temp;
  1390. info = (PKEY_VALUE_PARTIAL_INFORMATION) returnBuffer;
  1391. ASSERT(info->DataLength == sizeof(ULONG));
  1392. Temp = *((PULONG) info->Data);
  1393. ASSERT(!(Temp & 0xFFFF0000));
  1394. *IrqFlags = (USHORT) Temp;
  1395. DebugPrint((DEBUG_IRQ, "Got Irq Flags of %d for %ws\n",
  1396. (ULONG) *IrqFlags,
  1397. unicodeString.Buffer));
  1398. } else {
  1399. DebugPrint((DEBUG_IRQ, "Failed to get irq flags for %ws\n",
  1400. unicodeString.Buffer));
  1401. }
  1402. cleanup:
  1403. if (Buffer != NULL) {
  1404. ExFreePool(Buffer);
  1405. }
  1406. return status;
  1407. }
  1408. VOID
  1409. PipResetGlobals (
  1410. VOID
  1411. )
  1412. {
  1413. PipReadDataPort = PipCommandPort = PipAddressPort = NULL;
  1414. PipRDPNode = NULL;
  1415. }
  1416. #endif
  1417. NTSTATUS
  1418. PipOpenRegistryKey(
  1419. OUT PHANDLE Handle,
  1420. IN HANDLE BaseHandle OPTIONAL,
  1421. IN PUNICODE_STRING KeyName,
  1422. IN ACCESS_MASK DesiredAccess,
  1423. IN BOOLEAN Create
  1424. )
  1425. /*++
  1426. Routine Description:
  1427. Opens or creates a VOLATILE registry key using the name passed in based
  1428. at the BaseHandle node.
  1429. Arguments:
  1430. Handle - Pointer to the handle which will contain the registry key that
  1431. was opened.
  1432. BaseHandle - Handle to the base path from which the key must be opened.
  1433. KeyName - Name of the Key that must be opened/created.
  1434. DesiredAccess - Specifies the desired access that the caller needs to
  1435. the key.
  1436. Create - Determines if the key is to be created if it does not exist.
  1437. Return Value:
  1438. The function value is the final status of the operation.
  1439. --*/
  1440. {
  1441. OBJECT_ATTRIBUTES objectAttributes;
  1442. ULONG disposition;
  1443. PAGED_CODE();
  1444. //
  1445. // Initialize the object for the key.
  1446. //
  1447. InitializeObjectAttributes( &objectAttributes,
  1448. KeyName,
  1449. OBJ_CASE_INSENSITIVE,
  1450. BaseHandle,
  1451. (PSECURITY_DESCRIPTOR) NULL );
  1452. //
  1453. // Create the key or open it, as appropriate based on the caller's
  1454. // wishes.
  1455. //
  1456. if (Create) {
  1457. return ZwCreateKey( Handle,
  1458. DesiredAccess,
  1459. &objectAttributes,
  1460. 0,
  1461. (PUNICODE_STRING) NULL,
  1462. REG_OPTION_VOLATILE,
  1463. &disposition );
  1464. } else {
  1465. return ZwOpenKey( Handle,
  1466. DesiredAccess,
  1467. &objectAttributes );
  1468. }
  1469. }
  1470. NTSTATUS
  1471. PipGetRegistryValue(
  1472. IN HANDLE KeyHandle,
  1473. IN PWSTR ValueName,
  1474. OUT PKEY_VALUE_FULL_INFORMATION *Information
  1475. )
  1476. /*++
  1477. Routine Description:
  1478. This routine is invoked to retrieve the data for a registry key's value.
  1479. This is done by querying the value of the key with a zero-length buffer
  1480. to determine the size of the value, and then allocating a buffer and
  1481. actually querying the value into the buffer.
  1482. It is the responsibility of the caller to free the buffer.
  1483. Arguments:
  1484. KeyHandle - Supplies the key handle whose value is to be queried
  1485. ValueName - Supplies the null-terminated Unicode name of the value.
  1486. Information - Returns a pointer to the allocated data buffer.
  1487. Return Value:
  1488. The function value is the final status of the query operation.
  1489. --*/
  1490. {
  1491. UNICODE_STRING unicodeString;
  1492. NTSTATUS status;
  1493. PKEY_VALUE_FULL_INFORMATION infoBuffer;
  1494. ULONG keyValueLength;
  1495. PAGED_CODE();
  1496. *Information = NULL;
  1497. RtlInitUnicodeString( &unicodeString, ValueName );
  1498. //
  1499. // Figure out how big the data value is so that a buffer of the
  1500. // appropriate size can be allocated.
  1501. //
  1502. status = ZwQueryValueKey( KeyHandle,
  1503. &unicodeString,
  1504. KeyValueFullInformation,
  1505. (PVOID) NULL,
  1506. 0,
  1507. &keyValueLength );
  1508. if (status != STATUS_BUFFER_OVERFLOW &&
  1509. status != STATUS_BUFFER_TOO_SMALL) {
  1510. return status;
  1511. }
  1512. //
  1513. // Allocate a buffer large enough to contain the entire key data value.
  1514. //
  1515. infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength );
  1516. if (!infoBuffer) {
  1517. return STATUS_INSUFFICIENT_RESOURCES;
  1518. }
  1519. //
  1520. // Query the data for the key value.
  1521. //
  1522. status = ZwQueryValueKey( KeyHandle,
  1523. &unicodeString,
  1524. KeyValueFullInformation,
  1525. infoBuffer,
  1526. keyValueLength,
  1527. &keyValueLength );
  1528. if (!NT_SUCCESS( status )) {
  1529. ExFreePool( infoBuffer );
  1530. return status;
  1531. }
  1532. //
  1533. // Everything worked, so simply return the address of the allocated
  1534. // buffer to the caller, who is now responsible for freeing it.
  1535. //
  1536. *Information = infoBuffer;
  1537. return STATUS_SUCCESS;
  1538. }
  1539. BOOLEAN
  1540. PiNeedDeferISABridge(
  1541. IN PDRIVER_OBJECT DriverObject,
  1542. IN PDEVICE_OBJECT DeviceObject
  1543. )
  1544. {
  1545. BOOLEAN defer=FALSE;
  1546. NTSTATUS status;
  1547. HANDLE hKey;
  1548. ULONG value;
  1549. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1550. status = IoOpenDeviceRegistryKey (DeviceObject,PLUGPLAY_REGKEY_DEVICE,KEY_READ,&hKey);
  1551. if (NT_SUCCESS (status)) {
  1552. status = PipGetRegistryValue (hKey,&BRIDGE_CHECK_KEY,&keyValueInformation);
  1553. if (NT_SUCCESS (status)) {
  1554. if((keyValueInformation->Type == REG_DWORD) &&
  1555. (keyValueInformation->DataLength >= sizeof(ULONG))) {
  1556. value = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
  1557. //
  1558. // Assume that if the value !0 then the bridge is 'broken'
  1559. //
  1560. defer = (value == 0)?FALSE:TRUE;
  1561. }
  1562. }
  1563. ZwClose(hKey);
  1564. }
  1565. return defer;
  1566. }
  1567. NTSTATUS
  1568. PipValidateResourceList(
  1569. IN PCM_RESOURCE_LIST ResourceList,
  1570. IN ULONG Length
  1571. )
  1572. /*++
  1573. Routine Description:
  1574. This routine verifies that a resource list structure is properly
  1575. formated and the buffer containing it is large enough.
  1576. Arguments:
  1577. ResourceList - The CM_RESOURCE_LIST to verify.
  1578. Length - The length of the ResourceList buffer.
  1579. Return Value:
  1580. STATUS_SUCCESS if the resource list is valid
  1581. STATUS_UNSUCCESSFUL otherwise.
  1582. --*/
  1583. {
  1584. ULONG requiredLength;
  1585. if (Length < sizeof(CM_RESOURCE_LIST)) {
  1586. return STATUS_UNSUCCESSFUL;
  1587. }
  1588. if (ResourceList->Count != 1) {
  1589. return STATUS_UNSUCCESSFUL;
  1590. }
  1591. requiredLength = sizeof(CM_RESOURCE_LIST);
  1592. if (ResourceList->List[0].PartialResourceList.Count > 1) {
  1593. requiredLength += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (ResourceList->List[0].PartialResourceList.Count - 1);
  1594. }
  1595. if (requiredLength > Length) {
  1596. return STATUS_UNSUCCESSFUL;
  1597. }
  1598. return STATUS_SUCCESS;
  1599. }
  1600. #if DBG
  1601. VOID
  1602. PipDebugPrintContinue (
  1603. ULONG Level,
  1604. PCCHAR DebugMessage,
  1605. ...
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. This routine displays debugging message or causes a break.
  1610. Arguments:
  1611. Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only.
  1612. DEBUG_BREAK - displays message and break.
  1613. DebugMessage - supplies a pointer to the debugging message.
  1614. Return Value:
  1615. None.
  1616. --*/
  1617. {
  1618. va_list ap;
  1619. va_start(ap, DebugMessage);
  1620. vDbgPrintEx(DPFLTR_ISAPNP_ID,
  1621. Level,
  1622. DebugMessage,
  1623. ap
  1624. );
  1625. if (Level & DEBUG_BREAK) {
  1626. DbgBreakPoint();
  1627. }
  1628. va_end(ap);
  1629. }
  1630. VOID
  1631. PipDebugPrint (
  1632. ULONG Level,
  1633. PCCHAR DebugMessage,
  1634. ...
  1635. )
  1636. /*++
  1637. Routine Description:
  1638. This routine displays debugging message or causes a break.
  1639. Arguments:
  1640. Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only.
  1641. DEBUG_BREAK - displays message and break.
  1642. DebugMessage - supplies a pointer to the debugging message.
  1643. Return Value:
  1644. None.
  1645. --*/
  1646. {
  1647. va_list ap;
  1648. va_start(ap, DebugMessage);
  1649. vDbgPrintExWithPrefix("ISAPNP: ",
  1650. DPFLTR_ISAPNP_ID,
  1651. Level,
  1652. DebugMessage,
  1653. ap
  1654. );
  1655. if (Level & DEBUG_BREAK) {
  1656. DbgBreakPoint();
  1657. }
  1658. va_end(ap);
  1659. }
  1660. #endif
  1661. VOID
  1662. PipDumpIoResourceDescriptor (
  1663. IN PUCHAR Indent,
  1664. IN PIO_RESOURCE_DESCRIPTOR Desc
  1665. )
  1666. /*++
  1667. Routine Description:
  1668. This routine processes a IO_RESOURCE_DESCRIPTOR and displays it.
  1669. Arguments:
  1670. Indent - # char of indentation.
  1671. Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed.
  1672. Return Value:
  1673. None.
  1674. --*/
  1675. {
  1676. UCHAR c = ' ';
  1677. if (Desc->Option == IO_RESOURCE_ALTERNATIVE) {
  1678. c = 'A';
  1679. } else if (Desc->Option == IO_RESOURCE_PREFERRED) {
  1680. c = 'P';
  1681. }
  1682. switch (Desc->Type) {
  1683. case CmResourceTypePort:
  1684. DebugPrint ((
  1685. DEBUG_RESOURCE,
  1686. "%sIO %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
  1687. Indent, c,
  1688. Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart,
  1689. Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart,
  1690. Desc->u.Port.Alignment,
  1691. Desc->u.Port.Length
  1692. ));
  1693. break;
  1694. case CmResourceTypeMemory:
  1695. DebugPrint ((
  1696. DEBUG_RESOURCE,
  1697. "%sMEM %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
  1698. Indent, c,
  1699. Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart,
  1700. Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart,
  1701. Desc->u.Memory.Alignment,
  1702. Desc->u.Memory.Length
  1703. ));
  1704. break;
  1705. case CmResourceTypeInterrupt:
  1706. DebugPrint ((
  1707. DEBUG_RESOURCE,
  1708. "%sINT %c Min: %x, Max: %x\n",
  1709. Indent, c,
  1710. Desc->u.Interrupt.MinimumVector,
  1711. Desc->u.Interrupt.MaximumVector
  1712. ));
  1713. break;
  1714. case CmResourceTypeDma:
  1715. DebugPrint ((
  1716. DEBUG_RESOURCE,
  1717. "%sDMA %c Min: %x, Max: %x\n",
  1718. Indent, c,
  1719. Desc->u.Dma.MinimumChannel,
  1720. Desc->u.Dma.MaximumChannel
  1721. ));
  1722. break;
  1723. }
  1724. }
  1725. VOID
  1726. PipDumpIoResourceList (
  1727. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList
  1728. )
  1729. /*++
  1730. Routine Description:
  1731. This routine displays Io resource requirements list.
  1732. Arguments:
  1733. IoList - supplies a pointer to the Io resource requirements list to be displayed.
  1734. Return Value:
  1735. None.
  1736. --*/
  1737. {
  1738. PIO_RESOURCE_LIST resList;
  1739. PIO_RESOURCE_DESCRIPTOR resDesc;
  1740. ULONG listCount, count, i, j;
  1741. if (IoList == NULL) {
  1742. return;
  1743. }
  1744. DebugPrint((DEBUG_RESOURCE,
  1745. "Pnp Bios IO Resource Requirements List for Slot %x -\n",
  1746. IoList->SlotNumber
  1747. ));
  1748. DebugPrint((DEBUG_RESOURCE,
  1749. " List Count = %x, Bus Number = %x\n",
  1750. IoList->AlternativeLists,
  1751. IoList->BusNumber
  1752. ));
  1753. listCount = IoList->AlternativeLists;
  1754. resList = &IoList->List[0];
  1755. for (i = 0; i < listCount; i++) {
  1756. DebugPrint((DEBUG_RESOURCE,
  1757. " Version = %x, Revision = %x, Desc count = %x\n",
  1758. resList->Version, resList->Revision, resList->Count
  1759. ));
  1760. resDesc = &resList->Descriptors[0];
  1761. count = resList->Count;
  1762. for (j = 0; j < count; j++) {
  1763. PipDumpIoResourceDescriptor(" ", resDesc);
  1764. resDesc++;
  1765. }
  1766. resList = (PIO_RESOURCE_LIST) resDesc;
  1767. }
  1768. }
  1769. VOID
  1770. PipDumpCmResourceDescriptor (
  1771. IN PUCHAR Indent,
  1772. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. This routine processes a IO_RESOURCE_DESCRIPTOR and displays it.
  1777. Arguments:
  1778. Indent - # char of indentation.
  1779. Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed.
  1780. Return Value:
  1781. None.
  1782. --*/
  1783. {
  1784. switch (Desc->Type) {
  1785. case CmResourceTypePort:
  1786. DebugPrint ((
  1787. DEBUG_RESOURCE,
  1788. "%sIO Start: %x:%08x, Length: %x\n",
  1789. Indent,
  1790. Desc->u.Port.Start.HighPart, Desc->u.Port.Start.LowPart,
  1791. Desc->u.Port.Length
  1792. ));
  1793. break;
  1794. case CmResourceTypeMemory:
  1795. DebugPrint ((
  1796. DEBUG_RESOURCE,
  1797. "%sMEM Start: %x:%08x, Length: %x\n",
  1798. Indent,
  1799. Desc->u.Memory.Start.HighPart, Desc->u.Memory.Start.LowPart,
  1800. Desc->u.Memory.Length
  1801. ));
  1802. break;
  1803. case CmResourceTypeInterrupt:
  1804. DebugPrint ((
  1805. DEBUG_RESOURCE,
  1806. "%sINT Level: %x, Vector: %x, Affinity: %x\n",
  1807. Indent,
  1808. Desc->u.Interrupt.Level,
  1809. Desc->u.Interrupt.Vector,
  1810. Desc->u.Interrupt.Affinity
  1811. ));
  1812. break;
  1813. case CmResourceTypeDma:
  1814. DebugPrint ((
  1815. DEBUG_RESOURCE,
  1816. "%sDMA Channel: %x, Port: %x\n",
  1817. Indent,
  1818. Desc->u.Dma.Channel,
  1819. Desc->u.Dma.Port
  1820. ));
  1821. break;
  1822. }
  1823. }
  1824. VOID
  1825. PipDumpCmResourceList (
  1826. IN PCM_RESOURCE_LIST CmList
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine displays CM resource list.
  1831. Arguments:
  1832. CmList - supplies a pointer to CM resource list
  1833. Return Value:
  1834. None.
  1835. --*/
  1836. {
  1837. PCM_FULL_RESOURCE_DESCRIPTOR fullDesc;
  1838. PCM_PARTIAL_RESOURCE_LIST partialDesc;
  1839. PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
  1840. ULONG count, i;
  1841. if (CmList) {
  1842. fullDesc = &CmList->List[0];
  1843. DebugPrint((DEBUG_RESOURCE,
  1844. "Pnp Bios Cm Resource List -\n"
  1845. ));
  1846. DebugPrint((DEBUG_RESOURCE,
  1847. " List Count = %x, Bus Number = %x\n",
  1848. CmList->Count, fullDesc->BusNumber
  1849. ));
  1850. partialDesc = &fullDesc->PartialResourceList;
  1851. DebugPrint((DEBUG_RESOURCE,
  1852. " Version = %x, Revision = %x, Desc count = %x\n",
  1853. partialDesc->Version, partialDesc->Revision, partialDesc->Count
  1854. ));
  1855. count = partialDesc->Count;
  1856. desc = &partialDesc->PartialDescriptors[0];
  1857. for (i = 0; i < count; i++) {
  1858. PipDumpCmResourceDescriptor(" ", desc);
  1859. desc++;
  1860. }
  1861. }
  1862. }