92b7a0d802386a3b491d19e133914b61b402bad1
[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 <ddk/ntddk.h>
11 #include <ddk/ntifs.h>
12 #include <initguid.h>
13 #include <ddk/wdmguid.h>
14 #include "pcidef.h"
15 #include "pci.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /*** PRIVATE *****************************************************************/
21
22 static NTSTATUS
23 PdoQueryDeviceText(
24 IN PDEVICE_OBJECT DeviceObject,
25 IN PIRP Irp,
26 PIO_STACK_LOCATION IrpSp)
27 {
28 PPDO_DEVICE_EXTENSION DeviceExtension;
29 NTSTATUS Status;
30
31 DPRINT("Called\n");
32
33 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
34
35 Status = STATUS_SUCCESS;
36
37 switch (IrpSp->Parameters.QueryDeviceText.DeviceTextType)
38 {
39 case DeviceTextDescription:
40 DPRINT("DeviceTextDescription\n");
41 Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceDescription.Buffer;
42 break;
43
44 case DeviceTextLocationInformation:
45 DPRINT("DeviceTextLocationInformation\n");
46 Irp->IoStatus.Information = (ULONG_PTR)DeviceExtension->DeviceLocation.Buffer;
47 break;
48
49 default:
50 Irp->IoStatus.Information = 0;
51 Status = STATUS_INVALID_PARAMETER;
52 }
53
54 return Status;
55 }
56
57
58 static NTSTATUS
59 PdoQueryId(
60 IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp,
62 PIO_STACK_LOCATION IrpSp)
63 {
64 PPDO_DEVICE_EXTENSION DeviceExtension;
65 UNICODE_STRING String;
66 NTSTATUS Status;
67
68 DPRINT("Called\n");
69
70 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
71
72 // Irp->IoStatus.Information = 0;
73
74 Status = STATUS_SUCCESS;
75
76 RtlInitUnicodeString(&String, NULL);
77
78 switch (IrpSp->Parameters.QueryId.IdType) {
79 case BusQueryDeviceID:
80 Status = RtlDuplicateUnicodeString(
81 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
82 &DeviceExtension->DeviceID,
83 &String);
84
85 DPRINT("DeviceID: %S\n", String.Buffer);
86
87 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
88 break;
89
90 case BusQueryHardwareIDs:
91 Status = RtlDuplicateUnicodeString(
92 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
93 &DeviceExtension->HardwareIDs,
94 &String);
95
96 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
97 break;
98
99 case BusQueryCompatibleIDs:
100 Status = RtlDuplicateUnicodeString(
101 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
102 &DeviceExtension->CompatibleIDs,
103 &String);
104
105 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
106 break;
107
108 case BusQueryInstanceID:
109 Status = RtlDuplicateUnicodeString(
110 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
111 &DeviceExtension->InstanceID,
112 &String);
113
114 DPRINT("InstanceID: %S\n", String.Buffer);
115
116 Irp->IoStatus.Information = (ULONG_PTR)String.Buffer;
117 break;
118
119 case BusQueryDeviceSerialNumber:
120 default:
121 Status = STATUS_NOT_IMPLEMENTED;
122 }
123
124 return Status;
125 }
126
127
128 static NTSTATUS
129 PdoQueryBusInformation(
130 IN PDEVICE_OBJECT DeviceObject,
131 IN PIRP Irp,
132 PIO_STACK_LOCATION IrpSp)
133 {
134 PPDO_DEVICE_EXTENSION DeviceExtension;
135 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
136 PPNP_BUS_INFORMATION BusInformation;
137
138 DPRINT("Called\n");
139
140 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
141 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
142 BusInformation = ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
143 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
144 if (BusInformation != NULL)
145 {
146 BusInformation->BusTypeGuid = GUID_BUS_TYPE_PCI;
147 BusInformation->LegacyBusType = PCIBus;
148 BusInformation->BusNumber = DeviceExtension->PciDevice->BusNumber;
149
150 return STATUS_SUCCESS;
151 }
152
153 return STATUS_INSUFFICIENT_RESOURCES;
154 }
155
156
157 static NTSTATUS
158 PdoQueryCapabilities(
159 IN PDEVICE_OBJECT DeviceObject,
160 IN PIRP Irp,
161 PIO_STACK_LOCATION IrpSp)
162 {
163 PPDO_DEVICE_EXTENSION DeviceExtension;
164 PDEVICE_CAPABILITIES DeviceCapabilities;
165
166 DPRINT("Called\n");
167
168 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
169 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
170
171 if (DeviceCapabilities->Version != 1)
172 return STATUS_UNSUCCESSFUL;
173
174 DeviceCapabilities->UniqueID = FALSE;
175 DeviceCapabilities->Address = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
176 DeviceCapabilities->UINumber = (ULONG)-1; /* FIXME */
177
178 return STATUS_SUCCESS;
179 }
180
181
182 static BOOLEAN
183 PdoGetRangeLength(PPDO_DEVICE_EXTENSION DeviceExtension,
184 ULONG Offset,
185 PULONG Base,
186 PULONG Length,
187 PULONG Flags)
188 {
189 ULONG OrigValue;
190 ULONG BaseValue;
191 ULONG NewValue;
192 ULONG Size;
193 ULONG XLength;
194
195 /* Save original value */
196 Size= HalGetBusDataByOffset(PCIConfiguration,
197 DeviceExtension->PciDevice->BusNumber,
198 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
199 &OrigValue,
200 Offset,
201 sizeof(ULONG));
202 if (Size != sizeof(ULONG))
203 {
204 DPRINT1("Wrong size %lu\n", Size);
205 return FALSE;
206 }
207
208 BaseValue = (OrigValue & 0x00000001) ? (OrigValue & ~0x3) : (OrigValue & ~0xF);
209
210 *Base = BaseValue;
211
212 /* Set magic value */
213 NewValue = (ULONG)-1;
214 Size= HalSetBusDataByOffset(PCIConfiguration,
215 DeviceExtension->PciDevice->BusNumber,
216 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
217 &NewValue,
218 Offset,
219 sizeof(ULONG));
220 if (Size != sizeof(ULONG))
221 {
222 DPRINT1("Wrong size %lu\n", Size);
223 return FALSE;
224 }
225
226 /* Get the range length */
227 Size= HalGetBusDataByOffset(PCIConfiguration,
228 DeviceExtension->PciDevice->BusNumber,
229 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
230 &NewValue,
231 Offset,
232 sizeof(ULONG));
233 if (Size != sizeof(ULONG))
234 {
235 DPRINT1("Wrong size %lu\n", Size);
236 return FALSE;
237 }
238
239 /* Restore original value */
240 Size= HalSetBusDataByOffset(PCIConfiguration,
241 DeviceExtension->PciDevice->BusNumber,
242 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
243 &OrigValue,
244 Offset,
245 sizeof(ULONG));
246 if (Size != sizeof(ULONG))
247 {
248 DPRINT1("Wrong size %lu\n", Size);
249 return FALSE;
250 }
251
252 if (NewValue == 0)
253 {
254 DPRINT("Unused address register\n");
255 *Base = 0;
256 *Length = 0;
257 *Flags = 0;
258 return TRUE;
259 }
260
261 XLength = ~((NewValue & 0x00000001) ? (NewValue & ~0x3) : (NewValue & ~0xF)) + 1;
262
263 #if 0
264 DbgPrint("BaseAddress 0x%08lx Length 0x%08lx",
265 BaseValue, XLength);
266
267 if (NewValue & 0x00000001)
268 {
269 DbgPrint(" IO range");
270 }
271 else
272 {
273 DbgPrint(" Memory range");
274 if ((NewValue & 0x00000006) == 0)
275 {
276 DbgPrint(" in 32-Bit address space");
277 }
278 else if ((NewValue & 0x00000006) == 2)
279 {
280 DbgPrint(" below 1BM ");
281 }
282 else if ((NewValue & 0x00000006) == 4)
283 {
284 DbgPrint(" in 64-Bit address space");
285 }
286
287 if (NewValue & 0x00000008)
288 {
289 DbgPrint(" prefetchable");
290 }
291 }
292
293 DbgPrint("\n");
294 #endif
295
296 *Length = XLength;
297 *Flags = (NewValue & 0x00000001) ? (NewValue & 0x3) : (NewValue & 0xF);
298
299 return TRUE;
300 }
301
302
303 static NTSTATUS
304 PdoQueryResourceRequirements(
305 IN PDEVICE_OBJECT DeviceObject,
306 IN PIRP Irp,
307 PIO_STACK_LOCATION IrpSp)
308 {
309 PPDO_DEVICE_EXTENSION DeviceExtension;
310 PCI_COMMON_CONFIG PciConfig;
311 PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
312 PIO_RESOURCE_DESCRIPTOR Descriptor;
313 ULONG Size;
314 ULONG ResCount = 0;
315 ULONG ListSize;
316 ULONG i;
317 ULONG Base;
318 ULONG Length;
319 ULONG Flags;
320
321 DPRINT("PdoQueryResourceRequirements() called\n");
322
323 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
324
325 /* Get PCI configuration space */
326 Size= HalGetBusData(PCIConfiguration,
327 DeviceExtension->PciDevice->BusNumber,
328 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
329 &PciConfig,
330 PCI_COMMON_HDR_LENGTH);
331 DPRINT("Size %lu\n", Size);
332 if (Size < PCI_COMMON_HDR_LENGTH)
333 {
334 Irp->IoStatus.Information = 0;
335 return STATUS_UNSUCCESSFUL;
336 }
337
338 DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
339
340 /* Count required resource descriptors */
341 ResCount = 0;
342 if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
343 {
344 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
345 {
346 if (!PdoGetRangeLength(DeviceExtension,
347 0x10 + i * 4,
348 &Base,
349 &Length,
350 &Flags))
351 break;
352
353 if (Length != 0)
354 ResCount += 2;
355 }
356
357 /* FIXME: Check ROM address */
358
359 if (PciConfig.u.type0.InterruptPin != 0)
360 ResCount++;
361 }
362 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
363 {
364 for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
365 {
366 if (!PdoGetRangeLength(DeviceExtension,
367 0x10 + i * 4,
368 &Base,
369 &Length,
370 &Flags))
371 break;
372
373 if (Length != 0)
374 ResCount += 2;
375 }
376 if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
377 ResCount++;
378 }
379 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
380 {
381 }
382 else
383 {
384 DPRINT1("Unsupported header type %u\n", PCI_CONFIGURATION_TYPE(&PciConfig));
385 }
386
387 if (ResCount == 0)
388 {
389 Irp->IoStatus.Information = 0;
390 return STATUS_SUCCESS;
391 }
392
393 /* Calculate the resource list size */
394 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
395 if (ResCount > 1)
396 {
397 ListSize += ((ResCount - 1) * sizeof(IO_RESOURCE_DESCRIPTOR));
398 }
399
400 DPRINT("ListSize %lu (0x%lx)\n", ListSize, ListSize);
401
402 /* Allocate the resource requirements list */
403 ResourceList = ExAllocatePool(PagedPool,
404 ListSize);
405 if (ResourceList == NULL)
406 {
407 Irp->IoStatus.Information = 0;
408 return STATUS_INSUFFICIENT_RESOURCES;
409 }
410
411 ResourceList->ListSize = ListSize;
412 ResourceList->InterfaceType = PCIBus;
413 ResourceList->BusNumber = DeviceExtension->PciDevice->BusNumber;
414 ResourceList->SlotNumber = DeviceExtension->PciDevice->SlotNumber.u.AsULONG;
415 ResourceList->AlternativeLists = 1;
416
417 ResourceList->List[0].Version = 1;
418 ResourceList->List[0].Revision = 1;
419 ResourceList->List[0].Count = ResCount;
420
421 Descriptor = &ResourceList->List[0].Descriptors[0];
422 if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
423 {
424 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
425 {
426 if (!PdoGetRangeLength(DeviceExtension,
427 0x10 + i * 4,
428 &Base,
429 &Length,
430 &Flags))
431 {
432 DPRINT1("PdoGetRangeLength() failed\n");
433 break;
434 }
435
436 if (Length == 0)
437 {
438 DPRINT("Unused address register\n");
439 continue;
440 }
441
442 /* Set preferred descriptor */
443 Descriptor->Option = IO_RESOURCE_PREFERRED;
444 if (Flags & PCI_ADDRESS_IO_SPACE)
445 {
446 Descriptor->Type = CmResourceTypePort;
447 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
448 Descriptor->Flags = CM_RESOURCE_PORT_IO |
449 CM_RESOURCE_PORT_16_BIT_DECODE |
450 CM_RESOURCE_PORT_POSITIVE_DECODE;
451
452 Descriptor->u.Port.Length = Length;
453 Descriptor->u.Port.Alignment = 1;
454 Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)Base;
455 Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
456 }
457 else
458 {
459 Descriptor->Type = CmResourceTypeMemory;
460 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
461 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
462
463 Descriptor->u.Memory.Length = Length;
464 Descriptor->u.Memory.Alignment = 1;
465 Descriptor->u.Memory.MinimumAddress.QuadPart = (ULONGLONG)Base;
466 Descriptor->u.Memory.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
467 }
468 Descriptor++;
469
470 /* Set alternative descriptor */
471 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
472 if (Flags & PCI_ADDRESS_IO_SPACE)
473 {
474 Descriptor->Type = CmResourceTypePort;
475 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
476 Descriptor->Flags = CM_RESOURCE_PORT_IO |
477 CM_RESOURCE_PORT_16_BIT_DECODE |
478 CM_RESOURCE_PORT_POSITIVE_DECODE;
479
480 Descriptor->u.Port.Length = Length;
481 Descriptor->u.Port.Alignment = Length;
482 Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
483 Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
484 }
485 else
486 {
487 Descriptor->Type = CmResourceTypeMemory;
488 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
489 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
490
491 Descriptor->u.Memory.Length = Length;
492 Descriptor->u.Memory.Alignment = Length;
493 Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
494 Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
495 }
496 Descriptor++;
497 }
498
499 /* FIXME: Check ROM address */
500
501 if (PciConfig.u.type0.InterruptPin != 0)
502 {
503 Descriptor->Option = 0; /* Required */
504 Descriptor->Type = CmResourceTypeInterrupt;
505 Descriptor->ShareDisposition = CmResourceShareShared;
506 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
507
508 Descriptor->u.Interrupt.MinimumVector = 0;
509 Descriptor->u.Interrupt.MaximumVector = 0xFF;
510 }
511 }
512 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
513 {
514 for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
515 {
516 if (!PdoGetRangeLength(DeviceExtension,
517 0x10 + i * 4,
518 &Base,
519 &Length,
520 &Flags))
521 {
522 DPRINT1("PdoGetRangeLength() failed\n");
523 break;
524 }
525
526 if (Length == 0)
527 {
528 DPRINT("Unused address register\n");
529 continue;
530 }
531
532 /* Set preferred descriptor */
533 Descriptor->Option = IO_RESOURCE_PREFERRED;
534 if (Flags & PCI_ADDRESS_IO_SPACE)
535 {
536 Descriptor->Type = CmResourceTypePort;
537 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
538 Descriptor->Flags = CM_RESOURCE_PORT_IO |
539 CM_RESOURCE_PORT_16_BIT_DECODE |
540 CM_RESOURCE_PORT_POSITIVE_DECODE;
541
542 Descriptor->u.Port.Length = Length;
543 Descriptor->u.Port.Alignment = 1;
544 Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)Base;
545 Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
546 }
547 else
548 {
549 Descriptor->Type = CmResourceTypeMemory;
550 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
551 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
552
553 Descriptor->u.Memory.Length = Length;
554 Descriptor->u.Memory.Alignment = 1;
555 Descriptor->u.Memory.MinimumAddress.QuadPart = (ULONGLONG)Base;
556 Descriptor->u.Memory.MaximumAddress.QuadPart = (ULONGLONG)(Base + Length - 1);
557 }
558 Descriptor++;
559
560 /* Set alternative descriptor */
561 Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
562 if (Flags & PCI_ADDRESS_IO_SPACE)
563 {
564 Descriptor->Type = CmResourceTypePort;
565 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
566 Descriptor->Flags = CM_RESOURCE_PORT_IO |
567 CM_RESOURCE_PORT_16_BIT_DECODE |
568 CM_RESOURCE_PORT_POSITIVE_DECODE;
569
570 Descriptor->u.Port.Length = Length;
571 Descriptor->u.Port.Alignment = Length;
572 Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
573 Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
574 }
575 else
576 {
577 Descriptor->Type = CmResourceTypeMemory;
578 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
579 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
580
581 Descriptor->u.Memory.Length = Length;
582 Descriptor->u.Memory.Alignment = Length;
583 Descriptor->u.Port.MinimumAddress.QuadPart = (ULONGLONG)0;
584 Descriptor->u.Port.MaximumAddress.QuadPart = (ULONGLONG)0x00000000FFFFFFFF;
585 }
586 Descriptor++;
587 }
588 if (DeviceExtension->PciDevice->PciConfig.BaseClass == PCI_CLASS_BRIDGE_DEV)
589 {
590 Descriptor->Option = 0; /* Required */
591 Descriptor->Type = CmResourceTypeBusNumber;
592 Descriptor->ShareDisposition = CmResourceShareShared;
593 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
594
595 Descriptor->u.BusNumber.MinBusNumber =
596 Descriptor->u.BusNumber.MaxBusNumber = DeviceExtension->PciDevice->PciConfig.u.type1.SubordinateBus;
597 Descriptor->u.BusNumber.Length = 1;
598 Descriptor->u.BusNumber.Reserved = 0;
599 }
600 }
601 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
602 {
603 /* FIXME: Add Cardbus bridge resources */
604 }
605
606 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
607
608 return STATUS_SUCCESS;
609 }
610
611
612 static NTSTATUS
613 PdoQueryResources(
614 IN PDEVICE_OBJECT DeviceObject,
615 IN PIRP Irp,
616 PIO_STACK_LOCATION IrpSp)
617 {
618 PPDO_DEVICE_EXTENSION DeviceExtension;
619 PCI_COMMON_CONFIG PciConfig;
620 PCM_RESOURCE_LIST ResourceList;
621 PCM_PARTIAL_RESOURCE_LIST PartialList;
622 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
623 ULONG Size;
624 ULONG ResCount = 0;
625 ULONG ListSize;
626 ULONG i;
627 ULONG Base;
628 ULONG Length;
629 ULONG Flags;
630
631 DPRINT("PdoQueryResources() called\n");
632
633 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
634
635 /* Get PCI configuration space */
636 Size= HalGetBusData(PCIConfiguration,
637 DeviceExtension->PciDevice->BusNumber,
638 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
639 &PciConfig,
640 PCI_COMMON_HDR_LENGTH);
641 DPRINT("Size %lu\n", Size);
642 if (Size < PCI_COMMON_HDR_LENGTH)
643 {
644 Irp->IoStatus.Information = 0;
645 return STATUS_UNSUCCESSFUL;
646 }
647
648 DPRINT("Command register: 0x%04hx\n", PciConfig.Command);
649
650 /* Count required resource descriptors */
651 ResCount = 0;
652 if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
653 {
654 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
655 {
656 if (!PdoGetRangeLength(DeviceExtension,
657 0x10 + i * 4,
658 &Base,
659 &Length,
660 &Flags))
661 break;
662
663 if (Length)
664 ResCount++;
665 }
666
667 if ((PciConfig.u.type0.InterruptPin != 0) &&
668 (PciConfig.u.type0.InterruptLine != 0xFF))
669 ResCount++;
670 }
671 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
672 {
673 for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
674 {
675 if (!PdoGetRangeLength(DeviceExtension,
676 0x10 + i * 4,
677 &Base,
678 &Length,
679 &Flags))
680 break;
681
682 if (Length != 0)
683 ResCount++;
684 }
685 }
686 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
687 {
688
689 }
690 else
691 {
692 DPRINT1("Unsupported header type %u\n", PCI_CONFIGURATION_TYPE(&PciConfig));
693 }
694
695 if (ResCount == 0)
696 {
697 Irp->IoStatus.Information = 0;
698 return STATUS_SUCCESS;
699 }
700
701 /* Calculate the resource list size */
702 ListSize = sizeof(CM_RESOURCE_LIST);
703 if (ResCount > 1)
704 {
705 ListSize += ((ResCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
706 }
707
708 /* Allocate the resource list */
709 ResourceList = ExAllocatePool(PagedPool,
710 ListSize);
711 if (ResourceList == NULL)
712 return STATUS_INSUFFICIENT_RESOURCES;
713
714 ResourceList->Count = 1;
715 ResourceList->List[0].InterfaceType = PCIConfiguration;
716 ResourceList->List[0].BusNumber = DeviceExtension->PciDevice->BusNumber;
717
718 PartialList = &ResourceList->List[0].PartialResourceList;
719 PartialList->Version = 0;
720 PartialList->Revision = 0;
721 PartialList->Count = ResCount;
722
723 Descriptor = &PartialList->PartialDescriptors[0];
724 if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_DEVICE_TYPE)
725 {
726 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
727 {
728 if (!PdoGetRangeLength(DeviceExtension,
729 0x10 + i * 4,
730 &Base,
731 &Length,
732 &Flags))
733 {
734 DPRINT1("PdoGetRangeLength() failed\n");
735 break;
736 }
737
738 if (Length == 0)
739 {
740 DPRINT("Unused address register\n");
741 continue;
742 }
743
744 if (Flags & PCI_ADDRESS_IO_SPACE)
745 {
746 Descriptor->Type = CmResourceTypePort;
747 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
748 Descriptor->Flags = CM_RESOURCE_PORT_IO;
749 Descriptor->u.Port.Start.QuadPart =
750 (ULONGLONG)Base;
751 Descriptor->u.Port.Length = Length;
752 }
753 else
754 {
755 Descriptor->Type = CmResourceTypeMemory;
756 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
757 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
758 Descriptor->u.Memory.Start.QuadPart =
759 (ULONGLONG)Base;
760 Descriptor->u.Memory.Length = Length;
761 }
762
763 Descriptor++;
764 }
765
766 /* Add interrupt resource */
767 if ((PciConfig.u.type0.InterruptPin != 0) &&
768 (PciConfig.u.type0.InterruptLine != 0xFF))
769 {
770 Descriptor->Type = CmResourceTypeInterrupt;
771 Descriptor->ShareDisposition = CmResourceShareShared;
772 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
773 Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
774 Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
775 Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
776 }
777 }
778 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_BRIDGE_TYPE)
779 {
780 for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
781 {
782 if (!PdoGetRangeLength(DeviceExtension,
783 0x10 + i * 4,
784 &Base,
785 &Length,
786 &Flags))
787 {
788 DPRINT1("PdoGetRangeLength() failed\n");
789 break;
790 }
791
792 if (Length == 0)
793 {
794 DPRINT("Unused address register\n");
795 continue;
796 }
797
798 if (Flags & PCI_ADDRESS_IO_SPACE)
799 {
800 Descriptor->Type = CmResourceTypePort;
801 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
802 Descriptor->Flags = CM_RESOURCE_PORT_IO;
803 Descriptor->u.Port.Start.QuadPart =
804 (ULONGLONG)Base;
805 Descriptor->u.Port.Length = Length;
806 }
807 else
808 {
809 Descriptor->Type = CmResourceTypeMemory;
810 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
811 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
812 Descriptor->u.Memory.Start.QuadPart =
813 (ULONGLONG)Base;
814 Descriptor->u.Memory.Length = Length;
815 }
816
817 Descriptor++;
818 }
819 }
820 else if (PCI_CONFIGURATION_TYPE(&PciConfig) == PCI_CARDBUS_BRIDGE_TYPE)
821 {
822 /* FIXME: Cardbus */
823 }
824
825 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
826
827 return STATUS_SUCCESS;
828 }
829
830
831 static VOID NTAPI
832 InterfaceReference(
833 IN PVOID Context)
834 {
835 PPDO_DEVICE_EXTENSION DeviceExtension;
836
837 DPRINT("InterfaceReference(%p)\n", Context);
838
839 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
840 InterlockedIncrement(&DeviceExtension->References);
841 }
842
843
844 static VOID NTAPI
845 InterfaceDereference(
846 IN PVOID Context)
847 {
848 PPDO_DEVICE_EXTENSION DeviceExtension;
849
850 DPRINT("InterfaceDereference(%p)\n", Context);
851
852 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
853 InterlockedDecrement(&DeviceExtension->References);
854 }
855
856
857 static BOOLEAN NTAPI
858 InterfaceBusTranslateBusAddress(
859 IN PVOID Context,
860 IN PHYSICAL_ADDRESS BusAddress,
861 IN ULONG Length,
862 IN OUT PULONG AddressSpace,
863 OUT PPHYSICAL_ADDRESS TranslatedAddress)
864 {
865 PPDO_DEVICE_EXTENSION DeviceExtension;
866 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
867
868 DPRINT("InterfaceBusTranslateBusAddress(%p %p 0x%lx %p %p)\n",
869 Context, BusAddress, Length, AddressSpace, TranslatedAddress);
870
871 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
872 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
873
874 return HalTranslateBusAddress(
875 PCIBus, FdoDeviceExtension->BusNumber,
876 BusAddress, AddressSpace, TranslatedAddress);
877 }
878
879
880 static PDMA_ADAPTER NTAPI
881 InterfaceBusGetDmaAdapter(
882 IN PVOID Context,
883 IN PDEVICE_DESCRIPTION DeviceDescription,
884 OUT PULONG NumberOfMapRegisters)
885 {
886 DPRINT("InterfaceBusGetDmaAdapter(%p %p %p)\n",
887 Context, DeviceDescription, NumberOfMapRegisters);
888 return (PDMA_ADAPTER)HalGetAdapter(DeviceDescription, NumberOfMapRegisters);
889 }
890
891
892 static ULONG NTAPI
893 InterfaceBusSetBusData(
894 IN PVOID Context,
895 IN ULONG DataType,
896 IN PVOID Buffer,
897 IN ULONG Offset,
898 IN ULONG Length)
899 {
900 PPDO_DEVICE_EXTENSION DeviceExtension;
901 ULONG Size;
902
903 DPRINT("InterfaceBusSetBusData()\n",
904 Context, DataType, Buffer, Offset, Length);
905
906 if (DataType != PCI_WHICHSPACE_CONFIG)
907 {
908 DPRINT("Unknown DataType %lu\n", DataType);
909 return 0;
910 }
911
912 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
913
914 /* Get PCI configuration space */
915 Size = HalSetBusDataByOffset(PCIConfiguration,
916 DeviceExtension->PciDevice->BusNumber,
917 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
918 Buffer,
919 Offset,
920 Length);
921 return Size;
922 }
923
924
925 static ULONG NTAPI
926 InterfaceBusGetBusData(
927 IN PVOID Context,
928 IN ULONG DataType,
929 IN PVOID Buffer,
930 IN ULONG Offset,
931 IN ULONG Length)
932 {
933 PPDO_DEVICE_EXTENSION DeviceExtension;
934 ULONG Size;
935
936 DPRINT("InterfaceBusGetBusData() called\n",
937 Context, DataType, Buffer, Offset, Length);
938
939 if (DataType != PCI_WHICHSPACE_CONFIG)
940 {
941 DPRINT("Unknown DataType %lu\n", DataType);
942 return 0;
943 }
944
945 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
946
947 /* Get PCI configuration space */
948 Size = HalGetBusDataByOffset(PCIConfiguration,
949 DeviceExtension->PciDevice->BusNumber,
950 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
951 Buffer,
952 Offset,
953 Length);
954 return Size;
955 }
956
957
958 static NTSTATUS
959 PdoQueryInterface(
960 IN PDEVICE_OBJECT DeviceObject,
961 IN PIRP Irp,
962 PIO_STACK_LOCATION IrpSp)
963 {
964 NTSTATUS Status;
965
966 if (RtlCompareMemory(IrpSp->Parameters.QueryInterface.InterfaceType,
967 &GUID_BUS_INTERFACE_STANDARD, sizeof(GUID)) == sizeof(GUID))
968 {
969 /* BUS_INTERFACE STANDARD */
970 if (IrpSp->Parameters.QueryInterface.Version < 1)
971 Status = STATUS_NOT_SUPPORTED;
972 else if (IrpSp->Parameters.QueryInterface.Size < sizeof(BUS_INTERFACE_STANDARD))
973 Status = STATUS_BUFFER_TOO_SMALL;
974 else
975 {
976 PBUS_INTERFACE_STANDARD BusInterface;
977 BusInterface = (PBUS_INTERFACE_STANDARD)IrpSp->Parameters.QueryInterface.Interface;
978 BusInterface->Size = sizeof(BUS_INTERFACE_STANDARD);
979 BusInterface->Version = 1;
980 BusInterface->Context = DeviceObject;
981 BusInterface->InterfaceReference = InterfaceReference;
982 BusInterface->InterfaceDereference = InterfaceDereference;
983 BusInterface->TranslateBusAddress = InterfaceBusTranslateBusAddress;
984 BusInterface->GetDmaAdapter = InterfaceBusGetDmaAdapter;
985 BusInterface->SetBusData = InterfaceBusSetBusData;
986 BusInterface->GetBusData = InterfaceBusGetBusData;
987 Status = STATUS_SUCCESS;
988 }
989 }
990 else
991 {
992 /* Not a supported interface */
993 return STATUS_NOT_SUPPORTED;
994 }
995
996 if (NT_SUCCESS(Status))
997 {
998 /* Add a reference for the returned interface */
999 PINTERFACE Interface;
1000 Interface = (PINTERFACE)IrpSp->Parameters.QueryInterface.Interface;
1001 Interface->InterfaceReference(Interface->Context);
1002 }
1003
1004 return Status;
1005 }
1006
1007
1008 static NTSTATUS
1009 PdoReadConfig(
1010 IN PDEVICE_OBJECT DeviceObject,
1011 IN PIRP Irp,
1012 PIO_STACK_LOCATION IrpSp)
1013 {
1014 ULONG Size;
1015
1016 DPRINT("PdoReadConfig() called\n");
1017
1018 Size = InterfaceBusGetBusData(
1019 DeviceObject,
1020 IrpSp->Parameters.ReadWriteConfig.WhichSpace,
1021 IrpSp->Parameters.ReadWriteConfig.Buffer,
1022 IrpSp->Parameters.ReadWriteConfig.Offset,
1023 IrpSp->Parameters.ReadWriteConfig.Length);
1024
1025 if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
1026 {
1027 DPRINT1("Size %lu Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
1028 Irp->IoStatus.Information = 0;
1029 return STATUS_UNSUCCESSFUL;
1030 }
1031
1032 Irp->IoStatus.Information = Size;
1033
1034 return STATUS_SUCCESS;
1035 }
1036
1037
1038 static NTSTATUS
1039 PdoWriteConfig(
1040 IN PDEVICE_OBJECT DeviceObject,
1041 IN PIRP Irp,
1042 PIO_STACK_LOCATION IrpSp)
1043 {
1044 ULONG Size;
1045
1046 DPRINT1("PdoWriteConfig() called\n");
1047
1048 /* Get PCI configuration space */
1049 Size = InterfaceBusSetBusData(
1050 DeviceObject,
1051 IrpSp->Parameters.ReadWriteConfig.WhichSpace,
1052 IrpSp->Parameters.ReadWriteConfig.Buffer,
1053 IrpSp->Parameters.ReadWriteConfig.Offset,
1054 IrpSp->Parameters.ReadWriteConfig.Length);
1055
1056 if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
1057 {
1058 DPRINT1("Size %lu Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
1059 Irp->IoStatus.Information = 0;
1060 return STATUS_UNSUCCESSFUL;
1061 }
1062
1063 Irp->IoStatus.Information = Size;
1064
1065 return STATUS_SUCCESS;
1066 }
1067
1068
1069 static NTSTATUS
1070 PdoSetPower(
1071 IN PDEVICE_OBJECT DeviceObject,
1072 IN PIRP Irp,
1073 PIO_STACK_LOCATION IrpSp)
1074 {
1075 PPDO_DEVICE_EXTENSION DeviceExtension;
1076 NTSTATUS Status;
1077
1078 DPRINT("Called\n");
1079
1080 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1081
1082 if (IrpSp->Parameters.Power.Type == DevicePowerState) {
1083 Status = STATUS_SUCCESS;
1084 switch (IrpSp->Parameters.Power.State.SystemState) {
1085 default:
1086 Status = STATUS_UNSUCCESSFUL;
1087 }
1088 } else {
1089 Status = STATUS_UNSUCCESSFUL;
1090 }
1091
1092 return Status;
1093 }
1094
1095
1096 /*** PUBLIC ******************************************************************/
1097
1098 NTSTATUS
1099 PdoPnpControl(
1100 PDEVICE_OBJECT DeviceObject,
1101 PIRP Irp)
1102 /*
1103 * FUNCTION: Handle Plug and Play IRPs for the child device
1104 * ARGUMENTS:
1105 * DeviceObject = Pointer to physical device object of the child device
1106 * Irp = Pointer to IRP that should be handled
1107 * RETURNS:
1108 * Status
1109 */
1110 {
1111 PIO_STACK_LOCATION IrpSp;
1112 NTSTATUS Status;
1113
1114 DPRINT("Called\n");
1115
1116 Status = Irp->IoStatus.Status;
1117
1118 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1119
1120 switch (IrpSp->MinorFunction) {
1121 #if 0
1122 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
1123 break;
1124
1125 case IRP_MN_EJECT:
1126 break;
1127 #endif
1128
1129 case IRP_MN_QUERY_BUS_INFORMATION:
1130 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1131 break;
1132
1133 case IRP_MN_QUERY_CAPABILITIES:
1134 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
1135 break;
1136
1137 #if 0
1138 case IRP_MN_QUERY_DEVICE_RELATIONS:
1139 /* FIXME: Possibly handle for RemovalRelations */
1140 break;
1141 #endif
1142
1143 case IRP_MN_QUERY_DEVICE_TEXT:
1144 DPRINT("IRP_MN_QUERY_DEVICE_TEXT received\n");
1145 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1146 break;
1147
1148 case IRP_MN_QUERY_ID:
1149 DPRINT("IRP_MN_QUERY_ID received\n");
1150 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1151 break;
1152
1153 #if 0
1154 case IRP_MN_QUERY_PNP_DEVICE_STATE:
1155 break;
1156 #endif
1157
1158 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
1159 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS received\n");
1160 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1161 break;
1162
1163 case IRP_MN_QUERY_RESOURCES:
1164 DPRINT("IRP_MN_QUERY_RESOURCES received\n");
1165 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1166 break;
1167
1168 #if 0
1169 case IRP_MN_SET_LOCK:
1170 break;
1171 #endif
1172
1173 case IRP_MN_START_DEVICE:
1174 case IRP_MN_QUERY_STOP_DEVICE:
1175 case IRP_MN_CANCEL_STOP_DEVICE:
1176 case IRP_MN_STOP_DEVICE:
1177 case IRP_MN_QUERY_REMOVE_DEVICE:
1178 case IRP_MN_CANCEL_REMOVE_DEVICE:
1179 case IRP_MN_REMOVE_DEVICE:
1180 case IRP_MN_SURPRISE_REMOVAL:
1181 Status = STATUS_SUCCESS;
1182 break;
1183
1184 case IRP_MN_QUERY_INTERFACE:
1185 DPRINT("IRP_MN_QUERY_INTERFACE received\n");
1186 Status = PdoQueryInterface(DeviceObject, Irp, IrpSp);
1187 break;
1188
1189 case IRP_MN_READ_CONFIG:
1190 DPRINT("IRP_MN_READ_CONFIG received\n");
1191 Status = PdoReadConfig(DeviceObject, Irp, IrpSp);
1192 break;
1193
1194 case IRP_MN_WRITE_CONFIG:
1195 DPRINT("IRP_MN_WRITE_CONFIG received\n");
1196 Status = PdoWriteConfig(DeviceObject, Irp, IrpSp);
1197 break;
1198
1199 default:
1200 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
1201 break;
1202 }
1203
1204 if (Status != STATUS_PENDING) {
1205 Irp->IoStatus.Status = Status;
1206 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1207 }
1208
1209 DPRINT("Leaving. Status 0x%X\n", Status);
1210
1211 return Status;
1212 }
1213
1214 NTSTATUS
1215 PdoPowerControl(
1216 PDEVICE_OBJECT DeviceObject,
1217 PIRP Irp)
1218 /*
1219 * FUNCTION: Handle power management IRPs for the child device
1220 * ARGUMENTS:
1221 * DeviceObject = Pointer to physical device object of the child device
1222 * Irp = Pointer to IRP that should be handled
1223 * RETURNS:
1224 * Status
1225 */
1226 {
1227 PIO_STACK_LOCATION IrpSp;
1228 NTSTATUS Status;
1229
1230 DPRINT("Called\n");
1231
1232 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1233
1234 switch (IrpSp->MinorFunction) {
1235 case IRP_MN_SET_POWER:
1236 Status = PdoSetPower(DeviceObject, Irp, IrpSp);
1237 break;
1238
1239 default:
1240 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1241 Status = STATUS_NOT_IMPLEMENTED;
1242 break;
1243 }
1244
1245 if (Status != STATUS_PENDING) {
1246 Irp->IoStatus.Status = Status;
1247 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1248 }
1249
1250 DPRINT("Leaving. Status 0x%X\n", Status);
1251
1252 return Status;
1253 }
1254
1255 /* EOF */