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
PdoQueryDeviceText(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoQueryId(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoQueryBusInformation(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoQueryCapabilities(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoReadPciBar(PPDO_DEVICE_EXTENSION DeviceExtension,ULONG Offset,PULONG OriginalValue,PULONG NewValue)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
PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,UCHAR Bar,PULONGLONG Base,PULONGLONG Length,PULONG Flags,PUCHAR NextBar,PULONGLONG MaximumAddress)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
PdoQueryResourceRequirements(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoQueryResources(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
InterfaceReference(IN PVOID Context)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
InterfaceDereference(IN PVOID Context)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
InterfaceBusTranslateBusAddress(IN PVOID Context,IN PHYSICAL_ADDRESS BusAddress,IN ULONG Length,IN OUT PULONG AddressSpace,OUT PPHYSICAL_ADDRESS TranslatedAddress)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
InterfaceBusGetDmaAdapter(IN PVOID Context,IN PDEVICE_DESCRIPTION DeviceDescription,OUT PULONG NumberOfMapRegisters)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
InterfaceBusSetBusData(IN PVOID Context,IN ULONG DataType,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)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
InterfaceBusGetBusData(IN PVOID Context,IN ULONG DataType,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)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
InterfacePciDevicePresent(IN USHORT VendorID,IN USHORT DeviceID,IN UCHAR RevisionID,IN USHORT SubVendorID,IN USHORT SubSystemID,IN ULONG Flags)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
CheckPciDevice(IN PPCI_COMMON_CONFIG PciConfig,IN PPCI_DEVICE_PRESENCE_PARAMETERS Parameters)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
InterfacePciDevicePresentEx(IN PVOID Context,IN PPCI_DEVICE_PRESENCE_PARAMETERS Parameters)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
PdoQueryInterface(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoStartDevice(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoReadConfig(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoWriteConfig(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoQueryDeviceRelations(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,PIO_STACK_LOCATION IrpSp)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
PdoPnpControl(PDEVICE_OBJECT DeviceObject,PIRP Irp)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
PdoPowerControl(PDEVICE_OBJECT DeviceObject,PIRP Irp)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