xref: /reactos/drivers/storage/floppy/fdc/fdo.c (revision 4f410007)
1 /*
2  * PROJECT:        ReactOS Floppy Disk Controller Driver
3  * LICENSE:        GNU GPLv2 only as published by the Free Software Foundation
4  * FILE:           drivers/storage/fdc/fdc/fdo.c
5  * PURPOSE:        Functional Device Object routines
6  * PROGRAMMERS:    Eric Kohl
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "fdc.h"
12 
13 #include <stdio.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* FUNCTIONS ******************************************************************/
18 
19 NTSTATUS
20 NTAPI
ForwardIrpAndForget(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)21 ForwardIrpAndForget(
22     IN PDEVICE_OBJECT DeviceObject,
23     IN PIRP Irp)
24 {
25     PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
26 
27     ASSERT(LowerDevice);
28 
29     IoSkipCurrentIrpStackLocation(Irp);
30     return IoCallDriver(LowerDevice, Irp);
31 }
32 
33 
34 static
35 NTSTATUS
FdcFdoStartDevice(IN PDEVICE_OBJECT DeviceObject,IN PCM_RESOURCE_LIST ResourceList,IN PCM_RESOURCE_LIST ResourceListTranslated)36 FdcFdoStartDevice(
37     IN PDEVICE_OBJECT DeviceObject,
38     IN PCM_RESOURCE_LIST ResourceList,
39     IN PCM_RESOURCE_LIST ResourceListTranslated)
40 {
41     PFDO_DEVICE_EXTENSION DeviceExtension;
42     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
43 //    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
44     ULONG i;
45 
46     DPRINT("FdcFdoStartDevice called\n");
47 
48     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
49 
50     ASSERT(DeviceExtension);
51 
52     if (ResourceList == NULL ||
53         ResourceListTranslated == NULL)
54     {
55         DPRINT1("No allocated resources sent to driver\n");
56         return STATUS_INSUFFICIENT_RESOURCES;
57     }
58 
59     if (ResourceList->Count != 1)
60     {
61         DPRINT1("Wrong number of allocated resources sent to driver\n");
62         return STATUS_INSUFFICIENT_RESOURCES;
63     }
64 
65     if (ResourceList->List[0].PartialResourceList.Version != 1 ||
66         ResourceList->List[0].PartialResourceList.Revision != 1 ||
67         ResourceListTranslated->List[0].PartialResourceList.Version != 1 ||
68         ResourceListTranslated->List[0].PartialResourceList.Revision != 1)
69     {
70         DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
71                 ResourceList->List[0].PartialResourceList.Version,
72                 ResourceList->List[0].PartialResourceList.Revision,
73                 ResourceListTranslated->List[0].PartialResourceList.Version,
74                 ResourceListTranslated->List[0].PartialResourceList.Revision);
75         return STATUS_REVISION_MISMATCH;
76     }
77 
78     for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
79     {
80         PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
81 //        PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
82 
83         switch (PartialDescriptor->Type)
84         {
85             case CmResourceTypePort:
86                 DPRINT("Port: 0x%lx (%lu)\n",
87                         PartialDescriptor->u.Port.Start.u.LowPart,
88                         PartialDescriptor->u.Port.Length);
89                 if (PartialDescriptor->u.Port.Length >= 6)
90                     DeviceExtension->ControllerInfo.BaseAddress = (PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart;
91                 break;
92 
93             case CmResourceTypeInterrupt:
94                 DPRINT("Interrupt: Level %lu  Vector %lu\n",
95                         PartialDescriptor->u.Interrupt.Level,
96                         PartialDescriptor->u.Interrupt.Vector);
97 /*
98                 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
99                 Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
100                 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
101                 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
102                     InterruptMode = Latched;
103                 else
104                     InterruptMode = LevelSensitive;
105                 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
106 */
107                 break;
108 
109             case CmResourceTypeDma:
110                 DPRINT("Dma: Channel %lu\n",
111                         PartialDescriptor->u.Dma.Channel);
112                 break;
113         }
114     }
115 
116     return STATUS_SUCCESS;
117 }
118 
119 
120 static
121 NTSTATUS
122 NTAPI
FdcFdoConfigCallback(PVOID Context,PUNICODE_STRING PathName,INTERFACE_TYPE BusType,ULONG BusNumber,PKEY_VALUE_FULL_INFORMATION * BusInformation,CONFIGURATION_TYPE ControllerType,ULONG ControllerNumber,PKEY_VALUE_FULL_INFORMATION * ControllerInformation,CONFIGURATION_TYPE PeripheralType,ULONG PeripheralNumber,PKEY_VALUE_FULL_INFORMATION * PeripheralInformation)123 FdcFdoConfigCallback(
124     PVOID Context,
125     PUNICODE_STRING PathName,
126     INTERFACE_TYPE BusType,
127     ULONG BusNumber,
128     PKEY_VALUE_FULL_INFORMATION *BusInformation,
129     CONFIGURATION_TYPE ControllerType,
130     ULONG ControllerNumber,
131     PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
132     CONFIGURATION_TYPE PeripheralType,
133     ULONG PeripheralNumber,
134     PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
135 {
136     PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor;
137     PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor;
138     PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor;
139     PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor;
140     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
141     PCM_FLOPPY_DEVICE_DATA FloppyDeviceData;
142     PFDO_DEVICE_EXTENSION DeviceExtension;
143     PDRIVE_INFO DriveInfo;
144     BOOLEAN ControllerFound = FALSE;
145     ULONG i;
146 
147     DPRINT("FdcFdoConfigCallback() called\n");
148 
149     DeviceExtension = (PFDO_DEVICE_EXTENSION)Context;
150 
151     /* Get the controller resources */
152     ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData];
153     ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor +
154                                                                   ControllerFullDescriptor->DataOffset);
155 
156     for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++)
157     {
158         PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i];
159 
160         if (PartialDescriptor->Type == CmResourceTypePort)
161         {
162             if ((PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart == DeviceExtension->ControllerInfo.BaseAddress)
163                 ControllerFound = TRUE;
164         }
165     }
166 
167     /* Leave, if the enumerated controller is not the one represented by the FDO */
168     if (ControllerFound == FALSE)
169         return STATUS_SUCCESS;
170 
171     /* Get the peripheral resources */
172     PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData];
173     PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor +
174                                                                   PeripheralFullDescriptor->DataOffset);
175 
176     /* learn about drives attached to controller */
177     for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++)
178     {
179         PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i];
180 
181         if (PartialDescriptor->Type != CmResourceTypeDeviceSpecific)
182             continue;
183 
184         FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1);
185 
186         DriveInfo = &DeviceExtension->ControllerInfo.DriveInfo[DeviceExtension->ControllerInfo.NumberOfDrives];
187 
188         DriveInfo->ControllerInfo = &DeviceExtension->ControllerInfo;
189         DriveInfo->UnitNumber = DeviceExtension->ControllerInfo.NumberOfDrives;
190         DriveInfo->PeripheralNumber = PeripheralNumber;
191 
192         DriveInfo->FloppyDeviceData.MaxDensity = FloppyDeviceData->MaxDensity;
193         DriveInfo->FloppyDeviceData.MountDensity = FloppyDeviceData->MountDensity;
194         DriveInfo->FloppyDeviceData.StepRateHeadUnloadTime = FloppyDeviceData->StepRateHeadUnloadTime;
195         DriveInfo->FloppyDeviceData.HeadLoadTime = FloppyDeviceData->HeadLoadTime;
196         DriveInfo->FloppyDeviceData.MotorOffTime = FloppyDeviceData->MotorOffTime;
197         DriveInfo->FloppyDeviceData.SectorLengthCode = FloppyDeviceData->SectorLengthCode;
198         DriveInfo->FloppyDeviceData.SectorPerTrack = FloppyDeviceData->SectorPerTrack;
199         DriveInfo->FloppyDeviceData.ReadWriteGapLength = FloppyDeviceData->ReadWriteGapLength;
200         DriveInfo->FloppyDeviceData.FormatGapLength = FloppyDeviceData->FormatGapLength;
201         DriveInfo->FloppyDeviceData.FormatFillCharacter = FloppyDeviceData->FormatFillCharacter;
202         DriveInfo->FloppyDeviceData.HeadSettleTime = FloppyDeviceData->HeadSettleTime;
203         DriveInfo->FloppyDeviceData.MotorSettleTime = FloppyDeviceData->MotorSettleTime;
204         DriveInfo->FloppyDeviceData.MaximumTrackValue = FloppyDeviceData->MaximumTrackValue;
205         DriveInfo->FloppyDeviceData.DataTransferLength = FloppyDeviceData->DataTransferLength;
206 
207         /* Once it's all set up, acknowledge its existence in the controller info object */
208         DeviceExtension->ControllerInfo.NumberOfDrives++;
209     }
210 
211     DeviceExtension->ControllerInfo.Populated = TRUE;
212 
213     DPRINT("Detected %lu floppy drives!\n",
214             DeviceExtension->ControllerInfo.NumberOfDrives);
215 
216     return STATUS_SUCCESS;
217 }
218 
219 
220 static
221 NTSTATUS
PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs)222 PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs)
223 {
224     WCHAR Buffer[256];
225     UNICODE_STRING BufferU;
226     ULONG Index;
227 
228     Index = 0;
229     Index += swprintf(&Buffer[Index],
230                       L"FDC\\GENERIC_FLOPPY_DRIVE");
231     Index++;
232 
233     Buffer[Index] = UNICODE_NULL;
234 
235     BufferU.Length = BufferU.MaximumLength = (USHORT) Index * sizeof(WCHAR);
236     BufferU.Buffer = Buffer;
237 
238     return DuplicateUnicodeString(0, &BufferU, HardwareIDs);
239 }
240 
241 
242 static
243 NTSTATUS
PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs)244 PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs)
245 {
246     WCHAR Buffer[256];
247     UNICODE_STRING BufferU;
248     ULONG Index;
249 
250     Index = 0;
251     Index += swprintf(&Buffer[Index],
252                       L"GenFloppyDisk");
253     Index++;
254 
255     Buffer[Index] = UNICODE_NULL;
256 
257     BufferU.Length = BufferU.MaximumLength = (USHORT)Index * sizeof(WCHAR);
258     BufferU.Buffer = Buffer;
259 
260     return DuplicateUnicodeString(0, &BufferU, CompatibleIDs);
261 }
262 
263 
264 static
265 NTSTATUS
PciCreateInstanceIDString(PUNICODE_STRING InstanceID,ULONG PeripheralNumber)266 PciCreateInstanceIDString(PUNICODE_STRING InstanceID,
267                           ULONG PeripheralNumber)
268 {
269     WCHAR Buffer[3];
270 
271     swprintf(Buffer, L"%02X", PeripheralNumber & 0xff);
272 
273     return RtlCreateUnicodeString(InstanceID, Buffer) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
274 }
275 
276 
277 static
278 NTSTATUS
FdcFdoQueryBusRelations(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_RELATIONS * DeviceRelations)279 FdcFdoQueryBusRelations(
280     IN PDEVICE_OBJECT DeviceObject,
281     OUT PDEVICE_RELATIONS *DeviceRelations)
282 {
283     PFDO_DEVICE_EXTENSION FdoDeviceExtension;
284     PPDO_DEVICE_EXTENSION PdoDeviceExtension;
285     INTERFACE_TYPE InterfaceType = Isa;
286     CONFIGURATION_TYPE ControllerType = DiskController;
287     CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral;
288     PDEVICE_RELATIONS Relations;
289     PDRIVE_INFO DriveInfo;
290     PDEVICE_OBJECT Pdo;
291     WCHAR DeviceNameBuffer[80];
292     UNICODE_STRING DeviceName;
293     ULONG DeviceNumber = 0;
294     ULONG Size;
295     ULONG i;
296     NTSTATUS Status;
297 
298     DPRINT("FdcFdoQueryBusRelations() called\n");
299 
300     FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
301 
302     Status = IoQueryDeviceDescription(&InterfaceType,
303                                       NULL,
304                                       &ControllerType,
305                                       NULL,
306                                       &PeripheralType,
307                                       NULL,
308                                       FdcFdoConfigCallback,
309                                       FdoDeviceExtension);
310     if (!NT_SUCCESS(Status) && (Status != STATUS_NO_MORE_ENTRIES))
311         return Status;
312 
313     Size = sizeof(DEVICE_RELATIONS) +
314            sizeof(Relations->Objects) * (FdoDeviceExtension->ControllerInfo.NumberOfDrives - 1);
315     Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
316     if (Relations == NULL)
317     {
318         return STATUS_INSUFFICIENT_RESOURCES;
319     }
320 
321     Relations->Count = FdoDeviceExtension->ControllerInfo.NumberOfDrives;
322 
323     for (i = 0; i < FdoDeviceExtension->ControllerInfo.NumberOfDrives; i++)
324     {
325         DriveInfo = &FdoDeviceExtension->ControllerInfo.DriveInfo[i];
326 
327         if (DriveInfo->DeviceObject == NULL)
328         {
329             do
330             {
331                 swprintf(DeviceNameBuffer, L"\\Device\\FloppyPDO%lu", DeviceNumber++);
332                 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
333                 DPRINT("Device name: %S\n", DeviceNameBuffer);
334 
335                 /* Create physical device object */
336                 Status = IoCreateDevice(FdoDeviceExtension->Common.DeviceObject->DriverObject,
337                                         sizeof(PDO_DEVICE_EXTENSION),
338                                         &DeviceName,
339                                         FILE_DEVICE_MASS_STORAGE,
340                                         FILE_DEVICE_SECURE_OPEN,
341                                         FALSE,
342                                         &Pdo);
343             }
344             while (Status == STATUS_OBJECT_NAME_COLLISION);
345 
346             if (!NT_SUCCESS(Status))
347             {
348                 DPRINT1("PDO creation failed (Status 0x%08lx)\n", Status);
349                 goto done;
350             }
351 
352             DPRINT("PDO created: %S\n", DeviceNameBuffer);
353 
354             DriveInfo->DeviceObject = Pdo;
355 
356             PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
357             RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
358 
359             PdoDeviceExtension->Common.IsFDO = FALSE;
360             PdoDeviceExtension->Common.DeviceObject = Pdo;
361 
362             PdoDeviceExtension->Fdo = FdoDeviceExtension->Common.DeviceObject;
363             PdoDeviceExtension->DriveInfo = DriveInfo;
364 
365             Pdo->Flags |= DO_DIRECT_IO;
366             Pdo->Flags |= DO_POWER_PAGABLE;
367             Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
368 
369             /* Add Device ID string */
370             RtlCreateUnicodeString(&PdoDeviceExtension->DeviceId,
371                                    L"FDC\\GENERIC_FLOPPY_DRIVE");
372             DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceId.Buffer);
373 
374             /* Add Hardware IDs string */
375             Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIds);
376             if (!NT_SUCCESS(Status))
377             {
378 //                ErrorStatus = Status;
379 //                ErrorOccurred = TRUE;
380                 break;
381             }
382 
383             /* Add Compatible IDs string */
384             Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIds);
385             if (!NT_SUCCESS(Status))
386             {
387 //                ErrorStatus = Status;
388 //                ErrorOccurred = TRUE;
389                 break;
390             }
391 
392             /* Add Instance ID string */
393             Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceId,
394                                                DriveInfo->PeripheralNumber);
395             if (!NT_SUCCESS(Status))
396             {
397 //                ErrorStatus = Status;
398 //                ErrorOccurred = TRUE;
399                 break;
400             }
401 
402 #if 0
403              /* Add device description string */
404             Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device);
405             if (!NT_SUCCESS(Status))
406             {
407 //                ErrorStatus = Status;
408 //                ErrorOccurred = TRUE;
409                 break;
410             }
411 
412             /* Add device location string */
413             Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device);
414             if (!NT_SUCCESS(Status))
415             {
416 //                ErrorStatus = Status;
417 //                ErrorOccurred = TRUE;
418                 break;
419             }
420 #endif
421         }
422 
423         ObReferenceObject(DriveInfo->DeviceObject);
424         Relations->Objects[i] = DriveInfo->DeviceObject;
425     }
426 
427 done:
428     if (NT_SUCCESS(Status))
429     {
430         *DeviceRelations = Relations;
431     }
432     else
433     {
434         if (Relations != NULL)
435             ExFreePool(Relations);
436     }
437 
438     return Status;
439 }
440 
441 
442 NTSTATUS
443 NTAPI
FdcFdoPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)444 FdcFdoPnp(
445     IN PDEVICE_OBJECT DeviceObject,
446     IN PIRP Irp)
447 {
448     PFDO_DEVICE_EXTENSION FdoExtension;
449     PIO_STACK_LOCATION IrpSp;
450     PDEVICE_RELATIONS DeviceRelations = NULL;
451     ULONG_PTR Information = 0;
452     NTSTATUS Status = STATUS_NOT_SUPPORTED;
453 
454     DPRINT("FdcFdoPnp()\n");
455 
456     IrpSp = IoGetCurrentIrpStackLocation(Irp);
457 
458     switch (IrpSp->MinorFunction)
459     {
460         case IRP_MN_START_DEVICE:
461             DPRINT("  IRP_MN_START_DEVICE received\n");
462 
463             /* Call lower driver */
464             Status = STATUS_UNSUCCESSFUL;
465             FdoExtension = DeviceObject->DeviceExtension;
466 
467             if (IoForwardIrpSynchronously(FdoExtension->LowerDevice, Irp))
468             {
469                 Status = Irp->IoStatus.Status;
470                 if (NT_SUCCESS(Status))
471                 {
472                     Status = FdcFdoStartDevice(DeviceObject,
473                         IrpSp->Parameters.StartDevice.AllocatedResources,
474                         IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated);
475                 }
476             }
477 
478             break;
479 
480         case IRP_MN_QUERY_REMOVE_DEVICE:
481             DPRINT("  IRP_MN_QUERY_REMOVE_DEVICE\n");
482             break;
483 
484         case IRP_MN_REMOVE_DEVICE:
485             DPRINT("  IRP_MN_REMOVE_DEVICE received\n");
486             break;
487 
488         case IRP_MN_CANCEL_REMOVE_DEVICE:
489             DPRINT("  IRP_MN_CANCEL_REMOVE_DEVICE\n");
490             break;
491 
492         case IRP_MN_STOP_DEVICE:
493             DPRINT("  IRP_MN_STOP_DEVICE received\n");
494             break;
495 
496         case IRP_MN_QUERY_STOP_DEVICE:
497             DPRINT("  IRP_MN_QUERY_STOP_DEVICE received\n");
498             break;
499 
500         case IRP_MN_CANCEL_STOP_DEVICE:
501             DPRINT("  IRP_MN_CANCEL_STOP_DEVICE\n");
502             break;
503 
504         case IRP_MN_QUERY_DEVICE_RELATIONS:
505             DPRINT("  IRP_MN_QUERY_DEVICE_RELATIONS\n");
506 
507             switch (IrpSp->Parameters.QueryDeviceRelations.Type)
508             {
509                 case BusRelations:
510                     DPRINT("    IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
511                     Status = FdcFdoQueryBusRelations(DeviceObject, &DeviceRelations);
512                     Information = (ULONG_PTR)DeviceRelations;
513                     break;
514 
515                 case RemovalRelations:
516                     DPRINT("    IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
517                     return ForwardIrpAndForget(DeviceObject, Irp);
518 
519                 default:
520                     DPRINT("    IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
521                             IrpSp->Parameters.QueryDeviceRelations.Type);
522                     return ForwardIrpAndForget(DeviceObject, Irp);
523             }
524             break;
525 
526         case IRP_MN_SURPRISE_REMOVAL:
527             DPRINT("  IRP_MN_SURPRISE_REMOVAL received\n");
528             break;
529 
530         default:
531             DPRINT("  Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
532             return ForwardIrpAndForget(DeviceObject, Irp);
533     }
534 
535     Irp->IoStatus.Information = Information;
536     Irp->IoStatus.Status = Status;
537     IoCompleteRequest(Irp, IO_NO_INCREMENT);
538 
539     return Status;
540 }
541 
542 /* EOF */
543