Transform pci.sys to a Plug-and-Play driver.
[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 sizeof(PCI_COMMON_CONFIG));
331 DPRINT("Size %lu\n", Size);
332 if (Size < sizeof(PCI_COMMON_CONFIG))
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) == 0)
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) == 1)
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) == 2)
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 sizeof(PCI_COMMON_CONFIG));
641 DPRINT("Size %lu\n", Size);
642 if (Size < sizeof(PCI_COMMON_CONFIG))
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) == 0)
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) == 1)
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) == 2)
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) == 0)
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) == 1)
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) == 2)
821 {
822 /* FIXME: Cardbus */
823 }
824
825 Irp->IoStatus.Information = (ULONG_PTR)ResourceList;
826
827 return STATUS_SUCCESS;
828 }
829
830
831 static NTSTATUS
832 PdoReadConfig(
833 IN PDEVICE_OBJECT DeviceObject,
834 IN PIRP Irp,
835 PIO_STACK_LOCATION IrpSp)
836 {
837 PPDO_DEVICE_EXTENSION DeviceExtension;
838 ULONG Size;
839
840 DPRINT1("PdoReadConfig() called\n");
841
842 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
843
844 #if 0
845 if (IrpSp->Parameters.ReadWriteConfig.WhichSpace != PCI_WHICHSPACE_CONFIG)
846 return STATUS_NOT_SUPPORTED;
847 #endif
848
849 /* Get PCI configuration space */
850 Size= HalGetBusDataByOffset(PCIConfiguration,
851 DeviceExtension->PciDevice->BusNumber,
852 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
853 IrpSp->Parameters.ReadWriteConfig.Buffer,
854 IrpSp->Parameters.ReadWriteConfig.Offset,
855 IrpSp->Parameters.ReadWriteConfig.Length);
856 if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
857 {
858 DPRINT1("Size %lu Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
859 Irp->IoStatus.Information = 0;
860 return STATUS_UNSUCCESSFUL;
861 }
862
863 Irp->IoStatus.Information = Size;
864
865 return STATUS_SUCCESS;
866 }
867
868
869 static NTSTATUS
870 PdoWriteConfig(
871 IN PDEVICE_OBJECT DeviceObject,
872 IN PIRP Irp,
873 PIO_STACK_LOCATION IrpSp)
874 {
875 PPDO_DEVICE_EXTENSION DeviceExtension;
876 ULONG Size;
877
878 DPRINT1("PdoWriteConfig() called\n");
879
880 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
881
882 #if 0
883 if (IrpSp->Parameters.ReadWriteConfig.WhichSpace != PCI_WHICHSPACE_CONFIG)
884 return STATUS_NOT_SUPPORTED;
885 #endif
886
887 /* Get PCI configuration space */
888 Size= HalSetBusDataByOffset(PCIConfiguration,
889 DeviceExtension->PciDevice->BusNumber,
890 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
891 IrpSp->Parameters.ReadWriteConfig.Buffer,
892 IrpSp->Parameters.ReadWriteConfig.Offset,
893 IrpSp->Parameters.ReadWriteConfig.Length);
894 if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
895 {
896 DPRINT1("Size %lu Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
897 Irp->IoStatus.Information = 0;
898 return STATUS_UNSUCCESSFUL;
899 }
900
901 Irp->IoStatus.Information = Size;
902
903 return STATUS_SUCCESS;
904 }
905
906
907 static NTSTATUS
908 PdoSetPower(
909 IN PDEVICE_OBJECT DeviceObject,
910 IN PIRP Irp,
911 PIO_STACK_LOCATION IrpSp)
912 {
913 PPDO_DEVICE_EXTENSION DeviceExtension;
914 NTSTATUS Status;
915
916 DPRINT("Called\n");
917
918 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
919
920 if (IrpSp->Parameters.Power.Type == DevicePowerState) {
921 Status = STATUS_SUCCESS;
922 switch (IrpSp->Parameters.Power.State.SystemState) {
923 default:
924 Status = STATUS_UNSUCCESSFUL;
925 }
926 } else {
927 Status = STATUS_UNSUCCESSFUL;
928 }
929
930 return Status;
931 }
932
933
934 /*** PUBLIC ******************************************************************/
935
936 NTSTATUS
937 PdoPnpControl(
938 PDEVICE_OBJECT DeviceObject,
939 PIRP Irp)
940 /*
941 * FUNCTION: Handle Plug and Play IRPs for the child device
942 * ARGUMENTS:
943 * DeviceObject = Pointer to physical device object of the child device
944 * Irp = Pointer to IRP that should be handled
945 * RETURNS:
946 * Status
947 */
948 {
949 PIO_STACK_LOCATION IrpSp;
950 NTSTATUS Status;
951
952 DPRINT("Called\n");
953
954 Status = Irp->IoStatus.Status;
955
956 IrpSp = IoGetCurrentIrpStackLocation(Irp);
957
958 switch (IrpSp->MinorFunction) {
959 #if 0
960 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
961 break;
962
963 case IRP_MN_EJECT:
964 break;
965 #endif
966
967 case IRP_MN_QUERY_BUS_INFORMATION:
968 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
969 break;
970
971 case IRP_MN_QUERY_CAPABILITIES:
972 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
973 break;
974
975 #if 0
976 case IRP_MN_QUERY_DEVICE_RELATIONS:
977 /* FIXME: Possibly handle for RemovalRelations */
978 break;
979 #endif
980
981 case IRP_MN_QUERY_DEVICE_TEXT:
982 DPRINT("IRP_MN_QUERY_DEVICE_TEXT received\n");
983 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
984 break;
985
986 case IRP_MN_QUERY_ID:
987 DPRINT("IRP_MN_QUERY_ID received\n");
988 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
989 break;
990
991 #if 0
992 case IRP_MN_QUERY_PNP_DEVICE_STATE:
993 break;
994 #endif
995
996 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
997 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS received\n");
998 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
999 break;
1000
1001 case IRP_MN_QUERY_RESOURCES:
1002 DPRINT("IRP_MN_QUERY_RESOURCES received\n");
1003 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1004 break;
1005
1006 #if 0
1007 case IRP_MN_SET_LOCK:
1008 break;
1009 #endif
1010
1011 case IRP_MN_START_DEVICE:
1012 case IRP_MN_QUERY_STOP_DEVICE:
1013 case IRP_MN_CANCEL_STOP_DEVICE:
1014 case IRP_MN_STOP_DEVICE:
1015 case IRP_MN_QUERY_REMOVE_DEVICE:
1016 case IRP_MN_CANCEL_REMOVE_DEVICE:
1017 case IRP_MN_REMOVE_DEVICE:
1018 case IRP_MN_SURPRISE_REMOVAL:
1019 Status = STATUS_SUCCESS;
1020 break;
1021
1022 case IRP_MN_READ_CONFIG:
1023 DPRINT1("IRP_MN_READ_CONFIG received\n");
1024 Status = PdoReadConfig(DeviceObject, Irp, IrpSp);
1025 break;
1026
1027 case IRP_MN_WRITE_CONFIG:
1028 DPRINT1("IRP_MN_WRITE_CONFIG received\n");
1029 Status = PdoWriteConfig(DeviceObject, Irp, IrpSp);
1030 break;
1031
1032 default:
1033 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1034 break;
1035 }
1036
1037 if (Status != STATUS_PENDING) {
1038 Irp->IoStatus.Status = Status;
1039 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1040 }
1041
1042 DPRINT("Leaving. Status 0x%X\n", Status);
1043
1044 return Status;
1045 }
1046
1047 NTSTATUS
1048 PdoPowerControl(
1049 PDEVICE_OBJECT DeviceObject,
1050 PIRP Irp)
1051 /*
1052 * FUNCTION: Handle power management IRPs for the child device
1053 * ARGUMENTS:
1054 * DeviceObject = Pointer to physical device object of the child device
1055 * Irp = Pointer to IRP that should be handled
1056 * RETURNS:
1057 * Status
1058 */
1059 {
1060 PIO_STACK_LOCATION IrpSp;
1061 NTSTATUS Status;
1062
1063 DPRINT("Called\n");
1064
1065 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1066
1067 switch (IrpSp->MinorFunction) {
1068 case IRP_MN_SET_POWER:
1069 Status = PdoSetPower(DeviceObject, Irp, IrpSp);
1070 break;
1071
1072 default:
1073 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1074 Status = STATUS_NOT_IMPLEMENTED;
1075 break;
1076 }
1077
1078 if (Status != STATUS_PENDING) {
1079 Irp->IoStatus.Status = Status;
1080 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1081 }
1082
1083 DPRINT("Leaving. Status 0x%X\n", Status);
1084
1085 return Status;
1086 }
1087
1088 /* EOF */