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