2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/pdo.c
5 * PURPOSE: PDO Device Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 LONG PciPdoSequenceNumber
;
19 C_ASSERT(FIELD_OFFSET(PCI_FDO_EXTENSION
, DeviceState
) == FIELD_OFFSET(PCI_PDO_EXTENSION
, DeviceState
));
20 C_ASSERT(FIELD_OFFSET(PCI_FDO_EXTENSION
, TentativeNextState
) == FIELD_OFFSET(PCI_PDO_EXTENSION
, TentativeNextState
));
21 C_ASSERT(FIELD_OFFSET(PCI_FDO_EXTENSION
, List
) == FIELD_OFFSET(PCI_PDO_EXTENSION
, Next
));
23 PCI_MN_DISPATCH_TABLE PciPdoDispatchPowerTable
[] =
25 {IRP_DISPATCH
, (PCI_DISPATCH_FUNCTION
)PciPdoWaitWake
},
26 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
27 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoSetPowerState
},
28 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryPower
},
29 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
}
32 PCI_MN_DISPATCH_TABLE PciPdoDispatchPnpTable
[] =
34 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpStartDevice
},
35 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryRemoveDevice
},
36 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpRemoveDevice
},
37 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpCancelRemoveDevice
},
38 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpStopDevice
},
39 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryStopDevice
},
40 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpCancelStopDevice
},
41 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryDeviceRelations
},
42 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryInterface
},
43 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryCapabilities
},
44 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryResources
},
45 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryResourceRequirements
},
46 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryDeviceText
},
47 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
48 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
49 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpReadConfig
},
50 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpWriteConfig
},
51 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
52 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
},
53 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryId
},
54 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryDeviceState
},
55 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryBusInformation
},
56 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpDeviceUsageNotification
},
57 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpSurpriseRemoval
},
58 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciPdoIrpQueryLegacyBusInformation
},
59 {IRP_COMPLETE
, (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
}
62 PCI_MJ_DISPATCH_TABLE PciPdoDispatchTable
=
64 IRP_MN_QUERY_LEGACY_BUS_INFORMATION
,
65 PciPdoDispatchPnpTable
,
67 PciPdoDispatchPowerTable
,
69 (PCI_DISPATCH_FUNCTION
)PciIrpNotSupported
,
71 (PCI_DISPATCH_FUNCTION
)PciIrpInvalidDeviceRequest
74 /* FUNCTIONS ******************************************************************/
78 PciPdoWaitWake(IN PIRP Irp
,
79 IN PIO_STACK_LOCATION IoStackLocation
,
80 IN PPCI_PDO_EXTENSION DeviceExtension
)
82 UNIMPLEMENTED_DBGBREAK();
83 return STATUS_NOT_SUPPORTED
;
88 PciPdoSetPowerState(IN PIRP Irp
,
89 IN PIO_STACK_LOCATION IoStackLocation
,
90 IN PPCI_PDO_EXTENSION DeviceExtension
)
93 return STATUS_NOT_SUPPORTED
;
98 PciPdoIrpQueryPower(IN PIRP Irp
,
99 IN PIO_STACK_LOCATION IoStackLocation
,
100 IN PPCI_PDO_EXTENSION DeviceExtension
)
102 UNIMPLEMENTED_DBGBREAK();
103 return STATUS_NOT_SUPPORTED
;
108 PciPdoIrpStartDevice(IN PIRP Irp
,
109 IN PIO_STACK_LOCATION IoStackLocation
,
110 IN PPCI_PDO_EXTENSION DeviceExtension
)
113 BOOLEAN Changed
, DoReset
;
114 POWER_STATE PowerState
;
119 /* Begin entering the start phase */
120 Status
= PciBeginStateTransition((PVOID
)DeviceExtension
, PciStarted
);
121 if (!NT_SUCCESS(Status
)) return Status
;
123 /* Check if this is a VGA device */
124 if (((DeviceExtension
->BaseClass
== PCI_CLASS_PRE_20
) &&
125 (DeviceExtension
->SubClass
== PCI_SUBCLASS_PRE_20_VGA
)) ||
126 ((DeviceExtension
->BaseClass
== PCI_CLASS_DISPLAY_CTLR
) &&
127 (DeviceExtension
->SubClass
== PCI_SUBCLASS_VID_VGA_CTLR
)))
129 /* Always force it on */
130 DeviceExtension
->CommandEnables
|= (PCI_ENABLE_IO_SPACE
|
131 PCI_ENABLE_MEMORY_SPACE
);
134 /* Check if native IDE is enabled and it owns the I/O ports */
135 if (DeviceExtension
->IoSpaceUnderNativeIdeControl
)
137 /* Then don't allow I/O access */
138 DeviceExtension
->CommandEnables
&= ~PCI_ENABLE_IO_SPACE
;
141 /* Always enable bus mastering */
142 DeviceExtension
->CommandEnables
|= PCI_ENABLE_BUS_MASTER
;
144 /* Check if the OS assigned resources differ from the PCI configuration */
145 Changed
= PciComputeNewCurrentSettings(DeviceExtension
,
146 IoStackLocation
->Parameters
.
147 StartDevice
.AllocatedResources
);
150 /* Remember this for later */
151 DeviceExtension
->MovedDevice
= TRUE
;
156 DPRINT1("PCI - START not changing resource settings.\n");
159 /* Check if the device was sleeping */
160 if (DeviceExtension
->PowerState
.CurrentDeviceState
!= PowerDeviceD0
)
163 Status
= PciSetPowerManagedDevicePowerState(DeviceExtension
,
166 if (!NT_SUCCESS(Status
))
168 /* Powerup fail, fail the request */
169 PciCancelStateTransition((PVOID
)DeviceExtension
, PciStarted
);
170 return STATUS_DEVICE_POWER_FAILURE
;
173 /* Tell the power manager that the device is powered up */
174 PowerState
.DeviceState
= PowerDeviceD0
;
175 PoSetPowerState(DeviceExtension
->PhysicalDeviceObject
,
179 /* Update internal state */
180 DeviceExtension
->PowerState
.CurrentDeviceState
= PowerDeviceD0
;
182 /* This device's resources and decodes will need to be reset */
186 /* Update resource information now that the device is powered up and active */
187 Status
= PciSetResources(DeviceExtension
, DoReset
, TRUE
);
188 if (!NT_SUCCESS(Status
))
190 /* That failed, so cancel the transition */
191 PciCancelStateTransition((PVOID
)DeviceExtension
, PciStarted
);
195 /* Fully commit, as the device is now started up and ready to go */
196 PciCommitStateTransition((PVOID
)DeviceExtension
, PciStarted
);
199 /* Return the result of the start request */
205 PciPdoIrpQueryRemoveDevice(IN PIRP Irp
,
206 IN PIO_STACK_LOCATION IoStackLocation
,
207 IN PPCI_PDO_EXTENSION DeviceExtension
)
210 return STATUS_NOT_SUPPORTED
;
215 PciPdoIrpRemoveDevice(IN PIRP Irp
,
216 IN PIO_STACK_LOCATION IoStackLocation
,
217 IN PPCI_PDO_EXTENSION DeviceExtension
)
219 UNIMPLEMENTED_DBGBREAK();
220 return STATUS_NOT_SUPPORTED
;
225 PciPdoIrpCancelRemoveDevice(IN PIRP Irp
,
226 IN PIO_STACK_LOCATION IoStackLocation
,
227 IN PPCI_PDO_EXTENSION DeviceExtension
)
229 UNIMPLEMENTED_DBGBREAK();
230 return STATUS_NOT_SUPPORTED
;
235 PciPdoIrpStopDevice(IN PIRP Irp
,
236 IN PIO_STACK_LOCATION IoStackLocation
,
237 IN PPCI_PDO_EXTENSION DeviceExtension
)
239 UNIMPLEMENTED_DBGBREAK();
240 return STATUS_NOT_SUPPORTED
;
245 PciPdoIrpQueryStopDevice(IN PIRP Irp
,
246 IN PIO_STACK_LOCATION IoStackLocation
,
247 IN PPCI_PDO_EXTENSION DeviceExtension
)
249 UNIMPLEMENTED_DBGBREAK();
250 return STATUS_NOT_SUPPORTED
;
255 PciPdoIrpCancelStopDevice(IN PIRP Irp
,
256 IN PIO_STACK_LOCATION IoStackLocation
,
257 IN PPCI_PDO_EXTENSION DeviceExtension
)
259 UNIMPLEMENTED_DBGBREAK();
260 return STATUS_NOT_SUPPORTED
;
265 PciPdoIrpQueryInterface(IN PIRP Irp
,
266 IN PIO_STACK_LOCATION IoStackLocation
,
267 IN PPCI_PDO_EXTENSION DeviceExtension
)
269 UNIMPLEMENTED_DBGBREAK();
270 return STATUS_NOT_SUPPORTED
;
275 PciPdoIrpQueryDeviceRelations(IN PIRP Irp
,
276 IN PIO_STACK_LOCATION IoStackLocation
,
277 IN PPCI_PDO_EXTENSION DeviceExtension
)
282 /* Are ejection relations being queried? */
283 if (IoStackLocation
->Parameters
.QueryDeviceRelations
.Type
== EjectionRelations
)
285 /* Call the worker function */
286 Status
= PciQueryEjectionRelations(DeviceExtension
,
287 (PDEVICE_RELATIONS
*)&Irp
->
288 IoStatus
.Information
);
290 else if (IoStackLocation
->Parameters
.QueryDeviceRelations
.Type
== TargetDeviceRelation
)
292 /* The only other relation supported is the target device relation */
293 Status
= PciQueryTargetDeviceRelations(DeviceExtension
,
294 (PDEVICE_RELATIONS
*)&Irp
->
295 IoStatus
.Information
);
299 /* All other relations are unsupported */
300 Status
= STATUS_NOT_SUPPORTED
;
303 /* Return either the result of the worker function, or unsupported status */
309 PciPdoIrpQueryCapabilities(IN PIRP Irp
,
310 IN PIO_STACK_LOCATION IoStackLocation
,
311 IN PPCI_PDO_EXTENSION DeviceExtension
)
315 /* Call the worker function */
316 return PciQueryCapabilities(DeviceExtension
,
318 Parameters
.DeviceCapabilities
.Capabilities
);
323 PciPdoIrpQueryResources(IN PIRP Irp
,
324 IN PIO_STACK_LOCATION IoStackLocation
,
325 IN PPCI_PDO_EXTENSION DeviceExtension
)
329 /* Call the worker function */
330 return PciQueryResources(DeviceExtension
,
331 (PCM_RESOURCE_LIST
*)&Irp
->IoStatus
.Information
);
336 PciPdoIrpQueryResourceRequirements(IN PIRP Irp
,
337 IN PIO_STACK_LOCATION IoStackLocation
,
338 IN PPCI_PDO_EXTENSION DeviceExtension
)
342 /* Call the worker function */
343 return PciQueryRequirements(DeviceExtension
,
344 (PIO_RESOURCE_REQUIREMENTS_LIST
*)&Irp
->
345 IoStatus
.Information
);
350 PciPdoIrpQueryDeviceText(IN PIRP Irp
,
351 IN PIO_STACK_LOCATION IoStackLocation
,
352 IN PPCI_PDO_EXTENSION DeviceExtension
)
356 /* Call the worker function */
357 return PciQueryDeviceText(DeviceExtension
,
359 Parameters
.QueryDeviceText
.DeviceTextType
,
361 Parameters
.QueryDeviceText
.LocaleId
,
362 (PWCHAR
*)&Irp
->IoStatus
.Information
);
367 PciPdoIrpQueryId(IN PIRP Irp
,
368 IN PIO_STACK_LOCATION IoStackLocation
,
369 IN PPCI_PDO_EXTENSION DeviceExtension
)
373 /* Call the worker function */
374 return PciQueryId(DeviceExtension
,
375 IoStackLocation
->Parameters
.QueryId
.IdType
,
376 (PWCHAR
*)&Irp
->IoStatus
.Information
);
381 PciPdoIrpQueryBusInformation(IN PIRP Irp
,
382 IN PIO_STACK_LOCATION IoStackLocation
,
383 IN PPCI_PDO_EXTENSION DeviceExtension
)
387 /* Call the worker function */
388 return PciQueryBusInformation(DeviceExtension
,
389 (PPNP_BUS_INFORMATION
*)&Irp
->
390 IoStatus
.Information
);
395 PciPdoIrpReadConfig(IN PIRP Irp
,
396 IN PIO_STACK_LOCATION IoStackLocation
,
397 IN PPCI_PDO_EXTENSION DeviceExtension
)
399 UNIMPLEMENTED_DBGBREAK();
400 return STATUS_NOT_SUPPORTED
;
405 PciPdoIrpWriteConfig(IN PIRP Irp
,
406 IN PIO_STACK_LOCATION IoStackLocation
,
407 IN PPCI_PDO_EXTENSION DeviceExtension
)
409 UNIMPLEMENTED_DBGBREAK();
410 return STATUS_NOT_SUPPORTED
;
415 PciPdoIrpQueryDeviceState(IN PIRP Irp
,
416 IN PIO_STACK_LOCATION IoStackLocation
,
417 IN PPCI_PDO_EXTENSION DeviceExtension
)
420 return STATUS_NOT_SUPPORTED
;
425 PciPdoIrpDeviceUsageNotification(IN PIRP Irp
,
426 IN PIO_STACK_LOCATION IoStackLocation
,
427 IN PPCI_PDO_EXTENSION DeviceExtension
)
429 UNIMPLEMENTED_DBGBREAK();
430 return STATUS_NOT_SUPPORTED
;
435 PciPdoIrpSurpriseRemoval(IN PIRP Irp
,
436 IN PIO_STACK_LOCATION IoStackLocation
,
437 IN PPCI_PDO_EXTENSION DeviceExtension
)
439 UNIMPLEMENTED_DBGBREAK();
440 return STATUS_NOT_SUPPORTED
;
445 PciPdoIrpQueryLegacyBusInformation(IN PIRP Irp
,
446 IN PIO_STACK_LOCATION IoStackLocation
,
447 IN PPCI_PDO_EXTENSION DeviceExtension
)
449 UNIMPLEMENTED_DBGBREAK();
450 return STATUS_NOT_SUPPORTED
;
455 PciPdoCreate(IN PPCI_FDO_EXTENSION DeviceExtension
,
456 IN PCI_SLOT_NUMBER Slot
,
457 OUT PDEVICE_OBJECT
*PdoDeviceObject
)
459 WCHAR DeviceName
[32];
460 UNICODE_STRING DeviceString
;
462 PDEVICE_OBJECT DeviceObject
;
463 PPCI_PDO_EXTENSION PdoExtension
;
464 ULONG SequenceNumber
;
467 /* Pick an atomically unique sequence number for this device */
468 SequenceNumber
= InterlockedIncrement(&PciPdoSequenceNumber
);
470 /* Create the standard PCI device name for a PDO */
471 swprintf(DeviceName
, L
"\\Device\\NTPNP_PCI%04d", SequenceNumber
);
472 RtlInitUnicodeString(&DeviceString
, DeviceName
);
474 /* Create the actual device now */
475 Status
= IoCreateDevice(DeviceExtension
->FunctionalDeviceObject
->DriverObject
,
476 sizeof(PCI_PDO_EXTENSION
),
478 FILE_DEVICE_BUS_EXTENDER
,
482 ASSERT(NT_SUCCESS(Status
));
484 /* Get the extension for it */
485 PdoExtension
= (PPCI_PDO_EXTENSION
)DeviceObject
->DeviceExtension
;
486 DPRINT1("PCI: New PDO (b=0x%x, d=0x%x, f=0x%x) @ %p, ext @ %p\n",
487 DeviceExtension
->BaseBus
,
488 Slot
.u
.bits
.DeviceNumber
,
489 Slot
.u
.bits
.FunctionNumber
,
491 DeviceObject
->DeviceExtension
);
493 /* Configure the extension */
494 PdoExtension
->ExtensionType
= PciPdoExtensionType
;
495 PdoExtension
->IrpDispatchTable
= &PciPdoDispatchTable
;
496 PdoExtension
->PhysicalDeviceObject
= DeviceObject
;
497 PdoExtension
->Slot
= Slot
;
498 PdoExtension
->PowerState
.CurrentSystemState
= PowerDeviceD0
;
499 PdoExtension
->PowerState
.CurrentDeviceState
= PowerDeviceD0
;
500 PdoExtension
->ParentFdoExtension
= DeviceExtension
;
502 /* Initialize the lock for arbiters and other interfaces */
503 KeInitializeEvent(&PdoExtension
->SecondaryExtLock
, SynchronizationEvent
, TRUE
);
505 /* Initialize the state machine */
506 PciInitializeState((PPCI_FDO_EXTENSION
)PdoExtension
);
508 /* Add the PDO to the parent's list */
509 PdoExtension
->Next
= NULL
;
510 PciInsertEntryAtTail((PSINGLE_LIST_ENTRY
)&DeviceExtension
->ChildPdoList
,
511 (PPCI_FDO_EXTENSION
)PdoExtension
,
512 &DeviceExtension
->ChildListLock
);
514 /* And finally return it to the caller */
515 *PdoDeviceObject
= DeviceObject
;
516 return STATUS_SUCCESS
;