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 *****************************************************************/
20 PFDO_DEVICE_EXTENSION DeviceExtension
,
21 PCI_SLOT_NUMBER SlotNumber
,
22 PPCI_COMMON_CONFIG PciConfig
)
24 PLIST_ENTRY CurrentEntry
;
25 PPCI_DEVICE CurrentDevice
;
29 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
30 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
31 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
33 /* If both vendor ID and device ID match, it is the same device */
34 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
35 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
36 (SlotNumber
.u
.AsULONG
== CurrentDevice
->SlotNumber
.u
.AsULONG
)) {
37 *Device
= CurrentDevice
;
39 return STATUS_SUCCESS
;
42 CurrentEntry
= CurrentEntry
->Flink
;
47 return STATUS_UNSUCCESSFUL
;
53 PDEVICE_OBJECT DeviceObject
)
55 PFDO_DEVICE_EXTENSION DeviceExtension
;
56 PCI_COMMON_CONFIG PciConfig
;
57 PLIST_ENTRY CurrentEntry
;
59 PCI_SLOT_NUMBER SlotNumber
;
67 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
69 /* Mark all devices to be removed. If we don't discover them again during
70 enumeration, assume that they have been surprise removed */
71 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
72 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
73 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
74 Device
->RemovePending
= TRUE
;
75 CurrentEntry
= CurrentEntry
->Flink
;
78 DeviceExtension
->DeviceListCount
= 0;
80 /* Enumerate devices on the PCI bus */
81 SlotNumber
.u
.AsULONG
= 0;
82 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
84 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
85 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
87 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
89 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
90 DeviceExtension
->BusNumber
,
94 RtlZeroMemory(&PciConfig
,
95 sizeof(PCI_COMMON_CONFIG
));
97 Size
= HalGetBusData(PCIConfiguration
,
98 DeviceExtension
->BusNumber
,
101 PCI_COMMON_HDR_LENGTH
);
102 DPRINT("Size %lu\n", Size
);
103 if (Size
< PCI_COMMON_HDR_LENGTH
)
105 if (FunctionNumber
== 0)
115 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
116 DeviceExtension
->BusNumber
,
122 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, SlotNumber
, &PciConfig
);
123 if (!NT_SUCCESS(Status
))
125 Device
= (PPCI_DEVICE
)ExAllocatePool(NonPagedPool
, sizeof(PCI_DEVICE
));
128 /* FIXME: Cleanup resources for already discovered devices */
129 return STATUS_INSUFFICIENT_RESOURCES
;
132 RtlZeroMemory(Device
,
135 Device
->BusNumber
= DeviceExtension
->BusNumber
;
137 RtlCopyMemory(&Device
->SlotNumber
,
139 sizeof(PCI_SLOT_NUMBER
));
141 RtlCopyMemory(&Device
->PciConfig
,
143 sizeof(PCI_COMMON_CONFIG
));
145 ExInterlockedInsertTailList(
146 &DeviceExtension
->DeviceListHead
,
148 &DeviceExtension
->DeviceListLock
);
151 /* Don't remove this device */
152 Device
->RemovePending
= FALSE
;
154 DeviceExtension
->DeviceListCount
++;
156 /* Skip to next device if the current one is not a multifunction device */
157 if ((FunctionNumber
== 0) &&
158 ((PciConfig
.HeaderType
& 0x80) == 0))
167 return STATUS_SUCCESS
;
172 FdoQueryBusRelations(
173 IN PDEVICE_OBJECT DeviceObject
,
175 PIO_STACK_LOCATION IrpSp
)
177 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
178 PFDO_DEVICE_EXTENSION DeviceExtension
;
179 PDEVICE_RELATIONS Relations
;
180 PLIST_ENTRY CurrentEntry
;
183 BOOLEAN ErrorOccurred
;
184 NTSTATUS ErrorStatus
;
190 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
192 Status
= STATUS_SUCCESS
;
194 ErrorOccurred
= FALSE
;
196 FdoEnumerateDevices(DeviceObject
);
198 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
200 if (Irp
->IoStatus
.Information
) {
201 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
202 structure so we must merge this structure with our own */
205 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(Relations
->Objects
) *
206 (DeviceExtension
->DeviceListCount
- 1);
207 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
209 return STATUS_INSUFFICIENT_RESOURCES
;
211 Relations
->Count
= DeviceExtension
->DeviceListCount
;
214 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
215 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
216 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
218 PdoDeviceExtension
= NULL
;
221 /* Create a physical device object for the
222 device as it does not already have one */
223 Status
= IoCreateDevice(
224 DeviceObject
->DriverObject
,
225 sizeof(PDO_DEVICE_EXTENSION
),
227 FILE_DEVICE_CONTROLLER
,
228 FILE_AUTOGENERATED_DEVICE_NAME
,
231 if (!NT_SUCCESS(Status
)) {
232 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
233 ErrorStatus
= Status
;
234 ErrorOccurred
= TRUE
;
238 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
240 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
242 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
244 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
246 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
248 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
250 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
252 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
254 PdoDeviceExtension
->Fdo
= DeviceObject
;
256 PdoDeviceExtension
->PciDevice
= Device
;
258 /* Add Device ID string */
259 Status
= PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
, Device
);
260 if (!NT_SUCCESS(Status
))
262 ErrorStatus
= Status
;
263 ErrorOccurred
= TRUE
;
267 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
269 /* Add Instance ID string */
270 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
, Device
);
271 if (!NT_SUCCESS(Status
))
273 ErrorStatus
= Status
;
274 ErrorOccurred
= TRUE
;
278 /* Add Hardware IDs string */
279 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
, Device
);
280 if (!NT_SUCCESS(Status
))
282 ErrorStatus
= Status
;
283 ErrorOccurred
= TRUE
;
287 /* Add Compatible IDs string */
288 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
, Device
);
289 if (!NT_SUCCESS(Status
))
291 ErrorStatus
= Status
;
292 ErrorOccurred
= TRUE
;
296 /* Add device description string */
297 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
298 if (!NT_SUCCESS(Status
))
300 ErrorStatus
= Status
;
301 ErrorOccurred
= TRUE
;
305 /* Add device location string */
306 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
307 if (!NT_SUCCESS(Status
))
309 ErrorStatus
= Status
;
310 ErrorOccurred
= TRUE
;
315 if (!Device
->RemovePending
) {
316 /* Reference the physical device object. The PnP manager
317 will dereference it again when it is no longer needed */
318 ObReferenceObject(Device
->Pdo
);
320 Relations
->Objects
[i
] = Device
->Pdo
;
325 CurrentEntry
= CurrentEntry
->Flink
;
329 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
330 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
331 if (PdoDeviceExtension
) {
332 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
333 RtlFreeUnicodeString(&PdoDeviceExtension
->InstanceID
);
334 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIDs
);
335 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIDs
);
336 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
337 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceLocation
);
340 ExFreePool(Relations
);
344 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
354 IN PDEVICE_OBJECT DeviceObject
,
357 static BOOLEAN FoundBuggyAllocatedResourcesList
= FALSE
;
358 PFDO_DEVICE_EXTENSION DeviceExtension
;
359 PCM_RESOURCE_LIST AllocatedResources
;
360 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
361 ULONG FoundBusNumber
= FALSE
;
366 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
368 AllocatedResources
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.StartDevice
.AllocatedResources
;
369 /* HACK due to a bug in ACPI driver, which doesn't report the bus number */
370 if (!FoundBuggyAllocatedResourcesList
|| !AllocatedResources
|| AllocatedResources
->Count
== 0)
372 FoundBuggyAllocatedResourcesList
= TRUE
;
373 DPRINT1("No bus number resource found (bug in acpi.sys?), assuming bus number #0\n");
374 DeviceExtension
->BusNumber
= 0;
378 if (!AllocatedResources
)
380 DPRINT("No allocated resources sent to driver\n");
381 return STATUS_INSUFFICIENT_RESOURCES
;
383 if (AllocatedResources
->Count
< 1)
385 DPRINT("Not enough allocated resources sent to driver\n");
386 return STATUS_INSUFFICIENT_RESOURCES
;
388 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
389 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1)
390 return STATUS_REVISION_MISMATCH
;
392 ASSERT(DeviceExtension
->State
== dsStopped
);
394 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
396 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
397 switch (ResourceDescriptor
->Type
)
399 case CmResourceTypeBusNumber
:
401 if (FoundBusNumber
|| ResourceDescriptor
->u
.BusNumber
.Length
!= 1)
402 return STATUS_INVALID_PARAMETER
;
403 DeviceExtension
->BusNumber
= ResourceDescriptor
->u
.BusNumber
.Start
;
404 DPRINT("Found bus number resource: %lu\n", DeviceExtension
->BusNumber
);
405 FoundBusNumber
= TRUE
;
409 DPRINT1("Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
414 DPRINT("Some required resources were not found in allocated resources list\n");
415 return STATUS_INSUFFICIENT_RESOURCES
;
419 InitializeListHead(&DeviceExtension
->DeviceListHead
);
420 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
421 DeviceExtension
->DeviceListCount
= 0;
422 DeviceExtension
->State
= dsStarted
;
424 ExInterlockedInsertTailList(
425 &DriverExtension
->BusListHead
,
426 &DeviceExtension
->ListEntry
,
427 &DriverExtension
->BusListLock
);
429 Irp
->IoStatus
.Information
= 0;
431 return STATUS_SUCCESS
;
437 IN PDEVICE_OBJECT DeviceObject
,
439 PIO_STACK_LOCATION IrpSp
)
441 PFDO_DEVICE_EXTENSION DeviceExtension
;
446 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
448 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
) {
449 /* FIXME: Set device power state for the device */
450 Status
= STATUS_UNSUCCESSFUL
;
452 Status
= STATUS_UNSUCCESSFUL
;
459 /*** PUBLIC ******************************************************************/
463 PDEVICE_OBJECT DeviceObject
,
466 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
468 * DeviceObject = Pointer to functional device object of the PCI driver
469 * Irp = Pointer to IRP that should be handled
474 PFDO_DEVICE_EXTENSION DeviceExtension
;
475 PIO_STACK_LOCATION IrpSp
;
480 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
482 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
483 switch (IrpSp
->MinorFunction
) {
485 case IRP_MN_CANCEL_REMOVE_DEVICE
:
486 Status
= STATUS_NOT_IMPLEMENTED
;
489 case IRP_MN_CANCEL_STOP_DEVICE
:
490 Status
= STATUS_NOT_IMPLEMENTED
;
493 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
494 Status
= STATUS_NOT_IMPLEMENTED
;
497 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
498 Status
= STATUS_NOT_IMPLEMENTED
;
501 case IRP_MN_QUERY_DEVICE_RELATIONS
:
502 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
505 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
506 Status
= STATUS_NOT_IMPLEMENTED
;
509 case IRP_MN_QUERY_REMOVE_DEVICE
:
510 Status
= STATUS_NOT_IMPLEMENTED
;
513 case IRP_MN_QUERY_STOP_DEVICE
:
514 Status
= STATUS_NOT_IMPLEMENTED
;
517 case IRP_MN_REMOVE_DEVICE
:
518 Status
= STATUS_NOT_IMPLEMENTED
;
521 case IRP_MN_START_DEVICE
:
522 DPRINT("IRP_MN_START_DEVICE received\n");
523 Status
= FdoStartDevice(DeviceObject
, Irp
);
525 case IRP_MN_STOP_DEVICE
:
526 /* Currently not supported */
527 Status
= STATUS_UNSUCCESSFUL
;
530 case IRP_MN_SURPRISE_REMOVAL
:
531 Status
= STATUS_NOT_IMPLEMENTED
;
535 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
538 * Do NOT complete the IRP as it will be processed by the lower
539 * device object, which will complete the IRP
541 IoSkipCurrentIrpStackLocation(Irp
);
542 Status
= IoCallDriver(DeviceExtension
->Ldo
, Irp
);
548 if (Status
!= STATUS_PENDING
) {
549 if (Status
!= STATUS_NOT_IMPLEMENTED
)
550 Irp
->IoStatus
.Status
= Status
;
551 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
554 DPRINT("Leaving. Status 0x%X\n", Status
);
562 PDEVICE_OBJECT DeviceObject
,
565 * FUNCTION: Handle power management IRPs for the PCI device object
567 * DeviceObject = Pointer to functional device object of the PCI driver
568 * Irp = Pointer to IRP that should be handled
573 PIO_STACK_LOCATION IrpSp
;
578 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
580 switch (IrpSp
->MinorFunction
) {
581 case IRP_MN_SET_POWER
:
582 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
586 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
587 Status
= STATUS_NOT_IMPLEMENTED
;
591 if (Status
!= STATUS_PENDING
) {
592 Irp
->IoStatus
.Status
= Status
;
593 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
596 DPRINT("Leaving. Status 0x%X\n", Status
);