Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1393 lines
39 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. fdo.c
  5. Abstract:
  6. This module handles IRPs for PCI FDO's.
  7. Author:
  8. Adrian J. Oney (adriao) & Andrew Thornton (andrewth) 10-20-1998
  9. Revision History:
  10. --*/
  11. #include "pcip.h"
  12. NTSTATUS
  13. PciFdoIrpStartDevice(
  14. IN PIRP Irp,
  15. IN PIO_STACK_LOCATION IrpSp,
  16. IN PPCI_COMMON_EXTENSION DeviceExtension
  17. );
  18. NTSTATUS
  19. PciFdoIrpQueryRemoveDevice(
  20. IN PIRP Irp,
  21. IN PIO_STACK_LOCATION IrpSp,
  22. IN PPCI_COMMON_EXTENSION DeviceExtension
  23. );
  24. NTSTATUS
  25. PciFdoIrpRemoveDevice(
  26. IN PIRP Irp,
  27. IN PIO_STACK_LOCATION IrpSp,
  28. IN PPCI_COMMON_EXTENSION DeviceExtension
  29. );
  30. NTSTATUS
  31. PciFdoIrpCancelRemoveDevice(
  32. IN PIRP Irp,
  33. IN PIO_STACK_LOCATION IrpSp,
  34. IN PPCI_COMMON_EXTENSION DeviceExtension
  35. );
  36. NTSTATUS
  37. PciFdoIrpStopDevice(
  38. IN PIRP Irp,
  39. IN PIO_STACK_LOCATION IrpSp,
  40. IN PPCI_COMMON_EXTENSION DeviceExtension
  41. );
  42. NTSTATUS
  43. PciFdoIrpQueryStopDevice(
  44. IN PIRP Irp,
  45. IN PIO_STACK_LOCATION IrpSp,
  46. IN PPCI_COMMON_EXTENSION DeviceExtension
  47. );
  48. NTSTATUS
  49. PciFdoIrpCancelStopDevice(
  50. IN PIRP Irp,
  51. IN PIO_STACK_LOCATION IrpSp,
  52. IN PPCI_COMMON_EXTENSION DeviceExtension
  53. );
  54. NTSTATUS
  55. PciFdoIrpQueryCapabilities(
  56. IN PIRP Irp,
  57. IN PIO_STACK_LOCATION IrpSp,
  58. IN PPCI_COMMON_EXTENSION DeviceExtension
  59. );
  60. NTSTATUS
  61. PciFdoIrpQueryInterface(
  62. IN PIRP Irp,
  63. IN PIO_STACK_LOCATION IrpSp,
  64. IN PPCI_COMMON_EXTENSION DeviceExtension
  65. );
  66. NTSTATUS
  67. PciFdoIrpQueryLegacyBusInformation(
  68. IN PIRP Irp,
  69. IN PIO_STACK_LOCATION IrpSp,
  70. IN PPCI_COMMON_EXTENSION DeviceExtension
  71. );
  72. NTSTATUS
  73. PciFdoIrpDeviceUsageNotification(
  74. IN PIRP Irp,
  75. IN PIO_STACK_LOCATION IrpSp,
  76. IN PPCI_COMMON_EXTENSION DeviceExtension
  77. );
  78. NTSTATUS
  79. PciFdoIrpSurpriseRemoval(
  80. IN PIRP Irp,
  81. IN PIO_STACK_LOCATION IrpSp,
  82. IN PPCI_COMMON_EXTENSION DeviceExtension
  83. );
  84. VOID
  85. PciGetHotPlugParameters(
  86. IN PPCI_FDO_EXTENSION Fdo
  87. );
  88. #ifdef ALLOC_PRAGMA
  89. #pragma alloc_text(PAGE, PciAddDevice)
  90. #pragma alloc_text(PAGE, PciInitializeFdoExtensionCommonFields)
  91. #pragma alloc_text(PAGE, PciFdoIrpStartDevice)
  92. #pragma alloc_text(PAGE, PciFdoIrpQueryRemoveDevice)
  93. #pragma alloc_text(PAGE, PciFdoIrpRemoveDevice)
  94. #pragma alloc_text(PAGE, PciFdoIrpCancelRemoveDevice)
  95. #pragma alloc_text(PAGE, PciFdoIrpQueryStopDevice)
  96. #pragma alloc_text(PAGE, PciFdoIrpStopDevice)
  97. #pragma alloc_text(PAGE, PciFdoIrpCancelStopDevice)
  98. #pragma alloc_text(PAGE, PciFdoIrpQueryDeviceRelations)
  99. #pragma alloc_text(PAGE, PciFdoIrpQueryInterface)
  100. #pragma alloc_text(PAGE, PciFdoIrpQueryCapabilities)
  101. #pragma alloc_text(PAGE, PciFdoIrpDeviceUsageNotification)
  102. #pragma alloc_text(PAGE, PciFdoIrpSurpriseRemoval)
  103. #pragma alloc_text(PAGE, PciFdoIrpQueryLegacyBusInformation)
  104. #pragma alloc_text(PAGE, PciGetHotPlugParameters)
  105. #endif
  106. //
  107. // The following is used to determine if we failed to get a
  108. // reasonable configuration from the PDO (in AddDevice) more
  109. // than once. If only once, we try to guess, if twice, we're
  110. // in big trouble.
  111. //
  112. static BOOLEAN HaveGuessedConfigOnceAlready = FALSE;
  113. /*++
  114. The majority of functions in this file are called based on their presence
  115. in Pnp and Po dispatch tables. In the interests of brevity the arguments
  116. to all those functions will be described below:
  117. NTSTATUS
  118. PciXxxPdo(
  119. IN PIRP Irp,
  120. IN PIO_STACK_LOCATION IrpStack,
  121. IN PPCI_EXTENSION DeviceExtension
  122. )
  123. Routine Description:
  124. This function handles the Xxx requests for a given PCI FDO or PDO.
  125. Arguments:
  126. Irp - Points to the IRP associated with this request.
  127. IrpStack - Points to the current stack location for this request.
  128. DeviceExtension - Points to the device's extension.
  129. Return Value:
  130. Status code that indicates whether or not the function was successful.
  131. STATUS_NOT_SUPPORTED indicates that the IRP should be completed without
  132. changing the Irp->IoStatus.Status field otherwise it is updated with this
  133. status.
  134. --*/
  135. #define PCI_MAX_MINOR_POWER_IRP 0x3
  136. #define PCI_MAX_MINOR_PNP_IRP 0x18
  137. PCI_MN_DISPATCH_TABLE PciFdoDispatchPowerTable[] = {
  138. { IRP_DISPATCH, PciFdoWaitWake }, // 0x00 - IRP_MN_WAIT_WAKE
  139. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x01 - IRP_MN_POWER_SEQUENCE
  140. { IRP_DOWNWARD, PciFdoSetPowerState }, // 0x02 - IRP_MN_SET_POWER
  141. { IRP_DOWNWARD, PciFdoIrpQueryPower }, // 0x03 - IRP_MN_QUERY_POWER
  142. { IRP_DOWNWARD, PciIrpNotSupported } // - UNHANDLED Power IRP
  143. };
  144. PCI_MN_DISPATCH_TABLE PciFdoDispatchPnpTable[] = {
  145. { IRP_UPWARD, PciFdoIrpStartDevice }, // 0x00 - IRP_MN_START_DEVICE
  146. { IRP_DOWNWARD, PciFdoIrpQueryRemoveDevice }, // 0x01 - IRP_MN_QUERY_REMOVE_DEVICE
  147. { IRP_DISPATCH, PciFdoIrpRemoveDevice }, // 0x02 - IRP_MN_REMOVE_DEVICE
  148. { IRP_DOWNWARD, PciFdoIrpCancelRemoveDevice }, // 0x03 - IRP_MN_CANCEL_REMOVE_DEVICE
  149. { IRP_DOWNWARD, PciFdoIrpStopDevice }, // 0x04 - IRP_MN_STOP_DEVICE
  150. { IRP_DOWNWARD, PciFdoIrpQueryStopDevice }, // 0x05 - IRP_MN_QUERY_STOP_DEVICE
  151. { IRP_DOWNWARD, PciFdoIrpCancelStopDevice }, // 0x06 - IRP_MN_CANCEL_STOP_DEVICE
  152. { IRP_DOWNWARD, PciFdoIrpQueryDeviceRelations }, // 0x07 - IRP_MN_QUERY_DEVICE_RELATIONS
  153. { IRP_DISPATCH, PciFdoIrpQueryInterface }, // 0x08 - IRP_MN_QUERY_INTERFACE
  154. { IRP_UPWARD, PciFdoIrpQueryCapabilities }, // 0x09 - IRP_MN_QUERY_CAPABILITIES
  155. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x0A - IRP_MN_QUERY_RESOURCES
  156. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x0B - IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  157. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x0C - IRP_MN_QUERY_DEVICE_TEXT
  158. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x0D - IRP_MN_FILTER_RESOURCE_REQUIREMENTS
  159. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x0E - NOT USED
  160. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x0F - IRP_MN_READ_CONFIG
  161. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x10 - IRP_MN_WRITE_CONFIG
  162. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x11 - IRP_MN_EJECT
  163. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x12 - IRP_MN_SET_LOCK
  164. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x13 - IRP_MN_QUERY_ID
  165. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x14 - IRP_MN_QUERY_PNP_DEVICE_STATE
  166. { IRP_DOWNWARD, PciIrpNotSupported }, // 0x15 - IRP_MN_QUERY_BUS_INFORMATION
  167. { IRP_UPWARD, PciFdoIrpDeviceUsageNotification }, // 0x16 - IRP_MN_DEVICE_USAGE_NOTIFICATION
  168. { IRP_DOWNWARD, PciFdoIrpSurpriseRemoval }, // 0x17 - IRP_MN_SURPRISE_REMOVAL
  169. { IRP_DOWNWARD, PciFdoIrpQueryLegacyBusInformation }, // 0x18 - IRP_MN_QUERY_LEGACY_BUS_INFORMATION
  170. { IRP_DOWNWARD, PciIrpNotSupported } // - UNHANDLED PNP IRP
  171. };
  172. //
  173. // This is the major function dispatch table for Fdo's
  174. //
  175. PCI_MJ_DISPATCH_TABLE PciFdoDispatchTable = {
  176. PCI_MAX_MINOR_PNP_IRP, PciFdoDispatchPnpTable, // Pnp irps
  177. PCI_MAX_MINOR_POWER_IRP, PciFdoDispatchPowerTable, // Power irps
  178. IRP_DOWNWARD, PciIrpNotSupported, // SystemControl - just pass down!
  179. IRP_DOWNWARD, PciIrpNotSupported // DeviceControl - just pass down!
  180. };
  181. NTSTATUS
  182. PciFdoIrpStartDevice(
  183. IN PIRP Irp,
  184. IN PIO_STACK_LOCATION IrpSp,
  185. IN PPCI_COMMON_EXTENSION DeviceExtension
  186. )
  187. /*++
  188. Routine Description:
  189. Handler routine for start IRPs. This allows PDO filters to
  190. modify the allocated resources if they are filtering resource
  191. requirements. Called after completion.
  192. Arguments:
  193. DeviceObject - Supplies the device object
  194. Irp - Supplies the IRP_MN_START_DEVICE irp.
  195. FdoExtension - Supplies the FDO extension
  196. Return Value:
  197. ERROR_SUCCESS if successful
  198. NTSTATUS error code otherwise
  199. --*/
  200. {
  201. NTSTATUS status;
  202. PPCI_FDO_EXTENSION fdoExtension;
  203. PPCI_PDO_EXTENSION pdoExtension;
  204. PCM_RESOURCE_LIST resources;
  205. UCHAR barType[PCI_TYPE1_ADDRESSES] = {0,0};
  206. ULONG index;
  207. PCM_PARTIAL_RESOURCE_DESCRIPTOR currentResource;
  208. PIO_RESOURCE_DESCRIPTOR currentRequirement;
  209. PAGED_CODE();
  210. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  211. return STATUS_NOT_SUPPORTED;
  212. }
  213. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  214. status = PciBeginStateTransition(DeviceExtension, PciStarted);
  215. if (!NT_SUCCESS(status)) {
  216. return status;
  217. }
  218. //
  219. // If this is a PCI-PCI bridge then check if it has any bars and if so exclude
  220. // them from the list used to initialize the arbiters.
  221. //
  222. resources = IrpSp->Parameters.StartDevice.AllocatedResources;
  223. if (resources && !PCI_IS_ROOT_FDO(fdoExtension)) {
  224. ASSERT(resources->Count == 1);
  225. pdoExtension = PCI_BRIDGE_PDO(fdoExtension);
  226. if (pdoExtension->Resources) {
  227. if (pdoExtension->HeaderType == PCI_BRIDGE_TYPE) {
  228. //
  229. // If there are any bars they are at the beginning of the list
  230. // so "begin at the beginning which is a very good place to start".
  231. //
  232. currentResource = resources->List[0].PartialResourceList.PartialDescriptors;
  233. for (index = 0; index < PCI_TYPE1_ADDRESSES; index++) {
  234. //
  235. // Extract the requirement we asked for to determine if this
  236. // bridge implements any bars (index 0 and 1 in the Limits
  237. // array)
  238. //
  239. currentRequirement = &pdoExtension->Resources->Limit[index];
  240. //
  241. // CmResourceTypeNull indicates that we didn't request any
  242. // resources so the bar is not implemented and there is nothing
  243. // to prune out.
  244. //
  245. if (currentRequirement->Type != CmResourceTypeNull) {
  246. ASSERT(currentResource->Type == currentRequirement->Type);
  247. //
  248. // Save away the type so we can restore it later
  249. //
  250. barType[index] = currentResource->Type;
  251. //
  252. // Null out the resource so we don't configure the arbiters to
  253. // use it
  254. //
  255. currentResource->Type = CmResourceTypeNull;
  256. //
  257. // Advance the pointer into the started resources by 2
  258. // descriptors to skip over the device private
  259. //
  260. ASSERT((currentResource+1)->Type == CmResourceTypeDevicePrivate);
  261. currentResource+=2;
  262. }
  263. }
  264. }
  265. }
  266. }
  267. //
  268. // Initialize the arbiters
  269. //
  270. status = PciInitializeArbiterRanges(fdoExtension, resources);
  271. //
  272. // Restore the original resource list if we changed it
  273. //
  274. if (resources && !PCI_IS_ROOT_FDO(fdoExtension) && pdoExtension->Resources) {
  275. currentResource = resources->List[0].PartialResourceList.PartialDescriptors;
  276. for (index = 0; index < PCI_TYPE1_ADDRESSES; index++) {
  277. if (barType[index] != CmResourceTypeNull) {
  278. currentResource->Type = barType[index];
  279. //
  280. // Advance the pointer into the started resources by 2
  281. // descriptors to skip over the device private
  282. //
  283. ASSERT((currentResource+1)->Type == CmResourceTypeDevicePrivate);
  284. currentResource+=2;
  285. }
  286. }
  287. }
  288. if (!NT_SUCCESS(status)) {
  289. PciCancelStateTransition(DeviceExtension, PciStarted);
  290. return status;
  291. }
  292. PciCommitStateTransition(DeviceExtension, PciStarted);
  293. return STATUS_SUCCESS;
  294. }
  295. NTSTATUS
  296. PciFdoIrpQueryRemoveDevice(
  297. IN PIRP Irp,
  298. IN PIO_STACK_LOCATION IrpSp,
  299. IN PPCI_COMMON_EXTENSION DeviceExtension
  300. )
  301. {
  302. PAGED_CODE();
  303. return PciBeginStateTransition(DeviceExtension, PciDeleted);
  304. }
  305. NTSTATUS
  306. PciFdoIrpRemoveDevice(
  307. IN PIRP Irp,
  308. IN PIO_STACK_LOCATION IrpSp,
  309. IN PPCI_COMMON_EXTENSION DeviceExtension
  310. )
  311. {
  312. PPCI_FDO_EXTENSION fdoExtension;
  313. PPCI_PDO_EXTENSION pdox;
  314. PDEVICE_OBJECT attachedDevice;
  315. NTSTATUS status;
  316. PAGED_CODE();
  317. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  318. ExAcquireFastMutex(&fdoExtension->ChildListMutex);
  319. while (fdoExtension->ChildPdoList) {
  320. pdox = (PPCI_PDO_EXTENSION) fdoExtension->ChildPdoList;
  321. #if DBG
  322. PciDebugPrint(
  323. PciDbgVerbose,
  324. "PCI Killing PDO %p PDOx %p (b=%d, d=%d, f=%d)\n",
  325. pdox->PhysicalDeviceObject,
  326. pdox,
  327. PCI_PARENT_FDOX(pdox)->BaseBus,
  328. pdox->Slot.u.bits.DeviceNumber,
  329. pdox->Slot.u.bits.FunctionNumber
  330. );
  331. ASSERT(pdox->DeviceState == PciNotStarted);
  332. #endif
  333. PciPdoDestroy(pdox->PhysicalDeviceObject);
  334. }
  335. ExReleaseFastMutex(&fdoExtension->ChildListMutex);
  336. //
  337. // Destroy any secondary extensions associated with
  338. // this FDO.
  339. //
  340. while (fdoExtension->SecondaryExtension.Next) {
  341. PcipDestroySecondaryExtension(
  342. &fdoExtension->SecondaryExtension,
  343. NULL,
  344. fdoExtension->SecondaryExtension.Next
  345. );
  346. }
  347. //
  348. // Destroy the FDO.
  349. //
  350. // The IRP needs to go down the device stack but we
  351. // need to remove the device from the stack so grab
  352. // the next object first, then detach, then pass it
  353. // down.
  354. //
  355. PciDebugPrint(
  356. PciDbgInformative,
  357. "PCI FDOx (%p) destroyed.",
  358. fdoExtension
  359. );
  360. //
  361. // Note that a filter above us may have failed Start. If this is so, we get
  362. // no query because the "devnode" has never been started...
  363. //
  364. if (!PciIsInTransitionToState(DeviceExtension, PciDeleted)) {
  365. status = PciBeginStateTransition(DeviceExtension, PciDeleted);
  366. ASSERT(NT_SUCCESS(status));
  367. }
  368. PciCommitStateTransition(DeviceExtension, PciDeleted);
  369. PciRemoveEntryFromList(&PciFdoExtensionListHead,
  370. &fdoExtension->List,
  371. &PciGlobalLock);
  372. attachedDevice = fdoExtension->AttachedDeviceObject;
  373. IoDetachDevice(attachedDevice);
  374. IoDeleteDevice(fdoExtension->FunctionalDeviceObject);
  375. Irp->IoStatus.Status = STATUS_SUCCESS;
  376. IoSkipCurrentIrpStackLocation(Irp);
  377. return IoCallDriver(attachedDevice, Irp);
  378. }
  379. NTSTATUS
  380. PciFdoIrpCancelRemoveDevice(
  381. IN PIRP Irp,
  382. IN PIO_STACK_LOCATION IrpSp,
  383. IN PPCI_COMMON_EXTENSION DeviceExtension
  384. )
  385. {
  386. PAGED_CODE();
  387. PciCancelStateTransition(DeviceExtension, PciDeleted);
  388. return STATUS_SUCCESS;
  389. }
  390. NTSTATUS
  391. PciFdoIrpStopDevice(
  392. IN PIRP Irp,
  393. IN PIO_STACK_LOCATION IrpSp,
  394. IN PPCI_COMMON_EXTENSION DeviceExtension
  395. )
  396. {
  397. PAGED_CODE();
  398. PciCommitStateTransition(DeviceExtension, PciStopped);
  399. return STATUS_SUCCESS;
  400. }
  401. NTSTATUS
  402. PciFdoIrpQueryStopDevice(
  403. IN PIRP Irp,
  404. IN PIO_STACK_LOCATION IrpSp,
  405. IN PPCI_COMMON_EXTENSION DeviceExtension
  406. )
  407. {
  408. PAGED_CODE();
  409. PciBeginStateTransition(DeviceExtension, PciStopped);
  410. //
  411. // We don't support multilevel rebalance so we can't stop host bridges.
  412. //
  413. return STATUS_UNSUCCESSFUL;
  414. }
  415. NTSTATUS
  416. PciFdoIrpCancelStopDevice(
  417. IN PIRP Irp,
  418. IN PIO_STACK_LOCATION IrpSp,
  419. IN PPCI_COMMON_EXTENSION DeviceExtension
  420. )
  421. {
  422. PAGED_CODE();
  423. PciCancelStateTransition(DeviceExtension, PciStopped);
  424. return STATUS_SUCCESS;
  425. }
  426. NTSTATUS
  427. PciFdoIrpQueryDeviceRelations(
  428. IN PIRP Irp,
  429. IN PIO_STACK_LOCATION IrpSp,
  430. IN PPCI_COMMON_EXTENSION DeviceExtension
  431. )
  432. {
  433. PAGED_CODE();
  434. if (IrpSp->Parameters.QueryDeviceRelations.Type == BusRelations) {
  435. return PciQueryDeviceRelations(
  436. (PPCI_FDO_EXTENSION) DeviceExtension,
  437. (PDEVICE_RELATIONS *) &Irp->IoStatus.Information
  438. );
  439. }
  440. //
  441. // No other relation types need to be handled.
  442. //
  443. return STATUS_NOT_SUPPORTED;
  444. }
  445. NTSTATUS
  446. PciFdoIrpQueryCapabilities(
  447. IN PIRP Irp,
  448. IN PIO_STACK_LOCATION IrpSp,
  449. IN PPCI_COMMON_EXTENSION DeviceExtension
  450. )
  451. /*++
  452. Routine Description:
  453. Snoops the results of a QUERY CAPABILITIES IRP that got sent
  454. downwards. This saves us having to send our own for things
  455. like the device's power characteristics.
  456. Arguments:
  457. DeviceObject - Supplies the device object
  458. Irp - Supplies the IRP_MN_QUERY_CAPABILITIES irp.
  459. FdoExtension - Supplies the FDO extension
  460. Return Value:
  461. STATUS_SUCCESS
  462. --*/
  463. {
  464. PDEVICE_CAPABILITIES capabilities;
  465. PPCI_FDO_EXTENSION fdoExtension;
  466. PAGED_CODE();
  467. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  468. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  469. PciDebugPrint(
  470. PciDbgQueryCap,
  471. "PCI - FdoQueryCapabilitiesCompletion (fdox %08x) child status = %08x\n",
  472. fdoExtension,
  473. Irp->IoStatus.Status
  474. );
  475. //
  476. // Grab a pointer to the capablities for easy referencing
  477. //
  478. capabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
  479. //
  480. // Remember what the system wake and device wake level are
  481. //
  482. fdoExtension->PowerState.SystemWakeLevel = capabilities->SystemWake;
  483. fdoExtension->PowerState.DeviceWakeLevel = capabilities->DeviceWake;
  484. //
  485. // Grab the S-state to D-State mapping
  486. //
  487. RtlCopyMemory(
  488. fdoExtension->PowerState.SystemStateMapping,
  489. capabilities->DeviceState,
  490. (PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE)
  491. );
  492. #if DBG
  493. if (PciDebug & PciDbgQueryCap) {
  494. PciDebugDumpQueryCapabilities(capabilities);
  495. }
  496. #endif
  497. return STATUS_SUCCESS;
  498. }
  499. NTSTATUS
  500. PciFdoIrpQueryLegacyBusInformation(
  501. IN PIRP Irp,
  502. IN PIO_STACK_LOCATION IrpSp,
  503. IN PPCI_COMMON_EXTENSION DeviceExtension
  504. )
  505. {
  506. PAGED_CODE();
  507. return PciQueryLegacyBusInformation(
  508. (PPCI_FDO_EXTENSION) DeviceExtension,
  509. (PLEGACY_BUS_INFORMATION *) &Irp->IoStatus.Information
  510. );
  511. }
  512. NTSTATUS
  513. PciFdoIrpDeviceUsageNotification(
  514. IN PIRP Irp,
  515. IN PIO_STACK_LOCATION IrpSp,
  516. IN PPCI_COMMON_EXTENSION DeviceExtension
  517. )
  518. {
  519. PPCI_FDO_EXTENSION fdoExtension;
  520. PAGED_CODE();
  521. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  522. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  523. return PciLocalDeviceUsage(&fdoExtension->PowerState, Irp);
  524. } else {
  525. return STATUS_NOT_SUPPORTED;
  526. }
  527. }
  528. NTSTATUS
  529. PciFdoIrpQueryInterface(
  530. IN PIRP Irp,
  531. IN PIO_STACK_LOCATION IrpSp,
  532. IN PPCI_COMMON_EXTENSION DeviceExtension
  533. )
  534. {
  535. PPCI_FDO_EXTENSION fdoExtension;
  536. NTSTATUS status;
  537. PAGED_CODE();
  538. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  539. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  540. // NTRAID #54671 - 4/20/2000 - andrewth
  541. //
  542. // We might want to do a synchronizing state
  543. // transition here so we don't attempt to get the interface during a
  544. // stop/remove sequence.
  545. //
  546. // We shouldn't hold interfaces when something isn't
  547. // started. But we won't boot unless we hack the below....
  548. //
  549. //if (fdoExtension->DeviceState != PciStarted) {
  550. if (fdoExtension->DeviceState == PciDeleted) {
  551. return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
  552. }
  553. status = PciQueryInterface(
  554. fdoExtension,
  555. IrpSp->Parameters.QueryInterface.InterfaceType,
  556. IrpSp->Parameters.QueryInterface.Size,
  557. IrpSp->Parameters.QueryInterface.Version,
  558. IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
  559. IrpSp->Parameters.QueryInterface.Interface,
  560. FALSE
  561. );
  562. if (NT_SUCCESS(status)) {
  563. Irp->IoStatus.Status = status;
  564. return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
  565. } else if (status == STATUS_NOT_SUPPORTED) {
  566. //
  567. // Status == STATUS_NOT_SUPPORTED. Pass IRP down the stack
  568. // and see if anyone else is kind enough to provide this
  569. // interface.
  570. //
  571. status = PciCallDownIrpStack(DeviceExtension, Irp);
  572. if (status == STATUS_NOT_SUPPORTED) {
  573. //
  574. // If nobody provided the interface, try again at
  575. // this level.
  576. //
  577. status = PciQueryInterface(
  578. fdoExtension,
  579. IrpSp->Parameters.QueryInterface.InterfaceType,
  580. IrpSp->Parameters.QueryInterface.Size,
  581. IrpSp->Parameters.QueryInterface.Version,
  582. IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
  583. IrpSp->Parameters.QueryInterface.Interface,
  584. TRUE
  585. );
  586. }
  587. }
  588. if (status != STATUS_NOT_SUPPORTED) {
  589. Irp->IoStatus.Status = status;
  590. } else {
  591. status = Irp->IoStatus.Status;
  592. }
  593. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  594. return status;
  595. }
  596. NTSTATUS
  597. PciFdoIrpSurpriseRemoval(
  598. IN PIRP Irp,
  599. IN PIO_STACK_LOCATION IrpSp,
  600. IN PPCI_COMMON_EXTENSION DeviceExtension
  601. )
  602. {
  603. PPCI_FDO_EXTENSION fdoExtension;
  604. NTSTATUS status;
  605. PAGED_CODE();
  606. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  607. status = PciBeginStateTransition(DeviceExtension, PciSurpriseRemoved);
  608. ASSERT(NT_SUCCESS(status));
  609. if (NT_SUCCESS(status)) {
  610. PciCommitStateTransition(DeviceExtension, PciSurpriseRemoved);
  611. status = PciBeginStateTransition(DeviceExtension, PciDeleted);
  612. }
  613. return status;
  614. }
  615. NTSTATUS
  616. PciAddDevice(
  617. IN PDRIVER_OBJECT DriverObject,
  618. IN PDEVICE_OBJECT PhysicalDeviceObject
  619. )
  620. /*++
  621. Routine Description:
  622. Given a physical device object, this routine creates a functional
  623. device object for it.
  624. Arguments:
  625. DriverObject - Pointer to our driver's DRIVER_OBJECT structure.
  626. PhysicalDeviceObject - Pointer to the physical device object for which
  627. we must create a functional device object.
  628. Return Value:
  629. NT status.
  630. --*/
  631. {
  632. PDEVICE_OBJECT functionalDeviceObject = NULL;
  633. PDEVICE_OBJECT attachedTo = NULL;
  634. PPCI_FDO_EXTENSION fdoExtension = NULL;
  635. PPCI_FDO_EXTENSION pciParentFdoExtension;
  636. PPCI_PDO_EXTENSION pdoExtension;
  637. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
  638. NTSTATUS status;
  639. PSINGLE_LIST_ENTRY nextEntry;
  640. HANDLE deviceRegistryHandle;
  641. ULONG resultLength;
  642. UNICODE_STRING hackFlagsString;
  643. UCHAR infoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1];
  644. PKEY_VALUE_PARTIAL_INFORMATION info = (PKEY_VALUE_PARTIAL_INFORMATION) infoBuffer;
  645. PAGED_CODE();
  646. PciDebugPrint(PciDbgAddDevice, "PCI - AddDevice (a new bus).\n");
  647. //
  648. // Find out if the PDO was created by the PCI driver. That is,
  649. // if it is a child or a root bus. Validate a few things before
  650. // going any further.
  651. //
  652. pciParentFdoExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
  653. &PciGlobalLock);
  654. if (pciParentFdoExtension) {
  655. //
  656. // The PDO was created by this driver, therefore we can look at
  657. // the extension. Get it and verify it's ours.
  658. //
  659. pdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
  660. ASSERT_PCI_PDO_EXTENSION(pdoExtension);
  661. //
  662. // The only thing we should get an add device that is a
  663. // child device is a PCI-PCI bridge.
  664. //
  665. if ((pdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) ||
  666. (pdoExtension->SubClass != PCI_SUBCLASS_BR_PCI_TO_PCI)) {
  667. PciDebugPrint(
  668. PciDbgAlways,
  669. "PCI - PciAddDevice for Non-Root/Non-PCI-PCI bridge,\n"
  670. " Class %02x, SubClass %02x, will not add.\n",
  671. pdoExtension->BaseClass,
  672. pdoExtension->SubClass
  673. );
  674. ASSERT((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
  675. (pdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
  676. status = STATUS_INVALID_DEVICE_REQUEST;
  677. goto cleanup;
  678. }
  679. PciDebugPrint(PciDbgAddDevice,
  680. "PCI - AddDevice (new bus is child of bus 0x%x).\n",
  681. pciParentFdoExtension->BaseBus
  682. );
  683. if (!PciAreBusNumbersConfigured(pdoExtension)) {
  684. //
  685. // This bridge isn't configured and if we had been able to we would
  686. // already have done so
  687. //
  688. PciDebugPrint(
  689. PciDbgAddDevice | PciDbgInformative,
  690. "PCI - Bus numbers not configured for bridge (0x%x.0x%x.0x%x)\n",
  691. pciParentFdoExtension->BaseBus,
  692. pdoExtension->Slot.u.bits.DeviceNumber,
  693. pdoExtension->Slot.u.bits.FunctionNumber,
  694. pdoExtension->Dependent.type1.PrimaryBus
  695. );
  696. status = STATUS_INVALID_DEVICE_REQUEST;
  697. goto cleanup;
  698. }
  699. }
  700. //
  701. // We've been given the PhysicalDeviceObject for a PCI bus. Create the
  702. // functionalDeviceObject. Our FDO will be nameless.
  703. //
  704. status = IoCreateDevice(
  705. DriverObject, // our driver object
  706. sizeof(PCI_FDO_EXTENSION), // size of our extension
  707. NULL, // our name
  708. FILE_DEVICE_BUS_EXTENDER, // device type
  709. 0, // device characteristics
  710. FALSE, // not exclusive
  711. &functionalDeviceObject // store new device object here
  712. );
  713. if (!NT_SUCCESS(status)) {
  714. goto cleanup;
  715. }
  716. fdoExtension = (PPCI_FDO_EXTENSION)functionalDeviceObject->DeviceExtension;
  717. //
  718. // We have our functionalDeviceObject, initialize it.
  719. //
  720. PciInitializeFdoExtensionCommonFields(
  721. fdoExtension,
  722. functionalDeviceObject,
  723. PhysicalDeviceObject
  724. );
  725. //
  726. // Now attach to the PDO we were given.
  727. //
  728. attachedTo = IoAttachDeviceToDeviceStack(functionalDeviceObject,
  729. PhysicalDeviceObject);
  730. if (attachedTo == NULL) {
  731. ASSERT(attachedTo != NULL);
  732. status = STATUS_NO_SUCH_DEVICE;
  733. goto cleanup;
  734. }
  735. fdoExtension->AttachedDeviceObject = attachedTo;
  736. //
  737. // Get the access registers and base bus number for this bus.
  738. // If this bus was discovered by this driver, then the PDO was
  739. // created by this driver and will be on one of the PDO lists
  740. // under one of the FDOs owned by this driver. Otherwise it
  741. // is a new root,.... use magic.
  742. //
  743. if (pciParentFdoExtension) {
  744. //
  745. // This physical device was discovered by this driver.
  746. // Get the bus number from the PDO extension.
  747. //
  748. PSINGLE_LIST_ENTRY secondaryExtension;
  749. fdoExtension->BaseBus = pdoExtension->Dependent.type1.SecondaryBus;
  750. //
  751. // Copy the access methods from the root fdo and set
  752. // the root fdo back pointer.
  753. //
  754. fdoExtension->BusRootFdoExtension =
  755. pciParentFdoExtension->BusRootFdoExtension;
  756. //
  757. // Point the PDOextension to the new FDOextension (also indicates
  758. // the object is a bridge) and vice versa.
  759. //
  760. pdoExtension->BridgeFdoExtension = fdoExtension;
  761. fdoExtension->ParentFdoExtension = pciParentFdoExtension;
  762. //
  763. // Cause the requirements list to be reevaluated.
  764. //
  765. PciInvalidateResourceInfoCache(pdoExtension);
  766. } else {
  767. PVOID buffer;
  768. //
  769. // Get the boot configuration (CmResourceList) for
  770. // this PDO. This gives us the bus number and the
  771. // ranges covered by this host bridge.
  772. //
  773. status = PciGetDeviceProperty(
  774. PhysicalDeviceObject,
  775. DevicePropertyBootConfiguration,
  776. &buffer
  777. );
  778. if (NT_SUCCESS(status)) {
  779. #if DBG
  780. PciDebugPrint(PciDbgAddDeviceRes,
  781. "PCI - CM RESOURCE LIST FROM ROOT PDO\n");
  782. PciDebugPrintCmResList(PciDbgAddDeviceRes,
  783. buffer);
  784. #endif
  785. descriptor = PciFindDescriptorInCmResourceList(
  786. CmResourceTypeBusNumber,
  787. buffer,
  788. NULL
  789. );
  790. } else {
  791. descriptor = NULL;
  792. }
  793. if (descriptor != NULL) {
  794. //
  795. // Sanity check, some servers are aproaching
  796. // 256 busses but as there is no way to deal with
  797. // numbering bridges under a bus > 256 and we don't
  798. // have raw and translated bus numbers yet - it had
  799. // better be < 0xFF!
  800. //
  801. ASSERT(descriptor->u.BusNumber.Start <= 0xFF);
  802. ASSERT(descriptor->u.BusNumber.Start + descriptor->u.BusNumber.Length - 1 <= 0xFF);
  803. fdoExtension->BaseBus =
  804. (UCHAR)descriptor->u.BusNumber.Start;
  805. fdoExtension->MaxSubordinateBus =
  806. (UCHAR)(descriptor->u.BusNumber.Start + descriptor->u.BusNumber.Length - 1);
  807. PciDebugPrint(PciDbgAddDevice,
  808. "PCI - Root Bus # 0x%x->0x%x.\n",
  809. fdoExtension->BaseBus,
  810. fdoExtension->MaxSubordinateBus
  811. );
  812. } else {
  813. //
  814. // HaveGuessedConfigOnceAlready is used to tell
  815. // if have multiple roots and no config info. If
  816. // this happens we end up gussing the bus number
  817. // as zero, doing this more than once is not good.
  818. //
  819. if (HaveGuessedConfigOnceAlready) {
  820. KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
  821. PCI_BUGCODE_TOO_MANY_CONFIG_GUESSES,
  822. (ULONG_PTR)PhysicalDeviceObject,
  823. 0,
  824. 0);
  825. }
  826. PciDebugPrint(
  827. PciDbgAlways,
  828. "PCI Will use default configuration.\n"
  829. );
  830. HaveGuessedConfigOnceAlready = TRUE;
  831. fdoExtension->BaseBus = 0;
  832. }
  833. fdoExtension->BusRootFdoExtension = fdoExtension;
  834. }
  835. //
  836. // Organise access to config space
  837. //
  838. status = PciGetConfigHandlers(fdoExtension);
  839. if (!NT_SUCCESS(status)) {
  840. goto cleanup;
  841. }
  842. //
  843. // Initialize arbiters for this FDO.
  844. //
  845. status = PciInitializeArbiters(fdoExtension);
  846. if (!NT_SUCCESS(status)) {
  847. goto cleanup;
  848. }
  849. //
  850. // Indicate this is a REAL FDO extension that is part of a REAL
  851. // FDO. (Fake extensions exist to assist in the enumeration of
  852. // busses which PCI isn't the real controller for (eg CardBus).
  853. //
  854. fdoExtension->Fake = FALSE;
  855. //
  856. // Insert this Fdo in the list of PCI parent Fdos.
  857. //
  858. PciInsertEntryAtTail(&PciFdoExtensionListHead,
  859. &fdoExtension->List,
  860. &PciGlobalLock);
  861. #if defined(_WIN64)
  862. //
  863. // Update the legacy hardware tree that would have been build by the ARC
  864. // firmware or NTDetect which don't exist here.
  865. //
  866. status = PciUpdateLegacyHardwareDescription(fdoExtension);
  867. if (!NT_SUCCESS(status)) {
  868. goto cleanup;
  869. }
  870. #endif
  871. //
  872. // Check if there are any hacks to apply to this bus.
  873. // These are located under the device registry key in a value called HackFlags
  874. //
  875. status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  876. PLUGPLAY_REGKEY_DEVICE,
  877. KEY_ALL_ACCESS,
  878. &deviceRegistryHandle
  879. );
  880. if (!NT_SUCCESS(status)) {
  881. goto cleanup;
  882. }
  883. PciConstStringToUnicodeString(&hackFlagsString, L"HackFlags");
  884. status = ZwQueryValueKey(deviceRegistryHandle,
  885. &hackFlagsString,
  886. KeyValuePartialInformation,
  887. info,
  888. sizeof(infoBuffer),
  889. &resultLength
  890. );
  891. ZwClose(deviceRegistryHandle);
  892. //
  893. // If we have valid data in the registry then remember it
  894. //
  895. if (NT_SUCCESS(status)
  896. && (info->Type == REG_DWORD)
  897. && (info->DataLength == sizeof(ULONG))) {
  898. fdoExtension->BusHackFlags = *((PULONG)(&info->Data));
  899. }
  900. //
  901. // We can receive IRPs now...
  902. //
  903. functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  904. //
  905. // Get any hotplug parameters (we send IRPS for this so it must be after
  906. // DO_DEVICE_INITIALIZING is cleared so we can deal with them)
  907. //
  908. PciGetHotPlugParameters(fdoExtension);
  909. return STATUS_SUCCESS;
  910. cleanup:
  911. ASSERT(!NT_SUCCESS(status));
  912. //
  913. // Destroy any secondary extensions associated with
  914. // this FDO.
  915. //
  916. if (fdoExtension) {
  917. while (fdoExtension->SecondaryExtension.Next) {
  918. PcipDestroySecondaryExtension(
  919. &fdoExtension->SecondaryExtension,
  920. NULL,
  921. fdoExtension->SecondaryExtension.Next
  922. );
  923. }
  924. }
  925. if (attachedTo) {
  926. IoDetachDevice(attachedTo);
  927. }
  928. if (functionalDeviceObject) {
  929. IoDeleteDevice(functionalDeviceObject);
  930. }
  931. return status;
  932. }
  933. VOID
  934. PciInitializeFdoExtensionCommonFields(
  935. IN PPCI_FDO_EXTENSION FdoExtension,
  936. IN PDEVICE_OBJECT Fdo,
  937. IN PDEVICE_OBJECT Pdo
  938. )
  939. {
  940. RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
  941. FdoExtension->ExtensionType = PciFdoExtensionType;
  942. FdoExtension->PhysicalDeviceObject = Pdo;
  943. FdoExtension->FunctionalDeviceObject = Fdo;
  944. FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
  945. FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
  946. FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
  947. ExInitializeFastMutex(&FdoExtension->SecondaryExtMutex);
  948. ExInitializeFastMutex(&FdoExtension->ChildListMutex);
  949. PciInitializeState((PPCI_COMMON_EXTENSION) FdoExtension);
  950. }
  951. VOID
  952. PciGetHotPlugParameters(
  953. IN PPCI_FDO_EXTENSION Fdo
  954. )
  955. /*++
  956. Description:
  957. Runs the _HPP (described below) on the device and saves the parameters if available
  958. Method (_HPP, 0) {
  959. Return (Package(){
  960. 0x00000008, // CacheLineSize in DWORDS
  961. 0x00000040, // LatencyTimer in PCI clocks
  962. 0x00000001, // Enable SERR (Boolean)
  963. 0x00000001 // Enable PERR (Boolean)
  964. })
  965. Arguments:
  966. Fdo - The PDO extension for the bridge
  967. Return Value:
  968. TRUE - if the parameters are available, FASLE otherwise
  969. --*/
  970. {
  971. #ifndef HPPTESTING
  972. NTSTATUS status;
  973. ACPI_EVAL_INPUT_BUFFER input;
  974. PACPI_EVAL_OUTPUT_BUFFER output = NULL;
  975. ULONG count;
  976. PACPI_METHOD_ARGUMENT argument;
  977. ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + sizeof(ACPI_METHOD_ARGUMENT) * PCI_HPP_PACKAGE_COUNT;
  978. PAGED_CODE();
  979. output = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, outputSize);
  980. if (!output) {
  981. status = STATUS_INSUFFICIENT_RESOURCES;
  982. goto exit;
  983. }
  984. RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
  985. RtlZeroMemory(output, outputSize);
  986. //
  987. // Send a IOCTL to ACPI to request it to run the _HPP method on this device
  988. // if the method it is present
  989. //
  990. input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  991. input.MethodNameAsUlong = (ULONG)'PPH_';
  992. //
  993. // PciSendIoctl deals with sending this from the top of the stack.
  994. //
  995. status = PciSendIoctl(Fdo->PhysicalDeviceObject,
  996. IOCTL_ACPI_EVAL_METHOD,
  997. &input,
  998. sizeof(ACPI_EVAL_INPUT_BUFFER),
  999. output,
  1000. outputSize
  1001. );
  1002. if (!NT_SUCCESS(status)) {
  1003. //
  1004. // Inherit them from my parent (If I have one)
  1005. //
  1006. if (!PCI_IS_ROOT_FDO(Fdo)) {
  1007. RtlCopyMemory(&Fdo->HotPlugParameters,
  1008. &Fdo->ParentFdoExtension->HotPlugParameters,
  1009. sizeof(Fdo->HotPlugParameters)
  1010. );
  1011. }
  1012. } else {
  1013. if (output->Count != PCI_HPP_PACKAGE_COUNT) {
  1014. goto exit;
  1015. }
  1016. //
  1017. // Check they are all integers and in the right bounds
  1018. //
  1019. for (count = 0; count < PCI_HPP_PACKAGE_COUNT; count++) {
  1020. ULONG current;
  1021. if (output->Argument[count].Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  1022. goto exit;
  1023. }
  1024. current = output->Argument[count].Argument;
  1025. switch (count) {
  1026. case PCI_HPP_CACHE_LINE_SIZE_INDEX:
  1027. case PCI_HPP_LATENCY_TIMER_INDEX:
  1028. //
  1029. // These registers are only a UCHAR in length
  1030. //
  1031. if (current > 0xFF) {
  1032. goto exit;
  1033. }
  1034. break;
  1035. case PCI_HPP_ENABLE_SERR_INDEX:
  1036. case PCI_HPP_ENABLE_PERR_INDEX:
  1037. //
  1038. // These are booleans - 1 or 0
  1039. //
  1040. if (current > 1) {
  1041. goto exit;
  1042. }
  1043. break;
  1044. }
  1045. }
  1046. //
  1047. // Finally save them and remember we got them.
  1048. //
  1049. Fdo->HotPlugParameters.CacheLineSize = (UCHAR)output->Argument[PCI_HPP_CACHE_LINE_SIZE_INDEX].Argument;
  1050. Fdo->HotPlugParameters.LatencyTimer = (UCHAR)output->Argument[PCI_HPP_LATENCY_TIMER_INDEX].Argument;
  1051. Fdo->HotPlugParameters.EnableSERR = (BOOLEAN)output->Argument[PCI_HPP_ENABLE_SERR_INDEX].Argument;
  1052. Fdo->HotPlugParameters.EnablePERR = (BOOLEAN)output->Argument[PCI_HPP_ENABLE_PERR_INDEX].Argument;
  1053. Fdo->HotPlugParameters.Acquired = TRUE;
  1054. }
  1055. exit:
  1056. if (output) {
  1057. ExFreePool(output);
  1058. }
  1059. #else
  1060. Fdo->HotPlugParameters.CacheLineSize = 0x8;
  1061. Fdo->HotPlugParameters.LatencyTimer = 0x20;
  1062. Fdo->HotPlugParameters.EnableSERR = 0;
  1063. Fdo->HotPlugParameters.EnablePERR = 0;
  1064. Fdo->HotPlugParameters.Acquired = TRUE;
  1065. #endif
  1066. }