Leaked source code of windows server 2003
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.

1386 lines
40 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 = NULL;
  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. PCI_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. PCI_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. PCI_ASSERT((currentResource+1)->Type == CmResourceTypeDevicePrivate);
  261. currentResource+=2;
  262. }
  263. }
  264. }
  265. }
  266. }
  267. //
  268. // Initialize arbiters with these resources.
  269. //
  270. status = PciInitializeArbiterRanges(fdoExtension, resources);
  271. if (!NT_SUCCESS(status)) {
  272. goto cleanup;
  273. }
  274. //
  275. // Restore the original resource list if we changed it
  276. //
  277. if (resources && !PCI_IS_ROOT_FDO(fdoExtension) && pdoExtension->Resources) {
  278. currentResource = resources->List[0].PartialResourceList.PartialDescriptors;
  279. for (index = 0; index < PCI_TYPE1_ADDRESSES; index++) {
  280. if (barType[index] != CmResourceTypeNull) {
  281. currentResource->Type = barType[index];
  282. //
  283. // Advance the pointer into the started resources by 2
  284. // descriptors to skip over the device private
  285. //
  286. PCI_ASSERT((currentResource+1)->Type == CmResourceTypeDevicePrivate);
  287. currentResource+=2;
  288. }
  289. }
  290. }
  291. cleanup:
  292. if (!NT_SUCCESS(status)) {
  293. PciCancelStateTransition(DeviceExtension, PciStarted);
  294. return status;
  295. }
  296. PciCommitStateTransition(DeviceExtension, PciStarted);
  297. return STATUS_SUCCESS;
  298. }
  299. NTSTATUS
  300. PciFdoIrpQueryRemoveDevice(
  301. IN PIRP Irp,
  302. IN PIO_STACK_LOCATION IrpSp,
  303. IN PPCI_COMMON_EXTENSION DeviceExtension
  304. )
  305. {
  306. PAGED_CODE();
  307. return PciBeginStateTransition(DeviceExtension, PciDeleted);
  308. }
  309. NTSTATUS
  310. PciFdoIrpRemoveDevice(
  311. IN PIRP Irp,
  312. IN PIO_STACK_LOCATION IrpSp,
  313. IN PPCI_COMMON_EXTENSION DeviceExtension
  314. )
  315. {
  316. PPCI_FDO_EXTENSION fdoExtension;
  317. PPCI_PDO_EXTENSION pdox;
  318. PDEVICE_OBJECT attachedDevice;
  319. NTSTATUS status;
  320. PAGED_CODE();
  321. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  322. ExAcquireFastMutex(&fdoExtension->ChildListMutex);
  323. while (fdoExtension->ChildPdoList) {
  324. pdox = (PPCI_PDO_EXTENSION) fdoExtension->ChildPdoList;
  325. #if DBG
  326. PciDebugPrint(
  327. PciDbgVerbose,
  328. "PCI Killing PDO %p PDOx %p (b=%d, d=%d, f=%d)\n",
  329. pdox->PhysicalDeviceObject,
  330. pdox,
  331. PCI_PARENT_FDOX(pdox)->BaseBus,
  332. pdox->Slot.u.bits.DeviceNumber,
  333. pdox->Slot.u.bits.FunctionNumber
  334. );
  335. PCI_ASSERT(pdox->DeviceState == PciNotStarted);
  336. #endif
  337. PciPdoDestroy(pdox->PhysicalDeviceObject);
  338. }
  339. ExReleaseFastMutex(&fdoExtension->ChildListMutex);
  340. //
  341. // Destroy any secondary extensions associated with
  342. // this FDO.
  343. //
  344. while (fdoExtension->SecondaryExtension.Next) {
  345. PcipDestroySecondaryExtension(
  346. &fdoExtension->SecondaryExtension,
  347. NULL,
  348. fdoExtension->SecondaryExtension.Next
  349. );
  350. }
  351. //
  352. // Destroy the FDO.
  353. //
  354. // The IRP needs to go down the device stack but we
  355. // need to remove the device from the stack so grab
  356. // the next object first, then detach, then pass it
  357. // down.
  358. //
  359. PciDebugPrint(
  360. PciDbgInformative,
  361. "PCI FDOx (%p) destroyed.",
  362. fdoExtension
  363. );
  364. //
  365. // Note that a filter above us may have failed Start. If this is so, we get
  366. // no query because the "devnode" has never been started...
  367. //
  368. if (!PciIsInTransitionToState(DeviceExtension, PciDeleted)) {
  369. status = PciBeginStateTransition(DeviceExtension, PciDeleted);
  370. PCI_ASSERT(NT_SUCCESS(status));
  371. }
  372. PciCommitStateTransition(DeviceExtension, PciDeleted);
  373. PciRemoveEntryFromList(&PciFdoExtensionListHead,
  374. &fdoExtension->List,
  375. &PciGlobalLock);
  376. attachedDevice = fdoExtension->AttachedDeviceObject;
  377. IoDetachDevice(attachedDevice);
  378. IoDeleteDevice(fdoExtension->FunctionalDeviceObject);
  379. Irp->IoStatus.Status = STATUS_SUCCESS;
  380. IoSkipCurrentIrpStackLocation(Irp);
  381. return IoCallDriver(attachedDevice, Irp);
  382. }
  383. NTSTATUS
  384. PciFdoIrpCancelRemoveDevice(
  385. IN PIRP Irp,
  386. IN PIO_STACK_LOCATION IrpSp,
  387. IN PPCI_COMMON_EXTENSION DeviceExtension
  388. )
  389. {
  390. PAGED_CODE();
  391. PciCancelStateTransition(DeviceExtension, PciDeleted);
  392. return STATUS_SUCCESS;
  393. }
  394. NTSTATUS
  395. PciFdoIrpStopDevice(
  396. IN PIRP Irp,
  397. IN PIO_STACK_LOCATION IrpSp,
  398. IN PPCI_COMMON_EXTENSION DeviceExtension
  399. )
  400. {
  401. PAGED_CODE();
  402. PciCommitStateTransition(DeviceExtension, PciStopped);
  403. return STATUS_SUCCESS;
  404. }
  405. NTSTATUS
  406. PciFdoIrpQueryStopDevice(
  407. IN PIRP Irp,
  408. IN PIO_STACK_LOCATION IrpSp,
  409. IN PPCI_COMMON_EXTENSION DeviceExtension
  410. )
  411. {
  412. PAGED_CODE();
  413. PciBeginStateTransition(DeviceExtension, PciStopped);
  414. //
  415. // We don't support multilevel rebalance so we can't stop host bridges.
  416. //
  417. return STATUS_UNSUCCESSFUL;
  418. }
  419. NTSTATUS
  420. PciFdoIrpCancelStopDevice(
  421. IN PIRP Irp,
  422. IN PIO_STACK_LOCATION IrpSp,
  423. IN PPCI_COMMON_EXTENSION DeviceExtension
  424. )
  425. {
  426. PAGED_CODE();
  427. PciCancelStateTransition(DeviceExtension, PciStopped);
  428. return STATUS_SUCCESS;
  429. }
  430. NTSTATUS
  431. PciFdoIrpQueryDeviceRelations(
  432. IN PIRP Irp,
  433. IN PIO_STACK_LOCATION IrpSp,
  434. IN PPCI_COMMON_EXTENSION DeviceExtension
  435. )
  436. {
  437. PAGED_CODE();
  438. if (IrpSp->Parameters.QueryDeviceRelations.Type == BusRelations) {
  439. return PciQueryDeviceRelations(
  440. (PPCI_FDO_EXTENSION) DeviceExtension,
  441. (PDEVICE_RELATIONS *) &Irp->IoStatus.Information
  442. );
  443. }
  444. //
  445. // No other relation types need to be handled.
  446. //
  447. return STATUS_NOT_SUPPORTED;
  448. }
  449. NTSTATUS
  450. PciFdoIrpQueryCapabilities(
  451. IN PIRP Irp,
  452. IN PIO_STACK_LOCATION IrpSp,
  453. IN PPCI_COMMON_EXTENSION DeviceExtension
  454. )
  455. /*++
  456. Routine Description:
  457. Snoops the results of a QUERY CAPABILITIES IRP that got sent
  458. downwards. This saves us having to send our own for things
  459. like the device's power characteristics.
  460. Arguments:
  461. DeviceObject - Supplies the device object
  462. Irp - Supplies the IRP_MN_QUERY_CAPABILITIES irp.
  463. FdoExtension - Supplies the FDO extension
  464. Return Value:
  465. STATUS_SUCCESS
  466. --*/
  467. {
  468. PDEVICE_CAPABILITIES capabilities;
  469. PPCI_FDO_EXTENSION fdoExtension;
  470. PAGED_CODE();
  471. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  472. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  473. PciDebugPrint(
  474. PciDbgQueryCap,
  475. "PCI - FdoQueryCapabilitiesCompletion (fdox %08x) child status = %08x\n",
  476. fdoExtension,
  477. Irp->IoStatus.Status
  478. );
  479. //
  480. // Grab a pointer to the capablities for easy referencing
  481. //
  482. capabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
  483. //
  484. // Remember what the system wake and device wake level are
  485. //
  486. fdoExtension->PowerState.SystemWakeLevel = capabilities->SystemWake;
  487. fdoExtension->PowerState.DeviceWakeLevel = capabilities->DeviceWake;
  488. //
  489. // Grab the S-state to D-State mapping
  490. //
  491. RtlCopyMemory(
  492. fdoExtension->PowerState.SystemStateMapping,
  493. capabilities->DeviceState,
  494. (PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE)
  495. );
  496. #if DBG
  497. if (PciDebug & PciDbgQueryCap) {
  498. PciDebugDumpQueryCapabilities(capabilities);
  499. }
  500. #endif
  501. return STATUS_SUCCESS;
  502. }
  503. NTSTATUS
  504. PciFdoIrpQueryLegacyBusInformation(
  505. IN PIRP Irp,
  506. IN PIO_STACK_LOCATION IrpSp,
  507. IN PPCI_COMMON_EXTENSION DeviceExtension
  508. )
  509. {
  510. PAGED_CODE();
  511. return PciQueryLegacyBusInformation(
  512. (PPCI_FDO_EXTENSION) DeviceExtension,
  513. (PLEGACY_BUS_INFORMATION *) &Irp->IoStatus.Information
  514. );
  515. }
  516. NTSTATUS
  517. PciFdoIrpDeviceUsageNotification(
  518. IN PIRP Irp,
  519. IN PIO_STACK_LOCATION IrpSp,
  520. IN PPCI_COMMON_EXTENSION DeviceExtension
  521. )
  522. {
  523. PPCI_FDO_EXTENSION fdoExtension;
  524. PAGED_CODE();
  525. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  526. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  527. return PciLocalDeviceUsage(&fdoExtension->PowerState, Irp);
  528. } else {
  529. return STATUS_NOT_SUPPORTED;
  530. }
  531. }
  532. NTSTATUS
  533. PciFdoIrpQueryInterface(
  534. IN PIRP Irp,
  535. IN PIO_STACK_LOCATION IrpSp,
  536. IN PPCI_COMMON_EXTENSION DeviceExtension
  537. )
  538. {
  539. PPCI_FDO_EXTENSION fdoExtension;
  540. NTSTATUS status;
  541. PAGED_CODE();
  542. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  543. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  544. // NTRAID #54671 - 4/20/2000 - andrewth
  545. //
  546. // We might want to do a synchronizing state
  547. // transition here so we don't attempt to get the interface during a
  548. // stop/remove sequence.
  549. //
  550. // We shouldn't hold interfaces when something isn't
  551. // started. But we won't boot unless we hack the below....
  552. //
  553. //if (fdoExtension->DeviceState != PciStarted) {
  554. if (fdoExtension->DeviceState == PciDeleted) {
  555. return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
  556. }
  557. status = PciQueryInterface(
  558. fdoExtension,
  559. IrpSp->Parameters.QueryInterface.InterfaceType,
  560. IrpSp->Parameters.QueryInterface.Size,
  561. IrpSp->Parameters.QueryInterface.Version,
  562. IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
  563. IrpSp->Parameters.QueryInterface.Interface,
  564. FALSE
  565. );
  566. if (NT_SUCCESS(status)) {
  567. Irp->IoStatus.Status = status;
  568. return PciPassIrpFromFdoToPdo(DeviceExtension, Irp);
  569. } else if (status == STATUS_NOT_SUPPORTED) {
  570. //
  571. // Status == STATUS_NOT_SUPPORTED. Pass IRP down the stack
  572. // and see if anyone else is kind enough to provide this
  573. // interface.
  574. //
  575. status = PciCallDownIrpStack(DeviceExtension, Irp);
  576. if (status == STATUS_NOT_SUPPORTED) {
  577. //
  578. // If nobody provided the interface, try again at
  579. // this level.
  580. //
  581. status = PciQueryInterface(
  582. fdoExtension,
  583. IrpSp->Parameters.QueryInterface.InterfaceType,
  584. IrpSp->Parameters.QueryInterface.Size,
  585. IrpSp->Parameters.QueryInterface.Version,
  586. IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
  587. IrpSp->Parameters.QueryInterface.Interface,
  588. TRUE
  589. );
  590. }
  591. }
  592. if (status != STATUS_NOT_SUPPORTED) {
  593. Irp->IoStatus.Status = status;
  594. } else {
  595. status = Irp->IoStatus.Status;
  596. }
  597. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  598. return status;
  599. }
  600. NTSTATUS
  601. PciFdoIrpSurpriseRemoval(
  602. IN PIRP Irp,
  603. IN PIO_STACK_LOCATION IrpSp,
  604. IN PPCI_COMMON_EXTENSION DeviceExtension
  605. )
  606. {
  607. PPCI_FDO_EXTENSION fdoExtension;
  608. NTSTATUS status;
  609. PAGED_CODE();
  610. fdoExtension = (PPCI_FDO_EXTENSION) DeviceExtension;
  611. status = PciBeginStateTransition(DeviceExtension, PciSurpriseRemoved);
  612. PCI_ASSERT(NT_SUCCESS(status));
  613. if (NT_SUCCESS(status)) {
  614. PciCommitStateTransition(DeviceExtension, PciSurpriseRemoved);
  615. status = PciBeginStateTransition(DeviceExtension, PciDeleted);
  616. }
  617. return status;
  618. }
  619. NTSTATUS
  620. PciAddDevice(
  621. IN PDRIVER_OBJECT DriverObject,
  622. IN PDEVICE_OBJECT PhysicalDeviceObject
  623. )
  624. /*++
  625. Routine Description:
  626. Given a physical device object, this routine creates a functional
  627. device object for it.
  628. Arguments:
  629. DriverObject - Pointer to our driver's DRIVER_OBJECT structure.
  630. PhysicalDeviceObject - Pointer to the physical device object for which
  631. we must create a functional device object.
  632. Return Value:
  633. NT status.
  634. --*/
  635. {
  636. PDEVICE_OBJECT functionalDeviceObject = NULL;
  637. PDEVICE_OBJECT attachedTo = NULL;
  638. PPCI_FDO_EXTENSION fdoExtension = NULL;
  639. PPCI_FDO_EXTENSION pciParentFdoExtension;
  640. PPCI_PDO_EXTENSION pdoExtension = NULL;
  641. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
  642. NTSTATUS status;
  643. HANDLE deviceRegistryHandle;
  644. ULONG resultLength;
  645. UNICODE_STRING hackFlagsString;
  646. UCHAR infoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1];
  647. PKEY_VALUE_PARTIAL_INFORMATION info = (PKEY_VALUE_PARTIAL_INFORMATION) infoBuffer;
  648. PAGED_CODE();
  649. PciDebugPrint(PciDbgAddDevice, "PCI - AddDevice (a new bus).\n");
  650. //
  651. // Find out if the PDO was created by the PCI driver. That is,
  652. // if it is a child or a root bus. Validate a few things before
  653. // going any further.
  654. //
  655. pciParentFdoExtension = PciFindParentPciFdoExtension(PhysicalDeviceObject,
  656. &PciGlobalLock);
  657. if (pciParentFdoExtension) {
  658. //
  659. // The PDO was created by this driver, therefore we can look at
  660. // the extension. Get it and verify it's ours.
  661. //
  662. pdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
  663. ASSERT_PCI_PDO_EXTENSION(pdoExtension);
  664. //
  665. // The only thing we should get an add device that is a
  666. // child device is a PCI-PCI bridge.
  667. //
  668. if ((pdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) ||
  669. (pdoExtension->SubClass != PCI_SUBCLASS_BR_PCI_TO_PCI)) {
  670. PciDebugPrint(
  671. PciDbgAlways,
  672. "PCI - PciAddDevice for Non-Root/Non-PCI-PCI bridge,\n"
  673. " Class %02x, SubClass %02x, will not add.\n",
  674. pdoExtension->BaseClass,
  675. pdoExtension->SubClass
  676. );
  677. PCI_ASSERT((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
  678. (pdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
  679. status = STATUS_INVALID_DEVICE_REQUEST;
  680. goto cleanup;
  681. }
  682. PciDebugPrint(PciDbgAddDevice,
  683. "PCI - AddDevice (new bus is child of bus 0x%x).\n",
  684. pciParentFdoExtension->BaseBus
  685. );
  686. if (!PciAreBusNumbersConfigured(pdoExtension)) {
  687. //
  688. // This bridge isn't configured and if we had been able to we would
  689. // already have done so
  690. //
  691. PciDebugPrint(
  692. PciDbgAddDevice | PciDbgInformative,
  693. "PCI - Bus numbers not configured for bridge (0x%x.0x%x.0x%x)\n",
  694. pciParentFdoExtension->BaseBus,
  695. pdoExtension->Slot.u.bits.DeviceNumber,
  696. pdoExtension->Slot.u.bits.FunctionNumber,
  697. pdoExtension->Dependent.type1.PrimaryBus
  698. );
  699. status = STATUS_INVALID_DEVICE_REQUEST;
  700. goto cleanup;
  701. }
  702. }
  703. //
  704. // We've been given the PhysicalDeviceObject for a PCI bus. Create the
  705. // functionalDeviceObject. Our FDO will be nameless.
  706. //
  707. status = IoCreateDevice(
  708. DriverObject, // our driver object
  709. sizeof(PCI_FDO_EXTENSION), // size of our extension
  710. NULL, // our name
  711. FILE_DEVICE_BUS_EXTENDER, // device type
  712. 0, // device characteristics
  713. FALSE, // not exclusive
  714. &functionalDeviceObject // store new device object here
  715. );
  716. if (!NT_SUCCESS(status)) {
  717. goto cleanup;
  718. }
  719. fdoExtension = (PPCI_FDO_EXTENSION)functionalDeviceObject->DeviceExtension;
  720. //
  721. // We have our functionalDeviceObject, initialize it.
  722. //
  723. PciInitializeFdoExtensionCommonFields(
  724. fdoExtension,
  725. functionalDeviceObject,
  726. PhysicalDeviceObject
  727. );
  728. //
  729. // Now attach to the PDO we were given.
  730. //
  731. attachedTo = IoAttachDeviceToDeviceStack(functionalDeviceObject,
  732. PhysicalDeviceObject);
  733. if (attachedTo == NULL) {
  734. PCI_ASSERT(attachedTo != NULL);
  735. status = STATUS_NO_SUCH_DEVICE;
  736. goto cleanup;
  737. }
  738. fdoExtension->AttachedDeviceObject = attachedTo;
  739. //
  740. // Get the access registers and base bus number for this bus.
  741. // If this bus was discovered by this driver, then the PDO was
  742. // created by this driver and will be on one of the PDO lists
  743. // under one of the FDOs owned by this driver. Otherwise it
  744. // is a new root,.... use magic.
  745. //
  746. if (pciParentFdoExtension) {
  747. //
  748. // This physical device was discovered by this driver.
  749. // Get the bus number from the PDO extension.
  750. //
  751. fdoExtension->BaseBus = pdoExtension->Dependent.type1.SecondaryBus;
  752. //
  753. // Copy the access methods from the root fdo and set
  754. // the root fdo back pointer.
  755. //
  756. fdoExtension->BusRootFdoExtension =
  757. pciParentFdoExtension->BusRootFdoExtension;
  758. //
  759. // Point the PDOextension to the new FDOextension (also indicates
  760. // the object is a bridge) and vice versa.
  761. //
  762. pdoExtension->BridgeFdoExtension = fdoExtension;
  763. fdoExtension->ParentFdoExtension = pciParentFdoExtension;
  764. } else {
  765. PVOID buffer;
  766. //
  767. // Get the boot configuration (CmResourceList) for
  768. // this PDO. This gives us the bus number and the
  769. // ranges covered by this host bridge.
  770. //
  771. status = PciGetDeviceProperty(
  772. PhysicalDeviceObject,
  773. DevicePropertyBootConfiguration,
  774. &buffer
  775. );
  776. if (NT_SUCCESS(status)) {
  777. #if DBG
  778. PciDebugPrint(PciDbgAddDeviceRes,
  779. "PCI - CM RESOURCE LIST FROM ROOT PDO\n");
  780. PciDebugPrintCmResList(PciDbgAddDeviceRes,
  781. buffer);
  782. #endif
  783. descriptor = PciFindDescriptorInCmResourceList(
  784. CmResourceTypeBusNumber,
  785. buffer,
  786. NULL
  787. );
  788. } else {
  789. descriptor = NULL;
  790. }
  791. if (descriptor != NULL) {
  792. //
  793. // Sanity check, some servers are aproaching
  794. // 256 busses but as there is no way to deal with
  795. // numbering bridges under a bus > 256 and we don't
  796. // have raw and translated bus numbers yet - it had
  797. // better be < 0xFF!
  798. //
  799. PCI_ASSERT(descriptor->u.BusNumber.Start <= 0xFF);
  800. PCI_ASSERT(descriptor->u.BusNumber.Start + descriptor->u.BusNumber.Length - 1 <= 0xFF);
  801. fdoExtension->BaseBus =
  802. (UCHAR)descriptor->u.BusNumber.Start;
  803. fdoExtension->MaxSubordinateBus =
  804. (UCHAR)(descriptor->u.BusNumber.Start + descriptor->u.BusNumber.Length - 1);
  805. PciDebugPrint(PciDbgAddDevice,
  806. "PCI - Root Bus # 0x%x->0x%x.\n",
  807. fdoExtension->BaseBus,
  808. fdoExtension->MaxSubordinateBus
  809. );
  810. } else {
  811. //
  812. // HaveGuessedConfigOnceAlready is used to tell
  813. // if have multiple roots and no config info. If
  814. // this happens we end up gussing the bus number
  815. // as zero, doing this more than once is not good.
  816. //
  817. if (HaveGuessedConfigOnceAlready) {
  818. KeBugCheckEx(PCI_BUS_DRIVER_INTERNAL,
  819. PCI_BUGCODE_TOO_MANY_CONFIG_GUESSES,
  820. (ULONG_PTR)PhysicalDeviceObject,
  821. 0,
  822. 0);
  823. }
  824. PciDebugPrint(
  825. PciDbgAlways,
  826. "PCI Will use default configuration.\n"
  827. );
  828. HaveGuessedConfigOnceAlready = TRUE;
  829. fdoExtension->BaseBus = 0;
  830. }
  831. fdoExtension->BusRootFdoExtension = fdoExtension;
  832. }
  833. //
  834. // Organise access to config space
  835. //
  836. status = PciGetConfigHandlers(fdoExtension);
  837. if (!NT_SUCCESS(status)) {
  838. goto cleanup;
  839. }
  840. //
  841. // Initialize arbiters for this FDO.
  842. //
  843. status = PciInitializeArbiters(fdoExtension);
  844. if (!NT_SUCCESS(status)) {
  845. goto cleanup;
  846. }
  847. //
  848. // Indicate this is a REAL FDO extension that is part of a REAL
  849. // FDO. (Fake extensions exist to assist in the enumeration of
  850. // busses which PCI isn't the real controller for (eg CardBus).
  851. //
  852. fdoExtension->Fake = FALSE;
  853. //
  854. // Insert this Fdo in the list of PCI parent Fdos.
  855. //
  856. PciInsertEntryAtTail(&PciFdoExtensionListHead,
  857. &fdoExtension->List,
  858. &PciGlobalLock);
  859. #if defined(_WIN64)
  860. //
  861. // Update the legacy hardware tree that would have been build by the ARC
  862. // firmware or NTDetect which don't exist here.
  863. //
  864. status = PciUpdateLegacyHardwareDescription(fdoExtension);
  865. if (!NT_SUCCESS(status)) {
  866. goto cleanup;
  867. }
  868. #endif
  869. //
  870. // Check if there are any hacks to apply to this bus.
  871. // These are located under the device registry key in a value called HackFlags
  872. //
  873. status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  874. PLUGPLAY_REGKEY_DEVICE,
  875. KEY_ALL_ACCESS,
  876. &deviceRegistryHandle
  877. );
  878. if (!NT_SUCCESS(status)) {
  879. goto cleanup;
  880. }
  881. PciConstStringToUnicodeString(&hackFlagsString, L"HackFlags");
  882. status = ZwQueryValueKey(deviceRegistryHandle,
  883. &hackFlagsString,
  884. KeyValuePartialInformation,
  885. info,
  886. sizeof(infoBuffer),
  887. &resultLength
  888. );
  889. ZwClose(deviceRegistryHandle);
  890. //
  891. // If we have valid data in the registry then remember it
  892. //
  893. if (NT_SUCCESS(status)
  894. && (info->Type == REG_DWORD)
  895. && (info->DataLength == sizeof(ULONG))) {
  896. fdoExtension->BusHackFlags = *((PULONG)(&info->Data));
  897. }
  898. //
  899. // We can receive IRPs now...
  900. //
  901. functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  902. //
  903. // Get any hotplug parameters (we send IRPS for this so it must be after
  904. // DO_DEVICE_INITIALIZING is cleared so we can deal with them)
  905. //
  906. PciGetHotPlugParameters(fdoExtension);
  907. return STATUS_SUCCESS;
  908. cleanup:
  909. PCI_ASSERT(!NT_SUCCESS(status));
  910. //
  911. // Destroy any secondary extensions associated with
  912. // this FDO.
  913. //
  914. if (fdoExtension) {
  915. while (fdoExtension->SecondaryExtension.Next) {
  916. PcipDestroySecondaryExtension(
  917. &fdoExtension->SecondaryExtension,
  918. NULL,
  919. fdoExtension->SecondaryExtension.Next
  920. );
  921. }
  922. }
  923. if (attachedTo) {
  924. IoDetachDevice(attachedTo);
  925. }
  926. if (functionalDeviceObject) {
  927. IoDeleteDevice(functionalDeviceObject);
  928. }
  929. return status;
  930. }
  931. VOID
  932. PciInitializeFdoExtensionCommonFields(
  933. IN PPCI_FDO_EXTENSION FdoExtension,
  934. IN PDEVICE_OBJECT Fdo,
  935. IN PDEVICE_OBJECT Pdo
  936. )
  937. {
  938. RtlZeroMemory(FdoExtension, sizeof(PCI_FDO_EXTENSION));
  939. FdoExtension->ExtensionType = PciFdoExtensionType;
  940. FdoExtension->PhysicalDeviceObject = Pdo;
  941. FdoExtension->FunctionalDeviceObject = Fdo;
  942. FdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
  943. FdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
  944. FdoExtension->IrpDispatchTable = &PciFdoDispatchTable;
  945. ExInitializeFastMutex(&FdoExtension->SecondaryExtMutex);
  946. ExInitializeFastMutex(&FdoExtension->ChildListMutex);
  947. PciInitializeState((PPCI_COMMON_EXTENSION) FdoExtension);
  948. }
  949. VOID
  950. PciGetHotPlugParameters(
  951. IN PPCI_FDO_EXTENSION Fdo
  952. )
  953. /*++
  954. Description:
  955. Runs the _HPP (described below) on the device and saves the parameters if available
  956. Method (_HPP, 0) {
  957. Return (Package(){
  958. 0x00000008, // CacheLineSize in DWORDS
  959. 0x00000040, // LatencyTimer in PCI clocks
  960. 0x00000001, // Enable SERR (Boolean)
  961. 0x00000001 // Enable PERR (Boolean)
  962. })
  963. Arguments:
  964. Fdo - The PDO extension for the bridge
  965. Return Value:
  966. TRUE - if the parameters are available, FASLE otherwise
  967. --*/
  968. {
  969. NTSTATUS status;
  970. ACPI_EVAL_INPUT_BUFFER input;
  971. PACPI_EVAL_OUTPUT_BUFFER output = NULL;
  972. ULONG count;
  973. ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + sizeof(ACPI_METHOD_ARGUMENT) * PCI_HPP_PACKAGE_COUNT;
  974. PAGED_CODE();
  975. output = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, outputSize);
  976. if (!output) {
  977. status = STATUS_INSUFFICIENT_RESOURCES;
  978. goto exit;
  979. }
  980. RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
  981. RtlZeroMemory(output, outputSize);
  982. //
  983. // Send a IOCTL to ACPI to request it to run the _HPP method on this device
  984. // if the method it is present
  985. //
  986. input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  987. input.MethodNameAsUlong = (ULONG)'PPH_';
  988. //
  989. // PciSendIoctl deals with sending this from the top of the stack.
  990. //
  991. status = PciSendIoctl(Fdo->PhysicalDeviceObject,
  992. IOCTL_ACPI_EVAL_METHOD,
  993. &input,
  994. sizeof(ACPI_EVAL_INPUT_BUFFER),
  995. output,
  996. outputSize
  997. );
  998. if (!NT_SUCCESS(status)) {
  999. //
  1000. // Inherit them from my parent (If I have one)
  1001. //
  1002. if (!PCI_IS_ROOT_FDO(Fdo)) {
  1003. RtlCopyMemory(&Fdo->HotPlugParameters,
  1004. &Fdo->ParentFdoExtension->HotPlugParameters,
  1005. sizeof(Fdo->HotPlugParameters)
  1006. );
  1007. }
  1008. } else {
  1009. if (output->Count != PCI_HPP_PACKAGE_COUNT) {
  1010. goto exit;
  1011. }
  1012. //
  1013. // Check they are all integers and in the right bounds
  1014. //
  1015. for (count = 0; count < PCI_HPP_PACKAGE_COUNT; count++) {
  1016. ULONG current;
  1017. if (output->Argument[count].Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  1018. goto exit;
  1019. }
  1020. current = output->Argument[count].Argument;
  1021. switch (count) {
  1022. case PCI_HPP_CACHE_LINE_SIZE_INDEX:
  1023. case PCI_HPP_LATENCY_TIMER_INDEX:
  1024. //
  1025. // These registers are only a UCHAR in length
  1026. //
  1027. if (current > 0xFF) {
  1028. goto exit;
  1029. }
  1030. break;
  1031. case PCI_HPP_ENABLE_SERR_INDEX:
  1032. case PCI_HPP_ENABLE_PERR_INDEX:
  1033. //
  1034. // These are booleans - 1 or 0
  1035. //
  1036. if (current > 1) {
  1037. goto exit;
  1038. }
  1039. break;
  1040. }
  1041. }
  1042. //
  1043. // Finally save them and remember we got them.
  1044. //
  1045. Fdo->HotPlugParameters.CacheLineSize = (UCHAR)output->Argument[PCI_HPP_CACHE_LINE_SIZE_INDEX].Argument;
  1046. Fdo->HotPlugParameters.LatencyTimer = (UCHAR)output->Argument[PCI_HPP_LATENCY_TIMER_INDEX].Argument;
  1047. Fdo->HotPlugParameters.EnableSERR = (BOOLEAN)output->Argument[PCI_HPP_ENABLE_SERR_INDEX].Argument;
  1048. Fdo->HotPlugParameters.EnablePERR = (BOOLEAN)output->Argument[PCI_HPP_ENABLE_PERR_INDEX].Argument;
  1049. Fdo->HotPlugParameters.Acquired = TRUE;
  1050. }
  1051. exit:
  1052. if (output) {
  1053. ExFreePool(output);
  1054. }
  1055. }