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.

1283 lines
35 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. pdo.c
  5. Abstract:
  6. This module handles IRPs for PCI PDO'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. PciPdoIrpStartDevice(
  14. IN PIRP Irp,
  15. IN PIO_STACK_LOCATION IrpSp,
  16. IN PPCI_COMMON_EXTENSION DeviceExtension
  17. );
  18. NTSTATUS
  19. PciPdoIrpQueryRemoveDevice(
  20. IN PIRP Irp,
  21. IN PIO_STACK_LOCATION IrpSp,
  22. IN PPCI_COMMON_EXTENSION DeviceExtension
  23. );
  24. NTSTATUS
  25. PciPdoIrpRemoveDevice(
  26. IN PIRP Irp,
  27. IN PIO_STACK_LOCATION IrpSp,
  28. IN PPCI_COMMON_EXTENSION DeviceExtension
  29. );
  30. NTSTATUS
  31. PciPdoIrpCancelRemoveDevice(
  32. IN PIRP Irp,
  33. IN PIO_STACK_LOCATION IrpSp,
  34. IN PPCI_COMMON_EXTENSION DeviceExtension
  35. );
  36. NTSTATUS
  37. PciPdoIrpStopDevice(
  38. IN PIRP Irp,
  39. IN PIO_STACK_LOCATION IrpSp,
  40. IN PPCI_COMMON_EXTENSION DeviceExtension
  41. );
  42. NTSTATUS
  43. PciPdoIrpQueryStopDevice(
  44. IN PIRP Irp,
  45. IN PIO_STACK_LOCATION IrpSp,
  46. IN PPCI_COMMON_EXTENSION DeviceExtension
  47. );
  48. NTSTATUS
  49. PciPdoIrpCancelStopDevice(
  50. IN PIRP Irp,
  51. IN PIO_STACK_LOCATION IrpSp,
  52. IN PPCI_COMMON_EXTENSION DeviceExtension
  53. );
  54. NTSTATUS
  55. PciPdoIrpQueryDeviceRelations(
  56. IN PIRP Irp,
  57. IN PIO_STACK_LOCATION IrpSp,
  58. IN PPCI_COMMON_EXTENSION DeviceExtension
  59. );
  60. NTSTATUS
  61. PciPdoIrpQueryCapabilities(
  62. IN PIRP Irp,
  63. IN PIO_STACK_LOCATION IrpSp,
  64. IN PPCI_COMMON_EXTENSION DeviceExtension
  65. );
  66. NTSTATUS
  67. PciPdoIrpQueryInterface(
  68. IN PIRP Irp,
  69. IN PIO_STACK_LOCATION IrpSp,
  70. IN PPCI_COMMON_EXTENSION DeviceExtension
  71. );
  72. NTSTATUS
  73. PciPdoIrpQueryResources(
  74. IN PIRP Irp,
  75. IN PIO_STACK_LOCATION IrpSp,
  76. IN PPCI_COMMON_EXTENSION DeviceExtension
  77. );
  78. NTSTATUS
  79. PciPdoIrpQueryResourceRequirements(
  80. IN PIRP Irp,
  81. IN PIO_STACK_LOCATION IrpSp,
  82. IN PPCI_COMMON_EXTENSION DeviceExtension
  83. );
  84. NTSTATUS
  85. PciPdoIrpQueryDeviceText(
  86. IN PIRP Irp,
  87. IN PIO_STACK_LOCATION IrpSp,
  88. IN PPCI_COMMON_EXTENSION DeviceExtension
  89. );
  90. NTSTATUS
  91. PciPdoIrpReadConfig(
  92. IN PIRP Irp,
  93. IN PIO_STACK_LOCATION IrpSp,
  94. IN PPCI_COMMON_EXTENSION DeviceExtension
  95. );
  96. NTSTATUS
  97. PciPdoIrpWriteConfig(
  98. IN PIRP Irp,
  99. IN PIO_STACK_LOCATION IrpSp,
  100. IN PPCI_COMMON_EXTENSION DeviceExtension
  101. );
  102. NTSTATUS
  103. PciPdoIrpQueryId(
  104. IN PIRP Irp,
  105. IN PIO_STACK_LOCATION IrpSp,
  106. IN PPCI_COMMON_EXTENSION DeviceExtension
  107. );
  108. NTSTATUS
  109. PciPdoIrpQueryBusInformation(
  110. IN PIRP Irp,
  111. IN PIO_STACK_LOCATION IrpSp,
  112. IN PPCI_COMMON_EXTENSION DeviceExtension
  113. );
  114. NTSTATUS
  115. PciPdoIrpDeviceUsageNotification(
  116. IN PIRP Irp,
  117. IN PIO_STACK_LOCATION IrpSp,
  118. IN PPCI_COMMON_EXTENSION DeviceExtension
  119. );
  120. NTSTATUS
  121. PciPdoIrpQueryLegacyBusInformation(
  122. IN PIRP Irp,
  123. IN PIO_STACK_LOCATION IrpSp,
  124. IN PPCI_COMMON_EXTENSION DeviceExtension
  125. );
  126. NTSTATUS
  127. PciPdoIrpSurpriseRemoval(
  128. IN PIRP Irp,
  129. IN PIO_STACK_LOCATION IrpSp,
  130. IN PPCI_COMMON_EXTENSION DeviceExtension
  131. );
  132. NTSTATUS
  133. PciPdoIrpQueryDeviceState(
  134. IN PIRP Irp,
  135. IN PIO_STACK_LOCATION IrpSp,
  136. IN PPCI_COMMON_EXTENSION DeviceExtension
  137. );
  138. #ifdef ALLOC_PRAGMA
  139. #pragma alloc_text(PAGE, PciPdoCreate)
  140. #pragma alloc_text(PAGE, PciPdoDestroy)
  141. #pragma alloc_text(PAGE, PciPdoIrpStartDevice)
  142. #pragma alloc_text(PAGE, PciPdoIrpQueryRemoveDevice)
  143. #pragma alloc_text(PAGE, PciPdoIrpRemoveDevice)
  144. #pragma alloc_text(PAGE, PciPdoIrpCancelRemoveDevice)
  145. #pragma alloc_text(PAGE, PciPdoIrpStopDevice)
  146. #pragma alloc_text(PAGE, PciPdoIrpQueryStopDevice)
  147. #pragma alloc_text(PAGE, PciPdoIrpCancelStopDevice)
  148. #pragma alloc_text(PAGE, PciPdoIrpQueryDeviceRelations)
  149. #pragma alloc_text(PAGE, PciPdoIrpQueryInterface)
  150. #pragma alloc_text(PAGE, PciPdoIrpQueryCapabilities)
  151. #pragma alloc_text(PAGE, PciPdoIrpQueryResources)
  152. #pragma alloc_text(PAGE, PciPdoIrpQueryResourceRequirements)
  153. #pragma alloc_text(PAGE, PciPdoIrpQueryDeviceText)
  154. #pragma alloc_text(PAGE, PciPdoIrpReadConfig)
  155. #pragma alloc_text(PAGE, PciPdoIrpWriteConfig)
  156. #pragma alloc_text(PAGE, PciPdoIrpQueryId)
  157. #pragma alloc_text(PAGE, PciPdoIrpQueryBusInformation)
  158. #pragma alloc_text(PAGE, PciPdoIrpDeviceUsageNotification)
  159. #pragma alloc_text(PAGE, PciPdoIrpQueryLegacyBusInformation)
  160. #pragma alloc_text(PAGE, PciPdoIrpSurpriseRemoval)
  161. #pragma alloc_text(PAGE, PciPdoIrpQueryDeviceState)
  162. #endif
  163. /*++
  164. The majority of functions in this file are called based on their presence
  165. in Pnp and Po dispatch tables. In the interests of brevity the arguments
  166. to all those functions will be described below:
  167. NTSTATUS
  168. PciXxxPdo(
  169. IN PIRP Irp,
  170. IN PIO_STACK_LOCATION IrpStack,
  171. IN PPCI_EXTENSION DeviceExtension
  172. )
  173. Routine Description:
  174. This function handles the Xxx requests for a given PCI FDO or PDO.
  175. Arguments:
  176. Irp - Points to the IRP associated with this request.
  177. IrpStack - Points to the current stack location for this request.
  178. DeviceExtension - Points to the device's extension.
  179. Return Value:
  180. Status code that indicates whether or not the function was successful.
  181. STATUS_NOT_SUPPORTED indicates that the IRP should be completed without
  182. changing the Irp->IoStatus.Status field otherwise it is updated with this
  183. status.
  184. --*/
  185. #define PCI_MAX_MINOR_POWER_IRP 0x3
  186. #define PCI_MAX_MINOR_PNP_IRP 0x18
  187. PCI_MN_DISPATCH_TABLE PciPdoDispatchPowerTable[] = {
  188. { IRP_DISPATCH, PciPdoWaitWake }, // 0x00 - IRP_MN_WAIT_WAKE
  189. { IRP_COMPLETE, PciIrpNotSupported }, // 0x01 - IRP_MN_POWER_SEQUENCE
  190. { IRP_COMPLETE, PciPdoSetPowerState }, // 0x02 - IRP_MN_SET_POWER
  191. { IRP_COMPLETE, PciPdoIrpQueryPower }, // 0x03 - IRP_MN_QUERY_POWER
  192. { IRP_COMPLETE, PciIrpNotSupported }, // - UNHANDLED Power IRP
  193. };
  194. PCI_MN_DISPATCH_TABLE PciPdoDispatchPnpTable[] = {
  195. { IRP_COMPLETE, PciPdoIrpStartDevice }, // 0x00 - IRP_MN_START_DEVICE
  196. { IRP_COMPLETE, PciPdoIrpQueryRemoveDevice }, // 0x01 - IRP_MN_QUERY_REMOVE_DEVICE
  197. { IRP_COMPLETE, PciPdoIrpRemoveDevice }, // 0x02 - IRP_MN_REMOVE_DEVICE
  198. { IRP_COMPLETE, PciPdoIrpCancelRemoveDevice }, // 0x03 - IRP_MN_CANCEL_REMOVE_DEVICE
  199. { IRP_COMPLETE, PciPdoIrpStopDevice }, // 0x04 - IRP_MN_STOP_DEVICE
  200. { IRP_COMPLETE, PciPdoIrpQueryStopDevice }, // 0x05 - IRP_MN_QUERY_STOP_DEVICE
  201. { IRP_COMPLETE, PciPdoIrpCancelStopDevice }, // 0x06 - IRP_MN_CANCEL_STOP_DEVICE
  202. { IRP_COMPLETE, PciPdoIrpQueryDeviceRelations }, // 0x07 - IRP_MN_QUERY_DEVICE_RELATIONS
  203. { IRP_COMPLETE, PciPdoIrpQueryInterface }, // 0x08 - IRP_MN_QUERY_INTERFACE
  204. { IRP_COMPLETE, PciPdoIrpQueryCapabilities }, // 0x09 - IRP_MN_QUERY_CAPABILITIES
  205. { IRP_COMPLETE, PciPdoIrpQueryResources }, // 0x0A - IRP_MN_QUERY_RESOURCES
  206. { IRP_COMPLETE, PciPdoIrpQueryResourceRequirements }, // 0x0B - IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  207. { IRP_COMPLETE, PciPdoIrpQueryDeviceText }, // 0x0C - IRP_MN_QUERY_DEVICE_TEXT
  208. { IRP_COMPLETE, PciIrpNotSupported }, // 0x0D - IRP_MN_FILTER_RESOURCE_REQUIREMENTS
  209. { IRP_COMPLETE, PciIrpNotSupported }, // 0x0E - NOT USED
  210. { IRP_COMPLETE, PciPdoIrpReadConfig }, // 0x0F - IRP_MN_READ_CONFIG
  211. { IRP_COMPLETE, PciPdoIrpWriteConfig }, // 0x10 - IRP_MN_WRITE_CONFIG
  212. { IRP_COMPLETE, PciIrpNotSupported }, // 0x11 - IRP_MN_EJECT
  213. { IRP_COMPLETE, PciIrpNotSupported }, // 0x12 - IRP_MN_SET_LOCK
  214. { IRP_COMPLETE, PciPdoIrpQueryId }, // 0x13 - IRP_MN_QUERY_ID
  215. { IRP_COMPLETE, PciPdoIrpQueryDeviceState }, // 0x14 - IRP_MN_QUERY_PNP_DEVICE_STATE
  216. { IRP_COMPLETE, PciPdoIrpQueryBusInformation }, // 0x15 - IRP_MN_QUERY_BUS_INFORMATION
  217. { IRP_COMPLETE, PciPdoIrpDeviceUsageNotification }, // 0x16 - IRP_MN_DEVICE_USAGE_NOTIFICATION
  218. { IRP_COMPLETE, PciPdoIrpSurpriseRemoval }, // 0x17 - IRP_MN_SURPRISE_REMOVAL
  219. { IRP_COMPLETE, PciPdoIrpQueryLegacyBusInformation }, // 0x18 - IRP_MN_QUERY_LEGACY_BUS_INFORMATION
  220. { IRP_COMPLETE, PciIrpNotSupported } // - UNHANDLED PNP IRP
  221. };
  222. //
  223. // This is the major function dispatch table for Pdo's
  224. //
  225. PCI_MJ_DISPATCH_TABLE PciPdoDispatchTable = {
  226. PCI_MAX_MINOR_PNP_IRP, PciPdoDispatchPnpTable, // Pnp irps
  227. PCI_MAX_MINOR_POWER_IRP, PciPdoDispatchPowerTable, // Power irps
  228. IRP_COMPLETE, PciIrpNotSupported,
  229. IRP_COMPLETE, PciIrpInvalidDeviceRequest // Other
  230. };
  231. //
  232. // Data
  233. //
  234. BOOLEAN PciStopOnIllegalConfigAccess = FALSE;
  235. ULONG PciPdoSequenceNumber = (ULONG)-1;
  236. NTSTATUS
  237. PciPdoCreate(
  238. IN PPCI_FDO_EXTENSION FdoExtension,
  239. IN PCI_SLOT_NUMBER Slot,
  240. OUT PDEVICE_OBJECT *PhysicalDeviceObject
  241. )
  242. {
  243. NTSTATUS status;
  244. PDRIVER_OBJECT driverObject;
  245. PDEVICE_OBJECT functionalDeviceObject;
  246. PDEVICE_OBJECT physicalDeviceObject;
  247. PPCI_PDO_EXTENSION pdoExtension;
  248. UNICODE_STRING unicodeDeviceString;
  249. WCHAR deviceString[32];
  250. PAGED_CODE();
  251. //
  252. // We've been asked to create a new PDO for a PCI device. First get
  253. // a pointer to our driver object.
  254. //
  255. functionalDeviceObject = FdoExtension->FunctionalDeviceObject;
  256. driverObject = functionalDeviceObject->DriverObject;
  257. //
  258. // Create the physical device object for this device.
  259. // In theory it doesn't need a name,... It must have
  260. // a name.
  261. //
  262. // But what name? For now we'll call it NTPNP_PCIxxxx,
  263. // where xxxx is the 0-based number of PCI devices we've
  264. // found.
  265. //
  266. _snwprintf(deviceString,
  267. sizeof(deviceString)/sizeof(WCHAR),
  268. L"\\Device\\NTPNP_PCI%04d",
  269. InterlockedIncrement(&PciPdoSequenceNumber));
  270. RtlInitUnicodeString(&unicodeDeviceString, deviceString);
  271. status = IoCreateDevice(
  272. driverObject, // our driver object
  273. sizeof(PCI_PDO_EXTENSION), // size of our extension,
  274. &unicodeDeviceString, // our name
  275. FILE_DEVICE_UNKNOWN, // device type
  276. 0, // device characteristics
  277. FALSE, // not exclusive
  278. &physicalDeviceObject // store new device object here
  279. );
  280. if (!NT_SUCCESS(status)) {
  281. ASSERT(NT_SUCCESS(status));
  282. return status;
  283. }
  284. pdoExtension = (PPCI_PDO_EXTENSION)physicalDeviceObject->DeviceExtension;
  285. PciDebugPrint(PciDbgVerbose,
  286. "PCI: New PDO (b=0x%x, d=0x%x, f=0x%x) @ %p, ext @ %p\n",
  287. FdoExtension->BaseBus,
  288. Slot.u.bits.DeviceNumber,
  289. Slot.u.bits.FunctionNumber,
  290. physicalDeviceObject,
  291. pdoExtension);
  292. //
  293. // We have our physical device object, initialize it.
  294. //
  295. // And yes, I would have zeroed the extension if I didn't know
  296. // for a fact that it was zeroed by IoCreateDevice().
  297. //
  298. pdoExtension->ExtensionType = PciPdoExtensionType;
  299. pdoExtension->IrpDispatchTable = &PciPdoDispatchTable;
  300. pdoExtension->PhysicalDeviceObject = physicalDeviceObject;
  301. pdoExtension->Slot = Slot;
  302. pdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
  303. pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
  304. pdoExtension->ParentFdoExtension = FdoExtension;
  305. ExInitializeFastMutex(&pdoExtension->SecondaryExtMutex);
  306. PciInitializeState((PPCI_COMMON_EXTENSION) pdoExtension);
  307. //
  308. // Insert it into the list of child PDOs hanging off of the FdoExtension.
  309. // We won't be re-entered enumerating the same bus, so we don't need to
  310. // protect the list.
  311. //
  312. pdoExtension->Next = NULL;
  313. PciInsertEntryAtTail(
  314. (PSINGLE_LIST_ENTRY)&FdoExtension->ChildPdoList,
  315. (PSINGLE_LIST_ENTRY)&pdoExtension->Next,
  316. &FdoExtension->ChildListMutex
  317. );
  318. *PhysicalDeviceObject = physicalDeviceObject;
  319. return STATUS_SUCCESS;
  320. }
  321. VOID
  322. PciPdoDestroy(
  323. IN PDEVICE_OBJECT PhysicalDeviceObject
  324. )
  325. {
  326. PPCI_PDO_EXTENSION pdoExtension;
  327. PPCI_PDO_EXTENSION *previousBridge;
  328. PPCI_FDO_EXTENSION fdoExtension;
  329. PAGED_CODE();
  330. pdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
  331. ASSERT_PCI_PDO_EXTENSION(pdoExtension);
  332. ASSERT(!pdoExtension->LegacyDriver);
  333. fdoExtension = PCI_PARENT_FDOX(pdoExtension);
  334. ASSERT_PCI_FDO_EXTENSION(fdoExtension);
  335. PciDebugPrint(PciDbgVerbose,
  336. "PCI: destroy PDO (b=0x%x, d=0x%x, f=0x%x)\n",
  337. PCI_PARENT_FDOX(pdoExtension)->BaseBus,
  338. pdoExtension->Slot.u.bits.DeviceNumber,
  339. pdoExtension->Slot.u.bits.FunctionNumber);
  340. //
  341. // Remove this PDO from the Child Pdo List.
  342. //
  343. ASSERT_MUTEX_HELD(&fdoExtension->ChildListMutex);
  344. PciRemoveEntryFromList((PSINGLE_LIST_ENTRY)&fdoExtension->ChildPdoList,
  345. (PSINGLE_LIST_ENTRY)pdoExtension,
  346. NULL);
  347. for (previousBridge = &fdoExtension->ChildBridgePdoList;
  348. *previousBridge;
  349. previousBridge = &((*previousBridge)->NextBridge)) {
  350. if (*previousBridge == pdoExtension) {
  351. *previousBridge = pdoExtension->NextBridge;
  352. pdoExtension->NextBridge = NULL;
  353. break;
  354. }
  355. }
  356. pdoExtension->Next = NULL;
  357. //
  358. // Delete any secondary extensions this PDO may have.
  359. //
  360. while (pdoExtension->SecondaryExtension.Next) {
  361. PcipDestroySecondaryExtension(&pdoExtension->SecondaryExtension,
  362. NULL,
  363. pdoExtension->SecondaryExtension.Next);
  364. }
  365. //
  366. // Zap the extension type so we'll trip up if we try to resuse it.
  367. //
  368. pdoExtension->ExtensionType = 0xdead;
  369. //
  370. // If there are any resource lists etc associated with this puppy,
  371. // give them back to the system.
  372. //
  373. PciInvalidateResourceInfoCache(pdoExtension);
  374. if (pdoExtension->Resources) {
  375. ExFreePool(pdoExtension->Resources);
  376. }
  377. //
  378. // And finally,...
  379. //
  380. IoDeleteDevice(PhysicalDeviceObject);
  381. }
  382. NTSTATUS
  383. PciPdoIrpStartDevice(
  384. IN PIRP Irp,
  385. IN PIO_STACK_LOCATION IrpSp,
  386. IN PPCI_COMMON_EXTENSION DeviceExtension
  387. )
  388. {
  389. NTSTATUS status;
  390. BOOLEAN change, powerOn, isVideoController;
  391. PPCI_PDO_EXTENSION pdoExtension;
  392. PAGED_CODE();
  393. status = PciBeginStateTransition(DeviceExtension, PciStarted);
  394. if (!NT_SUCCESS(status)) {
  395. return status;
  396. }
  397. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  398. //
  399. // If there is a motherboard video device and a plug in video
  400. // device, the BIOS will have disabled the motherboard one. The
  401. // video drivers use this fact to determine if this device should
  402. // be disabled,... don't change its settings here.
  403. //
  404. isVideoController =
  405. ((pdoExtension->BaseClass == PCI_CLASS_PRE_20) &&
  406. (pdoExtension->SubClass == PCI_SUBCLASS_PRE_20_VGA)) ||
  407. ((pdoExtension->BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
  408. (pdoExtension->SubClass == PCI_SUBCLASS_VID_VGA_CTLR));
  409. if ( !isVideoController ) {
  410. //
  411. // Non-VGA, unconditionally enable the IO and Memory for the device.
  412. //
  413. pdoExtension->CommandEnables |= (PCI_ENABLE_IO_SPACE
  414. | PCI_ENABLE_MEMORY_SPACE);
  415. }
  416. //
  417. // Disable interrupt generation for IDE controllers until IDE is up and
  418. // running (See comment in PciConfigureIdeController)
  419. //
  420. if (pdoExtension->IoSpaceUnderNativeIdeControl) {
  421. pdoExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE;
  422. }
  423. //
  424. // Always enable the bus master bit - even for video controllers
  425. //
  426. pdoExtension->CommandEnables |= PCI_ENABLE_BUS_MASTER;
  427. //
  428. // Extract the PDO Resources (PCI driver internal style)
  429. // from the incoming resource list.
  430. //
  431. change = PciComputeNewCurrentSettings(
  432. pdoExtension,
  433. IrpSp->Parameters.StartDevice.AllocatedResources
  434. );
  435. //
  436. // Remember if we ever move the device
  437. //
  438. if (change) {
  439. pdoExtension->MovedDevice = TRUE;
  440. }
  441. #if DBG
  442. if (!change) {
  443. PciDebugPrint(
  444. PciDbgObnoxious,
  445. "PCI - START not changing resource settings.\n"
  446. );
  447. }
  448. #endif
  449. //
  450. // The device should be powered up at this stage.
  451. //
  452. powerOn = FALSE;
  453. if (pdoExtension->PowerState.CurrentDeviceState != PowerDeviceD0) {
  454. POWER_STATE powerState;
  455. status = PciSetPowerManagedDevicePowerState(
  456. pdoExtension,
  457. PowerDeviceD0,
  458. FALSE
  459. );
  460. if (!NT_SUCCESS(status)) {
  461. PciCancelStateTransition(DeviceExtension, PciStarted);
  462. return STATUS_DEVICE_POWER_FAILURE;
  463. }
  464. powerState.DeviceState = PowerDeviceD0;
  465. PoSetPowerState(
  466. pdoExtension->PhysicalDeviceObject,
  467. DevicePowerState,
  468. powerState
  469. );
  470. //
  471. // Force PciSetResources to write the configuration
  472. // and other extraneous data to the device.
  473. //
  474. powerOn = TRUE;
  475. pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
  476. }
  477. //
  478. // Program the device with the resources allocated.
  479. //
  480. status = PciSetResources(
  481. pdoExtension,
  482. powerOn,
  483. TRUE
  484. );
  485. if (NT_SUCCESS(status)) {
  486. PciCommitStateTransition(DeviceExtension, PciStarted);
  487. } else {
  488. PciCancelStateTransition(DeviceExtension, PciStarted);
  489. }
  490. return status;
  491. }
  492. NTSTATUS
  493. PciPdoIrpQueryRemoveDevice(
  494. IN PIRP Irp,
  495. IN PIO_STACK_LOCATION IrpSp,
  496. IN PPCI_COMMON_EXTENSION DeviceExtension
  497. )
  498. {
  499. PPCI_PDO_EXTENSION pdoExtension;
  500. PAGED_CODE();
  501. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  502. //
  503. // Don't allow the paging device (or a hibernate device) to
  504. // be removed or stopped
  505. //
  506. if (pdoExtension->PowerState.Hibernate ||
  507. pdoExtension->PowerState.Paging ||
  508. pdoExtension->PowerState.CrashDump ||
  509. pdoExtension->OnDebugPath ||
  510. (pdoExtension->HackFlags & PCI_HACK_FAIL_QUERY_REMOVE)) {
  511. return STATUS_DEVICE_BUSY;
  512. }
  513. //
  514. // Don't allow devices with legacy drivers to be removed (even thought the
  515. // driver may be root enumerated)
  516. //
  517. if (pdoExtension->LegacyDriver) {
  518. return STATUS_INVALID_DEVICE_REQUEST;
  519. }
  520. if (DeviceExtension->DeviceState == PciNotStarted) {
  521. return STATUS_SUCCESS;
  522. } else {
  523. return PciBeginStateTransition(DeviceExtension, PciNotStarted);
  524. }
  525. }
  526. NTSTATUS
  527. PciPdoIrpRemoveDevice(
  528. IN PIRP Irp,
  529. IN PIO_STACK_LOCATION IrpSp,
  530. IN PPCI_COMMON_EXTENSION DeviceExtension
  531. )
  532. {
  533. NTSTATUS status;
  534. PPCI_PDO_EXTENSION pdoExtension;
  535. PAGED_CODE();
  536. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  537. //
  538. // If this PDO is for a PCI-PCI bridge, it has a pointer
  539. // to the FDO that was attached to it. That FDO was destroyed
  540. // as a result of the IRP coming down the stack. Clear the
  541. // pointer. (Unconditionally as it is only set for bridges).
  542. //
  543. pdoExtension->BridgeFdoExtension = NULL;
  544. if (!pdoExtension->NotPresent) {
  545. //
  546. // Turn the device off. (Checks for whether or not
  547. // this is a good idea are in the PciDecodeEnable routine).
  548. // While you might think this should be done only if we were already
  549. // headed to PciNotStarted, we may in fact have a boot config that
  550. // needs to be disabled.
  551. //
  552. PciDecodeEnable(pdoExtension, FALSE, NULL);
  553. //
  554. // Power it down if we are allowed to disable its decodes - if not then
  555. // don't turn it off. eg. Don't turn of the VGA card...
  556. //
  557. if (pdoExtension->PowerState.CurrentDeviceState != PowerDeviceD3
  558. && PciCanDisableDecodes(pdoExtension, NULL, 0, 0)) {
  559. POWER_STATE powerState;
  560. status = PciSetPowerManagedDevicePowerState(
  561. pdoExtension,
  562. PowerDeviceD3,
  563. FALSE
  564. );
  565. pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD3;
  566. powerState.DeviceState = PowerDeviceD3;
  567. PoSetPowerState(
  568. pdoExtension->PhysicalDeviceObject,
  569. DevicePowerState,
  570. powerState
  571. );
  572. }
  573. }
  574. //
  575. // We can get a remove in one of three states:
  576. // 1) We have received a QueryRemove/SurpriseRemove in which case we are
  577. // transitioning to PciNotStarted.
  578. // 2) We were never started, so we are already in PciNotStarted.
  579. // 3) We started the PDO, but the FDO failed start. We are in PciStarted in
  580. // this case.
  581. //
  582. if (!PciIsInTransitionToState(DeviceExtension, PciNotStarted)&&
  583. (DeviceExtension->DeviceState == PciStarted)) {
  584. PciBeginStateTransition(DeviceExtension, PciNotStarted);
  585. }
  586. if (PciIsInTransitionToState(DeviceExtension, PciNotStarted)) {
  587. PciCommitStateTransition(DeviceExtension, PciNotStarted);
  588. }
  589. if (pdoExtension->ReportedMissing) {
  590. status = PciBeginStateTransition(DeviceExtension, PciDeleted);
  591. ASSERT(NT_SUCCESS(status));
  592. PciCommitStateTransition(DeviceExtension, PciDeleted);
  593. PciPdoDestroy(pdoExtension->PhysicalDeviceObject);
  594. }
  595. return STATUS_SUCCESS;
  596. }
  597. NTSTATUS
  598. PciPdoIrpCancelRemoveDevice(
  599. IN PIRP Irp,
  600. IN PIO_STACK_LOCATION IrpSp,
  601. IN PPCI_COMMON_EXTENSION DeviceExtension
  602. )
  603. {
  604. PAGED_CODE();
  605. PciCancelStateTransition(DeviceExtension, PciNotStarted);
  606. return STATUS_SUCCESS;
  607. }
  608. NTSTATUS
  609. PciPdoIrpStopDevice(
  610. IN PIRP Irp,
  611. IN PIO_STACK_LOCATION IrpSp,
  612. IN PPCI_COMMON_EXTENSION DeviceExtension
  613. )
  614. {
  615. NTSTATUS status;
  616. PAGED_CODE();
  617. //
  618. // Turn the device off. (Checks for whether or not
  619. // this is a good idea are in the PciDecodeEnable routine).
  620. //
  621. PciDecodeEnable((PPCI_PDO_EXTENSION) DeviceExtension, FALSE, NULL);
  622. PciCommitStateTransition(DeviceExtension, PciStopped);
  623. return STATUS_SUCCESS;
  624. }
  625. NTSTATUS
  626. PciPdoIrpQueryStopDevice(
  627. IN PIRP Irp,
  628. IN PIO_STACK_LOCATION IrpSp,
  629. IN PPCI_COMMON_EXTENSION DeviceExtension
  630. )
  631. {
  632. PPCI_PDO_EXTENSION pdoExtension;
  633. PAGED_CODE();
  634. //
  635. // Don't allow the paging device (or a hibernate device) to
  636. // be removed or stopped
  637. //
  638. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  639. if (pdoExtension->PowerState.Hibernate ||
  640. pdoExtension->PowerState.Paging ||
  641. pdoExtension->PowerState.CrashDump ||
  642. pdoExtension->OnDebugPath) {
  643. return STATUS_DEVICE_BUSY;
  644. }
  645. //
  646. // Don't stop PCI->PCI and CardBus bridges
  647. //
  648. if (pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV
  649. && (pdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI
  650. || pdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)) {
  651. return STATUS_INVALID_DEVICE_REQUEST;
  652. }
  653. //
  654. // Don't allow devices with legacy drivers to be stopped (even thought the
  655. // driver may be root enumerated)
  656. //
  657. if (pdoExtension->LegacyDriver) {
  658. return STATUS_INVALID_DEVICE_REQUEST;
  659. }
  660. //
  661. // If we cannot free the resources, do tell the OS.
  662. //
  663. if (!PciCanDisableDecodes(pdoExtension, NULL, 0, 0)) {
  664. return STATUS_INVALID_DEVICE_REQUEST;
  665. }
  666. return PciBeginStateTransition(DeviceExtension, PciStopped);
  667. }
  668. NTSTATUS
  669. PciPdoIrpCancelStopDevice(
  670. IN PIRP Irp,
  671. IN PIO_STACK_LOCATION IrpSp,
  672. IN PPCI_COMMON_EXTENSION DeviceExtension
  673. )
  674. {
  675. PAGED_CODE();
  676. PciCancelStateTransition(DeviceExtension, PciStopped);
  677. return STATUS_SUCCESS;
  678. }
  679. NTSTATUS
  680. PciPdoIrpQueryDeviceRelations(
  681. IN PIRP Irp,
  682. IN PIO_STACK_LOCATION IrpSp,
  683. IN PPCI_COMMON_EXTENSION DeviceExtension
  684. )
  685. {
  686. NTSTATUS status;
  687. PPCI_PDO_EXTENSION pdoExtension, childList;
  688. PAGED_CODE();
  689. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  690. switch(IrpSp->Parameters.QueryDeviceRelations.Type) {
  691. case EjectionRelations:
  692. status = PciQueryEjectionRelations(
  693. pdoExtension,
  694. (PDEVICE_RELATIONS*)&Irp->IoStatus.Information
  695. );
  696. break;
  697. case TargetDeviceRelation:
  698. status = PciQueryTargetDeviceRelations(
  699. pdoExtension,
  700. (PDEVICE_RELATIONS*)&Irp->IoStatus.Information
  701. );
  702. break;
  703. default:
  704. status = STATUS_NOT_SUPPORTED;
  705. break;
  706. }
  707. return status;
  708. }
  709. NTSTATUS
  710. PciPdoIrpQueryInterface(
  711. IN PIRP Irp,
  712. IN PIO_STACK_LOCATION IrpSp,
  713. IN PPCI_COMMON_EXTENSION DeviceExtension
  714. )
  715. {
  716. NTSTATUS status;
  717. PPCI_PDO_EXTENSION pdoExtension;
  718. PAGED_CODE();
  719. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  720. status = PciQueryInterface(
  721. pdoExtension,
  722. IrpSp->Parameters.QueryInterface.InterfaceType,
  723. IrpSp->Parameters.QueryInterface.Size,
  724. IrpSp->Parameters.QueryInterface.Version,
  725. IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
  726. IrpSp->Parameters.QueryInterface.Interface,
  727. FALSE
  728. );
  729. if (!NT_SUCCESS(status)) {
  730. //
  731. // KLUDGE: If this pdo has a fake FDO attatched to
  732. // it (because it's a cardbus controller), we should
  733. // check to see if this interface could have been supplied
  734. // by the FDO and supply it if so.
  735. //
  736. // Yes, this is really gross and yes it breaks the filter
  737. // model. The correct thing is for cardbus to pass the
  738. // IRP here via the "backdoor" while it has it at the FDO
  739. // level.
  740. //
  741. PPCI_FDO_EXTENSION fakeFdo;
  742. fakeFdo = pdoExtension->BridgeFdoExtension;
  743. if (fakeFdo && (fakeFdo->Fake == TRUE)) {
  744. ASSERT((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
  745. (pdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS));
  746. status = PciQueryInterface(
  747. fakeFdo,
  748. IrpSp->Parameters.QueryInterface.InterfaceType,
  749. IrpSp->Parameters.QueryInterface.Size,
  750. IrpSp->Parameters.QueryInterface.Version,
  751. IrpSp->Parameters.QueryInterface.InterfaceSpecificData,
  752. IrpSp->Parameters.QueryInterface.Interface,
  753. FALSE
  754. );
  755. }
  756. }
  757. return status;
  758. }
  759. NTSTATUS
  760. PciPdoIrpQueryCapabilities(
  761. IN PIRP Irp,
  762. IN PIO_STACK_LOCATION IrpSp,
  763. IN PPCI_COMMON_EXTENSION DeviceExtension
  764. )
  765. {
  766. PAGED_CODE();
  767. return PciQueryCapabilities(
  768. (PPCI_PDO_EXTENSION) DeviceExtension,
  769. IrpSp->Parameters.DeviceCapabilities.Capabilities
  770. );
  771. }
  772. NTSTATUS
  773. PciPdoIrpQueryId(
  774. IN PIRP Irp,
  775. IN PIO_STACK_LOCATION IrpSp,
  776. IN PPCI_COMMON_EXTENSION DeviceExtension
  777. )
  778. {
  779. PAGED_CODE();
  780. //
  781. // Get a pointer to the query id structure and process.
  782. //
  783. return PciQueryId(
  784. (PPCI_PDO_EXTENSION) DeviceExtension,
  785. IrpSp->Parameters.QueryId.IdType,
  786. (PWSTR*)&Irp->IoStatus.Information
  787. );
  788. }
  789. NTSTATUS
  790. PciPdoIrpQueryResources(
  791. IN PIRP Irp,
  792. IN PIO_STACK_LOCATION IrpSp,
  793. IN PPCI_COMMON_EXTENSION DeviceExtension
  794. )
  795. {
  796. PAGED_CODE();
  797. return PciQueryResources(
  798. (PPCI_PDO_EXTENSION) DeviceExtension,
  799. (PCM_RESOURCE_LIST*)&Irp->IoStatus.Information
  800. );
  801. }
  802. NTSTATUS
  803. PciPdoIrpQueryResourceRequirements(
  804. IN PIRP Irp,
  805. IN PIO_STACK_LOCATION IrpSp,
  806. IN PPCI_COMMON_EXTENSION DeviceExtension
  807. )
  808. {
  809. PAGED_CODE();
  810. return PciQueryRequirements(
  811. (PPCI_PDO_EXTENSION) DeviceExtension,
  812. (PIO_RESOURCE_REQUIREMENTS_LIST*)&Irp->IoStatus.Information
  813. );
  814. }
  815. NTSTATUS
  816. PciPdoIrpQueryDeviceText(
  817. IN PIRP Irp,
  818. IN PIO_STACK_LOCATION IrpSp,
  819. IN PPCI_COMMON_EXTENSION DeviceExtension
  820. )
  821. {
  822. PAGED_CODE();
  823. return PciQueryDeviceText(
  824. (PPCI_PDO_EXTENSION) DeviceExtension,
  825. IrpSp->Parameters.QueryDeviceText.DeviceTextType,
  826. IrpSp->Parameters.QueryDeviceText.LocaleId,
  827. (PWSTR*)&Irp->IoStatus.Information
  828. );
  829. }
  830. NTSTATUS
  831. PciPdoIrpReadConfig(
  832. IN PIRP Irp,
  833. IN PIO_STACK_LOCATION IrpSp,
  834. IN PPCI_COMMON_EXTENSION DeviceExtension
  835. )
  836. {
  837. NTSTATUS status;
  838. ULONG lengthRead;
  839. PPCI_PDO_EXTENSION pdoExtension;
  840. PAGED_CODE();
  841. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  842. status = PciReadDeviceSpace(pdoExtension,
  843. IrpSp->Parameters.ReadWriteConfig.WhichSpace,
  844. IrpSp->Parameters.ReadWriteConfig.Buffer,
  845. IrpSp->Parameters.ReadWriteConfig.Offset,
  846. IrpSp->Parameters.ReadWriteConfig.Length,
  847. &lengthRead
  848. );
  849. //
  850. // Update the information files with the number of bytes read
  851. //
  852. Irp->IoStatus.Information = lengthRead;
  853. return status;
  854. }
  855. NTSTATUS
  856. PciPdoIrpWriteConfig(
  857. IN PIRP Irp,
  858. IN PIO_STACK_LOCATION IrpSp,
  859. IN PPCI_COMMON_EXTENSION DeviceExtension
  860. )
  861. {
  862. NTSTATUS status;
  863. ULONG lengthWritten;
  864. PPCI_PDO_EXTENSION pdoExtension;
  865. PAGED_CODE();
  866. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  867. status = PciWriteDeviceSpace(pdoExtension,
  868. IrpSp->Parameters.ReadWriteConfig.WhichSpace,
  869. IrpSp->Parameters.ReadWriteConfig.Buffer,
  870. IrpSp->Parameters.ReadWriteConfig.Offset,
  871. IrpSp->Parameters.ReadWriteConfig.Length,
  872. &lengthWritten
  873. );
  874. //
  875. // Update the information files with the number of bytes read
  876. //
  877. Irp->IoStatus.Information = lengthWritten;
  878. return status;
  879. }
  880. NTSTATUS
  881. PciPdoIrpQueryBusInformation(
  882. IN PIRP Irp,
  883. IN PIO_STACK_LOCATION IrpSp,
  884. IN PPCI_COMMON_EXTENSION DeviceExtension
  885. )
  886. {
  887. PAGED_CODE();
  888. return PciQueryBusInformation(
  889. (PPCI_PDO_EXTENSION) DeviceExtension,
  890. (PPNP_BUS_INFORMATION *) &Irp->IoStatus.Information
  891. );
  892. }
  893. NTSTATUS
  894. PciPdoIrpDeviceUsageNotification(
  895. IN PIRP Irp,
  896. IN PIO_STACK_LOCATION IrpSp,
  897. IN PPCI_COMMON_EXTENSION DeviceExtension
  898. )
  899. {
  900. PAGED_CODE();
  901. return PciPdoDeviceUsage((PPCI_PDO_EXTENSION) DeviceExtension, Irp);
  902. }
  903. NTSTATUS
  904. PciPdoIrpQueryLegacyBusInformation(
  905. IN PIRP Irp,
  906. IN PIO_STACK_LOCATION IrpSp,
  907. IN PPCI_COMMON_EXTENSION DeviceExtension
  908. )
  909. {
  910. PPCI_PDO_EXTENSION PdoExtension;
  911. PLEGACY_BUS_INFORMATION information;
  912. PAGED_CODE();
  913. //
  914. // We're interested in IRP_MN_QUERY_LEGACY_BUS_INFORMATION on a
  915. // PDO if the PDO is for a CardBus bridge. In this case, the
  916. // CardBus/PCMCIA FDO has passed the irp down so that we can
  917. // answer it correctly.
  918. //
  919. PdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  920. if (PciClassifyDeviceType(PdoExtension) != PciTypeCardbusBridge) {
  921. return STATUS_NOT_SUPPORTED;
  922. }
  923. information = ExAllocatePool(PagedPool, sizeof(LEGACY_BUS_INFORMATION));
  924. if (information == NULL) {
  925. return STATUS_INSUFFICIENT_RESOURCES;
  926. }
  927. RtlCopyMemory(&information->BusTypeGuid, &GUID_BUS_TYPE_PCI, sizeof(GUID));
  928. information->LegacyBusType = PCIBus;
  929. information->BusNumber = PdoExtension->Dependent.type1.SecondaryBus;
  930. (PLEGACY_BUS_INFORMATION) Irp->IoStatus.Information = information;
  931. return STATUS_SUCCESS;
  932. }
  933. NTSTATUS
  934. PciPdoIrpSurpriseRemoval(
  935. IN PIRP Irp,
  936. IN PIO_STACK_LOCATION IrpSp,
  937. IN PPCI_COMMON_EXTENSION DeviceExtension
  938. )
  939. {
  940. NTSTATUS status;
  941. PPCI_PDO_EXTENSION pdoExtension;
  942. PAGED_CODE();
  943. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  944. //
  945. // There are two kinds of surprise removals
  946. // - Surprise removals due to removal of our device
  947. // - Surprise removals due to failure of our device to start
  948. //
  949. if (!pdoExtension->NotPresent) {
  950. //
  951. // Turn the device off. (Checks for whether or not
  952. // this is a good idea are in the PciDecodeEnable routine).
  953. // While you might think this should be done only if we were already
  954. // headed to PciNotStarted, we may in fact have a boot config that
  955. // needs to be disabled. Note that we may turn it off again in remove
  956. // device. No big deal.
  957. //
  958. PciDecodeEnable(pdoExtension, FALSE, NULL);
  959. //
  960. // Power it down if we are allowed to disable its decodes - if not then
  961. // don't turn it off. eg. Don't turn of the VGA card...
  962. //
  963. if (pdoExtension->PowerState.CurrentDeviceState != PowerDeviceD3
  964. && PciCanDisableDecodes(pdoExtension, NULL, 0, 0)) {
  965. POWER_STATE powerState;
  966. //
  967. // Power it down - if it fails we don't care - the hardware may be
  968. // gone!
  969. //
  970. PciSetPowerManagedDevicePowerState(
  971. pdoExtension,
  972. PowerDeviceD3,
  973. FALSE
  974. );
  975. pdoExtension->PowerState.CurrentDeviceState = PowerDeviceD3;
  976. powerState.DeviceState = PowerDeviceD3;
  977. PoSetPowerState(
  978. pdoExtension->PhysicalDeviceObject,
  979. DevicePowerState,
  980. powerState
  981. );
  982. }
  983. }
  984. if (!pdoExtension->ReportedMissing) {
  985. PciBeginStateTransition(DeviceExtension, PciNotStarted);
  986. } else {
  987. //
  988. // The device is physically gone, don't dare touch it!
  989. //
  990. PciBeginStateTransition(DeviceExtension, PciSurpriseRemoved);
  991. PciCommitStateTransition(DeviceExtension, PciSurpriseRemoved);
  992. }
  993. return STATUS_SUCCESS;
  994. }
  995. NTSTATUS
  996. PciPdoIrpQueryDeviceState(
  997. IN PIRP Irp,
  998. IN PIO_STACK_LOCATION IrpSp,
  999. IN PPCI_COMMON_EXTENSION DeviceExtension
  1000. )
  1001. {
  1002. PPCI_PDO_EXTENSION pdoExtension;
  1003. PAGED_CODE();
  1004. pdoExtension = (PPCI_PDO_EXTENSION) DeviceExtension;
  1005. //
  1006. // Host brides cannot be disabled and the user should not be given a
  1007. // opportunity to do so.
  1008. //
  1009. if ((pdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
  1010. (pdoExtension->SubClass == PCI_SUBCLASS_BR_HOST)) {
  1011. (PNP_DEVICE_STATE)Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
  1012. }
  1013. return STATUS_SUCCESS;
  1014. }