Synchronize up to trunk's revision r57756.
[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 %u\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 %u\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
900 static BOOLEAN NTAPI
901 InterfaceBusTranslateBusAddress(
902 IN PVOID Context,
903 IN PHYSICAL_ADDRESS BusAddress,
904 IN ULONG Length,
905 IN OUT PULONG AddressSpace,
906 OUT PPHYSICAL_ADDRESS TranslatedAddress)
907 {
908 PPDO_DEVICE_EXTENSION DeviceExtension;
909
910 DPRINT("InterfaceBusTranslateBusAddress(%p %p 0x%lx %p %p)\n",
911 Context, BusAddress, Length, AddressSpace, TranslatedAddress);
912
913 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
914
915 return HalTranslateBusAddress(
916 PCIBus, DeviceExtension->PciDevice->BusNumber,
917 BusAddress, AddressSpace, TranslatedAddress);
918 }
919
920
921 static PDMA_ADAPTER NTAPI
922 InterfaceBusGetDmaAdapter(
923 IN PVOID Context,
924 IN PDEVICE_DESCRIPTION DeviceDescription,
925 OUT PULONG NumberOfMapRegisters)
926 {
927 DPRINT("InterfaceBusGetDmaAdapter(%p %p %p)\n",
928 Context, DeviceDescription, NumberOfMapRegisters);
929 return (PDMA_ADAPTER)HalGetAdapter(DeviceDescription, NumberOfMapRegisters);
930 }
931
932
933 static ULONG NTAPI
934 InterfaceBusSetBusData(
935 IN PVOID Context,
936 IN ULONG DataType,
937 IN PVOID Buffer,
938 IN ULONG Offset,
939 IN ULONG Length)
940 {
941 PPDO_DEVICE_EXTENSION DeviceExtension;
942 ULONG Size;
943
944 DPRINT("InterfaceBusSetBusData(%p 0x%lx %p 0x%lx 0x%lx)\n",
945 Context, DataType, Buffer, Offset, Length);
946
947 if (DataType != PCI_WHICHSPACE_CONFIG)
948 {
949 DPRINT("Unknown DataType %lu\n", DataType);
950 return 0;
951 }
952
953 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
954
955 /* Get PCI configuration space */
956 Size = HalSetBusDataByOffset(PCIConfiguration,
957 DeviceExtension->PciDevice->BusNumber,
958 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
959 Buffer,
960 Offset,
961 Length);
962 return Size;
963 }
964
965
966 static ULONG NTAPI
967 InterfaceBusGetBusData(
968 IN PVOID Context,
969 IN ULONG DataType,
970 IN PVOID Buffer,
971 IN ULONG Offset,
972 IN ULONG Length)
973 {
974 PPDO_DEVICE_EXTENSION DeviceExtension;
975 ULONG Size;
976
977 DPRINT("InterfaceBusGetBusData(%p 0x%lx %p 0x%lx 0x%lx) called\n",
978 Context, DataType, Buffer, Offset, Length);
979
980 if (DataType != PCI_WHICHSPACE_CONFIG)
981 {
982 DPRINT("Unknown DataType %lu\n", DataType);
983 return 0;
984 }
985
986 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
987
988 /* Get PCI configuration space */
989 Size = HalGetBusDataByOffset(PCIConfiguration,
990 DeviceExtension->PciDevice->BusNumber,
991 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
992 Buffer,
993 Offset,
994 Length);
995 return Size;
996 }
997
998
999 static BOOLEAN NTAPI
1000 InterfacePciDevicePresent(
1001 IN USHORT VendorID,
1002 IN USHORT DeviceID,
1003 IN UCHAR RevisionID,
1004 IN USHORT SubVendorID,
1005 IN USHORT SubSystemID,
1006 IN ULONG Flags)
1007 {
1008 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
1009 PPCI_DEVICE PciDevice;
1010 PLIST_ENTRY CurrentBus, CurrentEntry;
1011 KIRQL OldIrql;
1012 BOOLEAN Found = FALSE;
1013
1014 KeAcquireSpinLock(&DriverExtension->BusListLock, &OldIrql);
1015 CurrentBus = DriverExtension->BusListHead.Flink;
1016 while (!Found && CurrentBus != &DriverExtension->BusListHead)
1017 {
1018 FdoDeviceExtension = CONTAINING_RECORD(CurrentBus, FDO_DEVICE_EXTENSION, ListEntry);
1019
1020 KeAcquireSpinLockAtDpcLevel(&FdoDeviceExtension->DeviceListLock);
1021 CurrentEntry = FdoDeviceExtension->DeviceListHead.Flink;
1022 while (!Found && CurrentEntry != &FdoDeviceExtension->DeviceListHead)
1023 {
1024 PciDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
1025 if (PciDevice->PciConfig.VendorID == VendorID &&
1026 PciDevice->PciConfig.DeviceID == DeviceID)
1027 {
1028 if (!(Flags & PCI_USE_SUBSYSTEM_IDS) || (
1029 PciDevice->PciConfig.u.type0.SubVendorID == SubVendorID &&
1030 PciDevice->PciConfig.u.type0.SubSystemID == SubSystemID))
1031 {
1032 if (!(Flags & PCI_USE_REVISION) ||
1033 PciDevice->PciConfig.RevisionID == RevisionID)
1034 {
1035 DPRINT("Found the PCI device\n");
1036 Found = TRUE;
1037 }
1038 }
1039 }
1040
1041 CurrentEntry = CurrentEntry->Flink;
1042 }
1043
1044 KeReleaseSpinLockFromDpcLevel(&FdoDeviceExtension->DeviceListLock);
1045 CurrentBus = CurrentBus->Flink;
1046 }
1047 KeReleaseSpinLock(&DriverExtension->BusListLock, OldIrql);
1048
1049 return Found;
1050 }
1051
1052
1053 static BOOLEAN
1054 CheckPciDevice(
1055 IN PPCI_COMMON_CONFIG PciConfig,
1056 IN PPCI_DEVICE_PRESENCE_PARAMETERS Parameters)
1057 {
1058 if ((Parameters->Flags & PCI_USE_VENDEV_IDS) && (
1059 PciConfig->VendorID != Parameters->VendorID ||
1060 PciConfig->DeviceID != Parameters->DeviceID))
1061 {
1062 return FALSE;
1063 }
1064 if ((Parameters->Flags & PCI_USE_CLASS_SUBCLASS) && (
1065 PciConfig->BaseClass != Parameters->BaseClass ||
1066 PciConfig->SubClass != Parameters->SubClass))
1067 {
1068 return FALSE;
1069 }
1070 if ((Parameters->Flags & PCI_USE_PROGIF) &&
1071 PciConfig->ProgIf != Parameters->ProgIf)
1072 {
1073 return FALSE;
1074 }
1075 if ((Parameters->Flags & PCI_USE_SUBSYSTEM_IDS) && (
1076 PciConfig->u.type0.SubVendorID != Parameters->SubVendorID ||
1077 PciConfig->u.type0.SubSystemID != Parameters->SubSystemID))
1078 {
1079 return FALSE;
1080 }
1081 if ((Parameters->Flags & PCI_USE_REVISION) &&
1082 PciConfig->RevisionID != Parameters->RevisionID)
1083 {
1084 return FALSE;
1085 }
1086 return TRUE;
1087 }
1088
1089
1090 static BOOLEAN NTAPI
1091 InterfacePciDevicePresentEx(
1092 IN PVOID Context,
1093 IN PPCI_DEVICE_PRESENCE_PARAMETERS Parameters)
1094 {
1095 PPDO_DEVICE_EXTENSION DeviceExtension;
1096 PFDO_DEVICE_EXTENSION MyFdoDeviceExtension;
1097 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
1098 PPCI_DEVICE PciDevice;
1099 PLIST_ENTRY CurrentBus, CurrentEntry;
1100 KIRQL OldIrql;
1101 BOOLEAN Found = FALSE;
1102
1103 DPRINT("InterfacePciDevicePresentEx(%p %p) called\n",
1104 Context, Parameters);
1105
1106 if (!Parameters || Parameters->Size != sizeof(PCI_DEVICE_PRESENCE_PARAMETERS))
1107 return FALSE;
1108
1109 DeviceExtension = (PPDO_DEVICE_EXTENSION)((PDEVICE_OBJECT)Context)->DeviceExtension;
1110 MyFdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceExtension->Fdo->DeviceExtension;
1111
1112 if (Parameters->Flags & PCI_USE_LOCAL_DEVICE)
1113 {
1114 return CheckPciDevice(&DeviceExtension->PciDevice->PciConfig, Parameters);
1115 }
1116
1117 KeAcquireSpinLock(&DriverExtension->BusListLock, &OldIrql);
1118 CurrentBus = DriverExtension->BusListHead.Flink;
1119 while (!Found && CurrentBus != &DriverExtension->BusListHead)
1120 {
1121 FdoDeviceExtension = CONTAINING_RECORD(CurrentBus, FDO_DEVICE_EXTENSION, ListEntry);
1122 if (!(Parameters->Flags & PCI_USE_LOCAL_BUS) || FdoDeviceExtension == MyFdoDeviceExtension)
1123 {
1124 KeAcquireSpinLockAtDpcLevel(&FdoDeviceExtension->DeviceListLock);
1125 CurrentEntry = FdoDeviceExtension->DeviceListHead.Flink;
1126 while (!Found && CurrentEntry != &FdoDeviceExtension->DeviceListHead)
1127 {
1128 PciDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry);
1129
1130 if (CheckPciDevice(&PciDevice->PciConfig, Parameters))
1131 {
1132 DPRINT("Found the PCI device\n");
1133 Found = TRUE;
1134 }
1135
1136 CurrentEntry = CurrentEntry->Flink;
1137 }
1138
1139 KeReleaseSpinLockFromDpcLevel(&FdoDeviceExtension->DeviceListLock);
1140 }
1141 CurrentBus = CurrentBus->Flink;
1142 }
1143 KeReleaseSpinLock(&DriverExtension->BusListLock, OldIrql);
1144
1145 return Found;
1146 }
1147
1148
1149 static NTSTATUS
1150 PdoQueryInterface(
1151 IN PDEVICE_OBJECT DeviceObject,
1152 IN PIRP Irp,
1153 PIO_STACK_LOCATION IrpSp)
1154 {
1155 NTSTATUS Status;
1156
1157 UNREFERENCED_PARAMETER(Irp);
1158 if (RtlCompareMemory(IrpSp->Parameters.QueryInterface.InterfaceType,
1159 &GUID_BUS_INTERFACE_STANDARD, sizeof(GUID)) == sizeof(GUID))
1160 {
1161 /* BUS_INTERFACE_STANDARD */
1162 if (IrpSp->Parameters.QueryInterface.Version < 1)
1163 Status = STATUS_NOT_SUPPORTED;
1164 else if (IrpSp->Parameters.QueryInterface.Size < sizeof(BUS_INTERFACE_STANDARD))
1165 Status = STATUS_BUFFER_TOO_SMALL;
1166 else
1167 {
1168 PBUS_INTERFACE_STANDARD BusInterface;
1169 BusInterface = (PBUS_INTERFACE_STANDARD)IrpSp->Parameters.QueryInterface.Interface;
1170 BusInterface->Size = sizeof(BUS_INTERFACE_STANDARD);
1171 BusInterface->Version = 1;
1172 BusInterface->TranslateBusAddress = InterfaceBusTranslateBusAddress;
1173 BusInterface->GetDmaAdapter = InterfaceBusGetDmaAdapter;
1174 BusInterface->SetBusData = InterfaceBusSetBusData;
1175 BusInterface->GetBusData = InterfaceBusGetBusData;
1176 Status = STATUS_SUCCESS;
1177 }
1178 }
1179 else if (RtlCompareMemory(IrpSp->Parameters.QueryInterface.InterfaceType,
1180 &GUID_PCI_DEVICE_PRESENT_INTERFACE, sizeof(GUID)) == sizeof(GUID))
1181 {
1182 /* PCI_DEVICE_PRESENT_INTERFACE */
1183 if (IrpSp->Parameters.QueryInterface.Version < 1)
1184 Status = STATUS_NOT_SUPPORTED;
1185 else if (IrpSp->Parameters.QueryInterface.Size < sizeof(PCI_DEVICE_PRESENT_INTERFACE))
1186 Status = STATUS_BUFFER_TOO_SMALL;
1187 else
1188 {
1189 PPCI_DEVICE_PRESENT_INTERFACE PciDevicePresentInterface;
1190 PciDevicePresentInterface = (PPCI_DEVICE_PRESENT_INTERFACE)IrpSp->Parameters.QueryInterface.Interface;
1191 PciDevicePresentInterface->Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
1192 PciDevicePresentInterface->Version = 1;
1193 PciDevicePresentInterface->IsDevicePresent = InterfacePciDevicePresent;
1194 PciDevicePresentInterface->IsDevicePresentEx = InterfacePciDevicePresentEx;
1195 Status = STATUS_SUCCESS;
1196 }
1197 }
1198 else
1199 {
1200 /* Not a supported interface */
1201 return STATUS_NOT_SUPPORTED;
1202 }
1203
1204 if (NT_SUCCESS(Status))
1205 {
1206 /* Add a reference for the returned interface */
1207 PINTERFACE Interface;
1208 Interface = (PINTERFACE)IrpSp->Parameters.QueryInterface.Interface;
1209 Interface->Context = DeviceObject;
1210 Interface->InterfaceReference = InterfaceReference;
1211 Interface->InterfaceDereference = InterfaceDereference;
1212 Interface->InterfaceReference(Interface->Context);
1213 }
1214
1215 return Status;
1216 }
1217
1218 static NTSTATUS
1219 PdoStartDevice(
1220 IN PDEVICE_OBJECT DeviceObject,
1221 IN PIRP Irp,
1222 PIO_STACK_LOCATION IrpSp)
1223 {
1224 PCM_RESOURCE_LIST RawResList = IrpSp->Parameters.StartDevice.AllocatedResources;
1225 PCM_FULL_RESOURCE_DESCRIPTOR RawFullDesc;
1226 PCM_PARTIAL_RESOURCE_DESCRIPTOR RawPartialDesc;
1227 ULONG i, ii;
1228 PPDO_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1229 UCHAR Irq;
1230 USHORT Command;
1231
1232 if (!RawResList)
1233 return STATUS_SUCCESS;
1234
1235 /* TODO: Assign the other resources we get to the card */
1236
1237 for (i = 0; i < RawResList->Count; i++)
1238 {
1239 RawFullDesc = &RawResList->List[i];
1240
1241 for (ii = 0; ii < RawFullDesc->PartialResourceList.Count; ii++)
1242 {
1243 RawPartialDesc = &RawFullDesc->PartialResourceList.PartialDescriptors[ii];
1244
1245 if (RawPartialDesc->Type == CmResourceTypeInterrupt)
1246 {
1247 DPRINT1("Assigning IRQ %d to PCI device 0x%x on bus 0x%x\n",
1248 RawPartialDesc->u.Interrupt.Vector,
1249 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1250 DeviceExtension->PciDevice->BusNumber);
1251
1252 Irq = (UCHAR)RawPartialDesc->u.Interrupt.Vector;
1253 HalSetBusDataByOffset(PCIConfiguration,
1254 DeviceExtension->PciDevice->BusNumber,
1255 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1256 &Irq,
1257 0x3c /* PCI_INTERRUPT_LINE */,
1258 sizeof(UCHAR));
1259 }
1260 }
1261 }
1262
1263 Command = 0;
1264
1265 DPRINT1("Enabling command flags for PCI device 0x%x on bus 0x%x: ",
1266 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1267 DeviceExtension->PciDevice->BusNumber);
1268 if (DeviceExtension->PciDevice->EnableBusMaster)
1269 {
1270 Command |= PCI_ENABLE_BUS_MASTER;
1271 DbgPrint("[Bus master] ");
1272 }
1273
1274 if (DeviceExtension->PciDevice->EnableMemorySpace)
1275 {
1276 Command |= PCI_ENABLE_MEMORY_SPACE;
1277 DbgPrint("[Memory space enable] ");
1278 }
1279
1280 if (DeviceExtension->PciDevice->EnableIoSpace)
1281 {
1282 Command |= PCI_ENABLE_IO_SPACE;
1283 DbgPrint("[I/O space enable] ");
1284 }
1285
1286 if (Command != 0)
1287 {
1288 DbgPrint("\n");
1289
1290 /* OR with the previous value */
1291 Command |= DeviceExtension->PciDevice->PciConfig.Command;
1292
1293 HalSetBusDataByOffset(PCIConfiguration,
1294 DeviceExtension->PciDevice->BusNumber,
1295 DeviceExtension->PciDevice->SlotNumber.u.AsULONG,
1296 &Command,
1297 FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
1298 sizeof(USHORT));
1299 }
1300 else
1301 {
1302 DbgPrint("None\n");
1303 }
1304
1305 return STATUS_SUCCESS;
1306 }
1307
1308 static NTSTATUS
1309 PdoReadConfig(
1310 IN PDEVICE_OBJECT DeviceObject,
1311 IN PIRP Irp,
1312 PIO_STACK_LOCATION IrpSp)
1313 {
1314 ULONG Size;
1315
1316 DPRINT("PdoReadConfig() called\n");
1317
1318 Size = InterfaceBusGetBusData(
1319 DeviceObject,
1320 IrpSp->Parameters.ReadWriteConfig.WhichSpace,
1321 IrpSp->Parameters.ReadWriteConfig.Buffer,
1322 IrpSp->Parameters.ReadWriteConfig.Offset,
1323 IrpSp->Parameters.ReadWriteConfig.Length);
1324
1325 if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
1326 {
1327 DPRINT1("Size %lu Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
1328 Irp->IoStatus.Information = 0;
1329 return STATUS_UNSUCCESSFUL;
1330 }
1331
1332 Irp->IoStatus.Information = Size;
1333
1334 return STATUS_SUCCESS;
1335 }
1336
1337
1338 static NTSTATUS
1339 PdoWriteConfig(
1340 IN PDEVICE_OBJECT DeviceObject,
1341 IN PIRP Irp,
1342 PIO_STACK_LOCATION IrpSp)
1343 {
1344 ULONG Size;
1345
1346 DPRINT1("PdoWriteConfig() called\n");
1347
1348 /* Get PCI configuration space */
1349 Size = InterfaceBusSetBusData(
1350 DeviceObject,
1351 IrpSp->Parameters.ReadWriteConfig.WhichSpace,
1352 IrpSp->Parameters.ReadWriteConfig.Buffer,
1353 IrpSp->Parameters.ReadWriteConfig.Offset,
1354 IrpSp->Parameters.ReadWriteConfig.Length);
1355
1356 if (Size != IrpSp->Parameters.ReadWriteConfig.Length)
1357 {
1358 DPRINT1("Size %lu Length %lu\n", Size, IrpSp->Parameters.ReadWriteConfig.Length);
1359 Irp->IoStatus.Information = 0;
1360 return STATUS_UNSUCCESSFUL;
1361 }
1362
1363 Irp->IoStatus.Information = Size;
1364
1365 return STATUS_SUCCESS;
1366 }
1367
1368 static NTSTATUS
1369 PdoQueryDeviceRelations(
1370 IN PDEVICE_OBJECT DeviceObject,
1371 IN PIRP Irp,
1372 PIO_STACK_LOCATION IrpSp)
1373 {
1374 PDEVICE_RELATIONS DeviceRelations;
1375
1376 /* We only support TargetDeviceRelation for child PDOs */
1377 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
1378 return Irp->IoStatus.Status;
1379
1380 /* We can do this because we only return 1 PDO for TargetDeviceRelation */
1381 DeviceRelations = ExAllocatePool(PagedPool, sizeof(*DeviceRelations));
1382 if (!DeviceRelations)
1383 return STATUS_INSUFFICIENT_RESOURCES;
1384
1385 DeviceRelations->Count = 1;
1386 DeviceRelations->Objects[0] = DeviceObject;
1387
1388 /* The PnP manager will remove this when it is done with the PDO */
1389 ObReferenceObject(DeviceObject);
1390
1391 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
1392
1393 return STATUS_SUCCESS;
1394 }
1395
1396 static NTSTATUS
1397 PdoSetPower(
1398 IN PDEVICE_OBJECT DeviceObject,
1399 IN PIRP Irp,
1400 PIO_STACK_LOCATION IrpSp)
1401 {
1402 NTSTATUS Status;
1403
1404 UNREFERENCED_PARAMETER(Irp);
1405 DPRINT("Called\n");
1406
1407 if (IrpSp->Parameters.Power.Type == DevicePowerState) {
1408 Status = STATUS_SUCCESS;
1409 switch (IrpSp->Parameters.Power.State.SystemState) {
1410 default:
1411 Status = STATUS_UNSUCCESSFUL;
1412 }
1413 } else {
1414 Status = STATUS_UNSUCCESSFUL;
1415 }
1416
1417 return Status;
1418 }
1419
1420
1421 /*** PUBLIC ******************************************************************/
1422
1423 NTSTATUS
1424 PdoPnpControl(
1425 PDEVICE_OBJECT DeviceObject,
1426 PIRP Irp)
1427 /*
1428 * FUNCTION: Handle Plug and Play IRPs for the child device
1429 * ARGUMENTS:
1430 * DeviceObject = Pointer to physical device object of the child device
1431 * Irp = Pointer to IRP that should be handled
1432 * RETURNS:
1433 * Status
1434 */
1435 {
1436 PIO_STACK_LOCATION IrpSp;
1437 NTSTATUS Status;
1438
1439 DPRINT("Called\n");
1440
1441 Status = Irp->IoStatus.Status;
1442
1443 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1444
1445 switch (IrpSp->MinorFunction) {
1446
1447 case IRP_MN_DEVICE_USAGE_NOTIFICATION:
1448 DPRINT("Unimplemented IRP_MN_DEVICE_USAGE_NOTIFICATION received\n");
1449 break;
1450
1451 case IRP_MN_EJECT:
1452 DPRINT("Unimplemented IRP_MN_EJECT received\n");
1453 break;
1454
1455 case IRP_MN_QUERY_BUS_INFORMATION:
1456 Status = PdoQueryBusInformation(DeviceObject, Irp, IrpSp);
1457 break;
1458
1459 case IRP_MN_QUERY_CAPABILITIES:
1460 Status = PdoQueryCapabilities(DeviceObject, Irp, IrpSp);
1461 break;
1462
1463 case IRP_MN_QUERY_DEVICE_RELATIONS:
1464 Status = PdoQueryDeviceRelations(DeviceObject, Irp, IrpSp);
1465 break;
1466
1467 case IRP_MN_QUERY_DEVICE_TEXT:
1468 DPRINT("IRP_MN_QUERY_DEVICE_TEXT received\n");
1469 Status = PdoQueryDeviceText(DeviceObject, Irp, IrpSp);
1470 break;
1471
1472 case IRP_MN_QUERY_ID:
1473 DPRINT("IRP_MN_QUERY_ID received\n");
1474 Status = PdoQueryId(DeviceObject, Irp, IrpSp);
1475 break;
1476
1477 case IRP_MN_QUERY_PNP_DEVICE_STATE:
1478 DPRINT("Unimplemented IRP_MN_QUERY_ID received\n");
1479 break;
1480
1481 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
1482 DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS received\n");
1483 Status = PdoQueryResourceRequirements(DeviceObject, Irp, IrpSp);
1484 break;
1485
1486 case IRP_MN_QUERY_RESOURCES:
1487 DPRINT("IRP_MN_QUERY_RESOURCES received\n");
1488 Status = PdoQueryResources(DeviceObject, Irp, IrpSp);
1489 break;
1490
1491 case IRP_MN_SET_LOCK:
1492 DPRINT("Unimplemented IRP_MN_SET_LOCK received\n");
1493 break;
1494
1495 case IRP_MN_START_DEVICE:
1496 Status = PdoStartDevice(DeviceObject, Irp, IrpSp);
1497 break;
1498
1499 case IRP_MN_QUERY_STOP_DEVICE:
1500 case IRP_MN_CANCEL_STOP_DEVICE:
1501 case IRP_MN_STOP_DEVICE:
1502 case IRP_MN_QUERY_REMOVE_DEVICE:
1503 case IRP_MN_CANCEL_REMOVE_DEVICE:
1504 case IRP_MN_SURPRISE_REMOVAL:
1505 Status = STATUS_SUCCESS;
1506 break;
1507
1508 case IRP_MN_REMOVE_DEVICE:
1509 {
1510 PPDO_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
1511 PFDO_DEVICE_EXTENSION FdoDeviceExtension = DeviceExtension->Fdo->DeviceExtension;
1512 KIRQL OldIrql;
1513
1514 /* Remove it from the device list */
1515 KeAcquireSpinLock(&FdoDeviceExtension->DeviceListLock, &OldIrql);
1516 RemoveEntryList(&DeviceExtension->PciDevice->ListEntry);
1517 FdoDeviceExtension->DeviceListCount--;
1518 KeReleaseSpinLock(&FdoDeviceExtension->DeviceListLock, OldIrql);
1519
1520 /* Free the device */
1521 ExFreePool(DeviceExtension->PciDevice);
1522
1523 /* Complete the IRP */
1524 Irp->IoStatus.Status = STATUS_SUCCESS;
1525 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1526
1527 /* Delete the DO */
1528 IoDeleteDevice(DeviceObject);
1529 return STATUS_SUCCESS;
1530 }
1531
1532 case IRP_MN_QUERY_INTERFACE:
1533 DPRINT("IRP_MN_QUERY_INTERFACE received\n");
1534 Status = PdoQueryInterface(DeviceObject, Irp, IrpSp);
1535 break;
1536
1537 case IRP_MN_READ_CONFIG:
1538 DPRINT("IRP_MN_READ_CONFIG received\n");
1539 Status = PdoReadConfig(DeviceObject, Irp, IrpSp);
1540 break;
1541
1542 case IRP_MN_WRITE_CONFIG:
1543 DPRINT("IRP_MN_WRITE_CONFIG received\n");
1544 Status = PdoWriteConfig(DeviceObject, Irp, IrpSp);
1545 break;
1546
1547 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
1548 DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS received\n");
1549 /* Nothing to do */
1550 Irp->IoStatus.Status = Status;
1551 break;
1552
1553 default:
1554 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
1555 break;
1556 }
1557
1558 if (Status != STATUS_PENDING) {
1559 Irp->IoStatus.Status = Status;
1560 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1561 }
1562
1563 DPRINT("Leaving. Status 0x%X\n", Status);
1564
1565 return Status;
1566 }
1567
1568 NTSTATUS
1569 PdoPowerControl(
1570 PDEVICE_OBJECT DeviceObject,
1571 PIRP Irp)
1572 /*
1573 * FUNCTION: Handle power management IRPs for the child device
1574 * ARGUMENTS:
1575 * DeviceObject = Pointer to physical device object of the child device
1576 * Irp = Pointer to IRP that should be handled
1577 * RETURNS:
1578 * Status
1579 */
1580 {
1581 PIO_STACK_LOCATION IrpSp;
1582 NTSTATUS Status;
1583
1584 DPRINT("Called\n");
1585
1586 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1587
1588 switch (IrpSp->MinorFunction) {
1589 case IRP_MN_SET_POWER:
1590 Status = PdoSetPower(DeviceObject, Irp, IrpSp);
1591 break;
1592
1593 default:
1594 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction);
1595 Status = STATUS_NOT_IMPLEMENTED;
1596 break;
1597 }
1598
1599 if (Status != STATUS_PENDING) {
1600 Irp->IoStatus.Status = Status;
1601 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1602 }
1603
1604 DPRINT("Leaving. Status 0x%X\n", Status);
1605
1606 return Status;
1607 }
1608
1609 /* EOF */