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