[RAMDISK]
[reactos.git] / reactos / drivers / storage / class / ramdisk / ramdisk.c
index 1966f63..143a6f6 100644 (file)
@@ -63,6 +63,12 @@ DEFINE_GUID(RamdiskBusInterface,
     0x410F,
     0x80, 0xE4, 0x05, 0xF8, 0x10, 0xE7, 0xA8, 0x8A);
 
+DEFINE_GUID(RamdiskDiskInterface,
+    0x31D909F0,
+    0x2CDF,
+    0x4A20,
+    0x9E, 0xD4, 0x7D, 0x65, 0x47, 0x6C, 0xA7, 0x68);
+
 typedef struct _RAMDISK_EXTENSION
 {
     RAMDISK_DEVICE_TYPE Type;
@@ -623,8 +629,8 @@ RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension,
         ExInitializeFastMutex(&DriveExtension->DiskListLock);
         IoInitializeRemoveLock(&DriveExtension->RemoveLock,
                               'dmaR',
-                              0,
-                              1);
+                              1,
+                              0);
         DriveExtension->DriveDeviceName = DeviceName;
         DriveExtension->SymbolicLinkName = SymbolicLinkName;
         DriveExtension->GuidString = GuidString;
@@ -1734,7 +1740,7 @@ RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type,
     //
     // Anything but bus relations, we don't handle
     //
-    if (Type) goto PassToNext;
+    if (Type != BusRelations) goto PassToNext;
     
     //
     // Acquire the disk list lock
@@ -2022,6 +2028,270 @@ RamdiskRemoveBusDevice(IN PDEVICE_OBJECT DeviceObject,
     return Status;
 }
 
+NTSTATUS
+NTAPI
+RamdiskQueryId(IN PRAMDISK_DRIVE_EXTENSION DriveExtension,
+               IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStackLocation;
+    PWSTR OutputString = NULL;
+    ULONG StringLength;
+
+    Status = STATUS_SUCCESS;
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // Get what is being queried
+    //
+    switch (IoStackLocation->Parameters.QueryId.IdType)
+    {
+        case BusQueryDeviceID:
+
+            //
+            // Allocate a buffer long enough to receive Ramdisk\RamDisk in any case
+            // In case we don't have RAMDISK_REGISTRY_DISK, we then need two more
+            // chars to store Ramdisk\RamVolume instead
+            //
+            StringLength = 4 * (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK) + sizeof(L"Ramdisk\\RamDisk");
+            OutputString = ExAllocatePoolWithTag(PagedPool, StringLength, 'dmaR');
+            if (OutputString == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            wcsncpy(OutputString, L"Ramdisk\\", StringLength / sizeof(WCHAR));
+            if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
+            {
+                wcsncat(OutputString, L"RamVolume", StringLength / sizeof(WCHAR));
+            }
+            else
+            {
+                wcsncat(OutputString, L"RamDisk", StringLength / sizeof(WCHAR));
+            }
+
+            break;
+
+        case BusQueryHardwareIDs:
+
+            //
+            // Allocate a buffer long enough to receive Ramdisk\RamDisk in any case
+            // In case we don't have RAMDISK_REGISTRY_DISK, we then need two more
+            // chars to store Ramdisk\RamVolume instead
+            // We also need an extra char, because it is required that the string
+            // is null-terminated twice
+            //
+            StringLength = 4 * (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK) +
+                           sizeof(UNICODE_NULL) + sizeof(L"Ramdisk\\RamDisk");
+            OutputString = ExAllocatePoolWithTag(PagedPool, StringLength, 'dmaR');
+            if (OutputString == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            wcsncpy(OutputString, L"Ramdisk\\", StringLength / sizeof(WCHAR));
+            if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
+            {
+                wcsncat(OutputString, L"RamVolume", StringLength / sizeof(WCHAR));
+            }
+            else
+            {
+                wcsncat(OutputString, L"RamDisk", StringLength / sizeof(WCHAR));
+            }
+            OutputString[(StringLength / sizeof(WCHAR)) - 1] = UNICODE_NULL;
+
+            break;
+
+        case BusQueryCompatibleIDs:
+
+            if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
+            {
+                Status = STATUS_INVALID_DEVICE_REQUEST;
+                break;
+            }
+
+            StringLength = sizeof(L"GenDisk");
+            OutputString = ExAllocatePoolWithTag(PagedPool, StringLength, 'dmaR');
+            if (OutputString == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            wcsncpy(OutputString, L"GenDisk", StringLength / sizeof(WCHAR));
+            OutputString[(StringLength / sizeof(WCHAR)) - 1] = UNICODE_NULL;
+
+            break;
+
+        case BusQueryInstanceID:
+
+            OutputString = ExAllocatePoolWithTag(PagedPool, DriveExtension->GuidString.MaximumLength, 'dmaR');
+            if (OutputString == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            wcsncpy(OutputString, DriveExtension->GuidString.Buffer, DriveExtension->GuidString.MaximumLength / sizeof(WCHAR));
+
+            break;
+
+        case BusQueryDeviceSerialNumber:
+            
+            //
+            // Nothing to do
+            //
+
+            break;
+    }
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = (ULONG_PTR)OutputString;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+RamdiskQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,
+                         IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStackLocation;
+    PDEVICE_CAPABILITIES DeviceCapabilities;
+    PRAMDISK_DRIVE_EXTENSION DriveExtension;
+
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    DeviceCapabilities = IoStackLocation->Parameters.DeviceCapabilities.Capabilities;
+    DriveExtension = DeviceObject->DeviceExtension;
+
+    //
+    // Validate our input buffer
+    //
+    if (DeviceCapabilities->Version != 1 || DeviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES))
+    {
+        Status = STATUS_UNSUCCESSFUL;
+    }
+    else
+    {
+        //
+        // And set everything we know about our capabilities
+        //
+        DeviceCapabilities->Removable = MarkRamdisksAsRemovable;
+        DeviceCapabilities->UniqueID = TRUE;
+        DeviceCapabilities->SilentInstall = TRUE;
+        DeviceCapabilities->RawDeviceOK = TRUE;
+        DeviceCapabilities->SurpriseRemovalOK = (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK);
+        DeviceCapabilities->NoDisplayInUI = TRUE;
+        Status = STATUS_SUCCESS;
+    }
+
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+RamdiskQueryDeviceText(IN PRAMDISK_DRIVE_EXTENSION DriveExtension,
+                       IN PIRP Irp)
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStackLocation;
+    DEVICE_TEXT_TYPE DeviceTextType;
+    PWSTR OutputString = NULL;
+
+    IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+    DeviceTextType = IoStackLocation->Parameters.QueryDeviceText.DeviceTextType;
+    Status = STATUS_SUCCESS;
+
+    //
+    // Just copy our constants, according to the input
+    //
+    switch (DeviceTextType)
+    {
+        case DeviceTextDescription:
+
+            OutputString = ExAllocatePoolWithTag(PagedPool, sizeof(L"RamDisk"), 'dmaR');
+            if (OutputString == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            wcsncpy(OutputString, L"RamDisk", sizeof(L"RamDisk") / sizeof(WCHAR));
+
+            break;
+
+        case DeviceTextLocationInformation:
+
+            OutputString = ExAllocatePoolWithTag(PagedPool, sizeof(L"RamDisk\\0"), 'dmaR');
+            if (OutputString == NULL)
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+                break;
+            }
+
+            wcsncpy(OutputString, L"RamDisk\\0", sizeof(L"RamDisk\\0") / sizeof(WCHAR));
+
+            break;
+    }
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = (ULONG_PTR)OutputString;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+RamdiskQueryBusInformation(IN PDEVICE_OBJECT DeviceObject,
+                           IN PIRP Irp)
+{
+    PPNP_BUS_INFORMATION PnpBusInfo;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    //
+    // Allocate output memory
+    //
+    PnpBusInfo = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), 'dmaR');
+    if (PnpBusInfo == NULL)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+    }
+    else
+    {
+        //
+        // Copy our bus GUID and set our legacy type
+        //
+        RtlCopyMemory(&PnpBusInfo->BusTypeGuid, &GUID_BUS_TYPE_RAMDISK, sizeof(GUID));
+        PnpBusInfo->LegacyBusType = PNPBus;
+        PnpBusInfo->BusNumber = 0;
+    }
+
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = (ULONG_PTR)PnpBusInfo;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+RamdiskIoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
+                           IN PIRP Irp,
+                           IN PVOID Context)
+
+{
+    //
+    // Just set the event to unlock caller
+    //
+    KeSetEvent((PKEVENT)Context, 0, FALSE);
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
 NTSTATUS
 NTAPI
 RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
@@ -2031,7 +2301,8 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
     PRAMDISK_BUS_EXTENSION DeviceExtension;
     NTSTATUS Status;
     UCHAR Minor;
-    
+    KEVENT Event;
+
     //
     // Get the device extension and stack location
     //
@@ -2080,8 +2351,112 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
     switch (Minor)
     {
         case IRP_MN_START_DEVICE:
-            
-            UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
+
+            if (DeviceExtension->Type == RamdiskDrive)
+            {
+                ULONG ResultLength;
+                DEVICE_INSTALL_STATE InstallState;
+                PRAMDISK_DRIVE_EXTENSION DriveExtension = (PRAMDISK_DRIVE_EXTENSION)DeviceExtension;
+
+                //
+                // If we already have a drive name, free it
+                //
+                if (DriveExtension->DriveDeviceName.Buffer)
+                {
+                    ExFreePool(DriveExtension->DriveDeviceName.Buffer);
+                }
+
+                //
+                // Register our device interface
+                //
+                if (DriveExtension->DiskType != RAMDISK_REGISTRY_DISK)
+                {
+                    Status = IoRegisterDeviceInterface(DeviceObject,
+                                                       &GUID_DEVINTERFACE_VOLUME,
+                                                       NULL,
+                                                       &DriveExtension->DriveDeviceName);
+                }
+                else
+                {
+                    Status = IoRegisterDeviceInterface(DeviceObject,
+                                                       &RamdiskDiskInterface,
+                                                       NULL,
+                                                       &DriveExtension->DriveDeviceName);
+                }
+
+                //
+                // If we were asked not to assign a drive letter or
+                // if getting a name failed, just return saying
+                // we're now started
+                //
+                if (DriveExtension->DiskOptions.NoDriveLetter ||
+                    DriveExtension->DriveDeviceName.Buffer == NULL)
+                {
+                    DriveExtension->State = RamdiskStateStarted;
+                    Irp->IoStatus.Status = Status;
+                    break;
+                }
+
+                //
+                // Now get our installation state
+                //
+                Status = IoGetDeviceProperty(DeviceObject, DevicePropertyInstallState,
+                                             sizeof(InstallState), &InstallState, &ResultLength);
+                //
+                // If querying the information failed, assume success
+                //
+                if (!NT_SUCCESS(Status))
+                {
+                    InstallState = InstallStateInstalled;
+                }
+
+                //
+                // If we were properly installed, then, enable the interface
+                //
+                if (InstallState == InstallStateInstalled)
+                {
+                    Status = IoSetDeviceInterfaceState(&DriveExtension->DriveDeviceName, TRUE);
+                }
+
+                //
+                // We're fine & up
+                //
+                DriveExtension->State = RamdiskStateStarted;
+                Irp->IoStatus.Status = Status;
+                break;
+            }
+
+            //
+            // Prepare next stack to pass it down
+            //
+            IoCopyCurrentIrpStackLocationToNext(Irp);
+
+            //
+            // Initialize our notification event & our completion routine
+            //
+            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+            IoSetCompletionRoutine(Irp, RamdiskIoCompletionRoutine, &Event, TRUE, TRUE, TRUE);
+
+            //
+            // Call lower driver
+            //
+            Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp);
+            if (Status == STATUS_PENDING)
+            {
+                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = Irp->IoStatus.Status;
+            }
+
+            //
+            // If it succeed to start, then, enable ourselve and we're up!
+            //
+            if (NT_SUCCESS(Status))
+            {
+                Status = IoSetDeviceInterfaceState(&DeviceExtension->DriveDeviceName, TRUE);
+                DeviceExtension->State = RamdiskStateStarted;
+            }
+
+            Irp->IoStatus.Status = Status;
             break;
             
         case IRP_MN_QUERY_STOP_DEVICE:
@@ -2150,7 +2525,7 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
             //
             if (DeviceExtension->Type == RamdiskDrive)
             {
-                UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
+                Status = RamdiskQueryId((PRAMDISK_DRIVE_EXTENSION)DeviceExtension, Irp);
             }
             break;
             
@@ -2161,7 +2536,7 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
             //
             if (DeviceExtension->Type == RamdiskDrive)
             {
-                UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
+                Status = RamdiskQueryBusInformation(DeviceObject, Irp);
             }
             break;
             
@@ -2177,7 +2552,7 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
             //
             if (DeviceExtension->Type == RamdiskDrive)
             {
-                UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
+                Status = RamdiskQueryDeviceText((PRAMDISK_DRIVE_EXTENSION)DeviceExtension, Irp);
             }
             break;
             
@@ -2200,7 +2575,7 @@ RamdiskPnp(IN PDEVICE_OBJECT DeviceObject,
             //
             if (DeviceExtension->Type == RamdiskDrive)
             {
-                UNIMPLEMENTED_DBGBREAK("PnP IRP: %lx\n", Minor);
+                Status = RamdiskQueryCapabilities(DeviceObject, Irp);
             }
             break;
             
@@ -2520,8 +2895,8 @@ RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject,
        ExInitializeFastMutex(&DeviceExtension->DiskListLock);
         IoInitializeRemoveLock(&DeviceExtension->RemoveLock,
                                'dmaR',
-                               0,
-                               1);
+                               1,
+                               0);
        InitializeListHead(&DeviceExtension->DiskList);
         DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
         DeviceExtension->DeviceObject = DeviceObject;