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