[ros-diffs] [sir_richard] 46004: [NTOS]: Have I/O Manager Volume Device Objects register with the Power Manager so that they can receive dope. [NTOS]: Reimplement NtShutdownSystem. [NTOS]: Implement NtSetSystemPowerState for the shutdown/reboot cases. [NTOS]: Use the dope from the volume device objects to flush all writeable (non-floppy) devices. Pending hard-disk changes are now flushed to disks before shutdown. [NTOS]: Flush \\REGISTRY during shutdown. This flushes all pending changes. [NTOS]: Call into Cc to flush lazy writer during shutdown. [NTOS]: Stop killing processes on shutdown. The kernel should not be doing this. [NTOS]: Don't only shutdown disk file systems, but also cdrom and tape. [NTOS]: Don't only notify drivers of first-chance shutdown -- also parse the last-change shutdown list. [NTOS]: Reference drivers registering for shutdown notifications so that they remain loaded for them to get the notification at shutdown. [NTOS]: Notify drivers that have registered/opened the Power State callback. [NTOS]: A lot of the Po* power state code is highly simplified, but provides a good roadmap to anyone interested in this functionality long-term.

sir_richard at svn.reactos.org sir_richard at svn.reactos.org
Mon Mar 8 21:47:11 CET 2010


Author: sir_richard
Date: Mon Mar  8 21:47:10 2010
New Revision: 46004

URL: http://svn.reactos.org/svn/reactos?rev=46004&view=rev
Log:
[NTOS]: Have I/O Manager Volume Device Objects register with the Power Manager so that they can receive dope.
[NTOS]: Reimplement NtShutdownSystem.
[NTOS]: Implement NtSetSystemPowerState for the shutdown/reboot cases.
[NTOS]: Use the dope from the volume device objects to flush all writeable (non-floppy) devices. Pending hard-disk changes are now flushed to disks before shutdown.
[NTOS]: Flush \\REGISTRY during shutdown. This flushes all pending changes.
[NTOS]: Call into Cc to flush lazy writer during shutdown.
[NTOS]: Stop killing processes on shutdown. The kernel should not be doing this.
[NTOS]: Don't only shutdown disk file systems, but also cdrom and tape.
[NTOS]: Don't only notify drivers of first-chance shutdown -- also parse the last-change shutdown list.
[NTOS]: Reference drivers registering for shutdown notifications so that they remain loaded for them to get the notification at shutdown.
[NTOS]: Notify drivers that have registered/opened the Power State callback.
[NTOS]: A lot of the Po* power state code is highly simplified, but provides a good roadmap to anyone interested in this functionality long-term.

Added:
    trunk/reactos/ntoskrnl/po/poshtdwn.c   (with props)
    trunk/reactos/ntoskrnl/po/povolume.c   (with props)
Modified:
    trunk/reactos/ntoskrnl/ex/shutdown.c
    trunk/reactos/ntoskrnl/include/internal/io.h
    trunk/reactos/ntoskrnl/include/internal/po.h
    trunk/reactos/ntoskrnl/io/iomgr/device.c
    trunk/reactos/ntoskrnl/io/iomgr/volume.c
    trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild
    trunk/reactos/ntoskrnl/po/power.c

Modified: trunk/reactos/ntoskrnl/ex/shutdown.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/shutdown.c?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ex/shutdown.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ex/shutdown.c [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -14,123 +14,40 @@
 
 /* FUNCTIONS *****************************************************************/
 
-VOID NTAPI
-ShutdownThreadMain(PVOID Context)
-{
-   SHUTDOWN_ACTION Action = (SHUTDOWN_ACTION)Context;
-   PUCHAR Logo1, Logo2;
-   ULONG i;
-
-   /* Run the thread on the boot processor */
-   KeSetSystemAffinityThread(1);
-
-   PspShutdownProcessManager();
-
-   CmShutdownSystem();
-   IoShutdownRegisteredFileSystems();
-   IoShutdownRegisteredDevices();
-    
-   if (Action == ShutdownNoReboot)
-     {
-        /* Try the platform driver */
-        PopSetSystemPowerState(PowerSystemShutdown);
-        
-        /* If that didn't work, try legacy switch off */
-        //HalReturnToFirmware(HalPowerDownRoutine);
-        
-        /* If that still didn't work, stop all interrupts */
-        KeRaiseIrqlToDpcLevel();
-        _disable();
-
-        /* Do we have boot video */
-        if (InbvIsBootDriverInstalled())
-        {
-            /* Yes we do, cleanup for shutdown screen */
-            if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership();
-            InbvResetDisplay();
-            InbvSolidColorFill(0, 0, 639, 479, 0);
-            InbvEnableDisplayString(TRUE);
-            InbvSetScrollRegion(0, 0, 639, 479);
-
-            /* Display shutdown logo and message */
-            Logo1 = InbvGetResourceAddress(IDB_SHUTDOWN_LOGO);
-            Logo2 = InbvGetResourceAddress(IDB_LOGO);
-            if ((Logo1) && (Logo2))
-            {
-                InbvBitBlt(Logo1, 215, 352);
-                InbvBitBlt(Logo2, 217, 111);
-            }
-        }
-        else
-        {
-            /* Do it in text-mode */
-            for (i = 0; i < 25; i++) InbvDisplayString("\n");
-            InbvDisplayString("                       ");
-            InbvDisplayString("The system may be powered off now.\n");
-        }
-
-        /* Hang the system */
-        for (;;) HalHaltSystem();
-     }
-    else if (Action == ShutdownReboot)
-     {
-        HalReturnToFirmware (HalRebootRoutine);
-     }
-   else
-     {
-        HalReturnToFirmware (HalHaltRoutine);
-     }
-}
-
-
-NTSTATUS NTAPI
-NtSetSystemPowerState(IN POWER_ACTION SystemAction,
-		      IN SYSTEM_POWER_STATE MinSystemState,
-		      IN ULONG Flags)
-{
-  /* Windows 2000 only */
-  return(STATUS_NOT_IMPLEMENTED);
-}
-
 /*
  * @implemented
  */
-NTSTATUS NTAPI
+NTSTATUS
+NTAPI
 NtShutdownSystem(IN SHUTDOWN_ACTION Action)
 {
-   NTSTATUS Status;
-   HANDLE ThreadHandle;
-   PETHREAD ShutdownThread;
-
-   if (Action > ShutdownPowerOff)
-     return STATUS_INVALID_PARAMETER;
-   Status = PsCreateSystemThread(&ThreadHandle,
-                                 THREAD_ALL_ACCESS,
-                                 NULL,
-                                 NULL,
-                                 NULL,
-                                 ShutdownThreadMain,
-                                 (PVOID)Action);
-   if (!NT_SUCCESS(Status))
-   {
-      ASSERT(FALSE);
-   }
-   Status = ObReferenceObjectByHandle(ThreadHandle,
-				      THREAD_ALL_ACCESS,
-				      PsThreadType,
-				      KernelMode,
-				      (PVOID*)&ShutdownThread,
-				      NULL);
-   NtClose(ThreadHandle);
-   if (!NT_SUCCESS(Status))
-     {
-        ASSERT(FALSE);
-     }
-
-   KeSetPriorityThread(&ShutdownThread->Tcb, LOW_REALTIME_PRIORITY + 1);
-   ObDereferenceObject(ShutdownThread);
-
-   return STATUS_SUCCESS;
+    POWER_ACTION PowerAction;
+    
+    /* Convert to power action */
+    if (Action == ShutdownNoReboot)
+    {
+        PowerAction = PowerActionShutdown;
+    }
+    else if (Action == ShutdownReboot)
+    {
+        PowerAction = PowerActionShutdownReset;
+    }
+    else if (Action == ShutdownPowerOff)
+    {
+        PowerAction = PowerActionShutdownOff;
+    }
+    else
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    /* Now call the power manager */
+    DPRINT1("Setting state to: %lx\n", PowerAction);
+    return NtSetSystemPowerState(PowerAction,
+                                 PowerSystemSleeping3,
+                                 POWER_ACTION_OVERRIDE_APPS |
+                                 POWER_ACTION_DISABLE_WAKES |
+                                 POWER_ACTION_CRITICAL);
 }
 
 /* EOF */

Modified: trunk/reactos/ntoskrnl/include/internal/io.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/io.h?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/io.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/io.h [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -743,14 +743,14 @@
 
 VOID
 NTAPI
-IoShutdownRegisteredDevices(
-    VOID
-);
-
-VOID
-NTAPI
-IoShutdownRegisteredFileSystems(
-    VOID
+IoShutdownSystem(
+    IN ULONG Phase
+);
+
+VOID
+NTAPI
+IopShutdownBaseFileSystems(
+    IN PLIST_ENTRY ListHead
 );
 
 //

Modified: trunk/reactos/ntoskrnl/include/internal/po.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/po.h?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/po.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/po.h [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -32,6 +32,228 @@
 #define POTRACE(x, ...) DPRINT(__VA_ARGS__)
 #endif
 
+typedef struct _PO_HIBER_PERF
+{
+    ULONGLONG IoTicks;
+    ULONGLONG InitTicks;
+    ULONGLONG CopyTicks;
+    ULONGLONG StartCount;
+    ULONG ElapsedTime;
+    ULONG IoTime;
+    ULONG CopyTime;
+    ULONG InitTime;
+    ULONG PagesWritten;
+    ULONG PagesProcessed;
+    ULONG BytesCopied;
+    ULONG DumpCount;
+    ULONG FileRuns;
+} PO_HIBER_PERF, *PPO_HIBER_PERF;
+
+typedef struct _PO_MEMORY_IMAGE
+{
+    ULONG Signature;
+    ULONG Version;
+    ULONG CheckSum;
+    ULONG LengthSelf;
+    PFN_NUMBER PageSelf;
+    ULONG PageSize;
+    ULONG ImageType;
+    LARGE_INTEGER SystemTime;
+    ULONGLONG InterruptTime;
+    ULONG FeatureFlags;
+    UCHAR HiberFlags;
+    UCHAR spare[3];
+    ULONG NoHiberPtes;
+    ULONG_PTR HiberVa;
+    PHYSICAL_ADDRESS HiberPte;
+    ULONG NoFreePages;
+    ULONG FreeMapCheck;
+    ULONG WakeCheck;
+    PFN_NUMBER TotalPages;
+    PFN_NUMBER FirstTablePage;
+    PFN_NUMBER LastFilePage;
+    PO_HIBER_PERF PerfInfo;
+} PO_MEMORY_IMAGE, *PPO_MEMORY_IMAGE;
+
+typedef struct _PO_MEMORY_RANGE_ARRAY_RANGE
+{
+    PFN_NUMBER PageNo;
+    PFN_NUMBER StartPage;
+    PFN_NUMBER EndPage;
+    ULONG CheckSum;
+} PO_MEMORY_RANGE_ARRAY_RANGE;
+
+typedef struct _PO_MEMORY_RANGE_ARRAY_LINK
+{
+    struct _PO_MEMORY_RANGE_ARRAY *Next;
+    PFN_NUMBER NextTable;
+    ULONG CheckSum;
+    ULONG EntryCount;
+} PO_MEMORY_RANGE_ARRAY_LINK;
+
+typedef struct _PO_MEMORY_RANGE_ARRAY
+{
+    union
+    {
+        PO_MEMORY_RANGE_ARRAY_RANGE Range;
+        PO_MEMORY_RANGE_ARRAY_LINK Link;
+    };
+} PO_MEMORY_RANGE_ARRAY, *PPO_MEMORY_RANGE_ARRAY;
+
+typedef struct _POP_HIBER_CONTEXT
+{
+    BOOLEAN WriteToFile;
+    BOOLEAN ReserveLoaderMemory;
+    BOOLEAN ReserveFreeMemory;
+    BOOLEAN VerifyOnWake;
+    BOOLEAN Reset;
+    UCHAR HiberFlags;
+    BOOLEAN LinkFile;
+    HANDLE LinkFileHandle;
+    PKSPIN_LOCK Lock;
+    BOOLEAN MapFrozen;
+    RTL_BITMAP MemoryMap;
+    LIST_ENTRY ClonedRanges;
+    ULONG ClonedRangeCount;
+    PLIST_ENTRY NextCloneRange;
+    PFN_NUMBER NextPreserve;
+    PMDL LoaderMdl;
+    PMDL Clones;
+    PUCHAR NextClone;
+    ULONG NoClones;
+    PMDL Spares;
+    ULONGLONG PagesOut;
+    PVOID IoPage;
+    PVOID CurrentMcb;
+    PVOID DumpStack;
+    PKPROCESSOR_STATE WakeState;
+    ULONG NoRanges;
+    ULONG_PTR HiberVa;
+    PHYSICAL_ADDRESS HiberPte;
+    NTSTATUS Status;
+    PPO_MEMORY_IMAGE MemoryImage;
+    PPO_MEMORY_RANGE_ARRAY TableHead;
+    PVOID CompressionWorkspace;
+    PUCHAR CompressedWriteBuffer;
+    PULONG PerformanceStats;
+    PVOID CompressionBlock;
+    PVOID DmaIO;
+    PVOID TemporaryHeap;
+    PO_HIBER_PERF PerfInfo;
+} POP_HIBER_CONTEXT, *PPOP_HIBER_CONTEXT;
+
+typedef struct _PO_NOTIFY_ORDER_LEVEL
+{
+    KEVENT LevelReady;
+    ULONG DeviceCount;
+    ULONG ActiveCount;
+    LIST_ENTRY WaitSleep;
+    LIST_ENTRY ReadySleep;
+    LIST_ENTRY Pending;
+    LIST_ENTRY Complete;
+    LIST_ENTRY ReadyS0;
+    LIST_ENTRY WaitS0;
+} PO_NOTIFY_ORDER_LEVEL, *PPO_NOTIFY_ORDER_LEVEL;
+
+typedef struct _POP_SHUTDOWN_BUG_CHECK
+{
+    HANDLE ThreadHandle;
+    HANDLE ThreadId;
+    HANDLE ProcessId;
+    ULONG Code;
+    ULONG_PTR Parameter1;
+    ULONG_PTR Parameter2;
+    ULONG_PTR Parameter3;
+    ULONG_PTR Parameter4;
+} POP_SHUTDOWN_BUG_CHECK, *PPOP_SHUTDOWN_BUG_CHECK;
+
+typedef struct _POP_DEVICE_POWER_IRP
+{
+    SINGLE_LIST_ENTRY Free;
+    PIRP Irp;
+    PPO_DEVICE_NOTIFY Notify;
+    LIST_ENTRY Pending;
+    LIST_ENTRY Complete;
+    LIST_ENTRY Abort;
+    LIST_ENTRY Failed;
+} POP_DEVICE_POWER_IRP, *PPOP_DEVICE_POWER_IRP;
+
+typedef struct _PO_DEVICE_NOTIFY_ORDER
+{
+    ULONG DevNodeSequence;
+    PDEVICE_OBJECT *WarmEjectPdoPointer;
+    PO_NOTIFY_ORDER_LEVEL OrderLevel[8];
+} PO_DEVICE_NOTIFY_ORDER, *PPO_DEVICE_NOTIFY_ORDER;
+
+typedef struct _POP_DEVICE_SYS_STATE
+{
+    UCHAR IrpMinor;
+    SYSTEM_POWER_STATE SystemState;
+    PKEVENT Event;
+    KSPIN_LOCK SpinLock;
+    PKTHREAD Thread;
+    BOOLEAN GetNewDeviceList;
+    PO_DEVICE_NOTIFY_ORDER Order;
+    NTSTATUS Status;
+    PDEVICE_OBJECT FailedDevice;
+    BOOLEAN Waking;
+    BOOLEAN Cancelled;
+    BOOLEAN IgnoreErrors;
+    BOOLEAN IgnoreNotImplemented;
+    BOOLEAN _WaitAny;
+    BOOLEAN _WaitAll;
+    LIST_ENTRY PresentIrpQueue;
+    POP_DEVICE_POWER_IRP Head;
+    POP_DEVICE_POWER_IRP PowerIrpState[20];
+} POP_DEVICE_SYS_STATE, *PPOP_DEVICE_SYS_STATE;
+
+typedef struct _POP_POWER_ACTION
+{
+    UCHAR Updates;
+    UCHAR State;
+    BOOLEAN Shutdown;
+    POWER_ACTION Action;
+    SYSTEM_POWER_STATE LightestState;
+    ULONG Flags;
+    NTSTATUS Status;
+    UCHAR IrpMinor;
+    SYSTEM_POWER_STATE SystemState;
+    SYSTEM_POWER_STATE NextSystemState;
+    PPOP_SHUTDOWN_BUG_CHECK ShutdownBugCode;
+    PPOP_DEVICE_SYS_STATE DevState;
+    PPOP_HIBER_CONTEXT HiberContext;
+    ULONGLONG WakeTime;
+    ULONGLONG SleepTime;
+} POP_POWER_ACTION, *PPOP_POWER_ACTION;
+
+typedef enum _POP_DEVICE_IDLE_TYPE
+{
+    DeviceIdleNormal,
+    DeviceIdleDisk,
+} POP_DEVICE_IDLE_TYPE, *PPOP_DEVICE_IDLE_TYPE;
+
+typedef struct _POWER_CHANNEL_SUMMARY
+{
+    ULONG Signature;
+    ULONG TotalCount;
+    ULONG D0Count;
+    LIST_ENTRY NotifyList;
+} POWER_CHANNEL_SUMMARY, *PPOWER_CHANNEL_SUMMARY;
+    
+typedef struct  _DEVICE_OBJECT_POWER_EXTENSION
+{
+    ULONG IdleCount;
+    ULONG ConservationIdleTime;
+    ULONG PerformanceIdleTime;
+    PDEVICE_OBJECT DeviceObject;
+    LIST_ENTRY IdleList;
+    DEVICE_POWER_STATE State;
+    LIST_ENTRY NotifySourceList;
+    LIST_ENTRY NotifyTargetList;
+    POWER_CHANNEL_SUMMARY PowerChannelSummary;
+    LIST_ENTRY Volume;
+} DEVICE_OBJECT_POWER_EXTENSION, *PDEVICE_OBJECT_POWER_EXTENSION;
+
 //
 // Initialization routines
 //
@@ -45,6 +267,21 @@
 NTAPI
 PoInitializePrcb(
     IN PKPRCB Prcb
+);
+
+//
+// I/O Routines
+//
+VOID
+NTAPI
+PoInitializeDeviceObject(
+    IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension
+);
+
+VOID
+NTAPI
+PoVolumeDevice(
+    IN PDEVICE_OBJECT DeviceObject
 );
 
 //
@@ -79,6 +316,32 @@
 );
 
 //
+// Shutdown routines
+//
+VOID
+NTAPI
+PopReadShutdownPolicy(
+    VOID
+);
+
+VOID
+NTAPI
+PopGracefulShutdown(
+    IN PVOID Context
+);
+
+VOID
+NTAPI
+PopFlushVolumes(
+    IN BOOLEAN ShuttingDown
+);
+
+//
 // Global data inside the Power Manager
 //
 extern PDEVICE_NODE PopSystemPowerDeviceNode;
+extern KGUARDED_MUTEX PopVolumeLock;
+extern LIST_ENTRY PopVolumeDevices;
+extern KSPIN_LOCK PopDopeGlobalLock;
+extern POP_POWER_ACTION PopAction;
+

Modified: trunk/reactos/ntoskrnl/io/iomgr/device.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/device.c?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/device.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/device.c [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -17,9 +17,11 @@
 /* GLOBALS ********************************************************************/
 
 ULONG IopDeviceObjectNumber = 0;
-
 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
 KSPIN_LOCK ShutdownListLock;
+extern LIST_ENTRY IopDiskFsListHead;
+extern LIST_ENTRY IopCdRomFsListHead;
+extern LIST_ENTRY IopTapeFsListHead;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
@@ -95,7 +97,15 @@
 
 VOID
 NTAPI
-IoShutdownRegisteredDevices(VOID)
+IoShutdownPnpDevices(VOID)
+{
+    /* This routine is only used by Driver Verifier to validate shutdown */
+    return;
+}
+
+VOID
+NTAPI
+IoShutdownSystem(IN ULONG Phase)
 {
     PLIST_ENTRY ListEntry;
     PDEVICE_OBJECT DeviceObject;
@@ -104,46 +114,108 @@
     PIRP Irp;
     KEVENT Event;
     NTSTATUS Status;
-
+        
     /* Initialize an event to wait on */
     KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
-    /* Get the first entry and start looping */
-    ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
-                                            &ShutdownListLock);
-    while (ListEntry)
-    {
-        /* Get the shutdown entry */
-        ShutdownEntry = CONTAINING_RECORD(ListEntry,
-                                          SHUTDOWN_ENTRY,
-                                          ShutdownList);
-
-        /* Get the attached device */
-        DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
-
-        /* Build the shutdown IRP and call the driver */
-        Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
-                                           DeviceObject,
-                                           NULL,
-                                           0,
-                                           NULL,
-                                           &Event,
-                                           &StatusBlock);
-        Status = IoCallDriver(DeviceObject, Irp);
-        if (Status == STATUS_PENDING)
-        {
-            /* Wait on the driver */
-            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-        }
-
-        /* Free the shutdown entry and reset the event */
-        ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
-        KeClearEvent(&Event);
-
-        /* Go to the next entry */
+    
+    /* What phase? */
+    if (Phase == 0)
+    {
+        /* Shutdown PnP */
+        IoShutdownPnpDevices();
+
+        /* Loop first-chance shutdown notifications */
         ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
                                                 &ShutdownListLock);
-     }
+        while (ListEntry)
+        {
+            /* Get the shutdown entry */
+            ShutdownEntry = CONTAINING_RECORD(ListEntry,
+                                              SHUTDOWN_ENTRY,
+                                              ShutdownList);
+
+            /* Get the attached device */
+            DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
+
+            /* Build the shutdown IRP and call the driver */
+            Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
+                                               DeviceObject,
+                                               NULL,
+                                               0,
+                                               NULL,
+                                               &Event,
+                                               &StatusBlock);
+            Status = IoCallDriver(DeviceObject, Irp);
+            if (Status == STATUS_PENDING)
+            {
+                /* Wait on the driver */
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+            }
+
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
+            
+            /* Free the shutdown entry and reset the event */
+            ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            KeClearEvent(&Event);
+
+            /* Go to the next entry */
+            ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
+                                                    &ShutdownListLock);
+         }
+    }
+    else if (Phase == 1)
+    {
+        /* Shutdown disk file systems */
+        IopShutdownBaseFileSystems(&IopDiskFsListHead);
+
+        /* Shutdown cdrom file systems */
+        IopShutdownBaseFileSystems(&IopCdRomFsListHead);
+
+        /* Shutdown tape filesystems */
+        IopShutdownBaseFileSystems(&IopTapeFsListHead);
+        
+        /* Loop last-chance shutdown notifications */
+        ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
+                                                &ShutdownListLock);
+        while (ListEntry)
+        {
+            /* Get the shutdown entry */
+            ShutdownEntry = CONTAINING_RECORD(ListEntry,
+                                              SHUTDOWN_ENTRY,
+                                              ShutdownList);
+
+            /* Get the attached device */
+            DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
+
+            /* Build the shutdown IRP and call the driver */
+            Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
+                                               DeviceObject,
+                                               NULL,
+                                               0,
+                                               NULL,
+                                               &Event,
+                                               &StatusBlock);
+            Status = IoCallDriver(DeviceObject, Irp);
+            if (Status == STATUS_PENDING)
+            {
+                /* Wait on the driver */
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+            }
+
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
+            
+            /* Free the shutdown entry and reset the event */
+            ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            KeClearEvent(&Event);
+
+            /* Go to the next entry */
+            ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
+                                                    &ShutdownListLock);
+         }
+
+    }
 }
 
 NTSTATUS
@@ -843,6 +915,9 @@
     /* Set the Type and Size. Question: why is Size 0 on Windows? */
     DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
     DeviceObjectExtension->Size = 0;
+    
+    /* Initialize with Power Manager */
+    PoInitializeDeviceObject(DeviceObjectExtension);
 
     /* Link the Object and Extension */
     DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
@@ -932,6 +1007,9 @@
     ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
     CreatedDeviceObject->DriverObject = DriverObject;
     IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
+    
+    /* Link with the power manager */
+    if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
 
     /* Close the temporary handle and return to caller */
     ObCloseHandle(TempHandle, KernelMode);
@@ -1351,6 +1429,9 @@
 
     /* Set the DO */
     Entry->DeviceObject = DeviceObject;
+    
+    /* Reference it so it doesn't go away */
+    ObReferenceObject(DeviceObject);
 
     /* Insert it into the list */
     ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
@@ -1379,6 +1460,9 @@
 
     /* Set the DO */
     Entry->DeviceObject = DeviceObject;
+    
+    /* Reference it so it doesn't go away */
+    ObReferenceObject(DeviceObject);
 
     /* Insert it into the list */
     ExInterlockedInsertHeadList(&ShutdownListHead,
@@ -1420,6 +1504,9 @@
 
             /* Free the entry */
             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
         }
 
         /* Go to the next entry */
@@ -1444,6 +1531,9 @@
 
             /* Free the entry */
             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
+            
+            /* Get rid of our reference to it */
+            ObDereferenceObject(DeviceObject);
         }
 
         /* Go to the next entry */

Modified: trunk/reactos/ntoskrnl/io/iomgr/volume.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/volume.c?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/volume.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/volume.c [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -245,7 +245,7 @@
 
 VOID
 NTAPI
-IoShutdownRegisteredFileSystems(VOID)
+IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead)
 {
     PLIST_ENTRY ListEntry;
     PDEVICE_OBJECT DeviceObject;
@@ -260,8 +260,8 @@
     KeInitializeEvent(&Event, NotificationEvent, FALSE);
 
     /* Get the first entry and start looping */
-    ListEntry = IopDiskFsListHead.Flink;
-    while (ListEntry != &IopDiskFsListHead)
+    ListEntry = ListHead->Flink;
+    while (ListEntry != ListHead)
     {
         /* Get the device object */
         DeviceObject = CONTAINING_RECORD(ListEntry,

Modified: trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -438,8 +438,10 @@
 		<file>obwait.c</file>
 	</directory>
 	<directory name="po">
+	    <file>events.c</file>
 		<file>power.c</file>
-		<file>events.c</file>
+		<file>poshtdwn.c</file>
+		<file>povolume.c</file>
 	</directory>
 	<directory name="ps">
 		<if property="ARCH" value="i386">

Added: trunk/reactos/ntoskrnl/po/poshtdwn.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/po/poshtdwn.c?rev=46004&view=auto
==============================================================================
--- trunk/reactos/ntoskrnl/po/poshtdwn.c (added)
+++ trunk/reactos/ntoskrnl/po/poshtdwn.c [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -1,0 +1,196 @@
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/po/poshtdwn.c
+ * PURPOSE:         Power Manager Shutdown Code
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+ULONG PopShutdownPowerOffPolicy;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+PopShutdownHandler(VOID)
+{
+    PUCHAR Logo1, Logo2;
+    ULONG i;
+    
+    /* Stop all interrupts */
+    KeRaiseIrqlToDpcLevel();
+    _disable();
+
+    /* Do we have boot video */
+    if (InbvIsBootDriverInstalled())
+    {
+        /* Yes we do, cleanup for shutdown screen */
+        if (!InbvCheckDisplayOwnership()) InbvAcquireDisplayOwnership();
+        InbvResetDisplay();
+        InbvSolidColorFill(0, 0, 639, 479, 0);
+        InbvEnableDisplayString(TRUE);
+        InbvSetScrollRegion(0, 0, 639, 479);
+
+        /* Display shutdown logo and message */
+        Logo1 = InbvGetResourceAddress(IDB_SHUTDOWN_LOGO);
+        Logo2 = InbvGetResourceAddress(IDB_LOGO);
+        if ((Logo1) && (Logo2))
+        {
+            InbvBitBlt(Logo1, 215, 352);
+            InbvBitBlt(Logo2, 217, 111);
+        }
+    }
+    else
+    {
+        /* Do it in text-mode */
+        for (i = 0; i < 25; i++) InbvDisplayString("\n");
+        InbvDisplayString("                       ");
+        InbvDisplayString("The system may be powered off now.\n");
+    }
+
+    /* Hang the system */
+    for (;;) HalHaltSystem();
+}
+
+VOID
+NTAPI
+PopShutdownSystem(IN POWER_ACTION SystemAction)
+{
+    /* Note should notify caller of NtPowerInformation(PowerShutdownNotification) */
+
+    /* Unload symbols */
+    DPRINT1("It's the final countdown...%lx\n", SystemAction);
+    DbgUnLoadImageSymbols(NULL, (PVOID)-1, 0);
+    
+    /* Run the thread on the boot processor */
+    KeSetSystemAffinityThread(1);
+
+    /* Now check what the caller wants */
+    switch (SystemAction)
+    {
+        /* Reset */
+        case PowerActionShutdownReset:
+
+            /* Try platform driver first, then legacy */
+            //PopInvokeSystemStateHandler(PowerStateShutdownReset, NULL);
+            HalReturnToFirmware(HalRebootRoutine);
+            break;
+
+        case PowerActionShutdown:
+
+            /* Check for group policy that says to use "it is now safe" screen */
+            if (PopShutdownPowerOffPolicy)
+            {
+                /* FIXFIX: Switch to legacy shutdown handler */
+                //PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler;
+            }
+
+        case PowerActionShutdownOff:
+
+            /* Call shutdown handler */
+            //PopInvokeSystemStateHandler(PowerStateShutdownOff, NULL);
+            
+            /* ReactOS Hack */
+            PopSetSystemPowerState(PowerSystemShutdown);
+            PopShutdownHandler();
+
+            /* If that didn't work, call the HAL */
+            HalReturnToFirmware(HalPowerDownRoutine);
+            break;
+
+        default:
+            break;
+    }
+
+    /* Anything else should not happen */
+    KeBugCheckEx(INTERNAL_POWER_ERROR, 5, 0, 0, 0);
+}
+
+VOID
+NTAPI
+PopGracefulShutdown(IN PVOID Context)
+{
+    /* First, the HAL handles any "end of boot" special functionality */
+    DPRINT1("HAL shutting down\n");
+    HalEndOfBoot();
+
+    /* In this step, the I/O manager does first-chance shutdown notification */
+    DPRINT1("I/O manager shutting down in phase 0\n");    
+    IoShutdownSystem(0);
+    
+    /* In this step, all workers are killed and hives are flushed */
+    DPRINT1("Configuration Manager shutting down\n");
+    CmShutdownSystem();
+    
+    /* Note that modified pages should be written here (MiShutdownSystem) */
+
+    /* In this step, the I/O manager does last-chance shutdown notification */
+    DPRINT1("I/O manager shutting down in phase 1\n"); 
+    IoShutdownSystem(1);
+    CcWaitForCurrentLazyWriterActivity();
+
+    /* Note that here, we should broadcast the power IRP to devices */
+
+    /* In this step, the HAL disables any wake timers */
+    DPRINT1("Disabling wake timers\n");
+    HalSetWakeEnable(FALSE);
+    
+    /* And finally the power request is sent */
+    DPRINT1("Taking the system down\n");
+    PopShutdownSystem(PopAction.Action);
+}
+
+VOID
+NTAPI
+PopReadShutdownPolicy(VOID)
+{
+    UNICODE_STRING KeyString;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    NTSTATUS Status;
+    HANDLE KeyHandle;
+    ULONG Length;
+    UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
+    PKEY_VALUE_PARTIAL_INFORMATION Info = (PVOID)Buffer;
+    
+    /* Setup object attributes */
+    RtlInitUnicodeString(&KeyString,
+                         L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT");
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyString,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               NULL,
+                               NULL);
+
+    /* Open the key */
+    Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
+    if (NT_SUCCESS(Status))
+    {
+        /* Open the policy value and query it */
+        RtlInitUnicodeString(&KeyString, L"DontPowerOffAfterShutdown");
+        Status = ZwQueryValueKey(KeyHandle,
+                                 &KeyString,
+                                 KeyValuePartialInformation,
+                                 &Info,
+                                 sizeof(Info),
+                                 &Length);
+        if ((NT_SUCCESS(Status)) && (Info->Type == REG_DWORD))
+        {
+            /* Read the policy */
+            PopShutdownPowerOffPolicy = *Info->Data == 1;
+        }
+
+        /* Close the key */
+        ZwClose(KeyHandle);
+    }
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+

Propchange: trunk/reactos/ntoskrnl/po/poshtdwn.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: trunk/reactos/ntoskrnl/po/povolume.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/po/povolume.c?rev=46004&view=auto
==============================================================================
--- trunk/reactos/ntoskrnl/po/povolume.c (added)
+++ trunk/reactos/ntoskrnl/po/povolume.c [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -1,0 +1,334 @@
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/po/povolume.c
+ * PURPOSE:         Power Manager DOPE and Volume Management
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+typedef struct _POP_FLUSH_VOLUME
+{
+    LIST_ENTRY List;
+    LONG Count;
+    KEVENT Wait;
+} POP_FLUSH_VOLUME, *PPOP_FLUSH_VOLUME;
+ 
+ULONG PopFlushPolicy = 0;
+
+KGUARDED_MUTEX PopVolumeLock;
+LIST_ENTRY PopVolumeDevices;
+KSPIN_LOCK PopDopeGlobalLock;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+PDEVICE_OBJECT_POWER_EXTENSION
+NTAPI
+PopGetDope(IN PDEVICE_OBJECT DeviceObject)
+{
+    PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
+    PDEVICE_OBJECT_POWER_EXTENSION Dope;
+    KIRQL OldIrql;
+    PAGED_CODE();
+
+    /* If the device already has the dope, return it */
+    DeviceExtension = IoGetDevObjExtension(DeviceObject);
+    if (DeviceExtension->Dope) goto Return;
+
+    /* Allocate some dope for the device */
+    Dope = ExAllocatePoolWithTag(NonPagedPool,
+                                 sizeof(DEVICE_OBJECT_POWER_EXTENSION),
+                                 'Dope');
+    if (!Dope) goto Return;
+
+    /* Initialize the initial contents of the dope */
+    RtlZeroMemory(Dope, sizeof(DEVICE_OBJECT_POWER_EXTENSION));
+    Dope->DeviceObject = DeviceObject;
+    Dope->State = PowerDeviceUnspecified;
+    InitializeListHead(&Dope->IdleList);
+
+    /* Make sure only one caller can assign dope to a device */
+    KeAcquireSpinLock(&PopDopeGlobalLock, &OldIrql);
+    
+    /* Make sure the device still has no dope */
+    if (!DeviceExtension->Dope)
+    {
+        /* Give the local dope to this device, and remember we won the race */
+        DeviceExtension->Dope = (PVOID)Dope;
+        Dope = NULL;
+    }
+
+    /* Allow other dope transactions now */
+    KeReleaseSpinLock(&PopDopeGlobalLock, OldIrql);
+    
+    /* Check if someone other than us already assigned the dope, so free ours */
+    if (Dope) ExFreePoolWithTag(Dope, 'Dope');
+
+    /* Return the dope to the caller */
+Return:
+    return (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope;
+}
+
+VOID
+NTAPI
+PoVolumeDevice(IN PDEVICE_OBJECT DeviceObject)
+{
+    PDEVICE_OBJECT_POWER_EXTENSION Dope;
+    PAGED_CODE();
+
+    /* Get dope from the device (if the device has no dope, it will receive some) */
+    DPRINT1("New volume: %p\n", DeviceObject);
+    Dope = PopGetDope(DeviceObject);
+    if (Dope)
+    {
+        /* Make sure we can flush safely */
+        DPRINT1("Acquiring volume lock\n");
+        KeAcquireGuardedMutex(&PopVolumeLock);
+
+        /* Add this volume into the list of power-manager volumes */
+        DPRINT1("Got DOPE: %p\n", Dope);
+        if (!Dope->Volume.Flink) InsertTailList(&PopVolumeDevices, &Dope->Volume);
+        
+        /* Allow flushes to go through */
+        KeReleaseGuardedMutex(&PopVolumeLock);
+    }
+}
+    
+VOID
+NTAPI
+PopFlushVolumeWorker(IN PVOID Context)
+{
+    PPOP_FLUSH_VOLUME FlushContext = (PPOP_FLUSH_VOLUME)Context;
+    PDEVICE_OBJECT_POWER_EXTENSION Dope;
+    PLIST_ENTRY NextEntry;
+    NTSTATUS Status;
+    UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + 512];
+    POBJECT_NAME_INFORMATION NameInfo = (PVOID)Buffer;
+    ULONG Length;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE VolumeHandle;
+    IO_STATUS_BLOCK IoStatusBlock;
+
+    /* Acquire the flush lock since we're messing with the list */
+    KeAcquireGuardedMutex(&PopVolumeLock);
+
+    /* Loop the flush list */
+    while (!IsListEmpty(&FlushContext->List))
+    {
+        /* Grab the next (ie: current) entry and remove it */
+        NextEntry = FlushContext->List.Flink;
+        RemoveEntryList(NextEntry);
+        
+        /* Add it back on the volume list */
+        InsertTailList(&PopVolumeDevices, NextEntry);
+        
+        /* Done touching the volume list */
+        KeReleaseGuardedMutex(&PopVolumeLock);
+
+        /* Get the dope from the volume link */
+        Dope = CONTAINING_RECORD(NextEntry, DEVICE_OBJECT_POWER_EXTENSION, Volume);
+
+        /* Get the name */
+        Status = ObQueryNameString(Dope->DeviceObject,
+                                   NameInfo,
+                                   sizeof(Buffer),
+                                   &Length);
+        if ((NT_SUCCESS(Status)) && (NameInfo->Name.Buffer))
+        {
+            /* Open the volume */
+            DPRINT1("Opening: %wZ\n", &NameInfo->Name);
+            InitializeObjectAttributes(&ObjectAttributes,
+                                       &NameInfo->Name,
+                                       OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                       0,
+                                       0);
+            Status = ZwCreateFile(&VolumeHandle,
+                                  SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+                                  &ObjectAttributes,
+                                  &IoStatusBlock,
+                                  NULL,
+                                  GENERIC_READ | GENERIC_WRITE,
+                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                  FILE_OPEN,
+                                  0,
+                                  NULL,
+                                  0);
+            if (NT_SUCCESS(Status))
+            {
+                /* Flush it and close it */
+                DPRINT1("Sending flush to: %lx\n", VolumeHandle);
+                ZwFlushBuffersFile(VolumeHandle, &IoStatusBlock);
+                ZwClose(VolumeHandle);
+            }
+        }
+
+        /* Acquire the flush lock again since we'll touch the list */
+        KeAcquireGuardedMutex(&PopVolumeLock);
+    }
+
+    /* One more flush completed... if it was the last, signal the caller */
+    if (!--FlushContext->Count) KeSetEvent(&FlushContext->Wait, IO_NO_INCREMENT, FALSE);
+
+    /* Serialize with flushers */
+    KeReleaseGuardedMutex(&PopVolumeLock);
+}
+
+VOID
+NTAPI
+PopFlushVolumes(IN BOOLEAN ShuttingDown)
+{
+    POP_FLUSH_VOLUME FlushContext = {{0}};
+    ULONG FlushPolicy;
+    UNICODE_STRING RegistryName = RTL_CONSTANT_STRING(L"\\Registry");
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE RegistryHandle;
+    PLIST_ENTRY NextEntry;
+    PDEVICE_OBJECT_POWER_EXTENSION  Dope;    
+    ULONG VolumeCount = 0;
+    NTSTATUS Status;
+    HANDLE ThreadHandle;
+    ULONG ThreadCount;
+
+    /* Setup the flush context */
+    InitializeListHead(&FlushContext.List);
+    KeInitializeEvent(&FlushContext.Wait, NotificationEvent, FALSE);
+
+    /* What to flush */
+    FlushPolicy = ShuttingDown ? 1 | 2 : PopFlushPolicy;
+    if ((FlushPolicy & 1))
+    {
+        /* Registry flush requested, so open it */
+        DPRINT1("Opening registry\n");
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &RegistryName,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+        Status = ZwOpenKey(&RegistryHandle, KEY_READ, &ObjectAttributes);
+        if (NT_SUCCESS(Status))
+        {
+            /* Flush the registry */
+            DPRINT1("Flushing registry\n");
+            ZwFlushKey(RegistryHandle);
+            ZwClose(RegistryHandle);
+        }
+    }
+
+    /* Serialize with other flushes */
+    KeAcquireGuardedMutex(&PopVolumeLock);
+    
+    /* Scan the volume list */
+    NextEntry = PopVolumeDevices.Flink;
+    while (NextEntry != &PopVolumeDevices)
+    {
+        /* Get the dope from the link */
+        Dope = CONTAINING_RECORD(NextEntry, DEVICE_OBJECT_POWER_EXTENSION, Volume);
+        
+        /* Grab the next entry now, since we'll be modifying the list */
+        NextEntry = NextEntry->Flink;
+
+        /* Make sure the object is mounted, writable, exists, and is not a floppy */
+        if (!(Dope->DeviceObject->Vpb->Flags & VPB_MOUNTED) ||
+            (Dope->DeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) ||
+            (Dope->DeviceObject->Characteristics & FILE_READ_ONLY_DEVICE) ||
+            ((Dope->DeviceObject->Vpb->RealDevice) &&
+             (Dope->DeviceObject->Vpb->RealDevice->Characteristics & FILE_FLOPPY_DISKETTE)))
+        {
+            /* Not flushable */
+            continue;
+        }
+
+        /* Remove it from the dope and add it to the flush context list */
+        RemoveEntryList(&Dope->Volume);
+        InsertTailList(&FlushContext.List, &Dope->Volume);
+        
+        /* Next */
+        VolumeCount++;
+    }
+
+    /* Check if we should skip non-removable devices */
+    if (!(FlushPolicy & 2))
+    {
+        /* ReactOS only implements this routine for shutdown, which requires it */
+        UNIMPLEMENTED;
+        while (TRUE);
+    }
+
+    /* Check if there were no volumes at all */
+    if (!VolumeCount)
+    {
+        /* Nothing to do */
+        KeReleaseGuardedMutex(&PopVolumeLock);
+        return;
+    }
+
+    /* Allocate up to 8 flusher threads */
+    ThreadCount = min(VolumeCount, 8);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               NULL,
+                               OBJ_KERNEL_HANDLE,
+                               NULL,
+                               NULL);
+
+    /* We will ourselves become a flusher thread */
+    FlushContext.Count = 1;
+    ThreadCount--;
+    
+    /* Look for any extra ones we might need */
+    while (ThreadCount > 0)
+    {
+        /* Create a new one */
+        ThreadCount--;
+        DPRINT1("Creating flush thread\n");
+        Status = PsCreateSystemThread(&ThreadHandle,
+                                      THREAD_ALL_ACCESS,
+                                      &ObjectAttributes,
+                                      0L,
+                                      NULL,
+                                      PopFlushVolumeWorker,
+                                      &FlushContext);
+        if (NT_SUCCESS(Status))
+        {
+            /* One more created... */
+            FlushContext.Count++;
+            ZwClose(ThreadHandle);
+        }
+    }
+
+    /* Allow flushes to go through */
+    KeReleaseGuardedMutex(&PopVolumeLock);
+
+    /* Enter the flush work */
+    DPRINT1("Local flush\n");
+    PopFlushVolumeWorker(&FlushContext);
+    
+    /* Wait for all flushes to be over */
+    DPRINT1("Waiting for flushes\n");
+    KeWaitForSingleObject(&FlushContext.Wait, Executive, KernelMode, FALSE, NULL);
+    DPRINT1("Flushes have completed\n");
+}
+
+VOID
+NTAPI
+PoInitializeDeviceObject(IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension)
+{
+    PEXTENDED_DEVOBJ_EXTENSION DeviceExtension = (PVOID)DeviceObjectExtension;
+    PAGED_CODE();
+
+    /* Initialize the power flags */
+    DeviceExtension->PowerFlags = PowerSystemUnspecified & 0xF;
+    DeviceExtension->PowerFlags |= ((PowerDeviceUnspecified << 4) & 0xF0);
+
+    /* The device object is not on drugs yet */
+    DeviceExtension->Dope = NULL;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+

Propchange: trunk/reactos/ntoskrnl/po/povolume.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/reactos/ntoskrnl/po/power.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/po/power.c?rev=46004&r1=46003&r2=46004&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/po/power.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/po/power.c [iso-8859-1] Mon Mar  8 21:47:10 2010
@@ -24,6 +24,8 @@
 
 PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
 BOOLEAN PopAcpiPresent = FALSE;
+POP_POWER_ACTION PopAction;
+WORK_QUEUE_ITEM PopShutdownWorkItem;
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
@@ -165,6 +167,13 @@
         PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
     }
 
+    
+    /* Initialize volume support */
+    InitializeListHead(&PopVolumeDevices);
+    KeInitializeGuardedMutex(&PopVolumeLock);
+    
+    /* Initialize support for dope */
+    KeInitializeSpinLock(&PopDopeGlobalLock);
     return TRUE;
 }
 
@@ -636,3 +645,138 @@
     /* All is good */
     return STATUS_SUCCESS;
 }
+
+NTSTATUS
+NTAPI
+NtSetSystemPowerState(IN POWER_ACTION SystemAction,
+		              IN SYSTEM_POWER_STATE MinSystemState,
+		              IN ULONG Flags)
+{
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    POP_POWER_ACTION Action = {0};
+    NTSTATUS Status;
+
+    /* Check for invalid parameter combinations */
+    if ((MinSystemState >= PowerSystemMaximum) ||
+        (MinSystemState <= PowerSystemUnspecified) ||
+        (SystemAction > PowerActionWarmEject) ||
+        (SystemAction < PowerActionReserved) ||
+        (Flags & ~(POWER_ACTION_QUERY_ALLOWED  |  
+                   POWER_ACTION_UI_ALLOWED     | 
+                   POWER_ACTION_OVERRIDE_APPS  | 
+                   POWER_ACTION_LIGHTEST_FIRST | 
+                   POWER_ACTION_LOCK_CONSOLE   | 
+                   POWER_ACTION_DISABLE_WAKES  | 
+                   POWER_ACTION_CRITICAL)))
+    {
+        DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
+        DPRINT1("                       SystemAction: 0x%x\n", SystemAction);
+        DPRINT1("                       MinSystemState: 0x%x\n", MinSystemState);
+        DPRINT1("                       Flags: 0x%x\n", Flags);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Check for user caller */
+    if (PreviousMode != KernelMode)
+    {
+        /* Check for shutdown permission */
+        if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
+        {
+            /* Not granted */
+            DPRINT1("ERROR: Privilege not held for shutdown\n");
+            //return STATUS_PRIVILEGE_NOT_HELD; HACK!
+        }
+
+        /* Do it as a kernel-mode caller for consistency with system state */
+        return ZwSetSystemPowerState (SystemAction, MinSystemState, Flags);
+    }
+
+    /* Read policy settings (partial shutdown vs. full shutdown) */
+    if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
+
+    /* Disable lazy flushing of registry */
+    DPRINT1("Stopping lazy flush\n");
+    CmSetLazyFlushState(FALSE);
+
+    /* Setup the power action */
+    Action.Action = SystemAction;
+    Action.Flags = Flags;
+
+    /* Notify callbacks */
+    DPRINT1("Notifying callbacks\n");
+    ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
+ 
+    /* Swap in any worker thread stacks */
+    DPRINT1("Swapping worker threads\n");
+    ExSwapinWorkerThreads(FALSE);
+    
+    /* Make our action global */
+    PopAction = Action;
+
+    /* Start power loop */
+    Status = STATUS_CANCELLED;
+    while (TRUE)
+    {
+        /* Break out if there's nothing to do */
+        if (Action.Action == PowerActionNone) break;
+
+        /* Check for first-pass or restart */
+        if (Status == STATUS_CANCELLED)
+        {
+            /* Check for shutdown action */
+            if ((PopAction.Action == PowerActionShutdown) ||
+                (PopAction.Action == PowerActionShutdownReset) ||
+                (PopAction.Action == PowerActionShutdownOff))
+            {
+                /* Set the action */
+                PopAction.Shutdown = TRUE;
+            }
+
+            /* Now we are good to go */
+            Status = STATUS_SUCCESS;
+        }
+
+        /* Check if we're still in an invalid status */
+        if (!NT_SUCCESS(Status)) break;
+
+        /* Flush all volumes and the registry */
+        DPRINT1("Flushing volumes\n");
+        PopFlushVolumes(PopAction.Shutdown);
+
+        /* Set IRP for drivers */
+        PopAction.IrpMinor = IRP_MN_SET_POWER;
+        if (PopAction.Shutdown)
+        {
+            DPRINT1("Queueing shutdown thread\n");
+            /* Check if we are running in the system context */
+            if (PsGetCurrentProcess() != PsInitialSystemProcess)
+            {
+                /* We're not, so use a worker thread for shutdown */
+                ExInitializeWorkItem(&PopShutdownWorkItem,
+                                     &PopGracefulShutdown,
+                                     NULL);
+
+                ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
+                                
+                /* Spend us -- when we wake up, the system is good to go down */
+                KeSuspendThread(KeGetCurrentThread());
+                Status = STATUS_SYSTEM_SHUTDOWN;
+                goto Exit;
+
+            }
+            else
+            {
+                /* Do the shutdown inline */
+                PopGracefulShutdown(NULL);
+            }
+        }
+        
+        /* You should not have made it this far */
+        ASSERT(FALSE && "System is still up and running?!");
+        break;
+    }
+
+Exit:
+    /* We're done, return */
+    return Status;
+}




More information about the Ros-diffs mailing list