xref: /reactos/drivers/bus/pci/pdo.c (revision 09dde2cf)
1 /*
2  * PROJECT:         ReactOS PCI bus driver
3  * FILE:            pdo.c
4  * PURPOSE:         Child device object dispatch routines
5  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
6  * UPDATE HISTORY:
7  *      10-09-2001  CSH  Created
8  */
9 
10 #include "pci.h"
11 
12 #include <initguid.h>
13 #include <wdmguid.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 #if 0
19 #define DBGPRINT(...) DbgPrint(__VA_ARGS__)
20 #else
21 #define DBGPRINT(...)
22 #endif
23 
24 #define PCI_ADDRESS_MEMORY_ADDRESS_MASK_64     0xfffffffffffffff0ull
25 #define PCI_ADDRESS_IO_ADDRESS_MASK_64         0xfffffffffffffffcull
26 
27 /*** PRIVATE *****************************************************************/
28 
29 static NTSTATUS
30 PdoQueryDeviceText(
31     IN PDEVICE_OBJECT DeviceObject,
32     IN PIRP Irp,
33     PIO_STACK_LOCATION IrpSp)
34 {
35     PPDO_DEVICE_EXTENSION DeviceExtension;
36     UNICODE_STRING String;
37     NTSTATUS Status;
38 
39     DPRINT("Called\n");
40 
41     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
42 
43     switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
44     {
45         case DeviceTextDescription:
46             Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
47                                                &DeviceExtension->DeviceDescription,
48                                                &String);
49 
50             DPRINT("DeviceTextDescription\n");
51             Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
52             break;
53 
54         case DeviceTextLocationInformation:
55             Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
56                                                &DeviceExtension->DeviceLocation,
57                                                &String);
58 
59             DPRINT("DeviceTextLocationInformation\n");
60             Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
61             break;
62 
63         default:
64             Irp->IoStatus.Information = 0;
65             Status = STATUS_INVALID_PARAMETER;
66             break;
67     }
68 
69     return Status;
70 }
71 
72 
73 static NTSTATUS
74 PdoQueryId(
75     IN PDEVICE_OBJECT DeviceObject,
76     IN PIRP Irp,
77     PIO_STACK_LOCATION IrpSp)
78 {
79     PPDO_DEVICE_EXTENSION DeviceExtension;
80     UNICODE_STRING String;
81     NTSTATUS Status;
82 
83     DPRINT("Called\n");
84 
85     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
86 
87 //    Irp->IoStatus.Information = 0;
88 
89     Status = STATUS_SUCCESS;
90 
91     RtlInitUnicodeString(&String, NULL);
92 
93     switch (IrpSp->Parameters.QueryId.IdType)
94     {
95         case BusQueryDeviceID:
96             Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
97                                                &DeviceExtension->DeviceID,
98                                                &String);
99 
100             DPRINT("DeviceID: %S\n", String.Buffer);
101 
102             Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
103             break;
104 
105         case BusQueryHardwareIDs:
106             Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
107                                                &DeviceExtension->HardwareIDs,
108                                                &String);
109 
110             Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
111             break;
112 
113         case BusQueryCompatibleIDs:
114             Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
115                                                &DeviceExtension->CompatibleIDs,
116                                                &String);
117 
118             Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
119             break;
120 
121         case BusQueryInstanceID:
122             Status = PciDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
123                                                &DeviceExtension->InstanceID,
124                                                &String);
125 
126             DPRINT("InstanceID: %S\n", String.Buffer);
127 
128             Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
129             break;
130 
131         case BusQueryDeviceSerialNumber:
132         default:
133             Status = STATUS_NOT_IMPLEMENTED;
134     }
135 
136     return Status;
137 }
138 
139 
140 static NTSTATUS
141 PdoQueryBusInformation(
142     IN PDEVICE_OBJECT DeviceObject,
143     IN PIRP Irp,
144     PIO_STACK_LOCATION IrpSp)
145 {
146     PPDO_DEVICE_EXTENSION DeviceExtension;
147     PPNP_BUS_INFORMATION BusInformation;
148 
149     UNREFERENCED_PARAMETER(IrpSp);
150     DPRINT("Called\n");
151 
152     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
153     BusInformation = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), TAG_PCI);
154     Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
155     if (BusInformation != NULL)
156     {
157         BusInformation->BusTypeGuid = GUID_BUS_TYPE_PCI;
158         BusInformation->LegacyBusType = PCIBus;
159         BusInformation->BusNumber = DeviceExtension->PciDevice->BusNumber;
160 
161         return STATUS_SUCCESS;
162     }
163 
164     return STATUS_INSUFFICIENT_RESOURCES;
165 }
166 
167 
168 static NTSTATUS
169 PdoQueryCapabilities(
170     IN PDEVICE_OBJECT DeviceObject,
171     IN PIRP Irp,
172     PIO_STACK_LOCATION IrpSp)
173 {
174     PPDO_DEVICE_EXTENSION DeviceExtension;
175     PDEVICE_CAPABILITIES DeviceCapabilities;
176     ULONG DeviceNumber, FunctionNumber;
177 
178     UNREFERENCED_PARAMETER(Irp);
179     DPRINT("Called\n");
180 
181     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
182     DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
183 
184     if (DeviceCapabilities->Version != 1)
185         return STATUS_UNSUCCESSFUL;
186 
187     DeviceNumber = DeviceExtension->PciDevice->SlotNumber.u.bits.DeviceNumber;
188     FunctionNumber = DeviceExtension->PciDevice->SlotNumber.u.bits.FunctionNumber;
189 
190     DeviceCapabilities->UniqueID = FALSE;
191     DeviceCapabilities->Address = ((DeviceNumber << 16) & 0xFFFF0000) + (FunctionNumber & 0xFFFF);
192     DeviceCapabilities->UINumber = MAXULONG; /* FIXME */
193 
194     return STATUS_SUCCESS;
195 }
196 
197 static BOOLEAN
198 PdoReadPciBar(PPDO_DEVICE_EXTENSION DeviceExtension,
199               ULONG Offset,
200               PULONG OriginalValue,
201               PULONG NewValue)
202 {
203     ULONG Size;
204     ULONG AllOnes;
205 
206     /* Read the original value */
207     Size = HalGetBusDataByOffset(PCIConfiguration,
208                                  DeviceExtension->PciDevice->BusNumber,
209                                  DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
210                                  OriginalValue,
211                                  Offset,
212                                  sizeof(ULONG));
213     if (Size != sizeof(ULONG))
214     {
215         DPRINT1("Wrong size %lu\n", Size);
216         return FALSE;
217     }
218 
219     /* Write all ones to determine which bits are held to zero */
220     AllOnes = MAXULONG;
221     Size = HalSetBusDataByOffset(PCIConfiguration,
222                                  DeviceExtension->PciDevice->BusNumber,
223                                  DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
224                                  &AllOnes,
225                                  Offset,
226                                  sizeof(ULONG));
227     if (Size != sizeof(ULONG))
228     {
229         DPRINT1("Wrong size %lu\n", Size);
230         return FALSE;
231     }
232 
233     /* Get the range length */
234     Size = HalGetBusDataByOffset(PCIConfiguration,
235                                  DeviceExtension->PciDevice->BusNumber,
236                                  DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
237                                  NewValue,
238                                  Offset,
239                                  sizeof(ULONG));
240     if (Size != sizeof(ULONG))
241     {
242         DPRINT1("Wrong size %lu\n", Size);
243         return FALSE;
244     }
245 
246     /* Restore original value */
247     Size = HalSetBusDataByOffset(PCIConfiguration,
248                                  DeviceExtension->PciDevice->BusNumber,
249                                  DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
250                                  OriginalValue,
251                                  Offset,
252                                  sizeof(ULONG));
253     if (Size != sizeof(ULONG))
254     {
255         DPRINT1("Wrong size %lu\n", Size);
256         return FALSE;
257     }
258 
259     return TRUE;
260 }
261 
262 static BOOLEAN
263 PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
264                   UCHAR Bar,
265                   PULONGLONG Base,
266                   PULONGLONG Length,
267                   PULONG Flags,
268                   PUCHAR NextBar,
269                   PULONGLONG MaximumAddress)
270 {
271     union {
272         struct {
273             ULONG Bar0;
274             ULONG Bar1;
275         } Bars;
276         ULONGLONG Bar;
277     } OriginalValue;
278     union {
279         struct {
280             ULONG Bar0;
281             ULONG Bar1;
282         } Bars;
283         ULONGLONG Bar;
284     } NewValue;
285     ULONG Offset;
286     ULONGLONG Size;
287 
288     /* Compute the offset of this BAR in PCI config space */
289     Offset = 0x10 + Bar * 4;
290 
291     /* Assume this is a 32-bit BAR until we find wrong */
292     *NextBar = Bar + 1;
293 
294     /* Initialize BAR values to zero */
295     OriginalValue.Bar = 0ULL;
296     NewValue.Bar = 0ULL;
297 
298     /* Read the first BAR */
299     if (!PdoReadPciBar(DeviceExtension, Offset,
300                        &OriginalValue.Bars.Bar0,
301                        &NewValue.Bars.Bar0))
302     {
303         return FALSE;
304     }
305 
306     /* Check if this is a memory BAR */
307     if (!(OriginalValue.Bars.Bar0 & PCI_ADDRESS_IO_SPACE))
308     {
309         /* Write the maximum address if the caller asked for it */
310         if (MaximumAddress != NULL)
311         {
312             if ((OriginalValue.Bars.Bar0 & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_32BIT)
313             {
314                 *MaximumAddress = 0x00000000FFFFFFFFULL;
315             }
316             else if ((OriginalValue.Bars.Bar0 & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
317             {
318                 *MaximumAddress = 0x00000000000FFFFFULL;
319             }
320             else if ((OriginalValue.Bars.Bar0 & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
321             {
322                 *MaximumAddress = 0xFFFFFFFFFFFFFFFFULL;
323             }
324         }
325 
326         /* Check if this is a 64-bit BAR */
327         if ((OriginalValue.Bars.Bar0 & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
328         {
329             /* We've now consumed the next BAR too */
330             *NextBar = Bar + 2;
331 
332             /* Read the next BAR */
333             if (!PdoReadPciBar(DeviceExtension, Offset + 4,
334                                &OriginalValue.Bars.Bar1,
335                                &NewValue.Bars.Bar1))
336             {
337                 return FALSE;
338             }
339         }
340     }
341     else
342     {
343         /* Write the maximum I/O port address */
344         if (MaximumAddress != NULL)
345         {
346             *MaximumAddress = 0x00000000FFFFFFFFULL;
347         }
348     }
349 
350     if (NewValue.Bar == 0)
351     {
352         DPRINT("Unused address register\n");
353         *Base = 0;
354         *Length = 0;
355         *Flags = 0;
356         return TRUE;
357     }
358 
359     *Base = ((OriginalValue.Bar & PCI_ADDRESS_IO_SPACE)
360              ? (OriginalValue.Bar & PCI_ADDRESS_IO_ADDRESS_MASK_64)
361              : (OriginalValue.Bar & PCI_ADDRESS_MEMORY_ADDRESS_MASK_64));
362 
363     Size = (NewValue.Bar & PCI_ADDRESS_IO_SPACE)
364            ? (NewValue.Bar & PCI_ADDRESS_IO_ADDRESS_MASK_64)
365            : (NewValue.Bar & PCI_ADDRESS_MEMORY_ADDRESS_MASK_64);
366     *Length = Size & ~(Size - 1);
367 
368     *Flags = (NewValue.Bar & PCI_ADDRESS_IO_SPACE)
369              ? (NewValue.Bar & ~PCI_ADDRESS_IO_ADDRESS_MASK_64)
370              : (NewValue.Bar & ~PCI_ADDRESS_MEMORY_ADDRESS_MASK_64);
371 
372     return TRUE;
373 }
374 
375 
376 static NTSTATUS
377 PdoQueryResourceRequirements(
378     IN PDEVICE_OBJECT DeviceObject,
379     IN PIRP Irp,
380     PIO_STACK_LOCATION IrpSp)
381 {
382     PPDO_DEVICE_EXTENSION DeviceExtension;
383     PCI_COMMON_CONFIG PciConfig;
384     PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
385     PIO_RESOURCE_DESCRIPTOR Descriptor;
386     ULONG Size;
387     ULONG ResCount = 0;
388     ULONG ListSize;
389     UCHAR Bar;
390     ULONGLONG Base;
391     ULONGLONG Length;
392     ULONG Flags;
393     ULONGLONG MaximumAddress;
394 
395     UNREFERENCED_PARAMETER(IrpSp);
396     DPRINT("PdoQueryResourceRequirements() called\n");
397 
398     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
399 
400     /* Get PCI configuration space */
401     Size= HalGetBusData(PCIConfiguration,
402                         DeviceExtension->PciDevice->BusNumber,
403                         DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
404                         &PciConfig,
405                         PCI_COMMON_HDR_LENGTH);
406     DPRINT("Size %lu\n", Size);
407     if (Size < PCI_COMMON_HDR_LENGTH)
408     {
409         Irp->IoStatus.Information = 0;
410         return STATUS_UNSUCCESSFUL;
411     }
412 
413     DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
414 
415     /* Count required resource descriptors */
416     ResCount = 0;
417     if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
418     {
419         for (Bar = 0; Bar < PCI_TYPE0_ADDRESSES;)
420         {
421             if (!PdoGetRangeLength(DeviceExtension,
422                                    Bar,
423                                    &Base,
424                                    &Length,
425                                    &Flags,
426                                    &Bar,
427                                    NULL))
428                 break;
429 
430             if (Length != 0)
431                 ResCount += 2;
432         }
433 
434         /* FIXME: Check ROM address */
435 
436         if (PciConfig.u.type0.InterruptPin != 0)
437             ResCount++;
438     }
439     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
440     {
441         for (Bar = 0; Bar < PCI_TYPE1_ADDRESSES;)
442         {
443             if (!PdoGetRangeLength(DeviceExtension,
444                                    Bar,
445                                    &Base,
446                                    &Length,
447                                    &Flags,
448                                    &Bar,
449                                    NULL))
450                 break;
451 
452             if (Length != 0)
453                 ResCount += 2;
454         }
455 
456         if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
457             ResCount++;
458     }
459     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
460     {
461         /* FIXME: Count Cardbus bridge resources */
462     }
463     else
464     {
465         DPRINT1("Unsupported header type %d\n", PCI_CONFIGURATION_TYPE(&PciConfig));
466     }
467 
468     if (ResCount == 0)
469     {
470         Irp->IoStatus.Information = 0;
471         return STATUS_SUCCESS;
472     }
473 
474     /* Calculate the resource list size */
475     ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List[0].Descriptors) +
476                ResCount * sizeof(IO_RESOURCE_DESCRIPTOR);
477 
478     DPRINT("ListSize %lu (0x%lx)\n", ListSize, ListSize);
479 
480     /* Allocate the resource requirements list */
481     ResourceList = ExAllocatePoolWithTag(PagedPool,
482                                          ListSize,
483                                          TAG_PCI);
484     if (ResourceList == NULL)
485     {
486         Irp->IoStatus.Information = 0;
487         return STATUS_INSUFFICIENT_RESOURCES;
488     }
489 
490     RtlZeroMemory(ResourceList, ListSize);
491     ResourceList->ListSize = ListSize;
492     ResourceList->InterfaceType = PCIBus;
493     ResourceList->BusNumber = DeviceExtension->PciDevice->BusNumber;
494     ResourceList->SlotNumber = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
495     ResourceList->AlternativeLists = 1;
496 
497     ResourceList->List[0].Version = 1;
498     ResourceList->List[0].Revision = 1;
499     ResourceList->List[0].Count = ResCount;
500 
501     Descriptor = &ResourceList->List[0].Descriptors[0];
502     if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
503     {
504         for (Bar = 0; Bar < PCI_TYPE0_ADDRESSES;)
505         {
506             if (!PdoGetRangeLength(DeviceExtension,
507                                    Bar,
508                                    &Base,
509                                    &Length,
510                                    &Flags,
511                                    &Bar,
512                                    &MaximumAddress))
513             {
514                 DPRINT1("PdoGetRangeLength() failed\n");
515                 break;
516             }
517 
518             if (Length == 0)
519             {
520                 DPRINT("Unused address register\n");
521                 continue;
522             }
523 
524             /* Set preferred descriptor */
525             Descriptor->Option = IO_RESOURCE_PREFERRED;
526             if (Flags & PCI_ADDRESS_IO_SPACE)
527             {
528                 Descriptor->Type = CmResourceTypePort;
529                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
530                 Descriptor->Flags = CM_RESOURCE_PORT_IO |
531                                     CM_RESOURCE_PORT_16_BIT_DECODE |
532                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
533 
534                 Descriptor->u.Port.Length = Length;
535                 Descriptor->u.Port.Alignment = 1;
536                 Descriptor->u.Port.MinimumAddress.QuadPart = Base;
537                 Descriptor->u.Port.MaximumAddress.QuadPart = Base + Length - 1;
538             }
539             else
540             {
541                 Descriptor->Type = CmResourceTypeMemory;
542                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
543                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
544                     (Flags & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? CM_RESOURCE_MEMORY_PREFETCHABLE : 0;
545 
546                 Descriptor->u.Memory.Length = Length;
547                 Descriptor->u.Memory.Alignment = 1;
548                 Descriptor->u.Memory.MinimumAddress.QuadPart = Base;
549                 Descriptor->u.Memory.MaximumAddress.QuadPart = Base + Length - 1;
550             }
551             Descriptor++;
552 
553             /* Set alternative descriptor */
554             Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
555             if (Flags & PCI_ADDRESS_IO_SPACE)
556             {
557                 Descriptor->Type = CmResourceTypePort;
558                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
559                 Descriptor->Flags = CM_RESOURCE_PORT_IO |
560                                     CM_RESOURCE_PORT_16_BIT_DECODE |
561                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
562 
563                 Descriptor->u.Port.Length = Length;
564                 Descriptor->u.Port.Alignment = Length;
565                 Descriptor->u.Port.MinimumAddress.QuadPart = 0;
566                 Descriptor->u.Port.MaximumAddress.QuadPart = MaximumAddress;
567             }
568             else
569             {
570                 Descriptor->Type = CmResourceTypeMemory;
571                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
572                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
573                     (Flags & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? CM_RESOURCE_MEMORY_PREFETCHABLE : 0;
574 
575                 Descriptor->u.Memory.Length = Length;
576                 Descriptor->u.Memory.Alignment = Length;
577                 Descriptor->u.Port.MinimumAddress.QuadPart = 0;
578                 Descriptor->u.Port.MaximumAddress.QuadPart = MaximumAddress;
579             }
580             Descriptor++;
581         }
582 
583         /* FIXME: Check ROM address */
584 
585         if (PciConfig.u.type0.InterruptPin != 0)
586         {
587             Descriptor->Option = 0; /* Required */
588             Descriptor->Type = CmResourceTypeInterrupt;
589             Descriptor->ShareDisposition = CmResourceShareShared;
590             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
591 
592             Descriptor->u.Interrupt.MinimumVector = 0;
593             Descriptor->u.Interrupt.MaximumVector = 0xFF;
594         }
595     }
596     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
597     {
598         for (Bar = 0; Bar < PCI_TYPE1_ADDRESSES;)
599         {
600             if (!PdoGetRangeLength(DeviceExtension,
601                                    Bar,
602                                    &Base,
603                                    &Length,
604                                    &Flags,
605                                    &Bar,
606                                    &MaximumAddress))
607             {
608                 DPRINT1("PdoGetRangeLength() failed\n");
609                 break;
610             }
611 
612             if (Length == 0)
613             {
614                 DPRINT("Unused address register\n");
615                 continue;
616             }
617 
618             /* Set preferred descriptor */
619             Descriptor->Option = IO_RESOURCE_PREFERRED;
620             if (Flags & PCI_ADDRESS_IO_SPACE)
621             {
622                 Descriptor->Type = CmResourceTypePort;
623                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
624                 Descriptor->Flags = CM_RESOURCE_PORT_IO |
625                                     CM_RESOURCE_PORT_16_BIT_DECODE |
626                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
627 
628                 Descriptor->u.Port.Length = Length;
629                 Descriptor->u.Port.Alignment = 1;
630                 Descriptor->u.Port.MinimumAddress.QuadPart = Base;
631                 Descriptor->u.Port.MaximumAddress.QuadPart = Base + Length - 1;
632             }
633             else
634             {
635                 Descriptor->Type = CmResourceTypeMemory;
636                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
637                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
638                     (Flags & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? CM_RESOURCE_MEMORY_PREFETCHABLE : 0;
639 
640                 Descriptor->u.Memory.Length = Length;
641                 Descriptor->u.Memory.Alignment = 1;
642                 Descriptor->u.Memory.MinimumAddress.QuadPart = Base;
643                 Descriptor->u.Memory.MaximumAddress.QuadPart = Base + Length - 1;
644             }
645             Descriptor++;
646 
647             /* Set alternative descriptor */
648             Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
649             if (Flags & PCI_ADDRESS_IO_SPACE)
650             {
651                 Descriptor->Type = CmResourceTypePort;
652                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
653                 Descriptor->Flags = CM_RESOURCE_PORT_IO |
654                                     CM_RESOURCE_PORT_16_BIT_DECODE |
655                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
656 
657                 Descriptor->u.Port.Length = Length;
658                 Descriptor->u.Port.Alignment = Length;
659                 Descriptor->u.Port.MinimumAddress.QuadPart = 0;
660                 Descriptor->u.Port.MaximumAddress.QuadPart = MaximumAddress;
661             }
662             else
663             {
664                 Descriptor->Type = CmResourceTypeMemory;
665                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
666                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
667                     (Flags & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? CM_RESOURCE_MEMORY_PREFETCHABLE : 0;
668 
669                 Descriptor->u.Memory.Length = Length;
670                 Descriptor->u.Memory.Alignment = Length;
671                 Descriptor->u.Port.MinimumAddress.QuadPart = 0;
672                 Descriptor->u.Port.MaximumAddress.QuadPart = MaximumAddress;
673             }
674             Descriptor++;
675         }
676 
677         if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
678         {
679             Descriptor->Option = 0; /* Required */
680             Descriptor->Type = CmResourceTypeBusNumber;
681             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
682 
683             ResourceList->BusNumber =
684             Descriptor->u.BusNumber.MinBusNumber =
685             Descriptor->u.BusNumber.MaxBusNumber = DeviceExtension->PciDevice->PciConfig.u.type1.SecondaryBus;
686             Descriptor->u.BusNumber.Length = 1;
687             Descriptor->u.BusNumber.Reserved = 0;
688         }
689     }
690     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
691     {
692         /* FIXME: Add Cardbus bridge resources */
693     }
694 
695     Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
696 
697     return STATUS_SUCCESS;
698 }
699 
700 
701 static NTSTATUS
702 PdoQueryResources(
703     IN PDEVICE_OBJECT DeviceObject,
704     IN PIRP Irp,
705     PIO_STACK_LOCATION IrpSp)
706 {
707     PPDO_DEVICE_EXTENSION DeviceExtension;
708     PCI_COMMON_CONFIG PciConfig;
709     PCM_RESOURCE_LIST ResourceList;
710     PCM_PARTIAL_RESOURCE_LIST PartialList;
711     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
712     ULONG Size;
713     ULONG ResCount = 0;
714     ULONG ListSize;
715     UCHAR Bar;
716     ULONGLONG Base;
717     ULONGLONG Length;
718     ULONG Flags;
719 
720     DPRINT("PdoQueryResources() called\n");
721 
722     UNREFERENCED_PARAMETER(IrpSp);
723     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
724 
725     /* Get PCI configuration space */
726     Size= HalGetBusData(PCIConfiguration,
727                         DeviceExtension->PciDevice->BusNumber,
728                         DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
729                         &PciConfig,
730                         PCI_COMMON_HDR_LENGTH);
731     DPRINT("Size %lu\n", Size);
732     if (Size < PCI_COMMON_HDR_LENGTH)
733     {
734         Irp->IoStatus.Information = 0;
735         return STATUS_UNSUCCESSFUL;
736     }
737 
738     DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
739 
740     /* Count required resource descriptors */
741     ResCount = 0;
742     if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
743     {
744         for (Bar = 0; Bar < PCI_TYPE0_ADDRESSES;)
745         {
746             if (!PdoGetRangeLength(DeviceExtension,
747                                    Bar,
748                                    &Base,
749                                    &Length,
750                                    &Flags,
751                                    &Bar,
752                                    NULL))
753                 break;
754 
755             if (Length)
756                 ResCount++;
757         }
758 
759         if ((PciConfig.u.type0.InterruptPin != 0) &&
760             (PciConfig.u.type0.InterruptLine != 0) &&
761             (PciConfig.u.type0.InterruptLine != 0xFF))
762             ResCount++;
763     }
764     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
765     {
766         for (Bar = 0; Bar < PCI_TYPE1_ADDRESSES;)
767         {
768             if (!PdoGetRangeLength(DeviceExtension,
769                                    Bar,
770                                    &Base,
771                                    &Length,
772                                    &Flags,
773                                    &Bar,
774                                    NULL))
775                 break;
776 
777             if (Length != 0)
778                 ResCount++;
779         }
780 
781         if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
782             ResCount++;
783     }
784     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
785     {
786         /* FIXME: Count Cardbus bridge resources */
787     }
788     else
789     {
790         DPRINT1("Unsupported header type %d\n", PCI_CONFIGURATION_TYPE(&PciConfig));
791     }
792 
793     if (ResCount == 0)
794     {
795         Irp->IoStatus.Information = 0;
796         return STATUS_SUCCESS;
797     }
798 
799     /* Calculate the resource list size */
800     ListSize = FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.PartialDescriptors) +
801                ResCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
802 
803     /* Allocate the resource list */
804     ResourceList = ExAllocatePoolWithTag(PagedPool,
805                                          ListSize,
806                                          TAG_PCI);
807     if (ResourceList == NULL)
808         return STATUS_INSUFFICIENT_RESOURCES;
809 
810     RtlZeroMemory(ResourceList, ListSize);
811     ResourceList->Count = 1;
812     ResourceList->List[0].InterfaceType = PCIBus;
813     ResourceList->List[0].BusNumber = DeviceExtension->PciDevice->BusNumber;
814 
815     PartialList = &ResourceList->List[0].PartialResourceList;
816     PartialList->Version = 1;
817     PartialList->Revision = 1;
818     PartialList->Count = ResCount;
819 
820     Descriptor = &PartialList->PartialDescriptors[0];
821     if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
822     {
823         for (Bar = 0; Bar < PCI_TYPE0_ADDRESSES;)
824         {
825             if (!PdoGetRangeLength(DeviceExtension,
826                                    Bar,
827                                    &Base,
828                                    &Length,
829                                    &Flags,
830                                    &Bar,
831                                    NULL))
832                 break;
833 
834             if (Length == 0)
835             {
836                 DPRINT("Unused address register\n");
837                 continue;
838             }
839 
840             if (Flags & PCI_ADDRESS_IO_SPACE)
841             {
842                 Descriptor->Type = CmResourceTypePort;
843                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
844                 Descriptor->Flags = CM_RESOURCE_PORT_IO |
845                                     CM_RESOURCE_PORT_16_BIT_DECODE |
846                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
847                 Descriptor->u.Port.Start.QuadPart = (ULONGLONG)Base;
848                 Descriptor->u.Port.Length = Length;
849 
850                 /* Enable IO space access */
851                 DeviceExtension->PciDevice->EnableIoSpace = TRUE;
852             }
853             else
854             {
855                 Descriptor->Type = CmResourceTypeMemory;
856                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
857                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
858                     (Flags & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? CM_RESOURCE_MEMORY_PREFETCHABLE : 0;
859                 Descriptor->u.Memory.Start.QuadPart = (ULONGLONG)Base;
860                 Descriptor->u.Memory.Length = Length;
861 
862                 /* Enable memory space access */
863                 DeviceExtension->PciDevice->EnableMemorySpace = TRUE;
864             }
865 
866             Descriptor++;
867         }
868 
869         /* Add interrupt resource */
870         if ((PciConfig.u.type0.InterruptPin != 0) &&
871             (PciConfig.u.type0.InterruptLine != 0) &&
872             (PciConfig.u.type0.InterruptLine != 0xFF))
873         {
874             Descriptor->Type = CmResourceTypeInterrupt;
875             Descriptor->ShareDisposition = CmResourceShareShared;
876             Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
877             Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
878             Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
879             Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
880         }
881 
882         /* Allow bus master mode */
883        DeviceExtension->PciDevice->EnableBusMaster = TRUE;
884     }
885     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
886     {
887         for (Bar = 0; Bar < PCI_TYPE1_ADDRESSES;)
888         {
889             if (!PdoGetRangeLength(DeviceExtension,
890                                    Bar,
891                                    &Base,
892                                    &Length,
893                                    &Flags,
894                                    &Bar,
895                                    NULL))
896                 break;
897 
898             if (Length == 0)
899             {
900                 DPRINT("Unused address register\n");
901                 continue;
902             }
903 
904             if (Flags & PCI_ADDRESS_IO_SPACE)
905             {
906                 Descriptor->Type = CmResourceTypePort;
907                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
908                 Descriptor->Flags = CM_RESOURCE_PORT_IO |
909                                     CM_RESOURCE_PORT_16_BIT_DECODE |
910                                     CM_RESOURCE_PORT_POSITIVE_DECODE;
911                 Descriptor->u.Port.Start.QuadPart = (ULONGLONG)Base;
912                 Descriptor->u.Port.Length = Length;
913 
914                 /* Enable IO space access */
915                 DeviceExtension->PciDevice->EnableIoSpace = TRUE;
916             }
917             else
918             {
919                 Descriptor->Type = CmResourceTypeMemory;
920                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
921                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE |
922                     (Flags & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? CM_RESOURCE_MEMORY_PREFETCHABLE : 0;
923                 Descriptor->u.Memory.Start.QuadPart = (ULONGLONG)Base;
924                 Descriptor->u.Memory.Length = Length;
925 
926                 /* Enable memory space access */
927                 DeviceExtension->PciDevice->EnableMemorySpace = TRUE;
928             }
929 
930             Descriptor++;
931         }
932 
933         if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
934         {
935             Descriptor->Type = CmResourceTypeBusNumber;
936             Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
937 
938             ResourceList->List[0].BusNumber =
939             Descriptor->u.BusNumber.Start = DeviceExtension->PciDevice->PciConfig.u.type1.SecondaryBus;
940             Descriptor->u.BusNumber.Length = 1;
941             Descriptor->u.BusNumber.Reserved = 0;
942         }
943     }
944     else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
945     {
946         /* FIXME: Add Cardbus bridge resources */
947     }
948 
949     Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
950 
951     return STATUS_SUCCESS;
952 }
953 
954 
955 static VOID NTAPI
956 InterfaceReference(
957     IN PVOID Context)
958 {
959     PPDO_DEVICE_EXTENSION DeviceExtension;
960 
961     DPRINT("InterfaceReference(%p)\n", Context);
962 
963     DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
964     InterlockedIncrement(&DeviceExtension->References);
965 }
966 
967 
968 static VOID NTAPI
969 InterfaceDereference(
970     IN PVOID Context)
971 {
972     PPDO_DEVICE_EXTENSION DeviceExtension;
973 
974     DPRINT("InterfaceDereference(%p)\n", Context);
975 
976     DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
977     InterlockedDecrement(&DeviceExtension->References);
978 }
979 
980 static TRANSLATE_BUS_ADDRESS InterfaceBusTranslateBusAddress;
981 
982 static
983 BOOLEAN
984 NTAPI
985 InterfaceBusTranslateBusAddress(
986     IN PVOID Context,
987     IN PHYSICAL_ADDRESS BusAddress,
988     IN ULONG Length,
989     IN OUT PULONG AddressSpace,
990     OUT PPHYSICAL_ADDRESS TranslatedAddress)
991 {
992     PPDO_DEVICE_EXTENSION DeviceExtension;
993 
994     DPRINT("InterfaceBusTranslateBusAddress(%p %p 0x%lx %p %p)\n",
995            Context, BusAddress, Length, AddressSpace, TranslatedAddress);
996 
997     DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
998 
999     return HalTranslateBusAddress(PCIBus,
1000                                   DeviceExtension->PciDevice->BusNumber,
1001                                   BusAddress,
1002                                   AddressSpace,
1003                                   TranslatedAddress);
1004 }
1005 
1006 static GET_DMA_ADAPTER InterfaceBusGetDmaAdapter;
1007 
1008 static
1009 PDMA_ADAPTER
1010 NTAPI
1011 InterfaceBusGetDmaAdapter(
1012     IN PVOID Context,
1013     IN PDEVICE_DESCRIPTION DeviceDescription,
1014     OUT PULONG NumberOfMapRegisters)
1015 {
1016     DPRINT("InterfaceBusGetDmaAdapter(%p %p %p)\n",
1017            Context, DeviceDescription, NumberOfMapRegisters);
1018     return (PDMA_ADAPTER)HalGetAdapter(DeviceDescription, NumberOfMapRegisters);
1019 }
1020 
1021 static GET_SET_DEVICE_DATA InterfaceBusSetBusData;
1022 
1023 static
1024 ULONG
1025 NTAPI
1026 InterfaceBusSetBusData(
1027     IN PVOID Context,
1028     IN ULONG DataType,
1029     IN PVOID Buffer,
1030     IN ULONG Offset,
1031     IN ULONG Length)
1032 {
1033     PPDO_DEVICE_EXTENSION DeviceExtension;
1034     ULONG Size;
1035 
1036     DPRINT("InterfaceBusSetBusData(%p 0x%lx %p 0x%lx 0x%lx)\n",
1037            Context, DataType, Buffer, Offset, Length);
1038 
1039     if (DataType != PCI_WHICHSPACE_CONFIG)
1040     {
1041         DPRINT("Unknown DataType %lu\n", DataType);
1042         return 0;
1043     }
1044 
1045     DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
1046 
1047     /* Get PCI configuration space */
1048     Size = HalSetBusDataByOffset(PCIConfiguration,
1049                                  DeviceExtension->PciDevice->BusNumber,
1050                                  DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1051                                  Buffer,
1052                                  Offset,
1053                                  Length);
1054     return Size;
1055 }
1056 
1057 static GET_SET_DEVICE_DATA InterfaceBusGetBusData;
1058 
1059 static
1060 ULONG
1061 NTAPI
1062 InterfaceBusGetBusData(
1063     IN PVOID Context,
1064     IN ULONG DataType,
1065     IN PVOID Buffer,
1066     IN ULONG Offset,
1067     IN ULONG Length)
1068 {
1069     PPDO_DEVICE_EXTENSION DeviceExtension;
1070     ULONG Size;
1071 
1072     DPRINT("InterfaceBusGetBusData(%p 0x%lx %p 0x%lx 0x%lx) called\n",
1073            Context, DataType, Buffer, Offset, Length);
1074 
1075     if (DataType != PCI_WHICHSPACE_CONFIG)
1076     {
1077         DPRINT("Unknown DataType %lu\n", DataType);
1078         return 0;
1079     }
1080 
1081     DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
1082 
1083     /* Get PCI configuration space */
1084     Size = HalGetBusDataByOffset(PCIConfiguration,
1085                                  DeviceExtension->PciDevice->BusNumber,
1086                                  DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1087                                  Buffer,
1088                                  Offset,
1089                                  Length);
1090     return Size;
1091 }
1092 
1093 
1094 static BOOLEAN NTAPI
1095 InterfacePciDevicePresent(
1096     IN USHORT VendorID,
1097     IN USHORT DeviceID,
1098     IN UCHAR RevisionID,
1099     IN USHORT SubVendorID,
1100     IN USHORT SubSystemID,
1101     IN ULONG Flags)
1102 {
1103     PFDO_DEVICE_EXTENSION FdoDeviceExtension;
1104     PPCI_DEVICE PciDevice;
1105     PLIST_ENTRY CurrentBus, CurrentEntry;
1106     KIRQL OldIrql;
1107     BOOLEAN Found = FALSE;
1108 
1109     KeAcquireSpinLock(&DriverExtension->BusListLock, &OldIrql);
1110     CurrentBus = DriverExtension->BusListHead.Flink;
1111     while (!Found && CurrentBus != &DriverExtension->BusListHead)
1112     {
1113         FdoDeviceExtension = CONTAINING_RECORD(CurrentBus, FDO_DEVICE_EXTENSION, ListEntry);
1114 
1115         KeAcquireSpinLockAtDpcLevel(&FdoDeviceExtension->DeviceListLock);
1116         CurrentEntry = FdoDeviceExtension->DeviceListHead.Flink;
1117         while (!Found && CurrentEntry != &FdoDeviceExtension->DeviceListHead)
1118         {
1119             PciDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
1120             if (PciDevice->PciConfig.VendorID == VendorID &&
1121                 PciDevice->PciConfig.DeviceID == DeviceID)
1122             {
1123                 if (!(Flags & PCI_USE_SUBSYSTEM_IDS) ||
1124                     (PciDevice->PciConfig.u.type0.SubVendorID == SubVendorID &&
1125                      PciDevice->PciConfig.u.type0.SubSystemID == SubSystemID))
1126                 {
1127                     if (!(Flags & PCI_USE_REVISION) ||
1128                         PciDevice->PciConfig.RevisionID == RevisionID)
1129                     {
1130                         DPRINT("Found the PCI device\n");
1131                         Found = TRUE;
1132                     }
1133                 }
1134             }
1135 
1136             CurrentEntry = CurrentEntry->Flink;
1137         }
1138 
1139         KeReleaseSpinLockFromDpcLevel(&FdoDeviceExtension->DeviceListLock);
1140         CurrentBus = CurrentBus->Flink;
1141     }
1142     KeReleaseSpinLock(&DriverExtension->BusListLock, OldIrql);
1143 
1144     return Found;
1145 }
1146 
1147 
1148 static BOOLEAN
1149 CheckPciDevice(
1150     IN PPCI_COMMON_CONFIG PciConfig,
1151     IN PPCI_DEVICE_PRESENCE_PARAMETERS Parameters)
1152 {
1153     if ((Parameters->Flags & PCI_USE_VENDEV_IDS) &&
1154         (PciConfig->VendorID != Parameters->VendorID ||
1155          PciConfig->DeviceID != Parameters->DeviceID))
1156     {
1157         return FALSE;
1158     }
1159 
1160     if ((Parameters->Flags & PCI_USE_CLASS_SUBCLASS) &&
1161         (PciConfig->BaseClass != Parameters->BaseClass ||
1162          PciConfig->SubClass != Parameters->SubClass))
1163     {
1164         return FALSE;
1165     }
1166 
1167     if ((Parameters->Flags & PCI_USE_PROGIF) &&
1168          PciConfig->ProgIf != Parameters->ProgIf)
1169     {
1170         return FALSE;
1171     }
1172 
1173     if ((Parameters->Flags & PCI_USE_SUBSYSTEM_IDS) &&
1174         (PciConfig->u.type0.SubVendorID != Parameters->SubVendorID ||
1175          PciConfig->u.type0.SubSystemID != Parameters->SubSystemID))
1176     {
1177         return FALSE;
1178     }
1179 
1180     if ((Parameters->Flags & PCI_USE_REVISION) &&
1181         PciConfig->RevisionID != Parameters->RevisionID)
1182     {
1183         return FALSE;
1184     }
1185 
1186     return TRUE;
1187 }
1188 
1189 
1190 static BOOLEAN NTAPI
1191 InterfacePciDevicePresentEx(
1192     IN PVOID Context,
1193     IN PPCI_DEVICE_PRESENCE_PARAMETERS Parameters)
1194 {
1195     PPDO_DEVICE_EXTENSION DeviceExtension;
1196     PFDO_DEVICE_EXTENSION MyFdoDeviceExtension;
1197     PFDO_DEVICE_EXTENSION FdoDeviceExtension;
1198     PPCI_DEVICE PciDevice;
1199     PLIST_ENTRY CurrentBus, CurrentEntry;
1200     KIRQL OldIrql;
1201     BOOLEAN Found = FALSE;
1202 
1203     DPRINT("InterfacePciDevicePresentEx(%p %p) called\n",
1204            Context, Parameters);
1205 
1206     if (!Parameters || Parameters->Size != sizeof(PCI_DEVICE_PRESENCE_PARAMETERS))
1207         return FALSE;
1208 
1209     DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
1210     MyFdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
1211 
1212     if (Parameters->Flags & PCI_USE_LOCAL_DEVICE)
1213     {
1214         return CheckPciDevice(&DeviceExtension->PciDevice->PciConfig, Parameters);
1215     }
1216 
1217     KeAcquireSpinLock(&DriverExtension->BusListLock, &OldIrql);
1218     CurrentBus = DriverExtension->BusListHead.Flink;
1219     while (!Found && CurrentBus != &DriverExtension->BusListHead)
1220     {
1221         FdoDeviceExtension = CONTAINING_RECORD(CurrentBus, FDO_DEVICE_EXTENSION, ListEntry);
1222         if (!(Parameters->Flags & PCI_USE_LOCAL_BUS) || FdoDeviceExtension == MyFdoDeviceExtension)
1223         {
1224             KeAcquireSpinLockAtDpcLevel(&FdoDeviceExtension->DeviceListLock);
1225             CurrentEntry = FdoDeviceExtension->DeviceListHead.Flink;
1226             while (!Found && CurrentEntry != &FdoDeviceExtension->DeviceListHead)
1227             {
1228                 PciDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
1229 
1230                 if (CheckPciDevice(&PciDevice->PciConfig, Parameters))
1231                 {
1232                     DPRINT("Found the PCI device\n");
1233                     Found = TRUE;
1234                 }
1235 
1236                 CurrentEntry = CurrentEntry->Flink;
1237             }
1238 
1239             KeReleaseSpinLockFromDpcLevel(&FdoDeviceExtension->DeviceListLock);
1240         }
1241         CurrentBus = CurrentBus->Flink;
1242     }
1243     KeReleaseSpinLock(&DriverExtension->BusListLock, OldIrql);
1244 
1245     return Found;
1246 }
1247 
1248 
1249 static NTSTATUS
1250 PdoQueryInterface(
1251     IN PDEVICE_OBJECT DeviceObject,
1252     IN PIRP Irp,
1253     PIO_STACK_LOCATION IrpSp)
1254 {
1255     NTSTATUS Status;
1256 
1257     UNREFERENCED_PARAMETER(Irp);
1258 
1259     if (RtlCompareMemory(IrpSp->Parameters.QueryInterface.InterfaceType,
1260                          &GUID_BUS_INTERFACE_STANDARD, sizeof(GUID)) == sizeof(GUID))
1261     {
1262         /* BUS_INTERFACE_STANDARD */
1263         if (IrpSp->Parameters.QueryInterface.Version < 1)
1264             Status = STATUS_NOT_SUPPORTED;
1265         else if (IrpSp->Parameters.QueryInterface.Size < sizeof(BUS_INTERFACE_STANDARD))
1266             Status = STATUS_BUFFER_TOO_SMALL;
1267         else
1268         {
1269             PBUS_INTERFACE_STANDARD BusInterface;
1270             BusInterface = (PBUS_INTERFACE_STANDARD)IrpSp->Parameters.QueryInterface.Interface;
1271             BusInterface->Size = sizeof(BUS_INTERFACE_STANDARD);
1272             BusInterface->Version = 1;
1273             BusInterface->TranslateBusAddress = InterfaceBusTranslateBusAddress;
1274             BusInterface->GetDmaAdapter = InterfaceBusGetDmaAdapter;
1275             BusInterface->SetBusData = InterfaceBusSetBusData;
1276             BusInterface->GetBusData = InterfaceBusGetBusData;
1277             Status = STATUS_SUCCESS;
1278         }
1279     }
1280     else if (RtlCompareMemory(IrpSp->Parameters.QueryInterface.InterfaceType,
1281                               &GUID_PCI_DEVICE_PRESENT_INTERFACE, sizeof(GUID)) == sizeof(GUID))
1282     {
1283         /* PCI_DEVICE_PRESENT_INTERFACE */
1284         if (IrpSp->Parameters.QueryInterface.Version < 1)
1285             Status = STATUS_NOT_SUPPORTED;
1286         else if (IrpSp->Parameters.QueryInterface.Size < sizeof(PCI_DEVICE_PRESENT_INTERFACE))
1287             Status = STATUS_BUFFER_TOO_SMALL;
1288         else
1289         {
1290             PPCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface;
1291             PciDevicePresentInterface = (PPCI_DEVICE_PRESENT_INTERFACE)IrpSp->Parameters.QueryInterface.Interface;
1292             PciDevicePresentInterface->Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
1293             PciDevicePresentInterface->Version = 1;
1294             PciDevicePresentInterface->IsDevicePresent = InterfacePciDevicePresent;
1295             PciDevicePresentInterface->IsDevicePresentEx = InterfacePciDevicePresentEx;
1296             Status = STATUS_SUCCESS;
1297         }
1298     }
1299     else
1300     {
1301         /* Not a supported interface */
1302         return STATUS_NOT_SUPPORTED;
1303     }
1304 
1305     if (NT_SUCCESS(Status))
1306     {
1307         /* Add a reference for the returned interface */
1308         PINTERFACE Interface;
1309         Interface = (PINTERFACE)IrpSp->Parameters.QueryInterface.Interface;
1310         Interface->Context = DeviceObject;
1311         Interface->InterfaceReference = InterfaceReference;
1312         Interface->InterfaceDereference = InterfaceDereference;
1313         Interface->InterfaceReference(Interface->Context);
1314     }
1315 
1316     return Status;
1317 }
1318 
1319 static NTSTATUS
1320 PdoStartDevice(
1321     IN PDEVICE_OBJECT DeviceObject,
1322     IN PIRP Irp,
1323     PIO_STACK_LOCATION IrpSp)
1324 {
1325     PCM_RESOURCE_LIST RawResList = IrpSp->Parameters.StartDevice.AllocatedResources;
1326     PCM_FULL_RESOURCE_DESCRIPTOR RawFullDesc;
1327     PCM_PARTIAL_RESOURCE_DESCRIPTOR RawPartialDesc;
1328     ULONG i, ii;
1329     PPDO_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1330     UCHAR Irq;
1331     USHORT Command;
1332 
1333     UNREFERENCED_PARAMETER(Irp);
1334 
1335     if (!RawResList)
1336         return STATUS_SUCCESS;
1337 
1338     /* TODO: Assign the other resources we get to the card */
1339 
1340     RawFullDesc = &RawResList->List[0];
1341     for (i = 0; i < RawResList->Count; i++, RawFullDesc = CmiGetNextResourceDescriptor(RawFullDesc))
1342     {
1343         for (ii = 0; ii < RawFullDesc->PartialResourceList.Count; ii++)
1344         {
1345             /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
1346                but only one is allowed and it must be the last one in the list! */
1347             RawPartialDesc = &RawFullDesc->PartialResourceList.PartialDescriptors[ii];
1348 
1349             if (RawPartialDesc->Type == CmResourceTypeInterrupt)
1350             {
1351                 DPRINT("Assigning IRQ %u to PCI device 0x%x on bus 0x%x\n",
1352                         RawPartialDesc->u.Interrupt.Vector,
1353                         DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1354                         DeviceExtension->PciDevice->BusNumber);
1355 
1356                 Irq = (UCHAR)RawPartialDesc->u.Interrupt.Vector;
1357                 HalSetBusDataByOffset(PCIConfiguration,
1358                                       DeviceExtension->PciDevice->BusNumber,
1359                                       DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1360                                       &Irq,
1361                                       0x3c /* PCI_INTERRUPT_LINE */,
1362                                       sizeof(UCHAR));
1363             }
1364         }
1365     }
1366 
1367     Command = 0;
1368 
1369     DBGPRINT("pci!PdoStartDevice: Enabling command flags for PCI device 0x%x on bus 0x%x: ",
1370             DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1371             DeviceExtension->PciDevice->BusNumber);
1372     if (DeviceExtension->PciDevice->EnableBusMaster)
1373     {
1374         Command |= PCI_ENABLE_BUS_MASTER;
1375         DBGPRINT("[Bus master] ");
1376     }
1377 
1378     if (DeviceExtension->PciDevice->EnableMemorySpace)
1379     {
1380         Command |= PCI_ENABLE_MEMORY_SPACE;
1381         DBGPRINT("[Memory space enable] ");
1382     }
1383 
1384     if (DeviceExtension->PciDevice->EnableIoSpace)
1385     {
1386         Command |= PCI_ENABLE_IO_SPACE;
1387         DBGPRINT("[I/O space enable] ");
1388     }
1389 
1390     if (Command != 0)
1391     {
1392         DBGPRINT("\n");
1393 
1394         /* OR with the previous value */
1395         Command |= DeviceExtension->PciDevice->PciConfig.Command;
1396 
1397         HalSetBusDataByOffset(PCIConfiguration,
1398                               DeviceExtension->PciDevice->BusNumber,
1399                               DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1400                               &Command,
1401                               FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
1402                               sizeof(USHORT));
1403     }
1404     else
1405     {
1406         DBGPRINT("None\n");
1407     }
1408 
1409     return STATUS_SUCCESS;
1410 }
1411 
1412 static NTSTATUS
1413 PdoReadConfig(
1414     IN PDEVICE_OBJECT DeviceObject,
1415     IN PIRP Irp,
1416     PIO_STACK_LOCATION IrpSp)
1417 {
1418     ULONG Size;
1419 
1420     DPRINT("PdoReadConfig() called\n");
1421 
1422     Size = InterfaceBusGetBusData(DeviceObject,
1423                                   IrpSp->Parameters.ReadWriteConfig.WhichSpace,
1424                                   IrpSp->Parameters.ReadWriteConfig.Buffer,
1425                                   IrpSp->Parameters.ReadWriteConfig.Offset,
1426                                   IrpSp->Parameters.ReadWriteConfig.Length);
1427 
1428     if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
1429     {
1430         DPRINT1("Size %lu  Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
1431         Irp->IoStatus.Information = 0;
1432         return STATUS_UNSUCCESSFUL;
1433     }
1434 
1435     Irp->IoStatus.Information = Size;
1436 
1437     return STATUS_SUCCESS;
1438 }
1439 
1440 
1441 static NTSTATUS
1442 PdoWriteConfig(
1443     IN PDEVICE_OBJECT DeviceObject,
1444     IN PIRP Irp,
1445     PIO_STACK_LOCATION IrpSp)
1446 {
1447     ULONG Size;
1448 
1449     DPRINT1("PdoWriteConfig() called\n");
1450 
1451     /* Get PCI configuration space */
1452     Size = InterfaceBusSetBusData(DeviceObject,
1453                                   IrpSp->Parameters.ReadWriteConfig.WhichSpace,
1454                                   IrpSp->Parameters.ReadWriteConfig.Buffer,
1455                                   IrpSp->Parameters.ReadWriteConfig.Offset,
1456                                   IrpSp->Parameters.ReadWriteConfig.Length);
1457 
1458     if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
1459     {
1460         DPRINT1("Size %lu  Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
1461         Irp->IoStatus.Information = 0;
1462         return STATUS_UNSUCCESSFUL;
1463     }
1464 
1465     Irp->IoStatus.Information = Size;
1466 
1467     return STATUS_SUCCESS;
1468 }
1469 
1470 static NTSTATUS
1471 PdoQueryDeviceRelations(
1472     IN PDEVICE_OBJECT DeviceObject,
1473     IN PIRP Irp,
1474     PIO_STACK_LOCATION IrpSp)
1475 {
1476     PDEVICE_RELATIONS DeviceRelations;
1477 
1478     /* We only support TargetDeviceRelation for child PDOs */
1479     if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
1480         return Irp->IoStatus.Status;
1481 
1482     /* We can do this because we only return 1 PDO for TargetDeviceRelation */
1483     DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(*DeviceRelations), TAG_PCI);
1484     if (!DeviceRelations)
1485         return STATUS_INSUFFICIENT_RESOURCES;
1486 
1487     DeviceRelations->Count = 1;
1488     DeviceRelations->Objects[0] = DeviceObject;
1489 
1490     /* The PnP manager will remove this when it is done with the PDO */
1491     ObReferenceObject(DeviceObject);
1492 
1493     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1494 
1495     return STATUS_SUCCESS;
1496 }
1497 
1498 
1499 /*** PUBLIC ******************************************************************/
1500 
1501 NTSTATUS
1502 PdoPnpControl(
1503     PDEVICE_OBJECT DeviceObject,
1504     PIRP Irp)
1505 /*
1506  * FUNCTION: Handle Plug and Play IRPs for the child device
1507  * ARGUMENTS:
1508  *     DeviceObject = Pointer to physical device object of the child device
1509  *     Irp          = Pointer to IRP that should be handled
1510  * RETURNS:
1511  *     Status
1512  */
1513 {
1514     PIO_STACK_LOCATION IrpSp;
1515     NTSTATUS Status;
1516 
1517     DPRINT("Called\n");
1518 
1519     Status = Irp->IoStatus.Status;
1520 
1521     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1522 
1523     switch (IrpSp->MinorFunction)
1524     {
1525         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
1526             DPRINT("Unimplemented IRP_MN_DEVICE_USAGE_NOTIFICATION received\n");
1527             break;
1528 
1529         case IRP_MN_EJECT:
1530             DPRINT("Unimplemented IRP_MN_EJECT received\n");
1531             break;
1532 
1533         case IRP_MN_QUERY_BUS_INFORMATION:
1534             Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1535             break;
1536 
1537         case IRP_MN_QUERY_CAPABILITIES:
1538             Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
1539             break;
1540 
1541         case IRP_MN_QUERY_DEVICE_RELATIONS:
1542             Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1543             break;
1544 
1545         case IRP_MN_QUERY_DEVICE_TEXT:
1546             DPRINT("IRP_MN_QUERY_DEVICE_TEXT received\n");
1547             Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1548             break;
1549 
1550         case IRP_MN_QUERY_ID:
1551             DPRINT("IRP_MN_QUERY_ID received\n");
1552             Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1553             break;
1554 
1555         case IRP_MN_QUERY_PNP_DEVICE_STATE:
1556             DPRINT("Unimplemented IRP_MN_QUERY_ID received\n");
1557             break;
1558 
1559         case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
1560             DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS received\n");
1561             Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1562             break;
1563 
1564         case IRP_MN_QUERY_RESOURCES:
1565             DPRINT("IRP_MN_QUERY_RESOURCES received\n");
1566             Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1567             break;
1568 
1569         case IRP_MN_SET_LOCK:
1570             DPRINT("Unimplemented IRP_MN_SET_LOCK received\n");
1571             break;
1572 
1573         case IRP_MN_START_DEVICE:
1574             Status = PdoStartDevice(DeviceObject, Irp, IrpSp);
1575             break;
1576 
1577         case IRP_MN_QUERY_STOP_DEVICE:
1578         case IRP_MN_CANCEL_STOP_DEVICE:
1579         case IRP_MN_STOP_DEVICE:
1580         case IRP_MN_QUERY_REMOVE_DEVICE:
1581         case IRP_MN_CANCEL_REMOVE_DEVICE:
1582         case IRP_MN_REMOVE_DEVICE:
1583         case IRP_MN_SURPRISE_REMOVAL:
1584             Status = STATUS_SUCCESS;
1585             break;
1586 
1587         case IRP_MN_QUERY_INTERFACE:
1588             DPRINT("IRP_MN_QUERY_INTERFACE received\n");
1589             Status = PdoQueryInterface(DeviceObject, Irp, IrpSp);
1590             break;
1591 
1592         case IRP_MN_READ_CONFIG:
1593             DPRINT("IRP_MN_READ_CONFIG received\n");
1594             Status = PdoReadConfig(DeviceObject, Irp, IrpSp);
1595             break;
1596 
1597         case IRP_MN_WRITE_CONFIG:
1598             DPRINT("IRP_MN_WRITE_CONFIG received\n");
1599             Status = PdoWriteConfig(DeviceObject, Irp, IrpSp);
1600             break;
1601 
1602         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
1603             DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS received\n");
1604             /* Nothing to do */
1605             Irp->IoStatus.Status = Status;
1606             break;
1607 
1608         default:
1609             DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
1610             break;
1611     }
1612 
1613     if (Status != STATUS_PENDING)
1614     {
1615         Irp->IoStatus.Status = Status;
1616         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1617     }
1618 
1619     DPRINT("Leaving. Status 0x%X\n", Status);
1620 
1621     return Status;
1622 }
1623 
1624 NTSTATUS
1625 PdoPowerControl(
1626     PDEVICE_OBJECT DeviceObject,
1627     PIRP Irp)
1628 /*
1629  * FUNCTION: Handle power management IRPs for the child device
1630  * ARGUMENTS:
1631  *     DeviceObject = Pointer to physical device object of the child device
1632  *     Irp          = Pointer to IRP that should be handled
1633  * RETURNS:
1634  *     Status
1635  */
1636 {
1637     PIO_STACK_LOCATION IrpSp;
1638     NTSTATUS Status = Irp->IoStatus.Status;
1639 
1640     DPRINT("Called\n");
1641 
1642     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1643 
1644     switch (IrpSp->MinorFunction)
1645     {
1646         case IRP_MN_QUERY_POWER:
1647         case IRP_MN_SET_POWER:
1648             Status = STATUS_SUCCESS;
1649             break;
1650     }
1651 
1652     PoStartNextPowerIrp(Irp);
1653     Irp->IoStatus.Status = Status;
1654     IoCompleteRequest(Irp, IO_NO_INCREMENT);
1655 
1656     DPRINT("Leaving. Status 0x%X\n", Status);
1657 
1658     return Status;
1659 }
1660 
1661 /* EOF */
1662