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