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.

1308 lines
29 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. internal.c
  5. Abstract:
  6. This file contains those functions which didn't easily fit into any
  7. of the other project files. They are typically accessory functions
  8. used to prevent repeatitive and tedious coding.
  9. Author:
  10. Stephane Plante (splante)
  11. Environment:
  12. NT Kernel Model Driver only
  13. --*/
  14. #include "pch.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,ACPIInternalGetDeviceCapabilities)
  17. #pragma alloc_text(PAGE,ACPIInternalIsPci)
  18. #pragma alloc_text(PAGE,ACPIInternalGrowBuffer)
  19. #pragma alloc_text(PAGE,ACPIInternalSendSynchronousIrp)
  20. #endif
  21. //
  22. // For IA32 bit machines, which don't have a 64 bit compare-exchange
  23. // instruction, we need a spinlock so that the OS can simulate it
  24. //
  25. KSPIN_LOCK AcpiUpdateFlagsLock;
  26. //
  27. // We need to have a table of HexDigits so that we can easily generate
  28. // the proper nane for a GPE method
  29. //
  30. UCHAR HexDigit[] = "0123456789ABCDEF";
  31. //
  32. // This is a look-up table. The entry into the table corresponds to the
  33. // first bit set (in an x86-architecture, this is the left most bit set to
  34. // one...
  35. //
  36. UCHAR FirstSetLeftBit[256] = {
  37. 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  38. 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  39. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  40. 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  41. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  42. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  43. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  44. 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  45. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  46. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  47. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  48. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  49. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  50. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  51. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  52. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
  53. };
  54. BOOLEAN
  55. ACPIInternalConvertToNumber(
  56. IN UCHAR ValueLow,
  57. IN UCHAR ValueHigh,
  58. IN PULONG Output
  59. )
  60. /*++
  61. Routine Description:
  62. This routine takes the supplied values (in ASCII format) and converts
  63. them into numerical format. The ValueLow is the the low nibble of a uchar,
  64. and the ValueHigh is the high nibble of a uchar. The input ASCII format
  65. is HEX
  66. Arguments:
  67. ValueLow - ASCII Hex representation of low nibble
  68. ValueHigh - ASCII Hex representation of high nibble
  69. Output - Where to write the resulting UCHAR.
  70. Return Value:
  71. BOOLEAN - TRUE if converstion went okay
  72. - FALSE otherwise
  73. --*/
  74. {
  75. UCHAR Number;
  76. UCHAR Scratch;
  77. //
  78. // Calculate the high nibble
  79. //
  80. if ( (ValueHigh < '0') || (ValueHigh > '9') ) {
  81. if ( (ValueHigh < 'A') || (ValueHigh > 'F') ) {
  82. return FALSE;
  83. } else {
  84. Scratch = (ValueHigh - 'A') + 10;
  85. }
  86. } else {
  87. Scratch = (ValueHigh - '0');
  88. }
  89. //
  90. // We now have the high nibble
  91. //
  92. Number = (UCHAR)Scratch;
  93. Number <<=4;
  94. //
  95. // Calculate the low nibble
  96. //
  97. if ( (ValueLow < '0') || (ValueLow > '9') ) {
  98. if ( (ValueLow < 'A') || (ValueLow > 'F') ) {
  99. return FALSE;
  100. } else {
  101. Scratch = (ValueLow - 'A') + 10;
  102. }
  103. } else {
  104. Scratch = (ValueLow - '0' );
  105. }
  106. //
  107. // We now have the low nibble
  108. //
  109. Number |= ((UCHAR)Scratch);
  110. //
  111. // Store the result
  112. //
  113. if ( Output ) {
  114. *Output = Number;
  115. return TRUE;
  116. } else {
  117. return FALSE;
  118. }
  119. }
  120. VOID
  121. ACPIInternalDecrementIrpReferenceCount(
  122. IN PDEVICE_EXTENSION DeviceExtension
  123. )
  124. /*++
  125. Routine Description:
  126. This routine decrements the number of outstanding request count in the
  127. device extension and does the correct thing when this goes to zero
  128. Arguments:
  129. DeviceExtension - The Extension to decrement the count
  130. Return Value:
  131. NTSTATUS
  132. --*/
  133. {
  134. LONG oldReferenceCount;
  135. //
  136. // Decrement the reference count since we are done processing
  137. // the irp by the time we get back here
  138. //
  139. oldReferenceCount = InterlockedDecrement(
  140. &(DeviceExtension->OutstandingIrpCount)
  141. );
  142. if (oldReferenceCount == 0) {
  143. KeSetEvent( DeviceExtension->RemoveEvent, 0, FALSE );
  144. }
  145. }
  146. NTSTATUS
  147. ACPIInternalGetDeviceCapabilities(
  148. IN PDEVICE_OBJECT DeviceObject,
  149. IN PDEVICE_CAPABILITIES DeviceCapabilities
  150. )
  151. /*++
  152. Routine Description:
  153. This routine sends get the capabilities of the given stack
  154. Arguments:
  155. DeviceObject - The object that we want to know about
  156. DeviceCapabilities - The capabilities of that device
  157. Return Value:
  158. NTSTATUS
  159. --*/
  160. {
  161. IO_STACK_LOCATION irpSp;
  162. NTSTATUS status;
  163. PUCHAR dummy;
  164. PAGED_CODE();
  165. ASSERT( DeviceObject != NULL );
  166. ASSERT( DeviceCapabilities != NULL );
  167. //
  168. // Initialize the stack location that we will use
  169. //
  170. RtlZeroMemory( &irpSp, sizeof(IO_STACK_LOCATION) );
  171. irpSp.MajorFunction = IRP_MJ_PNP;
  172. irpSp.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  173. irpSp.Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  174. //
  175. // Initialize the capabilities that we will send down
  176. //
  177. RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
  178. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  179. DeviceCapabilities->Version = 1;
  180. DeviceCapabilities->Address = (ULONG) -1;
  181. DeviceCapabilities->UINumber = (ULONG) -1;
  182. //
  183. // Make the call now...
  184. //
  185. status = ACPIInternalSendSynchronousIrp(
  186. DeviceObject,
  187. &irpSp,
  188. (PVOID) &dummy
  189. );
  190. // Done
  191. //
  192. return status;
  193. }
  194. PDEVICE_EXTENSION
  195. ACPIInternalGetDeviceExtension(
  196. IN PDEVICE_OBJECT DeviceObject
  197. )
  198. /*++
  199. Routine Description:
  200. The ACPI Driver can no longer just get the device extension by
  201. Dereferencing DeviceObject->DeviceExtension because it allows a
  202. race condition when dealing with the surprise remove case
  203. This routine is called to turn the Device Object into a Device Extension
  204. Arguments:
  205. DeviceObject - The Device Object
  206. Return Value:
  207. PDEVICE_EXTENSION
  208. --*/
  209. {
  210. KIRQL oldIrql;
  211. PDEVICE_EXTENSION deviceExtension;
  212. //
  213. // Acquire the device tree lock
  214. //
  215. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  216. //
  217. // Dereference the device extension
  218. //
  219. deviceExtension = DeviceObject->DeviceExtension;
  220. #if 0
  221. //
  222. // Is this a surprise removed device extension?
  223. //
  224. if (deviceExtension != NULL &&
  225. deviceExtension->Flags & DEV_TYPE_SURPRISE_REMOVED) {
  226. //
  227. // Get the "real" extension
  228. //
  229. deviceExtension = deviceExtension->Removed.OriginalAcpiExtension;
  230. }
  231. #endif
  232. //
  233. // Done with the lock
  234. //
  235. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  236. //
  237. // Return the device extension
  238. //
  239. return deviceExtension;
  240. }
  241. NTSTATUS
  242. ACPIInternalGetDispatchTable(
  243. IN PDEVICE_OBJECT DeviceObject,
  244. OUT PDEVICE_EXTENSION *DeviceExtension,
  245. OUT PIRP_DISPATCH_TABLE *DispatchTable
  246. )
  247. /*++
  248. Routine Description:
  249. This routine returns the deviceExtension and dispatch table that is
  250. to be used by the target object
  251. Arguments:
  252. DeviceObject - The Device Object
  253. DeviceExtension - Where to store the deviceExtension
  254. DispatchTable - Where to store the dispatchTable
  255. Return Value:
  256. PDEVICE_EXTENSION
  257. --*/
  258. {
  259. KIRQL oldIrql;
  260. //
  261. // Acquire the device tree lock
  262. //
  263. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  264. //
  265. // Dereference the device extension
  266. //
  267. *DeviceExtension = DeviceObject->DeviceExtension;
  268. if (DeviceObject->DeviceExtension) {
  269. //
  270. // Dereference the dispatch table
  271. //
  272. *DispatchTable = (*DeviceExtension)->DispatchTable;
  273. } else {
  274. //
  275. // No dispatch table to hand back
  276. //
  277. *DispatchTable = NULL;
  278. }
  279. //
  280. // Done with the lock
  281. //
  282. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  283. //
  284. // Return
  285. //
  286. return STATUS_SUCCESS;
  287. }
  288. NTSTATUS
  289. ACPIInternalGrowBuffer(
  290. IN OUT PVOID *Buffer,
  291. IN ULONG OriginalSize,
  292. IN ULONG NewSize
  293. )
  294. /*++
  295. Routine Description:
  296. This function is used to grow a buffer. It allocates memory, zeroes it out,
  297. and copies the original information over.
  298. Note: I suppose it can *shrink* a buffer as well, but I wouldn't bet my life
  299. on it. The caller is responsible for freeing allocated memory
  300. Arguments
  301. Buffer - Points to the Pointer to the Buffer that we want to change
  302. OriginalSize - How big the buffer was originally
  303. NewSize - How big we want to make the buffer
  304. Return Value:
  305. NTSTATUS
  306. --*/
  307. {
  308. PUCHAR temp;
  309. PAGED_CODE();
  310. ASSERT( Buffer != NULL );
  311. temp = ExAllocatePoolWithTag(
  312. PagedPool,
  313. NewSize,
  314. ACPI_RESOURCE_POOLTAG
  315. );
  316. if (temp == NULL) {
  317. if (*Buffer) {
  318. ExFreePool ( *Buffer );
  319. *Buffer = NULL;
  320. }
  321. return STATUS_INSUFFICIENT_RESOURCES;
  322. }
  323. RtlZeroMemory ( temp, NewSize );
  324. if ( *Buffer ) {
  325. RtlCopyMemory ( temp, *Buffer, OriginalSize );
  326. ExFreePool( *Buffer );
  327. }
  328. *Buffer = temp;
  329. return STATUS_SUCCESS;
  330. }
  331. NTSTATUS
  332. ACPIInternalIsPci(
  333. IN PDEVICE_OBJECT DeviceObject
  334. )
  335. /*++
  336. Routine Description:
  337. This routine determines if the specified device object is part of a
  338. PCI stack, either as a PCI device or as a PCI Bus.
  339. This routine will then set the flags that if it is a PCI device, then
  340. it will always be remembered as such
  341. Arguments:
  342. DeviceObject - The device object to check
  343. --*/
  344. {
  345. AMLISUPP_CONTEXT_PASSIVE isPciDeviceContext;
  346. BOOLEAN pciDevice;
  347. KEVENT removeEvent;
  348. NTSTATUS status;
  349. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  350. PAGED_CODE();
  351. //
  352. // Is this already a PCI device?
  353. //
  354. if ( (deviceExtension->Flags & DEV_CAP_PCI) ||
  355. (deviceExtension->Flags & DEV_CAP_PCI_DEVICE) ) {
  356. return STATUS_SUCCESS;
  357. }
  358. //
  359. // Is this a PCI bus?
  360. //
  361. if (IsPciBus(deviceExtension->DeviceObject)) {
  362. //
  363. // Remember that we are a PCI bus
  364. //
  365. ACPIInternalUpdateFlags(
  366. &(deviceExtension->Flags),
  367. (DEV_CAP_PCI),
  368. FALSE
  369. );
  370. return STATUS_SUCCESS;
  371. }
  372. //
  373. // Are we a PCI device?
  374. //
  375. isPciDeviceContext.Status = STATUS_NOT_FOUND;
  376. KeInitializeEvent(
  377. &isPciDeviceContext.Event,
  378. SynchronizationEvent,
  379. FALSE
  380. );
  381. status = IsPciDevice(
  382. deviceExtension->AcpiObject,
  383. AmlisuppCompletePassive,
  384. (PVOID) &isPciDeviceContext,
  385. &pciDevice
  386. );
  387. if (status == STATUS_PENDING) {
  388. KeWaitForSingleObject(
  389. &isPciDeviceContext.Event,
  390. Executive,
  391. KernelMode,
  392. FALSE,
  393. NULL
  394. );
  395. status = isPciDeviceContext.Status;
  396. }
  397. if (NT_SUCCESS(status) && pciDevice) {
  398. //
  399. // Remember that we are a PCI device
  400. //
  401. ACPIInternalUpdateFlags(
  402. &(deviceExtension->Flags),
  403. (DEV_CAP_PCI_DEVICE),
  404. FALSE
  405. );
  406. }
  407. return status;
  408. }
  409. BOOLEAN
  410. ACPIInternalIsReportedMissing(
  411. IN PDEVICE_EXTENSION DeviceExtension
  412. )
  413. {
  414. KIRQL oldIrql;
  415. PDEVICE_EXTENSION currentExtension;
  416. BOOLEAN reportedMissing;
  417. //
  418. // Preinit
  419. //
  420. reportedMissing = FALSE;
  421. //
  422. // Acquire the device tree lock
  423. //
  424. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  425. currentExtension = DeviceExtension;
  426. do {
  427. if ( currentExtension->Flags & DEV_TYPE_NOT_ENUMERATED ) {
  428. reportedMissing = TRUE;
  429. break;
  430. }
  431. currentExtension = currentExtension->ParentExtension;
  432. } while ( currentExtension );
  433. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  434. return reportedMissing;
  435. }
  436. VOID
  437. ACPIInternalMoveList(
  438. IN PLIST_ENTRY FromList,
  439. IN PLIST_ENTRY ToList
  440. )
  441. /*++
  442. Routine Description:
  443. This routine moves entire list arounds.
  444. Arguments:
  445. FromList - the List to move items from
  446. ToList - the List to move items to
  447. Return Value:
  448. None
  449. --*/
  450. {
  451. PLIST_ENTRY oldHead;
  452. PLIST_ENTRY oldTail;
  453. PLIST_ENTRY newTail;
  454. //
  455. // We have to check to see if the from list is empty, otherwise, the
  456. // direct pointer hacking will make a mess of things
  457. //
  458. if (!IsListEmpty(FromList)) {
  459. newTail = ToList->Blink;
  460. oldTail = FromList->Blink;
  461. oldHead = FromList->Flink;
  462. //
  463. // Move the pointers around some
  464. //
  465. oldTail->Flink = ToList;
  466. ToList->Blink = oldTail;
  467. oldHead->Blink = newTail;
  468. newTail->Flink = oldHead;
  469. InitializeListHead( FromList );
  470. }
  471. }
  472. VOID
  473. ACPIInternalMovePowerList(
  474. IN PLIST_ENTRY FromList,
  475. IN PLIST_ENTRY ToList
  476. )
  477. /*++
  478. Routine Description:
  479. This routine moves entire list arounds. Since this routine is only
  480. used for Device Power Management, we also take the time to reset the
  481. amount of work done to NULL.
  482. Arguments:
  483. FromList - the List to move items from
  484. ToList - the List to move items to
  485. Return Value:
  486. None
  487. --*/
  488. {
  489. PACPI_POWER_REQUEST powerRequest;
  490. PLIST_ENTRY oldHead = FromList->Flink;
  491. //
  492. // Before we do anything, walk the From and reset the amount of work that
  493. // was done
  494. //
  495. while (oldHead != FromList) {
  496. //
  497. // Obtain the power request that this entry contains
  498. //
  499. powerRequest = CONTAINING_RECORD(
  500. oldHead,
  501. ACPI_POWER_REQUEST,
  502. ListEntry
  503. );
  504. #if DBG
  505. if (oldHead == &AcpiPowerPhase0List ||
  506. oldHead == &AcpiPowerPhase1List ||
  507. oldHead == &AcpiPowerPhase2List ||
  508. oldHead == &AcpiPowerPhase3List ||
  509. oldHead == &AcpiPowerPhase4List ||
  510. oldHead == &AcpiPowerPhase5List ||
  511. oldHead == &AcpiPowerWaitWakeList) {
  512. ACPIPrint( (
  513. ACPI_PRINT_CRITICAL,
  514. "ACPIInternalMoveList: %08x is linked into %08lx\n",
  515. oldHead,
  516. FromList
  517. ) );
  518. DbgBreakPoint();
  519. }
  520. #endif
  521. //
  522. // Grab the next entry
  523. //
  524. oldHead = oldHead->Flink;
  525. //
  526. // Reset the amount of work done. Note: This could be a CompareExchange
  527. // with the Comparand being WORK_DONE_COMPLETED
  528. //
  529. InterlockedExchange(
  530. &(powerRequest->WorkDone),
  531. WORK_DONE_STEP_0
  532. );
  533. }
  534. //
  535. // Actually Move the list here...
  536. //
  537. ACPIInternalMoveList( FromList, ToList );
  538. }
  539. NTSTATUS
  540. ACPIInternalRegisterPowerCallBack(
  541. IN PDEVICE_EXTENSION DeviceExtension,
  542. IN PCALLBACK_FUNCTION CallBackFunction
  543. )
  544. /*++
  545. Routine Description:
  546. This routine is called to register a Power Call on the appropriate
  547. device extension.
  548. Arguments:
  549. DeviceExtension - This will be the context field of the CallBackFunction
  550. CallBackFunction - The function to invoke
  551. Return Value:
  552. NSTATUS
  553. --*/
  554. {
  555. NTSTATUS status;
  556. OBJECT_ATTRIBUTES objAttributes;
  557. PCALLBACK_OBJECT callBack;
  558. PVOID callBackRegistration;
  559. UNICODE_STRING callBackName;
  560. //
  561. // if there is already a callback present, this is a nop
  562. //
  563. if (DeviceExtension->Flags & DEV_PROP_CALLBACK) {
  564. return STATUS_SUCCESS;
  565. }
  566. //
  567. // Remember that we have a callback
  568. //
  569. ACPIInternalUpdateFlags(
  570. &(DeviceExtension->Flags),
  571. DEV_PROP_CALLBACK,
  572. FALSE
  573. );
  574. //
  575. // Register a callback that tells us when the user changes the
  576. // system power policy
  577. //
  578. RtlInitUnicodeString( &callBackName, L"\\Callback\\PowerState" );
  579. InitializeObjectAttributes(
  580. &objAttributes,
  581. &callBackName,
  582. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  583. NULL,
  584. NULL
  585. );
  586. status = ExCreateCallback(
  587. &callBack,
  588. &objAttributes,
  589. FALSE,
  590. TRUE
  591. );
  592. if (NT_SUCCESS(status)) {
  593. ExRegisterCallback(
  594. callBack,
  595. CallBackFunction,
  596. DeviceExtension
  597. );
  598. }
  599. if (!NT_SUCCESS(status)) {
  600. //
  601. // Ignored failed registrations
  602. //
  603. ACPIDevPrint( (
  604. ACPI_PRINT_FAILURE,
  605. DeviceExtension,
  606. "ACPIInternalRegisterPowerCallBack: Failed to register callback %x",
  607. status
  608. ) );
  609. status = STATUS_SUCCESS;
  610. //
  611. // Remember that we don't have a callback
  612. //
  613. ACPIInternalUpdateFlags(
  614. &(DeviceExtension->Flags),
  615. DEV_PROP_CALLBACK,
  616. TRUE
  617. );
  618. }
  619. return status;
  620. }
  621. NTSTATUS
  622. ACPIInternalSendSynchronousIrp(
  623. IN PDEVICE_OBJECT DeviceObject,
  624. IN PIO_STACK_LOCATION TopStackLocation,
  625. OUT PVOID *Information
  626. )
  627. /*++
  628. Routine Description:
  629. Builds a PNP Irp and sends it down to DeviceObject
  630. Arguments:
  631. DeviceObject - Target DeviceObject
  632. TopStackLocation - Specifies the Parameters for the Irp
  633. Information - The returned IoStatus.Information field
  634. Return Value:
  635. NTSTATUS
  636. --*/
  637. {
  638. IO_STATUS_BLOCK ioStatus;
  639. KEVENT pnpEvent;
  640. NTSTATUS status;
  641. PDEVICE_OBJECT targetObject;
  642. PIO_STACK_LOCATION irpStack;
  643. PIRP pnpIrp;
  644. PAGED_CODE();
  645. //
  646. // Initialize the event
  647. //
  648. KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
  649. //
  650. // Get the irp that we will send the request to
  651. //
  652. targetObject = IoGetAttachedDeviceReference( DeviceObject );
  653. //
  654. // Build an IRP
  655. //
  656. pnpIrp = IoBuildSynchronousFsdRequest(
  657. IRP_MJ_PNP,
  658. targetObject,
  659. NULL, // I don't need a buffer
  660. 0, // Size is empty
  661. NULL, // Don't have to worry about the starting location
  662. &pnpEvent,
  663. &ioStatus
  664. );
  665. if (pnpIrp == NULL) {
  666. status = STATUS_INSUFFICIENT_RESOURCES;
  667. goto ACPIInternalSendSynchronousIrpExit;
  668. }
  669. //
  670. // PNP Irps all begin life as STATUS_NOT_SUPPORTED.
  671. //
  672. pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
  673. pnpIrp->IoStatus.Information = 0;
  674. //
  675. // Get the top of stack ...
  676. //
  677. irpStack = IoGetNextIrpStackLocation ( pnpIrp );
  678. if (irpStack == NULL) {
  679. status = STATUS_INVALID_PARAMETER;
  680. goto ACPIInternalSendSynchronousIrpExit;
  681. }
  682. //
  683. // Set the top of stack
  684. //
  685. *irpStack = *TopStackLocation;
  686. //
  687. // Make sure that there are no completion routine set
  688. //
  689. IoSetCompletionRoutine(
  690. pnpIrp,
  691. NULL,
  692. NULL,
  693. FALSE,
  694. FALSE,
  695. FALSE
  696. );
  697. //
  698. // Call the driver
  699. //
  700. status = IoCallDriver( targetObject, pnpIrp );
  701. if (status == STATUS_PENDING) {
  702. //
  703. // If the status is STATUS_PENDING, than we must block until the irp completes
  704. // and pull the true status out
  705. //
  706. KeWaitForSingleObject(
  707. &pnpEvent,
  708. Executive,
  709. KernelMode,
  710. FALSE,
  711. NULL);
  712. status = ioStatus.Status;
  713. }
  714. //
  715. // Tell the user how much information was passed (if necessary)
  716. //
  717. if (NT_SUCCESS(status) && (Information != NULL)) {
  718. *Information = (PVOID)ioStatus.Information;
  719. }
  720. ACPIInternalSendSynchronousIrpExit:
  721. ACPIPrint( (
  722. ACPI_PRINT_IRP,
  723. "ACPIInternalSendSynchronousIrp: %#08lx Status = %#08lx\n",
  724. DeviceObject, status
  725. ) );
  726. //
  727. // Done with reference
  728. //
  729. ObDereferenceObject( targetObject );
  730. return status;
  731. }
  732. NTSTATUS
  733. ACPIInternalSetDeviceInterface (
  734. IN PDEVICE_OBJECT DeviceObject,
  735. IN LPGUID InterfaceGuid
  736. )
  737. /*++
  738. Routine Description:
  739. This routine does all the grunt work for registering an interface and
  740. enabling it
  741. Arguments:
  742. DeviceObject - The device we wish to register the interface on
  743. InterfaceGuid - The interface we wish to register
  744. Return Value:
  745. NTSTATUS
  746. --*/
  747. {
  748. NTSTATUS status;
  749. PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject);
  750. UNICODE_STRING symbolicLinkName;
  751. //
  752. // Register the interface
  753. //
  754. status = IoRegisterDeviceInterface(
  755. DeviceObject,
  756. InterfaceGuid,
  757. NULL,
  758. &symbolicLinkName
  759. );
  760. if (!NT_SUCCESS(status)) {
  761. ACPIDevPrint( (
  762. ACPI_PRINT_FAILURE,
  763. deviceExtension,
  764. "ACPIInternalSetDeviceInterface: IoRegisterDeviceInterface = %08lx",
  765. status
  766. ) );
  767. return status;
  768. }
  769. //
  770. // Turn on the interface
  771. //
  772. status = IoSetDeviceInterfaceState(&symbolicLinkName, TRUE);
  773. if (!NT_SUCCESS(status)) {
  774. ACPIDevPrint( (
  775. ACPI_PRINT_FAILURE,
  776. deviceExtension,
  777. "ACPIInternalSetDeviceInterface: IoSetDeviceInterfaceState = %08lx",
  778. status
  779. ) );
  780. goto ACPIInternalSetDeviceInterfaceExit;
  781. }
  782. ACPIInternalSetDeviceInterfaceExit:
  783. //
  784. // Done
  785. //
  786. return status;
  787. }
  788. VOID
  789. ACPIInternalUpdateDeviceStatus(
  790. IN PDEVICE_EXTENSION DeviceExtension,
  791. IN ULONG DeviceStatus
  792. )
  793. /*++
  794. Routine Description:
  795. This routine is called to update the status of the DeviceExtension based
  796. upon the result of the _STA, which are passed as DeviceStatus
  797. Arguments:
  798. DeviceExtension - The extension whose status is to be updated
  799. DeviceState - The status of the device
  800. Return Value:
  801. VOID
  802. --*/
  803. {
  804. KIRQL oldIrql;
  805. ULONGLONG originalFlags;
  806. PDEVICE_EXTENSION parentExtension = NULL;
  807. BOOLEAN bPreviouslyPresent;
  808. //
  809. // Is the device working okay?
  810. //
  811. originalFlags = ACPIInternalUpdateFlags(
  812. &(DeviceExtension->Flags),
  813. DEV_PROP_DEVICE_FAILED,
  814. (BOOLEAN) (DeviceStatus & STA_STATUS_WORKING_OK)
  815. );
  816. //
  817. // Is the device meant to be shown in the UI?
  818. //
  819. originalFlags = ACPIInternalUpdateFlags(
  820. &(DeviceExtension->Flags),
  821. DEV_CAP_NO_SHOW_IN_UI,
  822. (BOOLEAN) (DeviceStatus & STA_STATUS_USER_INTERFACE)
  823. );
  824. //
  825. // Is the device decoding its resources?
  826. //
  827. originalFlags = ACPIInternalUpdateFlags(
  828. &(DeviceExtension->Flags),
  829. DEV_PROP_DEVICE_ENABLED,
  830. (BOOLEAN) !(DeviceStatus & STA_STATUS_ENABLED)
  831. );
  832. //
  833. // Update the extensions flags bassed on wether or not STA_STATUS_PRESENT is
  834. // set
  835. //
  836. originalFlags = ACPIInternalUpdateFlags(
  837. &(DeviceExtension->Flags),
  838. DEV_TYPE_NOT_PRESENT,
  839. (BOOLEAN) (DeviceStatus & STA_STATUS_PRESENT)
  840. );
  841. //
  842. // If the original flags do not contain the set value, but we are setting
  843. // the flags, then we must call IoInvalidDeviceRelations on the parent
  844. //
  845. if (!(originalFlags & DEV_TYPE_NOT_PRESENT) &&
  846. !(DeviceStatus & STA_STATUS_PRESENT)) {
  847. //
  848. // Need the device tree lock
  849. //
  850. KeAcquireSpinLock( &AcpiDeviceTreeLock, &oldIrql );
  851. parentExtension = DeviceExtension->ParentExtension;
  852. while (parentExtension && (parentExtension->Flags & DEV_TYPE_NOT_FOUND)) {
  853. parentExtension = parentExtension->ParentExtension;
  854. }
  855. if (parentExtension) {
  856. IoInvalidateDeviceRelations(
  857. parentExtension->PhysicalDeviceObject,
  858. BusRelations
  859. );
  860. }
  861. //
  862. // Done with the lock
  863. //
  864. KeReleaseSpinLock( &AcpiDeviceTreeLock, oldIrql );
  865. }
  866. }
  867. ULONGLONG
  868. ACPIInternalUpdateFlags(
  869. IN PULONGLONG FlagLocation,
  870. IN ULONGLONG NewFlags,
  871. IN BOOLEAN Clear
  872. )
  873. /*++
  874. Routine Description:
  875. This routine updates flags in the specified location
  876. Arguments:
  877. FlagLocation - Where the flags are located
  878. NewFlags - The bits that should be set or cleared
  879. Clear - Wether the bits should be set or cleared
  880. Return Value:
  881. Original Flags
  882. --*/
  883. {
  884. ULONGLONG originalFlags;
  885. ULONGLONG tempFlags;
  886. ULONGLONG flags;
  887. ULONG uFlags;
  888. ULONG uTempFlags;
  889. ULONG uOriginalFlags;
  890. #if 0
  891. if (Clear) {
  892. //
  893. // Clear the bits
  894. //
  895. originalFlags = *FlagLocation;
  896. do {
  897. tempFlags = originalFlags;
  898. flags = tempFlags & ~NewFlags;
  899. //
  900. // Calculate the low part
  901. //
  902. uFlags = (ULONG) flags;
  903. uTempFlags = (ULONG) tempFlags;
  904. originalFlags = InterlockedCompareExchange(
  905. (PULONG) FlagLocation,
  906. uFlags,
  907. uTempFlags
  908. );
  909. //
  910. // Calculate the high part
  911. //
  912. uFlags = (ULONG) (flags >> 32);
  913. uTempFlags = (ULONG) (tempFlags >> 32);
  914. uOriginalFlags = InterlockedCompareExchange(
  915. (PULONG) FlagLocation+1,
  916. uFlags,
  917. uTempFlags
  918. );
  919. //
  920. // Rebuild the original flags
  921. //
  922. originalFlags |= (uOriginalFlags << 32);
  923. tempFlags |= (uTempFlags << 32);
  924. } while ( tempFlags != originalFlags );
  925. } else {
  926. //
  927. // Set the bits
  928. //
  929. originalFlags = *FlagLocation;
  930. do {
  931. tempFlags = originalFlags;
  932. flags = tempFlags | NewFlags;
  933. //
  934. // Calculate the low part
  935. //
  936. uFlags = (ULONG) flags;
  937. uTempFlags = (ULONG) tempFlags;
  938. originalFlags = InterlockedCompareExchange(
  939. (PULONG) FlagLocation,
  940. uFlags,
  941. uTempFlags
  942. );
  943. //
  944. // Calculate the high part
  945. //
  946. uFlags = (ULONG) (flags >> 32);
  947. uTempFlags = (ULONG) (tempFlags >> 32);
  948. uOriginalFlags = InterlockedCompareExchange(
  949. (PULONG) FlagLocation+1,
  950. uFlags,
  951. uTempFlags
  952. );
  953. //
  954. // Rebuild the original flags
  955. //
  956. originalFlags |= (uOriginalFlags << 32);
  957. tempFlags |= (uTempFlags << 32);
  958. } while ( tempFlags != originalFlags );
  959. }
  960. #else
  961. if (Clear) {
  962. //
  963. // Clear the bits
  964. //
  965. originalFlags = *FlagLocation;
  966. do {
  967. tempFlags = originalFlags;
  968. flags = tempFlags & ~NewFlags;
  969. //
  970. // Exchange the bits
  971. //
  972. originalFlags = ExInterlockedCompareExchange64(
  973. (PLONGLONG) FlagLocation,
  974. (PLONGLONG) &flags,
  975. (PLONGLONG) &tempFlags,
  976. &AcpiUpdateFlagsLock
  977. );
  978. } while ( tempFlags != originalFlags );
  979. } else {
  980. //
  981. // Set the bits
  982. //
  983. originalFlags = *FlagLocation;
  984. do {
  985. tempFlags = originalFlags;
  986. flags = tempFlags | NewFlags;
  987. //
  988. // Exchange teh bits
  989. //
  990. originalFlags = ExInterlockedCompareExchange64(
  991. (PLONGLONG) FlagLocation,
  992. (PLONGLONG) &flags,
  993. (PLONGLONG) &tempFlags,
  994. &AcpiUpdateFlagsLock
  995. );
  996. } while ( tempFlags != originalFlags );
  997. }
  998. #endif
  999. //
  1000. // return the original flags
  1001. //
  1002. return originalFlags;
  1003. }