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