xref: /reactos/drivers/storage/port/storport/fdo.c (revision 7ed1883c)
1 /*
2  * PROJECT:     ReactOS Storport Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Storport FDO code
5  * COPYRIGHT:   Copyright 2017 Eric Kohl (eric.kohl@reactos.org)
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include "precomp.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 
16 /* FUNCTIONS ******************************************************************/
17 
18 static
19 BOOLEAN
20 NTAPI
PortFdoInterruptRoutine(_In_ PKINTERRUPT Interrupt,_In_ PVOID ServiceContext)21 PortFdoInterruptRoutine(
22     _In_ PKINTERRUPT Interrupt,
23     _In_ PVOID ServiceContext)
24 {
25     PFDO_DEVICE_EXTENSION DeviceExtension;
26 
27     DPRINT1("PortFdoInterruptRoutine(%p %p)\n",
28             Interrupt, ServiceContext);
29 
30     DeviceExtension = (PFDO_DEVICE_EXTENSION)ServiceContext;
31 
32     return MiniportHwInterrupt(&DeviceExtension->Miniport);
33 }
34 
35 
36 static
37 NTSTATUS
PortFdoConnectInterrupt(_In_ PFDO_DEVICE_EXTENSION DeviceExtension)38 PortFdoConnectInterrupt(
39     _In_ PFDO_DEVICE_EXTENSION DeviceExtension)
40 {
41     ULONG Vector;
42     KIRQL Irql;
43     KINTERRUPT_MODE InterruptMode;
44     BOOLEAN ShareVector;
45     KAFFINITY Affinity;
46     NTSTATUS Status;
47 
48     DPRINT1("PortFdoConnectInterrupt(%p)\n",
49             DeviceExtension);
50 
51     /* No resources, no interrupt. Done! */
52     if (DeviceExtension->AllocatedResources == NULL ||
53         DeviceExtension->TranslatedResources == NULL)
54     {
55         DPRINT1("Checkpoint\n");
56         return STATUS_SUCCESS;
57     }
58 
59     /* Get the interrupt data from the resource list */
60     Status = GetResourceListInterrupt(DeviceExtension,
61                                       &Vector,
62                                       &Irql,
63                                       &InterruptMode,
64                                       &ShareVector,
65                                       &Affinity);
66     if (!NT_SUCCESS(Status))
67     {
68         DPRINT1("GetResourceListInterrupt() failed (Status 0x%08lx)\n", Status);
69         return Status;
70     }
71 
72     DPRINT1("Vector: %lu\n", Vector);
73     DPRINT1("Irql: %lu\n", Irql);
74 
75     DPRINT1("Affinity: 0x%08lx\n", Affinity);
76 
77     /* Connect the interrupt */
78     Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
79                                 PortFdoInterruptRoutine,
80                                 DeviceExtension,
81                                 NULL,
82                                 Vector,
83                                 Irql,
84                                 Irql,
85                                 InterruptMode,
86                                 ShareVector,
87                                 Affinity,
88                                 FALSE);
89     if (NT_SUCCESS(Status))
90     {
91         DeviceExtension->InterruptIrql = Irql;
92     }
93     else
94     {
95         DPRINT1("IoConnectInterrupt() failed (Status 0x%08lx)\n", Status);
96     }
97 
98     return Status;
99 }
100 
101 
102 static
103 NTSTATUS
PortFdoStartMiniport(_In_ PFDO_DEVICE_EXTENSION DeviceExtension)104 PortFdoStartMiniport(
105     _In_ PFDO_DEVICE_EXTENSION DeviceExtension)
106 {
107     PHW_INITIALIZATION_DATA InitData;
108     INTERFACE_TYPE InterfaceType;
109     NTSTATUS Status;
110 
111     DPRINT1("PortFdoStartDevice(%p)\n", DeviceExtension);
112 
113     /* Get the interface type of the lower device */
114     InterfaceType = GetBusInterface(DeviceExtension->LowerDevice);
115     if (InterfaceType == InterfaceTypeUndefined)
116         return STATUS_NO_SUCH_DEVICE;
117 
118     /* Get the driver init data for the given interface type */
119     InitData = PortGetDriverInitData(DeviceExtension->DriverExtension,
120                                      InterfaceType);
121     if (InitData == NULL)
122         return STATUS_NO_SUCH_DEVICE;
123 
124     /* Initialize the miniport */
125     Status = MiniportInitialize(&DeviceExtension->Miniport,
126                                 DeviceExtension,
127                                 InitData);
128     if (!NT_SUCCESS(Status))
129     {
130         DPRINT1("MiniportInitialize() failed (Status 0x%08lx)\n", Status);
131         return Status;
132     }
133 
134     /* Call the miniports FindAdapter function */
135     Status = MiniportFindAdapter(&DeviceExtension->Miniport);
136     if (!NT_SUCCESS(Status))
137     {
138         DPRINT1("MiniportFindAdapter() failed (Status 0x%08lx)\n", Status);
139         return Status;
140     }
141 
142     /* Connect the configured interrupt */
143     Status = PortFdoConnectInterrupt(DeviceExtension);
144     if (!NT_SUCCESS(Status))
145     {
146         DPRINT1("PortFdoConnectInterrupt() failed (Status 0x%08lx)\n", Status);
147         return Status;
148     }
149 
150     /* Call the miniports HwInitialize function */
151     Status = MiniportHwInitialize(&DeviceExtension->Miniport);
152     if (!NT_SUCCESS(Status))
153     {
154         DPRINT1("MiniportHwInitialize() failed (Status 0x%08lx)\n", Status);
155         return Status;
156     }
157 
158     /* Call the HwPassiveInitRoutine function, if available */
159     if (DeviceExtension->HwPassiveInitRoutine != NULL)
160     {
161         DPRINT1("Calling HwPassiveInitRoutine()\n");
162         if (!DeviceExtension->HwPassiveInitRoutine(&DeviceExtension->Miniport.MiniportExtension->HwDeviceExtension))
163         {
164             DPRINT1("HwPassiveInitRoutine() failed\n");
165             return STATUS_UNSUCCESSFUL;
166         }
167     }
168 
169     return STATUS_SUCCESS;
170 }
171 
172 
173 static
174 NTSTATUS
175 NTAPI
PortFdoStartDevice(_In_ PFDO_DEVICE_EXTENSION DeviceExtension,_In_ PIRP Irp)176 PortFdoStartDevice(
177     _In_ PFDO_DEVICE_EXTENSION DeviceExtension,
178     _In_ PIRP Irp)
179 {
180     PIO_STACK_LOCATION Stack;
181     NTSTATUS Status;
182 
183     DPRINT1("PortFdoStartDevice(%p %p)\n",
184             DeviceExtension, Irp);
185 
186     ASSERT(DeviceExtension->ExtensionType == FdoExtension);
187 
188     /* Get the current stack location */
189     Stack = IoGetCurrentIrpStackLocation(Irp);
190 
191     /* Start the lower device if the FDO is in 'stopped' state */
192     if (DeviceExtension->PnpState == dsStopped)
193     {
194         if (IoForwardIrpSynchronously(DeviceExtension->LowerDevice, Irp))
195         {
196             Status = Irp->IoStatus.Status;
197         }
198         else
199         {
200             Status = STATUS_UNSUCCESSFUL;
201         }
202 
203         if (!NT_SUCCESS(Status))
204         {
205             DPRINT1("Lower device failed the IRP (Status 0x%08lx)\n", Status);
206             return Status;
207         }
208     }
209 
210     /* Change to the 'started' state */
211     DeviceExtension->PnpState = dsStarted;
212 
213     /* Copy the raw and translated resource lists into the device extension */
214     if (Stack->Parameters.StartDevice.AllocatedResources != NULL &&
215         Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
216     {
217         DeviceExtension->AllocatedResources = CopyResourceList(NonPagedPool,
218                                                                Stack->Parameters.StartDevice.AllocatedResources);
219         if (DeviceExtension->AllocatedResources == NULL)
220             return STATUS_NO_MEMORY;
221 
222         DeviceExtension->TranslatedResources = CopyResourceList(NonPagedPool,
223                                                                 Stack->Parameters.StartDevice.AllocatedResourcesTranslated);
224         if (DeviceExtension->TranslatedResources == NULL)
225             return STATUS_NO_MEMORY;
226     }
227 
228     /* Get the bus interface of the lower (bus) device */
229     Status = QueryBusInterface(DeviceExtension->LowerDevice,
230                                (PGUID)&GUID_BUS_INTERFACE_STANDARD,
231                                sizeof(BUS_INTERFACE_STANDARD),
232                                1,
233                                &DeviceExtension->BusInterface,
234                                NULL);
235     DPRINT1("Status: 0x%08lx\n", Status);
236     if (NT_SUCCESS(Status))
237     {
238         DPRINT1("Context: %p\n", DeviceExtension->BusInterface.Context);
239         DeviceExtension->BusInitialized = TRUE;
240     }
241 
242     /* Start the miniport (FindAdapter & Initialize) */
243     Status = PortFdoStartMiniport(DeviceExtension);
244     if (!NT_SUCCESS(Status))
245     {
246         DPRINT1("FdoStartMiniport() failed (Status 0x%08lx)\n", Status);
247         DeviceExtension->PnpState = dsStopped;
248     }
249 
250     return Status;
251 }
252 
253 
254 static
255 NTSTATUS
PortSendInquiry(_In_ PPDO_DEVICE_EXTENSION PdoExtension)256 PortSendInquiry(
257     _In_ PPDO_DEVICE_EXTENSION PdoExtension)
258 {
259     IO_STATUS_BLOCK IoStatusBlock;
260     PIO_STACK_LOCATION IrpStack;
261     KEVENT Event;
262 //    KIRQL Irql;
263     PIRP Irp;
264     NTSTATUS Status;
265     PSENSE_DATA SenseBuffer;
266     BOOLEAN KeepTrying = TRUE;
267     ULONG RetryCount = 0;
268     SCSI_REQUEST_BLOCK Srb;
269     PCDB Cdb;
270 //    PSCSI_PORT_LUN_EXTENSION LunExtension;
271 //    PFDO_DEVICE_EXTENSION DeviceExtension;
272 
273     DPRINT("PortSendInquiry(%p)\n", PdoExtension);
274 
275     if (PdoExtension->InquiryBuffer == NULL)
276     {
277         PdoExtension->InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_INQUIRY_DATA);
278         if (PdoExtension->InquiryBuffer == NULL)
279             return STATUS_INSUFFICIENT_RESOURCES;
280     }
281 
282     SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SENSE_DATA);
283     if (SenseBuffer == NULL)
284     {
285         return STATUS_INSUFFICIENT_RESOURCES;
286     }
287 
288     while (KeepTrying)
289     {
290         /* Initialize event for waiting */
291         KeInitializeEvent(&Event,
292                           NotificationEvent,
293                           FALSE);
294 
295         /* Create an IRP */
296         Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
297                                             PdoExtension->Device,
298                                             NULL,
299                                             0,
300                                             PdoExtension->InquiryBuffer,
301                                             INQUIRYDATABUFFERSIZE,
302                                             TRUE,
303                                             &Event,
304                                             &IoStatusBlock);
305         if (Irp == NULL)
306         {
307             DPRINT("IoBuildDeviceIoControlRequest() failed\n");
308 
309             /* Quit the loop */
310             Status = STATUS_INSUFFICIENT_RESOURCES;
311             KeepTrying = FALSE;
312             continue;
313         }
314 
315         /* Prepare SRB */
316         RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
317 
318         Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
319         Srb.OriginalRequest = Irp;
320         Srb.PathId = PdoExtension->Bus;
321         Srb.TargetId = PdoExtension->Target;
322         Srb.Lun = PdoExtension->Lun;
323         Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
324         Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
325         Srb.TimeOutValue = 4;
326         Srb.CdbLength = 6;
327 
328         Srb.SenseInfoBuffer = SenseBuffer;
329         Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
330 
331         Srb.DataBuffer = PdoExtension->InquiryBuffer;
332         Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
333 
334         /* Attach Srb to the Irp */
335         IrpStack = IoGetNextIrpStackLocation(Irp);
336         IrpStack->Parameters.Scsi.Srb = &Srb;
337 
338         /* Fill in CDB */
339         Cdb = (PCDB)Srb.Cdb;
340         Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
341         Cdb->CDB6INQUIRY.LogicalUnitNumber = PdoExtension->Lun;
342         Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
343 
344         /* Call the driver */
345         Status = IoCallDriver(PdoExtension->Device, Irp);
346 
347         /* Wait for it to complete */
348         if (Status == STATUS_PENDING)
349         {
350             DPRINT1("PortSendInquiry(): Waiting for the driver to process request...\n");
351             KeWaitForSingleObject(&Event,
352                                   Executive,
353                                   KernelMode,
354                                   FALSE,
355                                   NULL);
356             Status = IoStatusBlock.Status;
357         }
358 
359         DPRINT("PortSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
360 
361         if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
362         {
363             DPRINT("Found a device!\n");
364 
365             /* Quit the loop */
366             Status = STATUS_SUCCESS;
367             KeepTrying = FALSE;
368             continue;
369         }
370 
371         DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
372 
373         /* Check if the queue is frozen */
374         if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
375         {
376             /* Something weird happened, deal with it (unfreeze the queue) */
377             KeepTrying = FALSE;
378 
379             DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
380 
381 //            LunExtension = SpiGetLunExtension(DeviceExtension,
382 //                                              LunInfo->PathId,
383 //                                              LunInfo->TargetId,
384 //                                              LunInfo->Lun);
385 
386             /* Clear frozen flag */
387 //            LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
388 
389             /* Acquire the spinlock */
390 //            KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
391 
392             /* Process the request */
393 //            SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
394 
395             /* SpiGetNextRequestFromLun() releases the spinlock,
396                 so we just lower irql back to what it was before */
397 //            KeLowerIrql(Irql);
398         }
399 
400         /* Check if data overrun happened */
401         if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
402         {
403             DPRINT("Data overrun at TargetId %d\n", PdoExtension->Target);
404 
405             /* Quit the loop */
406             Status = STATUS_SUCCESS;
407             KeepTrying = FALSE;
408         }
409         else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
410                  SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
411         {
412             /* LUN is not valid, but some device responds there.
413                 Mark it as invalid anyway */
414 
415             /* Quit the loop */
416             Status = STATUS_INVALID_DEVICE_REQUEST;
417             KeepTrying = FALSE;
418         }
419         else
420         {
421             /* Retry a couple of times if no timeout happened */
422             if ((RetryCount < 2) &&
423                 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
424                 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
425             {
426                 RetryCount++;
427                 KeepTrying = TRUE;
428             }
429             else
430             {
431                 /* That's all, quit the loop */
432                 KeepTrying = FALSE;
433 
434                 /* Set status according to SRB status */
435                 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
436                     SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
437                 {
438                     Status = STATUS_INVALID_DEVICE_REQUEST;
439                 }
440                 else
441                 {
442                     Status = STATUS_IO_DEVICE_ERROR;
443                 }
444             }
445         }
446     }
447 
448     /* Free the sense buffer */
449     ExFreePoolWithTag(SenseBuffer, TAG_SENSE_DATA);
450 
451     DPRINT("PortSendInquiry() done with Status 0x%08X\n", Status);
452 
453     return Status;
454 }
455 
456 
457 
458 static
459 NTSTATUS
PortFdoScanBus(_In_ PFDO_DEVICE_EXTENSION DeviceExtension)460 PortFdoScanBus(
461     _In_ PFDO_DEVICE_EXTENSION DeviceExtension)
462 {
463     PPDO_DEVICE_EXTENSION PdoExtension;
464     ULONG Bus, Target; //, Lun;
465     NTSTATUS Status;
466 
467     DPRINT("PortFdoScanBus(%p)\n", DeviceExtension);
468 
469     DPRINT("NumberOfBuses: %lu\n", DeviceExtension->Miniport.PortConfig.NumberOfBuses);
470     DPRINT("MaximumNumberOfTargets: %lu\n", DeviceExtension->Miniport.PortConfig.MaximumNumberOfTargets);
471     DPRINT("MaximumNumberOfLogicalUnits: %lu\n", DeviceExtension->Miniport.PortConfig.MaximumNumberOfLogicalUnits);
472 
473     /* Scan all buses */
474     for (Bus = 0; Bus < DeviceExtension->Miniport.PortConfig.NumberOfBuses; Bus++)
475     {
476         DPRINT("Scanning bus %ld\n", Bus);
477 
478         /* Scan all targets */
479         for (Target = 0; Target < DeviceExtension->Miniport.PortConfig.MaximumNumberOfTargets; Target++)
480         {
481             DPRINT("  Scanning target %ld:%ld\n", Bus, Target);
482 
483             DPRINT("    Scanning logical unit %ld:%ld:%ld\n", Bus, Target, 0);
484             Status = PortCreatePdo(DeviceExtension, Bus, Target, 0, &PdoExtension);
485             if (NT_SUCCESS(Status))
486             {
487                 /* Scan LUN 0 */
488                 Status = PortSendInquiry(PdoExtension);
489                 DPRINT("PortSendInquiry returned 0x%08lx\n", Status);
490                 if (!NT_SUCCESS(Status))
491                 {
492                     PortDeletePdo(PdoExtension);
493                 }
494                 else
495                 {
496                     DPRINT("VendorId: %.8s\n", PdoExtension->InquiryBuffer->VendorId);
497                     DPRINT("ProductId: %.16s\n", PdoExtension->InquiryBuffer->ProductId);
498                     DPRINT("ProductRevisionLevel: %.4s\n", PdoExtension->InquiryBuffer->ProductRevisionLevel);
499                     DPRINT("VendorSpecific: %.20s\n", PdoExtension->InquiryBuffer->VendorSpecific);
500                 }
501             }
502 
503 #if 0
504             /* Scan all logical units */
505             for (Lun = 1; Lun < DeviceExtension->Miniport.PortConfig.MaximumNumberOfLogicalUnits; Lun++)
506             {
507                 DPRINT("    Scanning logical unit %ld:%ld:%ld\n", Bus, Target, Lun);
508                 Status = PortSendInquiry(DeviceExtension->Device, Bus, Target, Lun);
509                 DPRINT("PortSendInquiry returned 0x%08lx\n", Status);
510                 if (!NT_SUCCESS(Status))
511                     break;
512             }
513 #endif
514         }
515     }
516 
517     DPRINT("PortFdoScanBus() done!\n");
518 
519     return STATUS_SUCCESS;
520 }
521 
522 
523 static
524 NTSTATUS
PortFdoQueryBusRelations(_In_ PFDO_DEVICE_EXTENSION DeviceExtension,_Out_ PULONG_PTR Information)525 PortFdoQueryBusRelations(
526     _In_ PFDO_DEVICE_EXTENSION DeviceExtension,
527     _Out_ PULONG_PTR Information)
528 {
529     NTSTATUS Status = STATUS_SUCCESS;;
530 
531     DPRINT1("PortFdoQueryBusRelations(%p %p)\n",
532             DeviceExtension, Information);
533 
534     Status = PortFdoScanBus(DeviceExtension);
535 
536     DPRINT1("Units found: %lu\n", DeviceExtension->PdoCount);
537 
538     *Information = 0;
539 
540     return Status;
541 }
542 
543 
544 static
545 NTSTATUS
PortFdoFilterRequirements(PFDO_DEVICE_EXTENSION DeviceExtension,PIRP Irp)546 PortFdoFilterRequirements(
547     PFDO_DEVICE_EXTENSION DeviceExtension,
548     PIRP Irp)
549 {
550     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
551 
552     DPRINT1("PortFdoFilterRequirements(%p %p)\n", DeviceExtension, Irp);
553 
554     /* Get the bus number and the slot number */
555     RequirementsList =(PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
556     if (RequirementsList != NULL)
557     {
558         DeviceExtension->BusNumber = RequirementsList->BusNumber;
559         DeviceExtension->SlotNumber = RequirementsList->SlotNumber;
560     }
561 
562     return STATUS_SUCCESS;
563 }
564 
565 
566 NTSTATUS
567 NTAPI
PortFdoScsi(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)568 PortFdoScsi(
569     _In_ PDEVICE_OBJECT DeviceObject,
570     _In_ PIRP Irp)
571 {
572     PFDO_DEVICE_EXTENSION DeviceExtension;
573 //    PIO_STACK_LOCATION Stack;
574     ULONG_PTR Information = 0;
575     NTSTATUS Status = STATUS_NOT_SUPPORTED;
576 
577     DPRINT("PortFdoScsi(%p %p)\n", DeviceObject, Irp);
578 
579     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
580     ASSERT(DeviceExtension);
581     ASSERT(DeviceExtension->ExtensionType == FdoExtension);
582 
583 //    Stack = IoGetCurrentIrpStackLocation(Irp);
584 
585 
586     Irp->IoStatus.Information = Information;
587     Irp->IoStatus.Status = Status;
588     IoCompleteRequest(Irp, IO_NO_INCREMENT);
589 
590     return Status;
591 }
592 
593 
594 NTSTATUS
595 NTAPI
PortFdoPnp(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp)596 PortFdoPnp(
597     _In_ PDEVICE_OBJECT DeviceObject,
598     _In_ PIRP Irp)
599 {
600     PFDO_DEVICE_EXTENSION DeviceExtension;
601     PIO_STACK_LOCATION Stack;
602     ULONG_PTR Information = 0;
603     NTSTATUS Status = STATUS_NOT_SUPPORTED;
604 
605     DPRINT1("PortFdoPnp(%p %p)\n",
606             DeviceObject, Irp);
607 
608     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
609     ASSERT(DeviceExtension);
610     ASSERT(DeviceExtension->ExtensionType == FdoExtension);
611 
612     Stack = IoGetCurrentIrpStackLocation(Irp);
613 
614     switch (Stack->MinorFunction)
615     {
616         case IRP_MN_START_DEVICE: /* 0x00 */
617             DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
618             Status = PortFdoStartDevice(DeviceExtension, Irp);
619             break;
620 
621         case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */
622             DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
623             break;
624 
625         case IRP_MN_REMOVE_DEVICE: /* 0x02 */
626             DPRINT1("IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n");
627             break;
628 
629         case IRP_MN_CANCEL_REMOVE_DEVICE: /* 0x03 */
630             DPRINT1("IRP_MJ_PNP / IRP_MN_CANCEL_REMOVE_DEVICE\n");
631             break;
632 
633         case IRP_MN_STOP_DEVICE: /* 0x04 */
634             DPRINT1("IRP_MJ_PNP / IRP_MN_STOP_DEVICE\n");
635             break;
636 
637         case IRP_MN_QUERY_STOP_DEVICE: /* 0x05 */
638             DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_STOP_DEVICE\n");
639             break;
640 
641         case IRP_MN_CANCEL_STOP_DEVICE: /* 0x06 */
642             DPRINT1("IRP_MJ_PNP / IRP_MN_CANCEL_STOP_DEVICE\n");
643             break;
644 
645         case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
646             DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
647             switch (Stack->Parameters.QueryDeviceRelations.Type)
648             {
649                 case BusRelations:
650                     DPRINT1("    IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
651                     Status = PortFdoQueryBusRelations(DeviceExtension, &Information);
652                     break;
653 
654                 case RemovalRelations:
655                     DPRINT1("    IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
656                     return ForwardIrpAndForget(DeviceExtension->LowerDevice, Irp);
657 
658                 default:
659                     DPRINT1("    IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
660                             Stack->Parameters.QueryDeviceRelations.Type);
661                     return ForwardIrpAndForget(DeviceExtension->LowerDevice, Irp);
662             }
663             break;
664 
665         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
666             DPRINT1("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
667             PortFdoFilterRequirements(DeviceExtension, Irp);
668             return ForwardIrpAndForget(DeviceExtension->LowerDevice, Irp);
669 
670         case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
671             DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
672             break;
673 
674         case IRP_MN_DEVICE_USAGE_NOTIFICATION: /* 0x16 */
675             DPRINT1("IRP_MJ_PNP / IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
676             break;
677 
678         case IRP_MN_SURPRISE_REMOVAL: /* 0x17 */
679             DPRINT1("IRP_MJ_PNP / IRP_MN_SURPRISE_REMOVAL\n");
680             break;
681 
682         default:
683             DPRINT1("IRP_MJ_PNP / Unknown IOCTL 0x%lx\n", Stack->MinorFunction);
684             return ForwardIrpAndForget(DeviceExtension->LowerDevice, Irp);
685     }
686 
687     Irp->IoStatus.Information = Information;
688     Irp->IoStatus.Status = Status;
689     IoCompleteRequest(Irp, IO_NO_INCREMENT);
690 
691     return Status;
692 }
693 
694 /* EOF */
695