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 *****************************************************************/
22 PFDO_DEVICE_EXTENSION DeviceExtension
,
23 PCI_SLOT_NUMBER SlotNumber
,
24 PPCI_COMMON_CONFIG PciConfig
)
26 PLIST_ENTRY CurrentEntry
;
27 PPCI_DEVICE CurrentDevice
;
31 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
32 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
33 CurrentDevice
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
35 /* If both vendor ID and device ID match, it is the same device */
36 if ((PciConfig
->VendorID
== CurrentDevice
->PciConfig
.VendorID
) &&
37 (PciConfig
->DeviceID
== CurrentDevice
->PciConfig
.DeviceID
) &&
38 (SlotNumber
.u
.AsULONG
== CurrentDevice
->SlotNumber
.u
.AsULONG
)) {
39 *Device
= CurrentDevice
;
41 return STATUS_SUCCESS
;
44 CurrentEntry
= CurrentEntry
->Flink
;
49 return STATUS_UNSUCCESSFUL
;
55 PDEVICE_OBJECT DeviceObject
)
57 PFDO_DEVICE_EXTENSION DeviceExtension
;
58 PCI_COMMON_CONFIG PciConfig
;
59 PLIST_ENTRY CurrentEntry
;
61 PCI_SLOT_NUMBER SlotNumber
;
69 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
71 /* Mark all devices to be removed. If we don't discover them again during
72 enumeration, assume that they have been surprise removed */
73 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
74 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
75 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
76 Device
->RemovePending
= TRUE
;
77 CurrentEntry
= CurrentEntry
->Flink
;
80 DeviceExtension
->DeviceListCount
= 0;
82 /* Enumerate devices on the PCI bus */
83 SlotNumber
.u
.AsULONG
= 0;
84 for (DeviceNumber
= 0; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
86 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
87 for (FunctionNumber
= 0; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
89 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
91 DPRINT("Bus %1lu Device %2lu Func %1lu\n",
92 DeviceExtension
->BusNumber
,
96 RtlZeroMemory(&PciConfig
,
97 sizeof(PCI_COMMON_CONFIG
));
99 Size
= HalGetBusData(PCIConfiguration
,
100 DeviceExtension
->BusNumber
,
101 SlotNumber
.u
.AsULONG
,
103 PCI_COMMON_HDR_LENGTH
);
104 DPRINT("Size %lu\n", Size
);
105 if (Size
< PCI_COMMON_HDR_LENGTH
)
107 if (FunctionNumber
== 0)
117 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
118 DeviceExtension
->BusNumber
,
124 Status
= FdoLocateChildDevice(&Device
, DeviceExtension
, SlotNumber
, &PciConfig
);
125 if (!NT_SUCCESS(Status
))
127 Device
= (PPCI_DEVICE
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(PCI_DEVICE
),TAG_PCI
);
130 /* FIXME: Cleanup resources for already discovered devices */
131 return STATUS_INSUFFICIENT_RESOURCES
;
134 RtlZeroMemory(Device
,
137 Device
->BusNumber
= DeviceExtension
->BusNumber
;
139 RtlCopyMemory(&Device
->SlotNumber
,
141 sizeof(PCI_SLOT_NUMBER
));
143 RtlCopyMemory(&Device
->PciConfig
,
145 sizeof(PCI_COMMON_CONFIG
));
147 ExInterlockedInsertTailList(
148 &DeviceExtension
->DeviceListHead
,
150 &DeviceExtension
->DeviceListLock
);
153 /* Don't remove this device */
154 Device
->RemovePending
= FALSE
;
156 DeviceExtension
->DeviceListCount
++;
158 /* Skip to next device if the current one is not a multifunction device */
159 if ((FunctionNumber
== 0) &&
160 ((PciConfig
.HeaderType
& 0x80) == 0))
169 return STATUS_SUCCESS
;
174 FdoQueryBusRelations(
175 IN PDEVICE_OBJECT DeviceObject
,
177 PIO_STACK_LOCATION IrpSp
)
179 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
180 PFDO_DEVICE_EXTENSION DeviceExtension
;
181 PDEVICE_RELATIONS Relations
;
182 PLIST_ENTRY CurrentEntry
;
185 BOOLEAN ErrorOccurred
;
186 NTSTATUS ErrorStatus
;
192 ErrorStatus
= STATUS_INSUFFICIENT_RESOURCES
;
194 Status
= STATUS_SUCCESS
;
196 ErrorOccurred
= FALSE
;
198 FdoEnumerateDevices(DeviceObject
);
200 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
202 if (Irp
->IoStatus
.Information
) {
203 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS
204 structure so we must merge this structure with our own */
207 Size
= sizeof(DEVICE_RELATIONS
) + sizeof(Relations
->Objects
) *
208 (DeviceExtension
->DeviceListCount
- 1);
209 Relations
= (PDEVICE_RELATIONS
)ExAllocatePoolWithTag(PagedPool
, Size
, TAG_PCI
);
211 return STATUS_INSUFFICIENT_RESOURCES
;
213 Relations
->Count
= DeviceExtension
->DeviceListCount
;
216 CurrentEntry
= DeviceExtension
->DeviceListHead
.Flink
;
217 while (CurrentEntry
!= &DeviceExtension
->DeviceListHead
) {
218 Device
= CONTAINING_RECORD(CurrentEntry
, PCI_DEVICE
, ListEntry
);
220 PdoDeviceExtension
= NULL
;
223 /* Create a physical device object for the
224 device as it does not already have one */
225 Status
= IoCreateDevice(
226 DeviceObject
->DriverObject
,
227 sizeof(PDO_DEVICE_EXTENSION
),
229 FILE_DEVICE_CONTROLLER
,
230 FILE_AUTOGENERATED_DEVICE_NAME
,
233 if (!NT_SUCCESS(Status
)) {
234 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status
);
235 ErrorStatus
= Status
;
236 ErrorOccurred
= TRUE
;
240 Device
->Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
242 Device
->Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
244 //Device->Pdo->Flags |= DO_POWER_PAGABLE;
246 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Device
->Pdo
->DeviceExtension
;
248 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
250 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
252 PdoDeviceExtension
->Common
.DeviceObject
= Device
->Pdo
;
254 PdoDeviceExtension
->Common
.DevicePowerState
= PowerDeviceD0
;
256 PdoDeviceExtension
->Fdo
= DeviceObject
;
258 PdoDeviceExtension
->PciDevice
= Device
;
260 /* Add Device ID string */
261 Status
= PciCreateDeviceIDString(&PdoDeviceExtension
->DeviceID
, Device
);
262 if (!NT_SUCCESS(Status
))
264 ErrorStatus
= Status
;
265 ErrorOccurred
= TRUE
;
269 DPRINT("DeviceID: %S\n", PdoDeviceExtension
->DeviceID
.Buffer
);
271 /* Add Instance ID string */
272 Status
= PciCreateInstanceIDString(&PdoDeviceExtension
->InstanceID
, Device
);
273 if (!NT_SUCCESS(Status
))
275 ErrorStatus
= Status
;
276 ErrorOccurred
= TRUE
;
280 /* Add Hardware IDs string */
281 Status
= PciCreateHardwareIDsString(&PdoDeviceExtension
->HardwareIDs
, Device
);
282 if (!NT_SUCCESS(Status
))
284 ErrorStatus
= Status
;
285 ErrorOccurred
= TRUE
;
289 /* Add Compatible IDs string */
290 Status
= PciCreateCompatibleIDsString(&PdoDeviceExtension
->CompatibleIDs
, Device
);
291 if (!NT_SUCCESS(Status
))
293 ErrorStatus
= Status
;
294 ErrorOccurred
= TRUE
;
298 /* Add device description string */
299 Status
= PciCreateDeviceDescriptionString(&PdoDeviceExtension
->DeviceDescription
, Device
);
300 if (!NT_SUCCESS(Status
))
302 ErrorStatus
= Status
;
303 ErrorOccurred
= TRUE
;
307 /* Add device location string */
308 Status
= PciCreateDeviceLocationString(&PdoDeviceExtension
->DeviceLocation
, Device
);
309 if (!NT_SUCCESS(Status
))
311 ErrorStatus
= Status
;
312 ErrorOccurred
= TRUE
;
317 if (!Device
->RemovePending
) {
318 /* Reference the physical device object. The PnP manager
319 will dereference it again when it is no longer needed */
320 ObReferenceObject(Device
->Pdo
);
322 Relations
->Objects
[i
] = Device
->Pdo
;
327 CurrentEntry
= CurrentEntry
->Flink
;
331 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */
332 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */
333 if (PdoDeviceExtension
) {
334 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceID
);
335 RtlFreeUnicodeString(&PdoDeviceExtension
->InstanceID
);
336 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIDs
);
337 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIDs
);
338 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
339 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceLocation
);
342 ExFreePool(Relations
);
346 Irp
->IoStatus
.Information
= (ULONG_PTR
)Relations
;
356 IN PDEVICE_OBJECT DeviceObject
,
359 static BOOLEAN FoundBuggyAllocatedResourcesList
= FALSE
;
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 /* HACK due to a bug in ACPI driver, which doesn't report the bus number */
372 if (!FoundBuggyAllocatedResourcesList
|| !AllocatedResources
|| AllocatedResources
->Count
== 0)
374 FoundBuggyAllocatedResourcesList
= TRUE
;
375 DPRINT1("No bus number resource found (bug in acpi.sys?), assuming bus number #0\n");
376 DeviceExtension
->BusNumber
= 0;
380 if (!AllocatedResources
)
382 DPRINT("No allocated resources sent to driver\n");
383 return STATUS_INSUFFICIENT_RESOURCES
;
385 if (AllocatedResources
->Count
< 1)
387 DPRINT("Not enough allocated resources sent to driver\n");
388 return STATUS_INSUFFICIENT_RESOURCES
;
390 if (AllocatedResources
->List
[0].PartialResourceList
.Version
!= 1
391 || AllocatedResources
->List
[0].PartialResourceList
.Revision
!= 1)
392 return STATUS_REVISION_MISMATCH
;
394 ASSERT(DeviceExtension
->State
== dsStopped
);
396 for (i
= 0; i
< AllocatedResources
->List
[0].PartialResourceList
.Count
; i
++)
398 ResourceDescriptor
= &AllocatedResources
->List
[0].PartialResourceList
.PartialDescriptors
[i
];
399 switch (ResourceDescriptor
->Type
)
401 case CmResourceTypeBusNumber
:
403 if (FoundBusNumber
|| ResourceDescriptor
->u
.BusNumber
.Length
!= 1)
404 return STATUS_INVALID_PARAMETER
;
405 DeviceExtension
->BusNumber
= ResourceDescriptor
->u
.BusNumber
.Start
;
406 DPRINT("Found bus number resource: %lu\n", DeviceExtension
->BusNumber
);
407 FoundBusNumber
= TRUE
;
411 DPRINT1("Unknown resource descriptor type 0x%x\n", ResourceDescriptor
->Type
);
416 DPRINT("Some required resources were not found in allocated resources list\n");
417 return STATUS_INSUFFICIENT_RESOURCES
;
421 InitializeListHead(&DeviceExtension
->DeviceListHead
);
422 KeInitializeSpinLock(&DeviceExtension
->DeviceListLock
);
423 DeviceExtension
->DeviceListCount
= 0;
424 DeviceExtension
->State
= dsStarted
;
426 ExInterlockedInsertTailList(
427 &DriverExtension
->BusListHead
,
428 &DeviceExtension
->ListEntry
,
429 &DriverExtension
->BusListLock
);
431 Irp
->IoStatus
.Information
= 0;
433 return STATUS_SUCCESS
;
439 IN PDEVICE_OBJECT DeviceObject
,
441 PIO_STACK_LOCATION IrpSp
)
443 PFDO_DEVICE_EXTENSION DeviceExtension
;
448 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
450 if (IrpSp
->Parameters
.Power
.Type
== DevicePowerState
) {
451 /* FIXME: Set device power state for the device */
452 Status
= STATUS_UNSUCCESSFUL
;
454 Status
= STATUS_UNSUCCESSFUL
;
461 /*** PUBLIC ******************************************************************/
465 PDEVICE_OBJECT DeviceObject
,
468 * FUNCTION: Handle Plug and Play IRPs for the PCI device object
470 * DeviceObject = Pointer to functional device object of the PCI driver
471 * Irp = Pointer to IRP that should be handled
476 PFDO_DEVICE_EXTENSION DeviceExtension
;
477 PIO_STACK_LOCATION IrpSp
;
482 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
484 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
485 switch (IrpSp
->MinorFunction
) {
487 case IRP_MN_CANCEL_REMOVE_DEVICE
:
488 Status
= STATUS_NOT_IMPLEMENTED
;
491 case IRP_MN_CANCEL_STOP_DEVICE
:
492 Status
= STATUS_NOT_IMPLEMENTED
;
495 case IRP_MN_DEVICE_USAGE_NOTIFICATION
:
496 Status
= STATUS_NOT_IMPLEMENTED
;
499 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
500 Status
= STATUS_NOT_IMPLEMENTED
;
503 case IRP_MN_QUERY_DEVICE_RELATIONS
:
504 Status
= FdoQueryBusRelations(DeviceObject
, Irp
, IrpSp
);
507 case IRP_MN_QUERY_PNP_DEVICE_STATE
:
508 Status
= STATUS_NOT_IMPLEMENTED
;
511 case IRP_MN_QUERY_REMOVE_DEVICE
:
512 Status
= STATUS_NOT_IMPLEMENTED
;
515 case IRP_MN_QUERY_STOP_DEVICE
:
516 Status
= STATUS_NOT_IMPLEMENTED
;
519 case IRP_MN_REMOVE_DEVICE
:
520 Status
= STATUS_NOT_IMPLEMENTED
;
523 case IRP_MN_START_DEVICE
:
524 DPRINT("IRP_MN_START_DEVICE received\n");
525 Status
= FdoStartDevice(DeviceObject
, Irp
);
527 case IRP_MN_STOP_DEVICE
:
528 /* Currently not supported */
529 Status
= STATUS_UNSUCCESSFUL
;
532 case IRP_MN_SURPRISE_REMOVAL
:
533 Status
= STATUS_NOT_IMPLEMENTED
;
537 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp
->MinorFunction
);
540 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS
:
542 * Do NOT complete the IRP as it will be processed by the lower
543 * device object, which will complete the IRP
545 IoSkipCurrentIrpStackLocation(Irp
);
546 Status
= IoCallDriver(DeviceExtension
->Ldo
, Irp
);
552 if (Status
!= STATUS_PENDING
) {
553 if (Status
!= STATUS_NOT_IMPLEMENTED
)
554 Irp
->IoStatus
.Status
= Status
;
555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
558 DPRINT("Leaving. Status 0x%X\n", Status
);
566 PDEVICE_OBJECT DeviceObject
,
569 * FUNCTION: Handle power management IRPs for the PCI device object
571 * DeviceObject = Pointer to functional device object of the PCI driver
572 * Irp = Pointer to IRP that should be handled
577 PIO_STACK_LOCATION IrpSp
;
582 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
584 switch (IrpSp
->MinorFunction
) {
585 case IRP_MN_SET_POWER
:
586 Status
= FdoSetPower(DeviceObject
, Irp
, IrpSp
);
590 DPRINT("Unknown IOCTL 0x%X\n", IrpSp
->MinorFunction
);
591 Status
= STATUS_NOT_IMPLEMENTED
;
595 if (Status
!= STATUS_PENDING
) {
596 Irp
->IoStatus
.Status
= Status
;
597 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
600 DPRINT("Leaving. Status 0x%X\n", Status
);