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