2 * captive media (cdrom/disk) emulation for reactos
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "media.h" /* self */
23 #include "captive/storage.h" /* self */
24 #include <glib/gmessages.h>
25 #include "reactos/ddk/class2.h" /* for DEVICE_EXTENSION */
26 #include "reactos/ddk/status.h"
27 #include "reactos/ddk/iofuncs.h" /* for IoIsErrorUserInduced() */
28 #include "captive/macros.h"
29 #include "reactos/ddk/mmfuncs.h" /* for MmGetMdlByteCount() */
30 #include "captive/unicode.h"
31 #include <glib/gmacros.h>
32 #include "reactos/structs.h" /* for PREVENT_MEDIA_REMOVAL */
33 #include "captive/options.h"
36 GIOChannel *captive_image_iochannel;
37 guint64 captive_image_size;
40 static gboolean validate_DeviceObject(DEVICE_OBJECT *DeviceObject)
42 DEVICE_EXTENSION *DeviceExtension;
43 DISK_GEOMETRY *DiskGeometry;
44 IO_SCSI_CAPABILITIES *PortCapabilities;
45 struct captive_DriverObject *captive_DriverObject;
47 g_return_val_if_fail(DeviceObject!=NULL,FALSE);
49 captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
50 DeviceExtension=DeviceObject->DeviceExtension;
52 DiskGeometry=DeviceExtension->DiskGeometry;
53 g_return_val_if_fail(DiskGeometry==&captive_DriverObject->DiskGeometry,FALSE);
54 g_return_val_if_fail(DiskGeometry->MediaType==captive_DriverObject->DiskGeometry_check.MediaType,FALSE);
55 g_return_val_if_fail(DiskGeometry->TracksPerCylinder==captive_DriverObject->DiskGeometry_check.TracksPerCylinder,FALSE);
56 g_return_val_if_fail(DiskGeometry->SectorsPerTrack==captive_DriverObject->DiskGeometry_check.SectorsPerTrack,FALSE);
57 g_return_val_if_fail(DiskGeometry->BytesPerSector==captive_DriverObject->DiskGeometry_check.BytesPerSector,FALSE);
58 g_return_val_if_fail(DiskGeometry->Cylinders.QuadPart==captive_DriverObject->DiskGeometry_check.Cylinders.QuadPart,FALSE);
59 g_return_val_if_fail(DeviceExtension->PartitionLength.QuadPart==(gint64)captive_image_size,FALSE);
61 PortCapabilities=DeviceExtension->PortCapabilities;
62 g_return_val_if_fail(PortCapabilities==&captive_DriverObject->PortCapabilities,FALSE);
63 g_return_val_if_fail(PortCapabilities->Length==captive_DriverObject->PortCapabilities_check.Length,FALSE);
64 g_return_val_if_fail(PortCapabilities->MaximumTransferLength==captive_DriverObject->PortCapabilities_check.MaximumTransferLength,FALSE);
65 g_return_val_if_fail(PortCapabilities->MaximumPhysicalPages==captive_DriverObject->PortCapabilities_check.MaximumPhysicalPages,FALSE);
66 g_return_val_if_fail(PortCapabilities->SupportedAsynchronousEvents==captive_DriverObject->PortCapabilities_check.SupportedAsynchronousEvents,FALSE);
67 g_return_val_if_fail(PortCapabilities->AlignmentMask==captive_DriverObject->PortCapabilities_check.AlignmentMask,FALSE);
68 g_return_val_if_fail(PortCapabilities->TaggedQueuing==captive_DriverObject->PortCapabilities_check.TaggedQueuing,FALSE);
69 g_return_val_if_fail(PortCapabilities->AdapterScansDown==captive_DriverObject->PortCapabilities_check.AdapterScansDown,FALSE);
70 g_return_val_if_fail(PortCapabilities->AdapterUsesPio==captive_DriverObject->PortCapabilities_check.AdapterUsesPio,FALSE);
76 static NTSTATUS MajorFunction_Irp_finish(DEVICE_OBJECT *DeviceObject,IRP *Irp)
80 g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
81 g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
83 /* required for removable media only */
84 if (!NT_SUCCESS(Irp->IoStatus.Status) && IoIsErrorUserInduced(Irp->IoStatus.Status)) {
85 g_assert(Irp->Tail.Overlay.Thread!=NULL); /* FIXME: Error should be postponed to first !=NULL Irp later */
86 IoSetHardErrorOrVerifyDevice(Irp,DeviceObject);
87 Irp->IoStatus.Information=0; /* may got set during some processing before error occured */
90 /* IoCompleteRequest() will do 'IoFreeIrp(Irp);'!
91 * 'IoStatus.Status' must be saved before its invocation!
93 r=Irp->IoStatus.Status;
94 IoCompleteRequest(Irp,IO_NO_INCREMENT);
99 /* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
100 * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
102 #define MajorFunction_DEVICE_CONTROL ((PDRIVER_DISPATCH)MajorFunction_DEVICE_CONTROL_func)
103 static NTSTATUS CAPTIVE_STDCALL MajorFunction_DEVICE_CONTROL_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
105 struct captive_DriverObject *captive_DriverObject;
106 IO_STACK_LOCATION *IrpStack;
108 g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
109 g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
111 captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
113 Irp->IoStatus.Information=0; /* request-specific, may get overriden later */
114 IrpStack=IoGetCurrentIrpStackLocation(Irp);
115 g_assert(IrpStack->MajorFunction==IRP_MJ_DEVICE_CONTROL);
116 g_assert(IrpStack->MinorFunction==0);
118 switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
120 case IOCTL_CDROM_GET_LAST_SESSION:
121 /* Nothing interesting to see, move along.
122 * FIXME: This call is somehow multisession related - must we care?
126 case IOCTL_CDROM_READ_TOC: {
129 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(CDROM_TOC)) {
130 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
131 Irp->IoStatus.Information=sizeof(CDROM_TOC);
132 g_assert_not_reached();
135 CdromToc=(CDROM_TOC *)Irp->AssociatedIrp.SystemBuffer;
136 CAPTIVE_MEMZERO(CdromToc);
137 CdromToc->Length[0]=((sizeof(*CdromToc)-2)>>0U)&0xFFU; /* little-endian */
138 CdromToc->Length[1]=((sizeof(*CdromToc)-2)>>8U)&0xFFU;
139 CdromToc->FirstTrack=0; /* one track; TOC_LAST_TRACK does not count */
140 CdromToc->LastTrack =0; /* one track; TOC_LAST_TRACK does not count */
141 CdromToc->TrackData[0].Control=TOC_DATA_TRACK;
142 CdromToc->TrackData[0].Adr=0; /* Q-subchannel subinfo */
143 CdromToc->TrackData[0].TrackNumber=0;
144 CdromToc->TrackData[0].Address[0]=0>>24U; /* LBA offset; big-endian */
145 CdromToc->TrackData[0].Address[1]=0>>16U;
146 CdromToc->TrackData[0].Address[2]=0>> 8U;
147 CdromToc->TrackData[0].Address[3]=0>> 0U;
148 CdromToc->TrackData[1].Control=0;
149 CdromToc->TrackData[1].Adr=0; /* Q-subchannel subinfo */
150 CdromToc->TrackData[1].TrackNumber=TOC_LAST_TRACK;
151 /* FIXME: should we put the captive_image_size to TOC_LAST_TRACK? */
152 CdromToc->TrackData[1].Address[0]=(captive_image_size/512)>>24U; /* LBA offset; big-endian */
153 CdromToc->TrackData[1].Address[1]=(captive_image_size/512)>>16U;
154 CdromToc->TrackData[1].Address[2]=(captive_image_size/512)>> 8U;
155 CdromToc->TrackData[1].Address[3]=(captive_image_size/512)>> 0U;
157 Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
158 Irp->IoStatus.Status=STATUS_SUCCESS;
161 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
162 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
163 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(DISK_GEOMETRY)) {
164 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
165 Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
166 g_assert_not_reached();
169 *(DISK_GEOMETRY *)Irp->AssociatedIrp.SystemBuffer=captive_DriverObject->DiskGeometry;
170 Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
171 Irp->IoStatus.Status=STATUS_SUCCESS;
174 case IOCTL_CDROM_CHECK_VERIFY:
175 case IOCTL_DISK_CHECK_VERIFY:
176 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength) {
177 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(ULONG)) {
178 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
179 Irp->IoStatus.Information=sizeof(ULONG);
180 g_assert_not_reached();
183 *(ULONG *)Irp->AssociatedIrp.SystemBuffer=0; /* MediaChangeCount */
184 Irp->IoStatus.Information=sizeof(ULONG);
187 Irp->IoStatus.Information=0;
189 Irp->IoStatus.Status=STATUS_SUCCESS;
192 case IOCTL_SCSI_GET_CAPABILITIES:
193 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(IO_SCSI_CAPABILITIES)) {
194 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
195 Irp->IoStatus.Information=sizeof(IO_SCSI_CAPABILITIES);
196 g_assert_not_reached();
199 *(IO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer=captive_DriverObject->PortCapabilities;
200 Irp->IoStatus.Information=sizeof(IO_SCSI_CAPABILITIES);
201 Irp->IoStatus.Status=STATUS_SUCCESS;
204 case IOCTL_DISK_GET_PARTITION_INFO: {
205 PARTITION_INFORMATION *PartitionInformation;
207 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(PARTITION_INFORMATION)) {
208 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
209 Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION);
210 g_assert_not_reached();
213 PartitionInformation=(PARTITION_INFORMATION *)Irp->AssociatedIrp.SystemBuffer;
214 PartitionInformation->StartingOffset.QuadPart=0;
215 PartitionInformation->PartitionLength.QuadPart=captive_image_size; /* unit=bytes */
216 PartitionInformation->HiddenSectors=0; /* FIXME: real image disk offset */
217 PartitionInformation->PartitionNumber=1;
218 PartitionInformation->PartitionType=0; /* FIXME: meaning? */
219 PartitionInformation->BootIndicator=TRUE;
220 PartitionInformation->RecognizedPartition=TRUE;
221 PartitionInformation->RewritePartition=FALSE; /* FIXME: meaning? */
222 Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION);
223 Irp->IoStatus.Status=STATUS_SUCCESS;
226 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
227 PARTITION_INFORMATION_EX *PartitionInformationEx;
229 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(PARTITION_INFORMATION_EX)) {
230 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
231 Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION_EX);
232 g_assert_not_reached();
235 PartitionInformationEx=(PARTITION_INFORMATION_EX *)Irp->AssociatedIrp.SystemBuffer;
236 PartitionInformationEx->PartitionStyle=PARTITION_STYLE_RAW; /* not MBR or GPT */
237 PartitionInformationEx->StartingOffset.QuadPart=0;
238 PartitionInformationEx->PartitionLength.QuadPart=captive_image_size; /* unit=bytes */
239 PartitionInformationEx->PartitionNumber=0; /* FIXME: what number? */
240 PartitionInformationEx->RewritePartition=FALSE; /* FIXME: meaning? */
241 Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION_EX);
242 Irp->IoStatus.Status=STATUS_SUCCESS;
245 case IOCTL_STORAGE_GET_HOTPLUG_INFO:
246 Irp->IoStatus.Status=STATUS_NOT_SUPPORTED;
249 case IOCTL_DISK_IS_WRITABLE:
250 Irp->IoStatus.Information=0;
251 switch (captive_options->rwmode) {
252 case CAPTIVE_OPTION_RWMODE_RO: Irp->IoStatus.Status=STATUS_MEDIA_WRITE_PROTECTED; break;
253 case CAPTIVE_OPTION_RWMODE_BLIND: Irp->IoStatus.Status=STATUS_SUCCESS; break;
254 case CAPTIVE_OPTION_RWMODE_RW: Irp->IoStatus.Status=STATUS_SUCCESS; break;
255 default: g_assert_not_reached();
259 case IOCTL_DISK_MEDIA_REMOVAL: {
260 PREVENT_MEDIA_REMOVAL *PreventMediaRemoval;
262 /* FIXME: ntfs.sys calls this function with empty buffer; dunno what it means.
264 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength==0) {
265 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: IOCTL_DISK_MEDIA_REMOVAL with empty buffer",G_STRLOC);
266 Irp->IoStatus.Information=0;
267 Irp->IoStatus.Status=STATUS_SUCCESS;
270 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(PREVENT_MEDIA_REMOVAL)) {
271 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
272 Irp->IoStatus.Information=sizeof(PREVENT_MEDIA_REMOVAL);
273 g_assert_not_reached();
276 PreventMediaRemoval=(PREVENT_MEDIA_REMOVAL *)Irp->AssociatedIrp.SystemBuffer;
277 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: IOCTL_DISK_MEDIA_REMOVAL now %s",
278 G_STRLOC,(PreventMediaRemoval->PreventMediaRemoval ? "TRUE" : "FALSE"));
280 Irp->IoStatus.Information=sizeof(PREVENT_MEDIA_REMOVAL);
281 Irp->IoStatus.Status=STATUS_SUCCESS;
284 case IOCTL_DISK_CONTROLLER_NUMBER: {
285 DISK_CONTROLLER_NUMBER *DiskControllerNumber;
287 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(DISK_CONTROLLER_NUMBER)) {
288 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
289 Irp->IoStatus.Information=sizeof(DISK_CONTROLLER_NUMBER);
290 g_assert_not_reached();
293 DiskControllerNumber=(DISK_CONTROLLER_NUMBER *)Irp->AssociatedIrp.SystemBuffer;
294 DiskControllerNumber->ControllerNumber=0; /* FIXME: based on 0 or 1? */
295 DiskControllerNumber->DiskNumber=0; /* FIXME: based on 0 or 1? */
297 Irp->IoStatus.Information=sizeof(DISK_CONTROLLER_NUMBER);
298 Irp->IoStatus.Status=STATUS_SUCCESS;
301 case IOCTL_DISK_GET_LENGTH_INFO: {
302 GET_LENGTH_INFORMATION *GetLengthInformation;
304 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(GET_LENGTH_INFORMATION)) {
305 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
306 Irp->IoStatus.Information=sizeof(GET_LENGTH_INFORMATION);
307 g_assert_not_reached();
310 GetLengthInformation=(GET_LENGTH_INFORMATION *)Irp->AssociatedIrp.SystemBuffer;
311 GetLengthInformation->Length.QuadPart=captive_image_size;
313 Irp->IoStatus.Information=sizeof(GET_LENGTH_INFORMATION);
314 Irp->IoStatus.Status=STATUS_SUCCESS;
318 g_error("%s: Invalid media IOCTL 0x%08lx - by NtfsFixDataError()",G_STRLOC,
319 (unsigned long)IrpStack->Parameters.DeviceIoControl.IoControlCode);
323 g_error("%s: Invalid media IOCTL 0x%08lX",G_STRLOC,
324 (unsigned long)IrpStack->Parameters.DeviceIoControl.IoControlCode);
325 Irp->IoStatus.Status=STATUS_INVALID_DEVICE_REQUEST;
326 g_assert_not_reached();
331 done: /* 'err:' but we flow here even during success */
332 return MajorFunction_Irp_finish(DeviceObject,Irp);
336 struct MajorFunction_READ_WRITE_func_Parameters {
339 LARGE_INTEGER ByteOffset;
342 /* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
343 * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
345 #define MajorFunction_READ_WRITE ((PDRIVER_DISPATCH)MajorFunction_READ_WRITE_func)
346 static NTSTATUS CAPTIVE_STDCALL MajorFunction_READ_WRITE_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
348 IO_STACK_LOCATION *IrpStack;
349 gpointer buffer=NULL;
350 GIOStatus erriostatus;
351 struct captive_DriverObject *captive_DriverObject;
352 const struct MajorFunction_READ_WRITE_func_Parameters *Parameters=NULL; /* Prevent: `Parameters' might be used uninitialized */
354 g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
355 g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
357 captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
359 Irp->IoStatus.Information=0; /* request-specific, may get overriden later */
360 IrpStack=IoGetCurrentIrpStackLocation(Irp);
361 g_assert(IrpStack->MajorFunction==IRP_MJ_READ || IrpStack->MajorFunction==IRP_MJ_WRITE);
362 g_assert(IrpStack->MinorFunction==0);
364 #define READ_WRITE_ASSERT_PARAMETERS_OFFSET(struct_a,struct_b,member) \
365 g_assert(G_STRUCT_OFFSET(typeof(IrpStack->Parameters.struct_a),member) \
366 ==G_STRUCT_OFFSET(typeof(IrpStack->Parameters.struct_b),member))
367 READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,Length);
368 READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,Key);
369 READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,ByteOffset);
370 READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,ByteOffset.QuadPart);
371 #undef READ_WRITE_ASSERT_PARAMETERS_OFFSET
373 switch (IrpStack->MajorFunction) {
374 case IRP_MJ_READ: Parameters=(const struct MajorFunction_READ_WRITE_func_Parameters *)&IrpStack->Parameters.Read; break;
375 case IRP_MJ_WRITE: Parameters=(const struct MajorFunction_READ_WRITE_func_Parameters *)&IrpStack->Parameters.Write; break;
376 default: g_assert_not_reached();
379 /* Autodetect 'buffer' as we are !DO_BUFFERED_IO && !DO_DIRECT_IO hybrid */
380 if (Irp->UserBuffer) {
381 g_assert(buffer==NULL);
382 buffer=Irp->UserBuffer;
384 /* Forbid both IRP_BUFFERED_IO and IRP_ASSOCIATED_IRP as it should be IMO invalid state. */
385 g_assert(!((Irp->Flags & IRP_BUFFERED_IO) && (Irp->Flags & IRP_ASSOCIATED_IRP)));
386 if (Irp->Flags & IRP_BUFFERED_IO && Irp->AssociatedIrp.SystemBuffer) {
387 g_assert(buffer==NULL);
388 buffer=Irp->AssociatedIrp.SystemBuffer;
390 if (Irp->MdlAddress) {
391 /* See comment at ntoskrnl/io/buildirp.c/IoBuildSynchronousFsdRequestWithMdl()
392 * initialization of 'Irp->UserBuffer'.
394 g_assert(buffer==MmGetSystemAddressForMdl(Irp->MdlAddress) || buffer==NULL);
395 g_assert(Parameters->Length<=MmGetMdlByteCount(Irp->MdlAddress));
396 buffer=MmGetSystemAddressForMdl(Irp->MdlAddress);
398 g_assert(buffer!=NULL);
400 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: %s: ByteOffset=0x%llX,Length=0x%lX",
401 G_STRLOC,(IrpStack->MajorFunction==IRP_MJ_READ ? "IRP_MJ_READ" : "IRP_MJ_WRITE"),
402 (guint64)Parameters->ByteOffset.QuadPart,(gulong)Parameters->Length);
404 erriostatus=g_io_channel_seek_position(captive_image_iochannel,
405 Parameters->ByteOffset.QuadPart, /* offset */
406 G_SEEK_SET, /* type */
408 g_assert(erriostatus==G_IO_STATUS_NORMAL);
410 switch (IrpStack->MajorFunction) {
414 erriostatus=g_io_channel_read_chars(captive_image_iochannel,
416 Parameters->Length, /* count */
417 &bytesread, /* bytesread */
419 g_assert(erriostatus==G_IO_STATUS_NORMAL);
420 g_assert(bytesread==Parameters->Length);
426 erriostatus=g_io_channel_write_chars(captive_image_iochannel,
428 Parameters->Length, /* count */
429 &byteswritten, /* byteswritten */
431 g_assert(erriostatus==G_IO_STATUS_NORMAL);
432 g_assert(byteswritten==Parameters->Length);
435 default: g_assert_not_reached();
438 Irp->IoStatus.Information=Parameters->Length;
439 Irp->IoStatus.Status=STATUS_SUCCESS;
442 /* done: */ /* 'err:' but we flow here even during success */
443 return MajorFunction_Irp_finish(DeviceObject,Irp);
447 /* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
448 * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
450 #define MajorFunction_SHUTDOWN ((PDRIVER_DISPATCH)MajorFunction_SHUTDOWN_func)
451 static NTSTATUS CAPTIVE_STDCALL MajorFunction_SHUTDOWN_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
453 IO_STACK_LOCATION *IrpStack;
454 GIOStatus erriostatus;
455 struct captive_DriverObject *captive_DriverObject;
457 g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
458 g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
460 captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
462 IrpStack=IoGetCurrentIrpStackLocation(Irp);
463 g_assert(IrpStack->MajorFunction==IRP_MJ_SHUTDOWN || IrpStack->MajorFunction==IRP_MJ_FLUSH_BUFFERS);
464 g_assert(IrpStack->MinorFunction==0);
466 /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
467 erriostatus=g_io_channel_flush(
468 captive_image_iochannel, /* channel */
470 g_assert(erriostatus==G_IO_STATUS_NORMAL);
472 Irp->IoStatus.Information=0;
473 Irp->IoStatus.Status=STATUS_SUCCESS;
475 return MajorFunction_Irp_finish(DeviceObject,Irp);
479 /* FLUSH_BUFFERS has exactly the functionality for us. */
480 #define MajorFunction_FLUSH_BUFFERS MajorFunction_SHUTDOWN
483 /* similiar to drivers/storage/cdrom/cdrom.c/DriverEntry()->...
484 * ...->CdromClassCreateDeviceObject()->
485 * ->reactos/drivers/storage/class2/class2.c/ScsiClassCreateDeviceObject()
486 * We should be driving a lower layer PortDevice but currently we
487 * do not provide it, I hope W32 filesystems don't touch it.
489 NTSTATUS captive_media_DriverEntry(struct captive_DriverObject *captive_DriverObject,PUNICODE_STRING RegistryPath)
491 DRIVER_OBJECT *DriverObject;
492 DEVICE_OBJECT *DeviceObject;
493 DEVICE_EXTENSION *DeviceExtension;
496 g_return_val_if_fail(captive_DriverObject!=NULL,STATUS_INVALID_PARAMETER);
497 g_return_val_if_fail(RegistryPath!=NULL,STATUS_INVALID_PARAMETER);
499 DriverObject=(DRIVER_OBJECT *)captive_DriverObject;
502 DriverObject, /* DriverObject */
503 sizeof(DEVICE_EXTENSION), /* DeviceExtensionSize; additional storage not used */
504 captive_utf8_to_UnicodeString_alloca(captive_DriverObject->DeviceName_utf8), /* DeviceName */
505 captive_DriverObject->DeviceType, /* DeviceType */
506 captive_DriverObject->DeviceCharacteristics, /* DeviceCharacteristics */
507 FALSE, /* Exclusive */
508 &DeviceObject); /* DeviceObject */
509 g_return_val_if_fail(NT_SUCCESS(err),FALSE);
511 /* Currently we are !DO_BUFFERED_IO && !DO_DIRECT_IO and we must solve
512 * being called with 'Irp->UserBuffer', 'Irp->AssociatedIrp.SystemBuffer' or 'Irp->MdlAddress'.
514 /* should be left from IoCreateDevice(DeviceCharacteristics) above: */
515 if (captive_DriverObject->DeviceCharacteristics & FILE_REMOVABLE_MEDIA)
516 g_assert(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
517 /* ignored: DeviceObject->StackSize */
518 /* ignored: DeviceObject->AlignmentRequirement */
520 /* from reactos/drivers/storage/scsiport/scsiport.c/ScsiPortCreatePortDevice() */
521 captive_DriverObject->PortCapabilities.Length=sizeof(captive_DriverObject->PortCapabilities);
522 captive_DriverObject->PortCapabilities.MaximumTransferLength=0x10000; /* 64KB */
523 g_assert((captive_DriverObject->PortCapabilities.MaximumTransferLength%PAGE_SIZE)==0);
524 captive_DriverObject->PortCapabilities.MaximumPhysicalPages=captive_DriverObject->PortCapabilities.MaximumTransferLength/PAGE_SIZE;
525 captive_DriverObject->PortCapabilities.SupportedAsynchronousEvents=0;
526 captive_DriverObject->PortCapabilities.AlignmentMask=1; /* no alignment required by us; speced as "integer multiple" */
527 captive_DriverObject->PortCapabilities.TaggedQueuing=FALSE;
528 captive_DriverObject->PortCapabilities.AdapterScansDown=FALSE;
529 captive_DriverObject->PortCapabilities.AdapterUsesPio=TRUE;
530 captive_DriverObject->PortCapabilities_check=captive_DriverObject->PortCapabilities; /* for g_assert() checking against foreign modifications */
532 DeviceExtension=DeviceObject->DeviceExtension;
533 DeviceExtension->MediaChangeCount=0;
534 DeviceExtension->PhysicalDevice=DeviceObject; /* no real PhysicalDeviceObject */
535 DeviceExtension->LockCount=0;
536 DeviceExtension->DeviceNumber=0; /* corresponds to the # in "\\Device\\CdRom0" */
537 /* ignored DeviceExtension->PortDeviceObject
538 * as we are the final driver and we don't have any PortDeviceObject
540 DeviceExtension->PortCapabilities=&captive_DriverObject->PortCapabilities;
541 DeviceExtension->StartingOffset.QuadPart=0;
542 DeviceExtension->PartitionLength.QuadPart=captive_image_size;
543 DeviceExtension->PortNumber=0;
544 DeviceExtension->PathId=0;
545 DeviceExtension->TargetId=0;
546 DeviceExtension->Lun=0;
548 /* expect 'captive_DriverObject->DiskGeometry.MediaType' */
549 captive_DriverObject->DiskGeometry.TracksPerCylinder=64;
550 captive_DriverObject->DiskGeometry.SectorsPerTrack=32;
551 /* expect 'captive_DriverObject->DiskGeometry.BytesPerSector' */
552 captive_DriverObject->DiskGeometry.Cylinders.QuadPart=captive_image_size
553 /captive_DriverObject->DiskGeometry.BytesPerSector
554 /captive_DriverObject->DiskGeometry.SectorsPerTrack
555 /captive_DriverObject->DiskGeometry.TracksPerCylinder;
556 /* 'DeviceExtension->DiskGeometry' is NULL! */
557 captive_DriverObject->DiskGeometry_check=captive_DriverObject->DiskGeometry; /* for g_assert() checking against foreign modifications */
558 DeviceExtension->DiskGeometry=&captive_DriverObject->DiskGeometry;
560 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=MajorFunction_DEVICE_CONTROL;
561 DriverObject->MajorFunction[IRP_MJ_READ ]=MajorFunction_READ_WRITE;
562 DriverObject->MajorFunction[IRP_MJ_WRITE ]=MajorFunction_READ_WRITE;
563 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN ]=MajorFunction_SHUTDOWN;
564 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS ]=MajorFunction_FLUSH_BUFFERS;
566 return STATUS_SUCCESS;