2 * PROJECT: Ramdisk Class Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/storage/class/ramdisk/ramdisk.c
5 * PURPOSE: Main Driver Routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
23 #include <reactos/drivers/ntddrdsk.h>
28 /* GLOBALS ********************************************************************/
30 typedef enum _RAMDISK_DEVICE_TYPE
34 } RAMDISK_DEVICE_TYPE
;
36 typedef enum _RAMDISK_DEVICE_STATE
38 RamdiskStateUninitialized
,
43 RamdiskStateBusRemoved
,
44 RamdiskStateEnumerated
,
45 } RAMDISK_DEVICE_STATE
;
47 DEFINE_GUID(RamdiskBusInterface
,
51 0x80, 0xE4, 0x05, 0xF8, 0x10, 0xE7, 0xA8, 0x8A);
54 // GCC does not seem to support anonymous structures
56 #define RAMDISK_EXTENSION \
57 RAMDISK_DEVICE_TYPE Type; \
58 RAMDISK_DEVICE_STATE State; \
59 PDEVICE_OBJECT DeviceObject; \
60 PDEVICE_OBJECT PhysicalDeviceObject; \
61 PDEVICE_OBJECT AttachedDevice; \
62 IO_REMOVE_LOCK RemoveLock; \
63 UNICODE_STRING DriveDeviceName; \
64 UNICODE_STRING BusDeviceName; \
65 FAST_MUTEX DiskListLock; \
68 typedef struct _RAMDISK_BUS_EXTENSION
71 } RAMDISK_BUS_EXTENSION
, *PRAMDISK_BUS_EXTENSION
;
73 typedef struct _RAMDISK_DRIVE_EXTENSION
77 UNICODE_STRING GuidString
;
78 UNICODE_STRING SymbolicLinkName
;
80 RAMDISK_CREATE_OPTIONS DiskOptions
;
84 } RAMDISK_DRIVE_EXTENSION
, *PRAMDISK_DRIVE_EXTENSION
;
86 ULONG MaximumViewLength
;
87 ULONG MaximumPerDiskViewLength
;
88 ULONG ReportDetectedDevice
;
89 ULONG MarkRamdisksAsRemovable
;
90 ULONG MinimumViewCount
;
91 ULONG DefaultViewCount
;
92 ULONG MaximumViewCount
;
93 ULONG MinimumViewLength
;
94 ULONG DefaultViewLength
;
95 UNICODE_STRING DriverRegistryPath
;
96 BOOLEAN ExportBootDiskAsCd
;
98 PDEVICE_OBJECT RamdiskBusFdo
;
100 /* FUNCTIONS ******************************************************************/
104 QueryParameters(IN PUNICODE_STRING RegistryPath
)
106 ULONG MinView
, DefView
, MinViewLength
, DefViewLength
, MaxViewLength
;
107 RTL_QUERY_REGISTRY_TABLE QueryTable
[10];
112 MaximumViewLength
= 0x10000000u
;
113 MaximumPerDiskViewLength
= 0x10000000u
;
114 ReportDetectedDevice
= 0;
115 MarkRamdisksAsRemovable
= 0;
116 MinimumViewCount
= 2;
117 DefaultViewCount
= 16;
118 MaximumViewCount
= 64;
119 MinimumViewLength
= 0x10000u
;
120 DefaultViewLength
= 0x100000u
;
123 // Setup the query table and query the registry
125 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
126 QueryTable
[0].Flags
= 1;
127 QueryTable
[0].Name
= L
"Parameters";
128 QueryTable
[1].Flags
= 32;
129 QueryTable
[1].Name
= L
"ReportDetectedDevice";
130 QueryTable
[1].EntryContext
= &ReportDetectedDevice
;
131 QueryTable
[2].Flags
= 32;
132 QueryTable
[2].Name
= L
"MarkRamdisksAsRemovable";
133 QueryTable
[2].EntryContext
= &MarkRamdisksAsRemovable
;
134 QueryTable
[3].Flags
= 32;
135 QueryTable
[3].Name
= L
"MinimumViewCount";
136 QueryTable
[3].EntryContext
= &MinimumViewCount
;
137 QueryTable
[4].Flags
= 32;
138 QueryTable
[4].Name
= L
"DefaultViewCount";
139 QueryTable
[4].EntryContext
= &DefaultViewCount
;
140 QueryTable
[5].Flags
= 32;
141 QueryTable
[5].Name
= L
"MaximumViewCount";
142 QueryTable
[5].EntryContext
= &MaximumViewCount
;
143 QueryTable
[6].Flags
= 32;
144 QueryTable
[6].Name
= L
"MinimumViewLength";
145 QueryTable
[6].EntryContext
= &MinimumViewLength
;
146 QueryTable
[7].Flags
= 32;
147 QueryTable
[7].Name
= L
"DefaultViewLength";
148 QueryTable
[7].EntryContext
= &DefaultViewLength
;
149 QueryTable
[8].Flags
= 32;
150 QueryTable
[8].Name
= L
"MaximumViewLength";
151 QueryTable
[8].EntryContext
= &MaximumViewLength
;
152 QueryTable
[9].Flags
= 32;
153 QueryTable
[9].Name
= L
"MaximumPerDiskViewLength";
154 QueryTable
[9].EntryContext
= &MaximumPerDiskViewLength
;
155 RtlQueryRegistryValues(RTL_REGISTRY_OPTIONAL
,
156 RegistryPath
->Buffer
,
162 // Parse minimum view count, cannot be bigger than 256 or smaller than 2
164 MinView
= MinimumViewCount
;
165 if (MinimumViewCount
>= 2)
167 if (MinimumViewCount
> 256) MinView
= 256;
173 MinimumViewCount
= MinView
;
176 // Parse default view count, cannot be bigger than 256 or smaller than minimum
178 DefView
= DefaultViewCount
;
179 if (DefaultViewCount
>= MinView
)
181 if (DefaultViewCount
> 256) DefView
= 256;
187 DefaultViewCount
= DefView
;
190 // Parse maximum view count, cannot be bigger than 256 or smaller than default
192 if (MaximumViewCount
>= DefView
)
194 if (MaximumViewCount
> 256) MaximumViewCount
= 256;
198 MaximumViewCount
= DefView
;
202 // Parse minimum view length, cannot be bigger than 1GB or smaller than 64KB
204 MinViewLength
= MinimumViewLength
;
205 if (MinimumViewLength
>= 0x10000)
207 if (MinimumViewLength
> 0x40000000) MinViewLength
= 0x40000000u
;
211 MinViewLength
= 0x10000u
;
213 MinimumViewLength
= MinViewLength
;
216 // Parse default view length, cannot be bigger than 1GB or smaller than minimum
218 DefViewLength
= DefaultViewLength
;
219 if (DefaultViewLength
>= MinViewLength
)
221 if (DefaultViewLength
> 0x40000000) DefViewLength
= 0x40000000u
;
225 DefViewLength
= MinViewLength
;
227 DefaultViewLength
= DefViewLength
;
230 // Parse maximum view length, cannot be bigger than 1GB or smaller than default
232 MaxViewLength
= MaximumViewLength
;
233 if (MaximumViewLength
>= DefViewLength
)
235 if (MaximumViewLength
> 0x40000000) MaxViewLength
= 0x40000000u
;
239 MaxViewLength
= DefViewLength
;
241 MaximumViewLength
= MaxViewLength
;
244 // Parse maximum view length per disk, cannot be smaller than 16MB
246 if (MaximumPerDiskViewLength
>= 0x1000000)
248 if (MaxViewLength
> 0xFFFFFFFF) MaximumPerDiskViewLength
= -1;
252 MaximumPerDiskViewLength
= 0x1000000u
;
258 RamdiskCreateDiskDevice(IN PRAMDISK_BUS_EXTENSION DeviceExtension
,
259 IN PRAMDISK_CREATE_INPUT Input
,
260 IN BOOLEAN ValidateOnly
,
261 OUT PRAMDISK_DRIVE_EXTENSION
*NewDriveExtension
)
263 ULONG BasePage
, ViewCount
, DiskType
, Length
;
265 PDEVICE_OBJECT DeviceObject
;
266 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
268 WCHAR LocalBuffer
[16];
269 UNICODE_STRING SymbolicLinkName
, DriveString
, GuidString
, DeviceName
;
272 // Check if we're a CDROM-type RAM disk
274 DiskType
= Input
->DiskType
;
275 if (DiskType
> FILE_DEVICE_CD_ROM
)
278 // Check if we're an ISO
280 if (DiskType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
)
283 // NTLDR mounted us somewhere
285 BasePage
= Input
->BasePage
;
286 if (!BasePage
) return STATUS_INVALID_PARAMETER
;
289 // Sanitize disk options
291 Input
->Options
.Fixed
= TRUE
;
292 Input
->Options
.Readonly
= Input
->Options
.ExportAsCd
|
293 Input
->Options
.Readonly
;
294 Input
->Options
.Hidden
= FALSE
;
295 Input
->Options
.NoDosDevice
= FALSE
;
296 Input
->Options
.NoDriveLetter
= IsWinPEBoot
? TRUE
: FALSE
;
301 // The only other possibility is a controller
303 if (DiskType
!= FILE_DEVICE_CONTROLLER
)
304 return STATUS_INVALID_PARAMETER
;
307 // Read the view count instead
309 ViewCount
= Input
->ViewCount
;
312 // Sanitize disk options
314 Input
->Options
.Hidden
= FALSE
;
315 Input
->Options
.NoDosDevice
= FALSE
;
316 Input
->Options
.Readonly
= FALSE
;
317 Input
->Options
.NoDriveLetter
= TRUE
;
318 Input
->Options
.Fixed
= TRUE
;
322 // Are we just validating and returning to the user?
324 if (ValidateOnly
) return STATUS_SUCCESS
;
327 // Build the GUID string
329 Status
= RtlStringFromGUID(&Input
->DiskGuid
, &GuidString
);
330 if (!(NT_SUCCESS(Status
)) || !(GuidString
.Buffer
))
335 Status
= STATUS_INSUFFICIENT_RESOURCES
;
340 // Allocate our device name
342 Length
= GuidString
.Length
+ 32;
343 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
345 TAG('R', 'a', 'm', 'd'));
351 Status
= STATUS_INSUFFICIENT_RESOURCES
;
356 // Build the device name string
358 DeviceName
.Buffer
= Buffer
;
359 DeviceName
.Length
= Length
- 2;
360 DeviceName
.MaximumLength
= Length
;
361 wcsncpy(Buffer
, L
"\\Device\\Ramdisk", Length
/ sizeof(WCHAR
));
362 wcsncat(Buffer
, GuidString
.Buffer
, Length
/ sizeof(WCHAR
));
363 DPRINT1("Creating device: %wZ\n", &DeviceName
);
366 // Create the drive device
368 Status
= IoCreateDevice(DeviceExtension
->DeviceObject
->DriverObject
,
369 sizeof(RAMDISK_DRIVE_EXTENSION
),
371 FILE_DEVICE_DISK_FILE_SYSTEM
, // FIXME: DISK
372 FILE_READ_ONLY_DEVICE
, // FIXME: Not always
375 if (!NT_SUCCESS(Status
)) goto FailCreate
;
378 // Grab the drive extension
380 DriveExtension
= DeviceObject
->DeviceExtension
;
383 // Check if we need a DOS device
385 if (!Input
->Options
.NoDosDevice
)
388 // Build the symbolic link name
390 SymbolicLinkName
.MaximumLength
= GuidString
.Length
+ 36;
391 SymbolicLinkName
.Length
= GuidString
.Length
+ 34;
392 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
393 SymbolicLinkName
.MaximumLength
,
394 TAG('R', 'a', 'm', 'd'));
395 SymbolicLinkName
.Buffer
= Buffer
;
402 L
"\\GLOBAL??\\Ramdisk",
403 SymbolicLinkName
.MaximumLength
/ sizeof(WCHAR
));
406 SymbolicLinkName
.MaximumLength
/ sizeof(WCHAR
));
407 DPRINT1("Creating symbolic link: %wZ to %wZ \n",
408 &SymbolicLinkName
, &DeviceName
);
409 Status
= IoCreateSymbolicLink(&SymbolicLinkName
, &DeviceName
);
410 if (!NT_SUCCESS(Status
))
415 Input
->Options
.NoDosDevice
= TRUE
;
417 SymbolicLinkName
.Buffer
= NULL
;
425 Input
->Options
.NoDosDevice
= TRUE
;
429 // It this an ISO boot ramdisk?
431 if (Input
->DiskType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
)
434 // Does it need a drive letter?
436 if (!Input
->Options
.NoDriveLetter
)
439 // Build it and take over the existing symbolic link
441 _snwprintf(LocalBuffer
,
443 L
"\\DosDevices\\%wc:",
445 RtlInitUnicodeString(&DriveString
, LocalBuffer
);
446 DPRINT1("Creating symbolic link: %wZ to %wZ\n",
447 &DriveString
, &DeviceName
);
448 IoDeleteSymbolicLink(&DriveString
);
449 IoCreateSymbolicLink(&DriveString
, &DeviceName
);
452 // Save the drive letter
454 DriveExtension
->DriveLetter
= Input
->DriveLetter
;
461 // Setup the device object flags
463 DeviceObject
->Flags
|= (DO_XIP
| DO_POWER_PAGABLE
| DO_DIRECT_IO
);
464 DeviceObject
->AlignmentRequirement
= 1;
467 // Build the drive FDO
469 *NewDriveExtension
= DriveExtension
;
470 DriveExtension
->Type
= RamdiskDrive
;
471 ExInitializeFastMutex(&DriveExtension
->DiskListLock
);
472 IoInitializeRemoveLock(&DriveExtension
->RemoveLock
,
473 TAG('R', 'a', 'm', 'd'),
476 DriveExtension
->DriveDeviceName
= DeviceName
;
477 DriveExtension
->SymbolicLinkName
= SymbolicLinkName
;
478 DriveExtension
->GuidString
= GuidString
;
479 DriveExtension
->DiskGuid
= Input
->DiskGuid
;
480 DriveExtension
->PhysicalDeviceObject
= DeviceObject
;
481 DriveExtension
->DeviceObject
= RamdiskBusFdo
;
482 DriveExtension
->AttachedDevice
= RamdiskBusFdo
;
483 DriveExtension
->DiskType
= Input
->DiskType
;
484 DriveExtension
->DiskOptions
= Input
->Options
;
485 DriveExtension
->DiskLength
= Input
->DiskLength
;
486 DriveExtension
->DiskOffset
= Input
->DiskOffset
;
489 // Make sure we don't free it later
491 DeviceName
.Buffer
= NULL
;
492 SymbolicLinkName
.Buffer
= NULL
;
493 GuidString
.Buffer
= NULL
;
499 return STATUS_SUCCESS
;
504 RamdiskCreateRamdisk(IN PDEVICE_OBJECT DeviceObject
,
506 IN BOOLEAN ValidateOnly
)
508 PRAMDISK_CREATE_INPUT Input
;
510 PRAMDISK_BUS_EXTENSION DeviceExtension
;
511 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
513 PWCHAR FileNameStart
, FileNameEnd
;
515 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
518 // Get the device extension and our input data
520 DeviceExtension
= DeviceObject
->DeviceExtension
;
521 Length
= IoStackLocation
->Parameters
.DeviceIoControl
.InputBufferLength
;
522 Input
= (PRAMDISK_CREATE_INPUT
)Irp
->AssociatedIrp
.SystemBuffer
;
525 // Validate input parameters
527 if ((Length
< sizeof(RAMDISK_CREATE_INPUT
)) ||
528 (Input
->Version
!= sizeof(RAMDISK_CREATE_INPUT
)))
533 return STATUS_INVALID_PARAMETER
;
537 // Validate the disk type
539 DiskType
= Input
->DiskType
;
540 if (DiskType
== FILE_DEVICE_CONTROLLER
) return STATUS_INVALID_PARAMETER
;
543 // Look at the disk type
545 if (DiskType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
)
548 // We only allow this as an early-init boot
550 if (!KeLoaderBlock
) return STATUS_INVALID_PARAMETER
;
553 // Save command-line flags
555 if (ExportBootDiskAsCd
) Input
->Options
.ExportAsCd
= TRUE
;
556 if (IsWinPEBoot
) Input
->Options
.NoDriveLetter
= TRUE
;
560 // Validate the disk type
562 if ((Input
->Options
.ExportAsCd
) &&
563 (DiskType
!= FILE_DEVICE_CD_ROM_FILE_SYSTEM
))
566 // If the type isn't CDFS, it has to at least be raw CD
568 if (DiskType
!= FILE_DEVICE_CD_ROM
) return STATUS_INVALID_PARAMETER
;
572 // Check if this is an actual file
574 if (DiskType
<= FILE_DEVICE_CD_ROM
)
577 // Validate the file name
579 FileNameStart
= (PWCHAR
)((ULONG_PTR
)Input
+ Length
);
580 FileNameEnd
= Input
->FileName
+ 1;
581 while ((FileNameEnd
< FileNameStart
) && *(FileNameEnd
)) FileNameEnd
++;
582 if (FileNameEnd
== FileNameStart
) return STATUS_INVALID_PARAMETER
;
586 // Create the actual device
588 Status
= RamdiskCreateDiskDevice(DeviceExtension
,
592 if (NT_SUCCESS(Status
))
595 // Invalidate and set success
597 IoInvalidateDeviceRelations(DeviceExtension
->PhysicalDeviceObject
, 0);
598 Irp
->IoStatus
.Information
= STATUS_SUCCESS
;
609 RamdiskWorkerThread(IN PDEVICE_OBJECT DeviceObject
,
612 PRAMDISK_BUS_EXTENSION DeviceExtension
;
614 PIO_STACK_LOCATION IoStackLocation
;
618 // Get the stack location
620 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
623 // Free the work item
625 IoFreeWorkItem(Irp
->Tail
.Overlay
.DriverContext
[0]);
628 // Grab the device extension and lock it
630 DeviceExtension
= DeviceObject
->DeviceExtension
;
631 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
632 if (NT_SUCCESS(Status
))
635 // Discriminate by major code
637 switch (IoStackLocation
->MajorFunction
)
642 case IRP_MJ_DEVICE_CONTROL
:
645 // Let's take a look at the IOCTL
647 switch (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
)
650 // Ramdisk create request
652 case FSCTL_CREATE_RAM_DISK
:
655 // This time we'll do it for real
657 Status
= RamdiskCreateRamdisk(DeviceObject
, Irp
, FALSE
);
660 case IOCTL_DISK_SET_PARTITION_INFO
:
662 DPRINT1("Set partition info request\n");
667 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
669 DPRINT1("Get drive layout request\n");
674 case IOCTL_DISK_GET_PARTITION_INFO
:
676 DPRINT1("Get partitinon info request\n");
683 DPRINT1("Invalid request\n");
695 // Read or write request
700 DPRINT1("Read/Write request\n");
706 // Internal request (SCSI?)
708 case IRP_MJ_INTERNAL_DEVICE_CONTROL
:
710 DPRINT1("SCSI request\n");
718 case IRP_MJ_FLUSH_BUFFERS
:
720 DPRINT1("Flush request\n");
730 DPRINT1("Invalid request: %lx\n", IoStackLocation
->MajorFunction
);
739 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
740 Irp
->IoStatus
.Status
= Status
;
741 Irp
->IoStatus
.Information
= 0;
742 return IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
748 Irp
->IoStatus
.Status
= Status
;
749 Irp
->IoStatus
.Information
= 0;
750 return IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
755 SendIrpToThread(IN PDEVICE_OBJECT DeviceObject
,
758 PIO_WORKITEM WorkItem
;
761 // Mark the IRP pending
763 IoMarkIrpPending(Irp
);
766 // Allocate a work item
768 WorkItem
= IoAllocateWorkItem(DeviceObject
);
774 Irp
->Tail
.Overlay
.DriverContext
[0] = WorkItem
;
775 IoQueueWorkItem(WorkItem
, RamdiskWorkerThread
, DelayedWorkQueue
, Irp
);
776 return STATUS_PENDING
;
783 return STATUS_INSUFFICIENT_RESOURCES
;
789 RamdiskOpenClose(IN PDEVICE_OBJECT DeviceObject
,
795 Irp
->IoStatus
.Information
= 1;
796 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
797 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
798 return STATUS_SUCCESS
;
803 RamdiskReadWrite(IN PDEVICE_OBJECT DeviceObject
,
808 return STATUS_SUCCESS
;
813 RamdiskDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
817 PIO_STACK_LOCATION IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
818 PRAMDISK_BUS_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
819 ULONG Information
= 0;
822 // Grab the remove lock
824 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
825 if (!NT_SUCCESS(Status
))
830 Irp
->IoStatus
.Information
= 0;
831 Irp
->IoStatus
.Status
= Status
;
832 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
837 // Check if this is an bus device or the drive
839 if (DeviceExtension
->Type
== RamdiskBus
)
842 // Check what the request is
844 switch (IoStackLocation
->Parameters
.DeviceIoControl
.IoControlCode
)
847 // Request to create a ramdisk
849 case FSCTL_CREATE_RAM_DISK
:
854 Status
= RamdiskCreateRamdisk(DeviceObject
, Irp
, TRUE
);
855 if (!NT_SUCCESS(Status
)) goto CompleteRequest
;
861 // We don't handle anything else yet
870 // Drive code not yet done
876 // Queue the request to our worker thread
878 Status
= SendIrpToThread(DeviceObject
, Irp
);
884 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
885 if (Status
!= STATUS_PENDING
)
888 // Complete the request
890 Irp
->IoStatus
.Status
= Status
;
891 Irp
->IoStatus
.Information
= Information
;
892 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
903 RamdiskQueryDeviceRelations(IN DEVICE_RELATION_TYPE Type
,
904 IN PDEVICE_OBJECT DeviceObject
,
907 PRAMDISK_BUS_EXTENSION DeviceExtension
;
908 PRAMDISK_DRIVE_EXTENSION DriveExtension
;
909 PDEVICE_RELATIONS DeviceRelations
, OurDeviceRelations
;
910 ULONG Count
, DiskCount
, FinalCount
;
911 PLIST_ENTRY ListHead
, NextEntry
;
912 PDEVICE_OBJECT
* DriveDeviceObject
;
913 RAMDISK_DEVICE_STATE State
;
916 // Get the device extension and check if this is a drive
918 DeviceExtension
= DeviceObject
->DeviceExtension
;
919 if (DeviceExtension
->Type
== RamdiskDrive
)
929 // Anything but bus relations, we don't handle
931 if (Type
) goto PassToNext
;
934 // Acquire the disk list lock
936 KeEnterCriticalRegion();
937 ExAcquireFastMutex(&DeviceExtension
->DiskListLock
);
940 // Did a device already fill relations?
942 DeviceRelations
= (PDEVICE_RELATIONS
)Irp
->IoStatus
.Information
;
948 Count
= DeviceRelations
->Count
;
959 // Now loop our drives
962 ListHead
= &DeviceExtension
->DiskList
;
963 NextEntry
= ListHead
->Flink
;
964 while (NextEntry
!= ListHead
)
967 // As long as it wasn't removed, count it in
969 DriveExtension
= CONTAINING_RECORD(NextEntry
,
970 RAMDISK_DRIVE_EXTENSION
,
972 if (DriveExtension
->State
< RamdiskStateBusRemoved
) DiskCount
++;
975 // Move to the next one
977 NextEntry
= NextEntry
->Flink
;
981 // Now we know our final count
983 FinalCount
= Count
+ DiskCount
;
986 // Allocate the structure
988 OurDeviceRelations
= ExAllocatePoolWithTag(PagedPool
,
989 FIELD_OFFSET(DEVICE_RELATIONS
,
992 sizeof(PDEVICE_OBJECT
),
993 TAG('R', 'a', 'm', 'd'));
994 if (!OurDeviceRelations
)
999 ExReleaseFastMutex(&DeviceExtension
->DiskListLock
);
1000 KeLeaveCriticalRegion();
1001 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1002 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1003 return STATUS_INSUFFICIENT_RESOURCES
;
1007 // Check if we already had some relations
1014 RtlCopyMemory(OurDeviceRelations
->Objects
,
1015 DeviceRelations
->Objects
,
1016 Count
* sizeof(PDEVICE_OBJECT
));
1022 OurDeviceRelations
->Count
= FinalCount
;
1025 // Now loop our drives again
1027 ListHead
= &DeviceExtension
->DiskList
;
1028 NextEntry
= ListHead
->Flink
;
1029 while (NextEntry
!= ListHead
)
1032 // Go to the end of the list
1034 DriveDeviceObject
= &OurDeviceRelations
->Objects
[Count
];
1037 // Get the drive state
1039 DriveExtension
= CONTAINING_RECORD(NextEntry
,
1040 RAMDISK_DRIVE_EXTENSION
,
1042 State
= DriveExtension
->State
;
1045 // If it was removed or enumerated, we don't touch the device object
1047 if (State
>= RamdiskStateBusRemoved
)
1050 // If it was removed, we still have to keep track of this though
1052 if (State
== RamdiskStateBusRemoved
)
1055 // Mark it as enumerated now, but don't actually reference it
1057 DriveExtension
->State
= RamdiskStateEnumerated
;
1063 // First time it's enumerated, reference the device object
1065 ObReferenceObject(DriveExtension
->DeviceObject
);
1068 // Save the object pointer, and move on
1070 *DriveDeviceObject
++ = DriveExtension
->DeviceObject
;
1073 if (DriveExtension
->State
< RamdiskStateBusRemoved
) DiskCount
++;
1076 // Move to the next one
1078 NextEntry
= NextEntry
->Flink
;
1084 ExReleaseFastMutex(&DeviceExtension
->DiskListLock
);
1085 KeLeaveCriticalRegion();
1088 // Cleanup old relations
1090 if (DeviceRelations
) ExFreePool(DeviceRelations
);
1095 Irp
->IoStatus
.Information
= (ULONG_PTR
)OurDeviceRelations
;
1096 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1099 // Pass to the next driver
1102 IoCopyCurrentIrpStackLocationToNext(Irp
);
1103 return IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
1108 RamdiskPnp(IN PDEVICE_OBJECT DeviceObject
,
1111 PIO_STACK_LOCATION IoStackLocation
;
1112 PRAMDISK_BUS_EXTENSION DeviceExtension
;
1117 // Get the device extension and stack location
1119 DeviceExtension
= DeviceObject
->DeviceExtension
;
1120 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
1121 Minor
= IoStackLocation
->MinorFunction
;
1124 // Check if the bus is removed
1126 if (DeviceExtension
->State
== RamdiskStateBusRemoved
)
1129 // Only remove-device and query-id are allowed
1131 if ((Minor
!= IRP_MN_REMOVE_DEVICE
) || (Minor
!= IRP_MN_QUERY_ID
))
1134 // Fail anything else
1136 Status
= STATUS_NO_SUCH_DEVICE
;
1137 Irp
->IoStatus
.Status
= Status
;
1138 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1144 // Acquire the remove lock
1146 Status
= IoAcquireRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
1147 if (!NT_SUCCESS(Status
))
1152 Irp
->IoStatus
.Information
= 0;
1153 Irp
->IoStatus
.Status
= Status
;
1154 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1159 // Query the IRP type
1163 case IRP_MN_START_DEVICE
:
1165 DPRINT1("PnP IRP: %lx\n", Minor
);
1169 case IRP_MN_QUERY_STOP_DEVICE
:
1171 DPRINT1("PnP IRP: %lx\n", Minor
);
1175 case IRP_MN_CANCEL_STOP_DEVICE
:
1177 DPRINT1("PnP IRP: %lx\n", Minor
);
1181 case IRP_MN_STOP_DEVICE
:
1183 DPRINT1("PnP IRP: %lx\n", Minor
);
1187 case IRP_MN_QUERY_REMOVE_DEVICE
:
1189 DPRINT1("PnP IRP: %lx\n", Minor
);
1193 case IRP_MN_CANCEL_REMOVE_DEVICE
:
1195 DPRINT1("PnP IRP: %lx\n", Minor
);
1199 case IRP_MN_REMOVE_DEVICE
:
1201 DPRINT1("PnP IRP: %lx\n", Minor
);
1205 case IRP_MN_SURPRISE_REMOVAL
:
1207 DPRINT1("PnP IRP: %lx\n", Minor
);
1211 case IRP_MN_QUERY_ID
:
1216 if (DeviceExtension
->Type
== RamdiskDrive
)
1218 DPRINT1("PnP IRP: %lx\n", Minor
);
1223 case IRP_MN_QUERY_BUS_INFORMATION
:
1228 if (DeviceExtension
->Type
== RamdiskDrive
)
1230 DPRINT1("PnP IRP: %lx\n", Minor
);
1237 DPRINT1("PnP IRP: %lx\n", Minor
);
1241 case IRP_MN_QUERY_DEVICE_TEXT
:
1246 if (DeviceExtension
->Type
== RamdiskDrive
)
1248 DPRINT1("PnP IRP: %lx\n", Minor
);
1253 case IRP_MN_QUERY_DEVICE_RELATIONS
:
1256 // Call our main routine
1258 Status
= RamdiskQueryDeviceRelations(IoStackLocation
->
1260 QueryDeviceRelations
.Type
,
1263 goto ReleaseAndReturn
;
1265 case IRP_MN_QUERY_CAPABILITIES
:
1270 if (DeviceExtension
->Type
== RamdiskDrive
)
1272 DPRINT1("PnP IRP: %lx\n", Minor
);
1277 case IRP_MN_QUERY_RESOURCES
:
1278 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS
:
1281 // Complete immediately without touching it
1283 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1284 goto ReleaseAndReturn
;
1288 DPRINT1("Illegal IRP: %lx\n", Minor
);
1295 if (DeviceExtension
->Type
== RamdiskBus
)
1298 // Do we have an attached device?
1300 if (DeviceExtension
->AttachedDevice
)
1305 IoSkipCurrentIrpStackLocation(Irp
);
1306 Status
= IoCallDriver(DeviceExtension
->AttachedDevice
, Irp
);
1311 // Release the lock and return status
1314 IoReleaseRemoveLock(&DeviceExtension
->RemoveLock
, Irp
);
1320 RamdiskPower(IN PDEVICE_OBJECT DeviceObject
,
1325 return STATUS_SUCCESS
;
1330 RamdiskSystemControl(IN PDEVICE_OBJECT DeviceObject
,
1335 return STATUS_SUCCESS
;
1340 RamdiskScsi(IN PDEVICE_OBJECT DeviceObject
,
1345 return STATUS_SUCCESS
;
1350 RamdiskFlushBuffers(IN PDEVICE_OBJECT DeviceObject
,
1355 return STATUS_SUCCESS
;
1360 RamdiskUnload(IN PDRIVER_OBJECT DriverObject
)
1368 RamdiskAddDevice(IN PDRIVER_OBJECT DriverObject
,
1369 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1371 PRAMDISK_BUS_EXTENSION DeviceExtension
;
1372 PDEVICE_OBJECT AttachedDevice
;
1374 UNICODE_STRING DeviceName
;
1375 PDEVICE_OBJECT DeviceObject
;
1378 // Only create the bus FDO once
1380 if (RamdiskBusFdo
) return STATUS_DEVICE_ALREADY_ATTACHED
;
1383 // Create the bus FDO
1385 RtlInitUnicodeString(&DeviceName
, L
"\\Device\\Ramdisk");
1386 Status
= IoCreateDevice(DriverObject
,
1387 sizeof(RAMDISK_BUS_EXTENSION
),
1389 FILE_DEVICE_BUS_EXTENDER
,
1390 FILE_DEVICE_SECURE_OPEN
,
1393 if (NT_SUCCESS(Status
))
1396 // Initialize the bus FDO extension
1398 DeviceExtension
= DeviceObject
->DeviceExtension
;
1399 RtlZeroMemory(DeviceObject
->DeviceExtension
,
1400 sizeof(RAMDISK_BUS_EXTENSION
));
1403 // Set bus FDO flags
1405 DeviceObject
->Flags
|= DO_POWER_PAGABLE
| DO_DIRECT_IO
;
1408 // Setup the bus FDO extension
1410 DeviceExtension
->Type
= RamdiskBus
;
1411 ExInitializeFastMutex(&DeviceExtension
->DiskListLock
);
1412 IoInitializeRemoveLock(&DeviceExtension
->RemoveLock
,
1413 TAG('R', 'a', 'm', 'd'),
1416 InitializeListHead(&DeviceExtension
->DiskList
);
1417 DeviceExtension
->PhysicalDeviceObject
= PhysicalDeviceObject
;
1418 DeviceExtension
->DeviceObject
= DeviceObject
;
1421 // Register the RAM disk device interface
1423 Status
= IoRegisterDeviceInterface(PhysicalDeviceObject
,
1424 &RamdiskBusInterface
,
1426 &DeviceExtension
->BusDeviceName
);
1427 if (!NT_SUCCESS(Status
))
1432 IoDeleteDevice(DeviceObject
);
1437 // Attach us to the device stack
1439 AttachedDevice
= IoAttachDeviceToDeviceStack(DeviceObject
,
1440 PhysicalDeviceObject
);
1441 DeviceExtension
->AttachedDevice
= AttachedDevice
;
1442 if (!AttachedDevice
)
1447 IoSetDeviceInterfaceState(&DeviceExtension
->BusDeviceName
, 0);
1448 RtlFreeUnicodeString(&DeviceExtension
->BusDeviceName
);
1449 IoDeleteDevice(DeviceObject
);
1450 return STATUS_NO_SUCH_DEVICE
;
1454 // Bus FDO is initialized
1456 RamdiskBusFdo
= DeviceObject
;
1459 // Loop for loader block
1464 // Are we being booted from setup? Not yet supported
1466 ASSERT (!KeLoaderBlock
->SetupLdrBlock
);
1472 DeviceObject
->Flags
&= DO_DEVICE_INITIALIZING
;
1473 Status
= STATUS_SUCCESS
;
1484 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
1485 IN PUNICODE_STRING RegistryPath
)
1487 PCHAR BootDeviceName
, CommandLine
;
1488 PDEVICE_OBJECT PhysicalDeviceObject
= NULL
;
1492 // Query ramdisk parameters
1494 QueryParameters(RegistryPath
);
1497 // Save the registry path
1499 DriverRegistryPath
= *RegistryPath
;
1500 DriverRegistryPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1501 RegistryPath
->Length
+
1503 TAG('R', 'a', 'm', 'd'));
1504 if (!DriverRegistryPath
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1505 RtlCopyUnicodeString(&DriverRegistryPath
, RegistryPath
);
1508 // Set device routines
1510 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = RamdiskOpenClose
;
1511 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = RamdiskOpenClose
;
1512 DriverObject
->MajorFunction
[IRP_MJ_READ
] = RamdiskReadWrite
;
1513 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = RamdiskReadWrite
;
1514 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = RamdiskDeviceControl
;
1515 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = RamdiskPnp
;
1516 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = RamdiskPower
;
1517 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = RamdiskSystemControl
;
1518 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = RamdiskScsi
;
1519 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = RamdiskFlushBuffers
;
1520 DriverObject
->DriverExtension
->AddDevice
= RamdiskAddDevice
;
1521 DriverObject
->DriverUnload
= RamdiskUnload
;
1524 // Check for a loader block
1529 // Get the boot device name
1531 BootDeviceName
= KeLoaderBlock
->ArcBootDeviceName
;
1535 // Check if we're booting from ramdisk
1537 if ((strlen(BootDeviceName
) >= 10) &&
1538 !(_strnicmp(BootDeviceName
, "ramdisk(0)", 10)))
1541 // We'll have to tell the PnP Manager
1543 ReportDetectedDevice
= TRUE
;
1546 // Check for a command line
1548 CommandLine
= KeLoaderBlock
->LoadOptions
;
1552 // Check if this is an ISO boot
1554 if (strstr(CommandLine
, "RDEXPORTASCD"))
1557 // Remember for later
1559 ExportBootDiskAsCd
= TRUE
;
1563 // Check if this is PE boot
1565 if (strstr(CommandLine
, "MININT"))
1568 // Remember for later
1579 // Installing from Ramdisk isn't supported yet
1581 ASSERT(!KeLoaderBlock
->SetupLdrBlock
);
1584 // Are we reporting the device
1586 if (ReportDetectedDevice
)
1591 Status
= IoReportDetectedDevice(DriverObject
,
1592 InterfaceTypeUndefined
,
1598 &PhysicalDeviceObject
);
1599 if (NT_SUCCESS(Status
))
1603 // The ReactOS Plug and Play Manager is broken and does not create
1604 // the required keys when reporting a detected device.
1605 // We hack around this ourselves.
1607 RtlCreateUnicodeString(&((PEXTENDED_DEVOBJ_EXTENSION
)
1608 PhysicalDeviceObject
->DeviceObjectExtension
)
1609 ->DeviceNode
->InstancePath
,
1610 L
"Root\\UNKNOWN\\0000");
1613 // Create the device object
1615 Status
= RamdiskAddDevice(DriverObject
, PhysicalDeviceObject
);
1616 if (NT_SUCCESS(Status
))
1621 PhysicalDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1622 Status
= STATUS_SUCCESS
;
1631 Status
= STATUS_SUCCESS
;