1 /* $Id: fdo.c,v 1.9 2004/08/16 09:13:00 ekohl Exp $
3 * PROJECT: ReactOS PCI bus driver
5 * PURPOSE: PCI device object dispatch routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 10-09-2001 CSH Created
11 #include <ddk/ntddk.h>
19 /*** PRIVATE *****************************************************************/
24 PFDO_DEVICE_EXTENSION DeviceExtension
,
25 PCI_SLOT_NUMBER SlotNumber
,
26 PPCI_COMMON_CONFIG PciConfig
)
28 PLIST_ENTRY CurrentEntry
;
29 PPCI_DEVICE CurrentDevice
;
33 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
34 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
35 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
37 /* If both vendor ID and device ID match, it is the same device */
38 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
39 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
40 (SlotNumber
.u
.AsULONG
== CurrentDevice
->SlotNumber
.u
.AsULONG
)) {
41 *Device
= CurrentDevice
;
43 return STATUS_SUCCESS
;
46 CurrentEntry
= CurrentEntry
->Flink
;
51 return STATUS_UNSUCCESSFUL
;
57 PDEVICE_OBJECT DeviceObject
)
59 PFDO_DEVICE_EXTENSION DeviceExtension
;
60 PCI_COMMON_CONFIG PciConfig
;
61 PLIST_ENTRY CurrentEntry
;
63 PCI_SLOT_NUMBER SlotNumber
;
72 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
74 /* Mark all devices to be removed. If we don't discover them again during
75 enumeration, assume that they have been surprise removed */
76 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
77 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
78 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
79 Device
->RemovePending
= TRUE
;
80 CurrentEntry
= CurrentEntry
->Flink
;
83 DeviceExtension
->DeviceListCount
= 0;
85 /* Enumerate devices on the PCI bus */
86 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
88 SlotNumber
.u
.AsULONG
= 0;
89 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
91 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
92 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
94 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
96 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
101 RtlZeroMemory(&PciConfig
,
102 sizeof(PCI_COMMON_CONFIG
));
104 Size
= HalGetBusData(PCIConfiguration
,
106 SlotNumber
.u
.AsULONG
,
108 sizeof(PCI_COMMON_CONFIG
));
109 DPRINT("Size %lu\n", Size
);
110 if (Size
< sizeof(PCI_COMMON_CONFIG
))
112 if (FunctionNumber
== 0)
122 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
129 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, SlotNumber
, &PciConfig
);
130 if (!NT_SUCCESS(Status
))
132 Device
= (PPCI_DEVICE
)ExAllocatePool(PagedPool
, sizeof(PCI_DEVICE
));
135 /* FIXME: Cleanup resources for already discovered devices */
136 return STATUS_INSUFFICIENT_RESOURCES
;
139 RtlZeroMemory(Device
,
142 Device
->BusNumber
= BusNumber
;
144 RtlCopyMemory(&Device
->SlotNumber
,
146 sizeof(PCI_SLOT_NUMBER
));
148 RtlCopyMemory(&Device
->PciConfig
,
150 sizeof(PCI_COMMON_CONFIG
));
152 ExInterlockedInsertTailList(
153 &DeviceExtension
->DeviceListHead
,
155 &DeviceExtension
->DeviceListLock
);
158 /* Don't remove this device */
159 Device
->RemovePending
= FALSE
;
161 DeviceExtension
->DeviceListCount
++;
163 /* Skip to next device if the current one is not a multifunction device */
164 if ((FunctionNumber
== 0) &&
165 ((PciConfig
.HeaderType
& 0x80) == 0))
175 return STATUS_SUCCESS
;
180 FdoQueryBusRelations(
181 IN PDEVICE_OBJECT DeviceObject
,
183 PIO_STACK_LOCATION IrpSp
)
185 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
186 PFDO_DEVICE_EXTENSION DeviceExtension
;
187 PDEVICE_RELATIONS Relations
;
188 PLIST_ENTRY CurrentEntry
;
191 BOOLEAN ErrorOccurred
;
192 NTSTATUS ErrorStatus
;
198 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
200 Status
= STATUS_SUCCESS
;
202 ErrorOccurred
= FALSE
;
204 FdoEnumerateDevices(DeviceObject
);
206 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
208 if (Irp
->IoStatus
.Information
) {
209 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
210 structure so we must merge this structure with our own */
213 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(Relations
->Objects
) *
214 (DeviceExtension
->DeviceListCount
- 1);
215 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
217 return STATUS_INSUFFICIENT_RESOURCES
;
219 Relations
->Count
= DeviceExtension
->DeviceListCount
;
222 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
223 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
224 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
226 PdoDeviceExtension
= NULL
;
229 /* Create a physical device object for the
230 device as it does not already have one */
231 Status
= IoCreateDevice(
232 DeviceObject
->DriverObject
,
233 sizeof(PDO_DEVICE_EXTENSION
),
235 FILE_DEVICE_CONTROLLER
,
239 if (!NT_SUCCESS(Status
)) {
240 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
241 ErrorStatus
= Status
;
242 ErrorOccurred
= TRUE
;
246 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
248 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
250 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
252 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
254 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
256 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
258 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
260 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
262 PdoDeviceExtension
->Fdo
= DeviceObject
;
264 PdoDeviceExtension
->BusNumber
= Device
->BusNumber
;
267 &PdoDeviceExtension
->SlotNumber
,
269 sizeof(PCI_SLOT_NUMBER
));
271 /* Add Device ID string */
272 if (!PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
,
275 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
276 ErrorOccurred
= TRUE
;
280 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
282 /* Add Instance ID string */
283 if (!PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
,
286 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
287 ErrorOccurred
= TRUE
;
291 /* Add Hardware IDs string */
292 if (!PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
,
295 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
296 ErrorOccurred
= TRUE
;
300 /* Add Compatible IDs string */
301 if (!PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
,
304 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
305 ErrorOccurred
= TRUE
;
309 /* Add device description string */
310 if (!PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
,
313 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
314 ErrorOccurred
= TRUE
;
318 /* Add device location string */
319 if (!PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
,
322 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
323 ErrorOccurred
= TRUE
;
328 if (!Device
->RemovePending
) {
329 /* Reference the physical device object. The PnP manager
330 will dereference it again when it is no longer needed */
331 ObReferenceObject(Device
->Pdo
);
333 Relations
->Objects
[i
] = Device
->Pdo
;
338 CurrentEntry
= CurrentEntry
->Flink
;
342 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
343 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
344 if (PdoDeviceExtension
) {
345 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
346 ExFreePool(PdoDeviceExtension
);
349 ExFreePool(Relations
);
353 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
363 IN PDEVICE_OBJECT DeviceObject
,
366 PFDO_DEVICE_EXTENSION DeviceExtension
;
370 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
372 assert(DeviceExtension
->State
== dsStopped
);
374 InitializeListHead(&DeviceExtension
->DeviceListHead
);
375 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
376 DeviceExtension
->DeviceListCount
= 0;
377 DeviceExtension
->State
= dsStarted
;
379 //Irp->IoStatus.Information = 0;
381 return STATUS_SUCCESS
;
387 IN PDEVICE_OBJECT DeviceObject
,
389 PIO_STACK_LOCATION IrpSp
)
391 PFDO_DEVICE_EXTENSION DeviceExtension
;
396 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
398 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
) {
399 /* FIXME: Set device power state for the device */
400 Status
= STATUS_UNSUCCESSFUL
;
402 Status
= STATUS_UNSUCCESSFUL
;
409 /*** PUBLIC ******************************************************************/
413 PDEVICE_OBJECT DeviceObject
,
416 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
418 * DeviceObject = Pointer to functional device object of the PCI driver
419 * Irp = Pointer to IRP that should be handled
424 PFDO_DEVICE_EXTENSION DeviceExtension
;
425 PIO_STACK_LOCATION IrpSp
;
430 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
432 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
433 switch (IrpSp
->MinorFunction
) {
435 case IRP_MN_CANCEL_REMOVE_DEVICE
:
436 Status
= STATUS_NOT_IMPLEMENTED
;
439 case IRP_MN_CANCEL_STOP_DEVICE
:
440 Status
= STATUS_NOT_IMPLEMENTED
;
443 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
444 Status
= STATUS_NOT_IMPLEMENTED
;
447 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
448 Status
= STATUS_NOT_IMPLEMENTED
;
451 case IRP_MN_QUERY_DEVICE_RELATIONS
:
452 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
455 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
456 Status
= STATUS_NOT_IMPLEMENTED
;
459 case IRP_MN_QUERY_REMOVE_DEVICE
:
460 Status
= STATUS_NOT_IMPLEMENTED
;
463 case IRP_MN_QUERY_STOP_DEVICE
:
464 Status
= STATUS_NOT_IMPLEMENTED
;
467 case IRP_MN_REMOVE_DEVICE
:
468 Status
= STATUS_NOT_IMPLEMENTED
;
471 case IRP_MN_START_DEVICE
:
472 DPRINT("IRP_MN_START_DEVICE received\n");
473 Status
= FdoStartDevice(DeviceObject
, Irp
);
475 case IRP_MN_STOP_DEVICE
:
476 /* Currently not supported */
477 Status
= STATUS_UNSUCCESSFUL
;
480 case IRP_MN_SURPRISE_REMOVAL
:
481 Status
= STATUS_NOT_IMPLEMENTED
;
485 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
488 * Do NOT complete the IRP as it will be processed by the lower
489 * device object, which will complete the IRP
491 IoSkipCurrentIrpStackLocation(Irp
);
492 Status
= IoCallDriver(DeviceExtension
->Ldo
, Irp
);
498 if (Status
!= STATUS_PENDING
) {
499 if (Status
!= STATUS_NOT_IMPLEMENTED
)
500 Irp
->IoStatus
.Status
= Status
;
501 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
504 DPRINT("Leaving. Status 0x%X\n", Status
);
512 PDEVICE_OBJECT DeviceObject
,
515 * FUNCTION: Handle power management IRPs for the PCI device object
517 * DeviceObject = Pointer to functional device object of the PCI driver
518 * Irp = Pointer to IRP that should be handled
523 PIO_STACK_LOCATION IrpSp
;
528 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
530 switch (IrpSp
->MinorFunction
) {
531 case IRP_MN_SET_POWER
:
532 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
536 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
537 Status
= STATUS_NOT_IMPLEMENTED
;
541 if (Status
!= STATUS_PENDING
) {
542 Irp
->IoStatus
.Status
= Status
;
543 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
546 DPRINT("Leaving. Status 0x%X\n", Status
);