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