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