[HEADERS]
[reactos.git] / reactos / drivers / storage / class / ramdisk / ramdisk.c
index 36dff70..1ebe196 100644 (file)
 
 #include <initguid.h>
 #include <ntddk.h>
+#include <ntifs.h>
 #include <ntdddisk.h>
+#include <ntddcdrm.h>
 #include <scsi.h>
 #include <ntddscsi.h>
+#include <ntddvol.h>
 #include <mountdev.h>
 #include <mountmgr.h>
-#include <helper.h>
 #include <ketypes.h>
 #include <iotypes.h>
 #include <rtlfuncs.h>
 #include <arc/arc.h>
 #include <reactos/drivers/ntddrdsk.h>
+#include "../../../filesystems/fs_rec/fs_rec.h"
+#include <stdio.h>
 #define NDEBUG
 #include <debug.h>
 
+#define DO_XIP   0x00020000
+
 /* GLOBALS ********************************************************************/
 
+#define RAMDISK_SESSION_SIZE \
+    FIELD_OFFSET(CDROM_TOC, TrackData) + sizeof(TRACK_DATA)
+    
+#define RAMDISK_TOC_SIZE \
+    FIELD_OFFSET(CDROM_TOC, TrackData) + 2 * sizeof(TRACK_DATA)
+                                    
+#define TOC_DATA_TRACK              (0x04)
+
 typedef enum _RAMDISK_DEVICE_TYPE
 {
-    RamdiskFdo,
-    RamdiskPdo
+    RamdiskBus,
+    RamdiskDrive
 } RAMDISK_DEVICE_TYPE;
 
 typedef enum _RAMDISK_DEVICE_STATE
@@ -40,6 +54,7 @@ typedef enum _RAMDISK_DEVICE_STATE
     RamdiskStateStopped,
     RamdiskStateRemoved,
     RamdiskStateBusRemoved,
+    RamdiskStateEnumerated,
 } RAMDISK_DEVICE_STATE;
 
 DEFINE_GUID(RamdiskBusInterface,
@@ -56,11 +71,47 @@ typedef struct _RAMDISK_EXTENSION
     PDEVICE_OBJECT PhysicalDeviceObject;
     PDEVICE_OBJECT AttachedDevice;
     IO_REMOVE_LOCK RemoveLock;
-    UNICODE_STRING SymbolicLinkName;
+    UNICODE_STRING DriveDeviceName;
+    UNICODE_STRING BusDeviceName;
     FAST_MUTEX DiskListLock;
-    LIST_ENTRY DiskListHead;
+    LIST_ENTRY DiskList;
 } RAMDISK_EXTENSION, *PRAMDISK_EXTENSION;
 
+typedef struct _RAMDISK_BUS_EXTENSION
+{
+    RAMDISK_EXTENSION;
+} RAMDISK_BUS_EXTENSION, *PRAMDISK_BUS_EXTENSION;
+
+typedef struct _RAMDISK_DRIVE_EXTENSION
+{
+    //
+    // Inherited base class
+    //
+    RAMDISK_EXTENSION;
+    
+    //
+    // Data we get from the creator
+    //
+    GUID DiskGuid;
+    UNICODE_STRING GuidString;
+    UNICODE_STRING SymbolicLinkName;
+    ULONG DiskType;
+    RAMDISK_CREATE_OPTIONS DiskOptions;
+    LARGE_INTEGER DiskLength;
+    LONG DiskOffset;
+    WCHAR DriveLetter;
+    ULONG BasePage;
+    
+    //
+    // Data we get from the disk
+    //
+    ULONG BytesPerSector;
+    ULONG SectorsPerTrack;
+    ULONG NumberOfHeads;
+    ULONG Cylinders;
+    ULONG HiddenSectors;
+} RAMDISK_DRIVE_EXTENSION, *PRAMDISK_DRIVE_EXTENSION;
+
 ULONG MaximumViewLength;
 ULONG MaximumPerDiskViewLength;
 ULONG ReportDetectedDevice;
@@ -231,187 +282,1831 @@ QueryParameters(IN PUNICODE_STRING RegistryPath)
     }
 }
 
-NTSTATUS
+PVOID
 NTAPI
-RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject,
-                 IN PIRP Irp)
+RamdiskMapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension,
+                IN LARGE_INTEGER Offset,
+                IN ULONG Length,
+                OUT PULONG OutputLength)
 {
+    PHYSICAL_ADDRESS PhysicalAddress;
+    PVOID MappedBase;
+    ULONG PageOffset;
+    SIZE_T ActualLength;
+    LARGE_INTEGER ActualOffset;
+    LARGE_INTEGER ActualPages;
+    
     //
-    // Complete the IRP
+    // We only support boot disks for now
     //
-    Irp->IoStatus.Information = 1;
-    Irp->IoStatus.Status = STATUS_SUCCESS;
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject,
-                 IN PIRP Irp)
-{
-    UNIMPLEMENTED;
-    while (TRUE);
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
-                     IN PIRP Irp)
-{
-    UNIMPLEMENTED;
-    while (TRUE);
-    return STATUS_SUCCESS;
+    ASSERT(DeviceExtension->DiskType == RAMDISK_BOOT_DISK);
+    
+    //
+    // Calculate the actual offset in the drive
+    //
+    ActualOffset.QuadPart = DeviceExtension->DiskOffset + Offset.QuadPart;
+    
+    //
+    // Convert to pages
+    //
+    ActualPages.QuadPart = ActualOffset.QuadPart >> PAGE_SHIFT;
+    
+    //
+    // Now add the base page
+    //
+    ActualPages.QuadPart = DeviceExtension->BasePage + ActualPages.QuadPart;
+    
+    //
+    // Calculate final amount of bytes
+    //
+    PhysicalAddress.QuadPart = ActualPages.QuadPart << PAGE_SHIFT;
+    
+    //
+    // Calculate pages spanned for the mapping
+    //
+    ActualLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset.QuadPart, Length);
+    
+    //
+    // And convert this back to bytes
+    //
+    ActualLength <<= PAGE_SHIFT;
+    
+    //
+    // Get the offset within the page
+    //
+    PageOffset = BYTE_OFFSET(ActualOffset.QuadPart);
+    
+    //
+    // Map the I/O Space from the loader
+    //
+    MappedBase = MmMapIoSpace(PhysicalAddress, ActualLength, MmCached);
+    
+    //
+    // Return actual offset within the page as well as the length
+    //
+    if (MappedBase) MappedBase = (PVOID)((ULONG_PTR)MappedBase + PageOffset);
+    *OutputLength = Length;
+    return MappedBase;
 }
 
-NTSTATUS
+VOID
 NTAPI
-RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
-           IN PIRP Irp)
+RamdiskUnmapPages(IN PRAMDISK_DRIVE_EXTENSION DeviceExtension,
+                  IN PVOID BaseAddress,
+                  IN LARGE_INTEGER Offset,
+                  IN ULONG Length)
 {
-    PIO_STACK_LOCATION IoStackLocation;
-    PRAMDISK_EXTENSION DeviceExtension;
-    NTSTATUS Status;
-    UCHAR Minor;
+    LARGE_INTEGER ActualOffset;
+    SIZE_T ActualLength;
+    ULONG PageOffset;
     
     //
-    // Get the device extension and stack location
+    // We only support boot disks for now
     //
-    DeviceExtension = DeviceObject->DeviceExtension;
-    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
-    Minor = IoStackLocation->MinorFunction;
+    ASSERT(DeviceExtension->DiskType == RAMDISK_BOOT_DISK);
     
     //
-    // Check if the bus is removed
+    // Calculate the actual offset in the drive
     //
-    if (DeviceExtension->State == RamdiskStateBusRemoved)
-    {
+    ActualOffset.QuadPart = DeviceExtension->DiskOffset + Offset.QuadPart;
+    
+    //
+    // Calculate pages spanned for the mapping
+    //
+    ActualLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(ActualOffset.QuadPart, Length);
+    
+    //
+    // And convert this back to bytes
+    //
+    ActualLength <<= PAGE_SHIFT;
+    
+    //
+    // Get the offset within the page
+    //
+    PageOffset = BYTE_OFFSET(ActualOffset.QuadPart);
+    
+    //
+    // Calculate actual base address where we mapped this
+    //
+    BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - PageOffset);
+    
+    //
+    // Unmap the I/O space we got from the loader
+    //
+    MmUnmapIoSpace(BaseAddress, ActualLength);
+}
+
+NTSTATUS
+NTAPI
+RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
+                                               IN PRAMDISK_CREATE_INPUT Input,
+                                               IN BOOLEAN ValidateOnly,
+                                               OUT PRAMDISK_DRIVE_EXTENSION *NewDriveExtension)
+{
+       ULONG BasePage, ViewCount, DiskType, Length;
+    NTSTATUS Status;
+    PDEVICE_OBJECT DeviceObject;
+    PRAMDISK_DRIVE_EXTENSION DriveExtension;
+    PVOID Buffer;
+    WCHAR LocalBuffer[16];
+    UNICODE_STRING SymbolicLinkName, DriveString, GuidString, DeviceName;
+    PPACKED_BOOT_SECTOR BootSector;
+    BIOS_PARAMETER_BLOCK BiosBlock;
+    ULONG BytesPerSector, SectorsPerTrack, Heads, BytesRead;
+    PVOID BaseAddress;
+    LARGE_INTEGER CurrentOffset, CylinderSize, DiskLength;
+    ULONG CylinderCount, SizeByCylinders;
+       
+       //
+       // Check if we're a boot RAM disk
+       //
+       DiskType = Input->DiskType;
+       if (DiskType >= RAMDISK_BOOT_DISK)
+       {
+               //
+               // Check if we're an ISO
+               // 
+               if (DiskType == RAMDISK_BOOT_DISK)
+               {
+                       //
+                       // NTLDR mounted us somewhere
+                       //
+                       BasePage = Input->BasePage;
+                       if (!BasePage) return STATUS_INVALID_PARAMETER;
+                       
+                       //
+                       // Sanitize disk options
+                       //
+                       Input->Options.Fixed = TRUE;
+                       Input->Options.Readonly = Input->Options.ExportAsCd |
+                                      Input->Options.Readonly;
+                       Input->Options.Hidden = FALSE;
+                       Input->Options.NoDosDevice = FALSE;
+                       Input->Options.NoDriveLetter = IsWinPEBoot ? TRUE : FALSE;
+               }
+               else
+               {
+                       //
+                       // The only other possibility is a WIM disk
+                       //
+                       if (DiskType != RAMDISK_WIM_DISK)
+            {
+                //
+                // Fail
+                //
+                return STATUS_INVALID_PARAMETER;
+            }
+                       
+                       //
+                       // Read the view count instead
+                       //
+                       ViewCount = Input->ViewCount;
+                       
+                       //
+                       // Sanitize disk options
+                       //
+                       Input->Options.Hidden = FALSE;
+                       Input->Options.NoDosDevice = FALSE;
+                       Input->Options.Readonly = FALSE;
+                       Input->Options.NoDriveLetter = TRUE;
+                       Input->Options.Fixed = TRUE;
+               }
+               
+               //
+               // Are we just validating and returning to the user?
+               //
+               if (ValidateOnly) return STATUS_SUCCESS;
+        
         //
-        // Only remove-device and query-id are allowed
+        // Build the GUID string
         //
-        if ((Minor != IRP_MN_REMOVE_DEVICE) || (Minor != IRP_MN_QUERY_ID))
+        Status = RtlStringFromGUID(&Input->DiskGuid, &GuidString);
+        if (!(NT_SUCCESS(Status)) || !(GuidString.Buffer))
         {
             //
-            // Fail anything else
+            // Fail
             //
-            Status = STATUS_NO_SUCH_DEVICE;
-            Irp->IoStatus.Status = Status;
-            IoCompleteRequest(Irp, IO_NO_INCREMENT);
-            return Status;
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto FailCreate;
         }
-    }
-    
-    //
-    // Acquire the remove lock
-    //
-    Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
-    if (!NT_SUCCESS(Status))
-    {
+        
         //
-        // Fail the IRP
+        // Allocate our device name
         //
-        Irp->IoStatus.Information = 0;
-        Irp->IoStatus.Status = Status;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        return Status;
-    }
-    
-    //
-    // Query the IRP type
-    //
-    switch (Minor)
-    {
-        case IRP_MN_START_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_QUERY_STOP_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_CANCEL_STOP_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_STOP_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_QUERY_REMOVE_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_CANCEL_REMOVE_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_REMOVE_DEVICE:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-
-        case IRP_MN_SURPRISE_REMOVAL:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
-            
-        case IRP_MN_QUERY_ID:
-            
+        Length = GuidString.Length + 32;
+        Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                       Length,
+                                       'dmaR');
+        if (!Buffer)
+        {
             //
-            // Are we a PDO?
+            // Fail
             //
-            if (DeviceExtension->Type == RamdiskPdo)
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            goto FailCreate;
+        }
+        
+        // 
+        // Build the device name string
+        //
+        DeviceName.Buffer = Buffer;
+        DeviceName.Length = Length - 2;
+        DeviceName.MaximumLength = Length;
+        wcsncpy(Buffer, L"\\Device\\Ramdisk", Length / sizeof(WCHAR));
+        wcsncat(Buffer, GuidString.Buffer, Length / sizeof(WCHAR));
+        
+        //
+        // Create the drive device
+        //
+        Status = IoCreateDevice(DeviceExtension->DeviceObject->DriverObject,
+                                sizeof(RAMDISK_DRIVE_EXTENSION),
+                                &DeviceName,
+                                (Input->Options.ExportAsCd) ?
+                                FILE_DEVICE_CD_ROM : FILE_DEVICE_DISK,
+                                0,
+                                0,
+                                &DeviceObject);
+        if (!NT_SUCCESS(Status)) goto FailCreate;
+        
+        //
+        // Grab the drive extension
+        //
+        DriveExtension = DeviceObject->DeviceExtension;
+       
+        //
+        // Check if we need a DOS device
+        //
+        if (!Input->Options.NoDosDevice)
+        {
+            //
+            // Build the symbolic link name
+            //
+            SymbolicLinkName.MaximumLength = GuidString.Length + 36;
+            SymbolicLinkName.Length = GuidString.Length + 34;
+            Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                           SymbolicLinkName.MaximumLength,
+                                           'dmaR');
+            SymbolicLinkName.Buffer = Buffer;
+            if (Buffer)
             {
-                DPRINT1("PnP IRP: %lx\n", Minor);
-                while (TRUE);
-            }            
-            break;
-            
-        case IRP_MN_QUERY_BUS_INFORMATION:
-            
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
+                //
+                // Create it
+                //
+                wcsncpy(Buffer,
+                        L"\\GLOBAL??\\Ramdisk",
+                        SymbolicLinkName.MaximumLength / sizeof(WCHAR));
+                wcsncat(Buffer,
+                        GuidString.Buffer,
+                        SymbolicLinkName.MaximumLength / sizeof(WCHAR));
+                Status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
+                if (!NT_SUCCESS(Status))
+                {
+                    //
+                    // Nevermind...
+                    //
+                    Input->Options.NoDosDevice = TRUE;
+                    ExFreePool(Buffer);
+                    SymbolicLinkName.Buffer = NULL;
+                }
+            }
+            else
+            {
+                //
+                // No DOS device
+                //
+                Input->Options.NoDosDevice = TRUE;
+            }
             
-        case IRP_MN_EJECT:
+            //
+            // It this an ISO boot ramdisk?
+            //
+            if (Input->DiskType == RAMDISK_BOOT_DISK)
+            {
+                //
+                // Does it need a drive letter?
+                //
+                if (!Input->Options.NoDriveLetter)
+                {
+                    //
+                    // Build it and take over the existing symbolic link
+                    //
+                    _snwprintf(LocalBuffer,
+                               30,
+                               L"\\DosDevices\\%wc:",
+                               Input->DriveLetter);
+                    RtlInitUnicodeString(&DriveString, LocalBuffer);
+                    IoDeleteSymbolicLink(&DriveString);
+                    IoCreateSymbolicLink(&DriveString, &DeviceName);
+                    
+                    //
+                    // Save the drive letter
+                    //
+                    DriveExtension->DriveLetter = Input->DriveLetter;
+                }
+            }
             
-            DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);
-            break;
+        }
+        
+        //
+        // Setup the device object flags
+        //
+        DeviceObject->Flags |= (DO_XIP | DO_POWER_PAGABLE | DO_DIRECT_IO);
+        DeviceObject->AlignmentRequirement = 1;
+        
+        //
+        // Build the drive FDO
+        //
+        *NewDriveExtension = DriveExtension;
+        DriveExtension->Type = RamdiskDrive;
+        DiskLength = Input->DiskLength;
+               ExInitializeFastMutex(&DriveExtension->DiskListLock);
+           IoInitializeRemoveLock(&DriveExtension->RemoveLock,
+                               'dmaR',
+                               0,
+                               1);
+        DriveExtension->DriveDeviceName = DeviceName;
+        DriveExtension->SymbolicLinkName = SymbolicLinkName;
+        DriveExtension->GuidString = GuidString;
+        DriveExtension->DiskGuid = Input->DiskGuid;
+           DriveExtension->PhysicalDeviceObject = DeviceObject;
+           DriveExtension->DeviceObject = RamdiskBusFdo;
+        DriveExtension->AttachedDevice = RamdiskBusFdo;
+        DriveExtension->DiskType = Input->DiskType;
+        DriveExtension->DiskOptions = Input->Options;
+        DriveExtension->DiskLength = DiskLength;
+        DriveExtension->DiskOffset = Input->DiskOffset;
+        DriveExtension->BasePage = Input->BasePage;
+        DriveExtension->BytesPerSector = 0;
+        DriveExtension->SectorsPerTrack = 0;
+        DriveExtension->NumberOfHeads = 0;
+        
+        //
+        // Make sure we don't free it later
+        //
+        DeviceName.Buffer = NULL;
+        SymbolicLinkName.Buffer = NULL;
+        GuidString.Buffer = NULL;
+        
+        //
+        // Check if this is an boot disk, or a registry ram drive
+        //
+        if (!(Input->Options.ExportAsCd) &&
+            (Input->DiskType == RAMDISK_BOOT_DISK))
+        {
+            //
+            // Not an ISO boot, but it's a boot FS -- map it to figure out the
+            // drive settings
+            //
+            CurrentOffset.QuadPart = 0;
+            BaseAddress = RamdiskMapPages(DriveExtension,
+                                          CurrentOffset,
+                                          PAGE_SIZE,
+                                          &BytesRead);
+            if (BaseAddress)
+            {
+                //
+                // Get the data
+                //
+                BootSector = (PPACKED_BOOT_SECTOR)BaseAddress;
+                FatUnpackBios(&BiosBlock, &BootSector->PackedBpb);
+                BytesPerSector = BiosBlock.BytesPerSector;
+                SectorsPerTrack = BiosBlock.SectorsPerTrack;
+                Heads = BiosBlock.Heads;
+                
+                //
+                // Save it
+                //
+                DriveExtension->BytesPerSector = BytesPerSector;
+                DriveExtension->SectorsPerTrack = SectorsPerTrack;
+                DriveExtension->NumberOfHeads = Heads;
+                
+                //
+                // Unmap now
+                //
+                CurrentOffset.QuadPart = 0;
+                RamdiskUnmapPages(DriveExtension,
+                                  BaseAddress,
+                                  CurrentOffset,
+                                  BytesRead);
+            }
+            else
+            {
+                //
+                // Fail
+                //
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto FailCreate;
+            }
+        }
+                
+        //
+        // Check if the drive settings haven't been set yet
+        //
+        if ((DriveExtension->BytesPerSector == 0) ||
+            (DriveExtension->SectorsPerTrack == 0) ||
+            (DriveExtension->NumberOfHeads == 0))
+        {
+            //
+            // Check if this is a CD
+            //
+            if (Input->Options.ExportAsCd)
+            {
+                //
+                // Setup partition parameters default for ISO 9660
+                //
+                DriveExtension->BytesPerSector = 2048;
+                DriveExtension->SectorsPerTrack = 32;
+                DriveExtension->NumberOfHeads = 64;
+            }
+            else
+            {
+                //
+                // Setup partition parameters default for FAT
+                //
+                DriveExtension->BytesPerSector = 512;
+                DriveExtension->SectorsPerTrack = 128;
+                DriveExtension->NumberOfHeads = 16;
+            }
+        }
+        
+        //
+        // Calculate the cylinder size
+        //
+        CylinderSize.QuadPart = DriveExtension->BytesPerSector *
+                                DriveExtension->SectorsPerTrack *
+                                DriveExtension->NumberOfHeads;
+        CylinderCount = DiskLength.QuadPart / CylinderSize.QuadPart;
+        SizeByCylinders = CylinderSize.QuadPart * CylinderCount;
+        DriveExtension->Cylinders = CylinderCount;
+        if ((DiskLength.HighPart > 0) || (SizeByCylinders < DiskLength.LowPart))
+        {
+            //
+            // Align cylinder size up
+            //
+            DriveExtension->Cylinders++;
+        }
+        
+        //
+        // Acquire the disk lock
+        //
+        KeEnterCriticalRegion();
+        ExAcquireFastMutex(&DeviceExtension->DiskListLock);
+        
+        //
+        // Insert us
+        //
+        InsertTailList(&DeviceExtension->DiskList, &DriveExtension->DiskList);
+        
+        //
+        // Release the lock
+        //
+        ExReleaseFastMutex(&DeviceExtension->DiskListLock);
+        KeLeaveCriticalRegion();
+        
+        //
+        // Clear init flag
+        //
+        DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+        return STATUS_SUCCESS;
+    }
+    
+FailCreate:
+    UNIMPLEMENTED;
+    while (TRUE);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject,
+                     IN PIRP Irp,
+                                        IN BOOLEAN ValidateOnly)
+{
+       PRAMDISK_CREATE_INPUT Input;
+       ULONG Length;
+       PRAMDISK_BUS_EXTENSION DeviceExtension;
+    PRAMDISK_DRIVE_EXTENSION DriveExtension; 
+       ULONG DiskType;
+       PWCHAR FileNameStart, FileNameEnd;
+       NTSTATUS Status;
+       PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+       
+       //
+       // Get the device extension and our input data
+       //
+       DeviceExtension = DeviceObject->DeviceExtension;
+       Length = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength;
+       Input = (PRAMDISK_CREATE_INPUT)Irp->AssociatedIrp.SystemBuffer;
+       
+       //
+       // Validate input parameters
+       //
+       if ((Length < sizeof(RAMDISK_CREATE_INPUT)) ||
+               (Input->Version != sizeof(RAMDISK_CREATE_INPUT)))
+       {
+               //
+               // Invalid input
+               //
+               return STATUS_INVALID_PARAMETER;
+       }
+       
+       //
+       // Validate the disk type
+       //
+       DiskType = Input->DiskType;
+       if (DiskType == RAMDISK_WIM_DISK) return STATUS_INVALID_PARAMETER;
+       
+       //
+       // Look at the disk type
+       //
+       if (DiskType == RAMDISK_BOOT_DISK)
+       {
+               //
+               // We only allow this as an early-init boot
+               //
+               if (!KeLoaderBlock) return STATUS_INVALID_PARAMETER;
+               
+               //
+               // Save command-line flags
+               //
+               if (ExportBootDiskAsCd) Input->Options.ExportAsCd = TRUE;
+               if (IsWinPEBoot) Input->Options.NoDriveLetter = TRUE;
+       }
+    
+       //
+       // Validate the disk type
+       //
+       if ((Input->Options.ExportAsCd) && (DiskType != RAMDISK_BOOT_DISK))
+       {
+               //
+               // If the type isn't CDFS, it has to at least be raw CD
+               //
+               if (DiskType != RAMDISK_MEMORY_MAPPED_DISK) return STATUS_INVALID_PARAMETER;
+       }
+       
+       //
+       // Check if this is an actual file
+       //
+       if (DiskType <= RAMDISK_MEMORY_MAPPED_DISK)
+       {
+               //
+               // Validate the file name
+               //
+               FileNameStart = (PWCHAR)((ULONG_PTR)Input + Length);
+               FileNameEnd = Input->FileName + 1;
+               while ((FileNameEnd < FileNameStart) && *(FileNameEnd)) FileNameEnd++;
+               if (FileNameEnd == FileNameStart) return STATUS_INVALID_PARAMETER;
+       }
+    
+       //
+       // Create the actual device
+       //
+       Status = RamdiskCreateDiskDevice(DeviceExtension,
+                                                                        Input, 
+                                                                        ValidateOnly,
+                                                                        &DriveExtension);
+       if (NT_SUCCESS(Status))
+       {
+               //
+               // Invalidate and set success
+               //
+               IoInvalidateDeviceRelations(DeviceExtension->PhysicalDeviceObject, 0);
+               Irp->IoStatus.Information = STATUS_SUCCESS;
+       }
+       
+       //
+       // We're done
+       //
+       return Status;
+}
+
+VOID
+NTAPI
+RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject,
+                    IN PVOID Context)
+{
+    PRAMDISK_BUS_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStackLocation;
+    PIRP Irp = Context;
+    
+    //
+    // Get the stack location
+    //
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    
+    //
+    // Free the work item
+    //
+    IoFreeWorkItem(Irp->Tail.Overlay.DriverContext[0]);
+    
+    //
+    // Grab the device extension and lock it
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+    Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // Discriminate by major code
+        //
+        switch (IoStackLocation->MajorFunction)
+        {
+            //
+            // Device control
+            //
+            case IRP_MJ_DEVICE_CONTROL:
+                               
+                //
+                // Let's take a look at the IOCTL
+                //
+                switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
+                {
+                    //
+                    // Ramdisk create request
+                    //
+                    case FSCTL_CREATE_RAM_DISK:
+                        
+                        //
+                        // This time we'll do it for real
+                        //
+                        Status = RamdiskCreateRamdisk(DeviceObject, Irp, FALSE);
+                        break;
+                        
+                    case IOCTL_DISK_SET_PARTITION_INFO:
+                        
+                        DPRINT1("Set partition info request\n");
+                        UNIMPLEMENTED;
+                        while (TRUE);
+                        break;
+                        
+                    case IOCTL_DISK_GET_DRIVE_LAYOUT:
+                        
+                        DPRINT1("Get drive layout request\n");
+                        UNIMPLEMENTED;
+                        while (TRUE);
+                        break;
+                        
+                    case IOCTL_DISK_GET_PARTITION_INFO:
+                        
+                        DPRINT1("Get partitinon info request\n");
+                        UNIMPLEMENTED;
+                        while (TRUE);
+                        break;
+                        
+                    default:
+                        
+                        DPRINT1("Invalid request\n");
+                        UNIMPLEMENTED;
+                        while (TRUE);
+                        break;
+                }
+                
+                //
+                // We're  here
+                //
+                break;
+                
+            //
+            // Read or write request
+            //
+            case IRP_MJ_READ:
+            case IRP_MJ_WRITE:
+                
+                DPRINT1("Read/Write request\n");
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            //
+            // Internal request (SCSI?)
+            //
+            case IRP_MJ_INTERNAL_DEVICE_CONTROL:
+
+                DPRINT1("SCSI request\n");
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            //
+            // Flush request
+            //
+            case IRP_MJ_FLUSH_BUFFERS:
+                
+                DPRINT1("Flush request\n");
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+
+            //
+            // Anything else
+            //
+            default:
+                
+                DPRINT1("Invalid request: %lx\n", IoStackLocation->MajorFunction);
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+        }
+        
+        //
+        // Complete the I/O
+        //
+        IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
+        Irp->IoStatus.Status = Status;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+        return;
+    }
+    
+    //
+    // Fail the I/O
+    //
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+NTSTATUS
+NTAPI
+SendIrpToThread(IN PDEVICE_OBJECT DeviceObject,
+                IN PIRP Irp)
+{
+    PIO_WORKITEM WorkItem;
+    
+    //
+    // Mark the IRP pending
+    //
+    IoMarkIrpPending(Irp);
+    
+    //
+    // Allocate a work item
+    //
+    WorkItem = IoAllocateWorkItem(DeviceObject);
+    if (WorkItem)
+    {
+        //
+        // Queue it up
+        //
+        Irp->Tail.Overlay.DriverContext[0] = WorkItem;
+        IoQueueWorkItem(WorkItem, RamdiskWorkerThread, DelayedWorkQueue, Irp);
+        return STATUS_PENDING;
+    }
+    else
+    {
+        //
+        // Fail
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+}
+
+NTSTATUS
+NTAPI
+RamdiskReadWriteReal(IN PIRP Irp,
+                     IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
+{
+    PMDL Mdl;
+    PVOID CurrentBase, SystemVa, BaseAddress;
+    PIO_STACK_LOCATION IoStackLocation;
+    LARGE_INTEGER CurrentOffset;
+    ULONG BytesRead, BytesLeft, CopyLength;
+    PVOID Source, Destination;
+    NTSTATUS Status;
+    
+    //
+    // Get the MDL and check if it's mapped
+    //
+    Mdl = Irp->MdlAddress;
+    if (Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL))
+    {
+        //
+        // Use the mapped address
+        //
+        SystemVa = Mdl->MappedSystemVa;
+    }
+    else
+    {
+        //
+        // Map it ourselves
+        //
+        SystemVa = MmMapLockedPagesSpecifyCache(Mdl,
+                                                0,
+                                                MmCached,
+                                                NULL,
+                                                0, 
+                                                NormalPagePriority);
+    }
+    
+    //
+    // Make sure we were able to map it
+    //
+    CurrentBase = SystemVa;
+    if (!SystemVa) return STATUS_INSUFFICIENT_RESOURCES;
+    
+    //
+    // Initialize default
+    //
+    Irp->IoStatus.Information = 0;
+    
+    //
+    // Get the I/O Stack Location and capture the data
+    //
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    CurrentOffset = IoStackLocation->Parameters.Read.ByteOffset;
+    BytesLeft = IoStackLocation->Parameters.Read.Length;
+    if (!BytesLeft) return STATUS_INVALID_PARAMETER;
+    
+    //
+    // Do the copy loop
+    //
+    while (TRUE)
+    {
+        //
+        // Map the pages
+        //
+        BaseAddress = RamdiskMapPages(DeviceExtension,
+                                      CurrentOffset,
+                                      BytesLeft,
+                                      &BytesRead);
+        if (!BaseAddress) return STATUS_INSUFFICIENT_RESOURCES;
+        
+        //
+        // Update our lengths
+        //
+        Irp->IoStatus.Information += BytesRead;
+        CopyLength = BytesRead;
+        
+        //
+        // Check if this was a read or write
+        //
+        Status = STATUS_SUCCESS;
+        if (IoStackLocation->MajorFunction == IRP_MJ_READ)
+        {
+            //
+            // Set our copy parameters
+            //
+            Destination = CurrentBase;
+            Source = BaseAddress;
+            goto DoCopy;
+        }
+        else if (IoStackLocation->MajorFunction == IRP_MJ_WRITE)
+        {
+            //
+            // Set our copy parameters
+            //
+            Destination = BaseAddress;
+            Source = CurrentBase;
+DoCopy:
+            //
+            // Copy the data
+            //
+            RtlCopyMemory(Destination, Source, CopyLength);
+        }
+        else
+        {
+            //
+            // Prepare us for failure
+            //
+            BytesLeft = CopyLength;
+            Status = STATUS_INVALID_PARAMETER;
+        }
+        
+        //
+        // Unmap the pages
+        //
+        RamdiskUnmapPages(DeviceExtension,
+                          BaseAddress,
+                          CurrentOffset,
+                          BytesRead);
+        
+        //
+        // Update offset and bytes left
+        //
+        BytesLeft -= BytesRead;
+        CurrentOffset.QuadPart += BytesRead;
+        CurrentBase = (PVOID)((ULONG_PTR)CurrentBase + BytesRead);
+        
+        //
+        // Check if we're done
+        //
+        if (!BytesLeft) return Status;
+    }
+}
+
+NTSTATUS
+NTAPI
+RamdiskGetPartitionInfo(IN PIRP Irp,
+                        IN PRAMDISK_DRIVE_EXTENSION DeviceExtension)
+{
+    NTSTATUS Status;
+    PPARTITION_INFORMATION PartitionInfo;
+    PVOID BaseAddress;
+    LARGE_INTEGER Zero = {{0, 0}};
+    ULONG Length;
+    PIO_STACK_LOCATION IoStackLocation;
+    
+    //
+    // Validate the length
+    //
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    if (IoStackLocation->Parameters.DeviceIoControl.
+        OutputBufferLength < sizeof(PARTITION_INFORMATION))
+    {
+        //
+        // Invalid length
+        //
+        Status = STATUS_BUFFER_TOO_SMALL;
+        Irp->IoStatus.Status = Status;
+        Irp->IoStatus.Information = 0;
+        return Status;
+    }
+    
+    //
+    // Map the partition table
+    //
+    BaseAddress = RamdiskMapPages(DeviceExtension, Zero, PAGE_SIZE, &Length);
+    if (!BaseAddress)
+    {
+        //
+        // No memory
+        //
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        Irp->IoStatus.Status = Status;
+        Irp->IoStatus.Information = 0;
+        return Status;
+    }
+    
+    //
+    // Fill out the information
+    //
+    PartitionInfo = Irp->AssociatedIrp.SystemBuffer;
+    PartitionInfo->StartingOffset.QuadPart = DeviceExtension->BytesPerSector;
+    PartitionInfo->PartitionLength.QuadPart = DeviceExtension->BytesPerSector *
+                                              DeviceExtension->SectorsPerTrack *
+                                              DeviceExtension->NumberOfHeads *
+                                              DeviceExtension->Cylinders;
+    PartitionInfo->HiddenSectors = DeviceExtension->HiddenSectors;
+    PartitionInfo->PartitionNumber = 0;
+    PartitionInfo->PartitionType = PARTITION_FAT32; //*((PCHAR)BaseAddress + 450);
+    PartitionInfo->BootIndicator = (DeviceExtension->DiskType ==
+                                    RAMDISK_BOOT_DISK) ? TRUE: FALSE;
+    PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartitionInfo->
+                                                               PartitionType);
+    PartitionInfo->RewritePartition = FALSE;
+
+    //
+    // Unmap the partition table
+    //
+    RamdiskUnmapPages(DeviceExtension, BaseAddress, Zero, Length);
+    
+    //
+    // Done
+    //
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject,
+                 IN PIRP Irp)
+{
+    //
+    // Complete the IRP
+    //
+    Irp->IoStatus.Information = 1;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject,
+                 IN PIRP Irp)
+{
+    PRAMDISK_DRIVE_EXTENSION DeviceExtension;
+    ULONG Length;
+    LARGE_INTEGER ByteOffset;
+    PIO_STACK_LOCATION IoStackLocation;
+    NTSTATUS Status, ReturnStatus;
+    
+    //
+    // Get the device extension and make sure this isn't a bus
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+    if (DeviceExtension->Type == RamdiskBus)
+    {
+        //
+        // Fail
+        //
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+        goto Complete;
+    }
+    
+    //
+    // Capture parameters
+    //
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    Length = IoStackLocation->Parameters.Read.Length;
+    ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;
+    
+    //
+    // FIXME: Validate offset
+    //
+    
+    //
+    // FIXME: Validate sector
+    //
+    
+    //
+    // Validate write
+    //
+    if ((IoStackLocation->MajorFunction == IRP_MJ_WRITE) &&
+        (DeviceExtension->DiskOptions.Readonly))
+    {
+        //
+        // Fail, this is read-only
+        //
+        Status = STATUS_MEDIA_WRITE_PROTECTED;
+        goto Complete;
+    }
+    
+    //
+    // See if we want to do this sync or async
+    //
+    if (DeviceExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
+    {
+        //
+        // Do it sync
+        //
+        Status = RamdiskReadWriteReal(Irp, DeviceExtension);
+        goto Complete;
+    }
+    
+    //
+    // Queue it to the worker
+    //
+    Status = SendIrpToThread(DeviceObject, Irp);
+    ReturnStatus = STATUS_PENDING;
+    
+    //
+    // Check if we're pending or not
+    //
+    if (Status != STATUS_PENDING)
+    {
+Complete:
+        //
+        // Complete the IRP
+        //
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_DISK_INCREMENT);
+        ReturnStatus = Status;
+    }
+    
+    //
+    // Return to caller
+    //
+    return ReturnStatus;
+}
+
+NTSTATUS
+NTAPI
+RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject,
+                     IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    PRAMDISK_BUS_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
+    PRAMDISK_DRIVE_EXTENSION DriveExtension = (PVOID)DeviceExtension;
+    ULONG Information;
+    PCDROM_TOC Toc;
+    PDISK_GEOMETRY DiskGeometry;
+    
+    //
+    // Grab the remove lock
+    //
+    Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // Fail the IRP
+        //
+        Irp->IoStatus.Information = 0;
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+    
+    //
+    // Setup some defaults
+    //
+    Status = STATUS_INVALID_DEVICE_REQUEST;
+    Information = 0;
+    
+    //
+    // Check if this is an bus device or the drive
+    //
+    if (DeviceExtension->Type == RamdiskBus)
+    {
+        //
+        // Check what the request is
+        //
+        switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
+        {
+            //
+            // Request to create a ramdisk
+            //
+            case FSCTL_CREATE_RAM_DISK:
+                
+                //
+                // Do it
+                //
+                Status = RamdiskCreateRamdisk(DeviceObject, Irp, TRUE);
+                if (!NT_SUCCESS(Status)) goto CompleteRequest;
+                break;
+                
+            default:
+                
+                //
+                // We don't handle anything else yet
+                //
+                ASSERT(FALSE);
+                while (TRUE);
+        }
+    }
+    else
+    {
+        //
+        // Check what the request is
+        //
+        switch (IoStackLocation->Parameters.DeviceIoControl.IoControlCode)
+        {
+            case IOCTL_DISK_CHECK_VERIFY:
+            case IOCTL_STORAGE_CHECK_VERIFY:
+            case IOCTL_STORAGE_CHECK_VERIFY2:
+            case IOCTL_CDROM_CHECK_VERIFY:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+
+            case IOCTL_STORAGE_GET_MEDIA_TYPES:
+            case IOCTL_DISK_GET_MEDIA_TYPES:
+            case IOCTL_DISK_GET_DRIVE_GEOMETRY:
+            case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
+                
+                //
+                // Validate the length
+                //
+                if (IoStackLocation->Parameters.DeviceIoControl.
+                    OutputBufferLength < sizeof(DISK_GEOMETRY))
+                {
+                    //
+                    // Invalid length
+                    //
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                    break;
+                }
+                
+                //
+                // Fill it out
+                //
+                DiskGeometry = Irp->AssociatedIrp.SystemBuffer;
+                DiskGeometry->Cylinders.QuadPart = DriveExtension->Cylinders;
+                DiskGeometry->BytesPerSector = DriveExtension->BytesPerSector;
+                DiskGeometry->SectorsPerTrack = DriveExtension->SectorsPerTrack;
+                DiskGeometry->TracksPerCylinder = DriveExtension->NumberOfHeads;
+                DiskGeometry->MediaType = DriveExtension->DiskOptions.Fixed ?
+                                          FixedMedia : RemovableMedia;
+                
+                //
+                // We're done
+                //
+                Status = STATUS_SUCCESS;
+                Information = sizeof(DISK_GEOMETRY);
+                break;
+            
+            //
+            // Hack to support ReactOS's broken CDFS
+            //
+            case IOCTL_CDROM_GET_LAST_SESSION:
+            
+                //
+                // Validate the length
+                //
+                if (IoStackLocation->Parameters.DeviceIoControl.
+                    OutputBufferLength < RAMDISK_SESSION_SIZE)
+                {
+                    //
+                    // Invalid length
+                    //
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                    break;
+                }
+                
+                //
+                // Fill out the TOC
+                //
+                Toc = Irp->AssociatedIrp.SystemBuffer;
+                Toc->Length[0] = 0;
+                Toc->Length[1] = RAMDISK_SESSION_SIZE - sizeof(Toc->Length);
+                Toc->FirstTrack = 1;
+                Toc->LastTrack = 1;
+                Toc->TrackData[0].Adr = 1;
+                Toc->TrackData[0].Control = TOC_DATA_TRACK;
+                Toc->TrackData[0].TrackNumber = 1;
+                Toc->TrackData[0].Address[0] =
+                Toc->TrackData[0].Address[1] =
+                Toc->TrackData[0].Address[2] =
+                Toc->TrackData[0].Address[3] = 0;
+                                
+                //
+                // We're done
+                //
+                Status = STATUS_SUCCESS;
+                Information = RAMDISK_SESSION_SIZE;
+                break;
+                                
+            case IOCTL_CDROM_READ_TOC:
+                
+                //
+                // Validate the length
+                //
+                if (IoStackLocation->Parameters.DeviceIoControl.
+                    OutputBufferLength < sizeof(CDROM_TOC))
+                {
+                    //
+                    // Invalid length
+                    //
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                    break;
+                }
+                
+                //
+                // Clear the TOC
+                //
+                Toc = Irp->AssociatedIrp.SystemBuffer;
+                RtlZeroMemory(Toc, sizeof(CDROM_TOC));
+                
+                //
+                // Fill it out
+                //
+                Toc->Length[0] = 0;
+                Toc->Length[1] = RAMDISK_TOC_SIZE - sizeof(Toc->Length);
+                Toc->FirstTrack = 1;
+                Toc->LastTrack = 1;
+                Toc->TrackData[0].Adr = 1;
+                Toc->TrackData[0].Control = TOC_DATA_TRACK;
+                Toc->TrackData[0].TrackNumber = 1;
+                
+                //
+                // We're done
+                //
+                Status = STATUS_SUCCESS;
+                Information = RAMDISK_TOC_SIZE;
+                break;
+                
+            case IOCTL_DISK_SET_PARTITION_INFO:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_DISK_GET_PARTITION_INFO:
+                
+                //
+                // Validate the length
+                //
+                if (IoStackLocation->Parameters.DeviceIoControl.
+                    OutputBufferLength < sizeof(PARTITION_INFORMATION))
+                {
+                    //
+                    // Invalid length
+                    //
+                    Status = STATUS_BUFFER_TOO_SMALL;
+                    break;
+                }
+                
+                //
+                // Check if we need to do this sync or async
+                //
+                if (DriveExtension->DiskType > RAMDISK_MEMORY_MAPPED_DISK)
+                {
+                    //
+                    // Call the helper function
+                    //
+                    Status = RamdiskGetPartitionInfo(Irp, DriveExtension);
+                }
+                else
+                {
+                    //
+                    // Do it asynchronously later
+                    //
+                    goto CallWorker;
+                }
+                
+                //
+                // We're done
+                //
+                Information = Irp->IoStatus.Information;
+                break;
+                
+            case IOCTL_DISK_GET_DRIVE_LAYOUT:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_DISK_GET_LENGTH_INFO:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_DISK_IS_WRITABLE:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_SCSI_MINIPORT:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_STORAGE_QUERY_PROPERTY:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_VOLUME_SET_GPT_ATTRIBUTES:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            case IOCTL_VOLUME_OFFLINE:
+                
+                UNIMPLEMENTED;
+                while (TRUE);
+                break;
+                
+            default:
+         
+                //
+                // Drive code not emulated
+                //
+                DPRINT1("IOCTL: %lx\n", IoStackLocation->Parameters.DeviceIoControl.IoControlCode);                
+                break;
+        }
+
+        //
+        // If requests drop down here, we just return them complete them
+        //
+        goto CompleteRequest;
+    }
+    
+    //
+    // Queue the request to our worker thread
+    //
+CallWorker:
+    Status = SendIrpToThread(DeviceObject, Irp);
+    
+CompleteRequest:
+    //
+    // Release the lock
+    //
+    IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
+    if (Status != STATUS_PENDING)
+    {
+        //
+        // Complete the request
+        //
+        Irp->IoStatus.Status = Status;
+        Irp->IoStatus.Information = Information;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+    
+    //
+    // Return status
+    //
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type,
+                            IN PDEVICE_OBJECT DeviceObject,
+                            IN PIRP Irp)
+{
+    PRAMDISK_BUS_EXTENSION DeviceExtension;
+    PRAMDISK_DRIVE_EXTENSION DriveExtension;
+    PDEVICE_RELATIONS DeviceRelations, OurDeviceRelations;
+    ULONG Count, DiskCount, FinalCount;
+    PLIST_ENTRY ListHead, NextEntry;
+    PDEVICE_OBJECT* DriveDeviceObject;
+    RAMDISK_DEVICE_STATE State;
+    
+    //
+    // Get the device extension and check if this is a drive
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+    if (DeviceExtension->Type == RamdiskDrive)
+    {
+        //
+        // FIXME: TODO
+        //
+        UNIMPLEMENTED;
+        while (TRUE);
+    }
+    
+    //
+    // Anything but bus relations, we don't handle
+    //
+    if (Type) goto PassToNext;
+    
+    //
+    // Acquire the disk list lock
+    //
+    KeEnterCriticalRegion();
+    ExAcquireFastMutex(&DeviceExtension->DiskListLock);
+    
+    //
+    // Did a device already fill relations?
+    //
+    DeviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
+    if (DeviceRelations)
+    {
+        //
+        // Use the data
+        //
+        Count = DeviceRelations->Count;
+    }
+    else
+    {
+        //
+        // We're the first
+        //
+        Count = 0;
+    }
+    
+    //
+    // Now loop our drives
+    //
+    DiskCount = 0;
+    ListHead = &DeviceExtension->DiskList;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        //
+        // As long as it wasn't removed, count it in
+        //
+        DriveExtension = CONTAINING_RECORD(NextEntry,
+                                           RAMDISK_DRIVE_EXTENSION,
+                                           DiskList);
+        if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++;
+        
+        //
+        // Move to the next one
+        //
+        NextEntry = NextEntry->Flink;
+    }
+    
+    //
+    // Now we know our final count
+    //
+    FinalCount = Count + DiskCount;
+    
+    //
+    // Allocate the structure
+    //
+    OurDeviceRelations = ExAllocatePoolWithTag(PagedPool,
+                                               FIELD_OFFSET(DEVICE_RELATIONS,
+                                                            Objects) +
+                                               FinalCount *
+                                               sizeof(PDEVICE_OBJECT),
+                                               'dmaR');
+    if (!OurDeviceRelations)
+    {
+        //
+        // Fail
+        //
+        ExReleaseFastMutex(&DeviceExtension->DiskListLock);
+        KeLeaveCriticalRegion();
+        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    
+    //
+    // Check if we already had some relations
+    //
+    if (Count)
+    {
+        //
+        // Copy them in
+        //
+        RtlCopyMemory(OurDeviceRelations->Objects,
+                      DeviceRelations->Objects,
+                      Count * sizeof(PDEVICE_OBJECT));
+    }
+    
+    //
+    // Save the count
+    //
+    OurDeviceRelations->Count = FinalCount;
+    
+    //
+    // Now loop our drives again
+    //
+    ListHead = &DeviceExtension->DiskList;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        //
+        // Go to the end of the list
+        //
+        DriveDeviceObject = &OurDeviceRelations->Objects[Count];
+        
+        //
+        // Get the drive state
+        //
+        DriveExtension = CONTAINING_RECORD(NextEntry,
+                                           RAMDISK_DRIVE_EXTENSION,
+                                           DiskList);
+        State = DriveExtension->State;
+        
+        //
+        // If it was removed or enumerated, we don't touch the device object
+        //
+        if (State >= RamdiskStateBusRemoved)
+        {
+            //
+            // If it was removed, we still have to keep track of this though
+            //
+            if (State == RamdiskStateBusRemoved)
+            {
+                //
+                // Mark it as enumerated now, but don't actually reference it
+                //
+                DriveExtension->State = RamdiskStateEnumerated;
+            }
+        }
+        else
+        {
+            //
+            // First time it's enumerated, reference the device object
+            //
+            ObReferenceObject(DriveExtension->DeviceObject);
             
-        case IRP_MN_QUERY_DEVICE_TEXT:
+            //
+            // Save the object pointer, and move on
+            //
+            *DriveDeviceObject++ = DriveExtension->DeviceObject;
+        }
+        
+        if (DriveExtension->State < RamdiskStateBusRemoved) DiskCount++;
+        
+        //
+        // Move to the next one
+        //
+        NextEntry = NextEntry->Flink;
+    }
+
+    //
+    // Release the lock
+    //
+    ExReleaseFastMutex(&DeviceExtension->DiskListLock);
+    KeLeaveCriticalRegion();
+    
+    //
+    // Cleanup old relations
+    //
+    if (DeviceRelations) ExFreePool(DeviceRelations);
+    
+    //
+    // Complete our IRP
+    //
+    Irp->IoStatus.Information = (ULONG_PTR)OurDeviceRelations;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    
+    //
+    // Pass to the next driver
+    //
+PassToNext:
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+    return IoCallDriver(DeviceExtension->AttachedDevice, Irp);  
+}
+
+NTSTATUS
+NTAPI
+RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
+           IN PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStackLocation;
+    PRAMDISK_BUS_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+    UCHAR Minor;
+    
+    //
+    // Get the device extension and stack location
+    //
+    DeviceExtension = DeviceObject->DeviceExtension;
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    Minor = IoStackLocation->MinorFunction;
+    
+    //
+    // Check if the bus is removed
+    //
+    if (DeviceExtension->State == RamdiskStateBusRemoved)
+    {
+        //
+        // Only remove-device and query-id are allowed
+        //
+        if ((Minor != IRP_MN_REMOVE_DEVICE) || (Minor != IRP_MN_QUERY_ID))
+        {
+            //
+            // Fail anything else
+            //
+            Status = STATUS_NO_SUCH_DEVICE;
+            Irp->IoStatus.Status = Status;
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            return Status;
+        }
+    }
+    
+    //
+    // Acquire the remove lock
+    //
+    Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // Fail the IRP
+        //
+        Irp->IoStatus.Information = 0;
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return Status;
+    }
+    
+    //
+    // Query the IRP type
+    //
+    switch (Minor)
+    {
+        case IRP_MN_START_DEVICE:
             
             DPRINT1("PnP IRP: %lx\n", Minor);
             while (TRUE);
             break;
             
-        case IRP_MN_QUERY_DEVICE_RELATIONS:
+        case IRP_MN_QUERY_STOP_DEVICE:
+            
+            DPRINT1("PnP IRP: %lx\n", Minor);
+            while (TRUE);
+            break;
+            
+        case IRP_MN_CANCEL_STOP_DEVICE:
+            
+            DPRINT1("PnP IRP: %lx\n", Minor);
+            while (TRUE);
+            break;
+            
+        case IRP_MN_STOP_DEVICE:
+            
+            DPRINT1("PnP IRP: %lx\n", Minor);
+            while (TRUE);
+            break;
+            
+        case IRP_MN_QUERY_REMOVE_DEVICE:
+            
+            DPRINT1("PnP IRP: %lx\n", Minor);
+            while (TRUE);
+            break;
+            
+        case IRP_MN_CANCEL_REMOVE_DEVICE:
+            
+            DPRINT1("PnP IRP: %lx\n", Minor);
+            while (TRUE);
+            break;
+            
+        case IRP_MN_REMOVE_DEVICE:
+            
+            DPRINT1("PnP IRP: %lx\n", Minor);
+            while (TRUE);
+            break;
 
+        case IRP_MN_SURPRISE_REMOVAL:
+            
             DPRINT1("PnP IRP: %lx\n", Minor);
-            while (TRUE);            
+            while (TRUE);
             break;
             
-        case IRP_MN_QUERY_CAPABILITIES:
+        case IRP_MN_QUERY_ID:
+            
+            //
+            // Are we a drive?
+            //
+            if (DeviceExtension->Type == RamdiskDrive)
+            {
+                DPRINT1("PnP IRP: %lx\n", Minor);
+                while (TRUE);
+            }
+            break;
+            
+        case IRP_MN_QUERY_BUS_INFORMATION:
+            
+            //
+            // Are we a drive?
+            //
+            if (DeviceExtension->Type == RamdiskDrive)
+            {
+                DPRINT1("PnP IRP: %lx\n", Minor);
+                while (TRUE);
+            }
+            break;
+            
+        case IRP_MN_EJECT:
             
             DPRINT1("PnP IRP: %lx\n", Minor);
             while (TRUE);
             break;
             
+        case IRP_MN_QUERY_DEVICE_TEXT:
+            
+            //
+            // Are we a drive?
+            //
+            if (DeviceExtension->Type == RamdiskDrive)
+            {
+                DPRINT1("PnP IRP: %lx\n", Minor);
+                while (TRUE);
+            }
+            break;
+            
+        case IRP_MN_QUERY_DEVICE_RELATIONS:
+
+            //
+            // Call our main routine
+            //
+            Status = RamdiskQueryDeviceRelations(IoStackLocation->
+                                                 Parameters.
+                                                 QueryDeviceRelations.Type,
+                                                 DeviceObject,
+                                                 Irp);
+            goto ReleaseAndReturn;
+            
+        case IRP_MN_QUERY_CAPABILITIES:
+            
+            //
+            // Are we a drive?
+            //
+            if (DeviceExtension->Type == RamdiskDrive)
+            {
+                DPRINT1("PnP IRP: %lx\n", Minor);
+                while (TRUE);
+            }
+            break;
+            
+        case IRP_MN_QUERY_RESOURCES:
+        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
+            
+            //
+            // Complete immediately without touching it
+            //
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            goto ReleaseAndReturn;
+            
         default:
             
             DPRINT1("Illegal IRP: %lx\n", Minor);
@@ -419,9 +2114,9 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
     }
     
     //
-    // Are we an FDO?
+    // Are we the bus?
     //
-    if (DeviceExtension->Type == RamdiskFdo)
+    if (DeviceExtension->Type == RamdiskBus)
     {
         //
         // Do we have an attached device?
@@ -439,6 +2134,7 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
     //
     // Release the lock and return status
     //
+ReleaseAndReturn:
     IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
     return Status;
 }
@@ -496,23 +2192,23 @@ NTAPI
 RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject, 
                  IN PDEVICE_OBJECT PhysicalDeviceObject)
 {
-       PRAMDISK_EXTENSION DeviceExtension;
+       PRAMDISK_BUS_EXTENSION DeviceExtension;
        PDEVICE_OBJECT AttachedDevice;
        NTSTATUS Status; 
        UNICODE_STRING DeviceName;
        PDEVICE_OBJECT DeviceObject;
        
        //
-       // Only create the FDO once
+       // Only create the bus FDO once
        //
        if (RamdiskBusFdo) return STATUS_DEVICE_ALREADY_ATTACHED;
        
        //
-       // Create the FDO
+       // Create the bus FDO
        //
        RtlInitUnicodeString(&DeviceName, L"\\Device\\Ramdisk");
        Status = IoCreateDevice(DriverObject,
-                                                   sizeof(RAMDISK_EXTENSION),
+                                                   sizeof(RAMDISK_BUS_EXTENSION),
                                                        &DeviceName,
                                                        FILE_DEVICE_BUS_EXTENDER,
                                                        FILE_DEVICE_SECURE_OPEN,
@@ -521,26 +2217,27 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
        if (NT_SUCCESS(Status))
        {
                //
-               // Initialize the FDO extension
+               // Initialize the bus FDO extension
                //
-           DeviceExtension = (PRAMDISK_EXTENSION)DeviceObject->DeviceExtension;
-           RtlZeroMemory(DeviceObject->DeviceExtension, sizeof(RAMDISK_EXTENSION));
+           DeviceExtension = DeviceObject->DeviceExtension;
+           RtlZeroMemory(DeviceObject->DeviceExtension,
+                      sizeof(RAMDISK_BUS_EXTENSION));
 
                //
-               // Set FDO flags
+               // Set bus FDO flags
                //
            DeviceObject->Flags |= DO_POWER_PAGABLE | DO_DIRECT_IO;
 
                //
-               // Setup the FDO extension
+               // Setup the bus FDO extension
                //
-           DeviceExtension->Type = RamdiskFdo;
+           DeviceExtension->Type = RamdiskBus;
                ExInitializeFastMutex(&DeviceExtension->DiskListLock);
            IoInitializeRemoveLock(&DeviceExtension->RemoveLock,
-                               TAG('R', 'a', 'm', 'd'),
+                               'dmaR',
                                0,
                                1);
-               InitializeListHead(&DeviceExtension->DiskListHead);
+               InitializeListHead(&DeviceExtension->DiskList);
            DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
            DeviceExtension->DeviceObject = DeviceObject;
 
@@ -550,7 +2247,7 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
            Status = IoRegisterDeviceInterface(PhysicalDeviceObject,
                                                                                   &RamdiskBusInterface,
                                                                                   NULL,
-                                                                                  &DeviceExtension->SymbolicLinkName);
+                                                                                  &DeviceExtension->BusDeviceName);
            if (!NT_SUCCESS(Status))
            {
                        //
@@ -571,14 +2268,14 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
                        //
                        // Fail
                        //
-                       IoSetDeviceInterfaceState(&DeviceExtension->SymbolicLinkName, 0);
-                       RtlFreeUnicodeString(&DeviceExtension->SymbolicLinkName);
+                       IoSetDeviceInterfaceState(&DeviceExtension->BusDeviceName, 0);
+                       RtlFreeUnicodeString(&DeviceExtension->BusDeviceName);
                        IoDeleteDevice(DeviceObject);
                        return STATUS_NO_SUCH_DEVICE;
            }
 
                //
-               // FDO is initialized
+               // Bus FDO is initialized
                //
            RamdiskBusFdo = DeviceObject;
 
@@ -590,7 +2287,7 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
                        //
                        // Are we being booted from setup? Not yet supported
                        //
-                       ASSERT (!KeLoaderBlock->SetupLdrBlock);
+                       //ASSERT(!KeLoaderBlock->SetupLdrBlock);
            }
 
                //
@@ -614,6 +2311,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     PCHAR BootDeviceName, CommandLine;
     PDEVICE_OBJECT PhysicalDeviceObject = NULL;
     NTSTATUS Status;
+    DPRINT("RAM Disk Driver Initialized\n");
     
     //
     // Query ramdisk parameters
@@ -627,7 +2325,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     DriverRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
                                                       RegistryPath->Length +
                                                       sizeof(WCHAR),
-                                                      TAG('R', 'a', 'm', 'd'));
+                                                      'dmaR');
     if (!DriverRegistryPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
     RtlCopyUnicodeString(&DriverRegistryPath, RegistryPath);
     
@@ -705,7 +2403,7 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
     //
     // Installing from Ramdisk isn't supported yet
     //
-    ASSERT(!KeLoaderBlock->SetupLdrBlock);
+    //ASSERT(!KeLoaderBlock->SetupLdrBlock);
     
     //
     // Are we reporting the device
@@ -731,7 +2429,9 @@ DriverEntry(IN PDRIVER_OBJECT DriverObject,
             // the required keys when reporting a detected device.
             // We hack around this ourselves.
             //
-            RtlCreateUnicodeString(&((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode->InstancePath,
+            RtlCreateUnicodeString(&((PEXTENDED_DEVOBJ_EXTENSION)
+                                   PhysicalDeviceObject->DeviceObjectExtension)
+                                   ->DeviceNode->InstancePath,
                                    L"Root\\UNKNOWN\\0000");
             
             //