1 /* $Id: fdo.c,v 1.11 2004/11/15 11:49:37 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
,
26 PCI_SLOT_NUMBER SlotNumber
,
27 PPCI_COMMON_CONFIG PciConfig
)
29 PLIST_ENTRY CurrentEntry
;
30 PPCI_DEVICE CurrentDevice
;
34 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
35 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
36 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
38 /* If both vendor ID and device ID match, it is the same device */
39 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
40 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
41 (SlotNumber
.u
.AsULONG
== CurrentDevice
->SlotNumber
.u
.AsULONG
) &&
42 (BusNumber
== CurrentDevice
->BusNumber
)) {
43 *Device
= CurrentDevice
;
45 return STATUS_SUCCESS
;
48 CurrentEntry
= CurrentEntry
->Flink
;
53 return STATUS_UNSUCCESSFUL
;
59 PDEVICE_OBJECT DeviceObject
)
61 PFDO_DEVICE_EXTENSION DeviceExtension
;
62 PCI_COMMON_CONFIG PciConfig
;
63 PLIST_ENTRY CurrentEntry
;
65 PCI_SLOT_NUMBER SlotNumber
;
74 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
76 /* Mark all devices to be removed. If we don't discover them again during
77 enumeration, assume that they have been surprise removed */
78 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
79 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
80 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
81 Device
->RemovePending
= TRUE
;
82 CurrentEntry
= CurrentEntry
->Flink
;
85 DeviceExtension
->DeviceListCount
= 0;
87 /* Enumerate devices on the PCI bus */
88 for (BusNumber
= 0; BusNumber
< 8; BusNumber
++)
90 SlotNumber
.u
.AsULONG
= 0;
91 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
93 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
94 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
96 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
98 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
103 RtlZeroMemory(&PciConfig
,
104 sizeof(PCI_COMMON_CONFIG
));
106 Size
= HalGetBusData(PCIConfiguration
,
108 SlotNumber
.u
.AsULONG
,
110 PCI_COMMON_HDR_LENGTH
);
111 DPRINT("Size %lu\n", Size
);
112 if (Size
< PCI_COMMON_HDR_LENGTH
)
114 if (FunctionNumber
== 0)
124 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
131 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, BusNumber
, SlotNumber
, &PciConfig
);
132 if (!NT_SUCCESS(Status
))
134 Device
= (PPCI_DEVICE
)ExAllocatePool(PagedPool
, sizeof(PCI_DEVICE
));
137 /* FIXME: Cleanup resources for already discovered devices */
138 return STATUS_INSUFFICIENT_RESOURCES
;
141 RtlZeroMemory(Device
,
144 Device
->BusNumber
= BusNumber
;
146 RtlCopyMemory(&Device
->SlotNumber
,
148 sizeof(PCI_SLOT_NUMBER
));
150 RtlCopyMemory(&Device
->PciConfig
,
152 sizeof(PCI_COMMON_CONFIG
));
154 ExInterlockedInsertTailList(
155 &DeviceExtension
->DeviceListHead
,
157 &DeviceExtension
->DeviceListLock
);
160 /* Don't remove this device */
161 Device
->RemovePending
= FALSE
;
163 DeviceExtension
->DeviceListCount
++;
165 /* Skip to next device if the current one is not a multifunction device */
166 if ((FunctionNumber
== 0) &&
167 ((PciConfig
.HeaderType
& 0x80) == 0))
177 return STATUS_SUCCESS
;
182 FdoQueryBusRelations(
183 IN PDEVICE_OBJECT DeviceObject
,
185 PIO_STACK_LOCATION IrpSp
)
187 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
188 PFDO_DEVICE_EXTENSION DeviceExtension
;
189 PDEVICE_RELATIONS Relations
;
190 PLIST_ENTRY CurrentEntry
;
193 BOOLEAN ErrorOccurred
;
194 NTSTATUS ErrorStatus
;
200 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
202 Status
= STATUS_SUCCESS
;
204 ErrorOccurred
= FALSE
;
206 FdoEnumerateDevices(DeviceObject
);
208 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
210 if (Irp
->IoStatus
.Information
) {
211 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
212 structure so we must merge this structure with our own */
215 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(Relations
->Objects
) *
216 (DeviceExtension
->DeviceListCount
- 1);
217 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
219 return STATUS_INSUFFICIENT_RESOURCES
;
221 Relations
->Count
= DeviceExtension
->DeviceListCount
;
224 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
225 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
226 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
228 PdoDeviceExtension
= NULL
;
231 /* Create a physical device object for the
232 device as it does not already have one */
233 Status
= IoCreateDevice(
234 DeviceObject
->DriverObject
,
235 sizeof(PDO_DEVICE_EXTENSION
),
237 FILE_DEVICE_CONTROLLER
,
238 FILE_AUTOGENERATED_DEVICE_NAME
,
241 if (!NT_SUCCESS(Status
)) {
242 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
243 ErrorStatus
= Status
;
244 ErrorOccurred
= TRUE
;
248 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
250 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
252 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
254 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
256 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
258 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
260 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
262 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
264 PdoDeviceExtension
->Fdo
= DeviceObject
;
266 PdoDeviceExtension
->BusNumber
= Device
->BusNumber
;
269 &PdoDeviceExtension
->SlotNumber
,
271 sizeof(PCI_SLOT_NUMBER
));
273 /* Add Device ID string */
274 if (!PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
,
277 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
278 ErrorOccurred
= TRUE
;
282 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
284 /* Add Instance ID string */
285 if (!PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
,
288 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
289 ErrorOccurred
= TRUE
;
293 /* Add Hardware IDs string */
294 if (!PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
,
297 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
298 ErrorOccurred
= TRUE
;
302 /* Add Compatible IDs string */
303 if (!PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
,
306 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
307 ErrorOccurred
= TRUE
;
311 /* Add device description string */
312 if (!PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
,
315 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
316 ErrorOccurred
= TRUE
;
320 /* Add device location string */
321 if (!PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
,
324 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
325 ErrorOccurred
= TRUE
;
330 if (!Device
->RemovePending
) {
331 /* Reference the physical device object. The PnP manager
332 will dereference it again when it is no longer needed */
333 ObReferenceObject(Device
->Pdo
);
335 Relations
->Objects
[i
] = Device
->Pdo
;
340 CurrentEntry
= CurrentEntry
->Flink
;
344 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
345 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
346 if (PdoDeviceExtension
) {
347 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
348 ExFreePool(PdoDeviceExtension
);
351 ExFreePool(Relations
);
355 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
365 IN PDEVICE_OBJECT DeviceObject
,
368 PFDO_DEVICE_EXTENSION DeviceExtension
;
372 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
374 assert(DeviceExtension
->State
== dsStopped
);
376 InitializeListHead(&DeviceExtension
->DeviceListHead
);
377 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
378 DeviceExtension
->DeviceListCount
= 0;
379 DeviceExtension
->State
= dsStarted
;
381 //Irp->IoStatus.Information = 0;
383 return STATUS_SUCCESS
;
389 IN PDEVICE_OBJECT DeviceObject
,
391 PIO_STACK_LOCATION IrpSp
)
393 PFDO_DEVICE_EXTENSION DeviceExtension
;
398 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
400 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
) {
401 /* FIXME: Set device power state for the device */
402 Status
= STATUS_UNSUCCESSFUL
;
404 Status
= STATUS_UNSUCCESSFUL
;
411 /*** PUBLIC ******************************************************************/
415 PDEVICE_OBJECT DeviceObject
,
418 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
420 * DeviceObject = Pointer to functional device object of the PCI driver
421 * Irp = Pointer to IRP that should be handled
426 PFDO_DEVICE_EXTENSION DeviceExtension
;
427 PIO_STACK_LOCATION IrpSp
;
432 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
434 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
435 switch (IrpSp
->MinorFunction
) {
437 case IRP_MN_CANCEL_REMOVE_DEVICE
:
438 Status
= STATUS_NOT_IMPLEMENTED
;
441 case IRP_MN_CANCEL_STOP_DEVICE
:
442 Status
= STATUS_NOT_IMPLEMENTED
;
445 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
446 Status
= STATUS_NOT_IMPLEMENTED
;
449 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
450 Status
= STATUS_NOT_IMPLEMENTED
;
453 case IRP_MN_QUERY_DEVICE_RELATIONS
:
454 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
457 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
458 Status
= STATUS_NOT_IMPLEMENTED
;
461 case IRP_MN_QUERY_REMOVE_DEVICE
:
462 Status
= STATUS_NOT_IMPLEMENTED
;
465 case IRP_MN_QUERY_STOP_DEVICE
:
466 Status
= STATUS_NOT_IMPLEMENTED
;
469 case IRP_MN_REMOVE_DEVICE
:
470 Status
= STATUS_NOT_IMPLEMENTED
;
473 case IRP_MN_START_DEVICE
:
474 DPRINT("IRP_MN_START_DEVICE received\n");
475 Status
= FdoStartDevice(DeviceObject
, Irp
);
477 case IRP_MN_STOP_DEVICE
:
478 /* Currently not supported */
479 Status
= STATUS_UNSUCCESSFUL
;
482 case IRP_MN_SURPRISE_REMOVAL
:
483 Status
= STATUS_NOT_IMPLEMENTED
;
487 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
490 * Do NOT complete the IRP as it will be processed by the lower
491 * device object, which will complete the IRP
493 IoSkipCurrentIrpStackLocation(Irp
);
494 Status
= IoCallDriver(DeviceExtension
->Ldo
, Irp
);
500 if (Status
!= STATUS_PENDING
) {
501 if (Status
!= STATUS_NOT_IMPLEMENTED
)
502 Irp
->IoStatus
.Status
= Status
;
503 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
506 DPRINT("Leaving. Status 0x%X\n", Status
);
514 PDEVICE_OBJECT DeviceObject
,
517 * FUNCTION: Handle power management IRPs for the PCI device object
519 * DeviceObject = Pointer to functional device object of the PCI driver
520 * Irp = Pointer to IRP that should be handled
525 PIO_STACK_LOCATION IrpSp
;
530 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
532 switch (IrpSp
->MinorFunction
) {
533 case IRP_MN_SET_POWER
:
534 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
538 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
539 Status
= STATUS_NOT_IMPLEMENTED
;
543 if (Status
!= STATUS_PENDING
) {
544 Irp
->IoStatus
.Status
= Status
;
545 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
548 DPRINT("Leaving. Status 0x%X\n", Status
);