xref: /reactos/drivers/storage/ide/pciidex/pdo.c (revision cce399e7)
1 /*
2  * PROJECT:     PCI IDE bus driver extension
3  * LICENSE:     See COPYING in the top level directory
4  * PURPOSE:     IRP_MJ_PNP operations for PDOs
5  * COPYRIGHT:   Copyright 2005 Hervé Poussineau <hpoussin@reactos.org>
6  *              Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
7  */
8 
9 #include "pciidex.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 static
15 CODE_SEG("PAGE")
16 NTSTATUS
17 PciIdeXPdoStartDevice(
18     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
19     _In_ PCM_RESOURCE_LIST ResourceList)
20 {
21     PUCHAR IoBase;
22 
23     PAGED_CODE();
24 
25     IoBase = PdoExtension->ParentController->BusMasterPortBase;
26     if (!IS_PRIMARY_CHANNEL(PdoExtension))
27     {
28         IoBase += BM_SECONDARY_CHANNEL_OFFSET;
29     }
30     DPRINT("Bus Master Base %p\n", IoBase);
31 
32     return STATUS_SUCCESS;
33 }
34 
35 static
36 CODE_SEG("PAGE")
37 NTSTATUS
38 PciIdeXPdoStopDevice(
39     _In_ PPDO_DEVICE_EXTENSION PdoExtension)
40 {
41     PAGED_CODE();
42 
43     return STATUS_SUCCESS;
44 }
45 
46 static
47 CODE_SEG("PAGE")
48 NTSTATUS
49 PciIdeXPdoRemoveDevice(
50     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
51     _In_ BOOLEAN FinalRemove)
52 {
53     PFDO_DEVICE_EXTENSION FdoExtension = PdoExtension->ParentController;
54     ULONG i;
55 
56     PAGED_CODE();
57 
58     if (FinalRemove && PdoExtension->ReportedMissing)
59     {
60         ExAcquireFastMutex(&FdoExtension->DeviceSyncMutex);
61 
62         for (i = 0; i < MAX_IDE_CHANNEL; ++i)
63         {
64             if (FdoExtension->Channels[i] == PdoExtension)
65             {
66                 FdoExtension->Channels[i] = NULL;
67                 break;
68             }
69         }
70 
71         ExReleaseFastMutex(&FdoExtension->DeviceSyncMutex);
72 
73         IoDeleteDevice(PdoExtension->Common.Self);
74     }
75 
76     return STATUS_SUCCESS;
77 }
78 
79 static
80 CODE_SEG("PAGE")
81 NTSTATUS
82 PciIdeXPdoQueryStopRemoveDevice(
83     _In_ PPDO_DEVICE_EXTENSION PdoExtension)
84 {
85     PAGED_CODE();
86 
87     if (PdoExtension->Common.PageFiles ||
88         PdoExtension->Common.HibernateFiles ||
89         PdoExtension->Common.DumpFiles)
90     {
91         return STATUS_DEVICE_BUSY;
92     }
93 
94     return STATUS_SUCCESS;
95 }
96 
97 static
98 CODE_SEG("PAGE")
99 NTSTATUS
100 PciIdeXPdoQueryTargetDeviceRelations(
101     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
102     _In_ PIRP Irp)
103 {
104     PDEVICE_RELATIONS DeviceRelations;
105 
106     PAGED_CODE();
107 
108     DeviceRelations = ExAllocatePoolWithTag(PagedPool,
109                                             sizeof(DEVICE_RELATIONS),
110                                             TAG_PCIIDEX);
111     if (!DeviceRelations)
112         return STATUS_INSUFFICIENT_RESOURCES;
113 
114     DeviceRelations->Count = 1;
115     DeviceRelations->Objects[0] = PdoExtension->Common.Self;
116     ObReferenceObject(PdoExtension->Common.Self);
117 
118     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
119     return STATUS_SUCCESS;
120 }
121 
122 static IO_COMPLETION_ROUTINE PciIdeXOnRepeaterCompletion;
123 
124 static
125 NTSTATUS
126 NTAPI
127 PciIdeXOnRepeaterCompletion(
128     _In_ PDEVICE_OBJECT DeviceObject,
129     _In_ PIRP Irp,
130     _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
131 {
132     UNREFERENCED_PARAMETER(DeviceObject);
133 
134     if (Irp->PendingReturned)
135         KeSetEvent(Context, IO_NO_INCREMENT, FALSE);
136 
137     return STATUS_MORE_PROCESSING_REQUIRED;
138 }
139 
140 static
141 CODE_SEG("PAGE")
142 NTSTATUS
143 PciIdeXPdoRepeatRequest(
144     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
145     _In_ PIRP Irp,
146     _In_opt_ PDEVICE_CAPABILITIES DeviceCapabilities)
147 {
148     PDEVICE_OBJECT Fdo, TopDeviceObject;
149     PIO_STACK_LOCATION IoStack, SubStack;
150     PIRP SubIrp;
151     KEVENT Event;
152     NTSTATUS Status;
153 
154     PAGED_CODE();
155 
156     Fdo = PdoExtension->ParentController->Common.Self;
157     TopDeviceObject = IoGetAttachedDeviceReference(Fdo);
158 
159     SubIrp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
160     if (!SubIrp)
161     {
162         ObDereferenceObject(TopDeviceObject);
163         return STATUS_INSUFFICIENT_RESOURCES;
164     }
165 
166     KeInitializeEvent(&Event, NotificationEvent, FALSE);
167 
168     IoStack = IoGetCurrentIrpStackLocation(Irp);
169     SubStack = IoGetNextIrpStackLocation(SubIrp);
170     RtlCopyMemory(SubStack, IoStack, sizeof(IO_STACK_LOCATION));
171 
172     if (DeviceCapabilities)
173         SubStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
174 
175     IoSetCompletionRoutine(SubIrp,
176                            PciIdeXOnRepeaterCompletion,
177                            &Event,
178                            TRUE,
179                            TRUE,
180                            TRUE);
181 
182     SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
183 
184     Status = IoCallDriver(TopDeviceObject, SubIrp);
185     if (Status == STATUS_PENDING)
186     {
187         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
188     }
189 
190     ObDereferenceObject(TopDeviceObject);
191 
192     Status = SubIrp->IoStatus.Status;
193     IoFreeIrp(SubIrp);
194 
195     return Status;
196 }
197 
198 static
199 CODE_SEG("PAGE")
200 NTSTATUS
201 PciIdeXPdoQueryCapabilities(
202     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
203     _In_ PIRP Irp)
204 {
205     DEVICE_CAPABILITIES ParentCapabilities;
206     PDEVICE_CAPABILITIES DeviceCapabilities;
207     PIO_STACK_LOCATION IoStack;
208     NTSTATUS Status;
209 
210     PAGED_CODE();
211 
212     /* Get the capabilities of the parent device */
213     RtlZeroMemory(&ParentCapabilities, sizeof(ParentCapabilities));
214     ParentCapabilities.Size = sizeof(ParentCapabilities);
215     ParentCapabilities.Version = 1;
216     ParentCapabilities.Address = MAXULONG;
217     ParentCapabilities.UINumber = MAXULONG;
218     Status = PciIdeXPdoRepeatRequest(PdoExtension, Irp, &ParentCapabilities);
219     if (!NT_SUCCESS(Status))
220         return Status;
221 
222     IoStack = IoGetCurrentIrpStackLocation(Irp);
223     DeviceCapabilities = IoStack->Parameters.DeviceCapabilities.Capabilities;
224     *DeviceCapabilities = ParentCapabilities;
225 
226     /* Override some fields */
227     DeviceCapabilities->UniqueID = FALSE;
228     DeviceCapabilities->Address = PdoExtension->Channel;
229 
230     return STATUS_SUCCESS;
231 }
232 
233 static
234 CODE_SEG("PAGE")
235 NTSTATUS
236 PciIdeXPdoQueryPnpDeviceState(
237     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
238     _In_ PIRP Irp)
239 {
240     PAGED_CODE();
241 
242     if (PdoExtension->Common.PageFiles ||
243         PdoExtension->Common.HibernateFiles ||
244         PdoExtension->Common.DumpFiles)
245     {
246         Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
247     }
248 
249     return STATUS_SUCCESS;
250 }
251 
252 static
253 CODE_SEG("PAGE")
254 NTSTATUS
255 PciIdeXPdoQueryResources(
256     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
257     _In_ PIRP Irp)
258 {
259     PFDO_DEVICE_EXTENSION FdoExtension;
260     IDE_CHANNEL_STATE ChannelState;
261     PCM_RESOURCE_LIST ResourceList;
262     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
263     ULONG CommandPortBase, ControlPortBase, InterruptVector;
264     ULONG ListSize;
265 
266     PAGED_CODE();
267 
268     FdoExtension = PdoExtension->ParentController;
269     if (FdoExtension->InNativeMode)
270         return Irp->IoStatus.Status;
271 
272     ChannelState = PciIdeXChannelState(FdoExtension, PdoExtension->Channel);
273     if (ChannelState == ChannelDisabled)
274         return Irp->IoStatus.Status;
275 
276     ListSize = sizeof(CM_RESOURCE_LIST) +
277                sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCIIDE_LEGACY_RESOURCE_COUNT - 1);
278     ResourceList = ExAllocatePoolZero(PagedPool, ListSize, TAG_PCIIDEX);
279     if (!ResourceList)
280         return STATUS_INSUFFICIENT_RESOURCES;
281 
282     /* Legacy mode resources */
283     ResourceList->Count = 1;
284     ResourceList->List[0].InterfaceType = Isa;
285     ResourceList->List[0].PartialResourceList.Version = 1;
286     ResourceList->List[0].PartialResourceList.Revision = 1;
287     ResourceList->List[0].PartialResourceList.Count = PCIIDE_LEGACY_RESOURCE_COUNT;
288 
289     if (IS_PRIMARY_CHANNEL(PdoExtension))
290     {
291         CommandPortBase = PCIIDE_LEGACY_PRIMARY_COMMAND_BASE;
292         ControlPortBase = PCIIDE_LEGACY_PRIMARY_CONTROL_BASE;
293         InterruptVector = PCIIDE_LEGACY_PRIMARY_IRQ;
294     }
295     else
296     {
297         CommandPortBase = PCIIDE_LEGACY_SECONDARY_COMMAND_BASE;
298         ControlPortBase = PCIIDE_LEGACY_SECONDARY_CONTROL_BASE;
299         InterruptVector = PCIIDE_LEGACY_SECONDARY_IRQ;
300     }
301 
302     Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[0];
303 
304     /* Command port base */
305     Descriptor->Type = CmResourceTypePort;
306     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
307     Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
308     Descriptor->u.Port.Length = PCIIDE_LEGACY_COMMAND_IO_RANGE_LENGTH;
309     Descriptor->u.Port.Start.LowPart = CommandPortBase;
310     ++Descriptor;
311 
312     /* Control port base */
313     Descriptor->Type = CmResourceTypePort;
314     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
315     Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
316     Descriptor->u.Port.Length = PCIIDE_LEGACY_CONTROL_IO_RANGE_LENGTH;
317     Descriptor->u.Port.Start.LowPart = ControlPortBase;
318     ++Descriptor;
319 
320     /* Interrupt */
321     Descriptor->Type = CmResourceTypeInterrupt;
322     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
323     Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
324     Descriptor->u.Interrupt.Level = InterruptVector;
325     Descriptor->u.Interrupt.Vector = InterruptVector;
326     Descriptor->u.Interrupt.Affinity = (KAFFINITY)-1;
327 
328     Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
329     return STATUS_SUCCESS;
330 }
331 
332 static
333 CODE_SEG("PAGE")
334 NTSTATUS
335 PciIdeXPdoQueryResourceRequirements(
336     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
337     _In_ PIRP Irp)
338 {
339     PFDO_DEVICE_EXTENSION FdoExtension;
340     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
341     PIO_RESOURCE_DESCRIPTOR Descriptor;
342     IDE_CHANNEL_STATE ChannelState;
343     ULONG CommandPortBase, ControlPortBase, InterruptVector;
344     ULONG ListSize;
345 
346     PAGED_CODE();
347 
348     FdoExtension = PdoExtension->ParentController;
349     if (FdoExtension->InNativeMode)
350         return Irp->IoStatus.Status;
351 
352     ChannelState = PciIdeXChannelState(FdoExtension, PdoExtension->Channel);
353     if (ChannelState == ChannelDisabled)
354         return Irp->IoStatus.Status;
355 
356     ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
357                sizeof(IO_RESOURCE_DESCRIPTOR) * (PCIIDE_LEGACY_RESOURCE_COUNT - 1);
358     RequirementsList = ExAllocatePoolZero(PagedPool, ListSize, TAG_PCIIDEX);
359     if (!RequirementsList)
360         return STATUS_INSUFFICIENT_RESOURCES;
361 
362     /* Legacy mode resources */
363     RequirementsList->InterfaceType = Isa;
364     RequirementsList->ListSize = ListSize;
365     RequirementsList->AlternativeLists = 1;
366     RequirementsList->List[0].Version = 1;
367     RequirementsList->List[0].Revision = 1;
368     RequirementsList->List[0].Count = PCIIDE_LEGACY_RESOURCE_COUNT;
369 
370     if (IS_PRIMARY_CHANNEL(PdoExtension))
371     {
372         CommandPortBase = PCIIDE_LEGACY_PRIMARY_COMMAND_BASE;
373         ControlPortBase = PCIIDE_LEGACY_PRIMARY_CONTROL_BASE;
374         InterruptVector = PCIIDE_LEGACY_PRIMARY_IRQ;
375     }
376     else
377     {
378         CommandPortBase = PCIIDE_LEGACY_SECONDARY_COMMAND_BASE;
379         ControlPortBase = PCIIDE_LEGACY_SECONDARY_CONTROL_BASE;
380         InterruptVector = PCIIDE_LEGACY_SECONDARY_IRQ;
381     }
382 
383     Descriptor = &RequirementsList->List[0].Descriptors[0];
384 
385     /* Command port base */
386     Descriptor->Type = CmResourceTypePort;
387     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
388     Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
389     Descriptor->u.Port.Length = PCIIDE_LEGACY_COMMAND_IO_RANGE_LENGTH;
390     Descriptor->u.Port.Alignment = 1;
391     Descriptor->u.Port.MinimumAddress.LowPart = CommandPortBase;
392     Descriptor->u.Port.MaximumAddress.LowPart = CommandPortBase +
393                                                 PCIIDE_LEGACY_COMMAND_IO_RANGE_LENGTH - 1;
394     ++Descriptor;
395 
396     /* Control port base */
397     Descriptor->Type = CmResourceTypePort;
398     Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
399     Descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
400     Descriptor->u.Port.Length = PCIIDE_LEGACY_CONTROL_IO_RANGE_LENGTH;
401     Descriptor->u.Port.Alignment = 1;
402     Descriptor->u.Port.MinimumAddress.LowPart = ControlPortBase;
403     Descriptor->u.Port.MaximumAddress.LowPart = ControlPortBase +
404                                                 PCIIDE_LEGACY_CONTROL_IO_RANGE_LENGTH - 1;
405     ++Descriptor;
406 
407     /* Interrupt */
408     Descriptor->Type = CmResourceTypeInterrupt;
409     Descriptor->ShareDisposition = CmResourceShareShared;
410     Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
411     Descriptor->u.Interrupt.MinimumVector = InterruptVector;
412     Descriptor->u.Interrupt.MaximumVector = InterruptVector;
413 
414     Irp->IoStatus.Information = (ULONG_PTR)RequirementsList;
415     return STATUS_SUCCESS;
416 }
417 
418 static
419 CODE_SEG("PAGE")
420 PCWSTR
421 PciIdeXGetControllerVendorId(
422     _In_ PFDO_DEVICE_EXTENSION FdoExtension)
423 {
424     PAGED_CODE();
425 
426     switch (FdoExtension->VendorId)
427     {
428         case 0x0E11:
429             return L"Compaq";
430         case 0x1039:
431             return L"SiS";
432         case 0x1050:
433             return L"WinBond";
434         case 0x1095:
435             return L"CMD";
436         case 0x10B9:
437             return L"ALi";
438         case 0x8086:
439             return L"Intel";
440 
441         default:
442             break;
443     }
444 
445     /* Only certain controllers have a non-numeric identifier */
446     return NULL;
447 }
448 
449 static
450 CODE_SEG("PAGE")
451 PCWSTR
452 PciIdeXGetControllerDeviceId(
453     _In_ PFDO_DEVICE_EXTENSION FdoExtension)
454 {
455     PAGED_CODE();
456 
457     /* Intel */
458     if (FdoExtension->VendorId == 0x8086)
459     {
460         switch (FdoExtension->DeviceId)
461         {
462             case 0x1230:
463                 return L"PIIX";
464             case 0x7010:
465                 return L"PIIX3";
466             case 0x7111:
467                 return L"PIIX4";
468 
469             default:
470                 break;
471         }
472     }
473 
474     return NULL;
475 }
476 
477 static
478 CODE_SEG("PAGE")
479 NTSTATUS
480 PciIdeXPdoQueryId(
481     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
482     _In_ PIRP Irp)
483 {
484     PIO_STACK_LOCATION IoStack;
485     NTSTATUS Status;
486     PWCHAR Buffer, End;
487     size_t CharCount, Remaining;
488     static const WCHAR IdeCompatibleId[] = L"*PNP0600";
489 
490     PAGED_CODE();
491 
492     IoStack = IoGetCurrentIrpStackLocation(Irp);
493     switch (IoStack->Parameters.QueryId.IdType)
494     {
495       case BusQueryDeviceID:
496       {
497           static const WCHAR PciIdeDeviceId[] = L"PCIIDE\\IDEChannel";
498 
499           Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(PciIdeDeviceId), TAG_PCIIDEX);
500           if (!Buffer)
501               return STATUS_INSUFFICIENT_RESOURCES;
502 
503           RtlCopyMemory(Buffer, PciIdeDeviceId, sizeof(PciIdeDeviceId));
504 
505           DPRINT("Device ID: '%S'\n", Buffer);
506           break;
507       }
508 
509       case BusQueryHardwareIDs:
510       {
511           PFDO_DEVICE_EXTENSION FdoExtension;
512           PCWSTR VendorString;
513           PWCHAR IdStart;
514 
515           DBG_UNREFERENCED_LOCAL_VARIABLE(IdStart);
516 
517           /* Maximum string length */
518           CharCount = sizeof("WinBond-1234") +
519                       sizeof("Secondary_IDE_Channel") +
520                       sizeof(IdeCompatibleId) +
521                       sizeof(ANSI_NULL); /* multi-string */
522 
523           Buffer = ExAllocatePoolWithTag(PagedPool,
524                                          CharCount * sizeof(WCHAR),
525                                          TAG_PCIIDEX);
526           if (!Buffer)
527               return STATUS_INSUFFICIENT_RESOURCES;
528 
529           FdoExtension = PdoExtension->ParentController;
530           VendorString = PciIdeXGetControllerVendorId(FdoExtension);
531 
532           DPRINT("HardwareIDs:\n");
533 
534           /* ID 1 */
535           if (VendorString)
536           {
537               PCWSTR DeviceString = PciIdeXGetControllerDeviceId(FdoExtension);
538 
539               if (DeviceString)
540               {
541                   Status = RtlStringCchPrintfExW(Buffer,
542                                                  CharCount,
543                                                  &End,
544                                                  &Remaining,
545                                                  0,
546                                                  L"%ls-%ls",
547                                                  VendorString,
548                                                  DeviceString);
549               }
550               else
551               {
552                   Status = RtlStringCchPrintfExW(Buffer,
553                                                  CharCount,
554                                                  &End,
555                                                  &Remaining,
556                                                  0,
557                                                  L"%ls-%04x",
558                                                  VendorString,
559                                                  FdoExtension->DeviceId);
560               }
561           }
562           else
563           {
564               Status = RtlStringCchPrintfExW(Buffer,
565                                              CharCount,
566                                              &End,
567                                              &Remaining,
568                                              0,
569                                              L"%04x-%04x",
570                                              FdoExtension->VendorId,
571                                              FdoExtension->DeviceId);
572           }
573           ASSERT(NT_SUCCESS(Status));
574 
575           DPRINT("  '%S'\n", Buffer);
576 
577           ++End;
578           --Remaining;
579 
580           /* ID 2 */
581           IdStart = End;
582           Status = RtlStringCchPrintfExW(End,
583                                          Remaining,
584                                          &End,
585                                          &Remaining,
586                                          0,
587                                          L"%ls",
588                                          IS_PRIMARY_CHANNEL(PdoExtension) ?
589                                          L"Primary_IDE_Channel" :
590                                          L"Secondary_IDE_Channel");
591           ASSERT(NT_SUCCESS(Status));
592 
593           DPRINT("  '%S'\n", IdStart);
594 
595           ++End;
596           --Remaining;
597 
598           /* ID 3 */
599           IdStart = End;
600           Status = RtlStringCchPrintfExW(End,
601                                          Remaining,
602                                          &End,
603                                          &Remaining,
604                                          0,
605                                          L"%ls",
606                                          IdeCompatibleId);
607           ASSERT(NT_SUCCESS(Status));
608 
609           DPRINT("  '%S'\n", IdStart);
610 
611           *++End = UNICODE_NULL; /* multi-string */
612           break;
613       }
614 
615       case BusQueryCompatibleIDs:
616       {
617           Buffer = ExAllocatePoolWithTag(PagedPool,
618                                          sizeof(IdeCompatibleId) + sizeof(UNICODE_NULL),
619                                          TAG_PCIIDEX);
620           if (!Buffer)
621               return STATUS_INSUFFICIENT_RESOURCES;
622 
623           RtlCopyMemory(Buffer, IdeCompatibleId, sizeof(IdeCompatibleId));
624 
625           Buffer[sizeof(IdeCompatibleId) / sizeof(WCHAR)] = UNICODE_NULL; /* multi-string */
626 
627           DPRINT("Compatible ID: '%S'\n", Buffer);
628           break;
629       }
630 
631       case BusQueryInstanceID:
632       {
633           CharCount = sizeof("0");
634 
635           Buffer = ExAllocatePoolWithTag(PagedPool,
636                                          CharCount * sizeof(WCHAR),
637                                          TAG_PCIIDEX);
638           if (!Buffer)
639               return STATUS_INSUFFICIENT_RESOURCES;
640 
641           Status = RtlStringCchPrintfExW(Buffer,
642                                          CharCount,
643                                          NULL,
644                                          NULL,
645                                          0,
646                                          L"%lu",
647                                          PdoExtension->Channel);
648           ASSERT(NT_SUCCESS(Status));
649 
650           DPRINT("Instance ID: '%S'\n", Buffer);
651           break;
652       }
653 
654       default:
655           return Irp->IoStatus.Status;
656     }
657 
658     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
659     return STATUS_SUCCESS;
660 }
661 
662 static
663 CODE_SEG("PAGE")
664 NTSTATUS
665 PciIdeXPdoQueryDeviceText(
666     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
667     _In_ PIRP Irp)
668 {
669     PIO_STACK_LOCATION IoStack;
670     PWCHAR Buffer;
671     ULONG Size;
672 
673     PAGED_CODE();
674 
675     IoStack = IoGetCurrentIrpStackLocation(Irp);
676     switch (IoStack->Parameters.QueryDeviceText.DeviceTextType)
677     {
678         case DeviceTextLocationInformation:
679         {
680             static const WCHAR PrimaryChannelText[] = L"Primary channel";
681             static const WCHAR SecondaryChannelText[] = L"Secondary channel";
682 
683             if (IS_PRIMARY_CHANNEL(PdoExtension))
684                 Size = sizeof(PrimaryChannelText);
685             else
686                 Size = sizeof(SecondaryChannelText);
687 
688             Buffer = ExAllocatePoolWithTag(PagedPool, Size, TAG_PCIIDEX);
689             if (!Buffer)
690                 return STATUS_INSUFFICIENT_RESOURCES;
691 
692             RtlCopyMemory(Buffer,
693                           IS_PRIMARY_CHANNEL(PdoExtension) ?
694                           PrimaryChannelText : SecondaryChannelText,
695                           Size);
696 
697             DPRINT("Device ID: '%S'\n", Buffer);
698             break;
699         }
700 
701         default:
702             return Irp->IoStatus.Status;
703     }
704 
705     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
706     return STATUS_SUCCESS;
707 }
708 
709 static
710 CODE_SEG("PAGE")
711 NTSTATUS
712 PciIdeXPdoQueryDeviceUsageNotification(
713     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
714     _In_ PIRP Irp)
715 {
716     PIO_STACK_LOCATION IoStack;
717     NTSTATUS Status;
718     volatile LONG* Counter;
719 
720     PAGED_CODE();
721 
722     Status = PciIdeXPdoRepeatRequest(PdoExtension, Irp, NULL);
723     if (!NT_SUCCESS(Status))
724         return Status;
725 
726     IoStack = IoGetCurrentIrpStackLocation(Irp);
727     switch (IoStack->Parameters.UsageNotification.Type)
728     {
729         case DeviceUsageTypePaging:
730             Counter = &PdoExtension->Common.PageFiles;
731             break;
732 
733         case DeviceUsageTypeHibernation:
734             Counter = &PdoExtension->Common.HibernateFiles;
735             break;
736 
737         case DeviceUsageTypeDumpFile:
738             Counter = &PdoExtension->Common.DumpFiles;
739             break;
740 
741         default:
742             return Status;
743     }
744 
745     IoAdjustPagingPathCount(Counter, IoStack->Parameters.UsageNotification.InPath);
746     IoInvalidateDeviceState(PdoExtension->Common.Self);
747 
748     return STATUS_SUCCESS;
749 }
750 
751 static
752 CODE_SEG("PAGE")
753 NTSTATUS
754 PciIdeXPdoDispatchPnp(
755     _In_ PPDO_DEVICE_EXTENSION PdoExtension,
756     _Inout_ PIRP Irp)
757 {
758     NTSTATUS Status;
759     PIO_STACK_LOCATION IoStack;
760 
761     PAGED_CODE();
762 
763     IoStack = IoGetCurrentIrpStackLocation(Irp);
764     switch (IoStack->MinorFunction)
765     {
766         case IRP_MN_START_DEVICE:
767             Status = PciIdeXPdoStartDevice(PdoExtension,
768                                            IoStack->Parameters.StartDevice.AllocatedResources);
769             break;
770 
771         case IRP_MN_STOP_DEVICE:
772             Status = PciIdeXPdoStopDevice(PdoExtension);
773             break;
774 
775         case IRP_MN_QUERY_STOP_DEVICE:
776         case IRP_MN_QUERY_REMOVE_DEVICE:
777             Status = PciIdeXPdoQueryStopRemoveDevice(PdoExtension);
778             break;
779 
780         case IRP_MN_CANCEL_REMOVE_DEVICE:
781         case IRP_MN_CANCEL_STOP_DEVICE:
782             Status = STATUS_SUCCESS;
783             break;
784 
785         case IRP_MN_SURPRISE_REMOVAL:
786         case IRP_MN_REMOVE_DEVICE:
787             Status = PciIdeXPdoRemoveDevice(PdoExtension,
788                                             IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE);
789             break;
790 
791         case IRP_MN_QUERY_DEVICE_RELATIONS:
792             if (IoStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
793                 Status = PciIdeXPdoQueryTargetDeviceRelations(PdoExtension, Irp);
794             else
795                 Status = Irp->IoStatus.Status;
796             break;
797 
798         case IRP_MN_QUERY_CAPABILITIES:
799             Status = PciIdeXPdoQueryCapabilities(PdoExtension, Irp);
800             break;
801 
802         case IRP_MN_QUERY_PNP_DEVICE_STATE:
803             Status = PciIdeXPdoQueryPnpDeviceState(PdoExtension, Irp);
804             break;
805 
806         case IRP_MN_QUERY_RESOURCES:
807             Status = PciIdeXPdoQueryResources(PdoExtension, Irp);
808             break;
809 
810         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
811             Status = PciIdeXPdoQueryResourceRequirements(PdoExtension, Irp);
812             break;
813 
814         case IRP_MN_QUERY_ID:
815             Status = PciIdeXPdoQueryId(PdoExtension, Irp);
816             break;
817 
818         case IRP_MN_QUERY_DEVICE_TEXT:
819             Status = PciIdeXPdoQueryDeviceText(PdoExtension, Irp);
820             break;
821 
822         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
823             Status = PciIdeXPdoQueryDeviceUsageNotification(PdoExtension, Irp);
824             break;
825 
826         default:
827             Status = Irp->IoStatus.Status;
828             break;
829     }
830 
831     Irp->IoStatus.Status = Status;
832     IoCompleteRequest(Irp, IO_NO_INCREMENT);
833 
834     return Status;
835 }
836 
837 CODE_SEG("PAGE")
838 NTSTATUS
839 NTAPI
840 PciIdeXDispatchPnp(
841     _In_ PDEVICE_OBJECT DeviceObject,
842     _Inout_ PIRP Irp)
843 {
844     PAGED_CODE();
845 
846     if (IS_FDO(DeviceObject->DeviceExtension))
847         return PciIdeXFdoDispatchPnp(DeviceObject->DeviceExtension, Irp);
848     else
849         return PciIdeXPdoDispatchPnp(DeviceObject->DeviceExtension, Irp);
850 }
851