2 * PROJECT: ReactOS PCI bus driver
4 * PURPOSE: PCI device object dispatch routines
5 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * 10-09-2001 CSH Created
15 /*** PRIVATE *****************************************************************/
17 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
;
20 ForwardIrpAndWaitCompletion(
21 IN PDEVICE_OBJECT DeviceObject
,
25 UNREFERENCED_PARAMETER(DeviceObject
);
26 if (Irp
->PendingReturned
)
27 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
28 return STATUS_MORE_PROCESSING_REQUIRED
;
33 IN PDEVICE_OBJECT DeviceObject
,
38 PDEVICE_OBJECT LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Ldo
;
41 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
42 IoCopyCurrentIrpStackLocationToNext(Irp
);
44 IoSetCompletionRoutine(Irp
, ForwardIrpAndWaitCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
46 Status
= IoCallDriver(LowerDevice
, Irp
);
47 if (Status
== STATUS_PENDING
)
49 Status
= KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
50 if (NT_SUCCESS(Status
))
51 Status
= Irp
->IoStatus
.Status
;
60 PFDO_DEVICE_EXTENSION DeviceExtension
,
61 PCI_SLOT_NUMBER SlotNumber
,
62 PPCI_COMMON_CONFIG PciConfig
)
64 PLIST_ENTRY CurrentEntry
;
65 PPCI_DEVICE CurrentDevice
;
69 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
70 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
)
72 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
74 /* If both vendor ID and device ID match, it is the same device */
75 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
76 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
77 (SlotNumber
.u
.AsULONG
== CurrentDevice
->SlotNumber
.u
.AsULONG
))
79 *Device
= CurrentDevice
;
81 return STATUS_SUCCESS
;
84 CurrentEntry
= CurrentEntry
->Flink
;
89 return STATUS_UNSUCCESSFUL
;
95 PDEVICE_OBJECT DeviceObject
)
97 PFDO_DEVICE_EXTENSION DeviceExtension
;
98 PCI_COMMON_CONFIG PciConfig
;
100 PCI_SLOT_NUMBER SlotNumber
;
102 ULONG FunctionNumber
;
108 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
110 DeviceExtension
->DeviceListCount
= 0;
112 /* Enumerate devices on the PCI bus */
113 SlotNumber
.u
.AsULONG
= 0;
114 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
116 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
117 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
119 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
121 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
122 DeviceExtension
->BusNumber
,
126 RtlZeroMemory(&PciConfig
,
127 sizeof(PCI_COMMON_CONFIG
));
129 Size
= HalGetBusData(PCIConfiguration
,
130 DeviceExtension
->BusNumber
,
131 SlotNumber
.u
.AsULONG
,
133 PCI_COMMON_HDR_LENGTH
);
134 DPRINT("Size %lu\n", Size
);
135 if (Size
< PCI_COMMON_HDR_LENGTH
)
137 if (FunctionNumber
== 0)
147 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
148 DeviceExtension
->BusNumber
,
154 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, SlotNumber
, &PciConfig
);
155 if (!NT_SUCCESS(Status
))
157 Device
= (PPCI_DEVICE
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(PCI_DEVICE
),TAG_PCI
);
160 /* FIXME: Cleanup resources for already discovered devices */
161 return STATUS_INSUFFICIENT_RESOURCES
;
164 RtlZeroMemory(Device
,
167 Device
->BusNumber
= DeviceExtension
->BusNumber
;
169 RtlCopyMemory(&Device
->SlotNumber
,
171 sizeof(PCI_SLOT_NUMBER
));
173 RtlCopyMemory(&Device
->PciConfig
,
175 sizeof(PCI_COMMON_CONFIG
));
177 ExInterlockedInsertTailList(
178 &DeviceExtension
->DeviceListHead
,
180 &DeviceExtension
->DeviceListLock
);
183 DeviceExtension
->DeviceListCount
++;
185 /* Skip to next device if the current one is not a multifunction device */
186 if ((FunctionNumber
== 0) &&
187 ((PciConfig
.HeaderType
& 0x80) == 0))
196 return STATUS_SUCCESS
;
201 FdoQueryBusRelations(
202 IN PDEVICE_OBJECT DeviceObject
,
204 PIO_STACK_LOCATION IrpSp
)
206 PPDO_DEVICE_EXTENSION PdoDeviceExtension
= NULL
;
207 PFDO_DEVICE_EXTENSION DeviceExtension
;
208 PDEVICE_RELATIONS Relations
;
209 PLIST_ENTRY CurrentEntry
;
212 BOOLEAN ErrorOccurred
;
213 NTSTATUS ErrorStatus
;
217 UNREFERENCED_PARAMETER(IrpSp
);
221 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
223 Status
= STATUS_SUCCESS
;
225 ErrorOccurred
= FALSE
;
227 FdoEnumerateDevices(DeviceObject
);
229 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
231 if (Irp
->IoStatus
.Information
)
233 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
234 structure so we must merge this structure with our own */
237 Size
= sizeof(DEVICE_RELATIONS
) +
238 sizeof(Relations
->Objects
) * (DeviceExtension
->DeviceListCount
- 1);
239 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
241 return STATUS_INSUFFICIENT_RESOURCES
;
243 Relations
->Count
= DeviceExtension
->DeviceListCount
;
246 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
247 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
)
249 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
251 PdoDeviceExtension
= NULL
;
255 /* Create a physical device object for the
256 device as it does not already have one */
257 Status
= IoCreateDevice(DeviceObject
->DriverObject
,
258 sizeof(PDO_DEVICE_EXTENSION
),
260 FILE_DEVICE_CONTROLLER
,
261 FILE_AUTOGENERATED_DEVICE_NAME
,
264 if (!NT_SUCCESS(Status
))
266 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
267 ErrorStatus
= Status
;
268 ErrorOccurred
= TRUE
;
272 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
274 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
276 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
278 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
280 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
282 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
284 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
286 PdoDeviceExtension
->Fdo
= DeviceObject
;
288 PdoDeviceExtension
->PciDevice
= Device
;
290 /* Add Device ID string */
291 Status
= PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
, Device
);
292 if (!NT_SUCCESS(Status
))
294 ErrorStatus
= Status
;
295 ErrorOccurred
= TRUE
;
299 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
301 /* Add Instance ID string */
302 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
, Device
);
303 if (!NT_SUCCESS(Status
))
305 ErrorStatus
= Status
;
306 ErrorOccurred
= TRUE
;
310 /* Add Hardware IDs string */
311 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
, Device
);
312 if (!NT_SUCCESS(Status
))
314 ErrorStatus
= Status
;
315 ErrorOccurred
= TRUE
;
319 /* Add Compatible IDs string */
320 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
, Device
);
321 if (!NT_SUCCESS(Status
))
323 ErrorStatus
= Status
;
324 ErrorOccurred
= TRUE
;
328 /* Add device description string */
329 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
330 if (!NT_SUCCESS(Status
))
332 ErrorStatus
= Status
;
333 ErrorOccurred
= TRUE
;
337 /* Add device location string */
338 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
339 if (!NT_SUCCESS(Status
))
341 ErrorStatus
= Status
;
342 ErrorOccurred
= TRUE
;
347 /* Reference the physical device object. The PnP manager
348 will dereference it again when it is no longer needed */
349 ObReferenceObject(Device
->Pdo
);
351 Relations
->Objects
[i
] = Device
->Pdo
;
355 CurrentEntry
= CurrentEntry
->Flink
;
360 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
361 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
362 if (PdoDeviceExtension
)
364 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
365 RtlFreeUnicodeString(&PdoDeviceExtension
->InstanceID
);
366 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIDs
);
367 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIDs
);
368 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
369 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceLocation
);
372 ExFreePool(Relations
);
376 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
386 IN PDEVICE_OBJECT DeviceObject
,
389 PFDO_DEVICE_EXTENSION DeviceExtension
;
390 PCM_RESOURCE_LIST AllocatedResources
;
391 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
392 ULONG FoundBusNumber
= FALSE
;
397 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
399 AllocatedResources
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.StartDevice
.AllocatedResources
;
400 if (!AllocatedResources
)
402 DPRINT("No allocated resources sent to driver\n");
403 return STATUS_INSUFFICIENT_RESOURCES
;
406 if (AllocatedResources
->Count
< 1)
408 DPRINT("Not enough allocated resources sent to driver\n");
409 return STATUS_INSUFFICIENT_RESOURCES
;
412 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1 ||
413 AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1)
414 return STATUS_REVISION_MISMATCH
;
416 ASSERT(DeviceExtension
->State
== dsStopped
);
418 /* By default, use the bus number in the resource list header */
419 DeviceExtension
->BusNumber
= AllocatedResources
->List
[0].BusNumber
;
421 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
423 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
424 switch (ResourceDescriptor
->Type
)
426 case CmResourceTypeBusNumber
:
427 if (FoundBusNumber
|| ResourceDescriptor
->u
.BusNumber
.Length
!= 1)
428 return STATUS_INVALID_PARAMETER
;
430 /* Use this one instead */
431 ASSERT(AllocatedResources
->List
[0].BusNumber
== ResourceDescriptor
->u
.BusNumber
.Start
);
432 DeviceExtension
->BusNumber
= ResourceDescriptor
->u
.BusNumber
.Start
;
433 DPRINT("Found bus number resource: %lu\n", DeviceExtension
->BusNumber
);
434 FoundBusNumber
= TRUE
;
438 DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
442 InitializeListHead(&DeviceExtension
->DeviceListHead
);
443 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
444 DeviceExtension
->DeviceListCount
= 0;
445 DeviceExtension
->State
= dsStarted
;
447 ExInterlockedInsertTailList(
448 &DriverExtension
->BusListHead
,
449 &DeviceExtension
->ListEntry
,
450 &DriverExtension
->BusListLock
);
452 Irp
->IoStatus
.Information
= 0;
454 return STATUS_SUCCESS
;
460 IN PDEVICE_OBJECT DeviceObject
,
462 PIO_STACK_LOCATION IrpSp
)
466 UNREFERENCED_PARAMETER(DeviceObject
);
467 UNREFERENCED_PARAMETER(Irp
);
471 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
)
473 /* FIXME: Set device power state for the device */
474 Status
= STATUS_UNSUCCESSFUL
;
478 Status
= STATUS_UNSUCCESSFUL
;
485 /*** PUBLIC ******************************************************************/
489 PDEVICE_OBJECT DeviceObject
,
492 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
494 * DeviceObject = Pointer to functional device object of the PCI driver
495 * Irp = Pointer to IRP that should be handled
500 PFDO_DEVICE_EXTENSION DeviceExtension
;
501 PIO_STACK_LOCATION IrpSp
;
502 NTSTATUS Status
= Irp
->IoStatus
.Status
;
506 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
508 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
509 switch (IrpSp
->MinorFunction
)
512 case IRP_MN_CANCEL_REMOVE_DEVICE
:
513 Status
= STATUS_NOT_IMPLEMENTED
;
516 case IRP_MN_CANCEL_STOP_DEVICE
:
517 Status
= STATUS_NOT_IMPLEMENTED
;
520 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
521 Status
= STATUS_NOT_IMPLEMENTED
;
524 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
525 Status
= STATUS_NOT_IMPLEMENTED
;
528 case IRP_MN_QUERY_DEVICE_RELATIONS
:
529 if (IrpSp
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
532 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
533 Irp
->IoStatus
.Status
= Status
;
534 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
537 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
538 Status
= STATUS_NOT_IMPLEMENTED
;
541 case IRP_MN_QUERY_REMOVE_DEVICE
:
542 Status
= STATUS_NOT_IMPLEMENTED
;
545 case IRP_MN_START_DEVICE
:
546 DPRINT("IRP_MN_START_DEVICE received\n");
547 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
548 if (NT_SUCCESS(Status
))
549 Status
= FdoStartDevice(DeviceObject
, Irp
);
551 Irp
->IoStatus
.Status
= Status
;
552 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
555 case IRP_MN_QUERY_STOP_DEVICE
:
556 /* We don't support stopping yet */
557 Status
= STATUS_UNSUCCESSFUL
;
558 Irp
->IoStatus
.Status
= Status
;
559 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
562 case IRP_MN_STOP_DEVICE
:
563 /* We can't fail this one so we fail the QUERY_STOP request that precedes it */
566 case IRP_MN_SURPRISE_REMOVAL
:
567 Status
= STATUS_NOT_IMPLEMENTED
;
571 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
574 case IRP_MN_REMOVE_DEVICE
:
575 /* Detach the device object from the device stack */
576 IoDetachDevice(DeviceExtension
->Ldo
);
578 /* Delete the device object */
579 IoDeleteDevice(DeviceObject
);
582 Status
= STATUS_SUCCESS
;
586 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
590 Irp
->IoStatus
.Status
= Status
;
591 IoSkipCurrentIrpStackLocation(Irp
);
592 Status
= IoCallDriver(DeviceExtension
->Ldo
, Irp
);
594 DPRINT("Leaving. Status 0x%X\n", Status
);
602 PDEVICE_OBJECT DeviceObject
,
605 * FUNCTION: Handle power management IRPs for the PCI device object
607 * DeviceObject = Pointer to functional device object of the PCI driver
608 * Irp = Pointer to IRP that should be handled
613 PIO_STACK_LOCATION IrpSp
;
618 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
620 switch (IrpSp
->MinorFunction
)
622 case IRP_MN_SET_POWER
:
623 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
627 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
628 Status
= STATUS_NOT_IMPLEMENTED
;
632 if (Status
!= STATUS_PENDING
)
634 Irp
->IoStatus
.Status
= Status
;
635 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
638 DPRINT("Leaving. Status 0x%X\n", Status
);