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
17 /*** PRIVATE *****************************************************************/
19 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion
;
22 ForwardIrpAndWaitCompletion(
23 IN PDEVICE_OBJECT DeviceObject
,
27 UNREFERENCED_PARAMETER(DeviceObject
);
28 if (Irp
->PendingReturned
)
29 KeSetEvent((PKEVENT
)Context
, IO_NO_INCREMENT
, FALSE
);
30 return STATUS_MORE_PROCESSING_REQUIRED
;
35 IN PDEVICE_OBJECT DeviceObject
,
40 PDEVICE_OBJECT LowerDevice
= ((PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->Ldo
;
43 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
44 IoCopyCurrentIrpStackLocationToNext(Irp
);
46 IoSetCompletionRoutine(Irp
, ForwardIrpAndWaitCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
48 Status
= IoCallDriver(LowerDevice
, Irp
);
49 if (Status
== STATUS_PENDING
)
51 Status
= KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
52 if (NT_SUCCESS(Status
))
53 Status
= Irp
->IoStatus
.Status
;
62 PFDO_DEVICE_EXTENSION DeviceExtension
,
63 PCI_SLOT_NUMBER SlotNumber
,
64 PPCI_COMMON_CONFIG PciConfig
)
66 PLIST_ENTRY CurrentEntry
;
67 PPCI_DEVICE CurrentDevice
;
71 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
72 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
73 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
75 /* If both vendor ID and device ID match, it is the same device */
76 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
77 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
78 (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
;
99 PLIST_ENTRY CurrentEntry
;
101 PCI_SLOT_NUMBER SlotNumber
;
103 ULONG FunctionNumber
;
109 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
111 /* Mark all devices to be removed. If we don't discover them again during
112 enumeration, assume that they have been surprise removed */
113 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
114 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
115 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
116 Device
->RemovePending
= TRUE
;
117 CurrentEntry
= CurrentEntry
->Flink
;
120 DeviceExtension
->DeviceListCount
= 0;
122 /* Enumerate devices on the PCI bus */
123 SlotNumber
.u
.AsULONG
= 0;
124 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
126 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
127 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
129 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
131 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
132 DeviceExtension
->BusNumber
,
136 RtlZeroMemory(&PciConfig
,
137 sizeof(PCI_COMMON_CONFIG
));
139 Size
= HalGetBusData(PCIConfiguration
,
140 DeviceExtension
->BusNumber
,
141 SlotNumber
.u
.AsULONG
,
143 PCI_COMMON_HDR_LENGTH
);
144 DPRINT("Size %lu\n", Size
);
145 if (Size
< PCI_COMMON_HDR_LENGTH
)
147 if (FunctionNumber
== 0)
157 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
158 DeviceExtension
->BusNumber
,
164 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, SlotNumber
, &PciConfig
);
165 if (!NT_SUCCESS(Status
))
167 Device
= (PPCI_DEVICE
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(PCI_DEVICE
),TAG_PCI
);
170 /* FIXME: Cleanup resources for already discovered devices */
171 return STATUS_INSUFFICIENT_RESOURCES
;
174 RtlZeroMemory(Device
,
177 Device
->BusNumber
= DeviceExtension
->BusNumber
;
179 RtlCopyMemory(&Device
->SlotNumber
,
181 sizeof(PCI_SLOT_NUMBER
));
183 RtlCopyMemory(&Device
->PciConfig
,
185 sizeof(PCI_COMMON_CONFIG
));
187 ExInterlockedInsertTailList(
188 &DeviceExtension
->DeviceListHead
,
190 &DeviceExtension
->DeviceListLock
);
193 /* Don't remove this device */
194 Device
->RemovePending
= FALSE
;
196 DeviceExtension
->DeviceListCount
++;
198 /* Skip to next device if the current one is not a multifunction device */
199 if ((FunctionNumber
== 0) &&
200 ((PciConfig
.HeaderType
& 0x80) == 0))
209 return STATUS_SUCCESS
;
214 FdoQueryBusRelations(
215 IN PDEVICE_OBJECT DeviceObject
,
217 PIO_STACK_LOCATION IrpSp
)
219 PPDO_DEVICE_EXTENSION PdoDeviceExtension
= NULL
;
220 PFDO_DEVICE_EXTENSION DeviceExtension
;
221 PDEVICE_RELATIONS Relations
;
222 PLIST_ENTRY CurrentEntry
;
225 BOOLEAN ErrorOccurred
;
226 NTSTATUS ErrorStatus
;
230 UNREFERENCED_PARAMETER(IrpSp
);
234 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
236 Status
= STATUS_SUCCESS
;
238 ErrorOccurred
= FALSE
;
240 FdoEnumerateDevices(DeviceObject
);
242 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
244 if (Irp
->IoStatus
.Information
) {
245 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
246 structure so we must merge this structure with our own */
249 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(Relations
->Objects
) *
250 (DeviceExtension
->DeviceListCount
- 1);
251 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
253 return STATUS_INSUFFICIENT_RESOURCES
;
255 Relations
->Count
= DeviceExtension
->DeviceListCount
;
258 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
259 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
260 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
262 PdoDeviceExtension
= NULL
;
265 /* Create a physical device object for the
266 device as it does not already have one */
267 Status
= IoCreateDevice(
268 DeviceObject
->DriverObject
,
269 sizeof(PDO_DEVICE_EXTENSION
),
271 FILE_DEVICE_CONTROLLER
,
272 FILE_AUTOGENERATED_DEVICE_NAME
,
275 if (!NT_SUCCESS(Status
)) {
276 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
277 ErrorStatus
= Status
;
278 ErrorOccurred
= TRUE
;
282 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
284 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
286 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
288 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
290 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
292 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
294 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
296 PdoDeviceExtension
->Fdo
= DeviceObject
;
298 PdoDeviceExtension
->PciDevice
= Device
;
300 /* Add Device ID string */
301 Status
= PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
, Device
);
302 if (!NT_SUCCESS(Status
))
304 ErrorStatus
= Status
;
305 ErrorOccurred
= TRUE
;
309 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
311 /* Add Instance ID string */
312 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
, Device
);
313 if (!NT_SUCCESS(Status
))
315 ErrorStatus
= Status
;
316 ErrorOccurred
= TRUE
;
320 /* Add Hardware IDs string */
321 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
, Device
);
322 if (!NT_SUCCESS(Status
))
324 ErrorStatus
= Status
;
325 ErrorOccurred
= TRUE
;
329 /* Add Compatible IDs string */
330 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
, Device
);
331 if (!NT_SUCCESS(Status
))
333 ErrorStatus
= Status
;
334 ErrorOccurred
= TRUE
;
338 /* Add device description string */
339 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
340 if (!NT_SUCCESS(Status
))
342 ErrorStatus
= Status
;
343 ErrorOccurred
= TRUE
;
347 /* Add device location string */
348 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
349 if (!NT_SUCCESS(Status
))
351 ErrorStatus
= Status
;
352 ErrorOccurred
= TRUE
;
357 if (!Device
->RemovePending
) {
358 /* Reference the physical device object. The PnP manager
359 will dereference it again when it is no longer needed */
360 ObReferenceObject(Device
->Pdo
);
362 Relations
->Objects
[i
] = Device
->Pdo
;
367 CurrentEntry
= CurrentEntry
->Flink
;
371 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
372 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
373 if (PdoDeviceExtension
) {
374 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
375 RtlFreeUnicodeString(&PdoDeviceExtension
->InstanceID
);
376 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIDs
);
377 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIDs
);
378 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
379 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceLocation
);
382 ExFreePool(Relations
);
386 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
396 IN PDEVICE_OBJECT DeviceObject
,
399 PFDO_DEVICE_EXTENSION DeviceExtension
;
400 PCM_RESOURCE_LIST AllocatedResources
;
401 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
402 ULONG FoundBusNumber
= FALSE
;
407 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
409 AllocatedResources
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.StartDevice
.AllocatedResources
;
410 if (!AllocatedResources
)
412 DPRINT("No allocated resources sent to driver\n");
413 return STATUS_INSUFFICIENT_RESOURCES
;
415 if (AllocatedResources
->Count
< 1)
417 DPRINT("Not enough allocated resources sent to driver\n");
418 return STATUS_INSUFFICIENT_RESOURCES
;
420 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
421 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1)
422 return STATUS_REVISION_MISMATCH
;
424 ASSERT(DeviceExtension
->State
== dsStopped
);
426 /* By default, use the bus number in the resource list header */
427 DeviceExtension
->BusNumber
= AllocatedResources
->List
[0].BusNumber
;
429 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
431 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
432 switch (ResourceDescriptor
->Type
)
434 case CmResourceTypeBusNumber
:
436 if (FoundBusNumber
|| ResourceDescriptor
->u
.BusNumber
.Length
!= 1)
437 return STATUS_INVALID_PARAMETER
;
438 /* Use this one instead */
439 ASSERT(AllocatedResources
->List
[0].BusNumber
== ResourceDescriptor
->u
.BusNumber
.Start
);
440 DeviceExtension
->BusNumber
= ResourceDescriptor
->u
.BusNumber
.Start
;
441 DPRINT("Found bus number resource: %lu\n", DeviceExtension
->BusNumber
);
442 FoundBusNumber
= TRUE
;
446 DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
450 InitializeListHead(&DeviceExtension
->DeviceListHead
);
451 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
452 DeviceExtension
->DeviceListCount
= 0;
453 DeviceExtension
->State
= dsStarted
;
455 ExInterlockedInsertTailList(
456 &DriverExtension
->BusListHead
,
457 &DeviceExtension
->ListEntry
,
458 &DriverExtension
->BusListLock
);
460 Irp
->IoStatus
.Information
= 0;
462 return STATUS_SUCCESS
;
468 IN PDEVICE_OBJECT DeviceObject
,
470 PIO_STACK_LOCATION IrpSp
)
474 UNREFERENCED_PARAMETER(Irp
);
478 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
) {
479 /* FIXME: Set device power state for the device */
480 Status
= STATUS_UNSUCCESSFUL
;
482 Status
= STATUS_UNSUCCESSFUL
;
489 /*** PUBLIC ******************************************************************/
493 PDEVICE_OBJECT DeviceObject
,
496 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
498 * DeviceObject = Pointer to functional device object of the PCI driver
499 * Irp = Pointer to IRP that should be handled
504 PFDO_DEVICE_EXTENSION DeviceExtension
;
505 PIO_STACK_LOCATION IrpSp
;
506 NTSTATUS Status
= Irp
->IoStatus
.Status
;
510 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
512 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
513 switch (IrpSp
->MinorFunction
) {
515 case IRP_MN_CANCEL_REMOVE_DEVICE
:
516 Status
= STATUS_NOT_IMPLEMENTED
;
519 case IRP_MN_CANCEL_STOP_DEVICE
:
520 Status
= STATUS_NOT_IMPLEMENTED
;
523 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
524 Status
= STATUS_NOT_IMPLEMENTED
;
527 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
528 Status
= STATUS_NOT_IMPLEMENTED
;
531 case IRP_MN_QUERY_DEVICE_RELATIONS
:
532 if (IrpSp
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
535 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
536 Irp
->IoStatus
.Status
= Status
;
537 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
540 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
541 Status
= STATUS_NOT_IMPLEMENTED
;
544 case IRP_MN_QUERY_REMOVE_DEVICE
:
545 Status
= STATUS_NOT_IMPLEMENTED
;
548 case IRP_MN_START_DEVICE
:
549 DPRINT("IRP_MN_START_DEVICE received\n");
550 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
551 if (NT_SUCCESS(Status
))
552 Status
= FdoStartDevice(DeviceObject
, Irp
);
554 Irp
->IoStatus
.Status
= Status
;
555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
558 case IRP_MN_QUERY_STOP_DEVICE
:
559 /* We don't support stopping yet */
560 Status
= STATUS_UNSUCCESSFUL
;
561 Irp
->IoStatus
.Status
= Status
;
562 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
565 case IRP_MN_STOP_DEVICE
:
566 /* We can't fail this one so we fail the QUERY_STOP request that precedes it */
569 case IRP_MN_SURPRISE_REMOVAL
:
570 Status
= STATUS_NOT_IMPLEMENTED
;
573 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
575 case IRP_MN_REMOVE_DEVICE
:
576 /* Detach the device object from the device stack */
577 IoDetachDevice(DeviceExtension
->Ldo
);
579 /* Delete the device object */
580 IoDeleteDevice(DeviceObject
);
583 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
) {
621 case IRP_MN_SET_POWER
:
622 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
626 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
627 Status
= STATUS_NOT_IMPLEMENTED
;
631 if (Status
!= STATUS_PENDING
) {
632 Irp
->IoStatus
.Status
= Status
;
633 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
636 DPRINT("Leaving. Status 0x%X\n", Status
);