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
10 #include <ddk/ntddk.h>
18 /*** PRIVATE *****************************************************************/
23 PFDO_DEVICE_EXTENSION DeviceExtension
,
24 PCI_SLOT_NUMBER SlotNumber
,
25 PPCI_COMMON_CONFIG PciConfig
)
27 PLIST_ENTRY CurrentEntry
;
28 PPCI_DEVICE CurrentDevice
;
32 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
33 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
34 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
36 /* If both vendor ID and device ID match, it is the same device */
37 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
38 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
39 (SlotNumber
.u
.AsULONG
== CurrentDevice
->SlotNumber
.u
.AsULONG
)) {
40 *Device
= CurrentDevice
;
42 return STATUS_SUCCESS
;
45 CurrentEntry
= CurrentEntry
->Flink
;
50 return STATUS_UNSUCCESSFUL
;
56 PDEVICE_OBJECT DeviceObject
)
58 PFDO_DEVICE_EXTENSION DeviceExtension
;
59 PCI_COMMON_CONFIG PciConfig
;
60 PLIST_ENTRY CurrentEntry
;
62 PCI_SLOT_NUMBER SlotNumber
;
70 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
72 /* Mark all devices to be removed. If we don't discover them again during
73 enumeration, assume that they have been surprise removed */
74 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
75 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
76 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
77 Device
->RemovePending
= TRUE
;
78 CurrentEntry
= CurrentEntry
->Flink
;
81 DeviceExtension
->DeviceListCount
= 0;
83 /* Enumerate devices on the PCI bus */
84 SlotNumber
.u
.AsULONG
= 0;
85 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
87 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
88 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
90 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
92 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
93 DeviceExtension
->BusNumber
,
97 RtlZeroMemory(&PciConfig
,
98 sizeof(PCI_COMMON_CONFIG
));
100 Size
= HalGetBusData(PCIConfiguration
,
101 DeviceExtension
->BusNumber
,
102 SlotNumber
.u
.AsULONG
,
104 PCI_COMMON_HDR_LENGTH
);
105 DPRINT("Size %lu\n", Size
);
106 if (Size
< PCI_COMMON_HDR_LENGTH
)
108 if (FunctionNumber
== 0)
118 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
119 DeviceExtension
->BusNumber
,
125 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, SlotNumber
, &PciConfig
);
126 if (!NT_SUCCESS(Status
))
128 Device
= (PPCI_DEVICE
)ExAllocatePool(NonPagedPool
, sizeof(PCI_DEVICE
));
131 /* FIXME: Cleanup resources for already discovered devices */
132 return STATUS_INSUFFICIENT_RESOURCES
;
135 RtlZeroMemory(Device
,
138 Device
->BusNumber
= DeviceExtension
->BusNumber
;
140 RtlCopyMemory(&Device
->SlotNumber
,
142 sizeof(PCI_SLOT_NUMBER
));
144 RtlCopyMemory(&Device
->PciConfig
,
146 sizeof(PCI_COMMON_CONFIG
));
148 ExInterlockedInsertTailList(
149 &DeviceExtension
->DeviceListHead
,
151 &DeviceExtension
->DeviceListLock
);
154 /* Don't remove this device */
155 Device
->RemovePending
= FALSE
;
157 DeviceExtension
->DeviceListCount
++;
159 /* Skip to next device if the current one is not a multifunction device */
160 if ((FunctionNumber
== 0) &&
161 ((PciConfig
.HeaderType
& 0x80) == 0))
170 return STATUS_SUCCESS
;
175 FdoQueryBusRelations(
176 IN PDEVICE_OBJECT DeviceObject
,
178 PIO_STACK_LOCATION IrpSp
)
180 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
181 PFDO_DEVICE_EXTENSION DeviceExtension
;
182 PDEVICE_RELATIONS Relations
;
183 PLIST_ENTRY CurrentEntry
;
186 BOOLEAN ErrorOccurred
;
187 NTSTATUS ErrorStatus
;
193 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
195 Status
= STATUS_SUCCESS
;
197 ErrorOccurred
= FALSE
;
199 FdoEnumerateDevices(DeviceObject
);
201 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
203 if (Irp
->IoStatus
.Information
) {
204 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
205 structure so we must merge this structure with our own */
208 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(Relations
->Objects
) *
209 (DeviceExtension
->DeviceListCount
- 1);
210 Relations
= (PDEVICE_RELATIONS
)ExAllocatePool(PagedPool
, Size
);
212 return STATUS_INSUFFICIENT_RESOURCES
;
214 Relations
->Count
= DeviceExtension
->DeviceListCount
;
217 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
218 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
219 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
221 PdoDeviceExtension
= NULL
;
224 /* Create a physical device object for the
225 device as it does not already have one */
226 Status
= IoCreateDevice(
227 DeviceObject
->DriverObject
,
228 sizeof(PDO_DEVICE_EXTENSION
),
230 FILE_DEVICE_CONTROLLER
,
231 FILE_AUTOGENERATED_DEVICE_NAME
,
234 if (!NT_SUCCESS(Status
)) {
235 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
236 ErrorStatus
= Status
;
237 ErrorOccurred
= TRUE
;
241 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
243 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
245 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
247 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
249 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
251 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
253 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
255 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
257 PdoDeviceExtension
->Fdo
= DeviceObject
;
259 PdoDeviceExtension
->PciDevice
= Device
;
261 /* Add Device ID string */
262 Status
= PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
, Device
);
263 if (!NT_SUCCESS(Status
))
265 ErrorStatus
= Status
;
266 ErrorOccurred
= TRUE
;
270 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
272 /* Add Instance ID string */
273 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
, Device
);
274 if (!NT_SUCCESS(Status
))
276 ErrorStatus
= Status
;
277 ErrorOccurred
= TRUE
;
281 /* Add Hardware IDs string */
282 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
, Device
);
283 if (!NT_SUCCESS(Status
))
285 ErrorStatus
= Status
;
286 ErrorOccurred
= TRUE
;
290 /* Add Compatible IDs string */
291 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
, Device
);
292 if (!NT_SUCCESS(Status
))
294 ErrorStatus
= Status
;
295 ErrorOccurred
= TRUE
;
299 /* Add device description string */
300 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
301 if (!NT_SUCCESS(Status
))
303 ErrorStatus
= Status
;
304 ErrorOccurred
= TRUE
;
308 /* Add device location string */
309 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
310 if (!NT_SUCCESS(Status
))
312 ErrorStatus
= Status
;
313 ErrorOccurred
= TRUE
;
318 if (!Device
->RemovePending
) {
319 /* Reference the physical device object. The PnP manager
320 will dereference it again when it is no longer needed */
321 ObReferenceObject(Device
->Pdo
);
323 Relations
->Objects
[i
] = Device
->Pdo
;
328 CurrentEntry
= CurrentEntry
->Flink
;
332 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
333 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
334 if (PdoDeviceExtension
) {
335 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
336 RtlFreeUnicodeString(&PdoDeviceExtension
->InstanceID
);
337 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIDs
);
338 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIDs
);
339 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
340 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceLocation
);
343 ExFreePool(Relations
);
347 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
357 IN PDEVICE_OBJECT DeviceObject
,
360 PFDO_DEVICE_EXTENSION DeviceExtension
;
361 PCM_RESOURCE_LIST AllocatedResources
;
362 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor
;
363 ULONG FoundBusNumber
= FALSE
;
368 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
370 AllocatedResources
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.StartDevice
.AllocatedResources
;
371 if (!AllocatedResources
)
373 DPRINT("No allocated resources sent to driver\n");
374 return STATUS_INSUFFICIENT_RESOURCES
;
376 if (AllocatedResources
->Count
< 1)
378 DPRINT("Not enough allocated resources sent to driver\n");
379 return STATUS_INSUFFICIENT_RESOURCES
;
381 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
382 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1)
383 return STATUS_REVISION_MISMATCH
;
385 ASSERT(DeviceExtension
->State
== dsStopped
);
387 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
389 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
390 switch (ResourceDescriptor
->Type
)
392 case CmResourceTypeBusNumber
:
394 if (FoundBusNumber
|| ResourceDescriptor
->u
.BusNumber
.Length
!= 1)
395 return STATUS_INVALID_PARAMETER
;
396 DeviceExtension
->BusNumber
= ResourceDescriptor
->u
.BusNumber
.Start
;
397 DPRINT("Found bus number resource: %lu\n", DeviceExtension
->BusNumber
);
398 FoundBusNumber
= TRUE
;
402 DPRINT1("Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
407 DPRINT("Some required resources were not found in allocated resources list\n");
408 return STATUS_INSUFFICIENT_RESOURCES
;
411 InitializeListHead(&DeviceExtension
->DeviceListHead
);
412 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
413 DeviceExtension
->DeviceListCount
= 0;
414 DeviceExtension
->State
= dsStarted
;
416 ExInterlockedInsertTailList(
417 &DriverExtension
->BusListHead
,
418 &DeviceExtension
->ListEntry
,
419 &DriverExtension
->BusListLock
);
421 Irp
->IoStatus
.Information
= 0;
423 return STATUS_SUCCESS
;
429 IN PDEVICE_OBJECT DeviceObject
,
431 PIO_STACK_LOCATION IrpSp
)
433 PFDO_DEVICE_EXTENSION DeviceExtension
;
438 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
440 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
) {
441 /* FIXME: Set device power state for the device */
442 Status
= STATUS_UNSUCCESSFUL
;
444 Status
= STATUS_UNSUCCESSFUL
;
451 /*** PUBLIC ******************************************************************/
455 PDEVICE_OBJECT DeviceObject
,
458 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
460 * DeviceObject = Pointer to functional device object of the PCI driver
461 * Irp = Pointer to IRP that should be handled
466 PFDO_DEVICE_EXTENSION DeviceExtension
;
467 PIO_STACK_LOCATION IrpSp
;
472 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
474 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
475 switch (IrpSp
->MinorFunction
) {
477 case IRP_MN_CANCEL_REMOVE_DEVICE
:
478 Status
= STATUS_NOT_IMPLEMENTED
;
481 case IRP_MN_CANCEL_STOP_DEVICE
:
482 Status
= STATUS_NOT_IMPLEMENTED
;
485 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
486 Status
= STATUS_NOT_IMPLEMENTED
;
489 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
490 Status
= STATUS_NOT_IMPLEMENTED
;
493 case IRP_MN_QUERY_DEVICE_RELATIONS
:
494 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
497 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
498 Status
= STATUS_NOT_IMPLEMENTED
;
501 case IRP_MN_QUERY_REMOVE_DEVICE
:
502 Status
= STATUS_NOT_IMPLEMENTED
;
505 case IRP_MN_QUERY_STOP_DEVICE
:
506 Status
= STATUS_NOT_IMPLEMENTED
;
509 case IRP_MN_REMOVE_DEVICE
:
510 Status
= STATUS_NOT_IMPLEMENTED
;
513 case IRP_MN_START_DEVICE
:
514 DPRINT("IRP_MN_START_DEVICE received\n");
515 Status
= FdoStartDevice(DeviceObject
, Irp
);
517 case IRP_MN_STOP_DEVICE
:
518 /* Currently not supported */
519 Status
= STATUS_UNSUCCESSFUL
;
522 case IRP_MN_SURPRISE_REMOVAL
:
523 Status
= STATUS_NOT_IMPLEMENTED
;
527 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
530 * Do NOT complete the IRP as it will be processed by the lower
531 * device object, which will complete the IRP
533 IoSkipCurrentIrpStackLocation(Irp
);
534 Status
= IoCallDriver(DeviceExtension
->Ldo
, Irp
);
540 if (Status
!= STATUS_PENDING
) {
541 if (Status
!= STATUS_NOT_IMPLEMENTED
)
542 Irp
->IoStatus
.Status
= Status
;
543 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
546 DPRINT("Leaving. Status 0x%X\n", Status
);
554 PDEVICE_OBJECT DeviceObject
,
557 * FUNCTION: Handle power management IRPs for the PCI device object
559 * DeviceObject = Pointer to functional device object of the PCI driver
560 * Irp = Pointer to IRP that should be handled
565 PIO_STACK_LOCATION IrpSp
;
570 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
572 switch (IrpSp
->MinorFunction
) {
573 case IRP_MN_SET_POWER
:
574 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
578 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
579 Status
= STATUS_NOT_IMPLEMENTED
;
583 if (Status
!= STATUS_PENDING
) {
584 Irp
->IoStatus
.Status
= Status
;
585 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
588 DPRINT("Leaving. Status 0x%X\n", Status
);