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.

2506 lines
68 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. detect.c
  5. Abstract:
  6. This module contains the detector for the NT driver.
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. NT Kernel Model Driver only
  11. Revision History:
  12. July 7, 1997 - Complete rewrite
  13. --*/
  14. #include "pch.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, ACPIDetectCouldExtensionBeInRelation)
  17. #pragma alloc_text(PAGE, ACPIDetectFilterMatch)
  18. #pragma alloc_text(PAGE, ACPIDetectPdoMatch)
  19. #endif
  20. //
  21. // This is the root device extension
  22. //
  23. PDEVICE_EXTENSION RootDeviceExtension;
  24. //
  25. // This is the pool that controls the allocations for Device Extensions
  26. //
  27. NPAGED_LOOKASIDE_LIST DeviceExtensionLookAsideList;
  28. //
  29. // This is the list entry for all the surprise removed extensions
  30. //
  31. PDEVICE_EXTENSION AcpiSurpriseRemovedDeviceExtensions[ACPI_MAX_REMOVED_EXTENSIONS];
  32. //
  33. // This is the index into the Surprise Removed Index array
  34. //
  35. ULONG AcpiSurpriseRemovedIndex;
  36. //
  37. // This is the lock that is required when modifying the links between
  38. // the device extension structures
  39. //
  40. KSPIN_LOCK AcpiDeviceTreeLock;
  41. //
  42. // This is the ulong that will remember which S states are supported by the
  43. // system. The convention for using this ulong is that we 1 << SupportedState
  44. // into it
  45. //
  46. ULONG AcpiSupportedSystemStates;
  47. //
  48. // This is where acpi will store the various overrides
  49. //
  50. ULONG AcpiOverrideAttributes;
  51. //
  52. // This is where acpi will store its registry path
  53. //
  54. UNICODE_STRING AcpiRegistryPath;
  55. //
  56. // This is the processor revision string...
  57. //
  58. ANSI_STRING AcpiProcessorString;
  59. NTSTATUS
  60. ACPIDetectCouldExtensionBeInRelation(
  61. IN PDEVICE_EXTENSION DeviceExtension,
  62. IN PDEVICE_RELATIONS DeviceRelations,
  63. IN BOOLEAN RequireADR,
  64. IN BOOLEAN RequireHID,
  65. OUT PDEVICE_OBJECT *PdoObject
  66. )
  67. /*++
  68. Routine Description:
  69. This routine takes a given extension and a set of relations and decides
  70. whether a the given extension *could* be represented in the relation
  71. list. This is done by seeing if any of the passed in relations match
  72. the hardware described by the extension. If the extension's object is
  73. already a member of the list, the corrosponding Pdo will be written
  74. into the PdoObject parameter. If success is returned without a PdoObject,
  75. a filter or Pdo should probably be created (note that this routine does
  76. not check to see if the devices are present).
  77. Arguments:
  78. DeviceExtension - Extension we wish to match in the relation
  79. DeviceRelations - Relations we should examine
  80. RequireADR - If set, nodes must have _ADR's
  81. RequireHID - If set, nodes must have _HID's
  82. PdoObject - Where to store the match if found
  83. Return Value:
  84. NTSTATUS - STATUS_SUCCESS if extension might be or is in list.
  85. PdoObject - Non-Null means that this PDO corrosponds to the passed in
  86. extension.
  87. --*/
  88. {
  89. BOOLEAN match = FALSE;
  90. BOOLEAN testADR = FALSE;
  91. BOOLEAN testHID = FALSE;
  92. NTSTATUS status;
  93. UNICODE_STRING acpiUnicodeID;
  94. ULONG address;
  95. ULONG i;
  96. PAGED_CODE();
  97. ASSERT( PdoObject != NULL);
  98. if (PdoObject == NULL) {
  99. return STATUS_INVALID_PARAMETER_1;
  100. }
  101. *PdoObject = NULL;
  102. //
  103. // Make sure to initialize the UNICODE_STRING
  104. //
  105. RtlZeroMemory( &acpiUnicodeID, sizeof(UNICODE_STRING) );
  106. //
  107. // Check to see if there is an _ADR present
  108. //
  109. if (RequireADR) {
  110. //
  111. // Filters must have _ADR's
  112. //
  113. if ( !(DeviceExtension->Flags & DEV_PROP_ADDRESS) ) {
  114. return STATUS_OBJECT_NAME_NOT_FOUND;
  115. }
  116. }
  117. //
  118. // Check to see if there is an _HID present
  119. //
  120. if (RequireHID) {
  121. //
  122. // Non-Filters require _HID's
  123. //
  124. if (DeviceExtension->DeviceID == NULL ||
  125. !(DeviceExtension->Flags & DEV_PROP_HID) ) {
  126. return STATUS_OBJECT_NAME_NOT_FOUND;
  127. }
  128. }
  129. //
  130. // Check to see if the relation is non-empty. If it isn't, there isn't
  131. // any work to do. This device obviously could be a Pdo child (as opposed
  132. // to a filter) but it sure isn't at the moment.
  133. //
  134. if (DeviceRelations == NULL || DeviceRelations->Count == 0) {
  135. //
  136. // No match
  137. //
  138. return STATUS_SUCCESS;
  139. }
  140. //
  141. // If we get to this point, and there is an _ADR present, we will test with
  142. // it. We also obtain the address at this time
  143. //
  144. if ( (DeviceExtension->Flags & DEV_MASK_ADDRESS) ) {
  145. testADR = TRUE;
  146. status = ACPIGetAddressSync(
  147. DeviceExtension,
  148. &address,
  149. NULL
  150. );
  151. }
  152. //
  153. // If we get to this point, and there is an _HID present, then we will
  154. // test with it. We will build the unicode address at this time
  155. //
  156. if ( (DeviceExtension->Flags & DEV_MASK_HID) ) {
  157. status = ACPIGetPnpIDSyncWide(
  158. DeviceExtension,
  159. &(acpiUnicodeID.Buffer),
  160. &(acpiUnicodeID.Length)
  161. );
  162. if (!NT_SUCCESS(status)) {
  163. return status;
  164. }
  165. //
  166. // Make sure that we have the maximum length of the string
  167. //
  168. acpiUnicodeID.MaximumLength = acpiUnicodeID.Length;
  169. //
  170. // Remember to test fora _HID
  171. //
  172. testHID = TRUE;
  173. }
  174. //
  175. // Loop for all the object in the extension
  176. //
  177. for (i = 0; i < DeviceRelations->Count; i++) {
  178. //
  179. // Assume we don't have a match
  180. //
  181. match = FALSE;
  182. //
  183. // Check to see if we match the address
  184. //
  185. if (testHID) {
  186. status = ACPIMatchHardwareId(
  187. DeviceRelations->Objects[i],
  188. &acpiUnicodeID,
  189. &match
  190. );
  191. if (!NT_SUCCESS(status)) {
  192. //
  193. // If we failed, then I guess we can just ignore it and
  194. // proceed
  195. //
  196. continue;
  197. }
  198. }
  199. //
  200. // Did we match?
  201. //
  202. // NB: the test for AddrObject is a hack specially reserved for
  203. // PCI. The issue is this. Some buses, have no concept of PnP ids
  204. // so the above test will never succeed. However, those buses are
  205. // expected to have ADR, so we can use ADR's to determine if we
  206. // we have a match. So if we don't have a match and we don't have
  207. // an ADR, then we just continue. But if we have ADR and don't have
  208. // a match, we might just have a match, so we will try again
  209. //
  210. if (match == FALSE && testADR == FALSE) {
  211. //
  212. // Then just continue
  213. //
  214. continue;
  215. }
  216. //
  217. // If there is an ADR, then we must check for that as well
  218. //
  219. if (testADR) {
  220. match = FALSE;
  221. status = ACPIMatchHardwareAddress(
  222. DeviceRelations->Objects[i],
  223. address,
  224. &match
  225. );
  226. if (!NT_SUCCESS(status)) {
  227. //
  228. // If we failed, then I guess we
  229. continue;
  230. }
  231. //
  232. // Did we match?
  233. //
  234. if (match == FALSE) {
  235. //
  236. // Then just continue
  237. //
  238. continue;
  239. }
  240. } // if (addrObject ... )
  241. //
  242. // At this point, there is no doubt, there is a match
  243. //
  244. *PdoObject = DeviceRelations->Objects[i];
  245. break ;
  246. } // for
  247. //
  248. // We have exhausted all options --- thus there is no match
  249. //
  250. return STATUS_SUCCESS ;
  251. }
  252. NTSTATUS
  253. ACPIDetectDockDevices(
  254. IN PDEVICE_EXTENSION DeviceExtension,
  255. IN OUT PDEVICE_RELATIONS *DeviceRelations
  256. )
  257. /*++
  258. Routine Description
  259. Arguments:
  260. deviceExtension - The device extension of the object whose
  261. relations we care to know about
  262. DeviceRelations - Pointer to Pointer to the array of device
  263. relations
  264. Return Value:
  265. NTSTATUS
  266. --*/
  267. {
  268. BOOLEAN matchFound;
  269. EXTENSIONLIST_ENUMDATA eled ;
  270. LONG oldReferenceCount;
  271. KIRQL oldIrql;
  272. PDEVICE_OBJECT tempPdo ;
  273. NTSTATUS status = STATUS_SUCCESS;
  274. PDEVICE_EXTENSION providerExtension = NULL;
  275. PDEVICE_EXTENSION targetExtension = NULL;
  276. PDEVICE_RELATIONS currentRelations = NULL;
  277. PDEVICE_RELATIONS newRelations = NULL;
  278. PLIST_ENTRY listEntry = NULL;
  279. ULONG i = 0;
  280. ULONG j = 0;
  281. ULONG index = 0;
  282. ULONG newRelationSize = 0;
  283. ULONG deviceStatus;
  284. //
  285. // Determine the current size of the device relation (if any exists)
  286. //
  287. if (DeviceRelations != NULL && *DeviceRelations != NULL) {
  288. //
  289. // We need this value to help us build an MDL. After that is done,
  290. // we will refetch it
  291. //
  292. currentRelations = (*DeviceRelations);
  293. newRelationSize = currentRelations->Count;
  294. }
  295. ACPIExtListSetupEnum(
  296. &eled,
  297. &(DeviceExtension->ChildDeviceList),
  298. &AcpiDeviceTreeLock,
  299. SiblingDeviceList,
  300. WALKSCHEME_REFERENCE_ENTRIES
  301. ) ;
  302. for(providerExtension = ACPIExtListStartEnum(&eled);
  303. ACPIExtListTestElement(&eled, (BOOLEAN) NT_SUCCESS(status));
  304. providerExtension = ACPIExtListEnumNext(&eled)) {
  305. if (providerExtension == NULL) {
  306. ACPIExtListExitEnumEarly( &eled );
  307. break;
  308. }
  309. //
  310. // Only profile providers for this walk...
  311. //
  312. if (!(providerExtension->Flags & DEV_PROP_DOCK)) {
  313. continue;
  314. }
  315. //
  316. // Is it physically present?
  317. //
  318. status = ACPIGetDevicePresenceSync(
  319. providerExtension,
  320. (PVOID *) &deviceStatus,
  321. NULL
  322. );
  323. if (!(providerExtension->Flags & DEV_MASK_NOT_PRESENT)) {
  324. //
  325. // This profile provider should be in the list
  326. //
  327. if (providerExtension->DeviceObject == NULL) {
  328. //
  329. // Build it
  330. //
  331. status = ACPIBuildPdo(
  332. DeviceExtension->DeviceObject->DriverObject,
  333. providerExtension,
  334. DeviceExtension->DeviceObject,
  335. FALSE
  336. );
  337. if (!NT_SUCCESS(status)) {
  338. ASSERT(providerExtension->DeviceObject == NULL) ;
  339. }
  340. }
  341. if (providerExtension->DeviceObject != NULL) {
  342. if (!ACPIExtListIsMemberOfRelation(
  343. providerExtension->DeviceObject,
  344. currentRelations
  345. )) {
  346. newRelationSize++;
  347. }
  348. }
  349. } // if (providerExtension ... )
  350. }
  351. if (!NT_SUCCESS(status)) {
  352. //
  353. // Hmm... Let the world know that this happened
  354. //
  355. ACPIDevPrint( (
  356. ACPI_PRINT_FAILURE,
  357. providerExtension,
  358. "ACPIDetectDockDevices: ACPIBuildPdo = %08lx\n",
  359. status
  360. ) );
  361. return status;
  362. }
  363. //
  364. // At this point, we can see if we need to change the size of the
  365. // device relations
  366. //
  367. if ( (currentRelations != NULL && newRelationSize == currentRelations->Count) ||
  368. (currentRelations == NULL && newRelationSize == 0) ) {
  369. //
  370. // Done
  371. //
  372. return STATUS_SUCCESS;
  373. }
  374. //
  375. // Determine the size of the new relations. Use index as a
  376. // scratch buffer
  377. //
  378. index = sizeof(DEVICE_RELATIONS) +
  379. ( sizeof(PDEVICE_OBJECT) * (newRelationSize - 1) );
  380. //
  381. // Allocate the new device relation buffer. Use nonpaged pool since we
  382. // are at dispatch
  383. //
  384. newRelations = ExAllocatePoolWithTag(
  385. NonPagedPool,
  386. index,
  387. ACPI_DEVICE_POOLTAG
  388. );
  389. if (newRelations == NULL) {
  390. //
  391. // Return failure
  392. //
  393. return STATUS_INSUFFICIENT_RESOURCES;
  394. }
  395. //
  396. // Initialize DeviceRelations data structure
  397. //
  398. RtlZeroMemory( newRelations, index );
  399. //
  400. // If there are existing relations, we must determine
  401. if (currentRelations) {
  402. //
  403. // Copy old relations, and determine the starting index for the
  404. // first of the PDOs created by this driver. We will put off freeing
  405. // the old relations till we are no longer holding the lock
  406. //
  407. RtlCopyMemory(
  408. newRelations->Objects,
  409. currentRelations->Objects,
  410. currentRelations->Count * sizeof(PDEVICE_OBJECT)
  411. );
  412. index = currentRelations->Count;
  413. j = currentRelations->Count;
  414. } else {
  415. //
  416. // There will not be a lot of work to do in this case
  417. //
  418. index = j = 0;
  419. }
  420. ACPIExtListSetupEnum(
  421. &eled,
  422. &(DeviceExtension->ChildDeviceList),
  423. &AcpiDeviceTreeLock,
  424. SiblingDeviceList,
  425. WALKSCHEME_HOLD_SPINLOCK
  426. ) ;
  427. //
  428. // We need the spin lock so that we can walk the tree again. This time
  429. // we don't need to let it go until we are done since we don't need
  430. // to call anything that will at PASSIVE_LEVEL
  431. //
  432. for(providerExtension = ACPIExtListStartEnum(&eled);
  433. ACPIExtListTestElement(&eled, (BOOLEAN) (newRelationSize!=index));
  434. providerExtension = ACPIExtListEnumNext(&eled)) {
  435. //
  436. // The only objects that we care about are those that are marked as
  437. // PDOs and have a physical object associated with them
  438. //
  439. if (!(providerExtension->Flags & DEV_MASK_NOT_PRESENT) &&
  440. (providerExtension->Flags & DEV_PROP_DOCK) &&
  441. providerExtension->DeviceObject != NULL ) {
  442. //
  443. // We don't ObReferenceO here because we are still at
  444. // dispatch level (and for efficiency's sake, we don't
  445. // want to drop down)
  446. //
  447. newRelations->Objects[index] =
  448. providerExtension->PhysicalDeviceObject;
  449. //
  450. // Update the location for the next object in the
  451. // relation
  452. //
  453. index++ ;
  454. } // if (providerExtension->Flags ... )
  455. } // for
  456. //
  457. // Update the size of the relations by the number of matches that we
  458. // successfully made
  459. //
  460. newRelations->Count = index;
  461. newRelationSize = index;
  462. //
  463. // We have to reference all of the objects that we added
  464. //
  465. index = (currentRelations != NULL ? currentRelations->Count : 0);
  466. for (; index < newRelationSize; index++) {
  467. //
  468. // Attempt to reference the object
  469. //
  470. status = ObReferenceObjectByPointer(
  471. newRelations->Objects[index],
  472. 0,
  473. NULL,
  474. KernelMode
  475. );
  476. if (!NT_SUCCESS(status) ) {
  477. PDEVICE_OBJECT tempDeviceObject;
  478. //
  479. // Hmm... Let the world know that this happened
  480. //
  481. ACPIPrint( (
  482. ACPI_PRINT_FAILURE,
  483. "ACPIDetectDockDevices: ObjReferenceObject(0x%08lx) "
  484. "= 0x%08lx\n",
  485. newRelations->Objects[index],
  486. status
  487. ) );
  488. //
  489. // Swap the bad element for the last one in the chain
  490. //
  491. newRelations->Count--;
  492. tempDeviceObject = newRelations->Objects[newRelations->Count];
  493. newRelations->Objects[newRelations->Count] =
  494. newRelations->Objects[index];
  495. newRelations->Objects[index] = tempDeviceObject;
  496. }
  497. }
  498. //
  499. // Free the old device relations (if it is present)
  500. //
  501. if (currentRelations) {
  502. ExFreePool( *DeviceRelations );
  503. }
  504. //
  505. // Update the device relation pointer
  506. //
  507. *DeviceRelations = newRelations;
  508. //
  509. // Done
  510. //
  511. return STATUS_SUCCESS;
  512. }
  513. VOID
  514. ACPIDetectDuplicateADR(
  515. IN PDEVICE_EXTENSION DeviceExtension
  516. )
  517. /*++
  518. Routine Description:
  519. This routine looks at all the sibling devices of the specified
  520. device and determines if there are devices with duplicate _ADRs
  521. Arguments:
  522. DeviceExtension - The DeviceExtension that we are trying to detect
  523. duplicate's on
  524. Return Value:
  525. VOID
  526. --*/
  527. {
  528. BOOLEAN resetDeviceAddress = FALSE;
  529. EXTENSIONLIST_ENUMDATA eled;
  530. PDEVICE_EXTENSION childExtension;
  531. PDEVICE_EXTENSION parentExtension = DeviceExtension->ParentExtension;
  532. //
  533. // Is this the root of the device tree?
  534. //
  535. if (parentExtension == NULL) {
  536. return;
  537. }
  538. //
  539. // Do we fail to eject a PDO for this device? Or does this device not have
  540. // an _ADR?
  541. //
  542. if ( (DeviceExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
  543. (DeviceExtension->Flags & DEV_TYPE_NOT_PRESENT) ||
  544. !(DeviceExtension->Flags & DEV_MASK_ADDRESS) ) {
  545. return;
  546. }
  547. //
  548. // Walk the children --- spinlock is taken
  549. //
  550. ACPIExtListSetupEnum(
  551. &eled,
  552. &(parentExtension->ChildDeviceList),
  553. &AcpiDeviceTreeLock,
  554. SiblingDeviceList,
  555. WALKSCHEME_HOLD_SPINLOCK
  556. );
  557. for (childExtension = ACPIExtListStartEnum( &eled );
  558. ACPIExtListTestElement( &eled, TRUE );
  559. childExtension = ACPIExtListEnumNext( &eled ) ) {
  560. if (childExtension == NULL) {
  561. ACPIExtListExitEnumEarly( &eled );
  562. break;
  563. }
  564. //
  565. // If the child and target extension matches, then we are looking
  566. // at ourselves. This is not a very interesting comparison
  567. //
  568. if (childExtension == DeviceExtension) {
  569. continue;
  570. }
  571. //
  572. // Does the child have an _ADR? If not, then its boring to compare
  573. //
  574. if ( (childExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
  575. (childExtension->Flags & DEV_MASK_NOT_PRESENT) ||
  576. (childExtension->Flags & DEV_PROP_UNLOADING) ||
  577. !(childExtension->Flags & DEV_PROP_ADDRESS) ) {
  578. continue;
  579. }
  580. //
  581. // If we don't have matching ADRs, this is a boring comparison to make
  582. // also
  583. //
  584. if (childExtension->Address != DeviceExtension->Address) {
  585. continue;
  586. }
  587. //
  588. // At this point, we are hosed. We have two different devices with the
  589. // same ADR. Very Bad. We need to remember that we have a match so that
  590. // we can reset the current device extension address as well, once
  591. // we have scanned all the siblings
  592. //
  593. ACPIDevPrint( (
  594. ACPI_PRINT_FAILURE,
  595. DeviceExtension,
  596. "ACPIDetectDuplicateADR - matches with %08lx\n",
  597. childExtension
  598. ) );
  599. resetDeviceAddress = TRUE;
  600. //
  601. // Reset the child's Address. We do this by OR'ing in 0xFFFF which
  602. // effectively resets the Function Number to -1.
  603. //
  604. childExtension->Address |= 0xFFFF;
  605. ACPIInternalUpdateFlags(
  606. &(childExtension->Flags),
  607. DEV_PROP_FIXED_ADDRESS,
  608. FALSE
  609. );
  610. }
  611. //
  612. // Do we reset the DeviceExtension's address?
  613. //
  614. if (resetDeviceAddress) {
  615. DeviceExtension->Address |= 0xFFFF;
  616. ACPIInternalUpdateFlags(
  617. &(DeviceExtension->Flags),
  618. DEV_PROP_FIXED_ADDRESS,
  619. FALSE
  620. );
  621. }
  622. }
  623. VOID
  624. ACPIDetectDuplicateHID(
  625. IN PDEVICE_EXTENSION DeviceExtension
  626. )
  627. /*++
  628. Routine Description:
  629. This routine looks at all the sibling devices of the specified
  630. device and determines if there are devices with duplicate HIDs and
  631. UIDs
  632. Arguments:
  633. DeviceExtension - The DeviceExtension that we are trying to detect
  634. duplicate's on
  635. Return Value:
  636. VOID -or- Bugcheck
  637. --*/
  638. {
  639. EXTENSIONLIST_ENUMDATA eled;
  640. PDEVICE_EXTENSION childExtension;
  641. PDEVICE_EXTENSION parentExtension = DeviceExtension->ParentExtension;
  642. //
  643. // Is this the root of the device tree?
  644. //
  645. if (parentExtension == NULL) {
  646. return;
  647. }
  648. //
  649. // Do we fail to eject a PDO for this device? Or does this device not have
  650. // an _HID?
  651. //
  652. if ( (DeviceExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
  653. (DeviceExtension->Flags & DEV_MASK_NOT_PRESENT) ||
  654. !(DeviceExtension->Flags & DEV_MASK_HID) ) {
  655. return;
  656. }
  657. //
  658. // Walk the children --- spinlock is taken
  659. //
  660. ACPIExtListSetupEnum(
  661. &eled,
  662. &(parentExtension->ChildDeviceList),
  663. &AcpiDeviceTreeLock,
  664. SiblingDeviceList,
  665. WALKSCHEME_HOLD_SPINLOCK
  666. );
  667. for (childExtension = ACPIExtListStartEnum( &eled );
  668. ACPIExtListTestElement( &eled, TRUE );
  669. childExtension = ACPIExtListEnumNext( &eled ) ) {
  670. if (childExtension == NULL) {
  671. ACPIExtListExitEnumEarly( &eled );
  672. break;
  673. }
  674. //
  675. // If the child and target extension matches, then we are looking
  676. // at ourselves. This is not a very interesting comparison
  677. //
  678. if (childExtension == DeviceExtension) {
  679. continue;
  680. }
  681. //
  682. // Does the child have an _HID? If not, then its boring to compare
  683. //
  684. if ( (childExtension->Flags & DEV_TYPE_NEVER_PRESENT) ||
  685. (childExtension->Flags & DEV_MASK_NOT_PRESENT) ||
  686. (childExtension->Flags & DEV_PROP_UNLOADING) ||
  687. !(childExtension->Flags & DEV_MASK_HID) ) {
  688. continue;
  689. }
  690. //
  691. // If we don't have matching HIDs, this is a boring comparison to make
  692. // also
  693. //
  694. if (!strstr(childExtension->DeviceID, DeviceExtension->DeviceID) ) {
  695. continue;
  696. }
  697. //
  698. // Work around OSCeola bugs
  699. //
  700. if ( (childExtension->Flags & DEV_MASK_UID) &&
  701. (DeviceExtension->Flags & DEV_MASK_UID) ) {
  702. //
  703. // Check to see if their UIDs match
  704. //
  705. if (strcmp(childExtension->InstanceID, DeviceExtension->InstanceID) ) {
  706. continue;
  707. }
  708. //
  709. // At this point, we are hosed. We have two different devices with the
  710. // same PNP id, but no UIDs. Very bad
  711. //
  712. ACPIDevPrint( (
  713. ACPI_PRINT_CRITICAL,
  714. DeviceExtension,
  715. "ACPIDetectDuplicateHID - has _UID match with %08lx\n"
  716. "\t\tContact the Machine Vendor to get this problem fixed\n",
  717. childExtension
  718. ) );
  719. KeBugCheckEx(
  720. ACPI_BIOS_ERROR,
  721. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  722. (ULONG_PTR) DeviceExtension,
  723. PACKED_UID,
  724. 1
  725. );
  726. }
  727. //
  728. // At this point, we are hosed. We have two different devices with the
  729. // same PNP id, but no UIDs. Very bad
  730. //
  731. ACPIDevPrint( (
  732. ACPI_PRINT_FAILURE,
  733. DeviceExtension,
  734. "ACPIDetectDuplicateHID - matches with %08lx\n",
  735. childExtension
  736. ) );
  737. KeBugCheckEx(
  738. ACPI_BIOS_ERROR,
  739. ACPI_REQUIRED_METHOD_NOT_PRESENT,
  740. (ULONG_PTR) DeviceExtension,
  741. PACKED_UID,
  742. 0
  743. );
  744. //
  745. // Make sure to only muck with the DeviceExtension UID if it doesn't
  746. // already have one
  747. //
  748. if (!(DeviceExtension->Flags & DEV_MASK_UID) ) {
  749. //
  750. // Build a fake instance ID for the device
  751. //
  752. DeviceExtension->InstanceID = ExAllocatePoolWithTag(
  753. NonPagedPool,
  754. 9 * sizeof(UCHAR),
  755. ACPI_STRING_POOLTAG
  756. );
  757. if (DeviceExtension->InstanceID == NULL) {
  758. ACPIDevPrint( (
  759. ACPI_PRINT_CRITICAL,
  760. DeviceExtension,
  761. "ACPIDetectDuplicateHID - no memory!\n"
  762. ) );
  763. ACPIInternalError( ACPI_DETECT );
  764. }
  765. RtlZeroMemory( DeviceExtension->InstanceID, 9 * sizeof(UCHAR) );
  766. sprintf( DeviceExtension->InstanceID, "%lx", DeviceExtension->AcpiObject->dwNameSeg );
  767. //
  768. // Remember that we have a fixed uid
  769. //
  770. ACPIInternalUpdateFlags(
  771. &(DeviceExtension->Flags),
  772. DEV_PROP_FIXED_UID,
  773. FALSE
  774. );
  775. }
  776. //
  777. // Make sure to only muck with the ChildExtension UID if it doesn't
  778. // already have one
  779. //
  780. if (!(childExtension->Flags & DEV_MASK_UID) ) {
  781. //
  782. // Build a fake instance ID for the duplicate
  783. //
  784. childExtension->InstanceID = ExAllocatePoolWithTag(
  785. NonPagedPool,
  786. 9 * sizeof(UCHAR),
  787. ACPI_STRING_POOLTAG
  788. );
  789. if (childExtension->InstanceID == NULL) {
  790. ACPIDevPrint( (
  791. ACPI_PRINT_CRITICAL,
  792. DeviceExtension,
  793. "ACPIDetectDuplicateHID - no memory!\n"
  794. ) );
  795. ACPIInternalError( ACPI_DETECT );
  796. }
  797. RtlZeroMemory( childExtension->InstanceID, 9 * sizeof(UCHAR) );
  798. sprintf( childExtension->InstanceID, "%lx", childExtension->AcpiObject->dwNameSeg );
  799. //
  800. // Update the flags for both devices to indicate the fixed UID
  801. //
  802. ACPIInternalUpdateFlags(
  803. &(childExtension->Flags),
  804. DEV_PROP_FIXED_UID,
  805. FALSE
  806. );
  807. }
  808. }
  809. }
  810. NTSTATUS
  811. ACPIDetectEjectDevices(
  812. IN PDEVICE_EXTENSION DeviceExtension,
  813. IN OUT PDEVICE_RELATIONS *DeviceRelations,
  814. IN PDEVICE_EXTENSION AdditionalExtension OPTIONAL
  815. )
  816. /*++
  817. Routine Description
  818. Arguments:
  819. DeviceExtension - The device extension of the object whose
  820. relations we care to know about
  821. DeviceRelations - Pointer to Pointer to the array of device
  822. relations
  823. AdditionalExtension - If set, non-NULL AdditionalExtension's
  824. DeviceObject will be added to the list (this
  825. is for the profile providers)
  826. ADRIAO N.B 07/14/1999 -
  827. A more clever way to solve the profile provider issue is listed here.
  828. 1) Add a new phase in buildsrc after the _EJD phase, call it PhaseDock
  829. 2) When PhaseDock finds a _DCK node, it creates a seperate extension,
  830. RemoveEntryList's the EjectHead and Inserts the list on the new extension
  831. (ie, new extension hijacks old extensions _EJD's)
  832. 3) New extension adds old as an ejection relation
  833. 4) Old extension adds new as it's *only* ejection relation
  834. (We're not taking this design due to the ship schedule, it's safer to hack
  835. the existing one).
  836. Return Value:
  837. NTSTATUS
  838. --*/
  839. {
  840. BOOLEAN inRelation;
  841. EXTENSIONLIST_ENUMDATA eled ;
  842. LONG oldReferenceCount;
  843. KIRQL oldIrql;
  844. NTSTATUS status;
  845. PDEVICE_OBJECT tempPdo ;
  846. PDEVICE_EXTENSION ejecteeExtension = NULL;
  847. PDEVICE_EXTENSION targetExtension = NULL;
  848. PDEVICE_RELATIONS currentRelations = NULL;
  849. PDEVICE_RELATIONS newRelations = NULL;
  850. PLIST_ENTRY listEntry = NULL;
  851. ULONG i = 0;
  852. ULONG index = 0;
  853. ULONG newRelationSize = 0;
  854. //
  855. // We might not have resolved all our ejection dependencies, so lets do
  856. // that now...
  857. //
  858. ACPIBuildMissingEjectionRelations();
  859. //
  860. // Determine the current size of the device relation (if any exists)
  861. //
  862. if (DeviceRelations != NULL && *DeviceRelations != NULL) {
  863. //
  864. // We need this value to help us build an MDL. After that is done,
  865. // we will refetch it
  866. //
  867. currentRelations = (*DeviceRelations);
  868. newRelationSize = currentRelations->Count;
  869. }
  870. ACPIExtListSetupEnum(
  871. &eled,
  872. &(DeviceExtension->EjectDeviceHead),
  873. &AcpiDeviceTreeLock,
  874. EjectDeviceList,
  875. WALKSCHEME_REFERENCE_ENTRIES
  876. ) ;
  877. for(ejecteeExtension = ACPIExtListStartEnum(&eled);
  878. ACPIExtListTestElement(&eled, TRUE);
  879. ejecteeExtension = ACPIExtListEnumNext(&eled)) {
  880. //
  881. // Is it physically present?
  882. //
  883. if (!(ejecteeExtension->Flags & DEV_MASK_NOT_PRESENT) &&
  884. !(ejecteeExtension->Flags & DEV_PROP_FAILED_INIT) &&
  885. (ejecteeExtension->PhysicalDeviceObject != NULL) ) {
  886. //
  887. // Is there a match between the device relations and the current
  888. // device extension?
  889. //
  890. status = ACPIDetectCouldExtensionBeInRelation(
  891. ejecteeExtension,
  892. currentRelations,
  893. FALSE,
  894. FALSE,
  895. &tempPdo
  896. ) ;
  897. if ( tempPdo == NULL && NT_SUCCESS(status) ) {
  898. //
  899. // We are here if we an extension that does not match any
  900. // of the hardware represented by the current contents of
  901. // the relation.
  902. //
  903. if (ejecteeExtension->PhysicalDeviceObject != NULL) {
  904. inRelation = ACPIExtListIsMemberOfRelation(
  905. ejecteeExtension->PhysicalDeviceObject,
  906. currentRelations
  907. );
  908. if (inRelation == FALSE) {
  909. newRelationSize++;
  910. }
  911. }
  912. }
  913. } // if (ejecteeExtension ... )
  914. }
  915. //
  916. // Do we have an extra device to include in the list?
  917. //
  918. if (ARGUMENT_PRESENT(AdditionalExtension) &&
  919. !(AdditionalExtension->Flags & DEV_MASK_NOT_PRESENT) &&
  920. (AdditionalExtension->PhysicalDeviceObject != NULL)) {
  921. inRelation = ACPIExtListIsMemberOfRelation(
  922. AdditionalExtension->PhysicalDeviceObject,
  923. currentRelations);
  924. if (inRelation == FALSE) {
  925. newRelationSize++;
  926. }
  927. }
  928. //
  929. // At this point, we can see if we need to change the size of the
  930. // device relations
  931. //
  932. if ( (currentRelations != NULL && newRelationSize == currentRelations->Count) ||
  933. (currentRelations == NULL && newRelationSize == 0) ) {
  934. //
  935. // Done
  936. //
  937. return STATUS_SUCCESS;
  938. }
  939. //
  940. // Determine the size of the new relations. Use index as a
  941. // scratch buffer
  942. //
  943. index = sizeof(DEVICE_RELATIONS) +
  944. ( sizeof(PDEVICE_OBJECT) * (newRelationSize - 1) );
  945. //
  946. // Allocate the new device relation buffer. Use nonpaged pool since we
  947. // are at dispatch
  948. //
  949. newRelations = ExAllocatePoolWithTag(
  950. PagedPool,
  951. index,
  952. ACPI_DEVICE_POOLTAG
  953. );
  954. if (newRelations == NULL) {
  955. //
  956. // Return failure
  957. //
  958. return STATUS_INSUFFICIENT_RESOURCES;
  959. }
  960. //
  961. // Initialize DeviceRelations data structure
  962. //
  963. RtlZeroMemory( newRelations, index );
  964. //
  965. // If there are existing relations, we must determine
  966. if (currentRelations) {
  967. //
  968. // Copy old relations, and determine the starting index for the
  969. // first of the PDOs created by this driver. We will put off freeing
  970. // the old relations till we are no longer holding the lock
  971. //
  972. RtlCopyMemory(
  973. newRelations->Objects,
  974. currentRelations->Objects,
  975. currentRelations->Count * sizeof(PDEVICE_OBJECT)
  976. );
  977. index = currentRelations->Count;
  978. } else {
  979. //
  980. // There will not be a lot of work to do in this case
  981. //
  982. index = 0;
  983. }
  984. ACPIExtListSetupEnum(
  985. &eled,
  986. &(DeviceExtension->EjectDeviceHead),
  987. &AcpiDeviceTreeLock,
  988. EjectDeviceList,
  989. WALKSCHEME_REFERENCE_ENTRIES
  990. ) ;
  991. //
  992. // We need the spin lock so that we can walk the tree again. This time
  993. // we don't need to let it go until we are done since we don't need
  994. // to call anything that will at PASSIVE_LEVEL
  995. //
  996. for(ejecteeExtension = ACPIExtListStartEnum(&eled);
  997. ACPIExtListTestElement(&eled, (BOOLEAN) (newRelationSize!=index));
  998. ejecteeExtension = ACPIExtListEnumNext(&eled)) {
  999. if (ejecteeExtension == NULL) {
  1000. ACPIExtListExitEnumEarly( &eled );
  1001. break;
  1002. }
  1003. //
  1004. // The only objects that we care about are those that are marked as
  1005. // PDOs and have a phsyical object associated with them
  1006. //
  1007. if (!(ejecteeExtension->Flags & DEV_MASK_NOT_PRESENT) &&
  1008. !(ejecteeExtension->Flags & DEV_PROP_DOCK) &&
  1009. (ejecteeExtension->PhysicalDeviceObject != NULL) ) {
  1010. //
  1011. // See if the object is already in the relations. Note that it
  1012. // actually correct to use currentRelations for the test instead
  1013. // of newRelations. This is because we only want to compare
  1014. // against those object which were handed to us, not the ones
  1015. // that we added.
  1016. //
  1017. inRelation = ACPIExtListIsMemberOfRelation(
  1018. ejecteeExtension->PhysicalDeviceObject,
  1019. currentRelations
  1020. );
  1021. if (inRelation == FALSE) {
  1022. //
  1023. // We don't ObReferenceO here because we are still at
  1024. // dispatch level (and for efficiency's sake, we don't
  1025. // want to drop down). We also update the location for
  1026. // the next object in the relation
  1027. //
  1028. newRelations->Objects[index++] =
  1029. ejecteeExtension->PhysicalDeviceObject;
  1030. }
  1031. } // if (ejecteeExtension->Flags ... )
  1032. } // for
  1033. //
  1034. // Do we have an extra device to include in the list? If so, add it now
  1035. //
  1036. if (ARGUMENT_PRESENT(AdditionalExtension) &&
  1037. !(AdditionalExtension->Flags & DEV_MASK_NOT_PRESENT) &&
  1038. (AdditionalExtension->PhysicalDeviceObject != NULL)) {
  1039. inRelation = ACPIExtListIsMemberOfRelation(
  1040. AdditionalExtension->PhysicalDeviceObject,
  1041. currentRelations);
  1042. if (inRelation == FALSE) {
  1043. newRelations->Objects[index++] =
  1044. AdditionalExtension->PhysicalDeviceObject;
  1045. }
  1046. }
  1047. //
  1048. // Update the size of the relations by the number of matches that we
  1049. // successfully made
  1050. //
  1051. newRelations->Count = index;
  1052. newRelationSize = index;
  1053. //
  1054. // We have to reference all of the objects that we added
  1055. //
  1056. index = (currentRelations != NULL ? currentRelations->Count : 0);
  1057. for (; index < newRelationSize; index++) {
  1058. //
  1059. // Attempt to reference the object
  1060. //
  1061. status = ObReferenceObjectByPointer(
  1062. newRelations->Objects[index],
  1063. 0,
  1064. NULL,
  1065. KernelMode
  1066. );
  1067. if (!NT_SUCCESS(status) ) {
  1068. PDEVICE_OBJECT tempDeviceObject;
  1069. //
  1070. // Hmm... Let the world know that this happened
  1071. //
  1072. ACPIPrint( (
  1073. ACPI_PRINT_FAILURE,
  1074. "ACPIDetectEjectDevices: ObjReferenceObject(0x%08lx) "
  1075. "= 0x%08lx\n",
  1076. newRelations->Objects[index],
  1077. status
  1078. ) );
  1079. //
  1080. // Swap the bad element for the last one in the chain
  1081. //
  1082. newRelations->Count--;
  1083. tempDeviceObject = newRelations->Objects[newRelations->Count];
  1084. newRelations->Objects[newRelations->Count] =
  1085. newRelations->Objects[index];
  1086. newRelations->Objects[index] = tempDeviceObject;
  1087. }
  1088. }
  1089. //
  1090. // Free the old device relations (if it is present)
  1091. //
  1092. if (currentRelations) {
  1093. ExFreePool( *DeviceRelations );
  1094. }
  1095. //
  1096. // Update the device relation pointer
  1097. //
  1098. *DeviceRelations = newRelations;
  1099. //
  1100. // Done
  1101. //
  1102. return STATUS_SUCCESS;
  1103. }
  1104. NTSTATUS
  1105. ACPIDetectFilterDevices(
  1106. IN PDEVICE_OBJECT DeviceObject,
  1107. IN PDEVICE_RELATIONS DeviceRelations
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. This is one of the two routines that is used for QueryDeviceRelations.
  1112. This routine is called on the IRPs way *up* the stack. Its purpose is
  1113. to create FILTERS for device which are in the relation and are known
  1114. to ACPI
  1115. Arguments:
  1116. DeviceObject - The object whose relations we care to know about
  1117. DeviceRelations - Pointer to array of device relations
  1118. Return Value:
  1119. NTSTATUS
  1120. --*/
  1121. {
  1122. LONG oldReferenceCount = 0;
  1123. KIRQL oldIrql;
  1124. NTSTATUS status;
  1125. PDEVICE_EXTENSION deviceExtension = NULL;
  1126. PDEVICE_EXTENSION parentExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1127. PDEVICE_EXTENSION targetExtension = NULL;
  1128. PDEVICE_OBJECT pdoObject = NULL;
  1129. PLIST_ENTRY listEntry = NULL;
  1130. ULONG deviceStatus;
  1131. //
  1132. // Sync with the build surprise removal code...
  1133. //
  1134. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1135. //
  1136. // Do we have missing children?
  1137. //
  1138. if (parentExtension->Flags & DEV_PROP_REBUILD_CHILDREN) {
  1139. ACPIInternalUpdateFlags(
  1140. &(parentExtension->Flags),
  1141. DEV_PROP_REBUILD_CHILDREN,
  1142. TRUE
  1143. );
  1144. ACPIBuildMissingChildren( parentExtension );
  1145. }
  1146. //
  1147. // Done with the sync part
  1148. //
  1149. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1150. //
  1151. // No matter what, we must make sure that we are synchronized with the
  1152. // build engine.
  1153. //
  1154. status = ACPIBuildFlushQueue( parentExtension );
  1155. if (!NT_SUCCESS(status)) {
  1156. ACPIDevPrint( (
  1157. ACPI_PRINT_FAILURE,
  1158. parentExtension,
  1159. "ACPIBuildFlushQueue = %08lx\n",
  1160. status
  1161. ) );
  1162. return status;
  1163. }
  1164. //
  1165. // We must walk the tree at dispatch level <sigh>
  1166. //
  1167. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1168. //
  1169. // Sanity check
  1170. //
  1171. if (IsListEmpty( &(parentExtension->ChildDeviceList) ) ) {
  1172. //
  1173. // We have nothing to do here
  1174. //
  1175. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1176. return STATUS_SUCCESS;
  1177. }
  1178. //
  1179. // Grab the first child
  1180. //
  1181. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1182. parentExtension->ChildDeviceList.Flink,
  1183. DEVICE_EXTENSION,
  1184. SiblingDeviceList
  1185. );
  1186. //
  1187. // Always update the reference count to make sure that no one will
  1188. // ever delete the node without our knowing it
  1189. //
  1190. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  1191. //
  1192. // Relinquish the spin lock
  1193. //
  1194. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1195. //
  1196. // Loop until we get back to the parent
  1197. //
  1198. while (deviceExtension != NULL) {
  1199. //
  1200. // Note: Do *NOT* set the NOT_ENUMERATED bit here. We have already
  1201. // set the bit in ACPIDetectPdoDevices()
  1202. //
  1203. //
  1204. // Update the device status. Make sure that we call at PASSIVE
  1205. // level, since we will be calling synchronously
  1206. //
  1207. status = ACPIGetDevicePresenceSync(
  1208. deviceExtension,
  1209. (PVOID *) &deviceStatus,
  1210. NULL
  1211. );
  1212. if ( NT_SUCCESS(status) &&
  1213. !(deviceExtension->Flags & DEV_MASK_NOT_PRESENT) ) {
  1214. //
  1215. // Is there a match between the device relations and the current
  1216. // device extension?
  1217. //
  1218. status = ACPIDetectFilterMatch(
  1219. deviceExtension,
  1220. DeviceRelations,
  1221. &pdoObject
  1222. );
  1223. if (NT_SUCCESS(status) ) {
  1224. if (pdoObject != NULL) {
  1225. //
  1226. // We have to build a filter object here
  1227. //
  1228. status = ACPIBuildFilter(
  1229. DeviceObject->DriverObject,
  1230. deviceExtension,
  1231. pdoObject
  1232. );
  1233. if (!NT_SUCCESS(status)) {
  1234. ACPIDevPrint( (
  1235. ACPI_PRINT_FAILURE,
  1236. deviceExtension,
  1237. "ACPIDetectFilterDevices = %08lx\n",
  1238. status
  1239. ) );
  1240. }
  1241. }
  1242. } else {
  1243. ACPIDevPrint( (
  1244. ACPI_PRINT_FAILURE,
  1245. deviceExtension,
  1246. "ACPIDetectFilterMatch = 0x%08lx\n",
  1247. status
  1248. ) );
  1249. }
  1250. }
  1251. //
  1252. // Reacquire the spin lock
  1253. //
  1254. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1255. //
  1256. // Decrement the reference count on the node
  1257. //
  1258. oldReferenceCount = InterlockedDecrement(
  1259. &(deviceExtension->ReferenceCount)
  1260. );
  1261. //
  1262. // Check to see if we have gone all the way around the list
  1263. // list
  1264. if (deviceExtension->SiblingDeviceList.Flink ==
  1265. &(parentExtension->ChildDeviceList) ) {
  1266. //
  1267. // Remove the node, if necessary
  1268. //
  1269. if (oldReferenceCount == 0) {
  1270. //
  1271. // Free the memory allocated by the extension
  1272. //
  1273. ACPIInitDeleteDeviceExtension( deviceExtension );
  1274. }
  1275. //
  1276. // Release the spin lock
  1277. //
  1278. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1279. //
  1280. // Stop the loop
  1281. //
  1282. break;
  1283. } // if
  1284. //
  1285. // Next element
  1286. //
  1287. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1288. deviceExtension->SiblingDeviceList.Flink,
  1289. DEVICE_EXTENSION,
  1290. SiblingDeviceList
  1291. );
  1292. //
  1293. // Remove the old node, if necessary
  1294. //
  1295. if (oldReferenceCount == 0) {
  1296. //
  1297. // Unlink the extension from the tree
  1298. //
  1299. listEntry = RemoveTailList(
  1300. &(deviceExtension->SiblingDeviceList)
  1301. );
  1302. //
  1303. // It is not possible for this to point to the parent without
  1304. // having succeeded the previous test
  1305. //
  1306. targetExtension = CONTAINING_RECORD(
  1307. listEntry,
  1308. DEVICE_EXTENSION,
  1309. SiblingDeviceList
  1310. );
  1311. //
  1312. // Free the memory allocated for the extension
  1313. //
  1314. ACPIInitDeleteDeviceExtension( targetExtension );
  1315. }
  1316. //
  1317. // Increment the reference count on this node so that it too
  1318. // cannot be deleted
  1319. //
  1320. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  1321. //
  1322. // Now, we release the spin lock
  1323. //
  1324. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1325. } // while
  1326. //
  1327. // We succeeded
  1328. //
  1329. return STATUS_SUCCESS;
  1330. }
  1331. NTSTATUS
  1332. ACPIDetectFilterMatch(
  1333. IN PDEVICE_EXTENSION DeviceExtension,
  1334. IN PDEVICE_RELATIONS DeviceRelations,
  1335. OUT PDEVICE_OBJECT *PdoObject
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. This routine takes a given extension and a set of relations and decides
  1340. whether a new filter should be attached to one of the PDO's listed in
  1341. the relation list.
  1342. Arguments:
  1343. DeviceExtension - Extension we wish to match in the relation
  1344. DeviceRelations - Relations we should examine
  1345. PdoObject - Where to store the match
  1346. Return Value:
  1347. NTSTATUS
  1348. PdoObject - Non-Null means that PdoObject needs a filter attached to it.
  1349. --*/
  1350. {
  1351. NTSTATUS status;
  1352. PAGED_CODE();
  1353. ASSERT( PdoObject != NULL);
  1354. if (PdoObject == NULL) {
  1355. return STATUS_INVALID_PARAMETER_1;
  1356. }
  1357. *PdoObject = NULL;
  1358. //
  1359. // For this to work, we must set the DEV_TYPE_NOT_FOUND flag when we
  1360. // first create the device and at any time when there is no device object
  1361. // associated with the extension
  1362. //
  1363. if ( !(DeviceExtension->Flags & DEV_TYPE_NOT_FOUND) ||
  1364. (DeviceExtension->Flags & DEV_PROP_DOCK) ||
  1365. DeviceExtension->DeviceObject != NULL) {
  1366. ULONG count;
  1367. //
  1368. // If we don't have any relations, then we can't match anything
  1369. //
  1370. if (DeviceRelations == NULL || DeviceRelations->Count == 0) {
  1371. return STATUS_SUCCESS;
  1372. }
  1373. //
  1374. // Look at all the PDOs in the relation and see if they match what
  1375. // a device object that we are attached to
  1376. //
  1377. for (count = 0; count < DeviceRelations->Count; count++) {
  1378. if (DeviceExtension->PhysicalDeviceObject == DeviceRelations->Objects[count]) {
  1379. //
  1380. // Clear the flag that says that we haven't enumerated
  1381. // this
  1382. //
  1383. ACPIInternalUpdateFlags(
  1384. &(DeviceExtension->Flags),
  1385. DEV_TYPE_NOT_ENUMERATED,
  1386. TRUE
  1387. );
  1388. }
  1389. }
  1390. return STATUS_SUCCESS;
  1391. }
  1392. status = ACPIDetectCouldExtensionBeInRelation(
  1393. DeviceExtension,
  1394. DeviceRelations,
  1395. TRUE,
  1396. FALSE,
  1397. PdoObject
  1398. ) ;
  1399. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1400. //
  1401. // Harmless cleanup, we just checked a node on a non-ACPI bus that
  1402. // doesn't have an _ADR (likely it has a _HID, and will make it's
  1403. // own PDO)
  1404. //
  1405. status = STATUS_SUCCESS;
  1406. }
  1407. return status ;
  1408. }
  1409. NTSTATUS
  1410. ACPIDetectPdoDevices(
  1411. IN PDEVICE_OBJECT DeviceObject,
  1412. IN PDEVICE_RELATIONS *DeviceRelations
  1413. )
  1414. /*++
  1415. Routine Description
  1416. This is one of the two functions that is used for QueryDeviceRelations.
  1417. This routine is called on the IRPs way *down* the stack. Its purpose is
  1418. to create PDOs for device which are not in the relation
  1419. Arguments:
  1420. DeviceObject - The object whose relations we care to know about
  1421. DeviceRelations - Pointer to Pointer to the array of device relations
  1422. Return Value:
  1423. NTSTATUS
  1424. --*/
  1425. {
  1426. BOOLEAN matchFound;
  1427. LONG oldReferenceCount;
  1428. KIRQL oldIrql;
  1429. NTSTATUS status;
  1430. PDEVICE_EXTENSION deviceExtension = NULL;
  1431. PDEVICE_EXTENSION parentExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  1432. PDEVICE_EXTENSION targetExtension = NULL;
  1433. PDEVICE_RELATIONS currentRelations = NULL;
  1434. PDEVICE_RELATIONS newRelations = NULL;
  1435. PLIST_ENTRY listEntry = NULL;
  1436. ULONG i = 0;
  1437. ULONG j = 0;
  1438. ULONG index = 0;
  1439. ULONG newRelationSize = 0;
  1440. ULONG deviceStatus;
  1441. //
  1442. // Determine the current size of the device relation (if any exists)
  1443. //
  1444. if (DeviceRelations != NULL && *DeviceRelations != NULL) {
  1445. //
  1446. // We need this value to help us build an MDL. After that is done,
  1447. // we will refetch it
  1448. //
  1449. currentRelations = (*DeviceRelations);
  1450. newRelationSize = currentRelations->Count;
  1451. }
  1452. //
  1453. // Sync with the build surprise removal code...
  1454. //
  1455. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1456. //
  1457. // Do we have missing children?
  1458. //
  1459. if (parentExtension->Flags & DEV_PROP_REBUILD_CHILDREN) {
  1460. ACPIInternalUpdateFlags(
  1461. &(parentExtension->Flags),
  1462. DEV_PROP_REBUILD_CHILDREN,
  1463. TRUE
  1464. );
  1465. ACPIBuildMissingChildren( parentExtension );
  1466. }
  1467. //
  1468. // Done with the sync part
  1469. //
  1470. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1471. //
  1472. // The first step is to actually try to make sure that we are currently
  1473. // synchronized with the build engine
  1474. //
  1475. status = ACPIBuildFlushQueue( parentExtension );
  1476. if (!NT_SUCCESS(status)) {
  1477. ACPIDevPrint( (
  1478. ACPI_PRINT_FAILURE,
  1479. parentExtension,
  1480. "ACPIBuildFlushQueue = %08lx\n",
  1481. status
  1482. ) );
  1483. return status;
  1484. }
  1485. //
  1486. // We must walk the tree at dispatch level <sigh>
  1487. //
  1488. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1489. //
  1490. // Sanity check
  1491. //
  1492. if (IsListEmpty( &(parentExtension->ChildDeviceList) ) ) {
  1493. //
  1494. // We have nothing to do here
  1495. //
  1496. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1497. //
  1498. // Do we currently have some relations? If so, then we just return
  1499. // those and don't need to add anything to them
  1500. //
  1501. if (currentRelations) {
  1502. return STATUS_SUCCESS;
  1503. }
  1504. //
  1505. // We still need to return an information context with a count of 0
  1506. //
  1507. newRelations = ExAllocatePoolWithTag(
  1508. NonPagedPool,
  1509. sizeof(DEVICE_RELATIONS),
  1510. ACPI_DEVICE_POOLTAG
  1511. );
  1512. if (newRelations == NULL) {
  1513. //
  1514. // Return failure
  1515. //
  1516. return STATUS_INSUFFICIENT_RESOURCES;
  1517. }
  1518. //
  1519. // Initialize DeviceRelations data structure
  1520. //
  1521. RtlZeroMemory( newRelations, sizeof(DEVICE_RELATIONS) );
  1522. //
  1523. // We don't need to this, but its better to be explicit
  1524. //
  1525. newRelations->Count = 0;
  1526. //
  1527. // Remember the new relations and return
  1528. //
  1529. *DeviceRelations = newRelations;
  1530. return STATUS_SUCCESS;
  1531. }
  1532. //
  1533. // Grab the first child
  1534. //
  1535. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1536. parentExtension->ChildDeviceList.Flink,
  1537. DEVICE_EXTENSION,
  1538. SiblingDeviceList
  1539. );
  1540. //
  1541. // Always update the reference count to make sure that no one will
  1542. // ever delete the node without our knowing it
  1543. //
  1544. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  1545. //
  1546. // Relinquish the spin lock
  1547. //
  1548. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1549. //
  1550. // Loop until we get back to the parent
  1551. //
  1552. while (deviceExtension != NULL) {
  1553. //
  1554. // Always consider the device as never having been enumerated.
  1555. //
  1556. // NOTE:
  1557. // The reason that we do this here (and only here) is because
  1558. // ACPIDetectFilterMatch() is called later on and we need to know
  1559. // which device objects were detected as PDOs and which ones were
  1560. // also detected as Filters. Setting this flag twice would defeat that
  1561. // purpose.
  1562. //
  1563. ACPIInternalUpdateFlags(
  1564. &(deviceExtension->Flags),
  1565. DEV_TYPE_NOT_ENUMERATED,
  1566. FALSE
  1567. );
  1568. //
  1569. // Update the current device status
  1570. //
  1571. status = ACPIGetDevicePresenceSync(
  1572. deviceExtension,
  1573. (PVOID *) &deviceStatus,
  1574. NULL
  1575. );
  1576. //
  1577. // If the device exists
  1578. //
  1579. if ( NT_SUCCESS(status) &&
  1580. !(deviceExtension->Flags & DEV_MASK_NOT_PRESENT) ) {
  1581. //
  1582. // Is there a match between the device relations and the current
  1583. // device extension?
  1584. //
  1585. matchFound = ACPIDetectPdoMatch(
  1586. deviceExtension,
  1587. currentRelations
  1588. );
  1589. if (matchFound == FALSE) {
  1590. //
  1591. // NOTE: we use this here to prevent having to typecase later
  1592. // on
  1593. //
  1594. matchFound =
  1595. (parentExtension->Flags & DEV_TYPE_FDO) ? FALSE : TRUE;
  1596. //
  1597. // Build a new PDO
  1598. //
  1599. status = ACPIBuildPdo(
  1600. DeviceObject->DriverObject,
  1601. deviceExtension,
  1602. parentExtension->PhysicalDeviceObject,
  1603. matchFound
  1604. );
  1605. if (NT_SUCCESS(status)) {
  1606. //
  1607. // We have created a device object that we will have to
  1608. // add into the device relations
  1609. //
  1610. newRelationSize += 1;
  1611. }
  1612. } else if (deviceExtension->Flags & DEV_TYPE_PDO &&
  1613. deviceExtension->DeviceObject != NULL) {
  1614. //
  1615. // Just we because the device_extension matched doesn't mean
  1616. // that it is included in the device relations. What we will
  1617. // do here is look to see if
  1618. // a) the extension is a PDO
  1619. // b) there is a device object associated with the
  1620. // extension
  1621. // c) the device object is *not* in the device relation
  1622. //
  1623. matchFound = FALSE;
  1624. if (currentRelations != NULL) {
  1625. for (index = 0; index < currentRelations->Count; index++) {
  1626. if (currentRelations->Objects[index] ==
  1627. deviceExtension->DeviceObject) {
  1628. //
  1629. // Match found
  1630. //
  1631. matchFound = TRUE;
  1632. break;
  1633. }
  1634. } // for
  1635. }
  1636. //
  1637. // Did we not find a match?
  1638. //
  1639. if (!matchFound) {
  1640. //
  1641. // We need to make sure that its in the relation
  1642. //
  1643. newRelationSize += 1;
  1644. //
  1645. // And at the same time, clear the flag that says that
  1646. // we haven't enumerated this
  1647. //
  1648. ACPIInternalUpdateFlags(
  1649. &(deviceExtension->Flags),
  1650. DEV_TYPE_NOT_ENUMERATED,
  1651. TRUE
  1652. );
  1653. }
  1654. } // if (ACPIDetectPDOMatch ... )
  1655. } // if (deviceExtension ... )
  1656. //
  1657. // Reacquire the spin lock
  1658. //
  1659. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1660. //
  1661. // Decrement the reference count on the node
  1662. //
  1663. oldReferenceCount = InterlockedDecrement(
  1664. &(deviceExtension->ReferenceCount)
  1665. );
  1666. //
  1667. // Check to see if we have gone all the way around the list
  1668. // list
  1669. if (deviceExtension->SiblingDeviceList.Flink ==
  1670. &(parentExtension->ChildDeviceList) ) {
  1671. //
  1672. // Remove the node, if necessary
  1673. //
  1674. if (oldReferenceCount == 0) {
  1675. //
  1676. // Free the memory allocated by the extension
  1677. //
  1678. ACPIInitDeleteDeviceExtension( deviceExtension );
  1679. }
  1680. //
  1681. // Now, we release the spin lock
  1682. //
  1683. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1684. //
  1685. // Stop the loop
  1686. //
  1687. break;
  1688. } // if
  1689. //
  1690. // Next element
  1691. //
  1692. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1693. deviceExtension->SiblingDeviceList.Flink,
  1694. DEVICE_EXTENSION,
  1695. SiblingDeviceList
  1696. );
  1697. //
  1698. // Remove the old node, if necessary
  1699. //
  1700. if (oldReferenceCount == 0) {
  1701. //
  1702. // Unlink the obsolete extension
  1703. //
  1704. listEntry = RemoveTailList(
  1705. &(deviceExtension->SiblingDeviceList)
  1706. );
  1707. //
  1708. // It is not possible for this to point to the parent without
  1709. // having succeeded the previous test
  1710. //
  1711. targetExtension = CONTAINING_RECORD(
  1712. listEntry,
  1713. DEVICE_EXTENSION,
  1714. SiblingDeviceList
  1715. );
  1716. //
  1717. // Deleted the old extension
  1718. //
  1719. ACPIInitDeleteDeviceExtension( targetExtension );
  1720. }
  1721. //
  1722. // Increment the reference count on this node so that it too
  1723. // cannot be deleted
  1724. //
  1725. InterlockedIncrement( &(deviceExtension->ReferenceCount) );
  1726. //
  1727. // Now, we release the spin lock
  1728. //
  1729. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1730. } // while
  1731. //
  1732. // At this point, we can see if we need to change the size of the
  1733. // device relations
  1734. //
  1735. if ( (currentRelations && newRelationSize == currentRelations->Count) ||
  1736. (currentRelations == NULL && newRelationSize == 0) ) {
  1737. //
  1738. // Done
  1739. //
  1740. return STATUS_SUCCESS;
  1741. }
  1742. //
  1743. // Determine the size of the new relations. Use index as a
  1744. // scratch buffer
  1745. //
  1746. index = sizeof(DEVICE_RELATIONS) +
  1747. ( sizeof(PDEVICE_OBJECT) * (newRelationSize - 1) );
  1748. //
  1749. // Allocate the new device relation buffer. Use nonpaged pool since we
  1750. // are at dispatch
  1751. //
  1752. newRelations = ExAllocatePoolWithTag(
  1753. NonPagedPool,
  1754. index,
  1755. ACPI_DEVICE_POOLTAG
  1756. );
  1757. if (newRelations == NULL) {
  1758. //
  1759. // Return failure
  1760. //
  1761. return STATUS_INSUFFICIENT_RESOURCES;
  1762. }
  1763. //
  1764. // Initialize DeviceRelations data structure
  1765. //
  1766. RtlZeroMemory( newRelations, index );
  1767. //
  1768. // If there are existing relations, we must determine
  1769. if (currentRelations) {
  1770. //
  1771. // Copy old relations, and determine the starting index for the
  1772. // first of the PDOs created by this driver. We will put off freeing
  1773. // the old relations till we are no longer holding the lock
  1774. //
  1775. RtlCopyMemory(
  1776. newRelations->Objects,
  1777. currentRelations->Objects,
  1778. currentRelations->Count * sizeof(PDEVICE_OBJECT)
  1779. );
  1780. index = currentRelations->Count;
  1781. j = currentRelations->Count;
  1782. } else {
  1783. //
  1784. // There will not be a lot of work to do in this case
  1785. //
  1786. index = j = 0;
  1787. }
  1788. //
  1789. // We need the spin lock so that we can walk the tree again. This time
  1790. // we don't need to let it go until we are done since we don't need
  1791. // to call anything that will at PASSIVE_LEVEL
  1792. //
  1793. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  1794. //
  1795. // Sanity check
  1796. //
  1797. if (IsListEmpty( &(parentExtension->ChildDeviceList) ) ) {
  1798. //
  1799. // We have nothing to do here
  1800. //
  1801. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1802. ExFreePool( newRelations );
  1803. return STATUS_SUCCESS;
  1804. }
  1805. //
  1806. // Walk the tree one more time and add all PDOs that aren't present in
  1807. // the device relations
  1808. //
  1809. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1810. parentExtension->ChildDeviceList.Flink,
  1811. DEVICE_EXTENSION,
  1812. SiblingDeviceList
  1813. );
  1814. //
  1815. // Loop until we get back to the parent
  1816. //
  1817. while (deviceExtension != NULL) {
  1818. //
  1819. // The only objects that we care about are those that are marked as
  1820. // PDOs and have a phsyical object associated with them
  1821. //
  1822. if (deviceExtension->Flags & DEV_TYPE_PDO &&
  1823. deviceExtension->DeviceObject != NULL &&
  1824. !(deviceExtension->Flags & DEV_MASK_NOT_PRESENT) ) {
  1825. //
  1826. // We don't ObReferenceO here because we are still at
  1827. // dispatch level (and for efficiency's sake, we don't
  1828. // want to drop down)
  1829. //
  1830. newRelations->Objects[index] =
  1831. deviceExtension->DeviceObject;
  1832. //
  1833. // Update the location for the next object in the
  1834. // relation
  1835. //
  1836. index += 1;
  1837. //
  1838. // And at the same time, clear the flag that says that
  1839. // we haven't enumerated this
  1840. //
  1841. ACPIInternalUpdateFlags(
  1842. &(deviceExtension->Flags),
  1843. DEV_TYPE_NOT_ENUMERATED,
  1844. TRUE
  1845. );
  1846. } // if (deviceExtension->Flags ... )
  1847. //
  1848. // Check to see if we have found all the objects that we care
  1849. // about. As in, don't mess the system by walking past the end
  1850. // of the device relations
  1851. //
  1852. if (newRelationSize == index) {
  1853. //
  1854. // Done
  1855. //
  1856. break;
  1857. }
  1858. //
  1859. // Check to see if we have gone all the way around the list
  1860. // list
  1861. if (deviceExtension->SiblingDeviceList.Flink ==
  1862. &(parentExtension->ChildDeviceList) ) {
  1863. break;
  1864. } // if
  1865. //
  1866. // Next element
  1867. //
  1868. deviceExtension = (PDEVICE_EXTENSION) CONTAINING_RECORD(
  1869. deviceExtension->SiblingDeviceList.Flink,
  1870. DEVICE_EXTENSION,
  1871. SiblingDeviceList
  1872. );
  1873. } // while (deviceExtension ... )
  1874. //
  1875. // Update the size of the relations by the number of matches that we
  1876. // successfully made
  1877. //
  1878. newRelations->Count = index;
  1879. newRelationSize = index;
  1880. //
  1881. // At this point, we are well and truely done with the spinlock
  1882. //
  1883. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  1884. //
  1885. // We have to reference all of the objects that we added
  1886. //
  1887. index = (currentRelations != NULL ? currentRelations->Count : 0);
  1888. for (; index < newRelationSize; index++) {
  1889. //
  1890. // Attempt to reference the object
  1891. //
  1892. status = ObReferenceObjectByPointer(
  1893. newRelations->Objects[index],
  1894. 0,
  1895. NULL,
  1896. KernelMode
  1897. );
  1898. if (!NT_SUCCESS(status) ) {
  1899. PDEVICE_OBJECT tempDeviceObject;
  1900. //
  1901. // Hmm... Let the world know that this happened
  1902. //
  1903. ACPIPrint( (
  1904. ACPI_PRINT_FAILURE,
  1905. "ACPIDetectPdoDevices: ObjReferenceObject(0x%08lx) "
  1906. "= 0x%08lx\n",
  1907. newRelations->Objects[index],
  1908. status
  1909. ) );
  1910. //
  1911. // Swap the bad element for the last one in the chain
  1912. //
  1913. newRelations->Count--;
  1914. tempDeviceObject = newRelations->Objects[newRelations->Count];
  1915. newRelations->Objects[newRelations->Count] =
  1916. newRelations->Objects[index];
  1917. newRelations->Objects[index] = tempDeviceObject;
  1918. }
  1919. }
  1920. //
  1921. // Free the old device relations (if it is present)
  1922. //
  1923. if (currentRelations) {
  1924. ExFreePool( *DeviceRelations );
  1925. }
  1926. //
  1927. // Update the device relation pointer
  1928. //
  1929. *DeviceRelations = newRelations;
  1930. //
  1931. // Done
  1932. //
  1933. return STATUS_SUCCESS;
  1934. }
  1935. BOOLEAN
  1936. ACPIDetectPdoMatch(
  1937. IN PDEVICE_EXTENSION DeviceExtension,
  1938. IN PDEVICE_RELATIONS DeviceRelations
  1939. )
  1940. /*++
  1941. Routine Description:
  1942. This routine takes a given extension and a set of relations and decides
  1943. whether a new PDO should be created for the extension. Return result
  1944. is *FALSE* if one should be created, *TRUE* if one was already created.
  1945. NB: This routine is called by a parent who owns the AcpiDeviceTreeLock...
  1946. NNB: This means that this routine is always called at DISPATCH_LEVEL
  1947. Arguments:
  1948. DeviceExtension - What we are trying to match too
  1949. DeviceRelations - What we are trying to match with
  1950. Return Value:
  1951. TRUE - The DeviceExtension can be ignored
  1952. FALSE - A device object needs to be created for the extension
  1953. --*/
  1954. {
  1955. NTSTATUS status;
  1956. PDEVICE_OBJECT devicePdoObject = NULL ;
  1957. PAGED_CODE();
  1958. //
  1959. // For this to work, we must set the DEV_TYPE_NOT_FOUND flag when we
  1960. // first create the device and at any time when there is no device object
  1961. // associated with the extension
  1962. //
  1963. if (!(DeviceExtension->Flags & DEV_TYPE_NOT_FOUND) ||
  1964. (DeviceExtension->Flags & DEV_PROP_DOCK) ||
  1965. DeviceExtension->DeviceObject != NULL) {
  1966. return TRUE;
  1967. }
  1968. //
  1969. // deviceObject will be filled in if the extension in question is
  1970. // already in the relation. The status will not be successful if the
  1971. // extension could not be in the relation.
  1972. //
  1973. status = ACPIDetectCouldExtensionBeInRelation(
  1974. DeviceExtension,
  1975. DeviceRelations,
  1976. FALSE,
  1977. TRUE,
  1978. &devicePdoObject
  1979. ) ;
  1980. return (devicePdoObject||(!NT_SUCCESS(status))) ? TRUE : FALSE ;
  1981. }