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.

286 lines
8.1 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. state.c
  5. Abstract:
  6. This module the state manipulation engine for PCI
  7. Author:
  8. Adrian J. Oney (AdriaO) 20-Oct-1998
  9. Revision History:
  10. Environment:
  11. NT Kernel Model Driver only
  12. --*/
  13. #include "pcip.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, PciBeginStateTransition)
  16. #pragma alloc_text(PAGE, PciCommitStateTransition)
  17. #pragma alloc_text(PAGE, PciCancelStateTransition)
  18. #pragma alloc_text(PAGE, PciIsInTransitionToState)
  19. #endif
  20. //
  21. // This array marks Allowed, Disallowed, and Illegal state transitions.
  22. //
  23. // The horizontal axis represents the current state.
  24. // The vertical axis represents the state we are being asked to transition into.
  25. //
  26. // There are four values in the table:
  27. // STATUS_SUCCESS - State transition is possible
  28. // STATUS_INVALID_DEVICE_STATE - We legally cannot do the state transition
  29. // STATUS_INVALID_DEVICE_REQUEST - Illegal transition, but known OS bug.
  30. // STATUS_FAIL_CHECK - Consistancy problem. We should ASSERT!
  31. //
  32. // Count is PciMaxObjectState of
  33. //
  34. // PciNotStarted, PciStarted, PciDeleted, PciStopped, PciSurpriseRemoved, and
  35. // PciSynchronizedOperation
  36. //
  37. // The final state is used to initiate operations that synchronously with
  38. // respect to it and other state transitions. Commiting PciSynchronizedOperation
  39. // is strictly illegal, and we are never strickly "in" that state.
  40. //
  41. //
  42. // We will use the following visually shorter notation (State Transition foo)
  43. // for the table:
  44. //
  45. #define ST_OK STATUS_SUCCESS
  46. #define ST_NOTOK STATUS_INVALID_DEVICE_STATE
  47. #define ST_ERROR STATUS_FAIL_CHECK
  48. #define ST_NTBUG STATUS_INVALID_DEVICE_REQUEST
  49. #define ST_OSBUG STATUS_INVALID_DEVICE_REQUEST
  50. #define ST_9XBUG STATUS_FAIL_CHECK // Change to STATUS_SUCCESS for 9x
  51. NTSTATUS PnpStateTransitionArray[PciMaxObjectState][PciMaxObjectState] = {
  52. // at NotStarted, Started, Deleted, Stopped, SurpriseRemoved, SynchronizedOperation
  53. { ST_ERROR, ST_OK, ST_ERROR, ST_OK, ST_ERROR, ST_ERROR }, // entering PciNotStarted
  54. { ST_OK, ST_ERROR, ST_ERROR, ST_OK, ST_ERROR, ST_ERROR }, // entering PciStarted
  55. { ST_OK, ST_OK, ST_ERROR, ST_ERROR, ST_OK, ST_ERROR }, // entering PciDeleted
  56. { ST_OSBUG, ST_OK, ST_ERROR, ST_ERROR, ST_ERROR, ST_ERROR }, // entering PciStopped
  57. { ST_NTBUG, ST_OK, ST_ERROR, ST_OK, ST_ERROR, ST_ERROR }, // entering PciSurpriseRemoved
  58. { ST_OK, ST_OK, ST_NOTOK, ST_OK, ST_NOTOK, ST_ERROR } // entering PciSynchronizedOperation
  59. };
  60. //
  61. // This array is used in debug to restrict which state transitions can be
  62. // spuriously cancelled. We restrict this to Stops and Removes, which come
  63. // through all the time due to the inability of PnP to differentiate which
  64. // device in a stack failed a query.
  65. //
  66. #if DBG
  67. // Cancelling NotStarted, Started, Removed, Stopped, SurpriseRemoved, SynchronizedOperation
  68. NTSTATUS PnpStateCancelArray[PciMaxObjectState] =
  69. { ST_NTBUG, ST_ERROR, ST_NOTOK, ST_NOTOK, ST_ERROR, ST_ERROR };
  70. //
  71. // While here, declare the text we use for debug squirties...
  72. //
  73. PUCHAR PciTransitionText[] = {
  74. "PciNotStarted",
  75. "PciStarted",
  76. "PciDeleted",
  77. "PciStopped",
  78. "PciSurpriseRemoved",
  79. "PciSynchronizedOperation",
  80. "PciMaxObjectState"
  81. };
  82. #endif
  83. VOID
  84. PciInitializeState(
  85. IN PPCI_COMMON_EXTENSION DeviceExtension
  86. )
  87. {
  88. DeviceExtension->DeviceState = PciNotStarted;
  89. DeviceExtension->TentativeNextState = PciNotStarted;
  90. }
  91. NTSTATUS
  92. PciBeginStateTransition(
  93. IN PPCI_COMMON_EXTENSION DeviceExtension,
  94. IN PCI_OBJECT_STATE NewState
  95. )
  96. {
  97. NTSTATUS status;
  98. PCI_OBJECT_STATE currentState;
  99. #if DBG
  100. PciDebugPrint(
  101. PciDbgInformative,
  102. "PCI Request to begin transition of Extension %p to %s ->",
  103. DeviceExtension,
  104. PciTransitionText[NewState]
  105. );
  106. #endif
  107. //
  108. // Our "next" device state should be the same as our current device state.
  109. //
  110. ASSERT(DeviceExtension->TentativeNextState == DeviceExtension->DeviceState);
  111. currentState = DeviceExtension->DeviceState;
  112. //
  113. // One of three returns will wind their way out of this code:
  114. // STATUS_SUCCESS - State transition is possible
  115. // STATUS_INVALID_DEVICE_STATE - We legally cannot do the state transition
  116. // STATUS_FAIL_CHECK - Consistancy problem. We should ASSERT!
  117. //
  118. ASSERT(currentState < PciMaxObjectState);
  119. ASSERT(NewState < PciMaxObjectState);
  120. //
  121. // Get plausibility and legality of requested state change.
  122. //
  123. status = PnpStateTransitionArray[NewState][currentState];
  124. #if DBG
  125. //
  126. // State bug in PnP or driver. Investigation required.
  127. //
  128. if (status == STATUS_FAIL_CHECK) {
  129. PciDebugPrintf(
  130. PciDbgAlways,
  131. "ERROR\nPCI: Error trying to enter state \"%s\" from state \"%s\"\n",
  132. PciTransitionText[NewState],
  133. PciTransitionText[currentState]
  134. );
  135. DbgBreakPoint();
  136. } else if (status == STATUS_INVALID_DEVICE_REQUEST) {
  137. PciDebugPrintf(
  138. PciDbgInformative,
  139. "ERROR\nPCI: Illegal request to try to enter state \"%s\" from state \"%s\", rejecting",
  140. PciTransitionText[NewState],
  141. PciTransitionText[currentState]
  142. );
  143. }
  144. #endif
  145. //
  146. // Someone tried to transition from A to A. We must fail the attemtpt
  147. // (ie STATUS_INVALID_DEVICE_STATE). There is no known case where we
  148. // should return success yet do nothing.
  149. //
  150. ASSERT((NewState!=DeviceExtension->DeviceState) || (!NT_SUCCESS(status)));
  151. if (NT_SUCCESS(status)) {
  152. DeviceExtension->TentativeNextState = (UCHAR)NewState;
  153. }
  154. PciDebugPrint(PciDbgInformative, "->%x\n", status);
  155. return status;
  156. }
  157. VOID
  158. PciCommitStateTransition(
  159. IN PPCI_COMMON_EXTENSION DeviceExtension,
  160. IN PCI_OBJECT_STATE NewState
  161. )
  162. {
  163. #if DBG
  164. PciDebugPrint(
  165. PciDbgInformative,
  166. "PCI Commit transition of Extension %p to %s\n",
  167. DeviceExtension,
  168. PciTransitionText[NewState]
  169. );
  170. #endif
  171. //
  172. // This state is illegal.
  173. //
  174. ASSERT(NewState != PciSynchronizedOperation);
  175. //
  176. // verify commit properly pairs with previous PciBeginStateTransition.
  177. //
  178. ASSERT(DeviceExtension->TentativeNextState == NewState);
  179. DeviceExtension->DeviceState = (UCHAR)NewState;
  180. }
  181. NTSTATUS
  182. PciCancelStateTransition(
  183. IN PPCI_COMMON_EXTENSION DeviceExtension,
  184. IN PCI_OBJECT_STATE StateNotEntered
  185. )
  186. {
  187. #if DBG
  188. PciDebugPrint(
  189. PciDbgInformative,
  190. "PCI Request to cancel transition of Extension %p to %s ->",
  191. DeviceExtension,
  192. PciTransitionText[StateNotEntered]
  193. );
  194. #endif
  195. //
  196. // Spurious Cancel's are allowed in specific states. This is allowed
  197. // because PnP can't help but send them.
  198. //
  199. if (DeviceExtension->TentativeNextState == DeviceExtension->DeviceState) {
  200. PciDebugPrint(PciDbgInformative, "%x\n", STATUS_INVALID_DEVICE_STATE);
  201. ASSERT(StateNotEntered < PciMaxObjectState);
  202. ASSERT(PnpStateCancelArray[StateNotEntered] != STATUS_FAIL_CHECK);
  203. return STATUS_INVALID_DEVICE_STATE;
  204. }
  205. //
  206. // verify cancel properly pairs with previous PciBeginStateTransition.
  207. //
  208. ASSERT(DeviceExtension->TentativeNextState == StateNotEntered);
  209. //
  210. // OK, our tests say we are in a transition. Verify the mutex.
  211. //
  212. DeviceExtension->TentativeNextState = DeviceExtension->DeviceState;
  213. PciDebugPrint(PciDbgInformative, "%x\n", STATUS_SUCCESS);
  214. return STATUS_SUCCESS;
  215. }
  216. BOOLEAN
  217. PciIsInTransitionToState(
  218. IN PPCI_COMMON_EXTENSION DeviceExtension,
  219. IN PCI_OBJECT_STATE NextState
  220. )
  221. {
  222. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  223. ASSERT(NextState < PciMaxObjectState);
  224. //
  225. // Are we in a state transition?
  226. //
  227. if (DeviceExtension->TentativeNextState == DeviceExtension->DeviceState) {
  228. return FALSE;
  229. }
  230. //
  231. // OK, our tests say we are in a transition. Verify the mutex.
  232. //
  233. ASSERT_MUTEX_HELD(&DeviceExtension->StateMutex);
  234. return (DeviceExtension->TentativeNextState == NextState);
  235. }